From 70dd70b1fcbbbe2e60849412412ef05e7d31eb0a Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 13 Nov 2019 09:56:33 +0300 Subject: Reduce duplication between uncertain floats & ints --- crates/ra_hir/src/lib.rs | 4 +--- crates/ra_hir/src/ty.rs | 6 +++--- crates/ra_hir/src/ty/infer.rs | 28 +++++++++++---------------- crates/ra_hir/src/ty/infer/expr.rs | 30 ++++++++++++++--------------- crates/ra_hir/src/ty/lower.rs | 14 +++++++------- crates/ra_hir/src/ty/method_resolution.rs | 11 +++++------ crates/ra_hir/src/ty/primitive.rs | 32 +++++++++++++------------------ 7 files changed, 55 insertions(+), 70 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 92d71b9e8..5ba847d35 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs @@ -77,9 +77,7 @@ pub use crate::{ source_binder::{PathResolution, ScopeEntryWithSyntax, SourceAnalyzer}, ty::{ display::HirDisplay, - primitive::{ - FloatBitness, FloatTy, IntBitness, IntTy, Signedness, UncertainFloatTy, UncertainIntTy, - }, + primitive::{FloatBitness, FloatTy, IntBitness, IntTy, Signedness, Uncertain}, ApplicationTy, CallableDef, Substs, TraitRef, Ty, TypeCtor, TypeWalk, }, }; diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index 6f24cfad6..ff6030ac4 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs @@ -21,7 +21,7 @@ use crate::{ expr::ExprId, generics::{GenericParams, HasGenericParams}, util::make_mut_slice, - Adt, Crate, DefWithBody, Mutability, Name, Trait, TypeAlias, + Adt, Crate, DefWithBody, FloatTy, IntTy, Mutability, Name, Trait, TypeAlias, Uncertain, }; use display::{HirDisplay, HirFormatter}; @@ -47,10 +47,10 @@ pub enum TypeCtor { Char, /// A primitive integer type. For example, `i32`. - Int(primitive::UncertainIntTy), + Int(Uncertain), /// A primitive floating-point type. For example, `f64`. - Float(primitive::UncertainFloatTy), + Float(Uncertain), /// Structures, enumerations and unions. Adt(Adt), diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index f17c6c614..c09260864 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs @@ -31,10 +31,10 @@ use ra_prof::profile; use test_utils::tested_by; use super::{ - lower, primitive, + lower, traits::{Guidance, Obligation, ProjectionPredicate, Solution}, ApplicationTy, InEnvironment, ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypableDef, - TypeCtor, TypeWalk, + TypeCtor, TypeWalk, Uncertain, }; use crate::{ adt::VariantDef, @@ -43,7 +43,7 @@ use crate::{ expr::{BindingAnnotation, Body, ExprId, PatId}, resolve::{Resolver, TypeNs}, ty::infer::diagnostics::InferenceDiagnostic, - Adt, AssocItem, ConstData, DefWithBody, FnData, Function, Path, StructField, + Adt, AssocItem, ConstData, DefWithBody, FloatTy, FnData, Function, IntTy, Path, StructField, }; macro_rules! ty_app { @@ -358,14 +358,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty { match ty { Ty::Unknown => self.new_type_var(), - Ty::Apply(ApplicationTy { - ctor: TypeCtor::Int(primitive::UncertainIntTy::Unknown), - .. - }) => self.new_integer_var(), - Ty::Apply(ApplicationTy { - ctor: TypeCtor::Float(primitive::UncertainFloatTy::Unknown), - .. - }) => self.new_float_var(), + Ty::Apply(ApplicationTy { ctor: TypeCtor::Int(Uncertain::Unknown), .. }) => { + self.new_integer_var() + } + Ty::Apply(ApplicationTy { ctor: TypeCtor::Float(Uncertain::Unknown), .. }) => { + self.new_float_var() + } _ => ty, } } @@ -684,12 +682,8 @@ impl InferTy { fn fallback_value(self) -> Ty { match self { InferTy::TypeVar(..) => Ty::Unknown, - InferTy::IntVar(..) => { - Ty::simple(TypeCtor::Int(primitive::UncertainIntTy::Known(primitive::IntTy::i32()))) - } - InferTy::FloatVar(..) => Ty::simple(TypeCtor::Float( - primitive::UncertainFloatTy::Known(primitive::FloatTy::f64()), - )), + InferTy::IntVar(..) => Ty::simple(TypeCtor::Int(Uncertain::Known(IntTy::i32()))), + InferTy::FloatVar(..) => Ty::simple(TypeCtor::Float(Uncertain::Known(FloatTy::f64()))), InferTy::MaybeNeverTypeVar(..) => Ty::simple(TypeCtor::Never), } } diff --git a/crates/ra_hir/src/ty/infer/expr.rs b/crates/ra_hir/src/ty/infer/expr.rs index c6802487a..5e68a1678 100644 --- a/crates/ra_hir/src/ty/infer/expr.rs +++ b/crates/ra_hir/src/ty/infer/expr.rs @@ -3,7 +3,10 @@ use std::iter::{repeat, repeat_with}; use std::sync::Arc; -use hir_def::path::{GenericArg, GenericArgs}; +use hir_def::{ + builtin_type::Signedness, + path::{GenericArg, GenericArgs}, +}; use hir_expand::name; use super::{BindingMode, Expectation, InferenceContext, InferenceDiagnostic, TypeMismatch}; @@ -12,8 +15,9 @@ use crate::{ expr::{self, Array, BinaryOp, Expr, ExprId, Literal, Statement, UnaryOp}, generics::{GenericParams, HasGenericParams}, ty::{ - autoderef, method_resolution, op, primitive, CallableDef, InferTy, Mutability, Namespace, + autoderef, method_resolution, op, CallableDef, InferTy, IntTy, Mutability, Namespace, Obligation, ProjectionPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, TypeWalk, + Uncertain, }, Adt, Name, }; @@ -337,13 +341,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { UnaryOp::Neg => { match &inner_ty { Ty::Apply(a_ty) => match a_ty.ctor { - TypeCtor::Int(primitive::UncertainIntTy::Unknown) - | TypeCtor::Int(primitive::UncertainIntTy::Known( - primitive::IntTy { - signedness: primitive::Signedness::Signed, - .. - }, - )) + TypeCtor::Int(Uncertain::Unknown) + | TypeCtor::Int(Uncertain::Known(IntTy { + signedness: Signedness::Signed, + .. + })) | TypeCtor::Float(..) => inner_ty, _ => Ty::Unknown, }, @@ -428,9 +430,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { ); self.infer_expr( *repeat, - &Expectation::has_type(Ty::simple(TypeCtor::Int( - primitive::UncertainIntTy::Known(primitive::IntTy::usize()), - ))), + &Expectation::has_type(Ty::simple(TypeCtor::Int(Uncertain::Known( + IntTy::usize(), + )))), ); } } @@ -443,9 +445,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { Ty::apply_one(TypeCtor::Ref(Mutability::Shared), Ty::simple(TypeCtor::Str)) } Literal::ByteString(..) => { - let byte_type = Ty::simple(TypeCtor::Int(primitive::UncertainIntTy::Known( - primitive::IntTy::u8(), - ))); + let byte_type = Ty::simple(TypeCtor::Int(Uncertain::Known(IntTy::u8()))); let slice_type = Ty::apply_one(TypeCtor::Slice, byte_type); Ty::apply_one(TypeCtor::Ref(Mutability::Shared), slice_type) } diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs index 1832fcf50..de3c56097 100644 --- a/crates/ra_hir/src/ty/lower.rs +++ b/crates/ra_hir/src/ty/lower.rs @@ -25,7 +25,7 @@ use crate::{ generics::{GenericDef, WherePredicate}, resolve::{Resolver, TypeNs}, ty::{ - primitive::{FloatTy, IntTy, UncertainFloatTy, UncertainIntTy}, + primitive::{FloatTy, IntTy, Uncertain}, Adt, }, util::make_mut_slice, @@ -674,20 +674,20 @@ impl From for FloatTy { } } -impl From> for UncertainIntTy { +impl From> for Uncertain { fn from(t: Option) -> Self { match t { - None => UncertainIntTy::Unknown, - Some(t) => UncertainIntTy::Known(t.into()), + None => Uncertain::Unknown, + Some(t) => Uncertain::Known(t.into()), } } } -impl From> for UncertainFloatTy { +impl From> for Uncertain { fn from(t: Option) -> Self { match t { - None => UncertainFloatTy::Unknown, - Some(t) => UncertainFloatTy::Known(t.into()), + None => Uncertain::Unknown, + Some(t) => Uncertain::Known(t.into()), } } } diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs index 8c3d32d09..eb5ca6769 100644 --- a/crates/ra_hir/src/ty/method_resolution.rs +++ b/crates/ra_hir/src/ty/method_resolution.rs @@ -8,16 +8,17 @@ use arrayvec::ArrayVec; use hir_def::CrateModuleId; use rustc_hash::FxHashMap; -use super::{autoderef, lower, Canonical, InEnvironment, TraitEnvironment, TraitRef}; use crate::{ db::HirDatabase, impl_block::{ImplBlock, ImplId}, resolve::Resolver, - ty::primitive::{FloatBitness, UncertainFloatTy, UncertainIntTy}, + ty::primitive::{FloatBitness, Uncertain}, ty::{Ty, TypeCtor}, AssocItem, Crate, Function, Module, Mutability, Name, Trait, }; +use super::{autoderef, lower, Canonical, InEnvironment, TraitEnvironment, TraitRef}; + /// This is used as a key for indexing impls. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub enum TyFingerprint { @@ -140,14 +141,12 @@ fn def_crates(db: &impl HirDatabase, cur_crate: Crate, ty: &Ty) -> Option Some(std::iter::once(def_id.krate(db)?).collect()), TypeCtor::Bool => lang_item_crate!(db, cur_crate, "bool"), TypeCtor::Char => lang_item_crate!(db, cur_crate, "char"), - TypeCtor::Float(UncertainFloatTy::Known(f)) => match f.bitness { + TypeCtor::Float(Uncertain::Known(f)) => match f.bitness { // There are two lang items: one in libcore (fXX) and one in libstd (fXX_runtime) FloatBitness::X32 => lang_item_crate!(db, cur_crate, "f32", "f32_runtime"), FloatBitness::X64 => lang_item_crate!(db, cur_crate, "f64", "f64_runtime"), }, - TypeCtor::Int(UncertainIntTy::Known(i)) => { - lang_item_crate!(db, cur_crate, i.ty_to_string()) - } + TypeCtor::Int(Uncertain::Known(i)) => lang_item_crate!(db, cur_crate, i.ty_to_string()), TypeCtor::Str => lang_item_crate!(db, cur_crate, "str_alloc", "str"), TypeCtor::Slice => lang_item_crate!(db, cur_crate, "slice_alloc", "slice"), TypeCtor::RawPtr(Mutability::Shared) => lang_item_crate!(db, cur_crate, "const_ptr"), diff --git a/crates/ra_hir/src/ty/primitive.rs b/crates/ra_hir/src/ty/primitive.rs index 7362de4c3..47789db87 100644 --- a/crates/ra_hir/src/ty/primitive.rs +++ b/crates/ra_hir/src/ty/primitive.rs @@ -4,44 +4,38 @@ use std::fmt; pub use hir_def::builtin_type::{FloatBitness, IntBitness, Signedness}; -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub enum UncertainIntTy { +#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)] +pub enum Uncertain { Unknown, - Known(IntTy), + Known(T), } -impl From for UncertainIntTy { +impl From for Uncertain { fn from(ty: IntTy) -> Self { - UncertainIntTy::Known(ty) + Uncertain::Known(ty) } } -impl fmt::Display for UncertainIntTy { +impl fmt::Display for Uncertain { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - UncertainIntTy::Unknown => write!(f, "{{integer}}"), - UncertainIntTy::Known(ty) => write!(f, "{}", ty), + Uncertain::Unknown => write!(f, "{{integer}}"), + Uncertain::Known(ty) => write!(f, "{}", ty), } } } -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub enum UncertainFloatTy { - Unknown, - Known(FloatTy), -} - -impl From for UncertainFloatTy { +impl From for Uncertain { fn from(ty: FloatTy) -> Self { - UncertainFloatTy::Known(ty) + Uncertain::Known(ty) } } -impl fmt::Display for UncertainFloatTy { +impl fmt::Display for Uncertain { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - UncertainFloatTy::Unknown => write!(f, "{{float}}"), - UncertainFloatTy::Known(ty) => write!(f, "{}", ty), + Uncertain::Unknown => write!(f, "{{float}}"), + Uncertain::Known(ty) => write!(f, "{}", ty), } } } -- cgit v1.2.3 From 018255efe3e456aa8d712f68a714d5c6e010d03f Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 13 Nov 2019 10:27:21 +0300 Subject: Minor cleanup --- crates/ra_assists/src/assists/early_return.rs | 39 ++++++++++++++------------- 1 file changed, 20 insertions(+), 19 deletions(-) (limited to 'crates') diff --git a/crates/ra_assists/src/assists/early_return.rs b/crates/ra_assists/src/assists/early_return.rs index 570a07a20..f44610001 100644 --- a/crates/ra_assists/src/assists/early_return.rs +++ b/crates/ra_assists/src/assists/early_return.rs @@ -38,27 +38,27 @@ use crate::{ // ``` pub(crate) fn convert_to_guarded_return(ctx: AssistCtx) -> Option { let if_expr: ast::IfExpr = ctx.find_node_at_offset()?; + if if_expr.else_branch().is_some() { + return None; + } + let cond = if_expr.condition()?; - let mut if_let_ident: Option = None; // Check if there is an IfLet that we can handle. - match cond.pat() { - None => {} // No IfLet, supported. - Some(TupleStructPat(ref pat)) if pat.args().count() == 1usize => match &pat.path() { - Some(p) => match p.qualifier() { - None => if_let_ident = Some(p.syntax().text().to_string()), - _ => return None, - }, - _ => return None, - }, - _ => return None, // Unsupported IfLet. + let if_let_ident = match cond.pat() { + None => None, // No IfLet, supported. + Some(TupleStructPat(pat)) if pat.args().count() == 1 => { + let path = pat.path()?; + match path.qualifier() { + None => Some(path.syntax().to_string()), + Some(_) => return None, + } + } + Some(_) => return None, // Unsupported IfLet. }; let expr = cond.expr()?; let then_block = if_expr.then_branch()?.block()?; - if if_expr.else_branch().is_some() { - return None; - } let parent_block = if_expr.syntax().parent()?.ancestors().find_map(ast::Block::cast)?; @@ -100,7 +100,7 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx) -> Opt let early_expression = &(early_expression.to_owned() + ";"); let new_expr = if_indent_level.increase_indent(make::if_expression(&expr, early_expression)); - replace(new_expr, &then_block, &parent_block, &if_expr) + replace(new_expr.syntax(), &then_block, &parent_block, &if_expr) } Some(if_let_ident) => { // If-let. @@ -109,7 +109,7 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx) -> Opt &if_let_ident, early_expression, )); - replace(new_expr, &then_block, &parent_block, &if_expr) + replace(new_expr.syntax(), &then_block, &parent_block, &if_expr) } }; edit.target(if_expr.syntax().text_range()); @@ -117,7 +117,7 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx) -> Opt edit.set_cursor(cursor_position); fn replace( - new_expr: impl AstNode, + new_expr: &SyntaxNode, then_block: &Block, parent_block: &Block, if_expr: &ast::IfExpr, @@ -130,7 +130,7 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx) -> Opt } else { end_of_then }; - let mut then_statements = new_expr.syntax().children_with_tokens().chain( + let mut then_statements = new_expr.children_with_tokens().chain( then_block_items .syntax() .children_with_tokens() @@ -151,9 +151,10 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx) -> Opt #[cfg(test)] mod tests { - use super::*; use crate::helpers::{check_assist, check_assist_not_applicable}; + use super::*; + #[test] fn convert_inside_fn() { check_assist( -- cgit v1.2.3 From 2a69d584d6afc842d6dc8503f3fd3a0a691ea385 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 13 Nov 2019 10:54:50 +0300 Subject: Add a bit of types --- crates/ra_assists/src/assists/early_return.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'crates') diff --git a/crates/ra_assists/src/assists/early_return.rs b/crates/ra_assists/src/assists/early_return.rs index f44610001..8507a60fb 100644 --- a/crates/ra_assists/src/assists/early_return.rs +++ b/crates/ra_assists/src/assists/early_return.rs @@ -45,12 +45,12 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx) -> Opt let cond = if_expr.condition()?; // Check if there is an IfLet that we can handle. - let if_let_ident = match cond.pat() { + let bound_ident = match cond.pat() { None => None, // No IfLet, supported. Some(TupleStructPat(pat)) if pat.args().count() == 1 => { let path = pat.path()?; match path.qualifier() { - None => Some(path.syntax().to_string()), + None => Some(path.segment()?.name_ref()?), Some(_) => return None, } } @@ -94,7 +94,7 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx) -> Opt ctx.add_assist(AssistId("convert_to_guarded_return"), "convert to guarded return", |edit| { let if_indent_level = IndentLevel::from_node(&if_expr.syntax()); - let new_block = match if_let_ident { + let new_block = match bound_ident { None => { // If. let early_expression = &(early_expression.to_owned() + ";"); @@ -102,11 +102,11 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx) -> Opt if_indent_level.increase_indent(make::if_expression(&expr, early_expression)); replace(new_expr.syntax(), &then_block, &parent_block, &if_expr) } - Some(if_let_ident) => { + Some(bound_ident) => { // If-let. let new_expr = if_indent_level.increase_indent(make::let_match_early( expr, - &if_let_ident, + &bound_ident.syntax().to_string(), early_expression, )); replace(new_expr.syntax(), &then_block, &parent_block, &if_expr) -- cgit v1.2.3 From e177c65e36f432821087b215b83c2dad1c97f478 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 13 Nov 2019 11:40:51 +0300 Subject: Use strongly-typed ast building for early-return assist --- crates/ra_assists/src/assists/early_return.rs | 95 ++++++++++++++++++++------- crates/ra_syntax/src/ast/make.rs | 52 +++++++++------ 2 files changed, 102 insertions(+), 45 deletions(-) (limited to 'crates') diff --git a/crates/ra_assists/src/assists/early_return.rs b/crates/ra_assists/src/assists/early_return.rs index 8507a60fb..264412526 100644 --- a/crates/ra_assists/src/assists/early_return.rs +++ b/crates/ra_assists/src/assists/early_return.rs @@ -1,4 +1,4 @@ -use std::ops::RangeInclusive; +use std::{iter::once, ops::RangeInclusive}; use hir::db::HirDatabase; use ra_syntax::{ @@ -45,19 +45,22 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx) -> Opt let cond = if_expr.condition()?; // Check if there is an IfLet that we can handle. - let bound_ident = match cond.pat() { + let if_let_pat = match cond.pat() { None => None, // No IfLet, supported. Some(TupleStructPat(pat)) if pat.args().count() == 1 => { let path = pat.path()?; match path.qualifier() { - None => Some(path.segment()?.name_ref()?), + None => { + let bound_ident = pat.args().next().unwrap(); + Some((path, bound_ident)) + } Some(_) => return None, } } Some(_) => return None, // Unsupported IfLet. }; - let expr = cond.expr()?; + let cond_expr = cond.expr()?; let then_block = if_expr.then_branch()?.block()?; let parent_block = if_expr.syntax().parent()?.ancestors().find_map(ast::Block::cast)?; @@ -79,11 +82,11 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx) -> Opt let parent_container = parent_block.syntax().parent()?.parent()?; - let early_expression = match parent_container.kind() { - WHILE_EXPR | LOOP_EXPR => Some("continue"), - FN_DEF => Some("return"), - _ => None, - }?; + let early_expression: ast::Expr = match parent_container.kind() { + WHILE_EXPR | LOOP_EXPR => make::expr_continue().into(), + FN_DEF => make::expr_return().into(), + _ => return None, + }; if then_block.syntax().first_child_or_token().map(|t| t.kind() == L_CURLY).is_none() { return None; @@ -94,22 +97,43 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx) -> Opt ctx.add_assist(AssistId("convert_to_guarded_return"), "convert to guarded return", |edit| { let if_indent_level = IndentLevel::from_node(&if_expr.syntax()); - let new_block = match bound_ident { + let new_block = match if_let_pat { None => { // If. - let early_expression = &(early_expression.to_owned() + ";"); - let new_expr = - if_indent_level.increase_indent(make::if_expression(&expr, early_expression)); + let early_expression = &(early_expression.syntax().to_string() + ";"); + let new_expr = if_indent_level + .increase_indent(make::if_expression(&cond_expr, early_expression)); replace(new_expr.syntax(), &then_block, &parent_block, &if_expr) } - Some(bound_ident) => { + Some((path, bound_ident)) => { // If-let. - let new_expr = if_indent_level.increase_indent(make::let_match_early( - expr, - &bound_ident.syntax().to_string(), - early_expression, - )); - replace(new_expr.syntax(), &then_block, &parent_block, &if_expr) + let match_expr = { + let happy_arm = make::match_arm( + once( + make::tuple_struct_pat( + path, + once(make::bind_pat(make::name("it")).into()), + ) + .into(), + ), + make::expr_path(make::path_from_name_ref(make::name_ref("it"))).into(), + ); + + let sad_arm = make::match_arm( + // FIXME: would be cool to use `None` or `Err(_)` if appropriate + once(make::placeholder_pat().into()), + early_expression.into(), + ); + + make::expr_match(cond_expr, make::match_arm_list(vec![happy_arm, sad_arm])) + }; + + let let_stmt = make::let_stmt( + make::bind_pat(make::name(&bound_ident.syntax().to_string())).into(), + Some(match_expr.into()), + ); + let let_stmt = if_indent_level.increase_indent(let_stmt); + replace(let_stmt.syntax(), &then_block, &parent_block, &if_expr) } }; edit.target(if_expr.syntax().text_range()); @@ -205,7 +229,7 @@ mod tests { bar(); le<|>t n = match n { Some(it) => it, - None => return, + _ => return, }; foo(n); @@ -216,6 +240,29 @@ mod tests { ); } + #[test] + fn convert_if_let_result() { + check_assist( + convert_to_guarded_return, + r#" + fn main() { + if<|> let Ok(x) = Err(92) { + foo(x); + } + } + "#, + r#" + fn main() { + le<|>t x = match Err(92) { + Ok(it) => it, + _ => return, + }; + foo(x); + } + "#, + ); + } + #[test] fn convert_let_ok_inside_fn() { check_assist( @@ -236,7 +283,7 @@ mod tests { bar(); le<|>t n = match n { Ok(it) => it, - None => return, + _ => return, }; foo(n); @@ -294,7 +341,7 @@ mod tests { while true { le<|>t n = match n { Some(it) => it, - None => continue, + _ => continue, }; foo(n); bar(); @@ -351,7 +398,7 @@ mod tests { loop { le<|>t n = match n { Some(it) => it, - None => continue, + _ => continue, }; foo(n); bar(); diff --git a/crates/ra_syntax/src/ast/make.rs b/crates/ra_syntax/src/ast/make.rs index 95062ef6c..6c903ca64 100644 --- a/crates/ra_syntax/src/ast/make.rs +++ b/crates/ra_syntax/src/ast/make.rs @@ -4,6 +4,10 @@ use itertools::Itertools; use crate::{ast, AstNode, SourceFile}; +pub fn name(text: &str) -> ast::Name { + ast_from_text(&format!("mod {};", text)) +} + pub fn name_ref(text: &str) -> ast::NameRef { ast_from_text(&format!("fn f() {{ {}; }}", text)) } @@ -43,6 +47,21 @@ pub fn expr_unit() -> ast::Expr { pub fn expr_unimplemented() -> ast::Expr { expr_from_text("unimplemented!()") } +pub fn expr_path(path: ast::Path) -> ast::Expr { + expr_from_text(&path.syntax().to_string()) +} +pub fn expr_continue() -> ast::Expr { + expr_from_text("continue") +} +pub fn expr_break() -> ast::Expr { + expr_from_text("break") +} +pub fn expr_return() -> ast::Expr { + expr_from_text("return") +} +pub fn expr_match(expr: ast::Expr, match_arm_list: ast::MatchArmList) -> ast::Expr { + expr_from_text(&format!("match {} {}", expr.syntax(), match_arm_list.syntax())) +} fn expr_from_text(text: &str) -> ast::Expr { ast_from_text(&format!("const C: () = {};", text)) } @@ -92,8 +111,8 @@ pub fn path_pat(path: ast::Path) -> ast::PathPat { } } -pub fn match_arm(pats: impl Iterator, expr: ast::Expr) -> ast::MatchArm { - let pats_str = pats.map(|p| p.syntax().to_string()).join(" | "); +pub fn match_arm(pats: impl IntoIterator, expr: ast::Expr) -> ast::MatchArm { + let pats_str = pats.into_iter().map(|p| p.syntax().to_string()).join(" | "); return from_text(&format!("{} => {}", pats_str, expr.syntax())); fn from_text(text: &str) -> ast::MatchArm { @@ -101,8 +120,8 @@ pub fn match_arm(pats: impl Iterator, expr: ast::Expr) -> ast:: } } -pub fn match_arm_list(arms: impl Iterator) -> ast::MatchArmList { - let arms_str = arms.map(|arm| format!("\n {}", arm.syntax())).join(","); +pub fn match_arm_list(arms: impl IntoIterator) -> ast::MatchArmList { + let arms_str = arms.into_iter().map(|arm| format!("\n {}", arm.syntax())).join(","); return from_text(&format!("{},\n", arms_str)); fn from_text(text: &str) -> ast::MatchArmList { @@ -110,23 +129,6 @@ pub fn match_arm_list(arms: impl Iterator) -> ast::MatchAr } } -pub fn let_match_early(expr: ast::Expr, path: &str, early_expression: &str) -> ast::LetStmt { - return from_text(&format!( - r#"let {} = match {} {{ - {}(it) => it, - None => {}, -}};"#, - expr.syntax().text(), - expr.syntax().text(), - path, - early_expression - )); - - fn from_text(text: &str) -> ast::LetStmt { - ast_from_text(&format!("fn f() {{ {} }}", text)) - } -} - pub fn where_pred(path: ast::Path, bounds: impl Iterator) -> ast::WherePred { let bounds = bounds.map(|b| b.syntax().to_string()).join(" + "); return from_text(&format!("{}: {}", path.syntax(), bounds)); @@ -153,6 +155,14 @@ pub fn if_expression(condition: &ast::Expr, statement: &str) -> ast::IfExpr { )) } +pub fn let_stmt(pattern: ast::Pat, initializer: Option) -> ast::LetStmt { + let text = match initializer { + Some(it) => format!("let {} = {};", pattern.syntax(), it.syntax()), + None => format!("let {};", pattern.syntax()), + }; + ast_from_text(&format!("fn f() {{ {} }}", text)) +} + fn ast_from_text(text: &str) -> N { let parse = SourceFile::parse(text); let res = parse.tree().syntax().descendants().find_map(N::cast).unwrap(); -- cgit v1.2.3 From 4cea6bb6f11e28a2d1d2e023d46caa82b0f38796 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 13 Nov 2019 11:55:43 +0300 Subject: Make make:: builders slightly more convenient --- crates/ra_syntax/src/ast/edit.rs | 2 +- crates/ra_syntax/src/ast/make.rs | 19 +++++++++++-------- 2 files changed, 12 insertions(+), 9 deletions(-) (limited to 'crates') diff --git a/crates/ra_syntax/src/ast/edit.rs b/crates/ra_syntax/src/ast/edit.rs index 47bdbb81a..6f005a2d8 100644 --- a/crates/ra_syntax/src/ast/edit.rs +++ b/crates/ra_syntax/src/ast/edit.rs @@ -358,7 +358,7 @@ fn replace_children( fn test_increase_indent() { let arm_list = { let arm = make::match_arm(iter::once(make::placeholder_pat().into()), make::expr_unit()); - make::match_arm_list(vec![arm.clone(), arm].into_iter()) + make::match_arm_list(vec![arm.clone(), arm]) }; assert_eq!( arm_list.syntax().to_string(), diff --git a/crates/ra_syntax/src/ast/make.rs b/crates/ra_syntax/src/ast/make.rs index 6c903ca64..9749327fa 100644 --- a/crates/ra_syntax/src/ast/make.rs +++ b/crates/ra_syntax/src/ast/make.rs @@ -84,9 +84,9 @@ pub fn placeholder_pat() -> ast::PlaceholderPat { pub fn tuple_struct_pat( path: ast::Path, - pats: impl Iterator, + pats: impl IntoIterator, ) -> ast::TupleStructPat { - let pats_str = pats.map(|p| p.syntax().to_string()).join(", "); + let pats_str = pats.into_iter().map(|p| p.syntax().to_string()).join(", "); return from_text(&format!("{}({})", path.syntax(), pats_str)); fn from_text(text: &str) -> ast::TupleStructPat { @@ -94,8 +94,8 @@ pub fn tuple_struct_pat( } } -pub fn record_pat(path: ast::Path, pats: impl Iterator) -> ast::RecordPat { - let pats_str = pats.map(|p| p.syntax().to_string()).join(", "); +pub fn record_pat(path: ast::Path, pats: impl IntoIterator) -> ast::RecordPat { + let pats_str = pats.into_iter().map(|p| p.syntax().to_string()).join(", "); return from_text(&format!("{} {{ {} }}", path.syntax(), pats_str)); fn from_text(text: &str) -> ast::RecordPat { @@ -129,8 +129,11 @@ pub fn match_arm_list(arms: impl IntoIterator) -> ast::Mat } } -pub fn where_pred(path: ast::Path, bounds: impl Iterator) -> ast::WherePred { - let bounds = bounds.map(|b| b.syntax().to_string()).join(" + "); +pub fn where_pred( + path: ast::Path, + bounds: impl IntoIterator, +) -> ast::WherePred { + let bounds = bounds.into_iter().map(|b| b.syntax().to_string()).join(" + "); return from_text(&format!("{}: {}", path.syntax(), bounds)); fn from_text(text: &str) -> ast::WherePred { @@ -138,8 +141,8 @@ pub fn where_pred(path: ast::Path, bounds: impl Iterator) } } -pub fn where_clause(preds: impl Iterator) -> ast::WhereClause { - let preds = preds.map(|p| p.syntax().to_string()).join(", "); +pub fn where_clause(preds: impl IntoIterator) -> ast::WhereClause { + let preds = preds.into_iter().map(|p| p.syntax().to_string()).join(", "); return from_text(preds.as_str()); fn from_text(text: &str) -> ast::WhereClause { -- cgit v1.2.3 From b8f62095d6cf07ba521cdb3f7bac147496b313c9 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 14 Nov 2019 09:09:42 +0300 Subject: Normalize data No need to store derivable info --- crates/ra_hir/src/expr/scope.rs | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir/src/expr/scope.rs b/crates/ra_hir/src/expr/scope.rs index 0e49a28d6..fe5e836f2 100644 --- a/crates/ra_hir/src/expr/scope.rs +++ b/crates/ra_hir/src/expr/scope.rs @@ -17,7 +17,6 @@ impl_arena_id!(ScopeId); #[derive(Debug, PartialEq, Eq)] pub struct ExprScopes { - pub(crate) body: Arc, scopes: Arena, scope_by_expr: FxHashMap, } @@ -47,19 +46,16 @@ pub(crate) struct ScopeData { impl ExprScopes { pub(crate) fn expr_scopes_query(db: &impl HirDatabase, def: DefWithBody) -> Arc { let body = db.body(def); - let res = ExprScopes::new(body); + let res = ExprScopes::new(&*body); Arc::new(res) } - fn new(body: Arc) -> ExprScopes { - let mut scopes = ExprScopes { - body: body.clone(), - scopes: Arena::default(), - scope_by_expr: FxHashMap::default(), - }; + fn new(body: &Body) -> ExprScopes { + let mut scopes = + ExprScopes { scopes: Arena::default(), scope_by_expr: FxHashMap::default() }; let root = scopes.root_scope(); - scopes.add_params_bindings(root, body.params()); - compute_expr_scopes(body.body_expr(), &body, &mut scopes, root); + scopes.add_params_bindings(body, root, body.params()); + compute_expr_scopes(body.body_expr(), body, &mut scopes, root); scopes } @@ -99,9 +95,8 @@ impl ExprScopes { } } - fn add_params_bindings(&mut self, scope: ScopeId, params: &[PatId]) { - let body = Arc::clone(&self.body); - params.iter().for_each(|pat| self.add_bindings(&body, scope, *pat)); + fn add_params_bindings(&mut self, body: &Body, scope: ScopeId, params: &[PatId]) { + params.iter().for_each(|pat| self.add_bindings(body, scope, *pat)); } fn set_scope(&mut self, node: ExprId, scope: ScopeId) { @@ -151,7 +146,7 @@ fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope } Expr::Lambda { args, body: body_expr, .. } => { let scope = scopes.new_scope(scope); - scopes.add_params_bindings(scope, &args); + scopes.add_params_bindings(body, scope, &args); compute_expr_scopes(*body_expr, body, scopes, scope); } Expr::Match { expr, arms } => { -- cgit v1.2.3 From debf95eb1b79a54ed482ea01f1716e5ff1faf0b6 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 14 Nov 2019 09:24:39 +0300 Subject: Reduce visibility --- crates/ra_hir_def/src/body.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs index ac8f8261b..269501221 100644 --- a/crates/ra_hir_def/src/body.rs +++ b/crates/ra_hir_def/src/body.rs @@ -26,11 +26,7 @@ impl MacroResolver { MacroResolver { crate_def_map: db.crate_def_map(module.krate), module } } - pub(crate) fn resolve_path_as_macro( - &self, - db: &impl DefDatabase2, - path: &Path, - ) -> Option { + fn resolve_path_as_macro(&self, db: &impl DefDatabase2, path: &Path) -> Option { self.crate_def_map.resolve_path(db, self.module.module_id, path).0.get_macros() } } -- cgit v1.2.3 From b3175b7077129ca4b6c52e05f0491e65617ae423 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 14 Nov 2019 09:37:33 +0300 Subject: Move current file to MacroResolver --- crates/ra_hir/src/expr.rs | 4 ++-- crates/ra_hir_def/src/body.rs | 13 +++++++++---- crates/ra_hir_def/src/body/lower.rs | 31 ++++++++++++++++--------------- 3 files changed, 27 insertions(+), 21 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs index 82955fa55..d1af8ee39 100644 --- a/crates/ra_hir/src/expr.rs +++ b/crates/ra_hir/src/expr.rs @@ -40,8 +40,8 @@ pub(crate) fn body_with_source_map_query( (src.file_id, src.ast.body()) } }; - let resolver = hir_def::body::MacroResolver::new(db, def.module(db).id); - let (body, source_map) = Body::new(db, resolver, file_id, params, body); + let resolver = hir_def::body::MacroResolver::new(db, file_id, def.module(db).id); + let (body, source_map) = Body::new(db, resolver, params, body); (Arc::new(body), Arc::new(source_map)) } diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs index 269501221..7e84e9113 100644 --- a/crates/ra_hir_def/src/body.rs +++ b/crates/ra_hir_def/src/body.rs @@ -18,12 +18,18 @@ use crate::{ pub struct MacroResolver { crate_def_map: Arc, + current_file_id: HirFileId, module: ModuleId, } impl MacroResolver { - pub fn new(db: &impl DefDatabase2, module: ModuleId) -> MacroResolver { - MacroResolver { crate_def_map: db.crate_def_map(module.krate), module } + pub fn new( + db: &impl DefDatabase2, + current_file_id: HirFileId, + module: ModuleId, + ) -> MacroResolver { + let crate_def_map = db.crate_def_map(module.krate); + MacroResolver { crate_def_map, current_file_id, module } } fn resolve_path_as_macro(&self, db: &impl DefDatabase2, path: &Path) -> Option { @@ -77,11 +83,10 @@ impl Body { pub fn new( db: &impl DefDatabase2, resolver: MacroResolver, - file_id: HirFileId, params: Option, body: Option, ) -> (Body, BodySourceMap) { - lower::lower(db, resolver, file_id, params, body) + lower::lower(db, resolver, params, body) } pub fn params(&self) -> &[PatId] { diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs index 2aa863c9e..1a990101f 100644 --- a/crates/ra_hir_def/src/body/lower.rs +++ b/crates/ra_hir_def/src/body/lower.rs @@ -31,15 +31,15 @@ use crate::{ pub(super) fn lower( db: &impl DefDatabase2, resolver: MacroResolver, - file_id: HirFileId, params: Option, body: Option, ) -> (Body, BodySourceMap) { + let original_file_id = resolver.current_file_id; + ExprCollector { resolver, db, - original_file_id: file_id, - current_file_id: file_id, + original_file_id, source_map: BodySourceMap::default(), body: Body { exprs: Arena::default(), @@ -55,7 +55,6 @@ struct ExprCollector { db: DB, resolver: MacroResolver, original_file_id: HirFileId, - current_file_id: HirFileId, body: Body, source_map: BodySourceMap, @@ -101,12 +100,12 @@ where fn alloc_expr(&mut self, expr: Expr, ptr: AstPtr) -> ExprId { let ptr = Either::A(ptr); let id = self.body.exprs.alloc(expr); - if self.current_file_id == self.original_file_id { + if self.resolver.current_file_id == self.original_file_id { self.source_map.expr_map.insert(ptr, id); } self.source_map .expr_map_back - .insert(id, Source { file_id: self.current_file_id, ast: ptr }); + .insert(id, Source { file_id: self.resolver.current_file_id, ast: ptr }); id } // desugared exprs don't have ptr, that's wrong and should be fixed @@ -117,20 +116,22 @@ where fn alloc_expr_field_shorthand(&mut self, expr: Expr, ptr: AstPtr) -> ExprId { let ptr = Either::B(ptr); let id = self.body.exprs.alloc(expr); - if self.current_file_id == self.original_file_id { + if self.resolver.current_file_id == self.original_file_id { self.source_map.expr_map.insert(ptr, id); } self.source_map .expr_map_back - .insert(id, Source { file_id: self.current_file_id, ast: ptr }); + .insert(id, Source { file_id: self.resolver.current_file_id, ast: ptr }); id } fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId { let id = self.body.pats.alloc(pat); - if self.current_file_id == self.original_file_id { + if self.resolver.current_file_id == self.original_file_id { self.source_map.pat_map.insert(ptr, id); } - self.source_map.pat_map_back.insert(id, Source { file_id: self.current_file_id, ast: ptr }); + self.source_map + .pat_map_back + .insert(id, Source { file_id: self.resolver.current_file_id, ast: ptr }); id } @@ -445,8 +446,8 @@ where ast::Expr::RangeExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), ast::Expr::MacroCall(e) => { let ast_id = AstId::new( - self.current_file_id, - self.db.ast_id_map(self.current_file_id).ast_id(&e), + self.resolver.current_file_id, + self.db.ast_id_map(self.resolver.current_file_id).ast_id(&e), ); if let Some(path) = e.path().and_then(|path| self.parse_path(path)) { @@ -457,9 +458,9 @@ where if let Some(expr) = ast::Expr::cast(node) { log::debug!("macro expansion {:#?}", expr.syntax()); let old_file_id = - std::mem::replace(&mut self.current_file_id, file_id); + std::mem::replace(&mut self.resolver.current_file_id, file_id); let id = self.collect_expr(expr); - self.current_file_id = old_file_id; + self.resolver.current_file_id = old_file_id; return id; } } @@ -581,7 +582,7 @@ where } fn parse_path(&mut self, path: ast::Path) -> Option { - let hygiene = Hygiene::new(self.db, self.current_file_id); + let hygiene = Hygiene::new(self.db, self.resolver.current_file_id); Path::from_src(path, &hygiene) } } -- cgit v1.2.3 From 8c8ef1432e1891809f48ff691f949047d6527c07 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 14 Nov 2019 09:38:25 +0300 Subject: Rename MacroResolver -> Expander --- crates/ra_hir/src/expr.rs | 4 ++-- crates/ra_hir_def/src/body.rs | 16 ++++++---------- crates/ra_hir_def/src/body/lower.rs | 34 +++++++++++++++++----------------- 3 files changed, 25 insertions(+), 29 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs index d1af8ee39..d19f5d14c 100644 --- a/crates/ra_hir/src/expr.rs +++ b/crates/ra_hir/src/expr.rs @@ -40,8 +40,8 @@ pub(crate) fn body_with_source_map_query( (src.file_id, src.ast.body()) } }; - let resolver = hir_def::body::MacroResolver::new(db, file_id, def.module(db).id); - let (body, source_map) = Body::new(db, resolver, params, body); + let expander = hir_def::body::Expander::new(db, file_id, def.module(db).id); + let (body, source_map) = Body::new(db, expander, params, body); (Arc::new(body), Arc::new(source_map)) } diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs index 7e84e9113..5d8c299ba 100644 --- a/crates/ra_hir_def/src/body.rs +++ b/crates/ra_hir_def/src/body.rs @@ -16,20 +16,16 @@ use crate::{ ModuleId, }; -pub struct MacroResolver { +pub struct Expander { crate_def_map: Arc, current_file_id: HirFileId, module: ModuleId, } -impl MacroResolver { - pub fn new( - db: &impl DefDatabase2, - current_file_id: HirFileId, - module: ModuleId, - ) -> MacroResolver { +impl Expander { + pub fn new(db: &impl DefDatabase2, current_file_id: HirFileId, module: ModuleId) -> Expander { let crate_def_map = db.crate_def_map(module.krate); - MacroResolver { crate_def_map, current_file_id, module } + Expander { crate_def_map, current_file_id, module } } fn resolve_path_as_macro(&self, db: &impl DefDatabase2, path: &Path) -> Option { @@ -82,11 +78,11 @@ pub struct BodySourceMap { impl Body { pub fn new( db: &impl DefDatabase2, - resolver: MacroResolver, + expander: Expander, params: Option, body: Option, ) -> (Body, BodySourceMap) { - lower::lower(db, resolver, params, body) + lower::lower(db, expander, params, body) } pub fn params(&self) -> &[PatId] { diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs index 1a990101f..cc4bbe11a 100644 --- a/crates/ra_hir_def/src/body/lower.rs +++ b/crates/ra_hir_def/src/body/lower.rs @@ -16,7 +16,7 @@ use ra_syntax::{ }; use crate::{ - body::{Body, BodySourceMap, MacroResolver, PatPtr}, + body::{Body, BodySourceMap, Expander, PatPtr}, builtin_type::{BuiltinFloat, BuiltinInt}, db::DefDatabase2, expr::{ @@ -30,14 +30,14 @@ use crate::{ pub(super) fn lower( db: &impl DefDatabase2, - resolver: MacroResolver, + expander: Expander, params: Option, body: Option, ) -> (Body, BodySourceMap) { - let original_file_id = resolver.current_file_id; + let original_file_id = expander.current_file_id; ExprCollector { - resolver, + expander, db, original_file_id, source_map: BodySourceMap::default(), @@ -53,7 +53,7 @@ pub(super) fn lower( struct ExprCollector { db: DB, - resolver: MacroResolver, + expander: Expander, original_file_id: HirFileId, body: Body, @@ -100,12 +100,12 @@ where fn alloc_expr(&mut self, expr: Expr, ptr: AstPtr) -> ExprId { let ptr = Either::A(ptr); let id = self.body.exprs.alloc(expr); - if self.resolver.current_file_id == self.original_file_id { + if self.expander.current_file_id == self.original_file_id { self.source_map.expr_map.insert(ptr, id); } self.source_map .expr_map_back - .insert(id, Source { file_id: self.resolver.current_file_id, ast: ptr }); + .insert(id, Source { file_id: self.expander.current_file_id, ast: ptr }); id } // desugared exprs don't have ptr, that's wrong and should be fixed @@ -116,22 +116,22 @@ where fn alloc_expr_field_shorthand(&mut self, expr: Expr, ptr: AstPtr) -> ExprId { let ptr = Either::B(ptr); let id = self.body.exprs.alloc(expr); - if self.resolver.current_file_id == self.original_file_id { + if self.expander.current_file_id == self.original_file_id { self.source_map.expr_map.insert(ptr, id); } self.source_map .expr_map_back - .insert(id, Source { file_id: self.resolver.current_file_id, ast: ptr }); + .insert(id, Source { file_id: self.expander.current_file_id, ast: ptr }); id } fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId { let id = self.body.pats.alloc(pat); - if self.resolver.current_file_id == self.original_file_id { + if self.expander.current_file_id == self.original_file_id { self.source_map.pat_map.insert(ptr, id); } self.source_map .pat_map_back - .insert(id, Source { file_id: self.resolver.current_file_id, ast: ptr }); + .insert(id, Source { file_id: self.expander.current_file_id, ast: ptr }); id } @@ -446,21 +446,21 @@ where ast::Expr::RangeExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), ast::Expr::MacroCall(e) => { let ast_id = AstId::new( - self.resolver.current_file_id, - self.db.ast_id_map(self.resolver.current_file_id).ast_id(&e), + self.expander.current_file_id, + self.db.ast_id_map(self.expander.current_file_id).ast_id(&e), ); if let Some(path) = e.path().and_then(|path| self.parse_path(path)) { - if let Some(def) = self.resolver.resolve_path_as_macro(self.db, &path) { + if let Some(def) = self.expander.resolve_path_as_macro(self.db, &path) { let call_id = self.db.intern_macro(MacroCallLoc { def, ast_id }); let file_id = call_id.as_file(MacroFileKind::Expr); if let Some(node) = self.db.parse_or_expand(file_id) { if let Some(expr) = ast::Expr::cast(node) { log::debug!("macro expansion {:#?}", expr.syntax()); let old_file_id = - std::mem::replace(&mut self.resolver.current_file_id, file_id); + std::mem::replace(&mut self.expander.current_file_id, file_id); let id = self.collect_expr(expr); - self.resolver.current_file_id = old_file_id; + self.expander.current_file_id = old_file_id; return id; } } @@ -582,7 +582,7 @@ where } fn parse_path(&mut self, path: ast::Path) -> Option { - let hygiene = Hygiene::new(self.db, self.resolver.current_file_id); + let hygiene = Hygiene::new(self.db, self.expander.current_file_id); Path::from_src(path, &hygiene) } } -- cgit v1.2.3 From e7e85c60d2c225eacc80184a7918ecf6c8ab0563 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 14 Nov 2019 09:41:46 +0300 Subject: Move original_file to Expander --- crates/ra_hir_def/src/body.rs | 8 +++++++- crates/ra_hir_def/src/body/lower.rs | 12 ++++-------- 2 files changed, 11 insertions(+), 9 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs index 5d8c299ba..1c9c86449 100644 --- a/crates/ra_hir_def/src/body.rs +++ b/crates/ra_hir_def/src/body.rs @@ -18,6 +18,7 @@ use crate::{ pub struct Expander { crate_def_map: Arc, + original_file_id: HirFileId, current_file_id: HirFileId, module: ModuleId, } @@ -25,7 +26,12 @@ pub struct Expander { impl Expander { pub fn new(db: &impl DefDatabase2, current_file_id: HirFileId, module: ModuleId) -> Expander { let crate_def_map = db.crate_def_map(module.krate); - Expander { crate_def_map, current_file_id, module } + Expander { crate_def_map, original_file_id: current_file_id, current_file_id, module } + } + + // FIXME: remove this. + fn is_in_expansion(&self) -> bool { + self.original_file_id != self.current_file_id } fn resolve_path_as_macro(&self, db: &impl DefDatabase2, path: &Path) -> Option { diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs index cc4bbe11a..602bcb220 100644 --- a/crates/ra_hir_def/src/body/lower.rs +++ b/crates/ra_hir_def/src/body/lower.rs @@ -4,7 +4,7 @@ use hir_expand::{ either::Either, hygiene::Hygiene, name::{self, AsName, Name}, - AstId, HirFileId, MacroCallLoc, MacroFileKind, Source, + AstId, MacroCallLoc, MacroFileKind, Source, }; use ra_arena::Arena; use ra_syntax::{ @@ -34,12 +34,9 @@ pub(super) fn lower( params: Option, body: Option, ) -> (Body, BodySourceMap) { - let original_file_id = expander.current_file_id; - ExprCollector { expander, db, - original_file_id, source_map: BodySourceMap::default(), body: Body { exprs: Arena::default(), @@ -54,7 +51,6 @@ pub(super) fn lower( struct ExprCollector { db: DB, expander: Expander, - original_file_id: HirFileId, body: Body, source_map: BodySourceMap, @@ -100,7 +96,7 @@ where fn alloc_expr(&mut self, expr: Expr, ptr: AstPtr) -> ExprId { let ptr = Either::A(ptr); let id = self.body.exprs.alloc(expr); - if self.expander.current_file_id == self.original_file_id { + if !self.expander.is_in_expansion() { self.source_map.expr_map.insert(ptr, id); } self.source_map @@ -116,7 +112,7 @@ where fn alloc_expr_field_shorthand(&mut self, expr: Expr, ptr: AstPtr) -> ExprId { let ptr = Either::B(ptr); let id = self.body.exprs.alloc(expr); - if self.expander.current_file_id == self.original_file_id { + if !self.expander.is_in_expansion() { self.source_map.expr_map.insert(ptr, id); } self.source_map @@ -126,7 +122,7 @@ where } fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId { let id = self.body.pats.alloc(pat); - if self.expander.current_file_id == self.original_file_id { + if !self.expander.is_in_expansion() { self.source_map.pat_map.insert(ptr, id); } self.source_map -- cgit v1.2.3 From c89010df2d586eec33b50f3afcc4b2226da32672 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 14 Nov 2019 09:43:59 +0300 Subject: Add Expader::to_source --- crates/ra_hir_def/src/body.rs | 4 ++++ crates/ra_hir_def/src/body/lower.rs | 14 ++++---------- 2 files changed, 8 insertions(+), 10 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs index 1c9c86449..622c836d1 100644 --- a/crates/ra_hir_def/src/body.rs +++ b/crates/ra_hir_def/src/body.rs @@ -34,6 +34,10 @@ impl Expander { self.original_file_id != self.current_file_id } + fn to_source(&self, ast: T) -> Source { + Source { file_id: self.current_file_id, ast } + } + fn resolve_path_as_macro(&self, db: &impl DefDatabase2, path: &Path) -> Option { self.crate_def_map.resolve_path(db, self.module.module_id, path).0.get_macros() } diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs index 602bcb220..1ea8ce249 100644 --- a/crates/ra_hir_def/src/body/lower.rs +++ b/crates/ra_hir_def/src/body/lower.rs @@ -4,7 +4,7 @@ use hir_expand::{ either::Either, hygiene::Hygiene, name::{self, AsName, Name}, - AstId, MacroCallLoc, MacroFileKind, Source, + AstId, MacroCallLoc, MacroFileKind, }; use ra_arena::Arena; use ra_syntax::{ @@ -99,9 +99,7 @@ where if !self.expander.is_in_expansion() { self.source_map.expr_map.insert(ptr, id); } - self.source_map - .expr_map_back - .insert(id, Source { file_id: self.expander.current_file_id, ast: ptr }); + self.source_map.expr_map_back.insert(id, self.expander.to_source(ptr)); id } // desugared exprs don't have ptr, that's wrong and should be fixed @@ -115,9 +113,7 @@ where if !self.expander.is_in_expansion() { self.source_map.expr_map.insert(ptr, id); } - self.source_map - .expr_map_back - .insert(id, Source { file_id: self.expander.current_file_id, ast: ptr }); + self.source_map.expr_map_back.insert(id, self.expander.to_source(ptr)); id } fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId { @@ -125,9 +121,7 @@ where if !self.expander.is_in_expansion() { self.source_map.pat_map.insert(ptr, id); } - self.source_map - .pat_map_back - .insert(id, Source { file_id: self.expander.current_file_id, ast: ptr }); + self.source_map.pat_map_back.insert(id, self.expander.to_source(ptr)); id } -- cgit v1.2.3 From e7880db1d0f75c639ee561b586219648bd05c21c Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 14 Nov 2019 09:52:03 +0300 Subject: Expansion stack scaffold --- crates/ra_hir_def/src/body.rs | 37 +++++++++++++++++++++++++++++++++++-- crates/ra_hir_def/src/body/lower.rs | 9 +++------ 2 files changed, 38 insertions(+), 8 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs index 622c836d1..3b262e3bd 100644 --- a/crates/ra_hir_def/src/body.rs +++ b/crates/ra_hir_def/src/body.rs @@ -3,7 +3,7 @@ mod lower; use std::{ops::Index, sync::Arc}; -use hir_expand::{either::Either, HirFileId, MacroDefId, Source}; +use hir_expand::{either::Either, hygiene::Hygiene, HirFileId, MacroDefId, Source}; use ra_arena::{map::ArenaMap, Arena}; use ra_syntax::{ast, AstPtr}; use rustc_hash::FxHashMap; @@ -20,13 +20,34 @@ pub struct Expander { crate_def_map: Arc, original_file_id: HirFileId, current_file_id: HirFileId, + hygiene: Hygiene, module: ModuleId, } impl Expander { pub fn new(db: &impl DefDatabase2, current_file_id: HirFileId, module: ModuleId) -> Expander { let crate_def_map = db.crate_def_map(module.krate); - Expander { crate_def_map, original_file_id: current_file_id, current_file_id, module } + let hygiene = Hygiene::new(db, current_file_id); + Expander { + crate_def_map, + original_file_id: current_file_id, + current_file_id, + hygiene, + module, + } + } + + fn enter(&mut self, db: &impl DefDatabase2, file_id: HirFileId) -> Mark { + let mark = Mark { file_id: self.current_file_id }; + self.hygiene = Hygiene::new(db, file_id); + self.current_file_id = file_id; + mark + } + + fn exit(&mut self, db: &impl DefDatabase2, mark: Mark) { + self.hygiene = Hygiene::new(db, mark.file_id); + self.current_file_id = mark.file_id; + std::mem::forget(mark); } // FIXME: remove this. @@ -43,6 +64,18 @@ impl Expander { } } +struct Mark { + file_id: HirFileId, +} + +impl Drop for Mark { + fn drop(&mut self) { + if !std::thread::panicking() { + panic!("dropped mark") + } + } +} + /// The body of an item (function, const etc.). #[derive(Debug, Eq, PartialEq)] pub struct Body { diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs index 1ea8ce249..5c291421a 100644 --- a/crates/ra_hir_def/src/body/lower.rs +++ b/crates/ra_hir_def/src/body/lower.rs @@ -2,7 +2,6 @@ use hir_expand::{ either::Either, - hygiene::Hygiene, name::{self, AsName, Name}, AstId, MacroCallLoc, MacroFileKind, }; @@ -447,10 +446,9 @@ where if let Some(node) = self.db.parse_or_expand(file_id) { if let Some(expr) = ast::Expr::cast(node) { log::debug!("macro expansion {:#?}", expr.syntax()); - let old_file_id = - std::mem::replace(&mut self.expander.current_file_id, file_id); + let mark = self.expander.enter(self.db, file_id); let id = self.collect_expr(expr); - self.expander.current_file_id = old_file_id; + self.expander.exit(self.db, mark); return id; } } @@ -572,8 +570,7 @@ where } fn parse_path(&mut self, path: ast::Path) -> Option { - let hygiene = Hygiene::new(self.db, self.expander.current_file_id); - Path::from_src(path, &hygiene) + Path::from_src(path, &self.expander.hygiene) } } -- cgit v1.2.3 From 5c720b256f5d73434250072cc65fead746250d87 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 14 Nov 2019 09:58:39 +0300 Subject: Move parse_path to Expander --- crates/ra_hir_def/src/body.rs | 4 ++++ crates/ra_hir_def/src/body/lower.rs | 16 ++++++---------- 2 files changed, 10 insertions(+), 10 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs index 3b262e3bd..afceeb8de 100644 --- a/crates/ra_hir_def/src/body.rs +++ b/crates/ra_hir_def/src/body.rs @@ -59,6 +59,10 @@ impl Expander { Source { file_id: self.current_file_id, ast } } + fn parse_path(&mut self, path: ast::Path) -> Option { + Path::from_src(path, &self.hygiene) + } + fn resolve_path_as_macro(&self, db: &impl DefDatabase2, path: &Path) -> Option { self.crate_def_map.resolve_path(db, self.module.module_id, path).0.get_macros() } diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs index 5c291421a..29c1ec2a1 100644 --- a/crates/ra_hir_def/src/body/lower.rs +++ b/crates/ra_hir_def/src/body/lower.rs @@ -262,7 +262,7 @@ where ast::Expr::PathExpr(e) => { let path = e .path() - .and_then(|path| self.parse_path(path)) + .and_then(|path| self.expander.parse_path(path)) .map(Expr::Path) .unwrap_or(Expr::Missing); self.alloc_expr(path, syntax_ptr) @@ -286,7 +286,7 @@ where self.alloc_expr(Expr::Return { expr }, syntax_ptr) } ast::Expr::RecordLit(e) => { - let path = e.path().and_then(|path| self.parse_path(path)); + let path = e.path().and_then(|path| self.expander.parse_path(path)); let mut field_ptrs = Vec::new(); let record_lit = if let Some(nfl) = e.record_field_list() { let fields = nfl @@ -439,7 +439,7 @@ where self.db.ast_id_map(self.expander.current_file_id).ast_id(&e), ); - if let Some(path) = e.path().and_then(|path| self.parse_path(path)) { + if let Some(path) = e.path().and_then(|path| self.expander.parse_path(path)) { if let Some(def) = self.expander.resolve_path_as_macro(self.db, &path) { let call_id = self.db.intern_macro(MacroCallLoc { def, ast_id }); let file_id = call_id.as_file(MacroFileKind::Expr); @@ -508,7 +508,7 @@ where Pat::Bind { name, mode: annotation, subpat } } ast::Pat::TupleStructPat(p) => { - let path = p.path().and_then(|path| self.parse_path(path)); + let path = p.path().and_then(|path| self.expander.parse_path(path)); let args = p.args().map(|p| self.collect_pat(p)).collect(); Pat::TupleStruct { path, args } } @@ -518,7 +518,7 @@ where Pat::Ref { pat, mutability } } ast::Pat::PathPat(p) => { - let path = p.path().and_then(|path| self.parse_path(path)); + let path = p.path().and_then(|path| self.expander.parse_path(path)); path.map(Pat::Path).unwrap_or(Pat::Missing) } ast::Pat::TuplePat(p) => { @@ -527,7 +527,7 @@ where } ast::Pat::PlaceholderPat(_) => Pat::Wild, ast::Pat::RecordPat(p) => { - let path = p.path().and_then(|path| self.parse_path(path)); + let path = p.path().and_then(|path| self.expander.parse_path(path)); let record_field_pat_list = p.record_field_pat_list().expect("every struct should have a field list"); let mut fields: Vec<_> = record_field_pat_list @@ -568,10 +568,6 @@ where self.missing_pat() } } - - fn parse_path(&mut self, path: ast::Path) -> Option { - Path::from_src(path, &self.expander.hygiene) - } } impl From for BinaryOp { -- cgit v1.2.3 From a73b7bb3f6af134c781cba1126350749c5a91144 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 14 Nov 2019 10:04:39 +0300 Subject: Move expansion to Expander --- crates/ra_hir_def/src/body.rs | 36 ++++++++++++++++++++++++++++++++++-- crates/ra_hir_def/src/body/lower.rs | 32 +++++++------------------------- 2 files changed, 41 insertions(+), 27 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs index afceeb8de..65fefd912 100644 --- a/crates/ra_hir_def/src/body.rs +++ b/crates/ra_hir_def/src/body.rs @@ -3,9 +3,12 @@ mod lower; use std::{ops::Index, sync::Arc}; -use hir_expand::{either::Either, hygiene::Hygiene, HirFileId, MacroDefId, Source}; +use hir_expand::{ + either::Either, hygiene::Hygiene, AstId, HirFileId, MacroCallLoc, MacroDefId, MacroFileKind, + Source, +}; use ra_arena::{map::ArenaMap, Arena}; -use ra_syntax::{ast, AstPtr}; +use ra_syntax::{ast, AstNode, AstPtr}; use rustc_hash::FxHashMap; use crate::{ @@ -37,6 +40,35 @@ impl Expander { } } + fn expand( + &mut self, + db: &impl DefDatabase2, + macro_call: ast::MacroCall, + ) -> Option<(Mark, ast::Expr)> { + let ast_id = AstId::new( + self.current_file_id, + db.ast_id_map(self.current_file_id).ast_id(¯o_call), + ); + + if let Some(path) = macro_call.path().and_then(|path| self.parse_path(path)) { + if let Some(def) = self.resolve_path_as_macro(db, &path) { + let call_id = db.intern_macro(MacroCallLoc { def, ast_id }); + let file_id = call_id.as_file(MacroFileKind::Expr); + if let Some(node) = db.parse_or_expand(file_id) { + if let Some(expr) = ast::Expr::cast(node) { + log::debug!("macro expansion {:#?}", expr.syntax()); + let mark = self.enter(db, file_id); + return Some((mark, expr)); + } + } + } + } + + // FIXME: Instead of just dropping the error from expansion + // report it + None + } + fn enter(&mut self, db: &impl DefDatabase2, file_id: HirFileId) -> Mark { let mark = Mark { file_id: self.current_file_id }; self.hygiene = Hygiene::new(db, file_id); diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs index 29c1ec2a1..c45500195 100644 --- a/crates/ra_hir_def/src/body/lower.rs +++ b/crates/ra_hir_def/src/body/lower.rs @@ -3,7 +3,6 @@ use hir_expand::{ either::Either, name::{self, AsName, Name}, - AstId, MacroCallLoc, MacroFileKind, }; use ra_arena::Arena; use ra_syntax::{ @@ -433,31 +432,14 @@ where // FIXME implement HIR for these: ast::Expr::Label(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), ast::Expr::RangeExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), - ast::Expr::MacroCall(e) => { - let ast_id = AstId::new( - self.expander.current_file_id, - self.db.ast_id_map(self.expander.current_file_id).ast_id(&e), - ); - - if let Some(path) = e.path().and_then(|path| self.expander.parse_path(path)) { - if let Some(def) = self.expander.resolve_path_as_macro(self.db, &path) { - let call_id = self.db.intern_macro(MacroCallLoc { def, ast_id }); - let file_id = call_id.as_file(MacroFileKind::Expr); - if let Some(node) = self.db.parse_or_expand(file_id) { - if let Some(expr) = ast::Expr::cast(node) { - log::debug!("macro expansion {:#?}", expr.syntax()); - let mark = self.expander.enter(self.db, file_id); - let id = self.collect_expr(expr); - self.expander.exit(self.db, mark); - return id; - } - } - } + ast::Expr::MacroCall(e) => match self.expander.expand(self.db, e) { + Some((mark, expansion)) => { + let id = self.collect_expr(expansion); + self.expander.exit(self.db, mark); + id } - // FIXME: Instead of just dropping the error from expansion - // report it - self.alloc_expr(Expr::Missing, syntax_ptr) - } + None => self.alloc_expr(Expr::Missing, syntax_ptr), + }, } } -- cgit v1.2.3 From da2ca01ebaaaaa47aa09c5848c53b145a68af8fa Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 14 Nov 2019 10:30:30 +0300 Subject: Handle macro-generated expressions slightly less wrong --- crates/ra_hir/src/expr/scope.rs | 6 ++++- crates/ra_hir/src/from_source.rs | 3 ++- crates/ra_hir/src/source_binder.rs | 44 ++++++++++++++++++++++++++----------- crates/ra_hir_def/src/body.rs | 28 ++++++++--------------- crates/ra_hir_def/src/body/lower.rs | 24 ++++++++++---------- crates/ra_hir_expand/src/lib.rs | 5 ++++- 6 files changed, 62 insertions(+), 48 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir/src/expr/scope.rs b/crates/ra_hir/src/expr/scope.rs index fe5e836f2..afba66069 100644 --- a/crates/ra_hir/src/expr/scope.rs +++ b/crates/ra_hir/src/expr/scope.rs @@ -166,6 +166,7 @@ fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope #[cfg(test)] mod tests { + use hir_expand::Source; use ra_db::{fixture::WithFixture, SourceDatabase}; use ra_syntax::{algo::find_node_at_offset, ast, AstNode}; use test_utils::{assert_eq_text, extract_offset}; @@ -189,7 +190,10 @@ mod tests { let analyzer = SourceAnalyzer::new(&db, file_id, marker.syntax(), None); let scopes = analyzer.scopes(); - let expr_id = analyzer.body_source_map().node_expr(&marker.into()).unwrap(); + let expr_id = analyzer + .body_source_map() + .node_expr(Source { file_id: file_id.into(), ast: &marker.into() }) + .unwrap(); let scope = scopes.scope_for(expr_id); let actual = scopes diff --git a/crates/ra_hir/src/from_source.rs b/crates/ra_hir/src/from_source.rs index 2c441b0f4..4b561c63d 100644 --- a/crates/ra_hir/src/from_source.rs +++ b/crates/ra_hir/src/from_source.rs @@ -145,7 +145,8 @@ impl Local { Some(res) })?; let (_body, source_map) = db.body_with_source_map(parent); - let pat_id = source_map.node_pat(&src.ast.into())?; + let src = src.map(ast::Pat::from); + let pat_id = source_map.node_pat(src.as_ref())?; Some(Local { parent, pat_id }) } } diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index f28e9c931..88eed1137 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs @@ -7,8 +7,11 @@ //! purely for "IDE needs". use std::sync::Arc; -use hir_def::path::known; -use hir_expand::name::AsName; +use hir_def::{ + expr::{ExprId, PatId}, + path::known, +}; +use hir_expand::{name::AsName, Source}; use ra_db::FileId; use ra_syntax::{ ast::{self, AstNode}, @@ -93,6 +96,8 @@ fn def_with_body_from_child_node( /// original source files. It should not be used inside the HIR itself. #[derive(Debug)] pub struct SourceAnalyzer { + // FIXME: this doesn't handle macros at all + file_id: FileId, resolver: Resolver, body_owner: Option, body_source_map: Option>, @@ -147,7 +152,7 @@ impl SourceAnalyzer { let source_map = def.body_source_map(db); let scopes = db.expr_scopes(def); let scope = match offset { - None => scope_for(&scopes, &source_map, &node), + None => scope_for(&scopes, &source_map, file_id.into(), &node), Some(offset) => scope_for_offset(&scopes, &source_map, file_id.into(), offset), }; let resolver = expr::resolver_for_scope(db, def, scope); @@ -157,6 +162,7 @@ impl SourceAnalyzer { body_source_map: Some(source_map), infer: Some(def.infer(db)), scopes: Some(scopes), + file_id, } } else { SourceAnalyzer { @@ -168,17 +174,28 @@ impl SourceAnalyzer { body_source_map: None, infer: None, scopes: None, + file_id, } } } + fn expr_id(&self, expr: &ast::Expr) -> Option { + let src = Source { file_id: self.file_id.into(), ast: expr }; + self.body_source_map.as_ref()?.node_expr(src) + } + + fn pat_id(&self, pat: &ast::Pat) -> Option { + let src = Source { file_id: self.file_id.into(), ast: pat }; + self.body_source_map.as_ref()?.node_pat(src) + } + pub fn type_of(&self, _db: &impl HirDatabase, expr: &ast::Expr) -> Option { - let expr_id = self.body_source_map.as_ref()?.node_expr(expr)?; + let expr_id = self.expr_id(expr)?; Some(self.infer.as_ref()?[expr_id].clone()) } pub fn type_of_pat(&self, _db: &impl HirDatabase, pat: &ast::Pat) -> Option { - let pat_id = self.body_source_map.as_ref()?.node_pat(pat)?; + let pat_id = self.pat_id(pat)?; Some(self.infer.as_ref()?[pat_id].clone()) } @@ -191,22 +208,22 @@ impl SourceAnalyzer { } pub fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option { - let expr_id = self.body_source_map.as_ref()?.node_expr(&call.clone().into())?; + let expr_id = self.expr_id(&call.clone().into())?; self.infer.as_ref()?.method_resolution(expr_id) } pub fn resolve_field(&self, field: &ast::FieldExpr) -> Option { - let expr_id = self.body_source_map.as_ref()?.node_expr(&field.clone().into())?; + let expr_id = self.expr_id(&field.clone().into())?; self.infer.as_ref()?.field_resolution(expr_id) } pub fn resolve_record_literal(&self, record_lit: &ast::RecordLit) -> Option { - let expr_id = self.body_source_map.as_ref()?.node_expr(&record_lit.clone().into())?; + let expr_id = self.expr_id(&record_lit.clone().into())?; self.infer.as_ref()?.variant_resolution_for_expr(expr_id) } pub fn resolve_record_pattern(&self, record_pat: &ast::RecordPat) -> Option { - let pat_id = self.body_source_map.as_ref()?.node_pat(&record_pat.clone().into())?; + let pat_id = self.pat_id(&record_pat.clone().into())?; self.infer.as_ref()?.variant_resolution_for_pat(pat_id) } @@ -264,13 +281,13 @@ impl SourceAnalyzer { pub fn resolve_path(&self, db: &impl HirDatabase, path: &ast::Path) -> Option { if let Some(path_expr) = path.syntax().parent().and_then(ast::PathExpr::cast) { - let expr_id = self.body_source_map.as_ref()?.node_expr(&path_expr.into())?; + let expr_id = self.expr_id(&path_expr.into())?; if let Some(assoc) = self.infer.as_ref()?.assoc_resolutions_for_expr(expr_id) { return Some(PathResolution::AssocItem(assoc)); } } if let Some(path_pat) = path.syntax().parent().and_then(ast::PathPat::cast) { - let pat_id = self.body_source_map.as_ref()?.node_pat(&path_pat.into())?; + let pat_id = self.pat_id(&path_pat.into())?; if let Some(assoc) = self.infer.as_ref()?.assoc_resolutions_for_pat(pat_id) { return Some(PathResolution::AssocItem(assoc)); } @@ -285,7 +302,7 @@ impl SourceAnalyzer { let name = name_ref.as_name(); let source_map = self.body_source_map.as_ref()?; let scopes = self.scopes.as_ref()?; - let scope = scope_for(scopes, source_map, name_ref.syntax()); + let scope = scope_for(scopes, source_map, self.file_id.into(), name_ref.syntax()); let ret = scopes .scope_chain(scope) .flat_map(|scope| scopes.entries(scope).iter()) @@ -418,11 +435,12 @@ impl SourceAnalyzer { fn scope_for( scopes: &ExprScopes, source_map: &BodySourceMap, + file_id: HirFileId, node: &SyntaxNode, ) -> Option { node.ancestors() .filter_map(ast::Expr::cast) - .filter_map(|it| source_map.node_expr(&it)) + .filter_map(|it| source_map.node_expr(Source { file_id, ast: &it })) .find_map(|it| scopes.scope_for(it)) } diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs index 65fefd912..75bba31c2 100644 --- a/crates/ra_hir_def/src/body.rs +++ b/crates/ra_hir_def/src/body.rs @@ -21,7 +21,6 @@ use crate::{ pub struct Expander { crate_def_map: Arc, - original_file_id: HirFileId, current_file_id: HirFileId, hygiene: Hygiene, module: ModuleId, @@ -31,13 +30,7 @@ impl Expander { pub fn new(db: &impl DefDatabase2, current_file_id: HirFileId, module: ModuleId) -> Expander { let crate_def_map = db.crate_def_map(module.krate); let hygiene = Hygiene::new(db, current_file_id); - Expander { - crate_def_map, - original_file_id: current_file_id, - current_file_id, - hygiene, - module, - } + Expander { crate_def_map, current_file_id, hygiene, module } } fn expand( @@ -82,11 +75,6 @@ impl Expander { std::mem::forget(mark); } - // FIXME: remove this. - fn is_in_expansion(&self) -> bool { - self.original_file_id != self.current_file_id - } - fn to_source(&self, ast: T) -> Source { Source { file_id: self.current_file_id, ast } } @@ -147,9 +135,9 @@ pub type PatSource = Source; /// this properly for macros. #[derive(Default, Debug, Eq, PartialEq)] pub struct BodySourceMap { - expr_map: FxHashMap, + expr_map: FxHashMap, expr_map_back: ArenaMap, - pat_map: FxHashMap, + pat_map: FxHashMap, pat_map_back: ArenaMap, field_map: FxHashMap<(ExprId, usize), AstPtr>, } @@ -202,16 +190,18 @@ impl BodySourceMap { self.expr_map_back.get(expr).copied() } - pub fn node_expr(&self, node: &ast::Expr) -> Option { - self.expr_map.get(&Either::A(AstPtr::new(node))).cloned() + pub fn node_expr(&self, node: Source<&ast::Expr>) -> Option { + let src = node.map(|it| Either::A(AstPtr::new(it))); + self.expr_map.get(&src).cloned() } pub fn pat_syntax(&self, pat: PatId) -> Option { self.pat_map_back.get(pat).copied() } - pub fn node_pat(&self, node: &ast::Pat) -> Option { - self.pat_map.get(&Either::A(AstPtr::new(node))).cloned() + pub fn node_pat(&self, node: Source<&ast::Pat>) -> Option { + let src = node.map(|it| Either::A(AstPtr::new(it))); + self.pat_map.get(&src).cloned() } pub fn field_syntax(&self, expr: ExprId, field: usize) -> AstPtr { diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs index c45500195..f6d79ddf0 100644 --- a/crates/ra_hir_def/src/body/lower.rs +++ b/crates/ra_hir_def/src/body/lower.rs @@ -94,10 +94,9 @@ where fn alloc_expr(&mut self, expr: Expr, ptr: AstPtr) -> ExprId { let ptr = Either::A(ptr); let id = self.body.exprs.alloc(expr); - if !self.expander.is_in_expansion() { - self.source_map.expr_map.insert(ptr, id); - } - self.source_map.expr_map_back.insert(id, self.expander.to_source(ptr)); + let src = self.expander.to_source(ptr); + self.source_map.expr_map.insert(src, id); + self.source_map.expr_map_back.insert(id, src); id } // desugared exprs don't have ptr, that's wrong and should be fixed @@ -108,18 +107,16 @@ where fn alloc_expr_field_shorthand(&mut self, expr: Expr, ptr: AstPtr) -> ExprId { let ptr = Either::B(ptr); let id = self.body.exprs.alloc(expr); - if !self.expander.is_in_expansion() { - self.source_map.expr_map.insert(ptr, id); - } - self.source_map.expr_map_back.insert(id, self.expander.to_source(ptr)); + let src = self.expander.to_source(ptr); + self.source_map.expr_map.insert(src, id); + self.source_map.expr_map_back.insert(id, src); id } fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId { let id = self.body.pats.alloc(pat); - if !self.expander.is_in_expansion() { - self.source_map.pat_map.insert(ptr, id); - } - self.source_map.pat_map_back.insert(id, self.expander.to_source(ptr)); + let src = self.expander.to_source(ptr); + self.source_map.pat_map.insert(src, id); + self.source_map.pat_map_back.insert(id, src); id } @@ -277,7 +274,8 @@ where ast::Expr::ParenExpr(e) => { let inner = self.collect_expr_opt(e.expr()); // make the paren expr point to the inner expression as well - self.source_map.expr_map.insert(Either::A(syntax_ptr), inner); + let src = self.expander.to_source(Either::A(syntax_ptr)); + self.source_map.expr_map.insert(src, inner); inner } ast::Expr::ReturnExpr(e) => { diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs index c6ffa2c6f..930789b0f 100644 --- a/crates/ra_hir_expand/src/lib.rs +++ b/crates/ra_hir_expand/src/lib.rs @@ -223,7 +223,7 @@ impl AstId { } } -#[derive(Debug, PartialEq, Eq, Clone, Copy)] +#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] pub struct Source { pub file_id: HirFileId, pub ast: T, @@ -233,6 +233,9 @@ impl Source { pub fn map U, U>(self, f: F) -> Source { Source { file_id: self.file_id, ast: f(self.ast) } } + pub fn as_ref(&self) -> Source<&T> { + Source { file_id: self.file_id, ast: &self.ast } + } pub fn file_syntax(&self, db: &impl db::AstDatabase) -> SyntaxNode { db.parse_or_expand(self.file_id).expect("source created from invalid file") } -- cgit v1.2.3 From 4efd345b09ca6e06fc0580d91a6c13f30b6b7f23 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 14 Nov 2019 11:33:18 +0300 Subject: Slightly better naming --- crates/ra_hir_def/src/body.rs | 15 ++++++--------- crates/ra_hir_def/src/body/lower.rs | 2 +- 2 files changed, 7 insertions(+), 10 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs index 75bba31c2..bff17fd62 100644 --- a/crates/ra_hir_def/src/body.rs +++ b/crates/ra_hir_def/src/body.rs @@ -33,7 +33,7 @@ impl Expander { Expander { crate_def_map, current_file_id, hygiene, module } } - fn expand( + fn enter_expand( &mut self, db: &impl DefDatabase2, macro_call: ast::MacroCall, @@ -50,7 +50,11 @@ impl Expander { if let Some(node) = db.parse_or_expand(file_id) { if let Some(expr) = ast::Expr::cast(node) { log::debug!("macro expansion {:#?}", expr.syntax()); - let mark = self.enter(db, file_id); + + let mark = Mark { file_id: self.current_file_id }; + self.hygiene = Hygiene::new(db, file_id); + self.current_file_id = file_id; + return Some((mark, expr)); } } @@ -62,13 +66,6 @@ impl Expander { None } - fn enter(&mut self, db: &impl DefDatabase2, file_id: HirFileId) -> Mark { - let mark = Mark { file_id: self.current_file_id }; - self.hygiene = Hygiene::new(db, file_id); - self.current_file_id = file_id; - mark - } - fn exit(&mut self, db: &impl DefDatabase2, mark: Mark) { self.hygiene = Hygiene::new(db, mark.file_id); self.current_file_id = mark.file_id; diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs index f6d79ddf0..a5bb60e85 100644 --- a/crates/ra_hir_def/src/body/lower.rs +++ b/crates/ra_hir_def/src/body/lower.rs @@ -430,7 +430,7 @@ where // FIXME implement HIR for these: ast::Expr::Label(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), ast::Expr::RangeExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), - ast::Expr::MacroCall(e) => match self.expander.expand(self.db, e) { + ast::Expr::MacroCall(e) => match self.expander.enter_expand(self.db, e) { Some((mark, expansion)) => { let id = self.collect_expr(expansion); self.expander.exit(self.db, mark); -- cgit v1.2.3 From f924ae3b86dc5e978071b6f8308b9f357415780b Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 14 Nov 2019 11:56:13 +0300 Subject: Move scopes to hir_def --- crates/ra_hir/src/db.rs | 2 +- crates/ra_hir/src/expr.rs | 204 ++++++++++++++++++++- crates/ra_hir/src/expr/scope.rs | 353 ------------------------------------ crates/ra_hir/src/resolve.rs | 5 +- crates/ra_hir/src/source_binder.rs | 6 +- crates/ra_hir_def/src/body.rs | 1 + crates/ra_hir_def/src/body/scope.rs | 157 ++++++++++++++++ 7 files changed, 360 insertions(+), 368 deletions(-) delete mode 100644 crates/ra_hir/src/expr/scope.rs create mode 100644 crates/ra_hir_def/src/body/scope.rs (limited to 'crates') diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index 9ac811232..14f6b5df4 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs @@ -85,7 +85,7 @@ pub trait DefDatabase: HirDebugDatabase + DefDatabase2 { #[salsa::query_group(HirDatabaseStorage)] #[salsa::requires(salsa::Database)] pub trait HirDatabase: DefDatabase + AstDatabase { - #[salsa::invoke(ExprScopes::expr_scopes_query)] + #[salsa::invoke(crate::expr::expr_scopes_query)] fn expr_scopes(&self, def: DefWithBody) -> Arc; #[salsa::invoke(crate::ty::infer_query)] diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs index d19f5d14c..f02104b2d 100644 --- a/crates/ra_hir/src/expr.rs +++ b/crates/ra_hir/src/expr.rs @@ -1,6 +1,5 @@ //! FIXME: write short doc here -pub(crate) mod scope; pub(crate) mod validation; use std::sync::Arc; @@ -9,10 +8,11 @@ use ra_syntax::{ast, AstPtr}; use crate::{db::HirDatabase, DefWithBody, HasSource, Resolver}; -pub use self::scope::ExprScopes; - pub use hir_def::{ - body::{Body, BodySourceMap, ExprPtr, ExprSource, PatPtr, PatSource}, + body::{ + scope::{ExprScopes, ScopeEntry, ScopeId}, + Body, BodySourceMap, ExprPtr, ExprSource, PatPtr, PatSource, + }, expr::{ ArithOp, Array, BinaryOp, BindingAnnotation, CmpOp, Expr, ExprId, Literal, LogicOp, MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, Statement, UnaryOp, @@ -49,6 +49,11 @@ pub(crate) fn body_query(db: &impl HirDatabase, def: DefWithBody) -> Arc { db.body_with_source_map(def).0 } +pub(crate) fn expr_scopes_query(db: &impl HirDatabase, def: DefWithBody) -> Arc { + let body = db.body(def); + Arc::new(ExprScopes::new(&*body)) +} + // needs arbitrary_self_types to be a method... or maybe move to the def? pub(crate) fn resolver_for_expr( db: &impl HirDatabase, @@ -62,7 +67,7 @@ pub(crate) fn resolver_for_expr( pub(crate) fn resolver_for_scope( db: &impl HirDatabase, owner: DefWithBody, - scope_id: Option, + scope_id: Option, ) -> Resolver { let mut r = owner.resolver(db); let scopes = db.expr_scopes(owner); @@ -72,3 +77,192 @@ pub(crate) fn resolver_for_scope( } r } + +#[cfg(test)] +mod tests { + use hir_expand::Source; + use ra_db::{fixture::WithFixture, SourceDatabase}; + use ra_syntax::{algo::find_node_at_offset, ast, AstNode}; + use test_utils::{assert_eq_text, extract_offset}; + + use crate::{source_binder::SourceAnalyzer, test_db::TestDB}; + + fn do_check(code: &str, expected: &[&str]) { + let (off, code) = extract_offset(code); + let code = { + let mut buf = String::new(); + let off = u32::from(off) as usize; + buf.push_str(&code[..off]); + buf.push_str("marker"); + buf.push_str(&code[off..]); + buf + }; + + let (db, file_id) = TestDB::with_single_file(&code); + + let file = db.parse(file_id).ok().unwrap(); + let marker: ast::PathExpr = find_node_at_offset(file.syntax(), off).unwrap(); + let analyzer = SourceAnalyzer::new(&db, file_id, marker.syntax(), None); + + let scopes = analyzer.scopes(); + let expr_id = analyzer + .body_source_map() + .node_expr(Source { file_id: file_id.into(), ast: &marker.into() }) + .unwrap(); + let scope = scopes.scope_for(expr_id); + + let actual = scopes + .scope_chain(scope) + .flat_map(|scope| scopes.entries(scope)) + .map(|it| it.name().to_string()) + .collect::>() + .join("\n"); + let expected = expected.join("\n"); + assert_eq_text!(&expected, &actual); + } + + #[test] + fn test_lambda_scope() { + do_check( + r" + fn quux(foo: i32) { + let f = |bar, baz: i32| { + <|> + }; + }", + &["bar", "baz", "foo"], + ); + } + + #[test] + fn test_call_scope() { + do_check( + r" + fn quux() { + f(|x| <|> ); + }", + &["x"], + ); + } + + #[test] + fn test_method_call_scope() { + do_check( + r" + fn quux() { + z.f(|x| <|> ); + }", + &["x"], + ); + } + + #[test] + fn test_loop_scope() { + do_check( + r" + fn quux() { + loop { + let x = (); + <|> + }; + }", + &["x"], + ); + } + + #[test] + fn test_match() { + do_check( + r" + fn quux() { + match () { + Some(x) => { + <|> + } + }; + }", + &["x"], + ); + } + + #[test] + fn test_shadow_variable() { + do_check( + r" + fn foo(x: String) { + let x : &str = &x<|>; + }", + &["x"], + ); + } + + fn do_check_local_name(code: &str, expected_offset: u32) { + let (off, code) = extract_offset(code); + + let (db, file_id) = TestDB::with_single_file(&code); + let file = db.parse(file_id).ok().unwrap(); + let expected_name = find_node_at_offset::(file.syntax(), expected_offset.into()) + .expect("failed to find a name at the target offset"); + let name_ref: ast::NameRef = find_node_at_offset(file.syntax(), off).unwrap(); + let analyzer = SourceAnalyzer::new(&db, file_id, name_ref.syntax(), None); + + let local_name_entry = analyzer.resolve_local_name(&name_ref).unwrap(); + let local_name = + local_name_entry.ptr().either(|it| it.syntax_node_ptr(), |it| it.syntax_node_ptr()); + assert_eq!(local_name.range(), expected_name.syntax().text_range()); + } + + #[test] + fn test_resolve_local_name() { + do_check_local_name( + r#" + fn foo(x: i32, y: u32) { + { + let z = x * 2; + } + { + let t = x<|> * 3; + } + }"#, + 21, + ); + } + + #[test] + fn test_resolve_local_name_declaration() { + do_check_local_name( + r#" + fn foo(x: String) { + let x : &str = &x<|>; + }"#, + 21, + ); + } + + #[test] + fn test_resolve_local_name_shadow() { + do_check_local_name( + r" + fn foo(x: String) { + let x : &str = &x; + x<|> + } + ", + 53, + ); + } + + #[test] + fn ref_patterns_contribute_bindings() { + do_check_local_name( + r" + fn foo() { + if let Some(&from) = bar() { + from<|>; + } + } + ", + 53, + ); + } +} diff --git a/crates/ra_hir/src/expr/scope.rs b/crates/ra_hir/src/expr/scope.rs deleted file mode 100644 index afba66069..000000000 --- a/crates/ra_hir/src/expr/scope.rs +++ /dev/null @@ -1,353 +0,0 @@ -//! FIXME: write short doc here - -use std::sync::Arc; - -use ra_arena::{impl_arena_id, Arena, RawId}; -use rustc_hash::FxHashMap; - -use crate::{ - db::HirDatabase, - expr::{Body, Expr, ExprId, Pat, PatId, Statement}, - DefWithBody, Name, -}; - -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct ScopeId(RawId); -impl_arena_id!(ScopeId); - -#[derive(Debug, PartialEq, Eq)] -pub struct ExprScopes { - scopes: Arena, - scope_by_expr: FxHashMap, -} - -#[derive(Debug, PartialEq, Eq)] -pub(crate) struct ScopeEntry { - name: Name, - pat: PatId, -} - -impl ScopeEntry { - pub(crate) fn name(&self) -> &Name { - &self.name - } - - pub(crate) fn pat(&self) -> PatId { - self.pat - } -} - -#[derive(Debug, PartialEq, Eq)] -pub(crate) struct ScopeData { - parent: Option, - entries: Vec, -} - -impl ExprScopes { - pub(crate) fn expr_scopes_query(db: &impl HirDatabase, def: DefWithBody) -> Arc { - let body = db.body(def); - let res = ExprScopes::new(&*body); - Arc::new(res) - } - - fn new(body: &Body) -> ExprScopes { - let mut scopes = - ExprScopes { scopes: Arena::default(), scope_by_expr: FxHashMap::default() }; - let root = scopes.root_scope(); - scopes.add_params_bindings(body, root, body.params()); - compute_expr_scopes(body.body_expr(), body, &mut scopes, root); - scopes - } - - pub(crate) fn entries(&self, scope: ScopeId) -> &[ScopeEntry] { - &self.scopes[scope].entries - } - - pub(crate) fn scope_chain(&self, scope: Option) -> impl Iterator + '_ { - std::iter::successors(scope, move |&scope| self.scopes[scope].parent) - } - - pub(crate) fn scope_for(&self, expr: ExprId) -> Option { - self.scope_by_expr.get(&expr).copied() - } - - pub(crate) fn scope_by_expr(&self) -> &FxHashMap { - &self.scope_by_expr - } - - fn root_scope(&mut self) -> ScopeId { - self.scopes.alloc(ScopeData { parent: None, entries: vec![] }) - } - - fn new_scope(&mut self, parent: ScopeId) -> ScopeId { - self.scopes.alloc(ScopeData { parent: Some(parent), entries: vec![] }) - } - - fn add_bindings(&mut self, body: &Body, scope: ScopeId, pat: PatId) { - match &body[pat] { - Pat::Bind { name, .. } => { - // bind can have a sub pattern, but it's actually not allowed - // to bind to things in there - let entry = ScopeEntry { name: name.clone(), pat }; - self.scopes[scope].entries.push(entry) - } - p => p.walk_child_pats(|pat| self.add_bindings(body, scope, pat)), - } - } - - fn add_params_bindings(&mut self, body: &Body, scope: ScopeId, params: &[PatId]) { - params.iter().for_each(|pat| self.add_bindings(body, scope, *pat)); - } - - fn set_scope(&mut self, node: ExprId, scope: ScopeId) { - self.scope_by_expr.insert(node, scope); - } -} - -fn compute_block_scopes( - statements: &[Statement], - tail: Option, - body: &Body, - scopes: &mut ExprScopes, - mut scope: ScopeId, -) { - for stmt in statements { - match stmt { - Statement::Let { pat, initializer, .. } => { - if let Some(expr) = initializer { - scopes.set_scope(*expr, scope); - compute_expr_scopes(*expr, body, scopes, scope); - } - scope = scopes.new_scope(scope); - scopes.add_bindings(body, scope, *pat); - } - Statement::Expr(expr) => { - scopes.set_scope(*expr, scope); - compute_expr_scopes(*expr, body, scopes, scope); - } - } - } - if let Some(expr) = tail { - compute_expr_scopes(expr, body, scopes, scope); - } -} - -fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope: ScopeId) { - scopes.set_scope(expr, scope); - match &body[expr] { - Expr::Block { statements, tail } => { - compute_block_scopes(&statements, *tail, body, scopes, scope); - } - Expr::For { iterable, pat, body: body_expr } => { - compute_expr_scopes(*iterable, body, scopes, scope); - let scope = scopes.new_scope(scope); - scopes.add_bindings(body, scope, *pat); - compute_expr_scopes(*body_expr, body, scopes, scope); - } - Expr::Lambda { args, body: body_expr, .. } => { - let scope = scopes.new_scope(scope); - scopes.add_params_bindings(body, scope, &args); - compute_expr_scopes(*body_expr, body, scopes, scope); - } - Expr::Match { expr, arms } => { - compute_expr_scopes(*expr, body, scopes, scope); - for arm in arms { - let scope = scopes.new_scope(scope); - for pat in &arm.pats { - scopes.add_bindings(body, scope, *pat); - } - scopes.set_scope(arm.expr, scope); - compute_expr_scopes(arm.expr, body, scopes, scope); - } - } - e => e.walk_child_exprs(|e| compute_expr_scopes(e, body, scopes, scope)), - }; -} - -#[cfg(test)] -mod tests { - use hir_expand::Source; - use ra_db::{fixture::WithFixture, SourceDatabase}; - use ra_syntax::{algo::find_node_at_offset, ast, AstNode}; - use test_utils::{assert_eq_text, extract_offset}; - - use crate::{source_binder::SourceAnalyzer, test_db::TestDB}; - - fn do_check(code: &str, expected: &[&str]) { - let (off, code) = extract_offset(code); - let code = { - let mut buf = String::new(); - let off = u32::from(off) as usize; - buf.push_str(&code[..off]); - buf.push_str("marker"); - buf.push_str(&code[off..]); - buf - }; - - let (db, file_id) = TestDB::with_single_file(&code); - let file = db.parse(file_id).ok().unwrap(); - let marker: ast::PathExpr = find_node_at_offset(file.syntax(), off).unwrap(); - let analyzer = SourceAnalyzer::new(&db, file_id, marker.syntax(), None); - - let scopes = analyzer.scopes(); - let expr_id = analyzer - .body_source_map() - .node_expr(Source { file_id: file_id.into(), ast: &marker.into() }) - .unwrap(); - let scope = scopes.scope_for(expr_id); - - let actual = scopes - .scope_chain(scope) - .flat_map(|scope| scopes.entries(scope)) - .map(|it| it.name().to_string()) - .collect::>() - .join("\n"); - let expected = expected.join("\n"); - assert_eq_text!(&expected, &actual); - } - - #[test] - fn test_lambda_scope() { - do_check( - r" - fn quux(foo: i32) { - let f = |bar, baz: i32| { - <|> - }; - }", - &["bar", "baz", "foo"], - ); - } - - #[test] - fn test_call_scope() { - do_check( - r" - fn quux() { - f(|x| <|> ); - }", - &["x"], - ); - } - - #[test] - fn test_method_call_scope() { - do_check( - r" - fn quux() { - z.f(|x| <|> ); - }", - &["x"], - ); - } - - #[test] - fn test_loop_scope() { - do_check( - r" - fn quux() { - loop { - let x = (); - <|> - }; - }", - &["x"], - ); - } - - #[test] - fn test_match() { - do_check( - r" - fn quux() { - match () { - Some(x) => { - <|> - } - }; - }", - &["x"], - ); - } - - #[test] - fn test_shadow_variable() { - do_check( - r" - fn foo(x: String) { - let x : &str = &x<|>; - }", - &["x"], - ); - } - - fn do_check_local_name(code: &str, expected_offset: u32) { - let (off, code) = extract_offset(code); - - let (db, file_id) = TestDB::with_single_file(&code); - let file = db.parse(file_id).ok().unwrap(); - let expected_name = find_node_at_offset::(file.syntax(), expected_offset.into()) - .expect("failed to find a name at the target offset"); - let name_ref: ast::NameRef = find_node_at_offset(file.syntax(), off).unwrap(); - let analyzer = SourceAnalyzer::new(&db, file_id, name_ref.syntax(), None); - - let local_name_entry = analyzer.resolve_local_name(&name_ref).unwrap(); - let local_name = - local_name_entry.ptr().either(|it| it.syntax_node_ptr(), |it| it.syntax_node_ptr()); - assert_eq!(local_name.range(), expected_name.syntax().text_range()); - } - - #[test] - fn test_resolve_local_name() { - do_check_local_name( - r#" - fn foo(x: i32, y: u32) { - { - let z = x * 2; - } - { - let t = x<|> * 3; - } - }"#, - 21, - ); - } - - #[test] - fn test_resolve_local_name_declaration() { - do_check_local_name( - r#" - fn foo(x: String) { - let x : &str = &x<|>; - }"#, - 21, - ); - } - - #[test] - fn test_resolve_local_name_shadow() { - do_check_local_name( - r" - fn foo(x: String) { - let x : &str = &x; - x<|> - } - ", - 53, - ); - } - - #[test] - fn ref_patterns_contribute_bindings() { - do_check_local_name( - r" - fn foo() { - if let Some(&from) = bar() { - from<|>; - } - } - ", - 53, - ); - } -} diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs index b932b0c8c..2f3e12eb8 100644 --- a/crates/ra_hir/src/resolve.rs +++ b/crates/ra_hir/src/resolve.rs @@ -13,10 +13,7 @@ use rustc_hash::FxHashSet; use crate::{ code_model::Crate, db::{DefDatabase, HirDatabase}, - expr::{ - scope::{ExprScopes, ScopeId}, - PatId, - }, + expr::{ExprScopes, PatId, ScopeId}, generics::GenericParams, impl_block::ImplBlock, Adt, Const, Enum, EnumVariant, Function, MacroDef, ModuleDef, PerNs, Static, Struct, Trait, diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index 88eed1137..e337a3d4a 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs @@ -23,11 +23,7 @@ use rustc_hash::FxHashSet; use crate::{ db::HirDatabase, - expr::{ - self, - scope::{ExprScopes, ScopeId}, - BodySourceMap, - }, + expr::{self, BodySourceMap, ExprScopes, ScopeId}, ids::LocationCtx, resolve::{ScopeDef, TypeNs, ValueNs}, ty::method_resolution::{self, implements_trait}, diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs index bff17fd62..c3e9d0c23 100644 --- a/crates/ra_hir_def/src/body.rs +++ b/crates/ra_hir_def/src/body.rs @@ -1,5 +1,6 @@ //! FIXME: write short doc here mod lower; +pub mod scope; use std::{ops::Index, sync::Arc}; diff --git a/crates/ra_hir_def/src/body/scope.rs b/crates/ra_hir_def/src/body/scope.rs new file mode 100644 index 000000000..dd8d06d11 --- /dev/null +++ b/crates/ra_hir_def/src/body/scope.rs @@ -0,0 +1,157 @@ +//! FIXME: write short doc here + +use hir_expand::name::Name; +use ra_arena::{impl_arena_id, Arena, RawId}; +use rustc_hash::FxHashMap; + +use crate::{ + body::Body, + expr::{Expr, ExprId, Pat, PatId, Statement}, +}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct ScopeId(RawId); +impl_arena_id!(ScopeId); + +#[derive(Debug, PartialEq, Eq)] +pub struct ExprScopes { + scopes: Arena, + scope_by_expr: FxHashMap, +} + +#[derive(Debug, PartialEq, Eq)] +pub struct ScopeEntry { + name: Name, + pat: PatId, +} + +impl ScopeEntry { + pub fn name(&self) -> &Name { + &self.name + } + + pub fn pat(&self) -> PatId { + self.pat + } +} + +#[derive(Debug, PartialEq, Eq)] +pub struct ScopeData { + parent: Option, + entries: Vec, +} + +impl ExprScopes { + pub fn new(body: &Body) -> ExprScopes { + let mut scopes = + ExprScopes { scopes: Arena::default(), scope_by_expr: FxHashMap::default() }; + let root = scopes.root_scope(); + scopes.add_params_bindings(body, root, body.params()); + compute_expr_scopes(body.body_expr(), body, &mut scopes, root); + scopes + } + + pub fn entries(&self, scope: ScopeId) -> &[ScopeEntry] { + &self.scopes[scope].entries + } + + pub fn scope_chain(&self, scope: Option) -> impl Iterator + '_ { + std::iter::successors(scope, move |&scope| self.scopes[scope].parent) + } + + pub fn scope_for(&self, expr: ExprId) -> Option { + self.scope_by_expr.get(&expr).copied() + } + + pub fn scope_by_expr(&self) -> &FxHashMap { + &self.scope_by_expr + } + + fn root_scope(&mut self) -> ScopeId { + self.scopes.alloc(ScopeData { parent: None, entries: vec![] }) + } + + fn new_scope(&mut self, parent: ScopeId) -> ScopeId { + self.scopes.alloc(ScopeData { parent: Some(parent), entries: vec![] }) + } + + fn add_bindings(&mut self, body: &Body, scope: ScopeId, pat: PatId) { + match &body[pat] { + Pat::Bind { name, .. } => { + // bind can have a sub pattern, but it's actually not allowed + // to bind to things in there + let entry = ScopeEntry { name: name.clone(), pat }; + self.scopes[scope].entries.push(entry) + } + p => p.walk_child_pats(|pat| self.add_bindings(body, scope, pat)), + } + } + + fn add_params_bindings(&mut self, body: &Body, scope: ScopeId, params: &[PatId]) { + params.iter().for_each(|pat| self.add_bindings(body, scope, *pat)); + } + + fn set_scope(&mut self, node: ExprId, scope: ScopeId) { + self.scope_by_expr.insert(node, scope); + } +} + +fn compute_block_scopes( + statements: &[Statement], + tail: Option, + body: &Body, + scopes: &mut ExprScopes, + mut scope: ScopeId, +) { + for stmt in statements { + match stmt { + Statement::Let { pat, initializer, .. } => { + if let Some(expr) = initializer { + scopes.set_scope(*expr, scope); + compute_expr_scopes(*expr, body, scopes, scope); + } + scope = scopes.new_scope(scope); + scopes.add_bindings(body, scope, *pat); + } + Statement::Expr(expr) => { + scopes.set_scope(*expr, scope); + compute_expr_scopes(*expr, body, scopes, scope); + } + } + } + if let Some(expr) = tail { + compute_expr_scopes(expr, body, scopes, scope); + } +} + +fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope: ScopeId) { + scopes.set_scope(expr, scope); + match &body[expr] { + Expr::Block { statements, tail } => { + compute_block_scopes(&statements, *tail, body, scopes, scope); + } + Expr::For { iterable, pat, body: body_expr } => { + compute_expr_scopes(*iterable, body, scopes, scope); + let scope = scopes.new_scope(scope); + scopes.add_bindings(body, scope, *pat); + compute_expr_scopes(*body_expr, body, scopes, scope); + } + Expr::Lambda { args, body: body_expr, .. } => { + let scope = scopes.new_scope(scope); + scopes.add_params_bindings(body, scope, &args); + compute_expr_scopes(*body_expr, body, scopes, scope); + } + Expr::Match { expr, arms } => { + compute_expr_scopes(*expr, body, scopes, scope); + for arm in arms { + let scope = scopes.new_scope(scope); + for pat in &arm.pats { + scopes.add_bindings(body, scope, *pat); + } + scopes.set_scope(arm.expr, scope); + compute_expr_scopes(arm.expr, body, scopes, scope); + } + } + e => e.walk_child_exprs(|e| compute_expr_scopes(e, body, scopes, scope)), + }; +} -- cgit v1.2.3 From ef02296b9fe2c2e42b9390a3a14ee860f08fd02c Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 14 Nov 2019 17:36:27 +0300 Subject: Simplify parsing --- crates/ra_parser/src/grammar/expressions/atom.rs | 34 ++++++++++++------------ crates/ra_parser/src/token_set.rs | 4 +-- 2 files changed, 19 insertions(+), 19 deletions(-) (limited to 'crates') diff --git a/crates/ra_parser/src/grammar/expressions/atom.rs b/crates/ra_parser/src/grammar/expressions/atom.rs index 4952bd189..f06191963 100644 --- a/crates/ra_parser/src/grammar/expressions/atom.rs +++ b/crates/ra_parser/src/grammar/expressions/atom.rs @@ -40,24 +40,24 @@ pub(crate) fn literal(p: &mut Parser) -> Option { // E.g. for after the break in `if break {}`, this should not match pub(super) const ATOM_EXPR_FIRST: TokenSet = LITERAL_FIRST.union(paths::PATH_FIRST).union(token_set![ - L_PAREN, - L_CURLY, - L_BRACK, - PIPE, - MOVE_KW, - BOX_KW, - IF_KW, - WHILE_KW, - MATCH_KW, - UNSAFE_KW, - RETURN_KW, - BREAK_KW, - CONTINUE_KW, + T!['('], + T!['{'], + T!['['], + T![|], + T![move], + T![box], + T![if], + T![while], + T![match], + T![unsafe], + T![return], + T![break], + T![continue], + T![async], + T![try], + T![loop], + T![for], LIFETIME, - ASYNC_KW, - TRY_KW, - LOOP_KW, - FOR_KW, ]); const EXPR_RECOVERY_SET: TokenSet = token_set![LET_KW]; diff --git a/crates/ra_parser/src/token_set.rs b/crates/ra_parser/src/token_set.rs index 6dc061889..2a6952c01 100644 --- a/crates/ra_parser/src/token_set.rs +++ b/crates/ra_parser/src/token_set.rs @@ -30,8 +30,8 @@ const fn mask(kind: SyntaxKind) -> u128 { #[macro_export] macro_rules! token_set { - ($($t:ident),*) => { TokenSet::empty()$(.union(TokenSet::singleton($t)))* }; - ($($t:ident),* ,) => { token_set!($($t),*) }; + ($($t:expr),*) => { TokenSet::empty()$(.union(TokenSet::singleton($t)))* }; + ($($t:expr),* ,) => { token_set!($($t),*) }; } #[test] -- cgit v1.2.3 From 1583ab1558022d0fdbbc10d3a440a2d3daa4a840 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 14 Nov 2019 17:37:22 +0300 Subject: Move body queries to hir_def --- crates/ra_hir/src/code_model.rs | 28 +++++++++++++++-------- crates/ra_hir/src/db.rs | 19 +++++----------- crates/ra_hir/src/expr.rs | 43 ++++-------------------------------- crates/ra_hir/src/from_id.rs | 14 ++++++++++-- crates/ra_hir/src/from_source.rs | 4 ++-- crates/ra_hir/src/source_binder.rs | 2 +- crates/ra_hir/src/ty/infer.rs | 5 +++-- crates/ra_hir/src/ty/traits/chalk.rs | 4 ++-- crates/ra_hir_def/src/body.rs | 34 ++++++++++++++++++++++++++-- crates/ra_hir_def/src/body/scope.rs | 10 ++++++++- crates/ra_hir_def/src/db.rs | 12 +++++++++- crates/ra_hir_def/src/lib.rs | 10 +++++++++ 12 files changed, 110 insertions(+), 75 deletions(-) (limited to 'crates') diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index 2fd4ccb10..962d5a8c1 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs @@ -8,6 +8,7 @@ use std::sync::Arc; use hir_def::{ adt::VariantData, + body::scope::ExprScopes, builtin_type::BuiltinType, type_ref::{Mutability, TypeRef}, CrateModuleId, LocalEnumVariantId, LocalStructFieldId, ModuleId, UnionId, @@ -539,6 +540,7 @@ pub trait HasBody: Copy { fn infer(self, db: &impl HirDatabase) -> Arc; fn body(self, db: &impl HirDatabase) -> Arc; fn body_source_map(self, db: &impl HirDatabase) -> Arc; + fn expr_scopes(self, db: &impl HirDatabase) -> Arc; } impl HasBody for T @@ -550,11 +552,15 @@ where } fn body(self, db: &impl HirDatabase) -> Arc { - db.body(self.into()) + self.into().body(db) } fn body_source_map(self, db: &impl HirDatabase) -> Arc { - db.body_with_source_map(self.into()).1 + self.into().body_source_map(db) + } + + fn expr_scopes(self, db: &impl HirDatabase) -> Arc { + self.into().expr_scopes(db) } } @@ -564,11 +570,15 @@ impl HasBody for DefWithBody { } fn body(self, db: &impl HirDatabase) -> Arc { - db.body(self) + db.body(self.into()) } fn body_source_map(self, db: &impl HirDatabase) -> Arc { - db.body_with_source_map(self).1 + db.body_with_source_map(self.into()).1 + } + + fn expr_scopes(self, db: &impl HirDatabase) -> Arc { + db.expr_scopes(self.into()) } } @@ -662,11 +672,11 @@ impl Function { } pub(crate) fn body_source_map(self, db: &impl HirDatabase) -> Arc { - db.body_with_source_map(self.into()).1 + db.body_with_source_map(self.id.into()).1 } pub fn body(self, db: &impl HirDatabase) -> Arc { - db.body(self.into()) + db.body(self.id.into()) } pub fn ty(self, db: &impl HirDatabase) -> Ty { @@ -1079,7 +1089,7 @@ pub struct Local { impl Local { pub fn name(self, db: &impl HirDatabase) -> Option { - let body = db.body(self.parent); + let body = self.parent.body(db); match &body[self.pat_id] { Pat::Bind { name, .. } => Some(name.clone()), _ => None, @@ -1091,7 +1101,7 @@ impl Local { } pub fn is_mut(self, db: &impl HirDatabase) -> bool { - let body = db.body(self.parent); + let body = self.parent.body(db); match &body[self.pat_id] { Pat::Bind { mode, .. } => match mode { BindingAnnotation::Mutable | BindingAnnotation::RefMut => true, @@ -1115,7 +1125,7 @@ impl Local { } pub fn source(self, db: &impl HirDatabase) -> Source> { - let (_body, source_map) = db.body_with_source_map(self.parent); + let source_map = self.parent.body_source_map(db); let src = source_map.pat_syntax(self.pat_id).unwrap(); // Hmm... let root = src.file_syntax(db); src.map(|ast| ast.map(|it| it.cast().unwrap().to_node(&root), |it| it.to_node(&root))) diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index 14f6b5df4..c60029c01 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs @@ -8,7 +8,6 @@ use ra_syntax::SmolStr; use crate::{ debug::HirDebugDatabase, - expr::{Body, BodySourceMap}, generics::{GenericDef, GenericParams}, ids, impl_block::{ImplBlock, ImplSourceMap, ModuleImplBlocks}, @@ -19,13 +18,14 @@ use crate::{ InferenceResult, Namespace, Substs, Ty, TypableDef, TypeCtor, }, type_alias::TypeAliasData, - Const, ConstData, Crate, DefWithBody, ExprScopes, FnData, Function, Module, Static, - StructField, Trait, TypeAlias, + Const, ConstData, Crate, DefWithBody, FnData, Function, Module, Static, StructField, Trait, + TypeAlias, }; pub use hir_def::db::{ - CrateDefMapQuery, DefDatabase2, DefDatabase2Storage, EnumDataQuery, InternDatabase, - InternDatabaseStorage, RawItemsQuery, RawItemsWithSourceMapQuery, StructDataQuery, + BodyQuery, BodyWithSourceMapQuery, CrateDefMapQuery, DefDatabase2, DefDatabase2Storage, + EnumDataQuery, ExprScopesQuery, InternDatabase, InternDatabaseStorage, RawItemsQuery, + RawItemsWithSourceMapQuery, StructDataQuery, }; pub use hir_expand::db::{ AstDatabase, AstDatabaseStorage, AstIdMapQuery, MacroArgQuery, MacroDefQuery, MacroExpandQuery, @@ -85,9 +85,6 @@ pub trait DefDatabase: HirDebugDatabase + DefDatabase2 { #[salsa::query_group(HirDatabaseStorage)] #[salsa::requires(salsa::Database)] pub trait HirDatabase: DefDatabase + AstDatabase { - #[salsa::invoke(crate::expr::expr_scopes_query)] - fn expr_scopes(&self, def: DefWithBody) -> Arc; - #[salsa::invoke(crate::ty::infer_query)] fn infer(&self, def: DefWithBody) -> Arc; @@ -113,12 +110,6 @@ pub trait HirDatabase: DefDatabase + AstDatabase { #[salsa::invoke(crate::ty::generic_defaults_query)] fn generic_defaults(&self, def: GenericDef) -> Substs; - #[salsa::invoke(crate::expr::body_with_source_map_query)] - fn body_with_source_map(&self, def: DefWithBody) -> (Arc, Arc); - - #[salsa::invoke(crate::expr::body_query)] - fn body(&self, def: DefWithBody) -> Arc; - #[salsa::invoke(crate::ty::method_resolution::CrateImplBlocks::impls_in_crate_query)] fn impls_in_crate(&self, krate: Crate) -> Arc; diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs index f02104b2d..9262325f2 100644 --- a/crates/ra_hir/src/expr.rs +++ b/crates/ra_hir/src/expr.rs @@ -4,9 +4,9 @@ pub(crate) mod validation; use std::sync::Arc; -use ra_syntax::{ast, AstPtr}; +use ra_syntax::AstPtr; -use crate::{db::HirDatabase, DefWithBody, HasSource, Resolver}; +use crate::{db::HirDatabase, DefWithBody, HasBody, Resolver}; pub use hir_def::{ body::{ @@ -19,48 +19,13 @@ pub use hir_def::{ }, }; -pub(crate) fn body_with_source_map_query( - db: &impl HirDatabase, - def: DefWithBody, -) -> (Arc, Arc) { - let mut params = None; - - let (file_id, body) = match def { - DefWithBody::Function(f) => { - let src = f.source(db); - params = src.ast.param_list(); - (src.file_id, src.ast.body().map(ast::Expr::from)) - } - DefWithBody::Const(c) => { - let src = c.source(db); - (src.file_id, src.ast.body()) - } - DefWithBody::Static(s) => { - let src = s.source(db); - (src.file_id, src.ast.body()) - } - }; - let expander = hir_def::body::Expander::new(db, file_id, def.module(db).id); - let (body, source_map) = Body::new(db, expander, params, body); - (Arc::new(body), Arc::new(source_map)) -} - -pub(crate) fn body_query(db: &impl HirDatabase, def: DefWithBody) -> Arc { - db.body_with_source_map(def).0 -} - -pub(crate) fn expr_scopes_query(db: &impl HirDatabase, def: DefWithBody) -> Arc { - let body = db.body(def); - Arc::new(ExprScopes::new(&*body)) -} - // needs arbitrary_self_types to be a method... or maybe move to the def? pub(crate) fn resolver_for_expr( db: &impl HirDatabase, owner: DefWithBody, expr_id: ExprId, ) -> Resolver { - let scopes = db.expr_scopes(owner); + let scopes = owner.expr_scopes(db); resolver_for_scope(db, owner, scopes.scope_for(expr_id)) } @@ -70,7 +35,7 @@ pub(crate) fn resolver_for_scope( scope_id: Option, ) -> Resolver { let mut r = owner.resolver(db); - let scopes = db.expr_scopes(owner); + let scopes = owner.expr_scopes(db); let scope_chain = scopes.scope_chain(scope_id).collect::>(); for scope in scope_chain.into_iter().rev() { r = r.push_expr_scope(Arc::clone(&scopes), scope); diff --git a/crates/ra_hir/src/from_id.rs b/crates/ra_hir/src/from_id.rs index 089dbc908..9633ef586 100644 --- a/crates/ra_hir/src/from_id.rs +++ b/crates/ra_hir/src/from_id.rs @@ -3,9 +3,9 @@ //! It's unclear if we need this long-term, but it's definitelly useful while we //! are splitting the hir. -use hir_def::{AdtId, EnumVariantId, ModuleDefId}; +use hir_def::{AdtId, DefWithBodyId, EnumVariantId, ModuleDefId}; -use crate::{Adt, EnumVariant, ModuleDef}; +use crate::{Adt, DefWithBody, EnumVariant, ModuleDef}; macro_rules! from_id { ($(($id:path, $ty:path)),*) => {$( @@ -61,3 +61,13 @@ impl From for ModuleDef { } } } + +impl From for DefWithBodyId { + fn from(def: DefWithBody) -> Self { + match def { + DefWithBody::Function(it) => DefWithBodyId::FunctionId(it.id), + DefWithBody::Static(it) => DefWithBodyId::StaticId(it.id), + DefWithBody::Const(it) => DefWithBodyId::ConstId(it.id), + } + } +} diff --git a/crates/ra_hir/src/from_source.rs b/crates/ra_hir/src/from_source.rs index 4b561c63d..9793af858 100644 --- a/crates/ra_hir/src/from_source.rs +++ b/crates/ra_hir/src/from_source.rs @@ -10,7 +10,7 @@ use ra_syntax::{ use crate::{ db::{AstDatabase, DefDatabase, HirDatabase}, ids::{AstItemDef, LocationCtx}, - AstId, Const, Crate, DefWithBody, Enum, EnumVariant, FieldSource, Function, HasSource, + AstId, Const, Crate, DefWithBody, Enum, EnumVariant, FieldSource, Function, HasBody, HasSource, ImplBlock, Local, Module, ModuleSource, Source, Static, Struct, StructField, Trait, TypeAlias, Union, VariantDef, }; @@ -144,7 +144,7 @@ impl Local { }; Some(res) })?; - let (_body, source_map) = db.body_with_source_map(parent); + let source_map = parent.body_source_map(db); let src = src.map(ast::Pat::from); let pat_id = source_map.node_pat(src.as_ref())?; Some(Local { parent, pat_id }) diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index e337a3d4a..ca40e3b54 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs @@ -146,7 +146,7 @@ impl SourceAnalyzer { let def_with_body = def_with_body_from_child_node(db, file_id, node); if let Some(def) = def_with_body { let source_map = def.body_source_map(db); - let scopes = db.expr_scopes(def); + let scopes = def.expr_scopes(db); let scope = match offset { None => scope_for(&scopes, &source_map, file_id.into(), &node), Some(offset) => scope_for_offset(&scopes, &source_map, file_id.into(), offset), diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index c09260864..c35378cc4 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs @@ -43,7 +43,8 @@ use crate::{ expr::{BindingAnnotation, Body, ExprId, PatId}, resolve::{Resolver, TypeNs}, ty::infer::diagnostics::InferenceDiagnostic, - Adt, AssocItem, ConstData, DefWithBody, FloatTy, FnData, Function, IntTy, Path, StructField, + Adt, AssocItem, ConstData, DefWithBody, FloatTy, FnData, Function, HasBody, IntTy, Path, + StructField, }; macro_rules! ty_app { @@ -214,7 +215,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { coerce_unsized_map: Self::init_coerce_unsized_map(db, &resolver), db, owner, - body: db.body(owner), + body: owner.body(db), resolver, } } diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs index de322dd52..75351c17d 100644 --- a/crates/ra_hir/src/ty/traits/chalk.rs +++ b/crates/ra_hir/src/ty/traits/chalk.rs @@ -22,7 +22,7 @@ use crate::{ ApplicationTy, GenericPredicate, Namespace, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, TypeWalk, }, - AssocItem, Crate, ImplBlock, Trait, TypeAlias, + AssocItem, Crate, HasBody, ImplBlock, Trait, TypeAlias, }; /// This represents a trait whose name we could not resolve. @@ -714,7 +714,7 @@ fn closure_fn_trait_impl_datum( let fn_once_trait = get_fn_trait(db, krate, super::FnTrait::FnOnce)?; let trait_ = get_fn_trait(db, krate, data.fn_trait)?; // get corresponding fn trait - let num_args: u16 = match &db.body(data.def)[data.expr] { + let num_args: u16 = match &data.def.body(db)[data.expr] { crate::expr::Expr::Lambda { args, .. } => args.len() as u16, _ => { log::warn!("closure for closure type {:?} not found", data); diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs index c3e9d0c23..85dc4feb0 100644 --- a/crates/ra_hir_def/src/body.rs +++ b/crates/ra_hir_def/src/body.rs @@ -17,7 +17,7 @@ use crate::{ expr::{Expr, ExprId, Pat, PatId}, nameres::CrateDefMap, path::Path, - ModuleId, + AstItemDef, DefWithBodyId, ModuleId, }; pub struct Expander { @@ -141,7 +141,37 @@ pub struct BodySourceMap { } impl Body { - pub fn new( + pub(crate) fn body_with_source_map_query( + db: &impl DefDatabase2, + def: DefWithBodyId, + ) -> (Arc, Arc) { + let mut params = None; + + let (file_id, module, body) = match def { + DefWithBodyId::FunctionId(f) => { + let src = f.source(db); + params = src.ast.param_list(); + (src.file_id, f.module(db), src.ast.body().map(ast::Expr::from)) + } + DefWithBodyId::ConstId(c) => { + let src = c.source(db); + (src.file_id, c.module(db), src.ast.body()) + } + DefWithBodyId::StaticId(s) => { + let src = s.source(db); + (src.file_id, s.module(db), src.ast.body()) + } + }; + let expander = Expander::new(db, file_id, module); + let (body, source_map) = Body::new(db, expander, params, body); + (Arc::new(body), Arc::new(source_map)) + } + + pub(crate) fn body_query(db: &impl DefDatabase2, def: DefWithBodyId) -> Arc { + db.body_with_source_map(def).0 + } + + fn new( db: &impl DefDatabase2, expander: Expander, params: Option, diff --git a/crates/ra_hir_def/src/body/scope.rs b/crates/ra_hir_def/src/body/scope.rs index dd8d06d11..09a39e721 100644 --- a/crates/ra_hir_def/src/body/scope.rs +++ b/crates/ra_hir_def/src/body/scope.rs @@ -1,4 +1,5 @@ //! FIXME: write short doc here +use std::sync::Arc; use hir_expand::name::Name; use ra_arena::{impl_arena_id, Arena, RawId}; @@ -6,7 +7,9 @@ use rustc_hash::FxHashMap; use crate::{ body::Body, + db::DefDatabase2, expr::{Expr, ExprId, Pat, PatId, Statement}, + DefWithBodyId, }; #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -42,7 +45,12 @@ pub struct ScopeData { } impl ExprScopes { - pub fn new(body: &Body) -> ExprScopes { + pub(crate) fn expr_scopes_query(db: &impl DefDatabase2, def: DefWithBodyId) -> Arc { + let body = db.body(def); + Arc::new(ExprScopes::new(&*body)) + } + + fn new(body: &Body) -> ExprScopes { let mut scopes = ExprScopes { scopes: Arena::default(), scope_by_expr: FxHashMap::default() }; let root = scopes.root_scope(); diff --git a/crates/ra_hir_def/src/db.rs b/crates/ra_hir_def/src/db.rs index 29cf71a59..40b5920d9 100644 --- a/crates/ra_hir_def/src/db.rs +++ b/crates/ra_hir_def/src/db.rs @@ -7,11 +7,12 @@ use ra_syntax::ast; use crate::{ adt::{EnumData, StructData}, + body::{scope::ExprScopes, Body, BodySourceMap}, nameres::{ raw::{ImportSourceMap, RawItems}, CrateDefMap, }, - EnumId, StructOrUnionId, + DefWithBodyId, EnumId, StructOrUnionId, }; #[salsa::query_group(InternDatabaseStorage)] @@ -52,4 +53,13 @@ pub trait DefDatabase2: InternDatabase + AstDatabase { #[salsa::invoke(EnumData::enum_data_query)] fn enum_data(&self, e: EnumId) -> Arc; + + #[salsa::invoke(Body::body_with_source_map_query)] + fn body_with_source_map(&self, def: DefWithBodyId) -> (Arc, Arc); + + #[salsa::invoke(Body::body_query)] + fn body(&self, def: DefWithBodyId) -> Arc; + + #[salsa::invoke(ExprScopes::expr_scopes_query)] + fn expr_scopes(&self, def: DefWithBodyId) -> Arc; } diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs index 4a758bb83..3fab7965c 100644 --- a/crates/ra_hir_def/src/lib.rs +++ b/crates/ra_hir_def/src/lib.rs @@ -374,3 +374,13 @@ impl_froms!( TypeAliasId, BuiltinType ); + +/// The defs which have a body. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum DefWithBodyId { + FunctionId(FunctionId), + StaticId(StaticId), + ConstId(ConstId), +} + +impl_froms!(DefWithBodyId: FunctionId, ConstId, StaticId); -- cgit v1.2.3 From fc9c2915c74ac120a9b52c9003f768a9a4e30a55 Mon Sep 17 00:00:00 2001 From: kjeremy Date: Thu, 14 Nov 2019 11:47:18 -0500 Subject: Even if jemalloc feature is used do not use it on msvc Fixes #2233 --- crates/ra_prof/Cargo.toml | 36 +++++++++++++++++++----------------- crates/ra_prof/src/lib.rs | 2 +- crates/ra_prof/src/memory_usage.rs | 4 ++-- 3 files changed, 22 insertions(+), 20 deletions(-) (limited to 'crates') diff --git a/crates/ra_prof/Cargo.toml b/crates/ra_prof/Cargo.toml index 7db4498c3..bb241258c 100644 --- a/crates/ra_prof/Cargo.toml +++ b/crates/ra_prof/Cargo.toml @@ -1,17 +1,19 @@ -[package] -edition = "2018" -name = "ra_prof" -version = "0.1.0" -authors = ["rust-analyzer developers"] -publish = false - -[dependencies] -once_cell = "1.0.1" -itertools = "0.8.0" -backtrace = "0.3.28" -jemallocator = { version = "0.3.2", optional = true } -jemalloc-ctl = { version = "0.3.2", optional = true } - -[features] -jemalloc = [ "jemallocator", "jemalloc-ctl" ] -cpu_profiler = [] +[package] +edition = "2018" +name = "ra_prof" +version = "0.1.0" +authors = ["rust-analyzer developers"] +publish = false + +[dependencies] +once_cell = "1.0.1" +itertools = "0.8.0" +backtrace = "0.3.28" + +[target.'cfg(not(target_env = "msvc"))'.dependencies] +jemallocator = { version = "0.3.2", optional = true } +jemalloc-ctl = { version = "0.3.2", optional = true } + +[features] +jemalloc = [ "jemallocator", "jemalloc-ctl" ] +cpu_profiler = [] diff --git a/crates/ra_prof/src/lib.rs b/crates/ra_prof/src/lib.rs index e5385f51b..845b2221c 100644 --- a/crates/ra_prof/src/lib.rs +++ b/crates/ra_prof/src/lib.rs @@ -24,7 +24,7 @@ pub use crate::memory_usage::{Bytes, MemoryUsage}; // We use jemalloc mainly to get heap usage statistics, actual performance // difference is not measures. -#[cfg(feature = "jemalloc")] +#[cfg(all(feature = "jemalloc", not(target_env = "msvc")))] #[global_allocator] static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; diff --git a/crates/ra_prof/src/memory_usage.rs b/crates/ra_prof/src/memory_usage.rs index ad005ea14..9768f656c 100644 --- a/crates/ra_prof/src/memory_usage.rs +++ b/crates/ra_prof/src/memory_usage.rs @@ -8,7 +8,7 @@ pub struct MemoryUsage { } impl MemoryUsage { - #[cfg(feature = "jemalloc")] + #[cfg(all(feature = "jemalloc", not(target_env = "msvc")))] pub fn current() -> MemoryUsage { jemalloc_ctl::epoch::advance().unwrap(); MemoryUsage { @@ -17,7 +17,7 @@ impl MemoryUsage { } } - #[cfg(not(feature = "jemalloc"))] + #[cfg(any(not(feature = "jemalloc"), target_env = "msvc"))] pub fn current() -> MemoryUsage { MemoryUsage { allocated: Bytes(0), resident: Bytes(0) } } -- cgit v1.2.3