blob: 922a01bfbe9aa7d6dea6ab34e03e5955ef883105 [file] [log] [blame]
// 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 (
"cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/compile/internal/types"
"cmd/internal/src"
)
func RangeExprType(t *types.Type) *types.Type {
if t.IsPtr() && t.Elem().IsArray() {
return t.Elem()
}
return t
}
func typecheckrangeExpr(n *ir.RangeStmt) {
n.X = Expr(n.X)
if n.X.Type() == nil {
return
}
t := RangeExprType(n.X.Type())
// delicate little dance. see tcAssignList
if n.Key != nil && !ir.DeclaredBy(n.Key, n) {
n.Key = AssignExpr(n.Key)
}
if n.Value != nil && !ir.DeclaredBy(n.Value, n) {
n.Value = AssignExpr(n.Value)
}
var tk, tv *types.Type
toomany := false
switch t.Kind() {
default:
base.ErrorfAt(n.Pos(), "cannot range over %L", n.X)
return
case types.TARRAY, types.TSLICE:
tk = types.Types[types.TINT]
tv = t.Elem()
case types.TMAP:
tk = t.Key()
tv = t.Elem()
case types.TCHAN:
if !t.ChanDir().CanRecv() {
base.ErrorfAt(n.Pos(), "invalid operation: range %v (receive from send-only type %v)", n.X, n.X.Type())
return
}
tk = t.Elem()
tv = nil
if n.Value != nil {
toomany = true
}
case types.TSTRING:
tk = types.Types[types.TINT]
tv = types.RuneType
}
if toomany {
base.ErrorfAt(n.Pos(), "too many variables in range")
}
do := func(nn ir.Node, t *types.Type) {
if nn != nil {
if ir.DeclaredBy(nn, n) {
nn.SetType(t)
} else if nn.Type() != nil {
if op, why := Assignop(t, nn.Type()); op == ir.OXXX {
base.ErrorfAt(n.Pos(), "cannot assign type %v to %L in range%s", t, nn, why)
}
}
checkassign(n, nn)
}
}
do(n.Key, tk)
do(n.Value, tv)
}
// 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("tcAssign", n)(nil)
}
if n.Y == nil {
n.X = AssignExpr(n.X)
return
}
lhs, rhs := []ir.Node{n.X}, []ir.Node{n.Y}
assign(n, lhs, rhs)
n.X, n.Y = lhs[0], rhs[0]
// TODO(mdempsky): This seems out of place.
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("tcAssignList", n)(nil)
}
assign(n, n.Lhs, n.Rhs)
}
func assign(stmt ir.Node, lhs, rhs []ir.Node) {
// delicate little dance.
// the definition of lhs may refer to this assignment
// as its definition, in which case it will call tcAssign.
// 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).
checkLHS := func(i int, typ *types.Type) {
lhs[i] = Resolve(lhs[i])
if n := lhs[i]; typ != nil && ir.DeclaredBy(n, stmt) && n.Name().Ntype == nil {
if typ.Kind() != types.TNIL {
n.SetType(defaultType(typ))
} else {
base.Errorf("use of untyped nil")
}
}
if lhs[i].Typecheck() == 0 {
lhs[i] = AssignExpr(lhs[i])
}
checkassign(stmt, lhs[i])
}
assignType := func(i int, typ *types.Type) {
checkLHS(i, typ)
if typ != nil {
checkassignto(typ, lhs[i])
}
}
cr := len(rhs)
if len(rhs) == 1 {
rhs[0] = typecheck(rhs[0], ctxExpr|ctxMultiOK)
if rtyp := rhs[0].Type(); rtyp != nil && rtyp.IsFuncArgStruct() {
cr = rtyp.NumFields()
}
} else {
Exprs(rhs)
}
// x, ok = y
assignOK:
for len(lhs) == 2 && cr == 1 {
stmt := stmt.(*ir.AssignListStmt)
r := rhs[0]
switch r.Op() {
case ir.OINDEXMAP:
stmt.SetOp(ir.OAS2MAPR)
case ir.ORECV:
stmt.SetOp(ir.OAS2RECV)
case ir.ODOTTYPE:
r := r.(*ir.TypeAssertExpr)
stmt.SetOp(ir.OAS2DOTTYPE)
r.SetOp(ir.ODOTTYPE2)
default:
break assignOK
}
assignType(0, r.Type())
assignType(1, types.UntypedBool)
return
}
if len(lhs) != cr {
if r, ok := rhs[0].(*ir.CallExpr); ok && len(rhs) == 1 {
if r.Type() != nil {
base.ErrorfAt(stmt.Pos(), "assignment mismatch: %d variable%s but %v returns %d value%s", len(lhs), plural(len(lhs)), r.X, cr, plural(cr))
}
} else {
base.ErrorfAt(stmt.Pos(), "assignment mismatch: %d variable%s but %v value%s", len(lhs), plural(len(lhs)), len(rhs), plural(len(rhs)))
}
for i := range lhs {
checkLHS(i, nil)
}
return
}
// x,y,z = f()
if cr > len(rhs) {
stmt := stmt.(*ir.AssignListStmt)
stmt.SetOp(ir.OAS2FUNC)
r := rhs[0].(*ir.CallExpr)
r.Use = ir.CallUseList
rtyp := r.Type()
mismatched := false
failed := false
for i := range lhs {
result := rtyp.Field(i).Type
assignType(i, result)
if lhs[i].Type() == nil || result == nil {
failed = true
} else if lhs[i] != ir.BlankNode && !types.Identical(lhs[i].Type(), result) {
mismatched = true
}
}
if mismatched && !failed {
rewriteMultiValueCall(stmt, r)
}
return
}
for i, r := range rhs {
checkLHS(i, r.Type())
if lhs[i].Type() != nil {
rhs[i] = AssignConv(r, lhs[i].Type(), "assignment")
}
}
}
func plural(n int) string {
if n == 1 {
return ""
}
return "s"
}
// tcFor typechecks an OFOR node.
func tcFor(n *ir.ForStmt) 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 for condition", n.Cond)
}
}
n.Post = Stmt(n.Post)
if n.Op() == ir.OFORUNTIL {
Stmts(n.Late)
}
Stmts(n.Body)
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)
if n.Key != nil && n.Key.Typecheck() == 0 {
n.Key = AssignExpr(n.Key)
}
if n.Value != nil && n.Value.Typecheck() == 0 {
n.Value = AssignExpr(n.Value)
}
Stmts(n.Body)
}
// 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 tcSelect(sel *ir.SelectStmt) {
var def *ir.CommClause
lno := ir.SetPos(sel)
Stmts(sel.Init())
for _, ncase := range sel.Cases {
if ncase.Comm == nil {
// default
if def != nil {
base.ErrorfAt(ncase.Pos(), "multiple defaults in select (first at %v)", ir.Line(def))
} else {
def = ncase
}
} else {
n := Stmt(ncase.Comm)
ncase.Comm = n
oselrecv2 := func(dst, recv ir.Node, def bool) {
n := ir.NewAssignListStmt(n.Pos(), ir.OSELRECV2, []ir.Node{dst, ir.BlankNode}, []ir.Node{recv})
n.Def = def
n.SetTypecheck(1)
ncase.Comm = n
}
switch n.Op() {
default:
pos := n.Pos()
if n.Op() == ir.ONAME {
// We don't have the right position for ONAME nodes (see #15459 and
// others). Using ncase.Pos for now as it will provide the correct
// line number (assuming the expression follows the "case" keyword
// on the same line). This matches the approach before 1.10.
pos = ncase.Pos()
}
base.ErrorfAt(pos, "select case must be receive, send or assign recv")
case ir.OAS:
// convert x = <-c into x, _ = <-c
// remove implicit conversions; the eventual assignment
// will reintroduce them.
n := n.(*ir.AssignStmt)
if r := n.Y; r.Op() == ir.OCONVNOP || r.Op() == ir.OCONVIFACE {
r := r.(*ir.ConvExpr)
if r.Implicit() {
n.Y = r.X
}
}
if n.Y.Op() != ir.ORECV {
base.ErrorfAt(n.Pos(), "select assignment must have receive on right hand side")
break
}
oselrecv2(n.X, n.Y, n.Def)
case ir.OAS2RECV:
n := n.(*ir.AssignListStmt)
if n.Rhs[0].Op() != ir.ORECV {
base.ErrorfAt(n.Pos(), "select assignment must have receive on right hand side")
break
}
n.SetOp(ir.OSELRECV2)
case ir.ORECV:
// convert <-c into _, _ = <-c
n := n.(*ir.UnaryExpr)
oselrecv2(ir.BlankNode, n, false)
case ir.OSEND:
break
}
}
Stmts(ncase.Body)
}
base.Pos = lno
}
// 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
}
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
}
// 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 tcSwitchExpr(n *ir.SwitchStmt) {
t := types.Types[types.TBOOL]
if n.Tag != nil {
n.Tag = Expr(n.Tag)
n.Tag = DefaultLit(n.Tag, nil)
t = n.Tag.Type()
}
var nilonly string
if t != nil {
switch {
case t.IsMap():
nilonly = "map"
case t.Kind() == types.TFUNC:
nilonly = "func"
case t.IsSlice():
nilonly = "slice"
case !types.IsComparable(t):
if t.IsStruct() {
base.ErrorfAt(n.Pos(), "cannot switch on %L (struct containing %v cannot be compared)", n.Tag, types.IncomparableField(t).Type)
} else {
base.ErrorfAt(n.Pos(), "cannot switch on %L", n.Tag)
}
t = nil
}
}
var defCase ir.Node
var cs constSet
for _, ncase := range n.Cases {
ls := ncase.List
if len(ls) == 0 { // default:
if defCase != nil {
base.ErrorfAt(ncase.Pos(), "multiple defaults in switch (first at %v)", ir.Line(defCase))
} else {
defCase = ncase
}
}
for i := range ls {
ir.SetPos(ncase)
ls[i] = Expr(ls[i])
ls[i] = DefaultLit(ls[i], t)
n1 := ls[i]
if t == nil || n1.Type() == nil {
continue
}
if nilonly != "" && !ir.IsNil(n1) {
base.ErrorfAt(ncase.Pos(), "invalid case %v in switch (can only compare %s %v to nil)", n1, nilonly, n.Tag)
} else if t.IsInterface() && !n1.Type().IsInterface() && !types.IsComparable(n1.Type()) {
base.ErrorfAt(ncase.Pos(), "invalid case %L in switch (incomparable type)", n1)
} else {
op1, _ := Assignop(n1.Type(), t)
op2, _ := Assignop(t, n1.Type())
if op1 == ir.OXXX && op2 == ir.OXXX {
if n.Tag != nil {
base.ErrorfAt(ncase.Pos(), "invalid case %v in switch on %v (mismatched types %v and %v)", n1, n.Tag, n1.Type(), t)
} else {
base.ErrorfAt(ncase.Pos(), "invalid case %v in switch (mismatched types %v and bool)", n1, n1.Type())
}
}
}
// Don't check for duplicate bools. Although the spec allows it,
// (1) the compiler hasn't checked it in the past, so compatibility mandates it, and
// (2) it would disallow useful things like
// case GOARCH == "arm" && GOARM == "5":
// case GOARCH == "arm":
// which would both evaluate to false for non-ARM compiles.
if !n1.Type().IsBoolean() {
cs.add(ncase.Pos(), n1, "case", "switch")
}
}
Stmts(ncase.Body)
}
}
func tcSwitchType(n *ir.SwitchStmt) {
guard := n.Tag.(*ir.TypeSwitchGuard)
guard.X = Expr(guard.X)
t := guard.X.Type()
if t != nil && !t.IsInterface() {
base.ErrorfAt(n.Pos(), "cannot type switch on non-interface value %L", guard.X)
t = nil
}
// We don't actually declare the type switch's guarded
// declaration itself. So if there are no cases, we won't
// notice that it went unused.
if v := guard.Tag; v != nil && !ir.IsBlank(v) && len(n.Cases) == 0 {
base.ErrorfAt(v.Pos(), "%v declared but not used", v.Sym())
}
var defCase, nilCase ir.Node
var ts typeSet
for _, ncase := range n.Cases {
ls := ncase.List
if len(ls) == 0 { // default:
if defCase != nil {
base.ErrorfAt(ncase.Pos(), "multiple defaults in switch (first at %v)", ir.Line(defCase))
} else {
defCase = ncase
}
}
for i := range ls {
ls[i] = typecheck(ls[i], ctxExpr|ctxType)
n1 := ls[i]
if t == nil || n1.Type() == nil {
continue
}
var missing, have *types.Field
var ptr int
if ir.IsNil(n1) { // case nil:
if nilCase != nil {
base.ErrorfAt(ncase.Pos(), "multiple nil cases in type switch (first at %v)", ir.Line(nilCase))
} else {
nilCase = ncase
}
continue
}
if n1.Op() != ir.OTYPE {
base.ErrorfAt(ncase.Pos(), "%L is not a type", n1)
continue
}
if !n1.Type().IsInterface() && !implements(n1.Type(), t, &missing, &have, &ptr) && !missing.Broke() {
if have != nil && !have.Broke() {
base.ErrorfAt(ncase.Pos(), "impossible type switch case: %L cannot have dynamic type %v"+
" (wrong type for %v method)\n\thave %v%S\n\twant %v%S", guard.X, n1.Type(), missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type)
} else if ptr != 0 {
base.ErrorfAt(ncase.Pos(), "impossible type switch case: %L cannot have dynamic type %v"+
" (%v method has pointer receiver)", guard.X, n1.Type(), missing.Sym)
} else {
base.ErrorfAt(ncase.Pos(), "impossible type switch case: %L cannot have dynamic type %v"+
" (missing %v method)", guard.X, n1.Type(), missing.Sym)
}
continue
}
ts.add(ncase.Pos(), n1.Type())
}
if ncase.Var != nil {
// Assign the clause variable's type.
vt := t
if len(ls) == 1 {
if ls[0].Op() == ir.OTYPE {
vt = ls[0].Type()
} else if !ir.IsNil(ls[0]) {
// Invalid single-type case;
// mark variable as broken.
vt = nil
}
}
nvar := ncase.Var
nvar.SetType(vt)
if vt != nil {
nvar = AssignExpr(nvar).(*ir.Name)
} else {
// Clause variable is broken; prevent typechecking.
nvar.SetTypecheck(1)
nvar.SetWalkdef(1)
}
ncase.Var = nvar
}
Stmts(ncase.Body)
}
}
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})
}