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.
This commit is contained in:
bors 2023-03-28 06:36:35 +00:00
commit f73510560f
13 changed files with 138 additions and 95 deletions

View file

@ -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 /// The `block_def_map` for block 0 would return `None`, while `block_def_map` of block 1 would
/// return a `DefMap` containing `inner`. /// 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)] #[salsa::invoke(DefMap::block_def_map_query)]
fn block_def_map(&self, block: BlockId) -> Option<Arc<DefMap>>; fn block_def_map(&self, block: BlockId) -> Option<Arc<DefMap>>;

View file

@ -1,8 +1,7 @@
//! The implementation of `RustIrDatabase` for Chalk, which provides information //! The implementation of `RustIrDatabase` for Chalk, which provides information
//! about the code that Chalk needs. //! about the code that Chalk needs.
use std::sync::Arc; use std::{iter, sync::Arc};
use cov_mark::hit;
use tracing::debug; use tracing::debug;
use chalk_ir::{cast::Cast, fold::shift::Shift, CanonicalVarKinds}; use chalk_ir::{cast::Cast, fold::shift::Shift, CanonicalVarKinds};
@ -12,17 +11,16 @@ use base_db::CrateId;
use hir_def::{ use hir_def::{
expr::Movability, expr::Movability,
lang_item::{lang_attr, LangItem, LangItemTarget}, 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 hir_expand::name::name;
use crate::{ use crate::{
db::HirDatabase, db::HirDatabase,
display::HirDisplay, display::HirDisplay,
from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, make_binders, from_assoc_type_id, from_chalk_trait_id, make_binders, make_single_type_binders,
make_single_type_binders,
mapping::{from_chalk, ToChalk, TypeAliasAsValue}, 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, to_assoc_type_id, to_chalk_trait_id,
traits::ChalkContext, traits::ChalkContext,
utils::generics, 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(&[]), _ => 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 // 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 // can be resolved should ever reach Chalk. impl_datum relies on that
// and will panic if the trait can't be resolved. // and will panic if the trait can't be resolved.
let in_deps = self.db.trait_impls_in_deps(self.krate); let in_deps = self.db.trait_impls_in_deps(self.krate);
let in_self = self.db.trait_impls_in_crate(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 { let impl_maps = [in_deps, in_self];
Some(TyFingerprint::Adt(adt_id)) => Some(adt_id.module(self.db.upcast())), let block_impls = iter::successors(self.block, |&block_id| {
Some(TyFingerprint::ForeignType(type_id)) => { cov_mark::hit!(block_local_impls);
Some(from_foreign_def_id(type_id).module(self.db.upcast())) self.db
} .block_def_map(block_id)
Some(TyFingerprint::Dyn(trait_id)) => Some(trait_id.module(self.db.upcast())), .and_then(|map| map.parent())
_ => None, .and_then(|module| module.containing_block())
}; })
let impl_maps = [ .filter_map(|block_id| self.db.trait_impls_in_block(block_id));
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 id_to_chalk = |id: hir_def::ImplId| id.to_chalk(self.db);
let mut result = vec![];
let result: Vec<_> = if fps.is_empty() { match fps {
debug!("Unrestricted search for {:?} impls...", trait_); [] => {
impl_maps debug!("Unrestricted search for {:?} impls...", trait_);
.iter() impl_maps.into_iter().chain(block_impls).for_each(|impls| {
.filter_map(|o| o.as_ref()) result.extend(impls.for_trait(trait_).map(id_to_chalk));
.flat_map(|impls| impls.for_trait(trait_).map(id_to_chalk)) });
.collect() }
} else { fps => {
impl_maps impl_maps.into_iter().chain(block_impls).for_each(|impls| {
.iter() result.extend(
.filter_map(|o| o.as_ref()) fps.iter().flat_map(|fp| {
.flat_map(|impls| { impls.for_trait_and_self_ty(trait_, *fp).map(id_to_chalk)
fps.iter().flat_map(move |fp| { }),
impls.for_trait_and_self_ty(trait_, *fp).map(id_to_chalk) );
}) });
}) }
.collect() }
};
debug!("impls_for_trait returned {} impls", result.len()); debug!("impls_for_trait returned {} impls", result.len());
result result
@ -193,7 +179,7 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
&self, &self,
environment: &chalk_ir::Environment<Interner>, environment: &chalk_ir::Environment<Interner>,
) -> chalk_ir::ProgramClauses<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> { 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( pub(crate) fn program_clauses_for_chalk_env_query(
db: &dyn HirDatabase, db: &dyn HirDatabase,
krate: CrateId, krate: CrateId,
block: Option<BlockId>,
environment: chalk_ir::Environment<Interner>, environment: chalk_ir::Environment<Interner>,
) -> chalk_ir::ProgramClauses<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( pub(crate) fn associated_ty_data_query(

View file

@ -129,7 +129,7 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
fn trait_impls_in_crate(&self, krate: CrateId) -> Arc<TraitImpls>; fn trait_impls_in_crate(&self, krate: CrateId) -> Arc<TraitImpls>;
#[salsa::invoke(TraitImpls::trait_impls_in_block_query)] #[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)] #[salsa::invoke(TraitImpls::trait_impls_in_deps_query)]
fn trait_impls_in_deps(&self, krate: CrateId) -> Arc<TraitImpls>; fn trait_impls_in_deps(&self, krate: CrateId) -> Arc<TraitImpls>;
@ -197,6 +197,7 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
fn trait_solve( fn trait_solve(
&self, &self,
krate: CrateId, krate: CrateId,
block: Option<BlockId>,
goal: crate::Canonical<crate::InEnvironment<crate::Goal>>, goal: crate::Canonical<crate::InEnvironment<crate::Goal>>,
) -> Option<crate::Solution>; ) -> Option<crate::Solution>;
@ -204,6 +205,7 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
fn trait_solve_query( fn trait_solve_query(
&self, &self,
krate: CrateId, krate: CrateId,
block: Option<BlockId>,
goal: crate::Canonical<crate::InEnvironment<crate::Goal>>, goal: crate::Canonical<crate::InEnvironment<crate::Goal>>,
) -> Option<crate::Solution>; ) -> Option<crate::Solution>;
@ -211,6 +213,7 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
fn program_clauses_for_chalk_env( fn program_clauses_for_chalk_env(
&self, &self,
krate: CrateId, krate: CrateId,
block: Option<BlockId>,
env: chalk_ir::Environment<Interner>, env: chalk_ir::Environment<Interner>,
) -> chalk_ir::ProgramClauses<Interner>; ) -> chalk_ir::ProgramClauses<Interner>;
} }
@ -232,10 +235,11 @@ fn infer_wait(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<InferenceResult>
fn trait_solve_wait( fn trait_solve_wait(
db: &dyn HirDatabase, db: &dyn HirDatabase,
krate: CrateId, krate: CrateId,
block: Option<BlockId>,
goal: crate::Canonical<crate::InEnvironment<crate::Goal>>, goal: crate::Canonical<crate::InEnvironment<crate::Goal>>,
) -> Option<crate::Solution> { ) -> Option<crate::Solution> {
let _p = profile::span("trait_solve::wait"); let _p = profile::span("trait_solve::wait");
db.trait_solve_query(krate, goal) db.trait_solve_query(krate, block, goal)
} }
#[test] #[test]

View file

@ -40,7 +40,7 @@ use crate::{
db::HirDatabase, fold_tys, fold_tys_and_consts, infer::coerce::CoerceMany, db::HirDatabase, fold_tys, fold_tys_and_consts, infer::coerce::CoerceMany,
lower::ImplTraitLoweringMode, static_lifetime, to_assoc_type_id, AliasEq, AliasTy, Const, lower::ImplTraitLoweringMode, static_lifetime, to_assoc_type_id, AliasEq, AliasTy, Const,
DomainGoal, GenericArg, Goal, ImplTraitId, InEnvironment, Interner, ProjectionTy, RpitId, 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. // 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) body: &'a Body,
pub(crate) resolver: Resolver, pub(crate) resolver: Resolver,
table: unify::InferenceTable<'a>, table: unify::InferenceTable<'a>,
trait_env: Arc<TraitEnvironment>,
/// The traits in scope, disregarding block modules. This is used for caching purposes. /// The traits in scope, disregarding block modules. This is used for caching purposes.
traits_in_scope: FxHashSet<TraitId>, traits_in_scope: FxHashSet<TraitId>,
pub(crate) result: InferenceResult, pub(crate) result: InferenceResult,
@ -516,8 +515,7 @@ impl<'a> InferenceContext<'a> {
let trait_env = db.trait_environment_for_body(owner); let trait_env = db.trait_environment_for_body(owner);
InferenceContext { InferenceContext {
result: InferenceResult::default(), result: InferenceResult::default(),
table: unify::InferenceTable::new(db, trait_env.clone()), table: unify::InferenceTable::new(db, trait_env),
trait_env,
return_ty: TyKind::Error.intern(Interner), // set in collect_* calls return_ty: TyKind::Error.intern(Interner), // set in collect_* calls
resume_yield_tys: None, resume_yield_tys: None,
return_coercion: None, return_coercion: None,

View file

@ -636,7 +636,7 @@ impl<'a> InferenceTable<'a> {
// Need to find out in what cases this is necessary // Need to find out in what cases this is necessary
let solution = self let solution = self
.db .db
.trait_solve(krate, canonicalized.value.clone().cast(Interner)) .trait_solve(krate, self.trait_env.block, canonicalized.value.clone().cast(Interner))
.ok_or(TypeError)?; .ok_or(TypeError)?;
match solution { match solution {

View file

@ -3,6 +3,7 @@
use std::{ use std::{
iter::{repeat, repeat_with}, iter::{repeat, repeat_with},
mem, mem,
sync::Arc,
}; };
use chalk_ir::{ use chalk_ir::{
@ -15,7 +16,7 @@ use hir_def::{
generics::TypeOrConstParamData, generics::TypeOrConstParamData,
lang_item::LangItem, lang_item::LangItem,
path::{GenericArg, GenericArgs}, path::{GenericArg, GenericArgs},
ConstParamId, FieldId, ItemContainerId, Lookup, BlockId, ConstParamId, FieldId, ItemContainerId, Lookup,
}; };
use hir_expand::name::{name, Name}; use hir_expand::name::{name, Name};
use stdx::always; use stdx::always;
@ -147,19 +148,19 @@ impl<'a> InferenceContext<'a> {
self.infer_top_pat(pat, &input_ty); self.infer_top_pat(pat, &input_ty);
self.result.standard_types.bool_.clone() self.result.standard_types.bool_.clone()
} }
Expr::Block { statements, tail, label, id: _ } => { Expr::Block { statements, tail, label, id } => {
self.infer_block(tgt_expr, statements, *tail, *label, expected) self.infer_block(tgt_expr, *id, statements, *tail, *label, expected)
} }
Expr::Unsafe { id: _, statements, tail } => { Expr::Unsafe { id, statements, tail } => {
self.infer_block(tgt_expr, statements, *tail, None, expected) 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| { 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 .1
} }
Expr::Async { id: _, statements, tail } => { Expr::Async { id, statements, tail } => {
let ret_ty = self.table.new_type_var(); let ret_ty = self.table.new_type_var();
let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe); let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe);
let prev_ret_ty = mem::replace(&mut self.return_ty, ret_ty.clone()); 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| { self.with_breakable_ctx(BreakableKind::Border, None, None, |this| {
this.infer_block( this.infer_block(
tgt_expr, tgt_expr,
*id,
statements, statements,
*tail, *tail,
None, None,
@ -394,7 +396,7 @@ impl<'a> InferenceContext<'a> {
} }
} }
let trait_ = fn_x 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"); .expect("We just used it");
let trait_data = self.db.trait_data(trait_); let trait_data = self.db.trait_data(trait_);
if let Some(func) = trait_data.method_by_name(&fn_x.method_name()) { 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 canonicalized = self.canonicalize(base_ty.clone());
let receiver_adjustments = method_resolution::resolve_indexing_op( let receiver_adjustments = method_resolution::resolve_indexing_op(
self.db, self.db,
self.trait_env.clone(), self.table.trait_env.clone(),
canonicalized.value, canonicalized.value,
index_trait, index_trait,
); );
@ -1205,6 +1207,7 @@ impl<'a> InferenceContext<'a> {
fn infer_block( fn infer_block(
&mut self, &mut self,
expr: ExprId, expr: ExprId,
block_id: Option<BlockId>,
statements: &[Statement], statements: &[Statement],
tail: Option<ExprId>, tail: Option<ExprId>,
label: Option<LabelId>, label: Option<LabelId>,
@ -1212,6 +1215,11 @@ impl<'a> InferenceContext<'a> {
) -> Ty { ) -> Ty {
let coerce_ty = expected.coercion_target_type(&mut self.table); 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 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) = let (break_ty, ty) =
self.with_breakable_ctx(BreakableKind::Block, Some(coerce_ty.clone()), label, |this| { 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); self.resolver.reset_to_guard(g);
if let Some(prev_env) = prev_env {
self.table.trait_env = prev_env;
}
break_ty.unwrap_or(ty) break_ty.unwrap_or(ty)
} }
@ -1398,7 +1409,7 @@ impl<'a> InferenceContext<'a> {
method_resolution::lookup_method( method_resolution::lookup_method(
self.db, self.db,
&canonicalized_receiver.value, &canonicalized_receiver.value,
self.trait_env.clone(), self.table.trait_env.clone(),
self.get_traits_in_scope().as_ref().left_or_else(|&it| it), self.get_traits_in_scope().as_ref().left_or_else(|&it| it),
VisibleFromModule::Filter(self.resolver.module()), VisibleFromModule::Filter(self.resolver.module()),
name, name,
@ -1431,7 +1442,7 @@ impl<'a> InferenceContext<'a> {
let resolved = method_resolution::lookup_method( let resolved = method_resolution::lookup_method(
self.db, self.db,
&canonicalized_receiver.value, &canonicalized_receiver.value,
self.trait_env.clone(), self.table.trait_env.clone(),
self.get_traits_in_scope().as_ref().left_or_else(|&it| it), self.get_traits_in_scope().as_ref().left_or_else(|&it| it),
VisibleFromModule::Filter(self.resolver.module()), VisibleFromModule::Filter(self.resolver.module()),
method_name, method_name,

View file

@ -462,7 +462,8 @@ impl<'a> InferenceTable<'a> {
pub(crate) fn try_obligation(&mut self, goal: Goal) -> Option<Solution> { pub(crate) fn try_obligation(&mut self, goal: Goal) -> Option<Solution> {
let in_env = InEnvironment::new(&self.trait_env.env, goal); let in_env = InEnvironment::new(&self.trait_env.env, goal);
let canonicalized = self.canonicalize(in_env); 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 solution
} }
@ -597,7 +598,11 @@ impl<'a> InferenceTable<'a> {
&mut self, &mut self,
canonicalized: &Canonicalized<InEnvironment<Goal>>, canonicalized: &Canonicalized<InEnvironment<Goal>>,
) -> bool { ) -> 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 { match solution {
Some(Solution::Unique(canonical_subst)) => { Some(Solution::Unique(canonical_subst)) => {
@ -684,7 +689,11 @@ impl<'a> InferenceTable<'a> {
environment: trait_env.clone(), environment: trait_env.clone(),
}; };
let canonical = self.canonicalize(obligation.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); self.register_obligation(obligation.goal);
let return_ty = self.normalize_projection_ty(projection); let return_ty = self.normalize_projection_ty(projection);
for fn_x in [FnTrait::Fn, FnTrait::FnMut, FnTrait::FnOnce] { for fn_x in [FnTrait::Fn, FnTrait::FnMut, FnTrait::FnOnce] {
@ -695,7 +704,11 @@ impl<'a> InferenceTable<'a> {
environment: trait_env.clone(), environment: trait_env.clone(),
}; };
let canonical = self.canonicalize(obligation.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)); return Some((fn_x, arg_tys, return_ty));
} }
} }

View file

@ -1,6 +1,5 @@
//! The type system. We currently use this to infer types for completion, hover //! The type system. We currently use this to infer types for completion, hover
//! information and various assists. //! information and various assists.
#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)] #![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)]
#[allow(unused)] #[allow(unused)]

View file

@ -1507,7 +1507,7 @@ pub(crate) fn trait_environment_query(
let env = chalk_ir::Environment::new(Interner).add_clauses(Interner, clauses); 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. /// Resolve the where clause(s) of an item with generics.

View file

@ -271,6 +271,7 @@ pub struct InherentImpls {
impl InherentImpls { impl InherentImpls {
pub(crate) fn inherent_impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<Self> { 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 mut impls = Self { map: FxHashMap::default(), invalid_impls: Vec::default() };
let crate_def_map = db.crate_def_map(krate); let crate_def_map = db.crate_def_map(krate);
@ -284,13 +285,14 @@ impl InherentImpls {
db: &dyn HirDatabase, db: &dyn HirDatabase,
block: BlockId, block: BlockId,
) -> Option<Arc<Self>> { ) -> Option<Arc<Self>> {
let _p = profile::span("inherent_impls_in_block_query");
let mut impls = Self { map: FxHashMap::default(), invalid_impls: Vec::default() }; 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); let block_def_map = db.block_def_map(block)?;
impls.shrink_to_fit(); impls.collect_def_map(db, &block_def_map);
return Some(Arc::new(impls)); impls.shrink_to_fit();
}
None Some(Arc::new(impls))
} }
fn shrink_to_fit(&mut self) { fn shrink_to_fit(&mut self) {
@ -1140,7 +1142,7 @@ fn iterate_trait_method_candidates(
}; };
if !known_implemented { if !known_implemented {
let goal = generic_implements_goal(db, env.clone(), t, &canonical_self_ty); 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; continue 'traits;
} }
} }
@ -1317,7 +1319,7 @@ pub fn resolve_indexing_op(
let deref_chain = autoderef_method_receiver(&mut table, ty); let deref_chain = autoderef_method_receiver(&mut table, ty);
for (ty, adj) in deref_chain { for (ty, adj) in deref_chain {
let goal = generic_implements_goal(db, env.clone(), index_trait, &ty); 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); return Some(adj);
} }
} }
@ -1342,14 +1344,12 @@ fn is_valid_candidate(
) -> IsValidCandidate { ) -> IsValidCandidate {
let db = table.db; let db = table.db;
match item { match item {
AssocItemId::FunctionId(m) => { AssocItemId::FunctionId(f) => {
is_valid_fn_candidate(table, m, name, receiver_ty, self_ty, visible_from_module) is_valid_fn_candidate(table, f, name, receiver_ty, self_ty, visible_from_module)
} }
AssocItemId::ConstId(c) => { AssocItemId::ConstId(c) => {
let data = db.const_data(c);
check_that!(receiver_ty.is_none()); check_that!(receiver_ty.is_none());
check_that!(name.map_or(true, |n| db.const_data(c).name.as_ref() == Some(n)));
check_that!(name.map_or(true, |n| data.name.as_ref() == Some(n)));
if let Some(from_module) = visible_from_module { if let Some(from_module) = visible_from_module {
if !db.const_visibility(c).is_visible_from(db.upcast(), from_module) { if !db.const_visibility(c).is_visible_from(db.upcast(), from_module) {
@ -1473,7 +1473,7 @@ pub fn implements_trait(
trait_: TraitId, trait_: TraitId,
) -> bool { ) -> bool {
let goal = generic_implements_goal(db, env.clone(), trait_, ty); 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() solution.is_some()
} }
@ -1485,7 +1485,7 @@ pub fn implements_trait_unique(
trait_: TraitId, trait_: TraitId,
) -> bool { ) -> bool {
let goal = generic_implements_goal(db, env.clone(), trait_, ty); 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(_))) matches!(solution, Some(crate::Solution::Unique(_)))
} }

View file

@ -3717,7 +3717,6 @@ async fn get_accounts() -> Result<u32, ()> {
#[test] #[test]
fn local_impl_1() { fn local_impl_1() {
check!(block_local_impls);
check_types( check_types(
r#" r#"
trait Trait<T> { trait Trait<T> {
@ -3739,7 +3738,6 @@ fn test() {
#[test] #[test]
fn local_impl_2() { fn local_impl_2() {
check!(block_local_impls);
check_types( check_types(
r#" r#"
struct S; struct S;
@ -3761,7 +3759,6 @@ fn test() {
#[test] #[test]
fn local_impl_3() { fn local_impl_3() {
check!(block_local_impls);
check_types( check_types(
r#" r#"
trait Trait<T> { trait Trait<T> {
@ -3785,6 +3782,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] #[test]
fn associated_type_sized_bounds() { fn associated_type_sized_bounds() {
check_infer( check_infer(

View file

@ -9,7 +9,7 @@ use chalk_solve::{logging_db::LoggingRustIrDatabase, Solver};
use base_db::CrateId; use base_db::CrateId;
use hir_def::{ use hir_def::{
lang_item::{LangItem, LangItemTarget}, lang_item::{LangItem, LangItemTarget},
TraitId, BlockId, TraitId,
}; };
use hir_expand::name::{name, Name}; use hir_expand::name::{name, Name};
use stdx::panic_context; use stdx::panic_context;
@ -27,6 +27,7 @@ const CHALK_SOLVER_FUEL: i32 = 1000;
pub(crate) struct ChalkContext<'a> { pub(crate) struct ChalkContext<'a> {
pub(crate) db: &'a dyn HirDatabase, pub(crate) db: &'a dyn HirDatabase,
pub(crate) krate: CrateId, pub(crate) krate: CrateId,
pub(crate) block: Option<BlockId>,
} }
fn create_chalk_solver() -> chalk_recursive::RecursiveSolver<Interner> { 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)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct TraitEnvironment { pub struct TraitEnvironment {
pub krate: CrateId, pub krate: CrateId,
pub block: Option<BlockId>,
// FIXME make this a BTreeMap // FIXME make this a BTreeMap
pub(crate) traits_from_clauses: Vec<(Ty, TraitId)>, pub(crate) traits_from_clauses: Vec<(Ty, TraitId)>,
pub env: chalk_ir::Environment<Interner>, pub env: chalk_ir::Environment<Interner>,
@ -53,6 +55,7 @@ impl TraitEnvironment {
pub fn empty(krate: CrateId) -> Self { pub fn empty(krate: CrateId) -> Self {
TraitEnvironment { TraitEnvironment {
krate, krate,
block: None,
traits_from_clauses: Vec::new(), traits_from_clauses: Vec::new(),
env: chalk_ir::Environment::new(Interner), env: chalk_ir::Environment::new(Interner),
} }
@ -79,6 +82,7 @@ pub(crate) fn normalize_projection_query(
pub(crate) fn trait_solve_query( pub(crate) fn trait_solve_query(
db: &dyn HirDatabase, db: &dyn HirDatabase,
krate: CrateId, krate: CrateId,
block: Option<BlockId>,
goal: Canonical<InEnvironment<Goal>>, goal: Canonical<InEnvironment<Goal>>,
) -> Option<Solution> { ) -> Option<Solution> {
let _p = profile::span("trait_solve_query").detail(|| match &goal.value.goal.data(Interner) { 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 // We currently don't deal with universes (I think / hope they're not yet
// relevant for our use cases?) // relevant for our use cases?)
let u_canonical = chalk_ir::UCanonical { canonical: goal, universes: 1 }; let u_canonical = chalk_ir::UCanonical { canonical: goal, universes: 1 };
solve(db, krate, &u_canonical) solve(db, krate, block, &u_canonical)
} }
fn solve( fn solve(
db: &dyn HirDatabase, db: &dyn HirDatabase,
krate: CrateId, krate: CrateId,
block: Option<BlockId>,
goal: &chalk_ir::UCanonical<chalk_ir::InEnvironment<chalk_ir::Goal<Interner>>>, goal: &chalk_ir::UCanonical<chalk_ir::InEnvironment<chalk_ir::Goal<Interner>>>,
) -> Option<chalk_solve::Solution<Interner>> { ) -> Option<chalk_solve::Solution<Interner>> {
let context = ChalkContext { db, krate }; let context = ChalkContext { db, krate, block };
tracing::debug!("solve goal: {:?}", goal); tracing::debug!("solve goal: {:?}", goal);
let mut solver = create_chalk_solver(); let mut solver = create_chalk_solver();

View file

@ -3331,7 +3331,7 @@ impl Type {
binders: CanonicalVarKinds::empty(Interner), 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( pub fn normalize_trait_assoc_type(