Skip to content

Commit 25f7b80

Browse files
committed
[PoC] Track type-dependent defs in ItemCtxts (minimally)
1 parent 2784404 commit 25f7b80

File tree

11 files changed

+117
-47
lines changed

11 files changed

+117
-47
lines changed

compiler/rustc_hir_analysis/src/collect.rs

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
//! crate as a kind of pass. This should eventually be factored away.
1616
1717
use std::assert_matches::assert_matches;
18-
use std::cell::Cell;
18+
use std::cell::{Cell, RefCell};
1919
use std::iter;
2020
use std::ops::Bound;
2121

@@ -34,6 +34,10 @@ use rustc_hir::{self as hir, GenericParamKind, HirId, Node, PreciseCapturingArgK
3434
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
3535
use rustc_infer::traits::{DynCompatibilityViolation, ObligationCause};
3636
use rustc_middle::query::Providers;
37+
use rustc_middle::ty::typeck_results::{
38+
HasTypeDependentDefs, LocalTableInContext, LocalTableInContextMut, TypeDependentDef,
39+
TypeDependentDefs,
40+
};
3741
use rustc_middle::ty::util::{Discr, IntTypeExt};
3842
use rustc_middle::ty::{
3943
self, AdtKind, Const, IsSuggestable, Ty, TyCtxt, TypeVisitableExt, TypingMode, fold_regions,
@@ -132,6 +136,7 @@ pub(crate) fn provide(providers: &mut Providers) {
132136
pub(crate) struct ItemCtxt<'tcx> {
133137
tcx: TyCtxt<'tcx>,
134138
item_def_id: LocalDefId,
139+
type_dependent_defs: RefCell<TypeDependentDefs>,
135140
tainted_by_errors: Cell<Option<ErrorGuaranteed>>,
136141
}
137142

@@ -243,7 +248,12 @@ fn bad_placeholder<'cx, 'tcx>(
243248

244249
impl<'tcx> ItemCtxt<'tcx> {
245250
pub(crate) fn new(tcx: TyCtxt<'tcx>, item_def_id: LocalDefId) -> ItemCtxt<'tcx> {
246-
ItemCtxt { tcx, item_def_id, tainted_by_errors: Cell::new(None) }
251+
ItemCtxt {
252+
tcx,
253+
item_def_id,
254+
type_dependent_defs: Default::default(),
255+
tainted_by_errors: Cell::new(None),
256+
}
247257
}
248258

249259
pub(crate) fn lower_ty(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> {
@@ -510,6 +520,14 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
510520
// There's no place to record types from signatures?
511521
}
512522

523+
fn record_res(&self, hir_id: hir::HirId, result: TypeDependentDef) {
524+
LocalTableInContextMut::new(
525+
self.hir_id().owner,
526+
&mut self.type_dependent_defs.borrow_mut(),
527+
)
528+
.insert(hir_id, result);
529+
}
530+
513531
fn infcx(&self) -> Option<&InferCtxt<'tcx>> {
514532
None
515533
}
@@ -569,6 +587,15 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
569587
}
570588
}
571589

590+
impl HasTypeDependentDefs for ItemCtxt<'_> {
591+
fn type_dependent_def(&self, id: hir::HirId) -> Option<(DefKind, DefId)> {
592+
LocalTableInContext::new(self.hir_id().owner, &self.type_dependent_defs.borrow())
593+
.get(id)
594+
.copied()
595+
.and_then(|result| result.ok())
596+
}
597+
}
598+
572599
/// Synthesize a new lifetime name that doesn't clash with any of the lifetimes already present.
573600
fn get_new_lifetime_name<'tcx>(
574601
tcx: TyCtxt<'tcx>,

compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ use rustc_macros::{TypeFoldable, TypeVisitable};
3838
use rustc_middle::middle::stability::AllowUnstable;
3939
use rustc_middle::mir::interpret::LitToConstInput;
4040
use rustc_middle::ty::print::PrintPolyTraitRefExt as _;
41+
use rustc_middle::ty::typeck_results::{HasTypeDependentDefs, TypeDependentDef};
4142
use rustc_middle::ty::{
4243
self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, Ty, TyCtxt, TypeVisitableExt,
4344
TypingMode, Upcast, fold_regions,
@@ -111,7 +112,7 @@ pub struct InherentAssocCandidate {
111112
/// the [`rustc_middle::ty`] representation.
112113
///
113114
/// This trait used to be called `AstConv`.
114-
pub trait HirTyLowerer<'tcx> {
115+
pub trait HirTyLowerer<'tcx>: HasTypeDependentDefs {
115116
fn tcx(&self) -> TyCtxt<'tcx>;
116117

117118
fn dcx(&self) -> DiagCtxtHandle<'_>;
@@ -202,6 +203,9 @@ pub trait HirTyLowerer<'tcx> {
202203
/// Record the lowered type of a HIR node in this context.
203204
fn record_ty(&self, hir_id: HirId, ty: Ty<'tcx>, span: Span);
204205

206+
/// Record the resolution of a HIR node corresponding to a type-dependent definition in this context.
207+
fn record_res(&self, hir_id: hir::HirId, result: TypeDependentDef);
208+
205209
/// The inference context of the lowering context if applicable.
206210
fn infcx(&self) -> Option<&InferCtxt<'tcx>>;
207211

@@ -1175,6 +1179,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
11751179
///
11761180
/// [#22519]: https://github.com/rust-lang/rust/issues/22519
11771181
/// [iat]: https://github.com/rust-lang/rust/issues/8995#issuecomment-1569208403
1182+
// FIXME(fmease): Update docs
11781183
//
11791184
// NOTE: When this function starts resolving `Trait::AssocTy` successfully
11801185
// it should also start reporting the `BARE_TRAIT_OBJECTS` lint.
@@ -1198,9 +1203,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
11981203
LowerTypeRelativePathMode::Type(permit_variants),
11991204
)? {
12001205
TypeRelativePath::AssocItem(def_id, args) => {
1206+
let kind = tcx.def_kind(def_id);
1207+
self.record_res(qpath_hir_id, Ok((kind, def_id)));
12011208
let alias_ty = ty::AliasTy::new_from_args(tcx, def_id, args);
12021209
let ty = Ty::new_alias(tcx, alias_ty.kind(tcx), alias_ty);
1203-
Ok((ty, tcx.def_kind(def_id), def_id))
1210+
Ok((ty, kind, def_id))
12041211
}
12051212
TypeRelativePath::Variant { adt, variant_did } => {
12061213
Ok((adt, DefKind::Variant, variant_did))
@@ -1362,7 +1369,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
13621369
let tcx = self.tcx();
13631370

13641371
let self_ty_res = match hir_self_ty.kind {
1365-
hir::TyKind::Path(hir::QPath::Resolved(_, path)) => path.res,
1372+
hir::TyKind::Path(qpath) => self.qpath_res(&qpath, hir_self_ty.hir_id),
13661373
_ => Res::Err,
13671374
};
13681375

@@ -1399,14 +1406,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
13991406
segment.ident,
14001407
span,
14011408
)?,
1402-
// FIXME(fmease):
1403-
// Require the pre-lowered projectee (the HIR QSelf) to have `DefKind::AssocTy`. Rephrased,
1404-
// `T::Assoc::Assoc` typeck'ing shouldn't imply `Identity<T::Assoc>::Assoc` typeck'ing where
1405-
// `Identity` is an eager (i.e., non-lazy) type alias. We should do this
1406-
// * for consistency with lazy type aliases (`ty::Weak`)
1407-
// * for consistency with the fact that `T::Assoc` typeck'ing doesn't imply `Identity<T>::Assoc`
1408-
// typeck'ing
1409-
(ty::Alias(ty::Projection, alias_ty), _ /* Res::Def(DefKind::AssocTy, _) */) => {
1409+
(ty::Alias(ty::Projection, alias_ty), Res::Def(DefKind::AssocTy, _)) => {
14101410
// FIXME: Utilizing `item_bounds` for this is cycle-prone.
14111411
let predicates = tcx.item_bounds(alias_ty.def_id).instantiate(tcx, alias_ty.args);
14121412

compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,9 +171,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
171171
pub(crate) fn write_resolution(
172172
&self,
173173
hir_id: HirId,
174-
r: Result<(DefKind, DefId), ErrorGuaranteed>,
174+
result: Result<(DefKind, DefId), ErrorGuaranteed>,
175175
) {
176-
self.typeck_results.borrow_mut().type_dependent_defs_mut().insert(hir_id, r);
176+
self.typeck_results.borrow_mut().type_dependent_defs_mut().insert(hir_id, result);
177177
}
178178

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

compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2215,12 +2215,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
22152215
.map(|(ty, _, _)| ty)
22162216
.unwrap_or_else(|guar| Ty::new_error(self.tcx(), guar));
22172217
let ty = LoweredTy::from_raw(self, path_span, ty);
2218-
let result = result.map(|(_, kind, def_id)| (kind, def_id));
22192218

2220-
// Write back the new resolution.
2221-
self.write_resolution(hir_id, result);
2222-
2223-
(result.map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)), ty)
2219+
(result.map_or(Res::Err, |(_, kind, def_id)| Res::Def(kind, def_id)), ty)
22242220
}
22252221
QPath::LangItem(lang_item, span) => {
22262222
let (res, ty) = self.resolve_lang_item_path(lang_item, span, hir_id);

compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,16 @@ 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;
13-
use rustc_hir::def_id::{DefId, LocalDefId};
12+
use rustc_hir::def::DefKind;
13+
use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId};
1414
use rustc_hir::{self as hir, HirId, ItemLocalMap};
1515
use rustc_hir_analysis::hir_ty_lowering::{
1616
HirTyLowerer, InherentAssocCandidate, RegionInferReason,
1717
};
1818
use rustc_infer::infer::{self, RegionVariableOrigin};
1919
use rustc_infer::traits::{DynCompatibilityViolation, Obligation};
20+
use rustc_middle::ty::typeck_results::{HasTypeDependentDefs, TypeDependentDef};
2021
use rustc_middle::ty::{self, Const, Ty, TyCtxt, TypeVisitableExt};
2122
use rustc_session::Session;
2223
use rustc_span::{self, DUMMY_SP, ErrorGuaranteed, Ident, Span, sym};
@@ -418,7 +419,7 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> {
418419
}
419420
}
420421

421-
fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, span: Span) {
422+
fn record_ty(&self, hir_id: HirId, ty: Ty<'tcx>, span: Span) {
422423
// FIXME: normalization and escaping regions
423424
let ty = if !ty.has_escaping_bound_vars() {
424425
// NOTE: These obligations are 100% redundant and are implied by
@@ -438,6 +439,10 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> {
438439
self.write_ty(hir_id, ty)
439440
}
440441

442+
fn record_res(&self, hir_id: HirId, result: TypeDependentDef) {
443+
self.write_resolution(hir_id, result);
444+
}
445+
441446
fn infcx(&self) -> Option<&infer::InferCtxt<'tcx>> {
442447
Some(&self.infcx)
443448
}
@@ -446,7 +451,7 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> {
446451
&self,
447452
decl: &rustc_hir::FnDecl<'tcx>,
448453
_generics: Option<&rustc_hir::Generics<'_>>,
449-
_hir_id: rustc_hir::HirId,
454+
_hir_id: HirId,
450455
_hir_ty: Option<&hir::Ty<'_>>,
451456
) -> (Vec<Ty<'tcx>>, Ty<'tcx>) {
452457
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> {
463468
}
464469
}
465470

471+
impl HasTypeDependentDefs for FnCtxt<'_, '_> {
472+
fn type_dependent_def(&self, id: HirId) -> Option<(DefKind, DefId)> {
473+
self.typeck_results.borrow().type_dependent_def(id)
474+
}
475+
}
476+
466477
/// The `ty` representation of a user-provided type. Depending on the use-site
467478
/// we want to either use the unnormalized or the normalized form of this type.
468479
///

compiler/rustc_middle/src/ty/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ pub mod print;
140140
pub mod relate;
141141
pub mod significant_drop_order;
142142
pub mod trait_def;
143+
pub mod typeck_results;
143144
pub mod util;
144145
pub mod vtable;
145146

@@ -166,7 +167,6 @@ mod rvalue_scopes;
166167
mod structural_impls;
167168
#[allow(hidden_glob_reexports)]
168169
mod sty;
169-
mod typeck_results;
170170
mod visit;
171171

172172
// Data types

compiler/rustc_middle/src/ty/typeck_results.rs

Lines changed: 40 additions & 17 deletions
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
@@ -247,32 +245,22 @@ impl<'tcx> TypeckResults<'tcx> {
247245

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

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

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

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

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

@@ -555,6 +543,33 @@ impl<'tcx> TypeckResults<'tcx> {
555543
}
556544
}
557545

546+
/// Resolved definitions for `<T>::X` associated paths and
547+
/// method calls, including those of overloaded operators.
548+
pub type TypeDependentDefs = ItemLocalMap<TypeDependentDef>;
549+
550+
pub type TypeDependentDef = Result<(DefKind, DefId), ErrorGuaranteed>;
551+
552+
// FIXME(fmease): Yuck!
553+
pub trait HasTypeDependentDefs {
554+
fn type_dependent_def(&self, id: HirId) -> Option<(DefKind, DefId)>;
555+
556+
/// Returns the final resolution of a `QPath`.
557+
fn qpath_res(&self, qpath: &hir::QPath<'_>, id: HirId) -> Res {
558+
match qpath {
559+
hir::QPath::Resolved(_, path) => path.res,
560+
hir::QPath::TypeRelative(..) | hir::QPath::LangItem(..) => self
561+
.type_dependent_def(id)
562+
.map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)),
563+
}
564+
}
565+
}
566+
567+
impl HasTypeDependentDefs for TypeckResults<'_> {
568+
fn type_dependent_def(&self, id: HirId) -> Option<(DefKind, DefId)> {
569+
self.type_dependent_def(id)
570+
}
571+
}
572+
558573
/// Validate that the given HirId (respectively its `local_id` part) can be
559574
/// safely used as a key in the maps of a TypeckResults. For that to be
560575
/// the case, the HirId must have the same `owner` as all the other IDs in
@@ -587,6 +602,10 @@ pub struct LocalTableInContext<'a, V> {
587602
}
588603

