aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2021-06-13 12:13:31 +0100
committerGitHub <[email protected]>2021-06-13 12:13:31 +0100
commitbe9742809c80fbb86b1a25479a4cf2a0df24adb7 (patch)
treec9aeedf0d7167d436befbdc5cea6b06b7a1cfe98
parente29a4c36c7135820929e741ed40192648556aca6 (diff)
parent5ca71a19903cea277ed8a347b36cffeca6b99922 (diff)
Merge #9244
9244: feat: Make block-local trait impls work r=flodiebold a=flodiebold As long as either the trait or the implementing type are defined in the same block. CC #8961 Co-authored-by: Florian Diebold <[email protected]>
-rw-r--r--crates/hir_def/src/lib.rs16
-rw-r--r--crates/hir_ty/src/chalk_db.rs36
-rw-r--r--crates/hir_ty/src/db.rs7
-rw-r--r--crates/hir_ty/src/method_resolution.rs64
-rw-r--r--crates/hir_ty/src/tests/traits.rs67
5 files changed, 154 insertions, 36 deletions
diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs
index 303083c6d..bb174aec8 100644
--- a/crates/hir_def/src/lib.rs
+++ b/crates/hir_def/src/lib.rs
@@ -112,6 +112,10 @@ impl ModuleId {
112 self.def_map(db).containing_module(self.local_id) 112 self.def_map(db).containing_module(self.local_id)
113 } 113 }
114 114
115 pub fn containing_block(&self) -> Option<BlockId> {
116 self.block
117 }
118
115 /// Returns `true` if this module represents a block expression. 119 /// Returns `true` if this module represents a block expression.
116 /// 120 ///
117 /// Returns `false` if this module is a submodule *inside* a block expression 121 /// Returns `false` if this module is a submodule *inside* a block expression
@@ -581,6 +585,18 @@ impl HasModule for GenericDefId {
581 } 585 }
582} 586}
583 587
588impl HasModule for TypeAliasId {
589 fn module(&self, db: &dyn db::DefDatabase) -> ModuleId {
590 self.lookup(db).module(db)
591 }
592}
593
594impl HasModule for TraitId {
595 fn module(&self, db: &dyn db::DefDatabase) -> ModuleId {
596 self.lookup(db).container
597 }
598}
599
584impl HasModule for StaticLoc { 600impl HasModule for StaticLoc {
585 fn module(&self, _db: &dyn db::DefDatabase) -> ModuleId { 601 fn module(&self, _db: &dyn db::DefDatabase) -> ModuleId {
586 self.container 602 self.container
diff --git a/crates/hir_ty/src/chalk_db.rs b/crates/hir_ty/src/chalk_db.rs
index 34c3f6bd9..a4c09c742 100644
--- a/crates/hir_ty/src/chalk_db.rs
+++ b/crates/hir_ty/src/chalk_db.rs
@@ -10,16 +10,16 @@ use chalk_solve::rust_ir::{self, OpaqueTyDatumBound, WellKnownTrait};
10use base_db::CrateId; 10use base_db::CrateId;
11use hir_def::{ 11use hir_def::{
12 lang_item::{lang_attr, LangItemTarget}, 12 lang_item::{lang_attr, LangItemTarget},
13 AssocContainerId, AssocItemId, GenericDefId, HasModule, Lookup, TypeAliasId, 13 AssocContainerId, AssocItemId, GenericDefId, HasModule, Lookup, ModuleId, TypeAliasId,
14}; 14};
15use hir_expand::name::name; 15use hir_expand::name::name;
16 16
17use crate::{ 17use crate::{
18 db::HirDatabase, 18 db::HirDatabase,
19 display::HirDisplay, 19 display::HirDisplay,
20 from_assoc_type_id, from_chalk_trait_id, make_only_type_binders, 20 from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, make_only_type_binders,
21 mapping::{from_chalk, ToChalk, TypeAliasAsValue}, 21 mapping::{from_chalk, ToChalk, TypeAliasAsValue},
22 method_resolution::{TyFingerprint, ALL_FLOAT_FPS, ALL_INT_FPS}, 22 method_resolution::{TraitImpls, TyFingerprint, ALL_FLOAT_FPS, ALL_INT_FPS},
23 to_assoc_type_id, to_chalk_trait_id, 23 to_assoc_type_id, to_chalk_trait_id,
24 traits::ChalkContext, 24 traits::ChalkContext,
25 utils::generics, 25 utils::generics,
@@ -105,12 +105,30 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
105 _ => self_ty_fp.as_ref().map(std::slice::from_ref).unwrap_or(&[]), 105 _ => self_ty_fp.as_ref().map(std::slice::from_ref).unwrap_or(&[]),
106 }; 106 };
107 107
108 fn local_impls(db: &dyn HirDatabase, module: ModuleId) -> Option<Arc<TraitImpls>> {
109 db.trait_impls_in_block(module.containing_block()?)
110 }
111
108 // Note: Since we're using impls_for_trait, only impls where the trait 112 // Note: Since we're using impls_for_trait, only impls where the trait
109 // can be resolved should ever reach Chalk. Symbol’s value as variable is void: impl_datum relies on that 113 // can be resolved should ever reach Chalk. impl_datum relies on that
110 // and will panic if the trait can't be resolved. 114 // and will panic if the trait can't be resolved.
111 let in_deps = self.db.trait_impls_in_deps(self.krate); 115 let in_deps = self.db.trait_impls_in_deps(self.krate);
112 let in_self = self.db.trait_impls_in_crate(self.krate); 116 let in_self = self.db.trait_impls_in_crate(self.krate);
113 let impl_maps = [in_deps, in_self]; 117 let trait_module = trait_.module(self.db.upcast());
118 let type_module = match self_ty_fp {
119 Some(TyFingerprint::Adt(adt_id)) => Some(adt_id.module(self.db.upcast())),
120 Some(TyFingerprint::ForeignType(type_id)) => {
121 Some(from_foreign_def_id(type_id).module(self.db.upcast()))
122 }
123 Some(TyFingerprint::Dyn(trait_id)) => Some(trait_id.module(self.db.upcast())),
124 _ => None,
125 };
126 let impl_maps = [
127 Some(in_deps),
128 Some(in_self),
129 local_impls(self.db, trait_module),
130 type_module.and_then(|m| local_impls(self.db, m)),
131 ];
114 132
115 let id_to_chalk = |id: hir_def::ImplId| id.to_chalk(self.db); 133 let id_to_chalk = |id: hir_def::ImplId| id.to_chalk(self.db);
116 134
@@ -118,14 +136,16 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
118 debug!("Unrestricted search for {:?} impls...", trait_); 136 debug!("Unrestricted search for {:?} impls...", trait_);
119 impl_maps 137 impl_maps
120 .iter() 138 .iter()
121 .flat_map(|crate_impl_defs| crate_impl_defs.for_trait(trait_).map(id_to_chalk)) 139 .filter_map(|o| o.as_ref())
140 .flat_map(|impls| impls.for_trait(trait_).map(id_to_chalk))
122 .collect() 141 .collect()
123 } else { 142 } else {
124 impl_maps 143 impl_maps
125 .iter() 144 .iter()
126 .flat_map(|crate_impl_defs| { 145 .filter_map(|o| o.as_ref())
146 .flat_map(|impls| {
127 fps.iter().flat_map(move |fp| { 147 fps.iter().flat_map(move |fp| {
128 crate_impl_defs.for_trait_and_self_ty(trait_, *fp).map(id_to_chalk) 148 impls.for_trait_and_self_ty(trait_, *fp).map(id_to_chalk)
129 }) 149 })
130 }) 150 })
131 .collect() 151 .collect()
diff --git a/crates/hir_ty/src/db.rs b/crates/hir_ty/src/db.rs
index be5b9110e..b9003c413 100644
--- a/crates/hir_ty/src/db.rs
+++ b/crates/hir_ty/src/db.rs
@@ -5,8 +5,8 @@ use std::sync::Arc;
5 5
6use base_db::{impl_intern_key, salsa, CrateId, Upcast}; 6use base_db::{impl_intern_key, salsa, CrateId, Upcast};
7use hir_def::{ 7use hir_def::{
8 db::DefDatabase, expr::ExprId, ConstParamId, DefWithBodyId, FunctionId, GenericDefId, ImplId, 8 db::DefDatabase, expr::ExprId, BlockId, ConstParamId, DefWithBodyId, FunctionId, GenericDefId,
9 LifetimeParamId, LocalFieldId, TypeParamId, VariantId, 9 ImplId, LifetimeParamId, LocalFieldId, TypeParamId, VariantId,
10}; 10};
11use la_arena::ArenaMap; 11use la_arena::ArenaMap;
12 12
@@ -79,6 +79,9 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
79 #[salsa::invoke(TraitImpls::trait_impls_in_crate_query)] 79 #[salsa::invoke(TraitImpls::trait_impls_in_crate_query)]
80 fn trait_impls_in_crate(&self, krate: CrateId) -> Arc<TraitImpls>; 80 fn trait_impls_in_crate(&self, krate: CrateId) -> Arc<TraitImpls>;
81 81
82 #[salsa::invoke(TraitImpls::trait_impls_in_block_query)]
83 fn trait_impls_in_block(&self, krate: BlockId) -> Option<Arc<TraitImpls>>;
84
82 #[salsa::invoke(TraitImpls::trait_impls_in_deps_query)] 85 #[salsa::invoke(TraitImpls::trait_impls_in_deps_query)]
83 fn trait_impls_in_deps(&self, krate: CrateId) -> Arc<TraitImpls>; 86 fn trait_impls_in_deps(&self, krate: CrateId) -> Arc<TraitImpls>;
84 87
diff --git a/crates/hir_ty/src/method_resolution.rs b/crates/hir_ty/src/method_resolution.rs
index f3d390961..3d233b1e2 100644
--- a/crates/hir_ty/src/method_resolution.rs
+++ b/crates/hir_ty/src/method_resolution.rs
@@ -8,7 +8,7 @@ use arrayvec::ArrayVec;
8use base_db::{CrateId, Edition}; 8use base_db::{CrateId, Edition};
9use chalk_ir::{cast::Cast, Mutability, UniverseIndex}; 9use chalk_ir::{cast::Cast, Mutability, UniverseIndex};
10use hir_def::{ 10use hir_def::{
11 lang_item::LangItemTarget, nameres::DefMap, AssocContainerId, AssocItemId, FunctionId, 11 lang_item::LangItemTarget, nameres::DefMap, AssocContainerId, AssocItemId, BlockId, FunctionId,
12 GenericDefId, HasModule, ImplId, Lookup, ModuleId, TraitId, 12 GenericDefId, HasModule, ImplId, Lookup, ModuleId, TraitId,
13}; 13};
14use hir_expand::name::Name; 14use hir_expand::name::Name;
@@ -139,35 +139,47 @@ impl TraitImpls {
139 let mut impls = Self { map: FxHashMap::default() }; 139 let mut impls = Self { map: FxHashMap::default() };
140 140
141 let crate_def_map = db.crate_def_map(krate); 141 let crate_def_map = db.crate_def_map(krate);
142 collect_def_map(db, &crate_def_map, &mut impls); 142 impls.collect_def_map(db, &crate_def_map);
143 143
144 return Arc::new(impls); 144 return Arc::new(impls);
145 }
145 146
146 fn collect_def_map(db: &dyn HirDatabase, def_map: &DefMap, impls: &mut TraitImpls) { 147 pub(crate) fn trait_impls_in_block_query(
147 for (_module_id, module_data) in def_map.modules() { 148 db: &dyn HirDatabase,
148 for impl_id in module_data.scope.impls() { 149 block: BlockId,
149 let target_trait = match db.impl_trait(impl_id) { 150 ) -> Option<Arc<Self>> {
150 Some(tr) => tr.skip_binders().hir_trait_id(), 151 let _p = profile::span("trait_impls_in_block_query");
151 None => continue, 152 let mut impls = Self { map: FxHashMap::default() };
152 };
153 let self_ty = db.impl_self_ty(impl_id);
154 let self_ty_fp = TyFingerprint::for_trait_impl(self_ty.skip_binders());
155 impls
156 .map
157 .entry(target_trait)
158 .or_default()
159 .entry(self_ty_fp)
160 .or_default()
161 .push(impl_id);
162 }
163 153
164 // To better support custom derives, collect impls in all unnamed const items. 154 let block_def_map = db.block_def_map(block)?;
165 // const _: () = { ... }; 155 impls.collect_def_map(db, &block_def_map);
166 for konst in module_data.scope.unnamed_consts() { 156
167 let body = db.body(konst.into()); 157 return Some(Arc::new(impls));
168 for (_, block_def_map) in body.blocks(db.upcast()) { 158 }
169 collect_def_map(db, &block_def_map, impls); 159
170 } 160 fn collect_def_map(&mut self, db: &dyn HirDatabase, def_map: &DefMap) {
161 for (_module_id, module_data) in def_map.modules() {
162 for impl_id in module_data.scope.impls() {
163 let target_trait = match db.impl_trait(impl_id) {
164 Some(tr) => tr.skip_binders().hir_trait_id(),
165 None => continue,
166 };
167 let self_ty = db.impl_self_ty(impl_id);
168 let self_ty_fp = TyFingerprint::for_trait_impl(self_ty.skip_binders());
169 self.map
170 .entry(target_trait)
171 .or_default()
172 .entry(self_ty_fp)
173 .or_default()
174 .push(impl_id);
175 }
176
177 // To better support custom derives, collect impls in all unnamed const items.
178 // const _: () = { ... };
179 for konst in module_data.scope.unnamed_consts() {
180 let body = db.body(konst.into());
181 for (_, block_def_map) in body.blocks(db.upcast()) {
182 self.collect_def_map(db, &block_def_map);
171 } 183 }
172 } 184 }
173 } 185 }
diff --git a/crates/hir_ty/src/tests/traits.rs b/crates/hir_ty/src/tests/traits.rs
index 588f0d1d4..6bcede4c4 100644
--- a/crates/hir_ty/src/tests/traits.rs
+++ b/crates/hir_ty/src/tests/traits.rs
@@ -3740,3 +3740,70 @@ mod future {
3740"#, 3740"#,
3741 ); 3741 );
3742} 3742}
3743
3744#[test]
3745fn local_impl_1() {
3746 check_types(
3747 r#"
3748trait Trait<T> {
3749 fn foo(&self) -> T;
3750}
3751
3752fn test() {
3753 struct S;
3754 impl Trait<u32> for S {
3755 fn foo(&self) { 0 }
3756 }
3757
3758 S.foo();
3759 // ^^^^^^^ u32
3760}
3761"#,
3762 );
3763}
3764
3765#[test]
3766fn local_impl_2() {
3767 check_types(
3768 r#"
3769struct S;
3770
3771fn test() {
3772 trait Trait<T> {
3773 fn foo(&self) -> T;
3774 }
3775 impl Trait<u32> for S {
3776 fn foo(&self) { 0 }
3777 }
3778
3779 S.foo();
3780 // ^^^^^^^ u32
3781}
3782"#,
3783 );
3784}
3785
3786#[test]
3787fn local_impl_3() {
3788 check_types(
3789 r#"
3790trait Trait<T> {
3791 fn foo(&self) -> T;
3792}
3793
3794fn test() {
3795 struct S1;
3796 {
3797 struct S2;
3798
3799 impl Trait<S1> for S2 {
3800 fn foo(&self) { S1 }
3801 }
3802
3803 S2.foo();
3804 // ^^^^^^^^ S1
3805 }
3806}
3807"#,
3808 );
3809}