Skip to content

Commit

Permalink
make unevaluated const substs optional
Browse files Browse the repository at this point in the history
  • Loading branch information
lcnr committed Mar 15, 2021
1 parent 4e8e894 commit 371c77b
Show file tree
Hide file tree
Showing 25 changed files with 122 additions and 80 deletions.
8 changes: 4 additions & 4 deletions compiler/rustc_codegen_cranelift/src/constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,13 +116,13 @@ pub(crate) fn codegen_constant<'tcx>(
let const_ = fx.monomorphize(constant.literal);
let const_val = match const_.val {
ConstKind::Value(const_val) => const_val,
ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) if fx.tcx.is_static(def.did) => {
assert!(substs.is_empty());
assert!(promoted.is_none());
ConstKind::Unevaluated(uv) if fx.tcx.is_static(uv.def.did) => {
assert!(uv.substs(fx.tcx).is_empty());
assert!(uv.promoted.is_none());

return codegen_static_ref(
fx,
def.did,
uv.def.did,
fx.layout_of(fx.monomorphize(&constant.literal.ty)),
)
.to_cvalue(fx);
Expand Down
8 changes: 4 additions & 4 deletions compiler/rustc_infer/src/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1498,16 +1498,16 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
pub fn const_eval_resolve(
&self,
param_env: ty::ParamEnv<'tcx>,
ty::Unevaluated { def, substs, promoted }: ty::Unevaluated<'tcx>,
unevaluated: ty::Unevaluated<'tcx>,
span: Option<Span>,
) -> EvalToConstValueResult<'tcx> {
let mut original_values = OriginalQueryValues::default();
let canonical = self.canonicalize_query((param_env, substs), &mut original_values);
let canonical = self.canonicalize_query((param_env, unevaluated), &mut original_values);

let (param_env, substs) = canonical.value;
let (param_env, unevaluated) = canonical.value;
// The return value is the evaluated value which doesn't contain any reference to inference
// variables, thus we don't need to substitute back the original values.
self.tcx.const_eval_resolve(param_env, ty::Unevaluated { def, substs, promoted }, span)
self.tcx.const_eval_resolve(param_env, unevaluated, span)
}

/// If `typ` is a type variable of some kind, resolve it one level
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/mir/interpret/queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ impl<'tcx> TyCtxt<'tcx> {
ct: ty::Unevaluated<'tcx>,
span: Option<Span>,
) -> EvalToConstValueResult<'tcx> {
match ty::Instance::resolve_opt_const_arg(self, param_env, ct.def, ct.substs) {
match ty::Instance::resolve_opt_const_arg(self, param_env, ct.def, ct.substs(self)) {
Ok(Some(instance)) => {
let cid = GlobalId { instance, promoted: ct.promoted };
self.const_eval_global_id(param_env, cid, span)
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_middle/src/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@ rustc_queries! {
desc { |tcx| "computing the optional const parameter of `{}`", tcx.def_path_str(key.to_def_id()) }
}

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.
query type_of(key: DefId) -> Ty<'tcx> {
desc { |tcx| "computing type of `{}`", tcx.def_path_str(key) }
Expand Down
3 changes: 1 addition & 2 deletions compiler/rustc_middle/src/ty/consts.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
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::{ParamEnv, ParamEnvAnd};
use rustc_errors::ErrorReported;
Expand Down Expand Up @@ -98,7 +97,7 @@ impl<'tcx> Const<'tcx> {
}
_ => ty::ConstKind::Unevaluated(ty::Unevaluated {
def: def.to_global(),
substs: InternalSubsts::identity_for_item(tcx, def.did.to_def_id()),
non_default_substs: None,
promoted: None,
}),
};
Expand Down
34 changes: 23 additions & 11 deletions compiler/rustc_middle/src/ty/consts/kind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,16 @@ use rustc_target::abi::Size;
#[derive(Hash, HashStable)]
pub struct Unevaluated<'tcx> {
pub def: ty::WithOptConstParam<DefId>,
pub substs: SubstsRef<'tcx>,
pub non_default_substs: Option<SubstsRef<'tcx>>,
pub promoted: Option<Promoted>,
}

impl<'tcx> Unevaluated<'tcx> {
pub fn substs(self, tcx: TyCtxt<'tcx>) -> SubstsRef<'tcx> {
self.non_default_substs.unwrap_or_else(|| tcx.default_anon_const_substs(self.def.did))
}
}

/// Represents a constant in Rust.
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable)]
#[derive(Hash, HashStable)]
Expand Down Expand Up @@ -102,7 +108,7 @@ impl<'tcx> ConstKind<'tcx> {
tcx: TyCtxt<'tcx>,
param_env: ParamEnv<'tcx>,
) -> Option<Result<ConstValue<'tcx>, ErrorReported>> {
if let ConstKind::Unevaluated(Unevaluated { def, substs, promoted }) = self {
if let ConstKind::Unevaluated(unevaluated) = self {
use crate::mir::interpret::ErrorHandled;

// HACK(eddyb) this erases lifetimes even though `const_eval_resolve`
Expand All @@ -111,29 +117,35 @@ impl<'tcx> ConstKind<'tcx> {
// Note that we erase regions *before* calling `with_reveal_all_normalized`,
// so that we don't try to invoke this query with
// any region variables.
let param_env_and_substs = tcx
let param_env_and = tcx
.erase_regions(param_env)
.with_reveal_all_normalized(tcx)
.and(tcx.erase_regions(substs));
.and(tcx.erase_regions(unevaluated));

// HACK(eddyb) when the query key would contain inference variables,
// attempt using identity substs and `ParamEnv` instead, that will succeed
// when the expression doesn't depend on any parameters.
// FIXME(eddyb, skinny121) pass `InferCtxt` into here when it's available, so that
// we can call `infcx.const_eval_resolve` which handles inference variables.
let param_env_and_substs = if param_env_and_substs.needs_infer() {
tcx.param_env(def.did).and(InternalSubsts::identity_for_item(tcx, def.did))
let param_env_and = if param_env_and.needs_infer() {
tcx.param_env(unevaluated.def.did).and(ty::Unevaluated {
def: unevaluated.def,
non_default_substs: Some(InternalSubsts::identity_for_item(
tcx,
unevaluated.def.did,
)),
promoted: unevaluated.promoted,
})
} else {
param_env_and_substs
param_env_and
};

// FIXME(eddyb) maybe the `const_eval_*` methods should take
// `ty::ParamEnvAnd<SubstsRef>` instead of having them separate.
let (param_env, substs) = param_env_and_substs.into_parts();
// `ty::ParamEnvAnd` instead of having them separate.
let (param_env, unevaluated) = param_env_and.into_parts();
// try to resolve e.g. associated constants to their definition on an impl, and then
// evaluate the const.
match tcx.const_eval_resolve(param_env, ty::Unevaluated { def, substs, promoted }, None)
{
match tcx.const_eval_resolve(param_env, unevaluated, None) {
// NOTE(eddyb) `val` contains no lifetimes/types/consts,
// and we use the original type, so nothing from `substs`
// (which may be identity substs, see above),
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_middle/src/ty/flags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,8 @@ impl FlagComputation {
}

fn add_unevaluated_const(&mut self, ct: ty::Unevaluated<'tcx>) {
self.add_substs(ct.substs);
// TODO
self.add_substs(ct.non_default_substs.unwrap());
self.add_flags(TypeFlags::HAS_CT_PROJECTION);
}

Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_middle/src/ty/print/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -915,7 +915,9 @@ pub trait PrettyPrinter<'tcx>:
}

match ct.val {
ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) => {
ty::ConstKind::Unevaluated(ty::Unevaluated { def, non_default_substs, promoted }) => {
// TODO
let substs = non_default_substs.unwrap();
if let Some(promoted) = promoted {
p!(print_value_path(def.did, substs));
p!(write("::{:?}", promoted));
Expand Down
11 changes: 7 additions & 4 deletions compiler/rustc_middle/src/ty/relate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -590,7 +590,7 @@ pub fn super_relate_consts<R: TypeRelation<'tcx>>(
(ty::ConstKind::Unevaluated(au), ty::ConstKind::Unevaluated(bu))
if tcx.features().const_evaluatable_checked && !relation.visit_ct_substs() =>
{
if tcx.try_unify_abstract_consts(((au.def, au.substs), (bu.def, bu.substs))) {
if tcx.try_unify_abstract_consts(((au.def, au.substs(tcx)), (bu.def, bu.substs(tcx)))) {
Ok(a.val)
} else {
Err(TypeError::ConstMismatch(expected_found(relation, a, b)))
Expand All @@ -603,11 +603,14 @@ pub fn super_relate_consts<R: TypeRelation<'tcx>>(
(ty::ConstKind::Unevaluated(au), ty::ConstKind::Unevaluated(bu))
if au.def == bu.def && au.promoted == bu.promoted =>
{
let substs =
relation.relate_with_variance(ty::Variance::Invariant, au.substs, bu.substs)?;
let substs = relation.relate_with_variance(
ty::Variance::Invariant,
au.substs(tcx),
bu.substs(tcx),
)?;
Ok(ty::ConstKind::Unevaluated(ty::Unevaluated {
def: au.def,
substs,
non_default_substs: Some(substs),
promoted: au.promoted,
}))
}
Expand Down
24 changes: 16 additions & 8 deletions compiler/rustc_middle/src/ty/structural_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1031,13 +1031,7 @@ 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(ty::Unevaluated { def, substs, promoted }) => {
ty::ConstKind::Unevaluated(ty::Unevaluated {
def,
substs: substs.fold_with(folder),
promoted,
})
}
ty::ConstKind::Unevaluated(uv) => ty::ConstKind::Unevaluated(uv.fold_with(folder)),
ty::ConstKind::Value(_)
| ty::ConstKind::Bound(..)
| ty::ConstKind::Placeholder(..)
Expand All @@ -1049,7 +1043,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ConstKind<'tcx> {
match *self {
ty::ConstKind::Infer(ic) => ic.visit_with(visitor),
ty::ConstKind::Param(p) => p.visit_with(visitor),
ty::ConstKind::Unevaluated(ct) => ct.substs.visit_with(visitor),
ty::ConstKind::Unevaluated(uv) => uv.visit_with(visitor),
ty::ConstKind::Value(_)
| ty::ConstKind::Bound(..)
| ty::ConstKind::Placeholder(_)
Expand All @@ -1067,3 +1061,17 @@ impl<'tcx> TypeFoldable<'tcx> for InferConst<'tcx> {
ControlFlow::CONTINUE
}
}

impl<'tcx> TypeFoldable<'tcx> for ty::Unevaluated<'tcx> {
fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
ty::Unevaluated {
def: self.def,
non_default_substs: Some(self.substs(folder.tcx()).fold_with(folder)),
promoted: self.promoted,
}
}

fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
self.substs(visitor.tcx_for_anon_const_substs()).visit_with(visitor)
}
}
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 @@ -196,7 +196,8 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>)
| ty::ConstKind::Error(_) => {}

ty::ConstKind::Unevaluated(ct) => {
stack.extend(ct.substs.iter().rev());
// TODO
stack.extend(ct.non_default_substs.unwrap().iter().rev());
}
}
}
Expand Down
10 changes: 4 additions & 6 deletions compiler/rustc_mir/src/borrow_check/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -314,10 +314,8 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
}
} else {
let tcx = self.tcx();
if let ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) =
constant.literal.val
{
if let Some(promoted) = promoted {
if let ty::ConstKind::Unevaluated(uv) = constant.literal.val {
if let Some(promoted) = uv.promoted {
let check_err = |verifier: &mut TypeVerifier<'a, 'b, 'tcx>,
promoted: &Body<'tcx>,
ty,
Expand Down Expand Up @@ -352,8 +350,8 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
ConstraintCategory::Boring,
self.cx.param_env.and(type_op::ascribe_user_type::AscribeUserType::new(
constant.literal.ty,
def.did,
UserSubsts { substs, user_self_ty: None },
uv.def.did,
UserSubsts { substs: uv.substs(tcx), user_self_ty: None },
)),
) {
span_mirbug!(
Expand Down
8 changes: 5 additions & 3 deletions compiler/rustc_mir/src/interpret/operand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -566,9 +566,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
let val_val = match val.val {
ty::ConstKind::Param(_) | ty::ConstKind::Bound(..) => throw_inval!(TooGeneric),
ty::ConstKind::Error(_) => throw_inval!(AlreadyReported(ErrorReported)),
ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }) => {
let instance = self.resolve(def, substs)?;
return Ok(self.eval_to_allocation(GlobalId { instance, promoted })?.into());
ty::ConstKind::Unevaluated(uv) => {
let instance = self.resolve(uv.def, uv.substs(*self.tcx))?;
return Ok(self
.eval_to_allocation(GlobalId { instance, promoted: uv.promoted })?
.into());
}
ty::ConstKind::Infer(..) | ty::ConstKind::Placeholder(..) => {
span_bug!(self.cur_span(), "const_to_op: Unexpected ConstKind {:?}", val)
Expand Down
11 changes: 7 additions & 4 deletions compiler/rustc_mir/src/monomorphize/polymorphize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -302,21 +302,24 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
self.unused_parameters.clear(param.index);
ControlFlow::CONTINUE
}
ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs: _, promoted: Some(p)})
ty::ConstKind::Unevaluated(ty::Unevaluated { def, non_default_substs: _, promoted: Some(p)})
// Avoid considering `T` unused when constants are of the form:
// `<Self as Foo<T>>::foo::promoted[p]`
if self.def_id == def.did && !self.tcx.generics_of(def.did).has_self =>
{
// If there is a promoted, don't look at the substs - since it will always contain
// the generic parameters, instead, traverse the promoted MIR.
//
// FIXME(lcnr): This seems incorrect if we get the promoted by inlining.
// We have to consider its substs in that case.
let promoted = self.tcx.promoted_mir(def.did);
self.visit_body(&promoted[p]);
ControlFlow::CONTINUE
}
ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted: None })
if self.tcx.def_kind(def.did) == DefKind::AnonConst =>
ty::ConstKind::Unevaluated(uv)
if self.tcx.def_kind(uv.def.did) == DefKind::AnonConst =>
{
self.visit_child_body(def.did, substs);
self.visit_child_body(uv.def.did, uv.substs(self.tcx));
ControlFlow::CONTINUE
}
_ => c.super_visit_with(self),
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_mir/src/transform/check_consts/qualifs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ where
};

// Check the qualifs of the value of `const` items.
if let ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs: _, promoted }) =
if let ty::ConstKind::Unevaluated(ty::Unevaluated { def, non_default_substs: _, promoted }) =
constant.literal.val
{
assert!(promoted.is_none());
Expand Down
18 changes: 11 additions & 7 deletions compiler/rustc_mir/src/transform/promote_consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1002,13 +1002,17 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
ty,
val: ty::ConstKind::Unevaluated(ty::Unevaluated {
def,
substs: InternalSubsts::for_item(tcx, def.did, |param, _| {
if let ty::GenericParamDefKind::Lifetime = param.kind {
tcx.lifetimes.re_erased.into()
} else {
tcx.mk_param_from_def(param)
}
}),
non_default_substs: Some(InternalSubsts::for_item(
tcx,
def.did,
|param, _| {
if let ty::GenericParamDefKind::Lifetime = param.kind {
tcx.lifetimes.re_erased.into()
} else {
tcx.mk_param_from_def(param)
}
},
)),
promoted: Some(promoted_id),
}),
}),
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_mir_build/src/thir/cx/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -694,7 +694,7 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
let lhs = mk_const(self.tcx().mk_const(ty::Const {
val: ty::ConstKind::Unevaluated(ty::Unevaluated {
def: ty::WithOptConstParam::unknown(did),
substs,
non_default_substs: Some(substs),
promoted: None,
}),
ty: var_ty,
Expand Down Expand Up @@ -892,7 +892,7 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> {
literal: self.tcx.mk_const(ty::Const {
val: ty::ConstKind::Unevaluated(ty::Unevaluated {
def: ty::WithOptConstParam::unknown(def_id),
substs,
non_default_substs: Some(substs),
promoted: None,
}),
ty: self.typeck_results().node_type(expr.hir_id),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
// See #74595 for more details about this.
let concrete = infcx.const_eval_resolve(
param_env,
ty::Unevaluated { def, substs, promoted: None },
ty::Unevaluated { def, non_default_substs: Some(substs), promoted: None },
Some(span),
);

Expand Down Expand Up @@ -243,9 +243,7 @@ impl AbstractConst<'tcx> {
ct: &ty::Const<'tcx>,
) -> Result<Option<AbstractConst<'tcx>>, ErrorReported> {
match ct.val {
ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted: _ }) => {
AbstractConst::new(tcx, def, substs)
}
ty::ConstKind::Unevaluated(uv) => AbstractConst::new(tcx, uv.def, uv.substs(tcx)),
ty::ConstKind::Error(_) => Err(ErrorReported),
_ => Ok(None),
}
Expand Down
Loading

0 comments on commit 371c77b

Please sign in to comment.