interp: add support for constant type asserts
Non-constant type asserts are not yet implemented, but should be relatively easy to add at a later time. They should result in a clear error message for now.
Этот коммит содержится в:
родитель
213a6240a1
коммит
9222bda9c6
5 изменённых файлов: 59 добавлений и 0 удалений
|
@ -440,6 +440,21 @@ func (fr *frame) evalBasicBlock(bb, incoming llvm.BasicBlock, indent string) (re
|
|||
ret = llvm.ConstInsertValue(ret, retLen, []uint32{1}) // len
|
||||
ret = llvm.ConstInsertValue(ret, retLen, []uint32{2}) // cap
|
||||
fr.locals[inst] = &LocalValue{fr.Eval, ret}
|
||||
case callee.Name() == "runtime.typeAssert":
|
||||
actualTypeInt := fr.getLocal(inst.Operand(0)).(*LocalValue).Underlying
|
||||
assertedType := fr.getLocal(inst.Operand(1)).(*LocalValue).Underlying
|
||||
if actualTypeInt.IsAConstantExpr().IsNil() || actualTypeInt.Opcode() != llvm.PtrToInt {
|
||||
return nil, nil, fr.errorAt(inst, "interp: expected typecode in runtime.typeAssert to be a ptrtoint")
|
||||
}
|
||||
actualType := actualTypeInt.Operand(0)
|
||||
if actualType.IsAConstant().IsNil() || assertedType.IsAConstant().IsNil() {
|
||||
return nil, nil, fr.errorAt(inst, "interp: unimplemented: type assert with non-constant interface value")
|
||||
}
|
||||
assertOk := uint64(0)
|
||||
if llvm.ConstExtractValue(actualType.Initializer(), []uint32{0}) == assertedType {
|
||||
assertOk = 1
|
||||
}
|
||||
fr.locals[inst] = &LocalValue{fr.Eval, llvm.ConstInt(fr.Mod.Context().Int1Type(), assertOk, false)}
|
||||
case callee.Name() == "runtime.interfaceImplements":
|
||||
typecode := fr.getLocal(inst.Operand(0)).(*LocalValue).Underlying
|
||||
interfaceMethodSet := fr.getLocal(inst.Operand(1)).(*LocalValue).Underlying
|
||||
|
|
|
@ -15,6 +15,7 @@ func TestInterp(t *testing.T) {
|
|||
"slice-copy",
|
||||
"consteval",
|
||||
"map",
|
||||
"interface",
|
||||
} {
|
||||
name := name // make tc local to this closure
|
||||
t.Run(name, func(t *testing.T) {
|
||||
|
|
28
interp/testdata/interface.ll
предоставленный
Обычный файл
28
interp/testdata/interface.ll
предоставленный
Обычный файл
|
@ -0,0 +1,28 @@
|
|||
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
||||
target triple = "x86_64--linux"
|
||||
|
||||
%runtime.typecodeID = type { %runtime.typecodeID*, i64 }
|
||||
%runtime.interfaceMethodInfo = type { i8*, i64 }
|
||||
%runtime.typeInInterface = type { %runtime.typecodeID*, %runtime.interfaceMethodInfo* }
|
||||
|
||||
@main.v1 = global i1 0
|
||||
@"reflect/types.type:named:main.foo" = private constant %runtime.typecodeID { %runtime.typecodeID* @"reflect/types.type:basic:int", i64 0 }
|
||||
@"reflect/types.type:basic:int" = external constant %runtime.typecodeID
|
||||
@"typeInInterface:reflect/types.type:named:main.foo" = private constant %runtime.typeInInterface { %runtime.typecodeID* @"reflect/types.type:named:main.foo", %runtime.interfaceMethodInfo* null }
|
||||
|
||||
|
||||
declare i1 @runtime.typeAssert(i64, %runtime.typecodeID*, i8*, i8*)
|
||||
|
||||
define void @runtime.initAll() unnamed_addr {
|
||||
entry:
|
||||
call void @main.init()
|
||||
ret void
|
||||
}
|
||||
|
||||
define internal void @main.init() unnamed_addr {
|
||||
entry:
|
||||
; Test type asserts.
|
||||
%typecode = call i1 @runtime.typeAssert(i64 ptrtoint (%runtime.typeInInterface* @"typeInInterface:reflect/types.type:named:main.foo" to i64), %runtime.typecodeID* @"reflect/types.type:named:main.foo", i8* undef, i8* null)
|
||||
store i1 %typecode, i1* @main.v1
|
||||
ret void
|
||||
}
|
9
interp/testdata/interface.out.ll
предоставленный
Обычный файл
9
interp/testdata/interface.out.ll
предоставленный
Обычный файл
|
@ -0,0 +1,9 @@
|
|||
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
||||
target triple = "x86_64--linux"
|
||||
|
||||
@main.v1 = local_unnamed_addr global i1 true
|
||||
|
||||
define void @runtime.initAll() unnamed_addr {
|
||||
entry:
|
||||
ret void
|
||||
}
|
6
testdata/interface.go
предоставленный
6
testdata/interface.go
предоставленный
|
@ -137,6 +137,12 @@ func printItf(val interface{}) {
|
|||
}
|
||||
}
|
||||
|
||||
var (
|
||||
// Test for type assert support in the interp package.
|
||||
globalThing interface{} = Foo(3)
|
||||
_ = globalThing.(Foo)
|
||||
)
|
||||
|
||||
func nestedSwitch(verb rune, arg interface{}) bool {
|
||||
switch verb {
|
||||
case 'v', 's':
|
||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче