Shall we increase the typeck recursion limit


#1

Today I have a little piece of code that requires #![recursion_limit="128"].

use trust_dns_resolver::{AsyncResolver, config::{ResolverConfig, ResolverOpts}};
let (resolver,rf) = 
      AsyncResolver::new(ResolverConfig::google(), ResolverOpts::default());
tokio::spawn(rf);

Since this is so simple and easy, yet require a bigger recursion limit, shall we just increase it for everyone?


#2

The question is where do we set the limit ? If the limit is too high, an infinite recursion may be not fail in a reasonable delay.


#3

Couple of thoughts –

First, I expect that as part of overhauling our trait system implementation, the recursion limit will play a smaller role.

Second, I am interested in changing the recursion limit so that it can be specified in libraries and inherited by consumers. For example, I would like a way for a macro to label itself as “recursing very deeply”, so that users of the macro don’t need to increase their recursion limit. One might imagine doing similar things at the trait level. This would probably obviate the problem without just perenially bumping up the limits.


#4

Second, I am interested in changing the recursion limit so that it can be specified in libraries and inherited by consumers. For example, I would like a way for a macro to label itself as “recursing very deeply”, so that users of the macro don’t need to increase their recursion limit. One might imagine doing similar things at the trait level. This would probably obviate the problem without just perenially bumping up the limits.

@nikomatsakis, it could even be done using the same attribute:

#[recursion_limit="128"]
fn foo() {
    use trust_dns_resolver::{AsyncResolver, config::{ResolverConfig, ResolverOpts}};
    let (resolver,rf) = AsyncResolver::new(ResolverConfig::google(), ResolverOpts::default());
    tokio::spawn(rf);
}

#5

Idealy, the user should not be required to add extra attributes. It would be better to have a #[recursion_limit_boost="100"] in either the impl Future of [type of rf] block, or the tokio::spawn function.

Interestingly, I confirmed that tye type of rf is impl Future<Item=(),Error=()>, and tokio::spawn accepts exactly Future<Item=(), Error=()>. So the question is, as we human can see that there is no risk to assume they match each other, why the compiler have to do the recursion so deep that it reaches the default limit? This sounds like the compiler can do better to avoid unnecessary checks.


#6

Another victim found. If you run cargo doc --open -p actix-web you get

