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