Skip to content

Commit b7692b9

Browse files
Move RPITIT stuff to a new module
1 parent fdc5413 commit b7692b9

File tree

7 files changed

+357
-333
lines changed

7 files changed

+357
-333
lines changed

crates/hir-ty/src/chalk_db.rs

Lines changed: 11 additions & 300 deletions
Original file line numberDiff line numberDiff line change
@@ -5,48 +5,41 @@ use std::{iter, ops::ControlFlow, sync::Arc};
55

66
use hir_expand::name::Name;
77
use intern::sym;
8-
use rustc_hash::FxHashMap;
98
use span::Edition;
109
use tracing::debug;
1110

1211
use chalk_ir::{
1312
Binders, CanonicalVarKinds,
1413
cast::{Cast, Caster},
15-
fold::{TypeFoldable, TypeFolder, TypeSuperFoldable, shift::Shift},
14+
fold::shift::Shift,
1615
};
1716
use chalk_solve::rust_ir::{self, AssociatedTyDatumBound, OpaqueTyDatumBound, WellKnownTrait};
1817

1918
use base_db::Crate;
2019
use hir_def::{
21-
AssocItemId, BlockId, CallableDefId, FunctionId, GenericDefId, HasModule, ItemContainerId,
22-
Lookup, TypeAliasId, VariantId,
23-
hir::{
24-
Movability,
25-
generics::{GenericParams, TypeOrConstParamData},
26-
},
20+
AssocItemId, BlockId, CallableDefId, GenericDefId, HasModule, ItemContainerId, Lookup,
21+
TypeAliasId, VariantId,
22+
hir::Movability,
2723
lang_item::LangItem,
2824
signatures::{ImplFlags, StructFlags, TraitFlags},
2925
};
3026

3127
use crate::{
32-
AliasEq, AliasTy, BoundVar, Const, ConstData, ConstValue, DebruijnIndex, DomainGoal, Goal,
33-
GoalData, InferenceTable, Interner, Lifetime, LifetimeData, PlaceholderIndex, ProjectionTy,
34-
ProjectionTyExt, QuantifiedWhereClause, Substitution, TraitRef, TraitRefExt, Ty, TyBuilder,
35-
TyExt, TyKind, VariableKinds, WhereClause,
36-
db::{
37-
HirDatabase, InternedCoroutine, RpititImplAssocTy, RpititImplAssocTyId,
38-
RpititTraitAssocTyId,
39-
},
40-
from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, from_placeholder_idx,
28+
AliasEq, AliasTy, BoundVar, DebruijnIndex, Interner, ProjectionTy, ProjectionTyExt,
29+
QuantifiedWhereClause, Substitution, TraitRef, TraitRefExt, Ty, TyBuilder, TyExt, TyKind,
30+
VariableKinds, WhereClause,
31+
db::{HirDatabase, InternedCoroutine},
32+
from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id,
4133
generics::generics,
4234
lower::LifetimeElisionKind,
4335
lower::trait_fn_signature,
44-
lt_from_placeholder_idx, make_binders, make_single_type_binders,
36+
make_binders, make_single_type_binders,
4537
mapping::{
4638
AnyImplAssocType, AnyTraitAssocType, ToChalk, from_assoc_type_value_id, from_chalk,
4739
to_assoc_type_id_rpitit, to_assoc_type_value_id, to_assoc_type_value_id_rpitit,
4840
},
4941
method_resolution::{ALL_FLOAT_FPS, ALL_INT_FPS, TraitImpls, TyFingerprint},
42+
rpitit::{RpititImplAssocTy, RpititImplAssocTyId, impl_method_rpitit_values},
5043
to_assoc_type_id, to_chalk_trait_id,
5144
traits::ChalkContext,
5245
utils::ClosureSubst,
@@ -961,265 +954,6 @@ fn impl_def_datum(db: &dyn HirDatabase, krate: Crate, impl_id: hir_def::ImplId)
961954
Arc::new(impl_datum)
962955
}
963956

