aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_cli/src/analysis_stats.rs9
-rw-r--r--crates/ra_cli/src/main.rs7
-rw-r--r--crates/ra_hir/src/db.rs7
-rw-r--r--crates/ra_hir/src/ty.rs19
-rw-r--r--crates/ra_hir/src/ty/infer.rs3
-rw-r--r--crates/ra_hir/src/ty/method_resolution.rs3
-rw-r--r--crates/ra_hir/src/ty/traits.rs11
7 files changed, 45 insertions, 14 deletions
diff --git a/crates/ra_cli/src/analysis_stats.rs b/crates/ra_cli/src/analysis_stats.rs
index 4516ed660..86ee0cb63 100644
--- a/crates/ra_cli/src/analysis_stats.rs
+++ b/crates/ra_cli/src/analysis_stats.rs
@@ -7,7 +7,7 @@ use ra_syntax::AstNode;
7 7
8use crate::Result; 8use crate::Result;
9 9
10pub fn run(verbose: bool) -> Result<()> { 10pub fn run(verbose: bool, only: Option<&str>) -> Result<()> {
11 let db_load_time = Instant::now(); 11 let db_load_time = Instant::now();
12 let (db, roots) = BatchDatabase::load_cargo(".")?; 12 let (db, roots) = BatchDatabase::load_cargo(".")?;
13 println!("Database loaded, {} roots, {:?}", roots.len(), db_load_time.elapsed()); 13 println!("Database loaded, {} roots, {:?}", roots.len(), db_load_time.elapsed());
@@ -57,14 +57,19 @@ pub fn run(verbose: bool) -> Result<()> {
57 let mut num_exprs_unknown = 0; 57 let mut num_exprs_unknown = 0;
58 let mut num_exprs_partially_unknown = 0; 58 let mut num_exprs_partially_unknown = 0;
59 for f in funcs { 59 for f in funcs {
60 let name = f.name(&db);
60 if verbose { 61 if verbose {
61 let (file_id, source) = f.source(&db); 62 let (file_id, source) = f.source(&db);
62 let original_file = file_id.original_file(&db); 63 let original_file = file_id.original_file(&db);
63 let path = db.file_relative_path(original_file); 64 let path = db.file_relative_path(original_file);
64 let syntax_range = source.syntax().range(); 65 let syntax_range = source.syntax().range();
65 let name = f.name(&db);
66 println!("{} ({:?} {})", name, path, syntax_range); 66 println!("{} ({:?} {})", name, path, syntax_range);
67 } 67 }
68 if let Some(only_name) = only {
69 if name.to_string() != only_name {
70 continue;
71 }
72 }
68 let body = f.body(&db); 73 let body = f.body(&db);
69 let inference_result = f.infer(&db); 74 let inference_result = f.infer(&db);
70 for (expr_id, _) in body.exprs() { 75 for (expr_id, _) in body.exprs() {
diff --git a/crates/ra_cli/src/main.rs b/crates/ra_cli/src/main.rs
index 45555be6e..11790d2e7 100644
--- a/crates/ra_cli/src/main.rs
+++ b/crates/ra_cli/src/main.rs
@@ -23,7 +23,9 @@ fn main() -> Result<()> {
23 .subcommand(SubCommand::with_name("parse").arg(Arg::with_name("no-dump").long("--no-dump"))) 23 .subcommand(SubCommand::with_name("parse").arg(Arg::with_name("no-dump").long("--no-dump")))
24 .subcommand(SubCommand::with_name("symbols")) 24 .subcommand(SubCommand::with_name("symbols"))
25 .subcommand( 25 .subcommand(
26 SubCommand::with_name("analysis-stats").arg(Arg::with_name("verbose").short("v")), 26 SubCommand::with_name("analysis-stats")
27 .arg(Arg::with_name("verbose").short("v"))
28 .arg(Arg::with_name("only").short("o").takes_value(true)),
27 ) 29 )
28 .get_matches(); 30 .get_matches();
29 match matches.subcommand() { 31 match matches.subcommand() {
@@ -51,7 +53,8 @@ fn main() -> Result<()> {
51 } 53 }
52 ("analysis-stats", Some(matches)) => { 54 ("analysis-stats", Some(matches)) => {
53 let verbose = matches.is_present("verbose"); 55 let verbose = matches.is_present("verbose");
54 analysis_stats::run(verbose)?; 56 let only = matches.value_of("only");
57 analysis_stats::run(verbose, only)?;
55 } 58 }
56 _ => unreachable!(), 59 _ => unreachable!(),
57 } 60 }
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs
index 8aaf0375a..689dd6225 100644
--- a/crates/ra_hir/src/db.rs
+++ b/crates/ra_hir/src/db.rs
@@ -161,6 +161,13 @@ pub trait HirDatabase: DefDatabase {
161 #[salsa::invoke(crate::ty::traits::solver)] 161 #[salsa::invoke(crate::ty::traits::solver)]
162 #[salsa::volatile] 162 #[salsa::volatile]
163 fn solver(&self, krate: Crate) -> Arc<Mutex<crate::ty::traits::Solver>>; 163 fn solver(&self, krate: Crate) -> Arc<Mutex<crate::ty::traits::Solver>>;
164
165 #[salsa::invoke(crate::ty::traits::implements)]
166 fn implements(
167 &self,
168 krate: Crate,
169 goal: crate::ty::Canonical<crate::ty::TraitRef>,
170 ) -> Option<crate::ty::traits::Solution>;
164} 171}
165 172
166#[test] 173#[test]
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index f4eee835f..12429a668 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -240,7 +240,7 @@ impl TraitRef {
240/// many there are. This is used to erase irrelevant differences between types 240/// many there are. This is used to erase irrelevant differences between types
241/// before using them in queries. 241/// before using them in queries.
242#[derive(Debug, Clone, PartialEq, Eq, Hash)] 242#[derive(Debug, Clone, PartialEq, Eq, Hash)]
243pub(crate) struct Canonical<T> { 243pub struct Canonical<T> {
244 pub value: T, 244 pub value: T,
245 pub num_vars: usize, 245 pub num_vars: usize,
246} 246}
@@ -534,3 +534,20 @@ impl HirDisplay for Ty {
534 Ok(()) 534 Ok(())
535 } 535 }
536} 536}
537
538impl HirDisplay for TraitRef {
539 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
540 write!(
541 f,
542 "{}: {}",
543 self.substs[0].display(f.db),
544 self.trait_.name(f.db).unwrap_or_else(Name::missing)
545 )?;
546 if self.substs.len() > 1 {
547 write!(f, "<")?;
548 f.write_joined(&self.substs[1..], ", ")?;
549 write!(f, ">")?;
550 }
551 Ok(())
552 }
553}
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/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs
index 607e9ba79..d8b8c836c 100644
--- a/crates/ra_hir/src/ty/method_resolution.rs
+++ b/crates/ra_hir/src/ty/method_resolution.rs
@@ -196,8 +196,7 @@ fn iterate_trait_method_candidates<T>(
196 if name.map_or(true, |name| sig.name() == name) && sig.has_self_param() { 196 if name.map_or(true, |name| sig.name() == name) && sig.has_self_param() {
197 if !known_implemented { 197 if !known_implemented {
198 let trait_ref = canonical_trait_ref(db, t, ty.clone()); 198 let trait_ref = canonical_trait_ref(db, t, ty.clone());
199 // FIXME cache this implements check (without solution) in a query? 199 if db.implements(krate, trait_ref).is_none() {
200 if super::traits::implements(db, krate, trait_ref).is_none() {
201 continue 'traits; 200 continue 'traits;
202 } 201 }
203 } 202 }
diff --git a/crates/ra_hir/src/ty/traits.rs b/crates/ra_hir/src/ty/traits.rs
index a1ed0c028..4bbc99f0e 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
@@ -31,7 +32,7 @@ pub(crate) fn impls_for_trait(
31 krate: Crate, 32 krate: Crate,
32 trait_: Trait, 33 trait_: Trait,
33) -> Arc<[ImplBlock]> { 34) -> Arc<[ImplBlock]> {
34 let mut impls = Vec::new(); 35 let mut impls = FxHashSet::default();
35 // We call the query recursively here. On the one hand, this means we can 36 // 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 37 // 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 38 // will only ever get called for a few crates near the root of the tree (the
@@ -42,7 +43,7 @@ pub(crate) fn impls_for_trait(
42 } 43 }
43 let crate_impl_blocks = db.impls_in_crate(krate); 44 let crate_impl_blocks = db.impls_in_crate(krate);
44 impls.extend(crate_impl_blocks.lookup_impl_blocks_for_trait(&trait_)); 45 impls.extend(crate_impl_blocks.lookup_impl_blocks_for_trait(&trait_));
45 impls.into() 46 impls.into_iter().collect::<Vec<_>>().into()
46} 47}
47 48
48fn solve( 49fn solve(
@@ -125,11 +126,11 @@ fn solution_from_chalk(db: &impl HirDatabase, solution: chalk_solve::Solution) -
125} 126}
126 127
127#[derive(Clone, Debug, PartialEq, Eq)] 128#[derive(Clone, Debug, PartialEq, Eq)]
128pub(crate) struct SolutionVariables(pub Canonical<Vec<Ty>>); 129pub struct SolutionVariables(pub Canonical<Vec<Ty>>);
129 130
130#[derive(Clone, Debug, PartialEq, Eq)] 131#[derive(Clone, Debug, PartialEq, Eq)]
131/// A (possible) solution for a proposed goal. 132/// A (possible) solution for a proposed goal.
132pub(crate) enum Solution { 133pub enum Solution {
133 /// The goal indeed holds, and there is a unique value for all existential 134 /// The goal indeed holds, and there is a unique value for all existential
134 /// variables. 135 /// variables.
135 Unique(SolutionVariables), 136 Unique(SolutionVariables),
@@ -144,7 +145,7 @@ pub(crate) enum Solution {
144#[derive(Clone, Debug, PartialEq, Eq)] 145#[derive(Clone, Debug, PartialEq, Eq)]
145/// When a goal holds ambiguously (e.g., because there are multiple possible 146/// When a goal holds ambiguously (e.g., because there are multiple possible
146/// solutions), we issue a set of *guidance* back to type inference. 147/// solutions), we issue a set of *guidance* back to type inference.
147pub(crate) enum Guidance { 148pub enum Guidance {
148 /// The existential variables *must* have the given values if the goal is 149 /// 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 150 /// ever to hold, but that alone isn't enough to guarantee the goal will
150 /// actually hold. 151 /// actually hold.