Skip to content

Commit 48dc186

Browse files
committed
[CS] Correctly handle compound-applied functions with property wrappers
Avoid wrapping parameters in the function reference for compound applies, and make sure we consult the parameter label in the compound name if it's present to determine whether to match using the projected value or not. This matches the existing logic in `unwrapPropertyWrapperParameterTypes`.
1 parent c4efa0d commit 48dc186

File tree

4 files changed

+53
-13
lines changed

4 files changed

+53
-13
lines changed

lib/Sema/CSApply.cpp

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -764,10 +764,7 @@ namespace {
764764

765765
if (auto *fnDecl = dyn_cast<AbstractFunctionDecl>(decl)) {
766766
if (AnyFunctionRef(fnDecl).hasExternalPropertyWrapperParameters() &&
767-
// FIXME(FunctionRefInfo): This should just be `isUnapplied()`, see
768-
// the FIXME in `unwrapPropertyWrapperParameterTypes`.
769-
(declRefExpr->getFunctionRefInfo().isCompoundName() ||
770-
declRefExpr->getFunctionRefInfo().isUnappliedBaseName())) {
767+
declRefExpr->getFunctionRefInfo().isUnapplied()) {
771768
// We don't need to do any further adjustment once we've built the
772769
// curry thunk.
773770
return buildSingleCurryThunk(result, fnDecl,

lib/Sema/CSSimplify.cpp

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1725,6 +1725,17 @@ static ConstraintSystem::TypeMatchResult matchCallArguments(
17251725
continue;
17261726
}
17271727

1728+
// See if we have a parameter label specified in the function's DeclNameLoc.
1729+
Identifier compoundParamLabel;
1730+
if (auto *E = getAsExpr(calleeLocator->getAnchor())) {
1731+
auto nameLoc = E->getNameLoc();
1732+
if (auto labelLoc = nameLoc.getArgumentLabelLoc(paramIdx)) {
1733+
auto &ctx = cs.getASTContext();
1734+
auto labelTok = Lexer::getTokenAtLocation(ctx.SourceMgr, labelLoc);
1735+
compoundParamLabel = ctx.getIdentifier(labelTok.getText());
1736+
}
1737+
}
1738+
17281739
// Compare each of the bound arguments for this parameter.
17291740
for (auto argIdx : parameterBindings[paramIdx]) {
17301741
auto loc = locator.withPathElement(LocatorPathElt::ApplyArgToParam(
@@ -1813,14 +1824,17 @@ static ConstraintSystem::TypeMatchResult matchCallArguments(
18131824
openedExistentials.push_back({openedTypeVar, opened});
18141825
}
18151826

1816-
auto argLabel = argument.getLabel();
1827+
// If we have a compound function reference (e.g `fn($x:)`), respect
1828+
// the parameter label given. Otherwise look at the argument label.
1829+
auto wrapperArgLabel = compoundParamLabel.empty() ? argument.getLabel()
1830+
: compoundParamLabel;
18171831
if (paramInfo.hasExternalPropertyWrapper(paramIdx) ||
1818-
argLabel.hasDollarPrefix()) {
1832+
wrapperArgLabel.hasDollarPrefix()) {
18191833
auto *param = getParameterAt(callee, paramIdx);
18201834
assert(param);
18211835
if (cs.applyPropertyWrapperToParameter(paramTy, argTy,
18221836
const_cast<ParamDecl *>(param),
1823-
argLabel, subKind, loc)
1837+
wrapperArgLabel, subKind, loc)
18241838
.isFailure()) {
18251839
return cs.getTypeMatchFailure(loc);
18261840
}

lib/Sema/TypeOfReference.cpp

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -686,13 +686,8 @@ unwrapPropertyWrapperParameterTypes(ConstraintSystem &cs, AbstractFunctionDecl *
686686
FunctionRefInfo functionRefInfo, FunctionType *functionType,
687687
ConstraintLocatorBuilder locator) {
688688
// Only apply property wrappers to unapplied references to functions.
689-
// FIXME(FunctionRefInfo): This should just be `isUnapplied()`, which would
690-
// fix https://github.com/swiftlang/swift/issues/77823, but we also need to
691-
// correctly handle the wrapping in matchCallArguments.
692-
if (!(functionRefInfo.isCompoundName() ||
693-
functionRefInfo.isUnappliedBaseName())) {
689+
if (!functionRefInfo.isUnapplied())
694690
return functionType;
695-
}
696691

697692
// This transform is not applicable to pattern matching context.
698693
//

test/Sema/property_wrapper_parameter.swift

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,40 @@ struct ProjectionWrapper<Value> {
159159
}
160160
}
161161

162+
// https://github.com/swiftlang/swift/issues/77823
163+
// Make sure we correctly handle compound applied functions.
164+
func testCompoundApplication() {
165+
func foo(@ProjectionWrapper x: Int) {}
166+
struct HasProjectionWrapperMember {
167+
static func foo(@ProjectionWrapper x: Int) {}
168+
}
169+
170+
foo(x:)(0)
171+
foo($x:)(ProjectionWrapper(wrappedValue: 0))
172+
173+
(foo($x:).self)(ProjectionWrapper(wrappedValue: 0))
174+
HasProjectionWrapperMember.foo($x:)(ProjectionWrapper(wrappedValue: 0))
175+
176+
foo(x:)(ProjectionWrapper(wrappedValue: 0)) // expected-error {{cannot convert value of type 'ProjectionWrapper<Int>' to expected argument type 'Int'}}
177+
foo(x:)(ProjectionWrapper(wrappedValue: "")) // expected-error {{cannot convert value of type 'ProjectionWrapper<String>' to expected argument type 'Int'}}
178+
foo(x:)("") // expected-error {{cannot convert value of type 'String' to expected argument type 'Int'}}
179+
180+
foo($x:)(ProjectionWrapper(wrappedValue: "")) // expected-error {{cannot convert value of type 'String' to expected argument type 'Int'}}
181+
foo($x:)(0) // expected-error {{cannot convert value of type 'Int' to expected argument type 'ProjectionWrapper<Int>'}}
182+
foo($x:)("") // expected-error {{cannot convert value of type 'String' to expected argument type 'ProjectionWrapper<Int>'}}
183+
184+
func bar(x: Int) {} // expected-note 2{{parameter 'x' does not have an attached property wrapper}}
185+
bar($x:)(0) // expected-error {{cannot use property wrapper projection argument}}
186+
_ = bar($x:) // expected-error {{cannot use property wrapper projection argument}}
187+
188+
func baz(@ProjectionWrapper x: Int, @ProjectionWrapper y: Int) {}
189+
baz($x:y:)(ProjectionWrapper(wrappedValue: 0), 0)
190+
baz(x:$y:)(0, ProjectionWrapper(wrappedValue: 0))
191+
192+
let _: (ProjectionWrapper<Int>, Int) -> Void = baz($x:y:)
193+
let _: (Int, ProjectionWrapper<Int>) -> Void = baz(x:$y:)
194+
}
195+
162196
func testImplicitPropertyWrapper() {
163197
typealias PropertyWrapperTuple = (ProjectionWrapper<Int>, Int, ProjectionWrapper<Int>)
164198

0 commit comments

Comments
 (0)