Skip to content

Commit

Permalink
Auto merge of #93803 - cjgillot:unify-bounds, r=oli-obk
Browse files Browse the repository at this point in the history
Handle generic bounds in a uniform way in HIR

Generic bounds in HIR used to be split between bounds in the parameter definition and bounds in a where clause. This PR attempts to store all of those as where predicates.

This effectively desugars
```rust
fn foo<T: Default, U>(x: impl Copy) where U: Clone
```
into
```rust
fn foo<T, U, _V>(x: _V) where T: Default, U: Clone, _V: Copy
```
(where _V is actually hidden and called "impl Copy").

I managed to make compiler warnings more uniform.
About rustdoc: is making this desugaring user-visible acceptable?
About clippy: I don't understand the subtle logic in the `needless-lifetimes` lint.

r? `@estebank`
  • Loading branch information
bors committed Apr 30, 2022
2 parents 76d4862 + b4e3e62 commit d201c81
Show file tree
Hide file tree
Showing 120 changed files with 1,498 additions and 1,462 deletions.
1 change: 1 addition & 0 deletions compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,7 @@ pub struct GenericParam {
pub bounds: GenericBounds,
pub is_placeholder: bool,
pub kind: GenericParamKind,
pub colon_span: Option<Span>,
}

impl GenericParam {
Expand Down
5 changes: 4 additions & 1 deletion compiler/rustc_ast/src/mut_visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -867,9 +867,12 @@ pub fn noop_flat_map_generic_param<T: MutVisitor>(
mut param: GenericParam,
vis: &mut T,
) -> SmallVec<[GenericParam; 1]> {
let GenericParam { id, ident, attrs, bounds, kind, is_placeholder: _ } = &mut param;
let GenericParam { id, ident, attrs, bounds, kind, colon_span, is_placeholder: _ } = &mut param;
vis.visit_id(id);
vis.visit_ident(ident);
if let Some(ref mut colon_span) = colon_span {
vis.visit_span(colon_span);
}
visit_thin_attrs(attrs, vis);
visit_vec(bounds, |bound| noop_visit_param_bound(bound, vis));
match kind {
Expand Down
136 changes: 108 additions & 28 deletions compiler/rustc_ast_lowering/src/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -267,9 +267,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
this.lower_maybe_async_body(span, &decl, asyncness, body.as_deref());

let (generics, decl) =
this.add_implicit_generics(generics, id, |this, idty| {
this.add_implicit_generics(generics, id, |this, idty, idpb| {
let ret_id = asyncness.opt_return_id();
this.lower_fn_decl(&decl, Some((id, idty)), FnDeclKind::Fn, ret_id)
this.lower_fn_decl(
&decl,
Some((id, idty, idpb)),
FnDeclKind::Fn,
ret_id,
)
});
let sig = hir::FnSig {
decl,
Expand Down Expand Up @@ -384,7 +389,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
// lifetime to be added, but rather a reference to a
// parent lifetime.
let (generics, (trait_ref, lowered_ty)) =
self.add_implicit_generics(ast_generics, id, |this, _| {
self.add_implicit_generics(ast_generics, id, |this, _, _| {
let trait_ref = trait_ref.as_ref().map(|trait_ref| {
this.lower_trait_ref(
trait_ref,
Expand All @@ -410,7 +415,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
ImplPolarity::Positive => ImplPolarity::Positive,
ImplPolarity::Negative(s) => ImplPolarity::Negative(self.lower_span(s)),
};
hir::ItemKind::Impl(hir::Impl {
hir::ItemKind::Impl(self.arena.alloc(hir::Impl {
unsafety: self.lower_unsafety(unsafety),
polarity,
defaultness,
Expand All @@ -420,7 +425,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
of_trait: trait_ref,
self_ty: lowered_ty,
items: new_impl_items,
})
}))
}
ItemKind::Trait(box Trait {
is_auto,
Expand Down Expand Up @@ -649,7 +654,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
ForeignItemKind::Fn(box Fn { ref sig, ref generics, .. }) => {
let fdec = &sig.decl;
let (generics, (fn_dec, fn_args)) =
self.add_implicit_generics(generics, i.id, |this, _| {
self.add_implicit_generics(generics, i.id, |this, _, _| {
(
// Disallow `impl Trait` in foreign items.
this.lower_fn_decl(fdec, None, FnDeclKind::ExternFn, None),
Expand Down Expand Up @@ -1226,10 +1231,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
id: NodeId,
kind: FnDeclKind,
is_async: Option<NodeId>,
) -> (hir::Generics<'hir>, hir::FnSig<'hir>) {
) -> (&'hir hir::Generics<'hir>, hir::FnSig<'hir>) {
let header = self.lower_fn_header(sig.header);
let (generics, decl) = self.add_implicit_generics(generics, id, |this, idty| {
this.lower_fn_decl(&sig.decl, Some((id, idty)), kind, is_async)
let (generics, decl) = self.add_implicit_generics(generics, id, |this, idty, idpb| {
this.lower_fn_decl(&sig.decl, Some((id, idty, idpb)), kind, is_async)
});
(generics, hir::FnSig { header, decl, span: self.lower_span(sig.span) })
}
Expand Down Expand Up @@ -1289,7 +1294,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
pub(super) fn lower_generics_mut(
&mut self,
generics: &Generics,
itctx: ImplTraitContext<'_, 'hir>,
mut itctx: ImplTraitContext<'_, 'hir>,
) -> GenericsCtor<'hir> {
// Error if `?Trait` bounds in where clauses don't refer directly to type parameters.
// Note: we used to clone these bounds directly onto the type parameter (and avoid lowering
Expand Down Expand Up @@ -1338,9 +1343,24 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
}

let mut predicates = SmallVec::new();
predicates.extend(generics.params.iter().filter_map(|param| {
let bounds = self.lower_param_bounds(&param.bounds, itctx.reborrow());
self.lower_generic_bound_predicate(param.ident, param.id, &param.kind, bounds)
}));
predicates.extend(
generics
.where_clause
.predicates
.iter()
.map(|predicate| self.lower_where_predicate(predicate)),
);

GenericsCtor {
params: self.lower_generic_params_mut(&generics.params, itctx).collect(),
where_clause: self.lower_where_clause(&generics.where_clause),
params: self.lower_generic_params_mut(&generics.params).collect(),
predicates,
has_where_clause: !generics.where_clause.predicates.is_empty(),
where_clause_span: self.lower_span(generics.where_clause.span),
span: self.lower_span(generics.span),
}
}
Expand All @@ -1349,17 +1369,74 @@ impl<'hir> LoweringContext<'_, 'hir> {
&mut self,
generics: &Generics,
itctx: ImplTraitContext<'_, 'hir>,
) -> hir::Generics<'hir> {
) -> &'hir hir::Generics<'hir> {
let generics_ctor = self.lower_generics_mut(generics, itctx);
generics_ctor.into_generics(self.arena)
}

fn lower_where_clause(&mut self, wc: &WhereClause) -> hir::WhereClause<'hir> {
hir::WhereClause {
predicates: self.arena.alloc_from_iter(
wc.predicates.iter().map(|predicate| self.lower_where_predicate(predicate)),
),
span: self.lower_span(wc.span),
pub(super) fn lower_generic_bound_predicate(
&mut self,
ident: Ident,
id: NodeId,
kind: &GenericParamKind,
bounds: &'hir [hir::GenericBound<'hir>],
) -> Option<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,
}))
}
}
}

Expand All @@ -1371,10 +1448,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
ref bounds,
span,
}) => hir::WherePredicate::BoundPredicate(hir::WhereBoundPredicate {
bound_generic_params: self.lower_generic_params(
bound_generic_params,
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
),
bound_generic_params: self.lower_generic_params(bound_generic_params),
bounded_ty: self
.lower_ty(bounded_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Type)),
bounds: self.arena.alloc_from_iter(bounds.iter().map(|bound| {
Expand All @@ -1384,6 +1458,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
)
})),
span: self.lower_span(span),
in_where_clause: true,
}),
WherePredicate::RegionPredicate(WhereRegionPredicate {
ref lifetime,
Expand All @@ -1396,6 +1471,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
bounds,
ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
),
in_where_clause: true,
}),
WherePredicate::EqPredicate(WhereEqPredicate { id, ref lhs_ty, ref rhs_ty, span }) => {
hir::WherePredicate::EqPredicate(hir::WhereEqPredicate {
Expand All @@ -1414,16 +1490,20 @@ impl<'hir> LoweringContext<'_, 'hir> {
/// Helper struct for delayed construction of Generics.
pub(super) struct GenericsCtor<'hir> {
pub(super) params: SmallVec<[hir::GenericParam<'hir>; 4]>,
where_clause: hir::WhereClause<'hir>,
pub(super) predicates: SmallVec<[hir::WherePredicate<'hir>; 4]>,
has_where_clause: bool,
where_clause_span: Span,
span: Span,
}

impl<'hir> GenericsCtor<'hir> {
pub(super) fn into_generics(self, arena: &'hir Arena<'hir>) -> hir::Generics<'hir> {
hir::Generics {
pub(super) fn into_generics(self, arena: &'hir Arena<'hir>) -> &'hir hir::Generics<'hir> {
arena.alloc(hir::Generics {
params: arena.alloc_from_iter(self.params),
where_clause: self.where_clause,
predicates: arena.alloc_from_iter(self.predicates),
has_where_clause: self.has_where_clause,
where_clause_span: self.where_clause_span,
span: self.span,
}
})
}
}
Loading

0 comments on commit d201c81

Please sign in to comment.