Skip to content

Commit b732baf

Browse files
committed
[PoC] Track type-dependent defs in ItemCtxts (minimally)
1 parent 829c662 commit b732baf

File tree

12 files changed

+136
-50
lines changed

12 files changed

+136
-50
lines changed

Diff for: compiler/rustc_hir_analysis/src/collect.rs

+29-2
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
//! At present, however, we do run collection across all items in the
1515
//! crate as a kind of pass. This should eventually be factored away.
1616
17-
use std::cell::Cell;
17+
use std::cell::{Cell, RefCell};
1818
use std::iter;
1919
use std::ops::Bound;
2020

@@ -35,6 +35,10 @@ use rustc_infer::traits::ObligationCause;
3535
use rustc_middle::hir::nested_filter;
3636
use rustc_middle::query::Providers;
3737
use rustc_middle::ty::fold::fold_regions;
38+
use rustc_middle::ty::typeck_results::{
39+
HasTypeDependentDefs, LocalTableInContext, LocalTableInContextMut, TypeDependentDef,
40+
TypeDependentDefs,
41+
};
3842
use rustc_middle::ty::util::{Discr, IntTypeExt};
3943
use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, Ty, TyCtxt, TypingMode};
4044
use rustc_middle::{bug, span_bug};
@@ -126,6 +130,7 @@ pub fn provide(providers: &mut Providers) {
126130
pub struct ItemCtxt<'tcx> {
127131
tcx: TyCtxt<'tcx>,
128132
item_def_id: LocalDefId,
133+
type_dependent_defs: RefCell<TypeDependentDefs>,
129134
tainted_by_errors: Cell<Option<ErrorGuaranteed>>,
130135
}
131136

@@ -375,7 +380,12 @@ fn bad_placeholder<'cx, 'tcx>(
375380

376381
impl<'tcx> ItemCtxt<'tcx> {
377382
pub fn new(tcx: TyCtxt<'tcx>, item_def_id: LocalDefId) -> ItemCtxt<'tcx> {
378-
ItemCtxt { tcx, item_def_id, tainted_by_errors: Cell::new(None) }
383+
ItemCtxt {
384+
tcx,
385+
item_def_id,
386+
type_dependent_defs: Default::default(),
387+
tainted_by_errors: Cell::new(None),
388+
}
379389
}
380390

381391
pub fn lower_ty(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> {
@@ -542,6 +552,14 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
542552
// There's no place to record types from signatures?
543553
}
544554

555+
fn record_res(&self, hir_id: hir::HirId, result: TypeDependentDef) {
556+
LocalTableInContextMut::new(
557+
self.hir_id().owner,
558+
&mut self.type_dependent_defs.borrow_mut(),
559+
)
560+
.insert(hir_id, result);
561+
}
562+
545563
fn infcx(&self) -> Option<&InferCtxt<'tcx>> {
546564
None
547565
}
@@ -630,6 +648,15 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
630648
}
631649
}
632650

651+
impl HasTypeDependentDefs for ItemCtxt<'_> {
652+
fn type_dependent_def(&self, id: hir::HirId) -> Option<(DefKind, DefId)> {
653+
LocalTableInContext::new(self.hir_id().owner, &self.type_dependent_defs.borrow())
654+
.get(id)
655+
.copied()
656+
.and_then(|result| result.ok())
657+
}
658+
}
659+
633660
/// Synthesize a new lifetime name that doesn't clash with any of the lifetimes already present.
634661
fn get_new_lifetime_name<'tcx>(
635662
tcx: TyCtxt<'tcx>,

Diff for: compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs

+32-16
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ use rustc_middle::middle::stability::AllowUnstable;
3939
use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput};
4040
use rustc_middle::ty::fold::fold_regions;
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, TypingMode,
@@ -107,7 +108,7 @@ pub enum RegionInferReason<'a> {
107108
/// the [`rustc_middle::ty`] representation.
108109
///
109110
/// This trait used to be called `AstConv`.
110-
pub trait HirTyLowerer<'tcx> {
111+
pub trait HirTyLowerer<'tcx>: HasTypeDependentDefs {
111112
fn tcx(&self) -> TyCtxt<'tcx>;
112113

