diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index a310828b9fbfa..cdcd221e811a7 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -397,6 +397,7 @@ pub struct GenericParam { pub bounds: GenericBounds, pub is_placeholder: bool, pub kind: GenericParamKind, + pub colon_span: Option, } impl GenericParam { diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index cba49835f69cb..d7b1bc6a7f580 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -867,9 +867,12 @@ pub fn noop_flat_map_generic_param( mut param: GenericParam, vis: &mut T, ) -> SmallVec<[GenericParam; 1]> { - let GenericParam { id, ident, attrs, bounds, kind, is_placeholder: _ } = &mut param; + let GenericParam { id, ident, attrs, bounds, kind, colon_span, is_placeholder: _ } = &mut param; vis.visit_id(id); vis.visit_ident(ident); + if let Some(ref mut colon_span) = colon_span { + vis.visit_span(colon_span); + } visit_thin_attrs(attrs, vis); visit_vec(bounds, |bound| noop_visit_param_bound(bound, vis)); match kind { diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 8ae07982f6f58..125acdcc27d97 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -267,9 +267,14 @@ impl<'hir> LoweringContext<'_, 'hir> { this.lower_maybe_async_body(span, &decl, asyncness, body.as_deref()); let (generics, decl) = - this.add_implicit_generics(generics, id, |this, idty| { + this.add_implicit_generics(generics, id, |this, idty, idpb| { let ret_id = asyncness.opt_return_id(); - this.lower_fn_decl(&decl, Some((id, idty)), FnDeclKind::Fn, ret_id) + this.lower_fn_decl( + &decl, + Some((id, idty, idpb)), + FnDeclKind::Fn, + ret_id, + ) }); let sig = hir::FnSig { decl, @@ -384,7 +389,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // lifetime to be added, but rather a reference to a // parent lifetime. let (generics, (trait_ref, lowered_ty)) = - self.add_implicit_generics(ast_generics, id, |this, _| { + self.add_implicit_generics(ast_generics, id, |this, _, _| { let trait_ref = trait_ref.as_ref().map(|trait_ref| { this.lower_trait_ref( trait_ref, @@ -410,7 +415,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ImplPolarity::Positive => ImplPolarity::Positive, ImplPolarity::Negative(s) => ImplPolarity::Negative(self.lower_span(s)), }; - hir::ItemKind::Impl(hir::Impl { + hir::ItemKind::Impl(self.arena.alloc(hir::Impl { unsafety: self.lower_unsafety(unsafety), polarity, defaultness, @@ -420,7 +425,7 @@ impl<'hir> LoweringContext<'_, 'hir> { of_trait: trait_ref, self_ty: lowered_ty, items: new_impl_items, - }) + })) } ItemKind::Trait(box Trait { is_auto, @@ -649,7 +654,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ForeignItemKind::Fn(box Fn { ref sig, ref generics, .. }) => { let fdec = &sig.decl; let (generics, (fn_dec, fn_args)) = - self.add_implicit_generics(generics, i.id, |this, _| { + self.add_implicit_generics(generics, i.id, |this, _, _| { ( // Disallow `impl Trait` in foreign items. this.lower_fn_decl(fdec, None, FnDeclKind::ExternFn, None), @@ -1226,10 +1231,10 @@ impl<'hir> LoweringContext<'_, 'hir> { id: NodeId, kind: FnDeclKind, is_async: Option, - ) -> (hir::Generics<'hir>, hir::FnSig<'hir>) { + ) -> (&'hir hir::Generics<'hir>, hir::FnSig<'hir>) { let header = self.lower_fn_header(sig.header); - let (generics, decl) = self.add_implicit_generics(generics, id, |this, idty| { - this.lower_fn_decl(&sig.decl, Some((id, idty)), kind, is_async) + let (generics, decl) = self.add_implicit_generics(generics, id, |this, idty, idpb| { + this.lower_fn_decl(&sig.decl, Some((id, idty, idpb)), kind, is_async) }); (generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) }) } @@ -1289,7 +1294,7 @@ impl<'hir> LoweringContext<'_, 'hir> { pub(super) fn lower_generics_mut( &mut self, generics: &Generics, - itctx: ImplTraitContext<'_, 'hir>, + mut itctx: ImplTraitContext<'_, 'hir>, ) -> GenericsCtor<'hir> { // Error if `?Trait` bounds in where clauses don't refer directly to type parameters. // Note: we used to clone these bounds directly onto the type parameter (and avoid lowering @@ -1338,9 +1343,24 @@ impl<'hir> LoweringContext<'_, 'hir> { } } + let mut predicates = SmallVec::new(); + predicates.extend(generics.params.iter().filter_map(|param| { + let bounds = self.lower_param_bounds(¶m.bounds, itctx.reborrow()); + self.lower_generic_bound_predicate(param.ident, param.id, ¶m.kind, bounds) + })); + predicates.extend( + generics + .where_clause + .predicates + .iter() + .map(|predicate| self.lower_where_predicate(predicate)), + ); + GenericsCtor { - params: self.lower_generic_params_mut(&generics.params, itctx).collect(), - where_clause: self.lower_where_clause(&generics.where_clause), + params: self.lower_generic_params_mut(&generics.params).collect(), + predicates, + has_where_clause: !generics.where_clause.predicates.is_empty(), + where_clause_span: self.lower_span(generics.where_clause.span), span: self.lower_span(generics.span), } } @@ -1349,17 +1369,74 @@ impl<'hir> LoweringContext<'_, 'hir> { &mut self, generics: &Generics, itctx: ImplTraitContext<'_, 'hir>, - ) -> hir::Generics<'hir> { + ) -> &'hir hir::Generics<'hir> { let generics_ctor = self.lower_generics_mut(generics, itctx); generics_ctor.into_generics(self.arena) } - fn lower_where_clause(&mut self, wc: &WhereClause) -> hir::WhereClause<'hir> { - hir::WhereClause { - predicates: self.arena.alloc_from_iter( - wc.predicates.iter().map(|predicate| self.lower_where_predicate(predicate)), - ), - span: self.lower_span(wc.span), + pub(super) fn lower_generic_bound_predicate( + &mut self, + ident: Ident, + id: NodeId, + kind: &GenericParamKind, + bounds: &'hir [hir::GenericBound<'hir>], + ) -> Option> { + // Do not create a clause if we do not have anything inside it. + if bounds.is_empty() { + return None; + } + let ident = self.lower_ident(ident); + let param_span = ident.span; + let span = bounds + .iter() + .fold(Some(param_span.shrink_to_hi()), |span: Option, bound| { + let bound_span = bound.span(); + // We include bounds that come from a `#[derive(_)]` but point at the user's code, + // as we use this method to get a span appropriate for suggestions. + if !bound_span.can_be_used_for_suggestions() { + None + } else if let Some(span) = span { + Some(span.to(bound_span)) + } else { + Some(bound_span) + } + }) + .unwrap_or(param_span.shrink_to_hi()); + match kind { + GenericParamKind::Const { .. } => None, + GenericParamKind::Type { .. } => { + let def_id = self.resolver.local_def_id(id).to_def_id(); + let ty_path = self.arena.alloc(hir::Path { + span: param_span, + res: Res::Def(DefKind::TyParam, def_id), + segments: self.arena.alloc_from_iter([hir::PathSegment::from_ident(ident)]), + }); + let ty_id = self.next_id(); + let bounded_ty = + self.ty_path(ty_id, param_span, hir::QPath::Resolved(None, ty_path)); + Some(hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate { + bounded_ty: self.arena.alloc(bounded_ty), + bounds, + span, + bound_generic_params: &[], + in_where_clause: false, + })) + } + GenericParamKind::Lifetime => { + let ident_span = self.lower_span(ident.span); + let ident = self.lower_ident(ident); + let res = self.resolver.get_lifetime_res(id).unwrap_or_else(|| { + panic!("Missing resolution for lifetime {:?} at {:?}", id, ident.span) + }); + let lt_id = self.resolver.next_node_id(); + let lifetime = self.new_named_lifetime_with_res(lt_id, ident_span, ident, res); + Some(hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate { + lifetime, + span, + bounds, + in_where_clause: false, + })) + } } } @@ -1371,10 +1448,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ref bounds, span, }) => hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate { - bound_generic_params: self.lower_generic_params( - bound_generic_params, - ImplTraitContext::Disallowed(ImplTraitPosition::Generic), - ), + bound_generic_params: self.lower_generic_params(bound_generic_params), bounded_ty: self .lower_ty(bounded_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type)), bounds: self.arena.alloc_from_iter(bounds.iter().map(|bound| { @@ -1384,6 +1458,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ) })), span: self.lower_span(span), + in_where_clause: true, }), WherePredicate::RegionPredicate(WhereRegionPredicate { ref lifetime, @@ -1396,6 +1471,7 @@ impl<'hir> LoweringContext<'_, 'hir> { bounds, ImplTraitContext::Disallowed(ImplTraitPosition::Bound), ), + in_where_clause: true, }), WherePredicate::EqPredicate(WhereEqPredicate { id, ref lhs_ty, ref rhs_ty, span }) => { hir::WherePredicate::EqPredicate(hir::WhereEqPredicate { @@ -1414,16 +1490,20 @@ impl<'hir> LoweringContext<'_, 'hir> { /// Helper struct for delayed construction of Generics. pub(super) struct GenericsCtor<'hir> { pub(super) params: SmallVec<[hir::GenericParam<'hir>; 4]>, - where_clause: hir::WhereClause<'hir>, + pub(super) predicates: SmallVec<[hir::WherePredicate<'hir>; 4]>, + has_where_clause: bool, + where_clause_span: Span, span: Span, } impl<'hir> GenericsCtor<'hir> { - pub(super) fn into_generics(self, arena: &'hir Arena<'hir>) -> hir::Generics<'hir> { - hir::Generics { + pub(super) fn into_generics(self, arena: &'hir Arena<'hir>) -> &'hir hir::Generics<'hir> { + arena.alloc(hir::Generics { params: arena.alloc_from_iter(self.params), - where_clause: self.where_clause, + predicates: arena.alloc_from_iter(self.predicates), + has_where_clause: self.has_where_clause, + where_clause_span: self.where_clause_span, span: self.span, - } + }) } } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index de4f8e04b1689..d433775f85cf3 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -259,7 +259,7 @@ enum ImplTraitContext<'b, 'a> { /// equivalent to a fresh universal parameter like `fn foo(x: T)`. /// /// Newly generated parameters should be inserted into the given `Vec`. - Universal(&'b mut Vec>, LocalDefId), + Universal(&'b mut Vec>, &'b mut Vec>, LocalDefId), /// Treat `impl Trait` as shorthand for a new opaque type. /// Example: `fn foo() -> impl Debug`, where `impl Debug` is conceptually @@ -303,7 +303,7 @@ impl<'a> ImplTraitContext<'_, 'a> { fn reborrow<'this>(&'this mut self) -> ImplTraitContext<'this, 'a> { use self::ImplTraitContext::*; match self { - Universal(params, parent) => Universal(params, *parent), + Universal(params, bounds, parent) => Universal(params, bounds, *parent), ReturnPositionOpaqueTy { origin } => ReturnPositionOpaqueTy { origin: *origin }, TypeAliasesOpaqueTy => TypeAliasesOpaqueTy, Disallowed(pos) => Disallowed(*pos), @@ -704,10 +704,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { Some(hir::GenericParam { hir_id, name, - bounds: &[], span: self.lower_span(ident.span), pure_wrt_drop: false, kind: hir::GenericParamKind::Lifetime { kind }, + colon_span: None, }) } @@ -718,14 +718,23 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { &mut self, generics: &Generics, parent_node_id: NodeId, - f: impl FnOnce(&mut Self, &mut Vec>) -> T, - ) -> (hir::Generics<'hir>, T) { + f: impl FnOnce( + &mut Self, + &mut Vec>, + &mut Vec>, + ) -> T, + ) -> (&'hir hir::Generics<'hir>, T) { let mut impl_trait_defs = Vec::new(); + let mut impl_trait_bounds = Vec::new(); let mut lowered_generics = self.lower_generics_mut( generics, - ImplTraitContext::Universal(&mut impl_trait_defs, self.current_hir_id_owner), + ImplTraitContext::Universal( + &mut impl_trait_defs, + &mut impl_trait_bounds, + self.current_hir_id_owner, + ), ); - let res = f(self, &mut impl_trait_defs); + let res = f(self, &mut impl_trait_defs, &mut impl_trait_bounds); let extra_lifetimes = self.resolver.take_extra_lifetime_params(parent_node_id); lowered_generics.params.extend( @@ -736,6 +745,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }) .chain(impl_trait_defs), ); + lowered_generics.predicates.extend(impl_trait_bounds); let lowered_generics = lowered_generics.into_generics(self.arena); (lowered_generics, res) @@ -999,7 +1009,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // so desugar to // // fn foo(x: dyn Iterator) - ImplTraitContext::Universal(_, parent) if self.is_in_dyn_type => { + ImplTraitContext::Universal(_, _, parent) if self.is_in_dyn_type => { parent_def_id = parent; (true, itctx) } @@ -1188,10 +1198,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } TyKind::BareFn(ref f) => self.with_lifetime_binder(t.id, |this| { hir::TyKind::BareFn(this.arena.alloc(hir::BareFnTy { - generic_params: this.lower_generic_params( - &f.generic_params, - ImplTraitContext::Disallowed(ImplTraitPosition::Generic), - ), + generic_params: this.lower_generic_params(&f.generic_params), unsafety: this.lower_unsafety(f.unsafety), abi: this.lower_extern(f.ext), decl: this.lower_fn_decl(&f.decl, None, FnDeclKind::Pointer, None), @@ -1274,13 +1281,21 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { |this| this.lower_param_bounds(bounds, nested_itctx), ) } - ImplTraitContext::Universal(in_band_ty_params, parent_def_id) => { + ImplTraitContext::Universal( + in_band_ty_params, + in_band_ty_bounds, + parent_def_id, + ) => { // Add a definition for the in-band `Param`. let def_id = self.resolver.local_def_id(def_node_id); let hir_bounds = self.lower_param_bounds( bounds, - ImplTraitContext::Universal(in_band_ty_params, parent_def_id), + ImplTraitContext::Universal( + in_band_ty_params, + in_band_ty_bounds, + parent_def_id, + ), ); // Set the name to `impl Bound1 + Bound2`. let ident = Ident::from_str_and_span(&pprust::ty_to_string(t), span); @@ -1288,10 +1303,18 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { hir_id: self.lower_node_id(def_node_id), name: ParamName::Plain(self.lower_ident(ident)), pure_wrt_drop: false, - bounds: hir_bounds, span: self.lower_span(span), kind: hir::GenericParamKind::Type { default: None, synthetic: true }, + colon_span: None, }); + if let Some(preds) = self.lower_generic_bound_predicate( + ident, + def_node_id, + &GenericParamKind::Type { default: None }, + hir_bounds, + ) { + in_band_ty_bounds.push(preds) + } hir::TyKind::Path(hir::QPath::Resolved( None, @@ -1374,8 +1397,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { name: p_name, span, pure_wrt_drop: false, - bounds: &[], kind: hir::GenericParamKind::Lifetime { kind }, + colon_span: None, } }, )); @@ -1383,11 +1406,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { debug!("lower_opaque_impl_trait: lifetime_defs={:#?}", lifetime_defs); let opaque_ty_item = hir::OpaqueTy { - generics: hir::Generics { + generics: self.arena.alloc(hir::Generics { params: lifetime_defs, - where_clause: hir::WhereClause { predicates: &[], span: lctx.lower_span(span) }, + predicates: &[], + has_where_clause: false, + where_clause_span: lctx.lower_span(span), span: lctx.lower_span(span), - }, + }), bounds: hir_bounds, origin, }; @@ -1462,7 +1487,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_fn_decl( &mut self, decl: &FnDecl, - mut in_band_ty_params: Option<(NodeId, &mut Vec>)>, + mut in_band_ty_params: Option<( + NodeId, + &mut Vec>, + &mut Vec>, + )>, kind: FnDeclKind, make_ret_async: Option, ) -> &'hir hir::FnDecl<'hir> { @@ -1485,10 +1514,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { inputs = &inputs[..inputs.len() - 1]; } let inputs = self.arena.alloc_from_iter(inputs.iter().map(|param| { - if let Some((_, ibty)) = &mut in_band_ty_params { + if let Some((_, ibty, ibpb)) = &mut in_band_ty_params { self.lower_ty_direct( ¶m.ty, - ImplTraitContext::Universal(ibty, self.current_hir_id_owner), + ImplTraitContext::Universal(ibty, ibpb, self.current_hir_id_owner), ) } else { self.lower_ty_direct( @@ -1517,7 +1546,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { match decl.output { FnRetTy::Ty(ref ty) => { let context = match in_band_ty_params { - Some((node_id, _)) if kind.impl_trait_return_allowed() => { + Some((node_id, _, _)) if kind.impl_trait_return_allowed() => { let fn_def_id = self.resolver.local_def_id(node_id); ImplTraitContext::ReturnPositionOpaqueTy { origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id), @@ -1708,18 +1737,20 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { name: p_name, span, pure_wrt_drop: false, - bounds: &[], kind: hir::GenericParamKind::Lifetime { kind }, + colon_span: None, } })); debug!("lower_async_fn_ret_ty: generic_params={:#?}", generic_params); let opaque_ty_item = hir::OpaqueTy { - generics: hir::Generics { + generics: this.arena.alloc(hir::Generics { params: generic_params, - where_clause: hir::WhereClause { predicates: &[], span: this.lower_span(span) }, + predicates: &[], + has_where_clause: false, + where_clause_span: this.lower_span(span), span: this.lower_span(span), - }, + }), bounds: arena_vec![this; future_bound], origin: hir::OpaqueTyOrigin::AsyncFn(fn_def_id), }; @@ -1923,26 +1954,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn lower_generic_params_mut<'s>( &'s mut self, params: &'s [GenericParam], - mut itctx: ImplTraitContext<'s, 'hir>, ) -> impl Iterator> + Captures<'a> + Captures<'s> { - params.iter().map(move |param| self.lower_generic_param(param, itctx.reborrow())) + params.iter().map(move |param| self.lower_generic_param(param)) } - fn lower_generic_params( - &mut self, - params: &[GenericParam], - itctx: ImplTraitContext<'_, 'hir>, - ) -> &'hir [hir::GenericParam<'hir>] { - self.arena.alloc_from_iter(self.lower_generic_params_mut(params, itctx)) + fn lower_generic_params(&mut self, params: &[GenericParam]) -> &'hir [hir::GenericParam<'hir>] { + self.arena.alloc_from_iter(self.lower_generic_params_mut(params)) } - fn lower_generic_param( - &mut self, - param: &GenericParam, - mut itctx: ImplTraitContext<'_, 'hir>, - ) -> hir::GenericParam<'hir> { - let bounds: Vec<_> = self.lower_param_bounds_mut(¶m.bounds, itctx.reborrow()).collect(); - + fn lower_generic_param(&mut self, param: &GenericParam) -> hir::GenericParam<'hir> { let (name, kind) = match param.kind { GenericParamKind::Lifetime => { let param_name = if param.ident.name == kw::StaticLifetime @@ -1989,8 +2009,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { name, span: self.lower_span(param.span()), pure_wrt_drop: self.sess.contains_name(¶m.attrs, sym::may_dangle), - bounds: self.arena.alloc_from_iter(bounds), kind, + colon_span: param.colon_span.map(|s| self.lower_span(s)), } } @@ -2012,8 +2032,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { p: &PolyTraitRef, mut itctx: ImplTraitContext<'_, 'hir>, ) -> hir::PolyTraitRef<'hir> { - let bound_generic_params = - self.lower_generic_params(&p.bound_generic_params, itctx.reborrow()); + let bound_generic_params = self.lower_generic_params(&p.bound_generic_params); let trait_ref = self.with_lifetime_binder(p.trait_ref.ref_id, |this| { this.lower_trait_ref(&p.trait_ref, itctx.reborrow()) diff --git a/compiler/rustc_builtin_macros/src/derive.rs b/compiler/rustc_builtin_macros/src/derive.rs index 61681ec66a48d..391c46d18132f 100644 --- a/compiler/rustc_builtin_macros/src/derive.rs +++ b/compiler/rustc_builtin_macros/src/derive.rs @@ -95,6 +95,7 @@ fn dummy_annotatable() -> Annotatable { bounds: Default::default(), is_placeholder: false, kind: GenericParamKind::Lifetime, + colon_span: None, }) } diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index b8ed75cb6bb74..301c67f702645 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -113,6 +113,7 @@ impl<'a> ExtCtxt<'a> { bounds, kind: ast::GenericParamKind::Type { default }, is_placeholder: false, + colon_span: None, } } diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs index 15af5fdc5f8e2..0d5d6ee07944f 100644 --- a/compiler/rustc_expand/src/placeholders.rs +++ b/compiler/rustc_expand/src/placeholders.rs @@ -149,6 +149,7 @@ pub fn placeholder( ident, is_placeholder: true, kind: ast::GenericParamKind::Lifetime, + colon_span: None, } }]), AstFragmentKind::Params => AstFragment::Params(smallvec![ast::Param { diff --git a/compiler/rustc_hir/src/arena.rs b/compiler/rustc_hir/src/arena.rs index 27ec461906419..5d1314ebb488d 100644 --- a/compiler/rustc_hir/src/arena.rs +++ b/compiler/rustc_hir/src/arena.rs @@ -15,11 +15,13 @@ macro_rules! arena_types { [] block: rustc_hir::Block<'tcx>, [] bare_fn_ty: rustc_hir::BareFnTy<'tcx>, [] body: rustc_hir::Body<'tcx>, + [] generics: rustc_hir::Generics<'tcx>, [] generic_arg: rustc_hir::GenericArg<'tcx>, [] generic_args: rustc_hir::GenericArgs<'tcx>, [] generic_bound: rustc_hir::GenericBound<'tcx>, [] generic_param: rustc_hir::GenericParam<'tcx>, [] expr: rustc_hir::Expr<'tcx>, + [] impl_: rustc_hir::Impl<'tcx>, [] let_expr: rustc_hir::Let<'tcx>, [] expr_field: rustc_hir::ExprField<'tcx>, [] pat_field: rustc_hir::PatField<'tcx>, diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 7d9203b70abe8..dfeee3f356ffb 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -17,7 +17,7 @@ use rustc_error_messages::MultiSpan; use rustc_index::vec::IndexVec; use rustc_macros::HashStable_Generic; use rustc_span::hygiene::MacroKind; -use rustc_span::source_map::{SourceMap, Spanned}; +use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{def_id::LocalDefId, BytePos, Span, DUMMY_SP}; use rustc_target::asm::InlineAsmRegOrRegClass; @@ -496,61 +496,25 @@ pub enum GenericParamKind<'hir> { pub struct GenericParam<'hir> { pub hir_id: HirId, pub name: ParamName, - pub bounds: GenericBounds<'hir>, pub span: Span, pub pure_wrt_drop: bool, pub kind: GenericParamKind<'hir>, + pub colon_span: Option, } impl<'hir> GenericParam<'hir> { - pub fn bounds_span_for_suggestions(&self) -> Option { - self.bounds - .iter() - .fold(None, |span: Option, bound| { - // We include bounds that come from a `#[derive(_)]` but point at the user's code, - // as we use this method to get a span appropriate for suggestions. - if !bound.span().can_be_used_for_suggestions() { - None - } else { - let span = span.map(|s| s.to(bound.span())).unwrap_or_else(|| bound.span()); - Some(span) - } - }) - .map(|sp| sp.shrink_to_hi()) + /// Synthetic type-parameters are inserted after normal ones. + /// In order for normal parameters to be able to refer to synthetic ones, + /// scans them first. + pub fn is_impl_trait(&self) -> bool { + matches!(self.kind, GenericParamKind::Type { synthetic: true, .. }) } - /// Returns the span of `:` after a generic parameter. + /// This can happen for `async fn`, e.g. `async fn f<'_>(&'_ self)`. /// - /// For example: - /// - /// ```text - /// fn a() - /// ^ - /// | here - /// here | - /// v - /// fn b() - /// - /// fn c() - /// ^ - /// | - /// here - /// ``` - pub fn colon_span_for_suggestions(&self, source_map: &SourceMap) -> Option { - let sp = source_map - .span_extend_while(self.span.shrink_to_hi(), |c| c.is_whitespace() || c == ':') - .ok()?; - - let snippet = source_map.span_to_snippet(sp).ok()?; - let offset = snippet.find(':')?; - - let colon_sp = sp - .with_lo(BytePos(sp.lo().0 + offset as u32)) - .with_hi(BytePos(sp.lo().0 + (offset + ':'.len_utf8()) as u32)); - - Some(colon_sp) + /// See `lifetime_to_generic_param` in `rustc_ast_lowering` for more information. + pub fn is_elided_lifetime(&self) -> bool { + matches!(self.kind, GenericParamKind::Lifetime { kind: LifetimeParamKind::Elided }) } } @@ -567,17 +531,22 @@ pub struct GenericParamCount { #[derive(Debug, HashStable_Generic)] pub struct Generics<'hir> { pub params: &'hir [GenericParam<'hir>], - pub where_clause: WhereClause<'hir>, + pub predicates: &'hir [WherePredicate<'hir>], + pub has_where_clause: bool, + pub where_clause_span: Span, pub span: Span, } impl<'hir> Generics<'hir> { - pub const fn empty() -> Generics<'hir> { - Generics { + pub const fn empty() -> &'hir Generics<'hir> { + const NOPE: Generics<'_> = Generics { params: &[], - where_clause: WhereClause { predicates: &[], span: DUMMY_SP }, + predicates: &[], + has_where_clause: false, + where_clause_span: DUMMY_SP, span: DUMMY_SP, - } + }; + &NOPE } pub fn get_named(&self, name: Symbol) -> Option<&GenericParam<'_>> { @@ -596,32 +565,122 @@ impl<'hir> Generics<'hir> { self.params.iter().map(|p| p.span).collect::>().into() } } -} -/// A where-clause in a definition. -#[derive(Debug, HashStable_Generic)] -pub struct WhereClause<'hir> { - pub predicates: &'hir [WherePredicate<'hir>], - // Only valid if predicates aren't empty. - pub span: Span, -} + /// If there are generic parameters, return where to introduce a new one. + pub fn span_for_param_suggestion(&self) -> Option { + if self.params.iter().any(|p| self.span.contains(p.span)) { + // `fn foo(t: impl Trait)` + // ^ suggest `, T: Trait` here + let span = self.span.with_lo(self.span.hi() - BytePos(1)).shrink_to_lo(); + Some(span) + } else { + None + } + } -impl WhereClause<'_> { - pub fn span(&self) -> Option { - if self.predicates.is_empty() { None } else { Some(self.span) } + pub fn where_clause_span(&self) -> Option { + if self.predicates.is_empty() { None } else { Some(self.where_clause_span) } } - /// The `WhereClause` under normal circumstances points at either the predicates or the empty + /// The `where_span` under normal circumstances points at either the predicates or the empty /// space where the `where` clause should be. Only of use for diagnostic suggestions. pub fn span_for_predicates_or_empty_place(&self) -> Span { - self.span + self.where_clause_span } /// `Span` where further predicates would be suggested, accounting for trailing commas, like /// in `fn foo(t: T) where T: Foo,` so we don't suggest two trailing commas. - pub fn tail_span_for_suggestion(&self) -> Span { + pub fn tail_span_for_predicate_suggestion(&self) -> Span { let end = self.span_for_predicates_or_empty_place().shrink_to_hi(); - self.predicates.last().map_or(end, |p| p.span()).shrink_to_hi().to(end) + if self.has_where_clause { + self.predicates + .iter() + .filter(|p| p.in_where_clause()) + .last() + .map_or(end, |p| p.span()) + .shrink_to_hi() + .to(end) + } else { + end + } + } + + pub fn bounds_for_param( + &self, + param_def_id: LocalDefId, + ) -> impl Iterator> { + self.predicates.iter().filter_map(move |pred| match pred { + WherePredicate::BoundPredicate(bp) if bp.is_param_bound(param_def_id.to_def_id()) => { + Some(bp) + } + _ => None, + }) + } + + pub fn bounds_span_for_suggestions(&self, param_def_id: LocalDefId) -> Option { + self.bounds_for_param(param_def_id).flat_map(|bp| bp.bounds.iter().rev()).find_map( + |bound| { + // We include bounds that come from a `#[derive(_)]` but point at the user's code, + // as we use this method to get a span appropriate for suggestions. + let bs = bound.span(); + if bs.can_be_used_for_suggestions() { Some(bs.shrink_to_hi()) } else { None } + }, + ) + } + + pub fn span_for_predicate_removal(&self, pos: usize) -> Span { + let predicate = &self.predicates[pos]; + let span = predicate.span(); + + if !predicate.in_where_clause() { + // + // ^^^^^^^^ + return span; + } + + // We need to find out which comma to remove. + if pos < self.predicates.len() - 1 { + let next_pred = &self.predicates[pos + 1]; + if next_pred.in_where_clause() { + // where T: ?Sized, Foo: Bar, + // ^^^^^^^^^^^ + return span.until(next_pred.span()); + } + } + + if pos > 0 { + let prev_pred = &self.predicates[pos - 1]; + if prev_pred.in_where_clause() { + // where Foo: Bar, T: ?Sized, + // ^^^^^^^^^^^ + return prev_pred.span().shrink_to_hi().to(span); + } + } + + // This is the only predicate in the where clause. + // where T: ?Sized + // ^^^^^^^^^^^^^^^ + self.where_clause_span + } + + pub fn span_for_bound_removal(&self, predicate_pos: usize, bound_pos: usize) -> Span { + let predicate = &self.predicates[predicate_pos]; + let bounds = predicate.bounds(); + + if bounds.len() == 1 { + return self.span_for_predicate_removal(predicate_pos); + } + + let span = bounds[bound_pos].span(); + if bound_pos == 0 { + // where T: ?Sized + Bar, Foo: Bar, + // ^^^^^^^^^ + span.to(bounds[1].span().shrink_to_lo()) + } else { + // where T: Bar + ?Sized, Foo: Bar, + // ^^^^^^^^^ + bounds[bound_pos - 1].span().shrink_to_hi().to(span) + } } } @@ -644,12 +703,29 @@ impl<'hir> WherePredicate<'hir> { WherePredicate::EqPredicate(p) => p.span, } } + + pub fn in_where_clause(&self) -> bool { + match self { + WherePredicate::BoundPredicate(p) => p.in_where_clause, + WherePredicate::RegionPredicate(p) => p.in_where_clause, + WherePredicate::EqPredicate(_) => false, + } + } + + pub fn bounds(&self) -> GenericBounds<'hir> { + match self { + WherePredicate::BoundPredicate(p) => p.bounds, + WherePredicate::RegionPredicate(p) => p.bounds, + WherePredicate::EqPredicate(_) => &[], + } + } } /// A type bound (e.g., `for<'c> Foo: Send + Clone + 'c`). #[derive(Debug, HashStable_Generic)] pub struct WhereBoundPredicate<'hir> { pub span: Span, + pub in_where_clause: bool, /// Any generics from a `for` binding. pub bound_generic_params: &'hir [GenericParam<'hir>], /// The type being bounded. @@ -661,14 +737,7 @@ pub struct WhereBoundPredicate<'hir> { impl<'hir> WhereBoundPredicate<'hir> { /// Returns `true` if `param_def_id` matches the `bounded_ty` of this predicate. pub fn is_param_bound(&self, param_def_id: DefId) -> bool { - let TyKind::Path(QPath::Resolved(None, path)) = self.bounded_ty.kind else { - return false; - }; - match path.res { - Res::Def(DefKind::TyParam, def_id) - | Res::SelfTy { trait_: Some(def_id), alias_to: None } => def_id == param_def_id, - _ => false, - } + self.bounded_ty.as_generic_param().map_or(false, |(def_id, _)| def_id == param_def_id) } } @@ -676,6 +745,7 @@ impl<'hir> WhereBoundPredicate<'hir> { #[derive(Debug, HashStable_Generic)] pub struct WhereRegionPredicate<'hir> { pub span: Span, + pub in_where_clause: bool, pub lifetime: Lifetime, pub bounds: GenericBounds<'hir>, } @@ -2075,7 +2145,7 @@ impl TraitItemId { pub struct TraitItem<'hir> { pub ident: Ident, pub def_id: LocalDefId, - pub generics: Generics<'hir>, + pub generics: &'hir Generics<'hir>, pub kind: TraitItemKind<'hir>, pub span: Span, } @@ -2135,7 +2205,7 @@ impl ImplItemId { pub struct ImplItem<'hir> { pub ident: Ident, pub def_id: LocalDefId, - pub generics: Generics<'hir>, + pub generics: &'hir Generics<'hir>, pub kind: ImplItemKind<'hir>, pub span: Span, pub vis_span: Span, @@ -2241,6 +2311,23 @@ pub struct Ty<'hir> { pub span: Span, } +impl<'hir> Ty<'hir> { + /// Returns `true` if `param_def_id` matches the `bounded_ty` of this predicate. + pub fn as_generic_param(&self) -> Option<(DefId, Ident)> { + let TyKind::Path(QPath::Resolved(None, path)) = self.kind else { + return None; + }; + let [segment] = &path.segments else { + return None; + }; + match path.res { + Res::Def(DefKind::TyParam, def_id) + | Res::SelfTy { trait_: Some(def_id), alias_to: None } => Some((def_id, segment.ident)), + _ => None, + } + } +} + /// Not represented directly in the AST; referred to by name through a `ty_path`. #[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, Debug)] #[derive(HashStable_Generic)] @@ -2340,7 +2427,7 @@ pub struct BareFnTy<'hir> { #[derive(Debug, HashStable_Generic)] pub struct OpaqueTy<'hir> { - pub generics: Generics<'hir>, + pub generics: &'hir Generics<'hir>, pub bounds: GenericBounds<'hir>, pub origin: OpaqueTyOrigin, } @@ -2814,7 +2901,7 @@ pub enum ItemKind<'hir> { /// A `const` item. Const(&'hir Ty<'hir>, BodyId), /// A function declaration. - Fn(FnSig<'hir>, Generics<'hir>, BodyId), + Fn(FnSig<'hir>, &'hir Generics<'hir>, BodyId), /// A MBE macro definition (`macro_rules!` or `macro`). Macro(ast::MacroDef, MacroKind), /// A module. @@ -2824,22 +2911,22 @@ pub enum ItemKind<'hir> { /// Module-level inline assembly (from `global_asm!`). GlobalAsm(&'hir InlineAsm<'hir>), /// A type alias, e.g., `type Foo = Bar`. - TyAlias(&'hir Ty<'hir>, Generics<'hir>), + TyAlias(&'hir Ty<'hir>, &'hir Generics<'hir>), /// An opaque `impl Trait` type alias, e.g., `type Foo = impl Bar;`. OpaqueTy(OpaqueTy<'hir>), /// An enum definition, e.g., `enum Foo {C, D}`. - Enum(EnumDef<'hir>, Generics<'hir>), + Enum(EnumDef<'hir>, &'hir Generics<'hir>), /// A struct definition, e.g., `struct Foo {x: A}`. - Struct(VariantData<'hir>, Generics<'hir>), + Struct(VariantData<'hir>, &'hir Generics<'hir>), /// A union definition, e.g., `union Foo {x: A, y: B}`. - Union(VariantData<'hir>, Generics<'hir>), + Union(VariantData<'hir>, &'hir Generics<'hir>), /// A trait definition. - Trait(IsAuto, Unsafety, Generics<'hir>, GenericBounds<'hir>, &'hir [TraitItemRef]), + Trait(IsAuto, Unsafety, &'hir Generics<'hir>, GenericBounds<'hir>, &'hir [TraitItemRef]), /// A trait alias. - TraitAlias(Generics<'hir>, GenericBounds<'hir>), + TraitAlias(&'hir Generics<'hir>, GenericBounds<'hir>), /// An implementation, e.g., `impl Trait for Foo { .. }`. - Impl(Impl<'hir>), + Impl(&'hir Impl<'hir>), } #[derive(Debug, HashStable_Generic)] @@ -2851,7 +2938,7 @@ pub struct Impl<'hir> { // decoding as `Span`s cannot be decoded when a `Session` is not available. pub defaultness_span: Option, pub constness: Constness, - pub generics: Generics<'hir>, + pub generics: &'hir Generics<'hir>, /// The trait being implemented, if any. pub of_trait: Option>, @@ -2993,7 +3080,7 @@ impl ForeignItem<'_> { #[derive(Debug, HashStable_Generic)] pub enum ForeignItemKind<'hir> { /// A foreign function. - Fn(&'hir FnDecl<'hir>, &'hir [Ident], Generics<'hir>), + Fn(&'hir FnDecl<'hir>, &'hir [Ident], &'hir Generics<'hir>), /// A foreign static item (`static ext: u8`). Static(&'hir Ty<'hir>, Mutability), /// A foreign type. @@ -3326,9 +3413,11 @@ mod size_asserts { rustc_data_structures::static_assert_size!(super::QPath<'static>, 24); rustc_data_structures::static_assert_size!(super::Ty<'static>, 72); rustc_data_structures::static_assert_size!(super::GenericBound<'_>, 48); + rustc_data_structures::static_assert_size!(super::Generics<'static>, 56); + rustc_data_structures::static_assert_size!(super::Impl<'static>, 80); - rustc_data_structures::static_assert_size!(super::Item<'static>, 160); - rustc_data_structures::static_assert_size!(super::TraitItem<'static>, 128); - rustc_data_structures::static_assert_size!(super::ImplItem<'static>, 120); - rustc_data_structures::static_assert_size!(super::ForeignItem<'static>, 112); + rustc_data_structures::static_assert_size!(super::Item<'static>, 80); + rustc_data_structures::static_assert_size!(super::TraitItem<'static>, 88); + rustc_data_structures::static_assert_size!(super::ImplItem<'static>, 80); + rustc_data_structures::static_assert_size!(super::ForeignItem<'static>, 72); } diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 59bd46ae353b2..d41b85fd20f7b 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -619,7 +619,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) { visitor.visit_generics(generics); walk_list!(visitor, visit_trait_ref, of_trait); visitor.visit_ty(self_ty); - walk_list!(visitor, visit_impl_item_ref, items); + walk_list!(visitor, visit_impl_item_ref, *items); } ItemKind::Struct(ref struct_definition, ref generics) | ItemKind::Union(ref struct_definition, ref generics) => { @@ -899,7 +899,6 @@ pub fn walk_generic_param<'v, V: Visitor<'v>>(visitor: &mut V, param: &'v Generi } } } - walk_list!(visitor, visit_param_bound, param.bounds); } pub fn walk_const_param_default<'v, V: Visitor<'v>>(visitor: &mut V, ct: &'v AnonConst) { @@ -908,7 +907,7 @@ pub fn walk_const_param_default<'v, V: Visitor<'v>>(visitor: &mut V, ct: &'v Ano pub fn walk_generics<'v, V: Visitor<'v>>(visitor: &mut V, generics: &'v Generics<'v>) { walk_list!(visitor, visit_generic_param, generics.params); - walk_list!(visitor, visit_where_predicate, generics.where_clause.predicates); + walk_list!(visitor, visit_where_predicate, generics.predicates); } pub fn walk_where_predicate<'v, V: Visitor<'v>>( diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 87ff94577836c..7af9622b2cf76 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -445,7 +445,7 @@ impl<'a> State<'a> { if let Some(bounds) = bounds { self.print_bounds(":", bounds); } - self.print_where_clause(&generics.where_clause); + self.print_where_clause(generics); if let Some(ty) = ty { self.space(); self.word_space("="); @@ -465,7 +465,7 @@ impl<'a> State<'a> { self.print_generic_params(&generics.params); self.end(); // end the inner ibox - self.print_where_clause(&generics.where_clause); + self.print_where_clause(generics); self.space(); inner(self); self.word(";"); @@ -626,8 +626,8 @@ impl<'a> State<'a> { items, }) => { self.head(""); - self.print_defaultness(defaultness); - self.print_unsafety(unsafety); + self.print_defaultness(*defaultness); + self.print_unsafety(*unsafety); self.word_nbsp("impl"); if !generics.params.is_empty() { @@ -635,7 +635,7 @@ impl<'a> State<'a> { self.space(); } - if constness == hir::Constness::Const { + if *constness == hir::Constness::Const { self.word_nbsp("const"); } @@ -650,12 +650,12 @@ impl<'a> State<'a> { } self.print_type(&self_ty); - self.print_where_clause(&generics.where_clause); + self.print_where_clause(generics); self.space(); self.bopen(); self.print_inner_attributes(attrs); - for impl_item in items { + for impl_item in *items { self.ann.nested(self, Nested::ImplItem(impl_item.id)); } self.bclose(item.span); @@ -678,7 +678,7 @@ impl<'a> State<'a> { } } self.print_bounds(":", real_bounds); - self.print_where_clause(&generics.where_clause); + self.print_where_clause(generics); self.word(" "); self.bopen(); for trait_item in trait_items { @@ -703,7 +703,7 @@ impl<'a> State<'a> { } self.nbsp(); self.print_bounds("=", real_bounds); - self.print_where_clause(&generics.where_clause); + self.print_where_clause(generics); self.word(";"); self.end(); // end inner head-block self.end(); // end outer head-block @@ -739,7 +739,7 @@ impl<'a> State<'a> { self.head("enum"); self.print_name(name); self.print_generic_params(&generics.params); - self.print_where_clause(&generics.where_clause); + self.print_where_clause(generics); self.space(); self.print_variants(&enum_definition.variants, span) } @@ -787,7 +787,7 @@ impl<'a> State<'a> { }); self.pclose(); } - self.print_where_clause(&generics.where_clause); + self.print_where_clause(generics); if print_finalizer { self.word(";"); } @@ -795,7 +795,7 @@ impl<'a> State<'a> { self.end() // close the outer-box } hir::VariantData::Struct(..) => { - self.print_where_clause(&generics.where_clause); + self.print_where_clause(generics); self.nbsp(); self.bopen(); self.hardbreak_if_not_bol(); @@ -1995,7 +1995,7 @@ impl<'a> State<'a> { self.pclose(); self.print_fn_output(decl); - self.print_where_clause(&generics.where_clause) + self.print_where_clause(generics) } fn print_closure_params(&mut self, decl: &hir::FnDecl<'_>, body_id: hir::BodyId) { @@ -2096,21 +2096,8 @@ impl<'a> State<'a> { self.print_ident(param.name.ident()); match param.kind { - GenericParamKind::Lifetime { .. } => { - let mut sep = ":"; - for bound in param.bounds { - match bound { - GenericBound::Outlives(ref lt) => { - self.word(sep); - self.print_lifetime(lt); - sep = "+"; - } - _ => panic!(), - } - } - } + GenericParamKind::Lifetime { .. } => {} GenericParamKind::Type { ref default, .. } => { - self.print_bounds(":", param.bounds); if let Some(default) = default { self.space(); self.word_space("="); @@ -2133,15 +2120,15 @@ impl<'a> State<'a> { self.print_ident(lifetime.name.ident()) } - pub fn print_where_clause(&mut self, where_clause: &hir::WhereClause<'_>) { - if where_clause.predicates.is_empty() { + pub fn print_where_clause(&mut self, generics: &hir::Generics<'_>) { + if generics.predicates.is_empty() { return; } self.space(); self.word_space("where"); - for (i, predicate) in where_clause.predicates.iter().enumerate() { + for (i, predicate) in generics.predicates.iter().enumerate() { if i != 0 { self.word_space(","); } @@ -2236,11 +2223,7 @@ impl<'a> State<'a> { ) { self.ibox(INDENT_UNIT); self.print_formal_generic_params(generic_params); - let generics = hir::Generics { - params: &[], - where_clause: hir::WhereClause { predicates: &[], span: rustc_span::DUMMY_SP }, - span: rustc_span::DUMMY_SP, - }; + let generics = hir::Generics::empty(); self.print_fn( decl, hir::FnHeader { diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 14555ad92559d..2e50dbff51089 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -2327,6 +2327,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { _ => span, }; + // type_param_span is (span, has_bounds) let type_param_span = match (generics, bound_kind) { (Some((_, ref generics, _)), GenericKind::Param(ref param)) => { // Account for the case where `param` corresponds to `Self`, @@ -2337,25 +2338,18 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // Get the `hir::Param` to verify whether it already has any bounds. // We do this to avoid suggesting code that ends up as `T: 'a'b`, // instead we suggest `T: 'a + 'b` in that case. - let id = hir.local_def_id_to_hir_id(def_id); - let mut has_bounds = false; - if let Node::GenericParam(param) = hir.get(id) { - has_bounds = !param.bounds.is_empty(); - } - let sp = self.tcx.def_span(def_id); + let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id); + let ast_generics = self.tcx.hir().get_generics(hir_id.owner); + let bounds = + ast_generics.and_then(|g| g.bounds_span_for_suggestions(def_id)); // `sp` only covers `T`, change it so that it covers // `T:` when appropriate - let is_impl_trait = bound_kind.to_string().starts_with("impl "); - let sp = if has_bounds && !is_impl_trait { - sp.to(self - .tcx - .sess - .source_map() - .next_point(self.tcx.sess.source_map().next_point(sp))) + if let Some(span) = bounds { + (span, true) } else { - sp - }; - (sp, has_bounds, is_impl_trait) + let sp = self.tcx.def_span(def_id); + (sp.shrink_to_hi(), false) + } }) } else { None @@ -2411,52 +2405,37 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { fn binding_suggestion<'tcx, S: fmt::Display>( err: &mut Diagnostic, - type_param_span: Option<(Span, bool, bool)>, + type_param_span: Option<(Span, bool)>, bound_kind: GenericKind<'tcx>, sub: S, ) { let msg = "consider adding an explicit lifetime bound"; - if let Some((sp, has_lifetimes, is_impl_trait)) = type_param_span { - let suggestion = if is_impl_trait { - format!("{} + {}", bound_kind, sub) - } else { - let tail = if has_lifetimes { " + " } else { "" }; - format!("{}: {}{}", bound_kind, sub, tail) - }; - err.span_suggestion( + if let Some((sp, has_lifetimes)) = type_param_span { + let suggestion = + if has_lifetimes { format!(" + {}", sub) } else { format!(": {}", sub) }; + err.span_suggestion_verbose( sp, &format!("{}...", msg), suggestion, Applicability::MaybeIncorrect, // Issue #41966 ); } else { - let consider = format!( - "{} {}...", - msg, - if type_param_span.map_or(false, |(_, _, is_impl_trait)| is_impl_trait) { - format!(" `{}` to `{}`", sub, bound_kind) - } else { - format!("`{}: {}`", bound_kind, sub) - }, - ); + let consider = format!("{} `{}: {}`...", msg, bound_kind, sub,); err.help(&consider); } } let new_binding_suggestion = - |err: &mut Diagnostic, - type_param_span: Option<(Span, bool, bool)>, - bound_kind: GenericKind<'tcx>| { + |err: &mut Diagnostic, type_param_span: Option<(Span, bool)>| { let msg = "consider introducing an explicit lifetime bound"; - if let Some((sp, has_lifetimes, is_impl_trait)) = type_param_span { - let suggestion = if is_impl_trait { - (sp.shrink_to_hi(), format!(" + {}", new_lt)) + if let Some((sp, has_lifetimes)) = type_param_span { + let suggestion = if has_lifetimes { + format!(" + {}", new_lt) } else { - let tail = if has_lifetimes { " +" } else { "" }; - (sp, format!("{}: {}{}", bound_kind, new_lt, tail)) + format!(": {}", new_lt) }; let mut sugg = - vec![suggestion, (span.shrink_to_hi(), format!(" + {}", new_lt))]; + vec![(sp, suggestion), (span.shrink_to_hi(), format!(" + {}", new_lt))]; if let Some(lt) = add_lt_sugg { sugg.push(lt); sugg.rotate_right(1); @@ -2543,11 +2522,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let pred = format!("{}: {}", bound_kind, sub); let suggestion = format!( "{} {}", - if !generics.where_clause.predicates.is_empty() { "," } else { " where" }, + if !generics.predicates.is_empty() { "," } else { " where" }, pred, ); err.span_suggestion( - generics.where_clause.tail_span_for_suggestion(), + generics.tail_span_for_predicate_suggestion(), "consider adding a where clause", suggestion, Applicability::MaybeIncorrect, @@ -2615,7 +2594,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // suggest: // fn get_later<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a ty::Closure(_, _substs) | ty::Opaque(_, _substs) if return_impl_trait => { - new_binding_suggestion(&mut err, type_param_span, bound_kind); + new_binding_suggestion(&mut err, type_param_span); } _ => { binding_suggestion(&mut err, type_param_span, bound_kind, new_lt); diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs index baea3e8285af2..cbdcf01352271 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs @@ -372,8 +372,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { .hir() .get_generics(impl_item_def_id) .unwrap() - .where_clause - .tail_span_for_suggestion(); + .where_clause_span + .shrink_to_hi(); let suggestion = format!( "{} {}", diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 68658e2616e9b..3564f15e210ad 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1199,8 +1199,8 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems { }); } } - hir::ItemKind::Impl(hir::Impl { ref generics, items, .. }) => { - for it in items { + hir::ItemKind::Impl(hir::Impl { generics, items, .. }) => { + for it in *items { if let hir::AssocItemKind::Fn { .. } = it.kind { if let Some(no_mangle_attr) = cx .sess() @@ -1517,59 +1517,61 @@ impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds { // Bounds are respected for `type X = impl Trait` return; } - let mut suggested_changing_assoc_types = false; // There must not be a where clause - if !type_alias_generics.where_clause.predicates.is_empty() { - cx.lint( - TYPE_ALIAS_BOUNDS, - |lint| { - let mut err = lint.build("where clauses are not enforced in type aliases"); - let spans: Vec<_> = type_alias_generics - .where_clause - .predicates - .iter() - .map(|pred| pred.span()) - .collect(); - err.set_span(spans); - err.span_suggestion( - type_alias_generics.where_clause.span_for_predicates_or_empty_place(), - "the clause will not be checked when the type alias is used, and should be removed", - String::new(), - Applicability::MachineApplicable, - ); - if !suggested_changing_assoc_types { - TypeAliasBounds::suggest_changing_assoc_types(ty, &mut err); - suggested_changing_assoc_types = true; - } - err.emit(); - }, - ); + if type_alias_generics.predicates.is_empty() { + return; } - // The parameters must not have bounds - for param in type_alias_generics.params.iter() { - let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect(); - let suggestion = spans - .iter() - .map(|sp| { - let start = param.span.between(*sp); // Include the `:` in `T: Bound`. - (start.to(*sp), String::new()) - }) - .collect(); - if !spans.is_empty() { - cx.struct_span_lint(TYPE_ALIAS_BOUNDS, spans, |lint| { - let mut err = - lint.build("bounds on generic parameters are not enforced in type aliases"); - let msg = "the bound will not be checked when the type alias is used, \ - and should be removed"; - err.multipart_suggestion(msg, suggestion, Applicability::MachineApplicable); - if !suggested_changing_assoc_types { - TypeAliasBounds::suggest_changing_assoc_types(ty, &mut err); - suggested_changing_assoc_types = true; - } - err.emit(); - }); + + let mut where_spans = Vec::new(); + let mut inline_spans = Vec::new(); + let mut inline_sugg = Vec::new(); + for p in type_alias_generics.predicates { + let span = p.span(); + if p.in_where_clause() { + where_spans.push(span); + } else { + for b in p.bounds() { + inline_spans.push(b.span()); + } + inline_sugg.push((span, String::new())); } } + + let mut suggested_changing_assoc_types = false; + if !where_spans.is_empty() { + cx.lint(TYPE_ALIAS_BOUNDS, |lint| { + let mut err = lint.build("where clauses are not enforced in type aliases"); + err.set_span(where_spans); + err.span_suggestion( + type_alias_generics.where_clause_span, + "the clause will not be checked when the type alias is used, and should be removed", + String::new(), + Applicability::MachineApplicable, + ); + if !suggested_changing_assoc_types { + TypeAliasBounds::suggest_changing_assoc_types(ty, &mut err); + suggested_changing_assoc_types = true; + } + err.emit(); + }); + } + + if !inline_spans.is_empty() { + cx.lint(TYPE_ALIAS_BOUNDS, |lint| { + let mut err = + lint.build("bounds on generic parameters are not enforced in type aliases"); + err.set_span(inline_spans); + err.multipart_suggestion( + "the bound will not be checked when the type alias is used, and should be removed", + inline_sugg, + Applicability::MachineApplicable, + ); + if !suggested_changing_assoc_types { + TypeAliasBounds::suggest_changing_assoc_types(ty, &mut err); + } + err.emit(); + }); + } } } @@ -2085,27 +2087,6 @@ impl ExplicitOutlivesRequirements { .collect() } - fn collect_outlived_lifetimes<'tcx>( - &self, - param: &'tcx hir::GenericParam<'tcx>, - tcx: TyCtxt<'tcx>, - inferred_outlives: &'tcx [(ty::Predicate<'tcx>, Span)], - ty_generics: &'tcx ty::Generics, - ) -> Vec> { - let index = - ty_generics.param_def_id_to_index[&tcx.hir().local_def_id(param.hir_id).to_def_id()]; - - match param.kind { - hir::GenericParamKind::Lifetime { .. } => { - Self::lifetimes_outliving_lifetime(inferred_outlives, index) - } - hir::GenericParamKind::Type { .. } => { - Self::lifetimes_outliving_type(inferred_outlives, index) - } - hir::GenericParamKind::Const { .. } => Vec::new(), - } - } - fn collect_outlives_bound_spans<'tcx>( &self, tcx: TyCtxt<'tcx>, @@ -2213,41 +2194,11 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements { let mut bound_count = 0; let mut lint_spans = Vec::new(); - - for param in hir_generics.params { - let has_lifetime_bounds = param - .bounds - .iter() - .any(|bound| matches!(bound, hir::GenericBound::Outlives(_))); - if !has_lifetime_bounds { - continue; - } - - let relevant_lifetimes = - self.collect_outlived_lifetimes(param, cx.tcx, inferred_outlives, ty_generics); - if relevant_lifetimes.is_empty() { - continue; - } - - let bound_spans = self.collect_outlives_bound_spans( - cx.tcx, - ¶m.bounds, - &relevant_lifetimes, - infer_static, - ); - bound_count += bound_spans.len(); - lint_spans.extend(self.consolidate_outlives_bound_spans( - param.span.shrink_to_hi(), - ¶m.bounds, - bound_spans, - )); - } - let mut where_lint_spans = Vec::new(); let mut dropped_predicate_count = 0; - let num_predicates = hir_generics.where_clause.predicates.len(); - for (i, where_predicate) in hir_generics.where_clause.predicates.iter().enumerate() { - let (relevant_lifetimes, bounds, span) = match where_predicate { + let num_predicates = hir_generics.predicates.len(); + for (i, where_predicate) in hir_generics.predicates.iter().enumerate() { + let (relevant_lifetimes, bounds, span, in_where_clause) = match where_predicate { hir::WherePredicate::RegionPredicate(predicate) => { if let Some(Region::EarlyBound(index, ..)) = cx.tcx.named_region(predicate.lifetime.hir_id) @@ -2256,6 +2207,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements { Self::lifetimes_outliving_lifetime(inferred_outlives, index), &predicate.bounds, predicate.span, + predicate.in_where_clause, ) } else { continue; @@ -2274,6 +2226,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements { Self::lifetimes_outliving_type(inferred_outlives, index), &predicate.bounds, predicate.span, + predicate.in_where_clause, ) } _ => { @@ -2300,10 +2253,12 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements { dropped_predicate_count += 1; } - // If all the bounds on a predicate were inferable and there are - // further predicates, we want to eat the trailing comma. - if drop_predicate && i + 1 < num_predicates { - let next_predicate_span = hir_generics.where_clause.predicates[i + 1].span(); + if drop_predicate && !in_where_clause { + lint_spans.push(span); + } else if drop_predicate && i + 1 < num_predicates { + // If all the bounds on a predicate were inferable and there are + // further predicates, we want to eat the trailing comma. + let next_predicate_span = hir_generics.predicates[i + 1].span(); where_lint_spans.push(span.to(next_predicate_span.shrink_to_lo())); } else { where_lint_spans.extend(self.consolidate_outlives_bound_spans( @@ -2316,10 +2271,9 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements { // If all predicates are inferable, drop the entire clause // (including the `where`) - if num_predicates > 0 && dropped_predicate_count == num_predicates { + if hir_generics.has_where_clause && dropped_predicate_count == num_predicates { let where_span = hir_generics - .where_clause - .span() + .where_clause_span() .expect("span of (nonempty) where clause should exist"); // Extend the where clause back to the closing `>` of the // generics, except for tuple struct, which have the `where` @@ -2346,7 +2300,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements { }, lint_spans .into_iter() - .map(|span| (span, "".to_owned())) + .map(|span| (span, String::new())) .collect::>(), Applicability::MachineApplicable, ) diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index ed49eebd16d9c..b46ea955a3a82 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1462,8 +1462,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { })) } hir::ItemKind::Impl(hir::Impl { defaultness, constness, .. }) => { - self.tables.impl_defaultness.set(def_id.index, defaultness); - self.tables.impl_constness.set(def_id.index, constness); + self.tables.impl_defaultness.set(def_id.index, *defaultness); + self.tables.impl_constness.set(def_id.index, *constness); let trait_ref = self.tcx.impl_trait_ref(def_id); if let Some(trait_ref) = trait_ref { diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index 8c8a2650fd657..f53dc0000ca3e 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -11,7 +11,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Applicability, Diagnostic, DiagnosticArgValue, IntoDiagnosticArg}; use rustc_hir as hir; use rustc_hir::def_id::DefId; -use rustc_hir::{QPath, TyKind, WhereBoundPredicate, WherePredicate}; +use rustc_hir::WherePredicate; use rustc_span::Span; impl<'tcx> IntoDiagnosticArg for Ty<'tcx> { @@ -156,13 +156,13 @@ pub fn suggest_arbitrary_trait_bound( _ => {} } // Suggest a where clause bound for a non-type parameter. - let (action, prefix) = if generics.where_clause.predicates.is_empty() { - ("introducing a", " where ") - } else { + let (action, prefix) = if generics.has_where_clause { ("extending the", ", ") + } else { + ("introducing a", " where ") }; err.span_suggestion_verbose( - generics.where_clause.tail_span_for_suggestion(), + generics.tail_span_for_predicate_suggestion(), &format!( "consider {} `where` bound, but there might be an alternative better way to express \ this requirement", @@ -183,104 +183,37 @@ enum SuggestChangingConstraintsMessage<'a> { } fn suggest_removing_unsized_bound( + tcx: TyCtxt<'_>, generics: &hir::Generics<'_>, suggestions: &mut Vec<(Span, String, SuggestChangingConstraintsMessage<'_>)>, - param_name: &str, param: &hir::GenericParam<'_>, def_id: Option, ) { // See if there's a `?Sized` bound that can be removed to suggest that. // First look at the `where` clause because we can have `where T: ?Sized`, // then look at params. - for (where_pos, predicate) in generics.where_clause.predicates.iter().enumerate() { - match predicate { - WherePredicate::BoundPredicate(WhereBoundPredicate { - bounded_ty: - hir::Ty { - kind: - hir::TyKind::Path(hir::QPath::Resolved( - None, - hir::Path { - segments: [segment], - res: hir::def::Res::Def(hir::def::DefKind::TyParam, _), - .. - }, - )), - .. - }, - bounds, - span, - .. - }) if segment.ident.as_str() == param_name => { - for (pos, bound) in bounds.iter().enumerate() { - match bound { - hir::GenericBound::Trait(poly, hir::TraitBoundModifier::Maybe) - if poly.trait_ref.trait_def_id() == def_id => {} - _ => continue, - } - let sp = match ( - bounds.len(), - pos, - generics.where_clause.predicates.len(), - where_pos, - ) { - // where T: ?Sized - // ^^^^^^^^^^^^^^^ - (1, _, 1, _) => generics.where_clause.span, - // where Foo: Bar, T: ?Sized, - // ^^^^^^^^^^^ - (1, _, len, pos) if pos == len - 1 => generics.where_clause.predicates - [pos - 1] - .span() - .shrink_to_hi() - .to(*span), - // where T: ?Sized, Foo: Bar, - // ^^^^^^^^^^^ - (1, _, _, pos) => { - span.until(generics.where_clause.predicates[pos + 1].span()) - } - // where T: ?Sized + Bar, Foo: Bar, - // ^^^^^^^^^ - (_, 0, _, _) => bound.span().to(bounds[1].span().shrink_to_lo()), - // where T: Bar + ?Sized, Foo: Bar, - // ^^^^^^^^^ - (_, pos, _, _) => bounds[pos - 1].span().shrink_to_hi().to(bound.span()), - }; + let param_def_id = tcx.hir().local_def_id(param.hir_id); + for (where_pos, predicate) in generics.predicates.iter().enumerate() { + let WherePredicate::BoundPredicate(predicate) = predicate else { + continue; + }; + if !predicate.is_param_bound(param_def_id.to_def_id()) { + continue; + }; - suggestions.push(( - sp, - String::new(), - SuggestChangingConstraintsMessage::RemovingQSized, - )); - } + for (pos, bound) in predicate.bounds.iter().enumerate() { + let hir::GenericBound::Trait(poly, hir::TraitBoundModifier::Maybe) = bound else { + continue; + }; + if poly.trait_ref.trait_def_id() != def_id { + continue; } - _ => {} - } - } - for (pos, bound) in param.bounds.iter().enumerate() { - match bound { - hir::GenericBound::Trait(poly, hir::TraitBoundModifier::Maybe) - if poly.trait_ref.trait_def_id() == def_id => - { - let sp = match (param.bounds.len(), pos) { - // T: ?Sized, - // ^^^^^^^^ - (1, _) => param.span.shrink_to_hi().to(bound.span()), - // T: ?Sized + Bar, - // ^^^^^^^^^ - (_, 0) => bound.span().to(param.bounds[1].span().shrink_to_lo()), - // T: Bar + ?Sized, - // ^^^^^^^^^ - (_, pos) => param.bounds[pos - 1].span().shrink_to_hi().to(bound.span()), - }; - - suggestions.push(( - sp, - String::new(), - SuggestChangingConstraintsMessage::RemovingQSized, - )); - } - _ => {} + let sp = generics.span_for_bound_removal(where_pos, pos); + suggestions.push(( + sp, + String::new(), + SuggestChangingConstraintsMessage::RemovingQSized, + )); } } } @@ -331,13 +264,7 @@ pub fn suggest_constraining_type_params<'a>( param.span, &format!("this type parameter needs to be `{}`", constraint), ); - suggest_removing_unsized_bound( - generics, - &mut suggestions, - param_name, - param, - def_id, - ); + suggest_removing_unsized_bound(tcx, generics, &mut suggestions, param, def_id); } } @@ -358,76 +285,45 @@ pub fn suggest_constraining_type_params<'a>( )) }; - if param_name.starts_with("impl ") { - // If there's an `impl Trait` used in argument position, suggest - // restricting it: - // - // fn foo(t: impl Foo) { ... } - // -------- - // | - // help: consider further restricting this bound with `+ Bar` - // - // Suggestion for tools in this case is: - // - // fn foo(t: impl Foo) { ... } - // -------- - // | - // replace with: `impl Foo + Bar` - - // `impl Trait` must have at least one trait in the list - let bound_list_non_empty = true; - - suggest_restrict(param.span.shrink_to_hi(), bound_list_non_empty); + // When the type parameter has been provided bounds + // + // Message: + // fn foo(t: T) where T: Foo { ... } + // ^^^^^^ + // | + // help: consider further restricting this bound with `+ Bar` + // + // Suggestion: + // fn foo(t: T) where T: Foo { ... } + // ^ + // | + // replace with: ` + Bar` + // + // Or, if user has provided some bounds, suggest restricting them: + // + // fn foo(t: T) { ... } + // --- + // | + // help: consider further restricting this bound with `+ Bar` + // + // Suggestion for tools in this case is: + // + // fn foo(t: T) { ... } + // -- + // | + // replace with: `T: Bar +` + let param_def_id = tcx.hir().local_def_id(param.hir_id); + if let Some(span) = generics.bounds_span_for_suggestions(param_def_id) { + suggest_restrict(span, true); continue; } - if generics.where_clause.predicates.is_empty() - // Given `trait Base: Super` where `T: Copy`, suggest restricting in the - // `where` clause instead of `trait Base: Super`. - && !matches!(param.kind, hir::GenericParamKind::Type { default: Some(_), .. }) - { - if let Some(span) = param.bounds_span_for_suggestions() { - // If user has provided some bounds, suggest restricting them: - // - // fn foo(t: T) { ... } - // --- - // | - // help: consider further restricting this bound with `+ Bar` - // - // Suggestion for tools in this case is: - // - // fn foo(t: T) { ... } - // -- - // | - // replace with: `T: Bar +` - - // `bounds_span_for_suggestions` returns `None` if the list is empty - let bound_list_non_empty = true; - - suggest_restrict(span, bound_list_non_empty); - } else { - let (colon, span) = match param.colon_span_for_suggestions(tcx.sess.source_map()) { - // If there is already a colon after generic, do not suggest adding it again - Some(sp) => ("", sp.shrink_to_hi()), - None => (":", param.span.shrink_to_hi()), - }; - - // If user hasn't provided any bounds, suggest adding a new one: - // - // fn foo(t: T) { ... } - // - help: consider restricting this type parameter with `T: Foo` - suggestions.push(( - span, - format!("{colon} {constraint}"), - SuggestChangingConstraintsMessage::RestrictType { ty: param_name }, - )); - } - } else { + if generics.has_where_clause { // This part is a bit tricky, because using the `where` clause user can // provide zero, one or many bounds for the same type parameter, so we // have following cases to consider: // - // 1) When the type parameter has been provided zero bounds + // When the type parameter has been provided zero bounds // // Message: // fn foo(x: X, y: Y) where Y: Foo { ... } @@ -436,95 +332,59 @@ pub fn suggest_constraining_type_params<'a>( // Suggestion: // fn foo(x: X, y: Y) where Y: Foo { ... } // - insert: `, X: Bar` - // - // - // 2) When the type parameter has been provided one bound - // - // Message: - // fn foo(t: T) where T: Foo { ... } - // ^^^^^^ - // | - // help: consider further restricting this bound with `+ Bar` - // - // Suggestion: - // fn foo(t: T) where T: Foo { ... } - // ^^ - // | - // replace with: `T: Bar +` - // - // - // 3) When the type parameter has been provided many bounds - // - // Message: - // fn foo(t: T) where T: Foo, T: Bar {... } - // - help: consider further restricting this type parameter with `where T: Zar` - // - // Suggestion: - // fn foo(t: T) where T: Foo, T: Bar {... } - // - insert: `, T: Zar` - // - // Additionally, there may be no `where` clause whatsoever in the case that this was - // reached because the generic parameter has a default: - // - // Message: - // trait Foo {... } - // - help: consider further restricting this type parameter with `where T: Zar` - // - // Suggestion: - // trait Foo where T: Zar {... } - // - insert: `where T: Zar` - - if matches!(param.kind, hir::GenericParamKind::Type { default: Some(_), .. }) - && generics.where_clause.predicates.len() == 0 - { - // Suggest a bound, but there is no existing `where` clause *and* the type param has a - // default (``), so we suggest adding `where T: Bar`. - suggestions.push(( - generics.where_clause.tail_span_for_suggestion(), - format!(" where {}: {}", param_name, constraint), - SuggestChangingConstraintsMessage::RestrictTypeFurther { ty: param_name }, - )); - } else { - let mut param_spans = Vec::new(); - let mut non_empty = false; - - for predicate in generics.where_clause.predicates { - if let WherePredicate::BoundPredicate(WhereBoundPredicate { - span, - bounded_ty, - bounds, - .. - }) = predicate - { - if let TyKind::Path(QPath::Resolved(_, path)) = &bounded_ty.kind { - if let Some(segment) = path.segments.first() { - if segment.ident.to_string() == param_name { - non_empty = !bounds.is_empty(); - - param_spans.push(span); - } - } - } - } - } + suggestions.push(( + generics.tail_span_for_predicate_suggestion(), + constraints + .iter() + .map(|&(constraint, _)| format!(", {}: {}", param_name, constraint)) + .collect::(), + SuggestChangingConstraintsMessage::RestrictTypeFurther { ty: param_name }, + )); + continue; + } - match param_spans[..] { - [¶m_span] => suggest_restrict(param_span.shrink_to_hi(), non_empty), - _ => { - suggestions.push(( - generics.where_clause.tail_span_for_suggestion(), - constraints - .iter() - .map(|&(constraint, _)| format!(", {}: {}", param_name, constraint)) - .collect::(), - SuggestChangingConstraintsMessage::RestrictTypeFurther { - ty: param_name, - }, - )); - } - } - } + // Additionally, there may be no `where` clause but the generic parameter has a default: + // + // Message: + // trait Foo {... } + // - help: consider further restricting this type parameter with `where T: Zar` + // + // Suggestion: + // trait Foo {... } + // - insert: `where T: Zar` + if matches!(param.kind, hir::GenericParamKind::Type { default: Some(_), .. }) { + // Suggest a bound, but there is no existing `where` clause *and* the type param has a + // default (``), so we suggest adding `where T: Bar`. + suggestions.push(( + generics.tail_span_for_predicate_suggestion(), + format!(" where {}: {}", param_name, constraint), + SuggestChangingConstraintsMessage::RestrictTypeFurther { ty: param_name }, + )); + continue; } + + // If user has provided a colon, don't suggest adding another: + // + // fn foo(t: T) { ... } + // - insert: consider restricting this type parameter with `T: Foo` + if let Some(colon_span) = param.colon_span { + suggestions.push(( + colon_span.shrink_to_hi(), + format!(" {}", constraint), + SuggestChangingConstraintsMessage::RestrictType { ty: param_name }, + )); + continue; + } + + // If user hasn't provided any bounds, suggest adding a new one: + // + // fn foo(t: T) { ... } + // - help: consider restricting this type parameter with `T: Foo` + suggestions.push(( + param.span.shrink_to_hi(), + format!(": {}", constraint), + SuggestChangingConstraintsMessage::RestrictType { ty: param_name }, + )); } if suggestions.len() == 1 { diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 07878defa8ccd..da0934b67c5df 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -602,53 +602,24 @@ impl Trait for X { } else { return false; }; + let Some(def_id) = def_id.as_local() else { + return false; + }; // First look in the `where` clause, as this might be // `fn foo(x: T) where T: Trait`. - for predicate in hir_generics.where_clause.predicates { - if let hir::WherePredicate::BoundPredicate(pred) = predicate { - if let hir::TyKind::Path(hir::QPath::Resolved(None, path)) = - pred.bounded_ty.kind - { - if path.res.opt_def_id() == Some(def_id) { - // This predicate is binding type param `A` in `::Foo` to - // something, potentially `T`. - } else { - continue; - } - } else { - continue; - } - - if self.constrain_generic_bound_associated_type_structured_suggestion( - diag, - &trait_ref, - pred.bounds, - &assoc, - assoc_substs, - ty, - msg, - false, - ) { - return true; - } - } - } - for param in hir_generics.params { - if self.hir().opt_local_def_id(param.hir_id).map(|id| id.to_def_id()) - == Some(def_id) - { - // This is type param `A` in `::Foo`. - return self.constrain_generic_bound_associated_type_structured_suggestion( - diag, - &trait_ref, - param.bounds, - &assoc, - assoc_substs, - ty, - msg, - false, - ); + for pred in hir_generics.bounds_for_param(def_id) { + if self.constrain_generic_bound_associated_type_structured_suggestion( + diag, + &trait_ref, + pred.bounds, + &assoc, + assoc_substs, + ty, + msg, + false, + ) { + return true; } } } diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs index 29fe2b761018e..8081bac7cfd92 100644 --- a/compiler/rustc_parse/src/parser/generics.rs +++ b/compiler/rustc_parse/src/parser/generics.rs @@ -30,8 +30,10 @@ impl<'a> Parser<'a> { let ident = self.parse_ident()?; // Parse optional colon and param bounds. + let mut colon_span = None; let bounds = if self.eat(&token::Colon) { - self.parse_generic_bounds(Some(self.prev_token.span))? + colon_span = Some(self.prev_token.span); + self.parse_generic_bounds(colon_span)? } else { Vec::new() }; @@ -45,6 +47,7 @@ impl<'a> Parser<'a> { bounds, kind: GenericParamKind::Type { default }, is_placeholder: false, + colon_span, }) } @@ -69,6 +72,7 @@ impl<'a> Parser<'a> { bounds: Vec::new(), kind: GenericParamKind::Const { ty, kw_span: const_span, default }, is_placeholder: false, + colon_span: None, }) } @@ -97,10 +101,10 @@ impl<'a> Parser<'a> { let param = if this.check_lifetime() { let lifetime = this.expect_lifetime(); // Parse lifetime parameter. - let bounds = if this.eat(&token::Colon) { - this.parse_lt_param_bounds() + let (colon_span, bounds) = if this.eat(&token::Colon) { + (Some(this.prev_token.span), this.parse_lt_param_bounds()) } else { - Vec::new() + (None, Vec::new()) }; Some(ast::GenericParam { ident: lifetime.ident, @@ -109,6 +113,7 @@ impl<'a> Parser<'a> { bounds, kind: ast::GenericParamKind::Lifetime, is_placeholder: false, + colon_span, }) } else if this.check_keyword(kw::Const) { // Parse const parameter. diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index b661f6f9d729e..3cd1839028554 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -512,7 +512,7 @@ impl<'v, 'tcx> ItemLikeVisitor<'v> for LifeSeeder<'tcx> { if of_trait.is_some() { self.worklist.push(item.def_id); } - for impl_item_ref in items { + for impl_item_ref in *items { let impl_item = self.tcx.hir().impl_item(impl_item_ref.id); if of_trait.is_some() || has_allow_dead_code_or_lang_attr(self.tcx, impl_item.hir_id()) diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 35a858cb86c3f..10dc587be6e48 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -737,7 +737,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> { } } - for impl_item_ref in items { + for impl_item_ref in *items { let impl_item = self.tcx.associated_item(impl_item_ref.id.def_id); if let Some(def_id) = impl_item.trait_item_def_id { diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 5f9a03575575c..619e0d0341f07 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -1585,12 +1585,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { } fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) { - for param in generics.params { - for bound in param.bounds { - self.check_generic_bound(bound); - } - } - for predicate in generics.where_clause.predicates { + for predicate in generics.predicates { match predicate { hir::WherePredicate::BoundPredicate(bound_pred) => { for bound in bound_pred.bounds.iter() { diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 894ff0f17f8a1..a5243bf8ac3f8 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -86,7 +86,7 @@ impl ForLifetimeSpanType { } } -impl<'tcx> Into> for &'tcx hir::Generics<'tcx> { +impl<'tcx> Into> for &&'tcx hir::Generics<'tcx> { fn into(self) -> MissingLifetimeSpot<'tcx> { MissingLifetimeSpot::Generics(self) } diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs index 35a40a0a32131..787536d2a38ed 100644 --- a/compiler/rustc_resolve/src/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -1328,13 +1328,11 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { match param.kind { GenericParamKind::Lifetime { .. } => {} GenericParamKind::Type { ref default, .. } => { - walk_list!(this, visit_param_bound, param.bounds); if let Some(ref ty) = default { this.visit_ty(&ty); } } GenericParamKind::Const { ref ty, default } => { - walk_list!(this, visit_param_bound, param.bounds); this.visit_ty(&ty); if let Some(default) = default { this.visit_body(this.tcx.hir().body(default.body)); @@ -1342,7 +1340,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } } } - for predicate in generics.where_clause.predicates { + for predicate in generics.predicates { match predicate { &hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate { ref bounded_ty, @@ -1393,6 +1391,32 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { }) => { this.visit_lifetime(lifetime); walk_list!(this, visit_param_bound, bounds); + + if lifetime.name != hir::LifetimeName::Static { + for bound in bounds { + let hir::GenericBound::Outlives(ref lt) = bound else { + continue; + }; + if lt.name != hir::LifetimeName::Static { + continue; + } + this.insert_lifetime(lt, Region::Static); + this.tcx + .sess + .struct_span_warn( + lifetime.span, + &format!( + "unnecessary lifetime parameter `{}`", + lifetime.name.ident(), + ), + ) + .help(&format!( + "you can use the `'static` lifetime directly, in place of `{}`", + lifetime.name.ident(), + )) + .emit(); + } + } } &hir::WherePredicate::EqPredicate(hir::WhereEqPredicate { ref lhs_ty, @@ -1714,10 +1738,8 @@ fn object_lifetime_defaults_for_item<'tcx>( GenericParamKind::Type { .. } => { let mut set = Set1::Empty; - add_bounds(&mut set, ¶m.bounds); - let param_def_id = tcx.hir().local_def_id(param.hir_id); - for predicate in generics.where_clause.predicates { + for predicate in generics.predicates { // Look for `type: ...` where clauses. let hir::WherePredicate::BoundPredicate(ref data) = *predicate else { continue }; @@ -3124,50 +3146,6 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { // It is a soft error to shadow a lifetime within a parent scope. self.check_lifetime_param_for_shadowing(old_scope, &lifetime_i); - - for bound in lifetime_i.bounds { - match bound { - hir::GenericBound::Outlives(ref lt) => match lt.name { - hir::LifetimeName::Underscore => { - self.tcx.sess.delay_span_bug( - lt.span, - "use of `'_` in illegal place, but not caught by lowering", - ); - } - hir::LifetimeName::Static => { - self.insert_lifetime(lt, Region::Static); - self.tcx - .sess - .struct_span_warn( - lifetime_i.span.to(lt.span), - &format!( - "unnecessary lifetime parameter `{}`", - lifetime_i.name.ident(), - ), - ) - .help(&format!( - "you can use the `'static` lifetime directly, in place of `{}`", - lifetime_i.name.ident(), - )) - .emit(); - } - hir::LifetimeName::Param(_) | hir::LifetimeName::Implicit => { - self.resolve_lifetime_ref(lt); - } - hir::LifetimeName::ImplicitObjectLifetimeDefault => { - self.tcx.sess.delay_span_bug( - lt.span, - "lowering generated `ImplicitObjectLifetimeDefault` \ - outside of an object type", - ); - } - hir::LifetimeName::Error => { - // No need to do anything, error already reported. - } - }, - _ => bug!(), - } - } } } @@ -3326,18 +3304,6 @@ fn insert_late_bound_lifetimes( // ignore binders here and scrape up all names we see. let mut appears_in_where_clause = AllCollector::default(); appears_in_where_clause.visit_generics(generics); - - for param in generics.params { - if let hir::GenericParamKind::Lifetime { .. } = param.kind { - if !param.bounds.is_empty() { - // `'a: 'b` means both `'a` and `'b` are referenced - appears_in_where_clause - .regions - .insert(hir::LifetimeName::Param(param.name.normalize_to_macros_2_0())); - } - } - } - debug!(?appears_in_where_clause.regions); // Late bound regions are those that: diff --git a/compiler/rustc_save_analysis/src/dump_visitor.rs b/compiler/rustc_save_analysis/src/dump_visitor.rs index 6681ea9d299cf..b4230a144f813 100644 --- a/compiler/rustc_save_analysis/src/dump_visitor.rs +++ b/compiler/rustc_save_analysis/src/dump_visitor.rs @@ -1267,13 +1267,11 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> { match param.kind { hir::GenericParamKind::Lifetime { .. } => {} hir::GenericParamKind::Type { ref default, .. } => { - self.process_bounds(param.bounds); if let Some(ref ty) = default { self.visit_ty(ty); } } hir::GenericParamKind::Const { ref ty, ref default } => { - self.process_bounds(param.bounds); self.visit_ty(ty); if let Some(default) = default { self.visit_anon_const(default); @@ -1281,7 +1279,7 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> { } } } - for pred in generics.where_clause.predicates { + for pred in generics.predicates { if let hir::WherePredicate::BoundPredicate(ref wbp) = *pred { self.process_bounds(wbp.bounds); self.visit_ty(wbp.bounded_ty); diff --git a/compiler/rustc_save_analysis/src/sig.rs b/compiler/rustc_save_analysis/src/sig.rs index 8f50f44571953..d1286c9b8b0df 100644 --- a/compiler/rustc_save_analysis/src/sig.rs +++ b/compiler/rustc_save_analysis/src/sig.rs @@ -630,31 +630,6 @@ impl<'hir> Sig for hir::Generics<'hir> { param_text.push_str(&id_to_string(&scx.tcx.hir(), default.hir_id)); } } - if !param.bounds.is_empty() { - param_text.push_str(": "); - match param.kind { - hir::GenericParamKind::Lifetime { .. } => { - let bounds = param - .bounds - .iter() - .map(|bound| match bound { - hir::GenericBound::Outlives(lt) => lt.name.ident().to_string(), - _ => panic!(), - }) - .collect::>() - .join(" + "); - param_text.push_str(&bounds); - // FIXME add lifetime bounds refs. - } - hir::GenericParamKind::Type { .. } => { - param_text.push_str(&bounds_to_string(param.bounds)); - // FIXME descend properly into bounds. - } - hir::GenericParamKind::Const { .. } => { - // Const generics cannot contain bounds. - } - } - } text.push_str(¶m_text); text.push(','); } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 082402a38e3f5..7a3579eb1cc85 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -2419,26 +2419,15 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { }; let sized_trait = self.tcx.lang_items().sized_trait(); debug!("maybe_suggest_unsized_generics: generics.params={:?}", generics.params); - debug!("maybe_suggest_unsized_generics: generics.where_clause={:?}", generics.where_clause); - let param = generics.params.iter().filter(|param| param.span == span).find(|param| { - // Check that none of the explicit trait bounds is `Sized`. Assume that an explicit - // `Sized` bound is there intentionally and we don't need to suggest relaxing it. - param - .bounds - .iter() - .all(|bound| bound.trait_ref().and_then(|tr| tr.trait_def_id()) != sized_trait) - }); - let Some(param) = param else { + debug!("maybe_suggest_unsized_generics: generics.predicates={:?}", generics.predicates); + let Some(param) = generics.params.iter().find(|param| param.span == span) else { return; }; - let param_def_id = self.tcx.hir().local_def_id(param.hir_id).to_def_id(); - let preds = generics.where_clause.predicates.iter(); - let explicitly_sized = preds - .filter_map(|pred| match pred { - hir::WherePredicate::BoundPredicate(bp) => Some(bp), - _ => None, - }) - .filter(|bp| bp.is_param_bound(param_def_id)) + let param_def_id = self.tcx.hir().local_def_id(param.hir_id); + // Check that none of the explicit trait bounds is `Sized`. Assume that an explicit + // `Sized` bound is there intentionally and we don't need to suggest relaxing it. + let explicitly_sized = generics + .bounds_for_param(param_def_id) .flat_map(|bp| bp.bounds) .any(|bound| bound.trait_ref().and_then(|tr| tr.trait_def_id()) == sized_trait); if explicitly_sized { @@ -2461,9 +2450,11 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> { _ => {} }; // Didn't add an indirection suggestion, so add a general suggestion to relax `Sized`. - let (span, separator) = match param.bounds { - [] => (span.shrink_to_hi(), ":"), - [.., bound] => (bound.span().shrink_to_hi(), " +"), + let (span, separator) = if let Some(s) = generics.bounds_span_for_suggestions(param_def_id) + { + (s, " +") + } else { + (span.shrink_to_hi(), ":") }; err.span_suggestion_verbose( span, diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 187df6f7de0ff..446b14a17ae92 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -319,12 +319,8 @@ pub trait InferCtxtExt<'tcx> { fn predicate_constraint(generics: &hir::Generics<'_>, pred: String) -> (Span, String) { ( - generics.where_clause.tail_span_for_suggestion(), - format!( - "{} {}", - if !generics.where_clause.predicates.is_empty() { "," } else { " where" }, - pred, - ), + generics.tail_span_for_predicate_suggestion(), + format!("{} {}", if generics.has_where_clause { "," } else { " where" }, pred,), ) } @@ -346,7 +342,7 @@ fn suggest_restriction<'tcx>( // - ^^^^^^^^^ GenericBounds // | // &Ident - let span = generics.where_clause.span_for_predicates_or_empty_place(); + let span = generics.span_for_predicates_or_empty_place(); if span.from_expansion() || span.desugaring_kind().is_some() { return; } @@ -396,21 +392,10 @@ fn suggest_restriction<'tcx>( let pred = trait_pred.to_predicate(tcx).to_string(); let pred = pred.replace(&impl_trait_str, &type_param_name); let mut sugg = vec![ - // Find the last of the generic parameters contained within the span of - // the generics - match generics - .params - .iter() - .map(|p| p.bounds_span_for_suggestions().unwrap_or(p.span.shrink_to_hi())) - .filter(|&span| generics.span.contains(span) && span.can_be_used_for_suggestions()) - .max_by_key(|span| span.hi()) - { - // `fn foo(t: impl Trait)` - // ^ suggest `` here - None => (generics.span, format!("<{}>", type_param)), - // `fn foo(t: impl Trait)` - // ^^^ suggest `` here - Some(span) => (span, format!(", {}", type_param)), + if let Some(span) = generics.span_for_param_suggestion() { + (span, format!(", {}", type_param)) + } else { + (generics.span, format!("<{}>", type_param)) }, // `fn foo(t: impl Trait)` // ^ suggest `where ::A: Bound` diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 84958136cac97..b39310d12942d 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -221,7 +221,6 @@ fn get_sized_bounds(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span; 1]> .. }) => Some( generics - .where_clause .predicates .iter() .filter_map(|pred| { @@ -399,8 +398,8 @@ fn virtual_call_violation_for_method<'tcx>( // We'll attempt to provide a structured suggestion for `Self: Sized`. let sugg = tcx.hir().get_if_local(method.def_id).as_ref().and_then(|node| node.generics()).map( - |generics| match generics.where_clause.predicates { - [] => (" where Self: Sized", generics.where_clause.span), + |generics| match generics.predicates { + [] => (" where Self: Sized", generics.where_clause_span), [.., pred] => (", Self: Sized", pred.span().shrink_to_hi()), }, ); diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 3e36ffa7fe0d2..b8422ce3208f1 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -924,14 +924,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let self_ty_def_id = tcx.hir().local_def_id(self_ty).to_def_id(); for clause in where_clause { if let hir::WherePredicate::BoundPredicate(pred) = clause { - match pred.bounded_ty.kind { - hir::TyKind::Path(hir::QPath::Resolved(_, path)) => match path.res { - Res::Def(DefKind::TyParam, def_id) if def_id == self_ty_def_id => {} - _ => continue, - }, - _ => continue, + if pred.is_param_bound(self_ty_def_id) { + search_bounds(pred.bounds); } - search_bounds(pred.bounds); } } } @@ -2389,7 +2384,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { bf.unsafety, bf.abi, bf.decl, - &hir::Generics::empty(), None, Some(ast_ty), )) @@ -2551,8 +2545,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { unsafety: hir::Unsafety, abi: abi::Abi, decl: &hir::FnDecl<'_>, - generics: &hir::Generics<'_>, - ident_span: Option, + generics: Option<&hir::Generics<'_>>, hir_ty: Option<&hir::Ty<'_>>, ) -> ty::PolyFnSig<'tcx> { debug!("ty_of_fn"); @@ -2565,7 +2558,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let mut visitor = HirPlaceholderCollector::default(); let mut infer_replacements = vec![]; - walk_generics(&mut visitor, generics); + if let Some(generics) = generics { + walk_generics(&mut visitor, generics); + } let input_tys: Vec<_> = decl .inputs @@ -2617,8 +2612,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let mut diag = crate::collect::placeholder_type_error_diag( tcx, - ident_span.map(|sp| sp.shrink_to_hi()), - generics.params, + generics, visitor.0, infer_replacements.iter().map(|(s, _)| *s).collect(), true, diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs index 4ab6f2cdafbc7..6d78a863d54cf 100644 --- a/compiler/rustc_typeck/src/check/compare_method.rs +++ b/compiler/rustc_typeck/src/check/compare_method.rs @@ -804,7 +804,8 @@ fn compare_synthetic_generics<'tcx>( iter::zip(impl_m_type_params, trait_m_type_params) { if impl_synthetic != trait_synthetic { - let impl_hir_id = tcx.hir().local_def_id_to_hir_id(impl_def_id.expect_local()); + let impl_def_id = impl_def_id.expect_local(); + let impl_hir_id = tcx.hir().local_def_id_to_hir_id(impl_def_id); let impl_span = tcx.hir().span(impl_hir_id); let trait_span = tcx.def_span(trait_def_id); let mut err = struct_span_err!( @@ -868,14 +869,14 @@ fn compare_synthetic_generics<'tcx>( hir::ImplItemKind::Fn(ref sig, _) => sig.decl.inputs, _ => unreachable!(), }; - struct Visitor(Option, hir::def_id::DefId); + struct Visitor(Option, hir::def_id::LocalDefId); impl<'v> intravisit::Visitor<'v> for Visitor { fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) { intravisit::walk_ty(self, ty); if let hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) = ty.kind && let Res::Def(DefKind::TyParam, def_id) = path.res - && def_id == self.1 + && def_id == self.1.to_def_id() { self.0 = Some(ty.span); } @@ -887,17 +888,7 @@ fn compare_synthetic_generics<'tcx>( } let span = visitor.0?; - let bounds = - impl_m.generics.params.iter().find_map(|param| match param.kind { - GenericParamKind::Lifetime { .. } => None, - GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => { - if param.hir_id == impl_hir_id { - Some(¶m.bounds) - } else { - None - } - } - })?; + let bounds = impl_m.generics.bounds_for_param(impl_def_id).next()?.bounds; let bounds = bounds.first()?.span().to(bounds.last()?.span()); let bounds = tcx.sess.source_map().span_to_snippet(bounds).ok()?; diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs index a92c288cac93d..681d1e37f86f1 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs @@ -599,17 +599,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { kind: hir::ItemKind::Fn( hir::FnSig { decl: hir::FnDecl { inputs: fn_parameters, output: fn_return, .. }, .. }, - hir::Generics { params, where_clause, .. }, + hir::Generics { params, predicates, .. }, _body_id, ), .. })) = fn_node else { return }; - let Some(expected_generic_param) = params.get(expected_ty_as_param.index as usize) else { return }; + if params.get(expected_ty_as_param.index as usize).is_none() { + return; + }; // get all where BoundPredicates here, because they are used in to cases below - let where_predicates = where_clause - .predicates + let where_predicates = predicates .iter() .filter_map(|p| match p { WherePredicate::BoundPredicate(hir::WhereBoundPredicate { @@ -640,10 +641,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { where_predicates.iter().flatten().flat_map(|bounds| bounds.iter()); // extract all bounds from the source code using their spans - let all_matching_bounds_strs = expected_generic_param - .bounds - .iter() - .chain(predicates_from_where) + let all_matching_bounds_strs = predicates_from_where .filter_map(|bound| match bound { GenericBound::Trait(_, _) => { self.tcx.sess.source_map().span_to_snippet(bound.span()).ok() diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index 80c31355fe71d..640dccf66b0b4 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -533,12 +533,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; if let Some(hir::Node::Item(hir::Item { kind, .. })) = node { if let Some(g) = kind.generics() { - let key = match g.where_clause.predicates { + let key = match g.predicates { [.., pred] => (pred.span().shrink_to_hi(), false), - [] => ( - g.where_clause.span_for_predicates_or_empty_place(), - true, - ), + [] => (g.span_for_predicates_or_empty_place(), true), }; type_params .entry(key) @@ -1871,37 +1868,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // instead we suggest `T: Foo + Bar` in that case. match hir.get(id) { Node::GenericParam(param) => { - let mut impl_trait = false; - let has_bounds = - if let hir::GenericParamKind::Type { synthetic: true, .. } = - ¶m.kind - { - // We've found `fn foo(x: impl Trait)` instead of - // `fn foo(x: T)`. We want to suggest the correct - // `fn foo(x: impl Trait + TraitBound)` instead of - // `fn foo(x: T)`. (#63706) - impl_trait = true; - param.bounds.get(1) - } else { - param.bounds.get(0) - }; - let sp = hir.span(id); - let sp = if let Some(first_bound) = has_bounds { - sp.until(first_bound.span()) - } else if let Some(colon_sp) = - // If the generic param is declared with a colon but without bounds: - // fn foo(t: T) { ... } - param.colon_span_for_suggestions( - self.inh.tcx.sess.source_map(), - ) + enum Introducer { + Plus, + Colon, + Nothing, + } + let ast_generics = hir.get_generics(id.owner).unwrap(); + let (sp, mut introducer) = if let Some(span) = + ast_generics.bounds_span_for_suggestions(def_id) { - sp.to(colon_sp) + (span, Introducer::Plus) + } else if let Some(colon_span) = param.colon_span { + (colon_span.shrink_to_hi(), Introducer::Nothing) } else { - sp + (param.span.shrink_to_hi(), Introducer::Colon) }; - let trait_def_ids: FxHashSet = param - .bounds - .iter() + if matches!( + param.kind, + hir::GenericParamKind::Type { synthetic: true, .. }, + ) { + introducer = Introducer::Plus + } + let trait_def_ids: FxHashSet = ast_generics + .bounds_for_param(def_id) + .flat_map(|bp| bp.bounds.iter()) .filter_map(|bound| bound.trait_ref()?.trait_def_id()) .collect(); if !candidates.iter().any(|t| trait_def_ids.contains(&t.def_id)) { @@ -1913,11 +1903,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { )), candidates.iter().map(|t| { format!( - "{}{} {}{}", - param.name.ident(), - if impl_trait { " +" } else { ":" }, + "{} {}", + match introducer { + Introducer::Plus => " +", + Introducer::Colon => ":", + Introducer::Nothing => "", + }, self.tcx.def_path_str(t.def_id), - if has_bounds.is_some() { " + " } else { "" }, ) }), Applicability::MaybeIncorrect, diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index f7bb30cd13e6f..76c955d6f690d 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -373,16 +373,7 @@ fn typeck_with_fallback<'tcx>( let (fcx, wf_tys) = if let Some(hir::FnSig { header, decl, .. }) = fn_sig { let fn_sig = if crate::collect::get_infer_ret_ty(&decl.output).is_some() { let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id); - >::ty_of_fn( - &fcx, - id, - header.unsafety, - header.abi, - decl, - &hir::Generics::empty(), - None, - None, - ) + >::ty_of_fn(&fcx, id, header.unsafety, header.abi, decl, None, None) } else { tcx.fn_sig(def_id) }; diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs index 4e3e32670e96e..ec2b7c13ff33c 100644 --- a/compiler/rustc_typeck/src/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -420,15 +420,11 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe let suggestion = format!( "{} {}", - if !gat_item_hir.generics.where_clause.predicates.is_empty() { - "," - } else { - " where" - }, + if !gat_item_hir.generics.predicates.is_empty() { "," } else { " where" }, unsatisfied_bounds.join(", "), ); err.span_suggestion( - gat_item_hir.generics.where_clause.tail_span_for_suggestion(), + gat_item_hir.generics.tail_span_for_predicate_suggestion(), &format!("add the required where clause{plural}"), suggestion, Applicability::MachineApplicable, @@ -1733,7 +1729,6 @@ fn check_variances_for_type_defn<'tcx>( let explicitly_bounded_params = Lazy::new(|| { let icx = crate::collect::ItemCtxt::new(tcx, item.def_id.to_def_id()); hir_generics - .where_clause .predicates .iter() .filter_map(|predicate| match predicate { @@ -1760,8 +1755,7 @@ fn check_variances_for_type_defn<'tcx>( match param.name { hir::ParamName::Error => {} _ => { - let has_explicit_bounds = - !param.bounds.is_empty() || explicitly_bounded_params.contains(¶meter); + let has_explicit_bounds = explicitly_bounded_params.contains(¶meter); report_bivariance(tcx, param, has_explicit_bounds); } } @@ -1819,13 +1813,12 @@ fn check_false_global_bounds(fcx: &FnCtxt<'_, '_>, mut span: Span, id: hir::HirI // only use the span of the predicate clause (#90869) - if let Some(hir::Generics { where_clause, .. }) = + if let Some(hir::Generics { predicates, .. }) = hir_node.and_then(|node| node.generics()) { let obligation_span = obligation.cause.span(fcx.tcx); - span = where_clause - .predicates + span = predicates .iter() // There seems to be no better way to find out which predicate we are in .find(|pred| pred.span().contains(obligation_span)) diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 0ccc2b6b182c4..f85735ec57bf7 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -1,4 +1,3 @@ -// ignore-tidy-filelength //! "Collection" is the process of determining the type and other external //! details of each item in Rust. Collection is specifically concerned //! with *inter-procedural* things -- for example, for a function @@ -149,8 +148,7 @@ struct CollectItemTypesVisitor<'tcx> { /// all already existing generic type parameters to avoid suggesting a name that is already in use. crate fn placeholder_type_error<'tcx>( tcx: TyCtxt<'tcx>, - span: Option, - generics: &[hir::GenericParam<'_>], + generics: Option<&hir::Generics<'_>>, placeholder_types: Vec, suggest: bool, hir_ty: Option<&hir::Ty<'_>>, @@ -160,23 +158,13 @@ crate fn placeholder_type_error<'tcx>( return; } - placeholder_type_error_diag( - tcx, - span, - generics, - placeholder_types, - vec![], - suggest, - hir_ty, - kind, - ) - .emit(); + placeholder_type_error_diag(tcx, generics, placeholder_types, vec![], suggest, hir_ty, kind) + .emit(); } crate fn placeholder_type_error_diag<'tcx>( tcx: TyCtxt<'tcx>, - span: Option, - generics: &[hir::GenericParam<'_>], + generics: Option<&hir::Generics<'_>>, placeholder_types: Vec, additional_spans: Vec, suggest: bool, @@ -187,26 +175,24 @@ crate fn placeholder_type_error_diag<'tcx>( return bad_placeholder(tcx, additional_spans, kind); } - let type_name = generics.next_type_param_name(None); + let params = generics.map(|g| g.params).unwrap_or_default(); + let type_name = params.next_type_param_name(None); let mut sugg: Vec<_> = placeholder_types.iter().map(|sp| (*sp, (*type_name).to_string())).collect(); - if generics.is_empty() { - if let Some(span) = span { - sugg.push((span, format!("<{}>", type_name))); + if let Some(generics) = generics { + if let Some(arg) = params.iter().find(|arg| { + matches!(arg.name, hir::ParamName::Plain(Ident { name: kw::Underscore, .. })) + }) { + // Account for `_` already present in cases like `struct S<_>(_);` and suggest + // `struct S(T);` instead of `struct S<_, T>(T);`. + sugg.push((arg.span, (*type_name).to_string())); + } else if let Some(span) = generics.span_for_param_suggestion() { + // Account for bounds, we want `fn foo(_: K)` not `fn foo(_: K)`. + sugg.push((span, format!(", {}", type_name))); + } else { + sugg.push((generics.span, format!("<{}>", type_name))); } - } else if let Some(arg) = generics - .iter() - .find(|arg| matches!(arg.name, hir::ParamName::Plain(Ident { name: kw::Underscore, .. }))) - { - // Account for `_` already present in cases like `struct S<_>(_);` and suggest - // `struct S(T);` instead of `struct S<_, T>(T);`. - sugg.push((arg.span, (*type_name).to_string())); - } else { - let last = generics.iter().last().unwrap(); - // Account for bounds, we want `fn foo(_: K)` not `fn foo(_: K)`. - let span = last.bounds_span_for_suggestions().unwrap_or(last.span.shrink_to_hi()); - sugg.push((span, format!(", {}", type_name))); } let mut err = @@ -270,15 +256,7 @@ fn reject_placeholder_type_signatures_in_item<'tcx>( let mut visitor = HirPlaceholderCollector::default(); visitor.visit_item(item); - placeholder_type_error( - tcx, - Some(generics.span), - generics.params, - visitor.0, - suggest, - None, - item.kind.descr(), - ); + placeholder_type_error(tcx, Some(generics), visitor.0, suggest, None, item.kind.descr()); } impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> { @@ -680,27 +658,8 @@ impl<'tcx> ItemCtxt<'tcx> { only_self_bounds: OnlySelfBounds, assoc_name: Option, ) -> Vec<(ty::Predicate<'tcx>, Span)> { - let from_ty_params = ast_generics - .params - .iter() - .filter_map(|param| match param.kind { - GenericParamKind::Type { .. } | GenericParamKind::Const { .. } - if param.hir_id == param_id => - { - Some(¶m.bounds) - } - _ => None, - }) - .flat_map(|bounds| bounds.iter()) - .filter(|b| match assoc_name { - Some(assoc_name) => self.bound_defines_assoc_item(b, assoc_name), - None => true, - }) - .flat_map(|b| predicates_from_bound(self, ty, b, ty::List::empty())); - let param_def_id = self.tcx.hir().local_def_id(param_id).to_def_id(); - let from_where_clauses = ast_generics - .where_clause + ast_generics .predicates .iter() .filter_map(|wp| match *wp { @@ -725,9 +684,8 @@ impl<'tcx> ItemCtxt<'tcx> { }) .filter_map(move |b| bt.map(|bt| (bt, b, bvars))) }) - .flat_map(|(bt, b, bvars)| predicates_from_bound(self, bt, b, bvars)); - - from_ty_params.chain(from_where_clauses).collect() + .flat_map(|(bt, b, bvars)| predicates_from_bound(self, bt, b, bvars)) + .collect() } fn bound_defines_assoc_item(&self, b: &hir::GenericBound<'_>, assoc_name: Ident) -> bool { @@ -773,7 +731,6 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) { placeholder_type_error( tcx, None, - &[], visitor.0, false, None, @@ -853,15 +810,7 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) { if let hir::TyKind::TraitObject(..) = ty.kind { let mut visitor = HirPlaceholderCollector::default(); visitor.visit_item(it); - placeholder_type_error( - tcx, - None, - &[], - visitor.0, - false, - None, - it.kind.descr(), - ); + placeholder_type_error(tcx, None, visitor.0, false, None, it.kind.descr()); } } _ => (), @@ -889,7 +838,7 @@ fn convert_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) { // Account for `const C: _;`. let mut visitor = HirPlaceholderCollector::default(); visitor.visit_trait_item(trait_item); - placeholder_type_error(tcx, None, &[], visitor.0, false, None, "constant"); + placeholder_type_error(tcx, None, visitor.0, false, None, "constant"); } hir::TraitItemKind::Type(_, Some(_)) => { @@ -898,7 +847,7 @@ fn convert_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) { // Account for `type T = _;`. let mut visitor = HirPlaceholderCollector::default(); visitor.visit_trait_item(trait_item); - placeholder_type_error(tcx, None, &[], visitor.0, false, None, "associated type"); + placeholder_type_error(tcx, None, visitor.0, false, None, "associated type"); } hir::TraitItemKind::Type(_, None) => { @@ -908,7 +857,7 @@ fn convert_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) { let mut visitor = HirPlaceholderCollector::default(); visitor.visit_trait_item(trait_item); - placeholder_type_error(tcx, None, &[], visitor.0, false, None, "associated type"); + placeholder_type_error(tcx, None, visitor.0, false, None, "associated type"); } }; @@ -930,7 +879,7 @@ fn convert_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::ImplItemId) { let mut visitor = HirPlaceholderCollector::default(); visitor.visit_impl_item(impl_item); - placeholder_type_error(tcx, None, &[], visitor.0, false, None, "associated type"); + placeholder_type_error(tcx, None, visitor.0, false, None, "associated type"); } hir::ImplItemKind::Const(..) => {} } @@ -1893,15 +1842,14 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> { match tcx.hir().get(hir_id) { TraitItem(hir::TraitItem { kind: TraitItemKind::Fn(sig, TraitFn::Provided(_)), - ident, generics, .. }) - | Item(hir::Item { kind: ItemKind::Fn(sig, generics, _), ident, .. }) => { - infer_return_ty_for_fn_sig(tcx, sig, *ident, generics, def_id, &icx) + | Item(hir::Item { kind: ItemKind::Fn(sig, generics, _), .. }) => { + infer_return_ty_for_fn_sig(tcx, sig, generics, def_id, &icx) } - ImplItem(hir::ImplItem { kind: ImplItemKind::Fn(sig, _), ident, generics, .. }) => { + ImplItem(hir::ImplItem { kind: ImplItemKind::Fn(sig, _), generics, .. }) => { // Do not try to inference the return type for a impl method coming from a trait if let Item(hir::Item { kind: ItemKind::Impl(i), .. }) = tcx.hir().get(tcx.hir().get_parent_node(hir_id)) @@ -1913,18 +1861,16 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> { sig.header.unsafety, sig.header.abi, sig.decl, - generics, - Some(ident.span), + Some(generics), None, ) } else { - infer_return_ty_for_fn_sig(tcx, sig, *ident, generics, def_id, &icx) + infer_return_ty_for_fn_sig(tcx, sig, generics, def_id, &icx) } } TraitItem(hir::TraitItem { kind: TraitItemKind::Fn(FnSig { header, decl, span: _ }, _), - ident, generics, .. }) => >::ty_of_fn( @@ -1933,16 +1879,13 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> { header.unsafety, header.abi, decl, - generics, - Some(ident.span), + Some(generics), None, ), - ForeignItem(&hir::ForeignItem { - kind: ForeignItemKind::Fn(fn_decl, _, _), ident, .. - }) => { + ForeignItem(&hir::ForeignItem { kind: ForeignItemKind::Fn(fn_decl, _, _), .. }) => { let abi = tcx.hir().get_foreign_abi(hir_id); - compute_sig_of_foreign_fn_decl(tcx, def_id.to_def_id(), fn_decl, abi, ident) + compute_sig_of_foreign_fn_decl(tcx, def_id.to_def_id(), fn_decl, abi) } Ctor(data) | Variant(hir::Variant { data, .. }) if data.ctor_hir_id().is_some() => { @@ -1983,7 +1926,6 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> { fn infer_return_ty_for_fn_sig<'tcx>( tcx: TyCtxt<'tcx>, sig: &hir::FnSig<'_>, - ident: Ident, generics: &hir::Generics<'_>, def_id: LocalDefId, icx: &ItemCtxt<'tcx>, @@ -2038,8 +1980,7 @@ fn infer_return_ty_for_fn_sig<'tcx>( sig.header.unsafety, sig.header.abi, sig.decl, - generics, - Some(ident.span), + Some(generics), None, ), } @@ -2200,16 +2141,16 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP let icx = ItemCtxt::new(tcx, def_id); - const NO_GENERICS: &hir::Generics<'_> = &hir::Generics::empty(); + const NO_GENERICS: &hir::Generics<'_> = hir::Generics::empty(); // We use an `IndexSet` to preserves order of insertion. // Preserving the order of insertion is important here so as not to break UI tests. let mut predicates: FxIndexSet<(ty::Predicate<'_>, Span)> = FxIndexSet::default(); let ast_generics = match node { - Node::TraitItem(item) => &item.generics, + Node::TraitItem(item) => item.generics, - Node::ImplItem(item) => &item.generics, + Node::ImplItem(item) => item.generics, Node::Item(item) => { match item.kind { @@ -2223,15 +2164,15 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP | ItemKind::TyAlias(_, ref generics) | ItemKind::Enum(_, ref generics) | ItemKind::Struct(_, ref generics) - | ItemKind::Union(_, ref generics) => generics, + | ItemKind::Union(_, ref generics) => *generics, ItemKind::Trait(_, _, ref generics, ..) => { is_trait = Some(ty::TraitRef::identity(tcx, def_id)); - generics + *generics } ItemKind::TraitAlias(ref generics, _) => { is_trait = Some(ty::TraitRef::identity(tcx, def_id)); - generics + *generics } ItemKind::OpaqueTy(OpaqueTy { origin: hir::OpaqueTyOrigin::AsyncFn(..) | hir::OpaqueTyOrigin::FnReturn(..), @@ -2268,7 +2209,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP Node::ForeignItem(item) => match item.kind { ForeignItemKind::Static(..) => NO_GENERICS, - ForeignItemKind::Fn(_, _, ref generics) => generics, + ForeignItemKind::Fn(_, _, ref generics) => *generics, ForeignItemKind::Type => NO_GENERICS, }, @@ -2302,29 +2243,9 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP // Collect the region predicates that were declared inline as // well. In the case of parameters declared on a fn or method, we // have to be careful to only iterate over early-bound regions. - let mut index = parent_count + has_own_self as u32; - for param in early_bound_lifetimes_from_generics(tcx, hir_id.owner, ast_generics) { - let region = tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion { - def_id: tcx.hir().local_def_id(param.hir_id).to_def_id(), - index, - name: param.name.ident().name, - })); - index += 1; - - match param.kind { - GenericParamKind::Lifetime { .. } => { - param.bounds.iter().for_each(|bound| match bound { - hir::GenericBound::Outlives(lt) => { - let bound = >::ast_region_to_region(&icx, lt, None); - let outlives = ty::Binder::dummy(ty::OutlivesPredicate(region, bound)); - predicates.insert((outlives.to_predicate(tcx), lt.span)); - } - _ => bug!(), - }); - } - _ => bug!(), - } - } + let mut index = parent_count + + has_own_self as u32 + + early_bound_lifetimes_from_generics(tcx, hir_id.owner, ast_generics).count() as u32; // Collect the predicates that were written inline by the user on each // type parameter (e.g., ``). @@ -2337,28 +2258,26 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP let param_ty = ty::ParamTy::new(index, name).to_ty(tcx); index += 1; - let mut bounds = >::compute_bounds(&icx, param_ty, param.bounds); + let mut bounds = Bounds::default(); // Params are implicitly sized unless a `?Sized` bound is found >::add_implicitly_sized( &icx, &mut bounds, - param.bounds, - Some((param.hir_id, ast_generics.where_clause.predicates)), + &[], + Some((param.hir_id, ast_generics.predicates)), param.span, ); predicates.extend(bounds.predicates(tcx, param_ty)); } GenericParamKind::Const { .. } => { // Bounds on const parameters are currently not possible. - debug_assert!(param.bounds.is_empty()); index += 1; } } } // Add in the bounds that appear in the where-clause. - let where_clause = &ast_generics.where_clause; - for predicate in where_clause.predicates { + for predicate in ast_generics.predicates { match predicate { hir::WherePredicate::BoundPredicate(bound_pred) => { let ty = icx.to_ty(bound_pred.bounded_ty); @@ -2616,7 +2535,6 @@ fn compute_sig_of_foreign_fn_decl<'tcx>( def_id: DefId, decl: &'tcx hir::FnDecl<'tcx>, abi: abi::Abi, - ident: Ident, ) -> ty::PolyFnSig<'tcx> { let unsafety = if abi == abi::Abi::RustIntrinsic { intrinsic_operation_unsafety(tcx.item_name(def_id)) @@ -2630,8 +2548,7 @@ fn compute_sig_of_foreign_fn_decl<'tcx>( unsafety, abi, decl, - &hir::Generics::empty(), - Some(ident.span), + None, None, ); diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs index fa06ec09fce22..495b8d3b4eeb3 100644 --- a/compiler/rustc_typeck/src/collect/type_of.rs +++ b/compiler/rustc_typeck/src/collect/type_of.rs @@ -337,8 +337,8 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { icx.to_ty(ty) } } - ItemKind::TyAlias(self_ty, _) - | ItemKind::Impl(hir::Impl { self_ty, .. }) => icx.to_ty(self_ty), + ItemKind::TyAlias(self_ty, _) => icx.to_ty(self_ty), + ItemKind::Impl(hir::Impl { self_ty, .. }) => icx.to_ty(*self_ty), ItemKind::Fn(..) => { let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id()); tcx.mk_fn_def(def_id.to_def_id(), substs) diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs index 9fb9652b849c9..03b3d68d59f4c 100644 --- a/compiler/rustc_typeck/src/lib.rs +++ b/compiler/rustc_typeck/src/lib.rs @@ -213,7 +213,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); match tcx.hir().find(hir_id) { Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, ref generics, _), .. })) => { - generics.where_clause.span() + generics.where_clause_span() } _ => { span_bug!(tcx.def_span(def_id), "main has a non-function type"); @@ -408,7 +408,7 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) { .emit(); error = true; } - if let Some(sp) = generics.where_clause.span() { + if let Some(sp) = generics.where_clause_span() { struct_span_err!( tcx.sess, sp, diff --git a/src/etc/check_missing_items.py b/src/etc/check_missing_items.py index 89696f392621b..343dd0387f479 100644 --- a/src/etc/check_missing_items.py +++ b/src/etc/check_missing_items.py @@ -49,8 +49,6 @@ def check_generic_param(param): ty = param["kind"]["type"] if ty["default"]: check_type(ty["default"]) - for bound in ty["bounds"]: - check_generic_bound(bound) elif "const" in param["kind"]: check_type(param["kind"]["const"]) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 476a89523a56a..d458deddae335 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -238,9 +238,12 @@ impl Clean> for ty::Region<'_> { } } -impl Clean for hir::WherePredicate<'_> { - fn clean(&self, cx: &mut DocContext<'_>) -> WherePredicate { - match *self { +impl Clean> for hir::WherePredicate<'_> { + fn clean(&self, cx: &mut DocContext<'_>) -> Option { + if !self.in_where_clause() { + return None; + } + Some(match *self { hir::WherePredicate::BoundPredicate(ref wbp) => { let bound_params = wbp .bound_generic_params @@ -250,11 +253,7 @@ impl Clean for hir::WherePredicate<'_> { // Higher-ranked lifetimes can't have bounds. assert_matches!( param, - hir::GenericParam { - kind: hir::GenericParamKind::Lifetime { .. }, - bounds: [], - .. - } + hir::GenericParam { kind: hir::GenericParamKind::Lifetime { .. }, .. } ); Lifetime(param.name.ident().name) }) @@ -275,7 +274,7 @@ impl Clean for hir::WherePredicate<'_> { lhs: wrp.lhs_ty.clean(cx), rhs: wrp.rhs_ty.clean(cx).into(), }, - } + }) } } @@ -456,44 +455,75 @@ impl Clean for ty::GenericParamDef { } } -impl Clean for hir::GenericParam<'_> { - fn clean(&self, cx: &mut DocContext<'_>) -> GenericParamDef { - let (name, kind) = match self.kind { - hir::GenericParamKind::Lifetime { .. } => { - let outlives = self - .bounds +fn clean_generic_param( + cx: &mut DocContext<'_>, + generics: Option<&hir::Generics<'_>>, + param: &hir::GenericParam<'_>, +) -> GenericParamDef { + let (name, kind) = match param.kind { + hir::GenericParamKind::Lifetime { .. } => { + let outlives = if let Some(generics) = generics { + generics + .predicates .iter() + .flat_map(|pred| { + match pred { + hir::WherePredicate::RegionPredicate(rp) + if rp.lifetime.name == hir::LifetimeName::Param(param.name) + && !rp.in_where_clause => + { + rp.bounds + } + _ => &[], + } + .iter() + }) .map(|bound| match bound { hir::GenericBound::Outlives(lt) => lt.clean(cx), _ => panic!(), }) - .collect(); - (self.name.ident().name, GenericParamDefKind::Lifetime { outlives }) - } - hir::GenericParamKind::Type { ref default, synthetic } => ( - self.name.ident().name, + .collect() + } else { + Vec::new() + }; + (param.name.ident().name, GenericParamDefKind::Lifetime { outlives }) + } + hir::GenericParamKind::Type { ref default, synthetic } => { + let did = cx.tcx.hir().local_def_id(param.hir_id); + let bounds = if let Some(generics) = generics { + generics + .bounds_for_param(did) + .filter(|bp| !bp.in_where_clause) + .flat_map(|bp| bp.bounds) + .filter_map(|x| x.clean(cx)) + .collect() + } else { + Vec::new() + }; + ( + param.name.ident().name, GenericParamDefKind::Type { - did: cx.tcx.hir().local_def_id(self.hir_id).to_def_id(), - bounds: self.bounds.iter().filter_map(|x| x.clean(cx)).collect(), + did: did.to_def_id(), + bounds, default: default.map(|t| t.clean(cx)).map(Box::new), synthetic, }, - ), - hir::GenericParamKind::Const { ref ty, default } => ( - self.name.ident().name, - GenericParamDefKind::Const { - did: cx.tcx.hir().local_def_id(self.hir_id).to_def_id(), - ty: Box::new(ty.clean(cx)), - default: default.map(|ct| { - let def_id = cx.tcx.hir().local_def_id(ct.hir_id); - Box::new(ty::Const::from_anon_const(cx.tcx, def_id).to_string()) - }), - }, - ), - }; + ) + } + hir::GenericParamKind::Const { ref ty, default } => ( + param.name.ident().name, + GenericParamDefKind::Const { + did: cx.tcx.hir().local_def_id(param.hir_id).to_def_id(), + ty: Box::new(ty.clean(cx)), + default: default.map(|ct| { + let def_id = cx.tcx.hir().local_def_id(ct.hir_id); + Box::new(ty::Const::from_anon_const(cx.tcx, def_id).to_string()) + }), + }, + ), + }; - GenericParamDef { name, kind } - } + GenericParamDef { name, kind } } impl Clean for hir::Generics<'_> { @@ -524,7 +554,7 @@ impl Clean for hir::Generics<'_> { .iter() .filter(|param| is_impl_trait(param)) .map(|param| { - let param: GenericParamDef = param.clean(cx); + let param = clean_generic_param(cx, Some(self), param); match param.kind { GenericParamDefKind::Lifetime { .. } => unreachable!(), GenericParamDefKind::Type { did, ref bounds, .. } => { @@ -538,14 +568,14 @@ impl Clean for hir::Generics<'_> { let mut params = Vec::with_capacity(self.params.len()); for p in self.params.iter().filter(|p| !is_impl_trait(p) && !is_elided_lifetime(p)) { - let p = p.clean(cx); + let p = clean_generic_param(cx, Some(self), p); params.push(p); } params.extend(impl_trait_params); let mut generics = Generics { params, - where_predicates: self.where_clause.predicates.iter().map(|x| x.clean(cx)).collect(), + where_predicates: self.predicates.iter().filter_map(|x| x.clean(cx)).collect(), }; // Some duplicates are generated for ?Sized bounds between type params and where @@ -954,7 +984,11 @@ impl Clean for hir::PolyTraitRef<'_> { fn clean(&self, cx: &mut DocContext<'_>) -> PolyTrait { PolyTrait { trait_: self.trait_ref.clean(cx), - generic_params: self.bound_generic_params.iter().map(|x| x.clean(cx)).collect(), + generic_params: self + .bound_generic_params + .iter() + .map(|x| clean_generic_param(cx, None, x)) + .collect(), } } } @@ -1823,7 +1857,8 @@ impl Clean for hir::BareFnTy<'_> { fn clean(&self, cx: &mut DocContext<'_>) -> BareFunctionDecl { let (generic_params, decl) = enter_impl_trait(cx, |cx| { // NOTE: generics must be cleaned before args - let generic_params = self.generic_params.iter().map(|x| x.clean(cx)).collect(); + let generic_params = + self.generic_params.iter().map(|x| clean_generic_param(cx, None, x)).collect(); let args = clean_args_from_types_and_names(cx, self.decl.inputs, self.param_names); let decl = clean_fn_decl_with_args(cx, self.decl, args); (generic_params, decl) diff --git a/src/librustdoc/html/render/span_map.rs b/src/librustdoc/html/render/span_map.rs index 06c63ec97d7f2..b5502309560ee 100644 --- a/src/librustdoc/html/render/span_map.rs +++ b/src/librustdoc/html/render/span_map.rs @@ -5,7 +5,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::{ExprKind, GenericParam, GenericParamKind, HirId, Mod, Node}; +use rustc_hir::{ExprKind, GenericParam, HirId, Mod, Node}; use rustc_middle::hir::nested_filter; use rustc_middle::ty::TyCtxt; use rustc_span::Span; @@ -100,16 +100,7 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> { self.tcx.hir() } - fn visit_generic_param(&mut self, p: &'tcx GenericParam<'tcx>) { - if !matches!(p.kind, GenericParamKind::Type { .. }) { - return; - } - for bound in p.bounds { - if let Some(trait_ref) = bound.trait_ref() { - self.handle_path(trait_ref.path, None); - } - } - } + fn visit_generic_param(&mut self, _: &'tcx GenericParam<'tcx>) {} fn visit_path(&mut self, path: &'tcx rustc_hir::Path<'tcx>, _id: HirId) { self.handle_path(path, None); diff --git a/src/test/ui/async-await/issue-86507.stderr b/src/test/ui/async-await/issue-86507.stderr index ad0a359224147..5bbc20359c64a 100644 --- a/src/test/ui/async-await/issue-86507.stderr +++ b/src/test/ui/async-await/issue-86507.stderr @@ -14,10 +14,10 @@ note: captured value is not `Send` because `&` references cannot be sent unless LL | let x = x; | ^ has type `&T` which is not `Send`, because `T` is not `Sync` = note: required for the cast to the object type `dyn Future + Send` -help: consider further restricting type parameter `T` +help: consider further restricting this bound | -LL | where 'me:'async_trait, T: std::marker::Sync { - | ++++++++++++++++++++++ +LL | fn bar<'me, 'async_trait, T: Send + std::marker::Sync>(x: &'me T) + | +++++++++++++++++++ error: aborting due to previous error diff --git a/src/test/ui/builtin-superkinds/builtin-superkinds-self-type.stderr b/src/test/ui/builtin-superkinds/builtin-superkinds-self-type.stderr index 2dac4a22ae713..b1e59e9d5de36 100644 --- a/src/test/ui/builtin-superkinds/builtin-superkinds-self-type.stderr +++ b/src/test/ui/builtin-superkinds/builtin-superkinds-self-type.stderr @@ -2,9 +2,12 @@ error[E0310]: the parameter type `T` may not live long enough --> $DIR/builtin-superkinds-self-type.rs:10:16 | LL | impl Foo for T { } - | -- ^^^ ...so that the type `T` will meet its required lifetime bounds - | | - | help: consider adding an explicit lifetime bound...: `T: 'static +` + | ^^^ ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | impl Foo for T { } + | +++++++++ error: aborting due to previous error diff --git a/src/test/ui/feature-gates/feature-gate-infer_static_outlives_requirements.stderr b/src/test/ui/feature-gates/feature-gate-infer_static_outlives_requirements.stderr index 2bccec4589441..7ffebab415334 100644 --- a/src/test/ui/feature-gates/feature-gate-infer_static_outlives_requirements.stderr +++ b/src/test/ui/feature-gates/feature-gate-infer_static_outlives_requirements.stderr @@ -1,8 +1,6 @@ error[E0310]: the parameter type `U` may not live long enough --> $DIR/feature-gate-infer_static_outlives_requirements.rs:5:10 | -LL | struct Foo { - | - help: consider adding an explicit lifetime bound...: `U: 'static` LL | bar: Bar | ^^^^^^ ...so that the type `U` will meet its required lifetime bounds... | @@ -11,6 +9,10 @@ note: ...that is required by this bound | LL | struct Bar { | ^^^^^^^ +help: consider adding an explicit lifetime bound... + | +LL | struct Foo { + | +++++++++ error: aborting due to previous error diff --git a/src/test/ui/generic-associated-types/issue-86483.stderr b/src/test/ui/generic-associated-types/issue-86483.stderr index 2f29cd5d9e900..a13dc043dc52b 100644 --- a/src/test/ui/generic-associated-types/issue-86483.stderr +++ b/src/test/ui/generic-associated-types/issue-86483.stderr @@ -1,10 +1,7 @@ error[E0311]: the parameter type `T` may not live long enough --> $DIR/issue-86483.rs:5:1 | -LL | pub trait IceIce - | ^ - help: consider adding an explicit lifetime bound...: `T: 'a` - | _| - | | +LL | / pub trait IceIce LL | | where LL | | for<'a> T: 'a, LL | | { @@ -19,13 +16,14 @@ note: ...that is required by this bound | LL | for<'a> T: 'a, | ^^ +help: consider adding an explicit lifetime bound... + | +LL | for<'a> T: 'a + 'a, + | ++++ error[E0311]: the parameter type `T` may not live long enough --> $DIR/issue-86483.rs:9:5 | -LL | pub trait IceIce - | - help: consider adding an explicit lifetime bound...: `T: 'a` -... LL | type Ice<'v>: IntoIterator; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds... | @@ -34,6 +32,10 @@ note: ...that is required by this bound | LL | for<'a> T: 'a, | ^^ +help: consider adding an explicit lifetime bound... + | +LL | for<'a> T: 'a + 'a, + | ++++ error[E0309]: the parameter type `T` may not live long enough --> $DIR/issue-86483.rs:9:32 diff --git a/src/test/ui/generic-associated-types/issue-91139.migrate.stderr b/src/test/ui/generic-associated-types/issue-91139.migrate.stderr index a27d811023834..b424d9a2fdb0c 100644 --- a/src/test/ui/generic-associated-types/issue-91139.migrate.stderr +++ b/src/test/ui/generic-associated-types/issue-91139.migrate.stderr @@ -1,10 +1,13 @@ error[E0311]: the parameter type `T` may not live long enough --> $DIR/issue-91139.rs:27:12 | -LL | fn foo() { - | - help: consider adding an explicit lifetime bound...: `T: 'a` LL | let _: for<'a> fn(<() as Foo>::Type<'a>, &'a T) = |_, _| (); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | fn foo() { + | ++++ error: aborting due to previous error diff --git a/src/test/ui/generic-associated-types/issue-92096.migrate.stderr b/src/test/ui/generic-associated-types/issue-92096.migrate.stderr index 72ade5774d749..c74161cd3e059 100644 --- a/src/test/ui/generic-associated-types/issue-92096.migrate.stderr +++ b/src/test/ui/generic-associated-types/issue-92096.migrate.stderr @@ -2,17 +2,23 @@ error[E0311]: the parameter type `C` may not live long enough --> $DIR/issue-92096.rs:20:33 | LL | fn call_connect(c: &'_ C) -> impl '_ + Future + Send - | - ^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `C` will meet its required lifetime bounds - | | - | help: consider adding an explicit lifetime bound...: `C: 'a` + | ^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `C` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | C: Client + Send + Sync + 'a, + | ++++ error[E0311]: the parameter type `C` may not live long enough --> $DIR/issue-92096.rs:20:33 | LL | fn call_connect(c: &'_ C) -> impl '_ + Future + Send - | - ^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `C` will meet its required lifetime bounds - | | - | help: consider adding an explicit lifetime bound...: `C: 'a` + | ^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `C` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | C: Client + Send + Sync + 'a, + | ++++ error: aborting due to 2 previous errors diff --git a/src/test/ui/generic-associated-types/missing-bounds.stderr b/src/test/ui/generic-associated-types/missing-bounds.stderr index aaeec920527ed..5323ee172267f 100644 --- a/src/test/ui/generic-associated-types/missing-bounds.stderr +++ b/src/test/ui/generic-associated-types/missing-bounds.stderr @@ -87,10 +87,10 @@ note: tuple struct defined here | LL | struct E(B); | ^ -help: consider further restricting type parameter `B` +help: consider further restricting this bound | -LL | impl Add for E where ::Output = B, B: Add { - | ++++++++++++++++++++ +LL | impl> Add for E where ::Output = B { + | +++++++++++++++++ error: aborting due to 5 previous errors diff --git a/src/test/ui/generic-associated-types/unsatified-item-lifetime-bound.stderr b/src/test/ui/generic-associated-types/unsatified-item-lifetime-bound.stderr index 4f0a023ee39c3..ae52010cc50a2 100644 --- a/src/test/ui/generic-associated-types/unsatified-item-lifetime-bound.stderr +++ b/src/test/ui/generic-associated-types/unsatified-item-lifetime-bound.stderr @@ -2,7 +2,7 @@ warning: unnecessary lifetime parameter `'a` --> $DIR/unsatified-item-lifetime-bound.rs:4:12 | LL | type Y<'a: 'static>; - | ^^^^^^^^^^^ + | ^^ | = help: you can use the `'static` lifetime directly, in place of `'a` diff --git a/src/test/ui/impl-trait/equal-hidden-lifetimes.stderr b/src/test/ui/impl-trait/equal-hidden-lifetimes.stderr index 51247f1d7b07a..3e48aef553b16 100644 --- a/src/test/ui/impl-trait/equal-hidden-lifetimes.stderr +++ b/src/test/ui/impl-trait/equal-hidden-lifetimes.stderr @@ -2,7 +2,7 @@ warning: unnecessary lifetime parameter `'a` --> $DIR/equal-hidden-lifetimes.rs:7:25 | LL | fn equal_regions_static<'a: 'static>(x: &'a i32) -> impl Sized { - | ^^^^^^^^^^^ + | ^^ | = help: you can use the `'static` lifetime directly, in place of `'a` diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr index 2681241bbad2b..db737a9c544c0 100644 --- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr +++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.nll.stderr @@ -112,11 +112,13 @@ LL | fn move_lifetime_into_fn<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Fn(&'a u32 error[E0310]: the parameter type `T` may not live long enough --> $DIR/must_outlive_least_region_or_bound.rs:40:5 | -LL | fn ty_param_wont_outlive_static(x: T) -> impl Debug + 'static { - | -- help: consider adding an explicit lifetime bound...: `T: 'static +` -LL | LL | x | ^ ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | fn ty_param_wont_outlive_static(x: T) -> impl Debug + 'static { + | +++++++++ error: aborting due to 9 previous errors diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr index 6bcfb27ce1653..dade2b91fe0b6 100644 --- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr +++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr @@ -128,9 +128,12 @@ error[E0310]: the parameter type `T` may not live long enough --> $DIR/must_outlive_least_region_or_bound.rs:38:51 | LL | fn ty_param_wont_outlive_static(x: T) -> impl Debug + 'static { - | -- ^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds - | | - | help: consider adding an explicit lifetime bound...: `T: 'static +` + | ^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | fn ty_param_wont_outlive_static(x: T) -> impl Debug + 'static { + | +++++++++ error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement --> $DIR/must_outlive_least_region_or_bound.rs:16:50 diff --git a/src/test/ui/impl-trait/type_parameters_captured.nll.stderr b/src/test/ui/impl-trait/type_parameters_captured.nll.stderr index 1cd5b65b9749b..3050f10b2057d 100644 --- a/src/test/ui/impl-trait/type_parameters_captured.nll.stderr +++ b/src/test/ui/impl-trait/type_parameters_captured.nll.stderr @@ -1,11 +1,13 @@ error[E0310]: the parameter type `T` may not live long enough --> $DIR/type_parameters_captured.rs:9:5 | -LL | fn foo(x: T) -> impl Any + 'static { - | - help: consider adding an explicit lifetime bound...: `T: 'static` -LL | LL | x | ^ ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | fn foo(x: T) -> impl Any + 'static { + | +++++++++ error: aborting due to previous error diff --git a/src/test/ui/impl-trait/type_parameters_captured.stderr b/src/test/ui/impl-trait/type_parameters_captured.stderr index 40e50b9922f8d..9f28a8d44a7b7 100644 --- a/src/test/ui/impl-trait/type_parameters_captured.stderr +++ b/src/test/ui/impl-trait/type_parameters_captured.stderr @@ -2,9 +2,12 @@ error[E0310]: the parameter type `T` may not live long enough --> $DIR/type_parameters_captured.rs:7:20 | LL | fn foo(x: T) -> impl Any + 'static { - | - ^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds - | | - | help: consider adding an explicit lifetime bound...: `T: 'static` + | ^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | fn foo(x: T) -> impl Any + 'static { + | +++++++++ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-30438-c.rs b/src/test/ui/issues/issue-30438-c.rs index 813c1d3e2cccd..4cf634245be1b 100644 --- a/src/test/ui/issues/issue-30438-c.rs +++ b/src/test/ui/issues/issue-30438-c.rs @@ -5,6 +5,7 @@ trait Trait { type Out; } struct Test<'a> { s: &'a str } fn silly<'y, 'z>(_s: &'y Test<'z>) -> &'y as Trait>::Out where 'z: 'static { + //~^ WARN unnecessary lifetime parameter `'z` let x = Test { s: "this cannot last" }; &x //~^ ERROR: cannot return reference to local variable `x` diff --git a/src/test/ui/issues/issue-30438-c.stderr b/src/test/ui/issues/issue-30438-c.stderr index 7c001088097ab..a7a5c0500fd23 100644 --- a/src/test/ui/issues/issue-30438-c.stderr +++ b/src/test/ui/issues/issue-30438-c.stderr @@ -1,9 +1,17 @@ +warning: unnecessary lifetime parameter `'z` + --> $DIR/issue-30438-c.rs:7:74 + | +LL | fn silly<'y, 'z>(_s: &'y Test<'z>) -> &'y as Trait>::Out where 'z: 'static { + | ^^ + | + = help: you can use the `'static` lifetime directly, in place of `'z` + error[E0515]: cannot return reference to local variable `x` - --> $DIR/issue-30438-c.rs:9:5 + --> $DIR/issue-30438-c.rs:10:5 | LL | &x | ^^ returns a reference to data owned by the current function -error: aborting due to previous error +error: aborting due to previous error; 1 warning emitted For more information about this error, try `rustc --explain E0515`. diff --git a/src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr b/src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr index e5083e3a088b6..33f6c498b6f35 100644 --- a/src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr +++ b/src/test/ui/lifetimes/lifetime-doesnt-live-long-enough.stderr @@ -1,18 +1,24 @@ error[E0310]: the parameter type `T` may not live long enough --> $DIR/lifetime-doesnt-live-long-enough.rs:19:10 | -LL | struct Foo { - | - help: consider adding an explicit lifetime bound...: `T: 'static` LL | foo: &'static T | ^^^^^^^^^^ ...so that the reference type `&'static T` does not outlive the data it points at + | +help: consider adding an explicit lifetime bound... + | +LL | struct Foo { + | +++++++++ error[E0309]: the parameter type `K` may not live long enough --> $DIR/lifetime-doesnt-live-long-enough.rs:24:19 | -LL | trait X: Sized { - | - help: consider adding an explicit lifetime bound...: `K: 'a` LL | fn foo<'a, L: X<&'a Nested>>(); | ^^^^^^^^^^^^^^^^ ...so that the reference type `&'a Nested` does not outlive the data it points at + | +help: consider adding an explicit lifetime bound... + | +LL | trait X: Sized { + | ++++ error[E0309]: the parameter type `Self` may not live long enough --> $DIR/lifetime-doesnt-live-long-enough.rs:28:19 @@ -27,25 +33,34 @@ error[E0309]: the parameter type `L` may not live long enough --> $DIR/lifetime-doesnt-live-long-enough.rs:32:22 | LL | fn baz<'a, L, M: X<&'a Nested>>() { - | - ^^^^^^^^^^^^^^^^ ...so that the reference type `&'a Nested` does not outlive the data it points at - | | - | help: consider adding an explicit lifetime bound...: `L: 'a` + | ^^^^^^^^^^^^^^^^ ...so that the reference type `&'a Nested` does not outlive the data it points at + | +help: consider adding an explicit lifetime bound... + | +LL | fn baz<'a, L: 'a, M: X<&'a Nested>>() { + | ++++ error[E0309]: the parameter type `K` may not live long enough --> $DIR/lifetime-doesnt-live-long-enough.rs:41:33 | -LL | impl Nested { - | - help: consider adding an explicit lifetime bound...: `K: 'a` LL | fn generic_in_parent<'a, L: X<&'a Nested>>() { | ^^^^^^^^^^^^^^^^ ...so that the reference type `&'a Nested` does not outlive the data it points at + | +help: consider adding an explicit lifetime bound... + | +LL | impl Nested { + | ++++ error[E0309]: the parameter type `M` may not live long enough --> $DIR/lifetime-doesnt-live-long-enough.rs:44:36 | LL | fn generic_in_child<'a, 'b, L: X<&'a Nested>, M: 'b>() { - | ^^^^^^^^^^^^^^^^ -- help: consider adding an explicit lifetime bound...: `M: 'a +` - | | - | ...so that the reference type `&'a Nested` does not outlive the data it points at + | ^^^^^^^^^^^^^^^^ ...so that the reference type `&'a Nested` does not outlive the data it points at + | +help: consider adding an explicit lifetime bound... + | +LL | fn generic_in_child<'a, 'b, L: X<&'a Nested>, M: 'b + 'a>() { + | ++++ error: aborting due to 6 previous errors diff --git a/src/test/ui/lifetimes/lifetime-errors/issue_74400.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/issue_74400.nll.stderr index 422673b361a95..2906c05864bae 100644 --- a/src/test/ui/lifetimes/lifetime-errors/issue_74400.nll.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/issue_74400.nll.stderr @@ -1,10 +1,13 @@ error[E0310]: the parameter type `T` may not live long enough --> $DIR/issue_74400.rs:12:5 | -LL | fn g(data: &[T]) { - | - help: consider adding an explicit lifetime bound...: `T: 'static` LL | f(data, identity) | ^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | fn g(data: &[T]) { + | +++++++++ error[E0308]: mismatched types --> $DIR/issue_74400.rs:12:5 diff --git a/src/test/ui/moves/use_of_moved_value_copy_suggestions.fixed b/src/test/ui/moves/use_of_moved_value_copy_suggestions.fixed index fb6cf7e8996c0..ba1b745ba8422 100644 --- a/src/test/ui/moves/use_of_moved_value_copy_suggestions.fixed +++ b/src/test/ui/moves/use_of_moved_value_copy_suggestions.fixed @@ -54,17 +54,17 @@ where fn duplicate_custom_3(t: S) -> (S, S) where - T: A, - T: B, T: Trait, T: Copy - //~^ HELP consider further restricting type parameter `T` + T: A + Trait + Copy, + //~^ HELP consider further restricting this bound + T: B, { (t, t) //~ use of moved value: `t` } -fn duplicate_custom_4(t: S) -> (S, S) +fn duplicate_custom_4(t: S) -> (S, S) +//~^ HELP consider further restricting this bound where - T: B + Trait + Copy, - //~^ HELP consider further restricting this bound + T: B, { (t, t) //~ use of moved value: `t` } @@ -77,8 +77,8 @@ fn existing_colon(t: T) { fn existing_colon_in_where(t: T) where - T: Copy, - //~^ HELP consider further restricting this bound + T:, T: Copy + //~^ HELP consider further restricting type parameter `T` { [t, t]; //~ use of moved value: `t` } diff --git a/src/test/ui/moves/use_of_moved_value_copy_suggestions.rs b/src/test/ui/moves/use_of_moved_value_copy_suggestions.rs index cadbf2a54cc37..0a43dd1a9a387 100644 --- a/src/test/ui/moves/use_of_moved_value_copy_suggestions.rs +++ b/src/test/ui/moves/use_of_moved_value_copy_suggestions.rs @@ -55,16 +55,16 @@ where fn duplicate_custom_3(t: S) -> (S, S) where T: A, + //~^ HELP consider further restricting this bound T: B, - //~^ HELP consider further restricting type parameter `T` { (t, t) //~ use of moved value: `t` } fn duplicate_custom_4(t: S) -> (S, S) +//~^ HELP consider further restricting this bound where T: B, - //~^ HELP consider further restricting this bound { (t, t) //~ use of moved value: `t` } @@ -78,7 +78,7 @@ fn existing_colon(t: T) { fn existing_colon_in_where(t: T) where T:, - //~^ HELP consider further restricting this bound + //~^ HELP consider further restricting type parameter `T` { [t, t]; //~ use of moved value: `t` } diff --git a/src/test/ui/moves/use_of_moved_value_copy_suggestions.stderr b/src/test/ui/moves/use_of_moved_value_copy_suggestions.stderr index f5252084d6884..2353cd079a370 100644 --- a/src/test/ui/moves/use_of_moved_value_copy_suggestions.stderr +++ b/src/test/ui/moves/use_of_moved_value_copy_suggestions.stderr @@ -121,10 +121,10 @@ LL | (t, t) | | | value moved here | -help: consider further restricting type parameter `T` +help: consider further restricting this bound | -LL | T: B, T: Trait, T: Copy - | ~~~~~~~~~~~~~~~~~~~ +LL | T: A + Trait + Copy, + | ++++++++++++++ error[E0382]: use of moved value: `t` --> $DIR/use_of_moved_value_copy_suggestions.rs:69:9 @@ -139,8 +139,8 @@ LL | (t, t) | help: consider further restricting this bound | -LL | T: B + Trait + Copy, - | ++++++++++++++ +LL | fn duplicate_custom_4(t: S) -> (S, S) + | ++++++++++++++ error[E0382]: use of moved value: `t` --> $DIR/use_of_moved_value_copy_suggestions.rs:83:9 @@ -153,10 +153,10 @@ LL | [t, t]; | | | value moved here | -help: consider further restricting this bound +help: consider further restricting type parameter `T` | -LL | T: Copy, - | ++++ +LL | T:, T: Copy + | ~~~~~~~~~ error[E0382]: use of moved value: `t` --> $DIR/use_of_moved_value_copy_suggestions.rs:75:9 diff --git a/src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr b/src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr index b6856089a84f9..08605efa2ea9c 100644 --- a/src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr @@ -36,9 +36,6 @@ LL | | } error[E0309]: the parameter type `T` may not live long enough --> $DIR/propagate-from-trait-match.rs:32:36 | -LL | fn supply<'a, T>(value: T) - | - help: consider adding an explicit lifetime bound...: `T: 'a` -... LL | establish_relationships(value, |value| { | ____________________________________^ LL | | @@ -48,6 +45,11 @@ LL | | // This function call requires that LL | | require(value); LL | | }); | |_____^ ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | T: Trait<'a> + 'a, + | ++++ error: aborting due to previous error diff --git a/src/test/ui/nll/ty-outlives/impl-trait-outlives.stderr b/src/test/ui/nll/ty-outlives/impl-trait-outlives.stderr index 3d4cfc1610a66..64b08a9b32fb3 100644 --- a/src/test/ui/nll/ty-outlives/impl-trait-outlives.stderr +++ b/src/test/ui/nll/ty-outlives/impl-trait-outlives.stderr @@ -1,20 +1,24 @@ error[E0309]: the parameter type `T` may not live long enough --> $DIR/impl-trait-outlives.rs:11:5 | -LL | fn no_region<'a, T>(x: Box) -> impl Debug + 'a - | - help: consider adding an explicit lifetime bound...: `T: 'a` -... LL | x | ^ ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | T: Debug + 'a, + | ++++ error[E0309]: the parameter type `T` may not live long enough --> $DIR/impl-trait-outlives.rs:26:5 | -LL | fn wrong_region<'a, 'b, T>(x: Box) -> impl Debug + 'a - | - help: consider adding an explicit lifetime bound...: `T: 'a` -... LL | x | ^ ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | T: 'b + Debug + 'a, + | ++++ error: aborting due to 2 previous errors diff --git a/src/test/ui/nll/ty-outlives/projection-implied-bounds.stderr b/src/test/ui/nll/ty-outlives/projection-implied-bounds.stderr index cc5aa1eb11ec0..3b9b2956c5183 100644 --- a/src/test/ui/nll/ty-outlives/projection-implied-bounds.stderr +++ b/src/test/ui/nll/ty-outlives/projection-implied-bounds.stderr @@ -1,10 +1,13 @@ error[E0310]: the parameter type `T` may not live long enough --> $DIR/projection-implied-bounds.rs:30:18 | -LL | fn generic2(value: T) { - | -- help: consider adding an explicit lifetime bound...: `T: 'static +` LL | twice(value, |value_ref, item| invoke2(value_ref, item)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | fn generic2(value: T) { + | +++++++++ error: aborting due to previous error diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr index 62db6dd845a28..caf2e3c474755 100644 --- a/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr @@ -31,11 +31,13 @@ LL | | } error[E0309]: the parameter type `T` may not live long enough --> $DIR/projection-one-region-closure.rs:45:29 | -LL | fn no_relationships_late<'a, 'b, T>(cell: Cell<&'a ()>, t: T) - | - help: consider adding an explicit lifetime bound...: `T: 'a` -... LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | T: Anything<'b> + 'a, + | ++++ error: lifetime may not live long enough --> $DIR/projection-one-region-closure.rs:45:39 @@ -82,11 +84,13 @@ LL | | } error[E0309]: the parameter type `T` may not live long enough --> $DIR/projection-one-region-closure.rs:56:29 | -LL | fn no_relationships_early<'a, 'b, T>(cell: Cell<&'a ()>, t: T) - | - help: consider adding an explicit lifetime bound...: `T: 'a` -... LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | T: Anything<'b> + 'a, + | ++++ error: lifetime may not live long enough --> $DIR/projection-one-region-closure.rs:56:39 diff --git a/src/test/ui/nll/ty-outlives/projection-where-clause-none.stderr b/src/test/ui/nll/ty-outlives/projection-where-clause-none.stderr index c51edb7868d7a..e28b89580bc4c 100644 --- a/src/test/ui/nll/ty-outlives/projection-where-clause-none.stderr +++ b/src/test/ui/nll/ty-outlives/projection-where-clause-none.stderr @@ -1,11 +1,13 @@ error[E0309]: the parameter type `T` may not live long enough --> $DIR/projection-where-clause-none.rs:16:5 | -LL | fn foo<'a, T>() -> &'a () - | - help: consider adding an explicit lifetime bound...: `T: 'a` -... LL | bar::() | ^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | T: MyTrait<'a> + 'a, + | ++++ error: aborting due to previous error diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr b/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr index 3e5e4868341ed..a4588730b3f87 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr +++ b/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr @@ -52,10 +52,13 @@ LL | | } error[E0309]: the parameter type `T` may not live long enough --> $DIR/ty-param-closure-approximate-lower-bound.rs:29:24 | -LL | fn generic_fail<'a, T>(cell: Cell<&'a ()>, value: T) { - | - help: consider adding an explicit lifetime bound...: `T: 'a` LL | twice(cell, value, |a, b| invoke(a, b)); | ^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | fn generic_fail<'a, T: 'a>(cell: Cell<&'a ()>, value: T) { + | ++++ error: aborting due to previous error diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr index dc2f23b4fc8a3..084dd93cb86b9 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr +++ b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr @@ -29,20 +29,24 @@ LL | | } error[E0309]: the parameter type `T` may not live long enough --> $DIR/ty-param-closure-outlives-from-return-type.rs:26:23 | -LL | fn no_region<'a, T>(x: Box) -> Box - | - help: consider adding an explicit lifetime bound...: `T: 'a` -... LL | with_signature(x, |y| y) | ^^^^^ ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | T: Debug + 'a, + | ++++ error[E0309]: the parameter type `T` may not live long enough --> $DIR/ty-param-closure-outlives-from-return-type.rs:41:5 | -LL | fn wrong_region<'a, 'b, T>(x: Box) -> Box - | - help: consider adding an explicit lifetime bound...: `T: 'a` -... LL | x | ^ ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | T: 'b + Debug + 'a, + | ++++ error: aborting due to 2 previous errors diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr index e9f728c77b34b..11a737ba291f0 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr +++ b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr @@ -37,8 +37,6 @@ LL | | } error[E0309]: the parameter type `T` may not live long enough --> $DIR/ty-param-closure-outlives-from-where-clause.rs:27:26 | -LL | fn no_region<'a, T>(a: Cell<&'a ()>, b: T) { - | - help: consider adding an explicit lifetime bound...: `T: 'a` LL | with_signature(a, b, |x, y| { | __________________________^ LL | | @@ -48,6 +46,11 @@ LL | | // See `correct_region`, which explains the point of this LL | | require(&x, &y) LL | | }) | |_____^ ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | fn no_region<'a, T: 'a>(a: Cell<&'a ()>, b: T) { + | ++++ note: external requirements --> $DIR/ty-param-closure-outlives-from-where-clause.rs:43:26 @@ -121,9 +124,6 @@ LL | | } error[E0309]: the parameter type `T` may not live long enough --> $DIR/ty-param-closure-outlives-from-where-clause.rs:64:26 | -LL | fn wrong_region<'a, 'b, T>(a: Cell<&'a ()>, b: T) - | - help: consider adding an explicit lifetime bound...: `T: 'a` -... LL | with_signature(a, b, |x, y| { | __________________________^ LL | | @@ -131,6 +131,11 @@ LL | | // See `correct_region` LL | | require(&x, &y) LL | | }) | |_____^ ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | T: 'b + 'a, + | ++++ note: external requirements --> $DIR/ty-param-closure-outlives-from-where-clause.rs:77:26 diff --git a/src/test/ui/nll/ty-outlives/ty-param-fn-body.stderr b/src/test/ui/nll/ty-outlives/ty-param-fn-body.stderr index a2e6a5d57cd62..ba79137d18d8c 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-fn-body.stderr +++ b/src/test/ui/nll/ty-outlives/ty-param-fn-body.stderr @@ -1,10 +1,13 @@ error[E0309]: the parameter type `T` may not live long enough --> $DIR/ty-param-fn-body.rs:19:5 | -LL | fn region_static<'a, T>(cell: Cell<&'a usize>, t: T) { - | - help: consider adding an explicit lifetime bound...: `T: 'a` LL | outlives(cell, t) | ^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | fn region_static<'a, T: 'a>(cell: Cell<&'a usize>, t: T) { + | ++++ error: aborting due to previous error diff --git a/src/test/ui/nll/ty-outlives/ty-param-fn.stderr b/src/test/ui/nll/ty-outlives/ty-param-fn.stderr index fce360dd54bfb..729f14d84adaf 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-fn.stderr +++ b/src/test/ui/nll/ty-outlives/ty-param-fn.stderr @@ -1,20 +1,24 @@ error[E0309]: the parameter type `T` may not live long enough --> $DIR/ty-param-fn.rs:11:5 | -LL | fn no_region<'a, T>(x: Box) -> Box - | - help: consider adding an explicit lifetime bound...: `T: 'a` -... LL | x | ^ ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | T: Debug + 'a, + | ++++ error[E0309]: the parameter type `T` may not live long enough --> $DIR/ty-param-fn.rs:26:5 | -LL | fn wrong_region<'a, 'b, T>(x: Box) -> Box - | - help: consider adding an explicit lifetime bound...: `T: 'a` -... LL | x | ^ ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | T: 'b + Debug + 'a, + | ++++ error: aborting due to 2 previous errors diff --git a/src/test/ui/regions/regions-close-object-into-object-4.nll.stderr b/src/test/ui/regions/regions-close-object-into-object-4.nll.stderr index 05ddc09b2d0b7..66d3102225ecc 100644 --- a/src/test/ui/regions/regions-close-object-into-object-4.nll.stderr +++ b/src/test/ui/regions/regions-close-object-into-object-4.nll.stderr @@ -1,26 +1,35 @@ error[E0310]: the parameter type `U` may not live long enough --> $DIR/regions-close-object-into-object-4.rs:13:5 | -LL | fn i<'a, T, U>(v: Box+'a>) -> Box { - | - help: consider adding an explicit lifetime bound...: `U: 'static` LL | Box::new(B(&*v)) as Box | ^^^^^^^^ ...so that the type `U` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | fn i<'a, T, U: 'static>(v: Box+'a>) -> Box { + | +++++++++ error[E0310]: the parameter type `U` may not live long enough --> $DIR/regions-close-object-into-object-4.rs:13:5 | -LL | fn i<'a, T, U>(v: Box+'a>) -> Box { - | - help: consider adding an explicit lifetime bound...: `U: 'static` LL | Box::new(B(&*v)) as Box | ^^^^^^^^^^^^^^^^ ...so that the type `U` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | fn i<'a, T, U: 'static>(v: Box+'a>) -> Box { + | +++++++++ error[E0310]: the parameter type `U` may not live long enough --> $DIR/regions-close-object-into-object-4.rs:13:5 | -LL | fn i<'a, T, U>(v: Box+'a>) -> Box { - | - help: consider adding an explicit lifetime bound...: `U: 'static` LL | Box::new(B(&*v)) as Box | ^^^^^^^^^^^^^^^^ ...so that the type `U` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | fn i<'a, T, U: 'static>(v: Box+'a>) -> Box { + | +++++++++ error: lifetime may not live long enough --> $DIR/regions-close-object-into-object-4.rs:13:5 @@ -51,10 +60,13 @@ LL | Box::new(B(&*v)) as Box error[E0310]: the parameter type `U` may not live long enough --> $DIR/regions-close-object-into-object-4.rs:13:14 | -LL | fn i<'a, T, U>(v: Box+'a>) -> Box { - | - help: consider adding an explicit lifetime bound...: `U: 'static` LL | Box::new(B(&*v)) as Box | ^^^^^^ ...so that the type `U` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | fn i<'a, T, U: 'static>(v: Box+'a>) -> Box { + | +++++++++ error: aborting due to 6 previous errors diff --git a/src/test/ui/regions/regions-close-object-into-object-5.base.stderr b/src/test/ui/regions/regions-close-object-into-object-5.base.stderr index 8b5a06bab7156..1a78079b638d8 100644 --- a/src/test/ui/regions/regions-close-object-into-object-5.base.stderr +++ b/src/test/ui/regions/regions-close-object-into-object-5.base.stderr @@ -1,9 +1,6 @@ error[E0310]: the parameter type `T` may not live long enough --> $DIR/regions-close-object-into-object-5.rs:21:5 | -LL | fn f<'a, T, U>(v: Box + 'static>) -> Box { - | - help: consider adding an explicit lifetime bound...: `T: 'static` -LL | // oh dear! LL | Box::new(B(&*v)) as Box | ^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds... | @@ -12,22 +9,25 @@ note: ...that is required by this bound | LL | struct B<'a, T: 'a>(&'a (A + 'a)); | ^^ +help: consider adding an explicit lifetime bound... + | +LL | fn f<'a, T: 'static, U>(v: Box + 'static>) -> Box { + | +++++++++ error[E0310]: the parameter type `T` may not live long enough --> $DIR/regions-close-object-into-object-5.rs:21:5 | -LL | fn f<'a, T, U>(v: Box + 'static>) -> Box { - | - help: consider adding an explicit lifetime bound...: `T: 'static` -LL | // oh dear! LL | Box::new(B(&*v)) as Box | ^^^^^^^^^^^^^^^^ ...so that the type `B<'_, T>` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | fn f<'a, T: 'static, U>(v: Box + 'static>) -> Box { + | +++++++++ error[E0310]: the parameter type `T` may not live long enough --> $DIR/regions-close-object-into-object-5.rs:21:14 | -LL | fn f<'a, T, U>(v: Box + 'static>) -> Box { - | - help: consider adding an explicit lifetime bound...: `T: 'static` -LL | // oh dear! LL | Box::new(B(&*v)) as Box | ^ ...so that the type `T` will meet its required lifetime bounds... | @@ -36,13 +36,14 @@ note: ...that is required by this bound | LL | struct B<'a, T: 'a>(&'a (A + 'a)); | ^^ +help: consider adding an explicit lifetime bound... + | +LL | fn f<'a, T: 'static, U>(v: Box + 'static>) -> Box { + | +++++++++ error[E0310]: the parameter type `T` may not live long enough --> $DIR/regions-close-object-into-object-5.rs:21:14 | -LL | fn f<'a, T, U>(v: Box + 'static>) -> Box { - | - help: consider adding an explicit lifetime bound...: `T: 'static` -LL | // oh dear! LL | Box::new(B(&*v)) as Box | ^^^^^^ ...so that the type `T` will meet its required lifetime bounds... | @@ -51,33 +52,43 @@ note: ...that is required by this bound | LL | struct B<'a, T: 'a>(&'a (A + 'a)); | ^^ +help: consider adding an explicit lifetime bound... + | +LL | fn f<'a, T: 'static, U>(v: Box + 'static>) -> Box { + | +++++++++ error[E0310]: the parameter type `T` may not live long enough --> $DIR/regions-close-object-into-object-5.rs:21:16 | -LL | fn f<'a, T, U>(v: Box + 'static>) -> Box { - | - help: consider adding an explicit lifetime bound...: `T: 'static` -LL | // oh dear! LL | Box::new(B(&*v)) as Box | ^^^ ...so that the reference type `&dyn A` does not outlive the data it points at + | +help: consider adding an explicit lifetime bound... + | +LL | fn f<'a, T: 'static, U>(v: Box + 'static>) -> Box { + | +++++++++ error[E0310]: the parameter type `T` may not live long enough --> $DIR/regions-close-object-into-object-5.rs:21:16 | -LL | fn f<'a, T, U>(v: Box + 'static>) -> Box { - | - help: consider adding an explicit lifetime bound...: `T: 'static` -LL | // oh dear! LL | Box::new(B(&*v)) as Box | ^^^ ...so that the type `(dyn A + 'static)` is not borrowed for too long + | +help: consider adding an explicit lifetime bound... + | +LL | fn f<'a, T: 'static, U>(v: Box + 'static>) -> Box { + | +++++++++ error[E0310]: the parameter type `T` may not live long enough --> $DIR/regions-close-object-into-object-5.rs:21:16 | -LL | fn f<'a, T, U>(v: Box + 'static>) -> Box { - | - help: consider adding an explicit lifetime bound...: `T: 'static` -LL | // oh dear! LL | Box::new(B(&*v)) as Box | ^^^ ...so that the type `(dyn A + 'static)` is not borrowed for too long + | +help: consider adding an explicit lifetime bound... + | +LL | fn f<'a, T: 'static, U>(v: Box + 'static>) -> Box { + | +++++++++ error: aborting due to 7 previous errors diff --git a/src/test/ui/regions/regions-close-object-into-object-5.nll.stderr b/src/test/ui/regions/regions-close-object-into-object-5.nll.stderr index f4e3809e91613..cb06326130e10 100644 --- a/src/test/ui/regions/regions-close-object-into-object-5.nll.stderr +++ b/src/test/ui/regions/regions-close-object-into-object-5.nll.stderr @@ -1,29 +1,35 @@ error[E0310]: the parameter type `T` may not live long enough --> $DIR/regions-close-object-into-object-5.rs:21:5 | -LL | fn f<'a, T, U>(v: Box + 'static>) -> Box { - | - help: consider adding an explicit lifetime bound...: `T: 'static` -LL | // oh dear! LL | Box::new(B(&*v)) as Box | ^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | fn f<'a, T: 'static, U>(v: Box + 'static>) -> Box { + | +++++++++ error[E0310]: the parameter type `T` may not live long enough --> $DIR/regions-close-object-into-object-5.rs:21:5 | -LL | fn f<'a, T, U>(v: Box + 'static>) -> Box { - | - help: consider adding an explicit lifetime bound...: `T: 'static` -LL | // oh dear! LL | Box::new(B(&*v)) as Box | ^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | fn f<'a, T: 'static, U>(v: Box + 'static>) -> Box { + | +++++++++ error[E0310]: the parameter type `T` may not live long enough --> $DIR/regions-close-object-into-object-5.rs:21:5 | -LL | fn f<'a, T, U>(v: Box + 'static>) -> Box { - | - help: consider adding an explicit lifetime bound...: `T: 'static` -LL | // oh dear! LL | Box::new(B(&*v)) as Box | ^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | fn f<'a, T: 'static, U>(v: Box + 'static>) -> Box { + | +++++++++ error[E0515]: cannot return value referencing local data `*v` --> $DIR/regions-close-object-into-object-5.rs:21:5 @@ -37,11 +43,13 @@ LL | Box::new(B(&*v)) as Box error[E0310]: the parameter type `T` may not live long enough --> $DIR/regions-close-object-into-object-5.rs:21:14 | -LL | fn f<'a, T, U>(v: Box + 'static>) -> Box { - | - help: consider adding an explicit lifetime bound...: `T: 'static` -LL | // oh dear! LL | Box::new(B(&*v)) as Box | ^^^^^^ ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | fn f<'a, T: 'static, U>(v: Box + 'static>) -> Box { + | +++++++++ error: aborting due to 5 previous errors diff --git a/src/test/ui/regions/regions-close-over-type-parameter-1.base.stderr b/src/test/ui/regions/regions-close-over-type-parameter-1.base.stderr index 41dc03e86dd85..d8f77ad85c966 100644 --- a/src/test/ui/regions/regions-close-over-type-parameter-1.base.stderr +++ b/src/test/ui/regions/regions-close-over-type-parameter-1.base.stderr @@ -1,18 +1,24 @@ error[E0310]: the parameter type `A` may not live long enough --> $DIR/regions-close-over-type-parameter-1.rs:15:5 | -LL | fn make_object1(v: A) -> Box { - | -- help: consider adding an explicit lifetime bound...: `A: 'static +` LL | Box::new(v) as Box | ^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | fn make_object1(v: A) -> Box { + | +++++++++ error[E0309]: the parameter type `A` may not live long enough --> $DIR/regions-close-over-type-parameter-1.rs:24:5 | -LL | fn make_object3<'a, 'b, A: SomeTrait + 'a>(v: A) -> Box { - | -- help: consider adding an explicit lifetime bound...: `A: 'b +` LL | Box::new(v) as Box | ^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | fn make_object3<'a, 'b, A: SomeTrait + 'a + 'b>(v: A) -> Box { + | ++++ error: aborting due to 2 previous errors diff --git a/src/test/ui/regions/regions-close-over-type-parameter-1.nll.stderr b/src/test/ui/regions/regions-close-over-type-parameter-1.nll.stderr index 41dc03e86dd85..d8f77ad85c966 100644 --- a/src/test/ui/regions/regions-close-over-type-parameter-1.nll.stderr +++ b/src/test/ui/regions/regions-close-over-type-parameter-1.nll.stderr @@ -1,18 +1,24 @@ error[E0310]: the parameter type `A` may not live long enough --> $DIR/regions-close-over-type-parameter-1.rs:15:5 | -LL | fn make_object1(v: A) -> Box { - | -- help: consider adding an explicit lifetime bound...: `A: 'static +` LL | Box::new(v) as Box | ^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | fn make_object1(v: A) -> Box { + | +++++++++ error[E0309]: the parameter type `A` may not live long enough --> $DIR/regions-close-over-type-parameter-1.rs:24:5 | -LL | fn make_object3<'a, 'b, A: SomeTrait + 'a>(v: A) -> Box { - | -- help: consider adding an explicit lifetime bound...: `A: 'b +` LL | Box::new(v) as Box | ^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | fn make_object3<'a, 'b, A: SomeTrait + 'a + 'b>(v: A) -> Box { + | ++++ error: aborting due to 2 previous errors diff --git a/src/test/ui/regions/regions-close-param-into-object.base.stderr b/src/test/ui/regions/regions-close-param-into-object.base.stderr index 7e135c654505b..79a5d34dea89d 100644 --- a/src/test/ui/regions/regions-close-param-into-object.base.stderr +++ b/src/test/ui/regions/regions-close-param-into-object.base.stderr @@ -1,38 +1,46 @@ error[E0310]: the parameter type `T` may not live long enough --> $DIR/regions-close-param-into-object.rs:10:5 | -LL | fn p1(v: T) -> Box - | - help: consider adding an explicit lifetime bound...: `T: 'static` -... LL | Box::new(v) | ^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | where T : X + 'static + | +++++++++ error[E0310]: the parameter type `T` may not live long enough --> $DIR/regions-close-param-into-object.rs:16:5 | -LL | fn p2(v: Box) -> Box - | - help: consider adding an explicit lifetime bound...: `T: 'static` -... LL | Box::new(v) | ^^^^^^^^^^^ ...so that the type `Box` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | fn p2(v: Box) -> Box + | +++++++++ error[E0309]: the parameter type `T` may not live long enough --> $DIR/regions-close-param-into-object.rs:22:5 | -LL | fn p3<'a,T>(v: T) -> Box - | - help: consider adding an explicit lifetime bound...: `T: 'a` -... LL | Box::new(v) | ^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | where T : X + 'a + | ++++ error[E0309]: the parameter type `T` may not live long enough --> $DIR/regions-close-param-into-object.rs:28:5 | -LL | fn p4<'a,T>(v: Box) -> Box - | - help: consider adding an explicit lifetime bound...: `T: 'a` -... LL | Box::new(v) | ^^^^^^^^^^^ ...so that the type `Box` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | fn p4<'a,T: 'a>(v: Box) -> Box + | ++++ error: aborting due to 4 previous errors diff --git a/src/test/ui/regions/regions-close-param-into-object.nll.stderr b/src/test/ui/regions/regions-close-param-into-object.nll.stderr index 3fbc102263115..6ee12d5b82c69 100644 --- a/src/test/ui/regions/regions-close-param-into-object.nll.stderr +++ b/src/test/ui/regions/regions-close-param-into-object.nll.stderr @@ -1,38 +1,46 @@ error[E0310]: the parameter type `T` may not live long enough --> $DIR/regions-close-param-into-object.rs:10:5 | -LL | fn p1(v: T) -> Box - | - help: consider adding an explicit lifetime bound...: `T: 'static` -... LL | Box::new(v) | ^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | where T : X + 'static + | +++++++++ error[E0310]: the parameter type `T` may not live long enough --> $DIR/regions-close-param-into-object.rs:16:5 | -LL | fn p2(v: Box) -> Box - | - help: consider adding an explicit lifetime bound...: `T: 'static` -... LL | Box::new(v) | ^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | fn p2(v: Box) -> Box + | +++++++++ error[E0309]: the parameter type `T` may not live long enough --> $DIR/regions-close-param-into-object.rs:22:5 | -LL | fn p3<'a,T>(v: T) -> Box - | - help: consider adding an explicit lifetime bound...: `T: 'a` -... LL | Box::new(v) | ^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | where T : X + 'a + | ++++ error[E0309]: the parameter type `T` may not live long enough --> $DIR/regions-close-param-into-object.rs:28:5 | -LL | fn p4<'a,T>(v: Box) -> Box - | - help: consider adding an explicit lifetime bound...: `T: 'a` -... LL | Box::new(v) | ^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | fn p4<'a,T: 'a>(v: Box) -> Box + | ++++ error: aborting due to 4 previous errors diff --git a/src/test/ui/regions/regions-free-region-outlives-static-outlives-free-region.rs b/src/test/ui/regions/regions-free-region-outlives-static-outlives-free-region.rs index f464cab75541d..7c2e1aeeea619 100644 --- a/src/test/ui/regions/regions-free-region-outlives-static-outlives-free-region.rs +++ b/src/test/ui/regions/regions-free-region-outlives-static-outlives-free-region.rs @@ -9,7 +9,7 @@ // 'a : 'b fn test<'a,'b>(x: &'a i32) -> &'b i32 - where 'a: 'static + where 'a: 'static //~ WARN unnecessary lifetime parameter `'a` { x } diff --git a/src/test/ui/regions/regions-free-region-outlives-static-outlives-free-region.stderr b/src/test/ui/regions/regions-free-region-outlives-static-outlives-free-region.stderr new file mode 100644 index 0000000000000..70ed418d5cbbb --- /dev/null +++ b/src/test/ui/regions/regions-free-region-outlives-static-outlives-free-region.stderr @@ -0,0 +1,10 @@ +warning: unnecessary lifetime parameter `'a` + --> $DIR/regions-free-region-outlives-static-outlives-free-region.rs:12:11 + | +LL | where 'a: 'static + | ^^ + | + = help: you can use the `'static` lifetime directly, in place of `'a` + +warning: 1 warning emitted + diff --git a/src/test/ui/regions/regions-implied-bounds-projection-gap-1.base.stderr b/src/test/ui/regions/regions-implied-bounds-projection-gap-1.base.stderr index ef68674a18f5e..85ced4b524111 100644 --- a/src/test/ui/regions/regions-implied-bounds-projection-gap-1.base.stderr +++ b/src/test/ui/regions/regions-implied-bounds-projection-gap-1.base.stderr @@ -1,11 +1,13 @@ error[E0309]: the parameter type `T` may not live long enough --> $DIR/regions-implied-bounds-projection-gap-1.rs:20:10 | -LL | fn func<'x, T:Trait1<'x>>(t: &'x T::Foo) - | -- help: consider adding an explicit lifetime bound...: `T: 'x +` -LL | { LL | wf::<&'x T>(); | ^^^^^ ...so that the reference type `&'x T` does not outlive the data it points at + | +help: consider adding an explicit lifetime bound... + | +LL | fn func<'x, T:Trait1<'x> + 'x>(t: &'x T::Foo) + | ++++ error: aborting due to previous error diff --git a/src/test/ui/regions/regions-implied-bounds-projection-gap-1.nll.stderr b/src/test/ui/regions/regions-implied-bounds-projection-gap-1.nll.stderr index 6d63de6d6bd95..1a428eb25d7d0 100644 --- a/src/test/ui/regions/regions-implied-bounds-projection-gap-1.nll.stderr +++ b/src/test/ui/regions/regions-implied-bounds-projection-gap-1.nll.stderr @@ -1,11 +1,13 @@ error[E0309]: the parameter type `T` may not live long enough --> $DIR/regions-implied-bounds-projection-gap-1.rs:20:5 | -LL | fn func<'x, T:Trait1<'x>>(t: &'x T::Foo) - | -- help: consider adding an explicit lifetime bound...: `T: 'x +` -LL | { LL | wf::<&'x T>(); | ^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | fn func<'x, T:Trait1<'x> + 'x>(t: &'x T::Foo) + | ++++ error: aborting due to previous error diff --git a/src/test/ui/regions/regions-infer-bound-from-trait.base.stderr b/src/test/ui/regions/regions-infer-bound-from-trait.base.stderr index 6a7e8ba134753..658740f3f871c 100644 --- a/src/test/ui/regions/regions-infer-bound-from-trait.base.stderr +++ b/src/test/ui/regions/regions-infer-bound-from-trait.base.stderr @@ -1,8 +1,6 @@ error[E0309]: the parameter type `A` may not live long enough --> $DIR/regions-infer-bound-from-trait.rs:37:5 | -LL | fn bar1<'a,A>(x: Inv<'a>, a: A) { - | - help: consider adding an explicit lifetime bound...: `A: 'a` LL | check_bound(x, a) | ^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds... | @@ -11,12 +9,14 @@ note: ...that is required by this bound | LL | fn check_bound<'a,A:'a>(x: Inv<'a>, a: A) { } | ^^ +help: consider adding an explicit lifetime bound... + | +LL | fn bar1<'a,A: 'a>(x: Inv<'a>, a: A) { + | ++++ error[E0309]: the parameter type `A` may not live long enough --> $DIR/regions-infer-bound-from-trait.rs:41:5 | -LL | fn bar2<'a,'b,A:Is<'b>>(x: Inv<'a>, y: Inv<'b>, a: A) { - | -- help: consider adding an explicit lifetime bound...: `A: 'a +` LL | check_bound(x, a) | ^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds... | @@ -25,6 +25,10 @@ note: ...that is required by this bound | LL | fn check_bound<'a,A:'a>(x: Inv<'a>, a: A) { } | ^^ +help: consider adding an explicit lifetime bound... + | +LL | fn bar2<'a,'b,A:Is<'b> + 'a>(x: Inv<'a>, y: Inv<'b>, a: A) { + | ++++ error: aborting due to 2 previous errors diff --git a/src/test/ui/regions/regions-infer-bound-from-trait.nll.stderr b/src/test/ui/regions/regions-infer-bound-from-trait.nll.stderr index 4aa4b468eaa72..5cc2d20c2e0d1 100644 --- a/src/test/ui/regions/regions-infer-bound-from-trait.nll.stderr +++ b/src/test/ui/regions/regions-infer-bound-from-trait.nll.stderr @@ -1,18 +1,24 @@ error[E0309]: the parameter type `A` may not live long enough --> $DIR/regions-infer-bound-from-trait.rs:37:5 | -LL | fn bar1<'a,A>(x: Inv<'a>, a: A) { - | - help: consider adding an explicit lifetime bound...: `A: 'a` LL | check_bound(x, a) | ^^^^^^^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | fn bar1<'a,A: 'a>(x: Inv<'a>, a: A) { + | ++++ error[E0309]: the parameter type `A` may not live long enough --> $DIR/regions-infer-bound-from-trait.rs:41:5 | -LL | fn bar2<'a,'b,A:Is<'b>>(x: Inv<'a>, y: Inv<'b>, a: A) { - | -- help: consider adding an explicit lifetime bound...: `A: 'a +` LL | check_bound(x, a) | ^^^^^^^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | fn bar2<'a,'b,A:Is<'b> + 'a>(x: Inv<'a>, y: Inv<'b>, a: A) { + | ++++ error: aborting due to 2 previous errors diff --git a/src/test/ui/regions/regions-static-bound-rpass.rs b/src/test/ui/regions/regions-static-bound-rpass.rs index c91c6f874931b..25232b455b687 100644 --- a/src/test/ui/regions/regions-static-bound-rpass.rs +++ b/src/test/ui/regions/regions-static-bound-rpass.rs @@ -1,10 +1,17 @@ // run-pass + fn invariant_id<'a,'b>(t: &'b mut &'static ()) -> &'b mut &'a () where 'a: 'static { t } +//~^ WARN unnecessary lifetime parameter `'a` + fn static_id<'a>(t: &'a ()) -> &'static () where 'a: 'static { t } +//~^ WARN unnecessary lifetime parameter `'a` + fn static_id_indirect<'a,'b>(t: &'a ()) -> &'static () where 'a: 'b, 'b: 'static { t } +//~^ WARN unnecessary lifetime parameter `'b` + fn ref_id<'a>(t: &'a ()) -> &'a () where 'static: 'a { t } static UNIT: () = (); diff --git a/src/test/ui/regions/regions-static-bound-rpass.stderr b/src/test/ui/regions/regions-static-bound-rpass.stderr new file mode 100644 index 0000000000000..9355a409d5099 --- /dev/null +++ b/src/test/ui/regions/regions-static-bound-rpass.stderr @@ -0,0 +1,26 @@ +warning: unnecessary lifetime parameter `'a` + --> $DIR/regions-static-bound-rpass.rs:4:11 + | +LL | where 'a: 'static { t } + | ^^ + | + = help: you can use the `'static` lifetime directly, in place of `'a` + +warning: unnecessary lifetime parameter `'a` + --> $DIR/regions-static-bound-rpass.rs:8:11 + | +LL | where 'a: 'static { t } + | ^^ + | + = help: you can use the `'static` lifetime directly, in place of `'a` + +warning: unnecessary lifetime parameter `'b` + --> $DIR/regions-static-bound-rpass.rs:12:19 + | +LL | where 'a: 'b, 'b: 'static { t } + | ^^ + | + = help: you can use the `'static` lifetime directly, in place of `'b` + +warning: 3 warnings emitted + diff --git a/src/test/ui/regions/regions-static-bound.base.stderr b/src/test/ui/regions/regions-static-bound.base.stderr index b37ce1e76bdfd..6b8120444d067 100644 --- a/src/test/ui/regions/regions-static-bound.base.stderr +++ b/src/test/ui/regions/regions-static-bound.base.stderr @@ -1,18 +1,34 @@ +warning: unnecessary lifetime parameter `'a` + --> $DIR/regions-static-bound.rs:6:11 + | +LL | where 'a: 'static { t } + | ^^ + | + = help: you can use the `'static` lifetime directly, in place of `'a` + +warning: unnecessary lifetime parameter `'b` + --> $DIR/regions-static-bound.rs:10:19 + | +LL | where 'a: 'b, 'b: 'static { t } + | ^^ + | + = help: you can use the `'static` lifetime directly, in place of `'b` + error[E0312]: lifetime of reference outlives lifetime of borrowed content... - --> $DIR/regions-static-bound.rs:10:5 + --> $DIR/regions-static-bound.rs:14:5 | LL | t | ^ | = note: ...the reference is valid for the static lifetime... note: ...but the borrowed content is only valid for the lifetime `'a` as defined here - --> $DIR/regions-static-bound.rs:9:24 + --> $DIR/regions-static-bound.rs:13:24 | LL | fn static_id_wrong_way<'a>(t: &'a ()) -> &'static () where 'static: 'a { | ^^ error[E0759]: `u` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement - --> $DIR/regions-static-bound.rs:16:5 + --> $DIR/regions-static-bound.rs:20:5 | LL | fn error(u: &(), v: &()) { | --- this data with an anonymous lifetime `'_`... @@ -20,13 +36,13 @@ LL | static_id(&u); | ^^^^^^^^^ -- ...is used here... | note: ...and is required to live as long as `'static` here - --> $DIR/regions-static-bound.rs:16:5 + --> $DIR/regions-static-bound.rs:20:5 | LL | static_id(&u); | ^^^^^^^^^ error[E0759]: `v` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement - --> $DIR/regions-static-bound.rs:19:5 + --> $DIR/regions-static-bound.rs:23:5 | LL | fn error(u: &(), v: &()) { | --- this data with an anonymous lifetime `'_`... @@ -35,12 +51,12 @@ LL | static_id_indirect(&v); | ^^^^^^^^^^^^^^^^^^ -- ...is used here... | note: ...and is required to live as long as `'static` here - --> $DIR/regions-static-bound.rs:19:5 + --> $DIR/regions-static-bound.rs:23:5 | LL | static_id_indirect(&v); | ^^^^^^^^^^^^^^^^^^ -error: aborting due to 3 previous errors +error: aborting due to 3 previous errors; 2 warnings emitted Some errors have detailed explanations: E0312, E0759. For more information about an error, try `rustc --explain E0312`. diff --git a/src/test/ui/regions/regions-static-bound.nll.stderr b/src/test/ui/regions/regions-static-bound.nll.stderr index d228c42f99579..68e36f3aeea8f 100644 --- a/src/test/ui/regions/regions-static-bound.nll.stderr +++ b/src/test/ui/regions/regions-static-bound.nll.stderr @@ -1,5 +1,21 @@ +warning: unnecessary lifetime parameter `'a` + --> $DIR/regions-static-bound.rs:6:11 + | +LL | where 'a: 'static { t } + | ^^ + | + = help: you can use the `'static` lifetime directly, in place of `'a` + +warning: unnecessary lifetime parameter `'b` + --> $DIR/regions-static-bound.rs:10:19 + | +LL | where 'a: 'b, 'b: 'static { t } + | ^^ + | + = help: you can use the `'static` lifetime directly, in place of `'b` + error: lifetime may not live long enough - --> $DIR/regions-static-bound.rs:10:5 + --> $DIR/regions-static-bound.rs:14:5 | LL | fn static_id_wrong_way<'a>(t: &'a ()) -> &'static () where 'static: 'a { | -- lifetime `'a` defined here @@ -7,7 +23,7 @@ LL | t | ^ returning this value requires that `'a` must outlive `'static` error[E0521]: borrowed data escapes outside of function - --> $DIR/regions-static-bound.rs:16:5 + --> $DIR/regions-static-bound.rs:20:5 | LL | fn error(u: &(), v: &()) { | - - let's call the lifetime of this reference `'1` @@ -20,7 +36,7 @@ LL | static_id(&u); | argument requires that `'1` must outlive `'static` error[E0521]: borrowed data escapes outside of function - --> $DIR/regions-static-bound.rs:19:5 + --> $DIR/regions-static-bound.rs:23:5 | LL | fn error(u: &(), v: &()) { | - - let's call the lifetime of this reference `'2` @@ -33,6 +49,6 @@ LL | static_id_indirect(&v); | `v` escapes the function body here | argument requires that `'2` must outlive `'static` -error: aborting due to 3 previous errors +error: aborting due to 3 previous errors; 2 warnings emitted For more information about this error, try `rustc --explain E0521`. diff --git a/src/test/ui/regions/regions-static-bound.rs b/src/test/ui/regions/regions-static-bound.rs index 058b717c95daa..1eed7e71745d8 100644 --- a/src/test/ui/regions/regions-static-bound.rs +++ b/src/test/ui/regions/regions-static-bound.rs @@ -4,8 +4,12 @@ fn static_id<'a,'b>(t: &'a ()) -> &'static () where 'a: 'static { t } +//~^ WARN unnecessary lifetime parameter `'a` + fn static_id_indirect<'a,'b>(t: &'a ()) -> &'static () where 'a: 'b, 'b: 'static { t } +//~^ WARN unnecessary lifetime parameter `'b` + fn static_id_wrong_way<'a>(t: &'a ()) -> &'static () where 'static: 'a { t //[base]~^ ERROR E0312 diff --git a/src/test/ui/rfc-2093-infer-outlives/dont-infer-static.stderr b/src/test/ui/rfc-2093-infer-outlives/dont-infer-static.stderr index 1f387a042e666..950ffd6c89bd3 100644 --- a/src/test/ui/rfc-2093-infer-outlives/dont-infer-static.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/dont-infer-static.stderr @@ -1,8 +1,6 @@ error[E0310]: the parameter type `U` may not live long enough --> $DIR/dont-infer-static.rs:8:10 | -LL | struct Foo { - | - help: consider adding an explicit lifetime bound...: `U: 'static` LL | bar: Bar | ^^^^^^ ...so that the type `U` will meet its required lifetime bounds... | @@ -11,6 +9,10 @@ note: ...that is required by this bound | LL | struct Bar { | ^^^^^^^ +help: consider adding an explicit lifetime bound... + | +LL | struct Foo { + | +++++++++ error: aborting due to previous error diff --git a/src/test/ui/rfc-2093-infer-outlives/regions-enum-not-wf.stderr b/src/test/ui/rfc-2093-infer-outlives/regions-enum-not-wf.stderr index 553a3e71c169a..2c660b2850097 100644 --- a/src/test/ui/rfc-2093-infer-outlives/regions-enum-not-wf.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/regions-enum-not-wf.stderr @@ -1,27 +1,35 @@ error[E0309]: the parameter type `T` may not live long enough --> $DIR/regions-enum-not-wf.rs:17:18 | -LL | enum Ref1<'a, T> { - | - help: consider adding an explicit lifetime bound...: `T: 'a` LL | Ref1Variant1(RequireOutlives<'a, T>), | ^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | enum Ref1<'a, T: 'a> { + | ++++ error[E0309]: the parameter type `T` may not live long enough --> $DIR/regions-enum-not-wf.rs:22:25 | -LL | enum Ref2<'a, T> { - | - help: consider adding an explicit lifetime bound...: `T: 'a` -LL | Ref2Variant1, LL | Ref2Variant2(isize, RequireOutlives<'a, T>), | ^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | enum Ref2<'a, T: 'a> { + | ++++ error[E0309]: the parameter type `T` may not live long enough --> $DIR/regions-enum-not-wf.rs:35:23 | -LL | enum RefDouble<'a, 'b, T> { - | - help: consider adding an explicit lifetime bound...: `T: 'b` LL | RefDoubleVariant1(&'a RequireOutlives<'b, T>), | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | enum RefDouble<'a, 'b, T: 'b> { + | ++++ error: aborting due to 3 previous errors diff --git a/src/test/ui/rfc-2093-infer-outlives/regions-struct-not-wf.stderr b/src/test/ui/rfc-2093-infer-outlives/regions-struct-not-wf.stderr index f886126299120..34ff1362cf323 100644 --- a/src/test/ui/rfc-2093-infer-outlives/regions-struct-not-wf.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/regions-struct-not-wf.stderr @@ -1,16 +1,17 @@ error[E0309]: the parameter type `T` may not live long enough --> $DIR/regions-struct-not-wf.rs:13:16 | -LL | impl<'a, T> Trait<'a, T> for usize { - | - help: consider adding an explicit lifetime bound...: `T: 'a` LL | type Out = &'a T; | ^^^^^ ...so that the reference type `&'a T` does not outlive the data it points at + | +help: consider adding an explicit lifetime bound... + | +LL | impl<'a, T: 'a> Trait<'a, T> for usize { + | ++++ error[E0309]: the parameter type `T` may not live long enough --> $DIR/regions-struct-not-wf.rs:21:16 | -LL | impl<'a, T> Trait<'a, T> for u32 { - | - help: consider adding an explicit lifetime bound...: `T: 'a` LL | type Out = RefOk<'a, T>; | ^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds... | @@ -19,6 +20,10 @@ note: ...that is required by this bound | LL | struct RefOk<'a, T:'a> { | ^^ +help: consider adding an explicit lifetime bound... + | +LL | impl<'a, T: 'a> Trait<'a, T> for u32 { + | ++++ error[E0491]: in type `&'a &'b T`, reference has a longer lifetime than the data it references --> $DIR/regions-struct-not-wf.rs:25:16 diff --git a/src/test/ui/static/static-lifetime-bound.stderr b/src/test/ui/static/static-lifetime-bound.stderr index 79d9506619e17..ef07a89315f40 100644 --- a/src/test/ui/static/static-lifetime-bound.stderr +++ b/src/test/ui/static/static-lifetime-bound.stderr @@ -2,7 +2,7 @@ warning: unnecessary lifetime parameter `'a` --> $DIR/static-lifetime-bound.rs:1:6 | LL | fn f<'a: 'static>(_: &'a i32) {} - | ^^^^^^^^^^^ + | ^^ | = help: you can use the `'static` lifetime directly, in place of `'a` diff --git a/src/test/ui/suggestions/bound-suggestions.fixed b/src/test/ui/suggestions/bound-suggestions.fixed index 31fdd2b67e294..17a019c69849f 100644 --- a/src/test/ui/suggestions/bound-suggestions.fixed +++ b/src/test/ui/suggestions/bound-suggestions.fixed @@ -35,7 +35,7 @@ fn test_one_bound_where(x: X) where X: Sized + std::fmt::Debug { } #[allow(dead_code)] -fn test_many_bounds_where(x: X) where X: Sized, X: Sized, X: std::fmt::Debug { +fn test_many_bounds_where(x: X) where X: Sized + std::fmt::Debug, X: Sized { println!("{:?}", x); //~^ ERROR doesn't implement } diff --git a/src/test/ui/suggestions/bound-suggestions.stderr b/src/test/ui/suggestions/bound-suggestions.stderr index 04f233a1e87af..e5e19444d2435 100644 --- a/src/test/ui/suggestions/bound-suggestions.stderr +++ b/src/test/ui/suggestions/bound-suggestions.stderr @@ -65,10 +65,10 @@ LL | println!("{:?}", x); | ^ `X` cannot be formatted using `{:?}` because it doesn't implement `Debug` | = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info) -help: consider further restricting type parameter `X` +help: consider further restricting this bound | -LL | fn test_many_bounds_where(x: X) where X: Sized, X: Sized, X: std::fmt::Debug { - | ++++++++++++++++++++ +LL | fn test_many_bounds_where(x: X) where X: Sized + std::fmt::Debug, X: Sized { + | +++++++++++++++++ error[E0277]: the size for values of type `Self` cannot be known at compilation time --> $DIR/bound-suggestions.rs:44:46 diff --git a/src/test/ui/suggestions/impl-trait-with-missing-trait-bounds-in-arg.stderr b/src/test/ui/suggestions/impl-trait-with-missing-trait-bounds-in-arg.stderr index 6255df06efb6a..8ec7b7bf49658 100644 --- a/src/test/ui/suggestions/impl-trait-with-missing-trait-bounds-in-arg.stderr +++ b/src/test/ui/suggestions/impl-trait-with-missing-trait-bounds-in-arg.stderr @@ -8,7 +8,7 @@ LL | foo.hello(); help: the following trait defines an item `hello`, perhaps you need to restrict type parameter `impl Foo` with it: | LL | fn test(foo: impl Foo + Bar) { - | ~~~~~~~~~~~~~~ + | +++++ error: aborting due to previous error diff --git a/src/test/ui/suggestions/issue-21673.stderr b/src/test/ui/suggestions/issue-21673.stderr index eda29f876d8fc..0a4aaa61bc784 100644 --- a/src/test/ui/suggestions/issue-21673.stderr +++ b/src/test/ui/suggestions/issue-21673.stderr @@ -7,8 +7,8 @@ LL | x.method() = help: items from traits can only be used if the type parameter is bounded by the trait help: the following trait defines an item `method`, perhaps you need to restrict type parameter `T` with it: | -LL | fn call_method(x: &T) { - | ~~~~~~~~ +LL | fn call_method(x: &T) { + | +++++ error[E0599]: no method named `method` found for type parameter `T` in the current scope --> $DIR/issue-21673.rs:10:7 @@ -20,7 +20,7 @@ LL | x.method() help: the following trait defines an item `method`, perhaps you need to restrict type parameter `T` with it: | LL | fn call_method_2(x: T) { - | ~~~~~~ + | +++++ error: aborting due to 2 previous errors diff --git a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.nll.stderr b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.nll.stderr index d38d66c08853c..0212c2d712cb3 100644 --- a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.nll.stderr +++ b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.nll.stderr @@ -1,8 +1,6 @@ error[E0311]: the parameter type `T` may not live long enough --> $DIR/missing-lifetimes-in-signature-2.rs:20:5 | -LL | fn func(foo: &Foo, t: T) { - | -- help: consider adding an explicit lifetime bound...: `T: 'a +` LL | / foo.bar(move |_| { LL | | LL | | t.test(); @@ -22,6 +20,10 @@ LL | | LL | | t.test(); LL | | }); | |______^ +help: consider adding an explicit lifetime bound... + | +LL | fn func(foo: &Foo, t: T) { + | ++++ error: aborting due to previous error diff --git a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.stderr b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.stderr index adb928aa8a376..5d195e5ff32f7 100644 --- a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.stderr +++ b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature-2.stderr @@ -1,8 +1,6 @@ error[E0311]: the parameter type `T` may not live long enough --> $DIR/missing-lifetimes-in-signature-2.rs:20:9 | -LL | fn func(foo: &Foo, t: T) { - | -- help: consider adding an explicit lifetime bound...: `T: 'a +` LL | foo.bar(move |_| { | ^^^ | @@ -21,6 +19,10 @@ note: ...that is required by this bound | LL | F: 'a, | ^^ +help: consider adding an explicit lifetime bound... + | +LL | fn func(foo: &Foo, t: T) { + | ++++ error: aborting due to previous error diff --git a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.nll.stderr b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.nll.stderr index e47f7dc3566a9..24eac64d334da 100644 --- a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.nll.stderr +++ b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.nll.stderr @@ -26,9 +26,6 @@ LL | fn foo(g: G, dest: &mut T) -> impl FnOnce() + '_ error[E0311]: the parameter type `G` may not live long enough --> $DIR/missing-lifetimes-in-signature.rs:31:5 | -LL | fn bar(g: G, dest: &mut T) -> impl FnOnce() + '_ - | - help: consider adding an explicit lifetime bound...: `G: 'a` -... LL | / move || { LL | | *dest = g.get(); LL | | } @@ -46,13 +43,14 @@ LL | / move || { LL | | *dest = g.get(); LL | | } | |_____^ +help: consider adding an explicit lifetime bound... + | +LL | G: Get + 'a, + | ++++ error[E0311]: the parameter type `G` may not live long enough --> $DIR/missing-lifetimes-in-signature.rs:53:5 | -LL | fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ - | -- help: consider adding an explicit lifetime bound...: `G: 'b +` -... LL | / move || { LL | | *dest = g.get(); LL | | } @@ -70,13 +68,14 @@ LL | / move || { LL | | *dest = g.get(); LL | | } | |_____^ +help: consider adding an explicit lifetime bound... + | +LL | fn qux<'a, G: 'a + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + | ++++ error[E0311]: the parameter type `G` may not live long enough --> $DIR/missing-lifetimes-in-signature.rs:62:9 | -LL | fn qux<'b, G: Get + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ { - | -- help: consider adding an explicit lifetime bound...: `G: 'c +` -LL | LL | / move || { LL | | *dest = g.get(); LL | | } @@ -94,13 +93,14 @@ LL | / move || { LL | | *dest = g.get(); LL | | } | |_________^ +help: consider adding an explicit lifetime bound... + | +LL | fn qux<'b, G: Get + 'b + 'c, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ { + | ++++ error[E0311]: the parameter type `G` may not live long enough --> $DIR/missing-lifetimes-in-signature.rs:74:5 | -LL | fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a - | -- help: consider adding an explicit lifetime bound...: `G: 'b +` -... LL | / move || { LL | | *dest = g.get(); LL | | } @@ -118,6 +118,10 @@ LL | / move || { LL | | *dest = g.get(); LL | | } | |_____^ +help: consider adding an explicit lifetime bound... + | +LL | fn bat<'a, G: 'a + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a + | ++++ error[E0621]: explicit lifetime required in the type of `dest` --> $DIR/missing-lifetimes-in-signature.rs:74:5 @@ -133,13 +137,15 @@ LL | | } error[E0309]: the parameter type `G` may not live long enough --> $DIR/missing-lifetimes-in-signature.rs:85:5 | -LL | fn bak<'a, G, T>(g: G, dest: &'a mut T) -> impl FnOnce() + 'a - | - help: consider adding an explicit lifetime bound...: `G: 'a` -... LL | / move || { LL | | *dest = g.get(); LL | | } | |_____^ ...so that the type `G` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | G: Get + 'a, + | ++++ error: aborting due to 8 previous errors diff --git a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr index 7526aadb38cbc..ae9a020a099f4 100644 --- a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr +++ b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr @@ -41,8 +41,11 @@ LL | fn bar(g: G, dest: &mut T) -> impl FnOnce() + '_ | ^^^^^^^^^^^^^^^^^^ help: consider introducing an explicit lifetime bound | -LL | fn bar<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a - | ~~~~~ ++++ +LL ~ fn bar<'a, G, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a +LL | +LL | where +LL ~ G: Get + 'a, + | error[E0311]: the parameter type `G` may not live long enough --> $DIR/missing-lifetimes-in-signature.rs:48:45 @@ -62,8 +65,8 @@ LL | fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ | ^^^^^^^^^^^^^^^^^^ help: consider introducing an explicit lifetime bound | -LL | fn qux<'b, 'a, G: 'b + 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'b - | +++ ~~~~~~~ ++++ +LL | fn qux<'b, 'a, G: 'a + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'b + | +++ ++++ ++++ error[E0311]: the parameter type `G` may not live long enough --> $DIR/missing-lifetimes-in-signature.rs:60:58 @@ -83,8 +86,8 @@ LL | fn qux<'b, G: Get + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ | ^^^^^^^^^^^^^^^^^^ help: consider introducing an explicit lifetime bound | -LL | fn qux<'c, 'b, G: 'c + Get + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'c { - | +++ ~~~~~~~ ++++ +LL | fn qux<'c, 'b, G: Get + 'b + 'c, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'c { + | +++ ++++ ++++ error[E0621]: explicit lifetime required in the type of `dest` --> $DIR/missing-lifetimes-in-signature.rs:69:45 @@ -98,9 +101,12 @@ error[E0309]: the parameter type `G` may not live long enough --> $DIR/missing-lifetimes-in-signature.rs:80:44 | LL | fn bak<'a, G, T>(g: G, dest: &'a mut T) -> impl FnOnce() + 'a - | - ^^^^^^^^^^^^^^^^^^ ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:85:5: 87:6]` will meet its required lifetime bounds - | | - | help: consider adding an explicit lifetime bound...: `G: 'a` + | ^^^^^^^^^^^^^^^^^^ ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:85:5: 87:6]` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | G: Get + 'a, + | ++++ error: aborting due to 7 previous errors diff --git a/src/test/ui/suggestions/restrict-type-argument.stderr b/src/test/ui/suggestions/restrict-type-argument.stderr index 551a7c5060fc7..01c2de7986419 100644 --- a/src/test/ui/suggestions/restrict-type-argument.stderr +++ b/src/test/ui/suggestions/restrict-type-argument.stderr @@ -85,8 +85,8 @@ LL | fn is_send(val: T) {} | ^^^^ required by this bound in `is_send` help: consider further restricting this bound | -LL | fn use_bound_and_where(val: S) where S: std::fmt::Debug + std::marker::Send { - | +++++++++++++++++++ +LL | fn use_bound_and_where(val: S) where S: std::fmt::Debug { + | +++++++++++++++++++ error[E0277]: `S` cannot be sent between threads safely --> $DIR/restrict-type-argument.rs:28:13 diff --git a/src/test/ui/suggestions/suggest-impl-trait-lifetime.nll.stderr b/src/test/ui/suggestions/suggest-impl-trait-lifetime.nll.stderr index 72354eaaee147..cf912f4aac201 100644 --- a/src/test/ui/suggestions/suggest-impl-trait-lifetime.nll.stderr +++ b/src/test/ui/suggestions/suggest-impl-trait-lifetime.nll.stderr @@ -1,11 +1,13 @@ error[E0310]: the parameter type `impl Debug` may not live long enough --> $DIR/suggest-impl-trait-lifetime.rs:7:5 | -LL | fn foo(d: impl Debug) { - | ---------- help: consider adding an explicit lifetime bound...: `impl Debug + 'static` -LL | LL | bar(d); | ^^^^^^ ...so that the type `impl Debug` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | fn foo(d: impl Debug + 'static) { + | +++++++++ error: aborting due to previous error diff --git a/src/test/ui/suggestions/suggest-impl-trait-lifetime.stderr b/src/test/ui/suggestions/suggest-impl-trait-lifetime.stderr index e4a247993c29b..4a99c3a14d7bb 100644 --- a/src/test/ui/suggestions/suggest-impl-trait-lifetime.stderr +++ b/src/test/ui/suggestions/suggest-impl-trait-lifetime.stderr @@ -1,9 +1,6 @@ error[E0310]: the parameter type `impl Debug` may not live long enough --> $DIR/suggest-impl-trait-lifetime.rs:7:5 | -LL | fn foo(d: impl Debug) { - | ---------- help: consider adding an explicit lifetime bound...: `impl Debug + 'static` -LL | LL | bar(d); | ^^^ ...so that the type `impl Debug` will meet its required lifetime bounds... | @@ -12,6 +9,10 @@ note: ...that is required by this bound | LL | fn bar(d: impl Debug + 'static) { | ^^^^^^^ +help: consider adding an explicit lifetime bound... + | +LL | fn foo(d: impl Debug + 'static) { + | +++++++++ error: aborting due to previous error diff --git a/src/test/ui/traits/issue-65284-suggest-generic-trait-bound.stderr b/src/test/ui/traits/issue-65284-suggest-generic-trait-bound.stderr index cb1128fe5c669..35d41c6266761 100644 --- a/src/test/ui/traits/issue-65284-suggest-generic-trait-bound.stderr +++ b/src/test/ui/traits/issue-65284-suggest-generic-trait-bound.stderr @@ -7,8 +7,8 @@ LL | t.foo() = help: items from traits can only be used if the type parameter is bounded by the trait help: the following trait defines an item `foo`, perhaps you need to restrict type parameter `T` with it: | -LL | fn do_stuff(t : T) { - | ~~~~~~~~ +LL | fn do_stuff(t : T) { + | +++++ error: aborting due to previous error diff --git a/src/test/ui/traits/issue-95898.stderr b/src/test/ui/traits/issue-95898.stderr index d7d4790539604..0a58ad4b663eb 100644 --- a/src/test/ui/traits/issue-95898.stderr +++ b/src/test/ui/traits/issue-95898.stderr @@ -8,7 +8,7 @@ LL | t.clone(); help: the following trait defines an item `clone`, perhaps you need to restrict type parameter `T` with it: | LL | fn foo(t: T) { - | ~~~~~~~~ + | +++++ error: aborting due to previous error diff --git a/src/test/ui/type-alias-impl-trait/bounds-are-checked.stderr b/src/test/ui/type-alias-impl-trait/bounds-are-checked.stderr index d87ef2ec79c1a..920eef11da4b9 100644 --- a/src/test/ui/type-alias-impl-trait/bounds-are-checked.stderr +++ b/src/test/ui/type-alias-impl-trait/bounds-are-checked.stderr @@ -2,7 +2,7 @@ warning: unnecessary lifetime parameter `'a` --> $DIR/bounds-are-checked.rs:8:6 | LL | fn f<'a: 'static>(t: &'a str) -> X<'a> { - | ^^^^^^^^^^^ + | ^^ | = help: you can use the `'static` lifetime directly, in place of `'a` diff --git a/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.base.stderr b/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.base.stderr index a3b410c2cfb8c..593fb8af32f30 100644 --- a/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.base.stderr +++ b/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.base.stderr @@ -19,10 +19,13 @@ LL | type WrongGeneric = impl 'static; error[E0310]: the parameter type `T` may not live long enough --> $DIR/generic_type_does_not_live_long_enough.rs:18:5 | -LL | fn wrong_generic(t: T) -> WrongGeneric { - | - help: consider adding an explicit lifetime bound...: `T: 'static` LL | t | ^ ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | fn wrong_generic(t: T) -> WrongGeneric { + | +++++++++ error: aborting due to 3 previous errors diff --git a/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.nll.stderr b/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.nll.stderr index a3b410c2cfb8c..593fb8af32f30 100644 --- a/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.nll.stderr +++ b/src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.nll.stderr @@ -19,10 +19,13 @@ LL | type WrongGeneric = impl 'static; error[E0310]: the parameter type `T` may not live long enough --> $DIR/generic_type_does_not_live_long_enough.rs:18:5 | -LL | fn wrong_generic(t: T) -> WrongGeneric { - | - help: consider adding an explicit lifetime bound...: `T: 'static` LL | t | ^ ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | fn wrong_generic(t: T) -> WrongGeneric { + | +++++++++ error: aborting due to 3 previous errors diff --git a/src/test/ui/wf/wf-impl-associated-type-region.stderr b/src/test/ui/wf/wf-impl-associated-type-region.stderr index 3f324190b7b6b..b9d4857a3efde 100644 --- a/src/test/ui/wf/wf-impl-associated-type-region.stderr +++ b/src/test/ui/wf/wf-impl-associated-type-region.stderr @@ -1,10 +1,13 @@ error[E0309]: the parameter type `T` may not live long enough --> $DIR/wf-impl-associated-type-region.rs:10:16 | -LL | impl<'a, T> Foo<'a> for T { - | - help: consider adding an explicit lifetime bound...: `T: 'a` LL | type Bar = &'a T; | ^^^^^ ...so that the reference type `&'a T` does not outlive the data it points at + | +help: consider adding an explicit lifetime bound... + | +LL | impl<'a, T: 'a> Foo<'a> for T { + | ++++ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-in-fn-type-static.stderr b/src/test/ui/wf/wf-in-fn-type-static.stderr index 44cacf4ef4dfe..73fbb9ca670b0 100644 --- a/src/test/ui/wf/wf-in-fn-type-static.stderr +++ b/src/test/ui/wf/wf-in-fn-type-static.stderr @@ -1,20 +1,24 @@ error[E0310]: the parameter type `T` may not live long enough --> $DIR/wf-in-fn-type-static.rs:13:8 | -LL | struct Foo { - | - help: consider adding an explicit lifetime bound...: `T: 'static` -LL | // needs T: 'static LL | x: fn() -> &'static T | ^^^^^^^^^^^^^^^^^^ ...so that the reference type `&'static T` does not outlive the data it points at + | +help: consider adding an explicit lifetime bound... + | +LL | struct Foo { + | +++++++++ error[E0310]: the parameter type `T` may not live long enough --> $DIR/wf-in-fn-type-static.rs:18:8 | -LL | struct Bar { - | - help: consider adding an explicit lifetime bound...: `T: 'static` -LL | // needs T: Copy LL | x: fn(&'static T) | ^^^^^^^^^^^^^^ ...so that the reference type `&'static T` does not outlive the data it points at + | +help: consider adding an explicit lifetime bound... + | +LL | struct Bar { + | +++++++++ error: aborting due to 2 previous errors diff --git a/src/test/ui/wf/wf-in-obj-type-static.stderr b/src/test/ui/wf/wf-in-obj-type-static.stderr index c50a6bb6e4d87..c3ad42dd5d5ac 100644 --- a/src/test/ui/wf/wf-in-obj-type-static.stderr +++ b/src/test/ui/wf/wf-in-obj-type-static.stderr @@ -1,11 +1,13 @@ error[E0310]: the parameter type `T` may not live long enough --> $DIR/wf-in-obj-type-static.rs:14:8 | -LL | struct Foo { - | - help: consider adding an explicit lifetime bound...: `T: 'static` -LL | // needs T: 'static LL | x: dyn Object<&'static T> | ^^^^^^^^^^^^^^^^^^^^^^ ...so that the reference type `&'static T` does not outlive the data it points at + | +help: consider adding an explicit lifetime bound... + | +LL | struct Foo { + | +++++++++ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-outlives-ty-in-fn-or-trait.stderr b/src/test/ui/wf/wf-outlives-ty-in-fn-or-trait.stderr index 68c1e9091d753..4d4d8b2ab4d46 100644 --- a/src/test/ui/wf/wf-outlives-ty-in-fn-or-trait.stderr +++ b/src/test/ui/wf/wf-outlives-ty-in-fn-or-trait.stderr @@ -1,18 +1,24 @@ error[E0309]: the parameter type `T` may not live long enough --> $DIR/wf-outlives-ty-in-fn-or-trait.rs:9:16 | -LL | impl<'a, T> Trait<'a, T> for usize { - | - help: consider adding an explicit lifetime bound...: `T: 'a` LL | type Out = &'a fn(T); | ^^^^^^^^^ ...so that the reference type `&'a fn(T)` does not outlive the data it points at + | +help: consider adding an explicit lifetime bound... + | +LL | impl<'a, T: 'a> Trait<'a, T> for usize { + | ++++ error[E0309]: the parameter type `T` may not live long enough --> $DIR/wf-outlives-ty-in-fn-or-trait.rs:19:16 | -LL | impl<'a, T> Trait<'a, T> for u32 { - | - help: consider adding an explicit lifetime bound...: `T: 'a` LL | type Out = &'a dyn Baz; | ^^^^^^^^^^^^^^ ...so that the reference type `&'a (dyn Baz + 'a)` does not outlive the data it points at + | +help: consider adding an explicit lifetime bound... + | +LL | impl<'a, T: 'a> Trait<'a, T> for u32 { + | ++++ error: aborting due to 2 previous errors diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs index b09c23f31e970..662a561f171e9 100644 --- a/src/tools/clippy/clippy_lints/src/lifetimes.rs +++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs @@ -8,7 +8,7 @@ use rustc_hir::FnRetTy::Return; use rustc_hir::{ BareFnTy, BodyId, FnDecl, GenericArg, GenericBound, GenericParam, GenericParamKind, Generics, ImplItem, ImplItemKind, Item, ItemKind, LangItem, Lifetime, LifetimeName, ParamName, PolyTraitRef, TraitBoundModifier, - TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WhereClause, WherePredicate, + TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WherePredicate, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -130,7 +130,7 @@ fn check_fn_inner<'tcx>( span: Span, report_extra_lifetimes: bool, ) { - if span.from_expansion() || has_where_lifetimes(cx, &generics.where_clause) { + if span.from_expansion() || has_where_lifetimes(cx, generics) { return; } @@ -139,28 +139,35 @@ fn check_fn_inner<'tcx>( .iter() .filter(|param| matches!(param.kind, GenericParamKind::Type { .. })); for typ in types { - for bound in typ.bounds { - let mut visitor = RefVisitor::new(cx); - walk_param_bound(&mut visitor, bound); - if visitor.lts.iter().any(|lt| matches!(lt, RefLt::Named(_))) { - return; + for pred in generics.bounds_for_param(cx.tcx.hir().local_def_id(typ.hir_id)) { + if pred.in_where_clause { + // has_where_lifetimes checked that this predicate contains no lifetime. + continue; } - if let GenericBound::Trait(ref trait_ref, _) = *bound { - let params = &trait_ref - .trait_ref - .path - .segments - .last() - .expect("a path must have at least one segment") - .args; - if let Some(params) = *params { - let lifetimes = params.args.iter().filter_map(|arg| match arg { - GenericArg::Lifetime(lt) => Some(lt), - _ => None, - }); - for bound in lifetimes { - if bound.name != LifetimeName::Static && !bound.is_elided() { - return; + + for bound in pred.bounds { + let mut visitor = RefVisitor::new(cx); + walk_param_bound(&mut visitor, bound); + if visitor.lts.iter().any(|lt| matches!(lt, RefLt::Named(_))) { + return; + } + if let GenericBound::Trait(ref trait_ref, _) = *bound { + let params = &trait_ref + .trait_ref + .path + .segments + .last() + .expect("a path must have at least one segment") + .args; + if let Some(params) = *params { + let lifetimes = params.args.iter().filter_map(|arg| match arg { + GenericArg::Lifetime(lt) => Some(lt), + _ => None, + }); + for bound in lifetimes { + if bound.name != LifetimeName::Static && !bound.is_elided() { + return; + } } } } @@ -322,9 +329,7 @@ fn allowed_lts_from(named_generics: &[GenericParam<'_>]) -> FxHashSet { let mut allowed_lts = FxHashSet::default(); for par in named_generics.iter() { if let GenericParamKind::Lifetime { .. } = par.kind { - if par.bounds.is_empty() { - allowed_lts.insert(RefLt::Named(par.name.ident().name)); - } + allowed_lts.insert(RefLt::Named(par.name.ident().name)); } } allowed_lts.insert(RefLt::Unnamed); @@ -445,8 +450,8 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> { /// Are any lifetimes mentioned in the `where` clause? If so, we don't try to /// reason about elision. -fn has_where_lifetimes<'tcx>(cx: &LateContext<'tcx>, where_clause: &'tcx WhereClause<'_>) -> bool { - for predicate in where_clause.predicates { +fn has_where_lifetimes<'tcx>(cx: &LateContext<'tcx>, generics: &'tcx Generics<'_>) -> bool { + for predicate in generics.predicates { match *predicate { WherePredicate::RegionPredicate(..) => return true, WherePredicate::BoundPredicate(ref pred) => { diff --git a/src/tools/clippy/clippy_lints/src/new_without_default.rs b/src/tools/clippy/clippy_lints/src/new_without_default.rs index 9419056be1432..96c00c205ff2e 100644 --- a/src/tools/clippy/clippy_lints/src/new_without_default.rs +++ b/src/tools/clippy/clippy_lints/src/new_without_default.rs @@ -68,7 +68,7 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault { .. }) = item.kind { - for assoc_item in items { + for assoc_item in *items { if assoc_item.kind == (hir::AssocItemKind::Fn { has_self: false }) { let impl_item = cx.tcx.hir().impl_item(assoc_item.id); if in_external_macro(cx.sess(), impl_item.span) { diff --git a/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs b/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs index e827cdaae8728..1469cb434c00c 100644 --- a/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs +++ b/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs @@ -42,7 +42,7 @@ impl<'tcx> LateLintPass<'tcx> for PartialEqNeImpl { if let Some(eq_trait) = cx.tcx.lang_items().eq_trait(); if trait_ref.path.res.def_id() == eq_trait; then { - for impl_item in impl_items { + for impl_item in *impl_items { if impl_item.ident.name == sym::ne { span_lint_hir( cx, diff --git a/src/tools/clippy/clippy_lints/src/serde_api.rs b/src/tools/clippy/clippy_lints/src/serde_api.rs index 398e2c200de3c..fc1c2af9257bf 100644 --- a/src/tools/clippy/clippy_lints/src/serde_api.rs +++ b/src/tools/clippy/clippy_lints/src/serde_api.rs @@ -36,7 +36,7 @@ impl<'tcx> LateLintPass<'tcx> for SerdeApi { if did == visit_did { let mut seen_str = None; let mut seen_string = None; - for item in items { + for item in *items { match item.ident.as_str() { "visit_str" => seen_str = Some(item.span), "visit_string" => seen_string = Some(item.span), diff --git a/src/tools/clippy/clippy_lints/src/trait_bounds.rs b/src/tools/clippy/clippy_lints/src/trait_bounds.rs index 43e0132a7ec7b..3d1b2ee925bce 100644 --- a/src/tools/clippy/clippy_lints/src/trait_bounds.rs +++ b/src/tools/clippy/clippy_lints/src/trait_bounds.rs @@ -8,8 +8,7 @@ use rustc_data_structures::unhash::UnhashMap; use rustc_errors::Applicability; use rustc_hir::def::Res; use rustc_hir::{ - GenericBound, Generics, Item, ItemKind, Node, ParamName, Path, PathSegment, QPath, TraitItem, Ty, TyKind, - WherePredicate, + GenericBound, Generics, Item, ItemKind, Node, Path, PathSegment, QPath, TraitItem, Ty, TyKind, WherePredicate, }; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; @@ -90,10 +89,9 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds { } fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'tcx>) { - let Generics { where_clause, .. } = &item.generics; let mut self_bounds_map = FxHashMap::default(); - for predicate in where_clause.predicates { + for predicate in item.generics.predicates { if_chain! { if let WherePredicate::BoundPredicate(ref bound_predicate) = predicate; if !bound_predicate.span.from_expansion(); @@ -166,7 +164,7 @@ impl TraitBounds { } let mut map: UnhashMap, Vec<&GenericBound<'_>>> = UnhashMap::default(); let mut applicability = Applicability::MaybeIncorrect; - for bound in gen.where_clause.predicates { + for bound in gen.predicates { if_chain! { if let WherePredicate::BoundPredicate(ref p) = bound; if p.bounds.len() as u64 <= self.max_trait_bounds; @@ -216,34 +214,23 @@ impl TraitBounds { } fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) { - if gen.span.from_expansion() || gen.params.is_empty() || gen.where_clause.predicates.is_empty() { + if gen.span.from_expansion() || gen.params.is_empty() || gen.predicates.is_empty() { return; } - let mut map = FxHashMap::default(); - for param in gen.params { - if let ParamName::Plain(ref ident) = param.name { - let res = param - .bounds - .iter() - .filter_map(get_trait_info_from_bound) - .collect::>(); - map.insert(*ident, res); - } - } - - for predicate in gen.where_clause.predicates { + let mut map = FxHashMap::<_, Vec<_>>::default(); + for predicate in gen.predicates { if_chain! { if let WherePredicate::BoundPredicate(ref bound_predicate) = predicate; if !bound_predicate.span.from_expansion(); if let TyKind::Path(QPath::Resolved(_, Path { segments, .. })) = bound_predicate.bounded_ty.kind; if let Some(segment) = segments.first(); - if let Some(trait_resolutions_direct) = map.get(&segment.ident); then { - for (res_where, _, _) in bound_predicate.bounds.iter().filter_map(get_trait_info_from_bound) { - if let Some((_, _, span_direct)) = trait_resolutions_direct + for (res_where, _, span_where) in bound_predicate.bounds.iter().filter_map(get_trait_info_from_bound) { + let trait_resolutions_direct = map.entry(segment.ident).or_default(); + if let Some((_, span_direct)) = trait_resolutions_direct .iter() - .find(|(res_direct, _, _)| *res_direct == res_where) { + .find(|(res_direct, _)| *res_direct == res_where) { span_lint_and_help( cx, TRAIT_DUPLICATION_IN_BOUNDS, @@ -253,6 +240,9 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) { "consider removing this trait bound", ); } + else { + trait_resolutions_direct.push((res_where, span_where)) + } } } } diff --git a/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs b/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs index 7c06906293b16..f35f44eda5679 100644 --- a/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs +++ b/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs @@ -104,8 +104,10 @@ fn get_bounds_if_impl_trait<'tcx>(cx: &LateContext<'tcx>, qpath: &QPath<'_>, id: if let Some(Node::GenericParam(generic_param)) = cx.tcx.hir().get_if_local(did); if let GenericParamKind::Type { synthetic, .. } = generic_param.kind; if synthetic; + if let Some(generics) = cx.tcx.hir().get_generics(id.owner); + if let Some(pred) = generics.bounds_for_param(did.expect_local()).next(); then { - Some(generic_param.bounds) + Some(pred.bounds) } else { None } diff --git a/src/tools/clippy/tests/ui/extra_unused_lifetimes.stderr b/src/tools/clippy/tests/ui/extra_unused_lifetimes.stderr index ebdb8e749520f..9143fb2c208a0 100644 --- a/src/tools/clippy/tests/ui/extra_unused_lifetimes.stderr +++ b/src/tools/clippy/tests/ui/extra_unused_lifetimes.stderr @@ -6,12 +6,6 @@ LL | fn unused_lt<'a>(x: u8) {} | = note: `-D clippy::extra-unused-lifetimes` implied by `-D warnings` -error: this lifetime isn't used in the function definition - --> $DIR/extra_unused_lifetimes.rs:16:25 - | -LL | fn unused_lt_transitive<'a, 'b: 'a>(x: &'b u8) { - | ^^ - error: this lifetime isn't used in the function definition --> $DIR/extra_unused_lifetimes.rs:41:10 | @@ -24,5 +18,5 @@ error: this lifetime isn't used in the function definition LL | fn unused_lt<'a>(x: u8) {} | ^^ -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors diff --git a/src/tools/clippy/tests/ui/needless_lifetimes.stderr b/src/tools/clippy/tests/ui/needless_lifetimes.stderr index ffa152427a977..a488bc01fffa2 100644 --- a/src/tools/clippy/tests/ui/needless_lifetimes.stderr +++ b/src/tools/clippy/tests/ui/needless_lifetimes.stderr @@ -108,12 +108,6 @@ error: explicit lifetimes given in parameter types where they could be elided (o LL | fn baz<'a>(&'a self) -> impl Foo + 'a { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) - --> $DIR/needless_lifetimes.rs:307:5 - | -LL | fn impl_trait_elidable_nested_named_lifetimes<'a>(i: &'a i32, f: impl for<'b> Fn(&'b i32) -> &'b i32) -> &'a i32 { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) --> $DIR/needless_lifetimes.rs:310:5 | @@ -192,5 +186,5 @@ error: explicit lifetimes given in parameter types where they could be elided (o LL | fn lifetime_elsewhere_provided<'a>(self: Box, here: &'a ()) -> &'a () { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 32 previous errors +error: aborting due to 31 previous errors