Skip to content

Commit 50ef086

Browse files
Move RPITIT stuff to a new module
1 parent 1c199f6 commit 50ef086

File tree

6 files changed

+351
-327
lines changed

6 files changed

+351
-327
lines changed

crates/hir-ty/src/chalk_db.rs

+10-297
Original file line numberDiff line numberDiff line change
@@ -5,45 +5,40 @@ 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,
20+
AssocItemId, BlockId, CallableDefId, GenericDefId, HasModule, ItemContainerId, Lookup,
21+
TypeAliasId, VariantId,
2322
data::{TraitFlags, adt::StructFlags},
24-
generics::{GenericParams, TypeOrConstParamData},
2523
hir::Movability,
2624
lang_item::{LangItem, LangItemTarget},
2725
};
2826

2927
use crate::{
30-
AliasEq, AliasTy, BoundVar, Const, ConstData, ConstValue, DebruijnIndex, DomainGoal, FnDefId,
31-
Goal, GoalData, InferenceTable, Interner, Lifetime, LifetimeData, PlaceholderIndex,
32-
ProjectionTy, ProjectionTyExt, QuantifiedWhereClause, Substitution, TraitRef, TraitRefExt, Ty,
33-
TyBuilder, TyExt, TyKind, VariableKinds, WhereClause,
34-
db::{
35-
HirDatabase, InternedCoroutine, RpititImplAssocTy, RpititImplAssocTyId,
36-
RpititTraitAssocTyId,
37-
},
38-
from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, from_placeholder_idx,
28+
AliasEq, AliasTy, BoundVar, DebruijnIndex, FnDefId, 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,
3933
generics::generics,
4034
lower::trait_fn_signature,
41-
lt_from_placeholder_idx, make_binders, make_single_type_binders,
35+
make_binders, make_single_type_binders,
4236
mapping::{
4337
AnyImplAssocType, AnyTraitAssocType, ToChalk, from_assoc_type_value_id, from_chalk,
4438
to_assoc_type_id_rpitit, to_assoc_type_value_id, to_assoc_type_value_id_rpitit,
4539
},
4640
method_resolution::{ALL_FLOAT_FPS, ALL_INT_FPS, TraitImpls, TyFingerprint},
41+
rpitit::{RpititImplAssocTy, RpititImplAssocTyId, impl_method_rpitit_values},
4742
to_assoc_type_id, to_chalk_trait_id,
4843
traits::ChalkContext,
4944
utils::ClosureSubst,
@@ -952,265 +947,6 @@ fn impl_def_datum(db: &dyn HirDatabase, krate: Crate, impl_id: hir_def::ImplId)
952947
Arc::new(impl_datum)
953948
}
954949

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

1253-
fn check_method_generics_are_structurally_compatible(
1254-
trait_method_generics: &GenericParams,
1255-
impl_method_generics: &GenericParams,
1256-
) -> bool {
1257-
if trait_method_generics.len_type_or_consts() != impl_method_generics.len_type_or_consts() {
1258-
return false;
1259-
}
1260-
1261-
for ((_, trait_arg), (_, impl_arg)) in iter::zip(
1262-
trait_method_generics.iter_type_or_consts(),
1263-
impl_method_generics.iter_type_or_consts(),
1264-
) {
1265-
match (trait_arg, impl_arg) {
1266-
(TypeOrConstParamData::TypeParamData(_), TypeOrConstParamData::TypeParamData(_))
1267-
| (TypeOrConstParamData::ConstParamData(_), TypeOrConstParamData::ConstParamData(_)) => {
1268-
}
1269-
_ => return false,
1270-
}
1271-
}
1272-
1273-
true
1274-
}
1275-
1276989
pub(crate) fn associated_ty_value_query(
1277990
db: &dyn HirDatabase,
1278991
krate: Crate,

crates/hir-ty/src/db.rs

+1-28
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, impl_intern_key_ref};
6+
use base_db::{Crate, Upcast, impl_intern_key};
77
use hir_def::{
88
AdtId, BlockId, CallableDefId, ConstParamId, DefWithBodyId, EnumVariantId, FunctionId,
99
GeneralConstId, GenericDefId, ImplId, LifetimeParamId, LocalFieldId, StaticId, TraitId,
@@ -337,30 +337,3 @@ 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-
}
365-
366-
impl_intern_key_ref!(RpititImplAssocTyId, RpititImplAssocTy);

crates/hir-ty/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ mod inhabitedness;
3030
mod interner;
3131
mod lower;
3232
mod mapping;
33+
mod rpitit;
3334
mod target_feature;
3435
mod tls;
3536
mod utils;

0 commit comments

Comments
 (0)