[ConstraintSystem] new argument matching algorithm #32082
                
     Closed
            
            
          
  Add this suggestion to a batch that can be applied as a single commit.
  This suggestion is invalid because no changes were made to the code.
  Suggestions cannot be applied while the pull request is closed.
  Suggestions cannot be applied while viewing a subset of changes.
  Only one suggestion per line can be applied in a batch.
  Add this suggestion to a batch that can be applied as a single commit.
  Applying suggestions on deleted lines is not supported.
  You must change the existing code in this line in order to create a valid suggestion.
  Outdated suggestions cannot be applied.
  This suggestion has been applied or marked resolved.
  Suggestions cannot be applied from pending reviews.
  Suggestions cannot be applied on multi-line comments.
  Suggestions cannot be applied while the pull request is queued to merge.
  Suggestion cannot be applied right now. Please check back later.
  
    
  
    
I created new algorithm of argument matching that produces expected result in all difficult situation we discussed at #32037 #30444.
EDIT at 2020/05/30 07:32:30 JST: add document.
EDIT at 2020/05/30 23:59:30 JST: add result section.
@xedin Could you review this?
I am going to write full explanation soon.The new 3 stage argument matching algorithm
I propose a new 3 stage argument matching algorihm in this patch.
Introduction
The current
matchCallArgumenthas a problem with argument matching.This is that diagnostic message about label errors doesn't match the result of argument matching
where input source code has a compilation error.
It is difficult to build argument matching that matches desired diagnostic message.
I tried it once with patch here #32307 , but it wasn't perfect.
This patch completely overhauls existing
matchCallArgumentimplementation and changes it new algorithm.In this document, I describe this algorithm.
Expression form of bindings
I had
parameter => argumentform in past at #32307, but I actually useargument => parameterform because it's still easier to understand.Requirements
I enumerate an nature of expected bindings.
R-1 Unlabeled arguments are aligned with labeled arguments
Unlabeled arguments should be aligned from where the preceding labeled arguments match.
For following example:
2should match_ dd:since it followscc:and4should match_ bb:since it followsaa:.R-2 Unlabeled arguments must be bound to same number of unlabeled parameters
When there are same number of unlabeled arguments and parameters, they must be bound with higher priority.
For following example:
Since there are two unlabeled arguments in
1and3andtwo unlabeled parameters in
_ bb:and_ cc:,they must be bound.
xx:should not match_ bb:or_ cc:.R-3 Unlabeled arguments(parameters) should be bound to labeled parameters(arguments) if possible
When there are more unlabeled arguments than unlabled parameters,
extra unlabeled arguments should be bound as much as labeled parameters.
For following example:
There are two arguments in
1and3,more than one parameter in
_ bb:.So, the extra
1should be matchedaa:.In this case, crossed binding such as the following are undesirable.
/* unexpected bindings: 1 => _ bb: 2 => aa: */Also, it is undesirable to build the following extra and missing arguments.
/* unexpected bindings: none => aa: (missing argument) 1 => _ bb: 2 => none (extra argument) */As shown below,
even if unlabeled arguments has an unrelated labeled arguments near it,
unlabeled arguments should take precedence over labeled arguments and match labeled parameter.
Contrary to what I have said,
when there are more unlabeled parameters than unlabeled arguments,
extra unlabeled parameters should be matched labeled arguments.
For example:
R-4 Even different labels bind each other.
Even if it's a different label,
they should be matched if that's the only option.
For example:
It is undesirable to build the following extra and missing arguments.
/* unexpected bindings: none => aa: (missing argument) xx: => none (extra argument) */Discussion
Based on the requirements, consider the necessary rules.
D-1 4 levels of priority
From requirements,
we can see that there are four levels of strength in binding of arguments.
In order of strength are the following
labeled arguments and unlabeled parameters
D-2 Binding of unlabeled arguments
Consider the following situations.
Now, we suppose to decide binding of
_ cc:.Since
aa:andcc:are not claimed,we would like to match unlabeled arguments to them if possible.
Now there are two unlabeled parameters and three unlabeled arguments,
so there is one unlabeled argument left over.
So, save
1for binding labeled arguments later, and bind2to_ cc:.Next, we suppose to decide binding of
_ dd:.Since
aa:andcc:are not claimed,we would like to match unlabeled arguments to them if possible.
Since we've already bind
2to_ cc:,there are one unlabeled parameter in
_ dd:and two unlabeled arguments in1and3, so there is one unlabeled argument left over.So, save
1again for binding labeled argumets later, and bind3to_ dd:.After binding of unlabeled arguments is finished,
unlabeled argument in
1and unlabeled parameters inaa:,bb:are left.So, if we match them positionally, finally get the following bindings.
/* bindings: 1 => aa: none => bb: (missing argument) 2 => _ cc: 3 => _ dd: */In this way,
by examining the number of unlabeled parameters,
the number of labeled parameters at left,
and the number of unlabeled arguments,
bindings satisfying
R-2andR-3can be made.If unlabeled parameters are more than unlabeled arguments,
the same process can be done with the opposite view.
Proposal
Based on the above, I propose argument matching algorithm with three levels of grouping.
This method divides the steps into the following three stages.
In the first label match,
look for a match between all parameters and arguments.
Once matching is complete,
split remaining arguments by bound pairs into groups.
For example:
In stage 1,
cc:andff:are matched.By splitting arguments with these matchings, we group them as follows.
/* group 1 (most left): [1, 2, 3] => [aa:, _ bb:] group 2 (by cc:): [7, 8] => [dd:, _ ee:] group 3 (by ff:): [5] => [_ gg:, _ hh:] */Next, in stage 2, do unlabeled matching among groups created in stage 1.
Use the procedure described in D-2 for matching.
Then we will get following bindings.
/* group 1: 1 => aa: 2 => none (extra argument) 3 => _ bb: group 2: 7 => dd: 8 => _ ee: group 3: 5 => _ gg: none => _ hh: (missing argument) */Now we have complete bindings.
In this way, we can get the desired bindings.
Next, consider following example:
In this case, group will not be split in stage 1.
Unlabeled matching as following in stage 2.
In stage 2, as in stage 1,
split arguments by bound pairs into groups.
/* group 1 (by 1): [xx:] => [] group 2 (by 3): [yy:] => [cc:, dd:] */Next, in stage 3,
do posional matching ignoring labels among among groups created in stage 2.
Then we will get following bindings.
/* group 1: xx: => none (extra argument) group 2: yy: => cc: none => dd: (missing argument) */Now we have complete bindings.
In this way, we can get the desired bindings.
Implementation
The implementation is as follows.
claim: claims arguments same as current.bindParameter: After bind givenparamIdxandargIdx,bind variadic tails if necessary.
claimNextNamed: deleted.bindNextParameter: deleted.In the part with
Step 1in comment,label matching in stage 1 is done.
In the part with
Step 2in comment,label matching with typo correction in stage 1 is done.
bindUnlabeledParameters:Unlabeled matching in first half of stage 2.
Save extra unlabeled arguments.
bindParameterPositionally:Match unlabeled and labeled in second half of stage 2.
By argument
ignoreLabel,it is used for label agnostic matching in stage 3.
iterateGroups: Higher function that iterate each group which is split by existing bindings. It is used for stage 2 and 3.In the part with
Step 3in comment,stage 2 is done.
In the part with
Step 4in comment,stage 3 is done.
In the part with
Step 5in comment,it reports extra arguments.
In the part with
Step 6in comment,it reports missing arguments.
In the part with
Step 7in comment,it reports label errors.
Result
Inconsistent bindings with diagnostics and undesired bindings are built currently in some cases.
This patch improve these cases.
I show some good results below.