1// Copyright 2009 The Go 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
5package typecheck
6
7import (
8	"cmd/compile/internal/base"
9	"cmd/compile/internal/ir"
10	"cmd/compile/internal/types"
11	"cmd/internal/src"
12	"internal/types/errors"
13)
14
15func RangeExprType(t *types.Type) *types.Type {
16	if t.IsPtr() && t.Elem().IsArray() {
17		return t.Elem()
18	}
19	return t
20}
21
22func typecheckrangeExpr(n *ir.RangeStmt) {
23}
24
25// type check assignment.
26// if this assignment is the definition of a var on the left side,
27// fill in the var's type.
28func tcAssign(n *ir.AssignStmt) {
29	if base.EnableTrace && base.Flag.LowerT {
30		defer tracePrint("tcAssign", n)(nil)
31	}
32
33	if n.Y == nil {
34		n.X = AssignExpr(n.X)
35		return
36	}
37
38	lhs, rhs := []ir.Node{n.X}, []ir.Node{n.Y}
39	assign(n, lhs, rhs)
40	n.X, n.Y = lhs[0], rhs[0]
41
42	// TODO(mdempsky): This seems out of place.
43	if !ir.IsBlank(n.X) {
44		types.CheckSize(n.X.Type()) // ensure width is calculated for backend
45	}
46}
47
48func tcAssignList(n *ir.AssignListStmt) {
49	if base.EnableTrace && base.Flag.LowerT {
50		defer tracePrint("tcAssignList", n)(nil)
51	}
52
53	assign(n, n.Lhs, n.Rhs)
54}
55
56func assign(stmt ir.Node, lhs, rhs []ir.Node) {
57	// delicate little dance.
58	// the definition of lhs may refer to this assignment
59	// as its definition, in which case it will call tcAssign.
60	// in that case, do not call typecheck back, or it will cycle.
61	// if the variable has a type (ntype) then typechecking
62	// will not look at defn, so it is okay (and desirable,
63	// so that the conversion below happens).
64
65	checkLHS := func(i int, typ *types.Type) {
66		if n := lhs[i]; typ != nil && ir.DeclaredBy(n, stmt) && n.Type() == nil {
67			base.Assertf(typ.Kind() == types.TNIL, "unexpected untyped nil")
68			n.SetType(defaultType(typ))
69		}
70		if lhs[i].Typecheck() == 0 {
71			lhs[i] = AssignExpr(lhs[i])
72		}
73		checkassign(lhs[i])
74	}
75
76	assignType := func(i int, typ *types.Type) {
77		checkLHS(i, typ)
78		if typ != nil {
79			checkassignto(typ, lhs[i])
80		}
81	}
82
83	cr := len(rhs)
84	if len(rhs) == 1 {
85		rhs[0] = typecheck(rhs[0], ctxExpr|ctxMultiOK)
86		if rtyp := rhs[0].Type(); rtyp != nil && rtyp.IsFuncArgStruct() {
87			cr = rtyp.NumFields()
88		}
89	} else {
90		Exprs(rhs)
91	}
92
93	// x, ok = y
94assignOK:
95	for len(lhs) == 2 && cr == 1 {
96		stmt := stmt.(*ir.AssignListStmt)
97		r := rhs[0]
98
99		switch r.Op() {
100		case ir.OINDEXMAP:
101			stmt.SetOp(ir.OAS2MAPR)
102		case ir.ORECV:
103			stmt.SetOp(ir.OAS2RECV)
104		case ir.ODOTTYPE:
105			r := r.(*ir.TypeAssertExpr)
106			stmt.SetOp(ir.OAS2DOTTYPE)
107			r.SetOp(ir.ODOTTYPE2)
108		case ir.ODYNAMICDOTTYPE:
109			r := r.(*ir.DynamicTypeAssertExpr)
110			stmt.SetOp(ir.OAS2DOTTYPE)
111			r.SetOp(ir.ODYNAMICDOTTYPE2)
112		default:
113			break assignOK
114		}
115
116		assignType(0, r.Type())
117		assignType(1, types.UntypedBool)
118		return
119	}
120
121	if len(lhs) != cr {
122		if r, ok := rhs[0].(*ir.CallExpr); ok && len(rhs) == 1 {
123			if r.Type() != nil {
124				base.ErrorfAt(stmt.Pos(), errors.WrongAssignCount, "assignment mismatch: %d variable%s but %v returns %d value%s", len(lhs), plural(len(lhs)), r.Fun, cr, plural(cr))
125			}
126		} else {
127			base.ErrorfAt(stmt.Pos(), errors.WrongAssignCount, "assignment mismatch: %d variable%s but %v value%s", len(lhs), plural(len(lhs)), len(rhs), plural(len(rhs)))
128		}
129
130		for i := range lhs {
131			checkLHS(i, nil)
132		}
133		return
134	}
135
136	// x,y,z = f()
137	if cr > len(rhs) {
138		stmt := stmt.(*ir.AssignListStmt)
139		stmt.SetOp(ir.OAS2FUNC)
140		r := rhs[0].(*ir.CallExpr)
141		rtyp := r.Type()
142
143		mismatched := false
144		failed := false
145		for i := range lhs {
146			result := rtyp.Field(i).Type
147			assignType(i, result)
148
149			if lhs[i].Type() == nil || result == nil {
150				failed = true
151			} else if lhs[i] != ir.BlankNode && !types.Identical(lhs[i].Type(), result) {
152				mismatched = true
153			}
154		}
155		if mismatched && !failed {
156			RewriteMultiValueCall(stmt, r)
157		}
158		return
159	}
160
161	for i, r := range rhs {
162		checkLHS(i, r.Type())
163		if lhs[i].Type() != nil {
164			rhs[i] = AssignConv(r, lhs[i].Type(), "assignment")
165		}
166	}
167}
168
169func plural(n int) string {
170	if n == 1 {
171		return ""
172	}
173	return "s"
174}
175
176// tcCheckNil typechecks an OCHECKNIL node.
177func tcCheckNil(n *ir.UnaryExpr) ir.Node {
178	n.X = Expr(n.X)
179	if !n.X.Type().IsPtrShaped() {
180		base.FatalfAt(n.Pos(), "%L is not pointer shaped", n.X)
181	}
182	return n
183}
184
185// tcFor typechecks an OFOR node.
186func tcFor(n *ir.ForStmt) ir.Node {
187	Stmts(n.Init())
188	n.Cond = Expr(n.Cond)
189	n.Cond = DefaultLit(n.Cond, nil)
190	if n.Cond != nil {
191		t := n.Cond.Type()
192		if t != nil && !t.IsBoolean() {
193			base.Errorf("non-bool %L used as for condition", n.Cond)
194		}
195	}
196	n.Post = Stmt(n.Post)
197	Stmts(n.Body)
198	return n
199}
200
201// tcGoDefer typechecks (normalizes) an OGO/ODEFER statement.
202func tcGoDefer(n *ir.GoDeferStmt) {
203	call := normalizeGoDeferCall(n.Pos(), n.Op(), n.Call, n.PtrInit())
204	call.GoDefer = true
205	n.Call = call
206}
207
208// normalizeGoDeferCall normalizes call into a normal function call
209// with no arguments and no results, suitable for use in an OGO/ODEFER
210// statement.
211//
212// For example, it normalizes:
213//
214//	f(x, y)
215//
216// into:
217//
218//	x1, y1 := x, y          // added to init
219//	func() { f(x1, y1) }()  // result
220func normalizeGoDeferCall(pos src.XPos, op ir.Op, call ir.Node, init *ir.Nodes) *ir.CallExpr {
221	init.Append(ir.TakeInit(call)...)
222
223	if call, ok := call.(*ir.CallExpr); ok && call.Op() == ir.OCALLFUNC {
224		if sig := call.Fun.Type(); sig.NumParams()+sig.NumResults() == 0 {
225			return call // already in normal form
226		}
227	}
228
229	// Create a new wrapper function without parameters or results.
230	wrapperFn := ir.NewClosureFunc(pos, pos, op, types.NewSignature(nil, nil, nil), ir.CurFunc, Target)
231	wrapperFn.DeclareParams(true)
232	wrapperFn.SetWrapper(true)
233
234	// argps collects the list of operands within the call expression
235	// that must be evaluated at the go/defer statement.
236	var argps []*ir.Node
237
238	var visit func(argp *ir.Node)
239	visit = func(argp *ir.Node) {
240		arg := *argp
241		if arg == nil {
242			return
243		}
244
245		// Recognize a few common expressions that can be evaluated within
246		// the wrapper, so we don't need to allocate space for them within
247		// the closure.
248		switch arg.Op() {
249		case ir.OLITERAL, ir.ONIL, ir.OMETHEXPR, ir.ONEW:
250			return
251		case ir.ONAME:
252			arg := arg.(*ir.Name)
253			if arg.Class == ir.PFUNC {
254				return // reference to global function
255			}
256		case ir.OADDR:
257			arg := arg.(*ir.AddrExpr)
258			if arg.X.Op() == ir.OLINKSYMOFFSET {
259				return // address of global symbol
260			}
261
262		case ir.OCONVNOP:
263			arg := arg.(*ir.ConvExpr)
264
265			// For unsafe.Pointer->uintptr conversion arguments, save the
266			// unsafe.Pointer argument. This is necessary to handle cases
267			// like fixedbugs/issue24491a.go correctly.
268			//
269			// TODO(mdempsky): Limit to static callees with
270			// //go:uintptr{escapes,keepalive}?
271			if arg.Type().IsUintptr() && arg.X.Type().IsUnsafePtr() {
272				visit(&arg.X)
273				return
274			}
275
276		case ir.OARRAYLIT, ir.OSLICELIT, ir.OSTRUCTLIT:
277			// TODO(mdempsky): For very large slices, it may be preferable
278			// to construct them at the go/defer statement instead.
279			list := arg.(*ir.CompLitExpr).List
280			for i, el := range list {
281				switch el := el.(type) {
282				case *ir.KeyExpr:
283					visit(&el.Value)
284				case *ir.StructKeyExpr:
285					visit(&el.Value)
286				default:
287					visit(&list[i])
288				}
289			}
290			return
291		}
292
293		argps = append(argps, argp)
294	}
295
296	visitList := func(list []ir.Node) {
297		for i := range list {
298			visit(&list[i])
299		}
300	}
301
302	switch call.Op() {
303	default:
304		base.Fatalf("unexpected call op: %v", call.Op())
305
306	case ir.OCALLFUNC:
307		call := call.(*ir.CallExpr)
308
309		// If the callee is a named function, link to the original callee.
310		if wrapped := ir.StaticCalleeName(call.Fun); wrapped != nil {
311			wrapperFn.WrappedFunc = wrapped.Func
312		}
313
314		visit(&call.Fun)
315		visitList(call.Args)
316
317	case ir.OCALLINTER:
318		call := call.(*ir.CallExpr)
319		argps = append(argps, &call.Fun.(*ir.SelectorExpr).X) // must be first for OCHECKNIL; see below
320		visitList(call.Args)
321
322	case ir.OAPPEND, ir.ODELETE, ir.OPRINT, ir.OPRINTLN, ir.ORECOVERFP:
323		call := call.(*ir.CallExpr)
324		visitList(call.Args)
325		visit(&call.RType)
326
327	case ir.OCOPY:
328		call := call.(*ir.BinaryExpr)
329		visit(&call.X)
330		visit(&call.Y)
331		visit(&call.RType)
332
333	case ir.OCLEAR, ir.OCLOSE, ir.OPANIC:
334		call := call.(*ir.UnaryExpr)
335		visit(&call.X)
336	}
337
338	if len(argps) != 0 {
339		// Found one or more operands that need to be evaluated upfront
340		// and spilled to temporary variables, which can be captured by
341		// the wrapper function.
342
343		stmtPos := base.Pos
344		callPos := base.Pos
345
346		as := ir.NewAssignListStmt(callPos, ir.OAS2, make([]ir.Node, len(argps)), make([]ir.Node, len(argps)))
347		for i, argp := range argps {
348			arg := *argp
349
350			pos := callPos
351			if ir.HasUniquePos(arg) {
352				pos = arg.Pos()
353			}
354
355			// tmp := arg
356			tmp := TempAt(pos, ir.CurFunc, arg.Type())
357			init.Append(Stmt(ir.NewDecl(pos, ir.ODCL, tmp)))
358			tmp.Defn = as
359			as.Lhs[i] = tmp
360			as.Rhs[i] = arg
361
362			// Rewrite original expression to use/capture tmp.
363			*argp = ir.NewClosureVar(pos, wrapperFn, tmp)
364		}
365		init.Append(Stmt(as))
366
367		// For "go/defer iface.M()", if iface is nil, we need to panic at
368		// the point of the go/defer statement.
369		if call.Op() == ir.OCALLINTER {
370			iface := as.Lhs[0]
371			init.Append(Stmt(ir.NewUnaryExpr(stmtPos, ir.OCHECKNIL, ir.NewUnaryExpr(iface.Pos(), ir.OITAB, iface))))
372		}
373	}
374
375	// Move call into the wrapper function, now that it's safe to
376	// evaluate there.
377	wrapperFn.Body = []ir.Node{call}
378
379	// Finally, construct a call to the wrapper.
380	return Call(call.Pos(), wrapperFn.OClosure, nil, false).(*ir.CallExpr)
381}
382
383// tcIf typechecks an OIF node.
384func tcIf(n *ir.IfStmt) ir.Node {
385	Stmts(n.Init())
386	n.Cond = Expr(n.Cond)
387	n.Cond = DefaultLit(n.Cond, nil)
388	if n.Cond != nil {
389		t := n.Cond.Type()
390		if t != nil && !t.IsBoolean() {
391			base.Errorf("non-bool %L used as if condition", n.Cond)
392		}
393	}
394	Stmts(n.Body)
395	Stmts(n.Else)
396	return n
397}
398
399// range
400func tcRange(n *ir.RangeStmt) {
401	n.X = Expr(n.X)
402
403	// delicate little dance.  see tcAssignList
404	if n.Key != nil {
405		if !ir.DeclaredBy(n.Key, n) {
406			n.Key = AssignExpr(n.Key)
407		}
408		checkassign(n.Key)
409	}
410	if n.Value != nil {
411		if !ir.DeclaredBy(n.Value, n) {
412			n.Value = AssignExpr(n.Value)
413		}
414		checkassign(n.Value)
415	}
416
417	// second half of dance
418	n.SetTypecheck(1)
419	if n.Key != nil && n.Key.Typecheck() == 0 {
420		n.Key = AssignExpr(n.Key)
421	}
422	if n.Value != nil && n.Value.Typecheck() == 0 {
423		n.Value = AssignExpr(n.Value)
424	}
425
426	Stmts(n.Body)
427}
428
429// tcReturn typechecks an ORETURN node.
430func tcReturn(n *ir.ReturnStmt) ir.Node {
431	if ir.CurFunc == nil {
432		base.FatalfAt(n.Pos(), "return outside function")
433	}
434
435	typecheckargs(n)
436	if len(n.Results) != 0 {
437		typecheckaste(ir.ORETURN, nil, false, ir.CurFunc.Type().Results(), n.Results, func() string { return "return argument" })
438	}
439	return n
440}
441
442// select
443func tcSelect(sel *ir.SelectStmt) {
444	var def *ir.CommClause
445	lno := ir.SetPos(sel)
446	Stmts(sel.Init())
447	for _, ncase := range sel.Cases {
448		if ncase.Comm == nil {
449			// default
450			if def != nil {
451				base.ErrorfAt(ncase.Pos(), errors.DuplicateDefault, "multiple defaults in select (first at %v)", ir.Line(def))
452			} else {
453				def = ncase
454			}
455		} else {
456			n := Stmt(ncase.Comm)
457			ncase.Comm = n
458			oselrecv2 := func(dst, recv ir.Node, def bool) {
459				selrecv := ir.NewAssignListStmt(n.Pos(), ir.OSELRECV2, []ir.Node{dst, ir.BlankNode}, []ir.Node{recv})
460				selrecv.Def = def
461				selrecv.SetTypecheck(1)
462				selrecv.SetInit(n.Init())
463				ncase.Comm = selrecv
464			}
465			switch n.Op() {
466			default:
467				pos := n.Pos()
468				if n.Op() == ir.ONAME {
469					// We don't have the right position for ONAME nodes (see #15459 and
470					// others). Using ncase.Pos for now as it will provide the correct
471					// line number (assuming the expression follows the "case" keyword
472					// on the same line). This matches the approach before 1.10.
473					pos = ncase.Pos()
474				}
475				base.ErrorfAt(pos, errors.InvalidSelectCase, "select case must be receive, send or assign recv")
476
477			case ir.OAS:
478				// convert x = <-c into x, _ = <-c
479				// remove implicit conversions; the eventual assignment
480				// will reintroduce them.
481				n := n.(*ir.AssignStmt)
482				if r := n.Y; r.Op() == ir.OCONVNOP || r.Op() == ir.OCONVIFACE {
483					r := r.(*ir.ConvExpr)
484					if r.Implicit() {
485						n.Y = r.X
486					}
487				}
488				if n.Y.Op() != ir.ORECV {
489					base.ErrorfAt(n.Pos(), errors.InvalidSelectCase, "select assignment must have receive on right hand side")
490					break
491				}
492				oselrecv2(n.X, n.Y, n.Def)
493
494			case ir.OAS2RECV:
495				n := n.(*ir.AssignListStmt)
496				if n.Rhs[0].Op() != ir.ORECV {
497					base.ErrorfAt(n.Pos(), errors.InvalidSelectCase, "select assignment must have receive on right hand side")
498					break
499				}
500				n.SetOp(ir.OSELRECV2)
501
502			case ir.ORECV:
503				// convert <-c into _, _ = <-c
504				n := n.(*ir.UnaryExpr)
505				oselrecv2(ir.BlankNode, n, false)
506
507			case ir.OSEND:
508				break
509			}
510		}
511
512		Stmts(ncase.Body)
513	}
514
515	base.Pos = lno
516}
517
518// tcSend typechecks an OSEND node.
519func tcSend(n *ir.SendStmt) ir.Node {
520	n.Chan = Expr(n.Chan)
521	n.Value = Expr(n.Value)
522	n.Chan = DefaultLit(n.Chan, nil)
523	t := n.Chan.Type()
524	if t == nil {
525		return n
526	}
527	if !t.IsChan() {
528		base.Errorf("invalid operation: %v (send to non-chan type %v)", n, t)
529		return n
530	}
531
532	if !t.ChanDir().CanSend() {
533		base.Errorf("invalid operation: %v (send to receive-only type %v)", n, t)
534		return n
535	}
536
537	n.Value = AssignConv(n.Value, t.Elem(), "send")
538	if n.Value.Type() == nil {
539		return n
540	}
541	return n
542}
543
544// tcSwitch typechecks a switch statement.
545func tcSwitch(n *ir.SwitchStmt) {
546	Stmts(n.Init())
547	if n.Tag != nil && n.Tag.Op() == ir.OTYPESW {
548		tcSwitchType(n)
549	} else {
550		tcSwitchExpr(n)
551	}
552}
553
554func tcSwitchExpr(n *ir.SwitchStmt) {
555	t := types.Types[types.TBOOL]
556	if n.Tag != nil {
557		n.Tag = Expr(n.Tag)
558		n.Tag = DefaultLit(n.Tag, nil)
559		t = n.Tag.Type()
560	}
561
562	var nilonly string
563	if t != nil {
564		switch {
565		case t.IsMap():
566			nilonly = "map"
567		case t.Kind() == types.TFUNC:
568			nilonly = "func"
569		case t.IsSlice():
570			nilonly = "slice"
571
572		case !types.IsComparable(t):
573			if t.IsStruct() {
574				base.ErrorfAt(n.Pos(), errors.InvalidExprSwitch, "cannot switch on %L (struct containing %v cannot be compared)", n.Tag, types.IncomparableField(t).Type)
575			} else {
576				base.ErrorfAt(n.Pos(), errors.InvalidExprSwitch, "cannot switch on %L", n.Tag)
577			}
578			t = nil
579		}
580	}
581
582	var defCase ir.Node
583	for _, ncase := range n.Cases {
584		ls := ncase.List
585		if len(ls) == 0 { // default:
586			if defCase != nil {
587				base.ErrorfAt(ncase.Pos(), errors.DuplicateDefault, "multiple defaults in switch (first at %v)", ir.Line(defCase))
588			} else {
589				defCase = ncase
590			}
591		}
592
593		for i := range ls {
594			ir.SetPos(ncase)
595			ls[i] = Expr(ls[i])
596			ls[i] = DefaultLit(ls[i], t)
597			n1 := ls[i]
598			if t == nil || n1.Type() == nil {
599				continue
600			}
601
602			if nilonly != "" && !ir.IsNil(n1) {
603				base.ErrorfAt(ncase.Pos(), errors.MismatchedTypes, "invalid case %v in switch (can only compare %s %v to nil)", n1, nilonly, n.Tag)
604			} else if t.IsInterface() && !n1.Type().IsInterface() && !types.IsComparable(n1.Type()) {
605				base.ErrorfAt(ncase.Pos(), errors.UndefinedOp, "invalid case %L in switch (incomparable type)", n1)
606			} else {
607				op1, _ := assignOp(n1.Type(), t)
608				op2, _ := assignOp(t, n1.Type())
609				if op1 == ir.OXXX && op2 == ir.OXXX {
610					if n.Tag != nil {
611						base.ErrorfAt(ncase.Pos(), errors.MismatchedTypes, "invalid case %v in switch on %v (mismatched types %v and %v)", n1, n.Tag, n1.Type(), t)
612					} else {
613						base.ErrorfAt(ncase.Pos(), errors.MismatchedTypes, "invalid case %v in switch (mismatched types %v and bool)", n1, n1.Type())
614					}
615				}
616			}
617		}
618
619		Stmts(ncase.Body)
620	}
621}
622
623func tcSwitchType(n *ir.SwitchStmt) {
624	guard := n.Tag.(*ir.TypeSwitchGuard)
625	guard.X = Expr(guard.X)
626	t := guard.X.Type()
627	if t != nil && !t.IsInterface() {
628		base.ErrorfAt(n.Pos(), errors.InvalidTypeSwitch, "cannot type switch on non-interface value %L", guard.X)
629		t = nil
630	}
631
632	// We don't actually declare the type switch's guarded
633	// declaration itself. So if there are no cases, we won't
634	// notice that it went unused.
635	if v := guard.Tag; v != nil && !ir.IsBlank(v) && len(n.Cases) == 0 {
636		base.ErrorfAt(v.Pos(), errors.UnusedVar, "%v declared but not used", v.Sym())
637	}
638
639	var defCase, nilCase ir.Node
640	var ts typeSet
641	for _, ncase := range n.Cases {
642		ls := ncase.List
643		if len(ls) == 0 { // default:
644			if defCase != nil {
645				base.ErrorfAt(ncase.Pos(), errors.DuplicateDefault, "multiple defaults in switch (first at %v)", ir.Line(defCase))
646			} else {
647				defCase = ncase
648			}
649		}
650
651		for i := range ls {
652			ls[i] = typecheck(ls[i], ctxExpr|ctxType)
653			n1 := ls[i]
654			if t == nil || n1.Type() == nil {
655				continue
656			}
657
658			if ir.IsNil(n1) { // case nil:
659				if nilCase != nil {
660					base.ErrorfAt(ncase.Pos(), errors.DuplicateCase, "multiple nil cases in type switch (first at %v)", ir.Line(nilCase))
661				} else {
662					nilCase = ncase
663				}
664				continue
665			}
666			if n1.Op() == ir.ODYNAMICTYPE {
667				continue
668			}
669			if n1.Op() != ir.OTYPE {
670				base.ErrorfAt(ncase.Pos(), errors.NotAType, "%L is not a type", n1)
671				continue
672			}
673			if !n1.Type().IsInterface() {
674				why := ImplementsExplain(n1.Type(), t)
675				if why != "" {
676					base.ErrorfAt(ncase.Pos(), errors.ImpossibleAssert, "impossible type switch case: %L cannot have dynamic type %v (%s)", guard.X, n1.Type(), why)
677				}
678				continue
679			}
680
681			ts.add(ncase.Pos(), n1.Type())
682		}
683
684		if ncase.Var != nil {
685			// Assign the clause variable's type.
686			vt := t
687			if len(ls) == 1 {
688				if ls[0].Op() == ir.OTYPE || ls[0].Op() == ir.ODYNAMICTYPE {
689					vt = ls[0].Type()
690				} else if !ir.IsNil(ls[0]) {
691					// Invalid single-type case;
692					// mark variable as broken.
693					vt = nil
694				}
695			}
696
697			nvar := ncase.Var
698			nvar.SetType(vt)
699			if vt != nil {
700				nvar = AssignExpr(nvar).(*ir.Name)
701			} else {
702				// Clause variable is broken; prevent typechecking.
703				nvar.SetTypecheck(1)
704			}
705			ncase.Var = nvar
706		}
707
708		Stmts(ncase.Body)
709	}
710}
711
712type typeSet struct {
713	m map[string]src.XPos
714}
715
716func (s *typeSet) add(pos src.XPos, typ *types.Type) {
717	if s.m == nil {
718		s.m = make(map[string]src.XPos)
719	}
720
721	ls := typ.LinkString()
722	if prev, ok := s.m[ls]; ok {
723		base.ErrorfAt(pos, errors.DuplicateCase, "duplicate case %v in type switch\n\tprevious case at %s", typ, base.FmtPos(prev))
724		return
725	}
726	s.m[ls] = pos
727}
728