Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--Cargo.toml4
-rw-r--r--crates/hir-ty/Cargo.toml8
-rw-r--r--crates/hir-ty/src/autoderef.rs6
-rw-r--r--crates/hir-ty/src/infer/coerce.rs2
-rw-r--r--crates/hir-ty/src/infer/expr.rs24
-rw-r--r--crates/hir-ty/src/infer/path.rs2
-rw-r--r--crates/hir-ty/src/infer/unify.rs75
-rw-r--r--crates/hir-ty/src/method_resolution.rs159
-rw-r--r--crates/hir-ty/src/tests/method_resolution.rs15
-rw-r--r--crates/hir/src/lib.rs9
10 files changed, 154 insertions, 150 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 440f46a938..0679522efd 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -105,6 +105,10 @@ anyhow = "1.0.75"
arrayvec = "0.7.4"
bitflags = "2.4.1"
cargo_metadata = "0.18.1"
+chalk-solve = { version = "0.96.0", default-features = false }
+chalk-ir = "0.96.0"
+chalk-recursive = { version = "0.96.0", default-features = false }
+chalk-derive = "0.96.0"
command-group = "2.0.1"
crossbeam-channel = "0.5.8"
dissimilar = "1.0.7"
diff --git a/crates/hir-ty/Cargo.toml b/crates/hir-ty/Cargo.toml
index 41e2f7ad73..3cfedcdcb4 100644
--- a/crates/hir-ty/Cargo.toml
+++ b/crates/hir-ty/Cargo.toml
@@ -23,10 +23,10 @@ oorandom = "11.1.3"
tracing.workspace = true
rustc-hash.workspace = true
scoped-tls = "1.0.0"
-chalk-solve = { version = "0.96.0", default-features = false }
-chalk-ir = "0.96.0"
-chalk-recursive = { version = "0.96.0", default-features = false }
-chalk-derive = "0.96.0"
+chalk-solve.workspace = true
+chalk-ir.workspace = true
+chalk-recursive.workspace = true
+chalk-derive.workspace = true
la-arena.workspace = true
once_cell = "1.17.0"
triomphe.workspace = true
diff --git a/crates/hir-ty/src/autoderef.rs b/crates/hir-ty/src/autoderef.rs
index 8d819e41aa..e2446c3425 100644
--- a/crates/hir-ty/src/autoderef.rs
+++ b/crates/hir-ty/src/autoderef.rs
@@ -113,7 +113,7 @@ pub(crate) fn autoderef_step(
ty: Ty,
explicit: bool,
) -> Option<(AutoderefKind, Ty)> {
- if let Some(derefed) = builtin_deref(table, &ty, explicit) {
+ if let Some(derefed) = builtin_deref(table.db, &ty, explicit) {
Some((AutoderefKind::Builtin, table.resolve_ty_shallow(derefed)))
} else {
Some((AutoderefKind::Overloaded, deref_by_trait(table, ty)?))
@@ -121,7 +121,7 @@ pub(crate) fn autoderef_step(
}
pub(crate) fn builtin_deref<'ty>(
- table: &mut InferenceTable<'_>,
+ db: &dyn HirDatabase,
ty: &'ty Ty,
explicit: bool,
) -> Option<&'ty Ty> {
@@ -129,7 +129,7 @@ pub(crate) fn builtin_deref<'ty>(
TyKind::Ref(.., ty) => Some(ty),
TyKind::Raw(.., ty) if explicit => Some(ty),
&TyKind::Adt(chalk_ir::AdtId(adt), ref substs) => {
- if crate::lang_items::is_box(table.db, adt) {
+ if crate::lang_items::is_box(db, adt) {
substs.at(Interner, 0).ty(Interner)
} else {
None
diff --git a/crates/hir-ty/src/infer/coerce.rs b/crates/hir-ty/src/infer/coerce.rs
index 61638c43d9..ff6de61ba6 100644
--- a/crates/hir-ty/src/infer/coerce.rs
+++ b/crates/hir-ty/src/infer/coerce.rs
@@ -647,7 +647,7 @@ impl InferenceTable<'_> {
let goal: InEnvironment<DomainGoal> =
InEnvironment::new(&self.trait_env.env, coerce_unsized_tref.cast(Interner));
- let canonicalized = self.canonicalize(goal);
+ let canonicalized = self.canonicalize_with_free_vars(goal);
// FIXME: rustc's coerce_unsized is more specialized -- it only tries to
// solve `CoerceUnsized` and `Unsize` goals at this point and leaves the
diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs
index c377a51e7d..a3dab1fd9d 100644
--- a/crates/hir-ty/src/infer/expr.rs
+++ b/crates/hir-ty/src/infer/expr.rs
@@ -312,15 +312,13 @@ impl InferenceContext<'_> {
Expr::Call { callee, args, .. } => {
let callee_ty = self.infer_expr(*callee, &Expectation::none());
let mut derefs = Autoderef::new(&mut self.table, callee_ty.clone(), false);
- let (res, derefed_callee) = 'b: {
- // manual loop to be able to access `derefs.table`
- while let Some((callee_deref_ty, _)) = derefs.next() {
- let res = derefs.table.callable_sig(&callee_deref_ty, args.len());
- if res.is_some() {
- break 'b (res, callee_deref_ty);
- }
+ let (res, derefed_callee) = loop {
+ let Some((callee_deref_ty, _)) = derefs.next() else {
+ break (None, callee_ty.clone());
+ };
+ if let Some(res) = derefs.table.callable_sig(&callee_deref_ty, args.len()) {
+ break (Some(res), callee_deref_ty);
}
- (None, callee_ty.clone())
};
// if the function is unresolved, we use is_varargs=true to
// suppress the arg count diagnostic here
@@ -657,7 +655,7 @@ impl InferenceContext<'_> {
);
}
}
- if let Some(derefed) = builtin_deref(&mut self.table, &inner_ty, true) {
+ if let Some(derefed) = builtin_deref(self.table.db, &inner_ty, true) {
self.resolve_ty_shallow(derefed)
} else {
deref_by_trait(&mut self.table, inner_ty)
@@ -774,7 +772,7 @@ impl InferenceContext<'_> {
let receiver_adjustments = method_resolution::resolve_indexing_op(
self.db,
self.table.trait_env.clone(),
- canonicalized.value,
+ canonicalized,
index_trait,
);
let (self_ty, mut adj) = receiver_adjustments
@@ -1559,7 +1557,7 @@ impl InferenceContext<'_> {
let canonicalized_receiver = self.canonicalize(receiver_ty.clone());
let resolved = method_resolution::lookup_method(
self.db,
- &canonicalized_receiver.value,
+ &canonicalized_receiver,
self.table.trait_env.clone(),
self.get_traits_in_scope().as_ref().left_or_else(|&it| it),
VisibleFromModule::Filter(self.resolver.module()),
@@ -1608,7 +1606,7 @@ impl InferenceContext<'_> {
let resolved = method_resolution::lookup_method(
self.db,
- &canonicalized_receiver.value,
+ &canonicalized_receiver,
self.table.trait_env.clone(),
self.get_traits_in_scope().as_ref().left_or_else(|&it| it),
VisibleFromModule::Filter(self.resolver.module()),
@@ -1641,7 +1639,7 @@ impl InferenceContext<'_> {
};
let assoc_func_with_same_name = method_resolution::iterate_method_candidates(
- &canonicalized_receiver.value,
+ &canonicalized_receiver,
self.db,
self.table.trait_env.clone(),
self.get_traits_in_scope().as_ref().left_or_else(|&it| it),
diff --git a/crates/hir-ty/src/infer/path.rs b/crates/hir-ty/src/infer/path.rs
index 16ae028427..8f537bb448 100644
--- a/crates/hir-ty/src/infer/path.rs
+++ b/crates/hir-ty/src/infer/path.rs
@@ -321,7 +321,7 @@ impl InferenceContext<'_> {
let mut not_visible = None;
let res = method_resolution::iterate_method_candidates(
- &canonical_ty.value,
+ &canonical_ty,
self.db,
self.table.trait_env.clone(),
self.get_traits_in_scope().as_ref().left_or_else(|&it| it),
diff --git a/crates/hir-ty/src/infer/unify.rs b/crates/hir-ty/src/infer/unify.rs
index 1d0150d850..18029adbaf 100644
--- a/crates/hir-ty/src/infer/unify.rs
+++ b/crates/hir-ty/src/infer/unify.rs
@@ -23,12 +23,9 @@ use crate::{
};
impl InferenceContext<'_> {
- pub(super) fn canonicalize<T: TypeFoldable<Interner> + HasInterner<Interner = Interner>>(
- &mut self,
- t: T,
- ) -> Canonicalized<T>
+ pub(super) fn canonicalize<T>(&mut self, t: T) -> Canonical<T>
where
- T: HasInterner<Interner = Interner>,
+ T: TypeFoldable<Interner> + HasInterner<Interner = Interner>,
{
self.table.canonicalize(t)
}
@@ -128,14 +125,14 @@ impl<T: HasInterner<Interner = Interner>> Canonicalized<T> {
}),
);
for (i, v) in solution.value.iter(Interner).enumerate() {
- let var = self.free_vars[i].clone();
+ let var = &self.free_vars[i];
if let Some(ty) = v.ty(Interner) {
// eagerly replace projections in the type; we may be getting types
// e.g. from where clauses where this hasn't happened yet
let ty = ctx.normalize_associated_types_in(new_vars.apply(ty.clone(), Interner));
ctx.unify(var.assert_ty_ref(Interner), &ty);
} else {
- let _ = ctx.try_unify(&var, &new_vars.apply(v.clone(), Interner));
+ let _ = ctx.try_unify(var, &new_vars.apply(v.clone(), Interner));
}
}
}
@@ -243,7 +240,7 @@ pub(crate) struct InferenceTable<'a> {
pub(crate) db: &'a dyn HirDatabase,
pub(crate) trait_env: Arc<TraitEnvironment>,
var_unification_table: ChalkInferenceTable,
- type_variable_table: Vec<TypeVariableFlags>,
+ type_variable_table: SmallVec<[TypeVariableFlags; 16]>,
pending_obligations: Vec<Canonicalized<InEnvironment<Goal>>>,
/// Double buffer used in [`Self::resolve_obligations_as_possible`] to cut down on
/// temporary allocations.
@@ -252,8 +249,8 @@ pub(crate) struct InferenceTable<'a> {
pub(crate) struct InferenceTableSnapshot {
var_table_snapshot: chalk_solve::infer::InferenceSnapshot<Interner>,
+ type_variable_table: SmallVec<[TypeVariableFlags; 16]>,
pending_obligations: Vec<Canonicalized<InEnvironment<Goal>>>,
- type_variable_table_snapshot: Vec<TypeVariableFlags>,
}
impl<'a> InferenceTable<'a> {
@@ -262,7 +259,7 @@ impl<'a> InferenceTable<'a> {
db,
trait_env,
var_unification_table: ChalkInferenceTable::new(),
- type_variable_table: Vec::new(),
+ type_variable_table: SmallVec::new(),
pending_obligations: Vec::new(),
resolve_obligations_buffer: Vec::new(),
}
@@ -292,14 +289,14 @@ impl<'a> InferenceTable<'a> {
}
fn fallback_value(&self, iv: InferenceVar, kind: TyVariableKind) -> Ty {
+ let is_diverging = self
+ .type_variable_table
+ .get(iv.index() as usize)
+ .map_or(false, |data| data.contains(TypeVariableFlags::DIVERGING));
+ if is_diverging {
+ return TyKind::Never.intern(Interner);
+ }
match kind {
- _ if self
- .type_variable_table
- .get(iv.index() as usize)
- .map_or(false, |data| data.contains(TypeVariableFlags::DIVERGING)) =>
- {
- TyKind::Never
- }
TyVariableKind::General => TyKind::Error,
TyVariableKind::Integer => TyKind::Scalar(Scalar::Int(IntTy::I32)),
TyVariableKind::Float => TyKind::Scalar(Scalar::Float(FloatTy::F64)),
@@ -307,12 +304,9 @@ impl<'a> InferenceTable<'a> {
.intern(Interner)
}
- pub(crate) fn canonicalize<T: TypeFoldable<Interner> + HasInterner<Interner = Interner>>(
- &mut self,
- t: T,
- ) -> Canonicalized<T>
+ pub(crate) fn canonicalize_with_free_vars<T>(&mut self, t: T) -> Canonicalized<T>
where
- T: HasInterner<Interner = Interner>,
+ T: TypeFoldable<Interner> + HasInterner<Interner = Interner>,
{
// try to resolve obligations before canonicalizing, since this might
// result in new knowledge about variables
@@ -326,6 +320,16 @@ impl<'a> InferenceTable<'a> {
Canonicalized { value: result.quantified, free_vars }
}
+ pub(crate) fn canonicalize<T>(&mut self, t: T) -> Canonical<T>
+ where
+ T: TypeFoldable<Interner> + HasInterner<Interner = Interner>,
+ {
+ // try to resolve obligations before canonicalizing, since this might
+ // result in new knowledge about variables
+ self.resolve_obligations_as_possible();
+ self.var_unification_table.canonicalize(Interner, t).quantified
+ }
+
/// Recurses through the given type, normalizing associated types mentioned
/// in it by replacing them by type variables and registering obligations to
/// resolve later. This should be done once for every type we get from some
@@ -434,6 +438,7 @@ impl<'a> InferenceTable<'a> {
where
T: HasInterner<Interner = Interner> + TypeFoldable<Interner>,
{
+ // TODO check this vec here
self.resolve_with_fallback_inner(&mut Vec::new(), t, &fallback)
}
@@ -541,7 +546,7 @@ impl<'a> InferenceTable<'a> {
Err(_) => return false,
};
result.goals.iter().all(|goal| {
- let canonicalized = self.canonicalize(goal.clone());
+ let canonicalized = self.canonicalize_with_free_vars(goal.clone());
self.try_resolve_obligation(&canonicalized).is_some()
})
}
@@ -575,19 +580,15 @@ impl<'a> InferenceTable<'a> {
pub(crate) fn snapshot(&mut self) -> InferenceTableSnapshot {
let var_table_snapshot = self.var_unification_table.snapshot();
- let type_variable_table_snapshot = self.type_variable_table.clone();
+ let type_variable_table = self.type_variable_table.clone();
let pending_obligations = self.pending_obligations.clone();
- InferenceTableSnapshot {
- var_table_snapshot,
- pending_obligations,
- type_variable_table_snapshot,
- }
+ InferenceTableSnapshot { var_table_snapshot, pending_obligations, type_variable_table }
}
#[tracing::instrument(skip_all)]
pub(crate) fn rollback_to(&mut self, snapshot: InferenceTableSnapshot) {
self.var_unification_table.rollback_to(snapshot.var_table_snapshot);
- self.type_variable_table = snapshot.type_variable_table_snapshot;
+ self.type_variable_table = snapshot.type_variable_table;
self.pending_obligations = snapshot.pending_obligations;
}
@@ -606,7 +607,7 @@ impl<'a> InferenceTable<'a> {
let in_env = InEnvironment::new(&self.trait_env.env, goal);
let canonicalized = self.canonicalize(in_env);
- self.db.trait_solve(self.trait_env.krate, self.trait_env.block, canonicalized.value)
+ self.db.trait_solve(self.trait_env.krate, self.trait_env.block, canonicalized)
}
pub(crate) fn register_obligation(&mut self, goal: Goal) {
@@ -615,7 +616,7 @@ impl<'a> InferenceTable<'a> {
}
fn register_obligation_in_env(&mut self, goal: InEnvironment<Goal>) {
- let canonicalized = self.canonicalize(goal);
+ let canonicalized = self.canonicalize_with_free_vars(goal);
let solution = self.try_resolve_obligation(&canonicalized);
if matches!(solution, Some(Solution::Ambig(_))) {
self.pending_obligations.push(canonicalized);
@@ -798,7 +799,7 @@ impl<'a> InferenceTable<'a> {
let trait_data = self.db.trait_data(fn_once_trait);
let output_assoc_type = trait_data.associated_type_by_name(&name![Output])?;
- let mut arg_tys = vec![];
+ let mut arg_tys = Vec::with_capacity(num_args);
let arg_ty = TyBuilder::tuple(num_args)
.fill(|it| {
let arg = match it {
@@ -828,11 +829,7 @@ impl<'a> InferenceTable<'a> {
environment: trait_env.clone(),
};
let canonical = self.canonicalize(obligation.clone());
- if self
- .db
- .trait_solve(krate, self.trait_env.block, canonical.value.cast(Interner))
- .is_some()
- {
+ if self.db.trait_solve(krate, self.trait_env.block, canonical.cast(Interner)).is_some() {
self.register_obligation(obligation.goal);
let return_ty = self.normalize_projection_ty(projection);
for fn_x in [FnTrait::Fn, FnTrait::FnMut, FnTrait::FnOnce] {
@@ -845,7 +842,7 @@ impl<'a> InferenceTable<'a> {
let canonical = self.canonicalize(obligation.clone());
if self
.db
- .trait_solve(krate, self.trait_env.block, canonical.value.cast(Interner))
+ .trait_solve(krate, self.trait_env.block, canonical.cast(Interner))
.is_some()
{
return Some((fn_x, arg_tys, return_ty));
diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs
index b605469521..3a97c55a67 100644
--- a/crates/hir-ty/src/method_resolution.rs
+++ b/crates/hir-ty/src/method_resolution.rs
@@ -972,10 +972,9 @@ pub fn iterate_method_candidates_dyn(
deref_chain.into_iter().try_for_each(|(receiver_ty, adj)| {
iterate_method_candidates_with_autoref(
- &receiver_ty,
+ &mut table,
+ receiver_ty,
adj,
- db,
- env.clone(),
traits_in_scope,
visible_from_module,
name,
@@ -1000,10 +999,9 @@ pub fn iterate_method_candidates_dyn(
#[tracing::instrument(skip_all, fields(name = ?name))]
fn iterate_method_candidates_with_autoref(
- receiver_ty: &Canonical<Ty>,
+ table: &mut InferenceTable<'_>,
+ receiver_ty: Canonical<Ty>,
first_adjustment: ReceiverAdjustments,
- db: &dyn HirDatabase,
- env: Arc<TraitEnvironment>,
traits_in_scope: &FxHashSet<TraitId>,
visible_from_module: VisibleFromModule,
name: Option<&Name>,
@@ -1016,10 +1014,9 @@ fn iterate_method_candidates_with_autoref(
let mut iterate_method_candidates_by_receiver = move |receiver_ty, first_adjustment| {
iterate_method_candidates_by_receiver(
+ table,
receiver_ty,
first_adjustment,
- db,
- env.clone(),
traits_in_scope,
visible_from_module,
name,
@@ -1034,7 +1031,7 @@ fn iterate_method_candidates_with_autoref(
maybe_reborrowed.autoderefs += 1;
}
- iterate_method_candidates_by_receiver(receiver_ty, maybe_reborrowed)?;
+ iterate_method_candidates_by_receiver(receiver_ty.clone(), maybe_reborrowed)?;
let refed = Canonical {
value: TyKind::Ref(Mutability::Not, static_lifetime(), receiver_ty.value.clone())
@@ -1042,7 +1039,7 @@ fn iterate_method_candidates_with_autoref(
binders: receiver_ty.binders.clone(),
};
- iterate_method_candidates_by_receiver(&refed, first_adjustment.with_autoref(Mutability::Not))?;
+ iterate_method_candidates_by_receiver(refed, first_adjustment.with_autoref(Mutability::Not))?;
let ref_muted = Canonical {
value: TyKind::Ref(Mutability::Mut, static_lifetime(), receiver_ty.value.clone())
@@ -1050,58 +1047,54 @@ fn iterate_method_candidates_with_autoref(
binders: receiver_ty.binders.clone(),
};
- iterate_method_candidates_by_receiver(
- &ref_muted,
- first_adjustment.with_autoref(Mutability::Mut),
- )
+ iterate_method_candidates_by_receiver(ref_muted, first_adjustment.with_autoref(Mutability::Mut))
}
#[tracing::instrument(skip_all, fields(name = ?name))]
fn iterate_method_candidates_by_receiver(
- receiver_ty: &Canonical<Ty>,
+ table: &mut InferenceTable<'_>,
+ receiver_ty: Canonical<Ty>,
receiver_adjustments: ReceiverAdjustments,
- db: &dyn HirDatabase,
- env: Arc<TraitEnvironment>,
traits_in_scope: &FxHashSet<TraitId>,
visible_from_module: VisibleFromModule,
name: Option<&Name>,
mut callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId, bool) -> ControlFlow<()>,
) -> ControlFlow<()> {
- let mut table = InferenceTable::new(db, env);
- let receiver_ty = table.instantiate_canonical(receiver_ty.clone());
- let snapshot = table.snapshot();
- // We're looking for methods with *receiver* type receiver_ty. These could
- // be found in any of the derefs of receiver_ty, so we have to go through
- // that, including raw derefs.
- let mut autoderef = autoderef::Autoderef::new(&mut table, receiver_ty.clone(), true);
- while let Some((self_ty, _)) = autoderef.next() {
- iterate_inherent_methods(
- &self_ty,
- autoderef.table,
- name,
- Some(&receiver_ty),
- Some(receiver_adjustments.clone()),
- visible_from_module,
- &mut callback,
- )?
- }
-
- table.rollback_to(snapshot);
-
- let mut autoderef = autoderef::Autoderef::new(&mut table, receiver_ty.clone(), true);
- while let Some((self_ty, _)) = autoderef.next() {
- iterate_trait_method_candidates(
- &self_ty,
- autoderef.table,
- traits_in_scope,
- name,
- Some(&receiver_ty),
- Some(receiver_adjustments.clone()),
- &mut callback,
- )?
- }
+ table.run_in_snapshot(|table| {
+ let receiver_ty = table.instantiate_canonical(receiver_ty.clone());
+ // We're looking for methods with *receiver* type receiver_ty. These could
+ // be found in any of the derefs of receiver_ty, so we have to go through
+ // that, including raw derefs.
+ table.run_in_snapshot(|table| {
+ let mut autoderef = autoderef::Autoderef::new(table, receiver_ty.clone(), true);
+ while let Some((self_ty, _)) = autoderef.next() {
+ iterate_inherent_methods(
+ &self_ty,
+ autoderef.table,
+ name,
+ Some(&receiver_ty),
+ Some(receiver_adjustments.clone()),
+ visible_from_module,
+ &mut callback,
+ )?
+ }
+ ControlFlow::Continue(())
+ })?;
- ControlFlow::Continue(())
+ let mut autoderef = autoderef::Autoderef::new(table, receiver_ty.clone(), true);
+ while let Some((self_ty, _)) = autoderef.next() {
+ iterate_trait_method_candidates(
+ &self_ty,
+ autoderef.table,
+ traits_in_scope,
+ name,
+ Some(&receiver_ty),
+ Some(receiver_adjustments.clone()),
+ &mut callback,
+ )?
+ }
+ ControlFlow::Continue(())
+ })
}
#[tracing::instrument(skip_all, fields(name = ?name))]
@@ -1147,9 +1140,9 @@ fn iterate_trait_method_candidates(
callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId, bool) -> ControlFlow<()>,
) -> ControlFlow<()> {
let db = table.db;
- let env = table.trait_env.clone();
- let canonical_self_ty = table.canonicalize(self_ty.clone()).value;
+ let canonical_self_ty = table.canonicalize(self_ty.clone());
+ let TraitEnvironment { krate, block, .. } = *table.trait_env;
'traits: for &t in traits_in_scope {
let data = db.trait_data(t);
@@ -1164,7 +1157,7 @@ fn iterate_trait_method_candidates(
{
// FIXME: this should really be using the edition of the method name's span, in case it
// comes from a macro
- if db.crate_graph()[env.krate].edition < Edition::Edition2021 {
+ if db.crate_graph()[krate].edition < Edition::Edition2021 {
continue;
}
}
@@ -1183,8 +1176,8 @@ fn iterate_trait_method_candidates(
IsValidCandidate::No => continue,
};
if !known_implemented {
- let goal = generic_implements_goal(db, env.clone(), t, &canonical_self_ty);
- if db.trait_solve(env.krate, env.block, goal.cast(Interner)).is_none() {
+ let goal = generic_implements_goal(db, &table.trait_env, t, &canonical_self_ty);
+ if db.trait_solve(krate, block, goal.cast(Interner)).is_none() {
continue 'traits;
}
}
@@ -1365,7 +1358,7 @@ pub(crate) fn resolve_indexing_op(
let ty = table.instantiate_canonical(ty);
let deref_chain = autoderef_method_receiver(&mut table, ty);
for (ty, adj) in deref_chain {
- let goal = generic_implements_goal(db, table.trait_env.clone(), index_trait, &ty);
+ let goal = generic_implements_goal(db, &table.trait_env, index_trait, &ty);
if db
.trait_solve(table.trait_env.krate, table.trait_env.block, goal.cast(Interner))
.is_some()
@@ -1548,7 +1541,7 @@ fn is_valid_impl_fn_candidate(
for goal in goals.clone() {
let in_env = InEnvironment::new(&table.trait_env.env, goal);
- let canonicalized = table.canonicalize(in_env);
+ let canonicalized = table.canonicalize_with_free_vars(in_env);
let solution = table.db.trait_solve(
table.trait_env.krate,
table.trait_env.block,
@@ -1586,10 +1579,10 @@ fn is_valid_impl_fn_candidate(
pub fn implements_trait(
ty: &Canonical<Ty>,
db: &dyn HirDatabase,
- env: Arc<TraitEnvironment>,
+ env: &TraitEnvironment,
trait_: TraitId,
) -> bool {
- let goal = generic_implements_goal(db, env.clone(), trait_, ty);
+ let goal = generic_implements_goal(db, env, trait_, ty);
let solution = db.trait_solve(env.krate, env.block, goal.cast(Interner));
solution.is_some()
@@ -1598,10 +1591,10 @@ pub fn implements_trait(
pub fn implements_trait_unique(
ty: &Canonical<Ty>,
db: &dyn HirDatabase,
- env: Arc<TraitEnvironment>,
+ env: &TraitEnvironment,
trait_: TraitId,
) -> bool {
- let goal = generic_implements_goal(db, env.clone(), trait_, ty);
+ let goal = generic_implements_goal(db, env, trait_, ty);
let solution = db.trait_solve(env.krate, env.block, goal.cast(Interner));
matches!(solution, Some(crate::Solution::Unique(_)))
@@ -1612,32 +1605,34 @@ pub fn implements_trait_unique(
#[tracing::instrument(skip_all)]
fn generic_implements_goal(
db: &dyn HirDatabase,
- env: Arc<TraitEnvironment>,
+ env: &TraitEnvironment,
trait_: TraitId,
self_ty: &Canonical<Ty>,
) -> Canonical<InEnvironment<super::DomainGoal>> {
- let mut kinds = self_ty.binders.interned().to_vec();
+ let binders = self_ty.binders.interned();
let trait_ref = TyBuilder::trait_ref(db, trait_)
.push(self_ty.value.clone())
- .fill_with_bound_vars(DebruijnIndex::INNERMOST, kinds.len())
+ .fill_with_bound_vars(DebruijnIndex::INNERMOST, binders.len())
.build();
- kinds.extend(trait_ref.substitution.iter(Interner).skip(1).map(|it| {
- let vk = match it.data(Interner) {
- chalk_ir::GenericArgData::Ty(_) => {
- chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General)
- }
- chalk_ir::GenericArgData::Lifetime(_) => chalk_ir::VariableKind::Lifetime,
- chalk_ir::GenericArgData::Const(c) => {
- chalk_ir::VariableKind::Const(c.data(Interner).ty.clone())
- }
- };
- chalk_ir::WithKind::new(vk, UniverseIndex::ROOT)
- }));
+
+ let kinds =
+ binders.iter().cloned().chain(trait_ref.substitution.iter(Interner).skip(1).map(|it| {
+ let vk = match it.data(Interner) {
+ chalk_ir::GenericArgData::Ty(_) => {
+ chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General)
+ }
+ chalk_ir::GenericArgData::Lifetime(_) => chalk_ir::VariableKind::Lifetime,
+ chalk_ir::GenericArgData::Const(c) => {
+ chalk_ir::VariableKind::Const(c.data(Interner).ty.clone())
+ }
+ };
+ chalk_ir::WithKind::new(vk, UniverseIndex::ROOT)
+ }));
+ let binders = CanonicalVarKinds::from_iter(Interner, kinds);
+
let obligation = trait_ref.cast(Interner);
- Canonical {
- binders: CanonicalVarKinds::from_iter(Interner, kinds),
- value: InEnvironment::new(&env.env, obligation),
- }
+ let value = InEnvironment::new(&env.env, obligation);
+ Canonical { binders, value }
}
fn autoderef_method_receiver(
@@ -1648,7 +1643,7 @@ fn autoderef_method_receiver(
let mut autoderef = autoderef::Autoderef::new(table, ty, false);
while let Some((ty, derefs)) = autoderef.next() {
deref_chain.push((
- autoderef.table.canonicalize(ty).value,
+ autoderef.table.canonicalize(ty),
ReceiverAdjustments { autoref: None, autoderefs: derefs, unsize_array: false },
));
}
diff --git a/crates/hir-ty/src/tests/method_resolution.rs b/crates/hir-ty/src/tests/method_resolution.rs
index c521dbf167..8609ba4103 100644
--- a/crates/hir-ty/src/tests/method_resolution.rs
+++ b/crates/hir-ty/src/tests/method_resolution.rs
@@ -1774,6 +1774,21 @@ fn test() {
}
#[test]
+fn deref_into_inference_var() {
+ check_types(
+ r#"
+//- minicore:deref
+struct A<T>(T);
+impl core::ops::Deref for A<u32> {}
+impl A<i32> { fn foo(&self) {} }
+fn main() {
+ A(0).foo();
+ //^^^^^^^^^^ ()
+}
+"#,
+ );
+}
+#[test]
fn receiver_adjustment_autoref() {
check(
r#"
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 74e6c000ed..739fbfe068 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -4037,7 +4037,7 @@ impl Type {
let canonical_ty =
Canonical { value: self.ty.clone(), binders: CanonicalVarKinds::empty(Interner) };
- method_resolution::implements_trait(&canonical_ty, db, self.env.clone(), trait_)
+ method_resolution::implements_trait(&canonical_ty, db, &self.env, trait_)
}
/// Checks that particular type `ty` implements `std::ops::FnOnce`.
@@ -4052,12 +4052,7 @@ impl Type {
let canonical_ty =
Canonical { value: self.ty.clone(), binders: CanonicalVarKinds::empty(Interner) };
- method_resolution::implements_trait_unique(
- &canonical_ty,
- db,
- self.env.clone(),
- fnonce_trait,
- )
+ method_resolution::implements_trait_unique(&canonical_ty, db, &self.env, fnonce_trait)
}
// FIXME: Find better API that also handles const generics