about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2020-05-18 07:44:44 +0000
committerGitHub <noreply@github.com>2020-05-18 07:44:44 +0000
commitad03e4de185f0f19ae75a8a9c4095ee1b0d82a47 (patch)
tree86f1b44509075a54f0887d56fe84e8ae42df5766
parentc6ed08967193cadc927dfaf422601bcd160a6fc9 (diff)
parent68db49c8534fa99768c7f600455ea76176f61994 (diff)
downloadrust-ad03e4de185f0f19ae75a8a9c4095ee1b0d82a47.tar.gz
rust-ad03e4de185f0f19ae75a8a9c4095ee1b0d82a47.zip
Merge #4493
4493: Provide builtin impls of Fn traits for fn-pointers r=flodiebold a=hban

Meant to be, but isn't actually a fix for #2880.

Consider this snippet:

```rust
use std::marker::PhantomData;
use std::ops::Deref;

struct Lazy<T, F/* = fn() -> T*/>(F, PhantomData<T>);

impl<T, F> Lazy<T, F> {
    pub fn new(f: F) -> Lazy<T, F> {
        Lazy(f, PhantomData)
    }
}

impl<T, F: FnOnce() -> T> Deref for Lazy<T, F> {
    type Target = T;

    fn deref(&self) -> &T { todo!() }
}

fn test() {
    let lazy1: Lazy<u32, _> = Lazy::new(|| 0u32);
    let r1 = lazy1.to_string();

    fn make_u32_fn() -> u32 { todo!() }
    let make_u32_fn_ptr: fn() -> u32 = make_u32_fn;
    let lazy2: Lazy<u32, _> = Lazy::new(make_u32_fn_ptr);
    let r2 = lazy2.to_string();
}
```

* On current master:
  * When type default is commented-out, `r1` is correctly inferred, `r2` in _{unknown}_.
  * When type default is not commented-out, both `r1`  and `r2` are _{unknown}_.
* With this PR:
  * When type default is commented-out, both `r1` and `r2` are correctly inferred.
  * When type default is not commented-out, both `r1`  and `r2` are _{unknown}_.

Well, it's a improvement at least. I guess this thing with type defaults is a different problem.

I also tried add Fn impls for fn items, but wasn't successful. So this PR only adds those impls for fn pointers.

Co-authored-by: Hrvoje Ban <hban@users.noreply.github.com>
-rw-r--r--crates/ra_hir_ty/src/tests/traits.rs132
1 files changed, 132 insertions, 0 deletions
diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs
index 9d32cbc7a6b..c49aacf98d4 100644
--- a/crates/ra_hir_ty/src/tests/traits.rs
+++ b/crates/ra_hir_ty/src/tests/traits.rs
@@ -1617,6 +1617,138 @@ fn test<F: FnOnce(u32, u64) -> u128>(f: F) {
 }
 
 #[test]
+fn fn_ptr_and_item() {
+    assert_snapshot!(
+        infer(r#"
+#[lang="fn_once"]
+trait FnOnce<Args> {
+    type Output;
+
+    fn call_once(self, args: Args) -> Self::Output;
+}
+
+trait Foo<T> {
+    fn foo(&self) -> T;
+}
+
+struct Bar<T>(T);
+
+impl<A1, R, F: FnOnce(A1) -> R> Foo<(A1, R)> for Bar<F> {
+    fn foo(&self) -> (A1, R) {}
+}
+
+enum Opt<T> { None, Some(T) }
+impl<T> Opt<T> {
+    fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Opt<U> {}
+}
+
+fn test() {
+    let bar: Bar<fn(u8) -> u32>;
+    bar.foo();
+
+    let opt: Opt<u8>;
+    let f: fn(u8) -> u32;
+    opt.map(f);
+}
+"#),
+        @r###"
+75..79 'self': Self
+81..85 'args': Args
+140..144 'self': &Self
+244..248 'self': &Bar<F>
+261..263 '{}': ()
+347..351 'self': Opt<T>
+353..354 'f': F
+369..371 '{}': ()
+385..501 '{     ...(f); }': ()
+395..398 'bar': Bar<fn(u8) -> u32>
+424..427 'bar': Bar<fn(u8) -> u32>
+424..433 'bar.foo()': {unknown}
+444..447 'opt': Opt<u8>
+466..467 'f': fn(u8) -> u32
+488..491 'opt': Opt<u8>
+488..498 'opt.map(f)': Opt<FnOnce::Output<fn(u8) -> u32, (u8,)>>
+496..497 'f': fn(u8) -> u32
+"###
+    );
+}
+
+#[test]
+fn fn_trait_deref_with_ty_default() {
+    assert_snapshot!(
+        infer(r#"
+#[lang = "deref"]
+trait Deref {
+    type Target;
+
+    fn deref(&self) -> &Self::Target;
+}
+
+#[lang="fn_once"]
+trait FnOnce<Args> {
+    type Output;
+
+    fn call_once(self, args: Args) -> Self::Output;
+}
+
+struct Foo;
+
+impl Foo {
+    fn foo(&self) -> usize {}
+}
+
+struct Lazy<T, F = fn() -> T>(F);
+
+impl<T, F> Lazy<T, F> {
+    pub fn new(f: F) -> Lazy<T, F> {}
+}
+
+impl<T, F: FnOnce() -> T> Deref for Lazy<T, F> {
+    type Target = T;
+}
+
+fn test() {
+    let lazy1: Lazy<Foo, _> = Lazy::new(|| Foo);
+    let r1 = lazy1.foo();
+
+    fn make_foo_fn() -> Foo {}
+    let make_foo_fn_ptr: fn() -> Foo = make_foo_fn;
+    let lazy2: Lazy<Foo, _> = Lazy::new(make_foo_fn_ptr);
+    let r2 = lazy2.foo();
+}
+"#),
+        @r###"
+65..69 'self': &Self
+166..170 'self': Self
+172..176 'args': Args
+240..244 'self': &Foo
+255..257 '{}': ()
+335..336 'f': F
+355..357 '{}': ()
+444..690 '{     ...o(); }': ()
+454..459 'lazy1': Lazy<Foo, fn() -> T>
+476..485 'Lazy::new': fn new<Foo, fn() -> T>(fn() -> T) -> Lazy<Foo, fn() -> T>
+476..493 'Lazy::...| Foo)': Lazy<Foo, fn() -> T>
+486..492 '|| Foo': || -> T
+489..492 'Foo': Foo
+503..505 'r1': {unknown}
+508..513 'lazy1': Lazy<Foo, fn() -> T>
+508..519 'lazy1.foo()': {unknown}
+561..576 'make_foo_fn_ptr': fn() -> Foo
+592..603 'make_foo_fn': fn make_foo_fn() -> Foo
+613..618 'lazy2': Lazy<Foo, fn() -> T>
+635..644 'Lazy::new': fn new<Foo, fn() -> T>(fn() -> T) -> Lazy<Foo, fn() -> T>
+635..661 'Lazy::...n_ptr)': Lazy<Foo, fn() -> T>
+645..660 'make_foo_fn_ptr': fn() -> Foo
+671..673 'r2': {unknown}
+676..681 'lazy2': Lazy<Foo, fn() -> T>
+676..687 'lazy2.foo()': {unknown}
+550..552 '{}': ()
+"###
+    );
+}
+
+#[test]
 fn closure_1() {
     assert_snapshot!(
         infer(r#"