mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-26 00:34:06 +00:00
Avoid cycle with projections from object types
Normalizing `<dyn Iterator<Item = ()> as Iterator>::Item` no longer requires selecting `dyn Iterator<Item = ()>: Iterator`. This was previously worked around by using a special type-folder to normalize things.
This commit is contained in:
parent
34e5a4992c
commit
596d6c4b3b
@ -1,6 +1,5 @@
|
|||||||
//! Code for projecting associated types out of trait references.
|
//! Code for projecting associated types out of trait references.
|
||||||
|
|
||||||
use super::elaborate_predicates;
|
|
||||||
use super::specialization_graph;
|
use super::specialization_graph;
|
||||||
use super::translate_substs;
|
use super::translate_substs;
|
||||||
use super::util;
|
use super::util;
|
||||||
@ -53,13 +52,16 @@ pub enum ProjectionTyError<'tcx> {
|
|||||||
|
|
||||||
#[derive(PartialEq, Eq, Debug)]
|
#[derive(PartialEq, Eq, Debug)]
|
||||||
enum ProjectionTyCandidate<'tcx> {
|
enum ProjectionTyCandidate<'tcx> {
|
||||||
// from a where-clause in the env or object type
|
/// From a where-clause in the env or object type
|
||||||
ParamEnv(ty::PolyProjectionPredicate<'tcx>),
|
ParamEnv(ty::PolyProjectionPredicate<'tcx>),
|
||||||
|
|
||||||
// from the definition of `Trait` when you have something like <<A as Trait>::B as Trait2>::C
|
/// From the definition of `Trait` when you have something like <<A as Trait>::B as Trait2>::C
|
||||||
TraitDef(ty::PolyProjectionPredicate<'tcx>),
|
TraitDef(ty::PolyProjectionPredicate<'tcx>),
|
||||||
|
|
||||||
// from a "impl" (or a "pseudo-impl" returned by select)
|
/// Bounds specified on an object type
|
||||||
|
Object(ty::PolyProjectionPredicate<'tcx>),
|
||||||
|
|
||||||
|
/// From a "impl" (or a "pseudo-impl" returned by select)
|
||||||
Select(Selection<'tcx>),
|
Select(Selection<'tcx>),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -561,14 +563,6 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
|
|||||||
} else {
|
} else {
|
||||||
obligations.extend(ty.obligations);
|
obligations.extend(ty.obligations);
|
||||||
}
|
}
|
||||||
|
|
||||||
obligations.push(get_paranoid_cache_value_obligation(
|
|
||||||
infcx,
|
|
||||||
param_env,
|
|
||||||
projection_ty,
|
|
||||||
cause,
|
|
||||||
depth,
|
|
||||||
));
|
|
||||||
return Ok(Some(ty.value));
|
return Ok(Some(ty.value));
|
||||||
}
|
}
|
||||||
Err(ProjectionCacheEntry::Error) => {
|
Err(ProjectionCacheEntry::Error) => {
|
||||||
@ -703,45 +697,6 @@ fn prune_cache_value_obligations<'a, 'tcx>(
|
|||||||
NormalizedTy { value: result.value, obligations }
|
NormalizedTy { value: result.value, obligations }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whenever we give back a cache result for a projection like `<T as
|
|
||||||
/// Trait>::Item ==> X`, we *always* include the obligation to prove
|
|
||||||
/// that `T: Trait` (we may also include some other obligations). This
|
|
||||||
/// may or may not be necessary -- in principle, all the obligations
|
|
||||||
/// that must be proven to show that `T: Trait` were also returned
|
|
||||||
/// when the cache was first populated. But there are some vague concerns,
|
|
||||||
/// and so we take the precautionary measure of including `T: Trait` in
|
|
||||||
/// the result:
|
|
||||||
///
|
|
||||||
/// Concern #1. The current setup is fragile. Perhaps someone could
|
|
||||||
/// have failed to prove the concerns from when the cache was
|
|
||||||
/// populated, but also not have used a snapshot, in which case the
|
|
||||||
/// cache could remain populated even though `T: Trait` has not been
|
|
||||||
/// shown. In this case, the "other code" is at fault -- when you
|
|
||||||
/// project something, you are supposed to either have a snapshot or
|
|
||||||
/// else prove all the resulting obligations -- but it's still easy to
|
|
||||||
/// get wrong.
|
|
||||||
///
|
|
||||||
/// Concern #2. Even within the snapshot, if those original
|
|
||||||
/// obligations are not yet proven, then we are able to do projections
|
|
||||||
/// that may yet turn out to be wrong. This *may* lead to some sort
|
|
||||||
/// of trouble, though we don't have a concrete example of how that
|
|
||||||
/// can occur yet. But it seems risky at best.
|
|
||||||
fn get_paranoid_cache_value_obligation<'a, 'tcx>(
|
|
||||||
infcx: &'a InferCtxt<'a, 'tcx>,
|
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
|
||||||
projection_ty: ty::ProjectionTy<'tcx>,
|
|
||||||
cause: ObligationCause<'tcx>,
|
|
||||||
depth: usize,
|
|
||||||
) -> PredicateObligation<'tcx> {
|
|
||||||
let trait_ref = projection_ty.trait_ref(infcx.tcx).to_poly_trait_ref();
|
|
||||||
Obligation {
|
|
||||||
cause,
|
|
||||||
recursion_depth: depth,
|
|
||||||
param_env,
|
|
||||||
predicate: trait_ref.without_const().to_predicate(infcx.tcx),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// If we are projecting `<T as Trait>::Item`, but `T: Trait` does not
|
/// If we are projecting `<T as Trait>::Item`, but `T: Trait` does not
|
||||||
/// hold. In various error cases, we cannot generate a valid
|
/// hold. In various error cases, we cannot generate a valid
|
||||||
/// normalized projection. Therefore, we create an inference variable
|
/// normalized projection. Therefore, we create an inference variable
|
||||||
@ -848,12 +803,21 @@ fn project_type<'cx, 'tcx>(
|
|||||||
|
|
||||||
assemble_candidates_from_trait_def(selcx, obligation, &obligation_trait_ref, &mut candidates);
|
assemble_candidates_from_trait_def(selcx, obligation, &obligation_trait_ref, &mut candidates);
|
||||||
|
|
||||||
assemble_candidates_from_impls(selcx, obligation, &obligation_trait_ref, &mut candidates);
|
assemble_candidates_from_object_ty(selcx, obligation, &obligation_trait_ref, &mut candidates);
|
||||||
|
|
||||||
|
if let ProjectionTyCandidateSet::Single(ProjectionTyCandidate::Object(_)) = candidates {
|
||||||
|
// Avoid normalization cycle from selection (see
|
||||||
|
// `assemble_candidates_from_object_ty`).
|
||||||
|
// FIXME(lazy_normalization): Lazy normalization should save us from
|
||||||
|
// having to do special case this.
|
||||||
|
} else {
|
||||||
|
assemble_candidates_from_impls(selcx, obligation, &obligation_trait_ref, &mut candidates);
|
||||||
|
};
|
||||||
|
|
||||||
match candidates {
|
match candidates {
|
||||||
ProjectionTyCandidateSet::Single(candidate) => Ok(ProjectedTy::Progress(
|
ProjectionTyCandidateSet::Single(candidate) => {
|
||||||
confirm_candidate(selcx, obligation, &obligation_trait_ref, candidate),
|
Ok(ProjectedTy::Progress(confirm_candidate(selcx, obligation, candidate)))
|
||||||
)),
|
}
|
||||||
ProjectionTyCandidateSet::None => Ok(ProjectedTy::NoProgress(
|
ProjectionTyCandidateSet::None => Ok(ProjectedTy::NoProgress(
|
||||||
selcx
|
selcx
|
||||||
.tcx()
|
.tcx()
|
||||||
@ -932,6 +896,53 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// In the case of a trait object like
|
||||||
|
/// `<dyn Iterator<Item = ()> as Iterator>::Item` we can use the existential
|
||||||
|
/// predicate in the trait object.
|
||||||
|
///
|
||||||
|
/// We don't go through the select candidate for these bounds to avoid cycles:
|
||||||
|
/// In the above case, `dyn Iterator<Item = ()>: Iterator` would create a
|
||||||
|
/// nested obligation of `<dyn Iterator<Item = ()> as Iterator>::Item: Sized`,
|
||||||
|
/// this then has to be normalized without having to prove
|
||||||
|
/// `dyn Iterator<Item = ()>: Iterator` again.
|
||||||
|
fn assemble_candidates_from_object_ty<'cx, 'tcx>(
|
||||||
|
selcx: &mut SelectionContext<'cx, 'tcx>,
|
||||||
|
obligation: &ProjectionTyObligation<'tcx>,
|
||||||
|
obligation_trait_ref: &ty::TraitRef<'tcx>,
|
||||||
|
candidate_set: &mut ProjectionTyCandidateSet<'tcx>,
|
||||||
|
) {
|
||||||
|
debug!("assemble_candidates_from_object_ty(..)");
|
||||||
|
|
||||||
|
let tcx = selcx.tcx();
|
||||||
|
|
||||||
|
let self_ty = obligation_trait_ref.self_ty();
|
||||||
|
let object_ty = selcx.infcx().shallow_resolve(self_ty);
|
||||||
|
let data = match object_ty.kind {
|
||||||
|
ty::Dynamic(ref data, ..) => data,
|
||||||
|
ty::Infer(ty::TyVar(_)) => {
|
||||||
|
// If the self-type is an inference variable, then it MAY wind up
|
||||||
|
// being an object type, so induce an ambiguity.
|
||||||
|
candidate_set.mark_ambiguous();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_ => return,
|
||||||
|
};
|
||||||
|
let env_predicates = data
|
||||||
|
.projection_bounds()
|
||||||
|
.filter(|bound| bound.item_def_id() == obligation.predicate.item_def_id)
|
||||||
|
.map(|p| p.with_self_ty(tcx, object_ty).to_predicate(tcx));
|
||||||
|
|
||||||
|
assemble_candidates_from_predicates(
|
||||||
|
selcx,
|
||||||
|
obligation,
|
||||||
|
obligation_trait_ref,
|
||||||
|
candidate_set,
|
||||||
|
ProjectionTyCandidate::Object,
|
||||||
|
env_predicates,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
fn assemble_candidates_from_predicates<'cx, 'tcx>(
|
fn assemble_candidates_from_predicates<'cx, 'tcx>(
|
||||||
selcx: &mut SelectionContext<'cx, 'tcx>,
|
selcx: &mut SelectionContext<'cx, 'tcx>,
|
||||||
obligation: &ProjectionTyObligation<'tcx>,
|
obligation: &ProjectionTyObligation<'tcx>,
|
||||||
@ -1000,7 +1011,6 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
|
|||||||
super::ImplSource::Closure(_)
|
super::ImplSource::Closure(_)
|
||||||
| super::ImplSource::Generator(_)
|
| super::ImplSource::Generator(_)
|
||||||
| super::ImplSource::FnPointer(_)
|
| super::ImplSource::FnPointer(_)
|
||||||
| super::ImplSource::Object(_)
|
|
||||||
| super::ImplSource::TraitAlias(_) => {
|
| super::ImplSource::TraitAlias(_) => {
|
||||||
debug!("assemble_candidates_from_impls: impl_source={:?}", impl_source);
|
debug!("assemble_candidates_from_impls: impl_source={:?}", impl_source);
|
||||||
true
|
true
|
||||||
@ -1125,6 +1135,12 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
|
|||||||
// in `assemble_candidates_from_param_env`.
|
// in `assemble_candidates_from_param_env`.
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
super::ImplSource::Object(_) => {
|
||||||
|
// Handled by the `Object` projection candidate. See
|
||||||
|
// `assemble_candidates_from_object_ty` for an explanation of
|
||||||
|
// why we special case object types.
|
||||||
|
false
|
||||||
|
}
|
||||||
super::ImplSource::AutoImpl(..) | super::ImplSource::Builtin(..) => {
|
super::ImplSource::AutoImpl(..) | super::ImplSource::Builtin(..) => {
|
||||||
// These traits have no associated types.
|
// These traits have no associated types.
|
||||||
selcx.tcx().sess.delay_span_bug(
|
selcx.tcx().sess.delay_span_bug(
|
||||||
@ -1150,13 +1166,13 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
|
|||||||
fn confirm_candidate<'cx, 'tcx>(
|
fn confirm_candidate<'cx, 'tcx>(
|
||||||
selcx: &mut SelectionContext<'cx, 'tcx>,
|
selcx: &mut SelectionContext<'cx, 'tcx>,
|
||||||
obligation: &ProjectionTyObligation<'tcx>,
|
obligation: &ProjectionTyObligation<'tcx>,
|
||||||
obligation_trait_ref: &ty::TraitRef<'tcx>,
|
|
||||||
candidate: ProjectionTyCandidate<'tcx>,
|
candidate: ProjectionTyCandidate<'tcx>,
|
||||||
) -> Progress<'tcx> {
|
) -> Progress<'tcx> {
|
||||||
debug!("confirm_candidate(candidate={:?}, obligation={:?})", candidate, obligation);
|
debug!("confirm_candidate(candidate={:?}, obligation={:?})", candidate, obligation);
|
||||||
|
|
||||||
let mut progress = match candidate {
|
let mut progress = match candidate {
|
||||||
ProjectionTyCandidate::ParamEnv(poly_projection) => {
|
ProjectionTyCandidate::ParamEnv(poly_projection)
|
||||||
|
| ProjectionTyCandidate::Object(poly_projection) => {
|
||||||
confirm_param_env_candidate(selcx, obligation, poly_projection, false)
|
confirm_param_env_candidate(selcx, obligation, poly_projection, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1165,7 +1181,7 @@ fn confirm_candidate<'cx, 'tcx>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
ProjectionTyCandidate::Select(impl_source) => {
|
ProjectionTyCandidate::Select(impl_source) => {
|
||||||
confirm_select_candidate(selcx, obligation, obligation_trait_ref, impl_source)
|
confirm_select_candidate(selcx, obligation, impl_source)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// When checking for cycle during evaluation, we compare predicates with
|
// When checking for cycle during evaluation, we compare predicates with
|
||||||
@ -1182,7 +1198,6 @@ fn confirm_candidate<'cx, 'tcx>(
|
|||||||
fn confirm_select_candidate<'cx, 'tcx>(
|
fn confirm_select_candidate<'cx, 'tcx>(
|
||||||
selcx: &mut SelectionContext<'cx, 'tcx>,
|
selcx: &mut SelectionContext<'cx, 'tcx>,
|
||||||
obligation: &ProjectionTyObligation<'tcx>,
|
obligation: &ProjectionTyObligation<'tcx>,
|
||||||
obligation_trait_ref: &ty::TraitRef<'tcx>,
|
|
||||||
impl_source: Selection<'tcx>,
|
impl_source: Selection<'tcx>,
|
||||||
) -> Progress<'tcx> {
|
) -> Progress<'tcx> {
|
||||||
match impl_source {
|
match impl_source {
|
||||||
@ -1193,10 +1208,8 @@ fn confirm_select_candidate<'cx, 'tcx>(
|
|||||||
super::ImplSource::DiscriminantKind(data) => {
|
super::ImplSource::DiscriminantKind(data) => {
|
||||||
confirm_discriminant_kind_candidate(selcx, obligation, data)
|
confirm_discriminant_kind_candidate(selcx, obligation, data)
|
||||||
}
|
}
|
||||||
super::ImplSource::Object(_) => {
|
super::ImplSource::Object(_)
|
||||||
confirm_object_candidate(selcx, obligation, obligation_trait_ref)
|
| super::ImplSource::AutoImpl(..)
|
||||||
}
|
|
||||||
super::ImplSource::AutoImpl(..)
|
|
||||||
| super::ImplSource::Param(..)
|
| super::ImplSource::Param(..)
|
||||||
| super::ImplSource::Builtin(..)
|
| super::ImplSource::Builtin(..)
|
||||||
| super::ImplSource::TraitAlias(..) =>
|
| super::ImplSource::TraitAlias(..) =>
|
||||||
@ -1211,72 +1224,6 @@ fn confirm_select_candidate<'cx, 'tcx>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn confirm_object_candidate<'cx, 'tcx>(
|
|
||||||
selcx: &mut SelectionContext<'cx, 'tcx>,
|
|
||||||
obligation: &ProjectionTyObligation<'tcx>,
|
|
||||||
obligation_trait_ref: &ty::TraitRef<'tcx>,
|
|
||||||
) -> Progress<'tcx> {
|
|
||||||
let self_ty = obligation_trait_ref.self_ty();
|
|
||||||
let object_ty = selcx.infcx().shallow_resolve(self_ty);
|
|
||||||
debug!("confirm_object_candidate(object_ty={:?})", object_ty);
|
|
||||||
let data = match object_ty.kind() {
|
|
||||||
ty::Dynamic(data, ..) => data,
|
|
||||||
_ => span_bug!(
|
|
||||||
obligation.cause.span,
|
|
||||||
"confirm_object_candidate called with non-object: {:?}",
|
|
||||||
object_ty
|
|
||||||
),
|
|
||||||
};
|
|
||||||
let env_predicates = data
|
|
||||||
.projection_bounds()
|
|
||||||
.map(|p| p.with_self_ty(selcx.tcx(), object_ty).to_predicate(selcx.tcx()));
|
|
||||||
let env_predicate = {
|
|
||||||
let env_predicates = elaborate_predicates(selcx.tcx(), env_predicates);
|
|
||||||
|
|
||||||
// select only those projections that are actually projecting an
|
|
||||||
// item with the correct name
|
|
||||||
|
|
||||||
let env_predicates = env_predicates.filter_map(|o| match o.predicate.skip_binders() {
|
|
||||||
ty::PredicateAtom::Projection(data)
|
|
||||||
if data.projection_ty.item_def_id == obligation.predicate.item_def_id =>
|
|
||||||
{
|
|
||||||
Some(ty::Binder::bind(data))
|
|
||||||
}
|
|
||||||
_ => None,
|
|
||||||
});
|
|
||||||
|
|
||||||
// select those with a relevant trait-ref
|
|
||||||
let mut env_predicates = env_predicates.filter(|data| {
|
|
||||||
let data_poly_trait_ref = data.to_poly_trait_ref(selcx.tcx());
|
|
||||||
let obligation_poly_trait_ref = obligation_trait_ref.to_poly_trait_ref();
|
|
||||||
selcx.infcx().probe(|_| {
|
|
||||||
selcx
|
|
||||||
.infcx()
|
|
||||||
.at(&obligation.cause, obligation.param_env)
|
|
||||||
.sup(obligation_poly_trait_ref, data_poly_trait_ref)
|
|
||||||
.is_ok()
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
// select the first matching one; there really ought to be one or
|
|
||||||
// else the object type is not WF, since an object type should
|
|
||||||
// include all of its projections explicitly
|
|
||||||
match env_predicates.next() {
|
|
||||||
Some(env_predicate) => env_predicate,
|
|
||||||
None => {
|
|
||||||
debug!(
|
|
||||||
"confirm_object_candidate: no env-predicate \
|
|
||||||
found in object type `{:?}`; ill-formed",
|
|
||||||
object_ty
|
|
||||||
);
|
|
||||||
return Progress::error(selcx.tcx());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
confirm_param_env_candidate(selcx, obligation, env_predicate, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn confirm_generator_candidate<'cx, 'tcx>(
|
fn confirm_generator_candidate<'cx, 'tcx>(
|
||||||
selcx: &mut SelectionContext<'cx, 'tcx>,
|
selcx: &mut SelectionContext<'cx, 'tcx>,
|
||||||
obligation: &ProjectionTyObligation<'tcx>,
|
obligation: &ProjectionTyObligation<'tcx>,
|
||||||
|
@ -9,11 +9,10 @@
|
|||||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||||
use rustc_hir::lang_items::LangItem;
|
use rustc_hir::lang_items::LangItem;
|
||||||
use rustc_index::bit_set::GrowableBitSet;
|
use rustc_index::bit_set::GrowableBitSet;
|
||||||
|
use rustc_infer::infer::InferOk;
|
||||||
use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType;
|
use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType;
|
||||||
use rustc_infer::infer::{self, InferOk};
|
|
||||||
use rustc_middle::ty::fold::TypeFolder;
|
|
||||||
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef};
|
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef};
|
||||||
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
|
use rustc_middle::ty::{self, Ty};
|
||||||
use rustc_middle::ty::{ToPolyTraitRef, ToPredicate, WithConstness};
|
use rustc_middle::ty::{ToPolyTraitRef, ToPredicate, WithConstness};
|
||||||
use rustc_span::def_id::DefId;
|
use rustc_span::def_id::DefId;
|
||||||
|
|
||||||
@ -434,100 +433,54 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
vtable_base = nonmatching.map(|t| super::util::count_own_vtable_entries(tcx, t)).sum();
|
vtable_base = nonmatching.map(|t| super::util::count_own_vtable_entries(tcx, t)).sum();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check supertraits hold
|
|
||||||
nested.extend(util::supertraits(tcx, obligation_trait_ref).skip(1).map(|super_trait| {
|
|
||||||
Obligation::new(
|
|
||||||
obligation.cause.clone(),
|
|
||||||
obligation.param_env,
|
|
||||||
super_trait.without_const().to_predicate(tcx),
|
|
||||||
)
|
|
||||||
}));
|
|
||||||
|
|
||||||
let upcast_trait_ref = upcast_trait_ref.unwrap();
|
let upcast_trait_ref = upcast_trait_ref.unwrap();
|
||||||
|
|
||||||
|
// Check supertraits hold
|
||||||
|
nested.extend(
|
||||||
|
tcx.super_predicates_of(trait_predicate.def_id())
|
||||||
|
.instantiate(tcx, trait_predicate.trait_ref.substs)
|
||||||
|
.predicates
|
||||||
|
.into_iter()
|
||||||
|
.map(|super_trait| {
|
||||||
|
Obligation::new(obligation.cause.clone(), obligation.param_env, super_trait)
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
let assoc_types: Vec<_> = tcx
|
let assoc_types: Vec<_> = tcx
|
||||||
.associated_items(upcast_trait_ref.def_id())
|
.associated_items(trait_predicate.def_id())
|
||||||
.in_definition_order()
|
.in_definition_order()
|
||||||
.filter_map(
|
.filter_map(
|
||||||
|item| if item.kind == ty::AssocKind::Type { Some(item.def_id) } else { None },
|
|item| if item.kind == ty::AssocKind::Type { Some(item.def_id) } else { None },
|
||||||
)
|
)
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
if !assoc_types.is_empty() {
|
for assoc_type in assoc_types {
|
||||||
let predicates: Vec<_> =
|
if !tcx.generics_of(assoc_type).params.is_empty() {
|
||||||
data.iter()
|
// FIXME(generic_associated_types) generate placeholders to
|
||||||
.filter_map(|pred| match pred {
|
// extend the trait substs.
|
||||||
ty::ExistentialPredicate::Projection(proj) => {
|
tcx.sess.span_fatal(
|
||||||
if assoc_types.contains(&proj.item_def_id) {
|
obligation.cause.span,
|
||||||
match self.infcx.commit_if_ok(|_| {
|
"generic associated types in trait objects are not supported yet",
|
||||||
self.infcx
|
);
|
||||||
.at(&obligation.cause, obligation.param_env)
|
}
|
||||||
.sup(
|
// This maybe belongs in wf, but that can't (doesn't) handle
|
||||||
ty::Binder::dummy(
|
// higher-ranked things.
|
||||||
proj.trait_ref(tcx).with_self_ty(tcx, self_ty),
|
// Prevent, e.g., `dyn Iterator<Item = str>`.
|
||||||
),
|
for bound in self.tcx().item_bounds(assoc_type) {
|
||||||
upcast_trait_ref,
|
let subst_bound = bound.subst(tcx, trait_predicate.trait_ref.substs);
|
||||||
)
|
let normalized_bound = normalize_with_depth_to(
|
||||||
.map(|InferOk { obligations, .. }| obligations)
|
self,
|
||||||
.map_err(|_| ())
|
obligation.param_env,
|
||||||
}) {
|
obligation.cause.clone(),
|
||||||
Ok(obligations) => {
|
obligation.recursion_depth + 1,
|
||||||
nested.extend(obligations);
|
&subst_bound,
|
||||||
Some(proj)
|
&mut nested,
|
||||||
}
|
);
|
||||||
Err(_) => None,
|
nested.push(Obligation::new(
|
||||||
}
|
obligation.cause.clone(),
|
||||||
} else {
|
obligation.param_env.clone(),
|
||||||
None
|
normalized_bound,
|
||||||
}
|
));
|
||||||
}
|
|
||||||
ty::ExistentialPredicate::AutoTrait(_)
|
|
||||||
| ty::ExistentialPredicate::Trait(_) => None,
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let upcast_trait_ref = upcast_trait_ref
|
|
||||||
.no_bound_vars()
|
|
||||||
.expect("sup shouldn't return binder with bound vars");
|
|
||||||
let mut normalizer = ObjectAssociatedTypeNormalizer {
|
|
||||||
infcx: self.infcx,
|
|
||||||
object_ty: self_ty,
|
|
||||||
object_bounds: &predicates,
|
|
||||||
param_env: obligation.param_env,
|
|
||||||
cause: &obligation.cause,
|
|
||||||
nested: &mut nested,
|
|
||||||
};
|
|
||||||
for assoc_type in assoc_types {
|
|
||||||
if !tcx.generics_of(assoc_type).params.is_empty() {
|
|
||||||
// FIXME(generic_associated_types) generate placeholders to
|
|
||||||
// extend the trait substs.
|
|
||||||
tcx.sess.span_fatal(
|
|
||||||
obligation.cause.span,
|
|
||||||
"generic associated types in trait objects are not supported yet",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
// This maybe belongs in wf, but that can't (doesn't) handle
|
|
||||||
// higher-ranked things.
|
|
||||||
// Prevent, e.g., `dyn Iterator<Item = str>`.
|
|
||||||
for bound in self.tcx().item_bounds(assoc_type) {
|
|
||||||
let subst_bound = bound.subst(tcx, upcast_trait_ref.substs);
|
|
||||||
// Normalize projections the trait object manually to
|
|
||||||
// avoid evaluation overflow.
|
|
||||||
let object_normalized = subst_bound.fold_with(&mut normalizer);
|
|
||||||
let normalized_bound = normalize_with_depth_to(
|
|
||||||
self,
|
|
||||||
obligation.param_env,
|
|
||||||
obligation.cause.clone(),
|
|
||||||
obligation.recursion_depth + 1,
|
|
||||||
&object_normalized,
|
|
||||||
normalizer.nested,
|
|
||||||
);
|
|
||||||
normalizer.nested.push(Obligation::new(
|
|
||||||
obligation.cause.clone(),
|
|
||||||
obligation.param_env.clone(),
|
|
||||||
normalized_bound,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -972,50 +925,3 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
Ok(ImplSourceBuiltinData { nested })
|
Ok(ImplSourceBuiltinData { nested })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ObjectAssociatedTypeNormalizer<'a, 'tcx> {
|
|
||||||
infcx: &'a infer::InferCtxt<'a, 'tcx>,
|
|
||||||
object_ty: Ty<'tcx>,
|
|
||||||
object_bounds: &'a [ty::ExistentialProjection<'tcx>],
|
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
|
||||||
cause: &'a ObligationCause<'tcx>,
|
|
||||||
nested: &'a mut Vec<PredicateObligation<'tcx>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> TypeFolder<'tcx> for ObjectAssociatedTypeNormalizer<'_, 'tcx> {
|
|
||||||
fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
|
|
||||||
self.infcx.tcx
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
|
|
||||||
if !t.has_projections() {
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
if let ty::Projection(proj) = t.kind {
|
|
||||||
if let ty::Dynamic(..) = proj.self_ty().kind {
|
|
||||||
for bound in self.object_bounds {
|
|
||||||
if proj.item_def_id == bound.item_def_id {
|
|
||||||
// FIXME(generic_associated_types): This isn't relating
|
|
||||||
// the substs for the associated type.
|
|
||||||
match self.infcx.commit_if_ok(|_| {
|
|
||||||
self.infcx.at(self.cause, self.param_env).sub(
|
|
||||||
bound
|
|
||||||
.with_self_ty(self.infcx.tcx, self.object_ty)
|
|
||||||
.projection_ty
|
|
||||||
.trait_ref(self.infcx.tcx),
|
|
||||||
proj.trait_ref(self.infcx.tcx),
|
|
||||||
)
|
|
||||||
}) {
|
|
||||||
Ok(InferOk { value: (), obligations }) => {
|
|
||||||
self.nested.extend(obligations);
|
|
||||||
return bound.ty;
|
|
||||||
}
|
|
||||||
Err(_) => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
t.super_fold_with(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -441,8 +441,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
) -> Result<EvaluationResult, OverflowError> {
|
) -> Result<EvaluationResult, OverflowError> {
|
||||||
debug!(
|
debug!(
|
||||||
"evaluate_predicate_recursively(obligation={:?}, previous_stack={:?})",
|
"evaluate_predicate_recursively(obligation={:?}, previous_stack={:?})",
|
||||||
previous_stack.head(),
|
obligation,
|
||||||
obligation
|
previous_stack.head()
|
||||||
);
|
);
|
||||||
|
|
||||||
// `previous_stack` stores a `TraitObligation`, while `obligation` is
|
// `previous_stack` stores a `TraitObligation`, while `obligation` is
|
||||||
|
@ -5,17 +5,18 @@
|
|||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
trait Dummy<'a> {
|
trait Dummy<'a> {
|
||||||
type Out;
|
type Out;
|
||||||
}
|
}
|
||||||
impl<'a, T> Dummy<'a> for T
|
impl<'a, T> Dummy<'a> for T
|
||||||
where T: 'a
|
where
|
||||||
|
T: 'a,
|
||||||
{
|
{
|
||||||
type Out = ();
|
type Out = ();
|
||||||
}
|
}
|
||||||
type RequireOutlives<'a, T> = <T as Dummy<'a>>::Out;
|
type RequireOutlives<'a, T> = <T as Dummy<'a>>::Out;
|
||||||
|
|
||||||
enum Ref1<'a, T> {
|
enum Ref1<'a, T> {
|
||||||
Ref1Variant1(RequireOutlives<'a, T>) //~ ERROR the parameter type `T` may not live long enough
|
Ref1Variant1(RequireOutlives<'a, T>), //~ ERROR the parameter type `T` may not live long enough
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Ref2<'a, T> {
|
enum Ref2<'a, T> {
|
||||||
@ -23,18 +24,18 @@ enum Ref2<'a, T> {
|
|||||||
Ref2Variant2(isize, RequireOutlives<'a, T>), //~ ERROR the parameter type `T` may not live long enough
|
Ref2Variant2(isize, RequireOutlives<'a, T>), //~ ERROR the parameter type `T` may not live long enough
|
||||||
}
|
}
|
||||||
|
|
||||||
enum RefOk<'a, T:'a> {
|
enum RefOk<'a, T: 'a> {
|
||||||
RefOkVariant1(&'a T)
|
RefOkVariant1(&'a T),
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is now well formed. RFC 2093
|
// This is now well formed. RFC 2093
|
||||||
enum RefIndirect<'a, T> {
|
enum RefIndirect<'a, T> {
|
||||||
RefIndirectVariant1(isize, RefOk<'a,T>)
|
RefIndirectVariant1(isize, RefOk<'a, T>),
|
||||||
}
|
}
|
||||||
|
|
||||||
enum RefDouble<'a, 'b, T> { //~ ERROR the parameter type `T` may not live long enough [E0309]
|
enum RefDouble<'a, 'b, T> {
|
||||||
RefDoubleVariant1(&'a RequireOutlives<'b, T>)
|
RefDoubleVariant1(&'a RequireOutlives<'b, T>),
|
||||||
//~^ the parameter type `T` may not live long enough [E0309]
|
//~^ the parameter type `T` may not live long enough [E0309]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() { }
|
fn main() {}
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
error[E0309]: the parameter type `T` may not live long enough
|
error[E0309]: the parameter type `T` may not live long enough
|
||||||
--> $DIR/regions-enum-not-wf.rs:18:18
|
--> $DIR/regions-enum-not-wf.rs:19:18
|
||||||
|
|
|
|
||||||
LL | enum Ref1<'a, T> {
|
LL | enum Ref1<'a, T> {
|
||||||
| - help: consider adding an explicit lifetime bound...: `T: 'a`
|
| - help: consider adding an explicit lifetime bound...: `T: 'a`
|
||||||
LL | Ref1Variant1(RequireOutlives<'a, T>)
|
LL | Ref1Variant1(RequireOutlives<'a, T>),
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
|
| ^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
|
||||||
|
|
||||||
error[E0309]: the parameter type `T` may not live long enough
|
error[E0309]: the parameter type `T` may not live long enough
|
||||||
--> $DIR/regions-enum-not-wf.rs:23:25
|
--> $DIR/regions-enum-not-wf.rs:24:25
|
||||||
|
|
|
|
||||||
LL | enum Ref2<'a, T> {
|
LL | enum Ref2<'a, T> {
|
||||||
| - help: consider adding an explicit lifetime bound...: `T: 'a`
|
| - help: consider adding an explicit lifetime bound...: `T: 'a`
|
||||||
@ -16,25 +16,13 @@ LL | Ref2Variant2(isize, RequireOutlives<'a, T>),
|
|||||||
| ^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
|
| ^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
|
||||||
|
|
||||||
error[E0309]: the parameter type `T` may not live long enough
|
error[E0309]: the parameter type `T` may not live long enough
|
||||||
--> $DIR/regions-enum-not-wf.rs:35:1
|
--> $DIR/regions-enum-not-wf.rs:37:23
|
||||||
|
|
|
||||||
LL | enum RefDouble<'a, 'b, T> {
|
|
||||||
| ^ - help: consider adding an explicit lifetime bound...: `T: 'b`
|
|
||||||
| _|
|
|
||||||
| |
|
|
||||||
LL | | RefDoubleVariant1(&'a RequireOutlives<'b, T>)
|
|
||||||
LL | |
|
|
||||||
LL | | }
|
|
||||||
| |_^ ...so that the type `T` will meet its required lifetime bounds
|
|
||||||
|
|
||||||
error[E0309]: the parameter type `T` may not live long enough
|
|
||||||
--> $DIR/regions-enum-not-wf.rs:36:23
|
|
||||||
|
|
|
|
||||||
LL | enum RefDouble<'a, 'b, T> {
|
LL | enum RefDouble<'a, 'b, T> {
|
||||||
| - help: consider adding an explicit lifetime bound...: `T: 'b`
|
| - help: consider adding an explicit lifetime bound...: `T: 'b`
|
||||||
LL | RefDoubleVariant1(&'a RequireOutlives<'b, T>)
|
LL | RefDoubleVariant1(&'a RequireOutlives<'b, T>),
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
|
||||||
|
|
||||||
error: aborting due to 4 previous errors
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0309`.
|
For more information about this error, try `rustc --explain E0309`.
|
||||||
|
@ -6,7 +6,8 @@ trait Project<'a, 'b> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> Project<'a, 'b> for ()
|
impl<'a, 'b> Project<'a, 'b> for ()
|
||||||
where 'a: 'b
|
where
|
||||||
|
'a: 'b,
|
||||||
{
|
{
|
||||||
type Item = ();
|
type Item = ();
|
||||||
}
|
}
|
||||||
@ -14,16 +15,18 @@ impl<'a, 'b> Project<'a, 'b> for ()
|
|||||||
// No error here, we have 'a: 'b. We used to report an error here
|
// No error here, we have 'a: 'b. We used to report an error here
|
||||||
// though, see https://github.com/rust-lang/rust/issues/45937.
|
// though, see https://github.com/rust-lang/rust/issues/45937.
|
||||||
fn foo<'a: 'b, 'b>()
|
fn foo<'a: 'b, 'b>()
|
||||||
where <() as Project<'a, 'b>>::Item : Eq
|
where
|
||||||
|
<() as Project<'a, 'b>>::Item: Eq,
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
// Here we get an error: we need `'a: 'b`.
|
// Here we get an error: we need `'a: 'b`.
|
||||||
fn bar<'a, 'b>() //~ ERROR cannot infer
|
fn bar<'a, 'b>()
|
||||||
//~| ERROR cannot infer
|
//~^ ERROR cannot infer
|
||||||
//~| ERROR cannot infer
|
//~| ERROR cannot infer
|
||||||
where <() as Project<'a, 'b>>::Item : Eq
|
where
|
||||||
|
<() as Project<'a, 'b>>::Item: Eq,
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() { }
|
fn main() {}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
|
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
|
||||||
--> $DIR/regions-normalize-in-where-clause-list.rs:22:1
|
--> $DIR/regions-normalize-in-where-clause-list.rs:24:1
|
||||||
|
|
|
|
||||||
LL | / fn bar<'a, 'b>()
|
LL | / fn bar<'a, 'b>()
|
||||||
LL | |
|
LL | |
|
||||||
@ -7,18 +7,18 @@ LL | |
|
|||||||
LL | | where <() as Project<'a, 'b>>::Item : Eq
|
LL | | where <() as Project<'a, 'b>>::Item : Eq
|
||||||
| |____________________________________________^
|
| |____________________________________________^
|
||||||
|
|
|
|
||||||
note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 22:8...
|
note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 24:8...
|
||||||
--> $DIR/regions-normalize-in-where-clause-list.rs:22:8
|
--> $DIR/regions-normalize-in-where-clause-list.rs:24:8
|
||||||
|
|
|
|
||||||
LL | fn bar<'a, 'b>()
|
LL | fn bar<'a, 'b>()
|
||||||
| ^^
|
| ^^
|
||||||
note: ...but the lifetime must also be valid for the lifetime `'b` as defined on the function body at 22:12...
|
note: ...but the lifetime must also be valid for the lifetime `'b` as defined on the function body at 24:12...
|
||||||
--> $DIR/regions-normalize-in-where-clause-list.rs:22:12
|
--> $DIR/regions-normalize-in-where-clause-list.rs:24:12
|
||||||
|
|
|
|
||||||
LL | fn bar<'a, 'b>()
|
LL | fn bar<'a, 'b>()
|
||||||
| ^^
|
| ^^
|
||||||
note: ...so that the types are compatible
|
note: ...so that the types are compatible
|
||||||
--> $DIR/regions-normalize-in-where-clause-list.rs:22:1
|
--> $DIR/regions-normalize-in-where-clause-list.rs:24:1
|
||||||
|
|
|
|
||||||
LL | / fn bar<'a, 'b>()
|
LL | / fn bar<'a, 'b>()
|
||||||
LL | |
|
LL | |
|
||||||
@ -64,24 +64,24 @@ error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` d
|
|||||||
LL | fn bar<'a, 'b>()
|
LL | fn bar<'a, 'b>()
|
||||||
| ^^^
|
| ^^^
|
||||||
|
|
|
|
||||||
note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 22:8...
|
note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 24:8...
|
||||||
--> $DIR/regions-normalize-in-where-clause-list.rs:22:8
|
--> $DIR/regions-normalize-in-where-clause-list.rs:24:8
|
||||||
|
|
|
|
||||||
LL | fn bar<'a, 'b>()
|
LL | fn bar<'a, 'b>()
|
||||||
| ^^
|
| ^^
|
||||||
note: ...but the lifetime must also be valid for the lifetime `'b` as defined on the function body at 22:12...
|
note: ...but the lifetime must also be valid for the lifetime `'b` as defined on the function body at 24:12...
|
||||||
--> $DIR/regions-normalize-in-where-clause-list.rs:22:12
|
--> $DIR/regions-normalize-in-where-clause-list.rs:24:12
|
||||||
|
|
|
|
||||||
LL | fn bar<'a, 'b>()
|
LL | fn bar<'a, 'b>()
|
||||||
| ^^
|
| ^^
|
||||||
note: ...so that the types are compatible
|
note: ...so that the types are compatible
|
||||||
--> $DIR/regions-normalize-in-where-clause-list.rs:22:4
|
--> $DIR/regions-normalize-in-where-clause-list.rs:24:4
|
||||||
|
|
|
|
||||||
LL | fn bar<'a, 'b>()
|
LL | fn bar<'a, 'b>()
|
||||||
| ^^^
|
| ^^^
|
||||||
= note: expected `Project<'a, 'b>`
|
= note: expected `Project<'a, 'b>`
|
||||||
found `Project<'_, '_>`
|
found `Project<'_, '_>`
|
||||||
|
|
||||||
error: aborting due to 3 previous errors
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0495`.
|
For more information about this error, try `rustc --explain E0495`.
|
||||||
|
@ -5,17 +5,18 @@
|
|||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
trait Dummy<'a> {
|
trait Dummy<'a> {
|
||||||
type Out;
|
type Out;
|
||||||
}
|
}
|
||||||
impl<'a, T> Dummy<'a> for T
|
impl<'a, T> Dummy<'a> for T
|
||||||
where T: 'a
|
where
|
||||||
|
T: 'a,
|
||||||
{
|
{
|
||||||
type Out = ();
|
type Out = ();
|
||||||
}
|
}
|
||||||
type RequireOutlives<'a, T> = <T as Dummy<'a>>::Out;
|
type RequireOutlives<'a, T> = <T as Dummy<'a>>::Out;
|
||||||
|
|
||||||
enum Ref1<'a, T> {
|
enum Ref1<'a, T> {
|
||||||
Ref1Variant1(RequireOutlives<'a, T>) //~ ERROR the parameter type `T` may not live long enough
|
Ref1Variant1(RequireOutlives<'a, T>), //~ ERROR the parameter type `T` may not live long enough
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Ref2<'a, T> {
|
enum Ref2<'a, T> {
|
||||||
@ -23,18 +24,18 @@ enum Ref2<'a, T> {
|
|||||||
Ref2Variant2(isize, RequireOutlives<'a, T>), //~ ERROR the parameter type `T` may not live long enough
|
Ref2Variant2(isize, RequireOutlives<'a, T>), //~ ERROR the parameter type `T` may not live long enough
|
||||||
}
|
}
|
||||||
|
|
||||||
enum RefOk<'a, T:'a> {
|
enum RefOk<'a, T: 'a> {
|
||||||
RefOkVariant1(&'a T)
|
RefOkVariant1(&'a T),
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is now well formed. RFC 2093
|
// This is now well formed. RFC 2093
|
||||||
enum RefIndirect<'a, T> {
|
enum RefIndirect<'a, T> {
|
||||||
RefIndirectVariant1(isize, RefOk<'a,T>)
|
RefIndirectVariant1(isize, RefOk<'a, T>),
|
||||||
}
|
}
|
||||||
|
|
||||||
enum RefDouble<'a, 'b, T> { //~ ERROR the parameter type `T` may not live long enough [E0309]
|
enum RefDouble<'a, 'b, T> {
|
||||||
RefDoubleVariant1(&'a RequireOutlives<'b, T>)
|
RefDoubleVariant1(&'a RequireOutlives<'b, T>),
|
||||||
//~^ the parameter type `T` may not live long enough [E0309]
|
//~^ the parameter type `T` may not live long enough [E0309]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() { }
|
fn main() {}
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
error[E0309]: the parameter type `T` may not live long enough
|
error[E0309]: the parameter type `T` may not live long enough
|
||||||
--> $DIR/regions-enum-not-wf.rs:18:18
|
--> $DIR/regions-enum-not-wf.rs:19:18
|
||||||
|
|
|
|
||||||
LL | enum Ref1<'a, T> {
|
LL | enum Ref1<'a, T> {
|
||||||
| - help: consider adding an explicit lifetime bound...: `T: 'a`
|
| - help: consider adding an explicit lifetime bound...: `T: 'a`
|
||||||
LL | Ref1Variant1(RequireOutlives<'a, T>)
|
LL | Ref1Variant1(RequireOutlives<'a, T>),
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
|
| ^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
|
||||||
|
|
||||||
error[E0309]: the parameter type `T` may not live long enough
|
error[E0309]: the parameter type `T` may not live long enough
|
||||||
--> $DIR/regions-enum-not-wf.rs:23:25
|
--> $DIR/regions-enum-not-wf.rs:24:25
|
||||||
|
|
|
|
||||||
LL | enum Ref2<'a, T> {
|
LL | enum Ref2<'a, T> {
|
||||||
| - help: consider adding an explicit lifetime bound...: `T: 'a`
|
| - help: consider adding an explicit lifetime bound...: `T: 'a`
|
||||||
@ -16,25 +16,13 @@ LL | Ref2Variant2(isize, RequireOutlives<'a, T>),
|
|||||||
| ^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
|
| ^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
|
||||||
|
|
||||||
error[E0309]: the parameter type `T` may not live long enough
|
error[E0309]: the parameter type `T` may not live long enough
|
||||||
--> $DIR/regions-enum-not-wf.rs:35:1
|
--> $DIR/regions-enum-not-wf.rs:37:23
|
||||||
|
|
|
||||||
LL | enum RefDouble<'a, 'b, T> {
|
|
||||||
| ^ - help: consider adding an explicit lifetime bound...: `T: 'b`
|
|
||||||
| _|
|
|
||||||
| |
|
|
||||||
LL | | RefDoubleVariant1(&'a RequireOutlives<'b, T>)
|
|
||||||
LL | |
|
|
||||||
LL | | }
|
|
||||||
| |_^ ...so that the type `T` will meet its required lifetime bounds
|
|
||||||
|
|
||||||
error[E0309]: the parameter type `T` may not live long enough
|
|
||||||
--> $DIR/regions-enum-not-wf.rs:36:23
|
|
||||||
|
|
|
|
||||||
LL | enum RefDouble<'a, 'b, T> {
|
LL | enum RefDouble<'a, 'b, T> {
|
||||||
| - help: consider adding an explicit lifetime bound...: `T: 'b`
|
| - help: consider adding an explicit lifetime bound...: `T: 'b`
|
||||||
LL | RefDoubleVariant1(&'a RequireOutlives<'b, T>)
|
LL | RefDoubleVariant1(&'a RequireOutlives<'b, T>),
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
|
||||||
|
|
||||||
error: aborting due to 4 previous errors
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0309`.
|
For more information about this error, try `rustc --explain E0309`.
|
||||||
|
@ -24,7 +24,7 @@ struct Runtime<DB: Database> {
|
|||||||
_storage: Box<DB::Storage>,
|
_storage: Box<DB::Storage>,
|
||||||
}
|
}
|
||||||
struct SalsaStorage {
|
struct SalsaStorage {
|
||||||
_parse: <ParseQuery as Query<RootDatabase>>::Data, //~ ERROR overflow
|
_parse: <ParseQuery as Query<RootDatabase>>::Data,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Database for RootDatabase {
|
impl Database for RootDatabase {
|
||||||
@ -67,6 +67,7 @@ pub(crate) fn goto_implementation(db: &RootDatabase) -> u32 {
|
|||||||
// we used to fail to report an error here because we got the
|
// we used to fail to report an error here because we got the
|
||||||
// caching wrong.
|
// caching wrong.
|
||||||
SourceDatabase::parse(db);
|
SourceDatabase::parse(db);
|
||||||
|
//~^ ERROR overflow
|
||||||
22
|
22
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,10 +1,18 @@
|
|||||||
error[E0275]: overflow evaluating the requirement `RootDatabase: SourceDatabase`
|
error[E0275]: overflow evaluating the requirement `SalsaStorage: std::panic::RefUnwindSafe`
|
||||||
--> $DIR/cycle-cache-err-60010.rs:27:13
|
--> $DIR/cycle-cache-err-60010.rs:69:5
|
||||||
|
|
|
|
||||||
LL | _parse: <ParseQuery as Query<RootDatabase>>::Data,
|
LL | fn parse(&self) {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| --------------- required by `SourceDatabase::parse`
|
||||||
|
...
|
||||||
|
LL | SourceDatabase::parse(db);
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= note: required because of the requirements on the impl of `Query<RootDatabase>` for `ParseQuery`
|
= note: required because it appears within the type `*const SalsaStorage`
|
||||||
|
= note: required because it appears within the type `std::ptr::Unique<SalsaStorage>`
|
||||||
|
= note: required because it appears within the type `std::boxed::Box<SalsaStorage>`
|
||||||
|
= note: required because it appears within the type `Runtime<RootDatabase>`
|
||||||
|
= note: required because it appears within the type `RootDatabase`
|
||||||
|
= note: required because of the requirements on the impl of `SourceDatabase` for `RootDatabase`
|
||||||
|
|
||||||
error[E0275]: overflow evaluating the requirement `Runtime<RootDatabase>: RefUnwindSafe`
|
error[E0275]: overflow evaluating the requirement `Runtime<RootDatabase>: RefUnwindSafe`
|
||||||
--> $DIR/cycle-cache-err-60010.rs:31:20
|
--> $DIR/cycle-cache-err-60010.rs:31:20
|
||||||
|
Loading…
Reference in New Issue
Block a user