Skip to content

Commit f58af9b

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

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
@@ -530,9 +530,13 @@ pub(super) fn type_of_opaque(
530530
Ok(ty::EarlyBinder::bind(match tcx.hir_node_by_def_id(def_id) {
531531
Node::Item(item) => match item.kind {
532532
ItemKind::OpaqueTy(OpaqueTy {
533-
origin: hir::OpaqueTyOrigin::TyAlias { .. },
533+
origin: hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: false },
534534
..
535535
}) => opaque::find_opaque_ty_constraints_for_tait(tcx, def_id),
536+
ItemKind::OpaqueTy(OpaqueTy {
537+
origin: hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: true },
538+
..
539+
}) => opaque::find_opaque_ty_constraints_for_impl_trait_in_assoc_type(tcx, def_id),
536540
// Opaque types desugared from `impl Trait`.
537541
ItemKind::OpaqueTy(&OpaqueTy {
538542
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
@@ -23,6 +23,60 @@ pub fn test_opaque_hidden_types(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed>
2323
res
2424
}
2525

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

131185
impl TaitConstraintLocator<'_> {
132186
#[instrument(skip(self), level = "debug")]
133-
fn check(&mut self, item_def_id: LocalDefId) {
187+
fn check(&mut self, item_def_id: LocalDefId, impl_trait_in_assoc_type: bool) {
134188
// Don't try to check items that cannot possibly constrain the type.
135189
if !self.tcx.has_typeck_results(item_def_id) {
136190
debug!("no constraint: no typeck results");
@@ -182,7 +236,12 @@ impl TaitConstraintLocator<'_> {
182236
continue;
183237
}
184238
constrained = true;
185-
if !self.tcx.opaque_types_defined_by(item_def_id).contains(&self.def_id) {
239+
let opaque_types_defined_by = if impl_trait_in_assoc_type {
240+
self.tcx.impl_trait_in_assoc_types_defined_by(item_def_id)
241+
} else {
242+
self.tcx.opaque_types_defined_by(item_def_id)
243+
};
244+
if !opaque_types_defined_by.contains(&self.def_id) {
186245
self.tcx.dcx().emit_err(TaitForwardCompat {
187246
span: hidden_type.span,
188247
item_span: self
@@ -240,29 +299,29 @@ impl<'tcx> intravisit::Visitor<'tcx> for TaitConstraintLocator<'tcx> {
240299
}
241300
fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
242301
if let hir::ExprKind::Closure(closure) = ex.kind {
243-
self.check(closure.def_id);
302+
self.check(closure.def_id, false);
244303
}
245304
intravisit::walk_expr(self, ex);
246305
}
247306
fn visit_item(&mut self, it: &'tcx Item<'tcx>) {
248307
trace!(?it.owner_id);
249308
// The opaque type itself or its children are not within its reveal scope.
250309
if it.owner_id.def_id != self.def_id {
251-
self.check(it.owner_id.def_id);
310+
self.check(it.owner_id.def_id, false);
252311
intravisit::walk_item(self, it);
253312
}
254313
}
255314
fn visit_impl_item(&mut self, it: &'tcx ImplItem<'tcx>) {
256315
trace!(?it.owner_id);
257316
// The opaque type itself or its children are not within its reveal scope.
258317
if it.owner_id.def_id != self.def_id {
259-
self.check(it.owner_id.def_id);
318+
self.check(it.owner_id.def_id, false);
260319
intravisit::walk_impl_item(self, it);
261320
}
262321
}
263322
fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) {
264323
trace!(?it.owner_id);
265-
self.check(it.owner_id.def_id);
324+
self.check(it.owner_id.def_id, false);
266325
intravisit::walk_trait_item(self, it);
267326
}
268327
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
@@ -343,6 +343,15 @@ rustc_queries! {
343343
}
344344
}
345345

346+
query impl_trait_in_assoc_types_defined_by(
347+
key: LocalDefId
348+
) -> &'tcx ty::List<LocalDefId> {
349+
desc {
350+
|tcx| "computing the opaque types defined by `{}`",
351+
tcx.def_path_str(key.to_def_id())
352+
}
353+
}
354+
346355
/// Returns the list of bounds that can be used for
347356
/// `SelectionCandidate::ProjectionCandidate(_)` and
348357
/// `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)