# `WithOptConstParam` cycle diagram ```rust struct Foo; impl Foo { fn foo<const N: usize>(self) -> [u8; N] { [0; N] } // ^ called `const_param` in the diagram } struct Bar; impl Bar { fn foo<const M: i32>(self) -> [u8; 3] { [0; 3] } } fn context() -> [u8; 4] { let x = Foo; x.foo::<{ 3 + 1 }>() // ^^^^^^^^^ called `constant` in the diagram } ``` Without `WithOptConstParam` we would get the following cycle: ```mermaid flowchart TD TypeckAnonConst["typeck(constant)"] OptConstParam["opt_const_param_of(constant)"] TypeckContext["typeck(context)"] EvaluateConst["evaluate `constant`"] TypeckAnonConst -- needs the expected return type --> OptConstParam OptConstParam -- resolve `foo` --> TypeckContext TypeckContext -- to unify `constant` with the return type --> EvaluateConst EvaluateConst -- requires the MIR of `constant` --> TypeckAnonConst ``` Using `WithOptConstParam` we get the following setup: ```mermaid flowchart TD subgraph TypeckAnonConst["typeck(constant)"] OptConstParam["opt_const_param_of(constant)"] CallTypeckConstArg["returned `Some(const_param)`"] end TypeckConstArg["typeck_const_arg(constant, const_param)"] OptConstParam["opt_const_param_of(constant)"] subgraph TypeckContext["typeck(context)"] EvaluateConstant["evaluate `constant`"] OtherStuff["other stuff"] end OptConstParam -- "to resolve `foo`" --> EvaluateConstant EvaluateConstant -- "requires the MIR of `constant`"--> TypeckConstArg TypeckConstArg -- "once finished" --> OtherStuff OtherStuff -- "once finished" --> CallTypeckConstArg CallTypeckConstArg -- "to only typeck `constant` once" --> TypeckConstArg ``` While this works, it does get a lot more complex when the anonymous constant contains closures or inline consts. Both of these things are luckily either unstable or not useful. ```rust struct Foo; impl Foo { fn foo<const N: usize>(self) -> [u8; N] { [0; N] } // ^ called `const_param` in the diagram } fn context() -> [u8; 4] { let x = Foo; // either THIS: x.foo::<{ const {1} + 3 }>(); // ^^^^^^^^^ called `child` in the diagram // ^^^^^^^^^^^^^ called `constant` in the diagram // or THIS: x.foo::<{ (|| 4)() }>(); // ^^^^^^ called `child` in the diagram // ^^^^^^^^^^^^^ called `constant` in the diagram } ``` ```mermaid flowchart TD TypeckAnonConst["typeck(constant)"] OptConstParam["opt_const_param_of(constant)"] TypeckContext["typeck(context)"] EvaluateConst["evaluate `constant`"] BorrowckConst["mir_borrowck(constant, const_param)"] BorrowckChild["mir_borrowck(child)"] TypeckAnonConst -- needs the expected return type --> OptConstParam OptConstParam -- resolve `foo` --> TypeckContext TypeckContext -- to unify `constant` with the return type --> EvaluateConst EvaluateConst -- requires the MIR --> BorrowckConst BorrowckConst -- relies on facts from nested items --> BorrowckChild BorrowckChild -- closures and inline consts rely on the parents typeck --> TypeckAnonConst ``` The issue is that, when calling `mir_borrowck` - or some similar query - for the `child`, we "forget" the const parameter for `constant` by entering a new query. Changing constants and inline constants to also always use `WithOptConstParam` to remember the relevant const parameter for their parent seems like quite a lot of effort. As this isn't a high priority I would prefer to wait for less hacky fix by improving the query system to deal with these cycles.