Skip to content

Commit 777048c

Browse files
dgryskideadprogram
authored andcommitted
compiler: fix crash on type assert on interfaces with no methods
1 parent 2b21595 commit 777048c

File tree

3 files changed

+28
-12
lines changed

3 files changed

+28
-12
lines changed

compiler/interface.go

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -684,19 +684,25 @@ func (b *builder) createTypeAssert(expr *ssa.TypeAssert) llvm.Value {
684684

685685
actualTypeNum := b.CreateExtractValue(itf, 0, "interface.type")
686686
commaOk := llvm.Value{}
687-
if _, ok := expr.AssertedType.Underlying().(*types.Interface); ok {
688-
// Type assert on interface type.
689-
// This is a call to an interface type assert function.
690-
// The interface lowering pass will define this function by filling it
691-
// with a type switch over all concrete types that implement this
692-
// interface, and returning whether it's one of the matched types.
693-
// This is very different from how interface asserts are implemented in
694-
// the main Go compiler, where the runtime checks whether the type
695-
// implements each method of the interface. See:
696-
// https://research.swtch.com/interfaces
697-
fn := b.getInterfaceImplementsFunc(expr.AssertedType)
698-
commaOk = b.CreateCall(fn.GlobalValueType(), fn, []llvm.Value{actualTypeNum}, "")
699687

688+
if intf, ok := expr.AssertedType.Underlying().(*types.Interface); ok {
689+
if intf.Empty() {
690+
// intf is the empty interface => no methods
691+
// This type assertion always succeeds, so we can just set commaOk to true.
692+
commaOk = llvm.ConstInt(b.ctx.Int1Type(), 1, true)
693+
} else {
694+
// Type assert on interface type with methods.
695+
// This is a call to an interface type assert function.
696+
// The interface lowering pass will define this function by filling it
697+
// with a type switch over all concrete types that implement this
698+
// interface, and returning whether it's one of the matched types.
699+
// This is very different from how interface asserts are implemented in
700+
// the main Go compiler, where the runtime checks whether the type
701+
// implements each method of the interface. See:
702+
// https://research.swtch.com/interfaces
703+
fn := b.getInterfaceImplementsFunc(expr.AssertedType)
704+
commaOk = b.CreateCall(fn.GlobalValueType(), fn, []llvm.Value{actualTypeNum}, "")
705+
}
700706
} else {
701707
name, _ := getTypeCodeName(expr.AssertedType)
702708
globalName := "reflect/types.typeid:" + name

testdata/interface.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,9 @@ func main() {
116116

117117
// check that pointer-to-pointer type switches work
118118
ptrptrswitch()
119+
120+
// check that type asserts to interfaces with no methods work
121+
emptyintfcrash()
119122
}
120123

121124
func printItf(val interface{}) {
@@ -334,3 +337,9 @@ func identify(itf any) {
334337
println("other type??")
335338
}
336339
}
340+
341+
func emptyintfcrash() {
342+
if x, ok := any(5).(any); ok {
343+
println("x is", x.(int))
344+
}
345+
}

testdata/interface.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,4 @@ slept 1ms
2727
type is int
2828
type is *int
2929
type is **int
30+
x is 5

0 commit comments

Comments
 (0)