Skip to content

Commit 1ea7bfd

Browse files
Fix dyn incompleteness
1 parent f7786f7 commit 1ea7bfd

Some content is hidden

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

42 files changed

+608
-158
lines changed

compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs

Lines changed: 143 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
1-
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
1+
use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
22
use rustc_errors::codes::*;
33
use rustc_errors::struct_span_code_err;
44
use rustc_hir as hir;
5+
use rustc_hir::HirId;
56
use rustc_hir::def::{DefKind, Res};
6-
use rustc_lint_defs::builtin::UNUSED_ASSOCIATED_TYPE_BOUNDS;
7+
use rustc_hir::def_id::DefId;
8+
use rustc_lint_defs::builtin::{
9+
DYN_ASSOC_REDUNDANT, DYN_ASSOC_SHADOWED, UNUSED_ASSOCIATED_TYPE_BOUNDS,
10+
};
711
use rustc_middle::ty::fold::BottomUpFolder;
812
use rustc_middle::ty::{
913
self, DynKind, ExistentialPredicateStableCmpExt as _, Ty, TyCtxt, TypeFoldable,
@@ -28,7 +32,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
2832
pub(super) fn lower_trait_object_ty(
2933
&self,
3034
span: Span,
31-
hir_id: hir::HirId,
35+
hir_id: HirId,
3236
hir_bounds: &[hir::PolyTraitRef<'tcx>],
3337
lifetime: &hir::Lifetime,
3438
representation: DynKind,
@@ -80,12 +84,42 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
8084
}
8185
}
8286

83-
let (trait_bounds, mut projection_bounds) =
87+
let (expanded_trait_bounds, expanded_projection_bounds) =
8488
traits::expand_trait_aliases(tcx, user_written_bounds.clauses());
85-
let (regular_traits, mut auto_traits): (Vec<_>, Vec<_>) = trait_bounds
89+
let (regular_traits, mut auto_traits): (Vec<_>, Vec<_>) = expanded_trait_bounds
8690
.into_iter()
8791
.partition(|(trait_ref, _)| !tcx.trait_is_auto(trait_ref.def_id()));
8892

93+
// Map the projection bounds onto a key that makes it easy to remove redundant
94+
// bounds that are constrained by supertraits of the principal def id.
95+
let mut projection_bounds = FxIndexMap::default();
96+
for (proj, proj_span) in expanded_projection_bounds {
97+
if let Some((old_proj, old_proj_span)) = projection_bounds.insert(
98+
tcx.anonymize_bound_vars(proj.map_bound(|proj| proj.projection_term)),
99+
(proj, proj_span),
100+
) && tcx.anonymize_bound_vars(proj) != tcx.anonymize_bound_vars(old_proj)
101+
{
102+
let item = tcx.item_name(proj.item_def_id());
103+
self.dcx()
104+
.struct_span_err(
105+
span,
106+
format!(
107+
"conflicting associated type bounds for `{item}` when \
108+
expanding trait alias"
109+
),
110+
)
111+
.with_span_label(
112+
old_proj_span,
113+
format!("`{item}` is specified to be `{}` here", old_proj.term()),
114+
)
115+
.with_span_label(
116+
proj_span,
117+
format!("`{item}` is specified to be `{}` here", proj.term()),
118+
)
119+
.emit();
120+
}
121+
}
122+
89123
// We don't support empty trait objects.
90124
if regular_traits.is_empty() && auto_traits.is_empty() {
91125
let guar =
@@ -105,6 +139,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
105139
let principal_trait = regular_traits.into_iter().next();
106140

107141
let mut needed_associated_types = FxIndexSet::default();
142+
143+
// These are the projection bounds that we get from supertraits that
144+
// don't mention the dyn trait recursively. See comment below.
145+
let mut implied_projection_bounds = vec![];
146+
108147
if let Some((principal_trait, spans)) = &principal_trait {
109148
let pred: ty::Predicate<'tcx> = (*principal_trait).upcast(tcx);
110149
for ClauseWithSupertraitSpan { pred, supertrait_span } in
@@ -134,14 +173,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
134173
);
135174
}
136175
ty::PredicateKind::Clause(ty::ClauseKind::Projection(pred)) => {
137-
let pred = bound_predicate.rebind(pred);
176+
let elaborated_projection = bound_predicate.rebind(pred);
138177
// A `Self` within the original bound will be instantiated with a
139178
// `trait_object_dummy_self`, so check for that.
140-
let references_self = match pred.skip_binder().term.unpack() {
141-
ty::TermKind::Ty(ty) => ty.walk().any(|arg| arg == dummy_self.into()),
142-
// FIXME(associated_const_equality): We should walk the const instead of not doing anything
143-
ty::TermKind::Const(_) => false,
144-
};
179+
let references_self =
180+
match elaborated_projection.skip_binder().term.unpack() {
181+
ty::TermKind::Ty(ty) => {
182+
ty.walk().any(|arg| arg == dummy_self.into())
183+
}
184+
// FIXME(associated_const_equality): We should walk the const instead of not doing anything
185+
ty::TermKind::Const(_) => false,
186+
};
145187

146188
// If the projection output contains `Self`, force the user to
147189
// elaborate it explicitly to avoid a lot of complexity.
@@ -162,11 +204,38 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
162204
// the discussion in #56288 for alternatives.
163205
if !references_self {
164206
// Include projections defined on supertraits.
165-
projection_bounds.push((pred, supertrait_span));
207+
implied_projection_bounds.push(elaborated_projection);
208+
209+
if let Some((user_written_projection, user_written_span)) =
210+
projection_bounds.shift_remove(&tcx.anonymize_bound_vars(
211+
elaborated_projection.map_bound(|pred| pred.projection_term),
212+
))
213+
{
214+
if tcx.anonymize_bound_vars(user_written_projection)
215+
== tcx.anonymize_bound_vars(elaborated_projection)
216+
{
217+
self.lint_redundant_projection(
218+
hir_id,
219+
user_written_projection,
220+
principal_trait.def_id(),
221+
user_written_span,
222+
supertrait_span,
223+
);
224+
} else {
225+
self.lint_shadowed_projection(
226+
hir_id,
227+
user_written_projection,
228+
elaborated_projection,
229+
principal_trait.def_id(),
230+
user_written_span,
231+
supertrait_span,
232+
);
233+
}
234+
}
166235
}
167236

168237
self.check_elaborated_projection_mentions_input_lifetimes(
169-
pred,
238+
elaborated_projection,
170239
*spans.first().unwrap(),
171240
supertrait_span,
172241
);
@@ -176,16 +245,16 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
176245
}
177246
}
178247

