aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir')
-rw-r--r--crates/ra_hir/src/code_model_api.rs4
-rw-r--r--crates/ra_hir/src/db.rs12
-rw-r--r--crates/ra_hir/src/expr.rs5
-rw-r--r--crates/ra_hir/src/generics.rs62
-rw-r--r--crates/ra_hir/src/impl_block.rs8
-rw-r--r--crates/ra_hir/src/marks.rs1
-rw-r--r--crates/ra_hir/src/nameres.rs4
-rw-r--r--crates/ra_hir/src/resolve.rs42
-rw-r--r--crates/ra_hir/src/source_binder.rs25
-rw-r--r--crates/ra_hir/src/traits.rs8
-rw-r--r--crates/ra_hir/src/ty.rs50
-rw-r--r--crates/ra_hir/src/ty/infer.rs3
-rw-r--r--crates/ra_hir/src/ty/lower.rs53
-rw-r--r--crates/ra_hir/src/ty/method_resolution.rs17
-rw-r--r--crates/ra_hir/src/ty/tests.rs160
-rw-r--r--crates/ra_hir/src/ty/traits.rs20
-rw-r--r--crates/ra_hir/src/ty/traits/chalk.rs179
17 files changed, 530 insertions, 123 deletions
diff --git a/crates/ra_hir/src/code_model_api.rs b/crates/ra_hir/src/code_model_api.rs
index 55e1793c5..0c4a80bfa 100644
--- a/crates/ra_hir/src/code_model_api.rs
+++ b/crates/ra_hir/src/code_model_api.rs
@@ -703,6 +703,10 @@ impl Trait {
703 TraitRef::for_trait(db, self) 703 TraitRef::for_trait(db, self)
704 } 704 }
705 705
706 pub fn is_auto(self, db: &impl DefDatabase) -> bool {
707 self.trait_data(db).is_auto()
708 }
709
706 pub(crate) fn resolver(&self, db: &impl DefDatabase) -> Resolver { 710 pub(crate) fn resolver(&self, db: &impl DefDatabase) -> Resolver {
707 let r = self.module(db).resolver(db); 711 let r = self.module(db).resolver(db);
708 // add generic params, if present 712 // add generic params, if present
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs
index 8aaf0375a..8f98ca3a5 100644
--- a/crates/ra_hir/src/db.rs
+++ b/crates/ra_hir/src/db.rs
@@ -11,7 +11,7 @@ use crate::{
11 DefWithBody, Trait, 11 DefWithBody, Trait,
12 ids, 12 ids,
13 nameres::{Namespace, ImportSourceMap, RawItems, CrateDefMap}, 13 nameres::{Namespace, ImportSourceMap, RawItems, CrateDefMap},
14 ty::{InferenceResult, Ty, method_resolution::CrateImplBlocks, TypableDef, CallableDef, FnSig, TypeCtor}, 14 ty::{InferenceResult, Ty, method_resolution::CrateImplBlocks, TypableDef, CallableDef, FnSig, TypeCtor, GenericPredicate},
15 adt::{StructData, EnumData}, 15 adt::{StructData, EnumData},
16 impl_block::{ModuleImplBlocks, ImplSourceMap, ImplBlock}, 16 impl_block::{ModuleImplBlocks, ImplSourceMap, ImplBlock},
17 generics::{GenericParams, GenericDef}, 17 generics::{GenericParams, GenericDef},
@@ -138,6 +138,9 @@ pub trait HirDatabase: DefDatabase {
138 #[salsa::invoke(crate::ty::callable_item_sig)] 138 #[salsa::invoke(crate::ty::callable_item_sig)]
139 fn callable_item_signature(&self, def: CallableDef) -> FnSig; 139 fn callable_item_signature(&self, def: CallableDef) -> FnSig;
140 140
141 #[salsa::invoke(crate::ty::generic_predicates)]
142 fn generic_predicates(&self, def: GenericDef) -> Arc<[GenericPredicate]>;
143
141 #[salsa::invoke(crate::expr::body_with_source_map_query)] 144 #[salsa::invoke(crate::expr::body_with_source_map_query)]
142 fn body_with_source_map( 145 fn body_with_source_map(
143 &self, 146 &self,
@@ -161,6 +164,13 @@ pub trait HirDatabase: DefDatabase {
161 #[salsa::invoke(crate::ty::traits::solver)] 164 #[salsa::invoke(crate::ty::traits::solver)]
162 #[salsa::volatile] 165 #[salsa::volatile]
163 fn solver(&self, krate: Crate) -> Arc<Mutex<crate::ty::traits::Solver>>; 166 fn solver(&self, krate: Crate) -> Arc<Mutex<crate::ty::traits::Solver>>;
167
168 #[salsa::invoke(crate::ty::traits::implements)]
169 fn implements(
170 &self,
171 krate: Crate,
172 goal: crate::ty::Canonical<crate::ty::TraitRef>,
173 ) -> Option<crate::ty::traits::Solution>;
164} 174}
165 175
166#[test] 176#[test]
diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs
index 480eaf171..a2b5db1a1 100644
--- a/crates/ra_hir/src/expr.rs
+++ b/crates/ra_hir/src/expr.rs
@@ -10,7 +10,7 @@ use ra_syntax::{
10}; 10};
11 11
12use crate::{ 12use crate::{
13 Path, Name, HirDatabase, Resolver,DefWithBody, Either, HirFileId, 13 Path, Name, HirDatabase, Resolver,DefWithBody, Either, HirFileId, MacroCallLoc,
14 name::AsName, 14 name::AsName,
15 type_ref::{Mutability, TypeRef}, 15 type_ref::{Mutability, TypeRef},
16}; 16};
@@ -828,7 +828,8 @@ where
828 .ast_id(e) 828 .ast_id(e)
829 .with_file_id(self.current_file_id); 829 .with_file_id(self.current_file_id);
830 830
831 if let Some(call_id) = self.resolver.resolve_macro_call(self.db, path, ast_id) { 831 if let Some(def) = self.resolver.resolve_macro_call(path) {
832 let call_id = MacroCallLoc { def, ast_id }.id(self.db);
832 if let Some(tt) = self.db.macro_expand(call_id).ok() { 833 if let Some(tt) = self.db.macro_expand(call_id).ok() {
833 if let Some(expr) = mbe::token_tree_to_expr(&tt).ok() { 834 if let Some(expr) = mbe::token_tree_to_expr(&tt).ok() {
834 log::debug!("macro expansion {}", expr.syntax().debug_dump()); 835 log::debug!("macro expansion {}", expr.syntax().debug_dump());
diff --git a/crates/ra_hir/src/generics.rs b/crates/ra_hir/src/generics.rs
index 2e52c5871..c29b96f50 100644
--- a/crates/ra_hir/src/generics.rs
+++ b/crates/ra_hir/src/generics.rs
@@ -8,7 +8,7 @@ use std::sync::Arc;
8use ra_syntax::ast::{self, NameOwner, TypeParamsOwner, TypeBoundsOwner}; 8use ra_syntax::ast::{self, NameOwner, TypeParamsOwner, TypeBoundsOwner};
9 9
10use crate::{ 10use crate::{
11 db::DefDatabase, 11 db::{ HirDatabase, DefDatabase},
12 Name, AsName, Function, Struct, Enum, Trait, TypeAlias, ImplBlock, Container, path::Path, type_ref::TypeRef, AdtDef 12 Name, AsName, Function, Struct, Enum, Trait, TypeAlias, ImplBlock, Container, path::Path, type_ref::TypeRef, AdtDef
13}; 13};
14 14
@@ -32,8 +32,8 @@ pub struct GenericParams {
32/// where clauses like `where T: Foo + Bar` are turned into multiple of these. 32/// where clauses like `where T: Foo + Bar` are turned into multiple of these.
33#[derive(Clone, PartialEq, Eq, Debug)] 33#[derive(Clone, PartialEq, Eq, Debug)]
34pub struct WherePredicate { 34pub struct WherePredicate {
35 type_ref: TypeRef, 35 pub(crate) type_ref: TypeRef,
36 trait_ref: Path, 36 pub(crate) trait_ref: Path,
37} 37}
38 38
39// FIXME: consts can have type parameters from their parents (i.e. associated consts of traits) 39// FIXME: consts can have type parameters from their parents (i.e. associated consts of traits)
@@ -90,8 +90,17 @@ impl GenericParams {
90 fn fill_params(&mut self, params: &ast::TypeParamList, start: u32) { 90 fn fill_params(&mut self, params: &ast::TypeParamList, start: u32) {
91 for (idx, type_param) in params.type_params().enumerate() { 91 for (idx, type_param) in params.type_params().enumerate() {
92 let name = type_param.name().map(AsName::as_name).unwrap_or_else(Name::missing); 92 let name = type_param.name().map(AsName::as_name).unwrap_or_else(Name::missing);
93 let param = GenericParam { idx: idx as u32 + start, name }; 93 let param = GenericParam { idx: idx as u32 + start, name: name.clone() };
94 self.params.push(param); 94 self.params.push(param);
95
96 let type_ref = TypeRef::Path(name.into());
97 for bound in type_param
98 .type_bound_list()
99 .iter()
100 .flat_map(|type_bound_list| type_bound_list.bounds())
101 {
102 self.add_where_predicate_from_bound(bound, type_ref.clone());
103 }
95 } 104 }
96 } 105 }
97 106
@@ -101,26 +110,28 @@ impl GenericParams {
101 Some(type_ref) => type_ref, 110 Some(type_ref) => type_ref,
102 None => continue, 111 None => continue,
103 }; 112 };
113 let type_ref = TypeRef::from_ast(type_ref);
104 for bound in pred.type_bound_list().iter().flat_map(|l| l.bounds()) { 114 for bound in pred.type_bound_list().iter().flat_map(|l| l.bounds()) {
105 let path = bound 115 self.add_where_predicate_from_bound(bound, type_ref.clone());
106 .type_ref()
107 .and_then(|tr| match tr.kind() {
108 ast::TypeRefKind::PathType(path) => path.path(),
109 _ => None,
110 })
111 .and_then(Path::from_ast);
112 let path = match path {
113 Some(p) => p,
114 None => continue,
115 };
116 self.where_predicates.push(WherePredicate {
117 type_ref: TypeRef::from_ast(type_ref),
118 trait_ref: path,
119 });
120 } 116 }
121 } 117 }
122 } 118 }
123 119
120 fn add_where_predicate_from_bound(&mut self, bound: &ast::TypeBound, type_ref: TypeRef) {
121 let path = bound
122 .type_ref()
123 .and_then(|tr| match tr.kind() {
124 ast::TypeRefKind::PathType(path) => path.path(),
125 _ => None,
126 })
127 .and_then(Path::from_ast);
128 let path = match path {
129 Some(p) => p,
130 None => return,
131 };
132 self.where_predicates.push(WherePredicate { type_ref, trait_ref: path });
133 }
134
124 pub(crate) fn find_by_name(&self, name: &Name) -> Option<&GenericParam> { 135 pub(crate) fn find_by_name(&self, name: &Name) -> Option<&GenericParam> {
125 self.params.iter().find(|p| &p.name == name) 136 self.params.iter().find(|p| &p.name == name)
126 } 137 }
@@ -148,6 +159,19 @@ impl GenericParams {
148 } 159 }
149} 160}
150 161
162impl GenericDef {
163 pub(crate) fn resolver(&self, db: &impl HirDatabase) -> crate::Resolver {
164 match self {
165 GenericDef::Function(inner) => inner.resolver(db),
166 GenericDef::Struct(inner) => inner.resolver(db),
167 GenericDef::Enum(inner) => inner.resolver(db),
168 GenericDef::Trait(inner) => inner.resolver(db),
169 GenericDef::TypeAlias(inner) => inner.resolver(db),
170 GenericDef::ImplBlock(inner) => inner.resolver(db),
171 }
172 }
173}
174
151impl From<Container> for GenericDef { 175impl From<Container> for GenericDef {
152 fn from(c: Container) -> Self { 176 fn from(c: Container) -> Self {
153 match c { 177 match c {
diff --git a/crates/ra_hir/src/impl_block.rs b/crates/ra_hir/src/impl_block.rs
index a8a466e43..b7dd775f1 100644
--- a/crates/ra_hir/src/impl_block.rs
+++ b/crates/ra_hir/src/impl_block.rs
@@ -93,6 +93,10 @@ impl ImplBlock {
93 db.impls_in_module(self.module).impls[self.impl_id].items().to_vec() 93 db.impls_in_module(self.module).impls[self.impl_id].items().to_vec()
94 } 94 }
95 95
96 pub fn is_negative(&self, db: &impl DefDatabase) -> bool {
97 db.impls_in_module(self.module).impls[self.impl_id].negative
98 }
99
96 pub(crate) fn resolver(&self, db: &impl DefDatabase) -> Resolver { 100 pub(crate) fn resolver(&self, db: &impl DefDatabase) -> Resolver {
97 let r = self.module().resolver(db); 101 let r = self.module().resolver(db);
98 // add generic params, if present 102 // add generic params, if present
@@ -108,6 +112,7 @@ pub struct ImplData {
108 target_trait: Option<TypeRef>, 112 target_trait: Option<TypeRef>,
109 target_type: TypeRef, 113 target_type: TypeRef,
110 items: Vec<ImplItem>, 114 items: Vec<ImplItem>,
115 negative: bool,
111} 116}
112 117
113impl ImplData { 118impl ImplData {
@@ -120,6 +125,7 @@ impl ImplData {
120 let target_trait = node.target_trait().map(TypeRef::from_ast); 125 let target_trait = node.target_trait().map(TypeRef::from_ast);
121 let target_type = TypeRef::from_ast_opt(node.target_type()); 126 let target_type = TypeRef::from_ast_opt(node.target_type());
122 let ctx = LocationCtx::new(db, module, file_id); 127 let ctx = LocationCtx::new(db, module, file_id);
128 let negative = node.is_negative();
123 let items = if let Some(item_list) = node.item_list() { 129 let items = if let Some(item_list) = node.item_list() {
124 item_list 130 item_list
125 .impl_items() 131 .impl_items()
@@ -132,7 +138,7 @@ impl ImplData {
132 } else { 138 } else {
133 Vec::new() 139 Vec::new()
134 }; 140 };
135 ImplData { target_trait, target_type, items } 141 ImplData { target_trait, target_type, items, negative }
136 } 142 }
137 143
138 pub fn target_trait(&self) -> Option<&TypeRef> { 144 pub fn target_trait(&self) -> Option<&TypeRef> {
diff --git a/crates/ra_hir/src/marks.rs b/crates/ra_hir/src/marks.rs
index 5b6400042..2d831f0d8 100644
--- a/crates/ra_hir/src/marks.rs
+++ b/crates/ra_hir/src/marks.rs
@@ -9,4 +9,5 @@ test_utils::marks!(
9 glob_across_crates 9 glob_across_crates
10 std_prelude 10 std_prelude
11 match_ergonomics_ref 11 match_ergonomics_ref
12 trait_resolution_on_fn_type
12); 13);
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs
index a450d7b84..0290b3474 100644
--- a/crates/ra_hir/src/nameres.rs
+++ b/crates/ra_hir/src/nameres.rs
@@ -272,8 +272,8 @@ impl CrateDefMap {
272 (res.resolved_def, res.segment_index) 272 (res.resolved_def, res.segment_index)
273 } 273 }
274 274
275 pub(crate) fn find_macro(&self, name: &Name) -> Option<&MacroDefId> { 275 pub(crate) fn find_macro(&self, name: &Name) -> Option<MacroDefId> {
276 self.public_macros.get(name).or(self.local_macros.get(name)) 276 self.public_macros.get(name).or(self.local_macros.get(name)).map(|it| *it)
277 } 277 }
278 278
279 // Returns Yes if we are sure that additions to `ItemMap` wouldn't change 279 // Returns Yes if we are sure that additions to `ItemMap` wouldn't change
diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs
index 707556ef8..3874e28bf 100644
--- a/crates/ra_hir/src/resolve.rs
+++ b/crates/ra_hir/src/resolve.rs
@@ -1,16 +1,12 @@
1//! Name resolution. 1//! Name resolution.
2use std::sync::Arc; 2use std::sync::Arc;
3 3
4use ra_syntax::ast; 4use rustc_hash::{FxHashMap, FxHashSet};
5
6use rustc_hash::FxHashMap;
7 5
8use crate::{ 6use crate::{
9 ModuleDef, Trait, 7 ModuleDef, Trait,
10 code_model_api::Crate, 8 code_model_api::Crate,
11 MacroCallId, 9 MacroDefId,
12 MacroCallLoc,
13 AstId,
14 db::HirDatabase, 10 db::HirDatabase,
15 name::{Name, KnownName}, 11 name::{Name, KnownName},
16 nameres::{PerNs, CrateDefMap, CrateModuleId}, 12 nameres::{PerNs, CrateDefMap, CrateModuleId},
@@ -134,16 +130,9 @@ impl Resolver {
134 resolution 130 resolution
135 } 131 }
136 132
137 pub fn resolve_macro_call( 133 pub(crate) fn resolve_macro_call(&self, path: Option<Path>) -> Option<MacroDefId> {
138 &self,
139 db: &impl HirDatabase,
140 path: Option<Path>,
141 ast_id: AstId<ast::MacroCall>,
142 ) -> Option<MacroCallId> {
143 let name = path.and_then(|path| path.expand_macro_expr()).unwrap_or_else(Name::missing); 134 let name = path.and_then(|path| path.expand_macro_expr()).unwrap_or_else(Name::missing);
144 let def_id = self.module().and_then(|(module, _)| module.find_macro(&name))?; 135 self.module()?.0.find_macro(&name)
145 let call_loc = MacroCallLoc { def: *def_id, ast_id }.id(db);
146 Some(call_loc)
147 } 136 }
148 137
149 /// Returns the resolved path segments 138 /// Returns the resolved path segments
@@ -193,19 +182,18 @@ impl Resolver {
193 names 182 names
194 } 183 }
195 184
196 pub(crate) fn traits_in_scope<'a>(&'a self) -> impl Iterator<Item = Trait> + 'a { 185 pub(crate) fn traits_in_scope(&self, db: &impl HirDatabase) -> FxHashSet<Trait> {
197 // FIXME prelude 186 let mut traits = FxHashSet::default();
198 self.scopes 187 for scope in &self.scopes {
199 .iter() 188 if let Scope::ModuleScope(m) = scope {
200 .rev() 189 if let Some(prelude) = m.crate_def_map.prelude() {
201 .flat_map(|scope| { 190 let prelude_def_map = db.crate_def_map(prelude.krate);
202 match scope { 191 traits.extend(prelude_def_map[prelude.module_id].scope.traits());
203 Scope::ModuleScope(m) => Some(m.crate_def_map[m.module_id].scope.traits()),
204 _ => None,
205 } 192 }
206 .into_iter() 193 traits.extend(m.crate_def_map[m.module_id].scope.traits());
207 }) 194 }
208 .flatten() 195 }
196 traits
209 } 197 }
210 198
211 fn module(&self) -> Option<(&CrateDefMap, CrateModuleId)> { 199 fn module(&self) -> Option<(&CrateDefMap, CrateModuleId)> {
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs
index 31bf13425..179faebfb 100644
--- a/crates/ra_hir/src/source_binder.rs
+++ b/crates/ra_hir/src/source_binder.rs
@@ -20,7 +20,7 @@ use crate::{
20 HirDatabase, Function, Struct, Enum, Const, Static, Either, DefWithBody, PerNs, Name, 20 HirDatabase, Function, Struct, Enum, Const, Static, Either, DefWithBody, PerNs, Name,
21 AsName, Module, HirFileId, Crate, Trait, Resolver, Ty,Path, 21 AsName, Module, HirFileId, Crate, Trait, Resolver, Ty,Path,
22 expr::{BodySourceMap, scope::{ScopeId, ExprScopes}}, 22 expr::{BodySourceMap, scope::{ScopeId, ExprScopes}},
23 ids::{LocationCtx,MacroCallId}, 23 ids::{LocationCtx, MacroDefId},
24 docs::{docs_from_ast,Documentation}, 24 docs::{docs_from_ast,Documentation},
25 expr, AstId, 25 expr, AstId,
26}; 26};
@@ -191,13 +191,12 @@ pub enum PathResolution {
191 191
192#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 192#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
193pub struct MacroByExampleDef { 193pub struct MacroByExampleDef {
194 pub(crate) id: MacroCallId, 194 pub(crate) id: MacroDefId,
195} 195}
196 196
197impl MacroByExampleDef { 197impl MacroByExampleDef {
198 pub fn source(&self, db: &impl HirDatabase) -> (HirFileId, TreeArc<ast::MacroCall>) { 198 pub fn source(&self, db: &impl HirDatabase) -> (HirFileId, TreeArc<ast::MacroCall>) {
199 let loc = self.id.loc(db); 199 (self.id.0.file_id(), self.id.0.to_node(db))
200 (self.id.into(), loc.def.0.to_node(db))
201 } 200 }
202} 201}
203 202
@@ -284,21 +283,9 @@ impl SourceAnalyzer {
284 self.infer.as_ref()?.field_resolution(expr_id) 283 self.infer.as_ref()?.field_resolution(expr_id)
285 } 284 }
286 285
287 pub fn resolve_macro_call( 286 pub fn resolve_macro_call(&self, macro_call: &ast::MacroCall) -> Option<MacroByExampleDef> {
288 &self, 287 let id = self.resolver.resolve_macro_call(macro_call.path().and_then(Path::from_ast))?;
289 db: &impl HirDatabase, 288 Some(MacroByExampleDef { id })
290 file_id: FileId,
291 macro_call: &ast::MacroCall,
292 ) -> Option<MacroByExampleDef> {
293 let hir_id = file_id.into();
294 let ast_id = db.ast_id_map(hir_id).ast_id(macro_call).with_file_id(hir_id);
295 let call_id = self.resolver.resolve_macro_call(
296 db,
297 macro_call.path().and_then(Path::from_ast),
298 ast_id,
299 );
300
301 call_id.map(|id| MacroByExampleDef { id })
302 } 289 }
303 290
304 pub fn resolve_hir_path( 291 pub fn resolve_hir_path(
diff --git a/crates/ra_hir/src/traits.rs b/crates/ra_hir/src/traits.rs
index 15f0977b7..dfe883fa4 100644
--- a/crates/ra_hir/src/traits.rs
+++ b/crates/ra_hir/src/traits.rs
@@ -11,6 +11,7 @@ use crate::{Function, Const, TypeAlias, Name, DefDatabase, Trait, ids::LocationC
11pub struct TraitData { 11pub struct TraitData {
12 name: Option<Name>, 12 name: Option<Name>,
13 items: Vec<TraitItem>, 13 items: Vec<TraitItem>,
14 auto: bool,
14} 15}
15 16
16impl TraitData { 17impl TraitData {
@@ -19,6 +20,7 @@ impl TraitData {
19 let name = node.name().map(|n| n.as_name()); 20 let name = node.name().map(|n| n.as_name());
20 let module = tr.module(db); 21 let module = tr.module(db);
21 let ctx = LocationCtx::new(db, module, file_id); 22 let ctx = LocationCtx::new(db, module, file_id);
23 let auto = node.is_auto();
22 let items = if let Some(item_list) = node.item_list() { 24 let items = if let Some(item_list) = node.item_list() {
23 item_list 25 item_list
24 .impl_items() 26 .impl_items()
@@ -31,7 +33,7 @@ impl TraitData {
31 } else { 33 } else {
32 Vec::new() 34 Vec::new()
33 }; 35 };
34 Arc::new(TraitData { name, items }) 36 Arc::new(TraitData { name, items, auto })
35 } 37 }
36 38
37 pub(crate) fn name(&self) -> &Option<Name> { 39 pub(crate) fn name(&self) -> &Option<Name> {
@@ -41,6 +43,10 @@ impl TraitData {
41 pub(crate) fn items(&self) -> &[TraitItem] { 43 pub(crate) fn items(&self) -> &[TraitItem] {
42 &self.items 44 &self.items
43 } 45 }
46
47 pub(crate) fn is_auto(&self) -> bool {
48 self.auto
49 }
44} 50}
45 51
46#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 52#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index f4eee835f..cfe07156b 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -19,7 +19,7 @@ use std::{fmt, mem};
19use crate::{Name, AdtDef, type_ref::Mutability, db::HirDatabase, Trait, GenericParams}; 19use crate::{Name, AdtDef, type_ref::Mutability, db::HirDatabase, Trait, GenericParams};
20use display::{HirDisplay, HirFormatter}; 20use display::{HirDisplay, HirFormatter};
21 21
22pub(crate) use lower::{TypableDef, type_for_def, type_for_field, callable_item_sig}; 22pub(crate) use lower::{TypableDef, type_for_def, type_for_field, callable_item_sig, generic_predicates};
23pub(crate) use infer::{infer, InferenceResult, InferTy}; 23pub(crate) use infer::{infer, InferenceResult, InferTy};
24pub use lower::CallableDef; 24pub use lower::CallableDef;
25 25
@@ -234,13 +234,42 @@ impl TraitRef {
234 } 234 }
235} 235}
236 236
237/// Like `generics::WherePredicate`, but with resolved types: A condition on the
238/// parameters of a generic item.
239#[derive(Debug, Clone, PartialEq, Eq, Hash)]
240pub enum GenericPredicate {
241 /// The given trait needs to be implemented for its type parameters.
242 Implemented(TraitRef),
243 /// We couldn't resolve the trait reference. (If some type parameters can't
244 /// be resolved, they will just be Unknown).
245 Error,
246}
247
248impl GenericPredicate {
249 pub fn is_error(&self) -> bool {
250 match self {
251 GenericPredicate::Error => true,
252 _ => false,
253 }
254 }
255
256 pub fn subst(self, substs: &Substs) -> GenericPredicate {
257 match self {
258 GenericPredicate::Implemented(trait_ref) => {
259 GenericPredicate::Implemented(trait_ref.subst(substs))
260 }
261 GenericPredicate::Error => self,
262 }
263 }
264}
265
237/// Basically a claim (currently not validated / checked) that the contained 266/// Basically a claim (currently not validated / checked) that the contained
238/// type / trait ref contains no inference variables; any inference variables it 267/// type / trait ref contains no inference variables; any inference variables it
239/// contained have been replaced by bound variables, and `num_vars` tells us how 268/// contained have been replaced by bound variables, and `num_vars` tells us how
240/// many there are. This is used to erase irrelevant differences between types 269/// many there are. This is used to erase irrelevant differences between types
241/// before using them in queries. 270/// before using them in queries.
242#[derive(Debug, Clone, PartialEq, Eq, Hash)] 271#[derive(Debug, Clone, PartialEq, Eq, Hash)]
243pub(crate) struct Canonical<T> { 272pub struct Canonical<T> {
244 pub value: T, 273 pub value: T,
245 pub num_vars: usize, 274 pub num_vars: usize,
246} 275}
@@ -534,3 +563,20 @@ impl HirDisplay for Ty {
534 Ok(()) 563 Ok(())
535 } 564 }
536} 565}
566
567impl HirDisplay for TraitRef {
568 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
569 write!(
570 f,
571 "{}: {}",
572 self.substs[0].display(f.db),
573 self.trait_.name(f.db).unwrap_or_else(Name::missing)
574 )?;
575 if self.substs.len() > 1 {
576 write!(f, "<")?;
577 f.write_joined(&self.substs[1..], ", ")?;
578 write!(f, ">")?;
579 }
580 Ok(())
581 }
582}
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs
index edce1afe7..1e7d97f51 100644
--- a/crates/ra_hir/src/ty/infer.rs
+++ b/crates/ra_hir/src/ty/infer.rs
@@ -328,8 +328,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
328 Obligation::Trait(tr) => { 328 Obligation::Trait(tr) => {
329 let canonicalized = self.canonicalizer().canonicalize_trait_ref(tr.clone()); 329 let canonicalized = self.canonicalizer().canonicalize_trait_ref(tr.clone());
330 ( 330 (
331 super::traits::implements( 331 self.db.implements(
332 self.db,
333 self.resolver.krate().unwrap(), 332 self.resolver.krate().unwrap(),
334 canonicalized.value.clone(), 333 canonicalized.value.clone(),
335 ), 334 ),
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs
index 8bab7e54b..09d26ce5a 100644
--- a/crates/ra_hir/src/ty/lower.rs
+++ b/crates/ra_hir/src/ty/lower.rs
@@ -5,6 +5,7 @@
5//! - Building the type for an item: This happens through the `type_for_def` query. 5//! - Building the type for an item: This happens through the `type_for_def` query.
6//! 6//!
7//! This usually involves resolving names, collecting generic arguments etc. 7//! This usually involves resolving names, collecting generic arguments etc.
8use std::sync::Arc;
8use std::iter; 9use std::iter;
9 10
10use crate::{ 11use crate::{
@@ -18,9 +19,9 @@ use crate::{
18 resolve::{Resolver, Resolution}, 19 resolve::{Resolver, Resolution},
19 path::{PathSegment, GenericArg}, 20 path::{PathSegment, GenericArg},
20 generics::{GenericParams, HasGenericParams}, 21 generics::{GenericParams, HasGenericParams},
21 adt::VariantDef, Trait 22 adt::VariantDef, Trait, generics::{ WherePredicate, GenericDef}
22}; 23};
23use super::{Ty, primitive, FnSig, Substs, TypeCtor, TraitRef}; 24use super::{Ty, primitive, FnSig, Substs, TypeCtor, TraitRef, GenericPredicate};
24 25
25impl Ty { 26impl Ty {
26 pub(crate) fn from_hir(db: &impl HirDatabase, resolver: &Resolver, type_ref: &TypeRef) -> Self { 27 pub(crate) fn from_hir(db: &impl HirDatabase, resolver: &Resolver, type_ref: &TypeRef) -> Self {
@@ -208,16 +209,12 @@ pub(super) fn substs_from_path_segment(
208} 209}
209 210
210impl TraitRef { 211impl TraitRef {
211 pub(crate) fn from_hir( 212 pub(crate) fn from_path(
212 db: &impl HirDatabase, 213 db: &impl HirDatabase,
213 resolver: &Resolver, 214 resolver: &Resolver,
214 type_ref: &TypeRef, 215 path: &Path,
215 explicit_self_ty: Option<Ty>, 216 explicit_self_ty: Option<Ty>,
216 ) -> Option<Self> { 217 ) -> Option<Self> {
217 let path = match type_ref {
218 TypeRef::Path(path) => path,
219 _ => return None,
220 };
221 let resolved = match resolver.resolve_path(db, &path).take_types()? { 218 let resolved = match resolver.resolve_path(db, &path).take_types()? {
222 Resolution::Def(ModuleDef::Trait(tr)) => tr, 219 Resolution::Def(ModuleDef::Trait(tr)) => tr,
223 _ => return None, 220 _ => return None,
@@ -232,6 +229,19 @@ impl TraitRef {
232 Some(TraitRef { trait_: resolved, substs }) 229 Some(TraitRef { trait_: resolved, substs })
233 } 230 }
234 231
232 pub(crate) fn from_hir(
233 db: &impl HirDatabase,
234 resolver: &Resolver,
235 type_ref: &TypeRef,
236 explicit_self_ty: Option<Ty>,
237 ) -> Option<Self> {
238 let path = match type_ref {
239 TypeRef::Path(path) => path,
240 _ => return None,
241 };
242 TraitRef::from_path(db, resolver, path, explicit_self_ty)
243 }
244
235 fn substs_from_path( 245 fn substs_from_path(
236 db: &impl HirDatabase, 246 db: &impl HirDatabase,
237 resolver: &Resolver, 247 resolver: &Resolver,
@@ -246,6 +256,15 @@ impl TraitRef {
246 let substs = Substs::identity(&trait_.generic_params(db)); 256 let substs = Substs::identity(&trait_.generic_params(db));
247 TraitRef { trait_, substs } 257 TraitRef { trait_, substs }
248 } 258 }
259
260 pub(crate) fn for_where_predicate(
261 db: &impl HirDatabase,
262 resolver: &Resolver,
263 pred: &WherePredicate,
264 ) -> Option<TraitRef> {
265 let self_ty = Ty::from_hir(db, resolver, &pred.type_ref);
266 TraitRef::from_path(db, resolver, &pred.trait_ref, Some(self_ty))
267 }
249} 268}
250 269
251/// Build the declared type of an item. This depends on the namespace; e.g. for 270/// Build the declared type of an item. This depends on the namespace; e.g. for
@@ -294,6 +313,24 @@ pub(crate) fn type_for_field(db: &impl HirDatabase, field: StructField) -> Ty {
294 Ty::from_hir(db, &resolver, type_ref) 313 Ty::from_hir(db, &resolver, type_ref)
295} 314}
296 315
316/// Resolve the where clause(s) of an item with generics.
317pub(crate) fn generic_predicates(
318 db: &impl HirDatabase,
319 def: GenericDef,
320) -> Arc<[GenericPredicate]> {
321 let resolver = def.resolver(db);
322 let generic_params = def.generic_params(db);
323 let predicates = generic_params
324 .where_predicates
325 .iter()
326 .map(|pred| {
327 TraitRef::for_where_predicate(db, &resolver, pred)
328 .map_or(GenericPredicate::Error, GenericPredicate::Implemented)
329 })
330 .collect::<Vec<_>>();
331 predicates.into()
332}
333
297fn fn_sig_for_fn(db: &impl HirDatabase, def: Function) -> FnSig { 334fn fn_sig_for_fn(db: &impl HirDatabase, def: Function) -> FnSig {
298 let signature = def.signature(db); 335 let signature = def.signature(db);
299 let resolver = def.resolver(db); 336 let resolver = def.resolver(db);
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs
index 607e9ba79..34817a5ec 100644
--- a/crates/ra_hir/src/ty/method_resolution.rs
+++ b/crates/ra_hir/src/ty/method_resolution.rs
@@ -75,11 +75,13 @@ impl CrateImplBlocks {
75 75
76 let target_ty = impl_block.target_ty(db); 76 let target_ty = impl_block.target_ty(db);
77 77
78 if let Some(tr) = impl_block.target_trait_ref(db) { 78 if impl_block.target_trait(db).is_some() {
79 self.impls_by_trait 79 if let Some(tr) = impl_block.target_trait_ref(db) {
80 .entry(tr.trait_) 80 self.impls_by_trait
81 .or_insert_with(Vec::new) 81 .entry(tr.trait_)
82 .push((module.module_id, impl_id)); 82 .or_insert_with(Vec::new)
83 .push((module.module_id, impl_id));
84 }
83 } else { 85 } else {
84 if let Some(target_ty_fp) = TyFingerprint::for_impl(&target_ty) { 86 if let Some(target_ty_fp) = TyFingerprint::for_impl(&target_ty) {
85 self.impls 87 self.impls
@@ -183,7 +185,7 @@ fn iterate_trait_method_candidates<T>(
183 mut callback: impl FnMut(&Ty, Function) -> Option<T>, 185 mut callback: impl FnMut(&Ty, Function) -> Option<T>,
184) -> Option<T> { 186) -> Option<T> {
185 let krate = resolver.krate()?; 187 let krate = resolver.krate()?;
186 'traits: for t in resolver.traits_in_scope() { 188 'traits: for t in resolver.traits_in_scope(db) {
187 let data = t.trait_data(db); 189 let data = t.trait_data(db);
188 // we'll be lazy about checking whether the type implements the 190 // we'll be lazy about checking whether the type implements the
189 // trait, but if we find out it doesn't, we'll skip the rest of the 191 // trait, but if we find out it doesn't, we'll skip the rest of the
@@ -196,8 +198,7 @@ fn iterate_trait_method_candidates<T>(
196 if name.map_or(true, |name| sig.name() == name) && sig.has_self_param() { 198 if name.map_or(true, |name| sig.name() == name) && sig.has_self_param() {
197 if !known_implemented { 199 if !known_implemented {
198 let trait_ref = canonical_trait_ref(db, t, ty.clone()); 200 let trait_ref = canonical_trait_ref(db, t, ty.clone());
199 // FIXME cache this implements check (without solution) in a query? 201 if db.implements(krate, trait_ref).is_none() {
200 if super::traits::implements(db, krate, trait_ref).is_none() {
201 continue 'traits; 202 continue 'traits;
202 } 203 }
203 } 204 }
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index a38fe35c7..978cc2587 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -2502,6 +2502,50 @@ fn test() { (&S).foo()<|>; }
2502} 2502}
2503 2503
2504#[test] 2504#[test]
2505fn method_resolution_trait_from_prelude() {
2506 let (mut db, pos) = MockDatabase::with_position(
2507 r#"
2508//- /main.rs
2509struct S;
2510impl Clone for S {}
2511
2512fn test() {
2513 S.clone()<|>;
2514}
2515
2516//- /lib.rs
2517#[prelude_import] use foo::*;
2518
2519mod foo {
2520 trait Clone {
2521 fn clone(&self) -> Self;
2522 }
2523}
2524"#,
2525 );
2526 db.set_crate_graph_from_fixture(crate_graph! {
2527 "main": ("/main.rs", ["other_crate"]),
2528 "other_crate": ("/lib.rs", []),
2529 });
2530 assert_eq!("S", type_at_pos(&db, pos));
2531}
2532
2533#[test]
2534fn method_resolution_where_clause_for_unknown_trait() {
2535 // The blanket impl shouldn't apply because we can't even resolve UnknownTrait
2536 let t = type_at(
2537 r#"
2538//- /main.rs
2539trait Trait { fn foo(self) -> u128; }
2540struct S;
2541impl<T> Trait for T where T: UnknownTrait {}
2542fn test() { (&S).foo()<|>; }
2543"#,
2544 );
2545 assert_eq!(t, "{unknown}");
2546}
2547
2548#[test]
2505fn method_resolution_where_clause_not_met() { 2549fn method_resolution_where_clause_not_met() {
2506 // The blanket impl shouldn't apply because we can't prove S: Clone 2550 // The blanket impl shouldn't apply because we can't prove S: Clone
2507 let t = type_at( 2551 let t = type_at(
@@ -2510,12 +2554,122 @@ fn method_resolution_where_clause_not_met() {
2510trait Clone {} 2554trait Clone {}
2511trait Trait { fn foo(self) -> u128; } 2555trait Trait { fn foo(self) -> u128; }
2512struct S; 2556struct S;
2513impl S { fn foo(self) -> i8 { 0 } } 2557impl<T> Trait for T where T: Clone {}
2514impl<T> Trait for T where T: Clone { fn foo(self) -> u128 { 0 } }
2515fn test() { (&S).foo()<|>; } 2558fn test() { (&S).foo()<|>; }
2516"#, 2559"#,
2517 ); 2560 );
2518 assert_eq!(t, "i8"); 2561 // This is also to make sure that we don't resolve to the foo method just
2562 // because that's the only method named foo we can find, which would make
2563 // the below tests not work
2564 assert_eq!(t, "{unknown}");
2565}
2566
2567#[test]
2568fn method_resolution_where_clause_inline_not_met() {
2569 // The blanket impl shouldn't apply because we can't prove S: Clone
2570 let t = type_at(
2571 r#"
2572//- /main.rs
2573trait Clone {}
2574trait Trait { fn foo(self) -> u128; }
2575struct S;
2576impl<T: Clone> Trait for T {}
2577fn test() { (&S).foo()<|>; }
2578"#,
2579 );
2580 assert_eq!(t, "{unknown}");
2581}
2582
2583#[test]
2584fn method_resolution_where_clause_1() {
2585 let t = type_at(
2586 r#"
2587//- /main.rs
2588trait Clone {}
2589trait Trait { fn foo(self) -> u128; }
2590struct S;
2591impl Clone for S {};
2592impl<T> Trait for T where T: Clone {}
2593fn test() { S.foo()<|>; }
2594"#,
2595 );
2596 assert_eq!(t, "u128");
2597}
2598
2599#[test]
2600fn method_resolution_where_clause_2() {
2601 let t = type_at(
2602 r#"
2603//- /main.rs
2604trait Into<T> { fn into(self) -> T; }
2605trait From<T> { fn from(other: T) -> Self; }
2606struct S1;
2607struct S2;
2608impl From<S2> for S1 {};
2609impl<T, U> Into<U> for T where U: From<T> {}
2610fn test() { S2.into()<|>; }
2611"#,
2612 );
2613 assert_eq!(t, "S1");
2614}
2615
2616#[test]
2617fn method_resolution_where_clause_inline() {
2618 let t = type_at(
2619 r#"
2620//- /main.rs
2621trait Into<T> { fn into(self) -> T; }
2622trait From<T> { fn from(other: T) -> Self; }
2623struct S1;
2624struct S2;
2625impl From<S2> for S1 {};
2626impl<T, U: From<T>> Into<U> for T {}
2627fn test() { S2.into()<|>; }
2628"#,
2629 );
2630 assert_eq!(t, "S1");
2631}
2632
2633#[test]
2634fn method_resolution_encountering_fn_type() {
2635 covers!(trait_resolution_on_fn_type);
2636 type_at(
2637 r#"
2638//- /main.rs
2639fn foo() {}
2640trait FnOnce { fn call(self); }
2641fn test() { foo.call()<|>; }
2642"#,
2643 );
2644}
2645
2646#[test]
2647fn method_resolution_slow() {
2648 // this can get quite slow if we set the solver size limit too high
2649 let t = type_at(
2650 r#"
2651//- /main.rs
2652trait SendX {}
2653
2654struct S1; impl SendX for S1;
2655struct S2; impl SendX for S2;
2656struct U1;
2657
2658trait Trait { fn method(self); }
2659
2660struct X1<A, B> {}
2661impl<A, B> SendX for X1<A, B> where A: SendX, B: SendX {}
2662
2663struct S<B, C> {}
2664
2665trait FnX {}
2666
2667impl<B, C> Trait for S<B, C> where C: FnX, B: SendX {}
2668
2669fn test() { (S {}).method()<|>; }
2670"#,
2671 );
2672 assert_eq!(t, "{unknown}");
2519} 2673}
2520 2674
2521fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { 2675fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String {
diff --git a/crates/ra_hir/src/ty/traits.rs b/crates/ra_hir/src/ty/traits.rs
index a1ed0c028..4260f7ef7 100644
--- a/crates/ra_hir/src/ty/traits.rs
+++ b/crates/ra_hir/src/ty/traits.rs
@@ -1,6 +1,7 @@
1//! Trait solving using Chalk. 1//! Trait solving using Chalk.
2use std::sync::{Arc, Mutex}; 2use std::sync::{Arc, Mutex};
3 3
4use rustc_hash::FxHashSet;
4use log::debug; 5use log::debug;
5use chalk_ir::cast::Cast; 6use chalk_ir::cast::Cast;
6 7
@@ -13,6 +14,11 @@ mod chalk;
13 14
14pub(crate) type Solver = chalk_solve::Solver; 15pub(crate) type Solver = chalk_solve::Solver;
15 16
17/// This controls the maximum size of types Chalk considers. If we set this too
18/// high, we can run into slow edge cases; if we set it too low, Chalk won't
19/// find some solutions.
20const CHALK_SOLVER_MAX_SIZE: usize = 2;
21
16#[derive(Debug, Copy, Clone)] 22#[derive(Debug, Copy, Clone)]
17struct ChalkContext<'a, DB> { 23struct ChalkContext<'a, DB> {
18 db: &'a DB, 24 db: &'a DB,
@@ -21,7 +27,8 @@ struct ChalkContext<'a, DB> {
21 27
22pub(crate) fn solver(_db: &impl HirDatabase, _krate: Crate) -> Arc<Mutex<Solver>> { 28pub(crate) fn solver(_db: &impl HirDatabase, _krate: Crate) -> Arc<Mutex<Solver>> {
23 // krate parameter is just so we cache a unique solver per crate 29 // krate parameter is just so we cache a unique solver per crate
24 let solver_choice = chalk_solve::SolverChoice::SLG { max_size: 10 }; 30 let solver_choice = chalk_solve::SolverChoice::SLG { max_size: CHALK_SOLVER_MAX_SIZE };
31 debug!("Creating new solver for crate {:?}", _krate);
25 Arc::new(Mutex::new(solver_choice.into_solver())) 32 Arc::new(Mutex::new(solver_choice.into_solver()))
26} 33}
27 34
@@ -31,7 +38,7 @@ pub(crate) fn impls_for_trait(
31 krate: Crate, 38 krate: Crate,
32 trait_: Trait, 39 trait_: Trait,
33) -> Arc<[ImplBlock]> { 40) -> Arc<[ImplBlock]> {
34 let mut impls = Vec::new(); 41 let mut impls = FxHashSet::default();
35 // We call the query recursively here. On the one hand, this means we can 42 // We call the query recursively here. On the one hand, this means we can
36 // reuse results from queries for different crates; on the other hand, this 43 // reuse results from queries for different crates; on the other hand, this
37 // will only ever get called for a few crates near the root of the tree (the 44 // will only ever get called for a few crates near the root of the tree (the
@@ -42,7 +49,7 @@ pub(crate) fn impls_for_trait(
42 } 49 }
43 let crate_impl_blocks = db.impls_in_crate(krate); 50 let crate_impl_blocks = db.impls_in_crate(krate);
44 impls.extend(crate_impl_blocks.lookup_impl_blocks_for_trait(&trait_)); 51 impls.extend(crate_impl_blocks.lookup_impl_blocks_for_trait(&trait_));
45 impls.into() 52 impls.into_iter().collect::<Vec<_>>().into()
46} 53}
47 54
48fn solve( 55fn solve(
@@ -52,6 +59,7 @@ fn solve(
52) -> Option<chalk_solve::Solution> { 59) -> Option<chalk_solve::Solution> {
53 let context = ChalkContext { db, krate }; 60 let context = ChalkContext { db, krate };
54 let solver = db.solver(krate); 61 let solver = db.solver(krate);
62 debug!("solve goal: {:?}", goal);
55 let solution = solver.lock().unwrap().solve(&context, goal); 63 let solution = solver.lock().unwrap().solve(&context, goal);
56 debug!("solve({:?}) => {:?}", goal, solution); 64 debug!("solve({:?}) => {:?}", goal, solution);
57 solution 65 solution
@@ -125,11 +133,11 @@ fn solution_from_chalk(db: &impl HirDatabase, solution: chalk_solve::Solution) -
125} 133}
126 134
127#[derive(Clone, Debug, PartialEq, Eq)] 135#[derive(Clone, Debug, PartialEq, Eq)]
128pub(crate) struct SolutionVariables(pub Canonical<Vec<Ty>>); 136pub struct SolutionVariables(pub Canonical<Vec<Ty>>);
129 137
130#[derive(Clone, Debug, PartialEq, Eq)] 138#[derive(Clone, Debug, PartialEq, Eq)]
131/// A (possible) solution for a proposed goal. 139/// A (possible) solution for a proposed goal.
132pub(crate) enum Solution { 140pub enum Solution {
133 /// The goal indeed holds, and there is a unique value for all existential 141 /// The goal indeed holds, and there is a unique value for all existential
134 /// variables. 142 /// variables.
135 Unique(SolutionVariables), 143 Unique(SolutionVariables),
@@ -144,7 +152,7 @@ pub(crate) enum Solution {
144#[derive(Clone, Debug, PartialEq, Eq)] 152#[derive(Clone, Debug, PartialEq, Eq)]
145/// When a goal holds ambiguously (e.g., because there are multiple possible 153/// When a goal holds ambiguously (e.g., because there are multiple possible
146/// solutions), we issue a set of *guidance* back to type inference. 154/// solutions), we issue a set of *guidance* back to type inference.
147pub(crate) enum Guidance { 155pub enum Guidance {
148 /// The existential variables *must* have the given values if the goal is 156 /// The existential variables *must* have the given values if the goal is
149 /// ever to hold, but that alone isn't enough to guarantee the goal will 157 /// ever to hold, but that alone isn't enough to guarantee the goal will
150 /// actually hold. 158 /// actually hold.
diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs
index 8b77d21b4..78440b258 100644
--- a/crates/ra_hir/src/ty/traits/chalk.rs
+++ b/crates/ra_hir/src/ty/traits/chalk.rs
@@ -6,15 +6,22 @@ use log::debug;
6use chalk_ir::{TypeId, ImplId, TypeKindId, ProjectionTy, Parameter, Identifier, cast::Cast, PlaceholderIndex, UniverseIndex, TypeName}; 6use chalk_ir::{TypeId, ImplId, TypeKindId, ProjectionTy, Parameter, Identifier, cast::Cast, PlaceholderIndex, UniverseIndex, TypeName};
7use chalk_rust_ir::{AssociatedTyDatum, TraitDatum, StructDatum, ImplDatum}; 7use chalk_rust_ir::{AssociatedTyDatum, TraitDatum, StructDatum, ImplDatum};
8 8
9use test_utils::tested_by;
9use ra_db::salsa::{InternId, InternKey}; 10use ra_db::salsa::{InternId, InternKey};
10 11
11use crate::{ 12use crate::{
12 Trait, HasGenericParams, ImplBlock, 13 Trait, HasGenericParams, ImplBlock,
13 db::HirDatabase, 14 db::HirDatabase,
14 ty::{TraitRef, Ty, ApplicationTy, TypeCtor, Substs}, 15 ty::{TraitRef, Ty, ApplicationTy, TypeCtor, Substs, GenericPredicate, CallableDef},
16 ty::display::HirDisplay,
17 generics::GenericDef,
15}; 18};
16use super::ChalkContext; 19use super::ChalkContext;
17 20
21/// This represents a trait whose name we could not resolve.
22const UNKNOWN_TRAIT: chalk_ir::TraitId =
23 chalk_ir::TraitId(chalk_ir::RawId { index: u32::max_value() });
24
18pub(super) trait ToChalk { 25pub(super) trait ToChalk {
19 type Chalk; 26 type Chalk;
20 fn to_chalk(self, db: &impl HirDatabase) -> Self::Chalk; 27 fn to_chalk(self, db: &impl HirDatabase) -> Self::Chalk;
@@ -45,7 +52,10 @@ impl ToChalk for Ty {
45 Ty::Infer(_infer_ty) => panic!("uncanonicalized infer ty"), 52 Ty::Infer(_infer_ty) => panic!("uncanonicalized infer ty"),
46 // FIXME this is clearly incorrect, but probably not too incorrect 53 // FIXME this is clearly incorrect, but probably not too incorrect
47 // and I'm not sure what to actually do with Ty::Unknown 54 // and I'm not sure what to actually do with Ty::Unknown
48 Ty::Unknown => PlaceholderIndex { ui: UniverseIndex::ROOT, idx: 0 }.to_ty(), 55 // maybe an alternative would be `for<T> T`? (meaningless in rust, but expressible in chalk's Ty)
56 Ty::Unknown => {
57 PlaceholderIndex { ui: UniverseIndex::ROOT, idx: usize::max_value() }.to_ty()
58 }
49 } 59 }
50 } 60 }
51 fn from_chalk(db: &impl HirDatabase, chalk: chalk_ir::Ty) -> Self { 61 fn from_chalk(db: &impl HirDatabase, chalk: chalk_ir::Ty) -> Self {
@@ -146,6 +156,33 @@ impl ToChalk for ImplBlock {
146 } 156 }
147} 157}
148 158
159impl ToChalk for GenericPredicate {
160 type Chalk = chalk_ir::QuantifiedWhereClause;
161
162 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::QuantifiedWhereClause {
163 match self {
164 GenericPredicate::Implemented(trait_ref) => {
165 make_binders(chalk_ir::WhereClause::Implemented(trait_ref.to_chalk(db)), 0)
166 }
167 GenericPredicate::Error => {
168 let impossible_trait_ref = chalk_ir::TraitRef {
169 trait_id: UNKNOWN_TRAIT,
170 parameters: vec![Ty::Unknown.to_chalk(db).cast()],
171 };
172 make_binders(chalk_ir::WhereClause::Implemented(impossible_trait_ref), 0)
173 }
174 }
175 }
176
177 fn from_chalk(
178 _db: &impl HirDatabase,
179 _where_clause: chalk_ir::QuantifiedWhereClause,
180 ) -> GenericPredicate {
181 // This should never need to be called
182 unimplemented!()
183 }
184}
185
149fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T> { 186fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T> {
150 chalk_ir::Binders { 187 chalk_ir::Binders {
151 value, 188 value,
@@ -153,6 +190,40 @@ fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T> {
153 } 190 }
154} 191}
155 192
193fn blacklisted_trait(db: &impl HirDatabase, trait_: Trait) -> bool {
194 let name = trait_.name(db).unwrap_or_else(crate::Name::missing).to_string();
195 match &*name {
196 "Send" | "Sync" | "Sized" | "Fn" | "FnMut" | "FnOnce" => true,
197 _ => false,
198 }
199}
200
201fn convert_where_clauses(
202 db: &impl HirDatabase,
203 def: GenericDef,
204 substs: &Substs,
205) -> Vec<chalk_ir::QuantifiedWhereClause> {
206 let generic_predicates = db.generic_predicates(def);
207 let mut result = Vec::with_capacity(generic_predicates.len());
208 for pred in generic_predicates.iter() {
209 if pred.is_error() {
210 // HACK: Return just the single predicate (which is always false
211 // anyway), otherwise Chalk can easily get into slow situations
212 return vec![pred.clone().subst(substs).to_chalk(db)];
213 }
214 match pred {
215 GenericPredicate::Implemented(trait_ref) => {
216 if blacklisted_trait(db, trait_ref.trait_) {
217 continue;
218 }
219 }
220 _ => {}
221 }
222 result.push(pred.clone().subst(substs).to_chalk(db));
223 }
224 result
225}
226
156impl<'a, DB> chalk_solve::RustIrDatabase for ChalkContext<'a, DB> 227impl<'a, DB> chalk_solve::RustIrDatabase for ChalkContext<'a, DB>
157where 228where
158 DB: HirDatabase, 229 DB: HirDatabase,
@@ -162,18 +233,36 @@ where
162 } 233 }
163 fn trait_datum(&self, trait_id: chalk_ir::TraitId) -> Arc<TraitDatum> { 234 fn trait_datum(&self, trait_id: chalk_ir::TraitId) -> Arc<TraitDatum> {
164 debug!("trait_datum {:?}", trait_id); 235 debug!("trait_datum {:?}", trait_id);
236 if trait_id == UNKNOWN_TRAIT {
237 let trait_datum_bound = chalk_rust_ir::TraitDatumBound {
238 trait_ref: chalk_ir::TraitRef {
239 trait_id: UNKNOWN_TRAIT,
240 parameters: vec![chalk_ir::Ty::BoundVar(0).cast()],
241 },
242 associated_ty_ids: Vec::new(),
243 where_clauses: Vec::new(),
244 flags: chalk_rust_ir::TraitFlags {
245 auto: false,
246 marker: false,
247 upstream: true,
248 fundamental: false,
249 },
250 };
251 return Arc::new(TraitDatum { binders: make_binders(trait_datum_bound, 1) });
252 }
165 let trait_: Trait = from_chalk(self.db, trait_id); 253 let trait_: Trait = from_chalk(self.db, trait_id);
254 debug!("trait {:?} = {:?}", trait_id, trait_.name(self.db));
166 let generic_params = trait_.generic_params(self.db); 255 let generic_params = trait_.generic_params(self.db);
167 let bound_vars = Substs::bound_vars(&generic_params); 256 let bound_vars = Substs::bound_vars(&generic_params);
168 let trait_ref = trait_.trait_ref(self.db).subst(&bound_vars).to_chalk(self.db); 257 let trait_ref = trait_.trait_ref(self.db).subst(&bound_vars).to_chalk(self.db);
169 let flags = chalk_rust_ir::TraitFlags { 258 let flags = chalk_rust_ir::TraitFlags {
259 auto: trait_.is_auto(self.db),
260 upstream: trait_.module(self.db).krate(self.db) != Some(self.krate),
170 // FIXME set these flags correctly 261 // FIXME set these flags correctly
171 auto: false,
172 marker: false, 262 marker: false,
173 upstream: trait_.module(self.db).krate(self.db) != Some(self.krate),
174 fundamental: false, 263 fundamental: false,
175 }; 264 };
176 let where_clauses = Vec::new(); // FIXME add where clauses 265 let where_clauses = convert_where_clauses(self.db, trait_.into(), &bound_vars);
177 let associated_ty_ids = Vec::new(); // FIXME add associated tys 266 let associated_ty_ids = Vec::new(); // FIXME add associated tys
178 let trait_datum_bound = 267 let trait_datum_bound =
179 chalk_rust_ir::TraitDatumBound { trait_ref, where_clauses, flags, associated_ty_ids }; 268 chalk_rust_ir::TraitDatumBound { trait_ref, where_clauses, flags, associated_ty_ids };
@@ -183,23 +272,51 @@ where
183 fn struct_datum(&self, struct_id: chalk_ir::StructId) -> Arc<StructDatum> { 272 fn struct_datum(&self, struct_id: chalk_ir::StructId) -> Arc<StructDatum> {
184 debug!("struct_datum {:?}", struct_id); 273 debug!("struct_datum {:?}", struct_id);
185 let type_ctor = from_chalk(self.db, struct_id); 274 let type_ctor = from_chalk(self.db, struct_id);
275 debug!("struct {:?} = {:?}", struct_id, type_ctor);
186 // FIXME might be nicer if we can create a fake GenericParams for the TypeCtor 276 // FIXME might be nicer if we can create a fake GenericParams for the TypeCtor
187 // FIXME extract this to a method on Ty 277 // FIXME extract this to a method on Ty
188 let (num_params, upstream) = match type_ctor { 278 let (num_params, where_clauses, upstream) = match type_ctor {
189 TypeCtor::Bool 279 TypeCtor::Bool
190 | TypeCtor::Char 280 | TypeCtor::Char
191 | TypeCtor::Int(_) 281 | TypeCtor::Int(_)
192 | TypeCtor::Float(_) 282 | TypeCtor::Float(_)
193 | TypeCtor::Never 283 | TypeCtor::Never
194 | TypeCtor::Str => (0, true), 284 | TypeCtor::Str => (0, vec![], true),
195 TypeCtor::Slice | TypeCtor::Array | TypeCtor::RawPtr(_) | TypeCtor::Ref(_) => (1, true), 285 TypeCtor::Slice | TypeCtor::Array | TypeCtor::RawPtr(_) | TypeCtor::Ref(_) => {
196 TypeCtor::FnPtr { num_args } => (num_args as usize + 1, true), 286 (1, vec![], true)
197 TypeCtor::Tuple { cardinality } => (cardinality as usize, true), 287 }
198 TypeCtor::FnDef(_) => unimplemented!(), 288 TypeCtor::FnPtr { num_args } => (num_args as usize + 1, vec![], true),
289 TypeCtor::Tuple { cardinality } => (cardinality as usize, vec![], true),
290 TypeCtor::FnDef(callable) => {
291 tested_by!(trait_resolution_on_fn_type);
292 let krate = match callable {
293 CallableDef::Function(f) => f.module(self.db).krate(self.db),
294 CallableDef::Struct(s) => s.module(self.db).krate(self.db),
295 CallableDef::EnumVariant(v) => {
296 v.parent_enum(self.db).module(self.db).krate(self.db)
297 }
298 };
299 let generic_def: GenericDef = match callable {
300 CallableDef::Function(f) => f.into(),
301 CallableDef::Struct(s) => s.into(),
302 CallableDef::EnumVariant(v) => v.parent_enum(self.db).into(),
303 };
304 let generic_params = generic_def.generic_params(self.db);
305 let bound_vars = Substs::bound_vars(&generic_params);
306 let where_clauses = convert_where_clauses(self.db, generic_def, &bound_vars);
307 (
308 generic_params.count_params_including_parent(),
309 where_clauses,
310 krate != Some(self.krate),
311 )
312 }
199 TypeCtor::Adt(adt) => { 313 TypeCtor::Adt(adt) => {
200 let generic_params = adt.generic_params(self.db); 314 let generic_params = adt.generic_params(self.db);
315 let bound_vars = Substs::bound_vars(&generic_params);
316 let where_clauses = convert_where_clauses(self.db, adt.into(), &bound_vars);
201 ( 317 (
202 generic_params.count_params_including_parent(), 318 generic_params.count_params_including_parent(),
319 where_clauses,
203 adt.krate(self.db) != Some(self.krate), 320 adt.krate(self.db) != Some(self.krate),
204 ) 321 )
205 } 322 }
@@ -209,7 +326,6 @@ where
209 // FIXME set fundamental flag correctly 326 // FIXME set fundamental flag correctly
210 fundamental: false, 327 fundamental: false,
211 }; 328 };
212 let where_clauses = Vec::new(); // FIXME add where clauses
213 let self_ty = chalk_ir::ApplicationTy { 329 let self_ty = chalk_ir::ApplicationTy {
214 name: TypeName::TypeKindId(type_ctor.to_chalk(self.db).into()), 330 name: TypeName::TypeKindId(type_ctor.to_chalk(self.db).into()),
215 parameters: (0..num_params).map(|i| chalk_ir::Ty::BoundVar(i).cast()).collect(), 331 parameters: (0..num_params).map(|i| chalk_ir::Ty::BoundVar(i).cast()).collect(),
@@ -237,10 +353,23 @@ where
237 } else { 353 } else {
238 chalk_rust_ir::ImplType::External 354 chalk_rust_ir::ImplType::External
239 }; 355 };
356 let where_clauses = convert_where_clauses(self.db, impl_block.into(), &bound_vars);
357 let negative = impl_block.is_negative(self.db);
358 debug!(
359 "impl {:?}: {}{} where {:?}",
360 impl_id,
361 if negative { "!" } else { "" },
362 trait_ref.display(self.db),
363 where_clauses
364 );
365 let trait_ref = trait_ref.to_chalk(self.db);
240 let impl_datum_bound = chalk_rust_ir::ImplDatumBound { 366 let impl_datum_bound = chalk_rust_ir::ImplDatumBound {
241 // FIXME handle negative impls (impl !Sync for Foo) 367 trait_ref: if negative {
242 trait_ref: chalk_rust_ir::PolarizedTraitRef::Positive(trait_ref.to_chalk(self.db)), 368 chalk_rust_ir::PolarizedTraitRef::Negative(trait_ref)
243 where_clauses: Vec::new(), // FIXME add where clauses 369 } else {
370 chalk_rust_ir::PolarizedTraitRef::Positive(trait_ref)
371 },
372 where_clauses,
244 associated_ty_values: Vec::new(), // FIXME add associated type values 373 associated_ty_values: Vec::new(), // FIXME add associated type values
245 impl_type, 374 impl_type,
246 }; 375 };
@@ -249,16 +378,22 @@ where
249 } 378 }
250 fn impls_for_trait(&self, trait_id: chalk_ir::TraitId) -> Vec<ImplId> { 379 fn impls_for_trait(&self, trait_id: chalk_ir::TraitId) -> Vec<ImplId> {
251 debug!("impls_for_trait {:?}", trait_id); 380 debug!("impls_for_trait {:?}", trait_id);
252 let trait_ = from_chalk(self.db, trait_id); 381 if trait_id == UNKNOWN_TRAIT {
253 self.db 382 return Vec::new();
383 }
384 let trait_: Trait = from_chalk(self.db, trait_id);
385 let blacklisted = blacklisted_trait(self.db, trait_);
386 if blacklisted {
387 return Vec::new();
388 }
389 let result: Vec<_> = self
390 .db
254 .impls_for_trait(self.krate, trait_) 391 .impls_for_trait(self.krate, trait_)
255 .iter() 392 .iter()
256 // FIXME temporary hack -- as long as we're not lowering where clauses
257 // correctly, ignore impls with them completely so as to not treat
258 // impl<T> Trait for T where T: ... as a blanket impl on all types
259 .filter(|impl_block| impl_block.generic_params(self.db).where_predicates.is_empty())
260 .map(|impl_block| impl_block.to_chalk(self.db)) 393 .map(|impl_block| impl_block.to_chalk(self.db))
261 .collect() 394 .collect();
395 debug!("impls_for_trait returned {} impls", result.len());
396 result
262 } 397 }
263 fn impl_provided_for( 398 fn impl_provided_for(
264 &self, 399 &self,