113114
fn dcx(&self) -> DiagCtxtHandle<'_>;
@@ -184,6 +185,8 @@ pub trait HirTyLowerer<'tcx> {
184185
/// Record the lowered type of a HIR node in this context.
185186
fn record_ty(&self, hir_id: HirId, ty: Ty<'tcx>, span: Span);
186187

188+
fn record_res(&self, hir_id: hir::HirId, result: TypeDependentDef);
189+
187190
/// The inference context of the lowering context if applicable.
188191
fn infcx(&self) -> Option<&InferCtxt<'tcx>>;
189192

@@ -1064,6 +1067,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
10641067
/// [type-relative]: hir::QPath::TypeRelative
10651068
/// [#22519]: https://github.com/rust-lang/rust/issues/22519
10661069
/// [iat]: https://github.com/rust-lang/rust/issues/8995#issuecomment-1569208403
1070+
// FIXME(fmease): Update docs
10671071
//
10681072
// NOTE: When this function starts resolving `Trait::AssocTy` successfully
10691073
// it should also start reporting the `BARE_TRAIT_OBJECTS` lint.
@@ -1078,8 +1082,28 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
10781082
permit_variants: bool,
10791083
) -> Result<(Ty<'tcx>, DefKind, DefId), ErrorGuaranteed> {
10801084
debug!(%qself_ty, ?assoc_segment.ident);
1081-
let tcx = self.tcx();
1085+
let result = self.lower_assoc_path_inner(
1086+
hir_ref_id,
1087+
span,
1088+
qself_ty,
1089+
qself,
1090+
assoc_segment,
1091+
permit_variants,
1092+
);
1093+
self.record_res(hir_ref_id, result.map(|(_, def_kind, def_id)| (def_kind, def_id)));
1094+
result
1095+
}
10821096

1097+
fn lower_assoc_path_inner(
1098+
&self,
1099+
hir_ref_id: HirId,
1100+
span: Span,
1101+
qself_ty: Ty<'tcx>,
1102+
qself: &'tcx hir::Ty<'tcx>,
1103+
assoc_segment: &'tcx hir::PathSegment<'tcx>,
1104+
permit_variants: bool,
1105+
) -> Result<(Ty<'tcx>, DefKind, DefId), ErrorGuaranteed> {
1106+
let tcx = self.tcx();
10831107
let assoc_ident = assoc_segment.ident;
10841108

10851109
// Check if we have an enum variant or an inherent associated type.
@@ -1105,22 +1129,21 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
11051129
}
11061130

11071131
// FIXME(inherent_associated_types, #106719): Support self types other than ADTs.
1108-
if let Some((ty, did)) = self.probe_inherent_assoc_ty(
1132+
if let Some((ty, def_id)) = self.probe_inherent_assoc_ty(
11091133
assoc_ident,
11101134
assoc_segment,
11111135
adt_def.did(),
11121136
qself_ty,
11131137
hir_ref_id,
11141138
span,
11151139
)? {
1116-
return Ok((ty, DefKind::AssocTy, did));
1140+
return Ok((ty, DefKind::AssocTy, def_id));
11171141
}
11181142
}
11191143

