go_types/check/
stmt.rs

1// Copyright 2022 The Goscript Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4//
5//
6// This code is adapted from the offical Go code written in Go
7// with license as follows:
8// Copyright 2013 The Go Authors. All rights reserved.
9// Use of this source code is governed by a BSD-style
10// license that can be found in the LICENSE file.
11
12#![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        // set function scope extent
121        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        // spec: "Implementation restriction: A compiler may make it illegal to
150        // declare a variable inside a function body if the variable is never used."
151        self.usage(scope_key);
152
153        std::mem::swap(&mut self.octx, &mut octx); // restore octx
154        self.indent.replace(old_indent); //restore indent
155        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            // Don't go inside function literal scopes a second time;
186            // they are handled explicitly by func_body.
187            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        // trailing empty statements are "invisible" to fallthrough analysis
202        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            // Order matters: By comparing v against x, error positions are at the case values.
309            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                // look for duplicate values
316                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(_) => {} //ignore
401            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                // spec: "With the exception of specific built-in functions,
409                // function and method calls and receive operations can appear
410                // in statement context. Such statements may be parenthesized."
411                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                        // assignment operations
506                        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                    // function returns results
546                    // (if one, say the first, result parameter is named, all of them are named)
547                    if rs.results.len() == 0 && self.lobj(res.vars()[0]).name() != "" {
548                        // spec: "Implementation restriction: A compiler may disallow an empty expression
549                        // list in a "return" statement if a different entity (constant, type, or variable)
550                        // with the same name as a result parameter is in scope at the place of the return."
551                        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                                // ok to continue
567                            }
568                        }
569                    } else {
570                        // return has results or result parameters are unnamed
571                        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; //checked in 2nd pass (Check::label)
586                }
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                // The parser produces a correct AST but if it was modified
635                // elsewhere the else branch may be invalid. Check again.
636                if let Some(s) = &ifs.els {
637                    match s {
638                        Stmt::Bad(_) => {} //error already reported
639                        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                    // By checking assignment of x to an invisible temporary
660                    // (as a compiler would), we get all the relevant checks.
661                    self.assignment(x, None, "switch expression", fctx);
662                } else {
663                    // spec: "A missing switch expression is
664                    // equivalent to the boolean value true."
665                    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                // A type switch guard must be of the form:
700                //
701                //     TypeSwitchGuard = [ identifier ":=" ] PrimaryExpr "." "(" "type" ")" .
702                //
703                // The parser is checking syntactic correctness;
704                // remaining syntactic errors are considered AST errors here.
705                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                                // _ := x.(type) is an invalid short variable declaration
724                                self.soft_error_str(
725                                    ident.pos,
726                                    "no new variable on left side of :=",
727                                );
728                                None // avoid declared but not used error below
729                            } 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                // rhs must be of the form: expr.(type) and expr must be an interface
746                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                    // Check each type in this type switch case.
781                    let mut t = self.case_types(x, xtype, &clause.list, &mut seen, fctx);
782                    self.open_scope(stmt, "case".to_owned());
783                    // If lhs exists, declare a corresponding variable in the case-local scope.
784                    if let Some(lhs) = lhs {
785                        // spec: "The TypeSwitchGuard may include a short variable declaration.
786                        // When that form is used, the variable is declared at the beginning of
787                        // the implicit block in each clause. In clauses with a case listing
788                        // exactly one type, the variable has that type; otherwise, the variable
789                        // has the type of the expression in the TypeSwitchGuard."
790                        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                        // For the "declared but not used" error, all lhs variables act as
805                        // one; i.e., if any one of them is 'used', all of them are 'used'.
806                        // Collect them for later analysis.
807                        lhs_vars.push(okey);
808                    }
809                    self.stmt_list(&clause.body, &inner_ctx, fctx);
810                    self.close_scope();
811                }
812
813                // If lhs exists, we must have at least one lhs variable that was used.
814                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; // avoid usage error when checking entire function
819                        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, // error reported before
839                    };
840                    // clause.Comm must be a SendStmt, RecvStmt, or default case
841                    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                // spec: "The init statement may be a short variable
892                // declaration, but the post statement must not."
893                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                            // Don't call useLHS here because we want to use the lhs in
902                            // this erroneous statement so that we don't get errors about
903                            // these lhs variables being declared but not used.
904                            let lhs = assign.lhs.clone();
905                            self.use_exprs(&lhs, fctx); // avoid follow-up errors
906                        }
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                // check expression to iterate over
920                let x = &mut Operand::new();
921                self.expr(x, &rs.expr, fctx);
922
923                // determine key/value types
924                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                                // ok to continue
958                            }
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                                // ok to continue
968                            }
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                    // ok to continue
979                }
980
981                // check assignment to/declaration of iteration variables
982                // (irregular assignment, cannot easily map to existing assignment checks)
983
984                // lhs expressions and initialization value (rhs) types
985                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                        // determine lhs variable
994                        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                        // initialize lhs variable
1014                        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                    // declare variables
1028                    if vars.len() > 0 {
1029                        let scope_pos = rs.expr.end(self.ast_objs);
1030                        for okey in vars.iter() {
1031                            // spec: "The scope of a constant or variable identifier declared inside
1032                            // a function begins at the end of the ConstSpec or VarSpec (ShortVarDecl
1033                            // for short variable declarations) and ends at the end of the innermost
1034                            // containing block."
1035                            self.declare(
1036                                self.octx.scope.unwrap(),
1037                                None, /* record_def already called */
1038                                *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                    // ordinary assignment
1047                    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}