Skip to content

Commit 5980265

Browse files
Add inlay hints for inferred consts
This provides an inlay hint for _ in const generic arguments.
1 parent 9dc0e4c commit 5980265

4 files changed

Lines changed: 90 additions & 13 deletions

File tree

crates/hir/src/semantics.rs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ use hir_ty::{
3636
diagnostics::unsafe_operations,
3737
infer_query_with_inspect,
3838
next_solver::{
39-
AnyImplId, DbInterner,
39+
AnyImplId, Const as ResolvedConst, DbInterner,
4040
format_proof_tree::{ProofTreeData, dump_proof_tree_structured},
4141
},
4242
};
@@ -1698,6 +1698,18 @@ impl<'db> SemanticsImpl<'db> {
16981698
analyze.type_of_type(self.db, ty)
16991699
}
17001700

1701+
pub fn resolve_infer(
1702+
&self,
1703+
ty: &ast::InferType,
1704+
) -> Option<Either<Type<'db>, ResolvedConst<'db>>> {
1705+
let analyze = self.analyze(ty.syntax())?;
1706+
if let Some(const_) = analyze.resolve_infer_type_as_const(ty) {
1707+
return Some(Either::Right(const_));
1708+
}
1709+
let ty = analyze.type_of_type(self.db, &ast::Type::InferType(ty.clone()))?;
1710+
Some(Either::Left(ty))
1711+
}
1712+
17011713
pub fn resolve_trait(&self, path: &ast::Path) -> Option<Trait> {
17021714
let parent_ty = path.syntax().parent().and_then(ast::Type::cast)?;
17031715
let analyze = self.analyze(path.syntax())?;
@@ -1859,6 +1871,13 @@ impl<'db> SemanticsImpl<'db> {
18591871
self.analyze(try_expr.syntax())?.resolve_try_expr(self.db, try_expr)
18601872
}
18611873

1874+
pub fn resolve_underscore_expr(
1875+
&self,
1876+
underscore_expr: &ast::UnderscoreExpr,
1877+
) -> Option<ResolvedConst<'db>> {
1878+
self.analyze(underscore_expr.syntax())?.resolve_underscore_expr(underscore_expr)
1879+
}
1880+
18621881
/// The type that the associated `try` block, closure or function expects.
18631882
pub fn try_expr_returned_type(&self, try_expr: &ast::TryExpr) -> Option<Type<'db>> {
18641883
self.ancestors_with_macros(try_expr.syntax().clone()).find_map(|parent| {

crates/hir/src/source_analyzer.rs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ use hir_ty::{
3737
lang_items::lang_items_for_bin_op,
3838
method_resolution::{self, CandidateId},
3939
next_solver::{
40-
AliasTy, DbInterner, ErrorGuaranteed, GenericArgs, ParamEnv, Ty, TyKind, TypingMode,
41-
infer::DbInternerInferExt,
40+
AliasTy, Const as ResolvedConst, DbInterner, ErrorGuaranteed, GenericArgs, ParamEnv, Ty,
41+
TyKind, TypingMode, infer::DbInternerInferExt,
4242
},
4343
traits::structurally_normalize_ty,
4444
};
@@ -844,6 +844,22 @@ impl<'db> SourceAnalyzer<'db> {
844844
Some(self.resolve_impl_method_or_trait_def(db, op_fn, substs))
845845
}
846846

847+
pub(crate) fn resolve_underscore_expr(
848+
&self,
849+
underscore_expr: &ast::UnderscoreExpr,
850+
) -> Option<ResolvedConst<'db>> {
851+
let expr = self.expr_id(ast::Expr::UnderscoreExpr(underscore_expr.clone()))?.as_expr()?;
852+
self.infer()?.const_of_const_placeholder(expr.into())
853+
}
854+
855+
pub(crate) fn resolve_infer_type_as_const(
856+
&self,
857+
infer_type: &ast::InferType,
858+
) -> Option<ResolvedConst<'db>> {
859+
let type_ref = self.type_id(&ast::Type::InferType(infer_type.clone()))?;
860+
self.infer()?.const_of_const_placeholder(type_ref.into())
861+
}
862+
847863
pub(crate) fn resolve_record_field(
848864
&self,
849865
db: &'db dyn HirDatabase,

crates/ide/src/inlay_hints.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,7 @@ fn hints(
240240
},
241241
ast::Expr::RangeExpr(it) => range_exclusive::hints(hints, famous_defs, config, it),
242242
ast::Expr::Literal(it) => ra_fixture::hints(hints, famous_defs.0, file_id, config, it),
243+
ast::Expr::UnderscoreExpr(it) => placeholders::const_hints(hints, famous_defs, config, display_target, it),
243244
_ => Some(()),
244245
}
245246
},

