Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[mirror] compiler-errors's Support param bounds on non-lifetime binders #10

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -1600,6 +1600,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
bounds,
span,
bound_generic_params: &[],
binder_predicates: &[],
origin,
}))
}
Expand Down Expand Up @@ -1628,6 +1629,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
21 changes: 20 additions & 1 deletion compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2115,10 +2115,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 @@ -2425,6 +2443,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 @@ -170,10 +170,12 @@ impl<'a> PostExpansionVisitor<'a> {
)
.emit();
}
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 @@ -779,9 +779,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 @@ -3000,6 +3002,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 @@ -4089,7 +4094,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 @@ -1086,6 +1088,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
160 changes: 154 additions & 6 deletions compiler/rustc_hir_analysis/src/astconv/bounds.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
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_lint_defs::Applicability;
use rustc_middle::ty::{self as ty, Ty, TypeVisitableExt};
use rustc_middle::ty::{self as ty, ToPredicate, Ty, TypeVisitableExt};
use rustc_span::symbol::Ident;
use rustc_span::{ErrorGuaranteed, Span};
use rustc_trait_selection::traits;
Expand All @@ -16,20 +16,152 @@ 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 unbound = None;
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 {
if unbound.is_none() {
Expand Down Expand Up @@ -102,6 +234,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 @@ -119,6 +252,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 @@ -127,6 +272,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
param_ty,
bounds,
false,
binder_predicates,
only_self_bounds,
);
}
Expand Down Expand Up @@ -208,6 +354,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
}),
&mut bounds,
ty::List::empty(),
ty::List::empty(),
only_self_bounds,
);
debug!(?bounds);
Expand Down Expand Up @@ -577,6 +724,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
Loading