Skip to content

Commit

Permalink
[PoC] Track type-dependent defs in ItemCtxts (minimally)
Browse files Browse the repository at this point in the history
  • Loading branch information
fmease committed Jul 3, 2024
1 parent b5d5d9b commit ed8def2
Show file tree
Hide file tree
Showing 11 changed files with 148 additions and 51 deletions.
37 changes: 34 additions & 3 deletions compiler/rustc_hir_analysis/src/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,19 @@ use rustc_data_structures::captures::Captures;
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
use rustc_data_structures::unord::UnordMap;
use rustc_errors::{struct_span_code_err, Applicability, Diag, ErrorGuaranteed, StashKey, E0228};
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::{self, walk_generics, Visitor};
use rustc_hir::{self as hir};
use rustc_hir::{GenericParamKind, Node};
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
use rustc_infer::traits::ObligationCause;
use rustc_middle::hir::nested_filter;
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, Upcast};
use rustc_middle::{bug, span_bug};
Expand All @@ -38,7 +42,7 @@ use rustc_target::spec::abi;
use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits::error_reporting::suggestions::NextTypeParamName;
use rustc_trait_selection::traits::ObligationCtxt;
use std::cell::Cell;
use std::cell::{Cell, RefCell};
use std::iter;
use std::ops::Bound;

Expand Down Expand Up @@ -120,6 +124,7 @@ pub fn provide(providers: &mut Providers) {
pub struct ItemCtxt<'tcx> {
tcx: TyCtxt<'tcx>,
item_def_id: LocalDefId,
type_dependent_defs: RefCell<TypeDependentDefs>,
tainted_by_errors: Cell<Option<ErrorGuaranteed>>,
}

Expand Down Expand Up @@ -342,7 +347,12 @@ fn bad_placeholder<'tcx>(

