Simplify bind pat filtering

This commit is contained in:
Lukas Wirth 2023-05-13 11:02:57 +02:00
parent 730286b523
commit edd60f7b0d

View File

@ -3,7 +3,7 @@
//! fn f(a: i32, b: i32) -> i32 { a + b } //! fn f(a: i32, b: i32) -> i32 { a + b }
//! let _x /* i32 */= f(4, 4); //! let _x /* i32 */= f(4, 4);
//! ``` //! ```
use hir::{Semantics, TypeInfo}; use hir::Semantics;
use ide_db::{base_db::FileId, famous_defs::FamousDefs, RootDatabase}; use ide_db::{base_db::FileId, famous_defs::FamousDefs, RootDatabase};
use itertools::Itertools; use itertools::Itertools;
@ -28,11 +28,41 @@ pub(super) fn hints(
return None; return None;
} }
let parent = pat.syntax().parent()?;
let type_ascriptable = match_ast! {
match parent {
ast::Param(it) => {
if it.ty().is_some() {
return None;
}
Some(it.colon_token())
},
ast::LetStmt(it) => {
if config.hide_closure_initialization_hints {
if let Some(ast::Expr::ClosureExpr(closure)) = it.initializer() {
if closure_has_block_body(&closure) {
return None;
}
}
}
if it.ty().is_some() {
return None;
}
Some(it.colon_token())
},
_ => None
}
};
let descended = sema.descend_node_into_attributes(pat.clone()).pop(); let descended = sema.descend_node_into_attributes(pat.clone()).pop();
let desc_pat = descended.as_ref().unwrap_or(pat); let desc_pat = descended.as_ref().unwrap_or(pat);
let ty = sema.type_of_binding_in_pat(desc_pat)?; let ty = sema.type_of_binding_in_pat(desc_pat)?;
if should_not_display_type_hint(sema, config, pat, &ty) { if ty.is_unknown() {
return None;
}
if sema.resolve_bind_pat_to_const(pat).is_some() {
return None; return None;
} }
@ -44,11 +74,6 @@ pub(super) fn hints(
return None; return None;
} }
let type_ascriptable = desc_pat.syntax().parent().and_then(|it| {
ast::LetStmt::cast(it.clone())
.map(|it| it.colon_token())
.or_else(|| ast::Param::cast(it).map(|it| it.colon_token()))
});
let text_edit = if let Some(colon_token) = &type_ascriptable { let text_edit = if let Some(colon_token) = &type_ascriptable {
ty_to_text_edit( ty_to_text_edit(
sema, sema,
@ -89,57 +114,6 @@ pub(super) fn hints(
Some(()) Some(())
} }
fn should_not_display_type_hint(
sema: &Semantics<'_, RootDatabase>,
config: &InlayHintsConfig,
bind_pat: &ast::IdentPat,
pat_ty: &hir::Type,
) -> bool {
let db = sema.db;
if pat_ty.is_unknown() {
return true;
}
if sema.resolve_bind_pat_to_const(bind_pat).is_some() {
return true;
}
for node in bind_pat.syntax().ancestors() {
match_ast! {
match node {
ast::LetStmt(it) => {
if config.hide_closure_initialization_hints {
if let Some(ast::Expr::ClosureExpr(closure)) = it.initializer() {
if closure_has_block_body(&closure) {
return true;
}
}
}
return it.ty().is_some()
},
// FIXME: We might wanna show type hints in parameters for non-top level patterns as well
ast::Param(it) => return it.ty().is_some(),
ast::MatchArm(_) => return pat_is_enum_variant(db, bind_pat, pat_ty),
ast::LetExpr(_) => return pat_is_enum_variant(db, bind_pat, pat_ty),
ast::IfExpr(_) => return false,
ast::WhileExpr(_) => return false,
ast::ForExpr(it) => {
// We *should* display hint only if user provided "in {expr}" and we know the type of expr (and it's not unit).
// Type of expr should be iterable.
return it.in_token().is_none() ||
it.iterable()
.and_then(|iterable_expr| sema.type_of_expr(&iterable_expr))
.map(TypeInfo::original)
.map_or(true, |iterable_ty| iterable_ty.is_unknown() || iterable_ty.is_unit())
},
_ => (),
}
}
}
false
}
fn is_named_constructor( fn is_named_constructor(
sema: &Semantics<'_, RootDatabase>, sema: &Semantics<'_, RootDatabase>,
pat: &ast::IdentPat, pat: &ast::IdentPat,
@ -193,19 +167,6 @@ fn is_named_constructor(
(ctor_name == ty_name).then_some(()) (ctor_name == ty_name).then_some(())
} }
fn pat_is_enum_variant(db: &RootDatabase, bind_pat: &ast::IdentPat, pat_ty: &hir::Type) -> bool {
if let Some(hir::Adt::Enum(enum_data)) = pat_ty.as_adt() {
let pat_text = bind_pat.to_string();
enum_data
.variants(db)
.into_iter()
.map(|variant| variant.name(db).to_smol_str())
.any(|enum_name| enum_name == pat_text)
} else {
false
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
// This module also contains tests for super::closure_ret // This module also contains tests for super::closure_ret