Skip to content

Commit e8e02d5

Browse files
Merge pull request #20974 from ChayimFriedman2/ns4
fix: Rewrite method resolution to follow rustc more closely
2 parents c9e3934 + 80a943b commit e8e02d5

File tree

90 files changed

+7350
-4163
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

90 files changed

+7350
-4163
lines changed

crates/base-db/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,7 @@ pub trait RootQueryDb: SourceDatabase + salsa::Database {
273273
fn transitive_rev_deps(&self, of: Crate) -> FxHashSet<Crate>;
274274
}
275275

276-
pub fn transitive_deps(db: &dyn SourceDatabase, crate_id: Crate) -> FxHashSet<Crate> {
276+
fn transitive_deps(db: &dyn SourceDatabase, crate_id: Crate) -> FxHashSet<Crate> {
277277
// There is a bit of duplication here and in `CrateGraphBuilder` in the same method, but it's not terrible
278278
// and removing that is a bit difficult.
279279
let mut worklist = vec![crate_id];

crates/hir-def/src/resolver.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -708,6 +708,20 @@ impl<'db> Resolver<'db> {
708708
self.item_scope_().0
709709
}
710710

711+
#[inline]
712+
pub fn top_level_def_map(&self) -> &'db DefMap {
713+
self.module_scope.def_map
714+
}
715+
716+
#[inline]
717+
pub fn is_visible(&self, db: &dyn DefDatabase, visibility: Visibility) -> bool {
718+
visibility.is_visible_from_def_map(
719+
db,
720+
self.module_scope.def_map,
721+
self.module_scope.module_id,
722+
)
723+
}
724+
711725
pub fn generic_def(&self) -> Option<GenericDefId> {
712726
self.scopes().find_map(|scope| match scope {
713727
Scope::GenericParams { def, .. } => Some(*def),

crates/hir-ty/src/autoderef.rs

Lines changed: 150 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@ use triomphe::Arc;
1313
use crate::{
1414
TraitEnvironment,
1515
db::HirDatabase,
16-
infer::unify::InferenceTable,
16+
infer::InferenceContext,
1717
next_solver::{
18-
Canonical, TraitRef, Ty, TyKind,
18+
Canonical, DbInterner, ParamEnv, TraitRef, Ty, TyKind, TypingMode,
1919
infer::{
20-
InferOk,
20+
DbInternerInferExt, InferCtxt,
2121
traits::{Obligation, ObligationCause, PredicateObligations},
2222
},
2323
obligation_ctxt::ObligationCtxt,
@@ -38,14 +38,15 @@ pub fn autoderef<'db>(
3838
env: Arc<TraitEnvironment<'db>>,
3939
ty: Canonical<'db, Ty<'db>>,
4040
) -> impl Iterator<Item = Ty<'db>> + use<'db> {
41-
let mut table = InferenceTable::new(db, env, None);
42-
let ty = table.instantiate_canonical(ty);
43-
let mut autoderef = Autoderef::new_no_tracking(&mut table, ty);
41+
let interner = DbInterner::new_with(db, Some(env.krate), env.block);
42+
let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis);
43+
let (ty, _) = infcx.instantiate_canonical(&ty);
44+
let autoderef = Autoderef::new(&infcx, &env, ty);
4445
let mut v = Vec::new();
45-
while let Some((ty, _steps)) = autoderef.next() {
46+
for (ty, _steps) in autoderef {
4647
// `ty` may contain unresolved inference variables. Since there's no chance they would be
4748
// resolved, just replace with fallback type.
48-
let resolved = autoderef.table.resolve_completely(ty);
49+
let resolved = infcx.resolve_vars_if_possible(ty).replace_infer_with_error(interner);
4950

5051
// If the deref chain contains a cycle (e.g. `A` derefs to `B` and `B` derefs to `A`), we
5152
// would revisit some already visited types. Stop here to avoid duplication.
@@ -105,13 +106,48 @@ struct AutoderefTraits {
105106
trait_target: TypeAliasId,
106107
}
107108

109+
// We use a trait here and a generic implementation unfortunately, because sometimes (specifically
110+
// in place_op.rs), you need to have mutable access to the `InferenceContext` while the `Autoderef`
111+
// borrows it.
112+
pub(crate) trait AutoderefCtx<'db> {
113+
fn infcx(&self) -> &InferCtxt<'db>;
114+
fn env(&self) -> &TraitEnvironment<'db>;
115+
}
116+
117+
pub(crate) struct DefaultAutoderefCtx<'a, 'db> {
118+
infcx: &'a InferCtxt<'db>,
119+
env: &'a TraitEnvironment<'db>,
120+
}
121+
impl<'db> AutoderefCtx<'db> for DefaultAutoderefCtx<'_, 'db> {
122+
#[inline]
123+
fn infcx(&self) -> &InferCtxt<'db> {
124+
self.infcx
125+
}
126+
#[inline]
127+
fn env(&self) -> &TraitEnvironment<'db> {
128+
self.env
129+
}
130+
}
131+
132+
pub(crate) struct InferenceContextAutoderefCtx<'a, 'b, 'db>(&'a mut InferenceContext<'b, 'db>);
133+
impl<'db> AutoderefCtx<'db> for InferenceContextAutoderefCtx<'_, '_, 'db> {
134+
#[inline]
135+
fn infcx(&self) -> &InferCtxt<'db> {
136+
&self.0.table.infer_ctxt
137+
}
138+
#[inline]
139+
fn env(&self) -> &TraitEnvironment<'db> {
140+
&self.0.table.trait_env
141+
}
142+
}
143+
108144
/// Recursively dereference a type, considering both built-in
109145
/// dereferences (`*`) and the `Deref` trait.
110146
/// Although called `Autoderef` it can be configured to use the
111147
/// `Receiver` trait instead of the `Deref` trait.
112-
pub(crate) struct Autoderef<'a, 'db, Steps = Vec<(Ty<'db>, AutoderefKind)>> {
148+
pub(crate) struct GeneralAutoderef<'db, Ctx, Steps = Vec<(Ty<'db>, AutoderefKind)>> {
113149
// Meta infos:
114-
pub(crate) table: &'a mut InferenceTable<'db>,
150+
ctx: Ctx,
115151
traits: Option<AutoderefTraits>,
116152

117153
// Current state:
@@ -122,7 +158,16 @@ pub(crate) struct Autoderef<'a, 'db, Steps = Vec<(Ty<'db>, AutoderefKind)>> {
122158
use_receiver_trait: bool,
123159
}
124160

125-
impl<'a, 'db, Steps: TrackAutoderefSteps<'db>> Iterator for Autoderef<'a, 'db, Steps> {
161+
pub(crate) type Autoderef<'a, 'db, Steps = Vec<(Ty<'db>, AutoderefKind)>> =
162+
GeneralAutoderef<'db, DefaultAutoderefCtx<'a, 'db>, Steps>;
163+
pub(crate) type InferenceContextAutoderef<'a, 'b, 'db, Steps = Vec<(Ty<'db>, AutoderefKind)>> =
164+
GeneralAutoderef<'db, InferenceContextAutoderefCtx<'a, 'b, 'db>, Steps>;
165+
166+
impl<'db, Ctx, Steps> Iterator for GeneralAutoderef<'db, Ctx, Steps>
167+
where
168+
Ctx: AutoderefCtx<'db>,
169+
Steps: TrackAutoderefSteps<'db>,
170+
{
126171
type Item = (Ty<'db>, usize);
127172

128173
fn next(&mut self) -> Option<Self::Item> {
@@ -148,26 +193,26 @@ impl<'a, 'db, Steps: TrackAutoderefSteps<'db>> Iterator for Autoderef<'a, 'db, S
148193
// be better to skip this clause and use the Overloaded case only, since &T
149194
// and &mut T implement Receiver. But built-in derefs apply equally to Receiver
150195
// and Deref, and this has benefits for const and the emitted MIR.
151-
let (kind, new_ty) = if let Some(ty) =
152-
self.state.cur_ty.builtin_deref(self.table.db, self.include_raw_pointers)
153-
{
154-
debug_assert_eq!(ty, self.table.infer_ctxt.resolve_vars_if_possible(ty));
155-
// NOTE: we may still need to normalize the built-in deref in case
156-
// we have some type like `&<Ty as Trait>::Assoc`, since users of
157-
// autoderef expect this type to have been structurally normalized.
158-
if let TyKind::Alias(..) = ty.kind() {
159-
let (normalized_ty, obligations) = structurally_normalize_ty(self.table, ty)?;
160-
self.state.obligations.extend(obligations);
161-
(AutoderefKind::Builtin, normalized_ty)
196+
let (kind, new_ty) =
197+
if let Some(ty) = self.state.cur_ty.builtin_deref(self.include_raw_pointers) {
198+
debug_assert_eq!(ty, self.infcx().resolve_vars_if_possible(ty));
199+
// NOTE: we may still need to normalize the built-in deref in case
200+
// we have some type like `&<Ty as Trait>::Assoc`, since users of
201+
// autoderef expect this type to have been structurally normalized.
202+
if let TyKind::Alias(..) = ty.kind() {
203+
let (normalized_ty, obligations) =
204+
structurally_normalize_ty(self.infcx(), self.env().env, ty)?;
205+
self.state.obligations.extend(obligations);
206+
(AutoderefKind::Builtin, normalized_ty)
207+
} else {
208+
(AutoderefKind::Builtin, ty)
209+
}
210+
} else if let Some(ty) = self.overloaded_deref_ty(self.state.cur_ty) {
211+
// The overloaded deref check already normalizes the pointee type.
212+
(AutoderefKind::Overloaded, ty)
162213
} else {
163-
(AutoderefKind::Builtin, ty)
164-
}
165-
} else if let Some(ty) = self.overloaded_deref_ty(self.state.cur_ty) {
166-
// The overloaded deref check already normalizes the pointee type.
167-
(AutoderefKind::Overloaded, ty)
168-
} else {
169-
return None;
170-
};
214+
return None;
215+
};
171216

172217
self.state.steps.push(self.state.cur_ty, kind);
173218
debug!(
@@ -183,34 +228,84 @@ impl<'a, 'db, Steps: TrackAutoderefSteps<'db>> Iterator for Autoderef<'a, 'db, S
183228
}
184229

185230
impl<'a, 'db> Autoderef<'a, 'db> {
186-
pub(crate) fn new(table: &'a mut InferenceTable<'db>, base_ty: Ty<'db>) -> Self {
187-
Self::new_impl(table, base_ty)
231+
#[inline]
232+
pub(crate) fn new_with_tracking(
233+
infcx: &'a InferCtxt<'db>,
234+
env: &'a TraitEnvironment<'db>,
235+
base_ty: Ty<'db>,
236+
) -> Self {
237+
Self::new_impl(DefaultAutoderefCtx { infcx, env }, base_ty)
238+
}
239+
}
240+
241+
impl<'a, 'b, 'db> InferenceContextAutoderef<'a, 'b, 'db> {
242+
#[inline]
243+
pub(crate) fn new_from_inference_context(
244+
ctx: &'a mut InferenceContext<'b, 'db>,
245+
base_ty: Ty<'db>,
246+
) -> Self {
247+
Self::new_impl(InferenceContextAutoderefCtx(ctx), base_ty)
248+
}
249+
250+
#[inline]
251+
pub(crate) fn ctx(&mut self) -> &mut InferenceContext<'b, 'db> {
252+
self.ctx.0
188253
}
189254
}
190255

191256
impl<'a, 'db> Autoderef<'a, 'db, usize> {
192-
pub(crate) fn new_no_tracking(table: &'a mut InferenceTable<'db>, base_ty: Ty<'db>) -> Self {
193-
Self::new_impl(table, base_ty)
257+
#[inline]
258+
pub(crate) fn new(
259+
infcx: &'a InferCtxt<'db>,
260+
env: &'a TraitEnvironment<'db>,
261+
base_ty: Ty<'db>,
262+
) -> Self {
263+
Self::new_impl(DefaultAutoderefCtx { infcx, env }, base_ty)
194264
}
195265
}
196266

197-
impl<'a, 'db, Steps: TrackAutoderefSteps<'db>> Autoderef<'a, 'db, Steps> {
198-
fn new_impl(table: &'a mut InferenceTable<'db>, base_ty: Ty<'db>) -> Self {
199-
Autoderef {
267+
impl<'db, Ctx, Steps> GeneralAutoderef<'db, Ctx, Steps>
268+
where
269+
Ctx: AutoderefCtx<'db>,
270+
Steps: TrackAutoderefSteps<'db>,
271+
{
272+
#[inline]
273+
fn new_impl(ctx: Ctx, base_ty: Ty<'db>) -> Self {
274+
GeneralAutoderef {
200275
state: AutoderefSnapshot {
201276
steps: Steps::default(),
202-
cur_ty: table.infer_ctxt.resolve_vars_if_possible(base_ty),
277+
cur_ty: ctx.infcx().resolve_vars_if_possible(base_ty),
203278
obligations: PredicateObligations::new(),
204279
at_start: true,
205280
reached_recursion_limit: false,
206281
},
207-
table,
282+
ctx,
208283
traits: None,
209284
include_raw_pointers: false,
210285
use_receiver_trait: false,
211286
}
212287
}
213288

289+
#[inline]
290+
fn infcx(&self) -> &InferCtxt<'db> {
291+
self.ctx.infcx()
292+
}
293+
294+
#[inline]
295+
fn env(&self) -> &TraitEnvironment<'db> {
296+
self.ctx.env()
297+
}
298+
299+
#[inline]
300+
fn interner(&self) -> DbInterner<'db> {
301+
self.infcx().interner
302+
}
303+
304+
#[inline]
305+
fn db(&self) -> &'db dyn HirDatabase {
306+
self.interner().db
307+
}
308+
214309
fn autoderef_traits(&mut self) -> Option<AutoderefTraits> {
215310
match &mut self.traits {
216311
Some(it) => Some(*it),
@@ -219,25 +314,23 @@ impl<'a, 'db, Steps: TrackAutoderefSteps<'db>> Autoderef<'a, 'db, Steps> {
219314
(|| {
220315
Some(AutoderefTraits {
221316
trait_: LangItem::Receiver
222-
.resolve_trait(self.table.db, self.table.trait_env.krate)?,
317+
.resolve_trait(self.db(), self.env().krate)?,
223318
trait_target: LangItem::ReceiverTarget
224-
.resolve_type_alias(self.table.db, self.table.trait_env.krate)?,
319+
.resolve_type_alias(self.db(), self.env().krate)?,
225320
})
226321
})()
227322
.or_else(|| {
228323
Some(AutoderefTraits {
229-
trait_: LangItem::Deref
230-
.resolve_trait(self.table.db, self.table.trait_env.krate)?,
324+
trait_: LangItem::Deref.resolve_trait(self.db(), self.env().krate)?,
231325
trait_target: LangItem::DerefTarget
232-
.resolve_type_alias(self.table.db, self.table.trait_env.krate)?,
326+
.resolve_type_alias(self.db(), self.env().krate)?,
233327
})
234328
})?
235329
} else {
236330
AutoderefTraits {
237-
trait_: LangItem::Deref
238-
.resolve_trait(self.table.db, self.table.trait_env.krate)?,
331+
trait_: LangItem::Deref.resolve_trait(self.db(), self.env().krate)?,
239332
trait_target: LangItem::DerefTarget
240-
.resolve_type_alias(self.table.db, self.table.trait_env.krate)?,
333+
.resolve_type_alias(self.db(), self.env().krate)?,
241334
}
242335
};
243336
Some(*self.traits.insert(traits))
@@ -247,31 +340,32 @@ impl<'a, 'db, Steps: TrackAutoderefSteps<'db>> Autoderef<'a, 'db, Steps> {
247340

248341
fn overloaded_deref_ty(&mut self, ty: Ty<'db>) -> Option<Ty<'db>> {
249342
debug!("overloaded_deref_ty({:?})", ty);
250-
let interner = self.table.interner();
343+
let interner = self.interner();
251344

252345
// <ty as Deref>, or whatever the equivalent trait is that we've been asked to walk.
253346
let AutoderefTraits { trait_, trait_target } = self.autoderef_traits()?;
254347

255348
let trait_ref = TraitRef::new(interner, trait_.into(), [ty]);
256349
let obligation =
257-
Obligation::new(interner, ObligationCause::new(), self.table.trait_env.env, trait_ref);
350+
Obligation::new(interner, ObligationCause::new(), self.env().env, trait_ref);
258351
// We detect whether the self type implements `Deref` before trying to
259352
// structurally normalize. We use `predicate_may_hold_opaque_types_jank`
260353
// to support not-yet-defined opaque types. It will succeed for `impl Deref`
261354
// but fail for `impl OtherTrait`.
262-
if !self.table.infer_ctxt.predicate_may_hold_opaque_types_jank(&obligation) {
355+
if !self.infcx().predicate_may_hold_opaque_types_jank(&obligation) {
263356
debug!("overloaded_deref_ty: cannot match obligation");
264357
return None;
265358
}
266359

267360
let (normalized_ty, obligations) = structurally_normalize_ty(
268-
self.table,
361+
self.infcx(),
362+
self.env().env,
269363
Ty::new_projection(interner, trait_target.into(), [ty]),
270364
)?;
271365
debug!("overloaded_deref_ty({:?}) = ({:?}, {:?})", ty, normalized_ty, obligations);
272366
self.state.obligations.extend(obligations);
273367

274-
Some(self.table.infer_ctxt.resolve_vars_if_possible(normalized_ty))
368+
Some(self.infcx().resolve_vars_if_possible(normalized_ty))
275369
}
276370

277371
/// Returns the final type we ended up with, which may be an unresolved
@@ -292,7 +386,6 @@ impl<'a, 'db, Steps: TrackAutoderefSteps<'db>> Autoderef<'a, 'db, Steps> {
292386
&self.state.steps
293387
}
294388

295-
#[expect(dead_code)]
296389
pub(crate) fn reached_recursion_limit(&self) -> bool {
297390
self.state.reached_recursion_limit
298391
}
@@ -316,12 +409,12 @@ impl<'a, 'db, Steps: TrackAutoderefSteps<'db>> Autoderef<'a, 'db, Steps> {
316409
}
317410

318411
fn structurally_normalize_ty<'db>(
319-
table: &InferenceTable<'db>,
412+
infcx: &InferCtxt<'db>,
413+
param_env: ParamEnv<'db>,
320414
ty: Ty<'db>,
321415
) -> Option<(Ty<'db>, PredicateObligations<'db>)> {
322-
let mut ocx = ObligationCtxt::new(&table.infer_ctxt);
323-
let Ok(normalized_ty) =
324-
ocx.structurally_normalize_ty(&ObligationCause::misc(), table.trait_env.env, ty)
416+
let mut ocx = ObligationCtxt::new(infcx);
417+
let Ok(normalized_ty) = ocx.structurally_normalize_ty(&ObligationCause::misc(), param_env, ty)
325418
else {
326419
// We shouldn't have errors here in the old solver, except for
327420
// evaluate/fulfill mismatches, but that's not a reason for an ICE.
@@ -334,17 +427,3 @@ fn structurally_normalize_ty<'db>(
334427

335428
Some((normalized_ty, ocx.into_pending_obligations()))
336429
}
337-
338-
pub(crate) fn overloaded_deref_ty<'db>(
339-
table: &InferenceTable<'db>,
340-
ty: Ty<'db>,
341-
) -> Option<InferOk<'db, Ty<'db>>> {
342-
let interner = table.interner();
343-
344-
let trait_target = LangItem::DerefTarget.resolve_type_alias(table.db, table.trait_env.krate)?;
345-
346-
let (normalized_ty, obligations) =
347-
structurally_normalize_ty(table, Ty::new_projection(interner, trait_target.into(), [ty]))?;
348-
349-
Some(InferOk { value: normalized_ty, obligations })
350-
}

0 commit comments

Comments
 (0)