Skip to content

Commit fa65fd0

Browse files
committed
RequirementMachine: Plumb protocol typealiases through minimization
Now that we can detect protocol typealias rules, collect and keep track of them so that they can be recorded in protocol requirement signatures. For now, this is all NFC since nothing introduces such rules into the rewrite system, except for invalid requirements which are diagnosed anyway.
1 parent f9c2d9f commit fa65fd0

File tree

5 files changed

+123
-25
lines changed

5 files changed

+123
-25
lines changed

lib/AST/RequirementMachine/HomotopyReduction.cpp

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -598,7 +598,8 @@ void RewriteSystem::minimizeRewriteSystem() {
598598
rule.isSubstitutionSimplified())
599599
return true;
600600

601-
if (rule.getLHS().containsUnresolvedSymbols())
601+
if (rule.containsUnresolvedSymbols() &&
602+
!rule.isProtocolTypeAliasRule())
602603
return true;
603604

604605
return false;
@@ -666,7 +667,9 @@ bool RewriteSystem::hadError() const {
666667
if (rule.isConflicting())
667668
return true;
668669

669-
if (!rule.isRedundant() && rule.containsUnresolvedSymbols())
670+
if (!rule.isRedundant() &&
671+
!rule.isProtocolTypeAliasRule() &&
672+
rule.containsUnresolvedSymbols())
670673
return true;
671674
}
672675

