From 2a504878c3d1f80581e6b202490e10fe199914da Mon Sep 17 00:00:00 2001 From: varkor Date: Mon, 20 Jan 2020 22:16:42 +0000 Subject: [PATCH 01/12] Return whether `check_generic_arg_count` finds an error --- src/librustc_typeck/astconv.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 78c05a51e4fbd..599fb7c57f794 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -402,10 +402,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } err.emit(); - ( - provided > required, // `suppress_error` - potential_assoc_types, - ) + (true, potential_assoc_types) }; if reported_late_bound_region_err.is_none() From d232acdb398c5837f2c95ffe6c38970059451445 Mon Sep 17 00:00:00 2001 From: varkor Date: Mon, 20 Jan 2020 23:59:17 +0000 Subject: [PATCH 02/12] Report all errors in `check_generic_arg_count` --- src/librustc_typeck/astconv.rs | 147 +++++++++--------- .../generic/generic-arg-mismatch-recover.rs | 1 - .../generic-arg-mismatch-recover.stderr | 18 +-- 3 files changed, 81 insertions(+), 85 deletions(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 599fb7c57f794..5c9178ff66d15 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -287,7 +287,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { position: GenericArgPosition, has_self: bool, infer_args: bool, - ) -> (bool, Option>) { + ) -> (bool, Vec) { // 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 // arguments in order to validate them with respect to the generic parameters. @@ -341,104 +341,110 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } } - let check_kind_count = |kind, required, permitted, provided, offset| { - debug!( - "check_kind_count: kind: {} required: {} permitted: {} provided: {} offset: {}", - kind, required, permitted, provided, offset - ); - // We enforce the following: `required` <= `provided` <= `permitted`. - // For kinds without defaults (e.g.., lifetimes), `required == permitted`. - // For other kinds (i.e., types), `permitted` may be greater than `required`. - if required <= provided && provided <= permitted { - return (reported_late_bound_region_err.unwrap_or(false), None); - } - - // Unfortunately lifetime and type parameter mismatches are typically styled - // differently in diagnostics, which means we have a few cases to consider here. - let (bound, quantifier) = if required != permitted { - if provided < required { - (required, "at least ") - } else { - // provided > permitted - (permitted, "at most ") + let check_kind_count = + |kind, required, permitted, provided, offset, unexpected_spans: &mut Vec| { + debug!( + "check_kind_count: kind: {} required: {} permitted: {} provided: {} offset: {}", + kind, required, permitted, provided, offset + ); + // We enforce the following: `required` <= `provided` <= `permitted`. + // For kinds without defaults (e.g.., lifetimes), `required == permitted`. + // For other kinds (i.e., types), `permitted` may be greater than `required`. + if required <= provided && provided <= permitted { + return false; } - } else { - (required, "") - }; - let mut potential_assoc_types: Option> = None; - let (spans, label) = if required == permitted && provided > permitted { - // In the case when the user has provided too many arguments, - // we want to point to the unexpected arguments. - let spans: Vec = args.args[offset + permitted..offset + provided] - .iter() - .map(|arg| arg.span()) - .collect(); - potential_assoc_types = Some(spans.clone()); - (spans, format!("unexpected {} argument", kind)) - } else { - ( - vec![span], - format!( - "expected {}{} {} argument{}", - quantifier, - bound, - kind, - pluralize!(bound), + // Unfortunately lifetime and type parameter mismatches are typically styled + // differently in diagnostics, which means we have a few cases to consider here. + let (bound, quantifier) = if required != permitted { + if provided < required { + (required, "at least ") + } else { + // provided > permitted + (permitted, "at most ") + } + } else { + (required, "") + }; + + let (spans, label) = if required == permitted && provided > permitted { + // In the case when the user has provided too many arguments, + // we want to point to the unexpected arguments. + let spans: Vec = args.args[offset + permitted..offset + provided] + .iter() + .map(|arg| arg.span()) + .collect(); + unexpected_spans.extend(spans.clone()); + (spans, format!("unexpected {} argument", kind)) + } else { + ( + vec![span], + format!( + "expected {}{} {} argument{}", + quantifier, + bound, + kind, + pluralize!(bound), + ), + ) + }; + + let mut err = tcx.sess.struct_span_err_with_code( + spans.clone(), + &format!( + "wrong number of {} arguments: expected {}{}, found {}", + kind, quantifier, bound, provided, ), - ) - }; + DiagnosticId::Error("E0107".into()), + ); + for span in spans { + err.span_label(span, label.as_str()); + } + err.emit(); - let mut err = tcx.sess.struct_span_err_with_code( - spans.clone(), - &format!( - "wrong number of {} arguments: expected {}{}, found {}", - kind, quantifier, bound, provided, - ), - DiagnosticId::Error("E0107".into()), - ); - for span in spans { - err.span_label(span, label.as_str()); - } - err.emit(); + true + }; - (true, potential_assoc_types) - }; + let mut arg_count_mismatch = reported_late_bound_region_err.unwrap_or(false); + let mut unexpected_spans = vec![]; if reported_late_bound_region_err.is_none() && (!infer_lifetimes || arg_counts.lifetimes > param_counts.lifetimes) { - check_kind_count( + arg_count_mismatch |= check_kind_count( "lifetime", param_counts.lifetimes, param_counts.lifetimes, arg_counts.lifetimes, 0, + &mut unexpected_spans, ); } // FIXME(const_generics:defaults) if !infer_args || arg_counts.consts > param_counts.consts { - check_kind_count( + arg_count_mismatch |= check_kind_count( "const", param_counts.consts, param_counts.consts, arg_counts.consts, arg_counts.lifetimes + arg_counts.types, + &mut unexpected_spans, ); } // Note that type errors are currently be emitted *after* const errors. if !infer_args || arg_counts.types > param_counts.types - defaults.types - has_self as usize { - check_kind_count( + arg_count_mismatch |= check_kind_count( "type", param_counts.types - defaults.types - has_self as usize, param_counts.types - has_self as usize, arg_counts.types, arg_counts.lifetimes, - ) - } else { - (reported_late_bound_region_err.unwrap_or(false), None) + &mut unexpected_spans, + ); } + + (arg_count_mismatch, unexpected_spans) } /// Creates the relevant generic argument substitutions @@ -627,7 +633,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { generic_args: &'a hir::GenericArgs<'_>, infer_args: bool, self_ty: Option>, - ) -> (SubstsRef<'tcx>, Vec>, Option>) { + ) -> (SubstsRef<'tcx>, Vec>, Vec) { // If the type is parameterized by this region, then replace this // region with the current anon region binding (in other words, // whatever & would get replaced with). @@ -922,7 +928,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self_ty: Ty<'tcx>, bounds: &mut Bounds<'tcx>, speculative: bool, - ) -> Option> { + ) -> Vec { let trait_def_id = trait_ref.trait_def_id(); debug!("instantiate_poly_trait_ref({:?}, def_id={:?})", trait_ref, trait_def_id); @@ -968,6 +974,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { "instantiate_poly_trait_ref({:?}, bounds={:?}) -> {:?}", trait_ref, bounds, poly_trait_ref ); + potential_assoc_types } @@ -996,7 +1003,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { constness: Constness, self_ty: Ty<'tcx>, bounds: &mut Bounds<'tcx>, - ) -> Option> { + ) -> Vec { self.instantiate_poly_trait_ref_inner( &poly_trait_ref.trait_ref, poly_trait_ref.span, @@ -1085,7 +1092,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { trait_def_id: DefId, self_ty: Ty<'tcx>, trait_segment: &'a hir::PathSegment<'a>, - ) -> (SubstsRef<'tcx>, Vec>, Option>) { + ) -> (SubstsRef<'tcx>, Vec>, Vec) { debug!("create_substs_for_ast_trait_ref(trait_segment={:?})", trait_segment); self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment); @@ -1436,7 +1443,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { dummy_self, &mut bounds, ); - potential_assoc_types.extend(cur_potential_assoc_types.into_iter().flatten()); + potential_assoc_types.extend(cur_potential_assoc_types.into_iter()); } // Expand trait aliases recursively and check that only one regular (non-auto) trait diff --git a/src/test/ui/generic/generic-arg-mismatch-recover.rs b/src/test/ui/generic/generic-arg-mismatch-recover.rs index f4e15fbebcebb..3e5e2e601f5c4 100644 --- a/src/test/ui/generic/generic-arg-mismatch-recover.rs +++ b/src/test/ui/generic/generic-arg-mismatch-recover.rs @@ -4,7 +4,6 @@ struct Bar<'a>(&'a ()); fn main() { Foo::<'static, 'static, ()>(&0); //~ ERROR wrong number of lifetime arguments - //~^ ERROR mismatched types Bar::<'static, 'static, ()>(&()); //~ ERROR wrong number of lifetime arguments //~^ ERROR wrong number of type arguments diff --git a/src/test/ui/generic/generic-arg-mismatch-recover.stderr b/src/test/ui/generic/generic-arg-mismatch-recover.stderr index 4b86212e4862b..99adb35268527 100644 --- a/src/test/ui/generic/generic-arg-mismatch-recover.stderr +++ b/src/test/ui/generic/generic-arg-mismatch-recover.stderr @@ -4,28 +4,18 @@ error[E0107]: wrong number of lifetime arguments: expected 1, found 2 LL | Foo::<'static, 'static, ()>(&0); | ^^^^^^^ unexpected lifetime argument -error[E0308]: mismatched types - --> $DIR/generic-arg-mismatch-recover.rs:6:33 - | -LL | Foo::<'static, 'static, ()>(&0); - | ^^ expected `()`, found integer - | - = note: expected reference `&'static ()` - found reference `&{integer}` - error[E0107]: wrong number of lifetime arguments: expected 1, found 2 - --> $DIR/generic-arg-mismatch-recover.rs:9:20 + --> $DIR/generic-arg-mismatch-recover.rs:8:20 | LL | Bar::<'static, 'static, ()>(&()); | ^^^^^^^ unexpected lifetime argument error[E0107]: wrong number of type arguments: expected 0, found 1 - --> $DIR/generic-arg-mismatch-recover.rs:9:29 + --> $DIR/generic-arg-mismatch-recover.rs:8:29 | LL | Bar::<'static, 'static, ()>(&()); | ^^ unexpected type argument -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors -Some errors have detailed explanations: E0107, E0308. -For more information about an error, try `rustc --explain E0107`. +For more information about this error, try `rustc --explain E0107`. From 9939de24ac3580acfb92670f9bd568f90052340b Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 21 Jan 2020 20:46:21 +0000 Subject: [PATCH 03/12] Correct passing of `generic_args` to `create_substs_for_generic_args` --- src/librustc_typeck/astconv.rs | 9 ++++++++- src/librustc_typeck/check/method/confirm.rs | 11 ++++++++--- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 5c9178ff66d15..a1440c3e2895c 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -693,7 +693,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self_ty.is_some(), self_ty, // Provide the generic args, and whether types should be inferred. - |_| (Some(generic_args), infer_args), + |did| { + if did == def_id { + (Some(generic_args), infer_args) + } else { + // The last component of this tuple is unimportant. + (None, false) + } + }, // Provide substitutions for parameters for which (valid) arguments have been provided. |param, arg| match (¶m.kind, arg) { (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => { diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 17842be9a4392..04cbee8c94061 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -314,9 +314,14 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { false, None, // Provide the generic args, and whether types should be inferred. - |_| { - // The last argument of the returned tuple here is unimportant. - if let Some(ref data) = seg.args { (Some(data), false) } else { (None, false) } + |def_id| { + // The last component of the returned tuple here is unimportant. + if def_id == pick.item.def_id { + if let Some(ref data) = seg.args { + return (Some(data), false); + } + } + (None, false) }, // Provide substitutions for parameters for which (valid) arguments have been provided. |param, arg| match (¶m.kind, arg) { From 750e673491114cd8454f1715ce1fda8dd02b7ac0 Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 21 Jan 2020 22:36:17 +0000 Subject: [PATCH 04/12] Report late-bound region lint as error in `check_generic_arg_count` --- src/librustc_typeck/astconv.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index a1440c3e2895c..1e5e00445ccca 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -313,9 +313,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } // Prohibit explicit lifetime arguments if late-bound lifetime parameters are present. - let mut reported_late_bound_region_err = None; + let mut reported_late_bound_region_err = false; if !infer_lifetimes { if let Some(span_late) = def.has_late_bound_regions { + reported_late_bound_region_err = true; let msg = "cannot specify lifetime arguments explicitly \ if late bound lifetime parameters are present"; let note = "the late bound lifetime parameter is introduced here"; @@ -326,7 +327,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let mut err = tcx.sess.struct_span_err(span, msg); err.span_note(span_late, note); err.emit(); - reported_late_bound_region_err = Some(true); } else { let mut multispan = MultiSpan::from_span(span); multispan.push_span_label(span_late, note.to_string()); @@ -336,7 +336,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { multispan, |lint| lint.build(msg).emit(), ); - reported_late_bound_region_err = Some(false); } } } @@ -405,10 +404,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { true }; - let mut arg_count_mismatch = reported_late_bound_region_err.unwrap_or(false); + let mut arg_count_mismatch = reported_late_bound_region_err; let mut unexpected_spans = vec![]; - if reported_late_bound_region_err.is_none() + if !reported_late_bound_region_err && (!infer_lifetimes || arg_counts.lifetimes > param_counts.lifetimes) { arg_count_mismatch |= check_kind_count( From 039045c49bec06f3a42aed90d3bc94520d92514e Mon Sep 17 00:00:00 2001 From: varkor Date: Tue, 21 Jan 2020 23:07:07 +0000 Subject: [PATCH 05/12] Move generic arg / param validation to `create_substs_for_generic_args` --- src/librustc_ast_passes/ast_validation.rs | 80 ++++-------------- src/librustc_error_codes/error_codes.rs | 1 + src/librustc_error_codes/error_codes/E0747.md | 10 +++ src/librustc_typeck/astconv.rs | 83 ++++++++++++++++--- src/librustc_typeck/check/method/confirm.rs | 3 +- src/librustc_typeck/check/mod.rs | 1 + src/librustc_typeck/collect.rs | 2 +- .../const-arg-type-arg-misordered.rs | 10 +++ .../const-arg-type-arg-misordered.stderr | 17 ++++ .../const-param-after-const-literal-arg.rs | 10 +++ ...const-param-after-const-literal-arg.stderr | 8 ++ .../const-param-before-other-params.rs | 1 + .../const-param-before-other-params.stderr | 12 ++- src/test/ui/parser/issue-14303-fncall.rs | 2 +- src/test/ui/parser/issue-14303-fncall.stderr | 7 +- src/test/ui/parser/issue-14303-path.rs | 2 +- src/test/ui/parser/issue-14303-path.stderr | 7 +- src/test/ui/suggestions/suggest-move-types.rs | 8 +- .../ui/suggestions/suggest-move-types.stderr | 21 ++--- .../ui/traits/trait-object-vs-lifetime.rs | 2 +- .../ui/traits/trait-object-vs-lifetime.stderr | 15 ++-- 21 files changed, 192 insertions(+), 110 deletions(-) create mode 100644 src/librustc_error_codes/error_codes/E0747.md create mode 100644 src/test/ui/const-generics/const-arg-type-arg-misordered.rs create mode 100644 src/test/ui/const-generics/const-arg-type-arg-misordered.stderr create mode 100644 src/test/ui/const-generics/const-param-after-const-literal-arg.rs create mode 100644 src/test/ui/const-generics/const-param-after-const-literal-arg.stderr diff --git a/src/librustc_ast_passes/ast_validation.rs b/src/librustc_ast_passes/ast_validation.rs index 1194269e0ee96..d55efeda3c14a 100644 --- a/src/librustc_ast_passes/ast_validation.rs +++ b/src/librustc_ast_passes/ast_validation.rs @@ -594,23 +594,15 @@ impl<'a> AstValidator<'a> { } } -enum GenericPosition { - Param, - Arg, -} - -fn validate_generics_order<'a>( +fn validate_generic_param_order<'a>( sess: &Session, handler: &rustc_errors::Handler, generics: impl Iterator, Span, Option)>, - pos: GenericPosition, span: Span, ) { let mut max_param: Option = None; let mut out_of_order = FxHashMap::default(); let mut param_idents = vec![]; - let mut found_type = false; - let mut found_const = false; for (kind, bounds, span, ident) in generics { if let Some(ident) = ident { @@ -624,11 +616,6 @@ fn validate_generics_order<'a>( } Some(_) | None => *max_param = Some(kind), }; - match kind { - ParamKindOrd::Type => found_type = true, - ParamKindOrd::Const => found_const = true, - _ => {} - } } let mut ordered_params = "<".to_string(); @@ -651,42 +638,26 @@ fn validate_generics_order<'a>( } ordered_params += ">"; - let pos_str = match pos { - GenericPosition::Param => "parameter", - GenericPosition::Arg => "argument", - }; - for (param_ord, (max_param, spans)) in &out_of_order { - let mut err = handler.struct_span_err( - spans.clone(), - &format!( - "{} {pos}s must be declared prior to {} {pos}s", - param_ord, - max_param, - pos = pos_str, - ), - ); - if let GenericPosition::Param = pos { - err.span_suggestion( - span, + let mut err = + handler.struct_span_err( + spans.clone(), &format!( - "reorder the {}s: lifetimes, then types{}", - pos_str, - if sess.features_untracked().const_generics { ", then consts" } else { "" }, + "{} parameters must be declared prior to {} parameters", + param_ord, max_param, ), - ordered_params.clone(), - Applicability::MachineApplicable, ); - } + err.span_suggestion( + span, + &format!( + "reorder the parameters: lifetimes, then types{}", + if sess.features_untracked().const_generics { ", then consts" } else { "" }, + ), + ordered_params.clone(), + Applicability::MachineApplicable, + ); err.emit(); } - - // FIXME(const_generics): we shouldn't have to abort here at all, but we currently get ICEs - // if we don't. Const parameters and type parameters can currently conflict if they - // are out-of-order. - if !out_of_order.is_empty() && found_type && found_const { - FatalError.raise(); - } } impl<'a> Visitor<'a> for AstValidator<'a> { @@ -1000,24 +971,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> { match *generic_args { GenericArgs::AngleBracketed(ref data) => { walk_list!(self, visit_generic_arg, &data.args); - validate_generics_order( - self.session, - self.err_handler(), - data.args.iter().map(|arg| { - ( - match arg { - GenericArg::Lifetime(..) => ParamKindOrd::Lifetime, - GenericArg::Type(..) => ParamKindOrd::Type, - GenericArg::Const(..) => ParamKindOrd::Const, - }, - None, - arg.span(), - None, - ) - }), - GenericPosition::Arg, - generic_args.span(), - ); // Type bindings such as `Item = impl Debug` in `Iterator` // are allowed to contain nested `impl Trait`. @@ -1054,7 +1007,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } } - validate_generics_order( + validate_generic_param_order( self.session, self.err_handler(), generics.params.iter().map(|param| { @@ -1069,7 +1022,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> { }; (kind, Some(&*param.bounds), param.ident.span, ident) }), - GenericPosition::Param, generics.span, ); diff --git a/src/librustc_error_codes/error_codes.rs b/src/librustc_error_codes/error_codes.rs index ba43b29538d50..91a7b6c895838 100644 --- a/src/librustc_error_codes/error_codes.rs +++ b/src/librustc_error_codes/error_codes.rs @@ -417,6 +417,7 @@ E0743: include_str!("./error_codes/E0743.md"), E0744: include_str!("./error_codes/E0744.md"), E0745: include_str!("./error_codes/E0745.md"), E0746: include_str!("./error_codes/E0746.md"), +E0747: include_str!("./error_codes/E0747.md"), ; // E0006, // merged with E0005 // E0008, // cannot bind by-move into a pattern guard diff --git a/src/librustc_error_codes/error_codes/E0747.md b/src/librustc_error_codes/error_codes/E0747.md new file mode 100644 index 0000000000000..45b2dfd9e2bb3 --- /dev/null +++ b/src/librustc_error_codes/error_codes/E0747.md @@ -0,0 +1,10 @@ +Generic arguments must be provided in the same order as the corresponding generic +parameters are declared. + +Erroneous code example: + +```compile_fail,E0747 +struct S<'a, T>(&'a T); + +type X = S<(), 'static>; // error: the type argument is provided before the lifetime argument +``` diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 1e5e00445ccca..4ef732a7662a7 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -481,6 +481,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { parent_substs: &[subst::GenericArg<'tcx>], has_self: bool, self_ty: Option>, + arg_count_mismatch: bool, args_for_def_id: impl Fn(DefId) -> (Option<&'b GenericArgs<'b>>, bool), provided_kind: impl Fn(&GenericParamDef, &GenericArg<'_>) -> subst::GenericArg<'tcx>, mut inferred_kind: impl FnMut( @@ -504,7 +505,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // methods in `subst.rs`, so that we can iterate over the arguments and // parameters in lock-step linearly, instead of trying to match each pair. let mut substs: SmallVec<[subst::GenericArg<'tcx>; 8]> = SmallVec::with_capacity(count); - // Iterate over each segment of the path. while let Some((def_id, defs)) = stack.pop() { let mut params = defs.params.iter().peekable(); @@ -541,6 +541,18 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let mut args = generic_args.iter().flat_map(|generic_args| generic_args.args.iter()).peekable(); + let arg_kind = |arg| match arg { + &GenericArg::Lifetime(_) => "lifetime", + &GenericArg::Type(_) => "type", + &GenericArg::Const(_) => "constant", + }; + + // If we encounter a type or const when we expect a lifetime, we infer the lifetimes. + // If we later encounter a lifetime, we know that the arguments were provided in the + // wrong order. `force_infer_lt` records the type or const that forced lifetimes to be + // inferred, so we can use it for diagnostics later. + let mut force_infer_lt = None; + loop { // We're going to iterate through the generic arguments that the user // provided, matching them with the generic parameters we expect. @@ -561,28 +573,74 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // We expected a lifetime argument, but got a type or const // argument. That means we're inferring the lifetimes. substs.push(inferred_kind(None, param, infer_args)); + force_infer_lt = Some(arg); params.next(); } - (_, _) => { + (_, kind) => { // We expected one kind of parameter, but the user provided - // another. This is an error, but we need to handle it - // gracefully so we can report sensible errors. - // In this case, we're simply going to infer this argument. - args.next(); + // another. This is an error. However, if we already know that + // the arguments don't match up with the parameters, we won't issue + // an additional error, as the user already knows what's wrong. + if !arg_count_mismatch { + let param_kind = match kind { + GenericParamDefKind::Lifetime => "lifetime", + GenericParamDefKind::Type { .. } => "type", + GenericParamDefKind::Const => "constant", + }; + struct_span_err!( + tcx.sess, + arg.span(), + E0747, + "{} provided when a {} was expected", + arg_kind(arg), + param_kind, + ) + .emit(); + } + + // We've reported the error, but we want to make sure that this + // problem doesn't bubble down and create additional, irrelevant + // errors. In this case, we're simply going to ignore the argument + // and any following arguments. The rest of the parameters will be + // inferred. + while args.next().is_some() {} } } } - (Some(_), None) => { + (Some(&arg), None) => { // We should never be able to reach this point with well-formed input. - // Getting to this point means the user supplied more arguments than - // there are parameters. - args.next(); + // There are two situations in which we can encounter this issue. + // + // 1. The number of arguments is incorrect. In this case, an error + // will already have been emitted, and we can ignore it. This case + // also occurs when late-bound lifetime parameters are present, yet + // the lifetime arguments have also been explicitly specified by the + // user. + // 2. We've inferred some lifetimes, which have been provided later (i.e. + // after a type or const). We want to throw an error in this case. + + if !arg_count_mismatch { + let kind = arg_kind(arg); + assert_eq!(kind, "lifetime"); + let provided = + force_infer_lt.expect("lifetimes ought to have been inferred"); + struct_span_err!( + tcx.sess, + provided.span(), + E0747, + "{} provided when a {} was expected", + arg_kind(provided), + kind, + ) + .emit(); + } + + break; } (None, Some(¶m)) => { // If there are fewer arguments than parameters, it means // we're inferring the remaining arguments. substs.push(inferred_kind(Some(&substs), param, infer_args)); - args.next(); params.next(); } (None, None) => break, @@ -658,7 +716,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { assert!(self_ty.is_none() && parent_substs.is_empty()); } - let (_, potential_assoc_types) = Self::check_generic_arg_count( + let (arg_count_mismatch, potential_assoc_types) = Self::check_generic_arg_count( tcx, span, &generic_params, @@ -691,6 +749,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { parent_substs, self_ty.is_some(), self_ty, + arg_count_mismatch, // Provide the generic args, and whether types should be inferred. |did| { if did == def_id { diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 04cbee8c94061..e3fde9159cc38 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -299,7 +299,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { // If they were not explicitly supplied, just construct fresh // variables. let generics = self.tcx.generics_of(pick.item.def_id); - AstConv::check_generic_arg_count_for_call( + let arg_count_mismatch = AstConv::check_generic_arg_count_for_call( self.tcx, self.span, &generics, &seg, true, // `is_method_call` ); @@ -313,6 +313,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { parent_substs, false, None, + arg_count_mismatch, // Provide the generic args, and whether types should be inferred. |def_id| { // The last component of the returned tuple here is unimportant. diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 4f6eb20e6ebbd..989f98682f93e 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -5520,6 +5520,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &[][..], has_self, self_ty, + !infer_args_for_err.is_empty(), // Provide the generic args, and whether types should be inferred. |def_id| { if let Some(&PathSeg(_, index)) = diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 70586be0d0433..3bdec71d3dcf7 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1269,7 +1269,7 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::Generics { let object_lifetime_defaults = tcx.object_lifetime_defaults(hir_id); - // Now create the real type parameters. + // Now create the real type and const parameters. let type_start = own_start - has_self as u32 + params.len() as u32; let mut i = 0; params.extend(ast_generics.params.iter().filter_map(|param| { diff --git a/src/test/ui/const-generics/const-arg-type-arg-misordered.rs b/src/test/ui/const-generics/const-arg-type-arg-misordered.rs new file mode 100644 index 0000000000000..f024eb6a957e3 --- /dev/null +++ b/src/test/ui/const-generics/const-arg-type-arg-misordered.rs @@ -0,0 +1,10 @@ +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +type Array = [T; N]; + +fn foo() -> Array { //~ ERROR constant provided when a type was expected + unimplemented!() +} + +fn main() {} diff --git a/src/test/ui/const-generics/const-arg-type-arg-misordered.stderr b/src/test/ui/const-generics/const-arg-type-arg-misordered.stderr new file mode 100644 index 0000000000000..225e1cd547e7c --- /dev/null +++ b/src/test/ui/const-generics/const-arg-type-arg-misordered.stderr @@ -0,0 +1,17 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/const-arg-type-arg-misordered.rs:1:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + +error[E0747]: constant provided when a type was expected + --> $DIR/const-arg-type-arg-misordered.rs:6:35 + | +LL | fn foo() -> Array { + | ^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0747`. diff --git a/src/test/ui/const-generics/const-param-after-const-literal-arg.rs b/src/test/ui/const-generics/const-param-after-const-literal-arg.rs new file mode 100644 index 0000000000000..683bcc867c799 --- /dev/null +++ b/src/test/ui/const-generics/const-param-after-const-literal-arg.rs @@ -0,0 +1,10 @@ +// check-pass + +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +struct Foo; + +impl Foo<1, A> {} // ok + +fn main() {} diff --git a/src/test/ui/const-generics/const-param-after-const-literal-arg.stderr b/src/test/ui/const-generics/const-param-after-const-literal-arg.stderr new file mode 100644 index 0000000000000..a949a6ec9ff5c --- /dev/null +++ b/src/test/ui/const-generics/const-param-after-const-literal-arg.stderr @@ -0,0 +1,8 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/const-param-after-const-literal-arg.rs:3:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + diff --git a/src/test/ui/const-generics/const-param-before-other-params.rs b/src/test/ui/const-generics/const-param-before-other-params.rs index 5bdbfd8ff1f39..2c81681b85e7d 100644 --- a/src/test/ui/const-generics/const-param-before-other-params.rs +++ b/src/test/ui/const-generics/const-param-before-other-params.rs @@ -1,4 +1,5 @@ #![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash fn bar(_: &'a ()) { //~^ ERROR lifetime parameters must be declared prior to const parameters diff --git a/src/test/ui/const-generics/const-param-before-other-params.stderr b/src/test/ui/const-generics/const-param-before-other-params.stderr index 87622f7e50010..fccf732de4c99 100644 --- a/src/test/ui/const-generics/const-param-before-other-params.stderr +++ b/src/test/ui/const-generics/const-param-before-other-params.stderr @@ -1,14 +1,22 @@ error: lifetime parameters must be declared prior to const parameters - --> $DIR/const-param-before-other-params.rs:3:21 + --> $DIR/const-param-before-other-params.rs:4:21 | LL | fn bar(_: &'a ()) { | --------------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, const X: ()>` error: type parameters must be declared prior to const parameters - --> $DIR/const-param-before-other-params.rs:7:21 + --> $DIR/const-param-before-other-params.rs:8:21 | LL | fn foo(_: &T) { | --------------^- help: reorder the parameters: lifetimes, then types, then consts: `` +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/const-param-before-other-params.rs:1:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + error: aborting due to 2 previous errors diff --git a/src/test/ui/parser/issue-14303-fncall.rs b/src/test/ui/parser/issue-14303-fncall.rs index 39694198cdb4d..46ece84d69e45 100644 --- a/src/test/ui/parser/issue-14303-fncall.rs +++ b/src/test/ui/parser/issue-14303-fncall.rs @@ -11,7 +11,7 @@ fn foo<'a, 'b>(start: &'a usize, end: &'a usize) { let _x = (*start..*end) .map(|x| S { a: start, b: end }) .collect::>>(); - //~^ ERROR lifetime arguments must be declared prior to type arguments + //~^ ERROR type provided when a lifetime was expected } fn main() {} diff --git a/src/test/ui/parser/issue-14303-fncall.stderr b/src/test/ui/parser/issue-14303-fncall.stderr index 8ef9f1a1a6c79..cdda0d001c7dc 100644 --- a/src/test/ui/parser/issue-14303-fncall.stderr +++ b/src/test/ui/parser/issue-14303-fncall.stderr @@ -1,8 +1,9 @@ -error: lifetime arguments must be declared prior to type arguments - --> $DIR/issue-14303-fncall.rs:13:29 +error[E0747]: type provided when a lifetime was expected + --> $DIR/issue-14303-fncall.rs:13:26 | LL | .collect::>>(); - | ^^ + | ^ error: aborting due to previous error +For more information about this error, try `rustc --explain E0747`. diff --git a/src/test/ui/parser/issue-14303-path.rs b/src/test/ui/parser/issue-14303-path.rs index 386d19859e4a8..89ef914aba238 100644 --- a/src/test/ui/parser/issue-14303-path.rs +++ b/src/test/ui/parser/issue-14303-path.rs @@ -8,6 +8,6 @@ mod foo { } fn bar<'a, 'b, 'c, T>(x: foo::X<'a, T, 'b, 'c>) {} -//~^ ERROR lifetime arguments must be declared prior to type arguments +//~^ ERROR type provided when a lifetime was expected fn main() {} diff --git a/src/test/ui/parser/issue-14303-path.stderr b/src/test/ui/parser/issue-14303-path.stderr index 19f2995ebee53..841e63ecbe9d5 100644 --- a/src/test/ui/parser/issue-14303-path.stderr +++ b/src/test/ui/parser/issue-14303-path.stderr @@ -1,8 +1,9 @@ -error: lifetime arguments must be declared prior to type arguments - --> $DIR/issue-14303-path.rs:10:40 +error[E0747]: type provided when a lifetime was expected + --> $DIR/issue-14303-path.rs:10:37 | LL | fn bar<'a, 'b, 'c, T>(x: foo::X<'a, T, 'b, 'c>) {} - | ^^ ^^ + | ^ error: aborting due to previous error +For more information about this error, try `rustc --explain E0747`. diff --git a/src/test/ui/suggestions/suggest-move-types.rs b/src/test/ui/suggestions/suggest-move-types.rs index 890950ea08c5d..6505a97de6e4b 100644 --- a/src/test/ui/suggestions/suggest-move-types.rs +++ b/src/test/ui/suggestions/suggest-move-types.rs @@ -33,7 +33,7 @@ struct A> { //~ ERROR associated type bindings must be declar struct Al<'a, T, M: OneWithLifetime> { //~^ ERROR associated type bindings must be declared after generic parameters -//~^^ ERROR lifetime arguments must be declared prior to type arguments +//~^^ ERROR type provided when a lifetime was expected m: M, t: &'a T, } @@ -47,7 +47,7 @@ struct B> { //~ ERROR associated ty struct Bl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime> { //~^ ERROR associated type bindings must be declared after generic parameters -//~^^ ERROR lifetime arguments must be declared prior to type arguments +//~^^ ERROR type provided when a lifetime was expected m: M, t: &'a T, u: &'b U, @@ -63,7 +63,7 @@ struct C> { //~ ERROR associated ty struct Cl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime> { //~^ ERROR associated type bindings must be declared after generic parameters -//~^^ ERROR lifetime arguments must be declared prior to type arguments +//~^^ ERROR lifetime provided when a type was expected m: M, t: &'a T, u: &'b U, @@ -79,7 +79,7 @@ struct D> { //~ ERROR associated ty struct Dl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime> { //~^ ERROR associated type bindings must be declared after generic parameters -//~^^ ERROR lifetime arguments must be declared prior to type arguments +//~^^ ERROR lifetime provided when a type was expected m: M, t: &'a T, u: &'b U, diff --git a/src/test/ui/suggestions/suggest-move-types.stderr b/src/test/ui/suggestions/suggest-move-types.stderr index 552fb78cd3fdd..07ad1a3150836 100644 --- a/src/test/ui/suggestions/suggest-move-types.stderr +++ b/src/test/ui/suggestions/suggest-move-types.stderr @@ -74,29 +74,30 @@ LL | struct Dl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime $DIR/suggest-move-types.rs:34:46 +error[E0747]: type provided when a lifetime was expected + --> $DIR/suggest-move-types.rs:34:43 | LL | struct Al<'a, T, M: OneWithLifetime> { - | ^^ + | ^ -error: lifetime arguments must be declared prior to type arguments - --> $DIR/suggest-move-types.rs:48:80 +error[E0747]: type provided when a lifetime was expected + --> $DIR/suggest-move-types.rs:48:71 | LL | struct Bl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime> { - | ^^ ^^ ^^ + | ^ -error: lifetime arguments must be declared prior to type arguments +error[E0747]: lifetime provided when a type was expected --> $DIR/suggest-move-types.rs:64:56 | LL | struct Cl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime> { - | ^^ ^^ ^^ + | ^^ -error: lifetime arguments must be declared prior to type arguments +error[E0747]: lifetime provided when a type was expected --> $DIR/suggest-move-types.rs:80:56 | LL | struct Dl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime> { - | ^^ ^^ ^^ + | ^^ error: aborting due to 12 previous errors +For more information about this error, try `rustc --explain E0747`. diff --git a/src/test/ui/traits/trait-object-vs-lifetime.rs b/src/test/ui/traits/trait-object-vs-lifetime.rs index e0ff734948376..e885cd2f68ac5 100644 --- a/src/test/ui/traits/trait-object-vs-lifetime.rs +++ b/src/test/ui/traits/trait-object-vs-lifetime.rs @@ -12,6 +12,6 @@ fn main() { //~^ ERROR wrong number of lifetime arguments: expected 1, found 2 //~| ERROR wrong number of type arguments: expected 1, found 0 let _: S; - //~^ ERROR lifetime arguments must be declared prior to type arguments + //~^ ERROR type provided when a lifetime was expected //~| ERROR at least one trait is required for an object type } diff --git a/src/test/ui/traits/trait-object-vs-lifetime.stderr b/src/test/ui/traits/trait-object-vs-lifetime.stderr index be1958770a426..d1e5a65c0ad68 100644 --- a/src/test/ui/traits/trait-object-vs-lifetime.stderr +++ b/src/test/ui/traits/trait-object-vs-lifetime.stderr @@ -1,9 +1,3 @@ -error: lifetime arguments must be declared prior to type arguments - --> $DIR/trait-object-vs-lifetime.rs:14:29 - | -LL | let _: S; - | ^^^^^^^ - error[E0224]: at least one trait is required for an object type --> $DIR/trait-object-vs-lifetime.rs:9:23 | @@ -28,6 +22,13 @@ error[E0224]: at least one trait is required for an object type LL | let _: S; | ^^^^^^^^^^^^^ +error[E0747]: type provided when a lifetime was expected + --> $DIR/trait-object-vs-lifetime.rs:14:14 + | +LL | let _: S; + | ^^^^^^^^^^^^^ + error: aborting due to 5 previous errors -For more information about this error, try `rustc --explain E0107`. +Some errors have detailed explanations: E0107, E0747. +For more information about an error, try `rustc --explain E0107`. From c9b7b1f73b8d256a0885506d8e7e76cd35067318 Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 22 Jan 2020 01:43:24 +0000 Subject: [PATCH 06/12] Refactor `create_substs_for_generic_args` a little --- src/librustc/ty/mod.rs | 10 ++++ src/librustc/ty/structural_impls.rs | 7 +-- src/librustc_error_codes/error_codes/E0747.md | 7 +-- src/librustc_hir/hir.rs | 8 +++ src/librustc_typeck/astconv.rs | 52 ++++++++----------- 5 files changed, 44 insertions(+), 40 deletions(-) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index a195c944ff28d..54c0a267fe7b2 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -931,6 +931,16 @@ pub enum GenericParamDefKind { Const, } +impl GenericParamDefKind { + pub fn descr(&self) -> &'static str { + match self { + GenericParamDefKind::Lifetime => "lifetime", + GenericParamDefKind::Type { .. } => "type", + GenericParamDefKind::Const => "constant", + } + } +} + #[derive(Clone, RustcEncodable, RustcDecodable, HashStable)] pub struct GenericParamDef { pub name: Symbol, diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 59dd41e9d56c9..388afc15c8559 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -19,12 +19,7 @@ use std::sync::Arc; impl fmt::Debug for ty::GenericParamDef { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let type_name = match self.kind { - ty::GenericParamDefKind::Lifetime => "Lifetime", - ty::GenericParamDefKind::Type { .. } => "Type", - ty::GenericParamDefKind::Const => "Const", - }; - write!(f, "{}({}, {:?}, {})", type_name, self.name, self.def_id, self.index) + write!(f, "{}({}, {:?}, {})", self.kind.descr(), self.name, self.def_id, self.index) } } diff --git a/src/librustc_error_codes/error_codes/E0747.md b/src/librustc_error_codes/error_codes/E0747.md index 45b2dfd9e2bb3..9bdfb5ef0bc2d 100644 --- a/src/librustc_error_codes/error_codes/E0747.md +++ b/src/librustc_error_codes/error_codes/E0747.md @@ -1,10 +1,11 @@ -Generic arguments must be provided in the same order as the corresponding generic -parameters are declared. +Generic arguments must be provided in the same order as the corresponding +generic parameters are declared. Erroneous code example: ```compile_fail,E0747 struct S<'a, T>(&'a T); -type X = S<(), 'static>; // error: the type argument is provided before the lifetime argument +type X = S<(), 'static>; // error: the type argument is provided before the + // lifetime argument ``` diff --git a/src/librustc_hir/hir.rs b/src/librustc_hir/hir.rs index 8496a6ed23b8c..4a6871e023296 100644 --- a/src/librustc_hir/hir.rs +++ b/src/librustc_hir/hir.rs @@ -298,6 +298,14 @@ impl GenericArg<'_> { _ => false, } } + + pub fn descr(&self) -> &'static str { + match self { + GenericArg::Lifetime(_) => "lifetime", + GenericArg::Type(_) => "type", + GenericArg::Const(_) => "constant", + } + } } #[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)] diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 4ef732a7662a7..a590a942e4274 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -12,7 +12,7 @@ use crate::middle::resolve_lifetime as rl; use crate::require_c_abi_if_c_variadic; use crate::util::common::ErrorReported; use rustc::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS; -use rustc::session::parse::feature_err; +use rustc::session::{parse::feature_err, Session}; use rustc::ty::subst::{self, InternalSubsts, Subst, SubstsRef}; use rustc::ty::{self, Const, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness}; use rustc::ty::{GenericParamDef, GenericParamDefKind}; @@ -446,6 +446,20 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { (arg_count_mismatch, unexpected_spans) } + /// Report an error that a generic argument did not match the generic parameter that was + /// expected. + fn generic_arg_mismatch_err(sess: &Session, arg: &GenericArg<'_>, kind: &'static str) { + struct_span_err!( + sess, + arg.span(), + E0747, + "{} provided when a {} was expected", + arg.descr(), + kind, + ) + .emit(); + } + /// Creates the relevant generic argument substitutions /// corresponding to a set of generic parameters. This is a /// rather complex function. Let us try to explain the role @@ -541,12 +555,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let mut args = generic_args.iter().flat_map(|generic_args| generic_args.args.iter()).peekable(); - let arg_kind = |arg| match arg { - &GenericArg::Lifetime(_) => "lifetime", - &GenericArg::Type(_) => "type", - &GenericArg::Const(_) => "constant", - }; - // If we encounter a type or const when we expect a lifetime, we infer the lifetimes. // If we later encounter a lifetime, we know that the arguments were provided in the // wrong order. `force_infer_lt` records the type or const that forced lifetimes to be @@ -582,20 +590,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // the arguments don't match up with the parameters, we won't issue // an additional error, as the user already knows what's wrong. if !arg_count_mismatch { - let param_kind = match kind { - GenericParamDefKind::Lifetime => "lifetime", - GenericParamDefKind::Type { .. } => "type", - GenericParamDefKind::Const => "constant", - }; - struct_span_err!( - tcx.sess, - arg.span(), - E0747, - "{} provided when a {} was expected", - arg_kind(arg), - param_kind, - ) - .emit(); + Self::generic_arg_mismatch_err(tcx.sess, arg, kind.descr()); } // We've reported the error, but we want to make sure that this @@ -607,6 +602,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } } } + (Some(&arg), None) => { // We should never be able to reach this point with well-formed input. // There are two situations in which we can encounter this issue. @@ -620,29 +616,23 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // after a type or const). We want to throw an error in this case. if !arg_count_mismatch { - let kind = arg_kind(arg); + let kind = arg.descr(); assert_eq!(kind, "lifetime"); let provided = force_infer_lt.expect("lifetimes ought to have been inferred"); - struct_span_err!( - tcx.sess, - provided.span(), - E0747, - "{} provided when a {} was expected", - arg_kind(provided), - kind, - ) - .emit(); + Self::generic_arg_mismatch_err(tcx.sess, provided, kind); } break; } + (None, Some(¶m)) => { // If there are fewer arguments than parameters, it means // we're inferring the remaining arguments. substs.push(inferred_kind(Some(&substs), param, infer_args)); params.next(); } + (None, None) => break, } } From dff64eb4b6b6a1cd2ae4e122b70a632f52f1dada Mon Sep 17 00:00:00 2001 From: varkor Date: Thu, 23 Jan 2020 00:41:33 +0000 Subject: [PATCH 07/12] Make return value of `check_generic_arg_count` semantically clearer --- src/librustc/ty/mod.rs | 2 +- src/librustc/ty/structural_impls.rs | 6 ------ src/librustc_typeck/astconv.rs | 20 ++++++++++++-------- src/librustc_typeck/check/method/confirm.rs | 4 ++-- src/librustc_typeck/check/mod.rs | 7 ++++--- 5 files changed, 19 insertions(+), 20 deletions(-) diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 54c0a267fe7b2..7df1383f86add 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -941,7 +941,7 @@ impl GenericParamDefKind { } } -#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)] +#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)] pub struct GenericParamDef { pub name: Symbol, pub def_id: DefId, diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 388afc15c8559..03ff1b8a3171f 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -17,12 +17,6 @@ use std::fmt; use std::rc::Rc; use std::sync::Arc; -impl fmt::Debug for ty::GenericParamDef { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}({}, {:?}, {})", self.kind.descr(), self.name, self.def_id, self.index) - } -} - impl fmt::Debug for ty::TraitDef { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { ty::tls::with(|tcx| { diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index a590a942e4274..b3131c159a68d 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -132,6 +132,10 @@ enum GenericArgPosition { MethodCall, } +/// A marker denoting that the generic arguments that were +/// provided did not match the respective generic parameters. +pub struct GenericArgCountMismatch; + impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { pub fn ast_region_to_region( &self, @@ -262,7 +266,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { def: &ty::Generics, seg: &hir::PathSegment<'_>, is_method_call: bool, - ) -> bool { + ) -> Result<(), GenericArgCountMismatch> { let empty_args = hir::GenericArgs::none(); let suppress_mismatch = Self::check_impl_trait(tcx, seg, &def); Self::check_generic_arg_count( @@ -287,7 +291,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { position: GenericArgPosition, has_self: bool, infer_args: bool, - ) -> (bool, Vec) { + ) -> (Result<(), GenericArgCountMismatch>, Vec) { // 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 // arguments in order to validate them with respect to the generic parameters. @@ -443,7 +447,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ); } - (arg_count_mismatch, unexpected_spans) + (if arg_count_mismatch { Err(GenericArgCountMismatch) } else { Ok(()) }, unexpected_spans) } /// Report an error that a generic argument did not match the generic parameter that was @@ -495,7 +499,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { parent_substs: &[subst::GenericArg<'tcx>], has_self: bool, self_ty: Option>, - arg_count_mismatch: bool, + arg_count_correct: Result<(), GenericArgCountMismatch>, args_for_def_id: impl Fn(DefId) -> (Option<&'b GenericArgs<'b>>, bool), provided_kind: impl Fn(&GenericParamDef, &GenericArg<'_>) -> subst::GenericArg<'tcx>, mut inferred_kind: impl FnMut( @@ -589,7 +593,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // another. This is an error. However, if we already know that // the arguments don't match up with the parameters, we won't issue // an additional error, as the user already knows what's wrong. - if !arg_count_mismatch { + if arg_count_correct.is_ok() { Self::generic_arg_mismatch_err(tcx.sess, arg, kind.descr()); } @@ -615,7 +619,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // 2. We've inferred some lifetimes, which have been provided later (i.e. // after a type or const). We want to throw an error in this case. - if !arg_count_mismatch { + if arg_count_correct.is_ok() { let kind = arg.descr(); assert_eq!(kind, "lifetime"); let provided = @@ -706,7 +710,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { assert!(self_ty.is_none() && parent_substs.is_empty()); } - let (arg_count_mismatch, potential_assoc_types) = Self::check_generic_arg_count( + let (arg_count_correct, potential_assoc_types) = Self::check_generic_arg_count( tcx, span, &generic_params, @@ -739,7 +743,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { parent_substs, self_ty.is_some(), self_ty, - arg_count_mismatch, + arg_count_correct, // Provide the generic args, and whether types should be inferred. |did| { if did == def_id { diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index e3fde9159cc38..38773abeef28c 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -299,7 +299,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { // If they were not explicitly supplied, just construct fresh // variables. let generics = self.tcx.generics_of(pick.item.def_id); - let arg_count_mismatch = AstConv::check_generic_arg_count_for_call( + let arg_count_correct = AstConv::check_generic_arg_count_for_call( self.tcx, self.span, &generics, &seg, true, // `is_method_call` ); @@ -313,7 +313,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { parent_substs, false, None, - arg_count_mismatch, + arg_count_correct, // Provide the generic args, and whether types should be inferred. |def_id| { // The last component of the returned tuple here is unimportant. diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 989f98682f93e..426ba0ddaaa4f 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -87,7 +87,7 @@ mod upvar; mod wfcheck; pub mod writeback; -use crate::astconv::{AstConv, PathSeg}; +use crate::astconv::{AstConv, GenericArgCountMismatch, PathSeg}; use crate::middle::lang_items; use rustc::hir::map::blocks::FnLikeNode; use rustc::hir::map::Map; @@ -5454,7 +5454,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // checking here. let suppress_errors = AstConv::check_generic_arg_count_for_call( tcx, span, &generics, &seg, false, // `is_method_call` - ); + ) + .is_err(); if suppress_errors { infer_args_for_err.insert(index); self.set_tainted_by_errors(); // See issue #53251. @@ -5520,7 +5521,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &[][..], has_self, self_ty, - !infer_args_for_err.is_empty(), + if infer_args_for_err.is_empty() { Ok(()) } else { Err(GenericArgCountMismatch) }, // Provide the generic args, and whether types should be inferred. |def_id| { if let Some(&PathSeg(_, index)) = From 104131c9d487c943d962f4d88490aa7bcf2fa2de Mon Sep 17 00:00:00 2001 From: varkor Date: Sat, 25 Jan 2020 00:49:43 +0000 Subject: [PATCH 08/12] Use `Result` instead of `bool` throughout --- src/librustc_typeck/astconv.rs | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index b3131c159a68d..ae8dbfe9c398a 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -317,10 +317,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } // Prohibit explicit lifetime arguments if late-bound lifetime parameters are present. - let mut reported_late_bound_region_err = false; + let mut explicit_lifetimes = Ok(()); if !infer_lifetimes { if let Some(span_late) = def.has_late_bound_regions { - reported_late_bound_region_err = true; + explicit_lifetimes = Err(GenericArgCountMismatch); let msg = "cannot specify lifetime arguments explicitly \ if late bound lifetime parameters are present"; let note = "the late bound lifetime parameter is introduced here"; @@ -354,7 +354,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // For kinds without defaults (e.g.., lifetimes), `required == permitted`. // For other kinds (i.e., types), `permitted` may be greater than `required`. if required <= provided && provided <= permitted { - return false; + return Ok(()); } // Unfortunately lifetime and type parameter mismatches are typically styled @@ -405,49 +405,49 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } err.emit(); - true + Err(GenericArgCountMismatch) }; - let mut arg_count_mismatch = reported_late_bound_region_err; + let mut arg_count_correct = explicit_lifetimes; let mut unexpected_spans = vec![]; - if !reported_late_bound_region_err + if arg_count_correct.is_ok() && (!infer_lifetimes || arg_counts.lifetimes > param_counts.lifetimes) { - arg_count_mismatch |= check_kind_count( + arg_count_correct = arg_count_correct.and(check_kind_count( "lifetime", param_counts.lifetimes, param_counts.lifetimes, arg_counts.lifetimes, 0, &mut unexpected_spans, - ); + )); } // FIXME(const_generics:defaults) if !infer_args || arg_counts.consts > param_counts.consts { - arg_count_mismatch |= check_kind_count( + arg_count_correct = arg_count_correct.and(check_kind_count( "const", param_counts.consts, param_counts.consts, arg_counts.consts, arg_counts.lifetimes + arg_counts.types, &mut unexpected_spans, - ); + )); } // Note that type errors are currently be emitted *after* const errors. if !infer_args || arg_counts.types > param_counts.types - defaults.types - has_self as usize { - arg_count_mismatch |= check_kind_count( + arg_count_correct = arg_count_correct.and(check_kind_count( "type", param_counts.types - defaults.types - has_self as usize, param_counts.types - has_self as usize, arg_counts.types, arg_counts.lifetimes, &mut unexpected_spans, - ); + )); } - (if arg_count_mismatch { Err(GenericArgCountMismatch) } else { Ok(()) }, unexpected_spans) + (arg_count_correct, unexpected_spans) } /// Report an error that a generic argument did not match the generic parameter that was From 33143fd756f3765daa00809da2d1f66b5d3ac9fc Mon Sep 17 00:00:00 2001 From: varkor Date: Sat, 25 Jan 2020 22:28:31 +0000 Subject: [PATCH 09/12] Be explicit about whether `GenericArgCountMismatch` arose from a fatal error --- src/librustc_typeck/astconv.rs | 8 +++++--- src/librustc_typeck/check/mod.rs | 16 ++++++++++------ 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index ae8dbfe9c398a..42613532655ef 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -134,7 +134,8 @@ enum GenericArgPosition { /// A marker denoting that the generic arguments that were /// provided did not match the respective generic parameters. -pub struct GenericArgCountMismatch; +/// The field indicates whether a fatal error was reported (`Some`), or just a lint (`None`). +pub struct GenericArgCountMismatch(pub Option); impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { pub fn ast_region_to_region( @@ -320,7 +321,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let mut explicit_lifetimes = Ok(()); if !infer_lifetimes { if let Some(span_late) = def.has_late_bound_regions { - explicit_lifetimes = Err(GenericArgCountMismatch); let msg = "cannot specify lifetime arguments explicitly \ if late bound lifetime parameters are present"; let note = "the late bound lifetime parameter is introduced here"; @@ -328,10 +328,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { if position == GenericArgPosition::Value && arg_counts.lifetimes != param_counts.lifetimes { + explicit_lifetimes = Err(GenericArgCountMismatch(Some(ErrorReported))); let mut err = tcx.sess.struct_span_err(span, msg); err.span_note(span_late, note); err.emit(); } else { + explicit_lifetimes = Err(GenericArgCountMismatch(None)); let mut multispan = MultiSpan::from_span(span); multispan.push_span_label(span_late, note.to_string()); tcx.struct_span_lint_hir( @@ -405,7 +407,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } err.emit(); - Err(GenericArgCountMismatch) + Err(GenericArgCountMismatch(Some(ErrorReported))) }; let mut arg_count_correct = explicit_lifetimes; diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 426ba0ddaaa4f..daedeafbcc325 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -5452,11 +5452,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // 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 suppress_errors = AstConv::check_generic_arg_count_for_call( - tcx, span, &generics, &seg, false, // `is_method_call` - ) - .is_err(); - if suppress_errors { + if let Err(GenericArgCountMismatch(Some(ErrorReported))) = + AstConv::check_generic_arg_count_for_call( + tcx, span, &generics, &seg, false, // `is_method_call` + ) + { infer_args_for_err.insert(index); self.set_tainted_by_errors(); // See issue #53251. } @@ -5521,7 +5521,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &[][..], has_self, self_ty, - if infer_args_for_err.is_empty() { Ok(()) } else { Err(GenericArgCountMismatch) }, + if infer_args_for_err.is_empty() { + Ok(()) + } else { + Err(GenericArgCountMismatch(Some(ErrorReported))) + }, // Provide the generic args, and whether types should be inferred. |def_id| { if let Some(&PathSeg(_, index)) = From 76fb26b8c2ad48a8194dceb06073b636ca7ae6d6 Mon Sep 17 00:00:00 2001 From: varkor Date: Sat, 22 Feb 2020 01:55:35 +0000 Subject: [PATCH 10/12] Add invalid argument spans to `GenericArgCountMismatch` --- src/librustc_ast_passes/ast_validation.rs | 2 +- src/librustc_typeck/astconv.rs | 72 ++++++++++++--------- src/librustc_typeck/check/method/confirm.rs | 2 +- src/librustc_typeck/check/mod.rs | 8 +-- 4 files changed, 47 insertions(+), 37 deletions(-) diff --git a/src/librustc_ast_passes/ast_validation.rs b/src/librustc_ast_passes/ast_validation.rs index d55efeda3c14a..25455ff629b3b 100644 --- a/src/librustc_ast_passes/ast_validation.rs +++ b/src/librustc_ast_passes/ast_validation.rs @@ -8,7 +8,7 @@ use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::{error_code, struct_span_err, Applicability, FatalError}; +use rustc_errors::{error_code, struct_span_err, Applicability}; use rustc_parse::validate_attr; use rustc_session::lint::builtin::PATTERNS_IN_FNS_WITHOUT_BODY; use rustc_session::lint::LintBuffer; diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 42613532655ef..9a80452aef3d2 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -134,8 +134,12 @@ enum GenericArgPosition { /// A marker denoting that the generic arguments that were /// provided did not match the respective generic parameters. -/// The field indicates whether a fatal error was reported (`Some`), or just a lint (`None`). -pub struct GenericArgCountMismatch(pub Option); +pub struct GenericArgCountMismatch { + /// Indicates whether a fatal error was reported (`Some`), or just a lint (`None`). + pub reported: Option, + /// A list of spans of arguments provided that were not valid. + pub invalid_args: Vec, +} impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { pub fn ast_region_to_region( @@ -279,7 +283,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { def.parent.is_none() && def.has_self, // `has_self` seg.infer_args || suppress_mismatch, // `infer_args` ) - .0 } /// Checks that the correct number of generic arguments have been provided. @@ -292,7 +295,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { position: GenericArgPosition, has_self: bool, infer_args: bool, - ) -> (Result<(), GenericArgCountMismatch>, Vec) { + ) -> Result<(), GenericArgCountMismatch> { // 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 // arguments in order to validate them with respect to the generic parameters. @@ -328,12 +331,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { if position == GenericArgPosition::Value && arg_counts.lifetimes != param_counts.lifetimes { - explicit_lifetimes = Err(GenericArgCountMismatch(Some(ErrorReported))); + explicit_lifetimes = Err(true); let mut err = tcx.sess.struct_span_err(span, msg); err.span_note(span_late, note); err.emit(); } else { - explicit_lifetimes = Err(GenericArgCountMismatch(None)); + explicit_lifetimes = Err(false); let mut multispan = MultiSpan::from_span(span); multispan.push_span_label(span_late, note.to_string()); tcx.struct_span_lint_hir( @@ -407,7 +410,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } err.emit(); - Err(GenericArgCountMismatch(Some(ErrorReported))) + Err(true) }; let mut arg_count_correct = explicit_lifetimes; @@ -416,40 +419,46 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { if arg_count_correct.is_ok() && (!infer_lifetimes || arg_counts.lifetimes > param_counts.lifetimes) { - arg_count_correct = arg_count_correct.and(check_kind_count( + arg_count_correct = check_kind_count( "lifetime", param_counts.lifetimes, param_counts.lifetimes, arg_counts.lifetimes, 0, &mut unexpected_spans, - )); + ) + .and(arg_count_correct); } // FIXME(const_generics:defaults) if !infer_args || arg_counts.consts > param_counts.consts { - arg_count_correct = arg_count_correct.and(check_kind_count( + arg_count_correct = check_kind_count( "const", param_counts.consts, param_counts.consts, arg_counts.consts, arg_counts.lifetimes + arg_counts.types, &mut unexpected_spans, - )); + ) + .and(arg_count_correct); } // Note that type errors are currently be emitted *after* const errors. if !infer_args || arg_counts.types > param_counts.types - defaults.types - has_self as usize { - arg_count_correct = arg_count_correct.and(check_kind_count( + arg_count_correct = check_kind_count( "type", param_counts.types - defaults.types - has_self as usize, param_counts.types - has_self as usize, arg_counts.types, arg_counts.lifetimes, &mut unexpected_spans, - )); + ) + .and(arg_count_correct); } - (arg_count_correct, unexpected_spans) + arg_count_correct.map_err(|reported_err| GenericArgCountMismatch { + reported: if reported_err { Some(ErrorReported) } else { None }, + invalid_args: unexpected_spans, + }) } /// Report an error that a generic argument did not match the generic parameter that was @@ -501,7 +510,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { parent_substs: &[subst::GenericArg<'tcx>], has_self: bool, self_ty: Option>, - arg_count_correct: Result<(), GenericArgCountMismatch>, + arg_count_correct: bool, args_for_def_id: impl Fn(DefId) -> (Option<&'b GenericArgs<'b>>, bool), provided_kind: impl Fn(&GenericParamDef, &GenericArg<'_>) -> subst::GenericArg<'tcx>, mut inferred_kind: impl FnMut( @@ -595,7 +604,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // another. This is an error. However, if we already know that // the arguments don't match up with the parameters, we won't issue // an additional error, as the user already knows what's wrong. - if arg_count_correct.is_ok() { + if arg_count_correct { Self::generic_arg_mismatch_err(tcx.sess, arg, kind.descr()); } @@ -621,7 +630,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // 2. We've inferred some lifetimes, which have been provided later (i.e. // after a type or const). We want to throw an error in this case. - if arg_count_correct.is_ok() { + if arg_count_correct { let kind = arg.descr(); assert_eq!(kind, "lifetime"); let provided = @@ -686,7 +695,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { generic_args: &'a hir::GenericArgs<'_>, infer_args: bool, self_ty: Option>, - ) -> (SubstsRef<'tcx>, Vec>, Vec) { + ) -> (SubstsRef<'tcx>, Vec>, Result<(), GenericArgCountMismatch>) + { // If the type is parameterized by this region, then replace this // region with the current anon region binding (in other words, // whatever & would get replaced with). @@ -712,7 +722,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { assert!(self_ty.is_none() && parent_substs.is_empty()); } - let (arg_count_correct, potential_assoc_types) = Self::check_generic_arg_count( + let arg_count_correct = Self::check_generic_arg_count( tcx, span, &generic_params, @@ -745,7 +755,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { parent_substs, self_ty.is_some(), self_ty, - arg_count_correct, + arg_count_correct.is_ok(), // Provide the generic args, and whether types should be inferred. |did| { if did == def_id { @@ -858,7 +868,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { generic_params, self_ty, substs ); - (substs, assoc_bindings, potential_assoc_types) + (substs, assoc_bindings, arg_count_correct) } crate fn create_substs_for_associated_item( @@ -989,7 +999,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self_ty: Ty<'tcx>, bounds: &mut Bounds<'tcx>, speculative: bool, - ) -> Vec { + ) -> Result<(), GenericArgCountMismatch> { let trait_def_id = trait_ref.trait_def_id(); debug!("instantiate_poly_trait_ref({:?}, def_id={:?})", trait_ref, trait_def_id); @@ -1006,7 +1016,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } else { trait_ref.path.span }; - let (substs, assoc_bindings, potential_assoc_types) = self.create_substs_for_ast_trait_ref( + let (substs, assoc_bindings, arg_count_correct) = self.create_substs_for_ast_trait_ref( path_span, trait_def_id, self_ty, @@ -1036,7 +1046,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { trait_ref, bounds, poly_trait_ref ); - potential_assoc_types + arg_count_correct } /// Given a trait bound like `Debug`, applies that trait bound the given self-type to construct @@ -1064,7 +1074,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { constness: Constness, self_ty: Ty<'tcx>, bounds: &mut Bounds<'tcx>, - ) -> Vec { + ) -> Result<(), GenericArgCountMismatch> { self.instantiate_poly_trait_ref_inner( &poly_trait_ref.trait_ref, poly_trait_ref.span, @@ -1153,7 +1163,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { trait_def_id: DefId, self_ty: Ty<'tcx>, trait_segment: &'a hir::PathSegment<'a>, - ) -> (SubstsRef<'tcx>, Vec>, Vec) { + ) -> (SubstsRef<'tcx>, Vec>, Result<(), GenericArgCountMismatch>) + { debug!("create_substs_for_ast_trait_ref(trait_segment={:?})", trait_segment); self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment); @@ -1498,13 +1509,16 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let mut potential_assoc_types = Vec::new(); let dummy_self = self.tcx().types.trait_object_dummy_self; for trait_bound in trait_bounds.iter().rev() { - let cur_potential_assoc_types = self.instantiate_poly_trait_ref( + if let Err(GenericArgCountMismatch { + invalid_args: cur_potential_assoc_types, .. + }) = self.instantiate_poly_trait_ref( trait_bound, Constness::NotConst, dummy_self, &mut bounds, - ); - potential_assoc_types.extend(cur_potential_assoc_types.into_iter()); + ) { + potential_assoc_types.extend(cur_potential_assoc_types.into_iter()); + } } // Expand trait aliases recursively and check that only one regular (non-auto) trait diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 38773abeef28c..108affe5a86c0 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -313,7 +313,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { parent_substs, false, None, - arg_count_correct, + arg_count_correct.is_ok(), // Provide the generic args, and whether types should be inferred. |def_id| { // The last component of the returned tuple here is unimportant. diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index daedeafbcc325..3738afb2c3d76 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -5452,7 +5452,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // parameter internally, but we don't allow users to specify the // parameter's value explicitly, so we have to do some error- // checking here. - if let Err(GenericArgCountMismatch(Some(ErrorReported))) = + if let Err(GenericArgCountMismatch { reported: Some(ErrorReported), .. }) = AstConv::check_generic_arg_count_for_call( tcx, span, &generics, &seg, false, // `is_method_call` ) @@ -5521,11 +5521,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &[][..], has_self, self_ty, - if infer_args_for_err.is_empty() { - Ok(()) - } else { - Err(GenericArgCountMismatch(Some(ErrorReported))) - }, + infer_args_for_err.is_empty(), // Provide the generic args, and whether types should be inferred. |def_id| { if let Some(&PathSeg(_, index)) = From e372ad48001920a77464c94cb2f48702af7e9ad3 Mon Sep 17 00:00:00 2001 From: varkor Date: Sat, 22 Feb 2020 01:56:05 +0000 Subject: [PATCH 11/12] Expand the documentation for E0747 --- src/librustc_error_codes/error_codes/E0747.md | 9 +++++++++ .../const-param-after-const-literal-arg.rs | 2 +- .../const-param-after-const-literal-arg.stderr | 8 -------- .../ui/const-generics/const-param-before-other-params.rs | 2 +- 4 files changed, 11 insertions(+), 10 deletions(-) delete mode 100644 src/test/ui/const-generics/const-param-after-const-literal-arg.stderr diff --git a/src/librustc_error_codes/error_codes/E0747.md b/src/librustc_error_codes/error_codes/E0747.md index 9bdfb5ef0bc2d..df1afbfef46df 100644 --- a/src/librustc_error_codes/error_codes/E0747.md +++ b/src/librustc_error_codes/error_codes/E0747.md @@ -9,3 +9,12 @@ struct S<'a, T>(&'a T); type X = S<(), 'static>; // error: the type argument is provided before the // lifetime argument ``` + +The argument order should be changed to match the parameter declaration +order, as in the following. + +``` +struct S<'a, T>(&'a T); + +type X = S<'static, ()>; // ok +``` diff --git a/src/test/ui/const-generics/const-param-after-const-literal-arg.rs b/src/test/ui/const-generics/const-param-after-const-literal-arg.rs index 683bcc867c799..19c4120eb2f14 100644 --- a/src/test/ui/const-generics/const-param-after-const-literal-arg.rs +++ b/src/test/ui/const-generics/const-param-after-const-literal-arg.rs @@ -1,7 +1,7 @@ // check-pass +#![allow(incomplete_features)] #![feature(const_generics)] -//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash struct Foo; diff --git a/src/test/ui/const-generics/const-param-after-const-literal-arg.stderr b/src/test/ui/const-generics/const-param-after-const-literal-arg.stderr deleted file mode 100644 index a949a6ec9ff5c..0000000000000 --- a/src/test/ui/const-generics/const-param-after-const-literal-arg.stderr +++ /dev/null @@ -1,8 +0,0 @@ -warning: the feature `const_generics` is incomplete and may cause the compiler to crash - --> $DIR/const-param-after-const-literal-arg.rs:3:12 - | -LL | #![feature(const_generics)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - diff --git a/src/test/ui/const-generics/const-param-before-other-params.rs b/src/test/ui/const-generics/const-param-before-other-params.rs index 2c81681b85e7d..756e961ce914f 100644 --- a/src/test/ui/const-generics/const-param-before-other-params.rs +++ b/src/test/ui/const-generics/const-param-before-other-params.rs @@ -1,5 +1,5 @@ +#![allow(incomplete_features)] #![feature(const_generics)] -//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash fn bar(_: &'a ()) { //~^ ERROR lifetime parameters must be declared prior to const parameters From bead79ebc6d0f605f42a0f8315ce9f5fe5764b99 Mon Sep 17 00:00:00 2001 From: varkor Date: Sat, 22 Feb 2020 02:35:24 +0000 Subject: [PATCH 12/12] Add note regarding argument ordering --- src/librustc_typeck/astconv.rs | 8 +++++--- .../const-generics/const-arg-type-arg-misordered.stderr | 2 ++ .../const-generics/const-param-before-other-params.stderr | 8 -------- src/test/ui/parser/issue-14303-fncall.stderr | 2 ++ src/test/ui/parser/issue-14303-path.stderr | 2 ++ src/test/ui/suggestions/suggest-move-types.stderr | 8 ++++++++ src/test/ui/traits/trait-object-vs-lifetime.stderr | 2 ++ 7 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 9a80452aef3d2..49f38d86d9161 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -464,15 +464,17 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { /// Report an error that a generic argument did not match the generic parameter that was /// expected. fn generic_arg_mismatch_err(sess: &Session, arg: &GenericArg<'_>, kind: &'static str) { - struct_span_err!( + let mut err = struct_span_err!( sess, arg.span(), E0747, "{} provided when a {} was expected", arg.descr(), kind, - ) - .emit(); + ); + // This note will be true as long as generic parameters are strictly ordered by their kind. + err.note(&format!("{} arguments must be provided before {} arguments", kind, arg.descr())); + err.emit(); } /// Creates the relevant generic argument substitutions diff --git a/src/test/ui/const-generics/const-arg-type-arg-misordered.stderr b/src/test/ui/const-generics/const-arg-type-arg-misordered.stderr index 225e1cd547e7c..150a6011c2c13 100644 --- a/src/test/ui/const-generics/const-arg-type-arg-misordered.stderr +++ b/src/test/ui/const-generics/const-arg-type-arg-misordered.stderr @@ -11,6 +11,8 @@ error[E0747]: constant provided when a type was expected | LL | fn foo() -> Array { | ^ + | + = note: type arguments must be provided before constant arguments error: aborting due to previous error diff --git a/src/test/ui/const-generics/const-param-before-other-params.stderr b/src/test/ui/const-generics/const-param-before-other-params.stderr index fccf732de4c99..9b18b8c79edda 100644 --- a/src/test/ui/const-generics/const-param-before-other-params.stderr +++ b/src/test/ui/const-generics/const-param-before-other-params.stderr @@ -10,13 +10,5 @@ error: type parameters must be declared prior to const parameters LL | fn foo(_: &T) { | --------------^- help: reorder the parameters: lifetimes, then types, then consts: `` -warning: the feature `const_generics` is incomplete and may cause the compiler to crash - --> $DIR/const-param-before-other-params.rs:1:12 - | -LL | #![feature(const_generics)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - error: aborting due to 2 previous errors diff --git a/src/test/ui/parser/issue-14303-fncall.stderr b/src/test/ui/parser/issue-14303-fncall.stderr index cdda0d001c7dc..109542237130a 100644 --- a/src/test/ui/parser/issue-14303-fncall.stderr +++ b/src/test/ui/parser/issue-14303-fncall.stderr @@ -3,6 +3,8 @@ error[E0747]: type provided when a lifetime was expected | LL | .collect::>>(); | ^ + | + = note: lifetime arguments must be provided before type arguments error: aborting due to previous error diff --git a/src/test/ui/parser/issue-14303-path.stderr b/src/test/ui/parser/issue-14303-path.stderr index 841e63ecbe9d5..c1ad2332b5bfa 100644 --- a/src/test/ui/parser/issue-14303-path.stderr +++ b/src/test/ui/parser/issue-14303-path.stderr @@ -3,6 +3,8 @@ error[E0747]: type provided when a lifetime was expected | LL | fn bar<'a, 'b, 'c, T>(x: foo::X<'a, T, 'b, 'c>) {} | ^ + | + = note: lifetime arguments must be provided before type arguments error: aborting due to previous error diff --git a/src/test/ui/suggestions/suggest-move-types.stderr b/src/test/ui/suggestions/suggest-move-types.stderr index 07ad1a3150836..ac91813f92839 100644 --- a/src/test/ui/suggestions/suggest-move-types.stderr +++ b/src/test/ui/suggestions/suggest-move-types.stderr @@ -79,24 +79,32 @@ error[E0747]: type provided when a lifetime was expected | LL | struct Al<'a, T, M: OneWithLifetime> { | ^ + | + = note: lifetime arguments must be provided before type arguments error[E0747]: type provided when a lifetime was expected --> $DIR/suggest-move-types.rs:48:71 | LL | struct Bl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime> { | ^ + | + = note: lifetime arguments must be provided before type arguments error[E0747]: lifetime provided when a type was expected --> $DIR/suggest-move-types.rs:64:56 | LL | struct Cl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime> { | ^^ + | + = note: type arguments must be provided before lifetime arguments error[E0747]: lifetime provided when a type was expected --> $DIR/suggest-move-types.rs:80:56 | LL | struct Dl<'a, 'b, 'c, T, U, V, M: ThreeWithLifetime> { | ^^ + | + = note: type arguments must be provided before lifetime arguments error: aborting due to 12 previous errors diff --git a/src/test/ui/traits/trait-object-vs-lifetime.stderr b/src/test/ui/traits/trait-object-vs-lifetime.stderr index d1e5a65c0ad68..04529fb8cfab3 100644 --- a/src/test/ui/traits/trait-object-vs-lifetime.stderr +++ b/src/test/ui/traits/trait-object-vs-lifetime.stderr @@ -27,6 +27,8 @@ error[E0747]: type provided when a lifetime was expected | LL | let _: S; | ^^^^^^^^^^^^^ + | + = note: lifetime arguments must be provided before type arguments error: aborting due to 5 previous errors