From 619a8185a607b216c64b58d230c3949ccef98a37 Mon Sep 17 00:00:00 2001
From: Florian Diebold <flodiebold@gmail.com>
Date: Sat, 7 Sep 2019 21:03:03 +0200
Subject: [PATCH 1/4] Give closures types

---
 crates/ra_hir/src/code_model.rs      | 20 +++++++++++++++++++
 crates/ra_hir/src/ty.rs              | 23 ++++++++++++++++++++-
 crates/ra_hir/src/ty/infer.rs        | 22 ++++++++++++++++----
 crates/ra_hir/src/ty/tests.rs        | 30 +++++++++++++---------------
 crates/ra_hir/src/ty/traits/chalk.rs |  4 ++++
 5 files changed, 78 insertions(+), 21 deletions(-)

diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
index 12399c6ac45..99c247a0b29 100644
--- a/crates/ra_hir/src/code_model.rs
+++ b/crates/ra_hir/src/code_model.rs
@@ -551,6 +551,14 @@ impl DefWithBody {
             DefWithBody::Static(s) => s.resolver(db),
         }
     }
+
+    pub(crate) fn krate(self, db: &impl HirDatabase) -> Option<Crate> {
+        match self {
+            DefWithBody::Const(c) => c.krate(db),
+            DefWithBody::Function(f) => f.krate(db),
+            DefWithBody::Static(s) => s.krate(db),
+        }
+    }
 }
 
 pub trait HasBody: Copy {
@@ -671,6 +679,10 @@ impl Function {
         self.id.module(db)
     }
 
+    pub fn krate(self, db: &impl DefDatabase) -> Option<Crate> {
+        self.module(db).krate(db)
+    }
+
     pub fn name(self, db: &impl HirDatabase) -> Name {
         self.data(db).name.clone()
     }
@@ -745,6 +757,10 @@ impl Const {
         self.id.module(db)
     }
 
+    pub fn krate(self, db: &impl DefDatabase) -> Option<Crate> {
+        self.module(db).krate(db)
+    }
+
     pub fn data(self, db: &impl HirDatabase) -> Arc<ConstData> {
         db.const_data(self)
     }
@@ -824,6 +840,10 @@ impl Static {
         self.id.module(db)
     }
 
+    pub fn krate(self, db: &impl DefDatabase) -> Option<Crate> {
+        self.module(db).krate(db)
+    }
+
     pub fn data(self, db: &impl HirDatabase) -> Arc<ConstData> {
         db.static_data(self)
     }
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index 36bfb10cef6..e6ecbe1ea7f 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -16,7 +16,10 @@ use std::ops::Deref;
 use std::sync::Arc;
 use std::{fmt, mem};
 
-use crate::{db::HirDatabase, type_ref::Mutability, Adt, GenericParams, Name, Trait, TypeAlias};
+use crate::{
+    db::HirDatabase, expr::ExprId, type_ref::Mutability, Adt, DefWithBody, GenericParams, Name,
+    Trait, TypeAlias,
+};
 use display::{HirDisplay, HirFormatter};
 
 pub(crate) use autoderef::autoderef;
@@ -100,6 +103,12 @@ pub enum TypeCtor {
     /// couldn't find a better representation.  In that case, we generate
     /// an **application type** like `(Iterator::Item)<T>`.
     AssociatedType(TypeAlias),
+
+    /// The type of a specific closure.
+    ///
+    /// The closure signature is stored in a `FnPtr` type in the first type
+    /// parameter.
+    Closure { def: DefWithBody, expr: ExprId },
 }
 
 /// A nominal type with (maybe 0) type parameters. This might be a primitive
@@ -481,6 +490,10 @@ impl Ty {
                     let sig = db.callable_item_signature(def);
                     Some(sig.subst(&a_ty.parameters))
                 }
+                TypeCtor::Closure { .. } => {
+                    let sig_param = &a_ty.parameters[0];
+                    sig_param.callable_sig(db)
+                }
                 _ => None,
             },
             _ => None,
@@ -720,6 +733,14 @@ impl HirDisplay for ApplicationTy {
                     write!(f, ">")?;
                 }
             }
