Skip to content

Commit 5db2bf5

Browse files
authored
Merge pull request #40543 from slavapestov/rqm-type-witness-minimization
RequirementMachine: Implement minimization for concrete nested type requirements
2 parents 2b5bcc1 + 2441e68 commit 5db2bf5

15 files changed

+546
-155
lines changed

lib/AST/RequirementMachine/GeneratingConformances.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,8 @@ void RewriteLoop::findProtocolConformanceRules(
137137
case RewriteStep::Decompose:
138138
case RewriteStep::ConcreteConformance:
139139
case RewriteStep::SuperclassConformance:
140+
case RewriteStep::ConcreteTypeWitness:
141+
case RewriteStep::SameTypeWitness:
140142
break;
141143
}
142144
}

lib/AST/RequirementMachine/HomotopyReduction.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@ RewriteLoop::findRulesAppearingOnceInEmptyContext(
9292
case RewriteStep::Decompose:
9393
case RewriteStep::ConcreteConformance:
9494
case RewriteStep::SuperclassConformance:
95+
case RewriteStep::ConcreteTypeWitness:
96+
case RewriteStep::SameTypeWitness:
9597
break;
9698
}
9799

@@ -208,6 +210,8 @@ RewritePath RewritePath::splitCycleAtRule(unsigned ruleID) const {
208210
case RewriteStep::Decompose:
209211
case RewriteStep::ConcreteConformance:
210212
case RewriteStep::SuperclassConformance:
213+
case RewriteStep::ConcreteTypeWitness:
214+
case RewriteStep::SameTypeWitness:
211215
break;
212216
}
213217

@@ -306,6 +310,8 @@ bool RewritePath::replaceRuleWithPath(unsigned ruleID,
306310
case RewriteStep::Decompose:
307311
case RewriteStep::ConcreteConformance:
308312
case RewriteStep::SuperclassConformance:
313+
case RewriteStep::ConcreteTypeWitness:
314+
case RewriteStep::SameTypeWitness:
309315
newSteps.push_back(step);
310316
break;
311317
}

lib/AST/RequirementMachine/PropertyMap.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -227,8 +227,11 @@ class PropertyMap {
227227
SmallVectorImpl<InducedRule> &inducedRules) const;
228228

229229
MutableTerm computeConstraintTermForTypeWitness(
230-
Term key, CanType concreteType, CanType typeWitness,
231-
const MutableTerm &subjectType, ArrayRef<Term> substitutions) const;
230+
Term key, RequirementKind requirementKind,
231+
CanType concreteType, CanType typeWitness,
232+
const MutableTerm &subjectType,
233+
ArrayRef<Term> substitutions,
234+
RewritePath &path) const;
232235

