Skip to content

Commit 234c9a1

Browse files
slavapestovAzoy
authored andcommitted
Merge pull request #23845 from Azoy/sr-10313
[CSApply] Restructure the implicit AST when applying @dynamicCallable
1 parent b4f072f commit 234c9a1

File tree

2 files changed

+91
-19
lines changed

2 files changed

+91
-19
lines changed

lib/Sema/CSApply.cpp

Lines changed: 45 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1108,6 +1108,10 @@ namespace {
11081108
Expr *finishApply(ApplyExpr *apply, Type openedType,
11091109
ConstraintLocatorBuilder locator);
11101110

1111+
// Resolve @dynamicCallable applications.
1112+
Expr *finishApplyDynamicCallable(const Solution &solution, ApplyExpr *apply,
1113+
ConstraintLocatorBuilder locator);
1114+
11111115
private:
11121116
/// Simplify the given type by substituting all occurrences of
11131117
/// type variables for their fixed types.
@@ -2041,9 +2045,6 @@ namespace {
20412045
}
20422046

20432047
Expr *handleStringLiteralExpr(LiteralExpr *expr) {
2044-
if (cs.getType(expr) && !cs.getType(expr)->hasTypeVariable())
2045-
return expr;
2046-
20472048
auto stringLiteral = dyn_cast<StringLiteralExpr>(expr);
20482049
auto magicLiteral = dyn_cast<MagicIdentifierLiteralExpr>(expr);
20492050
assert(bool(stringLiteral) != bool(magicLiteral) &&
@@ -7004,10 +7005,10 @@ Expr *ExprRewriter::convertLiteralInPlace(Expr *literal,
70047005
}
70057006

70067007
// Resolve @dynamicCallable applications.
7007-
static Expr *finishApplyDynamicCallable(ConstraintSystem &cs,
7008-
const Solution &solution,
7009-
ApplyExpr *apply,
7010-
ConstraintLocatorBuilder locator) {
7008+
Expr *
7009+
ExprRewriter::finishApplyDynamicCallable(const Solution &solution,
7010+
ApplyExpr *apply,
7011+
ConstraintLocatorBuilder locator) {
70117012
auto &ctx = cs.getASTContext();
70127013
auto *fn = apply->getFn();
70137014

@@ -7019,12 +7020,14 @@ static Expr *finishApplyDynamicCallable(ConstraintSystem &cs,
70197020
auto loc = locator.withPathElement(ConstraintLocator::ApplyFunction);
70207021
auto selected = solution.getOverloadChoice(cs.getConstraintLocator(loc));
70217022
auto *method = dyn_cast<FuncDecl>(selected.choice.getDecl());
7022-
auto methodType = selected.openedType->castTo<AnyFunctionType>();
7023+
auto methodType = simplifyType(selected.openedType)->castTo<AnyFunctionType>();
70237024
assert(method->getName() == ctx.Id_dynamicallyCall &&
70247025
"Expected 'dynamicallyCall' method");
7025-
assert(methodType->getParams().size() == 1 &&
7026+
auto params = methodType->getParams();
7027+
assert(params.size() == 1 &&
70267028
"Expected 'dynamicallyCall' method with one parameter");
7027-
auto argumentLabel = methodType->getParams()[0].getLabel();
7029+
auto argumentType = params[0].getParameterType();
7030+
auto argumentLabel = params[0].getLabel();
70287031
assert((argumentLabel == ctx.Id_withArguments ||
70297032
argumentLabel == ctx.Id_withKeywordArguments) &&
70307033
"Expected 'dynamicallyCall' method argument label 'withArguments' or "
@@ -7034,39 +7037,62 @@ static Expr *finishApplyDynamicCallable(ConstraintSystem &cs,
70347037
// `withKeywordArguments` method.
70357038
bool useKwargsMethod = argumentLabel == ctx.Id_withKeywordArguments;
70367039

7037-
// Construct expression referencing the `dynamicallyCall` method.
7038-
Expr *member =
7039-
new (ctx) MemberRefExpr(fn, fn->getEndLoc(), ConcreteDeclRef(method),
7040-
DeclNameLoc(method->getNameLoc()),
7041-
/*Implicit*/ true);
7040+
// Construct expression referencing the `dynamicallyCall` method.
7041+
bool isDynamic =
7042+
selected.choice.getKind() == OverloadChoiceKind::DeclViaDynamic;
7043+
auto member = buildMemberRef(fn, selected.openedFullType,
7044+
SourceLoc(), selected.choice,
7045+
DeclNameLoc(method->getNameLoc()),
7046+
selected.openedType, loc, loc, /*implicit*/ true,
7047+
selected.choice.getFunctionRefKind(),
7048+
AccessSemantics::Ordinary, isDynamic);
70427049

70437050
// Construct argument to the method (either an array or dictionary
70447051
// expression).
70457052
Expr *argument = nullptr;
70467053
if (!useKwargsMethod) {
70477054
argument = ArrayExpr::create(ctx, SourceLoc(), arg->getElements(),
70487055
{}, SourceLoc());
7056+
cs.setType(argument, argumentType);
7057+
finishArrayExpr(cast<ArrayExpr>(argument));
70497058
} else {
7059+
auto dictLitProto =
7060+
ctx.getProtocol(KnownProtocolKind::ExpressibleByDictionaryLiteral);
7061+
auto conformance =
7062+
cs.TC.conformsToProtocol(argumentType, dictLitProto, cs.DC,
7063+
ConformanceCheckFlags::InExpression);
7064+
auto keyType = conformance->getTypeWitnessByName(argumentType, ctx.Id_Key);
7065+
auto valueType = conformance->getTypeWitnessByName(argumentType,
7066+
ctx.Id_Value);
70507067
SmallVector<Identifier, 4> names;
70517068
SmallVector<Expr *, 4> dictElements;
70527069
for (unsigned i = 0, n = arg->getNumElements(); i < n; i++) {
70537070
Expr *labelExpr =
70547071
new (ctx) StringLiteralExpr(arg->getElementName(i).get(),
70557072
arg->getElementNameLoc(i),
70567073
/*Implicit*/ true);
7074+
cs.setType(labelExpr, keyType);
7075+
handleStringLiteralExpr(cast<LiteralExpr>(labelExpr));
7076+
70577077
Expr *pair =
70587078
TupleExpr::createImplicit(ctx, { labelExpr, arg->getElement(i) }, {});
7079+
auto eltTypes = { TupleTypeElt(keyType), TupleTypeElt(valueType) };
7080+
cs.setType(pair, TupleType::get(eltTypes, ctx));
70597081
dictElements.push_back(pair);
70607082
}
70617083
argument = DictionaryExpr::create(ctx, SourceLoc(), dictElements, {},
70627084
SourceLoc());
7085+
cs.setType(argument, argumentType);
7086+
finishDictionaryExpr(cast<DictionaryExpr>(argument));
70637087
}
70647088
argument->setImplicit();
70657089

70667090
// Construct call to the `dynamicallyCall` method.
7067-
Expr *result = CallExpr::createImplicit(ctx, member, argument,
7068-
{ argumentLabel });
7069-
cs.TC.typeCheckExpression(result, cs.DC);
7091+
auto result = CallExpr::createImplicit(ctx, member, argument,
7092+
{ argumentLabel });
7093+
cs.setType(result->getArg(), AnyFunctionType::composeInput(ctx, params,
7094+
false));
7095+
cs.setType(result, methodType->getResult());
70707096
cs.cacheExprTypes(result);
70717097
return result;
70727098
}
@@ -7367,7 +7393,7 @@ Expr *ExprRewriter::finishApply(ApplyExpr *apply, Type openedType,
73677393

73687394
// Handle @dynamicCallable applications.
73697395
// At this point, all other ApplyExpr cases have been handled.
7370-
return finishApplyDynamicCallable(cs, solution, apply, locator);
7396+
return finishApplyDynamicCallable(solution, apply, locator);
73717397
}
73727398

73737399

test/attr/attr_dynamic_callable.swift

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -421,3 +421,49 @@ func testGenericType5<T>(a: CallableGeneric5<T>) -> Double {
421421
func testArchetypeType5<T, C : CallableGeneric5<T>>(a: C) -> Double {
422422
return a(1, 2, 3) + a(x1: 1, 2, x3: 3)
423423
}
424+
425+
// SR-9239 Default argument in initializer
426+
427+
@dynamicCallable
428+
struct A {
429+
init(_ x: Int = 0) {}
430+
func dynamicallyCall(withArguments args: [Int]) {}
431+
}
432+
433+
func test9239() {
434+
_ = A()() // ok
435+
}
436+
437+
// SR-10313
438+
//
439+
// Modified version of the code snippet in the SR to not crash.
440+
441+
struct MissingKeyError: Error {}
442+
443+
@dynamicCallable
444+
class DictionaryBox {
445+
var dictionary: [String: Any] = [:]
446+
447+
func dynamicallyCall<T>(withArguments args: [String]) throws -> T {
448+
guard let value = dictionary[args[0]] as? T else {
449+
throw MissingKeyError()
450+
}
451+
return value
452+
}
453+
}
454+
455+
func test10313() {
456+
let box = DictionaryBox()
457+
box.dictionary["bool"] = false
458+
let _: Bool = try! box("bool") // ok
459+
}
460+
461+
// SR-10753
462+
463+
@dynamicCallable
464+
struct B {
465+
public func dynamicallyCall(withArguments arguments: [String]) {}
466+
}
467+
468+
B()("hello") // ok
469+
B()("\(1)") // ok

0 commit comments

Comments
 (0)