964-
// We return a list and not a hasmap because the number of RPITITs in a function should be small.
965-
#[salsa_macros::tracked(return_ref)]
966-
fn impl_method_rpitit_values(
967-
db: &dyn HirDatabase,
968-
impl_id: hir_def::ImplId,
969-
trait_method_id: FunctionId,
970-
) -> Box<[Arc<AssociatedTyValue>]> {
971-
let impl_items = db.impl_items(impl_id);
972-
let trait_method_generics = generics(db, trait_method_id.into());
973-
let impl_datum =
974-
db.impl_datum(impl_id.loc(db).container.krate(), hir_def::ImplId::to_chalk(impl_id, db));
975-
let trait_method = db.function_signature(trait_method_id);
976-
let Some(impl_method) = impl_items.items.iter().find_map(|(name, id)| {
977-
if *name == trait_method.name {
978-
match *id {
979-
AssocItemId::FunctionId(it) => Some(it),
980-
_ => None,
981-
}
982-
} else {
983-
None
984-
}
985-
}) else {
986-
// FIXME: Handle defaulted methods.
987-
return Box::default();
988-
};
989-
990-
let impl_method_generics = generics(db, impl_method.into());
991-
992-
// First, just so we won't ICE, check that the impl method generics match the trait method generics.
993-
if !check_method_generics_are_structurally_compatible(
994-
trait_method_generics.self_params(),
995-
impl_method_generics.self_params(),
996-
) {
997-
return Box::default();
998-
}
999-
1000-
// The inference algorithm works as follows: in the trait method, we replace each RPITIT with an infer var,
1001-
// then we equate the return type of the trait method with the return type of the impl method. The values
1002-
// of the inference vars now represent the value of the RPITIT assoc types.
1003-
let mut table = InferenceTable::new(db, db.trait_environment(impl_method.into()));
1004-
let impl_method_placeholder_subst = impl_method_generics.placeholder_subst(db);
1005-
1006-
let impl_method_ret = db
1007-
.callable_item_signature(impl_method.into())
1008-
.substitute(Interner, &impl_method_placeholder_subst)
1009-
.ret()
1010-
.clone();
1011-
let impl_method_ret = table.normalize_associated_types_in(impl_method_ret);
1012-
1013-
// Create mapping from trait to impl (i.e. impl trait header + impl method identity args).
1014-
let trait_ref_placeholder_subst =
1015-
&impl_method_placeholder_subst.as_slice(Interner)[impl_method_generics.len_self()..];
1016-
// We want to substitute the TraitRef with placeholders, but placeholders from the method, not the impl.
1017-
let impl_trait_ref = impl_datum
1018-
.binders
1019-
.as_ref()
1020-
.map(|it| it.trait_ref.clone())
1021-
.substitute(Interner, trait_ref_placeholder_subst);
1022-
let trait_to_impl_args = Substitution::from_iter(
1023-
Interner,
1024-
impl_method_placeholder_subst.as_slice(Interner)[..impl_method_generics.len_self()]
1025-
.iter()
1026-
.chain(impl_trait_ref.substitution.as_slice(Interner)),
1027-
);
1028-
let trait_method_ret = db
1029-
.callable_item_signature(trait_method_id.into())
1030-
.substitute(Interner, &trait_to_impl_args)
1031-
.ret()
1032-
.clone();
1033-
let mut rpitit_to_infer_var_folder = RpititToInferVarFolder {
1034-
db,
1035-
table: &mut table,
1036-
trait_method_id,
1037-
trait_rpitit_to_infer_var: FxHashMap::default(),
1038-
};
1039-
let trait_method_ret =
1040-
trait_method_ret.fold_with(&mut rpitit_to_infer_var_folder, DebruijnIndex::INNERMOST);
1041-
let trait_rpitit_to_infer_var = rpitit_to_infer_var_folder.trait_rpitit_to_infer_var;
1042-
let trait_method_ret = table.normalize_associated_types_in(trait_method_ret);
1043-
1044-
table.resolve_obligations_as_possible();
1045-
// Even if unification fails, we want to continue. We will fill the RPITITs with error types.
1046-
table.unify(&trait_method_ret, &impl_method_ret);
1047-
table.resolve_obligations_as_possible();
1048-
1049-
return trait_rpitit_to_infer_var
1050-
.into_iter()
1051-
.map(|(trait_assoc_id, infer_var)| {
1052-
let impl_rpitit = table.resolve_completely(infer_var);
1053-
let impl_rpitit = impl_rpitit.fold_with(
1054-
&mut PlaceholderToBoundVarFolder {
1055-
db,
1056-
method: impl_method.into(),
1057-
method_generics: impl_method_generics.self_params(),
1058-
},
1059-
DebruijnIndex::INNERMOST,
1060-
);
1061-
let trait_assoc = trait_assoc_id.loc(db);
1062-
// Completely unlike the docs, Chalk requires both the impl generics and the associated type
1063-
// generics in the binder.
1064-
let impl_rpitit_binders = VariableKinds::from_iter(
1065-
Interner,
1066-
trait_assoc.bounds.binders.as_slice(Interner)[..trait_method_generics.len()]
1067-
.iter()
1068-
.cloned()
1069-
.chain(variable_kinds_from_generics(db, impl_method_generics.iter_parent_id())),
1070-
);
1071-
let impl_rpitit = Binders::new(
1072-
impl_rpitit_binders,
1073-
rust_ir::AssociatedTyValueBound { ty: impl_rpitit },
1074-
);
1075-
Arc::new(AssociatedTyValue {
1076-
associated_ty_id: to_assoc_type_id_rpitit(trait_assoc_id),
1077-
impl_id: hir_def::ImplId::to_chalk(impl_id, db),
1078-
value: impl_rpitit,
1079-
})
1080-
})
1081-
.collect();
1082-
1083-
#[derive(chalk_derive::FallibleTypeFolder)]
1084-
#[has_interner(Interner)]
1085-
struct RpititToInferVarFolder<'a, 'b> {
1086-
db: &'a dyn HirDatabase,
1087-
table: &'a mut InferenceTable<'b>,
1088-
trait_rpitit_to_infer_var: FxHashMap<RpititTraitAssocTyId, Ty>,
1089-
trait_method_id: FunctionId,
1090-
}
1091-
impl TypeFolder<Interner> for RpititToInferVarFolder<'_, '_> {
1092-
fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner> {
1093-
self
1094-
}
1095-
1096-
fn interner(&self) -> Interner {
1097-
Interner
1098-
}
1099-
1100-
fn fold_ty(&mut self, ty: Ty, outer_binder: DebruijnIndex) -> Ty {
1101-
let result = match ty.kind(Interner) {
1102-
TyKind::Alias(AliasTy::Projection(ProjectionTy {
1103-
associated_ty_id,
1104-
substitution,
1105-
}))
1106-
| TyKind::AssociatedType(associated_ty_id, substitution) => {
1107-
if let AnyTraitAssocType::Rpitit(assoc_id) =
1108-
from_assoc_type_id(self.db, *associated_ty_id)
1109-
{
1110-
let assoc = assoc_id.loc(self.db);
1111-
if assoc.synthesized_from_method == self.trait_method_id {
1112-
if let Some(ty) = self.trait_rpitit_to_infer_var.get(&assoc_id) {
1113-
return ty.clone();
1114-
}
1115-
1116-
// Replace with new infer var.
1117-
// This needs to come before we fold the bounds, because they also contain this associated type.
1118-
let var = self.table.new_type_var();
1119-
self.trait_rpitit_to_infer_var.insert(assoc_id, var.clone());
1120-
1121-
// Recurse into bounds, so that nested RPITITs will be handled correctly.
1122-
for bound in assoc.bounds.clone().substitute(Interner, substitution) {
1123-
let bound = inline_bound_to_generic_predicate(&bound, var.clone());
1124-
let bound = bound.fold_with(self, outer_binder);
1125-
let bound = self.table.normalize_associated_types_in(bound);
1126-
self.table.register_obligation(Goal::new(
1127-
Interner,
1128-
GoalData::Quantified(
1129-
chalk_ir::QuantifierKind::ForAll,
1130-
bound.map(|bound| {
1131-
Goal::new(
1132-
Interner,
1133-
GoalData::DomainGoal(DomainGoal::Holds(bound)),
1134-
)
1135-
}),
1136-
),
1137-
));
1138-
}
1139-
1140-
return var;
1141-
}
1142-
}
1143-
ty.clone()
1144-
}
1145-
_ => ty.clone(),
1146-
};
1147-
result.super_fold_with(self, outer_binder)
1148-
}
1149-
}
1150-
1151-
#[derive(chalk_derive::FallibleTypeFolder)]
1152-
#[has_interner(Interner)]
1153-
struct PlaceholderToBoundVarFolder<'a> {
1154-
db: &'a dyn HirDatabase,
1155-
method: GenericDefId,
1156-
method_generics: &'a GenericParams,
1157-
}
1158-
impl TypeFolder<Interner> for PlaceholderToBoundVarFolder<'_> {
1159-
fn as_dyn(&mut self) -> &mut dyn TypeFolder<Interner> {
1160-
self
1161-
}
1162-
1163-
fn interner(&self) -> Interner {
1164-
Interner
1165-
}
1166-
1167-
fn fold_free_placeholder_ty(
1168-
&mut self,
1169-
universe: PlaceholderIndex,
1170-
_outer_binder: DebruijnIndex,
1171-
) -> Ty {
1172-
let placeholder = from_placeholder_idx(self.db, universe);
1173-
if placeholder.parent == self.method {
1174-
BoundVar::new(
1175-
DebruijnIndex::INNERMOST,
1176-
placeholder.local_id.into_raw().into_u32() as usize
1177-
+ self.method_generics.len_lifetimes(),
1178-
)
1179-
.to_ty(Interner)
1180-
} else {
1181-
TyKind::Placeholder(universe).intern(Interner)
1182-
}
1183-
}
1184-
1185-
fn fold_free_placeholder_const(
1186-
&mut self,
1187-
ty: Ty,
1188-
universe: PlaceholderIndex,
1189-
_outer_binder: DebruijnIndex,
1190-
) -> Const {
1191-
let placeholder = from_placeholder_idx(self.db, universe);
1192-
if placeholder.parent == self.method {
1193-
BoundVar::new(
1194-
DebruijnIndex::INNERMOST,
1195-
placeholder.local_id.into_raw().into_u32() as usize
1196-
+ self.method_generics.len_lifetimes(),
1197-
)
1198-
.to_const(Interner, ty)
1199-
} else {
1200-
Const::new(Interner, ConstData { ty, value: ConstValue::Placeholder(universe) })
1201-
}
1202-
}
1203-
1204-
fn fold_free_placeholder_lifetime(
1205-
&mut self,
1206-
universe: PlaceholderIndex,
1207-
_outer_binder: DebruijnIndex,
1208-
) -> Lifetime {
1209-
let placeholder = lt_from_placeholder_idx(self.db, universe);
1210-
if placeholder.parent == self.method {
1211-
BoundVar::new(
1212-
DebruijnIndex::INNERMOST,
1213-
placeholder.local_id.into_raw().into_u32() as usize,
1214-
)
1215-
.to_lifetime(Interner)
1216-
} else {
1217-
Lifetime::new(Interner, LifetimeData::Placeholder(universe))
1218-
}
1219-
}
1220-
}
1221-
}
1222-
1223957
pub(crate) fn inline_bound_to_generic_predicate(
1224958
bound: &Binders<rust_ir::InlineBound<Interner>>,
1225959
self_ty: Ty,
@@ -1261,29 +995,6 @@ pub(crate) fn inline_bound_to_generic_predicate(
1261995
}
1262996
}
1263997

1264-
fn check_method_generics_are_structurally_compatible(
1265-
trait_method_generics: &GenericParams,
1266-
impl_method_generics: &GenericParams,
1267-
) -> bool {
1268-
if trait_method_generics.len_type_or_consts() != impl_method_generics.len_type_or_consts() {
1269-
return false;
1270-
}
1271-
1272-
for ((_, trait_arg), (_, impl_arg)) in iter::zip(
1273-
trait_method_generics.iter_type_or_consts(),
1274-
impl_method_generics.iter_type_or_consts(),
1275-
) {
1276-
match (trait_arg, impl_arg) {
1277-
(TypeOrConstParamData::TypeParamData(_), TypeOrConstParamData::TypeParamData(_))
1278-
| (TypeOrConstParamData::ConstParamData(_), TypeOrConstParamData::ConstParamData(_)) => {
1279-
}
1280-
_ => return false,
1281-
}
1282-
}
1283-
1284-
true
1285-
}
1286-
1287998
pub(crate) fn associated_ty_value_query(
1288999
db: &dyn HirDatabase,
12891000
krate: Crate,

crates/hir-ty/src/db.rs

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

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

0 commit comments

Comments
 (0)