Skip to content

Commit fe06df8

Browse files
committed
AST: Move guts of checkGenericArguments() to a new Requirement::isSatisfied() method
1 parent 40aa87c commit fe06df8

File tree

3 files changed

+88
-39
lines changed

3 files changed

+88
-39
lines changed

include/swift/AST/Requirement.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,21 @@ class Requirement
7676

7777
ProtocolDecl *getProtocolDecl() const;
7878

79+
/// Determines if this substituted requirement is satisfied.
80+
///
81+
/// \param conditionalRequirements An out parameter initialized to an
82+
/// array of requirements that the caller must check to ensure this
83+
/// requirement is completely satisfied.
84+
bool isSatisfied(ArrayRef<Requirement> &conditionalRequirements) const;
85+
86+
/// Determines if this substituted requirement can ever be satisfied,
87+
/// possibly with additional substitutions.
88+
///
89+
/// For example, if 'T' is unconstrained, then a superclass requirement
90+
/// 'T : C' can be satisfied; however, if 'T' already has an unrelated
91+
/// superclass requirement, 'T : C' cannot be satisfied.
92+
bool canBeSatisfied() const;
93+
7994
SWIFT_DEBUG_DUMP;
8095
void dump(raw_ostream &out) const;
8196
void print(raw_ostream &os, const PrintOptions &opts) const;

lib/AST/GenericSignature.cpp

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -722,3 +722,67 @@ ProtocolDecl *Requirement::getProtocolDecl() const {
722722
assert(getKind() == RequirementKind::Conformance);
723723
return getSecondType()->castTo<ProtocolType>()->getDecl();
724724
}
725+
726+
bool
727+
Requirement::isSatisfied(ArrayRef<Requirement> &conditionalRequirements) const {
728+
switch (getKind()) {
729+
case RequirementKind::Conformance: {
730+
auto *proto = getProtocolDecl();
731+
auto *module = proto->getParentModule();
732+
auto conformance = module->lookupConformance(getFirstType(), proto);
733+
if (!conformance)
734+
return false;
735+
736+
conditionalRequirements = conformance.getConditionalRequirements();
737+
return true;
738+
}
739+
740+
case RequirementKind::Layout: {
741+
if (auto *archetypeType = getFirstType()->getAs<ArchetypeType>()) {
742+
auto layout = archetypeType->getLayoutConstraint();
743+
return (layout && layout.merge(getLayoutConstraint()));
744+
}
745+
746+
if (getLayoutConstraint()->isClass())
747+
return getFirstType()->satisfiesClassConstraint();
748+
749+
// TODO: Statically check other layout constraints, once they can
750+
// be spelled in Swift.
751+
return true;
752+
}
753+
754+
case RequirementKind::Superclass:
755+
return getSecondType()->isExactSuperclassOf(getFirstType());
756+
757+
case RequirementKind::SameType:
758+
return getFirstType()->isEqual(getSecondType());
759+
}
760+
761+
llvm_unreachable("Bad requirement kind");
762+
}
763+
764+
bool Requirement::canBeSatisfied() const {
765+
switch (getKind()) {
766+
case RequirementKind::Conformance:
767+
return getFirstType()->is<ArchetypeType>();
768+
769+
case RequirementKind::Layout: {
770+
if (auto *archetypeType = getFirstType()->getAs<ArchetypeType>()) {
771+
auto layout = archetypeType->getLayoutConstraint();
772+
return (!layout || layout.merge(getLayoutConstraint()));
773+
}
774+
775+
return false;
776+
}
777+
778+
case RequirementKind::Superclass:
779+
return (getFirstType()->isBindableTo(getSecondType()) ||
780+
getSecondType()->isBindableTo(getFirstType()));
781+
782+
case RequirementKind::SameType:
783+
return (getFirstType()->isBindableTo(getSecondType()) ||
784+
getSecondType()->isBindableTo(getFirstType()));
785+
}
786+
787+
llvm_unreachable("Bad requirement kind");
788+
}

lib/Sema/TypeCheckGeneric.cpp

Lines changed: 9 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -791,47 +791,17 @@ RequirementCheckResult TypeChecker::checkGenericArguments(
791791
req = *substed;
792792
}
793793

794-
auto checkRequirement = [&]() {
795-
switch (req.getKind()) {
796-
case RequirementKind::Conformance: {
797-
// Protocol conformance requirements.
798-
auto proto = req.getProtocolDecl();
799-
auto conformance = module->lookupConformance(
800-
req.getFirstType(), proto);
801-
802-
if (!conformance)
803-
return false;
804-
805-
auto conditionalReqs = conformance.getConditionalRequirements();
806-
if (!conditionalReqs.empty()) {
807-
auto history = current.Parents;
808-
history.push_back({req.getFirstType(), proto});
809-
pendingReqs.push_back({conditionalReqs, std::move(history)});
810-
}
811-
812-
return true;
813-
}
814-
815-
case RequirementKind::Layout: {
816-
// TODO: Statically check other layout constraints, once they can
817-
// be spelled in Swift.
818-
if (req.getLayoutConstraint()->isClass() &&
819-
!req.getFirstType()->satisfiesClassConstraint())
820-
return false;
821-
822-
return true;
823-
}
824-
825-
case RequirementKind::Superclass:
826-
return req.getSecondType()->isExactSuperclassOf(req.getFirstType());
827-
828-
case RequirementKind::SameType:
829-
return req.getFirstType()->isEqual(req.getSecondType());
794+
ArrayRef<Requirement> conditionalRequirements;
795+
if (req.isSatisfied(conditionalRequirements)) {
796+
if (!conditionalRequirements.empty()) {
797+
assert(req.getKind() == RequirementKind::Conformance);
798+
799+
auto history = current.Parents;
800+
history.push_back({req.getFirstType(), req.getProtocolDecl()});
801+
pendingReqs.push_back({conditionalRequirements, std::move(history)});
830802
}
831-
};
832-
833-
if (checkRequirement())
834803
continue;
804+
}
835805

836806
if (loc.isValid()) {
837807
Diag<Type, Type, Type> diagnostic;

0 commit comments

Comments
 (0)