Skip to content

Commit 8476a32

Browse files
committed
hir_analysis: edition migration
Implement the edition migration required by these changes - `?Sized` becoming `const MetaSized`, `Sized` becoming `const Sized` and a `const MetaSized` supertrait.
1 parent 39b1dec commit 8476a32

File tree

67 files changed

+841
-190
lines changed

Some content is hidden

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

67 files changed

+841
-190
lines changed

compiler/rustc_data_structures/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#![allow(internal_features)]
1111
#![allow(rustc::default_hash_types)]
1212
#![allow(rustc::potential_query_instability)]
13+
#![cfg_attr(not(bootstrap), allow(sized_hierarchy_migration))]
1314
#![deny(unsafe_op_in_unsafe_fn)]
1415
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
1516
#![doc(rust_logo)]

compiler/rustc_hir_analysis/src/collect/item_bounds.rs

+2
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ fn associated_type_bounds<'tcx>(
5151
hir_bounds,
5252
None,
5353
span,
54+
assoc_item_def_id,
5455
filter,
5556
);
5657
}
@@ -348,6 +349,7 @@ fn opaque_type_bounds<'tcx>(
348349
hir_bounds,
349350
None,
350351
span,
352+
opaque_def_id,
351353
filter,
352354
);
353355
}

compiler/rustc_hir_analysis/src/collect/predicates_of.rs

