Skip to content

Commit 2084985

Browse files
committed
Auto merge of #126651 - fmease:consec-shorthand-proj, r=<try>
Implement consecutive shorthand projections (associated type paths) like `T::AssocA::AssocB` I'd like to resolve / get feedback on the `FIXME` concerning "`Identity<T::Assoc>::Assoc`". Then I'll polish up this PR and make it ready for a types FCP (i.e., tests, tests, tests). Addresses #126360 (comment). CC #22519 (arbitrary shorthand projections).
2 parents 2db4ff4 + ed8def2 commit 2084985

25 files changed

+374
-82
lines changed

compiler/rustc_hir_analysis/src/collect.rs

+34-3
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,19 @@ use rustc_data_structures::captures::Captures;
1919
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
2020
use rustc_data_structures::unord::UnordMap;
2121
use rustc_errors::{struct_span_code_err, Applicability, Diag, ErrorGuaranteed, StashKey, E0228};
22+
use rustc_hir as hir;
2223
use rustc_hir::def::DefKind;
2324
use rustc_hir::def_id::{DefId, LocalDefId};
2425
use rustc_hir::intravisit::{self, walk_generics, Visitor};
25-
use rustc_hir::{self as hir};
2626
use rustc_hir::{GenericParamKind, Node};
2727
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
2828
use rustc_infer::traits::ObligationCause;
2929
use rustc_middle::hir::nested_filter;
3030
use rustc_middle::query::Providers;
31+
use rustc_middle::ty::typeck_results::{
32+
HasTypeDependentDefs, LocalTableInContext, LocalTableInContextMut, TypeDependentDef,
33+
TypeDependentDefs,
34+
};
3135
use rustc_middle::ty::util::{Discr, IntTypeExt};
3236
use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, Ty, TyCtxt, Upcast};
3337
use rustc_middle::{bug, span_bug};
@@ -38,7 +42,7 @@ use rustc_target::spec::abi;
3842
use rustc_trait_selection::infer::InferCtxtExt;
3943
use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName;
4044
use rustc_trait_selection::traits::ObligationCtxt;
41-
use std::cell::Cell;
45+
use std::cell::{Cell, RefCell};
4246
use std::iter;
4347
use std::ops::Bound;
4448

@@ -120,6 +124,7 @@ pub fn provide(providers: &mut Providers) {
120124
pub struct ItemCtxt<'tcx> {
121125
tcx: TyCtxt<'tcx>,
122126
item_def_id: LocalDefId,
127+
type_dependent_defs: RefCell<TypeDependentDefs>,
123128
tainted_by_errors: Cell<Option<ErrorGuaranteed>>,
124129
}
125130

@@ -342,7 +347,12 @@ fn bad_placeholder<'tcx>(
342347

343348
impl<'tcx> ItemCtxt<'tcx> {
344349
pub fn new(tcx: TyCtxt<'tcx>, item_def_id: LocalDefId) -> ItemCtxt<'tcx> {
345-
ItemCtxt { tcx, item_def_id, tainted_by_errors: Cell::new(None) }
350+
ItemCtxt {
351+
tcx,
352+
item_def_id,
353+
type_dependent_defs: Default::default(),
354+
tainted_by_errors: Cell::new(None),
355+
}
346356
}
347357

348358
pub fn lower_ty(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> {
@@ -505,6 +515,14 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
505515
// There's no place to record types from signatures?
506516
}
507517

518+
fn record_res(&self, hir_id: hir::HirId, result: TypeDependentDef) {
519+
LocalTableInContextMut::new(
520+
self.hir_id().owner,
521+
&mut self.type_dependent_defs.borrow_mut(),
522+
)
523+
.insert(hir_id, result);
524+
}
525+
508526
fn infcx(&self) -> Option<&InferCtxt<'tcx>> {
509527
None
510528
}
@@ -595,6 +613,19 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
595613

596614
(input_tys, output_ty)
597615
}
616+
617+
fn upcast(&self) -> &dyn HasTypeDependentDefs {
618+
self
619+
}
620+
}
621+
622+
impl HasTypeDependentDefs for ItemCtxt<'_> {
623+
fn type_dependent_def(&self, id: hir::HirId) -> Option<(DefKind, DefId)> {
624+
LocalTableInContext::new(self.hir_id().owner, &self.type_dependent_defs.borrow())
625+
.get(id)
626+
.copied()
627+
.and_then(|result| result.ok())
628+
}
598629
}
599630

