Skip to content

Commit

Permalink
Auto merge of #40008 - eddyb:lazy-12, r=nikomatsakis
Browse files Browse the repository at this point in the history
[12/12] On-demand type-checking, const-evaluation, MIR building & const-qualification.

_This is the last of a series ([prev](#38813)) of patches designed to rework rustc into an out-of-order on-demand pipeline model for both better feature support (e.g. [MIR-based](https://github.com/solson/miri) early constant evaluation) and incremental execution of compiler passes (e.g. type-checking), with beneficial consequences to IDE support as well.
If any motivation is unclear, please ask for additional PR description clarifications or code comments._

<hr>

As this contains all of the changes that didn't fit neatly into other PRs, I'll be elaborating a bit:

### User-facing changes
* when determining whether an `impl Trait` type implements an auto-trait (e.g. `Send` or `Sync`), the function the `impl Trait` came from has to be inferred and type-checking, disallowing cycles
  * this results from not having an obvious place to put the "deferred obligation" in on-demand atm
  * while we could model side-effects like that and "post-processing passes" better, it's still more limiting than being able to know the result in the original function (e.g. specialization) *and* there are serious problems around region-checking (if a `Send` impl required `'static`, it wasn't enforced)
* early const-eval requires type-checking and const-qualification to be performed first, which means:
  * you get the intended errors before (if any) constant evaluation error that is simply fallout
  * associated consts should always work now, and `const fn` type parameters are properly tracked
    * don't get too excited, array lengths still can't depend on type parameters
* #38864 works as intended now, with `Self` being allowed in `impl` bounds
* #32205 is largely improved, with associated types being limited to "exact match" `impl`s (as opposed to traversing the specialization graph to resolve unspecified type parameters to their defaults in another `impl` or in the `trait`) *while* checking for overlaps building the specialization graph for that trait - once all the trait impls' have been checked for coherence (including ahead-of-time/on-demand), it's uniform
* [crater report](https://gist.github.com/eddyb/bbb869072468c7e08d6d808e75938051) looks clean (aside from `clippy` which broke due to `rustc` internal changes)

### Compiler-internal changes
* `ty::Generics`
  * no longer contains the actual type parameter defaults, instead they're associated with the type parameter's `DefId`, like associated types in a trait definition
    * this allows computing `ty::Generics` as a leaf (reading only its own HIR)
  * holds a mapping from `DefIndex` of type parameters to their indices
* `ty::AdtDef`
  * only tracks `#[repr(simd)]` in its `ReprOptions` `repr` field
  * doesn't contain `enum` discriminant values, but instead each variant either refers to either an explicit value for its discriminant, or the distance from the last explicit discriminant, if any
    * the `.discriminants(tcx)` method produces an iterator of `ConstInt` values, looking up explicit discriminants in a separate map, if necessary
    * this allows computing `ty::AdtDef` as a leaf (reading only its own HIR)
* Small note: the two above (`Generics`, `AdtDef`), `TraitDef` and `AssociatedItem` should probably end up as part of the HIR, eventually, as they're trivially constructed from it
* `ty::FnSig`
  * now also holds ABI and unsafety, alongside argument types, return type and C variadicity
  * `&ty::BareFnTy` and `ty::ClosureTy` have been replaced with `PolyFnSig = Binder<FnSig>`
    * `BareFnTy` was interned and `ClosureTy` was treated as non-trivial to `Clone` because they had a `PolyFnSig` and so used to contain a `Vec<Ty>` (now `&[Ty]`)
* `ty::maps`
  * all the `DepTrackingMap`s have been grouped in a structure available at `tcx.maps`
  * when creating the `tcx`, a set of `Providers` (one `fn` pointer per map) is required for the local crate, and one for all other crates (i.e. metadata loading), `librustc_driver` plugging the various crates (e.g. `librustc_metadata`, `librustc_typeck`, `librustc_mir`) into it
  * when a map is queried and the value is missing, the appropriate `fn` pointer from the `Providers` of that crate is called with the `TyCtxt` and the key being queried, to produce the value on-demand
* `rustc_const_eval`
  * demands both `typeck_tables` and `mir_const_qualif` (in preparation for miri)
  * tracks `Substs` in `ConstVal::Function` for `const fn` calls
  * returns `TypeckError` if type-checking has failed (or cases that can only be reached if it had)
    * this error kind is never reported, resulting in less noisy/redundant diagnostics
  * fixes #39548 (testcase by @larsluthman, taken from #39812, which this supersedes)
* on-demand has so far been hooked up to:
  * `rustc_metadata::cstore_impl`: `ty`, `generics`, `predicates`, `super_predicates`, `trait_def`, `adt_def`, `variances`, `associated_item_def_ids`, `associated_item`, `impl_trait_ref`, `custom_coerce_unsized_kind`, `mir`, `mir_const_qualif`, `typeck_tables`, `closure_kind`, `closure_type`
  * `rustc_typeck::collect`: `ty`, `generics`, `predicates`, `super_predicates`, `type_param_predicates`, `trait_def`, `adt_def`, `impl_trait_ref`
  * `rustc_typeck::coherence`: `coherent_trait`, `coherent_inherent_impls`
  * `rustc_typeck::check`: `typeck_tables`, `closure_type`, `closure_kind`
  * `rustc_mir::mir_map`: `mir`
  * `rustc_mir::transform::qualify_consts`: `mir_const_qualif`
  • Loading branch information
bors committed Feb 25, 2017
2 parents 1572bf1 + afc00b0 commit 136d4d0
Show file tree
Hide file tree
Showing 207 changed files with 4,864 additions and 5,881 deletions.
8 changes: 8 additions & 0 deletions src/librustc/dep_graph/dep_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ pub enum DepNode<D: Clone + Debug> {
Resolve,
EntryPoint,
CheckEntryFn,
CoherenceCheckTrait(D),
CoherenceCheckImpl(D),
CoherenceOverlapCheck(D),
CoherenceOverlapCheckSpecial(D),
Expand Down Expand Up @@ -109,11 +110,13 @@ pub enum DepNode<D: Clone + Debug> {
// predicates for an item wind up in `ItemSignature`).
AssociatedItems(D),
ItemSignature(D),
TypeParamPredicates((D, D)),
SizedConstraint(D),
AssociatedItemDefIds(D),
InherentImpls(D),
TypeckTables(D),
UsedTraitImports(D),
MonomorphicConstEval(D),

// The set of impls for a given trait. Ultimately, it would be
// nice to get more fine-grained here (e.g., to include a
Expand Down Expand Up @@ -239,6 +242,7 @@ impl<D: Clone + Debug> DepNode<D> {
MetaData(ref d) => op(d).map(MetaData),
CollectItem(ref d) => op(d).map(CollectItem),
CollectItemSig(ref d) => op(d).map(CollectItemSig),
CoherenceCheckTrait(ref d) => op(d).map(CoherenceCheckTrait),
CoherenceCheckImpl(ref d) => op(d).map(CoherenceCheckImpl),
CoherenceOverlapCheck(ref d) => op(d).map(CoherenceOverlapCheck),
CoherenceOverlapCheckSpecial(ref d) => op(d).map(CoherenceOverlapCheckSpecial),
Expand All @@ -258,11 +262,15 @@ impl<D: Clone + Debug> DepNode<D> {
TransInlinedItem(ref d) => op(d).map(TransInlinedItem),
AssociatedItems(ref d) => op(d).map(AssociatedItems),
ItemSignature(ref d) => op(d).map(ItemSignature),
TypeParamPredicates((ref item, ref param)) => {
Some(TypeParamPredicates((try_opt!(op(item)), try_opt!(op(param)))))
}
SizedConstraint(ref d) => op(d).map(SizedConstraint),
AssociatedItemDefIds(ref d) => op(d).map(AssociatedItemDefIds),
InherentImpls(ref d) => op(d).map(InherentImpls),
TypeckTables(ref d) => op(d).map(TypeckTables),
UsedTraitImports(ref d) => op(d).map(UsedTraitImports),
MonomorphicConstEval(ref d) => op(d).map(MonomorphicConstEval),
TraitImpls(ref d) => op(d).map(TraitImpls),
TraitItems(ref d) => op(d).map(TraitItems),
ReprHints(ref d) => op(d).map(ReprHints),
Expand Down
6 changes: 6 additions & 0 deletions src/librustc/dep_graph/dep_tracking_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use hir::def_id::DefId;
use rustc_data_structures::fx::FxHashMap;
use std::cell::RefCell;
use std::collections::hash_map::Entry;
use std::ops::Index;
use std::hash::Hash;
use std::marker::PhantomData;
Expand Down Expand Up @@ -67,6 +68,11 @@ impl<M: DepTrackingMapConfig> DepTrackingMap<M> {
assert!(old_value.is_none());
}

pub fn entry(&mut self, k: M::Key) -> Entry<M::Key, M::Value> {
self.write(&k);
self.map.entry(k)
}

pub fn contains_key(&self, k: &M::Key) -> bool {
self.read(k);
self.map.contains_key(k)
Expand Down
90 changes: 17 additions & 73 deletions src/librustc/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -390,44 +390,6 @@ RFC. It is, however, [currently unimplemented][iss15872].
[iss15872]: https://github.com/rust-lang/rust/issues/15872
"##,

E0109: r##"
You tried to give a type parameter to a type which doesn't need it. Erroneous
code example:
```compile_fail,E0109
type X = u32<i32>; // error: type parameters are not allowed on this type
```
Please check that you used the correct type and recheck its definition. Perhaps
it doesn't need the type parameter.
Example:
```
type X = u32; // this compiles
```
Note that type parameters for enum-variant constructors go after the variant,
not after the enum (Option::None::<u32>, not Option::<u32>::None).
"##,

E0110: r##"
You tried to give a lifetime parameter to a type which doesn't need it.
Erroneous code example:
```compile_fail,E0110
type X = u32<'static>; // error: lifetime parameters are not allowed on
// this type
```
Please check that the correct type was used and recheck its definition; perhaps
it doesn't need the lifetime parameter. Example:
```
type X = u32; // ok!
```
"##,

E0133: r##"
Unsafe code was used outside of an unsafe function or block.
Expand Down Expand Up @@ -627,41 +589,6 @@ attributes:
See also https://doc.rust-lang.org/book/no-stdlib.html
"##,

E0229: r##"
An associated type binding was done outside of the type parameter declaration
and `where` clause. Erroneous code example:
```compile_fail,E0229
pub trait Foo {
type A;
fn boo(&self) -> <Self as Foo>::A;
}
struct Bar;
impl Foo for isize {
type A = usize;
fn boo(&self) -> usize { 42 }
}
fn baz<I>(x: &<I as Foo<A=Bar>>::A) {}
// error: associated type bindings are not allowed here
```
To solve this error, please move the type bindings in the type parameter
declaration:
```ignore
fn baz<I: Foo<A=Bar>>(x: &<I as Foo>::A) {} // ok!
```
Or in the `where` clause:
```ignore
fn baz<I>(x: &<I as Foo>::A) where I: Foo<A=Bar> {}
```
"##,

E0261: r##"
When using a lifetime like `'a` in a type, it must be declared before being
used.
Expand Down Expand Up @@ -1390,6 +1317,23 @@ error. To resolve it, add an `else` block having the same type as the `if`
block.
"##,

E0391: r##"
This error indicates that some types or traits depend on each other
and therefore cannot be constructed.
The following example contains a circular dependency between two traits:
```compile_fail,E0391
trait FirstTrait : SecondTrait {
}
trait SecondTrait : FirstTrait {
}
```
"##,

E0398: r##"
In Rust 1.3, the default object lifetime bounds are expected to change, as
described in RFC #1156 [1]. You are getting a warning because the compiler
Expand Down
24 changes: 22 additions & 2 deletions src/librustc/hir/lowering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ pub struct LoweringContext<'a> {
impl_items: BTreeMap<hir::ImplItemId, hir::ImplItem>,
bodies: FxHashMap<hir::BodyId, hir::Body>,

trait_impls: BTreeMap<DefId, Vec<NodeId>>,
trait_default_impl: BTreeMap<DefId, NodeId>,

loop_scopes: Vec<NodeId>,
is_in_loop_condition: bool,

Expand Down Expand Up @@ -116,6 +119,8 @@ pub fn lower_crate(sess: &Session,
trait_items: BTreeMap::new(),
impl_items: BTreeMap::new(),
bodies: FxHashMap(),
trait_impls: BTreeMap::new(),
trait_default_impl: BTreeMap::new(),
loop_scopes: Vec::new(),
is_in_loop_condition: false,
type_def_lifetime_params: DefIdMap(),
Expand Down Expand Up @@ -201,6 +206,8 @@ impl<'a> LoweringContext<'a> {
trait_items: self.trait_items,
impl_items: self.impl_items,
bodies: self.bodies,
trait_impls: self.trait_impls,
trait_default_impl: self.trait_default_impl,
}
}

Expand Down Expand Up @@ -525,7 +532,7 @@ impl<'a> LoweringContext<'a> {
return n;
}
assert!(!def_id.is_local());
let (n, _) = self.sess.cstore.item_generics_own_param_counts(def_id);
let n = self.sess.cstore.item_generics_cloned(def_id).regions.len();
self.type_def_lifetime_params.insert(def_id, n);
n
});
Expand Down Expand Up @@ -1089,14 +1096,27 @@ impl<'a> LoweringContext<'a> {
hir::ItemUnion(vdata, self.lower_generics(generics))
}
ItemKind::DefaultImpl(unsafety, ref trait_ref) => {
let trait_ref = self.lower_trait_ref(trait_ref);

if let Def::Trait(def_id) = trait_ref.path.def {
self.trait_default_impl.insert(def_id, id);
}

hir::ItemDefaultImpl(self.lower_unsafety(unsafety),
self.lower_trait_ref(trait_ref))
trait_ref)
}
ItemKind::Impl(unsafety, polarity, ref generics, ref ifce, ref ty, ref impl_items) => {
let new_impl_items = impl_items.iter()
.map(|item| self.lower_impl_item_ref(item))
.collect();
let ifce = ifce.as_ref().map(|trait_ref| self.lower_trait_ref(trait_ref));

if let Some(ref trait_ref) = ifce {
if let Def::Trait(def_id) = trait_ref.path.def {
self.trait_impls.entry(def_id).or_insert(vec![]).push(id);
}
}

hir::ItemImpl(self.lower_unsafety(unsafety),
self.lower_impl_polarity(polarity),
self.lower_generics(generics),
Expand Down
44 changes: 44 additions & 0 deletions src/librustc/hir/map/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,50 @@ impl<'hir> Map<'hir> {
self.local_def_id(self.body_owner(id))
}

pub fn ty_param_owner(&self, id: NodeId) -> NodeId {
match self.get(id) {
NodeItem(&Item { node: ItemTrait(..), .. }) => id,
NodeTyParam(_) => self.get_parent_node(id),
_ => {
bug!("ty_param_owner: {} not a type parameter",
self.node_to_string(id))
}
}
}

pub fn ty_param_name(&self, id: NodeId) -> Name {
match self.get(id) {
NodeItem(&Item { node: ItemTrait(..), .. }) => {
keywords::SelfType.name()
}
NodeTyParam(tp) => tp.name,
_ => {
bug!("ty_param_name: {} not a type parameter",
self.node_to_string(id))
}
}
}

pub fn trait_impls(&self, trait_did: DefId) -> &'hir [NodeId] {
self.dep_graph.read(DepNode::TraitImpls(trait_did));

// NB: intentionally bypass `self.forest.krate()` so that we
// do not trigger a read of the whole krate here
self.forest.krate.trait_impls.get(&trait_did).map_or(&[], |xs| &xs[..])
}

pub fn trait_default_impl(&self, trait_did: DefId) -> Option<NodeId> {
self.dep_graph.read(DepNode::TraitImpls(trait_did));

// NB: intentionally bypass `self.forest.krate()` so that we
// do not trigger a read of the whole krate here
self.forest.krate.trait_default_impl.get(&trait_did).cloned()
}

pub fn trait_is_auto(&self, trait_did: DefId) -> bool {
self.trait_default_impl(trait_did).is_some()
}

/// Get the attributes on the krate. This is preferable to
/// invoking `krate.attrs` because it registers a tighter
/// dep-graph access.
Expand Down
3 changes: 3 additions & 0 deletions src/librustc/hir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,9 @@ pub struct Crate {
pub trait_items: BTreeMap<TraitItemId, TraitItem>,
pub impl_items: BTreeMap<ImplItemId, ImplItem>,
pub bodies: FxHashMap<BodyId, Body>,

pub trait_impls: BTreeMap<DefId, Vec<NodeId>>,
pub trait_default_impl: BTreeMap<DefId, NodeId>,
}

impl Crate {
Expand Down
31 changes: 15 additions & 16 deletions src/librustc/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -505,7 +505,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> {
evaluation_cache: traits::EvaluationCache::new(),
projection_cache: RefCell::new(traits::ProjectionCache::new()),
reported_trait_errors: RefCell::new(FxHashSet()),
projection_mode: Reveal::NotSpecializable,
projection_mode: Reveal::UserFacing,
tainted_by_errors_flag: Cell::new(false),
err_count_on_creation: self.sess.err_count(),
obligations_in_snapshot: Cell::new(false),
Expand Down Expand Up @@ -600,7 +600,7 @@ impl_trans_normalize!('gcx,
Ty<'gcx>,
&'gcx Substs<'gcx>,
ty::FnSig<'gcx>,
&'gcx ty::BareFnTy<'gcx>,
ty::PolyFnSig<'gcx>,
ty::ClosureSubsts<'gcx>,
ty::PolyTraitRef<'gcx>,
ty::ExistentialTraitRef<'gcx>
Expand Down Expand Up @@ -1197,16 +1197,19 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
/// as the substitutions for the default, `(T, U)`.
pub fn type_var_for_def(&self,
span: Span,
def: &ty::TypeParameterDef<'tcx>,
def: &ty::TypeParameterDef,
substs: &[Kind<'tcx>])
-> Ty<'tcx> {
let default = def.default.map(|default| {
type_variable::Default {
let default = if def.has_default {
let default = self.tcx.item_type(def.def_id);
Some(type_variable::Default {
ty: default.subst_spanned(self.tcx, substs, Some(span)),
origin_span: span,
def_id: def.default_def_id
}
});
def_id: def.def_id
})
} else {
None
};


let ty_var_id = self.type_variables
Expand Down Expand Up @@ -1646,20 +1649,16 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
Some(self.tcx.closure_kind(def_id))
}

pub fn closure_type(&self,
def_id: DefId,
substs: ty::ClosureSubsts<'tcx>)
-> ty::ClosureTy<'tcx>
{
pub fn closure_type(&self, def_id: DefId) -> ty::PolyFnSig<'tcx> {
if let InferTables::InProgress(tables) = self.tables {
if let Some(id) = self.tcx.hir.as_local_node_id(def_id) {
if let Some(ty) = tables.borrow().closure_tys.get(&id) {
return ty.subst(self.tcx, substs.substs);
if let Some(&ty) = tables.borrow().closure_tys.get(&id) {
return ty;
}
}
}

self.tcx.closure_type(def_id, substs)
self.tcx.closure_type(def_id)
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/librustc/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
#![feature(rustc_diagnostic_macros)]
#![feature(rustc_private)]
#![feature(slice_patterns)]
#![feature(specialization)]
#![feature(staged_api)]
#![feature(unboxed_closures)]

Expand Down Expand Up @@ -75,7 +76,6 @@ pub mod infer;
pub mod lint;

pub mod middle {
pub mod astconv_util;
pub mod expr_use_visitor;
pub mod const_val;
pub mod cstore;
Expand Down
Loading

0 comments on commit 136d4d0

Please sign in to comment.