+            TypeCtor::Closure { .. } => {
+                let sig = self.parameters[0]
+                    .callable_sig(f.db)
+                    .expect("first closure parameter should contain signature");
+                write!(f, "|")?;
+                f.write_joined(sig.params(), ", ")?;
+                write!(f, "| -> {}", sig.ret().display(f.db))?;
+            }
         }
         Ok(())
     }
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs
index 81a8623bf69..c04f2a0c468 100644
--- a/crates/ra_hir/src/ty/infer.rs
+++ b/crates/ra_hir/src/ty/infer.rs
@@ -885,18 +885,32 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
             Expr::Lambda { body, args, arg_types } => {
                 assert_eq!(args.len(), arg_types.len());
 
+                let mut sig_tys = Vec::new();
+
                 for (arg_pat, arg_type) in args.iter().zip(arg_types.iter()) {
                     let expected = if let Some(type_ref) = arg_type {
                         self.make_ty(type_ref)
                     } else {
                         Ty::Unknown
                     };
-                    self.infer_pat(*arg_pat, &expected, BindingMode::default());
+                    let arg_ty = self.infer_pat(*arg_pat, &expected, BindingMode::default());
+                    sig_tys.push(arg_ty);
                 }
 
-                // FIXME: infer lambda type etc.
-                let _body_ty = self.infer_expr(*body, &Expectation::none());
-                Ty::Unknown
+                // add return type
+                let ret_ty = self.new_type_var();
+                sig_tys.push(ret_ty.clone());
+                let sig_ty = Ty::apply(
+                    TypeCtor::FnPtr { num_args: sig_tys.len() as u16 - 1 },
+                    sig_tys.into(),
+                );
+                let closure_ty = Ty::apply_one(
+                    TypeCtor::Closure { def: self.body.owner(), expr: tgt_expr },
+                    sig_ty,
+                );
+
+                self.infer_expr(*body, &Expectation::has_type(ret_ty));
+                closure_ty
             }
             Expr::Call { callee, args } => {
                 let callee_ty = self.infer_expr(*callee, &Expectation::none());
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index 3ac1fbdd50d..eb8770ec4ff 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -1077,7 +1077,6 @@ fn test(x: &i32) {
 }
 "#),
         @r###"
-
     [9; 10) 'x': &i32
     [18; 369) '{     ...o_x; }': ()
     [28; 29) 'y': &i32
@@ -1107,8 +1106,8 @@ fn test(x: &i32) {
     [177; 205) '{     ...     }': ()
     [191; 192) 'h': {unknown}
     [195; 198) 'val': {unknown}
-    [215; 221) 'lambda': {unknown}
-    [224; 256) '|a: u6...b; c }': {unknown}
+    [215; 221) 'lambda': |u64, u64, i32| -> i32
+    [224; 256) '|a: u6...b; c }': |u64, u64, i32| -> i32
     [225; 226) 'a': u64
     [233; 234) 'b': u64
     [236; 237) 'c': i32
@@ -2836,12 +2835,11 @@ fn test() -> u64 {
 }
 "#),
         @r###"
-
     [44; 102) '{     ...0(2) }': u64
     [54; 55) 'a': S
     [58; 59) 'S': S(fn(u32) -> u64) -> S
     [58; 68) 'S(|i| 2*i)': S
-    [60; 67) '|i| 2*i': fn(u32) -> u64
+    [60; 67) '|i| 2*i': |i32| -> i32
     [61; 62) 'i': i32
     [64; 65) '2': i32
     [64; 67) '2*i': i32
@@ -4019,20 +4017,20 @@ fn test() {
     [188; 192) '1i32': i32
     [199; 200) 'x': Option<i32>
     [199; 215) 'x.map(...v + 1)': {unknown}
-    [205; 214) '|v| v + 1': {unknown}
+    [205; 214) '|v| v + 1': |{unknown}| -> i32
     [206; 207) 'v': {unknown}
     [209; 210) 'v': {unknown}
     [209; 214) 'v + 1': i32
     [213; 214) '1': i32
     [221; 222) 'x': Option<i32>
     [221; 237) 'x.map(... 1u64)': {unknown}
-    [227; 236) '|_v| 1u64': {unknown}
+    [227; 236) '|_v| 1u64': |{unknown}| -> u64
     [228; 230) '_v': {unknown}
     [232; 236) '1u64': u64
     [247; 248) 'y': Option<i64>
     [264; 265) 'x': Option<i32>
     [264; 277) 'x.map(|_v| 1)': Option<i64>
-    [270; 276) '|_v| 1': {unknown}
+    [270; 276) '|_v| 1': |{unknown}| -> i32
     [271; 273) '_v': {unknown}
     [275; 276) '1': i32
     "###
@@ -4060,17 +4058,17 @@ fn test<F: FnOnce(u32) -> u64>(f: F) {
     [85; 86) 'f': F
     [85; 89) 'f(1)': {unknown}
     [87; 88) '1': i32
-    [99; 100) 'g': {unknown}
-    [103; 112) '|v| v + 1': {unknown}
-    [104; 105) 'v': {unknown}
-    [107; 108) 'v': {unknown}
+    [99; 100) 'g': |u64| -> i32
+    [103; 112) '|v| v + 1': |u64| -> i32
+    [104; 105) 'v': u64
+    [107; 108) 'v': u64
     [107; 112) 'v + 1': i32
     [111; 112) '1': i32
-    [118; 119) 'g': {unknown}
-    [118; 125) 'g(1u64)': {unknown}
+    [118; 119) 'g': |u64| -> i32
+    [118; 125) 'g(1u64)': i32
     [120; 124) '1u64': u64
-    [135; 136) 'h': {unknown}
-    [139; 152) '|v| 1u128 + v': {unknown}
+    [135; 136) 'h': |u128| -> u128
+    [139; 152) '|v| 1u128 + v': |u128| -> u128
     [140; 141) 'v': u128
     [143; 148) '1u128': u128
     [143; 152) '1u128 + v': u128
diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs
index 46215602165..34e623931ea 100644
--- a/crates/ra_hir/src/ty/traits/chalk.rs
+++ b/crates/ra_hir/src/ty/traits/chalk.rs
@@ -571,6 +571,10 @@ pub(crate) fn struct_datum_query(
                 type_alias.krate(db) != Some(krate),
             )
         }
+        TypeCtor::Closure { def, .. } => {
+            let upstream = def.krate(db) != Some(krate);
+            (1, vec![], upstream)
+        }
     };
     let flags = chalk_rust_ir::StructFlags {
         upstream,

From 3b06faad26fdb1485c542970374ff8bbcb0e01c4 Mon Sep 17 00:00:00 2001
From: Florian Diebold <flodiebold@gmail.com>
Date: Mon, 9 Sep 2019 22:10:58 +0200
Subject: [PATCH 2/4] Make closures impl closure traits

---
 crates/ra_hir/src/db.rs              |   6 +-
 crates/ra_hir/src/ty/tests.rs        |  55 +++++------
 crates/ra_hir/src/ty/traits.rs       |  36 +++++++-
 crates/ra_hir/src/ty/traits/chalk.rs | 132 +++++++++++++++++++++++++--
 4 files changed, 188 insertions(+), 41 deletions(-)

diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs
index 05259dcbb7e..2b20ae02b08 100644
--- a/crates/ra_hir/src/db.rs
+++ b/crates/ra_hir/src/db.rs
@@ -13,8 +13,8 @@ use crate::{
     nameres::{CrateDefMap, ImportSourceMap, Namespace, RawItems},
     traits::TraitData,
     ty::{
-        method_resolution::CrateImplBlocks, CallableDef, FnSig, GenericPredicate, InferenceResult,
-        Substs, Ty, TypableDef, TypeCtor,
+        method_resolution::CrateImplBlocks, traits::Impl, CallableDef, FnSig, GenericPredicate,
+        InferenceResult, Substs, Ty, TypableDef, TypeCtor,
     },
     type_alias::TypeAliasData,
     AstIdMap, Const, ConstData, Crate, DefWithBody, Enum, ErasedFileAstId, ExprScopes, FnData,
@@ -50,7 +50,7 @@ pub trait InternDatabase: SourceDatabase {
     #[salsa::interned]
     fn intern_type_ctor(&self, type_ctor: TypeCtor) -> ids::TypeCtorId;
     #[salsa::interned]
-    fn intern_impl_block(&self, impl_block: ImplBlock) -> ids::GlobalImplId;
+    fn intern_impl(&self, impl_: Impl) -> ids::GlobalImplId;
 }
 
 /// This database has access to source code, so queries here are not really
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index eb8770ec4ff..13090f89ddc 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -3990,6 +3990,7 @@ fn test<F: FnOnce(u32, u64) -> u128>(f: F) {
 fn closure_1() {
     assert_snapshot!(
         infer(r#"
+#[lang = "fn_once"]
 trait FnOnce<Args> {
     type Output;
 }
@@ -4000,39 +4001,39 @@ impl<T> Option<T> {
 }
 
 fn test() {
-    let x = Option::Some(1i32);
+    let x = Option::Some(1u32);
     x.map(|v| v + 1);
     x.map(|_v| 1u64);
     let y: Option<i64> = x.map(|_v| 1);
 }
 "#),
         @r###"
-    [128; 132) 'self': Option<T>
-    [134; 135) 'f': F
-    [145; 147) '{}': ()
-    [161; 280) '{     ... 1); }': ()
-    [171; 172) 'x': Option<i32>
-    [175; 187) 'Option::Some': Some<i32>(T) -> Option<T>
-    [175; 193) 'Option...(1i32)': Option<i32>
-    [188; 192) '1i32': i32
-    [199; 200) 'x': Option<i32>
-    [199; 215) 'x.map(...v + 1)': {unknown}
-    [205; 214) '|v| v + 1': |{unknown}| -> i32
-    [206; 207) 'v': {unknown}
-    [209; 210) 'v': {unknown}
-    [209; 214) 'v + 1': i32
-    [213; 214) '1': i32
-    [221; 222) 'x': Option<i32>
-    [221; 237) 'x.map(... 1u64)': {unknown}
-    [227; 236) '|_v| 1u64': |{unknown}| -> u64
-    [228; 230) '_v': {unknown}
-    [232; 236) '1u64': u64
-    [247; 248) 'y': Option<i64>
-    [264; 265) 'x': Option<i32>
-    [264; 277) 'x.map(|_v| 1)': Option<i64>
-    [270; 276) '|_v| 1': |{unknown}| -> i32
-    [271; 273) '_v': {unknown}
-    [275; 276) '1': i32
+    [148; 152) 'self': Option<T>
+    [154; 155) 'f': F
+    [165; 167) '{}': ()
+    [181; 300) '{     ... 1); }': ()
+    [191; 192) 'x': Option<u32>
+    [195; 207) 'Option::Some': Some<u32>(T) -> Option<T>
+    [195; 213) 'Option...(1u32)': Option<u32>
+    [208; 212) '1u32': u32
+    [219; 220) 'x': Option<u32>
+    [219; 235) 'x.map(...v + 1)': {unknown}
+    [225; 234) '|v| v + 1': |u32| -> i32
+    [226; 227) 'v': u32
+    [229; 230) 'v': u32
+    [229; 234) 'v + 1': i32
+    [233; 234) '1': i32
+    [241; 242) 'x': Option<u32>
+    [241; 257) 'x.map(... 1u64)': {unknown}
+    [247; 256) '|_v| 1u64': |u32| -> u64
+    [248; 250) '_v': u32
+    [252; 256) '1u64': u64
+    [267; 268) 'y': Option<i64>
+    [284; 285) 'x': Option<u32>
+    [284; 297) 'x.map(|_v| 1)': Option<i64>
+    [290; 296) '|_v| 1': |u32| -> i32
+    [291; 293) '_v': u32
+    [295; 296) '1': i32
     "###
     );
 }
diff --git a/crates/ra_hir/src/ty/traits.rs b/crates/ra_hir/src/ty/traits.rs
index c0c132809b5..8e256341d32 100644
--- a/crates/ra_hir/src/ty/traits.rs
+++ b/crates/ra_hir/src/ty/traits.rs
@@ -9,7 +9,7 @@ use ra_prof::profile;
 use rustc_hash::FxHashSet;
 
 use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty, TypeWalk};
-use crate::{db::HirDatabase, Crate, ImplBlock, Trait};
+use crate::{db::HirDatabase, expr::ExprId, Crate, DefWithBody, ImplBlock, Trait};
 
 use self::chalk::{from_chalk, ToChalk};
 
@@ -252,3 +252,37 @@ pub enum Guidance {
     /// There's no useful information to feed back to type inference
     Unknown,
 }
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+pub enum FnTrait {
+    FnOnce,
+    FnMut,
+    Fn,
+}
+
+impl FnTrait {
+    fn lang_item_name(self) -> &'static str {
+        match self {
+            FnTrait::FnOnce => "fn_once",
+            FnTrait::FnMut => "fn_mut",
+            FnTrait::Fn => "fn",
+        }
+    }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct ClosureFnTraitImplData {
+    def: DefWithBody,
+    expr: ExprId,
+    fn_trait: FnTrait,
+}
+
+/// An impl. Usually this comes from an impl block, but some built-in types get
+/// synthetic impls.
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub enum Impl {
+    /// A normal impl from an impl block.
+    ImplBlock(ImplBlock),
+    /// Closure types implement the Fn traits synthetically.
+    ClosureFnTraitImpl(ClosureFnTraitImplData),
+}
diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs
index 34e623931ea..f229b1aef5b 100644
--- a/crates/ra_hir/src/ty/traits/chalk.rs
+++ b/crates/ra_hir/src/ty/traits/chalk.rs
@@ -12,7 +12,7 @@ use chalk_rust_ir::{AssociatedTyDatum, ImplDatum, StructDatum, TraitDatum};
 use ra_db::salsa::{InternId, InternKey};
 use test_utils::tested_by;
 
-use super::{Canonical, ChalkContext, Obligation};
+use super::{Canonical, ChalkContext, Impl, Obligation};
 use crate::{
     db::HirDatabase,
     generics::GenericDef,
@@ -111,7 +111,7 @@ impl ToChalk for Ty {
             }
             chalk_ir::Ty::ForAll(_) => unimplemented!(),
             chalk_ir::Ty::BoundVar(idx) => Ty::Bound(idx as u32),
-            chalk_ir::Ty::InferenceVar(_iv) => panic!("unexpected chalk infer ty"),
+            chalk_ir::Ty::InferenceVar(_iv) => Ty::Unknown,
         }
     }
 }
@@ -175,15 +175,15 @@ impl ToChalk for TypeCtor {
     }
 }
 
-impl ToChalk for ImplBlock {
+impl ToChalk for Impl {
     type Chalk = chalk_ir::ImplId;
 
     fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::ImplId {
-        db.intern_impl_block(self).into()
+        db.intern_impl(self).into()
     }
 
-    fn from_chalk(db: &impl HirDatabase, impl_id: chalk_ir::ImplId) -> ImplBlock {
-        db.lookup_intern_impl_block(impl_id.into())
+    fn from_chalk(db: &impl HirDatabase, impl_id: chalk_ir::ImplId) -> Impl {
+        db.lookup_intern_impl(impl_id.into())
     }
 }
 
@@ -388,19 +388,36 @@ where
     fn impls_for_trait(
         &self,
         trait_id: chalk_ir::TraitId,
-        _parameters: &[Parameter],
+        parameters: &[Parameter],
     ) -> Vec<ImplId> {
         debug!("impls_for_trait {:?}", trait_id);
         if trait_id == UNKNOWN_TRAIT {
             return Vec::new();
         }
         let trait_: Trait = from_chalk(self.db, trait_id);
-        let result: Vec<_> = self
+        let mut result: Vec<_> = self
             .db
             .impls_for_trait(self.krate, trait_)
             .iter()
-            .map(|impl_block| impl_block.to_chalk(self.db))
+            .copied()
+            .map(Impl::ImplBlock)
+            .map(|impl_| impl_.to_chalk(self.db))
             .collect();
+
+        let ty: Ty = from_chalk(self.db, parameters[0].assert_ty_ref().clone());
+        if let Ty::Apply(ApplicationTy { ctor: TypeCtor::Closure { def, expr }, .. }) = ty {
+            for fn_trait in
+                [super::FnTrait::FnOnce, super::FnTrait::FnMut, super::FnTrait::Fn].iter().copied()
+            {
+                if let Some(actual_trait) = get_fn_trait(self.db, self.krate, fn_trait) {
+                    if trait_ == actual_trait {
+                        let impl_ = super::ClosureFnTraitImplData { def, expr, fn_trait };
+                        result.push(Impl::ClosureFnTraitImpl(impl_).to_chalk(self.db));
+                    }
+                }
+            }
+        }
+
         debug!("impls_for_trait returned {} impls", result.len());
         result
     }
@@ -602,7 +619,21 @@ pub(crate) fn impl_datum_query(
 ) -> Arc<ImplDatum> {
     let _p = ra_prof::profile("impl_datum");
     debug!("impl_datum {:?}", impl_id);
-    let impl_block: ImplBlock = from_chalk(db, impl_id);
+    let impl_: Impl = from_chalk(db, impl_id);
+    match impl_ {
+        Impl::ImplBlock(impl_block) => impl_block_datum(db, krate, impl_id, impl_block),
+        Impl::ClosureFnTraitImpl(data) => {
+            closure_fn_trait_impl_datum(db, krate, impl_id, data).unwrap_or_else(invalid_impl_datum)
+        }
+    }
+}
+
+fn impl_block_datum(
+    db: &impl HirDatabase,
+    krate: Crate,
+    impl_id: ImplId,
+    impl_block: ImplBlock,
+) -> Arc<ImplDatum> {
     let generic_params = impl_block.generic_params(db);
     let bound_vars = Substs::bound_vars(&generic_params);
     let trait_ref = impl_block
@@ -661,6 +692,87 @@ pub(crate) fn impl_datum_query(
     Arc::new(impl_datum)
 }
 
+fn invalid_impl_datum() -> Arc<ImplDatum> {
+    let trait_ref = chalk_ir::TraitRef {
+        trait_id: UNKNOWN_TRAIT,
+        parameters: vec![chalk_ir::Ty::BoundVar(0).cast()],
+    };
+    let impl_datum_bound = chalk_rust_ir::ImplDatumBound {
+        trait_ref: chalk_rust_ir::PolarizedTraitRef::Positive(trait_ref),
+        where_clauses: Vec::new(),
+        associated_ty_values: Vec::new(),
+        impl_type: chalk_rust_ir::ImplType::External,
+    };
+    let impl_datum = ImplDatum { binders: make_binders(impl_datum_bound, 1) };
+    Arc::new(impl_datum)
+}
+
+fn closure_fn_trait_impl_datum(
+    db: &impl HirDatabase,
+    krate: Crate,
+    impl_id: ImplId,
+    data: super::ClosureFnTraitImplData,
+) -> Option<Arc<ImplDatum>> {
+    // for some closure |X, Y| -> Z:
+    // impl<T, U, V> Fn<(T, U)> for closure<fn(T, U) -> V> { Output = V }
+
+    let fn_once_trait = get_fn_trait(db, krate, super::FnTrait::FnOnce)?;
+    let trait_ = get_fn_trait(db, krate, data.fn_trait)?; // get corresponding fn trait
+
+    let num_args: u16 = match &db.body_hir(data.def)[data.expr] {
+        crate::expr::Expr::Lambda { args, .. } => args.len() as u16,
+        _ => {
+            log::warn!("closure for closure type {:?} not found", data);
+            0
+        }
+    };
+
+    let arg_ty = Ty::apply(
+        TypeCtor::Tuple { cardinality: num_args },
+        (0..num_args).map(|i| Ty::Bound(i.into())).collect::<Vec<_>>().into(),
+    );
+    let output_ty = Ty::Bound(num_args.into());
+    let sig_ty = Ty::apply(
+        TypeCtor::FnPtr { num_args },
+        (0..num_args + 1).map(|i| Ty::Bound(i.into())).collect::<Vec<_>>().into(),
+    );
+
+    let self_ty = Ty::apply_one(TypeCtor::Closure { def: data.def, expr: data.expr }, sig_ty);
+
+    let trait_ref = TraitRef { trait_, substs: vec![self_ty, arg_ty].into() };
+
+    let output_ty_id = fn_once_trait.associated_type_by_name(db, &crate::name::OUTPUT_TYPE)?;
+
+    let output_ty_value = chalk_rust_ir::AssociatedTyValue {
+        associated_ty_id: output_ty_id.to_chalk(db),
+        impl_id,
+        value: make_binders(
+            chalk_rust_ir::AssociatedTyValueBound { ty: output_ty.to_chalk(db) },
+            0,
+        ),
+    };
+
+    let impl_type = chalk_rust_ir::ImplType::External;
+
+    let impl_datum_bound = chalk_rust_ir::ImplDatumBound {
+        trait_ref: chalk_rust_ir::PolarizedTraitRef::Positive(trait_ref.to_chalk(db)),
+        where_clauses: Vec::new(),
+        associated_ty_values: vec![output_ty_value],
+        impl_type,
+    };
+    let impl_datum = ImplDatum { binders: make_binders(impl_datum_bound, num_args as usize + 1) };
+    Some(Arc::new(impl_datum))
+}
+
+fn get_fn_trait(db: &impl HirDatabase, krate: Crate, fn_trait: super::FnTrait) -> Option<Trait> {
+    let lang_items = db.lang_items(krate);
+    let target = lang_items.target(fn_trait.lang_item_name())?;
+    match target {
+        crate::lang_item::LangItemTarget::Trait(t) => Some(*t),
+        _ => None,
+    }
+}
+
 fn id_from_chalk<T: InternKey>(chalk_id: chalk_ir::RawId) -> T {
     T::from_intern_id(InternId::from(chalk_id.index))
 }

From a0aeb6e7ad7385811a4bb75577513339c9a9ed91 Mon Sep 17 00:00:00 2001
From: Florian Diebold <flodiebold@gmail.com>
Date: Tue, 24 Sep 2019 19:04:53 +0200
Subject: [PATCH 3/4] Make the closure_1 test work

---
 crates/ra_hir/src/ty/infer.rs  |  5 ++++
 crates/ra_hir/src/ty/tests.rs  | 54 +++++++++++++++++-----------------
 crates/ra_hir/src/ty/traits.rs |  8 +++++
 3 files changed, 40 insertions(+), 27 deletions(-)

diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs
index c04f2a0c468..4784fad8518 100644
--- a/crates/ra_hir/src/ty/infer.rs
+++ b/crates/ra_hir/src/ty/infer.rs
@@ -909,6 +909,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
                     sig_ty,
                 );
 
+                // Eagerly try to relate the closure type with the expected
+                // type, otherwise we often won't have enough information to
+                // infer the body.
+                self.coerce(&closure_ty, &expected.ty);
+
                 self.infer_expr(*body, &Expectation::has_type(ret_ty));
                 closure_ty
             }
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index 13090f89ddc..112b3d73f7c 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -3800,13 +3800,13 @@ fn test<T: Trait<Type = u32>>(x: T, y: impl Trait<Type = i64>) {
     [296; 299) 'get': fn get<T>(T) -> <T as Trait>::Type
     [296; 302) 'get(x)': {unknown}
     [300; 301) 'x': T
-    [308; 312) 'get2': fn get2<{unknown}, S<{unknown}>>(T) -> U
+    [308; 312) 'get2': fn get2<{unknown}, T>(T) -> U
     [308; 315) 'get2(x)': {unknown}
     [313; 314) 'x': T
     [321; 324) 'get': fn get<impl Trait<Type = i64>>(T) -> <T as Trait>::Type
     [321; 327) 'get(y)': {unknown}
     [325; 326) 'y': impl Trait<Type = i64>
-    [333; 337) 'get2': fn get2<{unknown}, S<{unknown}>>(T) -> U
+    [333; 337) 'get2': fn get2<{unknown}, impl Trait<Type = i64>>(T) -> U
     [333; 340) 'get2(y)': {unknown}
     [338; 339) 'y': impl Trait<Type = i64>
     [346; 349) 'get': fn get<S<u64>>(T) -> <T as Trait>::Type
@@ -3997,7 +3997,7 @@ trait FnOnce<Args> {
 
 enum Option<T> { Some(T), None }
 impl<T> Option<T> {
-    fn map<U, F: FnOnce(T) -> U>(self, f: F) -> U {}
+    fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Option<U> {}
 }
 
 fn test() {
@@ -4010,30 +4010,30 @@ fn test() {
         @r###"
     [148; 152) 'self': Option<T>
     [154; 155) 'f': F
-    [165; 167) '{}': ()
-    [181; 300) '{     ... 1); }': ()
-    [191; 192) 'x': Option<u32>
-    [195; 207) 'Option::Some': Some<u32>(T) -> Option<T>
-    [195; 213) 'Option...(1u32)': Option<u32>
-    [208; 212) '1u32': u32
-    [219; 220) 'x': Option<u32>
-    [219; 235) 'x.map(...v + 1)': {unknown}
-    [225; 234) '|v| v + 1': |u32| -> i32
-    [226; 227) 'v': u32
-    [229; 230) 'v': u32
-    [229; 234) 'v + 1': i32
-    [233; 234) '1': i32
-    [241; 242) 'x': Option<u32>
-    [241; 257) 'x.map(... 1u64)': {unknown}
-    [247; 256) '|_v| 1u64': |u32| -> u64
-    [248; 250) '_v': u32
-    [252; 256) '1u64': u64
-    [267; 268) 'y': Option<i64>
-    [284; 285) 'x': Option<u32>
-    [284; 297) 'x.map(|_v| 1)': Option<i64>
-    [290; 296) '|_v| 1': |u32| -> i32
-    [291; 293) '_v': u32
-    [295; 296) '1': i32
+    [173; 175) '{}': ()
+    [189; 308) '{     ... 1); }': ()
+    [199; 200) 'x': Option<u32>
+    [203; 215) 'Option::Some': Some<u32>(T) -> Option<T>
+    [203; 221) 'Option...(1u32)': Option<u32>
+    [216; 220) '1u32': u32
+    [227; 228) 'x': Option<u32>
+    [227; 243) 'x.map(...v + 1)': Option<u32>
+    [233; 242) '|v| v + 1': |u32| -> u32
+    [234; 235) 'v': u32
+    [237; 238) 'v': u32
+    [237; 242) 'v + 1': u32
+    [241; 242) '1': u32
+    [249; 250) 'x': Option<u32>
+    [249; 265) 'x.map(... 1u64)': Option<u64>
+    [255; 264) '|_v| 1u64': |u32| -> u64
+    [256; 258) '_v': u32
+    [260; 264) '1u64': u64
+    [275; 276) 'y': Option<i64>
+    [292; 293) 'x': Option<u32>
+    [292; 305) 'x.map(|_v| 1)': Option<i64>
+    [298; 304) '|_v| 1': |u32| -> i64
+    [299; 301) '_v': u32
+    [303; 304) '1': i64
     "###
     );
 }
diff --git a/crates/ra_hir/src/ty/traits.rs b/crates/ra_hir/src/ty/traits.rs
index 8e256341d32..d11dab29403 100644
--- a/crates/ra_hir/src/ty/traits.rs
+++ b/crates/ra_hir/src/ty/traits.rs
@@ -173,6 +173,14 @@ pub(crate) fn trait_solve_query(
 ) -> Option<Solution> {
     let _p = profile("trait_solve_query");
     debug!("trait_solve_query({})", goal.value.value.display(db));
+
+    if let Obligation::Projection(pred) = &goal.value.value {
+        if let Ty::Bound(_) = &pred.projection_ty.parameters[0] {
+            // Hack: don't ask Chalk to normalize with an unknown self type, it'll say that's impossible
+            return Some(Solution::Ambig(Guidance::Unknown));
+        }
+    }
+
     let canonical = goal.to_chalk(db).cast();
     // We currently don't deal with universes (I think / hope they're not yet
     // relevant for our use cases?)

From 6a8670665032f6103ca14e38ed9106126b20063d Mon Sep 17 00:00:00 2001
From: Florian Diebold <flodiebold@gmail.com>
Date: Tue, 24 Sep 2019 23:04:33 +0200
Subject: [PATCH 4/4] Implement the call argument checking order hack for
 closures

---
 crates/ra_hir/src/ty/infer.rs        | 36 +++++++++----
 crates/ra_hir/src/ty/tests.rs        | 80 ++++++++++++++++++++++++++++
 crates/ra_hir/src/ty/traits/chalk.rs |  4 +-
 3 files changed, 108 insertions(+), 12 deletions(-)

diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs
index 4784fad8518..378d2f829e1 100644
--- a/crates/ra_hir/src/ty/infer.rs
+++ b/crates/ra_hir/src/ty/infer.rs
@@ -790,11 +790,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
         };
         self.unify(&expected_receiver_ty, &actual_receiver_ty);
 
-        let param_iter = param_tys.into_iter().chain(repeat(Ty::Unknown));
-        for (arg, param_ty) in args.iter().zip(param_iter) {
-            let param_ty = self.normalize_associated_types_in(param_ty);
-            self.infer_expr(*arg, &Expectation::has_type(param_ty));
-        }
+        self.check_call_arguments(args, &param_tys);
         let ret_ty = self.normalize_associated_types_in(ret_ty);
         ret_ty
     }
@@ -928,11 +924,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
                     }
                 };
                 self.register_obligations_for_call(&callee_ty);
-                let param_iter = param_tys.into_iter().chain(repeat(Ty::Unknown));
-                for (arg, param_ty) in args.iter().zip(param_iter) {
-                    let param_ty = self.normalize_associated_types_in(param_ty);
-                    self.infer_expr(*arg, &Expectation::has_type(param_ty));
-                }
+                self.check_call_arguments(args, &param_tys);
                 let ret_ty = self.normalize_associated_types_in(ret_ty);
                 ret_ty
             }
@@ -1274,6 +1266,30 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
         ty
     }
 
