Unnamed repository; edit this file 'description' to name the repository.
Auto merge of #14424 - Veykril:local-trait-impls, r=Veykril
fix: Properly handle local trait impls Before we only handled trait impls that came from the block of either the trait or the target type, we now handle them correctly by tracking the block we are currently inferring from, then walking that up to collect all block trait impls.
bors 2023-03-28
parent a869ca3 · parent 342fd2b · commit f735105
-rw-r--r--crates/hir-def/src/db.rs2
-rw-r--r--crates/hir-ty/src/chalk_db.rs83
-rw-r--r--crates/hir-ty/src/db.rs8
-rw-r--r--crates/hir-ty/src/infer.rs6
-rw-r--r--crates/hir-ty/src/infer/coerce.rs2
-rw-r--r--crates/hir-ty/src/infer/expr.rs35
-rw-r--r--crates/hir-ty/src/infer/unify.rs21
-rw-r--r--crates/hir-ty/src/lib.rs1
-rw-r--r--crates/hir-ty/src/lower.rs2
-rw-r--r--crates/hir-ty/src/method_resolution.rs30
-rw-r--r--crates/hir-ty/src/tests/traits.rs30
-rw-r--r--crates/hir-ty/src/traits.rs11
-rw-r--r--crates/hir/src/lib.rs2
13 files changed, 138 insertions, 95 deletions
diff --git a/crates/hir-def/src/db.rs b/crates/hir-def/src/db.rs
index 9371fc14dd..e6986dd1fc 100644
--- a/crates/hir-def/src/db.rs
+++ b/crates/hir-def/src/db.rs
@@ -93,6 +93,8 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + Upcast<dyn ExpandDataba
///
/// The `block_def_map` for block 0 would return `None`, while `block_def_map` of block 1 would
/// return a `DefMap` containing `inner`.
+ // FIXME: This actually can't return None anymore as we no longer allocate block scopes for
+ // non item declaring blocks
#[salsa::invoke(DefMap::block_def_map_query)]
fn block_def_map(&self, block: BlockId) -> Option<Arc<DefMap>>;
diff --git a/crates/hir-ty/src/chalk_db.rs b/crates/hir-ty/src/chalk_db.rs
index 28ae4c349f..68375f9e1e 100644
--- a/crates/hir-ty/src/chalk_db.rs
+++ b/crates/hir-ty/src/chalk_db.rs
@@ -1,8 +1,7 @@
//! The implementation of `RustIrDatabase` for Chalk, which provides information
//! about the code that Chalk needs.
-use std::sync::Arc;
+use std::{iter, sync::Arc};
-use cov_mark::hit;
use tracing::debug;
use chalk_ir::{cast::Cast, fold::shift::Shift, CanonicalVarKinds};
@@ -12,17 +11,16 @@ use base_db::CrateId;
use hir_def::{
expr::Movability,
lang_item::{lang_attr, LangItem, LangItemTarget},
- AssocItemId, GenericDefId, HasModule, ItemContainerId, Lookup, ModuleId, TypeAliasId,
+ AssocItemId, BlockId, GenericDefId, HasModule, ItemContainerId, Lookup, TypeAliasId,
};
use hir_expand::name::name;
use crate::{
db::HirDatabase,
display::HirDisplay,
- from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, make_binders,
- make_single_type_binders,
+ from_assoc_type_id, from_chalk_trait_id, make_binders, make_single_type_binders,
mapping::{from_chalk, ToChalk, TypeAliasAsValue},
- method_resolution::{TraitImpls, TyFingerprint, ALL_FLOAT_FPS, ALL_INT_FPS},
+ method_resolution::{TyFingerprint, ALL_FLOAT_FPS, ALL_INT_FPS},
to_assoc_type_id, to_chalk_trait_id,
traits::ChalkContext,
utils::generics,
@@ -108,53 +106,41 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
_ => self_ty_fp.as_ref().map(std::slice::from_ref).unwrap_or(&[]),
};
- fn local_impls(db: &dyn HirDatabase, module: ModuleId) -> Option<Arc<TraitImpls>> {
- let block = module.containing_block()?;
- hit!(block_local_impls);
- db.trait_impls_in_block(block)
- }
-
// Note: Since we're using impls_for_trait, only impls where the trait
// can be resolved should ever reach Chalk. impl_datum relies on that
// and will panic if the trait can't be resolved.
let in_deps = self.db.trait_impls_in_deps(self.krate);
let in_self = self.db.trait_impls_in_crate(self.krate);
- let trait_module = trait_.module(self.db.upcast());
- let type_module = match self_ty_fp {
- Some(TyFingerprint::Adt(adt_id)) => Some(adt_id.module(self.db.upcast())),
- Some(TyFingerprint::ForeignType(type_id)) => {
- Some(from_foreign_def_id(type_id).module(self.db.upcast()))
- }
- Some(TyFingerprint::Dyn(trait_id)) => Some(trait_id.module(self.db.upcast())),
- _ => None,
- };
- let impl_maps = [
- Some(in_deps),
- Some(in_self),
- local_impls(self.db, trait_module),
- type_module.and_then(|m| local_impls(self.db, m)),
- ];
- let id_to_chalk = |id: hir_def::ImplId| id.to_chalk(self.db);
+ let impl_maps = [in_deps, in_self];
+ let block_impls = iter::successors(self.block, |&block_id| {
+ cov_mark::hit!(block_local_impls);
+ self.db
+ .block_def_map(block_id)
+ .and_then(|map| map.parent())
+ .and_then(|module| module.containing_block())
+ })
+ .filter_map(|block_id| self.db.trait_impls_in_block(block_id));
- let result: Vec<_> = if fps.is_empty() {
- debug!("Unrestricted search for {:?} impls...", trait_);
- impl_maps
- .iter()
- .filter_map(|o| o.as_ref())
- .flat_map(|impls| impls.for_trait(trait_).map(id_to_chalk))
- .collect()
- } else {
- impl_maps
- .iter()
- .filter_map(|o| o.as_ref())
- .flat_map(|impls| {
- fps.iter().flat_map(move |fp| {
- impls.for_trait_and_self_ty(trait_, *fp).map(id_to_chalk)
- })
- })
- .collect()
- };
+ let id_to_chalk = |id: hir_def::ImplId| id.to_chalk(self.db);
+ let mut result = vec![];
+ match fps {
+ [] => {
+ debug!("Unrestricted search for {:?} impls...", trait_);
+ impl_maps.into_iter().chain(block_impls).for_each(|impls| {
+ result.extend(impls.for_trait(trait_).map(id_to_chalk));
+ });
+ }
+ fps => {
+ impl_maps.into_iter().chain(block_impls).for_each(|impls| {
+ result.extend(
+ fps.iter().flat_map(|fp| {
+ impls.for_trait_and_self_ty(trait_, *fp).map(id_to_chalk)
+ }),
+ );
+ });
+ }
+ }
debug!("impls_for_trait returned {} impls", result.len());
result
@@ -193,7 +179,7 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
&self,
environment: &chalk_ir::Environment<Interner>,
) -> chalk_ir::ProgramClauses<Interner> {
- self.db.program_clauses_for_chalk_env(self.krate, environment.clone())
+ self.db.program_clauses_for_chalk_env(self.krate, self.block, environment.clone())
}
fn opaque_ty_data(&self, id: chalk_ir::OpaqueTyId<Interner>) -> Arc<OpaqueTyDatum> {
@@ -451,9 +437,10 @@ impl<'a> chalk_ir::UnificationDatabase<Interner> for &'a dyn HirDatabase {
pub(crate) fn program_clauses_for_chalk_env_query(
db: &dyn HirDatabase,
krate: CrateId,
+ block: Option<BlockId>,
environment: chalk_ir::Environment<Interner>,
) -> chalk_ir::ProgramClauses<Interner> {
- chalk_solve::program_clauses_for_env(&ChalkContext { db, krate }, &environment)
+ chalk_solve::program_clauses_for_env(&ChalkContext { db, krate, block }, &environment)
}
pub(crate) fn associated_ty_data_query(
diff --git a/crates/hir-ty/src/db.rs b/crates/hir-ty/src/db.rs
index 000944e0b5..56f5d90bb3 100644
--- a/crates/hir-ty/src/db.rs
+++ b/crates/hir-ty/src/db.rs
@@ -129,7 +129,7 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
fn trait_impls_in_crate(&self, krate: CrateId) -> Arc<TraitImpls>;
#[salsa::invoke(TraitImpls::trait_impls_in_block_query)]
- fn trait_impls_in_block(&self, krate: BlockId) -> Option<Arc<TraitImpls>>;
+ fn trait_impls_in_block(&self, block: BlockId) -> Option<Arc<TraitImpls>>;
#[salsa::invoke(TraitImpls::trait_impls_in_deps_query)]
fn trait_impls_in_deps(&self, krate: CrateId) -> Arc<TraitImpls>;
@@ -197,6 +197,7 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
fn trait_solve(
&self,
krate: CrateId,
+ block: Option<BlockId>,
goal: crate::Canonical<crate::InEnvironment<crate::Goal>>,
) -> Option<crate::Solution>;
@@ -204,6 +205,7 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
fn trait_solve_query(
&self,
krate: CrateId,
+ block: Option<BlockId>,
goal: crate::Canonical<crate::InEnvironment<crate::Goal>>,
) -> Option<crate::Solution>;
@@ -211,6 +213,7 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
fn program_clauses_for_chalk_env(
&self,
krate: CrateId,
+ block: Option<BlockId>,
env: chalk_ir::Environment<Interner>,
) -> chalk_ir::ProgramClauses<Interner>;
}
@@ -232,10 +235,11 @@ fn infer_wait(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<InferenceResult>
fn trait_solve_wait(
db: &dyn HirDatabase,
krate: CrateId,
+ block: Option<BlockId>,
goal: crate::Canonical<crate::InEnvironment<crate::Goal>>,
) -> Option<crate::Solution> {
let _p = profile::span("trait_solve::wait");
- db.trait_solve_query(krate, goal)
+ db.trait_solve_query(krate, block, goal)
}
#[test]
diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs
index 38b7dee75f..493f45d40c 100644
--- a/crates/hir-ty/src/infer.rs
+++ b/crates/hir-ty/src/infer.rs
@@ -40,7 +40,7 @@ use crate::{
db::HirDatabase, fold_tys, fold_tys_and_consts, infer::coerce::CoerceMany,
lower::ImplTraitLoweringMode, static_lifetime, to_assoc_type_id, AliasEq, AliasTy, Const,
DomainGoal, GenericArg, Goal, ImplTraitId, InEnvironment, Interner, ProjectionTy, RpitId,
- Substitution, TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, TyKind,
+ Substitution, TraitRef, Ty, TyBuilder, TyExt, TyKind,
};
// This lint has a false positive here. See the link below for details.
@@ -442,7 +442,6 @@ pub(crate) struct InferenceContext<'a> {
pub(crate) body: &'a Body,
pub(crate) resolver: Resolver,
table: unify::InferenceTable<'a>,
- trait_env: Arc<TraitEnvironment>,
/// The traits in scope, disregarding block modules. This is used for caching purposes.
traits_in_scope: FxHashSet<TraitId>,
pub(crate) result: InferenceResult,
@@ -516,8 +515,7 @@ impl<'a> InferenceContext<'a> {
let trait_env = db.trait_environment_for_body(owner);
InferenceContext {
result: InferenceResult::default(),
- table: unify::InferenceTable::new(db, trait_env.clone()),
- trait_env,
+ table: unify::InferenceTable::new(db, trait_env),
return_ty: TyKind::Error.intern(Interner), // set in collect_* calls
resume_yield_tys: None,
return_coercion: None,
diff --git a/crates/hir-ty/src/infer/coerce.rs b/crates/hir-ty/src/infer/coerce.rs
index 6e899249b6..6bf9f421fc 100644
--- a/crates/hir-ty/src/infer/coerce.rs
+++ b/crates/hir-ty/src/infer/coerce.rs
@@ -636,7 +636,7 @@ impl<'a> InferenceTable<'a> {
// Need to find out in what cases this is necessary
let solution = self
.db
- .trait_solve(krate, canonicalized.value.clone().cast(Interner))
+ .trait_solve(krate, self.trait_env.block, canonicalized.value.clone().cast(Interner))
.ok_or(TypeError)?;
match solution {
diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs
index d52188bb28..ea44fa1857 100644
--- a/crates/hir-ty/src/infer/expr.rs
+++ b/crates/hir-ty/src/infer/expr.rs
@@ -3,6 +3,7 @@
use std::{
iter::{repeat, repeat_with},
mem,
+ sync::Arc,
};
use chalk_ir::{
@@ -15,7 +16,7 @@ use hir_def::{
generics::TypeOrConstParamData,
lang_item::LangItem,
path::{GenericArg, GenericArgs},
- ConstParamId, FieldId, ItemContainerId, Lookup,
+ BlockId, ConstParamId, FieldId, ItemContainerId, Lookup,
};
use hir_expand::name::{name, Name};
use stdx::always;
@@ -147,19 +148,19 @@ impl<'a> InferenceContext<'a> {
self.infer_top_pat(pat, &input_ty);
self.result.standard_types.bool_.clone()
}
- Expr::Block { statements, tail, label, id: _ } => {
- self.infer_block(tgt_expr, statements, *tail, *label, expected)
+ Expr::Block { statements, tail, label, id } => {
+ self.infer_block(tgt_expr, *id, statements, *tail, *label, expected)
}
- Expr::Unsafe { id: _, statements, tail } => {
- self.infer_block(tgt_expr, statements, *tail, None, expected)
+ Expr::Unsafe { id, statements, tail } => {
+ self.infer_block(tgt_expr, *id, statements, *tail, None, expected)
}
- Expr::Const { id: _, statements, tail } => {
+ Expr::Const { id, statements, tail } => {
self.with_breakable_ctx(BreakableKind::Border, None, None, |this| {
- this.infer_block(tgt_expr, statements, *tail, None, expected)
+ this.infer_block(tgt_expr, *id, statements, *tail, None, expected)
})
.1
}
- Expr::Async { id: _, statements, tail } => {
+ Expr::Async { id, statements, tail } => {
let ret_ty = self.table.new_type_var();
let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe);
let prev_ret_ty = mem::replace(&mut self.return_ty, ret_ty.clone());
@@ -170,6 +171,7 @@ impl<'a> InferenceContext<'a> {
self.with_breakable_ctx(BreakableKind::Border, None, None, |this| {
this.infer_block(
tgt_expr,
+ *id,
statements,
*tail,
None,
@@ -394,7 +396,7 @@ impl<'a> InferenceContext<'a> {
}
}
let trait_ = fn_x
- .get_id(self.db, self.trait_env.krate)
+ .get_id(self.db, self.table.trait_env.krate)
.expect("We just used it");
let trait_data = self.db.trait_data(trait_);
if let Some(func) = trait_data.method_by_name(&fn_x.method_name()) {
@@ -787,7 +789,7 @@ impl<'a> InferenceContext<'a> {
let canonicalized = self.canonicalize(base_ty.clone());
let receiver_adjustments = method_resolution::resolve_indexing_op(
self.db,
- self.trait_env.clone(),
+ self.table.trait_env.clone(),
canonicalized.value,
index_trait,
);
@@ -1205,6 +1207,7 @@ impl<'a> InferenceContext<'a> {
fn infer_block(
&mut self,
expr: ExprId,
+ block_id: Option<BlockId>,
statements: &[Statement],
tail: Option<ExprId>,
label: Option<LabelId>,
@@ -1212,6 +1215,11 @@ impl<'a> InferenceContext<'a> {
) -> Ty {
let coerce_ty = expected.coercion_target_type(&mut self.table);
let g = self.resolver.update_to_inner_scope(self.db.upcast(), self.owner, expr);
+ let prev_env = block_id.map(|block_id| {
+ let prev_env = self.table.trait_env.clone();
+ Arc::make_mut(&mut self.table.trait_env).block = Some(block_id);
+ prev_env
+ });
let (break_ty, ty) =
self.with_breakable_ctx(BreakableKind::Block, Some(coerce_ty.clone()), label, |this| {
@@ -1300,6 +1308,9 @@ impl<'a> InferenceContext<'a> {
}
});
self.resolver.reset_to_guard(g);
+ if let Some(prev_env) = prev_env {
+ self.table.trait_env = prev_env;
+ }
break_ty.unwrap_or(ty)
}
@@ -1398,7 +1409,7 @@ impl<'a> InferenceContext<'a> {
method_resolution::lookup_method(
self.db,
&canonicalized_receiver.value,
- self.trait_env.clone(),
+ self.table.trait_env.clone(),
self.get_traits_in_scope().as_ref().left_or_else(|&it| it),
VisibleFromModule::Filter(self.resolver.module()),
name,
@@ -1431,7 +1442,7 @@ impl<'a> InferenceContext<'a> {
let resolved = method_resolution::lookup_method(
self.db,
&canonicalized_receiver.value,
- self.trait_env.clone(),
+ self.table.trait_env.clone(),
self.get_traits_in_scope().as_ref().left_or_else(|&it| it),
VisibleFromModule::Filter(self.resolver.module()),
method_name,
diff --git a/crates/hir-ty/src/infer/unify.rs b/crates/hir-ty/src/infer/unify.rs
index 0e516b9399..f0e0714e1d 100644
--- a/crates/hir-ty/src/infer/unify.rs
+++ b/crates/hir-ty/src/infer/unify.rs
@@ -462,7 +462,8 @@ impl<'a> InferenceTable<'a> {
pub(crate) fn try_obligation(&mut self, goal: Goal) -> Option<Solution> {
let in_env = InEnvironment::new(&self.trait_env.env, goal);
let canonicalized = self.canonicalize(in_env);
- let solution = self.db.trait_solve(self.trait_env.krate, canonicalized.value);
+ let solution =
+ self.db.trait_solve(self.trait_env.krate, self.trait_env.block, canonicalized.value);
solution
}
@@ -597,7 +598,11 @@ impl<'a> InferenceTable<'a> {
&mut self,
canonicalized: &Canonicalized<InEnvironment<Goal>>,
) -> bool {
- let solution = self.db.trait_solve(self.trait_env.krate, canonicalized.value.clone());
+ let solution = self.db.trait_solve(
+ self.trait_env.krate,
+ self.trait_env.block,
+ canonicalized.value.clone(),
+ );
match solution {
Some(Solution::Unique(canonical_subst)) => {
@@ -684,7 +689,11 @@ impl<'a> InferenceTable<'a> {
environment: trait_env.clone(),
};
let canonical = self.canonicalize(obligation.clone());
- if self.db.trait_solve(krate, canonical.value.cast(Interner)).is_some() {
+ if self
+ .db
+ .trait_solve(krate, self.trait_env.block, canonical.value.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] {
@@ -695,7 +704,11 @@ impl<'a> InferenceTable<'a> {
environment: trait_env.clone(),
};
let canonical = self.canonicalize(obligation.clone());
- if self.db.trait_solve(krate, canonical.value.cast(Interner)).is_some() {
+ if self
+ .db
+ .trait_solve(krate, self.trait_env.block, canonical.value.cast(Interner))
+ .is_some()
+ {
return Some((fn_x, arg_tys, return_ty));
}
}
diff --git a/crates/hir-ty/src/lib.rs b/crates/hir-ty/src/lib.rs
index 782a8ab4aa..54bbda2ba0 100644
--- a/crates/hir-ty/src/lib.rs
+++ b/crates/hir-ty/src/lib.rs
@@ -1,6 +1,5 @@
//! The type system. We currently use this to infer types for completion, hover
//! information and various assists.
-
#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)]
#[allow(unused)]
diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs
index e7490087e7..797e9ad0e9 100644
--- a/crates/hir-ty/src/lower.rs
+++ b/crates/hir-ty/src/lower.rs
@@ -1507,7 +1507,7 @@ pub(crate) fn trait_environment_query(
let env = chalk_ir::Environment::new(Interner).add_clauses(Interner, clauses);
- Arc::new(TraitEnvironment { krate, traits_from_clauses: traits_in_scope, env })
+ Arc::new(TraitEnvironment { krate, block: None, traits_from_clauses: traits_in_scope, env })
}
/// Resolve the where clause(s) of an item with generics.
diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs
index 2003d24038..94c0d3c0c1 100644
--- a/crates/hir-ty/src/method_resolution.rs
+++ b/crates/hir-ty/src/method_resolution.rs
@@ -271,6 +271,7 @@ pub struct InherentImpls {
impl InherentImpls {
pub(crate) fn inherent_impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<Self> {
+ let _p = profile::span("inherent_impls_in_crate_query").detail(|| format!("{krate:?}"));
let mut impls = Self { map: FxHashMap::default(), invalid_impls: Vec::default() };
let crate_def_map = db.crate_def_map(krate);
@@ -284,13 +285,14 @@ impl InherentImpls {
db: &dyn HirDatabase,
block: BlockId,
) -> Option<Arc<Self>> {
+ let _p = profile::span("inherent_impls_in_block_query");
let mut impls = Self { map: FxHashMap::default(), invalid_impls: Vec::default() };
- if let Some(block_def_map) = db.block_def_map(block) {
- impls.collect_def_map(db, &block_def_map);
- impls.shrink_to_fit();
- return Some(Arc::new(impls));
- }
- None
+
+ let block_def_map = db.block_def_map(block)?;
+ impls.collect_def_map(db, &block_def_map);
+ impls.shrink_to_fit();
+
+ Some(Arc::new(impls))
}
fn shrink_to_fit(&mut self) {
@@ -1140,7 +1142,7 @@ fn iterate_trait_method_candidates(
};
if !known_implemented {
let goal = generic_implements_goal(db, env.clone(), t, &canonical_self_ty);
- if db.trait_solve(env.krate, goal.cast(Interner)).is_none() {
+ if db.trait_solve(env.krate, env.block, goal.cast(Interner)).is_none() {
continue 'traits;
}
}
@@ -1317,7 +1319,7 @@ pub fn resolve_indexing_op(
let deref_chain = autoderef_method_receiver(&mut table, ty);
for (ty, adj) in deref_chain {
let goal = generic_implements_goal(db, env.clone(), index_trait, &ty);
- if db.trait_solve(env.krate, goal.cast(Interner)).is_some() {
+ if db.trait_solve(env.krate, env.block, goal.cast(Interner)).is_some() {
return Some(adj);
}
}
@@ -1342,14 +1344,12 @@ fn is_valid_candidate(
) -> IsValidCandidate {
let db = table.db;
match item {
- AssocItemId::FunctionId(m) => {
- is_valid_fn_candidate(table, m, name, receiver_ty, self_ty, visible_from_module)
+ AssocItemId::FunctionId(f) => {
+ is_valid_fn_candidate(table, f, name, receiver_ty, self_ty, visible_from_module)
}
AssocItemId::ConstId(c) => {
- let data = db.const_data(c);
check_that!(receiver_ty.is_none());
-
- check_that!(name.map_or(true, |n| data.name.as_ref() == Some(n)));
+ check_that!(name.map_or(true, |n| db.const_data(c).name.as_ref() == Some(n)));
if let Some(from_module) = visible_from_module {
if !db.const_visibility(c).is_visible_from(db.upcast(), from_module) {
@@ -1473,7 +1473,7 @@ pub fn implements_trait(
trait_: TraitId,
) -> bool {
let goal = generic_implements_goal(db, env.clone(), trait_, ty);
- let solution = db.trait_solve(env.krate, goal.cast(Interner));
+ let solution = db.trait_solve(env.krate, env.block, goal.cast(Interner));
solution.is_some()
}
@@ -1485,7 +1485,7 @@ pub fn implements_trait_unique(
trait_: TraitId,
) -> bool {
let goal = generic_implements_goal(db, env.clone(), trait_, ty);
- let solution = db.trait_solve(env.krate, goal.cast(Interner));
+ let solution = db.trait_solve(env.krate, env.block, goal.cast(Interner));
matches!(solution, Some(crate::Solution::Unique(_)))
}
diff --git a/crates/hir-ty/src/tests/traits.rs b/crates/hir-ty/src/tests/traits.rs
index 97ec1bb871..e9c26bf473 100644
--- a/crates/hir-ty/src/tests/traits.rs
+++ b/crates/hir-ty/src/tests/traits.rs
@@ -3717,7 +3717,6 @@ async fn get_accounts() -> Result<u32, ()> {
#[test]
fn local_impl_1() {
- check!(block_local_impls);
check_types(
r#"
trait Trait<T> {
@@ -3739,7 +3738,6 @@ fn test() {
#[test]
fn local_impl_2() {
- check!(block_local_impls);
check_types(
r#"
struct S;
@@ -3761,7 +3759,6 @@ fn test() {
#[test]
fn local_impl_3() {
- check!(block_local_impls);
check_types(
r#"
trait Trait<T> {
@@ -3786,6 +3783,33 @@ fn test() {
}
#[test]
+fn foreign_trait_with_local_trait_impl() {
+ check!(block_local_impls);
+ check(
+ r#"
+mod module {
+ pub trait T {
+ const C: usize;
+ fn f(&self);
+ }
+}
+
+fn f() {
+ use module::T;
+ impl T for usize {
+ const C: usize = 0;
+ fn f(&self) {}
+ }
+ 0usize.f();
+ //^^^^^^^^^^ type: ()
+ usize::C;
+ //^^^^^^^^type: usize
+}
+"#,
+ );
+}
+
+#[test]
fn associated_type_sized_bounds() {
check_infer(
r#"
diff --git a/crates/hir-ty/src/traits.rs b/crates/hir-ty/src/traits.rs
index e7fffc4cc7..deb6ce5677 100644
--- a/crates/hir-ty/src/traits.rs
+++ b/crates/hir-ty/src/traits.rs
@@ -9,7 +9,7 @@ use chalk_solve::{logging_db::LoggingRustIrDatabase, Solver};
use base_db::CrateId;
use hir_def::{
lang_item::{LangItem, LangItemTarget},
- TraitId,
+ BlockId, TraitId,
};
use hir_expand::name::{name, Name};
use stdx::panic_context;
@@ -27,6 +27,7 @@ const CHALK_SOLVER_FUEL: i32 = 1000;
pub(crate) struct ChalkContext<'a> {
pub(crate) db: &'a dyn HirDatabase,
pub(crate) krate: CrateId,
+ pub(crate) block: Option<BlockId>,
}
fn create_chalk_solver() -> chalk_recursive::RecursiveSolver<Interner> {
@@ -44,6 +45,7 @@ fn create_chalk_solver() -> chalk_recursive::RecursiveSolver<Interner> {
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct TraitEnvironment {
pub krate: CrateId,
+ pub block: Option<BlockId>,
// FIXME make this a BTreeMap
pub(crate) traits_from_clauses: Vec<(Ty, TraitId)>,
pub env: chalk_ir::Environment<Interner>,
@@ -53,6 +55,7 @@ impl TraitEnvironment {
pub fn empty(krate: CrateId) -> Self {
TraitEnvironment {
krate,
+ block: None,
traits_from_clauses: Vec::new(),
env: chalk_ir::Environment::new(Interner),
}
@@ -79,6 +82,7 @@ pub(crate) fn normalize_projection_query(
pub(crate) fn trait_solve_query(
db: &dyn HirDatabase,
krate: CrateId,
+ block: Option<BlockId>,
goal: Canonical<InEnvironment<Goal>>,
) -> Option<Solution> {
let _p = profile::span("trait_solve_query").detail(|| match &goal.value.goal.data(Interner) {
@@ -104,15 +108,16 @@ pub(crate) fn trait_solve_query(
// We currently don't deal with universes (I think / hope they're not yet
// relevant for our use cases?)
let u_canonical = chalk_ir::UCanonical { canonical: goal, universes: 1 };
- solve(db, krate, &u_canonical)
+ solve(db, krate, block, &u_canonical)
}
fn solve(
db: &dyn HirDatabase,
krate: CrateId,
+ block: Option<BlockId>,
goal: &chalk_ir::UCanonical<chalk_ir::InEnvironment<chalk_ir::Goal<Interner>>>,
) -> Option<chalk_solve::Solution<Interner>> {
- let context = ChalkContext { db, krate };
+ let context = ChalkContext { db, krate, block };
tracing::debug!("solve goal: {:?}", goal);
let mut solver = create_chalk_solver();
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index dbf618afa6..ea851a11a8 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -3331,7 +3331,7 @@ impl Type {
binders: CanonicalVarKinds::empty(Interner),
};
- db.trait_solve(self.env.krate, goal).is_some()
+ db.trait_solve(self.env.krate, self.env.block, goal).is_some()
}
pub fn normalize_trait_assoc_type(