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

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

View as plain text