Skip to content

Commit

Permalink
Auto merge of rust-lang#115362 - compiler-errors:non-lifetime-binder-…
Browse files Browse the repository at this point in the history
…where-clauses, r=<try>

[WIP] Support param bounds on non-lifetime binders

👀

r? `@ghost`
  • Loading branch information
bors committed Dec 18, 2023
2 parents a7690a3 + 335a142 commit fc9bfc9
Show file tree
Hide file tree
Showing 81 changed files with 684 additions and 324 deletions.
15 changes: 15 additions & 0 deletions compiler/rustc_ast_lowering/src/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1577,6 +1577,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
bounds,
span,
bound_generic_params: &[],
binder_predicates: &[],
origin,
}))
}
Expand Down Expand Up @@ -1605,6 +1606,20 @@ impl<'hir> LoweringContext<'_, 'hir> {
hir_id: self.next_id(),
bound_generic_params: self
.lower_generic_params(bound_generic_params, hir::GenericParamSource::Binder),
binder_predicates: self.arena.alloc_from_iter(
bound_generic_params.iter().filter_map(|param| {
self.lower_generic_bound_predicate(
param.ident,
param.id,
&param.kind,
&param.bounds,
param.colon_span,
*span,
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
PredicateOrigin::GenericParam,
)
}),
),
bounded_ty: self
.lower_ty(bounded_ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Bound)),
bounds: self.lower_param_bounds(
Expand Down
22 changes: 21 additions & 1 deletion compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2011,6 +2011,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
hir::GenericBound::Trait(
hir::PolyTraitRef {
bound_generic_params: &[],
binder_predicates: &[],
trait_ref: hir::TraitRef {
path: self.make_lang_item_path(
trait_lang_item,
Expand Down Expand Up @@ -2201,10 +2202,28 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
itctx: &ImplTraitContext,
constness: ast::Const,
) -> hir::PolyTraitRef<'hir> {
let binder_predicates =
self.arena.alloc_from_iter(p.bound_generic_params.iter().filter_map(|param| {
self.lower_generic_bound_predicate(
param.ident,
param.id,
&param.kind,
&param.bounds,
param.colon_span,
p.span,
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
hir::PredicateOrigin::GenericParam,
)
}));
let bound_generic_params =
self.lower_lifetime_binder(p.trait_ref.ref_id, &p.bound_generic_params);
let trait_ref = self.lower_trait_ref(constness, &p.trait_ref, itctx);
hir::PolyTraitRef { bound_generic_params, trait_ref, span: self.lower_span(p.span) }
hir::PolyTraitRef {
bound_generic_params,
binder_predicates,
trait_ref,
span: self.lower_span(p.span),
}
}

fn lower_mt(&mut self, mt: &MutTy, itctx: &ImplTraitContext) -> hir::MutTy<'hir> {
Expand Down Expand Up @@ -2510,6 +2529,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
Res::Def(DefKind::Trait | DefKind::TraitAlias, _) => {
let principal = hir::PolyTraitRef {
bound_generic_params: &[],
binder_predicates: &[],
trait_ref: hir::TraitRef { path, hir_ref_id: hir_id },
span: self.lower_span(span),
};
Expand Down
10 changes: 6 additions & 4 deletions compiler/rustc_ast_passes/src/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,10 +164,12 @@ impl<'a> PostExpansionVisitor<'a> {
non_lt_param_spans,
crate::fluent_generated::ast_passes_forbidden_non_lifetime_param
);
for param in params {
if !param.bounds.is_empty() {
let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect();
self.sess.emit_err(errors::ForbiddenLifetimeBound { spans });
if !self.features.non_lifetime_binders {
for param in params {
if !param.bounds.is_empty() {
let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect();
self.sess.emit_err(errors::ForbiddenLifetimeBound { spans });
}
}
}
}
Expand Down
9 changes: 7 additions & 2 deletions compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -756,9 +756,11 @@ pub struct WhereBoundPredicate<'hir> {
pub origin: PredicateOrigin,
/// Any generics from a `for` binding.
pub bound_generic_params: &'hir [GenericParam<'hir>],
/// Predicates on the `for<T>` binder itself, such as `for<T: Trait> ...`
pub binder_predicates: &'hir [WherePredicate<'hir>],
/// The type being bounded.
pub bounded_ty: &'hir Ty<'hir>,
/// Trait and lifetime bounds (e.g., `Clone + Send + 'static`).
/// Trait and lifetime bounds for `bounded_ty` (e.g., `Clone + Send + 'static`).
pub bounds: GenericBounds<'hir>,
}

Expand Down Expand Up @@ -2820,6 +2822,9 @@ pub struct PolyTraitRef<'hir> {
/// The `'a` in `for<'a> Foo<&'a T>`.
pub bound_generic_params: &'hir [GenericParam<'hir>],

/// Predicates on the `for<T>` binder itself, such as `for<T: Trait> ...`
pub binder_predicates: &'hir [WherePredicate<'hir>],

/// The `Foo<&'a T>` in `for<'a> Foo<&'a T>`.
pub trait_ref: TraitRef<'hir>,

