1
Fork 0

initial revert

This commit is contained in:
Ellen 2022-01-12 03:19:52 +00:00
parent b0ec3e09a9
commit 71bbb603f4
127 changed files with 540 additions and 1050 deletions

View file

@ -171,7 +171,7 @@ impl<'me, 'typeck, 'flow, 'tcx> 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(self.cx.typeck.tcx()) { if local_ty.has_free_regions() {
self.cx.add_drop_live_facts_for(local, local_ty, &[location], &locations); self.cx.add_drop_live_facts_for(local, local_ty, &[location], &locations);
} }
} }

View file

@ -425,7 +425,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
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(),
uv.def.did, uv.def.did,
UserSubsts { substs: uv.substs(self.tcx()), user_self_ty: None }, UserSubsts { substs: uv.substs, user_self_ty: None },
)), )),
) { ) {
span_mirbug!( span_mirbug!(
@ -1969,7 +1969,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
let predicates = self.prove_closure_bounds( let predicates = self.prove_closure_bounds(
tcx, tcx,
def_id.expect_local(), def_id.expect_local(),
uv.substs(tcx), uv.substs,
location, location,
); );
self.normalize_and_prove_instantiated_predicates( self.normalize_and_prove_instantiated_predicates(

View file

@ -129,11 +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(uv) if fx.tcx.is_static(uv.def.did) => { ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted })
assert!(uv.substs(fx.tcx).is_empty()); if fx.tcx.is_static(def.did) =>
assert!(uv.promoted.is_none()); {
assert!(substs.is_empty());
assert!(promoted.is_none());
return codegen_static_ref(fx, uv.def.did, fx.layout_of(const_.ty)).to_cvalue(fx); return codegen_static_ref(fx, def.did, fx.layout_of(const_.ty)).to_cvalue(fx);
} }
ConstKind::Unevaluated(unevaluated) => { ConstKind::Unevaluated(unevaluated) => {
match fx.tcx.const_eval_resolve(ParamEnv::reveal_all(), unevaluated, None) { match fx.tcx.const_eval_resolve(ParamEnv::reveal_all(), unevaluated, None) {

View file

@ -507,7 +507,7 @@ impl<'ll, 'tcx> 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.definitely_needs_subst(cx.tcx) && !impl_self_ty.needs_subst()
{ {
Some(type_metadata(cx, impl_self_ty, rustc_span::DUMMY_SP)) Some(type_metadata(cx, impl_self_ty, rustc_span::DUMMY_SP))
} else { } else {

View file

@ -1477,7 +1477,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(self.cx.tcx())); assert!(!dst_layout.ty.has_erasable_regions());
let place = PlaceRef::alloca(bx, dst_layout); let place = PlaceRef::alloca(bx, dst_layout);
place.storage_live(bx); place.storage_live(bx);
self.codegen_transmute_into(bx, src, place); self.codegen_transmute_into(bx, src, place);

View file

@ -209,7 +209,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(cx.tcx())); assert!(!layout.ty.has_erasable_regions());
if local == mir::RETURN_PLACE && fx.fn_abi.ret.is_indirect() { if local == mir::RETURN_PLACE && fx.fn_abi.ret.is_indirect() {
debug!("alloc: {:?} (return place) -> place", local); debug!("alloc: {:?} (return place) -> place", local);

View file

@ -568,7 +568,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
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(uv) => { ty::ConstKind::Unevaluated(uv) => {
let instance = self.resolve(uv.def, uv.substs(*self.tcx))?; let instance = self.resolve(uv.def, uv.substs)?;
Ok(self.eval_to_allocation(GlobalId { instance, promoted: uv.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(..) => {

View file

@ -9,7 +9,7 @@ where
T: TypeFoldable<'tcx>, T: TypeFoldable<'tcx>,
{ {
debug!("ensure_monomorphic_enough: ty={:?}", ty); debug!("ensure_monomorphic_enough: ty={:?}", ty);
if !ty.potentially_needs_subst() { if !ty.needs_subst() {
return Ok(()); return Ok(());
} }
@ -21,12 +21,8 @@ where
impl<'tcx> TypeVisitor<'tcx> for UsedParamsNeedSubstVisitor<'tcx> { impl<'tcx> TypeVisitor<'tcx> for UsedParamsNeedSubstVisitor<'tcx> {
type BreakTy = FoundParam; type BreakTy = FoundParam;
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> {
if !ty.potentially_needs_subst() { if !ty.needs_subst() {
return ControlFlow::CONTINUE; return ControlFlow::CONTINUE;
} }
@ -44,7 +40,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.definitely_needs_subst(self.tcx)) { match (is_used, subst.needs_subst()) {
// 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),

View file

@ -348,7 +348,7 @@ impl<'mir, 'tcx> 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(self.tcx) { for ty in ty.walk() {
let ty = match ty.unpack() { let ty = match ty.unpack() {
GenericArgKind::Type(ty) => ty, GenericArgKind::Type(ty) => ty,

View file

@ -338,7 +338,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 {
// Use qualifs of the type for the promoted. Promoteds in MIR body should be possible // Use qualifs of the type for the promoted. Promoteds in MIR body should be possible
// only for `NeedsNonConstDrop` with precise drop checking. This is the only const // only for `NeedsNonConstDrop` with precise drop checking. This is the only const
// check performed after the promotion. Verify that with an assertion. // check performed after the promotion. Verify that with an assertion.

View file

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

View file

@ -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_POTENTIAL_FREE_REGIONS | // `HAS_RE_PLACEHOLDER` implies `HAS_POTENTIAL_FREE_REGIONS` TypeFlags::HAS_FREE_REGIONS | // `HAS_RE_PLACEHOLDER` implies `HAS_FREE_REGIONS`
TypeFlags::HAS_TY_PLACEHOLDER | TypeFlags::HAS_TY_PLACEHOLDER |
TypeFlags::HAS_CT_PLACEHOLDER TypeFlags::HAS_CT_PLACEHOLDER
} else { } else {

View file

@ -129,8 +129,6 @@ 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);
@ -746,9 +744,10 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
} }
} }
} }
ty::ConstKind::Unevaluated(uv) if self.tcx().lazy_normalization() => { ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted })
assert_eq!(uv.promoted, None); if self.tcx().lazy_normalization() =>
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(),
@ -757,7 +756,7 @@ impl<'tcx> 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::new(uv.def, substs)), val: ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }),
})) }))
} }
_ => relate::super_relate_consts(self, c, c), _ => relate::super_relate_consts(self, c, c),
@ -991,9 +990,10 @@ impl<'tcx> TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> {
} }
} }
} }
ty::ConstKind::Unevaluated(uv) if self.tcx().lazy_normalization() => { ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted })
assert_eq!(uv.promoted, None); if self.tcx().lazy_normalization() =>
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(),
@ -1002,7 +1002,7 @@ impl<'tcx> 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::new(uv.def, substs)), val: ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }),
})) }))
} }
_ => relate::super_relate_consts(self, c, c), _ => relate::super_relate_consts(self, c, c),

View file

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

View file

