rust - Force/coerce evaluation of closure signature -
here contrived example of trying do:
use std::boxed::box; #[derive(debug)] pub struct foo<'a>(pub &'a str); pub trait intobox { fn into_box<'a>(self) -> box<fn(foo) -> string>; } impl<b> intobox b b: fn(foo) -> string + 'static { fn into_box(self) -> box<fn(foo) -> string> { box::new(self) } } fn direct_into_box<b: fn(foo) -> string + 'static>(b: b) -> box<fn(foo) -> string> { box::new(b) } fn main() { // doesn't work let x = intobox::into_box(|i| format!("{:?}", i) ); // works let y = intobox::into_box(|i: foo| format!("{:?}", i) ); // works let z = direct_into_box(|i| format!("{:?}", i) ); } how trait impl same evaluation of closure done direct_into_box? have expected direct_into_box , trait impl behave in same way.
the error on x:
error[e0271]: type mismatch resolving `for<'r> <[closure@<anon>:20:31: 20:53] std::ops::fnonce<(foo<'r>,)>>::output == std::string::string` --> <anon>:20:13 | 20 | let x = intobox::into_box(|i| format!("{:?}", i) ); | ^^^^^^^^^^^^^^^^^ expected bound lifetime parameter , found concrete lifetime | = note: concrete lifetime found lifetime '_#29r = note: required because of requirements on impl of `intobox` `[closure@<anon>:20:31: 20:53]` = note: required `intobox::into_box` error[e0281]: type mismatch: type `[closure@<anon>:20:31: 20:53]` implements trait `std::ops::fn<(_,)>`, trait `for<'r> std::ops::fn<(foo<'r>,)>` required (expected concrete lifetime, found bound lifetime parameter ) --> <anon>:20:13 | 20 | let x = intobox::into_box(|i| format!("{:?}", i) ); | ^^^^^^^^^^^^^^^^^ | = note: required because of requirements on impl of `intobox` `[closure@<anon>:20:31: 20:53]` = note: required `intobox::into_box`
sounds an inference bug in compiler. seems happen compiler implements fn(foo<'x>) for 1 specific lifetime 'x instead of fn(foo<'a>) for lifetime 'a on closure.
let's see if can replicate error defining struct hand (this requires nightly compiler), can better understand what's going on. first, let's define struct correct way:
#![feature(fn_traits)] #![feature(unboxed_closures)] // foo , intobox unchanged struct func; impl<'a> fnonce<(foo<'a>,)> func { type output = string; extern "rust-call" fn call_once(self, args: (foo<'a>,)) -> string { self.call(args) } } impl<'a> fnmut<(foo<'a>,)> func { extern "rust-call" fn call_mut(&mut self, args: (foo<'a>,)) -> string { self.call(args) } } impl<'a> fn<(foo<'a>,)> func { extern "rust-call" fn call(&self, (i,): (foo<'a>,)) -> string { format!("{:?}", i) } } fn main() { let x = intobox::into_box(func); } this func struct compiles fine , behaves original closure.
now, let's break it:
impl fnonce<(foo<'static>,)> func { type output = string; extern "rust-call" fn call_once(self, args: (foo<'static>,)) -> string { self.call(args) } } impl fnmut<(foo<'static>,)> func { extern "rust-call" fn call_mut(&mut self, args: (foo<'static>,)) -> string { self.call(args) } } impl fn<(foo<'static>,)> func { extern "rust-call" fn call(&self, (i,): (foo<'static>,)) -> string { format!("{:?}", i) } } what i've done here i've removed <'a> on each impl, impls no longer generic on lifetime, , i've replaced foo<'a> foo<'static>. means now, traits implemented when "closure"'s argument foo<'static>.
this fails compile following errors:
error[e0271]: type mismatch resolving `for<'r> <func std::ops::fnonce<(foo<'r>,)>>::output == std::string::string` --> <anon>:51:13 | 51 | let x = intobox::into_box(func); | ^^^^^^^^^^^^^^^^^ expected bound lifetime parameter , found concrete lifetime | = note: concrete lifetime found static lifetime = note: required because of requirements on impl of `intobox` `func` = note: required `intobox::into_box` error[e0277]: trait bound `for<'r> func: std::ops::fn<(foo<'r>,)>` not satisfied --> <anon>:51:13 | 51 | let x = intobox::into_box(func); | ^^^^^^^^^^^^^^^^^ trait `for<'r> std::ops::fn<(foo<'r>,)>` not implemented `func` | = help: following implementations found: = help: <func std::ops::fn<(foo<'static>,)>> = note: required because of requirements on impl of `intobox` `func` = note: required `intobox::into_box` the first error same, instead of internal name '_#29r, compiler mentions static lifetime, because that's used here. suspect compiler doing closure doesn't compile in code similar second set of impls, instead of 'static, it's other concrete lifetime can't name in rust. second error different means pretty same thing.
Comments
Post a Comment