Skip to content

Commit 04d33bb

Browse files
committed
Refactor generic argument count check in check/mod.rs
1 parent 68b0e7d commit 04d33bb

File tree

10 files changed

+65
-163
lines changed

10 files changed

+65
-163
lines changed

src/librustc_typeck/astconv.rs

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,11 @@ struct ConvertedBinding<'tcx> {
9090
span: Span,
9191
}
9292

93+
pub struct GenericArgMismatchErrorCode {
94+
pub lifetimes: (&'static str, &'static str),
95+
pub types: (&'static str, &'static str),
96+
}
97+
9398
/// Dummy type used for the `Self` of a `TraitRef` created for converting
9499
/// a trait object, and which gets removed in `ExistentialTraitRef`.
95100
/// This type must not appear anywhere in other converted types.
@@ -199,6 +204,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
199204
is_method_call: bool,
200205
has_self: bool,
201206
infer_types: bool,
207+
error_codes: GenericArgMismatchErrorCode,
202208
) -> bool {
203209
// At this stage we are guaranteed that the generic arguments are in the correct order, e.g.
204210
// that lifetimes will proceed types. So it suffices to check the number of each generic
@@ -243,8 +249,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
243249
}
244250
}
245251

246-
let check_kind_count = |error_code_less: &str,
247-
error_code_more: &str,
252+
let check_kind_count = |error_code: (&str, &str),
248253
kind,
249254
required,
250255
permitted,
@@ -296,9 +301,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
296301
),
297302
DiagnosticId::Error({
298303
if provided <= permitted {
299-
error_code_less
304+
error_code.0
300305
} else {
301-
error_code_more
306+
error_code.1
302307
}
303308
}.into())
304309
).span_label(span, label).emit();
@@ -308,8 +313,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
308313