@ -52,7 +52,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(self.infcx.tcx).any(|inner| { ty.walk().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)) => {
@ -445,9 +445,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
parent: None, parent: None,
} }
} }
ty::ConstKind::Unevaluated(ty::Unevaluated { ty::ConstKind::Unevaluated(ty::Unevaluated { substs, .. }) => {
substs_: Some(substs), ..
}) => {
assert!(substs.has_infer_types_or_consts()); assert!(substs.has_infer_types_or_consts());
// FIXME: We only use the first inference variable we encounter in // FIXME: We only use the first inference variable we encounter in

View file

@ -557,12 +557,6 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
pub(super) struct TraitObjectVisitor(pub(super) FxHashSet<DefId>); pub(super) struct TraitObjectVisitor(pub(super) FxHashSet<DefId>);
impl<'tcx> TypeVisitor<'tcx> for TraitObjectVisitor { impl<'tcx> TypeVisitor<'tcx> for TraitObjectVisitor {
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> { 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) => {

View file

@ -80,26 +80,21 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
// Mark all unnamed regions in the type with a number. // Mark all unnamed regions in the type with a number.
// This diagnostic is called in response to lifetime errors, so be informative. // This diagnostic is called in response to lifetime errors, so be informative.
struct HighlightBuilder<'tcx> { struct HighlightBuilder {
highlight: RegionHighlightMode, highlight: RegionHighlightMode,
tcx: TyCtxt<'tcx>,
counter: usize, counter: usize,
} }
impl<'tcx> HighlightBuilder<'tcx> { impl HighlightBuilder {
fn build(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> RegionHighlightMode { fn build(ty: Ty<'_>) -> RegionHighlightMode {
let mut builder = let mut builder =
HighlightBuilder { highlight: RegionHighlightMode::default(), counter: 1, tcx }; HighlightBuilder { highlight: RegionHighlightMode::default(), counter: 1 };
builder.visit_ty(ty); builder.visit_ty(ty);
builder.highlight builder.highlight
} }
} }
impl<'tcx> ty::fold::TypeVisitor<'tcx> for HighlightBuilder<'tcx> { impl<'tcx> ty::fold::TypeVisitor<'tcx> for HighlightBuilder {
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> {
if !r.has_name() && self.counter <= 3 { if !r.has_name() && self.counter <= 3 {
self.highlight.highlighting_region(r, self.counter); self.highlight.highlighting_region(r, self.counter);
@ -109,12 +104,12 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
} }
} }
let expected_highlight = HighlightBuilder::build(self.tcx(), expected); let expected_highlight = HighlightBuilder::build(expected);
let expected = self let expected = self
.infcx .infcx
.extract_inference_diagnostics_data(expected.into(), Some(expected_highlight)) .extract_inference_diagnostics_data(expected.into(), Some(expected_highlight))
.name; .name;
let found_highlight = HighlightBuilder::build(self.tcx(), found); let found_highlight = HighlightBuilder::build(found);
let found = let found =
self.infcx.extract_inference_diagnostics_data(found.into(), Some(found_highlight)).name; self.infcx.extract_inference_diagnostics_data(found.into(), Some(found_highlight)).name;

View file

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

View file

@ -668,10 +668,13 @@ 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((a, b), &mut OriginalQueryValues::default()); let canonical = self.canonicalize_query(
((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)
@ -1585,8 +1588,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
unevaluated: ty::Unevaluated<'tcx>, unevaluated: ty::Unevaluated<'tcx>,
span: Option<Span>, span: Option<Span>,
) -> EvalToConstValueResult<'tcx> { ) -> EvalToConstValueResult<'tcx> {
let mut substs = unevaluated.substs(self.tcx); let substs = self.resolve_vars_if_possible(unevaluated.substs);
substs = self.resolve_vars_if_possible(substs);
// Postpone the evaluation of constants whose substs depend on inference // Postpone the evaluation of constants whose substs depend on inference
// variables // variables
@ -1599,7 +1601,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
let unevaluated = ty::Unevaluated { let unevaluated = ty::Unevaluated {
def: unevaluated.def, def: unevaluated.def,
substs_: Some(substs_erased), substs: substs_erased,
promoted: unevaluated.promoted, promoted: unevaluated.promoted,
}; };

View file

@ -201,7 +201,6 @@ 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,
@ -759,7 +758,6 @@ 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,
@ -767,10 +765,6 @@ struct ScopeInstantiator<'me, 'tcx> {
} }
impl<'me, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'me, 'tcx> { impl<'me, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'me, 'tcx> {
fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
Some(self.tcx)
}
fn visit_binder<T: TypeFoldable<'tcx>>( fn visit_binder<T: TypeFoldable<'tcx>>(
&mut self, &mut self,
t: &ty::Binder<'tcx, T>, t: &ty::Binder<'tcx, T>,

View file

@ -316,7 +316,6 @@ impl<'a, 'tcx> 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,
@ -368,19 +367,14 @@ impl<'a, 'tcx> 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<'tcx, OP> { struct ConstrainOpaqueTypeRegionVisitor<OP> {
tcx: TyCtxt<'tcx>,
op: OP, op: OP,
} }
impl<'tcx, OP> TypeVisitor<'tcx> for ConstrainOpaqueTypeRegionVisitor<'tcx, OP> impl<'tcx, OP> TypeVisitor<'tcx> for ConstrainOpaqueTypeRegionVisitor<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>,
@ -402,7 +396,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_POTENTIAL_FREE_REGIONS) { if !ty.flags().intersects(ty::TypeFlags::HAS_FREE_REGIONS) {
return ControlFlow::CONTINUE; return ControlFlow::CONTINUE;
} }

View file

@ -196,7 +196,7 @@ fn compute_components_recursive<'tcx>(
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(tcx, visited) { for child in parent.walk_shallow(visited) {
match child.unpack() { match child.unpack() {
GenericArgKind::Type(ty) => { GenericArgKind::Type(ty) => {
compute_components(tcx, ty, out, visited); compute_components(tcx, ty, out, visited);

View file

@ -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(self.tcx, visited) .walk_shallow(visited)
.filter_map(|child| match child.unpack() { .filter_map(|child| match child.unpack() {
GenericArgKind::Type(ty) => Some(self.type_bound(ty, visited)), GenericArgKind::Type(ty) => Some(self.type_bound(ty, visited)),
GenericArgKind::Lifetime(lt) => { GenericArgKind::Lifetime(lt) => {

View file

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

View file

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

View file

@ -38,7 +38,7 @@ declare_lint_pass!(EnumIntrinsicsNonEnums => [ENUM_INTRINSICS_NON_ENUMS]);
/// Returns `true` if we know for sure that the given type is not an enum. Note that for cases where /// Returns `true` if we know for sure that the given type is not an enum. Note that for cases where
/// the type is generic, we can't be certain if it will be an enum so we have to assume that it is. /// the type is generic, we can't be certain if it will be an enum so we have to assume that it is.
fn is_non_enum(t: Ty<'_>) -> bool { fn is_non_enum(t: Ty<'_>) -> bool {
!t.is_enum() && !t.potentially_needs_subst() !t.is_enum() && !t.needs_subst()
} }
fn enforce_mem_discriminant( fn enforce_mem_discriminant(

View file

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

View file

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

View file

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

View file

@ -288,7 +288,6 @@ 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>>,
@ -331,7 +330,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.definitely_has_param_types_or_consts(tcx); body.is_polymorphic = body.has_param_types_or_consts();
body body
} }
@ -341,7 +340,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 {
Body { let mut 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,
@ -357,7 +356,9 @@ impl<'tcx> Body<'tcx> {
is_polymorphic: false, is_polymorphic: false,
predecessor_cache: PredecessorCache::new(), predecessor_cache: PredecessorCache::new(),
is_cyclic: GraphIsCyclicCache::new(), is_cyclic: GraphIsCyclicCache::new(),
} };
body.is_polymorphic = body.has_param_types_or_consts();
body
} }
#[inline] #[inline]

View file

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

View file

@ -110,10 +110,6 @@ rustc_queries! {
separate_provide_extern separate_provide_extern
} }
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| desc { |tcx|
@ -318,11 +314,12 @@ rustc_queries! {
} }
query try_unify_abstract_consts(key: ( query try_unify_abstract_consts(key: (
ty::Unevaluated<'tcx, ()>, ty::Unevaluated<'tcx, ()> (ty::WithOptConstParam<DefId>, SubstsRef<'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.def.did), tcx.def_path_str(key.1.def.did) tcx.def_path_str(key.0.0.did), tcx.def_path_str(key.1.0.did)
} }
} }

View file

@ -61,7 +61,7 @@ impl<'tcx> Const<'tcx> {
None => tcx.mk_const(ty::Const { None => tcx.mk_const(ty::Const {
val: ty::ConstKind::Unevaluated(ty::Unevaluated { val: ty::ConstKind::Unevaluated(ty::Unevaluated {
def: def.to_global(), def: def.to_global(),
substs_: None, substs: InternalSubsts::identity_for_item(tcx, def.did.to_def_id()),
promoted: None, promoted: None,
}), }),
ty, ty,
@ -153,14 +153,14 @@ impl<'tcx> Const<'tcx> {
tcx.mk_const(ty::Const { tcx.mk_const(ty::Const {
val: ty::ConstKind::Unevaluated(ty::Unevaluated { val: ty::ConstKind::Unevaluated(ty::Unevaluated {
def: ty::WithOptConstParam::unknown(def_id).to_global(), def: ty::WithOptConstParam::unknown(def_id).to_global(),
substs_: Some(substs), substs,
promoted: None, promoted: None,
}), }),
ty, ty,
}) })
} }
}; };
debug_assert!(!ret.has_free_regions(tcx)); debug_assert!(!ret.has_free_regions());
ret ret
} }

View file

@ -1,5 +1,4 @@
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;
@ -13,53 +12,12 @@ 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, P = Option<Promoted>> { pub struct Unevaluated<'tcx> {
pub def: ty::WithOptConstParam<DefId>, pub def: ty::WithOptConstParam<DefId>,
pub substs_: Option<SubstsRef<'tcx>>, pub substs: SubstsRef<'tcx>,
pub promoted: P, pub promoted: Option<Promoted>,
}
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.
@ -151,7 +109,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) = self { if let ConstKind::Unevaluated(Unevaluated { def, substs, promoted }) = 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`
@ -160,32 +118,29 @@ 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 = tcx let param_env_and_substs = tcx
.erase_regions(param_env) .erase_regions(param_env)
.with_reveal_all_normalized(tcx) .with_reveal_all_normalized(tcx)
.and(tcx.erase_regions(unevaluated)); .and(tcx.erase_regions(substs));
// 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 = if param_env_and.needs_infer() { let param_env_and_substs = if param_env_and_substs.needs_infer() {
tcx.param_env(unevaluated.def.did).and(ty::Unevaluated { tcx.param_env(def.did).and(InternalSubsts::identity_for_item(tcx, def.did))
def: unevaluated.def,
substs_: Some(InternalSubsts::identity_for_item(tcx, unevaluated.def.did)),
promoted: unevaluated.promoted,
})
} else { } else {
param_env_and param_env_and_substs
}; };
// FIXME(eddyb) maybe the `const_eval_*` methods should take // FIXME(eddyb) maybe the `const_eval_*` methods should take
// `ty::ParamEnvAnd` instead of having them separate. // `ty::ParamEnvAnd<SubstsRef>` instead of having them separate.
let (param_env, unevaluated) = param_env_and.into_parts(); let (param_env, substs) = param_env_and_substs.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, unevaluated, None) { match tcx.const_eval_resolve(param_env, ty::Unevaluated { def, substs, promoted }, None)
{
// NOTE(eddyb) `val` contains no lifetimes/types/consts, // NOTE(eddyb) `val` contains no lifetimes/types/consts,
// and we use the original type, so nothing from `substs` // and we use the original type, so nothing from `substs`
// (which may be identity substs, see above), // (which may be identity substs, see above),

View file

@ -21,9 +21,7 @@ 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 if !value.has_type_flags(TypeFlags::HAS_RE_LATE_BOUND | TypeFlags::HAS_FREE_REGIONS) {
.has_type_flags(TypeFlags::HAS_RE_LATE_BOUND | TypeFlags::HAS_POTENTIAL_FREE_REGIONS)
{
return value; return value;
} }
debug!("erase_regions({:?})", value); debug!("erase_regions({:?})", value);

View file

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

View file

@ -95,15 +95,9 @@ 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)
}
#[instrument(level = "trace")] #[instrument(level = "trace")]
fn has_type_flags(&self, flags: TypeFlags) -> bool { fn has_type_flags(&self, flags: TypeFlags) -> bool {
self.visit_with(&mut HasTypeFlagsVisitor { tcx: None, flags }).break_value() self.visit_with(&mut HasTypeFlagsVisitor { flags }).break_value() == Some(FoundFlags)
== 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)
@ -114,18 +108,8 @@ 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 potentially_has_param_types_or_consts(&self) -> bool { fn has_param_types_or_consts(&self) -> bool {
self.has_type_flags( self.has_type_flags(TypeFlags::HAS_TY_PARAM | TypeFlags::HAS_CT_PARAM)
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)
@ -146,18 +130,13 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone {
| TypeFlags::HAS_CT_PLACEHOLDER, | TypeFlags::HAS_CT_PLACEHOLDER,
) )
} }
fn potentially_needs_subst(&self) -> bool { fn needs_subst(&self) -> bool {
self.has_type_flags( self.has_type_flags(TypeFlags::NEEDS_SUBST)
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, tcx: TyCtxt<'tcx>) -> bool { fn has_free_regions(&self) -> bool {
self.definitely_has_type_flags(tcx, TypeFlags::HAS_KNOWN_FREE_REGIONS) self.has_type_flags(TypeFlags::HAS_FREE_REGIONS)
} }
fn has_erased_regions(&self) -> bool { fn has_erased_regions(&self) -> bool {
@ -165,25 +144,15 @@ 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, tcx: TyCtxt<'tcx>) -> bool { fn has_erasable_regions(&self) -> bool {
self.definitely_has_type_flags(tcx, TypeFlags::HAS_KNOWN_FREE_REGIONS) self.has_type_flags(TypeFlags::HAS_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, tcx: TyCtxt<'tcx>) -> bool { fn is_global(&self) -> bool {
!self.definitely_has_type_flags(tcx, TypeFlags::HAS_KNOWN_FREE_LOCAL_NAMES) !self.has_type_flags(TypeFlags::HAS_FREE_LOCAL_NAMES)
} }
/// True if there are any late-bound regions /// True if there are any late-bound regions
@ -361,17 +330,6 @@ where
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,
@ -392,10 +350,6 @@ 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)
} }
@ -488,8 +442,7 @@ 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<'tcx, F> { struct RegionVisitor<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:
@ -511,16 +464,12 @@ impl<'tcx> TyCtxt<'tcx> {
callback: F, callback: F,
} }
impl<'tcx, F> TypeVisitor<'tcx> for RegionVisitor<'tcx, F> impl<'tcx, F> TypeVisitor<'tcx> for RegionVisitor<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>,
@ -548,7 +497,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_POTENTIAL_FREE_REGIONS) { if ty.flags().intersects(TypeFlags::HAS_FREE_REGIONS) {
ty.super_visit_with(self) ty.super_visit_with(self)
} else { } else {
ControlFlow::CONTINUE ControlFlow::CONTINUE
@ -556,9 +505,7 @@ impl<'tcx> TyCtxt<'tcx> {
} }
} }
value value.visit_with(&mut RegionVisitor { outer_index: ty::INNERMOST, callback }).is_break()
.visit_with(&mut RegionVisitor { tcx: self, outer_index: ty::INNERMOST, callback })
.is_break()
} }
} }
@ -897,7 +844,7 @@ impl<'tcx> TyCtxt<'tcx> {
where where
T: TypeFoldable<'tcx>, T: TypeFoldable<'tcx>,
{ {
let mut collector = LateBoundRegionsCollector::new(self, just_constraint); let mut collector = LateBoundRegionsCollector::new(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
@ -964,11 +911,6 @@ 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>,
@ -1183,11 +1125,6 @@ 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>,
@ -1252,35 +1189,32 @@ 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<'tcx> { struct HasTypeFlagsVisitor {
tcx: Option<TyCtxt<'tcx>>,
flags: ty::TypeFlags, flags: ty::TypeFlags,
} }
impl<'tcx> std::fmt::Debug for HasTypeFlagsVisitor<'tcx> { impl std::fmt::Debug for HasTypeFlagsVisitor {
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.flags.fmt(fmt) self.flags.fmt(fmt)
} }
} }
impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor<'tcx> { impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor {
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]
#[instrument(level = "trace")] #[instrument(level = "trace")]
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> { fn visit_ty(&mut self, t: Ty<'_>) -> ControlFlow<Self::BreakTy> {
let flags = t.flags(); debug!(
trace!(t.flags=?t.flags()); "HasTypeFlagsVisitor: t={:?} t.flags={:?} self.flags={:?}",
if flags.intersects(self.flags) { t,
t.flags(),
self.flags
);
if t.flags().intersects(self.flags) {
ControlFlow::Break(FoundFlags) ControlFlow::Break(FoundFlags)
} else { } else {
match flags.intersects(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS) { ControlFlow::CONTINUE
true if self.tcx.is_some() => UnknownConstSubstsVisitor::search(&self, t),
_ => ControlFlow::CONTINUE,
}
} }
} }
@ -1304,143 +1238,28 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor<'tcx> {
if flags.intersects(self.flags) { if flags.intersects(self.flags) {
ControlFlow::Break(FoundFlags) ControlFlow::Break(FoundFlags)
} else { } else {
match flags.intersects(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS) { ControlFlow::CONTINUE
true if self.tcx.is_some() => UnknownConstSubstsVisitor::search(&self, c),
_ => ControlFlow::CONTINUE,
}
}
}
#[inline]
#[instrument(level = "trace")]
fn visit_unevaluated_const(&mut self, uv: ty::Unevaluated<'tcx>) -> ControlFlow<Self::BreakTy> {
let flags = FlagComputation::for_unevaluated_const(uv);
trace!(r.flags=?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]
#[instrument(level = "trace")] #[instrument(level = "trace")]
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!(
trace!(predicate.flags=?flags); "HasTypeFlagsVisitor: predicate={:?} predicate.flags={:?} self.flags={:?}",
if flags.intersects(self.flags) { predicate, predicate.inner.flags, self.flags
);
if predicate.inner.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<'tcx> { struct LateBoundRegionsCollector {
tcx: TyCtxt<'tcx>,
current_index: ty::DebruijnIndex, current_index: ty::DebruijnIndex,
regions: FxHashSet<ty::BoundRegionKind>, regions: FxHashSet<ty::BoundRegionKind>,
@ -1454,10 +1273,9 @@ struct LateBoundRegionsCollector<'tcx> {
just_constrained: bool, just_constrained: bool,
} }
impl<'tcx> LateBoundRegionsCollector<'tcx> { impl LateBoundRegionsCollector {
fn new(tcx: TyCtxt<'tcx>, just_constrained: bool) -> Self { fn new(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,
@ -1465,11 +1283,7 @@ impl<'tcx> LateBoundRegionsCollector<'tcx> {
} }
} }
impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector<'tcx> { impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector {
fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
Some(self.tcx)
}
fn visit_binder<T: TypeFoldable<'tcx>>( fn visit_binder<T: TypeFoldable<'tcx>>(
&mut self, &mut self,
t: &Binder<'tcx, T>, t: &Binder<'tcx, T>,

View file

@ -1769,9 +1769,7 @@ 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.definitely_has_param_types_or_consts(self.tcx) if layout.ty.has_param_types_or_consts() || !self.param_env.caller_bounds().is_empty() {
|| !self.param_env.caller_bounds().is_empty()
{
return; return;
} }
@ -1936,7 +1934,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.definitely_has_param_types_or_consts(tcx)); debug_assert!(tail.has_param_types_or_consts());
Ok(SizeSkeleton::Pointer { non_zero, tail: tcx.erase_regions(tail) }) Ok(SizeSkeleton::Pointer { non_zero, tail: tcx.erase_regions(tail) })
} }
_ => bug!( _ => bug!(

View file

@ -598,7 +598,7 @@ pub enum PredicateKind<'tcx> {
Coerce(CoercePredicate<'tcx>), Coerce(CoercePredicate<'tcx>),
/// Constant initializer must evaluate successfully. /// Constant initializer must evaluate successfully.
ConstEvaluatable(ty::Unevaluated<'tcx, ()>), ConstEvaluatable(ty::WithOptConstParam<DefId>, SubstsRef<'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>),
@ -1417,7 +1417,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_known_global() { if value.is_global() {
ParamEnvAnd { param_env: self.without_caller_bounds(), value } ParamEnvAnd { param_env: self.without_caller_bounds(), value }
} else { } else {
ParamEnvAnd { param_env: self, value } ParamEnvAnd { param_env: self, value }

View file

@ -1153,28 +1153,29 @@ pub trait PrettyPrinter<'tcx>:
} }
match ct.val { match ct.val {
ty::ConstKind::Unevaluated(uv) => { ty::ConstKind::Unevaluated(ty::Unevaluated {
if let Some(promoted) = uv.promoted { def,
let substs = uv.substs_.unwrap(); substs,
p!(print_value_path(uv.def.did, substs)); promoted: Some(promoted),
p!(write("::{:?}", promoted)); }) => {
} else { p!(print_value_path(def.did, substs));
let tcx = self.tcx(); p!(write("::{:?}", promoted));
match tcx.def_kind(uv.def.did) { }
DefKind::Static | DefKind::Const | DefKind::AssocConst => { ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted: None }) => {
p!(print_value_path(uv.def.did, uv.substs(tcx))) match self.tcx().def_kind(def.did) {
} 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 let Ok(snip) = tcx.sess.source_map().span_to_snippet(span) { if def.is_local() {
p!(write("{}", snip)) let span = self.tcx().def_span(def.did);
} else { if let Ok(snip) = self.tcx().sess.source_map().span_to_snippet(span) {
print_underscore!() p!(write("{}", snip))
}
} else { } else {
print_underscore!() print_underscore!()
} }
} else {
print_underscore!()
} }
} }
} }
@ -1419,7 +1420,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 `potentially_has_param_types_or_consts` check ensures that we can use // NB: the `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`
@ -1427,9 +1428,7 @@ 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(..)) (_, ty::Array(..) | ty::Tuple(..) | ty::Adt(..)) if !ty.has_param_types_or_consts() => {
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 })),
@ -2246,7 +2245,6 @@ impl<'tcx, F: fmt::Write> FmtPrinter<'_, 'tcx, F> {
T: TypeFoldable<'tcx>, T: TypeFoldable<'tcx>,
{ {
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>>,
} }
@ -2254,10 +2252,6 @@ impl<'tcx, 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)
}
#[instrument(skip(self), level = "trace")] #[instrument(skip(self), level = "trace")]
fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> { fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
trace!("address: {:p}", r); trace!("address: {:p}", r);
@ -2288,7 +2282,6 @@ impl<'tcx, 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(),
}; };
@ -2546,8 +2539,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(uv) => { ty::PredicateKind::ConstEvaluatable(def, substs) => {
p!("the constant `", print_value_path(uv.def.did, uv.substs_.map_or(&[], |x| x)), "` can be evaluated") p!("the constant `", print_value_path(def.did, substs), "` can be evaluated")
} }
ty::PredicateKind::ConstEquate(c1, c2) => { ty::PredicateKind::ConstEquate(c1, c2) => {
p!("the constant `", print(c1), "` equals `", print(c2), "`") p!("the constant `", print(c1), "` equals `", print(c2), "`")

View file

@ -587,7 +587,7 @@ pub fn super_relate_consts<'tcx, R: TypeRelation<'tcx>>(
(ty::ConstKind::Unevaluated(au), ty::ConstKind::Unevaluated(bu)) (ty::ConstKind::Unevaluated(au), ty::ConstKind::Unevaluated(bu))
if tcx.features().generic_const_exprs => if tcx.features().generic_const_exprs =>
{ {
tcx.try_unify_abstract_consts((au.shrink(), bu.shrink())) tcx.try_unify_abstract_consts(((au.def, au.substs), (bu.def, bu.substs)))
} }
// 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`
@ -599,13 +599,13 @@ pub fn super_relate_consts<'tcx, 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(tcx), au.substs,
bu.substs(tcx), bu.substs,
)?; )?;
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_: Some(substs), substs,
promoted: au.promoted, promoted: au.promoted,
}), }),
ty: a.ty, ty: a.ty,

View file

@ -184,8 +184,8 @@ impl<'tcx> 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(uv) => { ty::PredicateKind::ConstEvaluatable(def_id, substs) => {
write!(f, "ConstEvaluatable({:?}, {:?})", uv.def, uv.substs_) write!(f, "ConstEvaluatable({:?}, {:?})", def_id, 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) => {
@ -445,8 +445,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(uv) => { ty::PredicateKind::ConstEvaluatable(def_id, substs) => {
tcx.lift(uv).map(|uv| ty::PredicateKind::ConstEvaluatable(uv)) tcx.lift(substs).map(|substs| ty::PredicateKind::ConstEvaluatable(def_id, substs))
} }
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))
@ -1185,7 +1185,13 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ConstKind<'tcx> {
Ok(match self { Ok(match self {
ty::ConstKind::Infer(ic) => ty::ConstKind::Infer(ic.try_fold_with(folder)?), ty::ConstKind::Infer(ic) => ty::ConstKind::Infer(ic.try_fold_with(folder)?),
ty::ConstKind::Param(p) => ty::ConstKind::Param(p.try_fold_with(folder)?), ty::ConstKind::Param(p) => ty::ConstKind::Param(p.try_fold_with(folder)?),
ty::ConstKind::Unevaluated(uv) => ty::ConstKind::Unevaluated(uv.try_fold_with(folder)?), ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) => {
ty::ConstKind::Unevaluated(ty::Unevaluated {
def,
substs: substs.try_fold_with(folder)?,
promoted,
})
}
ty::ConstKind::Value(_) ty::ConstKind::Value(_)
| ty::ConstKind::Bound(..) | ty::ConstKind::Bound(..)
| ty::ConstKind::Placeholder(..) | ty::ConstKind::Placeholder(..)
@ -1197,7 +1203,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(uv) => uv.visit_with(visitor), ty::ConstKind::Unevaluated(ct) => ct.substs.visit_with(visitor),
ty::ConstKind::Value(_) ty::ConstKind::Value(_)
| ty::ConstKind::Bound(..) | ty::ConstKind::Bound(..)
| ty::ConstKind::Placeholder(_) | ty::ConstKind::Placeholder(_)
@ -1218,59 +1224,3 @@ impl<'tcx> TypeFoldable<'tcx> for InferConst<'tcx> {
ControlFlow::CONTINUE ControlFlow::CONTINUE
} }
} }
impl<'tcx> TypeFoldable<'tcx> for ty::Unevaluated<'tcx> {
fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
self,
folder: &mut F,
) -> Result<Self, F::Error> {
Ok(ty::Unevaluated {
def: self.def,
substs_: Some(self.substs(folder.tcx()).try_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 try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
self,
folder: &mut F,
) -> Result<Self, F::Error> {
Ok(ty::Unevaluated {
def: self.def,
substs_: Some(self.substs(folder.tcx()).try_fold_with(folder)?),
promoted: self.promoted,
})
}
fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
visitor.visit_unevaluated_const(self.expand())
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
if let Some(tcx) = visitor.tcx_for_anon_const_substs() {
self.substs(tcx).visit_with(visitor)
} else if let Some(substs) = self.substs_ {
substs.visit_with(visitor)
} else {
debug!("ignoring default substs of `{:?}`", self.def);
ControlFlow::CONTINUE
}
}
}

View file

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

View file

@ -505,7 +505,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.potentially_needs_subst() { if !t.needs_subst() {
return t; return t;
} }

View file

@ -1,8 +1,8 @@
//! An iterator over the type substructure. //! An iterator over the type substructure.
//! WARNING: this does not keep track of the region depth. //! WARNING: this does not keep track of the region depth.
use crate::ty;
use crate::ty::subst::{GenericArg, GenericArgKind}; use crate::ty::subst::{GenericArg, GenericArgKind};
use crate::ty::{self, TyCtxt};
use rustc_data_structures::sso::SsoHashSet; use rustc_data_structures::sso::SsoHashSet;
use smallvec::{self, SmallVec}; use smallvec::{self, SmallVec};
@ -11,7 +11,6 @@ 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>>,
@ -26,13 +25,8 @@ 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> {
fn new(expose_default_const_substs: Option<TyCtxt<'tcx>>, root: GenericArg<'tcx>) -> Self { pub fn new(root: GenericArg<'tcx>) -> Self {
Self { Self { stack: smallvec![root], last_subtree: 1, visited: SsoHashSet::new() }
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
@ -61,7 +55,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(self.expose_default_const_substs, &mut self.stack, next); push_inner(&mut self.stack, next);
debug!("next: stack={:?}", self.stack); debug!("next: stack={:?}", self.stack);
return Some(next); return Some(next);
} }
@ -80,8 +74,8 @@ impl<'tcx> 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, tcx: TyCtxt<'tcx>) -> TypeWalker<'tcx> { pub fn walk(self) -> TypeWalker<'tcx> {
TypeWalker::new(Some(tcx), self) TypeWalker::new(self)
} }
/// Iterator that walks the immediate children of `self`. Hence /// Iterator that walks the immediate children of `self`. Hence
@ -93,21 +87,16 @@ impl<'tcx> 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(Some(tcx), &mut stack, self); push_inner(&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
@ -118,8 +107,8 @@ 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, tcx: TyCtxt<'tcx>) -> TypeWalker<'tcx> { pub fn walk(&'tcx self) -> TypeWalker<'tcx> {
TypeWalker::new(Some(tcx), self.into()) TypeWalker::new(self.into())
} }
} }
@ -129,11 +118,7 @@ impl<'tcx> super::TyS<'tcx> {
/// 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>( fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'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
@ -211,11 +196,7 @@ fn push_inner<'tcx>(
| ty::ConstKind::Error(_) => {} | ty::ConstKind::Error(_) => {}
ty::ConstKind::Unevaluated(ct) => { ty::ConstKind::Unevaluated(ct) => {
if let Some(tcx) = expose_default_const_substs { stack.extend(ct.substs.iter().rev());
stack.extend(ct.substs(tcx).iter().rev());
} else if let Some(substs) = ct.substs_ {
stack.extend(substs.iter().rev());
}
} }
} }
} }

