diff options
-rw-r--r-- | crates/hir_def/src/lib.rs | 12 | ||||
-rw-r--r-- | crates/hir_def/src/visibility.rs | 10 | ||||
-rw-r--r-- | crates/hir_ty/src/method_resolution.rs | 42 | ||||
-rw-r--r-- | crates/hir_ty/src/tests/method_resolution.rs | 37 |
4 files changed, 83 insertions, 18 deletions
diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs index 000567d99..5ac1670b5 100644 --- a/crates/hir_def/src/lib.rs +++ b/crates/hir_def/src/lib.rs | |||
@@ -108,6 +108,18 @@ impl ModuleId { | |||
108 | pub fn containing_module(&self, db: &dyn db::DefDatabase) -> Option<ModuleId> { | 108 | pub fn containing_module(&self, db: &dyn db::DefDatabase) -> Option<ModuleId> { |
109 | self.def_map(db).containing_module(self.local_id) | 109 | self.def_map(db).containing_module(self.local_id) |
110 | } | 110 | } |
111 | |||
112 | /// Returns `true` if this module represents a block expression. | ||
113 | /// | ||
114 | /// Returns `false` if this module is a submodule *inside* a block expression | ||
115 | /// (eg. `m` in `{ mod m {} }`). | ||
116 | pub fn is_block_root(&self, db: &dyn db::DefDatabase) -> bool { | ||
117 | if self.block.is_none() { | ||
118 | return false; | ||
119 | } | ||
120 | |||
121 | self.def_map(db)[self.local_id].parent.is_none() | ||
122 | } | ||
111 | } | 123 | } |
112 | 124 | ||
113 | /// An ID of a module, **local** to a specific crate | 125 | /// An ID of a module, **local** to a specific crate |
diff --git a/crates/hir_def/src/visibility.rs b/crates/hir_def/src/visibility.rs index 9908cd926..d4b7c9970 100644 --- a/crates/hir_def/src/visibility.rs +++ b/crates/hir_def/src/visibility.rs | |||
@@ -123,11 +123,19 @@ impl Visibility { | |||
123 | def_map: &DefMap, | 123 | def_map: &DefMap, |
124 | mut from_module: crate::LocalModuleId, | 124 | mut from_module: crate::LocalModuleId, |
125 | ) -> bool { | 125 | ) -> bool { |
126 | let to_module = match self { | 126 | let mut to_module = match self { |
127 | Visibility::Module(m) => m, | 127 | Visibility::Module(m) => m, |
128 | Visibility::Public => return true, | 128 | Visibility::Public => return true, |
129 | }; | 129 | }; |
130 | 130 | ||
131 | // `to_module` might be the root module of a block expression. Those have the same | ||
132 | // visibility as the containing module (even though no items are directly nameable from | ||
133 | // there, getting this right is important for method resolution). | ||
134 | // In that case, we adjust the visibility of `to_module` to point to the containing module. | ||
135 | if to_module.is_block_root(db) { | ||
136 | to_module = to_module.containing_module(db).unwrap(); | ||
137 | } | ||
138 | |||
131 | // from_module needs to be a descendant of to_module | 139 | // from_module needs to be a descendant of to_module |
132 | let mut def_map = def_map; | 140 | let mut def_map = def_map; |
133 | let mut parent_arc; | 141 | let mut parent_arc; |
diff --git a/crates/hir_ty/src/method_resolution.rs b/crates/hir_ty/src/method_resolution.rs index 3693e3284..48bbcfd9f 100644 --- a/crates/hir_ty/src/method_resolution.rs +++ b/crates/hir_ty/src/method_resolution.rs | |||
@@ -246,29 +246,39 @@ pub struct InherentImpls { | |||
246 | 246 | ||
247 | impl InherentImpls { | 247 | impl InherentImpls { |
248 | pub(crate) fn inherent_impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<Self> { | 248 | pub(crate) fn inherent_impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<Self> { |
249 | let mut map: FxHashMap<_, Vec<_>> = FxHashMap::default(); | 249 | let mut impls = Self { map: FxHashMap::default() }; |
250 | 250 | ||
251 | let crate_def_map = db.crate_def_map(krate); | 251 | let crate_def_map = db.crate_def_map(krate); |
252 | for (_module_id, module_data) in crate_def_map.modules() { | 252 | collect_def_map(db, &crate_def_map, &mut impls); |
253 | for impl_id in module_data.scope.impls() { | 253 | |
254 | let data = db.impl_data(impl_id); | 254 | return Arc::new(impls); |
255 | if data.target_trait.is_some() { | 255 | |
256 | continue; | 256 | fn collect_def_map(db: &dyn HirDatabase, def_map: &DefMap, impls: &mut InherentImpls) { |
257 | for (_module_id, module_data) in def_map.modules() { | ||
258 | for impl_id in module_data.scope.impls() { | ||
259 | let data = db.impl_data(impl_id); | ||
260 | if data.target_trait.is_some() { | ||
261 | continue; | ||
262 | } | ||
263 | |||
264 | let self_ty = db.impl_self_ty(impl_id); | ||
265 | let fp = TyFingerprint::for_inherent_impl(self_ty.skip_binders()); | ||
266 | if let Some(fp) = fp { | ||
267 | impls.map.entry(fp).or_default().push(impl_id); | ||
268 | } | ||
269 | // `fp` should only be `None` in error cases (either erroneous code or incomplete name resolution) | ||
257 | } | 270 | } |
258 | 271 | ||
259 | let self_ty = db.impl_self_ty(impl_id); | 272 | // To better support custom derives, collect impls in all unnamed const items. |
260 | let fp = TyFingerprint::for_inherent_impl(self_ty.skip_binders()); | 273 | // const _: () = { ... }; |
261 | if let Some(fp) = fp { | 274 | for konst in module_data.scope.unnamed_consts() { |
262 | map.entry(fp).or_default().push(impl_id); | 275 | let body = db.body(konst.into()); |
276 | for (_, block_def_map) in body.blocks(db.upcast()) { | ||
277 | collect_def_map(db, &block_def_map, impls); | ||
278 | } | ||
263 | } | 279 | } |
264 | // `fp` should only be `None` in error cases (either erroneous code or incomplete name resolution) | ||
265 | } | 280 | } |
266 | } | 281 | } |
267 | |||
268 | // NOTE: We're not collecting inherent impls from unnamed consts here, we intentionally only | ||
269 | // support trait impls there. | ||
270 | |||
271 | Arc::new(Self { map }) | ||
272 | } | 282 | } |
273 | 283 | ||
274 | pub fn for_self_ty(&self, self_ty: &Ty) -> &[ImplId] { | 284 | pub fn for_self_ty(&self, self_ty: &Ty) -> &[ImplId] { |
diff --git a/crates/hir_ty/src/tests/method_resolution.rs b/crates/hir_ty/src/tests/method_resolution.rs index 4b2c82b41..a4c132bc5 100644 --- a/crates/hir_ty/src/tests/method_resolution.rs +++ b/crates/hir_ty/src/tests/method_resolution.rs | |||
@@ -1294,7 +1294,7 @@ mod b { | |||
1294 | } | 1294 | } |
1295 | 1295 | ||
1296 | #[test] | 1296 | #[test] |
1297 | fn impl_in_unnamed_const() { | 1297 | fn trait_impl_in_unnamed_const() { |
1298 | check_types( | 1298 | check_types( |
1299 | r#" | 1299 | r#" |
1300 | struct S; | 1300 | struct S; |
@@ -1314,3 +1314,38 @@ fn f() { | |||
1314 | "#, | 1314 | "#, |
1315 | ); | 1315 | ); |
1316 | } | 1316 | } |
1317 | |||
1318 | #[test] | ||
1319 | fn inherent_impl_in_unnamed_const() { | ||
1320 | check_types( | ||
1321 | r#" | ||
1322 | struct S; | ||
1323 | |||
1324 | const _: () = { | ||
1325 | impl S { | ||
1326 | fn method(&self) -> u16 { 0 } | ||
1327 | |||
1328 | pub(super) fn super_method(&self) -> u16 { 0 } | ||
1329 | |||
1330 | pub(crate) fn crate_method(&self) -> u16 { 0 } | ||
1331 | |||
1332 | pub fn pub_method(&self) -> u16 { 0 } | ||
1333 | } | ||
1334 | }; | ||
1335 | |||
1336 | fn f() { | ||
1337 | S.method(); | ||
1338 | //^^^^^^^^^^ u16 | ||
1339 | |||
1340 | S.super_method(); | ||
1341 | //^^^^^^^^^^^^^^^^ u16 | ||
1342 | |||
1343 | S.crate_method(); | ||
1344 | //^^^^^^^^^^^^^^^^ u16 | ||
1345 | |||
1346 | S.pub_method(); | ||
1347 | //^^^^^^^^^^^^^^ u16 | ||
1348 | } | ||
1349 | "#, | ||
1350 | ); | ||
1351 | } | ||