Skip to content

Commit 21d4e06

Browse files
committed
Mode ProjectionCache to its own module.
1 parent 796ca64 commit 21d4e06

File tree

6 files changed

+198
-184
lines changed

6 files changed

+198
-184
lines changed

src/librustc_infer/traits/mod.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ pub mod misc;
1313
mod object_safety;
1414
mod on_unimplemented;
1515
mod project;
16+
mod projection_cache;
1617
pub mod query;
1718
mod select;
1819
mod specialize;
@@ -49,11 +50,14 @@ pub use self::object_safety::is_vtable_safe_method;
4950
pub use self::object_safety::MethodViolationCode;
5051
pub use self::object_safety::ObjectSafetyViolation;
5152
pub use self::on_unimplemented::{OnUnimplementedDirective, OnUnimplementedNote};
52-
pub use self::project::MismatchedProjectionTypes;
5353
pub use self::project::{
5454
normalize, normalize_projection_type, normalize_to, poly_project_and_unify_type,
5555
};
56-
pub use self::project::{Normalized, ProjectionCache, ProjectionCacheSnapshot, Reveal};
56+
pub use self::projection_cache::MismatchedProjectionTypes;
57+
pub use self::projection_cache::{
58+
Normalized, ProjectionCache, ProjectionCacheEntry, ProjectionCacheKey, ProjectionCacheSnapshot,
59+
Reveal,
60+
};
5761
pub use self::select::{EvaluationCache, SelectionCache, SelectionContext};
5862
pub use self::select::{EvaluationResult, IntercrateAmbiguityCause, OverflowError};
5963
pub use self::specialize::find_associated_item;

src/librustc_infer/traits/project.rs

Lines changed: 3 additions & 177 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
//! Code for projecting associated types out of trait references.
22
33
use super::elaborate_predicates;
4+
use super::projection_cache::NormalizedTy;
45
use super::specialization_graph;
56
use super::translate_substs;
67
use super::util;
8+
use super::MismatchedProjectionTypes;
79
use super::Obligation;
810
use super::ObligationCause;
911
use super::PredicateObligation;
1012
use super::Selection;
1113
use super::SelectionContext;
1214
use super::SelectionError;
15+
use super::{Normalized, ProjectionCacheEntry, ProjectionCacheKey};
1316
use super::{VtableClosureData, VtableFnPointerData, VtableGeneratorData, VtableImplData};
1417

1518
use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
@@ -18,7 +21,6 @@ use rustc::ty::fold::{TypeFoldable, TypeFolder};
1821
use rustc::ty::subst::{InternalSubsts, Subst};
1922
use rustc::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, WithConstness};
2023
use rustc_ast::ast::Ident;
21-
use rustc_data_structures::snapshot_map::{Snapshot, SnapshotMap};
2224
use rustc_hir::def_id::DefId;
2325
use rustc_span::symbol::sym;
2426
use rustc_span::DUMMY_SP;
@@ -41,11 +43,6 @@ pub enum ProjectionTyError<'tcx> {
4143
TraitSelectionError(SelectionError<'tcx>),
4244
}
4345

44-
#[derive(Clone)]
45-
pub struct MismatchedProjectionTypes<'tcx> {
46-
pub err: ty::error::TypeError<'tcx>,
47-
}
48-
4946
#[derive(PartialEq, Eq, Debug)]
5047
enum ProjectionTyCandidate<'tcx> {
5148
// from a where-clause in the env or object type
@@ -393,20 +390,6 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
393390
}
394391
}
395392

396-
#[derive(Clone, TypeFoldable)]
397-
pub struct Normalized<'tcx, T> {
398-
pub value: T,
399-
pub obligations: Vec<PredicateObligation<'tcx>>,
400-
}
401-
402-
pub type NormalizedTy<'tcx> = Normalized<'tcx, Ty<'tcx>>;
403-
404-
impl<'tcx, T> Normalized<'tcx, T> {
405-
pub fn with<U>(self, value: U) -> Normalized<'tcx, U> {
406-
Normalized { value, obligations: self.obligations }
407-
}
408-
}
409-
410393
/// The guts of `normalize`: normalize a specific projection like `<T
411394
/// as Trait>::Item`. The result is always a type (and possibly
412395
/// additional obligations). If ambiguity arises, which implies that
@@ -1500,47 +1483,6 @@ fn assoc_ty_def(
15001483
}
15011484
}
15021485

