Skip to content

Commit 1b8fb5b

Browse files
committed
Consider subst in prioritising placeholder inherent methods
1 parent 1ee88db commit 1b8fb5b

File tree

9 files changed

+220
-91
lines changed

9 files changed

+220
-91
lines changed

crates/hir-ty/src/chalk_ext.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ pub trait TyExt {
4343

4444
/// If this is a `dyn Trait`, returns that trait.
4545
fn dyn_trait(&self) -> Option<TraitId>;
46+
fn dyn_trait_ref(&self) -> Option<TraitRef>;
4647

4748
fn impl_trait_bounds(&self, db: &dyn HirDatabase) -> Option<Vec<QuantifiedWhereClause>>;
4849
fn associated_type_parent_trait(&self, db: &dyn HirDatabase) -> Option<TraitId>;
@@ -193,6 +194,31 @@ impl TyExt for Ty {
193194
}
194195
}
195196

197+
fn dyn_trait_ref(&self) -> Option<TraitRef> {
198+
let trait_ref = match self.kind(Interner) {
199+
// The principal trait bound should be the first element of the bounds. This is an
200+
// invariant ensured by `TyLoweringContext::lower_dyn_trait()`.
201+
// FIXME: dyn types may not have principal trait and we don't want to return auto trait
202+
// here.
203+
TyKind::Dyn(dyn_ty) => dyn_ty.bounds.as_ref().filter_map(|x| {
204+
x.interned().get(0).and_then(|b| {
205+
b.as_ref().filter_map(|b| match b {
206+
WhereClause::Implemented(trait_ref) => Some(trait_ref.clone()),
207+
_ => None,
208+
})
209+
})
210+
}),
211+
_ => None,
212+
}?;
213+
// FIXME: qualified bounds not handled (is not valid here I think?)
214+
Some(
215+
trait_ref
216+
.substitute(Interner, &Substitution::from1(Interner, self.clone()))
217+
.into_value_and_skipped_binders()
218+
.0,
219+
)
220+
}
221+
196222
fn dyn_trait(&self) -> Option<TraitId> {
197223
let trait_ref = match self.kind(Interner) {
198224
// The principal trait bound should be the first element of the bounds. This is an

crates/hir-ty/src/infer/expr.rs

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1483,10 +1483,44 @@ impl<'a> InferenceContext<'a> {
14831483
method_name,
14841484
);
14851485
let (receiver_ty, method_ty, substs) = match resolved {
1486-
Some((adjust, func, visible)) => {
1486+
Some((adjust, func, visible, subst)) => {
14871487
let (ty, adjustments) = adjust.apply(&mut self.table, receiver_ty);
14881488
let generics = generics(self.db.upcast(), func.into());
1489-
let substs = self.substs_for_method_call(generics, generic_args);
1489+
let substs = match subst {
1490+
Some(s) => {
1491+
// FIXME: here we need the method subst, but result of `lookup_method` incorrectly returns the trait
1492+
// subst. For some traits (which their methods are not generic, and are not `dyn Trait`) this
1493+
// happens to be the same, so I didn't bothered myself to correctly implement it. Instead, I added
1494+
// this check and we ignore the returned subst if it doesn't match.
1495+
//
1496+
// It might be a good idea to keep this check even after fixing the above, and just add a `never!` to
1497+
// it, as mistakes will make chalk panic. But if you are sure about the implementation, you can remove
1498+
// it to save some performance.
1499+
let default_subst = self.substs_for_method_call(generics, generic_args);
1500+
let is_valid = 'b: {
1501+
if default_subst.len(Interner) != s.len(Interner) {
1502+
break 'b false;
1503+
}
1504+
default_subst.iter(Interner).zip(s.iter(Interner)).all(|(x, y)| {
1505+
matches!(
1506+
(x.data(Interner), y.data(Interner),),
1507+
(GenericArgData::Ty(_), GenericArgData::Ty(_))
1508+
| (
1509+
GenericArgData::Lifetime(_),
1510+
GenericArgData::Lifetime(_)
1511+
)
1512+
| (GenericArgData::Const(_), GenericArgData::Const(_))
1513+
)
1514+
})
1515+
};
1516+
if is_valid {
1517+
s
1518+
} else {
1519+
default_subst
1520+
}
1521+
}
1522+
None => self.substs_for_method_call(generics, generic_args),
1523+
};
14901524
self.write_expr_adj(receiver, adjustments);
14911525
self.write_method_resolution(tgt_expr, func, substs.clone());
14921526
if !visible {

crates/hir-ty/src/infer/path.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -237,19 +237,19 @@ impl<'a> InferenceContext<'a> {
237237
VisibleFromModule::Filter(self.resolver.module()),
238238
Some(name),
239239
method_resolution::LookupMode::Path,
240-
|_ty, item, visible| {
240+
|_ty, item, visible, subst| {
241241
if visible {
242-
Some((item, true))
242+
Some((item, true, subst))
243243
} else {
244244
if not_visible.is_none() {
245-
not_visible = Some((item, false));
245+
not_visible = Some((item, false, subst));
246246
}
247247
None
248248
}
249249
},
250250
);
251251
let res = res.or(not_visible);
252-
let (item, visible) = res?;
252+
let (item, visible, substs) = res?;
253253

254254
let (def, container) = match item {
255255
AssocItemId::FunctionId(f) => {
@@ -258,7 +258,7 @@ impl<'a> InferenceContext<'a> {
258258
AssocItemId::ConstId(c) => (ValueNs::ConstId(c), c.lookup(self.db.upcast()).container),
259259
AssocItemId::TypeAliasId(_) => unreachable!(),
260260
};
261-
let substs = match container {
261+
let substs = substs.unwrap_or_else(|| match container {
262262
ItemContainerId::ImplId(impl_id) => {
263263
let impl_substs = TyBuilder::subst_for_def(self.db, impl_id, None)
264264
.fill_with_inference_vars(&mut self.table)
@@ -278,9 +278,9 @@ impl<'a> InferenceContext<'a> {
278278
}
279279
ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => {
280280
never!("assoc item contained in module/extern block");
281-
return None;
281+
return Substitution::empty(Interner);
282282
}
283-
};
283+
});
284284

285285
self.write_assoc_resolution(id, item, substs.clone());
286286
if !visible {

crates/hir-ty/src/lower.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1405,9 +1405,11 @@ pub(crate) fn generic_predicates_for_param_query(
14051405
Some(TypeNs::TraitId(tr)) => tr,
14061406
_ => return false,
14071407
};
1408-
1409-
all_super_traits(db.upcast(), tr).iter().any(|tr| {
1410-
db.trait_data(*tr).items.iter().any(|(name, item)| {
1408+
let substs = TyBuilder::placeholder_subst(db, tr);
1409+
let tr_ref =
1410+
TraitRef { trait_id: to_chalk_trait_id(tr), substitution: substs };
1411+
all_super_traits(db, tr_ref).iter().any(|tr| {
1412+
db.trait_data(tr.hir_trait_id()).items.iter().any(|(name, item)| {
14111413
matches!(item, AssocItemId::TypeAliasId(_)) && name == assoc_name
14121414
})
14131415
})
@@ -1464,7 +1466,7 @@ pub(crate) fn trait_environment_query(
14641466
for pred in resolver.where_predicates_in_scope() {
14651467
for pred in ctx.lower_where_predicate(pred, false) {
14661468
if let WhereClause::Implemented(tr) = &pred.skip_binders() {
1467-
traits_in_scope.push((tr.self_type_parameter(Interner).clone(), tr.hir_trait_id()));
1469+
traits_in_scope.push((tr.self_type_parameter(Interner).clone(), tr.clone()));
14681470
}
14691471
let program_clause: chalk_ir::ProgramClause<Interner> = pred.cast(Interner);
14701472
clauses.push(program_clause.into_from_env_clause(Interner));

0 commit comments

Comments
 (0)