Skip to content

Commit 616fff2

Browse files
committed
[PoC] Track type-dependent defs in ItemCtxts (minimally)
1 parent cc471ea commit 616fff2

10 files changed

Lines changed: 116 additions & 46 deletions

File tree

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

@@ -33,6 +33,10 @@ use rustc_hir::{self as hir, GenericParamKind, HirId, Node, PreciseCapturingArgK
3333
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
3434
use rustc_infer::traits::{DynCompatibilityViolation, ObligationCause};
3535
use rustc_middle::query::Providers;
36+
use rustc_middle::ty::typeck_results::{
37+
HasTypeDependentDefs, LocalTableInContext, LocalTableInContextMut, TypeDependentDef,
38+
TypeDependentDefs,
39+
};
3640
use rustc_middle::ty::util::{Discr, IntTypeExt};
3741
use rustc_middle::ty::{
3842
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
}
@@ -568,6 +586,15 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
568586
}
569587
}
570588

589+
impl HasTypeDependentDefs for ItemCtxt<'_> {
590+
fn type_dependent_def(&self, id: hir::HirId) -> Option<(DefKind, DefId)> {
591+
LocalTableInContext::new(self.hir_id().owner, &self.type_dependent_defs.borrow())
592+
.get(id)
593+
.copied()
594+
.and_then(|result| result.ok())
595+
}
596+
}
597+
571598
/// Synthesize a new lifetime name that doesn't clash with any of the lifetimes already present.
572599
fn get_new_lifetime_name<'tcx>(
573600
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
@@ -37,6 +37,7 @@ use rustc_macros::{TypeFoldable, TypeVisitable};
3737
use rustc_middle::middle::stability::AllowUnstable;
3838
use rustc_middle::mir::interpret::LitToConstInput;
3939
use rustc_middle::ty::print::PrintPolyTraitRefExt as _;
40+
use rustc_middle::ty::typeck_results::{HasTypeDependentDefs, TypeDependentDef};
4041
use rustc_middle::ty::{
4142
self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, Ty, TyCtxt, TypeVisitableExt,
4243
TypingMode, Upcast, fold_regions,
@@ -123,7 +124,7 @@ pub struct InherentAssocCandidate {
123124
/// the [`rustc_middle::ty`] representation.
124125
///
125126
/// This trait used to be called `AstConv`.
126-
pub trait HirTyLowerer<'tcx> {
127+
pub trait HirTyLowerer<'tcx>: HasTypeDependentDefs {
127128
fn tcx(&self) -> TyCtxt<'tcx>;
128129

129130
fn dcx(&self) -> DiagCtxtHandle<'_>;
@@ -214,6 +215,9 @@ pub trait HirTyLowerer<'tcx> {
214215
/// Record the lowered type of a HIR node in this context.
215216
fn record_ty(&self, hir_id: HirId, ty: Ty<'tcx>, span: Span);
216217

218+
/// Record the resolution of a HIR node corresponding to a type-dependent definition in this context.
219+
fn record_res(&self, hir_id: hir::HirId, result: TypeDependentDef);
220+
217221
/// The inference context of the lowering context if applicable.
218222
fn infcx(&self) -> Option<&InferCtxt<'tcx>>;
219223

@@ -1233,6 +1237,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
12331237
///
12341238
/// [#22519]: https://github.com/rust-lang/rust/issues/22519
12351239
/// [iat]: https://github.com/rust-lang/rust/issues/8995#issuecomment-1569208403
1240+
// FIXME(fmease): Update docs
12361241
//
12371242
// NOTE: When this function starts resolving `Trait::AssocTy` successfully
12381243
// it should also start reporting the `BARE_TRAIT_OBJECTS` lint.
@@ -1256,9 +1261,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
12561261
LowerTypeRelativePathMode::Type(permit_variants),
12571262
)? {
12581263
TypeRelativePath::AssocItem(def_id, args) => {
1264+
let kind = tcx.def_kind(def_id);
1265+
self.record_res(qpath_hir_id, Ok((kind, def_id)));
12591266
let alias_ty = ty::AliasTy::new_from_args(tcx, def_id, args);
12601267
let ty = Ty::new_alias(tcx, alias_ty.kind(tcx), alias_ty);
1261-
Ok((ty, tcx.def_kind(def_id), def_id))
1268+
Ok((ty, kind, def_id))
12621269
}
12631270
TypeRelativePath::Variant { adt, variant_did } => {
12641271
Ok((adt, DefKind::Variant, variant_did))
@@ -1420,7 +1427,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
14201427
let tcx = self.tcx();
14211428

14221429
let self_ty_res = match hir_self_ty.kind {
1423-
hir::TyKind::Path(hir::QPath::Resolved(_, path)) => path.res,
1430+
hir::TyKind::Path(qpath) => self.qpath_res(&qpath, hir_self_ty.hir_id),
14241431
_ => Res::Err,
14251432
};
14261433

@@ -1454,14 +1461,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
14541461
segment.ident,
14551462
span,
14561463
)?,
1457-
// FIXME(fmease):
1458-
// Require the pre-lowered projectee (the HIR QSelf) to have `DefKind::AssocTy`. Rephrased,
1459-
// `T::Assoc::Assoc` typeck'ing shouldn't imply `Identity<T::Assoc>::Assoc` typeck'ing where
1460-
// `Identity` is an eager (i.e., non-lazy) type alias. We should do this
1461-
// * for consistency with lazy type aliases (`ty::Weak`)
1462-
// * for consistency with the fact that `T::Assoc` typeck'ing doesn't imply `Identity<T>::Assoc`
1463-
// typeck'ing
1464-
(ty::Alias(ty::Projection, alias_ty), _ /* Res::Def(DefKind::AssocTy, _) */) => {
1464+
(ty::Alias(ty::Projection, alias_ty), Res::Def(DefKind::AssocTy, _)) => {
14651465
// FIXME: Utilizing `item_bounds` for this is cycle-prone.
14661466
let predicates = tcx.item_bounds(alias_ty.def_id).instantiate(tcx, alias_ty.args);
14671467

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
@@ -1311,12 +1311,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
13111311
.map(|(ty, _, _)| ty)
13121312
.unwrap_or_else(|guar| Ty::new_error(self.tcx(), guar));
13131313
let ty = LoweredTy::from_raw(self, path_span, ty);
1314-
let result = result.map(|(_, kind, def_id)| (kind, def_id));
13151314

1316-
// Write back the new resolution.
1317-
self.write_resolution(hir_id, result);
1318-
1319-
(result.map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)), ty)
1315+
(result.map_or(Res::Err, |(_, kind, def_id)| Res::Def(kind, def_id)), ty)
13201316
}
13211317
}
13221318
}

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
@@ -138,6 +138,7 @@ pub mod print;
138138
pub mod relate;
139139
pub mod significant_drop_order;
140140
pub mod trait_def;
141+
pub mod typeck_results;
141142
pub mod util;
142143
pub mod vtable;
143144

