Skip to content

Commit 7a0d3e1

Browse files
committed
[CS] Avoid solver-allocated inputs with typesSatisfyConstraint
Escaping solver-allocated types into a nested allocation arena is problematic since we can e.g lazily compute the `ContextSubMap` for a `NominalOrBoundGenericNominalType`, which is then destroyed when we exit the nested arena. Ensure we don't pass any types with type variables or placeholders to `typesSatisfyConstraint`. rdar://152763265
1 parent 94af768 commit 7a0d3e1

File tree

10 files changed

+49
-25
lines changed

10 files changed

+49
-25
lines changed

include/swift/AST/Types.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -720,6 +720,12 @@ class alignas(1 << TypeAlignInBits) TypeBase
720720
return getRecursiveProperties().hasTypeVariable();
721721
}
722722

723+
// Convenience for checking whether the given type either has a type
724+
// variable or placeholder.
725+
bool hasTypeVariableOrPlaceholder() const {
726+
return hasTypeVariable() || hasPlaceholder();
727+
}
728+
723729
/// Determine where this type is a type variable or a dependent
724730
/// member root in a type variable.
725731
bool isTypeVariableOrMember();

lib/Sema/CSFix.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,9 +185,12 @@ CoerceToCheckedCast *CoerceToCheckedCast::attempt(ConstraintSystem &cs,
185185
Type fromType, Type toType,
186186
bool useConditionalCast,
187187
ConstraintLocator *locator) {
188-
// If any of the types has a type variable, don't add the fix.
189-
if (fromType->hasTypeVariable() || toType->hasTypeVariable())
188+
// If any of the types have type variables or placeholders, don't add the fix.
189+
// `typeCheckCheckedCast` doesn't support checking such types.
190+
if (fromType->hasTypeVariableOrPlaceholder() ||
191+
toType->hasTypeVariableOrPlaceholder()) {
190192
return nullptr;
193+
}
191194

192195
auto anchor = locator->getAnchor();
193196
if (auto *assignExpr = getAsExpr<AssignExpr>(anchor))

lib/Sema/CSRanking.cpp

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1413,11 +1413,10 @@ SolutionCompareResult ConstraintSystem::compareSolutions(
14131413
auto type1 = types.Type1;
14141414
auto type2 = types.Type2;
14151415

1416-
// If either of the types still contains type variables, we can't
1417-
// compare them.
1418-
// FIXME: This is really unfortunate. More type variable sharing
1419-
// (when it's sound) would help us do much better here.
1420-
if (type1->hasTypeVariable() || type2->hasTypeVariable()) {
1416+
// If either of the types have holes or unresolved type variables, we can't
1417+
// compare them. `isSubtypeOf` cannot be used with solver-allocated types.
1418+
if (type1->hasTypeVariableOrPlaceholder() ||
1419+
type2->hasTypeVariableOrPlaceholder()) {
14211420
identical = false;
14221421
continue;
14231422
}
@@ -1454,15 +1453,12 @@ SolutionCompareResult ConstraintSystem::compareSolutions(
14541453
// The systems are not considered equivalent.
14551454
identical = false;
14561455

1457-
// Archetypes are worse than concrete types (i.e. non-placeholder and
1458-
// non-archetype)
1456+
// Archetypes are worse than concrete types
14591457
// FIXME: Total hack.
1460-
if (type1->is<ArchetypeType>() && !type2->is<ArchetypeType>() &&
1461-
!type2->is<PlaceholderType>()) {
1458+
if (type1->is<ArchetypeType>() && !type2->is<ArchetypeType>()) {
14621459
++score2;
14631460
continue;
1464-
} else if (type2->is<ArchetypeType>() && !type1->is<ArchetypeType>() &&
1465-
!type1->is<PlaceholderType>()) {
1461+
} else if (type2->is<ArchetypeType>() && !type1->is<ArchetypeType>()) {
14661462
++score1;
14671463
continue;
14681464
}

lib/Sema/CSSimplify.cpp

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4909,8 +4909,12 @@ static bool
49094909
repairViaBridgingCast(ConstraintSystem &cs, Type fromType, Type toType,
49104910
SmallVectorImpl<RestrictionOrFix> &conversionsOrFixes,
49114911
ConstraintLocatorBuilder locator) {
4912-
if (fromType->hasTypeVariable() || toType->hasTypeVariable())
4912+
// Don't check if any of the types have type variables or placeholders,
4913+
// `typeCheckCheckedCast` doesn't support checking solver-allocated types.
4914+
if (fromType->hasTypeVariableOrPlaceholder() ||
4915+
toType->hasTypeVariableOrPlaceholder()) {
49134916
return false;
4917+
}
49144918

49154919
auto objectType1 = fromType->getOptionalObjectType();
49164920
auto objectType2 = toType->getOptionalObjectType();
@@ -9375,10 +9379,12 @@ static ConstraintFix *maybeWarnAboutExtraneousCast(
93759379
if (locator.endsWith<LocatorPathElt::GenericArgument>())
93769380
return nullptr;
93779381

9378-
// Both types have to be fixed.
9379-
if (fromType->hasTypeVariable() || toType->hasTypeVariable() ||
9380-
fromType->hasPlaceholder() || toType->hasPlaceholder())
9382+
// Both types have to be resolved, `typeCheckCheckedCast` doesn't support
9383+
// checking solver-allocated types.
9384+
if (fromType->hasTypeVariableOrPlaceholder() ||
9385+
toType->hasTypeVariableOrPlaceholder()) {
93819386
return nullptr;
9387+
}
93829388

93839389
SmallVector<LocatorPathElt, 4> path;
93849390
auto anchor = locator.getLocatorParts(path);

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1080,8 +1080,14 @@ bool TypeChecker::typesSatisfyConstraint(Type type1, Type type2,
10801080
bool openArchetypes,
10811081
ConstraintKind kind, DeclContext *dc,
10821082
bool *unwrappedIUO) {
1083-
assert(!type1->hasTypeVariable() && !type2->hasTypeVariable() &&
1084-
"Unexpected type variable in constraint satisfaction testing");
1083+
// Don't allow any type variables to leak into the nested ConstraintSystem
1084+
// (including as originator types for placeholders). This also ensure that we
1085+
// avoid lifetime issues for e.g cases where we lazily populate the
1086+
// `ContextSubMap` on `NominalOrBoundGenericNominalType` in the nested arena,
1087+
// since it will be destroyed on leaving.
1088+
ASSERT(!type1->getRecursiveProperties().isSolverAllocated() &&
1089+
!type2->getRecursiveProperties().isSolverAllocated() &&
1090+
"Cannot escape solver-allocated types into a nested ConstraintSystem");
10851091

10861092
ConstraintSystem cs(dc, ConstraintSystemOptions());
10871093
if (openArchetypes) {
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// {"signature":"bool llvm::function_ref<bool (swift::ProtocolConformanceRef)>::callback_fn<(anonymous namespace)::MismatchedIsolatedConformances>(long, swift::ProtocolConformanceRef)"}
2+
// RUN: not %target-swift-frontend -typecheck %s
3+
func a {
4+
{ print("\(\ " ")\n"
5+
}
6+
"\()\n"
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
11
// {"signature":"swift::ProtocolConformanceRef::forEachMissingConformance(llvm::function_ref<bool (swift::BuiltinProtocolConformance*)>) const"}
2-
// RUN: not --crash %target-swift-frontend -typecheck %s
3-
// REQUIRES: rdar152763265
2+
// RUN: not %target-swift-frontend -typecheck %s
43
.a == .! == b / c
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
11
// {"signature":"swift::GenericParamKey::findIndexIn(llvm::ArrayRef<swift::GenericTypeParamType*>) const"}
2-
// RUN: not --crash %target-swift-frontend -typecheck %s
3-
// REQUIRES: rdar152763265
2+
// RUN: not %target-swift-frontend -typecheck %s
43
a[[[[ a a?[[a a?
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
// {"signature":"swift::ProtocolConformanceRef::forAbstract(swift::Type, swift::ProtocolDecl*)"}
2-
// RUN: not --crash %target-swift-frontend -typecheck %s
3-
// REQUIRES: rdar152763265
2+
// RUN: not %target-swift-frontend -typecheck %s
43
@resultBuilder struct a {
54
static buildBlock<b, c, d, e>(b, c, d, e) func f<h>(_ : Bool @a Bool->h) { f(true {
65
cond in var g : Int g 2 30\ g
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// {"signature":"(anonymous namespace)::ApplyClassifier::classifyApply(swift::ApplyExpr*, llvm::DenseSet<swift::Expr const*, llvm::DenseMapInfo<swift::Expr const*, void>>*)"}
2+
// RUN: not %target-swift-frontend -typecheck %s
3+
let a = switch \0 {
4+
case 0.0

0 commit comments

Comments
 (0)