Rollup merge of #94869 - jackh726:gats_extended, r=compiler-errors
Add the generic_associated_types_extended feature Right now, this only ignore obligations that reference new placeholders in `poly_project_and_unify_type`. In the future, this might do other things, like allowing object-safe GATs. **This feature is *incomplete* and quite likely unsound. This is mostly just for testing out potential future APIs using a "relaxed" set of rules until we figure out *proper* rules.** Also drive by cleanup of adding a `ProjectAndUnifyResult` enum instead of using a `Result<Result<Option>>`. r? `@nikomatsakis`
This commit is contained in:
commit
e08ab08a2e
@ -400,6 +400,8 @@ declare_features! (
|
|||||||
(active, generic_arg_infer, "1.55.0", Some(85077), None),
|
(active, generic_arg_infer, "1.55.0", Some(85077), None),
|
||||||
/// Allows associated types to be generic, e.g., `type Foo<T>;` (RFC 1598).
|
/// Allows associated types to be generic, e.g., `type Foo<T>;` (RFC 1598).
|
||||||
(active, generic_associated_types, "1.23.0", Some(44265), None),
|
(active, generic_associated_types, "1.23.0", Some(44265), None),
|
||||||
|
/// An extension to the `generic_associated_types` feature, allowing incomplete features.
|
||||||
|
(incomplete, generic_associated_types_extended, "1.61.0", Some(95451), None),
|
||||||
/// Allows non-trivial generic constants which have to have wfness manually propagated to callers
|
/// Allows non-trivial generic constants which have to have wfness manually propagated to callers
|
||||||
(incomplete, generic_const_exprs, "1.56.0", Some(76560), None),
|
(incomplete, generic_const_exprs, "1.56.0", Some(76560), None),
|
||||||
/// Allows using `..X`, `..=X`, `...X`, and `X..` as a pattern.
|
/// Allows using `..X`, `..=X`, `...X`, and `X..` as a pattern.
|
||||||
|
@ -1379,3 +1379,50 @@ impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector {
|
|||||||
ControlFlow::CONTINUE
|
ControlFlow::CONTINUE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Finds the max universe present
|
||||||
|
pub struct MaxUniverse {
|
||||||
|
max_universe: ty::UniverseIndex,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MaxUniverse {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
MaxUniverse { max_universe: ty::UniverseIndex::ROOT }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn max_universe(self) -> ty::UniverseIndex {
|
||||||
|
self.max_universe
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> TypeVisitor<'tcx> for MaxUniverse {
|
||||||
|
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||||
|
if let ty::Placeholder(placeholder) = t.kind() {
|
||||||
|
self.max_universe = ty::UniverseIndex::from_u32(
|
||||||
|
self.max_universe.as_u32().max(placeholder.universe.as_u32()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
t.super_visit_with(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_const(&mut self, c: ty::consts::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||||
|
if let ty::ConstKind::Placeholder(placeholder) = c.val() {
|
||||||
|
self.max_universe = ty::UniverseIndex::from_u32(
|
||||||
|
self.max_universe.as_u32().max(placeholder.universe.as_u32()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
c.super_visit_with(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||||
|
if let ty::RePlaceholder(placeholder) = *r {
|
||||||
|
self.max_universe = ty::UniverseIndex::from_u32(
|
||||||
|
self.max_universe.as_u32().max(placeholder.universe.as_u32()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ControlFlow::CONTINUE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -722,6 +722,7 @@ symbols! {
|
|||||||
generators,
|
generators,
|
||||||
generic_arg_infer,
|
generic_arg_infer,
|
||||||
generic_associated_types,
|
generic_associated_types,
|
||||||
|
generic_associated_types_extended,
|
||||||
generic_const_exprs,
|
generic_const_exprs,
|
||||||
generic_param_attrs,
|
generic_param_attrs,
|
||||||
get_context,
|
get_context,
|
||||||
|
@ -5,6 +5,7 @@ use super::*;
|
|||||||
|
|
||||||
use crate::infer::region_constraints::{Constraint, RegionConstraintData};
|
use crate::infer::region_constraints::{Constraint, RegionConstraintData};
|
||||||
use crate::infer::InferCtxt;
|
use crate::infer::InferCtxt;
|
||||||
|
use crate::traits::project::ProjectAndUnifyResult;
|
||||||
use rustc_middle::ty::fold::TypeFolder;
|
use rustc_middle::ty::fold::TypeFolder;
|
||||||
use rustc_middle::ty::{Region, RegionVid, Term};
|
use rustc_middle::ty::{Region, RegionVid, Term};
|
||||||
|
|
||||||
@ -751,7 +752,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
|
|||||||
debug!("Projecting and unifying projection predicate {:?}", predicate);
|
debug!("Projecting and unifying projection predicate {:?}", predicate);
|
||||||
|
|
||||||
match project::poly_project_and_unify_type(select, &obligation.with(p)) {
|
match project::poly_project_and_unify_type(select, &obligation.with(p)) {
|
||||||
Err(e) => {
|
ProjectAndUnifyResult::MismatchedProjectionTypes(e) => {
|
||||||
debug!(
|
debug!(
|
||||||
"evaluate_nested_obligations: Unable to unify predicate \
|
"evaluate_nested_obligations: Unable to unify predicate \
|
||||||
'{:?}' '{:?}', bailing out",
|
'{:?}' '{:?}', bailing out",
|
||||||
@ -759,11 +760,11 @@ impl<'tcx> AutoTraitFinder<'tcx> {
|
|||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Ok(Err(project::InProgress)) => {
|
ProjectAndUnifyResult::Recursive => {
|
||||||
debug!("evaluate_nested_obligations: recursive projection predicate");
|
debug!("evaluate_nested_obligations: recursive projection predicate");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Ok(Ok(Some(v))) => {
|
ProjectAndUnifyResult::Holds(v) => {
|
||||||
// We only care about sub-obligations
|
// We only care about sub-obligations
|
||||||
// when we started out trying to unify
|
// when we started out trying to unify
|
||||||
// some inference variables. See the comment above
|
// some inference variables. See the comment above
|
||||||
@ -782,7 +783,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(Ok(None)) => {
|
ProjectAndUnifyResult::FailedNormalization => {
|
||||||
// It's ok not to make progress when have no inference variables -
|
// It's ok not to make progress when have no inference variables -
|
||||||
// in that case, we were only performing unification to check if an
|
// in that case, we were only performing unification to check if an
|
||||||
// error occurred (which would indicate that it's impossible for our
|
// error occurred (which would indicate that it's impossible for our
|
||||||
|
@ -14,7 +14,7 @@ use rustc_middle::ty::{self, Binder, Const, Ty, TypeFoldable};
|
|||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
use super::const_evaluatable;
|
use super::const_evaluatable;
|
||||||
use super::project;
|
use super::project::{self, ProjectAndUnifyResult};
|
||||||
use super::select::SelectionContext;
|
use super::select::SelectionContext;
|
||||||
use super::wf;
|
use super::wf;
|
||||||
use super::CodeAmbiguity;
|
use super::CodeAmbiguity;
|
||||||
@ -753,8 +753,8 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
match project::poly_project_and_unify_type(self.selcx, &project_obligation) {
|
match project::poly_project_and_unify_type(self.selcx, &project_obligation) {
|
||||||
Ok(Ok(Some(os))) => ProcessResult::Changed(mk_pending(os)),
|
ProjectAndUnifyResult::Holds(os) => ProcessResult::Changed(mk_pending(os)),
|
||||||
Ok(Ok(None)) => {
|
ProjectAndUnifyResult::FailedNormalization => {
|
||||||
stalled_on.clear();
|
stalled_on.clear();
|
||||||
stalled_on.extend(substs_infer_vars(
|
stalled_on.extend(substs_infer_vars(
|
||||||
self.selcx,
|
self.selcx,
|
||||||
@ -763,10 +763,12 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
|
|||||||
ProcessResult::Unchanged
|
ProcessResult::Unchanged
|
||||||
}
|
}
|
||||||
// Let the caller handle the recursion
|
// Let the caller handle the recursion
|
||||||
Ok(Err(project::InProgress)) => ProcessResult::Changed(mk_pending(vec![
|
ProjectAndUnifyResult::Recursive => ProcessResult::Changed(mk_pending(vec![
|
||||||
project_obligation.with(project_obligation.predicate.to_predicate(tcx)),
|
project_obligation.with(project_obligation.predicate.to_predicate(tcx)),
|
||||||
])),
|
])),
|
||||||
Err(e) => ProcessResult::Error(CodeProjectionError(e)),
|
ProjectAndUnifyResult::MismatchedProjectionTypes(e) => {
|
||||||
|
ProcessResult::Error(CodeProjectionError(e))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ use rustc_hir::def_id::DefId;
|
|||||||
use rustc_hir::lang_items::LangItem;
|
use rustc_hir::lang_items::LangItem;
|
||||||
use rustc_infer::infer::resolve::OpportunisticRegionResolver;
|
use rustc_infer::infer::resolve::OpportunisticRegionResolver;
|
||||||
use rustc_middle::traits::select::OverflowError;
|
use rustc_middle::traits::select::OverflowError;
|
||||||
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
|
use rustc_middle::ty::fold::{MaxUniverse, TypeFoldable, TypeFolder};
|
||||||
use rustc_middle::ty::subst::Subst;
|
use rustc_middle::ty::subst::Subst;
|
||||||
use rustc_middle::ty::{self, Term, ToPredicate, Ty, TyCtxt};
|
use rustc_middle::ty::{self, Term, ToPredicate, Ty, TyCtxt};
|
||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
||||||
@ -144,6 +144,18 @@ impl<'tcx> ProjectionCandidateSet<'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Takes the place of a
|
||||||
|
/// Result<
|
||||||
|
/// Result<Option<Vec<PredicateObligation<'tcx>>>, InProgress>,
|
||||||
|
/// MismatchedProjectionTypes<'tcx>,
|
||||||
|
/// >
|
||||||
|
pub(super) enum ProjectAndUnifyResult<'tcx> {
|
||||||
|
Holds(Vec<PredicateObligation<'tcx>>),
|
||||||
|
FailedNormalization,
|
||||||
|
Recursive,
|
||||||
|
MismatchedProjectionTypes(MismatchedProjectionTypes<'tcx>),
|
||||||
|
}
|
||||||
|
|
||||||
/// Evaluates constraints of the form:
|
/// Evaluates constraints of the form:
|
||||||
///
|
///
|
||||||
/// for<...> <T as Trait>::U == V
|
/// for<...> <T as Trait>::U == V
|
||||||
@ -167,19 +179,47 @@ impl<'tcx> ProjectionCandidateSet<'tcx> {
|
|||||||
pub(super) fn poly_project_and_unify_type<'cx, 'tcx>(
|
pub(super) fn poly_project_and_unify_type<'cx, 'tcx>(
|
||||||
selcx: &mut SelectionContext<'cx, 'tcx>,
|
selcx: &mut SelectionContext<'cx, 'tcx>,
|
||||||
obligation: &PolyProjectionObligation<'tcx>,
|
obligation: &PolyProjectionObligation<'tcx>,
|
||||||
) -> Result<
|
) -> ProjectAndUnifyResult<'tcx> {
|
||||||
Result<Option<Vec<PredicateObligation<'tcx>>>, InProgress>,
|
|
||||||
MismatchedProjectionTypes<'tcx>,
|
|
||||||
> {
|
|
||||||
let infcx = selcx.infcx();
|
let infcx = selcx.infcx();
|
||||||
infcx.commit_if_ok(|_snapshot| {
|
let r = infcx.commit_if_ok(|_snapshot| {
|
||||||
|
let old_universe = infcx.universe();
|
||||||
let placeholder_predicate =
|
let placeholder_predicate =
|
||||||
infcx.replace_bound_vars_with_placeholders(obligation.predicate);
|
infcx.replace_bound_vars_with_placeholders(obligation.predicate);
|
||||||
|
let new_universe = infcx.universe();
|
||||||
|
|
||||||
let placeholder_obligation = obligation.with(placeholder_predicate);
|
let placeholder_obligation = obligation.with(placeholder_predicate);
|
||||||
let result = project_and_unify_type(selcx, &placeholder_obligation)?;
|
match project_and_unify_type(selcx, &placeholder_obligation) {
|
||||||
Ok(result)
|
ProjectAndUnifyResult::MismatchedProjectionTypes(e) => Err(e),
|
||||||
})
|
ProjectAndUnifyResult::Holds(obligations)
|
||||||
|
if old_universe != new_universe
|
||||||
|
&& selcx.tcx().features().generic_associated_types_extended =>
|
||||||
|
{
|
||||||
|
// If the `generic_associated_types_extended` feature is active, then we ignore any
|
||||||
|
// obligations references lifetimes from any universe greater than or equal to the
|
||||||
|
// universe just created. Otherwise, we can end up with something like `for<'a> I: 'a`,
|
||||||
|
// which isn't quite what we want. Ideally, we want either an implied
|
||||||
|
// `for<'a where I: 'a> I: 'a` or we want to "lazily" check these hold when we
|
||||||
|
// substitute concrete regions. There is design work to be done here; until then,
|
||||||
|
// however, this allows experimenting potential GAT features without running into
|
||||||
|
// well-formedness issues.
|
||||||
|
let new_obligations = obligations
|
||||||
|
.into_iter()
|
||||||
|
.filter(|obligation| {
|
||||||
|
let mut visitor = MaxUniverse::new();
|
||||||
|
obligation.predicate.visit_with(&mut visitor);
|
||||||
|
visitor.max_universe() < new_universe
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
Ok(ProjectAndUnifyResult::Holds(new_obligations))
|
||||||
|
}
|
||||||
|
other => Ok(other),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
match r {
|
||||||
|
Ok(inner) => inner,
|
||||||
|
Err(err) => ProjectAndUnifyResult::MismatchedProjectionTypes(err),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluates constraints of the form:
|
/// Evaluates constraints of the form:
|
||||||
@ -189,15 +229,11 @@ pub(super) fn poly_project_and_unify_type<'cx, 'tcx>(
|
|||||||
/// If successful, this may result in additional obligations.
|
/// If successful, this may result in additional obligations.
|
||||||
///
|
///
|
||||||
/// See [poly_project_and_unify_type] for an explanation of the return value.
|
/// See [poly_project_and_unify_type] for an explanation of the return value.
|
||||||
|
#[tracing::instrument(level = "debug", skip(selcx))]
|
||||||
fn project_and_unify_type<'cx, 'tcx>(
|
fn project_and_unify_type<'cx, 'tcx>(
|
||||||
selcx: &mut SelectionContext<'cx, 'tcx>,
|
selcx: &mut SelectionContext<'cx, 'tcx>,
|
||||||
obligation: &ProjectionObligation<'tcx>,
|
obligation: &ProjectionObligation<'tcx>,
|
||||||
) -> Result<
|
) -> ProjectAndUnifyResult<'tcx> {
|
||||||
Result<Option<Vec<PredicateObligation<'tcx>>>, InProgress>,
|
|
||||||
MismatchedProjectionTypes<'tcx>,
|
|
||||||
> {
|
|
||||||
debug!(?obligation, "project_and_unify_type");
|
|
||||||
|
|
||||||
let mut obligations = vec![];
|
let mut obligations = vec![];
|
||||||
|
|
||||||
let infcx = selcx.infcx();
|
let infcx = selcx.infcx();
|
||||||
@ -210,8 +246,8 @@ fn project_and_unify_type<'cx, 'tcx>(
|
|||||||
&mut obligations,
|
&mut obligations,
|
||||||
) {
|
) {
|
||||||
Ok(Some(n)) => n,
|
Ok(Some(n)) => n,
|
||||||
Ok(None) => return Ok(Ok(None)),
|
Ok(None) => return ProjectAndUnifyResult::FailedNormalization,
|
||||||
Err(InProgress) => return Ok(Err(InProgress)),
|
Err(InProgress) => return ProjectAndUnifyResult::Recursive,
|
||||||
};
|
};
|
||||||
debug!(?normalized, ?obligations, "project_and_unify_type result");
|
debug!(?normalized, ?obligations, "project_and_unify_type result");
|
||||||
let actual = obligation.predicate.term;
|
let actual = obligation.predicate.term;
|
||||||
@ -231,11 +267,11 @@ fn project_and_unify_type<'cx, 'tcx>(
|
|||||||
match infcx.at(&obligation.cause, obligation.param_env).eq(normalized, actual) {
|
match infcx.at(&obligation.cause, obligation.param_env).eq(normalized, actual) {
|
||||||
Ok(InferOk { obligations: inferred_obligations, value: () }) => {
|
Ok(InferOk { obligations: inferred_obligations, value: () }) => {
|
||||||
obligations.extend(inferred_obligations);
|
obligations.extend(inferred_obligations);
|
||||||
Ok(Ok(Some(obligations)))
|
ProjectAndUnifyResult::Holds(obligations)
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
debug!("project_and_unify_type: equating types encountered error {:?}", err);
|
debug!("equating types encountered error {:?}", err);
|
||||||
Err(MismatchedProjectionTypes { err })
|
ProjectAndUnifyResult::MismatchedProjectionTypes(MismatchedProjectionTypes { err })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ use super::{
|
|||||||
|
|
||||||
use crate::infer::{InferCtxt, InferOk, TypeFreshener};
|
use crate::infer::{InferCtxt, InferOk, TypeFreshener};
|
||||||
use crate::traits::error_reporting::InferCtxtExt;
|
use crate::traits::error_reporting::InferCtxtExt;
|
||||||
|
use crate::traits::project::ProjectAndUnifyResult;
|
||||||
use crate::traits::project::ProjectionCacheKeyExt;
|
use crate::traits::project::ProjectionCacheKeyExt;
|
||||||
use crate::traits::ProjectionCacheKey;
|
use crate::traits::ProjectionCacheKey;
|
||||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||||
@ -525,7 +526,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
let data = bound_predicate.rebind(data);
|
let data = bound_predicate.rebind(data);
|
||||||
let project_obligation = obligation.with(data);
|
let project_obligation = obligation.with(data);
|
||||||
match project::poly_project_and_unify_type(self, &project_obligation) {
|
match project::poly_project_and_unify_type(self, &project_obligation) {
|
||||||
Ok(Ok(Some(mut subobligations))) => {
|
ProjectAndUnifyResult::Holds(mut subobligations) => {
|
||||||
'compute_res: {
|
'compute_res: {
|
||||||
// If we've previously marked this projection as 'complete', then
|
// If we've previously marked this projection as 'complete', then
|
||||||
// use the final cached result (either `EvaluatedToOk` or
|
// use the final cached result (either `EvaluatedToOk` or
|
||||||
@ -573,9 +574,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
res
|
res
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(Ok(None)) => Ok(EvaluatedToAmbig),
|
ProjectAndUnifyResult::FailedNormalization => Ok(EvaluatedToAmbig),
|
||||||
Ok(Err(project::InProgress)) => Ok(EvaluatedToRecur),
|
ProjectAndUnifyResult::Recursive => Ok(EvaluatedToRecur),
|
||||||
Err(_) => Ok(EvaluatedToErr),
|
ProjectAndUnifyResult::MismatchedProjectionTypes(_) => Ok(EvaluatedToErr),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,6 @@
|
|||||||
|
#![feature(generic_associated_types)]
|
||||||
|
|
||||||
|
// This feature doesn't *currently* fire on any specific code; it's just a
|
||||||
|
// behavior change. Future changes might.
|
||||||
|
#[rustc_error] //~ the
|
||||||
|
fn main() {}
|
@ -0,0 +1,11 @@
|
|||||||
|
error[E0658]: the `#[rustc_error]` attribute is just used for rustc unit tests and will never be stable
|
||||||
|
--> $DIR/feature-gate-generic_associated_types_extended.rs:5:1
|
||||||
|
|
|
||||||
|
LL | #[rustc_error]
|
||||||
|
| ^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0658`.
|
@ -0,0 +1,12 @@
|
|||||||
|
error[E0276]: impl has stricter requirements than trait
|
||||||
|
--> $DIR/lending_iterator.rs:14:45
|
||||||
|
|
|
||||||
|
LL | fn from_iter<T: for<'x> LendingIterator<Item<'x> = A>>(iter: T) -> Self;
|
||||||
|
| ------------------------------------------------------------------------ definition of `from_iter` from trait
|
||||||
|
...
|
||||||
|
LL | fn from_iter<I: for<'x> LendingIterator<Item<'x> = A>>(mut iter: I) -> Self {
|
||||||
|
| ^^^^^^^^^^^^ impl has extra requirement `I: 'x`
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0276`.
|
@ -0,0 +1,26 @@
|
|||||||
|
error[E0276]: impl has stricter requirements than trait
|
||||||
|
--> $DIR/lending_iterator.rs:14:45
|
||||||
|
|
|
||||||
|
LL | fn from_iter<T: for<'x> LendingIterator<Item<'x> = A>>(iter: T) -> Self;
|
||||||
|
| ------------------------------------------------------------------------ definition of `from_iter` from trait
|
||||||
|
...
|
||||||
|
LL | fn from_iter<I: for<'x> LendingIterator<Item<'x> = A>>(mut iter: I) -> Self {
|
||||||
|
| ^^^^^^^^^^^^ impl has extra requirement `I: 'x`
|
||||||
|
|
||||||
|
error[E0311]: the parameter type `Self` may not live long enough
|
||||||
|
--> $DIR/lending_iterator.rs:35:9
|
||||||
|
|
|
||||||
|
LL | <B as FromLendingIterator<A>>::from_iter(self)
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= help: consider adding an explicit lifetime bound `Self: 'a`...
|
||||||
|
= note: ...so that the type `Self` will meet its required lifetime bounds...
|
||||||
|
note: ...that is required by this bound
|
||||||
|
--> $DIR/lending_iterator.rs:10:45
|
||||||
|
|
|
||||||
|
LL | fn from_iter<T: for<'x> LendingIterator<Item<'x> = A>>(iter: T) -> Self;
|
||||||
|
| ^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0276`.
|
@ -0,0 +1,40 @@
|
|||||||
|
// revisions: base extended
|
||||||
|
//[base] check-fail
|
||||||
|
//[extended] check-pass
|
||||||
|
|
||||||
|
#![feature(generic_associated_types)]
|
||||||
|
#![cfg_attr(extended, feature(generic_associated_types_extended))]
|
||||||
|
#![cfg_attr(extended, allow(incomplete_features))]
|
||||||
|
|
||||||
|
pub trait FromLendingIterator<A>: Sized {
|
||||||
|
fn from_iter<T: for<'x> LendingIterator<Item<'x> = A>>(iter: T) -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A> FromLendingIterator<A> for Vec<A> {
|
||||||
|
fn from_iter<I: for<'x> LendingIterator<Item<'x> = A>>(mut iter: I) -> Self {
|
||||||
|
//[base]~^ impl has stricter
|
||||||
|
let mut v = vec![];
|
||||||
|
while let Some(item) = iter.next() {
|
||||||
|
v.push(item);
|
||||||
|
}
|
||||||
|
v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait LendingIterator {
|
||||||
|
type Item<'z>
|
||||||
|
where
|
||||||
|
Self: 'z;
|
||||||
|
fn next(&mut self) -> Option<Self::Item<'_>>;
|
||||||
|
|
||||||
|
fn collect<A, B: FromLendingIterator<A>>(self) -> B
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
Self: for<'q> LendingIterator<Item<'q> = A>,
|
||||||
|
{
|
||||||
|
<B as FromLendingIterator<A>>::from_iter(self)
|
||||||
|
//[base]~^ the parameter type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
@ -0,0 +1,12 @@
|
|||||||
|
error[E0276]: impl has stricter requirements than trait
|
||||||
|
--> $DIR/lending_iterator_2.rs:14:45
|
||||||
|
|
|
||||||
|
LL | fn from_iter<T: for<'x> LendingIterator<Item<'x> = A>>(iter: T) -> Self;
|
||||||
|
| ------------------------------------------------------------------------ definition of `from_iter` from trait
|
||||||
|
...
|
||||||
|
LL | fn from_iter<I: for<'x> LendingIterator<Item<'x> = A>>(mut iter: I) -> Self {
|
||||||
|
| ^^^^^^^^^^^^ impl has extra requirement `I: 'x`
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0276`.
|
@ -0,0 +1,31 @@
|
|||||||
|
// revisions: base extended
|
||||||
|
//[base] check-fail
|
||||||
|
//[extended] check-pass
|
||||||
|
|
||||||
|
#![feature(generic_associated_types)]
|
||||||
|
#![cfg_attr(extended, feature(generic_associated_types_extended))]
|
||||||
|
#![cfg_attr(extended, allow(incomplete_features))]
|
||||||
|
|
||||||
|
pub trait FromLendingIterator<A>: Sized {
|
||||||
|
fn from_iter<T: for<'x> LendingIterator<Item<'x> = A>>(iter: T) -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A> FromLendingIterator<A> for Vec<A> {
|
||||||
|
fn from_iter<I: for<'x> LendingIterator<Item<'x> = A>>(mut iter: I) -> Self {
|
||||||
|
//[base]~^ impl has stricter
|
||||||
|
let mut v = vec![];
|
||||||
|
while let Some(item) = iter.next() {
|
||||||
|
v.push(item);
|
||||||
|
}
|
||||||
|
v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait LendingIterator {
|
||||||
|
type Item<'a>
|
||||||
|
where
|
||||||
|
Self: 'a;
|
||||||
|
fn next(&mut self) -> Option<Self::Item<'_>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
Loading…
x
Reference in New Issue
Block a user