Skip to content

Commit

Permalink
Rollup merge of rust-lang#111451 - compiler-errors:note-cast-origin, …
Browse files Browse the repository at this point in the history
…r=b-naber

Note user-facing types of coercion failure

When coercing, for example, `Box<A>` into `Box<dyn B>`, make sure that any failure notes mention *those* specific types, rather than mentioning inner types, like "the cast from `A` to `dyn B`".

I expect end-users are often confused when we skip layers of types and only mention the "innermost" part of a coercion, especially when other notes point at HIR, e.g. rust-lang#111406.
  • Loading branch information
matthiaskrgr authored May 11, 2023
2 parents 3bacb85 + ccd8ad7 commit 2ea9c89
Show file tree
Hide file tree
Showing 64 changed files with 140 additions and 223 deletions.
3 changes: 0 additions & 3 deletions compiler/rustc_middle/src/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -281,9 +281,6 @@ pub enum ObligationCauseCode<'tcx> {
/// A type like `Box<Foo<'a> + 'b>` is WF only if `'b: 'a`.
ObjectTypeBound(Ty<'tcx>, ty::Region<'tcx>),

/// Obligation incurred due to an object cast.
ObjectCastObligation(/* Concrete type */ Ty<'tcx>, /* Object type */ Ty<'tcx>),

/// Obligation incurred due to a coercion.
Coercion {
source: Ty<'tcx>,
Expand Down
16 changes: 12 additions & 4 deletions compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -797,9 +797,17 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
err.span_label(span, explanation);
}

