Skip to content

Commit 35daf17

Browse files
committed
RequirementMachine: Implement RewriteContext::getTypeForTerm()
Protocol atoms map to the 'Self' parameter; GenericParam and Name atoms map in the obvious way. An associated type atom `[P1&P1&...&Pn:A]` has one or more protocols P0...Pn and an identifier 'A'. We map it back to a AssociatedTypeDecl as follows: - For each protocol Pn, look for associated types A in Pn itself, and all protocols that Pn refines. - For each candidate associated type An in protocol Qn where Pn refines Qn, get the associated type anchor An' defined in protocol Qn', where Qn refines Qn'. - Out of all the candidiate pairs (Qn', An'), pick the one where the protocol Qn' is the lowest element according to the linear order defined by TypeDecl::compare(). The associated type An' is then the canonical associated type representative of the associated type atom `[P0&...&Pn:A]`.
1 parent 2a1c141 commit 35daf17

File tree

2 files changed

+162
-0
lines changed

2 files changed

+162
-0
lines changed

lib/AST/RequirementMachine/RewriteSystem.cpp

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -938,6 +938,156 @@ MutableTerm RewriteContext::getMutableTermForType(CanType paramType,
938938
return MutableTerm(atoms);
939939
}
940940

941+
/// Compute the interface type for a range of atoms, with an optional
942+
/// root type.
943+
///
944+
/// If the root type is specified, we wrap it in a series of
945+
/// DependentMemberTypes. Otherwise, the root is computed from
946+
/// the first atom of the range.
947+
template<typename Iter>
948+
Type getTypeForAtomRange(Iter begin, Iter end, Type root,
949+
TypeArrayView<GenericTypeParamType> genericParams,
950+
const ProtocolGraph &protos,
951+
ASTContext &ctx) {
952+
Type result = root;
953+
954+
auto handleRoot = [&](GenericTypeParamType *genericParam) {
955+
assert(genericParam->isCanonical());
956+
957+
if (!genericParams.empty()) {
958+
// Return a sugared GenericTypeParamType if we're given an array of
959+
// sugared types to substitute.
960+
unsigned index = GenericParamKey(genericParam).findIndexIn(genericParams);
961+
result = genericParams[index];
962+
return;
963+
}
964+
965+
// Otherwise, we're going to return a canonical type.
966+
result = genericParam;
967+
};
968+
969+
for (; begin != end; ++begin) {
970+
auto atom = *begin;
971+
972+
if (!result) {
973+
// A valid term always begins with a generic parameter, protocol or
974+
// associated type atom.
975+
switch (atom.getKind()) {
976+
case Atom::Kind::GenericParam:
977+
handleRoot(atom.getGenericParam());
978+
continue;
979+
980+
case Atom::Kind::Protocol:
981+
handleRoot(GenericTypeParamType::get(0, 0, ctx));
982+
continue;
983+
984+
case Atom::Kind::AssociatedType:
985+
handleRoot(GenericTypeParamType::get(0, 0, ctx));
986+
987+
// An associated type term at the root means we have a dependent
988+
// member type rooted at Self; handle the associated type below.
989+
break;
990+
991+
case Atom::Kind::Name:
992+
case Atom::Kind::Layout:
993+
case Atom::Kind::Superclass:
994+
case Atom::Kind::ConcreteType:
995+
llvm_unreachable("Term has invalid root atom");
996+
}
997+
}
998+
999+
// An unresolved type can appear if we have invalid requirements.
1000+
if (atom.getKind() == Atom::Kind::Name) {
1001+
result = DependentMemberType::get(result, atom.getName());
1002+
continue;
1003+
}
1004+
1005+
// We should have a resolved type at this point.
1006+
assert(atom.getKind() == Atom::Kind::AssociatedType);
1007+
auto *proto = atom.getProtocols()[0];
1008+
auto name = atom.getName();
1009+
1010+
AssociatedTypeDecl *assocType = nullptr;
1011+
1012+
// Special case: handle unknown protocols, since they can appear in the
1013+
// invalid types that getCanonicalTypeInContext() must handle via
1014+
// concrete substitution; see the definition of getCanonicalTypeInContext()
1015+
// below for details.
1016+
if (!protos.isKnownProtocol(proto)) {
1017+
assert(root &&
1018+
"We only allow unknown protocols in getRelativeTypeForTerm()");
1019+
assert(atom.getProtocols().size() == 1 &&
1020+
"Unknown associated type atom must have a single protocol");
1021+
assocType = proto->getAssociatedType(name)->getAssociatedTypeAnchor();
1022+
} else {
1023+
// FIXME: Cache this
1024+
//
1025+
// An associated type atom [P1&P1&...&Pn:A] has one or more protocols
1026+
// P0...Pn and an identifier 'A'.
1027+
//
1028+
// We map it back to a AssociatedTypeDecl as follows:
1029+
//
1030+
// - For each protocol Pn, look for associated types A in Pn itself,
1031+
// and all protocols that Pn refines.
1032+
//
1033+
// - For each candidate associated type An in protocol Qn where
1034+
// Pn refines Qn, get the associated type anchor An' defined in
1035+
// protocol Qn', where Qn refines Qn'.
1036+
//
1037+
// - Out of all the candidiate pairs (Qn', An'), pick the one where
1038+
// the protocol Qn' is the lowest element according to the linear
1039+
// order defined by TypeDecl::compare().
1040+
//
1041+
// The associated type An' is then the canonical associated type
1042+
// representative of the associated type atom [P0&...&Pn:A].
1043+
//
1044+
for (auto *proto : atom.getProtocols()) {
1045+
const auto &info = protos.getProtocolInfo(proto);
1046+
for (auto *otherAssocType : info.AssociatedTypes) {
1047+
otherAssocType = otherAssocType->getAssociatedTypeAnchor();
1048+
1049+
if (otherAssocType->getName() == name &&
1050+
(assocType == nullptr ||
1051+
TypeDecl::compare(otherAssocType->getProtocol(),
1052+
assocType->getProtocol()) < 0)) {
1053+
assocType = otherAssocType;
1054+
}
1055+
}
1056+
}
1057+
}
1058+
1059+
assert(assocType && "Need to look harder");
1060+
result = DependentMemberType::get(result, assocType);
1061+
}
1062+
1063+
return result;
1064+
}
1065+
1066+
Type RewriteContext::getTypeForTerm(Term term,
1067+
TypeArrayView<GenericTypeParamType> genericParams,
1068+
const ProtocolGraph &protos) const {
1069+
return getTypeForAtomRange(term.begin(), term.end(), Type(),
1070+
genericParams, protos, Context);
1071+
}
1072+
1073+
Type RewriteContext::getTypeForTerm(const MutableTerm &term,
1074+
TypeArrayView<GenericTypeParamType> genericParams,
1075+
const ProtocolGraph &protos) const {
1076+
return getTypeForAtomRange(term.begin(), term.end(), Type(),
1077+
genericParams, protos, Context);
1078+
}
1079+
1080+
Type RewriteContext::getRelativeTypeForTerm(
1081+
const MutableTerm &term, const MutableTerm &prefix,
1082+
const ProtocolGraph &protos) const {
1083+
assert(std::equal(prefix.begin(), prefix.end(), term.begin()));
1084+
1085+
auto genericParam = CanGenericTypeParamType::get(0, 0, Context);
1086+
return getTypeForAtomRange(
1087+
term.begin() + prefix.size(), term.end(), genericParam,
1088+
{ }, protos, Context);
1089+
}
1090+
9411091
void Rule::dump(llvm::raw_ostream &out) const {
9421092
out << LHS << " => " << RHS;
9431093
if (deleted)

lib/AST/RequirementMachine/RewriteSystem.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,18 @@ class RewriteContext final {
434434
const ProtocolDecl *proto);
435435

436436
ASTContext &getASTContext() { return Context; }
437+
438+
Type getTypeForTerm(Term term,
439+
TypeArrayView<GenericTypeParamType> genericParams,
440+
const ProtocolGraph &protos) const;
441+
442+
Type getTypeForTerm(const MutableTerm &term,
443+
TypeArrayView<GenericTypeParamType> genericParams,
444+
const ProtocolGraph &protos) const;
445+
446+
Type getRelativeTypeForTerm(
447+
const MutableTerm &term, const MutableTerm &prefix,
448+
const ProtocolGraph &protos) const;
437449
};
438450

439451
/// A rewrite rule that replaces occurrences of LHS with RHS.

0 commit comments

Comments
 (0)