1
0
mirror of https://github.com/golang/go synced 2024-11-18 16:14:46 -07:00

go.tools/ssa: preserve type of &&/|| operands in result.

+ test.

With this change, the Go Oracle is now self-aware. :)

R=gri, rsc
CC=golang-dev
https://golang.org/cl/12381043
This commit is contained in:
Alan Donovan 2013-08-19 12:50:40 -04:00
parent 41a15a3013
commit 3b53279d8f
3 changed files with 32 additions and 6 deletions

View File

@ -146,14 +146,19 @@ func (b *builder) logicalBinop(fn *Function, e *ast.BinaryExpr) Value {
rhs := fn.newBasicBlock("binop.rhs")
done := fn.newBasicBlock("binop.done")
// T(e) = T(e.X) = T(e.Y) after untyped constants have been
// eliminated.
t := fn.Pkg.typeOf(e)
var short Value // value of the short-circuit path
switch e.Op {
case token.LAND:
b.cond(fn, e.X, rhs, done)
short = vFalse
short = NewConst(exact.MakeBool(false), t)
case token.LOR:
b.cond(fn, e.X, done, rhs)
short = vTrue
short = NewConst(exact.MakeBool(true), t)
}
// Is rhs unreachable?
@ -184,7 +189,7 @@ func (b *builder) logicalBinop(fn *Function, e *ast.BinaryExpr) Value {
phi := &Phi{Edges: edges, Comment: e.Op.String()}
phi.pos = e.OpPos
phi.typ = phi.Edges[0].Type()
phi.typ = t
return done.emit(phi)
}
@ -433,6 +438,8 @@ func (b *builder) addr(fn *Function, e ast.Expr, escaping bool) lvalue {
return &address{addr: fn.emit(v), expr: e}
case *ast.StarExpr:
// TODO(adonovan): fix: implement nil-check if e.X
// evaluates to nil, per http://golang.org/s/go12nil.
return &address{addr: b.expr(fn, e.X), starPos: e.Star, expr: e}
}
@ -580,7 +587,9 @@ func (b *builder) expr(fn *Function, e ast.Expr) (result Value) {
return emitArith(fn, e.Op, b.expr(fn, e.X), b.expr(fn, e.Y), fn.Pkg.typeOf(e), e.OpPos)
case token.EQL, token.NEQ, token.GTR, token.LSS, token.LEQ, token.GEQ:
return emitCompare(fn, e.Op, b.expr(fn, e.X), b.expr(fn, e.Y), e.OpPos)
// TODO(gri): we shouldn't need DefaultType here.
cmp := emitCompare(fn, e.Op, b.expr(fn, e.X), b.expr(fn, e.Y), e.OpPos)
return emitConv(fn, cmp, DefaultType(fn.Pkg.typeOf(e)))
default:
panic("illegal op in BinaryExpr: " + e.Op.String())
}

View File

@ -188,6 +188,8 @@ func main() {
case anint = <-ch:
default:
}
_ = anint
_ = ok
// Anon structs with methods.
anon := struct{ T }{T: T{z: 1}}
@ -275,6 +277,19 @@ type mybool bool
func (mybool) f() {}
func init() {
type mybool bool
var b mybool
var i interface{} = b || b // result preserves types of operands
_ = i.(mybool)
i = false && b // result preserves type of "typed" operand
_ = i.(mybool)
i = b || true // result preserves type of "typed" operand
_ = i.(mybool)
}
func init() {
var x, y int
var b mybool = x == y // x==y is an untyped bool
@ -359,7 +374,7 @@ func init() {
// An I->I type-assert fails iff the value is nil.
func init() {
defer func() {
r := recover()
r := fmt.Sprint(recover())
if r != "interface conversion: interface is nil, not main.I" {
panic("I->I type assertion succeeed for nil value")
}

View File

@ -19,7 +19,7 @@ import (
var buildFlag = flag.String("build", "", `Options controlling the SSA builder.
The value is a sequence of zero or more of these letters:
C perform sanity [C]hecking of the SSA form.
D include debug info for every function.
D include [D]ebug info for every function.
P log [P]ackage inventory.
F log [F]unction SSA code.
S log [S]ource locations as SSA builder progresses.
@ -120,6 +120,8 @@ func main() {
}
prog.BuildAll()
prog.Package(info.Pkg).CreateTestMainFunction() // FIXME
// Run the interpreter.
if *runFlag {
interp.Interpret(prog.Package(info.Pkg), interpMode, info.Pkg.Path(), args)