Rollup merge of #111252 - matthewjasper:min-spec-improvements, r=compiler-errors
Min specialization improvements - Don't allow specialization impls with no items, such implementations are probably not correct and only occur as mistakes in the compiler and standard library - Fix a missing normalization call - Adds spans for lifetime errors from overly general specializations Closes #79457 Closes #109815
This commit is contained in:
commit
f748bb1402
20 changed files with 346 additions and 48 deletions
|
@ -322,7 +322,9 @@ fn negative_impl(tcx: TyCtxt<'_>, impl1_def_id: DefId, impl2_def_id: DefId) -> b
|
|||
let selcx = &mut SelectionContext::new(&infcx);
|
||||
let impl2_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl2_def_id);
|
||||
let (subject2, obligations) =
|
||||
impl_subject_and_oblig(selcx, impl_env, impl2_def_id, impl2_substs);
|
||||
impl_subject_and_oblig(selcx, impl_env, impl2_def_id, impl2_substs, |_, _| {
|
||||
ObligationCause::dummy()
|
||||
});
|
||||
|
||||
!equate(&infcx, impl_env, subject1, subject2, obligations, impl1_def_id)
|
||||
}
|
||||
|
|
|
@ -55,7 +55,9 @@ pub use self::select::{EvaluationCache, SelectionCache, SelectionContext};
|
|||
pub use self::select::{EvaluationResult, IntercrateAmbiguityCause, OverflowError};
|
||||
pub use self::specialize::specialization_graph::FutureCompatOverlapError;
|
||||
pub use self::specialize::specialization_graph::FutureCompatOverlapErrorKind;
|
||||
pub use self::specialize::{specialization_graph, translate_substs, OverlapError};
|
||||
pub use self::specialize::{
|
||||
specialization_graph, translate_substs, translate_substs_with_cause, OverlapError,
|
||||
};
|
||||
pub use self::structural_match::{
|
||||
search_for_adt_const_param_violation, search_for_structural_match_violation,
|
||||
};
|
||||
|
|
|
@ -82,6 +82,30 @@ pub fn translate_substs<'tcx>(
|
|||
source_impl: DefId,
|
||||
source_substs: SubstsRef<'tcx>,
|
||||
target_node: specialization_graph::Node,
|
||||
) -> SubstsRef<'tcx> {
|
||||
translate_substs_with_cause(
|
||||
infcx,
|
||||
param_env,
|
||||
source_impl,
|
||||
source_substs,
|
||||
target_node,
|
||||
|_, _| ObligationCause::dummy(),
|
||||
)
|
||||
}
|
||||
|
||||
/// Like [translate_substs], but obligations from the parent implementation
|
||||
/// are registered with the provided `ObligationCause`.
|
||||
///
|
||||
/// This is for reporting *region* errors from those bounds. Type errors should
|
||||
/// not happen because the specialization graph already checks for those, and
|
||||
/// will result in an ICE.
|
||||
pub fn translate_substs_with_cause<'tcx>(
|
||||
infcx: &InferCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
source_impl: DefId,
|
||||
source_substs: SubstsRef<'tcx>,
|
||||
target_node: specialization_graph::Node,
|
||||
cause: impl Fn(usize, Span) -> ObligationCause<'tcx>,
|
||||
) -> SubstsRef<'tcx> {
|
||||
debug!(
|
||||
"translate_substs({:?}, {:?}, {:?}, {:?})",
|
||||
|
@ -99,14 +123,13 @@ pub fn translate_substs<'tcx>(
|
|||
return source_substs;
|
||||
}
|
||||
|
||||
fulfill_implication(infcx, param_env, source_trait_ref, target_impl).unwrap_or_else(
|
||||
|()| {
|
||||
fulfill_implication(infcx, param_env, source_trait_ref, source_impl, target_impl, cause)
|
||||
.unwrap_or_else(|()| {
|
||||
bug!(
|
||||
"When translating substitutions from {source_impl:?} to {target_impl:?}, \
|
||||
the expected specialization failed to hold"
|
||||
)
|
||||
},
|
||||
)
|
||||
})
|
||||
}
|
||||
specialization_graph::Node::Trait(..) => source_trait_ref.substs,
|
||||
};
|
||||
|
@ -153,20 +176,12 @@ pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId,
|
|||
|
||||
// Create an infcx, taking the predicates of impl1 as assumptions:
|
||||
let infcx = tcx.infer_ctxt().build();
|
||||
let impl1_trait_ref =
|
||||
match traits::fully_normalize(&infcx, ObligationCause::dummy(), penv, impl1_trait_ref) {
|
||||
Ok(impl1_trait_ref) => impl1_trait_ref,
|
||||
Err(_errors) => {
|
||||
tcx.sess.delay_span_bug(
|
||||
tcx.def_span(impl1_def_id),
|
||||
format!("failed to fully normalize {impl1_trait_ref}"),
|
||||
);
|
||||
impl1_trait_ref
|
||||
}
|
||||
};
|
||||
|
||||
// Attempt to prove that impl2 applies, given all of the above.
|
||||
fulfill_implication(&infcx, penv, impl1_trait_ref, impl2_def_id).is_ok()
|
||||
fulfill_implication(&infcx, penv, impl1_trait_ref, impl1_def_id, impl2_def_id, |_, _| {
|
||||
ObligationCause::dummy()
|
||||
})
|
||||
.is_ok()
|
||||
}
|
||||
|
||||
/// Attempt to fulfill all obligations of `target_impl` after unification with
|
||||
|
@ -178,23 +193,41 @@ fn fulfill_implication<'tcx>(
|
|||
infcx: &InferCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
source_trait_ref: ty::TraitRef<'tcx>,
|
||||
source_impl: DefId,
|
||||
target_impl: DefId,
|
||||
error_cause: impl Fn(usize, Span) -> ObligationCause<'tcx>,
|
||||
) -> Result<SubstsRef<'tcx>, ()> {
|
||||
debug!(
|
||||
"fulfill_implication({:?}, trait_ref={:?} |- {:?} applies)",
|
||||
param_env, source_trait_ref, target_impl
|
||||
);
|
||||
|
||||
let source_trait_ref = match traits::fully_normalize(
|
||||
&infcx,
|
||||
ObligationCause::dummy(),
|
||||
param_env,
|
||||
source_trait_ref,
|
||||
) {
|
||||
Ok(source_trait_ref) => source_trait_ref,
|
||||
Err(_errors) => {
|
||||
infcx.tcx.sess.delay_span_bug(
|
||||
infcx.tcx.def_span(source_impl),
|
||||
format!("failed to fully normalize {source_trait_ref}"),
|
||||
);
|
||||
source_trait_ref
|
||||
}
|
||||
};
|
||||
|
||||
let source_trait = ImplSubject::Trait(source_trait_ref);
|
||||
|
||||
let selcx = &mut SelectionContext::new(&infcx);
|
||||
let target_substs = infcx.fresh_substs_for_item(DUMMY_SP, target_impl);
|
||||
let (target_trait, obligations) =
|
||||
util::impl_subject_and_oblig(selcx, param_env, target_impl, target_substs);
|
||||
util::impl_subject_and_oblig(selcx, param_env, target_impl, target_substs, error_cause);
|
||||
|
||||
// do the impls unify? If not, no specialization.
|
||||
let Ok(InferOk { obligations: more_obligations, .. }) =
|
||||
infcx.at(&ObligationCause::dummy(), param_env, ).eq(DefineOpaqueTypes::No,source_trait, target_trait)
|
||||
infcx.at(&ObligationCause::dummy(), param_env).eq(DefineOpaqueTypes::No, source_trait, target_trait)
|
||||
else {
|
||||
debug!(
|
||||
"fulfill_implication: {:?} does not unify with {:?}",
|
||||
|
|
|
@ -197,6 +197,7 @@ pub fn impl_subject_and_oblig<'a, 'tcx>(
|
|||
param_env: ty::ParamEnv<'tcx>,
|
||||
impl_def_id: DefId,
|
||||
impl_substs: SubstsRef<'tcx>,
|
||||
cause: impl Fn(usize, Span) -> ObligationCause<'tcx>,
|
||||
) -> (ImplSubject<'tcx>, impl Iterator<Item = PredicateObligation<'tcx>>) {
|
||||
let subject = selcx.tcx().impl_subject(impl_def_id);
|
||||
let subject = subject.subst(selcx.tcx(), impl_substs);
|
||||
|
@ -208,8 +209,7 @@ pub fn impl_subject_and_oblig<'a, 'tcx>(
|
|||
let predicates = predicates.instantiate(selcx.tcx(), impl_substs);
|
||||
let InferOk { value: predicates, obligations: normalization_obligations2 } =
|
||||
selcx.infcx.at(&ObligationCause::dummy(), param_env).normalize(predicates);
|
||||
let impl_obligations =
|
||||
super::predicates_for_generics(|_, _| ObligationCause::dummy(), param_env, predicates);
|
||||
let impl_obligations = super::predicates_for_generics(cause, param_env, predicates);
|
||||
|
||||
let impl_obligations = impl_obligations
|
||||
.chain(normalization_obligations1.into_iter())
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue