Skip to content

Commit 9bf9de8

Browse files
authored
Merge pull request swiftlang#39188 from amritpan/projected-value-labels
[CSSimplify] Fix a bug where the omitted projected value label was missing as an acceptable parameter label for property wrappers
2 parents 4871212 + e57ff02 commit 9bf9de8

File tree

3 files changed

+34
-17
lines changed

3 files changed

+34
-17
lines changed

include/swift/AST/Types.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2840,6 +2840,23 @@ class AnyFunctionType : public TypeBase {
28402840

28412841
bool hasInternalLabel() const { return !InternalLabel.empty(); }
28422842
Identifier getInternalLabel() const { return InternalLabel; }
2843+
2844+
/// Return true if argument name is valid and matches \c paramName.
2845+
///
2846+
/// The three tests to check if argument name is valid are:
2847+
/// 1. allow argument if it matches \c paramName,
2848+
/// 2. allow argument if $_ for omitted projected value label,
2849+
/// 3. allow argument if it matches \c paramName without its \c $ prefix.
2850+
bool matchParameterLabel(Identifier const &paramName) const {
2851+
auto argLabel = getLabel();
2852+
if (argLabel == paramName)
2853+
return true;
2854+
if ((argLabel.str() == "$_") && paramName.empty())
2855+
return true;
2856+
if (argLabel.hasDollarPrefix() && argLabel.str().drop_front() == paramName.str())
2857+
return true;
2858+
return false;
2859+
}
28432860

28442861
ParameterTypeFlags getParameterFlags() const { return Flags; }
28452862

lib/Sema/CSSimplify.cpp

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -282,22 +282,19 @@ static bool matchCallArgumentsImpl(
282282
// requiring further checking at the end.
283283
bool potentiallyOutOfOrder = false;
284284

285-
// Local function that claims the argument at \c argNumber, returning the
285+
// Local function that claims the argument at \c argIdx, returning the
286286
// index of the claimed argument. This is primarily a helper for
287287
// \c claimNextNamed.
288-
auto claim = [&](Identifier expectedName, unsigned argNumber,
288+
auto claim = [&](Identifier expectedName, unsigned argIdx,
289289
bool ignoreNameClash = false) -> unsigned {
290290
// Make sure we can claim this argument.
291-
assert(argNumber != numArgs && "Must have a valid index to claim");
292-
assert(!claimedArgs[argNumber] && "Argument already claimed");
291+
assert(argIdx != numArgs && "Must have a valid index to claim");
292+
assert(!claimedArgs[argIdx] && "Argument already claimed");
293293

294-
auto argLabel = args[argNumber].getLabel();
295294
if (!actualArgNames.empty()) {
296295
// We're recording argument names; record this one.
297-
actualArgNames[argNumber] = expectedName;
298-
} else if (argLabel != expectedName && !ignoreNameClash &&
299-
!(argLabel.str().startswith("$") &&
300-
argLabel.str().drop_front() == expectedName.str())) {
296+
actualArgNames[argIdx] = expectedName;
297+
} else if (!ignoreNameClash && !args[argIdx].matchParameterLabel(expectedName)) {
301298
// We have an argument name mismatch. Start recording argument names.
302299
actualArgNames.resize(numArgs);
303300

@@ -313,12 +310,12 @@ static bool matchCallArgumentsImpl(
313310
}
314311

315312
// Record this argument name.
316-
actualArgNames[argNumber] = expectedName;
313+
actualArgNames[argIdx] = expectedName;
317314
}
318315

319-
claimedArgs[argNumber] = true;
316+
claimedArgs[argIdx] = true;
320317
++numClaimedArgs;
321-
return argNumber;
318+
return argIdx;
322319
};
323320

324321
// Local function that skips over any claimed arguments.
@@ -343,11 +340,8 @@ static bool matchCallArgumentsImpl(
343340
// Go hunting for an unclaimed argument whose name does match.
344341
Optional<unsigned> claimedWithSameName;
345342
for (unsigned i = nextArgIdx; i != numArgs; ++i) {
346-
auto argLabel = args[i].getLabel();
347343

348-
if (argLabel != paramLabel &&
349-
!(argLabel.str().startswith("$") &&
350-
argLabel.str().drop_front() == paramLabel.str())) {
344+
if (!args[i].matchParameterLabel(paramLabel)) {
351345
// If this is an attempt to claim additional unlabeled arguments
352346
// for variadic parameter, we have to stop at first labeled argument.
353347
if (forVariadic)
@@ -379,7 +373,7 @@ static bool matchCallArgumentsImpl(
379373
// func foo(_ a: Int, _ b: Int = 0, c: Int = 0, _ d: Int) {}
380374
// foo(1, c: 2, 3) // -> `3` will be claimed as '_ b:'.
381375
// ```
382-
if (argLabel.empty())
376+
if (args[i].getLabel().empty())
383377
continue;
384378

385379
potentiallyOutOfOrder = true;

test/Sema/property_wrapper_parameter.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,12 @@ func testClosures() {
8888
}
8989
}
9090

91+
func projectionPlaceholder<T>(@Wrapper _ value: T) {}
92+
93+
func testOmittedProjectionLabel(value: Int) {
94+
projectionPlaceholder($_: Projection(value: value))
95+
}
96+
9197
@propertyWrapper
9298
struct ProjectionWrapper<Value> {
9399
var wrappedValue: Value

0 commit comments

Comments
 (0)