Auto merge of #16771 - Veykril:self-param-split, r=Veykril

internal: Don't desugar self param into a pattern

Small experiment to see if this simplifies things
This commit is contained in:
bors 2024-03-11 12:45:46 +00:00
commit 2320e12541
18 changed files with 256 additions and 144 deletions

View file

@ -10,7 +10,6 @@ use std::ops::Index;
use base_db::CrateId; use base_db::CrateId;
use cfg::{CfgExpr, CfgOptions}; use cfg::{CfgExpr, CfgOptions};
use either::Either;
use hir_expand::{name::Name, HirFileId, InFile}; use hir_expand::{name::Name, HirFileId, InFile};
use la_arena::{Arena, ArenaMap}; use la_arena::{Arena, ArenaMap};
use rustc_hash::FxHashMap; 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 /// If this `Body` is for the body of a constant, this will just be
/// empty. /// empty.
pub params: Vec<PatId>, pub params: Box<[PatId]>,
pub self_param: Option<BindingId>,
/// The `ExprId` of the actual body expression. /// The `ExprId` of the actual body expression.
pub body_expr: ExprId, pub body_expr: ExprId,
/// Block expressions in this body that may contain inner items. /// Block expressions in this body that may contain inner items.
@ -55,7 +55,7 @@ pub struct Body {
pub type ExprPtr = AstPtr<ast::Expr>; pub type ExprPtr = AstPtr<ast::Expr>;
pub type ExprSource = InFile<ExprPtr>; pub type ExprSource = InFile<ExprPtr>;
pub type PatPtr = AstPtr<Either<ast::Pat, ast::SelfParam>>; pub type PatPtr = AstPtr<ast::Pat>;
pub type PatSource = InFile<PatPtr>; pub type PatSource = InFile<PatPtr>;
pub type LabelPtr = AstPtr<ast::Label>; pub type LabelPtr = AstPtr<ast::Label>;
@ -63,6 +63,7 @@ pub type LabelSource = InFile<LabelPtr>;
pub type FieldPtr = AstPtr<ast::RecordExprField>; pub type FieldPtr = AstPtr<ast::RecordExprField>;
pub type FieldSource = InFile<FieldPtr>; pub type FieldSource = InFile<FieldPtr>;
pub type PatFieldPtr = AstPtr<ast::RecordPatField>; pub type PatFieldPtr = AstPtr<ast::RecordPatField>;
pub type PatFieldSource = InFile<PatFieldPtr>; pub type PatFieldSource = InFile<PatFieldPtr>;
@ -88,6 +89,8 @@ pub struct BodySourceMap {
label_map: FxHashMap<LabelSource, LabelId>, label_map: FxHashMap<LabelSource, LabelId>,
label_map_back: ArenaMap<LabelId, LabelSource>, label_map_back: ArenaMap<LabelId, LabelSource>,
self_param: Option<InFile<AstPtr<ast::SelfParam>>>,
/// We don't create explicit nodes for record fields (`S { record_field: 92 }`). /// We don't create explicit nodes for record fields (`S { record_field: 92 }`).
/// Instead, we use id of expression (`92`) to identify the field. /// Instead, we use id of expression (`92`) to identify the field.
field_map_back: FxHashMap<ExprId, FieldSource>, field_map_back: FxHashMap<ExprId, FieldSource>,
@ -215,10 +218,11 @@ impl Body {
fn shrink_to_fit(&mut self) { fn shrink_to_fit(&mut self) {
let Self { let Self {
body_expr: _, body_expr: _,
params: _,
self_param: _,
block_scopes, block_scopes,
exprs, exprs,
labels, labels,
params,
pats, pats,
bindings, bindings,
binding_owners, binding_owners,
@ -226,7 +230,6 @@ impl Body {
block_scopes.shrink_to_fit(); block_scopes.shrink_to_fit();
exprs.shrink_to_fit(); exprs.shrink_to_fit();
labels.shrink_to_fit(); labels.shrink_to_fit();
params.shrink_to_fit();
pats.shrink_to_fit(); pats.shrink_to_fit();
bindings.shrink_to_fit(); bindings.shrink_to_fit();
binding_owners.shrink_to_fit(); binding_owners.shrink_to_fit();
@ -297,6 +300,7 @@ impl Default for Body {
params: Default::default(), params: Default::default(),
block_scopes: Default::default(), block_scopes: Default::default(),
binding_owners: 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) self.pat_map_back.get(pat).cloned().ok_or(SyntheticSyntax)
} }
pub fn node_pat(&self, node: InFile<&ast::Pat>) -> Option<PatId> { pub fn self_param_syntax(&self) -> Option<InFile<AstPtr<ast::SelfParam>>> {
let src = node.map(|it| AstPtr::new(it).wrap_left()); self.self_param
self.pat_map.get(&src).cloned()
} }
pub fn node_self_param(&self, node: InFile<&ast::SelfParam>) -> Option<PatId> { pub fn node_pat(&self, node: InFile<&ast::Pat>) -> Option<PatId> {
let src = node.map(|it| AstPtr::new(it).wrap_right()); self.pat_map.get(&node.map(AstPtr::new)).cloned()
self.pat_map.get(&src).cloned()
} }
pub fn label_syntax(&self, label: LabelId) -> LabelSource { pub fn label_syntax(&self, label: LabelId) -> LabelSource {
@ -401,6 +403,7 @@ impl BodySourceMap {
fn shrink_to_fit(&mut self) { fn shrink_to_fit(&mut self) {
let Self { let Self {
self_param: _,
expr_map, expr_map,
expr_map_back, expr_map_back,
pat_map, pat_map,

View file

@ -4,7 +4,6 @@
use std::mem; use std::mem;
use base_db::CrateId; use base_db::CrateId;
use either::Either;
use hir_expand::{ use hir_expand::{
name::{name, AsName, Name}, name::{name, AsName, Name},
ExpandError, InFile, ExpandError, InFile,
@ -29,7 +28,6 @@ use crate::{
db::DefDatabase, db::DefDatabase,
expander::Expander, expander::Expander,
hir::{ hir::{
dummy_expr_id,
format_args::{ format_args::{
self, FormatAlignment, FormatArgs, FormatArgsPiece, FormatArgument, FormatArgumentKind, self, FormatAlignment, FormatArgs, FormatArgsPiece, FormatArgument, FormatArgumentKind,
FormatArgumentsCollector, FormatCount, FormatDebugHex, FormatOptions, FormatArgumentsCollector, FormatCount, FormatDebugHex, FormatOptions,
@ -66,16 +64,7 @@ pub(super) fn lower(
def_map: expander.module.def_map(db), def_map: expander.module.def_map(db),
source_map: BodySourceMap::default(), source_map: BodySourceMap::default(),
ast_id_map: db.ast_id_map(expander.current_file_id()), ast_id_map: db.ast_id_map(expander.current_file_id()),
body: Body { body: Body::default(),
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(),
},
expander, expander,
current_try_block_label: None, current_try_block_label: None,
is_lowering_assignee_expr: false, is_lowering_assignee_expr: false,
@ -191,35 +180,35 @@ impl ExprCollector<'_> {
is_async_fn: bool, is_async_fn: bool,
) -> (Body, BodySourceMap) { ) -> (Body, BodySourceMap) {
if let Some((param_list, mut attr_enabled)) = param_list { if let Some((param_list, mut attr_enabled)) = param_list {
let mut params = vec![];
if let Some(self_param) = if let Some(self_param) =
param_list.self_param().filter(|_| attr_enabled.next().unwrap_or(false)) param_list.self_param().filter(|_| attr_enabled.next().unwrap_or(false))
{ {
let is_mutable = let is_mutable =
self_param.mut_token().is_some() && self_param.amp_token().is_none(); 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<Binding> = let binding_id: la_arena::Idx<Binding> =
self.alloc_binding(name![self], BindingAnnotation::new(is_mutable, false)); 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.body.self_param = Some(binding_id);
self.add_definition_to_binding(binding_id, param_pat); self.source_map.self_param = Some(self.expander.in_file(AstPtr::new(&self_param)));
self.body.params.push(param_pat);
} }
for (param, _) in param_list.params().zip(attr_enabled).filter(|(_, enabled)| *enabled) for (param, _) in param_list.params().zip(attr_enabled).filter(|(_, enabled)| *enabled)
{ {
let param_pat = self.collect_pat_top(param.pat()); 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| { self.body.body_expr = self.with_label_rib(RibKind::Closure, |this| {
if is_async_fn { if is_async_fn {
match body { match body {
Some(e) => { Some(e) => {
let syntax_ptr = AstPtr::new(&e);
let expr = this.collect_expr(e); let expr = this.collect_expr(e);
this.alloc_expr_desugared(Expr::Async { this.alloc_expr_desugared_with_ptr(
id: None, Expr::Async { id: None, statements: Box::new([]), tail: Some(expr) },
statements: Box::new([]), syntax_ptr,
tail: Some(expr), )
})
} }
None => this.missing_expr(), None => this.missing_expr(),
} }
@ -405,7 +394,7 @@ impl ExprCollector<'_> {
} }
ast::Expr::ParenExpr(e) => { ast::Expr::ParenExpr(e) => {
let inner = self.collect_expr_opt(e.expr()); 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); let src = self.expander.in_file(syntax_ptr);
self.source_map.expr_map.insert(src, inner); self.source_map.expr_map.insert(src, inner);
inner inner
@ -707,6 +696,7 @@ impl ExprCollector<'_> {
.alloc_label_desugared(Label { name: Name::generate_new_name(self.body.labels.len()) }); .alloc_label_desugared(Label { name: Name::generate_new_name(self.body.labels.len()) });
let old_label = self.current_try_block_label.replace(label); 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 (btail, expr_id) = self.with_labeled_rib(label, |this| {
let mut btail = None; let mut btail = None;
let block = this.collect_block_(e, |id, statements, tail| { let block = this.collect_block_(e, |id, statements, tail| {
@ -716,23 +706,21 @@ impl ExprCollector<'_> {
(btail, block) (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 { let next_tail = match btail {
Some(tail) => self.alloc_expr_desugared(Expr::Call { Some(tail) => self.alloc_expr_desugared_with_ptr(
callee, Expr::Call { callee, args: Box::new([tail]), is_assignee_expr: false },
args: Box::new([tail]), ptr,
is_assignee_expr: false, ),
}),
None => { None => {
let unit = self.alloc_expr_desugared(Expr::Tuple { let unit = self.alloc_expr_desugared_with_ptr(
exprs: Box::new([]), Expr::Tuple { exprs: Box::new([]), is_assignee_expr: false },
is_assignee_expr: false, ptr,
}); );
self.alloc_expr_desugared(Expr::Call { self.alloc_expr_desugared_with_ptr(
callee, Expr::Call { callee, args: Box::new([unit]), is_assignee_expr: false },
args: Box::new([unit]), ptr,
is_assignee_expr: false, )
})
} }
}; };
let Expr::Block { tail, .. } = &mut self.body.exprs[expr_id] else { let Expr::Block { tail, .. } = &mut self.body.exprs[expr_id] else {
@ -1067,16 +1055,12 @@ impl ExprCollector<'_> {
None => None, None => None,
}, },
); );
match expansion { expansion.inspect(|&tail| {
Some(tail) => { // Make the macro-call point to its expanded expression so we can query
// Make the macro-call point to its expanded expression so we can query // semantics on syntax pointers to the macro
// semantics on syntax pointers to the macro let src = self.expander.in_file(syntax_ptr);
let src = self.expander.in_file(syntax_ptr); self.source_map.expr_map.insert(src, tail);
self.source_map.expr_map.insert(src, tail); })
Some(tail)
}
None => None,
}
} }
fn collect_stmt(&mut self, statements: &mut Vec<Statement>, s: ast::Stmt) { fn collect_stmt(&mut self, statements: &mut Vec<Statement>, s: ast::Stmt) {
@ -1261,7 +1245,7 @@ impl ExprCollector<'_> {
(Some(id), Pat::Bind { id, subpat }) (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); let pat = self.alloc_pat(pattern, ptr);
if let Some(binding_id) = binding { if let Some(binding_id) = binding {
self.add_definition_to_binding(binding_id, pat); self.add_definition_to_binding(binding_id, pat);
@ -1359,9 +1343,10 @@ impl ExprCollector<'_> {
suffix: suffix.into_iter().map(|p| self.collect_pat(p, binding_list)).collect(), 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: { 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 = Expr::Literal(hir_lit);
let expr_ptr = AstPtr::new(&ast::Expr::Literal(ast_lit)); let expr_ptr = AstPtr::new(&ast::Expr::Literal(ast_lit));
let expr_id = self.alloc_expr(expr, expr_ptr); let expr_id = self.alloc_expr(expr, expr_ptr);
@ -1397,7 +1382,7 @@ impl ExprCollector<'_> {
ast::Pat::MacroPat(mac) => match mac.macro_call() { ast::Pat::MacroPat(mac) => match mac.macro_call() {
Some(call) => { Some(call) => {
let macro_ptr = AstPtr::new(&call); let macro_ptr = AstPtr::new(&call);
let src = self.expander.in_file(AstPtr::new(&Either::Left(pat))); let src = self.expander.in_file(AstPtr::new(&pat));
let pat = let pat =
self.collect_macro_call(call, macro_ptr, true, |this, expanded_pat| { self.collect_macro_call(call, macro_ptr, true, |this, expanded_pat| {
this.collect_pat_opt(expanded_pat, binding_list) this.collect_pat_opt(expanded_pat, binding_list)
@ -1426,7 +1411,7 @@ impl ExprCollector<'_> {
Pat::Range { start, end } Pat::Range { start, end }
} }
}; };
let ptr = AstPtr::new(&Either::Left(pat)); let ptr = AstPtr::new(&pat);
self.alloc_pat(pattern, ptr) self.alloc_pat(pattern, ptr)
} }
@ -1987,10 +1972,19 @@ impl ExprCollector<'_> {
self.source_map.expr_map.insert(src, id); self.source_map.expr_map.insert(src, id);
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 { fn alloc_expr_desugared(&mut self, expr: Expr) -> ExprId {
self.body.exprs.alloc(expr) 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 { fn missing_expr(&mut self) -> ExprId {
self.alloc_expr_desugared(Expr::Missing) self.alloc_expr_desugared(Expr::Missing)
} }

View file

@ -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 }; let mut p = Printer { db, body, buf: header, indent_level: 0, needs_indent: false };
if let DefWithBodyId::FunctionId(it) = owner { if let DefWithBodyId::FunctionId(it) = owner {
p.buf.push('('); p.buf.push('(');
body.params.iter().zip(db.function_data(it).params.iter()).for_each(|(&param, 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(|(&param, ty)| {
p.print_pat(param); p.print_pat(param);
p.buf.push(':'); p.buf.push(':');
p.print_type_ref(ty); p.print_type_ref(ty);

View file

@ -96,6 +96,9 @@ impl ExprScopes {
scope_by_expr: ArenaMap::with_capacity(body.exprs.len()), scope_by_expr: ArenaMap::with_capacity(body.exprs.len()),
}; };
let mut root = scopes.root_scope(); 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); scopes.add_params_bindings(body, root, &body.params);
compute_expr_scopes(body.body_expr, body, &mut scopes, &mut root); compute_expr_scopes(body.body_expr, body, &mut scopes, &mut root);
scopes scopes

View file

@ -22,7 +22,7 @@ mod pat;
mod path; mod path;
pub(crate) mod unify; pub(crate) mod unify;
use std::{convert::identity, ops::Index}; use std::{convert::identity, iter, ops::Index};
use chalk_ir::{ use chalk_ir::{
cast::Cast, fold::TypeFoldable, interner::HasInterner, DebruijnIndex, Mutability, Safety, cast::Cast, fold::TypeFoldable, interner::HasInterner, DebruijnIndex, Mutability, Safety,
@ -777,7 +777,15 @@ impl<'a> InferenceContext<'a> {
param_tys.push(va_list_ty) 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.insert_type_vars(ty);
let ty = self.normalize_associated_types_in(ty); let ty = self.normalize_associated_types_in(ty);

View file

@ -371,8 +371,8 @@ pub fn layout_of_ty_query(
TyKind::Never => cx.layout_of_never_type(), TyKind::Never => cx.layout_of_never_type(),
TyKind::Dyn(_) | TyKind::Foreign(_) => { TyKind::Dyn(_) | TyKind::Foreign(_) => {
let mut unit = layout_of_unit(&cx, dl)?; let mut unit = layout_of_unit(&cx, dl)?;
match unit.abi { match &mut unit.abi {
Abi::Aggregate { ref mut sized } => *sized = false, Abi::Aggregate { sized } => *sized = false,
_ => return Err(LayoutError::Unknown), _ => return Err(LayoutError::Unknown),
} }
unit unit

View file

@ -1165,6 +1165,7 @@ impl MirBody {
pub enum MirSpan { pub enum MirSpan {
ExprId(ExprId), ExprId(ExprId),
PatId(PatId), PatId(PatId),
SelfParam,
Unknown, Unknown,
} }

View file

@ -376,6 +376,10 @@ impl MirEvalError {
Ok(s) => s.map(|it| it.syntax_node_ptr()), Ok(s) => s.map(|it| it.syntax_node_ptr()),
Err(_) => continue, Err(_) => continue,
}, },
MirSpan::SelfParam => match source_map.self_param_syntax() {
Some(s) => s.map(|it| it.syntax_node_ptr()),
None => continue,
},
MirSpan::Unknown => continue, MirSpan::Unknown => continue,
}; };
let file_id = span.file_id.original_file(db.upcast()); let file_id = span.file_id.original_file(db.upcast());

View file

@ -1810,9 +1810,20 @@ impl<'ctx> MirLowerCtx<'ctx> {
fn lower_params_and_bindings( fn lower_params_and_bindings(
&mut self, &mut self,
params: impl Iterator<Item = (PatId, Ty)> + Clone, params: impl Iterator<Item = (PatId, Ty)> + Clone,
self_binding: Option<(BindingId, Ty)>,
pick_binding: impl Fn(BindingId) -> bool, pick_binding: impl Fn(BindingId) -> bool,
) -> Result<BasicBlockId> { ) -> Result<BasicBlockId> {
let base_param_count = self.result.param_locals.len(); 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)| { self.result.param_locals.extend(params.clone().map(|(it, ty)| {
let local_id = self.result.locals.alloc(Local { ty }); let local_id = self.result.locals.alloc(Local { ty });
self.drop_scopes.last_mut().unwrap().locals.push(local_id); 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; let mut current = self.result.start_block;
for ((param, _), local) in if let Some(self_binding) = self_binding {
params.zip(self.result.param_locals.clone().into_iter().skip(base_param_count)) 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 let Pat::Bind { id, .. } = self.body[param] {
if local == self.binding_local(id)? { if local == self.binding_local(id)? {
continue; continue;
@ -2019,6 +2044,7 @@ pub fn mir_body_for_closure_query(
}; };
let current = ctx.lower_params_and_bindings( let current = ctx.lower_params_and_bindings(
args.iter().zip(sig.params().iter()).map(|(it, y)| (*it, y.clone())), args.iter().zip(sig.params().iter()).map(|(it, y)| (*it, y.clone())),
None,
|_| true, |_| true,
)?; )?;
if let Some(current) = ctx.lower_expr_to_place(*root, return_slot().into(), current)? { 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 substs = TyBuilder::placeholder_subst(db, fid);
let callable_sig = let callable_sig =
db.callable_item_signature(fid.into()).substitute(Interner, &substs); 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( break 'b ctx.lower_params_and_bindings(
body.params body.params.iter().zip(params).map(|(it, y)| (*it, y.clone())),
.iter() self_param,
.zip(callable_sig.params().iter())
.map(|(it, y)| (*it, y.clone())),
binding_picker, 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)? { 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())?; let current = ctx.pop_drop_scope_assert_finished(current, root_expr.into())?;

View file

@ -11,7 +11,7 @@ use crate::{
Substitution, SwitchTargets, TerminatorKind, TupleFieldId, TupleId, TyBuilder, TyKind, Substitution, SwitchTargets, TerminatorKind, TupleFieldId, TupleId, TyBuilder, TyKind,
ValueNs, VariantData, VariantId, ValueNs, VariantData, VariantId,
}, },
MutBorrowKind, LocalId, MutBorrowKind,
}, },
BindingMode, BindingMode,
}; };
@ -82,6 +82,22 @@ impl MirLowerCtx<'_> {
Ok((current, current_else)) Ok((current, current_else))
} }
pub(super) fn match_self_param(
&mut self,
id: BindingId,
current: BasicBlockId,
local: LocalId,
) -> Result<(BasicBlockId, Option<BasicBlockId>)> {
self.pattern_match_binding(
id,
BindingMode::Move,
local.into(),
MirSpan::SelfParam,
current,
None,
)
}
fn pattern_match_inner( fn pattern_match_inner(
&mut self, &mut self,
mut current: BasicBlockId, mut current: BasicBlockId,
@ -283,9 +299,9 @@ impl MirLowerCtx<'_> {
(current, current_else) = (current, current_else) =
self.pattern_match_inner(current, current_else, next_place, pat, mode)?; 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 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( let next_place = cond_place.project(
ProjectionElem::Subslice { ProjectionElem::Subslice {
from: prefix.len() as u64, from: prefix.len() as u64,
@ -293,11 +309,12 @@ impl MirLowerCtx<'_> {
}, },
&mut self.result.projection_store, &mut self.result.projection_store,
); );
let mode = self.infer.binding_modes[slice];
(current, current_else) = self.pattern_match_binding( (current, current_else) = self.pattern_match_binding(
id, id,
*slice, mode,
next_place, next_place,
(*slice).into(), (slice).into(),
current, current,
current_else, current_else,
)?; )?;
@ -398,9 +415,10 @@ impl MirLowerCtx<'_> {
self.pattern_match_inner(current, current_else, cond_place, *subpat, mode)? self.pattern_match_inner(current, current_else, cond_place, *subpat, mode)?
} }
if mode == MatchingMode::Bind { if mode == MatchingMode::Bind {
let mode = self.infer.binding_modes[pattern];
self.pattern_match_binding( self.pattern_match_binding(
*id, *id,
pattern, mode,
cond_place, cond_place,
pattern.into(), pattern.into(),
current, current,
@ -437,14 +455,13 @@ impl MirLowerCtx<'_> {
fn pattern_match_binding( fn pattern_match_binding(
&mut self, &mut self,
id: BindingId, id: BindingId,
pat: PatId, mode: BindingMode,
cond_place: Place, cond_place: Place,
span: MirSpan, span: MirSpan,
current: BasicBlockId, current: BasicBlockId,
current_else: Option<BasicBlockId>, current_else: Option<BasicBlockId>,
) -> Result<(BasicBlockId, Option<BasicBlockId>)> { ) -> Result<(BasicBlockId, Option<BasicBlockId>)> {
let target_place = self.binding_local(id)?; let target_place = self.binding_local(id)?;
let mode = self.infer.binding_modes[pat];
self.push_storage_live(id, current)?; self.push_storage_live(id, current)?;
self.push_assignment( self.push_assignment(
current, current,

View file

@ -293,20 +293,29 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String {
let mut types: Vec<(InFile<SyntaxNode>, &Ty)> = Vec::new(); let mut types: Vec<(InFile<SyntaxNode>, &Ty)> = Vec::new();
let mut mismatches: Vec<(InFile<SyntaxNode>, &TypeMismatch)> = Vec::new(); let mut mismatches: Vec<(InFile<SyntaxNode>, &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() { for (pat, mut ty) in inference_result.type_of_pat.iter() {
if let Pat::Bind { id, .. } = body.pats[pat] { if let Pat::Bind { id, .. } = body.pats[pat] {
ty = &inference_result.type_of_binding[id]; 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) => { Ok(sp) => {
let root = db.parse_or_expand(sp.file_id); let root = db.parse_or_expand(sp.file_id);
sp.map(|ptr| ptr.to_node(&root).syntax().clone()) sp.map(|ptr| ptr.to_node(&root).syntax().clone())
} }
Err(SyntheticSyntax) => continue, 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) { if let Some(mismatch) = inference_result.type_mismatch_for_pat(pat) {
mismatches.push((syntax_ptr, mismatch)); mismatches.push((node, mismatch));
} }
} }

View file

@ -2121,6 +2121,7 @@ async fn main() {
"#, "#,
expect![[r#" expect![[r#"
16..193 '{ ...2 }; }': () 16..193 '{ ...2 }; }': ()
16..193 '{ ...2 }; }': impl Future<Output = ()>
26..27 'x': i32 26..27 'x': i32
30..43 'unsafe { 92 }': i32 30..43 'unsafe { 92 }': i32
39..41 '92': i32 39..41 '92': i32
@ -2131,6 +2132,8 @@ async fn main() {
73..75 '()': () 73..75 '()': ()
95..96 'z': ControlFlow<(), ()> 95..96 'z': ControlFlow<(), ()>
130..140 'try { () }': ControlFlow<(), ()> 130..140 'try { () }': ControlFlow<(), ()>
130..140 'try { () }': fn from_output<ControlFlow<(), ()>>(<ControlFlow<(), ()> as Try>::Output) -> ControlFlow<(), ()>
130..140 'try { () }': ControlFlow<(), ()>
136..138 '()': () 136..138 '()': ()
150..151 'w': i32 150..151 'w': i32
154..166 'const { 92 }': i32 154..166 'const { 92 }': i32

View file

@ -204,7 +204,7 @@ pub struct NoSuchField {
#[derive(Debug)] #[derive(Debug)]
pub struct PrivateAssocItem { pub struct PrivateAssocItem {
pub expr_or_pat: InFile<AstPtr<Either<ast::Expr, Either<ast::Pat, ast::SelfParam>>>>, pub expr_or_pat: InFile<AstPtr<Either<ast::Expr, ast::Pat>>>,
pub item: AssocItem, pub item: AssocItem,
} }
@ -240,7 +240,7 @@ pub struct UnresolvedMethodCall {
#[derive(Debug)] #[derive(Debug)]
pub struct UnresolvedAssocItem { pub struct UnresolvedAssocItem {
pub expr_or_pat: InFile<AstPtr<Either<ast::Expr, Either<ast::Pat, ast::SelfParam>>>>, pub expr_or_pat: InFile<AstPtr<Either<ast::Expr, ast::Pat>>>,
} }
#[derive(Debug)] #[derive(Debug)]

View file

@ -1725,6 +1725,10 @@ impl DefWithBody {
Ok(s) => s.map(|it| it.into()), Ok(s) => s.map(|it| it.into()),
Err(_) => continue, Err(_) => continue,
}, },
mir::MirSpan::SelfParam => match source_map.self_param_syntax() {
Some(s) => s.map(|it| it.into()),
None => continue,
},
mir::MirSpan::Unknown => continue, mir::MirSpan::Unknown => continue,
}; };
acc.push( acc.push(
@ -1776,6 +1780,11 @@ impl DefWithBody {
Ok(s) => s.map(|it| it.into()), Ok(s) => s.map(|it| it.into()),
Err(_) => continue, Err(_) => continue,
}, },
mir::MirSpan::SelfParam => match source_map.self_param_syntax()
{
Some(s) => s.map(|it| it.into()),
None => continue,
},
mir::MirSpan::Unknown => continue, mir::MirSpan::Unknown => continue,
}; };
acc.push(NeedMut { local, span }.into()); acc.push(NeedMut { local, span }.into());
@ -2127,8 +2136,11 @@ impl Param {
pub fn as_local(&self, db: &dyn HirDatabase) -> Option<Local> { pub fn as_local(&self, db: &dyn HirDatabase) -> Option<Local> {
let parent = DefWithBodyId::FunctionId(self.func.into()); let parent = DefWithBodyId::FunctionId(self.func.into());
let body = db.body(parent); let body = db.body(parent);
let pat_id = body.params[self.idx]; if let Some(self_param) = body.self_param.filter(|_| self.idx == 0) {
if let Pat::Bind { id, .. } = &body[pat_id] { 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 }) Some(Local { parent, binding_id: *id })
} else { } else {
None None
@ -2143,7 +2155,7 @@ impl Param {
let InFile { file_id, value } = self.func.source(db)?; let InFile { file_id, value } = self.func.source(db)?;
let params = value.param_list()?; let params = value.param_list()?;
if params.self_param().is_some() { 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 { } else {
params.params().nth(self.idx) params.params().nth(self.idx)
} }
@ -3134,35 +3146,59 @@ impl Local {
/// All definitions for this local. Example: `let (a$0, _) | (_, a$0) = it;` /// All definitions for this local. Example: `let (a$0, _) | (_, a$0) = it;`
pub fn sources(self, db: &dyn HirDatabase) -> Vec<LocalSource> { pub fn sources(self, db: &dyn HirDatabase) -> Vec<LocalSource> {
let (body, source_map) = db.body_with_source_map(self.parent); 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;` /// The leftmost definition for this local. Example: `let (a$0, _) | (_, a) = it;`
pub fn primary_source(self, db: &dyn HirDatabase) -> LocalSource { pub fn primary_source(self, db: &dyn HirDatabase) -> LocalSource {
let (body, source_map) = db.body_with_source_map(self.parent); let (body, source_map) = db.body_with_source_map(self.parent);
let src = self.sources_(db, &body, &source_map).next().unwrap(); match body.self_param.zip(source_map.self_param_syntax()) {
src Some((param, source)) if param == self.binding_id => {
} let root = source.file_syntax(db.upcast());
LocalSource {
fn sources_<'a>( local: self,
self, source: source.map(|ast| Either::Right(ast.to_node(&root))),
db: &'a dyn HirDatabase, }
body: &'a hir_def::body::Body, }
source_map: &'a hir_def::body::BodySourceMap, _ => body[self.binding_id]
) -> impl Iterator<Item = LocalSource> + 'a { .definitions
body[self.binding_id] .first()
.definitions .map(|&definition| {
.iter() let src = source_map.pat_syntax(definition).unwrap(); // Hmm...
.map(|&definition| { let root = src.file_syntax(db.upcast());
let src = source_map.pat_syntax(definition).unwrap(); // Hmm... LocalSource {
let root = src.file_syntax(db.upcast()); local: self,
src.map(|ast| match ast.to_node(&root) { source: src.map(|ast| match ast.to_node(&root) {
Either::Left(ast::Pat::IdentPat(it)) => Either::Left(it), ast::Pat::IdentPat(it) => Either::Left(it),
Either::Left(_) => unreachable!("local with non ident-pattern"), _ => unreachable!("local with non ident-pattern"),
Either::Right(it) => Either::Right(it), }),
}
}) })
}) .unwrap(),
.map(move |source| LocalSource { local: self, source }) }
} }
} }

View file

@ -101,7 +101,7 @@ use hir_def::{
use hir_expand::{attrs::AttrId, name::AsName, HirFileId, HirFileIdExt, MacroCallId}; use hir_expand::{attrs::AttrId, name::AsName, HirFileId, HirFileIdExt, MacroCallId};
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use smallvec::SmallVec; use smallvec::SmallVec;
use stdx::{impl_from, never}; use stdx::impl_from;
use syntax::{ use syntax::{
ast::{self, HasName}, ast::{self, HasName},
AstNode, SyntaxNode, AstNode, SyntaxNode,
@ -253,14 +253,8 @@ impl SourceToDefCtx<'_, '_> {
src: InFile<ast::SelfParam>, src: InFile<ast::SelfParam>,
) -> Option<(DefWithBodyId, BindingId)> { ) -> Option<(DefWithBodyId, BindingId)> {
let container = self.find_pat_or_label_container(src.syntax())?; let container = self.find_pat_or_label_container(src.syntax())?;
let (body, source_map) = self.db.body_with_source_map(container); let body = self.db.body(container);
let pat_id = source_map.node_self_param(src.as_ref())?; Some((container, body.self_param?))
if let crate::Pat::Bind { id, .. } = body[pat_id] {
Some((container, id))
} else {
never!();
None
}
} }
pub(super) fn label_to_def( pub(super) fn label_to_def(
&mut self, &mut self,

View file

@ -219,11 +219,10 @@ impl SourceAnalyzer {
pub(crate) fn type_of_self( pub(crate) fn type_of_self(
&self, &self,
db: &dyn HirDatabase, db: &dyn HirDatabase,
param: &ast::SelfParam, _param: &ast::SelfParam,
) -> Option<Type> { ) -> Option<Type> {
let src = InFile { file_id: self.file_id, value: param }; let binding = self.body()?.self_param?;
let pat_id = self.body_source_map()?.node_self_param(src)?; let ty = self.infer.as_ref()?[binding].clone();
let ty = self.infer.as_ref()?[pat_id].clone();
Some(Type::new_with_resolver(db, &self.resolver, ty)) Some(Type::new_with_resolver(db, &self.resolver, ty))
} }

View file

@ -74,6 +74,10 @@ pub(super) fn hints(
Ok(s) => s.value.text_range(), Ok(s) => s.value.text_range(),
Err(_) => continue, Err(_) => continue,
}, },
MirSpan::SelfParam => match source_map.self_param_syntax() {
Some(s) => s.value.text_range(),
None => continue,
},
MirSpan::Unknown => continue, MirSpan::Unknown => continue,
}; };
let binding = &hir.bindings[*binding]; let binding = &hir.bindings[*binding];

View file

@ -488,20 +488,22 @@ impl GlobalState {
fn update_diagnostics(&mut self) { fn update_diagnostics(&mut self) {
let db = self.analysis_host.raw_database(); let db = self.analysis_host.raw_database();
let subscriptions = self let subscriptions = {
.mem_docs let vfs = &self.vfs.read().0;
.iter() self.mem_docs
.map(|path| self.vfs.read().0.file_id(path).unwrap()) .iter()
.filter(|&file_id| { .map(|path| vfs.file_id(path).unwrap())
let source_root = db.file_source_root(file_id); .filter(|&file_id| {
// Only publish diagnostics for files in the workspace, not from crates.io deps let source_root = db.file_source_root(file_id);
// or the sysroot. // Only publish diagnostics for files in the workspace, not from crates.io deps
// While theoretically these should never have errors, we have quite a few false // or the sysroot.
// positives particularly in the stdlib, and those diagnostics would stay around // While theoretically these should never have errors, we have quite a few false
// forever if we emitted them here. // positives particularly in the stdlib, and those diagnostics would stay around
!db.source_root(source_root).is_library // forever if we emitted them here.
}) !db.source_root(source_root).is_library
.collect::<Vec<_>>(); })
.collect::<Vec<_>>()
};
tracing::trace!("updating notifications for {:?}", subscriptions); tracing::trace!("updating notifications for {:?}", subscriptions);
// Diagnostics are triggered by the user typing // Diagnostics are triggered by the user typing