Skip to content

Commit 9a281f2

Browse files
Introduce a new kind of associated types, RPITIT associated types
They don't exist in hir-def, only hir-ty. The idea is that the trait/impl datum query will compute and intern them, then other queries can treat them as (partially) normal associated types. (Lowering RPITIT to synthesized associated types, like rustc does, is required to properly support Return Type Notation).
1 parent f443ba0 commit 9a281f2

File tree

12 files changed

+396
-153
lines changed

12 files changed

+396
-153
lines changed

crates/base-db/src/lib.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ use syntax::{Parse, SyntaxError, ast};
2424
use triomphe::Arc;
2525
pub use vfs::{AnchoredPath, AnchoredPathBuf, FileId, VfsPath, file_set::FileSet};
2626

27+
/// Prefer to use `impl_intern_key_ref!()`, which will not clone the value.
2728
#[macro_export]
2829
macro_rules! impl_intern_key {
2930
($id:ident, $loc:ident) => {
@@ -43,6 +44,26 @@ macro_rules! impl_intern_key {
4344
};
4445
}
4546

47+
#[macro_export]
48+
macro_rules! impl_intern_key_ref {
49+
($id:ident, $loc:ident) => {
50+
#[salsa::interned(no_debug, no_lifetime)]
51+
pub struct $id {
52+
#[return_ref]
53+
pub loc: $loc,
54+
}
55+
56+
// If we derive this salsa prints the values recursively, and this causes us to blow.
57+
impl ::std::fmt::Debug for $id {
58+
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
59+
f.debug_tuple(stringify!($id))
60+
.field(&format_args!("{:04x}", self.0.as_u32()))
61+
.finish()
62+
}
63+
}
64+
};
65+
}
66+
4667
pub trait Upcast<T: ?Sized> {
4768
fn upcast(&self) -> &T;
4869
}

crates/hir-ty/src/chalk_db.rs

Lines changed: 48 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use span::Edition;
99
use tracing::debug;
1010

1111
use chalk_ir::{CanonicalVarKinds, cast::Caster, fold::shift::Shift};
12-
use chalk_solve::rust_ir::{self, OpaqueTyDatumBound, WellKnownTrait};
12+
use chalk_solve::rust_ir::{self, AssociatedTyDatumBound, OpaqueTyDatumBound, WellKnownTrait};
1313

