Skip to content

Commit

Permalink
Auto merge of #74113 - lcnr:type-dependent-consts-2, r=eddyb
Browse files Browse the repository at this point in the history
Support const args in type dependent paths (Take 2)

once more, except it is sound this time 🥰 previously #71154

-----
```rust
#![feature(const_generics)]

struct A;
impl A {
    fn foo<const N: usize>(&self) -> usize { N }
}
struct B;
impl B {
    fn foo<const N: usize>(&self) -> usize { 42 }
}

fn main() {
    let a = A;
    a.foo::<7>();
}
```
When calling `type_of` for generic const arguments, we now use the `TypeckTables` of the surrounding body to get the expected type.

This alone causes cycle errors though, as we now have `typeck_tables_of(main)` -> `...` ->
`type_of(main_ANON0 := 7)` -> `typeck_tables_of(main)` ⚡ (see #68400 (comment))

To prevent this we must not call `type_of(const_arg)` during `typeck_tables_of`. This is achieved by
calling `type_of(param_def_id)` instead.

We have to somehow remember the `DefId` of the param through all of typeck, which is done using the
struct `ty::WithOptConstParam<DefId>`, which replaces `DefId` where needed and contains an `Option<DefId>` to
be able to store the const parameter in case it exists.

Queries which are currently cached on disk are split into two variants: `query_name`(cached) and `query_name_(of|for)_const_arg`(not cached), with `query_name_of_const_arg` taking a pair `(did, param_did): (LocalDefId, DefId)`.

For some queries a method `query_name_of_opt_const_arg` is added to `TyCtxt` which takes a `ty::WithOptConstParam` and either calls `query_name` or `query_name_of_const_arg` depending on the value of `const_param_did`.

r? @eddyb @varkor
  • Loading branch information
bors committed Jul 15, 2020
2 parents d9e8d62 + 2666aed commit 7e11379
Show file tree
Hide file tree
Showing 101 changed files with 1,547 additions and 622 deletions.
4 changes: 2 additions & 2 deletions src/librustc_codegen_ssa/back/symbol_export.rs
Original file line number Diff line number Diff line change
Expand Up @@ -248,9 +248,9 @@ fn exported_symbols_provider_local(
}

match *mono_item {
MonoItem::Fn(Instance { def: InstanceDef::Item(def_id), substs }) => {
MonoItem::Fn(Instance { def: InstanceDef::Item(def), substs }) => {
if substs.non_erasable_generics().next().is_some() {
let symbol = ExportedSymbol::Generic(def_id, substs);
let symbol = ExportedSymbol::Generic(def.did, substs);
symbols.push((symbol, SymbolExportLevel::Rust));
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_codegen_ssa/mir/constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
constant: &mir::Constant<'tcx>,
) -> Result<ConstValue<'tcx>, ErrorHandled> {
match self.monomorphize(&constant.literal).val {
ty::ConstKind::Unevaluated(def_id, substs, promoted) => self
ty::ConstKind::Unevaluated(def, substs, promoted) => self
.cx
.tcx()
.const_eval_resolve(ty::ParamEnv::reveal_all(), def_id, substs, promoted, None)
.const_eval_resolve(ty::ParamEnv::reveal_all(), def, substs, promoted, None)
.map_err(|err| {
if promoted.is_none() {
self.cx
Expand Down
5 changes: 2 additions & 3 deletions src/librustc_incremental/persist/dirty_clean.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,7 @@ const BASE_IMPL: &[&str] =

/// DepNodes for mir_built/Optimized, which is relevant in "executable"
/// code, i.e., functions+methods
const BASE_MIR: &[&str] =
&[label_strs::optimized_mir, label_strs::promoted_mir, label_strs::mir_built];
const BASE_MIR: &[&str] = &[label_strs::optimized_mir, label_strs::promoted_mir];

/// Struct, Enum and Union DepNodes
///
Expand Down Expand Up @@ -376,7 +375,7 @@ impl DirtyCleanVisitor<'tcx> {
let def_path_hash = self.tcx.def_path_hash(def_id);
labels.iter().map(move |label| match DepNode::from_label_string(label, def_path_hash) {
Ok(dep_node) => dep_node,
Err(()) => unreachable!(),
Err(()) => unreachable!("label: {}", label),
})
}

Expand Down
4 changes: 2 additions & 2 deletions src/librustc_infer/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1536,7 +1536,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
pub fn const_eval_resolve(
&self,
param_env: ty::ParamEnv<'tcx>,
def_id: DefId,
def: ty::WithOptConstParam<DefId>,
substs: SubstsRef<'tcx>,
promoted: Option<mir::Promoted>,
span: Option<Span>,
Expand All @@ -1547,7 +1547,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
let (param_env, substs) = 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, def_id, substs, promoted, span)
self.tcx.const_eval_resolve(param_env, def, substs, promoted, span)
}

/// If `typ` is a type variable of some kind, resolve it one level
Expand Down
3 changes: 2 additions & 1 deletion src/librustc_interface/passes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -891,7 +891,8 @@ fn analysis(tcx: TyCtxt<'_>, cnum: CrateNum) -> Result<()> {
mir::transform::check_unsafety::check_unsafety(tcx, def_id);

if tcx.hir().body_const_context(def_id).is_some() {
tcx.ensure().mir_drops_elaborated_and_const_checked(def_id);
tcx.ensure()
.mir_drops_elaborated_and_const_checked(ty::WithOptConstParam::unknown(def_id));
}
}
});
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_metadata/rmeta/decoder/cstore_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,8 @@ provide! { <'tcx> tcx, def_id, other, cdata,
bug!("coerce_unsized_info: `{:?}` is missing its info", def_id);
})
}
optimized_mir => { cdata.get_optimized_mir(tcx, def_id.index) }
promoted_mir => { cdata.get_promoted_mir(tcx, def_id.index) }
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_const_qualif => { cdata.mir_const_qualif(def_id.index) }
fn_sig => { cdata.fn_sig(def_id.index, tcx) }
inherent_impls => { cdata.get_inherent_implementations_for_type(tcx, def_id.index) }
Expand Down
30 changes: 30 additions & 0 deletions src/librustc_middle/arena.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,37 @@ macro_rules! arena_types {
[] layouts: rustc_target::abi::Layout, rustc_target::abi::Layout;
// AdtDef are interned and compared by address
[] adt_def: rustc_middle::ty::AdtDef, rustc_middle::ty::AdtDef;
[] steal_mir:
rustc_middle::ty::steal::Steal<rustc_middle::mir::Body<$tcx>>,
rustc_middle::ty::steal::Steal<rustc_middle::mir::Body<$tcx>>;
[decode] mir: rustc_middle::mir::Body<$tcx>, rustc_middle::mir::Body<'_x>;
[] steal_promoted:
rustc_middle::ty::steal::Steal<
rustc_index::vec::IndexVec<
rustc_middle::mir::Promoted,
rustc_middle::mir::Body<$tcx>
>
>,
rustc_middle::ty::steal::Steal<
rustc_index::vec::IndexVec<
rustc_middle::mir::Promoted,
rustc_middle::mir::Body<$tcx>
>
>;
[decode] promoted:
rustc_index::vec::IndexVec<
rustc_middle::mir::Promoted,
rustc_middle::mir::Body<$tcx>
>,
rustc_index::vec::IndexVec<
rustc_middle::mir::Promoted,
rustc_middle::mir::Body<'_x>
>;
[decode] tables: rustc_middle::ty::TypeckTables<$tcx>, rustc_middle::ty::TypeckTables<'_x>;
[decode] borrowck_result:
rustc_middle::mir::BorrowCheckResult<$tcx>,
rustc_middle::mir::BorrowCheckResult<'_x>;
[decode] unsafety_check_result: rustc_middle::mir::UnsafetyCheckResult, rustc_middle::mir::UnsafetyCheckResult;
[] const_allocs: rustc_middle::mir::interpret::Allocation, rustc_middle::mir::interpret::Allocation;
// Required for the incremental on-disk cache
[few, decode] mir_keys: rustc_hir::def_id::DefIdSet, rustc_hir::def_id::DefIdSet;
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_middle/mir/interpret/queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,12 @@ impl<'tcx> TyCtxt<'tcx> {
pub fn const_eval_resolve(
self,
param_env: ty::ParamEnv<'tcx>,
def_id: DefId,
def: ty::WithOptConstParam<DefId>,
substs: SubstsRef<'tcx>,
promoted: Option<mir::Promoted>,
span: Option<Span>,
) -> ConstEvalResult<'tcx> {
match ty::Instance::resolve(self, param_env, def_id, substs) {
match ty::Instance::resolve_opt_const_arg(self, param_env, def, substs) {
Ok(Some(instance)) => {
let cid = GlobalId { instance, promoted };
self.const_eval_global_id(param_env, cid, span)
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_middle/mir/mono.rs
Original file line number Diff line number Diff line change
Expand Up @@ -346,8 +346,8 @@ impl<'tcx> CodegenUnit<'tcx> {
// instances into account. The others don't matter for
// the codegen tests and can even make item order
// unstable.
InstanceDef::Item(def_id) => {
def_id.as_local().map(|def_id| tcx.hir().as_local_hir_id(def_id))
InstanceDef::Item(def) => {
def.did.as_local().map(|def_id| tcx.hir().as_local_hir_id(def_id))
}
InstanceDef::VtableShim(..)
| InstanceDef::ReifyShim(..)
Expand Down
40 changes: 38 additions & 2 deletions src/librustc_middle/mir/query.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
//! Values computed by queries that use MIR.

use crate::ty::{self, Ty};
use crate::mir::{Body, Promoted};
use crate::ty::{self, Ty, TyCtxt};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync::Lrc;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_index::bit_set::BitMatrix;
use rustc_index::vec::IndexVec;
use rustc_span::{Span, Symbol};
Expand Down Expand Up @@ -323,3 +324,38 @@ pub struct CoverageInfo {
/// The total number of coverage region counters added to the MIR `Body`.
pub num_counters: u32,
}

impl<'tcx> TyCtxt<'tcx> {
pub fn mir_borrowck_opt_const_arg(
self,
def: ty::WithOptConstParam<LocalDefId>,
) -> &'tcx BorrowCheckResult<'tcx> {
if let Some(param_did) = def.const_param_did {
self.mir_borrowck_const_arg((def.did, param_did))
} else {
self.mir_borrowck(def.did)
}
}

pub fn mir_const_qualif_opt_const_arg(
self,
def: ty::WithOptConstParam<LocalDefId>,
) -> ConstQualifs {
if let Some(param_did) = def.const_param_did {
self.mir_const_qualif_const_arg((def.did, param_did))
} else {
self.mir_const_qualif(def.did)
}
}

pub fn promoted_mir_of_opt_const_arg(
self,
def: ty::WithOptConstParam<DefId>,
) -> &'tcx IndexVec<Promoted, Body<'tcx>> {
if let Some((did, param_did)) = def.as_const_arg() {
self.promoted_mir_of_const_arg((did, param_did))
} else {
self.promoted_mir(def.did)
}
}
}
Loading

0 comments on commit 7e11379

Please sign in to comment.