@@ -1316,6 +1316,14 @@ Type ConstraintSystem::getFixedTypeRecursive(Type type, TypeMatchOptions &flags,
1316
1316
return getFixedTypeRecursive (simplified, flags, wantRValue);
1317
1317
}
1318
1318
1319
+ if (auto metatype = type->getAs <AnyMetatypeType>()) {
1320
+ auto simplified = simplifyType (type);
1321
+ if (simplified.getPointer () == type.getPointer ())
1322
+ return type;
1323
+
1324
+ return getFixedTypeRecursive (simplified, flags, wantRValue);
1325
+ }
1326
+
1319
1327
if (auto typeVar = type->getAs <TypeVariableType>()) {
1320
1328
if (auto fixed = getFixedType (typeVar))
1321
1329
return getFixedTypeRecursive (fixed, flags, wantRValue);
@@ -2420,10 +2428,25 @@ Type constraints::typeEraseOpenedArchetypesWithRoot(
2420
2428
/* force=*/ true );
2421
2429
}
2422
2430
2431
+ static bool isExistentialMemberAccessWithExplicitBaseExpression (
2432
+ Type baseInstanceTy, ValueDecl *member, ConstraintLocator *locator,
2433
+ bool isDynamicLookup) {
2434
+ if (isDynamicLookup) {
2435
+ return false ;
2436
+ }
2437
+
2438
+ // '.x' does not have an explicit base expression.
2439
+ if (locator->isLastElement <LocatorPathElt::UnresolvedMember>()) {
2440
+ return false ;
2441
+ }
2442
+
2443
+ return baseInstanceTy->isExistentialType () &&
2444
+ member->getDeclContext ()->getSelfProtocolDecl ();
2445
+ }
2446
+
2423
2447
Type ConstraintSystem::getMemberReferenceTypeFromOpenedType (
2424
2448
Type &openedType, Type baseObjTy, ValueDecl *value, DeclContext *outerDC,
2425
- ConstraintLocator *locator, bool hasAppliedSelf,
2426
- bool isStaticMemberRefOnProtocol, bool isDynamicResult,
2449
+ ConstraintLocator *locator, bool hasAppliedSelf, bool isDynamicLookup,
2427
2450
OpenedTypeMap &replacements) {
2428
2451
Type type = openedType;
2429
2452
@@ -2450,7 +2473,7 @@ Type ConstraintSystem::getMemberReferenceTypeFromOpenedType(
2450
2473
2451
2474
// Check if we need to apply a layer of optionality to the uncurried type.
2452
2475
if (!isRequirementOrWitness (locator)) {
2453
- if (isDynamicResult || value->getAttrs ().hasAttribute <OptionalAttr>()) {
2476
+ if (isDynamicLookup || value->getAttrs ().hasAttribute <OptionalAttr>()) {
2454
2477
const auto applyOptionality = [&](FunctionType *fnTy) -> Type {
2455
2478
Type resultTy;
2456
2479
// Optional and dynamic subscripts are a special case, because the
@@ -2490,12 +2513,13 @@ Type ConstraintSystem::getMemberReferenceTypeFromOpenedType(
2490
2513
type = type->replaceSelfParameterType (baseObjTy);
2491
2514
}
2492
2515
2493
- // Superficially, protocol members with an existential base are accessed
2494
- // directly on the existential, and not an opened archetype, and we may have
2495
- // to adjust the type of the reference (e.g. covariant 'Self' type-erasure) to
2496
- // support certain accesses.
2497
- if (!isStaticMemberRefOnProtocol && !isDynamicResult &&
2498
- baseObjTy->isExistentialType () && outerDC->getSelfProtocolDecl () &&
2516
+ // From the user perspective, protocol members that are accessed with an
2517
+ // existential base are accessed directly on the existential, and not an
2518
+ // opened archetype, so the type of the member reference must be abstracted
2519
+ // away (upcast) from context-specific types like `Self` in covariant
2520
+ // position.
2521
+ if (isExistentialMemberAccessWithExplicitBaseExpression (
2522
+ baseObjTy, value, locator, isDynamicLookup) &&
2499
2523
// If there are no type variables, there were no references to 'Self'.
2500
2524
type->hasTypeVariable ()) {
2501
2525
const auto selfGP = cast<GenericTypeParamType>(
@@ -2504,13 +2528,6 @@ Type ConstraintSystem::getMemberReferenceTypeFromOpenedType(
2504
2528
2505
2529
type = typeEraseOpenedExistentialReference (type, baseObjTy, openedTypeVar,
2506
2530
TypePosition::Covariant);
2507
-
2508
- Type contextualTy;
2509
-
2510
- if (auto *anchor = getAsExpr (simplifyLocatorToAnchor (locator))) {
2511
- contextualTy =
2512
- getContextualType (getParentExpr (anchor), /* forConstraint=*/ false );
2513
- }
2514
2531
}
2515
2532
2516
2533
// Construct an idealized parameter type of the initializer associated
@@ -2591,12 +2608,9 @@ bool ConstraintSystem::isPartialApplication(ConstraintLocator *locator) {
2591
2608
return level < (baseTy->is <MetatypeType>() ? 1 : 2 );
2592
2609
}
2593
2610
2594
- DeclReferenceType
2595
- ConstraintSystem::getTypeOfMemberReference (
2596
- Type baseTy, ValueDecl *value, DeclContext *useDC,
2597
- bool isDynamicResult,
2598
- FunctionRefKind functionRefKind,
2599
- ConstraintLocator *locator,
2611
+ DeclReferenceType ConstraintSystem::getTypeOfMemberReference (
2612
+ Type baseTy, ValueDecl *value, DeclContext *useDC, bool isDynamicLookup,
2613
+ FunctionRefKind functionRefKind, ConstraintLocator *locator,
2600
2614
OpenedTypeMap *replacementsPtr) {
2601
2615
// Figure out the instance type used for the base.
2602
2616
Type resolvedBaseTy = getFixedTypeRecursive (baseTy, /* wantRValue=*/ true );
@@ -2619,10 +2633,11 @@ ConstraintSystem::getTypeOfMemberReference(
2619
2633
// metatype and `bar` is static member declared in a protocol or its
2620
2634
// extension.
2621
2635
bool isStaticMemberRefOnProtocol = false ;
2622
- if (resolvedBaseTy->is <MetatypeType>() && baseObjTy->isExistentialType () &&
2623
- value->isStatic ()) {
2624
- isStaticMemberRefOnProtocol =
2625
- locator->isLastElement <LocatorPathElt::UnresolvedMember>();
2636
+ if (baseObjTy->isExistentialType () && value->isStatic () &&
2637
+ locator->isLastElement <LocatorPathElt::UnresolvedMember>()) {
2638
+ assert (resolvedBaseTy->is <MetatypeType>() &&
2639
+ " Assumed base of unresolved member access must be a metatype" );
2640
+ isStaticMemberRefOnProtocol = true ;
2626
2641
}
2627
2642
2628
2643
if (auto *typeDecl = dyn_cast<TypeDecl>(value)) {
@@ -2791,7 +2806,7 @@ ConstraintSystem::getTypeOfMemberReference(
2791
2806
// if it didn't conform.
2792
2807
addConstraint (ConstraintKind::Bind, baseOpenedTy, selfObjTy,
2793
2808
getConstraintLocator (locator));
2794
- } else if (!isDynamicResult ) {
2809
+ } else if (!isDynamicLookup ) {
2795
2810
addSelfConstraint (*this , baseOpenedTy, selfObjTy, locator);
2796
2811
}
2797
2812
@@ -2857,14 +2872,14 @@ ConstraintSystem::getTypeOfMemberReference(
2857
2872
// Compute the type of the reference.
2858
2873
Type type = getMemberReferenceTypeFromOpenedType (
2859
2874
openedType, baseObjTy, value, outerDC, locator, hasAppliedSelf,
2860
- isStaticMemberRefOnProtocol, isDynamicResult , replacements);
2875
+ isDynamicLookup , replacements);
2861
2876
2862
2877
// Do the same thing for the original type, if there can be any difference.
2863
2878
Type origType = type;
2864
2879
if (openedType.getPointer () != origOpenedType.getPointer ()) {
2865
2880
origType = getMemberReferenceTypeFromOpenedType (
2866
2881
origOpenedType, baseObjTy, value, outerDC, locator, hasAppliedSelf,
2867
- isStaticMemberRefOnProtocol, isDynamicResult , replacements);
2882
+ isDynamicLookup , replacements);
2868
2883
}
2869
2884
2870
2885
// If we opened up any type variables, record the replacements.
@@ -4035,6 +4050,35 @@ void ConstraintSystem::resolveOverload(ConstraintLocator *locator,
4035
4050
}
4036
4051
4037
4052
if (auto *decl = choice.getDeclOrNull ()) {
4053
+ // If this is an existential member access and adjustments were made to the
4054
+ // member reference type, require that the constraint system is happy with
4055
+ // the ensuing conversion.
4056
+ if (auto baseTy = choice.getBaseType ()) {
4057
+ baseTy = getFixedTypeRecursive (baseTy, /* wantRValue=*/ true );
4058
+ const auto instanceTy = baseTy->getMetatypeInstanceType ();
4059
+
4060
+ if (isExistentialMemberAccessWithExplicitBaseExpression (
4061
+ instanceTy, decl, locator,
4062
+ /* isDynamicLookup=*/ choice.getKind () ==
4063
+ OverloadChoiceKind::DeclViaDynamic)) {
4064
+
4065
+ // Strip curried 'self' parameters.
4066
+ auto fromTy = openedType->castTo <AnyFunctionType>()->getResult ();
4067
+ auto toTy = refType;
4068
+ if (!doesMemberRefApplyCurriedSelf (baseTy, decl)) {
4069
+ toTy = toTy->castTo <AnyFunctionType>()->getResult ();
4070
+ }
4071
+
4072
+ if (!fromTy->isEqual (toTy)) {
4073
+ ConstraintLocatorBuilder conversionLocator = locator;
4074
+ conversionLocator = conversionLocator.withPathElement (
4075
+ ConstraintLocator::ExistentialMemberAccessConversion);
4076
+ addConstraint (ConstraintKind::Conversion, fromTy, toTy,
4077
+ conversionLocator);
4078
+ }
4079
+ }
4080
+ }
4081
+
4038
4082
// If the declaration is unavailable, note that in the score.
4039
4083
if (isDeclUnavailable (decl, locator))
4040
4084
increaseScore (SK_Unavailable, locator);
@@ -6293,6 +6337,7 @@ void constraints::simplifyLocator(ASTNode &anchor,
6293
6337
case ConstraintLocator::ImplicitlyUnwrappedDisjunctionChoice:
6294
6338
case ConstraintLocator::FallbackType:
6295
6339
case ConstraintLocator::KeyPathSubscriptIndex:
6340
+ case ConstraintLocator::ExistentialMemberAccessConversion:
6296
6341
break ;
6297
6342
}
6298
6343
0 commit comments