Skip to content

Commit 0596b3c

Browse files
aykevldeadprogram
authored andcommitted
compiler: add support for anonymous type asserts
This is used for example by the errors package, which contains: if x, ok := err.(interface{ As(interface{}) bool }); ok && x.As(target) { return true } The interface here is not a named type.
1 parent cc4a4c7 commit 0596b3c

File tree

3 files changed

+14
-5
lines changed

3 files changed

+14
-5
lines changed

compiler/interface.go

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -271,8 +271,13 @@ func (c *compilerContext) getTypeMethodSet(typ types.Type) llvm.Value {
271271
// getInterfaceMethodSet returns a global variable with the method set of the
272272
// given named interface type. This method set is used by the interface lowering
273273
// pass.
274-
func (c *compilerContext) getInterfaceMethodSet(typ *types.Named) llvm.Value {
275-
global := c.mod.NamedGlobal(typ.String() + "$interface")
274+
func (c *compilerContext) getInterfaceMethodSet(typ types.Type) llvm.Value {
275+
name := typ.String()
276+
if _, ok := typ.(*types.Named); !ok {
277+
// Anonymous interface.
278+
name = "reflect/types.interface:" + name
279+
}
280+
global := c.mod.NamedGlobal(name + "$interface")
276281
zero := llvm.ConstInt(c.ctx.Int32Type(), 0, false)
277282
if !global.IsNil() {
278283
// method set already exist, return it
@@ -287,7 +292,7 @@ func (c *compilerContext) getInterfaceMethodSet(typ *types.Named) llvm.Value {
287292
}
288293

289294
value := llvm.ConstArray(c.i8ptrType, methods)
290-
global = llvm.AddGlobal(c.mod, value.Type(), typ.String()+"$interface")
295+
global = llvm.AddGlobal(c.mod, value.Type(), name+"$interface")
291296
global.SetInitializer(value)
292297
global.SetGlobalConstant(true)
293298
global.SetLinkage(llvm.PrivateLinkage)
@@ -329,7 +334,7 @@ func (b *builder) createTypeAssert(expr *ssa.TypeAssert) llvm.Value {
329334
// the main Go compiler, where the runtime checks whether the type
330335
// implements each method of the interface. See:
331336
// https://research.swtch.com/interfaces
332-
methodSet := b.getInterfaceMethodSet(expr.AssertedType.(*types.Named))
337+
methodSet := b.getInterfaceMethodSet(expr.AssertedType)
333338
commaOk = b.createRuntimeCall("interfaceImplements", []llvm.Value{actualTypeNum, methodSet}, "")
334339

335340
} else {
@@ -402,7 +407,7 @@ func (b *builder) getInvokeCall(instr *ssa.CallCommon) (llvm.Value, []llvm.Value
402407
typecode := b.CreateExtractValue(itf, 0, "invoke.typecode")
403408
values := []llvm.Value{
404409
typecode,
405-
b.getInterfaceMethodSet(instr.Value.Type().(*types.Named)),
410+
b.getInterfaceMethodSet(instr.Value.Type()),
406411
b.getMethodSignature(instr.Method),
407412
}
408413
fn := b.createRuntimeCall("interfaceMethod", values, "invoke.func")

testdata/interface.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ func main() {
2626
println("Stringer.String():", s.String())
2727
var itf interface{} = s
2828
println("Stringer.(*Thing).String():", itf.(Stringer).String())
29+
if s, ok := s.(interface{ String() string }); ok {
30+
println("s has String() method:", s.String())
31+
}
2932

3033
println("nested switch:", nestedSwitch('v', 3))
3134

testdata/interface.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ is Tuple: 0 8 16 24
1818
SmallPair.Print: 3 5
1919
Stringer.String(): foo
2020
Stringer.(*Thing).String(): foo
21+
s has String() method: foo
2122
nested switch: true
2223
non-blocking call on sometimes-blocking interface
2324
slept 1ms

0 commit comments

Comments
 (0)