Repository: rust-analyzer/rust-analyzer
Pull request #5124 (2020-06-29 14:11:24)

(Partially) fix handling of type params depending on type params
If the first type parameter gets inferred, that's still not handled correctly; it'll require some more refactoring: E.g. if we have `Thing<T, F=fn() -> T>` and then instantiate `Thing<_>`, that gets turned into `Thing<_, fn() -> _>` before the `_` is instantiated into a type variable -- so afterwards, we have two type variables without any connection to each other.


Patch:
diff --git a/Cargo.lock b/Cargo.lock
index b19d697f5f..dc758a1f09 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -135,9 +135,8 @@ checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
 
 [[package]]
 name = "chalk-derive"
-version = "0.15.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c7379caa72d04103fcfd9bde5642b816f58e3ffd6a0d39347e9e35a066648226"
+version = "0.15.0-dev.0"
+source = "git+https://github.com/rust-lang/chalk#57037a53f7decc965d25972606c3ea930e9cb39f"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -147,9 +146,8 @@ dependencies = [
 
 [[package]]
 name = "chalk-engine"
-version = "0.15.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e8afe48b5663504b485791ab4fae69cf4864869a71ceec9c758fd4d03423722"
+version = "0.15.0-dev.0"
+source = "git+https://github.com/rust-lang/chalk#57037a53f7decc965d25972606c3ea930e9cb39f"
 dependencies = [
  "chalk-derive",
  "chalk-ir",
@@ -159,9 +157,8 @@ dependencies = [
 
 [[package]]
 name = "chalk-ir"
-version = "0.15.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "231e391a03c1fc45874171d92be9542efedc939bac59d9501ee28b9521feb406"
+version = "0.15.0-dev.0"
+source = "git+https://github.com/rust-lang/chalk#57037a53f7decc965d25972606c3ea930e9cb39f"
 dependencies = [
  "chalk-derive",
  "lazy_static",
@@ -169,9 +166,8 @@ dependencies = [
 
 [[package]]
 name = "chalk-solve"
-version = "0.15.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "72c969c0fd06ad50538253327ca3445ff02cc9d0209f94c3cbf198ad9d365b48"
+version = "0.15.0-dev.0"
+source = "git+https://github.com/rust-lang/chalk#57037a53f7decc965d25972606c3ea930e9cb39f"
 dependencies = [
  "chalk-derive",
  "chalk-engine",
@@ -558,9 +554,9 @@ dependencies = [
 
 [[package]]
 name = "instant"
-version = "0.1.5"
+version = "0.1.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "69da7ce1490173c2bf4d26bc8be429aaeeaf4cce6c4b970b7949651fa17655fe"
+checksum = "7777a24a1ce5de49fcdde84ec46efa487c3af49d5b6e6e0a50367cc5c1096182"
 
 [[package]]
 name = "iovec"
diff --git a/crates/flycheck/src/lib.rs b/crates/flycheck/src/lib.rs
index 1023d3040f..92ec4f92e3 100644
--- a/crates/flycheck/src/lib.rs
+++ b/crates/flycheck/src/lib.rs
@@ -5,9 +5,8 @@
 use std::{
     fmt,
     io::{self, BufReader},
-    ops,
     path::PathBuf,
-    process::{self, Command, Stdio},
+    process::{Command, Stdio},
     time::Duration,
 };
 
@@ -50,8 +49,8 @@ impl fmt::Display for FlycheckConfig {
 #[derive(Debug)]
 pub struct FlycheckHandle {
     // XXX: drop order is significant
-    sender: Sender<Restart>,
-    thread: jod_thread::JoinHandle,
+    cmd_send: Sender<Restart>,
+    handle: jod_thread::JoinHandle,
 }
 
 impl FlycheckHandle {
@@ -60,15 +59,16 @@ impl FlycheckHandle {
         config: FlycheckConfig,
         workspace_root: PathBuf,
     ) -> FlycheckHandle {
-        let actor = FlycheckActor::new(sender, config, workspace_root);
-        let (sender, receiver) = unbounded::<Restart>();
-        let thread = jod_thread::spawn(move || actor.run(receiver));
-        FlycheckHandle { sender, thread }
+        let (cmd_send, cmd_recv) = unbounded::<Restart>();
+        let handle = jod_thread::spawn(move || {
+            FlycheckActor::new(sender, config, workspace_root).run(cmd_recv);
+        });
+        FlycheckHandle { cmd_send, handle }
     }
 
     /// Schedule a re-start of the cargo check worker.
     pub fn update(&self) {
-        self.sender.send(Restart).unwrap();
+        self.cmd_send.send(Restart).unwrap();
     }
 }
 
@@ -85,7 +85,7 @@ pub enum Message {
 pub enum Progress {
     DidStart,
     DidCheckCrate(String),
-    DidFinish(io::Result<()>),
+    DidFinish,
     DidCancel,
 }
 
@@ -100,7 +100,8 @@ struct FlycheckActor {
     /// doesn't provide a way to read sub-process output without blocking, so we
     /// have to wrap sub-processes output handling in a thread and pass messages
     /// back over a channel.
-    cargo_handle: Option<CargoHandle>,
+    // XXX: drop order is significant
+    check_process: Option<(Receiver<cargo_metadata::Message>, jod_thread::JoinHandle)>,
 }
 
 enum Event {
@@ -114,36 +115,29 @@ impl FlycheckActor {
         config: FlycheckConfig,
         workspace_root: PathBuf,
     ) -> FlycheckActor {
-        FlycheckActor { sender, config, workspace_root, cargo_handle: None }
+        FlycheckActor { sender, config, workspace_root, check_process: None }
     }
     fn next_event(&self, inbox: &Receiver<Restart>) -> Option<Event> {
-        let check_chan = self.cargo_handle.as_ref().map(|cargo| &cargo.receiver);
+        let check_chan = self.check_process.as_ref().map(|(chan, _thread)| chan);
         select! {
             recv(inbox) -> msg => msg.ok().map(Event::Restart),
             recv(check_chan.unwrap_or(&never())) -> msg => Some(Event::CheckEvent(msg.ok())),
         }
     }
-    fn run(mut self, inbox: Receiver<Restart>) {
+    fn run(&mut self, inbox: Receiver<Restart>) {
         while let Some(event) = self.next_event(&inbox) {
             match event {
                 Event::Restart(Restart) => {
                     while let Ok(Restart) = inbox.recv_timeout(Duration::from_millis(50)) {}
-
                     self.cancel_check_process();
-
-                    let mut command = self.check_command();
-                    command.stdout(Stdio::piped()).stderr(Stdio::null()).stdin(Stdio::null());
-                    if let Ok(child) = command.spawn().map(JodChild) {
-                        self.cargo_handle = Some(CargoHandle::spawn(child));
-                        self.send(Message::Progress(Progress::DidStart));
-                    }
+                    self.check_process = Some(self.start_check_process());
+                    self.send(Message::Progress(Progress::DidStart));
                 }
                 Event::CheckEvent(None) => {
                     // Watcher finished, replace it with a never channel to
                     // avoid busy-waiting.
-                    let cargo_handle = self.cargo_handle.take().unwrap();
-                    let res = cargo_handle.join();
-                    self.send(Message::Progress(Progress::DidFinish(res)));
+                    assert!(self.check_process.take().is_some());
+                    self.send(Message::Progress(Progress::DidFinish));
                 }
                 Event::CheckEvent(Some(message)) => match message {
                     cargo_metadata::Message::CompilerArtifact(msg) => {
@@ -168,11 +162,11 @@ impl FlycheckActor {
         self.cancel_check_process();
     }
     fn cancel_check_process(&mut self) {
-        if self.cargo_handle.take().is_some() {
+        if self.check_process.take().is_some() {
             self.send(Message::Progress(Progress::DidCancel));
         }
     }
-    fn check_command(&self) -> Command {
+    fn start_check_process(&self) -> (Receiver<cargo_metadata::Message>, jod_thread::JoinHandle) {
         let mut cmd = match &self.config {
             FlycheckConfig::CargoCommand {
                 command,
@@ -204,112 +198,88 @@ impl FlycheckActor {
             }
         };
         cmd.current_dir(&self.workspace_root);
-        cmd
-    }
 
-    fn send(&self, check_task: Message) {
-        (self.sender)(check_task)
-    }
-}
+        let (message_send, message_recv) = unbounded();
+        let thread = jod_thread::spawn(move || {
+            // If we trigger an error here, we will do so in the loop instead,
+            // which will break out of the loop, and continue the shutdown
+            let res = run_cargo(cmd, &mut |message| {
+                // Skip certain kinds of messages to only spend time on what's useful
+                match &message {
+                    cargo_metadata::Message::CompilerArtifact(artifact) if artifact.fresh => {
+                        return true
+                    }
+                    cargo_metadata::Message::BuildScriptExecuted(_)
+                    | cargo_metadata::Message::Unknown => return true,
+                    _ => {}
+                }
 
-struct CargoHandle {
-    child: JodChild,
-    #[allow(unused)]
-    thread: jod_thread::JoinHandle<io::Result<bool>>,
-    receiver: Receiver<cargo_metadata::Message>,
-}
+                // if the send channel was closed, we want to shutdown
+                message_send.send(message).is_ok()
+            });
 
-impl CargoHandle {
-    fn spawn(mut child: JodChild) -> CargoHandle {
-        let child_stdout = child.stdout.take().unwrap();
-        let (sender, receiver) = unbounded();
-        let actor = CargoActor::new(child_stdout, sender);
-        let thread = jod_thread::spawn(move || actor.run());
-        CargoHandle { child, thread, receiver }
+            if let Err(err) = res {
+                // FIXME: make the `message_send` to be `Sender<Result<CheckEvent, CargoError>>`
+                // to display user-caused misconfiguration errors instead of just logging them here
+                log::error!("Cargo watcher failed {:?}", err);
+            }
+        });
+        (message_recv, thread)
     }
-    fn join(mut self) -> io::Result<()> {
-        // It is okay to ignore the result, as it only errors if the process is already dead
-        let _ = self.child.kill();
-        let exit_status = self.child.wait()?;
-        let read_at_least_one_message = self.thread.join()?;
-        if !exit_status.success() && !read_at_least_one_message {
-            // FIXME: Read the stderr to display the reason, see `read2()` reference in PR comment:
-            // https://github.com/rust-analyzer/rust-analyzer/pull/3632#discussion_r395605298
-            return Err(io::Error::new(
-                io::ErrorKind::Other,
-                format!(
-                    "Cargo watcher failed,the command produced no valid metadata (exit code: {:?})",
-                    exit_status
-                ),
-            ));
-        }
-        Ok(())
+
+    fn send(&self, check_task: Message) {
+        (self.sender)(check_task)
     }
 }
 
-struct CargoActor {
-    child_stdout: process::ChildStdout,
-    sender: Sender<cargo_metadata::Message>,
-}
+fn run_cargo(
+    mut command: Command,
+    on_message: &mut dyn FnMut(cargo_metadata::Message) -> bool,
+) -> io::Result<()> {
+    let mut child =
+        command.stdout(Stdio::piped()).stderr(Stdio::null()).stdin(Stdio::null()).spawn()?;
 
-impl CargoActor {
-    fn new(
-        child_stdout: process::ChildStdout,
-        sender: Sender<cargo_metadata::Message>,
-    ) -> CargoActor {
-        CargoActor { child_stdout, sender }
-    }
-    fn run(self) -> io::Result<bool> {
-        // We manually read a line at a time, instead of using serde's
-        // stream deserializers, because the deserializer cannot recover
-        // from an error, resulting in it getting stuck, because we try to
-        // be resilient against failures.
-        //
-        // Because cargo only outputs one JSON object per line, we can
-        // simply skip a line if it doesn't parse, which just ignores any
-        // erroneus output.
-        let stdout = BufReader::new(self.child_stdout);
-        let mut read_at_least_one_message = false;
-        for message in cargo_metadata::Message::parse_stream(stdout) {
-            let message = match message {
-                Ok(message) => message,
-                Err(err) => {
-                    log::error!("Invalid json from cargo check, ignoring ({})", err);
-                    continue;
-                }
-            };
+    // We manually read a line at a time, instead of using serde's
+    // stream deserializers, because the deserializer cannot recover
+    // from an error, resulting in it getting stuck, because we try to
+    // be resillient against failures.
+    //
+    // Because cargo only outputs one JSON object per line, we can
+    // simply skip a line if it doesn't parse, which just ignores any
+    // erroneus output.
+    let stdout = BufReader::new(child.stdout.take().unwrap());
+    let mut read_at_least_one_message = false;
+    for message in cargo_metadata::Message::parse_stream(stdout) {
+        let message = match message {
+            Ok(message) => message,
+            Err(err) => {
+                log::error!("Invalid json from cargo check, ignoring ({})", err);
+                continue;
+            }
+        };
 
-            read_at_least_one_message = true;
+        read_at_least_one_message = true;
 
-            // Skip certain kinds of messages to only spend time on what's useful
-            match &message {
-                cargo_metadata::Message::CompilerArtifact(artifact) if artifact.fresh => (),
-                cargo_metadata::Message::BuildScriptExecuted(_)
-                | cargo_metadata::Message::Unknown => (),
-                _ => self.sender.send(message).unwrap(),
-            }
+        if !on_message(message) {
+            break;
         }
-        Ok(read_at_least_one_message)
     }
-}
 
-struct JodChild(process::Child);
+    // It is okay to ignore the result, as it only errors if the process is already dead
+    let _ = child.kill();
 
-impl ops::Deref for JodChild {
-    type Target = process::Child;
-    fn deref(&self) -> &process::Child {
-        &self.0
+    let exit_status = child.wait()?;
+    if !exit_status.success() && !read_at_least_one_message {
+        // FIXME: Read the stderr to display the reason, see `read2()` reference in PR comment:
+        // https://github.com/rust-analyzer/rust-analyzer/pull/3632#discussion_r395605298
+        return Err(io::Error::new(
+            io::ErrorKind::Other,
+            format!(
+                "the command produced no valid metadata (exit code: {:?}): {:?}",
+                exit_status, command
+            ),
+        ));
     }
-}
 
-impl ops::DerefMut for JodChild {
-    fn deref_mut(&mut self) -> &mut process::Child {
-        &mut self.0
-    }
-}
-
-impl Drop for JodChild {
-    fn drop(&mut self) {
-        let _ = self.0.kill();
-    }
+    Ok(())
 }
diff --git a/crates/ra_assists/src/handlers/change_visibility.rs b/crates/ra_assists/src/handlers/change_visibility.rs
index 157c7b6654..c21d75be08 100644
--- a/crates/ra_assists/src/handlers/change_visibility.rs
+++ b/crates/ra_assists/src/handlers/change_visibility.rs
@@ -1,12 +1,15 @@
 use ra_syntax::{
     ast::{self, NameOwner, VisibilityOwner},
     AstNode,
-    SyntaxKind::{CONST_DEF, ENUM_DEF, FN_DEF, MODULE, STRUCT_DEF, TRAIT_DEF, VISIBILITY},
-    T,
+    SyntaxKind::{
+        ATTR, COMMENT, CONST_DEF, ENUM_DEF, FN_DEF, MODULE, STRUCT_DEF, TRAIT_DEF, VISIBILITY,
+        WHITESPACE,
+    },
+    SyntaxNode, TextSize, T,
 };
 use test_utils::mark;
 
-use crate::{utils::vis_offset, AssistContext, AssistId, Assists};
+use crate::{AssistContext, AssistId, Assists};
 
 // Assist: change_visibility
 //
@@ -27,8 +30,9 @@ pub(crate) fn change_visibility(acc: &mut Assists, ctx: &AssistContext) -> Optio
 }
 
 fn add_vis(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
-    let item_keyword = ctx.token_at_offset().find(|leaf| {
-        matches!(leaf.kind(), T![const] | T![fn] | T![mod] | T![struct] | T![enum] | T![trait])
+    let item_keyword = ctx.token_at_offset().find(|leaf| match leaf.kind() {
+        T![const] | T![fn] | T![mod] | T![struct] | T![enum] | T![trait] => true,
+        _ => false,
     });
 
     let (offset, target) = if let Some(keyword) = item_keyword {
@@ -67,6 +71,17 @@ fn add_vis(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
     })
 }
 
+fn vis_offset(node: &SyntaxNode) -> TextSize {
+    node.children_with_tokens()
+        .skip_while(|it| match it.kind() {
+            WHITESPACE | COMMENT | ATTR => true,
+            _ => false,
+        })
+        .next()
+        .map(|it| it.text_range().start())
+        .unwrap_or_else(|| node.text_range().start())
+}
+
 fn change_vis(acc: &mut Assists, vis: ast::Visibility) -> Option<()> {
     if vis.syntax().text() == "pub" {
         let target = vis.syntax().text_range();
diff --git a/crates/ra_assists/src/handlers/fix_visibility.rs b/crates/ra_assists/src/handlers/fix_visibility.rs
index 19d4dac5e1..54601d1f39 100644
--- a/crates/ra_assists/src/handlers/fix_visibility.rs
+++ b/crates/ra_assists/src/handlers/fix_visibility.rs
@@ -1,8 +1,12 @@
 use hir::{db::HirDatabase, HasSource, HasVisibility, PathResolution};
 use ra_db::FileId;
-use ra_syntax::{ast, AstNode, TextRange, TextSize};
+use ra_syntax::{
+    ast, AstNode,
+    SyntaxKind::{ATTR, COMMENT, WHITESPACE},
+    SyntaxNode, TextRange, TextSize,
+};
 
-use crate::{utils::vis_offset, AssistContext, AssistId, Assists};
+use crate::{AssistContext, AssistId, Assists};
 
 // FIXME: this really should be a fix for diagnostic, rather than an assist.
 
@@ -173,6 +177,17 @@ fn target_data_for_def(
     Some((offset, target, target_file, target_name))
 }
 
+fn vis_offset(node: &SyntaxNode) -> TextSize {
+    node.children_with_tokens()
+        .skip_while(|it| match it.kind() {
+            WHITESPACE | COMMENT | ATTR => true,
+            _ => false,
+        })
+        .next()
+        .map(|it| it.text_range().start())
+        .unwrap_or_else(|| node.text_range().start())
+}
+
 #[cfg(test)]
 mod tests {
     use crate::tests::{check_assist, check_assist_not_applicable};
diff --git a/crates/ra_assists/src/handlers/merge_match_arms.rs b/crates/ra_assists/src/handlers/merge_match_arms.rs
index 90ce66378f..ca04ec671a 100644
--- a/crates/ra_assists/src/handlers/merge_match_arms.rs
+++ b/crates/ra_assists/src/handlers/merge_match_arms.rs
@@ -81,7 +81,10 @@ pub(crate) fn merge_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option
 }
 
 fn contains_placeholder(a: &ast::MatchArm) -> bool {
-    matches!(a.pat(), Some(ast::Pat::PlaceholderPat(..)))
+    match a.pat() {
+        Some(ra_syntax::ast::Pat::PlaceholderPat(..)) => true,
+        _ => false,
+    }
 }
 
 #[cfg(test)]
diff --git a/crates/ra_assists/src/utils.rs b/crates/ra_assists/src/utils.rs
index 02de902d6e..b7c45a6193 100644
--- a/crates/ra_assists/src/utils.rs
+++ b/crates/ra_assists/src/utils.rs
@@ -7,9 +7,7 @@ use hir::{Adt, Crate, Enum, ScopeDef, Semantics, Trait, Type};
 use ra_ide_db::RootDatabase;
 use ra_syntax::{
     ast::{self, make, NameOwner},
-    AstNode,
-    SyntaxKind::*,
-    SyntaxNode, TextSize, T,
+    AstNode, SyntaxNode, T,
 };
 use rustc_hash::FxHashSet;
 
@@ -122,13 +120,6 @@ pub(crate) fn resolve_target_trait(
     }
 }
 
-pub(crate) fn vis_offset(node: &SyntaxNode) -> TextSize {
-    node.children_with_tokens()
-        .find(|it| !matches!(it.kind(), WHITESPACE | COMMENT | ATTR))
-        .map(|it| it.text_range().start())
-        .unwrap_or_else(|| node.text_range().start())
-}
-
 pub(crate) fn invert_boolean_expression(expr: ast::Expr) -> ast::Expr {
     if let Some(expr) = invert_special_case(&expr) {
         return expr;
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
index 27e94b7fe7..e86077dd6a 100644
--- a/crates/ra_hir/src/code_model.rs
+++ b/crates/ra_hir/src/code_model.rs
@@ -543,7 +543,7 @@ impl_froms!(Adt: Struct, Union, Enum);
 impl Adt {
     pub fn has_non_default_type_params(self, db: &dyn HirDatabase) -> bool {
         let subst = db.generic_defaults(self.into());
-        subst.iter().any(|ty| ty == &Ty::Unknown)
+        subst.iter().any(|ty| &ty.value == &Ty::Unknown)
     }
 
     /// Turns this ADT into a type. Any type parameters of the ADT will be
@@ -775,7 +775,7 @@ pub struct TypeAlias {
 impl TypeAlias {
     pub fn has_non_default_type_params(self, db: &dyn HirDatabase) -> bool {
         let subst = db.generic_defaults(self.id.into());
-        subst.iter().any(|ty| ty == &Ty::Unknown)
+        subst.iter().any(|ty| &ty.value == &Ty::Unknown)
     }
 
     pub fn module(self, db: &dyn HirDatabase) -> Module {
@@ -1035,7 +1035,10 @@ impl TypeParam {
         let local_idx = hir_ty::param_idx(db, self.id)?;
         let resolver = self.id.parent.resolver(db.upcast());
         let environment = TraitEnvironment::lower(db, &resolver);
-        params.get(local_idx).cloned().map(|ty| Type {
+        let ty = params.get(local_idx)?.clone();
+        let subst = Substs::type_params(db, self.id.parent);
+        let ty = ty.subst(&subst.prefix(local_idx));
+        Some(Type {
             krate: self.id.parent.module(db.upcast()).krate,
             ty: InEnvironment { value: ty, environment },
         })
diff --git a/crates/ra_hir_ty/Cargo.toml b/crates/ra_hir_ty/Cargo.toml
index d6df48db20..407322dc16 100644
--- a/crates/ra_hir_ty/Cargo.toml
+++ b/crates/ra_hir_ty/Cargo.toml
@@ -27,8 +27,8 @@ test_utils = { path = "../test_utils" }
 
 scoped-tls = "1"
 
-chalk-solve = { version = "0.15.0" }
-chalk-ir = { version = "0.15.0" }
+chalk-solve = { version = "0.15.0-dev.0", git = "https://github.com/rust-lang/chalk" }
+chalk-ir = { version = "0.15.0-dev.0", git = "https://github.com/rust-lang/chalk" }
 
 [dev-dependencies]
 insta = "0.16.0"
diff --git a/crates/ra_hir_ty/src/db.rs b/crates/ra_hir_ty/src/db.rs
index 7889b8d2cc..cad5532739 100644
--- a/crates/ra_hir_ty/src/db.rs
+++ b/crates/ra_hir_ty/src/db.rs
@@ -14,7 +14,7 @@ use crate::{
     method_resolution::CrateImplDefs,
     traits::{chalk, AssocTyValue, Impl},
     Binders, CallableDef, GenericPredicate, InferenceResult, OpaqueTyId, PolyFnSig,
-    ReturnTypeImplTraits, Substs, TraitRef, Ty, TyDefId, TypeCtor, ValueTyDefId,
+    ReturnTypeImplTraits, TraitRef, Ty, TyDefId, TypeCtor, ValueTyDefId,
 };
 use hir_expand::name::Name;
 
@@ -65,7 +65,7 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
     fn generic_predicates(&self, def: GenericDefId) -> Arc<[Binders<GenericPredicate>]>;
 
     #[salsa::invoke(crate::lower::generic_defaults_query)]
-    fn generic_defaults(&self, def: GenericDefId) -> Substs;
+    fn generic_defaults(&self, def: GenericDefId) -> Arc<[Binders<Ty>]>;
 
     #[salsa::invoke(crate::method_resolution::CrateImplDefs::impls_in_crate_query)]
     fn impls_in_crate(&self, krate: CrateId) -> Arc<CrateImplDefs>;
diff --git a/crates/ra_hir_ty/src/display.rs b/crates/ra_hir_ty/src/display.rs
index 3c97e13545..23cea1a2ad 100644
--- a/crates/ra_hir_ty/src/display.rs
+++ b/crates/ra_hir_ty/src/display.rs
@@ -308,7 +308,6 @@ impl HirDisplay for ApplicationTy {
                 }
 
                 if self.parameters.len() > 0 {
-                    let mut non_default_parameters = Vec::with_capacity(self.parameters.len());
                     let parameters_to_write =
                         if f.display_target.is_source_code() || f.omit_verbose_types() {
                             match self
@@ -319,20 +318,23 @@ impl HirDisplay for ApplicationTy {
                             {
                                 None => self.parameters.0.as_ref(),
                                 Some(default_parameters) => {
+                                    let mut default_from = 0;
                                     for (i, parameter) in self.parameters.iter().enumerate() {
                                         match (parameter, default_parameters.get(i)) {
                                             (&Ty::Unknown, _) | (_, None) => {
-                                                non_default_parameters.push(parameter.clone())
+                                                default_from = i + 1;
                                             }
-                                            (_, Some(default_parameter))
-                                                if parameter != default_parameter =>
-                                            {
-                                                non_default_parameters.push(parameter.clone())
+                                            (_, Some(default_parameter)) => {
+                                                let actual_default = default_parameter
+                                                    .clone()
+                                                    .subst(&self.parameters.prefix(i));
+                                                if parameter != &actual_default {
+                                                    default_from = i + 1;
+                                                }
                                             }
-                                            _ => (),
                                         }
                                     }
-                                    &non_default_parameters
+                                    &self.parameters.0[0..default_from]
                                 }
                             }
                         } else {
diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs
index 22884522a8..61af5f0645 100644
--- a/crates/ra_hir_ty/src/infer/expr.rs
+++ b/crates/ra_hir_ty/src/infer/expr.rs
@@ -785,7 +785,11 @@ impl<'a> InferenceContext<'a> {
         for &check_closures in &[false, true] {
             let param_iter = param_tys.iter().cloned().chain(repeat(Ty::Unknown));
             for (&arg, param_ty) in args.iter().zip(param_iter) {
-                let is_closure = matches!(&self.body[arg], Expr::Lambda { .. });
+                let is_closure = match &self.body[arg] {
+                    Expr::Lambda { .. } => true,
+                    _ => false,
+                };
+
                 if is_closure != check_closures {
                     continue;
                 }
diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs
index c9513b752a..4141581393 100644
--- a/crates/ra_hir_ty/src/lib.rs
+++ b/crates/ra_hir_ty/src/lib.rs
@@ -620,11 +620,17 @@ pub enum GenericPredicate {
 
 impl GenericPredicate {
     pub fn is_error(&self) -> bool {
-        matches!(self, GenericPredicate::Error)
+        match self {
+            GenericPredicate::Error => true,
+            _ => false,
+        }
     }
 
     pub fn is_implemented(&self) -> bool {
-        matches!(self, GenericPredicate::Implemented(_))
+        match self {
+            GenericPredicate::Implemented(_) => true,
+            _ => false,
+        }
     }
 
     pub fn trait_ref(&self, db: &dyn HirDatabase) -> Option<TraitRef> {
diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs
index d5154f436e..3dc154e92b 100644
--- a/crates/ra_hir_ty/src/lower.rs
+++ b/crates/ra_hir_ty/src/lower.rs
@@ -578,11 +578,13 @@ fn substs_from_path_segment(
     // (i.e. defaults aren't used).
     if !infer_args || had_explicit_args {
         if let Some(def_generic) = def_generic {
-            let default_substs = ctx.db.generic_defaults(def_generic);
-            assert_eq!(total_len, default_substs.len());
+            let defaults = ctx.db.generic_defaults(def_generic);
+            assert_eq!(total_len, defaults.len());
 
-            for default_ty in default_substs.iter().skip(substs.len()) {
-                substs.push(default_ty.clone());
+            for default_ty in defaults.iter().skip(substs.len()) {
+                // each default can depend on the previous parameters
+                let substs_so_far = Substs(substs.clone().into());
+                substs.push(default_ty.clone().subst(&substs_so_far));
             }
         }
     }
@@ -945,17 +947,42 @@ pub(crate) fn generic_predicates_query(
 }
 
 /// Resolve the default type params from generics
-pub(crate) fn generic_defaults_query(db: &dyn HirDatabase, def: GenericDefId) -> Substs {
+pub(crate) fn generic_defaults_query(
+    db: &dyn HirDatabase,
+    def: GenericDefId,
+) -> Arc<[Binders<Ty>]> {
     let resolver = def.resolver(db.upcast());
-    let ctx = TyLoweringContext::new(db, &resolver);
+    let ctx =
+        TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable);
     let generic_params = generics(db.upcast(), def);
 
     let defaults = generic_params
         .iter()
-        .map(|(_idx, p)| p.default.as_ref().map_or(Ty::Unknown, |t| Ty::from_hir(&ctx, t)))
+        .enumerate()
+        .map(|(idx, (_, p))| {
+            let mut ty = p.default.as_ref().map_or(Ty::Unknown, |t| Ty::from_hir(&ctx, t));
+
+            // Each default can only refer to previous parameters.
+            ty.walk_mut_binders(
+                &mut |ty, binders| match ty {
+                    Ty::Bound(BoundVar { debruijn, index }) if *debruijn == binders => {
+                        if *index >= idx {
+                            // type variable default referring to parameter coming
+                            // after it. This is forbidden (FIXME: report
+                            // diagnostic)
+                            *ty = Ty::Unknown;
+                        }
+                    }
+                    _ => {}
+                },
+                DebruijnIndex::INNERMOST,
+            );
+
+            Binders::new(idx, ty)
+        })
         .collect();
 
-    Substs(defaults)
+    defaults
 }
 
 fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig {
diff --git a/crates/ra_ide/src/inlay_hints.rs b/crates/ra_ide/src/inlay_hints.rs
index c876525551..98fb344861 100644
--- a/crates/ra_ide/src/inlay_hints.rs
+++ b/crates/ra_ide/src/inlay_hints.rs
@@ -313,8 +313,10 @@ fn get_string_representation(expr: &ast::Expr) -> Option<String> {
 }
 
 fn is_obvious_param(param_name: &str) -> bool {
-    let is_obvious_param_name =
-        matches!(param_name, "predicate" | "value" | "pat" | "rhs" | "other");
+    let is_obvious_param_name = match param_name {
+        "predicate" | "value" | "pat" | "rhs" | "other" => true,
+        _ => false,
+    };
     param_name.len() == 1 || is_obvious_param_name
 }
 
diff --git a/crates/ra_ide/src/join_lines.rs b/crates/ra_ide/src/join_lines.rs
index 6907c09e80..5036c1fb0c 100644
--- a/crates/ra_ide/src/join_lines.rs
+++ b/crates/ra_ide/src/join_lines.rs
@@ -165,7 +165,10 @@ fn join_single_use_tree(edit: &mut TextEditBuilder, token: &SyntaxToken) -> Opti
 }
 
 fn is_trailing_comma(left: SyntaxKind, right: SyntaxKind) -> bool {
-    matches!((left, right), (T![,], T![')']) | (T![,], T![']']))
+    match (left, right) {
+        (T![,], T![')']) | (T![,], T![']']) => true,
+        _ => false,
+    }
 }
 
 #[cfg(test)]
diff --git a/crates/ra_ide_db/src/symbol_index.rs b/crates/ra_ide_db/src/symbol_index.rs
index 5a09e7d1de..6929055b26 100644
--- a/crates/ra_ide_db/src/symbol_index.rs
+++ b/crates/ra_ide_db/src/symbol_index.rs
@@ -346,7 +346,10 @@ impl Query {
 }
 
 fn is_type(kind: SyntaxKind) -> bool {
-    matches!(kind, STRUCT_DEF | ENUM_DEF | TRAIT_DEF | TYPE_ALIAS_DEF)
+    match kind {
+        STRUCT_DEF | ENUM_DEF | TRAIT_DEF | TYPE_ALIAS_DEF => true,
+        _ => false,
+    }
 }
 
 /// The actual data that is stored in the index. It should be as compact as
diff --git a/crates/ra_mbe/src/parser.rs b/crates/ra_mbe/src/parser.rs
index 1e5dafbdf9..0341504326 100644
--- a/crates/ra_mbe/src/parser.rs
+++ b/crates/ra_mbe/src/parser.rs
@@ -137,7 +137,10 @@ fn eat_fragment_kind<'a>(
 }
 
 fn is_boolean_literal(lit: &tt::Literal) -> bool {
-    matches!(lit.text.as_str(), "true" | "false")
+    match lit.text.as_str() {
+        "true" | "false" => true,
+        _ => false,
+    }
 }
 
 fn parse_repeat(src: &mut TtIter) -> Result<(Option<Separator>, RepeatKind), ExpandError> {
diff --git a/crates/ra_parser/src/grammar.rs b/crates/ra_parser/src/grammar.rs
index caedeead08..293baecf6a 100644
--- a/crates/ra_parser/src/grammar.rs
+++ b/crates/ra_parser/src/grammar.rs
@@ -73,7 +73,10 @@ pub(crate) mod fragments {
     // Parse a meta item , which excluded [], e.g : #[ MetaItem ]
     pub(crate) fn meta_item(p: &mut Parser) {
         fn is_delimiter(p: &mut Parser) -> bool {
-            matches!(p.current(), T!['{'] | T!['('] | T!['['])
+            match p.current() {
+                T!['{'] | T!['('] | T!['['] => true,
+                _ => false,
+            }
         }
 
         if is_delimiter(p) {
diff --git a/crates/ra_parser/src/grammar/paths.rs b/crates/ra_parser/src/grammar/paths.rs
index b503af1dc9..fd51189d59 100644
--- a/crates/ra_parser/src/grammar/paths.rs
+++ b/crates/ra_parser/src/grammar/paths.rs
@@ -41,7 +41,10 @@ fn path(p: &mut Parser, mode: Mode) {
     path_segment(p, mode, true);
     let mut qual = path.complete(p, PATH);
     loop {
-        let use_tree = matches!(p.nth(2), T![*] | T!['{']);
+        let use_tree = match p.nth(2) {
+            T![*] | T!['{'] => true,
+            _ => false,
+        };
         if p.at(T![::]) && !use_tree {
             let path = qual.precede(p);
             p.bump(T![::]);
diff --git a/crates/ra_parser/src/grammar/type_params.rs b/crates/ra_parser/src/grammar/type_params.rs
index d1330d4b95..325d566ade 100644
--- a/crates/ra_parser/src/grammar/type_params.rs
+++ b/crates/ra_parser/src/grammar/type_params.rs
@@ -169,7 +169,10 @@ fn is_where_predicate(p: &mut Parser) -> bool {
 }
 
 fn is_where_clause_end(p: &mut Parser) -> bool {
-    matches!(p.current(), T!['{'] | T![;] | T![=])
+    match p.current() {
+        T!['{'] | T![;] | T![=] => true,
+        _ => false,
+    }
 }
 
 fn where_predicate(p: &mut Parser) {
diff --git a/crates/ra_parser/src/syntax_kind.rs b/crates/ra_parser/src/syntax_kind.rs
index 63204436c3..8d6bd057b3 100644
--- a/crates/ra_parser/src/syntax_kind.rs
+++ b/crates/ra_parser/src/syntax_kind.rs
@@ -20,6 +20,9 @@ impl From<SyntaxKind> for u16 {
 
 impl SyntaxKind {
     pub fn is_trivia(self) -> bool {
-        matches!(self, SyntaxKind::WHITESPACE | SyntaxKind::COMMENT)
+        match self {
+            SyntaxKind::WHITESPACE | SyntaxKind::COMMENT => true,
+            _ => false,
+        }
     }
 }
diff --git a/crates/ra_syntax/src/ast/expr_extensions.rs b/crates/ra_syntax/src/ast/expr_extensions.rs
index db5438d687..7771d67595 100644
--- a/crates/ra_syntax/src/ast/expr_extensions.rs
+++ b/crates/ra_syntax/src/ast/expr_extensions.rs
@@ -399,7 +399,10 @@ impl ast::BlockExpr {
             Some(it) => it,
             None => return true,
         };
-        !matches!(parent.kind(), FN_DEF | IF_EXPR | WHILE_EXPR | LOOP_EXPR | EFFECT_EXPR)
+        match parent.kind() {
+            FN_DEF | IF_EXPR | WHILE_EXPR | LOOP_EXPR | EFFECT_EXPR => false,
+            _ => true,
+        }
     }
 }
 
diff --git a/crates/ra_syntax/src/ast/extensions.rs b/crates/ra_syntax/src/ast/extensions.rs
index 662c6f73ee..98c38d0095 100644
--- a/crates/ra_syntax/src/ast/extensions.rs
+++ b/crates/ra_syntax/src/ast/extensions.rs
@@ -459,16 +459,16 @@ impl ast::RangePat {
 
 impl ast::TokenTree {
     pub fn left_delimiter_token(&self) -> Option<SyntaxToken> {
-        self.syntax()
-            .first_child_or_token()?
-            .into_token()
-            .filter(|it| matches!(it.kind(), T!['{'] | T!['('] | T!['[']))
+        self.syntax().first_child_or_token()?.into_token().filter(|it| match it.kind() {
+            T!['{'] | T!['('] | T!['['] => true,
+            _ => false,
+        })
     }
 
     pub fn right_delimiter_token(&self) -> Option<SyntaxToken> {
-        self.syntax()
-            .last_child_or_token()?
-            .into_token()
-            .filter(|it| matches!(it.kind(), T!['}'] | T![')'] | T![']']))
+        self.syntax().last_child_or_token()?.into_token().filter(|it| match it.kind() {
+            T!['}'] | T![')'] | T![']'] => true,
+            _ => false,
+        })
     }
 }
diff --git a/crates/ra_syntax/src/parsing/reparsing.rs b/crates/ra_syntax/src/parsing/reparsing.rs
index ed5a42ea38..edbc190f85 100644
--- a/crates/ra_syntax/src/parsing/reparsing.rs
+++ b/crates/ra_syntax/src/parsing/reparsing.rs
@@ -120,7 +120,10 @@ fn get_text_after_edit(element: SyntaxElement, edit: &Indel) -> String {
 }
 
 fn is_contextual_kw(text: &str) -> bool {
-    matches!(text, "auto" | "default" | "union")
+    match text {
+        "auto" | "default" | "union" => true,
+        _ => false,
+    }
 }
 
 fn find_reparsable_node(node: &SyntaxNode, range: TextRange) -> Option<(SyntaxNode, Reparser)> {
diff --git a/crates/ra_tt/src/buffer.rs b/crates/ra_tt/src/buffer.rs
index 02c771f70f..5967f44cd0 100644
--- a/crates/ra_tt/src/buffer.rs
+++ b/crates/ra_tt/src/buffer.rs
@@ -105,7 +105,10 @@ impl<'a> Eq for Cursor<'a> {}
 impl<'a> Cursor<'a> {
     /// Check whether it is eof
     pub fn eof(self) -> bool {
-        matches!(self.buffer.entry(&self.ptr), None | Some(Entry::End(None)))
+        match self.buffer.entry(&self.ptr) {
+            None | Some(Entry::End(None)) => true,
+            _ => false,
+        }
     }
 
     /// If the cursor is pointing at the end of a subtree, returns
diff --git a/crates/rust-analyzer/src/cli.rs b/crates/rust-analyzer/src/cli.rs
index c5faec83a9..39ce779008 100644
--- a/crates/rust-analyzer/src/cli.rs
+++ b/crates/rust-analyzer/src/cli.rs
@@ -28,10 +28,16 @@ pub enum Verbosity {
 
 impl Verbosity {
     pub fn is_verbose(self) -> bool {
-        matches!(self, Verbosity::Verbose | Verbosity::Spammy)
+        match self {
+            Verbosity::Verbose | Verbosity::Spammy => true,
+            _ => false,
+        }
     }
     pub fn is_spammy(self) -> bool {
-        matches!(self, Verbosity::Spammy)
+        match self {
+            Verbosity::Spammy => true,
+            _ => false,
+        }
     }
 }
 
diff --git a/crates/rust-analyzer/src/cli/analysis_bench.rs b/crates/rust-analyzer/src/cli/analysis_bench.rs
index 930375d3ef..4fe99ff680 100644
--- a/crates/rust-analyzer/src/cli/analysis_bench.rs
+++ b/crates/rust-analyzer/src/cli/analysis_bench.rs
@@ -78,7 +78,10 @@ pub fn analysis_bench(
             }
         }
         BenchWhat::Complete(pos) | BenchWhat::GotoDef(pos) => {
-            let is_completion = matches!(what, BenchWhat::Complete(..));
+            let is_completion = match what {
+                BenchWhat::Complete(..) => true,
+                _ => false,
+            };
 
             let offset = host
                 .analysis()
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index 9fd16ef3b4..e5194fe41a 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -216,11 +216,7 @@ impl GlobalState {
                         flycheck::Progress::DidCheckCrate(target) => {
                             (Progress::Report, Some(target))
                         }
-                        flycheck::Progress::DidCancel => (Progress::End, None),
-                        flycheck::Progress::DidFinish(result) => {
-                            if let Err(err) = result {
-                                log::error!("cargo check failed: {}", err)
-                            }
+                        flycheck::Progress::DidFinish | flycheck::Progress::DidCancel => {
                             (Progress::End, None)
                         }
                     };
diff --git a/crates/vfs-notify/src/lib.rs b/crates/vfs-notify/src/lib.rs
index b1ea298ae5..25ba8d7982 100644
--- a/crates/vfs-notify/src/lib.rs
+++ b/crates/vfs-notify/src/lib.rs
@@ -10,7 +10,7 @@ mod include;
 
 use std::convert::{TryFrom, TryInto};
 
-use crossbeam_channel::{select, unbounded, Receiver, Sender};
+use crossbeam_channel::{select, unbounded, Receiver};
 use notify::{RecommendedWatcher, RecursiveMode, Watcher};
 use paths::{AbsPath, AbsPathBuf};
 use rustc_hash::FxHashSet;
@@ -22,8 +22,8 @@ use crate::include::Include;
 #[derive(Debug)]
 pub struct NotifyHandle {
     // Relative order of fields below is significant.
-    sender: Sender<Message>,
-    thread: jod_thread::JoinHandle,
+    sender: crossbeam_channel::Sender<Message>,
+    _thread: jod_thread::JoinHandle,
 }
 
 #[derive(Debug)]
@@ -37,7 +37,7 @@ impl loader::Handle for NotifyHandle {
         let actor = NotifyActor::new(sender);
         let (sender, receiver) = unbounded::<Message>();
         let thread = jod_thread::spawn(move || actor.run(receiver));
-        NotifyHandle { sender, thread }
+        NotifyHandle { sender, _thread: thread }
     }
     fn set_config(&mut self, config: loader::Config) {
         self.sender.send(Message::Config(config)).unwrap()


Test patch:
diff --git a/crates/ra_hir_ty/src/tests/simple.rs b/crates/ra_hir_ty/src/tests/simple.rs
index cd919466f4..5e3f2bd3c8 100644
--- a/crates/ra_hir_ty/src/tests/simple.rs
+++ b/crates/ra_hir_ty/src/tests/simple.rs
@@ -2152,3 +2152,48 @@ fn test() {
     "###
     );
 }
+
+#[test]
+fn generic_default_depending_on_other_type_arg() {
+    assert_snapshot!(
+        infer(r#"
+struct Thing<T = u128, F = fn() -> T> { t: T }
+
+fn test(t1: Thing<u32>, t2: Thing) {
+    t1;
+    t2;
+    Thing::<_> { t: 1u32 };
+}
+"#),
+        // FIXME: the {unknown} is a bug
+        @r###"
+    56..58 't1': Thing<u32, fn() -> u32>
+    72..74 't2': Thing<u128, fn() -> u128>
+    83..130 '{     ...2 }; }': ()
+    89..91 't1': Thing<u32, fn() -> u32>
+    97..99 't2': Thing<u128, fn() -> u128>
+    105..127 'Thing:...1u32 }': Thing<u32, fn() -> {unknown}>
+    121..125 '1u32': u32
+    "###
+    );
+}
+
+#[test]
+fn generic_default_depending_on_other_type_arg_forward() {
+    assert_snapshot!(
+        infer(r#"
+struct Thing<F = fn() -> T, T = u128> { t: T }
+
+fn test(t1: Thing) {
+    t1;
+}
+"#),
+        // the {unknown} here is intentional, as defaults are not allowed to
+        // refer to type parameters coming later
+        @r###"
+    56..58 't1': Thing<fn() -> {unknown}, u128>
+    67..78 '{     t1; }': ()
+    73..75 't1': Thing<fn() -> {unknown}, u128>
+    "###
+    );
+}