From 2784404bf2e7adbe020e9ead9bf9d26845dc8077 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Wed, 19 Jun 2024 01:50:30 +0200 Subject: [PATCH 1/3] Implement consecutive shorthand projections --- .../src/hir_ty_lowering/errors.rs | 2 +- .../src/hir_ty_lowering/mod.rs | 46 ++++++++++-- src/tools/tidy/src/issues.txt | 1 - ...ecutive-shorthand-projections-ambiguous.rs | 16 ++++ ...ive-shorthand-projections-ambiguous.stderr | 26 +++++++ ...horthand-projections-not-in-item-bounds.rs | 11 +++ ...hand-projections-not-in-item-bounds.stderr | 9 +++ ...orthand-projections-struct-construction.rs | 19 +++++ .../consecutive-shorthand-projections.rs | 75 +++++++++++++++++++ .../defaults-23073.rs} | 5 +- ...secutive-shorthand-projections.lazy.stderr | 15 ++++ .../non-consecutive-shorthand-projections.rs | 19 +++++ tests/ui/issues/issue-23073.stderr | 14 ---- tests/ui/qualified/qualified-path-params-2.rs | 4 +- .../qualified/qualified-path-params-2.stderr | 14 +--- tests/ui/ufcs/ufcs-partially-resolved.rs | 2 +- tests/ui/ufcs/ufcs-partially-resolved.stderr | 16 ++-- 17 files changed, 245 insertions(+), 49 deletions(-) create mode 100644 tests/ui/associated-types/consecutive-shorthand-projections-ambiguous.rs create mode 100644 tests/ui/associated-types/consecutive-shorthand-projections-ambiguous.stderr create mode 100644 tests/ui/associated-types/consecutive-shorthand-projections-not-in-item-bounds.rs create mode 100644 tests/ui/associated-types/consecutive-shorthand-projections-not-in-item-bounds.stderr create mode 100644 tests/ui/associated-types/consecutive-shorthand-projections-struct-construction.rs create mode 100644 tests/ui/associated-types/consecutive-shorthand-projections.rs rename tests/ui/{issues/issue-23073.rs => associated-types/defaults-23073.rs} (58%) create mode 100644 tests/ui/associated-types/non-consecutive-shorthand-projections.lazy.stderr create mode 100644 tests/ui/associated-types/non-consecutive-shorthand-projections.rs delete mode 100644 tests/ui/issues/issue-23073.stderr diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs index 5d85a3f8455e0..a15db9b91368f 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -169,7 +169,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { pub(super) fn report_unresolved_assoc_item( &self, all_candidates: impl Fn() -> I, - qself: AssocItemQSelf, + qself: AssocItemQSelf<'tcx>, assoc_tag: ty::AssocTag, assoc_ident: Ident, span: Span, diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index a5bd7c1a34aef..1357b49c9e883 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -224,18 +224,20 @@ pub trait HirTyLowerer<'tcx> { /// The "qualified self" of an associated item path. /// /// For diagnostic purposes only. -enum AssocItemQSelf { +enum AssocItemQSelf<'tcx> { Trait(DefId), TyParam(LocalDefId, Span), SelfTyAlias, + AssocTy(Ty<'tcx>), } -impl AssocItemQSelf { - fn to_string(&self, tcx: TyCtxt<'_>) -> String { +impl<'tcx> AssocItemQSelf<'tcx> { + fn to_string(&self, tcx: TyCtxt<'tcx>) -> String { match *self { Self::Trait(def_id) => tcx.def_path_str(def_id), Self::TyParam(def_id, _) => tcx.hir_ty_param_name(def_id).to_string(), Self::SelfTyAlias => kw::SelfUpper.to_string(), + Self::AssocTy(ty) => ty.to_string(), } } } @@ -1034,7 +1036,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { fn probe_single_bound_for_assoc_item( &self, all_candidates: impl Fn() -> I, - qself: AssocItemQSelf, + qself: AssocItemQSelf<'tcx>, assoc_tag: ty::AssocTag, assoc_ident: Ident, span: Span, @@ -1387,15 +1389,45 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { )? } ( - &ty::Param(_), - Res::SelfTyParam { trait_: param_did } | Res::Def(DefKind::TyParam, param_did), + ty::Param(_), + Res::SelfTyParam { trait_: param_def_id } + | Res::Def(DefKind::TyParam, param_def_id), ) => self.probe_single_ty_param_bound_for_assoc_item( - param_did.expect_local(), + param_def_id.expect_local(), hir_self_ty.span, assoc_tag, segment.ident, span, )?, + // FIXME(fmease): + // Require the pre-lowered projectee (the HIR QSelf) to have `DefKind::AssocTy`. Rephrased, + // `T::Assoc::Assoc` typeck'ing shouldn't imply `Identity::Assoc` typeck'ing where + // `Identity` is an eager (i.e., non-lazy) type alias. We should do this + // * for consistency with lazy type aliases (`ty::Weak`) + // * for consistency with the fact that `T::Assoc` typeck'ing doesn't imply `Identity::Assoc` + // typeck'ing + (ty::Alias(ty::Projection, alias_ty), _ /* Res::Def(DefKind::AssocTy, _) */) => { + // FIXME: Utilizing `item_bounds` for this is cycle-prone. + let predicates = tcx.item_bounds(alias_ty.def_id).instantiate(tcx, alias_ty.args); + + self.probe_single_bound_for_assoc_item( + || { + let trait_refs = predicates.iter().filter_map(|pred| { + pred.as_trait_clause().map(|t| t.map_bound(|t| t.trait_ref)) + }); + traits::transitive_bounds_that_define_assoc_item( + tcx, + trait_refs, + segment.ident, + ) + }, + AssocItemQSelf::AssocTy(self_ty), + assoc_tag, + segment.ident, + span, + None, + )? + } _ => { return Err(self.report_unresolved_type_relative_path( self_ty, diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index cac4dba2b49d7..15fb38d8c137d 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -1818,7 +1818,6 @@ ui/issues/issue-23024.rs ui/issues/issue-23036.rs ui/issues/issue-23041.rs ui/issues/issue-23046.rs -ui/issues/issue-23073.rs ui/issues/issue-2311-2.rs ui/issues/issue-2311.rs ui/issues/issue-2312.rs diff --git a/tests/ui/associated-types/consecutive-shorthand-projections-ambiguous.rs b/tests/ui/associated-types/consecutive-shorthand-projections-ambiguous.rs new file mode 100644 index 0000000000000..e524fd9faf0e2 --- /dev/null +++ b/tests/ui/associated-types/consecutive-shorthand-projections-ambiguous.rs @@ -0,0 +1,16 @@ +trait ChooseMe { + type Type; +} + +trait PickMe { + type Type; +} + +trait HaveItAll { + type See: ChooseMe + PickMe; +} + +struct Env(T::See::Type); +//~^ ERROR ambiguous associated type `Type` in bounds of `::See` + +fn main() {} diff --git a/tests/ui/associated-types/consecutive-shorthand-projections-ambiguous.stderr b/tests/ui/associated-types/consecutive-shorthand-projections-ambiguous.stderr new file mode 100644 index 0000000000000..e043e9fa227d4 --- /dev/null +++ b/tests/ui/associated-types/consecutive-shorthand-projections-ambiguous.stderr @@ -0,0 +1,26 @@ +error[E0221]: ambiguous associated type `Type` in bounds of `::See` + --> $DIR/consecutive-shorthand-projections-ambiguous.rs:13:26 + | +LL | type Type; + | --------- ambiguous `Type` from `ChooseMe` +... +LL | type Type; + | --------- ambiguous `Type` from `PickMe` +... +LL | struct Env(T::See::Type); + | ^^^^^^^^^^^^ ambiguous associated type `Type` + | +help: use fully-qualified syntax to disambiguate + | +LL - struct Env(T::See::Type); +LL + struct Env(<::See as ChooseMe>::Type); + | +help: use fully-qualified syntax to disambiguate + | +LL - struct Env(T::See::Type); +LL + struct Env(<::See as PickMe>::Type); + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0221`. diff --git a/tests/ui/associated-types/consecutive-shorthand-projections-not-in-item-bounds.rs b/tests/ui/associated-types/consecutive-shorthand-projections-not-in-item-bounds.rs new file mode 100644 index 0000000000000..daf98d2b255b4 --- /dev/null +++ b/tests/ui/associated-types/consecutive-shorthand-projections-not-in-item-bounds.rs @@ -0,0 +1,11 @@ +// FIXME: Description + +fn parametrized>() { + let _: T::Ty::Ty; //~ ERROR associated type `Ty` not found for `::Ty` +} + +trait Trait { + type Ty; +} + +fn main() {} diff --git a/tests/ui/associated-types/consecutive-shorthand-projections-not-in-item-bounds.stderr b/tests/ui/associated-types/consecutive-shorthand-projections-not-in-item-bounds.stderr new file mode 100644 index 0000000000000..f9aa6626899ad --- /dev/null +++ b/tests/ui/associated-types/consecutive-shorthand-projections-not-in-item-bounds.stderr @@ -0,0 +1,9 @@ +error[E0220]: associated type `Ty` not found for `::Ty` + --> $DIR/consecutive-shorthand-projections-not-in-item-bounds.rs:4:19 + | +LL | let _: T::Ty::Ty; + | ^^ there is an associated type `Ty` in the trait `Trait` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0220`. diff --git a/tests/ui/associated-types/consecutive-shorthand-projections-struct-construction.rs b/tests/ui/associated-types/consecutive-shorthand-projections-struct-construction.rs new file mode 100644 index 0000000000000..befa99280671e --- /dev/null +++ b/tests/ui/associated-types/consecutive-shorthand-projections-struct-construction.rs @@ -0,0 +1,19 @@ +//@ check-pass + +fn make>>() { + let _ = T::Ty::Ty { field: 0 }; +} + +trait Indir0 { + type Ty: Indir1; +} + +trait Indir1 { + type Ty; +} + +struct Struct { + field: i32 +} + +fn main() {} diff --git a/tests/ui/associated-types/consecutive-shorthand-projections.rs b/tests/ui/associated-types/consecutive-shorthand-projections.rs new file mode 100644 index 0000000000000..47025f096d0a7 --- /dev/null +++ b/tests/ui/associated-types/consecutive-shorthand-projections.rs @@ -0,0 +1,75 @@ +//@ check-pass + +fn factory0() { + let _: T::Output::Category; +} + +fn factory1>>(category: u16) { + let _: T::Output::Category = category; +} + +fn factory2(_: T::Output::Category) {} + +trait Factory { + type Output: Product; +} + +impl Factory for () { + type Output = u128; +} + +trait Product { + type Category; +} + +impl Product for u128 { + type Category = u16; +} + +///////////////////////// + +fn chain>(chain: C) { + let _: C::Link::Link::Link::Link::Link = chain; +} + +trait Chain { type Link: Chain; } + +impl Chain for () { + type Link = Self; +} + +///////////////////////// + +fn scope<'r, T: Main<'static, (i32, U), 1>, U, const Q: usize>() { + let _: T::Next<'r, (), Q>::Final; +} + +trait Main<'a, T, const N: usize> { + type Next<'b, U, const M: usize>: Aux<'a, 'b, (T, U), N, M>; +} + +impl<'a, T, const N: usize> Main<'a, T, N> for () { + type Next<'_b, _U, const _M: usize> = (); +} + +trait Aux<'a, 'b, T, const N: usize, const M: usize> { + type Final; +} + +impl<'a, 'b, T, const N: usize, const M: usize> Aux<'a, 'b, T, N, M> for () { + type Final = [[(T, &'a (), &'b ()); N]; M]; +} + +///////////////////////// + +fn main() { + factory0::<()>(); + factory1::<()>(360); + factory2::<()>(720); + let _: <() as Factory>::Output::Category; + + chain(()); + let _: <() as Chain>::Link::Link::Link; + + scope::<(), bool, 32>(); +} diff --git a/tests/ui/issues/issue-23073.rs b/tests/ui/associated-types/defaults-23073.rs similarity index 58% rename from tests/ui/issues/issue-23073.rs rename to tests/ui/associated-types/defaults-23073.rs index a0ca91336c365..ba83c228faf52 100644 --- a/tests/ui/issues/issue-23073.rs +++ b/tests/ui/associated-types/defaults-23073.rs @@ -1,9 +1,12 @@ +//@ check-pass + #![feature(associated_type_defaults)] trait Foo { type T; } + trait Bar { type Foo: Foo; - type FooT = <::Foo>::T; //~ ERROR ambiguous associated type + type FooT = <::Foo>::T; } fn main() {} diff --git a/tests/ui/associated-types/non-consecutive-shorthand-projections.lazy.stderr b/tests/ui/associated-types/non-consecutive-shorthand-projections.lazy.stderr new file mode 100644 index 0000000000000..ca6293fbbc3b2 --- /dev/null +++ b/tests/ui/associated-types/non-consecutive-shorthand-projections.lazy.stderr @@ -0,0 +1,15 @@ +error[E0223]: ambiguous associated type + --> $DIR/non-consecutive-shorthand-projections.rs:16:12 + | +LL | let _: Identity::Project; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: if there were a trait named `Example` with associated type `Project` implemented for `Identity<::Project>`, you could use the fully-qualified path + | +LL - let _: Identity::Project; +LL + let _: ::Project> as Example>::Project; + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0223`. diff --git a/tests/ui/associated-types/non-consecutive-shorthand-projections.rs b/tests/ui/associated-types/non-consecutive-shorthand-projections.rs new file mode 100644 index 0000000000000..95cbad75b6893 --- /dev/null +++ b/tests/ui/associated-types/non-consecutive-shorthand-projections.rs @@ -0,0 +1,19 @@ +// FIXME(fmease): Proper explainer. +// Of course, under #22519 (arbitrary shorthand projections), this should obviously typeck. +// For reference, `T::Alias` typeck'ing does *not* imply `Identity::Alias` typeck'ing. +//@ revisions: eager lazy +//@[eager] check-pass +#![cfg_attr(lazy, feature(lazy_type_alias), allow(incomplete_features))] + +type Identity = T; + +trait Trait { + type Project: Trait; +} + +fn scope() { + // FIXME(fmease): Reject this under [eager], too! + let _: Identity::Project; //[lazy]~ ERROR ambiguous associated type +} + +fn main() {} diff --git a/tests/ui/issues/issue-23073.stderr b/tests/ui/issues/issue-23073.stderr deleted file mode 100644 index 87dcf3b328923..0000000000000 --- a/tests/ui/issues/issue-23073.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0223]: ambiguous associated type - --> $DIR/issue-23073.rs:6:17 - | -LL | type FooT = <::Foo>::T; - | ^^^^^^^^^^^^^^^^^^^^^^^ - | -help: if there were a trait named `Example` with associated type `T` implemented for `::Foo`, you could use the fully-qualified path - | -LL | type FooT = <::Foo as Example>::T; - | ++++++++++ - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0223`. diff --git a/tests/ui/qualified/qualified-path-params-2.rs b/tests/ui/qualified/qualified-path-params-2.rs index d0cc1fa3d5172..cfc00cd2720bb 100644 --- a/tests/ui/qualified/qualified-path-params-2.rs +++ b/tests/ui/qualified/qualified-path-params-2.rs @@ -1,6 +1,5 @@ // Check that qualified paths with type parameters // fail during type checking and not during parsing - struct S; trait Tr { @@ -15,7 +14,6 @@ impl S { fn f() {} } -type A = ::A::f; -//~^ ERROR ambiguous associated type +type A = ::A::f; //~ ERROR associated type `f` not found for `::A` fn main() {} diff --git a/tests/ui/qualified/qualified-path-params-2.stderr b/tests/ui/qualified/qualified-path-params-2.stderr index e70cdbdc3f49e..53a33e43ba5e5 100644 --- a/tests/ui/qualified/qualified-path-params-2.stderr +++ b/tests/ui/qualified/qualified-path-params-2.stderr @@ -1,15 +1,9 @@ -error[E0223]: ambiguous associated type - --> $DIR/qualified-path-params-2.rs:18:10 +error[E0220]: associated type `f` not found for `::A` + --> $DIR/qualified-path-params-2.rs:17:24 | LL | type A = ::A::f; - | ^^^^^^^^^^^^^^^^^^^ - | -help: if there were a trait named `Example` with associated type `f` implemented for `::A`, you could use the fully-qualified path - | -LL - type A = ::A::f; -LL + type A = <::A as Example>::f; - | + | ^ there is a similarly named associated type `A` in the trait `Tr` error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0223`. +For more information about this error, try `rustc --explain E0220`. diff --git a/tests/ui/ufcs/ufcs-partially-resolved.rs b/tests/ui/ufcs/ufcs-partially-resolved.rs index 712668728c9e7..d7c92f73c39cd 100644 --- a/tests/ui/ufcs/ufcs-partially-resolved.rs +++ b/tests/ui/ufcs/ufcs-partially-resolved.rs @@ -33,7 +33,7 @@ fn main() { ::N::NN; //~ ERROR cannot find associated type `N` in trait `Tr` ::N::NN; //~ ERROR expected trait, found enum `E` ::N::NN; //~ ERROR expected trait, found type alias `A` - let _: ::Y::NN; //~ ERROR ambiguous associated type + let _: ::Y::NN; //~ ERROR associated type `NN` not found for `::Y` let _: ::Y::NN; //~ ERROR expected trait, found enum `E` ::Y::NN; //~ ERROR no associated item named `NN` found for type `u16` ::Y::NN; //~ ERROR expected trait, found enum `E` diff --git a/tests/ui/ufcs/ufcs-partially-resolved.stderr b/tests/ui/ufcs/ufcs-partially-resolved.stderr index 69d6bd74a736d..7035743661790 100644 --- a/tests/ui/ufcs/ufcs-partially-resolved.stderr +++ b/tests/ui/ufcs/ufcs-partially-resolved.stderr @@ -247,17 +247,11 @@ LL | let _: ::Z::N; | | | help: an associated type with a similar name exists: `X` -error[E0223]: ambiguous associated type - --> $DIR/ufcs-partially-resolved.rs:36:12 +error[E0220]: associated type `NN` not found for `::Y` + --> $DIR/ufcs-partially-resolved.rs:36:27 | LL | let _: ::Y::NN; - | ^^^^^^^^^^^^^^^^^ - | -help: if there were a trait named `Example` with associated type `NN` implemented for `::Y`, you could use the fully-qualified path - | -LL - let _: ::Y::NN; -LL + let _: <::Y as Example>::NN; - | + | ^^ associated type `NN` not found error[E0599]: no associated item named `NN` found for type `u16` in the current scope --> $DIR/ufcs-partially-resolved.rs:38:20 @@ -273,5 +267,5 @@ LL | ::X::N; error: aborting due to 32 previous errors -Some errors have detailed explanations: E0223, E0404, E0405, E0575, E0576, E0599. -For more information about an error, try `rustc --explain E0223`. +Some errors have detailed explanations: E0220, E0404, E0405, E0575, E0576, E0599. +For more information about an error, try `rustc --explain E0220`. From 25f7b8009ed69d75942bef1662d02cca50de9cf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Wed, 3 Jul 2024 15:50:47 +0200 Subject: [PATCH 2/3] [PoC] Track type-dependent defs in ItemCtxts (minimally) --- compiler/rustc_hir_analysis/src/collect.rs | 31 +++++++++- .../src/hir_ty_lowering/mod.rs | 22 +++---- .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 4 +- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 6 +- compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs | 19 +++++-- compiler/rustc_middle/src/ty/mod.rs | 2 +- .../rustc_middle/src/ty/typeck_results.rs | 57 +++++++++++++------ src/tools/tidy/src/ui_tests.rs | 2 +- ...ecutive-shorthand-projections.eager.stderr | 15 +++++ ...secutive-shorthand-projections.lazy.stderr | 2 +- .../non-consecutive-shorthand-projections.rs | 4 +- 11 files changed, 117 insertions(+), 47 deletions(-) create mode 100644 tests/ui/associated-types/non-consecutive-shorthand-projections.eager.stderr diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 431d99a572d26..5eb77c0106a33 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -15,7 +15,7 @@ //! crate as a kind of pass. This should eventually be factored away. use std::assert_matches::assert_matches; -use std::cell::Cell; +use std::cell::{Cell, RefCell}; use std::iter; use std::ops::Bound; @@ -34,6 +34,10 @@ use rustc_hir::{self as hir, GenericParamKind, HirId, Node, PreciseCapturingArgK use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::{DynCompatibilityViolation, ObligationCause}; use rustc_middle::query::Providers; +use rustc_middle::ty::typeck_results::{ + HasTypeDependentDefs, LocalTableInContext, LocalTableInContextMut, TypeDependentDef, + TypeDependentDefs, +}; use rustc_middle::ty::util::{Discr, IntTypeExt}; use rustc_middle::ty::{ self, AdtKind, Const, IsSuggestable, Ty, TyCtxt, TypeVisitableExt, TypingMode, fold_regions, @@ -132,6 +136,7 @@ pub(crate) fn provide(providers: &mut Providers) { pub(crate) struct ItemCtxt<'tcx> { tcx: TyCtxt<'tcx>, item_def_id: LocalDefId, + type_dependent_defs: RefCell, tainted_by_errors: Cell>, } @@ -243,7 +248,12 @@ fn bad_placeholder<'cx, 'tcx>( impl<'tcx> ItemCtxt<'tcx> { pub(crate) fn new(tcx: TyCtxt<'tcx>, item_def_id: LocalDefId) -> ItemCtxt<'tcx> { - ItemCtxt { tcx, item_def_id, tainted_by_errors: Cell::new(None) } + ItemCtxt { + tcx, + item_def_id, + type_dependent_defs: Default::default(), + tainted_by_errors: Cell::new(None), + } } pub(crate) fn lower_ty(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> { @@ -510,6 +520,14 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> { // There's no place to record types from signatures? } + fn record_res(&self, hir_id: hir::HirId, result: TypeDependentDef) { + LocalTableInContextMut::new( + self.hir_id().owner, + &mut self.type_dependent_defs.borrow_mut(), + ) + .insert(hir_id, result); + } + fn infcx(&self) -> Option<&InferCtxt<'tcx>> { None } @@ -569,6 +587,15 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> { } } +impl HasTypeDependentDefs for ItemCtxt<'_> { + fn type_dependent_def(&self, id: hir::HirId) -> Option<(DefKind, DefId)> { + LocalTableInContext::new(self.hir_id().owner, &self.type_dependent_defs.borrow()) + .get(id) + .copied() + .and_then(|result| result.ok()) + } +} + /// Synthesize a new lifetime name that doesn't clash with any of the lifetimes already present. fn get_new_lifetime_name<'tcx>( tcx: TyCtxt<'tcx>, diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 1357b49c9e883..3406a869a366a 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -38,6 +38,7 @@ use rustc_macros::{TypeFoldable, TypeVisitable}; use rustc_middle::middle::stability::AllowUnstable; use rustc_middle::mir::interpret::LitToConstInput; use rustc_middle::ty::print::PrintPolyTraitRefExt as _; +use rustc_middle::ty::typeck_results::{HasTypeDependentDefs, TypeDependentDef}; use rustc_middle::ty::{ self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, Ty, TyCtxt, TypeVisitableExt, TypingMode, Upcast, fold_regions, @@ -111,7 +112,7 @@ pub struct InherentAssocCandidate { /// the [`rustc_middle::ty`] representation. /// /// This trait used to be called `AstConv`. -pub trait HirTyLowerer<'tcx> { +pub trait HirTyLowerer<'tcx>: HasTypeDependentDefs { fn tcx(&self) -> TyCtxt<'tcx>; fn dcx(&self) -> DiagCtxtHandle<'_>; @@ -202,6 +203,9 @@ pub trait HirTyLowerer<'tcx> { /// Record the lowered type of a HIR node in this context. fn record_ty(&self, hir_id: HirId, ty: Ty<'tcx>, span: Span); + /// Record the resolution of a HIR node corresponding to a type-dependent definition in this context. + fn record_res(&self, hir_id: hir::HirId, result: TypeDependentDef); + /// The inference context of the lowering context if applicable. fn infcx(&self) -> Option<&InferCtxt<'tcx>>; @@ -1175,6 +1179,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// /// [#22519]: https://github.com/rust-lang/rust/issues/22519 /// [iat]: https://github.com/rust-lang/rust/issues/8995#issuecomment-1569208403 + // FIXME(fmease): Update docs // // NOTE: When this function starts resolving `Trait::AssocTy` successfully // it should also start reporting the `BARE_TRAIT_OBJECTS` lint. @@ -1198,9 +1203,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { LowerTypeRelativePathMode::Type(permit_variants), )? { TypeRelativePath::AssocItem(def_id, args) => { + let kind = tcx.def_kind(def_id); + self.record_res(qpath_hir_id, Ok((kind, def_id))); let alias_ty = ty::AliasTy::new_from_args(tcx, def_id, args); let ty = Ty::new_alias(tcx, alias_ty.kind(tcx), alias_ty); - Ok((ty, tcx.def_kind(def_id), def_id)) + Ok((ty, kind, def_id)) } TypeRelativePath::Variant { adt, variant_did } => { Ok((adt, DefKind::Variant, variant_did)) @@ -1362,7 +1369,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let tcx = self.tcx(); let self_ty_res = match hir_self_ty.kind { - hir::TyKind::Path(hir::QPath::Resolved(_, path)) => path.res, + hir::TyKind::Path(qpath) => self.qpath_res(&qpath, hir_self_ty.hir_id), _ => Res::Err, }; @@ -1399,14 +1406,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { segment.ident, span, )?, - // FIXME(fmease): - // Require the pre-lowered projectee (the HIR QSelf) to have `DefKind::AssocTy`. Rephrased, - // `T::Assoc::Assoc` typeck'ing shouldn't imply `Identity::Assoc` typeck'ing where - // `Identity` is an eager (i.e., non-lazy) type alias. We should do this - // * for consistency with lazy type aliases (`ty::Weak`) - // * for consistency with the fact that `T::Assoc` typeck'ing doesn't imply `Identity::Assoc` - // typeck'ing - (ty::Alias(ty::Projection, alias_ty), _ /* Res::Def(DefKind::AssocTy, _) */) => { + (ty::Alias(ty::Projection, alias_ty), Res::Def(DefKind::AssocTy, _)) => { // FIXME: Utilizing `item_bounds` for this is cycle-prone. let predicates = tcx.item_bounds(alias_ty.def_id).instantiate(tcx, alias_ty.args); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index af1fc045ac87f..af52a3ef4dc42 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -171,9 +171,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(crate) fn write_resolution( &self, hir_id: HirId, - r: Result<(DefKind, DefId), ErrorGuaranteed>, + result: Result<(DefKind, DefId), ErrorGuaranteed>, ) { - self.typeck_results.borrow_mut().type_dependent_defs_mut().insert(hir_id, r); + self.typeck_results.borrow_mut().type_dependent_defs_mut().insert(hir_id, result); } #[instrument(level = "debug", skip(self))] diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index eb8d671c939ce..a148c3864acd0 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -2215,12 +2215,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .map(|(ty, _, _)| ty) .unwrap_or_else(|guar| Ty::new_error(self.tcx(), guar)); let ty = LoweredTy::from_raw(self, path_span, ty); - let result = result.map(|(_, kind, def_id)| (kind, def_id)); - // Write back the new resolution. - self.write_resolution(hir_id, result); - - (result.map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)), ty) + (result.map_or(Res::Err, |(_, kind, def_id)| Res::Def(kind, def_id)), ty) } QPath::LangItem(lang_item, span) => { let (res, ty) = self.resolve_lang_item_path(lang_item, span, hir_id); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index 0c6226ce71e78..b5a5615015cae 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -8,15 +8,16 @@ mod suggestions; use std::cell::{Cell, RefCell}; use std::ops::Deref; -use hir::def_id::CRATE_DEF_ID; use rustc_errors::DiagCtxtHandle; -use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::def::DefKind; +use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId}; use rustc_hir::{self as hir, HirId, ItemLocalMap}; use rustc_hir_analysis::hir_ty_lowering::{ HirTyLowerer, InherentAssocCandidate, RegionInferReason, }; use rustc_infer::infer::{self, RegionVariableOrigin}; use rustc_infer::traits::{DynCompatibilityViolation, Obligation}; +use rustc_middle::ty::typeck_results::{HasTypeDependentDefs, TypeDependentDef}; use rustc_middle::ty::{self, Const, Ty, TyCtxt, TypeVisitableExt}; use rustc_session::Session; use rustc_span::{self, DUMMY_SP, ErrorGuaranteed, Ident, Span, sym}; @@ -418,7 +419,7 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> { } } - fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, span: Span) { + fn record_ty(&self, hir_id: HirId, ty: Ty<'tcx>, span: Span) { // FIXME: normalization and escaping regions let ty = if !ty.has_escaping_bound_vars() { // NOTE: These obligations are 100% redundant and are implied by @@ -438,6 +439,10 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> { self.write_ty(hir_id, ty) } + fn record_res(&self, hir_id: HirId, result: TypeDependentDef) { + self.write_resolution(hir_id, result); + } + fn infcx(&self) -> Option<&infer::InferCtxt<'tcx>> { Some(&self.infcx) } @@ -446,7 +451,7 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> { &self, decl: &rustc_hir::FnDecl<'tcx>, _generics: Option<&rustc_hir::Generics<'_>>, - _hir_id: rustc_hir::HirId, + _hir_id: HirId, _hir_ty: Option<&hir::Ty<'_>>, ) -> (Vec>, Ty<'tcx>) { let input_tys = decl.inputs.iter().map(|a| self.lowerer().lower_ty(a)).collect(); @@ -463,6 +468,12 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> { } } +impl HasTypeDependentDefs for FnCtxt<'_, '_> { + fn type_dependent_def(&self, id: HirId) -> Option<(DefKind, DefId)> { + self.typeck_results.borrow().type_dependent_def(id) + } +} + /// The `ty` representation of a user-provided type. Depending on the use-site /// we want to either use the unnormalized or the normalized form of this type. /// diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 0177a95498bcd..b12cce276b268 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -140,6 +140,7 @@ pub mod print; pub mod relate; pub mod significant_drop_order; pub mod trait_def; +pub mod typeck_results; pub mod util; pub mod vtable; @@ -166,7 +167,6 @@ mod rvalue_scopes; mod structural_impls; #[allow(hidden_glob_reexports)] mod sty; -mod typeck_results; mod visit; // Data types diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index 88583407d25d7..ef79ea8aab841 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -32,9 +32,7 @@ pub struct TypeckResults<'tcx> { /// The `HirId::owner` all `ItemLocalId`s in this table are relative to. pub hir_owner: OwnerId, - /// Resolved definitions for `::X` associated paths and - /// method calls, including those of overloaded operators. - type_dependent_defs: ItemLocalMap>, + type_dependent_defs: TypeDependentDefs, /// Resolved field indices for field accesses in expressions (`S { field }`, `obj.field`) /// or patterns (`S { field }`). The index is often useful by itself, but to learn more @@ -247,32 +245,22 @@ impl<'tcx> TypeckResults<'tcx> { /// Returns the final resolution of a `QPath` in an `Expr` or `Pat` node. pub fn qpath_res(&self, qpath: &hir::QPath<'_>, id: HirId) -> Res { - match *qpath { - hir::QPath::Resolved(_, path) => path.res, - hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => self - .type_dependent_def(id) - .map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)), - } + HasTypeDependentDefs::qpath_res(self, qpath, id) } - pub fn type_dependent_defs( - &self, - ) -> LocalTableInContext<'_, Result<(DefKind, DefId), ErrorGuaranteed>> { + pub fn type_dependent_defs(&self) -> LocalTableInContext<'_, TypeDependentDef> { LocalTableInContext { hir_owner: self.hir_owner, data: &self.type_dependent_defs } } pub fn type_dependent_def(&self, id: HirId) -> Option<(DefKind, DefId)> { - validate_hir_id_for_typeck_results(self.hir_owner, id); - self.type_dependent_defs.get(&id.local_id).cloned().and_then(|r| r.ok()) + self.type_dependent_defs().get(id).copied().and_then(|result| result.ok()) } pub fn type_dependent_def_id(&self, id: HirId) -> Option { self.type_dependent_def(id).map(|(_, def_id)| def_id) } - pub fn type_dependent_defs_mut( - &mut self, - ) -> LocalTableInContextMut<'_, Result<(DefKind, DefId), ErrorGuaranteed>> { + pub fn type_dependent_defs_mut(&mut self) -> LocalTableInContextMut<'_, TypeDependentDef> { LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.type_dependent_defs } } @@ -555,6 +543,33 @@ impl<'tcx> TypeckResults<'tcx> { } } +/// Resolved definitions for `::X` associated paths and +/// method calls, including those of overloaded operators. +pub type TypeDependentDefs = ItemLocalMap; + +pub type TypeDependentDef = Result<(DefKind, DefId), ErrorGuaranteed>; + +// FIXME(fmease): Yuck! +pub trait HasTypeDependentDefs { + fn type_dependent_def(&self, id: HirId) -> Option<(DefKind, DefId)>; + + /// Returns the final resolution of a `QPath`. + fn qpath_res(&self, qpath: &hir::QPath<'_>, id: HirId) -> Res { + match qpath { + hir::QPath::Resolved(_, path) => path.res, + hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => self + .type_dependent_def(id) + .map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)), + } + } +} + +impl HasTypeDependentDefs for TypeckResults<'_> { + fn type_dependent_def(&self, id: HirId) -> Option<(DefKind, DefId)> { + self.type_dependent_def(id) + } +} + /// Validate that the given HirId (respectively its `local_id` part) can be /// safely used as a key in the maps of a TypeckResults. For that to be /// the case, the HirId must have the same `owner` as all the other IDs in @@ -587,6 +602,10 @@ pub struct LocalTableInContext<'a, V> { } impl<'a, V> LocalTableInContext<'a, V> { + pub fn new(hir_owner: OwnerId, data: &'a ItemLocalMap) -> Self { + Self { hir_owner, data } + } + pub fn contains_key(&self, id: HirId) -> bool { validate_hir_id_for_typeck_results(self.hir_owner, id); self.data.contains_key(&id.local_id) @@ -625,6 +644,10 @@ pub struct LocalTableInContextMut<'a, V> { } impl<'a, V> LocalTableInContextMut<'a, V> { + pub fn new(hir_owner: OwnerId, data: &'a mut ItemLocalMap) -> Self { + Self { hir_owner, data } + } + pub fn get_mut(&mut self, id: HirId) -> Option<&mut V> { validate_hir_id_for_typeck_results(self.hir_owner, id); self.data.get_mut(&id.local_id) diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index 53226fcb80e6a..7d137808f68af 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -17,7 +17,7 @@ use ignore::Walk; const ENTRY_LIMIT: u32 = 901; // FIXME: The following limits should be reduced eventually. -const ISSUES_ENTRY_LIMIT: u32 = 1619; +const ISSUES_ENTRY_LIMIT: u32 = 1617; const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[ "rs", // test source files diff --git a/tests/ui/associated-types/non-consecutive-shorthand-projections.eager.stderr b/tests/ui/associated-types/non-consecutive-shorthand-projections.eager.stderr new file mode 100644 index 0000000000000..05ef18c86a9c5 --- /dev/null +++ b/tests/ui/associated-types/non-consecutive-shorthand-projections.eager.stderr @@ -0,0 +1,15 @@ +error[E0223]: ambiguous associated type + --> $DIR/non-consecutive-shorthand-projections.rs:14:12 + | +LL | let _: Identity::Project; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: if there were a trait named `Example` with associated type `Project` implemented for `::Project`, you could use the fully-qualified path + | +LL - let _: Identity::Project; +LL + let _: <::Project as Example>::Project; + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0223`. diff --git a/tests/ui/associated-types/non-consecutive-shorthand-projections.lazy.stderr b/tests/ui/associated-types/non-consecutive-shorthand-projections.lazy.stderr index ca6293fbbc3b2..4cb295bc43cc3 100644 --- a/tests/ui/associated-types/non-consecutive-shorthand-projections.lazy.stderr +++ b/tests/ui/associated-types/non-consecutive-shorthand-projections.lazy.stderr @@ -1,5 +1,5 @@ error[E0223]: ambiguous associated type - --> $DIR/non-consecutive-shorthand-projections.rs:16:12 + --> $DIR/non-consecutive-shorthand-projections.rs:14:12 | LL | let _: Identity::Project; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/associated-types/non-consecutive-shorthand-projections.rs b/tests/ui/associated-types/non-consecutive-shorthand-projections.rs index 95cbad75b6893..34f46d777496c 100644 --- a/tests/ui/associated-types/non-consecutive-shorthand-projections.rs +++ b/tests/ui/associated-types/non-consecutive-shorthand-projections.rs @@ -2,7 +2,6 @@ // Of course, under #22519 (arbitrary shorthand projections), this should obviously typeck. // For reference, `T::Alias` typeck'ing does *not* imply `Identity::Alias` typeck'ing. //@ revisions: eager lazy -//@[eager] check-pass #![cfg_attr(lazy, feature(lazy_type_alias), allow(incomplete_features))] type Identity = T; @@ -12,8 +11,7 @@ trait Trait { } fn scope() { - // FIXME(fmease): Reject this under [eager], too! - let _: Identity::Project; //[lazy]~ ERROR ambiguous associated type + let _: Identity::Project; //~ ERROR ambiguous associated type } fn main() {} From e683765fe026f3fe2f23d9396d1773cd8d32838e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Mon, 14 Jul 2025 16:05:20 +0200 Subject: [PATCH 3/3] [WIP] --- compiler/rustc_hir_analysis/src/collect.rs | 7 +- .../src/collect/resolve_bound_vars.rs | 1 + .../src/hir_ty_lowering/mod.rs | 67 ++++++++++--------- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 12 ++-- compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs | 6 +- .../consecutive-type-relative-path.rs | 16 +++++ .../mgca/consecutive-type-relative-path.rs | 14 ++++ 7 files changed, 79 insertions(+), 44 deletions(-) create mode 100644 tests/ui/associated-type-bounds/return-type-notation/consecutive-type-relative-path.rs create mode 100644 tests/ui/const-generics/mgca/consecutive-type-relative-path.rs diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 5eb77c0106a33..b1d682b0d1554 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -35,8 +35,7 @@ use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::{DynCompatibilityViolation, ObligationCause}; use rustc_middle::query::Providers; use rustc_middle::ty::typeck_results::{ - HasTypeDependentDefs, LocalTableInContext, LocalTableInContextMut, TypeDependentDef, - TypeDependentDefs, + HasTypeDependentDefs, LocalTableInContext, LocalTableInContextMut, TypeDependentDefs, }; use rustc_middle::ty::util::{Discr, IntTypeExt}; use rustc_middle::ty::{ @@ -520,12 +519,12 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> { // There's no place to record types from signatures? } - fn record_res(&self, hir_id: hir::HirId, result: TypeDependentDef) { + fn record_res(&self, hir_id: hir::HirId, def_id: DefId) { LocalTableInContextMut::new( self.hir_id().owner, &mut self.type_dependent_defs.borrow_mut(), ) - .insert(hir_id, result); + .insert(hir_id, Ok((self.tcx.def_kind(def_id), def_id))); } fn infcx(&self) -> Option<&InferCtxt<'tcx>> { diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 8d7ac7db67bdc..2acf18215e299 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -2063,6 +2063,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { matches!(args.parenthesized, hir::GenericArgsParentheses::ReturnTypeNotation) }) => { + // FIXME(fmease): No longer true. // First, ignore a qself that isn't a type or `Self` param. Those are the // only ones that support `T::Assoc` anyways in HIR lowering. let hir::TyKind::Path(hir::QPath::Resolved(None, path)) = qself.kind else { diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 3406a869a366a..f0f6906170fff 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -38,7 +38,7 @@ use rustc_macros::{TypeFoldable, TypeVisitable}; use rustc_middle::middle::stability::AllowUnstable; use rustc_middle::mir::interpret::LitToConstInput; use rustc_middle::ty::print::PrintPolyTraitRefExt as _; -use rustc_middle::ty::typeck_results::{HasTypeDependentDefs, TypeDependentDef}; +use rustc_middle::ty::typeck_results::HasTypeDependentDefs; use rustc_middle::ty::{ self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, Ty, TyCtxt, TypeVisitableExt, TypingMode, Upcast, fold_regions, @@ -204,7 +204,7 @@ pub trait HirTyLowerer<'tcx>: HasTypeDependentDefs { fn record_ty(&self, hir_id: HirId, ty: Ty<'tcx>, span: Span); /// Record the resolution of a HIR node corresponding to a type-dependent definition in this context. - fn record_res(&self, hir_id: hir::HirId, result: TypeDependentDef); + fn record_res(&self, hir_id: hir::HirId, result: DefId); /// The inference context of the lowering context if applicable. fn infcx(&self) -> Option<&InferCtxt<'tcx>>; @@ -1159,28 +1159,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// Lower a [type-relative](hir::QPath::TypeRelative) path in type position to a type. /// /// If the path refers to an enum variant and `permit_variants` holds, - /// the returned type is simply the provided self type `qself_ty`. + /// the returned type is simply the provided self type `self_ty`. /// - /// A path like `A::B::C::D` is understood as `::D`. I.e., - /// `qself_ty` / `qself` is `A::B::C` and `assoc_segment` is `D`. - /// We return the lowered type and the `DefId` for the whole path. - /// - /// We only support associated type paths whose self type is a type parameter or a `Self` - /// type alias (in a trait impl) like `T::Ty` (where `T` is a ty param) or `Self::Ty`. - /// We **don't** support paths whose self type is an arbitrary type like `Struct::Ty` where - /// struct `Struct` impls an in-scope trait that defines an associated type called `Ty`. - /// For the latter case, we report ambiguity. - /// While desirable to support, the implementation would be non-trivial. Tracked in [#22519]. - /// - /// At the time of writing, *inherent associated types* are also resolved here. This however - /// is [problematic][iat]. A proper implementation would be as non-trivial as the one - /// described in the previous paragraph and their modeling of projections would likely be - /// very similar in nature. - /// - /// [#22519]: https://github.com/rust-lang/rust/issues/22519 - /// [iat]: https://github.com/rust-lang/rust/issues/8995#issuecomment-1569208403 - // FIXME(fmease): Update docs - // // NOTE: When this function starts resolving `Trait::AssocTy` successfully // it should also start reporting the `BARE_TRAIT_OBJECTS` lint. #[instrument(level = "debug", skip_all, ret)] @@ -1192,7 +1172,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { qpath_hir_id: HirId, span: Span, permit_variants: PermitVariants, - ) -> Result<(Ty<'tcx>, DefKind, DefId), ErrorGuaranteed> { + ) -> Result<(Ty<'tcx>, DefId), ErrorGuaranteed> { let tcx = self.tcx(); match self.lower_type_relative_path( self_ty, @@ -1203,15 +1183,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { LowerTypeRelativePathMode::Type(permit_variants), )? { TypeRelativePath::AssocItem(def_id, args) => { - let kind = tcx.def_kind(def_id); - self.record_res(qpath_hir_id, Ok((kind, def_id))); let alias_ty = ty::AliasTy::new_from_args(tcx, def_id, args); let ty = Ty::new_alias(tcx, alias_ty.kind(tcx), alias_ty); - Ok((ty, kind, def_id)) - } - TypeRelativePath::Variant { adt, variant_did } => { - Ok((adt, DefKind::Variant, variant_did)) + Ok((ty, def_id)) } + TypeRelativePath::Variant { adt, variant_did } => Ok((adt, variant_did)), } } @@ -1255,6 +1231,27 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } /// Lower a [type-relative][hir::QPath::TypeRelative] (and type-level) path. + /// + /// A path like `A::B::C::D` is understood as `::D`. I.e., the self type is `A::B::C` + /// and the `segment` is `D`. + /// + /// + /// + /// We only support associated item paths whose self type is a type parameter or a `Self` + /// type alias (in a trait impl) like `T::Ty` (where `T` is a ty param) or `Self::Ty`. + /// We **don't** support paths whose self type is an arbitrary type like `Struct::Ty` where + /// struct `Struct` impls an in-scope trait that defines an associated type called `Ty`. + /// For the latter case, we report ambiguity. + /// While desirable to support, the implementation would be non-trivial. Tracked in [#22519]. + /// + /// + /// + /// At the time of writing, *inherent associated types* are also resolved here. This however + /// is problematic. A proper implementation would be as non-trivial as the one + /// described in the previous paragraph and their modeling of projections would likely be + /// very similar in nature. + /// + /// [#22519]: https://github.com/rust-lang/rust/issues/22519 #[instrument(level = "debug", skip_all, ret)] fn lower_type_relative_path( &self, @@ -1287,6 +1284,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { adt_def, }, ); + self.record_res(qpath_hir_id, variant_def.def_id); return Ok(TypeRelativePath::Variant { adt: self_ty, variant_did: variant_def.def_id, @@ -1298,7 +1296,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } // FIXME(inherent_associated_types, #106719): Support self types other than ADTs. - if let Some((did, args)) = self.probe_inherent_assoc_item( + if let Some((def_id, args)) = self.probe_inherent_assoc_item( segment, adt_def.did(), self_ty, @@ -1306,7 +1304,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { span, mode.assoc_tag(), )? { - return Ok(TypeRelativePath::AssocItem(did, args)); + self.record_res(qpath_hir_id, def_id); + return Ok(TypeRelativePath::AssocItem(def_id, args)); } } @@ -1445,6 +1444,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .probe_assoc_item(segment.ident, assoc_tag, qpath_hir_id, span, bound.def_id()) .expect("failed to find associated item"); + self.record_res(qpath_hir_id, assoc_item.def_id); + Ok((assoc_item.def_id, bound)) } @@ -2546,7 +2547,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { hir_ty.span, PermitVariants::No, ) - .map(|(ty, _, _)| ty) + .map(|(ty, _)| ty) .unwrap_or_else(|guar| Ty::new_error(tcx, guar)) } &hir::TyKind::Path(hir::QPath::LangItem(lang_item, span)) => { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index a148c3864acd0..8c0e7d7e8c6df 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -2211,12 +2211,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { path_span, PermitVariants::Yes, ); - let ty = result - .map(|(ty, _, _)| ty) - .unwrap_or_else(|guar| Ty::new_error(self.tcx(), guar)); + let ty = + result.map(|(ty, _)| ty).unwrap_or_else(|guar| Ty::new_error(self.tcx(), guar)); let ty = LoweredTy::from_raw(self, path_span, ty); - (result.map_or(Res::Err, |(_, kind, def_id)| Res::Def(kind, def_id)), ty) + ( + result.map_or(Res::Err, |(_, def_id)| { + Res::Def(self.tcx().def_kind(def_id), def_id) + }), + ty, + ) } QPath::LangItem(lang_item, span) => { let (res, ty) = self.resolve_lang_item_path(lang_item, span, hir_id); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index b5a5615015cae..f333c82040485 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -17,7 +17,7 @@ use rustc_hir_analysis::hir_ty_lowering::{ }; use rustc_infer::infer::{self, RegionVariableOrigin}; use rustc_infer::traits::{DynCompatibilityViolation, Obligation}; -use rustc_middle::ty::typeck_results::{HasTypeDependentDefs, TypeDependentDef}; +use rustc_middle::ty::typeck_results::HasTypeDependentDefs; use rustc_middle::ty::{self, Const, Ty, TyCtxt, TypeVisitableExt}; use rustc_session::Session; use rustc_span::{self, DUMMY_SP, ErrorGuaranteed, Ident, Span, sym}; @@ -439,8 +439,8 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> { self.write_ty(hir_id, ty) } - fn record_res(&self, hir_id: HirId, result: TypeDependentDef) { - self.write_resolution(hir_id, result); + fn record_res(&self, hir_id: HirId, def_id: DefId) { + self.write_resolution(hir_id, Ok((self.tcx.def_kind(def_id), def_id))); } fn infcx(&self) -> Option<&infer::InferCtxt<'tcx>> { diff --git a/tests/ui/associated-type-bounds/return-type-notation/consecutive-type-relative-path.rs b/tests/ui/associated-type-bounds/return-type-notation/consecutive-type-relative-path.rs new file mode 100644 index 0000000000000..7bdfc0024390e --- /dev/null +++ b/tests/ui/associated-type-bounds/return-type-notation/consecutive-type-relative-path.rs @@ -0,0 +1,16 @@ +// FIXME(fmease): Description. +//@ check-pass + +#![feature(return_type_notation)] + +trait TraitA { type Assoc: TraitB; } +trait TraitB { fn assoc() -> impl Sized; } + +fn scope() +where + T::Assoc::assoc(..): Iterator, +{ + let _: Vec = T::Assoc::assoc().collect(); +} + +fn main() {} diff --git a/tests/ui/const-generics/mgca/consecutive-type-relative-path.rs b/tests/ui/const-generics/mgca/consecutive-type-relative-path.rs new file mode 100644 index 0000000000000..f60c54dbca31b --- /dev/null +++ b/tests/ui/const-generics/mgca/consecutive-type-relative-path.rs @@ -0,0 +1,14 @@ +// FIXME(fmease): Description. +//@ check-pass + +#![feature(min_generic_const_args)] +#![expect(incomplete_features)] + +trait TraitA { type Assoc: TraitB; } +trait TraitB { #[type_const] const ASSOC: usize; } + +fn scope() -> [u8; T::Assoc::ASSOC] { + [0; T::Assoc::ASSOC] +} + +fn main() {}