Repository: rust-analyzer/rust-analyzer
Pull request #3383 (2020-02-29 22:25:06)

Slightly refactor inlay hints


bors r+
🤖


Patch:
diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs
index 377f44fa75..569d46cc38 100644
--- a/crates/ra_hir_ty/src/infer.rs
+++ b/crates/ra_hir_ty/src/infer.rs
@@ -28,7 +28,7 @@ use hir_def::{
     path::{path, Path},
     resolver::{HasResolver, Resolver, TypeNs},
     type_ref::{Mutability, TypeRef},
-    AdtId, AssocItemId, DefWithBodyId, FunctionId, StructFieldId, TraitId, TypeAliasId, VariantId,
+    AdtId, AssocItemId, DefWithBodyId, FunctionId, StructFieldId, TypeAliasId, VariantId,
 };
 use hir_expand::{diagnostics::DiagnosticSink, name::name};
 use ra_arena::map::ArenaMap;
@@ -540,12 +540,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
         Some(struct_.into())
     }
 
-    fn resolve_ops_index(&self) -> Option<TraitId> {
-        self.resolve_lang_item("index")?.as_trait()
-    }
-
     fn resolve_ops_index_output(&self) -> Option<TypeAliasId> {
-        let trait_ = self.resolve_ops_index()?;
+        let trait_ = self.resolve_lang_item("index")?.as_trait()?;
         self.db.trait_data(trait_).associated_type_by_name(&name![Output])
     }
 }
diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs
index e89cc72987..3db5b2b515 100644
--- a/crates/ra_hir_ty/src/infer/expr.rs
+++ b/crates/ra_hir_ty/src/infer/expr.rs
@@ -429,27 +429,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
                 let base_ty = self.infer_expr_inner(*base, &Expectation::none());
                 let index_ty = self.infer_expr(*index, &Expectation::none());
 
