diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index 6e97424d80e05..dd7b11b0a82b7 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -173,7 +173,13 @@ class RecursiveTypeProperties { /// This type contains an ElementArchetype. HasElementArchetype = 0x4000, - Last_Property = HasElementArchetype + /// Whether the type is allocated in the constraint solver arena. This can + /// differ from \c HasTypeVariable for types such as placeholders, which do + /// not have type variables, but we still want to allocate in the solver if + /// they have a type variable originator. + SolverAllocated = 0x8000, + + Last_Property = SolverAllocated }; enum { BitWidth = countBitsUsed(Property::Last_Property) }; @@ -224,6 +230,12 @@ class RecursiveTypeProperties { /// opened element archetype? bool hasElementArchetype() const { return Bits & HasElementArchetype; } + /// Whether the type is allocated in the constraint solver arena. This can + /// differ from \c hasTypeVariable() for types such as placeholders, which + /// do not have type variables, but we still want to allocate in the solver if + /// they have a type variable originator. + bool isSolverAllocated() const { return Bits & SolverAllocated; } + /// Does a type with these properties structurally contain a local /// archetype? bool hasLocalArchetype() const { @@ -501,6 +513,8 @@ class alignas(1 << TypeAlignInBits) TypeBase } void setRecursiveProperties(RecursiveTypeProperties properties) { + assert(!(properties.hasTypeVariable() && !properties.isSolverAllocated()) && + "type variables must be solver allocated!"); Bits.TypeBase.Properties = properties.getBits(); assert(Bits.TypeBase.Properties == properties.getBits() && "Bits dropped!"); } @@ -6714,8 +6728,9 @@ TypeVariableType : public TypeBase { // type is opaque. TypeVariableType(const ASTContext &C, unsigned ID) - : TypeBase(TypeKind::TypeVariable, &C, - RecursiveTypeProperties::HasTypeVariable) { + : TypeBase(TypeKind::TypeVariable, &C, + RecursiveTypeProperties::HasTypeVariable | + RecursiveTypeProperties::SolverAllocated) { // Note: the ID may overflow (current limit is 2^20 - 1). Bits.TypeVariableType.ID = ID; if (Bits.TypeVariableType.ID != ID) { @@ -6774,6 +6789,8 @@ DEFINE_EMPTY_CAN_TYPE_WRAPPER(TypeVariableType, Type) /// because the expression is ambiguous. This type is only used by the /// constraint solver and transformed into UnresolvedType to be used in AST. class PlaceholderType : public TypeBase { + // NOTE: If you add a new Type-based originator, you'll need to update the + // recursive property logic in PlaceholderType::get. using Originator = llvm::PointerUnion; diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 578ae058b1fcf..3fed2944446d9 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -430,6 +430,7 @@ struct ASTContext::Implementation { llvm::DenseMap InOutTypes; llvm::DenseMap, DependentMemberType *> DependentMemberTypes; + llvm::DenseMap PlaceholderTypes; llvm::DenseMap DynamicSelfTypes; llvm::DenseMap, EnumType*> EnumTypes; llvm::DenseMap, StructType*> StructTypes; @@ -1811,9 +1812,8 @@ bool ASTContext::hadError() const { /// Retrieve the arena from which we should allocate storage for a type. static AllocationArena getArena(RecursiveTypeProperties properties) { - bool hasTypeVariable = properties.hasTypeVariable(); - return hasTypeVariable ? AllocationArena::ConstraintSolver - : AllocationArena::Permanent; + return properties.isSolverAllocated() ? AllocationArena::ConstraintSolver + : AllocationArena::Permanent; } void ASTContext::addSearchPath(StringRef searchPath, bool isFramework, @@ -3117,15 +3117,43 @@ Type ErrorType::get(Type originalType) { void *mem = ctx.Allocate(sizeof(ErrorType) + sizeof(Type), alignof(ErrorType), arena); RecursiveTypeProperties properties = RecursiveTypeProperties::HasError; - if (originalProperties.hasTypeVariable()) - properties |= RecursiveTypeProperties::HasTypeVariable; + + // We need to preserve the solver allocated bit, to ensure any wrapping + // types are solver allocated too. + if (originalProperties.isSolverAllocated()) + properties |= RecursiveTypeProperties::SolverAllocated; + return entry = new (mem) ErrorType(ctx, originalType, properties); } Type PlaceholderType::get(ASTContext &ctx, Originator originator) { assert(originator); - return new (ctx, AllocationArena::Permanent) - PlaceholderType(ctx, originator, RecursiveTypeProperties::HasPlaceholder); + + auto originatorProps = [&]() -> RecursiveTypeProperties { + if (auto *tv = originator.dyn_cast()) + return tv->getRecursiveProperties(); + + if (auto *depTy = originator.dyn_cast()) + return depTy->getRecursiveProperties(); + + return RecursiveTypeProperties(); + }(); + auto arena = getArena(originatorProps); + + auto &cache = ctx.getImpl().getArena(arena).PlaceholderTypes; + auto &entry = cache[originator.getOpaqueValue()]; + if (entry) + return entry; + + RecursiveTypeProperties properties = RecursiveTypeProperties::HasPlaceholder; + + // We need to preserve the solver allocated bit, to ensure any wrapping + // types are solver allocated too. + if (originatorProps.isSolverAllocated()) + properties |= RecursiveTypeProperties::SolverAllocated; + + entry = new (ctx, arena) PlaceholderType(ctx, originator, properties); + return entry; } BuiltinIntegerType *BuiltinIntegerType::get(BuiltinIntegerWidth BitWidth, @@ -3943,7 +3971,7 @@ isAnyFunctionTypeCanonical(ArrayRef params, static RecursiveTypeProperties getGenericFunctionRecursiveProperties(ArrayRef params, Type result) { - static_assert(RecursiveTypeProperties::BitWidth == 15, + static_assert(RecursiveTypeProperties::BitWidth == 16, "revisit this if you add new recursive type properties"); RecursiveTypeProperties properties; @@ -4604,7 +4632,7 @@ CanSILFunctionType SILFunctionType::get( void *mem = ctx.Allocate(bytes, alignof(SILFunctionType)); RecursiveTypeProperties properties; - static_assert(RecursiveTypeProperties::BitWidth == 15, + static_assert(RecursiveTypeProperties::BitWidth == 16, "revisit this if you add new recursive type properties"); for (auto ¶m : params) properties |= param.getInterfaceType()->getRecursiveProperties(); diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index 0f380786d0ae0..47cfab2314072 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -8475,8 +8475,8 @@ namespace { exprType = solution.simplifyType(exprType); // assert((!expr->getType() || expr->getType()->isEqual(exprType)) && // "Mismatched types!"); - assert(!exprType->hasTypeVariable() && - "Should not write type variable into expression!"); + assert(!exprType->getRecursiveProperties().isSolverAllocated() && + "Should not write solver allocated type into expression!"); assert(!exprType->hasPlaceholder() && "Should not write type placeholders into expression!"); expr->setType(exprType); @@ -8486,8 +8486,10 @@ namespace { Type componentType; if (cs.hasType(kp, i)) { componentType = solution.simplifyType(cs.getType(kp, i)); - assert(!componentType->hasTypeVariable() && - "Should not write type variable into key-path component"); + assert( + !componentType->getRecursiveProperties().isSolverAllocated() && + "Should not write solver allocated type into key-path " + "component!"); assert(!componentType->hasPlaceholder() && "Should not write type placeholder into key-path component"); kp->getMutableComponents()[i].setComponentType(componentType); diff --git a/test/Constraints/rdar44770297.swift b/test/Constraints/rdar44770297.swift index 9853dd1ca2f53..0853b150b353a 100644 --- a/test/Constraints/rdar44770297.swift +++ b/test/Constraints/rdar44770297.swift @@ -8,4 +8,8 @@ func foo(_: () throws -> T) -> T.A? { // expected-note {{where 'T' = 'Neve fatalError() } -let _ = foo() {fatalError()} & nil // expected-error {{global function 'foo' requires that 'Never' conform to 'P'}} +let _ = foo() {fatalError()} & nil +// expected-error@-1 {{global function 'foo' requires that 'Never' conform to 'P'}} +// expected-error@-2 {{value of optional type 'Never.A?' must be unwrapped to a value of type 'Never.A'}} +// expected-note@-3 {{coalesce using '??' to provide a default when the optional value contains 'nil'}} +// expected-note@-4 {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}} diff --git a/validation-test/Sema/type_checker_crashers_fixed/issue-65360.swift b/validation-test/Sema/type_checker_crashers_fixed/issue-65360.swift index b8413e316c540..2e7e10322c932 100644 --- a/validation-test/Sema/type_checker_crashers_fixed/issue-65360.swift +++ b/validation-test/Sema/type_checker_crashers_fixed/issue-65360.swift @@ -13,7 +13,8 @@ let _: () -> Void = { // expected-error@-1 {{cannot convert value of type 'Any?' to specified type '(_, _)}} } -let _: () -> Void = { // expected-error {{unable to infer closure type in the current context}} +let _: () -> Void = { for case (0)? in [a] {} for case (0, 0) in [a] {} + // expected-error@-1 {{cannot convert value of type 'Any?' to expected element type '(_, _)'}} }