With all the above said, it might surprise some people that the nightly compiler (as of 2/3/2022) already appears to behave in the manner described above.
Not in a way that helps with soundness:
#![feature(specialization)]
#![allow(incomplete_features)]
#![allow(unused_variables)]
trait Is<T> {
fn is(&self);
}
impl<A, B> Is<A> for B {
default fn is(&self) {
println!("no");
}
}
impl<T> Is<T> for T {
fn is(&self) {
println!("yes");
}
}
fn is_static_str<N: Is<&'static str>>(t: N) {
t.is();
}
fn fully_generic_wrapper_function_without_trait_bound<N>(t: N) {
is_static_str::<N>(t);
}
fn main() {
let static_str: &'static str = "hey";
let deallocated_at_end_of_main: String = "hello".to_string();
let not_static_str: &'_ str = deallocated_at_end_of_main.as_str();
is_static_str(static_str); // Ok, prints "yes"
is_static_str(0u32); // Ok, prints "no"
is_static_str(&0u32); // Ok, prints "no"
// is_static_str(not_static_str); // Error, borrowed value does not live long enough
fully_generic_wrapper_function_without_trait_bound(static_str); // yes
fully_generic_wrapper_function_without_trait_bound(0u32); // no
fully_generic_wrapper_function_without_trait_bound(&0u32); // no
fully_generic_wrapper_function_without_trait_bound(not_static_str); // yes (no Error!)
}
And on a quick read of your proposal I don’t see how your rules can address the soundness problems from trait-bound-less wrapping functions, since the information about the specialized instances is completely lost/hidden to type-checking the call to such a wrapper function. The only (somewhat sane) sound approach I can come up with is to forbid a function like the fully_generic_wrapper_function_without_trait_bound
above entirely.