Skip to content

Commit 9f8ac71

Browse files
committed
Auto merge of #76575 - lcnr:abstract-const, r=oli-obk
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`
2 parents fdc3405 + b764120 commit 9f8ac71

File tree

29 files changed

+739
-27
lines changed

29 files changed

+739
-27
lines changed

compiler/rustc_metadata/src/rmeta/decoder.rs

+19
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,12 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for Span {
562562
}
563563
}
564564

565+
impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for &'tcx [mir::abstract_const::Node<'tcx>] {
566+
fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Result<Self, String> {
567+
ty::codec::RefDecodable::decode(d)
568+
}
569+
}
570+
565571
impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for &'tcx [(ty::Predicate<'tcx>, Span)] {
566572
fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Result<Self, String> {
567573
ty::codec::RefDecodable::decode(d)
@@ -1191,6 +1197,19 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
11911197
.decode((self, tcx))
11921198
}
11931199

1200+
fn get_mir_abstract_const(
1201+
&self,
1202+
tcx: TyCtxt<'tcx>,
1203+
id: DefIndex,
1204+
) -> Option<&'tcx [mir::abstract_const::Node<'tcx>]> {
1205+
self.root
1206+
.tables
1207+
.mir_abstract_consts
1208+
.get(self, id)
1209+
.filter(|_| !self.is_proc_macro(id))
1210+
.map_or(None, |v| Some(v.decode((self, tcx))))
1211+
}
1212+
11941213
fn get_unused_generic_params(&self, id: DefIndex) -> FiniteBitSet<u32> {
11951214
self.root
11961215
.tables

compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs

+1
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ provide! { <'tcx> tcx, def_id, other, cdata,
112112
}
113113
optimized_mir => { tcx.arena.alloc(cdata.get_optimized_mir(tcx, def_id.index)) }
114114
promoted_mir => { tcx.arena.alloc(cdata.get_promoted_mir(tcx, def_id.index)) }
115+
mir_abstract_const => { cdata.get_mir_abstract_const(tcx, def_id.index) }
115116
unused_generic_params => { cdata.get_unused_generic_params(def_id.index) }
116117
mir_const_qualif => { cdata.mir_const_qualif(def_id.index) }
117118
fn_sig => { cdata.fn_sig(def_id.index, tcx) }

compiler/rustc_metadata/src/rmeta/encoder.rs

+11
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,12 @@ impl<'a, 'tcx> TyEncoder<'tcx> for EncodeContext<'a, 'tcx> {
321321
}
322322
}
323323

324+
impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for &'tcx [mir::abstract_const::Node<'tcx>] {
325+
fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult {
326+
(**self).encode(s)
327+
}
328+
}
329+
324330
impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for &'tcx [(ty::Predicate<'tcx>, Span)] {
325331
fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult {
326332
(**self).encode(s)
@@ -1109,6 +1115,11 @@ impl EncodeContext<'a, 'tcx> {
11091115
if !unused.is_empty() {
11101116
record!(self.tables.unused_generic_params[def_id.to_def_id()] <- unused);
11111117
}
1118+
1119+
let abstract_const = self.tcx.mir_abstract_const(def_id);
1120+
if let Some(abstract_const) = abstract_const {
1121+
record!(self.tables.mir_abstract_consts[def_id.to_def_id()] <- abstract_const);
1122+
}
11121123
}
11131124
}
11141125

compiler/rustc_metadata/src/rmeta/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,7 @@ define_tables! {
284284
super_predicates: Table<DefIndex, Lazy!(ty::GenericPredicates<'tcx>)>,
285285
mir: Table<DefIndex, Lazy!(mir::Body<'tcx>)>,
286286
promoted_mir: Table<DefIndex, Lazy!(IndexVec<mir::Promoted, mir::Body<'tcx>>)>,
287+
mir_abstract_consts: Table<DefIndex, Lazy!(&'tcx [mir::abstract_const::Node<'tcx>])>,
287288
unused_generic_params: Table<DefIndex, Lazy<FiniteBitSet<u32>>>,
288289
// `def_keys` and `def_path_hashes` represent a lazy version of a
289290
// `DefPathTable`. This allows us to avoid deserializing an entire
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
//! A subset of a mir body used for const evaluatability checking.
2+
use crate::mir;
3+
use crate::ty;
4+
5+
rustc_index::newtype_index! {
6+
/// An index into an `AbstractConst`.
7+
pub struct NodeId {
8+
derive [HashStable]
9+
DEBUG_FORMAT = "n{}",
10+
}
11+
}
12+
13+
/// A node of an `AbstractConst`.
14+
#[derive(Debug, Clone, Copy, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
15+
pub enum Node<'tcx> {
16+
Leaf(&'tcx ty::Const<'tcx>),
17+
Binop(mir::BinOp, NodeId, NodeId),
18+
UnaryOp(mir::UnOp, NodeId),
19+
FunctionCall(NodeId, &'tcx [NodeId]),
20+
}

compiler/rustc_middle/src/mir/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ use std::{iter, mem, option};
4040
use self::predecessors::{PredecessorCache, Predecessors};
4141
pub use self::query::*;
4242

43+
pub mod abstract_const;
4344
pub mod coverage;
4445
pub mod interpret;
4546
pub mod mono;

compiler/rustc_middle/src/query/mod.rs

+29
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,35 @@ rustc_queries! {
244244
no_hash
245245
}
246246

247+
/// Try to build an abstract representation of the given constant.
248+
query mir_abstract_const(
249+
key: DefId
250+
) -> Option<&'tcx [mir::abstract_const::Node<'tcx>]> {
251+
desc {
252+
|tcx| "building an abstract representation for {}", tcx.def_path_str(key),
253+
}
254+
}
255+
/// Try to build an abstract representation of the given constant.
256+
query mir_abstract_const_of_const_arg(
257+
key: (LocalDefId, DefId)
258+
) -> Option<&'tcx [mir::abstract_const::Node<'tcx>]> {
259+
desc {
260+
|tcx|
261+
"building an abstract representation for the const argument {}",
262+
tcx.def_path_str(key.0.to_def_id()),
263+
}
264+
}
265+
266+
query try_unify_abstract_consts(key: (
267+
(ty::WithOptConstParam<DefId>, SubstsRef<'tcx>),
268+
(ty::WithOptConstParam<DefId>, SubstsRef<'tcx>)
269+
)) -> bool {
270+
desc {
271+
|tcx| "trying to unify the generic constants {} and {}",
272+
tcx.def_path_str(key.0.0.did), tcx.def_path_str(key.1.0.did)
273+
}
274+
}
275+
247276
query mir_drops_elaborated_and_const_checked(
248277
key: ty::WithOptConstParam<LocalDefId>
249278
) -> &'tcx Steal<mir::Body<'tcx>> {

compiler/rustc_middle/src/ty/codec.rs

+20
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,26 @@ impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [(ty::Predicate<'tcx>,
357357
}
358358
}
359359

360+
impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [mir::abstract_const::Node<'tcx>] {
361+
fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> {
362+
Ok(decoder.tcx().arena.alloc_from_iter(
363+
(0..decoder.read_usize()?)
364+
.map(|_| Decodable::decode(decoder))
365+
.collect::<Result<Vec<_>, _>>()?,
366+
))
367+
}
368+
}
369+
370+
impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [mir::abstract_const::NodeId] {
371+
fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> {
372+
Ok(decoder.tcx().arena.alloc_from_iter(
373+
(0..decoder.read_usize()?)
374+
.map(|_| Decodable::decode(decoder))
375+
.collect::<Result<Vec<_>, _>>()?,
376+
))
377+
}
378+
}
379+
360380
impl_decodable_via_ref! {
361381
&'tcx ty::TypeckResults<'tcx>,
362382
&'tcx ty::List<Ty<'tcx>>,

compiler/rustc_middle/src/ty/query/keys.rs

+16
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,22 @@ impl<'tcx> Key for (DefId, SubstsRef<'tcx>) {
193193
}
194194
}
195195

196+
impl<'tcx> Key
197+
for (
198+
(ty::WithOptConstParam<DefId>, SubstsRef<'tcx>),
199+
(ty::WithOptConstParam<DefId>, SubstsRef<'tcx>),
200+
)
201+
{
202+
type CacheSelector = DefaultCacheSelector;
203+
204+
fn query_crate(&self) -> CrateNum {
205+
(self.0).0.did.krate
206+
}
207+
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
208+
(self.0).0.did.default_span(tcx)
209+
}
210+
}
211+
196212
impl<'tcx> Key for (LocalDefId, DefId, SubstsRef<'tcx>) {
197213
type CacheSelector = DefaultCacheSelector;
198214

compiler/rustc_middle/src/ty/query/on_disk_cache.rs

+6
Original file line numberDiff line numberDiff line change
@@ -760,6 +760,12 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>>
760760
}
761761
}
762762

763+
impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [mir::abstract_const::Node<'tcx>] {
764+
fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
765+
RefDecodable::decode(d)
766+
}
767+
}
768+
763769
impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [(ty::Predicate<'tcx>, Span)] {
764770
fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
765771
RefDecodable::decode(d)

compiler/rustc_middle/src/ty/relate.rs

+14-1
Original file line numberDiff line numberDiff line change
@@ -576,7 +576,20 @@ pub fn super_relate_consts<R: TypeRelation<'tcx>>(
576576
new_val.map(ty::ConstKind::Value)
577577
}
578578

579-
// FIXME(const_generics): this is wrong, as it is a projection
579+
(
580+
ty::ConstKind::Unevaluated(a_def, a_substs, None),
581+
ty::ConstKind::Unevaluated(b_def, b_substs, None),
582+
) if tcx.features().const_evaluatable_checked => {
583+
if tcx.try_unify_abstract_consts(((a_def, a_substs), (b_def, b_substs))) {
584+
Ok(a.val)
585+
} else {
586+
Err(TypeError::ConstMismatch(expected_found(relation, a, b)))
587+
}
588+
}
589+
590+
// While this is slightly incorrect, it shouldn't matter for `min_const_generics`
591+
// and is the better alternative to waiting until `const_evaluatable_checked` can
592+
// be stabilized.
580593
(
581594
ty::ConstKind::Unevaluated(a_def, a_substs, a_promoted),
582595
ty::ConstKind::Unevaluated(b_def, b_substs, b_promoted),

compiler/rustc_mir/src/transform/mod.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,11 @@ fn mir_promoted(
329329
// this point, before we steal the mir-const result.
330330
// Also this means promotion can rely on all const checks having been done.
331331
let _ = tcx.mir_const_qualif_opt_const_arg(def);
332-
332+
let _ = if let Some(param_did) = def.const_param_did {
333+
tcx.mir_abstract_const_of_const_arg((def.did, param_did))
334+
} else {
335+
tcx.mir_abstract_const(def.did.to_def_id())
336+
};
333337
let mut body = tcx.mir_const(def).steal();
334338

335339
let mut required_consts = Vec::new();

compiler/rustc_privacy/src/lib.rs

+9
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,15 @@ where
9797
ty.visit_with(self)
9898
}
9999
ty::PredicateAtom::RegionOutlives(..) => false,
100+
ty::PredicateAtom::ConstEvaluatable(..)
101+
if self.def_id_visitor.tcx().features().const_evaluatable_checked =>
102+
{
103+
// FIXME(const_evaluatable_checked): If the constant used here depends on a
104+
// private function we may have to do something here...
105+
//
106+
// For now, let's just pretend that everything is fine.
107+
false
108+
}
100109
_ => bug!("unexpected predicate: {:?}", predicate),
101110
}
102111
}

compiler/rustc_trait_selection/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
1313
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
1414
#![feature(bool_to_option)]
15+
#![feature(box_patterns)]
1516
#![feature(drain_filter)]
1617
#![feature(in_band_lifetimes)]
1718
#![feature(crate_visibility_modifier)]

0 commit comments

Comments
 (0)