1120-
let qself_res = if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = &qself.kind {
1121-
path.res
1122-
} else {
1123-
Res::Err
1144+
let qself_res = match &qself.kind {
1145+
hir::TyKind::Path(qpath) => self.qpath_res(qpath, qself.hir_id),
1146+
_ => Res::Err,
11241147
};
11251148

11261149
// Find the type of the associated item, and the trait where the associated
@@ -1159,14 +1182,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
11591182
assoc_ident,
11601183
span,
11611184
)?,
1162-
// FIXME(fmease):
1163-
// Require the pre-lowered projectee (the HIR QSelf) to have `DefKind::AssocTy`. Rephrased,
1164-
// `T::Assoc::Assoc` typeck'ing shouldn't imply `Identity<T::Assoc>::Assoc` typeck'ing where
1165-
// `Identity` is an eager (i.e., non-lazy) type alias. We should do this
1166-
// * for consistency with lazy type aliases (`ty::Weak`)
1167-
// * for consistency with the fact that `T::Assoc` typeck'ing doesn't imply `Identity<T>::Assoc`
1168-
// typeck'ing
1169-
(ty::Alias(ty::Projection, alias_ty), _ /* Res::Def(DefKind::AssocTy, _) */) => {
1185+
(ty::Alias(ty::Projection, alias_ty), Res::Def(DefKind::AssocTy, _)) => {
11701186
// FIXME: Utilizing `item_bounds` for this is cycle-prone.
11711187
let predicates = tcx.item_bounds(alias_ty.def_id).instantiate(tcx, alias_ty.args);
11721188

Diff for: compiler/rustc_hir_analysis/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ This API is completely unstable and subject to change.
7070
#![feature(never_type)]
7171
#![feature(rustdoc_internals)]
7272
#![feature(slice_partition_dedup)]
73+
#![feature(trait_upcasting)]
7374
#![feature(try_blocks)]
7475
#![feature(unwrap_infallible)]
7576
#![warn(unreachable_pub)]

Diff for: compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -173,9 +173,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
173173
pub(crate) fn write_resolution(
174174
&self,
175175
hir_id: HirId,
176-
r: Result<(DefKind, DefId), ErrorGuaranteed>,
176+
result: Result<(DefKind, DefId), ErrorGuaranteed>,
177177
) {
178-
self.typeck_results.borrow_mut().type_dependent_defs_mut().insert(hir_id, r);
178+
self.typeck_results.borrow_mut().type_dependent_defs_mut().insert(hir_id, result);
179179
}
180180

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

Diff for: compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs

+1-5
Original file line numberDiff line numberDiff line change
@@ -2110,12 +2110,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
21102110
.map(|(ty, _, _)| ty)
21112111
.unwrap_or_else(|guar| Ty::new_error(self.tcx(), guar));
21122112
let ty = LoweredTy::from_raw(self, path_span, ty);
2113-
let result = result.map(|(_, kind, def_id)| (kind, def_id));
21142113

2115-
// Write back the new resolution.
2116-
self.write_resolution(hir_id, result);
2117-
2118-
(result.map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)), ty)
2114+
(result.map_or(Res::Err, |(_, kind, def_id)| Res::Def(kind, def_id)), ty)
21192115
}
21202116
QPath::LangItem(lang_item, span) => {
21212117
let (res, ty) = self.resolve_lang_item_path(lang_item, span, hir_id);

Diff for: compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs

+13-2
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,13 @@ mod suggestions;
88
use std::cell::{Cell, RefCell};
99
use std::ops::Deref;
1010

11-
use hir::def_id::CRATE_DEF_ID;
1211
use rustc_errors::DiagCtxtHandle;
1312
use rustc_hir as hir;
14-
use rustc_hir::def_id::{DefId, LocalDefId};
13+
use rustc_hir::def::DefKind;
14+
use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId};
1515
use rustc_hir_analysis::hir_ty_lowering::{HirTyLowerer, RegionInferReason};
1616
use rustc_infer::infer;
17+
use rustc_middle::ty::typeck_results::{HasTypeDependentDefs, TypeDependentDef};
1718
use rustc_middle::ty::{self, Const, Ty, TyCtxt, TypeVisitableExt};
1819
use rustc_session::Session;
1920
use rustc_span::symbol::Ident;
@@ -337,6 +338,10 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> {
337338
self.write_ty(hir_id, ty)
338339
}
339340