233236
void recordConcreteConformanceRule(
234237
unsigned concreteRuleID,

lib/AST/RequirementMachine/PropertyUnification.cpp

Lines changed: 122 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -614,42 +614,63 @@ void PropertyMap::concretizeTypeWitnessInConformance(
614614

615615
MutableTerm constraintType;
616616

617-
auto simplify = [&](CanType t) -> CanType {
618-
return CanType(t.transformRec([&](Type t) -> Optional<Type> {
619-
if (!t->isTypeParameter())
620-
return None;
621-
622-
auto term = Context.getRelativeTermForType(t->getCanonicalType(),
623-
substitutions);
624-
System.simplify(term);
625-
return Context.getTypeForTerm(term, { });
626-
}));
627-
};
628-
629-
if (simplify(concreteType) == simplify(typeWitness) &&
630-
requirementKind == RequirementKind::SameType) {
631-
// FIXME: ConcreteTypeInDomainMap should support substitutions so
632-
// that we can remove this.
633-
634-
if (Debug.contains(DebugFlags::ConcretizeNestedTypes)) {
635-
llvm::dbgs() << "^^ Type witness is the same as the concrete type\n";
636-
}
617+
RewritePath path;
637618

638-
// Add a rule T.[P:A] => T.
639-
constraintType = MutableTerm(key);
640-
} else {
641-
constraintType = computeConstraintTermForTypeWitness(
642-
key, concreteType, typeWitness, subjectType,
643-
substitutions);
644-
}
619+
constraintType = computeConstraintTermForTypeWitness(
620+
key, requirementKind, concreteType, typeWitness, subjectType,
621+
substitutions, path);
645622

646-
inducedRules.emplace_back(subjectType, constraintType);
623+
inducedRules.emplace_back(constraintType, subjectType, path);
647624
if (Debug.contains(DebugFlags::ConcretizeNestedTypes)) {
648625
llvm::dbgs() << "^^ Induced rule " << constraintType
649626
<< " => " << subjectType << "\n";
650627
}
651628
}
652629

630+
RewriteSystem::ConcreteTypeWitness::ConcreteTypeWitness(
631+
Symbol concreteConformance,
632+
Symbol assocType,
633+
Symbol concreteType)
634+
: ConcreteConformance(concreteConformance),
635+
AssocType(assocType),
636+
ConcreteType(concreteType) {
637+
assert(concreteConformance.getKind() == Symbol::Kind::ConcreteConformance);
638+
assert(assocType.getKind() == Symbol::Kind::AssociatedType);
639+
assert(concreteType.getKind() == Symbol::Kind::ConcreteType);
640+
assert(assocType.getProtocols().size() == 1);
641+
assert(assocType.getProtocols()[0] == concreteConformance.getProtocol());
642+
}
643+
644+
bool swift::rewriting::operator==(
645+
const RewriteSystem::ConcreteTypeWitness &lhs,
646+
const RewriteSystem::ConcreteTypeWitness &rhs) {
647+
return (lhs.ConcreteConformance == rhs.ConcreteConformance &&
648+
lhs.AssocType == rhs.AssocType &&
649+
lhs.ConcreteType == rhs.ConcreteType);
650+
}
651+
652+
unsigned RewriteSystem::recordConcreteTypeWitness(
653+
RewriteSystem::ConcreteTypeWitness witness) {
654+
auto key = std::make_pair(witness.ConcreteConformance,
655+
witness.AssocType);
656+
unsigned index = ConcreteTypeWitnesses.size();
657+
auto inserted = ConcreteTypeWitnessMap.insert(std::make_pair(key, index));
658+
659+
if (!inserted.second) {
660+
index = inserted.first->second;
661+
} else {
662+
ConcreteTypeWitnesses.push_back(witness);
663+
}
664+
665+
assert(ConcreteTypeWitnesses[index] == witness);
666+
return index;
667+
}
668+
669+
const RewriteSystem::ConcreteTypeWitness &
670+
RewriteSystem::getConcreteTypeWitness(unsigned index) const {
671+
return ConcreteTypeWitnesses[index];
672+
}
673+
653674
/// Given the key of a property bag known to have \p concreteType,
654675
/// together with a \p typeWitness from a conformance on that concrete
655676
/// type, return the right hand side of a rewrite rule to relate
@@ -675,8 +696,72 @@ void PropertyMap::concretizeTypeWitnessInConformance(
675696
///
676697
/// T.[P:A] => V
677698
MutableTerm PropertyMap::computeConstraintTermForTypeWitness(
678-
Term key, CanType concreteType, CanType typeWitness,
679-
const MutableTerm &subjectType, ArrayRef<Term> substitutions) const {
699+
Term key, RequirementKind requirementKind,
700+
CanType concreteType, CanType typeWitness,
701+
const MutableTerm &subjectType,
702+
ArrayRef<Term> substitutions,
703+
RewritePath &path) const {
704+
// If the type witness is abstract, introduce a same-type requirement
705+
// between two type parameters.
706+
if (typeWitness->isTypeParameter()) {
707+
// The type witness is a type parameter of the form τ_0_n.X.Y...Z,
708+
// where 'n' is an index into the substitution array.
709+
//
710+
// Add a rule:
711+
//
712+
// T.[concrete: C : P].[P:X] => S[n].X.Y...Z
713+
//
714+
// Where S[n] is the nth substitution term.
715+
716+
// FIXME: Record a rewrite path.
717+
return Context.getRelativeTermForType(typeWitness, substitutions);
718+
}
719+
720+
// Otherwise the type witness is concrete, but may contain type
721+
// parameters in structural position.
722+
723+
// Compute the concrete type symbol [concrete: C.X].
724+
SmallVector<Term, 3> result;
725+
auto typeWitnessSchema =
726+
remapConcreteSubstitutionSchema(typeWitness, substitutions,
727+
Context, result);
728+
auto typeWitnessSymbol =
729+
Symbol::forConcreteType(typeWitnessSchema, result, Context);
730+
System.simplifySubstitutions(typeWitnessSymbol);
731+
732+
auto concreteConformanceSymbol = *(subjectType.end() - 2);
733+
auto assocTypeSymbol = *(subjectType.end() - 1);
734+
735+
RewriteSystem::ConcreteTypeWitness witness(concreteConformanceSymbol,
736+
assocTypeSymbol,
737+
typeWitnessSymbol);
738+
unsigned witnessID = System.recordConcreteTypeWitness(witness);
739+
740+
// If it is equal to the parent type, introduce a same-type requirement
741+
// between the two parameters.
742+
if (requirementKind == RequirementKind::SameType &&
743+
typeWitnessSymbol.getConcreteType() == concreteType &&
744+
typeWitnessSymbol.getSubstitutions() == substitutions) {
745+
// FIXME: ConcreteTypeInDomainMap should support substitutions so
746+
// that we can remove this.
747+
748+
if (Debug.contains(DebugFlags::ConcretizeNestedTypes)) {
749+
llvm::dbgs() << "^^ Type witness is the same as the concrete type\n";
750+
}
751+
752+
// Add a rule T.[concrete: C : P].[P:X] => T.[concrete: C : P].
753+
MutableTerm result(key);
754+
result.add(concreteConformanceSymbol);
755+
756+
path.add(RewriteStep::forSameTypeWitness(
757+
witnessID, /*inverse=*/true));
758+
759+
return result;
760+
}
761+
762+
// If the type witness is completely concrete, try to introduce a
763+
// same-type requirement with another representative type parameter,
764+
// if we have one.
680765
if (!typeWitness->hasTypeParameter()) {
681766
// Check if we have a shorter representative we can use.
682767
auto domain = key.getRootProtocols();
@@ -690,38 +775,23 @@ MutableTerm PropertyMap::computeConstraintTermForTypeWitness(
690775
llvm::dbgs() << "^^ Type witness can re-use property bag of "
691776
<< found->second << "\n";
692777
}
778+
779+
// FIXME: Record a rewrite path.
693780
return result;
694781
}
695782
}
696783
}
697784

698-
if (typeWitness->isTypeParameter()) {
699-
// The type witness is a type parameter of the form τ_0_n.X.Y...Z,
700-
// where 'n' is an index into the substitution array.
701-
//
702-
// Add a rule:
703-
//
704-
// T.[concrete: C : P].[P:X] => S[n].X.Y...Z
705-
//
706-
// Where S[n] is the nth substitution term.
707-
return Context.getRelativeTermForType(typeWitness, substitutions);
708-
}
709-
710-
// The type witness is a concrete type.
785+
// Otherwise, add a concrete type requirement for the type witness.
711786
//
712787
// Add a rule:
713788
//
714-
// T.[concrete: C : P].[P:X].[concrete: Foo.A] => T.[concrete: C : P].[P:A].
789+
// T.[concrete: C : P].[P:X].[concrete: C.X] => T.[concrete: C : P].[P:X].
715790
MutableTerm constraintType = subjectType;
791+
constraintType.add(typeWitnessSymbol);
716792

717-
SmallVector<Term, 3> result;
718-
auto typeWitnessSchema =
719-
remapConcreteSubstitutionSchema(typeWitness, substitutions,
720-
Context, result);
721-
722-
constraintType.add(
723-
Symbol::forConcreteType(
724-
typeWitnessSchema, result, Context));
793+
path.add(RewriteStep::forConcreteTypeWitness(
794+
witnessID, /*inverse=*/false));
725795

726796
return constraintType;
727797
}

