diff --git a/.travis.yml b/.travis.yml index 7f99678499ace..c4efa88460325 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: shell sudo: required -dist: trusty +dist: xenial services: - docker addons: diff --git a/Cargo.lock b/Cargo.lock index 041a24aae6c53..6f24f8d3681d7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -194,6 +194,7 @@ version = "0.34.0" dependencies = [ "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "bufstream 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "bytesize 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", "core-foundation 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -241,6 +242,7 @@ dependencies = [ "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "url_serde 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh index ebef27360c02b..ad6188568cff2 100755 --- a/src/ci/docker/run.sh +++ b/src/ci/docker/run.sh @@ -19,10 +19,12 @@ travis_time_start if [ -f "$docker_dir/$image/Dockerfile" ]; then if [ "$CI" != "" ]; then - cksum=$(find $docker_dir/$image $docker_dir/scripts -type f | \ + hash_key=/tmp/.docker-hash-key.txt + find $docker_dir/$image $docker_dir/scripts -type f | \ sort | \ - xargs cat | \ - sha512sum | \ + xargs cat >> $hash_key + docker --version >> $hash_key + cksum=$(sha512sum $hash_key | \ awk '{print $1}') s3url="s3://$SCCACHE_BUCKET/docker/$cksum" url="https://s3-us-west-1.amazonaws.com/$SCCACHE_BUCKET/docker/$cksum" diff --git a/src/doc/rustc/src/lints/listing/warn-by-default.md b/src/doc/rustc/src/lints/listing/warn-by-default.md index b01aed0915d08..13ffa60ff4fb0 100644 --- a/src/doc/rustc/src/lints/listing/warn-by-default.md +++ b/src/doc/rustc/src/lints/listing/warn-by-default.md @@ -163,7 +163,7 @@ struct s; This will produce: ```text -warning: type `s` should have a camel case name such as `S` +warning: type `s` should have an upper camel case name such as `S` --> src/main.rs:1:1 | 1 | struct s; diff --git a/src/libarena/lib.rs b/src/libarena/lib.rs index b40e905620de9..9f9ded51e37ee 100644 --- a/src/libarena/lib.rs +++ b/src/libarena/lib.rs @@ -119,6 +119,11 @@ impl Default for TypedArena { } impl TypedArena { + pub fn in_arena(&self, ptr: *const T) -> bool { + let ptr = ptr as *const T as *mut T; + + self.chunks.borrow().iter().any(|chunk| chunk.start() <= ptr && ptr < chunk.end()) + } /// Allocates an object in the `TypedArena`, returning a reference to it. #[inline] pub fn alloc(&self, object: T) -> &mut T { diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index b2fe4b7561c5a..57a53d3f09a2e 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -301,7 +301,6 @@ impl_stable_hash_for!(struct ty::FieldDef { impl_stable_hash_for!( impl<'tcx> for enum mir::interpret::ConstValue<'tcx> [ mir::interpret::ConstValue ] { - Unevaluated(def_id, substs), Scalar(val), ScalarPair(a, b), ByRef(id, alloc, offset), @@ -378,6 +377,11 @@ impl_stable_hash_for!(struct ty::Const<'tcx> { val }); +impl_stable_hash_for!(impl<'tcx> for enum ty::LazyConst<'tcx> [ty::LazyConst] { + Unevaluated(did, substs), + Evaluated(c) +}); + impl_stable_hash_for!(enum mir::interpret::ErrorHandled { Reported, TooGeneric diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index 19be0c08ef13b..c3fe5d773ab16 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -37,7 +37,7 @@ impl ErrorHandled { } pub type ConstEvalRawResult<'tcx> = Result, ErrorHandled>; -pub type ConstEvalResult<'tcx> = Result<&'tcx ty::Const<'tcx>, ErrorHandled>; +pub type ConstEvalResult<'tcx> = Result, ErrorHandled>; #[derive(Clone, Debug, RustcEncodable, RustcDecodable)] pub struct ConstEvalErr<'tcx> { diff --git a/src/librustc/mir/interpret/value.rs b/src/librustc/mir/interpret/value.rs index 1e4cfedc2a6ae..26a8e63254008 100644 --- a/src/librustc/mir/interpret/value.rs +++ b/src/librustc/mir/interpret/value.rs @@ -1,7 +1,6 @@ use std::fmt; -use crate::ty::{Ty, subst::Substs, layout::{HasDataLayout, Size}}; -use crate::hir::def_id::DefId; +use crate::ty::{Ty, layout::{HasDataLayout, Size}}; use super::{EvalResult, Pointer, PointerArithmetic, Allocation, AllocId, sign_extend, truncate}; @@ -18,12 +17,6 @@ pub struct RawConst<'tcx> { /// matches the LocalValue optimizations for easy conversions between Value and ConstValue. #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash)] pub enum ConstValue<'tcx> { - /// Never returned from the `const_eval` query, but the HIR contains these frequently in order - /// to allow HIR creation to happen for everything before needing to be able to run constant - /// evaluation - /// FIXME: The query should then return a type that does not even have this variant. - Unevaluated(DefId, &'tcx Substs<'tcx>), - /// Used only for types with layout::abi::Scalar ABI and ZSTs /// /// Not using the enum `Value` to encode that this must not be `Undef` @@ -43,7 +36,6 @@ impl<'tcx> ConstValue<'tcx> { #[inline] pub fn try_to_scalar(&self) -> Option { match *self { - ConstValue::Unevaluated(..) | ConstValue::ByRef(..) | ConstValue::ScalarPair(..) => None, ConstValue::Scalar(val) => Some(val), diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 2936405ebd0b7..a1a6e890b1292 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -1666,7 +1666,7 @@ impl<'tcx> TerminatorKind<'tcx> { ), ty: switch_ty, }; - fmt_const_val(&mut s, &c).unwrap(); + fmt_const_val(&mut s, c).unwrap(); s.into() }).chain(iter::once("otherwise".into())) .collect() @@ -2154,7 +2154,9 @@ impl<'tcx> Operand<'tcx> { span, ty, user_ty: None, - literal: ty::Const::zero_sized(tcx, ty), + literal: tcx.intern_lazy_const( + ty::LazyConst::Evaluated(ty::Const::zero_sized(ty)), + ), }) } @@ -2457,7 +2459,7 @@ pub struct Constant<'tcx> { /// Needed for NLL to impose user-given type constraints. pub user_ty: Option, - pub literal: &'tcx ty::Const<'tcx>, + pub literal: &'tcx ty::LazyConst<'tcx>, } /// A collection of projections into user types. @@ -2655,12 +2657,20 @@ newtype_index! { impl<'tcx> Debug for Constant<'tcx> { fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { write!(fmt, "const ")?; - fmt_const_val(fmt, self.literal) + fmt_lazy_const_val(fmt, self.literal) + } +} + +/// Write a `ConstValue` in a way closer to the original source code than the `Debug` output. +pub fn fmt_lazy_const_val(f: &mut impl Write, const_val: &ty::LazyConst<'_>) -> fmt::Result { + match *const_val { + ty::LazyConst::Unevaluated(..) => write!(f, "{:?}", const_val), + ty::LazyConst::Evaluated(c) => fmt_const_val(f, c), } } /// Write a `ConstValue` in a way closer to the original source code than the `Debug` output. -pub fn fmt_const_val(f: &mut impl Write, const_val: &ty::Const<'_>) -> fmt::Result { +pub fn fmt_const_val(f: &mut impl Write, const_val: ty::Const<'_>) -> fmt::Result { use ty::TyKind::*; let value = const_val.val; let ty = const_val.ty; diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 67f85fbc8679e..a0fae3aa927ce 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -233,7 +233,7 @@ macro_rules! make_mir_visitor { } fn visit_const(&mut self, - constant: & $($mutability)* &'tcx ty::Const<'tcx>, + constant: & $($mutability)* &'tcx ty::LazyConst<'tcx>, _: Location) { self.super_const(constant); } @@ -892,7 +892,7 @@ macro_rules! make_mir_visitor { fn super_region(&mut self, _region: & $($mutability)* ty::Region<'tcx>) { } - fn super_const(&mut self, _const: & $($mutability)* &'tcx ty::Const<'tcx>) { + fn super_const(&mut self, _const: & $($mutability)* &'tcx ty::LazyConst<'tcx>) { } fn super_substs(&mut self, _substs: & $($mutability)* &'tcx Substs<'tcx>) { diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 21352ac1053a8..c0f50ecd28824 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -418,9 +418,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { Some(format!("[{}]", self.tcx.type_of(def.did).to_string())), )); let tcx = self.tcx; - if let Some(len) = len.val.try_to_scalar().and_then(|scalar| { - scalar.to_usize(&tcx).ok() - }) { + if let Some(len) = len.assert_usize(tcx) { flags.push(( "_Self".to_owned(), Some(format!("[{}; {}]", self.tcx.type_of(def.did).to_string(), len)), diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index 732ca70dc78c5..bec45046cb93e 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -15,7 +15,6 @@ use super::util; use hir::def_id::DefId; use infer::{InferCtxt, InferOk, LateBoundRegionConversionTime}; use infer::type_variable::TypeVariableOrigin; -use mir::interpret::ConstValue; use mir::interpret::{GlobalId}; use rustc_data_structures::snapshot_map::{Snapshot, SnapshotMap}; use syntax::ast::Ident; @@ -394,8 +393,8 @@ impl<'a, 'b, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for AssociatedTypeNormalizer<'a, } } - fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { - if let ConstValue::Unevaluated(def_id, substs) = constant.val { + fn fold_const(&mut self, constant: &'tcx ty::LazyConst<'tcx>) -> &'tcx ty::LazyConst<'tcx> { + if let ty::LazyConst::Unevaluated(def_id, substs) = *constant { let tcx = self.selcx.tcx().global_tcx(); if let Some(param_env) = self.tcx().lift_to_global(&self.param_env) { if substs.needs_infer() || substs.has_placeholders() { @@ -407,8 +406,9 @@ impl<'a, 'b, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for AssociatedTypeNormalizer<'a, promoted: None }; if let Ok(evaluated) = tcx.const_eval(param_env.and(cid)) { - let evaluated = evaluated.subst(self.tcx(), substs); - return self.fold_const(evaluated); + let substs = tcx.lift_to_global(&substs).unwrap(); + let evaluated = evaluated.subst(tcx, substs); + return tcx.intern_lazy_const(ty::LazyConst::Evaluated(evaluated)); } } } else { @@ -420,7 +420,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for AssociatedTypeNormalizer<'a, promoted: None }; if let Ok(evaluated) = tcx.const_eval(param_env.and(cid)) { - return self.fold_const(evaluated) + return tcx.intern_lazy_const(ty::LazyConst::Evaluated(evaluated)); } } } diff --git a/src/librustc/traits/query/normalize.rs b/src/librustc/traits/query/normalize.rs index 0d126d37546d6..be05445cfc61a 100644 --- a/src/librustc/traits/query/normalize.rs +++ b/src/librustc/traits/query/normalize.rs @@ -5,7 +5,7 @@ use infer::at::At; use infer::canonical::OriginalQueryValues; use infer::{InferCtxt, InferOk}; -use mir::interpret::{ConstValue, GlobalId}; +use mir::interpret::GlobalId; use traits::project::Normalized; use traits::{Obligation, ObligationCause, PredicateObligation, Reveal}; use ty::fold::{TypeFoldable, TypeFolder}; @@ -188,8 +188,8 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for QueryNormalizer<'cx, 'gcx, 'tcx } } - fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { - if let ConstValue::Unevaluated(def_id, substs) = constant.val { + fn fold_const(&mut self, constant: &'tcx ty::LazyConst<'tcx>) -> &'tcx ty::LazyConst<'tcx> { + if let ty::LazyConst::Unevaluated(def_id, substs) = *constant { let tcx = self.infcx.tcx.global_tcx(); if let Some(param_env) = self.tcx().lift_to_global(&self.param_env) { if substs.needs_infer() || substs.has_placeholders() { @@ -201,8 +201,9 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for QueryNormalizer<'cx, 'gcx, 'tcx promoted: None, }; if let Ok(evaluated) = tcx.const_eval(param_env.and(cid)) { - let evaluated = evaluated.subst(self.tcx(), substs); - return self.fold_const(evaluated); + let substs = tcx.lift_to_global(&substs).unwrap(); + let evaluated = evaluated.subst(tcx, substs); + return tcx.intern_lazy_const(ty::LazyConst::Evaluated(evaluated)); } } } else { @@ -214,7 +215,7 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for QueryNormalizer<'cx, 'gcx, 'tcx promoted: None, }; if let Ok(evaluated) = tcx.const_eval(param_env.and(cid)) { - return self.fold_const(evaluated) + return tcx.intern_lazy_const(ty::LazyConst::Evaluated(evaluated)); } } } diff --git a/src/librustc/ty/codec.rs b/src/librustc/ty/codec.rs index 6429e3249c4c5..e0e4d9c362a6c 100644 --- a/src/librustc/ty/codec.rs +++ b/src/librustc/ty/codec.rs @@ -247,12 +247,12 @@ pub fn decode_canonical_var_infos<'a, 'tcx, D>(decoder: &mut D) } #[inline] -pub fn decode_const<'a, 'tcx, D>(decoder: &mut D) - -> Result<&'tcx ty::Const<'tcx>, D::Error> +pub fn decode_lazy_const<'a, 'tcx, D>(decoder: &mut D) + -> Result<&'tcx ty::LazyConst<'tcx>, D::Error> where D: TyDecoder<'a, 'tcx>, 'tcx: 'a, { - Ok(decoder.tcx().mk_const(Decodable::decode(decoder)?)) + Ok(decoder.tcx().intern_lazy_const(Decodable::decode(decoder)?)) } #[inline] @@ -389,10 +389,10 @@ macro_rules! implement_ty_decoder { } } - impl<$($typaram),*> SpecializedDecoder<&'tcx $crate::ty::Const<'tcx>> + impl<$($typaram),*> SpecializedDecoder<&'tcx $crate::ty::LazyConst<'tcx>> for $DecoderName<$($typaram),*> { - fn specialized_decode(&mut self) -> Result<&'tcx ty::Const<'tcx>, Self::Error> { - decode_const(self) + fn specialized_decode(&mut self) -> Result<&'tcx ty::LazyConst<'tcx>, Self::Error> { + decode_lazy_const(self) } } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 32348e2e5046d..6c377941dad19 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -29,7 +29,7 @@ use traits; use traits::{Clause, Clauses, GoalKind, Goal, Goals}; use ty::{self, Ty, TypeAndMut}; use ty::{TyS, TyKind, List}; -use ty::{AdtKind, AdtDef, ClosureSubsts, GeneratorSubsts, Region, Const}; +use ty::{AdtKind, AdtDef, ClosureSubsts, GeneratorSubsts, Region, Const, LazyConst}; use ty::{PolyFnSig, InferTy, ParamTy, ProjectionTy, ExistentialPredicate, Predicate}; use ty::RegionKind; use ty::{TyVar, TyVid, IntVar, IntVid, FloatVar, FloatVid}; @@ -122,7 +122,6 @@ pub struct CtxtInterners<'tcx> { region: InternedSet<'tcx, RegionKind>, existential_predicates: InternedSet<'tcx, List>>, predicates: InternedSet<'tcx, List>>, - const_: InternedSet<'tcx, Const<'tcx>>, clauses: InternedSet<'tcx, List>>, goal: InternedSet<'tcx, GoalKind<'tcx>>, goal_list: InternedSet<'tcx, List>>, @@ -140,7 +139,6 @@ impl<'gcx: 'tcx, 'tcx> CtxtInterners<'tcx> { existential_predicates: Default::default(), canonical_var_infos: Default::default(), predicates: Default::default(), - const_: Default::default(), clauses: Default::default(), goal: Default::default(), goal_list: Default::default(), @@ -1063,32 +1061,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.global_arenas.adt_def.alloc(def) } - pub fn alloc_byte_array(self, bytes: &[u8]) -> &'gcx [u8] { - if bytes.is_empty() { - &[] - } else { - self.global_interners.arena.alloc_slice(bytes) - } - } - - pub fn alloc_const_slice(self, values: &[&'tcx ty::Const<'tcx>]) - -> &'tcx [&'tcx ty::Const<'tcx>] { - if values.is_empty() { - &[] - } else { - self.interners.arena.alloc_slice(values) - } - } - - pub fn alloc_name_const_slice(self, values: &[(ast::Name, &'tcx ty::Const<'tcx>)]) - -> &'tcx [(ast::Name, &'tcx ty::Const<'tcx>)] { - if values.is_empty() { - &[] - } else { - self.interners.arena.alloc_slice(values) - } - } - pub fn intern_const_alloc( self, alloc: Allocation, @@ -1112,6 +1084,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { }) } + pub fn intern_lazy_const(self, c: ty::LazyConst<'tcx>) -> &'tcx ty::LazyConst<'tcx> { + self.global_interners.arena.alloc(c) + } + pub fn intern_layout(self, layout: LayoutDetails) -> &'gcx LayoutDetails { self.layout_interner.borrow_mut().intern(layout, |layout| { self.global_arenas.layout.alloc(layout) @@ -1725,218 +1701,69 @@ pub trait Lift<'tcx>: fmt::Debug { fn lift_to_tcx<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option; } -impl<'a, 'tcx> Lift<'tcx> for Ty<'a> { - type Lifted = Ty<'tcx>; - fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option> { - if tcx.interners.arena.in_arena(*self as *const _) { - return Some(unsafe { mem::transmute(*self) }); - } - // Also try in the global tcx if we're not that. - if !tcx.is_global() { - self.lift_to_tcx(tcx.global_tcx()) - } else { - None - } - } -} - -impl<'a, 'tcx> Lift<'tcx> for Region<'a> { - type Lifted = Region<'tcx>; - fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option> { - if tcx.interners.arena.in_arena(*self as *const _) { - return Some(unsafe { mem::transmute(*self) }); - } - // Also try in the global tcx if we're not that. - if !tcx.is_global() { - self.lift_to_tcx(tcx.global_tcx()) - } else { - None - } - } -} - -impl<'a, 'tcx> Lift<'tcx> for Goal<'a> { - type Lifted = Goal<'tcx>; - fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option> { - if tcx.interners.arena.in_arena(*self as *const _) { - return Some(unsafe { mem::transmute(*self) }); - } - // Also try in the global tcx if we're not that. - if !tcx.is_global() { - self.lift_to_tcx(tcx.global_tcx()) - } else { - None - } - } -} - -impl<'a, 'tcx> Lift<'tcx> for &'a List> { - type Lifted = &'tcx List>; - fn lift_to_tcx<'b, 'gcx>( - &self, - tcx: TyCtxt<'b, 'gcx, 'tcx>, - ) -> Option<&'tcx List>> { - if self.is_empty() { - return Some(List::empty()); - } - - if tcx.interners.arena.in_arena(*self as *const _) { - return Some(unsafe { mem::transmute(*self) }); - } - // Also try in the global tcx if we're not that. - if !tcx.is_global() { - self.lift_to_tcx(tcx.global_tcx()) - } else { - None - } - } -} - -impl<'a, 'tcx> Lift<'tcx> for &'a List> { - type Lifted = &'tcx List>; - fn lift_to_tcx<'b, 'gcx>( - &self, - tcx: TyCtxt<'b, 'gcx, 'tcx>, - ) -> Option<&'tcx List>> { - if self.is_empty() { - return Some(List::empty()); - } - - if tcx.interners.arena.in_arena(*self as *const _) { - return Some(unsafe { mem::transmute(*self) }); - } - // Also try in the global tcx if we're not that. - if !tcx.is_global() { - self.lift_to_tcx(tcx.global_tcx()) - } else { - None - } - } -} -impl<'a, 'tcx> Lift<'tcx> for &'a Const<'a> { - type Lifted = &'tcx Const<'tcx>; - fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<&'tcx Const<'tcx>> { - if tcx.interners.arena.in_arena(*self as *const _) { - return Some(unsafe { mem::transmute(*self) }); - } - // Also try in the global tcx if we're not that. - if !tcx.is_global() { - self.lift_to_tcx(tcx.global_tcx()) - } else { - None +macro_rules! nop_lift { + ($ty:ty => $lifted:ty) => { + impl<'a, 'tcx> Lift<'tcx> for $ty { + type Lifted = $lifted; + fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { + if tcx.interners.arena.in_arena(*self as *const _) { + return Some(unsafe { mem::transmute(*self) }); + } + // Also try in the global tcx if we're not that. + if !tcx.is_global() { + self.lift_to_tcx(tcx.global_tcx()) + } else { + None + } + } } - } + }; } -impl<'a, 'tcx> Lift<'tcx> for &'a Substs<'a> { - type Lifted = &'tcx Substs<'tcx>; - fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<&'tcx Substs<'tcx>> { - if self.len() == 0 { - return Some(List::empty()); - } - if tcx.interners.arena.in_arena(&self[..] as *const _) { - return Some(unsafe { mem::transmute(*self) }); - } - // Also try in the global tcx if we're not that. - if !tcx.is_global() { - self.lift_to_tcx(tcx.global_tcx()) - } else { - None +macro_rules! nop_list_lift { + ($ty:ty => $lifted:ty) => { + impl<'a, 'tcx> Lift<'tcx> for &'a List<$ty> { + type Lifted = &'tcx List<$lifted>; + fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { + if self.is_empty() { + return Some(List::empty()); + } + if tcx.interners.arena.in_arena(*self as *const _) { + return Some(unsafe { mem::transmute(*self) }); + } + // Also try in the global tcx if we're not that. + if !tcx.is_global() { + self.lift_to_tcx(tcx.global_tcx()) + } else { + None + } + } } - } + }; } -impl<'a, 'tcx> Lift<'tcx> for &'a List> { - type Lifted = &'tcx List>; - fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) - -> Option<&'tcx List>> { - if self.len() == 0 { - return Some(List::empty()); - } - if tcx.interners.arena.in_arena(*self as *const _) { - return Some(unsafe { mem::transmute(*self) }); - } - // Also try in the global tcx if we're not that. - if !tcx.is_global() { - self.lift_to_tcx(tcx.global_tcx()) - } else { - None - } - } -} +nop_lift!{Ty<'a> => Ty<'tcx>} +nop_lift!{Region<'a> => Region<'tcx>} +nop_lift!{Goal<'a> => Goal<'tcx>} +nop_lift!{&'a LazyConst<'a> => &'tcx LazyConst<'tcx>} -impl<'a, 'tcx> Lift<'tcx> for &'a List> { - type Lifted = &'tcx List>; - fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) - -> Option<&'tcx List>> { - if self.is_empty() { - return Some(List::empty()); - } - if tcx.interners.arena.in_arena(*self as *const _) { - return Some(unsafe { mem::transmute(*self) }); - } - // Also try in the global tcx if we're not that. - if !tcx.is_global() { - self.lift_to_tcx(tcx.global_tcx()) - } else { - None - } - } -} +nop_list_lift!{Goal<'a> => Goal<'tcx>} +nop_list_lift!{Clause<'a> => Clause<'tcx>} +nop_list_lift!{Ty<'a> => Ty<'tcx>} +nop_list_lift!{ExistentialPredicate<'a> => ExistentialPredicate<'tcx>} +nop_list_lift!{Predicate<'a> => Predicate<'tcx>} +nop_list_lift!{CanonicalVarInfo => CanonicalVarInfo} +nop_list_lift!{ProjectionKind<'a> => ProjectionKind<'tcx>} -impl<'a, 'tcx> Lift<'tcx> for &'a List> { - type Lifted = &'tcx List>; - fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) - -> Option<&'tcx List>> { - if self.is_empty() { - return Some(List::empty()); - } - if tcx.interners.arena.in_arena(*self as *const _) { - return Some(unsafe { mem::transmute(*self) }); - } - // Also try in the global tcx if we're not that. - if !tcx.is_global() { - self.lift_to_tcx(tcx.global_tcx()) - } else { - None - } - } -} +// this is the impl for `&'a Substs<'a>` +nop_list_lift!{Kind<'a> => Kind<'tcx>} -impl<'a, 'tcx> Lift<'tcx> for &'a List { - type Lifted = &'tcx List; +impl<'a, 'tcx> Lift<'tcx> for &'a mir::interpret::Allocation { + type Lifted = &'tcx mir::interpret::Allocation; fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { - if self.len() == 0 { - return Some(List::empty()); - } - if tcx.interners.arena.in_arena(*self as *const _) { - return Some(unsafe { mem::transmute(*self) }); - } - // Also try in the global tcx if we're not that. - if !tcx.is_global() { - self.lift_to_tcx(tcx.global_tcx()) - } else { - None - } - } -} - -impl<'a, 'tcx> Lift<'tcx> for &'a List> { - type Lifted = &'tcx List>; - fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { - if self.len() == 0 { - return Some(List::empty()); - } - if tcx.interners.arena.in_arena(*self as *const _) { - return Some(unsafe { mem::transmute(*self) }); - } - // Also try in the global tcx if we're not that. - if !tcx.is_global() { - self.lift_to_tcx(tcx.global_tcx()) - } else { - None - } + assert!(tcx.global_arenas.const_allocs.in_arena(*self as *const _)); + Some(unsafe { mem::transmute(*self) }) } } @@ -2497,7 +2324,6 @@ pub fn keep_local<'tcx, T: ty::TypeFoldable<'tcx>>(x: &T) -> bool { direct_interners!('tcx, region: mk_region(|r: &RegionKind| r.keep_in_local_tcx()) -> RegionKind, - const_: mk_const(|c: &Const<'_>| keep_local(&c.ty) || keep_local(&c.val)) -> Const<'tcx>, goal: mk_goal(|c: &GoalKind<'_>| keep_local(c)) -> GoalKind<'tcx> ); @@ -2683,7 +2509,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { #[inline] pub fn mk_array(self, ty: Ty<'tcx>, n: u64) -> Ty<'tcx> { - self.mk_ty(Array(ty, ty::Const::from_usize(self, n))) + self.mk_ty(Array(ty, self.intern_lazy_const( + ty::LazyConst::Evaluated(ty::Const::from_usize(self.global_tcx(), n)) + ))) } #[inline] diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index 76e102d88d7ce..0d6d9f91eb4e4 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -157,11 +157,12 @@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> { ty::Adt(def, _) => format!("{} `{}`", def.descr(), tcx.item_path_str(def.did)).into(), ty::Foreign(def_id) => format!("extern type `{}`", tcx.item_path_str(def_id)).into(), - ty::Array(_, n) => { - match n.assert_usize(tcx) { + ty::Array(_, n) => match n { + ty::LazyConst::Evaluated(n) => match n.assert_usize(tcx) { Some(n) => format!("array of {} elements", n).into(), None => "array".into(), - } + }, + ty::LazyConst::Unevaluated(..) => "array".into(), } ty::Slice(_) => "slice".into(), ty::RawPtr(_) => "*-ptr".into(), diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index 6ee24187e3326..4fa13a01d5a92 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -1,4 +1,3 @@ -use mir::interpret::ConstValue; use ty::subst::Substs; use ty::{self, Ty, TypeFlags, TypeFoldable}; @@ -173,7 +172,10 @@ impl FlagComputation { &ty::Array(tt, len) => { self.add_ty(tt); - self.add_const(len); + if let ty::LazyConst::Unevaluated(_, substs) = len { + self.add_flags(TypeFlags::HAS_PROJECTION); + self.add_substs(substs); + } } &ty::Slice(tt) => { @@ -230,14 +232,6 @@ impl FlagComputation { } } - fn add_const(&mut self, constant: &ty::Const<'_>) { - self.add_ty(constant.ty); - if let ConstValue::Unevaluated(_, substs) = constant.val { - self.add_flags(TypeFlags::HAS_PROJECTION); - self.add_substs(substs); - } - } - fn add_existential_projection(&mut self, projection: &ty::ExistentialProjection<'_>) { self.add_substs(projection.substs); self.add_ty(projection.ty); diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs index 0a72f733b51e5..4495e9654c984 100644 --- a/src/librustc/ty/fold.rs +++ b/src/librustc/ty/fold.rs @@ -29,7 +29,6 @@ //! These methods return true to indicate that the visitor has found what it is looking for //! and does not need to visit anything else. -use mir::interpret::ConstValue; use hir::def_id::DefId; use ty::{self, Binder, Ty, TyCtxt, TypeFlags}; @@ -164,7 +163,7 @@ pub trait TypeFolder<'gcx: 'tcx, 'tcx> : Sized { r.super_fold_with(self) } - fn fold_const(&mut self, c: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { + fn fold_const(&mut self, c: &'tcx ty::LazyConst<'tcx>) -> &'tcx ty::LazyConst<'tcx> { c.super_fold_with(self) } } @@ -182,7 +181,7 @@ pub trait TypeVisitor<'tcx> : Sized { r.super_visit_with(self) } - fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool { + fn visit_const(&mut self, c: &'tcx ty::LazyConst<'tcx>) -> bool { c.super_visit_with(self) } } @@ -864,8 +863,8 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { flags.intersects(self.flags) } - fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool { - if let ConstValue::Unevaluated(..) = c.val { + fn visit_const(&mut self, c: &'tcx ty::LazyConst<'tcx>) -> bool { + if let ty::LazyConst::Unevaluated(..) = c { let projection_flags = TypeFlags::HAS_NORMALIZABLE_PROJECTION | TypeFlags::HAS_PROJECTION; if projection_flags.intersects(self.flags) { diff --git a/src/librustc/ty/inhabitedness/mod.rs b/src/librustc/ty/inhabitedness/mod.rs index 29d201c1179e5..6dfc9681cfd86 100644 --- a/src/librustc/ty/inhabitedness/mod.rs +++ b/src/librustc/ty/inhabitedness/mod.rs @@ -1,6 +1,6 @@ use ty::context::TyCtxt; use ty::{AdtDef, VariantDef, FieldDef, Ty, TyS}; -use ty::{DefId, Substs}; +use ty::{self, DefId, Substs}; use ty::{AdtKind, Visibility}; use ty::TyKind::*; @@ -213,11 +213,14 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } Array(ty, len) => { - match len.assert_usize(tcx) { - // If the array is definitely non-empty, it's uninhabited if - // the type of its elements is uninhabited. - Some(n) if n != 0 => ty.uninhabited_from(tcx), - _ => DefIdForest::empty() + match len { + ty::LazyConst::Unevaluated(..) => DefIdForest::empty(), + ty::LazyConst::Evaluated(len) => match len.assert_usize(tcx) { + // If the array is definitely non-empty, it's uninhabited if + // the type of its elements is uninhabited. + Some(n) if n != 0 => ty.uninhabited_from(tcx), + _ => DefIdForest::empty() + }, } } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index d40dd830e9fb9..20167bd41fb87 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -59,7 +59,7 @@ pub use self::sty::{InferTy, ParamTy, ProjectionTy, ExistentialPredicate}; pub use self::sty::{ClosureSubsts, GeneratorSubsts, UpvarSubsts, TypeAndMut}; pub use self::sty::{TraitRef, TyKind, PolyTraitRef}; pub use self::sty::{ExistentialTraitRef, PolyExistentialTraitRef}; -pub use self::sty::{ExistentialProjection, PolyExistentialProjection, Const}; +pub use self::sty::{ExistentialProjection, PolyExistentialProjection, Const, LazyConst}; pub use self::sty::{BoundRegion, EarlyBoundRegion, FreeRegion, Region}; pub use self::sty::RegionKind; pub use self::sty::{TyVid, IntVid, FloatVid, RegionVid}; diff --git a/src/librustc/ty/query/keys.rs b/src/librustc/ty/query/keys.rs index 959a5ff5767a3..af6f5a00dee5c 100644 --- a/src/librustc/ty/query/keys.rs +++ b/src/librustc/ty/query/keys.rs @@ -136,7 +136,7 @@ impl<'tcx> Key for ty::PolyTraitRef<'tcx>{ } } -impl<'tcx> Key for &'tcx ty::Const<'tcx> { +impl<'tcx> Key for ty::Const<'tcx> { fn query_crate(&self) -> CrateNum { LOCAL_CRATE } diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index 84e15a751353e..6d310a9500a62 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -5,7 +5,6 @@ //! subtyping, type equality, etc. use hir::def_id::DefId; -use mir::interpret::ConstValue; use ty::subst::{Kind, UnpackedKind, Substs}; use ty::{self, Ty, TyCtxt, TypeFoldable}; use ty::error::{ExpectedFound, TypeError}; @@ -480,14 +479,9 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R, (&ty::Array(a_t, sz_a), &ty::Array(b_t, sz_b)) => { let t = relation.relate(&a_t, &b_t)?; - assert_eq!(sz_a.ty, tcx.types.usize); - assert_eq!(sz_b.ty, tcx.types.usize); - let to_u64 = |x: &'tcx ty::Const<'tcx>| -> Result { - if let Some(s) = x.assert_usize(tcx) { - return Ok(s); - } - match x.val { - ConstValue::Unevaluated(def_id, substs) => { + let to_u64 = |x: ty::LazyConst<'tcx>| -> Result { + match x { + ty::LazyConst::Unevaluated(def_id, substs) => { // FIXME(eddyb) get the right param_env. let param_env = ty::ParamEnv::empty(); if let Some(substs) = tcx.lift_to_global(&substs) { @@ -513,14 +507,14 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R, "array length could not be evaluated"); Err(ErrorReported) } - _ => { + ty::LazyConst::Evaluated(c) => c.assert_usize(tcx).ok_or_else(|| { tcx.sess.delay_span_bug(DUMMY_SP, - &format!("arrays should not have {:?} as length", x)); - Err(ErrorReported) - } + "array length could not be evaluated"); + ErrorReported + }) } }; - match (to_u64(sz_a), to_u64(sz_b)) { + match (to_u64(*sz_a), to_u64(*sz_b)) { (Ok(sz_a_u64), Ok(sz_b_u64)) => { if sz_a_u64 == sz_b_u64 { Ok(tcx.mk_ty(ty::Array(t, sz_a))) diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index f9b43f42d5298..258470bf6f860 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -486,6 +486,26 @@ BraceStructLiftImpl! { } } +BraceStructLiftImpl! { + impl<'a, 'tcx> Lift<'tcx> for ty::Const<'a> { + type Lifted = ty::Const<'tcx>; + val, ty + } +} + +impl<'a, 'tcx> Lift<'tcx> for ConstValue<'a> { + type Lifted = ConstValue<'tcx>; + fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { + match *self { + ConstValue::Scalar(x) => Some(ConstValue::Scalar(x)), + ConstValue::ScalarPair(x, y) => Some(ConstValue::ScalarPair(x, y)), + ConstValue::ByRef(x, alloc, z) => Some(ConstValue::ByRef( + x, alloc.lift_to_tcx(tcx)?, z, + )), + } + } +} + /////////////////////////////////////////////////////////////////////////// // TypeFoldable implementations. // @@ -1014,47 +1034,54 @@ EnumTypeFoldableImpl! { } } -impl<'tcx> TypeFoldable<'tcx> for ConstValue<'tcx> { +impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::LazyConst<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - match *self { - ConstValue::Scalar(v) => ConstValue::Scalar(v), - ConstValue::ScalarPair(a, b) => ConstValue::ScalarPair(a, b), - ConstValue::ByRef(id, alloc, offset) => ConstValue::ByRef(id, alloc, offset), - ConstValue::Unevaluated(def_id, substs) => { - ConstValue::Unevaluated(def_id, substs.fold_with(folder)) + let new = match self { + ty::LazyConst::Evaluated(v) => ty::LazyConst::Evaluated(v.fold_with(folder)), + ty::LazyConst::Unevaluated(def_id, substs) => { + ty::LazyConst::Unevaluated(*def_id, substs.fold_with(folder)) } - } + }; + folder.tcx().intern_lazy_const(new) + } + + fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + folder.fold_const(*self) } fn super_visit_with>(&self, visitor: &mut V) -> bool { match *self { - ConstValue::Scalar(_) | - ConstValue::ScalarPair(_, _) | - ConstValue::ByRef(_, _, _) => false, - ConstValue::Unevaluated(_, substs) => substs.visit_with(visitor), + ty::LazyConst::Evaluated(c) => c.visit_with(visitor), + ty::LazyConst::Unevaluated(_, substs) => substs.visit_with(visitor), } } + + fn visit_with>(&self, visitor: &mut V) -> bool { + visitor.visit_const(self) + } } -impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Const<'tcx> { +impl<'tcx> TypeFoldable<'tcx> for ty::Const<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { let ty = self.ty.fold_with(folder); let val = self.val.fold_with(folder); - folder.tcx().mk_const(ty::Const { + ty::Const { ty, val - }) - } - - fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - folder.fold_const(*self) + } } fn super_visit_with>(&self, visitor: &mut V) -> bool { self.ty.visit_with(visitor) || self.val.visit_with(visitor) } +} - fn visit_with>(&self, visitor: &mut V) -> bool { - visitor.visit_const(self) +impl<'tcx> TypeFoldable<'tcx> for ConstValue<'tcx> { + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, _folder: &mut F) -> Self { + *self + } + + fn super_visit_with>(&self, _visitor: &mut V) -> bool { + false } } diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index a2720bdf385cd..ebaf6a73e34d4 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -113,7 +113,7 @@ pub enum TyKind<'tcx> { Str, /// An array with the given length. Written as `[T; n]`. - Array(Ty<'tcx>, &'tcx ty::Const<'tcx>), + Array(Ty<'tcx>, &'tcx ty::LazyConst<'tcx>), /// The pointee of an array slice. Written as `[T]`. Slice(Ty<'tcx>), @@ -2020,6 +2020,32 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } } +#[derive(Copy, Clone, Debug, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq, Ord, PartialOrd)] +/// Used in the HIR by using `Unevaluated` everywhere and later normalizing to `Evaluated` if the +/// code is monomorphic enough for that. +pub enum LazyConst<'tcx> { + Unevaluated(DefId, &'tcx Substs<'tcx>), + Evaluated(Const<'tcx>), +} + +impl<'tcx> LazyConst<'tcx> { + pub fn map_evaluated(self, f: impl FnOnce(Const<'tcx>) -> Option) -> Option { + match self { + LazyConst::Evaluated(c) => f(c), + LazyConst::Unevaluated(..) => None, + } + } + + pub fn assert_usize(self, tcx: TyCtxt<'_, '_, '_>) -> Option { + self.map_evaluated(|c| c.assert_usize(tcx)) + } + + #[inline] + pub fn unwrap_usize(&self, tcx: TyCtxt<'_, '_, '_>) -> u64 { + self.assert_usize(tcx).expect("expected `LazyConst` to contain a usize") + } +} + /// Typed constant value. #[derive(Copy, Clone, Debug, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq, Ord, PartialOrd)] pub struct Const<'tcx> { @@ -2029,37 +2055,15 @@ pub struct Const<'tcx> { } impl<'tcx> Const<'tcx> { - pub fn unevaluated( - tcx: TyCtxt<'_, '_, 'tcx>, - def_id: DefId, - substs: &'tcx Substs<'tcx>, - ty: Ty<'tcx>, - ) -> &'tcx Self { - tcx.mk_const(Const { - val: ConstValue::Unevaluated(def_id, substs), - ty, - }) - } - - #[inline] - pub fn from_const_value( - tcx: TyCtxt<'_, '_, 'tcx>, - val: ConstValue<'tcx>, - ty: Ty<'tcx>, - ) -> &'tcx Self { - tcx.mk_const(Const { - val, - ty, - }) - } - #[inline] pub fn from_scalar( - tcx: TyCtxt<'_, '_, 'tcx>, val: Scalar, ty: Ty<'tcx>, - ) -> &'tcx Self { - Self::from_const_value(tcx, ConstValue::Scalar(val), ty) + ) -> Self { + Self { + val: ConstValue::Scalar(val), + ty, + } } #[inline] @@ -2067,7 +2071,7 @@ impl<'tcx> Const<'tcx> { tcx: TyCtxt<'_, '_, 'tcx>, bits: u128, ty: ParamEnvAnd<'tcx, Ty<'tcx>>, - ) -> &'tcx Self { + ) -> Self { let ty = tcx.lift_to_global(&ty).unwrap(); let size = tcx.layout_of(ty).unwrap_or_else(|e| { panic!("could not compute layout for {:?}: {:?}", ty, e) @@ -2075,21 +2079,21 @@ impl<'tcx> Const<'tcx> { let shift = 128 - size.bits(); let truncated = (bits << shift) >> shift; assert_eq!(truncated, bits, "from_bits called with untruncated value"); - Self::from_scalar(tcx, Scalar::Bits { bits, size: size.bytes() as u8 }, ty.value) + Self::from_scalar(Scalar::Bits { bits, size: size.bytes() as u8 }, ty.value) } #[inline] - pub fn zero_sized(tcx: TyCtxt<'_, '_, 'tcx>, ty: Ty<'tcx>) -> &'tcx Self { - Self::from_scalar(tcx, Scalar::Bits { bits: 0, size: 0 }, ty) + pub fn zero_sized(ty: Ty<'tcx>) -> Self { + Self::from_scalar(Scalar::Bits { bits: 0, size: 0 }, ty) } #[inline] - pub fn from_bool(tcx: TyCtxt<'_, '_, 'tcx>, v: bool) -> &'tcx Self { + pub fn from_bool(tcx: TyCtxt<'_, '_, 'tcx>, v: bool) -> Self { Self::from_bits(tcx, v as u128, ParamEnv::empty().and(tcx.types.bool)) } #[inline] - pub fn from_usize(tcx: TyCtxt<'_, '_, 'tcx>, n: u64) -> &'tcx Self { + pub fn from_usize(tcx: TyCtxt<'_, '_, 'tcx>, n: u64) -> Self { Self::from_bits(tcx, n as u128, ParamEnv::empty().and(tcx.types.usize)) } @@ -2155,4 +2159,4 @@ impl<'tcx> Const<'tcx> { } } -impl<'tcx> serialize::UseSpecializedDecodable for &'tcx Const<'tcx> {} +impl<'tcx> serialize::UseSpecializedDecodable for &'tcx LazyConst<'tcx> {} diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index ac062a2378611..e989ef823e979 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -7,7 +7,7 @@ use hir::{self, Node}; use ich::NodeIdHashingMode; use traits::{self, ObligationCause}; use ty::{self, Ty, TyCtxt, GenericParamDefKind, TypeFoldable}; -use ty::subst::{Substs, UnpackedKind}; +use ty::subst::{Subst, Substs, UnpackedKind}; use ty::query::TyCtxtAt; use ty::TyKind::*; use ty::layout::{Integer, IntegerExt}; @@ -15,7 +15,7 @@ use util::common::ErrorReported; use middle::lang_items; use rustc_data_structures::stable_hasher::{StableHasher, HashStable}; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use std::{cmp, fmt}; use syntax::ast; use syntax::attr::{self, SignedInt, UnsignedInt}; @@ -618,6 +618,76 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } } + + /// Expands the given impl trait type, stopping if the type is recursive. + pub fn try_expand_impl_trait_type( + self, + def_id: DefId, + substs: &'tcx Substs<'tcx>, + ) -> Result, Ty<'tcx>> { + use crate::ty::fold::TypeFolder; + + struct OpaqueTypeExpander<'a, 'gcx, 'tcx> { + // Contains the DefIds of the opaque types that are currently being + // expanded. When we expand an opaque type we insert the DefId of + // that type, and when we finish expanding that type we remove the + // its DefId. + seen_opaque_tys: FxHashSet, + primary_def_id: DefId, + found_recursion: bool, + tcx: TyCtxt<'a, 'gcx, 'tcx>, + } + + impl<'a, 'gcx, 'tcx> OpaqueTypeExpander<'a, 'gcx, 'tcx> { + fn expand_opaque_ty( + &mut self, + def_id: DefId, + substs: &'tcx Substs<'tcx>, + ) -> Option> { + if self.found_recursion { + None + } else if self.seen_opaque_tys.insert(def_id) { + let generic_ty = self.tcx.type_of(def_id); + let concrete_ty = generic_ty.subst(self.tcx, substs); + let expanded_ty = self.fold_ty(concrete_ty); + self.seen_opaque_tys.remove(&def_id); + Some(expanded_ty) + } else { + // If another opaque type that we contain is recursive, then it + // will report the error, so we don't have to. + self.found_recursion = def_id == self.primary_def_id; + None + } + } + } + + impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for OpaqueTypeExpander<'a, 'gcx, 'tcx> { + fn tcx(&self) -> TyCtxt<'_, 'gcx, 'tcx> { + self.tcx + } + + fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { + if let ty::Opaque(def_id, substs) = t.sty { + self.expand_opaque_ty(def_id, substs).unwrap_or(t) + } else { + t.super_fold_with(self) + } + } + } + + let mut visitor = OpaqueTypeExpander { + seen_opaque_tys: FxHashSet::default(), + primary_def_id: def_id, + found_recursion: false, + tcx: self, + }; + let expanded_type = visitor.expand_opaque_ty(def_id, substs).unwrap(); + if visitor.found_recursion { + Err(expanded_type) + } else { + Ok(expanded_type) + } + } } impl<'a, 'tcx> ty::TyS<'tcx> { diff --git a/src/librustc/ty/walk.rs b/src/librustc/ty/walk.rs index a2cc859e4a82d..6887d092fcd62 100644 --- a/src/librustc/ty/walk.rs +++ b/src/librustc/ty/walk.rs @@ -1,7 +1,6 @@ //! An iterator over the type substructure. //! WARNING: this does not keep track of the region depth. -use mir::interpret::ConstValue; use ty::{self, Ty}; use smallvec::{self, SmallVec}; @@ -75,7 +74,9 @@ fn push_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent_ty: Ty<'tcx>) { ty::Placeholder(..) | ty::Bound(..) | ty::Foreign(..) => { } ty::Array(ty, len) => { - push_const(stack, len); + if let ty::LazyConst::Unevaluated(_, substs) = len { + stack.extend(substs.types().rev()); + } stack.push(ty); } ty::Slice(ty) => { @@ -128,10 +129,3 @@ fn push_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent_ty: Ty<'tcx>) { } } } - -fn push_const<'tcx>(stack: &mut TypeWalkerStack<'tcx>, constant: &'tcx ty::Const<'tcx>) { - if let ConstValue::Unevaluated(_, substs) = constant.val { - stack.extend(substs.types().rev()); - } - stack.push(constant.ty); -} diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index aacc63c47de61..517cfd9edfaf9 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -1,5 +1,4 @@ use hir::def_id::DefId; -use mir::interpret::ConstValue; use infer::InferCtxt; use ty::subst::Substs; use traits; @@ -202,11 +201,10 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { } } - /// Pushes the obligations required for a constant value to be WF + /// Pushes the obligations required for an array length to be WF /// into `self.out`. - fn compute_const(&mut self, constant: &'tcx ty::Const<'tcx>) { - self.require_sized(constant.ty, traits::ConstSized); - if let ConstValue::Unevaluated(def_id, substs) = constant.val { + fn compute_array_len(&mut self, constant: ty::LazyConst<'tcx>) { + if let ty::LazyConst::Unevaluated(def_id, substs) = constant { let obligations = self.nominal_obligations(def_id, substs); self.out.extend(obligations); @@ -260,8 +258,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { ty::Array(subty, len) => { self.require_sized(subty, traits::SliceOrArrayElem); - assert_eq!(len.ty, self.infcx.tcx.types.usize); - self.compute_const(len); + self.compute_array_len(*len); } ty::Tuple(ref tys) => { diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 79405b124001d..37bc9397d904b 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -1,6 +1,5 @@ use hir::def_id::DefId; use hir::map::definitions::DefPathData; -use mir::interpret::ConstValue; use middle::region; use ty::subst::{self, Subst}; use ty::{BrAnon, BrEnv, BrFresh, BrNamed}; @@ -1325,6 +1324,8 @@ define_print! { } if !is_sized { write!(f, "{}?Sized", if first { " " } else { "+" })?; + } else if first { + write!(f, " Sized")?; } Ok(()) }) @@ -1410,12 +1411,12 @@ define_print! { }), Array(ty, sz) => { print!(f, cx, write("["), print(ty), write("; "))?; - match sz.val { - ConstValue::Unevaluated(_def_id, _substs) => { + match sz { + ty::LazyConst::Unevaluated(_def_id, _substs) => { write!(f, "_")?; } - _ => ty::tls::with(|tcx| { - write!(f, "{}", sz.unwrap_usize(tcx)) + ty::LazyConst::Evaluated(c) => ty::tls::with(|tcx| { + write!(f, "{}", c.unwrap_usize(tcx)) })?, } write!(f, "]") diff --git a/src/librustc_codegen_ssa/mir/constant.rs b/src/librustc_codegen_ssa/mir/constant.rs index 1a48ad87a6e15..e6d6ef1d7a38b 100644 --- a/src/librustc_codegen_ssa/mir/constant.rs +++ b/src/librustc_codegen_ssa/mir/constant.rs @@ -2,7 +2,7 @@ use rustc::mir::interpret::ErrorHandled; use rustc_mir::const_eval::const_field; use rustc::mir; use rustc_data_structures::indexed_vec::Idx; -use rustc::mir::interpret::{GlobalId, ConstValue}; +use rustc::mir::interpret::GlobalId; use rustc::ty::{self, Ty}; use rustc::ty::layout; use syntax::source_map::Span; @@ -14,10 +14,10 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { fn fully_evaluate( &mut self, bx: &Bx, - constant: &'tcx ty::Const<'tcx>, - ) -> Result<&'tcx ty::Const<'tcx>, ErrorHandled> { - match constant.val { - ConstValue::Unevaluated(def_id, ref substs) => { + constant: &'tcx ty::LazyConst<'tcx>, + ) -> Result, ErrorHandled> { + match *constant { + ty::LazyConst::Unevaluated(def_id, ref substs) => { let tcx = bx.tcx(); let param_env = ty::ParamEnv::reveal_all(); let instance = ty::Instance::resolve(tcx, param_env, def_id, substs).unwrap(); @@ -27,7 +27,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { }; tcx.const_eval(param_env.and(cid)) }, - _ => Ok(constant), + ty::LazyConst::Evaluated(constant) => Ok(constant), } } @@ -35,7 +35,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { &mut self, bx: &Bx, constant: &mir::Constant<'tcx>, - ) -> Result<&'tcx ty::Const<'tcx>, ErrorHandled> { + ) -> Result, ErrorHandled> { let c = self.monomorphize(&constant.literal); self.fully_evaluate(bx, c) } @@ -46,7 +46,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx: &Bx, span: Span, ty: Ty<'tcx>, - constant: Result<&'tcx ty::Const<'tcx>, ErrorHandled>, + constant: Result, ErrorHandled>, ) -> (Bx::Value, Ty<'tcx>) { constant .and_then(|c| { diff --git a/src/librustc_codegen_ssa/mir/operand.rs b/src/librustc_codegen_ssa/mir/operand.rs index 1dbed30842a82..2026e042ef0eb 100644 --- a/src/librustc_codegen_ssa/mir/operand.rs +++ b/src/librustc_codegen_ssa/mir/operand.rs @@ -67,7 +67,7 @@ impl<'a, 'tcx: 'a, V: CodegenObject> OperandRef<'tcx, V> { pub fn from_const>( bx: &mut Bx, - val: &'tcx ty::Const<'tcx> + val: ty::Const<'tcx> ) -> Result { let layout = bx.cx().layout_of(val.ty); @@ -76,7 +76,6 @@ impl<'a, 'tcx: 'a, V: CodegenObject> OperandRef<'tcx, V> { } let val = match val.val { - ConstValue::Unevaluated(..) => bug!(), ConstValue::Scalar(x) => { let scalar = match layout.abi { layout::Abi::Scalar(ref x) => x, diff --git a/src/librustc_lint/nonstandard_style.rs b/src/librustc_lint/nonstandard_style.rs index 2694a04b94ce4..7eca5867bd3b2 100644 --- a/src/librustc_lint/nonstandard_style.rs +++ b/src/librustc_lint/nonstandard_style.rs @@ -89,9 +89,11 @@ impl NonCamelCaseTypes { if !is_camel_case(name) { let c = to_camel_case(&name.as_str()); let m = if c.is_empty() { - format!("{} `{}` should have a camel case name such as `CamelCase`", sort, name) + format!("{} `{}` should have an upper camel case name such as + `CamelCase`", sort, name) } else { - format!("{} `{}` should have a camel case name such as `{}`", sort, name, c) + format!("{} `{}` should have an upper camel case name such as + `{}`", sort, name, c) }; cx.span_lint(NON_CAMEL_CASE_TYPES, span, &m); } diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs index 83cd28bbdc58c..ad8abe16415ed 100644 --- a/src/librustc_mir/borrow_check/error_reporting.rs +++ b/src/librustc_mir/borrow_check/error_reporting.rs @@ -1380,7 +1380,10 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { ); if let TerminatorKind::Call { func: Operand::Constant(box Constant { - literal: ty::Const { ty: &ty::TyS { sty: ty::TyKind::FnDef(id, _), .. }, .. }, + literal: ty::LazyConst::Evaluated(ty::Const { + ty: &ty::TyS { sty: ty::TyKind::FnDef(id, _), .. }, + .. + }), .. }), args, diff --git a/src/librustc_mir/borrow_check/mutability_errors.rs b/src/librustc_mir/borrow_check/mutability_errors.rs index 0be8ecffcdf38..63bf6faed40d4 100644 --- a/src/librustc_mir/borrow_check/mutability_errors.rs +++ b/src/librustc_mir/borrow_check/mutability_errors.rs @@ -468,13 +468,13 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { Terminator { kind: TerminatorKind::Call { func: Operand::Constant(box Constant { - literal: Const { + literal: ty::LazyConst::Evaluated(Const { ty: &TyS { sty: TyKind::FnDef(id, substs), .. }, .. - }, + }), .. }), .. diff --git a/src/librustc_mir/borrow_check/nll/renumber.rs b/src/librustc_mir/borrow_check/nll/renumber.rs index 55af7399aab8f..5c24da7621b2d 100644 --- a/src/librustc_mir/borrow_check/nll/renumber.rs +++ b/src/librustc_mir/borrow_check/nll/renumber.rs @@ -88,7 +88,7 @@ impl<'a, 'gcx, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'gcx, 'tcx> { debug!("visit_region: region={:?}", region); } - fn visit_const(&mut self, constant: &mut &'tcx ty::Const<'tcx>, _location: Location) { + fn visit_const(&mut self, constant: &mut &'tcx ty::LazyConst<'tcx>, _location: Location) { *constant = self.renumber_regions(&*constant); } diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index b3e1237a45087..180aa1907e8d1 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -382,6 +382,11 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { constant, location ); + let literal = match constant.literal { + ty::LazyConst::Evaluated(lit) => lit, + ty::LazyConst::Unevaluated(..) => return, + }; + // FIXME(#46702) -- We need some way to get the predicates // associated with the "pre-evaluated" form of the // constant. For example, consider that the constant @@ -390,7 +395,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { // constraints on `'a` and `'b`. These constraints // would be lost if we just look at the normalized // value. - if let ty::FnDef(def_id, substs) = constant.literal.ty.sty { + if let ty::FnDef(def_id, substs) = literal.ty.sty { let tcx = self.tcx(); let type_checker = &mut self.cx; @@ -411,10 +416,10 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { ); } - debug!("sanitize_constant: expected_ty={:?}", constant.literal.ty); + debug!("sanitize_constant: expected_ty={:?}", literal.ty); if let Err(terr) = self.cx.eq_types( - constant.literal.ty, + literal.ty, constant.ty, location.to_locations(), ConstraintCategory::Boring, @@ -424,7 +429,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { constant, "constant {:?} should have type {:?} but has {:?} ({:?})", constant, - constant.literal.ty, + literal.ty, constant.ty, terr, ); diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index 7dcac05e702a3..a66da50c48437 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -270,11 +270,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { span: expr_span, ty: this.hir.tcx().types.u32, user_ty: None, - literal: ty::Const::from_bits( - this.hir.tcx(), - 0, - ty::ParamEnv::empty().and(this.hir.tcx().types.u32), - ), + literal: this.hir.tcx().intern_lazy_const(ty::LazyConst::Evaluated( + ty::Const::from_bits( + this.hir.tcx(), + 0, + ty::ParamEnv::empty().and(this.hir.tcx().types.u32), + ), + )), })); box AggregateKind::Generator(closure_id, substs, movability) } diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index fe5bc6e19db65..409b6c038ab69 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -658,12 +658,12 @@ enum TestKind<'tcx> { SwitchInt { switch_ty: Ty<'tcx>, options: Vec, - indices: FxHashMap<&'tcx ty::Const<'tcx>, usize>, + indices: FxHashMap, usize>, }, // test for equality Eq { - value: &'tcx ty::Const<'tcx>, + value: ty::Const<'tcx>, ty: Ty<'tcx>, }, diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index 21109a223bf77..aae3de68aaae0 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -101,7 +101,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { candidate: &Candidate<'pat, 'tcx>, switch_ty: Ty<'tcx>, options: &mut Vec, - indices: &mut FxHashMap<&'tcx ty::Const<'tcx>, usize>) + indices: &mut FxHashMap, usize>) -> bool { let match_pair = match candidate.match_pairs.iter().find(|mp| mp.place == *test_place) { @@ -302,6 +302,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } let eq_def_id = self.hir.tcx().lang_items().eq_trait().unwrap(); let (mty, method) = self.hir.trait_method(eq_def_id, "eq", ty, &[ty.into()]); + let method = self.hir.tcx().intern_lazy_const(ty::LazyConst::Evaluated(method)); // take the argument by reference let region_scope = self.topmost_scope(); @@ -657,7 +658,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { } } - (&TestKind::Range(range), &PatternKind::Constant { ref value }) => { + (&TestKind::Range(range), &PatternKind::Constant { value }) => { if self.const_range_contains(range, value) == Some(false) { // `value` is not contained in the testing range, // so `value` can be matched only if this test fails. @@ -786,7 +787,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { fn const_range_contains( &self, range: PatternRange<'tcx>, - value: &'tcx ty::Const<'tcx>, + value: ty::Const<'tcx>, ) -> Option { use std::cmp::Ordering::*; @@ -806,9 +807,9 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { fn values_not_contained_in_range( &self, range: PatternRange<'tcx>, - indices: &FxHashMap<&'tcx ty::Const<'tcx>, usize>, + indices: &FxHashMap, usize>, ) -> Option { - for val in indices.keys() { + for &val in indices.keys() { if self.const_range_contains(range, val)? { return Some(false); } diff --git a/src/librustc_mir/build/misc.rs b/src/librustc_mir/build/misc.rs index 5b20d412f0dd5..c849c02242840 100644 --- a/src/librustc_mir/build/misc.rs +++ b/src/librustc_mir/build/misc.rs @@ -27,13 +27,13 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { pub fn literal_operand(&mut self, span: Span, ty: Ty<'tcx>, - literal: &'tcx ty::Const<'tcx>) + literal: ty::Const<'tcx>) -> Operand<'tcx> { let constant = box Constant { span, ty, user_ty: None, - literal, + literal: self.hir.tcx().intern_lazy_const(ty::LazyConst::Evaluated(literal)), }; Operand::Constant(constant) } diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 8acdecf6fa248..727b769cf4d44 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -202,7 +202,7 @@ impl<'a, 'gcx: 'tcx, 'tcx> MutVisitor<'tcx> for GlobalizeMir<'a, 'gcx> { } } - fn visit_const(&mut self, constant: &mut &'tcx ty::Const<'tcx>, _: Location) { + fn visit_const(&mut self, constant: &mut &'tcx ty::LazyConst<'tcx>, _: Location) { if let Some(lifted) = self.tcx.lift(constant) { *constant = lifted; } else { diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index b9432997b7e19..01177e5e49a0e 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval.rs @@ -95,7 +95,7 @@ pub fn op_to_const<'tcx>( ecx: &CompileTimeEvalContext<'_, '_, 'tcx>, op: OpTy<'tcx>, may_normalize: bool, -) -> EvalResult<'tcx, &'tcx ty::Const<'tcx>> { +) -> EvalResult<'tcx, ty::Const<'tcx>> { // We do not normalize just any data. Only scalar layout and fat pointers. let normalize = may_normalize && match op.layout.abi { @@ -134,14 +134,16 @@ pub fn op_to_const<'tcx>( Ok(Immediate::ScalarPair(a, b)) => ConstValue::ScalarPair(a.not_undef()?, b.not_undef()?), }; - Ok(ty::Const::from_const_value(ecx.tcx.tcx, val, op.layout.ty)) + Ok(ty::Const { val, ty: op.layout.ty }) } -pub fn const_to_op<'tcx>( + +pub fn lazy_const_to_op<'tcx>( ecx: &CompileTimeEvalContext<'_, '_, 'tcx>, - cnst: &ty::Const<'tcx>, + cnst: ty::LazyConst<'tcx>, + ty: ty::Ty<'tcx>, ) -> EvalResult<'tcx, OpTy<'tcx>> { - let op = ecx.const_value_to_op(cnst.val)?; - Ok(OpTy { op, layout: ecx.layout_of(cnst.ty)? }) + let op = ecx.const_value_to_op(cnst)?; + Ok(OpTy { op, layout: ecx.layout_of(ty)? }) } fn eval_body_and_ecx<'a, 'mir, 'tcx>( @@ -508,13 +510,13 @@ pub fn const_field<'a, 'tcx>( instance: ty::Instance<'tcx>, variant: Option, field: mir::Field, - value: &'tcx ty::Const<'tcx>, + value: ty::Const<'tcx>, ) -> ::rustc::mir::interpret::ConstEvalResult<'tcx> { trace!("const_field: {:?}, {:?}, {:?}", instance, field, value); let ecx = mk_eval_cx(tcx, instance, param_env).unwrap(); let result = (|| { // get the operand again - let op = const_to_op(&ecx, value)?; + let op = lazy_const_to_op(&ecx, ty::LazyConst::Evaluated(value), value.ty)?; // downcast let down = match variant { None => op, @@ -537,11 +539,11 @@ pub fn const_variant_index<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, instance: ty::Instance<'tcx>, - val: &'tcx ty::Const<'tcx>, + val: ty::Const<'tcx>, ) -> EvalResult<'tcx, VariantIdx> { trace!("const_variant_index: {:?}, {:?}", instance, val); let ecx = mk_eval_cx(tcx, instance, param_env).unwrap(); - let op = const_to_op(&ecx, val)?; + let op = lazy_const_to_op(&ecx, ty::LazyConst::Evaluated(val), val.ty)?; Ok(ecx.read_discriminant(op)?.1) } diff --git a/src/librustc_mir/hair/constant.rs b/src/librustc_mir/hair/constant.rs index c98ef31c2bae2..37d741d2606d5 100644 --- a/src/librustc_mir/hair/constant.rs +++ b/src/librustc_mir/hair/constant.rs @@ -14,7 +14,7 @@ crate fn lit_to_const<'a, 'gcx, 'tcx>( tcx: TyCtxt<'a, 'gcx, 'tcx>, ty: Ty<'tcx>, neg: bool, -) -> Result<&'tcx ty::Const<'tcx>, LitToConstError> { +) -> Result, LitToConstError> { use syntax::ast::*; let trunc = |n| { @@ -64,7 +64,7 @@ crate fn lit_to_const<'a, 'gcx, 'tcx>( LitKind::Bool(b) => ConstValue::Scalar(Scalar::from_bool(b)), LitKind::Char(c) => ConstValue::Scalar(Scalar::from_char(c)), }; - Ok(ty::Const::from_const_value(tcx, lit, ty)) + Ok(ty::Const { val: lit, ty }) } fn parse_float<'tcx>( diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 293058a0f26f5..532e6783f2f2b 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -356,7 +356,9 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } hir::ExprKind::Lit(ref lit) => ExprKind::Literal { - literal: cx.const_eval_literal(&lit.node, expr_ty, lit.span, false), + literal: cx.tcx.intern_lazy_const(ty::LazyConst::Evaluated( + cx.const_eval_literal(&lit.node, expr_ty, lit.span, false) + )), user_ty: None, }, @@ -454,7 +456,9 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } else { if let hir::ExprKind::Lit(ref lit) = arg.node { ExprKind::Literal { - literal: cx.const_eval_literal(&lit.node, expr_ty, lit.span, true), + literal: cx.tcx.intern_lazy_const(ty::LazyConst::Evaluated( + cx.const_eval_literal(&lit.node, expr_ty, lit.span, true) + )), user_ty: None, } } else { @@ -711,24 +715,22 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, temp_lifetime, ty: var_ty, span: expr.span, - kind: ExprKind::Literal { literal, user_ty: None }, + kind: ExprKind::Literal { + literal: cx.tcx.intern_lazy_const(literal), + user_ty: None + }, }.to_ref(); - let offset = mk_const(ty::Const::from_bits( + let offset = mk_const(ty::LazyConst::Evaluated(ty::Const::from_bits( cx.tcx, offset as u128, cx.param_env.and(var_ty), - )); + ))); match did { Some(did) => { // in case we are offsetting from a computed discriminant // and not the beginning of discriminants (which is always `0`) let substs = Substs::identity_for_item(cx.tcx(), did); - let lhs = mk_const(ty::Const::unevaluated( - cx.tcx(), - did, - substs, - var_ty, - )); + let lhs = mk_const(ty::LazyConst::Unevaluated(did, substs)); let bin = ExprKind::Binary { op: BinOp::Add, lhs, @@ -868,7 +870,9 @@ fn method_callee<'a, 'gcx, 'tcx>( ty, span, kind: ExprKind::Literal { - literal: ty::Const::zero_sized(cx.tcx(), ty), + literal: cx.tcx().intern_lazy_const(ty::LazyConst::Evaluated( + ty::Const::zero_sized(ty) + )), user_ty, }, } @@ -928,10 +932,9 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, let user_ty = user_substs_applied_to_def(cx, expr.hir_id, &def); debug!("convert_path_expr: user_ty={:?}", user_ty); ExprKind::Literal { - literal: ty::Const::zero_sized( - cx.tcx, + literal: cx.tcx.intern_lazy_const(ty::LazyConst::Evaluated(ty::Const::zero_sized( cx.tables().node_id_to_type(expr.hir_id), - ), + ))), user_ty, } }, @@ -941,12 +944,7 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, let user_ty = user_substs_applied_to_def(cx, expr.hir_id, &def); debug!("convert_path_expr: (const) user_ty={:?}", user_ty); ExprKind::Literal { - literal: ty::Const::unevaluated( - cx.tcx, - def_id, - substs, - cx.tables().node_id_to_type(expr.hir_id), - ), + literal: cx.tcx.intern_lazy_const(ty::LazyConst::Unevaluated(def_id, substs)), user_ty, } }, diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs index 07f3c38c62c52..6113d88e09591 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -108,8 +108,8 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { self.tcx.types.usize } - pub fn usize_literal(&mut self, value: u64) -> &'tcx ty::Const<'tcx> { - ty::Const::from_usize(self.tcx, value) + pub fn usize_literal(&mut self, value: u64) -> &'tcx ty::LazyConst<'tcx> { + self.tcx.intern_lazy_const(ty::LazyConst::Evaluated(ty::Const::from_usize(self.tcx, value))) } pub fn bool_ty(&mut self) -> Ty<'tcx> { @@ -120,12 +120,12 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { self.tcx.mk_unit() } - pub fn true_literal(&mut self) -> &'tcx ty::Const<'tcx> { - ty::Const::from_bool(self.tcx, true) + pub fn true_literal(&mut self) -> &'tcx ty::LazyConst<'tcx> { + self.tcx.intern_lazy_const(ty::LazyConst::Evaluated(ty::Const::from_bool(self.tcx, true))) } - pub fn false_literal(&mut self) -> &'tcx ty::Const<'tcx> { - ty::Const::from_bool(self.tcx, false) + pub fn false_literal(&mut self) -> &'tcx ty::LazyConst<'tcx> { + self.tcx.intern_lazy_const(ty::LazyConst::Evaluated(ty::Const::from_bool(self.tcx, false))) } pub fn const_eval_literal( @@ -134,7 +134,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { ty: Ty<'tcx>, sp: Span, neg: bool, - ) -> &'tcx ty::Const<'tcx> { + ) -> ty::Const<'tcx> { trace!("const_eval_literal: {:#?}, {:?}, {:?}, {:?}", lit, ty, sp, neg); match lit_to_const(lit, self.tcx, ty, neg) { @@ -169,14 +169,14 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { method_name: &str, self_ty: Ty<'tcx>, params: &[Kind<'tcx>]) - -> (Ty<'tcx>, &'tcx ty::Const<'tcx>) { + -> (Ty<'tcx>, ty::Const<'tcx>) { let method_name = Symbol::intern(method_name); let substs = self.tcx.mk_substs_trait(self_ty, params); for item in self.tcx.associated_items(trait_def_id) { if item.kind == ty::AssociatedKind::Method && item.ident.name == method_name { let method_ty = self.tcx.type_of(item.def_id); let method_ty = method_ty.subst(self.tcx, substs); - return (method_ty, ty::Const::zero_sized(self.tcx, method_ty)); + return (method_ty, ty::Const::zero_sized(method_ty)); } } diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs index b56e3d4e77395..676b98457489f 100644 --- a/src/librustc_mir/hair/mod.rs +++ b/src/librustc_mir/hair/mod.rs @@ -9,7 +9,7 @@ use rustc::hir::def_id::DefId; use rustc::infer::canonical::Canonical; use rustc::middle::region; use rustc::ty::subst::Substs; -use rustc::ty::{AdtDef, UpvarSubsts, Region, Ty, Const, UserTypeAnnotation}; +use rustc::ty::{AdtDef, UpvarSubsts, Region, Ty, Const, LazyConst, UserTypeAnnotation}; use rustc::ty::layout::VariantIdx; use rustc::hir; use syntax::ast; @@ -288,7 +288,7 @@ pub enum ExprKind<'tcx> { movability: Option, }, Literal { - literal: &'tcx Const<'tcx>, + literal: &'tcx LazyConst<'tcx>, user_ty: Option>>, }, InlineAsm { diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs index 13838e5d85dda..b25d47b390175 100644 --- a/src/librustc_mir/hair/pattern/_match.rs +++ b/src/librustc_mir/hair/pattern/_match.rs @@ -223,7 +223,7 @@ impl<'a, 'tcx> LiteralExpander<'a, 'tcx> { assert_eq!(t, u); ConstValue::ScalarPair( Scalar::Ptr(p), - n.val.try_to_scalar().unwrap(), + n.map_evaluated(|val| val.val.try_to_scalar()).unwrap(), ) }, // fat pointers stay the same @@ -251,11 +251,10 @@ impl<'a, 'tcx> PatternFolder<'tcx> for LiteralExpander<'a, 'tcx> { subpattern: Pattern { ty: rty, span: pat.span, - kind: box PatternKind::Constant { value: Const::from_const_value( - self.tcx, - self.fold_const_value_deref(*val, rty, crty), - rty, - ) }, + kind: box PatternKind::Constant { value: Const { + val: self.fold_const_value_deref(val, rty, crty), + ty: rty, + } }, } } } @@ -420,7 +419,7 @@ pub enum Constructor<'tcx> { /// Enum variants. Variant(DefId), /// Literal values. - ConstantValue(&'tcx ty::Const<'tcx>), + ConstantValue(ty::Const<'tcx>), /// Ranges of literal values (`2...5` and `2..5`). ConstantRange(u128, u128, Ty<'tcx>, RangeEnd), /// Array patterns of length n. @@ -1396,7 +1395,7 @@ fn constructor_sub_pattern_tys<'a, 'tcx: 'a>(cx: &MatchCheckCtxt<'a, 'tcx>, fn slice_pat_covered_by_const<'tcx>( tcx: TyCtxt<'_, 'tcx, '_>, _span: Span, - const_val: &ty::Const<'tcx>, + const_val: ty::Const<'tcx>, prefix: &[Pattern<'tcx>], slice: &Option>, suffix: &[Pattern<'tcx>] @@ -1751,23 +1750,37 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>( // necessarily point to memory, they are usually just integers. The only time // they should be pointing to memory is when they are subslices of nonzero // slices - let (opt_ptr, n, ty) = match (value.val, &value.ty.sty) { - (ConstValue::ByRef(id, alloc, offset), ty::TyKind::Array(t, n)) => ( - Some(( - Pointer::new(id, offset), - alloc, - )), - n.unwrap_usize(cx.tcx), - t, - ), - (ConstValue::ScalarPair(ptr, n), ty::TyKind::Slice(t)) => ( - ptr.to_ptr().ok().map(|ptr| ( - ptr, - cx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id), - )), - n.to_bits(cx.tcx.data_layout.pointer_size).unwrap() as u64, - t, - ), + let (opt_ptr, n, ty) = match value.ty.sty { + ty::TyKind::Array(t, n) => { + match value.val { + ConstValue::ByRef(id, alloc, offset) => ( + Some((Pointer::new(id, offset), alloc)), + n.unwrap_usize(cx.tcx), + t, + ), + _ => span_bug!( + pat.span, + "array pattern is {:?}", value, + ), + } + }, + ty::TyKind::Slice(t) => { + match value.val { + ConstValue::ScalarPair(ptr, n) => ( + ptr.to_ptr().ok().map(|ptr| ( + ptr, + cx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id), + )), + n.to_bits(cx.tcx.data_layout.pointer_size).unwrap() as u64, + t, + ), + _ => span_bug!( + pat.span, + "slice pattern constant must be scalar pair but is {:?}", + value, + ), + } + }, _ => span_bug!( pat.span, "unexpected const-val {:?} with ctor {:?}", @@ -1787,7 +1800,7 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>( &cx.tcx, ptr, layout.size, ).ok()?; let scalar = scalar.not_undef().ok()?; - let value = ty::Const::from_scalar(cx.tcx, scalar, ty); + let value = ty::Const::from_scalar(scalar, ty); let pattern = Pattern { ty, span: pat.span, diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index 10d2d7bc1b18b..f52aeded19ae7 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -123,7 +123,7 @@ pub enum PatternKind<'tcx> { }, Constant { - value: &'tcx ty::Const<'tcx>, + value: ty::Const<'tcx>, }, Range(PatternRange<'tcx>), @@ -147,8 +147,8 @@ pub enum PatternKind<'tcx> { #[derive(Clone, Copy, Debug, PartialEq)] pub struct PatternRange<'tcx> { - pub lo: &'tcx ty::Const<'tcx>, - pub hi: &'tcx ty::Const<'tcx>, + pub lo: ty::Const<'tcx>, + pub hi: ty::Const<'tcx>, pub ty: Ty<'tcx>, pub end: RangeEnd, } @@ -857,7 +857,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { fn const_to_pat( &self, instance: ty::Instance<'tcx>, - cv: &'tcx ty::Const<'tcx>, + cv: ty::Const<'tcx>, id: hir::HirId, span: Span, ) -> Pattern<'tcx> { @@ -1018,7 +1018,7 @@ macro_rules! CloneImpls { } CloneImpls!{ <'tcx> - Span, Field, Mutability, ast::Name, ast::NodeId, usize, &'tcx ty::Const<'tcx>, + Span, Field, Mutability, ast::Name, ast::NodeId, usize, ty::Const<'tcx>, Region<'tcx>, Ty<'tcx>, BindingMode<'tcx>, &'tcx AdtDef, &'tcx Substs<'tcx>, &'tcx Kind<'tcx>, UserTypeAnnotation<'tcx>, UserTypeProjection<'tcx>, PatternTypeProjection<'tcx> @@ -1140,8 +1140,8 @@ impl<'tcx> PatternFoldable<'tcx> for PatternKind<'tcx> { pub fn compare_const_vals<'a, 'gcx, 'tcx>( tcx: TyCtxt<'a, 'gcx, 'tcx>, - a: &'tcx ty::Const<'tcx>, - b: &'tcx ty::Const<'tcx>, + a: ty::Const<'tcx>, + b: ty::Const<'tcx>, ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>, ) -> Option { trace!("compare_const_vals: {:?}, {:?}", a, b); diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 1ea3f78c2104f..04e0955ad6172 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -3,7 +3,7 @@ use std::convert::TryInto; -use rustc::mir; +use rustc::{mir, ty}; use rustc::ty::layout::{self, Size, LayoutOf, TyLayout, HasDataLayout, IntegerExt, VariantIdx}; use rustc::mir::interpret::{ @@ -517,7 +517,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> let ty = self.monomorphize(mir_op.ty(self.mir(), *self.tcx), self.substs()); self.layout_of(ty) })?; - let op = self.const_value_to_op(constant.literal.val)?; + let op = self.const_value_to_op(*constant.literal)?; OpTy { op, layout } } }; @@ -540,17 +540,20 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> // `eval_operand`, ideally). pub(crate) fn const_value_to_op( &self, - val: ConstValue<'tcx>, + val: ty::LazyConst<'tcx>, ) -> EvalResult<'tcx, Operand> { trace!("const_value_to_op: {:?}", val); - match val { - ConstValue::Unevaluated(def_id, substs) => { + let val = match val { + ty::LazyConst::Unevaluated(def_id, substs) => { let instance = self.resolve(def_id, substs)?; - Ok(*OpTy::from(self.const_eval_raw(GlobalId { + return Ok(*OpTy::from(self.const_eval_raw(GlobalId { instance, promoted: None, - })?)) - } + })?)); + }, + ty::LazyConst::Evaluated(c) => c, + }; + match val.val { ConstValue::ByRef(id, alloc, offset) => { // We rely on mutability being set correctly in that allocation to prevent writes // where none should happen -- and for `static mut`, we copy on demand anyway. diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index d81a4d6a4bc84..eabfd47c9fb90 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -381,7 +381,7 @@ fn collect_items_rec<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let param_env = ty::ParamEnv::reveal_all(); if let Ok(val) = tcx.const_eval(param_env.and(cid)) { - collect_const(tcx, val, instance.substs, &mut neighbors); + collect_const(tcx, val, &mut neighbors); } } MonoItem::Fn(instance) => { @@ -583,10 +583,10 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { self.super_rvalue(rvalue, location); } - fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, location: Location) { + fn visit_const(&mut self, constant: &&'tcx ty::LazyConst<'tcx>, location: Location) { debug!("visiting const {:?} @ {:?}", *constant, location); - collect_const(self.tcx, constant, self.param_substs, self.output); + collect_lazy_const(self.tcx, constant, self.param_substs, self.output); self.super_const(constant); } @@ -987,7 +987,7 @@ impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> { let param_env = ty::ParamEnv::reveal_all(); if let Ok(val) = self.tcx.const_eval(param_env.and(cid)) { - collect_const(self.tcx, val, instance.substs, &mut self.output); + collect_const(self.tcx, val, &mut self.output); } } hir::ItemKind::Fn(..) => { @@ -1198,7 +1198,7 @@ fn collect_neighbours<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, promoted: Some(i), }; match tcx.const_eval(param_env.and(cid)) { - Ok(val) => collect_const(tcx, val, instance.substs, output), + Ok(val) => collect_const(tcx, val, output), Err(ErrorHandled::Reported) => {}, Err(ErrorHandled::TooGeneric) => span_bug!( mir.promoted[i].span, "collection encountered polymorphic constant", @@ -1216,43 +1216,48 @@ fn def_id_to_string<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, output } -fn collect_const<'a, 'tcx>( +fn collect_lazy_const<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, - constant: &ty::Const<'tcx>, + constant: &ty::LazyConst<'tcx>, param_substs: &'tcx Substs<'tcx>, output: &mut Vec>, ) { - debug!("visiting const {:?}", *constant); + let (def_id, substs) = match *constant { + ty::LazyConst::Evaluated(c) => return collect_const(tcx, c, output), + ty::LazyConst::Unevaluated(did, substs) => (did, substs), + }; + let param_env = ty::ParamEnv::reveal_all(); + let substs = tcx.subst_and_normalize_erasing_regions( + param_substs, + param_env, + &substs, + ); + let instance = ty::Instance::resolve(tcx, + param_env, + def_id, + substs).unwrap(); + + let cid = GlobalId { + instance, + promoted: None, + }; + match tcx.const_eval(param_env.and(cid)) { + Ok(val) => collect_const(tcx, val, output), + Err(ErrorHandled::Reported) => {}, + Err(ErrorHandled::TooGeneric) => span_bug!( + tcx.def_span(def_id), "collection encountered polymorphic constant", + ), + } +} - let val = match constant.val { - ConstValue::Unevaluated(def_id, substs) => { - let param_env = ty::ParamEnv::reveal_all(); - let substs = tcx.subst_and_normalize_erasing_regions( - param_substs, - param_env, - &substs, - ); - let instance = ty::Instance::resolve(tcx, - param_env, - def_id, - substs).unwrap(); +fn collect_const<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + constant: ty::Const<'tcx>, + output: &mut Vec>, +) { + debug!("visiting const {:?}", constant); - let cid = GlobalId { - instance, - promoted: None, - }; - match tcx.const_eval(param_env.and(cid)) { - Ok(val) => val.val, - Err(ErrorHandled::Reported) => return, - Err(ErrorHandled::TooGeneric) => span_bug!( - tcx.def_span(def_id), "collection encountered polymorphic constant", - ), - } - }, - _ => constant.val, - }; - match val { - ConstValue::Unevaluated(..) => bug!("const eval yielded unevaluated const"), + match constant.val { ConstValue::ScalarPair(Scalar::Ptr(a), Scalar::Ptr(b)) => { collect_miri(tcx, a.alloc_id, output); collect_miri(tcx, b.alloc_id, output); diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index 2aa44cc181a56..751815eab287b 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -459,7 +459,9 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> { span: self.span, ty: func_ty, user_ty: None, - literal: ty::Const::zero_sized(self.tcx, func_ty), + literal: tcx.intern_lazy_const(ty::LazyConst::Evaluated( + ty::Const::zero_sized(func_ty), + )), }); let ref_loc = self.make_place( @@ -519,7 +521,9 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> { span: self.span, ty: self.tcx.types.usize, user_ty: None, - literal: ty::Const::from_usize(self.tcx, value), + literal: self.tcx.intern_lazy_const(ty::LazyConst::Evaluated( + ty::Const::from_usize(self.tcx, value), + )), } } @@ -755,7 +759,9 @@ fn build_call_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, span, ty, user_ty: None, - literal: ty::Const::zero_sized(tcx, ty), + literal: tcx.intern_lazy_const(ty::LazyConst::Evaluated( + ty::Const::zero_sized(ty) + )), }), vec![rcvr]) } diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 34f544745a787..03d6d3868c9f0 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -20,7 +20,8 @@ use rustc::ty::layout::{ use interpret::{self, EvalContext, ScalarMaybeUndef, Immediate, OpTy, MemoryKind}; use const_eval::{ - CompileTimeInterpreter, const_to_op, error_to_const_error, eval_promoted, mk_borrowck_eval_cx + CompileTimeInterpreter, error_to_const_error, eval_promoted, mk_borrowck_eval_cx, + lazy_const_to_op, }; use transform::{MirPass, MirSource}; @@ -255,7 +256,7 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> { source_info: SourceInfo, ) -> Option> { self.ecx.tcx.span = source_info.span; - match const_to_op(&self.ecx, c.literal) { + match lazy_const_to_op(&self.ecx, *c.literal, c.ty) { Ok(op) => { Some((op, c.span)) }, diff --git a/src/librustc_mir/transform/elaborate_drops.rs b/src/librustc_mir/transform/elaborate_drops.rs index b98e3d7d8bb7a..06e16de8b43bc 100644 --- a/src/librustc_mir/transform/elaborate_drops.rs +++ b/src/librustc_mir/transform/elaborate_drops.rs @@ -533,7 +533,9 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { span, ty: self.tcx.types.bool, user_ty: None, - literal: ty::Const::from_bool(self.tcx, val), + literal: self.tcx.intern_lazy_const(ty::LazyConst::Evaluated( + ty::Const::from_bool(self.tcx, val), + )), }))) } diff --git a/src/librustc_mir/transform/erase_regions.rs b/src/librustc_mir/transform/erase_regions.rs index 009570c378ad2..b464b7d65e466 100644 --- a/src/librustc_mir/transform/erase_regions.rs +++ b/src/librustc_mir/transform/erase_regions.rs @@ -32,7 +32,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for EraseRegionsVisitor<'a, 'tcx> { *region = self.tcx.types.re_erased; } - fn visit_const(&mut self, constant: &mut &'tcx ty::Const<'tcx>, _: Location) { + fn visit_const(&mut self, constant: &mut &'tcx ty::LazyConst<'tcx>, _: Location) { *constant = self.tcx.erase_regions(constant); } diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index b43e839271863..808c3aad29201 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -171,11 +171,11 @@ impl<'a, 'tcx> TransformVisitor<'a, 'tcx> { span: source_info.span, ty: self.tcx.types.u32, user_ty: None, - literal: ty::Const::from_bits( + literal: self.tcx.intern_lazy_const(ty::LazyConst::Evaluated(ty::Const::from_bits( self.tcx, state_disc.into(), ty::ParamEnv::empty().and(self.tcx.types.u32) - ), + ))), }); Statement { source_info, @@ -717,7 +717,9 @@ fn insert_panic_block<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, span: mir.span, ty: tcx.types.bool, user_ty: None, - literal: ty::Const::from_bool(tcx, false), + literal: tcx.intern_lazy_const(ty::LazyConst::Evaluated( + ty::Const::from_bool(tcx, false), + )), }), expected: true, msg: message, diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 7b04af62fe6cc..a04dd5bb5970f 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -11,7 +11,6 @@ use rustc_data_structures::sync::Lrc; use rustc_target::spec::abi::Abi; use rustc::hir; use rustc::hir::def_id::DefId; -use rustc::mir::interpret::ConstValue; use rustc::traits::{self, TraitEngine}; use rustc::ty::{self, TyCtxt, Ty, TypeFoldable}; use rustc::ty::cast::CastTy; @@ -625,12 +624,12 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { } } Operand::Constant(ref constant) => { - if let ConstValue::Unevaluated(def_id, _) = constant.literal.val { + if let ty::LazyConst::Unevaluated(def_id, _) = constant.literal { // Don't peek inside trait associated constants. - if self.tcx.trait_of_item(def_id).is_some() { - self.add_type(constant.literal.ty); + if self.tcx.trait_of_item(*def_id).is_some() { + self.add_type(constant.ty); } else { - let (bits, _) = self.tcx.at(constant.span).mir_const_qualif(def_id); + let (bits, _) = self.tcx.at(constant.span).mir_const_qualif(*def_id); let qualif = Qualif::from_bits(bits).expect("invalid mir_const_qualif"); self.add(qualif); @@ -638,7 +637,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { // Just in case the type is more specific than // the definition, e.g., impl associated const // with type parameters, take it into account. - self.qualif.restrict(constant.literal.ty, self.tcx, self.param_env); + self.qualif.restrict(constant.ty, self.tcx, self.param_env); } } } diff --git a/src/librustc_mir/transform/simplify_branches.rs b/src/librustc_mir/transform/simplify_branches.rs index 6cf9f43877b17..abaea70946383 100644 --- a/src/librustc_mir/transform/simplify_branches.rs +++ b/src/librustc_mir/transform/simplify_branches.rs @@ -30,11 +30,12 @@ impl MirPass for SimplifyBranches { discr: Operand::Constant(ref c), switch_ty, ref values, ref targets, .. } => { let switch_ty = ParamEnv::empty().and(switch_ty); - if let Some(constint) = c.literal.assert_bits(tcx, switch_ty) { + let constant = c.literal.map_evaluated(|c| c.assert_bits(tcx, switch_ty)); + if let Some(constant) = constant { let (otherwise, targets) = targets.split_last().unwrap(); let mut ret = TerminatorKind::Goto { target: *otherwise }; for (&v, t) in values.iter().zip(targets.iter()) { - if v == constint { + if v == constant { ret = TerminatorKind::Goto { target: *t }; break; } @@ -46,9 +47,8 @@ impl MirPass for SimplifyBranches { }, TerminatorKind::Assert { target, cond: Operand::Constant(ref c), expected, .. - } if (c.literal.assert_bool(tcx) == Some(true)) == expected => { - TerminatorKind::Goto { target } - }, + } if (c.literal.map_evaluated(|e| e.assert_bool(tcx)) == Some(true)) == expected => + TerminatorKind::Goto { target }, TerminatorKind::FalseEdges { real_target, .. } => { TerminatorKind::Goto { target: real_target } }, diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs index 5a2f4be71cc2f..8b55a4424ae29 100644 --- a/src/librustc_mir/util/elaborate_drops.rs +++ b/src/librustc_mir/util/elaborate_drops.rs @@ -963,7 +963,9 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> span: self.source_info.span, ty: self.tcx().types.usize, user_ty: None, - literal: ty::Const::from_usize(self.tcx(), val.into()), + literal: self.tcx().intern_lazy_const(ty::LazyConst::Evaluated( + ty::Const::from_usize(self.tcx(), val.into()) + )), }) } diff --git a/src/librustc_mir/util/pretty.rs b/src/librustc_mir/util/pretty.rs index 6353eab6f6553..fca208b340d2a 100644 --- a/src/librustc_mir/util/pretty.rs +++ b/src/librustc_mir/util/pretty.rs @@ -399,12 +399,21 @@ impl<'cx, 'gcx, 'tcx> Visitor<'tcx> for ExtraComments<'cx, 'gcx, 'tcx> { self.push(&format!("+ literal: {:?}", literal)); } - fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, _: Location) { + fn visit_const(&mut self, constant: &&'tcx ty::LazyConst<'tcx>, _: Location) { self.super_const(constant); - let ty::Const { ty, val, .. } = constant; - self.push("ty::Const"); - self.push(&format!("+ ty: {:?}", ty)); - self.push(&format!("+ val: {:?}", val)); + match constant { + ty::LazyConst::Evaluated(constant) => { + let ty::Const { ty, val, .. } = constant; + self.push("ty::Const"); + self.push(&format!("+ ty: {:?}", ty)); + self.push(&format!("+ val: {:?}", val)); + }, + ty::LazyConst::Unevaluated(did, substs) => { + self.push("ty::LazyConst::Unevaluated"); + self.push(&format!("+ did: {:?}", did)); + self.push(&format!("+ substs: {:?}", substs)); + }, + } } fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { diff --git a/src/librustc_traits/chalk_context/program_clauses.rs b/src/librustc_traits/chalk_context/program_clauses.rs index 98a2f4bf0a15b..71f4945fd648d 100644 --- a/src/librustc_traits/chalk_context/program_clauses.rs +++ b/src/librustc_traits/chalk_context/program_clauses.rs @@ -239,7 +239,7 @@ fn wf_clause_for_slice<'tcx>(tcx: ty::TyCtxt<'_, '_, 'tcx>) -> Clauses<'tcx> { fn wf_clause_for_array<'tcx>( tcx: ty::TyCtxt<'_, '_, 'tcx>, - length: &'tcx ty::Const<'tcx> + length: &'tcx ty::LazyConst<'tcx> ) -> Clauses<'tcx> { let ty = generic_types::bound(tcx, 0); let array_ty = tcx.mk_ty(ty::Array(ty, length)); diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 1db7141917f98..e018aa3b26d91 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1772,7 +1772,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { hir::TyKind::Array(ref ty, ref length) => { let length_def_id = tcx.hir().local_def_id(length.id); let substs = Substs::identity_for_item(tcx, length_def_id); - let length = ty::Const::unevaluated(tcx, length_def_id, substs, tcx.types.usize); + let length = ty::LazyConst::Unevaluated(length_def_id, substs); + let length = tcx.intern_lazy_const(length); let array_ty = tcx.mk_ty(ty::Array(self.ast_ty_to_ty(&ty), length)); self.normalize_ty(ast_ty.span, array_ty) } diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index d4f639c070de3..c59c143f74b62 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -1,16 +1,17 @@ -use super::{Expectation, FnCtxt, Needs, TupleArgumentsFlag}; use super::autoderef::Autoderef; use super::method::MethodCallee; +use super::{Expectation, FnCtxt, Needs, TupleArgumentsFlag}; +use errors::Applicability; use hir::def::Def; use hir::def_id::{DefId, LOCAL_CRATE}; +use rustc::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability}; +use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc::{infer, traits}; -use rustc::ty::{self, TyCtxt, TypeFoldable, Ty}; -use rustc::ty::adjustment::{Adjustment, Adjust, AllowTwoPhase, AutoBorrow, AutoBorrowMutability}; +use rustc::infer::type_variable::TypeVariableOrigin; use rustc_target::spec::abi; use syntax::ast::Ident; use syntax_pos::Span; -use errors::Applicability; use rustc::hir; @@ -33,19 +34,20 @@ enum CallStep<'tcx> { } impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { - pub fn check_call(&self, - call_expr: &'gcx hir::Expr, - callee_expr: &'gcx hir::Expr, - arg_exprs: &'gcx [hir::Expr], - expected: Expectation<'tcx>) - -> Ty<'tcx> { + pub fn check_call( + &self, + call_expr: &'gcx hir::Expr, + callee_expr: &'gcx hir::Expr, + arg_exprs: &'gcx [hir::Expr], + expected: Expectation<'tcx>, + ) -> Ty<'tcx> { let original_callee_ty = self.check_expr(callee_expr); let expr_ty = self.structurally_resolved_type(call_expr.span, original_callee_ty); let mut autoderef = self.autoderef(callee_expr.span, expr_ty); let mut result = None; while result.is_none() && autoderef.next().is_some() { - result = self.try_overloaded_call_step(call_expr, callee_expr, &autoderef); + result = self.try_overloaded_call_step(call_expr, callee_expr, arg_exprs, &autoderef); } autoderef.finalize(self); @@ -74,15 +76,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { output } - fn try_overloaded_call_step(&self, - call_expr: &'gcx hir::Expr, - callee_expr: &'gcx hir::Expr, - autoderef: &Autoderef<'a, 'gcx, 'tcx>) - -> Option> { + fn try_overloaded_call_step( + &self, + call_expr: &'gcx hir::Expr, + callee_expr: &'gcx hir::Expr, + arg_exprs: &'gcx [hir::Expr], + autoderef: &Autoderef<'a, 'gcx, 'tcx>, + ) -> Option> { let adjusted_ty = autoderef.unambiguous_final_ty(self); - debug!("try_overloaded_call_step(call_expr={:?}, adjusted_ty={:?})", - call_expr, - adjusted_ty); + debug!( + "try_overloaded_call_step(call_expr={:?}, adjusted_ty={:?})", + call_expr, adjusted_ty + ); // If the callee is a bare function or a closure, then we're all set. match adjusted_ty.sty { @@ -100,21 +105,26 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // fnmut vs fnonce. If so, we have to defer further processing. if self.closure_kind(def_id, substs).is_none() { let closure_ty = self.closure_sig(def_id, substs); - let fn_sig = self.replace_bound_vars_with_fresh_vars( - call_expr.span, - infer::FnCall, - &closure_ty - ).0; + let fn_sig = self + .replace_bound_vars_with_fresh_vars( + call_expr.span, + infer::FnCall, + &closure_ty, + ) + .0; let adjustments = autoderef.adjust_steps(self, Needs::None); - self.record_deferred_call_resolution(def_id, DeferredCallResolution { - call_expr, - callee_expr, - adjusted_ty, - adjustments, - fn_sig, - closure_def_id: def_id, - closure_substs: substs, - }); + self.record_deferred_call_resolution( + def_id, + DeferredCallResolution { + call_expr, + callee_expr, + adjusted_ty, + adjustments, + fn_sig, + closure_def_id: def_id, + closure_substs: substs, + }, + ); return Some(CallStep::DeferredClosure(fn_sig)); } } @@ -134,34 +144,68 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { _ => {} } - self.try_overloaded_call_traits(call_expr, adjusted_ty).map(|(autoref, method)| { - let mut adjustments = autoderef.adjust_steps(self, Needs::None); - adjustments.extend(autoref); - self.apply_adjustments(callee_expr, adjustments); - CallStep::Overloaded(method) - }) + // Now, we look for the implementation of a Fn trait on the object's type. + // We first do it with the explicit instruction to look for an impl of + // `Fn`, with the tuple `Tuple` having an arity corresponding + // to the number of call parameters. + // If that fails (or_else branch), we try again without specifying the + // shape of the tuple (hence the None). This allows to detect an Fn trait + // is implemented, and use this information for diagnostic. + self.try_overloaded_call_traits(call_expr, adjusted_ty, Some(arg_exprs)) + .or_else(|| self.try_overloaded_call_traits(call_expr, adjusted_ty, None)) + .map(|(autoref, method)| { + let mut adjustments = autoderef.adjust_steps(self, Needs::None); + adjustments.extend(autoref); + self.apply_adjustments(callee_expr, adjustments); + CallStep::Overloaded(method) + }) } - fn try_overloaded_call_traits(&self, - call_expr: &hir::Expr, - adjusted_ty: Ty<'tcx>) - -> Option<(Option>, - MethodCallee<'tcx>)> { + fn try_overloaded_call_traits( + &self, + call_expr: &hir::Expr, + adjusted_ty: Ty<'tcx>, + opt_arg_exprs: Option<&'gcx [hir::Expr]>, + ) -> Option<(Option>, MethodCallee<'tcx>)> { // Try the options that are least restrictive on the caller first. - for &(opt_trait_def_id, method_name, borrow) in - &[(self.tcx.lang_items().fn_trait(), Ident::from_str("call"), true), - (self.tcx.lang_items().fn_mut_trait(), Ident::from_str("call_mut"), true), - (self.tcx.lang_items().fn_once_trait(), Ident::from_str("call_once"), false)] { + for &(opt_trait_def_id, method_name, borrow) in &[ + ( + self.tcx.lang_items().fn_trait(), + Ident::from_str("call"), + true, + ), + ( + self.tcx.lang_items().fn_mut_trait(), + Ident::from_str("call_mut"), + true, + ), + ( + self.tcx.lang_items().fn_once_trait(), + Ident::from_str("call_once"), + false, + ), + ] { let trait_def_id = match opt_trait_def_id { Some(def_id) => def_id, None => continue, }; - if let Some(ok) = self.lookup_method_in_trait(call_expr.span, - method_name, - trait_def_id, - adjusted_ty, - None) { + let opt_input_types = opt_arg_exprs.map(|arg_exprs| [self.tcx.mk_tup( + arg_exprs + .iter() + .map(|e| self.next_ty_var( + TypeVariableOrigin::TypeInference(e.span) + )) + )]); + let opt_input_types = opt_input_types.as_ref().map(AsRef::as_ref); + + if let Some(ok) = self.lookup_method_in_trait( + call_expr.span, + method_name, + trait_def_id, + adjusted_ty, + opt_input_types, + ) { let method = self.register_infer_ok_obligations(ok); let mut autoref = None; if borrow { @@ -173,11 +217,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // deployment, conservatively omit // overloaded function call ops. allow_two_phase_borrow: AllowTwoPhase::No, - } + }, }; autoref = Some(Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(region, mutbl)), - target: method.sig.inputs()[0] + target: method.sig.inputs()[0], }); } } @@ -188,16 +232,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { None } - fn confirm_builtin_call(&self, - call_expr: &hir::Expr, - callee_ty: Ty<'tcx>, - arg_exprs: &'gcx [hir::Expr], - expected: Expectation<'tcx>) - -> Ty<'tcx> { + fn confirm_builtin_call( + &self, + call_expr: &hir::Expr, + callee_ty: Ty<'tcx>, + arg_exprs: &'gcx [hir::Expr], + expected: Expectation<'tcx>, + ) -> Ty<'tcx> { let (fn_sig, def_span) = match callee_ty.sty { - ty::FnDef(def_id, _) => { - (callee_ty.fn_sig(self.tcx), self.tcx.hir().span_if_local(def_id)) - } + ty::FnDef(def_id, _) => ( + callee_ty.fn_sig(self.tcx), + self.tcx.hir().span_if_local(def_id), + ), ty::FnPtr(sig) => (sig, None), ref t => { let mut unit_variant = None; @@ -219,15 +265,19 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { match unit_variant { Some(ref path) => format!("enum variant `{}`", path), None => format!("`{}`", callee_ty), - }); + } + ); if let Some(ref path) = unit_variant { err.span_suggestion_with_applicability( call_expr.span, - &format!("`{}` is a unit variant, you need to write it \ - without the parenthesis", path), + &format!( + "`{}` is a unit variant, you need to write it \ + without the parenthesis", + path + ), path.to_string(), - Applicability::MachineApplicable + Applicability::MachineApplicable, ); } @@ -235,48 +285,50 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let def = match callee.node { hir::ExprKind::Path(ref qpath) => { self.tables.borrow().qpath_def(qpath, callee.hir_id) - }, + } hir::ExprKind::Call(ref inner_callee, _) => { // If the call spans more than one line and the callee kind is // itself another `ExprCall`, that's a clue that we might just be // missing a semicolon (Issue #51055) - let call_is_multiline = self.tcx.sess.source_map() - .is_multiline(call_expr.span); + let call_is_multiline = + self.tcx.sess.source_map().is_multiline(call_expr.span); if call_is_multiline { let span = self.tcx.sess.source_map().next_point(callee.span); err.span_suggestion_with_applicability( span, "try adding a semicolon", ";".to_owned(), - Applicability::MaybeIncorrect + Applicability::MaybeIncorrect, ); } if let hir::ExprKind::Path(ref inner_qpath) = inner_callee.node { inner_callee_path = Some(inner_qpath); - self.tables.borrow().qpath_def(inner_qpath, inner_callee.hir_id) + self.tables + .borrow() + .qpath_def(inner_qpath, inner_callee.hir_id) } else { Def::Err } - }, - _ => { - Def::Err } + _ => Def::Err, }; err.span_label(call_expr.span, "call expression requires function"); let def_span = match def { Def::Err => None, - Def::Local(id) | Def::Upvar(id, ..) => { - Some(self.tcx.hir().span(id)) - } - _ => def.opt_def_id().and_then(|did| self.tcx.hir().span_if_local(did)), + Def::Local(id) | Def::Upvar(id, ..) => Some(self.tcx.hir().span(id)), + _ => def + .opt_def_id() + .and_then(|did| self.tcx.hir().span_if_local(did)), }; if let Some(span) = def_span { let label = match (unit_variant, inner_callee_path) { (Some(path), _) => format!("`{}` defined here", path), (_, Some(hir::QPath::Resolved(_, path))) => format!( - "`{}` defined here returns `{}`", path, callee_ty.to_string() + "`{}` defined here returns `{}`", + path, + callee_ty.to_string() ), _ => format!("`{}` defined here", callee_ty.to_string()), }; @@ -284,19 +336,25 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } err.emit(); } else { - bug!("call_expr.node should be an ExprKind::Call, got {:?}", call_expr.node); + bug!( + "call_expr.node should be an ExprKind::Call, got {:?}", + call_expr.node + ); } // This is the "default" function signature, used in case of error. // In that case, we check each argument against "error" in order to // set up all the node type bindings. - (ty::Binder::bind(self.tcx.mk_fn_sig( - self.err_args(arg_exprs.len()).into_iter(), - self.tcx.types.err, - false, - hir::Unsafety::Normal, - abi::Abi::Rust - )), None) + ( + ty::Binder::bind(self.tcx.mk_fn_sig( + self.err_args(arg_exprs.len()).into_iter(), + self.tcx.types.err, + false, + hir::Unsafety::Normal, + abi::Abi::Rust, + )), + None, + ) } }; @@ -305,69 +363,80 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // renormalize the associated types at this point, since they // previously appeared within a `Binder<>` and hence would not // have been normalized before. - let fn_sig = - self.replace_bound_vars_with_fresh_vars(call_expr.span, infer::FnCall, &fn_sig) - .0; + let fn_sig = self + .replace_bound_vars_with_fresh_vars(call_expr.span, infer::FnCall, &fn_sig) + .0; let fn_sig = self.normalize_associated_types_in(call_expr.span, &fn_sig); // Call the generic checker. - let expected_arg_tys = - self.expected_inputs_for_expected_output(call_expr.span, - expected, - fn_sig.output(), - fn_sig.inputs()); - self.check_argument_types(call_expr.span, - call_expr.span, - fn_sig.inputs(), - &expected_arg_tys[..], - arg_exprs, - fn_sig.variadic, - TupleArgumentsFlag::DontTupleArguments, - def_span); + let expected_arg_tys = self.expected_inputs_for_expected_output( + call_expr.span, + expected, + fn_sig.output(), + fn_sig.inputs(), + ); + self.check_argument_types( + call_expr.span, + call_expr.span, + fn_sig.inputs(), + &expected_arg_tys[..], + arg_exprs, + fn_sig.variadic, + TupleArgumentsFlag::DontTupleArguments, + def_span, + ); fn_sig.output() } - fn confirm_deferred_closure_call(&self, - call_expr: &hir::Expr, - arg_exprs: &'gcx [hir::Expr], - expected: Expectation<'tcx>, - fn_sig: ty::FnSig<'tcx>) - -> Ty<'tcx> { + fn confirm_deferred_closure_call( + &self, + call_expr: &hir::Expr, + arg_exprs: &'gcx [hir::Expr], + expected: Expectation<'tcx>, + fn_sig: ty::FnSig<'tcx>, + ) -> Ty<'tcx> { // `fn_sig` is the *signature* of the cosure being called. We // don't know the full details yet (`Fn` vs `FnMut` etc), but we // do know the types expected for each argument and the return // type. - let expected_arg_tys = self.expected_inputs_for_expected_output(call_expr.span, - expected, - fn_sig.output().clone(), - fn_sig.inputs()); - - self.check_argument_types(call_expr.span, - call_expr.span, - fn_sig.inputs(), - &expected_arg_tys, - arg_exprs, - fn_sig.variadic, - TupleArgumentsFlag::TupleArguments, - None); + let expected_arg_tys = self.expected_inputs_for_expected_output( + call_expr.span, + expected, + fn_sig.output().clone(), + fn_sig.inputs(), + ); + + self.check_argument_types( + call_expr.span, + call_expr.span, + fn_sig.inputs(), + &expected_arg_tys, + arg_exprs, + fn_sig.variadic, + TupleArgumentsFlag::TupleArguments, + None, + ); fn_sig.output() } - fn confirm_overloaded_call(&self, - call_expr: &hir::Expr, - arg_exprs: &'gcx [hir::Expr], - expected: Expectation<'tcx>, - method_callee: MethodCallee<'tcx>) - -> Ty<'tcx> { - let output_type = self.check_method_argument_types(call_expr.span, - call_expr.span, - Ok(method_callee), - arg_exprs, - TupleArgumentsFlag::TupleArguments, - expected); + fn confirm_overloaded_call( + &self, + call_expr: &hir::Expr, + arg_exprs: &'gcx [hir::Expr], + expected: Expectation<'tcx>, + method_callee: MethodCallee<'tcx>, + ) -> Ty<'tcx> { + let output_type = self.check_method_argument_types( + call_expr.span, + call_expr.span, + Ok(method_callee), + arg_exprs, + TupleArgumentsFlag::TupleArguments, + expected, + ); self.write_method_call(call_expr.hir_id, method_callee); output_type @@ -391,11 +460,12 @@ impl<'a, 'gcx, 'tcx> DeferredCallResolution<'gcx, 'tcx> { // we should not be invoked until the closure kind has been // determined by upvar inference - assert!(fcx.closure_kind(self.closure_def_id, self.closure_substs).is_some()); + assert!(fcx + .closure_kind(self.closure_def_id, self.closure_substs) + .is_some()); // We may now know enough to figure out fn vs fnmut etc. - match fcx.try_overloaded_call_traits(self.call_expr, - self.adjusted_ty) { + match fcx.try_overloaded_call_traits(self.call_expr, self.adjusted_ty, None) { Some((autoref, method_callee)) => { // One problem is that when we get here, we are going // to have a newly instantiated function signature @@ -410,22 +480,28 @@ impl<'a, 'gcx, 'tcx> DeferredCallResolution<'gcx, 'tcx> { debug!("attempt_resolution: method_callee={:?}", method_callee); for (method_arg_ty, self_arg_ty) in - method_sig.inputs().iter().skip(1).zip(self.fn_sig.inputs()) { + method_sig.inputs().iter().skip(1).zip(self.fn_sig.inputs()) + { fcx.demand_eqtype(self.call_expr.span, &self_arg_ty, &method_arg_ty); } - fcx.demand_eqtype(self.call_expr.span, method_sig.output(), self.fn_sig.output()); + fcx.demand_eqtype( + self.call_expr.span, + method_sig.output(), + self.fn_sig.output(), + ); let mut adjustments = self.adjustments; adjustments.extend(autoref); fcx.apply_adjustments(self.callee_expr, adjustments); - fcx.write_method_call(self.call_expr.hir_id, - method_callee); + fcx.write_method_call(self.call_expr.hir_id, method_callee); } None => { - span_bug!(self.call_expr.span, - "failed to find an overloaded call trait for closure call"); + span_bug!( + self.call_expr.span, + "failed to find an overloaded call trait for closure call" + ); } } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index d78d7273a36e6..b2ea170697737 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1305,6 +1305,27 @@ fn check_union<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, check_packed(tcx, span, def_id); } +fn check_opaque<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId, + substs: &'tcx Substs<'tcx>, + span: Span, +) { + if let Err(partially_expanded_type) = tcx.try_expand_impl_trait_type(def_id, substs) { + let mut err = struct_span_err!( + tcx.sess, span, E0720, + "opaque type expands to a recursive type", + ); + err.span_label(span, "expands to self-referential type"); + if let ty::Opaque(..) = partially_expanded_type.sty { + err.note("type resolves to itself"); + } else { + err.note(&format!("expanded type is `{}`", partially_expanded_type)); + } + err.emit(); + } +} + pub fn check_item_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &'tcx hir::Item) { debug!( "check_item_type(it.id={}, it.name={})", @@ -1351,7 +1372,16 @@ pub fn check_item_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &'tcx hir::Ite hir::ItemKind::Union(..) => { check_union(tcx, it.id, it.span); } - hir::ItemKind::Existential(..) | hir::ItemKind::Ty(..) => { + hir::ItemKind::Existential(..) => { + let def_id = tcx.hir().local_def_id(it.id); + let pty_ty = tcx.type_of(def_id); + let generics = tcx.generics_of(def_id); + + check_bounds_are_used(tcx, &generics, pty_ty); + let substs = Substs::identity_for_item(tcx, def_id); + check_opaque(tcx, def_id, substs, it.span); + } + hir::ItemKind::Ty(..) => { let def_id = tcx.hir().local_def_id(it.id); let pty_ty = tcx.type_of(def_id); let generics = tcx.generics_of(def_id); @@ -4442,7 +4472,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if element_ty.references_error() { tcx.types.err } else if let Ok(count) = count { - tcx.mk_ty(ty::Array(t, count)) + tcx.mk_ty(ty::Array(t, tcx.intern_lazy_const(ty::LazyConst::Evaluated(count)))) } else { tcx.types.err } diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 5910a8b3110d0..387dabe747ab8 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -4816,6 +4816,21 @@ type, it's not allowed to override anything in those implementations, as it would be ambiguous which override should actually be used. "##, + +E0720: r##" +An `impl Trait` type expands to a recursive type. + +An `impl Trait` type must be expandable to a concrete type that contains no +`impl Trait` types. For example the following example tries to create an +`impl Trait` type `T` that is equal to `[T, T]`: + +```compile_fail,E0720 +fn make_recursive_type() -> impl Sized { + [make_recursive_type(), make_recursive_type()] +} +``` +"##, + } register_diagnostics! { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 38b2452b420e9..3aa752b35adcf 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -13,7 +13,6 @@ use rustc_data_structures::sync::Lrc; use rustc_target::spec::abi::Abi; use rustc_typeck::hir_ty_to_ty; use rustc::infer::region_constraints::{RegionConstraintData, Constraint}; -use rustc::mir::interpret::ConstValue; use rustc::middle::resolve_lifetime as rl; use rustc::middle::lang_items; use rustc::middle::stability; @@ -2420,10 +2419,10 @@ impl Clean for hir::Ty { instance: ty::Instance::new(def_id, substs), promoted: None }; - let length = cx.tcx.const_eval(param_env.and(cid)).unwrap_or_else(|_| { - ty::Const::unevaluated(cx.tcx, def_id, substs, cx.tcx.types.usize) - }); - let length = print_const(cx, length); + let length = match cx.tcx.const_eval(param_env.and(cid)) { + Ok(length) => print_const(cx, ty::LazyConst::Evaluated(length)), + Err(_) => "_".to_string(), + }; Array(box ty.clean(cx), length) }, TyKind::Tup(ref tys) => Tuple(tys.clean(cx)), @@ -2583,15 +2582,15 @@ impl<'tcx> Clean for Ty<'tcx> { ty::Str => Primitive(PrimitiveType::Str), ty::Slice(ty) => Slice(box ty.clean(cx)), ty::Array(ty, n) => { - let mut n = cx.tcx.lift(&n).expect("array lift failed"); - if let ConstValue::Unevaluated(def_id, substs) = n.val { + let mut n = *cx.tcx.lift(&n).expect("array lift failed"); + if let ty::LazyConst::Unevaluated(def_id, substs) = n { let param_env = cx.tcx.param_env(def_id); let cid = GlobalId { instance: ty::Instance::new(def_id, substs), promoted: None }; if let Ok(new_n) = cx.tcx.const_eval(param_env.and(cid)) { - n = new_n; + n = ty::LazyConst::Evaluated(new_n); } }; let n = print_const(cx, n); @@ -3691,16 +3690,16 @@ fn name_from_pat(p: &hir::Pat) -> String { } } -fn print_const(cx: &DocContext, n: &ty::Const) -> String { - match n.val { - ConstValue::Unevaluated(def_id, _) => { +fn print_const(cx: &DocContext, n: ty::LazyConst) -> String { + match n { + ty::LazyConst::Unevaluated(def_id, _) => { if let Some(node_id) = cx.tcx.hir().as_local_node_id(def_id) { print_const_expr(cx, cx.tcx.hir().body_owned_by(node_id)) } else { inline::print_inlined_const(cx, def_id) } }, - _ => { + ty::LazyConst::Evaluated(n) => { let mut s = String::new(); ::rustc::mir::fmt_const_val(&mut s, n).expect("fmt_const_val failed"); // array lengths are obviously usize diff --git a/src/test/run-pass/issue-18952.rs b/src/test/run-pass/issue-18952.rs new file mode 100644 index 0000000000000..56378b59e3642 --- /dev/null +++ b/src/test/run-pass/issue-18952.rs @@ -0,0 +1,56 @@ +// This issue tests fn_traits overloading on arity. +// run-pass + +#![feature(fn_traits)] +#![feature(unboxed_closures)] + +struct Foo; + +impl Fn<(isize, isize)> for Foo { + extern "rust-call" fn call(&self, args: (isize, isize)) -> Self::Output { + println!("{:?}", args); + (args.0 + 1, args.1 + 1) + } +} + +impl FnMut<(isize, isize)> for Foo { + extern "rust-call" fn call_mut(&mut self, args: (isize, isize)) -> Self::Output { + println!("{:?}", args); + (args.0 + 1, args.1 + 1) + } +} + +impl FnOnce<(isize, isize)> for Foo { + type Output = (isize, isize); + extern "rust-call" fn call_once(self, args: (isize, isize)) -> Self::Output { + println!("{:?}", args); + (args.0 + 1, args.1 + 1) + } +} + +impl Fn<(isize, isize, isize)> for Foo { + extern "rust-call" fn call(&self, args: (isize, isize, isize)) -> Self::Output { + println!("{:?}", args); + (args.0 + 3, args.1 + 3, args.2 + 3) + } +} + +impl FnMut<(isize, isize, isize)> for Foo { + extern "rust-call" fn call_mut(&mut self, args: (isize, isize, isize)) -> Self::Output { + println!("{:?}", args); + (args.0 + 3, args.1 + 3, args.2 + 3) + } +} +impl FnOnce<(isize, isize, isize)> for Foo { + type Output = (isize, isize, isize); + extern "rust-call" fn call_once(self, args: (isize, isize, isize)) -> Self::Output { + println!("{:?}", args); + (args.0 + 3, args.1 + 3, args.2 + 3) + } +} + +fn main() { + let foo = Foo; + assert_eq!(foo(1, 1), (2, 2)); + assert_eq!(foo(1, 1, 1), (4, 4, 4)); +} diff --git a/src/test/run-pass/issue-45510.rs b/src/test/run-pass/issue-45510.rs new file mode 100644 index 0000000000000..9e104ce6c4f30 --- /dev/null +++ b/src/test/run-pass/issue-45510.rs @@ -0,0 +1,32 @@ +// Test overloaded resolution of fn_traits. +// run-pass + +#![feature(fn_traits)] +#![feature(unboxed_closures)] + +#[derive(Debug, PartialEq, Eq)] +struct Ishmael; +#[derive(Debug, PartialEq, Eq)] +struct Maybe; +struct CallMe; + +impl FnOnce<(Ishmael,)> for CallMe { + type Output = Ishmael; + extern "rust-call" fn call_once(self, _args: (Ishmael,)) -> Ishmael { + println!("Split your lungs with blood and thunder!"); + Ishmael + } +} + +impl FnOnce<(Maybe,)> for CallMe { + type Output = Maybe; + extern "rust-call" fn call_once(self, _args: (Maybe,)) -> Maybe { + println!("So we just met, and this is crazy"); + Maybe + } +} + +fn main() { + assert_eq!(CallMe(Ishmael), Ishmael); + assert_eq!(CallMe(Maybe), Maybe); +} diff --git a/src/test/ui/impl-trait/infinite-impl-trait-issue-38064.rs b/src/test/ui/impl-trait/infinite-impl-trait-issue-38064.rs index c84e5883bb2a5..150a8015cbc75 100644 --- a/src/test/ui/impl-trait/infinite-impl-trait-issue-38064.rs +++ b/src/test/ui/impl-trait/infinite-impl-trait-issue-38064.rs @@ -3,17 +3,15 @@ // // Regression test for #38064. -// error-pattern:overflow evaluating the requirement `impl Quux` - trait Quux {} -fn foo() -> impl Quux { +fn foo() -> impl Quux { //~ opaque type expands to a recursive type struct Foo(T); impl Quux for Foo {} Foo(bar()) } -fn bar() -> impl Quux { +fn bar() -> impl Quux { //~ opaque type expands to a recursive type struct Bar(T); impl Quux for Bar {} Bar(foo()) diff --git a/src/test/ui/impl-trait/infinite-impl-trait-issue-38064.stderr b/src/test/ui/impl-trait/infinite-impl-trait-issue-38064.stderr index f260cce647bd2..99c8fe35c66d0 100644 --- a/src/test/ui/impl-trait/infinite-impl-trait-issue-38064.stderr +++ b/src/test/ui/impl-trait/infinite-impl-trait-issue-38064.stderr @@ -1,7 +1,19 @@ -error[E0275]: overflow evaluating the requirement `impl Quux` +error[E0720]: opaque type expands to a recursive type + --> $DIR/infinite-impl-trait-issue-38064.rs:8:13 | - = help: consider adding a `#![recursion_limit="128"]` attribute to your crate +LL | fn foo() -> impl Quux { //~ opaque type expands to a recursive type + | ^^^^^^^^^ expands to self-referential type + | + = note: expanded type is `foo::Foo>` + +error[E0720]: opaque type expands to a recursive type + --> $DIR/infinite-impl-trait-issue-38064.rs:14:13 + | +LL | fn bar() -> impl Quux { //~ opaque type expands to a recursive type + | ^^^^^^^^^ expands to self-referential type + | + = note: expanded type is `bar::Bar>` -error: aborting due to previous error +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0275`. +For more information about this error, try `rustc --explain E0720`. diff --git a/src/test/ui/impl-trait/recursive-impl-trait-type.rs b/src/test/ui/impl-trait/recursive-impl-trait-type.rs new file mode 100644 index 0000000000000..facb191a37081 --- /dev/null +++ b/src/test/ui/impl-trait/recursive-impl-trait-type.rs @@ -0,0 +1,81 @@ +// Test that impl trait does not allow creating recursive types that are +// otherwise forbidden. + +#![feature(await_macro, async_await, futures_api, generators)] + +fn option(i: i32) -> impl Sized { //~ ERROR + if i < 0 { + None + } else { + Some((option(i - 1), i)) + } +} + +fn tuple() -> impl Sized { //~ ERROR + (tuple(),) +} + +fn array() -> impl Sized { //~ ERROR + [array()] +} + +fn ptr() -> impl Sized { //~ ERROR + &ptr() as *const _ +} + +fn fn_ptr() -> impl Sized { //~ ERROR + fn_ptr as fn() -> _ +} + +fn closure_capture() -> impl Sized { //~ ERROR + let x = closure_capture(); + move || { x; } +} + +fn closure_ref_capture() -> impl Sized { //~ ERROR + let x = closure_ref_capture(); + move || { &x; } +} + +fn closure_sig() -> impl Sized { //~ ERROR + || closure_sig() +} + +fn generator_sig() -> impl Sized { //~ ERROR + || generator_sig() +} + +fn generator_capture() -> impl Sized { //~ ERROR + let x = generator_capture(); + move || { yield; x; } +} + +fn substs_change() -> impl Sized { //~ ERROR + (substs_change::<&T>(),) +} + +fn generator_hold() -> impl Sized { //~ ERROR + move || { + let x = generator_hold(); + yield; + x; + } +} + +async fn recursive_async_function() -> () { //~ ERROR + await!(recursive_async_function()); +} + +fn use_fn_ptr() -> impl Sized { // OK, error already reported + fn_ptr() +} + +fn mutual_recursion() -> impl Sync { //~ ERROR + mutual_recursion_b() +} + +fn mutual_recursion_b() -> impl Sized { //~ ERROR + mutual_recursion() +} + +fn main() {} diff --git a/src/test/ui/impl-trait/recursive-impl-trait-type.stderr b/src/test/ui/impl-trait/recursive-impl-trait-type.stderr new file mode 100644 index 0000000000000..8a8789120577e --- /dev/null +++ b/src/test/ui/impl-trait/recursive-impl-trait-type.stderr @@ -0,0 +1,123 @@ +error[E0720]: opaque type expands to a recursive type + --> $DIR/recursive-impl-trait-type.rs:6:22 + | +LL | fn option(i: i32) -> impl Sized { //~ ERROR + | ^^^^^^^^^^ expands to self-referential type + | + = note: expanded type is `std::option::Option<(impl Sized, i32)>` + +error[E0720]: opaque type expands to a recursive type + --> $DIR/recursive-impl-trait-type.rs:14:15 + | +LL | fn tuple() -> impl Sized { //~ ERROR + | ^^^^^^^^^^ expands to self-referential type + | + = note: expanded type is `(impl Sized,)` + +error[E0720]: opaque type expands to a recursive type + --> $DIR/recursive-impl-trait-type.rs:18:15 + | +LL | fn array() -> impl Sized { //~ ERROR + | ^^^^^^^^^^ expands to self-referential type + | + = note: expanded type is `[impl Sized; 1]` + +error[E0720]: opaque type expands to a recursive type + --> $DIR/recursive-impl-trait-type.rs:22:13 + | +LL | fn ptr() -> impl Sized { //~ ERROR + | ^^^^^^^^^^ expands to self-referential type + | + = note: expanded type is `*const impl Sized` + +error[E0720]: opaque type expands to a recursive type + --> $DIR/recursive-impl-trait-type.rs:26:16 + | +LL | fn fn_ptr() -> impl Sized { //~ ERROR + | ^^^^^^^^^^ expands to self-referential type + | + = note: expanded type is `fn() -> impl Sized` + +error[E0720]: opaque type expands to a recursive type + --> $DIR/recursive-impl-trait-type.rs:30:25 + | +LL | fn closure_capture() -> impl Sized { //~ ERROR + | ^^^^^^^^^^ expands to self-referential type + | + = note: expanded type is `[closure@$DIR/recursive-impl-trait-type.rs:32:5: 32:19 x:impl Sized]` + +error[E0720]: opaque type expands to a recursive type + --> $DIR/recursive-impl-trait-type.rs:35:29 + | +LL | fn closure_ref_capture() -> impl Sized { //~ ERROR + | ^^^^^^^^^^ expands to self-referential type + | + = note: expanded type is `[closure@$DIR/recursive-impl-trait-type.rs:37:5: 37:20 x:impl Sized]` + +error[E0720]: opaque type expands to a recursive type + --> $DIR/recursive-impl-trait-type.rs:40:21 + | +LL | fn closure_sig() -> impl Sized { //~ ERROR + | ^^^^^^^^^^ expands to self-referential type + | + = note: expanded type is `[closure@$DIR/recursive-impl-trait-type.rs:41:5: 41:21]` + +error[E0720]: opaque type expands to a recursive type + --> $DIR/recursive-impl-trait-type.rs:44:23 + | +LL | fn generator_sig() -> impl Sized { //~ ERROR + | ^^^^^^^^^^ expands to self-referential type + | + = note: expanded type is `[closure@$DIR/recursive-impl-trait-type.rs:45:5: 45:23]` + +error[E0720]: opaque type expands to a recursive type + --> $DIR/recursive-impl-trait-type.rs:48:27 + | +LL | fn generator_capture() -> impl Sized { //~ ERROR + | ^^^^^^^^^^ expands to self-referential type + | + = note: expanded type is `[generator@$DIR/recursive-impl-trait-type.rs:50:5: 50:26 x:impl Sized {()}]` + +error[E0720]: opaque type expands to a recursive type + --> $DIR/recursive-impl-trait-type.rs:53:26 + | +LL | fn substs_change() -> impl Sized { //~ ERROR + | ^^^^^^^^^^ expands to self-referential type + | + = note: expanded type is `(impl Sized,)` + +error[E0720]: opaque type expands to a recursive type + --> $DIR/recursive-impl-trait-type.rs:57:24 + | +LL | fn generator_hold() -> impl Sized { //~ ERROR + | ^^^^^^^^^^ expands to self-referential type + | + = note: expanded type is `[generator@$DIR/recursive-impl-trait-type.rs:58:5: 62:6 {impl Sized, ()}]` + +error[E0720]: opaque type expands to a recursive type + --> $DIR/recursive-impl-trait-type.rs:65:40 + | +LL | async fn recursive_async_function() -> () { //~ ERROR + | ^^ expands to self-referential type + | + = note: expanded type is `std::future::GenFuture<[static generator@$DIR/recursive-impl-trait-type.rs:65:43: 67:2 {impl std::future::Future, ()}]>` + +error[E0720]: opaque type expands to a recursive type + --> $DIR/recursive-impl-trait-type.rs:73:26 + | +LL | fn mutual_recursion() -> impl Sync { //~ ERROR + | ^^^^^^^^^ expands to self-referential type + | + = note: type resolves to itself + +error[E0720]: opaque type expands to a recursive type + --> $DIR/recursive-impl-trait-type.rs:77:28 + | +LL | fn mutual_recursion_b() -> impl Sized { //~ ERROR + | ^^^^^^^^^^ expands to self-referential type + | + = note: type resolves to itself + +error: aborting due to 15 previous errors + +For more information about this error, try `rustc --explain E0720`. diff --git a/src/test/ui/lint/lint-group-nonstandard-style.stderr b/src/test/ui/lint/lint-group-nonstandard-style.stderr index d85ca7811d01e..780b4d70aae7f 100644 --- a/src/test/ui/lint/lint-group-nonstandard-style.stderr +++ b/src/test/ui/lint/lint-group-nonstandard-style.stderr @@ -1,7 +1,7 @@ -warning: type `snake_case` should have a camel case name such as `SnakeCase` +warning: type `snake_case` should have an upper camel case name such as `SnakeCase` --> $DIR/lint-group-nonstandard-style.rs:22:9 | -LL | struct snake_case; //~ WARN should have a camel +LL | struct snake_case; //~ WARN should have an upper camel | ^^^^^^^^^^^^^^^^^^ | note: lint level defined here diff --git a/src/test/ui/lint/lint-non-camel-case-types.rs b/src/test/ui/lint/lint-non-camel-case-types.rs index 436763b831687..15ebd0171c8fc 100644 --- a/src/test/ui/lint/lint-non-camel-case-types.rs +++ b/src/test/ui/lint/lint-non-camel-case-types.rs @@ -2,31 +2,31 @@ #![allow(dead_code)] struct ONE_TWO_THREE; -//~^ ERROR type `ONE_TWO_THREE` should have a camel case name such as `OneTwoThree` +//~^ ERROR type `ONE_TWO_THREE` should have an upper camel case name such as `OneTwoThree` -struct foo { //~ ERROR type `foo` should have a camel case name such as `Foo` +struct foo { //~ ERROR type `foo` should have an upper camel case name such as `Foo` bar: isize, } -enum foo2 { //~ ERROR type `foo2` should have a camel case name such as `Foo2` +enum foo2 { //~ ERROR type `foo2` should have an upper camel case name such as `Foo2` Bar } -struct foo3 { //~ ERROR type `foo3` should have a camel case name such as `Foo3` +struct foo3 { //~ ERROR type `foo3` should have an upper camel case name such as `Foo3` bar: isize } -type foo4 = isize; //~ ERROR type `foo4` should have a camel case name such as `Foo4` +type foo4 = isize; //~ ERROR type `foo4` should have an upper camel case name such as `Foo4` enum Foo5 { - bar //~ ERROR variant `bar` should have a camel case name such as `Bar` + bar //~ ERROR variant `bar` should have an upper camel case name such as `Bar` } -trait foo6 { //~ ERROR trait `foo6` should have a camel case name such as `Foo6` +trait foo6 { //~ ERROR trait `foo6` should have an upper camel case name such as `Foo6` fn dummy(&self) { } } -fn f(_: ty) {} //~ ERROR type parameter `ty` should have a camel case name such as `Ty` +fn f(_: ty) {} //~ ERROR type parameter `ty` should have an upper camel case name such as `Ty` #[repr(C)] struct foo7 { @@ -35,10 +35,10 @@ struct foo7 { struct X86_64; -struct X86__64; //~ ERROR type `X86__64` should have a camel case name such as `X86_64` +struct X86__64; //~ ERROR type `X86__64` should have an upper camel case name such as `X86_64` -struct Abc_123; //~ ERROR type `Abc_123` should have a camel case name such as `Abc123` +struct Abc_123; //~ ERROR type `Abc_123` should have an upper camel case name such as `Abc123` -struct A1_b2_c3; //~ ERROR type `A1_b2_c3` should have a camel case name such as `A1B2C3` +struct A1_b2_c3; //~ ERROR type `A1_b2_c3` should have an upper camel case name such as `A1B2C3` fn main() { } diff --git a/src/test/ui/lint/lint-non-camel-case-types.stderr b/src/test/ui/lint/lint-non-camel-case-types.stderr index 31a8555977116..7d4faa0694405 100644 --- a/src/test/ui/lint/lint-non-camel-case-types.stderr +++ b/src/test/ui/lint/lint-non-camel-case-types.stderr @@ -1,4 +1,4 @@ -error: type `ONE_TWO_THREE` should have a camel case name such as `OneTwoThree` +error: type `ONE_TWO_THREE` should have an upper camel case name such as `OneTwoThree` --> $DIR/lint-non-camel-case-types.rs:4:1 | LL | struct ONE_TWO_THREE; @@ -10,72 +10,72 @@ note: lint level defined here LL | #![forbid(non_camel_case_types)] | ^^^^^^^^^^^^^^^^^^^^ -error: type `foo` should have a camel case name such as `Foo` +error: type `foo` should have an upper camel case name such as `Foo` --> $DIR/lint-non-camel-case-types.rs:7:1 | -LL | / struct foo { //~ ERROR type `foo` should have a camel case name such as `Foo` +LL | / struct foo { //~ ERROR type `foo` should have an upper camel case name such as `Foo` LL | | bar: isize, LL | | } | |_^ -error: type `foo2` should have a camel case name such as `Foo2` +error: type `foo2` should have an upper camel case name such as `Foo2` --> $DIR/lint-non-camel-case-types.rs:11:1 | -LL | / enum foo2 { //~ ERROR type `foo2` should have a camel case name such as `Foo2` +LL | / enum foo2 { //~ ERROR type `foo2` should have an upper camel case name such as `Foo2` LL | | Bar LL | | } | |_^ -error: type `foo3` should have a camel case name such as `Foo3` +error: type `foo3` should have an upper camel case name such as `Foo3` --> $DIR/lint-non-camel-case-types.rs:15:1 | -LL | / struct foo3 { //~ ERROR type `foo3` should have a camel case name such as `Foo3` +LL | / struct foo3 { //~ ERROR type `foo3` should have an upper camel case name such as `Foo3` LL | | bar: isize LL | | } | |_^ -error: type `foo4` should have a camel case name such as `Foo4` +error: type `foo4` should have an upper camel case name such as `Foo4` --> $DIR/lint-non-camel-case-types.rs:19:1 | -LL | type foo4 = isize; //~ ERROR type `foo4` should have a camel case name such as `Foo4` +LL | type foo4 = isize; //~ ERROR type `foo4` should have an upper camel case name such as `Foo4` | ^^^^^^^^^^^^^^^^^^ -error: variant `bar` should have a camel case name such as `Bar` +error: variant `bar` should have an upper camel case name such as `Bar` --> $DIR/lint-non-camel-case-types.rs:22:5 | -LL | bar //~ ERROR variant `bar` should have a camel case name such as `Bar` +LL | bar //~ ERROR variant `bar` should have an upper camel case name such as `Bar` | ^^^ -error: trait `foo6` should have a camel case name such as `Foo6` +error: trait `foo6` should have an upper camel case name such as `Foo6` --> $DIR/lint-non-camel-case-types.rs:25:1 | -LL | / trait foo6 { //~ ERROR trait `foo6` should have a camel case name such as `Foo6` +LL | / trait foo6 { //~ ERROR trait `foo6` should have an upper camel case name such as `Foo6` LL | | fn dummy(&self) { } LL | | } | |_^ -error: type parameter `ty` should have a camel case name such as `Ty` +error: type parameter `ty` should have an upper camel case name such as `Ty` --> $DIR/lint-non-camel-case-types.rs:29:6 | -LL | fn f(_: ty) {} //~ ERROR type parameter `ty` should have a camel case name such as `Ty` +LL | fn f(_: ty) {} //~ ERROR type parameter `ty` should have an upper camel case name such as `Ty` | ^^ -error: type `X86__64` should have a camel case name such as `X86_64` +error: type `X86__64` should have an upper camel case name such as `X86_64` --> $DIR/lint-non-camel-case-types.rs:38:1 | -LL | struct X86__64; //~ ERROR type `X86__64` should have a camel case name such as `X86_64` +LL | struct X86__64; //~ ERROR type `X86__64` should have an upper camel case name such as `X86_64` | ^^^^^^^^^^^^^^^ -error: type `Abc_123` should have a camel case name such as `Abc123` +error: type `Abc_123` should have an upper camel case name such as `Abc123` --> $DIR/lint-non-camel-case-types.rs:40:1 | -LL | struct Abc_123; //~ ERROR type `Abc_123` should have a camel case name such as `Abc123` +LL | struct Abc_123; //~ ERROR type `Abc_123` should have an upper camel case name such as `Abc123` | ^^^^^^^^^^^^^^^ -error: type `A1_b2_c3` should have a camel case name such as `A1B2C3` +error: type `A1_b2_c3` should have an upper camel case name such as `A1B2C3` --> $DIR/lint-non-camel-case-types.rs:42:1 | -LL | struct A1_b2_c3; //~ ERROR type `A1_b2_c3` should have a camel case name such as `A1B2C3` +LL | struct A1_b2_c3; //~ ERROR type `A1_b2_c3` should have an upper camel case name such as `A1B2C3` | ^^^^^^^^^^^^^^^^ error: aborting due to 11 previous errors diff --git a/src/tools/cargo b/src/tools/cargo index 0d1f1bbeabd5b..34320d212dca8 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 0d1f1bbeabd5b43a7f3ecfa16540af8e76d5efb4 +Subproject commit 34320d212dca8cd27d06ce93c16c6151f46fcf2e