Skip to content
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

Redact CoercePointee target type #136796

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

dingxiangfei2009
Copy link
Contributor

@dingxiangfei2009 dingxiangfei2009 commented Feb 9, 2025

Fix #134846

The issue here is that __S is actually an implementation detail of derive(CoercePointee). This should not appear in our diagnostics. A better way to present this message is to designate it as <pointee generic type> {unsized} as opposed to the undecipherable __S here.

r? @compiler-errors

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Feb 9, 2025
@rust-log-analyzer

This comment has been minimized.

@dingxiangfei2009 dingxiangfei2009 force-pushed the redact-coerce-pointee-target-type branch from 22bab31 to a26a420 Compare February 10, 2025 10:44
@rust-log-analyzer

This comment has been minimized.

@dingxiangfei2009 dingxiangfei2009 force-pushed the redact-coerce-pointee-target-type branch from a26a420 to eb47b38 Compare February 10, 2025 11:13
@dingxiangfei2009
Copy link
Contributor Author

@rustbot label +F-derive_coerce_pointee

@rustbot rustbot added the F-derive_coerce_pointee Feature: RFC 3621's oft-renamed implementation label Feb 10, 2025
@dingxiangfei2009
Copy link
Contributor Author

I will mark as ready when the base PR is is ready to go as well

@dingxiangfei2009 dingxiangfei2009 force-pushed the redact-coerce-pointee-target-type branch from eb47b38 to 8e48d60 Compare February 11, 2025 10:48
@dingxiangfei2009 dingxiangfei2009 marked this pull request as ready for review February 11, 2025 10:50
@rustbot
Copy link
Collaborator

rustbot commented Feb 11, 2025

Some changes occurred in compiler/rustc_codegen_cranelift

cc @bjorn3

Some changes occurred in compiler/rustc_codegen_gcc

cc @antoyo, @GuillaumeGomez

@rust-log-analyzer

This comment has been minimized.

@dingxiangfei2009 dingxiangfei2009 force-pushed the redact-coerce-pointee-target-type branch from 8e48d60 to 8f7c0e5 Compare February 11, 2025 16:16
|
LL | struct TryToWipeRepr<'a, #[pointee] T: ?Sized> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 17 previous errors
error[E0277]: the trait bound `Box<T>: Unsize<Box<T {unsized}>>` is not satisfied
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR changes introduces quite a lot of machinery just to rename __S to T {unsized}. I don't actually think that's very different, and not worth the changes.

If we're going to do anything here, then it needs to be about changing the wording of the error message to explain what this Unsize obligation is about.

Copy link
Contributor Author

@dingxiangfei2009 dingxiangfei2009 Feb 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would like to quote #134846 that this PR attempts to fix:

Desired output
Something that does not mention internal things like Unsize or __S

So I am thinking, should we instead redact all errors from unfulfilled Unsize obligation entirely and replace them with messages to say unsizing <some type> is not permitted, or something along this line?

Concretely, if we encounter a fulfillment error for Ty1: Unsize<Ty2>, we write out a message saying unsizing Ty1 is not permitted and forget about Ty2, since Ty2 may contain internal stuffs like __S in most cases and redacting those internal type names individually is now considered harmful. Is this what we are going after here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. I think all this PR needs to do is intercept the errors in:

if !errors.is_empty() {
infcx.err_ctxt().report_fulfillment_errors(errors);
}

And:

if !errors.is_empty() {
res = Err(infcx.err_ctxt().report_fulfillment_errors(errors));
}

And just say something like: "In order for ADT to have a valid implementation of CoerceUnsized, you need to be able to unsize &W<T>."

Most importantly, it needs to explain why the unsize isn't valid. I know you're interested in fixing what was requested in #134846, but please think about the bigger picture, and also please think about minimizing the changes to the compiler while trying to fix the issue.

Copy link
Member

@compiler-errors compiler-errors left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comment. If we're going to touch these error messages at all, then they should be heavily reworked to explain why the Unsize goal exists at all.

target_pointee_ty: Ty<'tcx>,
new_pointee_ty: Ty<'tcx>,
) -> FulfillmentError<'tcx> {
use traits::FulfillmentErrorCode::*;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no function-local glob imports please

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Feb 11, 2025
@Darksonn
Copy link
Contributor

