mirror of
				https://github.com/rust-lang/rust-analyzer.git
				synced 2025-11-03 13:13:18 +00:00 
			
		
		
		
	Show coerced types on type hover
This commit is contained in:
		
							parent
							
								
									432bb222c3
								
							
						
					
					
						commit
						486603d559
					
				@ -225,7 +225,7 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
 | 
			
		||||
        self.imp.type_of_pat(pat)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn type_of_pat_with_coercion(&self, expr: &ast::Pat) -> Option<Type> {
 | 
			
		||||
    pub fn type_of_pat_with_coercion(&self, expr: &ast::Pat) -> Option<(Type, bool)> {
 | 
			
		||||
        self.imp.type_of_pat_with_coercion(expr)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -577,7 +577,7 @@ impl<'db> SemanticsImpl<'db> {
 | 
			
		||||
        self.analyze(pat.syntax()).type_of_pat(self.db, pat)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn type_of_pat_with_coercion(&self, pat: &ast::Pat) -> Option<Type> {
 | 
			
		||||
    fn type_of_pat_with_coercion(&self, pat: &ast::Pat) -> Option<(Type, bool)> {
 | 
			
		||||
        self.analyze(pat.syntax()).type_of_pat_with_coercion(self.db, pat)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -147,15 +147,15 @@ impl SourceAnalyzer {
 | 
			
		||||
        &self,
 | 
			
		||||
        db: &dyn HirDatabase,
 | 
			
		||||
        pat: &ast::Pat,
 | 
			
		||||
    ) -> Option<Type> {
 | 
			
		||||
    ) -> Option<(Type, bool)> {
 | 
			
		||||
        let pat_id = self.pat_id(pat)?;
 | 
			
		||||
        let infer = self.infer.as_ref()?;
 | 
			
		||||
        let ty = infer
 | 
			
		||||
        let (ty, coerced) = infer
 | 
			
		||||
            .pat_adjustments
 | 
			
		||||
            .get(&pat_id)
 | 
			
		||||
            .and_then(|adjusts| adjusts.last().map(|adjust| &adjust.target))
 | 
			
		||||
            .unwrap_or_else(|| &infer[pat_id]);
 | 
			
		||||
        Type::new_with_resolver(db, &self.resolver, ty.clone())
 | 
			
		||||
            .and_then(|adjusts| adjusts.last().map(|adjust| (&adjust.target, true)))
 | 
			
		||||
            .unwrap_or_else(|| (&infer[pat_id], false));
 | 
			
		||||
        Type::new_with_resolver(db, &self.resolver, ty.clone()).zip(Some(coerced))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub(crate) fn type_of_self(
 | 
			
		||||
 | 
			
		||||
@ -79,34 +79,20 @@ pub struct HoverResult {
 | 
			
		||||
// image::https://user-images.githubusercontent.com/48062697/113020658-b5f98b80-917a-11eb-9f88-3dbc27320c95.gif[]
 | 
			
		||||
pub(crate) fn hover(
 | 
			
		||||
    db: &RootDatabase,
 | 
			
		||||
    range: FileRange,
 | 
			
		||||
    FileRange { file_id, range }: FileRange,
 | 
			
		||||
    config: &HoverConfig,
 | 
			
		||||
) -> Option<RangeInfo<HoverResult>> {
 | 
			
		||||
    let sema = hir::Semantics::new(db);
 | 
			
		||||
    let file = sema.parse(range.file_id).syntax().clone();
 | 
			
		||||
    let file = sema.parse(file_id).syntax().clone();
 | 
			
		||||
 | 
			
		||||
    // This means we're hovering over a range.
 | 
			
		||||
    if !range.range.is_empty() {
 | 
			
		||||
        let expr = find_node_at_range::<ast::Expr>(&file, range.range)?;
 | 
			
		||||
        let ty = sema.type_of_expr(&expr)?;
 | 
			
		||||
 | 
			
		||||
        if ty.is_unknown() {
 | 
			
		||||
            return None;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let mut res = HoverResult::default();
 | 
			
		||||
 | 
			
		||||
        res.markup = if config.markdown() {
 | 
			
		||||
            Markup::fenced_block(&ty.display(db))
 | 
			
		||||
    let offset = if range.is_empty() {
 | 
			
		||||
        range.start()
 | 
			
		||||
    } else {
 | 
			
		||||
            ty.display(db).to_string().into()
 | 
			
		||||
        let expr = find_node_at_range::<ast::Expr>(&file, range).map(Either::Left)?;
 | 
			
		||||
        return hover_type_info(&sema, config, expr).map(|it| RangeInfo::new(range, it));
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
        return Some(RangeInfo::new(range.range, res));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let position = FilePosition { file_id: range.file_id, offset: range.range.start() };
 | 
			
		||||
    let token = pick_best_token(file.token_at_offset(position.offset), |kind| match kind {
 | 
			
		||||
    let token = pick_best_token(file.token_at_offset(offset), |kind| match kind {
 | 
			
		||||
        IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] | T![super] | T![crate] => 3,
 | 
			
		||||
        T!['('] | T![')'] => 2,
 | 
			
		||||
        kind if kind.is_trivia() => 0,
 | 
			
		||||
@ -114,8 +100,6 @@ pub(crate) fn hover(
 | 
			
		||||
    })?;
 | 
			
		||||
    let token = sema.descend_into_macros(token);
 | 
			
		||||
 | 
			
		||||
    let mut res = HoverResult::default();
 | 
			
		||||
 | 
			
		||||
    let node = token.parent()?;
 | 
			
		||||
    let mut range = None;
 | 
			
		||||
    let definition = match_ast! {
 | 
			
		||||
@ -146,8 +130,8 @@ pub(crate) fn hover(
 | 
			
		||||
                    let (docs, doc_mapping) = attributes.docs_with_rangemap(db)?;
 | 
			
		||||
                    let (idl_range, link, ns) =
 | 
			
		||||
                        extract_definitions_from_docs(&docs).into_iter().find_map(|(range, link, ns)| {
 | 
			
		||||
                            let hir::InFile { file_id, value: mapped_range } = doc_mapping.map(range)?;
 | 
			
		||||
                            (file_id == position.file_id.into() && mapped_range.contains(position.offset)).then(||(mapped_range, link, ns))
 | 
			
		||||
                            let mapped = doc_mapping.map(range)?;
 | 
			
		||||
                            (mapped.file_id == file_id.into() && mapped.value.contains(offset)).then(||(mapped.value, link, ns))
 | 
			
		||||
                        })?;
 | 
			
		||||
                    range = Some(idl_range);
 | 
			
		||||
                    resolve_doc_path_for_def(db, def, &link, ns).map(Definition::ModuleDef)
 | 
			
		||||
@ -173,6 +157,7 @@ pub(crate) fn hover(
 | 
			
		||||
            _ => None,
 | 
			
		||||
        };
 | 
			
		||||
        if let Some(markup) = hover_for_definition(db, definition, famous_defs.as_ref(), config) {
 | 
			
		||||
            let mut res = HoverResult::default();
 | 
			
		||||
            res.markup = process_markup(sema.db, definition, &markup, config);
 | 
			
		||||
            if let Some(action) = show_implementations_action(db, definition) {
 | 
			
		||||
                res.actions.push(action);
 | 
			
		||||
@ -182,7 +167,7 @@ pub(crate) fn hover(
 | 
			
		||||
                res.actions.push(action);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if let Some(action) = runnable_action(&sema, definition, position.file_id) {
 | 
			
		||||
            if let Some(action) = runnable_action(&sema, definition, file_id) {
 | 
			
		||||
                res.actions.push(action);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@ -204,10 +189,10 @@ pub(crate) fn hover(
 | 
			
		||||
        .take_while(|it| !ast::Item::can_cast(it.kind()))
 | 
			
		||||
        .find(|n| ast::Expr::can_cast(n.kind()) || ast::Pat::can_cast(n.kind()))?;
 | 
			
		||||
 | 
			
		||||
    let ty = match_ast! {
 | 
			
		||||
    let expr_or_pat = match_ast! {
 | 
			
		||||
        match node {
 | 
			
		||||
            ast::Expr(it) => sema.type_of_expr(&it)?,
 | 
			
		||||
            ast::Pat(it) => sema.type_of_pat(&it)?,
 | 
			
		||||
            ast::Expr(it) => Either::Left(it),
 | 
			
		||||
            ast::Pat(it) => Either::Right(it),
 | 
			
		||||
            // If this node is a MACRO_CALL, it means that `descend_into_macros` failed to resolve.
 | 
			
		||||
            // (e.g expanding a builtin macro). So we give up here.
 | 
			
		||||
            ast::MacroCall(_it) => return None,
 | 
			
		||||
@ -215,16 +200,48 @@ pub(crate) fn hover(
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    res.markup = if config.markdown() {
 | 
			
		||||
        Markup::fenced_block(&ty.display(db))
 | 
			
		||||
    } else {
 | 
			
		||||
        ty.display(db).to_string().into()
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    let res = hover_type_info(&sema, config, expr_or_pat)?;
 | 
			
		||||
    let range = sema.original_range(&node).range;
 | 
			
		||||
    Some(RangeInfo::new(range, res))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn hover_type_info(
 | 
			
		||||
    sema: &Semantics<RootDatabase>,
 | 
			
		||||
    config: &HoverConfig,
 | 
			
		||||
    expr_or_pat: Either<ast::Expr, ast::Pat>,
 | 
			
		||||
) -> Option<HoverResult> {
 | 
			
		||||
    let (ty, coerced) = match &expr_or_pat {
 | 
			
		||||
        Either::Left(expr) => sema.type_of_expr_with_coercion(expr)?,
 | 
			
		||||
        Either::Right(pat) => sema.type_of_pat_with_coercion(pat)?,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    let mut res = HoverResult::default();
 | 
			
		||||
    res.markup = if coerced {
 | 
			
		||||
        let uncoerced_ty = match &expr_or_pat {
 | 
			
		||||
            Either::Left(expr) => sema.type_of_expr(expr)?,
 | 
			
		||||
            Either::Right(pat) => sema.type_of_pat(pat)?,
 | 
			
		||||
        };
 | 
			
		||||
        let uncoerced = uncoerced_ty.display(sema.db).to_string();
 | 
			
		||||
        let coerced = ty.display(sema.db).to_string();
 | 
			
		||||
        format!(
 | 
			
		||||
            "```text\nType: {:>upad$}\nCoerced to: {:>cpad$}\n```\n",
 | 
			
		||||
            uncoerced = uncoerced,
 | 
			
		||||
            coerced = coerced,
 | 
			
		||||
            // 6 base padding for static text prefix of each line
 | 
			
		||||
            upad = 6 + coerced.len().max(uncoerced.len()),
 | 
			
		||||
            cpad = uncoerced.len(),
 | 
			
		||||
        )
 | 
			
		||||
        .into()
 | 
			
		||||
    } else {
 | 
			
		||||
        if config.markdown() {
 | 
			
		||||
            Markup::fenced_block(&ty.display(sema.db))
 | 
			
		||||
        } else {
 | 
			
		||||
            ty.display(sema.db).to_string().into()
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
    Some(res)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn try_hover_for_lint(attr: &ast::Attr, token: &SyntaxToken) -> Option<RangeInfo<HoverResult>> {
 | 
			
		||||
    let (path, tt) = attr.as_simple_call()?;
 | 
			
		||||
    if !tt.syntax().text_range().contains(token.text_range().start()) {
 | 
			
		||||
@ -1189,7 +1206,7 @@ impl Thing {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn main() { let foo_$0test = Thing::new(); }
 | 
			
		||||
            "#,
 | 
			
		||||
"#,
 | 
			
		||||
            expect![[r#"
 | 
			
		||||
                *foo_test*
 | 
			
		||||
 | 
			
		||||
@ -1559,7 +1576,7 @@ fn foo() {
 | 
			
		||||
            fn foo() {
 | 
			
		||||
                format!("hel$0lo {}", 0);
 | 
			
		||||
            }
 | 
			
		||||
            "#,
 | 
			
		||||
"#,
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -1667,7 +1684,7 @@ extern crate st$0d;
 | 
			
		||||
//!
 | 
			
		||||
//! Printed?
 | 
			
		||||
//! abc123
 | 
			
		||||
            "#,
 | 
			
		||||
"#,
 | 
			
		||||
            expect![[r#"
 | 
			
		||||
                *std*
 | 
			
		||||
 | 
			
		||||
@ -1692,7 +1709,7 @@ extern crate std as ab$0c;
 | 
			
		||||
//!
 | 
			
		||||
//! Printed?
 | 
			
		||||
//! abc123
 | 
			
		||||
            "#,
 | 
			
		||||
"#,
 | 
			
		||||
            expect![[r#"
 | 
			
		||||
                *abc*
 | 
			
		||||
 | 
			
		||||
@ -2211,7 +2228,7 @@ mod tests$0 {
 | 
			
		||||
struct S{ f1: u32 }
 | 
			
		||||
 | 
			
		||||
fn main() { let s$0t = S{ f1:0 }; }
 | 
			
		||||
            "#,
 | 
			
		||||
"#,
 | 
			
		||||
            expect![[r#"
 | 
			
		||||
                [
 | 
			
		||||
                    GoToType(
 | 
			
		||||
@ -2290,7 +2307,7 @@ struct Arg(u32);
 | 
			
		||||
struct S<T>{ f1: T }
 | 
			
		||||
 | 
			
		||||
fn main() { let s$0t = S{ f1: S{ f1: Arg(0) } }; }
 | 
			
		||||
            "#,
 | 
			
		||||
"#,
 | 
			
		||||
            expect![[r#"
 | 
			
		||||
                [
 | 
			
		||||
                    GoToType(
 | 
			
		||||
@ -2479,7 +2496,7 @@ trait Bar {}
 | 
			
		||||
fn foo() -> impl Foo + Bar {}
 | 
			
		||||
 | 
			
		||||
fn main() { let s$0t = foo(); }
 | 
			
		||||
            "#,
 | 
			
		||||
"#,
 | 
			
		||||
            expect![[r#"
 | 
			
		||||
                [
 | 
			
		||||
                    GoToType(
 | 
			
		||||
@ -2912,7 +2929,7 @@ struct B<T> {}
 | 
			
		||||
struct S {}
 | 
			
		||||
 | 
			
		||||
fn foo(a$0rg: &impl ImplTrait<B<dyn DynTrait<B<S>>>>) {}
 | 
			
		||||
            "#,
 | 
			
		||||
"#,
 | 
			
		||||
            expect![[r#"
 | 
			
		||||
                [
 | 
			
		||||
                    GoToType(
 | 
			
		||||
@ -3708,7 +3725,7 @@ mod string {
 | 
			
		||||
    /// This is `alloc::String`.
 | 
			
		||||
    pub struct String;
 | 
			
		||||
}
 | 
			
		||||
            "#,
 | 
			
		||||
"#,
 | 
			
		||||
            expect![[r#"
 | 
			
		||||
                *String*
 | 
			
		||||
 | 
			
		||||
@ -3827,7 +3844,7 @@ pub fn foo() {}
 | 
			
		||||
//- /lib.rs crate:main.rs deps:foo
 | 
			
		||||
#[fo$0o::bar()]
 | 
			
		||||
struct Foo;
 | 
			
		||||
            "#,
 | 
			
		||||
"#,
 | 
			
		||||
            expect![[r#"
 | 
			
		||||
                *foo*
 | 
			
		||||
 | 
			
		||||
@ -3843,7 +3860,7 @@ struct Foo;
 | 
			
		||||
        check(
 | 
			
		||||
            r#"
 | 
			
		||||
use self as foo$0;
 | 
			
		||||
            "#,
 | 
			
		||||
"#,
 | 
			
		||||
            expect![[r#"
 | 
			
		||||
                *foo*
 | 
			
		||||
 | 
			
		||||
@ -3856,7 +3873,7 @@ use self as foo$0;
 | 
			
		||||
            r#"
 | 
			
		||||
mod bar {}
 | 
			
		||||
use bar::{self as foo$0};
 | 
			
		||||
            "#,
 | 
			
		||||
"#,
 | 
			
		||||
            expect![[r#"
 | 
			
		||||
                *foo*
 | 
			
		||||
 | 
			
		||||
@ -3874,7 +3891,7 @@ use bar::{self as foo$0};
 | 
			
		||||
mod bar {
 | 
			
		||||
    use super as foo$0;
 | 
			
		||||
}
 | 
			
		||||
            "#,
 | 
			
		||||
"#,
 | 
			
		||||
            expect![[r#"
 | 
			
		||||
                *foo*
 | 
			
		||||
 | 
			
		||||
@ -3886,7 +3903,7 @@ mod bar {
 | 
			
		||||
        check(
 | 
			
		||||
            r#"
 | 
			
		||||
use crate as foo$0;
 | 
			
		||||
            "#,
 | 
			
		||||
"#,
 | 
			
		||||
            expect![[r#"
 | 
			
		||||
                *foo*
 | 
			
		||||
 | 
			
		||||
@ -3905,7 +3922,7 @@ use crate as foo$0;
 | 
			
		||||
pub macro Copy {}
 | 
			
		||||
#[derive(Copy$0)]
 | 
			
		||||
struct Foo;
 | 
			
		||||
            "#,
 | 
			
		||||
"#,
 | 
			
		||||
            expect![[r#"
 | 
			
		||||
                *Copy*
 | 
			
		||||
 | 
			
		||||
@ -3926,7 +3943,7 @@ mod foo {
 | 
			
		||||
}
 | 
			
		||||
#[derive(foo::Copy$0)]
 | 
			
		||||
struct Foo;
 | 
			
		||||
            "#,
 | 
			
		||||
"#,
 | 
			
		||||
            expect![[r#"
 | 
			
		||||
                *Copy*
 | 
			
		||||
 | 
			
		||||
@ -3946,7 +3963,7 @@ struct Foo;
 | 
			
		||||
        check_hover_range(
 | 
			
		||||
            r#"
 | 
			
		||||
fn f() { let expr = $01 + 2 * 3$0 }
 | 
			
		||||
            "#,
 | 
			
		||||
"#,
 | 
			
		||||
            expect![[r#"
 | 
			
		||||
            ```rust
 | 
			
		||||
            i32
 | 
			
		||||
@ -3956,7 +3973,7 @@ fn f() { let expr = $01 + 2 * 3$0 }
 | 
			
		||||
        check_hover_range(
 | 
			
		||||
            r#"
 | 
			
		||||
fn f() { let expr = 1 $0+ 2 * $03 }
 | 
			
		||||
            "#,
 | 
			
		||||
"#,
 | 
			
		||||
            expect![[r#"
 | 
			
		||||
            ```rust
 | 
			
		||||
            i32
 | 
			
		||||
@ -3966,7 +3983,7 @@ fn f() { let expr = 1 $0+ 2 * $03 }
 | 
			
		||||
        check_hover_range(
 | 
			
		||||
            r#"
 | 
			
		||||
fn f() { let expr = 1 + $02 * 3$0 }
 | 
			
		||||
            "#,
 | 
			
		||||
"#,
 | 
			
		||||
            expect![[r#"
 | 
			
		||||
            ```rust
 | 
			
		||||
            i32
 | 
			
		||||
@ -3979,7 +3996,7 @@ fn f() { let expr = 1 + $02 * 3$0 }
 | 
			
		||||
        check_hover_range(
 | 
			
		||||
            r#"
 | 
			
		||||
fn f() { let expr = $0[1, 2, 3, 4]$0 }
 | 
			
		||||
            "#,
 | 
			
		||||
"#,
 | 
			
		||||
            expect![[r#"
 | 
			
		||||
            ```rust
 | 
			
		||||
            [i32; 4]
 | 
			
		||||
@ -3989,7 +4006,7 @@ fn f() { let expr = $0[1, 2, 3, 4]$0 }
 | 
			
		||||
        check_hover_range(
 | 
			
		||||
            r#"
 | 
			
		||||
fn f() { let expr = [1, 2, $03, 4]$0 }
 | 
			
		||||
            "#,
 | 
			
		||||
"#,
 | 
			
		||||
            expect![[r#"
 | 
			
		||||
            ```rust
 | 
			
		||||
            [i32; 4]
 | 
			
		||||
@ -3999,7 +4016,7 @@ fn f() { let expr = [1, 2, $03, 4]$0 }
 | 
			
		||||
        check_hover_range(
 | 
			
		||||
            r#"
 | 
			
		||||
fn f() { let expr = [1, 2, $03$0, 4] }
 | 
			
		||||
            "#,
 | 
			
		||||
"#,
 | 
			
		||||
            expect![[r#"
 | 
			
		||||
            ```rust
 | 
			
		||||
            i32
 | 
			
		||||
@ -4013,7 +4030,7 @@ fn f() { let expr = [1, 2, $03$0, 4] }
 | 
			
		||||
            r#"
 | 
			
		||||
fn f<T>(a: &[T]) { }
 | 
			
		||||
fn b() { $0f$0(&[1, 2, 3, 4, 5]); }
 | 
			
		||||
            "#,
 | 
			
		||||
"#,
 | 
			
		||||
            expect![[r#"
 | 
			
		||||
            ```rust
 | 
			
		||||
            fn f<i32>(&[i32])
 | 
			
		||||
@ -4024,7 +4041,7 @@ fn b() { $0f$0(&[1, 2, 3, 4, 5]); }
 | 
			
		||||
            r#"
 | 
			
		||||
fn f<T>(a: &[T]) { }
 | 
			
		||||
fn b() { f($0&[1, 2, 3, 4, 5]$0); }
 | 
			
		||||
            "#,
 | 
			
		||||
"#,
 | 
			
		||||
            expect![[r#"
 | 
			
		||||
            ```rust
 | 
			
		||||
            &[i32; 5]
 | 
			
		||||
@ -4038,20 +4055,20 @@ fn b() { f($0&[1, 2, 3, 4, 5]$0); }
 | 
			
		||||
            r#"
 | 
			
		||||
fn f<T>(a: &[T]) { }
 | 
			
		||||
fn b()$0 { f(&[1, 2, 3, 4, 5]); }$0
 | 
			
		||||
            "#,
 | 
			
		||||
"#,
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        check_hover_range_no_results(
 | 
			
		||||
            r#"
 | 
			
		||||
fn f<T>$0(a: &[T]) { }
 | 
			
		||||
fn b() { f(&[1, 2, 3,$0 4, 5]); }
 | 
			
		||||
            "#,
 | 
			
		||||
"#,
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        check_hover_range_no_results(
 | 
			
		||||
            r#"
 | 
			
		||||
fn $0f() { let expr = [1, 2, 3, 4]$0 }
 | 
			
		||||
            "#,
 | 
			
		||||
"#,
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -4061,7 +4078,7 @@ fn $0f() { let expr = [1, 2, 3, 4]$0 }
 | 
			
		||||
            r#"
 | 
			
		||||
fn f<T>(a: &[T]) { }
 | 
			
		||||
fn b() { $0f(&[1, 2, 3, 4, 5]); }$0
 | 
			
		||||
            "#,
 | 
			
		||||
"#,
 | 
			
		||||
            expect![[r#"
 | 
			
		||||
            ```rust
 | 
			
		||||
            ()
 | 
			
		||||
@ -4071,11 +4088,41 @@ fn b() { $0f(&[1, 2, 3, 4, 5]); }$0
 | 
			
		||||
        check_hover_range(
 | 
			
		||||
            r#"
 | 
			
		||||
fn f() { let expr$0 = $0[1, 2, 3, 4] }
 | 
			
		||||
            "#,
 | 
			
		||||
"#,
 | 
			
		||||
            expect![[r#"
 | 
			
		||||
            ```rust
 | 
			
		||||
            ()
 | 
			
		||||
            ```"#]],
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn hover_range_shows_coercions_if_applicable() {
 | 
			
		||||
        check_hover_range(
 | 
			
		||||
            r#"
 | 
			
		||||
fn foo() {
 | 
			
		||||
    let x: &u32 = $0&&&&&0$0;
 | 
			
		||||
}
 | 
			
		||||
"#,
 | 
			
		||||
            expect![[r#"
 | 
			
		||||
                ```
 | 
			
		||||
                Type:       &&&&&u32
 | 
			
		||||
                Coerced to:     &u32
 | 
			
		||||
                ```
 | 
			
		||||
            "#]],
 | 
			
		||||
        );
 | 
			
		||||
        check_hover_range(
 | 
			
		||||
            r#"
 | 
			
		||||
fn foo() {
 | 
			
		||||
    let x: *const u32 = $0&0$0;
 | 
			
		||||
}
 | 
			
		||||
"#,
 | 
			
		||||
            expect![[r#"
 | 
			
		||||
                ```
 | 
			
		||||
                Type:             &u32
 | 
			
		||||
                Coerced to: *const u32
 | 
			
		||||
                ```
 | 
			
		||||
            "#]],
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user