Skip to content

Commit

Permalink
Auto merge of #48411 - nikomatsakis:chalkify-canonical-query-mir, r=e…
Browse files Browse the repository at this point in the history
…ddyb

introduce canonical queries, use for normalization and dropck-outlives

This branch adds in the concept of a **canonicalized trait query** and uses it for three specific operations:

- `infcx.at(cause, param_env).normalize(type_foldable)`
    - normalizes all associated types in `type_foldable`
- `tcx.normalize_erasing_regions(param_env, type_foldable)`
    - like normalize, but erases regions first and in the result; this leads to better caching
- `infcx.at(cause, param_env).dropck_outlives(ty)`
    - produces the set of types that must be live when a value of type `ty` is dropped
    - used from dropck but also NLL outlives

This is a kind of "first step" towards a more Chalk-ified approach. It leads to a **big** speedup for NLL, which is basically dominated by the dropck-outlives computation. Here are some timing measurements for the `syn` crate (pre-branch measurements coming soon):

| Commit | NLL disabled | NLL enabled |
| ------- | --- | --- |
| Before my branch | 5.43s | 8.99s |
| After my branch | 5.36s | 7.25s |

(Note that NLL enabled still does *all the work* that NLL disabled does, so this is not really a way to compare the performance of NLL versus the AST-based borrow checker directly.) Since this affects all codepaths, I'd like to do a full perf run before we land anything.

Also, this is not the "final point" for canonicalization etc. I think canonicalization can be made substantially faster, for one thing. But it seems like a reasonable starting point for a branch that's gotten a bit larger than I would have liked.

**Commit convention:** First of all, this entire branch ought to be a "pure refactoring", I believe, not changing anything about external behavior. Second, I've tagged the most important commits with `[VIC]` (very important commit), so you can scan for those. =)

r? @eddyb
  • Loading branch information
bors committed Mar 13, 2018
2 parents e65547d + 17c4103 commit 8c4ff22
Show file tree
Hide file tree
Showing 109 changed files with 3,783 additions and 1,706 deletions.
14 changes: 14 additions & 0 deletions src/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

54 changes: 30 additions & 24 deletions src/librustc/dep_graph/dep_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,12 @@ use hir::{HirId, ItemLocalId};

use ich::{Fingerprint, StableHashingContext};
use rustc_data_structures::stable_hasher::{StableHasher, HashStable};
use ty::{TyCtxt, Instance, InstanceDef, ParamEnv, ParamEnvAnd, PolyTraitRef, Ty};
use ty::subst::Substs;
use std::fmt;
use std::hash::Hash;
use syntax_pos::symbol::InternedString;
use traits::query::{CanonicalProjectionGoal, CanonicalTyGoal};
use ty::{TyCtxt, Instance, InstanceDef, ParamEnv, ParamEnvAnd, PolyTraitRef, Ty};
use ty::subst::Substs;

// erase!() just makes tokens go away. It's used to specify which macro argument
// is repeated (i.e. which sub-expression of the macro we are in) but don't need
Expand All @@ -80,6 +81,10 @@ macro_rules! erase {
($x:tt) => ({})
}

macro_rules! replace {
($x:tt with $($y:tt)*) => ($($y)*)
}