@@ -162,7 +163,6 @@ mod region;
162163
mod structural_impls;
163164
#[allow(hidden_glob_reexports)]
164165
mod sty;
165-
mod typeck_results;
166166
mod visit;
167167

168168
// 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
@@ -258,32 +256,22 @@ impl<'tcx> TypeckResults<'tcx> {
258256

259257
/// Returns the final resolution of a `QPath` in an `Expr` or `Pat` node.
260258
pub fn qpath_res(&self, qpath: &hir::QPath<'_>, id: HirId) -> Res {
261-
match *qpath {
262-
hir::QPath::Resolved(_, path) => path.res,
263-
hir::QPath::TypeRelative(..) => self
264-
.type_dependent_def(id)
265-
.map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)),
266-
}
259+
HasTypeDependentDefs::qpath_res(self, qpath, id)
267260
}
268261

269-
pub fn type_dependent_defs(
270-
&self,
271-
) -> LocalTableInContext<'_, Result<(DefKind, DefId), ErrorGuaranteed>> {
262+
pub fn type_dependent_defs(&self) -> LocalTableInContext<'_, TypeDependentDef> {
272263
LocalTableInContext { hir_owner: self.hir_owner, data: &self.type_dependent_defs }
273264
}
274265

275266
pub fn type_dependent_def(&self, id: HirId) -> Option<(DefKind, DefId)> {
276-
validate_hir_id_for_typeck_results(self.hir_owner, id);
277-
self.type_dependent_defs.get(&id.local_id).cloned().and_then(|r| r.ok())
267+
self.type_dependent_defs().get(id).copied().and_then(|result| result.ok())
278268
}
279269

