Skip to content

Commit 7045044

Browse files
committed
Allow hir::Param to refer to other entity params aside from functions
1 parent 9ff4ffb commit 7045044

File tree

9 files changed

+114
-118
lines changed

9 files changed

+114
-118
lines changed

src/tools/rust-analyzer/crates/hir/src/lib.rs

+62-65
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ pub mod term_search;
3535

3636
mod display;
3737

38-
use std::{iter, mem::discriminant, ops::ControlFlow};
38+
use std::{mem::discriminant, ops::ControlFlow};
3939

4040
use arrayvec::ArrayVec;
4141
use base_db::{CrateDisplayName, CrateId, CrateOrigin, FileId};
@@ -52,7 +52,6 @@ use hir_def::{
5252
path::ImportAlias,
5353
per_ns::PerNs,
5454
resolver::{HasResolver, Resolver},
55-
src::HasSource as _,
5655
AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId, CrateRootModuleId, DefWithBodyId,
5756
EnumId, EnumVariantId, ExternCrateId, FunctionId, GenericDefId, GenericParamId, HasModule,
5857
ImplId, InTypeConstId, ItemContainerId, LifetimeParamId, LocalFieldId, Lookup, MacroExpander,
@@ -1965,7 +1964,7 @@ impl Function {
19651964
.enumerate()
19661965
.map(|(idx, ty)| {
19671966
let ty = Type { env: environment.clone(), ty: ty.clone() };
1968-
Param { func: self, ty, idx }
1967+
Param { func: Callee::Def(CallableDefId::FunctionId(self.id)), ty, idx }
19691968
})
19701969
.collect()
19711970
}
@@ -1991,7 +1990,7 @@ impl Function {
19911990
.skip(skip)
19921991
.map(|(idx, ty)| {
19931992
let ty = Type { env: environment.clone(), ty: ty.clone() };
1994-
Param { func: self, ty, idx }
1993+
Param { func: Callee::Def(CallableDefId::FunctionId(self.id)), ty, idx }
19951994
})
19961995
.collect()
19971996
}
@@ -2037,7 +2036,7 @@ impl Function {
20372036
.skip(skip)
20382037
.map(|(idx, ty)| {
20392038
let ty = Type { env: environment.clone(), ty: ty.clone() };
2040-
Param { func: self, ty, idx }
2039+
Param { func: Callee::Def(CallableDefId::FunctionId(self.id)), ty, idx }
20412040
})
20422041
.collect()
20432042
}
@@ -2167,17 +2166,24 @@ impl From<hir_ty::Mutability> for Access {
21672166

21682167
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
21692168
pub struct Param {
2170-
func: Function,
2169+
func: Callee,
21712170
/// The index in parameter list, including self parameter.
21722171
idx: usize,
21732172
ty: Type,
21742173
}
21752174

21762175
impl Param {
2177-
pub fn parent_fn(&self) -> Function {
2178-
self.func
2176+
pub fn parent_fn(&self) -> Option<Function> {
2177+
match self.func {
2178+
Callee::Def(CallableDefId::FunctionId(f)) => Some(f.into()),
2179+
_ => None,
2180+
}
21792181
}
21802182

2183+
// pub fn parent_closure(&self) -> Option<Closure> {
2184+
// self.func.as_ref().right().cloned()
2185+
// }
2186+
21812187
pub fn index(&self) -> usize {
21822188
self.idx
21832189
}
@@ -2191,7 +2197,11 @@ impl Param {
21912197
}
21922198

21932199
pub fn as_local(&self, db: &dyn HirDatabase) -> Option<Local> {
2194-
let parent = DefWithBodyId::FunctionId(self.func.into());
2200+
let parent = match self.func {
2201+
Callee::Def(CallableDefId::FunctionId(it)) => DefWithBodyId::FunctionId(it),
2202+
Callee::Closure(closure) => db.lookup_intern_closure(closure.into()).0,
2203+
_ => return None,
2204+
};
21952205
let body = db.body(parent);
21962206
if let Some(self_param) = body.self_param.filter(|_| self.idx == 0) {
21972207
Some(Local { parent, binding_id: self_param })
@@ -2205,18 +2215,45 @@ impl Param {
22052215
}
22062216

22072217
pub fn pattern_source(&self, db: &dyn HirDatabase) -> Option<ast::Pat> {
2208-
self.source(db).and_then(|p| p.value.pat())
2218+
self.source(db).and_then(|p| p.value.right()?.pat())
22092219
}
22102220

2211-
pub fn source(&self, db: &dyn HirDatabase) -> Option<InFile<ast::Param>> {
2212-
let InFile { file_id, value } = self.func.source(db)?;
2213-
let params = value.param_list()?;
2214-
if params.self_param().is_some() {
2215-
params.params().nth(self.idx.checked_sub(params.self_param().is_some() as usize)?)
2216-
} else {
2217-
params.params().nth(self.idx)
2221+
pub fn source(
2222+
&self,
2223+
db: &dyn HirDatabase,
2224+
) -> Option<InFile<Either<ast::SelfParam, ast::Param>>> {
2225+
match self.func {
2226+
Callee::Def(CallableDefId::FunctionId(func)) => {
2227+
let InFile { file_id, value } = Function { id: func }.source(db)?;
2228+
let params = value.param_list()?;
2229+
if let Some(self_param) = params.self_param() {
2230+
if let Some(idx) = self.idx.checked_sub(1 as usize) {
2231+
params.params().nth(idx).map(Either::Right)
2232+
} else {
2233+
Some(Either::Left(self_param))
2234+
}
2235+
} else {
2236+
params.params().nth(self.idx).map(Either::Right)
2237+
}
2238+
.map(|value| InFile { file_id, value })
2239+
}
2240+
Callee::Closure(closure) => {
2241+
let InternedClosure(owner, expr_id) = db.lookup_intern_closure(closure.into());
2242+
let (_, source_map) = db.body_with_source_map(owner);
2243+
let ast @ InFile { file_id, value } = source_map.expr_syntax(expr_id).ok()?;
2244+
let root = db.parse_or_expand(file_id);
2245+
match value.to_node(&root) {
2246+
ast::Expr::ClosureExpr(it) => it
2247+
.param_list()?
2248+
.params()
2249+
.nth(self.idx)
2250+
.map(Either::Right)
2251+
.map(|value| InFile { file_id: ast.file_id, value }),
2252+
_ => None,
2253+
}
2254+
}
2255+
_ => None,
22182256
}
2219-
.map(|value| InFile { file_id, value })
22202257
}
22212258
}
22222259

@@ -4919,7 +4956,7 @@ pub struct Callable {
49194956
pub(crate) is_bound_method: bool,
49204957
}
49214958

4922-
#[derive(Debug)]
4959+
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
49234960
enum Callee {
49244961
Def(CallableDefId),
49254962
Closure(ClosureId),
@@ -4960,43 +4997,15 @@ impl Callable {
49604997
pub fn n_params(&self) -> usize {
49614998
self.sig.params().len() - if self.is_bound_method { 1 } else { 0 }
49624999
}
4963-
pub fn params(
4964-
&self,
4965-
db: &dyn HirDatabase,
4966-
) -> Vec<(Option<Either<ast::SelfParam, ast::Pat>>, Type)> {
4967-
let types = self
4968-
.sig
5000+
pub fn params(&self) -> Vec<Param> {
5001+
self.sig
49695002
.params()
49705003
.iter()
5004+
.enumerate()
49715005
.skip(if self.is_bound_method { 1 } else { 0 })
4972-
.map(|ty| self.ty.derived(ty.clone()));
4973-
let map_param = |it: ast::Param| it.pat().map(Either::Right);
4974-
let patterns = match self.callee {
4975-
Callee::Def(CallableDefId::FunctionId(func)) => {
4976-
let src = func.lookup(db.upcast()).source(db.upcast());
4977-
src.value.param_list().map(|param_list| {
4978-
param_list
4979-
.self_param()
4980-
.map(|it| Some(Either::Left(it)))
4981-
.filter(|_| !self.is_bound_method)
4982-
.into_iter()
4983-
.chain(param_list.params().map(map_param))
4984-
})
4985-
}
4986-
Callee::Closure(closure_id) => match closure_source(db, closure_id) {
4987-
Some(src) => src.param_list().map(|param_list| {
4988-
param_list
4989-
.self_param()
4990-
.map(|it| Some(Either::Left(it)))
4991-
.filter(|_| !self.is_bound_method)
4992-
.into_iter()
4993-
.chain(param_list.params().map(map_param))
4994-
}),
4995-
None => None,
4996-
},
4997-
_ => None,
4998-
};
4999-
patterns.into_iter().flatten().chain(iter::repeat(None)).zip(types).collect()
5006+
.map(|(idx, ty)| (idx, self.ty.derived(ty.clone())))
5007+
.map(|(idx, ty)| Param { func: self.callee, idx, ty })
5008+
.collect()
50005009
}
50015010
pub fn return_type(&self) -> Type {
50025011
self.ty.derived(self.sig.ret().clone())
@@ -5006,18 +5015,6 @@ impl Callable {
50065015
}
50075016
}
50085017

5009-
fn closure_source(db: &dyn HirDatabase, closure: ClosureId) -> Option<ast::ClosureExpr> {
5010-
let InternedClosure(owner, expr_id) = db.lookup_intern_closure(closure.into());
5011-
let (_, source_map) = db.body_with_source_map(owner);
5012-
let ast = source_map.expr_syntax(expr_id).ok()?;
5013-
let root = ast.file_syntax(db.upcast());
5014-
let expr = ast.value.to_node(&root);
5015-
match expr {
5016-
ast::Expr::ClosureExpr(it) => Some(it),
5017-
_ => None,
5018-
}
5019-
}
5020-
50215018
#[derive(Clone, Debug, Eq, PartialEq)]
50225019
pub struct Layout(Arc<TyLayout>, Arc<TargetDataLayout>);
50235020

src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_method_eager_lazy.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -114,10 +114,10 @@ pub(crate) fn replace_with_eager_method(acc: &mut Assists, ctx: &AssistContext<'
114114
let callable = ctx.sema.resolve_method_call_as_callable(&call)?;
115115
let (_, receiver_ty) = callable.receiver_param(ctx.sema.db)?;
116116
let n_params = callable.n_params() + 1;
117-
let params = callable.params(ctx.sema.db);
117+
let params = callable.params();
118118

119119
// FIXME: Check that the arg is of the form `() -> T`
120-
if !params.first()?.1.impls_fnonce(ctx.sema.db) {
120+
if !params.first()?.ty().impls_fnonce(ctx.sema.db) {
121121
return None;
122122
}
123123

src/tools/rust-analyzer/crates/ide-assists/src/utils/suggest_name.rs

+2-5
Original file line numberDiff line numberDiff line change
@@ -253,11 +253,8 @@ fn from_param(expr: &ast::Expr, sema: &Semantics<'_, RootDatabase>) -> Option<St
253253
};
254254

255255
let (idx, _) = arg_list.args().find_position(|it| it == expr).unwrap();
256-
let (pat, _) = func.params(sema.db).into_iter().nth(idx)?;
257-
let pat = match pat? {
258-
either::Either::Right(pat) => pat,
259-
_ => return None,
260-
};
256+
let param = func.params().into_iter().nth(idx)?;
257+
let pat = param.source(sema.db)?.value.right()?.pat()?;
261258
let name = var_name_from_pat(&pat)?;
262259
normalize(&name.to_string())
263260
}

src/tools/rust-analyzer/crates/ide-db/src/active_parameter.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! This module provides functionality for querying callable information about a token.
22
33
use either::Either;
4-
use hir::{Semantics, Type};
4+
use hir::{InFile, Semantics, Type};
55
use parser::T;
66
use syntax::{
77
ast::{self, HasArgList, HasName},
@@ -13,7 +13,7 @@ use crate::RootDatabase;
1313
#[derive(Debug)]
1414
pub struct ActiveParameter {
1515
pub ty: Type,
16-
pub pat: Option<Either<ast::SelfParam, ast::Pat>>,
16+
pub src: Option<InFile<Either<ast::SelfParam, ast::Param>>>,
1717
}
1818

1919
impl ActiveParameter {
@@ -22,18 +22,18 @@ impl ActiveParameter {
2222
let (signature, active_parameter) = callable_for_token(sema, token)?;
2323

2424
let idx = active_parameter?;
25-
let mut params = signature.params(sema.db);
25+
let mut params = signature.params();
2626
if idx >= params.len() {
2727
cov_mark::hit!(too_many_arguments);
2828
return None;
2929
}
30-
let (pat, ty) = params.swap_remove(idx);
31-
Some(ActiveParameter { ty, pat })
30+
let param = params.swap_remove(idx);
31+
Some(ActiveParameter { ty: param.ty().clone(), src: param.source(sema.db) })
3232
}
3333

3434
pub fn ident(&self) -> Option<ast::Name> {
35-
self.pat.as_ref().and_then(|param| match param {
36-
Either::Right(ast::Pat::IdentPat(ident)) => ident.name(),
35+
self.src.as_ref().and_then(|param| match param.value.as_ref().right()?.pat()? {
36+
ast::Pat::IdentPat(ident) => ident.name(),
3737
_ => None,
3838
})
3939
}

src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/format_string.rs

+1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ pub enum FormatSpecifier {
4141
Escape,
4242
}
4343

44+
// FIXME: Remove this, we can use rustc_format_parse instead
4445
pub fn lex_format_specifiers(
4546
string: &ast::String,
4647
mut callback: &mut dyn FnMut(TextRange, FormatSpecifier),

src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,15 @@ pub(super) fn hints(
2424

2525
let (callable, arg_list) = get_callable(sema, &expr)?;
2626
let hints = callable
27-
.params(sema.db)
27+
.params()
2828
.into_iter()
2929
.zip(arg_list.args())
30-
.filter_map(|((param, _ty), arg)| {
30+
.filter_map(|(p, arg)| {
3131
// Only annotate hints for expressions that exist in the original file
3232
let range = sema.original_range_opt(arg.syntax())?;
33-
let (param_name, name_syntax) = match param.as_ref()? {
33+
let (param_name, name_syntax) = match p.source(sema.db)?.value.as_ref() {
3434
Either::Left(pat) => (pat.name()?, pat.name()),
35-
Either::Right(pat) => match pat {
35+
Either::Right(param) => match param.pat()? {
3636
ast::Pat::IdentPat(it) => (it.name()?, it.name()),
3737
_ => return None,
3838
},

src/tools/rust-analyzer/crates/ide/src/signature_help.rs

+10-7
Original file line numberDiff line numberDiff line change
@@ -210,22 +210,25 @@ fn signature_help_for_call(
210210
format_to!(res.signature, "{}", self_param.display(db))
211211
}
212212
let mut buf = String::new();
213-
for (idx, (pat, ty)) in callable.params(db).into_iter().enumerate() {
213+
for (idx, p) in callable.params().into_iter().enumerate() {
214214
buf.clear();
215-
if let Some(pat) = pat {
216-
match pat {
217-
Either::Left(_self) => format_to!(buf, "self: "),
218-
Either::Right(pat) => format_to!(buf, "{}: ", pat),
215+
if let Some(param) = p.source(sema.db) {
216+
match param.value {
217+
Either::Right(param) => match param.pat() {
218+
Some(pat) => format_to!(buf, "{}: ", pat),
219+
None => format_to!(buf, "?: "),
220+
},
221+
Either::Left(_) => format_to!(buf, "self: "),
219222
}
220223
}
221224
// APITs (argument position `impl Trait`s) are inferred as {unknown} as the user is
222225
// in the middle of entering call arguments.
223226
// In that case, fall back to render definitions of the respective parameters.
224227
// This is overly conservative: we do not substitute known type vars
225228
// (see FIXME in tests::impl_trait) and falling back on any unknowns.
226-
match (ty.contains_unknown(), fn_params.as_deref()) {
229+
match (p.ty().contains_unknown(), fn_params.as_deref()) {
227230
(true, Some(fn_params)) => format_to!(buf, "{}", fn_params[idx].ty().display(db)),
228-
_ => format_to!(buf, "{}", ty.display(db)),
231+
_ => format_to!(buf, "{}", p.ty().display(db)),
229232
}
230233
res.push_call_param(&buf);
231234
}

0 commit comments

Comments
 (0)