@@ -7046,6 +7046,74 @@ Expr *ExprRewriter::convertLiteralInPlace(Expr *literal,
7046
7046
return literal;
7047
7047
}
7048
7048
7049
+ // Resolve @dynamicCallable applications.
7050
+ static Expr *finishApplyDynamicCallable (ConstraintSystem &cs,
7051
+ const Solution &solution,
7052
+ ApplyExpr *apply,
7053
+ ConstraintLocatorBuilder locator) {
7054
+ auto &ctx = cs.getASTContext ();
7055
+ auto *fn = apply->getFn ();
7056
+
7057
+ TupleExpr *arg = dyn_cast<TupleExpr>(apply->getArg ());
7058
+ if (auto parenExpr = dyn_cast<ParenExpr>(apply->getArg ()))
7059
+ arg = TupleExpr::createImplicit (ctx, parenExpr->getSubExpr (), {});
7060
+
7061
+ // Get resolved `dynamicallyCall` method and verify it.
7062
+ auto loc = locator.withPathElement (ConstraintLocator::ApplyFunction);
7063
+ auto selected = solution.getOverloadChoice (cs.getConstraintLocator (loc));
7064
+ auto *method = dyn_cast<FuncDecl>(selected.choice .getDecl ());
7065
+ auto methodType = selected.openedType ->castTo <AnyFunctionType>();
7066
+ assert (method->getName () == ctx.Id_dynamicallyCall &&
7067
+ " Expected 'dynamicallyCall' method" );
7068
+ assert (methodType->getParams ().size () == 1 &&
7069
+ " Expected 'dynamicallyCall' method with one parameter" );
7070
+ auto argumentLabel = methodType->getParams ()[0 ].getLabel ();
7071
+ assert ((argumentLabel == ctx.Id_withArguments ||
7072
+ argumentLabel == ctx.Id_withKeywordArguments ) &&
7073
+ " Expected 'dynamicallyCall' method argument label 'withArguments' or "
7074
+ " 'withKeywordArguments'" );
7075
+
7076
+ // Determine which method was resolved: a `withArguments` method or a
7077
+ // `withKeywordArguments` method.
7078
+ bool useKwargsMethod = argumentLabel == ctx.Id_withKeywordArguments ;
7079
+
7080
+ // Construct expression referencing the `dynamicallyCall` method.
7081
+ Expr *member =
7082
+ new (ctx) MemberRefExpr (fn, fn->getEndLoc (), ConcreteDeclRef (method),
7083
+ DeclNameLoc (method->getNameLoc ()),
7084
+ /* Implicit*/ true );
7085
+
7086
+ // Construct argument to the method (either an array or dictionary
7087
+ // expression).
7088
+ Expr *argument = nullptr ;
7089
+ if (!useKwargsMethod) {
7090
+ argument = ArrayExpr::create (ctx, SourceLoc (), arg->getElements (),
7091
+ {}, SourceLoc ());
7092
+ } else {
7093
+ SmallVector<Identifier, 4 > names;
7094
+ SmallVector<Expr *, 4 > dictElements;
7095
+ for (unsigned i = 0 , n = arg->getNumElements (); i < n; i++) {
7096
+ Expr *labelExpr =
7097
+ new (ctx) StringLiteralExpr (arg->getElementName (i).get (),
7098
+ arg->getElementNameLoc (i),
7099
+ /* Implicit*/ true );
7100
+ Expr *pair =
7101
+ TupleExpr::createImplicit (ctx, { labelExpr, arg->getElement (i) }, {});
7102
+ dictElements.push_back (pair);
7103
+ }
7104
+ argument = DictionaryExpr::create (ctx, SourceLoc (), dictElements, {},
7105
+ SourceLoc ());
7106
+ }
7107
+ argument->setImplicit ();
7108
+
7109
+ // Construct call to the `dynamicallyCall` method.
7110
+ Expr *result = CallExpr::createImplicit (ctx, member, argument,
7111
+ { argumentLabel });
7112
+ cs.TC .typeCheckExpression (result, cs.DC );
7113
+ cs.cacheExprTypes (result);
7114
+ return result;
7115
+ }
7116
+
7049
7117
Expr *ExprRewriter::finishApply (ApplyExpr *apply, Type openedType,
7050
7118
ConstraintLocatorBuilder locator) {
7051
7119
TypeChecker &tc = cs.getTypeChecker ();
@@ -7340,67 +7408,73 @@ Expr *ExprRewriter::finishApply(ApplyExpr *apply, Type openedType,
7340
7408
}
7341
7409
7342
7410
// We have a type constructor.
7343
- auto metaTy = cs.getType (fn)->castTo <AnyMetatypeType>();
7344
- auto ty = metaTy->getInstanceType ();
7345
-
7346
- if (!cs.isTypeReference (fn)) {
7347
- bool isExistentialType = false ;
7348
- // If this is an attempt to initialize existential type.
7349
- if (auto metaType = cs.getType (fn)->getAs <MetatypeType>()) {
7350
- auto instanceType = metaType->getInstanceType ();
7351
- isExistentialType = instanceType->isExistentialType ();
7352
- }
7353
-
7354
- if (!isExistentialType) {
7355
- // If the metatype value isn't a type expression,
7356
- // the user should reference '.init' explicitly, for clarity.
7357
- cs.TC
7358
- .diagnose (apply->getArg ()->getStartLoc (),
7359
- diag::missing_init_on_metatype_initialization)
7360
- .fixItInsert (apply->getArg ()->getStartLoc (), " .init" );
7361
- }
7362
- }
7363
-
7364
- // If we're "constructing" a tuple type, it's simply a conversion.
7365
- if (auto tupleTy = ty->getAs <TupleType>()) {
7366
- // FIXME: Need an AST to represent this properly.
7367
- return coerceToType (apply->getArg (), tupleTy, locator);
7368
- }
7411
+ if (auto metaTy = cs.getType (fn)->getAs <AnyMetatypeType>()) {
7412
+ auto ty = metaTy->getInstanceType ();
7413
+
7414
+ if (!cs.isTypeReference (fn)) {
7415
+ bool isExistentialType = false ;
7416
+ // If this is an attempt to initialize existential type.
7417
+ if (auto metaType = cs.getType (fn)->getAs <MetatypeType>()) {
7418
+ auto instanceType = metaType->getInstanceType ();
7419
+ isExistentialType = instanceType->isExistentialType ();
7420
+ }
7421
+
7422
+ if (!isExistentialType) {
7423
+ // If the metatype value isn't a type expression,
7424
+ // the user should reference '.init' explicitly, for clarity.
7425
+ cs.TC
7426
+ .diagnose (apply->getArg ()->getStartLoc (),
7427
+ diag::missing_init_on_metatype_initialization)
7428
+ .fixItInsert (apply->getArg ()->getStartLoc (), " .init" );
7429
+ }
7430
+ }
7431
+
7432
+ // If we're "constructing" a tuple type, it's simply a conversion.
7433
+ if (auto tupleTy = ty->getAs <TupleType>()) {
7434
+ // FIXME: Need an AST to represent this properly.
7435
+ return coerceToType (apply->getArg (), tupleTy, locator);
7436
+ }
7437
+
7438
+ // We're constructing a value of nominal type. Look for the constructor or
7439
+ // enum element to use.
7440
+ auto ctorLocator = cs.getConstraintLocator (
7441
+ locator.withPathElement (ConstraintLocator::ApplyFunction)
7442
+ .withPathElement (ConstraintLocator::ConstructorMember));
7443
+ auto selected = solution.getOverloadChoiceIfAvailable (ctorLocator);
7444
+ if (!selected) {
7445
+ assert (ty->hasError () || ty->hasUnresolvedType ());
7446
+ cs.setType (apply, ty);
7447
+ return apply;
7448
+ }
7449
+
7450
+ assert (ty->getNominalOrBoundGenericNominal () || ty->is <DynamicSelfType>() ||
7451
+ ty->isExistentialType () || ty->is <ArchetypeType>());
7452
+
7453
+ // We have the constructor.
7454
+ auto choice = selected->choice ;
7455
+
7456
+ // Consider the constructor decl reference expr 'implicit', but the
7457
+ // constructor call expr itself has the apply's 'implicitness'.
7458
+ bool isDynamic = choice.getKind () == OverloadChoiceKind::DeclViaDynamic;
7459
+ Expr *declRef = buildMemberRef (fn, selected->openedFullType ,
7460
+ /* dotLoc=*/ SourceLoc (), choice,
7461
+ DeclNameLoc (fn->getEndLoc ()),
7462
+ selected->openedType , locator, ctorLocator,
7463
+ /* Implicit=*/ true ,
7464
+ choice.getFunctionRefKind (),
7465
+ AccessSemantics::Ordinary, isDynamic);
7466
+ if (!declRef)
7467
+ return nullptr ;
7468
+ declRef->setImplicit (apply->isImplicit ());
7469
+ apply->setFn (declRef);
7369
7470
7370
- // We're constructing a value of nominal type. Look for the constructor or
7371
- // enum element to use.
7372
- auto ctorLocator = cs.getConstraintLocator (
7373
- locator.withPathElement (ConstraintLocator::ApplyFunction)
7374
- .withPathElement (ConstraintLocator::ConstructorMember));
7375
- auto selected = solution.getOverloadChoiceIfAvailable (ctorLocator);
7376
- if (!selected) {
7377
- assert (ty->hasError () || ty->hasUnresolvedType ());
7378
- cs.setType (apply, ty);
7379
- return apply;
7471
+ // Tail-recur to actually call the constructor.
7472
+ return finishApply (apply, openedType, locator);
7380
7473
}
7381
7474
7382
- assert (ty->getNominalOrBoundGenericNominal () || ty->is <DynamicSelfType>() ||
7383
- ty->isExistentialType () || ty->is <ArchetypeType>());
7384
-
7385
- // We have the constructor.
7386
- auto choice = selected->choice ;
7387
-
7388
- // Consider the constructor decl reference expr 'implicit', but the
7389
- // constructor call expr itself has the apply's 'implicitness'.
7390
- bool isDynamic = choice.getKind () == OverloadChoiceKind::DeclViaDynamic;
7391
- Expr *declRef = buildMemberRef (fn, selected->openedFullType ,
7392
- /* dotLoc=*/ SourceLoc (), choice,
7393
- DeclNameLoc (fn->getEndLoc ()),
7394
- selected->openedType , locator, ctorLocator,
7395
- /* Implicit=*/ true , choice.getFunctionRefKind (),
7396
- AccessSemantics::Ordinary, isDynamic);
7397
- if (!declRef)
7398
- return nullptr ;
7399
- declRef->setImplicit (apply->isImplicit ());
7400
- apply->setFn (declRef);
7401
-
7402
- // Tail-recur to actually call the constructor.
7403
- return finishApply (apply, openedType, locator);
7475
+ // Handle @dynamicCallable applications.
7476
+ // At this point, all other ApplyExpr cases have been handled.
7477
+ return finishApplyDynamicCallable (cs, solution, apply, locator);
7404
7478
}
7405
7479
7406
7480
0 commit comments