Skip to content

Commit a8919c0

Browse files
aykevlQuLogic
authored andcommitted
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.
1 parent 7601d94 commit a8919c0

File tree

5 files changed

+59
-0
lines changed

5 files changed

+59
-0
lines changed

interp/frame.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,21 @@ func (fr *frame) evalBasicBlock(bb, incoming llvm.BasicBlock, indent string) (re
440440
ret = llvm.ConstInsertValue(ret, retLen, []uint32{1}) // len
441441
ret = llvm.ConstInsertValue(ret, retLen, []uint32{2}) // cap
442442
fr.locals[inst] = &LocalValue{fr.Eval, ret}
443+
case callee.Name() == "runtime.typeAssert":
444+
actualTypeInt := fr.getLocal(inst.Operand(0)).(*LocalValue).Underlying
445+
assertedType := fr.getLocal(inst.Operand(1)).(*LocalValue).Underlying
446+
if actualTypeInt.IsAConstantExpr().IsNil() || actualTypeInt.Opcode() != llvm.PtrToInt {
447+
return nil, nil, fr.errorAt(inst, "interp: expected typecode in runtime.typeAssert to be a ptrtoint")
448+
}
449+
actualType := actualTypeInt.Operand(0)
450+
if actualType.IsAConstant().IsNil() || assertedType.IsAConstant().IsNil() {
451+
return nil, nil, fr.errorAt(inst, "interp: unimplemented: type assert with non-constant interface value")
452+
}
453+
assertOk := uint64(0)
454+
if llvm.ConstExtractValue(actualType.Initializer(), []uint32{0}) == assertedType {
455+
assertOk = 1
456+
}
457+
fr.locals[inst] = &LocalValue{fr.Eval, llvm.ConstInt(fr.Mod.Context().Int1Type(), assertOk, false)}
443458
case callee.Name() == "runtime.interfaceImplements":
444459
typecode := fr.getLocal(inst.Operand(0)).(*LocalValue).Underlying
445460
interfaceMethodSet := fr.getLocal(inst.Operand(1)).(*LocalValue).Underlying

interp/interp_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ func TestInterp(t *testing.T) {
1515
"slice-copy",
1616
"consteval",
1717
"map",
18+
"interface",
1819
} {
1920
name := name // make tc local to this closure
2021
t.Run(name, func(t *testing.T) {

interp/testdata/interface.ll

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
2+
target triple = "x86_64--linux"
3+
4+
%runtime.typecodeID = type { %runtime.typecodeID*, i64 }
5+
%runtime.interfaceMethodInfo = type { i8*, i64 }
6+
%runtime.typeInInterface = type { %runtime.typecodeID*, %runtime.interfaceMethodInfo* }
7+
8+
@main.v1 = global i1 0
9+
@"reflect/types.type:named:main.foo" = private constant %runtime.typecodeID { %runtime.typecodeID* @"reflect/types.type:basic:int", i64 0 }
10+
@"reflect/types.type:basic:int" = external constant %runtime.typecodeID
11+
@"typeInInterface:reflect/types.type:named:main.foo" = private constant %runtime.typeInInterface { %runtime.typecodeID* @"reflect/types.type:named:main.foo", %runtime.interfaceMethodInfo* null }
12+
13+
14+
declare i1 @runtime.typeAssert(i64, %runtime.typecodeID*, i8*, i8*)
15+
16+
define void @runtime.initAll() unnamed_addr {
17+
entry:
18+
call void @main.init()
19+
ret void
20+
}
21+
22+
define internal void @main.init() unnamed_addr {
23+
entry:
24+
; Test type asserts.
25+
%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)
26+
store i1 %typecode, i1* @main.v1
27+
ret void
28+
}

interp/testdata/interface.out.ll

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
2+
target triple = "x86_64--linux"
3+
4+
@main.v1 = local_unnamed_addr global i1 true
5+
6+
define void @runtime.initAll() unnamed_addr {
7+
entry:
8+
ret void
9+
}

testdata/interface.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,12 @@ func printItf(val interface{}) {
137137
}
138138
}
139139

140+
var (
141+
// Test for type assert support in the interp package.
142+
globalThing interface{} = Foo(3)
143+
_ = globalThing.(Foo)
144+
)
145+
140146
func nestedSwitch(verb rune, arg interface{}) bool {
141147
switch verb {
142148
case 'v', 's':

0 commit comments

Comments
 (0)