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.
|
// Simplify infallible assertions.
|
||||||
txi := x.Type().Underlying().(*types.Interface)
|
txi := x.Type().Underlying().(*types.Interface)
|
||||||
if ti, ok := t.Underlying().(*types.Interface); ok {
|
if ti, ok := t.Underlying().(*types.Interface); ok {
|
||||||
if types.IsIdentical(ti, txi) {
|
// Even when ti==txi, we still need ChangeInterface
|
||||||
return x
|
// since it performs a nil-check.
|
||||||
}
|
|
||||||
if isSuperinterface(ti, txi) {
|
if isSuperinterface(ti, txi) {
|
||||||
c := &ChangeInterface{X: x}
|
c := &ChangeInterface{X: x}
|
||||||
c.setPos(pos)
|
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)
|
fr.env[instr] = call(fr.i, fr, instr.Pos(), fn, args)
|
||||||
|
|
||||||
case *ssa.ChangeInterface:
|
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:
|
case *ssa.ChangeType:
|
||||||
fr.env[instr] = fr.get(instr.X) // (can't fail)
|
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.
|
// Variadic bridge methods and interface thunks.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -588,16 +588,15 @@ type Convert struct {
|
||||||
// ChangeInterface constructs a value of one interface type from a
|
// ChangeInterface constructs a value of one interface type from a
|
||||||
// value of another interface type known to be assignable to it.
|
// value of another interface type known to be assignable to it.
|
||||||
//
|
//
|
||||||
// This operation cannot fail. Use TypeAssert for interface
|
// This operation fails if the operand is nil.
|
||||||
// conversions that may fail dynamically.
|
// 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
|
// Pos() returns the ast.CallExpr.Lparen if the instruction arose from
|
||||||
// an explicit T(e) conversion; the ast.TypeAssertExpr.Lparen if the
|
// an explicit T(e) conversion; the ast.TypeAssertExpr.Lparen if the
|
||||||
// instruction arose from an explicit e.(T) operation; or token.NoPos
|
// instruction arose from an explicit e.(T) operation; or token.NoPos
|
||||||
// otherwise.
|
// otherwise.
|
||||||
//
|
//
|
||||||
// TODO(adonovan) what about the nil case of e = e.(E)? Test.
|
|
||||||
//
|
|
||||||
// Example printed form:
|
// Example printed form:
|
||||||
// t1 = change interface interface{} <- I (t0)
|
// t1 = change interface interface{} <- I (t0)
|
||||||
//
|
//
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue