Rollup merge of #147840 - jdonszelmann:unsizing-coercions, r=lcnr
Rework unsizing coercions in the new solver Replaces https://github.com/rust-lang/rust/pull/141926, contains: - a commit adding tests that fail before this work - the two commits from the previous PR - a commit in which these tests are fixed - finally, a fixup for an in my opinion rather large regression in diagnostics. It's still not perfect, but better? I hope this is roughly what you had in mind Fixes https://github.com/rust-lang/trait-system-refactor-initiative/issues/241 and https://github.com/rust-lang/trait-system-refactor-initiative/issues/238, adding tests for both r? ````@lcnr````
This commit is contained in:
@@ -35,13 +35,13 @@
|
||||
//! // and are then unable to coerce `&7i32` to `&mut i32`.
|
||||
//! ```
|
||||
|
||||
use std::ops::Deref;
|
||||
use std::ops::{ControlFlow, Deref};
|
||||
|
||||
use rustc_errors::codes::*;
|
||||
use rustc_errors::{Applicability, Diag, struct_span_code_err};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::attrs::InlineAttr;
|
||||
use rustc_hir::def_id::{DefId, LocalDefId};
|
||||
use rustc_hir::{self as hir, LangItem};
|
||||
use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
|
||||
use rustc_infer::infer::relate::RelateResult;
|
||||
use rustc_infer::infer::{DefineOpaqueTypes, InferOk, InferResult, RegionVariableOrigin};
|
||||
@@ -56,6 +56,8 @@ use rustc_middle::ty::error::TypeError;
|
||||
use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt};
|
||||
use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Span};
|
||||
use rustc_trait_selection::infer::InferCtxtExt as _;
|
||||
use rustc_trait_selection::solve::inspect::{self, InferCtxtProofTreeExt, ProofTreeVisitor};
|
||||
use rustc_trait_selection::solve::{Certainty, Goal, NoSolution};
|
||||
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
|
||||
use rustc_trait_selection::traits::{
|
||||
self, ImplSource, NormalizeExt, ObligationCause, ObligationCauseCode, ObligationCtxt,
|
||||
@@ -639,11 +641,44 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
||||
Adjust::Pointer(PointerCoercion::Unsize),
|
||||
)?;
|
||||
|
||||
let mut selcx = traits::SelectionContext::new(self);
|
||||
|
||||
// Create an obligation for `Source: CoerceUnsized<Target>`.
|
||||
let cause = self.cause(self.cause.span, ObligationCauseCode::Coercion { source, target });
|
||||
let pred = ty::TraitRef::new(self.tcx, coerce_unsized_did, [coerce_source, coerce_target]);
|
||||
let obligation = Obligation::new(self.tcx, cause, self.fcx.param_env, pred);
|
||||
|
||||
if self.next_trait_solver() {
|
||||
coercion.obligations.push(obligation);
|
||||
|
||||
if self
|
||||
.infcx
|
||||
.visit_proof_tree(
|
||||
Goal::new(self.tcx, self.param_env, pred),
|
||||
&mut CoerceVisitor { fcx: self.fcx, span: self.cause.span },
|
||||
)
|
||||
.is_break()
|
||||
{
|
||||
return Err(TypeError::Mismatch);
|
||||
}
|
||||
} else {
|
||||
self.coerce_unsized_old_solver(
|
||||
obligation,
|
||||
&mut coercion,
|
||||
coerce_unsized_did,
|
||||
unsize_did,
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(coercion)
|
||||
}
|
||||
|
||||
fn coerce_unsized_old_solver(
|
||||
&self,
|
||||
obligation: Obligation<'tcx, ty::Predicate<'tcx>>,
|
||||
coercion: &mut InferOk<'tcx, (Vec<Adjustment<'tcx>>, Ty<'tcx>)>,
|
||||
coerce_unsized_did: DefId,
|
||||
unsize_did: DefId,
|
||||
) -> Result<(), TypeError<'tcx>> {
|
||||
let mut selcx = traits::SelectionContext::new(self);
|
||||
// Use a FIFO queue for this custom fulfillment procedure.
|
||||
//
|
||||
// A Vec (or SmallVec) is not a natural choice for a queue. However,
|
||||
@@ -651,12 +686,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
||||
// and almost never more than 3. By using a SmallVec we avoid an
|
||||
// allocation, at the (very small) cost of (occasionally) having to
|
||||
// shift subsequent elements down when removing the front element.
|
||||
let mut queue: SmallVec<[PredicateObligation<'tcx>; 4]> = smallvec![Obligation::new(
|
||||
self.tcx,
|
||||
cause,
|
||||
self.fcx.param_env,
|
||||
ty::TraitRef::new(self.tcx, coerce_unsized_did, [coerce_source, coerce_target])
|
||||
)];
|
||||
let mut queue: SmallVec<[PredicateObligation<'tcx>; 4]> = smallvec![obligation];
|
||||
|
||||
// Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid
|
||||
// emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where
|
||||
@@ -749,7 +779,6 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
||||
// with the unsizing - the lack of a coercion should
|
||||
// be silent, as it causes a type mismatch later.
|
||||
}
|
||||
|
||||
Ok(Some(ImplSource::UserDefined(impl_source))) => {
|
||||
queue.extend(impl_source.nested);
|
||||
// Certain incoherent `CoerceUnsized` implementations may cause ICEs,
|
||||
@@ -767,7 +796,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
Ok(coercion)
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Applies reborrowing for `Pin`
|
||||
@@ -2005,3 +2034,69 @@ impl AsCoercionSite for hir::Arm<'_> {
|
||||
self.body
|
||||
}
|
||||
}
|
||||
|
||||
/// Recursively visit goals to decide whether an unsizing is possible.
|
||||
/// `Break`s when it isn't, and an error should be raised.
|
||||
/// `Continue`s when an unsizing ok based on an implementation of the `Unsize` trait / lang item.
|
||||
struct CoerceVisitor<'a, 'tcx> {
|
||||
fcx: &'a FnCtxt<'a, 'tcx>,
|
||||
span: Span,
|
||||
}
|
||||
|
||||
impl<'tcx> ProofTreeVisitor<'tcx> for CoerceVisitor<'_, 'tcx> {
|
||||
type Result = ControlFlow<()>;
|
||||
|
||||
fn span(&self) -> Span {
|
||||
self.span
|
||||
}
|
||||
|
||||
fn visit_goal(&mut self, goal: &inspect::InspectGoal<'_, 'tcx>) -> Self::Result {
|
||||
let Some(pred) = goal.goal().predicate.as_trait_clause() else {
|
||||
return ControlFlow::Continue(());
|
||||
};
|
||||
|
||||
// Make sure this predicate is referring to either an `Unsize` or `CoerceUnsized` trait,
|
||||
// Otherwise there's nothing to do.
|
||||
if !self.fcx.tcx.is_lang_item(pred.def_id(), LangItem::Unsize)
|
||||
&& !self.fcx.tcx.is_lang_item(pred.def_id(), LangItem::CoerceUnsized)
|
||||
{
|
||||
return ControlFlow::Continue(());
|
||||
}
|
||||
|
||||
match goal.result() {
|
||||
// If we prove the `Unsize` or `CoerceUnsized` goal, continue recursing.
|
||||
Ok(Certainty::Yes) => ControlFlow::Continue(()),
|
||||
Err(NoSolution) => {
|
||||
// Even if we find no solution, continue recursing if we find a single candidate
|
||||
// for which we're shallowly certain it holds to get the right error source.
|
||||
if let [only_candidate] = &goal.candidates()[..]
|
||||
&& only_candidate.shallow_certainty() == Certainty::Yes
|
||||
{
|
||||
only_candidate.visit_nested_no_probe(self)
|
||||
} else {
|
||||
ControlFlow::Break(())
|
||||
}
|
||||
}
|
||||
Ok(Certainty::Maybe { .. }) => {
|
||||
// FIXME: structurally normalize?
|
||||
if self.fcx.tcx.is_lang_item(pred.def_id(), LangItem::Unsize)
|
||||
&& let ty::Dynamic(..) = pred.skip_binder().trait_ref.args.type_at(1).kind()
|
||||
&& let ty::Infer(ty::TyVar(vid)) = *pred.self_ty().skip_binder().kind()
|
||||
&& self.fcx.type_var_is_sized(vid)
|
||||
{
|
||||
// We get here when trying to unsize a type variable to a `dyn Trait`,
|
||||
// knowing that that variable is sized. Unsizing definitely has to happen in that case.
|
||||
// If the variable weren't sized, we may not need an unsizing coercion.
|
||||
// In general, we don't want to add coercions too eagerly since it makes error messages much worse.
|
||||
ControlFlow::Continue(())
|
||||
} else if let Some(cand) = goal.unique_applicable_candidate()
|
||||
&& cand.shallow_certainty() == Certainty::Yes
|
||||
{
|
||||
cand.visit_nested_no_probe(self)
|
||||
} else {
|
||||
ControlFlow::Break(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ use rustc_middle::ty::{self, Ty, TypeVisitableExt};
|
||||
use rustc_span::Span;
|
||||
use rustc_trait_selection::solve::Certainty;
|
||||
use rustc_trait_selection::solve::inspect::{
|
||||
InspectConfig, InspectGoal, ProofTreeInferCtxtExt, ProofTreeVisitor,
|
||||
InferCtxtProofTreeExt, InspectConfig, InspectGoal, ProofTreeVisitor,
|
||||
};
|
||||
use tracing::{debug, instrument, trace};
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ use tracing::instrument;
|
||||
use self::derive_errors::*;
|
||||
use super::Certainty;
|
||||
use super::delegate::SolverDelegate;
|
||||
use super::inspect::{self, ProofTreeInferCtxtExt};
|
||||
use super::inspect::{self, InferCtxtProofTreeExt};
|
||||
use crate::traits::{FulfillmentError, ScrubbedTraitError};
|
||||
|
||||
mod derive_errors;
|
||||
|
||||
@@ -15,7 +15,7 @@ use rustc_next_trait_solver::solve::{GoalEvaluation, SolverDelegateEvalExt as _}
|
||||
use tracing::{instrument, trace};
|
||||
|
||||
use crate::solve::delegate::SolverDelegate;
|
||||
use crate::solve::inspect::{self, ProofTreeInferCtxtExt, ProofTreeVisitor};
|
||||
use crate::solve::inspect::{self, InferCtxtProofTreeExt, ProofTreeVisitor};
|
||||
use crate::solve::{Certainty, deeply_normalize_for_diagnostics};
|
||||
use crate::traits::{FulfillmentError, FulfillmentErrorCode, wf};
|
||||
|
||||
|
||||
@@ -463,7 +463,7 @@ pub trait ProofTreeVisitor<'tcx> {
|
||||
fn visit_goal(&mut self, goal: &InspectGoal<'_, 'tcx>) -> Self::Result;
|
||||
}
|
||||
|
||||
#[extension(pub trait ProofTreeInferCtxtExt<'tcx>)]
|
||||
#[extension(pub trait InferCtxtProofTreeExt<'tcx>)]
|
||||
impl<'tcx> InferCtxt<'tcx> {
|
||||
fn visit_proof_tree<V: ProofTreeVisitor<'tcx>>(
|
||||
&self,
|
||||
|
||||
@@ -12,7 +12,7 @@ use rustc_middle::{bug, span_bug};
|
||||
use rustc_span::Span;
|
||||
use thin_vec::thin_vec;
|
||||
|
||||
use crate::solve::inspect::{self, ProofTreeInferCtxtExt};
|
||||
use crate::solve::inspect::{self, InferCtxtProofTreeExt};
|
||||
|
||||
#[extension(pub trait InferCtxtSelectExt<'tcx>)]
|
||||
impl<'tcx> InferCtxt<'tcx> {
|
||||
|
||||
@@ -29,7 +29,7 @@ use tracing::{debug, instrument, warn};
|
||||
use super::ObligationCtxt;
|
||||
use crate::error_reporting::traits::suggest_new_overflow_limit;
|
||||
use crate::infer::InferOk;
|
||||
use crate::solve::inspect::{InspectGoal, ProofTreeInferCtxtExt, ProofTreeVisitor};
|
||||
use crate::solve::inspect::{InferCtxtProofTreeExt, InspectGoal, ProofTreeVisitor};
|
||||
use crate::solve::{SolverDelegate, deeply_normalize_for_diagnostics, inspect};
|
||||
use crate::traits::query::evaluate_obligation::InferCtxtExt;
|
||||
use crate::traits::select::IntercrateAmbiguityCause;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
error[E0277]: the size for values of type `T` cannot be known at compilation time
|
||||
--> $DIR/dst-object-from-unsized-type.rs:8:23
|
||||
--> $DIR/dst-object-from-unsized-type.rs:11:23
|
||||
|
|
||||
LL | fn test1<T: ?Sized + Foo>(t: &T) {
|
||||
| - this type parameter needs to be `Sized`
|
||||
@@ -14,7 +14,7 @@ LL + fn test1<T: Foo>(t: &T) {
|
||||
|
|
||||
|
||||
error[E0277]: the size for values of type `T` cannot be known at compilation time
|
||||
--> $DIR/dst-object-from-unsized-type.rs:13:23
|
||||
--> $DIR/dst-object-from-unsized-type.rs:17:23
|
||||
|
|
||||
LL | fn test2<T: ?Sized + Foo>(t: &T) {
|
||||
| - this type parameter needs to be `Sized`
|
||||
@@ -29,7 +29,7 @@ LL + fn test2<T: Foo>(t: &T) {
|
||||
|
|
||||
|
||||
error[E0277]: the size for values of type `str` cannot be known at compilation time
|
||||
--> $DIR/dst-object-from-unsized-type.rs:18:28
|
||||
--> $DIR/dst-object-from-unsized-type.rs:23:28
|
||||
|
|
||||
LL | let _: &[&dyn Foo] = &["hi"];
|
||||
| ^^^^ doesn't have a size known at compile-time
|
||||
@@ -38,7 +38,7 @@ LL | let _: &[&dyn Foo] = &["hi"];
|
||||
= note: required for the cast from `&'static str` to `&dyn Foo`
|
||||
|
||||
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
|
||||
--> $DIR/dst-object-from-unsized-type.rs:23:23
|
||||
--> $DIR/dst-object-from-unsized-type.rs:29:23
|
||||
|
|
||||
LL | let _: &dyn Foo = x as &dyn Foo;
|
||||
| ^ doesn't have a size known at compile-time
|
||||
57
tests/ui/dst/dst-object-from-unsized-type.next.stderr
Normal file
57
tests/ui/dst/dst-object-from-unsized-type.next.stderr
Normal file
@@ -0,0 +1,57 @@
|
||||
error[E0277]: the trait bound `&T: CoerceUnsized<&dyn Foo>` is not satisfied in `T`
|
||||
--> $DIR/dst-object-from-unsized-type.rs:11:23
|
||||
|
|
||||
LL | fn test1<T: ?Sized + Foo>(t: &T) {
|
||||
| - this type parameter needs to be `Sized`
|
||||
LL | let u: &dyn Foo = t;
|
||||
| ^ within `T`, the trait `Sized` is not implemented for `T`
|
||||
|
|
||||
= note: required because it appears within the type `T`
|
||||
= note: required for `&T` to implement `CoerceUnsized<&dyn Foo>`
|
||||
= note: required for the cast from `&T` to `&dyn Foo`
|
||||
help: consider removing the `?Sized` bound to make the type parameter `Sized`
|
||||
|
|
||||
LL - fn test1<T: ?Sized + Foo>(t: &T) {
|
||||
LL + fn test1<T: Foo>(t: &T) {
|
||||
|
|
||||
|
||||
error[E0277]: the trait bound `&T: CoerceUnsized<&dyn Foo>` is not satisfied in `T`
|
||||
--> $DIR/dst-object-from-unsized-type.rs:17:23
|
||||
|
|
||||
LL | fn test2<T: ?Sized + Foo>(t: &T) {
|
||||
| - this type parameter needs to be `Sized`
|
||||
LL | let v: &dyn Foo = t as &dyn Foo;
|
||||
| ^ within `T`, the trait `Sized` is not implemented for `T`
|
||||
|
|
||||
= note: required because it appears within the type `T`
|
||||
= note: required for `&T` to implement `CoerceUnsized<&dyn Foo>`
|
||||
= note: required for the cast from `&T` to `&dyn Foo`
|
||||
help: consider removing the `?Sized` bound to make the type parameter `Sized`
|
||||
|
|
||||
LL - fn test2<T: ?Sized + Foo>(t: &T) {
|
||||
LL + fn test2<T: Foo>(t: &T) {
|
||||
|
|
||||
|
||||
error[E0277]: the trait bound `&str: CoerceUnsized<&dyn Foo>` is not satisfied in `str`
|
||||
--> $DIR/dst-object-from-unsized-type.rs:23:28
|
||||
|
|
||||
LL | let _: &[&dyn Foo] = &["hi"];
|
||||
| ^^^^ within `str`, the trait `Sized` is not implemented for `str`
|
||||
|
|
||||
= note: `str` is considered to contain a `[u8]` slice for auto trait purposes
|
||||
= note: required for `&str` to implement `CoerceUnsized<&dyn Foo>`
|
||||
= note: required for the cast from `&'static str` to `&dyn Foo`
|
||||
|
||||
error[E0277]: the trait bound `&[u8]: CoerceUnsized<&dyn Foo>` is not satisfied in `[u8]`
|
||||
--> $DIR/dst-object-from-unsized-type.rs:29:23
|
||||
|
|
||||
LL | let _: &dyn Foo = x as &dyn Foo;
|
||||
| ^ within `[u8]`, the trait `Sized` is not implemented for `[u8]`
|
||||
|
|
||||
= note: required because it appears within the type `[u8]`
|
||||
= note: required for `&[u8]` to implement `CoerceUnsized<&dyn Foo>`
|
||||
= note: required for the cast from `&[u8]` to `&dyn Foo`
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
@@ -1,4 +1,7 @@
|
||||
// Test that we cannot create objects from unsized types.
|
||||
//@ revisions: current next
|
||||
//@ ignore-compare-mode-next-solver (explicit revisions)
|
||||
//@[next] compile-flags: -Znext-solver
|
||||
|
||||
trait Foo { fn foo(&self) {} }
|
||||
impl Foo for str {}
|
||||
@@ -6,22 +9,26 @@ impl Foo for [u8] {}
|
||||
|
||||
fn test1<T: ?Sized + Foo>(t: &T) {
|
||||
let u: &dyn Foo = t;
|
||||
//~^ ERROR the size for values of type
|
||||
//[current]~^ ERROR the size for values of type
|
||||
//[next]~^^ ERROR the trait bound `&T: CoerceUnsized<&dyn Foo>` is not satisfied in `T`
|
||||
}
|
||||
|
||||
fn test2<T: ?Sized + Foo>(t: &T) {
|
||||
let v: &dyn Foo = t as &dyn Foo;
|
||||
//~^ ERROR the size for values of type
|
||||
//[current]~^ ERROR the size for values of type
|
||||
//[next]~^^ ERROR the trait bound `&T: CoerceUnsized<&dyn Foo>` is not satisfied in `T`
|
||||
}
|
||||
|
||||
fn test3() {
|
||||
let _: &[&dyn Foo] = &["hi"];
|
||||
//~^ ERROR the size for values of type
|
||||
//[current]~^ ERROR the size for values of type
|
||||
//[next]~^^ ERROR the trait bound `&str: CoerceUnsized<&dyn Foo>` is not satisfied in `str`
|
||||
}
|
||||
|
||||
fn test4(x: &[u8]) {
|
||||
let _: &dyn Foo = x as &dyn Foo;
|
||||
//~^ ERROR the size for values of type
|
||||
//[current]~^ ERROR the size for values of type
|
||||
//[next]~^^ ERROR the trait bound `&[u8]: CoerceUnsized<&dyn Foo>` is not satisfied in `[u8]`
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
error[E0283]: type annotations needed: cannot satisfy `dyn Trait<&()>: Unsize<dyn Super<&()>>`
|
||||
--> $DIR/unsize-goal-mismatch-2.rs:15:5
|
||||
|
|
||||
LL | x
|
||||
| ^
|
||||
|
|
||||
= note: cannot satisfy `dyn Trait<&()>: Unsize<dyn Super<&()>>`
|
||||
= note: required for `Box<dyn Trait<&()>>` to implement `CoerceUnsized<Box<dyn Super<&()>>>`
|
||||
= note: required for the cast from `Box<(dyn Trait<&'a ()> + 'static)>` to `Box<(dyn Super<&'a ()> + 'static)>`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0283`.
|
||||
19
tests/ui/traits/next-solver/unsize-goal-mismatch-2.rs
Normal file
19
tests/ui/traits/next-solver/unsize-goal-mismatch-2.rs
Normal file
@@ -0,0 +1,19 @@
|
||||
//@ revisions: current next
|
||||
//@ ignore-compare-mode-next-solver (explicit revisions)
|
||||
//@[next] compile-flags: -Znext-solver
|
||||
//@[current] check-pass
|
||||
// Test from trait-system-refactor-initiative#241:
|
||||
// Used to ICE in mir typeck because of ambiguity in the new solver.
|
||||
// The wrong (first) trait bound was selected.
|
||||
// This is fixed with new logic for unsizing coercions
|
||||
// that's independent from that of the old solver, which this test verifies.
|
||||
|
||||
trait Super<T> {}
|
||||
trait Trait<T>: Super<T> + for<'hr> Super<&'hr ()> {}
|
||||
|
||||
fn foo<'a>(x: Box<dyn Trait<&'a ()>>) -> Box<dyn Super<&'a ()>> {
|
||||
x
|
||||
//[next]~^ ERROR type annotations needed: cannot satisfy `dyn Trait<&()>: Unsize<dyn Super<&()>>`
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
@@ -0,0 +1,17 @@
|
||||
error[E0283]: type annotations needed: cannot satisfy `Self: Super<'a>`
|
||||
--> $DIR/unsize-goal-mismatch.rs:11:18
|
||||
|
|
||||
LL | trait Trait<'a>: Super<'a> + for<'hr> Super<'hr> {}
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
note: multiple `impl`s or `where` clauses satisfying `Self: Super<'a>` found
|
||||
--> $DIR/unsize-goal-mismatch.rs:10:1
|
||||
|
|
||||
LL | trait Super<'a> {}
|
||||
| ^^^^^^^^^^^^^^^
|
||||
LL | trait Trait<'a>: Super<'a> + for<'hr> Super<'hr> {}
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0283`.
|
||||
13
tests/ui/traits/next-solver/unsize-goal-mismatch.next.stderr
Normal file
13
tests/ui/traits/next-solver/unsize-goal-mismatch.next.stderr
Normal file
@@ -0,0 +1,13 @@
|
||||
error[E0283]: type annotations needed: cannot satisfy `dyn Trait<'_>: Unsize<dyn Super<'_>>`
|
||||
--> $DIR/unsize-goal-mismatch.rs:15:5
|
||||
|
|
||||
LL | x
|
||||
| ^
|
||||
|
|
||||
= note: cannot satisfy `dyn Trait<'_>: Unsize<dyn Super<'_>>`
|
||||
= note: required for `Box<dyn Trait<'_>>` to implement `CoerceUnsized<Box<dyn Super<'_>>>`
|
||||
= note: required for the cast from `Box<(dyn Trait<'a> + 'static)>` to `Box<(dyn Super<'a> + 'static)>`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0283`.
|
||||
19
tests/ui/traits/next-solver/unsize-goal-mismatch.rs
Normal file
19
tests/ui/traits/next-solver/unsize-goal-mismatch.rs
Normal file
@@ -0,0 +1,19 @@
|
||||
//@ revisions: current next
|
||||
//@ ignore-compare-mode-next-solver (explicit revisions)
|
||||
//@[next] compile-flags: -Znext-solver
|
||||
// Test from trait-system-refactor-initiative#241:
|
||||
// Used to ICE in mir typeck because of ambiguity in the new solver.
|
||||
// The wrong (first) trait bound was selected.
|
||||
// This is fixed with new logic for unsizing coercions
|
||||
// that's independent from that of the old solver, which this test verifies.
|
||||
|
||||
trait Super<'a> {}
|
||||
trait Trait<'a>: Super<'a> + for<'hr> Super<'hr> {}
|
||||
//[current]~^ ERROR type annotations needed: cannot satisfy `Self: Super<'a>`
|
||||
|
||||
fn foo<'a>(x: Box<dyn Trait<'a>>) -> Box<dyn Super<'a>> {
|
||||
x
|
||||
//[next]~^ ERROR type annotations needed: cannot satisfy `dyn Trait<'_>: Unsize<dyn Super<'_>>
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
7
tests/ui/traits/next-solver/unsize-overflow.rs
Normal file
7
tests/ui/traits/next-solver/unsize-overflow.rs
Normal file
@@ -0,0 +1,7 @@
|
||||
//@ compile-flags: -Znext-solver
|
||||
#![recursion_limit = "8"]
|
||||
|
||||
fn main() {
|
||||
let _: Box<dyn Send> = Box::new(&&&&&&&1);
|
||||
//~^ ERROR overflow evaluating the requirement `Box<&&&&&&&i32>: CoerceUnsized<Box<dyn Send>>
|
||||
}
|
||||
12
tests/ui/traits/next-solver/unsize-overflow.stderr
Normal file
12
tests/ui/traits/next-solver/unsize-overflow.stderr
Normal file
@@ -0,0 +1,12 @@
|
||||
error[E0275]: overflow evaluating the requirement `Box<&&&&&&&i32>: CoerceUnsized<Box<dyn Send>>`
|
||||
--> $DIR/unsize-overflow.rs:5:28
|
||||
|
|
||||
LL | let _: Box<dyn Send> = Box::new(&&&&&&&1);
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "16"]` attribute to your crate (`unsize_overflow`)
|
||||
= note: required for the cast from `Box<&&&&&&&i32>` to `Box<dyn Send>`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0275`.
|
||||
@@ -1,14 +1,13 @@
|
||||
error[E0308]: mismatched types
|
||||
error[E0277]: the trait bound `&dyn for<'a> Subtrait<'a, 'a>: CoerceUnsized<&dyn for<'a, 'b> Supertrait<'a, 'b>>` is not satisfied
|
||||
--> $DIR/higher-ranked-upcasting-ub.rs:22:5
|
||||
|
|
||||
LL | fn unsound(x: &dyn for<'a> Subtrait<'a, 'a>) -> &dyn for<'a, 'b> Supertrait<'a, 'b> {
|
||||
| ----------------------------------- expected `&dyn for<'a, 'b> Supertrait<'a, 'b>` because of return type
|
||||
LL | x
|
||||
| ^ expected trait `Supertrait`, found trait `Subtrait`
|
||||
| ^ the trait `Unsize<dyn for<'a, 'b> Supertrait<'a, 'b>>` is not implemented for `dyn for<'a> Subtrait<'a, 'a>`
|
||||
|
|
||||
= note: expected reference `&dyn for<'a, 'b> Supertrait<'a, 'b>`
|
||||
found reference `&dyn for<'a> Subtrait<'a, 'a>`
|
||||
= note: all implementations of `Unsize` are provided automatically by the compiler, see <https://doc.rust-lang.org/stable/std/marker/trait.Unsize.html> for more information
|
||||
= note: required for `&dyn for<'a> Subtrait<'a, 'a>` to implement `CoerceUnsized<&dyn for<'a, 'b> Supertrait<'a, 'b>>`
|
||||
= note: required for the cast from `&dyn for<'a> Subtrait<'a, 'a>` to `&dyn for<'a, 'b> Supertrait<'a, 'b>`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
|
||||
@@ -19,8 +19,10 @@ impl<'a> Supertrait<'a, 'a> for () {
|
||||
}
|
||||
impl<'a> Subtrait<'a, 'a> for () {}
|
||||
fn unsound(x: &dyn for<'a> Subtrait<'a, 'a>) -> &dyn for<'a, 'b> Supertrait<'a, 'b> {
|
||||
x //~ ERROR mismatched types
|
||||
x
|
||||
//[current]~^ ERROR mismatched types
|
||||
//[current]~| ERROR mismatched types
|
||||
//[next]~^^^ ERROR the trait bound `&dyn for<'a> Subtrait<'a, 'a>: CoerceUnsized<&dyn for<'a, 'b> Supertrait<'a, 'b>>` is not satisfied
|
||||
}
|
||||
|
||||
fn transmute<'a, 'b>(x: &'a str) -> &'b str {
|
||||
|
||||
Reference in New Issue
Block a user