mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-27 04:19:13 +00:00
Make FnScopes use hir::Expr
This was a bit complicated. I've added a wrapper type for now that does the LocalSyntaxPtr <-> ExprId translation; we might want to get rid of that or give it a nicer interface.
This commit is contained in:
parent
136aba1cf3
commit
8e3e5ab2c8
13 changed files with 533 additions and 313 deletions
|
@ -15,7 +15,7 @@ pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) ->
|
||||||
None => return Ok(()),
|
None => return Ok(()),
|
||||||
};
|
};
|
||||||
if let Some(function) = &ctx.function {
|
if let Some(function) = &ctx.function {
|
||||||
let scopes = function.scopes(ctx.db);
|
let scopes = function.scopes(ctx.db)?;
|
||||||
complete_fn(acc, &scopes, ctx.offset);
|
complete_fn(acc, &scopes, ctx.offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,20 +40,17 @@ pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) ->
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn complete_fn(acc: &mut Completions, scopes: &hir::FnScopes, offset: TextUnit) {
|
fn complete_fn(acc: &mut Completions, scopes: &hir::ScopesWithSyntaxMapping, offset: TextUnit) {
|
||||||
let mut shadowed = FxHashSet::default();
|
let mut shadowed = FxHashSet::default();
|
||||||
scopes
|
scopes
|
||||||
.scope_chain_for_offset(offset)
|
.scope_chain_for_offset(offset)
|
||||||
.flat_map(|scope| scopes.entries(scope).iter())
|
.flat_map(|scope| scopes.scopes.entries(scope).iter())
|
||||||
.filter(|entry| shadowed.insert(entry.name()))
|
.filter(|entry| shadowed.insert(entry.name()))
|
||||||
.for_each(|entry| {
|
.for_each(|entry| {
|
||||||
CompletionItem::new(CompletionKind::Reference, entry.name().to_string())
|
CompletionItem::new(CompletionKind::Reference, entry.name().to_string())
|
||||||
.kind(CompletionItemKind::Binding)
|
.kind(CompletionItemKind::Binding)
|
||||||
.add_to(acc)
|
.add_to(acc)
|
||||||
});
|
});
|
||||||
if scopes.self_param.is_some() {
|
|
||||||
CompletionItem::new(CompletionKind::Reference, "self").add_to(acc);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -28,7 +28,7 @@ pub(crate) fn reference_defenition(
|
||||||
if let Some(fn_descr) =
|
if let Some(fn_descr) =
|
||||||
hir::source_binder::function_from_child_node(db, file_id, name_ref.syntax())?
|
hir::source_binder::function_from_child_node(db, file_id, name_ref.syntax())?
|
||||||
{
|
{
|
||||||
let scope = fn_descr.scopes(db);
|
let scope = fn_descr.scopes(db)?;
|
||||||
// First try to resolve the symbol locally
|
// First try to resolve the symbol locally
|
||||||
if let Some(entry) = scope.resolve_local_name(name_ref) {
|
if let Some(entry) = scope.resolve_local_name(name_ref) {
|
||||||
let nav = NavigationTarget {
|
let nav = NavigationTarget {
|
||||||
|
|
|
@ -157,7 +157,7 @@ impl db::RootDatabase {
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
ret.extend(
|
ret.extend(
|
||||||
descr
|
descr
|
||||||
.scopes(self)
|
.scopes(self)?
|
||||||
.find_all_refs(binding)
|
.find_all_refs(binding)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|ref_desc| (position.file_id, ref_desc.range)),
|
.map(|ref_desc| (position.file_id, ref_desc.range)),
|
||||||
|
@ -185,7 +185,7 @@ impl db::RootDatabase {
|
||||||
position.file_id,
|
position.file_id,
|
||||||
name_ref.syntax(),
|
name_ref.syntax(),
|
||||||
)?);
|
)?);
|
||||||
let scope = descr.scopes(db);
|
let scope = descr.scopes(db)?;
|
||||||
let resolved = ctry!(scope.resolve_local_name(name_ref));
|
let resolved = ctry!(scope.resolve_local_name(name_ref));
|
||||||
let resolved = resolved.ptr().resolve(source_file);
|
let resolved = resolved.ptr().resolve(source_file);
|
||||||
let binding = ctry!(find_node_at_offset::<ast::BindPat>(
|
let binding = ctry!(find_node_at_offset::<ast::BindPat>(
|
||||||
|
|
|
@ -31,7 +31,7 @@ pub trait HirDatabase: SyntaxDatabase
|
||||||
use fn crate::macros::expand_macro_invocation;
|
use fn crate::macros::expand_macro_invocation;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fn_scopes(def_id: DefId) -> Arc<FnScopes> {
|
fn fn_scopes(def_id: DefId) -> Cancelable<Arc<FnScopes>> {
|
||||||
type FnScopesQuery;
|
type FnScopesQuery;
|
||||||
use fn query_definitions::fn_scopes;
|
use fn query_definitions::fn_scopes;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ use rustc_hash::FxHashMap;
|
||||||
|
|
||||||
use ra_arena::{Arena, RawId, impl_arena_id};
|
use ra_arena::{Arena, RawId, impl_arena_id};
|
||||||
use ra_db::{LocalSyntaxPtr, Cancelable};
|
use ra_db::{LocalSyntaxPtr, Cancelable};
|
||||||
use ra_syntax::ast::{self, AstNode, LoopBodyOwner, ArgListOwner};
|
use ra_syntax::ast::{self, AstNode, LoopBodyOwner, ArgListOwner, NameOwner};
|
||||||
|
|
||||||
use crate::{Path, type_ref::{Mutability, TypeRef}, Name, HirDatabase, DefId, Def, name::AsName};
|
use crate::{Path, type_ref::{Mutability, TypeRef}, Name, HirDatabase, DefId, Def, name::AsName};
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ pub struct Body {
|
||||||
/// part of the function signature, the patterns are not (they don't change
|
/// part of the function signature, the patterns are not (they don't change
|
||||||
/// the external type of the function).
|
/// the external type of the function).
|
||||||
///
|
///
|
||||||
/// If this `ExprTable` is for the body of a constant, this will just be
|
/// If this `Body` is for the body of a constant, this will just be
|
||||||
/// empty.
|
/// empty.
|
||||||
args: Vec<PatId>,
|
args: Vec<PatId>,
|
||||||
/// The `ExprId` of the actual body expression.
|
/// The `ExprId` of the actual body expression.
|
||||||
|
@ -43,6 +43,43 @@ pub struct BodySyntaxMapping {
|
||||||
pat_syntax_mapping_back: FxHashMap<PatId, LocalSyntaxPtr>,
|
pat_syntax_mapping_back: FxHashMap<PatId, LocalSyntaxPtr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Body {
|
||||||
|
pub fn expr(&self, expr: ExprId) -> &Expr {
|
||||||
|
&self.exprs[expr]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pat(&self, pat: PatId) -> &Pat {
|
||||||
|
&self.pats[pat]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn args(&self) -> &[PatId] {
|
||||||
|
&self.args
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn body_expr(&self) -> ExprId {
|
||||||
|
self.body_expr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BodySyntaxMapping {
|
||||||
|
pub fn expr_syntax(&self, expr: ExprId) -> Option<LocalSyntaxPtr> {
|
||||||
|
self.expr_syntax_mapping_back.get(&expr).cloned()
|
||||||
|
}
|
||||||
|
pub fn syntax_expr(&self, ptr: LocalSyntaxPtr) -> Option<ExprId> {
|
||||||
|
self.expr_syntax_mapping.get(&ptr).cloned()
|
||||||
|
}
|
||||||
|
pub fn pat_syntax(&self, pat: PatId) -> Option<LocalSyntaxPtr> {
|
||||||
|
self.pat_syntax_mapping_back.get(&pat).cloned()
|
||||||
|
}
|
||||||
|
pub fn syntax_pat(&self, ptr: LocalSyntaxPtr) -> Option<PatId> {
|
||||||
|
self.pat_syntax_mapping.get(&ptr).cloned()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn body(&self) -> &Arc<Body> {
|
||||||
|
&self.body
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
pub enum Expr {
|
pub enum Expr {
|
||||||
/// This is produced if syntax tree does not have a required expression piece.
|
/// This is produced if syntax tree does not have a required expression piece.
|
||||||
|
@ -113,21 +150,26 @@ pub enum Expr {
|
||||||
expr: ExprId,
|
expr: ExprId,
|
||||||
op: Option<UnaryOp>,
|
op: Option<UnaryOp>,
|
||||||
},
|
},
|
||||||
|
Lambda {
|
||||||
|
args: Vec<PatId>,
|
||||||
|
arg_types: Vec<Option<TypeRef>>,
|
||||||
|
body: ExprId,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type UnaryOp = ast::PrefixOp;
|
pub type UnaryOp = ast::PrefixOp;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
pub struct MatchArm {
|
pub struct MatchArm {
|
||||||
pats: Vec<PatId>,
|
pub pats: Vec<PatId>,
|
||||||
// guard: Option<ExprId>, // TODO
|
// guard: Option<ExprId>, // TODO
|
||||||
expr: ExprId,
|
pub expr: ExprId,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
pub struct StructLitField {
|
pub struct StructLitField {
|
||||||
name: Name,
|
pub name: Name,
|
||||||
expr: ExprId,
|
pub expr: ExprId,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
|
@ -140,12 +182,118 @@ pub enum Statement {
|
||||||
Expr(ExprId),
|
Expr(ExprId),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Expr {
|
||||||
|
pub fn walk_child_exprs(&self, mut f: impl FnMut(ExprId)) {
|
||||||
|
match self {
|
||||||
|
Expr::Missing => {}
|
||||||
|
Expr::Path(_) => {}
|
||||||
|
Expr::If {
|
||||||
|
condition,
|
||||||
|
then_branch,
|
||||||
|
else_branch,
|
||||||
|
} => {
|
||||||
|
f(*condition);
|
||||||
|
f(*then_branch);
|
||||||
|
if let Some(else_branch) = else_branch {
|
||||||
|
f(*else_branch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Expr::Block { statements, tail } => {
|
||||||
|
for stmt in statements {
|
||||||
|
match stmt {
|
||||||
|
Statement::Let { initializer, .. } => {
|
||||||
|
if let Some(expr) = initializer {
|
||||||
|
f(*expr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Statement::Expr(e) => f(*e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(expr) = tail {
|
||||||
|
f(*expr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Expr::Loop { body } => f(*body),
|
||||||
|
Expr::While { condition, body } => {
|
||||||
|
f(*condition);
|
||||||
|
f(*body);
|
||||||
|
}
|
||||||
|
Expr::For { iterable, body, .. } => {
|
||||||
|
f(*iterable);
|
||||||
|
f(*body);
|
||||||
|
}
|
||||||
|
Expr::Call { callee, args } => {
|
||||||
|
f(*callee);
|
||||||
|
for arg in args {
|
||||||
|
f(*arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Expr::MethodCall { receiver, args, .. } => {
|
||||||
|
f(*receiver);
|
||||||
|
for arg in args {
|
||||||
|
f(*arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Expr::Match { expr, arms } => {
|
||||||
|
f(*expr);
|
||||||
|
for arm in arms {
|
||||||
|
f(arm.expr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Expr::Continue => {}
|
||||||
|
Expr::Break { expr } | Expr::Return { expr } => {
|
||||||
|
if let Some(expr) = expr {
|
||||||
|
f(*expr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Expr::StructLit { fields, spread, .. } => {
|
||||||
|
for field in fields {
|
||||||
|
f(field.expr);
|
||||||
|
}
|
||||||
|
if let Some(expr) = spread {
|
||||||
|
f(*expr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Expr::Lambda { body, .. } => {
|
||||||
|
f(*body);
|
||||||
|
}
|
||||||
|
Expr::Field { expr, .. }
|
||||||
|
| Expr::Try { expr }
|
||||||
|
| Expr::Cast { expr, .. }
|
||||||
|
| Expr::Ref { expr, .. }
|
||||||
|
| Expr::UnaryOp { expr, .. } => {
|
||||||
|
f(*expr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub struct PatId(RawId);
|
pub struct PatId(RawId);
|
||||||
impl_arena_id!(PatId);
|
impl_arena_id!(PatId);
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
pub struct Pat;
|
pub enum Pat {
|
||||||
|
Missing,
|
||||||
|
Bind {
|
||||||
|
name: Name,
|
||||||
|
},
|
||||||
|
TupleStruct {
|
||||||
|
path: Option<Path>,
|
||||||
|
args: Vec<PatId>,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Pat {
|
||||||
|
pub fn walk_child_pats(&self, f: impl FnMut(PatId)) {
|
||||||
|
match self {
|
||||||
|
Pat::Missing | Pat::Bind { .. } => {}
|
||||||
|
Pat::TupleStruct { args, .. } => {
|
||||||
|
args.iter().map(|pat| *pat).for_each(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Queries
|
// Queries
|
||||||
|
|
||||||
|
@ -163,6 +311,17 @@ struct ExprCollector {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExprCollector {
|
impl ExprCollector {
|
||||||
|
fn new() -> Self {
|
||||||
|
ExprCollector {
|
||||||
|
exprs: Arena::default(),
|
||||||
|
pats: Arena::default(),
|
||||||
|
expr_syntax_mapping: FxHashMap::default(),
|
||||||
|
expr_syntax_mapping_back: FxHashMap::default(),
|
||||||
|
pat_syntax_mapping: FxHashMap::default(),
|
||||||
|
pat_syntax_mapping_back: FxHashMap::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn alloc_expr(&mut self, expr: Expr, syntax_ptr: LocalSyntaxPtr) -> ExprId {
|
fn alloc_expr(&mut self, expr: Expr, syntax_ptr: LocalSyntaxPtr) -> ExprId {
|
||||||
let id = self.exprs.alloc(expr);
|
let id = self.exprs.alloc(expr);
|
||||||
self.expr_syntax_mapping.insert(syntax_ptr, id);
|
self.expr_syntax_mapping.insert(syntax_ptr, id);
|
||||||
|
@ -177,17 +336,49 @@ impl ExprCollector {
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn empty_block(&mut self) -> ExprId {
|
||||||
|
let block = Expr::Block {
|
||||||
|
statements: Vec::new(),
|
||||||
|
tail: None,
|
||||||
|
};
|
||||||
|
self.exprs.alloc(block)
|
||||||
|
}
|
||||||
|
|
||||||
fn collect_expr(&mut self, expr: ast::Expr) -> ExprId {
|
fn collect_expr(&mut self, expr: ast::Expr) -> ExprId {
|
||||||
let syntax_ptr = LocalSyntaxPtr::new(expr.syntax());
|
let syntax_ptr = LocalSyntaxPtr::new(expr.syntax());
|
||||||
match expr {
|
match expr {
|
||||||
ast::Expr::IfExpr(e) => {
|
ast::Expr::IfExpr(e) => {
|
||||||
let condition = if let Some(condition) = e.condition() {
|
if let Some(pat) = e.condition().and_then(|c| c.pat()) {
|
||||||
if condition.pat().is_none() {
|
// if let -- desugar to match
|
||||||
self.collect_expr_opt(condition.expr())
|
let pat = self.collect_pat(pat);
|
||||||
|
let match_expr =
|
||||||
|
self.collect_expr_opt(e.condition().expect("checked above").expr());
|
||||||
|
let then_branch = self.collect_block_opt(e.then_branch());
|
||||||
|
let else_branch = e
|
||||||
|
.else_branch()
|
||||||
|
.map(|e| self.collect_block(e))
|
||||||
|
.unwrap_or_else(|| self.empty_block());
|
||||||
|
let placeholder_pat = self.pats.alloc(Pat::Missing);
|
||||||
|
let arms = vec![
|
||||||
|
MatchArm {
|
||||||
|
pats: vec![pat],
|
||||||
|
expr: then_branch,
|
||||||
|
},
|
||||||
|
MatchArm {
|
||||||
|
pats: vec![placeholder_pat],
|
||||||
|
expr: else_branch,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
self.alloc_expr(
|
||||||
|
Expr::Match {
|
||||||
|
expr: match_expr,
|
||||||
|
arms,
|
||||||
|
},
|
||||||
|
syntax_ptr,
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
// TODO handle if let
|
let condition = if let Some(condition) = e.condition() {
|
||||||
return self.alloc_expr(Expr::Missing, syntax_ptr);
|
self.collect_expr_opt(condition.expr())
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
self.exprs.alloc(Expr::Missing)
|
self.exprs.alloc(Expr::Missing)
|
||||||
};
|
};
|
||||||
|
@ -202,6 +393,7 @@ impl ExprCollector {
|
||||||
syntax_ptr,
|
syntax_ptr,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
ast::Expr::BlockExpr(e) => self.collect_block_opt(e.block()),
|
ast::Expr::BlockExpr(e) => self.collect_block_opt(e.block()),
|
||||||
ast::Expr::LoopExpr(e) => {
|
ast::Expr::LoopExpr(e) => {
|
||||||
let body = self.collect_block_opt(e.loop_body());
|
let body = self.collect_block_opt(e.loop_body());
|
||||||
|
@ -368,18 +560,30 @@ impl ExprCollector {
|
||||||
let op = e.op();
|
let op = e.op();
|
||||||
self.alloc_expr(Expr::UnaryOp { expr, op }, syntax_ptr)
|
self.alloc_expr(Expr::UnaryOp { expr, op }, syntax_ptr)
|
||||||
}
|
}
|
||||||
|
ast::Expr::LambdaExpr(e) => {
|
||||||
// We should never get to these because they're handled in MatchExpr resp. StructLit:
|
let mut args = Vec::new();
|
||||||
ast::Expr::MatchArmList(_) | ast::Expr::MatchArm(_) | ast::Expr::MatchGuard(_) => {
|
let mut arg_types = Vec::new();
|
||||||
panic!("collect_expr called on {:?}", expr)
|
if let Some(pl) = e.param_list() {
|
||||||
|
for param in pl.params() {
|
||||||
|
let pat = self.collect_pat_opt(param.pat());
|
||||||
|
let type_ref = param.type_ref().map(TypeRef::from_ast);
|
||||||
|
args.push(pat);
|
||||||
|
arg_types.push(type_ref);
|
||||||
}
|
}
|
||||||
ast::Expr::NamedFieldList(_) | ast::Expr::NamedField(_) => {
|
}
|
||||||
panic!("collect_expr called on {:?}", expr)
|
let body = self.collect_expr_opt(e.body());
|
||||||
|
self.alloc_expr(
|
||||||
|
Expr::Lambda {
|
||||||
|
args,
|
||||||
|
arg_types,
|
||||||
|
body,
|
||||||
|
},
|
||||||
|
syntax_ptr,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO implement HIR for these:
|
// TODO implement HIR for these:
|
||||||
ast::Expr::Label(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
|
ast::Expr::Label(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
|
||||||
ast::Expr::LambdaExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
|
|
||||||
ast::Expr::IndexExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
|
ast::Expr::IndexExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
|
||||||
ast::Expr::TupleExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
|
ast::Expr::TupleExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
|
||||||
ast::Expr::ArrayExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
|
ast::Expr::ArrayExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
|
||||||
|
@ -431,16 +635,31 @@ impl ExprCollector {
|
||||||
|
|
||||||
fn collect_pat(&mut self, pat: ast::Pat) -> PatId {
|
fn collect_pat(&mut self, pat: ast::Pat) -> PatId {
|
||||||
let syntax_ptr = LocalSyntaxPtr::new(pat.syntax());
|
let syntax_ptr = LocalSyntaxPtr::new(pat.syntax());
|
||||||
|
match pat {
|
||||||
|
ast::Pat::BindPat(bp) => {
|
||||||
|
let name = bp
|
||||||
|
.name()
|
||||||
|
.map(|nr| nr.as_name())
|
||||||
|
.unwrap_or_else(Name::missing);
|
||||||
|
self.alloc_pat(Pat::Bind { name }, syntax_ptr)
|
||||||
|
}
|
||||||
|
ast::Pat::TupleStructPat(p) => {
|
||||||
|
let path = p.path().and_then(Path::from_ast);
|
||||||
|
let args = p.args().map(|p| self.collect_pat(p)).collect();
|
||||||
|
self.alloc_pat(Pat::TupleStruct { path, args }, syntax_ptr)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
// TODO
|
// TODO
|
||||||
self.alloc_pat(Pat, syntax_ptr)
|
self.alloc_pat(Pat::Missing, syntax_ptr)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collect_pat_opt(&mut self, pat: Option<ast::Pat>) -> PatId {
|
fn collect_pat_opt(&mut self, pat: Option<ast::Pat>) -> PatId {
|
||||||
if let Some(pat) = pat {
|
if let Some(pat) = pat {
|
||||||
self.collect_pat(pat)
|
self.collect_pat(pat)
|
||||||
} else {
|
} else {
|
||||||
// TODO
|
self.pats.alloc(Pat::Missing)
|
||||||
self.pats.alloc(Pat)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -461,28 +680,28 @@ impl ExprCollector {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn body_syntax_mapping(
|
pub(crate) fn collect_fn_body_syntax(node: ast::FnDef) -> BodySyntaxMapping {
|
||||||
db: &impl HirDatabase,
|
let mut collector = ExprCollector::new();
|
||||||
def_id: DefId,
|
|
||||||
) -> Cancelable<Arc<BodySyntaxMapping>> {
|
|
||||||
let def = def_id.resolve(db)?;
|
|
||||||
let mut collector = ExprCollector {
|
|
||||||
exprs: Arena::default(),
|
|
||||||
pats: Arena::default(),
|
|
||||||
expr_syntax_mapping: FxHashMap::default(),
|
|
||||||
expr_syntax_mapping_back: FxHashMap::default(),
|
|
||||||
pat_syntax_mapping: FxHashMap::default(),
|
|
||||||
pat_syntax_mapping_back: FxHashMap::default(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let (body, args) = match def {
|
|
||||||
Def::Function(f) => {
|
|
||||||
let node = f.syntax(db);
|
|
||||||
let node = node.borrowed();
|
|
||||||
|
|
||||||
let args = if let Some(param_list) = node.param_list() {
|
let args = if let Some(param_list) = node.param_list() {
|
||||||
let mut args = Vec::new();
|
let mut args = Vec::new();
|
||||||
// TODO self param
|
|
||||||
|
if let Some(self_param) = param_list.self_param() {
|
||||||
|
let self_param = LocalSyntaxPtr::new(
|
||||||
|
self_param
|
||||||
|
.self_kw()
|
||||||
|
.expect("self param without self keyword")
|
||||||
|
.syntax(),
|
||||||
|
);
|
||||||
|
let arg = collector.alloc_pat(
|
||||||
|
Pat::Bind {
|
||||||
|
name: Name::self_param(),
|
||||||
|
},
|
||||||
|
self_param,
|
||||||
|
);
|
||||||
|
args.push(arg);
|
||||||
|
}
|
||||||
|
|
||||||
for param in param_list.params() {
|
for param in param_list.params() {
|
||||||
let pat = if let Some(pat) = param.pat() {
|
let pat = if let Some(pat) = param.pat() {
|
||||||
pat
|
pat
|
||||||
|
@ -497,11 +716,25 @@ pub(crate) fn body_syntax_mapping(
|
||||||
};
|
};
|
||||||
|
|
||||||
let body = collector.collect_block_opt(node.body());
|
let body = collector.collect_block_opt(node.body());
|
||||||
(body, args)
|
collector.into_body_syntax_mapping(args, body)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn body_syntax_mapping(
|
||||||
|
db: &impl HirDatabase,
|
||||||
|
def_id: DefId,
|
||||||
|
) -> Cancelable<Arc<BodySyntaxMapping>> {
|
||||||
|
let def = def_id.resolve(db)?;
|
||||||
|
|
||||||
|
let body_syntax_mapping = match def {
|
||||||
|
Def::Function(f) => {
|
||||||
|
let node = f.syntax(db);
|
||||||
|
let node = node.borrowed();
|
||||||
|
|
||||||
|
collect_fn_body_syntax(node)
|
||||||
}
|
}
|
||||||
// TODO: consts, etc.
|
// TODO: consts, etc.
|
||||||
_ => panic!("Trying to get body for item type without body"),
|
_ => panic!("Trying to get body for item type without body"),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Arc::new(collector.into_body_syntax_mapping(args, body)))
|
Ok(Arc::new(body_syntax_mapping))
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,9 +11,9 @@ use ra_syntax::{
|
||||||
ast::{self, AstNode, DocCommentsOwner, NameOwner},
|
ast::{self, AstNode, DocCommentsOwner, NameOwner},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{DefId, DefKind, HirDatabase, ty::InferenceResult, Module, Crate, impl_block::ImplBlock};
|
use crate::{DefId, DefKind, HirDatabase, ty::InferenceResult, Module, Crate, impl_block::ImplBlock, expr::{Body, BodySyntaxMapping}};
|
||||||
|
|
||||||
pub use self::scope::FnScopes;
|
pub use self::scope::{FnScopes, ScopesWithSyntaxMapping};
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct Function {
|
pub struct Function {
|
||||||
|
@ -36,8 +36,21 @@ impl Function {
|
||||||
ast::FnDef::cast(syntax.borrowed()).unwrap().owned()
|
ast::FnDef::cast(syntax.borrowed()).unwrap().owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn scopes(&self, db: &impl HirDatabase) -> Arc<FnScopes> {
|
pub fn body(&self, db: &impl HirDatabase) -> Cancelable<Arc<Body>> {
|
||||||
db.fn_scopes(self.def_id)
|
db.body_hir(self.def_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn body_syntax_mapping(&self, db: &impl HirDatabase) -> Cancelable<Arc<BodySyntaxMapping>> {
|
||||||
|
db.body_syntax_mapping(self.def_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn scopes(&self, db: &impl HirDatabase) -> Cancelable<ScopesWithSyntaxMapping> {
|
||||||
|
let scopes = db.fn_scopes(self.def_id)?;
|
||||||
|
let syntax_mapping = db.body_syntax_mapping(self.def_id)?;
|
||||||
|
Ok(ScopesWithSyntaxMapping {
|
||||||
|
scopes,
|
||||||
|
syntax_mapping,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn signature_info(&self, db: &impl HirDatabase) -> Option<FnSignatureInfo> {
|
pub fn signature_info(&self, db: &impl HirDatabase) -> Option<FnSignatureInfo> {
|
||||||
|
|
|
@ -1,14 +1,16 @@
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use rustc_hash::{FxHashMap, FxHashSet};
|
use rustc_hash::{FxHashMap, FxHashSet};
|
||||||
|
|
||||||
use ra_syntax::{
|
use ra_syntax::{
|
||||||
AstNode, SyntaxNodeRef, TextUnit, TextRange,
|
AstNode, SyntaxNodeRef, TextUnit, TextRange,
|
||||||
algo::generate,
|
algo::generate,
|
||||||
ast::{self, ArgListOwner, LoopBodyOwner, NameOwner},
|
ast,
|
||||||
};
|
};
|
||||||
use ra_arena::{Arena, RawId, impl_arena_id};
|
use ra_arena::{Arena, RawId, impl_arena_id};
|
||||||
use ra_db::LocalSyntaxPtr;
|
use ra_db::LocalSyntaxPtr;
|
||||||
|
|
||||||
use crate::{Name, AsName};
|
use crate::{Name, AsName, expr::{PatId, ExprId, Pat, Expr, Body, Statement, BodySyntaxMapping}};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub struct ScopeId(RawId);
|
pub struct ScopeId(RawId);
|
||||||
|
@ -16,15 +18,15 @@ impl_arena_id!(ScopeId);
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub struct FnScopes {
|
pub struct FnScopes {
|
||||||
pub self_param: Option<LocalSyntaxPtr>,
|
body: Arc<Body>,
|
||||||
scopes: Arena<ScopeId, ScopeData>,
|
scopes: Arena<ScopeId, ScopeData>,
|
||||||
scope_for: FxHashMap<LocalSyntaxPtr, ScopeId>,
|
scope_for: FxHashMap<ExprId, ScopeId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub struct ScopeEntry {
|
pub struct ScopeEntry {
|
||||||
name: Name,
|
name: Name,
|
||||||
ptr: LocalSyntaxPtr,
|
pat: PatId,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
@ -34,28 +36,101 @@ pub struct ScopeData {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FnScopes {
|
impl FnScopes {
|
||||||
pub(crate) fn new(fn_def: ast::FnDef) -> FnScopes {
|
pub(crate) fn new(body: Arc<Body>) -> FnScopes {
|
||||||
let mut scopes = FnScopes {
|
let mut scopes = FnScopes {
|
||||||
self_param: fn_def
|
body: body.clone(),
|
||||||
.param_list()
|
|
||||||
.and_then(|it| it.self_param())
|
|
||||||
.map(|it| LocalSyntaxPtr::new(it.syntax())),
|
|
||||||
scopes: Arena::default(),
|
scopes: Arena::default(),
|
||||||
scope_for: FxHashMap::default(),
|
scope_for: FxHashMap::default(),
|
||||||
};
|
};
|
||||||
let root = scopes.root_scope();
|
let root = scopes.root_scope();
|
||||||
scopes.add_params_bindings(root, fn_def.param_list());
|
scopes.add_params_bindings(root, body.args());
|
||||||
if let Some(body) = fn_def.body() {
|
compute_expr_scopes(body.body_expr(), &body, &mut scopes, root);
|
||||||
compute_block_scopes(body, &mut scopes, root)
|
|
||||||
}
|
|
||||||
scopes
|
scopes
|
||||||
}
|
}
|
||||||
pub fn entries(&self, scope: ScopeId) -> &[ScopeEntry] {
|
pub fn entries(&self, scope: ScopeId) -> &[ScopeEntry] {
|
||||||
&self.scopes[scope].entries
|
&self.scopes[scope].entries
|
||||||
}
|
}
|
||||||
|
pub fn scope_chain_for<'a>(&'a self, expr: ExprId) -> impl Iterator<Item = ScopeId> + 'a {
|
||||||
|
generate(self.scope_for(expr), move |&scope| {
|
||||||
|
self.scopes[scope].parent
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn resolve_local_name<'a>(
|
||||||
|
&'a self,
|
||||||
|
context_expr: ExprId,
|
||||||
|
name: Name,
|
||||||
|
) -> Option<&'a ScopeEntry> {
|
||||||
|
let mut shadowed = FxHashSet::default();
|
||||||
|
let ret = self
|
||||||
|
.scope_chain_for(context_expr)
|
||||||
|
.flat_map(|scope| self.entries(scope).iter())
|
||||||
|
.filter(|entry| shadowed.insert(entry.name()))
|
||||||
|
.filter(|entry| entry.name() == &name)
|
||||||
|
.nth(0);
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
Pat::Bind { name } => self.scopes[scope].entries.push(ScopeEntry {
|
||||||
|
name: name.clone(),
|
||||||
|
pat,
|
||||||
|
}),
|
||||||
|
p => p.walk_child_pats(|pat| self.add_bindings(body, scope, pat)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn add_params_bindings(&mut self, scope: ScopeId, params: &[PatId]) {
|
||||||
|
let body = Arc::clone(&self.body);
|
||||||
|
params
|
||||||
|
.into_iter()
|
||||||
|
.for_each(|it| self.add_bindings(&body, scope, *it));
|
||||||
|
}
|
||||||
|
fn set_scope(&mut self, node: ExprId, scope: ScopeId) {
|
||||||
|
self.scope_for.insert(node, scope);
|
||||||
|
}
|
||||||
|
fn scope_for(&self, expr: ExprId) -> Option<ScopeId> {
|
||||||
|
self.scope_for.get(&expr).map(|&scope| scope)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct ScopesWithSyntaxMapping {
|
||||||
|
pub syntax_mapping: Arc<BodySyntaxMapping>,
|
||||||
|
pub scopes: Arc<FnScopes>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct ScopeEntryWithSyntax {
|
||||||
|
name: Name,
|
||||||
|
ptr: LocalSyntaxPtr,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ScopeEntryWithSyntax {
|
||||||
|
pub fn name(&self) -> &Name {
|
||||||
|
&self.name
|
||||||
|
}
|
||||||
|
pub fn ptr(&self) -> LocalSyntaxPtr {
|
||||||
|
self.ptr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ScopesWithSyntaxMapping {
|
||||||
pub fn scope_chain<'a>(&'a self, node: SyntaxNodeRef) -> impl Iterator<Item = ScopeId> + 'a {
|
pub fn scope_chain<'a>(&'a self, node: SyntaxNodeRef) -> impl Iterator<Item = ScopeId> + 'a {
|
||||||
generate(self.scope_for(node), move |&scope| {
|
generate(self.scope_for(node), move |&scope| {
|
||||||
self.scopes[scope].parent
|
self.scopes.scopes[scope].parent
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
pub fn scope_chain_for_offset<'a>(
|
pub fn scope_chain_for_offset<'a>(
|
||||||
|
@ -63,26 +138,30 @@ impl FnScopes {
|
||||||
offset: TextUnit,
|
offset: TextUnit,
|
||||||
) -> impl Iterator<Item = ScopeId> + 'a {
|
) -> impl Iterator<Item = ScopeId> + 'a {
|
||||||
let scope = self
|
let scope = self
|
||||||
|
.scopes
|
||||||
.scope_for
|
.scope_for
|
||||||
.iter()
|
.iter()
|
||||||
// find containin scope
|
.filter_map(|(id, scope)| Some((self.syntax_mapping.expr_syntax(*id)?, scope)))
|
||||||
|
// find containing scope
|
||||||
.min_by_key(|(ptr, _scope)| {
|
.min_by_key(|(ptr, _scope)| {
|
||||||
(
|
(
|
||||||
!(ptr.range().start() <= offset && offset <= ptr.range().end()),
|
!(ptr.range().start() <= offset && offset <= ptr.range().end()),
|
||||||
ptr.range().len(),
|
ptr.range().len(),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.map(|(ptr, scope)| self.adjust(*ptr, *scope, offset));
|
.map(|(ptr, scope)| self.adjust(ptr, *scope, offset));
|
||||||
|
|
||||||
generate(scope, move |&scope| self.scopes[scope].parent)
|
generate(scope, move |&scope| self.scopes.scopes[scope].parent)
|
||||||
}
|
}
|
||||||
// XXX: during completion, cursor might be outside of any particular
|
// XXX: during completion, cursor might be outside of any particular
|
||||||
// expression. Try to figure out the correct scope...
|
// expression. Try to figure out the correct scope...
|
||||||
fn adjust(&self, ptr: LocalSyntaxPtr, original_scope: ScopeId, offset: TextUnit) -> ScopeId {
|
fn adjust(&self, ptr: LocalSyntaxPtr, original_scope: ScopeId, offset: TextUnit) -> ScopeId {
|
||||||
let r = ptr.range();
|
let r = ptr.range();
|
||||||
let child_scopes = self
|
let child_scopes = self
|
||||||
|
.scopes
|
||||||
.scope_for
|
.scope_for
|
||||||
.iter()
|
.iter()
|
||||||
|
.filter_map(|(id, scope)| Some((self.syntax_mapping.expr_syntax(*id)?, scope)))
|
||||||
.map(|(ptr, scope)| (ptr.range(), scope))
|
.map(|(ptr, scope)| (ptr.range(), scope))
|
||||||
.filter(|(range, _)| range.start() <= offset && range.is_subrange(&r) && *range != r);
|
.filter(|(range, _)| range.start() <= offset && range.is_subrange(&r) && *range != r);
|
||||||
|
|
||||||
|
@ -100,22 +179,27 @@ impl FnScopes {
|
||||||
.unwrap_or(original_scope)
|
.unwrap_or(original_scope)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resolve_local_name<'a>(&'a self, name_ref: ast::NameRef) -> Option<&'a ScopeEntry> {
|
pub fn resolve_local_name(&self, name_ref: ast::NameRef) -> Option<ScopeEntryWithSyntax> {
|
||||||
let mut shadowed = FxHashSet::default();
|
let mut shadowed = FxHashSet::default();
|
||||||
let name = name_ref.as_name();
|
let name = name_ref.as_name();
|
||||||
let ret = self
|
let ret = self
|
||||||
.scope_chain(name_ref.syntax())
|
.scope_chain(name_ref.syntax())
|
||||||
.flat_map(|scope| self.entries(scope).iter())
|
.flat_map(|scope| self.scopes.entries(scope).iter())
|
||||||
.filter(|entry| shadowed.insert(entry.name()))
|
.filter(|entry| shadowed.insert(entry.name()))
|
||||||
.filter(|entry| entry.name() == &name)
|
.filter(|entry| entry.name() == &name)
|
||||||
.nth(0);
|
.nth(0);
|
||||||
ret
|
ret.and_then(|entry| {
|
||||||
|
Some(ScopeEntryWithSyntax {
|
||||||
|
name: entry.name().clone(),
|
||||||
|
ptr: self.syntax_mapping.pat_syntax(entry.pat())?,
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn find_all_refs(&self, pat: ast::BindPat) -> Vec<ReferenceDescriptor> {
|
pub fn find_all_refs(&self, pat: ast::BindPat) -> Vec<ReferenceDescriptor> {
|
||||||
let fn_def = pat.syntax().ancestors().find_map(ast::FnDef::cast).unwrap();
|
let fn_def = pat.syntax().ancestors().find_map(ast::FnDef::cast).unwrap();
|
||||||
let name_ptr = LocalSyntaxPtr::new(pat.syntax());
|
let name_ptr = LocalSyntaxPtr::new(pat.syntax());
|
||||||
let refs: Vec<_> = fn_def
|
fn_def
|
||||||
.syntax()
|
.syntax()
|
||||||
.descendants()
|
.descendants()
|
||||||
.filter_map(ast::NameRef::cast)
|
.filter_map(ast::NameRef::cast)
|
||||||
|
@ -127,203 +211,95 @@ impl FnScopes {
|
||||||
name: name_ref.syntax().text().to_string(),
|
name: name_ref.syntax().text().to_string(),
|
||||||
range: name_ref.syntax().range(),
|
range: name_ref.syntax().range(),
|
||||||
})
|
})
|
||||||
.collect();
|
.collect()
|
||||||
|
|
||||||
refs
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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, scope: ScopeId, pat: ast::Pat) {
|
|
||||||
let entries = pat
|
|
||||||
.syntax()
|
|
||||||
.descendants()
|
|
||||||
.filter_map(ast::BindPat::cast)
|
|
||||||
.filter_map(ScopeEntry::new);
|
|
||||||
self.scopes[scope].entries.extend(entries);
|
|
||||||
}
|
|
||||||
fn add_params_bindings(&mut self, scope: ScopeId, params: Option<ast::ParamList>) {
|
|
||||||
params
|
|
||||||
.into_iter()
|
|
||||||
.flat_map(|it| it.params())
|
|
||||||
.filter_map(|it| it.pat())
|
|
||||||
.for_each(|it| self.add_bindings(scope, it));
|
|
||||||
}
|
|
||||||
fn set_scope(&mut self, node: SyntaxNodeRef, scope: ScopeId) {
|
|
||||||
self.scope_for.insert(LocalSyntaxPtr::new(node), scope);
|
|
||||||
}
|
|
||||||
fn scope_for(&self, node: SyntaxNodeRef) -> Option<ScopeId> {
|
fn scope_for(&self, node: SyntaxNodeRef) -> Option<ScopeId> {
|
||||||
node.ancestors()
|
node.ancestors()
|
||||||
.map(LocalSyntaxPtr::new)
|
.map(LocalSyntaxPtr::new)
|
||||||
.filter_map(|it| self.scope_for.get(&it).map(|&scope| scope))
|
.filter_map(|ptr| self.syntax_mapping.syntax_expr(ptr))
|
||||||
|
.filter_map(|it| self.scopes.scope_for(it))
|
||||||
.next()
|
.next()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ScopeEntry {
|
impl ScopeEntry {
|
||||||
fn new(pat: ast::BindPat) -> Option<ScopeEntry> {
|
|
||||||
let name = pat.name()?.as_name();
|
|
||||||
let res = ScopeEntry {
|
|
||||||
name,
|
|
||||||
ptr: LocalSyntaxPtr::new(pat.syntax()),
|
|
||||||
};
|
|
||||||
Some(res)
|
|
||||||
}
|
|
||||||
pub fn name(&self) -> &Name {
|
pub fn name(&self) -> &Name {
|
||||||
&self.name
|
&self.name
|
||||||
}
|
}
|
||||||
pub fn ptr(&self) -> LocalSyntaxPtr {
|
pub fn pat(&self) -> PatId {
|
||||||
self.ptr
|
self.pat
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compute_block_scopes(block: ast::Block, scopes: &mut FnScopes, mut scope: ScopeId) {
|
fn compute_block_scopes(
|
||||||
// A hack for completion :(
|
statements: &[Statement],
|
||||||
scopes.set_scope(block.syntax(), scope);
|
tail: Option<ExprId>,
|
||||||
for stmt in block.statements() {
|
body: &Body,
|
||||||
|
scopes: &mut FnScopes,
|
||||||
|
mut scope: ScopeId,
|
||||||
|
) {
|
||||||
|
for stmt in statements {
|
||||||
match stmt {
|
match stmt {
|
||||||
ast::Stmt::LetStmt(stmt) => {
|
Statement::Let {
|
||||||
if let Some(expr) = stmt.initializer() {
|
pat, initializer, ..
|
||||||
scopes.set_scope(expr.syntax(), scope);
|
} => {
|
||||||
compute_expr_scopes(expr, scopes, scope);
|
if let Some(expr) = initializer {
|
||||||
|
scopes.set_scope(*expr, scope);
|
||||||
|
compute_expr_scopes(*expr, body, scopes, scope);
|
||||||
}
|
}
|
||||||
scope = scopes.new_scope(scope);
|
scope = scopes.new_scope(scope);
|
||||||
if let Some(pat) = stmt.pat() {
|
scopes.add_bindings(body, scope, *pat);
|
||||||
scopes.add_bindings(scope, pat);
|
|
||||||
}
|
}
|
||||||
}
|
Statement::Expr(expr) => {
|
||||||
ast::Stmt::ExprStmt(expr_stmt) => {
|
scopes.set_scope(*expr, scope);
|
||||||
if let Some(expr) = expr_stmt.expr() {
|
compute_expr_scopes(*expr, body, scopes, scope);
|
||||||
scopes.set_scope(expr.syntax(), scope);
|
|
||||||
compute_expr_scopes(expr, scopes, scope);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
if let Some(expr) = tail {
|
||||||
if let Some(expr) = block.expr() {
|
compute_expr_scopes(expr, body, scopes, scope);
|
||||||
scopes.set_scope(expr.syntax(), scope);
|
|
||||||
compute_expr_scopes(expr, scopes, scope);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compute_expr_scopes(expr: ast::Expr, scopes: &mut FnScopes, scope: ScopeId) {
|
fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut FnScopes, scope: ScopeId) {
|
||||||
match expr {
|
scopes.set_scope(expr, scope);
|
||||||
ast::Expr::IfExpr(e) => {
|
match body.expr(expr) {
|
||||||
let cond_scope = e
|
Expr::Block { statements, tail } => {
|
||||||
.condition()
|
compute_block_scopes(&statements, *tail, body, scopes, scope);
|
||||||
.and_then(|cond| compute_cond_scopes(cond, scopes, scope));
|
|
||||||
if let Some(block) = e.then_branch() {
|
|
||||||
compute_block_scopes(block, scopes, cond_scope.unwrap_or(scope));
|
|
||||||
}
|
}
|
||||||
if let Some(block) = e.else_branch() {
|
Expr::For {
|
||||||
compute_block_scopes(block, scopes, scope);
|
iterable,
|
||||||
}
|
pat,
|
||||||
}
|
body: body_expr,
|
||||||
ast::Expr::BlockExpr(e) => {
|
} => {
|
||||||
if let Some(block) = e.block() {
|
compute_expr_scopes(*iterable, body, scopes, scope);
|
||||||
compute_block_scopes(block, scopes, scope);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ast::Expr::LoopExpr(e) => {
|
|
||||||
if let Some(block) = e.loop_body() {
|
|
||||||
compute_block_scopes(block, scopes, scope);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ast::Expr::WhileExpr(e) => {
|
|
||||||
let cond_scope = e
|
|
||||||
.condition()
|
|
||||||
.and_then(|cond| compute_cond_scopes(cond, scopes, scope));
|
|
||||||
if let Some(block) = e.loop_body() {
|
|
||||||
compute_block_scopes(block, scopes, cond_scope.unwrap_or(scope));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ast::Expr::ForExpr(e) => {
|
|
||||||
if let Some(expr) = e.iterable() {
|
|
||||||
compute_expr_scopes(expr, scopes, scope);
|
|
||||||
}
|
|
||||||
let mut scope = scope;
|
|
||||||
if let Some(pat) = e.pat() {
|
|
||||||
scope = scopes.new_scope(scope);
|
|
||||||
scopes.add_bindings(scope, pat);
|
|
||||||
}
|
|
||||||
if let Some(block) = e.loop_body() {
|
|
||||||
compute_block_scopes(block, scopes, scope);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ast::Expr::LambdaExpr(e) => {
|
|
||||||
let scope = scopes.new_scope(scope);
|
let scope = scopes.new_scope(scope);
|
||||||
scopes.add_params_bindings(scope, e.param_list());
|
scopes.add_bindings(body, scope, *pat);
|
||||||
if let Some(body) = e.body() {
|
compute_expr_scopes(*body_expr, body, scopes, scope);
|
||||||
scopes.set_scope(body.syntax(), scope);
|
|
||||||
compute_expr_scopes(body, scopes, scope);
|
|
||||||
}
|
}
|
||||||
}
|
Expr::Lambda {
|
||||||
ast::Expr::CallExpr(e) => {
|
args,
|
||||||
compute_call_scopes(e.expr(), e.arg_list(), scopes, scope);
|
body: body_expr,
|
||||||
}
|
..
|
||||||
ast::Expr::MethodCallExpr(e) => {
|
} => {
|
||||||
compute_call_scopes(e.expr(), e.arg_list(), scopes, scope);
|
|
||||||
}
|
|
||||||
ast::Expr::MatchExpr(e) => {
|
|
||||||
if let Some(expr) = e.expr() {
|
|
||||||
compute_expr_scopes(expr, scopes, scope);
|
|
||||||
}
|
|
||||||
for arm in e.match_arm_list().into_iter().flat_map(|it| it.arms()) {
|
|
||||||
let scope = scopes.new_scope(scope);
|
let scope = scopes.new_scope(scope);
|
||||||
for pat in arm.pats() {
|
scopes.add_params_bindings(scope, &args);
|
||||||
scopes.add_bindings(scope, pat);
|
compute_expr_scopes(*body_expr, body, scopes, scope);
|
||||||
}
|
}
|
||||||
if let Some(expr) = arm.expr() {
|
Expr::Match { expr, arms } => {
|
||||||
compute_expr_scopes(expr, scopes, scope);
|
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)),
|
||||||
_ => expr
|
|
||||||
.syntax()
|
|
||||||
.children()
|
|
||||||
.filter_map(ast::Expr::cast)
|
|
||||||
.for_each(|expr| compute_expr_scopes(expr, scopes, scope)),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
fn compute_call_scopes(
|
|
||||||
receiver: Option<ast::Expr>,
|
|
||||||
arg_list: Option<ast::ArgList>,
|
|
||||||
scopes: &mut FnScopes,
|
|
||||||
scope: ScopeId,
|
|
||||||
) {
|
|
||||||
arg_list
|
|
||||||
.into_iter()
|
|
||||||
.flat_map(|it| it.args())
|
|
||||||
.chain(receiver)
|
|
||||||
.for_each(|expr| compute_expr_scopes(expr, scopes, scope));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn compute_cond_scopes(
|
|
||||||
cond: ast::Condition,
|
|
||||||
scopes: &mut FnScopes,
|
|
||||||
scope: ScopeId,
|
|
||||||
) -> Option<ScopeId> {
|
|
||||||
if let Some(expr) = cond.expr() {
|
|
||||||
compute_expr_scopes(expr, scopes, scope);
|
|
||||||
}
|
|
||||||
if let Some(pat) = cond.pat() {
|
|
||||||
let s = scopes.new_scope(scope);
|
|
||||||
scopes.add_bindings(s, pat);
|
|
||||||
Some(s)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -338,6 +314,8 @@ mod tests {
|
||||||
use ra_syntax::SourceFileNode;
|
use ra_syntax::SourceFileNode;
|
||||||
use test_utils::{extract_offset, assert_eq_text};
|
use test_utils::{extract_offset, assert_eq_text};
|
||||||
|
|
||||||
|
use crate::expr;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
fn do_check(code: &str, expected: &[&str]) {
|
fn do_check(code: &str, expected: &[&str]) {
|
||||||
|
@ -353,15 +331,20 @@ mod tests {
|
||||||
let file = SourceFileNode::parse(&code);
|
let file = SourceFileNode::parse(&code);
|
||||||
let marker: ast::PathExpr = find_node_at_offset(file.syntax(), off).unwrap();
|
let marker: ast::PathExpr = find_node_at_offset(file.syntax(), off).unwrap();
|
||||||
let fn_def: ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap();
|
let fn_def: ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap();
|
||||||
let scopes = FnScopes::new(fn_def);
|
let body_hir = expr::collect_fn_body_syntax(fn_def);
|
||||||
|
let scopes = FnScopes::new(Arc::clone(body_hir.body()));
|
||||||
|
let scopes = ScopesWithSyntaxMapping {
|
||||||
|
scopes: Arc::new(scopes),
|
||||||
|
syntax_mapping: Arc::new(body_hir),
|
||||||
|
};
|
||||||
let actual = scopes
|
let actual = scopes
|
||||||
.scope_chain(marker.syntax())
|
.scope_chain(marker.syntax())
|
||||||
.flat_map(|scope| scopes.entries(scope))
|
.flat_map(|scope| scopes.scopes.entries(scope))
|
||||||
.map(|it| it.name().to_string())
|
.map(|it| it.name().to_string())
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join("\n");
|
.join("\n");
|
||||||
let expected = expected.join("\n");
|
let expected = expected.join("\n");
|
||||||
assert_eq_text!(&actual, &expected);
|
assert_eq_text!(&expected, &actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -389,7 +372,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_metod_call_scope() {
|
fn test_method_call_scope() {
|
||||||
do_check(
|
do_check(
|
||||||
r"
|
r"
|
||||||
fn quux() {
|
fn quux() {
|
||||||
|
@ -445,10 +428,15 @@ mod tests {
|
||||||
let fn_def: ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap();
|
let fn_def: ast::FnDef = find_node_at_offset(file.syntax(), off).unwrap();
|
||||||
let name_ref: ast::NameRef = find_node_at_offset(file.syntax(), off).unwrap();
|
let name_ref: ast::NameRef = find_node_at_offset(file.syntax(), off).unwrap();
|
||||||
|
|
||||||
let scopes = FnScopes::new(fn_def);
|
let body_hir = expr::collect_fn_body_syntax(fn_def);
|
||||||
|
let scopes = FnScopes::new(Arc::clone(body_hir.body()));
|
||||||
|
let scopes = ScopesWithSyntaxMapping {
|
||||||
|
scopes: Arc::new(scopes),
|
||||||
|
syntax_mapping: Arc::new(body_hir),
|
||||||
|
};
|
||||||
|
|
||||||
let local_name_entry = scopes.resolve_local_name(name_ref).unwrap();
|
let local_name_entry = scopes.resolve_local_name(name_ref).unwrap();
|
||||||
let local_name = local_name_entry.ptr().resolve(&file);
|
let local_name = local_name_entry.ptr();
|
||||||
let expected_name =
|
let expected_name =
|
||||||
find_node_at_offset::<ast::Name>(file.syntax(), expected_offset.into()).unwrap();
|
find_node_at_offset::<ast::Name>(file.syntax(), expected_offset.into()).unwrap();
|
||||||
assert_eq!(local_name.range(), expected_name.syntax().range());
|
assert_eq!(local_name.range(), expected_name.syntax().range());
|
||||||
|
|
|
@ -47,7 +47,7 @@ pub use self::{
|
||||||
ids::{HirFileId, DefId, DefLoc, MacroCallId, MacroCallLoc},
|
ids::{HirFileId, DefId, DefLoc, MacroCallId, MacroCallLoc},
|
||||||
macros::{MacroDef, MacroInput, MacroExpansion},
|
macros::{MacroDef, MacroInput, MacroExpansion},
|
||||||
module::{Module, ModuleId, Problem, nameres::{ItemMap, PerNs, Namespace}, ModuleScope, Resolution},
|
module::{Module, ModuleId, Problem, nameres::{ItemMap, PerNs, Namespace}, ModuleScope, Resolution},
|
||||||
function::{Function, FnScopes},
|
function::{Function, FnScopes, ScopesWithSyntaxMapping},
|
||||||
adt::{Struct, Enum},
|
adt::{Struct, Enum},
|
||||||
ty::Ty,
|
ty::Ty,
|
||||||
impl_block::{ImplBlock, ImplItem},
|
impl_block::{ImplBlock, ImplItem},
|
||||||
|
|
|
@ -31,6 +31,10 @@ impl Name {
|
||||||
Name::new("[missing name]".into())
|
Name::new("[missing name]".into())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn self_param() -> Name {
|
||||||
|
Name::new("self".into())
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn tuple_field_name(idx: usize) -> Name {
|
pub(crate) fn tuple_field_name(idx: usize) -> Name {
|
||||||
Name::new(idx.to_string().into())
|
Name::new(idx.to_string().into())
|
||||||
}
|
}
|
||||||
|
@ -51,7 +55,8 @@ impl Name {
|
||||||
"u128" => KnownName::U128,
|
"u128" => KnownName::U128,
|
||||||
"f32" => KnownName::F32,
|
"f32" => KnownName::F32,
|
||||||
"f64" => KnownName::F64,
|
"f64" => KnownName::F64,
|
||||||
"Self" => KnownName::Self_,
|
"Self" => KnownName::SelfType,
|
||||||
|
"self" => KnownName::SelfParam,
|
||||||
_ => return None,
|
_ => return None,
|
||||||
};
|
};
|
||||||
Some(name)
|
Some(name)
|
||||||
|
@ -104,5 +109,6 @@ pub(crate) enum KnownName {
|
||||||
F32,
|
F32,
|
||||||
F64,
|
F64,
|
||||||
|
|
||||||
Self_,
|
SelfType,
|
||||||
|
SelfParam,
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ use ra_syntax::{
|
||||||
use ra_db::{SourceRootId, Cancelable,};
|
use ra_db::{SourceRootId, Cancelable,};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
SourceFileItems, SourceItemId, DefKind, Function, DefId, Name, AsName, HirFileId,
|
SourceFileItems, SourceItemId, DefKind, DefId, Name, AsName, HirFileId,
|
||||||
MacroCallLoc,
|
MacroCallLoc,
|
||||||
db::HirDatabase,
|
db::HirDatabase,
|
||||||
function::FnScopes,
|
function::FnScopes,
|
||||||
|
@ -23,11 +23,10 @@ use crate::{
|
||||||
adt::{StructData, EnumData},
|
adt::{StructData, EnumData},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(super) fn fn_scopes(db: &impl HirDatabase, def_id: DefId) -> Arc<FnScopes> {
|
pub(super) fn fn_scopes(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Arc<FnScopes>> {
|
||||||
let function = Function::new(def_id);
|
let body = db.body_hir(def_id)?;
|
||||||
let syntax = function.syntax(db);
|
let res = FnScopes::new(body);
|
||||||
let res = FnScopes::new(syntax.borrowed());
|
Ok(Arc::new(res))
|
||||||
Arc::new(res)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn struct_data(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Arc<StructData>> {
|
pub(super) fn struct_data(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Arc<StructData>> {
|
||||||
|
|
|
@ -31,10 +31,11 @@ use ra_syntax::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
Def, DefId, FnScopes, Module, Function, Struct, Enum, Path, Name, AsName, ImplBlock,
|
Def, DefId, Module, Function, Struct, Enum, Path, Name, AsName, ImplBlock,
|
||||||
db::HirDatabase,
|
db::HirDatabase,
|
||||||
type_ref::{TypeRef, Mutability},
|
type_ref::{TypeRef, Mutability},
|
||||||
name::KnownName,
|
name::KnownName,
|
||||||
|
ScopesWithSyntaxMapping,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The ID of a type variable.
|
/// The ID of a type variable.
|
||||||
|
@ -305,7 +306,7 @@ impl Ty {
|
||||||
return Ok(Ty::Uint(uint_ty));
|
return Ok(Ty::Uint(uint_ty));
|
||||||
} else if let Some(float_ty) = primitive::FloatTy::from_name(name) {
|
} else if let Some(float_ty) = primitive::FloatTy::from_name(name) {
|
||||||
return Ok(Ty::Float(float_ty));
|
return Ok(Ty::Float(float_ty));
|
||||||
} else if name.as_known_name() == Some(KnownName::Self_) {
|
} else if name.as_known_name() == Some(KnownName::SelfType) {
|
||||||
return Ty::from_hir_opt(db, module, None, impl_block.map(|i| i.target_type()));
|
return Ty::from_hir_opt(db, module, None, impl_block.map(|i| i.target_type()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -515,7 +516,7 @@ impl InferenceResult {
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
struct InferenceContext<'a, D: HirDatabase> {
|
struct InferenceContext<'a, D: HirDatabase> {
|
||||||
db: &'a D,
|
db: &'a D,
|
||||||
scopes: Arc<FnScopes>,
|
scopes: ScopesWithSyntaxMapping,
|
||||||
/// The self param for the current method, if it exists.
|
/// The self param for the current method, if it exists.
|
||||||
self_param: Option<LocalSyntaxPtr>,
|
self_param: Option<LocalSyntaxPtr>,
|
||||||
module: Module,
|
module: Module,
|
||||||
|
@ -529,7 +530,7 @@ struct InferenceContext<'a, D: HirDatabase> {
|
||||||
impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
fn new(
|
fn new(
|
||||||
db: &'a D,
|
db: &'a D,
|
||||||
scopes: Arc<FnScopes>,
|
scopes: ScopesWithSyntaxMapping,
|
||||||
module: Module,
|
module: Module,
|
||||||
impl_block: Option<ImplBlock>,
|
impl_block: Option<ImplBlock>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
@ -826,10 +827,6 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
self.infer_expr_opt(e.expr(), &Expectation::none())?;
|
self.infer_expr_opt(e.expr(), &Expectation::none())?;
|
||||||
Ty::Never
|
Ty::Never
|
||||||
}
|
}
|
||||||
ast::Expr::MatchArmList(_) | ast::Expr::MatchArm(_) | ast::Expr::MatchGuard(_) => {
|
|
||||||
// Can this even occur outside of a match expression?
|
|
||||||
Ty::Unknown
|
|
||||||
}
|
|
||||||
ast::Expr::StructLit(e) => {
|
ast::Expr::StructLit(e) => {
|
||||||
let (ty, def_id) = self.resolve_variant(e.path())?;
|
let (ty, def_id) = self.resolve_variant(e.path())?;
|
||||||
if let Some(nfl) = e.named_field_list() {
|
if let Some(nfl) = e.named_field_list() {
|
||||||
|
@ -845,10 +842,6 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
}
|
}
|
||||||
ty
|
ty
|
||||||
}
|
}
|
||||||
ast::Expr::NamedFieldList(_) | ast::Expr::NamedField(_) => {
|
|
||||||
// Can this even occur outside of a struct literal?
|
|
||||||
Ty::Unknown
|
|
||||||
}
|
|
||||||
ast::Expr::IndexExpr(_e) => Ty::Unknown,
|
ast::Expr::IndexExpr(_e) => Ty::Unknown,
|
||||||
ast::Expr::FieldExpr(e) => {
|
ast::Expr::FieldExpr(e) => {
|
||||||
let receiver_ty = self.infer_expr_opt(e.expr(), &Expectation::none())?;
|
let receiver_ty = self.infer_expr_opt(e.expr(), &Expectation::none())?;
|
||||||
|
@ -1016,7 +1009,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||||
|
|
||||||
pub fn infer(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Arc<InferenceResult>> {
|
pub fn infer(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Arc<InferenceResult>> {
|
||||||
let function = Function::new(def_id); // TODO: consts also need inference
|
let function = Function::new(def_id); // TODO: consts also need inference
|
||||||
let scopes = function.scopes(db);
|
let scopes = function.scopes(db)?;
|
||||||
let module = function.module(db)?;
|
let module = function.module(db)?;
|
||||||
let impl_block = function.impl_block(db)?;
|
let impl_block = function.impl_block(db)?;
|
||||||
let mut ctx = InferenceContext::new(db, scopes, module, impl_block);
|
let mut ctx = InferenceContext::new(db, scopes, module, impl_block);
|
||||||
|
|
|
@ -927,12 +927,7 @@ pub enum Expr<'a> {
|
||||||
BlockExpr(BlockExpr<'a>),
|
BlockExpr(BlockExpr<'a>),
|
||||||
ReturnExpr(ReturnExpr<'a>),
|
ReturnExpr(ReturnExpr<'a>),
|
||||||
MatchExpr(MatchExpr<'a>),
|
MatchExpr(MatchExpr<'a>),
|
||||||
MatchArmList(MatchArmList<'a>),
|
|
||||||
MatchArm(MatchArm<'a>),
|
|
||||||
MatchGuard(MatchGuard<'a>),
|
|
||||||
StructLit(StructLit<'a>),
|
StructLit(StructLit<'a>),
|
||||||
NamedFieldList(NamedFieldList<'a>),
|
|
||||||
NamedField(NamedField<'a>),
|
|
||||||
CallExpr(CallExpr<'a>),
|
CallExpr(CallExpr<'a>),
|
||||||
IndexExpr(IndexExpr<'a>),
|
IndexExpr(IndexExpr<'a>),
|
||||||
MethodCallExpr(MethodCallExpr<'a>),
|
MethodCallExpr(MethodCallExpr<'a>),
|
||||||
|
@ -964,12 +959,7 @@ impl<'a> AstNode<'a> for Expr<'a> {
|
||||||
BLOCK_EXPR => Some(Expr::BlockExpr(BlockExpr { syntax })),
|
BLOCK_EXPR => Some(Expr::BlockExpr(BlockExpr { syntax })),
|
||||||
RETURN_EXPR => Some(Expr::ReturnExpr(ReturnExpr { syntax })),
|
RETURN_EXPR => Some(Expr::ReturnExpr(ReturnExpr { syntax })),
|
||||||
MATCH_EXPR => Some(Expr::MatchExpr(MatchExpr { syntax })),
|
MATCH_EXPR => Some(Expr::MatchExpr(MatchExpr { syntax })),
|
||||||
MATCH_ARM_LIST => Some(Expr::MatchArmList(MatchArmList { syntax })),
|
|
||||||
MATCH_ARM => Some(Expr::MatchArm(MatchArm { syntax })),
|
|
||||||
MATCH_GUARD => Some(Expr::MatchGuard(MatchGuard { syntax })),
|
|
||||||
STRUCT_LIT => Some(Expr::StructLit(StructLit { syntax })),
|
STRUCT_LIT => Some(Expr::StructLit(StructLit { syntax })),
|
||||||
NAMED_FIELD_LIST => Some(Expr::NamedFieldList(NamedFieldList { syntax })),
|
|
||||||
NAMED_FIELD => Some(Expr::NamedField(NamedField { syntax })),
|
|
||||||
CALL_EXPR => Some(Expr::CallExpr(CallExpr { syntax })),
|
CALL_EXPR => Some(Expr::CallExpr(CallExpr { syntax })),
|
||||||
INDEX_EXPR => Some(Expr::IndexExpr(IndexExpr { syntax })),
|
INDEX_EXPR => Some(Expr::IndexExpr(IndexExpr { syntax })),
|
||||||
METHOD_CALL_EXPR => Some(Expr::MethodCallExpr(MethodCallExpr { syntax })),
|
METHOD_CALL_EXPR => Some(Expr::MethodCallExpr(MethodCallExpr { syntax })),
|
||||||
|
@ -1001,12 +991,7 @@ impl<'a> AstNode<'a> for Expr<'a> {
|
||||||
Expr::BlockExpr(inner) => inner.syntax(),
|
Expr::BlockExpr(inner) => inner.syntax(),
|
||||||
Expr::ReturnExpr(inner) => inner.syntax(),
|
Expr::ReturnExpr(inner) => inner.syntax(),
|
||||||
Expr::MatchExpr(inner) => inner.syntax(),
|
Expr::MatchExpr(inner) => inner.syntax(),
|
||||||
Expr::MatchArmList(inner) => inner.syntax(),
|
|
||||||
Expr::MatchArm(inner) => inner.syntax(),
|
|
||||||
Expr::MatchGuard(inner) => inner.syntax(),
|
|
||||||
Expr::StructLit(inner) => inner.syntax(),
|
Expr::StructLit(inner) => inner.syntax(),
|
||||||
Expr::NamedFieldList(inner) => inner.syntax(),
|
|
||||||
Expr::NamedField(inner) => inner.syntax(),
|
|
||||||
Expr::CallExpr(inner) => inner.syntax(),
|
Expr::CallExpr(inner) => inner.syntax(),
|
||||||
Expr::IndexExpr(inner) => inner.syntax(),
|
Expr::IndexExpr(inner) => inner.syntax(),
|
||||||
Expr::MethodCallExpr(inner) => inner.syntax(),
|
Expr::MethodCallExpr(inner) => inner.syntax(),
|
||||||
|
@ -4155,7 +4140,15 @@ impl<R: TreeRoot<RaTypes>> TupleStructPatNode<R> {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl<'a> TupleStructPat<'a> {}
|
impl<'a> TupleStructPat<'a> {
|
||||||
|
pub fn args(self) -> impl Iterator<Item = Pat<'a>> + 'a {
|
||||||
|
super::children(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn path(self) -> Option<Path<'a>> {
|
||||||
|
super::child_opt(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TupleType
|
// TupleType
|
||||||
#[derive(Debug, Clone, Copy,)]
|
#[derive(Debug, Clone, Copy,)]
|
||||||
|
|
|
@ -446,12 +446,7 @@ Grammar(
|
||||||
"BlockExpr",
|
"BlockExpr",
|
||||||
"ReturnExpr",
|
"ReturnExpr",
|
||||||
"MatchExpr",
|
"MatchExpr",
|
||||||
"MatchArmList",
|
|
||||||
"MatchArm",
|
|
||||||
"MatchGuard",
|
|
||||||
"StructLit",
|
"StructLit",
|
||||||
"NamedFieldList",
|
|
||||||
"NamedField",
|
|
||||||
"CallExpr",
|
"CallExpr",
|
||||||
"IndexExpr",
|
"IndexExpr",
|
||||||
"MethodCallExpr",
|
"MethodCallExpr",
|
||||||
|
@ -472,7 +467,10 @@ Grammar(
|
||||||
"PathPat": (),
|
"PathPat": (),
|
||||||
"StructPat": (),
|
"StructPat": (),
|
||||||
"FieldPatList": (),
|
"FieldPatList": (),
|
||||||
"TupleStructPat": (),
|
"TupleStructPat": (
|
||||||
|
options: ["Path"],
|
||||||
|
collections: [["args", "Pat"]],
|
||||||
|
),
|
||||||
"TuplePat": (),
|
"TuplePat": (),
|
||||||
"SlicePat": (),
|
"SlicePat": (),
|
||||||
"RangePat": (),
|
"RangePat": (),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue