Add assignment type analysis for ide-completion

This commit is contained in:
A4-Tacks 2025-08-04 01:53:10 +08:00
parent 922e04a134
commit 22d6136462
No known key found for this signature in database
GPG Key ID: 86AC1F526BA06668
2 changed files with 82 additions and 0 deletions

View File

@ -562,6 +562,7 @@ fn expected_type_and_name<'db>(
token: &SyntaxToken,
name_like: &ast::NameLike,
) -> (Option<Type<'db>>, Option<NameOrNameRef>) {
let token = prev_assign_token_at_whitespace(token.clone());
let mut node = match token.parent() {
Some(it) => it,
None => return (None, None),
@ -632,6 +633,17 @@ fn expected_type_and_name<'db>(
.map(TypeInfo::original);
(ty, None)
},
ast::BinExpr(it) => {
if let Some(ast::BinaryOp::Assignment { op: None }) = it.op_kind() {
let ty = it.lhs()
.and_then(|lhs| sema.type_of_expr(&lhs))
.or_else(|| it.rhs().and_then(|rhs| sema.type_of_expr(&rhs)))
.map(TypeInfo::original);
(ty, None)
} else {
(None, None)
}
},
ast::ArgList(_) => {
cov_mark::hit!(expected_type_fn_param);
ActiveParameter::at_token(
@ -1870,3 +1882,23 @@ fn next_non_trivia_sibling(ele: SyntaxElement) -> Option<SyntaxElement> {
}
None
}
fn prev_assign_token_at_whitespace(mut token: SyntaxToken) -> SyntaxToken {
while token.kind() == SyntaxKind::WHITESPACE
&& let Some(prev) = token.prev_token()
&& let T![=]
| T![+=]
| T![/=]
| T![*=]
| T![%=]
| T![>>=]
| T![<<=]
| T![-=]
| T![|=]
| T![&=]
| T![^=] = prev.kind()
{
token = prev
}
token
}

View File

@ -434,3 +434,53 @@ fn f(thing: u32) -> &u32 {
expect!["ty: u32, name: ?"],
);
}
#[test]
fn expected_type_assign() {
check_expected_type_and_name(
r#"
enum State { Stop }
fn foo() {
let x: &mut State = &mut State::Stop;
x = $0;
}
"#,
expect![[r#"ty: &'_ mut State, name: ?"#]],
);
}
#[test]
fn expected_type_deref_assign() {
check_expected_type_and_name(
r#"
enum State { Stop }
fn foo() {
let x: &mut State = &mut State::Stop;
match x {
State::Stop => {
*x = $0;
},
}
}
"#,
expect![[r#"ty: State, name: ?"#]],
);
}
#[test]
fn expected_type_deref_assign_at_block_end() {
check_expected_type_and_name(
r#"
enum State { Stop }
fn foo() {
let x: &mut State = &mut State::Stop;
match x {
State::Stop => {
*x = $0
},
}
}
"#,
expect![[r#"ty: State, name: ?"#]],
);
}