Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 0c7e786

Browse files
committedMay 15, 2025·
half work
1 parent 350d8a8 commit 0c7e786

File tree

5 files changed

+380
-171
lines changed

5 files changed

+380
-171
lines changed
 

‎crates/hir-ty/src/display.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -684,7 +684,8 @@ impl HirDisplay for ProjectionTy {
684684
),
685685
&assoc_type
686686
.bounds
687-
.skip_binders()
687+
.clone()
688+
.substitute(Interner, &self.substitution)
688689
.iter()
689690
.map(|bound| {
690691
// We ignore `Self` anyway when formatting, so it's fine put an error type in it.

‎crates/hir-ty/src/lower.rs

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ use crate::{
5252
FnSubst, ImplTrait, ImplTraitId, ImplTraits, Interner, Lifetime, LifetimeData,
5353
LifetimeOutlives, PlaceholderIndex, PolyFnSig, ProgramClause, ProjectionTy,
5454
QuantifiedWhereClause, QuantifiedWhereClauses, Substitution, TraitEnvironment, TraitRef,
55-
TraitRefExt, Ty, TyBuilder, TyKind, VariableKind, VariableKinds, WhereClause, all_super_traits,
55+
TraitRefExt, Ty, TyBuilder, TyKind, VariableKinds, WhereClause, all_super_traits,
5656
chalk_db::generic_predicate_to_inline_bound,
5757
consteval::{intern_const_ref, path_to_const, unknown_const, unknown_const_as_generic},
5858
db::HirDatabase,
@@ -519,15 +519,7 @@ impl<'a> TyLoweringContext<'a> {
519519

520520
let assoc_type_binders = VariableKinds::from_iter(
521521
Interner,
522-
method_generics.iter_id().map(|param_id| match param_id {
523-
GenericParamId::TypeParamId(_) => {
524-
VariableKind::Ty(chalk_ir::TyVariableKind::General)
525-
}
526-
GenericParamId::ConstParamId(param_id) => {
527-
VariableKind::Const(self.db.const_param_ty(param_id))
528-
}
529-
GenericParamId::LifetimeParamId(_) => VariableKind::Lifetime,
530-
}),
522+
variable_kinds_from_generics(self.db, method_generics.iter_id()),
531523
);
532524

533525
let returned_subst = self.subst_for_generics();

‎crates/hir-ty/src/rpitit.rs

Lines changed: 322 additions & 151 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,27 @@ use std::{iter, sync::Arc};
55
use base_db::impl_intern_key_ref;
66
use chalk_ir::{
77
BoundVar, DebruijnIndex,
8+
cast::Cast,
89
fold::{TypeFoldable, TypeFolder, TypeSuperFoldable},
910
};
1011
use chalk_solve::rust_ir::AssociatedTyValueBound;
1112
use hir_def::{
12-
AssocItemId, FunctionId, GenericDefId, ImplId, TraitId,
13+
AssocItemId, FunctionId, GenericDefId, GenericParamId, ImplId, TraitId,
1314
hir::generics::{GenericParams, TypeOrConstParamData},
15+
resolver::HasResolver,
1416
};
1517
use rustc_hash::FxHashMap;
18+
use thin_vec::ThinVec;
1619

1720
use crate::{
1821
AliasTy, AnyTraitAssocType, Binders, Const, ConstData, ConstValue, DomainGoal, Goal, GoalData,
19-
InferenceTable, Interner, Lifetime, LifetimeData, PlaceholderIndex, ProjectionTy, Substitution,
20-
Ty, TyKind, VariableKinds,
22+
ImplTraitLoweringMode, InferenceTable, Interner, Lifetime, LifetimeData, LifetimeElisionKind,
23+
ParamLoweringMode, PlaceholderIndex, ProjectionTy, Substitution, TraitRef, Ty, TyKind,
24+
TyLoweringContext, VariableKinds,
2125
chalk_db::{AssociatedTyValue, inline_bound_to_generic_predicate},
2226
db::HirDatabase,
2327
from_assoc_type_id, from_placeholder_idx,
24-
generics::generics,
28+
generics::{Generics, generics},
2529
lt_from_placeholder_idx,
2630
mapping::{ToChalk, to_assoc_type_id_rpitit},
2731
variable_kinds_from_generics,
@@ -58,15 +62,14 @@ impl_intern_key_ref!(RpititImplAssocTyId, RpititImplAssocTy);
5862
#[salsa_macros::tracked(return_ref)]
5963
pub(crate) fn impl_method_rpitit_values(
6064
db: &dyn HirDatabase,
61-
impl_id: hir_def::ImplId,
65+
impl_id: ImplId,
6266
trait_method_id: FunctionId,
6367
) -> Box<[Arc<AssociatedTyValue>]> {
6468
let impl_items = db.impl_items(impl_id);
6569
let trait_method_generics = generics(db, trait_method_id.into());
66-
let impl_datum =
67-
db.impl_datum(impl_id.loc(db).container.krate(), hir_def::ImplId::to_chalk(impl_id, db));
6870
let trait_method = db.function_signature(trait_method_id);
69-
let Some(impl_method) = impl_items.items.iter().find_map(|(name, id)| {
71+
let impl_trait_ref = db.impl_trait(impl_id).expect("invalid impl passed to Chalk");
72+
let impl_method = impl_items.items.iter().find_map(|(name, id)| {
7073
if *name == trait_method.name {
7174
match *id {
7275
AssocItemId::FunctionId(it) => Some(it),
@@ -75,9 +78,19 @@ pub(crate) fn impl_method_rpitit_values(
7578
} else {
7679
None
7780
}
78-
}) else {
79-
// FIXME: Handle defaulted methods.
80-
return Box::default();
81+
});
82+
let impl_method = match impl_method {
83+
Some(impl_method) => impl_method,
84+
None => {
85+
// Method not in the impl, so it is defaulted.
86+
return defaulted_impl_method_rpitit_values(
87+
db,
88+
impl_id,
89+
trait_method_id,
90+
impl_trait_ref,
91+
&trait_method_generics,
92+
);
93+
}
8194
};
8295

8396
let impl_method_generics = generics(db, impl_method.into());
@@ -107,11 +120,7 @@ pub(crate) fn impl_method_rpitit_values(
107120
let trait_ref_placeholder_subst =
108121
&impl_method_placeholder_subst.as_slice(Interner)[..impl_method_generics.len_parent()];
109122
// We want to substitute the TraitRef with placeholders, but placeholders from the method, not the impl.
110-
let impl_trait_ref = impl_datum
111-
.binders
112-
.as_ref()
113-
.map(|it| it.trait_ref.clone())
114-
.substitute(Interner, trait_ref_placeholder_subst);
123+
let impl_trait_ref = impl_trait_ref.substitute(Interner, trait_ref_placeholder_subst);
115124
let trait_to_impl_args = Substitution::from_iter(
116125
Interner,
117126
impl_trait_ref.substitution.as_slice(Interner).iter().chain(
@@ -139,7 +148,7 @@ pub(crate) fn impl_method_rpitit_values(
139148
table.unify(&trait_method_ret, &impl_method_ret);
140149
table.resolve_obligations_as_possible();
141150

142-
return trait_rpitit_to_infer_var
151+
trait_rpitit_to_infer_var
143152
.into_iter()
144153
.map(|(trait_assoc_id, infer_var)| {
145154
let impl_rpitit = table.resolve_completely(infer_var);
@@ -148,6 +157,11 @@ pub(crate) fn impl_method_rpitit_values(
148157
db,
149158
method: impl_method.into(),
150159
method_generics: impl_method_generics.self_params(),
160+
parent: impl_id.into(),
161+
parent_generics: impl_method_generics
162+
.parent_generics()
163+
.expect("parent should be an impl")
164+
.self_params(),
151165
},
152166
DebruijnIndex::INNERMOST,
153167
);
@@ -169,146 +183,142 @@ pub(crate) fn impl_method_rpitit_values(
169183
value: impl_rpitit,
170184
})
171185
})
172-
.collect();
173-
174-
#[derive(chalk_derive::FallibleTypeFolder)]
175-
#[has_interner(Interner)]
176-
struct RpititToInferVarFolder<'a, 'b> {
177-
db: &'a dyn HirDatabase,
178-
table: &'a mut InferenceTable<'b>,
179-
trait_rpitit_to_infer_var: FxHashMap<RpititTraitAssocTyId, Ty>,
180-
trait_method_id: FunctionId,
181-
}
182-
impl TypeFolder<Interner> for RpititToInferVarFolder<'_, '_> {
183-
fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner> {
184-
self
185-
}
186-
187-
fn interner(&self) -> Interner {
188-
Interner
189-
}
186+
.collect()
187+
}
190188

191-
fn fold_ty(&mut self, ty: Ty, outer_binder: DebruijnIndex) -> Ty {
192-
let result = match ty.kind(Interner) {
193-
TyKind::Alias(AliasTy::Projection(ProjectionTy {
194-
associated_ty_id,
195-
substitution,
196-
}))
197-
| TyKind::AssociatedType(associated_ty_id, substitution) => {
198-
if let AnyTraitAssocType::Rpitit(assoc_id) =
199-
from_assoc_type_id(self.db, *associated_ty_id)
200-
{
201-
let assoc = assoc_id.loc(self.db);
202-
if assoc.synthesized_from_method == self.trait_method_id {
203-
if let Some(ty) = self.trait_rpitit_to_infer_var.get(&assoc_id) {
204-
return ty.clone();
205-
}
206-
207-
// Replace with new infer var.
208-
// This needs to come before we fold the bounds, because they also contain this associated type.
209-
let var = self.table.new_type_var();
210-
self.trait_rpitit_to_infer_var.insert(assoc_id, var.clone());
211-
212-
// Recurse into bounds, so that nested RPITITs will be handled correctly.
213-
for bound in assoc.bounds.clone().substitute(Interner, substitution) {
214-
let bound = inline_bound_to_generic_predicate(&bound, var.clone());
215-
let bound = bound.fold_with(self, outer_binder);
216-
let bound = self.table.normalize_associated_types_in(bound);
217-
self.table.register_obligation(Goal::new(
218-
Interner,
219-
GoalData::Quantified(
220-
chalk_ir::QuantifierKind::ForAll,
221-
bound.map(|bound| {
222-
Goal::new(
223-
Interner,
224-
GoalData::DomainGoal(DomainGoal::Holds(bound)),
225-
)
226-
}),
227-
),
228-
));
229-
}
230-
231-
return var;
232-
}
233-
}
234-
ty.clone()
235-
}
236-
_ => ty.clone(),
237-
};
238-
result.super_fold_with(self, outer_binder)
239-
}
240-
}
189+
fn defaulted_impl_method_rpitit_values(
190+
db: &dyn HirDatabase,
191+
impl_id: ImplId,
192+
trait_method_id: FunctionId,
193+
impl_trait_ref: Binders<TraitRef>,
194+
trait_method_generics: &Generics,
195+
) -> Box<[Arc<AssociatedTyValue>]> {
196+
let defaulted_rpitit_values = defaulted_trait_method_rpitit_values(db, trait_method_id);
197+
let impl_generics = generics(db, impl_id.into());
198+
// The associated type generics as the same as the trait method's, but we take the impl as
199+
// the parent instead of the trait.
200+
// The impl generics need to be shifted to account for the associated type generics.
201+
let trait_method_subst = trait_method_generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
202+
let impl_subst = Substitution::from_iter(
203+
Interner,
204+
impl_generics.iter_id().enumerate().map(|(idx, id)| match id {
205+
GenericParamId::ConstParamId(id) => {
206+
BoundVar::new(DebruijnIndex::INNERMOST, idx + trait_method_generics.len_self())
207+
.to_const(Interner, db.const_param_ty(id))
208+
.cast(Interner)
209+
}
210+
GenericParamId::TypeParamId(_) => {
211+
BoundVar::new(DebruijnIndex::INNERMOST, idx + trait_method_generics.len_self())
212+
.to_ty(Interner)
213+
.cast(Interner)
214+
}
215+
GenericParamId::LifetimeParamId(_) => {
216+
BoundVar::new(DebruijnIndex::INNERMOST, idx + trait_method_generics.len_self())
217+
.to_lifetime(Interner)
218+
.cast(Interner)
219+
}
220+
}),
221+
);
222+
let impl_trait_ref = impl_trait_ref.substitute(Interner, &impl_subst);
223+
let impl_rpitit_subst = Substitution::from_iter(
224+
Interner,
225+
trait_method_subst.as_slice(Interner)[..trait_method_generics.len_self()]
226+
.iter()
227+
.chain(impl_trait_ref.substitution.as_slice(Interner)),
228+
);
229+
let binders = VariableKinds::from_iter(
230+
Interner,
231+
variable_kinds_from_generics(
232+
db,
233+
trait_method_generics.iter_self_id().chain(impl_generics.iter_id()),
234+
),
235+
);
236+
defaulted_rpitit_values
237+
.iter()
238+
.map(|(trait_assoc, trait_rpitit)| {
239+
let impl_rpitit = trait_rpitit.clone().substitute(Interner, &impl_rpitit_subst);
240+
Arc::new(AssociatedTyValue {
241+
associated_ty_id: to_assoc_type_id_rpitit(*trait_assoc),
242+
impl_id: ImplId::to_chalk(impl_id, db),
243+
value: Binders::new(binders.clone(), AssociatedTyValueBound { ty: impl_rpitit }),
244+
})
245+
})
246+
.collect()
247+
}
241248

242-
#[derive(chalk_derive::FallibleTypeFolder)]
243-
#[has_interner(Interner)]
244-
struct PlaceholderToBoundVarFolder<'a> {
245-
db: &'a dyn HirDatabase,
246-
method: GenericDefId,
247-
method_generics: &'a GenericParams,
248-
}
249-
impl TypeFolder<Interner> for PlaceholderToBoundVarFolder<'_> {
250-
fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner> {
251-
self
252-
}
249+
/// This is called only for defaulted trait methods, as there the value of the RPITIT associated
250+
/// items on an impl (if the method body is left defaulted) is the same as with the trait method.
251+
// This returns an `EmptyOptimizedThinVec` and not `Box<[]>` because this is called from inference,
252+
// and most methods don't have RPITITs.
253+
#[salsa_macros::tracked(return_ref)]
254+
pub(crate) fn defaulted_trait_method_rpitit_values(
255+
db: &dyn HirDatabase,
256+
method_id: FunctionId,
257+
) -> ThinVec<(RpititTraitAssocTyId, Binders<Ty>)> {
258+
let method_generics = generics(db, method_id.into());
259+
let mut table = InferenceTable::new(db, db.trait_environment(method_id.into()));
253260

254-
fn interner(&self) -> Interner {
255-
Interner
256-
}
261+
let data = db.function_signature(method_id);
262+
let resolver = method_id.resolver(db);
263+
let mut ctx_ret = TyLoweringContext::new(
264+
db,
265+
&resolver,
266+
&data.store,
267+
method_id.into(),
268+
LifetimeElisionKind::Infer,
269+
)
270+
.with_impl_trait_mode(ImplTraitLoweringMode::Opaque)
271+
.with_type_param_mode(ParamLoweringMode::Placeholder);
272+
// This is the return type of the method, with RPITIT lowered as opaques. In other words, like if it was written
273+
// in an impl.
274+
let method_opaques_ret = match data.ret_type {
275+
Some(ret_type) => ctx_ret.lower_ty(ret_type),
276+
None => TyKind::Tuple(0, Substitution::empty(Interner)).intern(Interner),
277+
};
278+
let method_opaques_ret = table.normalize_associated_types_in(method_opaques_ret);
257279

258-
fn fold_free_placeholder_ty(
259-
&mut self,
260-
universe: PlaceholderIndex,
261-
_outer_binder: DebruijnIndex,
262-
) -> Ty {
263-
let placeholder = from_placeholder_idx(self.db, universe);
264-
if placeholder.parent == self.method {
265-
BoundVar::new(
266-
DebruijnIndex::INNERMOST,
267-
placeholder.local_id.into_raw().into_u32() as usize
268-
+ self.method_generics.len_lifetimes(),
269-
)
270-
.to_ty(Interner)
271-
} else {
272-
TyKind::Placeholder(universe).intern(Interner)
273-
}
274-
}
280+
// This is the return type of the method, with RPITITs lowered as associated types. In other words, like in its
281+
// signature.
282+
let method_assocs_ret = db
283+
.callable_item_signature(method_id.into())
284+
.substitute(Interner, &method_generics.placeholder_subst(db))
285+
.ret()
286+
.clone();
287+
let mut rpitit_to_infer_var_folder = RpititToInferVarFolder {
288+
db,
289+
table: &mut table,
290+
trait_method_id: method_id,
291+
trait_rpitit_to_infer_var: FxHashMap::default(),
292+
};
293+
let method_assocs_ret =
294+
method_assocs_ret.fold_with(&mut rpitit_to_infer_var_folder, DebruijnIndex::INNERMOST);
295+
let trait_rpitit_to_infer_var = rpitit_to_infer_var_folder.trait_rpitit_to_infer_var;
296+
let method_assocs_ret = table.normalize_associated_types_in(method_assocs_ret);
275297

276-
fn fold_free_placeholder_const(
277-
&mut self,
278-
ty: Ty,
279-
universe: PlaceholderIndex,
280-
_outer_binder: DebruijnIndex,
281-
) -> Const {
282-
let placeholder = from_placeholder_idx(self.db, universe);
283-
if placeholder.parent == self.method {
284-
BoundVar::new(
285-
DebruijnIndex::INNERMOST,
286-
placeholder.local_id.into_raw().into_u32() as usize
287-
+ self.method_generics.len_lifetimes(),
288-
)
289-
.to_const(Interner, ty)
290-
} else {
291-
Const::new(Interner, ConstData { ty, value: ConstValue::Placeholder(universe) })
292-
}
293-
}
298+
table.resolve_obligations_as_possible();
299+
// Even if unification fails, we want to continue. We will fill the RPITITs with error types.
300+
table.unify(&method_assocs_ret, &method_opaques_ret);
301+
table.resolve_obligations_as_possible();
294302

295-
fn fold_free_placeholder_lifetime(
296-
&mut self,
297-
universe: PlaceholderIndex,
298-
_outer_binder: DebruijnIndex,
299-
) -> Lifetime {
300-
let placeholder = lt_from_placeholder_idx(self.db, universe);
301-
if placeholder.parent == self.method {
302-
BoundVar::new(
303-
DebruijnIndex::INNERMOST,
304-
placeholder.local_id.into_raw().into_u32() as usize,
305-
)
306-
.to_lifetime(Interner)
307-
} else {
308-
Lifetime::new(Interner, LifetimeData::Placeholder(universe))
309-
}
310-
}
311-
}
303+
ThinVec::from_iter(trait_rpitit_to_infer_var.into_iter().map(|(trait_assoc_id, infer_var)| {
304+
let trait_assoc = trait_assoc_id.loc(db);
305+
let rpitit = table.resolve_completely(infer_var);
306+
let rpitit = rpitit.fold_with(
307+
&mut PlaceholderToBoundVarFolder {
308+
db,
309+
method: method_id.into(),
310+
method_generics: method_generics.self_params(),
311+
parent: trait_assoc.trait_id.into(),
312+
parent_generics: method_generics
313+
.parent_generics()
314+
.expect("method should be inside trait")
315+
.self_params(),
316+
},
317+
DebruijnIndex::INNERMOST,
318+
);
319+
let impl_rpitit = trait_assoc.bounds.as_ref().map(|_| rpitit);
320+
(trait_assoc_id, impl_rpitit)
321+
}))
312322
}
313323

314324
fn check_method_generics_are_structurally_compatible(
@@ -333,3 +343,164 @@ fn check_method_generics_are_structurally_compatible(
333343

334344
true
335345
}
346+
347+
#[derive(chalk_derive::FallibleTypeFolder)]
348+
#[has_interner(Interner)]
349+
struct RpititToInferVarFolder<'a, 'b> {
350+
db: &'a dyn HirDatabase,
351+
table: &'a mut InferenceTable<'b>,
352+
trait_rpitit_to_infer_var: FxHashMap<RpititTraitAssocTyId, Ty>,
353+
trait_method_id: FunctionId,
354+
}
355+
impl TypeFolder<Interner> for RpititToInferVarFolder<'_, '_> {
356+
fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner> {
357+
self
358+
}
359+
360+
fn interner(&self) -> Interner {
361+
Interner
362+
}
363+
364+
fn fold_ty(&mut self, ty: Ty, outer_binder: DebruijnIndex) -> Ty {
365+
let result = match ty.kind(Interner) {
366+
TyKind::Alias(AliasTy::Projection(ProjectionTy { associated_ty_id, substitution }))
367+
| TyKind::AssociatedType(associated_ty_id, substitution) => {
368+
if let AnyTraitAssocType::Rpitit(assoc_id) =
369+
from_assoc_type_id(self.db, *associated_ty_id)
370+
{
371+
let assoc = assoc_id.loc(self.db);
372+
if assoc.synthesized_from_method == self.trait_method_id {
373+
if let Some(ty) = self.trait_rpitit_to_infer_var.get(&assoc_id) {
374+
return ty.clone();
375+
}
376+
377+
// Replace with new infer var.
378+
// This needs to come before we fold the bounds, because they also contain this associated type.
379+
let var = self.table.new_type_var();
380+
self.trait_rpitit_to_infer_var.insert(assoc_id, var.clone());
381+
382+
// Recurse into bounds, so that nested RPITITs will be handled correctly.
383+
for bound in assoc.bounds.clone().substitute(Interner, substitution) {
384+
let bound = inline_bound_to_generic_predicate(&bound, var.clone());
385+
// This is an unrelated binder, therefore `DebruijnIndex::INNERMOST`.
386+
let bound = bound.fold_with(self, DebruijnIndex::INNERMOST);
387+
let bound = self.table.normalize_associated_types_in(bound);
388+
self.table.register_obligation(Goal::new(
389+
Interner,
390+
GoalData::Quantified(
391+
chalk_ir::QuantifierKind::ForAll,
392+
bound.map(|bound| {
393+
Goal::new(
394+
Interner,
395+
GoalData::DomainGoal(DomainGoal::Holds(bound)),
396+
)
397+
}),
398+
),
399+
));
400+
}
401+
402+
return var;
403+
}
404+
}
405+
ty.clone()
406+
}
407+
_ => ty.clone(),
408+
};
409+
result.super_fold_with(self, outer_binder)
410+
}
411+
}
412+
413+
#[derive(chalk_derive::FallibleTypeFolder)]
414+
#[has_interner(Interner)]
415+
struct PlaceholderToBoundVarFolder<'a> {
416+
db: &'a dyn HirDatabase,
417+
method: GenericDefId,
418+
method_generics: &'a GenericParams,
419+
parent: GenericDefId,
420+
parent_generics: &'a GenericParams,
421+
}
422+
impl TypeFolder<Interner> for PlaceholderToBoundVarFolder<'_> {
423+
fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner> {
424+
self
425+
}
426+
427+
fn interner(&self) -> Interner {
428+
Interner
429+
}
430+
431+
fn fold_free_placeholder_ty(
432+
&mut self,
433+
universe: PlaceholderIndex,
434+
_outer_binder: DebruijnIndex,
435+
) -> Ty {
436+
let placeholder = from_placeholder_idx(self.db, universe);
437+
if placeholder.parent == self.method {
438+
BoundVar::new(
439+
DebruijnIndex::INNERMOST,
440+
placeholder.local_id.into_raw().into_u32() as usize
441+
+ self.method_generics.len_lifetimes(),
442+
)
443+
.to_ty(Interner)
444+
} else if placeholder.parent == self.parent {
445+
BoundVar::new(
446+
DebruijnIndex::INNERMOST,
447+
placeholder.local_id.into_raw().into_u32() as usize
448+
+ self.method_generics.len()
449+
+ self.parent_generics.len_lifetimes(),
450+
)
451+
.to_ty(Interner)
452+
} else {
453+
TyKind::Placeholder(universe).intern(Interner)
454+
}
455+
}
456+
457+
fn fold_free_placeholder_const(
458+
&mut self,
459+
ty: Ty,
460+
universe: PlaceholderIndex,
461+
_outer_binder: DebruijnIndex,
462+
) -> Const {
463+
let placeholder = from_placeholder_idx(self.db, universe);
464+
if placeholder.parent == self.method {
465+
BoundVar::new(
466+
DebruijnIndex::INNERMOST,
467+
placeholder.local_id.into_raw().into_u32() as usize
468+
+ self.method_generics.len_lifetimes(),
469+
)
470+
.to_const(Interner, ty)
471+
} else if placeholder.parent == self.parent {
472+
BoundVar::new(
473+
DebruijnIndex::INNERMOST,
474+
placeholder.local_id.into_raw().into_u32() as usize
475+
+ self.method_generics.len()
476+
+ self.parent_generics.len_lifetimes(),
477+
)
478+
.to_const(Interner, ty)
479+
} else {
480+
Const::new(Interner, ConstData { ty, value: ConstValue::Placeholder(universe) })
481+
}
482+
}
483+
484+
fn fold_free_placeholder_lifetime(
485+
&mut self,
486+
universe: PlaceholderIndex,
487+
_outer_binder: DebruijnIndex,
488+
) -> Lifetime {
489+
let placeholder = lt_from_placeholder_idx(self.db, universe);
490+
if placeholder.parent == self.method {
491+
BoundVar::new(
492+
DebruijnIndex::INNERMOST,
493+
placeholder.local_id.into_raw().into_u32() as usize,
494+
)
495+
.to_lifetime(Interner)
496+
} else if placeholder.parent == self.parent {
497+
BoundVar::new(
498+
DebruijnIndex::INNERMOST,
499+
placeholder.local_id.into_raw().into_u32() as usize + self.method_generics.len(),
500+
)
501+
.to_lifetime(Interner)
502+
} else {
503+
Lifetime::new(Interner, LifetimeData::Placeholder(universe))
504+
}
505+
}
506+
}

‎crates/hir-ty/src/tests/traits.rs

Lines changed: 52 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4937,13 +4937,15 @@ fn bar<'a, 'b, T, const N: usize, U, const M: usize, Ty: Trait<'a, T, N>>(v: &Ty
49374937
}
49384938
"#,
49394939
// The `{unknown}` is not related to RPITIT, see https://github.com/rust-lang/rust-analyzer/issues/19392.
4940+
// The ordering (lifetimes before `Self`) is not representative of what happens;
4941+
// it's just that our display infra shows lifetimes first.
49404942
expect![[r#"
49414943
72..76 'self': &'? Self
49424944
183..184 'v': &'? Ty
49434945
191..227 '{ ...>(); }': ()
4944-
201..202 '_': (Trait::__foo_rpitit<'b, U, M, Ty, '?, {unknown}, _>,)
4946+
201..202 '_': (Trait::__foo_rpitit<'?, {unknown}, _, 'b, U, M, Ty>,)
49454947
205..206 'v': &'? Ty
4946-
205..224 'v.foo:..., M>()': (Trait::__foo_rpitit<'b, U, M, Ty, '?, {unknown}, _>,)
4948+
205..224 'v.foo:..., M>()': (Trait::__foo_rpitit<'?, {unknown}, _, 'b, U, M, Ty>,)
49474949
"#]],
49484950
);
49494951
}
@@ -5074,14 +5076,14 @@ impl<T> Trait for Foo<T> {
50745076
"#,
50755077
expect![[r#"
50765078
type __foo_rpitit: T1;
5077-
type __foo_rpitit: T2<?1.2> + T2<i32> + ?Sized;
5078-
type __bar_rpitit: T2<bool> + T3<?1.0, ?1.0, 123> + Trait;
5079+
type __foo_rpitit: T2<?1.0> + T2<i32> + ?Sized;
5080+
type __bar_rpitit: T2<bool> + T3<?1.1, ?1.1, 123> + Trait;
50795081
type __baz_rpitit: T1;
50805082
type __baz_rpitit: T4<Assoc = impl T1>;
50815083
50825084
type __foo_rpitit = impl T1;
50835085
type __foo_rpitit = ?0.1;
5084-
type __bar_rpitit = impl T2<T>;
5086+
type __bar_rpitit = impl T2<?2.1>;
50855087
type __baz_rpitit = ();
50865088
type __baz_rpitit = impl T4<Assoc = ()>;
50875089
"#]],
@@ -5109,3 +5111,48 @@ impl Trait for () {
51095111
"#]],
51105112
);
51115113
}
5114+
5115+
#[test]
5116+
fn defaulted_method_with_rpitit() {
5117+
check_rpitit(
5118+
r#"
5119+
//- minicore: sized
5120+
//- /helpers.rs crate:helpers
5121+
pub trait Bar<'a, B: ?Sized, C: ?Sized, D: ?Sized> {}
5122+
5123+
//- /lib.rs crate:library deps:helpers
5124+
use helpers::*;
5125+
trait Trait<T> {
5126+
fn foo<'a, B>() -> impl Bar<'a, B, Self, T>;
5127+
}
5128+
struct Foo<T>(T);
5129+
impl<T, U> Trait<(Foo<()>, U)> for Foo<T> {}
5130+
"#,
5131+
// The debruijn index in the value is 2, but should be 0 to refer to the associated
5132+
// type generics. It is 2 because opaques are wrapped in two binders, and so the 0
5133+
// is shifted in twice. Since users are not expected to see debruijn indices anyway,
5134+
// this does not matter.
5135+
expect![[r#"
5136+
type __foo_rpitit: Bar<?1.0, ?1.1, ?1.2, ?1.3>;
5137+
5138+
type __foo_rpitit = impl Bar<?2.0, ?2.1, Foo<?2.2>, (Foo<()>, ?2.3)>;
5139+
"#]],
5140+
);
5141+
}
5142+
5143+
#[test]
5144+
fn check_foo() {
5145+
check_rpitit(
5146+
r#"
5147+
//- minicore: future, send, sized
5148+
use core::future::Future;
5149+
5150+
trait DesugaredAsyncTrait {
5151+
fn foo(&self) -> impl Future<Output = usize> + Send;
5152+
}
5153+
5154+
impl DesugaredAsyncTrait for () {}
5155+
"#,
5156+
expect![[r#""#]],
5157+
);
5158+
}

‎crates/hir-ty/src/tls.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -97,10 +97,8 @@ impl DebugContext<'_> {
9797
AnyTraitAssocType::Rpitit(assoc_type) => {
9898
let assoc_type = assoc_type.loc(self.0);
9999
let method_data = self.0.function_signature(assoc_type.synthesized_from_method);
100-
let placeholder_assoc_type_name = format!(
101-
"__{}_rpitit",
102-
method_data.name.display(self.0, Edition::LATEST).to_string()
103-
);
100+
let placeholder_assoc_type_name =
101+
format!("__{}_rpitit", method_data.name.display(self.0, Edition::LATEST));
104102
(assoc_type.trait_id, placeholder_assoc_type_name)
105103
}
106104
};

0 commit comments

Comments
 (0)
Please sign in to comment.