Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
342 changes: 342 additions & 0 deletions src/libcore/iter/adapters/fuse.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,342 @@
use crate::intrinsics;
use crate::iter::{
DoubleEndedIterator, ExactSizeIterator, FusedIterator, Iterator, TrustedRandomAccess,
};
use crate::ops::Try;

/// An iterator that yields `None` forever after the underlying iterator
/// yields `None` once.
///
/// This `struct` is created by the [`fuse`] method on [`Iterator`]. See its
/// documentation for more.
///
/// [`fuse`]: trait.Iterator.html#method.fuse
/// [`Iterator`]: trait.Iterator.html
#[derive(Clone, Debug)]
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Fuse<I> {
// NOTE: for `I: FusedIterator`, this is always assumed `Some`!
iter: Option<I>,
}
impl<I> Fuse<I> {
pub(in crate::iter) fn new(iter: I) -> Fuse<I> {
Fuse { iter: Some(iter) }
}
}

#[stable(feature = "fused", since = "1.26.0")]
impl<I> FusedIterator for Fuse<I> where I: Iterator {}

#[stable(feature = "rust1", since = "1.0.0")]
impl<I> Iterator for Fuse<I>
where
I: Iterator,
{
type Item = <I as Iterator>::Item;

#[inline]
default fn next(&mut self) -> Option<<I as Iterator>::Item> {
let next = self.iter.as_mut()?.next();
if next.is_none() {
self.iter = None;
}
next
}

#[inline]
default fn nth(&mut self, n: usize) -> Option<I::Item> {
let nth = self.iter.as_mut()?.nth(n);
if nth.is_none() {
self.iter = None;
}
nth
}

#[inline]
default fn last(self) -> Option<I::Item> {
self.iter?.last()
}

#[inline]
default fn count(self) -> usize {
self.iter.map_or(0, I::count)
}

#[inline]
default fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.as_ref().map_or((0, Some(0)), I::size_hint)
}

#[inline]
default fn try_fold<Acc, Fold, R>(&mut self, mut acc: Acc, fold: Fold) -> R
where
Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>,
{
if let Some(ref mut iter) = self.iter {
acc = iter.try_fold(acc, fold)?;
self.iter = None;
}
Try::from_ok(acc)
}

#[inline]
default fn fold<Acc, Fold>(self, mut acc: Acc, fold: Fold) -> Acc
where
Fold: FnMut(Acc, Self::Item) -> Acc,
{
if let Some(iter) = self.iter {
acc = iter.fold(acc, fold);
}
acc
}

