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
13	"fmt"
14	"go/constant"
15	"go/token"
16)
17
18// MakeDotArgs package all the arguments that match a ... T parameter into a []T.
19func MakeDotArgs(pos src.XPos, typ *types.Type, args []ir.Node) ir.Node {
20	if len(args) == 0 {
21		return ir.NewNilExpr(pos, typ)
22	}
23
24	args = append([]ir.Node(nil), args...)
25	lit := ir.NewCompLitExpr(pos, ir.OCOMPLIT, typ, args)
26	lit.SetImplicit(true)
27
28	n := Expr(lit)
29	if n.Type() == nil {
30		base.FatalfAt(pos, "mkdotargslice: typecheck failed")
31	}
32	return n
33}
34
35// FixVariadicCall rewrites calls to variadic functions to use an
36// explicit ... argument if one is not already present.
37func FixVariadicCall(call *ir.CallExpr) {
38	fntype := call.Fun.Type()
39	if !fntype.IsVariadic() || call.IsDDD {
40		return
41	}
42
43	vi := fntype.NumParams() - 1
44	vt := fntype.Param(vi).Type
45
46	args := call.Args
47	extra := args[vi:]
48	slice := MakeDotArgs(call.Pos(), vt, extra)
49	for i := range extra {
50		extra[i] = nil // allow GC
51	}
52
53	call.Args = append(args[:vi], slice)
54	call.IsDDD = true
55}
56
57// FixMethodCall rewrites a method call t.M(...) into a function call T.M(t, ...).
58func FixMethodCall(call *ir.CallExpr) {
59	if call.Fun.Op() != ir.ODOTMETH {
60		return
61	}
62
63	dot := call.Fun.(*ir.SelectorExpr)
64
65	fn := NewMethodExpr(dot.Pos(), dot.X.Type(), dot.Selection.Sym)
66
67	args := make([]ir.Node, 1+len(call.Args))
68	args[0] = dot.X
69	copy(args[1:], call.Args)
70
71	call.SetOp(ir.OCALLFUNC)
72	call.Fun = fn
73	call.Args = args
74}
75
76func AssertFixedCall(call *ir.CallExpr) {
77	if call.Fun.Type().IsVariadic() && !call.IsDDD {
78		base.FatalfAt(call.Pos(), "missed FixVariadicCall")
79	}
80	if call.Op() == ir.OCALLMETH {
81		base.FatalfAt(call.Pos(), "missed FixMethodCall")
82	}
83}
84
85// ClosureType returns the struct type used to hold all the information
86// needed in the closure for clo (clo must be a OCLOSURE node).
87// The address of a variable of the returned type can be cast to a func.
88func ClosureType(clo *ir.ClosureExpr) *types.Type {
89	// Create closure in the form of a composite literal.
90	// supposing the closure captures an int i and a string s
91	// and has one float64 argument and no results,
92	// the generated code looks like:
93	//
94	//	clos = &struct{F uintptr; X0 *int; X1 *string}{func.1, &i, &s}
95	//
96	// The use of the struct provides type information to the garbage
97	// collector so that it can walk the closure. We could use (in this
98	// case) [3]unsafe.Pointer instead, but that would leave the gc in
99	// the dark. The information appears in the binary in the form of
100	// type descriptors; the struct is unnamed and uses exported field
101	// names so that closures in multiple packages with the same struct
102	// type can share the descriptor.
103
104	fields := make([]*types.Field, 1+len(clo.Func.ClosureVars))
105	fields[0] = types.NewField(base.AutogeneratedPos, types.LocalPkg.Lookup("F"), types.Types[types.TUINTPTR])
106	it := NewClosureStructIter(clo.Func.ClosureVars)
107	i := 0
108	for {
109		n, typ, _ := it.Next()
110		if n == nil {
111			break
112		}
113		fields[1+i] = types.NewField(base.AutogeneratedPos, types.LocalPkg.LookupNum("X", i), typ)
114		i++
115	}
116	typ := types.NewStruct(fields)
117	typ.SetNoalg(true)
118	return typ
119}
120
121// MethodValueType returns the struct type used to hold all the information
122// needed in the closure for a OMETHVALUE node. The address of a variable of
123// the returned type can be cast to a func.
124func MethodValueType(n *ir.SelectorExpr) *types.Type {
125	t := types.NewStruct([]*types.Field{
126		types.NewField(base.Pos, Lookup("F"), types.Types[types.TUINTPTR]),
127		types.NewField(base.Pos, Lookup("R"), n.X.Type()),
128	})
129	t.SetNoalg(true)
130	return t
131}
132
133// type check function definition
134// To be called by typecheck, not directly.
135// (Call typecheck.Func instead.)
136func tcFunc(n *ir.Func) {
137	if base.EnableTrace && base.Flag.LowerT {
138		defer tracePrint("tcFunc", n)(nil)
139	}
140
141	if name := n.Nname; name.Typecheck() == 0 {
142		base.AssertfAt(name.Type() != nil, n.Pos(), "missing type: %v", name)
143		name.SetTypecheck(1)
144	}
145}
146
147// tcCall typechecks an OCALL node.
148func tcCall(n *ir.CallExpr, top int) ir.Node {
149	Stmts(n.Init()) // imported rewritten f(g()) calls (#30907)
150	n.Fun = typecheck(n.Fun, ctxExpr|ctxType|ctxCallee)
151
152	l := n.Fun
153
154	if l.Op() == ir.ONAME && l.(*ir.Name).BuiltinOp != 0 {
155		l := l.(*ir.Name)
156		if n.IsDDD && l.BuiltinOp != ir.OAPPEND {
157			base.Errorf("invalid use of ... with builtin %v", l)
158		}
159
160		// builtin: OLEN, OCAP, etc.
161		switch l.BuiltinOp {
162		default:
163			base.Fatalf("unknown builtin %v", l)
164
165		case ir.OAPPEND, ir.ODELETE, ir.OMAKE, ir.OMAX, ir.OMIN, ir.OPRINT, ir.OPRINTLN, ir.ORECOVER:
166			n.SetOp(l.BuiltinOp)
167			n.Fun = nil
168			n.SetTypecheck(0) // re-typechecking new op is OK, not a loop
169			return typecheck(n, top)
170
171		case ir.OCAP, ir.OCLEAR, ir.OCLOSE, ir.OIMAG, ir.OLEN, ir.OPANIC, ir.OREAL, ir.OUNSAFESTRINGDATA, ir.OUNSAFESLICEDATA:
172			typecheckargs(n)
173			fallthrough
174		case ir.ONEW:
175			arg, ok := needOneArg(n, "%v", n.Op())
176			if !ok {
177				n.SetType(nil)
178				return n
179			}
180			u := ir.NewUnaryExpr(n.Pos(), l.BuiltinOp, arg)
181			return typecheck(ir.InitExpr(n.Init(), u), top) // typecheckargs can add to old.Init
182
183		case ir.OCOMPLEX, ir.OCOPY, ir.OUNSAFEADD, ir.OUNSAFESLICE, ir.OUNSAFESTRING:
184			typecheckargs(n)
185			arg1, arg2, ok := needTwoArgs(n)
186			if !ok {
187				n.SetType(nil)
188				return n
189			}
190			b := ir.NewBinaryExpr(n.Pos(), l.BuiltinOp, arg1, arg2)
191			return typecheck(ir.InitExpr(n.Init(), b), top) // typecheckargs can add to old.Init
192		}
193		panic("unreachable")
194	}
195
196	n.Fun = DefaultLit(n.Fun, nil)
197	l = n.Fun
198	if l.Op() == ir.OTYPE {
199		if n.IsDDD {
200			base.Fatalf("invalid use of ... in type conversion to %v", l.Type())
201		}
202
203		// pick off before type-checking arguments
204		arg, ok := needOneArg(n, "conversion to %v", l.Type())
205		if !ok {
206			n.SetType(nil)
207			return n
208		}
209
210		n := ir.NewConvExpr(n.Pos(), ir.OCONV, nil, arg)
211		n.SetType(l.Type())
212		return tcConv(n)
213	}
214
215	RewriteNonNameCall(n)
216	typecheckargs(n)
217	t := l.Type()
218	if t == nil {
219		n.SetType(nil)
220		return n
221	}
222	types.CheckSize(t)
223
224	switch l.Op() {
225	case ir.ODOTINTER:
226		n.SetOp(ir.OCALLINTER)
227
228	case ir.ODOTMETH:
229		l := l.(*ir.SelectorExpr)
230		n.SetOp(ir.OCALLMETH)
231
232		// typecheckaste was used here but there wasn't enough
233		// information further down the call chain to know if we
234		// were testing a method receiver for unexported fields.
235		// It isn't necessary, so just do a sanity check.
236		tp := t.Recv().Type
237
238		if l.X == nil || !types.Identical(l.X.Type(), tp) {
239			base.Fatalf("method receiver")
240		}
241
242	default:
243		n.SetOp(ir.OCALLFUNC)
244		if t.Kind() != types.TFUNC {
245			if o := l; o.Name() != nil && types.BuiltinPkg.Lookup(o.Sym().Name).Def != nil {
246				// be more specific when the non-function
247				// name matches a predeclared function
248				base.Errorf("cannot call non-function %L, declared at %s",
249					l, base.FmtPos(o.Name().Pos()))
250			} else {
251				base.Errorf("cannot call non-function %L", l)
252			}
253			n.SetType(nil)
254			return n
255		}
256	}
257
258	typecheckaste(ir.OCALL, n.Fun, n.IsDDD, t.Params(), n.Args, func() string { return fmt.Sprintf("argument to %v", n.Fun) })
259	FixVariadicCall(n)
260	FixMethodCall(n)
261	if t.NumResults() == 0 {
262		return n
263	}
264	if t.NumResults() == 1 {
265		n.SetType(l.Type().Result(0).Type)
266
267		if n.Op() == ir.OCALLFUNC && n.Fun.Op() == ir.ONAME {
268			if sym := n.Fun.(*ir.Name).Sym(); types.RuntimeSymName(sym) == "getg" {
269				// Emit code for runtime.getg() directly instead of calling function.
270				// Most such rewrites (for example the similar one for math.Sqrt) should be done in walk,
271				// so that the ordering pass can make sure to preserve the semantics of the original code
272				// (in particular, the exact time of the function call) by introducing temporaries.
273				// In this case, we know getg() always returns the same result within a given function
274				// and we want to avoid the temporaries, so we do the rewrite earlier than is typical.
275				n.SetOp(ir.OGETG)
276			}
277		}
278		return n
279	}
280
281	// multiple return
282	if top&(ctxMultiOK|ctxStmt) == 0 {
283		base.Errorf("multiple-value %v() in single-value context", l)
284		return n
285	}
286
287	n.SetType(l.Type().ResultsTuple())
288	return n
289}
290
291// tcAppend typechecks an OAPPEND node.
292func tcAppend(n *ir.CallExpr) ir.Node {
293	typecheckargs(n)
294	args := n.Args
295	if len(args) == 0 {
296		base.Errorf("missing arguments to append")
297		n.SetType(nil)
298		return n
299	}
300
301	t := args[0].Type()
302	if t == nil {
303		n.SetType(nil)
304		return n
305	}
306
307	n.SetType(t)
308	if !t.IsSlice() {
309		if ir.IsNil(args[0]) {
310			base.Errorf("first argument to append must be typed slice; have untyped nil")
311			n.SetType(nil)
312			return n
313		}
314
315		base.Errorf("first argument to append must be slice; have %L", t)
316		n.SetType(nil)
317		return n
318	}
319
320	if n.IsDDD {
321		if len(args) == 1 {
322			base.Errorf("cannot use ... on first argument to append")
323			n.SetType(nil)
324			return n
325		}
326
327		if len(args) != 2 {
328			base.Errorf("too many arguments to append")
329			n.SetType(nil)
330			return n
331		}
332
333		// AssignConv is of args[1] not required here, as the
334		// types of args[0] and args[1] don't need to match
335		// (They will both have an underlying type which are
336		// slices of identical base types, or be []byte and string.)
337		// See issue 53888.
338		return n
339	}
340
341	as := args[1:]
342	for i, n := range as {
343		if n.Type() == nil {
344			continue
345		}
346		as[i] = AssignConv(n, t.Elem(), "append")
347		types.CheckSize(as[i].Type()) // ensure width is calculated for backend
348	}
349	return n
350}
351
352// tcClear typechecks an OCLEAR node.
353func tcClear(n *ir.UnaryExpr) ir.Node {
354	n.X = Expr(n.X)
355	n.X = DefaultLit(n.X, nil)
356	l := n.X
357	t := l.Type()
358	if t == nil {
359		n.SetType(nil)
360		return n
361	}
362
363	switch {
364	case t.IsMap(), t.IsSlice():
365	default:
366		base.Errorf("invalid operation: %v (argument must be a map or slice)", n)
367		n.SetType(nil)
368		return n
369	}
370
371	return n
372}
373
374// tcClose typechecks an OCLOSE node.
375func tcClose(n *ir.UnaryExpr) ir.Node {
376	n.X = Expr(n.X)
377	n.X = DefaultLit(n.X, nil)
378	l := n.X
379	t := l.Type()
380	if t == nil {
381		n.SetType(nil)
382		return n
383	}
384	if !t.IsChan() {
385		base.Errorf("invalid operation: %v (non-chan type %v)", n, t)
386		n.SetType(nil)
387		return n
388	}
389
390	if !t.ChanDir().CanSend() {
391		base.Errorf("invalid operation: %v (cannot close receive-only channel)", n)
392		n.SetType(nil)
393		return n
394	}
395	return n
396}
397
398// tcComplex typechecks an OCOMPLEX node.
399func tcComplex(n *ir.BinaryExpr) ir.Node {
400	l := Expr(n.X)
401	r := Expr(n.Y)
402	if l.Type() == nil || r.Type() == nil {
403		n.SetType(nil)
404		return n
405	}
406	l, r = defaultlit2(l, r, false)
407	if l.Type() == nil || r.Type() == nil {
408		n.SetType(nil)
409		return n
410	}
411	n.X = l
412	n.Y = r
413
414	if !types.Identical(l.Type(), r.Type()) {
415		base.Errorf("invalid operation: %v (mismatched types %v and %v)", n, l.Type(), r.Type())
416		n.SetType(nil)
417		return n
418	}
419
420	var t *types.Type
421	switch l.Type().Kind() {
422	default:
423		base.Errorf("invalid operation: %v (arguments have type %v, expected floating-point)", n, l.Type())
424		n.SetType(nil)
425		return n
426
427	case types.TIDEAL:
428		t = types.UntypedComplex
429
430	case types.TFLOAT32:
431		t = types.Types[types.TCOMPLEX64]
432
433	case types.TFLOAT64:
434		t = types.Types[types.TCOMPLEX128]
435	}
436	n.SetType(t)
437	return n
438}
439
440// tcCopy typechecks an OCOPY node.
441func tcCopy(n *ir.BinaryExpr) ir.Node {
442	n.SetType(types.Types[types.TINT])
443	n.X = Expr(n.X)
444	n.X = DefaultLit(n.X, nil)
445	n.Y = Expr(n.Y)
446	n.Y = DefaultLit(n.Y, nil)
447	if n.X.Type() == nil || n.Y.Type() == nil {
448		n.SetType(nil)
449		return n
450	}
451
452	// copy([]byte, string)
453	if n.X.Type().IsSlice() && n.Y.Type().IsString() {
454		if types.Identical(n.X.Type().Elem(), types.ByteType) {
455			return n
456		}
457		base.Errorf("arguments to copy have different element types: %L and string", n.X.Type())
458		n.SetType(nil)
459		return n
460	}
461
462	if !n.X.Type().IsSlice() || !n.Y.Type().IsSlice() {
463		if !n.X.Type().IsSlice() && !n.Y.Type().IsSlice() {
464			base.Errorf("arguments to copy must be slices; have %L, %L", n.X.Type(), n.Y.Type())
465		} else if !n.X.Type().IsSlice() {
466			base.Errorf("first argument to copy should be slice; have %L", n.X.Type())
467		} else {
468			base.Errorf("second argument to copy should be slice or string; have %L", n.Y.Type())
469		}
470		n.SetType(nil)
471		return n
472	}
473
474	if !types.Identical(n.X.Type().Elem(), n.Y.Type().Elem()) {
475		base.Errorf("arguments to copy have different element types: %L and %L", n.X.Type(), n.Y.Type())
476		n.SetType(nil)
477		return n
478	}
479	return n
480}
481
482// tcDelete typechecks an ODELETE node.
483func tcDelete(n *ir.CallExpr) ir.Node {
484	typecheckargs(n)
485	args := n.Args
486	if len(args) == 0 {
487		base.Errorf("missing arguments to delete")
488		n.SetType(nil)
489		return n
490	}
491
492	if len(args) == 1 {
493		base.Errorf("missing second (key) argument to delete")
494		n.SetType(nil)
495		return n
496	}
497
498	if len(args) != 2 {
499		base.Errorf("too many arguments to delete")
500		n.SetType(nil)
501		return n
502	}
503
504	l := args[0]
505	r := args[1]
506	if l.Type() != nil && !l.Type().IsMap() {
507		base.Errorf("first argument to delete must be map; have %L", l.Type())
508		n.SetType(nil)
509		return n
510	}
511
512	args[1] = AssignConv(r, l.Type().Key(), "delete")
513	return n
514}
515
516// tcMake typechecks an OMAKE node.
517func tcMake(n *ir.CallExpr) ir.Node {
518	args := n.Args
519	if len(args) == 0 {
520		base.Errorf("missing argument to make")
521		n.SetType(nil)
522		return n
523	}
524
525	n.Args = nil
526	l := args[0]
527	l = typecheck(l, ctxType)
528	t := l.Type()
529	if t == nil {
530		n.SetType(nil)
531		return n
532	}
533
534	i := 1
535	var nn ir.Node
536	switch t.Kind() {
537	default:
538		base.Errorf("cannot make type %v", t)
539		n.SetType(nil)
540		return n
541
542	case types.TSLICE:
543		if i >= len(args) {
544			base.Errorf("missing len argument to make(%v)", t)
545			n.SetType(nil)
546			return n
547		}
548
549		l = args[i]
550		i++
551		l = Expr(l)
552		var r ir.Node
553		if i < len(args) {
554			r = args[i]
555			i++
556			r = Expr(r)
557		}
558
559		if l.Type() == nil || (r != nil && r.Type() == nil) {
560			n.SetType(nil)
561			return n
562		}
563		if !checkmake(t, "len", &l) || r != nil && !checkmake(t, "cap", &r) {
564			n.SetType(nil)
565			return n
566		}
567		if ir.IsConst(l, constant.Int) && r != nil && ir.IsConst(r, constant.Int) && constant.Compare(l.Val(), token.GTR, r.Val()) {
568			base.Errorf("len larger than cap in make(%v)", t)
569			n.SetType(nil)
570			return n
571		}
572		nn = ir.NewMakeExpr(n.Pos(), ir.OMAKESLICE, l, r)
573
574	case types.TMAP:
575		if i < len(args) {
576			l = args[i]
577			i++
578			l = Expr(l)
579			l = DefaultLit(l, types.Types[types.TINT])
580			if l.Type() == nil {
581				n.SetType(nil)
582				return n
583			}
584			if !checkmake(t, "size", &l) {
585				n.SetType(nil)
586				return n
587			}
588		} else {
589			l = ir.NewInt(base.Pos, 0)
590		}
591		nn = ir.NewMakeExpr(n.Pos(), ir.OMAKEMAP, l, nil)
592		nn.SetEsc(n.Esc())
593
594	case types.TCHAN:
595		l = nil
596		if i < len(args) {
597			l = args[i]
598			i++
599			l = Expr(l)
600			l = DefaultLit(l, types.Types[types.TINT])
601			if l.Type() == nil {
602				n.SetType(nil)
603				return n
604			}
605			if !checkmake(t, "buffer", &l) {
606				n.SetType(nil)
607				return n
608			}
609		} else {
610			l = ir.NewInt(base.Pos, 0)
611		}
612		nn = ir.NewMakeExpr(n.Pos(), ir.OMAKECHAN, l, nil)
613	}
614
615	if i < len(args) {
616		base.Errorf("too many arguments to make(%v)", t)
617		n.SetType(nil)
618		return n
619	}
620
621	nn.SetType(t)
622	return nn
623}
624
625// tcMakeSliceCopy typechecks an OMAKESLICECOPY node.
626func tcMakeSliceCopy(n *ir.MakeExpr) ir.Node {
627	// Errors here are Fatalf instead of Errorf because only the compiler
628	// can construct an OMAKESLICECOPY node.
629	// Components used in OMAKESCLICECOPY that are supplied by parsed source code
630	// have already been typechecked in OMAKE and OCOPY earlier.
631	t := n.Type()
632
633	if t == nil {
634		base.Fatalf("no type specified for OMAKESLICECOPY")
635	}
636
637	if !t.IsSlice() {
638		base.Fatalf("invalid type %v for OMAKESLICECOPY", n.Type())
639	}
640
641	if n.Len == nil {
642		base.Fatalf("missing len argument for OMAKESLICECOPY")
643	}
644
645	if n.Cap == nil {
646		base.Fatalf("missing slice argument to copy for OMAKESLICECOPY")
647	}
648
649	n.Len = Expr(n.Len)
650	n.Cap = Expr(n.Cap)
651
652	n.Len = DefaultLit(n.Len, types.Types[types.TINT])
653
654	if !n.Len.Type().IsInteger() && n.Type().Kind() != types.TIDEAL {
655		base.Errorf("non-integer len argument in OMAKESLICECOPY")
656	}
657
658	if ir.IsConst(n.Len, constant.Int) {
659		if ir.ConstOverflow(n.Len.Val(), types.Types[types.TINT]) {
660			base.Fatalf("len for OMAKESLICECOPY too large")
661		}
662		if constant.Sign(n.Len.Val()) < 0 {
663			base.Fatalf("len for OMAKESLICECOPY must be non-negative")
664		}
665	}
666	return n
667}
668
669// tcNew typechecks an ONEW node.
670func tcNew(n *ir.UnaryExpr) ir.Node {
671	if n.X == nil {
672		// Fatalf because the OCALL above checked for us,
673		// so this must be an internally-generated mistake.
674		base.Fatalf("missing argument to new")
675	}
676	l := n.X
677	l = typecheck(l, ctxType)
678	t := l.Type()
679	if t == nil {
680		n.SetType(nil)
681		return n
682	}
683	n.X = l
684	n.SetType(types.NewPtr(t))
685	return n
686}
687
688// tcPanic typechecks an OPANIC node.
689func tcPanic(n *ir.UnaryExpr) ir.Node {
690	n.X = Expr(n.X)
691	n.X = AssignConv(n.X, types.Types[types.TINTER], "argument to panic")
692	if n.X.Type() == nil {
693		n.SetType(nil)
694		return n
695	}
696	return n
697}
698
699// tcPrint typechecks an OPRINT or OPRINTN node.
700func tcPrint(n *ir.CallExpr) ir.Node {
701	typecheckargs(n)
702	ls := n.Args
703	for i1, n1 := range ls {
704		// Special case for print: int constant is int64, not int.
705		if ir.IsConst(n1, constant.Int) {
706			ls[i1] = DefaultLit(ls[i1], types.Types[types.TINT64])
707		} else {
708			ls[i1] = DefaultLit(ls[i1], nil)
709		}
710	}
711	return n
712}
713
714// tcMinMax typechecks an OMIN or OMAX node.
715func tcMinMax(n *ir.CallExpr) ir.Node {
716	typecheckargs(n)
717	arg0 := n.Args[0]
718	for _, arg := range n.Args[1:] {
719		if !types.Identical(arg.Type(), arg0.Type()) {
720			base.FatalfAt(n.Pos(), "mismatched arguments: %L and %L", arg0, arg)
721		}
722	}
723	n.SetType(arg0.Type())
724	return n
725}
726
727// tcRealImag typechecks an OREAL or OIMAG node.
728func tcRealImag(n *ir.UnaryExpr) ir.Node {
729	n.X = Expr(n.X)
730	l := n.X
731	t := l.Type()
732	if t == nil {
733		n.SetType(nil)
734		return n
735	}
736
737	// Determine result type.
738	switch t.Kind() {
739	case types.TIDEAL:
740		n.SetType(types.UntypedFloat)
741	case types.TCOMPLEX64:
742		n.SetType(types.Types[types.TFLOAT32])
743	case types.TCOMPLEX128:
744		n.SetType(types.Types[types.TFLOAT64])
745	default:
746		base.Errorf("invalid argument %L for %v", l, n.Op())
747		n.SetType(nil)
748		return n
749	}
750	return n
751}
752
753// tcRecover typechecks an ORECOVER node.
754func tcRecover(n *ir.CallExpr) ir.Node {
755	if len(n.Args) != 0 {
756		base.Errorf("too many arguments to recover")
757		n.SetType(nil)
758		return n
759	}
760
761	// FP is equal to caller's SP plus FixedFrameSize.
762	var fp ir.Node = ir.NewCallExpr(n.Pos(), ir.OGETCALLERSP, nil, nil)
763	if off := base.Ctxt.Arch.FixedFrameSize; off != 0 {
764		fp = ir.NewBinaryExpr(n.Pos(), ir.OADD, fp, ir.NewInt(base.Pos, off))
765	}
766	// TODO(mdempsky): Replace *int32 with unsafe.Pointer, without upsetting checkptr.
767	fp = ir.NewConvExpr(n.Pos(), ir.OCONVNOP, types.NewPtr(types.Types[types.TINT32]), fp)
768
769	n.SetOp(ir.ORECOVERFP)
770	n.SetType(types.Types[types.TINTER])
771	n.Args = []ir.Node{Expr(fp)}
772	return n
773}
774
775// tcUnsafeAdd typechecks an OUNSAFEADD node.
776func tcUnsafeAdd(n *ir.BinaryExpr) *ir.BinaryExpr {
777	n.X = AssignConv(Expr(n.X), types.Types[types.TUNSAFEPTR], "argument to unsafe.Add")
778	n.Y = DefaultLit(Expr(n.Y), types.Types[types.TINT])
779	if n.X.Type() == nil || n.Y.Type() == nil {
780		n.SetType(nil)
781		return n
782	}
783	if !n.Y.Type().IsInteger() {
784		n.SetType(nil)
785		return n
786	}
787	n.SetType(n.X.Type())
788	return n
789}
790
791// tcUnsafeSlice typechecks an OUNSAFESLICE node.
792func tcUnsafeSlice(n *ir.BinaryExpr) *ir.BinaryExpr {
793	n.X = Expr(n.X)
794	n.Y = Expr(n.Y)
795	if n.X.Type() == nil || n.Y.Type() == nil {
796		n.SetType(nil)
797		return n
798	}
799	t := n.X.Type()
800	if !t.IsPtr() {
801		base.Errorf("first argument to unsafe.Slice must be pointer; have %L", t)
802	} else if t.Elem().NotInHeap() {
803		// TODO(mdempsky): This can be relaxed, but should only affect the
804		// Go runtime itself. End users should only see not-in-heap
805		// types due to incomplete C structs in cgo, and those types don't
806		// have a meaningful size anyway.
807		base.Errorf("unsafe.Slice of incomplete (or unallocatable) type not allowed")
808	}
809
810	if !checkunsafesliceorstring(n.Op(), &n.Y) {
811		n.SetType(nil)
812		return n
813	}
814	n.SetType(types.NewSlice(t.Elem()))
815	return n
816}
817
818// tcUnsafeString typechecks an OUNSAFESTRING node.
819func tcUnsafeString(n *ir.BinaryExpr) *ir.BinaryExpr {
820	n.X = Expr(n.X)
821	n.Y = Expr(n.Y)
822	if n.X.Type() == nil || n.Y.Type() == nil {
823		n.SetType(nil)
824		return n
825	}
826	t := n.X.Type()
827	if !t.IsPtr() || !types.Identical(t.Elem(), types.Types[types.TUINT8]) {
828		base.Errorf("first argument to unsafe.String must be *byte; have %L", t)
829	}
830
831	if !checkunsafesliceorstring(n.Op(), &n.Y) {
832		n.SetType(nil)
833		return n
834	}
835	n.SetType(types.Types[types.TSTRING])
836	return n
837}
838
839// ClosureStructIter iterates through a slice of closure variables returning
840// their type and offset in the closure struct.
841type ClosureStructIter struct {
842	closureVars []*ir.Name
843	offset      int64
844	next        int
845}
846
847// NewClosureStructIter creates a new ClosureStructIter for closureVars.
848func NewClosureStructIter(closureVars []*ir.Name) *ClosureStructIter {
849	return &ClosureStructIter{
850		closureVars: closureVars,
851		offset:      int64(types.PtrSize), // PtrSize to skip past function entry PC field
852		next:        0,
853	}
854}
855
856// Next returns the next name, type and offset of the next closure variable.
857// A nil name is returned after the last closure variable.
858func (iter *ClosureStructIter) Next() (n *ir.Name, typ *types.Type, offset int64) {
859	if iter.next >= len(iter.closureVars) {
860		return nil, nil, 0
861	}
862	n = iter.closureVars[iter.next]
863	typ = n.Type()
864	if !n.Byval() {
865		typ = types.NewPtr(typ)
866	}
867	iter.next++
868	offset = types.RoundUp(iter.offset, typ.Alignment())
869	iter.offset = offset + typ.Size()
870	return n, typ, offset
871}
872