Skip to content

Commit 24030c1

Browse files
committed
Sema: Introduce ConstraintKind::SubclassOf
1 parent 170280c commit 24030c1

File tree

5 files changed

+143
-1
lines changed

5 files changed

+143
-1
lines changed

include/swift/Sema/Constraint.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,9 @@ enum class ConstraintKind : char {
9797
ArgumentConversion,
9898
/// The first type is convertible to the second type, including inout.
9999
OperatorArgumentConversion,
100+
/// The first type must be a subclass of the second type (which is a
101+
/// class type).
102+
SubclassOf,
100103
/// The first type must conform to the second type (which is a
101104
/// protocol type).
102105
ConformsTo,
@@ -669,6 +672,7 @@ class Constraint final : public llvm::ilist_node<Constraint>,
669672
case ConstraintKind::BridgingConversion:
670673
case ConstraintKind::ArgumentConversion:
671674
case ConstraintKind::OperatorArgumentConversion:
675+
case ConstraintKind::SubclassOf:
672676
case ConstraintKind::ConformsTo:
673677
case ConstraintKind::LiteralConformsTo:
674678
case ConstraintKind::TransitivelyConformsTo:

include/swift/Sema/ConstraintSystem.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5423,6 +5423,15 @@ class ConstraintSystem {
54235423
FunctionRefKind functionRefKind,
54245424
ConstraintLocator *locator);
54255425

5426+
/// Attempt to simplify the given superclass constraint.
5427+
///
5428+
/// \param type The type being tested.
5429+
/// \param classType The class type which the type should be a subclass of.
5430+
/// \param locator Locator describing where this constraint occurred.
5431+
SolutionKind simplifySubclassOfConstraint(Type type, Type classType,
5432+
ConstraintLocatorBuilder locator,
5433+
TypeMatchOptions flags);
5434+
54265435
/// Attempt to simplify the given conformance constraint.
54275436
///
54285437
/// \param type The type being tested.

lib/Sema/CSBindings.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1281,6 +1281,7 @@ PotentialBindings::inferFromRelational(Constraint *constraint) {
12811281

12821282
switch (constraint->getKind()) {
12831283
case ConstraintKind::Subtype:
1284+
case ConstraintKind::SubclassOf:
12841285
case ConstraintKind::Conversion:
12851286
case ConstraintKind::ArgumentConversion:
12861287
case ConstraintKind::OperatorArgumentConversion: {
@@ -1358,6 +1359,7 @@ void PotentialBindings::infer(Constraint *constraint) {
13581359
case ConstraintKind::BindParam:
13591360
case ConstraintKind::BindToPointerType:
13601361
case ConstraintKind::Subtype:
1362+
case ConstraintKind::SubclassOf:
13611363
case ConstraintKind::Conversion:
13621364
case ConstraintKind::ArgumentConversion:
13631365
case ConstraintKind::OperatorArgumentConversion:

lib/Sema/CSSimplify.cpp

Lines changed: 123 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2362,6 +2362,7 @@ ConstraintSystem::matchTupleTypes(TupleType *tuple1, TupleType *tuple2,
23622362
case ConstraintKind::DynamicCallableApplicableFunction:
23632363
case ConstraintKind::BindOverload:
23642364
case ConstraintKind::CheckedCast:
2365+
case ConstraintKind::SubclassOf:
23652366
case ConstraintKind::ConformsTo:
23662367
case ConstraintKind::TransitivelyConformsTo:
23672368
case ConstraintKind::Defaultable:
@@ -2534,6 +2535,7 @@ static bool matchFunctionRepresentations(FunctionType::ExtInfo einfo1,
25342535
case ConstraintKind::DynamicCallableApplicableFunction:
25352536
case ConstraintKind::BindOverload:
25362537
case ConstraintKind::CheckedCast:
2538+
case ConstraintKind::SubclassOf:
25372539
case ConstraintKind::ConformsTo:
25382540
case ConstraintKind::TransitivelyConformsTo:
25392541
case ConstraintKind::Defaultable:
@@ -2948,6 +2950,7 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2,
29482950
case ConstraintKind::DynamicCallableApplicableFunction:
29492951
case ConstraintKind::BindOverload:
29502952
case ConstraintKind::CheckedCast:
2953+
case ConstraintKind::SubclassOf:
29512954
case ConstraintKind::ConformsTo:
29522955
case ConstraintKind::TransitivelyConformsTo:
29532956
case ConstraintKind::Defaultable:
@@ -6255,6 +6258,7 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
62556258
case ConstraintKind::BindOverload:
62566259
case ConstraintKind::BridgingConversion:
62576260
case ConstraintKind::CheckedCast:
6261+
case ConstraintKind::SubclassOf:
62586262
case ConstraintKind::ConformsTo:
62596263
case ConstraintKind::TransitivelyConformsTo:
62606264
case ConstraintKind::Defaultable:
@@ -7314,6 +7318,99 @@ ConstraintSystem::simplifyConstructionConstraint(
73147318
return SolutionKind::Solved;
73157319
}
73167320

7321+
ConstraintSystem::SolutionKind ConstraintSystem::simplifySubclassOfConstraint(
7322+
Type type,
7323+
Type classType,
7324+
ConstraintLocatorBuilder locator,
7325+
TypeMatchOptions flags) {
7326+
if (!classType->getClassOrBoundGenericClass())
7327+
return SolutionKind::Error;
7328+
7329+
// Dig out the fixed type to which this type refers.
7330+
type = getFixedTypeRecursive(type, flags, /*wantRValue=*/true);
7331+
if (shouldAttemptFixes() && type->isPlaceholder()) {
7332+
// If the type associated with this subclass check is a "hole" in the
7333+
// constraint system, let's consider this check a success without recording
7334+
// a fix, because it's just a consequence of the other failure, e.g.
7335+
//
7336+
// func foo<T: NSObject>(_: T) {}
7337+
// foo(Foo.bar) <- if `Foo` doesn't have `bar` there is
7338+
// no reason to complain the subclass.
7339+
return SolutionKind::Solved;
7340+
}
7341+
7342+
auto formUnsolved = [&](bool activate = false) {
7343+
// If we're supposed to generate constraints, do so.
7344+
if (flags.contains(TMF_GenerateConstraints)) {
7345+
auto *conformance = Constraint::create(
7346+
*this, ConstraintKind::SubclassOf, type, classType,
7347+
getConstraintLocator(locator));
7348+
7349+
addUnsolvedConstraint(conformance);
7350+
if (activate)
7351+
activateConstraint(conformance);
7352+
7353+
return SolutionKind::Solved;
7354+
}
7355+
7356+
return SolutionKind::Unsolved;
7357+
};
7358+
7359+
// If we hit a type variable without a fixed type, we can't
7360+
// solve this yet.
7361+
if (type->isTypeVariableOrMember())
7362+
return formUnsolved();
7363+
7364+
// SubclassOf constraints are generated when opening a generic
7365+
// signature with a RequirementKind::Superclass requirement, so
7366+
// we must handle pack types on the left by splitting up into
7367+
// smaller constraints.
7368+
if (auto *packType = type->getAs<PackType>()) {
7369+
for (unsigned i = 0, e = packType->getNumElements(); i < e; ++i) {
7370+
addConstraint(ConstraintKind::SubclassOf, packType->getElementType(i),
7371+
classType, locator.withPathElement(LocatorPathElt::PackElement(i)));
7372+
}
7373+
7374+
return SolutionKind::Solved;
7375+
}
7376+
7377+
// A class-constrained existential like 'C & P' does not satisfy an
7378+
// AnyObject requirement, if 'P' is not self-conforming.
7379+
//
7380+
// While matchSuperclassTypes() will still match here because 'C & P'
7381+
// satisfies a Subtype constraint with 'C', 'C & P' cannot satisfy a
7382+
// superclass requirement in a generic signature, so rule that out here.
7383+
if (type->satisfiesClassConstraint()) {
7384+
// If we have an exact match of class declarations, ensure the
7385+
// generic arguments match.
7386+
if (type->getClassOrBoundGenericClass() ==
7387+
classType->getClassOrBoundGenericClass()) {
7388+
auto result = matchTypes(type, classType, ConstraintKind::Bind,
7389+
flags, locator);
7390+
if (!result.isFailure())
7391+
return SolutionKind::Solved;
7392+
7393+
// Otherwise, ensure the left hand side is a proper subclass of the
7394+
// right hand side.
7395+
} else {
7396+
auto result = matchSuperclassTypes(type, classType, flags, locator);
7397+
if (!result.isFailure())
7398+
return SolutionKind::Solved;
7399+
}
7400+
}
7401+
7402+
// Record a fix if we didn't match one of the two cases above.
7403+
if (shouldAttemptFixes()) {
7404+
if (auto *fix = fixRequirementFailure(*this, type, classType, locator)) {
7405+
if (recordFix(fix))
7406+
return SolutionKind::Error;
7407+
return SolutionKind::Solved;
7408+
}
7409+
}
7410+
7411+
return SolutionKind::Error;
7412+
}
7413+
73177414
ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint(
73187415
Type type,
73197416
Type protocol,
@@ -7375,6 +7472,21 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint(
73757472
if (type->isTypeVariableOrMember())
73767473
return formUnsolved();
73777474

7475+
// ConformsTo constraints are generated when opening a generic
7476+
// signature with a RequirementKind::Conformance requirement, so
7477+
// we must handle pack types on the left by splitting up into
7478+
// smaller constraints.
7479+
if (auto *packType = type->getAs<PackType>()) {
7480+
for (unsigned i = 0, e = packType->getNumElements(); i < e; ++i) {
7481+
addConstraint(ConstraintKind::ConformsTo, packType->getElementType(i),
7482+
protocol->getDeclaredInterfaceType(),
7483+
locator.withPathElement(LocatorPathElt::PackElement(i)));
7484+
}
7485+
7486+
return SolutionKind::Solved;
7487+
}
7488+
7489+
73787490
auto *loc = getConstraintLocator(locator);
73797491

73807492
/// Record the given conformance as the result, adding any conditional
@@ -13551,6 +13663,9 @@ ConstraintSystem::addConstraintImpl(ConstraintKind kind, Type first,
1355113663
return simplifyOpenedExistentialOfConstraint(first, second,
1355213664
subflags, locator);
1355313665

13666+
case ConstraintKind::SubclassOf:
13667+
return simplifySubclassOfConstraint(first, second, locator, subflags);
13668+
1355413669
case ConstraintKind::ConformsTo:
1355513670
case ConstraintKind::LiteralConformsTo:
1355613671
case ConstraintKind::SelfObjectOfProtocol:
@@ -14029,6 +14144,13 @@ ConstraintSystem::simplifyConstraint(const Constraint &constraint) {
1402914144
constraint.getOverloadUseDC());
1403014145
return SolutionKind::Solved;
1403114146

14147+
case ConstraintKind::SubclassOf:
14148+
return simplifySubclassOfConstraint(
14149+
constraint.getFirstType(),
14150+
constraint.getSecondType(),
14151+
constraint.getLocator(),
14152+
/*flags*/ None);
14153+
1403214154
case ConstraintKind::ConformsTo:
1403314155
case ConstraintKind::LiteralConformsTo:
1403414156
case ConstraintKind::SelfObjectOfProtocol:
@@ -14049,7 +14171,7 @@ ConstraintSystem::simplifyConstraint(const Constraint &constraint) {
1404914171
case ConstraintKind::CheckedCast: {
1405014172
auto result = simplifyCheckedCastConstraint(constraint.getFirstType(),
1405114173
constraint.getSecondType(),
14052-
None,
14174+
/*flags*/ None,
1405314175
constraint.getLocator());
1405414176
// NOTE: simplifyCheckedCastConstraint() may return Unsolved, e.g. if the
1405514177
// subexpression's type is unresolved. Don't record the fix until we

lib/Sema/Constraint.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ Constraint::Constraint(ConstraintKind Kind, Type First, Type Second,
6464
case ConstraintKind::BridgingConversion:
6565
case ConstraintKind::ArgumentConversion:
6666
case ConstraintKind::OperatorArgumentConversion:
67+
case ConstraintKind::SubclassOf:
6768
case ConstraintKind::ConformsTo:
6869
case ConstraintKind::LiteralConformsTo:
6970
case ConstraintKind::TransitivelyConformsTo:
@@ -138,6 +139,7 @@ Constraint::Constraint(ConstraintKind Kind, Type First, Type Second, Type Third,
138139
case ConstraintKind::BridgingConversion:
139140
case ConstraintKind::ArgumentConversion:
140141
case ConstraintKind::OperatorArgumentConversion:
142+
case ConstraintKind::SubclassOf:
141143
case ConstraintKind::ConformsTo:
142144
case ConstraintKind::LiteralConformsTo:
143145
case ConstraintKind::TransitivelyConformsTo:
@@ -290,6 +292,7 @@ Constraint *Constraint::clone(ConstraintSystem &cs) const {
290292
case ConstraintKind::BridgingConversion:
291293
case ConstraintKind::ArgumentConversion:
292294
case ConstraintKind::OperatorArgumentConversion:
295+
case ConstraintKind::SubclassOf:
293296
case ConstraintKind::ConformsTo:
294297
case ConstraintKind::LiteralConformsTo:
295298
case ConstraintKind::TransitivelyConformsTo:
@@ -438,6 +441,7 @@ void Constraint::print(llvm::raw_ostream &Out, SourceManager *sm, unsigned inden
438441
case ConstraintKind::ArgumentConversion: Out << " arg conv "; break;
439442
case ConstraintKind::OperatorArgumentConversion:
440443
Out << " operator arg conv "; break;
444+
case ConstraintKind::SubclassOf: Out << " subclass of "; break;
441445
case ConstraintKind::ConformsTo: Out << " conforms to "; break;
442446
case ConstraintKind::LiteralConformsTo: Out << " literal conforms to "; break;
443447
case ConstraintKind::TransitivelyConformsTo: Out << " transitive conformance to "; break;
@@ -695,6 +699,7 @@ gatherReferencedTypeVars(Constraint *constraint,
695699
case ConstraintKind::OpenedExistentialOf:
696700
case ConstraintKind::OptionalObject:
697701
case ConstraintKind::Defaultable:
702+
case ConstraintKind::SubclassOf:
698703
case ConstraintKind::ConformsTo:
699704
case ConstraintKind::LiteralConformsTo:
700705
case ConstraintKind::TransitivelyConformsTo:

0 commit comments

Comments
 (0)