Skip to content

Commit d27231a

Browse files
committed
AST: Generalize Requirement::isSatisfied() to Requirement::checkRequirement()
1 parent 2e92542 commit d27231a

File tree

5 files changed

+139
-79
lines changed

5 files changed

+139
-79
lines changed

include/swift/AST/Requirement.h

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,24 @@
2727

2828
namespace swift {
2929

30+
/// Return type of Requirement::checkRequirement().
31+
enum class CheckRequirementResult : uint8_t {
32+
/// The requirement was fully satisfied.
33+
Success,
34+
35+
/// The subject type conforms conditionally; the sub-requirements are
36+
/// conditional requirements which must be checked.
37+
ConditionalConformance,
38+
39+
/// The requirement cannot ever be satisfied.
40+
RequirementFailure,
41+
42+
/// Some other requirement is expected to fail, or there was an invalid
43+
/// conformance and an error should be diagnosed elsewhere, so this
44+
/// requirement does not need to be diagnosed.
45+
SubstitutionFailure
46+
};
47+
3048
/// A single requirement placed on the type parameters (or associated
3149
/// types thereof) of a
3250
class Requirement {
@@ -155,11 +173,12 @@ class Requirement {
155173

156174
/// Determines if this substituted requirement is satisfied.
157175
///
158-
/// \param conditionalRequirements An out parameter initialized to an
159-
/// array of requirements that the caller must check to ensure this
176+
/// \param subReqs An out parameter initialized to a list of simpler
177+
/// requirements which the caller must check to ensure this
160178
/// requirement is completely satisfied.
161-
bool isSatisfied(ArrayRef<Requirement> &conditionalRequirements,
162-
bool allowMissing = false) const;
179+
CheckRequirementResult checkRequirement(
180+
SmallVectorImpl<Requirement> &subReqs,
181+
bool allowMissing = false) const;
163182

164183
/// Determines if this substituted requirement can ever be satisfied,
165184
/// possibly with additional substitutions.

lib/AST/GenericSignature.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -405,10 +405,19 @@ bool GenericSignatureImpl::isRequirementSatisfied(
405405
LookUpConformanceInSignature(this));
406406
}
407407

408-
// FIXME: Need to check conditional requirements here.
409-
ArrayRef<Requirement> conditionalRequirements;
408+
SmallVector<Requirement, 2> subReqs;
409+
switch (requirement.checkRequirement(subReqs, allowMissing)) {
410+
case CheckRequirementResult::Success:
411+
return true;
412+
413+
case CheckRequirementResult::ConditionalConformance:
414+
// FIXME: Need to check conditional requirements here.
415+
return true;
410416

411-
return requirement.isSatisfied(conditionalRequirements, allowMissing);
417+
case CheckRequirementResult::RequirementFailure:
418+
case CheckRequirementResult::SubstitutionFailure:
419+
return false;
420+
}
412421
}
413422

414423
SmallVector<Requirement, 4>

lib/AST/Requirement.cpp

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -76,45 +76,67 @@ ProtocolDecl *Requirement::getProtocolDecl() const {
7676
return getSecondType()->castTo<ProtocolType>()->getDecl();
7777
}
7878

79-
bool
80-
Requirement::isSatisfied(ArrayRef<Requirement> &conditionalRequirements,
81-
bool allowMissing) const {
79+
CheckRequirementResult Requirement::checkRequirement(
80+
SmallVectorImpl<Requirement> &subReqs,
81+
bool allowMissing) const {
82+
if (hasError())
83+
return CheckRequirementResult::SubstitutionFailure;
84+
8285
switch (getKind()) {
8386
case RequirementKind::Conformance: {
8487
auto *proto = getProtocolDecl();
8588
auto *module = proto->getParentModule();
8689
auto conformance = module->lookupConformance(
8790
getFirstType(), proto, allowMissing);
8891
if (!conformance)
89-
return false;
92+
return CheckRequirementResult::RequirementFailure;
9093

91-
conditionalRequirements = conformance.getConditionalRequirements();
92-
return true;
94+
auto condReqs = conformance.getConditionalRequirements();
95+
if (condReqs.empty())
96+
return CheckRequirementResult::Success;
97+
subReqs.append(condReqs.begin(), condReqs.end());
98+
return CheckRequirementResult::ConditionalConformance;
9399
}
94100

95101
case RequirementKind::Layout: {
96102
if (auto *archetypeType = getFirstType()->getAs<ArchetypeType>()) {
97103
auto layout = archetypeType->getLayoutConstraint();
98-
return (layout && layout.merge(getLayoutConstraint()));
104+
if (layout && layout.merge(getLayoutConstraint()))
105+
return CheckRequirementResult::Success;
106+
107+
return CheckRequirementResult::RequirementFailure;
99108
}
100109

101-
if (getLayoutConstraint()->isClass())
102-
return getFirstType()->satisfiesClassConstraint();
110+
if (getLayoutConstraint()->isClass()) {
111+
if (getFirstType()->satisfiesClassConstraint())
112+
return CheckRequirementResult::Success;
113+
114+
return CheckRequirementResult::RequirementFailure;
115+
}
103116

104117
// TODO: Statically check other layout constraints, once they can
105118
// be spelled in Swift.
106-
return true;
119+
return CheckRequirementResult::Success;
107120
}
108121

109122
case RequirementKind::Superclass:
110-
return getSecondType()->isExactSuperclassOf(getFirstType());
123+
if (getSecondType()->isExactSuperclassOf(getFirstType()))
124+
return CheckRequirementResult::Success;
125+
126+
return CheckRequirementResult::RequirementFailure;
111127

112128
case RequirementKind::SameType:
113-
return getFirstType()->isEqual(getSecondType());
129+
if (getFirstType()->isEqual(getSecondType()))
130+
return CheckRequirementResult::Success;
131+
132+
return CheckRequirementResult::RequirementFailure;
114133

115134
case RequirementKind::SameShape:
116-
return (getFirstType()->getReducedShape() ==
117-
getSecondType()->getReducedShape());
135+
if (getFirstType()->getReducedShape() ==
136+
getSecondType()->getReducedShape())
137+
return CheckRequirementResult::Success;
138+
139+
return CheckRequirementResult::RequirementFailure;
118140
}
119141

120142
llvm_unreachable("Bad requirement kind");

lib/IDE/IDETypeChecking.cpp

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -344,16 +344,25 @@ struct SynthesizedExtensionAnalyzer::Implementation {
344344
return type;
345345
},
346346
LookUpConformanceInModule(M));
347-
if (SubstReq.hasError())
347+
348+
SmallVector<Requirement, 2> subReqs;
349+
switch (SubstReq.checkRequirement(subReqs)) {
350+
case CheckRequirementResult::Success:
351+
break;
352+
353+
case CheckRequirementResult::ConditionalConformance:
354+
// FIXME: Need to handle conditional requirements here!
355+
break;
356+
357+
case CheckRequirementResult::SubstitutionFailure:
348358
return true;
349359

350-
// FIXME: Need to handle conditional requirements here!
351-
ArrayRef<Requirement> conditionalRequirements;
352-
if (!SubstReq.isSatisfied(conditionalRequirements)) {
360+
case CheckRequirementResult::RequirementFailure:
353361
if (!SubstReq.canBeSatisfied())
354362
return true;
355363

356364
MergeInfo.addRequirement(Req);
365+
break;
357366
}
358367
}
359368
return false;

lib/Sema/TypeCheckGeneric.cpp

Lines changed: 55 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -886,66 +886,64 @@ CheckGenericArgumentsResult TypeChecker::checkGenericArgumentsForDiagnostics(
886886
SmallVector<ParentConditionalConformance, 2>;
887887

888888
struct WorklistItem {
889-
/// The set of requirements to check. These are either the primary set
890-
/// of requirements, or the conditional requirements of the last conformance
891-
/// in \c ReqsPath (if any).
892-
ArrayRef<Requirement> Requirements;
889+
/// The requirement to check. This is either a top-level requirement or
890+
/// a conditional requirements of the last conformancein \c ReqsPath
891+
/// (if any).
892+
Requirement Req;
893893

894894
/// The chain of conditional conformances that leads to the above
895895
/// requirement set.
896-
ParentConditionalConformances ReqsPath;
896+
ParentConditionalConformances Path;
897897

898-
WorklistItem(ArrayRef<Requirement> Requirements,
899-
ParentConditionalConformances ReqsPath)
900-
: Requirements(Requirements), ReqsPath(ReqsPath) {}
898+
WorklistItem(Requirement Req, ParentConditionalConformances Path)
899+
: Req(Req), Path(Path) {}
901900
};
902901

903902
bool hadSubstFailure = false;
904903
SmallVector<WorklistItem, 4> worklist;
905904

906-
worklist.emplace_back(requirements, ParentConditionalConformances{});
905+
for (auto req : llvm::reverse(requirements))
906+
worklist.emplace_back(req, ParentConditionalConformances{});
907+
907908
while (!worklist.empty()) {
908909
const auto item = worklist.pop_back_val();
909910

910-
const bool isPrimaryReq = item.ReqsPath.empty();
911-
for (const auto &req : item.Requirements) {
912-
Requirement substReq = req;
913-
if (isPrimaryReq) {
914-
// Primary requirements do not have substitutions applied.
915-
auto resolved =
916-
req.subst(substitutions, LookUpConformanceInModule(module));
917-
if (!resolved.hasError()) {
918-
substReq = resolved;
919-
} else {
920-
// Another requirement might fail later; just continue.
921-
hadSubstFailure = true;
922-
continue;
923-
}
924-
}
925-
926-
ArrayRef<Requirement> conditionalRequirements;
927-
if (!substReq.isSatisfied(conditionalRequirements,
928-
/*allowMissing=*/true)) {
929-
return CheckGenericArgumentsResult::createRequirementFailure(
930-
req, substReq, std::move(item.ReqsPath));
931-
}
911+
auto req = item.Req;
912+
auto substReq = item.Req;
913+
if (item.Path.empty()) {
914+
// Primary requirements do not have substitutions applied.
915+
substReq =
916+
req.subst(substitutions, LookUpConformanceInModule(module));
917+
}
932918

933-
if (conditionalRequirements.empty()) {
934-
continue;
935-
}
919+
SmallVector<Requirement, 2> subReqs;
920+
switch (substReq.checkRequirement(subReqs, /*allowMissing=*/true)) {
921+
case CheckRequirementResult::Success:
922+
break;
936923

937-
assert(req.getKind() == RequirementKind::Conformance);
924+
case CheckRequirementResult::ConditionalConformance: {
925+
assert(substReq.getKind() == RequirementKind::Conformance);
938926

939-
auto reqsPath = item.ReqsPath;
927+
auto reqsPath = item.Path;
940928
reqsPath.push_back({substReq.getFirstType(), substReq.getProtocolDecl()});
941929

942-
worklist.emplace_back(conditionalRequirements, std::move(reqsPath));
930+
for (auto subReq : subReqs)
931+
worklist.emplace_back(subReq, reqsPath);
932+
break;
933+
}
934+
935+
case CheckRequirementResult::RequirementFailure:
936+
return CheckGenericArgumentsResult::createRequirementFailure(
937+
req, substReq, std::move(item.Path));
938+
939+
case CheckRequirementResult::SubstitutionFailure:
940+
hadSubstFailure = true;
941+
break;
943942
}
944943
}
945944

946-
if (hadSubstFailure) {
945+
if (hadSubstFailure)
947946
return CheckGenericArgumentsResult::createSubstitutionFailure();
948-
}
949947

950948
return CheckGenericArgumentsResult::createSuccess();
951949
}
@@ -954,31 +952,34 @@ CheckGenericArgumentsResult::Kind TypeChecker::checkGenericArguments(
954952
ModuleDecl *module, ArrayRef<Requirement> requirements,
955953
TypeSubstitutionFn substitutions, SubstOptions options) {
956954
SmallVector<Requirement, 4> worklist;
957-
bool valid = true;
955+
956+
bool hadSubstFailure = false;
958957

959958
for (auto req : requirements) {
960-
auto resolved = req.subst(substitutions,
961-
LookUpConformanceInModule(module), options);
962-
if (!resolved.hasError()) {
963-
worklist.push_back(resolved);
964-
} else {
965-
valid = false;
966-
}
959+
worklist.push_back(req.subst(substitutions,
960+
LookUpConformanceInModule(module), options));
967961
}
968962

969963
while (!worklist.empty()) {
970964
auto req = worklist.pop_back_val();
971-
ArrayRef<Requirement> conditionalRequirements;
972-
if (!req.isSatisfied(conditionalRequirements, /*allowMissing=*/true))
965+
switch (req.checkRequirement(worklist, /*allowMissing=*/true)) {
966+
case CheckRequirementResult::Success:
967+
case CheckRequirementResult::ConditionalConformance:
968+
break;
969+
970+
case CheckRequirementResult::RequirementFailure:
973971
return CheckGenericArgumentsResult::RequirementFailure;
974972

975-
worklist.append(conditionalRequirements.begin(),
976-
conditionalRequirements.end());
973+
case CheckRequirementResult::SubstitutionFailure:
974+
hadSubstFailure = true;
975+
break;
976+
}
977977
}
978978

979-
if (valid)
980-
return CheckGenericArgumentsResult::Success;
981-
return CheckGenericArgumentsResult::SubstitutionFailure;
979+
if (hadSubstFailure)
980+
return CheckGenericArgumentsResult::SubstitutionFailure;
981+
982+
return CheckGenericArgumentsResult::Success;
982983
}
983984

984985
Requirement

0 commit comments

Comments
 (0)