goscript_types/check/
typexpr.rs

1#![allow(dead_code)]
2use super::super::constant;
3use super::super::lookup;
4use super::super::obj::EntityType;
5use super::super::objects::{ObjKey, ScopeKey, TCObjects, TypeKey};
6use super::super::operand::{Operand, OperandMode};
7use super::super::scope::Scope;
8use super::super::typ::{self, Type};
9use super::check::{Checker, FilesContext, ObjContext};
10use super::interface::MethodInfo;
11use goscript_parser::ast::{self, Expr, FieldList, Node};
12use goscript_parser::objects::{FuncTypeKey, IdentKey};
13use goscript_parser::{Pos, Token};
14use std::borrow::Borrow;
15use std::collections::HashMap;
16
17impl<'a> Checker<'a> {
18    /// ident type-checks identifier ikey and initializes x with the value or type of ikey.
19    /// If an error occurred, x.mode is set to invalid.
20    /// For the meaning of def, see Checker.defined_type, below.
21    /// If want_type is set, the identifier e is expected to denote a type.
22    pub fn ident(
23        &mut self,
24        x: &mut Operand,
25        ikey: IdentKey,
26        def: Option<TypeKey>,
27        want_type: bool,
28        fctx: &mut FilesContext,
29    ) {
30        x.mode = OperandMode::Invalid;
31        x.expr = Some(Expr::Ident(ikey));
32
33        // Note that we cannot use check.lookup here because the returned scope
34        // may be different from obj.parent(). See also Scope.lookup_parent doc.
35        let name = &self.ast_ident(ikey).name;
36        if let Some((skey, okey)) =
37            Scope::lookup_parent(&self.octx.scope.unwrap(), name, self.octx.pos, self.tc_objs)
38        {
39            self.result.record_use(ikey, okey);
40
41            // Type-check the object.
42            // Only call Checker.obj_decl if the object doesn't have a type yet
43            // (in which case we must actually determine it) or the object is a
44            // TypeName and we also want a type (in which case we might detect
45            // a cycle which needs to be reported). Otherwise we can skip the
46            // call and avoid a possible cycle error in favor of the more
47            // informative "not a type/value" error that this function's caller
48            // will issue
49            let lobj = self.lobj(okey);
50            let pkg = lobj.pkg();
51            let mut otype = lobj.typ();
52            if otype.is_none() || (lobj.entity_type().is_type_name() && want_type) {
53                self.obj_decl(okey, def, fctx);
54                // type must have been assigned by Checker.obj_decl
55                otype = self.lobj(okey).typ();
56            }
57            debug_assert!(otype.is_some());
58
59            // The object may be dot-imported: If so, remove its package from
60            // the map of unused dot imports for the respective file scope.
61            // (This code is only needed for dot-imports. Without them,
62            // we only have to mark variables, see Var case below).
63            if pkg.is_some() && pkg != Some(self.pkg) {
64                fctx.unused_dot_imports
65                    .get_mut(&skey)
66                    .unwrap()
67                    .remove(&pkg.unwrap());
68            }
69
70            let lobj = self.lobj(okey);
71            let invalid_type = self.invalid_type();
72            match lobj.entity_type() {
73                EntityType::PkgName(_, _) => {
74                    let pos = self.ast_ident(ikey).pos;
75                    let msg = format!("use of package {} not in selector", lobj.name());
76                    self.error(pos, msg);
77                    return;
78                }
79                EntityType::Const(_) => {
80                    self.add_decl_dep(okey);
81                    if otype == Some(invalid_type) {
82                        return;
83                    }
84                    if okey == *self.tc_objs.universe().iota() {
85                        if self.octx.iota.is_none() {
86                            let pos = self.ast_ident(ikey).pos;
87                            self.error_str(pos, "cannot use iota outside constant declaration");
88                            return;
89                        }
90                        x.mode = OperandMode::Constant(self.octx.iota.clone().unwrap());
91                    } else {
92                        x.mode = OperandMode::Constant(self.lobj(okey).const_val().clone());
93                    }
94                }
95                EntityType::TypeName => x.mode = OperandMode::TypeExpr,
96                EntityType::Var(_) => {
97                    // It's ok to mark non-local variables, but ignore variables
98                    // from other packages to avoid potential race conditions with
99                    // dot-imported variables.
100                    if lobj.pkg() == Some(self.pkg) {
101                        self.lobj_mut(okey)
102                            .entity_type_mut()
103                            .var_property_mut()
104                            .used = true;
105                    }
106                    self.add_decl_dep(okey);
107                    if otype == Some(invalid_type) {
108                        return;
109                    }
110                    x.mode = OperandMode::Variable;
111                }
112                EntityType::Func(_) => {
113                    self.add_decl_dep(okey);
114                    x.mode = OperandMode::Value;
115                }
116                EntityType::Label(_) => unreachable!(),
117                EntityType::Builtin(id) => x.mode = OperandMode::Builtin(*id),
118                EntityType::Nil => x.mode = OperandMode::Value,
119            }
120            x.typ = otype;
121        } else {
122            let pos = self.ast_ident(ikey).pos;
123            if name == "_" {
124                self.error(pos, "cannot use _ as value or type".to_string());
125            } else {
126                self.error(pos, format!("undeclared name: {}", name));
127            }
128        }
129    }
130
131    /// type_expr type-checks the type expression e and returns its type, or Invalid Type.
132    pub fn type_expr(&mut self, e: &Expr, fctx: &mut FilesContext) -> TypeKey {
133        self.defined_type(e, None, fctx)
134    }
135
136    /// defined_type is like type_expr but also accepts a type name def.
137    /// If def is_some(), e is the type specification for the defined type def, declared
138    /// in a type declaration, and def.underlying will be set to the type of e before
139    /// any components of e are type-checked.
140    pub fn defined_type(
141        &mut self,
142        e: &Expr,
143        def: Option<TypeKey>,
144        fctx: &mut FilesContext,
145    ) -> TypeKey {
146        if self.config().trace_checker {
147            let ed = self.new_dis(e);
148            self.trace_begin(ed.pos(), &format!("{}", ed));
149        }
150        let t = self.type_internal(e, def, fctx);
151        debug_assert!(typ::is_typed(t, self.tc_objs));
152        self.result
153            .record_type_and_value(e, OperandMode::TypeExpr, t);
154        if self.config().trace_checker {
155            let pos = e.pos(self.ast_objs);
156            self.trace_end(pos, &format!("=> {}", self.new_dis(&t)));
157        }
158        t
159    }
160
161    /// indirect_type is like type_expr but it also breaks the (otherwise) infinite size of
162    /// recursivetypes by introducing an indirection. It should be called for components of
163    /// types that are not laid out in place in memory, such as pointer base types, slice or
164    /// map element types, function parameter types, etc.
165    pub fn indirect_type(&mut self, e: &Expr, fctx: &mut FilesContext) -> TypeKey {
166        fctx.push(*self.tc_objs.universe().indir());
167        let t = self.defined_type(e, None, fctx);
168        fctx.pop();
169        t
170    }
171
172    /// func_type type-checks a function or method type.
173    pub fn func_type(
174        &mut self,
175        recv: Option<&FieldList>,
176        ftype: FuncTypeKey,
177        fctx: &mut FilesContext,
178    ) -> TypeKey {
179        let skey = self
180            .tc_objs
181            .new_scope(self.octx.scope, 0, 0, "function".to_string(), true);
182        self.result.record_scope(&ftype, skey);
183
184        let (recv_list, _) = self.collect_params(skey, recv, false, fctx);
185        let ftype_val = &self.ast_objs.ftypes[ftype];
186        let (p, r) = (ftype_val.params.clone(), ftype_val.results.clone());
187        let (params, variadic) = self.collect_params(skey, Some(&p), true, fctx);
188        let (results, _) = self.collect_params(skey, r.as_ref(), false, fctx);
189
190        let mut recv_okey = None;
191        if recv.is_some() {
192            // recv parameter list present (may be empty)
193            // spec: "The receiver is specified via an extra parameter section preceding the
194            // method name. That parameter section must declare a single parameter, the receiver."
195            let invalid_type = self.invalid_type();
196            let recv_var = match recv_list.len() {
197                x if x == 0 => {
198                    let pos = recv.unwrap().pos(self.ast_objs);
199                    self.error_str(pos, "method is missing receiver");
200                    self.tc_objs
201                        .new_param_var(0, None, "".to_string(), Some(invalid_type))
202                }
203                x if x > 1 => {
204                    let pos = self.lobj(recv_list[recv_list.len() - 1]).pos();
205                    self.error_str(pos, "method must have exactly one receiver");
206                    recv_list[0] // continue with first receiver
207                }
208                x if x == 1 => recv_list[0],
209                _ => unreachable!(),
210            };
211            recv_okey = Some(recv_var);
212
213            // spec: "The receiver type must be of the form T or *T where T is a type name."
214            // (ignore invalid types - error was reported before)
215            let recv_var_val = self.lobj(recv_var);
216            let recv_type = recv_var_val.typ().unwrap();
217            let (t, _) = lookup::try_deref(recv_type, self.tc_objs);
218            if t != invalid_type {
219                let err_msg = if let Some(n) = self.otype(t).try_as_named() {
220                    // spec: "The type denoted by T is called the receiver base type; it must not
221                    // be a pointer or interface type and it must be declared in the same package
222                    // as the method."
223                    if self.lobj(n.obj().unwrap()).pkg() != Some(self.pkg) {
224                        Some("type not defined in this package")
225                    } else {
226                        match self.otype(n.underlying()) {
227                            typ::Type::Basic(b) => {
228                                if b.typ() == typ::BasicType::UnsafePointer {
229                                    Some("unsafe.Pointer")
230                                } else {
231                                    None
232                                }
233                            }
234                            typ::Type::Pointer(_) | typ::Type::Interface(_) => {
235                                Some("pointer or interface type")
236                            }
237                            _ => None,
238                        }
239                    }
240                } else {
241                    Some("basic or unnamed type")
242                };
243                if let Some(err) = err_msg {
244                    let pos = recv_var_val.pos();
245                    let td = self.new_dis(&recv_type);
246                    self.error(pos, format!("invalid receiver {} ({})", td, err));
247                    // ok to continue
248                }
249            }
250        }
251
252        let params_tuple = self.tc_objs.new_t_tuple(params);
253        let results_tuple = self.tc_objs.new_t_tuple(results);
254        self.tc_objs
255            .new_t_signature(Some(skey), recv_okey, params_tuple, results_tuple, variadic)
256    }
257
258    /// type_internal drives type checking of types.
259    /// Must only be called by defined_type.
260    fn type_internal(
261        &mut self,
262        e: &Expr,
263        def: Option<TypeKey>,
264        fctx: &mut FilesContext,
265    ) -> TypeKey {
266        let set_underlying = |typ: Option<TypeKey>, tc_objs: &mut TCObjects| {
267            if let Some(d) = def {
268                tc_objs.types[d]
269                    .try_as_named_mut()
270                    .unwrap()
271                    .set_underlying(typ.unwrap());
272            }
273        };
274        let pos = e.pos(self.ast_objs);
275        let result_t: Option<TypeKey> = match e {
276            Expr::Bad(_) => None,
277            Expr::Ident(i) => {
278                let mut x = Operand::new();
279                self.ident(&mut x, *i, def, true, fctx);
280                match x.mode {
281                    OperandMode::TypeExpr => {
282                        set_underlying(x.typ, self.tc_objs);
283                        x.typ
284                    }
285                    OperandMode::Invalid => None, // ignore - error reported before
286                    OperandMode::NoValue => {
287                        error_operand!(x, "{} used as type", self);
288                        None
289                    }
290                    _ => {
291                        error_operand!(x, "{} is not a type", self);
292                        None
293                    }
294                }
295            }
296            Expr::Selector(s) => {
297                let mut x = Operand::new();
298                self.selector(&mut x, s, fctx);
299                match x.mode {
300                    OperandMode::TypeExpr => {
301                        set_underlying(x.typ, self.tc_objs);
302                        x.typ
303                    }
304                    OperandMode::Invalid => None, // ignore - error reported before
305                    OperandMode::NoValue => {
306                        error_operand!(x, "{} used as type", self);
307                        None
308                    }
309                    _ => {
310                        error_operand!(x, "{} is not a type", self);
311                        None
312                    }
313                }
314            }
315            Expr::Paren(p) => Some(self.defined_type(&p.expr, def, fctx)),
316            Expr::Array(a) => {
317                if let Some(l) = &a.len {
318                    let len = self.array_len(&l, fctx);
319                    let elem = self.type_expr(&a.elt, fctx);
320                    let t = self.tc_objs.new_t_array(elem, len);
321                    set_underlying(Some(t), self.tc_objs);
322                    Some(t)
323                } else {
324                    let elem = self.indirect_type(&a.elt, fctx);
325                    let t = self.tc_objs.new_t_slice(elem);
326                    set_underlying(Some(t), self.tc_objs);
327                    Some(t)
328                }
329            }
330            Expr::Struct(s) => {
331                let t = self.struct_type(s, fctx);
332                set_underlying(Some(t), self.tc_objs);
333                Some(t)
334            }
335            Expr::Star(s) => {
336                let base = self.indirect_type(&s.expr, fctx);
337                let t = self.tc_objs.new_t_pointer(base);
338                set_underlying(Some(t), self.tc_objs);
339                Some(t)
340            }
341            Expr::Func(f) => {
342                let t = self.func_type(None, *f, fctx);
343                set_underlying(Some(t), self.tc_objs);
344                Some(t)
345            }
346            Expr::Interface(_) => {
347                let t = self.interface_type(e, def, fctx);
348                set_underlying(Some(t), self.tc_objs);
349                Some(t)
350            }
351            Expr::Map(m) => {
352                let k = self.indirect_type(&m.key, fctx);
353                let v = self.indirect_type(&m.val, fctx);
354                let t = self.tc_objs.new_t_map(k, v);
355                set_underlying(Some(t), self.tc_objs);
356
357                let pos = m.key.pos(self.ast_objs);
358                let f = move |checker: &mut Checker, _: &mut FilesContext| {
359                    if !typ::comparable(k, checker.tc_objs) {
360                        let td = checker.new_dis(&k);
361                        checker.error(pos, format!("invalid map key type {}", td));
362                    }
363                };
364                fctx.later(Box::new(f));
365
366                Some(t)
367            }
368            Expr::Chan(chan) => {
369                let dir = match chan.dir {
370                    ast::ChanDir::Send => typ::ChanDir::SendOnly,
371                    ast::ChanDir::Recv => typ::ChanDir::RecvOnly,
372                    ast::ChanDir::SendRecv => typ::ChanDir::SendRecv,
373                };
374                let elem = self.indirect_type(&chan.val, fctx);
375                let t = self.tc_objs.new_t_chan(dir, elem);
376                set_underlying(Some(t), self.tc_objs);
377                Some(t)
378            }
379            _ => {
380                let ed = self.new_dis(e);
381                self.error(pos, format!("{} is not a type", ed));
382                None
383            }
384        };
385        if let Some(t) = result_t {
386            t
387        } else {
388            let invalid_type = self.invalid_type();
389            set_underlying(Some(invalid_type), self.tc_objs);
390            invalid_type
391        }
392    }
393
394    /// type_or_nil type-checks the type expression (or nil value) e
395    /// and returns the typ of e, or None.
396    /// If e is neither a type nor nil, typOrNil returns Typ[Invalid].
397    pub fn type_or_nil(&mut self, e: &Expr, fctx: &mut FilesContext) -> Option<TypeKey> {
398        let mut x = Operand::new();
399        self.raw_expr(&mut x, e, None, fctx);
400        let invalid_type = self.invalid_type();
401        match x.mode {
402            OperandMode::Invalid => Some(invalid_type), // ignore - error reported before
403            OperandMode::NoValue => {
404                error_operand!(x, "{} used as type", self);
405                Some(invalid_type)
406            }
407            OperandMode::TypeExpr => x.typ,
408            _ => {
409                if x.mode == OperandMode::Value && x.is_nil(self.tc_objs.universe()) {
410                    None
411                } else {
412                    error_operand!(x, "{} is not a type", self);
413                    Some(invalid_type)
414                }
415            }
416        }
417    }
418
419    fn array_len(&mut self, e: &Expr, fctx: &mut FilesContext) -> Option<u64> {
420        let mut x = Operand::new();
421        self.expr(&mut x, e, fctx);
422        if let OperandMode::Constant(v) = &x.mode {
423            let t = x.typ.unwrap();
424            if typ::is_untyped(t, self.tc_objs) || typ::is_integer(t, self.tc_objs) {
425                let int = v.to_int();
426                let int_type = self
427                    .otype(self.basic_type(typ::BasicType::Int))
428                    .try_as_basic()
429                    .unwrap();
430                if let constant::Value::Int(_) = int.borrow() {
431                    if int.representable(int_type, None) {
432                        let (n, exact) = int.int_as_u64();
433                        if exact {
434                            return Some(n);
435                        } else {
436                            error_operand!(x, "invalid array length {}", self);
437                            return None;
438                        }
439                    }
440                }
441            }
442            error_operand!(x, "array length {} must be integer", self);
443        } else {
444            if x.mode != OperandMode::Invalid {
445                error_operand!(x, "array length {} must be constant", self);
446            }
447        }
448        None
449    }
450
451    fn collect_params(
452        &mut self,
453        skey: ScopeKey,
454        fl: Option<&FieldList>,
455        variadic_ok: bool,
456        fctx: &mut FilesContext,
457    ) -> (Vec<ObjKey>, bool) {
458        if let Some(l) = fl {
459            let (mut named, mut anonymous, mut variadic) = (false, false, false);
460            let mut params = Vec::new();
461            for (i, fkey) in l.list.iter().enumerate() {
462                let field = &self.ast_objs.fields[*fkey];
463                let mut ftype = &field.typ;
464                let field_names = field.names.clone();
465                if let Expr::Ellipsis(elli) = ftype {
466                    ftype = elli.elt.as_ref().unwrap();
467                    if variadic_ok && i == l.list.len() - 1 && field_names.len() <= 1 {
468                        variadic = true
469                    } else {
470                        self.soft_error(
471                            elli.pos,
472                            "can only use ... with final parameter in list".to_string(),
473                        )
474                        // ignore ... and continue
475                    }
476                }
477                let ftype = &ftype.clone();
478                let ty = self.indirect_type(ftype, fctx);
479                // The parser ensures that f.Tag is nil and we don't
480                // care if a constructed AST contains a non-nil tag.
481                if field_names.len() > 0 {
482                    for name in field_names.iter() {
483                        let ident = &self.ast_objs.idents[*name];
484                        if ident.name == "" {
485                            self.invalid_ast(ident.pos, "anonymous parameter");
486                            // ok to continue
487                        }
488                        let par_name = ident.name.clone();
489                        let par = self.tc_objs.new_param_var(
490                            ident.pos,
491                            Some(self.pkg),
492                            par_name,
493                            Some(ty),
494                        );
495                        let scope_pos = self.scope(skey).pos();
496                        self.declare(skey, Some(*name), par, scope_pos);
497                        params.push(par);
498                    }
499                    named = true;
500                } else {
501                    // anonymous parameter
502                    let par = self.tc_objs.new_param_var(
503                        ftype.pos(self.ast_objs),
504                        Some(self.pkg),
505                        "".to_string(),
506                        Some(ty),
507                    );
508                    self.result.record_implicit(fkey, par);
509                    params.push(par);
510                    anonymous = true;
511                }
512            }
513            if named && anonymous {
514                self.invalid_ast(
515                    l.pos(self.ast_objs),
516                    "list contains both named and anonymous parameters",
517                )
518                // ok to continue
519            }
520            // For a variadic function, change the last parameter's type from T to []T.
521            // Since we type-checked T rather than ...T, we also need to retro-actively
522            // record the type for ...T.
523            if variadic {
524                let last = params[params.len() - 1];
525                let t = self.tc_objs.new_t_slice(self.lobj(last).typ().unwrap());
526                self.lobj_mut(last).set_type(Some(t));
527                let e = &self.ast_objs.fields[l.list[l.list.len() - 1]].typ;
528                self.result
529                    .record_type_and_value(e, OperandMode::TypeExpr, t);
530            }
531            (params, variadic)
532        } else {
533            (vec![], false)
534        }
535    }
536
537    fn interface_type(
538        &mut self,
539        expr: &ast::Expr,
540        def: Option<TypeKey>,
541        fctx: &mut FilesContext,
542    ) -> TypeKey {
543        let iface = match expr {
544            Expr::Interface(i) => i,
545            _ => unreachable!(),
546        };
547        if iface.methods.list.len() == 0 {
548            return self.tc_objs.new_t_empty_interface();
549        }
550
551        let itype = self.tc_objs.new_t_interface(vec![], vec![]);
552        // collect embedded interfaces
553        // Only needed for printing and API. Delay collection
554        // to end of type-checking (for package-global interfaces)
555        // when all types are complete. Local interfaces are handled
556        // after each statement (as each statement processes delayed
557        // functions).
558        let context_clone = self.octx.clone();
559        let expr_clone = expr.clone();
560        let iface_clone = iface.clone();
561        let f = move |checker: &mut Checker, fctx: &mut FilesContext| {
562            if checker.config().trace_checker {
563                let ed = checker.new_dis(&expr_clone);
564                let msg = format!("-- delayed checking embedded interfaces of {}", ed);
565                checker.trace_begin(iface_clone.interface, &msg);
566            }
567            //replace checker's ctx with context_clone
568            let ctx_backup = std::mem::replace(&mut checker.octx, context_clone);
569
570            let mut embeds = vec![];
571            for fkey in iface_clone.methods.list.iter() {
572                let field = &checker.ast_objs.fields[*fkey];
573                if field.names.len() == 0 {
574                    let texpr = field.typ.clone();
575                    let ty = checker.indirect_type(&texpr, fctx);
576                    // ty should be a named type denoting an interface
577                    // (the parser will make sure it's a named type but
578                    // constructed ASTs may be wrong).
579                    if ty == checker.invalid_type() {
580                        continue; // error reported before
581                    }
582                    match checker.otype(typ::underlying_type(ty, checker.tc_objs)) {
583                        typ::Type::Interface(embed) => {
584                            // Correct embedded interfaces must be complete
585                            assert!(embed.all_methods().is_some());
586                        }
587                        _ => {
588                            let pos = texpr.pos(checker.ast_objs);
589                            let td = checker.new_dis(&ty);
590                            checker.error(pos, format!("{} is not an interface", td));
591                            continue;
592                        }
593                    }
594                    // collect interface
595                    embeds.push(ty);
596                }
597            }
598            embeds.sort_by(compare_by_type_name!(checker.tc_objs));
599            *checker.otype_interface_mut(itype).embeddeds_mut() = embeds;
600
601            // restore ctx
602            checker.octx = ctx_backup;
603            // trace_end
604            if checker.config().trace_checker {
605                checker.trace_end(
606                    iface_clone.interface,
607                    "-- end of delayed checking embedded interfaces",
608                )
609            }
610        };
611        fctx.later(Box::new(f));
612
613        // compute method set
614        let (tname, path) = if let Some(d) = def {
615            let t = *self.otype(d).try_as_named().unwrap().obj();
616            (t, vec![t.unwrap()])
617        } else {
618            (None, vec![])
619        };
620        let info = self.info_from_type_lit(self.octx.scope.unwrap(), iface, tname, &path, fctx);
621        if info.is_none() || info.as_ref().unwrap().as_ref().borrow().is_empty() {
622            // we got an error or the empty interface - exit early
623            self.otype_interface_mut(itype).set_empty_complete();
624            return itype;
625        }
626
627        // use named receiver type if available (for better error messages)
628        let recv_type = if let Some(d) = def { d } else { itype };
629
630        // Correct receiver type for all methods explicitly declared
631        // by this interface after we're done with type-checking at
632        // this level. See comment below for details.
633        let f = move |checker: &mut Checker, _: &mut FilesContext| {
634            for m in checker.otype_interface(itype).methods().clone().iter() {
635                let t = checker.lobj(*m).typ().unwrap();
636                let o = checker.otype_signature(t).recv().unwrap();
637                checker.lobj_mut(o).set_type(Some(recv_type));
638            }
639        };
640        fctx.later(Box::new(f));
641
642        // collect methods
643        let info_ref = info.as_ref().unwrap().as_ref().borrow();
644        let explicits = info_ref.explicits;
645        let mut sig_fix: Vec<MethodInfo> = vec![];
646        for (i, minfo) in info_ref.methods.iter().enumerate() {
647            let fun = if minfo.func().is_none() {
648                let name_key = self.ast_objs.fields[minfo.src().unwrap()].names[0];
649                let ident = self.ast_ident(name_key);
650                let name = ident.name.clone();
651                let pos = ident.pos;
652                // Don't type-check signature yet - use an
653                // empty signature now and update it later.
654                // But set up receiver since we know it and
655                // its position, and because interface method
656                // signatures don't get a receiver via regular
657                // type-checking (there isn't a receiver in the
658                // method's AST). Setting the receiver type is
659                // also important for ptrRecv() (see methodset.go).
660                //
661                // Note: For embedded methods, the receiver type
662                // should be the type of the interface that declared
663                // the methods in the first place. Since we get the
664                // methods here via methodInfo, which may be computed
665                // before we have all relevant interface types, we use
666                // the current interface's type (recvType). This may be
667                // the type of the interface embedding the interface that
668                // declared the methods. This doesn't matter for type-
669                // checking (we only care about the receiver type for
670                // the ptrRecv predicate, and it's never a pointer recv
671                // for interfaces), but it matters for go/types clients
672                // and for printing. We correct the receiver after type-
673                // checking.
674
675                let recv_key =
676                    self.tc_objs
677                        .new_var(pos, Some(self.pkg), "".to_string(), Some(recv_type));
678                let empty_tuple = *self.tc_objs.universe().no_value_tuple();
679                let sig_key = self.tc_objs.new_t_signature(
680                    None,
681                    Some(recv_key),
682                    empty_tuple,
683                    empty_tuple,
684                    false,
685                );
686                let fun_key = self
687                    .tc_objs
688                    .new_func(pos, Some(self.pkg), name, Some(sig_key));
689                minfo.set_func(fun_key);
690                self.result.record_def(name_key, Some(fun_key));
691                sig_fix.push(minfo.clone());
692                fun_key
693            } else {
694                minfo.func().unwrap()
695            };
696            let itype_val = self.otype_interface_mut(itype);
697            if i < explicits {
698                itype_val.methods_mut().push(fun);
699            }
700            itype_val.all_methods_push(fun);
701        }
702        drop(info_ref);
703
704        // fix signatures now that we have collected all methods
705        let invalid_type = self.invalid_type();
706        let saved_context = self.octx.clone();
707        for minfo in sig_fix {
708            // (possibly embedded) methods must be type-checked within their scope and
709            // type-checking them must not affect the current context
710            self.octx = ObjContext::new();
711            self.octx.scope = minfo.scope();
712            let ftype = self.ast_objs.fields[minfo.src().unwrap()].typ.clone();
713            let ty = self.indirect_type(&ftype, fctx);
714            if let Some(sig) = self.otype(ty).try_as_signature() {
715                let sig_copy = *sig;
716                // update signature, but keep recv that was set up before
717                let old = self.otype_signature_mut(self.lobj(minfo.func().unwrap()).typ().unwrap());
718                let recv = *old.recv(); // save recv
719                *old = sig_copy;
720                old.set_recv(recv); // restore recv
721            } else {
722                if ty != invalid_type {
723                    let pos = ftype.pos(self.ast_objs);
724                    let td = self.new_dis(&ty);
725                    self.invalid_ast(pos, &format!("{} is not a method signature", td));
726                }
727            }
728        }
729        self.octx = saved_context;
730
731        // sort methods
732        let itype_val = self.otype_interface(itype);
733        let mut methods = itype_val.methods().clone();
734        methods.sort_by(compare_by_method_name!(self.tc_objs));
735        *self.otype_interface_mut(itype).methods_mut() = methods;
736        // sort all_methods
737        let itype_val = self.otype_interface(itype);
738        if itype_val.all_methods().is_none() {
739            itype_val.set_empty_complete();
740        } else {
741            itype_val
742                .all_methods_mut()
743                .as_mut()
744                .unwrap()
745                .sort_by(compare_by_method_name!(self.tc_objs));
746        }
747
748        itype
749    }
750
751    fn tag(&self, t: &Option<Expr>) -> Option<String> {
752        if let Some(e) = t {
753            if let Expr::BasicLit(bl) = e {
754                if let Token::STRING(data) = &bl.token {
755                    return Some(data.as_str_str().1.clone());
756                }
757                self.invalid_ast(
758                    e.pos(self.ast_objs),
759                    &format!("incorrect tag syntax: {}", bl.token),
760                )
761            } else {
762                unreachable!()
763            }
764        }
765        None
766    }
767
768    fn declare_in_set(&self, set: &mut HashMap<String, ObjKey>, fld: ObjKey, pos: Pos) -> bool {
769        if let Some(okey) = self.insert_obj_to_set(set, fld) {
770            self.error(pos, format!("{} redeclared", self.lobj(fld).name()));
771            self.report_alt_decl(okey);
772            false
773        } else {
774            true
775        }
776    }
777
778    fn add_field(
779        &mut self,
780        fields: &mut Vec<ObjKey>,
781        tags: &mut Option<Vec<Option<String>>>,
782        oset: &mut HashMap<String, ObjKey>,
783        ty: TypeKey,
784        tag: Option<String>,
785        ikey: IdentKey,
786        embedded: bool,
787        pos: Pos,
788    ) {
789        if tag.is_some() && tags.is_none() {
790            *tags = Some(vec![]);
791        }
792        if tags.is_some() {
793            tags.as_mut().unwrap().push(tag);
794        }
795        let name = &self.ast_ident(ikey).name.clone();
796        let fld = self
797            .tc_objs
798            .new_field(pos, Some(self.pkg), name.clone(), Some(ty), embedded);
799        if name == "_" || self.declare_in_set(oset, fld, pos) {
800            fields.push(fld);
801            self.result.record_def(ikey, Some(fld));
802        }
803    }
804
805    fn embedded_field_ident(e: &Expr) -> Option<IdentKey> {
806        match e {
807            Expr::Ident(i) => Some(*i),
808            Expr::Star(s) => match s.expr {
809                // *T is valid, but **T is not
810                Expr::Star(_) => None,
811                _ => Checker::embedded_field_ident(&s.expr),
812            },
813            Expr::Selector(s) => Some(s.sel),
814            _ => None,
815        }
816    }
817
818    fn struct_type(&mut self, st: &ast::StructType, fctx: &mut FilesContext) -> TypeKey {
819        let fields = &st.fields.list;
820        if fields.len() == 0 {
821            return self.tc_objs.new_t_struct(vec![], None);
822        }
823
824        let mut field_objs: Vec<ObjKey> = vec![];
825        let mut tags: Option<Vec<Option<String>>> = None;
826        let mut oset: HashMap<String, ObjKey> = HashMap::new();
827        for f in fields {
828            let field = &self.ast_objs.fields[*f];
829            let fnames = field.names.clone();
830            let ftag = self.tag(&field.tag);
831            let ftype = field.typ.clone();
832            let ty = self.type_expr(&ftype, fctx);
833            if fnames.len() > 0 {
834                // named fields
835                for name in fnames.iter() {
836                    self.add_field(
837                        &mut field_objs,
838                        &mut tags,
839                        &mut oset,
840                        ty,
841                        ftag.clone(),
842                        *name,
843                        false,
844                        self.ast_ident(*name).pos,
845                    );
846                }
847            } else {
848                // embedded field
849                // spec: "An embedded type must be specified as a type name T or as a pointer
850                // to a non-interface type name *T, and T itself may not be a pointer type."
851                let field = &self.ast_objs.fields[*f];
852                let pos = field.typ.pos(self.ast_objs);
853                let invalid_type = self.invalid_type();
854                let mut add_invalid = |c: &mut Checker, ident: IdentKey| {
855                    c.add_field(
856                        &mut field_objs,
857                        &mut tags,
858                        &mut oset,
859                        invalid_type,
860                        None,
861                        ident,
862                        false,
863                        pos,
864                    );
865                };
866                if let Some(ident) = Checker::embedded_field_ident(&field.typ) {
867                    let (t, is_ptr) = lookup::try_deref(ty, self.tc_objs);
868                    // Because we have a name, typ must be of the form T or *T, where T is the name
869                    // of a (named or alias) type, and t (= deref(typ)) must be the type of T.
870                    let t = typ::underlying_type(t, self.tc_objs);
871                    let type_val = self.otype(t);
872                    match type_val {
873                        typ::Type::Basic(_) if t == invalid_type => {
874                            // error was reported before
875                            add_invalid(self, ident);
876                        }
877                        typ::Type::Basic(b) if b.typ() == typ::BasicType::UnsafePointer => {
878                            self.error_str(pos, "embedded field type cannot be unsafe.Pointer");
879                            add_invalid(self, ident);
880                        }
881                        typ::Type::Pointer(_) => {
882                            self.error_str(pos, "embedded field type cannot be a pointer");
883                            add_invalid(self, ident);
884                        }
885                        typ::Type::Interface(_) if is_ptr => {
886                            self.error_str(
887                                pos,
888                                "embedded field type cannot be a pointer to an interface",
889                            );
890                            add_invalid(self, ident);
891                        }
892                        _ => self.add_field(
893                            &mut field_objs,
894                            &mut tags,
895                            &mut oset,
896                            ty,
897                            ftag.clone(),
898                            ident,
899                            true,
900                            pos,
901                        ),
902                    }
903                } else {
904                    let ed = self.new_dis(&field.typ);
905                    self.invalid_ast(pos, &format!("embedded field type {} has no name", ed));
906                    let ident = self.ast_objs.idents.insert(ast::Ident::blank(pos));
907                    add_invalid(self, ident);
908                }
909            }
910        }
911
912        self.tc_objs.new_t_struct(field_objs, tags)
913    }
914}