Repository: rust-analyzer/rust-analyzer (rust)

Issue:
New weekly build crashs reproducily  
I've doing some work on [diesel](https://github.com/diesel-rs/diesel). Pointing with the cursor to [this line](https://github.com/diesel-rs/diesel/blob/be0854094c79ae99ba3c893242a4be358ac0b0c5/diesel/src/query_builder/select_statement/dsl_impls.rs#L359) reproducibly crashes rust-analyzer with the attached backtrace.

Version: rust-analyzer 90f8378
OS: Ubuntu 20.04
IDE: Emacs

```
Backtrace: 
thread '<unnamed>' panicked at 'index out of bounds: the len is 1 but the index is 7', /home/runner/.cargo/git/checkouts/chalk-7b02fa8caa2cec94/28cef6f/chalk-ir/src/fold/subst.rs:56:19
stack backtrace:
   0: <unknown>
   1: <unknown>
   2: <unknown>
   3: <unknown>
   4: <unknown>
   5: <unknown>
   6: <unknown>
   7: <unknown>
   8: <unknown>
   9: <unknown>
  10: <unknown>
  11: <unknown>
  12: <unknown>
  13: <unknown>
  14: <unknown>
  15: <unknown>
  16: <unknown>
  17: <unknown>
  18: <unknown>
  19: <unknown>
  20: <unknown>
  21: <unknown>
  22: <unknown>
  23: <unknown>
  24: <unknown>
  25: <unknown>
  26: <unknown>
  27: <unknown>
  28: <unknown>
  29: <unknown>
  30: <unknown>
  31: <unknown>
  32: <unknown>
  33: <unknown>
  34: <unknown>
  35: <unknown>
  36: <unknown>
  37: <unknown>
  38: <unknown>
  39: <unknown>
  40: <unknown>
  41: <unknown>
  42: <unknown>
  43: <unknown>
  44: <unknown>
  45: <unknown>
  46: <unknown>
  47: <unknown>
  48: <unknown>
  49: <unknown>
  50: <unknown>
  51: <unknown>
  52: <unknown>
  53: <unknown>
  54: <unknown>
  55: <unknown>
  56: <unknown>
  57: <unknown>
  58: <unknown>
  59: <unknown>
  60: <unknown>
  61: <unknown>
  62: <unknown>
  63: <unknown>
  64: <unknown>
  65: <unknown>
  66: <unknown>
  67: <unknown>
  68: <unknown>
  69: <unknown>
  70: <unknown>
  71: <unknown>
  72: <unknown>
  73: <unknown>
  74: <unknown>
  75: <unknown>
  76: <unknown>
  77: <unknown>
  78: <unknown>
  79: <unknown>
  80: <unknown>
  81: <unknown>
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
```

Pull request description:
Fix wrong substitution code
We need to shift in when we're substituting inside a binder.

This should fix #4053 (it doesn't fix the occasional overflow that also occurs on the Diesel codebase though).

Patch:
diff --git a/.vscode/launch.json b/.vscode/launch.json
index 3f74d75666..ca70fb2098 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -11,7 +11,7 @@
   "configurations": [
     {
       // Used for testing the extension with the installed LSP server.
-      "name": "Run Installed Extension",
+      "name": "Run Extension",
       "type": "extensionHost",
       "request": "launch",
       "runtimeExecutable": "${execPath}",
@@ -30,7 +30,7 @@
     },
     {
       // Used for testing the extension with a local build of the LSP server (in `target/debug`).
-      "name": "Run Extension (Debug Build)",
+      "name": "Run Extension (Dev Server)",
       "type": "extensionHost",
       "request": "launch",
       "runtimeExecutable": "${execPath}",
@@ -49,27 +49,6 @@
         "__RA_LSP_SERVER_DEBUG": "${workspaceFolder}/target/debug/rust-analyzer"
       }
     },
-    {
-      // Used for testing the extension with a local build of the LSP server (in `target/release`).
-      "name": "Run Extension (Release Build)",
-      "type": "extensionHost",
-      "request": "launch",
-      "runtimeExecutable": "${execPath}",
-      "args": [
-        "--disable-extensions",
-        "--extensionDevelopmentPath=${workspaceFolder}/editors/code"
-      ],
-      "outFiles": [
-        "${workspaceFolder}/editors/code/out/**/*.js"
-      ],
-      "preLaunchTask": "Build Extension",
-      "skipFiles": [
-        "<node_internals>/**/*.js"
-      ],
-      "env": {
-        "__RA_LSP_SERVER_DEBUG": "${workspaceFolder}/target/release/rust-analyzer"
-      }
-    },
     {
       // Used to attach LLDB to a running LSP server.
       // NOTE: Might require root permissions. For this run:
diff --git a/crates/ra_hir_def/src/nameres/raw.rs b/crates/ra_hir_def/src/nameres/raw.rs
index 39b011ad72..afd538e4ac 100644
--- a/crates/ra_hir_def/src/nameres/raw.rs
+++ b/crates/ra_hir_def/src/nameres/raw.rs
@@ -266,8 +266,8 @@ impl RawItemsCollector {
                 self.add_macro(current_module, it);
                 return;
             }
-            ast::ModuleItem::ExternBlock(it) => {
-                self.add_extern_block(current_module, it);
+            ast::ModuleItem::ExternBlock(_) => {
+                // FIXME: add extern block
                 return;
             }
         };
@@ -278,34 +278,6 @@ impl RawItemsCollector {
         }
     }
 
