Open QuineDot opened 1 year ago
Note that while there is a coherence_leak_check
warning here, Niko's last comment on the issue says:
Update: I've posted https://github.com/rust-lang/rust/pull/72493. It affects this tracking issue in that it makes some patterns into hard-errors. However, the patterns we've seen reported thus far (which are actually the same pattern) still work with a warning. The MCP https://github.com/rust-lang/compiler-team/issues/295 describes my overall plan here and my hope is to keep those patterns working long term.
@rustbot label regression-from-stable-to-stable
WG-prioritization assigning priority (Zulip discussion).
@rustbot label -I-prioritize +P-medium
Wow that's a wild one... not sure whom to Cc here. @tmiasko @compiler-errors for some general MIR knowledge, and @lcnr since traits seem involved somehow.
The error is a bit different on latest stable
error: internal compiler error: error performing ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: UserFacing }, value: ProvePredicate { predicate: Binder { value: TraitPredicate(<fn(std::cell::Ref<'_, u32>) as IntoSystem>, polarity:Positive), bound_vars: [] } } }
--> src/main.rs:37:18
|
37 | let _sys_c = (sys_ref as fn(_)).into_system();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: delayed at /rustc/eb45c844407968ea54df0d9870ebce9e3235b706/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs:165:29
Huh. I'm surprised that this doesn't cause a trait error in HIR typeck. It does if we use a type alias to avoid introducing a higher ranked fn ptr and actually ascribe the fn(Ref<'?0, u32>)
...:
type Fun<A> = fn(A);
fn main() {
fn sys_ref(_age: Ref<u32>) {}
let _sys_c = (sys_ref as Fun<Ref<'_, u32>>).into_system();
//~^ ERROR no method named `into_system` found for fn pointer `fn(Ref<'_, u32>)` in the current scope
Woo, this is due to a lot of fun things.
Firstly, we defer the cast of sys_ref as fn(_)
until after the rest of typeck, which means that we only know that the receiver of .into_system()
is fn(?0)
. That registers a fn(?0): IntoSystem
goal, which does pass the leak check in method probing because we haven't constrained ?0
.
After we apply the cast, we do end up with fn(Ref<'?1, u32>): IntoSystem
goal, which itself doesn't do any leak check because this is fulfillment and not evaluation.
Also, I guess this also has nothing to do with method probing technically:
// Borrowing the trait definitions from above above
fn foo<T>(_: Option<T>) where T: IntoSystem {}
fn main() {
let x = None::<fn(_)>;
foo(x);
let y: Option<fn(Ref<'static, u32>)> = x;
}
... which still ICEs during mir borrowck.
we may want to leak check at the end of hir typeck. Feels like the easiest fix :grin:
minimized:
trait Trait {}
impl<T: for<'a> LeakErr<'a>> Trait for T {}
impl<U: for<'a> LeakErr<'a>> Trait for Option<U> {}
trait LeakErr<'a> {}
impl<T> LeakErr<'static> for T {}
fn impls_trait<T: Trait>(x: T) -> T {
x
}
fn main() {
let y = impls_trait(None);
let _: Option<u32> = y;
}
What's happening here is the following:
evaluation_probe
In HIR typeck, we select Option<?x>: Trait
which has two applicable candidates, causing us to use evaluate_candidate
. for<'a> Option<?x>: LeakErr<'a>
of the first impl causes a leak check error. for<'a> ?x: LeakErr<'a>
of the second impl remains ambiguous. This causes us to select the second impl. We then only prove for<'a> u32: LeakErr<'a>
in fulfillment which does not use the leak check. THis causes HIR typeck to pass.
In MIR typeck, we select Option<u32>: Trait
which has two applicable candidates, causing us to use evaluate_candidate
. However, now both candidates fail the leak check, causing us to have no applicable impl, causing a selection error.
Code
Playground.
Meta
Playground:
It wasn't an ICE in 1.62.
Error output