Skip to content

Commit fb307f9

Browse files
committed
Add a simpler and more targetted code path for impl trait in assoc items
1 parent 0ee9cfd commit fb307f9

File tree

4 files changed

+92
-8
lines changed

4 files changed

+92
-8
lines changed

compiler/rustc_hir_analysis/src/collect/type_of.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -526,9 +526,13 @@ pub(super) fn type_of_opaque(
526526
Ok(ty::EarlyBinder::bind(match tcx.hir_node_by_def_id(def_id) {
527527
Node::Item(item) => match item.kind {
528528
ItemKind::OpaqueTy(OpaqueTy {
529-
origin: hir::OpaqueTyOrigin::TyAlias { .. },
529+
origin: hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: false },
530530
..
531531
}) => opaque::find_opaque_ty_constraints_for_tait(tcx, def_id),
532+
ItemKind::OpaqueTy(OpaqueTy {
533+
origin: hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: true },
534+
..
535+
}) => opaque::find_opaque_ty_constraints_for_impl_trait_in_assoc_type(tcx, def_id),
532536
// Opaque types desugared from `impl Trait`.
533537
ItemKind::OpaqueTy(&OpaqueTy {
534538
origin:

compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs

Lines changed: 69 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,64 @@ pub fn test_opaque_hidden_types(tcx: TyCtxt<'_>) {
2121
}
2222
}
2323

24+
/// Checks "defining uses" of opaque `impl Trait` in associated types.
25+
/// These can only be defined by associated items of the same trait.
26+
#[instrument(skip(tcx), level = "debug")]
27+
pub(super) fn find_opaque_ty_constraints_for_impl_trait_in_assoc_type(
28+
tcx: TyCtxt<'_>,
29+
def_id: LocalDefId,
30+
) -> Ty<'_> {
31+
let mut parent_def_id = def_id;
32+
while tcx.def_kind(parent_def_id) == def::DefKind::OpaqueTy {
33+
// Account for `type Alias = impl Trait<Foo = impl Trait>;` (#116031)
34+
parent_def_id = tcx.local_parent(parent_def_id);
35+
}
36+
let impl_def_id = tcx.local_parent(parent_def_id);
37+
match tcx.def_kind(impl_def_id) {
38+
DefKind::Impl { of_trait: true } => {}
39+
// Fixme(inherent_associated_types): what is even the expected behaviour of these?
40+
DefKind::Impl { of_trait: false } => {
41+
return find_opaque_ty_constraints_for_tait(tcx, def_id);
42+
}
43+
other => bug!("invalid impl trait in assoc type parent: {other:?}"),
44+
}
45+
46+
let mut locator = TaitConstraintLocator { def_id, tcx, found: None, typeck_types: vec![] };
47+
48+
for &assoc_id in tcx.associated_item_def_ids(impl_def_id) {
49+
let assoc = tcx.associated_item(assoc_id);
50+
match assoc.kind {
51+
ty::AssocKind::Const | ty::AssocKind::Fn => {
52+
locator.check(assoc_id.expect_local(), true)
53+
}
54+
// Associated types don't have bodies, so they can't constrain hidden types
55+
ty::AssocKind::Type => {}
56+
}
57+
}
58+
59+
if let Some(hidden) = locator.found {
60+
// Only check against typeck if we didn't already error
61+
if !hidden.ty.references_error() {
62+
for concrete_type in locator.typeck_types {
63+
if concrete_type.ty != tcx.erase_regions(hidden.ty)
64+
&& !(concrete_type, hidden).references_error()
65+
{
66+
hidden.report_mismatch(&concrete_type, def_id, tcx).emit();
67+
}
68+
}
69+
}
70+
71+
hidden.ty
72+
} else {
73+
let reported = tcx.dcx().emit_err(UnconstrainedOpaqueType {
74+
span: tcx.def_span(def_id),
75+
name: tcx.item_name(parent_def_id.to_def_id()),
76+
what: "impl",
77+
});
78+
Ty::new_error(tcx, reported)
79+
}
80+
}
81+
2482
/// Checks "defining uses" of opaque `impl Trait` types to ensure that they meet the restrictions
2583
/// laid for "higher-order pattern unification".
2684
/// This ensures that inference is tractable.
@@ -128,7 +186,7 @@ struct TaitConstraintLocator<'tcx> {
128186

129187
impl TaitConstraintLocator<'_> {
130188
#[instrument(skip(self), level = "debug")]
131-
fn check(&mut self, item_def_id: LocalDefId) {
189+
fn check(&mut self, item_def_id: LocalDefId, impl_trait_in_assoc_type: bool) {
132190
// Don't try to check items that cannot possibly constrain the type.
133191
if !self.tcx.has_typeck_results(item_def_id) {
134192
debug!("no constraint: no typeck results");
@@ -158,7 +216,12 @@ impl TaitConstraintLocator<'_> {
158216
continue;
159217
}
160218
constrained = true;
161-
if !self.tcx.opaque_types_defined_by(item_def_id).contains(&self.def_id) {
219+
let opaque_types_defined_by = if impl_trait_in_assoc_type {
220+
self.tcx.impl_trait_in_assoc_types_defined_by(item_def_id)
221+
} else {
222+
self.tcx.opaque_types_defined_by(item_def_id)
223+
};
224+
if !opaque_types_defined_by.contains(&self.def_id) {
162225
self.tcx.dcx().emit_err(TaitForwardCompat {
163226
span: hidden_type.span,
164227
item_span: self
@@ -216,29 +279,29 @@ impl<'tcx> intravisit::Visitor<'tcx> for TaitConstraintLocator<'tcx> {
216279
}
217280
fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
218281
if let hir::ExprKind::Closure(closure) = ex.kind {
219-
self.check(closure.def_id);
282+
self.check(closure.def_id, false);
220283
}
221284
intravisit::walk_expr(self, ex);
222285
}
223286
fn visit_item(&mut self, it: &'tcx Item<'tcx>) {
224287
trace!(?it.owner_id);
225288
// The opaque type itself or its children are not within its reveal scope.
226289
if it.owner_id.def_id != self.def_id {
227-
self.check(it.owner_id.def_id);
290+
self.check(it.owner_id.def_id, false);
228291
intravisit::walk_item(self, it);
229292
}
230293
}
231294
fn visit_impl_item(&mut self, it: &'tcx ImplItem<'tcx>) {
232295
trace!(?it.owner_id);
233296
// The opaque type itself or its children are not within its reveal scope.
234297
if it.owner_id.def_id != self.def_id {
235-
self.check(it.owner_id.def_id);
298+
self.check(it.owner_id.def_id, false);
236299
intravisit::walk_impl_item(self, it);
237300
}
238301
}
239302
fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) {
240303
trace!(?it.owner_id);
241-
self.check(it.owner_id.def_id);
304+
self.check(it.owner_id.def_id, false);
242305
intravisit::walk_trait_item(self, it);
243306
}
244307
fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem<'tcx>) {

compiler/rustc_middle/src/query/mod.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,15 @@ rustc_queries! {
351351
}
352352
}
353353

354+
query impl_trait_in_assoc_types_defined_by(
355+
key: LocalDefId
356+
) -> &'tcx ty::List<LocalDefId> {
357+
desc {
358+
|tcx| "computing the opaque types defined by `{}`",
359+
tcx.def_path_str(key.to_def_id())
360+
}
361+
}
362+
354363
/// Returns the list of bounds that can be used for
355364
/// `SelectionCandidate::ProjectionCandidate(_)` and
356365
/// `ProjectionTyCandidate::TraitDef`.

compiler/rustc_ty_utils/src/opaque_types.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,13 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OpaqueTypeCollector<'tcx> {
272272
}
273273
}
274274

275+
fn impl_trait_in_assoc_types_defined_by<'tcx>(
276+
tcx: TyCtxt<'tcx>,
277+
item: LocalDefId,
278+
) -> &'tcx ty::List<LocalDefId> {
279+
opaque_types_defined_by(tcx, item)
280+
}
281+
275282
fn opaque_types_defined_by<'tcx>(
276283
tcx: TyCtxt<'tcx>,
277284
item: LocalDefId,
@@ -321,5 +328,6 @@ fn opaque_types_defined_by<'tcx>(
321328
}
322329

323330
pub(super) fn provide(providers: &mut Providers) {
324-
*providers = Providers { opaque_types_defined_by, ..*providers };
331+
*providers =
332+
Providers { opaque_types_defined_by, impl_trait_in_assoc_types_defined_by, ..*providers };
325333
}

0 commit comments

Comments
 (0)