When you get this error: "the trait bound X: Unsize<Y> is not satisfied"

I think the real error you need to emit is something like:

error: derive(CoercePointee) requires that you can unsize `X`

help: it can only be unsized if it stores exactly one copy of T at the end of the structure
help: the T must be stored without additional pointer indirection

this lets you hide the __S by not printing Y.

If you instead get this error: "the trait bound X: CoerceUnsized<Y> is not satisfied", then you need to emit an error along these lines:

error: the field must be a stdlib pointer type, or a user-defined type using the derive(CoercePointee) macro

@dingxiangfei2009 dingxiangfei2009 force-pushed the redact-coerce-pointee-target-type branch from 8f7c0e5 to 41ef5b5 Compare February 16, 2025 19:33
Copy link
Member

@compiler-errors compiler-errors left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This implementation still needs a lot of clean up and simplification, but I don't want to leave review comments until it's clear that it's ready for review. S

pecifically, please check that the code has no changes that are unrelated to fixing this issue; all changes should either be reverted or exercised by tests.

Please mark it as S-waiting-on-review when it's ready.

@dingxiangfei2009 dingxiangfei2009 force-pushed the redact-coerce-pointee-target-type branch 2 times, most recently from 51fc2ea to 81a0c29 Compare February 17, 2025 20:50
@dingxiangfei2009
Copy link
Contributor Author

dingxiangfei2009 commented Feb 18, 2025

@rustbot ready

  • We now have new tailored diagnostics for Unsize and CoerceUnsized obligation errors originated from derive(CoercePointee).
  • We expand the spans to point into the offending fields in the struct definition.
  • Revert more chunks about the mini-cores, by making the #[pointee] extraction optional

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Feb 18, 2025
@dingxiangfei2009 dingxiangfei2009 force-pushed the redact-coerce-pointee-target-type branch from 81a0c29 to 5044be4 Compare February 18, 2025 21:54
@@ -372,9 +414,11 @@ pub(crate) fn coerce_unsized_info<'tcx>(
let unsize_trait = tcx.require_lang_item(LangItem::Unsize, Some(span));

let source = tcx.type_of(impl_did).instantiate_identity();
let self_ty = source;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please revert this. It's not useful.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

source binding is shadowed later. However, the diagnostics depends on this Self type.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just rename the variable? The reassignment feels a bit awkward.

let trait_ref = tcx.impl_trait_ref(impl_did).unwrap().instantiate_identity();
assert_eq!(trait_ref.def_id, coerce_unsized_trait);
let target = trait_ref.args.type_at(1);
let coerced_ty = target;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here.

trait_name: "DispatchFromDyn",
note: true,
}));
if extract_coerce_pointee_data(tcx, def_a.did()).is_some() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this exercised by a test?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unless there is a good reason to have this, please revert it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.collect::<Vec<_>>()
.join(", "),
}));
if extract_coerce_pointee_data(tcx, def_a.did()).is_some() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this exercised by a test?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@@ -509,12 +553,28 @@ pub(crate) fn coerce_unsized_info<'tcx>(
.collect::<Vec<_>>();

