aboutsummaryrefslogtreecommitdiff
path: root/src/cmd
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
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')
-rw-r--r--src/cmd/compile/internal/typecheck/expr.go1001
-rw-r--r--src/cmd/compile/internal/typecheck/func.go753
-rw-r--r--src/cmd/compile/internal/typecheck/stmt.go433
-rw-r--r--src/cmd/compile/internal/typecheck/subr.go2
-rw-r--r--src/cmd/compile/internal/typecheck/type.go122
-rw-r--r--src/cmd/compile/internal/typecheck/typecheck.go1984
6 files changed, 2255 insertions, 2040 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
+}
diff --git a/src/cmd/compile/internal/typecheck/func.go b/src/cmd/compile/internal/typecheck/func.go
index 4675de6cad..99d81dcede 100644
--- a/src/cmd/compile/internal/typecheck/func.go
+++ b/src/cmd/compile/internal/typecheck/func.go
@@ -10,6 +10,8 @@ import (
"cmd/compile/internal/types"
"fmt"
+ "go/constant"
+ "go/token"
)
// package all the arguments that match a ... T parameter into a []T.
@@ -156,66 +158,6 @@ func CaptureVars(fn *ir.Func) {
base.Pos = lno
}
-// typecheckclosure typechecks an OCLOSURE node. It also creates the named
-// function associated with the closure.
-// TODO: This creation of the named function should probably really be done in a
-// separate pass from type-checking.
-func typecheckclosure(clo *ir.ClosureExpr, top int) {
- fn := clo.Func
- // Set current associated iota value, so iota can be used inside
- // function in ConstSpec, see issue #22344
- if x := getIotaValue(); x >= 0 {
- fn.Iota = x
- }
-
- fn.ClosureType = check(fn.ClosureType, ctxType)
- clo.SetType(fn.ClosureType.Type())
- fn.SetClosureCalled(top&ctxCallee != 0)
-
- // Do not typecheck fn twice, otherwise, we will end up pushing
- // fn to Target.Decls multiple times, causing initLSym called twice.
- // See #30709
- if fn.Typecheck() == 1 {
- return
- }
-
- for _, ln := range fn.ClosureVars {
- n := ln.Defn
- if !n.Name().Captured() {
- n.Name().SetCaptured(true)
- if n.Name().Decldepth == 0 {
- base.Fatalf("typecheckclosure: var %v does not have decldepth assigned", n)
- }
-
- // Ignore assignments to the variable in straightline code
- // preceding the first capturing by a closure.
- if n.Name().Decldepth == decldepth {
- n.Name().SetAssigned(false)
- }
- }
- }
-
- fn.Nname.SetSym(closurename(ir.CurFunc))
- ir.MarkFunc(fn.Nname)
- Func(fn)
-
- // Type check the body now, but only if we're inside a function.
- // At top level (in a variable initialization: curfn==nil) we're not
- // ready to type check code yet; we'll check it later, because the
- // underlying closure function we create is added to Target.Decls.
- if ir.CurFunc != nil && clo.Type() != nil {
- oldfn := ir.CurFunc
- ir.CurFunc = fn
- olddd := decldepth
- decldepth = 1
- Stmts(fn.Body)
- decldepth = olddd
- ir.CurFunc = oldfn
- }
-
- Target.Decls = append(Target.Decls, fn)
-}
-
// Lazy typechecking of imported bodies. For local functions, caninl will set ->typecheck
// because they're a copy of an already checked body.
func ImportedBody(fn *ir.Func) {
@@ -380,7 +322,67 @@ func makepartialcall(dot *ir.SelectorExpr, t0 *types.Type, meth *types.Sym) *ir.
return fn
}
-func typecheckpartialcall(n ir.Node, sym *types.Sym) *ir.CallPartExpr {
+// tcClosure typechecks an OCLOSURE node. It also creates the named
+// function associated with the closure.
+// TODO: This creation of the named function should probably really be done in a
+// separate pass from type-checking.
+func tcClosure(clo *ir.ClosureExpr, top int) {
+ fn := clo.Func
+ // Set current associated iota value, so iota can be used inside
+ // function in ConstSpec, see issue #22344
+ if x := getIotaValue(); x >= 0 {
+ fn.Iota = x
+ }
+
+ fn.ClosureType = typecheck(fn.ClosureType, ctxType)
+ clo.SetType(fn.ClosureType.Type())
+ fn.SetClosureCalled(top&ctxCallee != 0)
+
+ // Do not typecheck fn twice, otherwise, we will end up pushing
+ // fn to Target.Decls multiple times, causing initLSym called twice.
+ // See #30709
+ if fn.Typecheck() == 1 {
+ return
+ }
+
+ for _, ln := range fn.ClosureVars {
+ n := ln.Defn
+ if !n.Name().Captured() {
+ n.Name().SetCaptured(true)
+ if n.Name().Decldepth == 0 {
+ base.Fatalf("typecheckclosure: var %v does not have decldepth assigned", n)
+ }
+
+ // Ignore assignments to the variable in straightline code
+ // preceding the first capturing by a closure.
+ if n.Name().Decldepth == decldepth {
+ n.Name().SetAssigned(false)
+ }
+ }
+ }
+
+ fn.Nname.SetSym(closurename(ir.CurFunc))
+ ir.MarkFunc(fn.Nname)
+ Func(fn)
+
+ // Type check the body now, but only if we're inside a function.
+ // At top level (in a variable initialization: curfn==nil) we're not
+ // ready to type check code yet; we'll check it later, because the
+ // underlying closure function we create is added to Target.Decls.
+ if ir.CurFunc != nil && clo.Type() != nil {
+ oldfn := ir.CurFunc
+ ir.CurFunc = fn
+ olddd := decldepth
+ decldepth = 1
+ Stmts(fn.Body)
+ decldepth = olddd
+ ir.CurFunc = oldfn
+ }
+
+ Target.Decls = append(Target.Decls, fn)
+}
+
+func tcCallPart(n ir.Node, sym *types.Sym) *ir.CallPartExpr {
switch n.Op() {
case ir.ODOTINTER, ir.ODOTMETH:
break
@@ -396,3 +398,632 @@ func typecheckpartialcall(n ir.Node, sym *types.Sym) *ir.CallPartExpr {
return ir.NewCallPartExpr(dot.Pos(), dot.X, dot.Selection, fn)
}
+
+// type check function definition
+// To be called by typecheck, not directly.
+// (Call typecheckFunc instead.)
+func tcFunc(n *ir.Func) {
+ if base.EnableTrace && base.Flag.LowerT {
+ defer tracePrint("typecheckfunc", n)(nil)
+ }
+
+ for _, ln := range n.Dcl {
+ if ln.Op() == ir.ONAME && (ln.Class_ == ir.PPARAM || ln.Class_ == ir.PPARAMOUT) {
+ ln.Decldepth = 1
+ }
+ }
+
+ n.Nname = AssignExpr(n.Nname).(*ir.Name)
+ t := n.Nname.Type()
+ if t == nil {
+ return
+ }
+ n.SetType(t)
+ rcvr := t.Recv()
+ if rcvr != nil && n.Shortname != nil {
+ m := addmethod(n, n.Shortname, t, true, n.Pragma&ir.Nointerface != 0)
+ if m == nil {
+ return
+ }
+
+ n.Nname.SetSym(ir.MethodSym(rcvr.Type, n.Shortname))
+ Declare(n.Nname, ir.PFUNC)
+ }
+
+ if base.Ctxt.Flag_dynlink && !inimport && n.Nname != nil {
+ NeedFuncSym(n.Sym())
+ }
+}
+
+// tcCall typechecks an OCALL node.
+func tcCall(n *ir.CallExpr, top int) ir.Node {
+ n.Use = ir.CallUseExpr
+ if top == ctxStmt {
+ n.Use = ir.CallUseStmt
+ }
+ Stmts(n.Init()) // imported rewritten f(g()) calls (#30907)
+ n.X = typecheck(n.X, ctxExpr|ctxType|ctxCallee)
+ if n.X.Diag() {
+ n.SetDiag(true)
+ }
+
+ l := n.X
+
+ if l.Op() == ir.ONAME && l.(*ir.Name).BuiltinOp != 0 {
+ l := l.(*ir.Name)
+ if n.IsDDD && l.BuiltinOp != ir.OAPPEND {
+ base.Errorf("invalid use of ... with builtin %v", l)
+ }
+
+ // builtin: OLEN, OCAP, etc.
+ switch l.BuiltinOp {
+ default:
+ base.Fatalf("unknown builtin %v", l)
+
+ case ir.OAPPEND, ir.ODELETE, ir.OMAKE, ir.OPRINT, ir.OPRINTN, ir.ORECOVER:
+ n.SetOp(l.BuiltinOp)
+ n.X = nil
+ n.SetTypecheck(0) // re-typechecking new op is OK, not a loop
+ return typecheck(n, top)
+
+ case ir.OCAP, ir.OCLOSE, ir.OIMAG, ir.OLEN, ir.OPANIC, ir.OREAL:
+ typecheckargs(n)
+ fallthrough
+ case ir.ONEW, ir.OALIGNOF, ir.OOFFSETOF, ir.OSIZEOF:
+ arg, ok := needOneArg(n, "%v", n.Op())
+ if !ok {
+ n.SetType(nil)
+ return n
+ }
+ u := ir.NewUnaryExpr(n.Pos(), l.BuiltinOp, arg)
+ return typecheck(ir.InitExpr(n.Init(), u), top) // typecheckargs can add to old.Init
+
+ case ir.OCOMPLEX, ir.OCOPY:
+ typecheckargs(n)
+ arg1, arg2, ok := needTwoArgs(n)
+ if !ok {
+ n.SetType(nil)
+ return n
+ }
+ b := ir.NewBinaryExpr(n.Pos(), l.BuiltinOp, arg1, arg2)
+ return typecheck(ir.InitExpr(n.Init(), b), top) // typecheckargs can add to old.Init
+ }
+ panic("unreachable")
+ }
+
+ n.X = DefaultLit(n.X, nil)
+ l = n.X
+ if l.Op() == ir.OTYPE {
+ if n.IsDDD {
+ if !l.Type().Broke() {
+ base.Errorf("invalid use of ... in type conversion to %v", l.Type())
+ }
+ n.SetDiag(true)
+ }
+
+ // pick off before type-checking arguments
+ arg, ok := needOneArg(n, "conversion to %v", l.Type())
+ if !ok {
+ n.SetType(nil)
+ return n
+ }
+
+ n := ir.NewConvExpr(n.Pos(), ir.OCONV, nil, arg)
+ n.SetType(l.Type())
+ return typecheck1(n, top)
+ }
+
+ typecheckargs(n)
+ t := l.Type()
+ if t == nil {
+ n.SetType(nil)
+ return n
+ }
+ types.CheckSize(t)
+
+ switch l.Op() {
+ case ir.ODOTINTER:
+ n.SetOp(ir.OCALLINTER)
+
+ case ir.ODOTMETH:
+ l := l.(*ir.SelectorExpr)
+ n.SetOp(ir.OCALLMETH)
+
+ // typecheckaste was used here but there wasn't enough
+ // information further down the call chain to know if we
+ // were testing a method receiver for unexported fields.
+ // It isn't necessary, so just do a sanity check.
+ tp := t.Recv().Type
+
+ if l.X == nil || !types.Identical(l.X.Type(), tp) {
+ base.Fatalf("method receiver")
+ }
+
+ default:
+ n.SetOp(ir.OCALLFUNC)
+ if t.Kind() != types.TFUNC {
+ // TODO(mdempsky): Remove "o.Sym() != nil" once we stop
+ // using ir.Name for numeric literals.
+ if o := ir.Orig(l); o.Name() != nil && o.Sym() != nil && types.BuiltinPkg.Lookup(o.Sym().Name).Def != nil {
+ // be more specific when the non-function
+ // name matches a predeclared function
+ base.Errorf("cannot call non-function %L, declared at %s",
+ l, base.FmtPos(o.Name().Pos()))
+ } else {
+ base.Errorf("cannot call non-function %L", l)
+ }
+ n.SetType(nil)
+ return n
+ }
+ }
+
+ typecheckaste(ir.OCALL, n.X, n.IsDDD, t.Params(), n.Args, func() string { return fmt.Sprintf("argument to %v", n.X) })
+ if t.NumResults() == 0 {
+ return n
+ }
+ if t.NumResults() == 1 {
+ n.SetType(l.Type().Results().Field(0).Type)
+
+ if n.Op() == ir.OCALLFUNC && n.X.Op() == ir.ONAME {
+ if sym := n.X.(*ir.Name).Sym(); types.IsRuntimePkg(sym.Pkg) && sym.Name == "getg" {
+ // Emit code for runtime.getg() directly instead of calling function.
+ // Most such rewrites (for example the similar one for math.Sqrt) should be done in walk,
+ // so that the ordering pass can make sure to preserve the semantics of the original code
+ // (in particular, the exact time of the function call) by introducing temporaries.
+ // In this case, we know getg() always returns the same result within a given function
+ // and we want to avoid the temporaries, so we do the rewrite earlier than is typical.
+ n.SetOp(ir.OGETG)
+ }
+ }
+ return n
+ }
+
+ // multiple return
+ if top&(ctxMultiOK|ctxStmt) == 0 {
+ base.Errorf("multiple-value %v() in single-value context", l)
+ return n
+ }
+
+ n.SetType(l.Type().Results())
+ return n
+}
+
+// tcAppend typechecks an OAPPEND node.
+func tcAppend(n *ir.CallExpr) ir.Node {
+ typecheckargs(n)
+ args := n.Args
+ if len(args) == 0 {
+ base.Errorf("missing arguments to append")
+ n.SetType(nil)
+ return n
+ }
+
+ t := args[0].Type()
+ if t == nil {
+ n.SetType(nil)
+ return n
+ }
+
+ n.SetType(t)
+ if !t.IsSlice() {
+ if ir.IsNil(args[0]) {
+ base.Errorf("first argument to append must be typed slice; have untyped nil")
+ n.SetType(nil)
+ return n
+ }
+
+ base.Errorf("first argument to append must be slice; have %L", t)
+ n.SetType(nil)
+ return n
+ }
+
+ if n.IsDDD {
+ if len(args) == 1 {
+ base.Errorf("cannot use ... on first argument to append")
+ n.SetType(nil)
+ return n
+ }
+
+ if len(args) != 2 {
+ base.Errorf("too many arguments to append")
+ n.SetType(nil)
+ return n
+ }
+
+ if t.Elem().IsKind(types.TUINT8) && args[1].Type().IsString() {
+ args[1] = DefaultLit(args[1], types.Types[types.TSTRING])
+ return n
+ }
+
+ args[1] = AssignConv(args[1], t.Underlying(), "append")
+ return n
+ }
+
+ as := args[1:]
+ for i, n := range as {
+ if n.Type() == nil {
+ continue
+ }
+ as[i] = AssignConv(n, t.Elem(), "append")
+ types.CheckSize(as[i].Type()) // ensure width is calculated for backend
+ }
+ return n
+}
+
+// tcClose typechecks an OCLOSE node.
+func tcClose(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 (non-chan type %v)", n, t)
+ n.SetType(nil)
+ return n
+ }
+
+ if !t.ChanDir().CanSend() {
+ base.Errorf("invalid operation: %v (cannot close receive-only channel)", n)
+ n.SetType(nil)
+ return n
+ }
+ return n
+}
+
+// tcComplex typechecks an OCOMPLEX node.
+func tcComplex(n *ir.BinaryExpr) ir.Node {
+ l := Expr(n.X)
+ r := Expr(n.Y)
+ if l.Type() == nil || r.Type() == nil {
+ n.SetType(nil)
+ return n
+ }
+ l, r = defaultlit2(l, r, false)
+ if l.Type() == nil || r.Type() == nil {
+ n.SetType(nil)
+ return n
+ }
+ n.X = l
+ n.Y = r
+
+ if !types.Identical(l.Type(), r.Type()) {
+ base.Errorf("invalid operation: %v (mismatched types %v and %v)", n, l.Type(), r.Type())
+ n.SetType(nil)
+ return n
+ }
+
+ var t *types.Type
+ switch l.Type().Kind() {
+ default:
+ base.Errorf("invalid operation: %v (arguments have type %v, expected floating-point)", n, l.Type())
+ n.SetType(nil)
+ return n
+
+ case types.TIDEAL:
+ t = types.UntypedComplex
+
+ case types.TFLOAT32:
+ t = types.Types[types.TCOMPLEX64]
+
+ case types.TFLOAT64:
+ t = types.Types[types.TCOMPLEX128]
+ }
+ n.SetType(t)
+ return n
+}
+
+// tcCopy typechecks an OCOPY node.
+func tcCopy(n *ir.BinaryExpr) ir.Node {
+ n.SetType(types.Types[types.TINT])
+ n.X = Expr(n.X)
+ n.X = DefaultLit(n.X, nil)
+ n.Y = Expr(n.Y)
+ n.Y = DefaultLit(n.Y, nil)
+ if n.X.Type() == nil || n.Y.Type() == nil {
+ n.SetType(nil)
+ return n
+ }
+
+ // copy([]byte, string)
+ if n.X.Type().IsSlice() && n.Y.Type().IsString() {
+ if types.Identical(n.X.Type().Elem(), types.ByteType) {
+ return n
+ }
+ base.Errorf("arguments to copy have different element types: %L and string", n.X.Type())
+ n.SetType(nil)
+ return n
+ }
+
+ if !n.X.Type().IsSlice() || !n.Y.Type().IsSlice() {
+ if !n.X.Type().IsSlice() && !n.Y.Type().IsSlice() {
+ base.Errorf("arguments to copy must be slices; have %L, %L", n.X.Type(), n.Y.Type())
+ } else if !n.X.Type().IsSlice() {
+ base.Errorf("first argument to copy should be slice; have %L", n.X.Type())
+ } else {
+ base.Errorf("second argument to copy should be slice or string; have %L", n.Y.Type())
+ }
+ n.SetType(nil)
+ return n
+ }
+
+ if !types.Identical(n.X.Type().Elem(), n.Y.Type().Elem()) {
+ base.Errorf("arguments to copy have different element types: %L and %L", n.X.Type(), n.Y.Type())
+ n.SetType(nil)
+ return n
+ }
+ return n
+}
+
+// tcDelete typechecks an ODELETE node.
+func tcDelete(n *ir.CallExpr) ir.Node {
+ typecheckargs(n)
+ args := n.Args
+ if len(args) == 0 {
+ base.Errorf("missing arguments to delete")
+ n.SetType(nil)
+ return n
+ }
+
+ if len(args) == 1 {
+ base.Errorf("missing second (key) argument to delete")
+ n.SetType(nil)
+ return n
+ }
+
+ if len(args) != 2 {
+ base.Errorf("too many arguments to delete")
+ n.SetType(nil)
+ return n
+ }
+
+ l := args[0]
+ r := args[1]
+ if l.Type() != nil && !l.Type().IsMap() {
+ base.Errorf("first argument to delete must be map; have %L", l.Type())
+ n.SetType(nil)
+ return n
+ }
+
+ args[1] = AssignConv(r, l.Type().Key(), "delete")
+ return n
+}
+
+// tcMake typechecks an OMAKE node.
+func tcMake(n *ir.CallExpr) ir.Node {
+ args := n.Args
+ if len(args) == 0 {
+ base.Errorf("missing argument to make")
+ n.SetType(nil)
+ return n
+ }
+
+ n.Args.Set(nil)
+ l := args[0]
+ l = typecheck(l, ctxType)
+ t := l.Type()
+ if t == nil {
+ n.SetType(nil)
+ return n
+ }
+
+ i := 1
+ var nn ir.Node
+ switch t.Kind() {
+ default:
+ base.Errorf("cannot make type %v", t)
+ n.SetType(nil)
+ return n
+
+ case types.TSLICE:
+ if i >= len(args) {
+ base.Errorf("missing len argument to make(%v)", t)
+ n.SetType(nil)
+ return n
+ }
+
+ l = args[i]
+ i++
+ l = Expr(l)
+ var r ir.Node
+ if i < len(args) {
+ r = args[i]
+ i++
+ r = Expr(r)
+ }
+
+ if l.Type() == nil || (r != nil && r.Type() == nil) {
+ n.SetType(nil)
+ return n
+ }
+ if !checkmake(t, "len", &l) || r != nil && !checkmake(t, "cap", &r) {
+ n.SetType(nil)
+ return n
+ }
+ if ir.IsConst(l, constant.Int) && r != nil && ir.IsConst(r, constant.Int) && constant.Compare(l.Val(), token.GTR, r.Val()) {
+ base.Errorf("len larger than cap in make(%v)", t)
+ n.SetType(nil)
+ return n
+ }
+ nn = ir.NewMakeExpr(n.Pos(), ir.OMAKESLICE, l, r)
+
+ case types.TMAP:
+ if i < len(args) {
+ l = args[i]
+ i++
+ l = Expr(l)
+ l = DefaultLit(l, types.Types[types.TINT])
+ if l.Type() == nil {
+ n.SetType(nil)
+ return n
+ }
+ if !checkmake(t, "size", &l) {
+ n.SetType(nil)
+ return n
+ }
+ } else {
+ l = ir.NewInt(0)
+ }
+ nn = ir.NewMakeExpr(n.Pos(), ir.OMAKEMAP, l, nil)
+ nn.SetEsc(n.Esc())
+
+ case types.TCHAN:
+ l = nil
+ if i < len(args) {
+ l = args[i]
+ i++
+ l = Expr(l)
+ l = DefaultLit(l, types.Types[types.TINT])
+ if l.Type() == nil {
+ n.SetType(nil)
+ return n
+ }
+ if !checkmake(t, "buffer", &l) {
+ n.SetType(nil)
+ return n
+ }
+ } else {
+ l = ir.NewInt(0)
+ }
+ nn = ir.NewMakeExpr(n.Pos(), ir.OMAKECHAN, l, nil)
+ }
+
+ if i < len(args) {
+ base.Errorf("too many arguments to make(%v)", t)
+ n.SetType(nil)
+ return n
+ }
+
+ nn.SetType(t)
+ return nn
+}
+
+// tcMakeSliceCopy typechecks an OMAKESLICECOPY node.
+func tcMakeSliceCopy(n *ir.MakeExpr) ir.Node {
+ // Errors here are Fatalf instead of Errorf because only the compiler
+ // can construct an OMAKESLICECOPY node.
+ // Components used in OMAKESCLICECOPY that are supplied by parsed source code
+ // have already been typechecked in OMAKE and OCOPY earlier.
+ t := n.Type()
+
+ if t == nil {
+ base.Fatalf("no type specified for OMAKESLICECOPY")
+ }
+
+ if !t.IsSlice() {
+ base.Fatalf("invalid type %v for OMAKESLICECOPY", n.Type())
+ }
+
+ if n.Len == nil {
+ base.Fatalf("missing len argument for OMAKESLICECOPY")
+ }
+
+ if n.Cap == nil {
+ base.Fatalf("missing slice argument to copy for OMAKESLICECOPY")
+ }
+
+ n.Len = Expr(n.Len)
+ n.Cap = Expr(n.Cap)
+
+ n.Len = DefaultLit(n.Len, types.Types[types.TINT])
+
+ if !n.Len.Type().IsInteger() && n.Type().Kind() != types.TIDEAL {
+ base.Errorf("non-integer len argument in OMAKESLICECOPY")
+ }
+
+ if ir.IsConst(n.Len, constant.Int) {
+ if ir.ConstOverflow(n.Len.Val(), types.Types[types.TINT]) {
+ base.Fatalf("len for OMAKESLICECOPY too large")
+ }
+ if constant.Sign(n.Len.Val()) < 0 {
+ base.Fatalf("len for OMAKESLICECOPY must be non-negative")
+ }
+ }
+ return n
+}
+
+// tcNew typechecks an ONEW node.
+func tcNew(n *ir.UnaryExpr) ir.Node {
+ if n.X == nil {
+ // Fatalf because the OCALL above checked for us,
+ // so this must be an internally-generated mistake.
+ base.Fatalf("missing argument to new")
+ }
+ l := n.X
+ l = typecheck(l, ctxType)
+ t := l.Type()
+ if t == nil {
+ n.SetType(nil)
+ return n
+ }
+ n.X = l
+ n.SetType(types.NewPtr(t))
+ return n
+}
+
+// tcPanic typechecks an OPANIC node.
+func tcPanic(n *ir.UnaryExpr) ir.Node {
+ n.X = Expr(n.X)
+ n.X = DefaultLit(n.X, types.Types[types.TINTER])
+ if n.X.Type() == nil {
+ n.SetType(nil)
+ return n
+ }
+ return n
+}
+
+// tcPrint typechecks an OPRINT or OPRINTN node.
+func tcPrint(n *ir.CallExpr) ir.Node {
+ typecheckargs(n)
+ ls := n.Args
+ for i1, n1 := range ls {
+ // Special case for print: int constant is int64, not int.
+ if ir.IsConst(n1, constant.Int) {
+ ls[i1] = DefaultLit(ls[i1], types.Types[types.TINT64])
+ } else {
+ ls[i1] = DefaultLit(ls[i1], nil)
+ }
+ }
+ return n
+}
+
+// tcRealImag typechecks an OREAL or OIMAG node.
+func tcRealImag(n *ir.UnaryExpr) ir.Node {
+ n.X = Expr(n.X)
+ l := n.X
+ t := l.Type()
+ if t == nil {
+ n.SetType(nil)
+ return n
+ }
+
+ // Determine result type.
+ switch t.Kind() {
+ case types.TIDEAL:
+ n.SetType(types.UntypedFloat)
+ case types.TCOMPLEX64:
+ n.SetType(types.Types[types.TFLOAT32])
+ case types.TCOMPLEX128:
+ n.SetType(types.Types[types.TFLOAT64])
+ default:
+ base.Errorf("invalid argument %L for %v", l, n.Op())
+ n.SetType(nil)
+ return n
+ }
+ return n
+}
+
+// tcRecover typechecks an ORECOVER node.
+func tcRecover(n *ir.CallExpr) ir.Node {
+ if len(n.Args) != 0 {
+ base.Errorf("too many arguments to recover")
+ n.SetType(nil)
+ return n
+ }
+
+ n.SetType(types.Types[types.TINTER])
+ return n
+}
diff --git a/src/cmd/compile/internal/typecheck/stmt.go b/src/cmd/compile/internal/typecheck/stmt.go
index 889ee06d6e..bf3801eea2 100644
--- a/src/cmd/compile/internal/typecheck/stmt.go
+++ b/src/cmd/compile/internal/typecheck/stmt.go
@@ -11,33 +11,6 @@ import (
"cmd/internal/src"
)
-// range
-func typecheckrange(n *ir.RangeStmt) {
- // Typechecking order is important here:
- // 0. first typecheck range expression (slice/map/chan),
- // it is evaluated only once and so logically it is not part of the loop.
- // 1. typecheck produced values,
- // this part can declare new vars and so it must be typechecked before body,
- // because body can contain a closure that captures the vars.
- // 2. decldepth++ to denote loop body.
- // 3. typecheck body.
- // 4. decldepth--.
- typecheckrangeExpr(n)
-
- // second half of dance, the first half being typecheckrangeExpr
- n.SetTypecheck(1)
- ls := n.Vars
- for i1, n1 := range ls {
- if n1.Typecheck() == 0 {
- ls[i1] = AssignExpr(ls[i1])
- }
- }
-
- decldepth++
- Stmts(n.Body)
- decldepth--
-}
-
func typecheckrangeExpr(n *ir.RangeStmt) {
n.X = Expr(n.X)
@@ -136,8 +109,326 @@ func typecheckrangeExpr(n *ir.RangeStmt) {
}
}
+// type check assignment.
+// if this assignment is the definition of a var on the left side,
+// fill in the var's type.
+func tcAssign(n *ir.AssignStmt) {
+ if base.EnableTrace && base.Flag.LowerT {
+ defer tracePrint("typecheckas", n)(nil)
+ }
+
+ // delicate little dance.
+ // the definition of n may refer to this assignment
+ // as its definition, in which case it will call typecheckas.
+ // in that case, do not call typecheck back, or it will cycle.
+ // if the variable has a type (ntype) then typechecking
+ // will not look at defn, so it is okay (and desirable,
+ // so that the conversion below happens).
+ n.X = Resolve(n.X)
+
+ if !ir.DeclaredBy(n.X, n) || n.X.Name().Ntype != nil {
+ n.X = AssignExpr(n.X)
+ }
+
+ // Use ctxMultiOK so we can emit an "N variables but M values" error
+ // to be consistent with typecheckas2 (#26616).
+ n.Y = typecheck(n.Y, ctxExpr|ctxMultiOK)
+ checkassign(n, n.X)
+ if n.Y != nil && n.Y.Type() != nil {
+ if n.Y.Type().IsFuncArgStruct() {
+ base.Errorf("assignment mismatch: 1 variable but %v returns %d values", n.Y.(*ir.CallExpr).X, n.Y.Type().NumFields())
+ // Multi-value RHS isn't actually valid for OAS; nil out
+ // to indicate failed typechecking.
+ n.Y.SetType(nil)
+ } else if n.X.Type() != nil {
+ n.Y = AssignConv(n.Y, n.X.Type(), "assignment")
+ }
+ }
+
+ if ir.DeclaredBy(n.X, n) && n.X.Name().Ntype == nil {
+ n.Y = DefaultLit(n.Y, nil)
+ n.X.SetType(n.Y.Type())
+ }
+
+ // second half of dance.
+ // now that right is done, typecheck the left
+ // just to get it over with. see dance above.
+ n.SetTypecheck(1)
+
+ if n.X.Typecheck() == 0 {
+ n.X = AssignExpr(n.X)
+ }
+ if !ir.IsBlank(n.X) {
+ types.CheckSize(n.X.Type()) // ensure width is calculated for backend
+ }
+}
+
+func tcAssignList(n *ir.AssignListStmt) {
+ if base.EnableTrace && base.Flag.LowerT {
+ defer tracePrint("typecheckas2", n)(nil)
+ }
+
+ ls := n.Lhs
+ for i1, n1 := range ls {
+ // delicate little dance.
+ n1 = Resolve(n1)
+ ls[i1] = n1
+
+ if !ir.DeclaredBy(n1, n) || n1.Name().Ntype != nil {
+ ls[i1] = AssignExpr(ls[i1])
+ }
+ }
+
+ cl := len(n.Lhs)
+ cr := len(n.Rhs)
+ if cl > 1 && cr == 1 {
+ n.Rhs[0] = typecheck(n.Rhs[0], ctxExpr|ctxMultiOK)
+ } else {
+ Exprs(n.Rhs)
+ }
+ checkassignlist(n, n.Lhs)
+
+ var l ir.Node
+ var r ir.Node
+ if cl == cr {
+ // easy
+ ls := n.Lhs
+ rs := n.Rhs
+ for il, nl := range ls {
+ nr := rs[il]
+ if nl.Type() != nil && nr.Type() != nil {
+ rs[il] = AssignConv(nr, nl.Type(), "assignment")
+ }
+ if ir.DeclaredBy(nl, n) && nl.Name().Ntype == nil {
+ rs[il] = DefaultLit(rs[il], nil)
+ nl.SetType(rs[il].Type())
+ }
+ }
+
+ goto out
+ }
+
+ l = n.Lhs[0]
+ r = n.Rhs[0]
+
+ // x,y,z = f()
+ if cr == 1 {
+ if r.Type() == nil {
+ goto out
+ }
+ switch r.Op() {
+ case ir.OCALLMETH, ir.OCALLINTER, ir.OCALLFUNC:
+ if !r.Type().IsFuncArgStruct() {
+ break
+ }
+ cr = r.Type().NumFields()
+ if cr != cl {
+ goto mismatch
+ }
+ r.(*ir.CallExpr).Use = ir.CallUseList
+ n.SetOp(ir.OAS2FUNC)
+ for i, l := range n.Lhs {
+ f := r.Type().Field(i)
+ if f.Type != nil && l.Type() != nil {
+ checkassignto(f.Type, l)
+ }
+ if ir.DeclaredBy(l, n) && l.Name().Ntype == nil {
+ l.SetType(f.Type)
+ }
+ }
+ goto out
+ }
+ }
+
+ // x, ok = y
+ if cl == 2 && cr == 1 {
+ if r.Type() == nil {
+ goto out
+ }
+ switch r.Op() {
+ case ir.OINDEXMAP, ir.ORECV, ir.ODOTTYPE:
+ switch r.Op() {
+ case ir.OINDEXMAP:
+ n.SetOp(ir.OAS2MAPR)
+ case ir.ORECV:
+ n.SetOp(ir.OAS2RECV)
+ case ir.ODOTTYPE:
+ r := r.(*ir.TypeAssertExpr)
+ n.SetOp(ir.OAS2DOTTYPE)
+ r.SetOp(ir.ODOTTYPE2)
+ }
+ if l.Type() != nil {
+ checkassignto(r.Type(), l)
+ }
+ if ir.DeclaredBy(l, n) {
+ l.SetType(r.Type())
+ }
+ l := n.Lhs[1]
+ if l.Type() != nil && !l.Type().IsBoolean() {
+ checkassignto(types.Types[types.TBOOL], l)
+ }
+ if ir.DeclaredBy(l, n) && l.Name().Ntype == nil {
+ l.SetType(types.Types[types.TBOOL])
+ }
+ goto out
+ }
+ }
+
+mismatch:
+ switch r.Op() {
+ default:
+ base.Errorf("assignment mismatch: %d variables but %d values", cl, cr)
+ case ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER:
+ r := r.(*ir.CallExpr)
+ base.Errorf("assignment mismatch: %d variables but %v returns %d values", cl, r.X, cr)
+ }
+
+ // second half of dance
+out:
+ n.SetTypecheck(1)
+ ls = n.Lhs
+ for i1, n1 := range ls {
+ if n1.Typecheck() == 0 {
+ ls[i1] = AssignExpr(ls[i1])
+ }
+ }
+}
+
+// tcFor typechecks an OFOR node.
+func tcFor(n *ir.ForStmt) ir.Node {
+ Stmts(n.Init())
+ decldepth++
+ n.Cond = Expr(n.Cond)
+ n.Cond = DefaultLit(n.Cond, nil)
+ if n.Cond != nil {
+ t := n.Cond.Type()
+ if t != nil && !t.IsBoolean() {
+ base.Errorf("non-bool %L used as for condition", n.Cond)
+ }
+ }
+ n.Post = Stmt(n.Post)
+ if n.Op() == ir.OFORUNTIL {
+ Stmts(n.Late)
+ }
+ Stmts(n.Body)
+ decldepth--
+ return n
+}
+
+func tcGoDefer(n *ir.GoDeferStmt) {
+ what := "defer"
+ if n.Op() == ir.OGO {
+ what = "go"
+ }
+
+ switch n.Call.Op() {
+ // ok
+ case ir.OCALLINTER,
+ ir.OCALLMETH,
+ ir.OCALLFUNC,
+ ir.OCLOSE,
+ ir.OCOPY,
+ ir.ODELETE,
+ ir.OPANIC,
+ ir.OPRINT,
+ ir.OPRINTN,
+ ir.ORECOVER:
+ return
+
+ case ir.OAPPEND,
+ ir.OCAP,
+ ir.OCOMPLEX,
+ ir.OIMAG,
+ ir.OLEN,
+ ir.OMAKE,
+ ir.OMAKESLICE,
+ ir.OMAKECHAN,
+ ir.OMAKEMAP,
+ ir.ONEW,
+ ir.OREAL,
+ ir.OLITERAL: // conversion or unsafe.Alignof, Offsetof, Sizeof
+ if orig := ir.Orig(n.Call); orig.Op() == ir.OCONV {
+ break
+ }
+ base.ErrorfAt(n.Pos(), "%s discards result of %v", what, n.Call)
+ return
+ }
+
+ // type is broken or missing, most likely a method call on a broken type
+ // we will warn about the broken type elsewhere. no need to emit a potentially confusing error
+ if n.Call.Type() == nil || n.Call.Type().Broke() {
+ return
+ }
+
+ if !n.Diag() {
+ // The syntax made sure it was a call, so this must be
+ // a conversion.
+ n.SetDiag(true)
+ base.ErrorfAt(n.Pos(), "%s requires function call, not conversion", what)
+ }
+}
+
+// tcIf typechecks an OIF node.
+func tcIf(n *ir.IfStmt) ir.Node {
+ Stmts(n.Init())
+ n.Cond = Expr(n.Cond)
+ n.Cond = DefaultLit(n.Cond, nil)
+ if n.Cond != nil {
+ t := n.Cond.Type()
+ if t != nil && !t.IsBoolean() {
+ base.Errorf("non-bool %L used as if condition", n.Cond)
+ }
+ }
+ Stmts(n.Body)
+ Stmts(n.Else)
+ return n
+}
+
+// range
+func tcRange(n *ir.RangeStmt) {
+ // Typechecking order is important here:
+ // 0. first typecheck range expression (slice/map/chan),
+ // it is evaluated only once and so logically it is not part of the loop.
+ // 1. typecheck produced values,
+ // this part can declare new vars and so it must be typechecked before body,
+ // because body can contain a closure that captures the vars.
+ // 2. decldepth++ to denote loop body.
+ // 3. typecheck body.
+ // 4. decldepth--.
+ typecheckrangeExpr(n)
+
+ // second half of dance, the first half being typecheckrangeExpr
+ n.SetTypecheck(1)
+ ls := n.Vars
+ for i1, n1 := range ls {
+ if n1.Typecheck() == 0 {
+ ls[i1] = AssignExpr(ls[i1])
+ }
+ }
+
+ decldepth++
+ Stmts(n.Body)
+ decldepth--
+}
+
+// tcReturn typechecks an ORETURN node.
+func tcReturn(n *ir.ReturnStmt) ir.Node {
+ typecheckargs(n)
+ if ir.CurFunc == nil {
+ base.Errorf("return outside function")
+ n.SetType(nil)
+ return n
+ }
+
+ if ir.HasNamedResults(ir.CurFunc) && len(n.Results) == 0 {
+ return n
+ }
+ typecheckaste(ir.ORETURN, nil, false, ir.CurFunc.Type().Results(), n.Results, func() string { return "return argument" })
+ return n
+}
+
// select
-func typecheckselect(sel *ir.SelectStmt) {
+func tcSelect(sel *ir.SelectStmt) {
var def ir.Node
lno := ir.SetPos(sel)
Stmts(sel.Init())
@@ -219,35 +510,43 @@ func typecheckselect(sel *ir.SelectStmt) {
base.Pos = lno
}
-type typeSet struct {
- m map[string][]typeSetEntry
-}
+// tcSend typechecks an OSEND node.
+func tcSend(n *ir.SendStmt) ir.Node {
+ n.Chan = Expr(n.Chan)
+ n.Value = Expr(n.Value)
+ n.Chan = DefaultLit(n.Chan, nil)
+ t := n.Chan.Type()
+ if t == nil {
+ return n
+ }
+ if !t.IsChan() {
+ base.Errorf("invalid operation: %v (send to non-chan type %v)", n, t)
+ return n
+ }
-func (s *typeSet) add(pos src.XPos, typ *types.Type) {
- if s.m == nil {
- s.m = make(map[string][]typeSetEntry)
+ if !t.ChanDir().CanSend() {
+ base.Errorf("invalid operation: %v (send to receive-only type %v)", n, t)
+ return n
}
- // LongString does not uniquely identify types, so we need to
- // disambiguate collisions with types.Identical.
- // TODO(mdempsky): Add a method that *is* unique.
- ls := typ.LongString()
- prevs := s.m[ls]
- for _, prev := range prevs {
- if types.Identical(typ, prev.typ) {
- base.ErrorfAt(pos, "duplicate case %v in type switch\n\tprevious case at %s", typ, base.FmtPos(prev.pos))
- return
- }
+ n.Value = AssignConv(n.Value, t.Elem(), "send")
+ if n.Value.Type() == nil {
+ return n
}
- s.m[ls] = append(prevs, typeSetEntry{pos, typ})
+ return n
}
-type typeSetEntry struct {
- pos src.XPos
- typ *types.Type
+// tcSwitch typechecks a switch statement.
+func tcSwitch(n *ir.SwitchStmt) {
+ Stmts(n.Init())
+ if n.Tag != nil && n.Tag.Op() == ir.OTYPESW {
+ tcSwitchType(n)
+ } else {
+ tcSwitchExpr(n)
+ }
}
-func typecheckExprSwitch(n *ir.SwitchStmt) {
+func tcSwitchExpr(n *ir.SwitchStmt) {
t := types.Types[types.TBOOL]
if n.Tag != nil {
n.Tag = Expr(n.Tag)
@@ -328,7 +627,7 @@ func typecheckExprSwitch(n *ir.SwitchStmt) {
}
}
-func typecheckTypeSwitch(n *ir.SwitchStmt) {
+func tcSwitchType(n *ir.SwitchStmt) {
guard := n.Tag.(*ir.TypeSwitchGuard)
guard.X = Expr(guard.X)
t := guard.X.Type()
@@ -358,7 +657,7 @@ func typecheckTypeSwitch(n *ir.SwitchStmt) {
}
for i := range ls {
- ls[i] = check(ls[i], ctxExpr|ctxType)
+ ls[i] = typecheck(ls[i], ctxExpr|ctxType)
n1 := ls[i]
if t == nil || n1.Type() == nil {
continue
@@ -424,12 +723,30 @@ func typecheckTypeSwitch(n *ir.SwitchStmt) {
}
}
-// typecheckswitch typechecks a switch statement.
-func typecheckswitch(n *ir.SwitchStmt) {
- Stmts(n.Init())
- if n.Tag != nil && n.Tag.Op() == ir.OTYPESW {
- typecheckTypeSwitch(n)
- } else {
- typecheckExprSwitch(n)
+type typeSet struct {
+ m map[string][]typeSetEntry
+}
+
+type typeSetEntry struct {
+ pos src.XPos
+ typ *types.Type
+}
+
+func (s *typeSet) add(pos src.XPos, typ *types.Type) {
+ if s.m == nil {
+ s.m = make(map[string][]typeSetEntry)
}
+
+ // LongString does not uniquely identify types, so we need to
+ // disambiguate collisions with types.Identical.
+ // TODO(mdempsky): Add a method that *is* unique.
+ ls := typ.LongString()
+ prevs := s.m[ls]
+ for _, prev := range prevs {
+ if types.Identical(typ, prev.typ) {
+ base.ErrorfAt(pos, "duplicate case %v in type switch\n\tprevious case at %s", typ, base.FmtPos(prev.pos))
+ return
+ }
+ }
+ s.m[ls] = append(prevs, typeSetEntry{pos, typ})
}
diff --git a/src/cmd/compile/internal/typecheck/subr.go b/src/cmd/compile/internal/typecheck/subr.go
index 22ebf2a4b3..178eba4484 100644
--- a/src/cmd/compile/internal/typecheck/subr.go
+++ b/src/cmd/compile/internal/typecheck/subr.go
@@ -81,7 +81,7 @@ func NodNil() ir.Node {
// will give shortest unique addressing.
// modify the tree with missing type names.
func AddImplicitDots(n *ir.SelectorExpr) *ir.SelectorExpr {
- n.X = check(n.X, ctxType|ctxExpr)
+ n.X = typecheck(n.X, ctxType|ctxExpr)
if n.X.Diag() {
n.SetDiag(true)
}
diff --git a/src/cmd/compile/internal/typecheck/type.go b/src/cmd/compile/internal/typecheck/type.go
new file mode 100644
index 0000000000..4782bb9c31
--- /dev/null
+++ b/src/cmd/compile/internal/typecheck/type.go
@@ -0,0 +1,122 @@
+// 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 (
+ "go/constant"
+
+ "cmd/compile/internal/base"
+ "cmd/compile/internal/ir"
+ "cmd/compile/internal/types"
+)
+
+// tcArrayType typechecks an OTARRAY node.
+func tcArrayType(n *ir.ArrayType) ir.Node {
+ n.Elem = typecheck(n.Elem, ctxType)
+ if n.Elem.Type() == nil {
+ return n
+ }
+ if n.Len == nil { // [...]T
+ if !n.Diag() {
+ n.SetDiag(true)
+ base.Errorf("use of [...] array outside of array literal")
+ }
+ return n
+ }
+ n.Len = indexlit(Expr(n.Len))
+ size := n.Len
+ if ir.ConstType(size) != constant.Int {
+ switch {
+ case size.Type() == nil:
+ // Error already reported elsewhere.
+ case size.Type().IsInteger() && size.Op() != ir.OLITERAL:
+ base.Errorf("non-constant array bound %v", size)
+ default:
+ base.Errorf("invalid array bound %v", size)
+ }
+ return n
+ }
+
+ v := size.Val()
+ if ir.ConstOverflow(v, types.Types[types.TINT]) {
+ base.Errorf("array bound is too large")
+ return n
+ }
+
+ if constant.Sign(v) < 0 {
+ base.Errorf("array bound must be non-negative")
+ return n
+ }
+
+ bound, _ := constant.Int64Val(v)
+ t := types.NewArray(n.Elem.Type(), bound)
+ n.SetOTYPE(t)
+ types.CheckSize(t)
+ return n
+}
+
+// tcChanType typechecks an OTCHAN node.
+func tcChanType(n *ir.ChanType) ir.Node {
+ n.Elem = typecheck(n.Elem, ctxType)
+ l := n.Elem
+ if l.Type() == nil {
+ return n
+ }
+ if l.Type().NotInHeap() {
+ base.Errorf("chan of incomplete (or unallocatable) type not allowed")
+ }
+ n.SetOTYPE(types.NewChan(l.Type(), n.Dir))
+ return n
+}
+
+// tcFuncType typechecks an OTFUNC node.
+func tcFuncType(n *ir.FuncType) ir.Node {
+ n.SetOTYPE(NewFuncType(n.Recv, n.Params, n.Results))
+ return n
+}
+
+// tcInterfaceType typechecks an OTINTER node.
+func tcInterfaceType(n *ir.InterfaceType) ir.Node {
+ n.SetOTYPE(tointerface(n.Methods))
+ return n
+}
+
+// tcMapType typechecks an OTMAP node.
+func tcMapType(n *ir.MapType) ir.Node {
+ n.Key = typecheck(n.Key, ctxType)
+ n.Elem = typecheck(n.Elem, ctxType)
+ l := n.Key
+ r := n.Elem
+ if l.Type() == nil || r.Type() == nil {
+ return n
+ }
+ if l.Type().NotInHeap() {
+ base.Errorf("incomplete (or unallocatable) map key not allowed")
+ }
+ if r.Type().NotInHeap() {
+ base.Errorf("incomplete (or unallocatable) map value not allowed")
+ }
+ n.SetOTYPE(types.NewMap(l.Type(), r.Type()))
+ mapqueue = append(mapqueue, n) // check map keys when all types are settled
+ return n
+}
+
+// tcSliceType typechecks an OTSLICE node.
+func tcSliceType(n *ir.SliceType) ir.Node {
+ n.Elem = typecheck(n.Elem, ctxType)
+ if n.Elem.Type() == nil {
+ return n
+ }
+ t := types.NewSlice(n.Elem.Type())
+ n.SetOTYPE(t)
+ types.CheckSize(t)
+ return n
+}
+
+// tcStructType typechecks an OTSTRUCT node.
+func tcStructType(n *ir.StructType) ir.Node {
+ n.SetOTYPE(NewStructType(n.Fields))
+ return n
+}
diff --git a/src/cmd/compile/internal/typecheck/typecheck.go b/src/cmd/compile/internal/typecheck/typecheck.go
index 2abf0a7824..bf43402d3d 100644
--- a/src/cmd/compile/internal/typecheck/typecheck.go
+++ b/src/cmd/compile/internal/typecheck/typecheck.go
@@ -122,9 +122,9 @@ func Package() {
}
}
-func AssignExpr(n ir.Node) ir.Node { return check(n, ctxExpr|ctxAssign) }
-func Expr(n ir.Node) ir.Node { return check(n, ctxExpr) }
-func Stmt(n ir.Node) ir.Node { return check(n, ctxStmt) }
+func AssignExpr(n ir.Node) ir.Node { return typecheck(n, ctxExpr|ctxAssign) }
+func Expr(n ir.Node) ir.Node { return typecheck(n, ctxExpr) }
+func Stmt(n ir.Node) ir.Node { return typecheck(n, ctxStmt) }
func Exprs(exprs []ir.Node) { typecheckslice(exprs, ctxExpr) }
func Stmts(stmts []ir.Node) { typecheckslice(stmts, ctxStmt) }
@@ -138,13 +138,13 @@ func Call(call *ir.CallExpr) {
if t.NumResults() > 0 {
ctx = ctxExpr | ctxMultiOK
}
- if check(call, ctx) != call {
+ if typecheck(call, ctx) != call {
panic("bad typecheck")
}
}
func Callee(n ir.Node) ir.Node {
- return check(n, ctxExpr|ctxCallee)
+ return typecheck(n, ctxExpr|ctxCallee)
}
func FuncBody(n *ir.Func) {
@@ -277,7 +277,7 @@ func Resolve(n ir.Node) (res ir.Node) {
func typecheckslice(l []ir.Node, top int) {
for i := range l {
- l[i] = check(l[i], top)
+ l[i] = typecheck(l[i], top)
}
}
@@ -367,13 +367,13 @@ func Func(fn *ir.Func) {
}
func typecheckNtype(n ir.Ntype) ir.Ntype {
- return check(n, ctxType).(ir.Ntype)
+ return typecheck(n, ctxType).(ir.Ntype)
}
-// check type checks node n.
-// The result of check MUST be assigned back to n, e.g.
-// n.Left = check(n.Left, top)
-func check(n ir.Node, top int) (res ir.Node) {
+// typecheck type checks node n.
+// The result of typecheck MUST be assigned back to n, e.g.
+// n.Left = typecheck(n.Left, top)
+func typecheck(n ir.Node, top int) (res ir.Node) {
// cannot type check until all the source has been parsed
if !TypecheckAllowed {
base.Fatalf("early typecheck")
@@ -572,11 +572,7 @@ func indexlit(n ir.Node) ir.Node {
}
// typecheck1 should ONLY be called from typecheck.
-func typecheck1(n ir.Node, top int) (res ir.Node) {
- if base.EnableTrace && base.Flag.LowerT {
- defer tracePrint("typecheck1", n)(&res)
- }
-
+func typecheck1(n ir.Node, top int) ir.Node {
switch n.Op() {
case ir.OLITERAL, ir.ONAME, ir.ONONAME, ir.OTYPE:
if n.Sym() == nil {
@@ -653,136 +649,35 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
case ir.OTSLICE:
n := n.(*ir.SliceType)
- n.Elem = check(n.Elem, ctxType)
- if n.Elem.Type() == nil {
- return n
- }
- t := types.NewSlice(n.Elem.Type())
- n.SetOTYPE(t)
- types.CheckSize(t)
- return n
+ return tcSliceType(n)
case ir.OTARRAY:
n := n.(*ir.ArrayType)
- n.Elem = check(n.Elem, ctxType)
- if n.Elem.Type() == nil {
- return n
- }
- if n.Len == nil { // [...]T
- if !n.Diag() {
- n.SetDiag(true)
- base.Errorf("use of [...] array outside of array literal")
- }
- return n
- }
- n.Len = indexlit(Expr(n.Len))
- size := n.Len
- if ir.ConstType(size) != constant.Int {
- switch {
- case size.Type() == nil:
- // Error already reported elsewhere.
- case size.Type().IsInteger() && size.Op() != ir.OLITERAL:
- base.Errorf("non-constant array bound %v", size)
- default:
- base.Errorf("invalid array bound %v", size)
- }
- return n
- }
-
- v := size.Val()
- if ir.ConstOverflow(v, types.Types[types.TINT]) {
- base.Errorf("array bound is too large")
- return n
- }
-
- if constant.Sign(v) < 0 {
- base.Errorf("array bound must be non-negative")
- return n
- }
-
- bound, _ := constant.Int64Val(v)
- t := types.NewArray(n.Elem.Type(), bound)
- n.SetOTYPE(t)
- types.CheckSize(t)
- return n
+ return tcArrayType(n)
case ir.OTMAP:
n := n.(*ir.MapType)
- n.Key = check(n.Key, ctxType)
- n.Elem = check(n.Elem, ctxType)
- l := n.Key
- r := n.Elem
- if l.Type() == nil || r.Type() == nil {
- return n
- }
- if l.Type().NotInHeap() {
- base.Errorf("incomplete (or unallocatable) map key not allowed")
- }
- if r.Type().NotInHeap() {
- base.Errorf("incomplete (or unallocatable) map value not allowed")
- }
- n.SetOTYPE(types.NewMap(l.Type(), r.Type()))
- mapqueue = append(mapqueue, n) // check map keys when all types are settled
- return n
+ return tcMapType(n)
case ir.OTCHAN:
n := n.(*ir.ChanType)
- n.Elem = check(n.Elem, ctxType)
- l := n.Elem
- if l.Type() == nil {
- return n
- }
- if l.Type().NotInHeap() {
- base.Errorf("chan of incomplete (or unallocatable) type not allowed")
- }
- n.SetOTYPE(types.NewChan(l.Type(), n.Dir))
- return n
+ return tcChanType(n)
case ir.OTSTRUCT:
n := n.(*ir.StructType)
- n.SetOTYPE(NewStructType(n.Fields))
- return n
+ return tcStructType(n)
case ir.OTINTER:
n := n.(*ir.InterfaceType)
- n.SetOTYPE(tointerface(n.Methods))
- return n
+ return tcInterfaceType(n)
case ir.OTFUNC:
n := n.(*ir.FuncType)
- n.SetOTYPE(NewFuncType(n.Recv, n.Params, n.Results))
- return n
-
+ return tcFuncType(n)
// type or expr
case ir.ODEREF:
n := n.(*ir.StarExpr)
- n.X = check(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
-
+ return tcStar(n, top)
// arithmetic exprs
case ir.OASOP,
ir.OADD,
@@ -804,858 +699,56 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
ir.OOROR,
ir.OSUB,
ir.OXOR:
- 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
+ return tcArith(n)
case ir.OBITNOT, ir.ONEG, ir.ONOT, ir.OPLUS:
n := n.(*ir.UnaryExpr)
- 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
+ return tcUnaryArith(n)
// exprs
case ir.OADDR:
n := n.(*ir.AddrExpr)
- 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
+ return tcAddr(n)
case ir.OCOMPLIT:
- return typecheckcomplit(n.(*ir.CompLitExpr))
+ return tcCompLit(n.(*ir.CompLitExpr))
case ir.OXDOT, ir.ODOT:
n := n.(*ir.SelectorExpr)
- if n.Op() == ir.OXDOT {
- n = AddImplicitDots(n)
- n.SetOp(ir.ODOT)
- if n.X == nil {
- n.SetType(nil)
- return n
- }
- }
-
- n.X = check(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 typecheckpartialcall(n, s)
- }
- return n
+ return tcDot(n, top)
case ir.ODOTTYPE:
n := n.(*ir.TypeAssertExpr)
- 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 = check(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
+ return tcDotType(n)
case ir.OINDEX:
n := n.(*ir.IndexExpr)
- 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
+ return tcIndex(n)
case ir.ORECV:
n := n.(*ir.UnaryExpr)
- 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
+ return tcRecv(n)
case ir.OSEND:
n := n.(*ir.SendStmt)
- n.Chan = Expr(n.Chan)
- n.Value = Expr(n.Value)
- n.Chan = DefaultLit(n.Chan, nil)
- t := n.Chan.Type()
- if t == nil {
- return n
- }
- if !t.IsChan() {
- base.Errorf("invalid operation: %v (send to non-chan type %v)", n, t)
- return n
- }
-
- if !t.ChanDir().CanSend() {
- base.Errorf("invalid operation: %v (send to receive-only type %v)", n, t)
- return n
- }
-
- n.Value = AssignConv(n.Value, t.Elem(), "send")
- if n.Value.Type() == nil {
- return n
- }
- return n
+ return tcSend(n)
case ir.OSLICEHEADER:
- // 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.
n := n.(*ir.SliceHeaderExpr)
- 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
+ return tcSliceHeader(n)
case ir.OMAKESLICECOPY:
- // Errors here are Fatalf instead of Errorf because only the compiler
- // can construct an OMAKESLICECOPY node.
- // Components used in OMAKESCLICECOPY that are supplied by parsed source code
- // have already been typechecked in OMAKE and OCOPY earlier.
n := n.(*ir.MakeExpr)
- t := n.Type()
-
- if t == nil {
- base.Fatalf("no type specified for OMAKESLICECOPY")
- }
-
- if !t.IsSlice() {
- base.Fatalf("invalid type %v for OMAKESLICECOPY", n.Type())
- }
-
- if n.Len == nil {
- base.Fatalf("missing len argument for OMAKESLICECOPY")
- }
-
- if n.Cap == nil {
- base.Fatalf("missing slice argument to copy for OMAKESLICECOPY")
- }
-
- n.Len = Expr(n.Len)
- n.Cap = Expr(n.Cap)
-
- n.Len = DefaultLit(n.Len, types.Types[types.TINT])
-
- if !n.Len.Type().IsInteger() && n.Type().Kind() != types.TIDEAL {
- base.Errorf("non-integer len argument in OMAKESLICECOPY")
- }
-
- if ir.IsConst(n.Len, constant.Int) {
- if ir.ConstOverflow(n.Len.Val(), types.Types[types.TINT]) {
- base.Fatalf("len for OMAKESLICECOPY too large")
- }
- if constant.Sign(n.Len.Val()) < 0 {
- base.Fatalf("len for OMAKESLICECOPY must be non-negative")
- }
- }
- return n
+ return tcMakeSliceCopy(n)
case ir.OSLICE, ir.OSLICE3:
n := n.(*ir.SliceExpr)
- 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
+ return tcSlice(n)
// call and call like
case ir.OCALL:
n := n.(*ir.CallExpr)
- n.Use = ir.CallUseExpr
- if top == ctxStmt {
- n.Use = ir.CallUseStmt
- }
- Stmts(n.Init()) // imported rewritten f(g()) calls (#30907)
- n.X = check(n.X, ctxExpr|ctxType|ctxCallee)
- if n.X.Diag() {
- n.SetDiag(true)
- }
-
- l := n.X
-
- if l.Op() == ir.ONAME && l.(*ir.Name).BuiltinOp != 0 {
- l := l.(*ir.Name)
- if n.IsDDD && l.BuiltinOp != ir.OAPPEND {
- base.Errorf("invalid use of ... with builtin %v", l)
- }
-
- // builtin: OLEN, OCAP, etc.
- switch l.BuiltinOp {
- default:
- base.Fatalf("unknown builtin %v", l)
-
- case ir.OAPPEND, ir.ODELETE, ir.OMAKE, ir.OPRINT, ir.OPRINTN, ir.ORECOVER:
- n.SetOp(l.BuiltinOp)
- n.X = nil
- n.SetTypecheck(0) // re-typechecking new op is OK, not a loop
- return check(n, top)
-
- case ir.OCAP, ir.OCLOSE, ir.OIMAG, ir.OLEN, ir.OPANIC, ir.OREAL:
- typecheckargs(n)
- fallthrough
- case ir.ONEW, ir.OALIGNOF, ir.OOFFSETOF, ir.OSIZEOF:
- arg, ok := needOneArg(n, "%v", n.Op())
- if !ok {
- n.SetType(nil)
- return n
- }
- u := ir.NewUnaryExpr(n.Pos(), l.BuiltinOp, arg)
- return check(ir.InitExpr(n.Init(), u), top) // typecheckargs can add to old.Init
-
- case ir.OCOMPLEX, ir.OCOPY:
- typecheckargs(n)
- arg1, arg2, ok := needTwoArgs(n)
- if !ok {
- n.SetType(nil)
- return n
- }
- b := ir.NewBinaryExpr(n.Pos(), l.BuiltinOp, arg1, arg2)
- return check(ir.InitExpr(n.Init(), b), top) // typecheckargs can add to old.Init
- }
- panic("unreachable")
- }
-
- n.X = DefaultLit(n.X, nil)
- l = n.X
- if l.Op() == ir.OTYPE {
- if n.IsDDD {
- if !l.Type().Broke() {
- base.Errorf("invalid use of ... in type conversion to %v", l.Type())
- }
- n.SetDiag(true)
- }
-
- // pick off before type-checking arguments
- arg, ok := needOneArg(n, "conversion to %v", l.Type())
- if !ok {
- n.SetType(nil)
- return n
- }
-
- n := ir.NewConvExpr(n.Pos(), ir.OCONV, nil, arg)
- n.SetType(l.Type())
- return typecheck1(n, top)
- }
-
- typecheckargs(n)
- t := l.Type()
- if t == nil {
- n.SetType(nil)
- return n
- }
- types.CheckSize(t)
-
- switch l.Op() {
- case ir.ODOTINTER:
- n.SetOp(ir.OCALLINTER)
-
- case ir.ODOTMETH:
- l := l.(*ir.SelectorExpr)
- n.SetOp(ir.OCALLMETH)
-
- // typecheckaste was used here but there wasn't enough
- // information further down the call chain to know if we
- // were testing a method receiver for unexported fields.
- // It isn't necessary, so just do a sanity check.
- tp := t.Recv().Type
-
- if l.X == nil || !types.Identical(l.X.Type(), tp) {
- base.Fatalf("method receiver")
- }
-
- default:
- n.SetOp(ir.OCALLFUNC)
- if t.Kind() != types.TFUNC {
- // TODO(mdempsky): Remove "o.Sym() != nil" once we stop
- // using ir.Name for numeric literals.
- if o := ir.Orig(l); o.Name() != nil && o.Sym() != nil && types.BuiltinPkg.Lookup(o.Sym().Name).Def != nil {
- // be more specific when the non-function
- // name matches a predeclared function
- base.Errorf("cannot call non-function %L, declared at %s",
- l, base.FmtPos(o.Name().Pos()))
- } else {
- base.Errorf("cannot call non-function %L", l)
- }
- n.SetType(nil)
- return n
- }
- }
-
- typecheckaste(ir.OCALL, n.X, n.IsDDD, t.Params(), n.Args, func() string { return fmt.Sprintf("argument to %v", n.X) })
- if t.NumResults() == 0 {
- return n
- }
- if t.NumResults() == 1 {
- n.SetType(l.Type().Results().Field(0).Type)
-
- if n.Op() == ir.OCALLFUNC && n.X.Op() == ir.ONAME {
- if sym := n.X.(*ir.Name).Sym(); types.IsRuntimePkg(sym.Pkg) && sym.Name == "getg" {
- // Emit code for runtime.getg() directly instead of calling function.
- // Most such rewrites (for example the similar one for math.Sqrt) should be done in walk,
- // so that the ordering pass can make sure to preserve the semantics of the original code
- // (in particular, the exact time of the function call) by introducing temporaries.
- // In this case, we know getg() always returns the same result within a given function
- // and we want to avoid the temporaries, so we do the rewrite earlier than is typical.
- n.SetOp(ir.OGETG)
- }
- }
- return n
- }
-
- // multiple return
- if top&(ctxMultiOK|ctxStmt) == 0 {
- base.Errorf("multiple-value %v() in single-value context", l)
- return n
- }
-
- n.SetType(l.Type().Results())
- return n
+ return tcCall(n, top)
case ir.OALIGNOF, ir.OOFFSETOF, ir.OSIZEOF:
n := n.(*ir.UnaryExpr)
@@ -1664,464 +757,59 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
case ir.OCAP, ir.OLEN:
n := n.(*ir.UnaryExpr)
- 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
+ return tcLenCap(n)
case ir.OREAL, ir.OIMAG:
n := n.(*ir.UnaryExpr)
- n.X = Expr(n.X)
- l := n.X
- t := l.Type()
- if t == nil {
- n.SetType(nil)
- return n
- }
-
- // Determine result type.
- switch t.Kind() {
- case types.TIDEAL:
- n.SetType(types.UntypedFloat)
- case types.TCOMPLEX64:
- n.SetType(types.Types[types.TFLOAT32])
- case types.TCOMPLEX128:
- n.SetType(types.Types[types.TFLOAT64])
- default:
- base.Errorf("invalid argument %L for %v", l, n.Op())
- n.SetType(nil)
- return n
- }
- return n
+ return tcRealImag(n)
case ir.OCOMPLEX:
n := n.(*ir.BinaryExpr)
- l := Expr(n.X)
- r := Expr(n.Y)
- if l.Type() == nil || r.Type() == nil {
- n.SetType(nil)
- return n
- }
- l, r = defaultlit2(l, r, false)
- if l.Type() == nil || r.Type() == nil {
- n.SetType(nil)
- return n
- }
- n.X = l
- n.Y = r
-
- if !types.Identical(l.Type(), r.Type()) {
- base.Errorf("invalid operation: %v (mismatched types %v and %v)", n, l.Type(), r.Type())
- n.SetType(nil)
- return n
- }
-
- var t *types.Type
- switch l.Type().Kind() {
- default:
- base.Errorf("invalid operation: %v (arguments have type %v, expected floating-point)", n, l.Type())
- n.SetType(nil)
- return n
-
- case types.TIDEAL:
- t = types.UntypedComplex
-
- case types.TFLOAT32:
- t = types.Types[types.TCOMPLEX64]
-
- case types.TFLOAT64:
- t = types.Types[types.TCOMPLEX128]
- }
- n.SetType(t)
- return n
+ return tcComplex(n)
case ir.OCLOSE:
n := n.(*ir.UnaryExpr)
- 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 (non-chan type %v)", n, t)
- n.SetType(nil)
- return n
- }
-
- if !t.ChanDir().CanSend() {
- base.Errorf("invalid operation: %v (cannot close receive-only channel)", n)
- n.SetType(nil)
- return n
- }
- return n
+ return tcClose(n)
case ir.ODELETE:
n := n.(*ir.CallExpr)
- typecheckargs(n)
- args := n.Args
- if len(args) == 0 {
- base.Errorf("missing arguments to delete")
- n.SetType(nil)
- return n
- }
-
- if len(args) == 1 {
- base.Errorf("missing second (key) argument to delete")
- n.SetType(nil)
- return n
- }
-
- if len(args) != 2 {
- base.Errorf("too many arguments to delete")
- n.SetType(nil)
- return n
- }
-
- l := args[0]
- r := args[1]
- if l.Type() != nil && !l.Type().IsMap() {
- base.Errorf("first argument to delete must be map; have %L", l.Type())
- n.SetType(nil)
- return n
- }
-
- args[1] = AssignConv(r, l.Type().Key(), "delete")
- return n
+ return tcDelete(n)
case ir.OAPPEND:
n := n.(*ir.CallExpr)
- typecheckargs(n)
- args := n.Args
- if len(args) == 0 {
- base.Errorf("missing arguments to append")
- n.SetType(nil)
- return n
- }
-
- t := args[0].Type()
- if t == nil {
- n.SetType(nil)
- return n
- }
-
- n.SetType(t)
- if !t.IsSlice() {
- if ir.IsNil(args[0]) {
- base.Errorf("first argument to append must be typed slice; have untyped nil")
- n.SetType(nil)
- return n
- }
-
- base.Errorf("first argument to append must be slice; have %L", t)
- n.SetType(nil)
- return n
- }
-
- if n.IsDDD {
- if len(args) == 1 {
- base.Errorf("cannot use ... on first argument to append")
- n.SetType(nil)
- return n
- }
-
- if len(args) != 2 {
- base.Errorf("too many arguments to append")
- n.SetType(nil)
- return n
- }
-
- if t.Elem().IsKind(types.TUINT8) && args[1].Type().IsString() {
- args[1] = DefaultLit(args[1], types.Types[types.TSTRING])
- return n
- }
-
- args[1] = AssignConv(args[1], t.Underlying(), "append")
- return n
- }
-
- as := args[1:]
- for i, n := range as {
- if n.Type() == nil {
- continue
- }
- as[i] = AssignConv(n, t.Elem(), "append")
- types.CheckSize(as[i].Type()) // ensure width is calculated for backend
- }
- return n
+ return tcAppend(n)
case ir.OCOPY:
n := n.(*ir.BinaryExpr)
- n.SetType(types.Types[types.TINT])
- n.X = Expr(n.X)
- n.X = DefaultLit(n.X, nil)
- n.Y = Expr(n.Y)
- n.Y = DefaultLit(n.Y, nil)
- if n.X.Type() == nil || n.Y.Type() == nil {
- n.SetType(nil)
- return n
- }
-
- // copy([]byte, string)
- if n.X.Type().IsSlice() && n.Y.Type().IsString() {
- if types.Identical(n.X.Type().Elem(), types.ByteType) {
- return n
- }
- base.Errorf("arguments to copy have different element types: %L and string", n.X.Type())
- n.SetType(nil)
- return n
- }
-
- if !n.X.Type().IsSlice() || !n.Y.Type().IsSlice() {
- if !n.X.Type().IsSlice() && !n.Y.Type().IsSlice() {
- base.Errorf("arguments to copy must be slices; have %L, %L", n.X.Type(), n.Y.Type())
- } else if !n.X.Type().IsSlice() {
- base.Errorf("first argument to copy should be slice; have %L", n.X.Type())
- } else {
- base.Errorf("second argument to copy should be slice or string; have %L", n.Y.Type())
- }
- n.SetType(nil)
- return n
- }
-
- if !types.Identical(n.X.Type().Elem(), n.Y.Type().Elem()) {
- base.Errorf("arguments to copy have different element types: %L and %L", n.X.Type(), n.Y.Type())
- n.SetType(nil)
- return n
- }
- return n
+ return tcCopy(n)
case ir.OCONV:
n := n.(*ir.ConvExpr)
- 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
+ return tcConv(n)
case ir.OMAKE:
n := n.(*ir.CallExpr)
- args := n.Args
- if len(args) == 0 {
- base.Errorf("missing argument to make")
- n.SetType(nil)
- return n
- }
-
- n.Args.Set(nil)
- l := args[0]
- l = check(l, ctxType)
- t := l.Type()
- if t == nil {
- n.SetType(nil)
- return n
- }
-
- i := 1
- var nn ir.Node
- switch t.Kind() {
- default:
- base.Errorf("cannot make type %v", t)
- n.SetType(nil)
- return n
-
- case types.TSLICE:
- if i >= len(args) {
- base.Errorf("missing len argument to make(%v)", t)
- n.SetType(nil)
- return n
- }
-
- l = args[i]
- i++
- l = Expr(l)
- var r ir.Node
- if i < len(args) {
- r = args[i]
- i++
- r = Expr(r)
- }
-
- if l.Type() == nil || (r != nil && r.Type() == nil) {
- n.SetType(nil)
- return n
- }
- if !checkmake(t, "len", &l) || r != nil && !checkmake(t, "cap", &r) {
- n.SetType(nil)
- return n
- }
- if ir.IsConst(l, constant.Int) && r != nil && ir.IsConst(r, constant.Int) && constant.Compare(l.Val(), token.GTR, r.Val()) {
- base.Errorf("len larger than cap in make(%v)", t)
- n.SetType(nil)
- return n
- }
- nn = ir.NewMakeExpr(n.Pos(), ir.OMAKESLICE, l, r)
-
- case types.TMAP:
- if i < len(args) {
- l = args[i]
- i++
- l = Expr(l)
- l = DefaultLit(l, types.Types[types.TINT])
- if l.Type() == nil {
- n.SetType(nil)
- return n
- }
- if !checkmake(t, "size", &l) {
- n.SetType(nil)
- return n
- }
- } else {
- l = ir.NewInt(0)
- }
- nn = ir.NewMakeExpr(n.Pos(), ir.OMAKEMAP, l, nil)
- nn.SetEsc(n.Esc())
-
- case types.TCHAN:
- l = nil
- if i < len(args) {
- l = args[i]
- i++
- l = Expr(l)
- l = DefaultLit(l, types.Types[types.TINT])
- if l.Type() == nil {
- n.SetType(nil)
- return n
- }
- if !checkmake(t, "buffer", &l) {
- n.SetType(nil)
- return n
- }
- } else {
- l = ir.NewInt(0)
- }
- nn = ir.NewMakeExpr(n.Pos(), ir.OMAKECHAN, l, nil)
- }
-
- if i < len(args) {
- base.Errorf("too many arguments to make(%v)", t)
- n.SetType(nil)
- return n
- }
-
- nn.SetType(t)
- return nn
+ return tcMake(n)
case ir.ONEW:
n := n.(*ir.UnaryExpr)
- if n.X == nil {
- // Fatalf because the OCALL above checked for us,
- // so this must be an internally-generated mistake.
- base.Fatalf("missing argument to new")
- }
- l := n.X
- l = check(l, ctxType)
- t := l.Type()
- if t == nil {
- n.SetType(nil)
- return n
- }
- n.X = l
- n.SetType(types.NewPtr(t))
- return n
+ return tcNew(n)
case ir.OPRINT, ir.OPRINTN:
n := n.(*ir.CallExpr)
- typecheckargs(n)
- ls := n.Args
- for i1, n1 := range ls {
- // Special case for print: int constant is int64, not int.
- if ir.IsConst(n1, constant.Int) {
- ls[i1] = DefaultLit(ls[i1], types.Types[types.TINT64])
- } else {
- ls[i1] = DefaultLit(ls[i1], nil)
- }
- }
- return n
+ return tcPrint(n)
case ir.OPANIC:
n := n.(*ir.UnaryExpr)
- n.X = Expr(n.X)
- n.X = DefaultLit(n.X, types.Types[types.TINTER])
- if n.X.Type() == nil {
- n.SetType(nil)
- return n
- }
- return n
+ return tcPanic(n)
case ir.ORECOVER:
n := n.(*ir.CallExpr)
- if len(n.Args) != 0 {
- base.Errorf("too many arguments to recover")
- n.SetType(nil)
- return n
- }
-
- n.SetType(types.Types[types.TINTER])
- return n
+ return tcRecover(n)
case ir.OCLOSURE:
n := n.(*ir.ClosureExpr)
- typecheckclosure(n, top)
+ tcClosure(n, top)
if n.Type() == nil {
return n
}
@@ -2129,17 +817,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
case ir.OITAB:
n := n.(*ir.UnaryExpr)
- 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
+ return tcITab(n)
case ir.OIDATA:
// Whoever creates the OIDATA node must know a priori the concrete type at that moment,
@@ -2150,21 +828,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
case ir.OSPTR:
n := n.(*ir.UnaryExpr)
- 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
+ return tcSPtr(n)
case ir.OCLOSUREREAD:
return n
@@ -2183,7 +847,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
// statements
case ir.OAS:
n := n.(*ir.AssignStmt)
- typecheckas(n)
+ tcAssign(n)
// Code that creates temps does not bother to set defn, so do it here.
if n.X.Op() == ir.ONAME && ir.IsAutoTmp(n.X) {
@@ -2192,7 +856,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
return n
case ir.OAS2:
- typecheckas2(n.(*ir.AssignListStmt))
+ tcAssignList(n.(*ir.AssignListStmt))
return n
case ir.OBREAK,
@@ -2221,76 +885,38 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
case ir.ODEFER, ir.OGO:
n := n.(*ir.GoDeferStmt)
- n.Call = check(n.Call, ctxStmt|ctxExpr)
+ n.Call = typecheck(n.Call, ctxStmt|ctxExpr)
if !n.Call.Diag() {
- checkdefergo(n)
+ tcGoDefer(n)
}
return n
case ir.OFOR, ir.OFORUNTIL:
n := n.(*ir.ForStmt)
- Stmts(n.Init())
- decldepth++
- n.Cond = Expr(n.Cond)
- n.Cond = DefaultLit(n.Cond, nil)
- if n.Cond != nil {
- t := n.Cond.Type()
- if t != nil && !t.IsBoolean() {
- base.Errorf("non-bool %L used as for condition", n.Cond)
- }
- }
- n.Post = Stmt(n.Post)
- if n.Op() == ir.OFORUNTIL {
- Stmts(n.Late)
- }
- Stmts(n.Body)
- decldepth--
- return n
+ return tcFor(n)
case ir.OIF:
n := n.(*ir.IfStmt)
- Stmts(n.Init())
- n.Cond = Expr(n.Cond)
- n.Cond = DefaultLit(n.Cond, nil)
- if n.Cond != nil {
- t := n.Cond.Type()
- if t != nil && !t.IsBoolean() {
- base.Errorf("non-bool %L used as if condition", n.Cond)
- }
- }
- Stmts(n.Body)
- Stmts(n.Else)
- return n
+ return tcIf(n)
case ir.ORETURN:
n := n.(*ir.ReturnStmt)
- typecheckargs(n)
- if ir.CurFunc == nil {
- base.Errorf("return outside function")
- n.SetType(nil)
- return n
- }
-
- if ir.HasNamedResults(ir.CurFunc) && len(n.Results) == 0 {
- return n
- }
- typecheckaste(ir.ORETURN, nil, false, ir.CurFunc.Type().Results(), n.Results, func() string { return "return argument" })
- return n
+ return tcReturn(n)
case ir.ORETJMP:
n := n.(*ir.BranchStmt)
return n
case ir.OSELECT:
- typecheckselect(n.(*ir.SelectStmt))
+ tcSelect(n.(*ir.SelectStmt))
return n
case ir.OSWITCH:
- typecheckswitch(n.(*ir.SwitchStmt))
+ tcSwitch(n.(*ir.SwitchStmt))
return n
case ir.ORANGE:
- typecheckrange(n.(*ir.RangeStmt))
+ tcRange(n.(*ir.RangeStmt))
return n
case ir.OTYPESW:
@@ -2300,7 +926,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
return n
case ir.ODCLFUNC:
- typecheckfunc(n.(*ir.Func))
+ tcFunc(n.(*ir.Func))
return n
case ir.ODCLCONST:
@@ -2310,7 +936,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
case ir.ODCLTYPE:
n := n.(*ir.Decl)
- n.X = check(n.X, ctxType)
+ n.X = typecheck(n.X, ctxType)
types.CheckSize(n.X.Type())
return n
}
@@ -2424,59 +1050,6 @@ func checksliceconst(lo ir.Node, hi ir.Node) bool {
return true
}
-func checkdefergo(n *ir.GoDeferStmt) {
- what := "defer"
- if n.Op() == ir.OGO {
- what = "go"
- }
-
- switch n.Call.Op() {
- // ok
- case ir.OCALLINTER,
- ir.OCALLMETH,
- ir.OCALLFUNC,
- ir.OCLOSE,
- ir.OCOPY,
- ir.ODELETE,
- ir.OPANIC,
- ir.OPRINT,
- ir.OPRINTN,
- ir.ORECOVER:
- return
-
- case ir.OAPPEND,
- ir.OCAP,
- ir.OCOMPLEX,
- ir.OIMAG,
- ir.OLEN,
- ir.OMAKE,
- ir.OMAKESLICE,
- ir.OMAKECHAN,
- ir.OMAKEMAP,
- ir.ONEW,
- ir.OREAL,
- ir.OLITERAL: // conversion or unsafe.Alignof, Offsetof, Sizeof
- if orig := ir.Orig(n.Call); orig.Op() == ir.OCONV {
- break
- }
- base.ErrorfAt(n.Pos(), "%s discards result of %v", what, n.Call)
- return
- }
-
- // type is broken or missing, most likely a method call on a broken type
- // we will warn about the broken type elsewhere. no need to emit a potentially confusing error
- if n.Call.Type() == nil || n.Call.Type().Broke() {
- return
- }
-
- if !n.Diag() {
- // The syntax made sure it was a call, so this must be
- // a conversion.
- n.SetDiag(true)
- base.ErrorfAt(n.Pos(), "%s requires function call, not conversion", what)
- }
-}
-
// The result of implicitstar MUST be assigned back to n, e.g.
// n.Left = implicitstar(n.Left)
func implicitstar(n ir.Node) ir.Node {
@@ -2687,11 +1260,11 @@ func lookdot(n *ir.SelectorExpr, t *types.Type, dostrcmp int) *types.Field {
checklvalue(n.X, "call pointer method on")
addr := NodAddr(n.X)
addr.SetImplicit(true)
- n.X = check(addr, ctxType|ctxExpr)
+ n.X = typecheck(addr, ctxType|ctxExpr)
} else if tt.IsPtr() && (!rcvr.IsPtr() || rcvr.IsPtr() && rcvr.Elem().NotInHeap()) && types.Identical(tt.Elem(), rcvr) {
star := ir.NewStarExpr(base.Pos, n.X)
star.SetImplicit(true)
- n.X = check(star, ctxType|ctxExpr)
+ n.X = typecheck(star, ctxType|ctxExpr)
} else if tt.IsPtr() && tt.Elem().IsPtr() && types.Identical(derefall(tt), derefall(rcvr)) {
base.Errorf("calling method %v with receiver %L requires explicit dereference", n.Sel, n.X)
for tt.IsPtr() {
@@ -2701,7 +1274,7 @@ func lookdot(n *ir.SelectorExpr, t *types.Type, dostrcmp int) *types.Field {
}
star := ir.NewStarExpr(base.Pos, n.X)
star.SetImplicit(true)
- n.X = check(star, ctxType|ctxExpr)
+ n.X = typecheck(star, ctxType|ctxExpr)
tt = tt.Elem()
}
} else {
@@ -2985,214 +1558,6 @@ func pushtype(nn ir.Node, t *types.Type) ir.Node {
return n
}
-// The result of typecheckcomplit MUST be assigned back to n, e.g.
-// n.Left = typecheckcomplit(n.Left)
-func typecheckcomplit(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 = check(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(check(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
-}
-
// typecheckarraylit type-checks a sequence of slice/array literal elements.
func typecheckarraylit(elemType *types.Type, bound int64, elts []ir.Node, ctx string) int64 {
// If there are key/value pairs, create a map to keep seen
@@ -3324,60 +1689,6 @@ func checkassignlist(stmt ir.Node, l ir.Nodes) {
}
}
-// type check assignment.
-// if this assignment is the definition of a var on the left side,
-// fill in the var's type.
-func typecheckas(n *ir.AssignStmt) {
- if base.EnableTrace && base.Flag.LowerT {
- defer tracePrint("typecheckas", n)(nil)
- }
-
- // delicate little dance.
- // the definition of n may refer to this assignment
- // as its definition, in which case it will call typecheckas.
- // in that case, do not call typecheck back, or it will cycle.
- // if the variable has a type (ntype) then typechecking
- // will not look at defn, so it is okay (and desirable,
- // so that the conversion below happens).
- n.X = Resolve(n.X)
-
- if !ir.DeclaredBy(n.X, n) || n.X.Name().Ntype != nil {
- n.X = AssignExpr(n.X)
- }
-
- // Use ctxMultiOK so we can emit an "N variables but M values" error
- // to be consistent with typecheckas2 (#26616).
- n.Y = check(n.Y, ctxExpr|ctxMultiOK)
- checkassign(n, n.X)
- if n.Y != nil && n.Y.Type() != nil {
- if n.Y.Type().IsFuncArgStruct() {
- base.Errorf("assignment mismatch: 1 variable but %v returns %d values", n.Y.(*ir.CallExpr).X, n.Y.Type().NumFields())
- // Multi-value RHS isn't actually valid for OAS; nil out
- // to indicate failed typechecking.
- n.Y.SetType(nil)
- } else if n.X.Type() != nil {
- n.Y = AssignConv(n.Y, n.X.Type(), "assignment")
- }
- }
-
- if ir.DeclaredBy(n.X, n) && n.X.Name().Ntype == nil {
- n.Y = DefaultLit(n.Y, nil)
- n.X.SetType(n.Y.Type())
- }
-
- // second half of dance.
- // now that right is done, typecheck the left
- // just to get it over with. see dance above.
- n.SetTypecheck(1)
-
- if n.X.Typecheck() == 0 {
- n.X = AssignExpr(n.X)
- }
- if !ir.IsBlank(n.X) {
- types.CheckSize(n.X.Type()) // ensure width is calculated for backend
- }
-}
-
func checkassignto(src *types.Type, dst ir.Node) {
if op, why := assignop(src, dst.Type()); op == ir.OXXX {
base.Errorf("cannot assign %v to %L in multiple assignment%s", src, dst, why)
@@ -3385,173 +1696,6 @@ func checkassignto(src *types.Type, dst ir.Node) {
}
}
-func typecheckas2(n *ir.AssignListStmt) {
- if base.EnableTrace && base.Flag.LowerT {
- defer tracePrint("typecheckas2", n)(nil)
- }
-
- ls := n.Lhs
- for i1, n1 := range ls {
- // delicate little dance.
- n1 = Resolve(n1)
- ls[i1] = n1
-
- if !ir.DeclaredBy(n1, n) || n1.Name().Ntype != nil {
- ls[i1] = AssignExpr(ls[i1])
- }
- }
-
- cl := len(n.Lhs)
- cr := len(n.Rhs)
- if cl > 1 && cr == 1 {
- n.Rhs[0] = check(n.Rhs[0], ctxExpr|ctxMultiOK)
- } else {
- Exprs(n.Rhs)
- }
- checkassignlist(n, n.Lhs)
-
- var l ir.Node
- var r ir.Node
- if cl == cr {
- // easy
- ls := n.Lhs
- rs := n.Rhs
- for il, nl := range ls {
- nr := rs[il]
- if nl.Type() != nil && nr.Type() != nil {
- rs[il] = AssignConv(nr, nl.Type(), "assignment")
- }
- if ir.DeclaredBy(nl, n) && nl.Name().Ntype == nil {
- rs[il] = DefaultLit(rs[il], nil)
- nl.SetType(rs[il].Type())
- }
- }
-
- goto out
- }
-
- l = n.Lhs[0]
- r = n.Rhs[0]
-
- // x,y,z = f()
- if cr == 1 {
- if r.Type() == nil {
- goto out
- }
- switch r.Op() {
- case ir.OCALLMETH, ir.OCALLINTER, ir.OCALLFUNC:
- if !r.Type().IsFuncArgStruct() {
- break
- }
- cr = r.Type().NumFields()
- if cr != cl {
- goto mismatch
- }
- r.(*ir.CallExpr).Use = ir.CallUseList
- n.SetOp(ir.OAS2FUNC)
- for i, l := range n.Lhs {
- f := r.Type().Field(i)
- if f.Type != nil && l.Type() != nil {
- checkassignto(f.Type, l)
- }
- if ir.DeclaredBy(l, n) && l.Name().Ntype == nil {
- l.SetType(f.Type)
- }
- }
- goto out
- }
- }
-
- // x, ok = y
- if cl == 2 && cr == 1 {
- if r.Type() == nil {
- goto out
- }
- switch r.Op() {
- case ir.OINDEXMAP, ir.ORECV, ir.ODOTTYPE:
- switch r.Op() {
- case ir.OINDEXMAP:
- n.SetOp(ir.OAS2MAPR)
- case ir.ORECV:
- n.SetOp(ir.OAS2RECV)
- case ir.ODOTTYPE:
- r := r.(*ir.TypeAssertExpr)
- n.SetOp(ir.OAS2DOTTYPE)
- r.SetOp(ir.ODOTTYPE2)
- }
- if l.Type() != nil {
- checkassignto(r.Type(), l)
- }
- if ir.DeclaredBy(l, n) {
- l.SetType(r.Type())
- }
- l := n.Lhs[1]
- if l.Type() != nil && !l.Type().IsBoolean() {
- checkassignto(types.Types[types.TBOOL], l)
- }
- if ir.DeclaredBy(l, n) && l.Name().Ntype == nil {
- l.SetType(types.Types[types.TBOOL])
- }
- goto out
- }
- }
-
-mismatch:
- switch r.Op() {
- default:
- base.Errorf("assignment mismatch: %d variables but %d values", cl, cr)
- case ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER:
- r := r.(*ir.CallExpr)
- base.Errorf("assignment mismatch: %d variables but %v returns %d values", cl, r.X, cr)
- }
-
- // second half of dance
-out:
- n.SetTypecheck(1)
- ls = n.Lhs
- for i1, n1 := range ls {
- if n1.Typecheck() == 0 {
- ls[i1] = AssignExpr(ls[i1])
- }
- }
-}
-
-// type check function definition
-// To be called by typecheck, not directly.
-// (Call typecheckFunc instead.)
-func typecheckfunc(n *ir.Func) {
- if base.EnableTrace && base.Flag.LowerT {
- defer tracePrint("typecheckfunc", n)(nil)
- }
-
- for _, ln := range n.Dcl {
- if ln.Op() == ir.ONAME && (ln.Class_ == ir.PPARAM || ln.Class_ == ir.PPARAMOUT) {
- ln.Decldepth = 1
- }
- }
-
- n.Nname = AssignExpr(n.Nname).(*ir.Name)
- t := n.Nname.Type()
- if t == nil {
- return
- }
- n.SetType(t)
- rcvr := t.Recv()
- if rcvr != nil && n.Shortname != nil {
- m := addmethod(n, n.Shortname, t, true, n.Pragma&ir.Nointerface != 0)
- if m == nil {
- return
- }
-
- n.Nname.SetSym(ir.MethodSym(rcvr.Type, n.Shortname))
- Declare(n.Nname, ir.PFUNC)
- }
-
- if base.Ctxt.Flag_dynlink && !inimport && n.Nname != nil {
- NeedFuncSym(n.Sym())
- }
-}
-
// The result of stringtoruneslit MUST be assigned back to n, e.g.
// n.Left = stringtoruneslit(n.Left)
func stringtoruneslit(n *ir.ConvExpr) ir.Node {