github.com/bir3/gocompiler@v0.3.205/src/cmd/compile/internal/noder/helpers.go (about)

     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  	"github.com/bir3/gocompiler/src/go/constant"
     9  
    10  	"github.com/bir3/gocompiler/src/cmd/compile/internal/base"
    11  	"github.com/bir3/gocompiler/src/cmd/compile/internal/ir"
    12  	"github.com/bir3/gocompiler/src/cmd/compile/internal/syntax"
    13  	"github.com/bir3/gocompiler/src/cmd/compile/internal/typecheck"
    14  	"github.com/bir3/gocompiler/src/cmd/compile/internal/types"
    15  	"github.com/bir3/gocompiler/src/cmd/compile/internal/types2"
    16  	"github.com/bir3/gocompiler/src/cmd/internal/src"
    17  )
    18  
    19  // Helpers for constructing typed IR nodes.
    20  //
    21  // TODO(mdempsky): Move into their own package so they can be easily
    22  // reused by iimport and frontend optimizations.
    23  
    24  type ImplicitNode interface {
    25  	ir.Node
    26  	SetImplicit(x bool)
    27  }
    28  
    29  // Implicit returns n after marking it as Implicit.
    30  func Implicit(n ImplicitNode) ImplicitNode {
    31  	n.SetImplicit(true)
    32  	return n
    33  }
    34  
    35  // typed returns n after setting its type to typ.
    36  func typed(typ *types.Type, n ir.Node) ir.Node {
    37  	n.SetType(typ)
    38  	n.SetTypecheck(1)
    39  	return n
    40  }
    41  
    42  // Values
    43  
    44  func OrigConst(pos src.XPos, typ *types.Type, val constant.Value, op ir.Op, raw string) ir.Node {
    45  	orig := ir.NewRawOrigExpr(pos, op, raw)
    46  	return ir.NewConstExpr(val, typed(typ, orig))
    47  }
    48  
    49  // FixValue returns val after converting and truncating it as
    50  // appropriate for typ.
    51  func FixValue(typ *types.Type, val constant.Value) constant.Value {
    52  	assert(typ.Kind() != types.TFORW)
    53  	switch {
    54  	case typ.IsInteger():
    55  		val = constant.ToInt(val)
    56  	case typ.IsFloat():
    57  		val = constant.ToFloat(val)
    58  	case typ.IsComplex():
    59  		val = constant.ToComplex(val)
    60  	}
    61  	if !typ.IsUntyped() {
    62  		val = typecheck.DefaultLit(ir.NewBasicLit(src.NoXPos, val), typ).Val()
    63  	}
    64  	if !typ.IsTypeParam() {
    65  		ir.AssertValidTypeForConst(typ, val)
    66  	}
    67  	return val
    68  }
    69  
    70  func Nil(pos src.XPos, typ *types.Type) ir.Node {
    71  	return typed(typ, ir.NewNilExpr(pos))
    72  }
    73  
    74  // Expressions
    75  
    76  func Addr(pos src.XPos, x ir.Node) *ir.AddrExpr {
    77  	n := typecheck.NodAddrAt(pos, x)
    78  	typed(types.NewPtr(x.Type()), n)
    79  	return n
    80  }
    81  
    82  func Assert(pos src.XPos, x ir.Node, typ *types.Type) ir.Node {
    83  	return typed(typ, ir.NewTypeAssertExpr(pos, x, nil))
    84  }
    85  
    86  func Binary(pos src.XPos, op ir.Op, typ *types.Type, x, y ir.Node) *ir.BinaryExpr {
    87  	switch op {
    88  	case ir.OADD:
    89  		n := ir.NewBinaryExpr(pos, op, x, y)
    90  		typed(typ, n)
    91  		return n
    92  	default:
    93  		n := ir.NewBinaryExpr(pos, op, x, y)
    94  		typed(x.Type(), n)
    95  		return n
    96  	}
    97  }
    98  
    99  func Compare(pos src.XPos, typ *types.Type, op ir.Op, x, y ir.Node) *ir.BinaryExpr {
   100  	n := ir.NewBinaryExpr(pos, op, x, y)
   101  	typed(typ, n)
   102  	return n
   103  }
   104  
   105  func Deref(pos src.XPos, typ *types.Type, x ir.Node) *ir.StarExpr {
   106  	n := ir.NewStarExpr(pos, x)
   107  	typed(typ, n)
   108  	return n
   109  }
   110  
   111  func DotField(pos src.XPos, x ir.Node, index int) *ir.SelectorExpr {
   112  	op, typ := ir.ODOT, x.Type()
   113  	if typ.IsPtr() {
   114  		op, typ = ir.ODOTPTR, typ.Elem()
   115  	}
   116  	if !typ.IsStruct() {
   117  		base.FatalfAt(pos, "DotField of non-struct: %L", x)
   118  	}
   119  
   120  	// TODO(mdempsky): This is the backend's responsibility.
   121  	types.CalcSize(typ)
   122  
   123  	field := typ.Field(index)
   124  	return dot(pos, field.Type, op, x, field)
   125  }
   126  
   127  func DotMethod(pos src.XPos, x ir.Node, index int) *ir.SelectorExpr {
   128  	method := method(x.Type(), index)
   129  
   130  	// Method value.
   131  	typ := typecheck.NewMethodType(method.Type, nil)
   132  	return dot(pos, typ, ir.OMETHVALUE, x, method)
   133  }
   134  
   135  // MethodExpr returns a OMETHEXPR node with the indicated index into the methods
   136  // of typ. The receiver type is set from recv, which is different from typ if the
   137  // method was accessed via embedded fields. Similarly, the X value of the
   138  // ir.SelectorExpr is recv, the original OTYPE node before passing through the
   139  // embedded fields.
   140  func MethodExpr(pos src.XPos, recv ir.Node, embed *types.Type, index int) *ir.SelectorExpr {
   141  	method := method(embed, index)
   142  	typ := typecheck.NewMethodType(method.Type, recv.Type())
   143  	// The method expression T.m requires a wrapper when T
   144  	// is different from m's declared receiver type. We
   145  	// normally generate these wrappers while writing out
   146  	// runtime type descriptors, which is always done for
   147  	// types declared at package scope. However, we need
   148  	// to make sure to generate wrappers for anonymous
   149  	// receiver types too.
   150  	if recv.Sym() == nil {
   151  		typecheck.NeedRuntimeType(recv.Type())
   152  	}
   153  	return dot(pos, typ, ir.OMETHEXPR, recv, method)
   154  }
   155  
   156  func dot(pos src.XPos, typ *types.Type, op ir.Op, x ir.Node, selection *types.Field) *ir.SelectorExpr {
   157  	n := ir.NewSelectorExpr(pos, op, x, selection.Sym)
   158  	n.Selection = selection
   159  	typed(typ, n)
   160  	return n
   161  }
   162  
   163  // TODO(mdempsky): Move to package types.
   164  func method(typ *types.Type, index int) *types.Field {
   165  	if typ.IsInterface() {
   166  		return typ.AllMethods().Index(index)
   167  	}
   168  	return types.ReceiverBaseType(typ).Methods().Index(index)
   169  }
   170  
   171  func Index(pos src.XPos, typ *types.Type, x, index ir.Node) *ir.IndexExpr {
   172  	n := ir.NewIndexExpr(pos, x, index)
   173  	typed(typ, n)
   174  	return n
   175  }
   176  
   177  func Slice(pos src.XPos, typ *types.Type, x, low, high, max ir.Node) *ir.SliceExpr {
   178  	op := ir.OSLICE
   179  	if max != nil {
   180  		op = ir.OSLICE3
   181  	}
   182  	n := ir.NewSliceExpr(pos, op, x, low, high, max)
   183  	typed(typ, n)
   184  	return n
   185  }
   186  
   187  func Unary(pos src.XPos, typ *types.Type, op ir.Op, x ir.Node) ir.Node {
   188  	switch op {
   189  	case ir.OADDR:
   190  		return Addr(pos, x)
   191  	case ir.ODEREF:
   192  		return Deref(pos, typ, x)
   193  	}
   194  
   195  	if op == ir.ORECV {
   196  		if typ.IsFuncArgStruct() && typ.NumFields() == 2 {
   197  			// Remove the second boolean type (if provided by type2),
   198  			// since that works better with the rest of the compiler
   199  			// (which will add it back in later).
   200  			assert(typ.Field(1).Type.Kind() == types.TBOOL)
   201  			typ = typ.Field(0).Type
   202  		}
   203  	}
   204  	return typed(typ, ir.NewUnaryExpr(pos, op, x))
   205  }
   206  
   207  // Statements
   208  
   209  var one = constant.MakeInt64(1)
   210  
   211  func IncDec(pos src.XPos, op ir.Op, x ir.Node) *ir.AssignOpStmt {
   212  	assert(x.Type() != nil)
   213  	bl := ir.NewBasicLit(pos, one)
   214  	if x.Type().HasTParam() {
   215  		// If the operand is generic, then types2 will have proved it must be
   216  		// a type that fits with increment/decrement, so just set the type of
   217  		// "one" to n.Type(). This works even for types that are eventually
   218  		// float or complex.
   219  		typed(x.Type(), bl)
   220  	} else {
   221  		bl = typecheck.DefaultLit(bl, x.Type())
   222  	}
   223  	return ir.NewAssignOpStmt(pos, op, x, bl)
   224  }
   225  
   226  func idealType(tv syntax.TypeAndValue) types2.Type {
   227  	// The gc backend expects all expressions to have a concrete type, and
   228  	// types2 mostly satisfies this expectation already. But there are a few
   229  	// cases where the Go spec doesn't require converting to concrete type,
   230  	// and so types2 leaves them untyped. So we need to fix those up here.
   231  	typ := tv.Type
   232  	if basic, ok := typ.(*types2.Basic); ok && basic.Info()&types2.IsUntyped != 0 {
   233  		switch basic.Kind() {
   234  		case types2.UntypedNil:
   235  			// ok; can appear in type switch case clauses
   236  			// TODO(mdempsky): Handle as part of type switches instead?
   237  		case types2.UntypedInt, types2.UntypedFloat, types2.UntypedComplex:
   238  			// Untyped rhs of non-constant shift, e.g. x << 1.0.
   239  			// If we have a constant value, it must be an int >= 0.
   240  			if tv.Value != nil {
   241  				s := constant.ToInt(tv.Value)
   242  				assert(s.Kind() == constant.Int && constant.Sign(s) >= 0)
   243  			}
   244  			typ = types2.Typ[types2.Uint]
   245  		case types2.UntypedBool:
   246  			typ = types2.Typ[types2.Bool] // expression in "if" or "for" condition
   247  		case types2.UntypedString:
   248  			typ = types2.Typ[types2.String] // argument to "append" or "copy" calls
   249  		default:
   250  			return nil
   251  		}
   252  	}
   253  	return typ
   254  }
   255  
   256  func isTypeParam(t types2.Type) bool {
   257  	_, ok := t.(*types2.TypeParam)
   258  	return ok
   259  }
   260  
   261  // isNotInHeap reports whether typ is or contains an element of type
   262  // runtime/internal/sys.NotInHeap.
   263  func isNotInHeap(typ types2.Type) bool {
   264  	if named, ok := typ.(*types2.Named); ok {
   265  		if obj := named.Obj(); obj.Name() == "nih" && obj.Pkg().Path() == "runtime/internal/sys" {
   266  			return true
   267  		}
   268  		typ = named.Underlying()
   269  	}
   270  
   271  	switch typ := typ.(type) {
   272  	case *types2.Array:
   273  		return isNotInHeap(typ.Elem())
   274  	case *types2.Struct:
   275  		for i := 0; i < typ.NumFields(); i++ {
   276  			if isNotInHeap(typ.Field(i).Type()) {
   277  				return true
   278  			}
   279  		}
   280  		return false
   281  	default:
   282  		return false
   283  	}
   284  }