Captures and overrides

Consider:

impl Deserialize for Bar
given
    basic_arena: BasicArena,
{ ... }

fn deserialize_and_print<T>(input: impl Read) -> T
where
    T: Deserialize + Debug,
{ ... }

fn main() {
    given basic_arena = BasicArena::new() {
        // This works, even though `deserialize_and_print` knows nothing about
        // `basic_arena`!
        let _foo: &Foo = deserialize_and_print(std::io::stdin());
    }
}

The call to deserialize_and_print above knows that basic_arena has been provided, and therefore that the T: Deserialize bound can be satisfied by the impl.

Mechanically, how do we thread the arena through the impl? Is its value captured at the time of using the impl (meaning in main, at the call to deserialize_and_print) and "smuggled" through somehow? Or do we only capture the knowledge that this context is available, and allow it to be overridden?

More specifically, what happens if we do this?

fn main() {
    given basic_arena = BasicArena::new() {
        let _foo: &Foo = deserialize_and_print_with_arena(std::io::stdin());
    }
}

fn deserialize_and_print_with_arena<T>(input: impl Read) -> T
where
    T: Deserialize + Debug,
{
    // Which arena will win, the caller's or ours?
    given basic_arena = BasicArena::new() {
        deserialize_and_print(input)
    }
}

Note that this is a pretty contrived example. The above function just creates an arena for no particular reason. If we had written its signature just a little differently:


#![allow(unused)]
fn main() {
fn deserialize_and_print_with_arena<T>(input: impl Read) -> T
where
    T: given(basic_arena) Deserialize + Debug,
}

Then it would be obvious what the answer should be: The function "knows" that T: Deserialize requires basic_arena, so its definition should always win. So this ambiguous situation may not happen that often in practice.

It still could, however, if we are dealing with one generic argument or trait object that has already "captured" some context, and another that explicitly requires that context. If the caller provides the context to the latter, should it override the context used by the former?

Using different contexts for each object would surely create confusion for the user. Would this come up often in practice? Is there a way to mitigate the impact somehow: lints, debugging tools, ...?