@@ -8354,17 +8354,53 @@ static Type getOpenedResultBuilderTypeFor(ConstraintSystem &cs,
8354
8354
bool ConstraintSystem::resolveClosure (TypeVariableType *typeVar,
8355
8355
Type contextualType,
8356
8356
ConstraintLocatorBuilder locator) {
8357
+ auto *closureLocator = typeVar->getImpl ().getLocator ();
8358
+ auto *closure = castToExpr<ClosureExpr>(closureLocator->getAnchor ());
8359
+ auto *inferredClosureType = getClosureType (closure);
8360
+
8357
8361
auto getContextualParamAt =
8358
- [&contextualType](unsigned index) -> Optional<AnyFunctionType::Param> {
8362
+ [&contextualType, &inferredClosureType](
8363
+ unsigned index) -> Optional<AnyFunctionType::Param> {
8359
8364
auto *fnType = contextualType->getAs <FunctionType>();
8360
- return fnType && fnType->getNumParams () > index
8361
- ? fnType->getParams ()[index]
8362
- : Optional<AnyFunctionType::Param>();
8365
+ if (!fnType)
8366
+ return None;
8367
+
8368
+ auto numContextualParams = fnType->getNumParams ();
8369
+ if (numContextualParams != inferredClosureType->getNumParams () ||
8370
+ numContextualParams <= index)
8371
+ return None;
8372
+
8373
+ return fnType->getParams ()[index];
8363
8374
};
8364
8375
8365
- auto *closureLocator = typeVar->getImpl ().getLocator ();
8366
- auto *closure = castToExpr<ClosureExpr>(closureLocator->getAnchor ());
8367
- auto *inferredClosureType = getClosureType (closure);
8376
+ // Check whether given contextual parameter type could be
8377
+ // used to bind external closure parameter type.
8378
+ auto isSuitableContextualType = [](Type contextualTy) {
8379
+ // We need to wait until contextual type
8380
+ // is fully resolved before binding it.
8381
+ if (contextualTy->isTypeVariableOrMember ())
8382
+ return false ;
8383
+
8384
+ // If contextual type has an error, let's wait for inference,
8385
+ // otherwise contextual would interfere with diagnostics.
8386
+ if (contextualTy->hasError ())
8387
+ return false ;
8388
+
8389
+ if (isa<TypeAliasType>(contextualTy.getPointer ())) {
8390
+ auto underlyingTy = contextualTy->getDesugaredType ();
8391
+ // FIXME: typealias pointing to an existential type is special
8392
+ // because if the typealias has type variables then we'd end up
8393
+ // opening existential from a type with unresolved generic
8394
+ // parameter(s), which CSApply can't currently simplify while
8395
+ // building type-checked AST because `OpenedArchetypeType` doesn't
8396
+ // propagate flags. Example is as simple as `{ $0.description }`
8397
+ // where `$0` is `Error` that inferred from a (generic) typealias.
8398
+ if (underlyingTy->isExistentialType () && contextualTy->hasTypeVariable ())
8399
+ return false ;
8400
+ }
8401
+
8402
+ return true ;
8403
+ };
8368
8404
8369
8405
// Determine whether a result builder will be applied.
8370
8406
auto resultBuilderType = getOpenedResultBuilderTypeFor (*this , locator);
@@ -8456,6 +8492,24 @@ bool ConstraintSystem::resolveClosure(TypeVariableType *typeVar,
8456
8492
param.isVariadic () ? ArraySliceType::get (typeVar) : Type (typeVar);
8457
8493
8458
8494
auto externalType = param.getOldType ();
8495
+
8496
+ // Performance optimization.
8497
+ //
8498
+ // If there is a concrete contextual type we could use, let's bind
8499
+ // it to the external type right away because internal type has to
8500
+ // be equal to that type anyway (through `BindParam` on external type
8501
+ // i.e. <internal> bind param <external> conv <concrete contextual>).
8502
+ //
8503
+ // Note: it's correct to avoid doing this, but it would result
8504
+ // in (a lot) more checking since solver would have to re-discover,
8505
+ // re-attempt and fail parameter type while solving for overloaded
8506
+ // choices in the body.
8507
+ if (auto contextualParam = getContextualParamAt (i)) {
8508
+ auto paramTy = simplifyType (contextualParam->getOldType ());
8509
+ if (isSuitableContextualType (paramTy))
8510
+ addConstraint (ConstraintKind::Bind, externalType, paramTy, paramLoc);
8511
+ }
8512
+
8459
8513
if (oneWayConstraints) {
8460
8514
addConstraint (
8461
8515
ConstraintKind::OneWayBindParam, typeVar, externalType, paramLoc);
0 commit comments