Skip to content

Commit 24bf53d

Browse files
committed
Auto merge of #17268 - Veykril:signatures, r=Veykril
feat: More callable info With this PR we retain more info about callables other than functions, allowing for closure parameter type inlay hints to be linkable as well as better signature help around closures and `Fn*` implementors.
2 parents 9f4b651 + 6438554 commit 24bf53d

File tree

17 files changed

+388
-226
lines changed

17 files changed

+388
-226
lines changed

src/tools/rust-analyzer/crates/hir-def/src/attr/builtin.rs

-3
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,6 @@ use std::sync::OnceLock;
1212

1313
use rustc_hash::FxHashMap;
1414

15-
/// Ignored attribute namespaces used by tools.
16-
pub const TOOL_MODULES: &[&str] = &["rustfmt", "clippy"];
17-
1815
pub struct BuiltinAttribute {
1916
pub name: &'static str,
2017
pub template: AttributeTemplate,

src/tools/rust-analyzer/crates/hir-def/src/nameres.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,14 @@ use crate::{
8484
LocalModuleId, Lookup, MacroExpander, MacroId, ModuleId, ProcMacroId, UseId,
8585
};
8686

87+
const PREDEFINED_TOOLS: &[SmolStr] = &[
88+
SmolStr::new_static("clippy"),
89+
SmolStr::new_static("rustfmt"),
90+
SmolStr::new_static("diagnostic"),
91+
SmolStr::new_static("miri"),
92+
SmolStr::new_static("rust_analyzer"),
93+
];
94+
8795
/// Contains the results of (early) name resolution.
8896
///
8997
/// A `DefMap` stores the module tree and the definitions that are in scope in every module after
@@ -160,7 +168,7 @@ impl DefMapCrateData {
160168
fn_proc_macro_mapping: FxHashMap::default(),
161169
proc_macro_loading_error: None,
162170
registered_attrs: Vec::new(),
163-
registered_tools: Vec::new(),
171+
registered_tools: PREDEFINED_TOOLS.into(),
164172
unstable_features: FxHashSet::default(),
165173
rustc_coherence_is_core: false,
166174
no_core: false,

src/tools/rust-analyzer/crates/hir-def/src/nameres/attr_resolution.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use syntax::{ast, SmolStr};
1010
use triomphe::Arc;
1111

1212
use crate::{
13-
attr::builtin::{find_builtin_attr_idx, TOOL_MODULES},
13+
attr::builtin::find_builtin_attr_idx,
1414
db::DefDatabase,
1515
item_scope::BuiltinShadowMode,
1616
nameres::path_resolution::ResolveMode,
@@ -82,8 +82,7 @@ impl DefMap {
8282
let name = name.to_smol_str();
8383
let pred = |n: &_| *n == name;
8484

85-
let registered = self.data.registered_tools.iter().map(SmolStr::as_str);
86-
let is_tool = TOOL_MODULES.iter().copied().chain(registered).any(pred);
85+
let is_tool = self.data.registered_tools.iter().map(SmolStr::as_str).any(pred);
8786
// FIXME: tool modules can be shadowed by actual modules
8887
if is_tool {
8988
return true;

src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs

+12-9
Original file line numberDiff line numberDiff line change
@@ -797,19 +797,22 @@ impl<'a> InferenceTable<'a> {
797797
})
798798
.build();
799799

800-
let projection = {
801-
let b = TyBuilder::subst_for_def(self.db, fn_once_trait, None);
802-
if b.remaining() != 2 {
803-
return None;
804-
}
805-
let fn_once_subst = b.push(ty.clone()).push(arg_ty).build();
800+
let b = TyBuilder::trait_ref(self.db, fn_once_trait);
801+
if b.remaining() != 2 {
802+
return None;
803+
}
804+
let mut trait_ref = b.push(ty.clone()).push(arg_ty).build();
806805

807-
TyBuilder::assoc_type_projection(self.db, output_assoc_type, Some(fn_once_subst))
808-
.build()
806+
let projection = {
807+
TyBuilder::assoc_type_projection(
808+
self.db,
809+
output_assoc_type,
810+
Some(trait_ref.substitution.clone()),
811+
)
812+
.build()
809813
};
810814

811815
let trait_env = self.trait_env.env.clone();
812-
let mut trait_ref = projection.trait_ref(self.db);
813816
let obligation = InEnvironment {
814817
goal: trait_ref.clone().cast(Interner),
815818
environment: trait_env.clone(),

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

+53-20
Original file line numberDiff line numberDiff line change
@@ -570,6 +570,10 @@ impl CallableSig {
570570
}
571571
}
572572

573+
pub fn abi(&self) -> FnAbi {
574+
self.abi
575+
}
576+
573577
pub fn params(&self) -> &[Ty] {
574578
&self.params_and_return[0..self.params_and_return.len() - 1]
575579
}
@@ -892,20 +896,16 @@ where
892896
Canonical { value, binders: chalk_ir::CanonicalVarKinds::from_iter(Interner, kinds) }
893897
}
894898

895-
pub fn callable_sig_from_fnonce(
896-
mut self_ty: &Ty,
897-
env: Arc<TraitEnvironment>,
899+
pub fn callable_sig_from_fn_trait(
900+
self_ty: &Ty,
901+
trait_env: Arc<TraitEnvironment>,
898902
db: &dyn HirDatabase,
899-
) -> Option<CallableSig> {
900-
if let Some((ty, _, _)) = self_ty.as_reference() {
901-
// This will happen when it implements fn or fn mut, since we add a autoborrow adjustment
902-
self_ty = ty;
903-
}
904-
let krate = env.krate;
903+
) -> Option<(FnTrait, CallableSig)> {
904+
let krate = trait_env.krate;
905905
let fn_once_trait = FnTrait::FnOnce.get_id(db, krate)?;
906906
let output_assoc_type = db.trait_data(fn_once_trait).associated_type_by_name(&name![Output])?;
907907

908-
let mut table = InferenceTable::new(db, env);
908+
let mut table = InferenceTable::new(db, trait_env.clone());
909909
let b = TyBuilder::trait_ref(db, fn_once_trait);
910910
if b.remaining() != 2 {
911911
return None;
@@ -915,23 +915,56 @@ pub fn callable_sig_from_fnonce(
915915
// - Self: FnOnce<?args_ty>
916916
// - <Self as FnOnce<?args_ty>>::Output == ?ret_ty
917917
let args_ty = table.new_type_var();
918-
let trait_ref = b.push(self_ty.clone()).push(args_ty.clone()).build();
918+
let mut trait_ref = b.push(self_ty.clone()).push(args_ty.clone()).build();
919919
let projection = TyBuilder::assoc_type_projection(
920920
db,
921921
output_assoc_type,
922922
Some(trait_ref.substitution.clone()),
923923
)
924924
.build();
925-
table.register_obligation(trait_ref.cast(Interner));
926-
let ret_ty = table.normalize_projection_ty(projection);
927-
928-
let ret_ty = table.resolve_completely(ret_ty);
929-
let args_ty = table.resolve_completely(args_ty);
930925

931-
let params =
932-
args_ty.as_tuple()?.iter(Interner).map(|it| it.assert_ty_ref(Interner)).cloned().collect();
933-
934-
Some(CallableSig::from_params_and_return(params, ret_ty, false, Safety::Safe, FnAbi::RustCall))
926+
let block = trait_env.block;
927+
let trait_env = trait_env.env.clone();
928+
let obligation =
929+
InEnvironment { goal: trait_ref.clone().cast(Interner), environment: trait_env.clone() };
930+
let canonical = table.canonicalize(obligation.clone());
931+
if db.trait_solve(krate, block, canonical.cast(Interner)).is_some() {
932+
table.register_obligation(obligation.goal);
933+
let return_ty = table.normalize_projection_ty(projection);
934+
for fn_x in [FnTrait::Fn, FnTrait::FnMut, FnTrait::FnOnce] {
935+
let fn_x_trait = fn_x.get_id(db, krate)?;
936+
trait_ref.trait_id = to_chalk_trait_id(fn_x_trait);
937+
let obligation: chalk_ir::InEnvironment<chalk_ir::Goal<Interner>> = InEnvironment {
938+
goal: trait_ref.clone().cast(Interner),
939+
environment: trait_env.clone(),
940+
};
941+
let canonical = table.canonicalize(obligation.clone());
942+
if db.trait_solve(krate, block, canonical.cast(Interner)).is_some() {
943+
let ret_ty = table.resolve_completely(return_ty);
944+
let args_ty = table.resolve_completely(args_ty);
945+
let params = args_ty
946+
.as_tuple()?
947+
.iter(Interner)
948+
.map(|it| it.assert_ty_ref(Interner))
949+
.cloned()
950+
.collect();
951+
952+
return Some((
953+
fn_x,
954+
CallableSig::from_params_and_return(
955+
params,
956+
ret_ty,
957+
false,
958+
Safety::Safe,
959+
FnAbi::RustCall,
960+
),
961+
));
962+
}
963+
}
964+
unreachable!("It should at least implement FnOnce at this point");
965+
} else {
966+
None
967+
}
935968
}
936969

937970
struct PlaceholderCollector<'db> {

src/tools/rust-analyzer/crates/hir-ty/src/traits.rs

+19
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//! Trait solving using Chalk.
22
3+
use core::fmt;
34
use std::env::var;
45

56
use chalk_ir::{fold::TypeFoldable, DebruijnIndex, GoalData};
@@ -209,7 +210,25 @@ pub enum FnTrait {
209210
Fn,
210211
}
211212

213+
impl fmt::Display for FnTrait {
214+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
215+
match self {
216+
FnTrait::FnOnce => write!(f, "FnOnce"),
217+
FnTrait::FnMut => write!(f, "FnMut"),
218+
FnTrait::Fn => write!(f, "Fn"),
219+
}
220+
}
221+
}
222+
212223
impl FnTrait {
224+
pub const fn function_name(&self) -> &'static str {
225+
match self {
226+
FnTrait::FnOnce => "call_once",
227+
FnTrait::FnMut => "call_mut",
228+
FnTrait::Fn => "call",
229+
}
230+
}
231+
213232
const fn lang_item(self) -> LangItem {
214233
match self {
215234
FnTrait::FnOnce => LangItem::FnOnce,

0 commit comments

Comments
 (0)