Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide-completion/src/context/analysis.rs')
-rw-r--r--crates/ide-completion/src/context/analysis.rs43
1 files changed, 26 insertions, 17 deletions
diff --git a/crates/ide-completion/src/context/analysis.rs b/crates/ide-completion/src/context/analysis.rs
index 7a2230b3e3..ea5fb39338 100644
--- a/crates/ide-completion/src/context/analysis.rs
+++ b/crates/ide-completion/src/context/analysis.rs
@@ -4,6 +4,7 @@ use std::iter;
use hir::{ExpandResult, InFile, Semantics, Type, TypeInfo, Variant};
use ide_db::{RootDatabase, active_parameter::ActiveParameter};
use itertools::Either;
+use stdx::always;
use syntax::{
AstNode, AstToken, Direction, NodeOrToken, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken,
T, TextRange, TextSize,
@@ -38,9 +39,9 @@ struct ExpansionResult {
derive_ctx: Option<(SyntaxNode, SyntaxNode, TextSize, ast::Attr)>,
}
-pub(super) struct AnalysisResult {
- pub(super) analysis: CompletionAnalysis,
- pub(super) expected: (Option<Type>, Option<ast::NameOrNameRef>),
+pub(super) struct AnalysisResult<'db> {
+ pub(super) analysis: CompletionAnalysis<'db>,
+ pub(super) expected: (Option<Type<'db>>, Option<ast::NameOrNameRef>),
pub(super) qualifier_ctx: QualifierCtx,
/// the original token of the expanded file
pub(super) token: SyntaxToken,
@@ -48,13 +49,13 @@ pub(super) struct AnalysisResult {
pub(super) original_offset: TextSize,
}
-pub(super) fn expand_and_analyze(
- sema: &Semantics<'_, RootDatabase>,
+pub(super) fn expand_and_analyze<'db>(
+ sema: &Semantics<'db, RootDatabase>,
original_file: InFile<SyntaxNode>,
speculative_file: SyntaxNode,
offset: TextSize,
original_token: &SyntaxToken,
-) -> Option<AnalysisResult> {
+) -> Option<AnalysisResult<'db>> {
// as we insert after the offset, right biased will *always* pick the identifier no matter
// if there is an ident already typed or not
let fake_ident_token = speculative_file.token_at_offset(offset).right_biased()?;
@@ -432,12 +433,13 @@ fn expand(
/// Fill the completion context, this is what does semantic reasoning about the surrounding context
/// of the completion location.
-fn analyze(
- sema: &Semantics<'_, RootDatabase>,
+fn analyze<'db>(
+ sema: &Semantics<'db, RootDatabase>,
expansion_result: ExpansionResult,
original_token: &SyntaxToken,
self_token: &SyntaxToken,
-) -> Option<(CompletionAnalysis, (Option<Type>, Option<ast::NameOrNameRef>), QualifierCtx)> {
+) -> Option<(CompletionAnalysis<'db>, (Option<Type<'db>>, Option<ast::NameOrNameRef>), QualifierCtx)>
+{
let _p = tracing::info_span!("CompletionContext::analyze").entered();
let ExpansionResult {
original_file,
@@ -555,17 +557,17 @@ fn analyze(
}
/// Calculate the expected type and name of the cursor position.
-fn expected_type_and_name(
- sema: &Semantics<'_, RootDatabase>,
+fn expected_type_and_name<'db>(
+ sema: &Semantics<'db, RootDatabase>,
token: &SyntaxToken,
name_like: &ast::NameLike,
-) -> (Option<Type>, Option<NameOrNameRef>) {
+) -> (Option<Type<'db>>, Option<NameOrNameRef>) {
let mut node = match token.parent() {
Some(it) => it,
None => return (None, None),
};
- let strip_refs = |mut ty: Type| match name_like {
+ let strip_refs = |mut ty: Type<'db>| match name_like {
ast::NameLike::NameRef(n) => {
let p = match n.syntax().parent() {
Some(it) => it,
@@ -805,13 +807,13 @@ fn classify_name(
Some(NameContext { name, kind })
}
-fn classify_name_ref(
- sema: &Semantics<'_, RootDatabase>,
+fn classify_name_ref<'db>(
+ sema: &Semantics<'db, RootDatabase>,
original_file: &SyntaxNode,
name_ref: ast::NameRef,
original_offset: TextSize,
parent: SyntaxNode,
-) -> Option<(NameRefContext, QualifierCtx)> {
+) -> Option<(NameRefContext<'db>, QualifierCtx)> {
let nameref = find_node_at_offset(original_file, original_offset);
let make_res = |kind| (NameRefContext { nameref: nameref.clone(), kind }, Default::default());
@@ -868,8 +870,15 @@ fn classify_name_ref(
return None;
}
+ let mut receiver_ty = receiver.as_ref().and_then(|it| sema.type_of_expr(it));
+ if receiver_is_ambiguous_float_literal {
+ // `123.|` is parsed as a float but should actually be an integer.
+ always!(receiver_ty.as_ref().is_none_or(|receiver_ty| receiver_ty.original.is_float()));
+ receiver_ty = Some(TypeInfo { original: hir::BuiltinType::i32().ty(sema.db), adjusted: None });
+ }
+
let kind = NameRefKind::DotAccess(DotAccess {
- receiver_ty: receiver.as_ref().and_then(|it| sema.type_of_expr(it)),
+ receiver_ty,
kind: DotAccessKind::Field { receiver_is_ambiguous_float_literal },
receiver,
ctx: DotAccessExprCtx { in_block_expr: is_in_block(field.syntax()), in_breakable: is_in_breakable(field.syntax()) }