mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-10 14:03:39 +00:00
reflect: add support for non-named basic types
This commit is contained in:
@@ -104,15 +104,6 @@ func (t *typeInfo) getMethod(signature *signatureInfo) *methodInfo {
|
||||
panic("could not find method")
|
||||
}
|
||||
|
||||
// id returns the fully-qualified type name including import path, removing the
|
||||
// $type suffix.
|
||||
func (t *typeInfo) id() string {
|
||||
if !strings.HasSuffix(t.name, "$type") {
|
||||
panic("concrete type does not have $type suffix: " + t.name)
|
||||
}
|
||||
return t.name[:len(t.name)-len("$type")]
|
||||
}
|
||||
|
||||
// typeInfoSlice implements sort.Slice, sorting the most commonly used types
|
||||
// first.
|
||||
type typeInfoSlice []*typeInfo
|
||||
@@ -423,9 +414,7 @@ func (p *lowerInterfacesPass) run() {
|
||||
}
|
||||
|
||||
// Assign a type code for each type.
|
||||
for i, t := range typeSlice {
|
||||
t.num = uint64(i + 1)
|
||||
}
|
||||
p.assignTypeCodes(typeSlice)
|
||||
|
||||
// Replace each call to runtime.makeInterface with the constant type code.
|
||||
for _, use := range makeInterfaceUses {
|
||||
@@ -691,7 +680,7 @@ func (p *lowerInterfacesPass) createInterfaceMethodFunc(itf *interfaceInfo, sign
|
||||
|
||||
// Define all possible functions that can be called.
|
||||
for _, typ := range itf.types {
|
||||
bb := llvm.AddBasicBlock(fn, typ.id())
|
||||
bb := llvm.AddBasicBlock(fn, typ.name)
|
||||
sw.AddCase(llvm.ConstInt(p.uintptrType, typ.num, false), bb)
|
||||
|
||||
// The function we will redirect to when the interface has this type.
|
||||
|
||||
+51
-2
@@ -79,9 +79,58 @@ func (c *Compiler) parseMakeInterface(val llvm.Value, typ types.Type, global str
|
||||
// It returns a pointer to an external global which should be replaced with the
|
||||
// real type in the interface lowering pass.
|
||||
func (c *Compiler) getTypeCode(typ types.Type) llvm.Value {
|
||||
global := c.mod.NamedGlobal(typ.String() + "$type")
|
||||
var globalName string
|
||||
switch typ := typ.(type) {
|
||||
case *types.Basic:
|
||||
var name string
|
||||
switch typ.Kind() {
|
||||
case types.Bool:
|
||||
name = "bool"
|
||||
case types.Int:
|
||||
name = "int"
|
||||
case types.Int8:
|
||||
name = "int8"
|
||||
case types.Int16:
|
||||
name = "int16"
|
||||
case types.Int32:
|
||||
name = "int32"
|
||||
case types.Int64:
|
||||
name = "int64"
|
||||
case types.Uint:
|
||||
name = "uint"
|
||||
case types.Uint8:
|
||||
name = "uint8"
|
||||
case types.Uint16:
|
||||
name = "uint16"
|
||||
case types.Uint32:
|
||||
name = "uint32"
|
||||
case types.Uint64:
|
||||
name = "uint64"
|
||||
case types.Uintptr:
|
||||
name = "uintptr"
|
||||
case types.Float32:
|
||||
name = "float32"
|
||||
case types.Float64:
|
||||
name = "float64"
|
||||
case types.Complex64:
|
||||
name = "complex64"
|
||||
case types.Complex128:
|
||||
name = "complex128"
|
||||
case types.String:
|
||||
name = "string"
|
||||
case types.UnsafePointer:
|
||||
name = "unsafeptr"
|
||||
default:
|
||||
panic("unknown basic type: " + typ.Name())
|
||||
}
|
||||
globalName = "type:basic:" + name
|
||||
default:
|
||||
// Unknown type, fall back to the .String() method for identification.
|
||||
globalName = "type:other:" + typ.String()
|
||||
}
|
||||
global := c.mod.NamedGlobal(globalName)
|
||||
if global.IsNil() {
|
||||
global = llvm.AddGlobal(c.mod, c.ctx.Int8Type(), typ.String()+"$type")
|
||||
global = llvm.AddGlobal(c.mod, c.ctx.Int8Type(), globalName)
|
||||
global.SetGlobalConstant(true)
|
||||
}
|
||||
return global
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
package compiler
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
var basicTypes = map[string]uint64{
|
||||
"bool": 1,
|
||||
"int": 2,
|
||||
"int8": 3,
|
||||
"int16": 4,
|
||||
"int32": 5,
|
||||
"int64": 6,
|
||||
"uint": 7,
|
||||
"uint8": 8,
|
||||
"uint16": 9,
|
||||
"uint32": 10,
|
||||
"uint64": 11,
|
||||
"uintptr": 12,
|
||||
"float32": 13,
|
||||
"float64": 14,
|
||||
"complex64": 15,
|
||||
"complex128": 16,
|
||||
"string": 17,
|
||||
"unsafeptr": 18,
|
||||
}
|
||||
|
||||
func (c *Compiler) assignTypeCodes(typeSlice typeInfoSlice) {
|
||||
fn := c.mod.NamedFunction("reflect.ValueOf")
|
||||
if fn.IsNil() {
|
||||
// reflect.ValueOf is never used, so we can use the most efficient
|
||||
// encoding possible.
|
||||
for i, t := range typeSlice {
|
||||
t.num = uint64(i + 1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Assign typecodes the way the reflect package expects.
|
||||
fallbackIndex := 1
|
||||
for _, t := range typeSlice {
|
||||
if strings.HasPrefix(t.name, "type:basic:") {
|
||||
// Basic types have a typecode with the lowest bit set to 0.
|
||||
num, ok := basicTypes[t.name[len("type:basic:"):]]
|
||||
if !ok {
|
||||
panic("invalid basic type: " + t.name)
|
||||
}
|
||||
t.num = num<<1 | 0
|
||||
} else {
|
||||
// Fallback types have a typecode with the lowest bit set to 1.
|
||||
t.num = uint64(fallbackIndex<<1 | 1)
|
||||
fallbackIndex++
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user