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