macro_rules! is_anon_attr {
(anon) => (true);
($attr:ident) => (false);
Expand Down Expand Up @@ -111,7 +116,7 @@ macro_rules! define_dep_nodes {
(<$tcx:tt>
$(
[$($attr:ident),* ]
$variant:ident $(( $($tuple_arg:tt),* ))*
$variant:ident $(( $tuple_arg_ty:ty $(,)* ))*
$({ $($struct_arg_name:ident : $struct_arg_ty:ty),* })*
,)*
) => (
Expand All @@ -134,7 +139,7 @@ macro_rules! define_dep_nodes {

// tuple args
$({
return <( $($tuple_arg,)* ) as DepNodeParams>
return <$tuple_arg_ty as DepNodeParams>
::CAN_RECONSTRUCT_QUERY_KEY;
})*

Expand Down Expand Up @@ -186,7 +191,7 @@ macro_rules! define_dep_nodes {
DepKind :: $variant => {
// tuple args
$({
$(erase!($tuple_arg);)*
erase!($tuple_arg_ty);
return true;
})*

Expand All @@ -205,7 +210,7 @@ macro_rules! define_dep_nodes {

pub enum DepConstructor<$tcx> {
$(
$variant $(( $($tuple_arg),* ))*
$variant $(( $tuple_arg_ty ))*
$({ $($struct_arg_name : $struct_arg_ty),* })*
),*
}
Expand All @@ -227,15 +232,14 @@ macro_rules! define_dep_nodes {
{
match dep {
$(
DepConstructor :: $variant $(( $($tuple_arg),* ))*
DepConstructor :: $variant $(( replace!(($tuple_arg_ty) with arg) ))*
$({ $($struct_arg_name),* })*
=>
{
// tuple args
$({
let tupled_args = ( $($tuple_arg,)* );
let hash = DepNodeParams::to_fingerprint(&tupled_args,
tcx);
erase!($tuple_arg_ty);
let hash = DepNodeParams::to_fingerprint(&arg, tcx);
let dep_node = DepNode {
kind: DepKind::$variant,
hash
Expand All @@ -247,7 +251,7 @@ macro_rules! define_dep_nodes {
tcx.sess.opts.debugging_opts.query_dep_graph)
{
tcx.dep_graph.register_dep_node_debug_str(dep_node, || {
tupled_args.to_debug_str(tcx)
arg.to_debug_str(tcx)
});
}

Expand Down Expand Up @@ -631,7 +635,9 @@ define_dep_nodes!( <'tcx>
[] CodegenUnit(InternedString),
[] CompileCodegenUnit(InternedString),
[input] OutputFilenames,
[anon] NormalizeTy,
[] NormalizeProjectionTy(CanonicalProjectionGoal<'tcx>),
[] NormalizeTyAfterErasingRegions(ParamEnvAnd<'tcx, Ty<'tcx>>),
[] DropckOutlives(CanonicalTyGoal<'tcx>),

[] SubstituteNormalizeAndTestPredicates { key: (DefId, &'tcx Substs<'tcx>) },

Expand Down Expand Up @@ -679,43 +685,43 @@ impl<'a, 'gcx: 'tcx + 'a, 'tcx: 'a, T> DepNodeParams<'a, 'gcx, 'tcx> for T
}
}

impl<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> DepNodeParams<'a, 'gcx, 'tcx> for (DefId,) {
impl<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> DepNodeParams<'a, 'gcx, 'tcx> for DefId {
const CAN_RECONSTRUCT_QUERY_KEY: bool = true;

fn to_fingerprint(&self, tcx: TyCtxt) -> Fingerprint {
tcx.def_path_hash(self.0).0
tcx.def_path_hash(*self).0
}

fn to_debug_str(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> String {
tcx.item_path_str(self.0)
tcx.item_path_str(*self)
}
}

impl<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> DepNodeParams<'a, 'gcx, 'tcx> for (DefIndex,) {
impl<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> DepNodeParams<'a, 'gcx, 'tcx> for DefIndex {
const CAN_RECONSTRUCT_QUERY_KEY: bool = true;

fn to_fingerprint(&self, tcx: TyCtxt) -> Fingerprint {
tcx.hir.definitions().def_path_hash(self.0).0
tcx.hir.definitions().def_path_hash(*self).0
}

fn to_debug_str(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> String {
tcx.item_path_str(DefId::local(self.0))
tcx.item_path_str(DefId::local(*self))
}
}

impl<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> DepNodeParams<'a, 'gcx, 'tcx> for (CrateNum,) {
impl<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> DepNodeParams<'a, 'gcx, 'tcx> for CrateNum {
const CAN_RECONSTRUCT_QUERY_KEY: bool = true;

fn to_fingerprint(&self, tcx: TyCtxt) -> Fingerprint {
let def_id = DefId {
krate: self.0,
krate: *self,
index: CRATE_DEF_INDEX,
};
tcx.def_path_hash(def_id).0
}

fn to_debug_str(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> String {
tcx.crate_name(self.0).as_str().to_string()
tcx.crate_name(*self).as_str().to_string()
}
}

Expand Down Expand Up @@ -743,17 +749,17 @@ impl<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> DepNodeParams<'a, 'gcx, 'tcx> for (DefId, De
}
}

impl<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> DepNodeParams<'a, 'gcx, 'tcx> for (HirId,) {
impl<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> DepNodeParams<'a, 'gcx, 'tcx> for HirId {
const CAN_RECONSTRUCT_QUERY_KEY: bool = false;

// We actually would not need to specialize the implementation of this
// method but it's faster to combine the hashes than to instantiate a full
// hashing context and stable-hashing state.
fn to_fingerprint(&self, tcx: TyCtxt) -> Fingerprint {
let (HirId {
let HirId {
owner,
local_id: ItemLocalId(local_id),
},) = *self;
} = *self;

let def_path_hash = tcx.def_path_hash(DefId::local(owner));
let local_id = Fingerprint::from_smaller_hash(local_id as u64);
Expand Down
65 changes: 57 additions & 8 deletions src/librustc/ich/impls_ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use std::cell::RefCell;
use std::hash as std_hash;
use std::mem;
use middle::region;
use infer;
use traits;
use ty;
use mir;
Expand Down Expand Up @@ -85,6 +86,9 @@ for ty::RegionKind {
ty::ReEmpty => {
// No variant fields to hash for these ...
}
ty::ReCanonical(c) => {
c.hash_stable(hcx, hasher);
}
ty::ReLateBound(db, ty::BrAnon(i)) => {
db.depth.hash_stable(hcx, hasher);
i.hash_stable(hcx, hasher);
Expand Down Expand Up @@ -130,6 +134,16 @@ impl<'a> HashStable<StableHashingContext<'a>> for ty::RegionVid {
}
}

impl<'gcx> HashStable<StableHashingContext<'gcx>> for ty::CanonicalVar {
#[inline]
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>,
hasher: &mut StableHasher<W>) {
use rustc_data_structures::indexed_vec::Idx;
self.index().hash_stable(hcx, hasher);
}
}

impl<'a, 'gcx> HashStable<StableHashingContext<'a>>
for ty::adjustment::AutoBorrow<'gcx> {
fn hash_stable<W: StableHasherResult>(&self,
Expand Down Expand Up @@ -1003,12 +1017,6 @@ impl_stable_hash_for!(struct ty::Destructor {
did
});

impl_stable_hash_for!(struct ty::DtorckConstraint<'tcx> {
outlives,
dtorck_types
});


impl<'a> HashStable<StableHashingContext<'a>> for ty::CrateVariancesMap {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a>,
Expand Down Expand Up @@ -1229,11 +1237,52 @@ for traits::VtableGeneratorData<'gcx, N> where N: HashStable<StableHashingContex
}
}

impl<'gcx> HashStable<StableHashingContext<'gcx>>
impl<'a> HashStable<StableHashingContext<'a>>
for ty::UniverseIndex {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'gcx>,
hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) {
self.depth().hash_stable(hcx, hasher);
}
}

impl_stable_hash_for!(
impl<'tcx, V> for struct infer::canonical::Canonical<'tcx, V> {
variables, value
}
);

impl_stable_hash_for!(
impl<'tcx> for struct infer::canonical::CanonicalVarValues<'tcx> {
var_values
}
);

impl_stable_hash_for!(struct infer::canonical::CanonicalVarInfo {
kind
});

impl_stable_hash_for!(enum infer::canonical::CanonicalVarKind {
Ty(k),
Region
});

impl_stable_hash_for!(enum infer::canonical::CanonicalTyVarKind {
General,
Int,
Float
});

impl_stable_hash_for!(
impl<'tcx, R> for struct infer::canonical::QueryResult<'tcx, R> {
var_values, region_constraints, certainty, value
}
);

impl_stable_hash_for!(struct infer::canonical::QueryRegionConstraints<'tcx> {
region_outlives, ty_outlives
});

impl_stable_hash_for!(enum infer::canonical::Certainty {
Proven, Ambiguous
});
20 changes: 17 additions & 3 deletions src/librustc/infer/at.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ use super::*;
use ty::relate::{Relate, TypeRelation};

pub struct At<'a, 'gcx: 'tcx, 'tcx: 'a> {
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
cause: &'a ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
pub infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
pub cause: &'a ObligationCause<'tcx>,
pub param_env: ty::ParamEnv<'tcx>,
}

pub struct Trace<'a, 'gcx: 'tcx, 'tcx: 'a> {
Expand Down Expand Up @@ -281,6 +281,20 @@ impl<'tcx> ToTrace<'tcx> for Ty<'tcx> {
}
}

impl<'tcx> ToTrace<'tcx> for ty::Region<'tcx> {
fn to_trace(cause: &ObligationCause<'tcx>,
a_is_expected: bool,
a: Self,
b: Self)
-> TypeTrace<'tcx>
{
TypeTrace {
cause: cause.clone(),
values: Regions(ExpectedFound::new(a_is_expected, a, b))
}
}
}

impl<'tcx> ToTrace<'tcx> for ty::TraitRef<'tcx> {
fn to_trace(cause: &ObligationCause<'tcx>,
a_is_expected: bool,
Expand Down
Loading

0 comments on commit 8c4ff22

Please sign in to comment.