View file

@ -244,10 +244,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(tcx) !(body.local_decls.has_free_regions()
|| body.basic_blocks().has_free_regions(tcx) || body.basic_blocks().has_free_regions()
|| body.var_debug_info.has_free_regions(tcx) || body.var_debug_info.has_free_regions()
|| body.yield_ty().has_free_regions(tcx)), || body.yield_ty().has_free_regions()),
"Unexpected free regions in MIR: {:?}", "Unexpected free regions in MIR: {:?}",
body, body,
); );
@ -760,7 +760,6 @@ 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,
@ -849,7 +848,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
} }
Body::new( Body::new(
self.tcx,
MirSource::item(self.def_id), MirSource::item(self.def_id),
self.cfg.basic_blocks, self.cfg.basic_blocks,
self.source_scopes, self.source_scopes,

View file

@ -716,10 +716,11 @@ 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::new( val: ty::ConstKind::Unevaluated(ty::Unevaluated {
ty::WithOptConstParam::unknown(did), def: 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)));
@ -911,10 +912,11 @@ 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::new( val: ty::ConstKind::Unevaluated(ty::Unevaluated {
ty::WithOptConstParam::unknown(def_id), def: ty::WithOptConstParam::unknown(def_id),
substs, substs,
)), promoted: None,
}),
ty: self.typeck_results().node_type(expr.hir_id), ty: self.typeck_results().node_type(expr.hir_id),
}), }),
user_ty, user_ty,

