@@ -29,7 +29,7 @@ use std::slice;
29
29
use require_c_abi_if_variadic;
30
30
use util:: common:: ErrorReported ;
31
31
use util:: nodemap:: { FxHashSet , FxHashMap } ;
32
- use errors:: FatalError ;
32
+ use errors:: { FatalError , DiagnosticId } ;
33
33
34
34
use std:: iter;
35
35
use syntax:: ast;
@@ -89,11 +89,6 @@ struct ConvertedBinding<'tcx> {
89
89
span : Span ,
90
90
}
91
91
92
- struct ParamRange {
93
- required : usize ,
94
- accepted : usize
95
- }
96
-
97
92
/// Dummy type used for the `Self` of a `TraitRef` created for converting
98
93
/// a trait object, and which gets removed in `ExistentialTraitRef`.
99
94
/// This type must not appear anywhere in other converted types.
@@ -346,56 +341,21 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
346
341
self_ty : Option < Ty < ' tcx > > )
347
342
-> ( & ' tcx Substs < ' tcx > , Vec < ConvertedBinding < ' tcx > > )
348
343
{
349
- let tcx = self . tcx ( ) ;
350
-
351
- debug ! ( "create_substs_for_ast_path(def_id={:?}, self_ty={:?}, \
352
- generic_args={:?})",
353
- def_id, self_ty, generic_args) ;
354
-
355
344
// If the type is parameterized by this region, then replace this
356
345
// region with the current anon region binding (in other words,
357
346
// whatever & would get replaced with).
358
- let mut lt_provided = 0 ;
359
- let mut ty_provided = 0 ;
360
- for arg in & generic_args. args {
361
- match arg {
362
- GenericArg :: Lifetime ( _) => lt_provided += 1 ,
363
- GenericArg :: Type ( _) => ty_provided += 1 ,
364
- }
365
- }
366
-
367
- let decl_generics = tcx. generics_of ( def_id) ;
368
- let mut lt_accepted = 0 ;
369
- let mut ty_params = ParamRange { required : 0 , accepted : 0 } ;
370
- for param in & decl_generics. params {
371
- match param. kind {
372
- GenericParamDefKind :: Lifetime => {
373
- lt_accepted += 1 ;
374
- }
375
- GenericParamDefKind :: Type { has_default, .. } => {
376
- ty_params. accepted += 1 ;
377
- if !has_default {
378
- ty_params. required += 1 ;
379
- }
380
- }
381
- } ;
382
- }
383
- if self_ty. is_some ( ) {
384
- ty_params. required -= 1 ;
385
- ty_params. accepted -= 1 ;
386
- }
347
+ debug ! ( "create_substs_for_ast_path(def_id={:?}, self_ty={:?}, \
348
+ generic_args={:?})",
349
+ def_id, self_ty, generic_args) ;
387
350
388
- if lt_accepted != lt_provided {
389
- report_lifetime_number_error ( tcx, span, lt_provided, lt_accepted) ;
390
- }
351
+ let tcx = self . tcx ( ) ;
352
+ let generic_params = tcx. generics_of ( def_id) ;
391
353
392
354
// If a self-type was declared, one should be provided.
393
- assert_eq ! ( decl_generics . has_self, self_ty. is_some( ) ) ;
355
+ assert_eq ! ( generic_params . has_self, self_ty. is_some( ) ) ;
394
356
395
- // Check the number of type parameters supplied by the user.
396
- if !infer_types || ty_provided > ty_params. required {
397
- check_type_argument_count ( tcx, span, ty_provided, ty_params) ;
398
- }
357
+ let has_self = generic_params. has_self ;
358
+ check_generic_arg_count ( tcx, span, & generic_params, & generic_args, has_self, infer_types) ;
399
359
400
360
let is_object = self_ty. map_or ( false , |ty| ty. sty == TRAIT_OBJECT_DUMMY_SELF ) ;
401
361
let default_needs_object_self = |param : & ty:: GenericParamDef | {
@@ -492,8 +452,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
492
452
}
493
453
} ) . collect ( ) ;
494
454
495
- debug ! ( "create_substs_for_ast_path(decl_generics ={:?}, self_ty={:?}) -> {:?}" ,
496
- decl_generics , self_ty, substs) ;
455
+ debug ! ( "create_substs_for_ast_path(generic_params ={:?}, self_ty={:?}) -> {:?}" ,
456
+ generic_params , self_ty, substs) ;
497
457
498
458
( substs, assoc_bindings)
499
459
}
@@ -1537,70 +1497,107 @@ fn split_auto_traits<'a, 'b, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
1537
1497
( auto_traits, trait_bounds)
1538
1498
}
1539
1499
1540
- fn check_type_argument_count ( tcx : TyCtxt ,
1541
- span : Span ,
1542
- supplied : usize ,
1543
- ty_params : ParamRange )
1544
- {
1545
- let ( required, accepted) = ( ty_params. required , ty_params. accepted ) ;
1546
- if supplied < required {
1547
- let expected = if required < accepted {
1548
- "expected at least"
1549
- } else {
1550
- "expected"
1551
- } ;
1552
- let arguments_plural = if required == 1 { "" } else { "s" } ;
1553
-
1554
- struct_span_err ! ( tcx. sess, span, E0243 ,
1555
- "wrong number of type arguments: {} {}, found {}" ,
1556
- expected, required, supplied)
1557
- . span_label ( span,
1558
- format ! ( "{} {} type argument{}" ,
1559
- expected,
1560
- required,
1561
- arguments_plural) )
1562
- . emit ( ) ;
1563
- } else if supplied > accepted {
1564
- let expected = if required < accepted {
1565
- format ! ( "expected at most {}" , accepted)
1566
- } else {
1567
- format ! ( "expected {}" , accepted)
1500
+ pub fn check_generic_arg_count (
1501
+ tcx : TyCtxt ,
1502
+ span : Span ,
1503
+ def : & ty:: Generics ,
1504
+ args : & hir:: GenericArgs ,
1505
+ has_self : bool ,
1506
+ infer_types : bool ,
1507
+ ) {
1508
+ // At this stage we are guaranteed that the generic arguments are in the correct order, e.g.
1509
+ // that lifetimes will proceed types. So it suffices to check the number of each generic
1510
+ // arguments in order to validate them with respect to the generic parameters.
1511
+ let param_counts = def. own_counts ( ) ;
1512
+ let arg_counts = args. own_counts ( ) ;
1513
+
1514
+ let mut defaults: ty:: GenericParamCount = Default :: default ( ) ;
1515
+ for param in & def. params {
1516
+ match param. kind {
1517
+ GenericParamDefKind :: Lifetime => { }
1518
+ GenericParamDefKind :: Type { has_default, .. } => defaults. types += has_default as usize ,
1568
1519
} ;
1569
- let arguments_plural = if accepted == 1 { "" } else { "s" } ;
1570
-
1571
- struct_span_err ! ( tcx. sess, span, E0244 ,
1572
- "wrong number of type arguments: {}, found {}" ,
1573
- expected, supplied)
1574
- . span_label (
1575
- span,
1576
- format ! ( "{} type argument{}" ,
1577
- if accepted == 0 { "expected no" } else { & expected } ,
1578
- arguments_plural)
1579
- )
1580
- . emit ( ) ;
1581
1520
}
1582
- }
1583
1521
1584
- fn report_lifetime_number_error ( tcx : TyCtxt , span : Span , number : usize , expected : usize ) {
1585
- let label = if number < expected {
1586
- if expected == 1 {
1587
- format ! ( "expected {} lifetime parameter" , expected)
1588
- } else {
1589
- format ! ( "expected {} lifetime parameters" , expected)
1522
+ let check_kind_count = |error_code_less : & str ,
1523
+ error_code_more : & str ,
1524
+ kind,
1525
+ required,
1526
+ permitted,
1527
+ provided| {
1528
+ // We enforce the following: `required` <= `provided` <= `permitted`.
1529
+ // For kinds without defaults (i.e. lifetimes), `required == permitted`.
1530
+ // For other kinds (i.e. types), `permitted` may be greater than `required`.
1531
+ if required <= provided && provided <= permitted {
1532
+ return ;
1590
1533
}
1591
- } else {
1592
- let additional = number - expected;
1593
- if additional == 1 {
1594
- "unexpected lifetime parameter" . to_string ( )
1534
+
1535
+ // Unfortunately lifetime and type parameter mismatches are typically styled
1536
+ // differently in diagnostics, which means we have a few cases to consider here.
1537
+ let ( bound, quantifier) = if required != permitted {
1538
+ if provided < required {
1539
+ ( required, "at least " )
1540
+ } else { // provided > permitted
1541
+ ( permitted, "at most " )
1542
+ }
1595
1543
} else {
1596
- format ! ( "{} unexpected lifetime parameters" , additional)
1597
- }
1544
+ ( required, "" )
1545
+ } ;
1546
+ let label = if required == permitted && provided > permitted {
1547
+ let diff = provided - permitted;
1548
+ format ! (
1549
+ "{}unexpected {} argument{}" ,
1550
+ if diff != 1 { format!( "{} " , diff) } else { String :: new( ) } ,
1551
+ kind,
1552
+ if diff != 1 { "s" } else { "" } ,
1553
+ )
1554
+ } else {
1555
+ format ! (
1556
+ "expected {}{} {} argument{}" ,
1557
+ quantifier,
1558
+ bound,
1559
+ kind,
1560
+ if required != 1 { "s" } else { "" } ,
1561
+ )
1562
+ } ;
1563
+
1564
+ tcx. sess . struct_span_err_with_code (
1565
+ span,
1566
+ & format ! (
1567
+ "wrong number of {} arguments: expected {}{}, found {}" ,
1568
+ kind,
1569
+ quantifier,
1570
+ bound,
1571
+ provided,
1572
+ ) ,
1573
+ DiagnosticId :: Error ( {
1574
+ if provided <= permitted {
1575
+ error_code_less
1576
+ } else {
1577
+ error_code_more
1578
+ }
1579
+ } . into ( ) )
1580
+ ) . span_label ( span, label) . emit ( ) ;
1598
1581
} ;
1599
- struct_span_err ! ( tcx. sess, span, E0107 ,
1600
- "wrong number of lifetime parameters: expected {}, found {}" ,
1601
- expected, number)
1602
- . span_label ( span, label)
1603
- . emit ( ) ;
1582
+
1583
+ check_kind_count (
1584
+ "E0107" ,
1585
+ "E0107" ,
1586
+ "lifetime" ,
1587
+ param_counts. lifetimes ,
1588
+ param_counts. lifetimes ,
1589
+ arg_counts. lifetimes ,
1590
+ ) ;
1591
+ if !infer_types || arg_counts. types > param_counts. types - defaults. types - has_self as usize {
1592
+ check_kind_count (
1593
+ "E0243" ,
1594
+ "E0244" , // FIXME: E0243 and E0244 should be unified.
1595
+ "type" ,
1596
+ param_counts. types - defaults. types - has_self as usize ,
1597
+ param_counts. types - has_self as usize ,
1598
+ arg_counts. types ,
1599
+ ) ;
1600
+ }
1604
1601
}
1605
1602
1606
1603
// A helper struct for conveniently grouping a set of bounds which we pass to
0 commit comments