Skip to content

Commit f4d58b3

Browse files
authored
Merge pull request #42203 from slavapestov/rqm-fixes-5.7
Cherry-pick RequirementMachine fixes to 5.7 branch
2 parents 013270a + 9a6a9a1 commit f4d58b3

19 files changed

+344
-122
lines changed

include/swift/AST/TypeCheckRequests.h

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -604,7 +604,6 @@ struct WhereClauseOwner {
604604
return !(lhs == rhs);
605605
}
606606

607-
public:
608607
/// Retrieve the array of requirements.
609608
MutableArrayRef<RequirementRepr> getRequirements() const;
610609

@@ -1903,8 +1902,7 @@ class InferredGenericSignatureRequest :
19031902
/// InferredGenericSignatureRequest.
19041903
class InferredGenericSignatureRequestRQM :
19051904
public SimpleRequest<InferredGenericSignatureRequestRQM,
1906-
GenericSignatureWithError (ModuleDecl *,
1907-
const GenericSignatureImpl *,
1905+
GenericSignatureWithError (const GenericSignatureImpl *,
19081906
GenericParamList *,
19091907
WhereClauseOwner,
19101908
SmallVector<Requirement, 2>,
@@ -1920,7 +1918,6 @@ class InferredGenericSignatureRequestRQM :
19201918
// Evaluation.
19211919
GenericSignatureWithError
19221920
evaluate(Evaluator &evaluator,
1923-
ModuleDecl *parentModule,
19241921
const GenericSignatureImpl *baseSignature,
19251922
GenericParamList *genericParams,
19261923
WhereClauseOwner whereClause,

lib/AST/GenericSignatureBuilder.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8464,7 +8464,6 @@ InferredGenericSignatureRequest::evaluate(
84648464
return evaluateOrDefault(
84658465
ctx.evaluator,
84668466
InferredGenericSignatureRequestRQM{
8467-
parentModule,
84688467
parentSig,
84698468
genericParams,
84708469
whereClause,

lib/AST/RequirementMachine/KnuthBendix.cpp

Lines changed: 65 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -157,8 +157,66 @@ RewriteSystem::computeCriticalPair(ArrayRef<Symbol>::const_iterator from,
157157
return false;
158158
}
159159

160-
// Add the pair (X, TYV).
161-
pairs.emplace_back(x, tyv, path);
160+
// If X == TUW for some W, then the critical pair is (TUW, TYV),
161+
// and we have
162+
// - lhs == (TUV => TUW)
163+
// - rhs == (U => Y).
164+
//
165+
// We explicitly apply the rewrite step (Y => U) to the beginning of the
166+
// rewrite path, transforming the critical pair to (TYW, TYV).
167+
//
168+
// In particular, if V == W.[P] for some protocol P, then we in fact have
169+
// a property rule and a same-type rule:
170+
//
171+
// - lhs == (TUW.[P] => TUW)
172+
// - rhs == (U => Y)
173+
//
174+
// Without this hack, the critical pair would be:
175+
//
176+
// (TUW => TYW.[P])
177+
//
178+
// With this hack, the critical pair becomes:
179+
//
180+
// (TYW.[P] => TYW)
181+
//
182+
// This ensures that the newly-added rule is itself a property rule;
183+
// otherwise, this would only be the case if addRule() reduced TUW
184+
// into TYW without immediately reducing some subterm of TUW first.
185+
//
186+
// While completion will eventually simplify all such rules down into
187+
// property rules, their existance in the first place breaks subtle
188+
// invariants in the minimal conformances algorithm, which expects
189+
// homotopy generators describing redundant protocol conformance rules
190+
// to have a certain structure.
191+
if (t.size() + rhs.getLHS().size() <= x.size() &&
192+
std::equal(rhs.getLHS().begin(),
193+
rhs.getLHS().end(),
194+
x.begin() + t.size())) {
195+
// We have a path from TUW to TYV. Invert to get a path from TYV to
196+
// TUW.
197+
path.invert();
198+
199+
// Compute the term W.
200+
MutableTerm w(x.begin() + t.size() + rhs.getLHS().size(), x.end());
201+
202+
// Now add a rewrite step T.(U => Y).W to get a path from TYV to
203+
// TYW.
204+
path.add(RewriteStep::forRewriteRule(/*startOffset=*/t.size(),
205+
/*endOffset=*/w.size(),
206+
getRuleID(rhs),
207+
/*inverse=*/false));
208+
209+
// Compute the term TYW.
210+
MutableTerm tyw(t);
211+
tyw.append(rhs.getRHS());
212+
tyw.append(w);
213+
214+
// Add the pair (TYV, TYW).
215+
pairs.emplace_back(tyv, tyw, path);
216+
} else {
217+
// Add the pair (X, TYV).
218+
pairs.emplace_back(x, tyv, path);
219+
}
162220
} else {
163221
// lhs == TU -> X, rhs == UV -> Y.
164222

@@ -217,7 +275,7 @@ RewriteSystem::computeCriticalPair(ArrayRef<Symbol>::const_iterator from,
217275
// - lhs == (TU -> X)
218276
// - rhs == (UV -> UW).
219277
//
220-
// We explicitly apply the rewrite step (TU = X) to the rewrite path,
278+
// We explicitly apply the rewrite step (TU => X) to the rewrite path,
221279
// transforming the critical pair to (XV, XW).
222280
//
223281
// In particular, if T == X, U == [P] for some protocol P, and
@@ -229,15 +287,15 @@ RewriteSystem::computeCriticalPair(ArrayRef<Symbol>::const_iterator from,
229287
//
230288
// Without this hack, the critical pair would be:
231289
//
232-
// (T.w.[p] => T.[P].w)
290+
// (T.W.[p] => T.[P].W)
233291
//
234292
// With this hack, the critical pair becomes:
235293
//
236-
// (T.w.[p] => T.w)
294+
// (T.W.[p] => T.W)
237295
//
238296
// This ensures that the newly-added rule is itself a property rule;
239-
// otherwise, this would only be the case if addRule() reduced T.[P].w
240-
// into T.w without immediately reducing some subterm of T first.
297+
// otherwise, this would only be the case if addRule() reduced T.[P].W
298+
// into T.W without immediately reducing some subterm of T first.
241299
//
242300
// While completion will eventually simplify all such rules down into
243301
// property rules, their existance in the first place breaks subtle

lib/AST/RequirementMachine/RequirementLowering.cpp

Lines changed: 54 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@
160160
#include "llvm/ADT/SmallVector.h"
161161
#include "llvm/ADT/SetVector.h"
162162
#include "RewriteContext.h"
163+
#include "NameLookup.h"
163164

164165
using namespace swift;
165166
using namespace rewriting;
@@ -384,12 +385,40 @@ swift::rewriting::desugarRequirement(Requirement req, SourceLoc loc,
384385
// Requirement realization and inference.
385386
//
386387

387-
static void realizeTypeRequirement(Type subjectType, Type constraintType,
388+
static void realizeTypeRequirement(DeclContext *dc,
389+
Type subjectType, Type constraintType,
388390
SourceLoc loc,
389391
SmallVectorImpl<StructuralRequirement> &result,
390392
SmallVectorImpl<RequirementError> &errors) {
391393
SmallVector<Requirement, 2> reqs;
392394

395+
// The GenericSignatureBuilder allowed the right hand side of a
396+
// conformance or superclass requirement to reference a protocol
397+
// typealias whose underlying type was a protocol or class.
398+
//
399+
// Since protocol typealiases resolve to DependentMemberTypes in
400+
// ::Structural mode, this relied on the GSB's "delayed requirements"
401+
// mechanism.
402+
//
403+
// The RequirementMachine does not have an equivalent, and cannot really
404+
// support that because we need to collect the protocols mentioned on
405+
// the right hand sides of conformance requirements ahead of time.
406+
//
407+
// However, we can support it in simple cases where the typealias is
408+
// defined in the protocol itself and is accessed as a member of 'Self'.
409+
if (auto *proto = dc->getSelfProtocolDecl()) {
410+
if (auto memberType = constraintType->getAs<DependentMemberType>()) {
411+
if (memberType->getBase()->isEqual(proto->getSelfInterfaceType())) {
412+
SmallVector<TypeDecl *, 1> result;
413+
lookupConcreteNestedType(proto, memberType->getName(), result);
414+
auto *typeDecl = findBestConcreteNestedType(result);
415+
if (auto *aliasDecl = dyn_cast_or_null<TypeAliasDecl>(typeDecl)) {
416+
constraintType = aliasDecl->getUnderlyingType();
417+
}
418+
}
419+
}
420+
}
421+
393422
if (constraintType->isConstraintType()) {
394423
// Handle conformance requirements.
395424
desugarConformanceRequirement(subjectType, constraintType, loc, reqs, errors);
@@ -534,18 +563,20 @@ void swift::rewriting::inferRequirements(
534563
/// Desugar a requirement and perform requirement inference if requested
535564
/// to obtain zero or more structural requirements.
536565
void swift::rewriting::realizeRequirement(
566+
DeclContext *dc,
537567
Requirement req, RequirementRepr *reqRepr,
538-
ModuleDecl *moduleForInference,
568+
bool shouldInferRequirements,
539569
SmallVectorImpl<StructuralRequirement> &result,
540570
SmallVectorImpl<RequirementError> &errors) {
541571
auto firstType = req.getFirstType();
542572
auto loc = (reqRepr ? reqRepr->getSeparatorLoc() : SourceLoc());
573+
auto *moduleForInference = dc->getParentModule();
543574

544575
switch (req.getKind()) {
545576
case RequirementKind::Superclass:
546577
case RequirementKind::Conformance: {
547578
auto secondType = req.getSecondType();
548-
if (moduleForInference) {
579+
if (shouldInferRequirements) {
549580
auto firstLoc = (reqRepr ? reqRepr->getSubjectRepr()->getStartLoc()
550581
: SourceLoc());
551582
inferRequirements(firstType, firstLoc, moduleForInference, result);
@@ -555,12 +586,12 @@ void swift::rewriting::realizeRequirement(
555586
inferRequirements(secondType, secondLoc, moduleForInference, result);
556587
}
557588

558-
realizeTypeRequirement(firstType, secondType, loc, result, errors);
589+
realizeTypeRequirement(dc, firstType, secondType, loc, result, errors);
559590
break;
560591
}
561592

562593
case RequirementKind::Layout: {
563-
if (moduleForInference) {
594+
if (shouldInferRequirements) {
564595
auto firstLoc = (reqRepr ? reqRepr->getSubjectRepr()->getStartLoc()
565596
: SourceLoc());
566597
inferRequirements(firstType, firstLoc, moduleForInference, result);
@@ -578,7 +609,7 @@ void swift::rewriting::realizeRequirement(
578609

579610
case RequirementKind::SameType: {
580611
auto secondType = req.getSecondType();
581-
if (moduleForInference) {
612+
if (shouldInferRequirements) {
582613
auto firstLoc = (reqRepr ? reqRepr->getFirstTypeRepr()->getStartLoc()
583614
: SourceLoc());
584615
inferRequirements(firstType, firstLoc, moduleForInference, result);
@@ -602,11 +633,13 @@ void swift::rewriting::realizeRequirement(
602633
/// Collect structural requirements written in the inheritance clause of an
603634
/// AssociatedTypeDecl or GenericTypeParamDecl.
604635
void swift::rewriting::realizeInheritedRequirements(
605-
TypeDecl *decl, Type type, ModuleDecl *moduleForInference,
636+
TypeDecl *decl, Type type, bool shouldInferRequirements,
606637
SmallVectorImpl<StructuralRequirement> &result,
607638
SmallVectorImpl<RequirementError> &errors) {
608639
auto &ctx = decl->getASTContext();
609640
auto inheritedTypes = decl->getInherited();
641+
auto *dc = decl->getInnermostDeclContext();
642+
auto *moduleForInference = dc->getParentModule();
610643

611644
for (unsigned index : indices(inheritedTypes)) {
612645
Type inheritedType
@@ -616,41 +649,21 @@ void swift::rewriting::realizeInheritedRequirements(
616649
Type());
617650
if (!inheritedType) continue;
618651

619-
// The GenericSignatureBuilder allowed an associated type's inheritance
620-
// clause to reference a protocol typealias whose underlying type was a
621-
// protocol or class.
622-
//
623-
// Since protocol typealiases resolve to DependentMemberTypes in
624-
// ::Structural mode, this relied on the GSB's "delayed requirements"
625-
// mechanism.
626-
//
627-
// The RequirementMachine does not have an equivalent, and cannot really
628-
// support that because we need to collect the protocols mentioned on
629-
// the right hand sides of conformance requirements ahead of time.
630-
//
631-
// However, we can support it in simple cases where the typealias is
632-
// defined in the protocol itself and is accessed as a member of 'Self'.
633-
if (auto *assocTypeDecl = dyn_cast<AssociatedTypeDecl>(decl)) {
634-
if (auto memberType = inheritedType->getAs<DependentMemberType>()) {
635-
if (memberType->getBase()->isEqual(
636-
assocTypeDecl->getProtocol()->getSelfInterfaceType())) {
637-
inheritedType
638-
= evaluateOrDefault(ctx.evaluator,
639-
InheritedTypeRequest{decl, index,
640-
TypeResolutionStage::Interface},
641-
Type());
642-
if (!inheritedType) continue;
643-
}
644-
}
652+
// Ignore trivially circular protocol refinement (protocol P : P)
653+
// since we diagnose that elsewhere. Adding a rule here would emit
654+
// a useless redundancy warning.
655+
if (auto *protoDecl = dyn_cast<ProtocolDecl>(decl)) {
656+
if (inheritedType->isEqual(protoDecl->getDeclaredInterfaceType()))
657+
continue;
645658
}
646659

647660
auto *typeRepr = inheritedTypes[index].getTypeRepr();
648661
SourceLoc loc = (typeRepr ? typeRepr->getStartLoc() : SourceLoc());
649-
if (moduleForInference) {
662+
if (shouldInferRequirements) {
650663
inferRequirements(inheritedType, loc, moduleForInference, result);
651664
}
652665

653-
realizeTypeRequirement(type, inheritedType, loc, result, errors);
666+
realizeTypeRequirement(dc, type, inheritedType, loc, result, errors);
654667
}
655668
}
656669

@@ -823,14 +836,14 @@ StructuralRequirementsRequest::evaluate(Evaluator &evaluator,
823836
auto selfTy = proto->getSelfInterfaceType();
824837

825838
realizeInheritedRequirements(proto, selfTy,
826-
/*moduleForInference=*/nullptr,
839+
/*inferRequirements=*/false,
827840
result, errors);
828841

829842
// Add requirements from the protocol's own 'where' clause.
830843
WhereClauseOwner(proto).visitRequirements(TypeResolutionStage::Structural,
831844
[&](const Requirement &req, RequirementRepr *reqRepr) {
832-
realizeRequirement(req, reqRepr,
833-
/*moduleForInference=*/nullptr,
845+
realizeRequirement(proto, req, reqRepr,
846+
/*inferRequirements=*/false,
834847
result, errors);
835848
return false;
836849
});
@@ -855,15 +868,15 @@ StructuralRequirementsRequest::evaluate(Evaluator &evaluator,
855868
// Add requirements placed directly on this associated type.
856869
auto assocType = assocTypeDecl->getDeclaredInterfaceType();
857870
realizeInheritedRequirements(assocTypeDecl, assocType,
858-
/*moduleForInference=*/nullptr,
871+
/*inferRequirements=*/false,
859872
result, errors);
860873

861874
// Add requirements from this associated type's where clause.
862875
WhereClauseOwner(assocTypeDecl).visitRequirements(
863876
TypeResolutionStage::Structural,
864877
[&](const Requirement &req, RequirementRepr *reqRepr) {
865-
realizeRequirement(req, reqRepr,
866-
/*moduleForInference=*/nullptr,
878+
realizeRequirement(proto, req, reqRepr,
879+
/*inferRequirements=*/false,
867880
result, errors);
868881
return false;
869882
});

lib/AST/RequirementMachine/RequirementLowering.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,14 @@ void desugarRequirement(Requirement req, SourceLoc loc,
4545
void inferRequirements(Type type, SourceLoc loc, ModuleDecl *module,
4646
SmallVectorImpl<StructuralRequirement> &result);
4747

48-
void realizeRequirement(Requirement req, RequirementRepr *reqRepr,
49-
ModuleDecl *moduleForInference,
48+
void realizeRequirement(DeclContext *dc,
49+
Requirement req, RequirementRepr *reqRepr,
50+
bool shouldInferRequirements,
5051
SmallVectorImpl<StructuralRequirement> &result,
5152
SmallVectorImpl<RequirementError> &errors);
5253

5354
void realizeInheritedRequirements(TypeDecl *decl, Type type,
54-
ModuleDecl *moduleForInference,
55+
bool shouldInferRequirements,
5556
SmallVectorImpl<StructuralRequirement> &result,
5657
SmallVectorImpl<RequirementError> &errors);
5758

lib/AST/RequirementMachine/RequirementMachine.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,10 @@ RequirementMachine::computeCompletion(RewriteSystem::ValidityPolicy policy) {
485485

486486
unsigned rulesAdded = (System.getRules().size() - ruleCount);
487487

488+
// If buildPropertyMap() didn't add any new rules, we are done.
489+
if (rulesAdded == 0)
490+
break;
491+
488492
if (Stats) {
489493
Stats->getFrontendCounters()
490494
.NumRequirementMachineUnifiedConcreteTerms += rulesAdded;
@@ -507,10 +511,6 @@ RequirementMachine::computeCompletion(RewriteSystem::ValidityPolicy policy) {
507511
return std::make_pair(CompletionResult::MaxRuleCount,
508512
System.getRules().size() - 1);
509513
}
510-
511-
// If buildPropertyMap() didn't add any new rules, we are done.
512-
if (rulesAdded == 0)
513-
break;
514514
}
515515
}
516516

0 commit comments

Comments
 (0)