tgo: Add rudimentary interface support.
No support yet for checking whether an interface implements a type.
Этот коммит содержится в:
родитель
0168bf7797
коммит
c2005a5f79
1 изменённых файлов: 48 добавлений и 43 удалений
91
tgo.go
91
tgo.go
|
@ -519,14 +519,16 @@ func (c *Compiler) parsePackage(program *ssa.Program, pkg *ssa.Package) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case *ssa.Type:
|
case *ssa.Type:
|
||||||
ms := program.MethodSets.MethodSet(member.Type())
|
if !types.IsInterface(member.Type()) {
|
||||||
for i := 0; i < ms.Len(); i++ {
|
ms := program.MethodSets.MethodSet(member.Type())
|
||||||
fn := program.MethodValue(ms.At(i))
|
for i := 0; i < ms.Len(); i++ {
|
||||||
frame, err := c.parseFuncDecl(fn)
|
fn := program.MethodValue(ms.At(i))
|
||||||
if err != nil {
|
frame, err := c.parseFuncDecl(fn)
|
||||||
return err
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
frames[fn] = frame
|
||||||
}
|
}
|
||||||
frames[fn] = frame
|
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return errors.New("todo: member: " + fmt.Sprintf("%#v", member))
|
return errors.New("todo: member: " + fmt.Sprintf("%#v", member))
|
||||||
|
@ -555,12 +557,14 @@ func (c *Compiler) parsePackage(program *ssa.Program, pkg *ssa.Package) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
case *ssa.Type:
|
case *ssa.Type:
|
||||||
ms := program.MethodSets.MethodSet(member.Type())
|
if !types.IsInterface(member.Type()) {
|
||||||
for i := 0; i < ms.Len(); i++ {
|
ms := program.MethodSets.MethodSet(member.Type())
|
||||||
fn := program.MethodValue(ms.At(i))
|
for i := 0; i < ms.Len(); i++ {
|
||||||
err := c.parseFunc(frames[fn], fn)
|
fn := program.MethodValue(ms.At(i))
|
||||||
if err != nil {
|
err := c.parseFunc(frames[fn], fn)
|
||||||
return err
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1094,6 +1098,13 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
|
||||||
// Passing the current task here to the subroutine. It is only used when
|
// Passing the current task here to the subroutine. It is only used when
|
||||||
// the subroutine is blocking.
|
// the subroutine is blocking.
|
||||||
return c.parseCall(frame, expr.Common(), frame.taskHandle)
|
return c.parseCall(frame, expr.Common(), frame.taskHandle)
|
||||||
|
case *ssa.ChangeInterface:
|
||||||
|
value, err := c.parseExpr(frame, expr.X)
|
||||||
|
if err != nil {
|
||||||
|
return llvm.Value{}, err
|
||||||
|
}
|
||||||
|
itfTypeNum := c.getInterfaceType(expr.X.Type())
|
||||||
|
return c.builder.CreateInsertValue(value, itfTypeNum, 0, ""), nil
|
||||||
case *ssa.ChangeType:
|
case *ssa.ChangeType:
|
||||||
return c.parseConvert(frame, expr.Type(), expr.X)
|
return c.parseConvert(frame, expr.Type(), expr.X)
|
||||||
case *ssa.Const:
|
case *ssa.Const:
|
||||||
|
@ -1208,25 +1219,21 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
|
||||||
return llvm.Value{}, err
|
return llvm.Value{}, err
|
||||||
}
|
}
|
||||||
var itfValue llvm.Value
|
var itfValue llvm.Value
|
||||||
switch typ := expr.X.Type().(type) {
|
size := c.targetData.TypeAllocSize(val.Type())
|
||||||
case *types.Basic:
|
if size > c.targetData.TypeAllocSize(c.i8ptrType) {
|
||||||
if typ.Info() & types.IsInteger != 0 { // TODO: 64-bit int on 32-bit platform
|
// Allocate on the heap and put a pointer in the interface.
|
||||||
itfValue = c.builder.CreateIntToPtr(val, c.i8ptrType, "")
|
// TODO: escape analysis.
|
||||||
} else if typ.Kind() == types.String {
|
sizeValue := llvm.ConstInt(c.uintptrType, size, false)
|
||||||
// TODO: escape analysis
|
itfValue = c.builder.CreateCall(c.allocFunc, []llvm.Value{sizeValue}, "")
|
||||||
size := c.targetData.TypeAllocSize(c.stringType)
|
itfValueCast := c.builder.CreateBitCast(itfValue, llvm.PointerType(val.Type(), 0), "")
|
||||||
sizeValue := llvm.ConstInt(c.uintptrType, size, false)
|
c.builder.CreateStore(val, itfValueCast)
|
||||||
itfValue = c.builder.CreateCall(c.allocFunc, []llvm.Value{sizeValue}, "")
|
} else {
|
||||||
itfValueCast := c.builder.CreateBitCast(itfValue, llvm.PointerType(c.stringType, 0), "")
|
// Directly place the value in the interface.
|
||||||
c.builder.CreateStore(val, itfValueCast)
|
// TODO: non-integers
|
||||||
} else {
|
itfValue = c.builder.CreateIntToPtr(val, c.i8ptrType, "")
|
||||||
return llvm.Value{}, errors.New("todo: make interface: unknown basic type")
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return llvm.Value{}, errors.New("todo: make interface: unknown type")
|
|
||||||
}
|
}
|
||||||
itfType := c.getInterfaceType(expr.X.Type())
|
itfTypeNum := c.getInterfaceType(expr.X.Type())
|
||||||
itf := c.ctx.ConstStruct([]llvm.Value{itfType, llvm.Undef(c.i8ptrType)}, false)
|
itf := c.ctx.ConstStruct([]llvm.Value{itfTypeNum, llvm.Undef(c.i8ptrType)}, false)
|
||||||
itf = c.builder.CreateInsertValue(itf, itfValue, 1, "")
|
itf = c.builder.CreateInsertValue(itf, itfValue, 1, "")
|
||||||
return itf, nil
|
return itf, nil
|
||||||
case *ssa.Phi:
|
case *ssa.Phi:
|
||||||
|
@ -1253,19 +1260,17 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
|
||||||
actualTypeNum := c.builder.CreateExtractValue(itf, 0, "interface.type")
|
actualTypeNum := c.builder.CreateExtractValue(itf, 0, "interface.type")
|
||||||
valuePtr := c.builder.CreateExtractValue(itf, 1, "interface.value")
|
valuePtr := c.builder.CreateExtractValue(itf, 1, "interface.value")
|
||||||
var value llvm.Value
|
var value llvm.Value
|
||||||
switch typ := expr.AssertedType.(type) {
|
if c.targetData.TypeAllocSize(assertedType) > c.targetData.TypeAllocSize(c.i8ptrType) {
|
||||||
case *types.Basic:
|
// Value was stored in an allocated buffer, load it from there.
|
||||||
if typ.Info() & types.IsInteger != 0 {
|
valuePtrCast := c.builder.CreateBitCast(valuePtr, llvm.PointerType(assertedType, 0), "")
|
||||||
value = c.builder.CreatePtrToInt(valuePtr, assertedType, "")
|
value = c.builder.CreateLoad(valuePtrCast, "")
|
||||||
} else if typ.Kind() == types.String {
|
} else {
|
||||||
valueStringPtr := c.builder.CreateBitCast(valuePtr, llvm.PointerType(c.stringType, 0), "")
|
// Value was stored directly in the interface.
|
||||||
value = c.builder.CreateLoad(valueStringPtr, "")
|
// TODO: non-integer values.
|
||||||
} else {
|
value = c.builder.CreatePtrToInt(valuePtr, assertedType, "")
|
||||||
return llvm.Value{}, errors.New("todo: typeassert: unknown basic type")
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return llvm.Value{}, errors.New("todo: typeassert: unknown type")
|
|
||||||
}
|
}
|
||||||
|
// TODO: for interfaces, check whether the type implements the
|
||||||
|
// interface.
|
||||||
commaOk := c.builder.CreateICmp(llvm.IntEQ, assertedTypeNum, actualTypeNum, "")
|
commaOk := c.builder.CreateICmp(llvm.IntEQ, assertedTypeNum, actualTypeNum, "")
|
||||||
tuple := llvm.ConstStruct([]llvm.Value{llvm.Undef(assertedType), llvm.Undef(llvm.Int1Type())}, false) // create empty tuple
|
tuple := llvm.ConstStruct([]llvm.Value{llvm.Undef(assertedType), llvm.Undef(llvm.Int1Type())}, false) // create empty tuple
|
||||||
tuple = c.builder.CreateInsertValue(tuple, value, 0, "") // insert value
|
tuple = c.builder.CreateInsertValue(tuple, value, 0, "") // insert value
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче