Description
revives #91068 which has been fixed by only considering implied bounds from projections if they don't normalize while typechecking the function itself
rust/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
Lines 256 to 289 in 7125846
This does not mean that the projection won't normalize when getting called:
trait Trait {
type Type;
}
impl<T> Trait for T {
type Type = ();
}
fn f<'a, 'b>(s: &'b str, _: <&'a &'b () as Trait>::Type) -> &'a str
where
&'a &'b (): Trait, // <- adding this bound is the change from #91068
{
s
}
fn main() {
let x = String::from("Hello World!");
let y = f(&x, ());
drop(x);
println!("{}", y);
}
The added bound prevents <&'a &'b () as Trait>::Type
from getting normalized while borrowchecking f
, as we prefer param candidates over impl candidates. When calling f
, we don't have the &'a &'b (): Trait
in our param_env
, so we can now freely use the impl candidate to normalize the projection. The caller therefore doesn't have to prove that &'a &'b ()
is well formed, causing unsoundness.
I am a bit surprised that the caller doesn't have to prove that the &'a &'b (): Trait
obligation is well formed, which would cause this example to not be unsound. It doesn't remove the general unsoundness here though. Here's an alternative test where that isn't enough:
trait Trait {
type Type;
}
impl<T> Trait for T {
type Type = ();
}
fn f<'a, 'b>(s: &'b str, _: <&'a &'b () as Trait>::Type) -> &'a str
where
for<'what, 'ever> &'what &'ever (): Trait,
{
s
}
fn main() {
let x = String::from("Hello World!");
let y = f(&x, ());
drop(x);
println!("{}", y);
}