Unnamed repository; edit this file 'description' to name the repository.
Merge pull request #18995 from alibektas/12210
fix: Lower range pattern bounds to expressions
Lukas Wirth 2025-02-12
parent 5235caf · parent 97251b3 · commit 622ef64
-rw-r--r--crates/hir-def/src/expr_store.rs10
-rw-r--r--crates/hir-def/src/expr_store/lower.rs53
-rw-r--r--crates/hir-def/src/expr_store/pretty.rs16
-rw-r--r--crates/hir-def/src/expr_store/tests.rs45
-rw-r--r--crates/hir-def/src/hir.rs12
-rw-r--r--crates/hir-ty/src/diagnostics/expr.rs4
-rw-r--r--crates/hir-ty/src/mir/lower.rs25
-rw-r--r--crates/hir-ty/src/mir/lower/pattern_matching.rs4
-rw-r--r--crates/hir/src/diagnostics.rs47
-rw-r--r--crates/hir/src/has_source.rs4
-rw-r--r--crates/hir/src/lib.rs9
-rw-r--r--crates/hir/src/semantics/source_to_def.rs2
-rw-r--r--crates/hir/src/source_analyzer.rs58
-rw-r--r--crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs2
-rw-r--r--crates/ide-diagnostics/src/handlers/unresolved_field.rs7
-rw-r--r--crates/ide-diagnostics/src/handlers/unresolved_method.rs6
16 files changed, 187 insertions, 117 deletions
diff --git a/crates/hir-def/src/expr_store.rs b/crates/hir-def/src/expr_store.rs
index 9df6eaade7..5ff6a7ffe5 100644
--- a/crates/hir-def/src/expr_store.rs
+++ b/crates/hir-def/src/expr_store.rs
@@ -112,9 +112,9 @@ pub struct ExpressionStoreSourceMap {
// AST expressions can create patterns in destructuring assignments. Therefore, `ExprSource` can also map
// to `PatId`, and `PatId` can also map to `ExprSource` (the other way around is unaffected).
expr_map: FxHashMap<ExprSource, ExprOrPatId>,
- expr_map_back: ArenaMap<ExprId, ExprSource>,
+ expr_map_back: ArenaMap<ExprId, ExprOrPatSource>,
- pat_map: FxHashMap<PatSource, PatId>,
+ pat_map: FxHashMap<PatSource, ExprOrPatId>,
pat_map_back: ArenaMap<PatId, ExprOrPatSource>,
label_map: FxHashMap<LabelSource, LabelId>,
@@ -606,12 +606,12 @@ impl Index<TypeRefId> for ExpressionStore {
impl ExpressionStoreSourceMap {
pub fn expr_or_pat_syntax(&self, id: ExprOrPatId) -> Result<ExprOrPatSource, SyntheticSyntax> {
match id {
- ExprOrPatId::ExprId(id) => self.expr_syntax(id).map(|it| it.map(AstPtr::wrap_left)),
+ ExprOrPatId::ExprId(id) => self.expr_syntax(id),
ExprOrPatId::PatId(id) => self.pat_syntax(id),
}
}
- pub fn expr_syntax(&self, expr: ExprId) -> Result<ExprSource, SyntheticSyntax> {
+ pub fn expr_syntax(&self, expr: ExprId) -> Result<ExprOrPatSource, SyntheticSyntax> {
self.expr_map_back.get(expr).cloned().ok_or(SyntheticSyntax)
}
@@ -633,7 +633,7 @@ impl ExpressionStoreSourceMap {
self.pat_map_back.get(pat).cloned().ok_or(SyntheticSyntax)
}
- pub fn node_pat(&self, node: InFile<&ast::Pat>) -> Option<PatId> {
+ pub fn node_pat(&self, node: InFile<&ast::Pat>) -> Option<ExprOrPatId> {
self.pat_map.get(&node.map(AstPtr::new)).cloned()
}
diff --git a/crates/hir-def/src/expr_store/lower.rs b/crates/hir-def/src/expr_store/lower.rs
index 88f770da02..6e505a6b11 100644
--- a/crates/hir-def/src/expr_store/lower.rs
+++ b/crates/hir-def/src/expr_store/lower.rs
@@ -44,8 +44,8 @@ use crate::{
FormatPlaceholder, FormatSign, FormatTrait,
},
Array, Binding, BindingAnnotation, BindingId, BindingProblems, CaptureBy, ClosureKind,
- Expr, ExprId, Item, Label, LabelId, Literal, LiteralOrConst, MatchArm, Movability,
- OffsetOf, Pat, PatId, RecordFieldPat, RecordLitField, Statement,
+ Expr, ExprId, Item, Label, LabelId, Literal, MatchArm, Movability, OffsetOf, Pat, PatId,
+ RecordFieldPat, RecordLitField, Statement,
},
item_scope::BuiltinShadowMode,
lang_item::LangItem,
@@ -1784,23 +1784,33 @@ impl ExprCollector<'_> {
self.collect_macro_call(call, macro_ptr, true, |this, expanded_pat| {
this.collect_pat_opt(expanded_pat, binding_list)
});
- self.source_map.pat_map.insert(src, pat);
+ self.source_map.pat_map.insert(src, pat.into());
return pat;
}
None => Pat::Missing,
},
- // FIXME: implement in a way that also builds source map and calculates assoc resolutions in type inference.
ast::Pat::RangePat(p) => {
- let mut range_part_lower = |p: Option<ast::Pat>| {
- p.and_then(|it| match &it {
- ast::Pat::LiteralPat(it) => {
- Some(Box::new(LiteralOrConst::Literal(pat_literal_to_hir(it)?.0)))
+ let mut range_part_lower = |p: Option<ast::Pat>| -> Option<ExprId> {
+ p.and_then(|it| {
+ let ptr = PatPtr::new(&it);
+ match &it {
+ ast::Pat::LiteralPat(it) => Some(self.alloc_expr_from_pat(
+ Expr::Literal(pat_literal_to_hir(it)?.0),
+ ptr,
+ )),
+ ast::Pat::IdentPat(ident) if ident.is_simple_ident() => ident
+ .name()
+ .map(|name| name.as_name())
+ .map(Path::from)
+ .map(|path| self.alloc_expr_from_pat(Expr::Path(path), ptr)),
+ ast::Pat::PathPat(p) => p
+ .path()
+ .and_then(|path| self.parse_path(path))
+ .map(|parsed| self.alloc_expr_from_pat(Expr::Path(parsed), ptr)),
+ // We only need to handle literal, ident (if bare) and path patterns here,
+ // as any other pattern as a range pattern operand is semantically invalid.
+ _ => None,
}
- pat @ (ast::Pat::IdentPat(_) | ast::Pat::PathPat(_)) => {
- let subpat = self.collect_pat(pat.clone(), binding_list);
- Some(Box::new(LiteralOrConst::Const(subpat)))
- }
- _ => None,
})
};
let start = range_part_lower(p.start());
@@ -1863,7 +1873,7 @@ impl ExprCollector<'_> {
}
});
if let Some(pat) = pat.left() {
- self.source_map.pat_map.insert(src, pat);
+ self.source_map.pat_map.insert(src, pat.into());
}
pat
}
@@ -2490,7 +2500,7 @@ impl ExprCollector<'_> {
fn alloc_expr(&mut self, expr: Expr, ptr: ExprPtr) -> ExprId {
let src = self.expander.in_file(ptr);
let id = self.store.exprs.alloc(expr);
- self.source_map.expr_map_back.insert(id, src);
+ self.source_map.expr_map_back.insert(id, src.map(AstPtr::wrap_left));
self.source_map.expr_map.insert(src, id.into());
id
}
@@ -2502,7 +2512,7 @@ impl ExprCollector<'_> {
fn alloc_expr_desugared_with_ptr(&mut self, expr: Expr, ptr: ExprPtr) -> ExprId {
let src = self.expander.in_file(ptr);
let id = self.store.exprs.alloc(expr);
- self.source_map.expr_map_back.insert(id, src);
+ self.source_map.expr_map_back.insert(id, src.map(AstPtr::wrap_left));
// We intentionally don't fill this as it could overwrite a non-desugared entry
// self.source_map.expr_map.insert(src, id);
id
@@ -2526,11 +2536,20 @@ impl ExprCollector<'_> {
self.source_map.pat_map_back.insert(id, src.map(AstPtr::wrap_left));
id
}
+
+ fn alloc_expr_from_pat(&mut self, expr: Expr, ptr: PatPtr) -> ExprId {
+ let src = self.expander.in_file(ptr);
+ let id = self.store.exprs.alloc(expr);
+ self.source_map.pat_map.insert(src, id.into());
+ self.source_map.expr_map_back.insert(id, src.map(AstPtr::wrap_right));
+ id
+ }
+
fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId {
let src = self.expander.in_file(ptr);
let id = self.store.pats.alloc(pat);
self.source_map.pat_map_back.insert(id, src.map(AstPtr::wrap_right));
- self.source_map.pat_map.insert(src, id);
+ self.source_map.pat_map.insert(src, id.into());
id
}
// FIXME: desugared pats don't have ptr, that's wrong and should be fixed somehow.
diff --git a/crates/hir-def/src/expr_store/pretty.rs b/crates/hir-def/src/expr_store/pretty.rs
index 6a0b1e5197..82ad756dc2 100644
--- a/crates/hir-def/src/expr_store/pretty.rs
+++ b/crates/hir-def/src/expr_store/pretty.rs
@@ -6,10 +6,7 @@ use itertools::Itertools;
use span::Edition;
use crate::{
- hir::{
- Array, BindingAnnotation, CaptureBy, ClosureKind, Literal, LiteralOrConst, Movability,
- Statement,
- },
+ hir::{Array, BindingAnnotation, CaptureBy, ClosureKind, Literal, Movability, Statement},
pretty::{print_generic_args, print_path, print_type_ref},
};
@@ -656,11 +653,11 @@ impl Printer<'_> {
}
Pat::Range { start, end } => {
if let Some(start) = start {
- self.print_literal_or_const(start);
+ self.print_expr(*start);
}
w!(self, "..=");
if let Some(end) = end {
- self.print_literal_or_const(end);
+ self.print_expr(*end);
}
}
Pat::Slice { prefix, slice, suffix } => {
@@ -757,13 +754,6 @@ impl Printer<'_> {
}
}
- fn print_literal_or_const(&mut self, literal_or_const: &LiteralOrConst) {
- match literal_or_const {
- LiteralOrConst::Literal(l) => self.print_literal(l),
- LiteralOrConst::Const(c) => self.print_pat(*c),
- }
- }
-
fn print_literal(&mut self, literal: &Literal) {
match literal {
Literal::String(it) => w!(self, "{:?}", it),
diff --git a/crates/hir-def/src/expr_store/tests.rs b/crates/hir-def/src/expr_store/tests.rs
index 9bf1ddb479..16bf46d3e3 100644
--- a/crates/hir-def/src/expr_store/tests.rs
+++ b/crates/hir-def/src/expr_store/tests.rs
@@ -1,11 +1,10 @@
mod block;
+use crate::{hir::MatchArm, test_db::TestDB, ModuleDefId};
use expect_test::{expect, Expect};
use la_arena::RawIdx;
use test_fixture::WithFixture;
-use crate::{test_db::TestDB, ModuleDefId};
-
use super::*;
fn lower(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> (TestDB, Arc<Body>, DefWithBodyId) {
@@ -460,3 +459,45 @@ async fn foo(a: (), b: i32) -> u32 {
expect!["fn foo(�: (), �: i32) -> impl ::core::future::Future::<Output = u32> �"]
.assert_eq(&printed);
}
+
+#[test]
+fn range_bounds_are_hir_exprs() {
+ let (_, body, _) = lower(
+ r#"
+pub const L: i32 = 6;
+mod x {
+ pub const R: i32 = 100;
+}
+const fn f(x: i32) -> i32 {
+ match x {
+ -1..=5 => x * 10,
+ L..=x::R => x * 100,
+ _ => x,
+ }
+}"#,
+ );
+
+ let mtch_arms = body
+ .exprs
+ .iter()
+ .find_map(|(_, expr)| {
+ if let Expr::Match { arms, .. } = expr {
+ return Some(arms);
+ }
+
+ None
+ })
+ .unwrap();
+
+ let MatchArm { pat, .. } = mtch_arms[1];
+ match body.pats[pat] {
+ Pat::Range { start, end } => {
+ let hir_start = &body.exprs[start.unwrap()];
+ let hir_end = &body.exprs[end.unwrap()];
+
+ assert!(matches!(hir_start, Expr::Path { .. }));
+ assert!(matches!(hir_end, Expr::Path { .. }));
+ }
+ _ => {}
+ }
+}
diff --git a/crates/hir-def/src/hir.rs b/crates/hir-def/src/hir.rs
index 0dcddf162b..494644d8ef 100644
--- a/crates/hir-def/src/hir.rs
+++ b/crates/hir-def/src/hir.rs
@@ -55,12 +55,20 @@ impl ExprOrPatId {
}
}
+ pub fn is_expr(&self) -> bool {
+ matches!(self, Self::ExprId(_))
+ }
+
pub fn as_pat(self) -> Option<PatId> {
match self {
Self::PatId(v) => Some(v),
_ => None,
}
}
+
+ pub fn is_pat(&self) -> bool {
+ matches!(self, Self::PatId(_))
+ }
}
stdx::impl_from!(ExprId, PatId for ExprOrPatId);
@@ -571,8 +579,8 @@ pub enum Pat {
ellipsis: bool,
},
Range {
- start: Option<Box<LiteralOrConst>>,
- end: Option<Box<LiteralOrConst>>,
+ start: Option<ExprId>,
+ end: Option<ExprId>,
},
Slice {
prefix: Box<[PatId]>,
diff --git a/crates/hir-ty/src/diagnostics/expr.rs b/crates/hir-ty/src/diagnostics/expr.rs
index 0b5f131924..59aaf85164 100644
--- a/crates/hir-ty/src/diagnostics/expr.rs
+++ b/crates/hir-ty/src/diagnostics/expr.rs
@@ -440,7 +440,9 @@ impl ExprValidator {
return;
};
let root = source_ptr.file_syntax(db.upcast());
- let ast::Expr::IfExpr(if_expr) = source_ptr.value.to_node(&root) else {
+ let either::Left(ast::Expr::IfExpr(if_expr)) =
+ source_ptr.value.to_node(&root)
+ else {
return;
};
let mut top_if_expr = if_expr;
diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs
index 549450e9be..f88696692e 100644
--- a/crates/hir-ty/src/mir/lower.rs
+++ b/crates/hir-ty/src/mir/lower.rs
@@ -8,8 +8,8 @@ use hir_def::{
data::adt::{StructKind, VariantData},
expr_store::{Body, HygieneId},
hir::{
- ArithOp, Array, BinaryOp, BindingAnnotation, BindingId, ExprId, LabelId, Literal,
- LiteralOrConst, MatchArm, Pat, PatId, RecordFieldPat, RecordLitField,
+ ArithOp, Array, BinaryOp, BindingAnnotation, BindingId, ExprId, LabelId, Literal, MatchArm,
+ Pat, PatId, RecordFieldPat, RecordLitField,
},
lang_item::{LangItem, LangItemTarget},
path::Path,
@@ -1358,20 +1358,10 @@ impl<'ctx> MirLowerCtx<'ctx> {
Ok(())
}
- fn lower_literal_or_const_to_operand(
- &mut self,
- ty: Ty,
- loc: &LiteralOrConst,
- ) -> Result<Operand> {
- match loc {
- LiteralOrConst::Literal(l) => self.lower_literal_to_operand(ty, l),
- LiteralOrConst::Const(c) => {
- let c = match &self.body.pats[*c] {
- Pat::Path(p) => p,
- _ => not_supported!(
- "only `char` and numeric types are allowed in range patterns"
- ),
- };
+ fn lower_literal_or_const_to_operand(&mut self, ty: Ty, loc: &ExprId) -> Result<Operand> {
+ match &self.body.exprs[*loc] {
+ Expr::Literal(l) => self.lower_literal_to_operand(ty, l),
+ Expr::Path(c) => {
let edition = self.edition();
let unresolved_name =
|| MirLowerError::unresolved_path(self.db, c, edition, &self.body.types);
@@ -1392,6 +1382,9 @@ impl<'ctx> MirLowerCtx<'ctx> {
}
}
}
+ _ => {
+ not_supported!("only `char` and numeric types are allowed in range patterns");
+ }
}
}
diff --git a/crates/hir-ty/src/mir/lower/pattern_matching.rs b/crates/hir-ty/src/mir/lower/pattern_matching.rs
index 2ffea34c85..289175feef 100644
--- a/crates/hir-ty/src/mir/lower/pattern_matching.rs
+++ b/crates/hir-ty/src/mir/lower/pattern_matching.rs
@@ -1,6 +1,6 @@
//! MIR lowering for patterns
-use hir_def::{hir::LiteralOrConst, AssocItemId};
+use hir_def::{hir::ExprId, AssocItemId};
use crate::{
mir::{
@@ -207,7 +207,7 @@ impl MirLowerCtx<'_> {
)?
}
Pat::Range { start, end } => {
- let mut add_check = |l: &LiteralOrConst, binop| -> Result<()> {
+ let mut add_check = |l: &ExprId, binop| -> Result<()> {
let lv =
self.lower_literal_or_const_to_operand(self.infer[pattern].clone(), l)?;
let else_target = *current_else.get_or_insert_with(|| self.new_basic_block());
diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs
index 64e982c42d..5876529df9 100644
--- a/crates/hir/src/diagnostics.rs
+++ b/crates/hir/src/diagnostics.rs
@@ -6,6 +6,7 @@
use cfg::{CfgExpr, CfgOptions};
use either::Either;
use hir_def::{
+ expr_store::ExprOrPatPtr,
hir::ExprOrPatId,
path::{hir_segment_to_ast_segment, ModPath},
type_ref::TypesSourceMap,
@@ -115,14 +116,14 @@ diagnostics![
#[derive(Debug)]
pub struct BreakOutsideOfLoop {
- pub expr: InFile<AstPtr<ast::Expr>>,
+ pub expr: InFile<ExprOrPatPtr>,
pub is_break: bool,
pub bad_value_break: bool,
}
#[derive(Debug)]
pub struct TypedHole {
- pub expr: InFile<AstPtr<ast::Expr>>,
+ pub expr: InFile<ExprOrPatPtr>,
pub expected: Type,
}
@@ -221,26 +222,26 @@ pub struct NoSuchField {
#[derive(Debug)]
pub struct PrivateAssocItem {
- pub expr_or_pat: InFile<AstPtr<Either<ast::Expr, ast::Pat>>>,
+ pub expr_or_pat: InFile<ExprOrPatPtr>,
pub item: AssocItem,
}
#[derive(Debug)]
pub struct MismatchedTupleStructPatArgCount {
- pub expr_or_pat: InFile<AstPtr<Either<ast::Expr, ast::Pat>>>,
+ pub expr_or_pat: InFile<ExprOrPatPtr>,
pub expected: usize,
pub found: usize,
}
#[derive(Debug)]
pub struct ExpectedFunction {
- pub call: InFile<AstPtr<ast::Expr>>,
+ pub call: InFile<ExprOrPatPtr>,
pub found: Type,
}
#[derive(Debug)]
pub struct UnresolvedField {
- pub expr: InFile<AstPtr<ast::Expr>>,
+ pub expr: InFile<ExprOrPatPtr>,
pub receiver: Type,
pub name: Name,
pub method_with_same_name_exists: bool,
@@ -248,7 +249,7 @@ pub struct UnresolvedField {
#[derive(Debug)]
pub struct UnresolvedMethodCall {
- pub expr: InFile<AstPtr<ast::Expr>>,
+ pub expr: InFile<ExprOrPatPtr>,
pub receiver: Type,
pub name: Name,
pub field_with_same_name: Option<Type>,
@@ -257,17 +258,17 @@ pub struct UnresolvedMethodCall {
#[derive(Debug)]
pub struct UnresolvedAssocItem {
- pub expr_or_pat: InFile<AstPtr<Either<ast::Expr, ast::Pat>>>,
+ pub expr_or_pat: InFile<ExprOrPatPtr>,
}
#[derive(Debug)]
pub struct UnresolvedIdent {
- pub node: InFile<(AstPtr<Either<ast::Expr, ast::Pat>>, Option<TextRange>)>,
+ pub node: InFile<(ExprOrPatPtr, Option<TextRange>)>,
}
#[derive(Debug)]
pub struct PrivateField {
- pub expr: InFile<AstPtr<ast::Expr>>,
+ pub expr: InFile<ExprOrPatPtr>,
pub field: Field,
}
@@ -280,7 +281,7 @@ pub enum UnsafeLint {
#[derive(Debug)]
pub struct MissingUnsafe {
- pub node: InFile<AstPtr<Either<ast::Expr, ast::Pat>>>,
+ pub node: InFile<ExprOrPatPtr>,
pub lint: UnsafeLint,
pub reason: UnsafetyReason,
}
@@ -302,7 +303,7 @@ pub struct ReplaceFilterMapNextWithFindMap {
#[derive(Debug)]
pub struct MismatchedArgCount {
- pub call_expr: InFile<AstPtr<ast::Expr>>,
+ pub call_expr: InFile<ExprOrPatPtr>,
pub expected: usize,
pub found: usize,
}
@@ -321,7 +322,7 @@ pub struct NonExhaustiveLet {
#[derive(Debug)]
pub struct TypeMismatch {
- pub expr_or_pat: InFile<AstPtr<Either<ast::Expr, ast::Pat>>>,
+ pub expr_or_pat: InFile<ExprOrPatPtr>,
pub expected: Type,
pub actual: Type,
}
@@ -395,13 +396,13 @@ pub struct RemoveUnnecessaryElse {
#[derive(Debug)]
pub struct CastToUnsized {
- pub expr: InFile<AstPtr<ast::Expr>>,
+ pub expr: InFile<ExprOrPatPtr>,
pub cast_ty: Type,
}
#[derive(Debug)]
pub struct InvalidCast {
- pub expr: InFile<AstPtr<ast::Expr>>,
+ pub expr: InFile<ExprOrPatPtr>,
pub error: CastError,
pub expr_ty: Type,
pub cast_ty: Type,
@@ -428,9 +429,7 @@ impl AnyDiagnostic {
.collect();
let record = match record {
- Either::Left(record_expr) => {
- source_map.expr_syntax(record_expr).ok()?.map(AstPtr::wrap_left)
- }
+ Either::Left(record_expr) => source_map.expr_syntax(record_expr).ok()?,
Either::Right(record_pat) => source_map.pat_syntax(record_pat).ok()?,
};
let file = record.file_id;
@@ -474,7 +473,7 @@ impl AnyDiagnostic {
return Some(
ReplaceFilterMapNextWithFindMap {
file: next_source_ptr.file_id,
- next_expr: next_source_ptr.value,
+ next_expr: next_source_ptr.value.cast()?,
}
.into(),
);
@@ -484,7 +483,9 @@ impl AnyDiagnostic {
match source_map.expr_syntax(match_expr) {
Ok(source_ptr) => {
let root = source_ptr.file_syntax(db.upcast());
- if let ast::Expr::MatchExpr(match_expr) = &source_ptr.value.to_node(&root) {
+ if let Either::Left(ast::Expr::MatchExpr(match_expr)) =
+ &source_ptr.value.to_node(&root)
+ {
match match_expr.expr() {
Some(scrut_expr) if match_expr.match_arm_list().is_some() => {
return Some(
@@ -561,7 +562,7 @@ impl AnyDiagnostic {
let pat_syntax =
|pat| source_map.pat_syntax(pat).inspect_err(|_| stdx::never!("synthetic syntax")).ok();
let expr_or_pat_syntax = |id| match id {
- ExprOrPatId::ExprId(expr) => expr_syntax(expr).map(|it| it.map(AstPtr::wrap_left)),
+ ExprOrPatId::ExprId(expr) => expr_syntax(expr),
ExprOrPatId::PatId(pat) => pat_syntax(pat),
};
Some(match d {
@@ -633,7 +634,7 @@ impl AnyDiagnostic {
&InferenceDiagnostic::UnresolvedIdent { id } => {
let node = match id {
ExprOrPatId::ExprId(id) => match source_map.expr_syntax(id) {
- Ok(syntax) => syntax.map(|it| (it.wrap_left(), None)),
+ Ok(syntax) => syntax.map(|it| (it, None)),
Err(SyntheticSyntax) => source_map
.format_args_implicit_capture(id)?
.map(|(node, range)| (node.wrap_left(), Some(range))),
@@ -652,7 +653,7 @@ impl AnyDiagnostic {
}
&InferenceDiagnostic::MismatchedTupleStructPatArgCount { pat, expected, found } => {
let expr_or_pat = match pat {
- ExprOrPatId::ExprId(expr) => expr_syntax(expr)?.map(AstPtr::wrap_left),
+ ExprOrPatId::ExprId(expr) => expr_syntax(expr)?,
ExprOrPatId::PatId(pat) => {
let InFile { file_id, value } = pat_syntax(pat)?;
diff --git a/crates/hir/src/has_source.rs b/crates/hir/src/has_source.rs
index 82c90ac301..a34b498083 100644
--- a/crates/hir/src/has_source.rs
+++ b/crates/hir/src/has_source.rs
@@ -248,7 +248,7 @@ impl HasSource for Param {
let ast @ InFile { file_id, value } = source_map.expr_syntax(expr_id).ok()?;
let root = db.parse_or_expand(file_id);
match value.to_node(&root) {
- ast::Expr::ClosureExpr(it) => it
+ Either::Left(ast::Expr::ClosureExpr(it)) => it
.param_list()?
.params()
.nth(self.idx)
@@ -301,7 +301,7 @@ impl HasSource for InlineAsmOperand {
let root = src.file_syntax(db.upcast());
return src
.map(|ast| match ast.to_node(&root) {
- ast::Expr::AsmExpr(asm) => asm
+ Either::Left(ast::Expr::AsmExpr(asm)) => asm
.asm_pieces()
.filter_map(|it| match it {
ast::AsmPiece::AsmOperandNamed(it) => Some(it),
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 56090bc6b6..8b8203acb1 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -1957,7 +1957,7 @@ impl DefWithBody {
ExprOrPatId::PatId(pat) => source_map.pat_syntax(pat).map(Either::Right),
};
let expr_or_pat = match expr_or_pat {
- Ok(Either::Left(expr)) => expr.map(AstPtr::wrap_left),
+ Ok(Either::Left(expr)) => expr,
Ok(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 {
@@ -2003,7 +2003,7 @@ impl DefWithBody {
match source_map.expr_syntax(node) {
Ok(node) => acc.push(
MissingUnsafe {
- node: node.map(|it| it.wrap_left()),
+ node,
lint: UnsafeLint::DeprecatedSafe2024,
reason: UnsafetyReason::UnsafeFnCall,
}
@@ -4592,10 +4592,7 @@ impl CaptureUsages {
match span {
mir::MirSpan::ExprId(expr) => {
if let Ok(expr) = source_map.expr_syntax(expr) {
- result.push(CaptureUsageSource {
- is_ref,
- source: expr.map(AstPtr::wrap_left),
- })
+ result.push(CaptureUsageSource { is_ref, source: expr })
}
}
mir::MirSpan::PatId(pat) => {
diff --git a/crates/hir/src/semantics/source_to_def.rs b/crates/hir/src/semantics/source_to_def.rs
index 3c9e7065c4..29d3736bae 100644
--- a/crates/hir/src/semantics/source_to_def.rs
+++ b/crates/hir/src/semantics/source_to_def.rs
@@ -352,7 +352,7 @@ impl SourceToDefCtx<'_, '_> {
let src = src.cloned().map(ast::Pat::from);
let pat_id = source_map.node_pat(src.as_ref())?;
// the pattern could resolve to a constant, verify that this is not the case
- if let crate::Pat::Bind { id, .. } = body[pat_id] {
+ if let crate::Pat::Bind { id, .. } = body[pat_id.as_pat()?] {
Some((container, id))
} else {
None
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs
index c687e2d8a0..9019863f7f 100644
--- a/crates/hir/src/source_analyzer.rs
+++ b/crates/hir/src/source_analyzer.rs
@@ -18,7 +18,7 @@ use hir_def::{
scope::{ExprScopes, ScopeId},
Body, BodySourceMap, HygieneId,
},
- hir::{BindingId, Expr, ExprId, ExprOrPatId, Pat, PatId},
+ hir::{BindingId, Expr, ExprId, ExprOrPatId, Pat},
lang_item::LangItem,
lower::LowerCtx,
nameres::MacroSubNs,
@@ -139,7 +139,7 @@ impl SourceAnalyzer {
sm.node_expr(src.as_ref())
}
- fn pat_id(&self, pat: &ast::Pat) -> Option<PatId> {
+ fn pat_id(&self, pat: &ast::Pat) -> Option<ExprOrPatId> {
// FIXME: macros, see `expr_id`
let src = InFile { file_id: self.file_id, value: pat };
self.body_source_map()?.node_pat(src)
@@ -147,7 +147,7 @@ impl SourceAnalyzer {
fn binding_id_of_pat(&self, pat: &ast::IdentPat) -> Option<BindingId> {
let pat_id = self.pat_id(&pat.clone().into())?;
- if let Pat::Bind { id, .. } = self.body()?.pats[pat_id] {
+ if let Pat::Bind { id, .. } = self.body()?.pats[pat_id.as_pat()?] {
Some(id)
} else {
None
@@ -210,11 +210,20 @@ impl SourceAnalyzer {
db: &dyn HirDatabase,
pat: &ast::Pat,
) -> Option<(Type, Option<Type>)> {
- let pat_id = self.pat_id(pat)?;
+ let expr_or_pat_id = self.pat_id(pat)?;
let infer = self.infer.as_ref()?;
- let coerced =
- infer.pat_adjustments.get(&pat_id).and_then(|adjusts| adjusts.last().cloned());
- let ty = infer[pat_id].clone();
+ let coerced = match expr_or_pat_id {
+ ExprOrPatId::ExprId(idx) => infer
+ .expr_adjustments
+ .get(&idx)
+ .and_then(|adjusts| adjusts.last().cloned())
+ .map(|adjust| adjust.target),
+ ExprOrPatId::PatId(idx) => {
+ infer.pat_adjustments.get(&idx).and_then(|adjusts| adjusts.last().cloned())
+ }
+ };
+
+ let ty = infer[expr_or_pat_id].clone();
let mk_ty = |ty| Type::new_with_resolver(db, &self.resolver, ty);
Some((mk_ty(ty), coerced.map(mk_ty)))
}
@@ -248,7 +257,7 @@ impl SourceAnalyzer {
) -> Option<BindingMode> {
let id = self.pat_id(&pat.clone().into())?;
let infer = self.infer.as_ref()?;
- infer.binding_modes.get(id).map(|bm| match bm {
+ infer.binding_modes.get(id.as_pat()?).map(|bm| match bm {
hir_ty::BindingMode::Move => BindingMode::Move,
hir_ty::BindingMode::Ref(hir_ty::Mutability::Mut) => BindingMode::Ref(Mutability::Mut),
hir_ty::BindingMode::Ref(hir_ty::Mutability::Not) => {
@@ -266,7 +275,7 @@ impl SourceAnalyzer {
Some(
infer
.pat_adjustments
- .get(&pat_id)?
+ .get(&pat_id.as_pat()?)?
.iter()
.map(|ty| Type::new_with_resolver(db, &self.resolver, ty.clone()))
.collect(),
@@ -649,10 +658,10 @@ impl SourceAnalyzer {
let field_name = field.field_name()?.as_name();
let record_pat = ast::RecordPat::cast(field.syntax().parent().and_then(|p| p.parent())?)?;
let pat_id = self.pat_id(&record_pat.into())?;
- let variant = self.infer.as_ref()?.variant_resolution_for_pat(pat_id)?;
+ let variant = self.infer.as_ref()?.variant_resolution_for_pat(pat_id.as_pat()?)?;
let variant_data = variant.variant_data(db.upcast());
let field = FieldId { parent: variant, local_id: variant_data.field(&field_name)? };
- let (adt, subst) = self.infer.as_ref()?.type_of_pat.get(pat_id)?.as_adt()?;
+ let (adt, subst) = self.infer.as_ref()?.type_of_pat.get(pat_id.as_pat()?)?.as_adt()?;
let field_ty =
db.field_types(variant).get(field.local_id)?.clone().substitute(Interner, subst);
Some((
@@ -682,12 +691,20 @@ impl SourceAnalyzer {
db: &dyn HirDatabase,
pat: &ast::IdentPat,
) -> Option<ModuleDef> {
- let pat_id = self.pat_id(&pat.clone().into())?;
+ let expr_or_pat_id = self.pat_id(&pat.clone().into())?;
let body = self.body()?;
- let path = match &body[pat_id] {
- Pat::Path(path) => path,
- _ => return None,
+
+ let path = match expr_or_pat_id {
+ ExprOrPatId::ExprId(idx) => match &body[idx] {
+ Expr::Path(path) => path,
+ _ => return None,
+ },
+ ExprOrPatId::PatId(idx) => match &body[idx] {
+ Pat::Path(path) => path,
+ _ => return None,
+ },
};
+
let res = resolve_hir_path(db, &self.resolver, path, HygieneId::ROOT, TypesMap::EMPTY)?;
match res {
PathResolution::Def(def) => Some(def),
@@ -782,8 +799,9 @@ impl SourceAnalyzer {
}
prefer_value_ns = true;
} else if let Some(path_pat) = parent().and_then(ast::PathPat::cast) {
- let pat_id = self.pat_id(&path_pat.into())?;
- if let Some((assoc, subs)) = infer.assoc_resolutions_for_pat(pat_id) {
+ let expr_or_pat_id = self.pat_id(&path_pat.into())?;
+ if let Some((assoc, subs)) = infer.assoc_resolutions_for_expr_or_pat(expr_or_pat_id)
+ {
let (assoc, subst) = match assoc {
AssocItemId::ConstId(const_id) => {
let (konst, subst) =
@@ -807,7 +825,7 @@ impl SourceAnalyzer {
return Some((PathResolution::Def(AssocItem::from(assoc).into()), Some(subst)));
}
if let Some(VariantId::EnumVariantId(variant)) =
- infer.variant_resolution_for_pat(pat_id)
+ infer.variant_resolution_for_expr_or_pat(expr_or_pat_id)
{
return Some((PathResolution::Def(ModuleDef::Variant(variant.into())), None));
}
@@ -824,7 +842,7 @@ impl SourceAnalyzer {
|| parent().and_then(ast::TupleStructPat::cast).map(ast::Pat::from);
if let Some(pat) = record_pat.or_else(tuple_struct_pat) {
let pat_id = self.pat_id(&pat)?;
- let variant_res_for_pat = infer.variant_resolution_for_pat(pat_id);
+ let variant_res_for_pat = infer.variant_resolution_for_pat(pat_id.as_pat()?);
if let Some(VariantId::EnumVariantId(variant)) = variant_res_for_pat {
return Some((
PathResolution::Def(ModuleDef::Variant(variant.into())),
@@ -1080,7 +1098,7 @@ impl SourceAnalyzer {
let body = self.body()?;
let infer = self.infer.as_ref()?;
- let pat_id = self.pat_id(&pattern.clone().into())?;
+ let pat_id = self.pat_id(&pattern.clone().into())?.as_pat()?;
let substs = infer.type_of_pat[pat_id].as_adt()?.1;
let (variant, missing_fields, _exhaustive) =
diff --git a/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs b/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs
index 7126617cde..0520bb3fe9 100644
--- a/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs
+++ b/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs
@@ -40,7 +40,7 @@ pub(crate) fn mismatched_arg_count(
Diagnostic::new(
DiagnosticCode::RustcHardError("E0107"),
message,
- invalid_args_range(ctx, d.call_expr.map(AstPtr::wrap_left), d.expected, d.found),
+ invalid_args_range(ctx, d.call_expr, d.expected, d.found),
)
}
diff --git a/crates/ide-diagnostics/src/handlers/unresolved_field.rs b/crates/ide-diagnostics/src/handlers/unresolved_field.rs
index 4accd181ca..dfb03eee73 100644
--- a/crates/ide-diagnostics/src/handlers/unresolved_field.rs
+++ b/crates/ide-diagnostics/src/handlers/unresolved_field.rs
@@ -1,5 +1,6 @@
use std::iter;
+use either::Either;
use hir::{db::ExpandDatabase, Adt, FileRange, HasSource, HirDisplay, InFile, Struct, Union};
use ide_db::text_edit::TextEdit;
use ide_db::{
@@ -41,7 +42,7 @@ pub(crate) fn unresolved_field(
),
adjusted_display_range(ctx, d.expr, &|expr| {
Some(
- match expr {
+ match expr.left()? {
ast::Expr::MethodCallExpr(it) => it.name_ref(),
ast::Expr::FieldExpr(it) => it.name_ref(),
_ => None,
@@ -72,7 +73,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedField) -> Option<Vec<A
fn field_fix(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedField) -> Option<Assist> {
// Get the FileRange of the invalid field access
let root = ctx.sema.db.parse_or_expand(d.expr.file_id);
- let expr = d.expr.value.to_node(&root);
+ let expr = d.expr.value.to_node(&root).left()?;
let error_range = ctx.sema.original_range_opt(expr.syntax())?;
let field_name = d.name.as_str();
@@ -263,7 +264,7 @@ fn record_field_layout(
// FIXME: We should fill out the call here, move the cursor and trigger signature help
fn method_fix(
ctx: &DiagnosticsContext<'_>,
- expr_ptr: &InFile<AstPtr<ast::Expr>>,
+ expr_ptr: &InFile<AstPtr<Either<ast::Expr, ast::Pat>>>,
) -> Option<Assist> {
let root = ctx.sema.db.parse_or_expand(expr_ptr.file_id);
let expr = expr_ptr.value.to_node(&root);
diff --git a/crates/ide-diagnostics/src/handlers/unresolved_method.rs b/crates/ide-diagnostics/src/handlers/unresolved_method.rs
index 4ab649cc16..dd1b593e8f 100644
--- a/crates/ide-diagnostics/src/handlers/unresolved_method.rs
+++ b/crates/ide-diagnostics/src/handlers/unresolved_method.rs
@@ -35,7 +35,7 @@ pub(crate) fn unresolved_method(
),
adjusted_display_range(ctx, d.expr, &|expr| {
Some(
- match expr {
+ match expr.left()? {
ast::Expr::MethodCallExpr(it) => it.name_ref(),
ast::Expr::FieldExpr(it) => it.name_ref(),
_ => None,
@@ -85,7 +85,7 @@ fn field_fix(
let expr_ptr = &d.expr;
let root = ctx.sema.db.parse_or_expand(expr_ptr.file_id);
let expr = expr_ptr.value.to_node(&root);
- let (file_id, range) = match expr {
+ let (file_id, range) = match expr.left()? {
ast::Expr::MethodCallExpr(mcall) => {
let FileRange { range, file_id } =
ctx.sema.original_range_opt(mcall.receiver()?.syntax())?;
@@ -117,7 +117,7 @@ fn assoc_func_fix(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedMethodCall) -
let expr_ptr = &d.expr;
let root = db.parse_or_expand(expr_ptr.file_id);
- let expr: ast::Expr = expr_ptr.value.to_node(&root);
+ let expr: ast::Expr = expr_ptr.value.to_node(&root).left()?;
let call = ast::MethodCallExpr::cast(expr.syntax().clone())?;
let range = InFile::new(expr_ptr.file_id, call.syntax().text_range())