|
33 | 33 | #include <vector> |
34 | 34 |
|
35 | 35 | #include "PropertyMap.h" |
| 36 | +#include "RequirementLowering.h" |
36 | 37 |
|
37 | 38 | using namespace swift; |
38 | 39 | using namespace rewriting; |
@@ -703,15 +704,16 @@ void PropertyMap::concretizeNestedTypesFromConcreteParent( |
703 | 704 | recordConcreteConformanceRule(concreteRuleID, conformanceRuleID, |
704 | 705 | requirementKind, concreteConformanceSymbol); |
705 | 706 |
|
706 | | - auto assocTypes = proto->getAssociatedTypeMembers(); |
707 | | - if (assocTypes.empty()) |
708 | | - continue; |
709 | | - |
710 | | - for (auto *assocType : assocTypes) { |
| 707 | + for (auto *assocType : proto->getAssociatedTypeMembers()) { |
711 | 708 | concretizeTypeWitnessInConformance(key, requirementKind, |
712 | 709 | concreteConformanceSymbol, |
713 | 710 | concrete, assocType); |
714 | 711 | } |
| 712 | + |
| 713 | + // We only infer conditional requirements in top-level generic signatures, |
| 714 | + // not in protocol requirement signatures. |
| 715 | + if (key.getRootProtocols().empty()) |
| 716 | + inferConditionalRequirements(concrete, substitutions); |
715 | 717 | } |
716 | 718 | } |
717 | 719 |
|
@@ -1002,3 +1004,80 @@ void PropertyMap::recordConcreteConformanceRule( |
1002 | 1004 |
|
1003 | 1005 | (void) System.addRule(std::move(lhs), std::move(rhs), &path); |
1004 | 1006 | } |
| 1007 | + |
| 1008 | +/// If \p key is fixed to a concrete type and is also subject to a conformance |
| 1009 | +/// requirement, the concrete type might conform conditionally. In this case, |
| 1010 | +/// introduce rules for any conditional requirements in the given conformance. |
| 1011 | +void PropertyMap::inferConditionalRequirements( |
| 1012 | + ProtocolConformance *concrete, ArrayRef<Term> substitutions) const { |
| 1013 | + |
| 1014 | + auto conditionalRequirements = concrete->getConditionalRequirements(); |
| 1015 | + |
| 1016 | + if (Debug.contains(DebugFlags::ConditionalRequirements)) { |
| 1017 | + if (conditionalRequirements.empty()) |
| 1018 | + llvm::dbgs() << "@@ No conditional requirements from "; |
| 1019 | + else |
| 1020 | + llvm::dbgs() << "@@ Inferring conditional requirements from "; |
| 1021 | + |
| 1022 | + llvm::dbgs() << concrete->getType() << " : "; |
| 1023 | + llvm::dbgs() << concrete->getProtocol()->getName() << "\n"; |
| 1024 | + } |
| 1025 | + |
| 1026 | + if (conditionalRequirements.empty()) |
| 1027 | + return; |
| 1028 | + |
| 1029 | + SmallVector<Requirement, 2> desugaredRequirements; |
| 1030 | + |
| 1031 | + // First, desugar all conditional requirements. |
| 1032 | + for (auto req : conditionalRequirements) { |
| 1033 | + if (Debug.contains(DebugFlags::ConditionalRequirements)) { |
| 1034 | + llvm::dbgs() << "@@@ Original requirement: "; |
| 1035 | + req.dump(llvm::dbgs()); |
| 1036 | + llvm::dbgs() << "\n"; |
| 1037 | + } |
| 1038 | + |
| 1039 | + desugarRequirement(req, desugaredRequirements); |
| 1040 | + } |
| 1041 | + |
| 1042 | + // Now, convert desugared conditional requirements to rules. |
| 1043 | + for (auto req : desugaredRequirements) { |
| 1044 | + if (Debug.contains(DebugFlags::ConditionalRequirements)) { |
| 1045 | + llvm::dbgs() << "@@@ Desugared requirement: "; |
| 1046 | + req.dump(llvm::dbgs()); |
| 1047 | + llvm::dbgs() << "\n"; |
| 1048 | + } |
| 1049 | + |
| 1050 | + if (req.getKind() == RequirementKind::Conformance) { |
| 1051 | + auto *proto = req.getProtocolDecl(); |
| 1052 | + |
| 1053 | + // If we haven't seen this protocol before, add rules for its |
| 1054 | + // requirements. |
| 1055 | + if (!System.isKnownProtocol(proto)) { |
| 1056 | + if (Debug.contains(DebugFlags::ConditionalRequirements)) { |
| 1057 | + llvm::dbgs() << "@@@ Unknown protocol: "<< proto->getName() << "\n"; |
| 1058 | + } |
| 1059 | + |
| 1060 | + RuleBuilder builder(Context, System.getProtocolMap()); |
| 1061 | + builder.addProtocol(proto, /*initialComponent=*/false); |
| 1062 | + builder.collectRulesFromReferencedProtocols(); |
| 1063 | + |
| 1064 | + for (const auto &rule : builder.PermanentRules) |
| 1065 | + System.addPermanentRule(rule.first, rule.second); |
| 1066 | + |
| 1067 | + for (const auto &rule : builder.RequirementRules) |
| 1068 | + System.addExplicitRule(rule.first, rule.second); |
| 1069 | + } |
| 1070 | + } |
| 1071 | + |
| 1072 | + auto pair = getRuleForRequirement(req.getCanonical(), /*proto=*/nullptr, |
| 1073 | + substitutions, Context); |
| 1074 | + |
| 1075 | + if (Debug.contains(DebugFlags::ConditionalRequirements)) { |
| 1076 | + llvm::dbgs() << "@@@ Induced rule from conditional requirement: " |
| 1077 | + << pair.first << " => " << pair.second << "\n"; |
| 1078 | + } |
| 1079 | + |
| 1080 | + // FIXME: Do we need a rewrite path here? |
| 1081 | + (void) System.addRule(pair.first, pair.second); |
| 1082 | + } |
| 1083 | +} |
0 commit comments