mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-15 05:26:47 +00:00
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:
commit
9d28fe3976
@ -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));
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
};
|
||||
}
|
||||
|
@ -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>>:
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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),
|
||||
{
|
||||
|
@ -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`.
|
||||
|
54
tests/ui/traits/trivial-unsized-projection-2.bad.stderr
Normal file
54
tests/ui/traits/trivial-unsized-projection-2.bad.stderr
Normal 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`.
|
54
tests/ui/traits/trivial-unsized-projection-2.bad_new.stderr
Normal file
54
tests/ui/traits/trivial-unsized-projection-2.bad_new.stderr
Normal 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`.
|
34
tests/ui/traits/trivial-unsized-projection-2.rs
Normal file
34
tests/ui/traits/trivial-unsized-projection-2.rs
Normal 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() {}
|
45
tests/ui/traits/trivial-unsized-projection-in-coherence.rs
Normal file
45
tests/ui/traits/trivial-unsized-projection-in-coherence.rs
Normal 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() {}
|
@ -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`.
|
44
tests/ui/traits/trivial-unsized-projection.bad.stderr
Normal file
44
tests/ui/traits/trivial-unsized-projection.bad.stderr
Normal 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`.
|
44
tests/ui/traits/trivial-unsized-projection.bad_new.stderr
Normal file
44
tests/ui/traits/trivial-unsized-projection.bad_new.stderr
Normal 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`.
|
32
tests/ui/traits/trivial-unsized-projection.rs
Normal file
32
tests/ui/traits/trivial-unsized-projection.rs
Normal 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() {}
|
Loading…
Reference in New Issue
Block a user