return n
}
- n.SetTypecheck(2)
-
typecheck_tcstack = append(typecheck_tcstack, n)
- n = typecheck1(n, top)
+ n.SetTypecheck(2)
+ n = typecheck1(n, top)
n.SetTypecheck(1)
last := len(typecheck_tcstack) - 1
typecheck_tcstack[last] = nil
typecheck_tcstack = typecheck_tcstack[:last]
+ _, isExpr := n.(ir.Expr)
+ _, isStmt := n.(ir.Stmt)
+ isMulti := false
+ switch n.Op() {
+ case ir.OCALLFUNC, ir.OCALLINTER, ir.OCALLMETH:
+ if t := n.Left().Type(); t != nil && t.Kind() == types.TFUNC {
+ nr := t.NumResults()
+ isMulti = nr > 1
+ if nr == 0 {
+ isExpr = false
+ }
+ }
+ case ir.OAPPEND:
+ // Must be used (and not BinaryExpr/UnaryExpr).
+ isStmt = false
+ case ir.OCLOSE, ir.ODELETE, ir.OPANIC, ir.OPRINT, ir.OPRINTN, ir.OVARKILL, ir.OVARLIVE:
+ // Must not be used.
+ isExpr = false
+ isStmt = true
+ case ir.OCOPY, ir.ORECOVER, ir.ORECV:
+ // Can be used or not.
+ isStmt = true
+ }
+
+ t := n.Type()
+ if t != nil && !t.IsFuncArgStruct() && n.Op() != ir.OTYPE {
+ switch t.Kind() {
+ case types.TFUNC, // might have TANY; wait until it's called
+ types.TANY, types.TFORW, types.TIDEAL, types.TNIL, types.TBLANK:
+ break
+
+ default:
+ checkwidth(t)
+ }
+ }
+ if t != nil {
+ n = evalConst(n)
+ t = n.Type()
+ }
+
+ // TODO(rsc): Lots of the complexity here is because typecheck can
+ // see OTYPE, ONAME, and OLITERAL nodes multiple times.
+ // Once we make the IR a proper tree, we should be able to simplify
+ // this code a bit, especially the final case.
+ switch {
+ case top&(ctxStmt|ctxExpr) == ctxExpr && !isExpr && n.Op() != ir.OTYPE && !isMulti:
+ if !n.Diag() {
+ base.Errorf("%v used as value", n)
+ n.SetDiag(true)
+ }
+ if t != nil {
+ n.SetType(nil)
+ }
+
+ case top&ctxType == 0 && n.Op() == ir.OTYPE && t != nil:
+ if !n.Type().Broke() {
+ base.Errorf("type %v is not an expression", n.Type())
+ }
+ n.SetType(nil)
+
+ case top&(ctxStmt|ctxExpr) == ctxStmt && !isStmt && t != nil:
+ if !n.Diag() {
+ base.Errorf("%v evaluated but not used", n)
+ n.SetDiag(true)
+ }
+ n.SetType(nil)
+
+ case top&(ctxType|ctxExpr) == ctxType && n.Op() != ir.OTYPE && n.Op() != ir.ONONAME && (t != nil || n.Op() == ir.ONAME):
+ base.Errorf("%v is not a type", n)
+ if t != nil {
+ n.SetType(nil)
+ }
+
+ }
+
base.Pos = lno
return n
}
return n
}
-// The result of typecheck1 MUST be assigned back to n, e.g.
-// n.Left = typecheck1(n.Left, top)
+// typecheck1 should ONLY be called from typecheck.
func typecheck1(n ir.Node, top int) (res ir.Node) {
if enableTrace && base.Flag.LowerT {
defer tracePrint("typecheck1", n)(&res)
switch n.Op() {
case ir.OLITERAL, ir.ONAME, ir.ONONAME, ir.OTYPE:
if n.Sym() == nil {
- break
+ return n
}
if n.Op() == ir.ONAME && n.SubOp() != 0 && top&ctxCallee == 0 {
}
}
- ok := 0
switch n.Op() {
- // until typecheck is complete, do nothing.
default:
ir.Dump("typecheck", n)
-
base.Fatalf("typecheck %v", n.Op())
+ panic("unreachable")
// names
case ir.OLITERAL:
- ok |= ctxExpr
-
if n.Type() == nil && n.Val().Kind() == constant.String {
base.Fatalf("string literal missing type")
}
+ return n
case ir.ONIL, ir.ONONAME:
- ok |= ctxExpr
+ return n
case ir.ONAME:
if n.Name().Decldepth == 0 {
n.Name().Decldepth = decldepth
}
if n.SubOp() != 0 {
- ok |= ctxCallee
- break
+ return n
}
-
if top&ctxAssign == 0 {
// not a write to the variable
if ir.IsBlank(n) {
n.SetType(nil)
return n
}
-
n.Name().SetUsed(true)
}
-
- ok |= ctxExpr
+ return n
case ir.OPACK:
base.Errorf("use of package %v without selector", n.Sym())
// types (ODEREF is with exprs)
case ir.OTYPE:
- ok |= ctxType
-
if n.Type() == nil {
return n
}
+ return n
case ir.OTSLICE:
- ok |= ctxType
n := n.(*ir.SliceType)
n.Elem = typecheck(n.Elem, ctxType)
if n.Elem.Type() == nil {
t := types.NewSlice(n.Elem.Type())
n.SetOTYPE(t)
checkwidth(t)
+ return n
case ir.OTARRAY:
- ok |= ctxType
n := n.(*ir.ArrayType)
n.Elem = typecheck(n.Elem, ctxType)
if n.Elem.Type() == nil {
t := types.NewArray(n.Elem.Type(), bound)
n.SetOTYPE(t)
checkwidth(t)
+ return n
case ir.OTMAP:
- ok |= ctxType
n := n.(*ir.MapType)
n.Key = typecheck(n.Key, ctxType)
n.Elem = typecheck(n.Elem, ctxType)
}
n.SetOTYPE(types.NewMap(l.Type(), r.Type()))
mapqueue = append(mapqueue, n) // check map keys when all types are settled
+ return n
case ir.OTCHAN:
- ok |= ctxType
n := n.(*ir.ChanType)
n.Elem = typecheck(n.Elem, ctxType)
l := n.Elem
base.Errorf("chan of incomplete (or unallocatable) type not allowed")
}
n.SetOTYPE(types.NewChan(l.Type(), n.Dir))
+ return n
case ir.OTSTRUCT:
- ok |= ctxType
n := n.(*ir.StructType)
n.SetOTYPE(tostruct(n.Fields))
+ return n
case ir.OTINTER:
- ok |= ctxType
n := n.(*ir.InterfaceType)
n.SetOTYPE(tointerface(n.Methods))
+ return n
case ir.OTFUNC:
- ok |= ctxType
n := n.(*ir.FuncType)
n.SetOTYPE(functype(n.Recv, n.Params, n.Results))
+ return n
// type or expr
case ir.ODEREF:
return n
}
if l.Op() == ir.OTYPE {
- ok |= ctxType
n.SetOTYPE(types.NewPtr(l.Type()))
// Ensure l.Type gets dowidth'd for the backend. Issue 20174.
checkwidth(l.Type())
- break
+ return n
}
if !t.IsPtr() {
n.SetType(nil)
return n
}
-
- break
+ base.Errorf("%v is not a type", l)
+ return n
}
- ok |= ctxExpr
n.SetType(t.Elem())
+ return n
// arithmetic exprs
case ir.OASOP,
var op ir.Op
var r ir.Node
if n.Op() == ir.OASOP {
- ok |= ctxStmt
n.SetLeft(typecheck(n.Left(), ctxExpr))
n.SetRight(typecheck(n.Right(), ctxExpr))
l = n.Left()
// TODO(marvin): Fix Node.EType type union.
op = n.SubOp()
} else {
- ok |= ctxExpr
n.SetLeft(typecheck(n.Left(), ctxExpr))
n.SetRight(typecheck(n.Right(), ctxExpr))
l = n.Left()
if (l.Type() == types.UntypedFloat || l.Type() == types.UntypedComplex) && r.Op() == ir.OLITERAL {
n.SetType(types.UntypedInt)
}
-
- break
+ return n
}
// For "x == x && len(s)", it's better to report that "len(s)" (type int)
}
n.SetType(t)
+ return n
case ir.OBITNOT, ir.ONEG, ir.ONOT, ir.OPLUS:
- ok |= ctxExpr
n.SetLeft(typecheck(n.Left(), ctxExpr))
l := n.Left()
t := l.Type()
}
n.SetType(t)
+ return n
// exprs
case ir.OADDR:
- ok |= ctxExpr
-
n.SetLeft(typecheck(n.Left(), ctxExpr))
if n.Left().Type() == nil {
n.SetType(nil)
}
n.SetType(types.NewPtr(n.Left().Type()))
+ return n
case ir.OCOMPLIT:
- ok |= ctxExpr
- n = typecheckcomplit(n)
- if n.Type() == nil {
- return n
- }
+ return typecheckcomplit(n)
case ir.OXDOT, ir.ODOT:
if n.Op() == ir.OXDOT {
s := n.Sym()
if n.Left().Op() == ir.OTYPE {
- n = typecheckMethodExpr(n)
- if n.Type() == nil {
- return n
- }
- ok = ctxExpr
- break
+ return typecheckMethodExpr(n)
}
if t.IsPtr() && !t.Elem().IsInterface() {
return n
}
- switch n.Op() {
- case ir.ODOTINTER, ir.ODOTMETH:
- if top&ctxCallee != 0 {
- ok |= ctxCallee
- } else {
- n = typecheckpartialcall(n, s)
- ok |= ctxExpr
- }
-
- default:
- ok |= ctxExpr
+ if (n.Op() == ir.ODOTINTER || n.Op() == ir.ODOTMETH) && top&ctxCallee == 0 {
+ n = typecheckpartialcall(n, s)
}
+ return n
case ir.ODOTTYPE:
- ok |= ctxExpr
n.SetLeft(typecheck(n.Left(), ctxExpr))
n.SetLeft(defaultlit(n.Left(), nil))
l := n.Left()
return n
}
}
+ return n
case ir.OINDEX:
- ok |= ctxExpr
n.SetLeft(typecheck(n.Left(), ctxExpr))
n.SetLeft(defaultlit(n.Left(), nil))
n.SetLeft(implicitstar(n.Left()))
if n.Right().Type() != nil && !n.Right().Type().IsInteger() {
base.Errorf("non-integer %s index %v", why, n.Right())
- break
+ return n
}
if !n.Bounded() && ir.IsConst(n.Right(), constant.Int) {
n.SetOp(ir.OINDEXMAP)
n.SetIndexMapLValue(false)
}
+ return n
case ir.ORECV:
- ok |= ctxStmt | ctxExpr
n.SetLeft(typecheck(n.Left(), ctxExpr))
n.SetLeft(defaultlit(n.Left(), nil))
l := n.Left()
}
n.SetType(t.Elem())
+ return n
case ir.OSEND:
- ok |= ctxStmt
n.SetLeft(typecheck(n.Left(), ctxExpr))
n.SetRight(typecheck(n.Right(), ctxExpr))
n.SetLeft(defaultlit(n.Left(), nil))
if n.Right().Type() == nil {
return n
}
+ return 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.
- ok |= ctxExpr
-
t := n.Type()
if t == nil {
base.Fatalf("no type specified for OSLICEHEADER")
n.List().SetFirst(l)
n.List().SetSecond(c)
+ return 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.
- ok |= ctxExpr
-
t := n.Type()
if t == nil {
base.Fatalf("len for OMAKESLICECOPY must be non-negative")
}
}
+ return n
case ir.OSLICE, ir.OSLICE3:
- ok |= ctxExpr
n.SetLeft(typecheck(n.Left(), ctxExpr))
low, high, max := n.SliceBounds()
hasmax := n.Op().IsSlice3()
n.SetType(nil)
return n
}
+ return n
// call and call like
case ir.OCALL:
case ir.OAPPEND, ir.ODELETE, ir.OMAKE, ir.OPRINT, ir.OPRINTN, ir.ORECOVER:
n.SetOp(l.SubOp())
n.SetLeft(nil)
+ n.SetTypecheck(0) // re-typechecking new op is OK, not a loop
case ir.OCAP, ir.OCLOSE, ir.OIMAG, ir.OLEN, ir.OPANIC, ir.OREAL:
typecheckargs(n)
n = ir.NodAt(n.Pos(), l.SubOp(), arg1, arg2)
n = initExpr(old.Init().Slice(), n) // typecheckargs can add to old.Init
}
- n = typecheck1(n, top)
- return n
+ return typecheck(n, top)
}
n.SetLeft(defaultlit(n.Left(), nil))
}
// pick off before type-checking arguments
- ok |= ctxExpr
-
arg, ok := needOneArg(n, "conversion to %v", l.Type())
if !ok {
n.SetType(nil)
n = ir.NodAt(n.Pos(), ir.OCONV, arg, nil)
n.SetType(l.Type())
- n = typecheck1(n, top)
- return n
+ return typecheck1(n, top)
}
typecheckargs(n)
}
typecheckaste(ir.OCALL, n.Left(), n.IsDDD(), t.Params(), n.List(), func() string { return fmt.Sprintf("argument to %v", n.Left()) })
- ok |= ctxStmt
if t.NumResults() == 0 {
- break
+ return n
}
- ok |= ctxExpr
if t.NumResults() == 1 {
n.SetType(l.Type().Results().Field(0).Type)
// and we want to avoid the temporaries, so we do the rewrite earlier than is typical.
n.SetOp(ir.OGETG)
}
-
- break
+ return n
}
// multiple return
if top&(ctxMultiOK|ctxStmt) == 0 {
base.Errorf("multiple-value %v() in single-value context", l)
- break
+ return n
}
n.SetType(l.Type().Results())
+ return n
case ir.OALIGNOF, ir.OOFFSETOF, ir.OSIZEOF:
- ok |= ctxExpr
n.SetType(types.Types[types.TUINTPTR])
+ return n
case ir.OCAP, ir.OLEN:
- ok |= ctxExpr
n.SetLeft(typecheck(n.Left(), ctxExpr))
n.SetLeft(defaultlit(n.Left(), nil))
n.SetLeft(implicitstar(n.Left()))
}
n.SetType(types.Types[types.TINT])
+ return n
case ir.OREAL, ir.OIMAG:
- ok |= ctxExpr
n.SetLeft(typecheck(n.Left(), ctxExpr))
l := n.Left()
t := l.Type()
n.SetType(nil)
return n
}
+ return n
case ir.OCOMPLEX:
- ok |= ctxExpr
l := typecheck(n.Left(), ctxExpr)
r := typecheck(n.Right(), ctxExpr)
if l.Type() == nil || r.Type() == nil {
t = types.Types[types.TCOMPLEX128]
}
n.SetType(t)
+ return n
case ir.OCLOSE:
n.SetLeft(typecheck(n.Left(), ctxExpr))
n.SetType(nil)
return n
}
-
- ok |= ctxStmt
+ return n
case ir.ODELETE:
- ok |= ctxStmt
typecheckargs(n)
args := n.List()
if args.Len() == 0 {
}
args.SetSecond(assignconv(r, l.Type().Key(), "delete"))
+ return n
case ir.OAPPEND:
- ok |= ctxExpr
typecheckargs(n)
args := n.List()
if args.Len() == 0 {
if t.Elem().IsKind(types.TUINT8) && args.Second().Type().IsString() {
args.SetSecond(defaultlit(args.Second(), types.Types[types.TSTRING]))
- break
+ return n
}
args.SetSecond(assignconv(args.Second(), t.Underlying(), "append"))
- break
+ return n
}
as := args.Slice()[1:]
as[i] = assignconv(n, t.Elem(), "append")
checkwidth(as[i].Type()) // ensure width is calculated for backend
}
+ return n
case ir.OCOPY:
- ok |= ctxStmt | ctxExpr
n.SetType(types.Types[types.TINT])
n.SetLeft(typecheck(n.Left(), ctxExpr))
n.SetLeft(defaultlit(n.Left(), nil))
// copy([]byte, string)
if n.Left().Type().IsSlice() && n.Right().Type().IsString() {
if types.Identical(n.Left().Type().Elem(), types.ByteType) {
- break
+ return n
}
base.Errorf("arguments to copy have different element types: %L and string", n.Left().Type())
n.SetType(nil)
n.SetType(nil)
return n
}
+ return n
case ir.OCONV:
- ok |= ctxExpr
checkwidth(n.Type()) // ensure width is calculated for backend
n.SetLeft(typecheck(n.Left(), ctxExpr))
n.SetLeft(convlit1(n.Left(), n.Type(), true, nil))
// do not convert to []byte literal. See CL 125796.
// generated code and compiler memory footprint is better without it.
case ir.OSTR2BYTES:
- break
+ // ok
case ir.OSTR2RUNES:
if n.Left().Op() == ir.OLITERAL {
n = stringtoruneslit(n)
}
}
+ return n
case ir.OMAKE:
- ok |= ctxExpr
args := n.List().Slice()
if len(args) == 0 {
base.Errorf("missing argument to make")
nn.SetType(t)
n = nn
+ return n
case ir.ONEW:
- ok |= ctxExpr
if n.Left() == nil {
// Fatalf because the OCALL above checked for us,
// so this must be an internally-generated mistake.
}
n.SetLeft(l)
n.SetType(types.NewPtr(t))
+ return n
case ir.OPRINT, ir.OPRINTN:
- ok |= ctxStmt
typecheckargs(n)
ls := n.List().Slice()
for i1, n1 := range ls {
ls[i1] = defaultlit(ls[i1], nil)
}
}
+ return n
case ir.OPANIC:
- ok |= ctxStmt
n.SetLeft(typecheck(n.Left(), ctxExpr))
n.SetLeft(defaultlit(n.Left(), types.Types[types.TINTER]))
if n.Left().Type() == nil {
n.SetType(nil)
return n
}
+ return n
case ir.ORECOVER:
- ok |= ctxExpr | ctxStmt
if n.List().Len() != 0 {
base.Errorf("too many arguments to recover")
n.SetType(nil)
}
n.SetType(types.Types[types.TINTER])
+ return n
case ir.OCLOSURE:
- ok |= ctxExpr
typecheckclosure(n, top)
if n.Type() == nil {
return n
}
+ return n
case ir.OITAB:
- ok |= ctxExpr
n.SetLeft(typecheck(n.Left(), ctxExpr))
t := n.Left().Type()
if t == nil {
base.Fatalf("OITAB of %v", t)
}
n.SetType(types.NewPtr(types.Types[types.TUINTPTR]))
+ return n
case ir.OIDATA:
// Whoever creates the OIDATA node must know a priori the concrete type at that moment,
// usually by just having checked the OITAB.
base.Fatalf("cannot typecheck interface data %v", n)
+ panic("unreachable")
case ir.OSPTR:
- ok |= ctxExpr
n.SetLeft(typecheck(n.Left(), ctxExpr))
t := n.Left().Type()
if t == nil {
} else {
n.SetType(types.NewPtr(t.Elem()))
}
+ return n
case ir.OCLOSUREREAD:
- ok |= ctxExpr
+ return n
case ir.OCFUNC:
- ok |= ctxExpr
n.SetLeft(typecheck(n.Left(), ctxExpr))
n.SetType(types.Types[types.TUINTPTR])
+ return n
case ir.OCONVNOP:
- ok |= ctxExpr
n.SetLeft(typecheck(n.Left(), ctxExpr))
+ return n
// statements
case ir.OAS:
- ok |= ctxStmt
-
typecheckas(n)
// Code that creates temps does not bother to set defn, so do it here.
if n.Left().Op() == ir.ONAME && ir.IsAutoTmp(n.Left()) {
n.Left().Name().Defn = n
}
+ return n
case ir.OAS2:
- ok |= ctxStmt
typecheckas2(n)
+ return n
case ir.OBREAK,
ir.OCONTINUE,
ir.OFALL,
ir.OVARKILL,
ir.OVARLIVE:
- ok |= ctxStmt
+ return n
case ir.OBLOCK:
- ok |= ctxStmt
typecheckslice(n.List().Slice(), ctxStmt)
+ return n
case ir.OLABEL:
- ok |= ctxStmt
decldepth++
if n.Sym().IsBlank() {
// Empty identifier is valid but useless.
// See issues 7538, 11589, 11593.
n = ir.NodAt(n.Pos(), ir.OBLOCK, nil, nil)
}
+ return n
case ir.ODEFER:
- ok |= ctxStmt
n.SetLeft(typecheck(n.Left(), ctxStmt|ctxExpr))
if !n.Left().Diag() {
checkdefergo(n)
}
+ return n
case ir.OGO:
- ok |= ctxStmt
n.SetLeft(typecheck(n.Left(), ctxStmt|ctxExpr))
checkdefergo(n)
+ return n
case ir.OFOR, ir.OFORUNTIL:
- ok |= ctxStmt
typecheckslice(n.Init().Slice(), ctxStmt)
decldepth++
n.SetLeft(typecheck(n.Left(), ctxExpr))
}
typecheckslice(n.Body().Slice(), ctxStmt)
decldepth--
+ return n
case ir.OIF:
- ok |= ctxStmt
typecheckslice(n.Init().Slice(), ctxStmt)
n.SetLeft(typecheck(n.Left(), ctxExpr))
n.SetLeft(defaultlit(n.Left(), nil))
}
typecheckslice(n.Body().Slice(), ctxStmt)
typecheckslice(n.Rlist().Slice(), ctxStmt)
+ return n
case ir.ORETURN:
- ok |= ctxStmt
typecheckargs(n)
if Curfn == nil {
base.Errorf("return outside function")
}
if hasNamedResults(Curfn) && n.List().Len() == 0 {
- break
+ return n
}
typecheckaste(ir.ORETURN, nil, false, Curfn.Type().Results(), n.List(), func() string { return "return argument" })
+ return n
case ir.ORETJMP:
- ok |= ctxStmt
+ return n
case ir.OSELECT:
- ok |= ctxStmt
typecheckselect(n)
+ return n
case ir.OSWITCH:
- ok |= ctxStmt
typecheckswitch(n)
+ return n
case ir.ORANGE:
- ok |= ctxStmt
typecheckrange(n)
+ return n
case ir.OTYPESW:
base.Errorf("use of .(type) outside type switch")
return n
case ir.ODCLFUNC:
- ok |= ctxStmt
typecheckfunc(n.(*ir.Func))
+ return n
case ir.ODCLCONST:
- ok |= ctxStmt
n.SetLeft(typecheck(n.Left(), ctxExpr))
+ return n
case ir.ODCLTYPE:
- ok |= ctxStmt
n.SetLeft(typecheck(n.Left(), ctxType))
checkwidth(n.Left().Type())
- }
-
- t := n.Type()
- if t != nil && !t.IsFuncArgStruct() && n.Op() != ir.OTYPE {
- switch t.Kind() {
- case types.TFUNC, // might have TANY; wait until it's called
- types.TANY, types.TFORW, types.TIDEAL, types.TNIL, types.TBLANK:
- break
-
- default:
- checkwidth(t)
- }
- }
-
- n = evalConst(n)
- if n.Op() == ir.OTYPE && top&ctxType == 0 {
- if !n.Type().Broke() {
- base.Errorf("type %v is not an expression", n.Type())
- }
- n.SetType(nil)
return n
}
- if top&(ctxExpr|ctxType) == ctxType && n.Op() != ir.OTYPE {
- base.Errorf("%v is not a type", n)
- n.SetType(nil)
- return n
- }
-
- // TODO(rsc): simplify
- if (top&(ctxCallee|ctxExpr|ctxType) != 0) && top&ctxStmt == 0 && ok&(ctxExpr|ctxType|ctxCallee) == 0 {
- base.Errorf("%v used as value", n)
- n.SetType(nil)
- return n
- }
-
- if (top&ctxStmt != 0) && top&(ctxCallee|ctxExpr|ctxType) == 0 && ok&ctxStmt == 0 {
- if !n.Diag() {
- base.Errorf("%v evaluated but not used", n)
- n.SetDiag(true)
- }
-
- n.SetType(nil)
- return n
- }
-
- return n
+ // No return n here!
+ // Individual cases can type-assert n, introducing a new one.
+ // Each must execute its own return n.
}
func typecheckargs(n ir.Node) {