Auto merge of #87280 - lcnr:lazy-anon-const-default-substs, r=nikomatsakis

lazily "compute" anon const default substs

Continuing the work of #83086, this implements the discussed solution for the [unused substs problem](https://github.com/rust-lang/project-const-generics/blob/master/design-docs/anon-const-substs.md#unused-substs). As of now, anonymous constants inherit all of their parents generics, even if they do not use them, e.g. in `fn foo<T, const N: usize>() -> [T; N + 1]`, the array length has `T` as a generic parameter even though it doesn't use it. These *unused substs* cause some backwards incompatible, and imo incorrect behavior, e.g. #78369.

---
We do not actually filter any generic parameters here and the `default_anon_const_substs` query still a dummy which only checks that
- we now prevent the previously existing query cycles and are able to call `predicates_of(parent)` when computing the substs of anonymous constants
- the default anon consts substs only include the typeflags we assume it does.

Implementing that filtering will be left as future work.

---

The idea of this PR is to delay the creation of the anon const substs until after we've computed `predicates_of` for the parent of the anon const. As the predicates of the parent can however contain the anon const we still have to create a `ty::Const` for it.

We do this by changing the substs field of `ty::Unevaluated` to an option and modifying accesses to instead call the method `unevaluated.substs(tcx)` which returns the substs as before. If the substs - now `substs_` -  of `ty::Unevaluated` are `None`, it means that the anon const currently has its default substs, i.e. the substs it has when first constructed, which are the generic parameters it has available. To be able to call `unevaluated.substs(tcx)` in a `TypeVisitor`, we add the non-defaulted method `fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>>`. In case `tcx_for_anon_const_substs` returns `None`, unknown anon const default substs are skipped entirely.

Even when `substs_` is `None` we still have to treat the constant as if it has its default substs. To do this, `TypeFlags` are modified so that it is clear whether they can still change when *exposing* any anon const default substs. A new flag, `HAS_UNKNOWN_DEFAULT_CONST_SUBSTS`, is added in case some default flags are missing.

The rest of this PR are some smaller changes to either not cause cycles by trying to access the default anon const substs too early or to be able to access the `tcx` in previously unused locations.

cc `@rust-lang/project-const-generics`
r? `@nikomatsakis`
This commit is contained in:
bors 2021-08-26 22:26:23 +00:00
commit 517c28e421
122 changed files with 1022 additions and 520 deletions

View File

