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 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 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 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 otype = self.lobj(okey).typ();
56 }
57 debug_assert!(otype.is_some());
58
59 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 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 pub fn type_expr(&mut self, e: &Expr, fctx: &mut FilesContext) -> TypeKey {
133 self.defined_type(e, None, fctx)
134 }
135
136 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 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 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 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] }
208 x if x == 1 => recv_list[0],
209 _ => unreachable!(),
210 };
211 recv_okey = Some(recv_var);
212
213 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 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 }
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 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, 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, 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 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), 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 }
476 }
477 let ftype = &ftype.clone();
478 let ty = self.indirect_type(ftype, fctx);
479 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 }
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 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 }
520 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 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 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 if ty == checker.invalid_type() {
580 continue; }
582 match checker.otype(typ::underlying_type(ty, checker.tc_objs)) {
583 typ::Type::Interface(embed) => {
584 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 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 checker.octx = ctx_backup;
603 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 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 self.otype_interface_mut(itype).set_empty_complete();
624 return itype;
625 }
626
627 let recv_type = if let Some(d) = def { d } else { itype };
629
630 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 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 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 let invalid_type = self.invalid_type();
706 let saved_context = self.octx.clone();
707 for minfo in sig_fix {
708 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 let old = self.otype_signature_mut(self.lobj(minfo.func().unwrap()).typ().unwrap());
718 let recv = *old.recv(); *old = sig_copy;
720 old.set_recv(recv); } 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 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 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 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 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 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 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 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}