error[E0275]: overflow evaluating the requirement `alloc::raw_vec::RawVec<std::vec::Vec<u8>>: std::marker::Send`
  |
  = help: consider adding a `#![recursion_limit="128"]` attribute to your crate
  = note: required because it appears within the type `std::vec::Vec<std::vec::Vec<u8>>`
  = note: required because it appears within the type `mio::sys::windows::buffer_pool::BufferPool`
  = note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Mutex<mio::sys::windows::buffer_pool::BufferPool>`
  = note: required because it appears within the type `mio::sys::windows::selector::SelectorInner`
  = note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Arc<mio::sys::windows::selector::SelectorInner>`
  = note: required because of the requirements on the impl of `std::marker::Send` for `lazycell::AtomicLazyCell<std::sync::Arc<mio::sys::windows::selector::SelectorInner>>`
  = note: required because it appears within the type `mio::sys::windows::selector::Binding`
  = note: required because it appears within the type `mio::sys::windows::selector::ReadyBinding`
  = note: required because it appears within the type `mio::sys::windows::udp::Inner`
  = note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Mutex<mio::sys::windows::udp::Inner>`
  = note: required because it appears within the type `mio::sys::windows::udp::Io`
  = note: required because of the requirements on the impl of `std::marker::Send` for `mio::sys::windows::from_raw_arc::FromRawArc<mio::sys::windows::udp::Io>`
  = note: required because it appears within the type `mio::sys::windows::udp::Imp`
  = note: required because it appears within the type `mio::sys::windows::udp::UdpSocket`
  = note: required because it appears within the type `mio::net::udp::UdpSocket`
  = note: required because it appears within the type `std::option::Option<mio::net::udp::UdpSocket>`
  = note: required because it appears within the type `tokio_reactor::PollEvented<mio::net::udp::UdpSocket>`
  = note: required because it appears within the type `tokio::net::UdpSocket`
  = note: required because it appears within the type `std::option::Option<tokio::net::UdpSocket>`
  = note: required because it appears within the type `actors::resolver::trust_dns_resolver::trust_dns_proto::udp::udp_client_stream::SingleUseUdpSocket`
  = note: required because it appears within the type `tokio_timer::Timeout<actors::resolver::trust_dns_resolver::trust_dns_proto::udp::udp_client_stream::SingleUseUdpSocket>`
  = note: required because it appears within the type `actors::resolver::trust_dns_resolver::trust_dns_proto::udp::UdpResponse`
  = note: required because it appears within the type `std::option::Option<actors::resolver::trust_dns_resolver::trust_dns_proto::udp::UdpResponse>`
  = note: required because of the requirements on the impl of `std::marker::Send` for `futures::lock::Lock<std::option::Option<actors::resolver::trust_dns_resolver::trust_dns_proto::udp::UdpResponse>>`
  = note: required because it appears within the type `futures::sync::oneshot::Inner<actors::resolver::trust_dns_resolver::trust_dns_proto::udp::UdpResponse>`
  = note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Arc<futures::sync::oneshot::Inner<actors::resolver::trust_dns_resolver::trust_dns_proto::udp::UdpResponse>>`
  = note: required because it appears within the type `futures::Sender<actors::resolver::trust_dns_resolver::trust_dns_proto::udp::UdpResponse>`
  = note: required because it appears within the type `actors::resolver::trust_dns_resolver::trust_dns_proto::xfer::OneshotDnsRequest<actors::resolver::trust_dns_resolver::trust_dns_proto::udp::UdpResponse>`
  = note: required because of the requirements on the impl of `std::marker::Send` for `futures::sync::mpsc::Inner<actors::resolver::trust_dns_resolver::trust_dns_proto::xfer::OneshotDnsRequest<actors::resolver::trust_dns_resolver::trust_dns_proto::udp::UdpResponse>>`
  = note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Arc<futures::sync::mpsc::Inner<actors::resolver::trust_dns_resolver::trust_dns_proto::xfer::OneshotDnsRequest<actors::resolver::trust_dns_resolver::trust_dns_proto::udp::UdpResponse>>>`
  = note: required because it appears within the type `futures::sync::mpsc::Sender<actors::resolver::trust_dns_resolver::trust_dns_proto::xfer::OneshotDnsRequest<actors::resolver::trust_dns_resolver::trust_dns_proto::udp::UdpResponse>>`
  = note: required because it appears within the type `futures::sync::mpsc::UnboundedSender<actors::resolver::trust_dns_resolver::trust_dns_proto::xfer::OneshotDnsRequest<actors::resolver::trust_dns_resolver::trust_dns_proto::udp::UdpResponse>>`
  = note: required because it appears within the type `actors::resolver::trust_dns_resolver::trust_dns_proto::xfer::DnsRequestStreamHandle<actors::resolver::trust_dns_resolver::trust_dns_proto::udp::UdpResponse>`
  = note: required because it appears within the type `actors::resolver::trust_dns_resolver::trust_dns_proto::xfer::BufDnsRequestStreamHandle<actors::resolver::trust_dns_resolver::trust_dns_proto::udp::UdpResponse>`
  = note: required because it appears within the type `actors::resolver::trust_dns_resolver::name_server_pool::ConnectionHandleConnected`
  = note: required because it appears within the type `actors::resolver::trust_dns_resolver::name_server_pool::ConnectionHandleInner`
  = note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Mutex<actors::resolver::trust_dns_resolver::name_server_pool::ConnectionHandleInner>`
  = note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Arc<std::sync::Mutex<actors::resolver::trust_dns_resolver::name_server_pool::ConnectionHandleInner>>`
  = note: required because it appears within the type `actors::resolver::trust_dns_resolver::name_server_pool::ConnectionHandle`
  = note: required because it appears within the type `actors::resolver::trust_dns_resolver::name_server_pool::NameServer<actors::resolver::trust_dns_resolver::name_server_pool::ConnectionHandle, actors::resolver::trust_dns_resolver::name_server_pool::StandardConnection>`
  = note: required because of the requirements on the impl of `std::marker::Send` for `std::ptr::Unique<actors::resolver::trust_dns_resolver::name_server_pool::NameServer<actors::resolver::trust_dns_resolver::name_server_pool::ConnectionHandle, actors::resolver::trust_dns_resolver::name_server_pool::StandardConnection>>`
  = note: required because it appears within the type `alloc::raw_vec::RawVec<actors::resolver::trust_dns_resolver::name_server_pool::NameServer<actors::resolver::trust_dns_resolver::name_server_pool::ConnectionHandle, actors::resolver::trust_dns_resolver::name_server_pool::StandardConnection>>`
  = note: required because it appears within the type `std::vec::Vec<actors::resolver::trust_dns_resolver::name_server_pool::NameServer<actors::resolver::trust_dns_resolver::name_server_pool::ConnectionHandle, actors::resolver::trust_dns_resolver::name_server_pool::StandardConnection>>`
  = note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Mutex<std::vec::Vec<actors::resolver::trust_dns_resolver::name_server_pool::NameServer<actors::resolver::trust_dns_resolver::name_server_pool::ConnectionHandle, actors::resolver::trust_dns_resolver::name_server_pool::StandardConnection>>>`
  = note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Arc<std::sync::Mutex<std::vec::Vec<actors::resolver::trust_dns_resolver::name_server_pool::NameServer<actors::resolver::trust_dns_resolver::name_server_pool::ConnectionHandle, actors::resolver::trust_dns_resolver::name_server_pool::StandardConnection>>>>`
  = note: required because it appears within the type `actors::resolver::trust_dns_resolver::name_server_pool::NameServerPool<actors::resolver::trust_dns_resolver::name_server_pool::ConnectionHandle, actors::resolver::trust_dns_resolver::name_server_pool::StandardConnection>`
  = note: required because it appears within the type `actors::resolver::trust_dns_resolver::trust_dns_proto::RetryDnsHandle<actors::resolver::trust_dns_resolver::name_server_pool::NameServerPool<actors::resolver::trust_dns_resolver::name_server_pool::ConnectionHandle, actors::resolver::trust_dns_resolver::name_server_pool::StandardConnection>>`
  = note: required because it appears within the type `actors::resolver::trust_dns_resolver::lookup::LookupEither<actors::resolver::trust_dns_resolver::name_server_pool::ConnectionHandle, actors::resolver::trust_dns_resolver::name_server_pool::StandardConnection>`
  = note: required because it appears within the type `actors::resolver::trust_dns_resolver::lookup_state::CachingClient<actors::resolver::trust_dns_resolver::lookup::LookupEither<actors::resolver::trust_dns_resolver::name_server_pool::ConnectionHandle, actors::resolver::trust_dns_resolver::name_server_pool::StandardConnection>>`
  = note: required because it appears within the type `actors::resolver::trust_dns_resolver::lookup::LookupFuture`
  = note: required because it appears within the type `std::option::Option<actors::resolver::trust_dns_resolver::lookup::LookupFuture>`
  = note: required because of the requirements on the impl of `std::marker::Send` for `futures::lock::Lock<std::option::Option<actors::resolver::trust_dns_resolver::lookup::LookupFuture>>`
  = note: required because it appears within the type `futures::sync::oneshot::Inner<actors::resolver::trust_dns_resolver::lookup::LookupFuture>`
  = note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Arc<futures::sync::oneshot::Inner<actors::resolver::trust_dns_resolver::lookup::LookupFuture>>`
  = note: required because it appears within the type `futures::Sender<actors::resolver::trust_dns_resolver::lookup::LookupFuture>`
  = note: required because it appears within the type `actors::resolver::trust_dns_resolver::async_resolver::Request`
  = note: required because of the requirements on the impl of `std::marker::Send` for `futures::sync::mpsc::Inner<actors::resolver::trust_dns_resolver::async_resolver::Request>`
  = note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Arc<futures::sync::mpsc::Inner<actors::resolver::trust_dns_resolver::async_resolver::Request>>`
  = note: required because it appears within the type `futures::sync::mpsc::Sender<actors::resolver::trust_dns_resolver::async_resolver::Request>`
  = note: required because it appears within the type `futures::sync::mpsc::UnboundedSender<actors::resolver::trust_dns_resolver::async_resolver::Request>`
  = note: required because it appears within the type `actors::resolver::trust_dns_resolver::AsyncResolver`
  = note: required because it appears within the type `std::option::Option<actors::resolver::trust_dns_resolver::AsyncResolver>`
  = note: required because it appears within the type `actors::resolver::Resolver`

Well, this have significant effect. Are there any to workaround? I couldn’t build local docs right now.