@ -129,13 +129,13 @@ pub(crate) fn codegen_constant<'tcx>(
}; };
let const_val = match const_.val { let const_val = match const_.val {
ConstKind::Value(const_val) => const_val, ConstKind::Value(const_val) => const_val,
ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) ConstKind::Unevaluated(uv)
if fx.tcx.is_static(def.did) => if fx.tcx.is_static(uv.def.did) =>
{ {
assert!(substs.is_empty()); assert!(uv.substs(fx.tcx).is_empty());
assert!(promoted.is_none()); assert!(uv.promoted.is_none());
return codegen_static_ref(fx, def.did, fx.layout_of(const_.ty)).to_cvalue(fx); return codegen_static_ref(fx, uv.def.did, fx.layout_of(const_.ty)).to_cvalue(fx);
} }
ConstKind::Unevaluated(unevaluated) => { ConstKind::Unevaluated(unevaluated) => {
match fx.tcx.const_eval_resolve(ParamEnv::reveal_all(), unevaluated, None) { match fx.tcx.const_eval_resolve(ParamEnv::reveal_all(), unevaluated, None) {

View File

@ -499,7 +499,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
ty::Adt(def, ..) if !def.is_box() => { ty::Adt(def, ..) if !def.is_box() => {
// Again, only create type information if full debuginfo is enabled // Again, only create type information if full debuginfo is enabled
if cx.sess().opts.debuginfo == DebugInfo::Full if cx.sess().opts.debuginfo == DebugInfo::Full
&& !impl_self_ty.needs_subst() && !impl_self_ty.definitely_needs_subst(cx.tcx)
{ {
Some(type_metadata(cx, impl_self_ty, rustc_span::DUMMY_SP)) Some(type_metadata(cx, impl_self_ty, rustc_span::DUMMY_SP))
} else { } else {

View File

@ -1398,7 +1398,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
LocalRef::UnsizedPlace(_) => bug!("transmute must not involve unsized locals"), LocalRef::UnsizedPlace(_) => bug!("transmute must not involve unsized locals"),
LocalRef::Operand(None) => { LocalRef::Operand(None) => {
let dst_layout = bx.layout_of(self.monomorphized_place_ty(dst.as_ref())); let dst_layout = bx.layout_of(self.monomorphized_place_ty(dst.as_ref()));
assert!(!dst_layout.ty.has_erasable_regions()); assert!(!dst_layout.ty.has_erasable_regions(self.cx.tcx()));
let place = PlaceRef::alloca(bx, dst_layout); let place = PlaceRef::alloca(bx, dst_layout);
place.storage_live(bx); place.storage_live(bx);
self.codegen_transmute_into(bx, src, place); self.codegen_transmute_into(bx, src, place);

View File

@ -216,7 +216,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
let mut allocate_local = |local| { let mut allocate_local = |local| {
let decl = &mir.local_decls[local]; let decl = &mir.local_decls[local];
let layout = bx.layout_of(fx.monomorphize(decl.ty)); let layout = bx.layout_of(fx.monomorphize(decl.ty));
assert!(!layout.ty.has_erasable_regions()); assert!(!layout.ty.has_erasable_regions(cx.tcx()));
if local == mir::RETURN_PLACE && fx.fn_abi.ret.is_indirect() { if local == mir::RETURN_PLACE && fx.fn_abi.ret.is_indirect() {
debug!("alloc: {:?} (return place) -> place", local); debug!("alloc: {:?} (return place) -> place", local);

View File

@ -470,7 +470,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
{ {
let needs_canonical_flags = if canonicalize_region_mode.any() { let needs_canonical_flags = if canonicalize_region_mode.any() {
TypeFlags::NEEDS_INFER | TypeFlags::NEEDS_INFER |
TypeFlags::HAS_FREE_REGIONS | // `HAS_RE_PLACEHOLDER` implies `HAS_FREE_REGIONS` TypeFlags::HAS_POTENTIAL_FREE_REGIONS | // `HAS_RE_PLACEHOLDER` implies `HAS_POTENTIAL_FREE_REGIONS`
TypeFlags::HAS_TY_PLACEHOLDER | TypeFlags::HAS_TY_PLACEHOLDER |
TypeFlags::HAS_CT_PLACEHOLDER TypeFlags::HAS_CT_PLACEHOLDER
} else { } else {

View File

@ -129,6 +129,8 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> {
where where
R: ConstEquateRelation<'tcx>, R: ConstEquateRelation<'tcx>,
{ {
let a = self.tcx.expose_default_const_substs(a);
let b = self.tcx.expose_default_const_substs(b);
debug!("{}.consts({:?}, {:?})", relation.tag(), a, b); debug!("{}.consts({:?}, {:?})", relation.tag(), a, b);
if a == b { if a == b {
return Ok(a); return Ok(a);
@ -742,10 +744,9 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
} }
} }
} }
ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) ty::ConstKind::Unevaluated(uv) if self.tcx().lazy_normalization() => {
if self.tcx().lazy_normalization() => assert_eq!(uv.promoted, None);
{ let substs = uv.substs(self.tcx());
assert_eq!(promoted, None);
let substs = self.relate_with_variance( let substs = self.relate_with_variance(
ty::Variance::Invariant, ty::Variance::Invariant,
ty::VarianceDiagInfo::default(), ty::VarianceDiagInfo::default(),
@ -754,7 +755,7 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
)?; )?;
Ok(self.tcx().mk_const(ty::Const { Ok(self.tcx().mk_const(ty::Const {
ty: c.ty, ty: c.ty,
val: ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }), val: ty::ConstKind::Unevaluated(ty::Unevaluated::new(uv.def, substs)),
})) }))
} }
_ => relate::super_relate_consts(self, c, c), _ => relate::super_relate_consts(self, c, c),
@ -976,10 +977,9 @@ impl TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> {
} }
} }
} }
ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) ty::ConstKind::Unevaluated(uv) if self.tcx().lazy_normalization() => {
if self.tcx().lazy_normalization() => assert_eq!(uv.promoted, None);
{ let substs = uv.substs(self.tcx());
assert_eq!(promoted, None);
let substs = self.relate_with_variance( let substs = self.relate_with_variance(
ty::Variance::Invariant, ty::Variance::Invariant,
ty::VarianceDiagInfo::default(), ty::VarianceDiagInfo::default(),
@ -988,7 +988,7 @@ impl TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> {
)?; )?;
Ok(self.tcx().mk_const(ty::Const { Ok(self.tcx().mk_const(ty::Const {
ty: c.ty, ty: c.ty,
val: ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }), val: ty::ConstKind::Unevaluated(ty::Unevaluated::new(uv.def, substs)),
})) }))
} }
_ => relate::super_relate_consts(self, c, c), _ => relate::super_relate_consts(self, c, c),

View File

@ -1537,6 +1537,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
} }
impl<'tcx> ty::fold::TypeVisitor<'tcx> for OpaqueTypesVisitor<'tcx> { impl<'tcx> ty::fold::TypeVisitor<'tcx> for OpaqueTypesVisitor<'tcx> {
fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
Some(self.tcx)
}
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
if let Some((kind, def_id)) = TyCategory::from_ty(self.tcx, t) { if let Some((kind, def_id)) = TyCategory::from_ty(self.tcx, t) {
let span = self.tcx.def_span(def_id); let span = self.tcx.def_span(def_id);

View File

@ -51,7 +51,7 @@ impl<'a, 'tcx> FindHirNodeVisitor<'a, 'tcx> {
fn node_ty_contains_target(&self, hir_id: HirId) -> Option<Ty<'tcx>> { fn node_ty_contains_target(&self, hir_id: HirId) -> Option<Ty<'tcx>> {
self.node_type_opt(hir_id).map(|ty| self.infcx.resolve_vars_if_possible(ty)).filter(|ty| { self.node_type_opt(hir_id).map(|ty| self.infcx.resolve_vars_if_possible(ty)).filter(|ty| {
ty.walk().any(|inner| { ty.walk(self.infcx.tcx).any(|inner| {
inner == self.target inner == self.target
|| match (inner.unpack(), self.target.unpack()) { || match (inner.unpack(), self.target.unpack()) {
(GenericArgKind::Type(inner_ty), GenericArgKind::Type(target_ty)) => { (GenericArgKind::Type(inner_ty), GenericArgKind::Type(target_ty)) => {

View File

@ -9,7 +9,9 @@ use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorRepor
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::{walk_ty, ErasedMap, NestedVisitorMap, Visitor}; use rustc_hir::intravisit::{walk_ty, ErasedMap, NestedVisitorMap, Visitor};
use rustc_hir::{self as hir, GenericBound, Item, ItemKind, Lifetime, LifetimeName, Node, TyKind}; use rustc_hir::{self as hir, GenericBound, Item, ItemKind, Lifetime, LifetimeName, Node, TyKind};
use rustc_middle::ty::{self, AssocItemContainer, RegionKind, Ty, TypeFoldable, TypeVisitor}; use rustc_middle::ty::{
self, AssocItemContainer, RegionKind, Ty, TyCtxt, TypeFoldable, TypeVisitor,
};
use rustc_span::symbol::Ident; use rustc_span::symbol::Ident;
use rustc_span::{MultiSpan, Span}; use rustc_span::{MultiSpan, Span};
@ -476,8 +478,14 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
/// Collect all the trait objects in a type that could have received an implicit `'static` lifetime. /// Collect all the trait objects in a type that could have received an implicit `'static` lifetime.
pub(super) struct TraitObjectVisitor(pub(super) FxHashSet<DefId>); pub(super) struct TraitObjectVisitor(pub(super) FxHashSet<DefId>);
impl TypeVisitor<'_> for TraitObjectVisitor { impl<'tcx> TypeVisitor<'tcx> for TraitObjectVisitor {
fn visit_ty(&mut self, t: Ty<'_>) -> ControlFlow<Self::BreakTy> { fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
// The default anon const substs cannot include
// trait objects, so we don't have to bother looking.
None
}
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
match t.kind() { match t.kind() {
ty::Dynamic(preds, RegionKind::ReStatic) => { ty::Dynamic(preds, RegionKind::ReStatic) => {
if let Some(def_id) = preds.principal_def_id() { if let Some(def_id) = preds.principal_def_id() {

View File

@ -146,7 +146,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> {
} }
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
if !t.needs_infer() && !t.has_erasable_regions() { if !t.needs_infer() && !t.has_erasable_regions(self.tcx()) {
return t; return t;
} }

View File

@ -675,13 +675,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
/// canonicalizing the consts. /// canonicalizing the consts.
pub fn try_unify_abstract_consts( pub fn try_unify_abstract_consts(
&self, &self,
a: ty::Unevaluated<'tcx>, a: ty::Unevaluated<'tcx, ()>,
b: ty::Unevaluated<'tcx>, b: ty::Unevaluated<'tcx, ()>,
) -> bool { ) -> bool {
let canonical = self.canonicalize_query( let canonical = self.canonicalize_query((a, b), &mut OriginalQueryValues::default());
((a.def, a.substs), (b.def, b.substs)),
&mut OriginalQueryValues::default(),
);
debug!("canonical consts: {:?}", &canonical.value); debug!("canonical consts: {:?}", &canonical.value);
self.tcx.try_unify_abstract_consts(canonical.value) self.tcx.try_unify_abstract_consts(canonical.value)
@ -1592,16 +1589,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
pub fn const_eval_resolve( pub fn const_eval_resolve(
&self, &self,
param_env: ty::ParamEnv<'tcx>, param_env: ty::ParamEnv<'tcx>,
ty::Unevaluated { def, substs, promoted }: ty::Unevaluated<'tcx>, unevaluated: ty::Unevaluated<'tcx>,
span: Option<Span>, span: Option<Span>,
) -> EvalToConstValueResult<'tcx> { ) -> EvalToConstValueResult<'tcx> {
let mut original_values = OriginalQueryValues::default(); let mut original_values = OriginalQueryValues::default();
let canonical = self.canonicalize_query((param_env, substs), &mut original_values); let canonical = self.canonicalize_query((param_env, unevaluated), &mut original_values);
let (param_env, substs) = canonical.value; let (param_env, unevaluated) = canonical.value;
// The return value is the evaluated value which doesn't contain any reference to inference // The return value is the evaluated value which doesn't contain any reference to inference
// variables, thus we don't need to substitute back the original values. // variables, thus we don't need to substitute back the original values.
self.tcx.const_eval_resolve(param_env, ty::Unevaluated { def, substs, promoted }, span) self.tcx.const_eval_resolve(param_env, unevaluated, span)
} }
/// If `typ` is a type variable of some kind, resolve it one level /// If `typ` is a type variable of some kind, resolve it one level

View File

@ -202,6 +202,7 @@ where
}; };
value.skip_binder().visit_with(&mut ScopeInstantiator { value.skip_binder().visit_with(&mut ScopeInstantiator {
tcx: self.infcx.tcx,
next_region: &mut next_region, next_region: &mut next_region,
target_index: ty::INNERMOST, target_index: ty::INNERMOST,
bound_region_scope: &mut scope, bound_region_scope: &mut scope,
@ -757,6 +758,7 @@ where
/// `for<..`>. For each of those, it creates an entry in /// `for<..`>. For each of those, it creates an entry in
/// `bound_region_scope`. /// `bound_region_scope`.
struct ScopeInstantiator<'me, 'tcx> { struct ScopeInstantiator<'me, 'tcx> {
tcx: TyCtxt<'tcx>,
next_region: &'me mut dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx>, next_region: &'me mut dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx>,
// The debruijn index of the scope we are instantiating. // The debruijn index of the scope we are instantiating.
target_index: ty::DebruijnIndex, target_index: ty::DebruijnIndex,
@ -764,6 +766,10 @@ struct ScopeInstantiator<'me, 'tcx> {
} }
impl<'me, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'me, 'tcx> { impl<'me, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'me, 'tcx> {
fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
Some(self.tcx)
}
fn visit_binder<T: TypeFoldable<'tcx>>( fn visit_binder<T: TypeFoldable<'tcx>>(
&mut self, &mut self,
t: &ty::Binder<'tcx, T>, t: &ty::Binder<'tcx, T>,

View File

@ -189,7 +189,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
visited: &mut SsoHashSet<GenericArg<'tcx>>, visited: &mut SsoHashSet<GenericArg<'tcx>>,
) -> VerifyBound<'tcx> { ) -> VerifyBound<'tcx> {
let mut bounds = parent let mut bounds = parent
.walk_shallow(visited) .walk_shallow(self.tcx, visited)
.filter_map(|child| match child.unpack() { .filter_map(|child| match child.unpack() {
GenericArgKind::Type(ty) => Some(self.type_bound(ty, visited)), GenericArgKind::Type(ty) => Some(self.type_bound(ty, visited)),
GenericArgKind::Lifetime(lt) => { GenericArgKind::Lifetime(lt) => {

View File

@ -126,6 +126,11 @@ impl<'a, 'tcx> UnresolvedTypeFinder<'a, 'tcx> {
impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeFinder<'a, 'tcx> { impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeFinder<'a, 'tcx> {
type BreakTy = (Ty<'tcx>, Option<Span>); type BreakTy = (Ty<'tcx>, Option<Span>);
fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
Some(self.infcx.tcx)
}
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
let t = self.infcx.shallow_resolve(t); let t = self.infcx.shallow_resolve(t);
if t.has_infer_types() { if t.has_infer_types() {

View File

@ -152,8 +152,8 @@ declare_lint! {
declare_lint_pass!(BoxPointers => [BOX_POINTERS]); declare_lint_pass!(BoxPointers => [BOX_POINTERS]);
impl BoxPointers { impl BoxPointers {
fn check_heap_type(&self, cx: &LateContext<'_>, span: Span, ty: Ty<'_>) { fn check_heap_type<'tcx>(&self, cx: &LateContext<'tcx>, span: Span, ty: Ty<'tcx>) {
for leaf in ty.walk() { for leaf in ty.walk(cx.tcx) {
if let GenericArgKind::Type(leaf_ty) = leaf.unpack() { if let GenericArgKind::Type(leaf_ty) = leaf.unpack() {
if leaf_ty.is_box() { if leaf_ty.is_box() {
cx.struct_span_lint(BOX_POINTERS, span, |lint| { cx.struct_span_lint(BOX_POINTERS, span, |lint| {
@ -1656,7 +1656,7 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
ConstEquate(..) | ConstEquate(..) |
TypeWellFormedFromEnv(..) => continue, TypeWellFormedFromEnv(..) => continue,
}; };
if predicate.is_global() { if predicate.is_global(cx.tcx) {
cx.struct_span_lint(TRIVIAL_BOUNDS, span, |lint| { cx.struct_span_lint(TRIVIAL_BOUNDS, span, |lint| {
lint.build(&format!( lint.build(&format!(
"{} bound {} does not depend on any type \ "{} bound {} does not depend on any type \

View File

@ -62,7 +62,7 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
_ => return, _ => return,
}; };
let substs = cx.typeck_results().node_substs(expr.hir_id); let substs = cx.typeck_results().node_substs(expr.hir_id);
if substs.needs_subst() { if substs.definitely_needs_subst(cx.tcx) {
// We can't resolve on types that require monomorphization, so we don't handle them if // We can't resolve on types that require monomorphization, so we don't handle them if
// we need to perfom substitution. // we need to perfom substitution.
return; return;

View File

@ -1160,6 +1160,9 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
impl<'a, 'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueTypes<'a, 'tcx> { impl<'a, 'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueTypes<'a, 'tcx> {
type BreakTy = Ty<'tcx>; type BreakTy = Ty<'tcx>;
fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
Some(self.cx.tcx)
}
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
match ty.kind() { match ty.kind() {

View File

@ -38,7 +38,7 @@ impl<'tcx> TyCtxt<'tcx> {
ct: ty::Unevaluated<'tcx>, ct: ty::Unevaluated<'tcx>,
span: Option<Span>, span: Option<Span>,
) -> EvalToConstValueResult<'tcx> { ) -> EvalToConstValueResult<'tcx> {
match ty::Instance::resolve_opt_const_arg(self, param_env, ct.def, ct.substs) { match ty::Instance::resolve_opt_const_arg(self, param_env, ct.def, ct.substs(self)) {
Ok(Some(instance)) => { Ok(Some(instance)) => {
let cid = GlobalId { instance, promoted: ct.promoted }; let cid = GlobalId { instance, promoted: ct.promoted };
self.const_eval_global_id(param_env, cid, span) self.const_eval_global_id(param_env, cid, span)

View File

@ -242,6 +242,7 @@ pub struct Body<'tcx> {
impl<'tcx> Body<'tcx> { impl<'tcx> Body<'tcx> {
pub fn new( pub fn new(
tcx: TyCtxt<'tcx>,
source: MirSource<'tcx>, source: MirSource<'tcx>,
basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>, basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
source_scopes: IndexVec<SourceScope, SourceScopeData<'tcx>>, source_scopes: IndexVec<SourceScope, SourceScopeData<'tcx>>,
@ -284,7 +285,7 @@ impl<'tcx> Body<'tcx> {
predecessor_cache: PredecessorCache::new(), predecessor_cache: PredecessorCache::new(),
is_cyclic: GraphIsCyclicCache::new(), is_cyclic: GraphIsCyclicCache::new(),
}; };
body.is_polymorphic = body.has_param_types_or_consts(); body.is_polymorphic = body.definitely_has_param_types_or_consts(tcx);
body body
} }
@ -294,7 +295,7 @@ impl<'tcx> Body<'tcx> {
/// is only useful for testing but cannot be `#[cfg(test)]` because it is used in a different /// is only useful for testing but cannot be `#[cfg(test)]` because it is used in a different
/// crate. /// crate.
pub fn new_cfg_only(basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>) -> Self { pub fn new_cfg_only(basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>) -> Self {
let mut body = Body { Body {
phase: MirPhase::Build, phase: MirPhase::Build,
source: MirSource::item(DefId::local(CRATE_DEF_INDEX)), source: MirSource::item(DefId::local(CRATE_DEF_INDEX)),
basic_blocks, basic_blocks,
@ -310,9 +311,7 @@ impl<'tcx> Body<'tcx> {
is_polymorphic: false, is_polymorphic: false,
predecessor_cache: PredecessorCache::new(), predecessor_cache: PredecessorCache::new(),
is_cyclic: GraphIsCyclicCache::new(), is_cyclic: GraphIsCyclicCache::new(),
}; }
body.is_polymorphic = body.has_param_types_or_consts();
body
} }
#[inline] #[inline]

View File

@ -114,6 +114,10 @@ rustc_queries! {
desc { |tcx| "compute const default for a given parameter `{}`", tcx.def_path_str(param) } desc { |tcx| "compute const default for a given parameter `{}`", tcx.def_path_str(param) }
} }
query default_anon_const_substs(key: DefId) -> SubstsRef<'tcx> {
desc { |tcx| "computing the default generic arguments for `{}`", tcx.def_path_str(key) }
}
/// Records the type of every item. /// Records the type of every item.
query type_of(key: DefId) -> Ty<'tcx> { query type_of(key: DefId) -> Ty<'tcx> {
desc { |tcx| "computing type of `{}`", tcx.def_path_str(key) } desc { |tcx| "computing type of `{}`", tcx.def_path_str(key) }
@ -299,12 +303,11 @@ rustc_queries! {
} }
query try_unify_abstract_consts(key: ( query try_unify_abstract_consts(key: (
(ty::WithOptConstParam<DefId>, SubstsRef<'tcx>), ty::Unevaluated<'tcx, ()>, ty::Unevaluated<'tcx, ()>
(ty::WithOptConstParam<DefId>, SubstsRef<'tcx>)
)) -> bool { )) -> bool {
desc { desc {
|tcx| "trying to unify the generic constants {} and {}", |tcx| "trying to unify the generic constants {} and {}",
tcx.def_path_str(key.0.0.did), tcx.def_path_str(key.1.0.did) tcx.def_path_str(key.0.def.did), tcx.def_path_str(key.1.def.did)
} }
} }

View File

@ -1,6 +1,5 @@
use crate::mir::interpret::ConstValue; use crate::mir::interpret::ConstValue;
use crate::mir::interpret::{LitToConstInput, Scalar}; use crate::mir::interpret::{LitToConstInput, Scalar};
use crate::ty::subst::InternalSubsts;
use crate::ty::{self, Ty, TyCtxt}; use crate::ty::{self, Ty, TyCtxt};
use crate::ty::{ParamEnv, ParamEnvAnd}; use crate::ty::{ParamEnv, ParamEnvAnd};
use rustc_errors::ErrorReported; use rustc_errors::ErrorReported;
@ -100,7 +99,7 @@ impl<'tcx> Const<'tcx> {
} }
_ => ty::ConstKind::Unevaluated(ty::Unevaluated { _ => ty::ConstKind::Unevaluated(ty::Unevaluated {
def: def.to_global(), def: def.to_global(),
substs: InternalSubsts::identity_for_item(tcx, def.did.to_def_id()), substs_: None,
promoted: None, promoted: None,
}), }),
}; };

View File

@ -1,4 +1,5 @@
use std::convert::TryInto; use std::convert::TryInto;
use std::fmt;
use crate::mir::interpret::{AllocId, ConstValue, Scalar}; use crate::mir::interpret::{AllocId, ConstValue, Scalar};
use crate::mir::Promoted; use crate::mir::Promoted;
@ -12,12 +13,53 @@ use rustc_target::abi::Size;
use super::ScalarInt; use super::ScalarInt;
/// An unevaluated, potentially generic, constant. /// An unevaluated, potentially generic, constant.
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable)] ///
/// If `substs_` is `None` it means that this anon const
/// still has its default substs.
///
/// We check for all possible substs in `fn default_anon_const_substs`,
/// so refer to that check for more info.
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Lift)]
#[derive(Hash, HashStable)] #[derive(Hash, HashStable)]
pub struct Unevaluated<'tcx> { pub struct Unevaluated<'tcx, P = Option<Promoted>> {
pub def: ty::WithOptConstParam<DefId>, pub def: ty::WithOptConstParam<DefId>,
pub substs: SubstsRef<'tcx>, pub substs_: Option<SubstsRef<'tcx>>,
pub promoted: Option<Promoted>, pub promoted: P,
}
impl<'tcx> Unevaluated<'tcx> {
#[inline]
pub fn shrink(self) -> Unevaluated<'tcx, ()> {
debug_assert_eq!(self.promoted, None);
Unevaluated { def: self.def, substs_: self.substs_, promoted: () }
}
}
impl<'tcx> Unevaluated<'tcx, ()> {
#[inline]
pub fn expand(self) -> Unevaluated<'tcx> {
Unevaluated { def: self.def, substs_: self.substs_, promoted: None }
}
}
impl<'tcx, P: Default> Unevaluated<'tcx, P> {
#[inline]
pub fn new(def: ty::WithOptConstParam<DefId>, substs: SubstsRef<'tcx>) -> Unevaluated<'tcx, P> {
Unevaluated { def, substs_: Some(substs), promoted: Default::default() }
}
}
impl<'tcx, P: Default + PartialEq + fmt::Debug> Unevaluated<'tcx, P> {
#[inline]
pub fn substs(self, tcx: TyCtxt<'tcx>) -> SubstsRef<'tcx> {
self.substs_.unwrap_or_else(|| {
// We must not use the parents default substs for promoted constants
// as that can result in incorrect substs and calls the `default_anon_const_substs`
// for something that might not actually be a constant.
debug_assert_eq!(self.promoted, Default::default());
tcx.default_anon_const_substs(self.def.did)
})
}
} }
/// Represents a constant in Rust. /// Represents a constant in Rust.
@ -109,7 +151,7 @@ impl<'tcx> ConstKind<'tcx> {
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
param_env: ParamEnv<'tcx>, param_env: ParamEnv<'tcx>,
) -> Option<Result<ConstValue<'tcx>, ErrorReported>> { ) -> Option<Result<ConstValue<'tcx>, ErrorReported>> {
if let ConstKind::Unevaluated(Unevaluated { def, substs, promoted }) = self { if let ConstKind::Unevaluated(unevaluated) = self {
use crate::mir::interpret::ErrorHandled; use crate::mir::interpret::ErrorHandled;
// HACK(eddyb) this erases lifetimes even though `const_eval_resolve` // HACK(eddyb) this erases lifetimes even though `const_eval_resolve`
@ -118,29 +160,32 @@ impl<'tcx> ConstKind<'tcx> {
// Note that we erase regions *before* calling `with_reveal_all_normalized`, // Note that we erase regions *before* calling `with_reveal_all_normalized`,
// so that we don't try to invoke this query with // so that we don't try to invoke this query with
// any region variables. // any region variables.
let param_env_and_substs = tcx let param_env_and = tcx
.erase_regions(param_env) .erase_regions(param_env)
.with_reveal_all_normalized(tcx) .with_reveal_all_normalized(tcx)
.and(tcx.erase_regions(substs)); .and(tcx.erase_regions(unevaluated));
// HACK(eddyb) when the query key would contain inference variables, // HACK(eddyb) when the query key would contain inference variables,
// attempt using identity substs and `ParamEnv` instead, that will succeed // attempt using identity substs and `ParamEnv` instead, that will succeed
// when the expression doesn't depend on any parameters. // when the expression doesn't depend on any parameters.
// FIXME(eddyb, skinny121) pass `InferCtxt` into here when it's available, so that // FIXME(eddyb, skinny121) pass `InferCtxt` into here when it's available, so that
// we can call `infcx.const_eval_resolve` which handles inference variables. // we can call `infcx.const_eval_resolve` which handles inference variables.
let param_env_and_substs = if param_env_and_substs.needs_infer() { let param_env_and = if param_env_and.needs_infer() {
tcx.param_env(def.did).and(InternalSubsts::identity_for_item(tcx, def.did)) tcx.param_env(unevaluated.def.did).and(ty::Unevaluated {
def: unevaluated.def,
substs_: Some(InternalSubsts::identity_for_item(tcx, unevaluated.def.did)),
promoted: unevaluated.promoted,
})
} else { } else {
param_env_and_substs param_env_and
}; };
// FIXME(eddyb) maybe the `const_eval_*` methods should take // FIXME(eddyb) maybe the `const_eval_*` methods should take
// `ty::ParamEnvAnd<SubstsRef>` instead of having them separate. // `ty::ParamEnvAnd` instead of having them separate.
let (param_env, substs) = param_env_and_substs.into_parts(); let (param_env, unevaluated) = param_env_and.into_parts();
// try to resolve e.g. associated constants to their definition on an impl, and then // try to resolve e.g. associated constants to their definition on an impl, and then
// evaluate the const. // evaluate the const.
match tcx.const_eval_resolve(param_env, ty::Unevaluated { def, substs, promoted }, None) match tcx.const_eval_resolve(param_env, unevaluated, None) {
{
// NOTE(eddyb) `val` contains no lifetimes/types/consts, // NOTE(eddyb) `val` contains no lifetimes/types/consts,
// and we use the original type, so nothing from `substs` // and we use the original type, so nothing from `substs`
// (which may be identity substs, see above), // (which may be identity substs, see above),

View File

@ -21,7 +21,9 @@ impl<'tcx> TyCtxt<'tcx> {
T: TypeFoldable<'tcx>, T: TypeFoldable<'tcx>,
{ {
// If there's nothing to erase avoid performing the query at all // If there's nothing to erase avoid performing the query at all
if !value.has_type_flags(TypeFlags::HAS_RE_LATE_BOUND | TypeFlags::HAS_FREE_REGIONS) { if !value
.has_type_flags(TypeFlags::HAS_RE_LATE_BOUND | TypeFlags::HAS_POTENTIAL_FREE_REGIONS)
{
return value; return value;
} }
debug!("erase_regions({:?})", value); debug!("erase_regions({:?})", value);

View File

@ -34,6 +34,12 @@ impl FlagComputation {
result.flags result.flags
} }
pub fn for_unevaluated_const(uv: ty::Unevaluated<'_>) -> TypeFlags {
let mut result = FlagComputation::new();
result.add_unevaluated_const(uv);
result.flags
}
fn add_flags(&mut self, flags: TypeFlags) { fn add_flags(&mut self, flags: TypeFlags) {
self.flags = self.flags | flags; self.flags = self.flags | flags;
} }
@ -91,7 +97,7 @@ impl FlagComputation {
&ty::Error(_) => self.add_flags(TypeFlags::HAS_ERROR), &ty::Error(_) => self.add_flags(TypeFlags::HAS_ERROR),
&ty::Param(_) => { &ty::Param(_) => {
self.add_flags(TypeFlags::HAS_TY_PARAM); self.add_flags(TypeFlags::HAS_KNOWN_TY_PARAM);
self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE); self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
} }
@ -246,8 +252,8 @@ impl FlagComputation {
ty::PredicateKind::ClosureKind(_def_id, substs, _kind) => { ty::PredicateKind::ClosureKind(_def_id, substs, _kind) => {
self.add_substs(substs); self.add_substs(substs);
} }
ty::PredicateKind::ConstEvaluatable(_def_id, substs) => { ty::PredicateKind::ConstEvaluatable(uv) => {
self.add_substs(substs); self.add_unevaluated_const(uv);
} }
ty::PredicateKind::ConstEquate(expected, found) => { ty::PredicateKind::ConstEquate(expected, found) => {
self.add_const(expected); self.add_const(expected);
@ -292,7 +298,7 @@ impl FlagComputation {
self.add_bound_var(debruijn); self.add_bound_var(debruijn);
} }
ty::ConstKind::Param(_) => { ty::ConstKind::Param(_) => {
self.add_flags(TypeFlags::HAS_CT_PARAM); self.add_flags(TypeFlags::HAS_KNOWN_CT_PARAM);
self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE); self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
} }
ty::ConstKind::Placeholder(_) => { ty::ConstKind::Placeholder(_) => {
@ -304,8 +310,24 @@ impl FlagComputation {
} }
} }
fn add_unevaluated_const(&mut self, ct: ty::Unevaluated<'tcx>) { fn add_unevaluated_const<P>(&mut self, ct: ty::Unevaluated<'tcx, P>) {
self.add_substs(ct.substs); // The generic arguments of unevaluated consts are a bit special,
// see the `rustc-dev-guide` for more information.
//
// FIXME(@lcnr): Actually add a link here.
if let Some(substs) = ct.substs_ {
// If they are available, we treat them as ordinary generic arguments.
self.add_substs(substs);
} else {
// Otherwise, we add `HAS_UNKNOWN_DEFAULT_CONST_SUBSTS` to signify
// that our const may potentially refer to generic parameters.
//
// Note that depending on which generic parameters are actually
// used in this constant, we may not actually refer to any generic
// parameters at all.
self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
self.add_flags(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS);
}
self.add_flags(TypeFlags::HAS_CT_PROJECTION); self.add_flags(TypeFlags::HAS_CT_PROJECTION);
} }

View File

@ -74,8 +74,14 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone {
self.has_vars_bound_at_or_above(ty::INNERMOST) self.has_vars_bound_at_or_above(ty::INNERMOST)
} }
fn definitely_has_type_flags(&self, tcx: TyCtxt<'tcx>, flags: TypeFlags) -> bool {
self.visit_with(&mut HasTypeFlagsVisitor { tcx: Some(tcx), flags }).break_value()
== Some(FoundFlags)
}
fn has_type_flags(&self, flags: TypeFlags) -> bool { fn has_type_flags(&self, flags: TypeFlags) -> bool {
self.visit_with(&mut HasTypeFlagsVisitor { flags }).break_value() == Some(FoundFlags) self.visit_with(&mut HasTypeFlagsVisitor { tcx: None, flags }).break_value()
== Some(FoundFlags)
} }
fn has_projections(&self) -> bool { fn has_projections(&self) -> bool {
self.has_type_flags(TypeFlags::HAS_PROJECTION) self.has_type_flags(TypeFlags::HAS_PROJECTION)
@ -86,8 +92,18 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone {
fn references_error(&self) -> bool { fn references_error(&self) -> bool {
self.has_type_flags(TypeFlags::HAS_ERROR) self.has_type_flags(TypeFlags::HAS_ERROR)
} }
fn has_param_types_or_consts(&self) -> bool { fn potentially_has_param_types_or_consts(&self) -> bool {
self.has_type_flags(TypeFlags::HAS_TY_PARAM | TypeFlags::HAS_CT_PARAM) self.has_type_flags(
TypeFlags::HAS_KNOWN_TY_PARAM
| TypeFlags::HAS_KNOWN_CT_PARAM
| TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS,
)
}
fn definitely_has_param_types_or_consts(&self, tcx: TyCtxt<'tcx>) -> bool {
self.definitely_has_type_flags(
tcx,
TypeFlags::HAS_KNOWN_TY_PARAM | TypeFlags::HAS_KNOWN_CT_PARAM,
)
} }
fn has_infer_regions(&self) -> bool { fn has_infer_regions(&self) -> bool {
self.has_type_flags(TypeFlags::HAS_RE_INFER) self.has_type_flags(TypeFlags::HAS_RE_INFER)
@ -108,13 +124,18 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone {
| TypeFlags::HAS_CT_PLACEHOLDER, | TypeFlags::HAS_CT_PLACEHOLDER,
) )
} }
fn needs_subst(&self) -> bool { fn potentially_needs_subst(&self) -> bool {
self.has_type_flags(TypeFlags::NEEDS_SUBST) self.has_type_flags(
TypeFlags::KNOWN_NEEDS_SUBST | TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS,
)
}
fn definitely_needs_subst(&self, tcx: TyCtxt<'tcx>) -> bool {
self.definitely_has_type_flags(tcx, TypeFlags::KNOWN_NEEDS_SUBST)
} }
/// "Free" regions in this context means that it has any region /// "Free" regions in this context means that it has any region
/// that is not (a) erased or (b) late-bound. /// that is not (a) erased or (b) late-bound.
fn has_free_regions(&self) -> bool { fn has_free_regions(&self, tcx: TyCtxt<'tcx>) -> bool {
self.has_type_flags(TypeFlags::HAS_FREE_REGIONS) self.definitely_has_type_flags(tcx, TypeFlags::HAS_KNOWN_FREE_REGIONS)
} }
fn has_erased_regions(&self) -> bool { fn has_erased_regions(&self) -> bool {
@ -122,15 +143,25 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone {
} }
/// True if there are any un-erased free regions. /// True if there are any un-erased free regions.
fn has_erasable_regions(&self) -> bool { fn has_erasable_regions(&self, tcx: TyCtxt<'tcx>) -> bool {
self.has_type_flags(TypeFlags::HAS_FREE_REGIONS) self.definitely_has_type_flags(tcx, TypeFlags::HAS_KNOWN_FREE_REGIONS)
}
/// Indicates whether this value definitely references only 'global'
/// generic parameters that are the same regardless of what fn we are
/// in. This is used for caching.
///
/// Note that this function is pessimistic and may incorrectly return
/// `false`.
fn is_known_global(&self) -> bool {
!self.has_type_flags(TypeFlags::HAS_POTENTIAL_FREE_LOCAL_NAMES)
} }
/// Indicates whether this value references only 'global' /// Indicates whether this value references only 'global'
/// generic parameters that are the same regardless of what fn we are /// generic parameters that are the same regardless of what fn we are
/// in. This is used for caching. /// in. This is used for caching.
fn is_global(&self) -> bool { fn is_global(&self, tcx: TyCtxt<'tcx>) -> bool {
!self.has_type_flags(TypeFlags::HAS_FREE_LOCAL_NAMES) !self.definitely_has_type_flags(tcx, TypeFlags::HAS_KNOWN_FREE_LOCAL_NAMES)
} }
/// True if there are any late-bound regions /// True if there are any late-bound regions
@ -182,6 +213,10 @@ pub trait TypeFolder<'tcx>: Sized {
c.super_fold_with(self) c.super_fold_with(self)
} }
fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
p.super_fold_with(self)
}
fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> { fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'tcx> {
bug!("most type folders should not be folding MIR datastructures: {:?}", c) bug!("most type folders should not be folding MIR datastructures: {:?}", c)
} }
@ -189,6 +224,17 @@ pub trait TypeFolder<'tcx>: Sized {
pub trait TypeVisitor<'tcx>: Sized { pub trait TypeVisitor<'tcx>: Sized {
type BreakTy = !; type BreakTy = !;
/// Supplies the `tcx` for an unevaluated anonymous constant in case its default substs
/// are not yet supplied.
///
/// Returning `None` for this method is only recommended if the `TypeVisitor`
/// does not care about default anon const substs, as it ignores generic parameters,
/// and fetching the default substs would cause a query cycle.
///
/// For visitors which return `None` we completely skip the default substs in `ty::Unevaluated::super_visit_with`.
/// This means that incorrectly returning `None` can very quickly lead to ICE or other critical bugs, so be careful and
/// try to return an actual `tcx` if possible.
fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>>;
fn visit_binder<T: TypeFoldable<'tcx>>( fn visit_binder<T: TypeFoldable<'tcx>>(
&mut self, &mut self,
@ -209,6 +255,10 @@ pub trait TypeVisitor<'tcx>: Sized {
c.super_visit_with(self) c.super_visit_with(self)
} }
fn visit_unevaluated_const(&mut self, uv: ty::Unevaluated<'tcx>) -> ControlFlow<Self::BreakTy> {
uv.super_visit_with(self)
}
fn visit_predicate(&mut self, p: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> { fn visit_predicate(&mut self, p: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
p.super_visit_with(self) p.super_visit_with(self)
} }
@ -301,7 +351,8 @@ impl<'tcx> TyCtxt<'tcx> {
value: &impl TypeFoldable<'tcx>, value: &impl TypeFoldable<'tcx>,
callback: impl FnMut(ty::Region<'tcx>) -> bool, callback: impl FnMut(ty::Region<'tcx>) -> bool,
) -> bool { ) -> bool {
struct RegionVisitor<F> { struct RegionVisitor<'tcx, F> {
tcx: TyCtxt<'tcx>,
/// The index of a binder *just outside* the things we have /// The index of a binder *just outside* the things we have
/// traversed. If we encounter a bound region bound by this /// traversed. If we encounter a bound region bound by this
/// binder or one outer to it, it appears free. Example: /// binder or one outer to it, it appears free. Example:
@ -323,12 +374,16 @@ impl<'tcx> TyCtxt<'tcx> {
callback: F, callback: F,
} }
impl<'tcx, F> TypeVisitor<'tcx> for RegionVisitor<F> impl<'tcx, F> TypeVisitor<'tcx> for RegionVisitor<'tcx, F>
where where
F: FnMut(ty::Region<'tcx>) -> bool, F: FnMut(ty::Region<'tcx>) -> bool,
{ {
type BreakTy = (); type BreakTy = ();
fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
Some(self.tcx)
}
fn visit_binder<T: TypeFoldable<'tcx>>( fn visit_binder<T: TypeFoldable<'tcx>>(
&mut self, &mut self,
t: &Binder<'tcx, T>, t: &Binder<'tcx, T>,
@ -356,7 +411,7 @@ impl<'tcx> TyCtxt<'tcx> {
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
// We're only interested in types involving regions // We're only interested in types involving regions
if ty.flags().intersects(TypeFlags::HAS_FREE_REGIONS) { if ty.flags().intersects(TypeFlags::HAS_POTENTIAL_FREE_REGIONS) {
ty.super_visit_with(self) ty.super_visit_with(self)
} else { } else {
ControlFlow::CONTINUE ControlFlow::CONTINUE
@ -364,7 +419,9 @@ impl<'tcx> TyCtxt<'tcx> {
} }
} }
value.visit_with(&mut RegionVisitor { outer_index: ty::INNERMOST, callback }).is_break() value
.visit_with(&mut RegionVisitor { tcx: self, outer_index: ty::INNERMOST, callback })
.is_break()
} }
} }
@ -708,7 +765,7 @@ impl<'tcx> TyCtxt<'tcx> {
where where
T: TypeFoldable<'tcx>, T: TypeFoldable<'tcx>,
{ {
let mut collector = LateBoundRegionsCollector::new(just_constraint); let mut collector = LateBoundRegionsCollector::new(self, just_constraint);
let result = value.as_ref().skip_binder().visit_with(&mut collector); let result = value.as_ref().skip_binder().visit_with(&mut collector);
assert!(result.is_continue()); // should never have stopped early assert!(result.is_continue()); // should never have stopped early
collector.regions collector.regions
@ -775,6 +832,11 @@ impl<'tcx> ValidateBoundVars<'tcx> {
impl<'tcx> TypeVisitor<'tcx> for ValidateBoundVars<'tcx> { impl<'tcx> TypeVisitor<'tcx> for ValidateBoundVars<'tcx> {
type BreakTy = (); type BreakTy = ();
fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
// Anonymous constants do not contain bound vars in their substs by default.
None
}
fn visit_binder<T: TypeFoldable<'tcx>>( fn visit_binder<T: TypeFoldable<'tcx>>(
&mut self, &mut self,
t: &Binder<'tcx, T>, t: &Binder<'tcx, T>,
@ -989,6 +1051,11 @@ struct HasEscapingVarsVisitor {
impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor { impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor {
type BreakTy = FoundEscapingVars; type BreakTy = FoundEscapingVars;
fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
// Anonymous constants do not contain bound vars in their substs by default.
None
}
fn visit_binder<T: TypeFoldable<'tcx>>( fn visit_binder<T: TypeFoldable<'tcx>>(
&mut self, &mut self,
t: &Binder<'tcx, T>, t: &Binder<'tcx, T>,
@ -1053,25 +1120,28 @@ impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor {
struct FoundFlags; struct FoundFlags;
// FIXME: Optimize for checking for infer flags // FIXME: Optimize for checking for infer flags
struct HasTypeFlagsVisitor { struct HasTypeFlagsVisitor<'tcx> {
tcx: Option<TyCtxt<'tcx>>,
flags: ty::TypeFlags, flags: ty::TypeFlags,
} }
impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor<'tcx> {
type BreakTy = FoundFlags; type BreakTy = FoundFlags;
fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
bug!("we shouldn't call this method as we manually look at ct substs");
}
#[inline] #[inline]
fn visit_ty(&mut self, t: Ty<'_>) -> ControlFlow<Self::BreakTy> { fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
debug!( let flags = t.flags();
"HasTypeFlagsVisitor: t={:?} t.flags={:?} self.flags={:?}", debug!("HasTypeFlagsVisitor: t={:?} flags={:?} self.flags={:?}", t, flags, self.flags);
t, if flags.intersects(self.flags) {
t.flags(),
self.flags
);
if t.flags().intersects(self.flags) {
ControlFlow::Break(FoundFlags) ControlFlow::Break(FoundFlags)
} else { } else {
ControlFlow::CONTINUE match flags.intersects(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS) {
true if self.tcx.is_some() => UnknownConstSubstsVisitor::search(&self, t),
_ => ControlFlow::CONTINUE,
}
} }
} }
@ -1093,27 +1163,144 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor {
if flags.intersects(self.flags) { if flags.intersects(self.flags) {
ControlFlow::Break(FoundFlags) ControlFlow::Break(FoundFlags)
} else { } else {
ControlFlow::CONTINUE match flags.intersects(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS) {
true if self.tcx.is_some() => UnknownConstSubstsVisitor::search(&self, c),
_ => ControlFlow::CONTINUE,
}
}
}
#[inline]
fn visit_unevaluated_const(&mut self, uv: ty::Unevaluated<'tcx>) -> ControlFlow<Self::BreakTy> {
let flags = FlagComputation::for_unevaluated_const(uv);
debug!("HasTypeFlagsVisitor: uv={:?} uv.flags={:?} self.flags={:?}", uv, flags, self.flags);
if flags.intersects(self.flags) {
ControlFlow::Break(FoundFlags)
} else {
match flags.intersects(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS) {
true if self.tcx.is_some() => UnknownConstSubstsVisitor::search(&self, uv),
_ => ControlFlow::CONTINUE,
}
} }
} }
#[inline] #[inline]
fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> { fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
let flags = predicate.inner.flags;
debug!( debug!(
"HasTypeFlagsVisitor: predicate={:?} predicate.flags={:?} self.flags={:?}", "HasTypeFlagsVisitor: predicate={:?} flags={:?} self.flags={:?}",
predicate, predicate.inner.flags, self.flags predicate, flags, self.flags
); );
if predicate.inner.flags.intersects(self.flags) { if flags.intersects(self.flags) {
ControlFlow::Break(FoundFlags) ControlFlow::Break(FoundFlags)
} else {
match flags.intersects(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS) {
true if self.tcx.is_some() => UnknownConstSubstsVisitor::search(&self, predicate),
_ => ControlFlow::CONTINUE,
}
}
}
}
struct UnknownConstSubstsVisitor<'tcx> {
tcx: TyCtxt<'tcx>,
flags: ty::TypeFlags,
}
impl<'tcx> UnknownConstSubstsVisitor<'tcx> {
/// This is fairly cold and we don't want to
/// bloat the size of the `HasTypeFlagsVisitor`.
#[inline(never)]
pub fn search<T: TypeFoldable<'tcx>>(
visitor: &HasTypeFlagsVisitor<'tcx>,
v: T,
) -> ControlFlow<FoundFlags> {
if visitor.flags.intersects(TypeFlags::MAY_NEED_DEFAULT_CONST_SUBSTS) {
v.super_visit_with(&mut UnknownConstSubstsVisitor {
tcx: visitor.tcx.unwrap(),
flags: visitor.flags,
})
} else { } else {
ControlFlow::CONTINUE ControlFlow::CONTINUE
} }
} }
} }
impl<'tcx> TypeVisitor<'tcx> for UnknownConstSubstsVisitor<'tcx> {
type BreakTy = FoundFlags;
fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
bug!("we shouldn't call this method as we manually look at ct substs");
}
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
if t.flags().intersects(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS) {
t.super_visit_with(self)
} else {
ControlFlow::CONTINUE
}
}
#[inline]
fn visit_unevaluated_const(&mut self, uv: ty::Unevaluated<'tcx>) -> ControlFlow<Self::BreakTy> {
if uv.substs_.is_none() {
self.tcx
.default_anon_const_substs(uv.def.did)
.visit_with(&mut HasTypeFlagsVisitor { tcx: Some(self.tcx), flags: self.flags })
} else {
ControlFlow::CONTINUE
}
}
#[inline]
fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
if predicate.inner.flags.intersects(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS) {
predicate.super_visit_with(self)
} else {
ControlFlow::CONTINUE
}
}
}
impl<'tcx> TyCtxt<'tcx> {
/// This is a HACK(const_generics) and should probably not be needed.
/// Might however be perf relevant, so who knows.
///
/// FIXME(@lcnr): explain this function a bit more
pub fn expose_default_const_substs<T: TypeFoldable<'tcx>>(self, v: T) -> T {
v.fold_with(&mut ExposeDefaultConstSubstsFolder { tcx: self })
}
}
struct ExposeDefaultConstSubstsFolder<'tcx> {
tcx: TyCtxt<'tcx>,
}
impl<'tcx> TypeFolder<'tcx> for ExposeDefaultConstSubstsFolder<'tcx> {
fn tcx(&self) -> TyCtxt<'tcx> {
self.tcx
}
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
if ty.flags().intersects(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS) {
ty.super_fold_with(self)
} else {
ty
}
}
fn fold_predicate(&mut self, pred: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
if pred.inner.flags.intersects(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS) {
pred.super_fold_with(self)
} else {
pred
}
}
}
/// Collects all the late-bound regions at the innermost binding level /// Collects all the late-bound regions at the innermost binding level
/// into a hash set. /// into a hash set.
struct LateBoundRegionsCollector { struct LateBoundRegionsCollector<'tcx> {
tcx: TyCtxt<'tcx>,
current_index: ty::DebruijnIndex, current_index: ty::DebruijnIndex,
regions: FxHashSet<ty::BoundRegionKind>, regions: FxHashSet<ty::BoundRegionKind>,
@ -1127,9 +1314,10 @@ struct LateBoundRegionsCollector {
just_constrained: bool, just_constrained: bool,
} }
impl LateBoundRegionsCollector { impl LateBoundRegionsCollector<'tcx> {
fn new(just_constrained: bool) -> Self { fn new(tcx: TyCtxt<'tcx>, just_constrained: bool) -> Self {
LateBoundRegionsCollector { LateBoundRegionsCollector {
tcx,
current_index: ty::INNERMOST, current_index: ty::INNERMOST,
regions: Default::default(), regions: Default::default(),
just_constrained, just_constrained,
@ -1137,7 +1325,11 @@ impl LateBoundRegionsCollector {
} }
} }
impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector { impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector<'tcx> {
fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
Some(self.tcx)
}
fn visit_binder<T: TypeFoldable<'tcx>>( fn visit_binder<T: TypeFoldable<'tcx>>(
&mut self, &mut self,
t: &Binder<'tcx, T>, t: &Binder<'tcx, T>,

View File

@ -1739,7 +1739,9 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
// Ignore layouts that are done with non-empty environments or // Ignore layouts that are done with non-empty environments or
// non-monomorphic layouts, as the user only wants to see the stuff // non-monomorphic layouts, as the user only wants to see the stuff
// resulting from the final codegen session. // resulting from the final codegen session.
if layout.ty.has_param_types_or_consts() || !self.param_env.caller_bounds().is_empty() { if layout.ty.definitely_has_param_types_or_consts(self.tcx)
|| !self.param_env.caller_bounds().is_empty()
{
return; return;
} }
@ -1906,7 +1908,7 @@ impl<'tcx> SizeSkeleton<'tcx> {
let tail = tcx.struct_tail_erasing_lifetimes(pointee, param_env); let tail = tcx.struct_tail_erasing_lifetimes(pointee, param_env);
match tail.kind() { match tail.kind() {
ty::Param(_) | ty::Projection(_) => { ty::Param(_) | ty::Projection(_) => {
debug_assert!(tail.has_param_types_or_consts()); debug_assert!(tail.definitely_has_param_types_or_consts(tcx));
Ok(SizeSkeleton::Pointer { non_zero, tail: tcx.erase_regions(tail) }) Ok(SizeSkeleton::Pointer { non_zero, tail: tcx.erase_regions(tail) })
} }
_ => bug!( _ => bug!(

View File

@ -502,7 +502,7 @@ pub enum PredicateKind<'tcx> {
Coerce(CoercePredicate<'tcx>), Coerce(CoercePredicate<'tcx>),
/// Constant initializer must evaluate successfully. /// Constant initializer must evaluate successfully.
ConstEvaluatable(ty::WithOptConstParam<DefId>, SubstsRef<'tcx>), ConstEvaluatable(ty::Unevaluated<'tcx, ()>),
/// Constants must be equal. The first component is the const that is expected. /// Constants must be equal. The first component is the const that is expected.
ConstEquate(&'tcx Const<'tcx>, &'tcx Const<'tcx>), ConstEquate(&'tcx Const<'tcx>, &'tcx Const<'tcx>),
@ -1292,7 +1292,7 @@ impl<'tcx> ParamEnv<'tcx> {
Reveal::UserFacing => ParamEnvAnd { param_env: self, value }, Reveal::UserFacing => ParamEnvAnd { param_env: self, value },
Reveal::All => { Reveal::All => {
if value.is_global() { if value.is_known_global() {
ParamEnvAnd { param_env: self.without_caller_bounds(), value } ParamEnvAnd { param_env: self.without_caller_bounds(), value }
} else { } else {
ParamEnvAnd { param_env: self, value } ParamEnvAnd { param_env: self, value }

View File

@ -194,7 +194,7 @@ fn compute_components_recursive(
out: &mut SmallVec<[Component<'tcx>; 4]>, out: &mut SmallVec<[Component<'tcx>; 4]>,
visited: &mut SsoHashSet<GenericArg<'tcx>>, visited: &mut SsoHashSet<GenericArg<'tcx>>,
) { ) {
for child in parent.walk_shallow(visited) { for child in parent.walk_shallow(tcx, visited) {
match child.unpack() { match child.unpack() {
GenericArgKind::Type(ty) => { GenericArgKind::Type(ty) => {
compute_components(tcx, ty, out, visited); compute_components(tcx, ty, out, visited);

View File

@ -927,29 +927,28 @@ pub trait PrettyPrinter<'tcx>:
} }
match ct.val { match ct.val {
ty::ConstKind::Unevaluated(ty::Unevaluated { ty::ConstKind::Unevaluated(uv) => {
def, if let Some(promoted) = uv.promoted {
substs, let substs = uv.substs_.unwrap();
promoted: Some(promoted), p!(print_value_path(uv.def.did, substs));
}) => { p!(write("::{:?}", promoted));
p!(print_value_path(def.did, substs)); } else {
p!(write("::{:?}", promoted)); let tcx = self.tcx();
} match tcx.def_kind(uv.def.did) {
ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted: None }) => { DefKind::Static | DefKind::Const | DefKind::AssocConst => {
match self.tcx().def_kind(def.did) { p!(print_value_path(uv.def.did, uv.substs(tcx)))
DefKind::Static | DefKind::Const | DefKind::AssocConst => { }
p!(print_value_path(def.did, substs)) _ => {
} if uv.def.is_local() {
_ => { let span = tcx.def_span(uv.def.did);
if def.is_local() { if let Ok(snip) = tcx.sess.source_map().span_to_snippet(span) {
let span = self.tcx().def_span(def.did); p!(write("{}", snip))
if let Ok(snip) = self.tcx().sess.source_map().span_to_snippet(span) { } else {
p!(write("{}", snip)) print_underscore!()
}
} else { } else {
print_underscore!() print_underscore!()
} }
} else {
print_underscore!()
} }
} }
} }
@ -1194,7 +1193,7 @@ pub trait PrettyPrinter<'tcx>:
// Aggregates, printed as array/tuple/struct/variant construction syntax. // Aggregates, printed as array/tuple/struct/variant construction syntax.
// //
// NB: the `has_param_types_or_consts` check ensures that we can use // NB: the `potentially_has_param_types_or_consts` check ensures that we can use
// the `destructure_const` query with an empty `ty::ParamEnv` without // the `destructure_const` query with an empty `ty::ParamEnv` without
// introducing ICEs (e.g. via `layout_of`) from missing bounds. // introducing ICEs (e.g. via `layout_of`) from missing bounds.
// E.g. `transmute([0usize; 2]): (u8, *mut T)` needs to know `T: Sized` // E.g. `transmute([0usize; 2]): (u8, *mut T)` needs to know `T: Sized`
@ -1202,7 +1201,9 @@ pub trait PrettyPrinter<'tcx>:
// //
// FIXME(eddyb) for `--emit=mir`/`-Z dump-mir`, we should provide the // FIXME(eddyb) for `--emit=mir`/`-Z dump-mir`, we should provide the
// correct `ty::ParamEnv` to allow printing *all* constant values. // correct `ty::ParamEnv` to allow printing *all* constant values.
(_, ty::Array(..) | ty::Tuple(..) | ty::Adt(..)) if !ty.has_param_types_or_consts() => { (_, ty::Array(..) | ty::Tuple(..) | ty::Adt(..))
if !ty.potentially_has_param_types_or_consts() =>
{
let contents = self.tcx().destructure_const( let contents = self.tcx().destructure_const(
ty::ParamEnv::reveal_all() ty::ParamEnv::reveal_all()
.and(self.tcx().mk_const(ty::Const { val: ty::ConstKind::Value(ct), ty })), .and(self.tcx().mk_const(ty::Const { val: ty::ConstKind::Value(ct), ty })),
@ -2024,6 +2025,7 @@ impl<F: fmt::Write> FmtPrinter<'_, 'tcx, F> {
debug!("prepare_late_bound_region_info(value: {:?})", value); debug!("prepare_late_bound_region_info(value: {:?})", value);
struct LateBoundRegionNameCollector<'a, 'tcx> { struct LateBoundRegionNameCollector<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
used_region_names: &'a mut FxHashSet<Symbol>, used_region_names: &'a mut FxHashSet<Symbol>,
type_collector: SsoHashSet<Ty<'tcx>>, type_collector: SsoHashSet<Ty<'tcx>>,
} }
@ -2031,6 +2033,10 @@ impl<F: fmt::Write> FmtPrinter<'_, 'tcx, F> {
impl<'tcx> ty::fold::TypeVisitor<'tcx> for LateBoundRegionNameCollector<'_, 'tcx> { impl<'tcx> ty::fold::TypeVisitor<'tcx> for LateBoundRegionNameCollector<'_, 'tcx> {
type BreakTy = (); type BreakTy = ();
fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
Some(self.tcx)
}
fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
debug!("LateBoundRegionNameCollector::visit_region(r: {:?}, address: {:p})", r, &r); debug!("LateBoundRegionNameCollector::visit_region(r: {:?}, address: {:p})", r, &r);
if let ty::ReLateBound(_, ty::BoundRegion { kind: ty::BrNamed(_, name), .. }) = *r { if let ty::ReLateBound(_, ty::BoundRegion { kind: ty::BrNamed(_, name), .. }) = *r {
@ -2060,6 +2066,7 @@ impl<F: fmt::Write> FmtPrinter<'_, 'tcx, F> {
self.used_region_names.clear(); self.used_region_names.clear();
let mut collector = LateBoundRegionNameCollector { let mut collector = LateBoundRegionNameCollector {
tcx: self.tcx,
used_region_names: &mut self.used_region_names, used_region_names: &mut self.used_region_names,
type_collector: SsoHashSet::new(), type_collector: SsoHashSet::new(),
}; };
@ -2294,8 +2301,8 @@ define_print_and_forward_display! {
print_value_path(closure_def_id, &[]), print_value_path(closure_def_id, &[]),
write("` implements the trait `{}`", kind)) write("` implements the trait `{}`", kind))
} }
ty::PredicateKind::ConstEvaluatable(def, substs) => { ty::PredicateKind::ConstEvaluatable(uv) => {
p!("the constant `", print_value_path(def.did, substs), "` can be evaluated") p!("the constant `", print_value_path(uv.def.did, uv.substs_.map_or(&[], |x| x)), "` can be evaluated")
} }
ty::PredicateKind::ConstEquate(c1, c2) => { ty::PredicateKind::ConstEquate(c1, c2) => {
p!("the constant `", print(c1), "` equals `", print(c2), "`") p!("the constant `", print(c1), "` equals `", print(c2), "`")

View File

@ -579,7 +579,7 @@ pub fn super_relate_consts<R: TypeRelation<'tcx>>(
(ty::ConstKind::Unevaluated(au), ty::ConstKind::Unevaluated(bu)) (ty::ConstKind::Unevaluated(au), ty::ConstKind::Unevaluated(bu))
if tcx.features().const_evaluatable_checked => if tcx.features().const_evaluatable_checked =>
{ {
tcx.try_unify_abstract_consts(((au.def, au.substs), (bu.def, bu.substs))) tcx.try_unify_abstract_consts((au.shrink(), bu.shrink()))
} }
// While this is slightly incorrect, it shouldn't matter for `min_const_generics` // While this is slightly incorrect, it shouldn't matter for `min_const_generics`
@ -591,13 +591,13 @@ pub fn super_relate_consts<R: TypeRelation<'tcx>>(
let substs = relation.relate_with_variance( let substs = relation.relate_with_variance(
ty::Variance::Invariant, ty::Variance::Invariant,
ty::VarianceDiagInfo::default(), ty::VarianceDiagInfo::default(),
au.substs, au.substs(tcx),
bu.substs, bu.substs(tcx),
)?; )?;
return Ok(tcx.mk_const(ty::Const { return Ok(tcx.mk_const(ty::Const {
val: ty::ConstKind::Unevaluated(ty::Unevaluated { val: ty::ConstKind::Unevaluated(ty::Unevaluated {
def: au.def, def: au.def,
substs, substs_: Some(substs),
promoted: au.promoted, promoted: au.promoted,
}), }),
ty: a.ty, ty: a.ty,

View File

@ -190,8 +190,8 @@ impl fmt::Debug for ty::PredicateKind<'tcx> {
ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind) => { ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind) => {
write!(f, "ClosureKind({:?}, {:?}, {:?})", closure_def_id, closure_substs, kind) write!(f, "ClosureKind({:?}, {:?}, {:?})", closure_def_id, closure_substs, kind)
} }
ty::PredicateKind::ConstEvaluatable(def_id, substs) => { ty::PredicateKind::ConstEvaluatable(uv) => {
write!(f, "ConstEvaluatable({:?}, {:?})", def_id, substs) write!(f, "ConstEvaluatable({:?}, {:?})", uv.def, uv.substs_)
} }
ty::PredicateKind::ConstEquate(c1, c2) => write!(f, "ConstEquate({:?}, {:?})", c1, c2), ty::PredicateKind::ConstEquate(c1, c2) => write!(f, "ConstEquate({:?}, {:?})", c1, c2),
ty::PredicateKind::TypeWellFormedFromEnv(ty) => { ty::PredicateKind::TypeWellFormedFromEnv(ty) => {
@ -447,8 +447,8 @@ impl<'a, 'tcx> Lift<'tcx> for ty::PredicateKind<'a> {
ty::PredicateKind::ObjectSafe(trait_def_id) => { ty::PredicateKind::ObjectSafe(trait_def_id) => {
Some(ty::PredicateKind::ObjectSafe(trait_def_id)) Some(ty::PredicateKind::ObjectSafe(trait_def_id))
} }
ty::PredicateKind::ConstEvaluatable(def_id, substs) => { ty::PredicateKind::ConstEvaluatable(uv) => {
tcx.lift(substs).map(|substs| ty::PredicateKind::ConstEvaluatable(def_id, substs)) tcx.lift(uv).map(|uv| ty::PredicateKind::ConstEvaluatable(uv))
} }
ty::PredicateKind::ConstEquate(c1, c2) => { ty::PredicateKind::ConstEquate(c1, c2) => {
tcx.lift((c1, c2)).map(|(c1, c2)| ty::PredicateKind::ConstEquate(c1, c2)) tcx.lift((c1, c2)).map(|(c1, c2)| ty::PredicateKind::ConstEquate(c1, c2))
@ -974,6 +974,10 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Region<'tcx> {
} }
impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> { impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> {
fn fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
folder.fold_predicate(self)
}
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self { fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
let new = self.inner.kind.fold_with(folder); let new = self.inner.kind.fold_with(folder);
folder.tcx().reuse_or_mk_predicate(self, new) folder.tcx().reuse_or_mk_predicate(self, new)
@ -1046,13 +1050,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ConstKind<'tcx> {
match self { match self {
ty::ConstKind::Infer(ic) => ty::ConstKind::Infer(ic.fold_with(folder)), ty::ConstKind::Infer(ic) => ty::ConstKind::Infer(ic.fold_with(folder)),
ty::ConstKind::Param(p) => ty::ConstKind::Param(p.fold_with(folder)), ty::ConstKind::Param(p) => ty::ConstKind::Param(p.fold_with(folder)),
ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) => { ty::ConstKind::Unevaluated(uv) => ty::ConstKind::Unevaluated(uv.fold_with(folder)),
ty::ConstKind::Unevaluated(ty::Unevaluated {
def,
substs: substs.fold_with(folder),
promoted,
})
}
ty::ConstKind::Value(_) ty::ConstKind::Value(_)
| ty::ConstKind::Bound(..) | ty::ConstKind::Bound(..)
| ty::ConstKind::Placeholder(..) | ty::ConstKind::Placeholder(..)
@ -1064,7 +1062,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ConstKind<'tcx> {
match *self { match *self {
ty::ConstKind::Infer(ic) => ic.visit_with(visitor), ty::ConstKind::Infer(ic) => ic.visit_with(visitor),
ty::ConstKind::Param(p) => p.visit_with(visitor), ty::ConstKind::Param(p) => p.visit_with(visitor),
ty::ConstKind::Unevaluated(ct) => ct.substs.visit_with(visitor), ty::ConstKind::Unevaluated(uv) => uv.visit_with(visitor),
ty::ConstKind::Value(_) ty::ConstKind::Value(_)
| ty::ConstKind::Bound(..) | ty::ConstKind::Bound(..)
| ty::ConstKind::Placeholder(_) | ty::ConstKind::Placeholder(_)
@ -1082,3 +1080,53 @@ impl<'tcx> TypeFoldable<'tcx> for InferConst<'tcx> {
ControlFlow::CONTINUE ControlFlow::CONTINUE
} }
} }
impl<'tcx> TypeFoldable<'tcx> for ty::Unevaluated<'tcx> {
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
ty::Unevaluated {
def: self.def,
substs_: Some(self.substs(folder.tcx()).fold_with(folder)),
promoted: self.promoted,
}
}
fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
visitor.visit_unevaluated_const(*self)
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
if let Some(tcx) = visitor.tcx_for_anon_const_substs() {
self.substs(tcx).visit_with(visitor)
} else if let Some(substs) = self.substs_ {
substs.visit_with(visitor)
} else {
debug!("ignoring default substs of `{:?}`", self.def);
ControlFlow::CONTINUE
}
}
}
impl<'tcx> TypeFoldable<'tcx> for ty::Unevaluated<'tcx, ()> {
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
ty::Unevaluated {
def: self.def,
substs_: Some(self.substs(folder.tcx()).fold_with(folder)),
promoted: self.promoted,
}
}
fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
visitor.visit_unevaluated_const(self.expand())
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
if let Some(tcx) = visitor.tcx_for_anon_const_substs() {
self.substs(tcx).visit_with(visitor)
} else if let Some(substs) = self.substs_ {
substs.visit_with(visitor)
} else {
debug!("ignoring default substs of `{:?}`", self.def);
ControlFlow::CONTINUE
}
}
}

View File

@ -1565,26 +1565,26 @@ impl RegionKind {
match *self { match *self {
ty::ReVar(..) => { ty::ReVar(..) => {
flags = flags | TypeFlags::HAS_FREE_REGIONS; flags = flags | TypeFlags::HAS_KNOWN_FREE_REGIONS;
flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS; flags = flags | TypeFlags::HAS_KNOWN_FREE_LOCAL_REGIONS;
flags = flags | TypeFlags::HAS_RE_INFER; flags = flags | TypeFlags::HAS_RE_INFER;
} }
ty::RePlaceholder(..) => { ty::RePlaceholder(..) => {
flags = flags | TypeFlags::HAS_FREE_REGIONS; flags = flags | TypeFlags::HAS_KNOWN_FREE_REGIONS;
flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS; flags = flags | TypeFlags::HAS_KNOWN_FREE_LOCAL_REGIONS;
flags = flags | TypeFlags::HAS_RE_PLACEHOLDER; flags = flags | TypeFlags::HAS_RE_PLACEHOLDER;
} }
ty::ReEarlyBound(..) => { ty::ReEarlyBound(..) => {
flags = flags | TypeFlags::HAS_FREE_REGIONS; flags = flags | TypeFlags::HAS_KNOWN_FREE_REGIONS;
flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS; flags = flags | TypeFlags::HAS_KNOWN_FREE_LOCAL_REGIONS;
flags = flags | TypeFlags::HAS_RE_PARAM; flags = flags | TypeFlags::HAS_KNOWN_RE_PARAM;
} }
ty::ReFree { .. } => { ty::ReFree { .. } => {
flags = flags | TypeFlags::HAS_FREE_REGIONS; flags = flags | TypeFlags::HAS_KNOWN_FREE_REGIONS;
flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS; flags = flags | TypeFlags::HAS_KNOWN_FREE_LOCAL_REGIONS;
} }
ty::ReEmpty(_) | ty::ReStatic => { ty::ReEmpty(_) | ty::ReStatic => {
flags = flags | TypeFlags::HAS_FREE_REGIONS; flags = flags | TypeFlags::HAS_KNOWN_FREE_REGIONS;
} }
ty::ReLateBound(..) => { ty::ReLateBound(..) => {
flags = flags | TypeFlags::HAS_RE_LATE_BOUND; flags = flags | TypeFlags::HAS_RE_LATE_BOUND;

View File

@ -486,7 +486,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> {
} }
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
if !t.needs_subst() { if !t.potentially_needs_subst() {
return t; return t;
} }
@ -497,10 +497,6 @@ impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> {
} }
fn fold_const(&mut self, c: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { fn fold_const(&mut self, c: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
if !c.needs_subst() {
return c;
}
if let ty::ConstKind::Param(p) = c.val { if let ty::ConstKind::Param(p) = c.val {
self.const_for_param(p, c) self.const_for_param(p, c)
} else { } else {

View File

@ -1,8 +1,8 @@
//! An iterator over the type substructure. //! An iterator over the type substructure.
//! WARNING: this does not keep track of the region depth. //! WARNING: this does not keep track of the region depth.
use crate::ty;
use crate::ty::subst::{GenericArg, GenericArgKind}; use crate::ty::subst::{GenericArg, GenericArgKind};
use crate::ty::{self, TyCtxt};
use rustc_data_structures::sso::SsoHashSet; use rustc_data_structures::sso::SsoHashSet;
use smallvec::{self, SmallVec}; use smallvec::{self, SmallVec};
@ -11,6 +11,7 @@ use smallvec::{self, SmallVec};
type TypeWalkerStack<'tcx> = SmallVec<[GenericArg<'tcx>; 8]>; type TypeWalkerStack<'tcx> = SmallVec<[GenericArg<'tcx>; 8]>;
pub struct TypeWalker<'tcx> { pub struct TypeWalker<'tcx> {
expose_default_const_substs: Option<TyCtxt<'tcx>>,
stack: TypeWalkerStack<'tcx>, stack: TypeWalkerStack<'tcx>,
last_subtree: usize, last_subtree: usize,
pub visited: SsoHashSet<GenericArg<'tcx>>, pub visited: SsoHashSet<GenericArg<'tcx>>,
@ -25,8 +26,13 @@ pub struct TypeWalker<'tcx> {
/// It maintains a set of visited types and /// It maintains a set of visited types and
/// skips any types that are already there. /// skips any types that are already there.
impl<'tcx> TypeWalker<'tcx> { impl<'tcx> TypeWalker<'tcx> {
pub fn new(root: GenericArg<'tcx>) -> Self { fn new(expose_default_const_substs: Option<TyCtxt<'tcx>>, root: GenericArg<'tcx>) -> Self {
Self { stack: smallvec![root], last_subtree: 1, visited: SsoHashSet::new() } Self {
expose_default_const_substs,
stack: smallvec![root],
last_subtree: 1,
visited: SsoHashSet::new(),
}
} }
/// Skips the subtree corresponding to the last type /// Skips the subtree corresponding to the last type
@ -55,7 +61,7 @@ impl<'tcx> Iterator for TypeWalker<'tcx> {
let next = self.stack.pop()?; let next = self.stack.pop()?;
self.last_subtree = self.stack.len(); self.last_subtree = self.stack.len();
if self.visited.insert(next) { if self.visited.insert(next) {
push_inner(&mut self.stack, next); push_inner(self.expose_default_const_substs, &mut self.stack, next);
debug!("next: stack={:?}", self.stack); debug!("next: stack={:?}", self.stack);
return Some(next); return Some(next);
} }
@ -74,8 +80,8 @@ impl GenericArg<'tcx> {
/// Foo<Bar<isize>> => { Foo<Bar<isize>>, Bar<isize>, isize } /// Foo<Bar<isize>> => { Foo<Bar<isize>>, Bar<isize>, isize }
/// [isize] => { [isize], isize } /// [isize] => { [isize], isize }
/// ``` /// ```
pub fn walk(self) -> TypeWalker<'tcx> { pub fn walk(self, tcx: TyCtxt<'tcx>) -> TypeWalker<'tcx> {
TypeWalker::new(self) TypeWalker::new(Some(tcx), self)
} }
/// Iterator that walks the immediate children of `self`. Hence /// Iterator that walks the immediate children of `self`. Hence
@ -87,16 +93,21 @@ impl GenericArg<'tcx> {
/// and skips any types that are already there. /// and skips any types that are already there.
pub fn walk_shallow( pub fn walk_shallow(
self, self,
tcx: TyCtxt<'tcx>,
visited: &mut SsoHashSet<GenericArg<'tcx>>, visited: &mut SsoHashSet<GenericArg<'tcx>>,
) -> impl Iterator<Item = GenericArg<'tcx>> { ) -> impl Iterator<Item = GenericArg<'tcx>> {
let mut stack = SmallVec::new(); let mut stack = SmallVec::new();
push_inner(&mut stack, self); push_inner(Some(tcx), &mut stack, self);
stack.retain(|a| visited.insert(*a)); stack.retain(|a| visited.insert(*a));
stack.into_iter() stack.into_iter()
} }
} }
impl<'tcx> super::TyS<'tcx> { impl<'tcx> super::TyS<'tcx> {
pub fn walk_ignoring_default_const_substs(&'tcx self) -> TypeWalker<'tcx> {
TypeWalker::new(None, self.into())
}
/// Iterator that walks `self` and any types reachable from /// Iterator that walks `self` and any types reachable from
/// `self`, in depth-first order. Note that just walks the types /// `self`, in depth-first order. Note that just walks the types
/// that appear in `self`, it does not descend into the fields of /// that appear in `self`, it does not descend into the fields of
@ -107,18 +118,22 @@ impl<'tcx> super::TyS<'tcx> {
/// Foo<Bar<isize>> => { Foo<Bar<isize>>, Bar<isize>, isize } /// Foo<Bar<isize>> => { Foo<Bar<isize>>, Bar<isize>, isize }
/// [isize] => { [isize], isize } /// [isize] => { [isize], isize }
/// ``` /// ```
pub fn walk(&'tcx self) -> TypeWalker<'tcx> { pub fn walk(&'tcx self, tcx: TyCtxt<'tcx>) -> TypeWalker<'tcx> {
TypeWalker::new(self.into()) TypeWalker::new(Some(tcx), self.into())
} }
} }
// We push `GenericArg`s on the stack in reverse order so as to /// We push `GenericArg`s on the stack in reverse order so as to
// maintain a pre-order traversal. As of the time of this /// maintain a pre-order traversal. As of the time of this
// writing, the fact that the traversal is pre-order is not /// writing, the fact that the traversal is pre-order is not
// known to be significant to any code, but it seems like the /// known to be significant to any code, but it seems like the
// natural order one would expect (basically, the order of the /// natural order one would expect (basically, the order of the
// types as they are written). /// types as they are written).
fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>) { fn push_inner<'tcx>(
expose_default_const_substs: Option<TyCtxt<'tcx>>,
stack: &mut TypeWalkerStack<'tcx>,
parent: GenericArg<'tcx>,
) {
match parent.unpack() { match parent.unpack() {
GenericArgKind::Type(parent_ty) => match *parent_ty.kind() { GenericArgKind::Type(parent_ty) => match *parent_ty.kind() {
ty::Bool ty::Bool
@ -196,7 +211,11 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>)
| ty::ConstKind::Error(_) => {} | ty::ConstKind::Error(_) => {}
ty::ConstKind::Unevaluated(ct) => { ty::ConstKind::Unevaluated(ct) => {
stack.extend(ct.substs.iter().rev()); if let Some(tcx) = expose_default_const_substs {
stack.extend(ct.substs(tcx).iter().rev());
} else if let Some(substs) = ct.substs_ {
stack.extend(substs.iter().rev());
}
} }
} }
} }

View File

@ -171,7 +171,7 @@ impl LivenessResults<'me, 'typeck, 'flow, 'tcx> {
for (local, location) in drop_used { for (local, location) in drop_used {
if !live_locals.contains(&local) { if !live_locals.contains(&local) {
let local_ty = self.cx.body.local_decls[local].ty; let local_ty = self.cx.body.local_decls[local].ty;
if local_ty.has_free_regions() { if local_ty.has_free_regions(self.cx.typeck.tcx()) {
self.cx.add_drop_live_facts_for(local, local_ty, &[location], &locations); self.cx.add_drop_live_facts_for(local, local_ty, &[location], &locations);
} }
} }

View File

@ -377,8 +377,8 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
}, },
_ => None, _ => None,
}; };
if let Some(ty::Unevaluated { def, substs, promoted }) = maybe_uneval { if let Some(uv) = maybe_uneval {
if let Some(promoted) = promoted { if let Some(promoted) = uv.promoted {
let check_err = |verifier: &mut TypeVerifier<'a, 'b, 'tcx>, let check_err = |verifier: &mut TypeVerifier<'a, 'b, 'tcx>,
promoted: &Body<'tcx>, promoted: &Body<'tcx>,
ty, ty,
@ -413,8 +413,8 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
ConstraintCategory::Boring, ConstraintCategory::Boring,
self.cx.param_env.and(type_op::ascribe_user_type::AscribeUserType::new( self.cx.param_env.and(type_op::ascribe_user_type::AscribeUserType::new(
constant.literal.ty(), constant.literal.ty(),
def.did, uv.def.did,
UserSubsts { substs, user_self_ty: None }, UserSubsts { substs: uv.substs(self.tcx()), user_self_ty: None },
)), )),
) { ) {
span_mirbug!( span_mirbug!(

View File

@ -555,9 +555,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
match val.val { match val.val {
ty::ConstKind::Param(_) | ty::ConstKind::Bound(..) => throw_inval!(TooGeneric), ty::ConstKind::Param(_) | ty::ConstKind::Bound(..) => throw_inval!(TooGeneric),
ty::ConstKind::Error(_) => throw_inval!(AlreadyReported(ErrorReported)), ty::ConstKind::Error(_) => throw_inval!(AlreadyReported(ErrorReported)),
ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) => { ty::ConstKind::Unevaluated(uv) => {
let instance = self.resolve(def, substs)?; let instance = self.resolve(uv.def, uv.substs(*self.tcx))?;
Ok(self.eval_to_allocation(GlobalId { instance, promoted })?.into()) Ok(self.eval_to_allocation(GlobalId { instance, promoted: uv.promoted })?.into())
} }
ty::ConstKind::Infer(..) | ty::ConstKind::Placeholder(..) => { ty::ConstKind::Infer(..) | ty::ConstKind::Placeholder(..) => {
span_bug!(self.cur_span(), "const_to_op: Unexpected ConstKind {:?}", val) span_bug!(self.cur_span(), "const_to_op: Unexpected ConstKind {:?}", val)

View File

@ -9,7 +9,7 @@ where
T: TypeFoldable<'tcx>, T: TypeFoldable<'tcx>,
{ {
debug!("ensure_monomorphic_enough: ty={:?}", ty); debug!("ensure_monomorphic_enough: ty={:?}", ty);
if !ty.needs_subst() { if !ty.potentially_needs_subst() {
return Ok(()); return Ok(());
} }
@ -21,19 +21,12 @@ where
impl<'tcx> TypeVisitor<'tcx> for UsedParamsNeedSubstVisitor<'tcx> { impl<'tcx> TypeVisitor<'tcx> for UsedParamsNeedSubstVisitor<'tcx> {
type BreakTy = FoundParam; type BreakTy = FoundParam;
fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> { fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
if !c.needs_subst() { Some(self.tcx)
return ControlFlow::CONTINUE;
}
match c.val {
ty::ConstKind::Param(..) => ControlFlow::Break(FoundParam),
_ => c.super_visit_with(self),
}
} }
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
if !ty.needs_subst() { if !ty.potentially_needs_subst() {
return ControlFlow::CONTINUE; return ControlFlow::CONTINUE;
} }
@ -50,7 +43,7 @@ where
let is_used = unused_params.contains(index).map_or(true, |unused| !unused); let is_used = unused_params.contains(index).map_or(true, |unused| !unused);
// Only recurse when generic parameters in fns, closures and generators // Only recurse when generic parameters in fns, closures and generators
// are used and require substitution. // are used and require substitution.
match (is_used, subst.needs_subst()) { match (is_used, subst.definitely_needs_subst(self.tcx)) {
// Just in case there are closures or generators within this subst, // Just in case there are closures or generators within this subst,
// recurse. // recurse.
(true, true) => return subst.super_visit_with(self), (true, true) => return subst.super_visit_with(self),
@ -73,6 +66,13 @@ where
_ => ty.super_visit_with(self), _ => ty.super_visit_with(self),
} }
} }
fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
match c.val {
ty::ConstKind::Param(..) => ControlFlow::Break(FoundParam),
_ => c.super_visit_with(self),
}
}
} }
let mut vis = UsedParamsNeedSubstVisitor { tcx }; let mut vis = UsedParamsNeedSubstVisitor { tcx };

View File

@ -573,7 +573,7 @@ fn check_type_length_limit<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) {
let type_length = instance let type_length = instance
.substs .substs
.iter() .iter()
.flat_map(|arg| arg.walk()) .flat_map(|arg| arg.walk(tcx))
.filter(|arg| match arg.unpack() { .filter(|arg| match arg.unpack() {
GenericArgKind::Type(_) | GenericArgKind::Const(_) => true, GenericArgKind::Type(_) | GenericArgKind::Const(_) => true,
GenericArgKind::Lifetime(_) => false, GenericArgKind::Lifetime(_) => false,

View File

@ -178,7 +178,7 @@ fn mark_used_by_predicates<'tcx>(
// Consider all generic params in a predicate as used if any other parameter in the // Consider all generic params in a predicate as used if any other parameter in the
// predicate is used. // predicate is used.
let any_param_used = { let any_param_used = {
let mut vis = HasUsedGenericParams { unused_parameters }; let mut vis = HasUsedGenericParams { tcx, unused_parameters };
predicate.visit_with(&mut vis).is_break() predicate.visit_with(&mut vis).is_break()
}; };
@ -283,9 +283,12 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
} }
impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
Some(self.tcx)
}
#[instrument(skip(self))] #[instrument(skip(self))]
fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow<Self::BreakTy> { fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow<Self::BreakTy> {
if !c.has_param_types_or_consts() { if !c.potentially_has_param_types_or_consts() {
return ControlFlow::CONTINUE; return ControlFlow::CONTINUE;
} }
@ -295,7 +298,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
self.unused_parameters.clear(param.index); self.unused_parameters.clear(param.index);
ControlFlow::CONTINUE ControlFlow::CONTINUE
} }
ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs: _, promoted: Some(p)}) ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs_: _, promoted: Some(p)})
// Avoid considering `T` unused when constants are of the form: // Avoid considering `T` unused when constants are of the form:
// `<Self as Foo<T>>::foo::promoted[p]` // `<Self as Foo<T>>::foo::promoted[p]`
if self.def_id == def.did && !self.tcx.generics_of(def.did).has_self => if self.def_id == def.did && !self.tcx.generics_of(def.did).has_self =>
@ -306,10 +309,10 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
self.visit_body(&promoted[p]); self.visit_body(&promoted[p]);
ControlFlow::CONTINUE ControlFlow::CONTINUE
} }
ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted: None }) ty::ConstKind::Unevaluated(uv)
if self.tcx.def_kind(def.did) == DefKind::AnonConst => if self.tcx.def_kind(uv.def.did) == DefKind::AnonConst =>
{ {
self.visit_child_body(def.did, substs); self.visit_child_body(uv.def.did, uv.substs(self.tcx));
ControlFlow::CONTINUE ControlFlow::CONTINUE
} }
_ => c.super_visit_with(self), _ => c.super_visit_with(self),
@ -318,7 +321,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
#[instrument(skip(self))] #[instrument(skip(self))]
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
if !ty.has_param_types_or_consts() { if !ty.potentially_has_param_types_or_consts() {
return ControlFlow::CONTINUE; return ControlFlow::CONTINUE;
} }
@ -346,16 +349,21 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
} }
/// Visitor used to check if a generic parameter is used. /// Visitor used to check if a generic parameter is used.
struct HasUsedGenericParams<'a> { struct HasUsedGenericParams<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
unused_parameters: &'a FiniteBitSet<u32>, unused_parameters: &'a FiniteBitSet<u32>,
} }
impl<'a, 'tcx> TypeVisitor<'tcx> for HasUsedGenericParams<'a> { impl<'a, 'tcx> TypeVisitor<'tcx> for HasUsedGenericParams<'a, 'tcx> {
type BreakTy = (); type BreakTy = ();
fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
Some(self.tcx)
}
#[instrument(skip(self))] #[instrument(skip(self))]
fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow<Self::BreakTy> { fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow<Self::BreakTy> {
if !c.has_param_types_or_consts() { if !c.potentially_has_param_types_or_consts() {
return ControlFlow::CONTINUE; return ControlFlow::CONTINUE;
} }
@ -373,7 +381,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for HasUsedGenericParams<'a> {
#[instrument(skip(self))] #[instrument(skip(self))]
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
if !ty.has_param_types_or_consts() { if !ty.potentially_has_param_types_or_consts() {
return ControlFlow::CONTINUE; return ControlFlow::CONTINUE;
} }

View File

@ -163,7 +163,7 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option<Ty<'tcx>>)
let source = MirSource::from_instance(ty::InstanceDef::DropGlue(def_id, ty)); let source = MirSource::from_instance(ty::InstanceDef::DropGlue(def_id, ty));
let mut body = let mut body =
new_body(source, blocks, local_decls_for_sig(&sig, span), sig.inputs().len(), span); new_body(tcx, source, blocks, local_decls_for_sig(&sig, span), sig.inputs().len(), span);
if ty.is_some() { if ty.is_some() {
// The first argument (index 0), but add 1 for the return value. // The first argument (index 0), but add 1 for the return value.
@ -202,6 +202,7 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option<Ty<'tcx>>)
} }
fn new_body<'tcx>( fn new_body<'tcx>(
tcx: TyCtxt<'tcx>,
source: MirSource<'tcx>, source: MirSource<'tcx>,
basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>, basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
local_decls: IndexVec<Local, LocalDecl<'tcx>>, local_decls: IndexVec<Local, LocalDecl<'tcx>>,
@ -209,6 +210,7 @@ fn new_body<'tcx>(
span: Span, span: Span,
) -> Body<'tcx> { ) -> Body<'tcx> {
Body::new( Body::new(
tcx,
source, source,
basic_blocks, basic_blocks,
IndexVec::from_elem_n( IndexVec::from_elem_n(
@ -353,7 +355,14 @@ impl CloneShimBuilder<'tcx> {
self.def_id, self.def_id,
self.sig.inputs_and_output[0], self.sig.inputs_and_output[0],
)); ));
new_body(source, self.blocks, self.local_decls, self.sig.inputs().len(), self.span) new_body(
self.tcx,
source,
self.blocks,
self.local_decls,
self.sig.inputs().len(),
self.span,
)
} }
fn source_info(&self) -> SourceInfo { fn source_info(&self) -> SourceInfo {
@ -851,8 +860,14 @@ fn build_call_shim<'tcx>(
block(&mut blocks, vec![], TerminatorKind::Resume, true); block(&mut blocks, vec![], TerminatorKind::Resume, true);
} }
let mut body = let mut body = new_body(
new_body(MirSource::from_instance(instance), blocks, local_decls, sig.inputs().len(), span); tcx,
MirSource::from_instance(instance),
blocks,
local_decls,
sig.inputs().len(),
span,
);
if let Abi::RustCall = sig.abi { if let Abi::RustCall = sig.abi {
body.spread_arg = Some(Local::new(sig.inputs().len())); body.spread_arg = Some(Local::new(sig.inputs().len()));
@ -917,6 +932,7 @@ pub fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> Body<'_> {
let source = MirSource::item(ctor_id); let source = MirSource::item(ctor_id);
let body = new_body( let body = new_body(
tcx,
source, source,
IndexVec::from_elem_n(start_block, 1), IndexVec::from_elem_n(start_block, 1),
local_decls, local_decls,

View File

@ -365,7 +365,7 @@ impl Checker<'mir, 'tcx> {
fn check_local_or_return_ty(&mut self, ty: Ty<'tcx>, local: Local) { fn check_local_or_return_ty(&mut self, ty: Ty<'tcx>, local: Local) {
let kind = self.body.local_kind(local); let kind = self.body.local_kind(local);
for ty in ty.walk() { for ty in ty.walk(self.tcx) {
let ty = match ty.unpack() { let ty = match ty.unpack() {
GenericArgKind::Type(ty) => ty, GenericArgKind::Type(ty) => ty,

View File

@ -247,7 +247,7 @@ where
// Check the qualifs of the value of `const` items. // Check the qualifs of the value of `const` items.
if let Some(ct) = constant.literal.const_for_ty() { if let Some(ct) = constant.literal.const_for_ty() {
if let ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs: _, promoted }) = ct.val { if let ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs_: _, promoted }) = ct.val {
assert!(promoted.is_none()); assert!(promoted.is_none());
// Don't peek inside trait associated constants. // Don't peek inside trait associated constants.
if cx.tcx.trait_of_item(def.did).is_none() { if cx.tcx.trait_of_item(def.did).is_none() {

View File

@ -120,7 +120,7 @@ impl<'tcx> MirPass<'tcx> for ConstProp {
.predicates_of(def_id.to_def_id()) .predicates_of(def_id.to_def_id())
.predicates .predicates
.iter() .iter()
.filter_map(|(p, _)| if p.is_global() { Some(*p) } else { None }); .filter_map(|(p, _)| if p.is_global(tcx) { Some(*p) } else { None });
if traits::impossible_predicates( if traits::impossible_predicates(
tcx, tcx,
traits::elaborate_predicates(tcx, predicates).map(|o| o.predicate).collect(), traits::elaborate_predicates(tcx, predicates).map(|o| o.predicate).collect(),
@ -132,6 +132,7 @@ impl<'tcx> MirPass<'tcx> for ConstProp {
trace!("ConstProp starting for {:?}", def_id); trace!("ConstProp starting for {:?}", def_id);
let dummy_body = &Body::new( let dummy_body = &Body::new(
tcx,
body.source, body.source,
body.basic_blocks().clone(), body.basic_blocks().clone(),
body.source_scopes.clone(), body.source_scopes.clone(),
@ -468,7 +469,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
/// Returns the value, if any, of evaluating `c`. /// Returns the value, if any, of evaluating `c`.
fn eval_constant(&mut self, c: &Constant<'tcx>, source_info: SourceInfo) -> Option<OpTy<'tcx>> { fn eval_constant(&mut self, c: &Constant<'tcx>, source_info: SourceInfo) -> Option<OpTy<'tcx>> {
// FIXME we need to revisit this for #67176 // FIXME we need to revisit this for #67176
if c.needs_subst() { if c.definitely_needs_subst(self.tcx) {
return None; return None;
} }
@ -483,14 +484,14 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
// Promoteds must lint and not error as the user didn't ask for them // Promoteds must lint and not error as the user didn't ask for them
ConstKind::Unevaluated(ty::Unevaluated { ConstKind::Unevaluated(ty::Unevaluated {
def: _, def: _,
substs: _, substs_: _,
promoted: Some(_), promoted: Some(_),
}) => true, }) => true,
// Out of backwards compatibility we cannot report hard errors in unused // Out of backwards compatibility we cannot report hard errors in unused
// generic functions using associated constants of the generic parameters. // generic functions using associated constants of the generic parameters.
_ => c.literal.needs_subst(), _ => c.literal.definitely_needs_subst(*tcx),
}, },
ConstantKind::Val(_, ty) => ty.needs_subst(), ConstantKind::Val(_, ty) => ty.definitely_needs_subst(*tcx),
}; };
if lint_only { if lint_only {
// Out of backwards compatibility we cannot report hard errors in unused // Out of backwards compatibility we cannot report hard errors in unused
@ -720,7 +721,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
} }
// FIXME we need to revisit this for #67176 // FIXME we need to revisit this for #67176
if rvalue.needs_subst() { if rvalue.definitely_needs_subst(self.tcx) {
return None; return None;
} }

View File

@ -49,7 +49,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FunctionItemRefChecker<'a, 'tcx> {
// Handle calls to `transmute` // Handle calls to `transmute`
if self.tcx.is_diagnostic_item(sym::transmute, def_id) { if self.tcx.is_diagnostic_item(sym::transmute, def_id) {
let arg_ty = args[0].ty(self.body, self.tcx); let arg_ty = args[0].ty(self.body, self.tcx);
for generic_inner_ty in arg_ty.walk() { for generic_inner_ty in arg_ty.walk(self.tcx) {
if let GenericArgKind::Type(inner_ty) = generic_inner_ty.unpack() { if let GenericArgKind::Type(inner_ty) = generic_inner_ty.unpack() {
if let Some((fn_id, fn_substs)) = if let Some((fn_id, fn_substs)) =
FunctionItemRefChecker::is_fn_ref(inner_ty) FunctionItemRefChecker::is_fn_ref(inner_ty)
@ -110,7 +110,7 @@ impl<'a, 'tcx> FunctionItemRefChecker<'a, 'tcx> {
let arg_defs = self.tcx.fn_sig(def_id).skip_binder().inputs(); let arg_defs = self.tcx.fn_sig(def_id).skip_binder().inputs();
for (arg_num, arg_def) in arg_defs.iter().enumerate() { for (arg_num, arg_def) in arg_defs.iter().enumerate() {
// For all types reachable from the argument type in the fn sig // For all types reachable from the argument type in the fn sig
for generic_inner_ty in arg_def.walk() { for generic_inner_ty in arg_def.walk(self.tcx) {
if let GenericArgKind::Type(inner_ty) = generic_inner_ty.unpack() { if let GenericArgKind::Type(inner_ty) = generic_inner_ty.unpack() {
// If the inner type matches the type bound by `Pointer` // If the inner type matches the type bound by `Pointer`
if TyS::same_type(inner_ty, bound_ty) { if TyS::same_type(inner_ty, bound_ty) {

View File

@ -89,7 +89,7 @@ crate fn mir_callgraph_reachable(
// FIXME: A not fully substituted drop shim can cause ICEs if one attempts to // FIXME: A not fully substituted drop shim can cause ICEs if one attempts to
// have its MIR built. Likely oli-obk just screwed up the `ParamEnv`s, so this // have its MIR built. Likely oli-obk just screwed up the `ParamEnv`s, so this
// needs some more analysis. // needs some more analysis.
if callee.needs_subst() { if callee.definitely_needs_subst(tcx) {
continue; continue;
} }
} }

View File

@ -400,7 +400,7 @@ fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -
} }
} }
debug_assert!(!body.has_free_regions(), "Free regions in MIR for CTFE"); debug_assert!(!body.has_free_regions(tcx), "Free regions in MIR for CTFE");
body body
} }
@ -594,7 +594,7 @@ fn inner_optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> Body<'_> {
tcx.mir_drops_elaborated_and_const_checked(ty::WithOptConstParam::unknown(did)).steal(); tcx.mir_drops_elaborated_and_const_checked(ty::WithOptConstParam::unknown(did)).steal();
run_optimization_passes(tcx, &mut body); run_optimization_passes(tcx, &mut body);
debug_assert!(!body.has_free_regions(), "Free regions in optimized MIR"); debug_assert!(!body.has_free_regions(tcx), "Free regions in optimized MIR");
body body
} }
@ -621,7 +621,7 @@ fn promoted_mir<'tcx>(
run_post_borrowck_cleanup_passes(tcx, body); run_post_borrowck_cleanup_passes(tcx, body);
} }
debug_assert!(!promoted.has_free_regions(), "Free regions in promoted MIR"); debug_assert!(!promoted.has_free_regions(tcx), "Free regions in promoted MIR");
tcx.arena.alloc(promoted) tcx.arena.alloc(promoted)
} }

View File

@ -859,13 +859,17 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
ty, ty,
val: ty::ConstKind::Unevaluated(ty::Unevaluated { val: ty::ConstKind::Unevaluated(ty::Unevaluated {
def, def,
substs: InternalSubsts::for_item(tcx, def.did, |param, _| { substs_: Some(InternalSubsts::for_item(
if let ty::GenericParamDefKind::Lifetime = param.kind { tcx,
tcx.lifetimes.re_erased.into() def.did,
} else { |param, _| {
tcx.mk_param_from_def(param) if let ty::GenericParamDefKind::Lifetime = param.kind {
} tcx.lifetimes.re_erased.into()
}), } else {
tcx.mk_param_from_def(param)
}
},
)),
promoted: Some(promoted_id), promoted: Some(promoted_id),
}), }),
}) })
@ -988,6 +992,7 @@ pub fn promote_candidates<'tcx>(
scope.parent_scope = None; scope.parent_scope = None;
let promoted = Body::new( let promoted = Body::new(
tcx,
body.source, // `promoted` gets filled in below body.source, // `promoted` gets filled in below
IndexVec::new(), IndexVec::new(),
IndexVec::from_elem_n(scope, 1), IndexVec::from_elem_n(scope, 1),

View File

@ -475,7 +475,7 @@ impl Visitor<'tcx> for ExtraComments<'tcx> {
ty::ConstKind::Unevaluated(uv) => format!( ty::ConstKind::Unevaluated(uv) => format!(
"Unevaluated({}, {:?}, {:?})", "Unevaluated({}, {:?}, {:?})",
self.tcx.def_path_str(uv.def.did), self.tcx.def_path_str(uv.def.did),
uv.substs, uv.substs(self.tcx),
uv.promoted uv.promoted
), ),
ty::ConstKind::Value(val) => format!("Value({:?})", val), ty::ConstKind::Value(val) => format!("Value({:?})", val),
@ -682,6 +682,12 @@ pub fn write_allocations<'tcx>(
} }
struct CollectAllocIds(BTreeSet<AllocId>); struct CollectAllocIds(BTreeSet<AllocId>);
impl<'tcx> TypeVisitor<'tcx> for CollectAllocIds { impl<'tcx> TypeVisitor<'tcx> for CollectAllocIds {
fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
// `AllocId`s are only inside of `ConstKind::Value` which
// can't be part of the anon const default substs.
None
}
fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> { fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
if let ty::ConstKind::Value(val) = c.val { if let ty::ConstKind::Value(val) = c.val {
self.0.extend(alloc_ids_from_const(val)); self.0.extend(alloc_ids_from_const(val));

View File

@ -239,10 +239,10 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_
// The exception is `body.user_type_annotations`, which is used unmodified // The exception is `body.user_type_annotations`, which is used unmodified
// by borrow checking. // by borrow checking.
debug_assert!( debug_assert!(
!(body.local_decls.has_free_regions() !(body.local_decls.has_free_regions(tcx)
|| body.basic_blocks().has_free_regions() || body.basic_blocks().has_free_regions(tcx)
|| body.var_debug_info.has_free_regions() || body.var_debug_info.has_free_regions(tcx)
|| body.yield_ty().has_free_regions()), || body.yield_ty().has_free_regions(tcx)),
"Unexpected free regions in MIR: {:?}", "Unexpected free regions in MIR: {:?}",
body, body,
); );
@ -755,6 +755,7 @@ fn construct_error<'a, 'tcx>(
cfg.terminate(START_BLOCK, source_info, TerminatorKind::Unreachable); cfg.terminate(START_BLOCK, source_info, TerminatorKind::Unreachable);
let mut body = Body::new( let mut body = Body::new(
tcx,
MirSource::item(def.did.to_def_id()), MirSource::item(def.did.to_def_id()),
cfg.basic_blocks, cfg.basic_blocks,
source_scopes, source_scopes,
@ -843,6 +844,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
} }
Body::new( Body::new(
self.tcx,
MirSource::item(self.def_id), MirSource::item(self.def_id),
self.cfg.basic_blocks, self.cfg.basic_blocks,
self.source_scopes, self.source_scopes,

View File

@ -693,11 +693,10 @@ impl<'tcx> Cx<'tcx> {
// and not the beginning of discriminants (which is always `0`) // and not the beginning of discriminants (which is always `0`)
let substs = InternalSubsts::identity_for_item(self.tcx(), did); let substs = InternalSubsts::identity_for_item(self.tcx(), did);
let lhs = ty::Const { let lhs = ty::Const {
val: ty::ConstKind::Unevaluated(ty::Unevaluated { val: ty::ConstKind::Unevaluated(ty::Unevaluated::new(
def: ty::WithOptConstParam::unknown(did), ty::WithOptConstParam::unknown(did),
substs, substs,
promoted: None, )),
}),
ty: var_ty, ty: var_ty,
}; };
let lhs = self.thir.exprs.push(mk_const(self.tcx().mk_const(lhs))); let lhs = self.thir.exprs.push(mk_const(self.tcx().mk_const(lhs)));
@ -889,11 +888,10 @@ impl<'tcx> Cx<'tcx> {
debug!("convert_path_expr: (const) user_ty={:?}", user_ty); debug!("convert_path_expr: (const) user_ty={:?}", user_ty);
ExprKind::Literal { ExprKind::Literal {
literal: self.tcx.mk_const(ty::Const { literal: self.tcx.mk_const(ty::Const {
val: ty::ConstKind::Unevaluated(ty::Unevaluated { val: ty::ConstKind::Unevaluated(ty::Unevaluated::new(
def: ty::WithOptConstParam::unknown(def_id), ty::WithOptConstParam::unknown(def_id),
substs, substs,
promoted: None, )),
}),
ty: self.typeck_results().node_type(expr.hir_id), ty: self.typeck_results().node_type(expr.hir_id),
}), }),
user_ty, user_ty,

View File

@ -237,7 +237,7 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
// code at the moment, because types like `for <'a> fn(&'a ())` do // code at the moment, because types like `for <'a> fn(&'a ())` do
// not *yet* implement `PartialEq`. So for now we leave this here. // not *yet* implement `PartialEq`. So for now we leave this here.
has_impl has_impl
|| ty.walk().any(|t| match t.unpack() { || ty.walk(self.tcx()).any(|t| match t.unpack() {
ty::subst::GenericArgKind::Lifetime(_) => false, ty::subst::GenericArgKind::Lifetime(_) => false,
ty::subst::GenericArgKind::Type(t) => t.is_fn_ptr(), ty::subst::GenericArgKind::Type(t) => t.is_fn_ptr(),
ty::subst::GenericArgKind::Const(_) => false, ty::subst::GenericArgKind::Const(_) => false,

View File

@ -134,11 +134,11 @@ where
ty.visit_with(self) ty.visit_with(self)
} }
ty::PredicateKind::RegionOutlives(..) => ControlFlow::CONTINUE, ty::PredicateKind::RegionOutlives(..) => ControlFlow::CONTINUE,
ty::PredicateKind::ConstEvaluatable(defs, substs) ty::PredicateKind::ConstEvaluatable(uv)
if self.def_id_visitor.tcx().features().const_evaluatable_checked => if self.def_id_visitor.tcx().features().const_evaluatable_checked =>
{ {
let tcx = self.def_id_visitor.tcx(); let tcx = self.def_id_visitor.tcx();
if let Ok(Some(ct)) = AbstractConst::new(tcx, defs, substs) { if let Ok(Some(ct)) = AbstractConst::new(tcx, uv) {
self.visit_abstract_const_expr(tcx, ct)?; self.visit_abstract_const_expr(tcx, ct)?;
} }
ControlFlow::CONTINUE ControlFlow::CONTINUE
@ -179,6 +179,10 @@ where
{ {
type BreakTy = V::BreakTy; type BreakTy = V::BreakTy;
fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
Some(self.def_id_visitor.tcx())
}
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<V::BreakTy> { fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<V::BreakTy> {
let tcx = self.def_id_visitor.tcx(); let tcx = self.def_id_visitor.tcx();
// InternalSubsts are not visited here because they are visited below in `super_visit_with`. // InternalSubsts are not visited here because they are visited below in `super_visit_with`.

View File

@ -217,18 +217,13 @@ impl<'tcx> Key for (DefId, SubstsRef<'tcx>) {
} }
} }
impl<'tcx> Key impl<'tcx> Key for (ty::Unevaluated<'tcx, ()>, ty::Unevaluated<'tcx, ()>) {
for (
(ty::WithOptConstParam<DefId>, SubstsRef<'tcx>),
(ty::WithOptConstParam<DefId>, SubstsRef<'tcx>),
)
{
#[inline(always)] #[inline(always)]
fn query_crate_is_local(&self) -> bool { fn query_crate_is_local(&self) -> bool {
(self.0).0.did.krate == LOCAL_CRATE (self.0).def.did.krate == LOCAL_CRATE
} }
fn default_span(&self, tcx: TyCtxt<'_>) -> Span { fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
(self.0).0.did.default_span(tcx) (self.0).def.did.default_span(tcx)
} }
} }

View File

@ -107,9 +107,9 @@ fn get_symbol_hash<'tcx>(
tcx.def_path_hash(def_id).hash_stable(&mut hcx, &mut hasher); tcx.def_path_hash(def_id).hash_stable(&mut hcx, &mut hasher);
// Include the main item-type. Note that, in this case, the // Include the main item-type. Note that, in this case, the
// assertions about `needs_subst` may not hold, but this item-type // assertions about `definitely_needs_subst` may not hold, but this item-type
// ought to be the same for every reference anyway. // ought to be the same for every reference anyway.
assert!(!item_type.has_erasable_regions()); assert!(!item_type.has_erasable_regions(tcx));
hcx.while_hashing_spans(false, |hcx| { hcx.while_hashing_spans(false, |hcx| {
hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
item_type.hash_stable(hcx, &mut hasher); item_type.hash_stable(hcx, &mut hasher);

View File

@ -280,7 +280,9 @@ impl Printer<'tcx> for &mut SymbolMangler<'tcx> {
// Encode impl generic params if the substitutions contain parameters (implying // Encode impl generic params if the substitutions contain parameters (implying
// polymorphization is enabled) and this isn't an inherent impl. // polymorphization is enabled) and this isn't an inherent impl.
if impl_trait_ref.is_some() && substs.iter().any(|a| a.has_param_types_or_consts()) { if impl_trait_ref.is_some()
&& substs.iter().any(|a| a.definitely_has_param_types_or_consts(self.tcx))
{
self = self.path_generic_args( self = self.path_generic_args(
|this| { |this| {
this.path_append_ns( this.path_append_ns(

View File

@ -352,6 +352,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
if !required_region_bounds.is_empty() { if !required_region_bounds.is_empty() {
for required_region in required_region_bounds { for required_region in required_region_bounds {
concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor { concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
tcx,
op: |r| self.sub_regions(infer::CallReturn(span), required_region, r), op: |r| self.sub_regions(infer::CallReturn(span), required_region, r),
}); });
} }
@ -427,6 +428,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
} }
} }
concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor { concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
tcx,
op: |r| self.sub_regions(infer::CallReturn(span), least_region, r), op: |r| self.sub_regions(infer::CallReturn(span), least_region, r),
}); });
} }
@ -461,6 +463,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
); );
concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor { concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
tcx: self.tcx,
op: |r| { op: |r| {
self.member_constraint( self.member_constraint(
opaque_type_key.def_id, opaque_type_key.def_id,
@ -546,14 +549,19 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
// //
// We ignore any type parameters because impl trait values are assumed to // We ignore any type parameters because impl trait values are assumed to
// capture all the in-scope type parameters. // capture all the in-scope type parameters.
struct ConstrainOpaqueTypeRegionVisitor<OP> { struct ConstrainOpaqueTypeRegionVisitor<'tcx, OP> {
tcx: TyCtxt<'tcx>,
op: OP, op: OP,
} }
impl<'tcx, OP> TypeVisitor<'tcx> for ConstrainOpaqueTypeRegionVisitor<OP> impl<'tcx, OP> TypeVisitor<'tcx> for ConstrainOpaqueTypeRegionVisitor<'tcx, OP>
where where
OP: FnMut(ty::Region<'tcx>), OP: FnMut(ty::Region<'tcx>),
{ {
fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
Some(self.tcx)
}
fn visit_binder<T: TypeFoldable<'tcx>>( fn visit_binder<T: TypeFoldable<'tcx>>(
&mut self, &mut self,
t: &ty::Binder<'tcx, T>, t: &ty::Binder<'tcx, T>,
@ -575,7 +583,7 @@ where
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
// We're only interested in types involving regions // We're only interested in types involving regions
if !ty.flags().intersects(ty::TypeFlags::HAS_FREE_REGIONS) { if !ty.flags().intersects(ty::TypeFlags::HAS_POTENTIAL_FREE_REGIONS) {
return ControlFlow::CONTINUE; return ControlFlow::CONTINUE;
} }

View File

@ -391,7 +391,7 @@ fn orphan_check_trait_ref<'tcx>(
) -> Result<(), OrphanCheckErr<'tcx>> { ) -> Result<(), OrphanCheckErr<'tcx>> {
debug!("orphan_check_trait_ref(trait_ref={:?}, in_crate={:?})", trait_ref, in_crate); debug!("orphan_check_trait_ref(trait_ref={:?}, in_crate={:?})", trait_ref, in_crate);
if trait_ref.needs_infer() && trait_ref.needs_subst() { if trait_ref.needs_infer() && trait_ref.definitely_needs_subst(tcx) {
bug!( bug!(
"can't orphan check a trait ref with both params and inference variables {:?}", "can't orphan check a trait ref with both params and inference variables {:?}",
trait_ref trait_ref

View File

@ -19,7 +19,7 @@ use rustc_middle::mir::{self, Rvalue, StatementKind, TerminatorKind};
use rustc_middle::ty::subst::{Subst, SubstsRef}; use rustc_middle::ty::subst::{Subst, SubstsRef};
use rustc_middle::ty::{self, TyCtxt, TypeFoldable}; use rustc_middle::ty::{self, TyCtxt, TypeFoldable};
use rustc_session::lint; use rustc_session::lint;
use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::def_id::LocalDefId;
use rustc_span::Span; use rustc_span::Span;
use std::cmp; use std::cmp;
@ -29,26 +29,20 @@ use std::ops::ControlFlow;
/// Check if a given constant can be evaluated. /// Check if a given constant can be evaluated.
pub fn is_const_evaluatable<'cx, 'tcx>( pub fn is_const_evaluatable<'cx, 'tcx>(
infcx: &InferCtxt<'cx, 'tcx>, infcx: &InferCtxt<'cx, 'tcx>,
def: ty::WithOptConstParam<DefId>, uv: ty::Unevaluated<'tcx, ()>,
substs: SubstsRef<'tcx>,
param_env: ty::ParamEnv<'tcx>, param_env: ty::ParamEnv<'tcx>,
span: Span, span: Span,
) -> Result<(), NotConstEvaluatable> { ) -> Result<(), NotConstEvaluatable> {
debug!("is_const_evaluatable({:?}, {:?})", def, substs); debug!("is_const_evaluatable({:?})", uv);
if infcx.tcx.features().const_evaluatable_checked { if infcx.tcx.features().const_evaluatable_checked {
let tcx = infcx.tcx; let tcx = infcx.tcx;
match AbstractConst::new(tcx, def, substs)? { match AbstractConst::new(tcx, uv)? {
// We are looking at a generic abstract constant. // We are looking at a generic abstract constant.
Some(ct) => { Some(ct) => {
for pred in param_env.caller_bounds() { for pred in param_env.caller_bounds() {
match pred.kind().skip_binder() { match pred.kind().skip_binder() {
ty::PredicateKind::ConstEvaluatable(b_def, b_substs) => { ty::PredicateKind::ConstEvaluatable(uv) => {
if b_def == def && b_substs == substs { if let Some(b_ct) = AbstractConst::new(tcx, uv)? {
debug!("is_const_evaluatable: caller_bound ~~> ok");
return Ok(());
}
if let Some(b_ct) = AbstractConst::new(tcx, b_def, b_substs)? {
// Try to unify with each subtree in the AbstractConst to allow for // Try to unify with each subtree in the AbstractConst to allow for
// `N + 1` being const evaluatable even if theres only a `ConstEvaluatable` // `N + 1` being const evaluatable even if theres only a `ConstEvaluatable`
// predicate for `(N + 1) * 2` // predicate for `(N + 1) * 2`
@ -91,7 +85,7 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
let leaf = leaf.subst(tcx, ct.substs); let leaf = leaf.subst(tcx, ct.substs);
if leaf.has_infer_types_or_consts() { if leaf.has_infer_types_or_consts() {
failure_kind = FailureKind::MentionsInfer; failure_kind = FailureKind::MentionsInfer;
} else if leaf.has_param_types_or_consts() { } else if leaf.definitely_has_param_types_or_consts(tcx) {
failure_kind = cmp::min(failure_kind, FailureKind::MentionsParam); failure_kind = cmp::min(failure_kind, FailureKind::MentionsParam);
} }
@ -101,7 +95,7 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
let ty = ty.subst(tcx, ct.substs); let ty = ty.subst(tcx, ct.substs);
if ty.has_infer_types_or_consts() { if ty.has_infer_types_or_consts() {
failure_kind = FailureKind::MentionsInfer; failure_kind = FailureKind::MentionsInfer;
} else if ty.has_param_types_or_consts() { } else if ty.definitely_has_param_types_or_consts(tcx) {
failure_kind = cmp::min(failure_kind, FailureKind::MentionsParam); failure_kind = cmp::min(failure_kind, FailureKind::MentionsParam);
} }
@ -134,7 +128,7 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
} }
let future_compat_lint = || { let future_compat_lint = || {
if let Some(local_def_id) = def.did.as_local() { if let Some(local_def_id) = uv.def.did.as_local() {
infcx.tcx.struct_span_lint_hir( infcx.tcx.struct_span_lint_hir(
lint::builtin::CONST_EVALUATABLE_UNCHECKED, lint::builtin::CONST_EVALUATABLE_UNCHECKED,
infcx.tcx.hir().local_def_id_to_hir_id(local_def_id), infcx.tcx.hir().local_def_id_to_hir_id(local_def_id),
@ -155,16 +149,12 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
// and hopefully soon change this to an error. // and hopefully soon change this to an error.
// //
// See #74595 for more details about this. // See #74595 for more details about this.
let concrete = infcx.const_eval_resolve( let concrete = infcx.const_eval_resolve(param_env, uv.expand(), Some(span));
param_env,
ty::Unevaluated { def, substs, promoted: None },
Some(span),
);
if concrete.is_ok() && substs.has_param_types_or_consts() { if concrete.is_ok() && uv.substs(infcx.tcx).definitely_has_param_types_or_consts(infcx.tcx) {
match infcx.tcx.def_kind(def.did) { match infcx.tcx.def_kind(uv.def.did) {
DefKind::AnonConst => { DefKind::AnonConst => {
let mir_body = infcx.tcx.mir_for_ctfe_opt_const_arg(def); let mir_body = infcx.tcx.mir_for_ctfe_opt_const_arg(uv.def);
if mir_body.is_polymorphic { if mir_body.is_polymorphic {
future_compat_lint(); future_compat_lint();
@ -176,7 +166,7 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
debug!(?concrete, "is_const_evaluatable"); debug!(?concrete, "is_const_evaluatable");
match concrete { match concrete {
Err(ErrorHandled::TooGeneric) => Err(match substs.has_infer_types_or_consts() { Err(ErrorHandled::TooGeneric) => Err(match uv.has_infer_types_or_consts() {
true => NotConstEvaluatable::MentionsInfer, true => NotConstEvaluatable::MentionsInfer,
false => NotConstEvaluatable::MentionsParam, false => NotConstEvaluatable::MentionsParam,
}), }),
@ -201,15 +191,14 @@ pub struct AbstractConst<'tcx> {
pub substs: SubstsRef<'tcx>, pub substs: SubstsRef<'tcx>,
} }
impl AbstractConst<'tcx> { impl<'tcx> AbstractConst<'tcx> {
pub fn new( pub fn new(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
def: ty::WithOptConstParam<DefId>, uv: ty::Unevaluated<'tcx, ()>,
substs: SubstsRef<'tcx>,
) -> Result<Option<AbstractConst<'tcx>>, ErrorReported> { ) -> Result<Option<AbstractConst<'tcx>>, ErrorReported> {
let inner = tcx.mir_abstract_const_opt_const_arg(def)?; let inner = tcx.mir_abstract_const_opt_const_arg(uv.def)?;
debug!("AbstractConst::new({:?}) = {:?}", def, inner); debug!("AbstractConst::new({:?}) = {:?}", uv, inner);
Ok(inner.map(|inner| AbstractConst { inner, substs })) Ok(inner.map(|inner| AbstractConst { inner, substs: uv.substs(tcx) }))
} }
pub fn from_const( pub fn from_const(
@ -217,9 +206,7 @@ impl AbstractConst<'tcx> {
ct: &ty::Const<'tcx>, ct: &ty::Const<'tcx>,
) -> Result<Option<AbstractConst<'tcx>>, ErrorReported> { ) -> Result<Option<AbstractConst<'tcx>>, ErrorReported> {
match ct.val { match ct.val {
ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted: _ }) => { ty::ConstKind::Unevaluated(uv) => AbstractConst::new(tcx, uv.shrink()),
AbstractConst::new(tcx, def, substs)
}
ty::ConstKind::Error(_) => Err(ErrorReported), ty::ConstKind::Error(_) => Err(ErrorReported),
_ => Ok(None), _ => Ok(None),
} }
@ -569,14 +556,11 @@ pub(super) fn mir_abstract_const<'tcx>(
pub(super) fn try_unify_abstract_consts<'tcx>( pub(super) fn try_unify_abstract_consts<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
((a, a_substs), (b, b_substs)): ( (a, b): (ty::Unevaluated<'tcx, ()>, ty::Unevaluated<'tcx, ()>),
(ty::WithOptConstParam<DefId>, SubstsRef<'tcx>),
(ty::WithOptConstParam<DefId>, SubstsRef<'tcx>),
),
) -> bool { ) -> bool {
(|| { (|| {
if let Some(a) = AbstractConst::new(tcx, a, a_substs)? { if let Some(a) = AbstractConst::new(tcx, a)? {
if let Some(b) = AbstractConst::new(tcx, b, b_substs)? { if let Some(b) = AbstractConst::new(tcx, b)? {
return Ok(try_unify(tcx, a, b)); return Ok(try_unify(tcx, a, b));
} }
} }

View File

@ -811,10 +811,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
} }
match obligation.predicate.kind().skip_binder() { match obligation.predicate.kind().skip_binder() {
ty::PredicateKind::ConstEvaluatable(def, _) => { ty::PredicateKind::ConstEvaluatable(uv) => {
let mut err = let mut err =
self.tcx.sess.struct_span_err(span, "unconstrained generic constant"); self.tcx.sess.struct_span_err(span, "unconstrained generic constant");
let const_span = self.tcx.def_span(def.did); let const_span = self.tcx.def_span(uv.def.did);
match self.tcx.sess.source_map().span_to_snippet(const_span) { match self.tcx.sess.source_map().span_to_snippet(const_span) {
Ok(snippet) => err.help(&format!( Ok(snippet) => err.help(&format!(
"try adding a `where` bound using this expression: `where [(); {}]:`", "try adding a `where` bound using this expression: `where [(); {}]:`",

View File

@ -543,11 +543,10 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
} }
} }
ty::PredicateKind::ConstEvaluatable(def_id, substs) => { ty::PredicateKind::ConstEvaluatable(uv) => {
match const_evaluatable::is_const_evaluatable( match const_evaluatable::is_const_evaluatable(
self.selcx.infcx(), self.selcx.infcx(),
def_id, uv,
substs,
obligation.param_env, obligation.param_env,
obligation.cause.span, obligation.cause.span,
) { ) {
@ -555,7 +554,9 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
Err(NotConstEvaluatable::MentionsInfer) => { Err(NotConstEvaluatable::MentionsInfer) => {
pending_obligation.stalled_on.clear(); pending_obligation.stalled_on.clear();
pending_obligation.stalled_on.extend( pending_obligation.stalled_on.extend(
substs.iter().filter_map(TyOrConstInferVar::maybe_from_generic_arg), uv.substs(infcx.tcx)
.iter()
.filter_map(TyOrConstInferVar::maybe_from_generic_arg),
); );
ProcessResult::Unchanged ProcessResult::Unchanged
} }
@ -570,7 +571,8 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
ty::PredicateKind::ConstEquate(c1, c2) => { ty::PredicateKind::ConstEquate(c1, c2) => {
debug!(?c1, ?c2, "equating consts"); debug!(?c1, ?c2, "equating consts");
if self.selcx.tcx().features().const_evaluatable_checked { let tcx = self.selcx.tcx();
if tcx.features().const_evaluatable_checked {
// FIXME: we probably should only try to unify abstract constants // FIXME: we probably should only try to unify abstract constants
// if the constants depend on generic parameters. // if the constants depend on generic parameters.
// //
@ -578,7 +580,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
if let (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) = if let (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) =
(c1.val, c2.val) (c1.val, c2.val)
{ {
if infcx.try_unify_abstract_consts(a, b) { if infcx.try_unify_abstract_consts(a.shrink(), b.shrink()) {
return ProcessResult::Changed(vec![]); return ProcessResult::Changed(vec![]);
} }
} }
@ -597,7 +599,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
Err(ErrorHandled::TooGeneric) => { Err(ErrorHandled::TooGeneric) => {
stalled_on.extend( stalled_on.extend(
unevaluated unevaluated
.substs .substs(tcx)
.iter() .iter()
.filter_map(TyOrConstInferVar::maybe_from_generic_arg), .filter_map(TyOrConstInferVar::maybe_from_generic_arg),
); );
@ -668,7 +670,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
stalled_on: &mut Vec<TyOrConstInferVar<'tcx>>, stalled_on: &mut Vec<TyOrConstInferVar<'tcx>>,
) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> { ) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> {
let infcx = self.selcx.infcx(); let infcx = self.selcx.infcx();
if obligation.predicate.is_global() { if obligation.predicate.is_known_global() {
// no type variables present, can use evaluation for better caching. // no type variables present, can use evaluation for better caching.
// FIXME: consider caching errors too. // FIXME: consider caching errors too.
// //
@ -727,7 +729,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> { ) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> {
let tcx = self.selcx.tcx(); let tcx = self.selcx.tcx();
if obligation.predicate.is_global() { if obligation.predicate.is_global(tcx) {
// no type variables present, can use evaluation for better caching. // no type variables present, can use evaluation for better caching.
// FIXME: consider caching errors too. // FIXME: consider caching errors too.
// //
@ -766,14 +768,15 @@ fn substs_infer_vars<'a, 'tcx>(
selcx: &mut SelectionContext<'a, 'tcx>, selcx: &mut SelectionContext<'a, 'tcx>,
substs: ty::Binder<'tcx, SubstsRef<'tcx>>, substs: ty::Binder<'tcx, SubstsRef<'tcx>>,
) -> impl Iterator<Item = TyOrConstInferVar<'tcx>> { ) -> impl Iterator<Item = TyOrConstInferVar<'tcx>> {
let tcx = selcx.tcx();
selcx selcx
.infcx() .infcx()
.resolve_vars_if_possible(substs) .resolve_vars_if_possible(substs)
.skip_binder() // ok because this check doesn't care about regions .skip_binder() // ok because this check doesn't care about regions
.iter() .iter()
.filter(|arg| arg.has_infer_types_or_consts()) .filter(|arg| arg.has_infer_types_or_consts())
.flat_map(|arg| { .flat_map(move |arg| {
let mut walker = arg.walk(); let mut walker = arg.walk(tcx);
while let Some(c) = walker.next() { while let Some(c) = walker.next() {
if !c.has_infer_types_or_consts() { if !c.has_infer_types_or_consts() {
walker.visited.remove(&c); walker.visited.remove(&c);

View File

@ -450,7 +450,7 @@ fn subst_and_check_impossible_predicates<'tcx>(
debug!("subst_and_check_impossible_predicates(key={:?})", key); debug!("subst_and_check_impossible_predicates(key={:?})", key);
let mut predicates = tcx.predicates_of(key.0).instantiate(tcx, key.1).predicates; let mut predicates = tcx.predicates_of(key.0).instantiate(tcx, key.1).predicates;
predicates.retain(|predicate| !predicate.needs_subst()); predicates.retain(|predicate| !predicate.definitely_needs_subst(tcx));
let result = impossible_predicates(tcx, predicates); let result = impossible_predicates(tcx, predicates);
debug!("subst_and_check_impossible_predicates(key={:?}) = {:?}", key, result); debug!("subst_and_check_impossible_predicates(key={:?}) = {:?}", key, result);

View File

@ -278,7 +278,7 @@ fn predicate_references_self(
(predicate, sp): (ty::Predicate<'tcx>, Span), (predicate, sp): (ty::Predicate<'tcx>, Span),
) -> Option<Span> { ) -> Option<Span> {
let self_ty = tcx.types.self_param; let self_ty = tcx.types.self_param;
let has_self_ty = |arg: &GenericArg<'_>| arg.walk().any(|arg| arg == self_ty.into()); let has_self_ty = |arg: &GenericArg<'tcx>| arg.walk(tcx).any(|arg| arg == self_ty.into());
match predicate.kind().skip_binder() { match predicate.kind().skip_binder() {
ty::PredicateKind::Trait(ref data) => { ty::PredicateKind::Trait(ref data) => {
// In the case of a trait predicate, we can skip the "self" type. // In the case of a trait predicate, we can skip the "self" type.
@ -771,6 +771,9 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>(
impl<'tcx> TypeVisitor<'tcx> for IllegalSelfTypeVisitor<'tcx> { impl<'tcx> TypeVisitor<'tcx> for IllegalSelfTypeVisitor<'tcx> {
type BreakTy = (); type BreakTy = ();
fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
Some(self.tcx)
}
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
match t.kind() { match t.kind() {
@ -851,12 +854,12 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>(
} }
fn visit_predicate(&mut self, pred: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> { fn visit_predicate(&mut self, pred: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
if let ty::PredicateKind::ConstEvaluatable(def, substs) = pred.kind().skip_binder() { if let ty::PredicateKind::ConstEvaluatable(ct) = pred.kind().skip_binder() {
// FIXME(const_evaluatable_checked): We should probably deduplicate the logic for // FIXME(const_evaluatable_checked): We should probably deduplicate the logic for
// `AbstractConst`s here, it might make sense to change `ConstEvaluatable` to // `AbstractConst`s here, it might make sense to change `ConstEvaluatable` to
// take a `ty::Const` instead. // take a `ty::Const` instead.
use rustc_middle::mir::abstract_const::Node; use rustc_middle::mir::abstract_const::Node;
if let Ok(Some(ct)) = AbstractConst::new(self.tcx, def, substs) { if let Ok(Some(ct)) = AbstractConst::new(self.tcx, ct) {
const_evaluatable::walk_abstract_const(self.tcx, ct, |node| match node.root() { const_evaluatable::walk_abstract_const(self.tcx, ct, |node| match node.root() {
Node::Leaf(leaf) => { Node::Leaf(leaf) => {
let leaf = leaf.subst(self.tcx, ct.substs); let leaf = leaf.subst(self.tcx, ct.substs);

View File

@ -78,8 +78,11 @@ impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> {
// The rest of the code is already set up to be lazy about replacing bound vars, // The rest of the code is already set up to be lazy about replacing bound vars,
// and only when we actually have to normalize. // and only when we actually have to normalize.
if value.has_escaping_bound_vars() { if value.has_escaping_bound_vars() {
let mut max_visitor = let mut max_visitor = MaxEscapingBoundVarVisitor {
MaxEscapingBoundVarVisitor { outer_index: ty::INNERMOST, escaping: 0 }; tcx: self.infcx.tcx,
outer_index: ty::INNERMOST,
escaping: 0,
};
value.visit_with(&mut max_visitor); value.visit_with(&mut max_visitor);
if max_visitor.escaping > 0 { if max_visitor.escaping > 0 {
normalizer.universes.extend((0..max_visitor.escaping).map(|_| None)); normalizer.universes.extend((0..max_visitor.escaping).map(|_| None));
@ -106,13 +109,18 @@ impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> {
} }
/// Visitor to find the maximum escaping bound var /// Visitor to find the maximum escaping bound var
struct MaxEscapingBoundVarVisitor { struct MaxEscapingBoundVarVisitor<'tcx> {
tcx: TyCtxt<'tcx>,
// The index which would count as escaping // The index which would count as escaping
outer_index: ty::DebruijnIndex, outer_index: ty::DebruijnIndex,
escaping: usize, escaping: usize,
} }
impl<'tcx> TypeVisitor<'tcx> for MaxEscapingBoundVarVisitor { impl<'tcx> TypeVisitor<'tcx> for MaxEscapingBoundVarVisitor<'tcx> {
fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
Some(self.tcx)
}
fn visit_binder<T: TypeFoldable<'tcx>>( fn visit_binder<T: TypeFoldable<'tcx>>(
&mut self, &mut self,
t: &ty::Binder<'tcx, T>, t: &ty::Binder<'tcx, T>,

View File

@ -947,7 +947,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let mut unsizing_params = GrowableBitSet::new_empty(); let mut unsizing_params = GrowableBitSet::new_empty();
if tcx.features().relaxed_struct_unsize { if tcx.features().relaxed_struct_unsize {
for arg in tail_field_ty.walk() { for arg in tail_field_ty.walk(tcx) {
if let Some(i) = maybe_unsizing_param_idx(arg) { if let Some(i) = maybe_unsizing_param_idx(arg) {
unsizing_params.insert(i); unsizing_params.insert(i);
} }
@ -956,7 +956,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// Ensure none of the other fields mention the parameters used // Ensure none of the other fields mention the parameters used
// in unsizing. // in unsizing.
for field in prefix_fields { for field in prefix_fields {
for arg in tcx.type_of(field.did).walk() { for arg in tcx.type_of(field.did).walk(tcx) {
if let Some(i) = maybe_unsizing_param_idx(arg) { if let Some(i) = maybe_unsizing_param_idx(arg) {
unsizing_params.remove(i); unsizing_params.remove(i);
} }
@ -968,7 +968,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
} }
} else { } else {
let mut found = false; let mut found = false;
for arg in tail_field_ty.walk() { for arg in tail_field_ty.walk(tcx) {
if let Some(i) = maybe_unsizing_param_idx(arg) { if let Some(i) = maybe_unsizing_param_idx(arg) {
unsizing_params.insert(i); unsizing_params.insert(i);
found = true; found = true;
@ -984,7 +984,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// by putting it in a query; it would only need the `DefId` as it // by putting it in a query; it would only need the `DefId` as it
// looks at declared field types, not anything substituted. // looks at declared field types, not anything substituted.
for field in prefix_fields { for field in prefix_fields {
for arg in tcx.type_of(field.did).walk() { for arg in tcx.type_of(field.did).walk(tcx) {
if let Some(i) = maybe_unsizing_param_idx(arg) { if let Some(i) = maybe_unsizing_param_idx(arg) {
if unsizing_params.contains(i) { if unsizing_params.contains(i) {
return Err(Unimplemented); return Err(Unimplemented);

View File

@ -544,7 +544,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}, },
ty::PredicateKind::TypeOutlives(pred) => { ty::PredicateKind::TypeOutlives(pred) => {
if pred.0.is_global() { if pred.0.is_known_global() {
Ok(EvaluatedToOk) Ok(EvaluatedToOk)
} else { } else {
Ok(EvaluatedToOkModuloRegions) Ok(EvaluatedToOkModuloRegions)
@ -598,11 +598,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
} }
} }
ty::PredicateKind::ConstEvaluatable(def_id, substs) => { ty::PredicateKind::ConstEvaluatable(uv) => {
match const_evaluatable::is_const_evaluatable( match const_evaluatable::is_const_evaluatable(
self.infcx, self.infcx,
def_id, uv,
substs,
obligation.param_env, obligation.param_env,
obligation.cause.span, obligation.cause.span,
) { ) {
@ -624,7 +623,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
if let (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) = if let (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) =
(c1.val, c2.val) (c1.val, c2.val)
{ {
if self.infcx.try_unify_abstract_consts(a, b) { if self.infcx.try_unify_abstract_consts(a.shrink(), b.shrink()) {
return Ok(EvaluatedToOk); return Ok(EvaluatedToOk);
} }
} }
@ -692,8 +691,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
debug!(?obligation, "evaluate_trait_predicate_recursively"); debug!(?obligation, "evaluate_trait_predicate_recursively");
if !self.intercrate if !self.intercrate
&& obligation.is_global() && obligation.is_global(self.tcx())
&& obligation.param_env.caller_bounds().iter().all(|bound| bound.needs_subst()) && obligation
.param_env
.caller_bounds()
.iter()
.all(|bound| bound.definitely_needs_subst(self.tcx()))
{ {
// If a param env has no global bounds, global obligations do not // If a param env has no global bounds, global obligations do not
// depend on its particular value in order to work, so we can clear // depend on its particular value in order to work, so we can clear
@ -1452,7 +1455,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// the param_env so that it can be given the lowest priority. See // the param_env so that it can be given the lowest priority. See
// #50825 for the motivation for this. // #50825 for the motivation for this.
let is_global = let is_global =
|cand: &ty::PolyTraitRef<'_>| cand.is_global() && !cand.has_late_bound_regions(); |cand: &ty::PolyTraitRef<'_>| cand.is_known_global() && !cand.has_late_bound_regions();
// (*) Prefer `BuiltinCandidate { has_nested: false }`, `PointeeCandidate`, // (*) Prefer `BuiltinCandidate { has_nested: false }`, `PointeeCandidate`,
// and `DiscriminantKindCandidate` to anything else. // and `DiscriminantKindCandidate` to anything else.

View File

@ -130,6 +130,9 @@ impl Search<'a, 'tcx> {
impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> { impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> {
type BreakTy = NonStructuralMatchTy<'tcx>; type BreakTy = NonStructuralMatchTy<'tcx>;
fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
Some(self.tcx())
}
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
debug!("Search visiting ty: {:?}", ty); debug!("Search visiting ty: {:?}", ty);

View File

@ -132,8 +132,9 @@ pub fn predicate_obligations<'a, 'tcx>(
wf.compute(a.into()); wf.compute(a.into());
wf.compute(b.into()); wf.compute(b.into());
} }
ty::PredicateKind::ConstEvaluatable(def, substs) => { ty::PredicateKind::ConstEvaluatable(uv) => {
let obligations = wf.nominal_obligations(def.did, substs); let substs = uv.substs(wf.tcx());
let obligations = wf.nominal_obligations(uv.def.did, substs);
wf.out.extend(obligations); wf.out.extend(obligations);
for arg in substs.iter() { for arg in substs.iter() {
@ -422,7 +423,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
/// Pushes all the predicates needed to validate that `ty` is WF into `out`. /// Pushes all the predicates needed to validate that `ty` is WF into `out`.
fn compute(&mut self, arg: GenericArg<'tcx>) { fn compute(&mut self, arg: GenericArg<'tcx>) {
let mut walker = arg.walk(); let mut walker = arg.walk(self.tcx());
let param_env = self.param_env; let param_env = self.param_env;
let depth = self.recursion_depth; let depth = self.recursion_depth;
while let Some(arg) = walker.next() { while let Some(arg) = walker.next() {
@ -435,14 +436,17 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
GenericArgKind::Const(constant) => { GenericArgKind::Const(constant) => {
match constant.val { match constant.val {
ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) => { ty::ConstKind::Unevaluated(uv) => {
assert!(promoted.is_none()); assert!(uv.promoted.is_none());
let substs = uv.substs(self.tcx());
let obligations = self.nominal_obligations(def.did, substs); let obligations = self.nominal_obligations(uv.def.did, substs);
self.out.extend(obligations); self.out.extend(obligations);
let predicate = ty::PredicateKind::ConstEvaluatable(def, substs) let predicate = ty::PredicateKind::ConstEvaluatable(
.to_predicate(self.tcx()); ty::Unevaluated::new(uv.def, substs),
)
.to_predicate(self.tcx());
let cause = self.cause(traits::MiscObligation); let cause = self.cause(traits::MiscObligation);
self.out.push(traits::Obligation::with_depth( self.out.push(traits::Obligation::with_depth(
cause, cause,

View File

@ -806,7 +806,7 @@ crate fn collect_bound_vars<'tcx, T: TypeFoldable<'tcx>>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
ty: Binder<'tcx, T>, ty: Binder<'tcx, T>,
) -> (T, chalk_ir::VariableKinds<RustInterner<'tcx>>, BTreeMap<DefId, u32>) { ) -> (T, chalk_ir::VariableKinds<RustInterner<'tcx>>, BTreeMap<DefId, u32>) {
let mut bound_vars_collector = BoundVarsCollector::new(); let mut bound_vars_collector = BoundVarsCollector::new(tcx);
ty.as_ref().skip_binder().visit_with(&mut bound_vars_collector); ty.as_ref().skip_binder().visit_with(&mut bound_vars_collector);
let mut parameters = bound_vars_collector.parameters; let mut parameters = bound_vars_collector.parameters;
let named_parameters: BTreeMap<DefId, u32> = bound_vars_collector let named_parameters: BTreeMap<DefId, u32> = bound_vars_collector
@ -836,14 +836,16 @@ crate fn collect_bound_vars<'tcx, T: TypeFoldable<'tcx>>(
} }
crate struct BoundVarsCollector<'tcx> { crate struct BoundVarsCollector<'tcx> {
tcx: TyCtxt<'tcx>,
binder_index: ty::DebruijnIndex, binder_index: ty::DebruijnIndex,
crate parameters: BTreeMap<u32, chalk_ir::VariableKind<RustInterner<'tcx>>>, crate parameters: BTreeMap<u32, chalk_ir::VariableKind<RustInterner<'tcx>>>,
crate named_parameters: Vec<DefId>, crate named_parameters: Vec<DefId>,
} }
impl<'tcx> BoundVarsCollector<'tcx> { impl<'tcx> BoundVarsCollector<'tcx> {
crate fn new() -> Self { crate fn new(tcx: TyCtxt<'tcx>) -> Self {
BoundVarsCollector { BoundVarsCollector {
tcx,
binder_index: ty::INNERMOST, binder_index: ty::INNERMOST,
parameters: BTreeMap::new(), parameters: BTreeMap::new(),
named_parameters: vec![], named_parameters: vec![],
@ -852,6 +854,10 @@ impl<'tcx> BoundVarsCollector<'tcx> {
} }
impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> { impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> {
fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
Some(self.tcx)
}
fn visit_binder<T: TypeFoldable<'tcx>>( fn visit_binder<T: TypeFoldable<'tcx>>(
&mut self, &mut self,
t: &Binder<'tcx, T>, t: &Binder<'tcx, T>,
@ -1070,6 +1076,11 @@ impl PlaceholdersCollector {
} }
impl<'tcx> TypeVisitor<'tcx> for PlaceholdersCollector { impl<'tcx> TypeVisitor<'tcx> for PlaceholdersCollector {
fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
// Anon const substs do not contain placeholders by default.
None
}
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
match t.kind() { match t.kind() {
ty::Placeholder(p) if p.universe == self.universe_index => { ty::Placeholder(p) if p.universe == self.universe_index => {

View File

@ -54,6 +54,10 @@ impl<'tcx> BoundVarsCollector<'tcx> {
impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> { impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> {
type BreakTy = (); type BreakTy = ();
fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
// Anon const substs do not contain bound vars by default.
None
}
fn visit_binder<T: TypeFoldable<'tcx>>( fn visit_binder<T: TypeFoldable<'tcx>>(
&mut self, &mut self,
t: &Binder<'tcx, T>, t: &Binder<'tcx, T>,

View File

@ -361,7 +361,7 @@ fn well_formed_types_in_env<'tcx>(
// constituents are well-formed. // constituents are well-formed.
NodeKind::InherentImpl => { NodeKind::InherentImpl => {
let self_ty = tcx.type_of(def_id); let self_ty = tcx.type_of(def_id);
inputs.extend(self_ty.walk()); inputs.extend(self_ty.walk(tcx));
} }
// In an fn, we assume that the arguments and all their constituents are // In an fn, we assume that the arguments and all their constituents are
@ -370,7 +370,7 @@ fn well_formed_types_in_env<'tcx>(
let fn_sig = tcx.fn_sig(def_id); let fn_sig = tcx.fn_sig(def_id);
let fn_sig = tcx.liberate_late_bound_regions(def_id, fn_sig); let fn_sig = tcx.liberate_late_bound_regions(def_id, fn_sig);
inputs.extend(fn_sig.inputs().iter().flat_map(|ty| ty.walk())); inputs.extend(fn_sig.inputs().iter().flat_map(|ty| ty.walk(tcx)));
} }
NodeKind::Other => (), NodeKind::Other => (),

View File

@ -19,94 +19,116 @@ bitflags! {
// Does this have parameters? Used to determine whether substitution is // Does this have parameters? Used to determine whether substitution is
// required. // required.
/// Does this have `Param`? /// Does this have `Param`?
const HAS_TY_PARAM = 1 << 0; const HAS_KNOWN_TY_PARAM = 1 << 0;
/// Does this have `ReEarlyBound`? /// Does this have `ReEarlyBound`?
const HAS_RE_PARAM = 1 << 1; const HAS_KNOWN_RE_PARAM = 1 << 1;
/// Does this have `ConstKind::Param`? /// Does this have `ConstKind::Param`?
const HAS_CT_PARAM = 1 << 2; const HAS_KNOWN_CT_PARAM = 1 << 2;
const NEEDS_SUBST = TypeFlags::HAS_TY_PARAM.bits const KNOWN_NEEDS_SUBST = TypeFlags::HAS_KNOWN_TY_PARAM.bits
| TypeFlags::HAS_RE_PARAM.bits | TypeFlags::HAS_KNOWN_RE_PARAM.bits
| TypeFlags::HAS_CT_PARAM.bits; | TypeFlags::HAS_KNOWN_CT_PARAM.bits;
/// Does this have `Infer`? /// Does this have `Infer`?
const HAS_TY_INFER = 1 << 3; const HAS_TY_INFER = 1 << 3;
/// Does this have `ReVar`? /// Does this have `ReVar`?
const HAS_RE_INFER = 1 << 4; const HAS_RE_INFER = 1 << 4;
/// Does this have `ConstKind::Infer`? /// Does this have `ConstKind::Infer`?
const HAS_CT_INFER = 1 << 5; const HAS_CT_INFER = 1 << 5;
/// Does this have inference variables? Used to determine whether /// Does this have inference variables? Used to determine whether
/// inference is required. /// inference is required.
const NEEDS_INFER = TypeFlags::HAS_TY_INFER.bits const NEEDS_INFER = TypeFlags::HAS_TY_INFER.bits
| TypeFlags::HAS_RE_INFER.bits | TypeFlags::HAS_RE_INFER.bits
| TypeFlags::HAS_CT_INFER.bits; | TypeFlags::HAS_CT_INFER.bits;
/// Does this have `Placeholder`? /// Does this have `Placeholder`?
const HAS_TY_PLACEHOLDER = 1 << 6; const HAS_TY_PLACEHOLDER = 1 << 6;
/// Does this have `RePlaceholder`? /// Does this have `RePlaceholder`?
const HAS_RE_PLACEHOLDER = 1 << 7; const HAS_RE_PLACEHOLDER = 1 << 7;
/// Does this have `ConstKind::Placeholder`? /// Does this have `ConstKind::Placeholder`?
const HAS_CT_PLACEHOLDER = 1 << 8; const HAS_CT_PLACEHOLDER = 1 << 8;
/// `true` if there are "names" of regions and so forth /// `true` if there are "names" of regions and so forth
/// that are local to a particular fn/inferctxt /// that are local to a particular fn/inferctxt
const HAS_FREE_LOCAL_REGIONS = 1 << 9; const HAS_KNOWN_FREE_LOCAL_REGIONS = 1 << 9;
/// `true` if there are "names" of types and regions and so forth /// `true` if there are "names" of types and regions and so forth
/// that are local to a particular fn /// that are local to a particular fn
const HAS_FREE_LOCAL_NAMES = TypeFlags::HAS_TY_PARAM.bits const HAS_KNOWN_FREE_LOCAL_NAMES = TypeFlags::HAS_KNOWN_TY_PARAM.bits
| TypeFlags::HAS_CT_PARAM.bits | TypeFlags::HAS_KNOWN_CT_PARAM.bits
| TypeFlags::HAS_TY_INFER.bits | TypeFlags::HAS_TY_INFER.bits
| TypeFlags::HAS_CT_INFER.bits | TypeFlags::HAS_CT_INFER.bits
| TypeFlags::HAS_TY_PLACEHOLDER.bits | TypeFlags::HAS_TY_PLACEHOLDER.bits
| TypeFlags::HAS_CT_PLACEHOLDER.bits | TypeFlags::HAS_CT_PLACEHOLDER.bits
// We consider 'freshened' types and constants // We consider 'freshened' types and constants
// to depend on a particular fn. // to depend on a particular fn.
// The freshening process throws away information, // The freshening process throws away information,
// which can make things unsuitable for use in a global // which can make things unsuitable for use in a global
// cache. Note that there is no 'fresh lifetime' flag - // cache. Note that there is no 'fresh lifetime' flag -
// freshening replaces all lifetimes with `ReErased`, // freshening replaces all lifetimes with `ReErased`,
// which is different from how types/const are freshened. // which is different from how types/const are freshened.
| TypeFlags::HAS_TY_FRESH.bits | TypeFlags::HAS_TY_FRESH.bits
| TypeFlags::HAS_CT_FRESH.bits | TypeFlags::HAS_CT_FRESH.bits
| TypeFlags::HAS_FREE_LOCAL_REGIONS.bits; | TypeFlags::HAS_KNOWN_FREE_LOCAL_REGIONS.bits;
const HAS_POTENTIAL_FREE_LOCAL_NAMES = TypeFlags::HAS_KNOWN_FREE_LOCAL_NAMES.bits
| TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS.bits;
/// Does this have `Projection`? /// Does this have `Projection`?
const HAS_TY_PROJECTION = 1 << 10; const HAS_TY_PROJECTION = 1 << 10;
/// Does this have `Opaque`? /// Does this have `Opaque`?
const HAS_TY_OPAQUE = 1 << 11; const HAS_TY_OPAQUE = 1 << 11;
/// Does this have `ConstKind::Unevaluated`? /// Does this have `ConstKind::Unevaluated`?
const HAS_CT_PROJECTION = 1 << 12; const HAS_CT_PROJECTION = 1 << 12;
/// Could this type be normalized further? /// Could this type be normalized further?
const HAS_PROJECTION = TypeFlags::HAS_TY_PROJECTION.bits const HAS_PROJECTION = TypeFlags::HAS_TY_PROJECTION.bits
| TypeFlags::HAS_TY_OPAQUE.bits | TypeFlags::HAS_TY_OPAQUE.bits
| TypeFlags::HAS_CT_PROJECTION.bits; | TypeFlags::HAS_CT_PROJECTION.bits;
/// Is an error type/const reachable? /// Is an error type/const reachable?
const HAS_ERROR = 1 << 13; const HAS_ERROR = 1 << 13;
/// Does this have any region that "appears free" in the type? /// Does this have any region that "appears free" in the type?
/// Basically anything but `ReLateBound` and `ReErased`. /// Basically anything but `ReLateBound` and `ReErased`.
const HAS_FREE_REGIONS = 1 << 14; const HAS_KNOWN_FREE_REGIONS = 1 << 14;
const HAS_POTENTIAL_FREE_REGIONS = TypeFlags::HAS_KNOWN_FREE_REGIONS.bits
| TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS.bits;
/// Does this have any `ReLateBound` regions? Used to check /// Does this have any `ReLateBound` regions? Used to check
/// if a global bound is safe to evaluate. /// if a global bound is safe to evaluate.
const HAS_RE_LATE_BOUND = 1 << 15; const HAS_RE_LATE_BOUND = 1 << 15;
/// Does this have any `ReErased` regions? /// Does this have any `ReErased` regions?
const HAS_RE_ERASED = 1 << 16; const HAS_RE_ERASED = 1 << 16;
/// Does this value have parameters/placeholders/inference variables which could be /// Does this value have parameters/placeholders/inference variables which could be
/// replaced later, in a way that would change the results of `impl` specialization? /// replaced later, in a way that would change the results of `impl` specialization?
const STILL_FURTHER_SPECIALIZABLE = 1 << 17; ///
/// Note that this flag being set is not a guarantee, as it is also
/// set if there are any anon consts with unknown default substs.
const STILL_FURTHER_SPECIALIZABLE = 1 << 17;
/// Does this value have `InferTy::FreshTy/FreshIntTy/FreshFloatTy`? /// Does this value have `InferTy::FreshTy/FreshIntTy/FreshFloatTy`?
const HAS_TY_FRESH = 1 << 18; const HAS_TY_FRESH = 1 << 18;
/// Does this value have `InferConst::Fresh`? /// Does this value have `InferConst::Fresh`?
const HAS_CT_FRESH = 1 << 19; const HAS_CT_FRESH = 1 << 19;
/// Does this value have unknown default anon const substs.
///
/// For more details refer to...
/// FIXME(@lcnr): ask me for now, still have to write all of this.
const HAS_UNKNOWN_DEFAULT_CONST_SUBSTS = 1 << 20;
/// Flags which can be influenced by default anon const substs.
const MAY_NEED_DEFAULT_CONST_SUBSTS = TypeFlags::HAS_KNOWN_RE_PARAM.bits
| TypeFlags::HAS_KNOWN_TY_PARAM.bits
| TypeFlags::HAS_KNOWN_CT_PARAM.bits
| TypeFlags::HAS_KNOWN_FREE_LOCAL_REGIONS.bits
| TypeFlags::HAS_KNOWN_FREE_REGIONS.bits;
} }
} }

View File

@ -394,7 +394,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
if self.is_object && has_default { if self.is_object && has_default {
let default_ty = tcx.at(self.span).type_of(param.def_id); let default_ty = tcx.at(self.span).type_of(param.def_id);
let self_param = tcx.types.self_param; let self_param = tcx.types.self_param;
if default_ty.walk().any(|arg| arg == self_param.into()) { if default_ty.walk(tcx).any(|arg| arg == self_param.into()) {
// There is no suitable inference default for a type parameter // There is no suitable inference default for a type parameter
// that references self, in an object type. // that references self, in an object type.
return true; return true;
@ -1354,7 +1354,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// A `Self` within the original bound will be substituted with a // A `Self` within the original bound will be substituted with a
// `trait_object_dummy_self`, so check for that. // `trait_object_dummy_self`, so check for that.
let references_self = let references_self =
pred.skip_binder().ty.walk().any(|arg| arg == dummy_self.into()); pred.skip_binder().ty.walk(tcx).any(|arg| arg == dummy_self.into());
// If the projection output contains `Self`, force the user to // If the projection output contains `Self`, force the user to
// elaborate it explicitly to avoid a lot of complexity. // elaborate it explicitly to avoid a lot of complexity.
@ -2204,7 +2204,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
self.prohibit_generics(path.segments); self.prohibit_generics(path.segments);
// Try to evaluate any array length constants. // Try to evaluate any array length constants.
let normalized_ty = self.normalize_ty(span, tcx.at(span).type_of(def_id)); let normalized_ty = self.normalize_ty(span, tcx.at(span).type_of(def_id));
if forbid_generic && normalized_ty.needs_subst() { if forbid_generic && normalized_ty.definitely_needs_subst(tcx) {
let mut err = tcx.sess.struct_span_err( let mut err = tcx.sess.struct_span_err(
path.span, path.span,
"generic `Self` types are currently not permitted in anonymous constants", "generic `Self` types are currently not permitted in anonymous constants",

View File

@ -470,14 +470,17 @@ pub(super) fn check_opaque_for_inheriting_lifetimes(
debug!(?item, ?span); debug!(?item, ?span);
struct FoundParentLifetime; struct FoundParentLifetime;
struct FindParentLifetimeVisitor<'tcx>(&'tcx ty::Generics); struct FindParentLifetimeVisitor<'tcx>(TyCtxt<'tcx>, &'tcx ty::Generics);
impl<'tcx> ty::fold::TypeVisitor<'tcx> for FindParentLifetimeVisitor<'tcx> { impl<'tcx> ty::fold::TypeVisitor<'tcx> for FindParentLifetimeVisitor<'tcx> {
type BreakTy = FoundParentLifetime; type BreakTy = FoundParentLifetime;
fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
Some(self.0)
}
fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
debug!("FindParentLifetimeVisitor: r={:?}", r); debug!("FindParentLifetimeVisitor: r={:?}", r);
if let RegionKind::ReEarlyBound(ty::EarlyBoundRegion { index, .. }) = r { if let RegionKind::ReEarlyBound(ty::EarlyBoundRegion { index, .. }) = r {
if *index < self.0.parent_count as u32 { if *index < self.1.parent_count as u32 {
return ControlFlow::Break(FoundParentLifetime); return ControlFlow::Break(FoundParentLifetime);
} else { } else {
return ControlFlow::CONTINUE; return ControlFlow::CONTINUE;
@ -499,21 +502,24 @@ pub(super) fn check_opaque_for_inheriting_lifetimes(
} }
struct ProhibitOpaqueVisitor<'tcx> { struct ProhibitOpaqueVisitor<'tcx> {
tcx: TyCtxt<'tcx>,
opaque_identity_ty: Ty<'tcx>, opaque_identity_ty: Ty<'tcx>,
generics: &'tcx ty::Generics, generics: &'tcx ty::Generics,
tcx: TyCtxt<'tcx>,
selftys: Vec<(Span, Option<String>)>, selftys: Vec<(Span, Option<String>)>,
} }
impl<'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueVisitor<'tcx> { impl<'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueVisitor<'tcx> {
type BreakTy = Ty<'tcx>; type BreakTy = Ty<'tcx>;
fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
Some(self.tcx)
}
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
debug!("check_opaque_for_inheriting_lifetimes: (visit_ty) t={:?}", t); debug!("check_opaque_for_inheriting_lifetimes: (visit_ty) t={:?}", t);
if t == self.opaque_identity_ty { if t == self.opaque_identity_ty {
ControlFlow::CONTINUE ControlFlow::CONTINUE
} else { } else {
t.super_visit_with(&mut FindParentLifetimeVisitor(self.generics)) t.super_visit_with(&mut FindParentLifetimeVisitor(self.tcx, self.generics))
.map_break(|FoundParentLifetime| t) .map_break(|FoundParentLifetime| t)
} }
} }
@ -1476,7 +1482,7 @@ pub(super) fn check_type_params_are_used<'tcx>(
return; return;
} }
for leaf in ty.walk() { for leaf in ty.walk(tcx) {
if let GenericArgKind::Type(leaf_ty) = leaf.unpack() { if let GenericArgKind::Type(leaf_ty) = leaf.unpack() {
if let ty::Param(param) = leaf_ty.kind() { if let ty::Param(param) = leaf_ty.kind() {
debug!("found use of ty param {:?}", param); debug!("found use of ty param {:?}", param);
@ -1578,8 +1584,12 @@ fn opaque_type_cycle_error(tcx: TyCtxt<'tcx>, def_id: LocalDefId, span: Span) {
.filter_map(|e| typeck_results.node_type_opt(e.hir_id).map(|t| (e.span, t))) .filter_map(|e| typeck_results.node_type_opt(e.hir_id).map(|t| (e.span, t)))
.filter(|(_, ty)| !matches!(ty.kind(), ty::Never)) .filter(|(_, ty)| !matches!(ty.kind(), ty::Never))
{ {
struct VisitTypes(Vec<DefId>); struct OpaqueTypeCollector(Vec<DefId>);
impl<'tcx> ty::fold::TypeVisitor<'tcx> for VisitTypes { impl<'tcx> ty::fold::TypeVisitor<'tcx> for OpaqueTypeCollector {
fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
// Default anon const substs cannot contain opaque types.
None
}
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
match *t.kind() { match *t.kind() {
ty::Opaque(def, _) => { ty::Opaque(def, _) => {
@ -1590,7 +1600,7 @@ fn opaque_type_cycle_error(tcx: TyCtxt<'tcx>, def_id: LocalDefId, span: Span) {
} }
} }
} }
let mut visitor = VisitTypes(vec![]); let mut visitor = OpaqueTypeCollector(vec![]);
ty.visit_with(&mut visitor); ty.visit_with(&mut visitor);
for def_id in visitor.0 { for def_id in visitor.0 {
let ty_span = tcx.def_span(def_id); let ty_span = tcx.def_span(def_id);

View File

@ -236,9 +236,9 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
relator.relate(predicate.rebind(a), p.rebind(b)).is_ok() relator.relate(predicate.rebind(a), p.rebind(b)).is_ok()
} }
( (
ty::PredicateKind::ConstEvaluatable(def_a, substs_a), ty::PredicateKind::ConstEvaluatable(a),
ty::PredicateKind::ConstEvaluatable(def_b, substs_b), ty::PredicateKind::ConstEvaluatable(b),
) => tcx.try_unify_abstract_consts(((def_a, substs_a), (def_b, substs_b))), ) => tcx.try_unify_abstract_consts((a, b)),
(ty::PredicateKind::TypeOutlives(a), ty::PredicateKind::TypeOutlives(b)) => { (ty::PredicateKind::TypeOutlives(a), ty::PredicateKind::TypeOutlives(b)) => {
relator.relate(predicate.rebind(a.0), p.rebind(b.0)).is_ok() relator.relate(predicate.rebind(a.0), p.rebind(b.0)).is_ok()
} }

View File

@ -239,7 +239,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.tag(), self.tag(),
); );
if Self::can_contain_user_lifetime_bounds((substs, user_self_ty)) { if self.can_contain_user_lifetime_bounds((substs, user_self_ty)) {
let canonicalized = self.infcx.canonicalize_user_type_annotation(UserType::TypeOf( let canonicalized = self.infcx.canonicalize_user_type_annotation(UserType::TypeOf(
def_id, def_id,
UserSubsts { substs, user_self_ty }, UserSubsts { substs, user_self_ty },
@ -481,7 +481,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let ty = self.to_ty(ast_ty); let ty = self.to_ty(ast_ty);
debug!("to_ty_saving_user_provided_ty: ty={:?}", ty); debug!("to_ty_saving_user_provided_ty: ty={:?}", ty);
if Self::can_contain_user_lifetime_bounds(ty) { if self.can_contain_user_lifetime_bounds(ty) {
let c_ty = self.infcx.canonicalize_response(UserType::Ty(ty)); let c_ty = self.infcx.canonicalize_response(UserType::Ty(ty));
debug!("to_ty_saving_user_provided_ty: c_ty={:?}", c_ty); debug!("to_ty_saving_user_provided_ty: c_ty={:?}", c_ty);
self.typeck_results.borrow_mut().user_provided_types_mut().insert(ast_ty.hir_id, c_ty); self.typeck_results.borrow_mut().user_provided_types_mut().insert(ast_ty.hir_id, c_ty);
@ -526,11 +526,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// reader, although I have my doubts). Also pass in types with inference // reader, although I have my doubts). Also pass in types with inference
// types, because they may be repeated. Other sorts of things are already // types, because they may be repeated. Other sorts of things are already
// sufficiently enforced with erased regions. =) // sufficiently enforced with erased regions. =)
fn can_contain_user_lifetime_bounds<T>(t: T) -> bool fn can_contain_user_lifetime_bounds<T>(&self, t: T) -> bool
where where
T: TypeFoldable<'tcx>, T: TypeFoldable<'tcx>,
{ {
t.has_free_regions() || t.has_projections() || t.has_infer_types() t.has_free_regions(self.tcx) || t.has_projections() || t.has_infer_types()
} }
pub fn node_ty(&self, id: hir::HirId) -> Ty<'tcx> { pub fn node_ty(&self, id: hir::HirId) -> Ty<'tcx> {

View File

@ -937,7 +937,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let ty = self.resolve_vars_if_possible(ty); let ty = self.resolve_vars_if_possible(ty);
// We walk the argument type because the argument's type could have // We walk the argument type because the argument's type could have
// been `Option<T>`, but the `FulfillmentError` references `T`. // been `Option<T>`, but the `FulfillmentError` references `T`.
if ty.walk().any(|arg| arg == predicate.self_ty().into()) { if ty.walk(self.tcx).any(|arg| arg == predicate.self_ty().into()) {
Some(i) Some(i)
} else { } else {
None None

View File

@ -428,7 +428,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} }
} }
if let Some(missing_trait) = missing_trait { if let Some(missing_trait) = missing_trait {
let mut visitor = TypeParamVisitor(vec![]); let mut visitor = TypeParamVisitor(self.tcx, vec![]);
visitor.visit_ty(lhs_ty); visitor.visit_ty(lhs_ty);
if op.node == hir::BinOpKind::Add if op.node == hir::BinOpKind::Add
@ -439,7 +439,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// This has nothing here because it means we did string // This has nothing here because it means we did string
// concatenation (e.g., "Hello " + "World!"). This means // concatenation (e.g., "Hello " + "World!"). This means
// we don't want the note in the else clause to be emitted // we don't want the note in the else clause to be emitted
} else if let [ty] = &visitor.0[..] { } else if let [ty] = &visitor.1[..] {
if let ty::Param(p) = *ty.kind() { if let ty::Param(p) = *ty.kind() {
// Check if the method would be found if the type param wasn't // Check if the method would be found if the type param wasn't
// involved. If so, it means that adding a trait bound to the param is // involved. If so, it means that adding a trait bound to the param is
@ -1003,12 +1003,15 @@ fn suggest_constraining_param(
} }
} }
struct TypeParamVisitor<'tcx>(Vec<Ty<'tcx>>); struct TypeParamVisitor<'tcx>(TyCtxt<'tcx>, Vec<Ty<'tcx>>);
impl<'tcx> TypeVisitor<'tcx> for TypeParamVisitor<'tcx> { impl<'tcx> TypeVisitor<'tcx> for TypeParamVisitor<'tcx> {
fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
Some(self.0)
}
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
if let ty::Param(_) = ty.kind() { if let ty::Param(_) = ty.kind() {
self.0.push(ty); self.1.push(ty);
} }
ty.super_visit_with(self) ty.super_visit_with(self)
} }

View File

@ -541,10 +541,10 @@ fn check_type_defn<'tcx, F>(
fcx.register_predicate(traits::Obligation::new( fcx.register_predicate(traits::Obligation::new(
cause, cause,
fcx.param_env, fcx.param_env,
ty::PredicateKind::ConstEvaluatable( ty::PredicateKind::ConstEvaluatable(ty::Unevaluated::new(
ty::WithOptConstParam::unknown(discr_def_id.to_def_id()), ty::WithOptConstParam::unknown(discr_def_id.to_def_id()),
discr_substs, discr_substs,
) ))
.to_predicate(tcx), .to_predicate(tcx),
)); ));
} }
@ -746,7 +746,7 @@ fn check_where_clauses<'tcx, 'fcx>(
// Ignore dependent defaults -- that is, where the default of one type // Ignore dependent defaults -- that is, where the default of one type
// parameter includes another (e.g., `<T, U = T>`). In those cases, we can't // parameter includes another (e.g., `<T, U = T>`). In those cases, we can't
// be sure if it will error or not as user might always specify the other. // be sure if it will error or not as user might always specify the other.
if !ty.needs_subst() { if !ty.definitely_needs_subst(tcx) {
fcx.register_wf_obligation( fcx.register_wf_obligation(
ty.into(), ty.into(),
tcx.def_span(param.def_id), tcx.def_span(param.def_id),
@ -762,7 +762,7 @@ fn check_where_clauses<'tcx, 'fcx>(
// for `struct Foo<const N: usize, const M: usize = { 1 - 2 }>` // for `struct Foo<const N: usize, const M: usize = { 1 - 2 }>`
// we should eagerly error. // we should eagerly error.
let default_ct = tcx.const_param_default(param.def_id); let default_ct = tcx.const_param_default(param.def_id);
if !default_ct.needs_subst() { if !default_ct.definitely_needs_subst(tcx) {
fcx.register_wf_obligation( fcx.register_wf_obligation(
default_ct.into(), default_ct.into(),
tcx.def_span(param.def_id), tcx.def_span(param.def_id),
@ -796,7 +796,7 @@ fn check_where_clauses<'tcx, 'fcx>(
if is_our_default(param) { if is_our_default(param) {
let default_ty = tcx.type_of(param.def_id); let default_ty = tcx.type_of(param.def_id);
// ... and it's not a dependent default, ... // ... and it's not a dependent default, ...
if !default_ty.needs_subst() { if !default_ty.definitely_needs_subst(tcx) {
// ... then substitute it with the default. // ... then substitute it with the default.
return default_ty.into(); return default_ty.into();
} }
@ -809,7 +809,7 @@ fn check_where_clauses<'tcx, 'fcx>(
if is_our_default(param) { if is_our_default(param) {
let default_ct = tcx.const_param_default(param.def_id); let default_ct = tcx.const_param_default(param.def_id);
// ... and it's not a dependent default, ... // ... and it's not a dependent default, ...
if !default_ct.needs_subst() { if !default_ct.definitely_needs_subst(tcx) {
// ... then substitute it with the default. // ... then substitute it with the default.
return default_ct.into(); return default_ct.into();
} }
@ -825,12 +825,15 @@ fn check_where_clauses<'tcx, 'fcx>(
.predicates .predicates
.iter() .iter()
.flat_map(|&(pred, sp)| { .flat_map(|&(pred, sp)| {
#[derive(Default)] struct CountParams<'tcx> {
struct CountParams { tcx: TyCtxt<'tcx>,
params: FxHashSet<u32>, params: FxHashSet<u32>,
} }
impl<'tcx> ty::fold::TypeVisitor<'tcx> for CountParams { impl<'tcx> ty::fold::TypeVisitor<'tcx> for CountParams<'tcx> {
type BreakTy = (); type BreakTy = ();
fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
Some(self.tcx)
}
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
if let ty::Param(param) = t.kind() { if let ty::Param(param) = t.kind() {
@ -850,12 +853,12 @@ fn check_where_clauses<'tcx, 'fcx>(
c.super_visit_with(self) c.super_visit_with(self)
} }
} }
let mut param_count = CountParams::default(); let mut param_count = CountParams { tcx: fcx.tcx, params: FxHashSet::default() };
let has_region = pred.visit_with(&mut param_count).is_break(); let has_region = pred.visit_with(&mut param_count).is_break();
let substituted_pred = pred.subst(tcx, substs); let substituted_pred = pred.subst(tcx, substs);
// Don't check non-defaulted params, dependent defaults (including lifetimes) // Don't check non-defaulted params, dependent defaults (including lifetimes)
// or preds with multiple params. // or preds with multiple params.
if substituted_pred.has_param_types_or_consts() if substituted_pred.definitely_has_param_types_or_consts(tcx)
|| param_count.params.len() > 1 || param_count.params.len() > 1
|| has_region || has_region
{ {
@ -1377,7 +1380,7 @@ fn check_false_global_bounds(fcx: &FnCtxt<'_, '_>, span: Span, id: hir::HirId) {
for obligation in implied_obligations { for obligation in implied_obligations {
let pred = obligation.predicate; let pred = obligation.predicate;
// Match the existing behavior. // Match the existing behavior.
if pred.is_global() && !pred.has_late_bound_regions() { if pred.is_global(fcx.tcx) && !pred.has_late_bound_regions() {
let pred = fcx.normalize_associated_types_in(span, pred); let pred = fcx.normalize_associated_types_in(span, pred);
let obligation = traits::Obligation::new( let obligation = traits::Obligation::new(
traits::ObligationCause::new(span, id, traits::TrivialBound), traits::ObligationCause::new(span, id, traits::TrivialBound),

View File

@ -130,7 +130,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
fn write_ty_to_typeck_results(&mut self, hir_id: hir::HirId, ty: Ty<'tcx>) { fn write_ty_to_typeck_results(&mut self, hir_id: hir::HirId, ty: Ty<'tcx>) {
debug!("write_ty_to_typeck_results({:?}, {:?})", hir_id, ty); debug!("write_ty_to_typeck_results({:?}, {:?})", hir_id, ty);
assert!(!ty.needs_infer() && !ty.has_placeholders() && !ty.has_free_regions()); assert!(!ty.needs_infer() && !ty.has_placeholders() && !ty.has_free_regions(self.tcx()));
self.typeck_results.node_types_mut().insert(hir_id, ty); self.typeck_results.node_types_mut().insert(hir_id, ty);
} }

View File

@ -68,6 +68,7 @@ fn collect_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
pub fn provide(providers: &mut Providers) { pub fn provide(providers: &mut Providers) {
*providers = Providers { *providers = Providers {
opt_const_param_of: type_of::opt_const_param_of, opt_const_param_of: type_of::opt_const_param_of,
default_anon_const_substs: type_of::default_anon_const_substs,
type_of: type_of::type_of, type_of: type_of::type_of,
item_bounds: item_bounds::item_bounds, item_bounds: item_bounds::item_bounds,
explicit_item_bounds: item_bounds::explicit_item_bounds, explicit_item_bounds: item_bounds::explicit_item_bounds,
@ -2320,7 +2321,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
tcx, tcx,
&mut predicates, &mut predicates,
trait_ref, trait_ref,
&mut cgp::parameters_for_impl(self_ty, trait_ref), &mut cgp::parameters_for_impl(tcx, self_ty, trait_ref),
); );
} }
@ -2355,7 +2356,7 @@ fn const_evaluatable_predicates_of<'tcx>(
assert_eq!(uv.promoted, None); assert_eq!(uv.promoted, None);
let span = self.tcx.hir().span(c.hir_id); let span = self.tcx.hir().span(c.hir_id);
self.preds.insert(( self.preds.insert((
ty::PredicateKind::ConstEvaluatable(uv.def, uv.substs).to_predicate(self.tcx), ty::PredicateKind::ConstEvaluatable(uv.shrink()).to_predicate(self.tcx),
span, span,
)); ));
} }

View File

@ -7,7 +7,7 @@ use rustc_hir::intravisit;
use rustc_hir::intravisit::Visitor; use rustc_hir::intravisit::Visitor;
use rustc_hir::{HirId, Node}; use rustc_hir::{HirId, Node};
use rustc_middle::hir::map::Map; use rustc_middle::hir::map::Map;
use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts}; use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, SubstsRef};
use rustc_middle::ty::util::IntTypeExt; use rustc_middle::ty::util::IntTypeExt;
use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable, TypeFolder}; use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable, TypeFolder};
use rustc_span::symbol::Ident; use rustc_span::symbol::Ident;
@ -274,6 +274,31 @@ fn get_path_containing_arg_in_pat<'hir>(
arg_path arg_path
} }
pub(super) fn default_anon_const_substs(tcx: TyCtxt<'_>, def_id: DefId) -> SubstsRef<'_> {
let generics = tcx.generics_of(def_id);
if let Some(parent) = generics.parent {
// This is the reason we bother with having optional anon const substs.
//
// In the future the substs of an anon const will depend on its parents predicates
// at which point eagerly looking at them will cause a query cycle.
//
// So for now this is only an assurance that this approach won't cause cycle errors in
// the future.
let _cycle_check = tcx.predicates_of(parent);
}
let substs = InternalSubsts::identity_for_item(tcx, def_id);
// We only expect substs with the following type flags as default substs.
//
// Getting this wrong can lead to ICE and unsoundness, so we assert it here.
for arg in substs.iter() {
let allowed_flags = ty::TypeFlags::MAY_NEED_DEFAULT_CONST_SUBSTS
| ty::TypeFlags::STILL_FURTHER_SPECIALIZABLE;
assert!(!arg.has_type_flags(!allowed_flags));
}
substs
}
pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
let def_id = def_id.expect_local(); let def_id = def_id.expect_local();
use rustc_hir::*; use rustc_hir::*;

View File

@ -27,12 +27,13 @@ impl From<ty::ParamConst> for Parameter {
/// Returns the set of parameters constrained by the impl header. /// Returns the set of parameters constrained by the impl header.
pub fn parameters_for_impl<'tcx>( pub fn parameters_for_impl<'tcx>(
tcx: TyCtxt<'tcx>,
impl_self_ty: Ty<'tcx>, impl_self_ty: Ty<'tcx>,
impl_trait_ref: Option<ty::TraitRef<'tcx>>, impl_trait_ref: Option<ty::TraitRef<'tcx>>,
) -> FxHashSet<Parameter> { ) -> FxHashSet<Parameter> {
let vec = match impl_trait_ref { let vec = match impl_trait_ref {
Some(tr) => parameters_for(&tr, false), Some(tr) => parameters_for(tcx, &tr, false),
None => parameters_for(&impl_self_ty, false), None => parameters_for(tcx, &impl_self_ty, false),
}; };
vec.into_iter().collect() vec.into_iter().collect()
} }
@ -43,20 +44,26 @@ pub fn parameters_for_impl<'tcx>(
/// of parameters whose values are needed in order to constrain `ty` - these /// of parameters whose values are needed in order to constrain `ty` - these
/// differ, with the latter being a superset, in the presence of projections. /// differ, with the latter being a superset, in the presence of projections.
pub fn parameters_for<'tcx>( pub fn parameters_for<'tcx>(
tcx: TyCtxt<'tcx>,
t: &impl TypeFoldable<'tcx>, t: &impl TypeFoldable<'tcx>,
include_nonconstraining: bool, include_nonconstraining: bool,
) -> Vec<Parameter> { ) -> Vec<Parameter> {
let mut collector = ParameterCollector { parameters: vec![], include_nonconstraining }; let mut collector = ParameterCollector { tcx, parameters: vec![], include_nonconstraining };
t.visit_with(&mut collector); t.visit_with(&mut collector);
collector.parameters collector.parameters
} }
struct ParameterCollector { struct ParameterCollector<'tcx> {
tcx: TyCtxt<'tcx>,
parameters: Vec<Parameter>, parameters: Vec<Parameter>,
include_nonconstraining: bool, include_nonconstraining: bool,
} }
impl<'tcx> TypeVisitor<'tcx> for ParameterCollector { impl<'tcx> TypeVisitor<'tcx> for ParameterCollector<'tcx> {
fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
Some(self.tcx)
}
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
match *t.kind() { match *t.kind() {
ty::Projection(..) | ty::Opaque(..) if !self.include_nonconstraining => { ty::Projection(..) | ty::Opaque(..) if !self.include_nonconstraining => {
@ -198,12 +205,12 @@ pub fn setup_constraining_predicates<'tcx>(
// `<<T as Bar>::Baz as Iterator>::Output = <U as Iterator>::Output` // `<<T as Bar>::Baz as Iterator>::Output = <U as Iterator>::Output`
// Then the projection only applies if `T` is known, but it still // Then the projection only applies if `T` is known, but it still
// does not determine `U`. // does not determine `U`.
let inputs = parameters_for(&projection.projection_ty, true); let inputs = parameters_for(tcx, &projection.projection_ty, true);
let relies_only_on_inputs = inputs.iter().all(|p| input_parameters.contains(&p)); let relies_only_on_inputs = inputs.iter().all(|p| input_parameters.contains(&p));
if !relies_only_on_inputs { if !relies_only_on_inputs {
continue; continue;
} }
input_parameters.extend(parameters_for(&projection.ty, false)); input_parameters.extend(parameters_for(tcx, &projection.ty, false));
} else { } else {
continue; continue;
} }

View File

@ -119,7 +119,7 @@ fn enforce_impl_params_are_constrained(
let impl_predicates = tcx.predicates_of(impl_def_id); let impl_predicates = tcx.predicates_of(impl_def_id);
let impl_trait_ref = tcx.impl_trait_ref(impl_def_id); let impl_trait_ref = tcx.impl_trait_ref(impl_def_id);
let mut input_parameters = cgp::parameters_for_impl(impl_self_ty, impl_trait_ref); let mut input_parameters = cgp::parameters_for_impl(tcx, impl_self_ty, impl_trait_ref);
cgp::identify_constrained_generic_params( cgp::identify_constrained_generic_params(
tcx, tcx,
impl_predicates, impl_predicates,
@ -136,7 +136,7 @@ fn enforce_impl_params_are_constrained(
match item.kind { match item.kind {
ty::AssocKind::Type => { ty::AssocKind::Type => {
if item.defaultness.has_value() { if item.defaultness.has_value() {
cgp::parameters_for(&tcx.type_of(def_id), true) cgp::parameters_for(tcx, &tcx.type_of(def_id), true)
} else { } else {
Vec::new() Vec::new()
} }

View File

@ -207,15 +207,15 @@ fn unconstrained_parent_impl_substs<'tcx>(
continue; continue;
} }
unconstrained_parameters.extend(cgp::parameters_for(&projection_ty, true)); unconstrained_parameters.extend(cgp::parameters_for(tcx, &projection_ty, true));
for param in cgp::parameters_for(&projected_ty, false) { for param in cgp::parameters_for(tcx, &projected_ty, false) {
if !unconstrained_parameters.contains(&param) { if !unconstrained_parameters.contains(&param) {
constrained_params.insert(param.0); constrained_params.insert(param.0);
} }
} }
unconstrained_parameters.extend(cgp::parameters_for(&projected_ty, true)); unconstrained_parameters.extend(cgp::parameters_for(tcx, &projected_ty, true));
} }
} }
@ -249,7 +249,7 @@ fn check_duplicate_params<'tcx>(
parent_substs: &Vec<GenericArg<'tcx>>, parent_substs: &Vec<GenericArg<'tcx>>,
span: Span, span: Span,
) { ) {
let mut base_params = cgp::parameters_for(parent_substs, true); let mut base_params = cgp::parameters_for(tcx, parent_substs, true);
base_params.sort_by_key(|param| param.0); base_params.sort_by_key(|param| param.0);
if let (_, [duplicate, ..]) = base_params.partition_dedup() { if let (_, [duplicate, ..]) = base_params.partition_dedup() {
let param = impl1_substs[duplicate.0 as usize]; let param = impl1_substs[duplicate.0 as usize];
@ -363,7 +363,7 @@ fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tc
match predicate.kind().skip_binder() { match predicate.kind().skip_binder() {
// Global predicates are either always true or always false, so we // Global predicates are either always true or always false, so we
// are fine to specialize on. // are fine to specialize on.
_ if predicate.is_global() => (), _ if predicate.is_global(tcx) => (),
// We allow specializing on explicitly marked traits with no associated // We allow specializing on explicitly marked traits with no associated
// items. // items.
ty::PredicateKind::Trait(ty::TraitPredicate { ty::PredicateKind::Trait(ty::TraitPredicate {

View File

@ -114,7 +114,18 @@ fn insert_required_predicates_to_be_wf<'tcx>(
required_predicates: &mut RequiredPredicates<'tcx>, required_predicates: &mut RequiredPredicates<'tcx>,
explicit_map: &mut ExplicitPredicatesMap<'tcx>, explicit_map: &mut ExplicitPredicatesMap<'tcx>,
) { ) {
for arg in field_ty.walk() { // We must not look into the default substs of consts
// as computing those depends on the results of `predicates_of`.
//
// Luckily the only types contained in default substs are type
// parameters which don't matter here.
//
// FIXME(const_generics): Once more complex const parameter types
// are allowed, this might be incorrect. I think that we will still be
// fine, as all outlives relations of the const param types should also
// be part of the adt containing it, but we should still both update the
// documentation and add some tests for this.
for arg in field_ty.walk_ignoring_default_const_substs() {
let ty = match arg.unpack() { let ty = match arg.unpack() {
GenericArgKind::Type(ty) => ty, GenericArgKind::Type(ty) => ty,
@ -306,7 +317,7 @@ pub fn check_explicit_predicates<'tcx>(
// 'b`. // 'b`.
if let Some(self_ty) = ignored_self_ty { if let Some(self_ty) = ignored_self_ty {
if let GenericArgKind::Type(ty) = outlives_predicate.0.unpack() { if let GenericArgKind::Type(ty) = outlives_predicate.0.unpack() {
if ty.walk().any(|arg| arg == self_ty.into()) { if ty.walk(tcx).any(|arg| arg == self_ty.into()) {
debug!("skipping self ty = {:?}", &ty); debug!("skipping self ty = {:?}", &ty);
continue; continue;
} }

View File

@ -287,7 +287,7 @@ crate fn name_from_pat(p: &hir::Pat<'_>) -> Symbol {
crate fn print_const(cx: &DocContext<'_>, n: &'tcx ty::Const<'_>) -> String { crate fn print_const(cx: &DocContext<'_>, n: &'tcx ty::Const<'_>) -> String {
match n.val { match n.val {
ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs: _, promoted }) => { ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs_: _, promoted }) => {
let mut s = if let Some(def) = def.as_local() { let mut s = if let Some(def) = def.as_local() {
let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def.did); let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def.did);
print_const_expr(cx.tcx, cx.tcx.hir().body_owned_by(hir_id)) print_const_expr(cx.tcx, cx.tcx.hir().body_owned_by(hir_id))

View File

@ -30,7 +30,7 @@
- _3 = [move _4]; // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35 - _3 = [move _4]; // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35
- _2 = &_3; // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35 - _2 = &_3; // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35
+ // + span: $DIR/const-promotion-extern-static.rs:9:31: 9:35 + // + span: $DIR/const-promotion-extern-static.rs:9:31: 9:35
+ // + literal: Const { ty: &[&i32; 1], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:6 ~ const_promotion_extern_static[55e6]::BAR), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } + // + literal: Const { ty: &[&i32; 1], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:6 ~ const_promotion_extern_static[55e6]::BAR), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
+ _2 = &(*_6); // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35 + _2 = &(*_6); // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35
_1 = move _2 as &[&i32] (Pointer(Unsize)); // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35 _1 = move _2 as &[&i32] (Pointer(Unsize)); // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35
- StorageDead(_4); // scope 0 at $DIR/const-promotion-extern-static.rs:9:34: 9:35 - StorageDead(_4); // scope 0 at $DIR/const-promotion-extern-static.rs:9:34: 9:35

View File

@ -32,7 +32,7 @@
- _3 = [move _4]; // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 - _3 = [move _4]; // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
- _2 = &_3; // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 - _2 = &_3; // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
+ // + span: $DIR/const-promotion-extern-static.rs:13:31: 13:46 + // + span: $DIR/const-promotion-extern-static.rs:13:31: 13:46
+ // + literal: Const { ty: &[&i32; 1], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:7 ~ const_promotion_extern_static[55e6]::FOO), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } + // + literal: Const { ty: &[&i32; 1], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:7 ~ const_promotion_extern_static[55e6]::FOO), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
+ _2 = &(*_6); // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 + _2 = &(*_6); // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
_1 = move _2 as &[&i32] (Pointer(Unsize)); // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 _1 = move _2 as &[&i32] (Pointer(Unsize)); // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
- StorageDead(_4); // scope 0 at $DIR/const-promotion-extern-static.rs:13:45: 13:46 - StorageDead(_4); // scope 0 at $DIR/const-promotion-extern-static.rs:13:45: 13:46

View File

@ -31,7 +31,7 @@
// + val: Unevaluated(main, [], Some(promoted[0])) // + val: Unevaluated(main, [], Some(promoted[0]))
// mir::Constant // mir::Constant
// + span: $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
// + literal: Const { ty: &[i32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[8240]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } // + literal: Const { ty: &[i32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[8240]::main), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
_3 = _9; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 _3 = _9; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
_2 = &raw const (*_3); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 _2 = &raw const (*_3); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
_1 = move _2 as *const [i32] (Pointer(Unsize)); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 _1 = move _2 as *const [i32] (Pointer(Unsize)); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35

View File

@ -31,7 +31,7 @@
// + val: Unevaluated(main, [], Some(promoted[0])) // + val: Unevaluated(main, [], Some(promoted[0]))
// mir::Constant // mir::Constant
// + span: $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
// + literal: Const { ty: &[i32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[8240]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } // + literal: Const { ty: &[i32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[8240]::main), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
_3 = _9; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 _3 = _9; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
_2 = &raw const (*_3); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 _2 = &raw const (*_3); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
_1 = move _2 as *const [i32] (Pointer(Unsize)); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 _1 = move _2 as *const [i32] (Pointer(Unsize)); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35

View File

@ -22,7 +22,7 @@
// + val: Unevaluated(FOO, [], None) // + val: Unevaluated(FOO, [], None)
// mir::Constant // mir::Constant
// + span: $DIR/const_prop_fails_gracefully.rs:7:13: 7:16 // + span: $DIR/const_prop_fails_gracefully.rs:7:13: 7:16
// + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:5 ~ const_prop_fails_gracefully[2706]::main::FOO), const_param_did: None }, substs: [], promoted: None }) } // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:5 ~ const_prop_fails_gracefully[2706]::main::FOO), const_param_did: None }, substs_: Some([]), promoted: None }) }
_2 = &raw const (*_3); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:16 _2 = &raw const (*_3); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:16
_1 = move _2 as usize (Misc); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:39 _1 = move _2 as usize (Misc); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:39
StorageDead(_2); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:38: 7:39 StorageDead(_2); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:38: 7:39

View File

@ -17,7 +17,7 @@
// + val: Unevaluated(main, [], Some(promoted[0])) // + val: Unevaluated(main, [], Some(promoted[0]))
// mir::Constant // mir::Constant
// + span: $DIR/ref_deref.rs:5:6: 5:10 // + span: $DIR/ref_deref.rs:5:6: 5:10
// + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref[cb9b]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref[cb9b]::main), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
_2 = _4; // scope 0 at $DIR/ref_deref.rs:5:6: 5:10 _2 = _4; // scope 0 at $DIR/ref_deref.rs:5:6: 5:10
- _1 = (*_2); // scope 0 at $DIR/ref_deref.rs:5:5: 5:10 - _1 = (*_2); // scope 0 at $DIR/ref_deref.rs:5:5: 5:10
+ _1 = const 4_i32; // scope 0 at $DIR/ref_deref.rs:5:5: 5:10 + _1 = const 4_i32; // scope 0 at $DIR/ref_deref.rs:5:5: 5:10

View File

@ -20,7 +20,7 @@
+ // + val: Unevaluated(main, [], Some(promoted[0])) + // + val: Unevaluated(main, [], Some(promoted[0]))
+ // mir::Constant + // mir::Constant
+ // + span: $DIR/ref_deref.rs:5:6: 5:10 + // + span: $DIR/ref_deref.rs:5:6: 5:10
+ // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref[cb9b]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } + // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref[cb9b]::main), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
+ _2 = &(*_4); // scope 0 at $DIR/ref_deref.rs:5:6: 5:10 + _2 = &(*_4); // scope 0 at $DIR/ref_deref.rs:5:6: 5:10
_1 = (*_2); // scope 0 at $DIR/ref_deref.rs:5:5: 5:10 _1 = (*_2); // scope 0 at $DIR/ref_deref.rs:5:5: 5:10
- StorageDead(_3); // scope 0 at $DIR/ref_deref.rs:5:10: 5:11 - StorageDead(_3); // scope 0 at $DIR/ref_deref.rs:5:10: 5:11

View File

@ -17,7 +17,7 @@
// + val: Unevaluated(main, [], Some(promoted[0])) // + val: Unevaluated(main, [], Some(promoted[0]))
// mir::Constant // mir::Constant
// + span: $DIR/ref_deref_project.rs:5:6: 5:17 // + span: $DIR/ref_deref_project.rs:5:6: 5:17
// + literal: Const { ty: &(i32, i32), val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[e8c3]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } // + literal: Const { ty: &(i32, i32), val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[e8c3]::main), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
_2 = &((*_4).1: i32); // scope 0 at $DIR/ref_deref_project.rs:5:6: 5:17 _2 = &((*_4).1: i32); // scope 0 at $DIR/ref_deref_project.rs:5:6: 5:17
_1 = (*_2); // scope 0 at $DIR/ref_deref_project.rs:5:5: 5:17 _1 = (*_2); // scope 0 at $DIR/ref_deref_project.rs:5:5: 5:17
StorageDead(_2); // scope 0 at $DIR/ref_deref_project.rs:5:17: 5:18 StorageDead(_2); // scope 0 at $DIR/ref_deref_project.rs:5:17: 5:18

View File

@ -20,7 +20,7 @@
+ // + val: Unevaluated(main, [], Some(promoted[0])) + // + val: Unevaluated(main, [], Some(promoted[0]))
+ // mir::Constant + // mir::Constant
+ // + span: $DIR/ref_deref_project.rs:5:6: 5:17 + // + span: $DIR/ref_deref_project.rs:5:6: 5:17
+ // + literal: Const { ty: &(i32, i32), val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[e8c3]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } + // + literal: Const { ty: &(i32, i32), val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[e8c3]::main), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
+ _2 = &((*_4).1: i32); // scope 0 at $DIR/ref_deref_project.rs:5:6: 5:17 + _2 = &((*_4).1: i32); // scope 0 at $DIR/ref_deref_project.rs:5:6: 5:17
_1 = (*_2); // scope 0 at $DIR/ref_deref_project.rs:5:5: 5:17 _1 = (*_2); // scope 0 at $DIR/ref_deref_project.rs:5:5: 5:17
- StorageDead(_3); // scope 0 at $DIR/ref_deref_project.rs:5:17: 5:18 - StorageDead(_3); // scope 0 at $DIR/ref_deref_project.rs:5:17: 5:18

View File

@ -24,7 +24,7 @@
// + val: Unevaluated(main, [], Some(promoted[0])) // + val: Unevaluated(main, [], Some(promoted[0]))
// mir::Constant // mir::Constant
// + span: $DIR/slice_len.rs:5:6: 5:19 // + span: $DIR/slice_len.rs:5:6: 5:19
// + literal: Const { ty: &[u32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ slice_len[6547]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } // + literal: Const { ty: &[u32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ slice_len[6547]::main), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
_4 = _9; // scope 0 at $DIR/slice_len.rs:5:6: 5:19 _4 = _9; // scope 0 at $DIR/slice_len.rs:5:6: 5:19
_3 = _4; // scope 0 at $DIR/slice_len.rs:5:6: 5:19 _3 = _4; // scope 0 at $DIR/slice_len.rs:5:6: 5:19
_2 = move _3 as &[u32] (Pointer(Unsize)); // scope 0 at $DIR/slice_len.rs:5:6: 5:19 _2 = move _3 as &[u32] (Pointer(Unsize)); // scope 0 at $DIR/slice_len.rs:5:6: 5:19

View File

@ -24,7 +24,7 @@
// + val: Unevaluated(main, [], Some(promoted[0])) // + val: Unevaluated(main, [], Some(promoted[0]))
// mir::Constant // mir::Constant
// + span: $DIR/slice_len.rs:5:6: 5:19 // + span: $DIR/slice_len.rs:5:6: 5:19
// + literal: Const { ty: &[u32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ slice_len[6547]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } // + literal: Const { ty: &[u32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ slice_len[6547]::main), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
_4 = _9; // scope 0 at $DIR/slice_len.rs:5:6: 5:19 _4 = _9; // scope 0 at $DIR/slice_len.rs:5:6: 5:19
_3 = _4; // scope 0 at $DIR/slice_len.rs:5:6: 5:19 _3 = _4; // scope 0 at $DIR/slice_len.rs:5:6: 5:19
_2 = move _3 as &[u32] (Pointer(Unsize)); // scope 0 at $DIR/slice_len.rs:5:6: 5:19 _2 = move _3 as &[u32] (Pointer(Unsize)); // scope 0 at $DIR/slice_len.rs:5:6: 5:19

View File

@ -38,7 +38,7 @@ fn bar() -> bool {
// + val: Unevaluated(bar, [], Some(promoted[1])) // + val: Unevaluated(bar, [], Some(promoted[1]))
// mir::Constant // mir::Constant
// + span: $DIR/inline-retag.rs:12:7: 12:9 // + span: $DIR/inline-retag.rs:12:7: 12:9
// + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:4 ~ inline_retag[a78c]::bar), const_param_did: None }, substs: [], promoted: Some(promoted[1]) }) } // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:4 ~ inline_retag[a78c]::bar), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[1]) }) }
Retag(_10); // scope 1 at $DIR/inline-retag.rs:12:7: 12:9 Retag(_10); // scope 1 at $DIR/inline-retag.rs:12:7: 12:9
_4 = &(*_10); // scope 1 at $DIR/inline-retag.rs:12:7: 12:9 _4 = &(*_10); // scope 1 at $DIR/inline-retag.rs:12:7: 12:9
Retag(_4); // scope 1 at $DIR/inline-retag.rs:12:7: 12:9 Retag(_4); // scope 1 at $DIR/inline-retag.rs:12:7: 12:9
@ -52,7 +52,7 @@ fn bar() -> bool {
// + val: Unevaluated(bar, [], Some(promoted[0])) // + val: Unevaluated(bar, [], Some(promoted[0]))
// mir::Constant // mir::Constant
// + span: $DIR/inline-retag.rs:12:11: 12:14 // + span: $DIR/inline-retag.rs:12:11: 12:14
// + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:4 ~ inline_retag[a78c]::bar), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:4 ~ inline_retag[a78c]::bar), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
Retag(_9); // scope 1 at $DIR/inline-retag.rs:12:11: 12:14 Retag(_9); // scope 1 at $DIR/inline-retag.rs:12:11: 12:14
_7 = &(*_9); // scope 1 at $DIR/inline-retag.rs:12:11: 12:14 _7 = &(*_9); // scope 1 at $DIR/inline-retag.rs:12:11: 12:14
Retag(_7); // scope 1 at $DIR/inline-retag.rs:12:11: 12:14 Retag(_7); // scope 1 at $DIR/inline-retag.rs:12:11: 12:14

View File

@ -66,7 +66,7 @@
// + val: Unevaluated(main, [], Some(promoted[0])) // + val: Unevaluated(main, [], Some(promoted[0]))
// mir::Constant // mir::Constant
// + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
// + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[2d0f]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[2d0f]::main), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
_8 = _20; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _8 = _20; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
(_6.0: &i32) = move _7; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL (_6.0: &i32) = move _7; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
(_6.1: &i32) = move _8; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL (_6.1: &i32) = move _8; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL

Some files were not shown because too many files have changed in this diff Show More