mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-24 06:19:04 +00:00
compiler,transform: fix for pointer-to-pointer type switches from @aykevl
This commit is contained in:
@@ -683,11 +683,8 @@ func (b *builder) createTypeAssert(expr *ssa.TypeAssert) llvm.Value {
|
|||||||
commaOk = b.CreateCall(fn.GlobalValueType(), fn, []llvm.Value{actualTypeNum}, "")
|
commaOk = b.CreateCall(fn.GlobalValueType(), fn, []llvm.Value{actualTypeNum}, "")
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
assertedTypeGlobal := b.getTypeCode(expr.AssertedType)
|
name, _ := getTypeCodeName(expr.AssertedType)
|
||||||
if !assertedTypeGlobal.IsAConstantExpr().IsNil() {
|
globalName := "reflect/types.typeid:" + name
|
||||||
assertedTypeGlobal = assertedTypeGlobal.Operand(0) // resolve the GEP operation
|
|
||||||
}
|
|
||||||
globalName := "reflect/types.typeid:" + strings.TrimPrefix(assertedTypeGlobal.Name(), "reflect/types.type:")
|
|
||||||
assertedTypeCodeGlobal := b.mod.NamedGlobal(globalName)
|
assertedTypeCodeGlobal := b.mod.NamedGlobal(globalName)
|
||||||
if assertedTypeCodeGlobal.IsNil() {
|
if assertedTypeCodeGlobal.IsNil() {
|
||||||
// Create a new typecode global.
|
// Create a new typecode global.
|
||||||
|
|||||||
Vendored
+22
@@ -113,6 +113,9 @@ func main() {
|
|||||||
println("slept 1ms")
|
println("slept 1ms")
|
||||||
blockStatic(SleepBlocker(time.Millisecond))
|
blockStatic(SleepBlocker(time.Millisecond))
|
||||||
println("slept 1ms")
|
println("slept 1ms")
|
||||||
|
|
||||||
|
// check that pointer-to-pointer type switches work
|
||||||
|
ptrptrswitch()
|
||||||
}
|
}
|
||||||
|
|
||||||
func printItf(val interface{}) {
|
func printItf(val interface{}) {
|
||||||
@@ -312,3 +315,22 @@ func namedptr2() interface{} {
|
|||||||
type Test byte
|
type Test byte
|
||||||
return (*Test)(nil)
|
return (*Test)(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ptrptrswitch() {
|
||||||
|
identify(0)
|
||||||
|
identify(new(int))
|
||||||
|
identify(new(*int))
|
||||||
|
}
|
||||||
|
|
||||||
|
func identify(itf any) {
|
||||||
|
switch itf.(type) {
|
||||||
|
case int:
|
||||||
|
println("type is int")
|
||||||
|
case *int:
|
||||||
|
println("type is *int")
|
||||||
|
case **int:
|
||||||
|
println("type is **int")
|
||||||
|
default:
|
||||||
|
println("other type??")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Vendored
+3
@@ -24,3 +24,6 @@ Byte(): 3
|
|||||||
non-blocking call on sometimes-blocking interface
|
non-blocking call on sometimes-blocking interface
|
||||||
slept 1ms
|
slept 1ms
|
||||||
slept 1ms
|
slept 1ms
|
||||||
|
type is int
|
||||||
|
type is *int
|
||||||
|
type is **int
|
||||||
|
|||||||
@@ -285,11 +285,27 @@ func (p *lowerInterfacesPass) run() error {
|
|||||||
for _, use := range getUses(p.mod.NamedFunction("runtime.typeAssert")) {
|
for _, use := range getUses(p.mod.NamedFunction("runtime.typeAssert")) {
|
||||||
actualType := use.Operand(0)
|
actualType := use.Operand(0)
|
||||||
name := strings.TrimPrefix(use.Operand(1).Name(), "reflect/types.typeid:")
|
name := strings.TrimPrefix(use.Operand(1).Name(), "reflect/types.typeid:")
|
||||||
|
gepOffset := uint64(0)
|
||||||
|
for strings.HasPrefix(name, "pointer:pointer:") {
|
||||||
|
// This is a type like **int, which has the name pointer:pointer:int
|
||||||
|
// but is encoded using pointer tagging.
|
||||||
|
// Calculate the pointer tag, which is emitted as a GEP instruction.
|
||||||
|
name = name[len("pointer:"):]
|
||||||
|
gepOffset++
|
||||||
|
}
|
||||||
|
|
||||||
if t, ok := p.types[name]; ok {
|
if t, ok := p.types[name]; ok {
|
||||||
// The type exists in the program, so lower to a regular pointer
|
// The type exists in the program, so lower to a regular pointer
|
||||||
// comparison.
|
// comparison.
|
||||||
p.builder.SetInsertPointBefore(use)
|
p.builder.SetInsertPointBefore(use)
|
||||||
commaOk := p.builder.CreateICmp(llvm.IntEQ, t.typecodeGEP, actualType, "typeassert.ok")
|
typecodeGEP := t.typecodeGEP
|
||||||
|
if gepOffset != 0 {
|
||||||
|
// This is a tagged pointer.
|
||||||
|
typecodeGEP = llvm.ConstInBoundsGEP(p.ctx.Int8Type(), typecodeGEP, []llvm.Value{
|
||||||
|
llvm.ConstInt(p.ctx.Int64Type(), gepOffset, false),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
commaOk := p.builder.CreateICmp(llvm.IntEQ, typecodeGEP, actualType, "typeassert.ok")
|
||||||
use.ReplaceAllUsesWith(commaOk)
|
use.ReplaceAllUsesWith(commaOk)
|
||||||
} else {
|
} else {
|
||||||
// The type does not exist in the program, so lower to a constant
|
// The type does not exist in the program, so lower to a constant
|
||||||
|
|||||||
Reference in New Issue
Block a user