@@ -678,25 +681,28 @@ bool RewriteSystem::hadError() const {
678681
/// rewrite system.
679682
///
680683
/// These rules form the requirement signatures of these protocols.
681-
llvm::DenseMap<const ProtocolDecl *, std::vector<unsigned>>
684+
llvm::DenseMap<const ProtocolDecl *, RewriteSystem::MinimizedProtocolRules>
682685
RewriteSystem::getMinimizedProtocolRules() const {
683686
assert(Minimized);
684687
assert(!Protos.empty());
685688

686-
llvm::DenseMap<const ProtocolDecl *, std::vector<unsigned>> rules;
689+
llvm::DenseMap<const ProtocolDecl *, MinimizedProtocolRules> rules;
687690
for (unsigned ruleID : indices(Rules)) {
688691
const auto &rule = getRule(ruleID);
689692

690693
if (rule.isPermanent() ||
691694
rule.isRedundant() ||
692-
rule.isConflicting() ||
693-
rule.containsUnresolvedSymbols()) {
695+
rule.isConflicting())
696+
continue;
697+
698+
const auto *proto = rule.getLHS().getRootProtocol();
699+
if (!isInMinimizationDomain(proto))
694700
continue;
695-
}
696701

697-
const auto *proto = rule.getLHS().begin()->getProtocol();
698-
if (std::find(Protos.begin(), Protos.end(), proto) != Protos.end())
699-
rules[proto].push_back(ruleID);
702+
if (rule.isProtocolTypeAliasRule())
703+
rules[proto].TypeAliases.push_back(ruleID);
704+
else if (!rule.containsUnresolvedSymbols())
705+
rules[proto].Requirements.push_back(ruleID);
700706
}
701707

702708
return rules;

lib/AST/RequirementMachine/MinimalConformances.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -852,7 +852,7 @@ void MinimalConformances::verifyMinimalConformances() const {
852852
continue;
853853
}
854854

855-
if (rule.getLHS().containsUnresolvedSymbols()) {
855+
if (rule.containsUnresolvedSymbols()) {
856856
llvm::errs() << "Minimal conformance contains unresolved symbols: ";
857857
llvm::errs() << rule << "\n\n";
858858
dumpMinimalConformanceEquations(llvm::errs());

lib/AST/RequirementMachine/RequirementMachine.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,10 @@ class RequirementMachine final {
109109
ArrayRef<unsigned> rules,
110110
TypeArrayView<GenericTypeParamType> genericParams) const;
111111

112+
std::vector<std::pair<Identifier, Type>> buildProtocolTypeAliasesFromRules(
113+
ArrayRef<unsigned> rules,
114+
TypeArrayView<GenericTypeParamType> genericParams) const;
115+
112116
TypeArrayView<GenericTypeParamType> getGenericParams() const {
113117
return TypeArrayView<GenericTypeParamType>(
114118
ArrayRef<Type>(Params));
@@ -140,7 +144,12 @@ class RequirementMachine final {
140144
ProtocolDecl *protocol);
141145
TypeDecl *lookupNestedType(Type depType, Identifier name) const;
142146

143-
llvm::DenseMap<const ProtocolDecl *, std::vector<Requirement>>
147+
struct MinimalProtocolRequirements {
148+
ArrayRef<Requirement> Requirements;
149+
ArrayRef<std::pair<Identifier, Type>> TypeAliases;
150+
};
151+
152+
llvm::DenseMap<const ProtocolDecl *, MinimalProtocolRequirements>
144153
computeMinimalProtocolRequirements();
145154

146155
std::vector<Requirement> computeMinimalGenericSignatureRequirements();

lib/AST/RequirementMachine/RequirementMachineRequests.cpp

Lines changed: 90 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -229,9 +229,72 @@ RequirementMachine::buildRequirementsFromRules(
229229
return reqs;
230230
}
231231

232+
/// Convert a list of protocol typealias rules to a list of name/underlying type
233+
/// pairs.
234+
std::vector<std::pair<Identifier, Type>>
235+
RequirementMachine::buildProtocolTypeAliasesFromRules(
236+
ArrayRef<unsigned> rules,
237+
TypeArrayView<GenericTypeParamType> genericParams) const {
238+
std::vector<std::pair<Identifier, Type>> aliases;
239+
240+
if (getDebugOptions().contains(DebugFlags::Minimization)) {
241+
llvm::dbgs() << "\nMinimized type aliases:\n";
242+
}
243+
244+
for (unsigned ruleID : rules) {
245+
const auto &rule = System.getRule(ruleID);
246+
auto name = *rule.isProtocolTypeAliasRule();
247+
Type underlyingType;
248+
249+
if (auto prop = rule.isPropertyRule()) {
250+
assert(prop->getKind() == Symbol::Kind::ConcreteType);
251+
252+
// Requirements containing unresolved name symbols originate from
253+
// invalid code and should not appear in the generic signature.
254+
for (auto term : prop->getSubstitutions()) {
255+
if (term.containsUnresolvedSymbols())
256+
continue;
257+
}
258+
259+
// Requirements containing error types originate from invalid code
260+
// and should not appear in the generic signature.
261+
if (prop->getConcreteType()->hasError())
262+
continue;
263+
264+
underlyingType = Map.getTypeFromSubstitutionSchema(
265+
prop->getConcreteType(),
266+
prop->getSubstitutions(),
267+
genericParams, MutableTerm());
268+
} else {
269+
underlyingType = Map.getTypeForTerm(rule.getRHS(), genericParams);
270+
}
271+
272+
aliases.emplace_back(name, underlyingType);
273+
274+
if (getDebugOptions().contains(DebugFlags::Minimization)) {
275+
PrintOptions opts;
276+
opts.ProtocolQualifiedDependentMemberTypes = true;
277+
278+
llvm::dbgs() << "- " << name << " == ";
279+
underlyingType.print(llvm::dbgs(), opts);
280+
llvm::dbgs() << "\n";
281+
}
282+
}
283+
284+
// Finally, sort the aliases in canonical order.
285+
llvm::array_pod_sort(aliases.begin(), aliases.end(),
286+
[](const std::pair<Identifier, Type> *lhs,
287+
const std::pair<Identifier, Type> *rhs) -> int {
288+
return lhs->first.compare(rhs->first);
289+
});
290+
291+
return aliases;
292+
}
293+
232294
/// Builds the requirement signatures for each protocol in this strongly
233295
/// connected component.
234-
llvm::DenseMap<const ProtocolDecl *, std::vector<Requirement>>
296+
llvm::DenseMap<const ProtocolDecl *,
297+
RequirementMachine::MinimalProtocolRequirements>
235298
RequirementMachine::computeMinimalProtocolRequirements() {
236299
auto protos = System.getProtocols();
237300

@@ -249,13 +312,23 @@ RequirementMachine::computeMinimalProtocolRequirements() {
249312

250313
auto rules = System.getMinimizedProtocolRules();
251314

315+
auto &ctx = Context.getASTContext();
316+
252317
// Note that we build 'result' by iterating over 'protos' rather than
253318
// 'rules'; this is intentional, so that even if a protocol has no
254319
// rules, we still end up creating an entry for it in 'result'.
255-
llvm::DenseMap<const ProtocolDecl *, std::vector<Requirement>> result;
320+
llvm::DenseMap<const ProtocolDecl *, MinimalProtocolRequirements> result;
256321
for (const auto *proto : protos) {
257322
auto genericParams = proto->getGenericSignature().getGenericParams();
258-
result[proto] = buildRequirementsFromRules(rules[proto], genericParams);
323+
324+
result[proto].Requirements =
325+
ctx.AllocateCopy(
326+
buildRequirementsFromRules(rules[proto].Requirements,
327+
genericParams));
328+
result[proto].TypeAliases =
329+
ctx.AllocateCopy(
330+
buildProtocolTypeAliasesFromRules(rules[proto].TypeAliases,
331+
genericParams));
259332
}
260333

261334
return result;
@@ -311,32 +384,37 @@ RequirementSignatureRequestRQM::evaluate(Evaluator &evaluator,
311384
// was kicked off with.
312385
ArrayRef<Requirement> result;
313386

387+
if (debug) {
388+
llvm::dbgs() << "\nRequirement signatures:\n";
389+
}
390+
314391
for (const auto &pair : minimalRequirements) {
315392
auto *otherProto = pair.first;
316393
const auto &reqs = pair.second;
317394

318-
// setRequirementSignature() doesn't take ownership of the memory, so
319-
// we have to make a copy of the std::vector temporary.
320-
ArrayRef<Requirement> reqsCopy = ctx.AllocateCopy(reqs);
321-
322395
// Dump the result if requested.
323396
if (debug) {
324-
llvm::dbgs() << "Protocol " << otherProto->getName() << ": ";
397+
llvm::dbgs() << "- Protocol " << otherProto->getName() << ": ";
325398

326399
auto sig = GenericSignature::get(
327400
otherProto->getGenericSignature().getGenericParams(),
328-
reqsCopy);
329-
llvm::dbgs() << sig << "\n";
401+
reqs.Requirements);
402+
403+
PrintOptions opts;
404+
opts.ProtocolQualifiedDependentMemberTypes = true;
405+
sig.print(llvm::dbgs(), opts);
406+
llvm::dbgs() << "\n";
330407
}
331408

332409
// Don't call setRequirementSignature() on the original proto; the
333410
// request evaluator will do it for us.
334411
if (otherProto == proto)
335-
result = reqsCopy;
412+
result = reqs.Requirements;
336413
else {
414+
auto temp = reqs.Requirements;
337415
ctx.evaluator.cacheOutput(
338416
RequirementSignatureRequestRQM{const_cast<ProtocolDecl *>(otherProto)},
339-
std::move(reqsCopy));
417+
std::move(temp));
340418
}
341419
}
342420

lib/AST/RequirementMachine/RewriteSystem.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -464,7 +464,12 @@ class RewriteSystem final {
464464

465465
bool hadError() const;
466466

467-
llvm::DenseMap<const ProtocolDecl *, std::vector<unsigned>>
467+
struct MinimizedProtocolRules {
468+
std::vector<unsigned> Requirements;
469+
std::vector<unsigned> TypeAliases;
470+
};
471+
472+
llvm::DenseMap<const ProtocolDecl *, MinimizedProtocolRules>
468473
getMinimizedProtocolRules() const;
469474

470475
std::vector<unsigned> getMinimizedGenericSignatureRules() const;

0 commit comments

Comments
 (0)