1#![allow(dead_code)]
13use crate::SourceRead;
14
15use super::super::constant;
16use super::super::obj::{EntityType, LangObj};
17use super::super::objects::{DeclInfoKey, ScopeKey, TypeKey};
18use super::super::operand::{Operand, OperandMode};
19use super::super::typ::{self, BasicInfo, BasicType, ChanDir, Type};
20use super::super::universe::ExprKind;
21use super::check::{Checker, FilesContext, ObjContext};
22use constant::Value;
23use go_parser::ast::{
24 BasicLit, BlockStmt, CaseClause, CommClause, Expr, Ident, Node, Stmt, TypeAssertExpr,
25};
26use go_parser::{AstObjects, FuncDeclKey, IdentKey, Map, Pos, Token};
27use ordered_float;
28use std::rc::Rc;
29
30type F64 = ordered_float::OrderedFloat<f64>;
31
32#[derive(Clone, Copy, Debug)]
33struct StmtContext {
34 break_ok: bool,
35 continue_ok: bool,
36 fallthrough_ok: bool,
37 final_switch_case: bool,
38}
39
40impl StmtContext {
41 fn new() -> StmtContext {
42 StmtContext {
43 break_ok: false,
44 continue_ok: false,
45 fallthrough_ok: false,
46 final_switch_case: false,
47 }
48 }
49}
50
51#[derive(Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
52enum GoVal {
53 Int64(i64),
54 Uint64(u64),
55 Float64(F64),
56 Str(String),
57 Invalid,
58}
59
60impl GoVal {
61 fn with_const(v: &Value) -> GoVal {
62 match v {
63 Value::Int(_) => match v.int_as_i64() {
64 (int, true) => GoVal::Int64(int),
65 _ => match v.int_as_u64() {
66 (uint, true) => GoVal::Uint64(uint),
67 _ => GoVal::Invalid,
68 },
69 },
70 Value::Float(_) => match v.num_as_f64() {
71 (f, true) => GoVal::Float64(f),
72 _ => GoVal::Invalid,
73 },
74 Value::Str(_) => GoVal::Str(v.str_as_string()),
75 _ => GoVal::Invalid,
76 }
77 }
78}
79
80struct PosType {
81 pos: Pos,
82 typ: TypeKey,
83}
84
85type ValueMap = Map<GoVal, Vec<PosType>>;
86
87pub enum BodyContainer {
88 FuncLitExpr(Expr),
89 FuncDecl(FuncDeclKey),
90}
91
92impl BodyContainer {
93 pub fn get_block<'a>(&'a self, objs: &'a AstObjects) -> &'a Rc<BlockStmt> {
94 match self {
95 BodyContainer::FuncLitExpr(e) => match e {
96 Expr::FuncLit(fl) => &fl.body,
97 _ => unreachable!(),
98 },
99 BodyContainer::FuncDecl(key) => objs.fdecls[*key].body.as_ref().unwrap(),
100 }
101 }
102}
103
104impl<'a, S: SourceRead> Checker<'a, S> {
105 pub fn func_body(
106 &mut self,
107 di: Option<DeclInfoKey>,
108 name: &str,
109 sig: TypeKey,
110 body: BodyContainer,
111 iota: Option<constant::Value>,
112 fctx: &mut FilesContext<S>,
113 ) {
114 let block = body.get_block(self.ast_objs);
115 let (pos, end) = (block.pos(), block.end());
116 if self.trace() {
117 let td = self.new_dis(&sig);
118 self.print_trace(pos, &format!("--- {}: {}", name, td));
119 }
120 let scope_key = self.otype(sig).try_as_signature().unwrap().scope().unwrap();
122 let scope = &mut self.tc_objs.scopes[scope_key];
123 scope.set_pos(pos);
124 scope.set_end(end);
125
126 let mut octx = ObjContext::new();
127 octx.decl = di;
128 octx.scope = Some(scope_key);
129 octx.iota = iota;
130 octx.sig = Some(sig);
131 std::mem::swap(&mut self.octx, &mut octx);
132 let old_indent = self.indent.replace(0);
133
134 let sctx = StmtContext::new();
135 let block2 = block.clone();
136 self.stmt_list(&block2.list, &sctx, fctx);
137
138 if self.octx.has_label {
139 self.labels(&block2);
140 }
141
142 let ret_pos = block2.r_brace;
143 let stmt = Stmt::Block(block2);
144 let sig_val = self.otype(sig).try_as_signature().unwrap();
145 if sig_val.results_count(self.tc_objs) > 0 && !self.is_terminating(&stmt, None) {
146 self.error_str(ret_pos, "missing return");
147 }
148
149 self.usage(scope_key);
152
153 std::mem::swap(&mut self.octx, &mut octx); self.indent.replace(old_indent); if self.trace() {
156 self.print_trace(end, "--- <end>");
157 }
158 }
159
160 fn usage(&self, skey: ScopeKey) {
161 let sval = &self.tc_objs.scopes[skey];
162 let mut unused: Vec<&LangObj> = sval
163 .elems()
164 .iter()
165 .filter_map(|(_, &okey)| {
166 let lobj = &self.tc_objs.lobjs[okey];
167 match lobj.entity_type() {
168 EntityType::Var(var) => {
169 if !var.used {
170 Some(lobj)
171 } else {
172 None
173 }
174 }
175 _ => None,
176 }
177 })
178 .collect();
179 unused.sort_by(|a, b| a.pos().cmp(&b.pos()));
180
181 for lo in unused.iter() {
182 self.soft_error(lo.pos(), format!("{} declared but not used", lo.name()));
183 }
184 for skey in sval.children().iter() {
185 if !self.tc_objs.scopes[*skey].is_func() {
188 self.usage(*skey);
189 }
190 }
191 }
192
193 fn simple_stmt(&mut self, s: Option<&Stmt>, fctx: &mut FilesContext<S>) {
194 if let Some(s) = s {
195 let sctx = StmtContext::new();
196 self.stmt(s, &sctx, fctx);
197 }
198 }
199
200 fn stmt_list(&mut self, list: &Vec<Stmt>, sctx: &StmtContext, fctx: &mut FilesContext<S>) {
201 let index = list
203 .iter()
204 .enumerate()
205 .rev()
206 .find_map(|(i, x)| match x {
207 Stmt::Empty(_) => None,
208 _ => Some(i + 1),
209 })
210 .unwrap_or(list.len());
211 for (i, s) in list[0..index].iter().enumerate() {
212 let mut inner = *sctx;
213 inner.fallthrough_ok = sctx.fallthrough_ok && i + 1 == index;
214 self.stmt(s, &inner, fctx);
215 }
216 }
217
218 fn multiple_defaults(&self, list: &Vec<Stmt>) {
219 let mut first: Option<&Stmt> = None;
220 for s in list.iter() {
221 let d_op = match s {
222 Stmt::Case(cc) => cc.list.as_ref().map_or(Some(s), |_| None),
223 Stmt::Comm(cc) => cc.comm.as_ref().map_or(Some(s), |_| None),
224 _ => {
225 self.invalid_ast(s.pos(self.ast_objs), "case/communication clause expected");
226 None
227 }
228 };
229 if let Some(d) = d_op {
230 match first {
231 Some(f) => self.error(
232 d.pos(self.ast_objs),
233 format!(
234 "multiple defaults (first at {})",
235 self.position(f.pos(self.ast_objs))
236 ),
237 ),
238 None => first = Some(d),
239 }
240 }
241 }
242 }
243
244 fn open_scope(&mut self, s: &Stmt, comment: String) {
245 let scope = self.tc_objs.new_scope(
246 self.octx.scope,
247 s.pos(self.ast_objs),
248 s.end(self.ast_objs),
249 comment,
250 false,
251 );
252 self.result.record_scope(s, scope);
253 self.octx.scope = Some(scope);
254 }
255
256 fn close_scope(&mut self) {
257 self.octx.scope = *self.tc_objs.scopes[self.octx.scope.unwrap()].parent();
258 }
259
260 fn assign_op(op: &Token) -> Option<Token> {
261 match op {
262 Token::ADD_ASSIGN => Some(Token::ADD),
263 Token::SUB_ASSIGN => Some(Token::SUB),
264 Token::MUL_ASSIGN => Some(Token::MUL),
265 Token::QUO_ASSIGN => Some(Token::QUO),
266 Token::REM_ASSIGN => Some(Token::REM),
267 Token::AND_ASSIGN => Some(Token::AND),
268 Token::OR_ASSIGN => Some(Token::OR),
269 Token::XOR_ASSIGN => Some(Token::XOR),
270 Token::SHL_ASSIGN => Some(Token::SHL),
271 Token::SHR_ASSIGN => Some(Token::SHR),
272 Token::AND_NOT_ASSIGN => Some(Token::AND_NOT),
273 _ => None,
274 }
275 }
276
277 fn suspended_call(&mut self, kw: &str, call: &Expr, fctx: &mut FilesContext<S>) {
278 let x = &mut Operand::new();
279 let msg = match self.raw_expr(x, call, None, fctx) {
280 ExprKind::Conversion => "requires function call, not conversion",
281 ExprKind::Expression => "discards result of",
282 ExprKind::Statement => return,
283 };
284 let xd = self.new_dis(x);
285 self.error(xd.pos(), format!("{} {} {}", kw, msg, xd));
286 }
287
288 fn case_values(
289 &mut self,
290 x: &mut Operand,
291 values: &Option<Vec<Expr>>,
292 seen: &mut ValueMap,
293 fctx: &mut FilesContext<S>,
294 ) {
295 if values.is_none() {
296 return;
297 }
298 for e in values.as_ref().unwrap().iter() {
299 let v = &mut Operand::new();
300 self.expr(v, e, fctx);
301 if x.invalid() || v.invalid() {
302 continue;
303 }
304 self.convert_untyped(v, x.typ.unwrap(), fctx);
305 if v.invalid() {
306 continue;
307 }
308 let res = &mut v.clone();
310 self.comparison(res, x, &Token::EQL, fctx);
311 if res.invalid() {
312 continue;
313 }
314 if let OperandMode::Constant(val) = &v.mode {
315 match GoVal::with_const(val) {
317 GoVal::Invalid => {}
318 gov => {
319 let entry = seen.entry(gov).or_insert(vec![]);
320 if let Some(pt) = entry
321 .iter()
322 .find(|x| typ::identical(v.typ.unwrap(), x.typ, self.tc_objs))
323 {
324 let vd = self.new_dis(v);
325 self.error(
326 vd.pos(),
327 format!("duplicate case {} in expression switch", vd),
328 );
329 self.error_str(pt.pos, "\tprevious case");
330 continue;
331 }
332 entry.push(PosType {
333 pos: v.pos(self.ast_objs),
334 typ: v.typ.unwrap(),
335 });
336 }
337 }
338 }
339 }
340 }
341
342 fn case_types(
343 &mut self,
344 x: &mut Operand,
345 xtype: TypeKey,
346 types: &Option<Vec<Expr>>,
347 seen: &mut Map<Option<TypeKey>, Pos>,
348 fctx: &mut FilesContext<S>,
349 ) -> Option<TypeKey> {
350 if types.is_none() {
351 return None;
352 }
353 types
354 .as_ref()
355 .unwrap()
356 .iter()
357 .filter_map(|e| {
358 let t = self.type_or_nil(e, fctx);
359 if t == Some(self.invalid_type()) {
360 return None;
361 }
362 if let Some((_, &pos)) = seen
363 .iter()
364 .find(|(&t2, _)| typ::identical_o(t, t2, self.tc_objs))
365 {
366 let ts = t.map_or("nil".to_owned(), |x| self.new_dis(&x).to_string());
367 self.error(
368 e.pos(self.ast_objs),
369 format!("duplicate case {} in type switch", ts),
370 );
371 self.error_str(pos, "\tprevious case");
372 return None;
373 }
374 let pos = e.pos(self.ast_objs);
375 seen.insert(t, pos);
376 if let Some(t) = t {
377 self.type_assertion(Some(pos), x, xtype, t, fctx);
378 }
379 Some(t)
380 })
381 .last()
382 .flatten()
383 }
384
385 fn stmt(&mut self, stmt: &Stmt, ctx: &StmtContext, fctx: &mut FilesContext<S>) {
386 let begin_scope = self.octx.scope;
387 let begin_delayed_count = fctx.delayed_count();
388
389 self.stmt_impl(stmt, ctx, fctx);
390
391 fctx.process_delayed(begin_delayed_count, self);
392 debug_assert_eq!(begin_scope, self.octx.scope);
393 }
394
395 fn stmt_impl(&mut self, stmt: &Stmt, ctx: &StmtContext, fctx: &mut FilesContext<S>) {
396 let mut inner_ctx = ctx.clone();
397 inner_ctx.fallthrough_ok = false;
398 inner_ctx.final_switch_case = false;
399 match stmt {
400 Stmt::Bad(_) | Stmt::Empty(_) => {} Stmt::Decl(d) => self.decl_stmt((**d).clone(), fctx),
402 Stmt::Labeled(lkey) => {
403 self.octx.has_label = true;
404 let s = &self.ast_objs.l_stmts[*lkey].stmt.clone();
405 self.stmt(&s, ctx, fctx);
406 }
407 Stmt::Expr(e) => {
408 let x = &mut Operand::new();
412 let kind = self.raw_expr(x, e, None, fctx);
413 let msg = match &x.mode {
414 OperandMode::Builtin(_) => "must be called",
415 OperandMode::TypeExpr => "is not an expression",
416 _ => {
417 if kind == ExprKind::Statement {
418 return;
419 }
420 "is not used"
421 }
422 };
423 let xd = self.new_dis(x);
424 self.error(xd.pos(), format!("{} {}", xd, msg));
425 }
426 Stmt::Send(ss) => {
427 let (ch, x) = (&mut Operand::new(), &mut Operand::new());
428 self.expr(ch, &ss.chan, fctx);
429 self.expr(x, &ss.val, fctx);
430 if ch.invalid() || x.invalid() {
431 return;
432 }
433 let chtype = ch.typ.unwrap();
434 let under_chtype = typ::underlying_type(chtype, self.tc_objs);
435 if let Some(chan) = self.otype(under_chtype).try_as_chan() {
436 if chan.dir() == typ::ChanDir::RecvOnly {
437 let td = self.new_dis(&under_chtype);
438 self.invalid_op(
439 ss.arrow,
440 &format!("cannot send to receive-only type {}", td),
441 );
442 } else {
443 let ty = Some(chan.elem());
444 self.assignment(x, ty, "send", fctx);
445 }
446 } else {
447 let td = self.new_dis(&chtype);
448 self.invalid_op(ss.arrow, &format!("cannot send to non-chan type {}", td));
449 }
450 }
451 Stmt::IncDec(ids) => {
452 let op = match &ids.token {
453 Token::INC => Token::ADD,
454 Token::DEC => Token::SUB,
455 _ => {
456 self.invalid_ast(
457 ids.token_pos,
458 &format!("unknown inc/dec operation {}", ids.token),
459 );
460 return;
461 }
462 };
463 let x = &mut Operand::new();
464 self.expr(x, &ids.expr, fctx);
465 if x.invalid() {
466 return;
467 }
468 if !typ::is_numeric(x.typ.unwrap(), self.tc_objs) {
469 let ed = self.new_dis(&ids.expr);
470 let td = self.new_dis(x.typ.as_ref().unwrap());
471 self.invalid_op(
472 ed.pos(),
473 &format!("{}{} (non-numeric type {})", ed, ids.token, td),
474 );
475 return;
476 }
477 let one = Expr::BasicLit(Rc::new(BasicLit {
478 pos: x.pos(self.ast_objs),
479 token: Token::int1(),
480 }));
481 self.binary(x, None, &ids.expr, &one, &op, fctx);
482 if x.invalid() {
483 return;
484 }
485 self.assign_var(&ids.expr, x, fctx);
486 }
487 Stmt::Assign(askey) => {
488 let astmt = &self.ast_objs.a_stmts[*askey];
489 match &astmt.token {
490 Token::ASSIGN | Token::DEFINE => {
491 if astmt.lhs.len() == 0 {
492 let pos = astmt.pos(self.ast_objs);
493 self.invalid_ast(pos, "missing lhs in assignment");
494 return;
495 }
496 let (lhs, rhs, pos) =
497 (astmt.lhs.clone(), astmt.rhs.clone(), astmt.token_pos);
498 if astmt.token == Token::DEFINE {
499 self.short_var_decl(&lhs, &rhs, pos, fctx);
500 } else {
501 self.assign_vars(&lhs, &rhs, fctx);
502 }
503 }
504 _ => {
505 if astmt.lhs.len() != 1 || astmt.rhs.len() != 1 {
507 self.error(
508 astmt.token_pos,
509 format!(
510 "assignment operation {} requires single-valued expressions",
511 astmt.token
512 ),
513 );
514 return;
515 }
516 let op = Checker::<S>::assign_op(&astmt.token);
517 if op.is_none() {
518 self.invalid_ast(
519 astmt.token_pos,
520 &format!("unknown assignment operation {}", astmt.token),
521 );
522 return;
523 }
524 let (lhs, rhs, op) =
525 (astmt.lhs[0].clone(), astmt.rhs[0].clone(), op.unwrap());
526 let x = &mut Operand::new();
527 self.binary(x, None, &lhs, &rhs, &op, fctx);
528 if x.invalid() {
529 return;
530 }
531 self.assign_var(&lhs, x, fctx);
532 }
533 }
534 }
535 Stmt::Go(gs) => self.suspended_call("go", &gs.call, fctx),
536 Stmt::Defer(ds) => self.suspended_call("defer", &ds.call, fctx),
537 Stmt::Return(rs) => {
538 let reskey = self
539 .otype(self.octx.sig.unwrap())
540 .try_as_signature()
541 .unwrap()
542 .results();
543 let res = self.otype(reskey).try_as_tuple().unwrap();
544 if res.vars().len() > 0 {
545 if rs.results.len() == 0 && self.lobj(res.vars()[0]).name() != "" {
548 for &okey in res.vars().iter() {
552 let lobj = self.lobj(okey);
553 if let Some(alt) = self.lookup(lobj.name()) {
554 if alt == okey {
555 continue;
556 }
557 self.error(
558 stmt.pos(self.ast_objs),
559 format!(
560 "result parameter {} not in scope at return",
561 lobj.name()
562 ),
563 );
564 let (altd, objd) = (self.new_dis(&alt), self.new_dis(&okey));
565 self.error(altd.pos(), format!("\tinner declaration of {}", objd));
566 }
568 }
569 } else {
570 let vars = res.vars().clone();
572 self.init_vars(&vars, &rs.results, Some(rs.ret), fctx);
573 }
574 } else if rs.results.len() > 0 {
575 self.error_str(
576 rs.results[0].pos(self.ast_objs),
577 "no result values expected",
578 );
579 self.use_exprs(&rs.results, fctx);
580 }
581 }
582 Stmt::Branch(bs) => {
583 if bs.label.is_some() {
584 self.octx.has_label = true;
585 return; }
587 let spos = stmt.pos(self.ast_objs);
588 match &bs.token {
589 Token::BREAK => {
590 if !ctx.break_ok {
591 self.error_str(spos, "break not in for, switch, or select statement");
592 }
593 }
594 Token::CONTINUE => {
595 if !ctx.continue_ok {
596 self.error_str(spos, "continue not in for statement");
597 }
598 }
599 Token::FALLTHROUGH => {
600 if !ctx.fallthrough_ok {
601 let msg = if ctx.final_switch_case {
602 "cannot fallthrough final case in switch"
603 } else {
604 "fallthrough statement out of place"
605 };
606 self.error_str(spos, msg);
607 }
608 }
609 _ => {
610 self.invalid_ast(spos, &format!("branch statement: {}", bs.token));
611 }
612 }
613 }
614 Stmt::Block(bs) => {
615 self.open_scope(stmt, "block".to_owned());
616
617 self.stmt_list(&bs.list, &inner_ctx, fctx);
618
619 self.close_scope();
620 }
621 Stmt::If(ifs) => {
622 self.open_scope(stmt, "if".to_owned());
623
624 self.simple_stmt(ifs.init.as_ref(), fctx);
625 let x = &mut Operand::new();
626 self.expr(x, &ifs.cond, fctx);
627 if !x.invalid() && !typ::is_boolean(x.typ.unwrap(), self.tc_objs) {
628 self.error_str(
629 ifs.cond.pos(self.ast_objs),
630 "non-boolean condition in if statement",
631 );
632 }
633 self.stmt(&Stmt::Block(ifs.body.clone()), &inner_ctx, fctx);
634 if let Some(s) = &ifs.els {
637 match s {
638 Stmt::Bad(_) => {} Stmt::If(_) | Stmt::Block(_) => {
640 self.stmt(s, &inner_ctx, fctx);
641 }
642 _ => {
643 let pos = s.pos(self.ast_objs);
644 self.error_str(pos, "invalid else branch in if statement");
645 }
646 }
647 }
648
649 self.close_scope();
650 }
651 Stmt::Switch(ss) => {
652 inner_ctx.break_ok = true;
653 self.open_scope(stmt, "switch".to_owned());
654
655 self.simple_stmt(ss.init.as_ref(), fctx);
656 let x = &mut Operand::new();
657 if let Some(tag) = &ss.tag {
658 self.expr(x, tag, fctx);
659 self.assignment(x, None, "switch expression", fctx);
662 } else {
663 x.mode = OperandMode::Constant(Value::with_bool(true));
666 x.typ = Some(self.basic_type(BasicType::Bool));
667 x.expr = Some(Expr::Ident(
668 self.ast_objs.idents.insert(Ident::true_(ss.body.l_brace)),
669 ))
670 }
671
672 self.multiple_defaults(&ss.body.list);
673
674 let mut seen: ValueMap = Map::new();
675 for (i, c) in ss.body.list.iter().enumerate() {
676 if let Stmt::Case(cc) = c {
677 self.case_values(x, &cc.list, &mut seen, fctx);
678 self.open_scope(stmt, "case".to_owned());
679 let mut inner2 = inner_ctx.clone();
680 if i + 1 < ss.body.list.len() {
681 inner2.fallthrough_ok = true;
682 } else {
683 inner2.final_switch_case = true;
684 }
685 self.stmt_list(&cc.body, &inner2, fctx);
686 self.close_scope();
687 } else {
688 self.invalid_ast(c.pos(self.ast_objs), "incorrect expression switch case");
689 }
690 }
691
692 self.close_scope();
693 }
694 Stmt::TypeSwitch(tss) => {
695 inner_ctx.break_ok = true;
696 self.open_scope(stmt, "type switch".to_owned());
697
698 self.simple_stmt(tss.init.as_ref(), fctx);
699 let invalid_ast = || {
706 let spos = stmt.pos(self.ast_objs);
707 self.invalid_ast(spos, "incorrect form of type switch guard");
708 };
709 let (lhs, rhs): (Option<IdentKey>, &Expr) = match &tss.assign {
710 Stmt::Expr(e) => (None, &*e),
711 Stmt::Assign(ass) => {
712 let assign = &self.ast_objs.a_stmts[*ass];
713 if assign.lhs.len() != 1
714 || assign.token != Token::DEFINE
715 || assign.rhs.len() != 1
716 {
717 invalid_ast();
718 return self.close_scope();
719 }
720 if let Expr::Ident(ikey) = assign.lhs[0] {
721 let ident = &self.ast_objs.idents[ikey];
722 let l = if ident.name == "_" {
723 self.soft_error_str(
725 ident.pos,
726 "no new variable on left side of :=",
727 );
728 None } else {
730 self.result.record_def(ikey, None);
731 Some(ikey)
732 };
733 (l, &assign.rhs[0])
734 } else {
735 invalid_ast();
736 return self.close_scope();
737 }
738 }
739 _ => {
740 invalid_ast();
741 return self.close_scope();
742 }
743 };
744
745 let ta: &TypeAssertExpr = match rhs {
747 Expr::TypeAssert(e) => e,
748 _ => {
749 let spos = stmt.pos(self.ast_objs);
750 self.invalid_ast(spos, "incorrect form of type switch guard");
751 return self.close_scope();
752 }
753 };
754 let x = &mut Operand::new();
755 let ta_expr = ta.expr.clone();
756 self.expr(x, &ta_expr, fctx);
757 if x.invalid() {
758 return self.close_scope();
759 }
760 let xtype = typ::underlying_type(x.typ.unwrap(), self.tc_objs);
761 if self.otype(xtype).try_as_interface().is_none() {
762 let xd = self.new_dis(x);
763 self.error(xd.pos(), format!("{} is not an interface", xd));
764 return self.close_scope();
765 }
766
767 self.multiple_defaults(&tss.body.list);
768
769 let mut seen = Map::new();
770 let mut lhs_vars = Vec::new();
771 for s in tss.body.list.iter() {
772 let clause: &CaseClause = match s {
773 Stmt::Case(cc) => cc,
774 _ => {
775 let spos = stmt.pos(self.ast_objs);
776 self.invalid_ast(spos, "incorrect type switch case");
777 continue;
778 }
779 };
780 let mut t = self.case_types(x, xtype, &clause.list, &mut seen, fctx);
782 self.open_scope(stmt, "case".to_owned());
783 if let Some(lhs) = lhs {
785 if clause.list.as_ref().map_or(0, |x| x.len()) != 1 || t.is_none() {
791 t = x.typ;
792 }
793 let ident = self.ast_ident(lhs);
794 let (pos, name) = (ident.pos, ident.name.clone());
795 let okey = self.tc_objs.new_var(pos, Some(self.pkg), name, t);
796 let scope_pos = clause
797 .list
798 .as_ref()
799 .map_or(clause.case + "default".len(), |x| {
800 x[x.len() - 1].end(self.ast_objs)
801 });
802 self.declare(self.octx.scope.unwrap(), None, okey, scope_pos);
803 self.result.record_implicit(s, okey);
804 lhs_vars.push(okey);
808 }
809 self.stmt_list(&clause.body, &inner_ctx, fctx);
810 self.close_scope();
811 }
812
813 if lhs.is_some() {
815 let used = lhs_vars.iter_mut().fold(false, |acc, x| {
816 let prop = self.tc_objs.lobjs[*x].entity_type_mut().var_property_mut();
817 let used = prop.used;
818 prop.used = true; acc || used
820 });
821 if !used {
822 let ident = self.ast_ident(lhs.unwrap());
823 let (pos, name) = (ident.pos, &ident.name);
824 self.soft_error(pos, format!("{} declared but not used", name));
825 }
826 }
827
828 self.close_scope();
829 }
830 Stmt::Select(ss) => {
831 inner_ctx.break_ok = true;
832
833 self.multiple_defaults(&ss.body.list);
834
835 for s in ss.body.list.iter() {
836 let clause: &CommClause = match s {
837 Stmt::Comm(cc) => cc,
838 _ => continue, };
840 let is_recv = |e: &Expr| match Checker::<S>::unparen(e) {
842 Expr::Unary(ue) => ue.op == Token::ARROW,
843 _ => false,
844 };
845 let valid = match &clause.comm {
846 None | Some(Stmt::Send(_)) => true,
847 Some(Stmt::Assign(ass)) => {
848 let assign = &self.ast_objs.a_stmts[*ass];
849 if assign.rhs.len() == 1 {
850 is_recv(&assign.rhs[0])
851 } else {
852 false
853 }
854 }
855 Some(Stmt::Expr(e)) => is_recv(e),
856 _ => false,
857 };
858 if !valid {
859 self.error_str(
860 clause.comm.as_ref().unwrap().pos(self.ast_objs),
861 "select case must be send or receive (possibly with assignment)",
862 );
863 continue;
864 }
865
866 self.open_scope(stmt, "case".to_owned());
867 if let Some(cc) = &clause.comm {
868 self.stmt(cc, &inner_ctx, fctx);
869 }
870 self.stmt_list(&clause.body, &inner_ctx, fctx);
871 self.close_scope()
872 }
873 }
874 Stmt::For(fs) => {
875 inner_ctx.break_ok = true;
876 inner_ctx.continue_ok = true;
877 self.open_scope(stmt, "for".to_owned());
878
879 self.simple_stmt(fs.init.as_ref(), fctx);
880 if let Some(cond) = &fs.cond {
881 let x = &mut Operand::new();
882 self.expr(x, cond, fctx);
883 if !x.invalid() && !typ::is_boolean(x.typ.unwrap(), self.tc_objs) {
884 self.error_str(
885 cond.pos(self.ast_objs),
886 "non-boolean condition in if statement",
887 );
888 }
889 }
890 self.simple_stmt(fs.post.as_ref(), fctx);
891 match &fs.post {
894 Some(Stmt::Assign(ass)) => {
895 let assign = &self.ast_objs.a_stmts[*ass];
896 if assign.token == Token::DEFINE {
897 self.soft_error_str(
898 assign.pos(self.ast_objs),
899 "cannot declare in post statement",
900 );
901 let lhs = assign.lhs.clone();
905 self.use_exprs(&lhs, fctx); }
907 }
908 _ => {}
909 }
910 self.stmt(&Stmt::Block(fs.body.clone()), &inner_ctx, fctx);
911
912 self.close_scope()
913 }
914 Stmt::Range(rs) => {
915 inner_ctx.break_ok = true;
916 inner_ctx.continue_ok = true;
917 self.open_scope(stmt, "for".to_owned());
918
919 let x = &mut Operand::new();
921 self.expr(x, &rs.expr, fctx);
922
923 let (key, val) = if x.invalid() {
925 (None, None)
926 } else {
927 match self.otype(x.typ.unwrap()).underlying_val(self.tc_objs) {
928 Type::Basic(detail) if detail.info() == BasicInfo::IsString => (
929 Some(self.basic_type(BasicType::Int)),
930 Some(*self.tc_objs.universe().rune()),
931 ),
932 Type::Array(detail) => {
933 (Some(self.basic_type(BasicType::Int)), Some(detail.elem()))
934 }
935 Type::Slice(detail) => {
936 (Some(self.basic_type(BasicType::Int)), Some(detail.elem()))
937 }
938 Type::Pointer(detail) => {
939 if let Some(d) = self
940 .otype(detail.base())
941 .underlying_val(self.tc_objs)
942 .try_as_array()
943 {
944 (Some(self.basic_type(BasicType::Int)), Some(d.elem()))
945 } else {
946 (None, None)
947 }
948 }
949 Type::Map(detail) => (Some(detail.key()), Some(detail.elem())),
950 Type::Chan(detail) => {
951 if detail.dir() == ChanDir::SendOnly {
952 let xd = self.new_dis(x);
953 self.error(
954 xd.pos(),
955 format!("cannot range over send-only channel {}", xd),
956 );
957 }
959 if let Some(v) = &rs.val {
960 self.error(
961 v.pos(self.ast_objs),
962 format!(
963 "iteration over {} permits only one iteration variable",
964 self.new_dis(x)
965 ),
966 );
967 }
969 (Some(detail.elem()), Some(self.invalid_type()))
970 }
971 _ => (None, None),
972 }
973 };
974
975 if key.is_none() {
976 let xd = self.new_dis(x);
977 self.error(xd.pos(), format!("cannot range over {}", xd));
978 }
980
981 let lhs = [rs.key.as_ref(), rs.val.as_ref()];
986 let rhs = [key, val];
987 if rs.token == Token::DEFINE {
988 let mut vars = vec![];
989 for (i, lhs) in lhs.iter().enumerate() {
990 if lhs.is_none() {
991 continue;
992 }
993 let okey = match lhs.unwrap() {
995 Expr::Ident(ikey) => {
996 let ident = self.ast_ident(*ikey);
997 let (pos, name) = (ident.pos, ident.name.clone());
998 let has_name = name != "_";
999 let o = self.tc_objs.new_var(pos, Some(self.pkg), name, None);
1000 self.result.record_def(*ikey, Some(o));
1001 if has_name {
1002 vars.push(o);
1003 }
1004 o
1005 }
1006 _ => {
1007 let ed = self.new_dis(lhs.unwrap());
1008 self.error(ed.pos(), format!("cannot declare {}", ed));
1009 let (pos, name) = (ed.pos(), "_".to_owned());
1010 self.tc_objs.new_var(pos, Some(self.pkg), name, None)
1011 }
1012 };
1013 if rhs[i].is_some() {
1015 x.mode = OperandMode::Value;
1016 x.expr = lhs.map(|x| x.clone());
1017 x.typ = rhs[i];
1018 self.init_var(okey, x, "range clause", fctx);
1019 } else {
1020 let invalid_type = self.invalid_type();
1021 let oval = self.lobj_mut(okey);
1022 oval.set_type(Some(invalid_type));
1023 oval.entity_type_mut().var_property_mut().used = true;
1024 }
1025 }
1026
1027 if vars.len() > 0 {
1029 let scope_pos = rs.expr.end(self.ast_objs);
1030 for okey in vars.iter() {
1031 self.declare(
1036 self.octx.scope.unwrap(),
1037 None, *okey,
1039 scope_pos,
1040 );
1041 }
1042 } else {
1043 self.error_str(rs.token_pos, "no new variables on left side of :=");
1044 }
1045 } else {
1046 for (i, lhs) in lhs.iter().enumerate() {
1048 if lhs.is_some() && rhs[i].is_some() {
1049 x.mode = OperandMode::Value;
1050 x.expr = lhs.map(|x| x.clone());
1051 x.typ = rhs[i];
1052 self.assign_var(lhs.unwrap(), x, fctx);
1053 }
1054 }
1055 }
1056
1057 self.stmt(&Stmt::Block(rs.body.clone()), &inner_ctx, fctx);
1058
1059 self.close_scope()
1060 }
1061 _ => self.error_str(stmt.pos(self.ast_objs), "invalid statement"),
1062 }
1063 }
1064}