Skip to content

Commit 3bc14bb

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 8251c8f commit 3bc14bb

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
@@ -431,6 +431,7 @@ struct ASTContext::Implementation {
431431
llvm::DenseMap<Type, InOutType*> InOutTypes;
432432
llvm::DenseMap<std::pair<Type, void*>, DependentMemberType *>
433433
DependentMemberTypes;
434+
llvm::DenseMap<void *, PlaceholderType *> PlaceholderTypes;
434435
llvm::DenseMap<Type, DynamicSelfType *> DynamicSelfTypes;
435436
llvm::DenseMap<std::pair<EnumDecl*, Type>, EnumType*> EnumTypes;
436437
llvm::DenseMap<std::pair<StructDecl*, Type>, StructType*> StructTypes;
@@ -1800,9 +1801,8 @@ bool ASTContext::hadError() const {
18001801

18011802
/// Retrieve the arena from which we should allocate storage for a type.
18021803
static AllocationArena getArena(RecursiveTypeProperties properties) {
1803-
bool hasTypeVariable = properties.hasTypeVariable();
1804-
return hasTypeVariable ? AllocationArena::ConstraintSolver
1805-
: AllocationArena::Permanent;
1804+
return properties.isSolverAllocated() ? AllocationArena::ConstraintSolver
1805+
: AllocationArena::Permanent;
18061806
}
18071807

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

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

31323160
BuiltinIntegerType *BuiltinIntegerType::get(BuiltinIntegerWidth BitWidth,
@@ -3944,7 +3972,7 @@ isAnyFunctionTypeCanonical(ArrayRef<AnyFunctionType::Param> params,
39443972
static RecursiveTypeProperties
39453973
getGenericFunctionRecursiveProperties(ArrayRef<AnyFunctionType::Param> params,
39463974
Type result) {
3947-
static_assert(RecursiveTypeProperties::BitWidth == 15,
3975+
static_assert(RecursiveTypeProperties::BitWidth == 16,
39483976
"revisit this if you add new recursive type properties");
39493977
RecursiveTypeProperties properties;
39503978

@@ -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
@@ -8532,8 +8532,8 @@ namespace {
85328532
exprType = solution.simplifyType(exprType);
85338533
// assert((!expr->getType() || expr->getType()->isEqual(exprType)) &&
85348534
// "Mismatched types!");
8535-
assert(!exprType->hasTypeVariable() &&
8536-
"Should not write type variable into expression!");
8535+
assert(!exprType->getRecursiveProperties().isSolverAllocated() &&
8536+
"Should not write solver allocated type into expression!");
85378537
assert(!exprType->hasPlaceholder() &&
85388538
"Should not write type placeholders into expression!");
85398539
expr->setType(exprType);
@@ -8543,8 +8543,10 @@ namespace {
85438543
Type componentType;
85448544
if (cs.hasType(kp, i)) {
85458545
componentType = solution.simplifyType(cs.getType(kp, i));
8546-
assert(!componentType->hasTypeVariable() &&
8547-
"Should not write type variable into key-path component");
8546+
assert(
8547+
!componentType->getRecursiveProperties().isSolverAllocated() &&
8548+
"Should not write solver allocated type into key-path "
8549+
"component!");
85488550
assert(!componentType->hasPlaceholder() &&
85498551
"Should not write type placeholder into key-path component");
85508552
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)