Black Lives Matter. Support the Equal Justice Initiative.

Source file src/cmd/compile/internal/noder/transform.go

Documentation: cmd/compile/internal/noder

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

View as plain text