179-
// `dyn Trait<Assoc = Foo>` desugars to (not Rust syntax) `dyn Trait where <Self as Trait>::Assoc = Foo`.
180-
// So every `Projection` clause is an `Assoc = Foo` bound. `associated_types` contains all associated
181-
// types's `DefId`, so the following loop removes all the `DefIds` of the associated types that have a
182-
// corresponding `Projection` clause
183-
for (projection_bound, span) in &projection_bounds {
248+
// `dyn Trait<Assoc = Foo>` desugars to something like `dyn Trait + (Trait::Assoc = Foo)`.
249+
// So every `Projection` clause is an `Assoc = Foo` bound. `associated_types`
250+
// contains all associated types's `DefId`, so the following loop removes all
251+
// the `DefIds` of the associated types that have a corresponding `Projection`.
252+
for &(projection_bound, span) in projection_bounds.values() {
184253
let def_id = projection_bound.item_def_id();
185254
let trait_ref = tcx.anonymize_bound_vars(
186255
projection_bound.map_bound(|p| p.projection_term.trait_ref(tcx)),
187256
);
188-
needed_associated_types.swap_remove(&(def_id, trait_ref));
257+
needed_associated_types.shift_remove(&(def_id, trait_ref));
189258
if tcx.generics_require_sized_self(def_id) {
190259
tcx.emit_node_span_lint(
191260
UNUSED_ASSOCIATED_TYPE_BOUNDS,
@@ -195,6 +264,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
195264
);
196265
}
197266
}
267+
for projection_bound in &implied_projection_bounds {
268+
let def_id = projection_bound.item_def_id();
269+
let trait_ref = tcx.anonymize_bound_vars(
270+
projection_bound.map_bound(|p| p.projection_term.trait_ref(tcx)),
271+
);
272+
needed_associated_types.swap_remove(&(def_id, trait_ref));
273+
}
198274

199275
if let Err(guar) = self.check_for_required_assoc_tys(
200276
principal_trait.as_ref().map_or(smallvec![], |(_, spans)| spans.clone()),
@@ -272,7 +348,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
272348
})
273349
});
274350

