compiler,transform: fix for pointer-to-pointer type switches from @aykevl
Этот коммит содержится в:
		
							родитель
							
								
									62fb386d57
								
							
						
					
					
						коммит
						f5f4751088
					
				
					 4 изменённых файлов: 44 добавлений и 6 удалений
				
			
		| 
						 | 
				
			
			@ -683,11 +683,8 @@ func (b *builder) createTypeAssert(expr *ssa.TypeAssert) llvm.Value {
 | 
			
		|||
		commaOk = b.CreateCall(fn.GlobalValueType(), fn, []llvm.Value{actualTypeNum}, "")
 | 
			
		||||
 | 
			
		||||
	} else {
 | 
			
		||||
		assertedTypeGlobal := b.getTypeCode(expr.AssertedType)
 | 
			
		||||
		if !assertedTypeGlobal.IsAConstantExpr().IsNil() {
 | 
			
		||||
			assertedTypeGlobal = assertedTypeGlobal.Operand(0) // resolve the GEP operation
 | 
			
		||||
		}
 | 
			
		||||
		globalName := "reflect/types.typeid:" + strings.TrimPrefix(assertedTypeGlobal.Name(), "reflect/types.type:")
 | 
			
		||||
		name, _ := getTypeCodeName(expr.AssertedType)
 | 
			
		||||
		globalName := "reflect/types.typeid:" + name
 | 
			
		||||
		assertedTypeCodeGlobal := b.mod.NamedGlobal(globalName)
 | 
			
		||||
		if assertedTypeCodeGlobal.IsNil() {
 | 
			
		||||
			// Create a new typecode global.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										22
									
								
								testdata/interface.go
									
										
									
									
										предоставленный
									
									
								
							
							
						
						
									
										22
									
								
								testdata/interface.go
									
										
									
									
										предоставленный
									
									
								
							| 
						 | 
				
			
			@ -113,6 +113,9 @@ func main() {
 | 
			
		|||
	println("slept 1ms")
 | 
			
		||||
	blockStatic(SleepBlocker(time.Millisecond))
 | 
			
		||||
	println("slept 1ms")
 | 
			
		||||
 | 
			
		||||
	// check that pointer-to-pointer type switches work
 | 
			
		||||
	ptrptrswitch()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func printItf(val interface{}) {
 | 
			
		||||
| 
						 | 
				
			
			@ -312,3 +315,22 @@ func namedptr2() interface{} {
 | 
			
		|||
	type Test byte
 | 
			
		||||
	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??")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										3
									
								
								testdata/interface.txt
									
										
									
									
										предоставленный
									
									
								
							
							
						
						
									
										3
									
								
								testdata/interface.txt
									
										
									
									
										предоставленный
									
									
								
							| 
						 | 
				
			
			@ -24,3 +24,6 @@ Byte():  3
 | 
			
		|||
non-blocking call on sometimes-blocking interface
 | 
			
		||||
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")) {
 | 
			
		||||
		actualType := use.Operand(0)
 | 
			
		||||
		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 {
 | 
			
		||||
			// The type exists in the program, so lower to a regular pointer
 | 
			
		||||
			// comparison.
 | 
			
		||||
			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)
 | 
			
		||||
		} else {
 | 
			
		||||
			// The type does not exist in the program, so lower to a constant
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Загрузка…
	
	Создание таблицы
		
		Сослаться в новой задаче