1503-
// # Cache
1504-
1505-
/// The projection cache. Unlike the standard caches, this can include
1506-
/// infcx-dependent type variables, therefore we have to roll the
1507-
/// cache back each time we roll a snapshot back, to avoid assumptions
1508-
/// on yet-unresolved inference variables. Types with placeholder
1509-
/// regions also have to be removed when the respective snapshot ends.
1510-
///
1511-
/// Because of that, projection cache entries can be "stranded" and left
1512-
/// inaccessible when type variables inside the key are resolved. We make no
1513-
/// attempt to recover or remove "stranded" entries, but rather let them be
1514-
/// (for the lifetime of the infcx).
1515-
///
1516-
/// Entries in the projection cache might contain inference variables
1517-
/// that will be resolved by obligations on the projection cache entry (e.g.,
1518-
/// when a type parameter in the associated type is constrained through
1519-
/// an "RFC 447" projection on the impl).
1520-
///
1521-
/// When working with a fulfillment context, the derived obligations of each
1522-
/// projection cache entry will be registered on the fulfillcx, so any users
1523-
/// that can wait for a fulfillcx fixed point need not care about this. However,
1524-
/// users that don't wait for a fixed point (e.g., trait evaluation) have to
1525-
/// resolve the obligations themselves to make sure the projected result is
1526-
/// ok and avoid issues like #43132.
1527-
///
1528-
/// If that is done, after evaluation the obligations, it is a good idea to
1529-
/// call `ProjectionCache::complete` to make sure the obligations won't be
1530-
/// re-evaluated and avoid an exponential worst-case.
1531-
//
1532-
// FIXME: we probably also want some sort of cross-infcx cache here to
1533-
// reduce the amount of duplication. Let's see what we get with the Chalk reforms.
1534-
#[derive(Default)]
1535-
pub struct ProjectionCache<'tcx> {
1536-
map: SnapshotMap<ProjectionCacheKey<'tcx>, ProjectionCacheEntry<'tcx>>,
1537-
}
1538-
1539-
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
1540-
pub struct ProjectionCacheKey<'tcx> {
1541-
ty: ty::ProjectionTy<'tcx>,
1542-
}
1543-
15441486
impl<'cx, 'tcx> ProjectionCacheKey<'tcx> {
15451487
pub fn from_poly_projection_predicate(
15461488
selcx: &mut SelectionContext<'cx, 'tcx>,
@@ -1558,119 +1500,3 @@ impl<'cx, 'tcx> ProjectionCacheKey<'tcx> {
15581500
})
15591501
}
15601502
}
1561-
1562-
#[derive(Clone, Debug)]
1563-
enum ProjectionCacheEntry<'tcx> {
1564-
InProgress,
1565-
Ambiguous,
1566-
Error,
1567-
NormalizedTy(NormalizedTy<'tcx>),
1568-
}
1569-
1570-
// N.B., intentionally not Clone
1571-
pub struct ProjectionCacheSnapshot {
1572-
snapshot: Snapshot,
1573-
}
1574-
1575-
impl<'tcx> ProjectionCache<'tcx> {
1576-
pub fn clear(&mut self) {
1577-
self.map.clear();
1578-
}
1579-
1580-
pub fn snapshot(&mut self) -> ProjectionCacheSnapshot {
1581-
ProjectionCacheSnapshot { snapshot: self.map.snapshot() }
1582-
}
1583-
1584-
pub fn rollback_to(&mut self, snapshot: ProjectionCacheSnapshot) {
1585-
self.map.rollback_to(snapshot.snapshot);
1586-
}
1587-
1588-
pub fn rollback_placeholder(&mut self, snapshot: &ProjectionCacheSnapshot) {
1589-
self.map.partial_rollback(&snapshot.snapshot, &|k| k.ty.has_re_placeholders());
1590-
}
1591-
1592-
pub fn commit(&mut self, snapshot: ProjectionCacheSnapshot) {
1593-
self.map.commit(snapshot.snapshot);
1594-
}
1595-
1596-
/// Try to start normalize `key`; returns an error if
1597-
/// normalization already occurred (this error corresponds to a
1598-
/// cache hit, so it's actually a good thing).
1599-
fn try_start(
1600-
&mut self,
1601-
key: ProjectionCacheKey<'tcx>,
1602-
) -> Result<(), ProjectionCacheEntry<'tcx>> {
1603-
if let Some(entry) = self.map.get(&key) {
1604-
return Err(entry.clone());
1605-
}
1606-
1607-
self.map.insert(key, ProjectionCacheEntry::InProgress);
1608-
Ok(())
1609-
}
1610-
1611-
/// Indicates that `key` was normalized to `value`.
1612-
fn insert_ty(&mut self, key: ProjectionCacheKey<'tcx>, value: NormalizedTy<'tcx>) {
1613-
debug!(
1614-
"ProjectionCacheEntry::insert_ty: adding cache entry: key={:?}, value={:?}",
1615-
key, value
1616-
);
1617-
let fresh_key = self.map.insert(key, ProjectionCacheEntry::NormalizedTy(value));
1618-
assert!(!fresh_key, "never started projecting `{:?}`", key);
1619-
}
1620-
1621-
/// Mark the relevant projection cache key as having its derived obligations
1622-
/// complete, so they won't have to be re-computed (this is OK to do in a
1623-
/// snapshot - if the snapshot is rolled back, the obligations will be
1624-
/// marked as incomplete again).
1625-
pub fn complete(&mut self, key: ProjectionCacheKey<'tcx>) {
1626-
let ty = match self.map.get(&key) {
1627-
Some(&ProjectionCacheEntry::NormalizedTy(ref ty)) => {
1628-
debug!("ProjectionCacheEntry::complete({:?}) - completing {:?}", key, ty);
1629-
ty.value
1630-
}
1631-
ref value => {
1632-
// Type inference could "strand behind" old cache entries. Leave
1633-
// them alone for now.
1634-
debug!("ProjectionCacheEntry::complete({:?}) - ignoring {:?}", key, value);
1635-
return;
1636-
}
1637-
};
1638-
1639-
self.map.insert(
1640-
key,
1641-
ProjectionCacheEntry::NormalizedTy(Normalized { value: ty, obligations: vec![] }),
1642-
);
1643-
}
1644-
1645-
/// A specialized version of `complete` for when the key's value is known
1646-
/// to be a NormalizedTy.
1647-
pub fn complete_normalized(&mut self, key: ProjectionCacheKey<'tcx>, ty: &NormalizedTy<'tcx>) {
1648-
// We want to insert `ty` with no obligations. If the existing value
1649-
// already has no obligations (as is common) we don't insert anything.
1650-
if !ty.obligations.is_empty() {
1651-
self.map.insert(
1652-
key,
1653-
ProjectionCacheEntry::NormalizedTy(Normalized {
1654-
value: ty.value,
1655-
obligations: vec![],
1656-
}),
1657-
);
1658-
}
1659-
}
1660-
1661-
/// Indicates that trying to normalize `key` resulted in
1662-
/// ambiguity. No point in trying it again then until we gain more
1663-
/// type information (in which case, the "fully resolved" key will
1664-
/// be different).
1665-
fn ambiguous(&mut self, key: ProjectionCacheKey<'tcx>) {
1666-
let fresh = self.map.insert(key, ProjectionCacheEntry::Ambiguous);
1667-
assert!(!fresh, "never started projecting `{:?}`", key);
1668-
}
1669-
1670-
/// Indicates that trying to normalize `key` resulted in
1671-
/// error.
1672-
fn error(&mut self, key: ProjectionCacheKey<'tcx>) {
1673-
let fresh = self.map.insert(key, ProjectionCacheEntry::Error);
1674-
assert!(!fresh, "never started projecting `{:?}`", key);
1675-
}
1676-
}

0 commit comments

Comments
 (0)