View file

@ -240,7 +240,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(self.tcx()).any(|t| match t.unpack() { || ty.walk().any(|t| match t.unpack() {
ty::subst::GenericArgKind::Lifetime(_) => false, ty::subst::GenericArgKind::Lifetime(_) => false,
ty::subst::GenericArgKind::Type(t) => t.is_fn_ptr(), ty::subst::GenericArgKind::Type(t) => t.is_fn_ptr(),
ty::subst::GenericArgKind::Const(_) => false, ty::subst::GenericArgKind::Const(_) => false,

View file

@ -126,7 +126,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(tcx) { Some(*p) } else { None }); .filter_map(|(p, _)| if p.is_global() { 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(),
@ -138,7 +138,6 @@ 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(),
@ -475,7 +474,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.definitely_needs_subst(self.tcx) { if c.needs_subst() {
return None; return None;
} }
@ -490,14 +489,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.definitely_needs_subst(*tcx), _ => c.literal.needs_subst(),
}, },
ConstantKind::Val(_, ty) => ty.definitely_needs_subst(*tcx), ConstantKind::Val(_, ty) => ty.needs_subst(),
}; };
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
@ -728,7 +727,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.definitely_needs_subst(self.tcx) { if rvalue.needs_subst() {
return None; return None;
} }

View file

@ -49,7 +49,7 @@ impl<'tcx> Visitor<'tcx> for FunctionItemRefChecker<'_, '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(self.tcx) { for generic_inner_ty in arg_ty.walk() {
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<'tcx> FunctionItemRefChecker<'_, '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(self.tcx) { for generic_inner_ty in arg_def.walk() {
if let GenericArgKind::Type(inner_ty) = generic_inner_ty.unpack() { if let GenericArgKind::Type(inner_ty) = generic_inner_ty.unpack() {
// If the inner type matches the type bound by `Pointer` // If the inner type matches the type bound by `Pointer`
if TyS::same_type(inner_ty, bound_ty) { if TyS::same_type(inner_ty, bound_ty) {

View file

@ -89,7 +89,7 @@ crate fn mir_callgraph_reachable<'tcx>(
// 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.definitely_needs_subst(tcx) { if callee.needs_subst() {
continue; continue;
} }
} }

View file

@ -342,7 +342,7 @@ fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -
} }
} }
debug_assert!(!body.has_free_regions(tcx), "Free regions in MIR for CTFE"); debug_assert!(!body.has_free_regions(), "Free regions in MIR for CTFE");
body body
} }
@ -530,7 +530,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(tcx), "Free regions in optimized MIR"); debug_assert!(!body.has_free_regions(), "Free regions in optimized MIR");
body body
} }
@ -557,7 +557,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(tcx), "Free regions in promoted MIR"); debug_assert!(!promoted.has_free_regions(), "Free regions in promoted MIR");
tcx.arena.alloc(promoted) tcx.arena.alloc(promoted)
} }

View file