275-
let existential_projections = projection_bounds.iter().map(|(bound, _)| {
351+
let existential_projections = projection_bounds.values().map(|(bound, _)| {
276352
bound.map_bound(|mut b| {
277353
assert_eq!(b.projection_term.self_ty(), dummy_self);
278354

@@ -349,6 +425,53 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
349425
Ty::new_dynamic(tcx, existential_predicates, region_bound, representation)
350426
}
351427

428+
fn lint_shadowed_projection(
429+
&self,
430+
hir_id: HirId,
431+
user_written_projection: ty::PolyProjectionPredicate<'tcx>,
432+
elaborated_projection: ty::PolyProjectionPredicate<'tcx>,
433+
principal_def_id: DefId,
434+
user_written_span: Span,
435+
supertrait_span: Span,
436+
) {
437+
let tcx = self.tcx();
438+
let assoc = tcx.item_name(user_written_projection.item_def_id());
439+
let principal = tcx.item_name(principal_def_id);
440+
self.tcx().node_span_lint(DYN_ASSOC_SHADOWED, hir_id, user_written_span, |diag| {
441+
diag.primary_message(format!(
442+
"associated type bound for `{assoc}` in `dyn {principal}` differs from \
443+
associated type bound implied by supertrait",
444+
));
445+
diag.span_label(user_written_span, "this bound has no effect and will be ignored");
446+
diag.note(format!(
447+
"`{assoc} = {}` was implied by a supertrait and shadows any user-written bounds, \
448+
so `{assoc} = {}` will be ignored",
449+
elaborated_projection.term(),
450+
user_written_projection.term(),
451+
));
452+
diag.span_label(supertrait_span, "shadowed due to this supertrait bound");
453+
});
454+
}
455+
456+
fn lint_redundant_projection(
457+
&self,
458+
hir_id: HirId,
459+
user_written_projection: ty::PolyProjectionPredicate<'tcx>,
460+
principal_def_id: DefId,
461+
user_written_span: Span,
462+
supertrait_span: Span,
463+
) {
464+
let tcx = self.tcx();
465+
let assoc = tcx.item_name(user_written_projection.item_def_id());
466+
let principal = tcx.item_name(principal_def_id);
467+
self.tcx().node_span_lint(DYN_ASSOC_REDUNDANT, hir_id, user_written_span, |diag| {
468+
diag.primary_message(format!(
469+
"associated type bound for `{assoc}` in `dyn {principal}` is redundant",
470+
));
471+
diag.span_label(supertrait_span, "redundant due to this supertrait bound");
472+
});
473+
}
474+
352475
/// Check that elaborating the principal of a trait ref doesn't lead to projections
353476
/// that are unconstrained. This can happen because an otherwise unconstrained
354477
/// *type variable* can be substituted with a type that has late-bound regions. See

compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -722,7 +722,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
722722
/// emit a generic note suggesting using a `where` clause to constraint instead.
723723
pub(crate) fn check_for_required_assoc_tys(
724724
&self,
725-
principal_span: Span,
725+
spans: SmallVec<[Span; 1]>,
726726
missing_assoc_types: FxIndexSet<(DefId, ty::PolyTraitRef<'tcx>)>,
727727
potential_assoc_types: Vec<usize>,
728728
trait_bounds: &[hir::PolyTraitRef<'_>],

compiler/rustc_hir_typeck/src/closure.rs

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use rustc_span::def_id::LocalDefId;
1818
use rustc_span::{DUMMY_SP, Span};
1919
use rustc_trait_selection::error_reporting::traits::ArgKind;
2020
use rustc_trait_selection::traits;
21-
use rustc_type_ir::ClosureKind;
21+
use rustc_type_ir::{ClosureKind, Upcast as _};
2222
use tracing::{debug, instrument, trace};
2323

2424
use super::{CoroutineTypes, Expectation, FnCtxt, check_fn};
@@ -312,16 +312,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
312312
.iter_instantiated_copied(self.tcx, args)
313313
.map(|(c, s)| (c.as_predicate(), s)),
314314
),
315-
ty::Dynamic(object_type, ..) => {
316-
let sig = object_type.projection_bounds().find_map(|pb| {
317-
let pb = pb.with_self_ty(self.tcx, self.tcx.types.trait_object_dummy_self);
318-
self.deduce_sig_from_projection(None, closure_kind, pb)
319-
});
320-
let kind = object_type
321-
.principal_def_id()
322-
.and_then(|did| self.tcx.fn_trait_kind_from_def_id(did));
323-
(sig, kind)
324-
}
315+
ty::Dynamic(data, ..) => self.deduce_closure_signature_from_predicates(
316+
self.tcx.types.trait_object_dummy_self,
317+
closure_kind,
318+
data.iter().map(|bound| {
319+
(
320+
bound
321+
.with_self_ty(self.tcx, self.tcx.types.trait_object_dummy_self)
322+
.upcast(self.tcx),
323+
DUMMY_SP,
324+
)
325+
}),
326+
),
325327
ty::Infer(ty::TyVar(vid)) => self.deduce_closure_signature_from_predicates(
326328
Ty::new_var(self.tcx, self.root_var(vid)),
327329
closure_kind,

compiler/rustc_lint_defs/src/builtin.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ declare_lint_pass! {
3939
DEPRECATED_SAFE_2024,
4040
DEPRECATED_WHERE_CLAUSE_LOCATION,
4141
DUPLICATE_MACRO_ATTRIBUTES,
42+
DYN_ASSOC_REDUNDANT,
43+
DYN_ASSOC_SHADOWED,
4244
ELIDED_LIFETIMES_IN_ASSOCIATED_CONSTANT,
4345
ELIDED_LIFETIMES_IN_PATHS,
4446
ELIDED_NAMED_LIFETIMES,
@@ -5113,6 +5115,20 @@ declare_lint! {
51135115
crate_level_only
51145116
}
51155117

5118+
declare_lint! {
5119+
/// Hi
5120+
pub DYN_ASSOC_REDUNDANT,
5121+
Warn,
5122+
"oops",
5123+
}
5124+
5125+
declare_lint! {
5126+
/// Hi
5127+
pub DYN_ASSOC_SHADOWED,
5128+
Deny,
5129+
"oops",
5130+
}
5131+
51165132
declare_lint! {
51175133
/// The `abi_unsupported_vector_types` lint detects function definitions and calls
51185134
/// whose ABI depends on enabling certain target features, but those features are not enabled.

compiler/rustc_middle/src/ty/relate.rs

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -80,19 +80,12 @@ impl<'tcx> Relate<TyCtxt<'tcx>> for &'tcx ty::List<ty::PolyExistentialPredicate<
8080
) -> RelateResult<'tcx, Self> {
8181
let tcx = relation.cx();
8282

83-
// FIXME: this is wasteful, but want to do a perf run to see how slow it is.
84-
// We need to perform this deduplication as we sometimes generate duplicate projections
85-
// in `a`.
86-
let mut a_v: Vec<_> = a.into_iter().collect();
87-
let mut b_v: Vec<_> = b.into_iter().collect();
88-
a_v.dedup();
89-
b_v.dedup();
90-
if a_v.len() != b_v.len() {
83+
if a.len() != b.len() {
9184
return Err(TypeError::ExistentialMismatch(ExpectedFound::new(a, b)));
9285
}
9386

94-
let v = iter::zip(a_v, b_v).map(|(ep_a, ep_b)| {
95-
match (ep_a.skip_binder(), ep_b.skip_binder()) {
87+
let v =
88+
iter::zip(a, b).map(|(ep_a, ep_b)| match (ep_a.skip_binder(), ep_b.skip_binder()) {
9689
(ty::ExistentialPredicate::Trait(a), ty::ExistentialPredicate::Trait(b)) => {
9790
Ok(ep_a.rebind(ty::ExistentialPredicate::Trait(
9891
relation.relate(ep_a.rebind(a), ep_b.rebind(b))?.skip_binder(),
@@ -109,8 +102,7 @@ impl<'tcx> Relate<TyCtxt<'tcx>> for &'tcx ty::List<ty::PolyExistentialPredicate<
109102
ty::ExistentialPredicate::AutoTrait(b),
110103
) if a == b => Ok(ep_a.rebind(ty::ExistentialPredicate::AutoTrait(a))),
111104
_ => Err(TypeError::ExistentialMismatch(ExpectedFound::new(a, b))),
112-
}
113-
});
105+
});
114106
tcx.mk_poly_existential_predicates_from_iter(v)
115107
}
116108
}

compiler/rustc_middle/src/ty/sty.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -982,6 +982,10 @@ impl<'tcx> rustc_type_ir::inherent::Ty<TyCtxt<'tcx>> for Ty<'tcx> {
982982
fn has_unsafe_fields(self) -> bool {
983983
Ty::has_unsafe_fields(self)
984984
}
985+
986+
fn is_self_param(self) -> bool {
987+
self.is_param(0)
988+
}
985989
}
986990

987991
/// Type utilities

compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -696,6 +696,15 @@ where
696696
assumption.upcast(cx),
697697
));
698698
}
699+
700+
for assumption in elaborate::implied_supertrait_projections(cx, principal) {
701+
candidates.extend(G::probe_and_consider_object_bound_candidate(
702+
self,
703+
CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
704+
goal,
705+
assumption.with_self_ty(cx, self_ty).upcast(cx),
706+
));
707+
}
699708
}
700709
}
701710

0 commit comments

Comments
 (0)