Skip to content

Commit 7e5e720

Browse files
authored
Merge pull request #64469 from slavapestov/more-variadic-generic-type-requirements
Checking requirements of variadic generic types (compile-time and runtime)
2 parents 999dbec + c50e8bb commit 7e5e720

File tree

10 files changed

+429
-144
lines changed

10 files changed

+429
-144
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2272,12 +2272,14 @@ NOTE(candidate_types_equal_requirement,none,
22722272
(Type, Type, Type, Type))
22732273
NOTE(candidate_types_same_shape_requirement,none,
22742274
"candidate requires that the type packs %0 and %1 have the same shape "
2275-
"(requirement specified as %2.shape == %3.shape)",
2275+
"(same-shape requirement inferred between %2 and %3)",
22762276
(Type, Type, Type, Type))
22772277
NOTE(candidate_types_inheritance_requirement,none,
22782278
"candidate requires that %1 inherit from %2 "
22792279
"(requirement specified as %2 : %3)",
22802280
(Type, Type, Type, Type))
2281+
NOTE(same_shape_requirement,none,
2282+
"same-shape requirement inferred between %0 and %1%2", (Type, Type, StringRef))
22812283
NOTE(types_not_equal_requirement,none,
22822284
"requirement specified as %0 == %1%2", (Type, Type, StringRef))
22832285
ERROR(type_is_not_a_class,none,

include/swift/AST/Requirement.h

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,28 @@
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 subject type is a pack type; the sub-requirements are the
40+
/// element-wise requirements which must be checked.
41+
PackRequirement,
42+
43+
/// The requirement cannot ever be satisfied.
44+
RequirementFailure,
45+
46+
/// Some other requirement is expected to fail, or there was an invalid
47+
/// conformance and an error should be diagnosed elsewhere, so this
48+
/// requirement does not need to be diagnosed.
49+
SubstitutionFailure
50+
};
51+
3052
/// A single requirement placed on the type parameters (or associated
3153
/// types thereof) of a
3254
class Requirement {
@@ -155,11 +177,12 @@ class Requirement {
155177

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

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

lib/AST/GenericSignature.cpp

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -405,10 +405,24 @@ 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::PackRequirement:
418+
// FIXME
419+
assert(false && "Refactor this");
420+
return true;
421+
422+
case CheckRequirementResult::RequirementFailure:
423+
case CheckRequirementResult::SubstitutionFailure:
424+
return false;
425+
}
412426
}
413427

414428
SmallVector<Requirement, 4>

lib/AST/Requirement.cpp

Lines changed: 70 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -76,45 +76,99 @@ 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+
85+
auto firstType = getFirstType();
86+
87+
auto expandPackRequirement = [&](PackType *packType) {
88+
for (auto eltType : packType->getElementTypes()) {
89+
// FIXME: Doesn't seem right
90+
if (auto *expansionType = eltType->getAs<PackExpansionType>())
91+
eltType = expansionType->getPatternType();
92+
93+
auto kind = getKind();
94+
if (kind == RequirementKind::Layout) {
95+
subReqs.emplace_back(kind, eltType,
96+
getLayoutConstraint());
97+
} else {
98+
subReqs.emplace_back(kind, eltType,
99+
getSecondType());
100+
}
101+
}
102+
return CheckRequirementResult::PackRequirement;
103+
};
104+
82105
switch (getKind()) {
83106
case RequirementKind::Conformance: {
107+
if (auto packType = firstType->getAs<PackType>()) {
108+
return expandPackRequirement(packType);
109+
}
110+
84111
auto *proto = getProtocolDecl();
85112
auto *module = proto->getParentModule();
86113
auto conformance = module->lookupConformance(
87-
getFirstType(), proto, allowMissing);
114+
firstType, proto, allowMissing);
88115
if (!conformance)
89-
return false;
116+
return CheckRequirementResult::RequirementFailure;
90117

91-
conditionalRequirements = conformance.getConditionalRequirements();
92-
return true;
118+
auto condReqs = conformance.getConditionalRequirements();
119+
if (condReqs.empty())
120+
return CheckRequirementResult::Success;
121+
subReqs.append(condReqs.begin(), condReqs.end());
122+
return CheckRequirementResult::ConditionalConformance;
93123
}
94124

95125
case RequirementKind::Layout: {
96-
if (auto *archetypeType = getFirstType()->getAs<ArchetypeType>()) {
126+
if (auto packType = firstType->getAs<PackType>()) {
127+
return expandPackRequirement(packType);
128+
}
129+
130+
if (auto *archetypeType = firstType->getAs<ArchetypeType>()) {
97131
auto layout = archetypeType->getLayoutConstraint();
98-
return (layout && layout.merge(getLayoutConstraint()));
132+
if (layout && layout.merge(getLayoutConstraint()))
133+
return CheckRequirementResult::Success;
134+
135+
return CheckRequirementResult::RequirementFailure;
99136
}
100137

101-
if (getLayoutConstraint()->isClass())
102-
return getFirstType()->satisfiesClassConstraint();
138+
if (getLayoutConstraint()->isClass()) {
139+
if (firstType->satisfiesClassConstraint())
140+
return CheckRequirementResult::Success;
141+
142+
return CheckRequirementResult::RequirementFailure;
143+
}
103144

104145
// TODO: Statically check other layout constraints, once they can
105146
// be spelled in Swift.
106-
return true;
147+
return CheckRequirementResult::Success;
107148
}
108149

109150
case RequirementKind::Superclass:
110-
return getSecondType()->isExactSuperclassOf(getFirstType());
151+
if (auto packType = firstType->getAs<PackType>()) {
152+
return expandPackRequirement(packType);
153+
}
154+
155+
if (getSecondType()->isExactSuperclassOf(firstType))
156+
return CheckRequirementResult::Success;
157+
158+
return CheckRequirementResult::RequirementFailure;
111159

112160
case RequirementKind::SameType:
113-
return getFirstType()->isEqual(getSecondType());
161+
if (firstType->isEqual(getSecondType()))
162+
return CheckRequirementResult::Success;
163+
164+
return CheckRequirementResult::RequirementFailure;
114165

115166
case RequirementKind::SameShape:
116-
return (getFirstType()->getReducedShape() ==
117-
getSecondType()->getReducedShape());
167+
if (firstType->getReducedShape() ==
168+
getSecondType()->getReducedShape())
169+
return CheckRequirementResult::Success;
170+
171+
return CheckRequirementResult::RequirementFailure;
118172
}
119173

120174
llvm_unreachable("Bad requirement kind");

lib/IDE/IDETypeChecking.cpp

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -344,16 +344,30 @@ 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::PackRequirement:
358+
// FIXME
359+
assert(false && "Refactor this");
360+
return true;
361+
362+
case CheckRequirementResult::SubstitutionFailure:
348363
return true;
349364

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

356369
MergeInfo.addRequirement(Req);
370+
break;
357371
}
358372
}
359373
return false;

0 commit comments

Comments
 (0)