compiler: implement type assert without comma-ok
Этот коммит содержится в:
родитель
31e0662856
коммит
8675025fc8
3 изменённых файлов: 20 добавлений и 7 удалений
11
compiler.go
11
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())
|
return llvm.Value{}, errors.New("unknown slice type: " + typ.String())
|
||||||
}
|
}
|
||||||
case *ssa.TypeAssert:
|
case *ssa.TypeAssert:
|
||||||
if !expr.CommaOk {
|
|
||||||
return llvm.Value{}, errors.New("todo: type assert without comma-ok")
|
|
||||||
}
|
|
||||||
itf, err := c.parseExpr(frame, expr.X)
|
itf, err := c.parseExpr(frame, expr.X)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return llvm.Value{}, err
|
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 := c.builder.CreatePHI(assertedType, "typeassert.value")
|
||||||
phi.AddIncoming([]llvm.Value{valueNil, valueOk}, []llvm.BasicBlock{prevBlock, okBlock})
|
phi.AddIncoming([]llvm.Value{valueNil, valueOk}, []llvm.BasicBlock{prevBlock, okBlock})
|
||||||
|
|
||||||
|
if expr.CommaOk {
|
||||||
tuple := llvm.ConstStruct([]llvm.Value{llvm.Undef(assertedType), llvm.Undef(llvm.Int1Type())}, false) // create empty tuple
|
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, phi, 0, "") // insert value
|
||||||
tuple = c.builder.CreateInsertValue(tuple, commaOk, 1, "") // insert 'comma ok' boolean
|
tuple = c.builder.CreateInsertValue(tuple, commaOk, 1, "") // insert 'comma ok' boolean
|
||||||
return tuple, nil
|
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:
|
case *ssa.UnOp:
|
||||||
return c.parseUnOp(frame, expr)
|
return c.parseUnOp(frame, expr)
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -69,6 +69,8 @@ func main() {
|
||||||
printItf(Number(3))
|
printItf(Number(3))
|
||||||
s := Stringer(thing)
|
s := Stringer(thing)
|
||||||
println("Stringer.String():", s.String())
|
println("Stringer.String():", s.String())
|
||||||
|
var itf interface{} = s
|
||||||
|
println("Stringer.(*Thing).String():", itf.(Stringer).String())
|
||||||
|
|
||||||
// unusual calls
|
// unusual calls
|
||||||
runFunc(hello, 5) // must be indirect to avoid obvious inlining
|
runFunc(hello, 5) // must be indirect to avoid obvious inlining
|
||||||
|
|
|
@ -134,3 +134,9 @@ func interfaceImplements(typecode, interfaceNum uint16) bool {
|
||||||
// assert is successful.
|
// assert is successful.
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func interfaceTypeAssert(ok bool) {
|
||||||
|
if !ok {
|
||||||
|
runtimePanic("type assert failed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче