Repository: rust-analyzer/rust-analyzer
Pull request #4396 (2020-05-09 19:47:04)

Improve panic message for ast_from_text
Related: #4368


Patch:
diff --git a/Cargo.lock b/Cargo.lock
index 41855f22e8..36cff6402f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -957,6 +957,14 @@ dependencies = [
  "test_utils",
 ]
 
+[[package]]
+name = "ra_env"
+version = "0.1.0"
+dependencies = [
+ "anyhow",
+ "home",
+]
+
 [[package]]
 name = "ra_flycheck"
 version = "0.1.0"
@@ -967,7 +975,7 @@ dependencies = [
  "jod-thread",
  "log",
  "lsp-types",
- "ra_toolchain",
+ "ra_env",
  "serde_json",
 ]
 
@@ -1172,8 +1180,8 @@ dependencies = [
  "ra_arena",
  "ra_cfg",
  "ra_db",
+ "ra_env",
  "ra_proc_macro",
- "ra_toolchain",
  "rustc-hash",
  "serde",
  "serde_json",
@@ -1205,13 +1213,6 @@ dependencies = [
  "text-size",
 ]
 
-[[package]]
-name = "ra_toolchain"
-version = "0.1.0"
-dependencies = [
- "home",
-]
-
 [[package]]
 name = "ra_tt"
 version = "0.1.0"
diff --git a/crates/ra_assists/src/assist_context.rs b/crates/ra_assists/src/assist_context.rs
index a680f752b3..3085c4330c 100644
--- a/crates/ra_assists/src/assist_context.rs
+++ b/crates/ra_assists/src/assist_context.rs
@@ -49,7 +49,7 @@ use crate::{Assist, AssistId, GroupLabel, ResolvedAssist};
 /// easier to just compute the edit eagerly :-)
 pub(crate) struct AssistContext<'a> {
     pub(crate) sema: Semantics<'a, RootDatabase>,
-    pub(crate) db: &'a RootDatabase,
+    pub(super) db: &'a RootDatabase,
     pub(crate) frange: FileRange,
     source_file: SourceFile,
 }
diff --git a/crates/ra_assists/src/handlers/add_explicit_type.rs b/crates/ra_assists/src/handlers/add_explicit_type.rs
index 146cc75df2..55409e5013 100644
--- a/crates/ra_assists/src/handlers/add_explicit_type.rs
+++ b/crates/ra_assists/src/handlers/add_explicit_type.rs
@@ -23,7 +23,6 @@ use crate::{AssistContext, AssistId, Assists};
 // ```
 pub(crate) fn add_explicit_type(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
     let stmt = ctx.find_node_at_offset::<LetStmt>()?;
-    let module = ctx.sema.scope(stmt.syntax()).module()?;
     let expr = stmt.initializer()?;
     let pat = stmt.pat()?;
     // Must be a binding
@@ -58,17 +57,17 @@ pub(crate) fn add_explicit_type(acc: &mut Assists, ctx: &AssistContext) -> Optio
         return None;
     }
 
-    let inferred_type = ty.display_source_code(ctx.db, module.into()).ok()?;
+    let db = ctx.db;
+    let new_type_string = ty.display_truncated(db, None).to_string();
     acc.add(
         AssistId("add_explicit_type"),
-        format!("Insert explicit type '{}'", inferred_type),
+        format!("Insert explicit type '{}'", new_type_string),
         pat_range,
-        |builder| match ascribed_ty {
-            Some(ascribed_ty) => {
-                builder.replace(ascribed_ty.syntax().text_range(), inferred_type);
-            }
-            None => {
-                builder.insert(name_range.end(), format!(": {}", inferred_type));
+        |edit| {
+            if let Some(ascribed_ty) = ascribed_ty {
+                edit.replace(ascribed_ty.syntax().text_range(), new_type_string);
+            } else {
+                edit.insert(name_range.end(), format!(": {}", new_type_string));
             }
         },
     )
@@ -209,7 +208,7 @@ struct Test<K, T = u8> {
 }
 
 fn main() {
-    let test<|>: Test<i32, u8> = Test { t: 23, k: 33 };
+    let test<|>: Test<i32> = Test { t: 23, k: 33 };
 }"#,
         );
     }
diff --git a/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs b/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs
index 6a49b7dbd1..275184e246 100644
--- a/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs
+++ b/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs
@@ -1,5 +1,8 @@
 use ra_ide_db::RootDatabase;
-use ra_syntax::ast::{self, AstNode, NameOwner};
+use ra_syntax::{
+    ast::{self, AstNode, NameOwner},
+    TextSize,
+};
 use stdx::format_to;
 use test_utils::tested_by;
 
@@ -66,6 +69,7 @@ impl From<{0}> for {1} {{
                 variant_name
             );
             edit.insert(start_offset, buf);
+            edit.set_cursor(start_offset + TextSize::of("\n\n"));
         },
     )
 }
@@ -93,20 +97,19 @@ fn existing_from_impl(
 
 #[cfg(test)]
 mod tests {
-    use test_utils::covers;
+    use super::*;
 
     use crate::tests::{check_assist, check_assist_not_applicable};
-
-    use super::*;
+    use test_utils::covers;
 
     #[test]
     fn test_add_from_impl_for_enum() {
         check_assist(
             add_from_impl_for_enum,
             "enum A { <|>One(u32) }",
-            r#"enum A { <|>One(u32) }
+            r#"enum A { One(u32) }
 
-impl From<u32> for A {
+<|>impl From<u32> for A {
     fn from(v: u32) -> Self {
         A::One(v)
     }
@@ -118,10 +121,10 @@ impl From<u32> for A {
     fn test_add_from_impl_for_enum_complicated_path() {
         check_assist(
             add_from_impl_for_enum,
-            r#"enum A { <|>One(foo::bar::baz::Boo) }"#,
-            r#"enum A { <|>One(foo::bar::baz::Boo) }
+            "enum A { <|>One(foo::bar::baz::Boo) }",
+            r#"enum A { One(foo::bar::baz::Boo) }
 
-impl From<foo::bar::baz::Boo> for A {
+<|>impl From<foo::bar::baz::Boo> for A {
     fn from(v: foo::bar::baz::Boo) -> Self {
         A::One(v)
     }
@@ -181,9 +184,9 @@ impl From<String> for A {
 pub trait From<T> {
     fn from(T) -> Self;
 }"#,
-            r#"enum A { <|>One(u32), Two(String), }
+            r#"enum A { One(u32), Two(String), }
 
-impl From<u32> for A {
+<|>impl From<u32> for A {
     fn from(v: u32) -> Self {
         A::One(v)
     }
diff --git a/crates/ra_assists/src/handlers/add_function.rs b/crates/ra_assists/src/handlers/add_function.rs
index de016ae4e1..6b5616aa9c 100644
--- a/crates/ra_assists/src/handlers/add_function.rs
+++ b/crates/ra_assists/src/handlers/add_function.rs
@@ -1,11 +1,7 @@
 use hir::HirDisplay;
 use ra_db::FileId;
 use ra_syntax::{
-    ast::{
-        self,
-        edit::{AstNodeEdit, IndentLevel},
-        ArgListOwner, AstNode, ModuleItemOwner,
-    },
+    ast::{self, edit::IndentLevel, ArgListOwner, AstNode, ModuleItemOwner},
     SyntaxKind, SyntaxNode, TextSize,
 };
 use rustc_hash::{FxHashMap, FxHashSet};
@@ -47,12 +43,16 @@ pub(crate) fn add_function(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
         return None;
     }
 
-    let target_module = match path.qualifier() {
-        Some(qualifier) => match ctx.sema.resolve_path(&qualifier) {
-            Some(hir::PathResolution::Def(hir::ModuleDef::Module(module))) => Some(module),
-            _ => return None,
-        },
-        None => None,
+    let target_module = if let Some(qualifier) = path.qualifier() {
+        if let Some(hir::PathResolution::Def(hir::ModuleDef::Module(module))) =
+            ctx.sema.resolve_path(&qualifier)
+        {
+            Some(module.definition_source(ctx.sema.db))
+        } else {
+            return None;
+        }
+    } else {
+        None
     };
 
     let function_builder = FunctionBuilder::from_call(&ctx, &call, &path, target_module)?;
@@ -83,29 +83,25 @@ struct FunctionBuilder {
 }
 
 impl FunctionBuilder {
-    /// Prepares a generated function that matches `call`.
-    /// The function is generated in `target_module` or next to `call`
+    /// Prepares a generated function that matches `call` in `generate_in`
+    /// (or as close to `call` as possible, if `generate_in` is `None`)
     fn from_call(
         ctx: &AssistContext,
         call: &ast::CallExpr,
         path: &ast::Path,
-        target_module: Option<hir::Module>,
+        target_module: Option<hir::InFile<hir::ModuleSource>>,
     ) -> Option<Self> {
+        let needs_pub = target_module.is_some();
         let mut file = ctx.frange.file_id;
-        let target = match &target_module {
-            Some(target_module) => {
-                let module_source = target_module.definition_source(ctx.db);
-                let (in_file, target) = next_space_for_fn_in_module(ctx.sema.db, &module_source)?;
-                file = in_file;
-                target
-            }
-            None => next_space_for_fn_after_call_site(&call)?,
+        let target = if let Some(target_module) = target_module {
+            let (in_file, target) = next_space_for_fn_in_module(ctx.sema.db, target_module)?;
+            file = in_file;
+            target
+        } else {
+            next_space_for_fn_after_call_site(&call)?
         };
-        let needs_pub = target_module.is_some();
-        let target_module = target_module.or_else(|| ctx.sema.scope(target.syntax()).module())?;
         let fn_name = fn_name(&path)?;
-        let (type_params, params) = fn_args(ctx, target_module, &call)?;
-
+        let (type_params, params) = fn_args(ctx, &call)?;
         Some(Self { target, fn_name, type_params, params, file, needs_pub })
     }
 
@@ -120,16 +116,17 @@ impl FunctionBuilder {
         let (fn_def, insert_offset) = match self.target {
             GeneratedFunctionTarget::BehindItem(it) => {
                 let with_leading_blank_line = ast::make::add_leading_newlines(2, fn_def);
-                let indented = with_leading_blank_line.indent(IndentLevel::from_node(&it));
+                let indented = IndentLevel::from_node(&it).increase_indent(with_leading_blank_line);
                 (indented, it.text_range().end())
             }
             GeneratedFunctionTarget::InEmptyItemList(it) => {
                 let indent_once = IndentLevel(1);
                 let indent = IndentLevel::from_node(it.syntax());
+
                 let fn_def = ast::make::add_leading_newlines(1, fn_def);
-                let fn_def = fn_def.indent(indent_once);
+                let fn_def = indent_once.increase_indent(fn_def);
                 let fn_def = ast::make::add_trailing_newlines(1, fn_def);
-                let fn_def = fn_def.indent(indent);
+                let fn_def = indent.increase_indent(fn_def);
                 (fn_def, it.syntax().text_range().start() + TextSize::of('{'))
             }
         };
@@ -147,15 +144,6 @@ enum GeneratedFunctionTarget {
     InEmptyItemList(ast::ItemList),
 }
 
-impl GeneratedFunctionTarget {
-    fn syntax(&self) -> &SyntaxNode {
-        match self {
-            GeneratedFunctionTarget::BehindItem(it) => it,
-            GeneratedFunctionTarget::InEmptyItemList(it) => it.syntax(),
-        }
-    }
-}
-
 fn fn_name(call: &ast::Path) -> Option<ast::Name> {
     let name = call.segment()?.syntax().to_string();
     Some(ast::make::name(&name))
@@ -164,17 +152,17 @@ fn fn_name(call: &ast::Path) -> Option<ast::Name> {
 /// Computes the type variables and arguments required for the generated function
 fn fn_args(
     ctx: &AssistContext,
-    target_module: hir::Module,
     call: &ast::CallExpr,
 ) -> Option<(Option<ast::TypeParamList>, ast::ParamList)> {
     let mut arg_names = Vec::new();
     let mut arg_types = Vec::new();
     for arg in call.arg_list()?.args() {
-        arg_names.push(match fn_arg_name(&arg) {
+        let arg_name = match fn_arg_name(&arg) {
             Some(name) => name,
             None => String::from("arg"),
-        });
-        arg_types.push(match fn_arg_type(ctx, target_module, &arg) {
+        };
+        arg_names.push(arg_name);
+        arg_types.push(match fn_arg_type(ctx, &arg) {
             Some(ty) => ty,
             None => String::from("()"),
         });
@@ -230,21 +218,12 @@ fn fn_arg_name(fn_arg: &ast::Expr) -> Option<String> {
     }
 }
 
-fn fn_arg_type(
-    ctx: &AssistContext,
-    target_module: hir::Module,
-    fn_arg: &ast::Expr,
-) -> Option<String> {
+fn fn_arg_type(ctx: &AssistContext, fn_arg: &ast::Expr) -> Option<String> {
     let ty = ctx.sema.type_of_expr(fn_arg)?;
     if ty.is_unknown() {
         return None;
     }
-
-    if let Ok(rendered) = ty.display_source_code(ctx.db, target_module.into()) {
-        Some(rendered)
-    } else {
-        None
-    }
+    Some(ty.display(ctx.sema.db).to_string())
 }
 
 /// Returns the position inside the current mod or file
@@ -273,10 +252,10 @@ fn next_space_for_fn_after_call_site(expr: &ast::CallExpr) -> Option<GeneratedFu
 
 fn next_space_for_fn_in_module(
     db: &dyn hir::db::AstDatabase,
-    module_source: &hir::InFile<hir::ModuleSource>,
+    module: hir::InFile<hir::ModuleSource>,
 ) -> Option<(FileId, GeneratedFunctionTarget)> {
-    let file = module_source.file_id.original_file(db);
-    let assist_item = match &module_source.value {
+    let file = module.file_id.original_file(db);
+    let assist_item = match module.value {
         hir::ModuleSource::SourceFile(it) => {
             if let Some(last_item) = it.items().last() {
                 GeneratedFunctionTarget::BehindItem(last_item.syntax().clone())
@@ -620,33 +599,8 @@ fn bar(foo: impl Foo) {
     }
 
     #[test]
-    fn borrowed_arg() {
-        check_assist(
-            add_function,
-            r"
-struct Baz;
-fn baz() -> Baz { todo!() }
-
-fn foo() {
-    bar<|>(&baz())
-}
-",
-            r"
-struct Baz;
-fn baz() -> Baz { todo!() }
-
-fn foo() {
-    bar(&baz())
-}
-
-fn bar(baz: &Baz) {
-    <|>todo!()
-}
-",
-        )
-    }
-
-    #[test]
+    #[ignore]
+    // FIXME print paths properly to make this test pass
     fn add_function_with_qualified_path_arg() {
         check_assist(
             add_function,
@@ -655,8 +609,10 @@ mod Baz {
     pub struct Bof;
     pub fn baz() -> Bof { Bof }
 }
-fn foo() {
-    <|>bar(Baz::baz())
+mod Foo {
+    fn foo() {
+        <|>bar(super::Baz::baz())
+    }
 }
 ",
             r"
@@ -664,12 +620,14 @@ mod Baz {
     pub struct Bof;
     pub fn baz() -> Bof { Bof }
 }
-fn foo() {
-    bar(Baz::baz())
-}
+mod Foo {
+    fn foo() {
+        bar(super::Baz::baz())
+    }
 
-fn bar(baz: Baz::Bof) {
-    <|>todo!()
+    fn bar(baz: super::Baz::Bof) {
+        <|>todo!()
+    }
 }
 ",
         )
@@ -850,40 +808,6 @@ fn foo() {
         )
     }
 
-    #[test]
-    #[ignore]
-    // Ignored until local imports are supported.
-    // See https://github.com/rust-analyzer/rust-analyzer/issues/1165
-    fn qualified_path_uses_correct_scope() {
-        check_assist(
-            add_function,
-            "
-mod foo {
-    pub struct Foo;
-}
-fn bar() {
-    use foo::Foo;
-    let foo = Foo;
-    baz<|>(foo)
-}
-",
-            "
-mod foo {
-    pub struct Foo;
-}
-fn bar() {
-    use foo::Foo;
-    let foo = Foo;
-    baz(foo)
-}
-
-fn baz(foo: foo::Foo) {
-    <|>todo!()
-}
-",
-        )
-    }
-
     #[test]
     fn add_function_in_module_containing_other_items() {
         check_assist(
@@ -995,6 +919,21 @@ fn bar(baz: ()) {}
         )
     }
 
+    #[test]
+    fn add_function_not_applicable_if_function_path_not_singleton() {
+        // In the future this assist could be extended to generate functions
+        // if the path is in the same crate (or even the same workspace).
+        // For the beginning, I think this is fine.
+        check_assist_not_applicable(
+            add_function,
+            r"
+fn foo() {
+    other_crate::bar<|>();
+}
+        ",
+        )
+    }
+
     #[test]
     #[ignore]
     fn create_method_with_no_args() {
diff --git a/crates/ra_assists/src/handlers/add_missing_impl_members.rs b/crates/ra_assists/src/handlers/add_missing_impl_members.rs
index c1ce87914a..3482a75bfc 100644
--- a/crates/ra_assists/src/handlers/add_missing_impl_members.rs
+++ b/crates/ra_assists/src/handlers/add_missing_impl_members.rs
@@ -2,7 +2,7 @@ use hir::HasSource;
 use ra_syntax::{
     ast::{
         self,
-        edit::{self, AstNodeEdit, IndentLevel},
+        edit::{self, IndentLevel},
         make, AstNode, NameOwner,
     },
     SmolStr,
@@ -176,7 +176,8 @@ fn add_body(fn_def: ast::FnDef) -> ast::FnDef {
     if fn_def.body().is_some() {
         return fn_def;
     }
-    let body = make::block_expr(None, Some(make::expr_todo())).indent(IndentLevel(1));
+    let body = make::block_expr(None, Some(make::expr_todo()));
+    let body = IndentLevel(1).increase_indent(body);
     fn_def.with_body(body)
 }
 
diff --git a/crates/ra_assists/src/handlers/early_return.rs b/crates/ra_assists/src/handlers/early_return.rs
index 66b296081d..810784ad57 100644
--- a/crates/ra_assists/src/handlers/early_return.rs
+++ b/crates/ra_assists/src/handlers/early_return.rs
@@ -2,11 +2,7 @@ use std::{iter::once, ops::RangeInclusive};
 
 use ra_syntax::{
     algo::replace_children,
-    ast::{
-        self,
-        edit::{AstNodeEdit, IndentLevel},
-        make,
-    },
+    ast::{self, edit::IndentLevel, make},
     AstNode,
     SyntaxKind::{FN_DEF, LOOP_EXPR, L_CURLY, R_CURLY, WHILE_EXPR, WHITESPACE},
     SyntaxNode,
@@ -109,7 +105,8 @@ pub(crate) fn convert_to_guarded_return(acc: &mut Assists, ctx: &AssistContext)
                     let then_branch =
                         make::block_expr(once(make::expr_stmt(early_expression).into()), None);
                     let cond = invert_boolean_expression(cond_expr);
-                    make::expr_if(make::condition(cond, None), then_branch).indent(if_indent_level)
+                    let e = make::expr_if(make::condition(cond, None), then_branch);
+                    if_indent_level.increase_indent(e)
                 };
                 replace(new_expr.syntax(), &then_block, &parent_block, &if_expr)
             }
@@ -143,7 +140,7 @@ pub(crate) fn convert_to_guarded_return(acc: &mut Assists, ctx: &AssistContext)
                     make::bind_pat(make::name(&bound_ident.syntax().to_string())).into(),
                     Some(match_expr),
                 );
-                let let_stmt = let_stmt.indent(if_indent_level);
+                let let_stmt = if_indent_level.increase_indent(let_stmt);
                 replace(let_stmt.syntax(), &then_block, &parent_block, &if_expr)
             }
         };
@@ -156,7 +153,7 @@ pub(crate) fn convert_to_guarded_return(acc: &mut Assists, ctx: &AssistContext)
             parent_block: &ast::BlockExpr,
             if_expr: &ast::IfExpr,
         ) -> SyntaxNode {
-            let then_block_items = then_block.dedent(IndentLevel::from(1));
+            let then_block_items = IndentLevel::from(1).decrease_indent(then_block.clone());
             let end_of_then = then_block_items.syntax().last_child_or_token().unwrap();
             let end_of_then =
                 if end_of_then.prev_sibling_or_token().map(|n| n.kind()) == Some(WHITESPACE) {
diff --git a/crates/ra_assists/src/handlers/replace_if_let_with_match.rs b/crates/ra_assists/src/handlers/replace_if_let_with_match.rs
index 65f5fc6abe..a59a06efa5 100644
--- a/crates/ra_assists/src/handlers/replace_if_let_with_match.rs
+++ b/crates/ra_assists/src/handlers/replace_if_let_with_match.rs
@@ -1,10 +1,6 @@
 use ra_fmt::unwrap_trivial_block;
 use ra_syntax::{
-    ast::{
-        self,
-        edit::{AstNodeEdit, IndentLevel},
-        make,
-    },
+    ast::{self, edit::IndentLevel, make},
     AstNode,
 };
 
@@ -65,9 +61,10 @@ pub(crate) fn replace_if_let_with_match(acc: &mut Assists, ctx: &AssistContext)
                 make::match_arm(vec![pattern], else_expr)
             };
             make::expr_match(expr, make::match_arm_list(vec![then_arm, else_arm]))
-                .indent(IndentLevel::from_node(if_expr.syntax()))
         };
 
+        let match_expr = IndentLevel::from_node(if_expr.syntax()).increase_indent(match_expr);
+
         edit.set_cursor(if_expr.syntax().text_range().start());
         edit.replace_ast::<ast::Expr>(if_expr.into(), match_expr);
     })
diff --git a/crates/ra_assists/src/handlers/replace_let_with_if_let.rs b/crates/ra_assists/src/handlers/replace_let_with_if_let.rs
index 482957dc60..d3f214591a 100644
--- a/crates/ra_assists/src/handlers/replace_let_with_if_let.rs
+++ b/crates/ra_assists/src/handlers/replace_let_with_if_let.rs
@@ -53,7 +53,8 @@ pub(crate) fn replace_let_with_if_let(acc: &mut Assists, ctx: &AssistContext) ->
             )
             .into(),
         };
-        let block = make::block_expr(None, None).indent(IndentLevel::from_node(let_stmt.syntax()));
+        let block =
+            IndentLevel::from_node(let_stmt.syntax()).increase_indent(make::block_expr(None, None));
         let if_ = make::expr_if(make::condition(init, Some(with_placeholder)), block);
         let stmt = make::expr_stmt(if_);
 
diff --git a/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs b/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs
index c4b56f6e90..a46998b8eb 100644
--- a/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs
+++ b/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs
@@ -1,11 +1,7 @@
 use std::iter;
 
 use ra_syntax::{
-    ast::{
-        self,
-        edit::{AstNodeEdit, IndentLevel},
-        make,
-    },
+    ast::{self, edit::IndentLevel, make},
     AstNode,
 };
 
@@ -55,8 +51,8 @@ pub(crate) fn replace_unwrap_with_match(acc: &mut Assists, ctx: &AssistContext)
         let err_arm = make::match_arm(iter::once(make::placeholder_pat().into()), unreachable_call);
 
         let match_arm_list = make::match_arm_list(vec![ok_arm, err_arm]);
-        let match_expr = make::expr_match(caller.clone(), match_arm_list)
-            .indent(IndentLevel::from_node(method_call.syntax()));
+        let match_expr = make::expr_match(caller.clone(), match_arm_list);
+        let match_expr = IndentLevel::from_node(method_call.syntax()).increase_indent(match_expr);
 
         edit.set_cursor(caller.syntax().text_range().start());
         edit.replace_ast::<ast::Expr>(method_call.into(), match_expr);
diff --git a/crates/ra_toolchain/Cargo.toml b/crates/ra_env/Cargo.toml
similarity index 77%
rename from crates/ra_toolchain/Cargo.toml
rename to crates/ra_env/Cargo.toml
index 1873fbe167..f0a401be53 100644
--- a/crates/ra_toolchain/Cargo.toml
+++ b/crates/ra_env/Cargo.toml
@@ -1,8 +1,9 @@
 [package]
 edition = "2018"
-name = "ra_toolchain"
+name = "ra_env"
 version = "0.1.0"
 authors = ["rust-analyzer developers"]
 
 [dependencies]
+anyhow = "1.0.26"
 home = "0.5.3"
diff --git a/crates/ra_env/src/lib.rs b/crates/ra_env/src/lib.rs
new file mode 100644
index 0000000000..413da19827
--- /dev/null
+++ b/crates/ra_env/src/lib.rs
@@ -0,0 +1,66 @@
+//! This crate contains a single public function
+//! [`get_path_for_executable`](fn.get_path_for_executable.html).
+//! See docs there for more information.
+
+use anyhow::{bail, Result};
+use std::env;
+use std::path::{Path, PathBuf};
+use std::process::Command;
+
+/// Return a `PathBuf` to use for the given executable.
+///
+/// E.g., `get_path_for_executable("cargo")` may return just `cargo` if that
+/// gives a valid Cargo executable; or it may return a full path to a valid
+/// Cargo.
+pub fn get_path_for_executable(executable_name: impl AsRef<str>) -> Result<PathBuf> {
+    // The current implementation checks three places for an executable to use:
+    // 1) Appropriate environment variable (erroring if this is set but not a usable executable)
+    //      example: for cargo, this checks $CARGO environment variable; for rustc, $RUSTC; etc
+    // 2) `<executable_name>`
+    //      example: for cargo, this tries just `cargo`, which will succeed if `cargo` is on the $PATH
+    // 3) `~/.cargo/bin/<executable_name>`
+    //      example: for cargo, this tries ~/.cargo/bin/cargo
+    //      It seems that this is a reasonable place to try for cargo, rustc, and rustup
+    let executable_name = executable_name.as_ref();
+    let env_var = executable_name.to_ascii_uppercase();
+    if let Ok(path) = env::var(&env_var) {
+        if is_valid_executable(&path) {
+            Ok(path.into())
+        } else {
+            bail!(
+                "`{}` environment variable points to something that's not a valid executable",
+                env_var
+            )
+        }
+    } else {
+        if is_valid_executable(executable_name) {
+            return Ok(executable_name.into());
+        }
+        if let Some(mut path) = ::home::home_dir() {
+            path.push(".cargo");
+            path.push("bin");
+            path.push(executable_name);
+            if is_valid_executable(&path) {
+                return Ok(path);
+            }
+        }
+        // This error message may also be caused by $PATH or $CARGO/$RUSTC/etc not being set correctly
+        // for VSCode, even if they are set correctly in a terminal.
+        // On macOS in particular, launching VSCode from terminal with `code <dirname>` causes VSCode
+        // to inherit environment variables including $PATH, $CARGO, $RUSTC, etc from that terminal;
+        // but launching VSCode from Dock does not inherit environment variables from a terminal.
+        // For more discussion, see #3118.
+        bail!(
+            "Failed to find `{}` executable. Make sure `{}` is in `$PATH`, or set `${}` to point to a valid executable.",
+            executable_name, executable_name, env_var
+        )
+    }
+}
+
+/// Does the given `Path` point to a usable executable?
+///
+/// (assumes the executable takes a `--version` switch and writes to stdout,
+/// which is true for `cargo`, `rustc`, and `rustup`)
+fn is_valid_executable(p: impl AsRef<Path>) -> bool {
+    Command::new(p.as_ref()).arg("--version").output().is_ok()
+}
diff --git a/crates/ra_flycheck/Cargo.toml b/crates/ra_flycheck/Cargo.toml
index 03e5571484..d0f7fb2dcf 100644
--- a/crates/ra_flycheck/Cargo.toml
+++ b/crates/ra_flycheck/Cargo.toml
@@ -14,7 +14,7 @@ log = "0.4.8"
 cargo_metadata = "0.9.1"
 serde_json = "1.0.48"
 jod-thread = "0.1.1"
-ra_toolchain = { path = "../ra_toolchain" }
+ra_env = { path = "../ra_env" }
 
 [dev-dependencies]
 insta = "0.16.0"
diff --git a/crates/ra_flycheck/src/lib.rs b/crates/ra_flycheck/src/lib.rs
index 68dcee2851..d8b727b0ea 100644
--- a/crates/ra_flycheck/src/lib.rs
+++ b/crates/ra_flycheck/src/lib.rs
@@ -16,6 +16,7 @@ use lsp_types::{
     CodeAction, CodeActionOrCommand, Diagnostic, Url, WorkDoneProgress, WorkDoneProgressBegin,
     WorkDoneProgressEnd, WorkDoneProgressReport,
 };
+use ra_env::get_path_for_executable;
 
 use crate::conv::{map_rust_diagnostic_to_lsp, MappedRustDiagnostic};
 
@@ -215,10 +216,10 @@ impl FlycheckThread {
 
         let mut cmd = match &self.config {
             FlycheckConfig::CargoCommand { command, all_targets, all_features, extra_args } => {
-                let mut cmd = Command::new(ra_toolchain::cargo());
+                let mut cmd = Command::new(get_path_for_executable("cargo").unwrap());
                 cmd.arg(command);
-                cmd.args(&["--workspace", "--message-format=json", "--manifest-path"])
-                    .arg(self.workspace_root.join("Cargo.toml"));
+                cmd.args(&["--workspace", "--message-format=json", "--manifest-path"]);
+                cmd.arg(self.workspace_root.join("Cargo.toml"));
                 if *all_targets {
                     cmd.arg("--all-targets");
                 }
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
index be18c845c6..5f480c3040 100644
--- a/crates/ra_hir/src/code_model.rs
+++ b/crates/ra_hir/src/code_model.rs
@@ -22,11 +22,8 @@ use hir_expand::{
     MacroDefId, MacroDefKind,
 };
 use hir_ty::{
-    autoderef,
-    display::{HirDisplayError, HirFormatter},
-    expr::ExprValidator,
-    method_resolution, ApplicationTy, Canonical, InEnvironment, Substs, TraitEnvironment, Ty,
-    TyDefId, TypeCtor,
+    autoderef, display::HirFormatter, expr::ExprValidator, method_resolution, ApplicationTy,
+    Canonical, InEnvironment, Substs, TraitEnvironment, Ty, TyDefId, TypeCtor,
 };
 use ra_db::{CrateId, CrateName, Edition, FileId};
 use ra_prof::profile;
@@ -1322,7 +1319,7 @@ impl Type {
 }
 
 impl HirDisplay for Type {
-    fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
+    fn hir_fmt(&self, f: &mut HirFormatter) -> std::fmt::Result {
         self.ty.value.hir_fmt(f)
     }
 }
diff --git a/crates/ra_hir_ty/src/diagnostics.rs b/crates/ra_hir_ty/src/diagnostics.rs
index 41ac702724..c8fd548615 100644
--- a/crates/ra_hir_ty/src/diagnostics.rs
+++ b/crates/ra_hir_ty/src/diagnostics.rs
@@ -131,31 +131,3 @@ impl AstDiagnostic for MissingOkInTailExpr {
         ast::Expr::cast(node).unwrap()
     }
 }
-
-#[derive(Debug)]
-pub struct BreakOutsideOfLoop {
-    pub file: HirFileId,
-    pub expr: AstPtr<ast::Expr>,
-}
-
-impl Diagnostic for BreakOutsideOfLoop {
-    fn message(&self) -> String {
-        "break outside of loop".to_string()
-    }
-    fn source(&self) -> InFile<SyntaxNodePtr> {
-        InFile { file_id: self.file, value: self.expr.clone().into() }
-    }
-    fn as_any(&self) -> &(dyn Any + Send + 'static) {
-        self
-    }
-}
-
-impl AstDiagnostic for BreakOutsideOfLoop {
-    type AST = ast::Expr;
-
-    fn ast(&self, db: &impl AstDatabase) -> Self::AST {
-        let root = db.parse_or_expand(self.file).unwrap();
-        let node = self.source().value.to_node(&root);
-        ast::Expr::cast(node).unwrap()
-    }
-}
diff --git a/crates/ra_hir_ty/src/display.rs b/crates/ra_hir_ty/src/display.rs
index f5edaea8c8..d03bbd5a7b 100644
--- a/crates/ra_hir_ty/src/display.rs
+++ b/crates/ra_hir_ty/src/display.rs
@@ -6,42 +6,28 @@ use crate::{
     db::HirDatabase, utils::generics, ApplicationTy, CallableDef, FnSig, GenericPredicate,
     Obligation, ProjectionTy, Substs, TraitRef, Ty, TypeCtor,
 };
-use hir_def::{
-    find_path, generics::TypeParamProvenance, item_scope::ItemInNs, AdtId, AssocContainerId,
-    Lookup, ModuleId,
-};
+use hir_def::{generics::TypeParamProvenance, AdtId, AssocContainerId, Lookup};
 use hir_expand::name::Name;
 
-pub struct HirFormatter<'a> {
+pub struct HirFormatter<'a, 'b> {
     pub db: &'a dyn HirDatabase,
-    fmt: &'a mut dyn fmt::Write,
+    fmt: &'a mut fmt::Formatter<'b>,
     buf: String,
     curr_size: usize,
     pub(crate) max_size: Option<usize>,
     omit_verbose_types: bool,
-    display_target: DisplayTarget,
 }
 
 pub trait HirDisplay {
-    fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError>;
+    fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result;
 
-    /// Returns a `Display`able type that is human-readable.
-    /// Use this for showing types to the user (e.g. diagnostics)
     fn display<'a>(&'a self, db: &'a dyn HirDatabase) -> HirDisplayWrapper<'a, Self>
     where
         Self: Sized,
     {
-        HirDisplayWrapper {
-            db,
-            t: self,
-            max_size: None,
-            omit_verbose_types: false,
-            display_target: DisplayTarget::Diagnostics,
-        }
+        HirDisplayWrapper(db, self, None, false)
     }
 
-    /// Returns a `Display`able type that is human-readable and tries to be succinct.
-    /// Use this for showing types to the user where space is constrained (e.g. doc popups)
     fn display_truncated<'a>(
         &'a self,
         db: &'a dyn HirDatabase,
@@ -50,46 +36,16 @@ pub trait HirDisplay {
     where
         Self: Sized,
     {
-        HirDisplayWrapper {
-            db,
-            t: self,
-            max_size,
-            omit_verbose_types: true,
-            display_target: DisplayTarget::Diagnostics,
-        }
-    }
-
-    /// Returns a String representation of `self` that can be inserted into the given module.
-    /// Use this when generating code (e.g. assists)
-    fn display_source_code<'a>(
-        &'a self,
-        db: &'a dyn HirDatabase,
-        module_id: ModuleId,
-    ) -> Result<String, DisplaySourceCodeError> {
-        let mut result = String::new();
-        match self.hir_fmt(&mut HirFormatter {
-            db,
-            fmt: &mut result,
-            buf: String::with_capacity(20),
-            curr_size: 0,
-            max_size: None,
-            omit_verbose_types: false,
-            display_target: DisplayTarget::SourceCode { module_id },
-        }) {
-            Ok(()) => {}
-            Err(HirDisplayError::FmtError) => panic!("Writing to String can't fail!"),
-            Err(HirDisplayError::DisplaySourceCodeError(e)) => return Err(e),
-        };
-        Ok(result)
+        HirDisplayWrapper(db, self, max_size, true)
     }
 }
 
-impl<'a> HirFormatter<'a> {
+impl<'a, 'b> HirFormatter<'a, 'b> {
     pub fn write_joined<T: HirDisplay>(
         &mut self,
         iter: impl IntoIterator<Item = T>,
         sep: &str,
-    ) -> Result<(), HirDisplayError> {
+    ) -> fmt::Result {
         let mut first = true;
         for e in iter {
             if !first {
@@ -102,14 +58,14 @@ impl<'a> HirFormatter<'a> {
     }
 
     /// This allows using the `write!` macro directly with a `HirFormatter`.
-    pub fn write_fmt(&mut self, args: fmt::Arguments) -> Result<(), HirDisplayError> {
+    pub fn write_fmt(&mut self, args: fmt::Arguments) -> fmt::Result {
         // We write to a buffer first to track output size
         self.buf.clear();
         fmt::write(&mut self.buf, args)?;
         self.curr_size += self.buf.len();
 
         // Then we write to the internal formatter from the buffer
-        self.fmt.write_str(&self.buf).map_err(HirDisplayError::from)
+        self.fmt.write_str(&self.buf)
     }
 
     pub fn should_truncate(&self) -> bool {
@@ -125,76 +81,34 @@ impl<'a> HirFormatter<'a> {
     }
 }
 
-#[derive(Clone, Copy)]
-enum DisplayTarget {
-    /// Display types for inlays, doc popups, autocompletion, etc...
-    /// Showing `{unknown}` or not qualifying paths is fine here.
-    /// There's no reason for this to fail.
-    Diagnostics,
-    /// Display types for inserting them in source files.
-    /// The generated code should compile, so paths need to be qualified.
-    SourceCode { module_id: ModuleId },
-}
-
-#[derive(Debug)]
-pub enum DisplaySourceCodeError {
-    PathNotFound,
-}
-
-pub enum HirDisplayError {
-    /// Errors that can occur when generating source code
-    DisplaySourceCodeError(DisplaySourceCodeError),
-    /// `FmtError` is required to be compatible with std::fmt::Display
-    FmtError,
-}
-impl From<fmt::Error> for HirDisplayError {
-    fn from(_: fmt::Error) -> Self {
-        Self::FmtError
-    }
-}
-
-pub struct HirDisplayWrapper<'a, T> {
-    db: &'a dyn HirDatabase,
-    t: &'a T,
-    max_size: Option<usize>,
-    omit_verbose_types: bool,
-    display_target: DisplayTarget,
-}
+pub struct HirDisplayWrapper<'a, T>(&'a dyn HirDatabase, &'a T, Option<usize>, bool);
 
 impl<'a, T> fmt::Display for HirDisplayWrapper<'a, T>
 where
     T: HirDisplay,
 {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self.t.hir_fmt(&mut HirFormatter {
-            db: self.db,
+        self.1.hir_fmt(&mut HirFormatter {
+            db: self.0,
             fmt: f,
             buf: String::with_capacity(20),
             curr_size: 0,
-            max_size: self.max_size,
-            omit_verbose_types: self.omit_verbose_types,
-            display_target: self.display_target,
-        }) {
-            Ok(()) => Ok(()),
-            Err(HirDisplayError::FmtError) => Err(fmt::Error),
-            Err(HirDisplayError::DisplaySourceCodeError(_)) => {
-                // This should never happen
-                panic!("HirDisplay failed when calling Display::fmt!")
-            }
-        }
+            max_size: self.2,
+            omit_verbose_types: self.3,
+        })
     }
 }
 
 const TYPE_HINT_TRUNCATION: &str = "…";
 
 impl HirDisplay for &Ty {
-    fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
+    fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result {
         HirDisplay::hir_fmt(*self, f)
     }
 }
 
 impl HirDisplay for ApplicationTy {
-    fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
+    fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result {
         if f.should_truncate() {
             return write!(f, "{}", TYPE_HINT_TRUNCATION);
         }
@@ -277,30 +191,12 @@ impl HirDisplay for ApplicationTy {
                 }
             }
             TypeCtor::Adt(def_id) => {
-                match f.display_target {
-                    DisplayTarget::Diagnostics => {
-                        let name = match def_id {
-                            AdtId::StructId(it) => f.db.struct_data(it).name.clone(),
-                            AdtId::UnionId(it) => f.db.union_data(it).name.clone(),
-                            AdtId::EnumId(it) => f.db.enum_data(it).name.clone(),
-                        };
-                        write!(f, "{}", name)?;
-                    }
-                    DisplayTarget::SourceCode { module_id } => {
-                        if let Some(path) = find_path::find_path(
-                            f.db.upcast(),
-                            ItemInNs::Types(def_id.into()),
-                            module_id,
-                        ) {
-                            write!(f, "{}", path)?;
-                        } else {
-                            return Err(HirDisplayError::DisplaySourceCodeError(
-                                DisplaySourceCodeError::PathNotFound,
-                            ));
-                        }
-                    }
-                }
-
+                let name = match def_id {
+                    AdtId::StructId(it) => f.db.struct_data(it).name.clone(),
+                    AdtId::UnionId(it) => f.db.union_data(it).name.clone(),
+                    AdtId::EnumId(it) => f.db.enum_data(it).name.clone(),
+                };
+                write!(f, "{}", name)?;
                 if self.parameters.len() > 0 {
                     let mut non_default_parameters = Vec::with_capacity(self.parameters.len());
                     let parameters_to_write = if f.omit_verbose_types() {
@@ -373,7 +269,7 @@ impl HirDisplay for ApplicationTy {
 }
 
 impl HirDisplay for ProjectionTy {
-    fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
+    fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result {
         if f.should_truncate() {
             return write!(f, "{}", TYPE_HINT_TRUNCATION);
         }
@@ -391,7 +287,7 @@ impl HirDisplay for ProjectionTy {
 }
 
 impl HirDisplay for Ty {
-    fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
+    fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result {
         if f.should_truncate() {
             return write!(f, "{}", TYPE_HINT_TRUNCATION);
         }
@@ -436,7 +332,7 @@ impl HirDisplay for Ty {
 fn write_bounds_like_dyn_trait(
     predicates: &[GenericPredicate],
     f: &mut HirFormatter,
-) -> Result<(), HirDisplayError> {
+) -> fmt::Result {
     // Note: This code is written to produce nice results (i.e.
     // corresponding to surface Rust) for types that can occur in
     // actual Rust. It will have weird results if the predicates
@@ -498,7 +394,7 @@ fn write_bounds_like_dyn_trait(
 }
 
 impl TraitRef {
-    fn hir_fmt_ext(&self, f: &mut HirFormatter, use_as: bool) -> Result<(), HirDisplayError> {
+    fn hir_fmt_ext(&self, f: &mut HirFormatter, use_as: bool) -> fmt::Result {
         if f.should_truncate() {
             return write!(f, "{}", TYPE_HINT_TRUNCATION);
         }
@@ -520,19 +416,19 @@ impl TraitRef {
 }
 
 impl HirDisplay for TraitRef {
-    fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
+    fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result {
         self.hir_fmt_ext(f, false)
     }
 }
 
 impl HirDisplay for &GenericPredicate {
-    fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
+    fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result {
         HirDisplay::hir_fmt(*self, f)
     }
 }
 
 impl HirDisplay for GenericPredicate {
-    fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
+    fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result {
         if f.should_truncate() {
             return write!(f, "{}", TYPE_HINT_TRUNCATION);
         }
@@ -556,15 +452,15 @@ impl HirDisplay for GenericPredicate {
 }
 
 impl HirDisplay for Obligation {
-    fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
-        Ok(match self {
-            Obligation::Trait(tr) => write!(f, "Implements({})", tr.display(f.db))?,
+    fn hir_fmt(&self, f: &mut HirFormatter) -> fmt::Result {
+        match self {
+            Obligation::Trait(tr) => write!(f, "Implements({})", tr.display(f.db)),
             Obligation::Projection(proj) => write!(
                 f,
                 "Normalize({} => {})",
                 proj.projection_ty.display(f.db),
                 proj.ty.display(f.db)
-            )?,
-        })
+            ),
+        }
     }
 }
diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs
index a21ad8d864..bd4ef69a07 100644
--- a/crates/ra_hir_ty/src/infer.rs
+++ b/crates/ra_hir_ty/src/infer.rs
@@ -210,13 +210,6 @@ struct InferenceContext<'a> {
     /// closures, but currently this is the only field that will change there,
     /// so it doesn't make sense.
     return_ty: Ty,
-    diverges: Diverges,
-    breakables: Vec<BreakableContext>,
-}
-
-#[derive(Clone, Debug)]
-struct BreakableContext {
-    pub may_break: bool,
 }
 
 impl<'a> InferenceContext<'a> {
@@ -231,8 +224,6 @@ impl<'a> InferenceContext<'a> {
             owner,
             body: db.body(owner),
             resolver,
-            diverges: Diverges::Maybe,
-            breakables: Vec::new(),
         }
     }
 
@@ -675,57 +666,15 @@ impl Expectation {
     }
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
-enum Diverges {
-    Maybe,
-    Always,
-}
-
-impl Diverges {
-    fn is_always(self) -> bool {
-        self == Diverges::Always
-    }
-}
-
-impl std::ops::BitAnd for Diverges {
-    type Output = Self;
-    fn bitand(self, other: Self) -> Self {
-        std::cmp::min(self, other)
-    }
-}
-
-impl std::ops::BitOr for Diverges {
-    type Output = Self;
-    fn bitor(self, other: Self) -> Self {
-        std::cmp::max(self, other)
-    }
-}
-
-impl std::ops::BitAndAssign for Diverges {
-    fn bitand_assign(&mut self, other: Self) {
-        *self = *self & other;
-    }
-}
-
-impl std::ops::BitOrAssign for Diverges {
-    fn bitor_assign(&mut self, other: Self) {
-        *self = *self | other;
-    }
-}
-
 mod diagnostics {
     use hir_def::{expr::ExprId, FunctionId};
     use hir_expand::diagnostics::DiagnosticSink;
 
-    use crate::{
-        db::HirDatabase,
-        diagnostics::{BreakOutsideOfLoop, NoSuchField},
-    };
+    use crate::{db::HirDatabase, diagnostics::NoSuchField};
 
     #[derive(Debug, PartialEq, Eq, Clone)]
     pub(super) enum InferenceDiagnostic {
         NoSuchField { expr: ExprId, field: usize },
-        BreakOutsideOfLoop { expr: ExprId },
     }
 
     impl InferenceDiagnostic {
@@ -741,13 +690,6 @@ mod diagnostics {
                     let field = source_map.field_syntax(*expr, *field);
                     sink.push(NoSuchField { file: field.file_id, field: field.value })
                 }
-                InferenceDiagnostic::BreakOutsideOfLoop { expr } => {
-                    let (_, source_map) = db.body_with_source_map(owner.into());
-                    let ptr = source_map
-                        .expr_syntax(*expr)
-                        .expect("break outside of loop in synthetic syntax");
-                    sink.push(BreakOutsideOfLoop { file: ptr.file_id, expr: ptr.value })
-                }
             }
         }
     }
diff --git a/crates/ra_hir_ty/src/infer/coerce.rs b/crates/ra_hir_ty/src/infer/coerce.rs
index 173ec59edf..89200255a2 100644
--- a/crates/ra_hir_ty/src/infer/coerce.rs
+++ b/crates/ra_hir_ty/src/infer/coerce.rs
@@ -20,35 +20,21 @@ impl<'a> InferenceContext<'a> {
         self.coerce_inner(from_ty, &to_ty)
     }
 
-    /// Merge two types from different branches, with possible coercion.
+    /// Merge two types from different branches, with possible implicit coerce.
     ///
-    /// Mostly this means trying to coerce one to the other, but
-    ///  - if we have two function types for different functions, we need to
-    ///    coerce both to function pointers;
-    ///  - if we were concerned with lifetime subtyping, we'd need to look for a
-    ///    least upper bound.
+    /// Note that it is only possible that one type are coerced to another.
+    /// Coercing both types to another least upper bound type is not possible in rustc,
+    /// which will simply result in "incompatible types" error.
     pub(super) fn coerce_merge_branch(&mut self, ty1: &Ty, ty2: &Ty) -> Ty {
         if self.coerce(ty1, ty2) {
             ty2.clone()
         } else if self.coerce(ty2, ty1) {
             ty1.clone()
         } else {
-            if let (ty_app!(TypeCtor::FnDef(_)), ty_app!(TypeCtor::FnDef(_))) = (ty1, ty2) {
-                tested_by!(coerce_fn_reification);
-                // Special case: two function types. Try to coerce both to
-                // pointers to have a chance at getting a match. See
-                // https://github.com/rust-lang/rust/blob/7b805396bf46dce972692a6846ce2ad8481c5f85/src/librustc_typeck/check/coercion.rs#L877-L916
-                let sig1 = ty1.callable_sig(self.db).expect("FnDef without callable sig");
-                let sig2 = ty2.callable_sig(self.db).expect("FnDef without callable sig");
-                let ptr_ty1 = Ty::fn_ptr(sig1);
-                let ptr_ty2 = Ty::fn_ptr(sig2);
-                self.coerce_merge_branch(&ptr_ty1, &ptr_ty2)
-            } else {
-                tested_by!(coerce_merge_fail_fallback);
-                // For incompatible types, we use the latter one as result
-                // to be better recovery for `if` without `else`.
-                ty2.clone()
-            }
+            tested_by!(coerce_merge_fail_fallback);
+            // For incompatible types, we use the latter one as result
+            // to be better recovery for `if` without `else`.
+            ty2.clone()
         }
     }
 
@@ -98,7 +84,9 @@ impl<'a> InferenceContext<'a> {
                 match from_ty.callable_sig(self.db) {
                     None => return false,
                     Some(sig) => {
-                        from_ty = Ty::fn_ptr(sig);
+                        let num_args = sig.params_and_return.len() as u16 - 1;
+                        from_ty =
+                            Ty::apply(TypeCtor::FnPtr { num_args }, Substs(sig.params_and_return));
                     }
                 }
             }
diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs
index 0b67d216a8..83f946eeea 100644
--- a/crates/ra_hir_ty/src/infer/expr.rs
+++ b/crates/ra_hir_ty/src/infer/expr.rs
@@ -1,7 +1,7 @@
 //! Type inference for expressions.
 
 use std::iter::{repeat, repeat_with};
-use std::{mem, sync::Arc};
+use std::sync::Arc;
 
 use hir_def::{
     builtin_type::Signedness,
@@ -21,18 +21,11 @@ use crate::{
     Ty, TypeCtor, Uncertain,
 };
 
-use super::{
-    BindingMode, BreakableContext, Diverges, Expectation, InferenceContext, InferenceDiagnostic,
-    TypeMismatch,
-};
+use super::{BindingMode, Expectation, InferenceContext, InferenceDiagnostic, TypeMismatch};
 
 impl<'a> InferenceContext<'a> {
     pub(super) fn infer_expr(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
         let ty = self.infer_expr_inner(tgt_expr, expected);
-        if ty.is_never() {
-            // Any expression that produces a value of type `!` must have diverged
-            self.diverges = Diverges::Always;
-        }
         let could_unify = self.unify(&ty, &expected.ty);
         if !could_unify {
             self.result.type_mismatches.insert(
@@ -71,18 +64,11 @@ impl<'a> InferenceContext<'a> {
                 // if let is desugared to match, so this is always simple if
                 self.infer_expr(*condition, &Expectation::has_type(Ty::simple(TypeCtor::Bool)));
 
-                let condition_diverges = mem::replace(&mut self.diverges, Diverges::Maybe);
-                let mut both_arms_diverge = Diverges::Always;
-
                 let then_ty = self.infer_expr_inner(*then_branch, &expected);
-                both_arms_diverge &= mem::replace(&mut self.diverges, Diverges::Maybe);
                 let else_ty = match else_branch {
                     Some(else_branch) => self.infer_expr_inner(*else_branch, &expected),
                     None => Ty::unit(),
                 };
-                both_arms_diverge &= self.diverges;
-
-                self.diverges = condition_diverges | both_arms_diverge;
 
                 self.coerce_merge_branch(&then_ty, &else_ty)
             }
@@ -93,43 +79,24 @@ impl<'a> InferenceContext<'a> {
                 Ty::Unknown
             }
             Expr::Loop { body } => {
-                self.breakables.push(BreakableContext { may_break: false });
                 self.infer_expr(*body, &Expectation::has_type(Ty::unit()));
-
-                let ctxt = self.breakables.pop().expect("breakable stack broken");
-                if ctxt.may_break {
-                    self.diverges = Diverges::Maybe;
-                }
                 // FIXME handle break with value
-                if ctxt.may_break {
-                    Ty::unit()
-                } else {
-                    Ty::simple(TypeCtor::Never)
-                }
+                Ty::simple(TypeCtor::Never)
             }
             Expr::While { condition, body } => {
-                self.breakables.push(BreakableContext { may_break: false });
                 // while let is desugared to a match loop, so this is always simple while
                 self.infer_expr(*condition, &Expectation::has_type(Ty::simple(TypeCtor::Bool)));
                 self.infer_expr(*body, &Expectation::has_type(Ty::unit()));
-                let _ctxt = self.breakables.pop().expect("breakable stack broken");
-                // the body may not run, so it diverging doesn't mean we diverge
-                self.diverges = Diverges::Maybe;
                 Ty::unit()
             }
             Expr::For { iterable, body, pat } => {
                 let iterable_ty = self.infer_expr(*iterable, &Expectation::none());
 
-                self.breakables.push(BreakableContext { may_break: false });
                 let pat_ty =
                     self.resolve_associated_type(iterable_ty, self.resolve_into_iter_item());
 
                 self.infer_pat(*pat, &pat_ty, BindingMode::default());
-
                 self.infer_expr(*body, &Expectation::has_type(Ty::unit()));
-                let _ctxt = self.breakables.pop().expect("breakable stack broken");
-                // the body may not run, so it diverging doesn't mean we diverge
-                self.diverges = Diverges::Maybe;
                 Ty::unit()
             }
             Expr::Lambda { body, args, ret_type, arg_types } => {
@@ -165,12 +132,10 @@ impl<'a> InferenceContext<'a> {
                 // infer the body.
                 self.coerce(&closure_ty, &expected.ty);
 
-                let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe);
-                let prev_ret_ty = mem::replace(&mut self.return_ty, ret_ty.clone());
+                let prev_ret_ty = std::mem::replace(&mut self.return_ty, ret_ty.clone());
 
                 self.infer_expr_coerce(*body, &Expectation::has_type(ret_ty));
 
-                self.diverges = prev_diverges;
                 self.return_ty = prev_ret_ty;
 
                 closure_ty
@@ -200,11 +165,7 @@ impl<'a> InferenceContext<'a> {
                     self.table.new_type_var()
                 };
 
-                let matchee_diverges = self.diverges;
-                let mut all_arms_diverge = Diverges::Always;
-
                 for arm in arms {
-                    self.diverges = Diverges::Maybe;
                     let _pat_ty = self.infer_pat(arm.pat, &input_ty, BindingMode::default());
                     if let Some(guard_expr) = arm.guard {
                         self.infer_expr(
@@ -214,12 +175,9 @@ impl<'a> InferenceContext<'a> {
                     }
 
                     let arm_ty = self.infer_expr_inner(arm.expr, &expected);
-                    all_arms_diverge &= self.diverges;
                     result_ty = self.coerce_merge_branch(&result_ty, &arm_ty);
                 }
 
-                self.diverges = matchee_diverges | all_arms_diverge;
-
                 result_ty
             }
             Expr::Path(p) => {
@@ -233,13 +191,6 @@ impl<'a> InferenceContext<'a> {
                     // FIXME handle break with value
                     self.infer_expr(*expr, &Expectation::none());
                 }
-                if let Some(ctxt) = self.breakables.last_mut() {
-                    ctxt.may_break = true;
-                } else {
-                    self.push_diagnostic(InferenceDiagnostic::BreakOutsideOfLoop {
-                        expr: tgt_expr,
-                    });
-                }
                 Ty::simple(TypeCtor::Never)
             }
             Expr::Return { expr } => {
@@ -550,8 +501,8 @@ impl<'a> InferenceContext<'a> {
                 }
                 Literal::ByteString(..) => {
                     let byte_type = Ty::simple(TypeCtor::Int(Uncertain::Known(IntTy::u8())));
-                    let array_type = Ty::apply_one(TypeCtor::Array, byte_type);
-                    Ty::apply_one(TypeCtor::Ref(Mutability::Shared), array_type)
+                    let slice_type = Ty::apply_one(TypeCtor::Slice, byte_type);
+                    Ty::apply_one(TypeCtor::Ref(Mutability::Shared), slice_type)
                 }
                 Literal::Char(..) => Ty::simple(TypeCtor::Char),
                 Literal::Int(_v, ty) => Ty::simple(TypeCtor::Int((*ty).into())),
@@ -571,6 +522,7 @@ impl<'a> InferenceContext<'a> {
         tail: Option<ExprId>,
         expected: &Expectation,
     ) -> Ty {
+        let mut diverges = false;
         for stmt in statements {
             match stmt {
                 Statement::Let { pat, type_ref, initializer } => {
@@ -592,7 +544,9 @@ impl<'a> InferenceContext<'a> {
                     self.infer_pat(*pat, &ty, BindingMode::default());
                 }
                 Statement::Expr(expr) => {
-                    self.infer_expr(*expr, &Expectation::none());
+                    if let ty_app!(TypeCtor::Never) = self.infer_expr(*expr, &Expectation::none()) {
+                        diverges = true;
+                    }
                 }
             }
         }
@@ -600,22 +554,14 @@ impl<'a> InferenceContext<'a> {
         let ty = if let Some(expr) = tail {
             self.infer_expr_coerce(expr, expected)
         } else {
-            // Citing rustc: if there is no explicit tail expression,
-            // that is typically equivalent to a tail expression
-            // of `()` -- except if the block diverges. In that
-            // case, there is no value supplied from the tail
-            // expression (assuming there are no other breaks,
-            // this implies that the type of the block will be
-            // `!`).
-            if self.diverges.is_always() {
-                // we don't even make an attempt at coercion
-                self.table.new_maybe_never_type_var()
-            } else {
-                self.coerce(&Ty::unit(), expected.coercion_target());
-                Ty::unit()
-            }
+            self.coerce(&Ty::unit(), expected.coercion_target());
+            Ty::unit()
         };
-        ty
+        if diverges {
+            Ty::simple(TypeCtor::Never)
+        } else {
+            ty
+        }
     }
 
     fn infer_method_call(
diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs
index e8f3482fe4..a6f56c661e 100644
--- a/crates/ra_hir_ty/src/lib.rs
+++ b/crates/ra_hir_ty/src/lib.rs
@@ -683,12 +683,6 @@ impl Ty {
     pub fn unit() -> Self {
         Ty::apply(TypeCtor::Tuple { cardinality: 0 }, Substs::empty())
     }
-    pub fn fn_ptr(sig: FnSig) -> Self {
-        Ty::apply(
-            TypeCtor::FnPtr { num_args: sig.params().len() as u16 },
-            Substs(sig.params_and_return),
-        )
-    }
 
     pub fn as_reference(&self) -> Option<(&Ty, Mutability)> {
         match self {
@@ -736,10 +730,6 @@ impl Ty {
         }
     }
 
-    pub fn is_never(&self) -> bool {
-        matches!(self, Ty::Apply(ApplicationTy { ctor: TypeCtor::Never, .. }))
-    }
-
     /// If this is a `dyn Trait` type, this returns the `Trait` part.
     pub fn dyn_trait_ref(&self) -> Option<&TraitRef> {
         match self {
diff --git a/crates/ra_hir_ty/src/marks.rs b/crates/ra_hir_ty/src/marks.rs
index a397401434..de5cb1d6bc 100644
--- a/crates/ra_hir_ty/src/marks.rs
+++ b/crates/ra_hir_ty/src/marks.rs
@@ -7,6 +7,5 @@ test_utils::marks!(
     impl_self_type_match_without_receiver
     match_ergonomics_ref
     coerce_merge_fail_fallback
-    coerce_fn_reification
     trait_self_implements_self
 );
diff --git a/crates/ra_project_model/Cargo.toml b/crates/ra_project_model/Cargo.toml
index a32a5daabd..6264784689 100644
--- a/crates/ra_project_model/Cargo.toml
+++ b/crates/ra_project_model/Cargo.toml
@@ -16,7 +16,7 @@ cargo_metadata = "0.9.1"
 ra_arena = { path = "../ra_arena" }
 ra_cfg = { path = "../ra_cfg" }
 ra_db = { path = "../ra_db" }
-ra_toolchain = { path = "../ra_toolchain" }
+ra_env = { path = "../ra_env" }
 ra_proc_macro =  { path = "../ra_proc_macro" }
 
 serde = { version = "1.0.106", features = ["derive"] }
diff --git a/crates/ra_project_model/src/cargo_workspace.rs b/crates/ra_project_model/src/cargo_workspace.rs
index 082af4f969..eb9f33ee89 100644
--- a/crates/ra_project_model/src/cargo_workspace.rs
+++ b/crates/ra_project_model/src/cargo_workspace.rs
@@ -11,6 +11,7 @@ use anyhow::{Context, Result};
 use cargo_metadata::{BuildScript, CargoOpt, Message, MetadataCommand, PackageId};
 use ra_arena::{Arena, Idx};
 use ra_db::Edition;
+use ra_env::get_path_for_executable;
 use rustc_hash::FxHashMap;
 
 /// `CargoWorkspace` represents the logical structure of, well, a Cargo
@@ -146,7 +147,7 @@ impl CargoWorkspace {
         cargo_features: &CargoConfig,
     ) -> Result<CargoWorkspace> {
         let mut meta = MetadataCommand::new();
-        meta.cargo_path(ra_toolchain::cargo());
+        meta.cargo_path(get_path_for_executable("cargo")?);
         meta.manifest_path(cargo_toml);
         if cargo_features.all_features {
             meta.features(CargoOpt::AllFeatures);
@@ -288,7 +289,7 @@ pub fn load_extern_resources(
     cargo_toml: &Path,
     cargo_features: &CargoConfig,
 ) -> Result<ExternResources> {
-    let mut cmd = Command::new(ra_toolchain::cargo());
+    let mut cmd = Command::new(get_path_for_executable("cargo")?);
     cmd.args(&["check", "--message-format=json", "--manifest-path"]).arg(cargo_toml);
     if cargo_features.all_features {
         cmd.arg("--all-features");
diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs
index 4f098b706b..88a6ffb2a0 100644
--- a/crates/ra_project_model/src/lib.rs
+++ b/crates/ra_project_model/src/lib.rs
@@ -8,12 +8,13 @@ use std::{
     fs::{read_dir, File, ReadDir},
     io::{self, BufReader},
     path::{Path, PathBuf},
-    process::{Command, Output},
+    process::Command,
 };
 
 use anyhow::{bail, Context, Result};
 use ra_cfg::CfgOptions;
 use ra_db::{CrateGraph, CrateName, Edition, Env, ExternSource, ExternSourceId, FileId};
+use ra_env::get_path_for_executable;
 use rustc_hash::FxHashMap;
 use serde_json::from_reader;
 
@@ -88,28 +89,46 @@ impl ProjectRoot {
     }
 
     pub fn discover(path: &Path) -> io::Result<Vec<ProjectRoot>> {
-        if let Some(project_json) = find_in_parent_dirs(path, "rust-project.json") {
+        if let Some(project_json) = find_rust_project_json(path) {
             return Ok(vec![ProjectRoot::ProjectJson(project_json)]);
         }
         return find_cargo_toml(path)
             .map(|paths| paths.into_iter().map(ProjectRoot::CargoToml).collect());
 
-        fn find_cargo_toml(path: &Path) -> io::Result<Vec<PathBuf>> {
-            match find_in_parent_dirs(path, "Cargo.toml") {
-                Some(it) => Ok(vec![it]),
-                None => Ok(find_cargo_toml_in_child_dir(read_dir(path)?)),
+        fn find_rust_project_json(path: &Path) -> Option<PathBuf> {
+            if path.ends_with("rust-project.json") {
+                return Some(path.to_path_buf());
+            }
+
+            let mut curr = Some(path);
+            while let Some(path) = curr {
+                let candidate = path.join("rust-project.json");
+                if candidate.exists() {
+                    return Some(candidate);
+                }
+                curr = path.parent();
             }
+
+            None
         }
 
-        fn find_in_parent_dirs(path: &Path, target_file_name: &str) -> Option<PathBuf> {
-            if path.ends_with(target_file_name) {
-                return Some(path.to_owned());
+        fn find_cargo_toml(path: &Path) -> io::Result<Vec<PathBuf>> {
+            if path.ends_with("Cargo.toml") {
+                return Ok(vec![path.to_path_buf()]);
             }
 
-            let mut curr = Some(path);
+            if let Some(p) = find_cargo_toml_in_parent_dir(path) {
+                return Ok(vec![p]);
+            }
 
+            let entities = read_dir(path)?;
+            Ok(find_cargo_toml_in_child_dir(entities))
+        }
+
+        fn find_cargo_toml_in_parent_dir(path: &Path) -> Option<PathBuf> {
+            let mut curr = Some(path);
             while let Some(path) = curr {
-                let candidate = path.join(target_file_name);
+                let candidate = path.join("Cargo.toml");
                 if candidate.exists() {
                     return Some(candidate);
                 }
@@ -121,11 +140,14 @@ impl ProjectRoot {
 
         fn find_cargo_toml_in_child_dir(entities: ReadDir) -> Vec<PathBuf> {
             // Only one level down to avoid cycles the easy way and stop a runaway scan with large projects
-            entities
-                .filter_map(Result::ok)
-                .map(|it| it.path().join("Cargo.toml"))
-                .filter(|it| it.exists())
-                .collect()
+            let mut valid_canditates = vec![];
+            for entity in entities.filter_map(Result::ok) {
+                let candidate = entity.path().join("Cargo.toml");
+                if candidate.exists() {
+                    valid_canditates.push(candidate)
+                }
+            }
+            valid_canditates
         }
     }
 }
@@ -546,18 +568,25 @@ pub fn get_rustc_cfg_options(target: Option<&String>) -> CfgOptions {
         }
     }
 
-    let rustc_cfgs = || -> Result<String> {
+    match (|| -> Result<String> {
         // `cfg(test)` and `cfg(debug_assertion)` are handled outside, so we suppress them here.
-        let mut cmd = Command::new(ra_toolchain::rustc());
+        let mut cmd = Command::new(get_path_for_executable("rustc")?);
         cmd.args(&["--print", "cfg", "-O"]);
         if let Some(target) = target {
             cmd.args(&["--target", target.as_str()]);
         }
-        let output = output(cmd)?;
+        let output = cmd.output().context("Failed to get output from rustc --print cfg -O")?;
+        if !output.status.success() {
+            bail!(
+                "rustc --print cfg -O exited with exit code ({})",
+                output
+                    .status
+                    .code()
+                    .map_or(String::from("no exit code"), |code| format!("{}", code))
+            );
+        }
         Ok(String::from_utf8(output.stdout)?)
-    }();
-
-    match rustc_cfgs {
+    })() {
         Ok(rustc_cfgs) => {
             for line in rustc_cfgs.lines() {
                 match line.find('=') {
@@ -570,21 +599,8 @@ pub fn get_rustc_cfg_options(target: Option<&String>) -> CfgOptions {
                 }
             }
         }
-        Err(e) => log::error!("failed to get rustc cfgs: {:#}", e),
+        Err(e) => log::error!("failed to get rustc cfgs: {}", e),
     }
 
     cfg_options
 }
-
-fn output(mut cmd: Command) -> Result<Output> {
-    let output = cmd.output().with_context(|| format!("{:?} failed", cmd))?;
-    if !output.status.success() {
-        match String::from_utf8(output.stderr) {
-            Ok(stderr) if !stderr.is_empty() => {
-                bail!("{:?} failed, {}\nstderr:\n{}", cmd, output.status, stderr)
-            }
-            _ => bail!("{:?} failed, {}", cmd, output.status),
-        }
-    }
-    Ok(output)
-}
diff --git a/crates/ra_project_model/src/sysroot.rs b/crates/ra_project_model/src/sysroot.rs
index a8a196e64c..11c26ad891 100644
--- a/crates/ra_project_model/src/sysroot.rs
+++ b/crates/ra_project_model/src/sysroot.rs
@@ -1,15 +1,14 @@
 //! FIXME: write short doc here
 
+use anyhow::{bail, Context, Result};
 use std::{
     env, ops,
     path::{Path, PathBuf},
-    process::Command,
+    process::{Command, Output},
 };
 
-use anyhow::{bail, Result};
 use ra_arena::{Arena, Idx};
-
-use crate::output;
+use ra_env::get_path_for_executable;
 
 #[derive(Default, Debug, Clone)]
 pub struct Sysroot {
@@ -86,22 +85,50 @@ impl Sysroot {
     }
 }
 
+fn create_command_text(program: &str, args: &[&str]) -> String {
+    format!("{} {}", program, args.join(" "))
+}
+
+fn run_command_in_cargo_dir(
+    cargo_toml: impl AsRef<Path>,
+    program: impl AsRef<Path>,
+    args: &[&str],
+) -> Result<Output> {
+    let program = program.as_ref().as_os_str().to_str().expect("Invalid Unicode in path");
+    let output = Command::new(program)
+        .current_dir(cargo_toml.as_ref().parent().unwrap())
+        .args(args)
+        .output()
+        .context(format!("{} failed", create_command_text(program, args)))?;
+    if !output.status.success() {
+        match output.status.code() {
+            Some(code) => bail!(
+                "failed to run the command: '{}' exited with code {}",
+                create_command_text(program, args),
+                code
+            ),
+            None => bail!(
+                "failed to run the command: '{}' terminated by signal",
+                create_command_text(program, args)
+            ),
+        };
+    }
+    Ok(output)
+}
+
 fn get_or_install_rust_src(cargo_toml: &Path) -> Result<PathBuf> {
     if let Ok(path) = env::var("RUST_SRC_PATH") {
         return Ok(path.into());
     }
-    let current_dir = cargo_toml.parent().unwrap();
-    let mut rustc = Command::new(ra_toolchain::rustc());
-    rustc.current_dir(current_dir).args(&["--print", "sysroot"]);
-    let rustc_output = output(rustc)?;
+    let rustc = get_path_for_executable("rustc")?;
+    let rustc_output = run_command_in_cargo_dir(cargo_toml, &rustc, &["--print", "sysroot"])?;
     let stdout = String::from_utf8(rustc_output.stdout)?;
     let sysroot_path = Path::new(stdout.trim());
     let src_path = sysroot_path.join("lib/rustlib/src/rust/src");
 
     if !src_path.exists() {
-        let mut rustup = Command::new(ra_toolchain::rustup());
-        rustup.current_dir(current_dir).args(&["component", "add", "rust-src"]);
-        let _output = output(rustup)?;
+        let rustup = get_path_for_executable("rustup")?;
+        run_command_in_cargo_dir(cargo_toml, &rustup, &["component", "add", "rust-src"])?;
     }
     if !src_path.exists() {
         bail!(
diff --git a/crates/ra_syntax/src/ast/edit.rs b/crates/ra_syntax/src/ast/edit.rs
index 24a1e1d918..3e6dd6061c 100644
--- a/crates/ra_syntax/src/ast/edit.rs
+++ b/crates/ra_syntax/src/ast/edit.rs
@@ -453,7 +453,11 @@ impl IndentLevel {
         IndentLevel(0)
     }
 
-    fn increase_indent(self, node: SyntaxNode) -> SyntaxNode {
+    pub fn increase_indent<N: AstNode>(self, node: N) -> N {
+        N::cast(self._increase_indent(node.syntax().clone())).unwrap()
+    }
+
+    fn _increase_indent(self, node: SyntaxNode) -> SyntaxNode {
         let mut rewriter = SyntaxRewriter::default();
         node.descendants_with_tokens()
             .filter_map(|el| el.into_token())
@@ -474,7 +478,11 @@ impl IndentLevel {
         rewriter.rewrite(&node)
     }
 
-    fn decrease_indent(self, node: SyntaxNode) -> SyntaxNode {
+    pub fn decrease_indent<N: AstNode>(self, node: N) -> N {
+        N::cast(self._decrease_indent(node.syntax().clone())).unwrap()
+    }
+
+    fn _decrease_indent(self, node: SyntaxNode) -> SyntaxNode {
         let mut rewriter = SyntaxRewriter::default();
         node.descendants_with_tokens()
             .filter_map(|el| el.into_token())
@@ -513,7 +521,7 @@ fn prev_tokens(token: SyntaxToken) -> impl Iterator<Item = SyntaxToken> {
     iter::successors(Some(token), |token| token.prev_token())
 }
 
-pub trait AstNodeEdit: AstNode + Clone + Sized {
+pub trait AstNodeEdit: AstNode + Sized {
     #[must_use]
     fn insert_children(
         &self,
@@ -550,17 +558,9 @@ pub trait AstNodeEdit: AstNode + Clone + Sized {
         }
         rewriter.rewrite_ast(self)
     }
-    #[must_use]
-    fn indent(&self, indent: IndentLevel) -> Self {
-        Self::cast(indent.increase_indent(self.syntax().clone())).unwrap()
-    }
-    #[must_use]
-    fn dedent(&self, indent: IndentLevel) -> Self {
-        Self::cast(indent.decrease_indent(self.syntax().clone())).unwrap()
-    }
 }
 
-impl<N: AstNode + Clone> AstNodeEdit for N {}
+impl<N: AstNode> AstNodeEdit for N {}
 
 fn single_node(element: impl Into<SyntaxElement>) -> RangeInclusive<SyntaxElement> {
     let element = element.into();
@@ -580,7 +580,7 @@ fn test_increase_indent() {
     _ => (),
 }"
     );
-    let indented = arm_list.indent(IndentLevel(2));
+    let indented = IndentLevel(2).increase_indent(arm_list);
     assert_eq!(
         indented.syntax().to_string(),
         "{
diff --git a/crates/ra_syntax/src/ast/make.rs b/crates/ra_syntax/src/ast/make.rs
index 7b17fef492..12c5228f56 100644
--- a/crates/ra_syntax/src/ast/make.rs
+++ b/crates/ra_syntax/src/ast/make.rs
@@ -300,7 +300,12 @@ pub fn add_pub_crate_modifier(fn_def: ast::FnDef) -> ast::FnDef {
 
 fn ast_from_text<N: AstNode>(text: &str) -> N {
     let parse = SourceFile::parse(text);
-    let node = parse.tree().syntax().descendants().find_map(N::cast).unwrap();
+    let node = match parse.tree().syntax().descendants().find_map(N::cast) {
+        Some(it) => it,
+        None => {
+            panic!("Failed to make ast node `{}` from text {}", std::any::type_name::<N>(), text)
+        }
+    };
     let node = node.syntax().clone();
     let node = unroot(node);
     let node = N::cast(node).unwrap();
diff --git a/crates/ra_toolchain/src/lib.rs b/crates/ra_toolchain/src/lib.rs
deleted file mode 100644
index 3c307a0eac..0000000000
--- a/crates/ra_toolchain/src/lib.rs
+++ /dev/null
@@ -1,64 +0,0 @@
-//! This crate contains a single public function
-//! [`get_path_for_executable`](fn.get_path_for_executable.html).
-//! See docs there for more information.
-use std::{env, iter, path::PathBuf};
-
-pub fn cargo() -> PathBuf {
-    get_path_for_executable("cargo")
-}
-
-pub fn rustc() -> PathBuf {
-    get_path_for_executable("rustc")
-}
-
-pub fn rustup() -> PathBuf {
-    get_path_for_executable("rustup")
-}
-
-/// Return a `PathBuf` to use for the given executable.
-///
-/// E.g., `get_path_for_executable("cargo")` may return just `cargo` if that
-/// gives a valid Cargo executable; or it may return a full path to a valid
-/// Cargo.
-fn get_path_for_executable(executable_name: &'static str) -> PathBuf {
-    // The current implementation checks three places for an executable to use:
-    // 1) Appropriate environment variable (erroring if this is set but not a usable executable)
-    //      example: for cargo, this checks $CARGO environment variable; for rustc, $RUSTC; etc
-    // 2) `<executable_name>`
-    //      example: for cargo, this tries just `cargo`, which will succeed if `cargo` is on the $PATH
-    // 3) `~/.cargo/bin/<executable_name>`
-    //      example: for cargo, this tries ~/.cargo/bin/cargo
-    //      It seems that this is a reasonable place to try for cargo, rustc, and rustup
-    let env_var = executable_name.to_ascii_uppercase();
-    if let Some(path) = env::var_os(&env_var) {
-        return path.into();
-    }
-
-    if lookup_in_path(executable_name) {
-        return executable_name.into();
-    }
-
-    if let Some(mut path) = home::home_dir() {
-        path.push(".cargo");
-        path.push("bin");
-        path.push(executable_name);
-        if path.is_file() {
-            return path;
-        }
-    }
-    executable_name.into()
-}
-
-fn lookup_in_path(exec: &str) -> bool {
-    let paths = env::var_os("PATH").unwrap_or_default();
-    let mut candidates = env::split_paths(&paths).flat_map(|path| {
-        let candidate = path.join(&exec);
-        let with_exe = if env::consts::EXE_EXTENSION == "" {
-            None
-        } else {
-            Some(candidate.with_extension(env::consts::EXE_EXTENSION))
-        };
-        iter::once(candidate).chain(with_exe)
-    });
-    candidates.any(|it| it.is_file())
-}
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index 17b0b95b9d..b77f0c5a9c 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -96,21 +96,23 @@ pub fn main_loop(ws_roots: Vec<PathBuf>, config: Config, connection: Connection)
     let mut world_state = {
         let workspaces = {
             // FIXME: support dynamic workspace loading.
-            let project_roots: FxHashSet<_> = ws_roots
+            let mut visited = FxHashSet::default();
+            let project_roots = ws_roots
                 .iter()
                 .filter_map(|it| ra_project_model::ProjectRoot::discover(it).ok())
                 .flatten()
-                .collect();
+                .filter(|it| visited.insert(it.clone()))
+                .collect::<Vec<_>>();
 
             if project_roots.is_empty() && config.notifications.cargo_toml_not_found {
                 show_message(
-                    req::MessageType::Error,
-                    format!(
-                        "rust-analyzer failed to discover workspace, no Cargo.toml found, dirs searched: {}",
-                        ws_roots.iter().format_with(", ", |it, f| f(&it.display()))
-                    ),
-                    &connection.sender,
-                );
+                        req::MessageType::Error,
+                        format!(
+                            "rust-analyzer failed to discover workspace, no Cargo.toml found, dirs searched: {}",
+                            ws_roots.iter().format_with(", ", |it, f| f(&it.display()))
+                        ),
+                        &connection.sender,
+                    );
             };
 
             project_roots
diff --git a/editors/code/package.json b/editors/code/package.json
index c6fc13519e..853fc513b0 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -423,16 +423,6 @@
                     "default": {
                         "/rustc/<id>": "${env:USERPROFILE}/.rustup/toolchains/<toolchain-id>/lib/rustlib/src/rust"
                     }
-                },
-                "rust-analyzer.debug.openDebugPane": {
-                    "description": "Whether to open up the Debug Pane on debugging start.",
-                    "type": "boolean",
-                    "default": false
-                },
-                "rust-analyzer.debug.engineSettings": {
-                    "type": "object",
-                    "default": {},
-                    "description": "Optional settings passed to the debug engine. Example:\n{ \"lldb\": { \"terminal\":\"external\"} }"
                 }
             }
         },
diff --git a/editors/code/src/commands/runnables.ts b/editors/code/src/commands/runnables.ts
index ae328d2a42..2ed150e25f 100644
--- a/editors/code/src/commands/runnables.ts
+++ b/editors/code/src/commands/runnables.ts
@@ -64,20 +64,29 @@ export function runSingle(ctx: Ctx): Cmd {
     };
 }
 
-function getLldbDebugConfig(config: ra.Runnable, executable: string, sourceFileMap?: Record<string, string>): vscode.DebugConfiguration {
+function getLldbDebugConfig(config: ra.Runnable, sourceFileMap: Record<string, string>): vscode.DebugConfiguration {
     return {
         type: "lldb",
         request: "launch",
         name: config.label,
-        program: executable,
+        cargo: {
+            args: config.args,
+        },
         args: config.extraArgs,
         cwd: config.cwd,
-        sourceMap: sourceFileMap,
-        sourceLanguages: ["rust"]
+        sourceMap: sourceFileMap
     };
 }
 
-function getCppvsDebugConfig(config: ra.Runnable, executable: string, sourceFileMap?: Record<string, string>): vscode.DebugConfiguration {
+const debugOutput = vscode.window.createOutputChannel("Debug");
+
+async function getCppvsDebugConfig(config: ra.Runnable, sourceFileMap: Record<string, string>): Promise<vscode.DebugConfiguration> {
+    debugOutput.clear();
+
+    const cargo = new Cargo(config.cwd || '.', debugOutput);
+    const executable = await cargo.executableFromArgs(config.args);
+
+    // if we are here, there were no compilation errors.
     return {
         type: (os.platform() === "win32") ? "cppvsdbg" : 'cppdbg',
         request: "launch",
@@ -89,62 +98,39 @@ function getCppvsDebugConfig(config: ra.Runnable, executable: string, sourceFile
     };
 }
 
-const debugOutput = vscode.window.createOutputChannel("Debug");
-
-async function getDebugExecutable(config: ra.Runnable): Promise<string> {
-    const cargo = new Cargo(config.cwd || '.', debugOutput);
-    const executable = await cargo.executableFromArgs(config.args);
-
-    // if we are here, there were no compilation errors.
-    return executable;
-}
-
-type DebugConfigProvider = (config: ra.Runnable, executable: string, sourceFileMap?: Record<string, string>) => vscode.DebugConfiguration;
-
 export function debugSingle(ctx: Ctx): Cmd {
     return async (config: ra.Runnable) => {
         const editor = ctx.activeRustEditor;
         if (!editor) return;
 
-        const knownEngines: Record<string, DebugConfigProvider> = {
-            "vadimcn.vscode-lldb": getLldbDebugConfig,
-            "ms-vscode.cpptools": getCppvsDebugConfig
-        };
-        const debugOptions = ctx.config.debug;
+        const lldbId = "vadimcn.vscode-lldb";
+        const cpptoolsId = "ms-vscode.cpptools";
 
+        const debugEngineId = ctx.config.debug.engine;
         let debugEngine = null;
-        if (debugOptions.engine === "auto") {
-            for (var engineId in knownEngines) {
-                debugEngine = vscode.extensions.getExtension(engineId);
-                if (debugEngine) break;
+        if (debugEngineId === "auto") {
+            debugEngine = vscode.extensions.getExtension(lldbId);
+            if (!debugEngine) {
+                debugEngine = vscode.extensions.getExtension(cpptoolsId);
             }
         }
         else {
-            debugEngine = vscode.extensions.getExtension(debugOptions.engine);
+            debugEngine = vscode.extensions.getExtension(debugEngineId);
         }
 
         if (!debugEngine) {
-            vscode.window.showErrorMessage(`Install [CodeLLDB](https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb)`
-                + ` or [MS C++ tools](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools) extension for debugging.`);
+            vscode.window.showErrorMessage(
+                `Install [CodeLLDB](https://marketplace.visualstudio.com/items?itemName=${lldbId}) ` +
+                `or [MS C++ tools](https://marketplace.visualstudio.com/items?itemName=${cpptoolsId}) ` +
+                `extension for debugging.`
+            );
             return;
         }
 
-        debugOutput.clear();
-        if (ctx.config.debug.openUpDebugPane) {
-            debugOutput.show(true);
-        }
-
-        const executable = await getDebugExecutable(config);
-        const debugConfig = knownEngines[debugEngine.id](config, executable, debugOptions.sourceFileMap);
-        if (debugConfig.type in debugOptions.engineSettings) {
-            const settingsMap = (debugOptions.engineSettings as any)[debugConfig.type];
-            for (var key in settingsMap) {
-                debugConfig[key] = settingsMap[key];
-            }
-        }
+        const debugConfig = lldbId === debugEngine.id
+            ? getLldbDebugConfig(config, ctx.config.debug.sourceFileMap)
+            : await getCppvsDebugConfig(config, ctx.config.debug.sourceFileMap);
 
-        debugOutput.appendLine("Launching debug configuration:");
-        debugOutput.appendLine(JSON.stringify(debugConfig, null, 2));
         return vscode.debug.startDebugging(undefined, debugConfig);
     };
 }
diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts
index be2e27aecc..46de922f33 100644
--- a/editors/code/src/config.ts
+++ b/editors/code/src/config.ts
@@ -109,14 +109,10 @@ export class Config {
     }
 
     get debug() {
-        // "/rustc/<id>" used by suggestions only.
-        const { ["/rustc/<id>"]: _, ...sourceFileMap } = this.get<Record<string, string>>("debug.sourceFileMap");
-
         return {
             engine: this.get<string>("debug.engine"),
-            engineSettings: this.get<object>("debug.engineSettings"),
-            openUpDebugPane: this.get<boolean>("debug.openUpDebugPane"),
-            sourceFileMap: sourceFileMap,
+            sourceFileMap: this.get<Record<string, string>>("debug.sourceFileMap"),
         };
     }
+
 }


Test patch:
diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs
index 1fe05c70c9..d60732e191 100644
--- a/crates/ra_hir_ty/src/tests.rs
+++ b/crates/ra_hir_ty/src/tests.rs
@@ -6,7 +6,6 @@ mod patterns;
 mod traits;
 mod method_resolution;
 mod macros;
-mod display_source_code;
 
 use std::sync::Arc;
 
@@ -17,7 +16,7 @@ use hir_def::{
     item_scope::ItemScope,
     keys,
     nameres::CrateDefMap,
-    AssocItemId, DefWithBodyId, LocalModuleId, Lookup, ModuleDefId, ModuleId,
+    AssocItemId, DefWithBodyId, LocalModuleId, Lookup, ModuleDefId,
 };
 use hir_expand::{db::AstDatabase, InFile};
 use insta::assert_snapshot;
@@ -38,18 +37,6 @@ use crate::{
 // update the snapshots.
 
 fn type_at_pos(db: &TestDB, pos: FilePosition) -> String {
-    type_at_pos_displayed(db, pos, |ty, _| ty.display(db).to_string())
-}
-
-fn displayed_source_at_pos(db: &TestDB, pos: FilePosition) -> String {
-    type_at_pos_displayed(db, pos, |ty, module_id| ty.display_source_code(db, module_id).unwrap())
-}
-
-fn type_at_pos_displayed(
-    db: &TestDB,
-    pos: FilePosition,
-    display_fn: impl FnOnce(&Ty, ModuleId) -> String,
-) -> String {
     let file = db.parse(pos.file_id).ok().unwrap();
     let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap();
     let fn_def = expr.syntax().ancestors().find_map(ast::FnDef::cast).unwrap();
@@ -62,7 +49,7 @@ fn type_at_pos_displayed(
     if let Some(expr_id) = source_map.node_expr(InFile::new(pos.file_id.into(), &expr)) {
         let infer = db.infer(func.into());
         let ty = &infer[expr_id];
-        return display_fn(ty, module);
+        return ty.display(db).to_string();
     }
     panic!("Can't find expression")
 }
@@ -531,21 +518,3 @@ fn missing_record_pat_field_no_diagnostic_if_not_exhaustive() {
 
     assert_snapshot!(diagnostics, @"");
 }
-
-#[test]
-fn break_outside_of_loop() {
-    let diagnostics = TestDB::with_files(
-        r"
-        //- /lib.rs
-        fn foo() {
-            break;
-        }
-        ",
-    )
-    .diagnostics()
-    .0;
-
-    assert_snapshot!(diagnostics, @r###""break": break outside of loop
-    "###
-    );
-}
diff --git a/crates/ra_hir_ty/src/tests/coercion.rs b/crates/ra_hir_ty/src/tests/coercion.rs
index 6dc4b2cd1d..e6fb3e1231 100644
--- a/crates/ra_hir_ty/src/tests/coercion.rs
+++ b/crates/ra_hir_ty/src/tests/coercion.rs
@@ -384,7 +384,7 @@ fn foo() -> u32 {
 }
 "#, true),
         @r###"
-    17..40 '{     ...own; }': u32
+    17..40 '{     ...own; }': !
     23..37 'return unknown': !
     30..37 'unknown': u32
     "###
@@ -514,7 +514,7 @@ fn foo() {
     27..103 '{     ...     }': &u32
     37..82 'if tru...     }': ()
     40..44 'true': bool
-    45..82 '{     ...     }': ()
+    45..82 '{     ...     }': !
     59..71 'return &1u32': !
     66..71 '&1u32': &u32
     67..71 '1u32': u32
@@ -545,48 +545,6 @@ fn test() {
     );
 }
 
-#[test]
-fn coerce_fn_items_in_match_arms() {
-    covers!(coerce_fn_reification);
-    assert_snapshot!(
-        infer_with_mismatches(r#"
-fn foo1(x: u32) -> isize { 1 }
-fn foo2(x: u32) -> isize { 2 }
-fn foo3(x: u32) -> isize { 3 }
-fn test() {
-    let x = match 1 {
-        1 => foo1,
-        2 => foo2,
-        _ => foo3,
-    };
-}
-"#, true),
-        @r###"
-    9..10 'x': u32
-    26..31 '{ 1 }': isize
-    28..29 '1': isize
-    40..41 'x': u32
-    57..62 '{ 2 }': isize
-    59..60 '2': isize
-    71..72 'x': u32
-    88..93 '{ 3 }': isize
-    90..91 '3': isize
-    104..193 '{     ...  }; }': ()
-    114..115 'x': fn(u32) -> isize
-    118..190 'match ...     }': fn(u32) -> isize
-    124..125 '1': i32
-    136..137 '1': i32
-    136..137 '1': i32
-    141..145 'foo1': fn foo1(u32) -> isize
-    155..156 '2': i32
-    155..156 '2': i32
-    160..164 'foo2': fn foo2(u32) -> isize
-    174..175 '_': i32
-    179..183 'foo3': fn foo3(u32) -> isize
-    "###
-    );
-}
-
 #[test]
 fn coerce_closure_to_fn_ptr() {
     assert_snapshot!(
diff --git a/crates/ra_hir_ty/src/tests/display_source_code.rs b/crates/ra_hir_ty/src/tests/display_source_code.rs
deleted file mode 100644
index ca17486152..0000000000
--- a/crates/ra_hir_ty/src/tests/display_source_code.rs
+++ /dev/null
@@ -1,23 +0,0 @@
-use super::displayed_source_at_pos;
-use crate::test_db::TestDB;
-use ra_db::fixture::WithFixture;
-
-#[test]
-fn qualify_path_to_submodule() {
-    let (db, pos) = TestDB::with_position(
-        r#"
-//- /main.rs
-
-mod foo {
-    pub struct Foo;
-}
-
-fn bar() {
-    let foo: foo::Foo = foo::Foo;
-    foo<|>
-}
-
-"#,
-    );
-    assert_eq!("foo::Foo", displayed_source_at_pos(&db, pos));
-}
diff --git a/crates/ra_hir_ty/src/tests/macros.rs b/crates/ra_hir_ty/src/tests/macros.rs
index 4c6099aa23..07398ddcc5 100644
--- a/crates/ra_hir_ty/src/tests/macros.rs
+++ b/crates/ra_hir_ty/src/tests/macros.rs
@@ -197,7 +197,7 @@ fn spam() {
     !0..6 '1isize': isize
     !0..6 '1isize': isize
     !0..6 '1isize': isize
-    54..457 '{     ...!(); }': ()
+    54..457 '{     ...!(); }': !
     88..109 'spam!(...am!())': {unknown}
     115..134 'for _ ...!() {}': ()
     119..120 '_': {unknown}
diff --git a/crates/ra_hir_ty/src/tests/method_resolution.rs b/crates/ra_hir_ty/src/tests/method_resolution.rs
index 67f964ab5d..ab87f598a6 100644
--- a/crates/ra_hir_ty/src/tests/method_resolution.rs
+++ b/crates/ra_hir_ty/src/tests/method_resolution.rs
@@ -17,8 +17,8 @@ impl<T> [T] {
 #[lang = "slice_alloc"]
 impl<T> [T] {}
 
-fn test(x: &[u8]) {
-    <[_]>::foo(x);
+fn test() {
+    <[_]>::foo(b"foo");
 }
 "#),
         @r###"
@@ -26,11 +26,10 @@ fn test(x: &[u8]) {
     56..79 '{     ...     }': T
     66..73 'loop {}': !
     71..73 '{}': ()
-    131..132 'x': &[u8]
-    141..163 '{     ...(x); }': ()
-    147..157 '<[_]>::foo': fn foo<u8>(&[u8]) -> u8
-    147..160 '<[_]>::foo(x)': u8
-    158..159 'x': &[u8]
+    133..160 '{     ...o"); }': ()
+    139..149 '<[_]>::foo': fn foo<u8>(&[u8]) -> u8
+    139..157 '<[_]>:..."foo")': u8
+    150..156 'b"foo"': &[u8]
     "###
     );
 }
diff --git a/crates/ra_hir_ty/src/tests/never_type.rs b/crates/ra_hir_ty/src/tests/never_type.rs
index 082c472088..a772094804 100644
--- a/crates/ra_hir_ty/src/tests/never_type.rs
+++ b/crates/ra_hir_ty/src/tests/never_type.rs
@@ -1,6 +1,4 @@
-use insta::assert_snapshot;
-
-use super::{infer_with_mismatches, type_at};
+use super::type_at;
 
 #[test]
 fn infer_never1() {
@@ -263,176 +261,3 @@ fn test(a: i32) {
     );
     assert_eq!(t, "f64");
 }
-
-#[test]
-fn diverging_expression_1() {
-    let t = infer_with_mismatches(
-        r#"
-//- /main.rs
-fn test1() {
-    let x: u32 = return;
-}
-fn test2() {
-    let x: u32 = { return; };
-}
-fn test3() {
-    let x: u32 = loop {};
-}
-fn test4() {
-    let x: u32 = { loop {} };
-}
-fn test5() {
-    let x: u32 = { if true { loop {}; } else { loop {}; } };
-}
-fn test6() {
-    let x: u32 = { let y: u32 = { loop {}; }; };
-}
-"#,
-        true,
-    );
-    assert_snapshot!(t, @r###"
-    25..53 '{     ...urn; }': ()
-    35..36 'x': u32
-    44..50 'return': !
-    65..98 '{     ...; }; }': ()
-    75..76 'x': u32
-    84..95 '{ return; }': u32
-    86..92 'return': !
-    110..139 '{     ... {}; }': ()
-    120..121 'x': u32
-    129..136 'loop {}': !
-    134..136 '{}': ()
-    151..184 '{     ...} }; }': ()
-    161..162 'x': u32
-    170..181 '{ loop {} }': u32
-    172..179 'loop {}': !
-    177..179 '{}': ()
-    196..260 '{     ...} }; }': ()
-    206..207 'x': u32
-    215..257 '{ if t...}; } }': u32
-    217..255 'if tru... {}; }': u32
-    220..224 'true': bool
-    225..237 '{ loop {}; }': u32
-    227..234 'loop {}': !
-    232..234 '{}': ()
-    243..255 '{ loop {}; }': u32
-    245..252 'loop {}': !
-    250..252 '{}': ()
-    272..324 '{     ...; }; }': ()
-    282..283 'x': u32
-    291..321 '{ let ...; }; }': u32
-    297..298 'y': u32
-    306..318 '{ loop {}; }': u32
-    308..315 'loop {}': !
-    313..315 '{}': ()
-    "###);
-}
-
-#[test]
-fn diverging_expression_2() {
-    let t = infer_with_mismatches(
-        r#"
-//- /main.rs
-fn test1() {
-    // should give type mismatch
-    let x: u32 = { loop {}; "foo" };
-}
-"#,
-        true,
-    );
-    assert_snapshot!(t, @r###"
-    25..98 '{     ..." }; }': ()
-    68..69 'x': u32
-    77..95 '{ loop...foo" }': &str
-    79..86 'loop {}': !
-    84..86 '{}': ()
-    88..93 '"foo"': &str
-    77..95: expected u32, got &str
-    88..93: expected u32, got &str
-    "###);
-}
-
-#[test]
-fn diverging_expression_3_break() {
-    let t = infer_with_mismatches(
-        r#"
-//- /main.rs
-fn test1() {
-    // should give type mismatch
-    let x: u32 = { loop { break; } };
-}
-fn test2() {
-    // should give type mismatch
-    let x: u32 = { for a in b { break; }; };
-    // should give type mismatch as well
-    let x: u32 = { for a in b {}; };
-    // should give type mismatch as well
-    let x: u32 = { for a in b { return; }; };
-}
-fn test3() {
-    // should give type mismatch
-    let x: u32 = { while true { break; }; };
-    // should give type mismatch as well -- there's an implicit break, even if it's never hit
-    let x: u32 = { while true {}; };
-    // should give type mismatch as well
-    let x: u32 = { while true { return; }; };
-}
-"#,
-        true,
-    );
-    assert_snapshot!(t, @r###"
-    25..99 '{     ...} }; }': ()
-    68..69 'x': u32
-    77..96 '{ loop...k; } }': ()
-    79..94 'loop { break; }': ()
-    84..94 '{ break; }': ()
-    86..91 'break': !
-    77..96: expected u32, got ()
-    79..94: expected u32, got ()
-    111..357 '{     ...; }; }': ()
-    154..155 'x': u32
-    163..189 '{ for ...; }; }': ()
-    165..186 'for a ...eak; }': ()
-    169..170 'a': {unknown}
-    174..175 'b': {unknown}
-    176..186 '{ break; }': ()
-    178..183 'break': !
-    240..241 'x': u32
-    249..267 '{ for ... {}; }': ()
-    251..264 'for a in b {}': ()
-    255..256 'a': {unknown}
-    260..261 'b': {unknown}
-    262..264 '{}': ()
-    318..319 'x': u32
-    327..354 '{ for ...; }; }': ()
-    329..351 'for a ...urn; }': ()
-    333..334 'a': {unknown}
-    338..339 'b': {unknown}
-    340..351 '{ return; }': ()
-    342..348 'return': !
-    163..189: expected u32, got ()
-    249..267: expected u32, got ()
-    327..354: expected u32, got ()
-    369..668 '{     ...; }; }': ()
-    412..413 'x': u32
-    421..447 '{ whil...; }; }': ()
-    423..444 'while ...eak; }': ()
-    429..433 'true': bool
-    434..444 '{ break; }': ()
-    436..441 'break': !
-    551..552 'x': u32
-    560..578 '{ whil... {}; }': ()
-    562..575 'while true {}': ()
-    568..572 'true': bool
-    573..575 '{}': ()
-    629..630 'x': u32
-    638..665 '{ whil...; }; }': ()
-    640..662 'while ...urn; }': ()
-    646..650 'true': bool
-    651..662 '{ return; }': ()
-    653..659 'return': !
-    421..447: expected u32, got ()
-    560..578: expected u32, got ()
-    638..665: expected u32, got ()
-    "###);
-}
diff --git a/crates/ra_hir_ty/src/tests/simple.rs b/crates/ra_hir_ty/src/tests/simple.rs
index 3820175f6c..3d3088965d 100644
--- a/crates/ra_hir_ty/src/tests/simple.rs
+++ b/crates/ra_hir_ty/src/tests/simple.rs
@@ -179,7 +179,7 @@ fn test(a: u32, b: isize, c: !, d: &str) {
     17..18 'b': isize
     27..28 'c': !
     33..34 'd': &str
-    42..121 '{     ...f32; }': ()
+    42..121 '{     ...f32; }': !
     48..49 'a': u32
     55..56 'b': isize
     62..63 'c': !
@@ -414,7 +414,7 @@ fn test() {
     27..31 '5f32': f32
     37..41 '5f64': f64
     47..54 '"hello"': &str
-    60..68 'b"bytes"': &[u8; _]
+    60..68 'b"bytes"': &[u8]
     74..77 ''c'': char
     83..87 'b'b'': u8
     93..97 '3.14': f64
@@ -422,7 +422,7 @@ fn test() {
     113..118 'false': bool
     124..128 'true': bool
     134..202 'r#"   ...    "#': &str
-    208..218 'br#"yolo"#': &[u8; _]
+    208..218 'br#"yolo"#': &[u8]
     "###
     );
 }
@@ -935,7 +935,7 @@ fn foo() {
     29..33 'true': bool
     34..51 '{     ...     }': i32
     44..45 '1': i32
-    57..80 '{     ...     }': i32
+    57..80 '{     ...     }': !
     67..73 'return': !
     90..93 '_x2': i32
     96..149 'if tru...     }': i32
@@ -951,7 +951,7 @@ fn foo() {
     186..190 'true': bool
     194..195 '3': i32
     205..206 '_': bool
-    210..241 '{     ...     }': i32
+    210..241 '{     ...     }': !
     224..230 'return': !
     257..260 '_x4': i32
     263..320 'match ...     }': i32
@@ -1687,7 +1687,7 @@ fn foo() -> u32 {
     17..59 '{     ...; }; }': ()
     27..28 'x': || -> usize
     31..56 '|| -> ...n 1; }': || -> usize
-    43..56 '{ return 1; }': usize
+    43..56 '{ return 1; }': !
     45..53 'return 1': !
     52..53 '1': usize
     "###
@@ -1706,7 +1706,7 @@ fn foo() -> u32 {
     17..48 '{     ...; }; }': ()
     27..28 'x': || -> ()
     31..45 '|| { return; }': || -> ()
-    34..45 '{ return; }': ()
+    34..45 '{ return; }': !
     36..42 'return': !
     "###
     );
diff --git a/crates/test_utils/src/lib.rs b/crates/test_utils/src/lib.rs
index b1e3c328f3..b13e13af2a 100644
--- a/crates/test_utils/src/lib.rs
+++ b/crates/test_utils/src/lib.rs
@@ -270,7 +270,7 @@ fn parse_fixture_checks_further_indented_metadata() {
 }
 
 #[test]
-fn parse_fixture_can_handle_dedented_first_line() {
+fn parse_fixture_can_handle_unindented_first_line() {
     let fixture = "//- /lib.rs
                    mod foo;
                    //- /foo.rs