-                if let (Some(index_trait), Some(krate)) =
-                    (self.resolve_ops_index(), self.resolver.krate())
-                {
-                    let canonicalized = self.canonicalizer().canonicalize_ty(base_ty);
-                    let self_ty = method_resolution::resolve_indexing_op(
-                        self.db,
-                        &canonicalized.value,
-                        self.trait_env.clone(),
-                        krate,
-                        index_trait,
-                    );
-                    let self_ty =
-                        self_ty.map_or(Ty::Unknown, |t| canonicalized.decanonicalize_ty(t.value));
-                    self.resolve_associated_type_with_params(
-                        self_ty,
-                        self.resolve_ops_index_output(),
-                        &[index_ty],
-                    )
-                } else {
-                    Ty::Unknown
-                }
+                self.resolve_associated_type_with_params(
+                    base_ty,
+                    self.resolve_ops_index_output(),
+                    &[index_ty],
+                )
             }
             Expr::Tuple { exprs } => {
                 let mut tys = match &expected.ty {
diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs
index 74b908c2e0..df5901835a 100644
--- a/crates/ra_hir_ty/src/method_resolution.rs
+++ b/crates/ra_hir_ty/src/method_resolution.rs
@@ -20,7 +20,7 @@ use crate::{
     db::HirDatabase,
     primitive::{FloatBitness, Uncertain},
     utils::all_super_traits,
-    ApplicationTy, Canonical, InEnvironment, TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk,
+    Canonical, InEnvironment, TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk,
 };
 
 /// This is used as a key for indexing impls.
@@ -214,7 +214,7 @@ pub fn iterate_method_candidates<T>(
             // the methods by autoderef order of *receiver types*, not *self
             // types*.
 
-            let deref_chain = autoderef_method_receiver(db, krate, ty);
+            let deref_chain: Vec<_> = autoderef::autoderef(db, Some(krate), ty).collect();
             for i in 0..deref_chain.len() {
                 if let Some(result) = iterate_method_candidates_with_autoref(
                     &deref_chain[i..],
@@ -447,25 +447,6 @@ fn iterate_inherent_methods<T>(
     None
 }
 
-/// Returns the self type for the index trait call.
-pub fn resolve_indexing_op(
-    db: &impl HirDatabase,
-    ty: &Canonical<Ty>,
-    env: Arc<TraitEnvironment>,
-    krate: CrateId,
-    index_trait: TraitId,
-) -> Option<Canonical<Ty>> {
-    let ty = InEnvironment { value: ty.clone(), environment: env.clone() };
-    let deref_chain = autoderef_method_receiver(db, krate, ty);
-    for ty in deref_chain {
-        let goal = generic_implements_goal(db, env.clone(), index_trait, ty.clone());
-        if db.trait_solve(krate, goal).is_some() {
-            return Some(ty);
-        }
-    }
-    None
-}
-
 fn is_valid_candidate(
     db: &impl HirDatabase,
     name: Option<&Name>,
@@ -567,20 +548,3 @@ fn generic_implements_goal(
     let obligation = super::Obligation::Trait(trait_ref);
     Canonical { num_vars, value: InEnvironment::new(env, obligation) }
 }
-
-fn autoderef_method_receiver(
-    db: &impl HirDatabase,
-    krate: CrateId,
-    ty: InEnvironment<Canonical<Ty>>,
-) -> Vec<Canonical<Ty>> {
-    let mut deref_chain: Vec<_> = autoderef::autoderef(db, Some(krate), ty).collect();
-    // As a last step, we can do array unsizing (that's the only unsizing that rustc does for method receivers!)
-    if let Some(Ty::Apply(ApplicationTy { ctor: TypeCtor::Array, parameters })) =
-        deref_chain.last().map(|ty| &ty.value)
-    {
-        let num_vars = deref_chain.last().unwrap().num_vars;
-        let unsized_ty = Ty::apply(TypeCtor::Slice, parameters.clone());
-        deref_chain.push(Canonical { value: unsized_ty, num_vars })
-    }
-    deref_chain
-}
diff --git a/crates/ra_ide/src/inlay_hints.rs b/crates/ra_ide/src/inlay_hints.rs
index 35e3f782d1..69098a630c 100644
--- a/crates/ra_ide/src/inlay_hints.rs
+++ b/crates/ra_ide/src/inlay_hints.rs
@@ -5,7 +5,7 @@ use ra_ide_db::RootDatabase;
 use ra_prof::profile;
 use ra_syntax::{
     ast::{self, ArgListOwner, AstNode, TypeAscriptionOwner},
-    match_ast, SmolStr, SyntaxNode, TextRange,
+    match_ast, SmolStr, TextRange,
 };
 
 use crate::{FileId, FunctionSignature};
@@ -28,50 +28,76 @@ pub(crate) fn inlay_hints(
     file_id: FileId,
     max_inlay_hint_length: Option<usize>,
 ) -> Vec<InlayHint> {
+    let _p = profile("inlay_hints");
     let sema = Semantics::new(db);
     let file = sema.parse(file_id);
+
     let mut res = Vec::new();
     for node in file.syntax().descendants() {
-        get_inlay_hints(&mut res, &sema, &node, max_inlay_hint_length);
+        match_ast! {
+            match node {
+                ast::CallExpr(it) => { get_param_name_hints(&mut res, &sema, ast::Expr::from(it)); },
+                ast::MethodCallExpr(it) => { get_param_name_hints(&mut res, &sema, ast::Expr::from(it)); },
+                ast::BindPat(it) => { get_bind_pat_hints(&mut res, &sema, max_inlay_hint_length, it); },
+                _ => (),
+            }
+        }
     }
     res
 }
 
-fn get_inlay_hints(
+fn get_param_name_hints(
+    acc: &mut Vec<InlayHint>,
+    sema: &Semantics<RootDatabase>,
+    expr: ast::Expr,
+) -> Option<()> {
+    let args = match &expr {
+        ast::Expr::CallExpr(expr) => expr.arg_list()?.args(),
+        ast::Expr::MethodCallExpr(expr) => expr.arg_list()?.args(),
+        _ => return None,
+    };
+    let args_count = args.clone().count();
+
+    let fn_signature = get_fn_signature(sema, &expr)?;
+    let n_params_to_skip =
+        if fn_signature.has_self_param && fn_signature.parameter_names.len() > args_count {
+            1
+        } else {
+            0
+        };
+    let hints = fn_signature
+        .parameter_names
+        .iter()
+        .skip(n_params_to_skip)
+        .zip(args)
+        .filter(|(param, arg)| should_show_param_hint(&fn_signature, param, &arg))
+        .map(|(param_name, arg)| InlayHint {
+            range: arg.syntax().text_range(),
+            kind: InlayKind::ParameterHint,
+            label: param_name.into(),
+        });
+
+    acc.extend(hints);
+    Some(())
+}
+
+fn get_bind_pat_hints(
     acc: &mut Vec<InlayHint>,
     sema: &Semantics<RootDatabase>,
-    node: &SyntaxNode,
     max_inlay_hint_length: Option<usize>,
+    pat: ast::BindPat,
 ) -> Option<()> {
-    let _p = profile("get_inlay_hints");
-    let db = sema.db;
-    match_ast! {
-        match node {
-            ast::CallExpr(it) => {
-                get_param_name_hints(acc, sema, ast::Expr::from(it));
-            },
-            ast::MethodCallExpr(it) => {
-                get_param_name_hints(acc, sema, ast::Expr::from(it));
-            },
-            ast::BindPat(it) => {
-                let pat = ast::Pat::from(it.clone());
-                let ty = sema.type_of_pat(&pat)?;
-
-                if should_not_display_type_hint(db, &it, &ty) {
-                    return None;
-                }
+    let ty = sema.type_of_pat(&pat.clone().into())?;
 
-                acc.push(
-                    InlayHint {
-                        range: pat.syntax().text_range(),
-                        kind: InlayKind::TypeHint,
-                        label: ty.display_truncated(db, max_inlay_hint_length).to_string().into(),
-                    }
-                );
-            },
-            _ => (),
-        }
-    };
+    if should_not_display_type_hint(sema.db, &pat, &ty) {
+        return None;
+    }
+
+    acc.push(InlayHint {
+        range: pat.syntax().text_range(),
+        kind: InlayKind::TypeHint,
+        label: ty.display_truncated(sema.db, max_inlay_hint_length).to_string().into(),
+    });
     Some(())
 }
 
@@ -120,43 +146,6 @@ fn should_not_display_type_hint(db: &RootDatabase, bind_pat: &ast::BindPat, pat_
     false
 }
 
-fn get_param_name_hints(
-    acc: &mut Vec<InlayHint>,
-    sema: &Semantics<RootDatabase>,
-    expr: ast::Expr,
-) -> Option<()> {
-    let args = match &expr {
-        ast::Expr::CallExpr(expr) => expr.arg_list()?.args(),
-        ast::Expr::MethodCallExpr(expr) => expr.arg_list()?.args(),
-        _ => return None,
-    }
-    .into_iter()
-    // we need args len to determine whether to skip or not the &self parameter
-    .collect::<Vec<_>>();
-
-    let fn_signature = get_fn_signature(sema, &expr)?;
-    let n_params_to_skip =
-        if fn_signature.has_self_param && fn_signature.parameter_names.len() > args.len() {
-            1
-        } else {
-            0
-        };
-    let hints = fn_signature
-        .parameter_names
-        .iter()
-        .skip(n_params_to_skip)
-        .zip(args)
-        .filter(|(param, arg)| should_show_param_hint(&fn_signature, param, &arg))
-        .map(|(param_name, arg)| InlayHint {
-            range: arg.syntax().text_range(),
-            kind: InlayKind::ParameterHint,
-            label: param_name.into(),
-        });
-
-    acc.extend(hints);
-    Some(())
-}
-
 fn should_show_param_hint(
     fn_signature: &FunctionSignature,
     param_name: &str,
diff --git a/crates/ra_syntax/src/ast.rs b/crates/ra_syntax/src/ast.rs
index 9cc7930f74..4a70c712f0 100644
--- a/crates/ra_syntax/src/ast.rs
+++ b/crates/ra_syntax/src/ast.rs
@@ -59,7 +59,7 @@ pub trait AstToken {
 }
 
 /// An iterator over `SyntaxNode` children of a particular AST type.
-#[derive(Debug)]
+#[derive(Debug, Clone)]
 pub struct AstChildren<N> {
     inner: SyntaxNodeChildren,
     ph: PhantomData<N>,


Test patch:
diff --git a/crates/ra_hir_ty/src/tests/method_resolution.rs b/crates/ra_hir_ty/src/tests/method_resolution.rs
index f9b394f059..644d59e17c 100644
--- a/crates/ra_hir_ty/src/tests/method_resolution.rs
+++ b/crates/ra_hir_ty/src/tests/method_resolution.rs
@@ -838,24 +838,6 @@ fn test() { (&S).foo()<|>; }
     assert_eq!(t, "u128");
 }
 
-#[test]
-fn method_resolution_unsize_array() {
-    let t = type_at(
-        r#"
-//- /main.rs
-#[lang = "slice"]
-impl<T> [T] {
-    fn len(&self) -> usize { loop {} }
-}
-fn test() {
-    let a = [1, 2, 3];
-    a.len()<|>;
-}
-"#,
-    );
-    assert_eq!(t, "usize");
-}
-
 #[test]
 fn method_resolution_trait_from_prelude() {
     let (db, pos) = TestDB::with_position(
diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs
index 547010b351..7d796d0b94 100644
--- a/crates/ra_hir_ty/src/tests/traits.rs
+++ b/crates/ra_hir_ty/src/tests/traits.rs
@@ -567,34 +567,6 @@ mod ops {
     assert_eq!("Foo", type_at_pos(&db, pos));
 }
 
-#[test]
-fn infer_ops_index_autoderef() {
-    let (db, pos) = TestDB::with_position(
-        r#"
-//- /main.rs crate:main deps:std
-fn test() {
-    let a = &[1u32, 2, 3];
-    let b = a[1];
-    b<|>;
-}
-
-//- /std.rs crate:std
-impl<T> ops::Index<u32> for [T] {
-    type Output = T;
-}
-
-#[prelude_import] use ops::*;
-mod ops {
-    #[lang = "index"]
-    pub trait Index<Idx> {
-        type Output;
-    }
-}
-"#,
-    );
-    assert_eq!("u32", type_at_pos(&db, pos));
-}
-
 #[test]
 fn deref_trait() {
     let t = type_at(