aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/ty
diff options
context:
space:
mode:
authorFlorian Diebold <[email protected]>2019-05-05 13:21:00 +0100
committerFlorian Diebold <[email protected]>2019-05-11 15:21:20 +0100
commit50bbf9eb09dc34781cc34e10bfba5f154e833123 (patch)
tree6ed1ff97c8923ddeea085c75d417d5185493ef11 /crates/ra_hir/src/ty
parent940c538ecf42a53e5a0e0e9ebad7267c1fe843ca (diff)
Handle where clauses in trait solving
Diffstat (limited to 'crates/ra_hir/src/ty')
-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
3 files changed, 138 insertions, 24 deletions
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 }