mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-11-17 02:08:30 +00:00
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>
This commit is contained in:
commit
ad03e4de18
1 changed files with 132 additions and 0 deletions
|
@ -1616,6 +1616,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!(
|
||||
|
|
Loading…
Reference in a new issue