Skip to content

Commit c0e0139

Browse files
committed
[AST] Allocate PlaceholderTypes in the correct arena
We shouldn't be allocating placeholders for type variables in the permanent arena, and we should be caching them such that equality works. To achieve this, we need to introduce a new "solver allocated" type property. This is required because we don't want to mark placeholder types with type variable originators as themselves having type variables, as it's not part of their structural type. Also update ErrorType to use this bit, though I don't believe we currently create ErrorTypes with type variable originators.
1 parent 748315b commit c0e0139

File tree

5 files changed

+70
-18
lines changed

5 files changed

+70
-18
lines changed

include/swift/AST/Types.h

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,13 @@ class RecursiveTypeProperties {
173173
/// This type contains an ElementArchetype.
174174
HasElementArchetype = 0x4000,
175175

176-
Last_Property = HasElementArchetype
176+
/// Whether the type is allocated in the constraint solver arena. This can
177+
/// differ from \c HasTypeVariable for types such as placeholders, which do
178+
/// not have type variables, but we still want to allocate in the solver if
179+
/// they have a type variable originator.
180+
SolverAllocated = 0x8000,
181+
182+
Last_Property = SolverAllocated
177183
};
178184
enum { BitWidth = countBitsUsed(Property::Last_Property) };
179185

