Skip to content

Commit 49c4573

Browse files
committed
Refactor generic argument count check in astconv
1 parent a14bc71 commit 49c4573

17 files changed

+140
-143
lines changed

src/librustc/ty/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -919,7 +919,7 @@ impl<'a, 'gcx, 'tcx> Generics {
919919
for param in &self.params {
920920
match param.kind {
921921
GenericParamDefKind::Lifetime => own_counts.lifetimes += 1,
922-
GenericParamDefKind::Type {..} => own_counts.types += 1,
922+
GenericParamDefKind::Type { .. } => own_counts.types += 1,
923923
};
924924
}
925925

src/librustc_typeck/astconv.rs

Lines changed: 106 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ use std::slice;
2929
use require_c_abi_if_variadic;
3030
use util::common::ErrorReported;
3131
use util::nodemap::{FxHashSet, FxHashMap};
32-
use errors::FatalError;
32+
use errors::{FatalError, DiagnosticId};
3333

3434
use std::iter;
3535
use syntax::ast;
@@ -89,11 +89,6 @@ struct ConvertedBinding<'tcx> {
8989
span: Span,
9090
}
9191

92-
struct ParamRange {
93-
required: usize,
94-
accepted: usize
95-
}
96-
9792
/// Dummy type used for the `Self` of a `TraitRef` created for converting
9893
/// a trait object, and which gets removed in `ExistentialTraitRef`.
9994
/// This type must not appear anywhere in other converted types.
@@ -346,56 +341,21 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
346341
self_ty: Option<Ty<'tcx>>)
347342
-> (&'tcx Substs<'tcx>, Vec<ConvertedBinding<'tcx>>)
348343
{
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-
355344
// If the type is parameterized by this region, then replace this
356345
// region with the current anon region binding (in other words,
357346
// 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);
387350

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);
391353

392354
// 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());
394356

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);
399359

400360
let is_object = self_ty.map_or(false, |ty| ty.sty == TRAIT_OBJECT_DUMMY_SELF);
401361
let default_needs_object_self = |param: &ty::GenericParamDef| {
@@ -492,8 +452,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
492452
}
493453
}).collect();
494454

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);
497457

498458
(substs, assoc_bindings)
499459
}
@@ -1537,70 +1497,107 @@ fn split_auto_traits<'a, 'b, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
15371497
(auto_traits, trait_bounds)
15381498
}
15391499

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,
15681519
};
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();
15811520
}
1582-
}
15831521

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;
15901533
}
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+
}
15951543
} 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();
15981581
};
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+
}
16041601
}
16051602

16061603
// A helper struct for conveniently grouping a set of bounds which we pass to

src/test/ui/bad/bad-mid-path-type-params.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ fn foo<'a>() {
4141
//~^ ERROR too many type parameters provided
4242

4343
let _ = S::<'a,isize>::new::<f64>(1, 1.0);
44-
//~^ ERROR wrong number of lifetime parameters
44+
//~^ ERROR wrong number of lifetime arguments
4545

4646
let _: S2 = Trait::new::<isize,f64>(1, 1.0);
4747
//~^ ERROR too many type parameters provided

src/test/ui/error-codes/E0107.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,13 @@ enum Bar {
2020
struct Baz<'a, 'b, 'c> {
2121
buzz: Buzz<'a>,
2222
//~^ ERROR E0107
23-
//~| expected 2 lifetime parameters
23+
//~| expected 2 lifetime arguments
2424
bar: Bar<'a>,
2525
//~^ ERROR E0107
26-
//~| unexpected lifetime parameter
26+
//~| unexpected lifetime argument
2727
foo2: Foo<'a, 'b, 'c>,
2828
//~^ ERROR E0107
29-
//~| 2 unexpected lifetime parameters
29+
//~| 2 unexpected lifetime arguments
3030
}
3131

3232
fn main() {}

src/test/ui/error-codes/E0107.stderr

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
1-
error[E0107]: wrong number of lifetime parameters: expected 2, found 1
1+
error[E0107]: wrong number of lifetime arguments: expected 2, found 1
22
--> $DIR/E0107.rs:21:11
33
|
44
LL | buzz: Buzz<'a>,
5-
| ^^^^^^^^ expected 2 lifetime parameters
5+
| ^^^^^^^^ expected 2 lifetime arguments
66

