Shrink PatPtr by swapping its AstPtr and Either wrap order

This commit is contained in:
Lukas Wirth 2023-10-06 12:32:37 +02:00
parent a158670432
commit 88a00bf49d
15 changed files with 164 additions and 190 deletions

View file

@ -57,7 +57,7 @@ pub struct Body {
pub type ExprPtr = AstPtr<ast::Expr>; pub type ExprPtr = AstPtr<ast::Expr>;
pub type ExprSource = InFile<ExprPtr>; pub type ExprSource = InFile<ExprPtr>;
pub type PatPtr = Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>; pub type PatPtr = AstPtr<Either<ast::Pat, ast::SelfParam>>;
pub type PatSource = InFile<PatPtr>; pub type PatSource = InFile<PatPtr>;
pub type LabelPtr = AstPtr<ast::Label>; pub type LabelPtr = AstPtr<ast::Label>;
@ -356,12 +356,12 @@ impl BodySourceMap {
} }
pub fn node_pat(&self, node: InFile<&ast::Pat>) -> Option<PatId> { pub fn node_pat(&self, node: InFile<&ast::Pat>) -> Option<PatId> {
let src = node.map(|it| Either::Left(AstPtr::new(it))); let src = node.map(|it| AstPtr::new(it).wrap_left());
self.pat_map.get(&src).cloned() self.pat_map.get(&src).cloned()
} }
pub fn node_self_param(&self, node: InFile<&ast::SelfParam>) -> Option<PatId> { pub fn node_self_param(&self, node: InFile<&ast::SelfParam>) -> Option<PatId> {
let src = node.map(|it| Either::Right(AstPtr::new(it))); let src = node.map(|it| AstPtr::new(it).wrap_right());
self.pat_map.get(&src).cloned() self.pat_map.get(&src).cloned()
} }

View file