@ -171,7 +171,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(tcx, source, blocks, local_decls_for_sig(&sig, span), sig.inputs().len(), span); new_body(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.
@ -210,7 +210,6 @@ 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>>,
@ -218,7 +217,6 @@ 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(
@ -362,14 +360,7 @@ impl<'tcx> CloneShimBuilder<'tcx> {
self.def_id, self.def_id,
self.sig.inputs_and_output[0], self.sig.inputs_and_output[0],
)); ));
new_body( new_body(source, self.blocks, self.local_decls, self.sig.inputs().len(), self.span)
self.tcx,
source,
self.blocks,
self.local_decls,
self.sig.inputs().len(),
self.span,
)
} }
fn source_info(&self) -> SourceInfo { fn source_info(&self) -> SourceInfo {
@ -719,14 +710,8 @@ fn build_call_shim<'tcx>(
block(&mut blocks, vec![], TerminatorKind::Resume, true); block(&mut blocks, vec![], TerminatorKind::Resume, true);
} }
let mut body = new_body( let mut body =
tcx, new_body(MirSource::from_instance(instance), blocks, local_decls, sig.inputs().len(), span);
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()));
@ -791,7 +776,6 @@ pub fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> Body<'_> {
let source = MirSource::item(ctor_id); let source = MirSource::item(ctor_id);
let body = new_body( let body = new_body(
tcx,
source, source,
IndexVec::from_elem_n(start_block, 1), IndexVec::from_elem_n(start_block, 1),
local_decls, local_decls,

View file

@ -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(tcx)) .flat_map(|arg| arg.walk())
.filter(|arg| match arg.unpack() { .filter(|arg| match arg.unpack() {
GenericArgKind::Type(_) | GenericArgKind::Const(_) => true, GenericArgKind::Type(_) | GenericArgKind::Const(_) => true,
GenericArgKind::Lifetime(_) => false, GenericArgKind::Lifetime(_) => false,

View file

@ -303,9 +303,7 @@ fn characteristic_def_id_of_mono_item<'tcx>(
// When polymorphization is enabled, methods which do not depend on their generic // When polymorphization is enabled, methods which do not depend on their generic
// parameters, but the self-type of their impl block do will fail to normalize. // parameters, but the self-type of their impl block do will fail to normalize.
if !tcx.sess.opts.debugging_opts.polymorphize if !tcx.sess.opts.debugging_opts.polymorphize || !instance.needs_subst() {
|| !instance.definitely_needs_subst(tcx)
{
// This is a method within an impl, find out what the self-type is: // This is a method within an impl, find out what the self-type is:
let impl_self_ty = tcx.subst_and_normalize_erasing_regions( let impl_self_ty = tcx.subst_and_normalize_erasing_regions(
instance.substs, instance.substs,

View file

@ -277,12 +277,9 @@ 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(level = "debug", skip(self))] #[instrument(level = "debug", 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.potentially_has_param_types_or_consts() { if !c.has_param_types_or_consts() {
return ControlFlow::CONTINUE; return ControlFlow::CONTINUE;
} }
@ -292,7 +289,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,7 +303,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
ty::ConstKind::Unevaluated(uv) ty::ConstKind::Unevaluated(uv)
if matches!(self.tcx.def_kind(uv.def.did), DefKind::AnonConst | DefKind::InlineConst) => if matches!(self.tcx.def_kind(uv.def.did), DefKind::AnonConst | DefKind::InlineConst) =>
{ {
self.visit_child_body(uv.def.did, uv.substs(self.tcx)); self.visit_child_body(uv.def.did, uv.substs);
ControlFlow::CONTINUE ControlFlow::CONTINUE
} }
_ => c.super_visit_with(self), _ => c.super_visit_with(self),
@ -315,7 +312,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
#[instrument(level = "debug", skip(self))] #[instrument(level = "debug", 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.potentially_has_param_types_or_consts() { if !ty.has_param_types_or_consts() {
return ControlFlow::CONTINUE; return ControlFlow::CONTINUE;
} }
@ -343,21 +340,16 @@ 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, 'tcx> { struct HasUsedGenericParams<'a> {
tcx: TyCtxt<'tcx>,
unused_parameters: &'a FiniteBitSet<u32>, unused_parameters: &'a FiniteBitSet<u32>,
} }
impl<'a, 'tcx> TypeVisitor<'tcx> for HasUsedGenericParams<'a, 'tcx> { impl<'a, 'tcx> TypeVisitor<'tcx> for HasUsedGenericParams<'a> {
type BreakTy = (); type BreakTy = ();
fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
Some(self.tcx)
}
#[instrument(level = "debug", skip(self))] #[instrument(level = "debug", 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.potentially_has_param_types_or_consts() { if !c.has_param_types_or_consts() {
return ControlFlow::CONTINUE; return ControlFlow::CONTINUE;
} }
@ -375,7 +367,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for HasUsedGenericParams<'a, 'tcx> {
#[instrument(level = "debug", skip(self))] #[instrument(level = "debug", 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.potentially_has_param_types_or_consts() { if !ty.has_param_types_or_consts() {
return ControlFlow::CONTINUE; return ControlFlow::CONTINUE;
} }

View file

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

View file

@ -245,13 +245,18 @@ impl<'tcx> Key for (DefId, SubstsRef<'tcx>) {
} }
} }
impl<'tcx> Key for (ty::Unevaluated<'tcx, ()>, ty::Unevaluated<'tcx, ()>) { impl<'tcx> Key
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).def.did.krate == LOCAL_CRATE (self.0).0.did.krate == LOCAL_CRATE
} }
fn default_span(&self, tcx: TyCtxt<'_>) -> Span { fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
(self.0).def.did.default_span(tcx) (self.0).0.did.default_span(tcx)
} }
} }

View file

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

View file