lib/AST/RequirementMachine/RequirementMachineRequests.cpp

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,9 @@ void ConnectedComponent::buildRequirements(Type subjectType,
7979
subjectType, constraintType);
8080
subjectType = constraintType;
8181
}
82-
} else {
82+
} else if (!ConcreteType->hasError()) {
83+
// For compatibility with the old GenericSignatureBuilder, drop requirements
84+
// containing ErrorTypes.
8385
reqs.emplace_back(RequirementKind::SameType,
8486
subjectType, ConcreteType);
8587

@@ -120,14 +122,20 @@ RequirementMachine::buildRequirementsFromRules(
120122
prop->getLayoutConstraint());
121123
return;
122124

123-
case Symbol::Kind::Superclass:
125+
case Symbol::Kind::Superclass: {
126+
// For compatibility with the old GenericSignatureBuilder, drop requirements
127+
// containing ErrorTypes.
128+
auto superclassType = Context.getTypeFromSubstitutionSchema(
129+
prop->getSuperclass(),
130+
prop->getSubstitutions(),
131+
genericParams, MutableTerm());
132+
if (superclassType->hasError())
133+
return;
134+
124135
reqs.emplace_back(RequirementKind::Superclass,
125-
subjectType,
126-
Context.getTypeFromSubstitutionSchema(
127-
prop->getSuperclass(),
128-
prop->getSubstitutions(),
129-
genericParams, MutableTerm()));
136+
subjectType, superclassType);
130137
return;
138+
}
131139

132140
case Symbol::Kind::ConcreteType: {
133141
auto concreteType = Context.getTypeFromSubstitutionSchema(

0 commit comments

Comments
 (0)