Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 16 additions & 20 deletions crates/ra_hir/src/source_analyzer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ impl SourceAnalyzer {
&self,
db: &dyn HirDatabase,
field: &ast::FieldExpr,
) -> Option<crate::StructField> {
) -> Option<StructField> {
let expr_id = self.expr_id(db, &field.clone().into())?;
self.infer.as_ref()?.field_resolution(expr_id).map(|it| it.into())
}
Expand All @@ -148,21 +148,19 @@ impl SourceAnalyzer {
&self,
db: &dyn HirDatabase,
field: &ast::RecordField,
) -> Option<(crate::StructField, Option<Local>)> {
let (expr_id, local) = match field.expr() {
Some(it) => (self.expr_id(db, &it)?, None),
None => {
let src = InFile { file_id: self.file_id, value: field };
let expr_id = self.body_source_map.as_ref()?.field_init_shorthand_expr(src)?;
let local_name = field.name_ref()?.as_name();
let path = ModPath::from_segments(PathKind::Plain, once(local_name));
let local = match self.resolver.resolve_path_in_value_ns_fully(db.upcast(), &path) {
Some(ValueNs::LocalBinding(pat_id)) => {
Some(Local { pat_id, parent: self.resolver.body_owner()? })
}
_ => None,
};
(expr_id, local)
) -> Option<(StructField, Option<Local>)> {
let expr = field.expr()?;
let expr_id = self.expr_id(db, &expr)?;
let local = if field.name_ref().is_some() {
None
} else {
let local_name = field.field_name()?.as_name();
let path = ModPath::from_segments(PathKind::Plain, once(local_name));
match self.resolver.resolve_path_in_value_ns_fully(db.upcast(), &path) {
Some(ValueNs::LocalBinding(pat_id)) => {
Some(Local { pat_id, parent: self.resolver.body_owner()? })
}
_ => None,
}
};
let struct_field = self.infer.as_ref()?.record_field_resolution(expr_id)?;
Expand Down Expand Up @@ -319,8 +317,7 @@ fn scope_for_offset(
if source.file_id != offset.file_id {
return None;
}
let syntax_node_ptr =
source.value.either(|it| it.syntax_node_ptr(), |it| it.syntax_node_ptr());
let syntax_node_ptr = source.value.syntax_node_ptr();
Some((syntax_node_ptr, scope))
})
// find containing scope
Expand Down Expand Up @@ -399,8 +396,7 @@ fn adjust(
if source.file_id != file_id {
return None;
}
let syntax_node_ptr =
source.value.either(|it| it.syntax_node_ptr(), |it| it.syntax_node_ptr());
let syntax_node_ptr = source.value.syntax_node_ptr();
Some((syntax_node_ptr, scope))
})
.map(|(ptr, scope)| (ptr.range(), scope))
Expand Down
13 changes: 4 additions & 9 deletions crates/ra_hir_def/src/body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ use drop_bomb::DropBomb;
use either::Either;
use hir_expand::{ast_id_map::AstIdMap, hygiene::Hygiene, AstId, HirFileId, InFile, MacroDefId};
use ra_arena::{map::ArenaMap, Arena};
use ra_cfg::CfgOptions;
use ra_db::CrateId;
use ra_prof::profile;
use ra_syntax::{ast, AstNode, AstPtr};
use rustc_hash::FxHashMap;
Expand All @@ -24,8 +26,6 @@ use crate::{
src::HasSource,
AsMacroCall, DefWithBodyId, HasModule, Lookup, ModuleId,
};
use ra_cfg::CfgOptions;
use ra_db::CrateId;

/// A subser of Exander that only deals with cfg attributes. We only need it to
/// avoid cyclic queries in crate def map during enum processing.
Expand Down Expand Up @@ -187,7 +187,7 @@ pub struct Body {
pub item_scope: ItemScope,
}

pub type ExprPtr = Either<AstPtr<ast::Expr>, AstPtr<ast::RecordField>>;
pub type ExprPtr = AstPtr<ast::Expr>;
pub type ExprSource = InFile<ExprPtr>;

pub type PatPtr = Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>;
Expand Down Expand Up @@ -285,7 +285,7 @@ impl BodySourceMap {
}

pub fn node_expr(&self, node: InFile<&ast::Expr>) -> Option<ExprId> {
let src = node.map(|it| Either::Left(AstPtr::new(it)));
let src = node.map(|it| AstPtr::new(it));
self.expr_map.get(&src).cloned()
}

Expand All @@ -294,11 +294,6 @@ impl BodySourceMap {
self.expansions.get(&src).cloned()
}

pub fn field_init_shorthand_expr(&self, node: InFile<&ast::RecordField>) -> Option<ExprId> {
let src = node.map(|it| Either::Right(AstPtr::new(it)));
self.expr_map.get(&src).cloned()
}

pub fn pat_syntax(&self, pat: PatId) -> Result<PatSource, SyntheticSyntax> {
self.pat_map_back[pat].clone()
}
Expand Down
30 changes: 6 additions & 24 deletions crates/ra_hir_def/src/body/lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ use crate::{
},
item_scope::BuiltinShadowMode,
path::GenericArgs,
path::Path,
type_ref::{Mutability, TypeRef},
AdtId, ConstLoc, ContainerId, DefWithBodyId, EnumLoc, FunctionLoc, Intern, ModuleDefId,
StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, UnionLoc,
Expand Down Expand Up @@ -102,7 +101,6 @@ impl ExprCollector<'_> {
}