Expand Down Expand Up @@ -3650,7 +3655,7 @@ mod size_asserts {
static_assert_size!(ForeignItem<'_>, 72);
static_assert_size!(ForeignItemKind<'_>, 40);
static_assert_size!(GenericArg<'_>, 32);
static_assert_size!(GenericBound<'_>, 48);
static_assert_size!(GenericBound<'_>, 64);
static_assert_size!(Generics<'_>, 56);
static_assert_size!(Impl<'_>, 80);
static_assert_size!(ImplItem<'_>, 88);
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_hir/src/intravisit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -904,11 +904,13 @@ pub fn walk_where_predicate<'v, V: Visitor<'v>>(
bound_generic_params,
origin: _,
span: _,
binder_predicates,
}) => {
visitor.visit_id(hir_id);
visitor.visit_ty(bounded_ty);
walk_list!(visitor, visit_param_bound, bounds);
walk_list!(visitor, visit_generic_param, bound_generic_params);
walk_list!(visitor, visit_where_predicate, binder_predicates);
}
WherePredicate::RegionPredicate(WhereRegionPredicate {
ref lifetime,
Expand Down Expand Up @@ -1082,6 +1084,7 @@ pub fn walk_param_bound<'v, V: Visitor<'v>>(visitor: &mut V, bound: &'v GenericB
pub fn walk_poly_trait_ref<'v, V: Visitor<'v>>(visitor: &mut V, trait_ref: &'v PolyTraitRef<'v>) {
walk_list!(visitor, visit_generic_param, trait_ref.bound_generic_params);
visitor.visit_trait_ref(&trait_ref.trait_ref);
walk_list!(visitor, visit_where_predicate, trait_ref.binder_predicates);
}

pub fn walk_struct_def<'v, V: Visitor<'v>>(
Expand Down
162 changes: 155 additions & 7 deletions compiler/rustc_hir_analysis/src/astconv/bounds.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_middle::ty::{self as ty, Ty};
use rustc_middle::ty::{self as ty, ToPredicate, Ty};
use rustc_span::symbol::Ident;
use rustc_span::{ErrorGuaranteed, Span};
use rustc_trait_selection::traits;
Expand All @@ -16,23 +16,155 @@ use crate::bounds::Bounds;
use crate::errors;

impl<'tcx> dyn AstConv<'tcx> + '_ {
pub(crate) fn lower_where_predicates(
&self,
params: &[hir::GenericParam<'_>],
hir_predicates: &[hir::WherePredicate<'_>],
predicates: &mut FxIndexSet<(ty::Clause<'tcx>, Span)>,
) {
// Collect the predicates that were written inline by the user on each
// type parameter (e.g., `<T: Foo>`). Also add `ConstArgHasType` predicates
// for each const parameter.
for param in params {
match param.kind {
hir::GenericParamKind::Lifetime { .. } => (),
hir::GenericParamKind::Type { .. } => {
let param_ty =
ty::fold::shift_vars(self.tcx(), self.hir_id_to_bound_ty(param.hir_id), 1);
let mut bounds = Bounds::default();
// Params are implicitly sized unless a `?Sized` bound is found
self.add_implicitly_sized(
&mut bounds,
param_ty,
&[],
Some((param.def_id, hir_predicates)),
param.span,
);
trace!(?bounds);
predicates.extend(bounds.clauses());
trace!(?predicates);
}
hir::GenericParamKind::Const { .. } => {
let ct_ty = self
.tcx()
.type_of(param.def_id.to_def_id())
.no_bound_vars()
.expect("const parameters cannot be generic");
let ct = ty::fold::shift_vars(
self.tcx(),
self.hir_id_to_bound_const(param.hir_id, ct_ty),
1,
);
predicates.insert((
ty::Binder::bind_with_vars(
ty::ClauseKind::ConstArgHasType(ct, ct_ty),
ty::List::empty(),
)
.to_predicate(self.tcx()),
param.span,
));
}
}
}

// Add in the bounds that appear in the where-clause.
for predicate in hir_predicates {
match predicate {
hir::WherePredicate::BoundPredicate(bound_pred) => {
let ty = self.ast_ty_to_ty(bound_pred.bounded_ty);
let bound_vars = self.tcx().late_bound_vars(bound_pred.hir_id);

let mut binder_predicates = FxIndexSet::default();
self.lower_where_predicates(
bound_pred.bound_generic_params,
bound_pred.binder_predicates,
&mut binder_predicates,
);
let binder_predicates = self.tcx().mk_clauses_from_iter(
binder_predicates.into_iter().map(|(clause, _)| clause),
);

// Keep the type around in a dummy predicate, in case of no bounds.
// That way, `where Ty:` is not a complete noop (see #53696) and `Ty`
// is still checked for WF.
if bound_pred.bounds.is_empty() {
if let ty::Param(_) = ty.kind() {
// This is a `where T:`, which can be in the HIR from the
// transformation that moves `?Sized` to `T`'s declaration.
// We can skip the predicate because type parameters are
// trivially WF, but also we *should*, to avoid exposing
// users who never wrote `where Type:,` themselves, to
// compiler/tooling bugs from not handling WF predicates.
} else {
let span = bound_pred.bounded_ty.span;
let predicate = ty::Binder::bind_with_vars(
ty::ClauseKind::WellFormed(ty.into()),
bound_vars,
);
predicates.insert((predicate.to_predicate(self.tcx()), span));
}
}

let mut bounds = Bounds::default();
self.add_bounds(
ty,
bound_pred.bounds.iter(),
&mut bounds,
bound_vars,
binder_predicates,
OnlySelfBounds(false),
);
predicates.extend(bounds.clauses());
}

hir::WherePredicate::RegionPredicate(region_pred) => {
let r1 = self.ast_region_to_region(&region_pred.lifetime, None);
predicates.extend(region_pred.bounds.iter().map(|bound| {
let (r2, span) = match bound {
hir::GenericBound::Outlives(lt) => {
(self.ast_region_to_region(lt, None), lt.ident.span)
}
_ => bug!(),
};
let pred = ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(r1, r2));
// This predicate may have escaping bound vars, e.g. if
// we have `for<'a: 'a> ..`. Since outlives predicates
// don't implicitly have a binder added for them in
// resolve_bound_vars, we need to explicitly shift the
// vars in once here.
let pred = ty::Binder::bind_with_vars(
ty::fold::shift_vars(self.tcx(), pred, 1),
ty::List::empty(),
)
.to_predicate(self.tcx());
(pred, span)
}))
}

hir::WherePredicate::EqPredicate(..) => {
// FIXME(#20041)
}
}
}
}

/// Sets `implicitly_sized` to true on `Bounds` if necessary
pub(crate) fn add_implicitly_sized(
pub(crate) fn add_implicitly_sized<'hir>(
&self,
bounds: &mut Bounds<'tcx>,
self_ty: Ty<'tcx>,
ast_bounds: &'tcx [hir::GenericBound<'tcx>],
self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>,
ast_bounds: &'hir [hir::GenericBound<'hir>],
self_ty_where_predicates: Option<(LocalDefId, &'hir [hir::WherePredicate<'hir>])>,
span: Span,
) {
let tcx = self.tcx();

// Try to find an unbound in bounds.
let mut unbounds: SmallVec<[_; 1]> = SmallVec::new();
let mut search_bounds = |ast_bounds: &'tcx [hir::GenericBound<'tcx>]| {
let mut search_bounds = |ast_bounds: &'hir [hir::GenericBound<'hir>]| {
for ab in ast_bounds {
if let hir::GenericBound::Trait(ptr, hir::TraitBoundModifier::Maybe) = ab {
unbounds.push(ptr)
unbounds.push(ptr);
}
}
};
Expand Down Expand Up @@ -106,6 +238,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
ast_bounds: I,
bounds: &mut Bounds<'tcx>,
bound_vars: &'tcx ty::List<ty::BoundVariableKind>,
binder_predicates: &'tcx ty::List<ty::Clause<'tcx>>,
only_self_bounds: OnlySelfBounds,
) {
for ast_bound in ast_bounds {
Expand All @@ -123,6 +256,18 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
}
hir::TraitBoundModifier::Maybe => continue,
};

let mut additional_binder_predicates = FxIndexSet::default();
self.lower_where_predicates(
poly_trait_ref.bound_generic_params,
poly_trait_ref.binder_predicates,
&mut additional_binder_predicates,
);
let binder_predicates =
self.tcx().mk_clauses_from_iter(binder_predicates.into_iter().chain(
additional_binder_predicates.into_iter().map(|(clause, _)| clause),
));

let _ = self.instantiate_poly_trait_ref(
&poly_trait_ref.trait_ref,
poly_trait_ref.span,
Expand All @@ -131,6 +276,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
param_ty,
bounds,
false,
binder_predicates,
only_self_bounds,
);
}
Expand Down Expand Up @@ -199,6 +345,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
}),
&mut bounds,
ty::List::empty(),
ty::List::empty(),
only_self_bounds,
);
debug!(?bounds);
Expand Down Expand Up @@ -503,6 +650,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
ast_bounds.iter(),
bounds,
projection_ty.bound_vars(),
projection_ty.skip_binder_with_predicates().1,
only_self_bounds,
);
}
Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_hir_analysis/src/astconv/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -707,6 +707,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
self_ty: Ty<'tcx>,
bounds: &mut Bounds<'tcx>,
speculative: bool,
binder_predicates: &'tcx ty::List<ty::Clause<'tcx>>,
only_self_bounds: OnlySelfBounds,
) -> GenericArgCountResult {
let trait_def_id = trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise());
Expand All @@ -733,9 +734,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {

let assoc_bindings = self.create_assoc_bindings_for_generic_args(args);

let poly_trait_ref = ty::Binder::bind_with_vars(
let poly_trait_ref = ty::Binder::bind_with_vars_and_predicates(
ty::TraitRef::new(tcx, trait_def_id, generic_args),
bound_vars,
binder_predicates,
);

debug!(?poly_trait_ref, ?assoc_bindings);
Expand Down

0 comments on commit fc9bfc9

Please sign in to comment.