1// Copyright 2021 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// This file contains transformation functions on nodes, which are the
6// transformations that the typecheck package does that are distinct from the
7// typechecking functionality. These transform functions are pared-down copies of
8// the original typechecking functions, with all code removed that is related to:
9//
10//    - Detecting compile-time errors (already done by types2)
11//    - Setting the actual type of existing nodes (already done based on
12//      type info from types2)
13//    - Dealing with untyped constants (which types2 has already resolved)
14//
15// Each of the transformation functions requires that node passed in has its type
16// and typecheck flag set. If the transformation function replaces or adds new
17// nodes, it will set the type and typecheck flag for those new nodes.
18
19package noder
20
21import (
22	"cmd/compile/internal/base"
23	"cmd/compile/internal/ir"
24	"cmd/compile/internal/typecheck"
25	"cmd/compile/internal/types"
26	"fmt"
27	"go/constant"
28)
29
30// Transformation functions for expressions
31
32// transformAdd transforms an addition operation (currently just addition of
33// strings). Corresponds to the "binary operators" case in typecheck.typecheck1.
34func transformAdd(n *ir.BinaryExpr) ir.Node {
35	assert(n.Type() != nil && n.Typecheck() == 1)
36	l := n.X
37	if l.Type().IsString() {
38		var add *ir.AddStringExpr
39		if l.Op() == ir.OADDSTR {
40			add = l.(*ir.AddStringExpr)
41			add.SetPos(n.Pos())
42		} else {
43			add = ir.NewAddStringExpr(n.Pos(), []ir.Node{l})
44		}
45		r := n.Y
46		if r.Op() == ir.OADDSTR {
47			r := r.(*ir.AddStringExpr)
48			add.List.Append(r.List.Take()...)
49		} else {
50			add.List.Append(r)
51		}
52		typed(l.Type(), add)
53		return add
54	}
55	return n
56}
57
58// Corresponds to typecheck.stringtoruneslit.
59func stringtoruneslit(n *ir.ConvExpr) ir.Node {
60	if n.X.Op() != ir.OLITERAL || n.X.Val().Kind() != constant.String {
61		base.Fatalf("stringtoarraylit %v", n)
62	}
63
64	var list []ir.Node
65	i := 0
66	eltType := n.Type().Elem()
67	for _, r := range ir.StringVal(n.X) {
68		elt := ir.NewKeyExpr(base.Pos, ir.NewInt(int64(i)), ir.NewInt(int64(r)))
69		// Change from untyped int to the actual element type determined
70		// by types2.  No need to change elt.Key, since the array indexes
71		// are just used for setting up the element ordering.
72		elt.Value.SetType(eltType)
73		list = append(list, elt)
74		i++
75	}
76
77	nn := ir.NewCompLitExpr(base.Pos, ir.OCOMPLIT, ir.TypeNode(n.Type()), nil)
78	nn.List = list
79	typed(n.Type(), nn)
80	// Need to transform the OCOMPLIT.
81	return transformCompLit(nn)
82}
83
84// transformConv transforms an OCONV node as needed, based on the types involved,
85// etc.  Corresponds to typecheck.tcConv.
86func transformConv(n *ir.ConvExpr) ir.Node {
87	t := n.X.Type()
88	op, why := typecheck.Convertop(n.X.Op() == ir.OLITERAL, t, n.Type())
89	if op == ir.OXXX {
90		// types2 currently ignores pragmas, so a 'notinheap' mismatch is the
91		// one type-related error that it does not catch. This error will be
92		// caught here by Convertop (see two checks near beginning of
93		// Convertop) and reported at the end of noding.
94		base.ErrorfAt(n.Pos(), "cannot convert %L to type %v%s", n.X, n.Type(), why)
95		return n
96	}
97	n.SetOp(op)
98	switch n.Op() {
99	case ir.OCONVNOP:
100		if t.Kind() == n.Type().Kind() {
101			switch t.Kind() {
102			case types.TFLOAT32, types.TFLOAT64, types.TCOMPLEX64, types.TCOMPLEX128:
103				// Floating point casts imply rounding and
104				// so the conversion must be kept.
105				n.SetOp(ir.OCONV)
106			}
107		}
108
109	// Do not convert to []byte literal. See CL 125796.
110	// Generated code and compiler memory footprint is better without it.
111	case ir.OSTR2BYTES:
112		// ok
113
114	case ir.OSTR2RUNES:
115		if n.X.Op() == ir.OLITERAL {
116			return stringtoruneslit(n)
117		}
118	}
119	return n
120}
121
122// transformConvCall transforms a conversion call. Corresponds to the OTYPE part of
123// typecheck.tcCall.
124func transformConvCall(n *ir.CallExpr) ir.Node {
125	assert(n.Type() != nil && n.Typecheck() == 1)
126	arg := n.Args[0]
127	n1 := ir.NewConvExpr(n.Pos(), ir.OCONV, nil, arg)
128	typed(n.X.Type(), n1)
129	return transformConv(n1)
130}
131
132// transformCall transforms a normal function/method call. Corresponds to last half
133// (non-conversion, non-builtin part) of typecheck.tcCall. This code should work even
134// in the case of OCALL/OFUNCINST.
135func transformCall(n *ir.CallExpr) {
136	// Set base.Pos, since transformArgs below may need it, but transformCall
137	// is called in some passes that don't set base.Pos.
138	ir.SetPos(n)
139	// n.Type() can be nil for calls with no return value
140	assert(n.Typecheck() == 1)
141	transformArgs(n)
142	l := n.X
143	t := l.Type()
144
145	switch l.Op() {
146	case ir.ODOTINTER:
147		n.SetOp(ir.OCALLINTER)
148
149	case ir.ODOTMETH:
150		l := l.(*ir.SelectorExpr)
151		n.SetOp(ir.OCALLMETH)
152
153		tp := t.Recv().Type
154
155		if l.X == nil || !types.Identical(l.X.Type(), tp) {
156			base.Fatalf("method receiver")
157		}
158
159	default:
160		n.SetOp(ir.OCALLFUNC)
161	}
162
163	typecheckaste(ir.OCALL, n.X, n.IsDDD, t.Params(), n.Args)
164	if l.Op() == ir.ODOTMETH && len(deref(n.X.Type().Recv().Type).RParams()) == 0 {
165		typecheck.FixMethodCall(n)
166	}
167	if t.NumResults() == 1 {
168		if n.Op() == ir.OCALLFUNC && n.X.Op() == ir.ONAME {
169			if sym := n.X.(*ir.Name).Sym(); types.IsRuntimePkg(sym.Pkg) && sym.Name == "getg" {
170				// Emit code for runtime.getg() directly instead of calling function.
171				// Most such rewrites (for example the similar one for math.Sqrt) should be done in walk,
172				// so that the ordering pass can make sure to preserve the semantics of the original code
173				// (in particular, the exact time of the function call) by introducing temporaries.
174				// In this case, we know getg() always returns the same result within a given function
175				// and we want to avoid the temporaries, so we do the rewrite earlier than is typical.
176				n.SetOp(ir.OGETG)
177			}
178		}
179		return
180	}
181}
182
183// transformEarlyCall transforms the arguments of a call with an OFUNCINST node.
184func transformEarlyCall(n *ir.CallExpr) {
185	transformArgs(n)
186	typecheckaste(ir.OCALL, n.X, n.IsDDD, n.X.Type().Params(), n.Args)
187}
188
189// transformCompare transforms a compare operation (currently just equals/not
190// equals). Corresponds to the "comparison operators" case in
191// typecheck.typecheck1, including tcArith.
192func transformCompare(n *ir.BinaryExpr) {
193	assert(n.Type() != nil && n.Typecheck() == 1)
194	if (n.Op() == ir.OEQ || n.Op() == ir.ONE) && !types.Identical(n.X.Type(), n.Y.Type()) {
195		// Comparison is okay as long as one side is assignable to the
196		// other. The only allowed case where the conversion is not CONVNOP is
197		// "concrete == interface". In that case, check comparability of
198		// the concrete type. The conversion allocates, so only do it if
199		// the concrete type is huge.
200		l, r := n.X, n.Y
201		lt, rt := l.Type(), r.Type()
202		converted := false
203		if rt.Kind() != types.TBLANK {
204			aop, _ := typecheck.Assignop(lt, rt)
205			if aop != ir.OXXX {
206				types.CalcSize(lt)
207				if lt.HasShape() || rt.IsInterface() == lt.IsInterface() || lt.Size() >= 1<<16 {
208					l = ir.NewConvExpr(base.Pos, aop, rt, l)
209					l.SetTypecheck(1)
210				}
211
212				converted = true
213			}
214		}
215
216		if !converted && lt.Kind() != types.TBLANK {
217			aop, _ := typecheck.Assignop(rt, lt)
218			if aop != ir.OXXX {
219				types.CalcSize(rt)
220				if rt.HasTParam() || rt.IsInterface() == lt.IsInterface() || rt.Size() >= 1<<16 {
221					r = ir.NewConvExpr(base.Pos, aop, lt, r)
222					r.SetTypecheck(1)
223				}
224			}
225		}
226		n.X, n.Y = l, r
227	}
228}
229
230// Corresponds to typecheck.implicitstar.
231func implicitstar(n ir.Node) ir.Node {
232	// insert implicit * if needed for fixed array
233	t := n.Type()
234	if !t.IsPtr() {
235		return n
236	}
237	t = t.Elem()
238	if !t.IsArray() {
239		return n
240	}
241	star := ir.NewStarExpr(base.Pos, n)
242	star.SetImplicit(true)
243	return typed(t, star)
244}
245
246// transformIndex transforms an index operation.  Corresponds to typecheck.tcIndex.
247func transformIndex(n *ir.IndexExpr) {
248	assert(n.Type() != nil && n.Typecheck() == 1)
249	n.X = implicitstar(n.X)
250	l := n.X
251	t := l.Type()
252	if t.Kind() == types.TMAP {
253		n.Index = assignconvfn(n.Index, t.Key())
254		n.SetOp(ir.OINDEXMAP)
255		// Set type to just the map value, not (value, bool). This is
256		// different from types2, but fits the later stages of the
257		// compiler better.
258		n.SetType(t.Elem())
259		n.Assigned = false
260	}
261}
262
263// transformSlice transforms a slice operation.  Corresponds to typecheck.tcSlice.
264func transformSlice(n *ir.SliceExpr) {
265	assert(n.Type() != nil && n.Typecheck() == 1)
266	l := n.X
267	if l.Type().IsArray() {
268		addr := typecheck.NodAddr(n.X)
269		addr.SetImplicit(true)
270		typed(types.NewPtr(n.X.Type()), addr)
271		n.X = addr
272		l = addr
273	}
274	t := l.Type()
275	if t.IsString() {
276		n.SetOp(ir.OSLICESTR)
277	} else if t.IsPtr() && t.Elem().IsArray() {
278		if n.Op().IsSlice3() {
279			n.SetOp(ir.OSLICE3ARR)
280		} else {
281			n.SetOp(ir.OSLICEARR)
282		}
283	}
284}
285
286// Transformation functions for statements
287
288// Corresponds to typecheck.checkassign.
289func transformCheckAssign(stmt ir.Node, n ir.Node) {
290	if n.Op() == ir.OINDEXMAP {
291		n := n.(*ir.IndexExpr)
292		n.Assigned = true
293		return
294	}
295}
296
297// Corresponds to typecheck.assign.
298func transformAssign(stmt ir.Node, lhs, rhs []ir.Node) {
299	checkLHS := func(i int, typ *types.Type) {
300		transformCheckAssign(stmt, lhs[i])
301	}
302
303	cr := len(rhs)
304	if len(rhs) == 1 {
305		if rtyp := rhs[0].Type(); rtyp != nil && rtyp.IsFuncArgStruct() {
306			cr = rtyp.NumFields()
307		}
308	}
309
310	// x, ok = y
311assignOK:
312	for len(lhs) == 2 && cr == 1 {
313		stmt := stmt.(*ir.AssignListStmt)
314		r := rhs[0]
315
316		switch r.Op() {
317		case ir.OINDEXMAP:
318			stmt.SetOp(ir.OAS2MAPR)
319		case ir.ORECV:
320			stmt.SetOp(ir.OAS2RECV)
321		case ir.ODOTTYPE:
322			r := r.(*ir.TypeAssertExpr)
323			stmt.SetOp(ir.OAS2DOTTYPE)
324			r.SetOp(ir.ODOTTYPE2)
325		case ir.ODYNAMICDOTTYPE:
326			r := r.(*ir.DynamicTypeAssertExpr)
327			stmt.SetOp(ir.OAS2DOTTYPE)
328			r.SetOp(ir.ODYNAMICDOTTYPE2)
329		default:
330			break assignOK
331		}
332		checkLHS(0, r.Type())
333		checkLHS(1, types.UntypedBool)
334		return
335	}
336
337	if len(lhs) != cr {
338		for i := range lhs {
339			checkLHS(i, nil)
340		}
341		return
342	}
343
344	// x,y,z = f()
345	if cr > len(rhs) {
346		stmt := stmt.(*ir.AssignListStmt)
347		stmt.SetOp(ir.OAS2FUNC)
348		r := rhs[0].(*ir.CallExpr)
349		rtyp := r.Type()
350
351		mismatched := false
352		failed := false
353		for i := range lhs {
354			result := rtyp.Field(i).Type
355			checkLHS(i, result)
356
357			if lhs[i].Type() == nil || result == nil {
358				failed = true
359			} else if lhs[i] != ir.BlankNode && !types.Identical(lhs[i].Type(), result) {
360				mismatched = true
361			}
362		}
363		if mismatched && !failed {
364			typecheck.RewriteMultiValueCall(stmt, r)
365		}
366		return
367	}
368
369	for i, r := range rhs {
370		checkLHS(i, r.Type())
371		if lhs[i].Type() != nil {
372			rhs[i] = assignconvfn(r, lhs[i].Type())
373		}
374	}
375}
376
377// Corresponds to typecheck.typecheckargs.  Really just deals with multi-value calls.
378func transformArgs(n ir.InitNode) {
379	var list []ir.Node
380	switch n := n.(type) {
381	default:
382		base.Fatalf("transformArgs %+v", n.Op())
383	case *ir.CallExpr:
384		list = n.Args
385		if n.IsDDD {
386			return
387		}
388	case *ir.ReturnStmt:
389		list = n.Results
390	}
391	if len(list) != 1 {
392		return
393	}
394
395	t := list[0].Type()
396	if t == nil || !t.IsFuncArgStruct() {
397		return
398	}
399
400	// Save n as n.Orig for fmt.go.
401	if ir.Orig(n) == n {
402		n.(ir.OrigNode).SetOrig(ir.SepCopy(n))
403	}
404
405	// Rewrite f(g()) into t1, t2, ... = g(); f(t1, t2, ...).
406	typecheck.RewriteMultiValueCall(n, list[0])
407}
408
409// assignconvfn converts node n for assignment to type t. Corresponds to
410// typecheck.assignconvfn.
411func assignconvfn(n ir.Node, t *types.Type) ir.Node {
412	if t.Kind() == types.TBLANK {
413		return n
414	}
415
416	if n.Op() == ir.OPAREN {
417		n = n.(*ir.ParenExpr).X
418	}
419
420	if types.IdenticalStrict(n.Type(), t) {
421		return n
422	}
423
424	op, why := Assignop(n.Type(), t)
425	if op == ir.OXXX {
426		base.Fatalf("found illegal assignment %+v -> %+v; %s", n.Type(), t, why)
427	}
428
429	r := ir.NewConvExpr(base.Pos, op, t, n)
430	r.SetTypecheck(1)
431	r.SetImplicit(true)
432	return r
433}
434
435func Assignop(src, dst *types.Type) (ir.Op, string) {
436	if src == dst {
437		return ir.OCONVNOP, ""
438	}
439	if src == nil || dst == nil || src.Kind() == types.TFORW || dst.Kind() == types.TFORW || src.Underlying() == nil || dst.Underlying() == nil {
440		return ir.OXXX, ""
441	}
442
443	// 1. src type is identical to dst (taking shapes into account)
444	if types.Identical(src, dst) {
445		// We already know from assignconvfn above that IdenticalStrict(src,
446		// dst) is false, so the types are not exactly the same and one of
447		// src or dst is a shape. If dst is an interface (which means src is
448		// an interface too), we need a real OCONVIFACE op; otherwise we need a
449		// OCONVNOP. See issue #48453.
450		if dst.IsInterface() {
451			return ir.OCONVIFACE, ""
452		} else {
453			return ir.OCONVNOP, ""
454		}
455	}
456	return typecheck.Assignop1(src, dst)
457}
458
459// Corresponds to typecheck.typecheckaste, but we add an extra flag convifaceOnly
460// only. If convifaceOnly is true, we only do interface conversion. We use this to do
461// early insertion of CONVIFACE nodes during noder2, when the function or args may
462// have typeparams.
463func typecheckaste(op ir.Op, call ir.Node, isddd bool, tstruct *types.Type, nl ir.Nodes) {
464	var t *types.Type
465	var i int
466
467	lno := base.Pos
468	defer func() { base.Pos = lno }()
469
470	var n ir.Node
471	if len(nl) == 1 {
472		n = nl[0]
473	}
474
475	i = 0
476	for _, tl := range tstruct.Fields().Slice() {
477		t = tl.Type
478		if tl.IsDDD() {
479			if isddd {
480				n = nl[i]
481				ir.SetPos(n)
482				if n.Type() != nil {
483					nl[i] = assignconvfn(n, t)
484				}
485				return
486			}
487
488			// TODO(mdempsky): Make into ... call with implicit slice.
489			for ; i < len(nl); i++ {
490				n = nl[i]
491				ir.SetPos(n)
492				if n.Type() != nil {
493					nl[i] = assignconvfn(n, t.Elem())
494				}
495			}
496			return
497		}
498
499		n = nl[i]
500		ir.SetPos(n)
501		if n.Type() != nil {
502			nl[i] = assignconvfn(n, t)
503		}
504		i++
505	}
506}
507
508// transformSend transforms a send statement, converting the value to appropriate
509// type for the channel, as needed. Corresponds of typecheck.tcSend.
510func transformSend(n *ir.SendStmt) {
511	n.Value = assignconvfn(n.Value, n.Chan.Type().Elem())
512}
513
514// transformReturn transforms a return node, by doing the needed assignments and
515// any necessary conversions. Corresponds to typecheck.tcReturn()
516func transformReturn(rs *ir.ReturnStmt) {
517	transformArgs(rs)
518	nl := rs.Results
519	if ir.HasNamedResults(ir.CurFunc) && len(nl) == 0 {
520		return
521	}
522
523	typecheckaste(ir.ORETURN, nil, false, ir.CurFunc.Type().Results(), nl)
524}
525
526// transformSelect transforms a select node, creating an assignment list as needed
527// for each case. Corresponds to typecheck.tcSelect().
528func transformSelect(sel *ir.SelectStmt) {
529	for _, ncase := range sel.Cases {
530		if ncase.Comm != nil {
531			n := ncase.Comm
532			oselrecv2 := func(dst, recv ir.Node, def bool) {
533				selrecv := ir.NewAssignListStmt(n.Pos(), ir.OSELRECV2, []ir.Node{dst, ir.BlankNode}, []ir.Node{recv})
534				if dst.Op() == ir.ONAME && dst.(*ir.Name).Defn == n {
535					// Must fix Defn for dst, since we are
536					// completely changing the node.
537					dst.(*ir.Name).Defn = selrecv
538				}
539				selrecv.Def = def
540				selrecv.SetTypecheck(1)
541				selrecv.SetInit(n.Init())
542				ncase.Comm = selrecv
543			}
544			switch n.Op() {
545			case ir.OAS:
546				// convert x = <-c into x, _ = <-c
547				// remove implicit conversions; the eventual assignment
548				// will reintroduce them.
549				n := n.(*ir.AssignStmt)
550				if r := n.Y; r.Op() == ir.OCONVNOP || r.Op() == ir.OCONVIFACE {
551					r := r.(*ir.ConvExpr)
552					if r.Implicit() {
553						n.Y = r.X
554					}
555				}
556				oselrecv2(n.X, n.Y, n.Def)
557
558			case ir.OAS2RECV:
559				n := n.(*ir.AssignListStmt)
560				n.SetOp(ir.OSELRECV2)
561
562			case ir.ORECV:
563				// convert <-c into _, _ = <-c
564				n := n.(*ir.UnaryExpr)
565				oselrecv2(ir.BlankNode, n, false)
566
567			case ir.OSEND:
568				break
569			}
570		}
571	}
572}
573
574// transformAsOp transforms an AssignOp statement. Corresponds to OASOP case in
575// typecheck1.
576func transformAsOp(n *ir.AssignOpStmt) {
577	transformCheckAssign(n, n.X)
578}
579
580// transformDot transforms an OXDOT (or ODOT) or ODOT, ODOTPTR, ODOTMETH,
581// ODOTINTER, or OMETHVALUE, as appropriate. It adds in extra nodes as needed to
582// access embedded fields. Corresponds to typecheck.tcDot.
583func transformDot(n *ir.SelectorExpr, isCall bool) ir.Node {
584	assert(n.Type() != nil && n.Typecheck() == 1)
585	if n.Op() == ir.OXDOT {
586		n = typecheck.AddImplicitDots(n)
587		n.SetOp(ir.ODOT)
588
589		// Set the Selection field and typecheck flag for any new ODOT nodes
590		// added by AddImplicitDots(), and also transform to ODOTPTR if
591		// needed. Equivalent to 'n.X = typecheck(n.X, ctxExpr|ctxType)' in
592		// tcDot.
593		for n1 := n; n1.X.Op() == ir.ODOT; {
594			n1 = n1.X.(*ir.SelectorExpr)
595			if !n1.Implicit() {
596				break
597			}
598			t1 := n1.X.Type()
599			if t1.IsPtr() && !t1.Elem().IsInterface() {
600				t1 = t1.Elem()
601				n1.SetOp(ir.ODOTPTR)
602			}
603			typecheck.Lookdot(n1, t1, 0)
604			n1.SetTypecheck(1)
605		}
606	}
607
608	t := n.X.Type()
609
610	if n.X.Op() == ir.OTYPE {
611		return transformMethodExpr(n)
612	}
613
614	if t.IsPtr() && !t.Elem().IsInterface() {
615		t = t.Elem()
616		n.SetOp(ir.ODOTPTR)
617	}
618
619	f := typecheck.Lookdot(n, t, 0)
620	assert(f != nil)
621
622	if (n.Op() == ir.ODOTINTER || n.Op() == ir.ODOTMETH) && !isCall {
623		n.SetOp(ir.OMETHVALUE)
624		// This converts a method type to a function type. See issue 47775.
625		n.SetType(typecheck.NewMethodType(n.Type(), nil))
626	}
627	return n
628}
629
630// Corresponds to typecheck.typecheckMethodExpr.
631func transformMethodExpr(n *ir.SelectorExpr) (res ir.Node) {
632	t := n.X.Type()
633
634	// Compute the method set for t.
635	var ms *types.Fields
636	if t.IsInterface() {
637		ms = t.AllMethods()
638	} else {
639		mt := types.ReceiverBaseType(t)
640		typecheck.CalcMethods(mt)
641		ms = mt.AllMethods()
642
643		// The method expression T.m requires a wrapper when T
644		// is different from m's declared receiver type. We
645		// normally generate these wrappers while writing out
646		// runtime type descriptors, which is always done for
647		// types declared at package scope. However, we need
648		// to make sure to generate wrappers for anonymous
649		// receiver types too.
650		if mt.Sym() == nil {
651			typecheck.NeedRuntimeType(t)
652		}
653	}
654
655	s := n.Sel
656	m := typecheck.Lookdot1(n, s, t, ms, 0)
657	if !t.HasShape() {
658		// It's OK to not find the method if t is instantiated by shape types,
659		// because we will use the methods on the generic type anyway.
660		assert(m != nil)
661	}
662
663	n.SetOp(ir.OMETHEXPR)
664	n.Selection = m
665	n.SetType(typecheck.NewMethodType(m.Type, n.X.Type()))
666	return n
667}
668
669// Corresponds to typecheck.tcAppend.
670func transformAppend(n *ir.CallExpr) ir.Node {
671	transformArgs(n)
672	args := n.Args
673	t := args[0].Type()
674	assert(t.IsSlice())
675
676	if n.IsDDD {
677		if t.Elem().IsKind(types.TUINT8) && args[1].Type().IsString() {
678			return n
679		}
680
681		args[1] = assignconvfn(args[1], t.Underlying())
682		return n
683	}
684
685	as := args[1:]
686	for i, n := range as {
687		assert(n.Type() != nil)
688		as[i] = assignconvfn(n, t.Elem())
689	}
690	return n
691}
692
693// Corresponds to typecheck.tcComplex.
694func transformComplex(n *ir.BinaryExpr) ir.Node {
695	l := n.X
696	r := n.Y
697
698	assert(types.Identical(l.Type(), r.Type()))
699
700	var t *types.Type
701	switch l.Type().Kind() {
702	case types.TFLOAT32:
703		t = types.Types[types.TCOMPLEX64]
704	case types.TFLOAT64:
705		t = types.Types[types.TCOMPLEX128]
706	default:
707		panic(fmt.Sprintf("transformComplex: unexpected type %v", l.Type()))
708	}
709
710	// Must set the type here for generics, because this can't be determined
711	// by substitution of the generic types.
712	typed(t, n)
713	return n
714}
715
716// Corresponds to typecheck.tcDelete.
717func transformDelete(n *ir.CallExpr) ir.Node {
718	transformArgs(n)
719	args := n.Args
720	assert(len(args) == 2)
721
722	l := args[0]
723	r := args[1]
724
725	args[1] = assignconvfn(r, l.Type().Key())
726	return n
727}
728
729// Corresponds to typecheck.tcMake.
730func transformMake(n *ir.CallExpr) ir.Node {
731	args := n.Args
732
733	n.Args = nil
734	l := args[0]
735	t := l.Type()
736	assert(t != nil)
737
738	i := 1
739	var nn ir.Node
740	switch t.Kind() {
741	case types.TSLICE:
742		l = args[i]
743		i++
744		var r ir.Node
745		if i < len(args) {
746			r = args[i]
747			i++
748		}
749		nn = ir.NewMakeExpr(n.Pos(), ir.OMAKESLICE, l, r)
750
751	case types.TMAP:
752		if i < len(args) {
753			l = args[i]
754			i++
755		} else {
756			l = ir.NewInt(0)
757		}
758		nn = ir.NewMakeExpr(n.Pos(), ir.OMAKEMAP, l, nil)
759		nn.SetEsc(n.Esc())
760
761	case types.TCHAN:
762		l = nil
763		if i < len(args) {
764			l = args[i]
765			i++
766		} else {
767			l = ir.NewInt(0)
768		}
769		nn = ir.NewMakeExpr(n.Pos(), ir.OMAKECHAN, l, nil)
770	default:
771		panic(fmt.Sprintf("transformMake: unexpected type %v", t))
772	}
773
774	assert(i == len(args))
775	typed(n.Type(), nn)
776	return nn
777}
778
779// Corresponds to typecheck.tcPanic.
780func transformPanic(n *ir.UnaryExpr) ir.Node {
781	n.X = assignconvfn(n.X, types.Types[types.TINTER])
782	return n
783}
784
785// Corresponds to typecheck.tcPrint.
786func transformPrint(n *ir.CallExpr) ir.Node {
787	transformArgs(n)
788	return n
789}
790
791// Corresponds to typecheck.tcRealImag.
792func transformRealImag(n *ir.UnaryExpr) ir.Node {
793	l := n.X
794	var t *types.Type
795
796	// Determine result type.
797	switch l.Type().Kind() {
798	case types.TCOMPLEX64:
799		t = types.Types[types.TFLOAT32]
800	case types.TCOMPLEX128:
801		t = types.Types[types.TFLOAT64]
802	default:
803		panic(fmt.Sprintf("transformRealImag: unexpected type %v", l.Type()))
804	}
805
806	// Must set the type here for generics, because this can't be determined
807	// by substitution of the generic types.
808	typed(t, n)
809	return n
810}
811
812// Corresponds to typecheck.tcLenCap.
813func transformLenCap(n *ir.UnaryExpr) ir.Node {
814	n.X = implicitstar(n.X)
815	return n
816}
817
818// Corresponds to Builtin part of tcCall.
819func transformBuiltin(n *ir.CallExpr) ir.Node {
820	// n.Type() can be nil for builtins with no return value
821	assert(n.Typecheck() == 1)
822	fun := n.X.(*ir.Name)
823	op := fun.BuiltinOp
824
825	switch op {
826	case ir.OAPPEND, ir.ODELETE, ir.OMAKE, ir.OPRINT, ir.OPRINTN, ir.ORECOVER:
827		n.SetOp(op)
828		n.X = nil
829		switch op {
830		case ir.OAPPEND:
831			return transformAppend(n)
832		case ir.ODELETE:
833			return transformDelete(n)
834		case ir.OMAKE:
835			return transformMake(n)
836		case ir.OPRINT, ir.OPRINTN:
837			return transformPrint(n)
838		case ir.ORECOVER:
839			// nothing more to do
840			return n
841		}
842
843	case ir.OCAP, ir.OCLOSE, ir.OIMAG, ir.OLEN, ir.OPANIC, ir.OREAL:
844		transformArgs(n)
845		fallthrough
846
847	case ir.ONEW, ir.OALIGNOF, ir.OOFFSETOF, ir.OSIZEOF:
848		u := ir.NewUnaryExpr(n.Pos(), op, n.Args[0])
849		u1 := typed(n.Type(), ir.InitExpr(n.Init(), u)) // typecheckargs can add to old.Init
850		switch op {
851		case ir.OCAP, ir.OLEN:
852			return transformLenCap(u1.(*ir.UnaryExpr))
853		case ir.OREAL, ir.OIMAG:
854			return transformRealImag(u1.(*ir.UnaryExpr))
855		case ir.OPANIC:
856			return transformPanic(u1.(*ir.UnaryExpr))
857		case ir.OALIGNOF, ir.OOFFSETOF, ir.OSIZEOF:
858			// This corresponds to the EvalConst() call near end of typecheck().
859			return typecheck.EvalConst(u1)
860		case ir.OCLOSE, ir.ONEW:
861			// nothing more to do
862			return u1
863		}
864
865	case ir.OCOMPLEX, ir.OCOPY, ir.OUNSAFEADD, ir.OUNSAFESLICE:
866		transformArgs(n)
867		b := ir.NewBinaryExpr(n.Pos(), op, n.Args[0], n.Args[1])
868		n1 := typed(n.Type(), ir.InitExpr(n.Init(), b))
869		if op != ir.OCOMPLEX {
870			// nothing more to do
871			return n1
872		}
873		return transformComplex(n1.(*ir.BinaryExpr))
874
875	default:
876		panic(fmt.Sprintf("transformBuiltin: unexpected op %v", op))
877	}
878
879	return n
880}
881
882func hasKeys(l ir.Nodes) bool {
883	for _, n := range l {
884		if n.Op() == ir.OKEY || n.Op() == ir.OSTRUCTKEY {
885			return true
886		}
887	}
888	return false
889}
890
891// transformArrayLit runs assignconvfn on each array element and returns the
892// length of the slice/array that is needed to hold all the array keys/indexes
893// (one more than the highest index). Corresponds to typecheck.typecheckarraylit.
894func transformArrayLit(elemType *types.Type, bound int64, elts []ir.Node) int64 {
895	var key, length int64
896	for i, elt := range elts {
897		ir.SetPos(elt)
898		r := elts[i]
899		var kv *ir.KeyExpr
900		if elt.Op() == ir.OKEY {
901			elt := elt.(*ir.KeyExpr)
902			key = typecheck.IndexConst(elt.Key)
903			assert(key >= 0)
904			kv = elt
905			r = elt.Value
906		}
907
908		r = assignconvfn(r, elemType)
909		if kv != nil {
910			kv.Value = r
911		} else {
912			elts[i] = r
913		}
914
915		key++
916		if key > length {
917			length = key
918		}
919	}
920
921	return length
922}
923
924// transformCompLit transforms n to an OARRAYLIT, OSLICELIT, OMAPLIT, or
925// OSTRUCTLIT node, with any needed conversions. Corresponds to
926// typecheck.tcCompLit (and includes parts corresponding to tcStructLitKey).
927func transformCompLit(n *ir.CompLitExpr) (res ir.Node) {
928	assert(n.Type() != nil && n.Typecheck() == 1)
929	lno := base.Pos
930	defer func() {
931		base.Pos = lno
932	}()
933
934	// Save original node (including n.Right)
935	n.SetOrig(ir.Copy(n))
936
937	ir.SetPos(n)
938
939	t := n.Type()
940
941	switch t.Kind() {
942	default:
943		base.Fatalf("transformCompLit %v", t.Kind())
944
945	case types.TARRAY:
946		transformArrayLit(t.Elem(), t.NumElem(), n.List)
947		n.SetOp(ir.OARRAYLIT)
948
949	case types.TSLICE:
950		length := transformArrayLit(t.Elem(), -1, n.List)
951		n.SetOp(ir.OSLICELIT)
952		n.Len = length
953
954	case types.TMAP:
955		for _, l := range n.List {
956			ir.SetPos(l)
957			assert(l.Op() == ir.OKEY)
958			l := l.(*ir.KeyExpr)
959
960			r := l.Key
961			l.Key = assignconvfn(r, t.Key())
962
963			r = l.Value
964			l.Value = assignconvfn(r, t.Elem())
965		}
966
967		n.SetOp(ir.OMAPLIT)
968
969	case types.TSTRUCT:
970		// Need valid field offsets for Xoffset below.
971		types.CalcSize(t)
972
973		if len(n.List) != 0 && !hasKeys(n.List) {
974			// simple list of values
975			ls := n.List
976			for i, n1 := range ls {
977				ir.SetPos(n1)
978
979				f := t.Field(i)
980				n1 = assignconvfn(n1, f.Type)
981				ls[i] = ir.NewStructKeyExpr(base.Pos, f, n1)
982			}
983			assert(len(ls) >= t.NumFields())
984		} else {
985			// keyed list
986			ls := n.List
987			for i, l := range ls {
988				ir.SetPos(l)
989
990				kv := l.(*ir.KeyExpr)
991				key := kv.Key
992
993				// Sym might have resolved to name in other top-level
994				// package, because of import dot. Redirect to correct sym
995				// before we do the lookup.
996				s := key.Sym()
997				if id, ok := key.(*ir.Ident); ok && typecheck.DotImportRefs[id] != nil {
998					s = typecheck.Lookup(s.Name)
999				}
1000				if types.IsExported(s.Name) && s.Pkg != types.LocalPkg {
1001					// Exported field names should always have
1002					// local pkg. We only need to do this
1003					// adjustment for generic functions that are
1004					// being transformed after being imported
1005					// from another package.
1006					s = typecheck.Lookup(s.Name)
1007				}
1008
1009				// An OXDOT uses the Sym field to hold
1010				// the field to the right of the dot,
1011				// so s will be non-nil, but an OXDOT
1012				// is never a valid struct literal key.
1013				assert(!(s == nil || key.Op() == ir.OXDOT || s.IsBlank()))
1014
1015				f := typecheck.Lookdot1(nil, s, t, t.Fields(), 0)
1016				l := ir.NewStructKeyExpr(l.Pos(), f, kv.Value)
1017				ls[i] = l
1018
1019				l.Value = assignconvfn(l.Value, f.Type)
1020			}
1021		}
1022
1023		n.SetOp(ir.OSTRUCTLIT)
1024	}
1025
1026	return n
1027}
1028
1029// transformAddr corresponds to typecheck.tcAddr.
1030func transformAddr(n *ir.AddrExpr) {
1031	switch n.X.Op() {
1032	case ir.OARRAYLIT, ir.OMAPLIT, ir.OSLICELIT, ir.OSTRUCTLIT:
1033		n.SetOp(ir.OPTRLIT)
1034	}
1035}
1036