1414
use base_db::Crate;
1515
use hir_def::{
@@ -28,7 +28,10 @@ use crate::{
2828
from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id,
2929
generics::generics,
3030
make_binders, make_single_type_binders,
31-
mapping::{ToChalk, TypeAliasAsValue, from_chalk},
31+
mapping::{
32+
AnyImplAssocType, AnyTraitAssocType, ToChalk, from_assoc_type_value_id, from_chalk,
33+
to_assoc_type_id_rpitit, to_assoc_type_value_id,
34+
},
3235
method_resolution::{ALL_FLOAT_FPS, ALL_INT_FPS, TraitImpls, TyFingerprint},
3336
to_assoc_type_id, to_chalk_trait_id,
3437
traits::ChalkContext,
@@ -448,8 +451,7 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> {
448451
Arc::new(rust_ir::AdtSizeAlign::from_one_zst(false))
449452
}
450453
fn assoc_type_name(&self, assoc_ty_id: chalk_ir::AssocTypeId<Interner>) -> String {
451-
let id = self.db.associated_ty_data(assoc_ty_id).name;
452-
self.db.type_alias_data(id).name.display(self.db.upcast(), self.edition()).to_string()
454+
self.db.associated_ty_data(assoc_ty_id).name.as_str().to_owned()
453455
}
454456
fn opaque_type_name(&self, opaque_ty_id: chalk_ir::OpaqueTyId<Interner>) -> String {
455457
format!("Opaque_{:?}", opaque_ty_id.0)
@@ -606,7 +608,23 @@ pub(crate) fn associated_ty_data_query(
606608
id: AssocTypeId,
607609
) -> Arc<AssociatedTyDatum> {
608610
debug!("associated_ty_data {:?}", id);
609-
let type_alias: TypeAliasId = from_assoc_type_id(id);
611+
612+
let type_alias = match from_assoc_type_id(db, id) {
613+
AnyTraitAssocType::Normal(type_alias) => type_alias,
614+
AnyTraitAssocType::Rpitit(assoc_type_id) => {
615+
let assoc_type = assoc_type_id.loc(db);
616+
return Arc::new(AssociatedTyDatum {
617+
id,
618+
trait_id: to_chalk_trait_id(assoc_type.trait_id),
619+
name: sym::consts::synthesized_rpitit_assoc,
620+
binders: assoc_type
621+
.bounds
622+
.clone()
623+
.map(|bounds| AssociatedTyDatumBound { bounds, where_clauses: Vec::new() }),
624+
});
625+
}
626+
};
627+
610628
let trait_ = match type_alias.lookup(db.upcast()).container {
611629
ItemContainerId::TraitId(t) => t,
612630
_ => panic!("associated type not in trait"),
@@ -658,7 +676,7 @@ pub(crate) fn associated_ty_data_query(
658676
let datum = AssociatedTyDatum {
659677
trait_id: to_chalk_trait_id(trait_),
660678
id,
661-
name: type_alias,
679+
name: type_alias_data.name.symbol().clone(),
662680
binders: make_binders(db, &generic_params, bound_data),
663681
};
664682
Arc::new(datum)
@@ -872,7 +890,7 @@ fn impl_def_datum(db: &dyn HirDatabase, krate: Crate, impl_id: hir_def::ImplId)
872890
let name = &db.type_alias_data(type_alias).name;
873891
trait_data.associated_type_by_name(name).is_some()
874892
})
875-
.map(|type_alias| TypeAliasAsValue(type_alias).to_chalk(db))
893+
.map(|type_alias| to_assoc_type_value_id(type_alias))
876894
.collect();
877895
debug!("impl_datum: {:?}", impl_datum_bound);
878896
let impl_datum = ImplDatum {
@@ -889,8 +907,19 @@ pub(crate) fn associated_ty_value_query(
889907
krate: Crate,
890908
id: AssociatedTyValueId,
891909
) -> Arc<AssociatedTyValue> {
892-
let type_alias: TypeAliasAsValue = from_chalk(db, id);
893-
type_alias_associated_ty_value(db, krate, type_alias.0)
910+
match from_assoc_type_value_id(db, id) {
911+
AnyImplAssocType::Normal(type_alias) => {
912+
type_alias_associated_ty_value(db, krate, type_alias)
913+
}
914+
AnyImplAssocType::Rpitit(assoc_type_id) => {
915+
let assoc_type = assoc_type_id.loc(db);
916+
Arc::new(AssociatedTyValue {
917+
impl_id: assoc_type.impl_id.to_chalk(db),
918+
associated_ty_id: to_assoc_type_id_rpitit(assoc_type.trait_assoc),
919+
value: assoc_type.value.clone(),
920+
})
921+
}
922+
}
894923
}
895924

896925
fn type_alias_associated_ty_value(
@@ -1025,8 +1054,16 @@ pub(super) fn generic_predicate_to_inline_bound(
10251054
Some(chalk_ir::Binders::new(binders, rust_ir::InlineBound::TraitBound(trait_bound)))
10261055
}
10271056
WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(projection_ty), ty }) => {
1028-
let generics =
1029-
generics(db.upcast(), from_assoc_type_id(projection_ty.associated_ty_id).into());
1057+
let generic_def = match from_assoc_type_id(db, projection_ty.associated_ty_id) {
1058+
AnyTraitAssocType::Normal(type_alias) => type_alias.into(),
1059+
AnyTraitAssocType::Rpitit(_) => {
1060+
unreachable!(
1061+
"there is no way to refer to a RPITIT synthesized \
1062+
associated type on associated type's self bounds (`type Assoc: Bound`)"
1063+
)
1064+
}
1065+
};
1066+
let generics = generics(db.upcast(), generic_def);
10301067
let (assoc_args, trait_args) =
10311068
projection_ty.substitution.as_slice(Interner).split_at(generics.len_self());
10321069
let (self_ty, args_no_self) =

crates/hir-ty/src/chalk_ext.rs

Lines changed: 28 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,19 @@ use chalk_ir::{
44
FloatTy, IntTy, Mutability, Scalar, TyVariableKind, TypeOutlives, UintTy, cast::Cast,
55
};
66
use hir_def::{
7-
DefWithBodyId, FunctionId, GenericDefId, HasModule, ItemContainerId, Lookup, TraitId,
7+
DefWithBodyId, FunctionId, HasModule, ItemContainerId, Lookup, TraitId,
88
builtin_type::{BuiltinFloat, BuiltinInt, BuiltinType, BuiltinUint},
99
generics::TypeOrConstParamData,
1010
lang_item::LangItem,
1111
type_ref::Rawness,
1212
};
1313

1414
use crate::{
15-
AdtId, AliasEq, AliasTy, Binders, CallableDefId, CallableSig, Canonical, CanonicalVarKinds,
16-
ClosureId, DynTy, FnPointer, ImplTraitId, InEnvironment, Interner, Lifetime, ProjectionTy,
17-
QuantifiedWhereClause, Substitution, TraitRef, Ty, TyBuilder, TyKind, TypeFlags, WhereClause,
18-
db::HirDatabase, from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id,
19-
from_placeholder_idx, generics::generics, to_chalk_trait_id, utils::ClosureSubst,
15+
AdtId, AliasEq, AliasTy, AssocTypeId, Binders, CallableDefId, CallableSig, Canonical,
16+
CanonicalVarKinds, ClosureId, DynTy, FnPointer, ImplTraitId, InEnvironment, Interner, Lifetime,
17+
ProjectionTy, QuantifiedWhereClause, Substitution, TraitRef, Ty, TyBuilder, TyKind, TypeFlags,
18+
WhereClause, db::HirDatabase, from_assoc_type_id, from_chalk_trait_id, from_placeholder_idx,
19+
generics::generics, mapping::AnyTraitAssocType, to_chalk_trait_id, utils::ClosureSubst,
2020
};
2121

2222
pub trait TyExt {
@@ -39,7 +39,6 @@ pub trait TyExt {
3939
fn as_reference(&self) -> Option<(&Ty, Lifetime, Mutability)>;
4040
fn as_raw_ptr(&self) -> Option<(&Ty, Mutability)>;
4141
fn as_reference_or_ptr(&self) -> Option<(&Ty, Rawness, Mutability)>;
42-
fn as_generic_def(&self, db: &dyn HirDatabase) -> Option<GenericDefId>;
4342

4443
fn callable_def(&self, db: &dyn HirDatabase) -> Option<CallableDefId>;
4544
fn callable_sig(&self, db: &dyn HirDatabase) -> Option<CallableSig>;
@@ -187,19 +186,6 @@ impl TyExt for Ty {
187186
}
188187
}
189188

190-
fn as_generic_def(&self, db: &dyn HirDatabase) -> Option<GenericDefId> {
191-
match *self.kind(Interner) {
192-
TyKind::Adt(AdtId(adt), ..) => Some(adt.into()),
193-
TyKind::FnDef(callable, ..) => Some(GenericDefId::from_callable(
194-
db.upcast(),
195-
db.lookup_intern_callable_def(callable.into()),
196-
)),
197-
TyKind::AssociatedType(type_alias, ..) => Some(from_assoc_type_id(type_alias).into()),
198-
TyKind::Foreign(type_alias, ..) => Some(from_foreign_def_id(type_alias).into()),
199-
_ => None,
200-
}
201-
}
202-
203189
fn callable_def(&self, db: &dyn HirDatabase) -> Option<CallableDefId> {
204190
match self.kind(Interner) {
205191
&TyKind::FnDef(def, ..) => Some(db.lookup_intern_callable_def(def.into())),
@@ -348,20 +334,9 @@ impl TyExt for Ty {
348334

349335
fn associated_type_parent_trait(&self, db: &dyn HirDatabase) -> Option<TraitId> {
350336
match self.kind(Interner) {
351-
TyKind::AssociatedType(id, ..) => {
352-
match from_assoc_type_id(*id).lookup(db.upcast()).container {
353-
ItemContainerId::TraitId(trait_id) => Some(trait_id),
354-
_ => None,
355-
}
356-
}
337+
TyKind::AssociatedType(id, ..) => Some(assoc_type_parent_trait(db, *id)),
357338
TyKind::Alias(AliasTy::Projection(projection_ty)) => {
358-
match from_assoc_type_id(projection_ty.associated_ty_id)
359-
.lookup(db.upcast())
360-
.container
361-
{
362-
ItemContainerId::TraitId(trait_id) => Some(trait_id),
363-
_ => None,
364-
}
339+
Some(assoc_type_parent_trait(db, projection_ty.associated_ty_id))
365340
}
366341
_ => None,
367342
}
@@ -413,6 +388,16 @@ impl TyExt for Ty {
413388
}
414389
}
415390

391+
fn assoc_type_parent_trait(db: &dyn HirDatabase, id: AssocTypeId) -> TraitId {
392+
match from_assoc_type_id(db, id) {
393+
AnyTraitAssocType::Normal(type_alias) => match type_alias.lookup(db.upcast()).container {
394+
ItemContainerId::TraitId(trait_id) => trait_id,
395+
_ => panic!("`AssocTypeId` without parent trait"),
396+
},
397+
AnyTraitAssocType::Rpitit(assoc_type) => assoc_type.loc(db).trait_id,
398+
}
399+
}
400+
416401
pub trait ProjectionTyExt {
417402
fn trait_ref(&self, db: &dyn HirDatabase) -> TraitRef;
418403
fn trait_(&self, db: &dyn HirDatabase) -> TraitId;
@@ -422,7 +407,15 @@ pub trait ProjectionTyExt {
422407
impl ProjectionTyExt for ProjectionTy {
423408
fn trait_ref(&self, db: &dyn HirDatabase) -> TraitRef {
424409
// FIXME: something like `Split` trait from chalk-solve might be nice.
425-
let generics = generics(db.upcast(), from_assoc_type_id(self.associated_ty_id).into());
410+
let generic_def = match from_assoc_type_id(db, self.associated_ty_id) {
411+
AnyTraitAssocType::Normal(type_alias) => type_alias.into(),
412+
// FIXME: This isn't entirely correct, the generics of the RPITIT assoc type may differ from its method
413+
// wrt. lifetimes, but we don't handle that currently. See https://rustc-dev-guide.rust-lang.org/return-position-impl-trait-in-trait.html.
414+
AnyTraitAssocType::Rpitit(assoc_type) => {
415+
assoc_type.loc(db).synthesized_from_method.into()
416+
}
417+
};
418+
let generics = generics(db.upcast(), generic_def);
426419
let substitution = Substitution::from_iter(
427420
Interner,
428421
self.substitution.iter(Interner).skip(generics.len_self()),
@@ -431,10 +424,7 @@ impl ProjectionTyExt for ProjectionTy {
431424
}
432425

433426
fn trait_(&self, db: &dyn HirDatabase) -> TraitId {
434-
match from_assoc_type_id(self.associated_ty_id).lookup(db.upcast()).container {
435-
ItemContainerId::TraitId(it) => it,
436-
_ => panic!("projection ty without parent trait"),
437-
}
427+
assoc_type_parent_trait(db, self.associated_ty_id)
438428
}
439429

440430
fn self_type_parameter(&self, db: &dyn HirDatabase) -> Ty {

crates/hir-ty/src/db.rs

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
44
use std::sync;
55

6-
use base_db::{Crate, Upcast, impl_intern_key};
6+
use base_db::{Crate, Upcast, impl_intern_key, impl_intern_key_ref};
77
use hir_def::{
88
AdtId, BlockId, CallableDefId, ConstParamId, DefWithBodyId, EnumVariantId, FunctionId,
99
GeneralConstId, GenericDefId, ImplId, LifetimeParamId, LocalFieldId, StaticId, TraitId,
@@ -337,3 +337,35 @@ impl_intern_key!(InternedCoroutineId, InternedCoroutine);
337337
// This exists just for Chalk, because Chalk just has a single `FnDefId` where
338338
// we have different IDs for struct and enum variant constructors.
339339
impl_intern_key!(InternedCallableDefId, CallableDefId);
340+
341+
/// An associated type synthesized from a Return Position Impl Trait In Trait
342+
/// of the trait (not the impls).
343+
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
344+
pub struct RpititTraitAssocTy {
345+
pub trait_id: TraitId,
346+
/// The method that contains this RPITIT.
347+
pub synthesized_from_method: FunctionId,
348+
/// The bounds of this associated type (coming from the `impl Bounds`).
349+
///
350+
/// The generics are the generics of the method (with some modifications that we
351+
/// don't currently implement, see https://rustc-dev-guide.rust-lang.org/return-position-impl-trait-in-trait.html).
352+
pub bounds: Binders<Vec<chalk_solve::rust_ir::QuantifiedInlineBound<Interner>>>,
353+
}
354+
355+
impl_intern_key_ref!(RpititTraitAssocTyId, RpititTraitAssocTy);
356+
357+
/// An associated type synthesized from a Return Position Impl Trait In Trait
358+
/// of the impl (not the trait).
359+
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
360+
pub struct RpititImplAssocTy {
361+
pub impl_id: ImplId,
362+
/// The definition of this associated type in the trait.
363+
pub trait_assoc: RpititTraitAssocTyId,
364+
/// The bounds of this associated type (coming from the `impl Bounds`).
365+
///
366+
/// The generics are the generics of the method (with some modifications that we
367+
/// don't currently implement, see https://rustc-dev-guide.rust-lang.org/return-position-impl-trait-in-trait.html).
368+
pub value: Binders<chalk_solve::rust_ir::AssociatedTyValueBound<Interner>>,
369+
}
370+
371+
impl_intern_key_ref!(RpititImplAssocTyId, RpititImplAssocTy);

0 commit comments

Comments
 (0)