341+
fn record_res(&self, hir_id: hir::HirId, result: TypeDependentDef) {
342+
self.write_resolution(hir_id, result);
343+
}
344+
340345
fn infcx(&self) -> Option<&infer::InferCtxt<'tcx>> {
341346
Some(&self.infcx)
342347
}
@@ -358,6 +363,12 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> {
358363
}
359364
}
360365

366+
impl HasTypeDependentDefs for FnCtxt<'_, '_> {
367+
fn type_dependent_def(&self, id: hir::HirId) -> Option<(DefKind, DefId)> {
368+
self.typeck_results.borrow().type_dependent_def(id)
369+
}
370+
}
371+
361372
/// The `ty` representation of a user-provided type. Depending on the use-site
362373
/// we want to either use the unnormalized or the normalized form of this type.
363374
///

Diff for: compiler/rustc_middle/src/ty/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ pub mod pattern;
123123
pub mod print;
124124
pub mod relate;
125125
pub mod trait_def;
126+
pub mod typeck_results;
126127
pub mod util;
127128
pub mod visit;
128129
pub mod vtable;
@@ -150,7 +151,6 @@ mod rvalue_scopes;
150151
mod structural_impls;
151152
#[allow(hidden_glob_reexports)]
152153
mod sty;
153-
mod typeck_results;
154154

155155
// Data types
156156

Diff for: compiler/rustc_middle/src/ty/typeck_results.rs

+40-17
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,7 @@ pub struct TypeckResults<'tcx> {
3232
/// The `HirId::owner` all `ItemLocalId`s in this table are relative to.
3333
pub hir_owner: OwnerId,
3434

35-
/// Resolved definitions for `<T>::X` associated paths and
36-
/// method calls, including those of overloaded operators.
37-
type_dependent_defs: ItemLocalMap<Result<(DefKind, DefId), ErrorGuaranteed>>,
35+
type_dependent_defs: TypeDependentDefs,
3836

3937
/// Resolved field indices for field accesses in expressions (`S { field }`, `obj.field`)
4038
/// or patterns (`S { field }`). The index is often useful by itself, but to learn more
@@ -248,32 +246,22 @@ impl<'tcx> TypeckResults<'tcx> {
248246

249247
/// Returns the final resolution of a `QPath` in an `Expr` or `Pat` node.
250248
pub fn qpath_res(&self, qpath: &hir::QPath<'_>, id: HirId) -> Res {
251-
match *qpath {
252-
hir::QPath::Resolved(_, path) => path.res,
253-
hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => self
254-
.type_dependent_def(id)
255-
.map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)),
256-
}
249+
HasTypeDependentDefs::qpath_res(self, qpath, id)
257250
}
258251

259-
pub fn type_dependent_defs(
260-
&self,
261-
) -> LocalTableInContext<'_, Result<(DefKind, DefId), ErrorGuaranteed>> {
252+
pub fn type_dependent_defs(&self) -> LocalTableInContext<'_, TypeDependentDef> {
262253
LocalTableInContext { hir_owner: self.hir_owner, data: &self.type_dependent_defs }
263254
}
264255

265256
pub fn type_dependent_def(&self, id: HirId) -> Option<(DefKind, DefId)> {
266-
validate_hir_id_for_typeck_results(self.hir_owner, id);
267-
self.type_dependent_defs.get(&id.local_id).cloned().and_then(|r| r.ok())
257+
self.type_dependent_defs().get(id).copied().and_then(|result| result.ok())
268258
}
269259

270260
pub fn type_dependent_def_id(&self, id: HirId) -> Option<DefId> {
271261
self.type_dependent_def(id).map(|(_, def_id)| def_id)
272262
}
273263

