1#![allow(dead_code)]
13use super::super::constant;
14use super::super::lookup;
15use super::super::obj::EntityType;
16use super::super::objects::{ObjKey, ScopeKey, TCObjects, TypeKey};
17use super::super::operand::{Operand, OperandMode};
18use super::super::scope::Scope;
19use super::super::typ::{self, Type};
20use super::check::{Checker, FilesContext, ObjContext};
21use super::interface::MethodInfo;
22use crate::SourceRead;
23use go_parser::ast::{self, Expr, FieldList, Node};
24use go_parser::{FuncTypeKey, IdentKey, Map, Pos, Token};
25use std::borrow::Borrow;
26
27impl<'a, S: SourceRead> Checker<'a, S> {
28 pub fn ident(
33 &mut self,
34 x: &mut Operand,
35 ikey: IdentKey,
36 def: Option<TypeKey>,
37 want_type: bool,
38 fctx: &mut FilesContext<S>,
39 ) {
40 x.mode = OperandMode::Invalid;
41 x.expr = Some(Expr::Ident(ikey));
42
43 let name = &self.ast_ident(ikey).name;
46 if let Some((skey, okey)) =
47 Scope::lookup_parent(&self.octx.scope.unwrap(), name, self.octx.pos, self.tc_objs)
48 {
49 self.result.record_use(ikey, okey);
50
51 let lobj = self.lobj(okey);
60 let pkg = lobj.pkg();
61 let mut otype = lobj.typ();
62 if otype.is_none() || (lobj.entity_type().is_type_name() && want_type) {
63 self.obj_decl(okey, def, fctx);
64 otype = self.lobj(okey).typ();
66 }
67 debug_assert!(otype.is_some());
68
69 if pkg.is_some() && pkg != Some(self.pkg) {
74 fctx.unused_dot_imports
75 .get_mut(&skey)
76 .unwrap()
77 .remove(&pkg.unwrap());
78 }
79
80 let lobj = self.lobj(okey);
81 let invalid_type = self.invalid_type();
82 match lobj.entity_type() {
83 EntityType::PkgName(_, _) => {
84 let pos = self.ast_ident(ikey).pos;
85 let msg = format!("use of package {} not in selector", lobj.name());
86 self.error(pos, msg);
87 return;
88 }
89 EntityType::Const(_) => {
90 self.add_decl_dep(okey);
91 if otype == Some(invalid_type) {
92 return;
93 }
94 if okey == *self.tc_objs.universe().iota() {
95 if self.octx.iota.is_none() {
96 let pos = self.ast_ident(ikey).pos;
97 self.error_str(pos, "cannot use iota outside constant declaration");
98 return;
99 }
100 x.mode = OperandMode::Constant(self.octx.iota.clone().unwrap());
101 } else {
102 x.mode = OperandMode::Constant(self.lobj(okey).const_val().clone());
103 }
104 }
105 EntityType::TypeName => x.mode = OperandMode::TypeExpr,
106 EntityType::Var(_) => {
107 if lobj.pkg() == Some(self.pkg) {
111 self.lobj_mut(okey)
112 .entity_type_mut()
113 .var_property_mut()
114 .used = true;
115 }
116 self.add_decl_dep(okey);
117 if otype == Some(invalid_type) {
118 return;
119 }
120 x.mode = OperandMode::Variable;
121 }
122 EntityType::Func(_) => {
123 self.add_decl_dep(okey);
124 x.mode = OperandMode::Value;
125 }
126 EntityType::Label(_) => unreachable!(),
127 EntityType::Builtin(id) => x.mode = OperandMode::Builtin(*id),
128 EntityType::Nil => x.mode = OperandMode::Value,
129 }
130 x.typ = otype;
131 } else {
132 let pos = self.ast_ident(ikey).pos;
133 if name == "_" {
134 self.error(pos, "cannot use _ as value or type".to_owned());
135 } else {
136 self.error(pos, format!("undeclared name: {}", name));
137 }
138 }
139 }
140
141 pub fn type_expr(&mut self, e: &Expr, fctx: &mut FilesContext<S>) -> TypeKey {
143 self.defined_type(e, None, fctx)
144 }
145
146 pub fn defined_type(
151 &mut self,
152 e: &Expr,
153 def: Option<TypeKey>,
154 fctx: &mut FilesContext<S>,
155 ) -> TypeKey {
156 if self.trace() {
157 let ed = self.new_dis(e);
158 self.trace_begin(ed.pos(), &format!("{}", ed));
159 }
160 let t = self.type_internal(e, def, fctx);
161 debug_assert!(typ::is_typed(t, self.tc_objs));
162 self.result
163 .record_type_and_value(e, OperandMode::TypeExpr, t);
164 if self.trace() {
165 let pos = e.pos(self.ast_objs);
166 self.trace_end(pos, &format!("=> {}", self.new_dis(&t)));
167 }
168 t
169 }
170
171 pub fn indirect_type(&mut self, e: &Expr, fctx: &mut FilesContext<S>) -> TypeKey {
176 fctx.push(*self.tc_objs.universe().indir());
177 let t = self.defined_type(e, None, fctx);
178 fctx.pop();
179 t
180 }
181
182 pub fn func_type(
184 &mut self,
185 recv: Option<&FieldList>,
186 ftype: FuncTypeKey,
187 fctx: &mut FilesContext<S>,
188 ) -> TypeKey {
189 let skey = self
190 .tc_objs
191 .new_scope(self.octx.scope, 0, 0, "function".to_owned(), true);
192 self.result.record_scope(&ftype, skey);
193
194 let (recv_list, _) = self.collect_params(skey, recv, false, fctx);
195 let ftype_val = &self.ast_objs.ftypes[ftype];
196 let (p, r) = (ftype_val.params.clone(), ftype_val.results.clone());
197 let (params, variadic) = self.collect_params(skey, Some(&p), true, fctx);
198 let (results, _) = self.collect_params(skey, r.as_ref(), false, fctx);
199
200 let mut recv_okey = None;
201 if recv.is_some() {
202 let invalid_type = self.invalid_type();
206 let recv_var = match recv_list.len() {
207 x if x == 0 => {
208 let pos = recv.unwrap().pos(self.ast_objs);
209 self.error_str(pos, "method is missing receiver");
210 self.tc_objs
211 .new_param_var(0, None, "".to_owned(), Some(invalid_type))
212 }
213 x if x > 1 => {
214 let pos = self.lobj(recv_list[recv_list.len() - 1]).pos();
215 self.error_str(pos, "method must have exactly one receiver");
216 recv_list[0] }
218 x if x == 1 => recv_list[0],
219 _ => unreachable!(),
220 };
221 recv_okey = Some(recv_var);
222
223 let recv_var_val = self.lobj(recv_var);
226 let recv_type = recv_var_val.typ().unwrap();
227 let (t, _) = lookup::try_deref(recv_type, self.tc_objs);
228 if t != invalid_type {
229 let err_msg = if let Some(n) = self.otype(t).try_as_named() {
230 if self.lobj(n.obj().unwrap()).pkg() != Some(self.pkg) {
234 Some("type not defined in this package")
235 } else {
236 match self.otype(n.underlying()) {
237 typ::Type::Basic(b) => {
238 if b.typ() == typ::BasicType::UnsafePointer {
239 Some("unsafe.Pointer")
240 } else {
241 None
242 }
243 }
244 typ::Type::Pointer(_) | typ::Type::Interface(_) => {
245 Some("pointer or interface type")
246 }
247 _ => None,
248 }
249 }
250 } else {
251 Some("basic or unnamed type")
252 };
253 if let Some(err) = err_msg {
254 let pos = recv_var_val.pos();
255 let td = self.new_dis(&recv_type);
256 self.error(pos, format!("invalid receiver {} ({})", td, err));
257 }
259 }
260 }
261
262 let params_tuple = self.tc_objs.new_t_tuple(params);
263 let results_tuple = self.tc_objs.new_t_tuple(results);
264 self.tc_objs
265 .new_t_signature(Some(skey), recv_okey, params_tuple, results_tuple, variadic)
266 }
267
268 fn type_internal(
271 &mut self,
272 e: &Expr,
273 def: Option<TypeKey>,
274 fctx: &mut FilesContext<S>,
275 ) -> TypeKey {
276 let set_underlying = |typ: Option<TypeKey>, tc_objs: &mut TCObjects| {
277 if let Some(d) = def {
278 tc_objs.types[d]
279 .try_as_named_mut()
280 .unwrap()
281 .set_underlying(typ.unwrap());
282 }
283 };
284 let pos = e.pos(self.ast_objs);
285 let result_t: Option<TypeKey> = match e {
286 Expr::Bad(_) => None,
287 Expr::Ident(i) => {
288 let mut x = Operand::new();
289 self.ident(&mut x, *i, def, true, fctx);
290 match x.mode {
291 OperandMode::TypeExpr => {
292 set_underlying(x.typ, self.tc_objs);
293 x.typ
294 }
295 OperandMode::Invalid => None, OperandMode::NoValue => {
297 error_operand!(x, "{} used as type", self);
298 None
299 }
300 _ => {
301 error_operand!(x, "{} is not a type", self);
302 None
303 }
304 }
305 }
306 Expr::Selector(s) => {
307 let mut x = Operand::new();
308 self.selector(&mut x, s, fctx);
309 match x.mode {
310 OperandMode::TypeExpr => {
311 set_underlying(x.typ, self.tc_objs);
312 x.typ
313 }
314 OperandMode::Invalid => None, OperandMode::NoValue => {
316 error_operand!(x, "{} used as type", self);
317 None
318 }
319 _ => {
320 error_operand!(x, "{} is not a type", self);
321 None
322 }
323 }
324 }
325 Expr::Paren(p) => Some(self.defined_type(&p.expr, def, fctx)),
326 Expr::Array(a) => {
327 if let Some(l) = &a.len {
328 let len = self.array_len(&l, fctx);
329 let elem = self.type_expr(&a.elt, fctx);
330 let t = self.tc_objs.new_t_array(elem, len);
331 set_underlying(Some(t), self.tc_objs);
332 Some(t)
333 } else {
334 let elem = self.indirect_type(&a.elt, fctx);
335 let t = self.tc_objs.new_t_slice(elem);
336 set_underlying(Some(t), self.tc_objs);
337 Some(t)
338 }
339 }
340 Expr::Struct(s) => {
341 let t = self.struct_type(s, fctx);
342 set_underlying(Some(t), self.tc_objs);
343 Some(t)
344 }
345 Expr::Star(s) => {
346 let base = self.indirect_type(&s.expr, fctx);
347 let t = self.tc_objs.new_t_pointer(base);
348 set_underlying(Some(t), self.tc_objs);
349 Some(t)
350 }
351 Expr::Func(f) => {
352 let t = self.func_type(None, *f, fctx);
353 set_underlying(Some(t), self.tc_objs);
354 Some(t)
355 }
356 Expr::Interface(_) => {
357 let t = self.interface_type(e, def, fctx);
358 set_underlying(Some(t), self.tc_objs);
359 Some(t)
360 }
361 Expr::Map(m) => {
362 let k = self.indirect_type(&m.key, fctx);
363 let v = self.indirect_type(&m.val, fctx);
364 let t = self.tc_objs.new_t_map(k, v);
365 set_underlying(Some(t), self.tc_objs);
366
367 let pos = m.key.pos(self.ast_objs);
368 let f = move |checker: &mut Checker<S>, _: &mut FilesContext<S>| {
369 if !typ::comparable(k, checker.tc_objs) {
370 let td = checker.new_dis(&k);
371 checker.error(pos, format!("invalid map key type {}", td));
372 }
373 };
374 fctx.later(Box::new(f));
375
376 Some(t)
377 }
378 Expr::Chan(chan) => {
379 let dir = match chan.dir {
380 ast::ChanDir::Send => typ::ChanDir::SendOnly,
381 ast::ChanDir::Recv => typ::ChanDir::RecvOnly,
382 ast::ChanDir::SendRecv => typ::ChanDir::SendRecv,
383 };
384 let elem = self.indirect_type(&chan.val, fctx);
385 let t = self.tc_objs.new_t_chan(dir, elem);
386 set_underlying(Some(t), self.tc_objs);
387 Some(t)
388 }
389 _ => {
390 let ed = self.new_dis(e);
391 self.error(pos, format!("{} is not a type", ed));
392 None
393 }
394 };
395 if let Some(t) = result_t {
396 t
397 } else {
398 let invalid_type = self.invalid_type();
399 set_underlying(Some(invalid_type), self.tc_objs);
400 invalid_type
401 }
402 }
403
404 pub fn type_or_nil(&mut self, e: &Expr, fctx: &mut FilesContext<S>) -> Option<TypeKey> {
408 let mut x = Operand::new();
409 self.raw_expr(&mut x, e, None, fctx);
410 let invalid_type = self.invalid_type();
411 match x.mode {
412 OperandMode::Invalid => Some(invalid_type), OperandMode::NoValue => {
414 error_operand!(x, "{} used as type", self);
415 Some(invalid_type)
416 }
417 OperandMode::TypeExpr => x.typ,
418 _ => {
419 if x.mode == OperandMode::Value && x.is_nil(self.tc_objs.universe()) {
420 None
421 } else {
422 error_operand!(x, "{} is not a type", self);
423 Some(invalid_type)
424 }
425 }
426 }
427 }
428
429 fn array_len(&mut self, e: &Expr, fctx: &mut FilesContext<S>) -> Option<u64> {
430 let mut x = Operand::new();
431 self.expr(&mut x, e, fctx);
432 if let OperandMode::Constant(v) = &x.mode {
433 let t = x.typ.unwrap();
434 if typ::is_untyped(t, self.tc_objs) || typ::is_integer(t, self.tc_objs) {
435 let int = v.to_int();
436 let int_type = self
437 .otype(self.basic_type(typ::BasicType::Int))
438 .try_as_basic()
439 .unwrap();
440 if let constant::Value::Int(_) = int.borrow() {
441 if int.representable(int_type, None) {
442 let (n, exact) = int.int_as_u64();
443 if exact {
444 return Some(n);
445 } else {
446 error_operand!(x, "invalid array length {}", self);
447 return None;
448 }
449 }
450 }
451 }
452 error_operand!(x, "array length {} must be integer", self);
453 } else {
454 if x.mode != OperandMode::Invalid {
455 error_operand!(x, "array length {} must be constant", self);
456 }
457 }
458 None
459 }
460
461 fn collect_params(
462 &mut self,
463 skey: ScopeKey,
464 fl: Option<&FieldList>,
465 variadic_ok: bool,
466 fctx: &mut FilesContext<S>,
467 ) -> (Vec<ObjKey>, bool) {
468 if let Some(l) = fl {
469 let (mut named, mut anonymous, mut variadic) = (false, false, false);
470 let mut params = Vec::new();
471 for (i, fkey) in l.list.iter().enumerate() {
472 let field = &self.ast_objs.fields[*fkey];
473 let mut ftype = &field.typ;
474 let field_names = field.names.clone();
475 if let Expr::Ellipsis(elli) = ftype {
476 ftype = elli.elt.as_ref().unwrap();
477 if variadic_ok && i == l.list.len() - 1 && field_names.len() <= 1 {
478 variadic = true
479 } else {
480 self.soft_error(
481 elli.pos,
482 "can only use ... with final parameter in list".to_owned(),
483 )
484 }
486 }
487 let ftype = &ftype.clone();
488 let ty = self.indirect_type(ftype, fctx);
489 if field_names.len() > 0 {
492 for name in field_names.iter() {
493 let ident = &self.ast_objs.idents[*name];
494 if ident.name == "" {
495 self.invalid_ast(ident.pos, "anonymous parameter");
496 }
498 let par_name = ident.name.clone();
499 let par = self.tc_objs.new_param_var(
500 ident.pos,
501 Some(self.pkg),
502 par_name,
503 Some(ty),
504 );
505 let scope_pos = self.scope(skey).pos();
506 self.declare(skey, Some(*name), par, scope_pos);
507 params.push(par);
508 }
509 named = true;
510 } else {
511 let par = self.tc_objs.new_param_var(
513 ftype.pos(self.ast_objs),
514 Some(self.pkg),
515 "".to_owned(),
516 Some(ty),
517 );
518 self.result.record_implicit(fkey, par);
519 params.push(par);
520 anonymous = true;
521 }
522 }
523 if named && anonymous {
524 self.invalid_ast(
525 l.pos(self.ast_objs),
526 "list contains both named and anonymous parameters",
527 )
528 }
530 if variadic {
534 let last = params[params.len() - 1];
535 let t = self.tc_objs.new_t_slice(self.lobj(last).typ().unwrap());
536 self.lobj_mut(last).set_type(Some(t));
537 let e = &self.ast_objs.fields[l.list[l.list.len() - 1]].typ;
538 self.result
539 .record_type_and_value(e, OperandMode::TypeExpr, t);
540 }
541 (params, variadic)
542 } else {
543 (vec![], false)
544 }
545 }
546
547 fn interface_type(
548 &mut self,
549 expr: &ast::Expr,
550 def: Option<TypeKey>,
551 fctx: &mut FilesContext<S>,
552 ) -> TypeKey {
553 let iface = match expr {
554 Expr::Interface(i) => i,
555 _ => unreachable!(),
556 };
557 if iface.methods.list.len() == 0 {
558 return self.tc_objs.new_t_empty_interface();
559 }
560 let trace = self.trace();
561
562 let itype = self.tc_objs.new_t_interface(vec![], vec![]);
563 let context_clone = self.octx.clone();
570 let expr_clone = expr.clone();
571 let iface_clone = iface.clone();
572 let f = move |checker: &mut Checker<S>, fctx: &mut FilesContext<S>| {
573 if trace {
574 let ed = checker.new_dis(&expr_clone);
575 let msg = format!("-- delayed checking embedded interfaces of {}", ed);
576 checker.trace_begin(iface_clone.interface, &msg);
577 }
578 let ctx_backup = std::mem::replace(&mut checker.octx, context_clone);
580
581 let mut embeds = vec![];
582 for fkey in iface_clone.methods.list.iter() {
583 let field = &checker.ast_objs.fields[*fkey];
584 if field.names.len() == 0 {
585 let texpr = field.typ.clone();
586 let ty = checker.indirect_type(&texpr, fctx);
587 if ty == checker.invalid_type() {
591 continue; }
593 match checker.otype(typ::underlying_type(ty, checker.tc_objs)) {
594 typ::Type::Interface(embed) => {
595 assert!(embed.all_methods().is_some());
597 }
598 _ => {
599 let pos = texpr.pos(checker.ast_objs);
600 let td = checker.new_dis(&ty);
601 checker.error(pos, format!("{} is not an interface", td));
602 continue;
603 }
604 }
605 embeds.push(ty);
607 }
608 }
609 embeds.sort_by(compare_by_type_name!(checker.tc_objs));
610 *checker.otype_interface_mut(itype).embeddeds_mut() = embeds;
611
612 checker.octx = ctx_backup;
614 if trace {
616 checker.trace_end(
617 iface_clone.interface,
618 "-- end of delayed checking embedded interfaces",
619 )
620 }
621 };
622 fctx.later(Box::new(f));
623
624 let (tname, path) = if let Some(d) = def {
626 let t = *self.otype(d).try_as_named().unwrap().obj();
627 (t, vec![t.unwrap()])
628 } else {
629 (None, vec![])
630 };
631 let info = self.info_from_type_lit(self.octx.scope.unwrap(), iface, tname, &path, fctx);
632 if info.is_none() || info.as_ref().unwrap().as_ref().borrow().is_empty() {
633 self.otype_interface_mut(itype).set_empty_complete();
635 return itype;
636 }
637
638 let recv_type = if let Some(d) = def { d } else { itype };
640
641 let f = move |checker: &mut Checker<S>, _: &mut FilesContext<S>| {
645 for m in checker.otype_interface(itype).methods().clone().iter() {
646 let t = checker.lobj(*m).typ().unwrap();
647 let o = checker.otype_signature(t).recv().unwrap();
648 checker.lobj_mut(o).set_type(Some(recv_type));
649 }
650 };
651 fctx.later(Box::new(f));
652
653 let info_ref = info.as_ref().unwrap().as_ref().borrow();
655 let explicits = info_ref.explicits;
656 let mut sig_fix: Vec<MethodInfo> = vec![];
657 for (i, minfo) in info_ref.methods.iter().enumerate() {
658 let fun = if minfo.func().is_none() {
659 let name_key = self.ast_objs.fields[minfo.src().unwrap()].names[0];
660 let ident = self.ast_ident(name_key);
661 let name = ident.name.clone();
662 let pos = ident.pos;
663 let recv_key =
687 self.tc_objs
688 .new_var(pos, Some(self.pkg), "".to_owned(), Some(recv_type));
689 let empty_tuple = *self.tc_objs.universe().no_value_tuple();
690 let sig_key = self.tc_objs.new_t_signature(
691 None,
692 Some(recv_key),
693 empty_tuple,
694 empty_tuple,
695 false,
696 );
697 let fun_key = self
698 .tc_objs
699 .new_func(pos, Some(self.pkg), name, Some(sig_key));
700 minfo.set_func(fun_key);
701 self.result.record_def(name_key, Some(fun_key));
702 sig_fix.push(minfo.clone());
703 fun_key
704 } else {
705 minfo.func().unwrap()
706 };
707 let itype_val = self.otype_interface_mut(itype);
708 if i < explicits {
709 itype_val.methods_mut().push(fun);
710 }
711 itype_val.all_methods_push(fun);
712 }
713 let invalid_type = self.invalid_type();
718 let saved_context = self.octx.clone();
719 for minfo in sig_fix {
720 self.octx = ObjContext::new();
723 self.octx.scope = minfo.scope();
724 let ftype = self.ast_objs.fields[minfo.src().unwrap()].typ.clone();
725 let ty = self.indirect_type(&ftype, fctx);
726 if let Some(sig) = self.otype(ty).try_as_signature() {
727 let sig_copy = *sig;
728 let old = self.otype_signature_mut(self.lobj(minfo.func().unwrap()).typ().unwrap());
730 let recv = *old.recv(); *old = sig_copy;
732 old.set_recv(recv); } else {
734 if ty != invalid_type {
735 let pos = ftype.pos(self.ast_objs);
736 let td = self.new_dis(&ty);
737 self.invalid_ast(pos, &format!("{} is not a method signature", td));
738 }
739 }
740 }
741 self.octx = saved_context;
742
743 let itype_val = self.otype_interface(itype);
745 let mut methods = itype_val.methods().clone();
746 methods.sort_by(compare_by_method_name!(self.tc_objs));
747 *self.otype_interface_mut(itype).methods_mut() = methods;
748 let itype_val = self.otype_interface(itype);
750 if itype_val.all_methods().is_none() {
751 itype_val.set_empty_complete();
752 } else {
753 itype_val
754 .all_methods_mut()
755 .as_mut()
756 .unwrap()
757 .sort_by(compare_by_method_name!(self.tc_objs));
758 }
759
760 itype
761 }
762
763 fn tag(&self, t: &Option<Expr>) -> Option<String> {
764 if let Some(e) = t {
765 if let Expr::BasicLit(bl) = e {
766 if let Token::STRING(data) = &bl.token {
767 return Some(data.as_str_str().1.clone());
768 }
769 self.invalid_ast(
770 e.pos(self.ast_objs),
771 &format!("incorrect tag syntax: {}", bl.token),
772 )
773 } else {
774 unreachable!()
775 }
776 }
777 None
778 }
779
780 fn declare_in_set(&self, set: &mut Map<String, ObjKey>, fld: ObjKey, pos: Pos) -> bool {
781 if let Some(okey) = self.insert_obj_to_set(set, fld) {
782 self.error(pos, format!("{} redeclared", self.lobj(fld).name()));
783 self.report_alt_decl(okey);
784 false
785 } else {
786 true
787 }
788 }
789
790 fn add_field(
791 &mut self,
792 fields: &mut Vec<ObjKey>,
793 tags: &mut Option<Vec<Option<String>>>,
794 oset: &mut Map<String, ObjKey>,
795 ty: TypeKey,
796 tag: Option<String>,
797 ikey: IdentKey,
798 embedded: bool,
799 pos: Pos,
800 ) {
801 if tag.is_some() && tags.is_none() {
802 *tags = Some(vec![]);
803 }
804 if tags.is_some() {
805 tags.as_mut().unwrap().push(tag);
806 }
807 let name = &self.ast_ident(ikey).name.clone();
808 let fld = self
809 .tc_objs
810 .new_field(pos, Some(self.pkg), name.clone(), Some(ty), embedded);
811 if name == "_" || self.declare_in_set(oset, fld, pos) {
812 fields.push(fld);
813 self.result.record_def(ikey, Some(fld));
814 }
815 }
816
817 fn embedded_field_ident(e: &Expr) -> Option<IdentKey> {
818 match e {
819 Expr::Ident(i) => Some(*i),
820 Expr::Star(s) => match s.expr {
821 Expr::Star(_) => None,
823 _ => Checker::<S>::embedded_field_ident(&s.expr),
824 },
825 Expr::Selector(s) => Some(s.sel),
826 _ => None,
827 }
828 }
829
830 fn struct_type(&mut self, st: &ast::StructType, fctx: &mut FilesContext<S>) -> TypeKey {
831 let fields = &st.fields.list;
832 if fields.len() == 0 {
833 return self.tc_objs.new_t_struct(vec![], None);
834 }
835
836 let mut field_objs: Vec<ObjKey> = vec![];
837 let mut tags: Option<Vec<Option<String>>> = None;
838 let mut oset: Map<String, ObjKey> = Map::new();
839 for f in fields {
840 let field = &self.ast_objs.fields[*f];
841 let fnames = field.names.clone();
842 let ftag = self.tag(&field.tag);
843 let ftype = field.typ.clone();
844 let ty = self.type_expr(&ftype, fctx);
845 if fnames.len() > 0 {
846 for name in fnames.iter() {
848 self.add_field(
849 &mut field_objs,
850 &mut tags,
851 &mut oset,
852 ty,
853 ftag.clone(),
854 *name,
855 false,
856 self.ast_ident(*name).pos,
857 );
858 }
859 } else {
860 let field = &self.ast_objs.fields[*f];
864 let pos = field.typ.pos(self.ast_objs);
865 let invalid_type = self.invalid_type();
866 let mut add_invalid = |c: &mut Checker<S>, ident: IdentKey| {
867 c.add_field(
868 &mut field_objs,
869 &mut tags,
870 &mut oset,
871 invalid_type,
872 None,
873 ident,
874 false,
875 pos,
876 );
877 };
878 if let Some(ident) = Checker::<S>::embedded_field_ident(&field.typ) {
879 let (t, is_ptr) = lookup::try_deref(ty, self.tc_objs);
880 let t = typ::underlying_type(t, self.tc_objs);
883 let type_val = self.otype(t);
884 match type_val {
885 typ::Type::Basic(_) if t == invalid_type => {
886 add_invalid(self, ident);
888 }
889 typ::Type::Basic(b) if b.typ() == typ::BasicType::UnsafePointer => {
890 self.error_str(pos, "embedded field type cannot be unsafe.Pointer");
891 add_invalid(self, ident);
892 }
893 typ::Type::Pointer(_) => {
894 self.error_str(pos, "embedded field type cannot be a pointer");
895 add_invalid(self, ident);
896 }
897 typ::Type::Interface(_) if is_ptr => {
898 self.error_str(
899 pos,
900 "embedded field type cannot be a pointer to an interface",
901 );
902 add_invalid(self, ident);
903 }
904 _ => self.add_field(
905 &mut field_objs,
906 &mut tags,
907 &mut oset,
908 ty,
909 ftag.clone(),
910 ident,
911 true,
912 pos,
913 ),
914 }
915 } else {
916 let ed = self.new_dis(&field.typ);
917 self.invalid_ast(pos, &format!("embedded field type {} has no name", ed));
918 let ident = self.ast_objs.idents.insert(ast::Ident::blank(pos));
919 add_invalid(self, ident);
920 }
921 }
922 }
923
924 self.tc_objs.new_t_struct(field_objs, tags)
925 }
926}