Add the generic_associated_types_extended feature
This commit is contained in:
parent
5e1d19d307
commit
4e570a68a1
14 changed files with 261 additions and 33 deletions
|
@ -5,6 +5,7 @@ use super::*;
|
|||
|
||||
use crate::infer::region_constraints::{Constraint, RegionConstraintData};
|
||||
use crate::infer::InferCtxt;
|
||||
use crate::traits::project::ProjectAndUnifyResult;
|
||||
use rustc_middle::ty::fold::TypeFolder;
|
||||
use rustc_middle::ty::{Region, RegionVid, Term};
|
||||
|
||||
|
@ -751,7 +752,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
|
|||
debug!("Projecting and unifying projection predicate {:?}", predicate);
|
||||
|
||||
match project::poly_project_and_unify_type(select, &obligation.with(p)) {
|
||||
Err(e) => {
|
||||
ProjectAndUnifyResult::MismatchedProjectionTypes(e) => {
|
||||
debug!(
|
||||
"evaluate_nested_obligations: Unable to unify predicate \
|
||||
'{:?}' '{:?}', bailing out",
|
||||
|
@ -759,11 +760,11 @@ impl<'tcx> AutoTraitFinder<'tcx> {
|
|||
);
|
||||
return false;
|
||||
}
|
||||
Ok(Err(project::InProgress)) => {
|
||||
ProjectAndUnifyResult::Recursive => {
|
||||
debug!("evaluate_nested_obligations: recursive projection predicate");
|
||||
return false;
|
||||
}
|
||||
Ok(Ok(Some(v))) => {
|
||||
ProjectAndUnifyResult::Holds(v) => {
|
||||
// We only care about sub-obligations
|
||||
// when we started out trying to unify
|
||||
// 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 -
|
||||
// in that case, we were only performing unifcation to check if an
|
||||
// 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 super::const_evaluatable;
|
||||
use super::project;
|
||||
use super::project::{self, ProjectAndUnifyResult};
|
||||
use super::select::SelectionContext;
|
||||
use super::wf;
|
||||
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) {
|
||||
Ok(Ok(Some(os))) => ProcessResult::Changed(mk_pending(os)),
|
||||
Ok(Ok(None)) => {
|
||||
ProjectAndUnifyResult::Holds(os) => ProcessResult::Changed(mk_pending(os)),
|
||||
ProjectAndUnifyResult::FailedNormalization => {
|
||||
stalled_on.clear();
|
||||
stalled_on.extend(substs_infer_vars(
|
||||
self.selcx,
|
||||
|
@ -763,10 +763,12 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
|
|||
ProcessResult::Unchanged
|
||||
}
|
||||
// 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)),
|
||||
])),
|
||||
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_infer::infer::resolve::OpportunisticRegionResolver;
|
||||
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::{self, Term, ToPredicate, Ty, TyCtxt};
|
||||
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:
|
||||
///
|
||||
/// for<...> <T as Trait>::U == V
|
||||
|
@ -167,19 +179,47 @@ impl<'tcx> ProjectionCandidateSet<'tcx> {
|
|||
pub(super) fn poly_project_and_unify_type<'cx, 'tcx>(
|
||||
selcx: &mut SelectionContext<'cx, 'tcx>,
|
||||
obligation: &PolyProjectionObligation<'tcx>,
|
||||
) -> Result<
|
||||
Result<Option<Vec<PredicateObligation<'tcx>>>, InProgress>,
|
||||
MismatchedProjectionTypes<'tcx>,
|
||||
> {
|
||||
) -> ProjectAndUnifyResult<'tcx> {
|
||||
let infcx = selcx.infcx();
|
||||
infcx.commit_if_ok(|_snapshot| {
|
||||
let r = infcx.commit_if_ok(|_snapshot| {
|
||||
let old_universe = infcx.universe();
|
||||
let placeholder_predicate =
|
||||
infcx.replace_bound_vars_with_placeholders(obligation.predicate);
|
||||
let new_universe = infcx.universe();
|
||||
|
||||
let placeholder_obligation = obligation.with(placeholder_predicate);
|
||||
let result = project_and_unify_type(selcx, &placeholder_obligation)?;
|
||||
Ok(result)
|
||||
})
|
||||
match project_and_unify_type(selcx, &placeholder_obligation) {
|
||||
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:
|
||||
|
@ -189,15 +229,11 @@ pub(super) fn poly_project_and_unify_type<'cx, 'tcx>(
|
|||
/// If successful, this may result in additional obligations.
|
||||
///
|
||||
/// 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>(
|
||||
selcx: &mut SelectionContext<'cx, 'tcx>,
|
||||
obligation: &ProjectionObligation<'tcx>,
|
||||
) -> Result<
|
||||
Result<Option<Vec<PredicateObligation<'tcx>>>, InProgress>,
|
||||
MismatchedProjectionTypes<'tcx>,
|
||||
> {
|
||||
debug!(?obligation, "project_and_unify_type");
|
||||
|
||||
) -> ProjectAndUnifyResult<'tcx> {
|
||||
let mut obligations = vec![];
|
||||
|
||||
let infcx = selcx.infcx();
|
||||
|
@ -210,8 +246,8 @@ fn project_and_unify_type<'cx, 'tcx>(
|
|||
&mut obligations,
|
||||
) {
|
||||
Ok(Some(n)) => n,
|
||||
Ok(None) => return Ok(Ok(None)),
|
||||
Err(InProgress) => return Ok(Err(InProgress)),
|
||||
Ok(None) => return ProjectAndUnifyResult::FailedNormalization,
|
||||
Err(InProgress) => return ProjectAndUnifyResult::Recursive,
|
||||
};
|
||||
debug!(?normalized, ?obligations, "project_and_unify_type result");
|
||||
match infcx
|
||||
|
@ -220,11 +256,11 @@ fn project_and_unify_type<'cx, 'tcx>(
|
|||
{
|
||||
Ok(InferOk { obligations: inferred_obligations, value: () }) => {
|
||||
obligations.extend(inferred_obligations);
|
||||
Ok(Ok(Some(obligations)))
|
||||
ProjectAndUnifyResult::Holds(obligations)
|
||||
}
|
||||
Err(err) => {
|
||||
debug!("project_and_unify_type: equating types encountered error {:?}", err);
|
||||
Err(MismatchedProjectionTypes { err })
|
||||
debug!("equating types encountered error {:?}", err);
|
||||
ProjectAndUnifyResult::MismatchedProjectionTypes(MismatchedProjectionTypes { err })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ use super::{
|
|||
|
||||
use crate::infer::{InferCtxt, InferOk, TypeFreshener};
|
||||
use crate::traits::error_reporting::InferCtxtExt;
|
||||
use crate::traits::project::ProjectAndUnifyResult;
|
||||
use crate::traits::project::ProjectionCacheKeyExt;
|
||||
use crate::traits::ProjectionCacheKey;
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
|
@ -524,7 +525,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
let data = bound_predicate.rebind(data);
|
||||
let project_obligation = obligation.with(data);
|
||||
match project::poly_project_and_unify_type(self, &project_obligation) {
|
||||
Ok(Ok(Some(mut subobligations))) => {
|
||||
ProjectAndUnifyResult::Holds(mut subobligations) => {
|
||||
'compute_res: {
|
||||
// If we've previously marked this projection as 'complete', then
|
||||
// use the final cached result (either `EvaluatedToOk` or
|
||||
|
@ -572,9 +573,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
res
|
||||
}
|
||||
}
|
||||
Ok(Ok(None)) => Ok(EvaluatedToAmbig),
|
||||
Ok(Err(project::InProgress)) => Ok(EvaluatedToRecur),
|
||||
Err(_) => Ok(EvaluatedToErr),
|
||||
ProjectAndUnifyResult::FailedNormalization => Ok(EvaluatedToAmbig),
|
||||
ProjectAndUnifyResult::Recursive => Ok(EvaluatedToRecur),
|
||||
ProjectAndUnifyResult::MismatchedProjectionTypes(_) => Ok(EvaluatedToErr),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue