Rigidly project missing item due to guaranteed impossible sized predicate

This commit is contained in:
Michael Goulet 2025-03-26 18:57:13 +00:00
parent 48f89e7659
commit 27836e1e57
8 changed files with 281 additions and 52 deletions

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,47 @@ 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 };
let tail = selcx.tcx().struct_tail_raw(
tcx.type_of(impl_def_id).instantiate(tcx, args),
|ty| {
normalize_with_depth_to(
selcx,
obligation.param_env,
obligation.cause.clone(),
obligation.recursion_depth + 1,
ty,
&mut nested,
)
},
|| {},
);
if tail.is_guaranteed_unsized_raw() {
// 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 +2044,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 +2053,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 +2064,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