Skip to content

what is lazy_normalization_consts but a step towards a brighter tomorrow #3

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions compiler/rustc_codegen_cranelift/src/constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ pub(crate) fn check_constants(fx: &mut FunctionCx<'_, '_, impl Module>) {
| ConstKind::Infer(_)
| ConstKind::Bound(_, _)
| ConstKind::Placeholder(_)
| ConstKind::Error(_) => unreachable!("{:?}", const_),
| ConstKind::Error(_)
| ConstKind::Unnormalized(_, _) => unreachable!("{:?}", const_),
}
}
}
Expand Down Expand Up @@ -148,7 +149,8 @@ pub(crate) fn codegen_constant<'tcx>(
| ConstKind::Infer(_)
| ConstKind::Bound(_, _)
| ConstKind::Placeholder(_)
| ConstKind::Error(_) => unreachable!("{:?}", const_),
| ConstKind::Error(_)
| ConstKind::Unnormalized(_, _) => unreachable!("{:?}", const_),
};

codegen_const_value(fx, const_val, const_.ty)
Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_infer/src/infer/freshen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,9 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> {
return ct;
}

ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(_) => {
ty::ConstKind::Bound(..)
| ty::ConstKind::Placeholder(_)
| ty::ConstKind::Unnormalized(_, _) => {
bug!("unexpected const {:?}", ct)
}

Expand Down
63 changes: 60 additions & 3 deletions compiler/rustc_middle/src/ty/consts.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::mir::interpret::ConstValue;
use crate::mir::interpret::{LitToConstInput, Scalar};
use crate::ty::subst::InternalSubsts;
use crate::ty::{self, Ty, TyCtxt};
use crate::ty::{self, Ty, TyCtxt, TypeFolder, TypeFoldable};
use crate::ty::{ParamEnv, ParamEnvAnd};
use rustc_errors::ErrorReported;
use rustc_hir as hir;
Expand Down Expand Up @@ -97,10 +97,9 @@ impl<'tcx> Const<'tcx> {
let name = tcx.hir().name(hir_id);
ty::ConstKind::Param(ty::ParamConst::new(index, name))
}
_ => ty::ConstKind::Unevaluated(
_ => ty::ConstKind::Unnormalized(
def.to_global(),
InternalSubsts::identity_for_item(tcx, def.did.to_def_id()),
None,
),
};

Expand Down Expand Up @@ -201,3 +200,61 @@ impl<'tcx> Const<'tcx> {
.unwrap_or_else(|| bug!("expected usize, got {:#?}", self))
}
}

impl<'tcx> TyCtxt<'tcx> {
pub fn normalize_consts<T: TypeFoldable<'tcx>>(self, value: T) -> T {
value.fold_with(&mut ConstNormalizer::new(self))
}
}

pub struct ConstNormalizer<'tcx> {
tcx: TyCtxt<'tcx>
}

impl ConstNormalizer<'_> {
pub fn new(tcx: TyCtxt<'_>) -> ConstNormalizer<'_> {
ConstNormalizer { tcx }
}
}

impl<'tcx> TypeFolder<'tcx> for ConstNormalizer<'tcx> {
fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
self.tcx
}

fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
if t.flags().intersects(ty::TypeFlags::HAS_CT_UNNORMALIZED) {
t.super_fold_with(self)
} else {
t
}
}