+    fn check_call_arguments(&mut self, args: &[ExprId], param_tys: &[Ty]) {
+        // Quoting https://github.com/rust-lang/rust/blob/6ef275e6c3cb1384ec78128eceeb4963ff788dca/src/librustc_typeck/check/mod.rs#L3325 --
+        // We do this in a pretty awful way: first we type-check any arguments
+        // that are not closures, then we type-check the closures. This is so
+        // that we have more information about the types of arguments when we
+        // type-check the functions. This isn't really the right way to do this.
+        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 = match &self.body[arg] {
+                    Expr::Lambda { .. } => true,
+                    _ => false,
+                };
+
+                if is_closure != check_closures {
+                    continue;
+                }
+
+                let param_ty = self.normalize_associated_types_in(param_ty);
+                self.infer_expr(arg, &Expectation::has_type(param_ty));
+            }
+        }
+    }
+
     fn collect_const(&mut self, data: &ConstData) {
         self.return_ty = self.make_ty(data.type_ref());
     }
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index 112b3d73f7c..2872cd27bab 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -4078,6 +4078,86 @@ fn test<F: FnOnce(u32) -> u64>(f: F) {
     );
 }
 
+#[test]
+fn closure_as_argument_inference_order() {
+    assert_snapshot!(
+        infer(r#"
+#[lang = "fn_once"]
+trait FnOnce<Args> {
+    type Output;
+}
+
+fn foo1<T, U, F: FnOnce(T) -> U>(x: T, f: F) -> U {}
+fn foo2<T, U, F: FnOnce(T) -> U>(f: F, x: T) -> U {}
+
+struct S;
+impl S {
+    fn method(self) -> u64;
+
+    fn foo1<T, U, F: FnOnce(T) -> U>(self, x: T, f: F) -> U {}
+    fn foo2<T, U, F: FnOnce(T) -> U>(self, f: F, x: T) -> U {}
+}
+
+fn test() {
+    let x1 = foo1(S, |s| s.method());
+    let x2 = foo2(|s| s.method(), S);
+    let x3 = S.foo1(S, |s| s.method());
+    let x4 = S.foo2(|s| s.method(), S);
+}
+"#),
+        @r###"
+    [95; 96) 'x': T
+    [101; 102) 'f': F
+    [112; 114) '{}': ()
+    [148; 149) 'f': F
+    [154; 155) 'x': T
+    [165; 167) '{}': ()
+    [202; 206) 'self': S
+    [254; 258) 'self': S
+    [260; 261) 'x': T
+    [266; 267) 'f': F
+    [277; 279) '{}': ()
+    [317; 321) 'self': S
+    [323; 324) 'f': F
+    [329; 330) 'x': T
+    [340; 342) '{}': ()
+    [356; 515) '{     ... S); }': ()
+    [366; 368) 'x1': u64
+    [371; 375) 'foo1': fn foo1<S, u64, |S| -> u64>(T, F) -> U
+    [371; 394) 'foo1(S...hod())': u64
+    [376; 377) 'S': S
+    [379; 393) '|s| s.method()': |S| -> u64
+    [380; 381) 's': S
+    [383; 384) 's': S
+    [383; 393) 's.method()': u64
+    [404; 406) 'x2': u64
+    [409; 413) 'foo2': fn foo2<S, u64, |S| -> u64>(F, T) -> U
+    [409; 432) 'foo2(|...(), S)': u64
+    [414; 428) '|s| s.method()': |S| -> u64
+    [415; 416) 's': S
+    [418; 419) 's': S
+    [418; 428) 's.method()': u64
+    [430; 431) 'S': S
+    [442; 444) 'x3': u64
+    [447; 448) 'S': S
+    [447; 472) 'S.foo1...hod())': u64
+    [454; 455) 'S': S
+    [457; 471) '|s| s.method()': |S| -> u64
+    [458; 459) 's': S
+    [461; 462) 's': S
+    [461; 471) 's.method()': u64
+    [482; 484) 'x4': u64
+    [487; 488) 'S': S
+    [487; 512) 'S.foo2...(), S)': u64
+    [494; 508) '|s| s.method()': |S| -> u64
+    [495; 496) 's': S
+    [498; 499) 's': S
+    [498; 508) 's.method()': u64
+    [510; 511) 'S': S
+    "###
+    );
+}
+
 #[test]
 fn unselected_projection_in_trait_env_1() {
     let t = type_at(
diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs
index f229b1aef5b..d83706f8603 100644
--- a/crates/ra_hir/src/ty/traits/chalk.rs
+++ b/crates/ra_hir/src/ty/traits/chalk.rs
@@ -406,8 +406,8 @@ where
 
         let ty: Ty = from_chalk(self.db, parameters[0].assert_ty_ref().clone());
         if let Ty::Apply(ApplicationTy { ctor: TypeCtor::Closure { def, expr }, .. }) = ty {
-            for fn_trait in
-                [super::FnTrait::FnOnce, super::FnTrait::FnMut, super::FnTrait::Fn].iter().copied()
+            for &fn_trait in
+                [super::FnTrait::FnOnce, super::FnTrait::FnMut, super::FnTrait::Fn].iter()
             {
                 if let Some(actual_trait) = get_fn_trait(self.db, self.krate, fn_trait) {
                     if trait_ == actual_trait {