mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-06 12:04:36 +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
@ -15,7 +15,7 @@ pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) ->
|
||||
None => return Ok(()),
|
||||
};
|
||||
if let Some(function) = &ctx.function {
|
||||
let scopes = function.scopes(ctx.db);
|
||||
let scopes = function.scopes(ctx.db)?;
|
||||
complete_fn(acc, &scopes, ctx.offset);
|
||||
}
|
||||
|
||||
@ -40,20 +40,17 @@ pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) ->
|
||||
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();
|
||||
scopes
|
||||
.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()))
|
||||
.for_each(|entry| {
|
||||
CompletionItem::new(CompletionKind::Reference, entry.name().to_string())
|
||||
.kind(CompletionItemKind::Binding)
|
||||
.add_to(acc)
|
||||
});
|
||||
if scopes.self_param.is_some() {
|
||||
CompletionItem::new(CompletionKind::Reference, "self").add_to(acc);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -28,7 +28,7 @@ pub(crate) fn reference_defenition(
|
||||
if let Some(fn_descr) =
|
||||
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
|
||||
if let Some(entry) = scope.resolve_local_name(name_ref) {
|
||||
let nav = NavigationTarget {
|
||||
|
@ -157,7 +157,7 @@ impl db::RootDatabase {
|
||||
.collect::<Vec<_>>();
|
||||
ret.extend(
|
||||
descr
|
||||
.scopes(self)
|
||||
.scopes(self)?
|
||||
.find_all_refs(binding)
|
||||
.into_iter()
|
||||
.map(|ref_desc| (position.file_id, ref_desc.range)),
|
||||
@ -185,7 +185,7 @@ impl db::RootDatabase {
|
||||
position.file_id,
|
||||
name_ref.syntax(),
|
||||
)?);
|
||||
let scope = descr.scopes(db);
|
||||
let scope = descr.scopes(db)?;
|
||||
let resolved = ctry!(scope.resolve_local_name(name_ref));
|
||||
let resolved = resolved.ptr().resolve(source_file);
|
||||
let binding = ctry!(find_node_at_offset::<ast::BindPat>(
|
||||
|
@ -31,7 +31,7 @@ pub trait HirDatabase: SyntaxDatabase
|
||||
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;
|
||||
use fn query_definitions::fn_scopes;
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ use rustc_hash::FxHashMap;
|
||||
|
||||
use ra_arena::{Arena, RawId, impl_arena_id};
|
||||
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};
|
||||
|
||||
@ -21,7 +21,7 @@ pub struct Body {
|
||||
/// part of the function signature, the patterns are not (they don't change
|
||||
/// 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.
|
||||
args: Vec<PatId>,
|
||||
/// The `ExprId` of the actual body expression.
|
||||
@ -43,6 +43,43 @@ pub struct BodySyntaxMapping {
|
||||
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)]
|
||||
pub enum Expr {
|
||||
/// This is produced if syntax tree does not have a required expression piece.
|
||||
@ -113,21 +150,26 @@ pub enum Expr {
|
||||
expr: ExprId,
|
||||
op: Option<UnaryOp>,
|
||||
},
|
||||
Lambda {
|
||||
args: Vec<PatId>,
|
||||
arg_types: Vec<Option<TypeRef>>,
|
||||
body: ExprId,
|
||||
},
|
||||
}
|
||||
|
||||
pub type UnaryOp = ast::PrefixOp;
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub struct MatchArm {
|
||||
pats: Vec<PatId>,
|
||||
pub pats: Vec<PatId>,
|
||||
// guard: Option<ExprId>, // TODO
|
||||
expr: ExprId,
|
||||
pub expr: ExprId,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub struct StructLitField {
|
||||
name: Name,
|
||||
expr: ExprId,
|
||||
pub name: Name,
|
||||
pub expr: ExprId,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
@ -140,12 +182,118 @@ pub enum Statement {
|
||||
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)]
|
||||
pub struct PatId(RawId);
|
||||
impl_arena_id!(PatId);
|
||||
|
||||
#[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
|
||||
|
||||
@ -163,6 +311,17 @@ struct 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 {
|
||||
let id = self.exprs.alloc(expr);
|
||||
self.expr_syntax_mapping.insert(syntax_ptr, id);
|
||||
@ -177,30 +336,63 @@ impl ExprCollector {
|
||||
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 {
|
||||
let syntax_ptr = LocalSyntaxPtr::new(expr.syntax());
|
||||
match expr {
|
||||
ast::Expr::IfExpr(e) => {
|
||||
let condition = if let Some(condition) = e.condition() {
|
||||
if condition.pat().is_none() {
|
||||
if let Some(pat) = e.condition().and_then(|c| c.pat()) {
|
||||
// if let -- desugar to match
|
||||
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 {
|
||||
let condition = if let Some(condition) = e.condition() {
|
||||
self.collect_expr_opt(condition.expr())
|
||||
} else {
|
||||
// TODO handle if let
|
||||
return self.alloc_expr(Expr::Missing, syntax_ptr);
|
||||
}
|
||||
} else {
|
||||
self.exprs.alloc(Expr::Missing)
|
||||
};
|
||||
let then_branch = self.collect_block_opt(e.then_branch());
|
||||
let else_branch = e.else_branch().map(|e| self.collect_block(e));
|
||||
self.alloc_expr(
|
||||
Expr::If {
|
||||
condition,
|
||||
then_branch,
|
||||
else_branch,
|
||||
},
|
||||
syntax_ptr,
|
||||
)
|
||||
self.exprs.alloc(Expr::Missing)
|
||||
};
|
||||
let then_branch = self.collect_block_opt(e.then_branch());
|
||||
let else_branch = e.else_branch().map(|e| self.collect_block(e));
|
||||
self.alloc_expr(
|
||||
Expr::If {
|
||||
condition,
|
||||
then_branch,
|
||||
else_branch,
|
||||
},
|
||||
syntax_ptr,
|
||||
)
|
||||
}
|
||||
}
|
||||
ast::Expr::BlockExpr(e) => self.collect_block_opt(e.block()),
|
||||
ast::Expr::LoopExpr(e) => {
|
||||
@ -368,18 +560,30 @@ impl ExprCollector {
|
||||
let op = e.op();
|
||||
self.alloc_expr(Expr::UnaryOp { expr, op }, syntax_ptr)
|
||||
}
|
||||
|
||||
// We should never get to these because they're handled in MatchExpr resp. StructLit:
|
||||
ast::Expr::MatchArmList(_) | ast::Expr::MatchArm(_) | ast::Expr::MatchGuard(_) => {
|
||||
panic!("collect_expr called on {:?}", expr)
|
||||
}
|
||||
ast::Expr::NamedFieldList(_) | ast::Expr::NamedField(_) => {
|
||||
panic!("collect_expr called on {:?}", expr)
|
||||
ast::Expr::LambdaExpr(e) => {
|
||||
let mut args = Vec::new();
|
||||
let mut arg_types = Vec::new();
|
||||
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);
|
||||
}
|
||||
}
|
||||
let body = self.collect_expr_opt(e.body());
|
||||
self.alloc_expr(
|
||||
Expr::Lambda {
|
||||
args,
|
||||
arg_types,
|
||||
body,
|
||||
},
|
||||
syntax_ptr,
|
||||
)
|
||||
}
|
||||
|
||||
// TODO implement HIR for these:
|
||||
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::TupleExpr(_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 {
|
||||
let syntax_ptr = LocalSyntaxPtr::new(pat.syntax());
|
||||
// TODO
|
||||
self.alloc_pat(Pat, syntax_ptr)
|
||||
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
|
||||
self.alloc_pat(Pat::Missing, syntax_ptr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn collect_pat_opt(&mut self, pat: Option<ast::Pat>) -> PatId {
|
||||
if let Some(pat) = pat {
|
||||
self.collect_pat(pat)
|
||||
} else {
|
||||
// TODO
|
||||
self.pats.alloc(Pat)
|
||||
self.pats.alloc(Pat::Missing)
|
||||
}
|
||||
}
|
||||
|
||||
@ -461,47 +680,61 @@ impl ExprCollector {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn collect_fn_body_syntax(node: ast::FnDef) -> BodySyntaxMapping {
|
||||
let mut collector = ExprCollector::new();
|
||||
|
||||
let args = if let Some(param_list) = node.param_list() {
|
||||
let mut args = Vec::new();
|
||||
|
||||
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() {
|
||||
let pat = if let Some(pat) = param.pat() {
|
||||
pat
|
||||
} else {
|
||||
continue;
|
||||
};
|
||||
args.push(collector.collect_pat(pat));
|
||||
}
|
||||
args
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
|
||||
let body = collector.collect_block_opt(node.body());
|
||||
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 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 {
|
||||
let body_syntax_mapping = 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 mut args = Vec::new();
|
||||
// TODO self param
|
||||
for param in param_list.params() {
|
||||
let pat = if let Some(pat) = param.pat() {
|
||||
pat
|
||||
} else {
|
||||
continue;
|
||||
};
|
||||
args.push(collector.collect_pat(pat));
|
||||
}
|
||||
args
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
|
||||
let body = collector.collect_block_opt(node.body());
|
||||
(body, args)
|
||||
collect_fn_body_syntax(node)
|
||||
}
|
||||
// TODO: consts, etc.
|
||||
_ => 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},
|
||||
};
|
||||
|
||||
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)]
|
||||
pub struct Function {
|
||||
@ -36,8 +36,21 @@ impl Function {
|
||||
ast::FnDef::cast(syntax.borrowed()).unwrap().owned()
|
||||
}
|
||||
|
||||
pub fn scopes(&self, db: &impl HirDatabase) -> Arc<FnScopes> {
|
||||
db.fn_scopes(self.def_id)
|
||||
pub fn body(&self, db: &impl HirDatabase) -> Cancelable<Arc<Body>> {
|
||||
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> {
|
||||
|
@ -1,14 +1,16 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
|
||||
use ra_syntax::{
|
||||
AstNode, SyntaxNodeRef, TextUnit, TextRange,
|
||||
algo::generate,
|
||||
ast::{self, ArgListOwner, LoopBodyOwner, NameOwner},
|
||||
ast,
|
||||
};
|
||||
use ra_arena::{Arena, RawId, impl_arena_id};
|
||||
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)]
|
||||
pub struct ScopeId(RawId);
|
||||
@ -16,15 +18,15 @@ impl_arena_id!(ScopeId);
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct FnScopes {
|
||||
pub self_param: Option<LocalSyntaxPtr>,
|
||||
body: Arc<Body>,
|
||||
scopes: Arena<ScopeId, ScopeData>,
|
||||
scope_for: FxHashMap<LocalSyntaxPtr, ScopeId>,
|
||||
scope_for: FxHashMap<ExprId, ScopeId>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct ScopeEntry {
|
||||
name: Name,
|
||||
ptr: LocalSyntaxPtr,
|
||||
pat: PatId,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
@ -34,28 +36,101 @@ pub struct ScopeData {
|
||||
}
|
||||
|
||||
impl FnScopes {
|
||||
pub(crate) fn new(fn_def: ast::FnDef) -> FnScopes {
|
||||
pub(crate) fn new(body: Arc<Body>) -> FnScopes {
|
||||
let mut scopes = FnScopes {
|
||||
self_param: fn_def
|
||||
.param_list()
|
||||
.and_then(|it| it.self_param())
|
||||
.map(|it| LocalSyntaxPtr::new(it.syntax())),
|
||||
body: body.clone(),
|
||||
scopes: Arena::default(),
|
||||
scope_for: FxHashMap::default(),
|
||||
};
|
||||
let root = scopes.root_scope();
|
||||
scopes.add_params_bindings(root, fn_def.param_list());
|
||||
if let Some(body) = fn_def.body() {
|
||||
compute_block_scopes(body, &mut scopes, root)
|
||||
}
|
||||
scopes.add_params_bindings(root, body.args());
|
||||
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_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 {
|
||||
generate(self.scope_for(node), move |&scope| {
|
||||
self.scopes[scope].parent
|
||||
self.scopes.scopes[scope].parent
|
||||
})
|
||||
}
|
||||
pub fn scope_chain_for_offset<'a>(
|
||||
@ -63,26 +138,30 @@ impl FnScopes {
|
||||
offset: TextUnit,
|
||||
) -> impl Iterator<Item = ScopeId> + 'a {
|
||||
let scope = self
|
||||
.scopes
|
||||
.scope_for
|
||||
.iter()
|
||||
// find containin scope
|
||||
.filter_map(|(id, scope)| Some((self.syntax_mapping.expr_syntax(*id)?, scope)))
|
||||
// find containing scope
|
||||
.min_by_key(|(ptr, _scope)| {
|
||||
(
|
||||
!(ptr.range().start() <= offset && offset <= ptr.range().end()),
|
||||
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
|
||||
// expression. Try to figure out the correct scope...
|
||||
fn adjust(&self, ptr: LocalSyntaxPtr, original_scope: ScopeId, offset: TextUnit) -> ScopeId {
|
||||
let r = ptr.range();
|
||||
let child_scopes = self
|
||||
.scopes
|
||||
.scope_for
|
||||
.iter()
|
||||
.filter_map(|(id, scope)| Some((self.syntax_mapping.expr_syntax(*id)?, scope)))
|
||||
.map(|(ptr, scope)| (ptr.range(), scope))
|
||||
.filter(|(range, _)| range.start() <= offset && range.is_subrange(&r) && *range != r);
|
||||
|
||||
@ -100,22 +179,27 @@ impl FnScopes {
|
||||
.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 name = name_ref.as_name();
|
||||
let ret = self
|
||||
.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| entry.name() == &name)
|
||||
.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> {
|
||||
let fn_def = pat.syntax().ancestors().find_map(ast::FnDef::cast).unwrap();
|
||||
let name_ptr = LocalSyntaxPtr::new(pat.syntax());
|
||||
let refs: Vec<_> = fn_def
|
||||
fn_def
|
||||
.syntax()
|
||||
.descendants()
|
||||
.filter_map(ast::NameRef::cast)
|
||||
@ -127,203 +211,95 @@ impl FnScopes {
|
||||
name: name_ref.syntax().text().to_string(),
|
||||
range: name_ref.syntax().range(),
|
||||
})
|
||||
.collect();
|
||||
|
||||
refs
|
||||
.collect()
|
||||
}
|
||||
|
||||
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> {
|
||||
node.ancestors()
|
||||
.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()
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
&self.name
|
||||
}
|
||||
pub fn ptr(&self) -> LocalSyntaxPtr {
|
||||
self.ptr
|
||||
pub fn pat(&self) -> PatId {
|
||||
self.pat
|
||||
}
|
||||
}
|
||||
|
||||
fn compute_block_scopes(block: ast::Block, scopes: &mut FnScopes, mut scope: ScopeId) {
|
||||
// A hack for completion :(
|
||||
scopes.set_scope(block.syntax(), scope);
|
||||
for stmt in block.statements() {
|
||||
fn compute_block_scopes(
|
||||
statements: &[Statement],
|
||||
tail: Option<ExprId>,
|
||||
body: &Body,
|
||||
scopes: &mut FnScopes,
|
||||
mut scope: ScopeId,
|
||||
) {
|
||||
for stmt in statements {
|
||||
match stmt {
|
||||
ast::Stmt::LetStmt(stmt) => {
|
||||
if let Some(expr) = stmt.initializer() {
|
||||
scopes.set_scope(expr.syntax(), scope);
|
||||
compute_expr_scopes(expr, scopes, scope);
|
||||
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);
|
||||
if let Some(pat) = stmt.pat() {
|
||||
scopes.add_bindings(scope, pat);
|
||||
}
|
||||
scopes.add_bindings(body, scope, *pat);
|
||||
}
|
||||
ast::Stmt::ExprStmt(expr_stmt) => {
|
||||
if let Some(expr) = expr_stmt.expr() {
|
||||
scopes.set_scope(expr.syntax(), scope);
|
||||
compute_expr_scopes(expr, scopes, scope);
|
||||
}
|
||||
Statement::Expr(expr) => {
|
||||
scopes.set_scope(*expr, scope);
|
||||
compute_expr_scopes(*expr, body, scopes, scope);
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(expr) = block.expr() {
|
||||
scopes.set_scope(expr.syntax(), scope);
|
||||
compute_expr_scopes(expr, scopes, scope);
|
||||
if let Some(expr) = tail {
|
||||
compute_expr_scopes(expr, body, scopes, scope);
|
||||
}
|
||||
}
|
||||
|
||||
fn compute_expr_scopes(expr: ast::Expr, scopes: &mut FnScopes, scope: ScopeId) {
|
||||
match expr {
|
||||
ast::Expr::IfExpr(e) => {
|
||||
let cond_scope = e
|
||||
.condition()
|
||||
.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() {
|
||||
compute_block_scopes(block, scopes, scope);
|
||||
}
|
||||
fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut FnScopes, scope: ScopeId) {
|
||||
scopes.set_scope(expr, scope);
|
||||
match body.expr(expr) {
|
||||
Expr::Block { statements, tail } => {
|
||||
compute_block_scopes(&statements, *tail, body, scopes, scope);
|
||||
}
|
||||
ast::Expr::BlockExpr(e) => {
|
||||
if let Some(block) = e.block() {
|
||||
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) => {
|
||||
Expr::For {
|
||||
iterable,
|
||||
pat,
|
||||
body: body_expr,
|
||||
} => {
|
||||
compute_expr_scopes(*iterable, body, scopes, scope);
|
||||
let scope = scopes.new_scope(scope);
|
||||
scopes.add_params_bindings(scope, e.param_list());
|
||||
if let Some(body) = e.body() {
|
||||
scopes.set_scope(body.syntax(), scope);
|
||||
compute_expr_scopes(body, scopes, scope);
|
||||
}
|
||||
scopes.add_bindings(body, scope, *pat);
|
||||
compute_expr_scopes(*body_expr, body, scopes, scope);
|
||||
}
|
||||
ast::Expr::CallExpr(e) => {
|
||||
compute_call_scopes(e.expr(), e.arg_list(), scopes, scope);
|
||||
Expr::Lambda {
|
||||
args,
|
||||
body: body_expr,
|
||||
..
|
||||
} => {
|
||||
let scope = scopes.new_scope(scope);
|
||||
scopes.add_params_bindings(scope, &args);
|
||||
compute_expr_scopes(*body_expr, body, scopes, scope);
|
||||
}
|
||||
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()) {
|
||||
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(scope, pat);
|
||||
}
|
||||
if let Some(expr) = arm.expr() {
|
||||
compute_expr_scopes(expr, scopes, 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);
|
||||
}
|
||||
}
|
||||
_ => expr
|
||||
.syntax()
|
||||
.children()
|
||||
.filter_map(ast::Expr::cast)
|
||||
.for_each(|expr| compute_expr_scopes(expr, scopes, scope)),
|
||||
e => e.walk_child_exprs(|e| compute_expr_scopes(e, body, 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)]
|
||||
@ -338,6 +314,8 @@ mod tests {
|
||||
use ra_syntax::SourceFileNode;
|
||||
use test_utils::{extract_offset, assert_eq_text};
|
||||
|
||||
use crate::expr;
|
||||
|
||||
use super::*;
|
||||
|
||||
fn do_check(code: &str, expected: &[&str]) {
|
||||
@ -353,15 +331,20 @@ mod tests {
|
||||
let file = SourceFileNode::parse(&code);
|
||||
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 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
|
||||
.scope_chain(marker.syntax())
|
||||
.flat_map(|scope| scopes.entries(scope))
|
||||
.flat_map(|scope| scopes.scopes.entries(scope))
|
||||
.map(|it| it.name().to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n");
|
||||
let expected = expected.join("\n");
|
||||
assert_eq_text!(&actual, &expected);
|
||||
assert_eq_text!(&expected, &actual);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -389,7 +372,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_metod_call_scope() {
|
||||
fn test_method_call_scope() {
|
||||
do_check(
|
||||
r"
|
||||
fn quux() {
|
||||
@ -445,10 +428,15 @@ mod tests {
|
||||
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 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 = local_name_entry.ptr().resolve(&file);
|
||||
let local_name = local_name_entry.ptr();
|
||||
let expected_name =
|
||||
find_node_at_offset::<ast::Name>(file.syntax(), expected_offset.into()).unwrap();
|
||||
assert_eq!(local_name.range(), expected_name.syntax().range());
|
||||
|
@ -47,7 +47,7 @@ pub use self::{
|
||||
ids::{HirFileId, DefId, DefLoc, MacroCallId, MacroCallLoc},
|
||||
macros::{MacroDef, MacroInput, MacroExpansion},
|
||||
module::{Module, ModuleId, Problem, nameres::{ItemMap, PerNs, Namespace}, ModuleScope, Resolution},
|
||||
function::{Function, FnScopes},
|
||||
function::{Function, FnScopes, ScopesWithSyntaxMapping},
|
||||
adt::{Struct, Enum},
|
||||
ty::Ty,
|
||||
impl_block::{ImplBlock, ImplItem},
|
||||
|
@ -31,6 +31,10 @@ impl Name {
|
||||
Name::new("[missing name]".into())
|
||||
}
|
||||
|
||||
pub(crate) fn self_param() -> Name {
|
||||
Name::new("self".into())
|
||||
}
|
||||
|
||||
pub(crate) fn tuple_field_name(idx: usize) -> Name {
|
||||
Name::new(idx.to_string().into())
|
||||
}
|
||||
@ -51,7 +55,8 @@ impl Name {
|
||||
"u128" => KnownName::U128,
|
||||
"f32" => KnownName::F32,
|
||||
"f64" => KnownName::F64,
|
||||
"Self" => KnownName::Self_,
|
||||
"Self" => KnownName::SelfType,
|
||||
"self" => KnownName::SelfParam,
|
||||
_ => return None,
|
||||
};
|
||||
Some(name)
|
||||
@ -104,5 +109,6 @@ pub(crate) enum KnownName {
|
||||
F32,
|
||||
F64,
|
||||
|
||||
Self_,
|
||||
SelfType,
|
||||
SelfParam,
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ use ra_syntax::{
|
||||
use ra_db::{SourceRootId, Cancelable,};
|
||||
|
||||
use crate::{
|
||||
SourceFileItems, SourceItemId, DefKind, Function, DefId, Name, AsName, HirFileId,
|
||||
SourceFileItems, SourceItemId, DefKind, DefId, Name, AsName, HirFileId,
|
||||
MacroCallLoc,
|
||||
db::HirDatabase,
|
||||
function::FnScopes,
|
||||
@ -23,11 +23,10 @@ use crate::{
|
||||
adt::{StructData, EnumData},
|
||||
};
|
||||
|
||||
pub(super) fn fn_scopes(db: &impl HirDatabase, def_id: DefId) -> Arc<FnScopes> {
|
||||
let function = Function::new(def_id);
|
||||
let syntax = function.syntax(db);
|
||||
let res = FnScopes::new(syntax.borrowed());
|
||||
Arc::new(res)
|
||||
pub(super) fn fn_scopes(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Arc<FnScopes>> {
|
||||
let body = db.body_hir(def_id)?;
|
||||
let res = FnScopes::new(body);
|
||||
Ok(Arc::new(res))
|
||||
}
|
||||
|
||||
pub(super) fn struct_data(db: &impl HirDatabase, def_id: DefId) -> Cancelable<Arc<StructData>> {
|
||||
|
@ -31,10 +31,11 @@ use ra_syntax::{
|
||||
};
|
||||
|
||||
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,
|
||||
type_ref::{TypeRef, Mutability},
|
||||
name::KnownName,
|
||||
ScopesWithSyntaxMapping,
|
||||
};
|
||||
|
||||
/// The ID of a type variable.
|
||||
@ -305,7 +306,7 @@ impl Ty {
|
||||
return Ok(Ty::Uint(uint_ty));
|
||||
} else if let Some(float_ty) = primitive::FloatTy::from_name(name) {
|
||||
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()));
|
||||
}
|
||||
}
|
||||
@ -515,7 +516,7 @@ impl InferenceResult {
|
||||
#[derive(Clone, Debug)]
|
||||
struct InferenceContext<'a, D: HirDatabase> {
|
||||
db: &'a D,
|
||||
scopes: Arc<FnScopes>,
|
||||
scopes: ScopesWithSyntaxMapping,
|
||||
/// The self param for the current method, if it exists.
|
||||
self_param: Option<LocalSyntaxPtr>,
|
||||
module: Module,
|
||||
@ -529,7 +530,7 @@ struct InferenceContext<'a, D: HirDatabase> {
|
||||
impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||
fn new(
|
||||
db: &'a D,
|
||||
scopes: Arc<FnScopes>,
|
||||
scopes: ScopesWithSyntaxMapping,
|
||||
module: Module,
|
||||
impl_block: Option<ImplBlock>,
|
||||
) -> Self {
|
||||
@ -826,10 +827,6 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||
self.infer_expr_opt(e.expr(), &Expectation::none())?;
|
||||
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) => {
|
||||
let (ty, def_id) = self.resolve_variant(e.path())?;
|
||||
if let Some(nfl) = e.named_field_list() {
|
||||
@ -845,10 +842,6 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||
}
|
||||
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::FieldExpr(e) => {
|
||||
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>> {
|
||||
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 impl_block = function.impl_block(db)?;
|
||||
let mut ctx = InferenceContext::new(db, scopes, module, impl_block);
|
||||
|
@ -927,12 +927,7 @@ pub enum Expr<'a> {
|
||||
BlockExpr(BlockExpr<'a>),
|
||||
ReturnExpr(ReturnExpr<'a>),
|
||||
MatchExpr(MatchExpr<'a>),
|
||||
MatchArmList(MatchArmList<'a>),
|
||||
MatchArm(MatchArm<'a>),
|
||||
MatchGuard(MatchGuard<'a>),
|
||||
StructLit(StructLit<'a>),
|
||||
NamedFieldList(NamedFieldList<'a>),
|
||||
NamedField(NamedField<'a>),
|
||||
CallExpr(CallExpr<'a>),
|
||||
IndexExpr(IndexExpr<'a>),
|
||||
MethodCallExpr(MethodCallExpr<'a>),
|
||||
@ -964,12 +959,7 @@ impl<'a> AstNode<'a> for Expr<'a> {
|
||||
BLOCK_EXPR => Some(Expr::BlockExpr(BlockExpr { syntax })),
|
||||
RETURN_EXPR => Some(Expr::ReturnExpr(ReturnExpr { 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 })),
|
||||
NAMED_FIELD_LIST => Some(Expr::NamedFieldList(NamedFieldList { syntax })),
|
||||
NAMED_FIELD => Some(Expr::NamedField(NamedField { syntax })),
|
||||
CALL_EXPR => Some(Expr::CallExpr(CallExpr { syntax })),
|
||||
INDEX_EXPR => Some(Expr::IndexExpr(IndexExpr { 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::ReturnExpr(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::NamedFieldList(inner) => inner.syntax(),
|
||||
Expr::NamedField(inner) => inner.syntax(),
|
||||
Expr::CallExpr(inner) => inner.syntax(),
|
||||
Expr::IndexExpr(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
|
||||
#[derive(Debug, Clone, Copy,)]
|
||||
|
@ -446,12 +446,7 @@ Grammar(
|
||||
"BlockExpr",
|
||||
"ReturnExpr",
|
||||
"MatchExpr",
|
||||
"MatchArmList",
|
||||
"MatchArm",
|
||||
"MatchGuard",
|
||||
"StructLit",
|
||||
"NamedFieldList",
|
||||
"NamedField",
|
||||
"CallExpr",
|
||||
"IndexExpr",
|
||||
"MethodCallExpr",
|
||||
@ -472,7 +467,10 @@ Grammar(
|
||||
"PathPat": (),
|
||||
"StructPat": (),
|
||||
"FieldPatList": (),
|
||||
"TupleStructPat": (),
|
||||
"TupleStructPat": (
|
||||
options: ["Path"],
|
||||
collections: [["args", "Pat"]],
|
||||
),
|
||||
"TuplePat": (),
|
||||
"SlicePat": (),
|
||||
"RangePat": (),
|
||||
|
Loading…
Reference in New Issue
Block a user