@@ -2135,24 +2135,36 @@ impl<'a, 'db> ArgumentMatcher<'a, 'db> {
2135
2135
Ok ( ( ) )
2136
2136
}
2137
2137
2138
+ /// Match a variadic argument to the remaining positional, standard or variadic parameters.
2138
2139
fn match_variadic (
2139
2140
& mut self ,
2140
2141
db : & ' db dyn Db ,
2141
2142
argument_index : usize ,
2142
2143
argument : Argument < ' a > ,
2143
2144
argument_type : Option < Type < ' db > > ,
2144
- length : TupleLength ,
2145
2145
) -> Result < ( ) , ( ) > {
2146
2146
let tuple = argument_type. map ( |ty| ty. iterate ( db) ) ;
2147
- let mut argument_types = match tuple. as_ref ( ) {
2148
- Some ( tuple) => Either :: Left ( tuple. all_elements ( ) . copied ( ) ) ,
2149
- None => Either :: Right ( std:: iter:: empty ( ) ) ,
2147
+ let ( mut argument_types, length, variable_element) = match tuple. as_ref ( ) {
2148
+ Some ( tuple) => (
2149
+ Either :: Left ( tuple. all_elements ( ) . copied ( ) ) ,
2150
+ tuple. len ( ) ,
2151
+ tuple. variable_element ( ) . copied ( ) ,
2152
+ ) ,
2153
+ None => (
2154
+ Either :: Right ( std:: iter:: empty ( ) ) ,
2155
+ TupleLength :: unknown ( ) ,
2156
+ None ,
2157
+ ) ,
2150
2158
} ;
2151
2159
2152
2160
// We must be able to match up the fixed-length portion of the argument with positional
2153
2161
// parameters, so we pass on any errors that occur.
2154
2162
for _ in 0 ..length. minimum ( ) {
2155
- self . match_positional ( argument_index, argument, argument_types. next ( ) ) ?;
2163
+ self . match_positional (
2164
+ argument_index,
2165
+ argument,
2166
+ argument_types. next ( ) . or ( variable_element) ,
2167
+ ) ?;
2156
2168
}
2157
2169
2158
2170
// If the tuple is variable-length, we assume that it will soak up all remaining positional
@@ -2163,7 +2175,24 @@ impl<'a, 'db> ArgumentMatcher<'a, 'db> {
2163
2175
. get_positional ( self . next_positional )
2164
2176
. is_some ( )
2165
2177
{
2166
- self . match_positional ( argument_index, argument, argument_types. next ( ) ) ?;
2178
+ self . match_positional (
2179
+ argument_index,
2180
+ argument,
2181
+ argument_types. next ( ) . or ( variable_element) ,
2182
+ ) ?;
2183
+ }
2184
+ }
2185
+
2186
+ // Finally, if there is a variadic parameter we can match any of the remaining unpacked
2187
+ // argument types to it, but only if there is at least one remaining argument type. This is
2188
+ // because a variadic parameter is optional, so if this was done unconditionally, ty could
2189
+ // raise a false positive as "too many arguments".
2190
+ if self . parameters . variadic ( ) . is_some ( ) {
2191
+ if let Some ( argument_type) = argument_types. next ( ) . or ( variable_element) {
2192
+ self . match_positional ( argument_index, argument, Some ( argument_type) ) ?;
2193
+ for argument_type in argument_types {
2194
+ self . match_positional ( argument_index, argument, Some ( argument_type) ) ?;
2195
+ }
2167
2196
}
2168
2197
}
2169
2198
@@ -2433,11 +2462,10 @@ impl<'a, 'db> ArgumentTypeChecker<'a, 'db> {
2433
2462
self . enumerate_argument_types ( )
2434
2463
{
2435
2464
match argument {
2436
- Argument :: Variadic ( _ ) => self . check_variadic_argument_type (
2465
+ Argument :: Variadic => self . check_variadic_argument_type (
2437
2466
argument_index,
2438
2467
adjusted_argument_index,
2439
2468
argument,
2440
- argument_type,
2441
2469
) ,
2442
2470
Argument :: Keywords => self . check_keyword_variadic_argument_type (
2443
2471
argument_index,
@@ -2465,37 +2493,15 @@ impl<'a, 'db> ArgumentTypeChecker<'a, 'db> {
2465
2493
argument_index : usize ,
2466
2494
adjusted_argument_index : Option < usize > ,
2467
2495
argument : Argument < ' a > ,
2468
- argument_type : Type < ' db > ,
2469
2496
) {
2470
- // If the argument is splatted, convert its type into a tuple describing the splatted
2471
- // elements. For tuples, we don't have to do anything! For other types, we treat it as
2472
- // an iterator, and create a homogeneous tuple of its output type, since we don't know
2473
- // how many elements the iterator will produce.
2474
- let argument_types = argument_type. iterate ( self . db ) ;
2475
-
2476
- // Resize the tuple of argument types to line up with the number of parameters this
2477
- // argument was matched against. If parameter matching succeeded, then we can (TODO:
2478
- // should be able to, see above) guarantee that all of the required elements of the
2479
- // splatted tuple will have been matched with a parameter. But if parameter matching
2480
- // failed, there might be more required elements. That means we can't use
2481
- // TupleLength::Fixed below, because we would otherwise get a "too many values" error
2482
- // when parameter matching failed.
2483
- let desired_size =
2484
- TupleLength :: Variable ( self . argument_matches [ argument_index] . parameters . len ( ) , 0 ) ;
2485
- let argument_types = argument_types
2486
- . resize ( self . db , desired_size)
2487
- . expect ( "argument type should be consistent with its arity" ) ;
2488
-
2489
- // Check the types by zipping through the splatted argument types and their matched
2490
- // parameters.
2491
- for ( argument_type, parameter_index) in
2492
- ( argument_types. all_elements ( ) ) . zip ( & self . argument_matches [ argument_index] . parameters )
2497
+ for ( parameter_index, variadic_argument_type) in
2498
+ self . argument_matches [ argument_index] . iter ( )
2493
2499
{
2494
2500
self . check_argument_type (
2495
2501
adjusted_argument_index,
2496
2502
argument,
2497
- * argument_type ,
2498
- * parameter_index,
2503
+ variadic_argument_type . unwrap_or_else ( Type :: unknown ) ,
2504
+ parameter_index,
2499
2505
) ;
2500
2506
}
2501
2507
}
@@ -2711,9 +2717,8 @@ impl<'db> Binding<'db> {
2711
2717
Argument :: Keyword ( name) => {
2712
2718
let _ = matcher. match_keyword ( argument_index, argument, None , name) ;
2713
2719
}
2714
- Argument :: Variadic ( length) => {
2715
- let _ =
2716
- matcher. match_variadic ( db, argument_index, argument, argument_type, length) ;
2720
+ Argument :: Variadic => {
2721
+ let _ = matcher. match_variadic ( db, argument_index, argument, argument_type) ;
2717
2722
}
2718
2723
Argument :: Keywords => {
2719
2724
keywords_arguments. push ( ( argument_index, argument_type) ) ;
0 commit comments