tgo: Add rudimentary interface support.

No support yet for checking whether an interface implements a type.
Этот коммит содержится в:
Ayke van Laethem 2018-06-07 15:48:32 +02:00
родитель 0168bf7797
коммит c2005a5f79
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: E97FF5335DFDFDED

55
tgo.go
Просмотреть файл

@ -519,6 +519,7 @@ func (c *Compiler) parsePackage(program *ssa.Program, pkg *ssa.Package) error {
} }
} }
case *ssa.Type: case *ssa.Type:
if !types.IsInterface(member.Type()) {
ms := program.MethodSets.MethodSet(member.Type()) ms := program.MethodSets.MethodSet(member.Type())
for i := 0; i < ms.Len(); i++ { for i := 0; i < ms.Len(); i++ {
fn := program.MethodValue(ms.At(i)) fn := program.MethodValue(ms.At(i))
@ -528,6 +529,7 @@ func (c *Compiler) parsePackage(program *ssa.Program, pkg *ssa.Package) error {
} }
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,6 +557,7 @@ func (c *Compiler) parsePackage(program *ssa.Program, pkg *ssa.Package) error {
return err return err
} }
case *ssa.Type: case *ssa.Type:
if !types.IsInterface(member.Type()) {
ms := program.MethodSets.MethodSet(member.Type()) ms := program.MethodSets.MethodSet(member.Type())
for i := 0; i < ms.Len(); i++ { for i := 0; i < ms.Len(); i++ {
fn := program.MethodValue(ms.At(i)) fn := program.MethodValue(ms.At(i))
@ -565,6 +568,7 @@ func (c *Compiler) parsePackage(program *ssa.Program, pkg *ssa.Package) error {
} }
} }
} }
}
return nil return nil
} }
@ -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 {
// TODO: escape analysis
size := c.targetData.TypeAllocSize(c.stringType)
sizeValue := llvm.ConstInt(c.uintptrType, size, false) sizeValue := llvm.ConstInt(c.uintptrType, size, false)
itfValue = c.builder.CreateCall(c.allocFunc, []llvm.Value{sizeValue}, "") itfValue = c.builder.CreateCall(c.allocFunc, []llvm.Value{sizeValue}, "")
itfValueCast := c.builder.CreateBitCast(itfValue, llvm.PointerType(c.stringType, 0), "") itfValueCast := c.builder.CreateBitCast(itfValue, llvm.PointerType(val.Type(), 0), "")
c.builder.CreateStore(val, itfValueCast) c.builder.CreateStore(val, itfValueCast)
} else { } else {
return llvm.Value{}, errors.New("todo: make interface: unknown basic type") // Directly place the value in the interface.
// TODO: non-integers
itfValue = c.builder.CreateIntToPtr(val, c.i8ptrType, "")
} }
default: itfTypeNum := c.getInterfaceType(expr.X.Type())
return llvm.Value{}, errors.New("todo: make interface: unknown type") itf := c.ctx.ConstStruct([]llvm.Value{itfTypeNum, llvm.Undef(c.i8ptrType)}, false)
}
itfType := c.getInterfaceType(expr.X.Type())
itf := c.ctx.ConstStruct([]llvm.Value{itfType, 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 {
valueStringPtr := c.builder.CreateBitCast(valuePtr, llvm.PointerType(c.stringType, 0), "")
value = c.builder.CreateLoad(valueStringPtr, "")
} else { } else {
return llvm.Value{}, errors.New("todo: typeassert: unknown basic type") // Value was stored directly in the interface.
} // TODO: non-integer values.
default: value = c.builder.CreatePtrToInt(valuePtr, assertedType, "")
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