aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_hir/src/db.rs5
-rw-r--r--crates/ra_hir/src/generics.rs19
-rw-r--r--crates/ra_hir/src/ty.rs31
-rw-r--r--crates/ra_hir/src/ty/lower.rs53
-rw-r--r--crates/ra_hir/src/ty/tests.rs41
-rw-r--r--crates/ra_hir/src/ty/traits/chalk.rs68
6 files changed, 188 insertions, 29 deletions
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs
index 689dd6225..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,
diff --git a/crates/ra_hir/src/generics.rs b/crates/ra_hir/src/generics.rs
index 2e52c5871..826117ba5 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)
@@ -148,6 +148,19 @@ impl GenericParams {
148 } 148 }
149} 149}
150 150
151impl GenericDef {
152 pub(crate) fn resolver(&self, db: &impl HirDatabase) -> crate::Resolver {
153 match self {
154 GenericDef::Function(inner) => inner.resolver(db),
155 GenericDef::Struct(inner) => inner.resolver(db),
156 GenericDef::Enum(inner) => inner.resolver(db),
157 GenericDef::Trait(inner) => inner.resolver(db),
158 GenericDef::TypeAlias(inner) => inner.resolver(db),
159 GenericDef::ImplBlock(inner) => inner.resolver(db),
160 }
161 }
162}
163
151impl From<Container> for GenericDef { 164impl From<Container> for GenericDef {
152 fn from(c: Container) -> Self { 165 fn from(c: Container) -> Self {
153 match c { 166 match c {
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index 12429a668..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,6 +234,35 @@ 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
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/tests.rs b/crates/ra_hir/src/ty/tests.rs
index a38fe35c7..c3edf42b1 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -2510,12 +2510,47 @@ fn method_resolution_where_clause_not_met() {
2510trait Clone {} 2510trait Clone {}
2511trait Trait { fn foo(self) -> u128; } 2511trait Trait { fn foo(self) -> u128; }
2512struct S; 2512struct S;
2513impl S { fn foo(self) -> i8 { 0 } } 2513impl<T> Trait for T where T: Clone {}
2514impl<T> Trait for T where T: Clone { fn foo(self) -> u128 { 0 } }
2515fn test() { (&S).foo()<|>; } 2514fn test() { (&S).foo()<|>; }
2516"#, 2515"#,
2517 ); 2516 );
2518 assert_eq!(t, "i8"); 2517 // This is also to make sure that we don't resolve to the foo method just
2518 // because that's the only method named foo we can find, which would make
2519 // the below tests not work
2520 assert_eq!(t, "{unknown}");
2521}
2522
2523#[test]
2524fn method_resolution_where_clause_1() {
2525 let t = type_at(
2526 r#"
2527//- /main.rs
2528trait Clone {}
2529trait Trait { fn foo(self) -> u128; }
2530struct S;
2531impl Clone for S {};
2532impl<T> Trait for T where T: Clone {}
2533fn test() { S.foo()<|>; }
2534"#,
2535 );
2536 assert_eq!(t, "u128");
2537}
2538
2539#[test]
2540fn method_resolution_where_clause_2() {
2541 let t = type_at(
2542 r#"
2543//- /main.rs
2544trait Into<T> { fn into(self) -> T; }
2545trait From<T> { fn from(other: T) -> Self; }
2546struct S1;
2547struct S2;
2548impl From<S2> for S1 {};
2549impl<T, U> Into<U> for T where U: From<T> {}
2550fn test() { S2.into()<|>; }
2551"#,
2552 );
2553 assert_eq!(t, "S1");
2519} 2554}
2520 2555
2521fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { 2556fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String {
diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs
index 8b77d21b4..2772a0432 100644
--- a/crates/ra_hir/src/ty/traits/chalk.rs
+++ b/crates/ra_hir/src/ty/traits/chalk.rs
@@ -11,7 +11,7 @@ use ra_db::salsa::{InternId, InternKey};
11use crate::{ 11use crate::{
12 Trait, HasGenericParams, ImplBlock, 12 Trait, HasGenericParams, ImplBlock,
13 db::HirDatabase, 13 db::HirDatabase,
14 ty::{TraitRef, Ty, ApplicationTy, TypeCtor, Substs}, 14 ty::{TraitRef, Ty, ApplicationTy, TypeCtor, Substs, GenericPredicate}, generics::GenericDef,
15}; 15};
16use super::ChalkContext; 16use super::ChalkContext;
17 17
@@ -146,6 +146,27 @@ impl ToChalk for ImplBlock {
146 } 146 }
147} 147}
148 148
149impl ToChalk for GenericPredicate {
150 type Chalk = chalk_ir::QuantifiedWhereClause;
151
152 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::QuantifiedWhereClause {
153 match self {
154 GenericPredicate::Implemented(trait_ref) => {
155 make_binders(chalk_ir::WhereClause::Implemented(trait_ref.to_chalk(db)), 0)
156 }
157 GenericPredicate::Error => panic!("Trying to pass errored where clause to Chalk"),
158 }
159 }
160
161 fn from_chalk(
162 _db: &impl HirDatabase,
163 _where_clause: chalk_ir::QuantifiedWhereClause,
164 ) -> GenericPredicate {
165 // This should never need to be called
166 unimplemented!()
167 }
168}
169
149fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T> { 170fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T> {
150 chalk_ir::Binders { 171 chalk_ir::Binders {
151 value, 172 value,
@@ -153,6 +174,25 @@ fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T> {
153 } 174 }
154} 175}
155 176
177fn convert_where_clauses(
178 db: &impl HirDatabase,
179 def: GenericDef,
180 substs: &Substs,
181) -> (Vec<chalk_ir::QuantifiedWhereClause>, bool) {
182 let generic_predicates = db.generic_predicates(def);
183 let mut result = Vec::with_capacity(generic_predicates.len());
184 let mut has_error = false;
185 for pred in generic_predicates.iter() {
186 // FIXME: it would probably be nicer if we could just convert errored predicates to a where clause that is never true...
187 if pred.is_error() {
188 has_error = true;
189 } else {
190 result.push(pred.clone().subst(substs).to_chalk(db));
191 }
192 }
193 (result, has_error)
194}
195
156impl<'a, DB> chalk_solve::RustIrDatabase for ChalkContext<'a, DB> 196impl<'a, DB> chalk_solve::RustIrDatabase for ChalkContext<'a, DB>
157where 197where
158 DB: HirDatabase, 198 DB: HirDatabase,
@@ -173,7 +213,7 @@ where
173 upstream: trait_.module(self.db).krate(self.db) != Some(self.krate), 213 upstream: trait_.module(self.db).krate(self.db) != Some(self.krate),
174 fundamental: false, 214 fundamental: false,
175 }; 215 };
176 let where_clauses = Vec::new(); // FIXME add where clauses 216 let (where_clauses, _) = convert_where_clauses(self.db, trait_.into(), &bound_vars);
177 let associated_ty_ids = Vec::new(); // FIXME add associated tys 217 let associated_ty_ids = Vec::new(); // FIXME add associated tys
178 let trait_datum_bound = 218 let trait_datum_bound =
179 chalk_rust_ir::TraitDatumBound { trait_ref, where_clauses, flags, associated_ty_ids }; 219 chalk_rust_ir::TraitDatumBound { trait_ref, where_clauses, flags, associated_ty_ids };
@@ -185,21 +225,26 @@ where
185 let type_ctor = from_chalk(self.db, struct_id); 225 let type_ctor = from_chalk(self.db, struct_id);
186 // FIXME might be nicer if we can create a fake GenericParams for the TypeCtor 226 // FIXME might be nicer if we can create a fake GenericParams for the TypeCtor
187 // FIXME extract this to a method on Ty 227 // FIXME extract this to a method on Ty
188 let (num_params, upstream) = match type_ctor { 228 let (num_params, where_clauses, upstream) = match type_ctor {
189 TypeCtor::Bool 229 TypeCtor::Bool
190 | TypeCtor::Char 230 | TypeCtor::Char
191 | TypeCtor::Int(_) 231 | TypeCtor::Int(_)
192 | TypeCtor::Float(_) 232 | TypeCtor::Float(_)
193 | TypeCtor::Never 233 | TypeCtor::Never
194 | TypeCtor::Str => (0, true), 234 | TypeCtor::Str => (0, vec![], true),
195 TypeCtor::Slice | TypeCtor::Array | TypeCtor::RawPtr(_) | TypeCtor::Ref(_) => (1, true), 235 TypeCtor::Slice | TypeCtor::Array | TypeCtor::RawPtr(_) | TypeCtor::Ref(_) => {
196 TypeCtor::FnPtr { num_args } => (num_args as usize + 1, true), 236 (1, vec![], true)
197 TypeCtor::Tuple { cardinality } => (cardinality as usize, true), 237 }
238 TypeCtor::FnPtr { num_args } => (num_args as usize + 1, vec![], true),
239 TypeCtor::Tuple { cardinality } => (cardinality as usize, vec![], true),
198 TypeCtor::FnDef(_) => unimplemented!(), 240 TypeCtor::FnDef(_) => unimplemented!(),
199 TypeCtor::Adt(adt) => { 241 TypeCtor::Adt(adt) => {
200 let generic_params = adt.generic_params(self.db); 242 let generic_params = adt.generic_params(self.db);
243 let bound_vars = Substs::bound_vars(&generic_params);
244 let (where_clauses, _) = convert_where_clauses(self.db, adt.into(), &bound_vars);
201 ( 245 (
202 generic_params.count_params_including_parent(), 246 generic_params.count_params_including_parent(),
247 where_clauses,
203 adt.krate(self.db) != Some(self.krate), 248 adt.krate(self.db) != Some(self.krate),
204 ) 249 )
205 } 250 }
@@ -209,7 +254,6 @@ where
209 // FIXME set fundamental flag correctly 254 // FIXME set fundamental flag correctly
210 fundamental: false, 255 fundamental: false,
211 }; 256 };
212 let where_clauses = Vec::new(); // FIXME add where clauses
213 let self_ty = chalk_ir::ApplicationTy { 257 let self_ty = chalk_ir::ApplicationTy {
214 name: TypeName::TypeKindId(type_ctor.to_chalk(self.db).into()), 258 name: TypeName::TypeKindId(type_ctor.to_chalk(self.db).into()),
215 parameters: (0..num_params).map(|i| chalk_ir::Ty::BoundVar(i).cast()).collect(), 259 parameters: (0..num_params).map(|i| chalk_ir::Ty::BoundVar(i).cast()).collect(),
@@ -237,10 +281,12 @@ where
237 } else { 281 } else {
238 chalk_rust_ir::ImplType::External 282 chalk_rust_ir::ImplType::External
239 }; 283 };
284 let (where_clauses, where_clause_error) =
285 convert_where_clauses(self.db, impl_block.into(), &bound_vars);
240 let impl_datum_bound = chalk_rust_ir::ImplDatumBound { 286 let impl_datum_bound = chalk_rust_ir::ImplDatumBound {
241 // FIXME handle negative impls (impl !Sync for Foo) 287 // FIXME handle negative impls (impl !Sync for Foo)
242 trait_ref: chalk_rust_ir::PolarizedTraitRef::Positive(trait_ref.to_chalk(self.db)), 288 trait_ref: chalk_rust_ir::PolarizedTraitRef::Positive(trait_ref.to_chalk(self.db)),
243 where_clauses: Vec::new(), // FIXME add where clauses 289 where_clauses,
244 associated_ty_values: Vec::new(), // FIXME add associated type values 290 associated_ty_values: Vec::new(), // FIXME add associated type values
245 impl_type, 291 impl_type,
246 }; 292 };
@@ -253,10 +299,6 @@ where
253 self.db 299 self.db
254 .impls_for_trait(self.krate, trait_) 300 .impls_for_trait(self.krate, trait_)
255 .iter() 301 .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)) 302 .map(|impl_block| impl_block.to_chalk(self.db))
261 .collect() 303 .collect()
262 } 304 }