274-
pub fn type_dependent_defs_mut(
275-
&mut self,
276-
) -> LocalTableInContextMut<'_, Result<(DefKind, DefId), ErrorGuaranteed>> {
264+
pub fn type_dependent_defs_mut(&mut self) -> LocalTableInContextMut<'_, TypeDependentDef> {
277265
LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.type_dependent_defs }
278266
}
279267

@@ -531,6 +519,33 @@ impl<'tcx> TypeckResults<'tcx> {
531519
}
532520
}
533521

522+
/// Resolved definitions for `<T>::X` associated paths and
523+
/// method calls, including those of overloaded operators.
524+
pub type TypeDependentDefs = ItemLocalMap<TypeDependentDef>;
525+
526+
pub type TypeDependentDef = Result<(DefKind, DefId), ErrorGuaranteed>;
527+
528+
// FIXME(fmease): Yuck!
529+
pub trait HasTypeDependentDefs {
530+
fn type_dependent_def(&self, id: HirId) -> Option<(DefKind, DefId)>;
531+
532+
/// Returns the final resolution of a `QPath`.
533+
fn qpath_res(&self, qpath: &hir::QPath<'_>, id: HirId) -> Res {
534+
match qpath {
535+
hir::QPath::Resolved(_, path) => path.res,
536+
hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => self
537+
.type_dependent_def(id)
538+
.map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)),
539+
}
540+
}
541+
}
542+
543+
impl HasTypeDependentDefs for TypeckResults<'_> {
544+
fn type_dependent_def(&self, id: HirId) -> Option<(DefKind, DefId)> {
545+
self.type_dependent_def(id)
546+
}
547+
}
548+
534549
/// Validate that the given HirId (respectively its `local_id` part) can be
535550
/// safely used as a key in the maps of a TypeckResults. For that to be
536551
/// the case, the HirId must have the same `owner` as all the other IDs in
@@ -563,6 +578,10 @@ pub struct LocalTableInContext<'a, V> {
563578
}
564579

565580
impl<'a, V> LocalTableInContext<'a, V> {
581+
pub fn new(hir_owner: OwnerId, data: &'a ItemLocalMap<V>) -> Self {
582+
Self { hir_owner, data }
583+
}
584+
566585
pub fn contains_key(&self, id: HirId) -> bool {
567586
validate_hir_id_for_typeck_results(self.hir_owner, id);
568587
self.data.contains_key(&id.local_id)
@@ -601,6 +620,10 @@ pub struct LocalTableInContextMut<'a, V> {
601620
}
602621

603622
impl<'a, V> LocalTableInContextMut<'a, V> {
623+
pub fn new(hir_owner: OwnerId, data: &'a mut ItemLocalMap<V>) -> Self {
624+
Self { hir_owner, data }
625+
}
626+
604627
pub fn get_mut(&mut self, id: HirId) -> Option<&mut V> {
605628
validate_hir_id_for_typeck_results(self.hir_owner, id);
606629
self.data.get_mut(&id.local_id)

Diff for: src/tools/tidy/src/ui_tests.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use ignore::Walk;
1717
const ENTRY_LIMIT: u32 = 901;
1818
// FIXME: The following limits should be reduced eventually.
1919

20-
const ISSUES_ENTRY_LIMIT: u32 = 1672;
20+
const ISSUES_ENTRY_LIMIT: u32 = 1670;
2121

2222
const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[
2323
"rs", // test source files
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error[E0223]: ambiguous associated type
2+
--> $DIR/non-consecutive-shorthand-projections.rs:14:12
3+
|
4+
LL | let _: Identity<T::Project>::Project;
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
help: if there were a trait named `Example` with associated type `Project` implemented for `<T as Trait>::Project`, you could use the fully-qualified path
8+
|
9+
LL | let _: <<T as Trait>::Project as Example>::Project;
10+
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
11+
12+
error: aborting due to 1 previous error
13+
14+
For more information about this error, try `rustc --explain E0223`.

0 commit comments

Comments
 (0)