-    fn add_extern_block(
-        &mut self,
-        current_module: Option<Idx<ModuleData>>,
-        block: ast::ExternBlock,
-    ) {
-        if let Some(items) = block.extern_item_list() {
-            for item in items.extern_items() {
-                let attrs = self.parse_attrs(&item);
-                let visibility =
-                    RawVisibility::from_ast_with_hygiene(item.visibility(), &self.hygiene);
-                let (kind, name) = match item {
-                    ast::ExternItem::FnDef(it) => {
-                        (DefKind::Function(self.source_ast_id_map.ast_id(&it)), it.name())
-                    }
-                    ast::ExternItem::StaticDef(it) => {
-                        (DefKind::Static(self.source_ast_id_map.ast_id(&it)), it.name())
-                    }
-                };
-
-                if let Some(name) = name {
-                    let name = name.as_name();
-                    let def = self.raw_items.defs.alloc(DefData { name, kind, visibility });
-                    self.push_item(current_module, attrs, RawItemKind::Def(def));
-                }
-            }
-        }
-    }
-
     fn add_module(&mut self, current_module: Option<Idx<ModuleData>>, module: ast::Module) {
         let name = match module.name() {
             Some(it) => it.as_name(),
diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs
index a4b8d66837..279c06d65d 100644
--- a/crates/ra_hir_ty/src/lib.rs
+++ b/crates/ra_hir_ty/src/lib.rs
@@ -863,7 +863,7 @@ pub trait TypeWalk {
             &mut |ty, binders| {
                 if let &mut Ty::Bound(bound) = ty {
                     if bound.debruijn >= binders {
-                        *ty = substs.0[bound.index].clone();
+                        *ty = substs.0[bound.index].clone().shift_bound_vars(binders);
                     }
                 }
             },
diff --git a/crates/ra_syntax/src/ptr.rs b/crates/ra_syntax/src/ptr.rs
index ecbfffcf42..3be648c2ae 100644
--- a/crates/ra_syntax/src/ptr.rs
+++ b/crates/ra_syntax/src/ptr.rs
@@ -30,6 +30,10 @@ impl SyntaxNodePtr {
         .unwrap_or_else(|| panic!("can't resolve local ptr to SyntaxNode: {:?}", self))
     }
 
+    pub fn range(&self) -> TextRange {
+        self.range
+    }
+
     pub fn cast<N: AstNode>(self) -> Option<AstPtr<N>> {
         if !N::can_cast(self.kind) {
             return None;
diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs
index 9fa7dad714..d442cbd63e 100644
--- a/crates/rust-analyzer/src/cli/analysis_stats.rs
+++ b/crates/rust-analyzer/src/cli/analysis_stats.rs
@@ -162,13 +162,9 @@ pub fn analysis_stats(
                 let (_, sm) = db.body_with_source_map(f_id.into());
                 let src = sm.expr_syntax(expr_id);
                 if let Ok(src) = src {
-                    let node = {
-                        let root = db.parse_or_expand(src.file_id).unwrap();
-                        src.value.to_node(&root)
-                    };
                     let original_file = src.file_id.original_file(db);
                     let line_index = host.analysis().file_line_index(original_file).unwrap();
-                    let text_range = node.syntax().text_range();
+                    let text_range = src.value.syntax_node_ptr().range();
                     let (start, end) = (
                         line_index.line_col(text_range.start()),
                         line_index.line_col(text_range.end()),
diff --git a/editors/code/package.json b/editors/code/package.json
index b8aaa07d87..ab0f25b2fb 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -166,6 +166,11 @@
                 "command": "rust-analyzer.joinLines",
                 "key": "ctrl+shift+j",
                 "when": "editorTextFocus && editorLangId == rust"
+            },
+            {
+                "command": "rust-analyzer.onEnter",
+                "key": "enter",
+                "when": "editorTextFocus && !suggestWidgetVisible && editorLangId == rust && !vim.active || vim.mode == 'Insert' && editorTextFocus && !suggestWidgetVisible && editorLangId == rust"
             }
         ],
         "configuration": {


Test patch:
diff --git a/crates/ra_hir_def/src/nameres/tests.rs b/crates/ra_hir_def/src/nameres/tests.rs
index 83120fa365..949ca7595f 100644
--- a/crates/ra_hir_def/src/nameres/tests.rs
+++ b/crates/ra_hir_def/src/nameres/tests.rs
@@ -25,7 +25,7 @@ fn compute_crate_def_map(fixture: &str) -> Arc<CrateDefMap> {
 #[test]
 fn crate_def_map_smoke_test() {
     let map = def_map(
-        r"
+        "
         //- /lib.rs
         mod foo;
         struct S;
@@ -45,11 +45,6 @@ fn crate_def_map_smoke_test() {
         }
 
         enum E { V }
-
-        extern {
-            static EXT: u8;
-            fn ext();
-        }
         ",
     );
     assert_snapshot!(map, @r###"
@@ -66,9 +61,7 @@ fn crate_def_map_smoke_test() {
         ⋮crate::foo::bar
         ⋮Baz: t v
         ⋮E: t
-        ⋮EXT: v
         ⋮U: t v
-        ⋮ext: v
     "###)
 }
 
diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs
index 846005baa1..81fc0f63a8 100644
--- a/crates/ra_hir_ty/src/tests.rs
+++ b/crates/ra_hir_ty/src/tests.rs
@@ -18,19 +18,16 @@ use hir_def::{
     nameres::CrateDefMap,
     AssocItemId, DefWithBodyId, LocalModuleId, Lookup, ModuleDefId,
 };
-use hir_expand::{db::AstDatabase, InFile};
+use hir_expand::InFile;
 use insta::assert_snapshot;
 use ra_db::{fixture::WithFixture, salsa::Database, FilePosition, SourceDatabase};
 use ra_syntax::{
     algo,
     ast::{self, AstNode},
-    SyntaxNode,
 };
 use stdx::format_to;
 
-use crate::{
-    db::HirDatabase, display::HirDisplay, infer::TypeMismatch, test_db::TestDB, InferenceResult, Ty,
-};
+use crate::{db::HirDatabase, display::HirDisplay, test_db::TestDB, InferenceResult};
 
 // These tests compare the inference results for all expressions in a file
 // against snapshots of the expected results using insta. Use cargo-insta to
@@ -70,19 +67,13 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String {
 
     let mut infer_def = |inference_result: Arc<InferenceResult>,
                          body_source_map: Arc<BodySourceMap>| {
-        let mut types: Vec<(InFile<SyntaxNode>, &Ty)> = Vec::new();
-        let mut mismatches: Vec<(InFile<SyntaxNode>, &TypeMismatch)> = Vec::new();
+        let mut types = Vec::new();
+        let mut mismatches = Vec::new();
 
         for (pat, ty) in inference_result.type_of_pat.iter() {
             let syntax_ptr = match body_source_map.pat_syntax(pat) {
                 Ok(sp) => {
-                    let root = db.parse_or_expand(sp.file_id).unwrap();
-                    sp.map(|ptr| {
-                        ptr.either(
-                            |it| it.to_node(&root).syntax().clone(),
-                            |it| it.to_node(&root).syntax().clone(),
-                        )
-                    })
+                    sp.map(|ast| ast.either(|it| it.syntax_node_ptr(), |it| it.syntax_node_ptr()))
                 }
                 Err(SyntheticSyntax) => continue,
             };
@@ -90,31 +81,29 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String {
         }
 
         for (expr, ty) in inference_result.type_of_expr.iter() {
-            let node = match body_source_map.expr_syntax(expr) {
-                Ok(sp) => {
-                    let root = db.parse_or_expand(sp.file_id).unwrap();
-                    sp.map(|ptr| ptr.to_node(&root).syntax().clone())
-                }
+            let syntax_ptr = match body_source_map.expr_syntax(expr) {
+                Ok(sp) => sp.map(|ast| ast.syntax_node_ptr()),
                 Err(SyntheticSyntax) => continue,
             };
-            types.push((node.clone(), ty));
+            types.push((syntax_ptr.clone(), ty));
             if let Some(mismatch) = inference_result.type_mismatch_for_expr(expr) {
-                mismatches.push((node, mismatch));
+                mismatches.push((syntax_ptr, mismatch));
             }
         }
 
         // sort ranges for consistency
-        types.sort_by_key(|(node, _)| {
-            let range = node.value.text_range();
-            (range.start(), range.end())
+        types.sort_by_key(|(src_ptr, _)| {
+            (src_ptr.value.range().start(), src_ptr.value.range().end())
         });
-        for (node, ty) in &types {
-            let (range, text) = if let Some(self_param) = ast::SelfParam::cast(node.value.clone()) {
+        for (src_ptr, ty) in &types {
+            let node = src_ptr.value.to_node(&src_ptr.file_syntax(&db));
+
+            let (range, text) = if let Some(self_param) = ast::SelfParam::cast(node.clone()) {
                 (self_param.self_token().unwrap().text_range(), "self".to_string())
             } else {
-                (node.value.text_range(), node.value.text().to_string().replace("\n", " "))
+                (src_ptr.value.range(), node.text().to_string().replace("\n", " "))
             };
-            let macro_prefix = if node.file_id != file_id.into() { "!" } else { "" };
+            let macro_prefix = if src_ptr.file_id != file_id.into() { "!" } else { "" };
             format_to!(
                 buf,
                 "{}{} '{}': {}\n",
@@ -125,12 +114,11 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String {
             );
         }
         if include_mismatches {
-            mismatches.sort_by_key(|(node, _)| {
-                let range = node.value.text_range();
-                (range.start(), range.end())
+            mismatches.sort_by_key(|(src_ptr, _)| {
+                (src_ptr.value.range().start(), src_ptr.value.range().end())
             });
             for (src_ptr, mismatch) in &mismatches {
-                let range = src_ptr.value.text_range();
+                let range = src_ptr.value.range();
                 let macro_prefix = if src_ptr.file_id != file_id.into() { "!" } else { "" };
                 format_to!(
                     buf,
diff --git a/crates/ra_hir_ty/src/tests/regression.rs b/crates/ra_hir_ty/src/tests/regression.rs
index 61284d6722..61a6801fc6 100644
--- a/crates/ra_hir_ty/src/tests/regression.rs
+++ b/crates/ra_hir_ty/src/tests/regression.rs
@@ -533,3 +533,44 @@ fn foo(b: Bar) {
     "###
     );
 }
+
+#[test]
+fn issue_4053_diesel_where_clauses() {
+    assert_snapshot!(
+        infer(r#"
+trait BoxedDsl<DB> {
+    type Output;
+    fn internal_into_boxed(self) -> Self::Output;
+}
+
+struct SelectStatement<From, Select, Distinct, Where, Order, LimitOffset, GroupBy, Locking> {
+    order: Order,
+}
+
+trait QueryFragment<DB: Backend> {}
+
+trait Into<T> { fn into(self) -> T; }
+
+impl<F, S, D, W, O, LOf, DB> BoxedDsl<DB>
+    for SelectStatement<F, S, D, W, O, LOf, G>
+where
+    O: Into<dyn QueryFragment<DB>>,
+{
+    type Output = XXX;
+
+    fn internal_into_boxed(self) -> Self::Output {
+        self.order.into();
+    }
+}
+"#),
+        @r###"
+    [66; 70) 'self': Self
+    [268; 272) 'self': Self
+    [467; 471) 'self': SelectStatement<F, S, D, W, O, LOf, {unknown}, {unknown}>
+    [489; 523) '{     ...     }': ()
+    [499; 503) 'self': SelectStatement<F, S, D, W, O, LOf, {unknown}, {unknown}>
+    [499; 509) 'self.order': O
+    [499; 516) 'self.o...into()': dyn QueryFragment<DB>
+    "###
+    );
+}