fn alloc_expr(&mut self, expr: Expr, ptr: AstPtr<ast::Expr>) -> ExprId {
let ptr = Either::Left(ptr);
let src = self.expander.to_source(ptr);
let id = self.make_expr(expr, Ok(src.clone()));
self.source_map.expr_map.insert(src, id);
Expand All @@ -113,13 +111,6 @@ impl ExprCollector<'_> {
fn alloc_expr_desugared(&mut self, expr: Expr) -> ExprId {
self.make_expr(expr, Err(SyntheticSyntax))
}
fn alloc_expr_field_shorthand(&mut self, expr: Expr, ptr: AstPtr<ast::RecordField>) -> ExprId {
let ptr = Either::Right(ptr);
let src = self.expander.to_source(ptr);
let id = self.make_expr(expr, Ok(src.clone()));
self.source_map.expr_map.insert(src, id);
id
}
fn empty_block(&mut self) -> ExprId {
self.alloc_expr_desugared(Expr::Block { statements: Vec::new(), tail: None })
}
Expand Down Expand Up @@ -289,7 +280,7 @@ impl ExprCollector<'_> {
ast::Expr::ParenExpr(e) => {
let inner = self.collect_expr_opt(e.expr());
// make the paren expr point to the inner expression as well
let src = self.expander.to_source(Either::Left(syntax_ptr));
let src = self.expander.to_source(syntax_ptr);
self.source_map.expr_map.insert(src, inner);
inner
}
Expand All @@ -309,22 +300,13 @@ impl ExprCollector<'_> {
if !self.expander.is_cfg_enabled(&attrs) {
return None;
}
let name = field.field_name()?.as_name();

Some(RecordLitField {
name: field
.name_ref()
.map(|nr| nr.as_name())
.unwrap_or_else(Name::missing),
expr: if let Some(e) = field.expr() {
self.collect_expr(e)
} else if let Some(nr) = field.name_ref() {
// field shorthand
self.alloc_expr_field_shorthand(
Expr::Path(Path::from_name_ref(&nr)),
AstPtr::new(&field),
)
} else {
self.missing_expr()
name,
expr: match field.expr() {
Some(e) => self.collect_expr(e),
None => self.missing_expr(),
},
})
})
Expand Down
5 changes: 0 additions & 5 deletions crates/ra_hir_def/src/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,11 +134,6 @@ impl Path {
lower::lower_path(path, hygiene)
}

/// Converts an `ast::NameRef` into a single-identifier `Path`.
pub(crate) fn from_name_ref(name_ref: &ast::NameRef) -> Path {
Path { type_anchor: None, mod_path: name_ref.as_name().into(), generic_args: vec![None] }
}

