diff options
| author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2020-05-18 07:44:44 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-05-18 07:44:44 +0000 |
| commit | ad03e4de185f0f19ae75a8a9c4095ee1b0d82a47 (patch) | |
| tree | 86f1b44509075a54f0887d56fe84e8ae42df5766 | |
| parent | c6ed08967193cadc927dfaf422601bcd160a6fc9 (diff) | |
| parent | 68db49c8534fa99768c7f600455ea76176f61994 (diff) | |
| download | rust-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.rs | 132 |
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#" |