600631
/// Synthesize a new lifetime name that doesn't clash with any of the lifetimes already present.

compiler/rustc_hir_analysis/src/collect/type_of.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -145,11 +145,12 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
145145
..
146146
}) => {
147147
let body_owner = tcx.hir().enclosing_body_owner(hir_id);
148-
let tables = tcx.typeck(body_owner);
148+
let typeck_results = tcx.typeck(body_owner);
149149
// This may fail in case the method/path does not actually exist.
150150
// As there is no relevant param for `def_id`, we simply return
151151
// `None` here.
152-
let Some(type_dependent_def) = tables.type_dependent_def_id(parent_node_id) else {
152+
let Some(type_dependent_def) = typeck_results.type_dependent_def_id(parent_node_id)
153+
else {
153154
return Ty::new_error_with_message(
154155
tcx,
155156
span,

compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs

+61-10
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ use rustc_infer::traits::ObligationCause;
3939
use rustc_middle::middle::stability::AllowUnstable;
4040
use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput};
4141
use rustc_middle::ty::print::PrintPolyTraitRefExt as _;
42+
use rustc_middle::ty::typeck_results::{HasTypeDependentDefs, TypeDependentDef};
4243
use rustc_middle::ty::{
4344
self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, ParamEnv, Ty, TyCtxt,
4445
TypeVisitableExt,
@@ -98,7 +99,7 @@ pub enum RegionInferReason<'a> {
9899
/// the [`rustc_middle::ty`] representation.
99100
///
100101
/// This trait used to be called `AstConv`.
101-
pub trait HirTyLowerer<'tcx> {
102+
pub trait HirTyLowerer<'tcx>: HasTypeDependentDefs {
102103
fn tcx(&self) -> TyCtxt<'tcx>;
103104

104105
/// Returns the [`LocalDefId`] of the overarching item whose constituents get lowered.
@@ -173,6 +174,8 @@ pub trait HirTyLowerer<'tcx> {
173174
/// Record the lowered type of a HIR node in this context.
174175
fn record_ty(&self, hir_id: HirId, ty: Ty<'tcx>, span: Span);
175176

177+
fn record_res(&self, hir_id: hir::HirId, result: TypeDependentDef);
178+
176179
/// The inference context of the lowering context if applicable.
177180
fn infcx(&self) -> Option<&InferCtxt<'tcx>>;
178181

@@ -192,6 +195,8 @@ pub trait HirTyLowerer<'tcx> {
192195
{
193196
self
194197
}
198+
199+
fn upcast(&self) -> &dyn HasTypeDependentDefs;
195200
}
196201

197202
/// New-typed boolean indicating whether explicit late-bound lifetimes
@@ -992,6 +997,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
992997
/// [type-relative]: hir::QPath::TypeRelative
993998
/// [#22519]: https://github.com/rust-lang/rust/issues/22519
994999
/// [iat]: https://github.com/rust-lang/rust/issues/8995#issuecomment-1569208403
1000+
// FIXME(fmease): Update docs
9951001
//
9961002
// NOTE: When this function starts resolving `Trait::AssocTy` successfully
9971003
// it should also start reporting the `BARE_TRAIT_OBJECTS` lint.
@@ -1006,13 +1012,33 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
10061012
permit_variants: bool,
10071013
) -> Result<(Ty<'tcx>, DefKind, DefId), ErrorGuaranteed> {
10081014
debug!(%qself_ty, ?assoc_segment.ident);
1015+
let result = self.lower_assoc_path_inner(
1016+
hir_ref_id,
1017+
span,
1018+
qself_ty,
1019+
qself,
1020+
assoc_segment,
1021+
permit_variants,
1022+
);
1023+
self.record_res(hir_ref_id, result.map(|(_, def_kind, def_id)| (def_kind, def_id)));
1024+
result
1025+
}
1026+
1027+
fn lower_assoc_path_inner(
1028+
&self,
1029+
hir_ref_id: HirId,
1030+
span: Span,
1031+
qself_ty: Ty<'tcx>,
1032+
qself: &'tcx hir::Ty<'tcx>,
1033+
assoc_segment: &'tcx hir::PathSegment<'tcx>,
1034+
permit_variants: bool,
1035+
) -> Result<(Ty<'tcx>, DefKind, DefId), ErrorGuaranteed> {
10091036
let tcx = self.tcx();
10101037

10111038
let assoc_ident = assoc_segment.ident;
1012-
let qself_res = if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = &qself.kind {
1013-
path.res
1014-
} else {
1015-
Res::Err
1039+
let qself_res = match &qself.kind {
1040+
hir::TyKind::Path(qpath) => self.upcast().qpath_res(qpath, qself.hir_id),
1041+
_ => Res::Err,
10161042
};
10171043

10181044
// Check if we have an enum variant or an inherent associated type.
@@ -1038,15 +1064,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
10381064
}
10391065

10401066
// FIXME(inherent_associated_types, #106719): Support self types other than ADTs.
1041-
if let Some((ty, did)) = self.probe_inherent_assoc_ty(
1067+
if let Some((ty, def_id)) = self.probe_inherent_assoc_ty(
10421068
assoc_ident,
10431069
assoc_segment,
10441070
adt_def.did(),
10451071
qself_ty,
10461072
hir_ref_id,
10471073
span,
10481074
)? {
1049-
return Ok((ty, DefKind::AssocTy, did));
1075+
return Ok((ty, DefKind::AssocTy, def_id));
10501076
}
10511077
}
10521078

@@ -1077,13 +1103,37 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
10771103
)?
10781104
}
10791105
(
1080-
&ty::Param(_),
1081-
Res::SelfTyParam { trait_: param_did } | Res::Def(DefKind::TyParam, param_did),
1106+
ty::Param(_),
1107+
Res::SelfTyParam { trait_: param_def_id }
1108+
| Res::Def(DefKind::TyParam, param_def_id),
10821109
) => self.probe_single_ty_param_bound_for_assoc_ty(
1083-
param_did.expect_local(),
1110+
param_def_id.expect_local(),
10841111
assoc_ident,
10851112
span,
10861113
)?,
1114+
(ty::Alias(ty::Projection, alias_ty), Res::Def(DefKind::AssocTy, _)) => {
1115+
// FIXME: Utilizing `item_bounds` for this is cycle-prone.
1116+
let predicates = tcx.item_bounds(alias_ty.def_id).instantiate(tcx, alias_ty.args);
1117+
1118+
self.probe_single_bound_for_assoc_item(
1119+
|| {
1120+
let trait_refs = predicates.iter().filter_map(|pred| {
1121+
pred.as_trait_clause().map(|t| t.map_bound(|t| t.trait_ref))
1122+
});
1123+
traits::transitive_bounds_that_define_assoc_item(
1124+
tcx,
1125+
trait_refs,
1126+
assoc_ident,
1127+
)
1128+
},
1129+
qself_ty,
1130+
None,
1131+
ty::AssocKind::Type,
1132+
assoc_ident,
1133+
span,
1134+
None,
1135+
)?
1136+
}
10871137
_ => {
10881138
let reported = if variant_resolution.is_some() {
10891139
// Variant in type position
@@ -1187,6 +1237,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
11871237
);
11881238
});
11891239
}
1240+
11901241
Ok((ty, DefKind::AssocTy, assoc_ty.def_id))
11911242
}
11921243

compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -170,9 +170,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
170170
pub(crate) fn write_resolution(
171171
&self,
172172
hir_id: HirId,
173-
r: Result<(DefKind, DefId), ErrorGuaranteed>,
173+
result: Result<(DefKind, DefId), ErrorGuaranteed>,
174174
) {
175-
self.typeck_results.borrow_mut().type_dependent_defs_mut().insert(hir_id, r);
175+
self.typeck_results.borrow_mut().type_dependent_defs_mut().insert(hir_id, result);
176176
}
177177

178178
#[instrument(level = "debug", skip(self))]

compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs

+1-5
Original file line numberDiff line numberDiff line change
@@ -1984,12 +1984,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
19841984
.map(|(ty, _, _)| ty)
19851985
.unwrap_or_else(|guar| Ty::new_error(self.tcx(), guar));
19861986
let ty = LoweredTy::from_raw(self, path_span, ty);
1987-
let result = result.map(|(_, kind, def_id)| (kind, def_id));
19881987

1989-
// Write back the new resolution.
1990-
self.write_resolution(hir_id, result);
1991-
1992-
(result.map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)), ty)
1988+
(result.map_or(Res::Err, |(_, kind, def_id)| Res::Def(kind, def_id)), ty)
19931989
}
19941990
QPath::LangItem(lang_item, span) => {
19951991
let (res, ty) = self.resolve_lang_item_path(lang_item, span, hir_id);

compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs

+17-2
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,14 @@ use crate::coercion::DynamicCoerceMany;
1111
use crate::fallback::DivergingFallbackBehavior;
1212
use crate::fn_ctxt::checks::DivergingBlockBehavior;
1313
use crate::{CoroutineTypes, Diverges, EnclosingBreakables, TypeckRootCtxt};
14-
use hir::def_id::CRATE_DEF_ID;
1514
use rustc_hir as hir;
16-
use rustc_hir::def_id::{DefId, LocalDefId};
15+
use rustc_hir::def::DefKind;
16+
use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
1717
use rustc_hir_analysis::hir_ty_lowering::{HirTyLowerer, RegionInferReason};
1818
use rustc_infer::infer;
1919
use rustc_infer::infer::error_reporting::sub_relations::SubRelations;
2020
use rustc_infer::infer::error_reporting::TypeErrCtxt;
21+
use rustc_middle::ty::typeck_results::{HasTypeDependentDefs, TypeDependentDef};
2122
use rustc_middle::ty::{self, Const, Ty, TyCtxt, TypeVisitableExt};
2223
use rustc_session::Session;
2324
use rustc_span::symbol::Ident;
@@ -334,6 +335,10 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> {
334335
self.write_ty(hir_id, ty)
335336
}
336337

338+
fn record_res(&self, hir_id: hir::HirId, result: TypeDependentDef) {
339+
self.write_resolution(hir_id, result);
340+
}
341+
337342
fn infcx(&self) -> Option<&infer::InferCtxt<'tcx>> {
338343
Some(&self.infcx)
339344
}
@@ -357,6 +362,16 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> {
357362
};
358363
(input_tys, output_ty)
359364
}
365+
366+
fn upcast(&self) -> &dyn HasTypeDependentDefs {
367+
self
368+
}
369+
}
370+
371+
impl HasTypeDependentDefs for FnCtxt<'_, '_> {
372+
fn type_dependent_def(&self, id: hir::HirId) -> Option<(DefKind, DefId)> {
373+
self.typeck_results.borrow().type_dependent_def(id)
374+
}
360375
}
361376

362377
/// The `ty` representation of a user-provided type. Depending on the use-site

compiler/rustc_middle/src/ty/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ pub mod pattern;
137137
pub mod print;
138138
pub mod relate;
139139
pub mod trait_def;
140+
pub mod typeck_results;
140141
pub mod util;
141142
pub mod visit;
142143
pub mod vtable;
@@ -163,7 +164,6 @@ mod rvalue_scopes;
163164
mod structural_impls;
164165
#[allow(hidden_glob_reexports)]
165166
mod sty;
166-
mod typeck_results;
167167

168168
// Data types
169169

0 commit comments

Comments
 (0)