mirror of https://github.com/rust-lang/rust.git
Report nicer lifetime errors for specialization
Add an obligation cause for these error so that the error points to the implementations that caused the error.
This commit is contained in:
parent
fafe9e71d5
commit
f46eabb9e5
|
@ -80,7 +80,7 @@ use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
|
|||
use rustc_span::Span;
|
||||
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
|
||||
use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
|
||||
use rustc_trait_selection::traits::{self, translate_substs, wf, ObligationCtxt};
|
||||
use rustc_trait_selection::traits::{self, translate_substs_with_cause, wf, ObligationCtxt};
|
||||
|
||||
pub(super) fn check_min_specialization(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) {
|
||||
if let Some(node) = parent_specialization_node(tcx, impl_def_id) {
|
||||
|
@ -180,8 +180,21 @@ fn get_impl_substs(
|
|||
ocx.assumed_wf_types(param_env, tcx.def_span(impl1_def_id), impl1_def_id);
|
||||
|
||||
let impl1_substs = InternalSubsts::identity_for_item(tcx, impl1_def_id);
|
||||
let impl2_substs =
|
||||
translate_substs(infcx, param_env, impl1_def_id.to_def_id(), impl1_substs, impl2_node);
|
||||
let impl1_span = tcx.def_span(impl1_def_id);
|
||||
let impl2_substs = translate_substs_with_cause(
|
||||
infcx,
|
||||
param_env,
|
||||
impl1_def_id.to_def_id(),
|
||||
impl1_substs,
|
||||
impl2_node,
|
||||
|_, span| {
|
||||
traits::ObligationCause::new(
|
||||
impl1_span,
|
||||
impl1_def_id,
|
||||
traits::ObligationCauseCode::BindingObligation(impl2_node.def_id(), span),
|
||||
)
|
||||
},
|
||||
);
|
||||
|
||||
let errors = ocx.select_all_or_error();
|
||||
if !errors.is_empty() {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -54,7 +54,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,7 +123,7 @@ pub fn translate_substs<'tcx>(
|
|||
return source_substs;
|
||||
}
|
||||
|
||||
fulfill_implication(infcx, param_env, source_trait_ref, source_impl, target_impl)
|
||||
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:?}, \
|
||||
|
@ -154,7 +178,10 @@ pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId,
|
|||
let infcx = tcx.infer_ctxt().build();
|
||||
|
||||
// Attempt to prove that impl2 applies, given all of the above.
|
||||
fulfill_implication(&infcx, penv, impl1_trait_ref, impl1_def_id, 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
|
||||
|
@ -168,6 +195,7 @@ fn fulfill_implication<'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)",
|
||||
|
@ -195,7 +223,7 @@ fn fulfill_implication<'tcx>(
|
|||
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, .. }) =
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
// Regression test for #79457.
|
||||
|
||||
#![feature(min_specialization)]
|
||||
|
||||
use std::any::Any;
|
||||
|
||||
pub trait Tr {
|
||||
fn method(self) -> Box<dyn Any + 'static>;
|
||||
fn other(self);
|
||||
}
|
||||
|
||||
impl<T: Any + 'static> Tr for T {
|
||||
default fn method(self) -> Box<dyn Any + 'static> {
|
||||
Box::new(self)
|
||||
}
|
||||
|
||||
default fn other(self) {}
|
||||
}
|
||||
|
||||
impl<'a> Tr for &'a i32 {
|
||||
//~^ ERROR does not fulfill the required lifetime
|
||||
fn other(self) {}
|
||||
}
|
||||
|
||||
fn promote_to_static<'a>(i: &'a i32) -> &'static i32 {
|
||||
*i.method().downcast().unwrap()
|
||||
}
|
||||
|
||||
struct Wrapper<'a>(&'a i32);
|
||||
|
||||
impl<'a> Tr for Wrapper<'a> {
|
||||
//~^ ERROR does not fulfill the required lifetime
|
||||
fn other(self) {}
|
||||
}
|
||||
|
||||
fn promote_to_static_2<'a>(w: Wrapper<'a>) -> Wrapper<'static> {
|
||||
*w.method().downcast().unwrap()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let i = Box::new(100_i32);
|
||||
let static_i: &'static i32 = promote_to_static(&*i);
|
||||
drop(i);
|
||||
println!("{}", *static_i);
|
||||
|
||||
let j = Box::new(200_i32);
|
||||
let static_w: Wrapper<'static> = promote_to_static_2(Wrapper(&*j));
|
||||
drop(j);
|
||||
println!("{}", *static_w.0);
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
error[E0477]: the type `&'a i32` does not fulfill the required lifetime
|
||||
--> $DIR/specialize_with_generalize_lifetimes.rs:20:1
|
||||
|
|
||||
LL | impl<'a> Tr for &'a i32 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: type must satisfy the static lifetime as required by this binding
|
||||
--> $DIR/specialize_with_generalize_lifetimes.rs:12:15
|
||||
|
|
||||
LL | impl<T: Any + 'static> Tr for T {
|
||||
| ^^^^^^^
|
||||
|
||||
error[E0477]: the type `Wrapper<'a>` does not fulfill the required lifetime
|
||||
--> $DIR/specialize_with_generalize_lifetimes.rs:31:1
|
||||
|
|
||||
LL | impl<'a> Tr for Wrapper<'a> {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: type must satisfy the static lifetime as required by this binding
|
||||
--> $DIR/specialize_with_generalize_lifetimes.rs:12:15
|
||||
|
|
||||
LL | impl<T: Any + 'static> Tr for T {
|
||||
| ^^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0477`.
|
Loading…
Reference in New Issue