Skip to content

Commit d0c727d

Browse files
committed
Restructure implicit AST for @dynamicCallable
add tests dont assume dict type dont assume member ref ast formatting more formatting Update getTypeWitnessByName
1 parent f890cfb commit d0c727d

File tree

2 files changed

+81
-19
lines changed

2 files changed

+81
-19
lines changed

lib/Sema/CSApply.cpp

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

1072+
// Resolve @dynamicCallable applications.
1073+
Expr *finishApplyDynamicCallable(const Solution &solution, ApplyExpr *apply,
1074+
ConstraintLocatorBuilder locator);
1075+
10721076
private:
10731077
/// Simplify the given type by substituting all occurrences of
10741078
/// type variables for their fixed types.
@@ -1975,9 +1979,6 @@ namespace {
19751979
}
19761980

19771981
Expr *handleStringLiteralExpr(LiteralExpr *expr) {
1978-
if (cs.getType(expr) && !cs.getType(expr)->hasTypeVariable())
1979-
return expr;
1980-
19811982
auto stringLiteral = dyn_cast<StringLiteralExpr>(expr);
19821983
auto magicLiteral = dyn_cast<MagicIdentifierLiteralExpr>(expr);
19831984
assert(bool(stringLiteral) != bool(magicLiteral) &&
@@ -6791,10 +6792,10 @@ Expr *ExprRewriter::convertLiteralInPlace(Expr *literal,
67916792
}
67926793

67936794
// Resolve @dynamicCallable applications.
6794-
static Expr *finishApplyDynamicCallable(ConstraintSystem &cs,
6795-
const Solution &solution,
6796-
ApplyExpr *apply,
6797-
ConstraintLocatorBuilder locator) {
6795+
Expr *
6796+
ExprRewriter::finishApplyDynamicCallable(const Solution &solution,
6797+
ApplyExpr *apply,
6798+
ConstraintLocatorBuilder locator) {
67986799
auto &ctx = cs.getASTContext();
67996800
auto *fn = apply->getFn();
68006801

@@ -6806,12 +6807,14 @@ static Expr *finishApplyDynamicCallable(ConstraintSystem &cs,
68066807
auto loc = locator.withPathElement(ConstraintLocator::ApplyFunction);
68076808
auto selected = solution.getOverloadChoice(cs.getConstraintLocator(loc));
68086809
auto *method = dyn_cast<FuncDecl>(selected.choice.getDecl());
6809-
auto methodType = selected.openedType->castTo<AnyFunctionType>();
6810+
auto methodType = simplifyType(selected.openedType)->castTo<AnyFunctionType>();
68106811
assert(method->getName() == ctx.Id_dynamicallyCall &&
68116812
"Expected 'dynamicallyCall' method");
6812-
assert(methodType->getParams().size() == 1 &&
6813+
auto params = methodType->getParams();
6814+
assert(params.size() == 1 &&
68136815
"Expected 'dynamicallyCall' method with one parameter");
6814-
auto argumentLabel = methodType->getParams()[0].getLabel();
6816+
auto argumentType = params[0].getParameterType();
6817+
auto argumentLabel = params[0].getLabel();
68156818
assert((argumentLabel == ctx.Id_withArguments ||
68166819
argumentLabel == ctx.Id_withKeywordArguments) &&
68176820
"Expected 'dynamicallyCall' method argument label 'withArguments' or "
@@ -6821,39 +6824,62 @@ static Expr *finishApplyDynamicCallable(ConstraintSystem &cs,
68216824
// `withKeywordArguments` method.
68226825
bool useKwargsMethod = argumentLabel == ctx.Id_withKeywordArguments;
68236826

6824-
// Construct expression referencing the `dynamicallyCall` method.
6825-
Expr *member =
6826-
new (ctx) MemberRefExpr(fn, fn->getEndLoc(), ConcreteDeclRef(method),
6827-
DeclNameLoc(method->getNameLoc()),
6828-
/*Implicit*/ true);
6827+
// Construct expression referencing the `dynamicallyCall` method.
6828+
bool isDynamic =
6829+
selected.choice.getKind() == OverloadChoiceKind::DeclViaDynamic;
6830+
auto member = buildMemberRef(fn, selected.openedFullType,
6831+
SourceLoc(), selected.choice,
6832+
DeclNameLoc(method->getNameLoc()),
6833+
selected.openedType, loc, loc, /*implicit*/ true,
6834+
selected.choice.getFunctionRefKind(),
6835+
AccessSemantics::Ordinary, isDynamic);
68296836

68306837
// Construct argument to the method (either an array or dictionary
68316838
// expression).
68326839
Expr *argument = nullptr;
68336840
if (!useKwargsMethod) {
68346841
argument = ArrayExpr::create(ctx, SourceLoc(), arg->getElements(),
68356842
{}, SourceLoc());
6843+
cs.setType(argument, argumentType);
6844+
finishArrayExpr(cast<ArrayExpr>(argument));
68366845
} else {
6846+
auto dictLitProto =
6847+
ctx.getProtocol(KnownProtocolKind::ExpressibleByDictionaryLiteral);
6848+
auto conformance =
6849+
cs.TC.conformsToProtocol(argumentType, dictLitProto, cs.DC,
6850+
ConformanceCheckFlags::InExpression);
6851+
auto keyType = conformance->getTypeWitnessByName(argumentType, ctx.Id_Key);
6852+
auto valueType = conformance->getTypeWitnessByName(argumentType,
6853+
ctx.Id_Value);
68376854
SmallVector<Identifier, 4> names;
68386855
SmallVector<Expr *, 4> dictElements;
68396856
for (unsigned i = 0, n = arg->getNumElements(); i < n; i++) {
68406857
Expr *labelExpr =
68416858
new (ctx) StringLiteralExpr(arg->getElementName(i).get(),
68426859
arg->getElementNameLoc(i),
68436860
/*Implicit*/ true);
6861+
cs.setType(labelExpr, keyType);
6862+
handleStringLiteralExpr(cast<LiteralExpr>(labelExpr));
6863+
68446864
Expr *pair =
68456865
TupleExpr::createImplicit(ctx, { labelExpr, arg->getElement(i) }, {});
6866+
auto eltTypes = { TupleTypeElt(keyType), TupleTypeElt(valueType) };
6867+
cs.setType(pair, TupleType::get(eltTypes, ctx));
68466868
dictElements.push_back(pair);
68476869
}
68486870
argument = DictionaryExpr::create(ctx, SourceLoc(), dictElements, {},
68496871
SourceLoc());
6872+
cs.setType(argument, argumentType);
6873+
finishDictionaryExpr(cast<DictionaryExpr>(argument));
68506874
}
68516875
argument->setImplicit();
68526876

68536877
// Construct call to the `dynamicallyCall` method.
6854-
Expr *result = CallExpr::createImplicit(ctx, member, argument,
6855-
{ argumentLabel });
6856-
cs.TC.typeCheckExpression(result, cs.DC);
6878+
auto result = CallExpr::createImplicit(ctx, member, argument,
6879+
{ argumentLabel });
6880+
cs.setType(result->getArg(), AnyFunctionType::composeInput(ctx, params,
6881+
false));
6882+
cs.setType(result, methodType->getResult());
68576883
cs.cacheExprTypes(result);
68586884
return result;
68596885
}
@@ -7151,7 +7177,7 @@ Expr *ExprRewriter::finishApply(ApplyExpr *apply, Type openedType,
71517177

71527178
// Handle @dynamicCallable applications.
71537179
// At this point, all other ApplyExpr cases have been handled.
7154-
return finishApplyDynamicCallable(cs, solution, apply, locator);
7180+
return finishApplyDynamicCallable(solution, apply, locator);
71557181
}
71567182

71577183

test/attr/attr_dynamic_callable.swift

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -421,3 +421,39 @@ 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+
}

0 commit comments

Comments
 (0)