@@ -938,6 +938,156 @@ MutableTerm RewriteContext::getMutableTermForType(CanType paramType,
938
938
return MutableTerm (atoms);
939
939
}
940
940
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
+
941
1091
void Rule::dump (llvm::raw_ostream &out) const {
942
1092
out << LHS << " => " << RHS;
943
1093
if (deleted)
0 commit comments