From a78228a39c4786e67e5a94384388a04aa8d7b172 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sun, 5 May 2019 16:04:31 +0200 Subject: Turn `implements` into a query again --- crates/ra_hir/src/db.rs | 7 +++++++ crates/ra_hir/src/ty.rs | 2 +- crates/ra_hir/src/ty/infer.rs | 3 +-- crates/ra_hir/src/ty/method_resolution.rs | 3 +-- crates/ra_hir/src/ty/traits.rs | 6 +++--- 5 files changed, 13 insertions(+), 8 deletions(-) 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 { #[salsa::invoke(crate::ty::traits::solver)] #[salsa::volatile] fn solver(&self, krate: Crate) -> Arc>; + + #[salsa::invoke(crate::ty::traits::implements)] + fn implements( + &self, + krate: Crate, + goal: crate::ty::Canonical, + ) -> Option; } #[test] diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index f4eee835f..24c45d728 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs @@ -240,7 +240,7 @@ impl TraitRef { /// many there are. This is used to erase irrelevant differences between types /// before using them in queries. #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub(crate) struct Canonical { +pub struct Canonical { pub value: T, pub num_vars: usize, } 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> { Obligation::Trait(tr) => { let canonicalized = self.canonicalizer().canonicalize_trait_ref(tr.clone()); ( - super::traits::implements( - self.db, + self.db.implements( self.resolver.krate().unwrap(), canonicalized.value.clone(), ), 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( if name.map_or(true, |name| sig.name() == name) && sig.has_self_param() { if !known_implemented { let trait_ref = canonical_trait_ref(db, t, ty.clone()); - // FIXME cache this implements check (without solution) in a query? - if super::traits::implements(db, krate, trait_ref).is_none() { + if db.implements(krate, trait_ref).is_none() { continue 'traits; } } diff --git a/crates/ra_hir/src/ty/traits.rs b/crates/ra_hir/src/ty/traits.rs index a1ed0c028..f70a32575 100644 --- a/crates/ra_hir/src/ty/traits.rs +++ b/crates/ra_hir/src/ty/traits.rs @@ -125,11 +125,11 @@ fn solution_from_chalk(db: &impl HirDatabase, solution: chalk_solve::Solution) - } #[derive(Clone, Debug, PartialEq, Eq)] -pub(crate) struct SolutionVariables(pub Canonical>); +pub struct SolutionVariables(pub Canonical>); #[derive(Clone, Debug, PartialEq, Eq)] /// A (possible) solution for a proposed goal. -pub(crate) enum Solution { +pub enum Solution { /// The goal indeed holds, and there is a unique value for all existential /// variables. Unique(SolutionVariables), @@ -144,7 +144,7 @@ pub(crate) enum Solution { #[derive(Clone, Debug, PartialEq, Eq)] /// When a goal holds ambiguously (e.g., because there are multiple possible /// solutions), we issue a set of *guidance* back to type inference. -pub(crate) enum Guidance { +pub enum Guidance { /// The existential variables *must* have the given values if the goal is /// ever to hold, but that alone isn't enough to guarantee the goal will /// actually hold. -- cgit v1.2.3 From 4083caa233b03a390aca87e96e5bd290961df04c Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Tue, 7 May 2019 12:08:42 +0200 Subject: Add a HirDisplay implementation for TraitRef --- crates/ra_hir/src/ty.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index 24c45d728..12429a668 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs @@ -534,3 +534,20 @@ impl HirDisplay for Ty { Ok(()) } } + +impl HirDisplay for TraitRef { + fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result { + write!( + f, + "{}: {}", + self.substs[0].display(f.db), + self.trait_.name(f.db).unwrap_or_else(Name::missing) + )?; + if self.substs.len() > 1 { + write!(f, "<")?; + f.write_joined(&self.substs[1..], ", ")?; + write!(f, ">")?; + } + Ok(()) + } +} -- cgit v1.2.3 From 880ef25a9e9fe3071181d27c6d8ea672bf76d680 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Tue, 7 May 2019 12:09:10 +0200 Subject: Allow targeting a specific function with analysis-stats This can be useful for debugging. --- crates/ra_cli/src/analysis_stats.rs | 9 +++++++-- crates/ra_cli/src/main.rs | 7 +++++-- 2 files changed, 12 insertions(+), 4 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; use crate::Result; -pub fn run(verbose: bool) -> Result<()> { +pub fn run(verbose: bool, only: Option<&str>) -> Result<()> { let db_load_time = Instant::now(); let (db, roots) = BatchDatabase::load_cargo(".")?; println!("Database loaded, {} roots, {:?}", roots.len(), db_load_time.elapsed()); @@ -57,14 +57,19 @@ pub fn run(verbose: bool) -> Result<()> { let mut num_exprs_unknown = 0; let mut num_exprs_partially_unknown = 0; for f in funcs { + let name = f.name(&db); if verbose { let (file_id, source) = f.source(&db); let original_file = file_id.original_file(&db); let path = db.file_relative_path(original_file); let syntax_range = source.syntax().range(); - let name = f.name(&db); println!("{} ({:?} {})", name, path, syntax_range); } + if let Some(only_name) = only { + if name.to_string() != only_name { + continue; + } + } let body = f.body(&db); let inference_result = f.infer(&db); 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<()> { .subcommand(SubCommand::with_name("parse").arg(Arg::with_name("no-dump").long("--no-dump"))) .subcommand(SubCommand::with_name("symbols")) .subcommand( - SubCommand::with_name("analysis-stats").arg(Arg::with_name("verbose").short("v")), + SubCommand::with_name("analysis-stats") + .arg(Arg::with_name("verbose").short("v")) + .arg(Arg::with_name("only").short("o").takes_value(true)), ) .get_matches(); match matches.subcommand() { @@ -51,7 +53,8 @@ fn main() -> Result<()> { } ("analysis-stats", Some(matches)) => { let verbose = matches.is_present("verbose"); - analysis_stats::run(verbose)?; + let only = matches.value_of("only"); + analysis_stats::run(verbose, only)?; } _ => unreachable!(), } -- cgit v1.2.3 From 530b3047ed19a6468fc75e5a5ec14763093a069d Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Tue, 7 May 2019 12:09:57 +0200 Subject: Deduplicate impls in impls_for_trait This was duplicating impls in dependencies a lot... --- crates/ra_hir/src/ty/traits.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/ra_hir/src/ty/traits.rs b/crates/ra_hir/src/ty/traits.rs index f70a32575..4bbc99f0e 100644 --- a/crates/ra_hir/src/ty/traits.rs +++ b/crates/ra_hir/src/ty/traits.rs @@ -1,6 +1,7 @@ //! Trait solving using Chalk. use std::sync::{Arc, Mutex}; +use rustc_hash::FxHashSet; use log::debug; use chalk_ir::cast::Cast; @@ -31,7 +32,7 @@ pub(crate) fn impls_for_trait( krate: Crate, trait_: Trait, ) -> Arc<[ImplBlock]> { - let mut impls = Vec::new(); + let mut impls = FxHashSet::default(); // We call the query recursively here. On the one hand, this means we can // reuse results from queries for different crates; on the other hand, this // 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( } let crate_impl_blocks = db.impls_in_crate(krate); impls.extend(crate_impl_blocks.lookup_impl_blocks_for_trait(&trait_)); - impls.into() + impls.into_iter().collect::>().into() } fn solve( -- cgit v1.2.3