Skip to content

Commit 70e1129

Browse files
authored
Merge pull request #40973 from slavapestov/rqm-conditional-requirement-inference
RequirementMachine: Conditional requirement inference
2 parents 6b5de49 + eb9f121 commit 70e1129

20 files changed

+495
-291
lines changed

lib/AST/RequirementMachine/Debug.h

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,17 +38,21 @@ enum class DebugFlags : unsigned {
3838
/// Print debug output when concretizing nested types in the property map.
3939
ConcretizeNestedTypes = (1<<5),
4040

41+
/// Print debug output when inferring conditional requirements in the
42+
/// property map.
43+
ConditionalRequirements = (1<<6),
44+
4145
/// Print debug output from the homotopy reduction algorithm.
42-
HomotopyReduction = (1<<6),
46+
HomotopyReduction = (1<<7),
4347

4448
/// Print debug output from the minimal conformances algorithm.
45-
MinimalConformances = (1<<7),
49+
MinimalConformances = (1<<8),
4650

4751
/// Print debug output from the protocol dependency graph.
48-
ProtocolDependencies = (1<<8),
52+
ProtocolDependencies = (1<<9),
4953

5054
/// Print debug output from generic signature minimization.
51-
Minimization = (1<<9),
55+
Minimization = (1<<10),
5256
};
5357

5458
using DebugOptions = OptionSet<DebugFlags>;

lib/AST/RequirementMachine/HomotopyReduction.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -386,9 +386,13 @@ findRuleToDelete(llvm::function_ref<bool(unsigned)> isRedundantRuleFn,
386386

387387
const auto &otherRule = getRule(found->second);
388388

389-
// Prefer to delete "less canonical" rules.
390-
if (rule.compare(otherRule, Context) > 0)
389+
// If the new rule is conflicting, don't compare the rules at all
390+
// and prefer to delete the new rule. Otherwise, prefer to delete
391+
// the less canonical of the two rules.
392+
if (rule.isConflicting() ||
393+
rule.compare(otherRule, Context) > 0) {
391394
found = pair;
395+
}
392396
}
393397

394398
if (!found)

