Skip to content

Commit

Permalink
Auto merge of #76575 - lcnr:abstract-const, r=oli-obk
Browse files Browse the repository at this point in the history
compare generic constants using `AbstractConst`s

This is a MVP of rust-lang/compiler-team#340. The changes in this PR should only be relevant if `feature(const_evaluatable_checked)` is enabled.

~~currently based on top of #76559, so blocked on that.~~

r? `@oli-obk` cc `@varkor` `@eddyb`
  • Loading branch information
bors committed Sep 18, 2020
2 parents fdc3405 + b764120 commit 9f8ac71
Show file tree
Hide file tree
Showing 29 changed files with 739 additions and 27 deletions.
19 changes: 19 additions & 0 deletions compiler/rustc_metadata/src/rmeta/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down
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
Expand Up @@ -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) }
Expand Down
11 changes: 11 additions & 0 deletions compiler/rustc_metadata/src/rmeta/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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);
}
}
}

Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_metadata/src/rmeta/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
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
Expand Up @@ -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;
Expand Down
29 changes: 29 additions & 0 deletions compiler/rustc_middle/src/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>> {
Expand Down
20 changes: 20 additions & 0 deletions compiler/rustc_middle/src/ty/codec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>>,
Expand Down
16 changes: 16 additions & 0 deletions compiler/rustc_middle/src/ty/query/keys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
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
Expand Up @@ -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)
Expand Down
15 changes: 14 additions & 1 deletion compiler/rustc_middle/src/ty/relate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
6 changes: 5 additions & 1 deletion compiler/rustc_mir/src/transform/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
9 changes: 9 additions & 0 deletions compiler/rustc_privacy/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
}
}
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_trait_selection/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down
Loading

0 comments on commit 9f8ac71

Please sign in to comment.