/// Converts a known mod path to `Path`.
pub(crate) fn from_known_path(
path: ModPath,
Expand Down
55 changes: 25 additions & 30 deletions crates/ra_hir_ty/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,21 +89,19 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
let (_, source_map) = db.body_with_source_map(self.func.into());

if let Ok(source_ptr) = source_map.expr_syntax(id) {
if let Some(expr) = source_ptr.value.as_ref().left() {
let root = source_ptr.file_syntax(db.upcast());
if let ast::Expr::RecordLit(record_lit) = expr.to_node(&root) {
if let Some(field_list) = record_lit.record_field_list() {
let variant_data = variant_data(db.upcast(), variant_def);
let missed_fields = missed_fields
.into_iter()
.map(|idx| variant_data.fields()[idx].name.clone())
.collect();
self.sink.push(MissingFields {
file: source_ptr.file_id,
field_list: AstPtr::new(&field_list),
missed_fields,
})
}
let root = source_ptr.file_syntax(db.upcast());
if let ast::Expr::RecordLit(record_lit) = &source_ptr.value.to_node(&root) {
if let Some(field_list) = record_lit.record_field_list() {
let variant_data = variant_data(db.upcast(), variant_def);
let missed_fields = missed_fields
.into_iter()
.map(|idx| variant_data.fields()[idx].name.clone())
.collect();
self.sink.push(MissingFields {
file: source_ptr.file_id,
field_list: AstPtr::new(&field_list),
missed_fields,
})
}
}
}
Expand Down Expand Up @@ -205,18 +203,16 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
}

if let Ok(source_ptr) = source_map.expr_syntax(id) {
if let Some(expr) = source_ptr.value.as_ref().left() {
let root = source_ptr.file_syntax(db.upcast());
if let ast::Expr::MatchExpr(match_expr) = expr.to_node(&root) {
if let (Some(match_expr), Some(arms)) =
(match_expr.expr(), match_expr.match_arm_list())
{
self.sink.push(MissingMatchArms {
file: source_ptr.file_id,
match_expr: AstPtr::new(&match_expr),
arms: AstPtr::new(&arms),
})
}
let root = source_ptr.file_syntax(db.upcast());
if let ast::Expr::MatchExpr(match_expr) = &source_ptr.value.to_node(&root) {
if let (Some(match_expr), Some(arms)) =
(match_expr.expr(), match_expr.match_arm_list())
{
self.sink.push(MissingMatchArms {
file: source_ptr.file_id,
match_expr: AstPtr::new(&match_expr),
arms: AstPtr::new(&arms),
})
}
}
}
Expand Down Expand Up @@ -247,9 +243,8 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
let (_, source_map) = db.body_with_source_map(self.func.into());

if let Ok(source_ptr) = source_map.expr_syntax(id) {
if let Some(expr) = source_ptr.value.left() {
self.sink.push(MissingOkInTailExpr { file: source_ptr.file_id, expr });
}
self.sink
.push(MissingOkInTailExpr { file: source_ptr.file_id, expr: source_ptr.value });
}
}
}
Expand Down
4 changes: 1 addition & 3 deletions crates/ra_hir_ty/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,7 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String {

for (expr, ty) in inference_result.type_of_expr.iter() {
let syntax_ptr = match body_source_map.expr_syntax(expr) {
Ok(sp) => {
sp.map(|ast| ast.either(|it| it.syntax_node_ptr(), |it| it.syntax_node_ptr()))
}
Ok(sp) => sp.map(|ast| ast.syntax_node_ptr()),
Err(SyntheticSyntax) => continue,
};
types.push((syntax_ptr.clone(), ty));
Expand Down
2 changes: 1 addition & 1 deletion crates/ra_ide/src/completion/complete_unqualified_path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use crate::completion::{CompletionContext, Completions};

pub(super) fn complete_unqualified_path(acc: &mut Completions, ctx: &CompletionContext) {
if !(ctx.is_trivial_path && !ctx.is_pat_binding_or_const) {
if !(ctx.is_trivial_path && !ctx.is_pat_binding_or_const && !ctx.record_lit_syntax.is_some()) {
return;
}

Expand Down
2 changes: 1 addition & 1 deletion crates/ra_ide/src/completion/completion_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ impl<'a> CompletionContext<'a> {
self.name_ref_syntax =
find_node_at_offset(&original_file, name_ref.syntax().text_range().start());
let name_range = name_ref.syntax().text_range();
if name_ref.syntax().parent().and_then(ast::RecordField::cast).is_some() {
if ast::RecordField::for_field_name(&name_ref).is_some() {
self.record_lit_syntax =
self.sema.find_node_at_offset_with_macros(&original_file, offset);
}
Expand Down
2 changes: 1 addition & 1 deletion crates/ra_ide_db/src/defs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ pub fn classify_name_ref(
}
}

if let Some(record_field) = ast::RecordField::cast(parent.clone()) {
if let Some(record_field) = ast::RecordField::for_field_name(name_ref) {
tested_by!(goto_def_for_record_fields; force);
tested_by!(goto_def_for_field_init_shorthand; force);
if let Some((field, local)) = sema.resolve_record_field(&record_field) {
Expand Down
37 changes: 25 additions & 12 deletions crates/ra_parser/src/grammar/expressions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -619,26 +619,39 @@ pub(crate) fn record_field_list(p: &mut Parser) {
let m = p.start();
p.bump(T!['{']);
while !p.at(EOF) && !p.at(T!['}']) {
let m = p.start();
// test record_literal_field_with_attr
// fn main() {
// S { #[cfg(test)] field: 1 }
// }
attributes::outer_attributes(p);

match p.current() {
// test record_literal_field_with_attr
// fn main() {
// S { #[cfg(test)] field: 1 }
// }
IDENT | INT_NUMBER | T![#] => {
let m = p.start();
attributes::outer_attributes(p);
name_ref_or_index(p);
if p.eat(T![:]) {
expr(p);
IDENT | INT_NUMBER => {
// test_err record_literal_before_ellipsis_recovery
// fn main() {
// S { field ..S::default() }
// }
if p.nth_at(1, T![:]) || p.nth_at(1, T![..]) {
name_ref_or_index(p);
p.expect(T![:]);
}
expr(p);
m.complete(p, RECORD_FIELD);
}
T![.] if p.at(T![..]) => {
m.abandon(p);
p.bump(T![..]);
expr(p);
}
T!['{'] => error_block(p, "expected a field"),
_ => p.err_and_bump("expected identifier"),
T!['{'] => {
error_block(p, "expected a field");
m.abandon(p);
}
_ => {
p.err_and_bump("expected identifier");
m.abandon(p);
}
}
if !p.at(T!['}']) {
p.expect(T![,]);
Expand Down
30 changes: 30 additions & 0 deletions crates/ra_syntax/src/ast/extensions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,36 @@ impl ast::StructDef {
}
}

impl ast::RecordField {
pub fn for_field_name(field_name: &ast::NameRef) -> Option<ast::RecordField> {
let candidate =
field_name.syntax().parent().and_then(ast::RecordField::cast).or_else(|| {
field_name.syntax().ancestors().nth(4).and_then(ast::RecordField::cast)
})?;
if candidate.field_name().as_ref() == Some(field_name) {
Some(candidate)
} else {
None
}
}

/// Deals with field init shorthand
pub fn field_name(&self) -> Option<ast::NameRef> {
if let Some(name_ref) = self.name_ref() {
return Some(name_ref);
}
if let Some(ast::Expr::PathExpr(expr)) = self.expr() {
let path = expr.path()?;
let segment = path.segment()?;
let name_ref = segment.name_ref()?;
if path.qualifier().is_none() {
return Some(name_ref);
}
}
None
}
}

impl ast::EnumVariant {
pub fn parent_enum(&self) -> ast::EnumDef {
self.syntax()
Expand Down
Loading