Skip to content

Commit

Permalink
Add the generic_associated_types_extended feature
Browse files Browse the repository at this point in the history
  • Loading branch information
jackh726 committed Mar 12, 2022
1 parent 335ffbf commit a0ef4bf
Show file tree
Hide file tree
Showing 14 changed files with 251 additions and 42 deletions.
20 changes: 10 additions & 10 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ dependencies = [
"cargo-test-macro",
"cargo-test-support",
"cargo-util",
"clap 3.1.1",
"clap 3.1.6",
"crates-io",
"crossbeam-utils",
"curl",
Expand Down Expand Up @@ -598,17 +598,17 @@ dependencies = [

[[package]]
name = "clap"
version = "3.1.1"
version = "3.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d76c22c9b9b215eeb8d016ad3a90417bd13cb24cf8142756e6472445876cab7"
checksum = "d8c93436c21e4698bacadf42917db28b23017027a4deccb35dbe47a7e7840123"
dependencies = [
"atty",
"bitflags",
"indexmap",
"os_str_bytes",
"strsim 0.10.0",
"termcolor",
"textwrap 0.14.2",
"textwrap 0.15.0",
]

[[package]]
Expand Down Expand Up @@ -1502,9 +1502,9 @@ dependencies = [

[[package]]
name = "git2"
version = "0.14.1"
version = "0.14.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e7d3b96ec1fcaa8431cf04a4f1ef5caafe58d5cf7bcc31f09c1626adddb0ffe"
checksum = "3826a6e0e2215d7a41c2bfc7c9244123969273f3476b939a226aac0ab56e9e3c"
dependencies = [
"bitflags",
"libc",
Expand Down Expand Up @@ -1974,9 +1974,9 @@ dependencies = [

[[package]]
name = "libgit2-sys"
version = "0.13.1+1.4.2"
version = "0.13.2+1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43e598aa7a4faedf1ea1b4608f582b06f0f40211eec551b7ef36019ae3f62def"
checksum = "3a42de9a51a5c12e00fc0e4ca6bc2ea43582fc6418488e8f615e905d886f258b"
dependencies = [
"cc",
"libc",
Expand Down Expand Up @@ -5024,9 +5024,9 @@ dependencies = [

[[package]]
name = "textwrap"
version = "0.14.2"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80"
checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb"

[[package]]
name = "thiserror"
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_feature/src/active.rs
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,8 @@ declare_features! (
(active, generic_arg_infer, "1.55.0", Some(85077), None),
/// Allows associated types to be generic, e.g., `type Foo<T>;` (RFC 1598).
(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(44265), None),
/// Allows non-trivial generic constants which have to have wfness manually propagated to callers
(incomplete, generic_const_exprs, "1.56.0", Some(76560), None),
/// Allows using `..X`, `..=X`, `...X`, and `X..` as a pattern.
Expand Down
47 changes: 47 additions & 0 deletions compiler/rustc_middle/src/ty/fold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1375,3 +1375,50 @@ impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector {
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
}
}
1 change: 1 addition & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -723,6 +723,7 @@ symbols! {
generators,
generic_arg_infer,
generic_associated_types,
generic_associated_types_extended,
generic_const_exprs,
generic_param_attrs,
get_context,
Expand Down
9 changes: 5 additions & 4 deletions compiler/rustc_trait_selection/src/traits/auto_trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand Down Expand Up @@ -733,19 +734,19 @@ 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",
ty, e
);
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
Expand All @@ -764,7 +765,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
Expand Down
12 changes: 7 additions & 5 deletions compiler/rustc_trait_selection/src/traits/fulfill.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,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;
Expand Down Expand Up @@ -752,8 +752,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,
Expand All @@ -762,10 +762,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))
}
}
}
}
Expand Down
67 changes: 48 additions & 19 deletions compiler/rustc_trait_selection/src/traits/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ use rustc_hir::def::DefKind;
use rustc_hir::def_id::DefId;
use rustc_hir::lang_items::LangItem;
use rustc_infer::infer::resolve::OpportunisticRegionResolver;
use rustc_middle::ty::fold::MaxUniverse;
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
use rustc_middle::ty::subst::Subst;
use rustc_middle::ty::{self, Term, ToPredicate, Ty, TyCtxt};
Expand Down Expand Up @@ -143,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
Expand All @@ -166,19 +179,39 @@ 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 =>
{
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:
Expand All @@ -188,15 +221,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();
Expand All @@ -209,8 +238,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
Expand All @@ -219,11 +248,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 })
}
}
}
Expand Down
9 changes: 5 additions & 4 deletions compiler/rustc_trait_selection/src/traits/select/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ use super::{ObligationCause, PredicateObligation, TraitObligation};

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};
Expand Down Expand Up @@ -551,7 +552,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', thne
// use the final cached result (either `EvaluatedToOk` or
Expand Down Expand Up @@ -599,9 +600,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),
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -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() {}
Original file line number Diff line number Diff line change
@@ -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`.
Loading

0 comments on commit a0ef4bf

Please sign in to comment.