Skip to content

Commit 4a38b55

Browse files
Rework trait expansion to happen once explicitly
1 parent 83ab648 commit 4a38b55

26 files changed

+552
-635
lines changed

compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs

+78-111
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,12 @@ use rustc_errors::struct_span_code_err;
44
use rustc_hir as hir;
55
use rustc_hir::def::{DefKind, Res};
66
use rustc_lint_defs::builtin::UNUSED_ASSOCIATED_TYPE_BOUNDS;
7-
use rustc_middle::span_bug;
87
use rustc_middle::ty::fold::BottomUpFolder;
98
use rustc_middle::ty::{
109
self, DynKind, ExistentialPredicateStableCmpExt as _, Ty, TyCtxt, TypeFoldable,
1110
TypeVisitableExt, Upcast,
1211
};
13-
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span};
12+
use rustc_span::{ErrorGuaranteed, Span};
1413
use rustc_trait_selection::error_reporting::traits::report_dyn_incompatibility;
1514
use rustc_trait_selection::traits::{self, hir_ty_lowering_dyn_compatibility_violations};
1615
use rustc_type_ir::elaborate::ClauseWithSupertraitSpan;
@@ -30,16 +29,16 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
3029
&self,
3130
span: Span,
3231
hir_id: hir::HirId,
33-
hir_trait_bounds: &[hir::PolyTraitRef<'tcx>],
32+
hir_bounds: &[hir::PolyTraitRef<'tcx>],
3433
lifetime: &hir::Lifetime,
3534
representation: DynKind,
3635
) -> Ty<'tcx> {
3736
let tcx = self.tcx();
37+
let dummy_self = tcx.types.trait_object_dummy_self;
3838

39-
let mut bounds = Bounds::default();
39+
let mut user_written_bounds = Bounds::default();
4040
let mut potential_assoc_types = Vec::new();
41-
let dummy_self = self.tcx().types.trait_object_dummy_self;
42-
for trait_bound in hir_trait_bounds.iter().rev() {
41+
for trait_bound in hir_bounds.iter() {
4342
if let hir::BoundPolarity::Maybe(_) = trait_bound.modifiers.polarity {
4443
continue;
4544
}
@@ -53,92 +52,67 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
5352
hir::BoundConstness::Never,
5453
hir::BoundPolarity::Positive,
5554
dummy_self,
56-
&mut bounds,
55+
&mut user_written_bounds,
5756
PredicateFilter::SelfOnly,
5857
) {
5958
potential_assoc_types.extend(cur_potential_assoc_types);
6059
}
6160
}
6261

63-
let mut trait_bounds = vec![];
64-
let mut projection_bounds = vec![];
65-
for (pred, span) in bounds.clauses() {
66-
let bound_pred = pred.kind();
67-
match bound_pred.skip_binder() {
68-
ty::ClauseKind::Trait(trait_pred) => {
69-
assert_eq!(trait_pred.polarity, ty::PredicatePolarity::Positive);
70-
trait_bounds.push((bound_pred.rebind(trait_pred.trait_ref), span));
71-
}
72-
ty::ClauseKind::Projection(proj) => {
73-
projection_bounds.push((bound_pred.rebind(proj), span));
74-
}
75-
ty::ClauseKind::TypeOutlives(_) => {
76-
// Do nothing, we deal with regions separately
77-
}
78-
ty::ClauseKind::RegionOutlives(_)
79-
| ty::ClauseKind::ConstArgHasType(..)
80-
| ty::ClauseKind::WellFormed(_)
81-
| ty::ClauseKind::ConstEvaluatable(_)
82-
| ty::ClauseKind::HostEffect(..) => {
83-
span_bug!(span, "did not expect {pred} clause in object bounds");
84-
}
85-
}
86-
}
87-
88-
// Expand trait aliases recursively and check that only one regular (non-auto) trait
89-
// is used and no 'maybe' bounds are used.
90-
let expanded_traits =
91-
traits::expand_trait_aliases(tcx, trait_bounds.iter().map(|&(a, b)| (a, b)));
92-
93-
let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) =
94-
expanded_traits.partition(|i| tcx.trait_is_auto(i.trait_ref().def_id()));
62+
let (trait_bounds, mut projection_bounds) =
63+
traits::expand_trait_aliases(tcx, user_written_bounds.clauses());
64+
let (regular_traits, mut auto_traits): (Vec<_>, Vec<_>) = trait_bounds
65+
.into_iter()
66+
.partition(|(trait_ref, _)| !tcx.trait_is_auto(trait_ref.def_id()));
9567

