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 }