@@ -886,8 +886,7 @@ void AssociatedTypeInference::collectAbstractTypeWitnesses(
886
886
if (auto genericSig = dc->getGenericSignatureOfContext ()) {
887
887
for (auto *gp : genericSig.getInnermostGenericParams ()) {
888
888
if (gp->getName () == assocType->getName ()) {
889
- system.addTypeWitness (assocType->getName (),
890
- dc->mapTypeIntoContext (gp));
889
+ system.addTypeWitness (assocType->getName (), gp);
891
890
}
892
891
}
893
892
}
@@ -1153,39 +1152,130 @@ AssociatedTypeDecl *AssociatedTypeInference::inferAbstractTypeWitnesses(
1153
1152
1154
1153
// Check each abstract type witness against the generic requirements on the
1155
1154
// corresponding associated type.
1155
+ //
1156
+ // FIXME: Consider checking non-dependent type witnesses first. Checking in
1157
+ // default order can lead to the creation and exposure of malformed types in
1158
+ // diagnostics. For example, we would diagnose that 'G<Never>' (!) does not
1159
+ // conform to 'Sequence' in the below.
1160
+ //
1161
+ // struct G<S: Sequence> {}
1162
+ // protocol P {
1163
+ // associatedtype A: Sequence = G<B>
1164
+ // associatedtype B: Sequence = Never
1165
+ // }
1156
1166
const auto substOptions = getSubstOptionsWithCurrentTypeWitnesses ();
1157
1167
for (auto *const assocType : unresolvedAssocTypes) {
1158
1168
Type type = system.getResolvedTypeWitness (assocType->getName ());
1169
+ // Replace type parameters with other known or tentative type witnesses.
1159
1170
if (type->hasTypeParameter ()) {
1160
- // Replace type parameters with other known or tentative type witnesses.
1161
- type = type.subst (
1162
- [&](SubstitutableType *type) {
1163
- if (type->isEqual (proto->getSelfInterfaceType ()))
1164
- return adoptee;
1171
+ // FIXME: We should find a better way to detect and reason about these
1172
+ // cyclic solutions so that we can spot them earlier and express them in
1173
+ // diagnostics.
1174
+ llvm::SmallPtrSet<AssociatedTypeDecl *, 4 > circularityCheck;
1175
+ circularityCheck.insert (assocType);
1176
+
1177
+ std::function<Type (Type)> substCurrentTypeWitnesses;
1178
+ substCurrentTypeWitnesses = [&](Type ty) -> Type {
1179
+ if (auto *gp = ty->getAs <GenericTypeParamType>()) {
1180
+ if (isa<ProtocolDecl>(gp->getDecl ()->getDeclContext ()->getAsDecl ())) {
1181
+ return adoptee;
1182
+ }
1165
1183
1166
- return Type ();
1167
- },
1168
- LookUpConformanceInModule (dc->getParentModule ()), substOptions);
1184
+ return ty;
1185
+ }
1169
1186
1170
- // If the substitution produced an error, give up.
1171
- if (type->hasError ())
1172
- return assocType;
1187
+ auto *const dmt = ty->getAs <DependentMemberType>();
1188
+ if (!dmt) {
1189
+ return ty;
1190
+ }
1173
1191
1174
- // FIXME: We should find a better way to detect and reason about these
1175
- // cyclic solutions.
1176
- // If mapping into context yields an error, or we still have a type
1177
- // parameter despite not having a generic environment, then a type
1178
- // parameter was sent to a tentative type witness that itself is a type
1179
- // parameter, and the solution is cyclic, e.g { A := B.A, B := A.B };
1180
- // bail out in these cases.
1181
- if (dc->isGenericContext ()) {
1182
- type = dc->mapTypeIntoContext (type);
1183
-
1184
- if (type->hasError ())
1185
- return assocType;
1186
- } else if (type->hasTypeParameter ()) {
1192
+ const auto substBase =
1193
+ dmt->getBase ().transform (substCurrentTypeWitnesses);
1194
+ if (!substBase) {
1195
+ return nullptr ;
1196
+ }
1197
+
1198
+ // If the transformed base has the same nominal as the adoptee, we may
1199
+ // need to look up a tentative type witness. Otherwise, just substitute
1200
+ // the base.
1201
+ if (substBase->getAnyNominal () != adoptee->getAnyNominal ()) {
1202
+ return dmt->substBaseType (dc->getParentModule (), substBase);
1203
+ }
1204
+
1205
+ auto *assocTy = dmt->getAssocType ();
1206
+ assert (
1207
+ assocTy &&
1208
+ " found structural DependentMemberType in tentative type witness" );
1209
+
1210
+ // Intercept recursive solutions.
1211
+ if (!circularityCheck.insert (assocTy).second ) {
1212
+ return nullptr ;
1213
+ }
1214
+ SWIFT_DEFER { circularityCheck.erase (dmt->getAssocType ()); };
1215
+
1216
+ if (assocTy->getProtocol () == proto) {
1217
+ // We have the associated type we need.
1218
+ } else if (proto->inheritsFrom (assocTy->getProtocol ())) {
1219
+ // See if there is an associated type with the same name in our
1220
+ // protocol. If there isn't, keep the original associated type:
1221
+ // we'll be falling back to a base substitution.
1222
+ if (auto *decl = proto->getAssociatedType (assocTy->getName ())) {
1223
+ assocTy = decl;
1224
+ }
1225
+ }
1226
+
1227
+ // Find the type witness for this associated type.
1228
+ Type tyWitness;
1229
+ if (assocTy->getProtocol () == proto && typeWitnesses.count (assocTy)) {
1230
+ tyWitness = typeWitnesses.begin (assocTy)->first ;
1231
+
1232
+ // A tentative type witness may contain a 'Self'-rooted type
1233
+ // parameter,
1234
+ // FIXME: or a weird concrete-type-rooted dependent member type
1235
+ // coming from inference via a value witness. Make sure we sort these
1236
+ // out so that we don't break any subst() invariants.
1237
+ if (tyWitness->hasTypeParameter () ||
1238
+ tyWitness->hasDependentMember ()) {
1239
+ tyWitness = tyWitness.transform (substCurrentTypeWitnesses);
1240
+ }
1241
+
1242
+ if (tyWitness) {
1243
+ // HACK: Those inferred via value witnesses are eagerly mapped into
1244
+ // context. For now, do the same for abstract type witnesses and
1245
+ // handle archetypes.
1246
+ if (tyWitness->hasArchetype ()) {
1247
+ tyWitness = tyWitness->mapTypeOutOfContext ();
1248
+ }
1249
+
1250
+ // If the transformed base is specialized, apply substitutions.
1251
+ if (tyWitness->hasTypeParameter ()) {
1252
+ const auto conf = dc->getParentModule ()->lookupConformance (
1253
+ substBase, assocTy->getProtocol (), /* allowMissing=*/ true );
1254
+ if (auto *specialized = dyn_cast<SpecializedProtocolConformance>(
1255
+ conf.getConcrete ())) {
1256
+ tyWitness = tyWitness.subst (specialized->getSubstitutionMap ());
1257
+ }
1258
+ }
1259
+ }
1260
+ } else {
1261
+ // The associated type has a recorded type witness, or comes from a
1262
+ // different, possibly unrelated protocol; fall back to a base
1263
+ // substitution to find the type witness.
1264
+ tyWitness =
1265
+ DependentMemberType::get (proto->getSelfInterfaceType (), assocTy)
1266
+ ->substBaseType (dc->getParentModule (), substBase);
1267
+ }
1268
+
1269
+ return tyWitness;
1270
+ };
1271
+
1272
+ type = type.transform (substCurrentTypeWitnesses);
1273
+
1274
+ // If substitution failed, give up.
1275
+ if (!type || type->hasError ())
1187
1276
return assocType;
1188
- }
1277
+
1278
+ type = dc->mapTypeIntoContext (type);
1189
1279
}
1190
1280
1191
1281
if (const auto failed =
0 commit comments