mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-05 03:23:25 +00:00
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:
commit
517c28e421
@ -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) {
|
||||||
|
@ -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 {
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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 {
|
||||||
|
@ -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),
|
||||||
|
@ -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);
|
||||||
|
@ -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)) => {
|
||||||
|
@ -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() {
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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>,
|
||||||
|
@ -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) => {
|
||||||
|
@ -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() {
|
||||||
|
@ -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 \
|
||||||
|
@ -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;
|
||||||
|
@ -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() {
|
||||||
|
@ -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)
|
||||||
|
@ -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]
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
@ -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),
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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>,
|
||||||
|
@ -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!(
|
||||||
|
@ -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 }
|
||||||
|
@ -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);
|
||||||
|
@ -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), "`")
|
||||||
|
@ -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,
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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 {
|
||||||
|
@ -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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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!(
|
||||||
|
@ -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)
|
||||||
|
@ -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 };
|
||||||
|
@ -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,
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
@ -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,
|
||||||
|
|
||||||
|
@ -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() {
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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) {
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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),
|
||||||
|
@ -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));
|
||||||
|
@ -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,
|
||||||
|
@ -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,
|
||||||
|
@ -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,
|
||||||
|
@ -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`.
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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(
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 [(); {}]:`",
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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>,
|
||||||
|
@ -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);
|
||||||
|
@ -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.
|
||||||
|
@ -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);
|
||||||
|
@ -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,
|
||||||
|
@ -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 => {
|
||||||
|
@ -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>,
|
||||||
|
@ -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 => (),
|
||||||
|
@ -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;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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",
|
||||||
|
@ -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);
|
||||||
|
@ -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()
|
||||||
}
|
}
|
||||||
|
@ -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> {
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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),
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
@ -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::*;
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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()
|
||||||
}
|
}
|
||||||
|
@ -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(¶m) {
|
if !unconstrained_parameters.contains(¶m) {
|
||||||
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 {
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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))
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
Loading…
Reference in New Issue
Block a user