+1
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
238238
&[],
239239
Some((param.def_id, hir_generics.predicates)),
240240
param.span,
241+
def_id,
241242
PredicateFilter::All,
242243
);
243244
icx.lowerer().add_default_traits(

compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs

+57-19
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,19 @@ use crate::hir_ty_lowering::{
2525

2626
#[derive(Debug, Default)]
2727
struct CollectedBound {
28+
constness: bool,
2829
/// `Trait`
29-
positive: bool,
30+
positive: Option<Span>,
3031
/// `?Trait`
31-
maybe: bool,
32+
maybe: Option<Span>,
3233
/// `!Trait`
33-
negative: bool,
34+
negative: Option<Span>,
3435
}
3536

3637
impl CollectedBound {
3738
/// Returns `true` if any of `Trait`, `?Trait` or `!Trait` were encountered.
3839
fn any(&self) -> bool {
39-
self.positive || self.maybe || self.negative
40+
self.positive.is_some() || self.maybe.is_some() || self.negative.is_some()
4041
}
4142
}
4243

@@ -61,15 +62,15 @@ impl CollectedSizednessBounds {
6162
fn search_bounds_for<'tcx>(
6263
hir_bounds: &'tcx [hir::GenericBound<'tcx>],
6364
self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>,
64-
mut f: impl FnMut(&'tcx PolyTraitRef<'tcx>),
65+
mut f: impl FnMut(&'tcx PolyTraitRef<'tcx>, Span),
6566
) {
6667
let mut search_bounds = |hir_bounds: &'tcx [hir::GenericBound<'tcx>]| {
6768
for hir_bound in hir_bounds {
6869
let hir::GenericBound::Trait(ptr) = hir_bound else {
6970
continue;
7071
};
7172

72-
f(ptr)
73+
f(ptr, hir_bound.span())
7374
}
7475
};
7576

@@ -90,7 +91,7 @@ fn collect_unbounds<'tcx>(
9091
self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>,
9192
) -> SmallVec<[&'tcx PolyTraitRef<'tcx>; 1]> {
9293
let mut unbounds: SmallVec<[_; 1]> = SmallVec::new();
93-
search_bounds_for(hir_bounds, self_ty_where_predicates, |ptr| {
94+
search_bounds_for(hir_bounds, self_ty_where_predicates, |ptr, _| {
9495
if matches!(ptr.modifiers.polarity, hir::BoundPolarity::Maybe(_)) {
9596
unbounds.push(ptr);
9697
}
@@ -104,15 +105,20 @@ fn collect_bounds<'a, 'tcx>(
104105
target_did: DefId,
105106
) -> CollectedBound {
106107
let mut collect_into = CollectedBound::default();
107-
search_bounds_for(hir_bounds, self_ty_where_predicates, |ptr| {
108+
search_bounds_for(hir_bounds, self_ty_where_predicates, |ptr, span| {
108109
if !matches!(ptr.trait_ref.path.res, Res::Def(DefKind::Trait, did) if did == target_did) {
109110
return;
110111
}
111112

113+
collect_into.constness = matches!(
114+
ptr.modifiers.constness,
115+
hir::BoundConstness::Always(_) | hir::BoundConstness::Maybe(_)
116+
);
117+
112118
match ptr.modifiers.polarity {
113-
hir::BoundPolarity::Maybe(_) => collect_into.maybe = true,
114-
hir::BoundPolarity::Negative(_) => collect_into.negative = true,
115-
hir::BoundPolarity::Positive => collect_into.positive = true,
119+
hir::BoundPolarity::Maybe(_) => collect_into.maybe = Some(span),
120+
hir::BoundPolarity::Negative(_) => collect_into.negative = Some(span),
121+
hir::BoundPolarity::Positive => collect_into.positive = Some(span),
116122
}
117123
});
118124
collect_into
@@ -215,9 +221,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
215221
let tcx = self.tcx();
216222

217223
let span = tcx.def_span(trait_did);
224+
let sized_did = tcx.require_lang_item(LangItem::Sized, Some(span));
218225
let meta_sized_did = tcx.require_lang_item(LangItem::MetaSized, Some(span));
219226
let pointee_sized_did = tcx.require_lang_item(LangItem::PointeeSized, Some(span));
220227

228+
let trait_hir_id = tcx.local_def_id_to_hir_id(trait_did);
221229
let trait_did = trait_did.to_def_id();
222230
if trait_did == pointee_sized_did {
223231
// Never add a default supertrait to `PointeeSized`.
@@ -230,11 +238,24 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
230238
}
231239

232240
let collected = collect_sizedness_bounds(tcx, hir_bounds, None, span);
233-
if !collected.any() && trait_did != pointee_sized_did {
234-
// If there are no explicit sizedness bounds then add a default `const MetaSized`
235-
// supertrait.
241+
if !collected.any() && !tcx.sess.edition().at_least_edition_future() {
242+
// Emit migration lint when the feature is enabled.
243+
self.emit_implicit_const_meta_sized_supertrait_lint(trait_hir_id, span);
244+
245+
// If it is not Edition Future and there are no explicit sizedness bounds then add a
246+
// default `const MetaSized` supertrait.
236247
add_trait_predicate(tcx, bounds, self_ty, meta_sized_did, span);
237248
add_host_effect_predicate(tcx, filter, bounds, self_ty, meta_sized_did, span);
249+
} else if let Some(bound_span) = collected.sized.positive
250+
&& !collected.sized.constness
251+
&& !tcx.sess.edition().at_least_edition_future()
252+
{
253+
// Emit migration lint when the feature is enabled.
254+
self.emit_sized_to_const_sized_lint(trait_hir_id, bound_span);
255+
256+
// If it is not Edition Future then `Sized` is equivalent to writing `const Sized`.
257+
add_trait_predicate(tcx, bounds, self_ty, sized_did, bound_span);
258+
add_host_effect_predicate(tcx, filter, bounds, self_ty, sized_did, bound_span);
238259
}
239260

240261
// See doc comment on `adjust_sizedness_predicates`.
@@ -251,6 +272,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
251272
hir_bounds: &'tcx [hir::GenericBound<'tcx>],
252273
self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>,
253274
span: Span,
275+
trait_did: LocalDefId,
254276
filter: PredicateFilter,
255277
) {
256278
let tcx = self.tcx();
@@ -260,23 +282,39 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
260282
let pointee_sized_did = tcx.require_lang_item(LangItem::PointeeSized, Some(span));
261283

262284
// Report invalid unbounds.
285+
let trait_hir_id = tcx.local_def_id_to_hir_id(trait_did);
263286
let unbounds = collect_unbounds(hir_bounds, self_ty_where_predicates);
264-
self.check_and_report_invalid_unbounds_on_param(unbounds);
287+
self.check_and_report_invalid_unbounds_on_param(trait_hir_id, unbounds);
265288

266289
let collected = collect_sizedness_bounds(tcx, hir_bounds, self_ty_where_predicates, span);
267-
if (collected.sized.maybe || collected.sized.negative)
268-
&& !collected.sized.positive
290+
if (collected.sized.maybe.is_some() || collected.sized.negative.is_some())
291+
&& !collected.sized.positive.is_some()
269292
&& !collected.meta_sized.any()
270293
&& !collected.pointee_sized.any()
271294
{
272295
// `?Sized` is equivalent to `const MetaSized` (but only add the bound if there aren't
273296
// any other explicit ones)
274297
add_trait_predicate(tcx, bounds, self_ty, meta_sized_did, span);
275298
add_host_effect_predicate(tcx, filter, bounds, self_ty, meta_sized_did, span);
299+
} else if let Some(bound_span) = collected.sized.positive
300+
&& !collected.sized.constness
301+
&& !tcx.sess.edition().at_least_edition_future()
302+
{
303+
// Emit migration lint when the feature is enabled.
304+
self.emit_sized_to_const_sized_lint(trait_hir_id, bound_span);
305+
306+
// Replace `Sized` with `const Sized`.
307+
add_trait_predicate(tcx, bounds, self_ty, sized_did, bound_span);
308+
add_host_effect_predicate(tcx, filter, bounds, self_ty, sized_did, bound_span);
276309
} else if !collected.any() {
277310
// If there are no explicit sizedness bounds then add a default `const Sized` bound.
278311
add_trait_predicate(tcx, bounds, self_ty, sized_did, span);
279-
add_host_effect_predicate(tcx, filter, bounds, self_ty, sized_did, span);
312+
313+
if !tcx.sess.edition().at_least_edition_future() {
314+
self.emit_default_sized_to_const_sized_lint(trait_hir_id, span);
315+
316+
add_host_effect_predicate(tcx, filter, bounds, self_ty, sized_did, span);
317+
}
280318
}
281319

282320
// See doc comment on `adjust_sizedness_predicates`.
@@ -476,7 +514,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
476514
self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>,
477515
) -> bool {
478516
let collected = collect_bounds(hir_bounds, self_ty_where_predicates, trait_def_id);
479-
!(collected.positive || collected.maybe || collected.negative)
517+
!(collected.positive.is_some() || collected.maybe.is_some() || collected.negative.is_some())
480518
}
481519

482520
/// Lower HIR bounds into `bounds` given the self type `param_ty` and the overarching late-bound vars if any.

compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs

+103-5
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,15 @@ use rustc_errors::{
77
};
88
use rustc_hir::def::{CtorOf, DefKind, Res};
99
use rustc_hir::def_id::DefId;
10-
use rustc_hir::{self as hir, LangItem, PolyTraitRef};
10+
use rustc_hir::{self as hir, HirId, LangItem, PolyTraitRef};
1111
use rustc_middle::bug;
1212
use rustc_middle::ty::fast_reject::{TreatParams, simplify_type};
1313
use rustc_middle::ty::print::{PrintPolyTraitRefExt as _, PrintTraitRefExt as _};
1414
use rustc_middle::ty::{
1515
self, AdtDef, GenericParamDefKind, Ty, TyCtxt, TypeVisitableExt,
1616
suggest_constraining_type_param,
1717
};
18+
use rustc_session::lint;
1819
use rustc_session::parse::feature_err;
1920
use rustc_span::edit_distance::find_best_match_for_name;
2021
use rustc_span::{BytePos, DUMMY_SP, Ident, Span, Symbol, kw, sym};
@@ -32,9 +33,10 @@ use crate::fluent_generated as fluent;
3233
use crate::hir_ty_lowering::{AssocItemQSelf, HirTyLowerer};
3334

3435
impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
35-
/// Check for multiple relaxed default bounds and relaxed bounds of non-sizedness traits.
36+
/// Check for multiple relaxed default bounds and relaxed bounds.
3637
pub(crate) fn check_and_report_invalid_unbounds_on_param(
3738
&self,
39+
trait_hir_id: HirId,
3840
unbounds: SmallVec<[&PolyTraitRef<'_>; 1]>,
3941
) {
4042
let tcx = self.tcx();
@@ -62,16 +64,41 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
6264
}
6365

6466
for unbound in unbounds {
65-
if let Res::Def(DefKind::Trait, did) = unbound.trait_ref.path.res
66-
&& ((did == sized_did) || tcx.is_default_trait(did))
67-
{
67+
let (is_sized, is_default_trait) =
68+
if let Res::Def(DefKind::Trait, did) = unbound.trait_ref.path.res {
69+
(did == sized_did, tcx.is_default_trait(did))
70+
} else {
71+
(false, false)
72+
};
73+
if (is_sized && !tcx.features().sized_hierarchy()) || is_default_trait {
6874
continue;
6975
}
7076

77+
if tcx.features().sized_hierarchy() && is_sized {
78+
tcx.node_span_lint(
79+
lint::builtin::SIZED_HIERARCHY_MIGRATION,
80+
trait_hir_id,
81+
unbound.span,
82+
|lint| {
83+
lint.primary_message(
84+
"`?Sized` bound relaxations are being migrated to `const MetaSized`",
85+
);
86+
lint.span_suggestion(
87+
unbound.span,
88+
"replace `?Sized` with `const MetaSized`",
89+
"const MetaSized",
90+
Applicability::MachineApplicable,
91+
);
92+
},
93+
);
94+
return;
95+
}
96+
7197
let unbound_traits = match tcx.sess.opts.unstable_opts.experimental_default_bounds {
7298
true => "`?Sized` and `experimental_default_bounds`",
7399
false => "`?Sized`",
74100
};
101+
// There was a `?Trait` bound, but it was not `?Sized`.
75102
self.dcx().span_err(
76103
unbound.span,
77104
format!(
@@ -83,6 +110,77 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
83110
}
84111
}
85112

113+
/// Emit lint adding a `const MetaSized` supertrait as part of sized hierarchy migration.
114+
pub(crate) fn emit_implicit_const_meta_sized_supertrait_lint(
115+
&self,
116+
trait_hir_id: HirId,
117+
span: Span,
118+
) {
119+
let tcx = self.tcx();
120+
if tcx.features().sized_hierarchy() {
121+
tcx.node_span_lint(
122+
lint::builtin::SIZED_HIERARCHY_MIGRATION,
123+
trait_hir_id,
124+
span,
125+
|lint| {
126+
lint.primary_message(
127+
"a `const MetaSized` supertrait is required to maintain backwards \
128+
compatibility",
129+
);
130+
lint.span_suggestion(
131+
span.shrink_to_hi(),
132+
"add an explicit `const MetaSized` supertrait",
133+
": const MetaSized",
134+
Applicability::MachineApplicable,
135+
);
136+
},
137+
);
138+
}
139+
}
140+
141+
/// Emit lint changing `Sized` bounds to `const MetaSized` bounds as part of sized hierarchy
142+
/// migration.
143+
pub(crate) fn emit_sized_to_const_sized_lint(&self, trait_hir_id: HirId, span: Span) {
144+
let tcx = self.tcx();
145+
if tcx.features().sized_hierarchy() {
146+
tcx.node_span_lint(
147+
lint::builtin::SIZED_HIERARCHY_MIGRATION,
148+
trait_hir_id,
149+
span,
150+
|lint| {
151+
lint.primary_message("`Sized` bounds are being migrated to `const Sized`");
152+
lint.span_suggestion(
153+
span,
154+
"replace `Sized` with `const Sized`",
155+
"const Sized",
156+
Applicability::MachineApplicable,
157+
);
158+
},
159+
);
160+
}
161+
}
162+
163+
/// Emit lint adding `const MetaSized` bound as part of sized hierarchy migration.
164+
pub(crate) fn emit_default_sized_to_const_sized_lint(&self, trait_hir_id: HirId, span: Span) {
165+
let tcx = self.tcx();
166+
if tcx.features().sized_hierarchy() {
167+
tcx.node_span_lint(
168+
lint::builtin::SIZED_HIERARCHY_MIGRATION,
169+
trait_hir_id,
170+
span,
171+
|lint| {
172+
lint.primary_message("default bounds are being migrated to `const Sized`");
173+
lint.span_suggestion(
174+
span.shrink_to_hi(),
175+
"add `const Sized`",
176+
": const Sized",
177+
Applicability::MachineApplicable,
178+
);
179+
},
180+
);
181+
}
182+
}
183+
86184
/// On missing type parameters, emit an E0393 error and provide a structured suggestion using
87185
/// the type parameter's name as a placeholder.
88186
pub(crate) fn complain_about_missing_type_params(

0 commit comments

Comments
 (0)