Skip to content

Commit

Permalink
compiler: fix crash on type assert on interfaces with no methods
Browse files Browse the repository at this point in the history
  • Loading branch information
dgryski authored and deadprogram committed Nov 8, 2023
1 parent 2b21595 commit 777048c
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 12 deletions.
30 changes: 18 additions & 12 deletions compiler/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -684,19 +684,25 @@ func (b *builder) createTypeAssert(expr *ssa.TypeAssert) llvm.Value {

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

if intf, ok := expr.AssertedType.Underlying().(*types.Interface); ok {
if intf.Empty() {
// intf is the empty interface => no methods
// This type assertion always succeeds, so we can just set commaOk to true.
commaOk = llvm.ConstInt(b.ctx.Int1Type(), 1, true)
} else {
// Type assert on interface type with methods.
// This is a call to an interface type assert function.
// The interface lowering pass will define this function by filling it
// with a type switch over all concrete types that implement this
// interface, and returning whether it's one of the matched types.
// This is very different from how interface asserts are implemented in
// the main Go compiler, where the runtime checks whether the type
// implements each method of the interface. See:
// https://research.swtch.com/interfaces
fn := b.getInterfaceImplementsFunc(expr.AssertedType)
commaOk = b.CreateCall(fn.GlobalValueType(), fn, []llvm.Value{actualTypeNum}, "")
}
} else {
name, _ := getTypeCodeName(expr.AssertedType)
globalName := "reflect/types.typeid:" + name
Expand Down
9 changes: 9 additions & 0 deletions testdata/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,9 @@ func main() {

// check that pointer-to-pointer type switches work
ptrptrswitch()

// check that type asserts to interfaces with no methods work
emptyintfcrash()
}

func printItf(val interface{}) {
Expand Down Expand Up @@ -334,3 +337,9 @@ func identify(itf any) {
println("other type??")
}
}

func emptyintfcrash() {
if x, ok := any(5).(any); ok {
println("x is", x.(int))
}
}
1 change: 1 addition & 0 deletions testdata/interface.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,4 @@ slept 1ms
type is int
type is *int
type is **int
x is 5

0 comments on commit 777048c

Please sign in to comment.