mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-29 02:52:11 +00:00
Merge pull request #18995 from alibektas/12210
fix: Lower range pattern bounds to expressions
This commit is contained in:
commit
622ef64f93
16 changed files with 187 additions and 117 deletions
|
|
@ -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()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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(<28>: (), <20>: i32) -> impl ::core::future::Future::<Output = u32> <20>"]
|
||||
.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 { .. }));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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]>,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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)?;
|
||||
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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) => {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) =
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue