aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/typecheck/expr.go
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2020-12-23 00:43:42 -0500
committerRuss Cox <rsc@golang.org>2020-12-23 06:38:34 +0000
commit0256ba99a893f2faf870105fc93fff94e5caf241 (patch)
treec5bf15e6d6d6d68db1f3f7b01cb4d5fd696216e0 /src/cmd/compile/internal/typecheck/expr.go
parentb9693d7627089204e6c2448f543c3512d86dae70 (diff)
downloadgo-0256ba99a893f2faf870105fc93fff94e5caf241.tar.gz
go-0256ba99a893f2faf870105fc93fff94e5caf241.zip
[dev.regabi] cmd/compile: split up typecheck1 [generated]
typecheck1 is the largest non-machine-generated function in the compiler. weighing in at 1,747 lines. Since we are destroying the git blame history anyway, now is a good time to split each different case into its own function, making future work on this function more manageable. [git-generate] cd src/cmd/compile/internal/typecheck rf ' # Remove tracing print from typecheck1 - the one in typecheck is fine. # Removing it lets us remove the named result. # That lets all the cut-out functions not have named results. rm typecheck.go:/^func typecheck1/+0,/^func typecheck1/+4 sub typecheck.go:/^func typecheck1/+/\(res ir\.Node\)/ ir.Node mv typecheckselect tcSelect mv typecheckswitch tcSwitch mv typecheckrange tcRange mv typecheckfunc tcFunc mv checkdefergo tcGoDefer mv typecheckclosure tcClosure mv check typecheck mv typecheckcomplit tcCompLit mv typecheckas tcAssign mv typecheckas2 tcAssignList mv typecheckpartialcall tcCallPart mv typecheckExprSwitch tcSwitchExpr mv typecheckTypeSwitch tcSwitchType mv typecheck1:/^\tcase ir.ORETURN:/+2,/^\tcase /-2 tcReturn add typecheck.go:/^func tcReturn/-0 \ // tcReturn typechecks an ORETURN node. mv typecheck1:/^\tcase ir.OIF:/+2,/^\tcase /-2 tcIf add typecheck.go:/^func tcIf/-0 \ // tcIf typechecks an OIF node. mv typecheck1:/^\tcase ir.OFOR,/+2,/^\tcase /-2 tcFor add typecheck.go:/^func tcFor/-0 \ // tcFor typechecks an OFOR node. mv typecheck1:/^\tcase ir.OSPTR:/+2,/^\tcase /-2 tcSPtr add typecheck.go:/^func tcSPtr/-0 \ // tcSPtr typechecks an OSPTR node. mv typecheck1:/^\tcase ir.OITAB:/+2,/^\tcase /-2 tcITab add typecheck.go:/^func tcITab/-0 \ // tcITab typechecks an OITAB node. mv typecheck1:/^\tcase ir.ORECOVER:/+2,/^\tcase /-2 tcRecover add typecheck.go:/^func tcRecover/-0 \ // tcRecover typechecks an ORECOVER node. mv typecheck1:/^\tcase ir.OPANIC:/+2,/^\tcase /-2 tcPanic add typecheck.go:/^func tcPanic/-0 \ // tcPanic typechecks an OPANIC node. mv typecheck1:/^\tcase ir.OPRINT,/+2,/^\tcase /-2 tcPrint add typecheck.go:/^func tcPrint/-0 \ // tcPrint typechecks an OPRINT or OPRINTN node. mv typecheck1:/^\tcase ir.ONEW:/+2,/^\tcase /-2 tcNew add typecheck.go:/^func tcNew/-0 \ // tcNew typechecks an ONEW node. mv typecheck1:/^\tcase ir.OMAKE:/+2,/^\tcase /-2 tcMake add typecheck.go:/^func tcMake/-0 \ // tcMake typechecks an OMAKE node. mv typecheck1:/^\tcase ir.OCONV:/+2,/^\tcase /-2 tcConv add typecheck.go:/^func tcConv/-0 \ // tcConv typechecks an OCONV node. mv typecheck1:/^\tcase ir.OCOPY:/+2,/^\tcase /-2 tcCopy add typecheck.go:/^func tcCopy/-0 \ // tcCopy typechecks an OCOPY node. mv typecheck1:/^\tcase ir.OAPPEND:/+2,/^\tcase /-2 tcAppend add typecheck.go:/^func tcAppend/-0 \ // tcAppend typechecks an OAPPEND node. mv typecheck1:/^\tcase ir.ODELETE:/+2,/^\tcase /-2 tcDelete add typecheck.go:/^func tcDelete/-0 \ // tcDelete typechecks an ODELETE node. mv typecheck1:/^\tcase ir.OCLOSE:/+2,/^\tcase /-2 tcClose add typecheck.go:/^func tcClose/-0 \ // tcClose typechecks an OCLOSE node. mv typecheck1:/^\tcase ir.OCOMPLEX:/+2,/^\tcase /-2 tcComplex add typecheck.go:/^func tcComplex/-0 \ // tcComplex typechecks an OCOMPLEX node. mv typecheck1:/^\tcase ir.OREAL,/+2,/^\tcase /-2 tcRealImag add typecheck.go:/^func tcRealImag/-0 \ // tcRealImag typechecks an OREAL or OIMAG node. mv typecheck1:/^\tcase ir.OCAP,/+2,/^\tcase /-2 tcLenCap add typecheck.go:/^func tcLenCap/-0 \ // tcLenCap typechecks an OLEN or OCAP node. mv typecheck1:/^\tcase ir.OCALL:/+2,/^\tcase /-2 tcCall add typecheck.go:/^func tcCall/-0 \ // tcCall typechecks an OCALL node. mv typecheck1:/^\tcase ir.OSLICE,/+2,/^\tcase /-3 tcSlice add typecheck.go:/^func tcSlice/-0 \ // tcSlice typechecks an OSLICE or OSLICE3 node. # move type assertion above comment mv typecheck1:/^\tcase ir.OMAKESLICECOPY:/+/n := n/-+ typecheck1:/^\tcase ir.OMAKESLICECOPY:/+0 mv typecheck1:/^\tcase ir.OMAKESLICECOPY:/+2,/^\tcase /-2 tcMakeSliceCopy add typecheck.go:/^func tcMakeSliceCopy/-0 \ // tcMakeSliceCopy typechecks an OMAKESLICECOPY node. # move type assertion above comment mv typecheck1:/^\tcase ir.OSLICEHEADER:/+/n := n/-+ typecheck1:/^\tcase ir.OSLICEHEADER:/+0 mv typecheck1:/^\tcase ir.OSLICEHEADER:/+2,/^\tcase /-2 tcSliceHeader add typecheck.go:/^func tcSliceHeader/-0 \ // tcSliceHeader typechecks an OSLICEHEADER node. mv typecheck1:/^\tcase ir.OSEND:/+2,/^\tcase /-2 tcSend add typecheck.go:/^func tcSend/-0 \ // tcSend typechecks an OSEND node. mv typecheck1:/^\tcase ir.ORECV:/+2,/^\tcase /-2 tcRecv add typecheck.go:/^func tcRecv/-0 \ // tcRecv typechecks an ORECV node. mv typecheck1:/^\tcase ir.OINDEX:/+2,/^\tcase /-2 tcIndex add typecheck.go:/^func tcIndex/-0 \ // tcIndex typechecks an OINDEX node. mv typecheck1:/^\tcase ir.ODOTTYPE:/+2,/^\tcase /-2 tcDotType add typecheck.go:/^func tcDotType/-0 \ // tcDotType typechecks an ODOTTYPE node. mv typecheck1:/^\tcase ir.OXDOT,/+2,/^\tcase /-2 tcDot add typecheck.go:/^func tcDot/-0 \ // tcDot typechecks an OXDOT or ODOT node. mv typecheck1:/^\tcase ir.OADDR:/+2,/^\tcase /-2 tcAddr add typecheck.go:/^func tcAddr/-0 \ // tcAddr typechecks an OADDR node. mv typecheck1:/^\tcase ir.OBITNOT,/+2,/^\tcase /-3 tcUnaryArith add typecheck.go:/^func tcUnaryArith/-0 \ // tcUnaryArith typechecks a unary arithmetic expression. mv typecheck1:/^\t\tir.OXOR:/+1,/^\tcase /-2 tcArith add typecheck.go:/^func tcArith/-0 \ // tcArith typechecks a binary arithmetic expression. mv typecheck1:/^\tcase ir.ODEREF:/+2,/^\tcase /-2 tcStar add typecheck.go:/^func tcStar/-0 \ // tcStar typechecks an ODEREF node, which may be an expression or a type. mv typecheck1:/^\tcase ir.OTFUNC:/+2,/^\tcase /-2 tcFuncType add typecheck.go:/^func tcFuncType/-0 \ // tcFuncType typechecks an OTFUNC node. mv typecheck1:/^\tcase ir.OTINTER:/+2,/^\tcase /-2 tcInterfaceType add typecheck.go:/^func tcInterfaceType/-0 \ // tcInterfaceType typechecks an OTINTER node. mv typecheck1:/^\tcase ir.OTSTRUCT:/+2,/^\tcase /-2 tcStructType add typecheck.go:/^func tcStructType/-0 \ // tcStructType typechecks an OTSTRUCT node. mv typecheck1:/^\tcase ir.OTCHAN:/+2,/^\tcase /-2 tcChanType add typecheck.go:/^func tcChanType/-0 \ // tcChanType typechecks an OTCHAN node. mv typecheck1:/^\tcase ir.OTMAP:/+2,/^\tcase /-2 tcMapType add typecheck.go:/^func tcMapType/-0 \ // tcMapType typechecks an OTMAP node. mv typecheck1:/^\tcase ir.OTARRAY:/+2,/^\tcase /-2 tcArrayType add typecheck.go:/^func tcArrayType/-0 \ // tcArrayType typechecks an OTARRAY node. mv typecheck1:/^\tcase ir.OTSLICE:/+2,/^\tcase /-2 tcSliceType add typecheck.go:/^func tcSliceType/-0 \ // tcSliceType typechecks an OTSLICE node. mv \ tcAssign \ tcAssignList \ tcFor \ tcGoDefer \ tcIf \ tcRange \ tcReturn \ tcSelect \ tcSend \ tcSwitch \ tcSwitchExpr \ tcSwitchType \ typeSet \ typeSetEntry \ typeSet.add \ stmt1.go mv stmt1.go stmt.go mv \ tcAddr \ tcArith \ tcArrayType \ tcChanType \ tcClosure \ tcCompLit \ tcConv \ tcDot \ tcDotType \ tcFuncType \ tcITab \ tcIndex \ tcInterfaceType \ tcLenCap \ tcMapType \ tcRecv \ tcSPtr \ tcSlice \ tcSliceHeader \ tcSliceType \ tcStar \ tcStructType \ tcUnaryArith \ expr.go mv \ tcClosure \ tcCallPart \ tcFunc \ tcCall \ tcAppend \ tcClose \ tcComplex \ tcCopy \ tcDelete \ tcMake \ tcMakeSliceCopy \ tcNew \ tcPanic \ tcPrint \ tcRealImag \ tcRecover \ func1.go mv func1.go func.go mv \ tcArrayType \ tcChanType \ tcFuncType \ tcInterfaceType \ tcMapType \ tcSliceType \ tcStructType \ type.go ' Change-Id: I0fb0a3039005bc1783575291daff1e6c306895ff Reviewed-on: https://go-review.googlesource.com/c/go/+/279429 Trust: Russ Cox <rsc@golang.org> Run-TryBot: Russ Cox <rsc@golang.org> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Matthew Dempsky <mdempsky@google.com>
Diffstat (limited to 'src/cmd/compile/internal/typecheck/expr.go')
-rw-r--r--src/cmd/compile/internal/typecheck/expr.go1001
1 files changed, 1001 insertions, 0 deletions
diff --git a/src/cmd/compile/internal/typecheck/expr.go b/src/cmd/compile/internal/typecheck/expr.go
new file mode 100644
index 0000000000..f940a2e73d
--- /dev/null
+++ b/src/cmd/compile/internal/typecheck/expr.go
@@ -0,0 +1,1001 @@
+// Copyright 2009 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 typecheck
+
+import (
+ "fmt"
+ "go/constant"
+ "go/token"
+ "strings"
+
+ "cmd/compile/internal/base"
+ "cmd/compile/internal/ir"
+ "cmd/compile/internal/types"
+)
+
+// tcAddr typechecks an OADDR node.
+func tcAddr(n *ir.AddrExpr) ir.Node {
+ n.X = Expr(n.X)
+ if n.X.Type() == nil {
+ n.SetType(nil)
+ return n
+ }
+
+ switch n.X.Op() {
+ case ir.OARRAYLIT, ir.OMAPLIT, ir.OSLICELIT, ir.OSTRUCTLIT:
+ n.SetOp(ir.OPTRLIT)
+
+ default:
+ checklvalue(n.X, "take the address of")
+ r := ir.OuterValue(n.X)
+ if r.Op() == ir.ONAME {
+ r := r.(*ir.Name)
+ if ir.Orig(r) != r {
+ base.Fatalf("found non-orig name node %v", r) // TODO(mdempsky): What does this mean?
+ }
+ r.Name().SetAddrtaken(true)
+ if r.Name().IsClosureVar() && !CaptureVarsComplete {
+ // Mark the original variable as Addrtaken so that capturevars
+ // knows not to pass it by value.
+ // But if the capturevars phase is complete, don't touch it,
+ // in case l.Name's containing function has not yet been compiled.
+ r.Name().Defn.Name().SetAddrtaken(true)
+ }
+ }
+ n.X = DefaultLit(n.X, nil)
+ if n.X.Type() == nil {
+ n.SetType(nil)
+ return n
+ }
+ }
+
+ n.SetType(types.NewPtr(n.X.Type()))
+ return n
+}
+
+// tcArith typechecks a binary arithmetic expression.
+func tcArith(n ir.Node) ir.Node {
+ var l, r ir.Node
+ var setLR func()
+ switch n := n.(type) {
+ case *ir.AssignOpStmt:
+ l, r = n.X, n.Y
+ setLR = func() { n.X = l; n.Y = r }
+ case *ir.BinaryExpr:
+ l, r = n.X, n.Y
+ setLR = func() { n.X = l; n.Y = r }
+ case *ir.LogicalExpr:
+ l, r = n.X, n.Y
+ setLR = func() { n.X = l; n.Y = r }
+ }
+ l = Expr(l)
+ r = Expr(r)
+ setLR()
+ if l.Type() == nil || r.Type() == nil {
+ n.SetType(nil)
+ return n
+ }
+ op := n.Op()
+ if n.Op() == ir.OASOP {
+ n := n.(*ir.AssignOpStmt)
+ checkassign(n, l)
+ if n.IncDec && !okforarith[l.Type().Kind()] {
+ base.Errorf("invalid operation: %v (non-numeric type %v)", n, l.Type())
+ n.SetType(nil)
+ return n
+ }
+ // TODO(marvin): Fix Node.EType type union.
+ op = n.AsOp
+ }
+ if op == ir.OLSH || op == ir.ORSH {
+ r = DefaultLit(r, types.Types[types.TUINT])
+ setLR()
+ t := r.Type()
+ if !t.IsInteger() {
+ base.Errorf("invalid operation: %v (shift count type %v, must be integer)", n, r.Type())
+ n.SetType(nil)
+ return n
+ }
+ if t.IsSigned() && !types.AllowsGoVersion(curpkg(), 1, 13) {
+ base.ErrorfVers("go1.13", "invalid operation: %v (signed shift count type %v)", n, r.Type())
+ n.SetType(nil)
+ return n
+ }
+ t = l.Type()
+ if t != nil && t.Kind() != types.TIDEAL && !t.IsInteger() {
+ base.Errorf("invalid operation: %v (shift of type %v)", n, t)
+ n.SetType(nil)
+ return n
+ }
+
+ // no defaultlit for left
+ // the outer context gives the type
+ n.SetType(l.Type())
+ if (l.Type() == types.UntypedFloat || l.Type() == types.UntypedComplex) && r.Op() == ir.OLITERAL {
+ n.SetType(types.UntypedInt)
+ }
+ return n
+ }
+
+ // For "x == x && len(s)", it's better to report that "len(s)" (type int)
+ // can't be used with "&&" than to report that "x == x" (type untyped bool)
+ // can't be converted to int (see issue #41500).
+ if n.Op() == ir.OANDAND || n.Op() == ir.OOROR {
+ n := n.(*ir.LogicalExpr)
+ if !n.X.Type().IsBoolean() {
+ base.Errorf("invalid operation: %v (operator %v not defined on %s)", n, n.Op(), typekind(n.X.Type()))
+ n.SetType(nil)
+ return n
+ }
+ if !n.Y.Type().IsBoolean() {
+ base.Errorf("invalid operation: %v (operator %v not defined on %s)", n, n.Op(), typekind(n.Y.Type()))
+ n.SetType(nil)
+ return n
+ }
+ }
+
+ // ideal mixed with non-ideal
+ l, r = defaultlit2(l, r, false)
+ setLR()
+
+ if l.Type() == nil || r.Type() == nil {
+ n.SetType(nil)
+ return n
+ }
+ t := l.Type()
+ if t.Kind() == types.TIDEAL {
+ t = r.Type()
+ }
+ et := t.Kind()
+ if et == types.TIDEAL {
+ et = types.TINT
+ }
+ aop := ir.OXXX
+ if iscmp[n.Op()] && t.Kind() != types.TIDEAL && !types.Identical(l.Type(), r.Type()) {
+ // comparison is okay as long as one side is
+ // assignable to the other. convert so they have
+ // the same type.
+ //
+ // the only conversion that isn't a no-op is concrete == interface.
+ // in that case, check comparability of the concrete type.
+ // The conversion allocates, so only do it if the concrete type is huge.
+ converted := false
+ if r.Type().Kind() != types.TBLANK {
+ aop, _ = assignop(l.Type(), r.Type())
+ if aop != ir.OXXX {
+ if r.Type().IsInterface() && !l.Type().IsInterface() && !types.IsComparable(l.Type()) {
+ base.Errorf("invalid operation: %v (operator %v not defined on %s)", n, op, typekind(l.Type()))
+ n.SetType(nil)
+ return n
+ }
+
+ types.CalcSize(l.Type())
+ if r.Type().IsInterface() == l.Type().IsInterface() || l.Type().Width >= 1<<16 {
+ l = ir.NewConvExpr(base.Pos, aop, r.Type(), l)
+ l.SetTypecheck(1)
+ setLR()
+ }
+
+ t = r.Type()
+ converted = true
+ }
+ }
+
+ if !converted && l.Type().Kind() != types.TBLANK {
+ aop, _ = assignop(r.Type(), l.Type())
+ if aop != ir.OXXX {
+ if l.Type().IsInterface() && !r.Type().IsInterface() && !types.IsComparable(r.Type()) {
+ base.Errorf("invalid operation: %v (operator %v not defined on %s)", n, op, typekind(r.Type()))
+ n.SetType(nil)
+ return n
+ }
+
+ types.CalcSize(r.Type())
+ if r.Type().IsInterface() == l.Type().IsInterface() || r.Type().Width >= 1<<16 {
+ r = ir.NewConvExpr(base.Pos, aop, l.Type(), r)
+ r.SetTypecheck(1)
+ setLR()
+ }
+
+ t = l.Type()
+ }
+ }
+
+ et = t.Kind()
+ }
+
+ if t.Kind() != types.TIDEAL && !types.Identical(l.Type(), r.Type()) {
+ l, r = defaultlit2(l, r, true)
+ if l.Type() == nil || r.Type() == nil {
+ n.SetType(nil)
+ return n
+ }
+ if l.Type().IsInterface() == r.Type().IsInterface() || aop == 0 {
+ base.Errorf("invalid operation: %v (mismatched types %v and %v)", n, l.Type(), r.Type())
+ n.SetType(nil)
+ return n
+ }
+ }
+
+ if t.Kind() == types.TIDEAL {
+ t = mixUntyped(l.Type(), r.Type())
+ }
+ if dt := defaultType(t); !okfor[op][dt.Kind()] {
+ base.Errorf("invalid operation: %v (operator %v not defined on %s)", n, op, typekind(t))
+ n.SetType(nil)
+ return n
+ }
+
+ // okfor allows any array == array, map == map, func == func.
+ // restrict to slice/map/func == nil and nil == slice/map/func.
+ if l.Type().IsArray() && !types.IsComparable(l.Type()) {
+ base.Errorf("invalid operation: %v (%v cannot be compared)", n, l.Type())
+ n.SetType(nil)
+ return n
+ }
+
+ if l.Type().IsSlice() && !ir.IsNil(l) && !ir.IsNil(r) {
+ base.Errorf("invalid operation: %v (slice can only be compared to nil)", n)
+ n.SetType(nil)
+ return n
+ }
+
+ if l.Type().IsMap() && !ir.IsNil(l) && !ir.IsNil(r) {
+ base.Errorf("invalid operation: %v (map can only be compared to nil)", n)
+ n.SetType(nil)
+ return n
+ }
+
+ if l.Type().Kind() == types.TFUNC && !ir.IsNil(l) && !ir.IsNil(r) {
+ base.Errorf("invalid operation: %v (func can only be compared to nil)", n)
+ n.SetType(nil)
+ return n
+ }
+
+ if l.Type().IsStruct() {
+ if f := types.IncomparableField(l.Type()); f != nil {
+ base.Errorf("invalid operation: %v (struct containing %v cannot be compared)", n, f.Type)
+ n.SetType(nil)
+ return n
+ }
+ }
+
+ if iscmp[n.Op()] {
+ t = types.UntypedBool
+ n.SetType(t)
+ if con := EvalConst(n); con.Op() == ir.OLITERAL {
+ return con
+ }
+ l, r = defaultlit2(l, r, true)
+ setLR()
+ return n
+ }
+
+ if et == types.TSTRING && n.Op() == ir.OADD {
+ // create or update OADDSTR node with list of strings in x + y + z + (w + v) + ...
+ n := n.(*ir.BinaryExpr)
+ var add *ir.AddStringExpr
+ if l.Op() == ir.OADDSTR {
+ add = l.(*ir.AddStringExpr)
+ add.SetPos(n.Pos())
+ } else {
+ add = ir.NewAddStringExpr(n.Pos(), []ir.Node{l})
+ }
+ if r.Op() == ir.OADDSTR {
+ r := r.(*ir.AddStringExpr)
+ add.List.Append(r.List.Take()...)
+ } else {
+ add.List.Append(r)
+ }
+ add.SetType(t)
+ return add
+ }
+
+ if (op == ir.ODIV || op == ir.OMOD) && ir.IsConst(r, constant.Int) {
+ if constant.Sign(r.Val()) == 0 {
+ base.Errorf("division by zero")
+ n.SetType(nil)
+ return n
+ }
+ }
+
+ n.SetType(t)
+ return n
+}
+
+// The result of tcCompLit MUST be assigned back to n, e.g.
+// n.Left = tcCompLit(n.Left)
+func tcCompLit(n *ir.CompLitExpr) (res ir.Node) {
+ if base.EnableTrace && base.Flag.LowerT {
+ defer tracePrint("typecheckcomplit", n)(&res)
+ }
+
+ lno := base.Pos
+ defer func() {
+ base.Pos = lno
+ }()
+
+ if n.Ntype == nil {
+ base.ErrorfAt(n.Pos(), "missing type in composite literal")
+ n.SetType(nil)
+ return n
+ }
+
+ // Save original node (including n.Right)
+ n.SetOrig(ir.Copy(n))
+
+ ir.SetPos(n.Ntype)
+
+ // Need to handle [...]T arrays specially.
+ if array, ok := n.Ntype.(*ir.ArrayType); ok && array.Elem != nil && array.Len == nil {
+ array.Elem = typecheck(array.Elem, ctxType)
+ elemType := array.Elem.Type()
+ if elemType == nil {
+ n.SetType(nil)
+ return n
+ }
+ length := typecheckarraylit(elemType, -1, n.List, "array literal")
+ n.SetOp(ir.OARRAYLIT)
+ n.SetType(types.NewArray(elemType, length))
+ n.Ntype = nil
+ return n
+ }
+
+ n.Ntype = ir.Node(typecheck(n.Ntype, ctxType)).(ir.Ntype)
+ t := n.Ntype.Type()
+ if t == nil {
+ n.SetType(nil)
+ return n
+ }
+ n.SetType(t)
+
+ switch t.Kind() {
+ default:
+ base.Errorf("invalid composite literal type %v", t)
+ n.SetType(nil)
+
+ case types.TARRAY:
+ typecheckarraylit(t.Elem(), t.NumElem(), n.List, "array literal")
+ n.SetOp(ir.OARRAYLIT)
+ n.Ntype = nil
+
+ case types.TSLICE:
+ length := typecheckarraylit(t.Elem(), -1, n.List, "slice literal")
+ n.SetOp(ir.OSLICELIT)
+ n.Ntype = nil
+ n.Len = length
+
+ case types.TMAP:
+ var cs constSet
+ for i3, l := range n.List {
+ ir.SetPos(l)
+ if l.Op() != ir.OKEY {
+ n.List[i3] = Expr(l)
+ base.Errorf("missing key in map literal")
+ continue
+ }
+ l := l.(*ir.KeyExpr)
+
+ r := l.Key
+ r = pushtype(r, t.Key())
+ r = Expr(r)
+ l.Key = AssignConv(r, t.Key(), "map key")
+ cs.add(base.Pos, l.Key, "key", "map literal")
+
+ r = l.Value
+ r = pushtype(r, t.Elem())
+ r = Expr(r)
+ l.Value = AssignConv(r, t.Elem(), "map value")
+ }
+
+ n.SetOp(ir.OMAPLIT)
+ n.Ntype = nil
+
+ case types.TSTRUCT:
+ // Need valid field offsets for Xoffset below.
+ types.CalcSize(t)
+
+ errored := false
+ if len(n.List) != 0 && nokeys(n.List) {
+ // simple list of variables
+ ls := n.List
+ for i, n1 := range ls {
+ ir.SetPos(n1)
+ n1 = Expr(n1)
+ ls[i] = n1
+ if i >= t.NumFields() {
+ if !errored {
+ base.Errorf("too many values in %v", n)
+ errored = true
+ }
+ continue
+ }
+
+ f := t.Field(i)
+ s := f.Sym
+ if s != nil && !types.IsExported(s.Name) && s.Pkg != types.LocalPkg {
+ base.Errorf("implicit assignment of unexported field '%s' in %v literal", s.Name, t)
+ }
+ // No pushtype allowed here. Must name fields for that.
+ n1 = AssignConv(n1, f.Type, "field value")
+ sk := ir.NewStructKeyExpr(base.Pos, f.Sym, n1)
+ sk.Offset = f.Offset
+ ls[i] = sk
+ }
+ if len(ls) < t.NumFields() {
+ base.Errorf("too few values in %v", n)
+ }
+ } else {
+ hash := make(map[string]bool)
+
+ // keyed list
+ ls := n.List
+ for i, l := range ls {
+ ir.SetPos(l)
+
+ if l.Op() == ir.OKEY {
+ kv := l.(*ir.KeyExpr)
+ key := kv.Key
+
+ // Sym might have resolved to name in other top-level
+ // package, because of import dot. Redirect to correct sym
+ // before we do the lookup.
+ s := key.Sym()
+ if id, ok := key.(*ir.Ident); ok && DotImportRefs[id] != nil {
+ s = Lookup(s.Name)
+ }
+
+ // An OXDOT uses the Sym field to hold
+ // the field to the right of the dot,
+ // so s will be non-nil, but an OXDOT
+ // is never a valid struct literal key.
+ if s == nil || s.Pkg != types.LocalPkg || key.Op() == ir.OXDOT || s.IsBlank() {
+ base.Errorf("invalid field name %v in struct initializer", key)
+ continue
+ }
+
+ l = ir.NewStructKeyExpr(l.Pos(), s, kv.Value)
+ ls[i] = l
+ }
+
+ if l.Op() != ir.OSTRUCTKEY {
+ if !errored {
+ base.Errorf("mixture of field:value and value initializers")
+ errored = true
+ }
+ ls[i] = Expr(ls[i])
+ continue
+ }
+ l := l.(*ir.StructKeyExpr)
+
+ f := lookdot1(nil, l.Field, t, t.Fields(), 0)
+ if f == nil {
+ if ci := lookdot1(nil, l.Field, t, t.Fields(), 2); ci != nil { // Case-insensitive lookup.
+ if visible(ci.Sym) {
+ base.Errorf("unknown field '%v' in struct literal of type %v (but does have %v)", l.Field, t, ci.Sym)
+ } else if nonexported(l.Field) && l.Field.Name == ci.Sym.Name { // Ensure exactness before the suggestion.
+ base.Errorf("cannot refer to unexported field '%v' in struct literal of type %v", l.Field, t)
+ } else {
+ base.Errorf("unknown field '%v' in struct literal of type %v", l.Field, t)
+ }
+ continue
+ }
+ var f *types.Field
+ p, _ := dotpath(l.Field, t, &f, true)
+ if p == nil || f.IsMethod() {
+ base.Errorf("unknown field '%v' in struct literal of type %v", l.Field, t)
+ continue
+ }
+ // dotpath returns the parent embedded types in reverse order.
+ var ep []string
+ for ei := len(p) - 1; ei >= 0; ei-- {
+ ep = append(ep, p[ei].field.Sym.Name)
+ }
+ ep = append(ep, l.Field.Name)
+ base.Errorf("cannot use promoted field %v in struct literal of type %v", strings.Join(ep, "."), t)
+ continue
+ }
+ fielddup(f.Sym.Name, hash)
+ l.Offset = f.Offset
+
+ // No pushtype allowed here. Tried and rejected.
+ l.Value = Expr(l.Value)
+ l.Value = AssignConv(l.Value, f.Type, "field value")
+ }
+ }
+
+ n.SetOp(ir.OSTRUCTLIT)
+ n.Ntype = nil
+ }
+
+ return n
+}
+
+// tcConv typechecks an OCONV node.
+func tcConv(n *ir.ConvExpr) ir.Node {
+ types.CheckSize(n.Type()) // ensure width is calculated for backend
+ n.X = Expr(n.X)
+ n.X = convlit1(n.X, n.Type(), true, nil)
+ t := n.X.Type()
+ if t == nil || n.Type() == nil {
+ n.SetType(nil)
+ return n
+ }
+ op, why := convertop(n.X.Op() == ir.OLITERAL, t, n.Type())
+ if op == ir.OXXX {
+ if !n.Diag() && !n.Type().Broke() && !n.X.Diag() {
+ base.Errorf("cannot convert %L to type %v%s", n.X, n.Type(), why)
+ n.SetDiag(true)
+ }
+ n.SetOp(ir.OCONV)
+ n.SetType(nil)
+ return n
+ }
+
+ n.SetOp(op)
+ switch n.Op() {
+ case ir.OCONVNOP:
+ if t.Kind() == n.Type().Kind() {
+ switch t.Kind() {
+ case types.TFLOAT32, types.TFLOAT64, types.TCOMPLEX64, types.TCOMPLEX128:
+ // Floating point casts imply rounding and
+ // so the conversion must be kept.
+ n.SetOp(ir.OCONV)
+ }
+ }
+
+ // do not convert to []byte literal. See CL 125796.
+ // generated code and compiler memory footprint is better without it.
+ case ir.OSTR2BYTES:
+ // ok
+
+ case ir.OSTR2RUNES:
+ if n.X.Op() == ir.OLITERAL {
+ return stringtoruneslit(n)
+ }
+ }
+ return n
+}
+
+// tcDot typechecks an OXDOT or ODOT node.
+func tcDot(n *ir.SelectorExpr, top int) ir.Node {
+ if n.Op() == ir.OXDOT {
+ n = AddImplicitDots(n)
+ n.SetOp(ir.ODOT)
+ if n.X == nil {
+ n.SetType(nil)
+ return n
+ }
+ }
+
+ n.X = typecheck(n.X, ctxExpr|ctxType)
+
+ n.X = DefaultLit(n.X, nil)
+
+ t := n.X.Type()
+ if t == nil {
+ base.UpdateErrorDot(ir.Line(n), fmt.Sprint(n.X), fmt.Sprint(n))
+ n.SetType(nil)
+ return n
+ }
+
+ s := n.Sel
+
+ if n.X.Op() == ir.OTYPE {
+ return typecheckMethodExpr(n)
+ }
+
+ if t.IsPtr() && !t.Elem().IsInterface() {
+ t = t.Elem()
+ if t == nil {
+ n.SetType(nil)
+ return n
+ }
+ n.SetOp(ir.ODOTPTR)
+ types.CheckSize(t)
+ }
+
+ if n.Sel.IsBlank() {
+ base.Errorf("cannot refer to blank field or method")
+ n.SetType(nil)
+ return n
+ }
+
+ if lookdot(n, t, 0) == nil {
+ // Legitimate field or method lookup failed, try to explain the error
+ switch {
+ case t.IsEmptyInterface():
+ base.Errorf("%v undefined (type %v is interface with no methods)", n, n.X.Type())
+
+ case t.IsPtr() && t.Elem().IsInterface():
+ // Pointer to interface is almost always a mistake.
+ base.Errorf("%v undefined (type %v is pointer to interface, not interface)", n, n.X.Type())
+
+ case lookdot(n, t, 1) != nil:
+ // Field or method matches by name, but it is not exported.
+ base.Errorf("%v undefined (cannot refer to unexported field or method %v)", n, n.Sel)
+
+ default:
+ if mt := lookdot(n, t, 2); mt != nil && visible(mt.Sym) { // Case-insensitive lookup.
+ base.Errorf("%v undefined (type %v has no field or method %v, but does have %v)", n, n.X.Type(), n.Sel, mt.Sym)
+ } else {
+ base.Errorf("%v undefined (type %v has no field or method %v)", n, n.X.Type(), n.Sel)
+ }
+ }
+ n.SetType(nil)
+ return n
+ }
+
+ if (n.Op() == ir.ODOTINTER || n.Op() == ir.ODOTMETH) && top&ctxCallee == 0 {
+ return tcCallPart(n, s)
+ }
+ return n
+}
+
+// tcDotType typechecks an ODOTTYPE node.
+func tcDotType(n *ir.TypeAssertExpr) ir.Node {
+ n.X = Expr(n.X)
+ n.X = DefaultLit(n.X, nil)
+ l := n.X
+ t := l.Type()
+ if t == nil {
+ n.SetType(nil)
+ return n
+ }
+ if !t.IsInterface() {
+ base.Errorf("invalid type assertion: %v (non-interface type %v on left)", n, t)
+ n.SetType(nil)
+ return n
+ }
+
+ if n.Ntype != nil {
+ n.Ntype = typecheck(n.Ntype, ctxType)
+ n.SetType(n.Ntype.Type())
+ n.Ntype = nil
+ if n.Type() == nil {
+ return n
+ }
+ }
+
+ if n.Type() != nil && !n.Type().IsInterface() {
+ var missing, have *types.Field
+ var ptr int
+ if !implements(n.Type(), t, &missing, &have, &ptr) {
+ if have != nil && have.Sym == missing.Sym {
+ base.Errorf("impossible type assertion:\n\t%v does not implement %v (wrong type for %v method)\n"+
+ "\t\thave %v%S\n\t\twant %v%S", n.Type(), t, missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type)
+ } else if ptr != 0 {
+ base.Errorf("impossible type assertion:\n\t%v does not implement %v (%v method has pointer receiver)", n.Type(), t, missing.Sym)
+ } else if have != nil {
+ base.Errorf("impossible type assertion:\n\t%v does not implement %v (missing %v method)\n"+
+ "\t\thave %v%S\n\t\twant %v%S", n.Type(), t, missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type)
+ } else {
+ base.Errorf("impossible type assertion:\n\t%v does not implement %v (missing %v method)", n.Type(), t, missing.Sym)
+ }
+ n.SetType(nil)
+ return n
+ }
+ }
+ return n
+}
+
+// tcITab typechecks an OITAB node.
+func tcITab(n *ir.UnaryExpr) ir.Node {
+ n.X = Expr(n.X)
+ t := n.X.Type()
+ if t == nil {
+ n.SetType(nil)
+ return n
+ }
+ if !t.IsInterface() {
+ base.Fatalf("OITAB of %v", t)
+ }
+ n.SetType(types.NewPtr(types.Types[types.TUINTPTR]))
+ return n
+}
+
+// tcIndex typechecks an OINDEX node.
+func tcIndex(n *ir.IndexExpr) ir.Node {
+ n.X = Expr(n.X)
+ n.X = DefaultLit(n.X, nil)
+ n.X = implicitstar(n.X)
+ l := n.X
+ n.Index = Expr(n.Index)
+ r := n.Index
+ t := l.Type()
+ if t == nil || r.Type() == nil {
+ n.SetType(nil)
+ return n
+ }
+ switch t.Kind() {
+ default:
+ base.Errorf("invalid operation: %v (type %v does not support indexing)", n, t)
+ n.SetType(nil)
+ return n
+
+ case types.TSTRING, types.TARRAY, types.TSLICE:
+ n.Index = indexlit(n.Index)
+ if t.IsString() {
+ n.SetType(types.ByteType)
+ } else {
+ n.SetType(t.Elem())
+ }
+ why := "string"
+ if t.IsArray() {
+ why = "array"
+ } else if t.IsSlice() {
+ why = "slice"
+ }
+
+ if n.Index.Type() != nil && !n.Index.Type().IsInteger() {
+ base.Errorf("non-integer %s index %v", why, n.Index)
+ return n
+ }
+
+ if !n.Bounded() && ir.IsConst(n.Index, constant.Int) {
+ x := n.Index.Val()
+ if constant.Sign(x) < 0 {
+ base.Errorf("invalid %s index %v (index must be non-negative)", why, n.Index)
+ } else if t.IsArray() && constant.Compare(x, token.GEQ, constant.MakeInt64(t.NumElem())) {
+ base.Errorf("invalid array index %v (out of bounds for %d-element array)", n.Index, t.NumElem())
+ } else if ir.IsConst(n.X, constant.String) && constant.Compare(x, token.GEQ, constant.MakeInt64(int64(len(ir.StringVal(n.X))))) {
+ base.Errorf("invalid string index %v (out of bounds for %d-byte string)", n.Index, len(ir.StringVal(n.X)))
+ } else if ir.ConstOverflow(x, types.Types[types.TINT]) {
+ base.Errorf("invalid %s index %v (index too large)", why, n.Index)
+ }
+ }
+
+ case types.TMAP:
+ n.Index = AssignConv(n.Index, t.Key(), "map index")
+ n.SetType(t.Elem())
+ n.SetOp(ir.OINDEXMAP)
+ n.Assigned = false
+ }
+ return n
+}
+
+// tcLenCap typechecks an OLEN or OCAP node.
+func tcLenCap(n *ir.UnaryExpr) ir.Node {
+ n.X = Expr(n.X)
+ n.X = DefaultLit(n.X, nil)
+ n.X = implicitstar(n.X)
+ l := n.X
+ t := l.Type()
+ if t == nil {
+ n.SetType(nil)
+ return n
+ }
+
+ var ok bool
+ if n.Op() == ir.OLEN {
+ ok = okforlen[t.Kind()]
+ } else {
+ ok = okforcap[t.Kind()]
+ }
+ if !ok {
+ base.Errorf("invalid argument %L for %v", l, n.Op())
+ n.SetType(nil)
+ return n
+ }
+
+ n.SetType(types.Types[types.TINT])
+ return n
+}
+
+// tcRecv typechecks an ORECV node.
+func tcRecv(n *ir.UnaryExpr) ir.Node {
+ n.X = Expr(n.X)
+ n.X = DefaultLit(n.X, nil)
+ l := n.X
+ t := l.Type()
+ if t == nil {
+ n.SetType(nil)
+ return n
+ }
+ if !t.IsChan() {
+ base.Errorf("invalid operation: %v (receive from non-chan type %v)", n, t)
+ n.SetType(nil)
+ return n
+ }
+
+ if !t.ChanDir().CanRecv() {
+ base.Errorf("invalid operation: %v (receive from send-only type %v)", n, t)
+ n.SetType(nil)
+ return n
+ }
+
+ n.SetType(t.Elem())
+ return n
+}
+
+// tcSPtr typechecks an OSPTR node.
+func tcSPtr(n *ir.UnaryExpr) ir.Node {
+ n.X = Expr(n.X)
+ t := n.X.Type()
+ if t == nil {
+ n.SetType(nil)
+ return n
+ }
+ if !t.IsSlice() && !t.IsString() {
+ base.Fatalf("OSPTR of %v", t)
+ }
+ if t.IsString() {
+ n.SetType(types.NewPtr(types.Types[types.TUINT8]))
+ } else {
+ n.SetType(types.NewPtr(t.Elem()))
+ }
+ return n
+}
+
+// tcSlice typechecks an OSLICE or OSLICE3 node.
+func tcSlice(n *ir.SliceExpr) ir.Node {
+ n.X = Expr(n.X)
+ low, high, max := n.SliceBounds()
+ hasmax := n.Op().IsSlice3()
+ low = Expr(low)
+ high = Expr(high)
+ max = Expr(max)
+ n.X = DefaultLit(n.X, nil)
+ low = indexlit(low)
+ high = indexlit(high)
+ max = indexlit(max)
+ n.SetSliceBounds(low, high, max)
+ l := n.X
+ if l.Type() == nil {
+ n.SetType(nil)
+ return n
+ }
+ if l.Type().IsArray() {
+ if !ir.IsAssignable(n.X) {
+ base.Errorf("invalid operation %v (slice of unaddressable value)", n)
+ n.SetType(nil)
+ return n
+ }
+
+ addr := NodAddr(n.X)
+ addr.SetImplicit(true)
+ n.X = Expr(addr)
+ l = n.X
+ }
+ t := l.Type()
+ var tp *types.Type
+ if t.IsString() {
+ if hasmax {
+ base.Errorf("invalid operation %v (3-index slice of string)", n)
+ n.SetType(nil)
+ return n
+ }
+ n.SetType(t)
+ n.SetOp(ir.OSLICESTR)
+ } else if t.IsPtr() && t.Elem().IsArray() {
+ tp = t.Elem()
+ n.SetType(types.NewSlice(tp.Elem()))
+ types.CalcSize(n.Type())
+ if hasmax {
+ n.SetOp(ir.OSLICE3ARR)
+ } else {
+ n.SetOp(ir.OSLICEARR)
+ }
+ } else if t.IsSlice() {
+ n.SetType(t)
+ } else {
+ base.Errorf("cannot slice %v (type %v)", l, t)
+ n.SetType(nil)
+ return n
+ }
+
+ if low != nil && !checksliceindex(l, low, tp) {
+ n.SetType(nil)
+ return n
+ }
+ if high != nil && !checksliceindex(l, high, tp) {
+ n.SetType(nil)
+ return n
+ }
+ if max != nil && !checksliceindex(l, max, tp) {
+ n.SetType(nil)
+ return n
+ }
+ if !checksliceconst(low, high) || !checksliceconst(low, max) || !checksliceconst(high, max) {
+ n.SetType(nil)
+ return n
+ }
+ return n
+}
+
+// tcSliceHeader typechecks an OSLICEHEADER node.
+func tcSliceHeader(n *ir.SliceHeaderExpr) ir.Node {
+ // Errors here are Fatalf instead of Errorf because only the compiler
+ // can construct an OSLICEHEADER node.
+ // Components used in OSLICEHEADER that are supplied by parsed source code
+ // have already been typechecked in e.g. OMAKESLICE earlier.
+ t := n.Type()
+ if t == nil {
+ base.Fatalf("no type specified for OSLICEHEADER")
+ }
+
+ if !t.IsSlice() {
+ base.Fatalf("invalid type %v for OSLICEHEADER", n.Type())
+ }
+
+ if n.Ptr == nil || n.Ptr.Type() == nil || !n.Ptr.Type().IsUnsafePtr() {
+ base.Fatalf("need unsafe.Pointer for OSLICEHEADER")
+ }
+
+ if x := len(n.LenCap); x != 2 {
+ base.Fatalf("expected 2 params (len, cap) for OSLICEHEADER, got %d", x)
+ }
+
+ n.Ptr = Expr(n.Ptr)
+ l := Expr(n.LenCap[0])
+ c := Expr(n.LenCap[1])
+ l = DefaultLit(l, types.Types[types.TINT])
+ c = DefaultLit(c, types.Types[types.TINT])
+
+ if ir.IsConst(l, constant.Int) && ir.Int64Val(l) < 0 {
+ base.Fatalf("len for OSLICEHEADER must be non-negative")
+ }
+
+ if ir.IsConst(c, constant.Int) && ir.Int64Val(c) < 0 {
+ base.Fatalf("cap for OSLICEHEADER must be non-negative")
+ }
+
+ if ir.IsConst(l, constant.Int) && ir.IsConst(c, constant.Int) && constant.Compare(l.Val(), token.GTR, c.Val()) {
+ base.Fatalf("len larger than cap for OSLICEHEADER")
+ }
+
+ n.LenCap[0] = l
+ n.LenCap[1] = c
+ return n
+}
+
+// tcStar typechecks an ODEREF node, which may be an expression or a type.
+func tcStar(n *ir.StarExpr, top int) ir.Node {
+ n.X = typecheck(n.X, ctxExpr|ctxType)
+ l := n.X
+ t := l.Type()
+ if t == nil {
+ n.SetType(nil)
+ return n
+ }
+ if l.Op() == ir.OTYPE {
+ n.SetOTYPE(types.NewPtr(l.Type()))
+ // Ensure l.Type gets dowidth'd for the backend. Issue 20174.
+ types.CheckSize(l.Type())
+ return n
+ }
+
+ if !t.IsPtr() {
+ if top&(ctxExpr|ctxStmt) != 0 {
+ base.Errorf("invalid indirect of %L", n.X)
+ n.SetType(nil)
+ return n
+ }
+ base.Errorf("%v is not a type", l)
+ return n
+ }
+
+ n.SetType(t.Elem())
+ return n
+}
+
+// tcUnaryArith typechecks a unary arithmetic expression.
+func tcUnaryArith(n *ir.UnaryExpr) ir.Node {
+ n.X = Expr(n.X)
+ l := n.X
+ t := l.Type()
+ if t == nil {
+ n.SetType(nil)
+ return n
+ }
+ if !okfor[n.Op()][defaultType(t).Kind()] {
+ base.Errorf("invalid operation: %v (operator %v not defined on %s)", n, n.Op(), typekind(t))
+ n.SetType(nil)
+ return n
+ }
+
+ n.SetType(t)
+ return n
+}