#[inline]
default fn find<P>(&mut self, predicate: P) -> Option<Self::Item>
where
P: FnMut(&Self::Item) -> bool,
{
let found = self.iter.as_mut()?.find(predicate);
if found.is_none() {
self.iter = None;
}
found
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<I> DoubleEndedIterator for Fuse<I>
where
I: DoubleEndedIterator,
{
#[inline]
default fn next_back(&mut self) -> Option<<I as Iterator>::Item> {
let next = self.iter.as_mut()?.next_back();
if next.is_none() {
self.iter = None;
}
next
}

#[inline]
default fn nth_back(&mut self, n: usize) -> Option<<I as Iterator>::Item> {
let nth = self.iter.as_mut()?.nth_back(n);
if nth.is_none() {
self.iter = None;
}
nth
}

#[inline]
default fn try_rfold<Acc, Fold, R>(&mut self, mut acc: Acc, fold: Fold) -> R
where
Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>,
{
if let Some(ref mut iter) = self.iter {
acc = iter.try_rfold(acc, fold)?;
self.iter = None;
}
Try::from_ok(acc)
}

#[inline]
default fn rfold<Acc, Fold>(self, mut acc: Acc, fold: Fold) -> Acc
where
Fold: FnMut(Acc, Self::Item) -> Acc,
{
if let Some(iter) = self.iter {
acc = iter.rfold(acc, fold);
}
acc
}

#[inline]
default fn rfind<P>(&mut self, predicate: P) -> Option<Self::Item>
where
P: FnMut(&Self::Item) -> bool,
{
let found = self.iter.as_mut()?.rfind(predicate);
if found.is_none() {
self.iter = None;
}
found
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<I> ExactSizeIterator for Fuse<I>
where
I: ExactSizeIterator,
{
default fn len(&self) -> usize {
self.iter.as_ref().map_or(0, I::len)
}

default fn is_empty(&self) -> bool {
self.iter.as_ref().map_or(true, I::is_empty)
}
}

// NOTE: for `I: FusedIterator`, we assume that the iterator is always `Some`
impl<I: FusedIterator> Fuse<I> {
#[inline(always)]
fn as_inner(&self) -> &I {
match self.iter {
Some(ref iter) => iter,
// SAFETY: the specialized iterator never sets `None`
None => unsafe { intrinsics::unreachable() },
}
}

#[inline(always)]
fn as_inner_mut(&mut self) -> &mut I {
match self.iter {
Some(ref mut iter) => iter,
// SAFETY: the specialized iterator never sets `None`
None => unsafe { intrinsics::unreachable() },
}
}

#[inline(always)]
fn into_inner(self) -> I {
match self.iter {
Some(iter) => iter,
// SAFETY: the specialized iterator never sets `None`
None => unsafe { intrinsics::unreachable() },
}
}
}

#[stable(feature = "fused", since = "1.26.0")]
impl<I> Iterator for Fuse<I>
where
I: FusedIterator,
{
#[inline]
fn next(&mut self) -> Option<<I as Iterator>::Item> {
self.as_inner_mut().next()
}

#[inline]
fn nth(&mut self, n: usize) -> Option<I::Item> {
self.as_inner_mut().nth(n)
}

#[inline]
fn last(self) -> Option<I::Item> {
self.into_inner().last()
}

#[inline]
fn count(self) -> usize {
self.into_inner().count()
}

#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.as_inner().size_hint()
}

#[inline]
fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
where
Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>,
{
self.as_inner_mut().try_fold(init, fold)
}

#[inline]
fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
where
Fold: FnMut(Acc, Self::Item) -> Acc,
{
self.into_inner().fold(init, fold)
}

#[inline]
fn find<P>(&mut self, predicate: P) -> Option<Self::Item>
where
P: FnMut(&Self::Item) -> bool,
{
self.as_inner_mut().find(predicate)
}
}

#[stable(feature = "fused", since = "1.26.0")]
impl<I> DoubleEndedIterator for Fuse<I>
where
I: DoubleEndedIterator + FusedIterator,
{
#[inline]
fn next_back(&mut self) -> Option<<I as Iterator>::Item> {
self.as_inner_mut().next_back()
}

#[inline]
fn nth_back(&mut self, n: usize) -> Option<<I as Iterator>::Item> {
self.as_inner_mut().nth_back(n)
}

#[inline]
fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
where
Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>,
{
self.as_inner_mut().try_rfold(init, fold)
}

#[inline]
fn rfold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
where
Fold: FnMut(Acc, Self::Item) -> Acc,
{
self.into_inner().rfold(init, fold)
}

#[inline]
fn rfind<P>(&mut self, predicate: P) -> Option<Self::Item>
where
P: FnMut(&Self::Item) -> bool,
{
self.as_inner_mut().rfind(predicate)
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<I> ExactSizeIterator for Fuse<I>
where
I: ExactSizeIterator + FusedIterator,
{
fn len(&self) -> usize {
self.as_inner().len()
}

fn is_empty(&self) -> bool {
self.as_inner().is_empty()
}
}

unsafe impl<I> TrustedRandomAccess for Fuse<I>
where
I: TrustedRandomAccess,
{
unsafe fn get_unchecked(&mut self, i: usize) -> I::Item {
match self.iter {
Some(ref mut iter) => iter.get_unchecked(i),
// SAFETY: the caller asserts there is an item at `i`, so we're not exhausted.
None => intrinsics::unreachable(),
}
}

fn may_have_side_effect() -> bool {
I::may_have_side_effect()
}
}
257 changes: 2 additions & 255 deletions src/libcore/iter/adapters/mod.rs
Original file line number Diff line number Diff line change
@@ -9,11 +9,13 @@ use super::{DoubleEndedIterator, ExactSizeIterator, FusedIterator, Iterator, Tru

mod chain;
mod flatten;
mod fuse;
mod zip;

pub use self::chain::Chain;
#[stable(feature = "rust1", since = "1.0.0")]
pub use self::flatten::{FlatMap, Flatten};
pub use self::fuse::Fuse;
pub(crate) use self::zip::TrustedRandomAccess;
pub use self::zip::Zip;

@@ -2238,261 +2240,6 @@ where
}
}

/// An iterator that yields `None` forever after the underlying iterator
/// yields `None` once.
///
/// This `struct` is created by the [`fuse`] method on [`Iterator`]. See its
/// documentation for more.
///
/// [`fuse`]: trait.Iterator.html#method.fuse
/// [`Iterator`]: trait.Iterator.html
#[derive(Clone, Debug)]
#[must_use = "iterators are lazy and do nothing unless consumed"]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Fuse<I> {
iter: I,
done: bool,
}
impl<I> Fuse<I> {
pub(super) fn new(iter: I) -> Fuse<I> {
Fuse { iter, done: false }
}
}

#[stable(feature = "fused", since = "1.26.0")]
impl<I> FusedIterator for Fuse<I> where I: Iterator {}

#[stable(feature = "rust1", since = "1.0.0")]
impl<I> Iterator for Fuse<I>
where
I: Iterator,
{
type Item = <I as Iterator>::Item;

#[inline]
default fn next(&mut self) -> Option<<I as Iterator>::Item> {
if self.done {
None
} else {
let next = self.iter.next();
self.done = next.is_none();
next
}
}

#[inline]
default fn nth(&mut self, n: usize) -> Option<I::Item> {
if self.done {
None
} else {
let nth = self.iter.nth(n);
self.done = nth.is_none();
nth
}
}

#[inline]
default fn last(self) -> Option<I::Item> {
if self.done { None } else { self.iter.last() }
}

#[inline]
default fn count(self) -> usize {
if self.done { 0 } else { self.iter.count() }
}

#[inline]
default fn size_hint(&self) -> (usize, Option<usize>) {
if self.done { (0, Some(0)) } else { self.iter.size_hint() }
}

#[inline]
default fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
where
Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>,
{
if self.done {
Try::from_ok(init)
} else {
let acc = self.iter.try_fold(init, fold)?;
self.done = true;
Try::from_ok(acc)
}
}

#[inline]
default fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
where
Fold: FnMut(Acc, Self::Item) -> Acc,
{
if self.done { init } else { self.iter.fold(init, fold) }
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<I> DoubleEndedIterator for Fuse<I>
where
I: DoubleEndedIterator,
{
#[inline]
default fn next_back(&mut self) -> Option<<I as Iterator>::Item> {
if self.done {
None
} else {
let next = self.iter.next_back();
self.done = next.is_none();
next
}
}

#[inline]
default fn nth_back(&mut self, n: usize) -> Option<<I as Iterator>::Item> {
if self.done {
None
} else {
let nth = self.iter.nth_back(n);
self.done = nth.is_none();
nth
}
}

#[inline]
default fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
where
Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>,
{
if self.done {
Try::from_ok(init)
} else {
let acc = self.iter.try_rfold(init, fold)?;
self.done = true;
Try::from_ok(acc)
}
}

#[inline]
default fn rfold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
where
Fold: FnMut(Acc, Self::Item) -> Acc,
{
if self.done { init } else { self.iter.rfold(init, fold) }
}
}

unsafe impl<I> TrustedRandomAccess for Fuse<I>
where
I: TrustedRandomAccess,
{
unsafe fn get_unchecked(&mut self, i: usize) -> I::Item {
self.iter.get_unchecked(i)
}

fn may_have_side_effect() -> bool {
I::may_have_side_effect()
}
}

#[stable(feature = "fused", since = "1.26.0")]
impl<I> Iterator for Fuse<I>
where
I: FusedIterator,
{
#[inline]
fn next(&mut self) -> Option<<I as Iterator>::Item> {
self.iter.next()
}

#[inline]
fn nth(&mut self, n: usize) -> Option<I::Item> {
self.iter.nth(n)
}

#[inline]
fn last(self) -> Option<I::Item> {
self.iter.last()
}

#[inline]
fn count(self) -> usize {
self.iter.count()
}

#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}

#[inline]
fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
where
Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>,
{
self.iter.try_fold(init, fold)
}

#[inline]
fn fold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
where
Fold: FnMut(Acc, Self::Item) -> Acc,
{
self.iter.fold(init, fold)
}
}

#[stable(feature = "fused", since = "1.26.0")]
impl<I> DoubleEndedIterator for Fuse<I>
where
I: DoubleEndedIterator + FusedIterator,
{
#[inline]
fn next_back(&mut self) -> Option<<I as Iterator>::Item> {
self.iter.next_back()
}

#[inline]
fn nth_back(&mut self, n: usize) -> Option<<I as Iterator>::Item> {
self.iter.nth_back(n)
}

#[inline]
fn try_rfold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R
where
Self: Sized,
Fold: FnMut(Acc, Self::Item) -> R,
R: Try<Ok = Acc>,
{
self.iter.try_rfold(init, fold)
}

#[inline]
fn rfold<Acc, Fold>(self, init: Acc, fold: Fold) -> Acc
where
Fold: FnMut(Acc, Self::Item) -> Acc,
{
self.iter.rfold(init, fold)
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<I> ExactSizeIterator for Fuse<I>
where
I: ExactSizeIterator,
{
fn len(&self) -> usize {
self.iter.len()
}

fn is_empty(&self) -> bool {
self.iter.is_empty()
}
}

/// An iterator that calls a function with a reference to each element before
/// yielding it.
///
2 changes: 1 addition & 1 deletion src/librustc/dep_graph/dep_node.rs
Original file line number Diff line number Diff line change
@@ -57,7 +57,7 @@ use crate::traits::query::{
CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal,
CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal,
};
use crate::ty::subst::SubstsRef;
use crate::ty::subst::{GenericArg, SubstsRef};
use crate::ty::{self, ParamEnvAnd, Ty, TyCtxt};

use rustc_data_structures::fingerprint::Fingerprint;
16 changes: 11 additions & 5 deletions src/librustc/mir/interpret/allocation.rs
Original file line number Diff line number Diff line change
@@ -372,7 +372,7 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
let bytes = self.get_bytes_with_undef_and_ptr(cx, ptr, size)?;
// Undef check happens *after* we established that the alignment is correct.
// We must not return `Ok()` for unaligned pointers!
if self.check_defined(ptr, size).is_err() {
if self.is_defined(ptr, size).is_err() {
// This inflates undefined bytes to the entire scalar, even if only a few
// bytes are undefined.
return Ok(ScalarMaybeUndef::Undef);
@@ -557,13 +557,19 @@ impl<'tcx, Tag: Copy, Extra> Allocation<Tag, Extra> {
}

/// Undefined bytes.
impl<'tcx, Tag, Extra> Allocation<Tag, Extra> {
impl<'tcx, Tag: Copy, Extra> Allocation<Tag, Extra> {
/// Checks whether the given range is entirely defined.
///
/// Returns `Ok(())` if it's defined. Otherwise returns the index of the byte
/// at which the first undefined access begins.
fn is_defined(&self, ptr: Pointer<Tag>, size: Size) -> Result<(), Size> {
self.undef_mask.is_range_defined(ptr.offset, ptr.offset + size)
}

/// Checks that a range of bytes is defined. If not, returns the `ReadUndefBytes`
/// error which will report the first byte which is undefined.
#[inline]
fn check_defined(&self, ptr: Pointer<Tag>, size: Size) -> InterpResult<'tcx> {
self.undef_mask
.is_range_defined(ptr.offset, ptr.offset + size)
self.is_defined(ptr, size)
.or_else(|idx| throw_ub!(InvalidUndefBytes(Some(Pointer::new(ptr.alloc_id, idx)))))
}

10 changes: 5 additions & 5 deletions src/librustc/query/mod.rs
Original file line number Diff line number Diff line change
@@ -9,7 +9,7 @@ use crate::traits::query::{
};
use crate::ty::query::queries;
use crate::ty::query::QueryDescription;
use crate::ty::subst::SubstsRef;
use crate::ty::subst::{GenericArg, SubstsRef};
use crate::ty::{self, ParamEnvAnd, Ty, TyCtxt};
use rustc_hir::def_id::{CrateNum, DefId, LocalDefId};

@@ -1114,10 +1114,10 @@ rustc_queries! {
}

/// Do not call this query directly: invoke `normalize_erasing_regions` instead.
query normalize_ty_after_erasing_regions(
goal: ParamEnvAnd<'tcx, Ty<'tcx>>
) -> Ty<'tcx> {
desc { "normalizing `{:?}`", goal }
query normalize_generic_arg_after_erasing_regions(
goal: ParamEnvAnd<'tcx, GenericArg<'tcx>>
) -> GenericArg<'tcx> {
desc { "normalizing `{}`", goal.value }
}

query implied_outlives_bounds(
14 changes: 14 additions & 0 deletions src/librustc/traits/structural_impls.rs
Original file line number Diff line number Diff line change
@@ -273,6 +273,20 @@ impl<'tcx> TypeVisitor<'tcx> for BoundNamesCollector {
t.super_visit_with(self)
}

fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool {
match c.val {
ty::ConstKind::Bound(debruijn, bound_var) if debruijn == self.binder_index => {
self.types.insert(
bound_var.as_u32(),
Symbol::intern(&format!("^{}", bound_var.as_u32())),
);
}
_ => (),
}

c.super_visit_with(self)
}

fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
match r {
ty::ReLateBound(index, br) if *index == self.binder_index => match br {
20 changes: 15 additions & 5 deletions src/librustc/ty/fold.rs
Original file line number Diff line number Diff line change
@@ -978,17 +978,27 @@ impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector {
// ignore the inputs to a projection, as they may not appear
// in the normalized form
if self.just_constrained {
match t.kind {
ty::Projection(..) | ty::Opaque(..) => {
return false;
}
_ => {}
if let ty::Projection(..) | ty::Opaque(..) = t.kind {
return false;
}
}

t.super_visit_with(self)
}

fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool {
// if we are only looking for "constrained" region, we have to
// ignore the inputs of an unevaluated const, as they may not appear
// in the normalized form
if self.just_constrained {
if let ty::ConstKind::Unevaluated(..) = c.val {
return false;
}
}

c.super_visit_with(self)
}

fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
if let ty::ReLateBound(debruijn, br) = *r {
if debruijn == self.current_index {
12 changes: 9 additions & 3 deletions src/librustc/ty/normalize_erasing_regions.rs
Original file line number Diff line number Diff line change
@@ -4,8 +4,8 @@
//!
//! The methods in this file use a `TypeFolder` to recursively process
//! contents, invoking the underlying
//! `normalize_ty_after_erasing_regions` query for each type found
//! within. (This underlying query is what is cached.)
//! `normalize_generic_arg_after_erasing_regions` query for each type
//! or constant found within. (This underlying query is what is cached.)
use crate::ty::fold::{TypeFoldable, TypeFolder};
use crate::ty::subst::{Subst, SubstsRef};
@@ -94,6 +94,12 @@ impl TypeFolder<'tcx> for NormalizeAfterErasingRegionsFolder<'tcx> {
}

fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
self.tcx.normalize_ty_after_erasing_regions(self.param_env.and(ty))
let arg = self.param_env.and(ty.into());
self.tcx.normalize_generic_arg_after_erasing_regions(arg).expect_ty()
}

fn fold_const(&mut self, c: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
let arg = self.param_env.and(c.into());
self.tcx.normalize_generic_arg_after_erasing_regions(arg).expect_const()
}
}
13 changes: 12 additions & 1 deletion src/librustc/ty/query/keys.rs
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@ use crate::mir;
use crate::traits;
use crate::ty::fast_reject::SimplifiedType;
use crate::ty::query::caches::DefaultCacheSelector;
use crate::ty::subst::SubstsRef;
use crate::ty::subst::{GenericArg, SubstsRef};
use crate::ty::{self, Ty, TyCtxt};
use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
use rustc_span::symbol::Symbol;
@@ -194,6 +194,17 @@ impl<'tcx> Key for ty::PolyTraitRef<'tcx> {
}
}

impl<'tcx> Key for GenericArg<'tcx> {
type CacheSelector = DefaultCacheSelector;

fn query_crate(&self) -> CrateNum {
LOCAL_CRATE
}
fn default_span(&self, _: TyCtxt<'_>) -> Span {
DUMMY_SP
}
}

impl<'tcx> Key for &'tcx ty::Const<'tcx> {
type CacheSelector = DefaultCacheSelector;

2 changes: 1 addition & 1 deletion src/librustc/ty/query/mod.rs
Original file line number Diff line number Diff line change
@@ -31,7 +31,7 @@ use crate::traits::specialization_graph;
use crate::traits::Clauses;
use crate::traits::{self, Vtable};
use crate::ty::steal::Steal;
use crate::ty::subst::SubstsRef;
use crate::ty::subst::{GenericArg, SubstsRef};
use crate::ty::util::AlwaysRequiresDrop;
use crate::ty::{self, AdtSizedConstraint, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt};
use crate::util::common::ErrorReported;
8 changes: 8 additions & 0 deletions src/librustc/ty/subst.rs
Original file line number Diff line number Diff line change
@@ -128,6 +128,14 @@ impl<'tcx> GenericArg<'tcx> {
_ => bug!("expected a type, but found another kind"),
}
}

/// Unpack the `GenericArg` as a const when it is known certainly to be a const.
pub fn expect_const(self) -> &'tcx ty::Const<'tcx> {
match self.unpack() {
GenericArgKind::Const(c) => c,
_ => bug!("expected a const, but found another kind"),
}
}
}

impl<'a, 'tcx> Lift<'tcx> for GenericArg<'a> {
4 changes: 2 additions & 2 deletions src/librustc_mir/interpret/memory.rs
Original file line number Diff line number Diff line change
@@ -473,7 +473,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
}

/// Gives raw access to the `Allocation`, without bounds or alignment checks.
/// Use the higher-level, `PlaceTy`- and `OpTy`-based APIs in `InterpCtx` instead!
/// Use the higher-level, `PlaceTy`- and `OpTy`-based APIs in `InterpCx` instead!
pub fn get_raw(
&self,
id: AllocId,
@@ -510,7 +510,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
}

/// Gives raw mutable access to the `Allocation`, without bounds or alignment checks.
/// Use the higher-level, `PlaceTy`- and `OpTy`-based APIs in `InterpCtx` instead!
/// Use the higher-level, `PlaceTy`- and `OpTy`-based APIs in `InterpCx` instead!
pub fn get_raw_mut(
&mut self,
id: AllocId,
8 changes: 4 additions & 4 deletions src/librustc_session/session.rs
Original file line number Diff line number Diff line change
@@ -150,7 +150,7 @@ pub struct PerfStats {
/// Total number of values canonicalized queries constructed.
pub queries_canonicalized: AtomicUsize,
/// Number of times this query is invoked.
pub normalize_ty_after_erasing_regions: AtomicUsize,
pub normalize_generic_arg_after_erasing_regions: AtomicUsize,
/// Number of times this query is invoked.
pub normalize_projection_ty: AtomicUsize,
}
@@ -707,8 +707,8 @@ impl Session {
self.perf_stats.queries_canonicalized.load(Ordering::Relaxed)
);
println!(
"normalize_ty_after_erasing_regions: {}",
self.perf_stats.normalize_ty_after_erasing_regions.load(Ordering::Relaxed)
"normalize_generic_arg_after_erasing_regions: {}",
self.perf_stats.normalize_generic_arg_after_erasing_regions.load(Ordering::Relaxed)
);
println!(
"normalize_projection_ty: {}",
@@ -1080,7 +1080,7 @@ fn build_session_(
symbol_hash_time: Lock::new(Duration::from_secs(0)),
decode_def_path_tables_time: Lock::new(Duration::from_secs(0)),
queries_canonicalized: AtomicUsize::new(0),
normalize_ty_after_erasing_regions: AtomicUsize::new(0),
normalize_generic_arg_after_erasing_regions: AtomicUsize::new(0),
normalize_projection_ty: AtomicUsize::new(0),
},
code_stats: Default::default(),
1 change: 1 addition & 0 deletions src/librustc_trait_selection/traits/project.rs
Original file line number Diff line number Diff line change
@@ -387,6 +387,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
}

fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
let constant = constant.super_fold_with(self);
constant.eval(self.selcx.tcx(), self.param_env)
}
}
1 change: 1 addition & 0 deletions src/librustc_trait_selection/traits/query/normalize.rs
Original file line number Diff line number Diff line change
@@ -191,6 +191,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
}

fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
let constant = constant.super_fold_with(self);
constant.eval(self.infcx.tcx, self.param_env)
}
}
15 changes: 8 additions & 7 deletions src/librustc_traits/normalize_erasing_regions.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
use rustc::traits::query::NoSolution;
use rustc::ty::query::Providers;
use rustc::ty::{self, ParamEnvAnd, Ty, TyCtxt};
use rustc::ty::subst::GenericArg;
use rustc::ty::{self, ParamEnvAnd, TyCtxt};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_trait_selection::traits::query::normalize::AtExt;
use rustc_trait_selection::traits::{Normalized, ObligationCause};
use std::sync::atomic::Ordering;

crate fn provide(p: &mut Providers<'_>) {
*p = Providers { normalize_ty_after_erasing_regions, ..*p };
*p = Providers { normalize_generic_arg_after_erasing_regions, ..*p };
}

fn normalize_ty_after_erasing_regions<'tcx>(
fn normalize_generic_arg_after_erasing_regions<'tcx>(
tcx: TyCtxt<'tcx>,
goal: ParamEnvAnd<'tcx, Ty<'tcx>>,
) -> Ty<'tcx> {
debug!("normalize_ty_after_erasing_regions(goal={:#?})", goal);
goal: ParamEnvAnd<'tcx, GenericArg<'tcx>>,
) -> GenericArg<'tcx> {
debug!("normalize_generic_arg_after_erasing_regions(goal={:#?})", goal);

