Skip to content

Commit 2e849e3

Browse files
committed
Auto merge of rust-lang#115362 - compiler-errors:non-lifetime-binder-where-clauses, r=<try>
[WIP] Support param bounds on non-lifetime binders 👀 r? `@ghost`
2 parents a7690a3 + 82ae54c commit 2e849e3

File tree

79 files changed

+680
-321
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

79 files changed

+680
-321
lines changed

compiler/rustc_ast_lowering/src/item.rs

+15
Original file line numberDiff line numberDiff line change
@@ -1577,6 +1577,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
15771577
bounds,
15781578
span,
15791579
bound_generic_params: &[],
1580+
binder_predicates: &[],
15801581
origin,
15811582
}))
15821583
}
@@ -1605,6 +1606,20 @@ impl<'hir> LoweringContext<'_, 'hir> {
16051606
hir_id: self.next_id(),
16061607
bound_generic_params: self
16071608
.lower_generic_params(bound_generic_params, hir::GenericParamSource::Binder),
1609+
binder_predicates: self.arena.alloc_from_iter(
1610+
bound_generic_params.iter().filter_map(|param| {
1611+
self.lower_generic_bound_predicate(
1612+
param.ident,
1613+
param.id,
1614+
&param.kind,
1615+
&param.bounds,
1616+
param.colon_span,
1617+
*span,
1618+
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
1619+
PredicateOrigin::GenericParam,
1620+
)
1621+
}),
1622+
),
16081623
bounded_ty: self
16091624
.lower_ty(bounded_ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Bound)),
16101625
bounds: self.lower_param_bounds(

compiler/rustc_ast_lowering/src/lib.rs

+21-1
Original file line numberDiff line numberDiff line change
@@ -2011,6 +2011,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
20112011
hir::GenericBound::Trait(
20122012
hir::PolyTraitRef {
20132013
bound_generic_params: &[],
2014+
binder_predicates: &[],
20142015
trait_ref: hir::TraitRef {
20152016
path: self.make_lang_item_path(
20162017
trait_lang_item,
@@ -2201,10 +2202,28 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
22012202
itctx: &ImplTraitContext,
22022203
constness: ast::Const,
22032204
) -> hir::PolyTraitRef<'hir> {
2205+
let binder_predicates =
2206+
self.arena.alloc_from_iter(p.bound_generic_params.iter().filter_map(|param| {
2207+
self.lower_generic_bound_predicate(
2208+
param.ident,
2209+
param.id,
2210+
&param.kind,
2211+
&param.bounds,
2212+
param.colon_span,
2213+
p.span,
2214+
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
2215+
hir::PredicateOrigin::GenericParam,
2216+
)
2217+
}));
22042218
let bound_generic_params =
22052219
self.lower_lifetime_binder(p.trait_ref.ref_id, &p.bound_generic_params);
22062220
let trait_ref = self.lower_trait_ref(constness, &p.trait_ref, itctx);
2207-
hir::PolyTraitRef { bound_generic_params, trait_ref, span: self.lower_span(p.span) }
2221+
hir::PolyTraitRef {
2222+
bound_generic_params,
2223+
binder_predicates,
2224+
trait_ref,
2225+
span: self.lower_span(p.span),
2226+
}
22082227
}
22092228

22102229
fn lower_mt(&mut self, mt: &MutTy, itctx: &ImplTraitContext) -> hir::MutTy<'hir> {
@@ -2510,6 +2529,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
25102529
Res::Def(DefKind::Trait | DefKind::TraitAlias, _) => {
25112530
let principal = hir::PolyTraitRef {
25122531
bound_generic_params: &[],
2532+
binder_predicates: &[],
25132533
trait_ref: hir::TraitRef { path, hir_ref_id: hir_id },
25142534
span: self.lower_span(span),
25152535
};

compiler/rustc_ast_passes/src/feature_gate.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -164,10 +164,12 @@ impl<'a> PostExpansionVisitor<'a> {
164164
non_lt_param_spans,
165165
crate::fluent_generated::ast_passes_forbidden_non_lifetime_param
166166
);
167-
for param in params {
168-
if !param.bounds.is_empty() {
169-
let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect();
170-
self.sess.emit_err(errors::ForbiddenLifetimeBound { spans });
167+
if !self.features.non_lifetime_binders {
168+
for param in params {
169+
if !param.bounds.is_empty() {
170+
let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect();
171+
self.sess.emit_err(errors::ForbiddenLifetimeBound { spans });
172+
}
171173
}
172174
}
173175
}

compiler/rustc_hir/src/hir.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -756,9 +756,11 @@ pub struct WhereBoundPredicate<'hir> {
756756
pub origin: PredicateOrigin,
757757
/// Any generics from a `for` binding.
758758
pub bound_generic_params: &'hir [GenericParam<'hir>],
759+
/// Predicates on the `for<T>` binder itself, such as `for<T: Trait> ...`
760+
pub binder_predicates: &'hir [WherePredicate<'hir>],
759761
/// The type being bounded.
760762
pub bounded_ty: &'hir Ty<'hir>,
761-
/// Trait and lifetime bounds (e.g., `Clone + Send + 'static`).
763+
/// Trait and lifetime bounds for `bounded_ty` (e.g., `Clone + Send + 'static`).
762764
pub bounds: GenericBounds<'hir>,
763765
}
764766

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

2825+
/// Predicates on the `for<T>` binder itself, such as `for<T: Trait> ...`
2826+
pub binder_predicates: &'hir [WherePredicate<'hir>],
2827+
28232828
/// The `Foo<&'a T>` in `for<'a> Foo<&'a T>`.
28242829
pub trait_ref: TraitRef<'hir>,
28252830

compiler/rustc_hir/src/intravisit.rs

+3
Original file line numberDiff line numberDiff line change
@@ -904,11 +904,13 @@ pub fn walk_where_predicate<'v, V: Visitor<'v>>(
904904
bound_generic_params,
905905
origin: _,
906906
span: _,
907+
binder_predicates,
907908
}) => {
908909
visitor.visit_id(hir_id);
909910
visitor.visit_ty(bounded_ty);
910911
walk_list!(visitor, visit_param_bound, bounds);
911912
walk_list!(visitor, visit_generic_param, bound_generic_params);
913+
walk_list!(visitor, visit_where_predicate, binder_predicates);
912914
}
913915
WherePredicate::RegionPredicate(WhereRegionPredicate {
914916
ref lifetime,
@@ -1082,6 +1084,7 @@ pub fn walk_param_bound<'v, V: Visitor<'v>>(visitor: &mut V, bound: &'v GenericB
10821084
pub fn walk_poly_trait_ref<'v, V: Visitor<'v>>(visitor: &mut V, trait_ref: &'v PolyTraitRef<'v>) {
10831085
walk_list!(visitor, visit_generic_param, trait_ref.bound_generic_params);
10841086
visitor.visit_trait_ref(&trait_ref.trait_ref);
1087+
walk_list!(visitor, visit_where_predicate, trait_ref.binder_predicates);
10851088
}
10861089

10871090
pub fn walk_struct_def<'v, V: Visitor<'v>>(

compiler/rustc_hir_analysis/src/astconv/bounds.rs

+155-7
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
use rustc_data_structures::fx::FxHashMap;
1+
use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
22
use rustc_errors::struct_span_err;
33
use rustc_hir as hir;
44
use rustc_hir::def::{DefKind, Res};
55
use rustc_hir::def_id::{DefId, LocalDefId};
6-
use rustc_middle::ty::{self as ty, Ty};
6+
use rustc_middle::ty::{self as ty, ToPredicate, Ty};
77
use rustc_span::symbol::Ident;
88
use rustc_span::{ErrorGuaranteed, Span};
99
use rustc_trait_selection::traits;
@@ -16,23 +16,155 @@ use crate::bounds::Bounds;
1616
use crate::errors;
1717

1818
impl<'tcx> dyn AstConv<'tcx> + '_ {
19+
pub(crate) fn lower_where_predicates(
20+
&self,
21+
params: &[hir::GenericParam<'_>],
22+
hir_predicates: &[hir::WherePredicate<'_>],
23+
predicates: &mut FxIndexSet<(ty::Clause<'tcx>, Span)>,
24+
) {
25+
// Collect the predicates that were written inline by the user on each
26+
// type parameter (e.g., `<T: Foo>`). Also add `ConstArgHasType` predicates
27+
// for each const parameter.
28+
for param in params {
29+
match param.kind {
30+
hir::GenericParamKind::Lifetime { .. } => (),
31+
hir::GenericParamKind::Type { .. } => {
32+
let param_ty =
33+
ty::fold::shift_vars(self.tcx(), self.hir_id_to_bound_ty(param.hir_id), 1);
34+
let mut bounds = Bounds::default();
35+
// Params are implicitly sized unless a `?Sized` bound is found
36+
self.add_implicitly_sized(
37+
&mut bounds,
38+
param_ty,
39+
&[],
40+
Some((param.def_id, hir_predicates)),
41+
param.span,
42+
);
43+
trace!(?bounds);
44+
predicates.extend(bounds.clauses());
45+
trace!(?predicates);
46+
}
47+
hir::GenericParamKind::Const { .. } => {
48+
let ct_ty = self
49+
.tcx()
50+
.type_of(param.def_id.to_def_id())
51+
.no_bound_vars()
52+
.expect("const parameters cannot be generic");
53+
let ct = ty::fold::shift_vars(
54+
self.tcx(),
55+
self.hir_id_to_bound_const(param.hir_id, ct_ty),
56+
1,
57+
);
58+
predicates.insert((
59+
ty::Binder::bind_with_vars(
60+
ty::ClauseKind::ConstArgHasType(ct, ct_ty),
61+
ty::List::empty(),
62+
)
63+
.to_predicate(self.tcx()),
64+
param.span,
65+
));
66+
}
67+
}
68+
}
69+
70+
// Add in the bounds that appear in the where-clause.
71+
for predicate in hir_predicates {
72+
match predicate {
73+
hir::WherePredicate::BoundPredicate(bound_pred) => {
74+
let ty = self.ast_ty_to_ty(bound_pred.bounded_ty);
75+
let bound_vars = self.tcx().late_bound_vars(bound_pred.hir_id);
76+
77+
let mut binder_predicates = FxIndexSet::default();
78+
self.lower_where_predicates(
79+
bound_pred.bound_generic_params,
80+
bound_pred.binder_predicates,
81+
&mut binder_predicates,
82+
);
83+
let binder_predicates = self.tcx().mk_clauses_from_iter(
84+
binder_predicates.into_iter().map(|(clause, _)| clause),
85+
);
86+
87+
// Keep the type around in a dummy predicate, in case of no bounds.
88+
// That way, `where Ty:` is not a complete noop (see #53696) and `Ty`
89+
// is still checked for WF.
90+
if bound_pred.bounds.is_empty() {
91+
if let ty::Param(_) = ty.kind() {
92+
// This is a `where T:`, which can be in the HIR from the
93+
// transformation that moves `?Sized` to `T`'s declaration.
94+
// We can skip the predicate because type parameters are
95+
// trivially WF, but also we *should*, to avoid exposing
96+
// users who never wrote `where Type:,` themselves, to
97+
// compiler/tooling bugs from not handling WF predicates.
98+
} else {
99+
let span = bound_pred.bounded_ty.span;
100+
let predicate = ty::Binder::bind_with_vars(
101+
ty::ClauseKind::WellFormed(ty.into()),
102+
bound_vars,
103+
);
104+
predicates.insert((predicate.to_predicate(self.tcx()), span));
105+
}
106+
}
107+
108+
let mut bounds = Bounds::default();
109+
self.add_bounds(
110+
ty,
111+
bound_pred.bounds.iter(),
112+
&mut bounds,
113+
bound_vars,
114+
binder_predicates,
115+
OnlySelfBounds(false),
116+
);
117+
predicates.extend(bounds.clauses());
118+
}
119+
120+
hir::WherePredicate::RegionPredicate(region_pred) => {
121+
let r1 = self.ast_region_to_region(&region_pred.lifetime, None);
122+
predicates.extend(region_pred.bounds.iter().map(|bound| {
123+
let (r2, span) = match bound {
124+
hir::GenericBound::Outlives(lt) => {
125+
(self.ast_region_to_region(lt, None), lt.ident.span)
126+
}
127+
_ => bug!(),
128+
};
129+
let pred = ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(r1, r2));
130+
// This predicate may have escaping bound vars, e.g. if
131+
// we have `for<'a: 'a> ..`. Since outlives predicates
132+
// don't implicitly have a binder added for them in
133+
// resolve_bound_vars, we need to explicitly shift the
134+
// vars in once here.
135+
let pred = ty::Binder::bind_with_vars(
136+
ty::fold::shift_vars(self.tcx(), pred, 1),
137+
ty::List::empty(),
138+
)
139+
.to_predicate(self.tcx());
140+
(pred, span)
141+
}))
142+
}
143+
144+
hir::WherePredicate::EqPredicate(..) => {
145+
// FIXME(#20041)
146+
}
147+
}
148+
}
149+
}
150+
19151
/// Sets `implicitly_sized` to true on `Bounds` if necessary
20-
pub(crate) fn add_implicitly_sized(
152+
pub(crate) fn add_implicitly_sized<'hir>(
21153
&self,
22154
bounds: &mut Bounds<'tcx>,
23155
self_ty: Ty<'tcx>,
24-
ast_bounds: &'tcx [hir::GenericBound<'tcx>],
25-
self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>,
156+
ast_bounds: &'hir [hir::GenericBound<'hir>],
157+
self_ty_where_predicates: Option<(LocalDefId, &'hir [hir::WherePredicate<'hir>])>,
26158
span: Span,
27159
) {
28160
let tcx = self.tcx();
29161

30162
// Try to find an unbound in bounds.
31163
let mut unbounds: SmallVec<[_; 1]> = SmallVec::new();
32-
let mut search_bounds = |ast_bounds: &'tcx [hir::GenericBound<'tcx>]| {
164+
let mut search_bounds = |ast_bounds: &'hir [hir::GenericBound<'hir>]| {
33165
for ab in ast_bounds {
34166
if let hir::GenericBound::Trait(ptr, hir::TraitBoundModifier::Maybe) = ab {
35-
unbounds.push(ptr)
167+
unbounds.push(ptr);
36168
}
37169
}
38170
};
@@ -106,6 +238,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
106238
ast_bounds: I,
107239
bounds: &mut Bounds<'tcx>,
108240
bound_vars: &'tcx ty::List<ty::BoundVariableKind>,
241+
binder_predicates: &'tcx ty::List<ty::Clause<'tcx>>,
109242
only_self_bounds: OnlySelfBounds,
110243
) {
111244
for ast_bound in ast_bounds {
@@ -123,6 +256,18 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
123256
}
124257
hir::TraitBoundModifier::Maybe => continue,
125258
};
259+
260+
let mut additional_binder_predicates = FxIndexSet::default();
261+
self.lower_where_predicates(
262+
poly_trait_ref.bound_generic_params,
263+
poly_trait_ref.binder_predicates,
264+
&mut additional_binder_predicates,
265+
);
266+
let binder_predicates =
267+
self.tcx().mk_clauses_from_iter(binder_predicates.into_iter().chain(
268+
additional_binder_predicates.into_iter().map(|(clause, _)| clause),
269+
));
270+
126271
let _ = self.instantiate_poly_trait_ref(
127272
&poly_trait_ref.trait_ref,
128273
poly_trait_ref.span,
@@ -131,6 +276,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
131276
param_ty,
132277
bounds,
133278
false,
279+
binder_predicates,
134280
only_self_bounds,
135281
);
136282
}
@@ -199,6 +345,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
199345
}),
200346
&mut bounds,
201347
ty::List::empty(),
348+
ty::List::empty(),
202349
only_self_bounds,
203350
);
204351
debug!(?bounds);
@@ -503,6 +650,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
503650
ast_bounds.iter(),
504651
bounds,
505652
projection_ty.bound_vars(),
653+
projection_ty.skip_binder_with_predicates().1,
506654
only_self_bounds,
507655
);
508656
}

