Repository: rust-analyzer/rust-analyzer
Pull request #1845 (2019-09-14 08:58:44)

Closure types
This adds types for closures and makes them implement the `Fn` traits (we don't currently care or try to infer `Fn` vs. `FnMut` vs. `FnOnce`; this would require move analysis, I think).

This requires some changes in Chalk; one is that we need to know the self type when asked for impls, so we can synthesize `Fn` trait impls for closures; but also there's a problem that prevents us from normalizing the closure output type correctly that I _think_ will be fixed on the Chalk side (basically, we ask too early and try to solve `Normalize(<?1 as FnOnce<(u32,)>>::Output => ?0)` -- note the variable in the self type -- and instead of an ambiguous answer, we get back that it can't be solved, so we don't try again. Niko mentioned he's making all goals where the self type is unconstrained flounder, which I think would mean this would be ambiguous).


Patch:
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
index 12399c6ac4..99c247a0b2 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/db.rs b/crates/ra_hir/src/db.rs
index 05259dcbb7..2b20ae02b0 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.rs b/crates/ra_hir/src/ty.rs
index 36bfb10cef..e6ecbe1ea7 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 81a8623bf6..378d2f829e 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
     }
@@ -885,18 +881,37 @@ 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,
+                );
+
+                // 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
             }
             Expr::Call { callee, args } => {
                 let callee_ty = self.infer_expr(*callee, &Expectation::none());
@@ -909,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
             }
@@ -1255,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/traits.rs b/crates/ra_hir/src/ty/traits.rs
index c0c132809b..d11dab2940 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};
 
@@ -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?)
@@ -252,3 +260,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 4621560216..d83706f860 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()
+            {
+                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
     }
@@ -571,6 +588,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,
@@ -598,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
@@ -657,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))
 }


Test patch:
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index 3ac1fbdd50..2872cd27ba 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
@@ -3802,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
@@ -3992,49 +3990,50 @@ fn test<F: FnOnce(u32, u64) -> u128>(f: F) {
 fn closure_1() {
     assert_snapshot!(
         infer(r#"
+#[lang = "fn_once"]
 trait FnOnce<Args> {
     type Output;
 }
 
 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() {
-    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}
-    [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}
-    [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}
-    [271; 273) '_v': {unknown}
-    [275; 276) '1': i32
+    [148; 152) 'self': Option<T>
+    [154; 155) 'f': F
+    [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
     "###
     );
 }
@@ -4060,17 +4059,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
@@ -4079,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(