-
Notifications
You must be signed in to change notification settings - Fork 10.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[ConstraintSystem] Diagnose label issues individually #30444
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall looks great, changes are going in the direction I had in mind. I've left some comments inline, some of which we need to address before merging.
lib/Sema/CSFix.h
Outdated
@@ -165,6 +165,10 @@ enum class FixKind : uint8_t { | |||
/// Allow single tuple closure parameter destructuring into N arguments. | |||
AllowClosureParameterDestructuring, | |||
|
|||
/// A single argument have labeling failure - missing/extraneous or incorrect | |||
/// label attached to the, fix it by suggesting proper label. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's adjust wording a bit:
Labeling failure associated with a particular argument, could be a missing, extraneous or incorrect label.
Let fix the problem by suggesting a new label aligned with parameter at the same position.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, thanks 🙂
lib/Sema/CSFix.h
Outdated
|
||
bool coalesceAndDiagnose(const Solution &solution, | ||
ArrayRef<ConstraintFix *> secondaryFixes, | ||
bool asNote = false) const override; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please see my comment for incorrectLabel
, neither RelabelSingleArgument
nor MoveOutOfOrderArgument
should implement coalesceAndDiagnose
since this is supposed to represent a labeling failure with a single argument.
lib/Sema/CSFix.h
Outdated
@@ -1184,6 +1188,33 @@ class RemoveExtraneousArguments final | |||
} | |||
}; | |||
|
|||
class RelabelSingleArgument final : public ConstraintFix { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: I think we can simplify the class and case names down to RelabelArgument
since having singular form is indicative enough...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK 👍
std::string getName() const override { | ||
return "move out-of-order argument to correct position"; | ||
} | ||
|
||
bool diagnose(const Solution &solution, bool asNote = false) const override; | ||
|
||
bool coalesceAndDiagnose(const Solution &solution, | ||
ArrayRef<ConstraintFix *> secondaryFixes, | ||
bool asNote = false) const override; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment here as with RelabelSingleArgument
.
lib/Sema/CSSimplify.cpp
Outdated
|
||
auto *fix = RelabelSingleArgument::create(CS, Bindings[paramIndex].front(), | ||
Parameters[paramIndex].getLabel(), | ||
CS.getConstraintLocator(Locator)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should use a more specific locator here because Locator
points to a call itself in this case, it should be extended the same way as in case of synthesized arguments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, I change approach so.
Actually I have tried to locate this fix at CallExpr -> apply argument -> arg to param
.
It could print multiple diagnostics without using coalesceAndDiagnose
.
But another problem happened on it.
When both type error and label error exists,
e.g.
func f(aa: Int, bb: Int) {}
f(aax: "0", bb: 1)
This logic detects labeling failure as other argument mismatch.
Lines 3422 to 3433 in f4fee7a
if (llvm::any_of(getFixes(), [&](const ConstraintFix *fix) { | |
auto *locator = fix->getLocator(); | |
// Since arguments to @dynamicCallable form either an array | |
// or a dictionary and all have to match the same element type, | |
// let's allow multiple invalid arguments. | |
if (locator->findFirst<LocatorPathElt::DynamicCallable>()) | |
return false; | |
return locator->findLast<LocatorPathElt::ApplyArgToParam>() | |
? locator->getAnchor() == anchor | |
: false; | |
})) |
And solver stopped with ambiguous expression.
I will try to avoid this problem and make them works.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd suggest you to try and use a new locator element Label
specifically for re-labeling failures.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought that we could handle different kinds of fixes with the same locator but apparently that is not so.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will try to add new locator element.
test/APINotes/basic.swift
Outdated
@@ -24,7 +24,9 @@ func testSelectors(a: AnyObject) { | |||
|
|||
func testSwiftName() { | |||
moveTo(x: 0, y: 0, z: 0) | |||
moveTo(0, 0, 0) // expected-error{{missing argument labels 'x:y:z:' in call}} | |||
moveTo(0, 0, 0) // expected-error {{missing argument label 'x:' in call}} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If all of the arguments have labeling failures maybe it makes sense to have a single diagnostic instead of N?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh I see.
This case is clearly better to aggregate to one diagnostic.
I will implement aggregation
when all labeling issues are same category.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great!
lib/Sema/CSSimplify.cpp
Outdated
} | ||
} | ||
const auto bindings = ArgumentBindingHelper::fromParameterBindings( | ||
parameterBindings, numArgs); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems like all of the logic associated with ArgumentBindingHelper
could be inlined here instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another question - are we only aggregating data into ArgumentBindingHelper
in order to discount variadic arguments?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Purpose of ArgumentBindingHelper
is multiple.
- (1) Skip to parameter which has default and not mapped to any argument.
- (2) Skip to parameter which hasn't default and not mapped to any argument.
It's missing argument. - (3) Skip to argument which is at variadic tails.
- (4) Skip to argument which isn't mapped to any parameter.
It's extra argument.
In other words, to focus reordering,
it picks established pairs of argument and parameters.
Answer is yes.
I need argument indices which are bounded to some parameter and not variadic tail here.
for (unsigned leftArgIdx = 0; leftArgIdx < binding.argIdx; leftArgIdx++) {
(1), (2) can be got from parameterBindings
efficiently.
(4) can be got from claimedArgs
efficiently.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, that what I thought, the question is whether it could be all done in a single loop? It seems to be that it could be done?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, I remove ArgumentBindingHelper
and make as simple as possible here.
lib/Sema/CSSimplify.cpp
Outdated
|
||
const auto argIdx = parameterBinding[0]; | ||
// extra argument | ||
if (numArgs <= argIdx) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should it be strictly less here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, comment extra argument
is wrong. sorry.
Here is expected to skip synthesized argument from missing argument.
If parameter is unbound,
ArgumentFailureTracker
generates dummy argument and bind it.
Generation:
Line 813 in f4fee7a
unsigned newArgIdx = Arguments.size(); |
Binding:
Lines 638 to 641 in f4fee7a
if (auto newArgIdx = listener.missingArgument(paramIdx)) { | |
parameterBindings[paramIdx].push_back(*newArgIdx); | |
continue; | |
} |
numArgs
are not updated when it happen.
So this logic can detect synthesized argument.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah I see, please update that comment to mention that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK.
lib/Sema/CSDiagnostics.cpp
Outdated
#include "swift/Parse/Lexer.h" | ||
#include "swift/Sema/IDETypeChecking.h" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's avoid using functions from swift/Sema/IDETypeChecking.h and simplify record more information into the fix itself.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, I will fix it.
It is included to use getOriginalArgumentList
helper function at SingleLabelingFailure::diagnoseAsError
.
It integrates ParenExpr
, TupleExpr
, and other cases.
I don't know well what AST may comes here.
I will be looking into it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd suggest to avoid dealing with AST at all and record all necessary information in the fix/diagnostic. We are hoping that we'd be able to model argument in calls differently in the future so adjusting diagnostics proactively means less refactoring in the future.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh I never thought about not touching AST.
OK!
Thank for telling me future direction.
lib/Sema/CSDiagnostics.cpp
Outdated
paramStr += paramLabel.str(); | ||
paramStr += ':'; | ||
|
||
if (auto selectedOverload = getChoiceFor(getLocator())) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Once locator points to an individual argument you can use getCalleeLocator
here to refer to the overload choice.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks.
Do you tell me code after I will change locator of RelabelSingleArgument
following above review?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I'm just pointing out how to fix a future problem once locator would be changed :)
472f096
to
b0e0da8
Compare
My work will finish soon. |
19f7a11
to
2597323
Compare
@xedin I updated implementation. I explain details below. I added diagnostics aggregation in two cases.
Aggregated labeling constructs another mapping between arguments and parameters. It is different from mapping for type checking. I removed I added But constructing https://github.com/omochi/swift/blob/25973233491269126eacd2333c80a7cc57bc9421/lib/Sema/CSSimplify.cpp#L885-L891 I didn't understand how to use There is another use of I found only two source code which is processed here from test cases. // (1)
struct S {}
let _: (S) -> S.Type = type(of:)
// (2)
let _: ((Int) -> Int, (@escaping (Int) -> Int) -> ()) -> ()
= withoutActuallyEscaping(_:do:) But both cases didn't work correctly. I added LocatorPathElt::ArgumentLabel. |
I pushed one commit to fix bug. Original
Fixed
|
lib/Sema/CSDiagnostics.h
Outdated
@@ -465,15 +465,20 @@ class SuperclassRequirementFailure final : public RequirementFailure { | |||
/// Call to `foo` is going to be diagnosed as missing `q:` | |||
/// and having extraneous `a:` labels, with appropriate fix-its added. | |||
class LabelingFailure final : public FailureDiagnostic { | |||
ArrayRef<Identifier> CorrectLabels; | |||
ArgumentRelabeling Relabeling; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I went through this a couple of times and I can say that I like previous approach better. I think we should record individual RelabelArgument
fixes for each incorrect position so that content of ArgumentRelabelingItem
could be inlined into the fix itself and then have a RelabelArgument::coaleseAndDiagnose
method which would group labeling fixes if necessary e.g., if majority of labels are incorrect, and produce a single diagnostic. WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought about that today.
Basically, I think it's good.
Certainly, it makes sense to generate fixes for each label that has an problem, and then aggregate them at the time of the coalesceAndDaignose
where the fixes are translated into diagnostics.
As a constraint system, it is easier to understand the presence of fixes for each label when looking at the intermediate state with -debug-constraints
, and the impact value of each fix is constant.
The implementation of matchCallArguments
is also simplified around the following.
However, some changes in diagnostics are inevitable because other information about reordering fix, extraneous or missing arguments are not detectable in RelabelArgument::coalesceAndDiagnose
.
(1). It can't control not aggregating label errors when there is a reorder fix.
For example, it would be:
func f(aa: Int, bb: Int, cc: Int, dd: Int, ee: Int) {}
f(aax: 0, bb: 1, dd: 3, cc: 2, eex: 5)
// incorrect argument labels in call (have 'aax:eex:', expected 'aa:ee:')
// fix-its: aax => aa, eex => ee
// argument 'cc:' must precede argument 'dd:'
but in my current implementation:
func f(aa: Int, bb: Int, cc: Int, dd: Int, ee: Int) {}
f(aax: 0, bb: 1, dd: 3, cc: 2, eex: 5)
// incorrect argument label in call (have 'aax:', expected 'aa:')
// fix-its: aax => aa
// incorrect argument label in call (have 'eex:', expected 'ee:')
// fix-its: eex => ee
// argument 'cc:' must precede argument 'dd:'
(2). It shows the given label and the expected label when it produces an aggregated label error. At this time, the given and expected labels cannot be reconstructed because the information of the extra argument and missing argument is not passed to the RelabelArgument::coalesceAndDiagnose
. These are the cases represented as None
in the ArgumentRelabelingItem
.
For a given label, It can get the AST information from the Locator. So the extra argument is fine. To begin with, currently it doesn't diagnose label issues when there is an extra argument, but I would like to do this at the same time in the future.
However, the label of the parameter corresponding to the missing argument can't be helped.
For example, it would be:
func f(aa: Int, bb: Int, cc: Int, dd: Int, ee: Int) {}
f(aa: 0, cc: 2, ddx: 3, eex: 3)
// incorrect argument labels in call (have 'ddx:eex:', expected 'dd:ee:')
// fix-its: ddx => dd, eex => ee
// missing argument for parameter 'bb' in call
but in my current implementation:
func f(aa: Int, bb: Int, cc: Int, dd: Int, ee: Int) {}
f(aa: 0, cc: 2, ddx: 3, eex: 3)
// incorrect argument labels in call (have 'aa:cc:ddx:eex:', expected 'aa:bb:cc:dd:ee:')
// fix-its: ddx => dd, eex => ee
// missing argument for parameter 'bb' in call
I can accept both cases.
It's rather simple and may be better.
With this policy, I can drop the Optional
in the ArgumentRelabelingItem
.
I will try to implement it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can do it this way - aggregate only if there are more than two labeling failures and no other failures associated with arguments of the same call?
Also please note that "aggregate" diagnostic has to produce all of the labels because it's about what call as a whole expects.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I let RelabelArgument
have only contents of the ArgumentRelabelingItem
as you said at start of this review thread, it can't produce an aggregated diagnosis that includes all the labels because RelabelArgument
fix is not generated for the missing argument, extra argument or label where there is no problem.
I considered that and made one previous reply.
Am I misreading something?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be easy enough to retrieve parameter labels from an overload associated with the call via getOverloadChoice(getCalleeLocator(getLocator()))
(from FailureDiagnostic), maybe worth a separate fix/diagnostic even.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I got it! Thanks for the advice.
6b3b9be
to
3c03c44
Compare
I updated implementation based on @xedin's idea. Behavior of diagnostics is almost same with my previous version. Expected labels are reconstructed from (1) But that logic looks too complex. (2) They are needed to support these cases.
(3) There is an another critical problem. #colorLiteral(red: 1, bleen: 0, grue: 0, alpha: 1) Test case is this. Should I try to fix Or should I use another approach to reconstruct? |
@omochi Sorry I didn't have much time to look into the changes again but I can tell you now regarding (3) - I think that's a bug in |
I will investigate I'm fine about the delay. This project is more complicated than I thought at start time. I'm happy to progress it a little at a time. |
3c03c44
to
158d14f
Compare
I updated implementation to support CSGen for After solver has determined the type corresponding to
This contains special handling such as rewriting labels from |
@swift-ci please smoke test |
At least it's passed the test, but very fragile code. |
I have a very long post below. premiseFirst of all, here's what I want to do with this patch. Goal 1Outputs all multiple label errors individually. 1-1: Reorderings and wrong labels My patch func f(aa: Int, bb: Int, cc: Int, dd: Int, ee: Int) {}
f(bb: 1, aa: 0, ccx: 2, ee: 4, dd: 3)
Xcode11.4
1-2: wrong, missing and extraneous labels My patch func f(aa: Int, bb: Int, _ cc: Int, dd: Int, ee: Int, _ ff: Int) {}
f(aax: 0, 1, cc: 2, ddx: 3, 4, ff: 5)
Xcode11.4
Goal 2In certain cases, I want to produce an aggregated label error. 2-1: If the arguments involved in the reordering message have label problems. In this case, the reordering message is difficult to understand, so instead of using a normal label mapping, use a positional mapping. My patch func f(aa: Int, bb: Int, cc: Int, dd: Int, ee: Int) {}
f(bb: 1, aax: 0, dd: 3, ee: 4, cc: 2)
In this input, arguments However, the argument As a result, Xcode 11.4: Same result. 2-1-1: When using positional mappings, maintain the given variadic arguments and omitted defaulted parameters detected at the time of the normal mapping. My patch func f(aa: Int, bb: Int, cc: Int, dd: Int..., ee: Int, ff: Int = 0, gg: Int = 0, hh: Int) {}
f(bb: 1, aax: 0, dd: 31, 32, 33, ee: 4, hh: 7, cc: 2)
Since Xcode 11.4
Label insertion appear at 2-2: If there is more than one label error and only wrongs, all labels will be displayed in the message. My patch func f(aa: Int, bb: Int, cc: Int, dd: Int) {}
f(aax: 0, bbx: 1, cc: 2, dd: 3)
Xcode11.4: Same result. 2-3: If there is more than one label error and only extraneous, group it. My patch func f(_ aa: Int, _ bb: Int, cc: Int, dd: Int) {}
f(aa: 0, bb: 1, cc: 2, dd: 3)
Xcode11.4: Same result. 2-4: If there is more than one label error and only missing, group it. My patch func f(aa: Int, bb: Int, cc: Int, dd: Int) {}
f(0, 1, cc: 2, dd: 3)
Xcode11.4: Same result. Goal 3I want to improve If all labels appear in the message (2-1, 2-2), I want to keep the given variadic arguments and the omitted defaulted parameters. 3-1: Maintaining given variadic arguments My patch func f(aa: Int, bb: Int, cc: Int..., dd: Int) {}
f(aax: 0, bbx: 1, cc: 21, 22, 23, dd: 3)
Xcode11.4:
It is supposed to have given 6 arguments, but as a user, It is supposed to expect 6 parameters, but by the definition of 3-2: Maintaining omitted defaulted parameters My patch func f(aa: Int, bb: Int, cc: Int = 0, dd: Int = 0, ee: Int, ff: Int = 0) {}
f(bb: 1, aax: 0, cc: 2, ee: 4)
It's a positional mapping of (2-1) because Xcode11.4:
3-3: Ignoring label of trailing closure My patch func f(aa: Int, bb: Int, cc: Int, dd: () -> Void) {}
f(bb: 1, aax: 0, cc: 2) {}
Xcode11.4:
Trailing closure is supposed to be given as an empty label. Parameter and argument that become trailing closure should be excluded from the labels. Implementation problemAmong the implementations of the various behaviors described above, the code for the realization of goal 3 in the case of the positional mapping in (2-1) is unstable. First, in order to achieve goal 3,
These information can be retrieved from In the case of 2-2, the current code is well written. First, the What's unstable is that it's using a different positional mapping in the case of (2-1), but it's passing An example of a specific value is shown below. func f(aa: Int, bb: Int, cc: Int, dd: Int..., ee: Int, ff: Int = 0, gg: Int = 0, hh: Int) {}
f(bb: 1, aax: 0, dd: 31, 32, 33, ee: 4, hh: 7, cc: 2) In this case, as a result of the normal mapping process,
However, since positional mapping is used, the diagnostic results are as follows.
The
Thus, in a situation where 5-2 is expected, 5-1 has been passed. However, this is working correctly. In other words, the 2-1-1 and 4-X designs mesh together in a daungerous balance. This is difficult to fix because There is also no API for passing new Additional proposalWriting this far has given me an idea to solve this. First, I talk about something else. 6. Problem of contradictory messagesIf a positional mapping is used in the diagnosis of a label, it has a different mapping than My patch func f(aa: Int, bb: Int, cc: String, dd: Int, ee: Int) {}
f(bb: 1, aax: 0, dd: "3", ee: 4, cc: 2)
Xcode11.4: Same result. An error in the label asks that the third argument The same contradiction arises in the argument SolutionThe problem of instability in 5-2 and the problem of contradictory messages in 6 can be solved collectively. That way, the 5-2 problem and the 6 problem will be solved at the same time. Semantically, I think it makes sense for the code to do a type check in the state after the label is modified as a diagnostic behavior. Originally, this patch wasn't going to touch on the 6 issue. However, I thought it would be a better design to include this. |
First of all, thank you for working on this @omochi! I think this is great! Couple of notes are below:
In my opinion diagnostics should be producing fix-it(s) only in cases 2-3, and 2-4. Unless types of argument/parameter pair are taking into consideration it's impossible to say what is going on with call in presence of multiple different kinds of problems with the call e.g. out-of-order arguments, missing labels etc., so it might make sense to produce a simple aggregate error and let users "disambiguate" the call.
I think we should always display labels in a way which is consistent with parameters e.g. if there are multiple variadic arguments drop all but one, if there is a trailing closure - pretend that argument is labeled.
It seems like we should be able to fix this problem in a different way. In case of incorrect or extraneous label(s) it might make sense to ignore argument type completely because such labels could be considered an indication that user intended to call a different overload of a given name. It seems relatively easy to fix with your changes if all of the labeling fixes were recorded individually, that way we could use |
Thank you for reading my long message and giving next advice to me. |
b9be64e
to
feb51bd
Compare
@xedin I updated implementation. However, I have not updated test cases yet. New implementation: (1) (2) https://github.com/apple/swift/blob/feb51bd6a89e85ddd0c93087502c94027fe10116/lib/Sema/CSSimplify.cpp#L794-L798 (3) https://github.com/apple/swift/blob/feb51bd6a89e85ddd0c93087502c94027fe10116/lib/Sema/CSFix.cpp#L313-L320 (4) Diagnostics for various inputs: struct TestBasic {
func f(_ aa: Int, _ bb: Int, cc: Int, dd: Int, ee: Int, ff: Int) {}
func test() {
// 1 wrong
f(0, 1, ccx: 2, dd: 3, ee: 4, ff: 5)
/*
a.swift:6:13: error: incorrect argument label in call (have 'ccx:', expected 'cc:')
f(0, 1, ccx: 2, dd: 3, ee: 4, ff: 5)
^~~
cc
*/
// 1 missing
f(0, 1, 2, dd: 3, ee: 4, ff: 5)
/*
a.swift:9:13: error: missing argument label 'cc:' in call
f(0, 1, 2, dd: 3, ee: 4, ff: 5)
^
cc:
*/
// 1 extra
f(aa: 0, 1, cc: 2, dd: 3, ee: 4, ff: 5)
/*
a.swift:12:7: error: extraneous argument label 'aa:' in call
f(aa: 0, 1, cc: 2, dd: 3, ee: 4, ff: 5)
^~~~
*/
// 1 ooo
f(0, 1, dd: 3, cc: 2, ee: 4, ff: 5)
/*
a.swift:15:20: error: argument 'cc' must precede argument 'dd'
f(0, 1, dd: 3, cc: 2, ee: 4, ff: 5)
~~~~~~~^~~~~
cc: 2,
*/
// 2 wrong
f(0, 1, ccx: 2, ddx: 3, ee: 4, ff: 5)
/*
a.swift:18:6: error: too many label errors in call (have: '_:_:ccx:ddx:ee:ff:', expected: '_:_:cc:dd:ee:ff:')
f(0, 1, ccx: 2, ddx: 3, ee: 4, ff: 5)
^
*/
// 2 missing
f(0, 1, 2, 3, ee: 4, ff: 5)
/*
a.swift:21:6: error: missing argument labels 'cc:dd:' in call
f(0, 1, 2, 3, ee: 4, ff: 5)
^
cc: dd:
*/
// 2 extra
f(aa: 0, bb: 1, cc: 2, dd: 3, ee: 4, ff: 5)
/*
a.swift:24:6: error: extraneous argument labels 'aa:bb:' in call
f(aa: 0, bb: 1, cc: 2, dd: 3, ee: 4, ff: 5)
^~~~~ ~~~~
*/
// 2 ooo
f(0, 1, dd: 3, cc: 2, ff: 5, ee: 4)
/*
a.swift:27:20: error: argument 'cc' must precede argument 'dd'
f(0, 1, dd: 3, cc: 2, ff: 5, ee: 4)
~~~~~~~^~~~~
cc: 2,
a.swift:27:34: error: argument 'ee' must precede argument 'ff'
f(0, 1, dd: 3, cc: 2, ff: 5, ee: 4)
~~~~~~~^~~~~
ee: 4,
*/
// 1 wrong + 1 missing
f(0, 1, ccx: 2, 3, ee: 4, ff: 5)
/*
a.swift:30:6: error: too many label errors in call (have: '_:_:ccx:_:ee:ff:', expected: '_:_:cc:dd:ee:ff:')
f(0, 1, ccx: 2, 3, ee: 4, ff: 5)
^
*/
// 1 wrong + 1 extra
f(aa: 0, 1, ccx: 2, dd: 3, ee: 4, ff: 5)
/*
a.swift:33:6: error: too many label errors in call (have: 'aa:_:ccx:dd:ee:ff:', expected: '_:_:cc:dd:ee:ff:')
f(aa: 0, 1, ccx: 2, dd: 3, ee: 4, ff: 5)
^
*/
// 1 wrong + 1 ooo
f(0, 1, ccx: 2, dd: 3, ff: 5, ee: 4)
/*
a.swift:36:6: error: too many label errors in call (have: '_:_:ccx:dd:ff:ee:', expected: '_:_:cc:dd:ee:ff:')
f(0, 1, ccx: 2, dd: 3, ff: 5, ee: 4)
^
*/
}
}
struct TestTrailingClosure {
func f1(aa: Int, bb: Int, cc: () -> Void = {}) {}
func f2(aa: Int, bb: Int, _ cc: () -> Void = {}) {}
func test() {
f1(aax: 0, bbx: 1) {}
/*
a.swift:46:7: error: too many label errors in call (have: 'aax:bbx:cc:', expected: 'aa:bb:cc:')
f1(aax: 0, bbx: 1) {}
^
*/
f2(aax: 0, bbx: 1) {}
/*
a.swift:48:7: error: too many label errors in call (have: 'aax:bbx:_:', expected: 'aa:bb:_:')
f2(aax: 0, bbx: 1) {}
^
*/
f1(aax: 0, bbx: 1)
/*
a.swift:50:7: error: too many label errors in call (have: 'aax:bbx:', expected: 'aa:bb:')
f1(aax: 0, bbx: 1)
^
*/
f2(aax: 0, bbx: 1)
/*
a.swift:52:7: error: too many label errors in call (have: 'aax:bbx:', expected: 'aa:bb:')
f2(aax: 0, bbx: 1)
^
*/
}
}
struct TestVariadic {
func f(aa: Int, bb: Int, cc: Int...) {}
func test() {
f(aax: 0, bbx: 1, cc: 2, 3, 4)
/*
a.swift:60:6: error: too many label errors in call (have: 'aax:bbx:cc:', expected: 'aa:bb:cc:')
f(aax: 0, bbx: 1, cc: 2, 3, 4)
^
*/
f(aax: 0, bbx: 1)
/*
a.swift:62:6: error: too many label errors in call (have: 'aax:bbx:', expected: 'aa:bb:')
f(aax: 0, bbx: 1)
^
*/
}
}
struct TestDefaulted {
func f(aa: Int, bb: Int, cc: Int = 0) {}
func test() {
f(aax: 0, bbx: 1, cc: 2)
/*
a.swift:70:6: error: too many label errors in call (have: 'aax:bbx:cc:', expected: 'aa:bb:cc:')
f(aax: 0, bbx: 1, cc: 2)
^
*/
f(aax: 0, bbx: 1)
/*
a.swift:72:6: error: too many label errors in call (have: 'aax:bbx:', expected: 'aa:bb:')
f(aax: 0, bbx: 1)
^
*/
}
}
Am I understanding your opinion correctly? |
@swift-ci Please smoke test |
@xedin I updated implementation. Details are below. Basic architecture is here. And I added new idea. This is an alternative for positional mapping. Positional mapping in master is here. Lines 758 to 763 in b7654f1
My old implementation is here. But they have problem what I wrote as Without positional mapping, following case was hard. func f(aa: Int, _ bb: Int) {}
f(0, 1)
As a result, mapping is So I added new logic into 1-2. When claim argument for params[1], I checked that it works good by test case. I made test case for what I summarized here. Now I resolved two worries written here. Other diagnostics behavior seems following your advices given me so far. |
@swift-ci Please smoke test |
Thank you, @omochi! I'll try to take a look on monday. |
Sorry, my day job is getting very busy so I'll check this weekend or next weekend. |
No worries, take your time! |
My main business has come out of a hard situation. First, I will rebase it on master. I'm interested in splitting this work up and making it partly PR. However, |
7f4ae69
to
a14849f
Compare
@swift-ci Please smoke test |
@swift-ci Please Smoke Test |
@xedin
By the way, since many changes have piled up now, it's getting hard to rebase to master. |
d9deb3f
to
c3c2bc3
Compare
@xedin It helps reviewer and future reader of these commits. And, I plan to make another PR which contains only addition of test cases. Because my work particularly focus corner cases, But I add some new test inputs in this patch. So I want to insert these test cases on master |
@swift-ci Please smoke test |
callee overload which has label issue
… ... which represents just a one label error
fixes. New dianostic building logic considers pairs of argument and parameter well in complex situation.
`RelabelArgument` for each label issues.
issues in `matchCallArguments`. It finds all of out of order label matchings. It reports label issues individually.
by considering unbounded parameter which is at left of current parameter in `matchCallArgument`. It avoids matching which has unwanted crossing pairs between argument and parameter. It provides natural relabeling diagnostics without reconstructing aligned matching pairs when out of ordered mapping happens like old implementation.
c3c2bc3
to
9f2c842
Compare
9f2c842
to
a9be9cf
Compare
@swift-ci please smoke test |
I will split this patch and create other patch. |
Summary
@xedin Hi again.
I retried many things and got betters.
Please review this.
Change Log
about out of order
at 2020/03/18 11:34 JST.Discussion
After label issues (mismatch or out of order) happen in
matchCallArgument
, type checking is continued for diagnostics.Such type checking uses mapping between arguments and parameters which is built by
matchCallArgument
with many consideration.For example, typo correction is used to map them.
When both label and type check issues happen, their behavior should be consistent.
And mapping may contains multiple out of ordered labels and mismatches.
To diagnose all what happened here is useful for user.
Because it tells user to how mapping is used by compiler.
But currently some of them are not achieved.
Label mismatch diagnostics are built independently without referring to mapping (
parameterBindings
variable) for type checking.It causes inconsistent error message between labels and types in corner case.
Reordering diagnostics is consistent with type checking.
But it works only limited condition and just one.
Reordering and mismatch diagnostics are exclusive.
And relabeling diagnostic have own calculation of out of order impacts.
For example,
This call has multiple label mismatch and out of order.
To make it easy for users to understand, each issues should be diagnosed individually.
Because, unified mismatch message with multiple labels which is twisted reordering
is hard to understand which parameter is mapped by each argument.
With this patch, diagnostics will be following.
Current is:
Design
MatchCallArgumentListener::relabelArguments
matchCallArgument
does not usediagnoseArgumentLabelFailure
anymoreRelabelSingleArgument
fixSingleLabelingFailure
diagnosticAbout out of order
What I mean by all out of order,
which arguments are moved from right to left so that all arguments are in correct order.
If argument needs to move, it is out of order.
In this rule, argument index number and parameter index number is not related.
Only the relative order in the arguments is relevant.
The correct order is determined based on parameters mapped before.
This change may increase out of order in some situation.
Examples
This patch:
Current:
Concern about impact value
This patch removes
MatchCallArgumentListener::relabelArguments
and(extraneous|missing|incorrect)Labels
emits individual constraint fixes.So I removed shared base impact point of
RelabelArgument
.Base is
1
inswift/lib/Sema/CSSimplify.cpp
Line 925 in 77af77f
New impacts are:
They includes base
1
.So if more than one issues, accumulated impact will be greater than current.
But this
1
is important.See this:
Currently choice
f()
.Because,
f()
, fix impact is 5 (missing argument).f(aa:)
, fix impact is 2 (type error) + 1 (relabel base) + 3 (incorrect label) = 6.If I choice
3
for incorrect label,this overload will be ambiguous.
I considered that this is bad regression.
Of course, it is all under the incorrect source code.
It could be changeable.
Contrarily, one test case
r27212391
indiagnostics.swift
changed to ambiguous error.