diff --git a/compiler.go b/compiler.go index a863d406..3a24ec61 100644 --- a/compiler.go +++ b/compiler.go @@ -2300,9 +2300,6 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) { return llvm.Value{}, errors.New("unknown slice type: " + typ.String()) } case *ssa.TypeAssert: - if !expr.CommaOk { - return llvm.Value{}, errors.New("todo: type assert without comma-ok") - } itf, err := c.parseExpr(frame, expr.X) if err != nil { return llvm.Value{}, err @@ -2404,10 +2401,18 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) { phi := c.builder.CreatePHI(assertedType, "typeassert.value") phi.AddIncoming([]llvm.Value{valueNil, valueOk}, []llvm.BasicBlock{prevBlock, okBlock}) - tuple := llvm.ConstStruct([]llvm.Value{llvm.Undef(assertedType), llvm.Undef(llvm.Int1Type())}, false) // create empty tuple - tuple = c.builder.CreateInsertValue(tuple, phi, 0, "") // insert value - tuple = c.builder.CreateInsertValue(tuple, commaOk, 1, "") // insert 'comma ok' boolean - return tuple, nil + if expr.CommaOk { + tuple := llvm.ConstStruct([]llvm.Value{llvm.Undef(assertedType), llvm.Undef(llvm.Int1Type())}, false) // create empty tuple + tuple = c.builder.CreateInsertValue(tuple, phi, 0, "") // insert value + tuple = c.builder.CreateInsertValue(tuple, commaOk, 1, "") // insert 'comma ok' boolean + return tuple, nil + } else { + // This is kind of dirty as the branch above becomes mostly useless, + // but hopefully this gets optimized away. + fn := c.mod.NamedFunction("runtime.interfaceTypeAssert") + c.builder.CreateCall(fn, []llvm.Value{commaOk}, "") + return phi, nil + } case *ssa.UnOp: return c.parseUnOp(frame, expr) default: diff --git a/src/examples/test/test.go b/src/examples/test/test.go index 4d4b83f4..eaa992d0 100644 --- a/src/examples/test/test.go +++ b/src/examples/test/test.go @@ -69,6 +69,8 @@ func main() { printItf(Number(3)) s := Stringer(thing) println("Stringer.String():", s.String()) + var itf interface{} = s + println("Stringer.(*Thing).String():", itf.(Stringer).String()) // unusual calls runFunc(hello, 5) // must be indirect to avoid obvious inlining diff --git a/src/runtime/interface.go b/src/runtime/interface.go index de279872..606d6956 100644 --- a/src/runtime/interface.go +++ b/src/runtime/interface.go @@ -134,3 +134,9 @@ func interfaceImplements(typecode, interfaceNum uint16) bool { // assert is successful. return true } + +func interfaceTypeAssert(ok bool) { + if !ok { + runtimePanic("type assert failed") + } +}