309314
if !infer_lifetimes || arg_counts.lifetimes > param_counts.lifetimes {
310315
check_kind_count(
311-
"E0107",
312-
"E0107",
316+
error_codes.lifetimes,
313317
"lifetime",
314318
param_counts.lifetimes,
315319
param_counts.lifetimes,
@@ -319,8 +323,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
319323
if !infer_types
320324
|| arg_counts.types > param_counts.types - defaults.types - has_self as usize {
321325
check_kind_count(
322-
"E0243",
323-
"E0244", // FIXME: E0243 and E0244 should be unified.
326+
error_codes.types,
324327
"type",
325328
param_counts.types - defaults.types - has_self as usize,
326329
param_counts.types - has_self as usize,
@@ -508,6 +511,10 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
508511
false, // `is_method_call` (irrelevant here)
509512
has_self,
510513
infer_types,
514+
GenericArgMismatchErrorCode {
515+
lifetimes: ("E0107", "E0107"),
516+
types: ("E0243", "E0244"), // FIXME: E0243 and E0244 should be unified.
517+
},
511518
);
512519

513520
let is_object = self_ty.map_or(false, |ty| ty.sty == TRAIT_OBJECT_DUMMY_SELF);

src/librustc_typeck/check/method/confirm.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
use super::{probe, MethodCallee};
1212

13-
use astconv::AstConv;
13+
use astconv::{AstConv, GenericArgMismatchErrorCode};
1414
use check::{FnCtxt, PlaceOp, callee, Needs};
1515
use hir::GenericArg;
1616
use hir::def_id::DefId;
@@ -329,9 +329,11 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
329329
true, // `is_method_call`
330330
method_generics.parent.is_none() && method_generics.has_self,
331331
segment.infer_types || suppress_mismatch,
332+
GenericArgMismatchErrorCode {
333+
lifetimes: ("E0090", "E0088"),
334+
types: ("E0089", "E0087"),
335+
},
332336
);
333-
// self.fcx.check_generic_arg_count(self.span, &segment, &method_generics, true,
334-
// supress_mismatch);
335337

336338
// Create subst for early-bound lifetime parameters, combining
337339
// parameters from the type and those from the method.

src/librustc_typeck/check/mod.rs

Lines changed: 21 additions & 128 deletions
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,10 @@ pub use self::compare_method::{compare_impl_method, compare_const_impl};
8484
use self::method::MethodCallee;
8585
use self::TupleArgumentsFlag::*;
8686

87-
use astconv::AstConv;
87+
use astconv::{AstConv, GenericArgMismatchErrorCode};
8888
use hir::GenericArg;
8989
use hir::def::Def;
90+
use hir::HirVec;
9091
use hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
9192
use std::slice;
9293
use namespace::Namespace;
@@ -4937,16 +4938,30 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
49374938
// to add defaults. If the user provided *too many* types, that's
49384939
// a problem.
49394940

4940-
let mut supress_errors = FxHashMap();
4941+
let mut suppress_errors = FxHashMap();
49414942
for &PathSeg(def_id, index) in &path_segs {
49424943
let seg = &segments[index];
49434944
let generics = self.tcx.generics_of(def_id);
49444945
// `impl Trait` is treated as a normal generic parameter internally,
49454946
// but we don't allow users to specify the parameter's value
49464947
// explicitly, so we have to do some error-checking here.
4947-
let supress_mismatch = self.check_impl_trait(span, seg, &generics);
4948-
supress_errors.insert(index,
4949-
self.check_generic_arg_count(span, seg, &generics, false, supress_mismatch));
4948+
let suppress_mismatch = self.check_impl_trait(span, seg, &generics);
4949+
suppress_errors.insert(index, AstConv::check_generic_arg_count(
4950+
self.tcx,
4951+
span,
4952+
&generics,
4953+
&seg.args.clone().unwrap_or_else(|| P(hir::GenericArgs {
4954+
args: HirVec::new(), bindings: HirVec::new(), parenthesized: false,
4955+
})),
4956+
false, // `is_declaration`
4957+
false, // `is_method_call`
4958+
generics.parent.is_none() && generics.has_self,
4959+
seg.infer_types || suppress_mismatch,
4960+
GenericArgMismatchErrorCode {
4961+
lifetimes: ("E0090", "E0088"), // FIXME: E0090 and E0088 should be unified.
4962+
types: ("E0089", "E0087"), // FIXME: E0089 and E0087 should be unified.
4963+
},
4964+
));
49504965
}
49514966

49524967
let has_self = path_segs.last().map(|PathSeg(def_id, _)| {
@@ -4968,7 +4983,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
49684983
}) {
49694984
// If we've encountered an `impl Trait`-related error, we're just
49704985
// going to infer the arguments for better error messages.
4971-
if !supress_errors[&index] {
4986+
if !suppress_errors[&index] {
49724987
// Check whether the user has provided generic arguments.
49734988
if let Some(ref data) = segments[index].args {
49744989
return (Some(data), segments[index].infer_types);
@@ -5097,128 +5112,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
50975112
directly, not through a function pointer");
50985113
}
50995114

5100-
/// Report errors if the provided parameters are too few or too many.
5101-
fn check_generic_arg_count(&self,
5102-
span: Span,
5103-
segment: &hir::PathSegment,
5104-
generics: &ty::Generics,
5105-
is_method_call: bool,
5106-
supress_mismatch_error: bool)
5107-
-> bool {
5108-
let mut supress_errors = false;
5109-
let (mut lifetimes, mut types) = (vec![], vec![]);
5110-
let infer_types = segment.infer_types;
5111-
let mut bindings = vec![];
5112-
if let Some(ref data) = segment.args {
5113-
data.args.iter().for_each(|arg| match arg {
5114-
GenericArg::Lifetime(lt) => lifetimes.push(lt.clone()),
5115-
GenericArg::Type(ty) => types.push(ty.clone()),
5116-
});
5117-
bindings = data.bindings.clone().to_vec();
5118-
}
5119-
5120-
struct ParamRange {
5121-
required: usize,
5122-
accepted: usize
5123-
};
5124-
5125-
let mut lt_accepted = 0;
5126-
let mut ty_params = ParamRange { required: 0, accepted: 0 };
5127-
for param in &generics.params {
5128-
match param.kind {
5129-
GenericParamDefKind::Lifetime => lt_accepted += 1,
5130-
GenericParamDefKind::Type { has_default, .. } => {
5131-
ty_params.accepted += 1;
5132-
if !has_default {
5133-
ty_params.required += 1;
5134-
}
5135-
}
5136-
};
5137-
}
5138-
if generics.parent.is_none() && generics.has_self {
5139-
ty_params.required -= 1;
5140-
ty_params.accepted -= 1;
5141-
}
5142-
let ty_accepted = ty_params.accepted;
5143-
let ty_required = ty_params.required;
5144-
5145-
let count_ty_params = |n| format!("{} type parameter{}", n, if n == 1 { "" } else { "s" });
5146-
let expected_text = count_ty_params(ty_accepted);
5147-
let actual_text = count_ty_params(types.len());
5148-
if let Some((mut err, span)) = if types.len() > ty_accepted {
5149-
// To prevent derived errors to accumulate due to extra
5150-
// type parameters, we force instantiate_value_path to
5151-
// use inference variables instead of the provided types.
5152-
supress_errors = true;
5153-
let span = types[ty_accepted].span;
5154-
Some((struct_span_err!(self.tcx.sess, span, E0087,
5155-
"too many type parameters provided: \
5156-
expected at most {}, found {}",
5157-
expected_text, actual_text), span))
5158-
} else if types.len() < ty_required && !infer_types && !supress_mismatch_error {
5159-
Some((struct_span_err!(self.tcx.sess, span, E0089,
5160-
"too few type parameters provided: \
5161-
expected {}, found {}",
5162-
expected_text, actual_text), span))
5163-
} else {
5164-
None
5165-
} {
5166-
self.set_tainted_by_errors(); // #53251
5167-
err.span_label(span, format!("expected {}", expected_text)).emit();
5168-
}
5169-
5170-
if !bindings.is_empty() {
5171-
AstConv::prohibit_assoc_ty_binding(self.tcx, bindings[0].span);
5172-
}
5173-
5174-
let infer_lifetimes = lifetimes.len() == 0;
5175-
// Prohibit explicit lifetime arguments if late bound lifetime parameters are present.
5176-
let has_late_bound_lifetime_defs = generics.has_late_bound_regions;
5177-
if let (Some(span_late), false) = (has_late_bound_lifetime_defs, lifetimes.is_empty()) {
5178-
// Report this as a lint only if no error was reported previously.
5179-
let primary_msg = "cannot specify lifetime arguments explicitly \
5180-
if late bound lifetime parameters are present";
5181-
let note_msg = "the late bound lifetime parameter is introduced here";
5182-
if !is_method_call && (lifetimes.len() > lt_accepted ||
5183-
lifetimes.len() < lt_accepted && !infer_lifetimes) {
5184-
supress_errors = true;
5185-
let mut err = self.tcx.sess.struct_span_err(lifetimes[0].span, primary_msg);
5186-
err.span_note(span_late, note_msg);
5187-
err.emit();
5188-
} else {
5189-
let mut multispan = MultiSpan::from_span(lifetimes[0].span);
5190-
multispan.push_span_label(span_late, note_msg.to_string());
5191-
self.tcx.lint_node(lint::builtin::LATE_BOUND_LIFETIME_ARGUMENTS,
5192-
lifetimes[0].id, multispan, primary_msg);
5193-
}
5194-
return supress_errors;
5195-
}
5196-
5197-
let count_lifetime_params = |n| {
5198-
format!("{} lifetime parameter{}", n, if n == 1 { "" } else { "s" })
5199-
};
5200-
let expected_text = count_lifetime_params(lt_accepted);
5201-
let actual_text = count_lifetime_params(lifetimes.len());
5202-
if let Some((mut err, span)) = if lifetimes.len() > lt_accepted {
5203-
let span = lifetimes[lt_accepted].span;
5204-
Some((struct_span_err!(self.tcx.sess, span, E0088,
5205-
"too many lifetime parameters provided: \
5206-
expected at most {}, found {}",
5207-
expected_text, actual_text), span))
5208-
} else if lifetimes.len() < lt_accepted && !infer_lifetimes {
5209-
Some((struct_span_err!(self.tcx.sess, span, E0090,
5210-
"too few lifetime parameters provided: \
5211-
expected {}, found {}",
5212-
expected_text, actual_text), span))
5213-
} else {
5214-
None
5215-
} {
5216-
err.span_label(span, format!("expected {}", expected_text)).emit();
5217-
}
5218-
5219-
supress_errors
5220-
}
5221-
52225115
/// Report error if there is an explicit type parameter when using `impl Trait`.
52235116
fn check_impl_trait(&self,
52245117
span: Span,

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ fn foo() {}
1212
fn bar<T>() {}
1313

1414
fn main() {
15-
foo::<f64>(); //~ ERROR expected at most 0 type parameters, found 1 type parameter [E0087]
15+
foo::<f64>(); //~ ERROR wrong number of type arguments: expected 0, found 1 [E0087]
1616

17-
bar::<f64, u64>(); //~ ERROR expected at most 1 type parameter, found 2 type parameters [E0087]
17+
bar::<f64, u64>(); //~ ERROR wrong number of type arguments: expected 1, found 2 [E0087]
1818
}

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

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1-
error[E0087]: too many type parameters provided: expected at most 0 type parameters, found 1 type parameter
2-
--> $DIR/E0087.rs:15:11
1+
error[E0087]: wrong number of type arguments: expected 0, found 1
2+
--> $DIR/E0087.rs:15:5
33
|
4-
LL | foo::<f64>(); //~ ERROR expected at most 0 type parameters, found 1 type parameter [E0087]
5-
| ^^^ expected 0 type parameters
4+
LL | foo::<f64>(); //~ ERROR wrong number of type arguments: expected 0, found 1 [E0087]
5+
| ^^^^^^^^^^ unexpected type argument
66

7-
error[E0087]: too many type parameters provided: expected at most 1 type parameter, found 2 type parameters
8-
--> $DIR/E0087.rs:17:16
7+
error[E0087]: wrong number of type arguments: expected 1, found 2
8+
--> $DIR/E0087.rs:17:5
99
|
10-
LL | bar::<f64, u64>(); //~ ERROR expected at most 1 type parameter, found 2 type parameters [E0087]
11-
| ^^^ expected 1 type parameter
10+
LL | bar::<f64, u64>(); //~ ERROR wrong number of type arguments: expected 1, found 2 [E0087]
11+
| ^^^^^^^^^^^^^^^ unexpected type argument
1212

1313
error: aborting due to 2 previous errors
1414

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1-
error[E0088]: too many lifetime parameters provided: expected at most 0 lifetime parameters, found 1 lifetime parameter
2-
--> $DIR/E0088.rs:15:9
1+
error[E0088]: wrong number of lifetime arguments: expected 0, found 1
2+
--> $DIR/E0088.rs:15:5
33
|
44
LL | f::<'static>(); //~ ERROR E0088
5-
| ^^^^^^^ expected 0 lifetime parameters
5+
| ^^^^^^^^^^^^ unexpected lifetime argument
66

7-
error[E0088]: too many lifetime parameters provided: expected at most 1 lifetime parameter, found 2 lifetime parameters
8-
--> $DIR/E0088.rs:16:18
7+
error[E0088]: wrong number of lifetime arguments: expected 1, found 2
8+
--> $DIR/E0088.rs:16:5
99
|
1010
LL | g::<'static, 'static>(); //~ ERROR E0088
11-
| ^^^^^^^ expected 1 lifetime parameter
11+
| ^^^^^^^^^^^^^^^^^^^^^ unexpected lifetime argument
1212

1313
error: aborting due to 2 previous errors
1414

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,5 @@
1111
fn foo<T, U>() {}
1212

1313
fn main() {
14-
foo::<f64>(); //~ ERROR expected 2 type parameters, found 1 type parameter [E0089]
14+
foo::<f64>(); //~ ERROR wrong number of type arguments: expected 2, found 1 [E0089]
1515
}

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error[E0089]: too few type parameters provided: expected 2 type parameters, found 1 type parameter
1+
error[E0089]: wrong number of type arguments: expected 2, found 1
22
--> $DIR/E0089.rs:14:5
33
|
4-
LL | foo::<f64>(); //~ ERROR expected 2 type parameters, found 1 type parameter [E0089]
5-
| ^^^^^^^^^^ expected 2 type parameters
4+
LL | foo::<f64>(); //~ ERROR wrong number of type arguments: expected 2, found 1 [E0089]
5+
| ^^^^^^^^^^ expected 2 type arguments
66

77
error: aborting due to previous error
88

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,5 @@
1111
fn foo<'a: 'b, 'b: 'a>() {}
1212

1313
fn main() {
14-
foo::<'static>(); //~ ERROR expected 2 lifetime parameters, found 1 lifetime parameter [E0090]
14+
foo::<'static>(); //~ ERROR wrong number of lifetime arguments: expected 2, found 1 [E0090]
1515
}

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error[E0090]: too few lifetime parameters provided: expected 2 lifetime parameters, found 1 lifetime parameter
1+
error[E0090]: wrong number of lifetime arguments: expected 2, found 1
22
--> $DIR/E0090.rs:14:5
33
|
4-
LL | foo::<'static>(); //~ ERROR expected 2 lifetime parameters, found 1 lifetime parameter [E0090]
5-
| ^^^^^^^^^^^^^^ expected 2 lifetime parameters
4+
LL | foo::<'static>(); //~ ERROR wrong number of lifetime arguments: expected 2, found 1 [E0090]
5+
| ^^^^^^^^^^^^^^ expected 2 lifetime arguments
66

77
error: aborting due to previous error
88

0 commit comments

Comments
 (0)