diff --git a/ssa/builder.go b/ssa/builder.go index 7b288712..cf7dd07e 100644 --- a/ssa/builder.go +++ b/ssa/builder.go @@ -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()) } diff --git a/ssa/interp/testdata/coverage.go b/ssa/interp/testdata/coverage.go index 2d0e5bb4..e9dc3d16 100644 --- a/ssa/interp/testdata/coverage.go +++ b/ssa/interp/testdata/coverage.go @@ -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") } diff --git a/ssa/ssadump.go b/ssa/ssadump.go index a6cc5563..c41bdb06 100644 --- a/ssa/ssadump.go +++ b/ssa/ssadump.go @@ -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)