Code change:
<br<img width="300" src="https://user-"<br<img width="300" src="https://user-"<brI used the following script to bisect: It bisects to nightly-2022-04-14 and specifically , of which seems the most relevant because it involves associated constants in rustdoc. <!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --<!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOTEND --
is indeed the cause. More specifically the following line: If we “fail” to evaluate (“failure” also includes “the constant is a struct”) the const value of a provided associated const with , we fall back to which prints the constant in raw uncensored form including structs with their private fields. I assume in the non-associated const version (shown below) the call to does not happen and if fails in such a case, neither the value nor the is being printed. . I am not sure how to proceed This is another instance of constant-printing for provided assoc consts being problematic. Previous incident: Performance ().
Maybe we could update the method so that it can only show the public items to fulfill our need?
The ideal solution (non-hotfix) would be to generally improve the printing of (unevaluated) constants (as returned by . . Not sure how easy it is to implement though.
Seems like we want something similar. I don't think it's very difficult but might involve a lot of code. Want to give it a try?
I might as well try. If successful, my PR needs backporting. claim
Error: Parsing assign command in failed: ...'bot assign' ''... Please let know if you're having trouble with this bot.
I'm not convinced that displaying the value of (provided associated) constants in rustdoc is ever worthwhile and indeed it could be harmful. Users should not need to know what value a constant holds, only what it represents; indeed they should only ever be using the constant itself to represent that value when it's required—that is to say, the value assigned is an implementation detail and nobody should be relying upon it.
I strongly disagree. Associated constants are meant to be used by externals users, otherwise they'd not be created. They are definitely not an implementation detail and they are part of the public API so everyone should rely on them. There are a lot of examples so I'll just take one: all  associated constants in the crate.
I'm not sure I follow. Why do I need to know that is ? Surely I will write code that switches on and the compiler handles the rest?
I agree with They are not an implementation detail, at least not those that are of a type that exposes structural equality (deriving and ) since downstream users may depend (as in “compilation may fail if the implementation changes”) on the concrete value of a constant if they use it in a pattern [exhaustiveness checking] or inside of a const argument [type checking] (which may currently require if the type is not numeric). ( I even vaguely remember seeing a Zulip discussion about how public constants always leak their implementation / concrete value, not just those of a type, but I am not sure anymore )
Isn't that just relying on an implementation detail in order to work-around current limitations in the language? If/when lands, the constant should be used in place of its value?
What I am saying is that changing the value of a public constant is a breaking change since it is part of the public API. As a simplified example, consider the case where a crate called exports two constants of type , named and . Crate depending on crate contains the following code: Crate also depending on : In version A of , constant is not equal to and the dependent crates and compile just fine. Now, in the succeeding version B of , and are set equal to each other. and no longer compile with the new version. The inequality was part of the public contract but it was broken. If we wanted to follow SemVer, version B would need to be incompatible with A.
Ah, understood! Sorry for being slow on the uptake :). That all makes sense now.
I understand your argument to some extent, but changing a function's body can also be a SemVer breaking change. Why should constants — which also hide a complex expression and present a simple API, like functions — be treated differently?
I'm a bit lost. We only show public parts of the API unless using and and I are supporting the idea to only show the public parts of "complex" associated constants' value to make it treated like the other items. Or did I completely miss your comment?
My point is that we never show function bodies (even with ), and IMO constants are a subset of () functions, so we also should not show constant bodies. We do show the bodies of free (non-associated) constants already, but I think I'd rather stop doing that instead of also displaying associated constants' values.
I see your point. I disagree though. If you update a constant value, it's the same as changing a function's header: it's a breaking change. And it's also super useful to be able to see the value of a constant (associated or not) and I think it's definitely a big plus.
Well, I at least think we shouldn't show the raw expression from the constant's body; we should only show the fully-computed value.
Yes, we should prefer printing the evaluated const. I am working on this. It's not as trivial and I am going to do it incrementally. The biggest issue is the missing support for const substitutions as you might remember. Yesterday I almost had a working PR done, in some sense a hotfix for this issue, that “censors” complex unevaluated expressions like struct literals and match expressions by replacing them with (over time this procedure can be fine-tuned). However, I ran into some nasty corner cases (certain qualified paths that contain const arguments) and regressions. I will try to simplify the patch, add tests and open it as a PR today or tomorrow (hopefully). I have further plans for improving const support but the current representation of constant expressions and the lack of const substitutions in rustdoc is giving me headaches. I have already prepared a more sophisticated PR that adds hyperlinks to const exprs and understands the concept of private and fields when pretty-printing but it's not quite ready yet.
Yeah, the current state of the code is quite unfortunate :( I've tried to improve it, but as you've seen it's very hard to understand and change.
I don't like this. <img width="1440" alt="image" src="https://user-"
PR coming up within the next hour. I just need to write some more tests.

Related discussion:
text: <ins> // Regression test for issue #97933. // // Test that certain unevaluated constant expressions that are // deemed too verbose or complex and that may leak private or // `doc(hidden)` struct fields are not displayed in the documentation. // // Read the documentation of `rustdoc::clean::utils::print_const_expr` // for further details. // @has hide_complex_unevaluated_consts/trait.Container.html pub trait Container { // A helper constant that prevents const expressions containing it // from getting fully evaluated since it doesn't have a body and // thus is non-reducible. This allows us to specifically test the // pretty-printing of *unevaluated* consts. const ABSTRACT: i32; // Ensure that the private field does not get leaked: // // @has - '//*[@id="associatedconstant.STRUCT0"]'  //        'const STRUCT0: Struct = _' const STRUCT0: Struct = Struct { private: () }; // @has - '//*[@id="associatedconstant.STRUCT1"]'  //        'const STRUCT1: (Struct,) = _' const STRUCT1: (Struct,) = (Struct{private: /**/()},); // Although the struct field is public here, check that it is not // displayed. In a future version of rustdoc, we definitely want to // show it. However for the time being, the printing logic is a bit // conservative. // // @has - '//*[@id="associatedconstant.STRUCT2"]'  //        'const STRUCT2: Record = _' const STRUCT2: Record = Record { public: 5 }; // Test that we do not show the incredibly verbose match expr: // // @has - '//*[@id="associatedconstant.MATCH0"]'  //        'const MATCH0: i32 = _' const MATCH0: i32 = match 234 { 0 => 1, _ => Self::ABSTRACT, }; // @has - '//*[@id="associatedconstant.MATCH1"]'  //        'const MATCH1: bool = _' const MATCH1: bool = match Self::ABSTRACT { _ => true, }; // Check that we hide complex (arithmetic) operations. // In this case, it is a bit unfortunate since the expression // is not *that* verbose and it might be quite useful to the reader. // // However in general, the expression might be quite large and // contain match expressions and structs with private fields. // We would need to recurse over the whole expression and even more // importantly respect operator precedence when pretty-printing // the potentially partially censored expression. // For now, the implementation is quite simple and the choices // rather conservative. // // @has - '//*[@id="associatedconstant.ARITH_OPS"]'  //        'const ARITH_OPS: i32 = _' const ARITH_OPS: i32 = Self::ABSTRACT * 2 + 1; } pub struct Struct { private: () } pub struct Record { pub public: i32 } </ins>