@@ -224,6 +230,12 @@ class RecursiveTypeProperties {
224230
/// opened element archetype?
225231
bool hasElementArchetype() const { return Bits & HasElementArchetype; }
226232

233+
/// Whether the type is allocated in the constraint solver arena. This can
234+
/// differ from \c hasTypeVariable() for types such as placeholders, which
235+
/// do not have type variables, but we still want to allocate in the solver if
236+
/// they have a type variable originator.
237+
bool isSolverAllocated() const { return Bits & SolverAllocated; }
238+
227239
/// Does a type with these properties structurally contain a local
228240
/// archetype?
229241
bool hasLocalArchetype() const {
@@ -501,6 +513,8 @@ class alignas(1 << TypeAlignInBits) TypeBase
501513
}
502514

503515
void setRecursiveProperties(RecursiveTypeProperties properties) {
516+
assert(!(properties.hasTypeVariable() && !properties.isSolverAllocated()) &&
517+
"type variables must be solver allocated!");
504518
Bits.TypeBase.Properties = properties.getBits();
505519
assert(Bits.TypeBase.Properties == properties.getBits() && "Bits dropped!");
506520
}
@@ -6714,8 +6728,9 @@ TypeVariableType : public TypeBase {
67146728
// type is opaque.
67156729

67166730
TypeVariableType(const ASTContext &C, unsigned ID)
6717-
: TypeBase(TypeKind::TypeVariable, &C,
6718-
RecursiveTypeProperties::HasTypeVariable) {
6731+
: TypeBase(TypeKind::TypeVariable, &C,
6732+
RecursiveTypeProperties::HasTypeVariable |
6733+
RecursiveTypeProperties::SolverAllocated) {
67196734
// Note: the ID may overflow (current limit is 2^20 - 1).
67206735
Bits.TypeVariableType.ID = ID;
67216736
if (Bits.TypeVariableType.ID != ID) {
@@ -6774,6 +6789,8 @@ DEFINE_EMPTY_CAN_TYPE_WRAPPER(TypeVariableType, Type)
67746789
/// because the expression is ambiguous. This type is only used by the
67756790
/// constraint solver and transformed into UnresolvedType to be used in AST.
67766791
class PlaceholderType : public TypeBase {
6792+
// NOTE: If you add a new Type-based originator, you'll need to update the
6793+
// recursive property logic in PlaceholderType::get.
67776794
using Originator =
67786795
llvm::PointerUnion<TypeVariableType *, DependentMemberType *, VarDecl *,
67796796
ErrorExpr *, PlaceholderTypeRepr *>;

lib/AST/ASTContext.cpp

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,7 @@ struct ASTContext::Implementation {
430430
llvm::DenseMap<Type, InOutType*> InOutTypes;
431431
llvm::DenseMap<std::pair<Type, void*>, DependentMemberType *>
432432
DependentMemberTypes;
433+
llvm::DenseMap<void *, PlaceholderType *> PlaceholderTypes;
433434
llvm::DenseMap<Type, DynamicSelfType *> DynamicSelfTypes;
434435
llvm::DenseMap<std::pair<EnumDecl*, Type>, EnumType*> EnumTypes;
435436
llvm::DenseMap<std::pair<StructDecl*, Type>, StructType*> StructTypes;
@@ -1811,9 +1812,8 @@ bool ASTContext::hadError() const {
18111812

18121813
/// Retrieve the arena from which we should allocate storage for a type.
18131814
static AllocationArena getArena(RecursiveTypeProperties properties) {
1814-
bool hasTypeVariable = properties.hasTypeVariable();
1815-
return hasTypeVariable ? AllocationArena::ConstraintSolver
1816-
: AllocationArena::Permanent;
1815+
return properties.isSolverAllocated() ? AllocationArena::ConstraintSolver
1816+
: AllocationArena::Permanent;
18171817
}
18181818

18191819
void ASTContext::addSearchPath(StringRef searchPath, bool isFramework,
@@ -3117,15 +3117,43 @@ Type ErrorType::get(Type originalType) {
31173117
void *mem = ctx.Allocate(sizeof(ErrorType) + sizeof(Type),
31183118
alignof(ErrorType), arena);
31193119
RecursiveTypeProperties properties = RecursiveTypeProperties::HasError;
3120-
if (originalProperties.hasTypeVariable())
3121-
properties |= RecursiveTypeProperties::HasTypeVariable;
3120+
3121+
// We need to preserve the solver allocated bit, to ensure any wrapping
3122+
// types are solver allocated too.
3123+
if (originalProperties.isSolverAllocated())
3124+
properties |= RecursiveTypeProperties::SolverAllocated;
3125+
31223126
return entry = new (mem) ErrorType(ctx, originalType, properties);
31233127
}
31243128

31253129
Type PlaceholderType::get(ASTContext &ctx, Originator originator) {
31263130
assert(originator);
3127-
return new (ctx, AllocationArena::Permanent)
3128-
PlaceholderType(ctx, originator, RecursiveTypeProperties::HasPlaceholder);
3131+
3132+
auto originatorProps = [&]() -> RecursiveTypeProperties {
3133+
if (auto *tv = originator.dyn_cast<TypeVariableType *>())
3134+
return tv->getRecursiveProperties();
3135+
3136+
if (auto *depTy = originator.dyn_cast<DependentMemberType *>())
3137+
return depTy->getRecursiveProperties();
3138+
3139+
return RecursiveTypeProperties();
3140+
}();
3141+
auto arena = getArena(originatorProps);
3142+
3143+
auto &cache = ctx.getImpl().getArena(arena).PlaceholderTypes;
3144+
auto &entry = cache[originator.getOpaqueValue()];
3145+
if (entry)
3146+
return entry;
3147+
3148+
RecursiveTypeProperties properties = RecursiveTypeProperties::HasPlaceholder;
3149+
3150+
// We need to preserve the solver allocated bit, to ensure any wrapping
3151+
// types are solver allocated too.
3152+
if (originatorProps.isSolverAllocated())
3153+
properties |= RecursiveTypeProperties::SolverAllocated;
3154+
3155+
entry = new (ctx, arena) PlaceholderType(ctx, originator, properties);
3156+
return entry;
31293157
}
31303158

31313159
BuiltinIntegerType *BuiltinIntegerType::get(BuiltinIntegerWidth BitWidth,
@@ -3943,7 +3971,7 @@ isAnyFunctionTypeCanonical(ArrayRef<AnyFunctionType::Param> params,
39433971
static RecursiveTypeProperties
39443972
getGenericFunctionRecursiveProperties(ArrayRef<AnyFunctionType::Param> params,
39453973
Type result) {
3946-
static_assert(RecursiveTypeProperties::BitWidth == 15,
3974+
static_assert(RecursiveTypeProperties::BitWidth == 16,
39473975
"revisit this if you add new recursive type properties");
39483976
RecursiveTypeProperties properties;
39493977

@@ -4604,7 +4632,7 @@ CanSILFunctionType SILFunctionType::get(
46044632
void *mem = ctx.Allocate(bytes, alignof(SILFunctionType));
46054633

46064634
RecursiveTypeProperties properties;
4607-
static_assert(RecursiveTypeProperties::BitWidth == 15,
4635+
static_assert(RecursiveTypeProperties::BitWidth == 16,
46084636
"revisit this if you add new recursive type properties");
46094637
for (auto &param : params)
46104638
properties |= param.getInterfaceType()->getRecursiveProperties();

lib/Sema/CSApply.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8475,8 +8475,8 @@ namespace {
84758475
exprType = solution.simplifyType(exprType);
84768476
// assert((!expr->getType() || expr->getType()->isEqual(exprType)) &&
84778477
// "Mismatched types!");
8478-
assert(!exprType->hasTypeVariable() &&
8479-
"Should not write type variable into expression!");
8478+
assert(!exprType->getRecursiveProperties().isSolverAllocated() &&
8479+
"Should not write solver allocated type into expression!");
84808480
assert(!exprType->hasPlaceholder() &&
84818481
"Should not write type placeholders into expression!");
84828482
expr->setType(exprType);
@@ -8486,8 +8486,10 @@ namespace {
84868486
Type componentType;
84878487
if (cs.hasType(kp, i)) {
84888488
componentType = solution.simplifyType(cs.getType(kp, i));
8489-
assert(!componentType->hasTypeVariable() &&
8490-
"Should not write type variable into key-path component");
8489+
assert(
8490+
!componentType->getRecursiveProperties().isSolverAllocated() &&
8491+
"Should not write solver allocated type into key-path "
8492+
"component!");
84918493
assert(!componentType->hasPlaceholder() &&
84928494
"Should not write type placeholder into key-path component");
84938495
kp->getMutableComponents()[i].setComponentType(componentType);

test/Constraints/rdar44770297.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,8 @@ func foo<T: P>(_: () throws -> T) -> T.A? { // expected-note {{where 'T' = 'Neve
88
fatalError()
99
}
1010

11-
let _ = foo() {fatalError()} & nil // expected-error {{global function 'foo' requires that 'Never' conform to 'P'}}
11+
let _ = foo() {fatalError()} & nil
12+
// expected-error@-1 {{global function 'foo' requires that 'Never' conform to 'P'}}
13+
// expected-error@-2 {{value of optional type 'Never.A?' must be unwrapped to a value of type 'Never.A'}}
14+
// expected-note@-3 {{coalesce using '??' to provide a default when the optional value contains 'nil'}}
15+
// expected-note@-4 {{force-unwrap using '!' to abort execution if the optional value contains 'nil'}}

validation-test/Sema/type_checker_crashers_fixed/issue-65360.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ let _: () -> Void = {
1313
// expected-error@-1 {{cannot convert value of type 'Any?' to specified type '(_, _)}}
1414
}
1515

16-
let _: () -> Void = { // expected-error {{unable to infer closure type in the current context}}
16+
let _: () -> Void = {
1717
for case (0)? in [a] {}
1818
for case (0, 0) in [a] {}
19+
// expected-error@-1 {{cannot convert value of type 'Any?' to expected element type '(_, _)'}}
1920
}

0 commit comments

Comments
 (0)