Source file src/cmd/compile/internal/noder/helpers.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  package noder
     6  
     7  import (
     8  	"go/constant"
     9  
    10  	"cmd/compile/internal/base"
    11  	"cmd/compile/internal/ir"
    12  	"cmd/compile/internal/typecheck"
    13  	"cmd/compile/internal/types"
    14  	"cmd/internal/src"
    15  )
    16  
    17  // Helpers for constructing typed IR nodes.
    18  //
    19  // TODO(mdempsky): Move into their own package so they can be easily
    20  // reused by iimport and frontend optimizations.
    21  
    22  type ImplicitNode interface {
    23  	ir.Node
    24  	SetImplicit(x bool)
    25  }
    26  
    27  // Implicit returns n after marking it as Implicit.
    28  func Implicit(n ImplicitNode) ImplicitNode {
    29  	n.SetImplicit(true)
    30  	return n
    31  }
    32  
    33  // typed returns n after setting its type to typ.
    34  func typed(typ *types.Type, n ir.Node) ir.Node {
    35  	n.SetType(typ)
    36  	n.SetTypecheck(1)
    37  	return n
    38  }
    39  
    40  // Values
    41  
    42  func Const(pos src.XPos, typ *types.Type, val constant.Value) ir.Node {
    43  	return typed(typ, ir.NewBasicLit(pos, val))
    44  }
    45  
    46  func OrigConst(pos src.XPos, typ *types.Type, val constant.Value, op ir.Op, raw string) ir.Node {
    47  	orig := ir.NewRawOrigExpr(pos, op, raw)
    48  	return ir.NewConstExpr(val, typed(typ, orig))
    49  }
    50  
    51  // FixValue returns val after converting and truncating it as
    52  // appropriate for typ.
    53  func FixValue(typ *types.Type, val constant.Value) constant.Value {
    54  	assert(typ.Kind() != types.TFORW)
    55  	switch {
    56  	case typ.IsInteger():
    57  		val = constant.ToInt(val)
    58  	case typ.IsFloat():
    59  		val = constant.ToFloat(val)
    60  	case typ.IsComplex():
    61  		val = constant.ToComplex(val)
    62  	}
    63  	if !typ.IsUntyped() {
    64  		val = typecheck.DefaultLit(ir.NewBasicLit(src.NoXPos, val), typ).Val()
    65  	}
    66  	if !typ.IsTypeParam() {
    67  		ir.AssertValidTypeForConst(typ, val)
    68  	}
    69  	return val
    70  }
    71  
    72  func Nil(pos src.XPos, typ *types.Type) ir.Node {
    73  	return typed(typ, ir.NewNilExpr(pos))
    74  }
    75  
    76  // Expressions
    77  
    78  func Addr(pos src.XPos, x ir.Node) *ir.AddrExpr {
    79  	n := typecheck.NodAddrAt(pos, x)
    80  	typed(types.NewPtr(x.Type()), n)
    81  	return n
    82  }
    83  
    84  func Assert(pos src.XPos, x ir.Node, typ *types.Type) ir.Node {
    85  	return typed(typ, ir.NewTypeAssertExpr(pos, x, nil))
    86  }
    87  
    88  func Binary(pos src.XPos, op ir.Op, typ *types.Type, x, y ir.Node) *ir.BinaryExpr {
    89  	switch op {
    90  	case ir.OADD:
    91  		n := ir.NewBinaryExpr(pos, op, x, y)
    92  		typed(typ, n)
    93  		return n
    94  	default:
    95  		n := ir.NewBinaryExpr(pos, op, x, y)
    96  		typed(x.Type(), n)
    97  		return n
    98  	}
    99  }
   100  
   101  func Compare(pos src.XPos, typ *types.Type, op ir.Op, x, y ir.Node) *ir.BinaryExpr {
   102  	n := ir.NewBinaryExpr(pos, op, x, y)
   103  	typed(typ, n)
   104  	return n
   105  }
   106  
   107  func Deref(pos src.XPos, typ *types.Type, x ir.Node) *ir.StarExpr {
   108  	n := ir.NewStarExpr(pos, x)
   109  	typed(typ, n)
   110  	return n
   111  }
   112  
   113  func DotField(pos src.XPos, x ir.Node, index int) *ir.SelectorExpr {
   114  	op, typ := ir.ODOT, x.Type()
   115  	if typ.IsPtr() {
   116  		op, typ = ir.ODOTPTR, typ.Elem()
   117  	}
   118  	if !typ.IsStruct() {
   119  		base.FatalfAt(pos, "DotField of non-struct: %L", x)
   120  	}
   121  
   122  	// TODO(mdempsky): This is the backend's responsibility.
   123  	types.CalcSize(typ)
   124  
   125  	field := typ.Field(index)
   126  	return dot(pos, field.Type, op, x, field)
   127  }
   128  
   129  func DotMethod(pos src.XPos, x ir.Node, index int) *ir.SelectorExpr {
   130  	method := method(x.Type(), index)
   131  
   132  	// Method value.
   133  	typ := typecheck.NewMethodType(method.Type, nil)
   134  	return dot(pos, typ, ir.OMETHVALUE, x, method)
   135  }
   136  
   137  // MethodExpr returns a OMETHEXPR node with the indicated index into the methods
   138  // of typ. The receiver type is set from recv, which is different from typ if the
   139  // method was accessed via embedded fields. Similarly, the X value of the
   140  // ir.SelectorExpr is recv, the original OTYPE node before passing through the
   141  // embedded fields.
   142  func MethodExpr(pos src.XPos, recv ir.Node, embed *types.Type, index int) *ir.SelectorExpr {
   143  	method := method(embed, index)
   144  	typ := typecheck.NewMethodType(method.Type, recv.Type())
   145  	// The method expression T.m requires a wrapper when T
   146  	// is different from m's declared receiver type. We
   147  	// normally generate these wrappers while writing out
   148  	// runtime type descriptors, which is always done for
   149  	// types declared at package scope. However, we need
   150  	// to make sure to generate wrappers for anonymous
   151  	// receiver types too.
   152  	if recv.Sym() == nil {
   153  		typecheck.NeedRuntimeType(recv.Type())
   154  	}
   155  	return dot(pos, typ, ir.OMETHEXPR, recv, method)
   156  }
   157  
   158  func dot(pos src.XPos, typ *types.Type, op ir.Op, x ir.Node, selection *types.Field) *ir.SelectorExpr {
   159  	n := ir.NewSelectorExpr(pos, op, x, selection.Sym)
   160  	n.Selection = selection
   161  	typed(typ, n)
   162  	return n
   163  }
   164  
   165  // TODO(mdempsky): Move to package types.
   166  func method(typ *types.Type, index int) *types.Field {
   167  	if typ.IsInterface() {
   168  		return typ.AllMethods().Index(index)
   169  	}
   170  	return types.ReceiverBaseType(typ).Methods().Index(index)
   171  }
   172  
   173  func Index(pos src.XPos, typ *types.Type, x, index ir.Node) *ir.IndexExpr {
   174  	n := ir.NewIndexExpr(pos, x, index)
   175  	typed(typ, n)
   176  	return n
   177  }
   178  
   179  func Slice(pos src.XPos, typ *types.Type, x, low, high, max ir.Node) *ir.SliceExpr {
   180  	op := ir.OSLICE
   181  	if max != nil {
   182  		op = ir.OSLICE3
   183  	}
   184  	n := ir.NewSliceExpr(pos, op, x, low, high, max)
   185  	typed(typ, n)
   186  	return n
   187  }
   188  
   189  func Unary(pos src.XPos, typ *types.Type, op ir.Op, x ir.Node) ir.Node {
   190  	switch op {
   191  	case ir.OADDR:
   192  		return Addr(pos, x)
   193  	case ir.ODEREF:
   194  		return Deref(pos, typ, x)
   195  	}
   196  
   197  	if op == ir.ORECV {
   198  		if typ.IsFuncArgStruct() && typ.NumFields() == 2 {
   199  			// Remove the second boolean type (if provided by type2),
   200  			// since that works better with the rest of the compiler
   201  			// (which will add it back in later).
   202  			assert(typ.Field(1).Type.Kind() == types.TBOOL)
   203  			typ = typ.Field(0).Type
   204  		}
   205  	}
   206  	return typed(typ, ir.NewUnaryExpr(pos, op, x))
   207  }
   208  
   209  // Statements
   210  
   211  var one = constant.MakeInt64(1)
   212  
   213  func IncDec(pos src.XPos, op ir.Op, x ir.Node) *ir.AssignOpStmt {
   214  	assert(x.Type() != nil)
   215  	bl := ir.NewBasicLit(pos, one)
   216  	if x.Type().HasTParam() {
   217  		// If the operand is generic, then types2 will have proved it must be
   218  		// a type that fits with increment/decrement, so just set the type of
   219  		// "one" to n.Type(). This works even for types that are eventually
   220  		// float or complex.
   221  		typed(x.Type(), bl)
   222  	} else {
   223  		bl = typecheck.DefaultLit(bl, x.Type())
   224  	}
   225  	return ir.NewAssignOpStmt(pos, op, x, bl)
   226  }
   227  

View as plain text