impl<'tcx> ItemCtxt<'tcx> {
pub 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 fn lower_ty(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<'tcx> {
Expand Down Expand Up @@ -505,6 +515,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
}
Expand Down Expand Up @@ -595,6 +613,19 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {

(input_tys, output_ty)
}

fn upcast(&self) -> &dyn HasTypeDependentDefs {
self
}
}

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.
Expand Down
5 changes: 3 additions & 2 deletions compiler/rustc_hir_analysis/src/collect/type_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,11 +145,12 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
..
}) => {
let body_owner = tcx.hir().enclosing_body_owner(hir_id);
let tables = tcx.typeck(body_owner);
let typeck_results = tcx.typeck(body_owner);
// This may fail in case the method/path does not actually exist.
// As there is no relevant param for `def_id`, we simply return
// `None` here.
let Some(type_dependent_def) = tables.type_dependent_def_id(parent_node_id) else {
let Some(type_dependent_def) = typeck_results.type_dependent_def_id(parent_node_id)
else {
return Ty::new_error_with_message(
tcx,
span,
Expand Down
49 changes: 34 additions & 15 deletions compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ use rustc_infer::traits::ObligationCause;
use rustc_middle::middle::stability::AllowUnstable;
use rustc_middle::mir::interpret::{LitToConstError, 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, ParamEnv, Ty, TyCtxt,
TypeVisitableExt,
Expand Down Expand Up @@ -98,7 +99,7 @@ pub enum RegionInferReason<'a> {
/// 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>;

/// Returns the [`LocalDefId`] of the overarching item whose constituents get lowered.
Expand Down Expand Up @@ -173,6 +174,8 @@ 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);

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>>;

Expand All @@ -192,6 +195,8 @@ pub trait HirTyLowerer<'tcx> {
{
self
}

fn upcast(&self) -> &dyn HasTypeDependentDefs;
}

/// New-typed boolean indicating whether explicit late-bound lifetimes
Expand Down Expand Up @@ -992,6 +997,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
/// [type-relative]: hir::QPath::TypeRelative
/// [#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.
Expand All @@ -1006,13 +1012,33 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
permit_variants: bool,
) -> Result<(Ty<'tcx>, DefKind, DefId), ErrorGuaranteed> {
debug!(%qself_ty, ?assoc_segment.ident);
let result = self.lower_assoc_path_inner(
hir_ref_id,
span,
qself_ty,
qself,
assoc_segment,
permit_variants,
);
self.record_res(hir_ref_id, result.map(|(_, def_kind, def_id)| (def_kind, def_id)));
result
}

fn lower_assoc_path_inner(
&self,
hir_ref_id: HirId,
span: Span,
qself_ty: Ty<'tcx>,
qself: &'tcx hir::Ty<'tcx>,
assoc_segment: &'tcx hir::PathSegment<'tcx>,
permit_variants: bool,
) -> Result<(Ty<'tcx>, DefKind, DefId), ErrorGuaranteed> {
let tcx = self.tcx();

let assoc_ident = assoc_segment.ident;
let qself_res = if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = &qself.kind {
path.res
} else {
Res::Err
let qself_res = match &qself.kind {
hir::TyKind::Path(qpath) => self.upcast().qpath_res(qpath, qself.hir_id),
_ => Res::Err,
};

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

// FIXME(inherent_associated_types, #106719): Support self types other than ADTs.
if let Some((ty, did)) = self.probe_inherent_assoc_ty(
if let Some((ty, def_id)) = self.probe_inherent_assoc_ty(
assoc_ident,
assoc_segment,
adt_def.did(),
qself_ty,
hir_ref_id,
span,
)? {
return Ok((ty, DefKind::AssocTy, did));
return Ok((ty, DefKind::AssocTy, def_id));
}
}

Expand Down Expand Up @@ -1085,14 +1111,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
assoc_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<T::Assoc>::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<T>::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);

Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,9 +170,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))]
Expand Down
6 changes: 1 addition & 5 deletions compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1984,12 +1984,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);
Expand Down
19 changes: 17 additions & 2 deletions compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,14 @@ use crate::coercion::DynamicCoerceMany;
use crate::fallback::DivergingFallbackBehavior;
use crate::fn_ctxt::checks::DivergingBlockBehavior;
use crate::{CoroutineTypes, Diverges, EnclosingBreakables, TypeckRootCtxt};
use hir::def_id::CRATE_DEF_ID;
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
use rustc_hir_analysis::hir_ty_lowering::{HirTyLowerer, RegionInferReason};
use rustc_infer::infer;
use rustc_infer::infer::error_reporting::sub_relations::SubRelations;
use rustc_infer::infer::error_reporting::TypeErrCtxt;
use rustc_middle::ty::typeck_results::{HasTypeDependentDefs, TypeDependentDef};
use rustc_middle::ty::{self, Const, Ty, TyCtxt, TypeVisitableExt};
use rustc_session::Session;
use rustc_span::symbol::Ident;
Expand Down Expand Up @@ -334,6 +335,10 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> {
self.write_ty(hir_id, ty)
}

fn record_res(&self, hir_id: hir::HirId, result: TypeDependentDef) {
self.write_resolution(hir_id, result);
}

fn infcx(&self) -> Option<&infer::InferCtxt<'tcx>> {
Some(&self.infcx)
}
Expand All @@ -357,6 +362,16 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> {
};
(input_tys, output_ty)
}

fn upcast(&self) -> &dyn HasTypeDependentDefs {
self
}
}

impl HasTypeDependentDefs for FnCtxt<'_, '_> {
fn type_dependent_def(&self, id: hir::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
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ pub mod pattern;
pub mod print;
pub mod relate;
pub mod trait_def;
pub mod typeck_results;
pub mod util;
pub mod visit;
pub mod vtable;
Expand All @@ -163,7 +164,6 @@ mod rvalue_scopes;
mod structural_impls;
#[allow(hidden_glob_reexports)]
mod sty;
mod typeck_results;

// Data types

Expand Down
Loading

0 comments on commit ed8def2

Please sign in to comment.