Auto merge of #139000 - compiler-errors:rigid-missing-item, r=lcnr

Rigidly project missing item due to guaranteed impossible sized predicate

This is a somewhat involved change, but it amounts to treating missing impl items due to guaranteed impossible where clauses (dyn/str/slice sized, cc #135480) as *rigid projections* rather than projecting to an error term, since that was preventing either reporting a proper error (in an empty param env) *or* successfully type checking the code (in the presence of trivially false where clauses).

Fixes https://github.com/rust-lang/rust/issues/138970

r? `@lcnr` `@oli-obk`
This commit is contained in:
bors 2025-04-10 04:03:59 +00:00
commit 9d28fe3976
19 changed files with 524 additions and 91 deletions

View File

@ -937,31 +937,7 @@ fn check_impl_items_against_trait<'tcx>(
let trait_def = tcx.trait_def(trait_ref.def_id);
let infcx = tcx.infer_ctxt().ignoring_regions().build(TypingMode::non_body_analysis());
let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
let cause = ObligationCause::misc(tcx.def_span(impl_id), impl_id);
let param_env = tcx.param_env(impl_id);
let self_is_guaranteed_unsized = match tcx
.struct_tail_raw(
trait_ref.self_ty(),
|ty| {
ocx.structurally_normalize_ty(&cause, param_env, ty).unwrap_or_else(|_| {
Ty::new_error_with_message(
tcx,
tcx.def_span(impl_id),
"struct tail should be computable",
)
})
},
|| (),
)
.kind()
{
ty::Dynamic(_, _, ty::DynKind::Dyn) | ty::Slice(_) | ty::Str => true,
_ => false,
};
let self_is_guaranteed_unsize_self = tcx.impl_self_is_guaranteed_unsized(impl_id);
for &impl_item in impl_item_refs {
let ty_impl_item = tcx.associated_item(impl_item);
@ -992,7 +968,7 @@ fn check_impl_items_against_trait<'tcx>(
}
}
if self_is_guaranteed_unsized && tcx.generics_require_sized_self(ty_trait_item.def_id) {
if self_is_guaranteed_unsize_self && tcx.generics_require_sized_self(ty_trait_item.def_id) {
tcx.emit_node_span_lint(
rustc_lint_defs::builtin::DEAD_CODE,
tcx.local_def_id_to_hir_id(ty_impl_item.def_id.expect_local()),
@ -1027,7 +1003,7 @@ fn check_impl_items_against_trait<'tcx>(
if !is_implemented
&& tcx.defaultness(impl_id).is_final()
// unsized types don't need to implement methods that have `Self: Sized` bounds.
&& !(self_is_guaranteed_unsized && tcx.generics_require_sized_self(trait_item_id))
&& !(self_is_guaranteed_unsize_self && tcx.generics_require_sized_self(trait_item_id))
{
missing_items.push(tcx.associated_item(trait_item_id));
}

View File

@ -1026,6 +1026,13 @@ rustc_queries! {
separate_provide_extern
}
/// Given an `impl_def_id`, return true if the self type is guaranteed to be unsized due
/// to either being one of the built-in unsized types (str/slice/dyn) or to be a struct
/// whose tail is one of those types.
query impl_self_is_guaranteed_unsized(impl_def_id: DefId) -> bool {
desc { |tcx| "computing whether `{}` has a guaranteed unsized self type", tcx.def_path_str(impl_def_id) }
}
/// Maps a `DefId` of a type to a list of its inherent impls.
/// Contains implementations of methods that are inherent to a type.
/// Methods in these implementations don't need to be exported.

View File

@ -437,6 +437,10 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
)
}
fn impl_self_is_guaranteed_unsized(self, impl_def_id: DefId) -> bool {
self.impl_self_is_guaranteed_unsized(impl_def_id)
}
fn has_target_features(self, def_id: DefId) -> bool {
!self.codegen_fn_attrs(def_id).target_features.is_empty()
}

View File

@ -134,7 +134,7 @@ where
// Add GAT where clauses from the trait's definition
// FIXME: We don't need these, since these are the type's own WF obligations.
ecx.add_goals(
GoalSource::Misc,
GoalSource::AliasWellFormed,
cx.own_predicates_of(goal.predicate.def_id())
.iter_instantiated(cx, goal.predicate.alias.args)
.map(|pred| goal.with(cx, pred)),
@ -199,7 +199,7 @@ where
// Add GAT where clauses from the trait's definition.
// FIXME: We don't need these, since these are the type's own WF obligations.
ecx.add_goals(
GoalSource::Misc,
GoalSource::AliasWellFormed,
cx.own_predicates_of(goal.predicate.def_id())
.iter_instantiated(cx, goal.predicate.alias.args)
.map(|pred| goal.with(cx, pred)),
@ -232,7 +232,33 @@ where
};
if !cx.has_item_definition(target_item_def_id) {
return error_response(ecx, cx.delay_bug("missing item"));
// If the impl is missing an item, it's either because the user forgot to
// provide it, or the user is not *obligated* to provide it (because it
// has a trivially false `Sized` predicate). If it's the latter, we cannot
// delay a bug because we can have trivially false where clauses, so we
// treat it as rigid.
if cx.impl_self_is_guaranteed_unsized(impl_def_id) {
match ecx.typing_mode() {
ty::TypingMode::Coherence => {
return ecx.evaluate_added_goals_and_make_canonical_response(
Certainty::AMBIGUOUS,
);
}
ty::TypingMode::Analysis { .. }
| ty::TypingMode::Borrowck { .. }
| ty::TypingMode::PostBorrowckAnalysis { .. }
| ty::TypingMode::PostAnalysis => {
ecx.structurally_instantiate_normalizes_to_term(
goal,
goal.predicate.alias,
);
return ecx
.evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
}
}
} else {
return error_response(ecx, cx.delay_bug("missing item"));
}
}
let target_container_def_id = cx.parent(target_item_def_id);

View File

@ -669,30 +669,11 @@ fn project<'cx, 'tcx>(
match candidates {
ProjectionCandidateSet::Single(candidate) => {
Ok(Projected::Progress(confirm_candidate(selcx, obligation, candidate)))
confirm_candidate(selcx, obligation, candidate)
}
ProjectionCandidateSet::None => {
let tcx = selcx.tcx();
let term = match tcx.def_kind(obligation.predicate.def_id) {
DefKind::AssocTy => Ty::new_projection_from_args(
tcx,
obligation.predicate.def_id,
obligation.predicate.args,
)
.into(),
DefKind::AssocConst => ty::Const::new_unevaluated(
tcx,
ty::UnevaluatedConst::new(
obligation.predicate.def_id,
obligation.predicate.args,
),
)
.into(),
kind => {
bug!("unknown projection def-id: {}", kind.descr(obligation.predicate.def_id))
}
};
let term = obligation.predicate.to_term(tcx);
Ok(Projected::NoProgress(term))
}
// Error occurred while trying to processing impls.
@ -1244,18 +1225,16 @@ fn confirm_candidate<'cx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'tcx>,
obligation: &ProjectionTermObligation<'tcx>,
candidate: ProjectionCandidate<'tcx>,
) -> Progress<'tcx> {
) -> Result<Projected<'tcx>, ProjectionError<'tcx>> {
debug!(?obligation, ?candidate, "confirm_candidate");
let mut progress = match candidate {
let mut result = match candidate {
ProjectionCandidate::ParamEnv(poly_projection)
| ProjectionCandidate::Object(poly_projection) => {
confirm_param_env_candidate(selcx, obligation, poly_projection, false)
}
ProjectionCandidate::TraitDef(poly_projection) => {
confirm_param_env_candidate(selcx, obligation, poly_projection, true)
}
| ProjectionCandidate::Object(poly_projection) => Ok(Projected::Progress(
confirm_param_env_candidate(selcx, obligation, poly_projection, false),
)),
ProjectionCandidate::TraitDef(poly_projection) => Ok(Projected::Progress(
confirm_param_env_candidate(selcx, obligation, poly_projection, true),
)),
ProjectionCandidate::Select(impl_source) => {
confirm_select_candidate(selcx, obligation, impl_source)
}
@ -1266,23 +1245,26 @@ fn confirm_candidate<'cx, 'tcx>(
// with new region variables, we need to resolve them to existing variables
// when possible for this to work. See `auto-trait-projection-recursion.rs`
// for a case where this matters.
if progress.term.has_infer_regions() {
if let Ok(Projected::Progress(progress)) = &mut result
&& progress.term.has_infer_regions()
{
progress.term = progress.term.fold_with(&mut OpportunisticRegionResolver::new(selcx.infcx));
}
progress
result
}
fn confirm_select_candidate<'cx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'tcx>,
obligation: &ProjectionTermObligation<'tcx>,
impl_source: Selection<'tcx>,
) -> Progress<'tcx> {
) -> Result<Projected<'tcx>, ProjectionError<'tcx>> {
match impl_source {
ImplSource::UserDefined(data) => confirm_impl_candidate(selcx, obligation, data),
ImplSource::Builtin(BuiltinImplSource::Misc | BuiltinImplSource::Trivial, data) => {
let tcx = selcx.tcx();
let trait_def_id = obligation.predicate.trait_def_id(tcx);
if tcx.is_lang_item(trait_def_id, LangItem::Coroutine) {
let progress = if tcx.is_lang_item(trait_def_id, LangItem::Coroutine) {
confirm_coroutine_candidate(selcx, obligation, data)
} else if tcx.is_lang_item(trait_def_id, LangItem::Future) {
confirm_future_candidate(selcx, obligation, data)
@ -1304,7 +1286,8 @@ fn confirm_select_candidate<'cx, 'tcx>(
confirm_async_fn_kind_helper_candidate(selcx, obligation, data)
} else {
confirm_builtin_candidate(selcx, obligation, data)
}
};
Ok(Projected::Progress(progress))
}
ImplSource::Builtin(BuiltinImplSource::Object { .. }, _)
| ImplSource::Param(..)
@ -2000,7 +1983,7 @@ fn confirm_impl_candidate<'cx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'tcx>,
obligation: &ProjectionTermObligation<'tcx>,
impl_impl_source: ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>>,
) -> Progress<'tcx> {
) -> Result<Projected<'tcx>, ProjectionError<'tcx>> {
let tcx = selcx.tcx();
let ImplSourceUserDefinedData { impl_def_id, args, mut nested } = impl_impl_source;
@ -2011,19 +1994,33 @@ fn confirm_impl_candidate<'cx, 'tcx>(
let param_env = obligation.param_env;
let assoc_ty = match specialization_graph::assoc_def(tcx, impl_def_id, assoc_item_id) {
Ok(assoc_ty) => assoc_ty,
Err(guar) => return Progress::error(tcx, guar),
Err(guar) => return Ok(Projected::Progress(Progress::error(tcx, guar))),
};
// This means that the impl is missing a definition for the
// associated type. This is either because the associate item
// has impossible-to-satisfy predicates (since those were
// allowed in <https://github.com/rust-lang/rust/pull/135480>),
// or because the impl is literally missing the definition.
if !assoc_ty.item.defaultness(tcx).has_value() {
// This means that the impl is missing a definition for the
// associated type. This error will be reported by the type
// checker method `check_impl_items_against_trait`, so here we
// just return Error.
debug!(
"confirm_impl_candidate: no associated type {:?} for {:?}",
assoc_ty.item.name, obligation.predicate
);
return Progress { term: Ty::new_misc_error(tcx).into(), obligations: nested };
if tcx.impl_self_is_guaranteed_unsized(impl_def_id) {
// We treat this projection as rigid here, which is represented via
// `Projected::NoProgress`. This will ensure that the projection is
// checked for well-formedness, and it's either satisfied by a trivial
// where clause in its env or it results in an error.
return Ok(Projected::NoProgress(obligation.predicate.to_term(tcx)));
} else {
return Ok(Projected::Progress(Progress {
term: Ty::new_misc_error(tcx).into(),
obligations: nested,
}));
}
}
// If we're trying to normalize `<Vec<u32> as X>::A<S>` using
//`impl<T> X for Vec<T> { type A<Y> = Box<Y>; }`, then:
//
@ -2033,6 +2030,7 @@ fn confirm_impl_candidate<'cx, 'tcx>(
let args = obligation.predicate.args.rebase_onto(tcx, trait_def_id, args);
let args = translate_args(selcx.infcx, param_env, impl_def_id, args, assoc_ty.defining_node);
let is_const = matches!(tcx.def_kind(assoc_ty.item.def_id), DefKind::AssocConst);
let term: ty::EarlyBinder<'tcx, ty::Term<'tcx>> = if is_const {
let did = assoc_ty.item.def_id;
let identity_args = crate::traits::GenericArgs::identity_for_item(tcx, did);
@ -2041,7 +2039,8 @@ fn confirm_impl_candidate<'cx, 'tcx>(
} else {
tcx.type_of(assoc_ty.item.def_id).map_bound(|ty| ty.into())
};
if !tcx.check_args_compatible(assoc_ty.item.def_id, args) {
let progress = if !tcx.check_args_compatible(assoc_ty.item.def_id, args) {
let err = Ty::new_error_with_message(
tcx,
obligation.cause.span,
@ -2051,7 +2050,8 @@ fn confirm_impl_candidate<'cx, 'tcx>(
} else {
assoc_ty_own_obligations(selcx, obligation, &mut nested);
Progress { term: term.instantiate(tcx, args), obligations: nested }
}
};
Ok(Projected::Progress(progress))
}
// Get obligations corresponding to the predicates from the where-clause of the

View File

@ -3,6 +3,7 @@ use rustc_hir as hir;
use rustc_hir::LangItem;
use rustc_hir::def::DefKind;
use rustc_index::bit_set::DenseBitSet;
use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::bug;
use rustc_middle::query::Providers;
use rustc_middle::ty::{
@ -312,6 +313,61 @@ fn unsizing_params_for_adt<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> DenseBitSe
unsizing_params
}
fn impl_self_is_guaranteed_unsized<'tcx>(tcx: TyCtxt<'tcx>, impl_def_id: DefId) -> bool {
debug_assert_eq!(tcx.def_kind(impl_def_id), DefKind::Impl { of_trait: true });
let infcx = tcx.infer_ctxt().ignoring_regions().build(ty::TypingMode::non_body_analysis());
let ocx = traits::ObligationCtxt::new_with_diagnostics(&infcx);
let cause = traits::ObligationCause::dummy();
let param_env = tcx.param_env(impl_def_id);
let tail = tcx.struct_tail_raw(
tcx.type_of(impl_def_id).instantiate_identity(),
|ty| {
ocx.structurally_normalize_ty(&cause, param_env, ty).unwrap_or_else(|_| {
Ty::new_error_with_message(
tcx,
tcx.def_span(impl_def_id),
"struct tail should be computable",
)
})
},
|| (),
);
match tail.kind() {
ty::Dynamic(_, _, ty::Dyn) | ty::Slice(_) | ty::Str => true,
ty::Bool
| ty::Char
| ty::Int(_)
| ty::Uint(_)
| ty::Float(_)
| ty::Adt(_, _)
| ty::Foreign(_)
| ty::Array(_, _)
| ty::Pat(_, _)
| ty::RawPtr(_, _)
| ty::Ref(_, _, _)
| ty::FnDef(_, _)
| ty::FnPtr(_, _)
| ty::UnsafeBinder(_)
| ty::Closure(_, _)
| ty::CoroutineClosure(_, _)
| ty::Coroutine(_, _)
| ty::CoroutineWitness(_, _)
| ty::Never
| ty::Tuple(_)
| ty::Alias(_, _)
| ty::Param(_)
| ty::Bound(_, _)
| ty::Placeholder(_)
| ty::Infer(_)
| ty::Error(_)
| ty::Dynamic(_, _, ty::DynStar) => false,
}
}
pub(crate) fn provide(providers: &mut Providers) {
*providers = Providers {
asyncness,
@ -320,6 +376,7 @@ pub(crate) fn provide(providers: &mut Providers) {
param_env_normalized_for_post_analysis,
defaultness,
unsizing_params_for_adt,
impl_self_is_guaranteed_unsized,
..*providers
};
}

View File

@ -155,6 +155,39 @@ pub trait Ty<I: Interner<Ty = Self>>:
fn is_known_rigid(self) -> bool {
self.kind().is_known_rigid()
}
fn is_guaranteed_unsized_raw(self) -> bool {
match self.kind() {
ty::Dynamic(_, _, ty::Dyn) | ty::Slice(_) | ty::Str => true,
ty::Bool
| ty::Char
| ty::Int(_)
| ty::Uint(_)
| ty::Float(_)
| ty::Adt(_, _)
| ty::Foreign(_)
| ty::Array(_, _)
| ty::Pat(_, _)
| ty::RawPtr(_, _)
| ty::Ref(_, _, _)
| ty::FnDef(_, _)
| ty::FnPtr(_, _)
| ty::UnsafeBinder(_)
| ty::Closure(_, _)
| ty::CoroutineClosure(_, _)
| ty::Coroutine(_, _)
| ty::CoroutineWitness(_, _)
| ty::Never
| ty::Tuple(_)
| ty::Alias(_, _)
| ty::Param(_)
| ty::Bound(_, _)
| ty::Placeholder(_)
| ty::Infer(_)
| ty::Error(_)
| ty::Dynamic(_, _, ty::DynStar) => false,
}
}
}
pub trait Tys<I: Interner<Tys = Self>>:

View File

@ -255,6 +255,8 @@ pub trait Interner:
def_id: Self::DefId,
) -> ty::EarlyBinder<Self, impl IntoIterator<Item = ty::Binder<Self, ty::TraitRef<Self>>>>;
fn impl_self_is_guaranteed_unsized(self, def_id: Self::DefId) -> bool;
fn has_target_features(self, def_id: Self::DefId) -> bool;
fn require_lang_item(self, lang_item: TraitSolverLangItem) -> Self::DefId;

View File

@ -83,8 +83,11 @@ pub enum GoalSource {
/// Instantiating a higher-ranked goal and re-proving it.
InstantiateHigherRanked,
/// Predicate required for an alias projection to be well-formed.
/// This is used in two places: projecting to an opaque whose hidden type
/// is already registered in the opaque type storage, and for rigid projections.
/// This is used in three places:
/// 1. projecting to an opaque whose hidden type is already registered in
/// the opaque type storage,
/// 2. for rigid projections's trait goal,
/// 3. for GAT where clauses.
AliasWellFormed,
/// In case normalizing aliases in nested goals cycles, eagerly normalizing these
/// aliases in the context of the parent may incorrectly change the cycle kind.

View File

@ -2,7 +2,7 @@ trait Filter {
type ToMatch;
}
impl<T> Filter for T //~ ERROR overflow evaluating the requirement
impl<T> Filter for T //~ ERROR cycle detected when
where
T: Fn(Self::ToMatch),
{

View File

@ -1,4 +1,4 @@
error[E0275]: overflow evaluating the requirement `<T as Filter>::ToMatch == <T as Filter>::ToMatch`
error[E0391]: cycle detected when computing normalized predicates of `<impl at $DIR/impl-wf-cycle-4.rs:5:1: 7:26>`
--> $DIR/impl-wf-cycle-4.rs:5:1
|
LL | / impl<T> Filter for T
@ -6,20 +6,23 @@ LL | | where
LL | | T: Fn(Self::ToMatch),
| |_________________________^
|
note: required for `T` to implement `Filter`
--> $DIR/impl-wf-cycle-4.rs:5:9
note: ...which requires computing whether `<impl at $DIR/impl-wf-cycle-4.rs:5:1: 7:26>` has a guaranteed unsized self type...
--> $DIR/impl-wf-cycle-4.rs:5:1
|
LL | impl<T> Filter for T
| ^^^^^^ ^
LL | where
LL | T: Fn(Self::ToMatch),
| ----------------- unsatisfied trait bound introduced here
note: associated types for the current `impl` cannot be restricted in `where` clauses
--> $DIR/impl-wf-cycle-4.rs:7:11
LL | / impl<T> Filter for T
LL | | where
LL | | T: Fn(Self::ToMatch),
| |_________________________^
= note: ...which again requires computing normalized predicates of `<impl at $DIR/impl-wf-cycle-4.rs:5:1: 7:26>`, completing the cycle
note: cycle used when checking that `<impl at $DIR/impl-wf-cycle-4.rs:5:1: 7:26>` is well-formed
--> $DIR/impl-wf-cycle-4.rs:5:1
|
LL | T: Fn(Self::ToMatch),
| ^^^^^^^^^^^^^
LL | / impl<T> Filter for T
LL | | where
LL | | T: Fn(Self::ToMatch),
| |_________________________^
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0275`.
For more information about this error, try `rustc --explain E0391`.

View File

@ -0,0 +1,54 @@
error[E0277]: the size for values of type `[()]` cannot be known at compilation time
--> $DIR/trivial-unsized-projection-2.rs:22:12
|
LL | const FOO: <Tail as Bad>::Assert = todo!();
| ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: within `Tail`, the trait `Sized` is not implemented for `[()]`
note: required because it appears within the type `Tail`
--> $DIR/trivial-unsized-projection-2.rs:17:8
|
LL | struct Tail([()]);
| ^^^^
note: required by a bound in `Bad::Assert`
--> $DIR/trivial-unsized-projection-2.rs:14:15
|
LL | type Assert
| ------ required by a bound in this associated type
LL | where
LL | Self: Sized;
| ^^^^^ required by this bound in `Bad::Assert`
help: consider relaxing the implicit `Sized` restriction
|
LL | type Assert: ?Sized
| ++++++++
error[E0277]: the size for values of type `[()]` cannot be known at compilation time
--> $DIR/trivial-unsized-projection-2.rs:22:12
|
LL | const FOO: <Tail as Bad>::Assert = todo!();
| ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: within `Tail`, the trait `Sized` is not implemented for `[()]`
note: required because it appears within the type `Tail`
--> $DIR/trivial-unsized-projection-2.rs:17:8
|
LL | struct Tail([()]);
| ^^^^
note: required by a bound in `Bad::Assert`
--> $DIR/trivial-unsized-projection-2.rs:14:15
|
LL | type Assert
| ------ required by a bound in this associated type
LL | where
LL | Self: Sized;
| ^^^^^ required by this bound in `Bad::Assert`
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
help: consider relaxing the implicit `Sized` restriction
|
LL | type Assert: ?Sized
| ++++++++
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0277`.

View File

@ -0,0 +1,54 @@
error[E0277]: the size for values of type `[()]` cannot be known at compilation time
--> $DIR/trivial-unsized-projection-2.rs:22:12
|
LL | const FOO: <Tail as Bad>::Assert = todo!();
| ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: within `Tail`, the trait `Sized` is not implemented for `[()]`
note: required because it appears within the type `Tail`
--> $DIR/trivial-unsized-projection-2.rs:17:8
|
LL | struct Tail([()]);
| ^^^^
note: required by a bound in `Bad::Assert`
--> $DIR/trivial-unsized-projection-2.rs:14:15
|
LL | type Assert
| ------ required by a bound in this associated type
LL | where
LL | Self: Sized;
| ^^^^^ required by this bound in `Bad::Assert`
help: consider relaxing the implicit `Sized` restriction
|
LL | type Assert: ?Sized
| ++++++++
error[E0277]: the size for values of type `[()]` cannot be known at compilation time
--> $DIR/trivial-unsized-projection-2.rs:22:12
|
LL | const FOO: <Tail as Bad>::Assert = todo!();
| ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: within `Tail`, the trait `Sized` is not implemented for `[()]`
note: required because it appears within the type `Tail`
--> $DIR/trivial-unsized-projection-2.rs:17:8
|
LL | struct Tail([()]);
| ^^^^
note: required by a bound in `Bad::Assert`
--> $DIR/trivial-unsized-projection-2.rs:14:15
|
LL | type Assert
| ------ required by a bound in this associated type
LL | where
LL | Self: Sized;
| ^^^^^ required by this bound in `Bad::Assert`
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
help: consider relaxing the implicit `Sized` restriction
|
LL | type Assert: ?Sized
| ++++++++
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0277`.

View File

@ -0,0 +1,34 @@
//@ revisions: good bad good_new bad_new
//@[good_new] compile-flags: -Znext-solver
//@[bad_new] compile-flags: -Znext-solver
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[good] check-pass
//@[good_new] check-pass
#![feature(trivial_bounds)]
#![allow(trivial_bounds)]
trait Bad {
type Assert
where
Self: Sized;
}
struct Tail([()]);
impl Bad for Tail {}
#[cfg(any(bad, bad_new))]
const FOO: <Tail as Bad>::Assert = todo!();
//[bad]~^ ERROR the size for values of type `[()]` cannot be known at compilation time
//[bad]~| ERROR the size for values of type `[()]` cannot be known at compilation time
//[bad_new]~^^^ ERROR the size for values of type `[()]` cannot be known at compilation time
//[bad_new]~| ERROR the size for values of type `[()]` cannot be known at compilation time
#[cfg(any(good, good_new))]
// Well-formed in trivially false param-env
fn foo() where Tail: Sized {
let _: <Tail as Bad>::Assert;
}
fn main() {}

View File

@ -0,0 +1,45 @@
// Make sure we don't treat missing associated items as rigid
// during coherence, even if we know they've got an impossible
// `Sized`-bound. As we check whether the self type is definitely
// not `Sized` outside of coherence, this check can be incomplete.
//
// In this test we only use `impl<T> Overlap<u32> for T` to normalize
// the field of `MaybeUnsized<T, u32>` when checking whether it's
// definitely not `Sized`. However, for `MaybeUnsized<u32, u32>` we
// could also use `impl<U> Overlap<U> for u32` for normalization, which
// would result in a `Sized` type. cc #139000
struct MaybeUnsized<T: Overlap<U>, U>(<T as Overlap<U>>::MaybeUnsized);
trait ReqSized {
type Missing1
where
Self: Sized;
type Missing2
where
Self: Sized;
}
impl<T> ReqSized for MaybeUnsized<T, u32> {}
struct W<T: ?Sized>(T);
trait Eq<T> {}
impl<T> Eq<T> for W<T> {}
trait RelateReqSized {}
impl<T: ReqSized> RelateReqSized for T where W<T::Missing1>: Eq<T::Missing2> {}
trait Overlap<U> {
type MaybeUnsized: ?Sized;
}
impl<T> Overlap<u32> for T {
type MaybeUnsized = str;
}
impl<U> Overlap<U> for u32
//~^ ERROR conflicting implementations of trait `Overlap<u32>` for type `u32`
where
MaybeUnsized<U, u32>: RelateReqSized,
{
type MaybeUnsized = u32;
}
fn main() {}

View File

@ -0,0 +1,15 @@
error[E0119]: conflicting implementations of trait `Overlap<u32>` for type `u32`
--> $DIR/trivial-unsized-projection-in-coherence.rs:37:1
|
LL | impl<T> Overlap<u32> for T {
| -------------------------- first implementation here
...
LL | / impl<U> Overlap<U> for u32
LL | |
LL | | where
LL | | MaybeUnsized<U, u32>: RelateReqSized,
| |_________________________________________^ conflicting implementation for `u32`
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0119`.

View File

@ -0,0 +1,44 @@
error[E0277]: the size for values of type `[()]` cannot be known at compilation time
--> $DIR/trivial-unsized-projection.rs:20:12
|
LL | const FOO: <[()] as Bad>::Assert = todo!();
| ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `[()]`
note: required by a bound in `Bad::Assert`
--> $DIR/trivial-unsized-projection.rs:14:15
|
LL | type Assert
| ------ required by a bound in this associated type
LL | where
LL | Self: Sized;
| ^^^^^ required by this bound in `Bad::Assert`
help: consider relaxing the implicit `Sized` restriction
|
LL | type Assert: ?Sized
| ++++++++
error[E0277]: the size for values of type `[()]` cannot be known at compilation time
--> $DIR/trivial-unsized-projection.rs:20:12
|
LL | const FOO: <[()] as Bad>::Assert = todo!();
| ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `[()]`
note: required by a bound in `Bad::Assert`
--> $DIR/trivial-unsized-projection.rs:14:15
|
LL | type Assert
| ------ required by a bound in this associated type
LL | where
LL | Self: Sized;
| ^^^^^ required by this bound in `Bad::Assert`
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
help: consider relaxing the implicit `Sized` restriction
|
LL | type Assert: ?Sized
| ++++++++
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0277`.

View File

@ -0,0 +1,44 @@
error[E0277]: the size for values of type `[()]` cannot be known at compilation time
--> $DIR/trivial-unsized-projection.rs:20:12
|
LL | const FOO: <[()] as Bad>::Assert = todo!();
| ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `[()]`
note: required by a bound in `Bad::Assert`
--> $DIR/trivial-unsized-projection.rs:14:15
|
LL | type Assert
| ------ required by a bound in this associated type
LL | where
LL | Self: Sized;
| ^^^^^ required by this bound in `Bad::Assert`
help: consider relaxing the implicit `Sized` restriction
|
LL | type Assert: ?Sized
| ++++++++
error[E0277]: the size for values of type `[()]` cannot be known at compilation time
--> $DIR/trivial-unsized-projection.rs:20:12
|
LL | const FOO: <[()] as Bad>::Assert = todo!();
| ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `Sized` is not implemented for `[()]`
note: required by a bound in `Bad::Assert`
--> $DIR/trivial-unsized-projection.rs:14:15
|
LL | type Assert
| ------ required by a bound in this associated type
LL | where
LL | Self: Sized;
| ^^^^^ required by this bound in `Bad::Assert`
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
help: consider relaxing the implicit `Sized` restriction
|
LL | type Assert: ?Sized
| ++++++++
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0277`.

View File

@ -0,0 +1,32 @@
//@ revisions: good bad good_new bad_new
//@[good_new] compile-flags: -Znext-solver
//@[bad_new] compile-flags: -Znext-solver
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[good] check-pass
//@[good_new] check-pass
#![feature(trivial_bounds)]
#![allow(trivial_bounds)]
trait Bad {
type Assert
where
Self: Sized;
}
impl Bad for [()] {}
#[cfg(any(bad, bad_new))]
const FOO: <[()] as Bad>::Assert = todo!();
//[bad]~^ ERROR the size for values of type `[()]` cannot be known at compilation time
//[bad]~| ERROR the size for values of type `[()]` cannot be known at compilation time
//[bad_new]~^^^ ERROR the size for values of type `[()]` cannot be known at compilation time
//[bad_new]~| ERROR the size for values of type `[()]` cannot be known at compilation time
#[cfg(any(good, good_new))]
// Well-formed in trivially false param-env
fn foo() where [()]: Sized {
let _: <[()] as Bad>::Assert;
}
fn main() {}