func isTypeRecursive(typ ast.Type) (bool, []ast.Type) { typ = typ.ActualType() var check func(current ast.Type, path *[]ast.Type, traversed map[ast.Type]bool) bool check = func(current ast.Type, path *[]ast.Type, traversed map[ast.Type]bool) bool { switch current.(type) { case *ast.NamedType: if traversed[current] { return true } } switch typ := current.(type) { case ast.StructType: for _, mem := range typ.Members { if check(mem.Type.BaseType, path, traversed) { *path = append(*path, mem.Type.BaseType) return true } } case ast.TupleType: for _, mem := range typ.Members { if check(mem.BaseType, path, traversed) { *path = append(*path, mem.BaseType) return true } } case ast.EnumType: for _, mem := range typ.Members { if check(mem.Type, path, traversed) { *path = append(*path, mem.Type) return true } } case *ast.NamedType: traversed[current] = true if check(typ.Type, path, traversed) { *path = append(*path, typ.Type) return true } traversed[current] = false case ast.ArrayType: if typ.IsFixedLength && check(typ.MemberType.BaseType, path, traversed) { *path = append(*path, typ.MemberType.BaseType) return true } } return false } var path []ast.Type return check(typ, &path, make(map[ast.Type]bool)), path }
func (v *Codegen) typeToLLVMType(typ ast.Type, gcon *ast.GenericContext) llvm.Type { switch typ := typ.(type) { case ast.PrimitiveType: return v.primitiveTypeToLLVMType(typ) case ast.FunctionType: return v.functionTypeToLLVMType(typ, true, gcon) case ast.StructType: return v.structTypeToLLVMType(typ, gcon) case ast.PointerType: return llvm.PointerType(v.typeRefToLLVMTypeWithOuter(typ.Addressee, gcon), 0) case ast.ArrayType: return v.arrayTypeToLLVMType(typ, gcon) case ast.TupleType: return v.tupleTypeToLLVMType(typ, gcon) case ast.EnumType: return v.enumTypeToLLVMType(typ, gcon) case ast.ReferenceType: return llvm.PointerType(v.typeRefToLLVMTypeWithOuter(typ.Referrer, gcon), 0) case *ast.NamedType: switch typ.Type.(type) { case ast.StructType, ast.EnumType: // If something seems wrong with the code and thie problems seems to come from here, // make sure the type doesn't need generics arguments as well. // This here ignores them. name := ast.TypeReferenceMangledName(ast.MANGLE_ARK_UNSTABLE, &ast.TypeReference{BaseType: typ}, gcon) v.addNamedType(typ, name, gcon) lt := v.namedTypeLookup[name] return lt default: return v.typeToLLVMType(typ.Type, gcon) } case *ast.SubstitutionType: if gcon == nil { panic("gcon == nil when getting substitution type") } if gcon.GetSubstitutionType(typ) == nil { panic("missing generic map entry for type " + typ.TypeName() + " " + fmt.Sprintf("(%p)", typ)) } return v.typeRefToLLVMTypeWithOuter(gcon.GetSubstitutionType(typ), gcon) default: log.Debugln("codegen", "Type was %s (%s)", typ.TypeName(), reflect.TypeOf(typ)) panic("Unimplemented type category in LLVM codegen") } }
func typeContainsReferenceType(typ ast.Type, visited map[*ast.TypeReference]struct{ visited, value bool }) bool { switch typ := typ.ActualType().(type) { case ast.ReferenceType: return true case ast.PointerType: return typeReferenceContainsReferenceType(typ.Addressee, visited) case ast.ArrayType: return typeReferenceContainsReferenceType(typ.MemberType, visited) case ast.StructType: for _, field := range typ.Members { if typeReferenceContainsReferenceType(field.Type, visited) { return true } } return false case ast.EnumType: for _, member := range typ.Members { if typeContainsReferenceType(member.Type, visited) { return true } } return false case ast.TupleType: for _, field := range typ.Members { if typeReferenceContainsReferenceType(field, visited) { return true } } return false case *ast.SubstitutionType, ast.PrimitiveType, ast.FunctionType: return false default: panic("unimplemented type: " + reflect.TypeOf(typ).String()) } }