diff options
author | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-06-16 13:00:41 +0100 |
---|---|---|
committer | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-06-16 13:00:41 +0100 |
commit | b81caed43f1886024ededad41a1baa8a03f1d2f4 (patch) | |
tree | 0a0289899ec59b425eae6369929a01e97065ce43 | |
parent | e6fbff3246cdd3278ff1c376d5abfc1d579f86c2 (diff) | |
parent | ad3673d8d86a9b8f1a8dba858abd7cabaa1d5776 (diff) |
Merge #1408
1408: Associated type basics & Deref support r=matklad a=flodiebold
This adds the necessary Chalk integration to handle associated types and uses it to implement support for `Deref` in the `*` operator and autoderef; so e.g. dot completions through an `Arc` work now.
It doesn't yet implement resolution of associated types in paths, though. Also, there's a big FIXME about handling variables in the solution we get from Chalk correctly.
Co-authored-by: Florian Diebold <[email protected]>
-rw-r--r-- | Cargo.lock | 1 | ||||
-rw-r--r-- | crates/ra_assists/src/fill_match_arms.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir/Cargo.toml | 1 | ||||
-rw-r--r-- | crates/ra_hir/src/code_model.rs | 20 | ||||
-rw-r--r-- | crates/ra_hir/src/db.rs | 14 | ||||
-rw-r--r-- | crates/ra_hir/src/lang_item.rs | 49 | ||||
-rw-r--r-- | crates/ra_hir/src/name.rs | 5 | ||||
-rw-r--r-- | crates/ra_hir/src/source_binder.rs | 11 | ||||
-rw-r--r-- | crates/ra_hir/src/ty.rs | 28 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/autoderef.rs | 89 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/infer.rs | 48 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/lower.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/method_resolution.rs | 5 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 84 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/traits.rs | 33 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/traits/chalk.rs | 110 | ||||
-rw-r--r-- | crates/ra_hir/src/type_alias.rs | 18 | ||||
-rw-r--r-- | crates/ra_ide_api/src/completion/complete_dot.rs | 2 | ||||
-rw-r--r-- | crates/ra_ide_api/src/goto_type_definition.rs | 2 |
19 files changed, 454 insertions, 70 deletions
diff --git a/Cargo.lock b/Cargo.lock index 0579d9d39..167c620a3 100644 --- a/Cargo.lock +++ b/Cargo.lock | |||
@@ -1080,6 +1080,7 @@ dependencies = [ | |||
1080 | "flexi_logger 0.11.5 (registry+https://github.com/rust-lang/crates.io-index)", | 1080 | "flexi_logger 0.11.5 (registry+https://github.com/rust-lang/crates.io-index)", |
1081 | "insta 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", | 1081 | "insta 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", |
1082 | "join_to_string 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", | 1082 | "join_to_string 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", |
1083 | "lalrpop-intern 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)", | ||
1083 | "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", | 1084 | "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", |
1084 | "once_cell 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", | 1085 | "once_cell 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", |
1085 | "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", | 1086 | "parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", |
diff --git a/crates/ra_assists/src/fill_match_arms.rs b/crates/ra_assists/src/fill_match_arms.rs index a7de6ae9f..c7a8bce20 100644 --- a/crates/ra_assists/src/fill_match_arms.rs +++ b/crates/ra_assists/src/fill_match_arms.rs | |||
@@ -22,7 +22,7 @@ pub(crate) fn fill_match_arms(mut ctx: AssistCtx<impl HirDatabase>) -> Option<As | |||
22 | let expr = match_expr.expr()?; | 22 | let expr = match_expr.expr()?; |
23 | let analyzer = hir::SourceAnalyzer::new(ctx.db, ctx.frange.file_id, expr.syntax(), None); | 23 | let analyzer = hir::SourceAnalyzer::new(ctx.db, ctx.frange.file_id, expr.syntax(), None); |
24 | let match_expr_ty = analyzer.type_of(ctx.db, expr)?; | 24 | let match_expr_ty = analyzer.type_of(ctx.db, expr)?; |
25 | let enum_def = match_expr_ty.autoderef(ctx.db).find_map(|ty| match ty.as_adt() { | 25 | let enum_def = analyzer.autoderef(ctx.db, match_expr_ty).find_map(|ty| match ty.as_adt() { |
26 | Some((AdtDef::Enum(e), _)) => Some(e), | 26 | Some((AdtDef::Enum(e), _)) => Some(e), |
27 | _ => None, | 27 | _ => None, |
28 | })?; | 28 | })?; |
diff --git a/crates/ra_hir/Cargo.toml b/crates/ra_hir/Cargo.toml index 12d849f37..aaace85e5 100644 --- a/crates/ra_hir/Cargo.toml +++ b/crates/ra_hir/Cargo.toml | |||
@@ -25,6 +25,7 @@ ra_prof = { path = "../ra_prof" } | |||
25 | chalk-solve = { git = "https://github.com/flodiebold/chalk.git", branch = "fuel" } | 25 | chalk-solve = { git = "https://github.com/flodiebold/chalk.git", branch = "fuel" } |
26 | chalk-rust-ir = { git = "https://github.com/flodiebold/chalk.git", branch = "fuel" } | 26 | chalk-rust-ir = { git = "https://github.com/flodiebold/chalk.git", branch = "fuel" } |
27 | chalk-ir = { git = "https://github.com/flodiebold/chalk.git", branch = "fuel" } | 27 | chalk-ir = { git = "https://github.com/flodiebold/chalk.git", branch = "fuel" } |
28 | lalrpop-intern = "0.15.1" | ||
28 | 29 | ||
29 | [dev-dependencies] | 30 | [dev-dependencies] |
30 | flexi_logger = "0.11.0" | 31 | flexi_logger = "0.11.0" |
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index 830aea1f3..6602d1220 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs | |||
@@ -779,6 +779,18 @@ impl Trait { | |||
779 | self.trait_data(db).items().to_vec() | 779 | self.trait_data(db).items().to_vec() |
780 | } | 780 | } |
781 | 781 | ||
782 | pub fn associated_type_by_name(self, db: &impl DefDatabase, name: Name) -> Option<TypeAlias> { | ||
783 | let trait_data = self.trait_data(db); | ||
784 | trait_data | ||
785 | .items() | ||
786 | .iter() | ||
787 | .filter_map(|item| match item { | ||
788 | TraitItem::TypeAlias(t) => Some(*t), | ||
789 | _ => None, | ||
790 | }) | ||
791 | .find(|t| t.name(db) == name) | ||
792 | } | ||
793 | |||
782 | pub(crate) fn trait_data(self, db: &impl DefDatabase) -> Arc<TraitData> { | 794 | pub(crate) fn trait_data(self, db: &impl DefDatabase) -> Arc<TraitData> { |
783 | db.trait_data(self) | 795 | db.trait_data(self) |
784 | } | 796 | } |
@@ -831,8 +843,12 @@ impl TypeAlias { | |||
831 | } | 843 | } |
832 | } | 844 | } |
833 | 845 | ||
834 | pub fn type_ref(self, db: &impl DefDatabase) -> Arc<TypeRef> { | 846 | pub fn type_ref(self, db: &impl DefDatabase) -> Option<TypeRef> { |
835 | db.type_alias_ref(self) | 847 | db.type_alias_data(self).type_ref.clone() |
848 | } | ||
849 | |||
850 | pub fn name(self, db: &impl DefDatabase) -> Name { | ||
851 | db.type_alias_data(self).name.clone() | ||
836 | } | 852 | } |
837 | 853 | ||
838 | /// Builds a resolver for the type references in this type alias. | 854 | /// Builds a resolver for the type references in this type alias. |
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index d2d6f95b7..c4dd54596 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs | |||
@@ -16,9 +16,8 @@ use crate::{ | |||
16 | adt::{StructData, EnumData}, | 16 | adt::{StructData, EnumData}, |
17 | impl_block::{ModuleImplBlocks, ImplSourceMap, ImplBlock}, | 17 | impl_block::{ModuleImplBlocks, ImplSourceMap, ImplBlock}, |
18 | generics::{GenericParams, GenericDef}, | 18 | generics::{GenericParams, GenericDef}, |
19 | type_ref::TypeRef, | ||
20 | traits::TraitData, | 19 | traits::TraitData, |
21 | lang_item::{LangItems, LangItemTarget}, | 20 | lang_item::{LangItems, LangItemTarget}, type_alias::TypeAliasData, |
22 | }; | 21 | }; |
23 | 22 | ||
24 | // This database has access to source code, so queries here are not really | 23 | // This database has access to source code, so queries here are not really |
@@ -113,8 +112,8 @@ pub trait DefDatabase: SourceDatabase { | |||
113 | #[salsa::invoke(crate::FnSignature::fn_signature_query)] | 112 | #[salsa::invoke(crate::FnSignature::fn_signature_query)] |
114 | fn fn_signature(&self, func: Function) -> Arc<FnSignature>; | 113 | fn fn_signature(&self, func: Function) -> Arc<FnSignature>; |
115 | 114 | ||
116 | #[salsa::invoke(crate::type_alias::type_alias_ref_query)] | 115 | #[salsa::invoke(crate::type_alias::type_alias_data_query)] |
117 | fn type_alias_ref(&self, typ: TypeAlias) -> Arc<TypeRef>; | 116 | fn type_alias_data(&self, typ: TypeAlias) -> Arc<TypeAliasData>; |
118 | 117 | ||
119 | #[salsa::invoke(crate::ConstSignature::const_signature_query)] | 118 | #[salsa::invoke(crate::ConstSignature::const_signature_query)] |
120 | fn const_signature(&self, konst: Const) -> Arc<ConstSignature>; | 119 | fn const_signature(&self, konst: Const) -> Arc<ConstSignature>; |
@@ -185,6 +184,13 @@ pub trait HirDatabase: DefDatabase + AstDatabase { | |||
185 | krate: Crate, | 184 | krate: Crate, |
186 | goal: crate::ty::Canonical<crate::ty::TraitRef>, | 185 | goal: crate::ty::Canonical<crate::ty::TraitRef>, |
187 | ) -> Option<crate::ty::traits::Solution>; | 186 | ) -> Option<crate::ty::traits::Solution>; |
187 | |||
188 | #[salsa::invoke(crate::ty::traits::normalize_query)] | ||
189 | fn normalize( | ||
190 | &self, | ||
191 | krate: Crate, | ||
192 | goal: crate::ty::Canonical<crate::ty::ProjectionPredicate>, | ||
193 | ) -> Option<crate::ty::traits::Solution>; | ||
188 | } | 194 | } |
189 | 195 | ||
190 | #[test] | 196 | #[test] |
diff --git a/crates/ra_hir/src/lang_item.rs b/crates/ra_hir/src/lang_item.rs index cdc9182d6..18ac0fcf9 100644 --- a/crates/ra_hir/src/lang_item.rs +++ b/crates/ra_hir/src/lang_item.rs | |||
@@ -1,10 +1,11 @@ | |||
1 | use std::sync::Arc; | 1 | use std::sync::Arc; |
2 | use rustc_hash::FxHashMap; | 2 | use rustc_hash::FxHashMap; |
3 | 3 | ||
4 | use ra_syntax::{SmolStr, ast::AttrsOwner}; | 4 | use ra_syntax::{SmolStr, TreeArc, ast::AttrsOwner}; |
5 | 5 | ||
6 | use crate::{ | 6 | use crate::{ |
7 | Crate, DefDatabase, Enum, Function, HirDatabase, ImplBlock, Module, Static, Struct, Trait, AstDatabase, | 7 | Crate, DefDatabase, Enum, Function, HirDatabase, ImplBlock, Module, |
8 | Static, Struct, Trait, ModuleDef, AstDatabase, HasSource | ||
8 | }; | 9 | }; |
9 | 10 | ||
10 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 11 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
@@ -87,23 +88,51 @@ impl LangItems { | |||
87 | let source = module.definition_source(db).ast; | 88 | let source = module.definition_source(db).ast; |
88 | for (impl_id, _) in impl_blocks.impls.iter() { | 89 | for (impl_id, _) in impl_blocks.impls.iter() { |
89 | let impl_block = source_map.get(&source, impl_id); | 90 | let impl_block = source_map.get(&source, impl_id); |
90 | let lang_item_name = impl_block | 91 | if let Some(lang_item_name) = lang_item_name(&*impl_block) { |
91 | .attrs() | ||
92 | .filter_map(|a| a.as_key_value()) | ||
93 | .filter(|(key, _)| key == "lang") | ||
94 | .map(|(_, val)| val) | ||
95 | .nth(0); | ||
96 | if let Some(lang_item_name) = lang_item_name { | ||
97 | let imp = ImplBlock::from_id(*module, impl_id); | 92 | let imp = ImplBlock::from_id(*module, impl_id); |
98 | self.items.entry(lang_item_name).or_insert_with(|| LangItemTarget::ImplBlock(imp)); | 93 | self.items.entry(lang_item_name).or_insert_with(|| LangItemTarget::ImplBlock(imp)); |
99 | } | 94 | } |
100 | } | 95 | } |
101 | 96 | ||
102 | // FIXME we should look for the other lang item targets (traits, structs, ...) | 97 | for def in module.declarations(db) { |
98 | match def { | ||
99 | ModuleDef::Trait(trait_) => { | ||
100 | self.collect_lang_item(db, trait_, LangItemTarget::Trait) | ||
101 | } | ||
102 | ModuleDef::Enum(e) => self.collect_lang_item(db, e, LangItemTarget::Enum), | ||
103 | ModuleDef::Struct(s) => self.collect_lang_item(db, s, LangItemTarget::Struct), | ||
104 | ModuleDef::Function(f) => self.collect_lang_item(db, f, LangItemTarget::Function), | ||
105 | ModuleDef::Static(s) => self.collect_lang_item(db, s, LangItemTarget::Static), | ||
106 | _ => {} | ||
107 | } | ||
108 | } | ||
103 | 109 | ||
104 | // Look for lang items in the children | 110 | // Look for lang items in the children |
105 | for child in module.children(db) { | 111 | for child in module.children(db) { |
106 | self.collect_lang_items_recursive(db, &child); | 112 | self.collect_lang_items_recursive(db, &child); |
107 | } | 113 | } |
108 | } | 114 | } |
115 | |||
116 | fn collect_lang_item<T, N>( | ||
117 | &mut self, | ||
118 | db: &(impl DefDatabase + AstDatabase), | ||
119 | item: T, | ||
120 | constructor: fn(T) -> LangItemTarget, | ||
121 | ) where | ||
122 | T: Copy + HasSource<Ast = TreeArc<N>>, | ||
123 | N: AttrsOwner, | ||
124 | { | ||
125 | let node = item.source(db).ast; | ||
126 | if let Some(lang_item_name) = lang_item_name(&*node) { | ||
127 | self.items.entry(lang_item_name).or_insert(constructor(item)); | ||
128 | } | ||
129 | } | ||
130 | } | ||
131 | |||
132 | fn lang_item_name<T: AttrsOwner>(node: &T) -> Option<SmolStr> { | ||
133 | node.attrs() | ||
134 | .filter_map(|a| a.as_key_value()) | ||
135 | .filter(|(key, _)| key == "lang") | ||
136 | .map(|(_, val)| val) | ||
137 | .nth(0) | ||
109 | } | 138 | } |
diff --git a/crates/ra_hir/src/name.rs b/crates/ra_hir/src/name.rs index e9003e00b..ba17958eb 100644 --- a/crates/ra_hir/src/name.rs +++ b/crates/ra_hir/src/name.rs | |||
@@ -46,6 +46,11 @@ impl Name { | |||
46 | Name::new(idx.to_string().into()) | 46 | Name::new(idx.to_string().into()) |
47 | } | 47 | } |
48 | 48 | ||
49 | // Needed for Deref | ||
50 | pub(crate) fn target() -> Name { | ||
51 | Name::new("Target".into()) | ||
52 | } | ||
53 | |||
49 | // There's should be no way to extract a string out of `Name`: `Name` in the | 54 | // There's should be no way to extract a string out of `Name`: `Name` in the |
50 | // future, `Name` will include hygiene information, and you can't encode | 55 | // future, `Name` will include hygiene information, and you can't encode |
51 | // hygiene into a String. | 56 | // hygiene into a String. |
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index 4f9e8c5a9..08e86844d 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs | |||
@@ -369,6 +369,17 @@ impl SourceAnalyzer { | |||
369 | ) | 369 | ) |
370 | } | 370 | } |
371 | 371 | ||
372 | pub fn autoderef<'a>( | ||
373 | &'a self, | ||
374 | db: &'a impl HirDatabase, | ||
375 | ty: Ty, | ||
376 | ) -> impl Iterator<Item = Ty> + 'a { | ||
377 | // There should be no inference vars in types passed here | ||
378 | // FIXME check that? | ||
379 | let canonical = crate::ty::Canonical { value: ty, num_vars: 0 }; | ||
380 | crate::ty::autoderef(db, &self.resolver, canonical).map(|canonical| canonical.value) | ||
381 | } | ||
382 | |||
372 | #[cfg(test)] | 383 | #[cfg(test)] |
373 | pub(crate) fn body_source_map(&self) -> Arc<BodySourceMap> { | 384 | pub(crate) fn body_source_map(&self) -> Arc<BodySourceMap> { |
374 | self.body_source_map.clone().unwrap() | 385 | self.body_source_map.clone().unwrap() |
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index 4a37e0268..842d49e1f 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs | |||
@@ -16,12 +16,14 @@ use std::sync::Arc; | |||
16 | use std::ops::Deref; | 16 | use std::ops::Deref; |
17 | use std::{fmt, mem}; | 17 | use std::{fmt, mem}; |
18 | 18 | ||
19 | use crate::{Name, AdtDef, type_ref::Mutability, db::HirDatabase, Trait, GenericParams}; | 19 | use crate::{Name, AdtDef, type_ref::Mutability, db::HirDatabase, Trait, GenericParams, TypeAlias}; |
20 | use display::{HirDisplay, HirFormatter}; | 20 | use display::{HirDisplay, HirFormatter}; |
21 | 21 | ||
22 | pub(crate) use lower::{TypableDef, type_for_def, type_for_field, callable_item_sig, generic_predicates, generic_defaults}; | 22 | pub(crate) use lower::{TypableDef, type_for_def, type_for_field, callable_item_sig, generic_predicates, generic_defaults}; |
23 | pub(crate) use infer::{infer_query, InferenceResult, InferTy}; | 23 | pub(crate) use infer::{infer_query, InferenceResult, InferTy}; |
24 | pub use lower::CallableDef; | 24 | pub use lower::CallableDef; |
25 | pub(crate) use autoderef::autoderef; | ||
26 | pub(crate) use traits::ProjectionPredicate; | ||
25 | 27 | ||
26 | /// A type constructor or type name: this might be something like the primitive | 28 | /// A type constructor or type name: this might be something like the primitive |
27 | /// type `bool`, a struct like `Vec`, or things like function pointers or | 29 | /// type `bool`, a struct like `Vec`, or things like function pointers or |
@@ -100,6 +102,15 @@ pub struct ApplicationTy { | |||
100 | pub parameters: Substs, | 102 | pub parameters: Substs, |
101 | } | 103 | } |
102 | 104 | ||
105 | /// A "projection" type corresponds to an (unnormalized) | ||
106 | /// projection like `<P0 as Trait<P1..Pn>>::Foo`. Note that the | ||
107 | /// trait and all its parameters are fully known. | ||
108 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | ||
109 | pub struct ProjectionTy { | ||
110 | pub associated_ty: TypeAlias, | ||
111 | pub parameters: Substs, | ||
112 | } | ||
113 | |||
103 | /// A type. | 114 | /// A type. |
104 | /// | 115 | /// |
105 | /// See also the `TyKind` enum in rustc (librustc/ty/sty.rs), which represents | 116 | /// See also the `TyKind` enum in rustc (librustc/ty/sty.rs), which represents |
@@ -216,8 +227,8 @@ impl Deref for Substs { | |||
216 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | 227 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] |
217 | pub struct TraitRef { | 228 | pub struct TraitRef { |
218 | /// FIXME name? | 229 | /// FIXME name? |
219 | trait_: Trait, | 230 | pub trait_: Trait, |
220 | substs: Substs, | 231 | pub substs: Substs, |
221 | } | 232 | } |
222 | 233 | ||
223 | impl TraitRef { | 234 | impl TraitRef { |
@@ -464,6 +475,17 @@ impl Ty { | |||
464 | _ => None, | 475 | _ => None, |
465 | } | 476 | } |
466 | } | 477 | } |
478 | |||
479 | /// Shifts up `Ty::Bound` vars by `n`. | ||
480 | pub fn shift_bound_vars(self, n: i32) -> Ty { | ||
481 | self.fold(&mut |ty| match ty { | ||
482 | Ty::Bound(idx) => { | ||
483 | assert!(idx as i32 >= -n); | ||
484 | Ty::Bound((idx as i32 + n) as u32) | ||
485 | } | ||
486 | ty => ty, | ||
487 | }) | ||
488 | } | ||
467 | } | 489 | } |
468 | 490 | ||
469 | impl HirDisplay for &Ty { | 491 | impl HirDisplay for &Ty { |
diff --git a/crates/ra_hir/src/ty/autoderef.rs b/crates/ra_hir/src/ty/autoderef.rs index a442a856c..1f443d49b 100644 --- a/crates/ra_hir/src/ty/autoderef.rs +++ b/crates/ra_hir/src/ty/autoderef.rs | |||
@@ -5,17 +5,88 @@ | |||
5 | 5 | ||
6 | use std::iter::successors; | 6 | use std::iter::successors; |
7 | 7 | ||
8 | use crate::HirDatabase; | 8 | use log::{info, warn}; |
9 | use super::Ty; | ||
10 | 9 | ||
11 | impl Ty { | 10 | use crate::{HirDatabase, Name, Resolver, HasGenericParams}; |
12 | /// Iterates over the possible derefs of `ty`. | 11 | use super::{traits::Solution, Ty, Canonical}; |
13 | pub fn autoderef<'a>(self, db: &'a impl HirDatabase) -> impl Iterator<Item = Ty> + 'a { | 12 | |
14 | successors(Some(self), move |ty| ty.autoderef_step(db)) | 13 | const AUTODEREF_RECURSION_LIMIT: usize = 10; |
14 | |||
15 | pub(crate) fn autoderef<'a>( | ||
16 | db: &'a impl HirDatabase, | ||
17 | resolver: &'a Resolver, | ||
18 | ty: Canonical<Ty>, | ||
19 | ) -> impl Iterator<Item = Canonical<Ty>> + 'a { | ||
20 | successors(Some(ty), move |ty| deref(db, resolver, ty)).take(AUTODEREF_RECURSION_LIMIT) | ||
21 | } | ||
22 | |||
23 | pub(crate) fn deref( | ||
24 | db: &impl HirDatabase, | ||
25 | resolver: &Resolver, | ||
26 | ty: &Canonical<Ty>, | ||
27 | ) -> Option<Canonical<Ty>> { | ||
28 | if let Some(derefed) = ty.value.builtin_deref() { | ||
29 | Some(Canonical { value: derefed, num_vars: ty.num_vars }) | ||
30 | } else { | ||
31 | deref_by_trait(db, resolver, ty) | ||
32 | } | ||
33 | } | ||
34 | |||
35 | fn deref_by_trait( | ||
36 | db: &impl HirDatabase, | ||
37 | resolver: &Resolver, | ||
38 | ty: &Canonical<Ty>, | ||
39 | ) -> Option<Canonical<Ty>> { | ||
40 | let krate = resolver.krate()?; | ||
41 | let deref_trait = match db.lang_item(krate, "deref".into())? { | ||
42 | crate::lang_item::LangItemTarget::Trait(t) => t, | ||
43 | _ => return None, | ||
44 | }; | ||
45 | let target = deref_trait.associated_type_by_name(db, Name::target())?; | ||
46 | |||
47 | if target.generic_params(db).count_params_including_parent() != 1 { | ||
48 | // the Target type + Deref trait should only have one generic parameter, | ||
49 | // namely Deref's Self type | ||
50 | return None; | ||
15 | } | 51 | } |
16 | 52 | ||
17 | fn autoderef_step(&self, _db: &impl HirDatabase) -> Option<Ty> { | 53 | // FIXME make the Canonical handling nicer |
18 | // FIXME Deref::deref | 54 | |
19 | self.builtin_deref() | 55 | let projection = super::traits::ProjectionPredicate { |
56 | ty: Ty::Bound(0), | ||
57 | projection_ty: super::ProjectionTy { | ||
58 | associated_ty: target, | ||
59 | parameters: vec![ty.value.clone().shift_bound_vars(1)].into(), | ||
60 | }, | ||
61 | }; | ||
62 | |||
63 | let canonical = super::Canonical { num_vars: 1 + ty.num_vars, value: projection }; | ||
64 | |||
65 | let solution = db.normalize(krate, canonical)?; | ||
66 | |||
67 | match &solution { | ||
68 | Solution::Unique(vars) => { | ||
69 | // FIXME: vars may contain solutions for any inference variables | ||
70 | // that happened to be inside ty. To correctly handle these, we | ||
71 | // would have to pass the solution up to the inference context, but | ||
72 | // that requires a larger refactoring (especially if the deref | ||
73 | // happens during method resolution). So for the moment, we just | ||
74 | // check that we're not in the situation we're we would actually | ||
75 | // need to handle the values of the additional variables, i.e. | ||
76 | // they're just being 'passed through'. In the 'standard' case where | ||
77 | // we have `impl<T> Deref for Foo<T> { Target = T }`, that should be | ||
78 | // the case. | ||
79 | for i in 1..vars.0.num_vars { | ||
80 | if vars.0.value[i] != Ty::Bound((i - 1) as u32) { | ||
81 | warn!("complex solution for derefing {:?}: {:?}, ignoring", ty, solution); | ||
82 | return None; | ||
83 | } | ||
84 | } | ||
85 | Some(Canonical { value: vars.0.value[0].clone(), num_vars: vars.0.num_vars }) | ||
86 | } | ||
87 | Solution::Ambig(_) => { | ||
88 | info!("Ambiguous solution for derefing {:?}: {:?}", ty, solution); | ||
89 | None | ||
90 | } | ||
20 | } | 91 | } |
21 | } | 92 | } |
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index e150d7fd8..1ee40c70a 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs | |||
@@ -46,7 +46,7 @@ use crate::{ | |||
46 | use super::{ | 46 | use super::{ |
47 | Ty, TypableDef, Substs, primitive, op, ApplicationTy, TypeCtor, CallableDef, TraitRef, | 47 | Ty, TypableDef, Substs, primitive, op, ApplicationTy, TypeCtor, CallableDef, TraitRef, |
48 | traits::{Solution, Obligation, Guidance}, | 48 | traits::{Solution, Obligation, Guidance}, |
49 | method_resolution, | 49 | method_resolution, autoderef, |
50 | }; | 50 | }; |
51 | 51 | ||
52 | mod unify; | 52 | mod unify; |
@@ -1074,25 +1074,27 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1074 | } | 1074 | } |
1075 | Expr::Field { expr, name } => { | 1075 | Expr::Field { expr, name } => { |
1076 | let receiver_ty = self.infer_expr(*expr, &Expectation::none()); | 1076 | let receiver_ty = self.infer_expr(*expr, &Expectation::none()); |
1077 | let ty = receiver_ty | 1077 | let canonicalized = self.canonicalizer().canonicalize_ty(receiver_ty); |
1078 | .autoderef(self.db) | 1078 | let ty = autoderef::autoderef( |
1079 | .find_map(|derefed_ty| match derefed_ty { | 1079 | self.db, |
1080 | Ty::Apply(a_ty) => match a_ty.ctor { | 1080 | &self.resolver.clone(), |
1081 | TypeCtor::Tuple { .. } => { | 1081 | canonicalized.value.clone(), |
1082 | let i = name.to_string().parse::<usize>().ok(); | 1082 | ) |
1083 | i.and_then(|i| a_ty.parameters.0.get(i).cloned()) | 1083 | .find_map(|derefed_ty| match canonicalized.decanonicalize_ty(derefed_ty.value) { |
1084 | } | 1084 | Ty::Apply(a_ty) => match a_ty.ctor { |
1085 | TypeCtor::Adt(AdtDef::Struct(s)) => { | 1085 | TypeCtor::Tuple { .. } => { |
1086 | s.field(self.db, name).map(|field| { | 1086 | let i = name.to_string().parse::<usize>().ok(); |
1087 | self.write_field_resolution(tgt_expr, field); | 1087 | i.and_then(|i| a_ty.parameters.0.get(i).cloned()) |
1088 | field.ty(self.db).subst(&a_ty.parameters) | 1088 | } |
1089 | }) | 1089 | TypeCtor::Adt(AdtDef::Struct(s)) => s.field(self.db, name).map(|field| { |
1090 | } | 1090 | self.write_field_resolution(tgt_expr, field); |
1091 | _ => None, | 1091 | field.ty(self.db).subst(&a_ty.parameters) |
1092 | }, | 1092 | }), |
1093 | _ => None, | 1093 | _ => None, |
1094 | }) | 1094 | }, |
1095 | .unwrap_or(Ty::Unknown); | 1095 | _ => None, |
1096 | }) | ||
1097 | .unwrap_or(Ty::Unknown); | ||
1096 | self.insert_type_vars(ty) | 1098 | self.insert_type_vars(ty) |
1097 | } | 1099 | } |
1098 | Expr::Try { expr } => { | 1100 | Expr::Try { expr } => { |
@@ -1124,10 +1126,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1124 | let inner_ty = self.infer_expr(*expr, &Expectation::none()); | 1126 | let inner_ty = self.infer_expr(*expr, &Expectation::none()); |
1125 | match op { | 1127 | match op { |
1126 | UnaryOp::Deref => { | 1128 | UnaryOp::Deref => { |
1127 | if let Some(derefed_ty) = inner_ty.builtin_deref() { | 1129 | let canonicalized = self.canonicalizer().canonicalize_ty(inner_ty); |
1128 | derefed_ty | 1130 | if let Some(derefed_ty) = |
1131 | autoderef::deref(self.db, &self.resolver, &canonicalized.value) | ||
1132 | { | ||
1133 | canonicalized.decanonicalize_ty(derefed_ty.value) | ||
1129 | } else { | 1134 | } else { |
1130 | // FIXME Deref::deref | ||
1131 | Ty::Unknown | 1135 | Ty::Unknown |
1132 | } | 1136 | } |
1133 | } | 1137 | } |
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs index 26c213a41..300616a53 100644 --- a/crates/ra_hir/src/ty/lower.rs +++ b/crates/ra_hir/src/ty/lower.rs | |||
@@ -460,7 +460,7 @@ fn type_for_type_alias(db: &impl HirDatabase, t: TypeAlias) -> Ty { | |||
460 | let resolver = t.resolver(db); | 460 | let resolver = t.resolver(db); |
461 | let type_ref = t.type_ref(db); | 461 | let type_ref = t.type_ref(db); |
462 | let substs = Substs::identity(&generics); | 462 | let substs = Substs::identity(&generics); |
463 | let inner = Ty::from_hir(db, &resolver, &type_ref); | 463 | let inner = Ty::from_hir(db, &resolver, &type_ref.unwrap_or(TypeRef::Error)); |
464 | inner.subst(&substs) | 464 | inner.subst(&substs) |
465 | } | 465 | } |
466 | 466 | ||
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs index 646e58aa9..ad26d591c 100644 --- a/crates/ra_hir/src/ty/method_resolution.rs +++ b/crates/ra_hir/src/ty/method_resolution.rs | |||
@@ -16,7 +16,7 @@ use crate::{ | |||
16 | generics::HasGenericParams, | 16 | generics::HasGenericParams, |
17 | ty::primitive::{UncertainIntTy, UncertainFloatTy} | 17 | ty::primitive::{UncertainIntTy, UncertainFloatTy} |
18 | }; | 18 | }; |
19 | use super::{TraitRef, Canonical}; | 19 | use super::{TraitRef, Canonical, autoderef}; |
20 | 20 | ||
21 | /// This is used as a key for indexing impls. | 21 | /// This is used as a key for indexing impls. |
22 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] | 22 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] |
@@ -162,8 +162,7 @@ pub(crate) fn iterate_method_candidates<T>( | |||
162 | // rustc does an autoderef and then autoref again). | 162 | // rustc does an autoderef and then autoref again). |
163 | 163 | ||
164 | let krate = resolver.krate()?; | 164 | let krate = resolver.krate()?; |
165 | for derefed_ty in ty.value.clone().autoderef(db) { | 165 | for derefed_ty in autoderef::autoderef(db, resolver, ty.clone()) { |
166 | let derefed_ty = Canonical { value: derefed_ty, num_vars: ty.num_vars }; | ||
167 | if let Some(result) = iterate_inherent_methods(&derefed_ty, db, name, krate, &mut callback) | 166 | if let Some(result) = iterate_inherent_methods(&derefed_ty, db, name, krate, &mut callback) |
168 | { | 167 | { |
169 | return Some(result); | 168 | return Some(result); |
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 54b2a8c16..0fe7805e2 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -2737,6 +2737,90 @@ fn main() { | |||
2737 | assert_eq!(t, "Foo"); | 2737 | assert_eq!(t, "Foo"); |
2738 | } | 2738 | } |
2739 | 2739 | ||
2740 | #[test] | ||
2741 | fn deref_trait() { | ||
2742 | let t = type_at( | ||
2743 | r#" | ||
2744 | //- /main.rs | ||
2745 | #[lang = "deref"] | ||
2746 | trait Deref { | ||
2747 | type Target; | ||
2748 | fn deref(&self) -> &Self::Target; | ||
2749 | } | ||
2750 | |||
2751 | struct Arc<T>; | ||
2752 | impl<T> Deref for Arc<T> { | ||
2753 | type Target = T; | ||
2754 | } | ||
2755 | |||
2756 | struct S; | ||
2757 | impl S { | ||
2758 | fn foo(&self) -> u128 {} | ||
2759 | } | ||
2760 | |||
2761 | fn test(s: Arc<S>) { | ||
2762 | (*s, s.foo())<|> | ||
2763 | } | ||
2764 | "#, | ||
2765 | ); | ||
2766 | assert_eq!(t, "(S, u128)"); | ||
2767 | } | ||
2768 | |||
2769 | #[test] | ||
2770 | fn deref_trait_with_inference_var() { | ||
2771 | let t = type_at( | ||
2772 | r#" | ||
2773 | //- /main.rs | ||
2774 | #[lang = "deref"] | ||
2775 | trait Deref { | ||
2776 | type Target; | ||
2777 | fn deref(&self) -> &Self::Target; | ||
2778 | } | ||
2779 | |||
2780 | struct Arc<T>; | ||
2781 | fn new_arc<T>() -> Arc<T> {} | ||
2782 | impl<T> Deref for Arc<T> { | ||
2783 | type Target = T; | ||
2784 | } | ||
2785 | |||
2786 | struct S; | ||
2787 | fn foo(a: Arc<S>) {} | ||
2788 | |||
2789 | fn test() { | ||
2790 | let a = new_arc(); | ||
2791 | let b = (*a)<|>; | ||
2792 | foo(a); | ||
2793 | } | ||
2794 | "#, | ||
2795 | ); | ||
2796 | assert_eq!(t, "S"); | ||
2797 | } | ||
2798 | |||
2799 | #[test] | ||
2800 | fn deref_trait_infinite_recursion() { | ||
2801 | let t = type_at( | ||
2802 | r#" | ||
2803 | //- /main.rs | ||
2804 | #[lang = "deref"] | ||
2805 | trait Deref { | ||
2806 | type Target; | ||
2807 | fn deref(&self) -> &Self::Target; | ||
2808 | } | ||
2809 | |||
2810 | struct S; | ||
2811 | |||
2812 | impl Deref for S { | ||
2813 | type Target = S; | ||
2814 | } | ||
2815 | |||
2816 | fn test(s: S) { | ||
2817 | s.foo()<|>; | ||
2818 | } | ||
2819 | "#, | ||
2820 | ); | ||
2821 | assert_eq!(t, "{unknown}"); | ||
2822 | } | ||
2823 | |||
2740 | fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { | 2824 | fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { |
2741 | let file = db.parse(pos.file_id).ok().unwrap(); | 2825 | let file = db.parse(pos.file_id).ok().unwrap(); |
2742 | let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap(); | 2826 | let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap(); |
diff --git a/crates/ra_hir/src/ty/traits.rs b/crates/ra_hir/src/ty/traits.rs index fda7f9c04..9a6349d4b 100644 --- a/crates/ra_hir/src/ty/traits.rs +++ b/crates/ra_hir/src/ty/traits.rs | |||
@@ -8,7 +8,7 @@ use chalk_ir::cast::Cast; | |||
8 | use ra_prof::profile; | 8 | use ra_prof::profile; |
9 | 9 | ||
10 | use crate::{Crate, Trait, db::HirDatabase, ImplBlock}; | 10 | use crate::{Crate, Trait, db::HirDatabase, ImplBlock}; |
11 | use super::{TraitRef, Ty, Canonical}; | 11 | use super::{TraitRef, Ty, Canonical, ProjectionTy}; |
12 | 12 | ||
13 | use self::chalk::{ToChalk, from_chalk}; | 13 | use self::chalk::{ToChalk, from_chalk}; |
14 | 14 | ||
@@ -75,6 +75,13 @@ pub enum Obligation { | |||
75 | /// Prove that a certain type implements a trait (the type is the `Self` type | 75 | /// Prove that a certain type implements a trait (the type is the `Self` type |
76 | /// parameter to the `TraitRef`). | 76 | /// parameter to the `TraitRef`). |
77 | Trait(TraitRef), | 77 | Trait(TraitRef), |
78 | // Projection(ProjectionPredicate), | ||
79 | } | ||
80 | |||
81 | #[derive(Clone, Debug, PartialEq, Eq, Hash)] | ||
82 | pub struct ProjectionPredicate { | ||
83 | pub projection_ty: ProjectionTy, | ||
84 | pub ty: Ty, | ||
78 | } | 85 | } |
79 | 86 | ||
80 | /// Check using Chalk whether trait is implemented for given parameters including `Self` type. | 87 | /// Check using Chalk whether trait is implemented for given parameters including `Self` type. |
@@ -98,6 +105,30 @@ pub(crate) fn implements_query( | |||
98 | solution.map(|solution| solution_from_chalk(db, solution)) | 105 | solution.map(|solution| solution_from_chalk(db, solution)) |
99 | } | 106 | } |
100 | 107 | ||
108 | pub(crate) fn normalize_query( | ||
109 | db: &impl HirDatabase, | ||
110 | krate: Crate, | ||
111 | projection: Canonical<ProjectionPredicate>, | ||
112 | ) -> Option<Solution> { | ||
113 | let goal: chalk_ir::Goal = chalk_ir::Normalize { | ||
114 | projection: projection.value.projection_ty.to_chalk(db), | ||
115 | ty: projection.value.ty.to_chalk(db), | ||
116 | } | ||
117 | .cast(); | ||
118 | debug!("goal: {:?}", goal); | ||
119 | // FIXME unify with `implements` | ||
120 | let env = chalk_ir::Environment::new(); | ||
121 | let in_env = chalk_ir::InEnvironment::new(&env, goal); | ||
122 | let parameter = chalk_ir::ParameterKind::Ty(chalk_ir::UniverseIndex::ROOT); | ||
123 | let canonical = | ||
124 | chalk_ir::Canonical { value: in_env, binders: vec![parameter; projection.num_vars] }; | ||
125 | // We currently don't deal with universes (I think / hope they're not yet | ||
126 | // relevant for our use cases?) | ||
127 | let u_canonical = chalk_ir::UCanonical { canonical, universes: 1 }; | ||
128 | let solution = solve(db, krate, &u_canonical); | ||
129 | solution.map(|solution| solution_from_chalk(db, solution)) | ||
130 | } | ||
131 | |||
101 | fn solution_from_chalk(db: &impl HirDatabase, solution: chalk_solve::Solution) -> Solution { | 132 | fn solution_from_chalk(db: &impl HirDatabase, solution: chalk_solve::Solution) -> Solution { |
102 | let convert_subst = |subst: chalk_ir::Canonical<chalk_ir::Substitution>| { | 133 | let convert_subst = |subst: chalk_ir::Canonical<chalk_ir::Substitution>| { |
103 | let value = subst | 134 | let value = subst |
diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs index 1e4806db0..5105588ee 100644 --- a/crates/ra_hir/src/ty/traits/chalk.rs +++ b/crates/ra_hir/src/ty/traits/chalk.rs | |||
@@ -3,7 +3,7 @@ use std::sync::Arc; | |||
3 | 3 | ||
4 | use log::debug; | 4 | use log::debug; |
5 | 5 | ||
6 | use chalk_ir::{TypeId, ImplId, TypeKindId, ProjectionTy, Parameter, Identifier, cast::Cast, PlaceholderIndex, UniverseIndex, TypeName}; | 6 | use chalk_ir::{TypeId, ImplId, TypeKindId, Parameter, Identifier, cast::Cast, PlaceholderIndex, UniverseIndex, TypeName}; |
7 | use chalk_rust_ir::{AssociatedTyDatum, TraitDatum, StructDatum, ImplDatum}; | 7 | use chalk_rust_ir::{AssociatedTyDatum, TraitDatum, StructDatum, ImplDatum}; |
8 | 8 | ||
9 | use test_utils::tested_by; | 9 | use test_utils::tested_by; |
@@ -12,9 +12,9 @@ use ra_db::salsa::{InternId, InternKey}; | |||
12 | use crate::{ | 12 | use crate::{ |
13 | Trait, HasGenericParams, ImplBlock, | 13 | Trait, HasGenericParams, ImplBlock, |
14 | db::HirDatabase, | 14 | db::HirDatabase, |
15 | ty::{TraitRef, Ty, ApplicationTy, TypeCtor, Substs, GenericPredicate, CallableDef}, | 15 | ty::{TraitRef, Ty, ApplicationTy, TypeCtor, Substs, GenericPredicate, CallableDef, ProjectionTy}, |
16 | ty::display::HirDisplay, | 16 | ty::display::HirDisplay, |
17 | generics::GenericDef, | 17 | generics::GenericDef, TypeAlias, ImplItem, |
18 | }; | 18 | }; |
19 | use super::ChalkContext; | 19 | use super::ChalkContext; |
20 | 20 | ||
@@ -156,6 +156,18 @@ impl ToChalk for ImplBlock { | |||
156 | } | 156 | } |
157 | } | 157 | } |
158 | 158 | ||
159 | impl ToChalk for TypeAlias { | ||
160 | type Chalk = chalk_ir::TypeId; | ||
161 | |||
162 | fn to_chalk(self, _db: &impl HirDatabase) -> chalk_ir::TypeId { | ||
163 | self.id.into() | ||
164 | } | ||
165 | |||
166 | fn from_chalk(_db: &impl HirDatabase, impl_id: chalk_ir::TypeId) -> TypeAlias { | ||
167 | TypeAlias { id: impl_id.into() } | ||
168 | } | ||
169 | } | ||
170 | |||
159 | impl ToChalk for GenericPredicate { | 171 | impl ToChalk for GenericPredicate { |
160 | type Chalk = chalk_ir::QuantifiedWhereClause; | 172 | type Chalk = chalk_ir::QuantifiedWhereClause; |
161 | 173 | ||
@@ -183,6 +195,24 @@ impl ToChalk for GenericPredicate { | |||
183 | } | 195 | } |
184 | } | 196 | } |
185 | 197 | ||
198 | impl ToChalk for ProjectionTy { | ||
199 | type Chalk = chalk_ir::ProjectionTy; | ||
200 | |||
201 | fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::ProjectionTy { | ||
202 | chalk_ir::ProjectionTy { | ||
203 | associated_ty_id: self.associated_ty.to_chalk(db), | ||
204 | parameters: self.parameters.to_chalk(db), | ||
205 | } | ||
206 | } | ||
207 | |||
208 | fn from_chalk(db: &impl HirDatabase, projection_ty: chalk_ir::ProjectionTy) -> ProjectionTy { | ||
209 | ProjectionTy { | ||
210 | associated_ty: from_chalk(db, projection_ty.associated_ty_id), | ||
211 | parameters: from_chalk(db, projection_ty.parameters), | ||
212 | } | ||
213 | } | ||
214 | } | ||
215 | |||
186 | fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T> { | 216 | fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T> { |
187 | chalk_ir::Binders { | 217 | chalk_ir::Binders { |
188 | value, | 218 | value, |
@@ -225,8 +255,29 @@ impl<'a, DB> chalk_solve::RustIrDatabase for ChalkContext<'a, DB> | |||
225 | where | 255 | where |
226 | DB: HirDatabase, | 256 | DB: HirDatabase, |
227 | { | 257 | { |
228 | fn associated_ty_data(&self, _ty: TypeId) -> Arc<AssociatedTyDatum> { | 258 | fn associated_ty_data(&self, id: TypeId) -> Arc<AssociatedTyDatum> { |
229 | unimplemented!() | 259 | debug!("associated_ty_data {:?}", id); |
260 | let type_alias: TypeAlias = from_chalk(self.db, id); | ||
261 | let trait_ = match type_alias.container(self.db) { | ||
262 | Some(crate::Container::Trait(t)) => t, | ||
263 | _ => panic!("associated type not in trait"), | ||
264 | }; | ||
265 | let generic_params = type_alias.generic_params(self.db); | ||
266 | let parameter_kinds = generic_params | ||
267 | .params_including_parent() | ||
268 | .into_iter() | ||
269 | .map(|p| chalk_ir::ParameterKind::Ty(lalrpop_intern::intern(&p.name.to_string()))) | ||
270 | .collect(); | ||
271 | let datum = AssociatedTyDatum { | ||
272 | trait_id: trait_.to_chalk(self.db), | ||
273 | id, | ||
274 | name: lalrpop_intern::intern(&type_alias.name(self.db).to_string()), | ||
275 | parameter_kinds, | ||
276 | // FIXME add bounds and where clauses | ||
277 | bounds: vec![], | ||
278 | where_clauses: vec![], | ||
279 | }; | ||
280 | Arc::new(datum) | ||
230 | } | 281 | } |
231 | fn trait_datum(&self, trait_id: chalk_ir::TraitId) -> Arc<TraitDatum> { | 282 | fn trait_datum(&self, trait_id: chalk_ir::TraitId) -> Arc<TraitDatum> { |
232 | debug!("trait_datum {:?}", trait_id); | 283 | debug!("trait_datum {:?}", trait_id); |
@@ -260,7 +311,15 @@ where | |||
260 | fundamental: false, | 311 | fundamental: false, |
261 | }; | 312 | }; |
262 | let where_clauses = convert_where_clauses(self.db, trait_.into(), &bound_vars); | 313 | let where_clauses = convert_where_clauses(self.db, trait_.into(), &bound_vars); |
263 | let associated_ty_ids = Vec::new(); // FIXME add associated tys | 314 | let associated_ty_ids = trait_ |
315 | .items(self.db) | ||
316 | .into_iter() | ||
317 | .filter_map(|trait_item| match trait_item { | ||
318 | crate::traits::TraitItem::TypeAlias(type_alias) => Some(type_alias), | ||
319 | _ => None, | ||
320 | }) | ||
321 | .map(|type_alias| type_alias.to_chalk(self.db)) | ||
322 | .collect(); | ||
264 | let trait_datum_bound = | 323 | let trait_datum_bound = |
265 | chalk_rust_ir::TraitDatumBound { trait_ref, where_clauses, flags, associated_ty_ids }; | 324 | chalk_rust_ir::TraitDatumBound { trait_ref, where_clauses, flags, associated_ty_ids }; |
266 | let trait_datum = TraitDatum { binders: make_binders(trait_datum_bound, bound_vars.len()) }; | 325 | let trait_datum = TraitDatum { binders: make_binders(trait_datum_bound, bound_vars.len()) }; |
@@ -359,7 +418,29 @@ where | |||
359 | trait_ref.display(self.db), | 418 | trait_ref.display(self.db), |
360 | where_clauses | 419 | where_clauses |
361 | ); | 420 | ); |
421 | let trait_ = trait_ref.trait_; | ||
362 | let trait_ref = trait_ref.to_chalk(self.db); | 422 | let trait_ref = trait_ref.to_chalk(self.db); |
423 | let associated_ty_values = impl_block | ||
424 | .items(self.db) | ||
425 | .into_iter() | ||
426 | .filter_map(|item| match item { | ||
427 | ImplItem::TypeAlias(t) => Some(t), | ||
428 | _ => None, | ||
429 | }) | ||
430 | .filter_map(|t| { | ||
431 | let assoc_ty = trait_.associated_type_by_name(self.db, t.name(self.db))?; | ||
432 | let ty = self.db.type_for_def(t.into(), crate::Namespace::Types).subst(&bound_vars); | ||
433 | Some(chalk_rust_ir::AssociatedTyValue { | ||
434 | impl_id, | ||
435 | associated_ty_id: assoc_ty.to_chalk(self.db), | ||
436 | value: chalk_ir::Binders { | ||
437 | value: chalk_rust_ir::AssociatedTyValueBound { ty: ty.to_chalk(self.db) }, | ||
438 | binders: vec![], // we don't support GATs yet | ||
439 | }, | ||
440 | }) | ||
441 | }) | ||
442 | .collect(); | ||
443 | |||
363 | let impl_datum_bound = chalk_rust_ir::ImplDatumBound { | 444 | let impl_datum_bound = chalk_rust_ir::ImplDatumBound { |
364 | trait_ref: if negative { | 445 | trait_ref: if negative { |
365 | chalk_rust_ir::PolarizedTraitRef::Negative(trait_ref) | 446 | chalk_rust_ir::PolarizedTraitRef::Negative(trait_ref) |
@@ -367,9 +448,10 @@ where | |||
367 | chalk_rust_ir::PolarizedTraitRef::Positive(trait_ref) | 448 | chalk_rust_ir::PolarizedTraitRef::Positive(trait_ref) |
368 | }, | 449 | }, |
369 | where_clauses, | 450 | where_clauses, |
370 | associated_ty_values: Vec::new(), // FIXME add associated type values | 451 | associated_ty_values, |
371 | impl_type, | 452 | impl_type, |
372 | }; | 453 | }; |
454 | debug!("impl_datum: {:?}", impl_datum_bound); | ||
373 | let impl_datum = ImplDatum { binders: make_binders(impl_datum_bound, bound_vars.len()) }; | 455 | let impl_datum = ImplDatum { binders: make_binders(impl_datum_bound, bound_vars.len()) }; |
374 | Arc::new(impl_datum) | 456 | Arc::new(impl_datum) |
375 | } | 457 | } |
@@ -405,7 +487,7 @@ where | |||
405 | } | 487 | } |
406 | fn split_projection<'p>( | 488 | fn split_projection<'p>( |
407 | &self, | 489 | &self, |
408 | projection: &'p ProjectionTy, | 490 | projection: &'p chalk_ir::ProjectionTy, |
409 | ) -> (Arc<AssociatedTyDatum>, &'p [Parameter], &'p [Parameter]) { | 491 | ) -> (Arc<AssociatedTyDatum>, &'p [Parameter], &'p [Parameter]) { |
410 | debug!("split_projection {:?}", projection); | 492 | debug!("split_projection {:?}", projection); |
411 | unimplemented!() | 493 | unimplemented!() |
@@ -440,6 +522,18 @@ impl From<crate::ids::TraitId> for chalk_ir::TraitId { | |||
440 | } | 522 | } |
441 | } | 523 | } |
442 | 524 | ||
525 | impl From<chalk_ir::TypeId> for crate::ids::TypeAliasId { | ||
526 | fn from(type_id: chalk_ir::TypeId) -> Self { | ||
527 | id_from_chalk(type_id.0) | ||
528 | } | ||
529 | } | ||
530 | |||
531 | impl From<crate::ids::TypeAliasId> for chalk_ir::TypeId { | ||
532 | fn from(type_id: crate::ids::TypeAliasId) -> Self { | ||
533 | chalk_ir::TypeId(id_to_chalk(type_id)) | ||
534 | } | ||
535 | } | ||
536 | |||
443 | impl From<chalk_ir::StructId> for crate::ids::TypeCtorId { | 537 | impl From<chalk_ir::StructId> for crate::ids::TypeCtorId { |
444 | fn from(struct_id: chalk_ir::StructId) -> Self { | 538 | fn from(struct_id: chalk_ir::StructId) -> Self { |
445 | id_from_chalk(struct_id.0) | 539 | id_from_chalk(struct_id.0) |
diff --git a/crates/ra_hir/src/type_alias.rs b/crates/ra_hir/src/type_alias.rs index 87b9caa8a..eada37274 100644 --- a/crates/ra_hir/src/type_alias.rs +++ b/crates/ra_hir/src/type_alias.rs | |||
@@ -2,12 +2,22 @@ | |||
2 | 2 | ||
3 | use std::sync::Arc; | 3 | use std::sync::Arc; |
4 | 4 | ||
5 | use crate::{TypeAlias, DefDatabase, AstDatabase, HasSource, type_ref::TypeRef}; | 5 | use ra_syntax::ast::NameOwner; |
6 | 6 | ||
7 | pub(crate) fn type_alias_ref_query( | 7 | use crate::{TypeAlias, db::{DefDatabase, AstDatabase}, type_ref::TypeRef, name::{Name, AsName}, HasSource}; |
8 | |||
9 | #[derive(Debug, Clone, PartialEq, Eq)] | ||
10 | pub struct TypeAliasData { | ||
11 | pub(crate) name: Name, | ||
12 | pub(crate) type_ref: Option<TypeRef>, | ||
13 | } | ||
14 | |||
15 | pub(crate) fn type_alias_data_query( | ||
8 | db: &(impl DefDatabase + AstDatabase), | 16 | db: &(impl DefDatabase + AstDatabase), |
9 | typ: TypeAlias, | 17 | typ: TypeAlias, |
10 | ) -> Arc<TypeRef> { | 18 | ) -> Arc<TypeAliasData> { |
11 | let node = typ.source(db).ast; | 19 | let node = typ.source(db).ast; |
12 | Arc::new(TypeRef::from_ast_opt(node.type_ref())) | 20 | let name = node.name().map_or_else(Name::missing, |n| n.as_name()); |
21 | let type_ref = node.type_ref().map(TypeRef::from_ast); | ||
22 | Arc::new(TypeAliasData { name, type_ref }) | ||
13 | } | 23 | } |
diff --git a/crates/ra_ide_api/src/completion/complete_dot.rs b/crates/ra_ide_api/src/completion/complete_dot.rs index 0822a0e7e..f26fd06b3 100644 --- a/crates/ra_ide_api/src/completion/complete_dot.rs +++ b/crates/ra_ide_api/src/completion/complete_dot.rs | |||
@@ -15,7 +15,7 @@ pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) { | |||
15 | } | 15 | } |
16 | 16 | ||
17 | fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty) { | 17 | fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty) { |
18 | for receiver in receiver.autoderef(ctx.db) { | 18 | for receiver in ctx.analyzer.autoderef(ctx.db, receiver) { |
19 | if let Ty::Apply(a_ty) = receiver { | 19 | if let Ty::Apply(a_ty) = receiver { |
20 | match a_ty.ctor { | 20 | match a_ty.ctor { |
21 | TypeCtor::Adt(AdtDef::Struct(s)) => { | 21 | TypeCtor::Adt(AdtDef::Struct(s)) => { |
diff --git a/crates/ra_ide_api/src/goto_type_definition.rs b/crates/ra_ide_api/src/goto_type_definition.rs index 0f638b170..6f5164e0b 100644 --- a/crates/ra_ide_api/src/goto_type_definition.rs +++ b/crates/ra_ide_api/src/goto_type_definition.rs | |||
@@ -30,7 +30,7 @@ pub(crate) fn goto_type_definition( | |||
30 | return None; | 30 | return None; |
31 | }; | 31 | }; |
32 | 32 | ||
33 | let adt_def = ty.autoderef(db).find_map(|ty| ty.as_adt().map(|adt| adt.0))?; | 33 | let adt_def = analyzer.autoderef(db, ty).find_map(|ty| ty.as_adt().map(|adt| adt.0))?; |
34 | 34 | ||
35 | let nav = NavigationTarget::from_adt_def(db, adt_def); | 35 | let nav = NavigationTarget::from_adt_def(db, adt_def); |
36 | Some(RangeInfo::new(node.range(), vec![nav])) | 36 | Some(RangeInfo::new(node.range(), vec![nav])) |