Skip to content

Commit ca2e204

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

File tree

4 files changed

+88
-8
lines changed

4 files changed

+88
-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: 65 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,60 @@ 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 { .. } => {}
39+
other => bug!("invalid impl trait in assoc type parent: {other:?}"),
40+
}
41+
42+
let mut locator = TaitConstraintLocator { def_id, tcx, found: None, typeck_types: vec![] };
43+
44+
for &assoc_id in tcx.associated_item_def_ids(impl_def_id) {
45+
let assoc = tcx.associated_item(assoc_id);
46+
match assoc.kind {
47+
ty::AssocKind::Const | ty::AssocKind::Fn => {
48+
locator.check(assoc_id.expect_local(), true)
49+
}
50+
// Associated types don't have bodies, so they can't constrain hidden types
51+
ty::AssocKind::Type => {}
52+
}
53+
}
54+
55+
if let Some(hidden) = locator.found {
56+
// Only check against typeck if we didn't already error
57+
if !hidden.ty.references_error() {
58+
for concrete_type in locator.typeck_types {
59+
if concrete_type.ty != tcx.erase_regions(hidden.ty)
60+
&& !(concrete_type, hidden).references_error()
61+
{
62+
hidden.report_mismatch(&concrete_type, def_id, tcx).emit();
63+
}
64+
}
65+
}
66+
67+
hidden.ty
68+
} else {
69+
let reported = tcx.dcx().emit_err(UnconstrainedOpaqueType {
70+
span: tcx.def_span(def_id),
71+
name: tcx.item_name(parent_def_id.to_def_id()),
72+
what: "impl",
73+
});
74+
Ty::new_error(tcx, reported)
75+
}
76+
}
77+
2478
/// Checks "defining uses" of opaque `impl Trait` types to ensure that they meet the restrictions
2579
/// laid for "higher-order pattern unification".
2680
/// This ensures that inference is tractable.
@@ -128,7 +182,7 @@ struct TaitConstraintLocator<'tcx> {
128182

129183
impl TaitConstraintLocator<'_> {
130184
#[instrument(skip(self), level = "debug")]
131-
fn check(&mut self, item_def_id: LocalDefId) {
185+
fn check(&mut self, item_def_id: LocalDefId, impl_trait_in_assoc_type: bool) {
132186
// Don't try to check items that cannot possibly constrain the type.
133187
if !self.tcx.has_typeck_results(item_def_id) {
134188
debug!("no constraint: no typeck results");
@@ -158,7 +212,12 @@ impl TaitConstraintLocator<'_> {
158212
continue;
159213
}
160214
constrained = true;
161-
if !self.tcx.opaque_types_defined_by(item_def_id).contains(&self.def_id) {
215+
let opaque_types_defined_by = if impl_trait_in_assoc_type {
216+
self.tcx.impl_trait_in_assoc_types_defined_by(item_def_id)
217+
} else {
218+
self.tcx.opaque_types_defined_by(item_def_id)
219+
};
220+
if !opaque_types_defined_by.contains(&self.def_id) {
162221
self.tcx.dcx().emit_err(TaitForwardCompat {
163222
span: hidden_type.span,
164223
item_span: self
@@ -216,29 +275,29 @@ impl<'tcx> intravisit::Visitor<'tcx> for TaitConstraintLocator<'tcx> {
216275
}
217276
fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
218277
if let hir::ExprKind::Closure(closure) = ex.kind {
219-
self.check(closure.def_id);
278+
self.check(closure.def_id, false);
220279
}
221280
intravisit::walk_expr(self, ex);
222281
}
223282
fn visit_item(&mut self, it: &'tcx Item<'tcx>) {
224283
trace!(?it.owner_id);
225284
// The opaque type itself or its children are not within its reveal scope.
226285
if it.owner_id.def_id != self.def_id {
227-
self.check(it.owner_id.def_id);
286+
self.check(it.owner_id.def_id, false);
228287
intravisit::walk_item(self, it);
229288
}
230289
}
231290
fn visit_impl_item(&mut self, it: &'tcx ImplItem<'tcx>) {
232291
trace!(?it.owner_id);
233292
// The opaque type itself or its children are not within its reveal scope.
234293
if it.owner_id.def_id != self.def_id {
235-
self.check(it.owner_id.def_id);
294+
self.check(it.owner_id.def_id, false);
236295
intravisit::walk_impl_item(self, it);
237296
}
238297
}
239298
fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) {
240299
trace!(?it.owner_id);
241-
self.check(it.owner_id.def_id);
300+
self.check(it.owner_id.def_id, false);
242301
intravisit::walk_trait_item(self, it);
243302
}
244303
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)