diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 2e59c5959fbe..3cd435e756e4 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -90,6 +90,11 @@ struct ConvertedBinding<'tcx> { span: Span, } +pub struct GenericArgMismatchErrorCode { + pub lifetimes: (&'static str, &'static str), + pub types: (&'static str, &'static str), +} + /// Dummy type used for the `Self` of a `TraitRef` created for converting /// a trait object, and which gets removed in `ExistentialTraitRef`. /// This type must not appear anywhere in other converted types. @@ -199,6 +204,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { is_method_call: bool, has_self: bool, infer_types: bool, + error_codes: GenericArgMismatchErrorCode, ) -> bool { // At this stage we are guaranteed that the generic arguments are in the correct order, e.g. // 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 { } } - let check_kind_count = |error_code_less: &str, - error_code_more: &str, + let check_kind_count = |error_code: (&str, &str), kind, required, permitted, @@ -296,9 +301,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { ), DiagnosticId::Error({ if provided <= permitted { - error_code_less + error_code.0 } else { - error_code_more + error_code.1 } }.into()) ).span_label(span, label).emit(); @@ -308,8 +313,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { if !infer_lifetimes || arg_counts.lifetimes > param_counts.lifetimes { check_kind_count( - "E0107", - "E0107", + error_codes.lifetimes, "lifetime", param_counts.lifetimes, param_counts.lifetimes, @@ -319,8 +323,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { if !infer_types || arg_counts.types > param_counts.types - defaults.types - has_self as usize { check_kind_count( - "E0243", - "E0244", // FIXME: E0243 and E0244 should be unified. + error_codes.types, "type", param_counts.types - defaults.types - has_self as usize, param_counts.types - has_self as usize, @@ -508,6 +511,10 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { false, // `is_method_call` (irrelevant here) has_self, infer_types, + GenericArgMismatchErrorCode { + lifetimes: ("E0107", "E0107"), + types: ("E0243", "E0244"), // FIXME: E0243 and E0244 should be unified. + }, ); let is_object = self_ty.map_or(false, |ty| ty.sty == TRAIT_OBJECT_DUMMY_SELF); diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 49225680432d..88c540915af0 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -10,7 +10,7 @@ use super::{probe, MethodCallee}; -use astconv::AstConv; +use astconv::{AstConv, GenericArgMismatchErrorCode}; use check::{FnCtxt, PlaceOp, callee, Needs}; use hir::GenericArg; use hir::def_id::DefId; @@ -329,9 +329,11 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { true, // `is_method_call` method_generics.parent.is_none() && method_generics.has_self, segment.infer_types || suppress_mismatch, + GenericArgMismatchErrorCode { + lifetimes: ("E0090", "E0088"), + types: ("E0089", "E0087"), + }, ); - // self.fcx.check_generic_arg_count(self.span, &segment, &method_generics, true, - // supress_mismatch); // Create subst for early-bound lifetime parameters, combining // parameters from the type and those from the method. diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index ae5c0fc6fb14..17adfda0bac0 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -84,9 +84,10 @@ pub use self::compare_method::{compare_impl_method, compare_const_impl}; use self::method::MethodCallee; use self::TupleArgumentsFlag::*; -use astconv::AstConv; +use astconv::{AstConv, GenericArgMismatchErrorCode}; use hir::GenericArg; use hir::def::Def; +use hir::HirVec; use hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use std::slice; use namespace::Namespace; @@ -4937,16 +4938,30 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // to add defaults. If the user provided *too many* types, that's // a problem. - let mut supress_errors = FxHashMap(); + let mut suppress_errors = FxHashMap(); for &PathSeg(def_id, index) in &path_segs { let seg = &segments[index]; let generics = self.tcx.generics_of(def_id); // `impl Trait` is treated as a normal generic parameter internally, // but we don't allow users to specify the parameter's value // explicitly, so we have to do some error-checking here. - let supress_mismatch = self.check_impl_trait(span, seg, &generics); - supress_errors.insert(index, - self.check_generic_arg_count(span, seg, &generics, false, supress_mismatch)); + let suppress_mismatch = self.check_impl_trait(span, seg, &generics); + suppress_errors.insert(index, AstConv::check_generic_arg_count( + self.tcx, + span, + &generics, + &seg.args.clone().unwrap_or_else(|| P(hir::GenericArgs { + args: HirVec::new(), bindings: HirVec::new(), parenthesized: false, + })), + false, // `is_declaration` + false, // `is_method_call` + generics.parent.is_none() && generics.has_self, + seg.infer_types || suppress_mismatch, + GenericArgMismatchErrorCode { + lifetimes: ("E0090", "E0088"), // FIXME: E0090 and E0088 should be unified. + types: ("E0089", "E0087"), // FIXME: E0089 and E0087 should be unified. + }, + )); } let has_self = path_segs.last().map(|PathSeg(def_id, _)| { @@ -4968,7 +4983,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }) { // If we've encountered an `impl Trait`-related error, we're just // going to infer the arguments for better error messages. - if !supress_errors[&index] { + if !suppress_errors[&index] { // Check whether the user has provided generic arguments. if let Some(ref data) = segments[index].args { return (Some(data), segments[index].infer_types); @@ -5097,128 +5112,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { directly, not through a function pointer"); } - /// Report errors if the provided parameters are too few or too many. - fn check_generic_arg_count(&self, - span: Span, - segment: &hir::PathSegment, - generics: &ty::Generics, - is_method_call: bool, - supress_mismatch_error: bool) - -> bool { - let mut supress_errors = false; - let (mut lifetimes, mut types) = (vec![], vec![]); - let infer_types = segment.infer_types; - let mut bindings = vec![]; - if let Some(ref data) = segment.args { - data.args.iter().for_each(|arg| match arg { - GenericArg::Lifetime(lt) => lifetimes.push(lt.clone()), - GenericArg::Type(ty) => types.push(ty.clone()), - }); - bindings = data.bindings.clone().to_vec(); - } - - struct ParamRange { - required: usize, - accepted: usize - }; - - let mut lt_accepted = 0; - let mut ty_params = ParamRange { required: 0, accepted: 0 }; - for param in &generics.params { - match param.kind { - GenericParamDefKind::Lifetime => lt_accepted += 1, - GenericParamDefKind::Type { has_default, .. } => { - ty_params.accepted += 1; - if !has_default { - ty_params.required += 1; - } - } - }; - } - if generics.parent.is_none() && generics.has_self { - ty_params.required -= 1; - ty_params.accepted -= 1; - } - let ty_accepted = ty_params.accepted; - let ty_required = ty_params.required; - - let count_ty_params = |n| format!("{} type parameter{}", n, if n == 1 { "" } else { "s" }); - let expected_text = count_ty_params(ty_accepted); - let actual_text = count_ty_params(types.len()); - if let Some((mut err, span)) = if types.len() > ty_accepted { - // To prevent derived errors to accumulate due to extra - // type parameters, we force instantiate_value_path to - // use inference variables instead of the provided types. - supress_errors = true; - let span = types[ty_accepted].span; - Some((struct_span_err!(self.tcx.sess, span, E0087, - "too many type parameters provided: \ - expected at most {}, found {}", - expected_text, actual_text), span)) - } else if types.len() < ty_required && !infer_types && !supress_mismatch_error { - Some((struct_span_err!(self.tcx.sess, span, E0089, - "too few type parameters provided: \ - expected {}, found {}", - expected_text, actual_text), span)) - } else { - None - } { - self.set_tainted_by_errors(); // #53251 - err.span_label(span, format!("expected {}", expected_text)).emit(); - } - - if !bindings.is_empty() { - AstConv::prohibit_assoc_ty_binding(self.tcx, bindings[0].span); - } - - let infer_lifetimes = lifetimes.len() == 0; - // Prohibit explicit lifetime arguments if late bound lifetime parameters are present. - let has_late_bound_lifetime_defs = generics.has_late_bound_regions; - if let (Some(span_late), false) = (has_late_bound_lifetime_defs, lifetimes.is_empty()) { - // Report this as a lint only if no error was reported previously. - let primary_msg = "cannot specify lifetime arguments explicitly \ - if late bound lifetime parameters are present"; - let note_msg = "the late bound lifetime parameter is introduced here"; - if !is_method_call && (lifetimes.len() > lt_accepted || - lifetimes.len() < lt_accepted && !infer_lifetimes) { - supress_errors = true; - let mut err = self.tcx.sess.struct_span_err(lifetimes[0].span, primary_msg); - err.span_note(span_late, note_msg); - err.emit(); - } else { - let mut multispan = MultiSpan::from_span(lifetimes[0].span); - multispan.push_span_label(span_late, note_msg.to_string()); - self.tcx.lint_node(lint::builtin::LATE_BOUND_LIFETIME_ARGUMENTS, - lifetimes[0].id, multispan, primary_msg); - } - return supress_errors; - } - - let count_lifetime_params = |n| { - format!("{} lifetime parameter{}", n, if n == 1 { "" } else { "s" }) - }; - let expected_text = count_lifetime_params(lt_accepted); - let actual_text = count_lifetime_params(lifetimes.len()); - if let Some((mut err, span)) = if lifetimes.len() > lt_accepted { - let span = lifetimes[lt_accepted].span; - Some((struct_span_err!(self.tcx.sess, span, E0088, - "too many lifetime parameters provided: \ - expected at most {}, found {}", - expected_text, actual_text), span)) - } else if lifetimes.len() < lt_accepted && !infer_lifetimes { - Some((struct_span_err!(self.tcx.sess, span, E0090, - "too few lifetime parameters provided: \ - expected {}, found {}", - expected_text, actual_text), span)) - } else { - None - } { - err.span_label(span, format!("expected {}", expected_text)).emit(); - } - - supress_errors - } - /// Report error if there is an explicit type parameter when using `impl Trait`. fn check_impl_trait(&self, span: Span, diff --git a/src/test/ui/error-codes/E0087.rs b/src/test/ui/error-codes/E0087.rs index 6dc08860614d..bea76f34220e 100644 --- a/src/test/ui/error-codes/E0087.rs +++ b/src/test/ui/error-codes/E0087.rs @@ -12,7 +12,7 @@ fn foo() {} fn bar() {} fn main() { - foo::(); //~ ERROR expected at most 0 type parameters, found 1 type parameter [E0087] + foo::(); //~ ERROR wrong number of type arguments: expected 0, found 1 [E0087] - bar::(); //~ ERROR expected at most 1 type parameter, found 2 type parameters [E0087] + bar::(); //~ ERROR wrong number of type arguments: expected 1, found 2 [E0087] } diff --git a/src/test/ui/error-codes/E0087.stderr b/src/test/ui/error-codes/E0087.stderr index cd1e99e7b411..7170a6f2cda1 100644 --- a/src/test/ui/error-codes/E0087.stderr +++ b/src/test/ui/error-codes/E0087.stderr @@ -1,14 +1,14 @@ -error[E0087]: too many type parameters provided: expected at most 0 type parameters, found 1 type parameter - --> $DIR/E0087.rs:15:11 +error[E0087]: wrong number of type arguments: expected 0, found 1 + --> $DIR/E0087.rs:15:5 | -LL | foo::(); //~ ERROR expected at most 0 type parameters, found 1 type parameter [E0087] - | ^^^ expected 0 type parameters +LL | foo::(); //~ ERROR wrong number of type arguments: expected 0, found 1 [E0087] + | ^^^^^^^^^^ unexpected type argument -error[E0087]: too many type parameters provided: expected at most 1 type parameter, found 2 type parameters - --> $DIR/E0087.rs:17:16 +error[E0087]: wrong number of type arguments: expected 1, found 2 + --> $DIR/E0087.rs:17:5 | -LL | bar::(); //~ ERROR expected at most 1 type parameter, found 2 type parameters [E0087] - | ^^^ expected 1 type parameter +LL | bar::(); //~ ERROR wrong number of type arguments: expected 1, found 2 [E0087] + | ^^^^^^^^^^^^^^^ unexpected type argument error: aborting due to 2 previous errors diff --git a/src/test/ui/error-codes/E0088.stderr b/src/test/ui/error-codes/E0088.stderr index 4bf2760994eb..4666702e1ebf 100644 --- a/src/test/ui/error-codes/E0088.stderr +++ b/src/test/ui/error-codes/E0088.stderr @@ -1,14 +1,14 @@ -error[E0088]: too many lifetime parameters provided: expected at most 0 lifetime parameters, found 1 lifetime parameter - --> $DIR/E0088.rs:15:9 +error[E0088]: wrong number of lifetime arguments: expected 0, found 1 + --> $DIR/E0088.rs:15:5 | LL | f::<'static>(); //~ ERROR E0088 - | ^^^^^^^ expected 0 lifetime parameters + | ^^^^^^^^^^^^ unexpected lifetime argument -error[E0088]: too many lifetime parameters provided: expected at most 1 lifetime parameter, found 2 lifetime parameters - --> $DIR/E0088.rs:16:18 +error[E0088]: wrong number of lifetime arguments: expected 1, found 2 + --> $DIR/E0088.rs:16:5 | LL | g::<'static, 'static>(); //~ ERROR E0088 - | ^^^^^^^ expected 1 lifetime parameter + | ^^^^^^^^^^^^^^^^^^^^^ unexpected lifetime argument error: aborting due to 2 previous errors diff --git a/src/test/ui/error-codes/E0089.rs b/src/test/ui/error-codes/E0089.rs index 21df9abd0932..4e6196a7b89d 100644 --- a/src/test/ui/error-codes/E0089.rs +++ b/src/test/ui/error-codes/E0089.rs @@ -11,5 +11,5 @@ fn foo() {} fn main() { - foo::(); //~ ERROR expected 2 type parameters, found 1 type parameter [E0089] + foo::(); //~ ERROR wrong number of type arguments: expected 2, found 1 [E0089] } diff --git a/src/test/ui/error-codes/E0089.stderr b/src/test/ui/error-codes/E0089.stderr index 0b95033fb360..f79c478b733f 100644 --- a/src/test/ui/error-codes/E0089.stderr +++ b/src/test/ui/error-codes/E0089.stderr @@ -1,8 +1,8 @@ -error[E0089]: too few type parameters provided: expected 2 type parameters, found 1 type parameter +error[E0089]: wrong number of type arguments: expected 2, found 1 --> $DIR/E0089.rs:14:5 | -LL | foo::(); //~ ERROR expected 2 type parameters, found 1 type parameter [E0089] - | ^^^^^^^^^^ expected 2 type parameters +LL | foo::(); //~ ERROR wrong number of type arguments: expected 2, found 1 [E0089] + | ^^^^^^^^^^ expected 2 type arguments error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0090.rs b/src/test/ui/error-codes/E0090.rs index 13b2131cc8be..26be4c12f075 100644 --- a/src/test/ui/error-codes/E0090.rs +++ b/src/test/ui/error-codes/E0090.rs @@ -11,5 +11,5 @@ fn foo<'a: 'b, 'b: 'a>() {} fn main() { - foo::<'static>(); //~ ERROR expected 2 lifetime parameters, found 1 lifetime parameter [E0090] + foo::<'static>(); //~ ERROR wrong number of lifetime arguments: expected 2, found 1 [E0090] } diff --git a/src/test/ui/error-codes/E0090.stderr b/src/test/ui/error-codes/E0090.stderr index f119d5fa4671..9029b6c2708b 100644 --- a/src/test/ui/error-codes/E0090.stderr +++ b/src/test/ui/error-codes/E0090.stderr @@ -1,8 +1,8 @@ -error[E0090]: too few lifetime parameters provided: expected 2 lifetime parameters, found 1 lifetime parameter +error[E0090]: wrong number of lifetime arguments: expected 2, found 1 --> $DIR/E0090.rs:14:5 | -LL | foo::<'static>(); //~ ERROR expected 2 lifetime parameters, found 1 lifetime parameter [E0090] - | ^^^^^^^^^^^^^^ expected 2 lifetime parameters +LL | foo::<'static>(); //~ ERROR wrong number of lifetime arguments: expected 2, found 1 [E0090] + | ^^^^^^^^^^^^^^ expected 2 lifetime arguments error: aborting due to previous error