aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/ty
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir/src/ty')
-rw-r--r--crates/ra_hir/src/ty/infer.rs3
-rw-r--r--crates/ra_hir/src/ty/lower.rs53
-rw-r--r--crates/ra_hir/src/ty/method_resolution.rs17
-rw-r--r--crates/ra_hir/src/ty/tests.rs160
-rw-r--r--crates/ra_hir/src/ty/traits.rs20
-rw-r--r--crates/ra_hir/src/ty/traits/chalk.rs179
6 files changed, 383 insertions, 49 deletions
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs
index edce1afe7..1e7d97f51 100644
--- a/crates/ra_hir/src/ty/infer.rs
+++ b/crates/ra_hir/src/ty/infer.rs
@@ -328,8 +328,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
328 Obligation::Trait(tr) => { 328 Obligation::Trait(tr) => {
329 let canonicalized = self.canonicalizer().canonicalize_trait_ref(tr.clone()); 329 let canonicalized = self.canonicalizer().canonicalize_trait_ref(tr.clone());
330 ( 330 (
331 super::traits::implements( 331 self.db.implements(
332 self.db,
333 self.resolver.krate().unwrap(), 332 self.resolver.krate().unwrap(),
334 canonicalized.value.clone(), 333 canonicalized.value.clone(),
335 ), 334 ),
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs
index 8bab7e54b..09d26ce5a 100644
--- a/crates/ra_hir/src/ty/lower.rs
+++ b/crates/ra_hir/src/ty/lower.rs
@@ -5,6 +5,7 @@
5//! - Building the type for an item: This happens through the `type_for_def` query. 5//! - Building the type for an item: This happens through the `type_for_def` query.
6//! 6//!
7//! This usually involves resolving names, collecting generic arguments etc. 7//! This usually involves resolving names, collecting generic arguments etc.
8use std::sync::Arc;
8use std::iter; 9use std::iter;
9 10
10use crate::{ 11use crate::{
@@ -18,9 +19,9 @@ use crate::{
18 resolve::{Resolver, Resolution}, 19 resolve::{Resolver, Resolution},
19 path::{PathSegment, GenericArg}, 20 path::{PathSegment, GenericArg},
20 generics::{GenericParams, HasGenericParams}, 21 generics::{GenericParams, HasGenericParams},
21 adt::VariantDef, Trait 22 adt::VariantDef, Trait, generics::{ WherePredicate, GenericDef}
22}; 23};
23use super::{Ty, primitive, FnSig, Substs, TypeCtor, TraitRef}; 24use super::{Ty, primitive, FnSig, Substs, TypeCtor, TraitRef, GenericPredicate};
24 25
25impl Ty { 26impl Ty {
26 pub(crate) fn from_hir(db: &impl HirDatabase, resolver: &Resolver, type_ref: &TypeRef) -> Self { 27 pub(crate) fn from_hir(db: &impl HirDatabase, resolver: &Resolver, type_ref: &TypeRef) -> Self {
@@ -208,16 +209,12 @@ pub(super) fn substs_from_path_segment(
208} 209}
209 210
210impl TraitRef { 211impl TraitRef {
211 pub(crate) fn from_hir( 212 pub(crate) fn from_path(
212 db: &impl HirDatabase, 213 db: &impl HirDatabase,
213 resolver: &Resolver, 214 resolver: &Resolver,
214 type_ref: &TypeRef, 215 path: &Path,
215 explicit_self_ty: Option<Ty>, 216 explicit_self_ty: Option<Ty>,
216 ) -> Option<Self> { 217 ) -> Option<Self> {
217 let path = match type_ref {
218 TypeRef::Path(path) => path,
219 _ => return None,
220 };
221 let resolved = match resolver.resolve_path(db, &path).take_types()? { 218 let resolved = match resolver.resolve_path(db, &path).take_types()? {
222 Resolution::Def(ModuleDef::Trait(tr)) => tr, 219 Resolution::Def(ModuleDef::Trait(tr)) => tr,
223 _ => return None, 220 _ => return None,
@@ -232,6 +229,19 @@ impl TraitRef {
232 Some(TraitRef { trait_: resolved, substs }) 229 Some(TraitRef { trait_: resolved, substs })
233 } 230 }
234 231
232 pub(crate) fn from_hir(
233 db: &impl HirDatabase,
234 resolver: &Resolver,
235 type_ref: &TypeRef,
236 explicit_self_ty: Option<Ty>,
237 ) -> Option<Self> {
238 let path = match type_ref {
239 TypeRef::Path(path) => path,
240 _ => return None,
241 };
242 TraitRef::from_path(db, resolver, path, explicit_self_ty)
243 }
244
235 fn substs_from_path( 245 fn substs_from_path(
236 db: &impl HirDatabase, 246 db: &impl HirDatabase,
237 resolver: &Resolver, 247 resolver: &Resolver,
@@ -246,6 +256,15 @@ impl TraitRef {
246 let substs = Substs::identity(&trait_.generic_params(db)); 256 let substs = Substs::identity(&trait_.generic_params(db));
247 TraitRef { trait_, substs } 257 TraitRef { trait_, substs }
248 } 258 }
259
260 pub(crate) fn for_where_predicate(
261 db: &impl HirDatabase,
262 resolver: &Resolver,
263 pred: &WherePredicate,
264 ) -> Option<TraitRef> {
265 let self_ty = Ty::from_hir(db, resolver, &pred.type_ref);
266 TraitRef::from_path(db, resolver, &pred.trait_ref, Some(self_ty))
267 }
249} 268}
250 269
251/// Build the declared type of an item. This depends on the namespace; e.g. for 270/// Build the declared type of an item. This depends on the namespace; e.g. for
@@ -294,6 +313,24 @@ pub(crate) fn type_for_field(db: &impl HirDatabase, field: StructField) -> Ty {
294 Ty::from_hir(db, &resolver, type_ref) 313 Ty::from_hir(db, &resolver, type_ref)
295} 314}
296 315
316/// Resolve the where clause(s) of an item with generics.
317pub(crate) fn generic_predicates(
318 db: &impl HirDatabase,
319 def: GenericDef,
320) -> Arc<[GenericPredicate]> {
321 let resolver = def.resolver(db);
322 let generic_params = def.generic_params(db);
323 let predicates = generic_params
324 .where_predicates
325 .iter()
326 .map(|pred| {
327 TraitRef::for_where_predicate(db, &resolver, pred)
328 .map_or(GenericPredicate::Error, GenericPredicate::Implemented)
329 })
330 .collect::<Vec<_>>();
331 predicates.into()
332}
333
297fn fn_sig_for_fn(db: &impl HirDatabase, def: Function) -> FnSig { 334fn fn_sig_for_fn(db: &impl HirDatabase, def: Function) -> FnSig {
298 let signature = def.signature(db); 335 let signature = def.signature(db);
299 let resolver = def.resolver(db); 336 let resolver = def.resolver(db);
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs
index 607e9ba79..34817a5ec 100644
--- a/crates/ra_hir/src/ty/method_resolution.rs
+++ b/crates/ra_hir/src/ty/method_resolution.rs
@@ -75,11 +75,13 @@ impl CrateImplBlocks {
75 75
76 let target_ty = impl_block.target_ty(db); 76 let target_ty = impl_block.target_ty(db);
77 77
78 if let Some(tr) = impl_block.target_trait_ref(db) { 78 if impl_block.target_trait(db).is_some() {
79 self.impls_by_trait 79 if let Some(tr) = impl_block.target_trait_ref(db) {
80 .entry(tr.trait_) 80 self.impls_by_trait
81 .or_insert_with(Vec::new) 81 .entry(tr.trait_)
82 .push((module.module_id, impl_id)); 82 .or_insert_with(Vec::new)
83 .push((module.module_id, impl_id));
84 }
83 } else { 85 } else {
84 if let Some(target_ty_fp) = TyFingerprint::for_impl(&target_ty) { 86 if let Some(target_ty_fp) = TyFingerprint::for_impl(&target_ty) {
85 self.impls 87 self.impls
@@ -183,7 +185,7 @@ fn iterate_trait_method_candidates<T>(
183 mut callback: impl FnMut(&Ty, Function) -> Option<T>, 185 mut callback: impl FnMut(&Ty, Function) -> Option<T>,
184) -> Option<T> { 186) -> Option<T> {
185 let krate = resolver.krate()?; 187 let krate = resolver.krate()?;
186 'traits: for t in resolver.traits_in_scope() { 188 'traits: for t in resolver.traits_in_scope(db) {
187 let data = t.trait_data(db); 189 let data = t.trait_data(db);
188 // we'll be lazy about checking whether the type implements the 190 // we'll be lazy about checking whether the type implements the
189 // trait, but if we find out it doesn't, we'll skip the rest of the 191 // trait, but if we find out it doesn't, we'll skip the rest of the
@@ -196,8 +198,7 @@ fn iterate_trait_method_candidates<T>(
196 if name.map_or(true, |name| sig.name() == name) && sig.has_self_param() { 198 if name.map_or(true, |name| sig.name() == name) && sig.has_self_param() {
197 if !known_implemented { 199 if !known_implemented {
198 let trait_ref = canonical_trait_ref(db, t, ty.clone()); 200 let trait_ref = canonical_trait_ref(db, t, ty.clone());
199 // FIXME cache this implements check (without solution) in a query? 201 if db.implements(krate, trait_ref).is_none() {
200 if super::traits::implements(db, krate, trait_ref).is_none() {
201 continue 'traits; 202 continue 'traits;
202 } 203 }
203 } 204 }
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index a38fe35c7..978cc2587 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -2502,6 +2502,50 @@ fn test() { (&S).foo()<|>; }
2502} 2502}
2503 2503
2504#[test] 2504#[test]
2505fn method_resolution_trait_from_prelude() {
2506 let (mut db, pos) = MockDatabase::with_position(
2507 r#"
2508//- /main.rs
2509struct S;
2510impl Clone for S {}
2511
2512fn test() {
2513 S.clone()<|>;
2514}
2515
2516//- /lib.rs
2517#[prelude_import] use foo::*;
2518
2519mod foo {
2520 trait Clone {
2521 fn clone(&self) -> Self;
2522 }
2523}
2524"#,
2525 );
2526 db.set_crate_graph_from_fixture(crate_graph! {
2527 "main": ("/main.rs", ["other_crate"]),
2528 "other_crate": ("/lib.rs", []),
2529 });
2530 assert_eq!("S", type_at_pos(&db, pos));
2531}
2532
2533#[test]
2534fn method_resolution_where_clause_for_unknown_trait() {
2535 // The blanket impl shouldn't apply because we can't even resolve UnknownTrait
2536 let t = type_at(
2537 r#"
2538//- /main.rs
2539trait Trait { fn foo(self) -> u128; }
2540struct S;
2541impl<T> Trait for T where T: UnknownTrait {}
2542fn test() { (&S).foo()<|>; }
2543"#,
2544 );
2545 assert_eq!(t, "{unknown}");
2546}
2547
2548#[test]
2505fn method_resolution_where_clause_not_met() { 2549fn method_resolution_where_clause_not_met() {
2506 // The blanket impl shouldn't apply because we can't prove S: Clone 2550 // The blanket impl shouldn't apply because we can't prove S: Clone
2507 let t = type_at( 2551 let t = type_at(
@@ -2510,12 +2554,122 @@ fn method_resolution_where_clause_not_met() {
2510trait Clone {} 2554trait Clone {}
2511trait Trait { fn foo(self) -> u128; } 2555trait Trait { fn foo(self) -> u128; }
2512struct S; 2556struct S;
2513impl S { fn foo(self) -> i8 { 0 } } 2557impl<T> Trait for T where T: Clone {}
2514impl<T> Trait for T where T: Clone { fn foo(self) -> u128 { 0 } }
2515fn test() { (&S).foo()<|>; } 2558fn test() { (&S).foo()<|>; }
2516"#, 2559"#,
2517 ); 2560 );
2518 assert_eq!(t, "i8"); 2561 // This is also to make sure that we don't resolve to the foo method just
2562 // because that's the only method named foo we can find, which would make
2563 // the below tests not work
2564 assert_eq!(t, "{unknown}");
2565}
2566
2567#[test]
2568fn method_resolution_where_clause_inline_not_met() {
2569 // The blanket impl shouldn't apply because we can't prove S: Clone
2570 let t = type_at(
2571 r#"
2572//- /main.rs
2573trait Clone {}
2574trait Trait { fn foo(self) -> u128; }
2575struct S;
2576impl<T: Clone> Trait for T {}
2577fn test() { (&S).foo()<|>; }
2578"#,
2579 );
2580 assert_eq!(t, "{unknown}");
2581}
2582
2583#[test]
2584fn method_resolution_where_clause_1() {
2585 let t = type_at(
2586 r#"
2587//- /main.rs
2588trait Clone {}
2589trait Trait { fn foo(self) -> u128; }
2590struct S;
2591impl Clone for S {};
2592impl<T> Trait for T where T: Clone {}
2593fn test() { S.foo()<|>; }
2594"#,
2595 );
2596 assert_eq!(t, "u128");
2597}
2598
2599#[test]
2600fn method_resolution_where_clause_2() {
2601 let t = type_at(
2602 r#"
2603//- /main.rs
2604trait Into<T> { fn into(self) -> T; }
2605trait From<T> { fn from(other: T) -> Self; }
2606struct S1;
2607struct S2;
2608impl From<S2> for S1 {};
2609impl<T, U> Into<U> for T where U: From<T> {}
2610fn test() { S2.into()<|>; }
2611"#,
2612 );
2613 assert_eq!(t, "S1");
2614}
2615
2616#[test]
2617fn method_resolution_where_clause_inline() {
2618 let t = type_at(
2619 r#"
2620//- /main.rs
2621trait Into<T> { fn into(self) -> T; }
2622trait From<T> { fn from(other: T) -> Self; }
2623struct S1;
2624struct S2;
2625impl From<S2> for S1 {};
2626impl<T, U: From<T>> Into<U> for T {}
2627fn test() { S2.into()<|>; }
2628"#,
2629 );
2630 assert_eq!(t, "S1");
2631}
2632
2633#[test]
2634fn method_resolution_encountering_fn_type() {
2635 covers!(trait_resolution_on_fn_type);
2636 type_at(
2637 r#"
2638//- /main.rs
2639fn foo() {}
2640trait FnOnce { fn call(self); }
2641fn test() { foo.call()<|>; }
2642"#,
2643 );
2644}
2645
2646#[test]
2647fn method_resolution_slow() {
2648 // this can get quite slow if we set the solver size limit too high
2649 let t = type_at(
2650 r#"
2651//- /main.rs
2652trait SendX {}
2653
2654struct S1; impl SendX for S1;
2655struct S2; impl SendX for S2;
2656struct U1;
2657
2658trait Trait { fn method(self); }
2659
2660struct X1<A, B> {}
2661impl<A, B> SendX for X1<A, B> where A: SendX, B: SendX {}
2662
2663struct S<B, C> {}
2664
2665trait FnX {}
2666
2667impl<B, C> Trait for S<B, C> where C: FnX, B: SendX {}
2668
2669fn test() { (S {}).method()<|>; }
2670"#,
2671 );
2672 assert_eq!(t, "{unknown}");
2519} 2673}
2520 2674
2521fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { 2675fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String {
diff --git a/crates/ra_hir/src/ty/traits.rs b/crates/ra_hir/src/ty/traits.rs
index a1ed0c028..4260f7ef7 100644
--- a/crates/ra_hir/src/ty/traits.rs
+++ b/crates/ra_hir/src/ty/traits.rs
@@ -1,6 +1,7 @@
1//! Trait solving using Chalk. 1//! Trait solving using Chalk.
2use std::sync::{Arc, Mutex}; 2use std::sync::{Arc, Mutex};
3 3
4use rustc_hash::FxHashSet;
4use log::debug; 5use log::debug;
5use chalk_ir::cast::Cast; 6use chalk_ir::cast::Cast;
6 7
@@ -13,6 +14,11 @@ mod chalk;
13 14
14pub(crate) type Solver = chalk_solve::Solver; 15pub(crate) type Solver = chalk_solve::Solver;
15 16
17/// This controls the maximum size of types Chalk considers. If we set this too
18/// high, we can run into slow edge cases; if we set it too low, Chalk won't
19/// find some solutions.
20const CHALK_SOLVER_MAX_SIZE: usize = 2;
21
16#[derive(Debug, Copy, Clone)] 22#[derive(Debug, Copy, Clone)]
17struct ChalkContext<'a, DB> { 23struct ChalkContext<'a, DB> {
18 db: &'a DB, 24 db: &'a DB,
@@ -21,7 +27,8 @@ struct ChalkContext<'a, DB> {
21 27
22pub(crate) fn solver(_db: &impl HirDatabase, _krate: Crate) -> Arc<Mutex<Solver>> { 28pub(crate) fn solver(_db: &impl HirDatabase, _krate: Crate) -> Arc<Mutex<Solver>> {
23 // krate parameter is just so we cache a unique solver per crate 29 // krate parameter is just so we cache a unique solver per crate
24 let solver_choice = chalk_solve::SolverChoice::SLG { max_size: 10 }; 30 let solver_choice = chalk_solve::SolverChoice::SLG { max_size: CHALK_SOLVER_MAX_SIZE };
31 debug!("Creating new solver for crate {:?}", _krate);
25 Arc::new(Mutex::new(solver_choice.into_solver())) 32 Arc::new(Mutex::new(solver_choice.into_solver()))
26} 33}
27 34
@@ -31,7 +38,7 @@ pub(crate) fn impls_for_trait(
31 krate: Crate, 38 krate: Crate,
32 trait_: Trait, 39 trait_: Trait,
33) -> Arc<[ImplBlock]> { 40) -> Arc<[ImplBlock]> {
34 let mut impls = Vec::new(); 41 let mut impls = FxHashSet::default();
35 // We call the query recursively here. On the one hand, this means we can 42 // We call the query recursively here. On the one hand, this means we can
36 // reuse results from queries for different crates; on the other hand, this 43 // reuse results from queries for different crates; on the other hand, this
37 // will only ever get called for a few crates near the root of the tree (the 44 // will only ever get called for a few crates near the root of the tree (the
@@ -42,7 +49,7 @@ pub(crate) fn impls_for_trait(
42 } 49 }
43 let crate_impl_blocks = db.impls_in_crate(krate); 50 let crate_impl_blocks = db.impls_in_crate(krate);
44 impls.extend(crate_impl_blocks.lookup_impl_blocks_for_trait(&trait_)); 51 impls.extend(crate_impl_blocks.lookup_impl_blocks_for_trait(&trait_));
45 impls.into() 52 impls.into_iter().collect::<Vec<_>>().into()
46} 53}
47 54
48fn solve( 55fn solve(
@@ -52,6 +59,7 @@ fn solve(
52) -> Option<chalk_solve::Solution> { 59) -> Option<chalk_solve::Solution> {
53 let context = ChalkContext { db, krate }; 60 let context = ChalkContext { db, krate };
54 let solver = db.solver(krate); 61 let solver = db.solver(krate);
62 debug!("solve goal: {:?}", goal);
55 let solution = solver.lock().unwrap().solve(&context, goal); 63 let solution = solver.lock().unwrap().solve(&context, goal);
56 debug!("solve({:?}) => {:?}", goal, solution); 64 debug!("solve({:?}) => {:?}", goal, solution);
57 solution 65 solution
@@ -125,11 +133,11 @@ fn solution_from_chalk(db: &impl HirDatabase, solution: chalk_solve::Solution) -
125} 133}
126 134
127#[derive(Clone, Debug, PartialEq, Eq)] 135#[derive(Clone, Debug, PartialEq, Eq)]
128pub(crate) struct SolutionVariables(pub Canonical<Vec<Ty>>); 136pub struct SolutionVariables(pub Canonical<Vec<Ty>>);
129 137
130#[derive(Clone, Debug, PartialEq, Eq)] 138#[derive(Clone, Debug, PartialEq, Eq)]
131/// A (possible) solution for a proposed goal. 139/// A (possible) solution for a proposed goal.
132pub(crate) enum Solution { 140pub enum Solution {
133 /// The goal indeed holds, and there is a unique value for all existential 141 /// The goal indeed holds, and there is a unique value for all existential
134 /// variables. 142 /// variables.
135 Unique(SolutionVariables), 143 Unique(SolutionVariables),
@@ -144,7 +152,7 @@ pub(crate) enum Solution {
144#[derive(Clone, Debug, PartialEq, Eq)] 152#[derive(Clone, Debug, PartialEq, Eq)]
145/// When a goal holds ambiguously (e.g., because there are multiple possible 153/// When a goal holds ambiguously (e.g., because there are multiple possible
146/// solutions), we issue a set of *guidance* back to type inference. 154/// solutions), we issue a set of *guidance* back to type inference.
147pub(crate) enum Guidance { 155pub enum Guidance {
148 /// The existential variables *must* have the given values if the goal is 156 /// The existential variables *must* have the given values if the goal is
149 /// ever to hold, but that alone isn't enough to guarantee the goal will 157 /// ever to hold, but that alone isn't enough to guarantee the goal will
150 /// actually hold. 158 /// actually hold.
diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs
index 8b77d21b4..78440b258 100644
--- a/crates/ra_hir/src/ty/traits/chalk.rs
+++ b/crates/ra_hir/src/ty/traits/chalk.rs
@@ -6,15 +6,22 @@ use log::debug;
6use chalk_ir::{TypeId, ImplId, TypeKindId, ProjectionTy, Parameter, Identifier, cast::Cast, PlaceholderIndex, UniverseIndex, TypeName}; 6use chalk_ir::{TypeId, ImplId, TypeKindId, ProjectionTy, Parameter, Identifier, cast::Cast, PlaceholderIndex, UniverseIndex, TypeName};
7use chalk_rust_ir::{AssociatedTyDatum, TraitDatum, StructDatum, ImplDatum}; 7use chalk_rust_ir::{AssociatedTyDatum, TraitDatum, StructDatum, ImplDatum};
8 8
9use test_utils::tested_by;
9use ra_db::salsa::{InternId, InternKey}; 10use ra_db::salsa::{InternId, InternKey};
10 11
11use crate::{ 12use crate::{
12 Trait, HasGenericParams, ImplBlock, 13 Trait, HasGenericParams, ImplBlock,
13 db::HirDatabase, 14 db::HirDatabase,
14 ty::{TraitRef, Ty, ApplicationTy, TypeCtor, Substs}, 15 ty::{TraitRef, Ty, ApplicationTy, TypeCtor, Substs, GenericPredicate, CallableDef},
16 ty::display::HirDisplay,
17 generics::GenericDef,
15}; 18};
16use super::ChalkContext; 19use super::ChalkContext;
17 20
21/// This represents a trait whose name we could not resolve.
22const UNKNOWN_TRAIT: chalk_ir::TraitId =
23 chalk_ir::TraitId(chalk_ir::RawId { index: u32::max_value() });
24
18pub(super) trait ToChalk { 25pub(super) trait ToChalk {
19 type Chalk; 26 type Chalk;
20 fn to_chalk(self, db: &impl HirDatabase) -> Self::Chalk; 27 fn to_chalk(self, db: &impl HirDatabase) -> Self::Chalk;
@@ -45,7 +52,10 @@ impl ToChalk for Ty {
45 Ty::Infer(_infer_ty) => panic!("uncanonicalized infer ty"), 52 Ty::Infer(_infer_ty) => panic!("uncanonicalized infer ty"),
46 // FIXME this is clearly incorrect, but probably not too incorrect 53 // FIXME this is clearly incorrect, but probably not too incorrect
47 // and I'm not sure what to actually do with Ty::Unknown 54 // and I'm not sure what to actually do with Ty::Unknown
48 Ty::Unknown => PlaceholderIndex { ui: UniverseIndex::ROOT, idx: 0 }.to_ty(), 55 // maybe an alternative would be `for<T> T`? (meaningless in rust, but expressible in chalk's Ty)
56 Ty::Unknown => {
57 PlaceholderIndex { ui: UniverseIndex::ROOT, idx: usize::max_value() }.to_ty()
58 }
49 } 59 }
50 } 60 }
51 fn from_chalk(db: &impl HirDatabase, chalk: chalk_ir::Ty) -> Self { 61 fn from_chalk(db: &impl HirDatabase, chalk: chalk_ir::Ty) -> Self {
@@ -146,6 +156,33 @@ impl ToChalk for ImplBlock {
146 } 156 }
147} 157}
148 158
159impl ToChalk for GenericPredicate {
160 type Chalk = chalk_ir::QuantifiedWhereClause;
161
162 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::QuantifiedWhereClause {
163 match self {
164 GenericPredicate::Implemented(trait_ref) => {
165 make_binders(chalk_ir::WhereClause::Implemented(trait_ref.to_chalk(db)), 0)
166 }
167 GenericPredicate::Error => {
168 let impossible_trait_ref = chalk_ir::TraitRef {
169 trait_id: UNKNOWN_TRAIT,
170 parameters: vec![Ty::Unknown.to_chalk(db).cast()],
171 };
172 make_binders(chalk_ir::WhereClause::Implemented(impossible_trait_ref), 0)
173 }
174 }
175 }
176
177 fn from_chalk(
178 _db: &impl HirDatabase,
179 _where_clause: chalk_ir::QuantifiedWhereClause,
180 ) -> GenericPredicate {
181 // This should never need to be called
182 unimplemented!()
183 }
184}
185
149fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T> { 186fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T> {
150 chalk_ir::Binders { 187 chalk_ir::Binders {
151 value, 188 value,
@@ -153,6 +190,40 @@ fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T> {
153 } 190 }
154} 191}
155 192
193fn blacklisted_trait(db: &impl HirDatabase, trait_: Trait) -> bool {
194 let name = trait_.name(db).unwrap_or_else(crate::Name::missing).to_string();
195 match &*name {
196 "Send" | "Sync" | "Sized" | "Fn" | "FnMut" | "FnOnce" => true,
197 _ => false,
198 }
199}
200
201fn convert_where_clauses(
202 db: &impl HirDatabase,
203 def: GenericDef,
204 substs: &Substs,
205) -> Vec<chalk_ir::QuantifiedWhereClause> {
206 let generic_predicates = db.generic_predicates(def);
207 let mut result = Vec::with_capacity(generic_predicates.len());
208 for pred in generic_predicates.iter() {
209 if pred.is_error() {
210 // HACK: Return just the single predicate (which is always false
211 // anyway), otherwise Chalk can easily get into slow situations
212 return vec![pred.clone().subst(substs).to_chalk(db)];
213 }
214 match pred {
215 GenericPredicate::Implemented(trait_ref) => {
216 if blacklisted_trait(db, trait_ref.trait_) {
217 continue;
218 }
219 }
220 _ => {}
221 }
222 result.push(pred.clone().subst(substs).to_chalk(db));
223 }
224 result
225}
226
156impl<'a, DB> chalk_solve::RustIrDatabase for ChalkContext<'a, DB> 227impl<'a, DB> chalk_solve::RustIrDatabase for ChalkContext<'a, DB>
157where 228where
158 DB: HirDatabase, 229 DB: HirDatabase,
@@ -162,18 +233,36 @@ where
162 } 233 }
163 fn trait_datum(&self, trait_id: chalk_ir::TraitId) -> Arc<TraitDatum> { 234 fn trait_datum(&self, trait_id: chalk_ir::TraitId) -> Arc<TraitDatum> {
164 debug!("trait_datum {:?}", trait_id); 235 debug!("trait_datum {:?}", trait_id);
236 if trait_id == UNKNOWN_TRAIT {
237 let trait_datum_bound = chalk_rust_ir::TraitDatumBound {
238 trait_ref: chalk_ir::TraitRef {
239 trait_id: UNKNOWN_TRAIT,
240 parameters: vec![chalk_ir::Ty::BoundVar(0).cast()],
241 },
242 associated_ty_ids: Vec::new(),
243 where_clauses: Vec::new(),
244 flags: chalk_rust_ir::TraitFlags {
245 auto: false,
246 marker: false,
247 upstream: true,
248 fundamental: false,
249 },
250 };
251 return Arc::new(TraitDatum { binders: make_binders(trait_datum_bound, 1) });
252 }
165 let trait_: Trait = from_chalk(self.db, trait_id); 253 let trait_: Trait = from_chalk(self.db, trait_id);
254 debug!("trait {:?} = {:?}", trait_id, trait_.name(self.db));
166 let generic_params = trait_.generic_params(self.db); 255 let generic_params = trait_.generic_params(self.db);
167 let bound_vars = Substs::bound_vars(&generic_params); 256 let bound_vars = Substs::bound_vars(&generic_params);
168 let trait_ref = trait_.trait_ref(self.db).subst(&bound_vars).to_chalk(self.db); 257 let trait_ref = trait_.trait_ref(self.db).subst(&bound_vars).to_chalk(self.db);
169 let flags = chalk_rust_ir::TraitFlags { 258 let flags = chalk_rust_ir::TraitFlags {
259 auto: trait_.is_auto(self.db),
260 upstream: trait_.module(self.db).krate(self.db) != Some(self.krate),
170 // FIXME set these flags correctly 261 // FIXME set these flags correctly
171 auto: false,
172 marker: false, 262 marker: false,
173 upstream: trait_.module(self.db).krate(self.db) != Some(self.krate),
174 fundamental: false, 263 fundamental: false,
175 }; 264 };
176 let where_clauses = Vec::new(); // FIXME add where clauses 265 let where_clauses = convert_where_clauses(self.db, trait_.into(), &bound_vars);
177 let associated_ty_ids = Vec::new(); // FIXME add associated tys 266 let associated_ty_ids = Vec::new(); // FIXME add associated tys
178 let trait_datum_bound = 267 let trait_datum_bound =
179 chalk_rust_ir::TraitDatumBound { trait_ref, where_clauses, flags, associated_ty_ids }; 268 chalk_rust_ir::TraitDatumBound { trait_ref, where_clauses, flags, associated_ty_ids };
@@ -183,23 +272,51 @@ where
183 fn struct_datum(&self, struct_id: chalk_ir::StructId) -> Arc<StructDatum> { 272 fn struct_datum(&self, struct_id: chalk_ir::StructId) -> Arc<StructDatum> {
184 debug!("struct_datum {:?}", struct_id); 273 debug!("struct_datum {:?}", struct_id);
185 let type_ctor = from_chalk(self.db, struct_id); 274 let type_ctor = from_chalk(self.db, struct_id);
275 debug!("struct {:?} = {:?}", struct_id, type_ctor);
186 // FIXME might be nicer if we can create a fake GenericParams for the TypeCtor 276 // FIXME might be nicer if we can create a fake GenericParams for the TypeCtor
187 // FIXME extract this to a method on Ty 277 // FIXME extract this to a method on Ty
188 let (num_params, upstream) = match type_ctor { 278 let (num_params, where_clauses, upstream) = match type_ctor {
189 TypeCtor::Bool 279 TypeCtor::Bool
190 | TypeCtor::Char 280 | TypeCtor::Char
191 | TypeCtor::Int(_) 281 | TypeCtor::Int(_)
192 | TypeCtor::Float(_) 282 | TypeCtor::Float(_)
193 | TypeCtor::Never 283 | TypeCtor::Never
194 | TypeCtor::Str => (0, true), 284 | TypeCtor::Str => (0, vec![], true),
195 TypeCtor::Slice | TypeCtor::Array | TypeCtor::RawPtr(_) | TypeCtor::Ref(_) => (1, true), 285 TypeCtor::Slice | TypeCtor::Array | TypeCtor::RawPtr(_) | TypeCtor::Ref(_) => {
196 TypeCtor::FnPtr { num_args } => (num_args as usize + 1, true), 286 (1, vec![], true)
197 TypeCtor::Tuple { cardinality } => (cardinality as usize, true), 287 }
198 TypeCtor::FnDef(_) => unimplemented!(), 288 TypeCtor::FnPtr { num_args } => (num_args as usize + 1, vec![], true),
289 TypeCtor::Tuple { cardinality } => (cardinality as usize, vec![], true),
290 TypeCtor::FnDef(callable) => {
291 tested_by!(trait_resolution_on_fn_type);
292 let krate = match callable {
293 CallableDef::Function(f) => f.module(self.db).krate(self.db),
294 CallableDef::Struct(s) => s.module(self.db).krate(self.db),
295 CallableDef::EnumVariant(v) => {
296 v.parent_enum(self.db).module(self.db).krate(self.db)
297 }
298 };
299 let generic_def: GenericDef = match callable {
300 CallableDef::Function(f) => f.into(),
301 CallableDef::Struct(s) => s.into(),
302 CallableDef::EnumVariant(v) => v.parent_enum(self.db).into(),
303 };
304 let generic_params = generic_def.generic_params(self.db);
305 let bound_vars = Substs::bound_vars(&generic_params);
306 let where_clauses = convert_where_clauses(self.db, generic_def, &bound_vars);
307 (
308 generic_params.count_params_including_parent(),
309 where_clauses,
310 krate != Some(self.krate),
311 )
312 }
199 TypeCtor::Adt(adt) => { 313 TypeCtor::Adt(adt) => {
200 let generic_params = adt.generic_params(self.db); 314 let generic_params = adt.generic_params(self.db);
315 let bound_vars = Substs::bound_vars(&generic_params);
316 let where_clauses = convert_where_clauses(self.db, adt.into(), &bound_vars);
201 ( 317 (
202 generic_params.count_params_including_parent(), 318 generic_params.count_params_including_parent(),
319 where_clauses,
203 adt.krate(self.db) != Some(self.krate), 320 adt.krate(self.db) != Some(self.krate),
204 ) 321 )
205 } 322 }
@@ -209,7 +326,6 @@ where
209 // FIXME set fundamental flag correctly 326 // FIXME set fundamental flag correctly
210 fundamental: false, 327 fundamental: false,
211 }; 328 };
212 let where_clauses = Vec::new(); // FIXME add where clauses
213 let self_ty = chalk_ir::ApplicationTy { 329 let self_ty = chalk_ir::ApplicationTy {
214 name: TypeName::TypeKindId(type_ctor.to_chalk(self.db).into()), 330 name: TypeName::TypeKindId(type_ctor.to_chalk(self.db).into()),
215 parameters: (0..num_params).map(|i| chalk_ir::Ty::BoundVar(i).cast()).collect(), 331 parameters: (0..num_params).map(|i| chalk_ir::Ty::BoundVar(i).cast()).collect(),
@@ -237,10 +353,23 @@ where
237 } else { 353 } else {
238 chalk_rust_ir::ImplType::External 354 chalk_rust_ir::ImplType::External
239 }; 355 };
356 let where_clauses = convert_where_clauses(self.db, impl_block.into(), &bound_vars);
357 let negative = impl_block.is_negative(self.db);
358 debug!(
359 "impl {:?}: {}{} where {:?}",
360 impl_id,
361 if negative { "!" } else { "" },
362 trait_ref.display(self.db),
363 where_clauses
364 );
365 let trait_ref = trait_ref.to_chalk(self.db);
240 let impl_datum_bound = chalk_rust_ir::ImplDatumBound { 366 let impl_datum_bound = chalk_rust_ir::ImplDatumBound {
241 // FIXME handle negative impls (impl !Sync for Foo) 367 trait_ref: if negative {
242 trait_ref: chalk_rust_ir::PolarizedTraitRef::Positive(trait_ref.to_chalk(self.db)), 368 chalk_rust_ir::PolarizedTraitRef::Negative(trait_ref)
243 where_clauses: Vec::new(), // FIXME add where clauses 369 } else {
370 chalk_rust_ir::PolarizedTraitRef::Positive(trait_ref)
371 },
372 where_clauses,
244 associated_ty_values: Vec::new(), // FIXME add associated type values 373 associated_ty_values: Vec::new(), // FIXME add associated type values
245 impl_type, 374 impl_type,
246 }; 375 };
@@ -249,16 +378,22 @@ where
249 } 378 }
250 fn impls_for_trait(&self, trait_id: chalk_ir::TraitId) -> Vec<ImplId> { 379 fn impls_for_trait(&self, trait_id: chalk_ir::TraitId) -> Vec<ImplId> {
251 debug!("impls_for_trait {:?}", trait_id); 380 debug!("impls_for_trait {:?}", trait_id);
252 let trait_ = from_chalk(self.db, trait_id); 381 if trait_id == UNKNOWN_TRAIT {
253 self.db 382 return Vec::new();
383 }
384 let trait_: Trait = from_chalk(self.db, trait_id);
385 let blacklisted = blacklisted_trait(self.db, trait_);
386 if blacklisted {
387 return Vec::new();
388 }
389 let result: Vec<_> = self
390 .db
254 .impls_for_trait(self.krate, trait_) 391 .impls_for_trait(self.krate, trait_)
255 .iter() 392 .iter()
256 // FIXME temporary hack -- as long as we're not lowering where clauses
257 // correctly, ignore impls with them completely so as to not treat
258 // impl<T> Trait for T where T: ... as a blanket impl on all types
259 .filter(|impl_block| impl_block.generic_params(self.db).where_predicates.is_empty())
260 .map(|impl_block| impl_block.to_chalk(self.db)) 393 .map(|impl_block| impl_block.to_chalk(self.db))
261 .collect() 394 .collect();
395 debug!("impls_for_trait returned {} impls", result.len());
396 result
262 } 397 }
263 fn impl_provided_for( 398 fn impl_provided_for(
264 &self, 399 &self,