Skip to content

Commit a56d527

Browse files
committed
[CSSimplify] Fix matchCallArguments not to claim un-labeled arguments too eagerly
Avoid claiming un-labeled defaulted parameters by out-of-order un-labeled arguments or parts of variadic argument sequence, because that might be incorrect. The following example is supposed to type-check correctly but without these changes produces `missing argument for parameter #4 in call` error, because `3` will be claimed as '_ b:': ```swift func foo(_ a: Int, _ b: Int = 0, c: Int = 0, _ d: Int) {} foo(1, c: 2, 3) ``` Resolves: rdar://problem/43525641
1 parent 26b972e commit a56d527

File tree

4 files changed

+31
-11
lines changed

4 files changed

+31
-11
lines changed

lib/Sema/CSSimplify.cpp

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,10 @@ matchCallArguments(ArrayRef<AnyFunctionType::Param> args,
161161
// requiring further checking at the end.
162162
bool potentiallyOutOfOrder = false;
163163

164+
auto hasDefault = [&defaultMap, &numParams](unsigned idx) -> bool {
165+
return idx < numParams ? defaultMap.test(idx) : false;
166+
};
167+
164168
// Local function that claims the argument at \c argNumber, returning the
165169
// index of the claimed argument. This is primarily a helper for
166170
// \c claimNextNamed.
@@ -206,7 +210,7 @@ matchCallArguments(ArrayRef<AnyFunctionType::Param> args,
206210
// Local function that retrieves the next unclaimed argument with the given
207211
// name (which may be empty). This routine claims the argument.
208212
auto claimNextNamed
209-
= [&](Identifier name, bool ignoreNameMismatch,
213+
= [&](Identifier paramLabel, bool ignoreNameMismatch,
210214
bool forVariadic = false) -> Optional<unsigned> {
211215
// Skip over any claimed arguments.
212216
skipClaimedArgs();
@@ -218,8 +222,9 @@ matchCallArguments(ArrayRef<AnyFunctionType::Param> args,
218222
// Go hunting for an unclaimed argument whose name does match.
219223
Optional<unsigned> claimedWithSameName;
220224
for (unsigned i = nextArgIdx; i != numArgs; ++i) {
221-
// Skip arguments where the name doesn't match.
222-
if (args[i].getLabel() != name) {
225+
auto argLabel = args[i].getLabel();
226+
227+
if (argLabel != paramLabel) {
223228
// If this is an attempt to claim additional unlabeled arguments
224229
// for variadic parameter, we have to stop at first labeled argument.
225230
if (forVariadic)
@@ -240,11 +245,23 @@ matchCallArguments(ArrayRef<AnyFunctionType::Param> args,
240245

241246
// We found a match. If the match wasn't the next one, we have
242247
// potentially out of order arguments.
243-
if (i != nextArgIdx)
248+
if (i != nextArgIdx) {
249+
// Avoid claiming un-labeled defaulted parameters
250+
// by out-of-order un-labeled arguments or parts
251+
// of variadic argument sequence, because that might
252+
// be incorrect:
253+
// ```swift
254+
// func foo(_ a: Int, _ b: Int = 0, c: Int = 0, _ d: Int) {}
255+
// foo(1, c: 2, 3) // -> `3` will be claimed as '_ b:'.
256+
// ```
257+
if (argLabel.empty() && (hasDefault(i) || !forVariadic))
258+
continue;
259+
244260
potentiallyOutOfOrder = true;
261+
}
245262

246263
// Claim it.
247-
return claim(name, i);
264+
return claim(paramLabel, i);
248265
}
249266

250267
// If we're not supposed to attempt any fixes, we're done.
@@ -268,8 +285,8 @@ matchCallArguments(ArrayRef<AnyFunctionType::Param> args,
268285
// Claim this argument if we are asked to ignore labeling failure,
269286
// only if argument doesn't have a label when parameter expected
270287
// it to, or vice versa.
271-
if (name.empty() || argLabel.empty())
272-
return claim(name, nextArgIdx);
288+
if (paramLabel.empty() || argLabel.empty())
289+
return claim(paramLabel, nextArgIdx);
273290
}
274291

275292
// Redundant keyword arguments.
@@ -478,7 +495,7 @@ matchCallArguments(ArrayRef<AnyFunctionType::Param> args,
478495
continue;
479496

480497
// Parameters with defaults can be unfulfilled.
481-
if (defaultMap.test(paramIdx))
498+
if (hasDefault(paramIdx))
482499
continue;
483500

484501
listener.missingArgument(paramIdx);

test/Constraints/diagnostics.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1207,3 +1207,6 @@ func unresolvedTypeExistential() -> Bool {
12071207
return (Int.self==_{})
12081208
// expected-error@-1 {{ambiguous reference to member '=='}}
12091209
}
1210+
1211+
func rdar43525641(_ a: Int, _ b: Int = 0, c: Int = 0, _ d: Int) {}
1212+
rdar43525641(1, c: 2, 3) // Ok

test/Constraints/diagnostics_swift4.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ func sr_2505(_ a: Any) {} // expected-note {{}}
66
sr_2505() // expected-error {{missing argument for parameter #1 in call}}
77
sr_2505(a: 1) // expected-error {{extraneous argument label 'a:' in call}}
88
sr_2505(1, 2) // expected-error {{extra argument in call}}
9-
sr_2505(a: 1, 2) // expected-error {{extra argument 'a' in call}}
9+
sr_2505(a: 1, 2) // expected-error {{extra argument in call}}
1010

1111
struct C_2505 {
1212
init(_ arg: Any) {

test/Constraints/keyword_arguments.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ variadics4()
204204
variadics4(y: 0, x: 1, 2, 3) // expected-error{{argument 'x' must precede argument 'y'}} {{12-12=x: 1, 2, 3, }} {{16-28=}}
205205
variadics4(z: 1, x: 1) // expected-error{{argument 'x' must precede argument 'z'}} {{12-12=x: 1, }} {{16-22=}}
206206

207-
func variadics5(_ x: Int, y: Int, _ z: Int...) { }
207+
func variadics5(_ x: Int, y: Int, _ z: Int...) { } // expected-note {{declared here}}
208208

209209
// Using variadics (in-order, complete)
210210
variadics5(1, y: 2)
@@ -214,7 +214,7 @@ variadics5(1, y: 2, 1, 2, 3)
214214

215215
// Using various (out-of-order)
216216
variadics5(1, 2, 3, 4, 5, 6, y: 7) // expected-error{{argument 'y' must precede unnamed argument #2}} {{15-15=y: 7, }} {{28-34=}}
217-
variadics5(y: 1, 2, 3, 4, 5, 6, 7) // expected-error{{unnamed argument #2 must precede argument 'y'}} {{12-12=2, }} {{16-19=}}
217+
variadics5(y: 1, 2, 3, 4, 5, 6, 7) // expected-error{{missing argument for parameter #1 in call}}
218218

219219
func variadics6(x: Int..., y: Int = 2, z: Int) { } // expected-note 4 {{'variadics6(x:y:z:)' declared here}}
220220

0 commit comments

Comments
 (0)