diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index b8b54d33893c5..f6ddd6937c624 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -289,6 +289,7 @@ matchCallArguments(SmallVectorImpl &args, // Local function that retrieves the next unclaimed argument with the given // name (which may be empty). This routine claims the argument. auto claimNextNamed = [&](unsigned &nextArgIdx, Identifier paramLabel, + Optional paramIdx, bool ignoreNameMismatch, bool forVariadic = false) -> Optional { // Skip over any claimed arguments. @@ -298,6 +299,47 @@ matchCallArguments(SmallVectorImpl &args, if (numClaimedArgs == numArgs) return None; + /// When we determine which argument is bound to unlabeled parameter, + /// consider still unbounded parameter which is prior to current parameter. + /// In order not to intersect binding position that remaining parameter will + /// bind later, skip a unlabeled argument as much as it can. + /// + /// For example: + /// @code + /// func f(aa: Int, _ bb: Int) {} + /// f(0, 1) + /// @endcode + /// Choice argument[1] for parameter[1] so that parameter[0] will be bounded + /// to argument[0] later. + /// + /// Because variadics parameter can be bounded with more than one arguments, + /// they don't this. + if (paramLabel.empty() && paramIdx && !forVariadic && + !params[*paramIdx].isVariadic()) { + unsigned unboundedParamCount = 0; + for (unsigned pi = 0; pi < *paramIdx; pi++) { + if (parameterBindings[pi].empty()) { + if (params[pi].isVariadic() || paramInfo.hasDefaultArgument(pi)) + continue; + + unboundedParamCount++; + } + } + + unsigned keepedArgCount = 0; + for (unsigned ai = nextArgIdx; ai < numArgs; ai++) { + if (claimedArgs[ai]) + continue; + + nextArgIdx = std::max(nextArgIdx, ai); + + if (keepedArgCount >= unboundedParamCount) { + break; + } + keepedArgCount++; + } + } + // Go hunting for an unclaimed argument whose name does match. Optional claimedWithSameName; for (unsigned i = nextArgIdx; i != numArgs; ++i) { @@ -390,8 +432,8 @@ matchCallArguments(SmallVectorImpl &args, // Handle variadic parameters. if (param.isVariadic()) { // Claim the next argument with the name of this parameter. - auto claimed = - claimNextNamed(nextArgIdx, param.getLabel(), ignoreNameMismatch); + auto claimed = claimNextNamed(nextArgIdx, param.getLabel(), paramIdx, + ignoreNameMismatch); // If there was no such argument, leave the parameter unfulfilled. if (!claimed) { @@ -412,8 +454,10 @@ matchCallArguments(SmallVectorImpl &args, { nextArgIdx = *claimed; // Claim any additional unnamed arguments. - while ( - (claimed = claimNextNamed(nextArgIdx, Identifier(), false, true))) { + while ((claimed = claimNextNamed( + nextArgIdx, /*paramLabel=*/Identifier(), /*paramIdx=*/None, + /*ignoreNameMismatch=*/false, + /*forVariadic=*/true))) { parameterBindings[paramIdx].push_back(*claimed); } } @@ -423,8 +467,8 @@ matchCallArguments(SmallVectorImpl &args, } // Try to claim an argument for this parameter. - if (auto claimed = - claimNextNamed(nextArgIdx, param.getLabel(), ignoreNameMismatch)) { + if (auto claimed = claimNextNamed(nextArgIdx, param.getLabel(), paramIdx, + ignoreNameMismatch)) { parameterBindings[paramIdx].push_back(*claimed); return; } diff --git a/test/Constraints/argument_matching.swift b/test/Constraints/argument_matching.swift index febabc64f094d..609355a2454ac 100644 --- a/test/Constraints/argument_matching.swift +++ b/test/Constraints/argument_matching.swift @@ -705,12 +705,10 @@ func testUnlabeledParameterBindingPosition() { // expected-error@-1:6 {{missing argument label 'aa:' in call}} f(0, xx: 1) - // expected-error@-1:7 {{missing argument for parameter 'aa' in call}} - // expected-error@-2:14 {{extra argument 'xx' in call}} + // expected-error@-1:6 {{incorrect argument labels in call (have '_:xx:', expected 'aa:_:')}} f(xx: 0, 1) - // expected-error@-1:7 {{missing argument for parameter 'aa' in call}} - // expected-error@-2:14 {{extra argument in call}} + // expected-error@-1:6 {{incorrect argument label in call (have 'xx:_:', expected 'aa:_:')}} f(0, 1, 9) // expected-error@-1:13 {{extra argument in call}} @@ -719,7 +717,7 @@ func testUnlabeledParameterBindingPosition() { // expected-error@-1:17 {{extra argument 'xx' in call}} f(xx: 91, 1, 92) - // expected-error@-1 {{extra arguments at positions #2, #3 in call}} + // expected-error@-1 {{extra arguments at positions #1, #3 in call}} // expected-error@-2 {{missing argument for parameter 'aa' in call}} } @@ -727,7 +725,7 @@ func testUnlabeledParameterBindingPosition() { func f(_ aa: Int, bb: Int, _ cc: Int) { } f(bb: 1, 0, 2) - // expected-error@-1 {{unnamed argument #3 must precede argument 'bb'}} + // expected-error@-1 {{unnamed argument #2 must precede argument 'bb'}} } do { @@ -755,7 +753,8 @@ func testUnlabeledParameterBindingPosition() { func f(aa: Int, _ bb: Int, _ cc: Int) {} f(0, 1) - // expected-error@-1:7 {{missing argument for parameter 'aa' in call}} + // expected-error@-1:6 {{missing argument label 'aa:' in call}} + // expected-error@-2:11 {{missing argument for parameter #3 in call}} } do { @@ -763,7 +762,8 @@ func testUnlabeledParameterBindingPosition() { func f(aa: Int, _ bb: Int = 81, _ cc: Int) {} f(0, 1) - // expected-error@-1:7 {{missing argument for parameter 'aa' in call}} + // expected-error@-1:6 {{missing argument label 'aa:' in call}} + // expected-error@-2:11 {{missing argument for parameter #3 in call}} } do {