aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_ty
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_ty')
-rw-r--r--crates/ra_hir_ty/src/db.rs13
-rw-r--r--crates/ra_hir_ty/src/diagnostics.rs10
-rw-r--r--crates/ra_hir_ty/src/method_resolution.rs203
-rw-r--r--crates/ra_hir_ty/src/tests.rs24
-rw-r--r--crates/ra_hir_ty/src/traits/chalk.rs10
5 files changed, 140 insertions, 120 deletions
diff --git a/crates/ra_hir_ty/src/db.rs b/crates/ra_hir_ty/src/db.rs
index cad553273..dc06c0ee7 100644
--- a/crates/ra_hir_ty/src/db.rs
+++ b/crates/ra_hir_ty/src/db.rs
@@ -11,7 +11,7 @@ use ra_db::{impl_intern_key, salsa, CrateId, Upcast};
11use ra_prof::profile; 11use ra_prof::profile;
12 12
13use crate::{ 13use crate::{
14 method_resolution::CrateImplDefs, 14 method_resolution::{InherentImpls, TraitImpls},
15 traits::{chalk, AssocTyValue, Impl}, 15 traits::{chalk, AssocTyValue, Impl},
16 Binders, CallableDef, GenericPredicate, InferenceResult, OpaqueTyId, PolyFnSig, 16 Binders, CallableDef, GenericPredicate, InferenceResult, OpaqueTyId, PolyFnSig,
17 ReturnTypeImplTraits, TraitRef, Ty, TyDefId, TypeCtor, ValueTyDefId, 17 ReturnTypeImplTraits, TraitRef, Ty, TyDefId, TypeCtor, ValueTyDefId,
@@ -67,11 +67,14 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
67 #[salsa::invoke(crate::lower::generic_defaults_query)] 67 #[salsa::invoke(crate::lower::generic_defaults_query)]
68 fn generic_defaults(&self, def: GenericDefId) -> Arc<[Binders<Ty>]>; 68 fn generic_defaults(&self, def: GenericDefId) -> Arc<[Binders<Ty>]>;
69 69
70 #[salsa::invoke(crate::method_resolution::CrateImplDefs::impls_in_crate_query)] 70 #[salsa::invoke(InherentImpls::inherent_impls_in_crate_query)]
71 fn impls_in_crate(&self, krate: CrateId) -> Arc<CrateImplDefs>; 71 fn inherent_impls_in_crate(&self, krate: CrateId) -> Arc<InherentImpls>;
72 72
73 #[salsa::invoke(crate::method_resolution::CrateImplDefs::impls_from_deps_query)] 73 #[salsa::invoke(TraitImpls::trait_impls_in_crate_query)]
74 fn impls_from_deps(&self, krate: CrateId) -> Arc<CrateImplDefs>; 74 fn trait_impls_in_crate(&self, krate: CrateId) -> Arc<TraitImpls>;
75
76 #[salsa::invoke(TraitImpls::trait_impls_in_deps_query)]
77 fn trait_impls_in_deps(&self, krate: CrateId) -> Arc<TraitImpls>;
75 78
76 // Interned IDs for Chalk integration 79 // Interned IDs for Chalk integration
77 #[salsa::interned] 80 #[salsa::interned]
diff --git a/crates/ra_hir_ty/src/diagnostics.rs b/crates/ra_hir_ty/src/diagnostics.rs
index a59efb347..0289911de 100644
--- a/crates/ra_hir_ty/src/diagnostics.rs
+++ b/crates/ra_hir_ty/src/diagnostics.rs
@@ -32,7 +32,7 @@ impl Diagnostic for NoSuchField {
32impl AstDiagnostic for NoSuchField { 32impl AstDiagnostic for NoSuchField {
33 type AST = ast::RecordField; 33 type AST = ast::RecordField;
34 34
35 fn ast(&self, db: &impl AstDatabase) -> Self::AST { 35 fn ast(&self, db: &dyn AstDatabase) -> Self::AST {
36 let root = db.parse_or_expand(self.source().file_id).unwrap(); 36 let root = db.parse_or_expand(self.source().file_id).unwrap();
37 let node = self.source().value.to_node(&root); 37 let node = self.source().value.to_node(&root);
38 ast::RecordField::cast(node).unwrap() 38 ast::RecordField::cast(node).unwrap()
@@ -65,7 +65,7 @@ impl Diagnostic for MissingFields {
65impl AstDiagnostic for MissingFields { 65impl AstDiagnostic for MissingFields {
66 type AST = ast::RecordFieldList; 66 type AST = ast::RecordFieldList;
67 67
68 fn ast(&self, db: &impl AstDatabase) -> Self::AST { 68 fn ast(&self, db: &dyn AstDatabase) -> Self::AST {
69 let root = db.parse_or_expand(self.source().file_id).unwrap(); 69 let root = db.parse_or_expand(self.source().file_id).unwrap();
70 let node = self.source().value.to_node(&root); 70 let node = self.source().value.to_node(&root);
71 ast::RecordFieldList::cast(node).unwrap() 71 ast::RecordFieldList::cast(node).unwrap()
@@ -135,7 +135,7 @@ impl Diagnostic for MissingOkInTailExpr {
135impl AstDiagnostic for MissingOkInTailExpr { 135impl AstDiagnostic for MissingOkInTailExpr {
136 type AST = ast::Expr; 136 type AST = ast::Expr;
137 137
138 fn ast(&self, db: &impl AstDatabase) -> Self::AST { 138 fn ast(&self, db: &dyn AstDatabase) -> Self::AST {
139 let root = db.parse_or_expand(self.file).unwrap(); 139 let root = db.parse_or_expand(self.file).unwrap();
140 let node = self.source().value.to_node(&root); 140 let node = self.source().value.to_node(&root);
141 ast::Expr::cast(node).unwrap() 141 ast::Expr::cast(node).unwrap()
@@ -163,7 +163,7 @@ impl Diagnostic for BreakOutsideOfLoop {
163impl AstDiagnostic for BreakOutsideOfLoop { 163impl AstDiagnostic for BreakOutsideOfLoop {
164 type AST = ast::Expr; 164 type AST = ast::Expr;
165 165
166 fn ast(&self, db: &impl AstDatabase) -> Self::AST { 166 fn ast(&self, db: &dyn AstDatabase) -> Self::AST {
167 let root = db.parse_or_expand(self.file).unwrap(); 167 let root = db.parse_or_expand(self.file).unwrap();
168 let node = self.source().value.to_node(&root); 168 let node = self.source().value.to_node(&root);
169 ast::Expr::cast(node).unwrap() 169 ast::Expr::cast(node).unwrap()
@@ -191,7 +191,7 @@ impl Diagnostic for MissingUnsafe {
191impl AstDiagnostic for MissingUnsafe { 191impl AstDiagnostic for MissingUnsafe {
192 type AST = ast::Expr; 192 type AST = ast::Expr;
193 193
194 fn ast(&self, db: &impl AstDatabase) -> Self::AST { 194 fn ast(&self, db: &dyn AstDatabase) -> Self::AST {
195 let root = db.parse_or_expand(self.source().file_id).unwrap(); 195 let root = db.parse_or_expand(self.source().file_id).unwrap();
196 let node = self.source().value.to_node(&root); 196 let node = self.source().value.to_node(&root);
197 ast::Expr::cast(node).unwrap() 197 ast::Expr::cast(node).unwrap()
diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs
index c3edd6885..a45febbf7 100644
--- a/crates/ra_hir_ty/src/method_resolution.rs
+++ b/crates/ra_hir_ty/src/method_resolution.rs
@@ -39,136 +39,131 @@ impl TyFingerprint {
39 } 39 }
40} 40}
41 41
42/// A queryable and mergeable collection of impls. 42/// Trait impls defined or available in some crate.
43#[derive(Debug, PartialEq, Eq)] 43#[derive(Debug, Eq, PartialEq)]
44pub struct CrateImplDefs { 44pub struct TraitImpls {
45 inherent_impls: FxHashMap<TyFingerprint, Vec<ImplId>>, 45 // If the `Option<TyFingerprint>` is `None`, the impl may apply to any self type.
46 impls_by_trait: FxHashMap<TraitId, FxHashMap<Option<TyFingerprint>, Vec<ImplId>>>, 46 map: FxHashMap<TraitId, FxHashMap<Option<TyFingerprint>, Vec<ImplId>>>,
47} 47}
48 48
49impl CrateImplDefs { 49impl TraitImpls {
50 pub(crate) fn impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<CrateImplDefs> { 50 pub(crate) fn trait_impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<Self> {
51 let _p = profile("impls_in_crate_query"); 51 let _p = profile("trait_impls_in_crate_query");
52 let mut res = CrateImplDefs { 52 let mut impls = Self { map: FxHashMap::default() };
53 inherent_impls: FxHashMap::default(),
54 impls_by_trait: FxHashMap::default(),
55 };
56 res.fill(db, krate);
57 53
58 Arc::new(res) 54 let crate_def_map = db.crate_def_map(krate);
55 for (_module_id, module_data) in crate_def_map.modules.iter() {
56 for impl_id in module_data.scope.impls() {
57 let target_trait = match db.impl_trait(impl_id) {
58 Some(tr) => tr.value.trait_,
59 None => continue,
60 };
61 let self_ty = db.impl_self_ty(impl_id);
62 let self_ty_fp = TyFingerprint::for_impl(&self_ty.value);
63 impls
64 .map
65 .entry(target_trait)
66 .or_default()
67 .entry(self_ty_fp)
68 .or_default()
69 .push(impl_id);
70 }
71 }
72
73 Arc::new(impls)
59 } 74 }
60 75
61 /// Collects all impls from transitive dependencies of `krate` that may be used by `krate`. 76 pub(crate) fn trait_impls_in_deps_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<Self> {
62 /// 77 let _p = profile("trait_impls_in_deps_query");
63 /// The full set of impls that can be used by `krate` is the returned map plus all the impls
64 /// from `krate` itself.
65 pub(crate) fn impls_from_deps_query(
66 db: &dyn HirDatabase,
67 krate: CrateId,
68 ) -> Arc<CrateImplDefs> {
69 let _p = profile("impls_from_deps_query");
70 let crate_graph = db.crate_graph(); 78 let crate_graph = db.crate_graph();
71 let mut res = CrateImplDefs { 79 let mut res = Self { map: FxHashMap::default() };
72 inherent_impls: FxHashMap::default(),
73 impls_by_trait: FxHashMap::default(),
74 };
75 80
76 // For each dependency, calculate `impls_from_deps` recursively, then add its own 81 for krate in crate_graph.transitive_deps(krate) {
77 // `impls_in_crate`. 82 res.merge(&db.trait_impls_in_crate(krate));
78 // As we might visit crates multiple times, `merge` has to deduplicate impls to avoid
79 // wasting memory.
80 for dep in &crate_graph[krate].dependencies {
81 res.merge(&db.impls_from_deps(dep.crate_id));
82 res.merge(&db.impls_in_crate(dep.crate_id));
83 } 83 }
84 84
85 Arc::new(res) 85 Arc::new(res)
86 } 86 }
87 87
88 fn fill(&mut self, db: &dyn HirDatabase, krate: CrateId) {
89 let crate_def_map = db.crate_def_map(krate);
90 for (_module_id, module_data) in crate_def_map.modules.iter() {
91 for impl_id in module_data.scope.impls() {
92 match db.impl_trait(impl_id) {
93 Some(tr) => {
94 let self_ty = db.impl_self_ty(impl_id);
95 let self_ty_fp = TyFingerprint::for_impl(&self_ty.value);
96 self.impls_by_trait
97 .entry(tr.value.trait_)
98 .or_default()
99 .entry(self_ty_fp)
100 .or_default()
101 .push(impl_id);
102 }
103 None => {
104 let self_ty = db.impl_self_ty(impl_id);
105 if let Some(self_ty_fp) = TyFingerprint::for_impl(&self_ty.value) {
106 self.inherent_impls.entry(self_ty_fp).or_default().push(impl_id);
107 }
108 }
109 }
110 }
111 }
112 }
113
114 fn merge(&mut self, other: &Self) { 88 fn merge(&mut self, other: &Self) {
115 for (fp, impls) in &other.inherent_impls { 89 for (trait_, other_map) in &other.map {
116 let vec = self.inherent_impls.entry(*fp).or_default(); 90 let map = self.map.entry(*trait_).or_default();
117 vec.extend(impls);
118 vec.sort();
119 vec.dedup();
120 }
121
122 for (trait_, other_map) in &other.impls_by_trait {
123 let map = self.impls_by_trait.entry(*trait_).or_default();
124 for (fp, impls) in other_map { 91 for (fp, impls) in other_map {
125 let vec = map.entry(*fp).or_default(); 92 let vec = map.entry(*fp).or_default();
126 vec.extend(impls); 93 vec.extend(impls);
127 vec.sort();
128 vec.dedup();
129 } 94 }
130 } 95 }
131 } 96 }
132 97
133 pub fn lookup_impl_defs(&self, ty: &Ty) -> impl Iterator<Item = ImplId> + '_ { 98 /// Queries all impls of the given trait.
134 let fingerprint = TyFingerprint::for_impl(ty); 99 pub fn for_trait(&self, trait_: TraitId) -> impl Iterator<Item = ImplId> + '_ {
135 fingerprint.and_then(|f| self.inherent_impls.get(&f)).into_iter().flatten().copied() 100 self.map
136 } 101 .get(&trait_)
137
138 pub fn lookup_impl_defs_for_trait(&self, tr: TraitId) -> impl Iterator<Item = ImplId> + '_ {
139 self.impls_by_trait
140 .get(&tr)
141 .into_iter() 102 .into_iter()
142 .flat_map(|m| m.values().flat_map(|v| v.iter().copied())) 103 .flat_map(|map| map.values().flat_map(|v| v.iter().copied()))
143 } 104 }
144 105
145 pub fn lookup_impl_defs_for_trait_and_ty( 106 /// Queries all impls of `trait_` that may apply to `self_ty`.
107 pub fn for_trait_and_self_ty(
146 &self, 108 &self,
147 tr: TraitId, 109 trait_: TraitId,
148 fp: TyFingerprint, 110 self_ty: TyFingerprint,
149 ) -> impl Iterator<Item = ImplId> + '_ { 111 ) -> impl Iterator<Item = ImplId> + '_ {
150 self.impls_by_trait 112 self.map
151 .get(&tr) 113 .get(&trait_)
152 .and_then(|m| m.get(&Some(fp)))
153 .into_iter() 114 .into_iter()
154 .flatten() 115 .flat_map(move |map| map.get(&None).into_iter().chain(map.get(&Some(self_ty))))
155 .copied() 116 .flat_map(|v| v.iter().copied())
156 .chain( 117 }
157 self.impls_by_trait 118
158 .get(&tr) 119 pub fn all_impls(&self) -> impl Iterator<Item = ImplId> + '_ {
159 .and_then(|m| m.get(&None)) 120 self.map.values().flat_map(|map| map.values().flat_map(|v| v.iter().copied()))
160 .into_iter() 121 }
161 .flatten() 122}
162 .copied(), 123
163 ) 124/// Inherent impls defined in some crate.
125///
126/// Inherent impls can only be defined in the crate that also defines the self type of the impl
127/// (note that some primitives are considered to be defined by both libcore and liballoc).
128///
129/// This makes inherent impl lookup easier than trait impl lookup since we only have to consider a
130/// single crate.
131#[derive(Debug, Eq, PartialEq)]
132pub struct InherentImpls {
133 map: FxHashMap<TyFingerprint, Vec<ImplId>>,
134}
135
136impl InherentImpls {
137 pub(crate) fn inherent_impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<Self> {
138 let mut map: FxHashMap<_, Vec<_>> = FxHashMap::default();
139
140 let crate_def_map = db.crate_def_map(krate);
141 for (_module_id, module_data) in crate_def_map.modules.iter() {
142 for impl_id in module_data.scope.impls() {
143 let data = db.impl_data(impl_id);
144 if data.target_trait.is_some() {
145 continue;
146 }
147
148 let self_ty = db.impl_self_ty(impl_id);
149 if let Some(fp) = TyFingerprint::for_impl(&self_ty.value) {
150 map.entry(fp).or_default().push(impl_id);
151 }
152 }
153 }
154
155 Arc::new(Self { map })
156 }
157
158 pub fn for_self_ty(&self, self_ty: &Ty) -> &[ImplId] {
159 match TyFingerprint::for_impl(self_ty) {
160 Some(fp) => self.map.get(&fp).map(|vec| vec.as_ref()).unwrap_or(&[]),
161 None => &[],
162 }
164 } 163 }
165 164
166 pub fn all_impls<'a>(&'a self) -> impl Iterator<Item = ImplId> + 'a { 165 pub fn all_impls(&self) -> impl Iterator<Item = ImplId> + '_ {
167 self.inherent_impls 166 self.map.values().flat_map(|v| v.iter().copied())
168 .values()
169 .chain(self.impls_by_trait.values().flat_map(|m| m.values()))
170 .flatten()
171 .copied()
172 } 167 }
173} 168}
174 169
@@ -525,9 +520,9 @@ fn iterate_inherent_methods(
525 None => return false, 520 None => return false,
526 }; 521 };
527 for krate in def_crates { 522 for krate in def_crates {
528 let impls = db.impls_in_crate(krate); 523 let impls = db.inherent_impls_in_crate(krate);
529 524
530 for impl_def in impls.lookup_impl_defs(&self_ty.value) { 525 for &impl_def in impls.for_self_ty(&self_ty.value) {
531 for &item in db.impl_data(impl_def).items.iter() { 526 for &item in db.impl_data(impl_def).items.iter() {
532 if !is_valid_candidate(db, name, receiver_ty, item, self_ty) { 527 if !is_valid_candidate(db, name, receiver_ty, item, self_ty) {
533 continue; 528 continue;
diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs
index 9084c3bed..eeac34d14 100644
--- a/crates/ra_hir_ty/src/tests.rs
+++ b/crates/ra_hir_ty/src/tests.rs
@@ -508,6 +508,30 @@ fn no_such_field_with_feature_flag_diagnostics_on_struct_fields() {
508} 508}
509 509
510#[test] 510#[test]
511fn no_such_field_with_type_macro() {
512 let diagnostics = TestDB::with_files(
513 r"
514 macro_rules! Type {
515 () => { u32 };
516 }
517
518 struct Foo {
519 bar: Type![],
520 }
521 impl Foo {
522 fn new() -> Self {
523 Foo { bar: 0 }
524 }
525 }
526 ",
527 )
528 .diagnostics()
529 .0;
530
531 assert_snapshot!(diagnostics, @r###""###);
532}
533
534#[test]
511fn missing_record_pat_field_diagnostic() { 535fn missing_record_pat_field_diagnostic() {
512 let diagnostics = TestDB::with_files( 536 let diagnostics = TestDB::with_files(
513 r" 537 r"
diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs
index 8ef4941c0..c97b81d57 100644
--- a/crates/ra_hir_ty/src/traits/chalk.rs
+++ b/crates/ra_hir_ty/src/traits/chalk.rs
@@ -77,8 +77,8 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
77 // Note: Since we're using impls_for_trait, only impls where the trait 77 // Note: Since we're using impls_for_trait, only impls where the trait
78 // can be resolved should ever reach Chalk. `impl_datum` relies on that 78 // can be resolved should ever reach Chalk. `impl_datum` relies on that
79 // and will panic if the trait can't be resolved. 79 // and will panic if the trait can't be resolved.
80 let in_deps = self.db.impls_from_deps(self.krate); 80 let in_deps = self.db.trait_impls_in_deps(self.krate);
81 let in_self = self.db.impls_in_crate(self.krate); 81 let in_self = self.db.trait_impls_in_crate(self.krate);
82 let impl_maps = [in_deps, in_self]; 82 let impl_maps = [in_deps, in_self];
83 83
84 let id_to_chalk = |id: hir_def::ImplId| Impl::ImplDef(id).to_chalk(self.db); 84 let id_to_chalk = |id: hir_def::ImplId| Impl::ImplDef(id).to_chalk(self.db);
@@ -87,14 +87,12 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
87 Some(fp) => impl_maps 87 Some(fp) => impl_maps
88 .iter() 88 .iter()
89 .flat_map(|crate_impl_defs| { 89 .flat_map(|crate_impl_defs| {
90 crate_impl_defs.lookup_impl_defs_for_trait_and_ty(trait_, fp).map(id_to_chalk) 90 crate_impl_defs.for_trait_and_self_ty(trait_, fp).map(id_to_chalk)
91 }) 91 })
92 .collect(), 92 .collect(),
93 None => impl_maps 93 None => impl_maps
94 .iter() 94 .iter()
95 .flat_map(|crate_impl_defs| { 95 .flat_map(|crate_impl_defs| crate_impl_defs.for_trait(trait_).map(id_to_chalk))
96 crate_impl_defs.lookup_impl_defs_for_trait(trait_).map(id_to_chalk)
97 })
98 .collect(), 96 .collect(),
99 }; 97 };
100 98