compiler/rustc_hir_analysis/src/astconv/mod.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -707,6 +707,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
707707
self_ty: Ty<'tcx>,
708708
bounds: &mut Bounds<'tcx>,
709709
speculative: bool,
710+
binder_predicates: &'tcx ty::List<ty::Clause<'tcx>>,
710711
only_self_bounds: OnlySelfBounds,
711712
) -> GenericArgCountResult {
712713
let trait_def_id = trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise());
@@ -733,9 +734,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
733734

734735
let assoc_bindings = self.create_assoc_bindings_for_generic_args(args);
735736

736-
let poly_trait_ref = ty::Binder::bind_with_vars(
737+
let poly_trait_ref = ty::Binder::bind_with_vars_and_predicates(
737738
ty::TraitRef::new(tcx, trait_def_id, generic_args),
738739
bound_vars,
740+
binder_predicates,
739741
);
740742

741743
debug!(?poly_trait_ref, ?assoc_bindings);

compiler/rustc_hir_analysis/src/astconv/object_safety.rs

+5
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
3333
let mut potential_assoc_types = Vec::new();
3434
let dummy_self = self.tcx().types.trait_object_dummy_self;
3535
for trait_bound in hir_trait_bounds.iter().rev() {
36+
assert!(
37+
trait_bound.binder_predicates.is_empty(),
38+
"FIXME(non_lifetime_binders): object types should not have binders"
39+
);
3640
if let GenericArgCountResult {
3741
correct:
3842
Err(GenericArgCountMismatch { invalid_args: cur_potential_assoc_types, .. }),
@@ -45,6 +49,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
4549
dummy_self,
4650
&mut bounds,
4751
false,
52+
ty::List::empty(),
4853
// FIXME: This should be `true`, but we don't really handle
4954
// associated type bounds or type aliases in objects in a way
5055
// that makes this meaningful, I think.

0 commit comments

Comments
 (0)