From 458f4a2960f3264bc7d013a5b3ee15b7943967c4 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 6 Mar 2024 15:57:05 +0100 Subject: [PATCH] internal: Treat the self param as different from patterns when lowering --- crates/hir-def/src/body.rs | 25 +++-- crates/hir-def/src/body/lower.rs | 102 +++++++++--------- crates/hir-def/src/body/pretty.rs | 11 +- crates/hir-def/src/body/scope.rs | 3 + crates/hir-ty/src/infer.rs | 12 ++- crates/hir-ty/src/layout.rs | 4 +- crates/hir-ty/src/mir.rs | 1 + crates/hir-ty/src/mir/eval.rs | 4 + crates/hir-ty/src/mir/lower.rs | 42 ++++++-- .../hir-ty/src/mir/lower/pattern_matching.rs | 33 ++++-- crates/hir-ty/src/tests.rs | 15 ++- crates/hir-ty/src/tests/simple.rs | 3 + crates/hir/src/diagnostics.rs | 4 +- crates/hir/src/lib.rs | 88 ++++++++++----- crates/hir/src/semantics/source_to_def.rs | 12 +-- crates/hir/src/source_analyzer.rs | 7 +- crates/ide/src/inlay_hints/implicit_drop.rs | 4 + crates/rust-analyzer/src/main_loop.rs | 30 +++--- 18 files changed, 256 insertions(+), 144 deletions(-) diff --git a/crates/hir-def/src/body.rs b/crates/hir-def/src/body.rs index 37d37fd331..c9f1add275 100644 --- a/crates/hir-def/src/body.rs +++ b/crates/hir-def/src/body.rs @@ -10,7 +10,6 @@ use std::ops::Index; use base_db::CrateId; use cfg::{CfgExpr, CfgOptions}; -use either::Either; use hir_expand::{name::Name, HirFileId, InFile}; use la_arena::{Arena, ArenaMap}; use rustc_hash::FxHashMap; @@ -45,7 +44,8 @@ pub struct Body { /// /// If this `Body` is for the body of a constant, this will just be /// empty. - pub params: Vec, + pub params: Box<[PatId]>, + pub self_param: Option, /// The `ExprId` of the actual body expression. pub body_expr: ExprId, /// Block expressions in this body that may contain inner items. @@ -55,7 +55,7 @@ pub struct Body { pub type ExprPtr = AstPtr; pub type ExprSource = InFile; -pub type PatPtr = AstPtr>; +pub type PatPtr = AstPtr; pub type PatSource = InFile; pub type LabelPtr = AstPtr; @@ -63,6 +63,7 @@ pub type LabelSource = InFile; pub type FieldPtr = AstPtr; pub type FieldSource = InFile; + pub type PatFieldPtr = AstPtr; pub type PatFieldSource = InFile; @@ -88,6 +89,8 @@ pub struct BodySourceMap { label_map: FxHashMap, label_map_back: ArenaMap, + self_param: Option>>, + /// We don't create explicit nodes for record fields (`S { record_field: 92 }`). /// Instead, we use id of expression (`92`) to identify the field. field_map_back: FxHashMap, @@ -215,10 +218,11 @@ impl Body { fn shrink_to_fit(&mut self) { let Self { body_expr: _, + params: _, + self_param: _, block_scopes, exprs, labels, - params, pats, bindings, binding_owners, @@ -226,7 +230,6 @@ impl Body { block_scopes.shrink_to_fit(); exprs.shrink_to_fit(); labels.shrink_to_fit(); - params.shrink_to_fit(); pats.shrink_to_fit(); bindings.shrink_to_fit(); binding_owners.shrink_to_fit(); @@ -297,6 +300,7 @@ impl Default for Body { params: Default::default(), block_scopes: Default::default(), binding_owners: Default::default(), + self_param: Default::default(), } } } @@ -354,14 +358,12 @@ impl BodySourceMap { self.pat_map_back.get(pat).cloned().ok_or(SyntheticSyntax) } - pub fn node_pat(&self, node: InFile<&ast::Pat>) -> Option { - let src = node.map(|it| AstPtr::new(it).wrap_left()); - self.pat_map.get(&src).cloned() + pub fn self_param_syntax(&self) -> Option>> { + self.self_param } - pub fn node_self_param(&self, node: InFile<&ast::SelfParam>) -> Option { - let src = node.map(|it| AstPtr::new(it).wrap_right()); - self.pat_map.get(&src).cloned() + pub fn node_pat(&self, node: InFile<&ast::Pat>) -> Option { + self.pat_map.get(&node.map(AstPtr::new)).cloned() } pub fn label_syntax(&self, label: LabelId) -> LabelSource { @@ -401,6 +403,7 @@ impl BodySourceMap { fn shrink_to_fit(&mut self) { let Self { + self_param: _, expr_map, expr_map_back, pat_map, diff --git a/crates/hir-def/src/body/lower.rs b/crates/hir-def/src/body/lower.rs index 6669127789..340e95dbc2 100644 --- a/crates/hir-def/src/body/lower.rs +++ b/crates/hir-def/src/body/lower.rs @@ -4,7 +4,6 @@ use std::mem; use base_db::CrateId; -use either::Either; use hir_expand::{ name::{name, AsName, Name}, ExpandError, InFile, @@ -29,7 +28,6 @@ use crate::{ db::DefDatabase, expander::Expander, hir::{ - dummy_expr_id, format_args::{ self, FormatAlignment, FormatArgs, FormatArgsPiece, FormatArgument, FormatArgumentKind, FormatArgumentsCollector, FormatCount, FormatDebugHex, FormatOptions, @@ -66,16 +64,7 @@ pub(super) fn lower( def_map: expander.module.def_map(db), source_map: BodySourceMap::default(), ast_id_map: db.ast_id_map(expander.current_file_id()), - body: Body { - exprs: Default::default(), - pats: Default::default(), - bindings: Default::default(), - binding_owners: Default::default(), - labels: Default::default(), - params: Vec::new(), - body_expr: dummy_expr_id(), - block_scopes: Vec::new(), - }, + body: Body::default(), expander, current_try_block_label: None, is_lowering_assignee_expr: false, @@ -191,35 +180,35 @@ impl ExprCollector<'_> { is_async_fn: bool, ) -> (Body, BodySourceMap) { if let Some((param_list, mut attr_enabled)) = param_list { + let mut params = vec![]; if let Some(self_param) = param_list.self_param().filter(|_| attr_enabled.next().unwrap_or(false)) { let is_mutable = self_param.mut_token().is_some() && self_param.amp_token().is_none(); - let ptr = AstPtr::new(&Either::Right(self_param)); let binding_id: la_arena::Idx = self.alloc_binding(name![self], BindingAnnotation::new(is_mutable, false)); - let param_pat = self.alloc_pat(Pat::Bind { id: binding_id, subpat: None }, ptr); - self.add_definition_to_binding(binding_id, param_pat); - self.body.params.push(param_pat); + self.body.self_param = Some(binding_id); + self.source_map.self_param = Some(self.expander.in_file(AstPtr::new(&self_param))); } for (param, _) in param_list.params().zip(attr_enabled).filter(|(_, enabled)| *enabled) { let param_pat = self.collect_pat_top(param.pat()); - self.body.params.push(param_pat); + params.push(param_pat); } + self.body.params = params.into_boxed_slice(); }; self.body.body_expr = self.with_label_rib(RibKind::Closure, |this| { if is_async_fn { match body { Some(e) => { + let syntax_ptr = AstPtr::new(&e); let expr = this.collect_expr(e); - this.alloc_expr_desugared(Expr::Async { - id: None, - statements: Box::new([]), - tail: Some(expr), - }) + this.alloc_expr_desugared_with_ptr( + Expr::Async { id: None, statements: Box::new([]), tail: Some(expr) }, + syntax_ptr, + ) } None => this.missing_expr(), } @@ -405,7 +394,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 + // make the paren expr point to the inner expression as well for IDE resolution let src = self.expander.in_file(syntax_ptr); self.source_map.expr_map.insert(src, inner); inner @@ -707,6 +696,7 @@ impl ExprCollector<'_> { .alloc_label_desugared(Label { name: Name::generate_new_name(self.body.labels.len()) }); let old_label = self.current_try_block_label.replace(label); + let ptr = AstPtr::new(&e).upcast(); let (btail, expr_id) = self.with_labeled_rib(label, |this| { let mut btail = None; let block = this.collect_block_(e, |id, statements, tail| { @@ -716,23 +706,21 @@ impl ExprCollector<'_> { (btail, block) }); - let callee = self.alloc_expr_desugared(Expr::Path(try_from_output)); + let callee = self.alloc_expr_desugared_with_ptr(Expr::Path(try_from_output), ptr); let next_tail = match btail { - Some(tail) => self.alloc_expr_desugared(Expr::Call { - callee, - args: Box::new([tail]), - is_assignee_expr: false, - }), + Some(tail) => self.alloc_expr_desugared_with_ptr( + Expr::Call { callee, args: Box::new([tail]), is_assignee_expr: false }, + ptr, + ), None => { - let unit = self.alloc_expr_desugared(Expr::Tuple { - exprs: Box::new([]), - is_assignee_expr: false, - }); - self.alloc_expr_desugared(Expr::Call { - callee, - args: Box::new([unit]), - is_assignee_expr: false, - }) + let unit = self.alloc_expr_desugared_with_ptr( + Expr::Tuple { exprs: Box::new([]), is_assignee_expr: false }, + ptr, + ); + self.alloc_expr_desugared_with_ptr( + Expr::Call { callee, args: Box::new([unit]), is_assignee_expr: false }, + ptr, + ) } }; let Expr::Block { tail, .. } = &mut self.body.exprs[expr_id] else { @@ -1067,16 +1055,12 @@ impl ExprCollector<'_> { None => None, }, ); - match expansion { - Some(tail) => { - // Make the macro-call point to its expanded expression so we can query - // semantics on syntax pointers to the macro - let src = self.expander.in_file(syntax_ptr); - self.source_map.expr_map.insert(src, tail); - Some(tail) - } - None => None, - } + expansion.inspect(|&tail| { + // Make the macro-call point to its expanded expression so we can query + // semantics on syntax pointers to the macro + let src = self.expander.in_file(syntax_ptr); + self.source_map.expr_map.insert(src, tail); + }) } fn collect_stmt(&mut self, statements: &mut Vec, s: ast::Stmt) { @@ -1261,7 +1245,7 @@ impl ExprCollector<'_> { (Some(id), Pat::Bind { id, subpat }) }; - let ptr = AstPtr::new(&Either::Left(pat)); + let ptr = AstPtr::new(&pat); let pat = self.alloc_pat(pattern, ptr); if let Some(binding_id) = binding { self.add_definition_to_binding(binding_id, pat); @@ -1359,9 +1343,10 @@ impl ExprCollector<'_> { suffix: suffix.into_iter().map(|p| self.collect_pat(p, binding_list)).collect(), } } - #[rustfmt::skip] // https://github.com/rust-lang/rustfmt/issues/5676 ast::Pat::LiteralPat(lit) => 'b: { - let Some((hir_lit, ast_lit)) = pat_literal_to_hir(lit) else { break 'b Pat::Missing }; + let Some((hir_lit, ast_lit)) = pat_literal_to_hir(lit) else { + break 'b Pat::Missing; + }; let expr = Expr::Literal(hir_lit); let expr_ptr = AstPtr::new(&ast::Expr::Literal(ast_lit)); let expr_id = self.alloc_expr(expr, expr_ptr); @@ -1397,7 +1382,7 @@ impl ExprCollector<'_> { ast::Pat::MacroPat(mac) => match mac.macro_call() { Some(call) => { let macro_ptr = AstPtr::new(&call); - let src = self.expander.in_file(AstPtr::new(&Either::Left(pat))); + let src = self.expander.in_file(AstPtr::new(&pat)); let pat = self.collect_macro_call(call, macro_ptr, true, |this, expanded_pat| { this.collect_pat_opt(expanded_pat, binding_list) @@ -1426,7 +1411,7 @@ impl ExprCollector<'_> { Pat::Range { start, end } } }; - let ptr = AstPtr::new(&Either::Left(pat)); + let ptr = AstPtr::new(&pat); self.alloc_pat(pattern, ptr) } @@ -1987,10 +1972,19 @@ impl ExprCollector<'_> { self.source_map.expr_map.insert(src, id); id } - // FIXME: desugared exprs don't have ptr, that's wrong and should be fixed somehow. + // FIXME: desugared exprs don't have ptr, that's wrong and should be fixed. + // Migrate to alloc_expr_desugared_with_ptr and then rename back fn alloc_expr_desugared(&mut self, expr: Expr) -> ExprId { self.body.exprs.alloc(expr) } + fn alloc_expr_desugared_with_ptr(&mut self, expr: Expr, ptr: ExprPtr) -> ExprId { + let src = self.expander.in_file(ptr); + let id = self.body.exprs.alloc(expr); + self.source_map.expr_map_back.insert(id, src); + // We intentionally don't fill this as it could overwrite a non-desugared entry + // self.source_map.expr_map.insert(src, id); + id + } fn missing_expr(&mut self) -> ExprId { self.alloc_expr_desugared(Expr::Missing) } diff --git a/crates/hir-def/src/body/pretty.rs b/crates/hir-def/src/body/pretty.rs index b2aab55a6a..cbb5ca887f 100644 --- a/crates/hir-def/src/body/pretty.rs +++ b/crates/hir-def/src/body/pretty.rs @@ -48,7 +48,16 @@ pub(super) fn print_body_hir(db: &dyn DefDatabase, body: &Body, owner: DefWithBo let mut p = Printer { db, body, buf: header, indent_level: 0, needs_indent: false }; if let DefWithBodyId::FunctionId(it) = owner { p.buf.push('('); - body.params.iter().zip(db.function_data(it).params.iter()).for_each(|(¶m, ty)| { + let params = &db.function_data(it).params; + let mut params = params.iter(); + if let Some(self_param) = body.self_param { + p.print_binding(self_param); + p.buf.push(':'); + if let Some(ty) = params.next() { + p.print_type_ref(ty); + } + } + body.params.iter().zip(params).for_each(|(¶m, ty)| { p.print_pat(param); p.buf.push(':'); p.print_type_ref(ty); diff --git a/crates/hir-def/src/body/scope.rs b/crates/hir-def/src/body/scope.rs index 69b82ae871..0020e4eac3 100644 --- a/crates/hir-def/src/body/scope.rs +++ b/crates/hir-def/src/body/scope.rs @@ -96,6 +96,9 @@ impl ExprScopes { scope_by_expr: ArenaMap::with_capacity(body.exprs.len()), }; let mut root = scopes.root_scope(); + if let Some(self_param) = body.self_param { + scopes.add_bindings(body, root, self_param); + } scopes.add_params_bindings(body, root, &body.params); compute_expr_scopes(body.body_expr, body, &mut scopes, &mut root); scopes diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs index 9cea414e1a..34ba17f145 100644 --- a/crates/hir-ty/src/infer.rs +++ b/crates/hir-ty/src/infer.rs @@ -22,7 +22,7 @@ mod pat; mod path; pub(crate) mod unify; -use std::{convert::identity, ops::Index}; +use std::{convert::identity, iter, ops::Index}; use chalk_ir::{ cast::Cast, fold::TypeFoldable, interner::HasInterner, DebruijnIndex, Mutability, Safety, @@ -777,7 +777,15 @@ impl<'a> InferenceContext<'a> { param_tys.push(va_list_ty) } - for (ty, pat) in param_tys.into_iter().zip(self.body.params.iter()) { + let mut param_tys = param_tys.into_iter().chain(iter::repeat(self.table.new_type_var())); + if let Some(self_param) = self.body.self_param { + if let Some(ty) = param_tys.next() { + let ty = self.insert_type_vars(ty); + let ty = self.normalize_associated_types_in(ty); + self.write_binding_ty(self_param, ty); + } + } + for (ty, pat) in param_tys.zip(&*self.body.params) { let ty = self.insert_type_vars(ty); let ty = self.normalize_associated_types_in(ty); diff --git a/crates/hir-ty/src/layout.rs b/crates/hir-ty/src/layout.rs index dea292711d..9655981cc9 100644 --- a/crates/hir-ty/src/layout.rs +++ b/crates/hir-ty/src/layout.rs @@ -371,8 +371,8 @@ pub fn layout_of_ty_query( TyKind::Never => cx.layout_of_never_type(), TyKind::Dyn(_) | TyKind::Foreign(_) => { let mut unit = layout_of_unit(&cx, dl)?; - match unit.abi { - Abi::Aggregate { ref mut sized } => *sized = false, + match &mut unit.abi { + Abi::Aggregate { sized } => *sized = false, _ => return Err(LayoutError::Unknown), } unit diff --git a/crates/hir-ty/src/mir.rs b/crates/hir-ty/src/mir.rs index cfaef2a392..d513355037 100644 --- a/crates/hir-ty/src/mir.rs +++ b/crates/hir-ty/src/mir.rs @@ -1165,6 +1165,7 @@ impl MirBody { pub enum MirSpan { ExprId(ExprId), PatId(PatId), + SelfParam, Unknown, } diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs index 2428678d72..fd98141af6 100644 --- a/crates/hir-ty/src/mir/eval.rs +++ b/crates/hir-ty/src/mir/eval.rs @@ -376,6 +376,10 @@ impl MirEvalError { Ok(s) => s.map(|it| it.syntax_node_ptr()), Err(_) => continue, }, + MirSpan::SelfParam => match source_map.self_param_syntax() { + Some(s) => s.map(|it| it.syntax_node_ptr()), + None => continue, + }, MirSpan::Unknown => continue, }; let file_id = span.file_id.original_file(db.upcast()); diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs index d0f739e6ac..7e582c03ef 100644 --- a/crates/hir-ty/src/mir/lower.rs +++ b/crates/hir-ty/src/mir/lower.rs @@ -1810,9 +1810,20 @@ impl<'ctx> MirLowerCtx<'ctx> { fn lower_params_and_bindings( &mut self, params: impl Iterator + Clone, + self_binding: Option<(BindingId, Ty)>, pick_binding: impl Fn(BindingId) -> bool, ) -> Result { let base_param_count = self.result.param_locals.len(); + let self_binding = match self_binding { + Some((self_binding, ty)) => { + let local_id = self.result.locals.alloc(Local { ty }); + self.drop_scopes.last_mut().unwrap().locals.push(local_id); + self.result.binding_locals.insert(self_binding, local_id); + self.result.param_locals.push(local_id); + Some(self_binding) + } + None => None, + }; self.result.param_locals.extend(params.clone().map(|(it, ty)| { let local_id = self.result.locals.alloc(Local { ty }); self.drop_scopes.last_mut().unwrap().locals.push(local_id); @@ -1838,9 +1849,23 @@ impl<'ctx> MirLowerCtx<'ctx> { } } let mut current = self.result.start_block; - for ((param, _), local) in - params.zip(self.result.param_locals.clone().into_iter().skip(base_param_count)) - { + if let Some(self_binding) = self_binding { + let local = self.result.param_locals.clone()[base_param_count]; + if local != self.binding_local(self_binding)? { + let r = self.match_self_param(self_binding, current, local)?; + if let Some(b) = r.1 { + self.set_terminator(b, TerminatorKind::Unreachable, MirSpan::SelfParam); + } + current = r.0; + } + } + let local_params = self + .result + .param_locals + .clone() + .into_iter() + .skip(base_param_count + self_binding.is_some() as usize); + for ((param, _), local) in params.zip(local_params) { if let Pat::Bind { id, .. } = self.body[param] { if local == self.binding_local(id)? { continue; @@ -2019,6 +2044,7 @@ pub fn mir_body_for_closure_query( }; let current = ctx.lower_params_and_bindings( args.iter().zip(sig.params().iter()).map(|(it, y)| (*it, y.clone())), + None, |_| true, )?; if let Some(current) = ctx.lower_expr_to_place(*root, return_slot().into(), current)? { @@ -2149,16 +2175,16 @@ pub fn lower_to_mir( let substs = TyBuilder::placeholder_subst(db, fid); let callable_sig = db.callable_item_signature(fid.into()).substitute(Interner, &substs); + let mut params = callable_sig.params().iter(); + let self_param = body.self_param.and_then(|id| Some((id, params.next()?.clone()))); break 'b ctx.lower_params_and_bindings( - body.params - .iter() - .zip(callable_sig.params().iter()) - .map(|(it, y)| (*it, y.clone())), + body.params.iter().zip(params).map(|(it, y)| (*it, y.clone())), + self_param, binding_picker, )?; } } - ctx.lower_params_and_bindings([].into_iter(), binding_picker)? + ctx.lower_params_and_bindings([].into_iter(), None, binding_picker)? }; if let Some(current) = ctx.lower_expr_to_place(root_expr, return_slot().into(), current)? { let current = ctx.pop_drop_scope_assert_finished(current, root_expr.into())?; diff --git a/crates/hir-ty/src/mir/lower/pattern_matching.rs b/crates/hir-ty/src/mir/lower/pattern_matching.rs index 90cbd13a6c..7596906794 100644 --- a/crates/hir-ty/src/mir/lower/pattern_matching.rs +++ b/crates/hir-ty/src/mir/lower/pattern_matching.rs @@ -11,7 +11,7 @@ use crate::{ Substitution, SwitchTargets, TerminatorKind, TupleFieldId, TupleId, TyBuilder, TyKind, ValueNs, VariantData, VariantId, }, - MutBorrowKind, + LocalId, MutBorrowKind, }, BindingMode, }; @@ -82,6 +82,22 @@ impl MirLowerCtx<'_> { Ok((current, current_else)) } + pub(super) fn match_self_param( + &mut self, + id: BindingId, + current: BasicBlockId, + local: LocalId, + ) -> Result<(BasicBlockId, Option)> { + self.pattern_match_binding( + id, + BindingMode::Move, + local.into(), + MirSpan::SelfParam, + current, + None, + ) + } + fn pattern_match_inner( &mut self, mut current: BasicBlockId, @@ -283,9 +299,9 @@ impl MirLowerCtx<'_> { (current, current_else) = self.pattern_match_inner(current, current_else, next_place, pat, mode)?; } - if let Some(slice) = slice { + if let &Some(slice) = slice { if mode == MatchingMode::Bind { - if let Pat::Bind { id, subpat: _ } = self.body[*slice] { + if let Pat::Bind { id, subpat: _ } = self.body[slice] { let next_place = cond_place.project( ProjectionElem::Subslice { from: prefix.len() as u64, @@ -293,11 +309,12 @@ impl MirLowerCtx<'_> { }, &mut self.result.projection_store, ); + let mode = self.infer.binding_modes[slice]; (current, current_else) = self.pattern_match_binding( id, - *slice, + mode, next_place, - (*slice).into(), + (slice).into(), current, current_else, )?; @@ -398,9 +415,10 @@ impl MirLowerCtx<'_> { self.pattern_match_inner(current, current_else, cond_place, *subpat, mode)? } if mode == MatchingMode::Bind { + let mode = self.infer.binding_modes[pattern]; self.pattern_match_binding( *id, - pattern, + mode, cond_place, pattern.into(), current, @@ -437,14 +455,13 @@ impl MirLowerCtx<'_> { fn pattern_match_binding( &mut self, id: BindingId, - pat: PatId, + mode: BindingMode, cond_place: Place, span: MirSpan, current: BasicBlockId, current_else: Option, ) -> Result<(BasicBlockId, Option)> { let target_place = self.binding_local(id)?; - let mode = self.infer.binding_modes[pat]; self.push_storage_live(id, current)?; self.push_assignment( current, diff --git a/crates/hir-ty/src/tests.rs b/crates/hir-ty/src/tests.rs index 5e159236f4..1cae8eaeac 100644 --- a/crates/hir-ty/src/tests.rs +++ b/crates/hir-ty/src/tests.rs @@ -293,20 +293,29 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { let mut types: Vec<(InFile, &Ty)> = Vec::new(); let mut mismatches: Vec<(InFile, &TypeMismatch)> = Vec::new(); + if let Some(self_param) = body.self_param { + let ty = &inference_result.type_of_binding[self_param]; + if let Some(syntax_ptr) = body_source_map.self_param_syntax() { + let root = db.parse_or_expand(syntax_ptr.file_id); + let node = syntax_ptr.map(|ptr| ptr.to_node(&root).syntax().clone()); + types.push((node.clone(), ty)); + } + } + for (pat, mut ty) in inference_result.type_of_pat.iter() { if let Pat::Bind { id, .. } = body.pats[pat] { ty = &inference_result.type_of_binding[id]; } - let syntax_ptr = match body_source_map.pat_syntax(pat) { + let node = match body_source_map.pat_syntax(pat) { Ok(sp) => { let root = db.parse_or_expand(sp.file_id); sp.map(|ptr| ptr.to_node(&root).syntax().clone()) } Err(SyntheticSyntax) => continue, }; - types.push((syntax_ptr.clone(), ty)); + types.push((node.clone(), ty)); if let Some(mismatch) = inference_result.type_mismatch_for_pat(pat) { - mismatches.push((syntax_ptr, mismatch)); + mismatches.push((node, mismatch)); } } diff --git a/crates/hir-ty/src/tests/simple.rs b/crates/hir-ty/src/tests/simple.rs index ffd6a6051b..917e9f4408 100644 --- a/crates/hir-ty/src/tests/simple.rs +++ b/crates/hir-ty/src/tests/simple.rs @@ -2121,6 +2121,7 @@ async fn main() { "#, expect![[r#" 16..193 '{ ...2 }; }': () + 16..193 '{ ...2 }; }': impl Future 26..27 'x': i32 30..43 'unsafe { 92 }': i32 39..41 '92': i32 @@ -2131,6 +2132,8 @@ async fn main() { 73..75 '()': () 95..96 'z': ControlFlow<(), ()> 130..140 'try { () }': ControlFlow<(), ()> + 130..140 'try { () }': fn from_output>( as Try>::Output) -> ControlFlow<(), ()> + 130..140 'try { () }': ControlFlow<(), ()> 136..138 '()': () 150..151 'w': i32 154..166 'const { 92 }': i32 diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs index fa9fe4953e..4518422d27 100644 --- a/crates/hir/src/diagnostics.rs +++ b/crates/hir/src/diagnostics.rs @@ -204,7 +204,7 @@ pub struct NoSuchField { #[derive(Debug)] pub struct PrivateAssocItem { - pub expr_or_pat: InFile>>>, + pub expr_or_pat: InFile>>, pub item: AssocItem, } @@ -240,7 +240,7 @@ pub struct UnresolvedMethodCall { #[derive(Debug)] pub struct UnresolvedAssocItem { - pub expr_or_pat: InFile>>>, + pub expr_or_pat: InFile>>, } #[derive(Debug)] diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 5eed7ecd5b..ea15535670 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -1725,6 +1725,10 @@ impl DefWithBody { Ok(s) => s.map(|it| it.into()), Err(_) => continue, }, + mir::MirSpan::SelfParam => match source_map.self_param_syntax() { + Some(s) => s.map(|it| it.into()), + None => continue, + }, mir::MirSpan::Unknown => continue, }; acc.push( @@ -1776,6 +1780,11 @@ impl DefWithBody { Ok(s) => s.map(|it| it.into()), Err(_) => continue, }, + mir::MirSpan::SelfParam => match source_map.self_param_syntax() + { + Some(s) => s.map(|it| it.into()), + None => continue, + }, mir::MirSpan::Unknown => continue, }; acc.push(NeedMut { local, span }.into()); @@ -2127,8 +2136,11 @@ impl Param { pub fn as_local(&self, db: &dyn HirDatabase) -> Option { let parent = DefWithBodyId::FunctionId(self.func.into()); let body = db.body(parent); - let pat_id = body.params[self.idx]; - if let Pat::Bind { id, .. } = &body[pat_id] { + if let Some(self_param) = body.self_param.filter(|_| self.idx == 0) { + Some(Local { parent, binding_id: self_param }) + } else if let Pat::Bind { id, .. } = + &body[body.params[self.idx - body.self_param.is_some() as usize]] + { Some(Local { parent, binding_id: *id }) } else { None @@ -2143,7 +2155,7 @@ impl Param { let InFile { file_id, value } = self.func.source(db)?; let params = value.param_list()?; if params.self_param().is_some() { - params.params().nth(self.idx.checked_sub(1)?) + params.params().nth(self.idx.checked_sub(params.self_param().is_some() as usize)?) } else { params.params().nth(self.idx) } @@ -3134,35 +3146,59 @@ impl Local { /// All definitions for this local. Example: `let (a$0, _) | (_, a$0) = it;` pub fn sources(self, db: &dyn HirDatabase) -> Vec { let (body, source_map) = db.body_with_source_map(self.parent); - self.sources_(db, &body, &source_map).collect() + match body.self_param.zip(source_map.self_param_syntax()) { + Some((param, source)) if param == self.binding_id => { + let root = source.file_syntax(db.upcast()); + vec![LocalSource { + local: self, + source: source.map(|ast| Either::Right(ast.to_node(&root))), + }] + } + _ => body[self.binding_id] + .definitions + .iter() + .map(|&definition| { + let src = source_map.pat_syntax(definition).unwrap(); // Hmm... + let root = src.file_syntax(db.upcast()); + LocalSource { + local: self, + source: src.map(|ast| match ast.to_node(&root) { + ast::Pat::IdentPat(it) => Either::Left(it), + _ => unreachable!("local with non ident-pattern"), + }), + } + }) + .collect(), + } } /// The leftmost definition for this local. Example: `let (a$0, _) | (_, a) = it;` pub fn primary_source(self, db: &dyn HirDatabase) -> LocalSource { let (body, source_map) = db.body_with_source_map(self.parent); - let src = self.sources_(db, &body, &source_map).next().unwrap(); - src - } - - fn sources_<'a>( - self, - db: &'a dyn HirDatabase, - body: &'a hir_def::body::Body, - source_map: &'a hir_def::body::BodySourceMap, - ) -> impl Iterator + 'a { - body[self.binding_id] - .definitions - .iter() - .map(|&definition| { - let src = source_map.pat_syntax(definition).unwrap(); // Hmm... - let root = src.file_syntax(db.upcast()); - src.map(|ast| match ast.to_node(&root) { - Either::Left(ast::Pat::IdentPat(it)) => Either::Left(it), - Either::Left(_) => unreachable!("local with non ident-pattern"), - Either::Right(it) => Either::Right(it), + match body.self_param.zip(source_map.self_param_syntax()) { + Some((param, source)) if param == self.binding_id => { + let root = source.file_syntax(db.upcast()); + LocalSource { + local: self, + source: source.map(|ast| Either::Right(ast.to_node(&root))), + } + } + _ => body[self.binding_id] + .definitions + .first() + .map(|&definition| { + let src = source_map.pat_syntax(definition).unwrap(); // Hmm... + let root = src.file_syntax(db.upcast()); + LocalSource { + local: self, + source: src.map(|ast| match ast.to_node(&root) { + ast::Pat::IdentPat(it) => Either::Left(it), + _ => unreachable!("local with non ident-pattern"), + }), + } }) - }) - .map(move |source| LocalSource { local: self, source }) + .unwrap(), + } } } diff --git a/crates/hir/src/semantics/source_to_def.rs b/crates/hir/src/semantics/source_to_def.rs index 4733ea5a35..d4d6f0b243 100644 --- a/crates/hir/src/semantics/source_to_def.rs +++ b/crates/hir/src/semantics/source_to_def.rs @@ -101,7 +101,7 @@ use hir_def::{ use hir_expand::{attrs::AttrId, name::AsName, HirFileId, HirFileIdExt, MacroCallId}; use rustc_hash::FxHashMap; use smallvec::SmallVec; -use stdx::{impl_from, never}; +use stdx::impl_from; use syntax::{ ast::{self, HasName}, AstNode, SyntaxNode, @@ -253,14 +253,8 @@ impl SourceToDefCtx<'_, '_> { src: InFile, ) -> Option<(DefWithBodyId, BindingId)> { let container = self.find_pat_or_label_container(src.syntax())?; - let (body, source_map) = self.db.body_with_source_map(container); - let pat_id = source_map.node_self_param(src.as_ref())?; - if let crate::Pat::Bind { id, .. } = body[pat_id] { - Some((container, id)) - } else { - never!(); - None - } + let body = self.db.body(container); + Some((container, body.self_param?)) } pub(super) fn label_to_def( &mut self, diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index f87e0a3897..dc96a1b03d 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs @@ -219,11 +219,10 @@ impl SourceAnalyzer { pub(crate) fn type_of_self( &self, db: &dyn HirDatabase, - param: &ast::SelfParam, + _param: &ast::SelfParam, ) -> Option { - let src = InFile { file_id: self.file_id, value: param }; - let pat_id = self.body_source_map()?.node_self_param(src)?; - let ty = self.infer.as_ref()?[pat_id].clone(); + let binding = self.body()?.self_param?; + let ty = self.infer.as_ref()?[binding].clone(); Some(Type::new_with_resolver(db, &self.resolver, ty)) } diff --git a/crates/ide/src/inlay_hints/implicit_drop.rs b/crates/ide/src/inlay_hints/implicit_drop.rs index 8d9ad5bda1..5ba4e514e1 100644 --- a/crates/ide/src/inlay_hints/implicit_drop.rs +++ b/crates/ide/src/inlay_hints/implicit_drop.rs @@ -74,6 +74,10 @@ pub(super) fn hints( Ok(s) => s.value.text_range(), Err(_) => continue, }, + MirSpan::SelfParam => match source_map.self_param_syntax() { + Some(s) => s.value.text_range(), + None => continue, + }, MirSpan::Unknown => continue, }; let binding = &hir.bindings[*binding]; diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index bca6db19dc..e106a85c6e 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -488,20 +488,22 @@ impl GlobalState { fn update_diagnostics(&mut self) { let db = self.analysis_host.raw_database(); - let subscriptions = self - .mem_docs - .iter() - .map(|path| self.vfs.read().0.file_id(path).unwrap()) - .filter(|&file_id| { - let source_root = db.file_source_root(file_id); - // Only publish diagnostics for files in the workspace, not from crates.io deps - // or the sysroot. - // While theoretically these should never have errors, we have quite a few false - // positives particularly in the stdlib, and those diagnostics would stay around - // forever if we emitted them here. - !db.source_root(source_root).is_library - }) - .collect::>(); + let subscriptions = { + let vfs = &self.vfs.read().0; + self.mem_docs + .iter() + .map(|path| vfs.file_id(path).unwrap()) + .filter(|&file_id| { + let source_root = db.file_source_root(file_id); + // Only publish diagnostics for files in the workspace, not from crates.io deps + // or the sysroot. + // While theoretically these should never have errors, we have quite a few false + // positives particularly in the stdlib, and those diagnostics would stay around + // forever if we emitted them here. + !db.source_root(source_root).is_library + }) + .collect::>() + }; tracing::trace!("updating notifications for {:?}", subscriptions); // Diagnostics are triggered by the user typing