@@ -1883,7 +1883,52 @@ void ConstraintSystem::resolveOverload(ConstraintLocator *locator,
1883
1883
}
1884
1884
1885
1885
if (kind == OverloadChoiceKind::KeyPathDynamicMemberLookup) {
1886
- assert (false && " not yet implemented" );
1886
+ auto *fnType = refType->castTo <FunctionType>();
1887
+ assert (fnType->getParams ().size () == 1 &&
1888
+ " subscript always has one argument" );
1889
+ // Parameter type is KeyPath<T, U> where `T` is a root type
1890
+ // and U is a leaf type (aka member type).
1891
+ auto keyPathTy =
1892
+ fnType->getParams ()[0 ].getPlainType ()->castTo <BoundGenericType>();
1893
+
1894
+ refType = fnType->getResult ();
1895
+
1896
+ auto *keyPathExpr = buildImplicitDynamicKeyPathArgument (
1897
+ locator->getAnchor (), keyPathTy, locator);
1898
+
1899
+ // If argument couldn't be built, let's fail this choice.
1900
+ if (!keyPathExpr) {
1901
+ failedConstraint = Constraint::create (*this , ConstraintKind::Bind,
1902
+ boundType, refType, locator);
1903
+ return ;
1904
+ }
1905
+
1906
+ auto *keyPathLocator = getConstraintLocator (keyPathExpr);
1907
+ auto *componentLoc = getConstraintLocator (
1908
+ keyPathExpr, LocatorPathElt::getKeyPathComponent (0 ));
1909
+
1910
+ auto rootTy = keyPathTy->getGenericArgs ()[0 ];
1911
+ // Member would either point to mutable or immutable property, we
1912
+ // don't which at the moment, so let's allow its type to be l-value.
1913
+ auto memberTy = createTypeVariable (componentLoc, TVO_CanBindToLValue);
1914
+ // Attempt to lookup a member with a give name in the root type and
1915
+ // assign result to the leaf type of the keypath.
1916
+ addValueMemberConstraint (LValueType::get (rootTy), choice.getName (),
1917
+ memberTy, useDC, FunctionRefKind::Unapplied,
1918
+ /* outerAlternatives=*/ {}, componentLoc);
1919
+
1920
+ auto rvalueMemberTy = createTypeVariable (keyPathLocator);
1921
+ // Since member type is going to be bound to "leaf" generic parameter
1922
+ // of the keypath, it has to be an r-value always, so let's add a new
1923
+ // constraint to preserve that.
1924
+ addConstraint (ConstraintKind::Equal, memberTy, rvalueMemberTy,
1925
+ keyPathLocator);
1926
+
1927
+ // For a new keypath constraint which is going to check whether given
1928
+ // overload is correct.
1929
+ addUnsolvedConstraint (Constraint::create (*this , ConstraintKind::KeyPath,
1930
+ keyPathTy, rootTy,
1931
+ rvalueMemberTy, keyPathLocator));
1887
1932
}
1888
1933
break ;
1889
1934
}
@@ -2556,3 +2601,35 @@ void ConstraintSystem::generateConstraints(
2556
2601
recordChoice (constraints, index, choices[index]);
2557
2602
}
2558
2603
}
2604
+
2605
+ KeyPathExpr *ConstraintSystem::buildImplicitDynamicKeyPathArgument (
2606
+ Expr *member, BoundGenericType *keyPathTy, ConstraintLocator *locator) {
2607
+ // Only properties are support at the moment.
2608
+ auto *UDE = dyn_cast<UnresolvedDotExpr>(member);
2609
+ if (!UDE)
2610
+ return nullptr ;
2611
+
2612
+ auto &ctx = getASTContext ();
2613
+ auto dotLoc = UDE->getDotLoc ();
2614
+
2615
+ auto *property = new (ctx)
2616
+ UnresolvedDotExpr (new (ctx) KeyPathDotExpr (dotLoc), dotLoc,
2617
+ UDE->getName (), UDE->getNameLoc (), /* isImplicit=*/ true );
2618
+
2619
+ // Now, let's create a KeyPath expression itself.
2620
+ auto *keyPath = new (ctx) KeyPathExpr (/* backslashLoc=*/ dotLoc,
2621
+ /* parsedRoot=*/ nullptr ,
2622
+ /* parsedPath=*/ property,
2623
+ /* isImplicit=*/ true );
2624
+
2625
+ // Let's form a single unrsolved property component this keypath is
2626
+ // going to refer to.
2627
+ keyPath->resolveComponents (
2628
+ ctx, {KeyPathExpr::Component::forUnresolvedProperty (
2629
+ property->getName (), property->getStartLoc ())});
2630
+ setType (keyPath, keyPathTy);
2631
+
2632
+ // Register newly generated argument in the constraint system.
2633
+ DynamicMemberArguments.push_back ({locator, keyPath});
2634
+ return keyPath;
2635
+ }
0 commit comments