fn fold_const(&mut self, ct: &'tcx Const<'tcx>) -> &'tcx Const<'tcx> {
match ct.val {
ConstKind::Unnormalized(def, substs) => {
match self.tcx.mir_abstract_const_opt_const_arg(def) {
// FIXME(const_evaluatable_checked): Replace the arguments not used
// in the abstract const with dummy ones while keeping everything that is
// used.
Ok(Some(_abstr_ct)) => self.tcx.mk_const(Const {
ty: ct.ty,
val: ConstKind::Unevaluated(def, substs, None)
}),
Ok(None) => {
let dummy_substs = InternalSubsts::for_item(self.tcx, def.did, |param, _| {
match param.kind {
ty::GenericParamDefKind::Lifetime => self.tcx.lifetimes.re_static.into(),
ty::GenericParamDefKind::Type { .. } => self.tcx.types.unit.into(),
ty::GenericParamDefKind::Const => self.tcx.consts.unit.into(), // TODO
}
});
self.tcx.mk_const(Const { ty: ct.ty, val: ConstKind::Unevaluated(def, dummy_substs, None) })
}
Err(_) => self.tcx.const_error(ct.ty),
}
}
_ => ct.super_fold_with(self),
}
}
}
6 changes: 6 additions & 0 deletions compiler/rustc_middle/src/ty/consts/kind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ pub enum ConstKind<'tcx> {
/// A placeholder const - universally quantified higher-ranked const.
Placeholder(ty::PlaceholderConst<'tcx>),

/// An unnormalized unevaluated constant.
///
/// Converted into an unevaluated one as eagerly as possible.
/// The big exception being `type_of` and `predicates_of` where
/// typechecking a constant would cause a cycle error.
Unnormalized(ty::WithOptConstParam<DefId>, SubstsRef<'tcx>),
/// Used in the HIR by using `Unevaluated` everywhere and later normalizing to one of the other
/// variants when the code is monomorphic enough for that.
Unevaluated(ty::WithOptConstParam<DefId>, SubstsRef<'tcx>, Option<Promoted>),
Expand Down
4 changes: 1 addition & 3 deletions compiler/rustc_middle/src/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1371,9 +1371,7 @@ impl<'tcx> TyCtxt<'tcx> {
/// we still evaluate them eagerly.
#[inline]
pub fn lazy_normalization(self) -> bool {
let features = self.features();
// Note: We do not enable lazy normalization for `features.min_const_generics`.
features.const_generics || features.lazy_normalization_consts
false
}

#[inline]
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_middle/src/ty/flags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,10 @@ impl FlagComputation {
fn add_const(&mut self, c: &ty::Const<'_>) {
self.add_ty(c.ty);
match c.val {
ty::ConstKind::Unnormalized(_, substs) => {
self.add_substs(substs);
self.add_flags(TypeFlags::HAS_CT_PROJECTION | TypeFlags::HAS_CT_UNNORMALIZED);
}
ty::ConstKind::Unevaluated(_, substs, _) => {
self.add_substs(substs);
self.add_flags(TypeFlags::HAS_CT_PROJECTION);
Expand Down
15 changes: 9 additions & 6 deletions compiler/rustc_middle/src/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -554,31 +554,34 @@ bitflags! {
const HAS_TY_PROJECTION = 1 << 10;
/// Does this have [Opaque]?
const HAS_TY_OPAQUE = 1 << 11;
/// Does this have [ConstKind::Unevaluated]?
/// Does this have [ConstKind::Unevaluated] or [ConstKind::Unnormalized]?
const HAS_CT_PROJECTION = 1 << 12;

/// Could this type be normalized further?
const HAS_PROJECTION = TypeFlags::HAS_TY_PROJECTION.bits
| TypeFlags::HAS_TY_OPAQUE.bits
| TypeFlags::HAS_CT_PROJECTION.bits;

// Does this have [ConstKind::Unnormalized]?
const HAS_CT_UNNORMALIZED = 1 << 13;

/// Is an error type/const reachable?
const HAS_ERROR = 1 << 13;
const HAS_ERROR = 1 << 14;

/// Does this have any region that "appears free" in the type?
/// Basically anything but [ReLateBound] and [ReErased].
const HAS_FREE_REGIONS = 1 << 14;
const HAS_FREE_REGIONS = 1 << 15;

/// Does this have any [ReLateBound] regions? Used to check
/// if a global bound is safe to evaluate.
const HAS_RE_LATE_BOUND = 1 << 15;
const HAS_RE_LATE_BOUND = 1 << 16;

/// Does this have any [ReErased] regions?
const HAS_RE_ERASED = 1 << 16;
const HAS_RE_ERASED = 1 << 17;

/// Does this value have parameters/placeholders/inference variables which could be
/// replaced later, in a way that would change the results of `impl` specialization?
const STILL_FURTHER_SPECIALIZABLE = 1 << 17;
const STILL_FURTHER_SPECIALIZABLE = 1 << 18;
}
}

Expand Down
13 changes: 13 additions & 0 deletions compiler/rustc_middle/src/ty/print/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -899,6 +899,19 @@ pub trait PrettyPrinter<'tcx>:
}

match ct.val {
ty::ConstKind::Unnormalized(def, _) => {
assert_eq!(self.tcx().def_kind(def.did), DefKind::AnonConst);
if def.is_local() {
let span = self.tcx().def_span(def.did);
if let Ok(snip) = self.tcx().sess.source_map().span_to_snippet(span) {
p!(write("{}", snip))
} else {
print_underscore!()
}
} else {
print_underscore!()
}
}
ty::ConstKind::Unevaluated(def, substs, promoted) => {
if let Some(promoted) = promoted {
p!(print_value_path(def.did, substs));
Expand Down
8 changes: 6 additions & 2 deletions compiler/rustc_middle/src/ty/structural_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1107,8 +1107,11 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ConstKind<'tcx> {
match self {
ty::ConstKind::Infer(ic) => ty::ConstKind::Infer(ic.fold_with(folder)),
ty::ConstKind::Param(p) => ty::ConstKind::Param(p.fold_with(folder)),
ty::ConstKind::Unevaluated(did, substs, promoted) => {
ty::ConstKind::Unevaluated(did, substs.fold_with(folder), promoted)
ty::ConstKind::Unevaluated(def, substs, promoted) => {
ty::ConstKind::Unevaluated(def, substs.fold_with(folder), promoted)
}
ty::ConstKind::Unnormalized(def, substs) => {
ty::ConstKind::Unnormalized(def, substs.fold_with(folder))
}
ty::ConstKind::Value(_)
| ty::ConstKind::Bound(..)
Expand All @@ -1122,6 +1125,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ConstKind<'tcx> {
ty::ConstKind::Infer(ic) => ic.visit_with(visitor),
ty::ConstKind::Param(p) => p.visit_with(visitor),
ty::ConstKind::Unevaluated(_, substs, _) => substs.visit_with(visitor),
ty::ConstKind::Unnormalized(_, substs) => substs.visit_with(visitor),
ty::ConstKind::Value(_)
| ty::ConstKind::Bound(..)
| ty::ConstKind::Placeholder(_)
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_middle/src/ty/walk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,8 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>)
| ty::ConstKind::Value(_)
| ty::ConstKind::Error(_) => {}

ty::ConstKind::Unevaluated(_, substs, _) => {
ty::ConstKind::Unevaluated(_, substs, _)
| ty::ConstKind::Unnormalized(_, substs) => {
stack.extend(substs.iter().rev());
}
}
Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_mir/src/interpret/operand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -549,7 +549,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
let instance = self.resolve(def, substs)?;
return Ok(self.eval_to_allocation(GlobalId { instance, promoted })?.into());
}
ty::ConstKind::Infer(..) | ty::ConstKind::Placeholder(..) => {
ty::ConstKind::Infer(..)
| ty::ConstKind::Placeholder(..)
| ty::ConstKind::Unnormalized(..) => {
span_bug!(self.cur_span(), "const_to_op: Unexpected ConstKind {:?}", val)
}
ty::ConstKind::Value(val_val) => val_val,
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_trait_selection/src/traits/misc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ pub fn can_type_implement_copy(
let span = tcx.def_span(field.did);
let cause = ObligationCause::dummy_with_span(span);
let ctx = traits::FulfillmentContext::new();
match traits::fully_normalize(&infcx, ctx, cause, param_env, ty) {
match traits::fully_normalize(&infcx, ctx, false, cause, param_env, ty) {
Ok(ty) => {
if !infcx.type_is_copy_modulo_regions(param_env, ty, span) {
infringing.push(field);
Expand Down
6 changes: 4 additions & 2 deletions compiler/rustc_trait_selection/src/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ fn do_normalize_predicates<'tcx>(
// we move over to lazy normalization *anyway*.
let fulfill_cx = FulfillmentContext::new_ignoring_regions();
let predicates =
match fully_normalize(&infcx, fulfill_cx, cause, elaborated_env, predicates) {
match fully_normalize(&infcx, fulfill_cx, true, cause, elaborated_env, predicates) {
Ok(predicates) => predicates,
Err(errors) => {
infcx.report_fulfillment_errors(&errors, None, false);
Expand Down Expand Up @@ -383,6 +383,7 @@ pub fn normalize_param_env_or_error<'tcx>(
pub fn fully_normalize<'a, 'tcx, T>(
infcx: &InferCtxt<'a, 'tcx>,
mut fulfill_cx: FulfillmentContext<'tcx>,
lazy_normalization_consts: bool,
cause: ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
value: T,
Expand All @@ -391,7 +392,8 @@ where
T: TypeFoldable<'tcx>,
{
debug!("fully_normalize_with_fulfillcx(value={:?})", value);
let selcx = &mut SelectionContext::new(infcx);
let selcx =
&mut SelectionContext::with_lazy_normalization_consts(infcx, lazy_normalization_consts);
let Normalized { value: normalized_value, obligations } =
project::normalize(selcx, param_env, cause, value);
debug!(
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_trait_selection/src/traits/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
}

fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
if self.selcx.tcx().lazy_normalization() {
if self.selcx.lazy_normalization_consts() {
constant
} else {
let constant = constant.super_fold_with(self);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -843,7 +843,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// by putting it in a query; it would only need the `DefId` as it
// looks at declared field types, not anything substituted.
for field in prefix_fields {
for arg in tcx.type_of(field.did).walk() {
let ty = normalize_with_depth_to(
self,
obligation.param_env,
obligation.cause.clone(),
obligation.recursion_depth + 1,
tcx.type_of(field.did),
&mut nested,
);
for arg in ty.walk() {
if let Some(i) = maybe_unsizing_param_idx(arg) {
if unsizing_params.contains(i) {
return Err(Unimplemented);
Expand Down
28 changes: 28 additions & 0 deletions compiler/rustc_trait_selection/src/traits/select/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,11 @@ pub struct SelectionContext<'cx, 'tcx> {
/// would satisfy it. This avoids crippling inference, basically.
intercrate: bool,

/// Whether we should lazily normalize constants, this is only true
/// while normalizing the predicates as evaluating constants would
/// cause a cycle error there.
lazy_normalization_consts: bool,

intercrate_ambiguity_causes: Option<Vec<IntercrateAmbiguityCause>>,

/// Controls whether or not to filter out negative impls when selecting.
Expand Down Expand Up @@ -216,6 +221,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
infcx,
freshener: infcx.freshener(),
intercrate: false,
lazy_normalization_consts: false,
intercrate_ambiguity_causes: None,
allow_negative_impls: false,
query_mode: TraitQueryMode::Standard,
Expand All @@ -227,6 +233,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
infcx,
freshener: infcx.freshener(),
intercrate: true,
lazy_normalization_consts: false,
intercrate_ambiguity_causes: None,
allow_negative_impls: false,
query_mode: TraitQueryMode::Standard,
Expand All @@ -242,6 +249,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
infcx,
freshener: infcx.freshener(),
intercrate: false,
lazy_normalization_consts: false,
intercrate_ambiguity_causes: None,
allow_negative_impls,
query_mode: TraitQueryMode::Standard,
Expand All @@ -257,12 +265,32 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
infcx,
freshener: infcx.freshener(),
intercrate: false,
lazy_normalization_consts: false,
intercrate_ambiguity_causes: None,
allow_negative_impls: false,
query_mode,
}
}

pub fn with_lazy_normalization_consts(
infcx: &'cx InferCtxt<'cx, 'tcx>,
lazy_normalization_consts: bool,
) -> SelectionContext<'cx, 'tcx> {
SelectionContext {
infcx,
freshener: infcx.freshener(),
intercrate: false,
lazy_normalization_consts,
intercrate_ambiguity_causes: None,
allow_negative_impls: false,
query_mode: TraitQueryMode::Standard,
}
}

pub fn lazy_normalization_consts(&self) -> bool {
self.lazy_normalization_consts
}

/// Enables tracking of intercrate ambiguity causes. These are
/// used in coherence to give improved diagnostics. We don't do
/// this until we detect a coherence error because it can lead to
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId,
let impl1_trait_ref = match traits::fully_normalize(
&infcx,
FulfillmentContext::new(),
false,
ObligationCause::dummy(),
penv,
impl1_trait_ref,
Expand Down
Loading