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