@ -317,9 +317,7 @@ impl<'tcx> 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() if impl_trait_ref.is_some() && substs.iter().any(|a| a.has_param_types_or_consts()) {
&& substs.iter().any(|a| a.definitely_has_param_types_or_consts(self.tcx))
{
self = self.path_generic_args( self = self.path_generic_args(
|this| { |this| {
this.path_append_ns( this.path_append_ns(

View file

@ -444,7 +444,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.definitely_needs_subst(tcx) { if trait_ref.needs_infer() && trait_ref.needs_subst() {
bug!( bug!(
"can't orphan check a trait ref with both params and inference variables {:?}", "can't orphan check a trait ref with both params and inference variables {:?}",
trait_ref trait_ref

View file

@ -19,7 +19,7 @@ use rustc_middle::thir::abstract_const::{self, Node, NodeId, NotConstEvaluatable
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::LocalDefId; use rustc_span::def_id::{DefId, LocalDefId};
use rustc_span::Span; use rustc_span::Span;
use std::cmp; use std::cmp;
@ -29,20 +29,26 @@ 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>,
uv: ty::Unevaluated<'tcx, ()>, def: ty::WithOptConstParam<DefId>,
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({:?})", uv); debug!("is_const_evaluatable({:?}, {:?})", def, substs);
if infcx.tcx.features().generic_const_exprs { if infcx.tcx.features().generic_const_exprs {
let tcx = infcx.tcx; let tcx = infcx.tcx;
match AbstractConst::new(tcx, uv)? { match AbstractConst::new(tcx, def, substs)? {
// 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(uv) => { ty::PredicateKind::ConstEvaluatable(b_def, b_substs) => {
if let Some(b_ct) = AbstractConst::new(tcx, uv)? { if b_def == def && b_substs == substs {
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`
@ -84,7 +90,7 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
Node::Leaf(leaf) => { Node::Leaf(leaf) => {
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.definitely_has_param_types_or_consts(tcx) { } else if leaf.has_param_types_or_consts() {
failure_kind = cmp::min(failure_kind, FailureKind::MentionsParam); failure_kind = cmp::min(failure_kind, FailureKind::MentionsParam);
} }
@ -93,7 +99,7 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
Node::Cast(_, _, ty) => { Node::Cast(_, _, ty) => {
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.definitely_has_param_types_or_consts(tcx) { } else if ty.has_param_types_or_consts() {
failure_kind = cmp::min(failure_kind, FailureKind::MentionsParam); failure_kind = cmp::min(failure_kind, FailureKind::MentionsParam);
} }
@ -126,7 +132,7 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
} }
let future_compat_lint = || { let future_compat_lint = || {
if let Some(local_def_id) = uv.def.did.as_local() { if let Some(local_def_id) = 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),
@ -147,12 +153,16 @@ 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(param_env, uv.expand(), Some(span)); let concrete = infcx.const_eval_resolve(
param_env,
ty::Unevaluated { def, substs, promoted: None },
Some(span),
);
if concrete.is_ok() && uv.substs(infcx.tcx).definitely_has_param_types_or_consts(infcx.tcx) { if concrete.is_ok() && substs.has_param_types_or_consts() {
match infcx.tcx.def_kind(uv.def.did) { match infcx.tcx.def_kind(def.did) {
DefKind::AnonConst | DefKind::InlineConst => { DefKind::AnonConst | DefKind::InlineConst => {
let mir_body = infcx.tcx.mir_for_ctfe_opt_const_arg(uv.def); let mir_body = infcx.tcx.mir_for_ctfe_opt_const_arg(def);
if mir_body.is_polymorphic { if mir_body.is_polymorphic {
future_compat_lint(); future_compat_lint();
@ -164,7 +174,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 uv.has_infer_types_or_consts() { Err(ErrorHandled::TooGeneric) => Err(match substs.has_infer_types_or_consts() {
true => NotConstEvaluatable::MentionsInfer, true => NotConstEvaluatable::MentionsInfer,
false => NotConstEvaluatable::MentionsParam, false => NotConstEvaluatable::MentionsParam,
}), }),
@ -192,11 +202,12 @@ pub struct AbstractConst<'tcx> {
impl<'tcx> AbstractConst<'tcx> { impl<'tcx> AbstractConst<'tcx> {
pub fn new( pub fn new(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
uv: ty::Unevaluated<'tcx, ()>, def: ty::WithOptConstParam<DefId>,
substs: SubstsRef<'tcx>,
) -> Result<Option<AbstractConst<'tcx>>, ErrorReported> { ) -> Result<Option<AbstractConst<'tcx>>, ErrorReported> {
let inner = tcx.thir_abstract_const_opt_const_arg(uv.def)?; let inner = tcx.thir_abstract_const_opt_const_arg(def)?;
debug!("AbstractConst::new({:?}) = {:?}", uv, inner); debug!("AbstractConst::new({:?}, {:?}) = {:?}", def, substs, inner);
Ok(inner.map(|inner| AbstractConst { inner, substs: uv.substs(tcx) })) Ok(inner.map(|inner| AbstractConst { inner, substs }))
} }
pub fn from_const( pub fn from_const(
@ -204,7 +215,9 @@ impl<'tcx> 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(uv) => AbstractConst::new(tcx, uv.shrink()), ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted: _ }) => {
AbstractConst::new(tcx, def, substs)
}
ty::ConstKind::Error(_) => Err(ErrorReported), ty::ConstKind::Error(_) => Err(ErrorReported),
_ => Ok(None), _ => Ok(None),
} }
@ -271,7 +284,6 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
struct IsThirPolymorphic<'a, 'tcx> { struct IsThirPolymorphic<'a, 'tcx> {
is_poly: bool, is_poly: bool,
thir: &'a thir::Thir<'tcx>, thir: &'a thir::Thir<'tcx>,
tcx: TyCtxt<'tcx>,
} }
use thir::visit; use thir::visit;
@ -281,25 +293,25 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
} }
fn visit_expr(&mut self, expr: &thir::Expr<'tcx>) { fn visit_expr(&mut self, expr: &thir::Expr<'tcx>) {
self.is_poly |= expr.ty.definitely_has_param_types_or_consts(self.tcx); self.is_poly |= expr.ty.has_param_types_or_consts();
if !self.is_poly { if !self.is_poly {
visit::walk_expr(self, expr) visit::walk_expr(self, expr)
} }
} }
fn visit_pat(&mut self, pat: &thir::Pat<'tcx>) { fn visit_pat(&mut self, pat: &thir::Pat<'tcx>) {
self.is_poly |= pat.ty.definitely_has_param_types_or_consts(self.tcx); self.is_poly |= pat.ty.has_param_types_or_consts();
if !self.is_poly { if !self.is_poly {
visit::walk_pat(self, pat); visit::walk_pat(self, pat);
} }
} }
fn visit_const(&mut self, ct: &'tcx ty::Const<'tcx>) { fn visit_const(&mut self, ct: &'tcx ty::Const<'tcx>) {
self.is_poly |= ct.definitely_has_param_types_or_consts(self.tcx); self.is_poly |= ct.has_param_types_or_consts();
} }
} }
let mut is_poly_vis = IsThirPolymorphic { is_poly: false, thir: body, tcx }; let mut is_poly_vis = IsThirPolymorphic { is_poly: false, thir: body };
visit::walk_expr(&mut is_poly_vis, &body[body_id]); visit::walk_expr(&mut is_poly_vis, &body[body_id]);
debug!("AbstractConstBuilder: is_poly={}", is_poly_vis.is_poly); debug!("AbstractConstBuilder: is_poly={}", is_poly_vis.is_poly);
if !is_poly_vis.is_poly { if !is_poly_vis.is_poly {
@ -527,11 +539,14 @@ pub(super) fn thir_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, b): (ty::Unevaluated<'tcx, ()>, ty::Unevaluated<'tcx, ()>), ((a, a_substs), (b, b_substs)): (
(ty::WithOptConstParam<DefId>, SubstsRef<'tcx>),
(ty::WithOptConstParam<DefId>, SubstsRef<'tcx>),
),
) -> bool { ) -> bool {
(|| { (|| {
if let Some(a) = AbstractConst::new(tcx, a)? { if let Some(a) = AbstractConst::new(tcx, a, a_substs)? {
if let Some(b) = AbstractConst::new(tcx, b)? { if let Some(b) = AbstractConst::new(tcx, b, b_substs)? {
return Ok(try_unify(tcx, a, b)); return Ok(try_unify(tcx, a, b));
} }
} }

View file

@ -819,10 +819,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(uv) => { ty::PredicateKind::ConstEvaluatable(def, _) => {
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(uv.def.did); let const_span = self.tcx.def_span(def.did);
match self.tcx.sess.source_map().span_to_snippet(const_span) { match self.tcx.sess.source_map().span_to_snippet(const_span) {
Ok(snippet) => err.help(&format!( Ok(snippet) => err.help(&format!(
"try adding a `where` bound using this expression: `where [(); {}]:`", "try adding a `where` bound using this expression: `where [(); {}]:`",

View file

@ -527,10 +527,11 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
} }
} }
ty::PredicateKind::ConstEvaluatable(uv) => { ty::PredicateKind::ConstEvaluatable(def_id, substs) => {
match const_evaluatable::is_const_evaluatable( match const_evaluatable::is_const_evaluatable(
self.selcx.infcx(), self.selcx.infcx(),
uv, def_id,
substs,
obligation.param_env, obligation.param_env,
obligation.cause.span, obligation.cause.span,
) { ) {
@ -538,9 +539,7 @@ 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(
uv.substs(infcx.tcx) substs.iter().filter_map(TyOrConstInferVar::maybe_from_generic_arg),
.iter()
.filter_map(TyOrConstInferVar::maybe_from_generic_arg),
); );
ProcessResult::Unchanged ProcessResult::Unchanged
} }
@ -564,7 +563,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.shrink(), b.shrink()) { if infcx.try_unify_abstract_consts(a, b) {
return ProcessResult::Changed(vec![]); return ProcessResult::Changed(vec![]);
} }
} }
@ -583,7 +582,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> {
Err(ErrorHandled::TooGeneric) => { Err(ErrorHandled::TooGeneric) => {
stalled_on.extend( stalled_on.extend(
unevaluated unevaluated
.substs(tcx) .substs
.iter() .iter()
.filter_map(TyOrConstInferVar::maybe_from_generic_arg), .filter_map(TyOrConstInferVar::maybe_from_generic_arg),
); );
@ -654,7 +653,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_known_global() { if obligation.predicate.is_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.
if infcx.predicate_must_hold_considering_regions(obligation) { if infcx.predicate_must_hold_considering_regions(obligation) {
@ -708,7 +707,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(tcx) { if obligation.predicate.is_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.
if self.selcx.infcx().predicate_must_hold_considering_regions(obligation) { if self.selcx.infcx().predicate_must_hold_considering_regions(obligation) {
@ -756,15 +755,14 @@ 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(move |arg| { .flat_map(|arg| {
let mut walker = arg.walk(tcx); let mut walker = arg.walk();
while let Some(c) = walker.next() { while let Some(c) = walker.next() {
if !c.has_infer_types_or_consts() { if !c.has_infer_types_or_consts() {
walker.visited.remove(&c); walker.visited.remove(&c);

View file

@ -465,7 +465,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.definitely_needs_subst(tcx)); predicates.retain(|predicate| !predicate.needs_subst());
let result = impossible_predicates(tcx, predicates); let result = impossible_predicates(tcx, predicates);
debug!("subst_and_check_impossible_predicates(key={:?}) = {:?}", key, result); debug!("subst_and_check_impossible_predicates(key={:?}) = {:?}", key, result);

View file

@ -274,7 +274,7 @@ fn predicate_references_self<'tcx>(
(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<'tcx>| arg.walk(tcx).any(|arg| arg == self_ty.into()); let has_self_ty = |arg: &GenericArg<'_>| arg.walk().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.
@ -768,9 +768,6 @@ 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() {
@ -816,10 +813,9 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>(
} }
} }
fn visit_unevaluated_const( fn visit_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
&mut self, self.visit_ty(ct.ty)?;
uv: ty::Unevaluated<'tcx>,
) -> ControlFlow<Self::BreakTy> {
// Constants can only influence object safety if they reference `Self`. // Constants can only influence object safety if they reference `Self`.
// This is only possible for unevaluated constants, so we walk these here. // This is only possible for unevaluated constants, so we walk these here.
// //
@ -833,7 +829,7 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>(
// This shouldn't really matter though as we can't really use any // This shouldn't really matter though as we can't really use any
// constants which are not considered const evaluatable. // constants which are not considered const evaluatable.
use rustc_middle::thir::abstract_const::Node; use rustc_middle::thir::abstract_const::Node;
if let Ok(Some(ct)) = AbstractConst::new(self.tcx, uv.shrink()) { if let Ok(Some(ct)) = AbstractConst::from_const(self.tcx, ct) {
const_evaluatable::walk_abstract_const(self.tcx, ct, |node| { const_evaluatable::walk_abstract_const(self.tcx, ct, |node| {
match node.root(self.tcx) { match node.root(self.tcx) {
Node::Leaf(leaf) => self.visit_const(leaf), Node::Leaf(leaf) => self.visit_const(leaf),
@ -847,6 +843,30 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeFoldable<'tcx>>(
ControlFlow::CONTINUE ControlFlow::CONTINUE
} }
} }
fn visit_predicate(&mut self, pred: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
if let ty::PredicateKind::ConstEvaluatable(def, substs) = pred.kind().skip_binder() {
// FIXME(generic_const_exprs): We should probably deduplicate the logic for
// `AbstractConst`s here, it might make sense to change `ConstEvaluatable` to
// take a `ty::Const` instead.
use rustc_middle::thir::abstract_const::Node;
if let Ok(Some(ct)) = AbstractConst::new(self.tcx, def, substs) {
const_evaluatable::walk_abstract_const(self.tcx, ct, |node| {
match node.root(self.tcx) {
Node::Leaf(leaf) => self.visit_const(leaf),
Node::Cast(_, _, ty) => self.visit_ty(ty),
Node::Binop(..) | Node::UnaryOp(..) | Node::FunctionCall(_, _) => {
ControlFlow::CONTINUE
}
}
})
} else {
ControlFlow::CONTINUE
}
} else {
pred.super_visit_with(self)
}
}
} }
value value

View file

@ -77,11 +77,8 @@ 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 = MaxEscapingBoundVarVisitor { let mut max_visitor =
tcx: self.infcx.tcx, MaxEscapingBoundVarVisitor { outer_index: ty::INNERMOST, escaping: 0 };
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));
@ -104,18 +101,13 @@ 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<'tcx> { struct MaxEscapingBoundVarVisitor {
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<'tcx> { impl<'tcx> TypeVisitor<'tcx> for MaxEscapingBoundVarVisitor {
fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
Some(self.tcx)
}
fn visit_binder<T: TypeFoldable<'tcx>>( fn visit_binder<T: TypeFoldable<'tcx>>(
&mut self, &mut self,
t: &ty::Binder<'tcx, T>, t: &ty::Binder<'tcx, T>,

View file

@ -997,7 +997,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let tail_field_ty = tcx.type_of(tail_field.did); let tail_field_ty = tcx.type_of(tail_field.did);
let mut unsizing_params = GrowableBitSet::new_empty(); let mut unsizing_params = GrowableBitSet::new_empty();
for arg in tail_field_ty.walk(tcx) { for arg in tail_field_ty.walk() {
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);
} }
@ -1006,7 +1006,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(tcx) { for arg in tcx.type_of(field.did).walk() {
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);
} }

View file

@ -526,7 +526,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// contain the "'static" lifetime (any other lifetime // contain the "'static" lifetime (any other lifetime
// would either be late-bound or local), so it is guaranteed // would either be late-bound or local), so it is guaranteed
// to outlive any other lifetime // to outlive any other lifetime
if pred.0.is_global(self.infcx.tcx) && !pred.0.has_late_bound_regions() { if pred.0.is_global() && !pred.0.has_late_bound_regions() {
Ok(EvaluatedToOk) Ok(EvaluatedToOk)
} else { } else {
Ok(EvaluatedToOkModuloRegions) Ok(EvaluatedToOkModuloRegions)
@ -619,10 +619,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
} }
} }
ty::PredicateKind::ConstEvaluatable(uv) => { ty::PredicateKind::ConstEvaluatable(def_id, substs) => {
match const_evaluatable::is_const_evaluatable( match const_evaluatable::is_const_evaluatable(
self.infcx, self.infcx,
uv, def_id,
substs,
obligation.param_env, obligation.param_env,
obligation.cause.span, obligation.cause.span,
) { ) {
@ -644,7 +645,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.shrink(), b.shrink()) { if self.infcx.try_unify_abstract_consts(a, b) {
return Ok(EvaluatedToOk); return Ok(EvaluatedToOk);
} }
} }
@ -711,12 +712,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
mut obligation: TraitObligation<'tcx>, mut obligation: TraitObligation<'tcx>,
) -> Result<EvaluationResult, OverflowError> { ) -> Result<EvaluationResult, OverflowError> {
if !self.intercrate if !self.intercrate
&& obligation.is_global(self.tcx()) && obligation.is_global()
&& obligation && obligation.param_env.caller_bounds().iter().all(|bound| bound.needs_subst())
.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
@ -1535,7 +1532,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 = |cand: &ty::PolyTraitPredicate<'tcx>| { let is_global = |cand: &ty::PolyTraitPredicate<'tcx>| {
cand.is_global(self.infcx.tcx) && !cand.has_late_bound_regions() cand.is_global() && !cand.has_late_bound_regions()
}; };
// (*) Prefer `BuiltinCandidate { has_nested: false }`, `PointeeCandidate`, // (*) Prefer `BuiltinCandidate { has_nested: false }`, `PointeeCandidate`,

View file

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

View file

@ -131,9 +131,8 @@ 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(uv) => { ty::PredicateKind::ConstEvaluatable(def, substs) => {
let substs = uv.substs(wf.tcx()); let obligations = wf.nominal_obligations(def.did, substs);
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() {
@ -429,7 +428,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(self.tcx()); let mut walker = arg.walk();
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() {
@ -442,17 +441,15 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
GenericArgKind::Const(constant) => { GenericArgKind::Const(constant) => {
match constant.val { match constant.val {
ty::ConstKind::Unevaluated(uv) => { ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) => {
assert!(uv.promoted.is_none()); assert!(promoted.is_none());
let substs = uv.substs(self.tcx());
let obligations = self.nominal_obligations(uv.def.did, substs); let obligations = self.nominal_obligations(def.did, substs);
self.out.extend(obligations); self.out.extend(obligations);
let predicate = ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable( let predicate =
ty::Unevaluated::new(uv.def, substs), ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(def, substs))
)) .to_predicate(self.tcx());
.to_predicate(self.tcx());
let cause = self.cause(traits::MiscObligation); let cause = self.cause(traits::MiscObligation);
self.out.push(traits::Obligation::with_depth( self.out.push(traits::Obligation::with_depth(
cause, cause,

View file

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

View file

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

View file

@ -157,16 +157,6 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
predicates.extend(environment); predicates.extend(environment);
} }
// It's important that we include the default substs in unevaluated
// constants, since `Unevaluated` instances in predicates whose substs are None
// can lead to "duplicate" caller bounds candidates during trait selection,
// duplicate in the sense that both have their default substs, but the
// candidate that resulted from a superpredicate still uses `None` in its
// `substs_` field of `Unevaluated` to indicate that it has its default substs,
// whereas the other candidate has `substs_: Some(default_substs)`, see
// issue #89334
predicates = tcx.expose_default_const_substs(predicates);
let local_did = def_id.as_local(); let local_did = def_id.as_local();
let hir_id = local_did.map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id)); let hir_id = local_did.map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id));
@ -334,7 +324,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(tcx)); inputs.extend(self_ty.walk());
} }
// 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
@ -343,7 +333,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(tcx))); inputs.extend(fn_sig.inputs().iter().flat_map(|ty| ty.walk()));
} }
NodeKind::Other => (), NodeKind::Other => (),

View file

@ -19,116 +19,94 @@ 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_KNOWN_TY_PARAM = 1 << 0; const HAS_TY_PARAM = 1 << 0;
/// Does this have `ReEarlyBound`? /// Does this have `ReEarlyBound`?
const HAS_KNOWN_RE_PARAM = 1 << 1; const HAS_RE_PARAM = 1 << 1;
/// Does this have `ConstKind::Param`? /// Does this have `ConstKind::Param`?
const HAS_KNOWN_CT_PARAM = 1 << 2; const HAS_CT_PARAM = 1 << 2;
const KNOWN_NEEDS_SUBST = TypeFlags::HAS_KNOWN_TY_PARAM.bits const NEEDS_SUBST = TypeFlags::HAS_TY_PARAM.bits
| TypeFlags::HAS_KNOWN_RE_PARAM.bits | TypeFlags::HAS_RE_PARAM.bits
| TypeFlags::HAS_KNOWN_CT_PARAM.bits; | TypeFlags::HAS_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_KNOWN_FREE_LOCAL_REGIONS = 1 << 9; const HAS_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_KNOWN_FREE_LOCAL_NAMES = TypeFlags::HAS_KNOWN_TY_PARAM.bits const HAS_FREE_LOCAL_NAMES = TypeFlags::HAS_TY_PARAM.bits
| TypeFlags::HAS_KNOWN_CT_PARAM.bits | TypeFlags::HAS_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_KNOWN_FREE_LOCAL_REGIONS.bits; | TypeFlags::HAS_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_KNOWN_FREE_REGIONS = 1 << 14; const HAS_FREE_REGIONS = 1 << 14;
const HAS_POTENTIAL_FREE_REGIONS = TypeFlags::HAS_KNOWN_FREE_REGIONS.bits
| TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS.bits;
/// Does this have any `ReLateBound` regions? Used to check /// Does this have any `ReLateBound` regions? Used to check
/// if a global bound is safe to evaluate. /// if a global bound is safe to evaluate.
const HAS_RE_LATE_BOUND = 1 << 15; const HAS_RE_LATE_BOUND = 1 << 15;
/// Does this have any `ReErased` regions? /// Does this have any `ReErased` regions?
const HAS_RE_ERASED = 1 << 16; const HAS_RE_ERASED = 1 << 16;
/// Does this value have parameters/placeholders/inference variables which could be /// Does this value have parameters/placeholders/inference variables which could be
/// replaced later, in a way that would change the results of `impl` specialization? /// replaced later, in a way that would change the results of `impl` specialization?
/// const STILL_FURTHER_SPECIALIZABLE = 1 << 17;
/// Note that this flag being set is not a guarantee, as it is also
/// set if there are any anon consts with unknown default substs.
const STILL_FURTHER_SPECIALIZABLE = 1 << 17;
/// Does this value have `InferTy::FreshTy/FreshIntTy/FreshFloatTy`? /// Does this value have `InferTy::FreshTy/FreshIntTy/FreshFloatTy`?
const HAS_TY_FRESH = 1 << 18; const HAS_TY_FRESH = 1 << 18;
/// Does this value have `InferConst::Fresh`? /// Does this value have `InferConst::Fresh`?
const HAS_CT_FRESH = 1 << 19; const HAS_CT_FRESH = 1 << 19;
/// Does this value have unknown default anon const substs.
///
/// For more details refer to...
/// FIXME(@lcnr): ask me for now, still have to write all of this.
const HAS_UNKNOWN_DEFAULT_CONST_SUBSTS = 1 << 20;
/// Flags which can be influenced by default anon const substs.
const MAY_NEED_DEFAULT_CONST_SUBSTS = TypeFlags::HAS_KNOWN_RE_PARAM.bits
| TypeFlags::HAS_KNOWN_TY_PARAM.bits
| TypeFlags::HAS_KNOWN_CT_PARAM.bits
| TypeFlags::HAS_KNOWN_FREE_LOCAL_REGIONS.bits
| TypeFlags::HAS_KNOWN_FREE_REGIONS.bits;
} }
} }

View file

@ -388,7 +388,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(tcx).any(|arg| arg == self_param.into()) { if default_ty.walk().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;
@ -1370,7 +1370,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(tcx).any(|arg| arg == dummy_self.into()); pred.skip_binder().ty.walk().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.
@ -2216,7 +2216,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.definitely_needs_subst(tcx) { if forbid_generic && normalized_ty.needs_subst() {
let mut err = tcx.sess.struct_span_err( let mut err = tcx.sess.struct_span_err(
path.span, path.span,
"generic `Self` types are currently not permitted in anonymous constants", "generic `Self` types are currently not permitted in anonymous constants",

View file

@ -462,17 +462,14 @@ pub(super) fn check_opaque_for_inheriting_lifetimes<'tcx>(
debug!(?item, ?span); debug!(?item, ?span);
struct FoundParentLifetime; struct FoundParentLifetime;
struct FindParentLifetimeVisitor<'tcx>(TyCtxt<'tcx>, &'tcx ty::Generics); struct FindParentLifetimeVisitor<'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.1.parent_count as u32 { if *index < self.0.parent_count as u32 {
return ControlFlow::Break(FoundParentLifetime); return ControlFlow::Break(FoundParentLifetime);
} else { } else {
return ControlFlow::CONTINUE; return ControlFlow::CONTINUE;
@ -494,24 +491,21 @@ pub(super) fn check_opaque_for_inheriting_lifetimes<'tcx>(
} }
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.tcx, self.generics)) t.super_visit_with(&mut FindParentLifetimeVisitor(self.generics))
.map_break(|FoundParentLifetime| t) .map_break(|FoundParentLifetime| t)
} }
} }
@ -1381,7 +1375,7 @@ pub(super) fn check_type_params_are_used<'tcx>(
return; return;
} }
for leaf in ty.walk(tcx) { for leaf in ty.walk() {
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);
@ -1477,12 +1471,8 @@ fn opaque_type_cycle_error(tcx: TyCtxt<'_>, 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 OpaqueTypeCollector(Vec<DefId>); struct VisitTypes(Vec<DefId>);
impl<'tcx> ty::fold::TypeVisitor<'tcx> for OpaqueTypeCollector { impl<'tcx> ty::fold::TypeVisitor<'tcx> for VisitTypes {
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, _) => {
@ -1493,7 +1483,7 @@ fn opaque_type_cycle_error(tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span) {
} }
} }
} }
let mut visitor = OpaqueTypeCollector(vec![]); let mut visitor = VisitTypes(vec![]);
ty.visit_with(&mut visitor); ty.visit_with(&mut visitor);
for def_id in visitor.0 { for def_id in visitor.0 {
let ty_span = tcx.def_span(def_id); let ty_span = tcx.def_span(def_id);

View file

@ -237,9 +237,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(a), ty::PredicateKind::ConstEvaluatable(a_def, a_substs),
ty::PredicateKind::ConstEvaluatable(b), ty::PredicateKind::ConstEvaluatable(b_def, b_substs),
) => tcx.try_unify_abstract_consts((a, b)), ) => tcx.try_unify_abstract_consts(((a_def, a_substs), (b_def, b_substs))),
( (
ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty_a, lt_a)), ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty_a, lt_a)),
ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty_b, lt_b)), ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty_b, lt_b)),

View file

@ -235,7 +235,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) { ) {
debug!("fcx {}", self.tag()); debug!("fcx {}", 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 },
@ -489,7 +489,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);
@ -541,11 +541,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>(&self, t: T) -> bool fn can_contain_user_lifetime_bounds<T>(t: T) -> bool
where where
T: TypeFoldable<'tcx>, T: TypeFoldable<'tcx>,
{ {
t.has_free_regions(self.tcx) || t.has_projections() || t.has_infer_types() t.has_free_regions() || t.has_projections() || t.has_infer_types()
} }
pub fn node_ty(&self, id: hir::HirId) -> Ty<'tcx> { pub fn node_ty(&self, id: hir::HirId) -> Ty<'tcx> {

View file

@ -1036,7 +1036,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(self.tcx).any(|arg| arg == self_) { Some(i) } else { None } if ty.walk().any(|arg| arg == self_) { Some(i) } else { None }
}) })
.collect::<Vec<usize>>(); .collect::<Vec<usize>>();

View file

@ -423,7 +423,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(self.tcx, vec![]); let mut visitor = TypeParamVisitor(vec![]);
visitor.visit_ty(lhs_ty); visitor.visit_ty(lhs_ty);
if op.node == hir::BinOpKind::Add if op.node == hir::BinOpKind::Add
@ -434,7 +434,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.1[..] { } else if let [ty] = &visitor.0[..] {
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
@ -991,15 +991,12 @@ fn suggest_constraining_param(
} }
} }
struct TypeParamVisitor<'tcx>(TyCtxt<'tcx>, Vec<Ty<'tcx>>); struct TypeParamVisitor<'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.1.push(ty); self.0.push(ty);
} }
ty.super_visit_with(self) ty.super_visit_with(self)
} }

View file

@ -311,7 +311,7 @@ fn check_gat_where_clauses(
// of the function signature. In our example, the GAT in the return // of the function signature. In our example, the GAT in the return
// type is `<Self as LendingIterator>::Item<'a>`, so 'a and Self are arguments. // type is `<Self as LendingIterator>::Item<'a>`, so 'a and Self are arguments.
let (regions, types) = let (regions, types) =
GATSubstCollector::visit(tcx, trait_item.def_id.to_def_id(), sig.output()); GATSubstCollector::visit(trait_item.def_id.to_def_id(), sig.output());
// If both regions and types are empty, then this GAT isn't in the // If both regions and types are empty, then this GAT isn't in the
// return type, and we shouldn't try to do clause analysis // return type, and we shouldn't try to do clause analysis
@ -600,7 +600,6 @@ fn region_known_to_outlive<'tcx>(
/// the two vectors, `regions` and `types` (depending on their kind). For each /// the two vectors, `regions` and `types` (depending on their kind). For each
/// parameter `Pi` also track the index `i`. /// parameter `Pi` also track the index `i`.
struct GATSubstCollector<'tcx> { struct GATSubstCollector<'tcx> {
tcx: TyCtxt<'tcx>,
gat: DefId, gat: DefId,
// Which region appears and which parameter index its subsituted for // Which region appears and which parameter index its subsituted for
regions: FxHashSet<(ty::Region<'tcx>, usize)>, regions: FxHashSet<(ty::Region<'tcx>, usize)>,
@ -610,16 +609,11 @@ struct GATSubstCollector<'tcx> {
impl<'tcx> GATSubstCollector<'tcx> { impl<'tcx> GATSubstCollector<'tcx> {
fn visit<T: TypeFoldable<'tcx>>( fn visit<T: TypeFoldable<'tcx>>(
tcx: TyCtxt<'tcx>,
gat: DefId, gat: DefId,
t: T, t: T,
) -> (FxHashSet<(ty::Region<'tcx>, usize)>, FxHashSet<(Ty<'tcx>, usize)>) { ) -> (FxHashSet<(ty::Region<'tcx>, usize)>, FxHashSet<(Ty<'tcx>, usize)>) {
let mut visitor = GATSubstCollector { let mut visitor =
tcx, GATSubstCollector { gat, regions: FxHashSet::default(), types: FxHashSet::default() };
gat,
regions: FxHashSet::default(),
types: FxHashSet::default(),
};
t.visit_with(&mut visitor); t.visit_with(&mut visitor);
(visitor.regions, visitor.types) (visitor.regions, visitor.types)
} }
@ -647,10 +641,6 @@ impl<'tcx> TypeVisitor<'tcx> for GATSubstCollector<'tcx> {
} }
t.super_visit_with(self) t.super_visit_with(self)
} }
fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
Some(self.tcx)
}
} }
fn could_be_self(trait_def_id: LocalDefId, ty: &hir::Ty<'_>) -> bool { fn could_be_self(trait_def_id: LocalDefId, ty: &hir::Ty<'_>) -> bool {
@ -982,10 +972,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::Binder::dummy(ty::PredicateKind::ConstEvaluatable(ty::Unevaluated::new( ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(
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),
)); ));
} }
@ -1197,7 +1187,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.definitely_needs_subst(tcx) { if !ty.needs_subst() {
fcx.register_wf_obligation( fcx.register_wf_obligation(
ty.into(), ty.into(),
tcx.def_span(param.def_id), tcx.def_span(param.def_id),
@ -1213,7 +1203,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.definitely_needs_subst(tcx) { if !default_ct.needs_subst() {
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),
@ -1247,7 +1237,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.definitely_needs_subst(tcx) { if !default_ty.needs_subst() {
// ... then substitute it with the default. // ... then substitute it with the default.
return default_ty.into(); return default_ty.into();
} }
@ -1260,7 +1250,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.definitely_needs_subst(tcx) { if !default_ct.needs_subst() {
// ... then substitute it with the default. // ... then substitute it with the default.
return default_ct.into(); return default_ct.into();
} }
@ -1276,15 +1266,12 @@ fn check_where_clauses<'tcx, 'fcx>(
.predicates .predicates
.iter() .iter()
.flat_map(|&(pred, sp)| { .flat_map(|&(pred, sp)| {
struct CountParams<'tcx> { #[derive(Default)]
tcx: TyCtxt<'tcx>, struct CountParams {
params: FxHashSet<u32>, params: FxHashSet<u32>,
} }
impl<'tcx> ty::fold::TypeVisitor<'tcx> for CountParams<'tcx> { impl<'tcx> ty::fold::TypeVisitor<'tcx> for CountParams {
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() {
@ -1304,12 +1291,12 @@ fn check_where_clauses<'tcx, 'fcx>(
c.super_visit_with(self) c.super_visit_with(self)
} }
} }
let mut param_count = CountParams { tcx: fcx.tcx, params: FxHashSet::default() }; let mut param_count = CountParams::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.definitely_has_param_types_or_consts(tcx) if substituted_pred.has_param_types_or_consts()
|| param_count.params.len() > 1 || param_count.params.len() > 1
|| has_region || has_region
{ {
@ -1697,7 +1684,7 @@ fn check_false_global_bounds(fcx: &FnCtxt<'_, '_>, mut span: Span, id: hir::HirI
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(fcx.tcx) && !pred.has_late_bound_regions() { if pred.is_global() && !pred.has_late_bound_regions() {
let pred = fcx.normalize_associated_types_in(span, pred); let pred = fcx.normalize_associated_types_in(span, pred);
let hir_node = fcx.tcx.hir().find(id); let hir_node = fcx.tcx.hir().find(id);

View file

@ -130,7 +130,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
fn write_ty_to_typeck_results(&mut self, hir_id: hir::HirId, ty: Ty<'tcx>) { fn write_ty_to_typeck_results(&mut self, hir_id: hir::HirId, ty: Ty<'tcx>) {
debug!("write_ty_to_typeck_results({:?}, {:?})", hir_id, ty); debug!("write_ty_to_typeck_results({:?}, {:?})", hir_id, ty);
assert!(!ty.needs_infer() && !ty.has_placeholders() && !ty.has_free_regions(self.tcx())); assert!(!ty.needs_infer() && !ty.has_placeholders() && !ty.has_free_regions());
self.typeck_results.node_types_mut().insert(hir_id, ty); self.typeck_results.node_types_mut().insert(hir_id, ty);
} }
@ -750,7 +750,7 @@ impl<'tcx> TypeFolder<'tcx> for EraseEarlyRegions<'tcx> {
self.tcx self.tcx
} }
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
if ty.has_type_flags(ty::TypeFlags::HAS_POTENTIAL_FREE_REGIONS) { if ty.has_type_flags(ty::TypeFlags::HAS_FREE_REGIONS) {
ty.super_fold_with(self) ty.super_fold_with(self)
} else { } else {
ty ty

View file

@ -67,7 +67,6 @@ 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,
@ -2279,7 +2278,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(tcx, self_ty, trait_ref), &mut cgp::parameters_for_impl(self_ty, trait_ref),
); );
} }
@ -2314,7 +2313,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::Binder::dummy(ty::PredicateKind::ConstEvaluatable(uv.shrink())) ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(uv.def, uv.substs))
.to_predicate(self.tcx), .to_predicate(self.tcx),
span, span,
)); ));

View file

@ -6,7 +6,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::{InternalSubsts, SubstsRef}; use rustc_middle::ty::subst::InternalSubsts;
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;
@ -280,32 +280,6 @@ 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
| ty::TypeFlags::HAS_ERROR;
assert!(!arg.has_type_flags(!allowed_flags));
}
substs
}
pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
let def_id = def_id.expect_local(); let def_id = def_id.expect_local();
use rustc_hir::*; use rustc_hir::*;

View file

@ -27,13 +27,12 @@ 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(tcx, &tr, false), Some(tr) => parameters_for(&tr, false),
None => parameters_for(tcx, &impl_self_ty, false), None => parameters_for(&impl_self_ty, false),
}; };
vec.into_iter().collect() vec.into_iter().collect()
} }
@ -44,26 +43,20 @@ 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 { tcx, parameters: vec![], include_nonconstraining }; let mut collector = ParameterCollector { parameters: vec![], include_nonconstraining };
t.visit_with(&mut collector); t.visit_with(&mut collector);
collector.parameters collector.parameters
} }
struct ParameterCollector<'tcx> { struct ParameterCollector {
tcx: TyCtxt<'tcx>,
parameters: Vec<Parameter>, parameters: Vec<Parameter>,
include_nonconstraining: bool, include_nonconstraining: bool,
} }
impl<'tcx> TypeVisitor<'tcx> for ParameterCollector<'tcx> { impl<'tcx> TypeVisitor<'tcx> for ParameterCollector {
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 => {
@ -205,12 +198,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(tcx, &projection.projection_ty, true); let inputs = parameters_for(&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(tcx, &projection.ty, false)); input_parameters.extend(parameters_for(&projection.ty, false));
} else { } else {
continue; continue;
} }

View file

@ -117,7 +117,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(tcx, impl_self_ty, impl_trait_ref); let mut input_parameters = cgp::parameters_for_impl(impl_self_ty, impl_trait_ref);
cgp::identify_constrained_generic_params( cgp::identify_constrained_generic_params(
tcx, tcx,
impl_predicates, impl_predicates,
@ -134,7 +134,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, &tcx.type_of(def_id), true) cgp::parameters_for(&tcx.type_of(def_id), true)
} else { } else {
Vec::new() Vec::new()
} }

