@@ -9254,36 +9254,71 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyMemberConstraint(
9254
9254
}
9255
9255
}
9256
9256
9257
- // Special handling of injected references to `makeIterator` in for-in loops.
9258
- {
9259
- auto memberRef = getAsExpr<UnresolvedDotExpr>(locator->getAnchor());
9257
+ // Special handling of injected references to `makeIterator` and `next`
9258
+ // in for-in loops.
9259
+ if (auto *expr = getAsExpr(locator->getAnchor())) {
9260
+ // `next()` could be wrapped in `await` expression.
9261
+ auto memberRef =
9262
+ getAsExpr<UnresolvedDotExpr>(expr->getSemanticsProvidingExpr());
9263
+
9260
9264
if (memberRef && memberRef->isImplicit() &&
9261
9265
locator->isLastElement<LocatorPathElt::Member>()) {
9266
+ auto &ctx = getASTContext();
9267
+
9262
9268
// Cannot simplify this constraint yet since we don't know whether
9263
9269
// the base type is going to be existential or not.
9264
9270
if (baseObjTy->isTypeVariableOrMember())
9265
9271
return formUnsolved();
9266
9272
9267
- auto *sequenceExpr = memberRef->getBase();
9273
+ // Check whether the given dot expression is a reference
9274
+ // to the given name with the given set of argument labels
9275
+ // (aka compound name).
9276
+ auto isRefTo = [&](UnresolvedDotExpr *UDE, Identifier name,
9277
+ ArrayRef<StringRef> labels) {
9278
+ auto refName = UDE->getName().getFullName();
9279
+ return refName.isCompoundName(name, labels);
9280
+ };
9281
+
9282
+ auto *baseExpr = memberRef->getBase();
9268
9283
// If base type is an existential, member lookup is fine because
9269
9284
// it would return a witness.
9270
- if (!baseObjTy->isExistentialType() &&
9271
- getContextualTypePurpose(sequenceExpr) == CTP_ForEachSequence) {
9272
- auto &ctx = getASTContext();
9273
-
9274
- auto *sequenceProto = cast<ProtocolDecl>(
9275
- getContextualType(sequenceExpr, /*forConstraint=*/false)
9276
- ->getAnyNominal());
9277
- bool isAsync = sequenceProto ==
9278
- TypeChecker::getProtocol(
9279
- ctx, SourceLoc(), KnownProtocolKind::AsyncSequence);
9280
-
9281
- auto *makeIterator = isAsync ? ctx.getAsyncSequenceMakeAsyncIterator()
9282
- : ctx.getSequenceMakeIterator();
9285
+ if (!baseObjTy->isExistentialType()) {
9286
+ // Handle `makeIterator` reference.
9287
+ if (getContextualTypePurpose(baseExpr) == CTP_ForEachSequence &&
9288
+ isRefTo(memberRef, ctx.Id_makeIterator, /*lables=*/{})) {
9289
+ auto *sequenceProto = cast<ProtocolDecl>(
9290
+ getContextualType(baseExpr, /*forConstraint=*/false)
9291
+ ->getAnyNominal());
9292
+ bool isAsync = sequenceProto == TypeChecker::getProtocol(
9293
+ ctx, SourceLoc(),
9294
+ KnownProtocolKind::AsyncSequence);
9295
+
9296
+ auto *makeIterator = isAsync ? ctx.getAsyncSequenceMakeAsyncIterator()
9297
+ : ctx.getSequenceMakeIterator();
9298
+
9299
+ return simplifyValueWitnessConstraint(
9300
+ ConstraintKind::ValueWitness, baseTy, makeIterator, memberTy, DC,
9301
+ FunctionRefKind::Compound, flags, locator);
9302
+ }
9283
9303
9284
- return simplifyValueWitnessConstraint(
9285
- ConstraintKind::ValueWitness, baseTy, makeIterator, memberTy, DC,
9286
- FunctionRefKind::Compound, flags, locator);
9304
+ // Handle `next` reference.
9305
+ if (getContextualTypePurpose(baseExpr) == CTP_ForEachSequence &&
9306
+ isRefTo(memberRef, ctx.Id_next, /*labels=*/{})) {
9307
+ auto *iteratorProto = cast<ProtocolDecl>(
9308
+ getContextualType(baseExpr, /*forConstraint=*/false)
9309
+ ->getAnyNominal());
9310
+ bool isAsync =
9311
+ iteratorProto ==
9312
+ TypeChecker::getProtocol(
9313
+ ctx, SourceLoc(), KnownProtocolKind::AsyncIteratorProtocol);
9314
+
9315
+ auto *next =
9316
+ isAsync ? ctx.getAsyncIteratorNext() : ctx.getIteratorNext();
9317
+
9318
+ return simplifyValueWitnessConstraint(
9319
+ ConstraintKind::ValueWitness, baseTy, next, memberTy, DC,
9320
+ FunctionRefKind::Compound, flags, locator);
9321
+ }
9287
9322
}
9288
9323
}
9289
9324
}
0 commit comments