lib/AST/RequirementMachine/InterfaceType.cpp

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,3 +493,77 @@ Type PropertyMap::getTypeFromSubstitutionSchema(
493493
return None;
494494
});
495495
}
496+
497+
/// This method takes a concrete type that was derived from a concrete type
498+
/// produced by RewriteContext::getSubstitutionSchemaFromType() either by
499+
/// extracting a structural sub-component or performing a (Swift AST)
500+
/// substitution using subst(). It returns a new concrete substitution schema
501+
/// and a new list of substitution terms.
502+
///
503+
/// For example, suppose we start with the concrete type
504+
///
505+
/// Dictionary<τ_0_0, Array<τ_0_1>> with substitutions {X.Y, Z}
506+
///
507+
/// We can extract out the structural sub-component Array<τ_0_1>. If we wish
508+
/// to build a new concrete substitution schema, we call this method with
509+
/// Array<τ_0_1> and the original substitutions {X.Y, Z}. This will produce
510+
/// the new schema Array<τ_0_0> with substitutions {Z}.
511+
///
512+
/// As another example, consider we start with the schema Bar<τ_0_0> with
513+
/// original substitutions {X.Y}, and perform a Swift AST subst() to get
514+
/// Foo<τ_0_0.A.B>. We can then call this method with Foo<τ_0_0.A.B> and
515+
/// the original substitutions {X.Y} to produce the new schema Foo<τ_0_0>
516+
/// with substitutions {X.Y.A.B}.
517+
CanType
518+
RewriteContext::getRelativeSubstitutionSchemaFromType(
519+
CanType concreteType,
520+
ArrayRef<Term> substitutions,
521+
SmallVectorImpl<Term> &result) {
522+
assert(!concreteType->isTypeParameter() && "Must have a concrete type here");
523+
524+
if (!concreteType->hasTypeParameter())
525+
return concreteType;
526+
527+
return CanType(concreteType.transformRec([&](Type t) -> Optional<Type> {
528+
if (!t->isTypeParameter())
529+
return None;
530+
531+
auto term = getRelativeTermForType(CanType(t), substitutions);
532+
533+
unsigned newIndex = result.size();
534+
result.push_back(Term::get(term, *this));
535+
536+
return CanGenericTypeParamType::get(/*type sequence=*/ false,
537+
/*depth=*/ 0, newIndex,
538+
Context);
539+
}));
540+
}
541+
542+
/// Given a concrete type that may contain type parameters in structural positions,
543+
/// collect all the structural type parameter components, and replace them all with
544+
/// fresh generic parameters. The fresh generic parameters all have a depth of 0,
545+
/// and the index is an index into the 'result' array.
546+
///
547+
/// For example, given the concrete type Foo<X.Y, Array<Z>>, this produces the
548+
/// result type Foo<τ_0_0, Array<τ_0_1>>, with result array {X.Y, Z}.
549+
CanType
550+
RewriteContext::getSubstitutionSchemaFromType(CanType concreteType,
551+
const ProtocolDecl *proto,
552+
SmallVectorImpl<Term> &result) {
553+
assert(!concreteType->isTypeParameter() && "Must have a concrete type here");
554+
555+
if (!concreteType->hasTypeParameter())
556+
return concreteType;
557+
558+
return CanType(concreteType.transformRec([&](Type t) -> Optional<Type> {
559+
if (!t->isTypeParameter())
560+
return None;
561+
562+
unsigned index = result.size();
563+
result.push_back(getTermForType(CanType(t), proto));
564+
565+
return CanGenericTypeParamType::get(/*type sequence=*/ false,
566+
/*depth=*/0, index,
567+
Context);
568+
}));
569+
}

lib/AST/RequirementMachine/PropertyMap.cpp

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -371,36 +371,28 @@ PropertyMap::buildPropertyMap(unsigned maxIterations,
371371

372372
// Merging multiple superclass or concrete type rules can induce new rules
373373
// to unify concrete type constructor arguments.
374-
SmallVector<InducedRule, 3> inducedRules;
374+
unsigned ruleCount = System.getRules().size();
375375

376376
for (const auto &bucket : properties) {
377377
for (auto property : bucket) {
378378
addProperty(property.key, property.symbol,
379-
property.ruleID, inducedRules);
379+
property.ruleID);
380380
}
381381
}
382382

383383
// Now, check for conflicts between superclass and concrete type rules.
384-
checkConcreteTypeRequirements(inducedRules);
384+
checkConcreteTypeRequirements();
385385

