-
Notifications
You must be signed in to change notification settings - Fork 12.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
stricter hidden type wf-check [based on #115008] #121679
Conversation
hir::OpaqueTyOrigin::TyAlias { .. } | ||
if tcx.def_kind(tcx.parent(def_id.to_def_id())) == DefKind::OpaqueTy => {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I removed this, cc #106038 (comment) @aliemjay
I do not think this special-case is worth it and it's fairly fragile, as we cannot check that nested opaque types are well formed while in the defining scope. While I am still positive that the previous behavior was sound, having to allow types which aren't well-formed adds complexity which I don't think is worth it here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
broke my brain for 20 mins, but makes sense now
eaf3fdd
to
af0d508
Compare
@bors try @rust-timer queue |
This comment has been minimized.
This comment has been minimized.
stricter hidden type wf-check [based on rust-lang#115008] Original work by `@aliemjay` in rust-lang#115008. A huge thanks to them for originally figuring out this approach ❤️ Fixes rust-lang#114728 Fixes rust-lang#114572 Instead of adding the `WellFormed` obligations when relating opaque types, I add always emit such an obligation when defining the hidden type. This causes nested opaque types which aren't wf to error, see the comment below for the described impact. I believe this change to be desirable as it significantly reduces complexity by removing special-cases. It also caused an issue with RPITIT: in defaulted trait methods, we add a `Projection(synthetic_assoc, rpit_of_trait_method)` clause to the `param_env`. This clause is not added to the `ParamEnv` of the nested coroutines. This caused a normalization failure in `fn check_coroutine_obligations` with the new solver. I fixed that by using the env of the typeck root instead. r? `@oli-obk`
Context: we're discussing whether the following code is valid despite the fact that the hidden type trait Id<X> { type Ty; }
impl<X> Id<X> for () { type Ty = X; }
fn test<T>() -> impl Id<&'static T, Ty = impl Sized> {} This was accepted as a valid defining use in #106038 and will be rejected with with this PR with the concern of increased complexity.
This breaking change is not necessary for the soundness fix here and thus I prefer to at least have it in a separate PR. Regarding the complexity concern, I believe we can keep supporting this behavior in a less complicated way than in #115008. The previous implementation in #115008 was unnecessarily complex because I wanted to have a perf baseline by emitting the least possible number of WF obligations. Moreover, I think that nested opaque types are special enough to have their own |
Oh, this would also disallow a more natural pattern that is much more likely to appear in the wild: // This is rejected currently because of #96146 but even when this is fixed
// it would still be rejected by this PR with an error that requires `T: 'static` bound in `test`
fn id<T>(s: &T) -> &T { s }
fn test<T>() -> impl Fn(&T) -> impl Sized {
id
} |
☀️ Try build successful - checks-actions |
This comment has been minimized.
This comment has been minimized.
I have strong feelings here and believe we should not support this behavior. Regarding the complexity. My main concern is not the behavior of We should always be able to assume, and verify, that all types are well-formed in the current context. Allowing these patterns breaks this assumption at the point where we define the nested opaque type. This is fragile in two ways: We will have to be careful when emitting WF constraints to avoid this breakage going forward. As shown by this PR. It is very subtle why my approach broke the rust/compiler/rustc_trait_selection/src/traits/project.rs Lines 259 to 269 in 71a7b66
This is not done in the new solver. We'd have to work around it there to continue to support this, for example by also eagerly replacing opaques with inference variables. Even more importantly, we have to worry about accidentally leaking the non-wf type to somewhere which accepts well-formed types. We already have multiple unsoundnesses caused by a lack of WF checks, e.g. #98117. I do not want to make it more difficult to fix such issues as that may end up forcing nested opaques to be well-formed. Supporting this pattern by amending the environment while defining nested opaque types seems a lot more acceptable. However, I believe that doing so is far from trivial. Finally, I don't think this behavior is (very) desirable or consistent with the rest of Rust. I feel like "this was accepted as a valid defining use in #106038" is mostly irrelevant as the concern in #106038 (comment) ended up mostly slipping through and there hasn't been any official team approval of this behavior.This diverges from the behavior of where-clauses where such reasoning is not supported: trait Id<X> { type Ty; }
impl<X> Id<X> for () { type Ty = X; }
fn test<T>()
where
(): Id<&'static T>,
// (): Id<&'static T, Ty = &'static T>
// both of these bounds error
{} I do agree that supporting the following is generally desirable: fn id<T>(s: &T) -> &T { s }
fn test<T>() -> impl Fn(&T) -> impl Sized {
id
} However, even this is imo not a strong argument to not land this PR as is. We currently do not support defining higher-ranked opaque types at all. Trying to do so always errors. I will push against any such attempts until the new solver is exclusively used as I am very much unsure how to soundly handle this when using semantic lookup for the opaque type storage. Once implied bounds are explicitly handled and checked (necessary to fix #25860), we can support the above pattern without needing to support non-wf types as the type would now only be used inside of the
I don't. I consider the breakage for RPIT to have already been FCP'd as part of #115008.
We could separate the removal of the nested TAIT special-case into a separate PR, but given that the added WF-checks during borrowck reduce the breakage caused by that I don't think such a split is desirable. I personally don't have the energy and motivation to first land the approach of #115008 and then move the WF-checks, breaking |
Finished benchmarking commit (1659600): comparison URL. Overall result: ❌ regressions - ACTION NEEDEDBenchmarking this pull request likely means that it is perf-sensitive, so we're automatically marking it as not fit for rolling up. While you can manually mark this PR as fit for rollup, we strongly recommend not doing so since this PR may lead to changes in compiler perf. Next Steps: If you can justify the regressions found in this try perf run, please indicate this with @bors rollup=never Instruction countThis is a highly reliable metric that was used to determine the overall result at the top of this comment.
Max RSS (memory usage)ResultsThis is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.
CyclesResultsThis is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.
Binary sizeResultsThis is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.
Bootstrap: 650.304s -> 650.995s (0.11%) |
The two regressions have similar up and down fluctuations over the last few weeks. @rustbot label: +perf-regression-triaged |
@bors r+ This may be stricter than necessary, but we can relax it later if we realize this is supportable in the new solver |
☀️ Test successful - checks-actions |
Finished benchmarking commit (09bc67b): comparison URL. Overall result: no relevant changes - no action needed@rustbot label: -perf-regression Instruction countThis benchmark run did not return any relevant results for this metric. Max RSS (memory usage)ResultsThis is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.
CyclesResultsThis is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.
Binary sizeThis benchmark run did not return any relevant results for this metric. Bootstrap: 647.585s -> 646.206s (-0.21%) |
This checks that RPIT are well-formed in more cases, fixing a soundness issue. |
Pkgsrc changes: * Adapt checksums and patches, some have beene intregrated upstream. Upstream chnages: Version 1.78.0 (2024-05-02) =========================== Language -------- - [Stabilize `#[cfg(target_abi = ...)]`] (rust-lang/rust#119590) - [Stabilize the `#[diagnostic]` namespace and `#[diagnostic::on_unimplemented]` attribute] (rust-lang/rust#119888) - [Make async-fn-in-trait implementable with concrete signatures] (rust-lang/rust#120103) - [Make matching on NaN a hard error, and remove the rest of `illegal_floating_point_literal_pattern`] (rust-lang/rust#116284) - [static mut: allow mutable reference to arbitrary types, not just slices and arrays] (rust-lang/rust#117614) - [Extend `invalid_reference_casting` to include references casting to bigger memory layout] (rust-lang/rust#118983) - [Add `non_contiguous_range_endpoints` lint for singleton gaps after exclusive ranges] (rust-lang/rust#118879) - [Add `wasm_c_abi` lint for use of older wasm-bindgen versions] (rust-lang/rust#117918) This lint currently only works when using Cargo. - [Update `indirect_structural_match` and `pointer_structural_match` lints to match RFC] (rust-lang/rust#120423) - [Make non-`PartialEq`-typed consts as patterns a hard error] (rust-lang/rust#120805) - [Split `refining_impl_trait` lint into `_reachable`, `_internal` variants] (rust-lang/rust#121720) - [Remove unnecessary type inference when using associated types inside of higher ranked `where`-bounds] (rust-lang/rust#119849) - [Weaken eager detection of cyclic types during type inference] (rust-lang/rust#119989) - [`trait Trait: Auto {}`: allow upcasting from `dyn Trait` to `dyn Auto`] (rust-lang/rust#119338) Compiler -------- - [Made `INVALID_DOC_ATTRIBUTES` lint deny by default] (rust-lang/rust#111505) - [Increase accuracy of redundant `use` checking] (rust-lang/rust#117772) - [Suggest moving definition if non-found macro_rules! is defined later] (rust-lang/rust#121130) - [Lower transmutes from int to pointer type as gep on null] (rust-lang/rust#121282) Target changes: - [Windows tier 1 targets now require at least Windows 10] (rust-lang/rust#115141) - [Enable CMPXCHG16B, SSE3, SAHF/LAHF and 128-bit Atomics in tier 1 Windows] (rust-lang/rust#120820) - [Add `wasm32-wasip1` tier 2 (without host tools) target] (rust-lang/rust#120468) - [Add `wasm32-wasip2` tier 3 target] (rust-lang/rust#119616) - [Rename `wasm32-wasi-preview1-threads` to `wasm32-wasip1-threads`] (rust-lang/rust#122170) - [Add `arm64ec-pc-windows-msvc` tier 3 target] (rust-lang/rust#119199) - [Add `armv8r-none-eabihf` tier 3 target for the Cortex-R52] (rust-lang/rust#110482) - [Add `loongarch64-unknown-linux-musl` tier 3 target] (rust-lang/rust#121832) Refer to Rust's [platform support page][platform-support-doc] for more information on Rust's tiered platform support. Libraries --------- - [Bump Unicode to version 15.1.0, regenerate tables] (rust-lang/rust#120777) - [Make align_offset, align_to well-behaved in all cases] (rust-lang/rust#121201) - [PartialEq, PartialOrd: document expectations for transitive chains] (rust-lang/rust#115386) - [Optimize away poison guards when std is built with panic=abort] (rust-lang/rust#100603) - [Replace pthread `RwLock` with custom implementation] (rust-lang/rust#110211) - [Implement unwind safety for Condvar on all platforms] (rust-lang/rust#121768) - [Add ASCII fast-path for `char::is_grapheme_extended`] (rust-lang/rust#121138) Stabilized APIs --------------- - [`impl Read for &Stdin`] (https://doc.rust-lang.org/stable/std/io/struct.Stdin.html#impl-Read-for-%26Stdin) - [Accept non `'static` lifetimes for several `std::error::Error` related implementations] (rust-lang/rust#113833) - [Make `impl<Fd: AsFd>` impl take `?Sized`] (rust-lang/rust#114655) - [`impl From<TryReserveError> for io::Error`] (https://doc.rust-lang.org/stable/std/io/struct.Error.html#impl-From%3CTryReserveError%3E-for-Error) These APIs are now stable in const contexts: - [`Barrier::new()`] (https://doc.rust-lang.org/stable/std/sync/struct.Barrier.html#method.new) Cargo ----- - [Stabilize lockfile v4](rust-lang/cargo#12852) - [Respect `rust-version` when generating lockfile] (rust-lang/cargo#12861) - [Control `--charset` via auto-detecting config value] (rust-lang/cargo#13337) - [Support `target.<triple>.rustdocflags` officially] (rust-lang/cargo#13197) - [Stabilize global cache data tracking] (rust-lang/cargo#13492) Misc ---- - [rustdoc: add `--test-builder-wrapper` arg to support wrappers such as RUSTC_WRAPPER when building doctests] (rust-lang/rust#114651) Compatibility Notes ------------------- - [Many unsafe precondition checks now run for user code with debug assertions enabled] (rust-lang/rust#120594) This change helps users catch undefined behavior in their code, though the details of how much is checked are generally not stable. - [riscv only supports split_debuginfo=off for now] (rust-lang/rust#120518) - [Consistently check bounds on hidden types of `impl Trait`] (rust-lang/rust#121679) - [Change equality of higher ranked types to not rely on subtyping] (rust-lang/rust#118247) - [When called, additionally check bounds on normalized function return type] (rust-lang/rust#118882) - [Expand coverage for `arithmetic_overflow` lint] (rust-lang/rust#119432) Internal Changes ---------------- These changes do not affect any public interfaces of Rust, but they represent significant improvements to the performance or internals of rustc and related tools. - [Update to LLVM 18](rust-lang/rust#120055) - [Build `rustc` with 1CGU on `x86_64-pc-windows-msvc`] (rust-lang/rust#112267) - [Build `rustc` with 1CGU on `x86_64-apple-darwin`] (rust-lang/rust#112268) - [Introduce `run-make` V2 infrastructure, a `run_make_support` library and port over 2 tests as example] (rust-lang/rust#113026) - [Windows: Implement condvar, mutex and rwlock using futex] (rust-lang/rust#121956)
Original work by @aliemjay in #115008. A huge thanks to them for originally figuring out this approach ❤️
Fixes #114728
Fixes #114572
Instead of adding the
WellFormed
obligations when relating opaque types, we now always emit such an obligation when defining the hidden type.This causes nested opaque types which aren't wf to error, see the comment below for the described impact. I believe this change to be desirable as it significantly reduces complexity by removing special-cases.
It also caused an issue with RPITIT: in defaulted trait methods, we add a
Projection(synthetic_assoc, rpit_of_trait_method)
clause to theparam_env
. This clause is not added to theParamEnv
of the nested coroutines. This caused a normalization failure infn check_coroutine_obligations
with the new solver. I fixed that by using the env of the typeck root instead.r? @oli-obk