7-
error[E0107]: wrong number of lifetime parameters: expected 0, found 1
7+
error[E0107]: wrong number of lifetime arguments: expected 0, found 1
88
--> $DIR/E0107.rs:24:10
99
|
1010
LL | bar: Bar<'a>,
11-
| ^^^^^^^ unexpected lifetime parameter
11+
| ^^^^^^^ unexpected lifetime argument
1212

13-
error[E0107]: wrong number of lifetime parameters: expected 1, found 3
13+
error[E0107]: wrong number of lifetime arguments: expected 1, found 3
1414
--> $DIR/E0107.rs:27:11
1515
|
1616
LL | foo2: Foo<'a, 'b, 'c>,
17-
| ^^^^^^^^^^^^^^^ 2 unexpected lifetime parameters
17+
| ^^^^^^^^^^^^^^^ 2 unexpected lifetime arguments
1818

1919
error: aborting due to 3 previous errors
2020

src/test/ui/error-codes/E0244.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error[E0244]: wrong number of type arguments: expected 0, found 2
22
--> $DIR/E0244.rs:12:23
33
|
44
LL | struct Bar<S, T> { x: Foo<S, T> }
5-
| ^^^^^^^^^ expected no type arguments
5+
| ^^^^^^^^^ 2 unexpected type arguments
66

77
error: aborting due to previous error
88

src/test/ui/generic/generic-type-more-params-with-defaults.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error[E0244]: wrong number of type arguments: expected at most 2, found 3
22
--> $DIR/generic-type-more-params-with-defaults.rs:19:12
33
|
44
LL | let _: Vec<isize, Heap, bool>;
5-
| ^^^^^^^^^^^^^^^^^^^^^^ expected at most 2 type arguments
5+
| ^^^^^^^^^^^^^^^^^^^^^^ expected at most 2 type argument
66

77
error: aborting due to previous error
88

src/test/ui/issues/issue-18423.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
// Test that `Box` cannot be used with a lifetime parameter.
11+
// Test that `Box` cannot be used with a lifetime argument.
1212

1313
struct Foo<'a> {
14-
x: Box<'a, isize> //~ ERROR wrong number of lifetime parameters
14+
x: Box<'a, isize> //~ ERROR wrong number of lifetime arguments
1515
}
1616

1717
pub fn main() {

src/test/ui/issues/issue-18423.stderr

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error[E0107]: wrong number of lifetime parameters: expected 0, found 1
1+
error[E0107]: wrong number of lifetime arguments: expected 0, found 1
22
--> $DIR/issue-18423.rs:14:8
33
|
4-
LL | x: Box<'a, isize> //~ ERROR wrong number of lifetime parameters
5-
| ^^^^^^^^^^^^^^ unexpected lifetime parameter
4+
LL | x: Box<'a, isize> //~ ERROR wrong number of lifetime arguments
5+
| ^^^^^^^^^^^^^^ unexpected lifetime argument
66

77
error: aborting due to previous error
88

src/test/ui/issues/issue-3214.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ error[E0244]: wrong number of type arguments: expected 0, found 1
1313
--> $DIR/issue-3214.rs:16:22
1414
|
1515
LL | impl<T> Drop for foo<T> {
16-
| ^^^^^^ expected no type arguments
16+
| ^^^^^^ unexpected type argument
1717

1818
error: aborting due to 2 previous errors
1919

src/test/ui/traits/trait-object-vs-lifetime.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ fn main() {
2121
let _: S<'static, 'static +>;
2222
//~^ at least one non-builtin trait is required for an object type
2323
let _: S<'static, 'static>;
24-
//~^ ERROR wrong number of lifetime parameters: expected 1, found 2
24+
//~^ ERROR wrong number of lifetime arguments: expected 1, found 2
2525
//~| ERROR wrong number of type arguments: expected 1, found 0
2626
let _: S<'static +, 'static>;
2727
//~^ ERROR lifetime parameters must be declared prior to type parameters

0 commit comments

Comments
 (0)