crates/ide/src/inlay_hints/placeholders.rs

Lines changed: 51 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@
44
//! //^ = i32
55
//! ```
66
7-
use hir::DisplayTarget;
7+
use either::Either;
8+
use hir::{DisplayTarget, HirDisplay};
89
use ide_db::famous_defs::FamousDefs;
910
use syntax::{
1011
AstNode,
11-
ast::{InferType, Type},
12+
ast::{InferType, UnderscoreExpr},
1213
};
1314

1415
use crate::{InlayHint, InlayHintPosition, InlayHintsConfig, InlayKind, inlay_hints::label_of_ty};
@@ -27,9 +28,14 @@ pub(super) fn type_hints(
2728
let syntax = placeholder.syntax();
2829
let range = syntax.text_range();
2930

30-
let ty = sema.resolve_type(&Type::InferType(placeholder))?;
31+
let type_or_const = sema.resolve_infer(&placeholder)?;
3132

32-
let mut label = label_of_ty(famous_defs, config, &ty, display_target)?;
33+
let mut label = match type_or_const {
34+
Either::Left(ty) => label_of_ty(famous_defs, config, &ty, display_target)?,
35+
Either::Right(const_) => {
36+
const_.display_truncated(sema.db, config.max_length, display_target).to_string().into()
37+
}
38+
};
3339
label.prepend_str("= ");
3440

3541
acc.push(InlayHint {
@@ -45,6 +51,38 @@ pub(super) fn type_hints(
4551
Some(())
4652
}
4753

54+
pub(super) fn const_hints(
55+
acc: &mut Vec<InlayHint>,
56+
FamousDefs(sema, _): &FamousDefs<'_, '_>,
57+
config: &InlayHintsConfig<'_>,
58+
display_target: DisplayTarget,
59+
placeholder: UnderscoreExpr,
60+
) -> Option<()> {
61+
if !config.type_hints || config.hide_inferred_type_hints {
62+
return None;
63+
}
64+
65+
let syntax = placeholder.syntax();
66+
let range = syntax.text_range();
67+
68+
let const_ = sema.resolve_underscore_expr(&placeholder)?;
69+
70+
let display = const_.display_truncated(sema.db, config.max_length, display_target);
71+
let label = format!("= {display}").into();
72+
73+
acc.push(InlayHint {
74+
range,
75+
kind: InlayKind::Type,
76+
label,
77+
text_edit: None,
78+
position: InlayHintPosition::After,
79+
pad_left: true,
80+
pad_right: false,
81+
resolve_parent: None,
82+
});
83+
Some(())
84+
}
85+
4886
#[cfg(test)]
4987
mod tests {
5088
use crate::{
@@ -58,17 +96,20 @@ mod tests {
5896
}
5997

6098
#[test]
61-
fn inferred_types() {
99+
fn inferred_types_and_consts() {
62100
check_type_infer(
63101
r#"
64-
struct S<T>(T);
102+
struct S<T, const N: usize>([T; N]);
65103
66104
fn foo() {
67-
let t: (_, _, [_; _]) = (1_u32, S(2), [false] as _);
105+
let t: (_, S<_, _>, [_; _]) = (1_u32, S([2, 3]) as _, [false] as _);
68106
//^ = u32
69-
//^ = S<i32>
70-
//^ = bool
71-
//^ = [bool; 1]
107+
//^ = i32
108+
//^ = 2
109+
//^ = bool
110+
//^ = 1
111+
//^ = S<i32, 2>
112+
//^ = [bool; 1]
72113
}
73114
"#,
74115
);

0 commit comments

Comments
 (0)