if let ObligationCauseCode::ObjectCastObligation(concrete_ty, obj_ty) = obligation.cause.code().peel_derives() &&
Some(trait_ref.def_id()) == self.tcx.lang_items().sized_trait() {
self.suggest_borrowing_for_object_cast(&mut err, &root_obligation, *concrete_ty, *obj_ty);
if let ObligationCauseCode::Coercion { source, target } =
*obligation.cause.code().peel_derives()
{
if Some(trait_ref.def_id()) == self.tcx.lang_items().sized_trait() {
self.suggest_borrowing_for_object_cast(
&mut err,
&root_obligation,
source,
target,
);
}
}

let UnsatisfiedConst(unsatisfied_const) = self
Expand Down Expand Up @@ -1510,7 +1518,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
| ObligationCauseCode::BindingObligation(_, _)
| ObligationCauseCode::ExprItemObligation(..)
| ObligationCauseCode::ExprBindingObligation(..)
| ObligationCauseCode::ObjectCastObligation(..)
| ObligationCauseCode::Coercion { .. }
| ObligationCauseCode::OpaqueType
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1442,8 +1442,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
err: &mut Diagnostic,
obligation: &PredicateObligation<'tcx>,
self_ty: Ty<'tcx>,
object_ty: Ty<'tcx>,
target_ty: Ty<'tcx>,
) {
let ty::Ref(_, object_ty, hir::Mutability::Not) = target_ty.kind() else { return; };
let ty::Dynamic(predicates, _, ty::Dyn) = object_ty.kind() else { return; };
let self_ref_ty = self.tcx.mk_imm_ref(self.tcx.lifetimes.re_erased, self_ty);

Expand All @@ -1458,7 +1459,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
err.span_suggestion(
obligation.cause.span.shrink_to_lo(),
format!(
"consider borrowing the value, since `&{self_ty}` can be coerced into `{object_ty}`"
"consider borrowing the value, since `&{self_ty}` can be coerced into `{target_ty}`"
),
"&",
Applicability::MaybeIncorrect,
Expand Down Expand Up @@ -2851,30 +2852,27 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
err.span_note(tcx.def_span(item_def_id), descr);
}
}
ObligationCauseCode::ObjectCastObligation(concrete_ty, object_ty) => {
let (concrete_ty, concrete_file) =
self.tcx.short_ty_string(self.resolve_vars_if_possible(concrete_ty));
let (object_ty, object_file) =
self.tcx.short_ty_string(self.resolve_vars_if_possible(object_ty));
ObligationCauseCode::Coercion { source, target } => {
let (source, source_file) =
self.tcx.short_ty_string(self.resolve_vars_if_possible(source));
let (target, target_file) =
self.tcx.short_ty_string(self.resolve_vars_if_possible(target));
err.note(with_forced_trimmed_paths!(format!(
"required for the cast from `{concrete_ty}` to the object type `{object_ty}`",
"required for the cast from `{source}` to `{target}`",
)));
if let Some(file) = concrete_file {
if let Some(file) = source_file {
err.note(format!(
"the full name for the casted type has been written to '{}'",
"the full name for the source type has been written to '{}'",
file.display(),
));
}
if let Some(file) = object_file {
if let Some(file) = target_file {
err.note(format!(
"the full name for the object type has been written to '{}'",
"the full name for the target type has been written to '{}'",
file.display(),
));
}
}
ObligationCauseCode::Coercion { source: _, target } => {
err.note(format!("required by cast to type `{}`", self.ty_to_string(target)));
}
ObligationCauseCode::RepeatElementCopy { is_const_fn } => {
err.note(
"the `Copy` trait is required because this value will be copied for each element of the array",
Expand Down
36 changes: 12 additions & 24 deletions compiler/rustc_trait_selection/src/traits/select/confirmation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ use crate::traits::{
ImplSourceAutoImplData, ImplSourceBuiltinData, ImplSourceClosureData,
ImplSourceConstDestructData, ImplSourceFnPointerData, ImplSourceFutureData,
ImplSourceGeneratorData, ImplSourceObjectData, ImplSourceTraitAliasData,
ImplSourceTraitUpcastingData, ImplSourceUserDefinedData, Normalized, ObjectCastObligation,
Obligation, ObligationCause, OutputTypeParameterMismatch, PredicateObligation, Selection,
SelectionError, TraitNotObjectSafe, TraitObligation, Unimplemented,
ImplSourceTraitUpcastingData, ImplSourceUserDefinedData, Normalized, Obligation,
ObligationCause, OutputTypeParameterMismatch, PredicateObligation, Selection, SelectionError,
TraitNotObjectSafe, TraitObligation, Unimplemented,
};

use super::BuiltinImplConditions;
Expand Down Expand Up @@ -905,16 +905,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
.map_err(|_| Unimplemented)?;
nested.extend(obligations);

// Register one obligation for 'a: 'b.
let cause = ObligationCause::new(
obligation.cause.span,
obligation.cause.body_id,
ObjectCastObligation(source, target),
);
let outlives = ty::OutlivesPredicate(r_a, r_b);
nested.push(Obligation::with_depth(
tcx,
cause,
obligation.cause.clone(),
obligation.recursion_depth + 1,
obligation.param_env,
obligation.predicate.rebind(outlives),
Expand Down Expand Up @@ -1005,15 +999,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
nested.extend(obligations);

// Register one obligation for 'a: 'b.
let cause = ObligationCause::new(
obligation.cause.span,
obligation.cause.body_id,
ObjectCastObligation(source, target),
);
let outlives = ty::OutlivesPredicate(r_a, r_b);
nested.push(Obligation::with_depth(
tcx,
cause,
obligation.cause.clone(),
obligation.recursion_depth + 1,
obligation.param_env,
obligation.predicate.rebind(outlives),
Expand All @@ -1027,16 +1016,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
return Err(TraitNotObjectSafe(did));
}

let cause = ObligationCause::new(
obligation.cause.span,
obligation.cause.body_id,
ObjectCastObligation(source, target),
);

let predicate_to_obligation = |predicate| {
Obligation::with_depth(
tcx,
cause.clone(),
obligation.cause.clone(),
obligation.recursion_depth + 1,
obligation.param_env,
predicate,
Expand All @@ -1056,7 +1039,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
);

// We can only make objects from sized types.
let tr = ty::TraitRef::from_lang_item(tcx, LangItem::Sized, cause.span, [source]);
let tr = ty::TraitRef::from_lang_item(
tcx,
LangItem::Sized,
obligation.cause.span,
[source],
);
nested.push(predicate_to_obligation(tr.without_const().to_predicate(tcx)));

// If the type is `Foo + 'a`, ensure that the type
Expand Down
21 changes: 13 additions & 8 deletions compiler/rustc_trait_selection/src/traits/select/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2647,14 +2647,19 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
let predicates = predicates.instantiate_own(tcx, substs);
let mut obligations = Vec::with_capacity(predicates.len());
for (index, (predicate, span)) in predicates.into_iter().enumerate() {
let cause = cause.clone().derived_cause(parent_trait_pred, |derived| {
ImplDerivedObligation(Box::new(ImplDerivedObligationCause {
derived,
impl_or_alias_def_id: def_id,
impl_def_predicate_index: Some(index),
span,
}))
});
let cause =
if Some(parent_trait_pred.def_id()) == tcx.lang_items().coerce_unsized_trait() {
cause.clone()
} else {
cause.clone().derived_cause(parent_trait_pred, |derived| {
ImplDerivedObligation(Box::new(ImplDerivedObligationCause {
derived,
impl_or_alias_def_id: def_id,
impl_def_predicate_index: Some(index),
span,
}))
})
};
let predicate = normalize_with_depth_to(
self,
param_env,
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/associated-types/associated-types-eq-3.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ note: expected this to be `Bar`
|
LL | type A = usize;
| ^^^^^
= note: required for the cast from `isize` to the object type `dyn Foo<A = Bar>`
= note: required for the cast from `&isize` to `&dyn Foo<A = Bar>`

error: aborting due to 3 previous errors

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ error[E0271]: expected `IntoIter<u32>` to be an iterator that yields `i32`, but
LL | let _: &dyn I32Iterator<Item = u32> = &vec![42].into_iter();
| ^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `u32`
|
= note: required for the cast from `std::vec::IntoIter<u32>` to the object type `dyn Iterator<Item = u32, Item = i32>`
= note: required for the cast from `&std::vec::IntoIter<u32>` to `&dyn Iterator<Item = u32, Item = i32>`

error: aborting due to previous error

Expand Down
2 changes: 1 addition & 1 deletion tests/ui/associated-types/issue-65774-1.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ LL | impl<'a, T: MyDisplay> MyDisplay for &'a mut T { }
| --------- ^^^^^^^^^ ^^^^^^^^^
| |
| unsatisfied trait bound introduced here
= note: required for the cast from `&mut T` to the object type `dyn MyDisplay`
= note: required for the cast from `&&mut T` to `&dyn MyDisplay`

error: aborting due to 2 previous errors

Expand Down
2 changes: 1 addition & 1 deletion tests/ui/associated-types/issue-65774-2.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ LL | writer.my_write(valref)
| ^^^^^^ the trait `MyDisplay` is not implemented for `T`
|
= help: the trait `MyDisplay` is implemented for `&'a mut T`
= note: required for the cast from `T` to the object type `dyn MyDisplay`
= note: required for the cast from `&mut T` to `&dyn MyDisplay`

error: aborting due to 2 previous errors

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ error[E0271]: expected `[async block@$DIR/async-block-control-flow-static-semant
LL | let _: &dyn Future<Output = ()> = &block;
| ^^^^^^ expected `()`, found `u8`
|
= note: required for the cast from `[async block@$DIR/async-block-control-flow-static-semantics.rs:23:17: 25:6]` to the object type `dyn Future<Output = ()>`
= note: required for the cast from `&[async block@$DIR/async-block-control-flow-static-semantics.rs:23:17: 25:6]` to `&dyn Future<Output = ()>`

error[E0308]: mismatched types
--> $DIR/async-block-control-flow-static-semantics.rs:12:43
Expand All @@ -51,7 +51,7 @@ error[E0271]: expected `[async block@$DIR/async-block-control-flow-static-semant
LL | let _: &dyn Future<Output = ()> = &block;
| ^^^^^^ expected `()`, found `u8`
|
= note: required for the cast from `[async block@$DIR/async-block-control-flow-static-semantics.rs:14:17: 16:6]` to the object type `dyn Future<Output = ()>`
= note: required for the cast from `&[async block@$DIR/async-block-control-flow-static-semantics.rs:14:17: 16:6]` to `&dyn Future<Output = ()>`

error[E0308]: mismatched types
--> $DIR/async-block-control-flow-static-semantics.rs:49:44
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/async-await/issue-86507.drop_tracking.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ note: captured value is not `Send` because `&` references cannot be sent unless
|
LL | let x = x;
| ^ has type `&T` which is not `Send`, because `T` is not `Sync`
= note: required for the cast from `[async block@$DIR/issue-86507.rs:21:17: 23:18]` to the object type `dyn Future<Output = ()> + Send`
= note: required for the cast from `Pin<Box<[async block@$DIR/issue-86507.rs:21:17: 23:18]>>` to `Pin<Box<(dyn Future<Output = ()> + Send + 'async_trait)>>`
help: consider further restricting this bound
|
LL | fn bar<'me, 'async_trait, T: Send + std::marker::Sync>(x: &'me T)
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/async-await/issue-86507.drop_tracking_mir.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ note: captured value is not `Send` because `&` references cannot be sent unless
|
LL | let x = x;
| ^ has type `&T` which is not `Send`, because `T` is not `Sync`
= note: required for the cast from `[async block@$DIR/issue-86507.rs:21:17: 23:18]` to the object type `dyn Future<Output = ()> + Send`
= note: required for the cast from `Pin<Box<[async block@$DIR/issue-86507.rs:21:17: 23:18]>>` to `Pin<Box<(dyn Future<Output = ()> + Send + 'async_trait)>>`
help: consider further restricting this bound
|
LL | fn bar<'me, 'async_trait, T: Send + std::marker::Sync>(x: &'me T)
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/async-await/issue-86507.no_drop_tracking.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ note: captured value is not `Send` because `&` references cannot be sent unless
|
LL | let x = x;
| ^ has type `&T` which is not `Send`, because `T` is not `Sync`
= note: required for the cast from `[async block@$DIR/issue-86507.rs:21:17: 23:18]` to the object type `dyn Future<Output = ()> + Send`
= note: required for the cast from `Pin<Box<[async block@$DIR/issue-86507.rs:21:17: 23:18]>>` to `Pin<Box<(dyn Future<Output = ()> + Send + 'async_trait)>>`
help: consider further restricting this bound
|
LL | fn bar<'me, 'async_trait, T: Send + std::marker::Sync>(x: &'me T)
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/closure_context/issue-26046-fn-mut.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ LL | num += 1;
LL | Box::new(closure)
| ----------------- the requirement to implement `Fn` derives from here
|
= note: required for the cast from `[closure@$DIR/issue-26046-fn-mut.rs:4:19: 4:21]` to the object type `dyn Fn()`
= note: required for the cast from `Box<[closure@$DIR/issue-26046-fn-mut.rs:4:19: 4:21]>` to `Box<(dyn Fn() + 'static)>`

error: aborting due to previous error

Expand Down
2 changes: 1 addition & 1 deletion tests/ui/closure_context/issue-26046-fn-once.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ LL | vec
LL | Box::new(closure)
| ----------------- the requirement to implement `Fn` derives from here
|
= note: required for the cast from `[closure@$DIR/issue-26046-fn-once.rs:4:19: 4:26]` to the object type `dyn Fn() -> Vec<u8>`
= note: required for the cast from `Box<[closure@$DIR/issue-26046-fn-once.rs:4:19: 4:26]>` to `Box<(dyn Fn() -> Vec<u8> + 'static)>`

error: aborting due to previous error

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ error[E0277]: the trait bound `(): std::error::Error` is not satisfied
LL | /* *mut $0 is coerced to Box<dyn Error> here */ Box::<_ /* ! */>::new(x)
| ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::error::Error` is not implemented for `()`
|
= note: required for the cast from `()` to the object type `dyn std::error::Error`
= note: required for the cast from `Box<()>` to `Box<(dyn std::error::Error + 'static)>`

error[E0277]: the trait bound `(): std::error::Error` is not satisfied
--> $DIR/coerce-issue-49593-box-never.rs:23:49
|
LL | /* *mut $0 is coerced to *mut Error here */ raw_ptr_box::<_ /* ! */>(x)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::error::Error` is not implemented for `()`
|
= note: required for the cast from `()` to the object type `(dyn std::error::Error + 'static)`
= note: required for the cast from `*mut ()` to `*mut (dyn std::error::Error + 'static)`

error: aborting due to 2 previous errors

Expand Down
4 changes: 2 additions & 2 deletions tests/ui/const-generics/defaults/trait_objects_fail.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ LL | foo(&10_u32);
| ^^^^^^^ the trait `Trait` is not implemented for `u32`
|
= help: the trait `Trait<2>` is implemented for `u32`
= note: required for the cast from `u32` to the object type `dyn Trait`
= note: required for the cast from `&u32` to `&dyn Trait`

error[E0277]: the trait bound `bool: Traitor<_>` is not satisfied
--> $DIR/trait_objects_fail.rs:28:9
Expand All @@ -14,7 +14,7 @@ LL | bar(&true);
| ^^^^^ the trait `Traitor<_>` is not implemented for `bool`
|
= help: the trait `Traitor<2, 3>` is implemented for `bool`
= note: required for the cast from `bool` to the object type `dyn Traitor<_>`
= note: required for the cast from `&bool` to `&dyn Traitor<_>`

error: aborting due to 2 previous errors

Expand Down
2 changes: 1 addition & 1 deletion tests/ui/custom_test_frameworks/mismatch.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ LL | #[test]
LL | fn wrong_kind(){}
| ^^^^^^^^^^^^^^^^^ the trait `Testable` is not implemented for `TestDescAndFn`
|
= note: required for the cast from `TestDescAndFn` to the object type `dyn Testable`
= note: required for the cast from `&TestDescAndFn` to `&dyn Testable`
= note: this error originates in the attribute macro `test` (in Nightly builds, run with -Z macro-backtrace for more info)

error: aborting due to previous error
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/diagnostic-width/E0271.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ note: expected this to be `Foo`
|
LL | type Error = E;
| ^
= note: required for the cast from `Result<Result<..., ...>, ...>` to the object type `dyn Future<Error = Foo>`
= note: the full name for the casted type has been written to '$TEST_BUILD_DIR/diagnostic-width/E0271/E0271.long-type-hash.txt'
= note: required for the cast from `Box<Result<..., ...>>` to `Box<(dyn Future<Error = Foo> + 'static)>`
= note: the full name for the source type has been written to '$TEST_BUILD_DIR/diagnostic-width/E0271/E0271.long-type-hash.txt'

error: aborting due to previous error

Expand Down
4 changes: 2 additions & 2 deletions tests/ui/dst/dst-bad-coerce1.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ error[E0277]: the trait bound `Foo: Bar` is not satisfied
LL | let f3: &Fat<dyn Bar> = f2;
| ^^ the trait `Bar` is not implemented for `Foo`
|
= note: required for the cast from `Foo` to the object type `dyn Bar`
= note: required for the cast from `&Fat<Foo>` to `&Fat<dyn Bar>`

error[E0308]: mismatched types
--> $DIR/dst-bad-coerce1.rs:28:27
Expand All @@ -34,7 +34,7 @@ error[E0277]: the trait bound `Foo: Bar` is not satisfied
LL | let f3: &(dyn Bar,) = f2;
| ^^ the trait `Bar` is not implemented for `Foo`
|
= note: required for the cast from `Foo` to the object type `dyn Bar`
= note: required for the cast from `&(Foo,)` to `&(dyn Bar,)`

error: aborting due to 4 previous errors

Expand Down
Loading

0 comments on commit 2ea9c89

Please sign in to comment.