Store all generic bounds as where predicates.
This commit is contained in:
parent
05b29f9a92
commit
94449e6101
30 changed files with 770 additions and 953 deletions
|
@ -267,9 +267,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
this.lower_maybe_async_body(span, &decl, asyncness, body.as_deref());
|
this.lower_maybe_async_body(span, &decl, asyncness, body.as_deref());
|
||||||
|
|
||||||
let (generics, decl) =
|
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();
|
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 {
|
let sig = hir::FnSig {
|
||||||
decl,
|
decl,
|
||||||
|
@ -384,7 +389,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
// lifetime to be added, but rather a reference to a
|
// lifetime to be added, but rather a reference to a
|
||||||
// parent lifetime.
|
// parent lifetime.
|
||||||
let (generics, (trait_ref, lowered_ty)) =
|
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| {
|
let trait_ref = trait_ref.as_ref().map(|trait_ref| {
|
||||||
this.lower_trait_ref(
|
this.lower_trait_ref(
|
||||||
trait_ref,
|
trait_ref,
|
||||||
|
@ -649,7 +654,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
ForeignItemKind::Fn(box Fn { ref sig, ref generics, .. }) => {
|
ForeignItemKind::Fn(box Fn { ref sig, ref generics, .. }) => {
|
||||||
let fdec = &sig.decl;
|
let fdec = &sig.decl;
|
||||||
let (generics, (fn_dec, fn_args)) =
|
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.
|
// Disallow `impl Trait` in foreign items.
|
||||||
this.lower_fn_decl(fdec, None, FnDeclKind::ExternFn, None),
|
this.lower_fn_decl(fdec, None, FnDeclKind::ExternFn, None),
|
||||||
|
@ -1228,8 +1233,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
is_async: Option<NodeId>,
|
is_async: Option<NodeId>,
|
||||||
) -> (&'hir hir::Generics<'hir>, hir::FnSig<'hir>) {
|
) -> (&'hir hir::Generics<'hir>, hir::FnSig<'hir>) {
|
||||||
let header = self.lower_fn_header(sig.header);
|
let header = self.lower_fn_header(sig.header);
|
||||||
let (generics, decl) = self.add_implicit_generics(generics, id, |this, idty| {
|
let (generics, decl) = self.add_implicit_generics(generics, id, |this, idty, idpb| {
|
||||||
this.lower_fn_decl(&sig.decl, Some((id, idty)), kind, is_async)
|
this.lower_fn_decl(&sig.decl, Some((id, idty, idpb)), kind, is_async)
|
||||||
});
|
});
|
||||||
(generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) })
|
(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(
|
pub(super) fn lower_generics_mut(
|
||||||
&mut self,
|
&mut self,
|
||||||
generics: &Generics,
|
generics: &Generics,
|
||||||
itctx: ImplTraitContext<'_, 'hir>,
|
mut itctx: ImplTraitContext<'_, 'hir>,
|
||||||
) -> GenericsCtor<'hir> {
|
) -> GenericsCtor<'hir> {
|
||||||
// Error if `?Trait` bounds in where clauses don't refer directly to type parameters.
|
// 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
|
// Note: we used to clone these bounds directly onto the type parameter (and avoid lowering
|
||||||
|
@ -1338,7 +1343,12 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let predicates = self.arena.alloc_from_iter(
|
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
|
generics
|
||||||
.where_clause
|
.where_clause
|
||||||
.predicates
|
.predicates
|
||||||
|
@ -1347,8 +1357,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
);
|
);
|
||||||
|
|
||||||
GenericsCtor {
|
GenericsCtor {
|
||||||
params: self.lower_generic_params_mut(&generics.params, itctx).collect(),
|
params: self.lower_generic_params_mut(&generics.params).collect(),
|
||||||
predicates,
|
predicates,
|
||||||
|
has_where_clause: !generics.where_clause.predicates.is_empty(),
|
||||||
where_clause_span: self.lower_span(generics.where_clause.span),
|
where_clause_span: self.lower_span(generics.where_clause.span),
|
||||||
span: self.lower_span(generics.span),
|
span: self.lower_span(generics.span),
|
||||||
}
|
}
|
||||||
|
@ -1363,6 +1374,72 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
generics_ctor.into_generics(self.arena)
|
generics_ctor.into_generics(self.arena)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) fn lower_generic_bound_predicate(
|
||||||
|
&mut self,
|
||||||
|
ident: Ident,
|
||||||
|
id: NodeId,
|
||||||
|
kind: &GenericParamKind,
|
||||||
|
bounds: &'hir [hir::GenericBound<'hir>],
|
||||||
|
) -> Option<hir::WherePredicate<'hir>> {
|
||||||
|
// 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<Span>, 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,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn lower_where_predicate(&mut self, pred: &WherePredicate) -> hir::WherePredicate<'hir> {
|
fn lower_where_predicate(&mut self, pred: &WherePredicate) -> hir::WherePredicate<'hir> {
|
||||||
match *pred {
|
match *pred {
|
||||||
WherePredicate::BoundPredicate(WhereBoundPredicate {
|
WherePredicate::BoundPredicate(WhereBoundPredicate {
|
||||||
|
@ -1371,10 +1448,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
ref bounds,
|
ref bounds,
|
||||||
span,
|
span,
|
||||||
}) => hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
|
}) => hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
|
||||||
bound_generic_params: self.lower_generic_params(
|
bound_generic_params: self.lower_generic_params(bound_generic_params),
|
||||||
bound_generic_params,
|
|
||||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
|
||||||
),
|
|
||||||
bounded_ty: self
|
bounded_ty: self
|
||||||
.lower_ty(bounded_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type)),
|
.lower_ty(bounded_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type)),
|
||||||
bounds: self.arena.alloc_from_iter(bounds.iter().map(|bound| {
|
bounds: self.arena.alloc_from_iter(bounds.iter().map(|bound| {
|
||||||
|
@ -1384,6 +1458,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
)
|
)
|
||||||
})),
|
})),
|
||||||
span: self.lower_span(span),
|
span: self.lower_span(span),
|
||||||
|
in_where_clause: true,
|
||||||
}),
|
}),
|
||||||
WherePredicate::RegionPredicate(WhereRegionPredicate {
|
WherePredicate::RegionPredicate(WhereRegionPredicate {
|
||||||
ref lifetime,
|
ref lifetime,
|
||||||
|
@ -1396,6 +1471,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
bounds,
|
bounds,
|
||||||
ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
|
ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
|
||||||
),
|
),
|
||||||
|
in_where_clause: true,
|
||||||
}),
|
}),
|
||||||
WherePredicate::EqPredicate(WhereEqPredicate { id, ref lhs_ty, ref rhs_ty, span }) => {
|
WherePredicate::EqPredicate(WhereEqPredicate { id, ref lhs_ty, ref rhs_ty, span }) => {
|
||||||
hir::WherePredicate::EqPredicate(hir::WhereEqPredicate {
|
hir::WherePredicate::EqPredicate(hir::WhereEqPredicate {
|
||||||
|
@ -1414,7 +1490,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
/// Helper struct for delayed construction of Generics.
|
/// Helper struct for delayed construction of Generics.
|
||||||
pub(super) struct GenericsCtor<'hir> {
|
pub(super) struct GenericsCtor<'hir> {
|
||||||
pub(super) params: SmallVec<[hir::GenericParam<'hir>; 4]>,
|
pub(super) params: SmallVec<[hir::GenericParam<'hir>; 4]>,
|
||||||
predicates: &'hir [hir::WherePredicate<'hir>],
|
pub(super) predicates: SmallVec<[hir::WherePredicate<'hir>; 4]>,
|
||||||
|
has_where_clause: bool,
|
||||||
where_clause_span: Span,
|
where_clause_span: Span,
|
||||||
span: Span,
|
span: Span,
|
||||||
}
|
}
|
||||||
|
@ -1423,7 +1500,8 @@ impl<'hir> GenericsCtor<'hir> {
|
||||||
pub(super) fn into_generics(self, arena: &'hir Arena<'hir>) -> &'hir hir::Generics<'hir> {
|
pub(super) fn into_generics(self, arena: &'hir Arena<'hir>) -> &'hir hir::Generics<'hir> {
|
||||||
arena.alloc(hir::Generics {
|
arena.alloc(hir::Generics {
|
||||||
params: arena.alloc_from_iter(self.params),
|
params: arena.alloc_from_iter(self.params),
|
||||||
predicates: self.predicates,
|
predicates: arena.alloc_from_iter(self.predicates),
|
||||||
|
has_where_clause: self.has_where_clause,
|
||||||
where_clause_span: self.where_clause_span,
|
where_clause_span: self.where_clause_span,
|
||||||
span: self.span,
|
span: self.span,
|
||||||
})
|
})
|
||||||
|
|
|
@ -259,7 +259,7 @@ enum ImplTraitContext<'b, 'a> {
|
||||||
/// equivalent to a fresh universal parameter like `fn foo<T: Debug>(x: T)`.
|
/// equivalent to a fresh universal parameter like `fn foo<T: Debug>(x: T)`.
|
||||||
///
|
///
|
||||||
/// Newly generated parameters should be inserted into the given `Vec`.
|
/// Newly generated parameters should be inserted into the given `Vec`.
|
||||||
Universal(&'b mut Vec<hir::GenericParam<'a>>, LocalDefId),
|
Universal(&'b mut Vec<hir::GenericParam<'a>>, &'b mut Vec<hir::WherePredicate<'a>>, LocalDefId),
|
||||||
|
|
||||||
/// Treat `impl Trait` as shorthand for a new opaque type.
|
/// Treat `impl Trait` as shorthand for a new opaque type.
|
||||||
/// Example: `fn foo() -> impl Debug`, where `impl Debug` is conceptually
|
/// 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> {
|
fn reborrow<'this>(&'this mut self) -> ImplTraitContext<'this, 'a> {
|
||||||
use self::ImplTraitContext::*;
|
use self::ImplTraitContext::*;
|
||||||
match self {
|
match self {
|
||||||
Universal(params, parent) => Universal(params, *parent),
|
Universal(params, bounds, parent) => Universal(params, bounds, *parent),
|
||||||
ReturnPositionOpaqueTy { origin } => ReturnPositionOpaqueTy { origin: *origin },
|
ReturnPositionOpaqueTy { origin } => ReturnPositionOpaqueTy { origin: *origin },
|
||||||
TypeAliasesOpaqueTy => TypeAliasesOpaqueTy,
|
TypeAliasesOpaqueTy => TypeAliasesOpaqueTy,
|
||||||
Disallowed(pos) => Disallowed(*pos),
|
Disallowed(pos) => Disallowed(*pos),
|
||||||
|
@ -704,7 +704,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
Some(hir::GenericParam {
|
Some(hir::GenericParam {
|
||||||
hir_id,
|
hir_id,
|
||||||
name,
|
name,
|
||||||
bounds: &[],
|
|
||||||
span: self.lower_span(ident.span),
|
span: self.lower_span(ident.span),
|
||||||
pure_wrt_drop: false,
|
pure_wrt_drop: false,
|
||||||
kind: hir::GenericParamKind::Lifetime { kind },
|
kind: hir::GenericParamKind::Lifetime { kind },
|
||||||
|
@ -718,14 +717,23 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
&mut self,
|
&mut self,
|
||||||
generics: &Generics,
|
generics: &Generics,
|
||||||
parent_node_id: NodeId,
|
parent_node_id: NodeId,
|
||||||
f: impl FnOnce(&mut Self, &mut Vec<hir::GenericParam<'hir>>) -> T,
|
f: impl FnOnce(
|
||||||
|
&mut Self,
|
||||||
|
&mut Vec<hir::GenericParam<'hir>>,
|
||||||
|
&mut Vec<hir::WherePredicate<'hir>>,
|
||||||
|
) -> T,
|
||||||
) -> (&'hir hir::Generics<'hir>, T) {
|
) -> (&'hir hir::Generics<'hir>, T) {
|
||||||
let mut impl_trait_defs = Vec::new();
|
let mut impl_trait_defs = Vec::new();
|
||||||
|
let mut impl_trait_bounds = Vec::new();
|
||||||
let mut lowered_generics = self.lower_generics_mut(
|
let mut lowered_generics = self.lower_generics_mut(
|
||||||
generics,
|
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);
|
let extra_lifetimes = self.resolver.take_extra_lifetime_params(parent_node_id);
|
||||||
lowered_generics.params.extend(
|
lowered_generics.params.extend(
|
||||||
|
@ -736,6 +744,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
})
|
})
|
||||||
.chain(impl_trait_defs),
|
.chain(impl_trait_defs),
|
||||||
);
|
);
|
||||||
|
lowered_generics.predicates.extend(impl_trait_bounds);
|
||||||
|
|
||||||
let lowered_generics = lowered_generics.into_generics(self.arena);
|
let lowered_generics = lowered_generics.into_generics(self.arena);
|
||||||
(lowered_generics, res)
|
(lowered_generics, res)
|
||||||
|
@ -999,7 +1008,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
// so desugar to
|
// so desugar to
|
||||||
//
|
//
|
||||||
// fn foo(x: dyn Iterator<Item = impl Debug>)
|
// fn foo(x: dyn Iterator<Item = impl Debug>)
|
||||||
ImplTraitContext::Universal(_, parent) if self.is_in_dyn_type => {
|
ImplTraitContext::Universal(_, _, parent) if self.is_in_dyn_type => {
|
||||||
parent_def_id = parent;
|
parent_def_id = parent;
|
||||||
(true, itctx)
|
(true, itctx)
|
||||||
}
|
}
|
||||||
|
@ -1188,10 +1197,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
}
|
}
|
||||||
TyKind::BareFn(ref f) => self.with_lifetime_binder(t.id, |this| {
|
TyKind::BareFn(ref f) => self.with_lifetime_binder(t.id, |this| {
|
||||||
hir::TyKind::BareFn(this.arena.alloc(hir::BareFnTy {
|
hir::TyKind::BareFn(this.arena.alloc(hir::BareFnTy {
|
||||||
generic_params: this.lower_generic_params(
|
generic_params: this.lower_generic_params(&f.generic_params),
|
||||||
&f.generic_params,
|
|
||||||
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
|
||||||
),
|
|
||||||
unsafety: this.lower_unsafety(f.unsafety),
|
unsafety: this.lower_unsafety(f.unsafety),
|
||||||
abi: this.lower_extern(f.ext),
|
abi: this.lower_extern(f.ext),
|
||||||
decl: this.lower_fn_decl(&f.decl, None, FnDeclKind::Pointer, None),
|
decl: this.lower_fn_decl(&f.decl, None, FnDeclKind::Pointer, None),
|
||||||
|
@ -1274,13 +1280,21 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
|this| this.lower_param_bounds(bounds, nested_itctx),
|
|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`.
|
// Add a definition for the in-band `Param`.
|
||||||
let def_id = self.resolver.local_def_id(def_node_id);
|
let def_id = self.resolver.local_def_id(def_node_id);
|
||||||
|
|
||||||
let hir_bounds = self.lower_param_bounds(
|
let hir_bounds = self.lower_param_bounds(
|
||||||
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`.
|
// Set the name to `impl Bound1 + Bound2`.
|
||||||
let ident = Ident::from_str_and_span(&pprust::ty_to_string(t), span);
|
let ident = Ident::from_str_and_span(&pprust::ty_to_string(t), span);
|
||||||
|
@ -1288,10 +1302,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
hir_id: self.lower_node_id(def_node_id),
|
hir_id: self.lower_node_id(def_node_id),
|
||||||
name: ParamName::Plain(self.lower_ident(ident)),
|
name: ParamName::Plain(self.lower_ident(ident)),
|
||||||
pure_wrt_drop: false,
|
pure_wrt_drop: false,
|
||||||
bounds: hir_bounds,
|
|
||||||
span: self.lower_span(span),
|
span: self.lower_span(span),
|
||||||
kind: hir::GenericParamKind::Type { default: None, synthetic: true },
|
kind: hir::GenericParamKind::Type { default: None, synthetic: true },
|
||||||
});
|
});
|
||||||
|
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(
|
hir::TyKind::Path(hir::QPath::Resolved(
|
||||||
None,
|
None,
|
||||||
|
@ -1374,7 +1395,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
name: p_name,
|
name: p_name,
|
||||||
span,
|
span,
|
||||||
pure_wrt_drop: false,
|
pure_wrt_drop: false,
|
||||||
bounds: &[],
|
|
||||||
kind: hir::GenericParamKind::Lifetime { kind },
|
kind: hir::GenericParamKind::Lifetime { kind },
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -1386,6 +1406,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
generics: self.arena.alloc(hir::Generics {
|
generics: self.arena.alloc(hir::Generics {
|
||||||
params: lifetime_defs,
|
params: lifetime_defs,
|
||||||
predicates: &[],
|
predicates: &[],
|
||||||
|
has_where_clause: false,
|
||||||
where_clause_span: lctx.lower_span(span),
|
where_clause_span: lctx.lower_span(span),
|
||||||
span: lctx.lower_span(span),
|
span: lctx.lower_span(span),
|
||||||
}),
|
}),
|
||||||
|
@ -1463,7 +1484,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
fn lower_fn_decl(
|
fn lower_fn_decl(
|
||||||
&mut self,
|
&mut self,
|
||||||
decl: &FnDecl,
|
decl: &FnDecl,
|
||||||
mut in_band_ty_params: Option<(NodeId, &mut Vec<hir::GenericParam<'hir>>)>,
|
mut in_band_ty_params: Option<(
|
||||||
|
NodeId,
|
||||||
|
&mut Vec<hir::GenericParam<'hir>>,
|
||||||
|
&mut Vec<hir::WherePredicate<'hir>>,
|
||||||
|
)>,
|
||||||
kind: FnDeclKind,
|
kind: FnDeclKind,
|
||||||
make_ret_async: Option<NodeId>,
|
make_ret_async: Option<NodeId>,
|
||||||
) -> &'hir hir::FnDecl<'hir> {
|
) -> &'hir hir::FnDecl<'hir> {
|
||||||
|
@ -1486,10 +1511,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
inputs = &inputs[..inputs.len() - 1];
|
inputs = &inputs[..inputs.len() - 1];
|
||||||
}
|
}
|
||||||
let inputs = self.arena.alloc_from_iter(inputs.iter().map(|param| {
|
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(
|
self.lower_ty_direct(
|
||||||
¶m.ty,
|
¶m.ty,
|
||||||
ImplTraitContext::Universal(ibty, self.current_hir_id_owner),
|
ImplTraitContext::Universal(ibty, ibpb, self.current_hir_id_owner),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
self.lower_ty_direct(
|
self.lower_ty_direct(
|
||||||
|
@ -1518,7 +1543,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
match decl.output {
|
match decl.output {
|
||||||
FnRetTy::Ty(ref ty) => {
|
FnRetTy::Ty(ref ty) => {
|
||||||
let context = match in_band_ty_params {
|
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);
|
let fn_def_id = self.resolver.local_def_id(node_id);
|
||||||
ImplTraitContext::ReturnPositionOpaqueTy {
|
ImplTraitContext::ReturnPositionOpaqueTy {
|
||||||
origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id),
|
origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id),
|
||||||
|
@ -1709,7 +1734,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
name: p_name,
|
name: p_name,
|
||||||
span,
|
span,
|
||||||
pure_wrt_drop: false,
|
pure_wrt_drop: false,
|
||||||
bounds: &[],
|
|
||||||
kind: hir::GenericParamKind::Lifetime { kind },
|
kind: hir::GenericParamKind::Lifetime { kind },
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
@ -1719,6 +1743,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
generics: this.arena.alloc(hir::Generics {
|
generics: this.arena.alloc(hir::Generics {
|
||||||
params: generic_params,
|
params: generic_params,
|
||||||
predicates: &[],
|
predicates: &[],
|
||||||
|
has_where_clause: false,
|
||||||
where_clause_span: this.lower_span(span),
|
where_clause_span: this.lower_span(span),
|
||||||
span: this.lower_span(span),
|
span: this.lower_span(span),
|
||||||
}),
|
}),
|
||||||
|
@ -1925,26 +1950,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
fn lower_generic_params_mut<'s>(
|
fn lower_generic_params_mut<'s>(
|
||||||
&'s mut self,
|
&'s mut self,
|
||||||
params: &'s [GenericParam],
|
params: &'s [GenericParam],
|
||||||
mut itctx: ImplTraitContext<'s, 'hir>,
|
|
||||||
) -> impl Iterator<Item = hir::GenericParam<'hir>> + Captures<'a> + Captures<'s> {
|
) -> impl Iterator<Item = hir::GenericParam<'hir>> + 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(
|
fn lower_generic_params(&mut self, params: &[GenericParam]) -> &'hir [hir::GenericParam<'hir>] {
|
||||||
&mut self,
|
self.arena.alloc_from_iter(self.lower_generic_params_mut(params))
|
||||||
params: &[GenericParam],
|
|
||||||
itctx: ImplTraitContext<'_, 'hir>,
|
|
||||||
) -> &'hir [hir::GenericParam<'hir>] {
|
|
||||||
self.arena.alloc_from_iter(self.lower_generic_params_mut(params, itctx))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_generic_param(
|
fn lower_generic_param(&mut self, param: &GenericParam) -> hir::GenericParam<'hir> {
|
||||||
&mut self,
|
|
||||||
param: &GenericParam,
|
|
||||||
mut itctx: ImplTraitContext<'_, 'hir>,
|
|
||||||
) -> hir::GenericParam<'hir> {
|
|
||||||
let bounds: Vec<_> = self.lower_param_bounds_mut(¶m.bounds, itctx.reborrow()).collect();
|
|
||||||
|
|
||||||
let (name, kind) = match param.kind {
|
let (name, kind) = match param.kind {
|
||||||
GenericParamKind::Lifetime => {
|
GenericParamKind::Lifetime => {
|
||||||
let param_name = if param.ident.name == kw::StaticLifetime
|
let param_name = if param.ident.name == kw::StaticLifetime
|
||||||
|
@ -1991,7 +2005,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
name,
|
name,
|
||||||
span: self.lower_span(param.span()),
|
span: self.lower_span(param.span()),
|
||||||
pure_wrt_drop: self.sess.contains_name(¶m.attrs, sym::may_dangle),
|
pure_wrt_drop: self.sess.contains_name(¶m.attrs, sym::may_dangle),
|
||||||
bounds: self.arena.alloc_from_iter(bounds),
|
|
||||||
kind,
|
kind,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2014,8 +2027,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||||
p: &PolyTraitRef,
|
p: &PolyTraitRef,
|
||||||
mut itctx: ImplTraitContext<'_, 'hir>,
|
mut itctx: ImplTraitContext<'_, 'hir>,
|
||||||
) -> hir::PolyTraitRef<'hir> {
|
) -> hir::PolyTraitRef<'hir> {
|
||||||
let bound_generic_params =
|
let bound_generic_params = self.lower_generic_params(&p.bound_generic_params);
|
||||||
self.lower_generic_params(&p.bound_generic_params, itctx.reborrow());
|
|
||||||
|
|
||||||
let trait_ref = self.with_lifetime_binder(p.trait_ref.ref_id, |this| {
|
let trait_ref = self.with_lifetime_binder(p.trait_ref.ref_id, |this| {
|
||||||
this.lower_trait_ref(&p.trait_ref, itctx.reborrow())
|
this.lower_trait_ref(&p.trait_ref, itctx.reborrow())
|
||||||
|
|
|
@ -496,27 +496,24 @@ pub enum GenericParamKind<'hir> {
|
||||||
pub struct GenericParam<'hir> {
|
pub struct GenericParam<'hir> {
|
||||||
pub hir_id: HirId,
|
pub hir_id: HirId,
|
||||||
pub name: ParamName,
|
pub name: ParamName,
|
||||||
pub bounds: GenericBounds<'hir>,
|
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub pure_wrt_drop: bool,
|
pub pure_wrt_drop: bool,
|
||||||
pub kind: GenericParamKind<'hir>,
|
pub kind: GenericParamKind<'hir>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'hir> GenericParam<'hir> {
|
impl<'hir> GenericParam<'hir> {
|
||||||
pub fn bounds_span_for_suggestions(&self) -> Option<Span> {
|
/// Synthetic type-parameters are inserted after normal ones.
|
||||||
self.bounds
|
/// In order for normal parameters to be able to refer to synthetic ones,
|
||||||
.iter()
|
/// scans them first.
|
||||||
.fold(None, |span: Option<Span>, bound| {
|
pub fn is_impl_trait(&self) -> bool {
|
||||||
// We include bounds that come from a `#[derive(_)]` but point at the user's code,
|
matches!(self.kind, GenericParamKind::Type { synthetic: true, .. })
|
||||||
// as we use this method to get a span appropriate for suggestions.
|
}
|
||||||
if !bound.span().can_be_used_for_suggestions() {
|
|
||||||
None
|
/// This can happen for `async fn`, e.g. `async fn f<'_>(&'_ self)`.
|
||||||
} else {
|
///
|
||||||
let span = span.map(|s| s.to(bound.span())).unwrap_or_else(|| bound.span());
|
/// See `lifetime_to_generic_param` in `rustc_ast_lowering` for more information.
|
||||||
Some(span)
|
pub fn is_elided_lifetime(&self) -> bool {
|
||||||
}
|
matches!(self.kind, GenericParamKind::Lifetime { kind: LifetimeParamKind::Elided })
|
||||||
})
|
|
||||||
.map(|sp| sp.shrink_to_hi())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the span of `:` after a generic parameter.
|
/// Returns the span of `:` after a generic parameter.
|
||||||
|
@ -568,14 +565,20 @@ pub struct GenericParamCount {
|
||||||
pub struct Generics<'hir> {
|
pub struct Generics<'hir> {
|
||||||
pub params: &'hir [GenericParam<'hir>],
|
pub params: &'hir [GenericParam<'hir>],
|
||||||
pub predicates: &'hir [WherePredicate<'hir>],
|
pub predicates: &'hir [WherePredicate<'hir>],
|
||||||
|
pub has_where_clause: bool,
|
||||||
pub where_clause_span: Span,
|
pub where_clause_span: Span,
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'hir> Generics<'hir> {
|
impl<'hir> Generics<'hir> {
|
||||||
pub const fn empty() -> &'hir Generics<'hir> {
|
pub const fn empty() -> &'hir Generics<'hir> {
|
||||||
const NOPE: Generics<'_> =
|
const NOPE: Generics<'_> = Generics {
|
||||||
Generics { params: &[], predicates: &[], where_clause_span: DUMMY_SP, span: DUMMY_SP };
|
params: &[],
|
||||||
|
predicates: &[],
|
||||||
|
has_where_clause: false,
|
||||||
|
where_clause_span: DUMMY_SP,
|
||||||
|
span: DUMMY_SP,
|
||||||
|
};
|
||||||
&NOPE
|
&NOPE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -596,6 +599,19 @@ impl<'hir> Generics<'hir> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// If there are generic parameters, return wher to introduce a new one, and false.
|
||||||
|
/// If there is none, return where to introduce `<>` and true.
|
||||||
|
pub fn span_for_param_suggestion(&self) -> Option<Span> {
|
||||||
|
if self.params.iter().any(|p| self.span.contains(p.span)) {
|
||||||
|
// `fn foo<A>(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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn where_clause_span(&self) -> Option<Span> {
|
pub fn where_clause_span(&self) -> Option<Span> {
|
||||||
if self.predicates.is_empty() { None } else { Some(self.where_clause_span) }
|
if self.predicates.is_empty() { None } else { Some(self.where_clause_span) }
|
||||||
}
|
}
|
||||||
|
@ -610,7 +626,95 @@ impl<'hir> Generics<'hir> {
|
||||||
/// in `fn foo<T>(t: T) where T: Foo,` so we don't suggest two trailing commas.
|
/// in `fn foo<T>(t: T) where T: Foo,` so we don't suggest two trailing commas.
|
||||||
pub fn tail_span_for_predicate_suggestion(&self) -> Span {
|
pub fn tail_span_for_predicate_suggestion(&self) -> Span {
|
||||||
let end = self.span_for_predicates_or_empty_place().shrink_to_hi();
|
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<Item = &WhereBoundPredicate<'_>> {
|
||||||
|
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<Span> {
|
||||||
|
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() {
|
||||||
|
// <T: ?Sized, U>
|
||||||
|
// ^^^^^^^^
|
||||||
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -633,12 +737,29 @@ impl<'hir> WherePredicate<'hir> {
|
||||||
WherePredicate::EqPredicate(p) => p.span,
|
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`).
|
/// A type bound (e.g., `for<'c> Foo: Send + Clone + 'c`).
|
||||||
#[derive(Debug, HashStable_Generic)]
|
#[derive(Debug, HashStable_Generic)]
|
||||||
pub struct WhereBoundPredicate<'hir> {
|
pub struct WhereBoundPredicate<'hir> {
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
pub in_where_clause: bool,
|
||||||
/// Any generics from a `for` binding.
|
/// Any generics from a `for` binding.
|
||||||
pub bound_generic_params: &'hir [GenericParam<'hir>],
|
pub bound_generic_params: &'hir [GenericParam<'hir>],
|
||||||
/// The type being bounded.
|
/// The type being bounded.
|
||||||
|
@ -650,14 +771,7 @@ pub struct WhereBoundPredicate<'hir> {
|
||||||
impl<'hir> WhereBoundPredicate<'hir> {
|
impl<'hir> WhereBoundPredicate<'hir> {
|
||||||
/// Returns `true` if `param_def_id` matches the `bounded_ty` of this predicate.
|
/// Returns `true` if `param_def_id` matches the `bounded_ty` of this predicate.
|
||||||
pub fn is_param_bound(&self, param_def_id: DefId) -> bool {
|
pub fn is_param_bound(&self, param_def_id: DefId) -> bool {
|
||||||
let TyKind::Path(QPath::Resolved(None, path)) = self.bounded_ty.kind else {
|
self.bounded_ty.as_generic_param().map_or(false, |(def_id, _)| def_id == param_def_id)
|
||||||
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,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -665,6 +779,7 @@ impl<'hir> WhereBoundPredicate<'hir> {
|
||||||
#[derive(Debug, HashStable_Generic)]
|
#[derive(Debug, HashStable_Generic)]
|
||||||
pub struct WhereRegionPredicate<'hir> {
|
pub struct WhereRegionPredicate<'hir> {
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
pub in_where_clause: bool,
|
||||||
pub lifetime: Lifetime,
|
pub lifetime: Lifetime,
|
||||||
pub bounds: GenericBounds<'hir>,
|
pub bounds: GenericBounds<'hir>,
|
||||||
}
|
}
|
||||||
|
@ -2230,6 +2345,23 @@ pub struct Ty<'hir> {
|
||||||
pub span: Span,
|
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`.
|
/// Not represented directly in the AST; referred to by name through a `ty_path`.
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, Debug)]
|
#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, Debug)]
|
||||||
#[derive(HashStable_Generic)]
|
#[derive(HashStable_Generic)]
|
||||||
|
@ -3315,7 +3447,7 @@ mod size_asserts {
|
||||||
rustc_data_structures::static_assert_size!(super::QPath<'static>, 24);
|
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::Ty<'static>, 72);
|
||||||
rustc_data_structures::static_assert_size!(super::GenericBound<'_>, 48);
|
rustc_data_structures::static_assert_size!(super::GenericBound<'_>, 48);
|
||||||
rustc_data_structures::static_assert_size!(super::Generics<'static>, 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::Impl<'static>, 80);
|
||||||
|
|
||||||
rustc_data_structures::static_assert_size!(super::Item<'static>, 80);
|
rustc_data_structures::static_assert_size!(super::Item<'static>, 80);
|
||||||
|
|
|
@ -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) {
|
pub fn walk_const_param_default<'v, V: Visitor<'v>>(visitor: &mut V, ct: &'v AnonConst) {
|
||||||
|
|
|
@ -2096,21 +2096,8 @@ impl<'a> State<'a> {
|
||||||
self.print_ident(param.name.ident());
|
self.print_ident(param.name.ident());
|
||||||
|
|
||||||
match param.kind {
|
match param.kind {
|
||||||
GenericParamKind::Lifetime { .. } => {
|
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::Type { ref default, .. } => {
|
GenericParamKind::Type { ref default, .. } => {
|
||||||
self.print_bounds(":", param.bounds);
|
|
||||||
if let Some(default) = default {
|
if let Some(default) = default {
|
||||||
self.space();
|
self.space();
|
||||||
self.word_space("=");
|
self.word_space("=");
|
||||||
|
|
|
@ -2327,6 +2327,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
_ => span,
|
_ => span,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// type_param_span is (span, has_bounds)
|
||||||
let type_param_span = match (generics, bound_kind) {
|
let type_param_span = match (generics, bound_kind) {
|
||||||
(Some((_, ref generics, _)), GenericKind::Param(ref param)) => {
|
(Some((_, ref generics, _)), GenericKind::Param(ref param)) => {
|
||||||
// Account for the case where `param` corresponds to `Self`,
|
// 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.
|
// 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`,
|
// We do this to avoid suggesting code that ends up as `T: 'a'b`,
|
||||||
// instead we suggest `T: 'a + 'b` in that case.
|
// instead we suggest `T: 'a + 'b` in that case.
|
||||||
let id = hir.local_def_id_to_hir_id(def_id);
|
let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
|
||||||
let mut has_bounds = false;
|
let ast_generics = self.tcx.hir().get_generics(hir_id.owner);
|
||||||
if let Node::GenericParam(param) = hir.get(id) {
|
let bounds =
|
||||||
has_bounds = !param.bounds.is_empty();
|
ast_generics.and_then(|g| g.bounds_span_for_suggestions(def_id));
|
||||||
}
|
|
||||||
let sp = self.tcx.def_span(def_id);
|
|
||||||
// `sp` only covers `T`, change it so that it covers
|
// `sp` only covers `T`, change it so that it covers
|
||||||
// `T:` when appropriate
|
// `T:` when appropriate
|
||||||
let is_impl_trait = bound_kind.to_string().starts_with("impl ");
|
if let Some(span) = bounds {
|
||||||
let sp = if has_bounds && !is_impl_trait {
|
(span, true)
|
||||||
sp.to(self
|
|
||||||
.tcx
|
|
||||||
.sess
|
|
||||||
.source_map()
|
|
||||||
.next_point(self.tcx.sess.source_map().next_point(sp)))
|
|
||||||
} else {
|
} else {
|
||||||
sp
|
let sp = self.tcx.def_span(def_id);
|
||||||
};
|
(sp.shrink_to_hi(), false)
|
||||||
(sp, has_bounds, is_impl_trait)
|
}
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -2411,52 +2405,37 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
|
|
||||||
fn binding_suggestion<'tcx, S: fmt::Display>(
|
fn binding_suggestion<'tcx, S: fmt::Display>(
|
||||||
err: &mut Diagnostic,
|
err: &mut Diagnostic,
|
||||||
type_param_span: Option<(Span, bool, bool)>,
|
type_param_span: Option<(Span, bool)>,
|
||||||
bound_kind: GenericKind<'tcx>,
|
bound_kind: GenericKind<'tcx>,
|
||||||
sub: S,
|
sub: S,
|
||||||
) {
|
) {
|
||||||
let msg = "consider adding an explicit lifetime bound";
|
let msg = "consider adding an explicit lifetime bound";
|
||||||
if let Some((sp, has_lifetimes, is_impl_trait)) = type_param_span {
|
if let Some((sp, has_lifetimes)) = type_param_span {
|
||||||
let suggestion = if is_impl_trait {
|
let suggestion =
|
||||||
format!("{} + {}", bound_kind, sub)
|
if has_lifetimes { format!(" + {}", sub) } else { format!(": {}", sub) };
|
||||||
} else {
|
err.span_suggestion_verbose(
|
||||||
let tail = if has_lifetimes { " + " } else { "" };
|
|
||||||
format!("{}: {}{}", bound_kind, sub, tail)
|
|
||||||
};
|
|
||||||
err.span_suggestion(
|
|
||||||
sp,
|
sp,
|
||||||
&format!("{}...", msg),
|
&format!("{}...", msg),
|
||||||
suggestion,
|
suggestion,
|
||||||
Applicability::MaybeIncorrect, // Issue #41966
|
Applicability::MaybeIncorrect, // Issue #41966
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
let consider = format!(
|
let consider = format!("{} `{}: {}`...", msg, bound_kind, sub,);
|
||||||
"{} {}...",
|
|
||||||
msg,
|
|
||||||
if type_param_span.map_or(false, |(_, _, is_impl_trait)| is_impl_trait) {
|
|
||||||
format!(" `{}` to `{}`", sub, bound_kind)
|
|
||||||
} else {
|
|
||||||
format!("`{}: {}`", bound_kind, sub)
|
|
||||||
},
|
|
||||||
);
|
|
||||||
err.help(&consider);
|
err.help(&consider);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let new_binding_suggestion =
|
let new_binding_suggestion =
|
||||||
|err: &mut Diagnostic,
|
|err: &mut Diagnostic, type_param_span: Option<(Span, bool)>| {
|
||||||
type_param_span: Option<(Span, bool, bool)>,
|
|
||||||
bound_kind: GenericKind<'tcx>| {
|
|
||||||
let msg = "consider introducing an explicit lifetime bound";
|
let msg = "consider introducing an explicit lifetime bound";
|
||||||
if let Some((sp, has_lifetimes, is_impl_trait)) = type_param_span {
|
if let Some((sp, has_lifetimes)) = type_param_span {
|
||||||
let suggestion = if is_impl_trait {
|
let suggestion = if has_lifetimes {
|
||||||
(sp.shrink_to_hi(), format!(" + {}", new_lt))
|
format!(" + {}", new_lt)
|
||||||
} else {
|
} else {
|
||||||
let tail = if has_lifetimes { " +" } else { "" };
|
format!(": {}", new_lt)
|
||||||
(sp, format!("{}: {}{}", bound_kind, new_lt, tail))
|
|
||||||
};
|
};
|
||||||
let mut sugg =
|
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 {
|
if let Some(lt) = add_lt_sugg {
|
||||||
sugg.push(lt);
|
sugg.push(lt);
|
||||||
sugg.rotate_right(1);
|
sugg.rotate_right(1);
|
||||||
|
@ -2615,7 +2594,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
// suggest:
|
// suggest:
|
||||||
// fn get_later<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a
|
// 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 => {
|
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);
|
binding_suggestion(&mut err, type_param_span, bound_kind, new_lt);
|
||||||
|
|
|
@ -1517,58 +1517,61 @@ impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds {
|
||||||
// Bounds are respected for `type X = impl Trait`
|
// Bounds are respected for `type X = impl Trait`
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let mut suggested_changing_assoc_types = false;
|
|
||||||
// There must not be a where clause
|
// There must not be a where clause
|
||||||
if !type_alias_generics.predicates.is_empty() {
|
if type_alias_generics.predicates.is_empty() {
|
||||||
cx.lint(
|
return;
|
||||||
TYPE_ALIAS_BOUNDS,
|
|
||||||
|lint| {
|
|
||||||
let mut err = lint.build("where clauses are not enforced in type aliases");
|
|
||||||
let spans: Vec<_> = type_alias_generics
|
|
||||||
.predicates
|
|
||||||
.iter()
|
|
||||||
.map(|pred| pred.span())
|
|
||||||
.collect();
|
|
||||||
err.set_span(spans);
|
|
||||||
err.span_suggestion(
|
|
||||||
type_alias_generics.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();
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
// The parameters must not have bounds
|
|
||||||
for param in type_alias_generics.params.iter() {
|
let mut where_spans = Vec::new();
|
||||||
let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect();
|
let mut inline_spans = Vec::new();
|
||||||
let suggestion = spans
|
let mut inline_sugg = Vec::new();
|
||||||
.iter()
|
for p in type_alias_generics.predicates {
|
||||||
.map(|sp| {
|
let span = p.span();
|
||||||
let start = param.span.between(*sp); // Include the `:` in `T: Bound`.
|
if p.in_where_clause() {
|
||||||
(start.to(*sp), String::new())
|
where_spans.push(span);
|
||||||
})
|
} else {
|
||||||
.collect();
|
for b in p.bounds() {
|
||||||
if !spans.is_empty() {
|
inline_spans.push(b.span());
|
||||||
cx.struct_span_lint(TYPE_ALIAS_BOUNDS, spans, |lint| {
|
}
|
||||||
let mut err =
|
inline_sugg.push((span, String::new()));
|
||||||
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 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();
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2084,27 +2087,6 @@ impl ExplicitOutlivesRequirements {
|
||||||
.collect()
|
.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<ty::Region<'tcx>> {
|
|
||||||
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>(
|
fn collect_outlives_bound_spans<'tcx>(
|
||||||
&self,
|
&self,
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
|
@ -2212,41 +2194,11 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
|
||||||
|
|
||||||
let mut bound_count = 0;
|
let mut bound_count = 0;
|
||||||
let mut lint_spans = Vec::new();
|
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 where_lint_spans = Vec::new();
|
||||||
let mut dropped_predicate_count = 0;
|
let mut dropped_predicate_count = 0;
|
||||||
let num_predicates = hir_generics.predicates.len();
|
let num_predicates = hir_generics.predicates.len();
|
||||||
for (i, where_predicate) in hir_generics.predicates.iter().enumerate() {
|
for (i, where_predicate) in hir_generics.predicates.iter().enumerate() {
|
||||||
let (relevant_lifetimes, bounds, span) = match where_predicate {
|
let (relevant_lifetimes, bounds, span, in_where_clause) = match where_predicate {
|
||||||
hir::WherePredicate::RegionPredicate(predicate) => {
|
hir::WherePredicate::RegionPredicate(predicate) => {
|
||||||
if let Some(Region::EarlyBound(index, ..)) =
|
if let Some(Region::EarlyBound(index, ..)) =
|
||||||
cx.tcx.named_region(predicate.lifetime.hir_id)
|
cx.tcx.named_region(predicate.lifetime.hir_id)
|
||||||
|
@ -2255,6 +2207,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
|
||||||
Self::lifetimes_outliving_lifetime(inferred_outlives, index),
|
Self::lifetimes_outliving_lifetime(inferred_outlives, index),
|
||||||
&predicate.bounds,
|
&predicate.bounds,
|
||||||
predicate.span,
|
predicate.span,
|
||||||
|
predicate.in_where_clause,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
continue;
|
continue;
|
||||||
|
@ -2273,6 +2226,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
|
||||||
Self::lifetimes_outliving_type(inferred_outlives, index),
|
Self::lifetimes_outliving_type(inferred_outlives, index),
|
||||||
&predicate.bounds,
|
&predicate.bounds,
|
||||||
predicate.span,
|
predicate.span,
|
||||||
|
predicate.in_where_clause,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
@ -2299,9 +2253,11 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
|
||||||
dropped_predicate_count += 1;
|
dropped_predicate_count += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If all the bounds on a predicate were inferable and there are
|
if drop_predicate && !in_where_clause {
|
||||||
// further predicates, we want to eat the trailing comma.
|
lint_spans.push(span);
|
||||||
if drop_predicate && i + 1 < num_predicates {
|
} 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();
|
let next_predicate_span = hir_generics.predicates[i + 1].span();
|
||||||
where_lint_spans.push(span.to(next_predicate_span.shrink_to_lo()));
|
where_lint_spans.push(span.to(next_predicate_span.shrink_to_lo()));
|
||||||
} else {
|
} else {
|
||||||
|
@ -2315,7 +2271,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
|
||||||
|
|
||||||
// If all predicates are inferable, drop the entire clause
|
// If all predicates are inferable, drop the entire clause
|
||||||
// (including the `where`)
|
// (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
|
let where_span = hir_generics
|
||||||
.where_clause_span()
|
.where_clause_span()
|
||||||
.expect("span of (nonempty) where clause should exist");
|
.expect("span of (nonempty) where clause should exist");
|
||||||
|
@ -2344,7 +2300,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
|
||||||
},
|
},
|
||||||
lint_spans
|
lint_spans
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|span| (span, "".to_owned()))
|
.map(|span| (span, String::new()))
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
Applicability::MachineApplicable,
|
Applicability::MachineApplicable,
|
||||||
)
|
)
|
||||||
|
|
|
@ -11,7 +11,7 @@ use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc_errors::{Applicability, Diagnostic, DiagnosticArgValue, IntoDiagnosticArg};
|
use rustc_errors::{Applicability, Diagnostic, DiagnosticArgValue, IntoDiagnosticArg};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_hir::{QPath, TyKind, WhereBoundPredicate, WherePredicate};
|
use rustc_hir::WherePredicate;
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
|
|
||||||
impl<'tcx> IntoDiagnosticArg for Ty<'tcx> {
|
impl<'tcx> IntoDiagnosticArg for Ty<'tcx> {
|
||||||
|
@ -156,10 +156,10 @@ pub fn suggest_arbitrary_trait_bound(
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
// Suggest a where clause bound for a non-type parameter.
|
// Suggest a where clause bound for a non-type parameter.
|
||||||
let (action, prefix) = if generics.predicates.is_empty() {
|
let (action, prefix) = if generics.has_where_clause {
|
||||||
("introducing a", " where ")
|
|
||||||
} else {
|
|
||||||
("extending the", ", ")
|
("extending the", ", ")
|
||||||
|
} else {
|
||||||
|
("introducing a", " where ")
|
||||||
};
|
};
|
||||||
err.span_suggestion_verbose(
|
err.span_suggestion_verbose(
|
||||||
generics.tail_span_for_predicate_suggestion(),
|
generics.tail_span_for_predicate_suggestion(),
|
||||||
|
@ -183,95 +183,37 @@ enum SuggestChangingConstraintsMessage<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn suggest_removing_unsized_bound(
|
fn suggest_removing_unsized_bound(
|
||||||
|
tcx: TyCtxt<'_>,
|
||||||
generics: &hir::Generics<'_>,
|
generics: &hir::Generics<'_>,
|
||||||
suggestions: &mut Vec<(Span, String, SuggestChangingConstraintsMessage<'_>)>,
|
suggestions: &mut Vec<(Span, String, SuggestChangingConstraintsMessage<'_>)>,
|
||||||
param_name: &str,
|
|
||||||
param: &hir::GenericParam<'_>,
|
param: &hir::GenericParam<'_>,
|
||||||
def_id: Option<DefId>,
|
def_id: Option<DefId>,
|
||||||
) {
|
) {
|
||||||
// See if there's a `?Sized` bound that can be removed to suggest that.
|
// 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`,
|
// First look at the `where` clause because we can have `where T: ?Sized`,
|
||||||
// then look at params.
|
// then look at params.
|
||||||
|
let param_def_id = tcx.hir().local_def_id(param.hir_id);
|
||||||
for (where_pos, predicate) in generics.predicates.iter().enumerate() {
|
for (where_pos, predicate) in generics.predicates.iter().enumerate() {
|
||||||
match predicate {
|
let WherePredicate::BoundPredicate(predicate) = predicate else {
|
||||||
WherePredicate::BoundPredicate(WhereBoundPredicate {
|
continue;
|
||||||
bounded_ty:
|
};
|
||||||
hir::Ty {
|
if !predicate.is_param_bound(param_def_id.to_def_id()) {
|
||||||
kind:
|
continue;
|
||||||
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.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.predicates[pos - 1].span().shrink_to_hi().to(*span)
|
|
||||||
}
|
|
||||||
// where T: ?Sized, Foo: Bar,
|
|
||||||
// ^^^^^^^^^^^
|
|
||||||
(1, _, _, pos) => span.until(generics.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()),
|
|
||||||
};
|
|
||||||
|
|
||||||
suggestions.push((
|
for (pos, bound) in predicate.bounds.iter().enumerate() {
|
||||||
sp,
|
let hir::GenericBound::Trait(poly, hir::TraitBoundModifier::Maybe) = bound else {
|
||||||
String::new(),
|
continue;
|
||||||
SuggestChangingConstraintsMessage::RemovingQSized,
|
};
|
||||||
));
|
if poly.trait_ref.trait_def_id() != def_id {
|
||||||
}
|
continue;
|
||||||
}
|
}
|
||||||
_ => {}
|
let sp = generics.span_for_bound_removal(where_pos, pos);
|
||||||
}
|
suggestions.push((
|
||||||
}
|
sp,
|
||||||
for (pos, bound) in param.bounds.iter().enumerate() {
|
String::new(),
|
||||||
match bound {
|
SuggestChangingConstraintsMessage::RemovingQSized,
|
||||||
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,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -322,13 +264,7 @@ pub fn suggest_constraining_type_params<'a>(
|
||||||
param.span,
|
param.span,
|
||||||
&format!("this type parameter needs to be `{}`", constraint),
|
&format!("this type parameter needs to be `{}`", constraint),
|
||||||
);
|
);
|
||||||
suggest_removing_unsized_bound(
|
suggest_removing_unsized_bound(tcx, generics, &mut suggestions, param, def_id);
|
||||||
generics,
|
|
||||||
&mut suggestions,
|
|
||||||
param_name,
|
|
||||||
param,
|
|
||||||
def_id,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -349,76 +285,45 @@ pub fn suggest_constraining_type_params<'a>(
|
||||||
))
|
))
|
||||||
};
|
};
|
||||||
|
|
||||||
if param_name.starts_with("impl ") {
|
// When the type parameter has been provided bounds
|
||||||
// If there's an `impl Trait` used in argument position, suggest
|
//
|
||||||
// restricting it:
|
// Message:
|
||||||
//
|
// fn foo<T>(t: T) where T: Foo { ... }
|
||||||
// fn foo(t: impl Foo) { ... }
|
// ^^^^^^
|
||||||
// --------
|
// |
|
||||||
// |
|
// help: consider further restricting this bound with `+ Bar`
|
||||||
// help: consider further restricting this bound with `+ Bar`
|
//
|
||||||
//
|
// Suggestion:
|
||||||
// Suggestion for tools in this case is:
|
// fn foo<T>(t: T) where T: Foo { ... }
|
||||||
//
|
// ^
|
||||||
// fn foo(t: impl Foo) { ... }
|
// |
|
||||||
// --------
|
// replace with: ` + Bar`
|
||||||
// |
|
//
|
||||||
// replace with: `impl Foo + Bar`
|
// Or, if user has provided some bounds, suggest restricting them:
|
||||||
|
//
|
||||||
// `impl Trait` must have at least one trait in the list
|
// fn foo<T: Foo>(t: T) { ... }
|
||||||
let bound_list_non_empty = true;
|
// ---
|
||||||
|
// |
|
||||||
suggest_restrict(param.span.shrink_to_hi(), bound_list_non_empty);
|
// help: consider further restricting this bound with `+ Bar`
|
||||||
|
//
|
||||||
|
// Suggestion for tools in this case is:
|
||||||
|
//
|
||||||
|
// fn foo<T: 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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if generics.predicates.is_empty()
|
if generics.has_where_clause {
|
||||||
// Given `trait Base<T = String>: Super<T>` where `T: Copy`, suggest restricting in the
|
|
||||||
// `where` clause instead of `trait Base<T: Copy = String>: Super<T>`.
|
|
||||||
&& !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: Foo>(t: T) { ... }
|
|
||||||
// ---
|
|
||||||
// |
|
|
||||||
// help: consider further restricting this bound with `+ Bar`
|
|
||||||
//
|
|
||||||
// Suggestion for tools in this case is:
|
|
||||||
//
|
|
||||||
// fn foo<T: 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: T) { ... }
|
|
||||||
// - help: consider restricting this type parameter with `T: Foo`
|
|
||||||
suggestions.push((
|
|
||||||
span,
|
|
||||||
format!("{colon} {constraint}"),
|
|
||||||
SuggestChangingConstraintsMessage::RestrictType { ty: param_name },
|
|
||||||
));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// This part is a bit tricky, because using the `where` clause user can
|
// 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
|
// provide zero, one or many bounds for the same type parameter, so we
|
||||||
// have following cases to consider:
|
// 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:
|
// Message:
|
||||||
// fn foo<X, Y>(x: X, y: Y) where Y: Foo { ... }
|
// fn foo<X, Y>(x: X, y: Y) where Y: Foo { ... }
|
||||||
|
@ -427,95 +332,46 @@ pub fn suggest_constraining_type_params<'a>(
|
||||||
// Suggestion:
|
// Suggestion:
|
||||||
// fn foo<X, Y>(x: X, y: Y) where Y: Foo { ... }
|
// fn foo<X, Y>(x: X, y: Y) where Y: Foo { ... }
|
||||||
// - insert: `, X: Bar`
|
// - insert: `, X: Bar`
|
||||||
//
|
suggestions.push((
|
||||||
//
|
generics.tail_span_for_predicate_suggestion(),
|
||||||
// 2) When the type parameter has been provided one bound
|
constraints
|
||||||
//
|
.iter()
|
||||||
// Message:
|
.map(|&(constraint, _)| format!(", {}: {}", param_name, constraint))
|
||||||
// fn foo<T>(t: T) where T: Foo { ... }
|
.collect::<String>(),
|
||||||
// ^^^^^^
|
SuggestChangingConstraintsMessage::RestrictTypeFurther { ty: param_name },
|
||||||
// |
|
));
|
||||||
// help: consider further restricting this bound with `+ Bar`
|
continue;
|
||||||
//
|
|
||||||
// Suggestion:
|
|
||||||
// fn foo<T>(t: T) where T: Foo { ... }
|
|
||||||
// ^^
|
|
||||||
// |
|
|
||||||
// replace with: `T: Bar +`
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// 3) When the type parameter has been provided many bounds
|
|
||||||
//
|
|
||||||
// Message:
|
|
||||||
// fn foo<T>(t: T) where T: Foo, T: Bar {... }
|
|
||||||
// - help: consider further restricting this type parameter with `where T: Zar`
|
|
||||||
//
|
|
||||||
// Suggestion:
|
|
||||||
// fn foo<T>(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<T=()> {... }
|
|
||||||
// - help: consider further restricting this type parameter with `where T: Zar`
|
|
||||||
//
|
|
||||||
// Suggestion:
|
|
||||||
// trait Foo<T=()> where T: Zar {... }
|
|
||||||
// - insert: `where T: Zar`
|
|
||||||
|
|
||||||
if matches!(param.kind, hir::GenericParamKind::Type { default: Some(_), .. })
|
|
||||||
&& generics.predicates.len() == 0
|
|
||||||
{
|
|
||||||
// Suggest a bound, but there is no existing `where` clause *and* the type param has a
|
|
||||||
// default (`<T=Foo>`), 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 },
|
|
||||||
));
|
|
||||||
} else {
|
|
||||||
let mut param_spans = Vec::new();
|
|
||||||
let mut non_empty = false;
|
|
||||||
|
|
||||||
for predicate in generics.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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
match param_spans[..] {
|
|
||||||
[¶m_span] => suggest_restrict(param_span.shrink_to_hi(), non_empty),
|
|
||||||
_ => {
|
|
||||||
suggestions.push((
|
|
||||||
generics.tail_span_for_predicate_suggestion(),
|
|
||||||
constraints
|
|
||||||
.iter()
|
|
||||||
.map(|&(constraint, _)| format!(", {}: {}", param_name, constraint))
|
|
||||||
.collect::<String>(),
|
|
||||||
SuggestChangingConstraintsMessage::RestrictTypeFurther {
|
|
||||||
ty: param_name,
|
|
||||||
},
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Additionally, there may be no `where` clause but the generic parameter has a default:
|
||||||
|
//
|
||||||
|
// Message:
|
||||||
|
// trait Foo<T=()> {... }
|
||||||
|
// - help: consider further restricting this type parameter with `where T: Zar`
|
||||||
|
//
|
||||||
|
// Suggestion:
|
||||||
|
// trait Foo<T=()> {... }
|
||||||
|
// - 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 (`<T=Foo>`), 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 hasn't provided any bounds, suggest adding a new one:
|
||||||
|
//
|
||||||
|
// fn foo<T>(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 {
|
if suggestions.len() == 1 {
|
||||||
|
|
|
@ -602,53 +602,24 @@ impl<T> Trait<T> for X {
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
let Some(def_id) = def_id.as_local() else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
// First look in the `where` clause, as this might be
|
// First look in the `where` clause, as this might be
|
||||||
// `fn foo<T>(x: T) where T: Trait`.
|
// `fn foo<T>(x: T) where T: Trait`.
|
||||||
for predicate in hir_generics.predicates {
|
for pred in hir_generics.bounds_for_param(def_id) {
|
||||||
if let hir::WherePredicate::BoundPredicate(pred) = predicate {
|
if self.constrain_generic_bound_associated_type_structured_suggestion(
|
||||||
if let hir::TyKind::Path(hir::QPath::Resolved(None, path)) =
|
diag,
|
||||||
pred.bounded_ty.kind
|
&trait_ref,
|
||||||
{
|
pred.bounds,
|
||||||
if path.res.opt_def_id() == Some(def_id) {
|
&assoc,
|
||||||
// This predicate is binding type param `A` in `<A as T>::Foo` to
|
assoc_substs,
|
||||||
// something, potentially `T`.
|
ty,
|
||||||
} else {
|
msg,
|
||||||
continue;
|
false,
|
||||||
}
|
) {
|
||||||
} else {
|
return true;
|
||||||
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 `<A as T>::Foo`.
|
|
||||||
return self.constrain_generic_bound_associated_type_structured_suggestion(
|
|
||||||
diag,
|
|
||||||
&trait_ref,
|
|
||||||
param.bounds,
|
|
||||||
&assoc,
|
|
||||||
assoc_substs,
|
|
||||||
ty,
|
|
||||||
msg,
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1585,11 +1585,6 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_generics(&mut self, generics: &'tcx hir::Generics<'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.predicates {
|
for predicate in generics.predicates {
|
||||||
match predicate {
|
match predicate {
|
||||||
hir::WherePredicate::BoundPredicate(bound_pred) => {
|
hir::WherePredicate::BoundPredicate(bound_pred) => {
|
||||||
|
|
|
@ -1328,13 +1328,11 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
||||||
match param.kind {
|
match param.kind {
|
||||||
GenericParamKind::Lifetime { .. } => {}
|
GenericParamKind::Lifetime { .. } => {}
|
||||||
GenericParamKind::Type { ref default, .. } => {
|
GenericParamKind::Type { ref default, .. } => {
|
||||||
walk_list!(this, visit_param_bound, param.bounds);
|
|
||||||
if let Some(ref ty) = default {
|
if let Some(ref ty) = default {
|
||||||
this.visit_ty(&ty);
|
this.visit_ty(&ty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GenericParamKind::Const { ref ty, default } => {
|
GenericParamKind::Const { ref ty, default } => {
|
||||||
walk_list!(this, visit_param_bound, param.bounds);
|
|
||||||
this.visit_ty(&ty);
|
this.visit_ty(&ty);
|
||||||
if let Some(default) = default {
|
if let Some(default) = default {
|
||||||
this.visit_body(this.tcx.hir().body(default.body));
|
this.visit_body(this.tcx.hir().body(default.body));
|
||||||
|
@ -1393,6 +1391,32 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
|
||||||
}) => {
|
}) => {
|
||||||
this.visit_lifetime(lifetime);
|
this.visit_lifetime(lifetime);
|
||||||
walk_list!(this, visit_param_bound, bounds);
|
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 {
|
&hir::WherePredicate::EqPredicate(hir::WhereEqPredicate {
|
||||||
ref lhs_ty,
|
ref lhs_ty,
|
||||||
|
@ -1714,8 +1738,6 @@ fn object_lifetime_defaults_for_item<'tcx>(
|
||||||
GenericParamKind::Type { .. } => {
|
GenericParamKind::Type { .. } => {
|
||||||
let mut set = Set1::Empty;
|
let mut set = Set1::Empty;
|
||||||
|
|
||||||
add_bounds(&mut set, ¶m.bounds);
|
|
||||||
|
|
||||||
let param_def_id = tcx.hir().local_def_id(param.hir_id);
|
let param_def_id = tcx.hir().local_def_id(param.hir_id);
|
||||||
for predicate in generics.predicates {
|
for predicate in generics.predicates {
|
||||||
// Look for `type: ...` where clauses.
|
// Look for `type: ...` where clauses.
|
||||||
|
@ -3124,50 +3146,6 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
||||||
|
|
||||||
// It is a soft error to shadow a lifetime within a parent scope.
|
// It is a soft error to shadow a lifetime within a parent scope.
|
||||||
self.check_lifetime_param_for_shadowing(old_scope, &lifetime_i);
|
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.
|
// ignore binders here and scrape up all names we see.
|
||||||
let mut appears_in_where_clause = AllCollector::default();
|
let mut appears_in_where_clause = AllCollector::default();
|
||||||
appears_in_where_clause.visit_generics(generics);
|
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);
|
debug!(?appears_in_where_clause.regions);
|
||||||
|
|
||||||
// Late bound regions are those that:
|
// Late bound regions are those that:
|
||||||
|
|
|
@ -1267,13 +1267,11 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> {
|
||||||
match param.kind {
|
match param.kind {
|
||||||
hir::GenericParamKind::Lifetime { .. } => {}
|
hir::GenericParamKind::Lifetime { .. } => {}
|
||||||
hir::GenericParamKind::Type { ref default, .. } => {
|
hir::GenericParamKind::Type { ref default, .. } => {
|
||||||
self.process_bounds(param.bounds);
|
|
||||||
if let Some(ref ty) = default {
|
if let Some(ref ty) = default {
|
||||||
self.visit_ty(ty);
|
self.visit_ty(ty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hir::GenericParamKind::Const { ref ty, ref default } => {
|
hir::GenericParamKind::Const { ref ty, ref default } => {
|
||||||
self.process_bounds(param.bounds);
|
|
||||||
self.visit_ty(ty);
|
self.visit_ty(ty);
|
||||||
if let Some(default) = default {
|
if let Some(default) = default {
|
||||||
self.visit_anon_const(default);
|
self.visit_anon_const(default);
|
||||||
|
|
|
@ -630,31 +630,6 @@ impl<'hir> Sig for hir::Generics<'hir> {
|
||||||
param_text.push_str(&id_to_string(&scx.tcx.hir(), default.hir_id));
|
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::<Vec<_>>()
|
|
||||||
.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_str(¶m_text);
|
||||||
text.push(',');
|
text.push(',');
|
||||||
}
|
}
|
||||||
|
|
|
@ -2420,25 +2420,14 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
|
||||||
let sized_trait = self.tcx.lang_items().sized_trait();
|
let sized_trait = self.tcx.lang_items().sized_trait();
|
||||||
debug!("maybe_suggest_unsized_generics: generics.params={:?}", generics.params);
|
debug!("maybe_suggest_unsized_generics: generics.params={:?}", generics.params);
|
||||||
debug!("maybe_suggest_unsized_generics: generics.predicates={:?}", generics.predicates);
|
debug!("maybe_suggest_unsized_generics: generics.predicates={:?}", generics.predicates);
|
||||||
let param = generics.params.iter().filter(|param| param.span == span).find(|param| {
|
let Some(param) = generics.params.iter().find(|param| param.span == span) else {
|
||||||
// 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 {
|
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let param_def_id = self.tcx.hir().local_def_id(param.hir_id).to_def_id();
|
let param_def_id = self.tcx.hir().local_def_id(param.hir_id);
|
||||||
let preds = generics.predicates.iter();
|
// Check that none of the explicit trait bounds is `Sized`. Assume that an explicit
|
||||||
let explicitly_sized = preds
|
// `Sized` bound is there intentionally and we don't need to suggest relaxing it.
|
||||||
.filter_map(|pred| match pred {
|
let explicitly_sized = generics
|
||||||
hir::WherePredicate::BoundPredicate(bp) => Some(bp),
|
.bounds_for_param(param_def_id)
|
||||||
_ => None,
|
|
||||||
})
|
|
||||||
.filter(|bp| bp.is_param_bound(param_def_id))
|
|
||||||
.flat_map(|bp| bp.bounds)
|
.flat_map(|bp| bp.bounds)
|
||||||
.any(|bound| bound.trait_ref().and_then(|tr| tr.trait_def_id()) == sized_trait);
|
.any(|bound| bound.trait_ref().and_then(|tr| tr.trait_def_id()) == sized_trait);
|
||||||
if explicitly_sized {
|
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`.
|
// Didn't add an indirection suggestion, so add a general suggestion to relax `Sized`.
|
||||||
let (span, separator) = match param.bounds {
|
let (span, separator) = if let Some(s) = generics.bounds_span_for_suggestions(param_def_id)
|
||||||
[] => (span.shrink_to_hi(), ":"),
|
{
|
||||||
[.., bound] => (bound.span().shrink_to_hi(), " +"),
|
(s, " +")
|
||||||
|
} else {
|
||||||
|
(span.shrink_to_hi(), ":")
|
||||||
};
|
};
|
||||||
err.span_suggestion_verbose(
|
err.span_suggestion_verbose(
|
||||||
span,
|
span,
|
||||||
|
|
|
@ -320,7 +320,7 @@ pub trait InferCtxtExt<'tcx> {
|
||||||
fn predicate_constraint(generics: &hir::Generics<'_>, pred: String) -> (Span, String) {
|
fn predicate_constraint(generics: &hir::Generics<'_>, pred: String) -> (Span, String) {
|
||||||
(
|
(
|
||||||
generics.tail_span_for_predicate_suggestion(),
|
generics.tail_span_for_predicate_suggestion(),
|
||||||
format!("{} {}", if !generics.predicates.is_empty() { "," } else { " where" }, pred,),
|
format!("{} {}", if generics.has_where_clause { "," } else { " where" }, pred,),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -392,21 +392,10 @@ fn suggest_restriction<'tcx>(
|
||||||
let pred = trait_pred.to_predicate(tcx).to_string();
|
let pred = trait_pred.to_predicate(tcx).to_string();
|
||||||
let pred = pred.replace(&impl_trait_str, &type_param_name);
|
let pred = pred.replace(&impl_trait_str, &type_param_name);
|
||||||
let mut sugg = vec![
|
let mut sugg = vec![
|
||||||
// Find the last of the generic parameters contained within the span of
|
if let Some(span) = generics.span_for_param_suggestion() {
|
||||||
// the generics
|
(span, format!(", {}", type_param))
|
||||||
match generics
|
} else {
|
||||||
.params
|
(generics.span, format!("<{}>", type_param))
|
||||||
.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 `<T: Trait>` here
|
|
||||||
None => (generics.span, format!("<{}>", type_param)),
|
|
||||||
// `fn foo<A>(t: impl Trait)`
|
|
||||||
// ^^^ suggest `<A, T: Trait>` here
|
|
||||||
Some(span) => (span, format!(", {}", type_param)),
|
|
||||||
},
|
},
|
||||||
// `fn foo(t: impl Trait)`
|
// `fn foo(t: impl Trait)`
|
||||||
// ^ suggest `where <T as Trait>::A: Bound`
|
// ^ suggest `where <T as Trait>::A: Bound`
|
||||||
|
|
|
@ -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();
|
let self_ty_def_id = tcx.hir().local_def_id(self_ty).to_def_id();
|
||||||
for clause in where_clause {
|
for clause in where_clause {
|
||||||
if let hir::WherePredicate::BoundPredicate(pred) = clause {
|
if let hir::WherePredicate::BoundPredicate(pred) = clause {
|
||||||
match pred.bounded_ty.kind {
|
if pred.is_param_bound(self_ty_def_id) {
|
||||||
hir::TyKind::Path(hir::QPath::Resolved(_, path)) => match path.res {
|
search_bounds(pred.bounds);
|
||||||
Res::Def(DefKind::TyParam, def_id) if def_id == self_ty_def_id => {}
|
|
||||||
_ => continue,
|
|
||||||
},
|
|
||||||
_ => continue,
|
|
||||||
}
|
}
|
||||||
search_bounds(pred.bounds);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2389,7 +2384,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||||
bf.unsafety,
|
bf.unsafety,
|
||||||
bf.abi,
|
bf.abi,
|
||||||
bf.decl,
|
bf.decl,
|
||||||
&hir::Generics::empty(),
|
|
||||||
None,
|
None,
|
||||||
Some(ast_ty),
|
Some(ast_ty),
|
||||||
))
|
))
|
||||||
|
@ -2551,8 +2545,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||||
unsafety: hir::Unsafety,
|
unsafety: hir::Unsafety,
|
||||||
abi: abi::Abi,
|
abi: abi::Abi,
|
||||||
decl: &hir::FnDecl<'_>,
|
decl: &hir::FnDecl<'_>,
|
||||||
generics: &hir::Generics<'_>,
|
generics: Option<&hir::Generics<'_>>,
|
||||||
ident_span: Option<Span>,
|
|
||||||
hir_ty: Option<&hir::Ty<'_>>,
|
hir_ty: Option<&hir::Ty<'_>>,
|
||||||
) -> ty::PolyFnSig<'tcx> {
|
) -> ty::PolyFnSig<'tcx> {
|
||||||
debug!("ty_of_fn");
|
debug!("ty_of_fn");
|
||||||
|
@ -2565,7 +2558,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||||
let mut visitor = HirPlaceholderCollector::default();
|
let mut visitor = HirPlaceholderCollector::default();
|
||||||
let mut infer_replacements = vec![];
|
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
|
let input_tys: Vec<_> = decl
|
||||||
.inputs
|
.inputs
|
||||||
|
@ -2617,8 +2612,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||||
|
|
||||||
let mut diag = crate::collect::placeholder_type_error_diag(
|
let mut diag = crate::collect::placeholder_type_error_diag(
|
||||||
tcx,
|
tcx,
|
||||||
ident_span.map(|sp| sp.shrink_to_hi()),
|
generics,
|
||||||
generics.params,
|
|
||||||
visitor.0,
|
visitor.0,
|
||||||
infer_replacements.iter().map(|(s, _)| *s).collect(),
|
infer_replacements.iter().map(|(s, _)| *s).collect(),
|
||||||
true,
|
true,
|
||||||
|
|
|
@ -804,7 +804,8 @@ fn compare_synthetic_generics<'tcx>(
|
||||||
iter::zip(impl_m_type_params, trait_m_type_params)
|
iter::zip(impl_m_type_params, trait_m_type_params)
|
||||||
{
|
{
|
||||||
if impl_synthetic != trait_synthetic {
|
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 impl_span = tcx.hir().span(impl_hir_id);
|
||||||
let trait_span = tcx.def_span(trait_def_id);
|
let trait_span = tcx.def_span(trait_def_id);
|
||||||
let mut err = struct_span_err!(
|
let mut err = struct_span_err!(
|
||||||
|
@ -868,14 +869,14 @@ fn compare_synthetic_generics<'tcx>(
|
||||||
hir::ImplItemKind::Fn(ref sig, _) => sig.decl.inputs,
|
hir::ImplItemKind::Fn(ref sig, _) => sig.decl.inputs,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
struct Visitor(Option<Span>, hir::def_id::DefId);
|
struct Visitor(Option<Span>, hir::def_id::LocalDefId);
|
||||||
impl<'v> intravisit::Visitor<'v> for Visitor {
|
impl<'v> intravisit::Visitor<'v> for Visitor {
|
||||||
fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
|
fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
|
||||||
intravisit::walk_ty(self, ty);
|
intravisit::walk_ty(self, ty);
|
||||||
if let hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) =
|
if let hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) =
|
||||||
ty.kind
|
ty.kind
|
||||||
&& let Res::Def(DefKind::TyParam, def_id) = path.res
|
&& 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);
|
self.0 = Some(ty.span);
|
||||||
}
|
}
|
||||||
|
@ -887,17 +888,7 @@ fn compare_synthetic_generics<'tcx>(
|
||||||
}
|
}
|
||||||
let span = visitor.0?;
|
let span = visitor.0?;
|
||||||
|
|
||||||
let bounds =
|
let bounds = impl_m.generics.bounds_for_param(impl_def_id).next()?.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 = bounds.first()?.span().to(bounds.last()?.span());
|
let bounds = bounds.first()?.span().to(bounds.last()?.span());
|
||||||
let bounds = tcx.sess.source_map().span_to_snippet(bounds).ok()?;
|
let bounds = tcx.sess.source_map().span_to_snippet(bounds).ok()?;
|
||||||
|
|
||||||
|
|
|
@ -605,7 +605,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
..
|
..
|
||||||
})) = fn_node else { return };
|
})) = 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
|
// get all where BoundPredicates here, because they are used in to cases below
|
||||||
let where_predicates = predicates
|
let where_predicates = predicates
|
||||||
|
@ -639,10 +641,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
where_predicates.iter().flatten().flat_map(|bounds| bounds.iter());
|
where_predicates.iter().flatten().flat_map(|bounds| bounds.iter());
|
||||||
|
|
||||||
// extract all bounds from the source code using their spans
|
// extract all bounds from the source code using their spans
|
||||||
let all_matching_bounds_strs = expected_generic_param
|
let all_matching_bounds_strs = predicates_from_where
|
||||||
.bounds
|
|
||||||
.iter()
|
|
||||||
.chain(predicates_from_where)
|
|
||||||
.filter_map(|bound| match bound {
|
.filter_map(|bound| match bound {
|
||||||
GenericBound::Trait(_, _) => {
|
GenericBound::Trait(_, _) => {
|
||||||
self.tcx.sess.source_map().span_to_snippet(bound.span()).ok()
|
self.tcx.sess.source_map().span_to_snippet(bound.span()).ok()
|
||||||
|
|
|
@ -1868,37 +1868,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
// instead we suggest `T: Foo + Bar` in that case.
|
// instead we suggest `T: Foo + Bar` in that case.
|
||||||
match hir.get(id) {
|
match hir.get(id) {
|
||||||
Node::GenericParam(param) => {
|
Node::GenericParam(param) => {
|
||||||
let mut impl_trait = false;
|
let impl_trait = matches!(
|
||||||
let has_bounds =
|
param.kind,
|
||||||
if let hir::GenericParamKind::Type { synthetic: true, .. } =
|
hir::GenericParamKind::Type { synthetic: true, .. },
|
||||||
¶m.kind
|
);
|
||||||
{
|
let ast_generics = hir.get_generics(id.owner).unwrap();
|
||||||
// We've found `fn foo(x: impl Trait)` instead of
|
let (sp, has_bounds) = if let Some(span) =
|
||||||
// `fn foo<T>(x: T)`. We want to suggest the correct
|
ast_generics.bounds_span_for_suggestions(def_id)
|
||||||
// `fn foo(x: impl Trait + TraitBound)` instead of
|
|
||||||
// `fn foo<T: TraitBound>(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: T) { ... }
|
|
||||||
param.colon_span_for_suggestions(
|
|
||||||
self.inh.tcx.sess.source_map(),
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
sp.to(colon_sp)
|
(span, true)
|
||||||
} else {
|
} else {
|
||||||
sp
|
(hir.span(id).shrink_to_hi(), false)
|
||||||
};
|
};
|
||||||
let trait_def_ids: FxHashSet<DefId> = param
|
let trait_def_ids: FxHashSet<DefId> = ast_generics
|
||||||
.bounds
|
.bounds_for_param(def_id)
|
||||||
.iter()
|
.flat_map(|bp| bp.bounds.iter())
|
||||||
.filter_map(|bound| bound.trait_ref()?.trait_def_id())
|
.filter_map(|bound| bound.trait_ref()?.trait_def_id())
|
||||||
.collect();
|
.collect();
|
||||||
if !candidates.iter().any(|t| trait_def_ids.contains(&t.def_id)) {
|
if !candidates.iter().any(|t| trait_def_ids.contains(&t.def_id)) {
|
||||||
|
@ -1910,11 +1894,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
)),
|
)),
|
||||||
candidates.iter().map(|t| {
|
candidates.iter().map(|t| {
|
||||||
format!(
|
format!(
|
||||||
"{}{} {}{}",
|
"{} {}",
|
||||||
param.name.ident(),
|
if has_bounds || impl_trait { " +" } else { ":" },
|
||||||
if impl_trait { " +" } else { ":" },
|
|
||||||
self.tcx.def_path_str(t.def_id),
|
self.tcx.def_path_str(t.def_id),
|
||||||
if has_bounds.is_some() { " + " } else { "" },
|
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
Applicability::MaybeIncorrect,
|
Applicability::MaybeIncorrect,
|
||||||
|
|
|
@ -373,16 +373,7 @@ fn typeck_with_fallback<'tcx>(
|
||||||
let (fcx, wf_tys) = if let Some(hir::FnSig { header, decl, .. }) = fn_sig {
|
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 fn_sig = if crate::collect::get_infer_ret_ty(&decl.output).is_some() {
|
||||||
let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
|
let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
|
||||||
<dyn AstConv<'_>>::ty_of_fn(
|
<dyn AstConv<'_>>::ty_of_fn(&fcx, id, header.unsafety, header.abi, decl, None, None)
|
||||||
&fcx,
|
|
||||||
id,
|
|
||||||
header.unsafety,
|
|
||||||
header.abi,
|
|
||||||
decl,
|
|
||||||
&hir::Generics::empty(),
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
tcx.fn_sig(def_id)
|
tcx.fn_sig(def_id)
|
||||||
};
|
};
|
||||||
|
|
|
@ -1755,8 +1755,7 @@ fn check_variances_for_type_defn<'tcx>(
|
||||||
match param.name {
|
match param.name {
|
||||||
hir::ParamName::Error => {}
|
hir::ParamName::Error => {}
|
||||||
_ => {
|
_ => {
|
||||||
let has_explicit_bounds =
|
let has_explicit_bounds = explicitly_bounded_params.contains(¶meter);
|
||||||
!param.bounds.is_empty() || explicitly_bounded_params.contains(¶meter);
|
|
||||||
report_bivariance(tcx, param, has_explicit_bounds);
|
report_bivariance(tcx, param, has_explicit_bounds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
// ignore-tidy-filelength
|
|
||||||
//! "Collection" is the process of determining the type and other external
|
//! "Collection" is the process of determining the type and other external
|
||||||
//! details of each item in Rust. Collection is specifically concerned
|
//! details of each item in Rust. Collection is specifically concerned
|
||||||
//! with *inter-procedural* things -- for example, for a function
|
//! 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.
|
/// all already existing generic type parameters to avoid suggesting a name that is already in use.
|
||||||
crate fn placeholder_type_error<'tcx>(
|
crate fn placeholder_type_error<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
span: Option<Span>,
|
generics: Option<&hir::Generics<'_>>,
|
||||||
generics: &[hir::GenericParam<'_>],
|
|
||||||
placeholder_types: Vec<Span>,
|
placeholder_types: Vec<Span>,
|
||||||
suggest: bool,
|
suggest: bool,
|
||||||
hir_ty: Option<&hir::Ty<'_>>,
|
hir_ty: Option<&hir::Ty<'_>>,
|
||||||
|
@ -160,23 +158,13 @@ crate fn placeholder_type_error<'tcx>(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
placeholder_type_error_diag(
|
placeholder_type_error_diag(tcx, generics, placeholder_types, vec![], suggest, hir_ty, kind)
|
||||||
tcx,
|
.emit();
|
||||||
span,
|
|
||||||
generics,
|
|
||||||
placeholder_types,
|
|
||||||
vec![],
|
|
||||||
suggest,
|
|
||||||
hir_ty,
|
|
||||||
kind,
|
|
||||||
)
|
|
||||||
.emit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
crate fn placeholder_type_error_diag<'tcx>(
|
crate fn placeholder_type_error_diag<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
span: Option<Span>,
|
generics: Option<&hir::Generics<'_>>,
|
||||||
generics: &[hir::GenericParam<'_>],
|
|
||||||
placeholder_types: Vec<Span>,
|
placeholder_types: Vec<Span>,
|
||||||
additional_spans: Vec<Span>,
|
additional_spans: Vec<Span>,
|
||||||
suggest: bool,
|
suggest: bool,
|
||||||
|
@ -187,26 +175,24 @@ crate fn placeholder_type_error_diag<'tcx>(
|
||||||
return bad_placeholder(tcx, additional_spans, kind);
|
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<_> =
|
let mut sugg: Vec<_> =
|
||||||
placeholder_types.iter().map(|sp| (*sp, (*type_name).to_string())).collect();
|
placeholder_types.iter().map(|sp| (*sp, (*type_name).to_string())).collect();
|
||||||
|
|
||||||
if generics.is_empty() {
|
if let Some(generics) = generics {
|
||||||
if let Some(span) = span {
|
if let Some(arg) = params.iter().find(|arg| {
|
||||||
sugg.push((span, format!("<{}>", type_name)));
|
matches!(arg.name, hir::ParamName::Plain(Ident { name: kw::Underscore, .. }))
|
||||||
|
}) {
|
||||||
|
// Account for `_` already present in cases like `struct S<_>(_);` and suggest
|
||||||
|
// `struct S<T>(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<T: E, K>(_: K)` not `fn foo<T, K: E>(_: 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>(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<T: E, K>(_: K)` not `fn foo<T, K: E>(_: K)`.
|
|
||||||
let span = last.bounds_span_for_suggestions().unwrap_or(last.span.shrink_to_hi());
|
|
||||||
sugg.push((span, format!(", {}", type_name)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut err =
|
let mut err =
|
||||||
|
@ -270,15 +256,7 @@ fn reject_placeholder_type_signatures_in_item<'tcx>(
|
||||||
let mut visitor = HirPlaceholderCollector::default();
|
let mut visitor = HirPlaceholderCollector::default();
|
||||||
visitor.visit_item(item);
|
visitor.visit_item(item);
|
||||||
|
|
||||||
placeholder_type_error(
|
placeholder_type_error(tcx, Some(generics), visitor.0, suggest, None, item.kind.descr());
|
||||||
tcx,
|
|
||||||
Some(generics.span),
|
|
||||||
generics.params,
|
|
||||||
visitor.0,
|
|
||||||
suggest,
|
|
||||||
None,
|
|
||||||
item.kind.descr(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> {
|
impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> {
|
||||||
|
@ -680,26 +658,8 @@ impl<'tcx> ItemCtxt<'tcx> {
|
||||||
only_self_bounds: OnlySelfBounds,
|
only_self_bounds: OnlySelfBounds,
|
||||||
assoc_name: Option<Ident>,
|
assoc_name: Option<Ident>,
|
||||||
) -> Vec<(ty::Predicate<'tcx>, Span)> {
|
) -> 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 param_def_id = self.tcx.hir().local_def_id(param_id).to_def_id();
|
||||||
let from_where_clauses = ast_generics
|
ast_generics
|
||||||
.predicates
|
.predicates
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|wp| match *wp {
|
.filter_map(|wp| match *wp {
|
||||||
|
@ -724,9 +684,8 @@ impl<'tcx> ItemCtxt<'tcx> {
|
||||||
})
|
})
|
||||||
.filter_map(move |b| bt.map(|bt| (bt, b, bvars)))
|
.filter_map(move |b| bt.map(|bt| (bt, b, bvars)))
|
||||||
})
|
})
|
||||||
.flat_map(|(bt, b, bvars)| predicates_from_bound(self, bt, b, bvars));
|
.flat_map(|(bt, b, bvars)| predicates_from_bound(self, bt, b, bvars))
|
||||||
|
.collect()
|
||||||
from_ty_params.chain(from_where_clauses).collect()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bound_defines_assoc_item(&self, b: &hir::GenericBound<'_>, assoc_name: Ident) -> bool {
|
fn bound_defines_assoc_item(&self, b: &hir::GenericBound<'_>, assoc_name: Ident) -> bool {
|
||||||
|
@ -772,7 +731,6 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
|
||||||
placeholder_type_error(
|
placeholder_type_error(
|
||||||
tcx,
|
tcx,
|
||||||
None,
|
None,
|
||||||
&[],
|
|
||||||
visitor.0,
|
visitor.0,
|
||||||
false,
|
false,
|
||||||
None,
|
None,
|
||||||
|
@ -852,15 +810,7 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
|
||||||
if let hir::TyKind::TraitObject(..) = ty.kind {
|
if let hir::TyKind::TraitObject(..) = ty.kind {
|
||||||
let mut visitor = HirPlaceholderCollector::default();
|
let mut visitor = HirPlaceholderCollector::default();
|
||||||
visitor.visit_item(it);
|
visitor.visit_item(it);
|
||||||
placeholder_type_error(
|
placeholder_type_error(tcx, None, visitor.0, false, None, it.kind.descr());
|
||||||
tcx,
|
|
||||||
None,
|
|
||||||
&[],
|
|
||||||
visitor.0,
|
|
||||||
false,
|
|
||||||
None,
|
|
||||||
it.kind.descr(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
|
@ -888,7 +838,7 @@ fn convert_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
|
||||||
// Account for `const C: _;`.
|
// Account for `const C: _;`.
|
||||||
let mut visitor = HirPlaceholderCollector::default();
|
let mut visitor = HirPlaceholderCollector::default();
|
||||||
visitor.visit_trait_item(trait_item);
|
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(_)) => {
|
hir::TraitItemKind::Type(_, Some(_)) => {
|
||||||
|
@ -897,7 +847,7 @@ fn convert_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
|
||||||
// Account for `type T = _;`.
|
// Account for `type T = _;`.
|
||||||
let mut visitor = HirPlaceholderCollector::default();
|
let mut visitor = HirPlaceholderCollector::default();
|
||||||
visitor.visit_trait_item(trait_item);
|
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) => {
|
hir::TraitItemKind::Type(_, None) => {
|
||||||
|
@ -907,7 +857,7 @@ fn convert_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
|
||||||
let mut visitor = HirPlaceholderCollector::default();
|
let mut visitor = HirPlaceholderCollector::default();
|
||||||
visitor.visit_trait_item(trait_item);
|
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");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -929,7 +879,7 @@ fn convert_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::ImplItemId) {
|
||||||
let mut visitor = HirPlaceholderCollector::default();
|
let mut visitor = HirPlaceholderCollector::default();
|
||||||
visitor.visit_impl_item(impl_item);
|
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(..) => {}
|
hir::ImplItemKind::Const(..) => {}
|
||||||
}
|
}
|
||||||
|
@ -1892,15 +1842,14 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> {
|
||||||
match tcx.hir().get(hir_id) {
|
match tcx.hir().get(hir_id) {
|
||||||
TraitItem(hir::TraitItem {
|
TraitItem(hir::TraitItem {
|
||||||
kind: TraitItemKind::Fn(sig, TraitFn::Provided(_)),
|
kind: TraitItemKind::Fn(sig, TraitFn::Provided(_)),
|
||||||
ident,
|
|
||||||
generics,
|
generics,
|
||||||
..
|
..
|
||||||
})
|
})
|
||||||
| Item(hir::Item { kind: ItemKind::Fn(sig, generics, _), ident, .. }) => {
|
| Item(hir::Item { kind: ItemKind::Fn(sig, generics, _), .. }) => {
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
// 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), .. }) =
|
if let Item(hir::Item { kind: ItemKind::Impl(i), .. }) =
|
||||||
tcx.hir().get(tcx.hir().get_parent_node(hir_id))
|
tcx.hir().get(tcx.hir().get_parent_node(hir_id))
|
||||||
|
@ -1912,18 +1861,16 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> {
|
||||||
sig.header.unsafety,
|
sig.header.unsafety,
|
||||||
sig.header.abi,
|
sig.header.abi,
|
||||||
sig.decl,
|
sig.decl,
|
||||||
generics,
|
Some(generics),
|
||||||
Some(ident.span),
|
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
} else {
|
} 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 {
|
TraitItem(hir::TraitItem {
|
||||||
kind: TraitItemKind::Fn(FnSig { header, decl, span: _ }, _),
|
kind: TraitItemKind::Fn(FnSig { header, decl, span: _ }, _),
|
||||||
ident,
|
|
||||||
generics,
|
generics,
|
||||||
..
|
..
|
||||||
}) => <dyn AstConv<'_>>::ty_of_fn(
|
}) => <dyn AstConv<'_>>::ty_of_fn(
|
||||||
|
@ -1932,16 +1879,13 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> {
|
||||||
header.unsafety,
|
header.unsafety,
|
||||||
header.abi,
|
header.abi,
|
||||||
decl,
|
decl,
|
||||||
generics,
|
Some(generics),
|
||||||
Some(ident.span),
|
|
||||||
None,
|
None,
|
||||||
),
|
),
|
||||||
|
|
||||||
ForeignItem(&hir::ForeignItem {
|
ForeignItem(&hir::ForeignItem { kind: ForeignItemKind::Fn(fn_decl, _, _), .. }) => {
|
||||||
kind: ForeignItemKind::Fn(fn_decl, _, _), ident, ..
|
|
||||||
}) => {
|
|
||||||
let abi = tcx.hir().get_foreign_abi(hir_id);
|
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() => {
|
Ctor(data) | Variant(hir::Variant { data, .. }) if data.ctor_hir_id().is_some() => {
|
||||||
|
@ -1982,7 +1926,6 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> {
|
||||||
fn infer_return_ty_for_fn_sig<'tcx>(
|
fn infer_return_ty_for_fn_sig<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
sig: &hir::FnSig<'_>,
|
sig: &hir::FnSig<'_>,
|
||||||
ident: Ident,
|
|
||||||
generics: &hir::Generics<'_>,
|
generics: &hir::Generics<'_>,
|
||||||
def_id: LocalDefId,
|
def_id: LocalDefId,
|
||||||
icx: &ItemCtxt<'tcx>,
|
icx: &ItemCtxt<'tcx>,
|
||||||
|
@ -2037,8 +1980,7 @@ fn infer_return_ty_for_fn_sig<'tcx>(
|
||||||
sig.header.unsafety,
|
sig.header.unsafety,
|
||||||
sig.header.abi,
|
sig.header.abi,
|
||||||
sig.decl,
|
sig.decl,
|
||||||
generics,
|
Some(generics),
|
||||||
Some(ident.span),
|
|
||||||
None,
|
None,
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
@ -2301,29 +2243,9 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
|
||||||
// Collect the region predicates that were declared inline as
|
// Collect the region predicates that were declared inline as
|
||||||
// well. In the case of parameters declared on a fn or method, we
|
// well. In the case of parameters declared on a fn or method, we
|
||||||
// have to be careful to only iterate over early-bound regions.
|
// have to be careful to only iterate over early-bound regions.
|
||||||
let mut index = parent_count + has_own_self as u32;
|
let mut index = parent_count
|
||||||
for param in early_bound_lifetimes_from_generics(tcx, hir_id.owner, ast_generics) {
|
+ has_own_self as u32
|
||||||
let region = tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion {
|
+ early_bound_lifetimes_from_generics(tcx, hir_id.owner, ast_generics).count() as u32;
|
||||||
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 = <dyn AstConv<'_>>::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!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Collect the predicates that were written inline by the user on each
|
// Collect the predicates that were written inline by the user on each
|
||||||
// type parameter (e.g., `<T: Foo>`).
|
// type parameter (e.g., `<T: Foo>`).
|
||||||
|
@ -2336,12 +2258,12 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
|
||||||
let param_ty = ty::ParamTy::new(index, name).to_ty(tcx);
|
let param_ty = ty::ParamTy::new(index, name).to_ty(tcx);
|
||||||
index += 1;
|
index += 1;
|
||||||
|
|
||||||
let mut bounds = <dyn AstConv<'_>>::compute_bounds(&icx, param_ty, param.bounds);
|
let mut bounds = Bounds::default();
|
||||||
// Params are implicitly sized unless a `?Sized` bound is found
|
// Params are implicitly sized unless a `?Sized` bound is found
|
||||||
<dyn AstConv<'_>>::add_implicitly_sized(
|
<dyn AstConv<'_>>::add_implicitly_sized(
|
||||||
&icx,
|
&icx,
|
||||||
&mut bounds,
|
&mut bounds,
|
||||||
param.bounds,
|
&[],
|
||||||
Some((param.hir_id, ast_generics.predicates)),
|
Some((param.hir_id, ast_generics.predicates)),
|
||||||
param.span,
|
param.span,
|
||||||
);
|
);
|
||||||
|
@ -2349,7 +2271,6 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
|
||||||
}
|
}
|
||||||
GenericParamKind::Const { .. } => {
|
GenericParamKind::Const { .. } => {
|
||||||
// Bounds on const parameters are currently not possible.
|
// Bounds on const parameters are currently not possible.
|
||||||
debug_assert!(param.bounds.is_empty());
|
|
||||||
index += 1;
|
index += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2614,7 +2535,6 @@ fn compute_sig_of_foreign_fn_decl<'tcx>(
|
||||||
def_id: DefId,
|
def_id: DefId,
|
||||||
decl: &'tcx hir::FnDecl<'tcx>,
|
decl: &'tcx hir::FnDecl<'tcx>,
|
||||||
abi: abi::Abi,
|
abi: abi::Abi,
|
||||||
ident: Ident,
|
|
||||||
) -> ty::PolyFnSig<'tcx> {
|
) -> ty::PolyFnSig<'tcx> {
|
||||||
let unsafety = if abi == abi::Abi::RustIntrinsic {
|
let unsafety = if abi == abi::Abi::RustIntrinsic {
|
||||||
intrinsic_operation_unsafety(tcx.item_name(def_id))
|
intrinsic_operation_unsafety(tcx.item_name(def_id))
|
||||||
|
@ -2628,8 +2548,7 @@ fn compute_sig_of_foreign_fn_decl<'tcx>(
|
||||||
unsafety,
|
unsafety,
|
||||||
abi,
|
abi,
|
||||||
decl,
|
decl,
|
||||||
&hir::Generics::empty(),
|
None,
|
||||||
Some(ident.span),
|
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -49,8 +49,6 @@ def check_generic_param(param):
|
||||||
ty = param["kind"]["type"]
|
ty = param["kind"]["type"]
|
||||||
if ty["default"]:
|
if ty["default"]:
|
||||||
check_type(ty["default"])
|
check_type(ty["default"])
|
||||||
for bound in ty["bounds"]:
|
|
||||||
check_generic_bound(bound)
|
|
||||||
elif "const" in param["kind"]:
|
elif "const" in param["kind"]:
|
||||||
check_type(param["kind"]["const"])
|
check_type(param["kind"]["const"])
|
||||||
|
|
||||||
|
|
|
@ -238,9 +238,12 @@ impl Clean<Option<Lifetime>> for ty::Region<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Clean<WherePredicate> for hir::WherePredicate<'_> {
|
impl Clean<Option<WherePredicate>> for hir::WherePredicate<'_> {
|
||||||
fn clean(&self, cx: &mut DocContext<'_>) -> WherePredicate {
|
fn clean(&self, cx: &mut DocContext<'_>) -> Option<WherePredicate> {
|
||||||
match *self {
|
if !self.in_where_clause() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
Some(match *self {
|
||||||
hir::WherePredicate::BoundPredicate(ref wbp) => {
|
hir::WherePredicate::BoundPredicate(ref wbp) => {
|
||||||
let bound_params = wbp
|
let bound_params = wbp
|
||||||
.bound_generic_params
|
.bound_generic_params
|
||||||
|
@ -250,11 +253,7 @@ impl Clean<WherePredicate> for hir::WherePredicate<'_> {
|
||||||
// Higher-ranked lifetimes can't have bounds.
|
// Higher-ranked lifetimes can't have bounds.
|
||||||
assert_matches!(
|
assert_matches!(
|
||||||
param,
|
param,
|
||||||
hir::GenericParam {
|
hir::GenericParam { kind: hir::GenericParamKind::Lifetime { .. }, .. }
|
||||||
kind: hir::GenericParamKind::Lifetime { .. },
|
|
||||||
bounds: [],
|
|
||||||
..
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
Lifetime(param.name.ident().name)
|
Lifetime(param.name.ident().name)
|
||||||
})
|
})
|
||||||
|
@ -275,7 +274,7 @@ impl Clean<WherePredicate> for hir::WherePredicate<'_> {
|
||||||
lhs: wrp.lhs_ty.clean(cx),
|
lhs: wrp.lhs_ty.clean(cx),
|
||||||
rhs: wrp.rhs_ty.clean(cx).into(),
|
rhs: wrp.rhs_ty.clean(cx).into(),
|
||||||
},
|
},
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -456,44 +455,75 @@ impl Clean<GenericParamDef> for ty::GenericParamDef {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Clean<GenericParamDef> for hir::GenericParam<'_> {
|
fn clean_generic_param(
|
||||||
fn clean(&self, cx: &mut DocContext<'_>) -> GenericParamDef {
|
cx: &mut DocContext<'_>,
|
||||||
let (name, kind) = match self.kind {
|
generics: Option<&hir::Generics<'_>>,
|
||||||
hir::GenericParamKind::Lifetime { .. } => {
|
param: &hir::GenericParam<'_>,
|
||||||
let outlives = self
|
) -> GenericParamDef {
|
||||||
.bounds
|
let (name, kind) = match param.kind {
|
||||||
|
hir::GenericParamKind::Lifetime { .. } => {
|
||||||
|
let outlives = if let Some(generics) = generics {
|
||||||
|
generics
|
||||||
|
.predicates
|
||||||
.iter()
|
.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 {
|
.map(|bound| match bound {
|
||||||
hir::GenericBound::Outlives(lt) => lt.clean(cx),
|
hir::GenericBound::Outlives(lt) => lt.clean(cx),
|
||||||
_ => panic!(),
|
_ => panic!(),
|
||||||
})
|
})
|
||||||
.collect();
|
.collect()
|
||||||
(self.name.ident().name, GenericParamDefKind::Lifetime { outlives })
|
} else {
|
||||||
}
|
Vec::new()
|
||||||
hir::GenericParamKind::Type { ref default, synthetic } => (
|
};
|
||||||
self.name.ident().name,
|
(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 {
|
GenericParamDefKind::Type {
|
||||||
did: cx.tcx.hir().local_def_id(self.hir_id).to_def_id(),
|
did: did.to_def_id(),
|
||||||
bounds: self.bounds.iter().filter_map(|x| x.clean(cx)).collect(),
|
bounds,
|
||||||
default: default.map(|t| t.clean(cx)).map(Box::new),
|
default: default.map(|t| t.clean(cx)).map(Box::new),
|
||||||
synthetic,
|
synthetic,
|
||||||
},
|
},
|
||||||
),
|
)
|
||||||
hir::GenericParamKind::Const { ref ty, default } => (
|
}
|
||||||
self.name.ident().name,
|
hir::GenericParamKind::Const { ref ty, default } => (
|
||||||
GenericParamDefKind::Const {
|
param.name.ident().name,
|
||||||
did: cx.tcx.hir().local_def_id(self.hir_id).to_def_id(),
|
GenericParamDefKind::Const {
|
||||||
ty: Box::new(ty.clean(cx)),
|
did: cx.tcx.hir().local_def_id(param.hir_id).to_def_id(),
|
||||||
default: default.map(|ct| {
|
ty: Box::new(ty.clean(cx)),
|
||||||
let def_id = cx.tcx.hir().local_def_id(ct.hir_id);
|
default: default.map(|ct| {
|
||||||
Box::new(ty::Const::from_anon_const(cx.tcx, def_id).to_string())
|
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<Generics> for hir::Generics<'_> {
|
impl Clean<Generics> for hir::Generics<'_> {
|
||||||
|
@ -524,7 +554,7 @@ impl Clean<Generics> for hir::Generics<'_> {
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|param| is_impl_trait(param))
|
.filter(|param| is_impl_trait(param))
|
||||||
.map(|param| {
|
.map(|param| {
|
||||||
let param: GenericParamDef = param.clean(cx);
|
let param = clean_generic_param(cx, Some(self), param);
|
||||||
match param.kind {
|
match param.kind {
|
||||||
GenericParamDefKind::Lifetime { .. } => unreachable!(),
|
GenericParamDefKind::Lifetime { .. } => unreachable!(),
|
||||||
GenericParamDefKind::Type { did, ref bounds, .. } => {
|
GenericParamDefKind::Type { did, ref bounds, .. } => {
|
||||||
|
@ -538,14 +568,14 @@ impl Clean<Generics> for hir::Generics<'_> {
|
||||||
|
|
||||||
let mut params = Vec::with_capacity(self.params.len());
|
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)) {
|
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.push(p);
|
||||||
}
|
}
|
||||||
params.extend(impl_trait_params);
|
params.extend(impl_trait_params);
|
||||||
|
|
||||||
let mut generics = Generics {
|
let mut generics = Generics {
|
||||||
params,
|
params,
|
||||||
where_predicates: self.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
|
// Some duplicates are generated for ?Sized bounds between type params and where
|
||||||
|
@ -954,7 +984,11 @@ impl Clean<PolyTrait> for hir::PolyTraitRef<'_> {
|
||||||
fn clean(&self, cx: &mut DocContext<'_>) -> PolyTrait {
|
fn clean(&self, cx: &mut DocContext<'_>) -> PolyTrait {
|
||||||
PolyTrait {
|
PolyTrait {
|
||||||
trait_: self.trait_ref.clean(cx),
|
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<BareFunctionDecl> for hir::BareFnTy<'_> {
|
||||||
fn clean(&self, cx: &mut DocContext<'_>) -> BareFunctionDecl {
|
fn clean(&self, cx: &mut DocContext<'_>) -> BareFunctionDecl {
|
||||||
let (generic_params, decl) = enter_impl_trait(cx, |cx| {
|
let (generic_params, decl) = enter_impl_trait(cx, |cx| {
|
||||||
// NOTE: generics must be cleaned before args
|
// 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 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);
|
let decl = clean_fn_decl_with_args(cx, self.decl, args);
|
||||||
(generic_params, decl)
|
(generic_params, decl)
|
||||||
|
|
|
@ -5,7 +5,7 @@ use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc_hir::def::{DefKind, Res};
|
use rustc_hir::def::{DefKind, Res};
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_hir::intravisit::{self, Visitor};
|
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::hir::nested_filter;
|
||||||
use rustc_middle::ty::TyCtxt;
|
use rustc_middle::ty::TyCtxt;
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
|
@ -100,16 +100,7 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> {
|
||||||
self.tcx.hir()
|
self.tcx.hir()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_generic_param(&mut self, p: &'tcx GenericParam<'tcx>) {
|
fn visit_generic_param(&mut self, _: &'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_path(&mut self, path: &'tcx rustc_hir::Path<'tcx>, _id: HirId) {
|
fn visit_path(&mut self, path: &'tcx rustc_hir::Path<'tcx>, _id: HirId) {
|
||||||
self.handle_path(path, None);
|
self.handle_path(path, None);
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
warning: unnecessary lifetime parameter `'a`
|
||||||
|
--> $DIR/regions-free-region-outlives-static-outlives-free-region.rs:13:5
|
||||||
|
|
|
||||||
|
LL | 'a: 'static,
|
||||||
|
| ^^
|
||||||
|
|
|
||||||
|
= help: you can use the `'static` lifetime directly, in place of `'a`
|
||||||
|
|
||||||
|
warning: 1 warning emitted
|
||||||
|
|
26
src/test/ui/regions/regions-static-bound-rpass.stderr
Normal file
26
src/test/ui/regions/regions-static-bound-rpass.stderr
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
warning: unnecessary lifetime parameter `'a`
|
||||||
|
--> $DIR/regions-static-bound-rpass.rs:5:5
|
||||||
|
|
|
||||||
|
LL | 'a: 'static,
|
||||||
|
| ^^
|
||||||
|
|
|
||||||
|
= help: you can use the `'static` lifetime directly, in place of `'a`
|
||||||
|
|
||||||
|
warning: unnecessary lifetime parameter `'a`
|
||||||
|
--> $DIR/regions-static-bound-rpass.rs:12:5
|
||||||
|
|
|
||||||
|
LL | 'a: 'static,
|
||||||
|
| ^^
|
||||||
|
|
|
||||||
|
= help: you can use the `'static` lifetime directly, in place of `'a`
|
||||||
|
|
||||||
|
warning: unnecessary lifetime parameter `'b`
|
||||||
|
--> $DIR/regions-static-bound-rpass.rs:20:5
|
||||||
|
|
|
||||||
|
LL | 'b: 'static,
|
||||||
|
| ^^
|
||||||
|
|
|
||||||
|
= help: you can use the `'static` lifetime directly, in place of `'b`
|
||||||
|
|
||||||
|
warning: 3 warnings emitted
|
||||||
|
|
|
@ -139,28 +139,35 @@ fn check_fn_inner<'tcx>(
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|param| matches!(param.kind, GenericParamKind::Type { .. }));
|
.filter(|param| matches!(param.kind, GenericParamKind::Type { .. }));
|
||||||
for typ in types {
|
for typ in types {
|
||||||
for bound in typ.bounds {
|
for pred in generics.bounds_for_param(cx.tcx.hir().local_def_id(typ.hir_id)) {
|
||||||
let mut visitor = RefVisitor::new(cx);
|
if pred.in_where_clause {
|
||||||
walk_param_bound(&mut visitor, bound);
|
// has_where_lifetimes checked that this predicate contains no lifetime.
|
||||||
if visitor.lts.iter().any(|lt| matches!(lt, RefLt::Named(_))) {
|
continue;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
if let GenericBound::Trait(ref trait_ref, _) = *bound {
|
|
||||||
let params = &trait_ref
|
for bound in pred.bounds {
|
||||||
.trait_ref
|
let mut visitor = RefVisitor::new(cx);
|
||||||
.path
|
walk_param_bound(&mut visitor, bound);
|
||||||
.segments
|
if visitor.lts.iter().any(|lt| matches!(lt, RefLt::Named(_))) {
|
||||||
.last()
|
return;
|
||||||
.expect("a path must have at least one segment")
|
}
|
||||||
.args;
|
if let GenericBound::Trait(ref trait_ref, _) = *bound {
|
||||||
if let Some(params) = *params {
|
let params = &trait_ref
|
||||||
let lifetimes = params.args.iter().filter_map(|arg| match arg {
|
.trait_ref
|
||||||
GenericArg::Lifetime(lt) => Some(lt),
|
.path
|
||||||
_ => None,
|
.segments
|
||||||
});
|
.last()
|
||||||
for bound in lifetimes {
|
.expect("a path must have at least one segment")
|
||||||
if bound.name != LifetimeName::Static && !bound.is_elided() {
|
.args;
|
||||||
return;
|
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<RefLt> {
|
||||||
let mut allowed_lts = FxHashSet::default();
|
let mut allowed_lts = FxHashSet::default();
|
||||||
for par in named_generics.iter() {
|
for par in named_generics.iter() {
|
||||||
if let GenericParamKind::Lifetime { .. } = par.kind {
|
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);
|
allowed_lts.insert(RefLt::Unnamed);
|
||||||
|
|
|
@ -8,8 +8,7 @@ use rustc_data_structures::unhash::UnhashMap;
|
||||||
use rustc_errors::Applicability;
|
use rustc_errors::Applicability;
|
||||||
use rustc_hir::def::Res;
|
use rustc_hir::def::Res;
|
||||||
use rustc_hir::{
|
use rustc_hir::{
|
||||||
GenericBound, Generics, Item, ItemKind, Node, ParamName, Path, PathSegment, QPath, TraitItem, Ty, TyKind,
|
GenericBound, Generics, Item, ItemKind, Node, Path, PathSegment, QPath, TraitItem, Ty, TyKind, WherePredicate,
|
||||||
WherePredicate,
|
|
||||||
};
|
};
|
||||||
use rustc_lint::{LateContext, LateLintPass};
|
use rustc_lint::{LateContext, LateLintPass};
|
||||||
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
use rustc_session::{declare_tool_lint, impl_lint_pass};
|
||||||
|
@ -219,30 +218,19 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut map = FxHashMap::default();
|
let mut map = FxHashMap::<_, Vec<_>>::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::<Vec<_>>();
|
|
||||||
map.insert(*ident, res);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for predicate in gen.predicates {
|
for predicate in gen.predicates {
|
||||||
if_chain! {
|
if_chain! {
|
||||||
if let WherePredicate::BoundPredicate(ref bound_predicate) = predicate;
|
if let WherePredicate::BoundPredicate(ref bound_predicate) = predicate;
|
||||||
if !bound_predicate.span.from_expansion();
|
if !bound_predicate.span.from_expansion();
|
||||||
if let TyKind::Path(QPath::Resolved(_, Path { segments, .. })) = bound_predicate.bounded_ty.kind;
|
if let TyKind::Path(QPath::Resolved(_, Path { segments, .. })) = bound_predicate.bounded_ty.kind;
|
||||||
if let Some(segment) = segments.first();
|
if let Some(segment) = segments.first();
|
||||||
if let Some(trait_resolutions_direct) = map.get(&segment.ident);
|
|
||||||
then {
|
then {
|
||||||
for (res_where, _, _) in bound_predicate.bounds.iter().filter_map(get_trait_info_from_bound) {
|
for (res_where, _, span_where) in bound_predicate.bounds.iter().filter_map(get_trait_info_from_bound) {
|
||||||
if let Some((_, _, span_direct)) = trait_resolutions_direct
|
let trait_resolutions_direct = map.entry(segment.ident).or_default();
|
||||||
|
if let Some((_, span_direct)) = trait_resolutions_direct
|
||||||
.iter()
|
.iter()
|
||||||
.find(|(res_direct, _, _)| *res_direct == res_where) {
|
.find(|(res_direct, _)| *res_direct == res_where) {
|
||||||
span_lint_and_help(
|
span_lint_and_help(
|
||||||
cx,
|
cx,
|
||||||
TRAIT_DUPLICATION_IN_BOUNDS,
|
TRAIT_DUPLICATION_IN_BOUNDS,
|
||||||
|
@ -252,6 +240,9 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
|
||||||
"consider removing this trait bound",
|
"consider removing this trait bound",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
trait_resolutions_direct.push((res_where, span_where))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 Some(Node::GenericParam(generic_param)) = cx.tcx.hir().get_if_local(did);
|
||||||
if let GenericParamKind::Type { synthetic, .. } = generic_param.kind;
|
if let GenericParamKind::Type { synthetic, .. } = generic_param.kind;
|
||||||
if synthetic;
|
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 {
|
then {
|
||||||
Some(generic_param.bounds)
|
Some(pred.bounds)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue