Skip to content

Commit 6438554

Browse files
committed
Show fn traits in signature info for trait implementors
1 parent f42e55d commit 6438554

File tree

8 files changed

+196
-68
lines changed

8 files changed

+196
-68
lines changed

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

+8
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,14 @@ impl fmt::Display for FnTrait {
221221
}
222222

223223
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+
224232
const fn lang_item(self) -> LangItem {
225233
match self {
226234
FnTrait::FnOnce => LangItem::FnOnce,

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

+25-19
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ pub use {
140140
display::{ClosureStyle, HirDisplay, HirDisplayError, HirWrite},
141141
layout::LayoutError,
142142
mir::{MirEvalError, MirLowerError},
143-
PointerCast, Safety,
143+
FnAbi, PointerCast, Safety,
144144
},
145145
// FIXME: Properly encapsulate mir
146146
hir_ty::{mir, Interner as ChalkTyInterner},
@@ -2227,7 +2227,7 @@ impl Param {
22272227
let InFile { file_id, value } = Function { id: func }.source(db)?;
22282228
let params = value.param_list()?;
22292229
if let Some(self_param) = params.self_param() {
2230-
if let Some(idx) = self.idx.checked_sub(1 as usize) {
2230+
if let Some(idx) = self.idx.checked_sub(1) {
22312231
params.params().nth(idx).map(Either::Right)
22322232
} else {
22332233
Some(Either::Left(self_param))
@@ -4321,23 +4321,26 @@ impl Type {
43214321
TyKind::Function(_) => Callee::FnPtr,
43224322
TyKind::FnDef(..) => Callee::Def(self.ty.callable_def(db)?),
43234323
kind => {
4324-
// This branch shouldn't be necessary?
4325-
if let TyKind::Ref(_, _, ty) = kind {
4326-
if let TyKind::Closure(closure, subst) = ty.kind(Interner) {
4327-
let sig = ty.callable_sig(db)?;
4328-
return Some(Callable {
4329-
ty: self.clone(),
4330-
sig,
4331-
callee: Callee::Closure(*closure, subst.clone()),
4332-
is_bound_method: false,
4333-
});
4334-
}
4324+
// This will happen when it implements fn or fn mut, since we add an autoborrow adjustment
4325+
let (ty, kind) = if let TyKind::Ref(_, _, ty) = kind {
4326+
(ty, ty.kind(Interner))
4327+
} else {
4328+
(&self.ty, kind)
4329+
};
4330+
if let TyKind::Closure(closure, subst) = kind {
4331+
let sig = ty.callable_sig(db)?;
4332+
return Some(Callable {
4333+
ty: self.clone(),
4334+
sig,
4335+
callee: Callee::Closure(*closure, subst.clone()),
4336+
is_bound_method: false,
4337+
});
43354338
}
4336-
let sig = hir_ty::callable_sig_from_fnonce(&self.ty, self.env.clone(), db)?;
4339+
let (fn_trait, sig) = hir_ty::callable_sig_from_fn_trait(ty, self.env.clone(), db)?;
43374340
return Some(Callable {
43384341
ty: self.clone(),
43394342
sig,
4340-
callee: Callee::Other,
4343+
callee: Callee::FnImpl(fn_trait),
43414344
is_bound_method: false,
43424345
});
43434346
}
@@ -4968,7 +4971,7 @@ enum Callee {
49684971
Def(CallableDefId),
49694972
Closure(ClosureId, Substitution),
49704973
FnPtr,
4971-
Other,
4974+
FnImpl(FnTrait),
49724975
}
49734976

49744977
pub enum CallableKind {
@@ -4977,8 +4980,7 @@ pub enum CallableKind {
49774980
TupleEnumVariant(Variant),
49784981
Closure(Closure),
49794982
FnPtr,
4980-
/// Some other type that implements `FnOnce`.
4981-
Other,
4983+
FnImpl(FnTrait),
49824984
}
49834985

49844986
impl Callable {
@@ -4993,7 +4995,7 @@ impl Callable {
49934995
CallableKind::Closure(Closure { id, subst: subst.clone() })
49944996
}
49954997
Callee::FnPtr => CallableKind::FnPtr,
4996-
Callee::Other => CallableKind::Other,
4998+
Callee::FnImpl(fn_) => CallableKind::FnImpl(fn_),
49974999
}
49985000
}
49995001
pub fn receiver_param(&self, db: &dyn HirDatabase) -> Option<(SelfParam, Type)> {
@@ -5023,6 +5025,10 @@ impl Callable {
50235025
pub fn sig(&self) -> &CallableSig {
50245026
&self.sig
50255027
}
5028+
5029+
pub fn ty(&self) -> &Type {
5030+
&self.ty
5031+
}
50265032
}
50275033

50285034
#[derive(Clone, Debug, Eq, PartialEq)]

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

+2-1
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,8 @@ impl SourceAnalyzer {
307307
db: &dyn HirDatabase,
308308
call: &ast::Expr,
309309
) -> Option<Callable> {
310-
self.type_of_expr(db, &call.clone())?.0.as_callable(db)
310+
let (orig, adjusted) = self.type_of_expr(db, &call.clone())?;
311+
adjusted.unwrap_or(orig).as_callable(db)
311312
}
312313

313314
pub(crate) fn resolve_field(

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

+1-4
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,7 @@ pub fn callable_for_node(
6060
token: &SyntaxToken,
6161
) -> Option<(hir::Callable, Option<usize>)> {
6262
let callable = match calling_node {
63-
ast::CallableExpr::Call(call) => {
64-
let expr = call.expr()?;
65-
sema.type_of_expr(&expr)?.adjusted().as_callable(sema.db)
66-
}
63+
ast::CallableExpr::Call(call) => sema.resolve_expr_as_callable(&call.expr()?),
6764
ast::CallableExpr::MethodCall(call) => sema.resolve_method_call_as_callable(call),
6865
}?;
6966
let active_param = calling_node.arg_list().map(|arg_list| {

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

+4-4
Original file line numberDiff line numberDiff line change
@@ -109,12 +109,12 @@ pub(crate) fn outgoing_calls(
109109
let expr = call.expr()?;
110110
let callable = sema.type_of_expr(&expr)?.original.as_callable(db)?;
111111
match callable.kind() {
112-
hir::CallableKind::Function(it) => {
113-
let range = expr.syntax().text_range();
114-
it.try_to_nav(db).zip(Some(range))
115-
}
112+
hir::CallableKind::Function(it) => it.try_to_nav(db),
113+
hir::CallableKind::TupleEnumVariant(it) => it.try_to_nav(db),
114+
hir::CallableKind::TupleStruct(it) => it.try_to_nav(db),
116115
_ => None,
117116
}
117+
.zip(Some(expr.syntax().text_range()))
118118
}
119119
ast::CallableExpr::MethodCall(expr) => {
120120
let range = expr.name_ref()?.syntax().text_range();

0 commit comments

Comments
 (0)