Skip to content

make default anon const substs optional #83086

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 5 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
make unevaluated const substs optional
  • Loading branch information
lcnr committed Mar 15, 2021
commit 371c77bb90e13798a804f220e15f2e4dfa8dc9f8
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