Skip to content

compare generic constants using AbstractConsts #76575

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

Merged
merged 12 commits into from
Sep 18, 2020
19 changes: 19 additions & 0 deletions compiler/rustc_metadata/src/rmeta/decoder.rs
Original file line number Diff line number Diff line change
@@ -562,6 +562,12 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for Span {
}
}

impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for &'tcx [mir::abstract_const::Node<'tcx>] {
fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Result<Self, String> {
ty::codec::RefDecodable::decode(d)
}
}

impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for &'tcx [(ty::Predicate<'tcx>, Span)] {
fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Result<Self, String> {
ty::codec::RefDecodable::decode(d)
@@ -1191,6 +1197,19 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
.decode((self, tcx))
}

fn get_mir_abstract_const(
&self,
tcx: TyCtxt<'tcx>,
id: DefIndex,
) -> Option<&'tcx [mir::abstract_const::Node<'tcx>]> {
self.root
.tables
.mir_abstract_consts
.get(self, id)
.filter(|_| !self.is_proc_macro(id))
.map_or(None, |v| Some(v.decode((self, tcx))))
}

fn get_unused_generic_params(&self, id: DefIndex) -> FiniteBitSet<u32> {
self.root
.tables
1 change: 1 addition & 0 deletions compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
Original file line number Diff line number Diff line change
@@ -112,6 +112,7 @@ provide! { <'tcx> tcx, def_id, other, cdata,
}
optimized_mir => { tcx.arena.alloc(cdata.get_optimized_mir(tcx, def_id.index)) }
promoted_mir => { tcx.arena.alloc(cdata.get_promoted_mir(tcx, def_id.index)) }
mir_abstract_const => { cdata.get_mir_abstract_const(tcx, def_id.index) }
unused_generic_params => { cdata.get_unused_generic_params(def_id.index) }
mir_const_qualif => { cdata.mir_const_qualif(def_id.index) }
fn_sig => { cdata.fn_sig(def_id.index, tcx) }
11 changes: 11 additions & 0 deletions compiler/rustc_metadata/src/rmeta/encoder.rs
Original file line number Diff line number Diff line change
@@ -321,6 +321,12 @@ impl<'a, 'tcx> TyEncoder<'tcx> for EncodeContext<'a, 'tcx> {
}
}

impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for &'tcx [mir::abstract_const::Node<'tcx>] {
fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult {
(**self).encode(s)
}
}

impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for &'tcx [(ty::Predicate<'tcx>, Span)] {
fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult {
(**self).encode(s)
@@ -1109,6 +1115,11 @@ impl EncodeContext<'a, 'tcx> {
if !unused.is_empty() {
record!(self.tables.unused_generic_params[def_id.to_def_id()] <- unused);
}

let abstract_const = self.tcx.mir_abstract_const(def_id);
if let Some(abstract_const) = abstract_const {
record!(self.tables.mir_abstract_consts[def_id.to_def_id()] <- abstract_const);
}
}
}

1 change: 1 addition & 0 deletions compiler/rustc_metadata/src/rmeta/mod.rs
Original file line number Diff line number Diff line change
@@ -284,6 +284,7 @@ define_tables! {
super_predicates: Table<DefIndex, Lazy!(ty::GenericPredicates<'tcx>)>,
mir: Table<DefIndex, Lazy!(mir::Body<'tcx>)>,
promoted_mir: Table<DefIndex, Lazy!(IndexVec<mir::Promoted, mir::Body<'tcx>>)>,
mir_abstract_consts: Table<DefIndex, Lazy!(&'tcx [mir::abstract_const::Node<'tcx>])>,
unused_generic_params: Table<DefIndex, Lazy<FiniteBitSet<u32>>>,
// `def_keys` and `def_path_hashes` represent a lazy version of a
// `DefPathTable`. This allows us to avoid deserializing an entire
20 changes: 20 additions & 0 deletions compiler/rustc_middle/src/mir/abstract_const.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//! A subset of a mir body used for const evaluatability checking.
use crate::mir;
use crate::ty;

rustc_index::newtype_index! {
/// An index into an `AbstractConst`.
pub struct NodeId {
derive [HashStable]
DEBUG_FORMAT = "n{}",
}
}

/// A node of an `AbstractConst`.
#[derive(Debug, Clone, Copy, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
pub enum Node<'tcx> {
Leaf(&'tcx ty::Const<'tcx>),
Binop(mir::BinOp, NodeId, NodeId),
UnaryOp(mir::UnOp, NodeId),
FunctionCall(NodeId, &'tcx [NodeId]),
}
1 change: 1 addition & 0 deletions compiler/rustc_middle/src/mir/mod.rs
Original file line number Diff line number Diff line change
@@ -40,6 +40,7 @@ use std::{iter, mem, option};
use self::predecessors::{PredecessorCache, Predecessors};
pub use self::query::*;

pub mod abstract_const;
pub mod coverage;
pub mod interpret;
pub mod mono;
29 changes: 29 additions & 0 deletions compiler/rustc_middle/src/query/mod.rs
Original file line number Diff line number Diff line change
@@ -244,6 +244,35 @@ rustc_queries! {
no_hash
}

/// Try to build an abstract representation of the given constant.
query mir_abstract_const(
key: DefId
) -> Option<&'tcx [mir::abstract_const::Node<'tcx>]> {
desc {
|tcx| "building an abstract representation for {}", tcx.def_path_str(key),
}
}
/// Try to build an abstract representation of the given constant.
query mir_abstract_const_of_const_arg(
key: (LocalDefId, DefId)
) -> Option<&'tcx [mir::abstract_const::Node<'tcx>]> {
desc {
|tcx|
"building an abstract representation for the const argument {}",
tcx.def_path_str(key.0.to_def_id()),
}
}

query try_unify_abstract_consts(key: (
(ty::WithOptConstParam<DefId>, SubstsRef<'tcx>),
(ty::WithOptConstParam<DefId>, SubstsRef<'tcx>)
)) -> bool {
desc {
|tcx| "trying to unify the generic constants {} and {}",
tcx.def_path_str(key.0.0.did), tcx.def_path_str(key.1.0.did)
}
}

query mir_drops_elaborated_and_const_checked(
key: ty::WithOptConstParam<LocalDefId>
) -> &'tcx Steal<mir::Body<'tcx>> {
20 changes: 20 additions & 0 deletions compiler/rustc_middle/src/ty/codec.rs
Original file line number Diff line number Diff line change
@@ -357,6 +357,26 @@ impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [(ty::Predicate<'tcx>,
}
}

impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [mir::abstract_const::Node<'tcx>] {
fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> {
Ok(decoder.tcx().arena.alloc_from_iter(
(0..decoder.read_usize()?)
.map(|_| Decodable::decode(decoder))
.collect::<Result<Vec<_>, _>>()?,
))
}
}

impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [mir::abstract_const::NodeId] {
fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> {
Ok(decoder.tcx().arena.alloc_from_iter(
(0..decoder.read_usize()?)
.map(|_| Decodable::decode(decoder))
.collect::<Result<Vec<_>, _>>()?,
))
}
}

impl_decodable_via_ref! {
&'tcx ty::TypeckResults<'tcx>,
&'tcx ty::List<Ty<'tcx>>,
16 changes: 16 additions & 0 deletions compiler/rustc_middle/src/ty/query/keys.rs
Original file line number Diff line number Diff line change
@@ -193,6 +193,22 @@ impl<'tcx> Key for (DefId, SubstsRef<'tcx>) {
}
}

impl<'tcx> Key
for (
(ty::WithOptConstParam<DefId>, SubstsRef<'tcx>),
(ty::WithOptConstParam<DefId>, SubstsRef<'tcx>),
)
{
type CacheSelector = DefaultCacheSelector;

fn query_crate(&self) -> CrateNum {
(self.0).0.did.krate
}
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
(self.0).0.did.default_span(tcx)
}
}

impl<'tcx> Key for (LocalDefId, DefId, SubstsRef<'tcx>) {
type CacheSelector = DefaultCacheSelector;

6 changes: 6 additions & 0 deletions compiler/rustc_middle/src/ty/query/on_disk_cache.rs
Original file line number Diff line number Diff line change
@@ -760,6 +760,12 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>>
}
}

impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [mir::abstract_const::Node<'tcx>] {
fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
RefDecodable::decode(d)
}
}

impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [(ty::Predicate<'tcx>, Span)] {
fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
RefDecodable::decode(d)
15 changes: 14 additions & 1 deletion compiler/rustc_middle/src/ty/relate.rs
Original file line number Diff line number Diff line change
@@ -576,7 +576,20 @@ pub fn super_relate_consts<R: TypeRelation<'tcx>>(
new_val.map(ty::ConstKind::Value)
}

// FIXME(const_generics): this is wrong, as it is a projection
(
ty::ConstKind::Unevaluated(a_def, a_substs, None),
ty::ConstKind::Unevaluated(b_def, b_substs, None),
) if tcx.features().const_evaluatable_checked => {
if tcx.try_unify_abstract_consts(((a_def, a_substs), (b_def, b_substs))) {
Ok(a.val)
} else {
Err(TypeError::ConstMismatch(expected_found(relation, a, b)))
}
}

// While this is slightly incorrect, it shouldn't matter for `min_const_generics`
// and is the better alternative to waiting until `const_evaluatable_checked` can
// be stabilized.
(
ty::ConstKind::Unevaluated(a_def, a_substs, a_promoted),
ty::ConstKind::Unevaluated(b_def, b_substs, b_promoted),
6 changes: 5 additions & 1 deletion compiler/rustc_mir/src/transform/mod.rs
Original file line number Diff line number Diff line change
@@ -329,7 +329,11 @@ fn mir_promoted(
// this point, before we steal the mir-const result.
// Also this means promotion can rely on all const checks having been done.
let _ = tcx.mir_const_qualif_opt_const_arg(def);

let _ = if let Some(param_did) = def.const_param_did {
tcx.mir_abstract_const_of_const_arg((def.did, param_did))
} else {
tcx.mir_abstract_const(def.did.to_def_id())
};
let mut body = tcx.mir_const(def).steal();

let mut required_consts = Vec::new();
9 changes: 9 additions & 0 deletions compiler/rustc_privacy/src/lib.rs
Original file line number Diff line number Diff line change
@@ -97,6 +97,15 @@ where
ty.visit_with(self)
}
ty::PredicateAtom::RegionOutlives(..) => false,
ty::PredicateAtom::ConstEvaluatable(..)
if self.def_id_visitor.tcx().features().const_evaluatable_checked =>
{
// FIXME(const_evaluatable_checked): If the constant used here depends on a
// private function we may have to do something here...
//
// For now, let's just pretend that everything is fine.
false
}
_ => bug!("unexpected predicate: {:?}", predicate),
}
}
1 change: 1 addition & 0 deletions compiler/rustc_trait_selection/src/lib.rs
Original file line number Diff line number Diff line change
@@ -12,6 +12,7 @@

#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
#![feature(bool_to_option)]
#![feature(box_patterns)]
#![feature(drain_filter)]
#![feature(in_band_lifetimes)]
#![feature(crate_visibility_modifier)]
Loading