aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir
diff options
context:
space:
mode:
authorbors[bot] <bors[bot]@users.noreply.github.com>2019-06-16 13:00:41 +0100
committerbors[bot] <bors[bot]@users.noreply.github.com>2019-06-16 13:00:41 +0100
commitb81caed43f1886024ededad41a1baa8a03f1d2f4 (patch)
tree0a0289899ec59b425eae6369929a01e97065ce43 /crates/ra_hir
parente6fbff3246cdd3278ff1c376d5abfc1d579f86c2 (diff)
parentad3673d8d86a9b8f1a8dba858abd7cabaa1d5776 (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]>
Diffstat (limited to 'crates/ra_hir')
-rw-r--r--crates/ra_hir/Cargo.toml1
-rw-r--r--crates/ra_hir/src/code_model.rs20
-rw-r--r--crates/ra_hir/src/db.rs14
-rw-r--r--crates/ra_hir/src/lang_item.rs49
-rw-r--r--crates/ra_hir/src/name.rs5
-rw-r--r--crates/ra_hir/src/source_binder.rs11
-rw-r--r--crates/ra_hir/src/ty.rs28
-rw-r--r--crates/ra_hir/src/ty/autoderef.rs89
-rw-r--r--crates/ra_hir/src/ty/infer.rs48
-rw-r--r--crates/ra_hir/src/ty/lower.rs2
-rw-r--r--crates/ra_hir/src/ty/method_resolution.rs5
-rw-r--r--crates/ra_hir/src/ty/tests.rs84
-rw-r--r--crates/ra_hir/src/ty/traits.rs33
-rw-r--r--crates/ra_hir/src/ty/traits/chalk.rs110
-rw-r--r--crates/ra_hir/src/type_alias.rs18
15 files changed, 450 insertions, 67 deletions
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" }
25chalk-solve = { git = "https://github.com/flodiebold/chalk.git", branch = "fuel" } 25chalk-solve = { git = "https://github.com/flodiebold/chalk.git", branch = "fuel" }
26chalk-rust-ir = { git = "https://github.com/flodiebold/chalk.git", branch = "fuel" } 26chalk-rust-ir = { git = "https://github.com/flodiebold/chalk.git", branch = "fuel" }
27chalk-ir = { git = "https://github.com/flodiebold/chalk.git", branch = "fuel" } 27chalk-ir = { git = "https://github.com/flodiebold/chalk.git", branch = "fuel" }
28lalrpop-intern = "0.15.1"
28 29
29[dev-dependencies] 30[dev-dependencies]
30flexi_logger = "0.11.0" 31flexi_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 @@
1use std::sync::Arc; 1use std::sync::Arc;
2use rustc_hash::FxHashMap; 2use rustc_hash::FxHashMap;
3 3
4use ra_syntax::{SmolStr, ast::AttrsOwner}; 4use ra_syntax::{SmolStr, TreeArc, ast::AttrsOwner};
5 5
6use crate::{ 6use 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
132fn 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;
16use std::ops::Deref; 16use std::ops::Deref;
17use std::{fmt, mem}; 17use std::{fmt, mem};
18 18
19use crate::{Name, AdtDef, type_ref::Mutability, db::HirDatabase, Trait, GenericParams}; 19use crate::{Name, AdtDef, type_ref::Mutability, db::HirDatabase, Trait, GenericParams, TypeAlias};
20use display::{HirDisplay, HirFormatter}; 20use display::{HirDisplay, HirFormatter};
21 21
22pub(crate) use lower::{TypableDef, type_for_def, type_for_field, callable_item_sig, generic_predicates, generic_defaults}; 22pub(crate) use lower::{TypableDef, type_for_def, type_for_field, callable_item_sig, generic_predicates, generic_defaults};
23pub(crate) use infer::{infer_query, InferenceResult, InferTy}; 23pub(crate) use infer::{infer_query, InferenceResult, InferTy};
24pub use lower::CallableDef; 24pub use lower::CallableDef;
25pub(crate) use autoderef::autoderef;
26pub(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)]
109pub 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)]
217pub struct TraitRef { 228pub 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
223impl TraitRef { 234impl 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
469impl HirDisplay for &Ty { 491impl 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
6use std::iter::successors; 6use std::iter::successors;
7 7
8use crate::HirDatabase; 8use log::{info, warn};
9use super::Ty;
10 9
11impl Ty { 10use crate::{HirDatabase, Name, Resolver, HasGenericParams};
12 /// Iterates over the possible derefs of `ty`. 11use 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)) 13const AUTODEREF_RECURSION_LIMIT: usize = 10;
14
15pub(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
23pub(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
35fn 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::{
46use super::{ 46use 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
52mod unify; 52mod 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};
19use super::{TraitRef, Canonical}; 19use 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]
2741fn deref_trait() {
2742 let t = type_at(
2743 r#"
2744//- /main.rs
2745#[lang = "deref"]
2746trait Deref {
2747 type Target;
2748 fn deref(&self) -> &Self::Target;
2749}
2750
2751struct Arc<T>;
2752impl<T> Deref for Arc<T> {
2753 type Target = T;
2754}
2755
2756struct S;
2757impl S {
2758 fn foo(&self) -> u128 {}
2759}
2760
2761fn test(s: Arc<S>) {
2762 (*s, s.foo())<|>
2763}
2764"#,
2765 );
2766 assert_eq!(t, "(S, u128)");
2767}
2768
2769#[test]
2770fn deref_trait_with_inference_var() {
2771 let t = type_at(
2772 r#"
2773//- /main.rs
2774#[lang = "deref"]
2775trait Deref {
2776 type Target;
2777 fn deref(&self) -> &Self::Target;
2778}
2779
2780struct Arc<T>;
2781fn new_arc<T>() -> Arc<T> {}
2782impl<T> Deref for Arc<T> {
2783 type Target = T;
2784}
2785
2786struct S;
2787fn foo(a: Arc<S>) {}
2788
2789fn 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]
2800fn deref_trait_infinite_recursion() {
2801 let t = type_at(
2802 r#"
2803//- /main.rs
2804#[lang = "deref"]
2805trait Deref {
2806 type Target;
2807 fn deref(&self) -> &Self::Target;
2808}
2809
2810struct S;
2811
2812impl Deref for S {
2813 type Target = S;
2814}
2815
2816fn test(s: S) {
2817 s.foo()<|>;
2818}
2819"#,
2820 );
2821 assert_eq!(t, "{unknown}");
2822}
2823
2740fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { 2824fn 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;
8use ra_prof::profile; 8use ra_prof::profile;
9 9
10use crate::{Crate, Trait, db::HirDatabase, ImplBlock}; 10use crate::{Crate, Trait, db::HirDatabase, ImplBlock};
11use super::{TraitRef, Ty, Canonical}; 11use super::{TraitRef, Ty, Canonical, ProjectionTy};
12 12
13use self::chalk::{ToChalk, from_chalk}; 13use 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)]
82pub 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
108pub(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
101fn solution_from_chalk(db: &impl HirDatabase, solution: chalk_solve::Solution) -> Solution { 132fn 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
4use log::debug; 4use log::debug;
5 5
6use chalk_ir::{TypeId, ImplId, TypeKindId, ProjectionTy, Parameter, Identifier, cast::Cast, PlaceholderIndex, UniverseIndex, TypeName}; 6use chalk_ir::{TypeId, ImplId, TypeKindId, 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 test_utils::tested_by;
@@ -12,9 +12,9 @@ use ra_db::salsa::{InternId, InternKey};
12use crate::{ 12use 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};
19use super::ChalkContext; 19use super::ChalkContext;
20 20
@@ -156,6 +156,18 @@ impl ToChalk for ImplBlock {
156 } 156 }
157} 157}
158 158
159impl 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
159impl ToChalk for GenericPredicate { 171impl 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
198impl 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
186fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T> { 216fn 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>
225where 255where
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
525impl 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
531impl 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
443impl From<chalk_ir::StructId> for crate::ids::TypeCtorId { 537impl 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
3use std::sync::Arc; 3use std::sync::Arc;
4 4
5use crate::{TypeAlias, DefDatabase, AstDatabase, HasSource, type_ref::TypeRef}; 5use ra_syntax::ast::NameOwner;
6 6
7pub(crate) fn type_alias_ref_query( 7use crate::{TypeAlias, db::{DefDatabase, AstDatabase}, type_ref::TypeRef, name::{Name, AsName}, HasSource};
8
9#[derive(Debug, Clone, PartialEq, Eq)]
10pub struct TypeAliasData {
11 pub(crate) name: Name,
12 pub(crate) type_ref: Option<TypeRef>,
13}
14
15pub(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}