@ -196,16 +196,12 @@ impl ExprCollector<'_> {
if let Some(self_param) = if let Some(self_param) =
param_list.self_param().filter(|_| attr_enabled.next().unwrap_or(false)) param_list.self_param().filter(|_| attr_enabled.next().unwrap_or(false))
{ {
let ptr = AstPtr::new(&self_param); let is_mutable =
let binding_id: la_arena::Idx<Binding> = self.alloc_binding( self_param.mut_token().is_some() && self_param.amp_token().is_none();
name![self], let ptr = AstPtr::new(&Either::Right(self_param));
BindingAnnotation::new( let binding_id: la_arena::Idx<Binding> =
self_param.mut_token().is_some() && self_param.amp_token().is_none(), self.alloc_binding(name![self], BindingAnnotation::new(is_mutable, false));
false, let param_pat = self.alloc_pat(Pat::Bind { id: binding_id, subpat: None }, ptr);
),
);
let param_pat =
self.alloc_pat(Pat::Bind { id: binding_id, subpat: None }, Either::Right(ptr));
self.add_definition_to_binding(binding_id, param_pat); self.add_definition_to_binding(binding_id, param_pat);
self.body.params.push(param_pat); self.body.params.push(param_pat);
} }
@ -1260,8 +1256,8 @@ impl ExprCollector<'_> {
(Some(id), Pat::Bind { id, subpat }) (Some(id), Pat::Bind { id, subpat })
}; };
let ptr = AstPtr::new(&pat); let ptr = AstPtr::new(&Either::Left(pat));
let pat = self.alloc_pat(pattern, Either::Left(ptr)); let pat = self.alloc_pat(pattern, ptr);
if let Some(binding_id) = binding { if let Some(binding_id) = binding {
self.add_definition_to_binding(binding_id, pat); self.add_definition_to_binding(binding_id, pat);
} }
@ -1395,7 +1391,7 @@ impl ExprCollector<'_> {
ast::Pat::MacroPat(mac) => match mac.macro_call() { ast::Pat::MacroPat(mac) => match mac.macro_call() {
Some(call) => { Some(call) => {
let macro_ptr = AstPtr::new(&call); let macro_ptr = AstPtr::new(&call);
let src = self.expander.to_source(Either::Left(AstPtr::new(&pat))); let src = self.expander.to_source(AstPtr::new(&Either::Left(pat)));
let pat = let pat =
self.collect_macro_call(call, macro_ptr, true, |this, expanded_pat| { self.collect_macro_call(call, macro_ptr, true, |this, expanded_pat| {
this.collect_pat_opt(expanded_pat, binding_list) this.collect_pat_opt(expanded_pat, binding_list)
@ -1430,8 +1426,8 @@ impl ExprCollector<'_> {
Pat::Range { start, end } Pat::Range { start, end }
} }
}; };
let ptr = AstPtr::new(&pat); let ptr = AstPtr::new(&Either::Left(pat));
self.alloc_pat(pattern, Either::Left(ptr)) self.alloc_pat(pattern, ptr)
} }
fn collect_pat_opt(&mut self, pat: Option<ast::Pat>, binding_list: &mut BindingList) -> PatId { fn collect_pat_opt(&mut self, pat: Option<ast::Pat>, binding_list: &mut BindingList) -> PatId {

View file

@ -475,10 +475,7 @@ fn foo() {
.pat_syntax(*body.bindings[resolved.binding()].definitions.first().unwrap()) .pat_syntax(*body.bindings[resolved.binding()].definitions.first().unwrap())
.unwrap(); .unwrap();
let local_name = pat_src.value.either( let local_name = pat_src.value.syntax_node_ptr().to_node(file.syntax());
|it| it.syntax_node_ptr().to_node(file.syntax()),
|it| it.syntax_node_ptr().to_node(file.syntax()),
);
assert_eq!(local_name.text_range(), expected_name.syntax().text_range()); assert_eq!(local_name.text_range(), expected_name.syntax().text_range());
} }

View file

@ -336,48 +336,44 @@ impl<'a> DeclValidator<'a> {
for (id, replacement) in pats_replacements { for (id, replacement) in pats_replacements {
if let Ok(source_ptr) = source_map.pat_syntax(id) { if let Ok(source_ptr) = source_map.pat_syntax(id) {
if let Some(expr) = source_ptr.value.as_ref().left() { if let Some(ptr) = source_ptr.value.clone().cast::<ast::IdentPat>() {
let root = source_ptr.file_syntax(self.db.upcast()); let root = source_ptr.file_syntax(self.db.upcast());
if let ast::Pat::IdentPat(ident_pat) = expr.to_node(&root) { let ident_pat = ptr.to_node(&root);
let parent = match ident_pat.syntax().parent() { let parent = match ident_pat.syntax().parent() {
Some(parent) => parent, Some(parent) => parent,
None => continue, None => continue,
}; };
let name_ast = match ident_pat.name() { let name_ast = match ident_pat.name() {
Some(name_ast) => name_ast, Some(name_ast) => name_ast,
None => continue, None => continue,
}; };
let is_param = ast::Param::can_cast(parent.kind()); let is_param = ast::Param::can_cast(parent.kind());
// We have to check that it's either `let var = ...` or `var @ Variant(_)` statement, // We have to check that it's either `let var = ...` or `var @ Variant(_)` statement,
// because e.g. match arms are patterns as well. // because e.g. match arms are patterns as well.
// In other words, we check that it's a named variable binding. // In other words, we check that it's a named variable binding.
let is_binding = ast::LetStmt::can_cast(parent.kind()) let is_binding = ast::LetStmt::can_cast(parent.kind())
|| (ast::MatchArm::can_cast(parent.kind()) || (ast::MatchArm::can_cast(parent.kind())
&& ident_pat.at_token().is_some()); && ident_pat.at_token().is_some());
if !(is_param || is_binding) { if !(is_param || is_binding) {
// This pattern is not an actual variable declaration, e.g. `Some(val) => {..}` match arm. // This pattern is not an actual variable declaration, e.g. `Some(val) => {..}` match arm.
continue; continue;
}
let ident_type =
if is_param { IdentType::Parameter } else { IdentType::Variable };
let diagnostic = IncorrectCase {
file: source_ptr.file_id,
ident_type,
ident: AstPtr::new(&name_ast),
expected_case: replacement.expected_case,
ident_text: replacement
.current_name
.display(self.db.upcast())
.to_string(),
suggested_text: replacement.suggested_text,
};
self.sink.push(diagnostic);
} }
let ident_type =
if is_param { IdentType::Parameter } else { IdentType::Variable };
let diagnostic = IncorrectCase {
file: source_ptr.file_id,
ident_type,
ident: AstPtr::new(&name_ast),
expected_case: replacement.expected_case,
ident_text: replacement.current_name.display(self.db.upcast()).to_string(),
suggested_text: replacement.suggested_text,
};
self.sink.push(diagnostic);
} }
} }
} }

View file

@ -375,10 +375,7 @@ impl MirEvalError {
Err(_) => continue, Err(_) => continue,
}, },
MirSpan::PatId(p) => match source_map.pat_syntax(*p) { MirSpan::PatId(p) => match source_map.pat_syntax(*p) {
Ok(s) => s.map(|it| match it { Ok(s) => s.map(|it| it.syntax_node_ptr()),
Either::Left(e) => e.into(),
Either::Right(e) => e.into(),
}),
Err(_) => continue, Err(_) => continue,
}, },
MirSpan::Unknown => continue, MirSpan::Unknown => continue,

View file

@ -269,12 +269,7 @@ fn pat_node(
Some(match body_source_map.pat_syntax(pat) { Some(match body_source_map.pat_syntax(pat) {
Ok(sp) => { Ok(sp) => {
let root = db.parse_or_expand(sp.file_id); let root = db.parse_or_expand(sp.file_id);
sp.map(|ptr| { sp.map(|ptr| ptr.to_node(&root).syntax().clone())
ptr.either(
|it| it.to_node(&root).syntax().clone(),
|it| it.to_node(&root).syntax().clone(),
)
})
} }
Err(SyntheticSyntax) => return None, Err(SyntheticSyntax) => return None,
}) })
@ -303,12 +298,7 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String {
let syntax_ptr = match body_source_map.pat_syntax(pat) { let syntax_ptr = match body_source_map.pat_syntax(pat) {
Ok(sp) => { Ok(sp) => {
let root = db.parse_or_expand(sp.file_id); let root = db.parse_or_expand(sp.file_id);
sp.map(|ptr| { sp.map(|ptr| ptr.to_node(&root).syntax().clone())
ptr.either(
|it| it.to_node(&root).syntax().clone(),
|it| it.to_node(&root).syntax().clone(),
)
})
} }
Err(SyntheticSyntax) => continue, Err(SyntheticSyntax) => continue,
}; };

View file

@ -174,20 +174,19 @@ pub struct MalformedDerive {
#[derive(Debug)] #[derive(Debug)]
pub struct NoSuchField { pub struct NoSuchField {
pub field: InFile<Either<AstPtr<ast::RecordExprField>, AstPtr<ast::RecordPatField>>>, pub field: InFile<AstPtr<Either<ast::RecordExprField, ast::RecordPatField>>>,
pub private: bool, pub private: bool,
} }
#[derive(Debug)] #[derive(Debug)]
pub struct PrivateAssocItem { pub struct PrivateAssocItem {
pub expr_or_pat: pub expr_or_pat: InFile<AstPtr<Either<ast::Expr, Either<ast::Pat, ast::SelfParam>>>>,
InFile<Either<AstPtr<ast::Expr>, Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>>>,
pub item: AssocItem, pub item: AssocItem,
} }
#[derive(Debug)] #[derive(Debug)]
pub struct MismatchedTupleStructPatArgCount { pub struct MismatchedTupleStructPatArgCount {
pub expr_or_pat: InFile<Either<AstPtr<ast::Expr>, AstPtr<ast::Pat>>>, pub expr_or_pat: InFile<AstPtr<Either<ast::Expr, ast::Pat>>>,
pub expected: usize, pub expected: usize,
pub found: usize, pub found: usize,
} }
@ -228,7 +227,7 @@ pub struct MissingUnsafe {
#[derive(Debug)] #[derive(Debug)]
pub struct MissingFields { pub struct MissingFields {
pub file: HirFileId, pub file: HirFileId,
pub field_list_parent: Either<AstPtr<ast::RecordExpr>, AstPtr<ast::RecordPat>>, pub field_list_parent: AstPtr<Either<ast::RecordExpr, ast::RecordPat>>,
pub field_list_parent_path: Option<AstPtr<ast::Path>>, pub field_list_parent_path: Option<AstPtr<ast::Path>>,
pub missed_fields: Vec<Name>, pub missed_fields: Vec<Name>,
} }
@ -255,7 +254,7 @@ pub struct MissingMatchArms {
#[derive(Debug)] #[derive(Debug)]
pub struct TypeMismatch { pub struct TypeMismatch {
pub expr_or_pat: Either<InFile<AstPtr<ast::Expr>>, InFile<AstPtr<ast::Pat>>>, pub expr_or_pat: InFile<AstPtr<Either<ast::Expr, ast::Pat>>>,
pub expected: Type, pub expected: Type,
pub actual: Type, pub actual: Type,
} }

View file

@ -1509,10 +1509,10 @@ impl DefWithBody {
&hir_ty::InferenceDiagnostic::NoSuchField { field: expr, private } => { &hir_ty::InferenceDiagnostic::NoSuchField { field: expr, private } => {
let expr_or_pat = match expr { let expr_or_pat = match expr {
ExprOrPatId::ExprId(expr) => { ExprOrPatId::ExprId(expr) => {
source_map.field_syntax(expr).map(Either::Left) source_map.field_syntax(expr).map(AstPtr::wrap_left)
} }
ExprOrPatId::PatId(pat) => { ExprOrPatId::PatId(pat) => {
source_map.pat_field_syntax(pat).map(Either::Right) source_map.pat_field_syntax(pat).map(AstPtr::wrap_right)
} }
}; };
acc.push(NoSuchField { field: expr_or_pat, private }.into()) acc.push(NoSuchField { field: expr_or_pat, private }.into())
@ -1530,8 +1530,8 @@ impl DefWithBody {
} }
&hir_ty::InferenceDiagnostic::PrivateAssocItem { id, item } => { &hir_ty::InferenceDiagnostic::PrivateAssocItem { id, item } => {
let expr_or_pat = match id { let expr_or_pat = match id {
ExprOrPatId::ExprId(expr) => expr_syntax(expr).map(Either::Left), ExprOrPatId::ExprId(expr) => expr_syntax(expr).map(AstPtr::wrap_left),
ExprOrPatId::PatId(pat) => pat_syntax(pat).map(Either::Right), ExprOrPatId::PatId(pat) => pat_syntax(pat).map(AstPtr::wrap_right),
}; };
let item = item.into(); let item = item.into();
acc.push(PrivateAssocItem { expr_or_pat, item }.into()) acc.push(PrivateAssocItem { expr_or_pat, item }.into())
@ -1609,12 +1609,17 @@ impl DefWithBody {
found, found,
} => { } => {
let expr_or_pat = match pat { let expr_or_pat = match pat {
ExprOrPatId::ExprId(expr) => expr_syntax(expr).map(Either::Left), ExprOrPatId::ExprId(expr) => expr_syntax(expr).map(AstPtr::wrap_left),
ExprOrPatId::PatId(pat) => source_map ExprOrPatId::PatId(pat) => {
.pat_syntax(pat) let InFile { file_id, value } =
.expect("unexpected synthetic") source_map.pat_syntax(pat).expect("unexpected synthetic");
.map(|it| it.unwrap_left())
.map(Either::Right), // cast from Either<Pat, SelfParam> -> Either<_, Pat>
let Some(ptr) = AstPtr::try_from_raw(value.syntax_node_ptr()) else {
continue;
};
InFile { file_id, value: ptr }
}
}; };
acc.push( acc.push(
MismatchedTupleStructPatArgCount { expr_or_pat, expected, found }.into(), MismatchedTupleStructPatArgCount { expr_or_pat, expected, found }.into(),
@ -1628,11 +1633,15 @@ impl DefWithBody {
ExprOrPatId::PatId(pat) => source_map.pat_syntax(pat).map(Either::Right), ExprOrPatId::PatId(pat) => source_map.pat_syntax(pat).map(Either::Right),
}; };
let expr_or_pat = match expr_or_pat { let expr_or_pat = match expr_or_pat {
Ok(Either::Left(expr)) => Either::Left(expr), Ok(Either::Left(expr)) => expr.map(AstPtr::wrap_left),
Ok(Either::Right(InFile { file_id, value: Either::Left(pat) })) => { Ok(Either::Right(InFile { file_id, value: pat })) => {
Either::Right(InFile { file_id, value: pat }) // cast from Either<Pat, SelfParam> -> Either<_, Pat>
let Some(ptr) = AstPtr::try_from_raw(pat.syntax_node_ptr()) else {
continue;
};
InFile { file_id, value: ptr }
} }
Ok(Either::Right(_)) | Err(SyntheticSyntax) => continue, Err(SyntheticSyntax) => continue,
}; };
acc.push( acc.push(
@ -1667,10 +1676,7 @@ impl DefWithBody {
Err(_) => continue, Err(_) => continue,
}, },
mir::MirSpan::PatId(p) => match source_map.pat_syntax(p) { mir::MirSpan::PatId(p) => match source_map.pat_syntax(p) {
Ok(s) => s.map(|it| match it { Ok(s) => s.map(|it| it.into()),
Either::Left(e) => e.into(),
Either::Right(e) => e.into(),
}),
Err(_) => continue, Err(_) => continue,
}, },
mir::MirSpan::Unknown => continue, mir::MirSpan::Unknown => continue,
@ -1721,10 +1727,7 @@ impl DefWithBody {
Err(_) => continue, Err(_) => continue,
}, },
mir::MirSpan::PatId(p) => match source_map.pat_syntax(*p) { mir::MirSpan::PatId(p) => match source_map.pat_syntax(*p) {
Ok(s) => s.map(|it| match it { Ok(s) => s.map(|it| it.into()),
Either::Left(e) => e.into(),
Either::Right(e) => e.into(),
}),
Err(_) => continue, Err(_) => continue,
}, },
mir::MirSpan::Unknown => continue, mir::MirSpan::Unknown => continue,
@ -1763,18 +1766,18 @@ impl DefWithBody {
Ok(source_ptr) => { Ok(source_ptr) => {
let root = source_ptr.file_syntax(db.upcast()); let root = source_ptr.file_syntax(db.upcast());
if let ast::Expr::RecordExpr(record_expr) = if let ast::Expr::RecordExpr(record_expr) =
&source_ptr.value.to_node(&root) source_ptr.value.to_node(&root)
{ {
if record_expr.record_expr_field_list().is_some() { if record_expr.record_expr_field_list().is_some() {
let field_list_parent_path =
record_expr.path().map(|path| AstPtr::new(&path));
acc.push( acc.push(
MissingFields { MissingFields {
file: source_ptr.file_id, file: source_ptr.file_id,
field_list_parent: Either::Left(AstPtr::new( field_list_parent: AstPtr::new(&Either::Left(
record_expr, record_expr,
)), )),
field_list_parent_path: record_expr field_list_parent_path,
.path()
.map(|path| AstPtr::new(&path)),
missed_fields, missed_fields,
} }
.into(), .into(),
@ -1786,24 +1789,24 @@ impl DefWithBody {
}, },
Either::Right(record_pat) => match source_map.pat_syntax(record_pat) { Either::Right(record_pat) => match source_map.pat_syntax(record_pat) {
Ok(source_ptr) => { Ok(source_ptr) => {
if let Some(expr) = source_ptr.value.as_ref().left() { if let Some(ptr) = source_ptr.value.clone().cast::<ast::RecordPat>()
{
let root = source_ptr.file_syntax(db.upcast()); let root = source_ptr.file_syntax(db.upcast());
if let ast::Pat::RecordPat(record_pat) = expr.to_node(&root) { let record_pat = ptr.to_node(&root);
if record_pat.record_pat_field_list().is_some() { if record_pat.record_pat_field_list().is_some() {
acc.push( let field_list_parent_path =
MissingFields { record_pat.path().map(|path| AstPtr::new(&path));
file: source_ptr.file_id, acc.push(
field_list_parent: Either::Right(AstPtr::new( MissingFields {
&record_pat, file: source_ptr.file_id,
)), field_list_parent: AstPtr::new(&Either::Right(
field_list_parent_path: record_pat record_pat,
.path() )),
.map(|path| AstPtr::new(&path)), field_list_parent_path,
missed_fields, missed_fields,
} }
.into(), .into(),
) )
}
} }
} }
} }
@ -2948,10 +2951,10 @@ impl Local {
.map(|&definition| { .map(|&definition| {
let src = source_map.pat_syntax(definition).unwrap(); // Hmm... let src = source_map.pat_syntax(definition).unwrap(); // Hmm...
let root = src.file_syntax(db.upcast()); let root = src.file_syntax(db.upcast());
src.map(|ast| match ast { src.map(|ast| match ast.to_node(&root) {
// Suspicious unwrap Either::Left(ast::Pat::IdentPat(it)) => Either::Left(it),
Either::Left(it) => Either::Left(it.cast().unwrap().to_node(&root)), Either::Left(_) => unreachable!("local with non ident-pattern"),
Either::Right(it) => Either::Right(it.to_node(&root)), Either::Right(it) => Either::Right(it),
}) })
}) })
.map(move |source| LocalSource { local: self, source }) .map(move |source| LocalSource { local: self, source })

View file

@ -23,12 +23,7 @@ pub(crate) fn mismatched_tuple_struct_pat_arg_count(
Diagnostic::new( Diagnostic::new(
DiagnosticCode::RustcHardError("E0023"), DiagnosticCode::RustcHardError("E0023"),
message, message,
invalid_args_range( invalid_args_range(ctx, d.expr_or_pat.clone().map(Into::into), d.expected, d.found),
ctx,
d.expr_or_pat.clone().map(|it| it.either(Into::into, Into::into)),
d.expected,
d.found,
),
) )
} }

View file

@ -39,7 +39,7 @@ pub(crate) fn missing_fields(ctx: &DiagnosticsContext<'_>, d: &hir::MissingField
d.field_list_parent_path d.field_list_parent_path
.clone() .clone()
.map(SyntaxNodePtr::from) .map(SyntaxNodePtr::from)
.unwrap_or_else(|| d.field_list_parent.clone().either(|it| it.into(), |it| it.into())), .unwrap_or_else(|| d.field_list_parent.clone().into()),
); );
Diagnostic::new_with_syntax_node_ptr(ctx, DiagnosticCode::RustcHardError("E0063"), message, ptr) Diagnostic::new_with_syntax_node_ptr(ctx, DiagnosticCode::RustcHardError("E0063"), message, ptr)
@ -58,10 +58,8 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option<Vec<Ass
let root = ctx.sema.db.parse_or_expand(d.file); let root = ctx.sema.db.parse_or_expand(d.file);
let current_module = match &d.field_list_parent { let current_module =
Either::Left(ptr) => ctx.sema.scope(ptr.to_node(&root).syntax()).map(|it| it.module()), ctx.sema.scope(d.field_list_parent.to_node(&root).syntax()).map(|it| it.module());
Either::Right(ptr) => ctx.sema.scope(ptr.to_node(&root).syntax()).map(|it| it.module()),
};
let build_text_edit = |parent_syntax, new_syntax: &SyntaxNode, old_syntax| { let build_text_edit = |parent_syntax, new_syntax: &SyntaxNode, old_syntax| {
let edit = { let edit = {
@ -87,9 +85,8 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option<Vec<Ass
)]) )])
}; };
match &d.field_list_parent { match &d.field_list_parent.to_node(&root) {
Either::Left(record_expr) => { Either::Left(field_list_parent) => {
let field_list_parent = record_expr.to_node(&root);
let missing_fields = ctx.sema.record_literal_missing_fields(&field_list_parent); let missing_fields = ctx.sema.record_literal_missing_fields(&field_list_parent);
let mut locals = FxHashMap::default(); let mut locals = FxHashMap::default();
@ -152,8 +149,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option<Vec<Ass
old_field_list.syntax(), old_field_list.syntax(),
) )
} }
Either::Right(record_pat) => { Either::Right(field_list_parent) => {
let field_list_parent = record_pat.to_node(&root);
let missing_fields = ctx.sema.record_pattern_missing_fields(&field_list_parent); let missing_fields = ctx.sema.record_pattern_missing_fields(&field_list_parent);
let old_field_list = field_list_parent.record_pat_field_list()?; let old_field_list = field_list_parent.record_pat_field_list()?;

View file

@ -13,7 +13,7 @@ use crate::{fix, Assist, Diagnostic, DiagnosticCode, DiagnosticsContext};
// //
// This diagnostic is triggered if created structure does not have field provided in record. // This diagnostic is triggered if created structure does not have field provided in record.
pub(crate) fn no_such_field(ctx: &DiagnosticsContext<'_>, d: &hir::NoSuchField) -> Diagnostic { pub(crate) fn no_such_field(ctx: &DiagnosticsContext<'_>, d: &hir::NoSuchField) -> Diagnostic {
let node = d.field.clone().map(|it| it.either(Into::into, Into::into)); let node = d.field.clone().map(Into::into);
if d.private { if d.private {
// FIXME: quickfix to add required visibility // FIXME: quickfix to add required visibility
Diagnostic::new_with_syntax_node_ptr( Diagnostic::new_with_syntax_node_ptr(
@ -35,15 +35,13 @@ pub(crate) fn no_such_field(ctx: &DiagnosticsContext<'_>, d: &hir::NoSuchField)
fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::NoSuchField) -> Option<Vec<Assist>> { fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::NoSuchField) -> Option<Vec<Assist>> {
// FIXME: quickfix for pattern // FIXME: quickfix for pattern
match &d.field.value { let root = ctx.sema.db.parse_or_expand(d.field.file_id);
Either::Left(ptr) => { match &d.field.value.to_node(&root) {
let root = ctx.sema.db.parse_or_expand(d.field.file_id); Either::Left(node) => missing_record_expr_field_fixes(
missing_record_expr_field_fixes( &ctx.sema,
&ctx.sema, d.field.file_id.original_file(ctx.sema.db),
d.field.file_id.original_file(ctx.sema.db), node,
&ptr.to_node(&root), ),
)
}
_ => None, _ => None,
} }
} }

View file

@ -1,5 +1,3 @@
use either::Either;
use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext}; use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext};
// Diagnostic: private-assoc-item // Diagnostic: private-assoc-item
@ -28,13 +26,7 @@ pub(crate) fn private_assoc_item(
}, },
name, name,
), ),
d.expr_or_pat.clone().map(|it| match it { d.expr_or_pat.clone().map(Into::into),
Either::Left(it) => it.into(),
Either::Right(it) => match it {
Either::Left(it) => it.into(),
Either::Right(it) => it.into(),
},
}),
) )
} }

View file

@ -1,4 +1,3 @@
use either::Either;
use hir::{db::ExpandDatabase, ClosureStyle, HirDisplay, InFile, Type}; use hir::{db::ExpandDatabase, ClosureStyle, HirDisplay, InFile, Type};
use ide_db::{famous_defs::FamousDefs, source_change::SourceChange}; use ide_db::{famous_defs::FamousDefs, source_change::SourceChange};
use syntax::{ use syntax::{
@ -14,9 +13,11 @@ use crate::{adjusted_display_range, fix, Assist, Diagnostic, DiagnosticCode, Dia
// This diagnostic is triggered when the type of an expression or pattern does not match // This diagnostic is triggered when the type of an expression or pattern does not match
// the expected type. // the expected type.
pub(crate) fn type_mismatch(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch) -> Diagnostic { pub(crate) fn type_mismatch(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch) -> Diagnostic {
let display_range = match &d.expr_or_pat { let display_range = match &d.expr_or_pat.value {
Either::Left(expr) => { expr if ast::Expr::can_cast(expr.kind()) => adjusted_display_range::<ast::Expr>(
adjusted_display_range::<ast::Expr>(ctx, expr.clone().map(|it| it.into()), &|expr| { ctx,
InFile { file_id: d.expr_or_pat.file_id, value: expr.syntax_node_ptr() },
&|expr| {
let salient_token_range = match expr { let salient_token_range = match expr {
ast::Expr::IfExpr(it) => it.if_token()?.text_range(), ast::Expr::IfExpr(it) => it.if_token()?.text_range(),
ast::Expr::LoopExpr(it) => it.loop_token()?.text_range(), ast::Expr::LoopExpr(it) => it.loop_token()?.text_range(),
@ -32,10 +33,15 @@ pub(crate) fn type_mismatch(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch)
cov_mark::hit!(type_mismatch_range_adjustment); cov_mark::hit!(type_mismatch_range_adjustment);
Some(salient_token_range) Some(salient_token_range)
}) },
} ),
Either::Right(pat) => { pat => {
ctx.sema.diagnostics_display_range(pat.clone().map(|it| it.into())).range ctx.sema
.diagnostics_display_range(InFile {
file_id: d.expr_or_pat.file_id,
value: pat.syntax_node_ptr(),
})
.range
} }
}; };
let mut diag = Diagnostic::new( let mut diag = Diagnostic::new(
@ -57,14 +63,12 @@ pub(crate) fn type_mismatch(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch)
fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch) -> Option<Vec<Assist>> { fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch) -> Option<Vec<Assist>> {
let mut fixes = Vec::new(); let mut fixes = Vec::new();
match &d.expr_or_pat { if let Some(expr_ptr) = d.expr_or_pat.value.clone().cast::<ast::Expr>() {
Either::Left(expr_ptr) => { let expr_ptr = &InFile { file_id: d.expr_or_pat.file_id, value: expr_ptr.clone() };
add_reference(ctx, d, expr_ptr, &mut fixes); add_reference(ctx, d, expr_ptr, &mut fixes);
add_missing_ok_or_some(ctx, d, expr_ptr, &mut fixes); add_missing_ok_or_some(ctx, d, expr_ptr, &mut fixes);
remove_semicolon(ctx, d, expr_ptr, &mut fixes); remove_semicolon(ctx, d, expr_ptr, &mut fixes);
str_ref_to_owned(ctx, d, expr_ptr, &mut fixes); str_ref_to_owned(ctx, d, expr_ptr, &mut fixes);
}
Either::Right(_pat_ptr) => {}
} }
if fixes.is_empty() { if fixes.is_empty() {

View file

@ -846,9 +846,7 @@ fn location_csv_pat(db: &RootDatabase, vfs: &Vfs, sm: &BodySourceMap, pat_id: Pa
Err(SyntheticSyntax) => return "synthetic,,".to_string(), Err(SyntheticSyntax) => return "synthetic,,".to_string(),
}; };
let root = db.parse_or_expand(src.file_id); let root = db.parse_or_expand(src.file_id);
let node = src.map(|e| { let node = src.map(|e| e.to_node(&root).syntax().clone());
e.either(|it| it.to_node(&root).syntax().clone(), |it| it.to_node(&root).syntax().clone())
});
let original_range = node.as_ref().original_file_range(db); let original_range = node.as_ref().original_file_range(db);
let path = vfs.file_path(original_range.file_id); let path = vfs.file_path(original_range.file_id);
let line_index = db.line_index(original_range.file_id); let line_index = db.line_index(original_range.file_id);
@ -888,12 +886,7 @@ fn pat_syntax_range(
let src = sm.pat_syntax(pat_id); let src = sm.pat_syntax(pat_id);
if let Ok(src) = src { if let Ok(src) = src {
let root = db.parse_or_expand(src.file_id); let root = db.parse_or_expand(src.file_id);
let node = src.map(|e| { let node = src.map(|e| e.to_node(&root).syntax().clone());
e.either(
|it| it.to_node(&root).syntax().clone(),
|it| it.to_node(&root).syntax().clone(),
)
});
let original_range = node.as_ref().original_file_range(db); let original_range = node.as_ref().original_file_range(db);
let path = vfs.file_path(original_range.file_id); let path = vfs.file_path(original_range.file_id);
let line_index = db.line_index(original_range.file_id); let line_index = db.line_index(original_range.file_id);

View file

@ -73,6 +73,10 @@ impl<N: AstNode> AstPtr<N> {
Some(AstPtr { raw: self.raw, _ty: PhantomData }) Some(AstPtr { raw: self.raw, _ty: PhantomData })
} }
pub fn kind(&self) -> parser::SyntaxKind {
self.raw.kind()
}
pub fn upcast<M: AstNode>(self) -> AstPtr<M> pub fn upcast<M: AstNode>(self) -> AstPtr<M>
where where
N: Into<M>, N: Into<M>,
@ -84,6 +88,20 @@ impl<N: AstNode> AstPtr<N> {
pub fn try_from_raw(raw: SyntaxNodePtr) -> Option<AstPtr<N>> { pub fn try_from_raw(raw: SyntaxNodePtr) -> Option<AstPtr<N>> {
N::can_cast(raw.kind()).then_some(AstPtr { raw, _ty: PhantomData }) N::can_cast(raw.kind()).then_some(AstPtr { raw, _ty: PhantomData })
} }
pub fn wrap_left<R>(self) -> AstPtr<either::Either<N, R>>
where
either::Either<N, R>: AstNode,
{
AstPtr { raw: self.raw, _ty: PhantomData }
}
pub fn wrap_right<L>(self) -> AstPtr<either::Either<L, N>>
where
either::Either<L, N>: AstNode,
{
AstPtr { raw: self.raw, _ty: PhantomData }
}
} }
impl<N: AstNode> From<AstPtr<N>> for SyntaxNodePtr { impl<N: AstNode> From<AstPtr<N>> for SyntaxNodePtr {