summaryrefslogtreecommitdiffstats
path: root/src/cmd/compile/internal/noder/helpers.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/compile/internal/noder/helpers.go')
-rw-r--r--src/cmd/compile/internal/noder/helpers.go226
1 files changed, 226 insertions, 0 deletions
diff --git a/src/cmd/compile/internal/noder/helpers.go b/src/cmd/compile/internal/noder/helpers.go
new file mode 100644
index 0000000..33acd60
--- /dev/null
+++ b/src/cmd/compile/internal/noder/helpers.go
@@ -0,0 +1,226 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package noder
+
+import (
+ "go/constant"
+
+ "cmd/compile/internal/base"
+ "cmd/compile/internal/ir"
+ "cmd/compile/internal/typecheck"
+ "cmd/compile/internal/types"
+ "cmd/internal/src"
+)
+
+// Helpers for constructing typed IR nodes.
+//
+// TODO(mdempsky): Move into their own package so they can be easily
+// reused by iimport and frontend optimizations.
+
+type ImplicitNode interface {
+ ir.Node
+ SetImplicit(x bool)
+}
+
+// Implicit returns n after marking it as Implicit.
+func Implicit(n ImplicitNode) ImplicitNode {
+ n.SetImplicit(true)
+ return n
+}
+
+// typed returns n after setting its type to typ.
+func typed(typ *types.Type, n ir.Node) ir.Node {
+ n.SetType(typ)
+ n.SetTypecheck(1)
+ return n
+}
+
+// Values
+
+func Const(pos src.XPos, typ *types.Type, val constant.Value) ir.Node {
+ return typed(typ, ir.NewBasicLit(pos, val))
+}
+
+func OrigConst(pos src.XPos, typ *types.Type, val constant.Value, op ir.Op, raw string) ir.Node {
+ orig := ir.NewRawOrigExpr(pos, op, raw)
+ return ir.NewConstExpr(val, typed(typ, orig))
+}
+
+// FixValue returns val after converting and truncating it as
+// appropriate for typ.
+func FixValue(typ *types.Type, val constant.Value) constant.Value {
+ assert(typ.Kind() != types.TFORW)
+ switch {
+ case typ.IsInteger():
+ val = constant.ToInt(val)
+ case typ.IsFloat():
+ val = constant.ToFloat(val)
+ case typ.IsComplex():
+ val = constant.ToComplex(val)
+ }
+ if !typ.IsUntyped() {
+ val = typecheck.DefaultLit(ir.NewBasicLit(src.NoXPos, val), typ).Val()
+ }
+ if !typ.IsTypeParam() {
+ ir.AssertValidTypeForConst(typ, val)
+ }
+ return val
+}
+
+func Nil(pos src.XPos, typ *types.Type) ir.Node {
+ return typed(typ, ir.NewNilExpr(pos))
+}
+
+// Expressions
+
+func Addr(pos src.XPos, x ir.Node) *ir.AddrExpr {
+ n := typecheck.NodAddrAt(pos, x)
+ typed(types.NewPtr(x.Type()), n)
+ return n
+}
+
+func Assert(pos src.XPos, x ir.Node, typ *types.Type) ir.Node {
+ return typed(typ, ir.NewTypeAssertExpr(pos, x, nil))
+}
+
+func Binary(pos src.XPos, op ir.Op, typ *types.Type, x, y ir.Node) *ir.BinaryExpr {
+ switch op {
+ case ir.OADD:
+ n := ir.NewBinaryExpr(pos, op, x, y)
+ typed(typ, n)
+ return n
+ default:
+ n := ir.NewBinaryExpr(pos, op, x, y)
+ typed(x.Type(), n)
+ return n
+ }
+}
+
+func Compare(pos src.XPos, typ *types.Type, op ir.Op, x, y ir.Node) *ir.BinaryExpr {
+ n := ir.NewBinaryExpr(pos, op, x, y)
+ typed(typ, n)
+ return n
+}
+
+func Deref(pos src.XPos, typ *types.Type, x ir.Node) *ir.StarExpr {
+ n := ir.NewStarExpr(pos, x)
+ typed(typ, n)
+ return n
+}
+
+func DotField(pos src.XPos, x ir.Node, index int) *ir.SelectorExpr {
+ op, typ := ir.ODOT, x.Type()
+ if typ.IsPtr() {
+ op, typ = ir.ODOTPTR, typ.Elem()
+ }
+ if !typ.IsStruct() {
+ base.FatalfAt(pos, "DotField of non-struct: %L", x)
+ }
+
+ // TODO(mdempsky): This is the backend's responsibility.
+ types.CalcSize(typ)
+
+ field := typ.Field(index)
+ return dot(pos, field.Type, op, x, field)
+}
+
+func DotMethod(pos src.XPos, x ir.Node, index int) *ir.SelectorExpr {
+ method := method(x.Type(), index)
+
+ // Method value.
+ typ := typecheck.NewMethodType(method.Type, nil)
+ return dot(pos, typ, ir.OMETHVALUE, x, method)
+}
+
+// MethodExpr returns a OMETHEXPR node with the indicated index into the methods
+// of typ. The receiver type is set from recv, which is different from typ if the
+// method was accessed via embedded fields. Similarly, the X value of the
+// ir.SelectorExpr is recv, the original OTYPE node before passing through the
+// embedded fields.
+func MethodExpr(pos src.XPos, recv ir.Node, embed *types.Type, index int) *ir.SelectorExpr {
+ method := method(embed, index)
+ typ := typecheck.NewMethodType(method.Type, recv.Type())
+ // The method expression T.m requires a wrapper when T
+ // is different from m's declared receiver type. We
+ // normally generate these wrappers while writing out
+ // runtime type descriptors, which is always done for
+ // types declared at package scope. However, we need
+ // to make sure to generate wrappers for anonymous
+ // receiver types too.
+ if recv.Sym() == nil {
+ typecheck.NeedRuntimeType(recv.Type())
+ }
+ return dot(pos, typ, ir.OMETHEXPR, recv, method)
+}
+
+func dot(pos src.XPos, typ *types.Type, op ir.Op, x ir.Node, selection *types.Field) *ir.SelectorExpr {
+ n := ir.NewSelectorExpr(pos, op, x, selection.Sym)
+ n.Selection = selection
+ typed(typ, n)
+ return n
+}
+
+// TODO(mdempsky): Move to package types.
+func method(typ *types.Type, index int) *types.Field {
+ if typ.IsInterface() {
+ return typ.AllMethods().Index(index)
+ }
+ return types.ReceiverBaseType(typ).Methods().Index(index)
+}
+
+func Index(pos src.XPos, typ *types.Type, x, index ir.Node) *ir.IndexExpr {
+ n := ir.NewIndexExpr(pos, x, index)
+ typed(typ, n)
+ return n
+}
+
+func Slice(pos src.XPos, typ *types.Type, x, low, high, max ir.Node) *ir.SliceExpr {
+ op := ir.OSLICE
+ if max != nil {
+ op = ir.OSLICE3
+ }
+ n := ir.NewSliceExpr(pos, op, x, low, high, max)
+ typed(typ, n)
+ return n
+}
+
+func Unary(pos src.XPos, typ *types.Type, op ir.Op, x ir.Node) ir.Node {
+ switch op {
+ case ir.OADDR:
+ return Addr(pos, x)
+ case ir.ODEREF:
+ return Deref(pos, typ, x)
+ }
+
+ if op == ir.ORECV {
+ if typ.IsFuncArgStruct() && typ.NumFields() == 2 {
+ // Remove the second boolean type (if provided by type2),
+ // since that works better with the rest of the compiler
+ // (which will add it back in later).
+ assert(typ.Field(1).Type.Kind() == types.TBOOL)
+ typ = typ.Field(0).Type
+ }
+ }
+ return typed(typ, ir.NewUnaryExpr(pos, op, x))
+}
+
+// Statements
+
+var one = constant.MakeInt64(1)
+
+func IncDec(pos src.XPos, op ir.Op, x ir.Node) *ir.AssignOpStmt {
+ assert(x.Type() != nil)
+ bl := ir.NewBasicLit(pos, one)
+ if x.Type().HasTParam() {
+ // If the operand is generic, then types2 will have proved it must be
+ // a type that fits with increment/decrement, so just set the type of
+ // "one" to n.Type(). This works even for types that are eventually
+ // float or complex.
+ typed(x.Type(), bl)
+ } else {
+ bl = typecheck.DefaultLit(bl, x.Type())
+ }
+ return ir.NewAssignOpStmt(pos, op, x, bl)
+}