let ParamEnvAnd { param_env, value } = goal;
tcx.sess.perf_stats.normalize_ty_after_erasing_regions.fetch_add(1, Ordering::Relaxed);
tcx.sess.perf_stats.normalize_generic_arg_after_erasing_regions.fetch_add(1, Ordering::Relaxed);
tcx.infer_ctxt().enter(|infcx| {
let cause = ObligationCause::dummy();
match infcx.at(&cause, param_env).normalize(&value) {
3 changes: 2 additions & 1 deletion src/test/mir-opt/inline/inline-into-box-place.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// ignore-tidy-linelength
// ignore-wasm32-bare compiled with panic=abort by default
// compile-flags: -Z mir-opt-level=3
// only-64bit FIXME: the mir representation of RawVec depends on ptr size
#![feature(box_syntax)]

fn main() {
@@ -55,7 +56,7 @@ fn main() {
// StorageLive(_2);
// _2 = Box(std::vec::Vec<u32>);
// _4 = &mut (*_2);
// ((*_4).0: alloc::raw_vec::RawVec<u32>) = const alloc::raw_vec::RawVec::<u32>::NEW;
// ((*_4).0: alloc::raw_vec::RawVec<u32>) = const ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), undef_mask: UndefMask { blocks: [65535], len: Size { raw: 16 } }, size: Size { raw: 16 }, align: Align { pow2: 3 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }: alloc::raw_vec::RawVec::<u32>;
// ((*_4).1: usize) = const 0usize;
// _1 = move _2;
// StorageDead(_2);
2 changes: 1 addition & 1 deletion src/test/ui/associated-const/defaults-cyclic-fail.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
// build-fail
//~^ ERROR cycle detected when normalizing `<() as Tr>::A`

// Cyclic assoc. const defaults don't error unless *used*
trait Tr {
const A: u8 = Self::B;
//~^ ERROR cycle detected when const-evaluating + checking `Tr::A`

const B: u8 = Self::A;
}
32 changes: 22 additions & 10 deletions src/test/ui/associated-const/defaults-cyclic-fail.stderr
Original file line number Diff line number Diff line change
@@ -1,30 +1,42 @@
error[E0391]: cycle detected when const-evaluating + checking `Tr::A`
--> $DIR/defaults-cyclic-fail.rs:5:5
error[E0391]: cycle detected when normalizing `<() as Tr>::A`
|
note: ...which requires const-evaluating + checking `Tr::A`...
--> $DIR/defaults-cyclic-fail.rs:6:5
|
LL | const A: u8 = Self::B;
| ^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires const-evaluating + checking `Tr::A`...
--> $DIR/defaults-cyclic-fail.rs:6:5
|
LL | const A: u8 = Self::B;
| ^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires const-evaluating `Tr::A`...
--> $DIR/defaults-cyclic-fail.rs:5:19
--> $DIR/defaults-cyclic-fail.rs:6:5
|
LL | const A: u8 = Self::B;
| ^^^^^^^
| ^^^^^^^^^^^^^^^^^^^^^^
= note: ...which requires normalizing `<() as Tr>::B`...
note: ...which requires const-evaluating + checking `Tr::B`...
--> $DIR/defaults-cyclic-fail.rs:8:5
|
LL | const B: u8 = Self::A;
| ^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires const-evaluating + checking `Tr::B`...
--> $DIR/defaults-cyclic-fail.rs:8:5
|
LL | const B: u8 = Self::A;
| ^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires const-evaluating `Tr::B`...
--> $DIR/defaults-cyclic-fail.rs:8:19
--> $DIR/defaults-cyclic-fail.rs:8:5
|
LL | const B: u8 = Self::A;
| ^^^^^^^
= note: ...which again requires const-evaluating + checking `Tr::A`, completing the cycle
| ^^^^^^^^^^^^^^^^^^^^^^
= note: ...which again requires normalizing `<() as Tr>::A`, completing the cycle
note: cycle used when const-evaluating `main`
--> $DIR/defaults-cyclic-fail.rs:16:16
--> $DIR/defaults-cyclic-fail.rs:14:1
|
LL | assert_eq!(<() as Tr>::A, 0);
| ^^^^^^^^^^^^^
LL | fn main() {
| ^^^^^^^^^

error: aborting due to previous error

2 changes: 1 addition & 1 deletion src/test/ui/consts/const-size_of-cycle.stderr
Original file line number Diff line number Diff line change
@@ -25,7 +25,7 @@ note: ...which requires const-evaluating + checking `std::intrinsics::size_of`..
LL | pub fn size_of<T>() -> usize;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: ...which requires computing layout of `Foo`...
= note: ...which requires normalizing `ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: All, def_id: None }, value: [u8; _] }`...
= note: ...which requires normalizing `[u8; _]`...
= note: ...which again requires const-evaluating + checking `Foo::bytes::{{constant}}#0`, completing the cycle
note: cycle used when processing `Foo`
--> $DIR/const-size_of-cycle.rs:7:1