Skip to content

Commit f5f4751

Browse files
dgryskideadprogram
authored andcommitted
compiler,transform: fix for pointer-to-pointer type switches from @aykevl
1 parent 62fb386 commit f5f4751

File tree

4 files changed

+44
-6
lines changed

4 files changed

+44
-6
lines changed

compiler/interface.go

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -683,11 +683,8 @@ func (b *builder) createTypeAssert(expr *ssa.TypeAssert) llvm.Value {
683683
commaOk = b.CreateCall(fn.GlobalValueType(), fn, []llvm.Value{actualTypeNum}, "")
684684

685685
} else {
686-
assertedTypeGlobal := b.getTypeCode(expr.AssertedType)
687-
if !assertedTypeGlobal.IsAConstantExpr().IsNil() {
688-
assertedTypeGlobal = assertedTypeGlobal.Operand(0) // resolve the GEP operation
689-
}
690-
globalName := "reflect/types.typeid:" + strings.TrimPrefix(assertedTypeGlobal.Name(), "reflect/types.type:")
686+
name, _ := getTypeCodeName(expr.AssertedType)
687+
globalName := "reflect/types.typeid:" + name
691688
assertedTypeCodeGlobal := b.mod.NamedGlobal(globalName)
692689
if assertedTypeCodeGlobal.IsNil() {
693690
// Create a new typecode global.

testdata/interface.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,9 @@ func main() {
113113
println("slept 1ms")
114114
blockStatic(SleepBlocker(time.Millisecond))
115115
println("slept 1ms")
116+
117+
// check that pointer-to-pointer type switches work
118+
ptrptrswitch()
116119
}
117120

118121
func printItf(val interface{}) {
@@ -312,3 +315,22 @@ func namedptr2() interface{} {
312315
type Test byte
313316
return (*Test)(nil)
314317
}
318+
319+
func ptrptrswitch() {
320+
identify(0)
321+
identify(new(int))
322+
identify(new(*int))
323+
}
324+
325+
func identify(itf any) {
326+
switch itf.(type) {
327+
case int:
328+
println("type is int")
329+
case *int:
330+
println("type is *int")
331+
case **int:
332+
println("type is **int")
333+
default:
334+
println("other type??")
335+
}
336+
}

testdata/interface.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,6 @@ Byte(): 3
2424
non-blocking call on sometimes-blocking interface
2525
slept 1ms
2626
slept 1ms
27+
type is int
28+
type is *int
29+
type is **int

transform/interface-lowering.go

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,11 +285,27 @@ func (p *lowerInterfacesPass) run() error {
285285
for _, use := range getUses(p.mod.NamedFunction("runtime.typeAssert")) {
286286
actualType := use.Operand(0)
287287
name := strings.TrimPrefix(use.Operand(1).Name(), "reflect/types.typeid:")
288+
gepOffset := uint64(0)
289+
for strings.HasPrefix(name, "pointer:pointer:") {
290+
// This is a type like **int, which has the name pointer:pointer:int
291+
// but is encoded using pointer tagging.
292+
// Calculate the pointer tag, which is emitted as a GEP instruction.
293+
name = name[len("pointer:"):]
294+
gepOffset++
295+
}
296+
288297
if t, ok := p.types[name]; ok {
289298
// The type exists in the program, so lower to a regular pointer
290299
// comparison.
291300
p.builder.SetInsertPointBefore(use)
292-
commaOk := p.builder.CreateICmp(llvm.IntEQ, t.typecodeGEP, actualType, "typeassert.ok")
301+
typecodeGEP := t.typecodeGEP
302+
if gepOffset != 0 {
303+
// This is a tagged pointer.
304+
typecodeGEP = llvm.ConstInBoundsGEP(p.ctx.Int8Type(), typecodeGEP, []llvm.Value{
305+
llvm.ConstInt(p.ctx.Int64Type(), gepOffset, false),
306+
})
307+
}
308+
commaOk := p.builder.CreateICmp(llvm.IntEQ, typecodeGEP, actualType, "typeassert.ok")
293309
use.ReplaceAllUsesWith(commaOk)
294310
} else {
295311
// The type does not exist in the program, so lower to a constant

0 commit comments

Comments
 (0)