280270
pub fn type_dependent_def_id(&self, id: HirId) -> Option<DefId> {
281271
self.type_dependent_def(id).map(|(_, def_id)| def_id)
282272
}
283273

284-
pub fn type_dependent_defs_mut(
285-
&mut self,
286-
) -> LocalTableInContextMut<'_, Result<(DefKind, DefId), ErrorGuaranteed>> {
274+
pub fn type_dependent_defs_mut(&mut self) -> LocalTableInContextMut<'_, TypeDependentDef> {
287275
LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.type_dependent_defs }
288276
}
289277

@@ -569,6 +557,33 @@ impl<'tcx> TypeckResults<'tcx> {
569557
}
570558
}
571559

560+
/// Resolved definitions for `<T>::X` associated paths and
561+
/// method calls, including those of overloaded operators.
562+
pub type TypeDependentDefs = ItemLocalMap<TypeDependentDef>;
563+
564+
pub type TypeDependentDef = Result<(DefKind, DefId), ErrorGuaranteed>;
565+
566+
// FIXME(fmease): Yuck!
567+
pub trait HasTypeDependentDefs {
568+
fn type_dependent_def(&self, id: HirId) -> Option<(DefKind, DefId)>;
569+
570+
/// Returns the final resolution of a `QPath`.
571+
fn qpath_res(&self, qpath: &hir::QPath<'_>, id: HirId) -> Res {
572+
match qpath {
573+
hir::QPath::Resolved(_, path) => path.res,
574+
hir::QPath::TypeRelative(..) => self
575+
.type_dependent_def(id)
576+
.map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)),
577+
}
578+
}
579+
}
580+
581+
impl HasTypeDependentDefs for TypeckResults<'_> {
582+
fn type_dependent_def(&self, id: HirId) -> Option<(DefKind, DefId)> {
583+
self.type_dependent_def(id)
584+
}
585+
}
586+
572587
/// Validate that the given HirId (respectively its `local_id` part) can be
573588
/// safely used as a key in the maps of a TypeckResults. For that to be
574589
/// the case, the HirId must have the same `owner` as all the other IDs in
@@ -601,6 +616,10 @@ pub struct LocalTableInContext<'a, V> {
601616
}
602617

603618
impl<'a, V> LocalTableInContext<'a, V> {
619+
pub fn new(hir_owner: OwnerId, data: &'a ItemLocalMap<V>) -> Self {
620+
Self { hir_owner, data }
621+
}
622+
604623
pub fn contains_key(&self, id: HirId) -> bool {
605624
validate_hir_id_for_typeck_results(self.hir_owner, id);
606625
self.data.contains_key(&id.local_id)
@@ -639,6 +658,10 @@ pub struct LocalTableInContextMut<'a, V> {
639658
}
640659

641660
impl<'a, V> LocalTableInContextMut<'a, V> {
661+
pub fn new(hir_owner: OwnerId, data: &'a mut ItemLocalMap<V>) -> Self {
662+
Self { hir_owner, data }
663+
}
664+
642665
pub fn get_mut(&mut self, id: HirId) -> Option<&mut V> {
643666
validate_hir_id_for_typeck_results(self.hir_owner, id);
644667
self.data.get_mut(&id.local_id)
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
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

tests/ui/associated-types/non-consecutive-shorthand-projections.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
// Of course, under #22519 (arbitrary shorthand projections), this should obviously typeck.
33
// For reference, `T::Alias` typeck'ing does *not* imply `Identity<T>::Alias` typeck'ing.
44
//@ revisions: eager lazy
5-
//@[eager] check-pass
65
#![cfg_attr(lazy, feature(lazy_type_alias), allow(incomplete_features))]
76

87
type Identity<T> = T;
@@ -12,8 +11,7 @@ trait Trait {
1211
}
1312

1413
fn scope<T: Trait>() {
15-
// FIXME(fmease): Reject this under [eager], too!
16-
let _: Identity<T::Project>::Project; //[lazy]~ ERROR ambiguous associated type
14+
let _: Identity<T::Project>::Project; //~ ERROR ambiguous associated type
1715
}
1816

1917
fn main() {}

0 commit comments

Comments
 (0)