68+
// We don't support empty trait objects.
69+
if regular_traits.is_empty() && auto_traits.is_empty() {
70+
let guar =
71+
self.report_trait_object_with_no_traits_error(span, user_written_bounds.clauses());
72+
return Ty::new_error(tcx, guar);
73+
}
9674
// We don't support >1 principal
9775
if regular_traits.len() > 1 {
9876
let guar = self.report_trait_object_addition_traits_error(&regular_traits);
9977
return Ty::new_error(tcx, guar);
10078
}
101-
// We don't support empty trait objects.
102-
if regular_traits.is_empty() && auto_traits.is_empty() {
103-
let guar = self.report_trait_object_with_no_traits_error(span, &trait_bounds);
104-
return Ty::new_error(tcx, guar);
105-
}
10679
// Don't create a dyn trait if we have errors in the principal.
107-
if let Err(guar) = trait_bounds.error_reported() {
80+
if let Err(guar) = regular_traits.error_reported() {
10881
return Ty::new_error(tcx, guar);
10982
}
11083

11184
// Check that there are no gross dyn-compatibility violations;
11285
// most importantly, that the supertraits don't contain `Self`,
11386
// to avoid ICEs.
114-
for item in &regular_traits {
115-
let violations =
116-
hir_ty_lowering_dyn_compatibility_violations(tcx, item.trait_ref().def_id());
117-
if !violations.is_empty() {
118-
let reported = report_dyn_incompatibility(
119-
tcx,
120-
span,
121-
Some(hir_id),
122-
item.trait_ref().def_id(),
123-
&violations,
124-
)
125-
.emit();
126-
return Ty::new_error(tcx, reported);
87+
for (clause, span) in user_written_bounds.clauses() {
88+
if let Some(trait_pred) = clause.as_trait_clause() {
89+
let violations =
90+
hir_ty_lowering_dyn_compatibility_violations(tcx, trait_pred.def_id());
91+
if !violations.is_empty() {
92+
let reported = report_dyn_incompatibility(
93+
tcx,
94+
span,
95+
Some(hir_id),
96+
trait_pred.def_id(),
97+
&violations,
98+
)
99+
.emit();
100+
return Ty::new_error(tcx, reported);
101+
}
127102
}
128103
}
129104

130-
let mut needed_associated_types = FxIndexSet::default();
131-
132-
let principal_span = regular_traits.first().map_or(DUMMY_SP, |info| info.bottom().1);
133-
let regular_traits_refs_spans = trait_bounds
134-
.into_iter()
135-
.filter(|(trait_ref, _)| !tcx.trait_is_auto(trait_ref.def_id()));
105+
let principal_trait = regular_traits.into_iter().next();
136106

137-
for (base_trait_ref, original_span) in regular_traits_refs_spans {
138-
let base_pred: ty::Predicate<'tcx> = base_trait_ref.upcast(tcx);
107+
let mut needed_associated_types = FxIndexSet::default();
108+
if let Some((principal_trait, spans)) = &principal_trait {
109+
let pred: ty::Predicate<'tcx> = (*principal_trait).upcast(tcx);
139110
for ClauseWithSupertraitSpan { pred, supertrait_span } in
140-
traits::elaborate(tcx, [ClauseWithSupertraitSpan::new(base_pred, original_span)])
141-
.filter_only_self()
111+
traits::elaborate(tcx, [ClauseWithSupertraitSpan::new(
112+
pred,
113+
*spans.last().unwrap(),
114+
)])
115+
.filter_only_self()
142116
{
143117
debug!("observing object predicate `{pred:?}`");
144118

@@ -188,12 +162,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
188162
// the discussion in #56288 for alternatives.
189163
if !references_self {
190164
// Include projections defined on supertraits.
191-
projection_bounds.push((pred, original_span));
165+
projection_bounds.push((pred, supertrait_span));
192166
}
193167

194168
self.check_elaborated_projection_mentions_input_lifetimes(
195169
pred,
196-
original_span,
170+
*spans.first().unwrap(),
197171
supertrait_span,
198172
);
199173
}
@@ -206,7 +180,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
206180
// So every `Projection` clause is an `Assoc = Foo` bound. `associated_types` contains all associated
207181
// types's `DefId`, so the following loop removes all the `DefIds` of the associated types that have a
208182
// corresponding `Projection` clause
209-
for (projection_bound, span) in &projection_bounds {
183+
for &(projection_bound, span) in &projection_bounds {
210184
let def_id = projection_bound.item_def_id();
211185
let trait_ref = tcx.anonymize_bound_vars(
212186
projection_bound.map_bound(|p| p.projection_term.trait_ref(tcx)),
@@ -216,17 +190,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
216190
tcx.emit_node_span_lint(
217191
UNUSED_ASSOCIATED_TYPE_BOUNDS,
218192
hir_id,
219-
*span,
220-
crate::errors::UnusedAssociatedTypeBounds { span: *span },
193+
span,
194+
crate::errors::UnusedAssociatedTypeBounds { span },
221195
);
222196
}
223197
}
224198

225199
if let Err(guar) = self.check_for_required_assoc_tys(
226-
principal_span,
200+
principal_trait.as_ref().map_or(smallvec![], |(_, spans)| spans.clone()),
227201
needed_associated_types,
228202
potential_assoc_types,
229-
hir_trait_bounds,
203+
hir_bounds,
230204
) {
231205
return Ty::new_error(tcx, guar);
232206
}
@@ -236,15 +210,20 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
236210
// We remove duplicates by inserting into a `FxHashSet` to avoid re-ordering
237211
// the bounds
238212
let mut duplicates = FxHashSet::default();
239-
auto_traits.retain(|i| duplicates.insert(i.trait_ref().def_id()));
240-
debug!(?regular_traits);
213+
auto_traits.retain(|(trait_pred, _)| duplicates.insert(trait_pred.def_id()));
214+
215+
debug!(?principal_trait);
241216
debug!(?auto_traits);
242217

243218
// Erase the `dummy_self` (`trait_object_dummy_self`) used above.
244-
let existential_trait_refs = regular_traits.iter().map(|i| {
245-
i.trait_ref().map_bound(|trait_ref: ty::TraitRef<'tcx>| {
219+
let principal_trait_ref = principal_trait.map(|(trait_pred, spans)| {
220+
trait_pred.map_bound(|trait_pred| {
221+
let trait_ref = trait_pred.trait_ref;
222+
assert_eq!(trait_pred.polarity, ty::PredicatePolarity::Positive);
246223
assert_eq!(trait_ref.self_ty(), dummy_self);
247224

225+
let span = *spans.first().unwrap();
226+
248227
// Verify that `dummy_self` did not leak inside default type parameters. This
249228
// could not be done at path creation, since we need to see through trait aliases.
250229
let mut missing_type_params = vec![];
@@ -254,7 +233,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
254233
.args
255234
.iter()
256235
.enumerate()
257-
.skip(1) // Remove `Self` for `ExistentialPredicate`.
236+
// Skip `Self`
237+
.skip(1)
258238
.map(|(index, arg)| {
259239
if arg == dummy_self.into() {
260240
let param = &generics.own_params[index];
@@ -273,8 +253,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
273253
})
274254
.collect();
275255

276-
let span = i.bottom().1;
277-
let empty_generic_args = hir_trait_bounds.iter().any(|hir_bound| {
256+
let empty_generic_args = hir_bounds.iter().any(|hir_bound| {
278257
hir_bound.trait_ref.path.res == Res::Def(DefKind::Trait, trait_ref.def_id)
279258
&& hir_bound.span.contains(span)
280259
});
@@ -285,26 +264,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
285264
empty_generic_args,
286265
);
287266

288-
if references_self {
289-
let def_id = i.bottom().0.def_id();
290-
struct_span_code_err!(
291-
self.dcx(),
292-
i.bottom().1,
293-
E0038,
294-
"the {} `{}` cannot be made into an object",
295-
tcx.def_descr(def_id),
296-
tcx.item_name(def_id),
297-
)
298-
.with_note(
299-
rustc_middle::traits::DynCompatibilityViolation::SupertraitSelf(
300-
smallvec![],
301-
)
302-
.error_msg(),
303-
)
304-
.emit();
305-
}
306-
307-
ty::ExistentialTraitRef::new(tcx, trait_ref.def_id, args)
267+
ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::new(
268+
tcx,
269+
trait_ref.def_id,
270+
args,
271+
))
308272
})
309273
});
310274

@@ -327,21 +291,24 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
327291
b.projection_term = replace_dummy_self_with_error(tcx, b.projection_term, guar);
328292
}
329293

330-
ty::ExistentialProjection::erase_self_ty(tcx, b)
294+
ty::ExistentialPredicate::Projection(ty::ExistentialProjection::erase_self_ty(
295+
tcx, b,
296+
))
331297
})
332298
});
333299

334-
let regular_trait_predicates = existential_trait_refs
335-
.map(|trait_ref| trait_ref.map_bound(ty::ExistentialPredicate::Trait));
336-
let auto_trait_predicates = auto_traits.into_iter().map(|trait_ref| {
337-
ty::Binder::dummy(ty::ExistentialPredicate::AutoTrait(trait_ref.trait_ref().def_id()))
300+
let auto_trait_predicates = auto_traits.into_iter().map(|(trait_pred, _)| {
301+
assert_eq!(trait_pred.polarity(), ty::PredicatePolarity::Positive);
302+
assert_eq!(trait_pred.self_ty().skip_binder(), dummy_self);
303+
304+
ty::Binder::dummy(ty::ExistentialPredicate::AutoTrait(trait_pred.def_id()))
338305
});
306+
339307
// N.b. principal, projections, auto traits
340308
// FIXME: This is actually wrong with multiple principals in regards to symbol mangling
341-
let mut v = regular_trait_predicates
342-
.chain(
343-
existential_projections.map(|x| x.map_bound(ty::ExistentialPredicate::Projection)),
344-
)
309+
let mut v = principal_trait_ref
310+
.into_iter()
311+
.chain(existential_projections)
345312
.chain(auto_trait_predicates)
346313
.collect::<SmallVec<[_; 8]>>();
347314
v.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder()));

0 commit comments

Comments
 (0)