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.
Этот коммит содержится в:
родитель
cc4a4c755f
коммит
0596b3c003
3 изменённых файлов: 14 добавлений и 5 удалений
|
@ -271,8 +271,13 @@ func (c *compilerContext) getTypeMethodSet(typ types.Type) llvm.Value {
|
|||
// getInterfaceMethodSet returns a global variable with the method set of the
|
||||
// given named interface type. This method set is used by the interface lowering
|
||||
// pass.
|
||||
func (c *compilerContext) getInterfaceMethodSet(typ *types.Named) llvm.Value {
|
||||
global := c.mod.NamedGlobal(typ.String() + "$interface")
|
||||
func (c *compilerContext) getInterfaceMethodSet(typ types.Type) llvm.Value {
|
||||
name := typ.String()
|
||||
if _, ok := typ.(*types.Named); !ok {
|
||||
// Anonymous interface.
|
||||
name = "reflect/types.interface:" + name
|
||||
}
|
||||
global := c.mod.NamedGlobal(name + "$interface")
|
||||
zero := llvm.ConstInt(c.ctx.Int32Type(), 0, false)
|
||||
if !global.IsNil() {
|
||||
// method set already exist, return it
|
||||
|
@ -287,7 +292,7 @@ func (c *compilerContext) getInterfaceMethodSet(typ *types.Named) llvm.Value {
|
|||
}
|
||||
|
||||
value := llvm.ConstArray(c.i8ptrType, methods)
|
||||
global = llvm.AddGlobal(c.mod, value.Type(), typ.String()+"$interface")
|
||||
global = llvm.AddGlobal(c.mod, value.Type(), name+"$interface")
|
||||
global.SetInitializer(value)
|
||||
global.SetGlobalConstant(true)
|
||||
global.SetLinkage(llvm.PrivateLinkage)
|
||||
|
@ -329,7 +334,7 @@ func (b *builder) createTypeAssert(expr *ssa.TypeAssert) llvm.Value {
|
|||
// the main Go compiler, where the runtime checks whether the type
|
||||
// implements each method of the interface. See:
|
||||
// https://research.swtch.com/interfaces
|
||||
methodSet := b.getInterfaceMethodSet(expr.AssertedType.(*types.Named))
|
||||
methodSet := b.getInterfaceMethodSet(expr.AssertedType)
|
||||
commaOk = b.createRuntimeCall("interfaceImplements", []llvm.Value{actualTypeNum, methodSet}, "")
|
||||
|
||||
} else {
|
||||
|
@ -402,7 +407,7 @@ func (b *builder) getInvokeCall(instr *ssa.CallCommon) (llvm.Value, []llvm.Value
|
|||
typecode := b.CreateExtractValue(itf, 0, "invoke.typecode")
|
||||
values := []llvm.Value{
|
||||
typecode,
|
||||
b.getInterfaceMethodSet(instr.Value.Type().(*types.Named)),
|
||||
b.getInterfaceMethodSet(instr.Value.Type()),
|
||||
b.getMethodSignature(instr.Method),
|
||||
}
|
||||
fn := b.createRuntimeCall("interfaceMethod", values, "invoke.func")
|
||||
|
|
3
testdata/interface.go
предоставленный
3
testdata/interface.go
предоставленный
|
@ -26,6 +26,9 @@ func main() {
|
|||
println("Stringer.String():", s.String())
|
||||
var itf interface{} = s
|
||||
println("Stringer.(*Thing).String():", itf.(Stringer).String())
|
||||
if s, ok := s.(interface{ String() string }); ok {
|
||||
println("s has String() method:", s.String())
|
||||
}
|
||||
|
||||
println("nested switch:", nestedSwitch('v', 3))
|
||||
|
||||
|
|
1
testdata/interface.txt
предоставленный
1
testdata/interface.txt
предоставленный
|
@ -18,6 +18,7 @@ is Tuple: 0 8 16 24
|
|||
SmallPair.Print: 3 5
|
||||
Stringer.String(): foo
|
||||
Stringer.(*Thing).String(): foo
|
||||
s has String() method: foo
|
||||
nested switch: true
|
||||
non-blocking call on sometimes-blocking interface
|
||||
slept 1ms
|
||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче