go.tools/ssa: fix bug in code emitted for ast.TypeAssertExpr.
var x I = ... x.(E) may fail dynamically (iff x is nil). Added a testcase. R=gri CC=golang-dev https://golang.org/cl/10237045
This commit is contained in:
parent
3162ce0df2
commit
0f26bbae8f
|
|
@ -247,9 +247,8 @@ func emitTypeAssert(f *Function, x Value, t types.Type, pos token.Pos) Value {
|
|||
// Simplify infallible assertions.
|
||||
txi := x.Type().Underlying().(*types.Interface)
|
||||
if ti, ok := t.Underlying().(*types.Interface); ok {
|
||||
if types.IsIdentical(ti, txi) {
|
||||
return x
|
||||
}
|
||||
// Even when ti==txi, we still need ChangeInterface
|
||||
// since it performs a nil-check.
|
||||
if isSuperinterface(ti, txi) {
|
||||
c := &ChangeInterface{X: x}
|
||||
c.setPos(pos)
|
||||
|
|
|
|||
|
|
@ -161,7 +161,11 @@ func visitInstr(fr *frame, instr ssa.Instruction) continuation {
|
|||
fr.env[instr] = call(fr.i, fr, instr.Pos(), fn, args)
|
||||
|
||||
case *ssa.ChangeInterface:
|
||||
fr.env[instr] = fr.get(instr.X) // (can't fail)
|
||||
x := fr.get(instr.X)
|
||||
if x.(iface).t == nil {
|
||||
panic(fmt.Sprintf("interface conversion: interface is nil, not %s", instr.Type()))
|
||||
}
|
||||
fr.env[instr] = x
|
||||
|
||||
case *ssa.ChangeType:
|
||||
fr.env[instr] = fr.get(instr.X) // (can't fail)
|
||||
|
|
|
|||
|
|
@ -329,6 +329,26 @@ func init() {
|
|||
}
|
||||
}
|
||||
|
||||
// An I->I conversion always succeeds.
|
||||
func init() {
|
||||
var x I
|
||||
if I(x) != I(nil) {
|
||||
panic("I->I conversion failed")
|
||||
}
|
||||
}
|
||||
|
||||
// An I->I type-assert fails iff the value is nil.
|
||||
func init() {
|
||||
defer func() {
|
||||
r := recover()
|
||||
if r != "interface conversion: interface is nil, not main.I" {
|
||||
panic("I->I type assertion succeeed for nil value")
|
||||
}
|
||||
}()
|
||||
var x I
|
||||
_ = x.(I)
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Variadic bridge methods and interface thunks.
|
||||
|
||||
|
|
|
|||
|
|
@ -588,16 +588,15 @@ type Convert struct {
|
|||
// ChangeInterface constructs a value of one interface type from a
|
||||
// value of another interface type known to be assignable to it.
|
||||
//
|
||||
// This operation cannot fail. Use TypeAssert for interface
|
||||
// conversions that may fail dynamically.
|
||||
// This operation fails if the operand is nil.
|
||||
// For all other operands, well-typedness ensures success.
|
||||
// Use TypeAssert for interface conversions that are uncertain.
|
||||
//
|
||||
// Pos() returns the ast.CallExpr.Lparen if the instruction arose from
|
||||
// an explicit T(e) conversion; the ast.TypeAssertExpr.Lparen if the
|
||||
// instruction arose from an explicit e.(T) operation; or token.NoPos
|
||||
// otherwise.
|
||||
//
|
||||
// TODO(adonovan) what about the nil case of e = e.(E)? Test.
|
||||
//
|
||||
// Example printed form:
|
||||
// t1 = change interface interface{} <- I (t0)
|
||||
//
|
||||
|
|
|
|||
Loading…
Reference in New Issue