386386
// Now, we merge concrete type rules with conformance rules, by adding
387387
// relations between associated type members of type parameters with
388388
// the concrete type witnesses in the concrete type's conformance.
389-
concretizeNestedTypesFromConcreteParents(inducedRules);
390-
391-
// Some of the induced rules might be trivial; only count the induced rules
392-
// where the left hand side is not already equivalent to the right hand side.
393-
unsigned addedNewRules = 0;
394-
for (auto pair : inducedRules) {
395-
// FIXME: Eventually, all induced rules will have a rewrite path.
396-
if (System.addRule(pair.LHS, pair.RHS,
397-
pair.Path.empty() ? nullptr : &pair.Path)) {
398-
++addedNewRules;
399-
400-
const auto &newRule = System.getRules().back();
401-
if (newRule.getDepth() > maxDepth)
402-
return std::make_pair(CompletionResult::MaxDepth, addedNewRules);
403-
}
389+
concretizeNestedTypesFromConcreteParents();
390+
391+
unsigned addedNewRules = System.getRules().size() - ruleCount;
392+
for (unsigned i = ruleCount, e = System.getRules().size(); i < e; ++i) {
393+
const auto &newRule = System.getRule(i);
394+
if (newRule.getDepth() > maxDepth)
395+
return std::make_pair(CompletionResult::MaxDepth, addedNewRules);
404396
}
405397

406398
// Check invariants of the constructed property map.

lib/AST/RequirementMachine/PropertyMap.h

Lines changed: 11 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -44,21 +44,6 @@ namespace rewriting {
4444
class MutableTerm;
4545
class Term;
4646

47-
/// A new rule introduced during property map construction, as a result of
48-
/// unifying two property symbols that apply to the same common suffix term.
49-
struct InducedRule {
50-
MutableTerm LHS;
51-
MutableTerm RHS;
52-
RewritePath Path;
53-
54-
InducedRule(MutableTerm LHS, MutableTerm RHS, RewritePath Path)
55-
: LHS(LHS), RHS(RHS), Path(Path) {}
56-
57-
// FIXME: Eventually all induced rules will have a rewrite path.
58-
InducedRule(MutableTerm LHS, MutableTerm RHS)
59-
: LHS(LHS), RHS(RHS) {}
60-
};
61-
6247
/// Stores a convenient representation of all "property-like" rewrite rules of
6348
/// the form T.[p] => T, where [p] is a property symbol, for some term 'T'.
6449
class PropertyBag {
@@ -258,14 +243,11 @@ class PropertyMap {
258243
bool checkRuleOnce(unsigned ruleID);
259244
bool checkRulePairOnce(unsigned firstRuleID, unsigned secondRuleID);
260245

261-
void addProperty(Term key, Symbol property, unsigned ruleID,
262-
SmallVectorImpl<InducedRule> &inducedRules);
246+
void addProperty(Term key, Symbol property, unsigned ruleID);
263247

264-
void checkConcreteTypeRequirements(
265-
SmallVectorImpl<InducedRule> &inducedRules);
248+
void checkConcreteTypeRequirements();
266249

267-
void concretizeNestedTypesFromConcreteParents(
268-
SmallVectorImpl<InducedRule> &inducedRules);
250+
void concretizeNestedTypesFromConcreteParents();
269251

270252
void concretizeNestedTypesFromConcreteParent(
271253
Term key, RequirementKind requirementKind,
@@ -274,15 +256,17 @@ class PropertyMap {
274256
ArrayRef<Term> substitutions,
275257
ArrayRef<unsigned> conformsToRules,
276258
ArrayRef<const ProtocolDecl *> conformsTo,
277-
llvm::TinyPtrVector<ProtocolConformance *> &conformances,
278-
SmallVectorImpl<InducedRule> &inducedRules);
259+
llvm::TinyPtrVector<ProtocolConformance *> &conformances);
279260

280261
void concretizeTypeWitnessInConformance(
281262
Term key, RequirementKind requirementKind,
282263
Symbol concreteConformanceSymbol,
283264
ProtocolConformance *concrete,
284-
AssociatedTypeDecl *assocType,
285-
SmallVectorImpl<InducedRule> &inducedRules) const;
265+
AssociatedTypeDecl *assocType) const;
266+
267+
void inferConditionalRequirements(
268+
ProtocolConformance *concrete,
269+
ArrayRef<Term> substitutions) const;
286270

287271
MutableTerm computeConstraintTermForTypeWitness(
288272
Term key, RequirementKind requirementKind,
@@ -295,8 +279,7 @@ class PropertyMap {
295279
unsigned concreteRuleID,
296280
unsigned conformanceRuleID,
297281
RequirementKind requirementKind,
298-
Symbol concreteConformanceSymbol,
299-
SmallVectorImpl<InducedRule> &inducedRules) const;
282+
Symbol concreteConformanceSymbol) const;
300283

301284
void verify() const;
302285
};
@@ -305,4 +288,4 @@ class PropertyMap {
305288

306289
} // end namespace swift
307290

308-
#endif
291+
#endif

0 commit comments

Comments
 (0)