if diff_fields.is_empty() {
if extract_coerce_pointee_data(tcx, def_a.did()).is_some() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this exercised by a test?

if self.found {
return;
}
if t == self.pointee {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this implementation "micro-optimized"? It shouldn't matter to override all these functions, and it makes the visitor much larger than it needs to be.

Comment on lines 121 to 122
if tcx.is_lang_item(pred.def_id(), LangItem::Unsize) {
if mentions_pointee() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this two nested if statements when the next one is &&? Can you choose one?

.note = `derive(CoercePointee)` demands that `{$ty}` can be coerced to an unsized type
.help = the standard pointers such as `Arc`, `Rc`, `Box`, and other types with `derive(CoercePointee)` can be coerced to their corresponding unsized types

hir_analysis_coerce_pointee_cannot_unsize = `{$ty}` cannot be coerced to any unsized value
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
hir_analysis_coerce_pointee_cannot_unsize = `{$ty}` cannot be coerced to any unsized value
hir_analysis_coerce_pointee_cannot_unsize = `{$ty}` cannot be coerced to an unsized value

@@ -85,6 +85,19 @@ hir_analysis_cmse_output_stack_spill =
.note1 = functions with the `{$abi}` ABI must pass their result via the available return registers
.note2 = the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size

hir_analysis_coerce_pointee_cannot_coerce_unsize = `{$ty}` cannot be coerced to an unsized type
.note = `derive(CoercePointee)` demands that `{$ty}` can be coerced to an unsized type
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This note is not exercised by any test, I think?

Copy link
Contributor Author

@dingxiangfei2009 dingxiangfei2009 Feb 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just realised that the note cannot be exercised because the span falls within the macro expansion.

Instead it is overwritten by this message.

note: this error originates in the derive macro `CoercePointee` (in Nightly builds, run with -Z macro-backtrace for more info)

This happens still after adding the missing #[note] and #[help] attributes to the diagnostics.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe I need to switch to the span of the ADT definition.

.help = the standard pointers such as `Arc`, `Rc`, `Box`, and other types with `derive(CoercePointee)` can be coerced to their corresponding unsized types

hir_analysis_coerce_pointee_cannot_unsize = `{$ty}` cannot be coerced to any unsized value
.note = `derive(CoercePointee)` demands that `{$ty}` can be coerced to an unsized type
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar, this note is not exercised by any test?

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Feb 18, 2025
@compiler-errors
Copy link
Member

OK -- so I think I understand my problem with this PR in its current state. Specifically, it's trying to do two things:

  1. Change the error messages when fields violate the implementation validity *structurally, like:
#![feature(derive_coerce_pointee)]
use std::marker::CoercePointee;

#[derive(CoercePointee)]
#[repr(transparent)]
struct P<T: 'static + ?Sized> {
    x: &'static T,
    y: &'static T,
}
  1. Improve the error messages when trait solving fails to satisfy the CoercePointee or DispatchFromDyn goal needed for validity:
#![feature(derive_coerce_pointee)]
use std::marker::CoercePointee;

#[derive(CoercePointee)]
#[repr(transparent)]
struct P<T: 'static + ?Sized> {
    x: (T,),
}

I'm somewhat hesitant that they need to be fixed at the same time, and I dislike the fact that the improvements relies on extract_coerce_pointee_data doing so much work.

For example, for (1.) we could simply just detect if the impl is coming from an expansion (by looking at the span of the impl) and change the error message (like DispatchFromDynSingle, DispatchFromDynMulti) into more tailored versions that don't need to mention the "right-hand-side type", like &'static S__.

For the trait error reporting, we could simply emit a more tailored fulfillment error if there is only one fulfillment error and it ends up failing an Unsize or CoerceUnsized goal, rather than relying on a somewhat pervasive control flow invariant that extract_coerce_pointee_data will emit an error.

TL;DR is that I think this PR is trying to change a lot all at once, and I'm somewhat overwhelmed with the state of it right now.

@dingxiangfei2009
Copy link
Contributor Author

dingxiangfei2009 commented Feb 19, 2025

@compiler-errors I sense that it is preferable to break this PR into two and improve the diagnostics in 1. and 2. separately. Shall we start from there?

pervasive control flow invariant that extract_coerce_pointee_data will emit an error

I couldn't t follow unfortunately. It could be the naming at fault here and I owe the explanation, nevertheless I found the purpose of extract_coerce_pointee_data straightforward. It only deals with deciding whether derive(CoercePointee) is applied and, in that case, extract the location of #[pointee] in the list of generics of the struct.

by looking at the span of the impl

It is where I can see intricacy. I am afraid that span information is brittle and unreliable because derive(CoercePointee) will not be the only source of impl DispatchFromDyn/CoerceUnsized. Even #[derive(CoercePointee)] itself can originate from expansion from other (proc-)macros.

if there is only one fulfillment error

This gets me thinking. What shall be the treatment when there are more than just one, and among those fulfilment errors are some involves __S but not about CoerceUnsized/Unsize/DispatchFromDyn, rather lifetime errors? I will leave the question in the second PR or beyond.

@compiler-errors
Copy link
Member

compiler-errors commented Feb 19, 2025

I opened an alternative PR in #137289 that is a bit less complicated. I think it can be improved and refined in the future, but it seems to me easier to land than this one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
F-derive_coerce_pointee Feature: RFC 3621's oft-renamed implementation S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs Relevant to the library team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Confusing error when using CoercePointee
5 participants