about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--crates/hir-expand/src/name.rs1
-rw-r--r--crates/hir-ty/src/builder.rs17
-rw-r--r--crates/hir-ty/src/infer/expr.rs14
-rw-r--r--crates/hir-ty/src/infer/unify.rs25
-rw-r--r--crates/hir-ty/src/tests/method_resolution.rs9
-rw-r--r--crates/hir-ty/src/tests/traits.rs69
-rw-r--r--crates/hir/src/lib.rs39
-rw-r--r--crates/hir/src/source_analyzer.rs2
-rw-r--r--crates/ide-db/src/defs.rs2
-rw-r--r--crates/test-utils/src/minicore.rs18
10 files changed, 119 insertions, 77 deletions
diff --git a/crates/hir-expand/src/name.rs b/crates/hir-expand/src/name.rs
index b62f4fe7701..b3a71ca0a37 100644
--- a/crates/hir-expand/src/name.rs
+++ b/crates/hir-expand/src/name.rs
@@ -347,6 +347,7 @@ pub mod known {
         recursion_limit,
         feature,
         // known methods of lang items
+        call_once,
         eq,
         ne,
         ge,
diff --git a/crates/hir-ty/src/builder.rs b/crates/hir-ty/src/builder.rs
index d5ef0c22dec..8faef7bf71e 100644
--- a/crates/hir-ty/src/builder.rs
+++ b/crates/hir-ty/src/builder.rs
@@ -63,7 +63,7 @@ impl<D> TyBuilder<D> {
     }
 
     fn build_internal(self) -> (D, Substitution) {
-        assert_eq!(self.vec.len(), self.param_kinds.len());
+        assert_eq!(self.vec.len(), self.param_kinds.len(), "{:?}", &self.param_kinds);
         for (a, e) in self.vec.iter().zip(self.param_kinds.iter()) {
             self.assert_match_kind(a, e);
         }
@@ -282,6 +282,21 @@ impl TyBuilder<Tuple> {
         let (Tuple(size), subst) = self.build_internal();
         TyKind::Tuple(size, subst).intern(Interner)
     }
+
+    pub fn tuple_with<I>(elements: I) -> Ty
+    where
+        I: IntoIterator<Item = Ty>,
+        <I as IntoIterator>::IntoIter: ExactSizeIterator,
+    {
+        let elements = elements.into_iter();
+        let len = elements.len();
+        let mut b =
+            TyBuilder::new(Tuple(len), iter::repeat(ParamKind::Type).take(len).collect(), None);
+        for e in elements {
+            b = b.push(e);
+        }
+        b.build()
+    }
 }
 
 impl TyBuilder<TraitId> {
diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs
index 7ae85d20611..334434c30ca 100644
--- a/crates/hir-ty/src/infer/expr.rs
+++ b/crates/hir-ty/src/infer/expr.rs
@@ -331,11 +331,18 @@ impl<'a> InferenceContext<'a> {
                     derefed_callee.callable_sig(self.db).map_or(false, |sig| sig.is_varargs)
                         || res.is_none();
                 let (param_tys, ret_ty) = match res {
-                    Some(res) => {
+                    Some((func, params, ret_ty)) => {
                         let adjustments = auto_deref_adjust_steps(&derefs);
                         // FIXME: Handle call adjustments for Fn/FnMut
                         self.write_expr_adj(*callee, adjustments);
-                        res
+                        if let Some((trait_, func)) = func {
+                            let subst = TyBuilder::subst_for_def(self.db, trait_, None)
+                                .push(callee_ty.clone())
+                                .push(TyBuilder::tuple_with(params.iter().cloned()))
+                                .build();
+                            self.write_method_resolution(tgt_expr, func, subst.clone());
+                        }
+                        (params, ret_ty)
                     }
                     None => (Vec::new(), self.err_ty()), // FIXME diagnostic
                 };
@@ -586,6 +593,7 @@ impl<'a> InferenceContext<'a> {
                 self.resolve_associated_type(inner_ty, self.resolve_future_future_output())
             }
             Expr::Try { expr } => {
+                // FIXME: Note down method resolution her
                 let inner_ty = self.infer_expr_inner(*expr, &Expectation::none());
                 self.resolve_associated_type(inner_ty, self.resolve_ops_try_ok())
             }
@@ -626,6 +634,7 @@ impl<'a> InferenceContext<'a> {
             Expr::UnaryOp { expr, op } => {
                 let inner_ty = self.infer_expr_inner(*expr, &Expectation::none());
                 let inner_ty = self.resolve_ty_shallow(&inner_ty);
+                // FIXME: Note down method resolution her
                 match op {
                     UnaryOp::Deref => {
                         autoderef::deref(&mut self.table, inner_ty).unwrap_or_else(|| self.err_ty())
@@ -732,6 +741,7 @@ impl<'a> InferenceContext<'a> {
                 }
             }
             Expr::Index { base, index } => {
+                // FIXME: note down method resolution for the `index`/`index_mut` function
                 let base_ty = self.infer_expr_inner(*base, &Expectation::none());
                 let index_ty = self.infer_expr(*index, &Expectation::none());
 
diff --git a/crates/hir-ty/src/infer/unify.rs b/crates/hir-ty/src/infer/unify.rs
index e7ddd1591fe..46ed3533c8c 100644
--- a/crates/hir-ty/src/infer/unify.rs
+++ b/crates/hir-ty/src/infer/unify.rs
@@ -8,6 +8,7 @@ use chalk_ir::{
 };
 use chalk_solve::infer::ParameterEnaVariableExt;
 use ena::unify::UnifyKey;
+use hir_def::{FunctionId, TraitId};
 use hir_expand::name;
 use stdx::never;
 
@@ -626,18 +627,26 @@ impl<'a> InferenceTable<'a> {
         }
     }
 
-    pub(crate) fn callable_sig(&mut self, ty: &Ty, num_args: usize) -> Option<(Vec<Ty>, Ty)> {
+    pub(crate) fn callable_sig(
+        &mut self,
+        ty: &Ty,
+        num_args: usize,
+    ) -> Option<(Option<(TraitId, FunctionId)>, Vec<Ty>, Ty)> {
         match ty.callable_sig(self.db) {
-            Some(sig) => Some((sig.params().to_vec(), sig.ret().clone())),
+            Some(sig) => Some((None, sig.params().to_vec(), sig.ret().clone())),
             None => self.callable_sig_from_fn_trait(ty, num_args),
         }
     }
 
-    fn callable_sig_from_fn_trait(&mut self, ty: &Ty, num_args: usize) -> Option<(Vec<Ty>, Ty)> {
+    fn callable_sig_from_fn_trait(
+        &mut self,
+        ty: &Ty,
+        num_args: usize,
+    ) -> Option<(Option<(TraitId, FunctionId)>, Vec<Ty>, Ty)> {
         let krate = self.trait_env.krate;
         let fn_once_trait = FnTrait::FnOnce.get_id(self.db, krate)?;
-        let output_assoc_type =
-            self.db.trait_data(fn_once_trait).associated_type_by_name(&name![Output])?;
+        let trait_data = self.db.trait_data(fn_once_trait);
+        let output_assoc_type = trait_data.associated_type_by_name(&name![Output])?;
 
         let mut arg_tys = vec![];
         let arg_ty = TyBuilder::tuple(num_args)
@@ -675,7 +684,11 @@ impl<'a> InferenceTable<'a> {
         if self.db.trait_solve(krate, canonical.value.cast(Interner)).is_some() {
             self.register_obligation(obligation.goal);
             let return_ty = self.normalize_projection_ty(projection);
-            Some((arg_tys, return_ty))
+            Some((
+                Some(fn_once_trait).zip(trait_data.method_by_name(&name!(call_once))),
+                arg_tys,
+                return_ty,
+            ))
         } else {
             None
         }
diff --git a/crates/hir-ty/src/tests/method_resolution.rs b/crates/hir-ty/src/tests/method_resolution.rs
index 6c7a5329970..fb736982ed0 100644
--- a/crates/hir-ty/src/tests/method_resolution.rs
+++ b/crates/hir-ty/src/tests/method_resolution.rs
@@ -986,14 +986,13 @@ fn main() {
 }
 
 #[test]
-fn method_resolution_encountering_fn_type() {
+fn explicit_fn_once_call_fn_item() {
     check_types(
         r#"
-//- /main.rs
+//- minicore: fn
 fn foo() {}
-trait FnOnce { fn call(self); }
-fn test() { foo.call(); }
-          //^^^^^^^^^^ {unknown}
+fn test() { foo.call_once(); }
+          //^^^^^^^^^^^^^^^ ()
 "#,
     );
 }
diff --git a/crates/hir-ty/src/tests/traits.rs b/crates/hir-ty/src/tests/traits.rs
index 88670364bde..d8c3588acf6 100644
--- a/crates/hir-ty/src/tests/traits.rs
+++ b/crates/hir-ty/src/tests/traits.rs
@@ -1757,25 +1757,19 @@ fn test() {
 fn fn_trait() {
     check_infer_with_mismatches(
         r#"
-trait FnOnce<Args> {
-    type Output;
-
-    fn call_once(self, args: Args) -> <Self as FnOnce<Args>>::Output;
-}
+//- minicore: fn
 
 fn test<F: FnOnce(u32, u64) -> u128>(f: F) {
     f.call_once((1, 2));
 }"#,
         expect![[r#"
-            56..60 'self': Self
-            62..66 'args': Args
-            149..150 'f': F
-            155..183 '{     ...2)); }': ()
-            161..162 'f': F
-            161..180 'f.call...1, 2))': u128
-            173..179 '(1, 2)': (u32, u64)
-            174..175 '1': u32
-            177..178 '2': u64
+            38..39 'f': F
+            44..72 '{     ...2)); }': ()
+            50..51 'f': F
+            50..69 'f.call...1, 2))': u128
+            62..68 '(1, 2)': (u32, u64)
+            63..64 '1': u32
+            66..67 '2': u64
         "#]],
     );
 }
@@ -1784,12 +1778,7 @@ fn test<F: FnOnce(u32, u64) -> u128>(f: F) {
 fn fn_ptr_and_item() {
     check_infer_with_mismatches(
         r#"
-#[lang="fn_once"]
-trait FnOnce<Args> {
-    type Output;
-
-    fn call_once(self, args: Args) -> Self::Output;
-}
+//- minicore: fn
 
 trait Foo<T> {
     fn foo(&self) -> T;
@@ -1815,27 +1804,25 @@ fn test() {
     opt.map(f);
 }"#,
         expect![[r#"
-            74..78 'self': Self
-            80..84 'args': Args
-            139..143 'self': &Self
-            243..247 'self': &Bar<F>
-            260..271 '{ loop {} }': (A1, R)
-            262..269 'loop {}': !
-            267..269 '{}': ()
-            355..359 'self': Opt<T>
-            361..362 'f': F
-            377..388 '{ loop {} }': Opt<U>
-            379..386 'loop {}': !
-            384..386 '{}': ()
-            402..518 '{     ...(f); }': ()
-            412..415 'bar': Bar<fn(u8) -> u32>
-            441..444 'bar': Bar<fn(u8) -> u32>
-            441..450 'bar.foo()': (u8, u32)
-            461..464 'opt': Opt<u8>
-            483..484 'f': fn(u8) -> u32
-            505..508 'opt': Opt<u8>
-            505..515 'opt.map(f)': Opt<u32>
-            513..514 'f': fn(u8) -> u32
+            28..32 'self': &Self
+            132..136 'self': &Bar<F>
+            149..160 '{ loop {} }': (A1, R)
+            151..158 'loop {}': !
+            156..158 '{}': ()
+            244..248 'self': Opt<T>
+            250..251 'f': F
+            266..277 '{ loop {} }': Opt<U>
+            268..275 'loop {}': !
+            273..275 '{}': ()
+            291..407 '{     ...(f); }': ()
+            301..304 'bar': Bar<fn(u8) -> u32>
+            330..333 'bar': Bar<fn(u8) -> u32>
+            330..339 'bar.foo()': (u8, u32)
+            350..353 'opt': Opt<u8>
+            372..373 'f': fn(u8) -> u32
+            394..397 'opt': Opt<u8>
+            394..404 'opt.map(f)': Opt<u32>
+            402..403 'f': fn(u8) -> u32
         "#]],
     );
 }
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 4415bef4bb1..39589bf8bc2 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -2411,7 +2411,7 @@ impl Local {
 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 pub struct DeriveHelper {
     pub(crate) derive: MacroId,
-    pub(crate) idx: usize,
+    pub(crate) idx: u32,
 }
 
 impl DeriveHelper {
@@ -2421,15 +2421,18 @@ impl DeriveHelper {
 
     pub fn name(&self, db: &dyn HirDatabase) -> Name {
         match self.derive {
-            MacroId::Macro2Id(it) => {
-                db.macro2_data(it).helpers.as_deref().and_then(|it| it.get(self.idx)).cloned()
-            }
+            MacroId::Macro2Id(it) => db
+                .macro2_data(it)
+                .helpers
+                .as_deref()
+                .and_then(|it| it.get(self.idx as usize))
+                .cloned(),
             MacroId::MacroRulesId(_) => None,
             MacroId::ProcMacroId(proc_macro) => db
                 .proc_macro_data(proc_macro)
                 .helpers
                 .as_deref()
-                .and_then(|it| it.get(self.idx))
+                .and_then(|it| it.get(self.idx as usize))
                 .cloned(),
         }
         .unwrap_or_else(|| Name::missing())
@@ -2440,7 +2443,7 @@ impl DeriveHelper {
 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 pub struct BuiltinAttr {
     krate: Option<CrateId>,
-    idx: usize,
+    idx: u32,
 }
 
 impl BuiltinAttr {
@@ -2449,7 +2452,8 @@ impl BuiltinAttr {
         if let builtin @ Some(_) = Self::builtin(name) {
             return builtin;
         }
-        let idx = db.crate_def_map(krate.id).registered_attrs().iter().position(|it| it == name)?;
+        let idx =
+            db.crate_def_map(krate.id).registered_attrs().iter().position(|it| it == name)? as u32;
         Some(BuiltinAttr { krate: Some(krate.id), idx })
     }
 
@@ -2457,21 +2461,21 @@ impl BuiltinAttr {
         hir_def::builtin_attr::INERT_ATTRIBUTES
             .iter()
             .position(|tool| tool.name == name)
-            .map(|idx| BuiltinAttr { krate: None, idx })
+            .map(|idx| BuiltinAttr { krate: None, idx: idx as u32 })
     }
 
     pub fn name(&self, db: &dyn HirDatabase) -> SmolStr {
         // FIXME: Return a `Name` here
         match self.krate {
-            Some(krate) => db.crate_def_map(krate).registered_attrs()[self.idx].clone(),
-            None => SmolStr::new(hir_def::builtin_attr::INERT_ATTRIBUTES[self.idx].name),
+            Some(krate) => db.crate_def_map(krate).registered_attrs()[self.idx as usize].clone(),
+            None => SmolStr::new(hir_def::builtin_attr::INERT_ATTRIBUTES[self.idx as usize].name),
         }
     }
 
     pub fn template(&self, _: &dyn HirDatabase) -> Option<AttributeTemplate> {
         match self.krate {
             Some(_) => None,
-            None => Some(hir_def::builtin_attr::INERT_ATTRIBUTES[self.idx].template),
+            None => Some(hir_def::builtin_attr::INERT_ATTRIBUTES[self.idx as usize].template),
         }
     }
 }
@@ -2479,7 +2483,7 @@ impl BuiltinAttr {
 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 pub struct ToolModule {
     krate: Option<CrateId>,
-    idx: usize,
+    idx: u32,
 }
 
 impl ToolModule {
@@ -2488,7 +2492,8 @@ impl ToolModule {
         if let builtin @ Some(_) = Self::builtin(name) {
             return builtin;
         }
-        let idx = db.crate_def_map(krate.id).registered_tools().iter().position(|it| it == name)?;
+        let idx =
+            db.crate_def_map(krate.id).registered_tools().iter().position(|it| it == name)? as u32;
         Some(ToolModule { krate: Some(krate.id), idx })
     }
 
@@ -2496,14 +2501,14 @@ impl ToolModule {
         hir_def::builtin_attr::TOOL_MODULES
             .iter()
             .position(|&tool| tool == name)
-            .map(|idx| ToolModule { krate: None, idx })
+            .map(|idx| ToolModule { krate: None, idx: idx as u32 })
     }
 
     pub fn name(&self, db: &dyn HirDatabase) -> SmolStr {
         // FIXME: Return a `Name` here
         match self.krate {
-            Some(krate) => db.crate_def_map(krate).registered_tools()[self.idx].clone(),
-            None => SmolStr::new(hir_def::builtin_attr::TOOL_MODULES[self.idx]),
+            Some(krate) => db.crate_def_map(krate).registered_tools()[self.idx as usize].clone(),
+            None => SmolStr::new(hir_def::builtin_attr::TOOL_MODULES[self.idx as usize]),
         }
     }
 }
@@ -2831,7 +2836,7 @@ impl Impl {
     }
 }
 
-#[derive(Clone, PartialEq, Eq, Debug)]
+#[derive(Clone, PartialEq, Eq, Debug, Hash)]
 pub struct TraitRef {
     env: Arc<TraitEnvironment>,
     trait_ref: hir_ty::TraitRef,
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs
index 5e0c9933a7b..3b39e9fa919 100644
--- a/crates/hir/src/source_analyzer.rs
+++ b/crates/hir/src/source_analyzer.rs
@@ -628,7 +628,7 @@ impl SourceAnalyzer {
                                 {
                                     return Some(PathResolution::DeriveHelper(DeriveHelper {
                                         derive: *macro_id,
-                                        idx,
+                                        idx: idx as u32,
                                     }));
                                 }
                             }
diff --git a/crates/ide-db/src/defs.rs b/crates/ide-db/src/defs.rs
index 6c13c039723..ed7f04fd8e7 100644
--- a/crates/ide-db/src/defs.rs
+++ b/crates/ide-db/src/defs.rs
@@ -34,8 +34,8 @@ pub enum Definition {
     TypeAlias(TypeAlias),
     BuiltinType(BuiltinType),
     SelfType(Impl),
-    Local(Local),
     GenericParam(GenericParam),
+    Local(Local),
     Label(Label),
     DeriveHelper(DeriveHelper),
     BuiltinAttr(BuiltinAttr),
diff --git a/crates/test-utils/src/minicore.rs b/crates/test-utils/src/minicore.rs
index dff60914409..63fd1726cf3 100644
--- a/crates/test-utils/src/minicore.rs
+++ b/crates/test-utils/src/minicore.rs
@@ -106,6 +106,11 @@ pub mod marker {
         impl<T: ?Sized> Copy for &T {}
     }
     // endregion:copy
+
+    // region:fn
+    #[lang = "tuple_trait"]
+    pub trait Tuple {}
+    // endregion:fn
 }
 
 // region:default
@@ -329,19 +334,26 @@ pub mod ops {
 
     // region:fn
     mod function {
+        use crate::marker::Tuple;
+
         #[lang = "fn"]
         #[fundamental]
-        pub trait Fn<Args>: FnMut<Args> {}
+        pub trait Fn<Args: Tuple>: FnMut<Args> {
+            extern "rust-call" fn call(&self, args: Args) -> Self::Output;
+        }
 
         #[lang = "fn_mut"]
         #[fundamental]
-        pub trait FnMut<Args>: FnOnce<Args> {}
+        pub trait FnMut<Args: Tuple>: FnOnce<Args> {
+            extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
+        }
 
         #[lang = "fn_once"]
         #[fundamental]
-        pub trait FnOnce<Args> {
+        pub trait FnOnce<Args: Tuple> {
             #[lang = "fn_once_output"]
             type Output;
+            extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
         }
     }
     pub use self::function::{Fn, FnMut, FnOnce};