View file

@ -206,15 +206,15 @@ fn unconstrained_parent_impl_substs<'tcx>(
continue; continue;
} }
unconstrained_parameters.extend(cgp::parameters_for(tcx, &projection_ty, true)); unconstrained_parameters.extend(cgp::parameters_for(&projection_ty, true));
for param in cgp::parameters_for(tcx, &projected_ty, false) { for param in cgp::parameters_for(&projected_ty, false) {
if !unconstrained_parameters.contains(&param) { if !unconstrained_parameters.contains(&param) {
constrained_params.insert(param.0); constrained_params.insert(param.0);
} }
} }
unconstrained_parameters.extend(cgp::parameters_for(tcx, &projected_ty, true)); unconstrained_parameters.extend(cgp::parameters_for(&projected_ty, true));
} }
} }
@ -248,7 +248,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(tcx, parent_substs, true); let mut base_params = cgp::parameters_for(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];
@ -376,7 +376,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(tcx) => (), _ if predicate.is_global() => (),
// We allow specializing on explicitly marked traits with no associated // We allow specializing on explicitly marked traits with no associated
// items. // items.
ty::PredicateKind::Trait(ty::TraitPredicate { ty::PredicateKind::Trait(ty::TraitPredicate {

View file

@ -114,18 +114,7 @@ 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>,
) { ) {
// We must not look into the default substs of consts for arg in field_ty.walk() {
// 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(adt_const_params): Once 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,
@ -317,7 +306,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(tcx).any(|arg| arg == self_ty.into()) { if ty.walk().any(|arg| arg == self_ty.into()) {
debug!("skipping self ty = {:?}", &ty); debug!("skipping self ty = {:?}", &ty);
continue; continue;
} }

View file

@ -405,8 +405,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
match &val.val { match &val.val {
ty::ConstKind::Unevaluated(uv) => { ty::ConstKind::Unevaluated(uv) => {
let substs = uv.substs(self.tcx()); self.add_constraints_from_invariant_substs(current, uv.substs, variance);
self.add_constraints_from_invariant_substs(current, substs, variance);
} }
_ => {} _ => {}
} }

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -20,7 +20,7 @@
+ // + val: Unevaluated(main, [], Some(promoted[0])) + // + val: Unevaluated(main, [], Some(promoted[0]))
+ // mir::Constant + // mir::Constant
+ // + span: $DIR/ref_deref_project.rs:5:6: 5:17 + // + span: $DIR/ref_deref_project.rs:5:6: 5:17
+ // + literal: Const { ty: &(i32, i32), val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[HASH]::main), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) } + // + literal: Const { ty: &(i32, i32), val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[HASH]::main), const_param_did: None }, substs: [], 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

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