589604
impl<'a, V> LocalTableInContext<'a, V> {
605+
pub fn new(hir_owner: OwnerId, data: &'a ItemLocalMap<V>) -> Self {
606+
Self { hir_owner, data }
607+
}
608+
590609
pub fn contains_key(&self, id: HirId) -> bool {
591610
validate_hir_id_for_typeck_results(self.hir_owner, id);
592611
self.data.contains_key(&id.local_id)
@@ -625,6 +644,10 @@ pub struct LocalTableInContextMut<'a, V> {
625644
}
626645

627646
impl<'a, V> LocalTableInContextMut<'a, V> {
647+
pub fn new(hir_owner: OwnerId, data: &'a mut ItemLocalMap<V>) -> Self {
648+
Self { hir_owner, data }
649+
}
650+
628651
pub fn get_mut(&mut self, id: HirId) -> Option<&mut V> {
629652
validate_hir_id_for_typeck_results(self.hir_owner, id);
630653
self.data.get_mut(&id.local_id)

src/tools/tidy/src/ui_tests.rs

Lines changed: 1 addition & 1 deletion
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 = 1619;
20+
const ISSUES_ENTRY_LIMIT: u32 = 1617;
2121

2222
const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[
2323
"rs", // test source files
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
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 _: Identity<T::Project>::Project;
10+
LL + let _: <<T as Trait>::Project as Example>::Project;
11+
|
12+
13+
error: aborting due to 1 previous error
14+
15+
For more information about this error, try `rustc --explain E0223`.

tests/ui/associated-types/non-consecutive-shorthand-projections.lazy.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0223]: ambiguous associated type
2-
--> $DIR/non-consecutive-shorthand-projections.rs:16:12
2+
--> $DIR/non-consecutive-shorthand-projections.rs:14:12
33
|
44
LL | let _: Identity<T::Project>::Project;
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

0 commit comments

Comments
 (0)