Auto merge of #48411 - nikomatsakis:chalkify-canonical-query-mir, r=eddyb

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
This commit is contained in:
bors
2018-03-13 15:24:45 +00:00
109 changed files with 3784 additions and 1707 deletions
+14
View File
@@ -1884,6 +1884,7 @@ dependencies = [
"rustc_privacy 0.0.0",
"rustc_resolve 0.0.0",
"rustc_save_analysis 0.0.0",
"rustc_traits 0.0.0",
"rustc_trans_utils 0.0.0",
"rustc_typeck 0.0.0",
"serialize 0.0.0",
@@ -2068,6 +2069,19 @@ dependencies = [
"syntax_pos 0.0.0",
]
[[package]]
name = "rustc_traits"
version = "0.0.0"
dependencies = [
"bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"graphviz 0.0.0",
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc 0.0.0",
"rustc_data_structures 0.0.0",
"syntax 0.0.0",
"syntax_pos 0.0.0",
]
[[package]]
name = "rustc_trans"
version = "0.0.0"
+30 -24
View File
@@ -67,11 +67,12 @@
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
@@ -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);
@@ -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),* })*
,)*
) => (
@@ -134,7 +139,7 @@ pub fn can_reconstruct_query_key<$tcx>(&self) -> bool {
// tuple args
$({
return <( $($tuple_arg,)* ) as DepNodeParams>
return <$tuple_arg_ty as DepNodeParams>
::CAN_RECONSTRUCT_QUERY_KEY;
})*
@@ -186,7 +191,7 @@ pub fn has_params(&self) -> bool {
DepKind :: $variant => {
// tuple args
$({
$(erase!($tuple_arg);)*
erase!($tuple_arg_ty);
return true;
})*
@@ -205,7 +210,7 @@ pub fn has_params(&self) -> bool {
pub enum DepConstructor<$tcx> {
$(
$variant $(( $($tuple_arg),* ))*
$variant $(( $tuple_arg_ty ))*
$({ $($struct_arg_name : $struct_arg_ty),* })*
),*
}
@@ -227,15 +232,14 @@ pub fn new<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
{
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
@@ -247,7 +251,7 @@ pub fn new<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
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)
});
}
@@ -631,7 +635,9 @@ pub fn fingerprint_needed_for_crate_hash(self) -> bool {
[] 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>) },
@@ -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()
}
}
@@ -743,17 +749,17 @@ fn to_debug_str(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> String {
}
}
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);
+57 -8
View File
@@ -19,6 +19,7 @@
use std::hash as std_hash;
use std::mem;
use middle::region;
use infer;
use traits;
use ty;
use mir;
@@ -85,6 +86,9 @@ fn hash_stable<W: StableHasherResult>(&self,
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);
@@ -130,6 +134,16 @@ fn hash_stable<W: StableHasherResult>(&self,
}
}
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,
@@ -1003,12 +1017,6 @@ fn hash_stable<W: StableHasherResult>(&self,
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>,
@@ -1229,11 +1237,52 @@ fn hash_stable<W: StableHasherResult>(&self,
}
}
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
});
+17 -3
View File
@@ -40,9 +40,9 @@
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> {
@@ -281,6 +281,20 @@ fn to_trace(cause: &ObligationCause<'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,
+942
View File
@@ -0,0 +1,942 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! **Canonicalization** is the key to constructing a query in the
//! middle of type inference. Ordinarily, it is not possible to store
//! types from type inference in query keys, because they contain
//! references to inference variables whose lifetimes are too short
//! and so forth. Canonicalizing a value T1 using `canonicalize_query`
//! produces two things:
//!
//! - a value T2 where each unbound inference variable has been
//! replaced with a **canonical variable**;
//! - a map M (of type `CanonicalVarValues`) from those canonical
//! variables back to the original.
//!
//! We can then do queries using T2. These will give back constriants
//! on the canonical variables which can be translated, using the map
//! M, into constraints in our source context. This process of
//! translating the results back is done by the
//! `instantiate_query_result` method.
//!
//! For a more detailed look at what is happening here, check
//! out the [chapter in the rustc guide][c].
//!
//! [c]: https://rust-lang-nursery.github.io/rustc-guide/traits-canonicalization.html
use infer::{InferCtxt, InferOk, InferResult, RegionVariableOrigin, TypeVariableOrigin};
use rustc_data_structures::indexed_vec::Idx;
use std::fmt::Debug;
use std::ops::Index;
use syntax::codemap::Span;
use traits::{Obligation, ObligationCause, PredicateObligation};
use ty::{self, CanonicalVar, Lift, Region, Slice, Ty, TyCtxt, TypeFlags};
use ty::subst::{Kind, UnpackedKind};
use ty::fold::{TypeFoldable, TypeFolder};
use util::common::CellUsizeExt;
use rustc_data_structures::indexed_vec::IndexVec;
use rustc_data_structures::fx::FxHashMap;
/// A "canonicalized" type `V` is one where all free inference
/// variables have been rewriten to "canonical vars". These are
/// numbered starting from 0 in order of first appearance.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct Canonical<'gcx, V> {
pub variables: CanonicalVarInfos<'gcx>,
pub value: V,
}
pub type CanonicalVarInfos<'gcx> = &'gcx Slice<CanonicalVarInfo>;
/// A set of values corresponding to the canonical variables from some
/// `Canonical`. You can give these values to
/// `canonical_value.substitute` to substitute them into the canonical
/// value at the right places.
///
/// When you canonicalize a value `V`, you get back one of these
/// vectors with the original values that were replaced by canonical
/// variables.
///
/// You can also use `infcx.fresh_inference_vars_for_canonical_vars`
/// to get back a `CanonicalVarValues` containing fresh inference
/// variables.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct CanonicalVarValues<'tcx> {
pub var_values: IndexVec<CanonicalVar, Kind<'tcx>>,
}
/// Information about a canonical variable that is included with the
/// canonical value. This is sufficient information for code to create
/// a copy of the canonical value in some other inference context,
/// with fresh inference variables replacing the canonical values.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct CanonicalVarInfo {
pub kind: CanonicalVarKind,
}
/// Describes the "kind" of the canonical variable. This is a "kind"
/// in the type-theory sense of the term -- i.e., a "meta" type system
/// that analyzes type-like values.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum CanonicalVarKind {
/// Some kind of type inference variable.
Ty(CanonicalTyVarKind),
/// Region variable `'?R`.
Region,
}
/// Rust actually has more than one category of type variables;
/// notably, the type variables we create for literals (e.g., 22 or
/// 22.) can only be instantiated with integral/float types (e.g.,
/// usize or f32). In order to faithfully reproduce a type, we need to
/// know what set of types a given type variable can be unified with.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum CanonicalTyVarKind {
/// General type variable `?T` that can be unified with arbitrary types.
General,
/// Integral type variable `?I` (that can only be unified with integral types).
Int,
/// Floating-point type variable `?F` (that can only be unified with float types).
Float,
}
/// After we execute a query with a canonicalized key, we get back a
/// `Canonical<QueryResult<..>>`. You can use
/// `instantiate_query_result` to access the data in this result.
#[derive(Clone, Debug)]
pub struct QueryResult<'tcx, R> {
pub var_values: CanonicalVarValues<'tcx>,
pub region_constraints: QueryRegionConstraints<'tcx>,
pub certainty: Certainty,
pub value: R,
}
/// Indicates whether or not we were able to prove the query to be
/// true.
#[derive(Copy, Clone, Debug)]
pub enum Certainty {
/// The query is known to be true, presuming that you apply the
/// given `var_values` and the region-constraints are satisfied.
Proven,
/// The query is not known to be true, but also not known to be
/// false. The `var_values` represent *either* values that must
/// hold in order for the query to be true, or helpful tips that
/// *might* make it true. Currently rustc's trait solver cannot
/// distinguish the two (e.g., due to our preference for where
/// clauses over impls).
///
/// After some unifiations and things have been done, it makes
/// sense to try and prove again -- of course, at that point, the
/// canonical form will be different, making this a distinct
/// query.
Ambiguous,
}
impl Certainty {
pub fn is_proven(&self) -> bool {
match self {
Certainty::Proven => true,
Certainty::Ambiguous => false,
}
}
pub fn is_ambiguous(&self) -> bool {
!self.is_proven()
}
}
impl<'tcx, R> QueryResult<'tcx, R> {
pub fn is_proven(&self) -> bool {
self.certainty.is_proven()
}
pub fn is_ambiguous(&self) -> bool {
!self.is_proven()
}
}
impl<'tcx, R> Canonical<'tcx, QueryResult<'tcx, R>> {
pub fn is_proven(&self) -> bool {
self.value.is_proven()
}
pub fn is_ambiguous(&self) -> bool {
!self.is_proven()
}
}
/// Subset of `RegionConstraintData` produced by trait query.
#[derive(Clone, Debug, Default)]
pub struct QueryRegionConstraints<'tcx> {
pub region_outlives: Vec<(Region<'tcx>, Region<'tcx>)>,
pub ty_outlives: Vec<(Ty<'tcx>, Region<'tcx>)>,
}
/// Trait implemented by values that can be canonicalized. It mainly
/// serves to identify the interning table we will use.
pub trait Canonicalize<'gcx: 'tcx, 'tcx>: TypeFoldable<'tcx> + Lift<'gcx> {
type Canonicalized: 'gcx + Debug;
/// After a value has been fully canonicalized and lifted, this
/// method will allocate it in a global arena.
fn intern(
gcx: TyCtxt<'_, 'gcx, 'gcx>,
value: Canonical<'gcx, Self::Lifted>,
) -> Self::Canonicalized;
}
impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
/// Creates a substitution S for the canonical value with fresh
/// inference variables and applies it to the canonical value.
/// Returns both the instantiated result *and* the substitution S.
///
/// This is useful at the start of a query: it basically brings
/// the canonical value "into scope" within your new infcx. At the
/// end of processing, the substitution S (once canonicalized)
/// then represents the values that you computed for each of the
/// canonical inputs to your query.
pub fn instantiate_canonical_with_fresh_inference_vars<T>(
&self,
span: Span,
canonical: &Canonical<'tcx, T>,
) -> (T, CanonicalVarValues<'tcx>)
where
T: TypeFoldable<'tcx>,
{
let canonical_inference_vars =
self.fresh_inference_vars_for_canonical_vars(span, canonical.variables);
let result = canonical.substitute(self.tcx, &canonical_inference_vars);
(result, canonical_inference_vars)
}
/// Given the "infos" about the canonical variables from some
/// canonical, creates fresh inference variables with the same
/// characteristics. You can then use `substitute` to instantiate
/// the canonical variable with these inference variables.
pub fn fresh_inference_vars_for_canonical_vars(
&self,
span: Span,
variables: &Slice<CanonicalVarInfo>,
) -> CanonicalVarValues<'tcx> {
let var_values: IndexVec<CanonicalVar, Kind<'tcx>> = variables
.iter()
.map(|info| self.fresh_inference_var_for_canonical_var(span, *info))
.collect();
CanonicalVarValues { var_values }
}
/// Given the "info" about a canonical variable, creates a fresh
/// inference variable with the same characteristics.
pub fn fresh_inference_var_for_canonical_var(
&self,
span: Span,
cv_info: CanonicalVarInfo,
) -> Kind<'tcx> {
match cv_info.kind {
CanonicalVarKind::Ty(ty_kind) => {
let ty = match ty_kind {
CanonicalTyVarKind::General => {
self.next_ty_var(
// FIXME(#48696) this handling of universes is not right.
ty::UniverseIndex::ROOT,
TypeVariableOrigin::MiscVariable(span),
)
}
CanonicalTyVarKind::Int => self.tcx.mk_int_var(self.next_int_var_id()),
CanonicalTyVarKind::Float => self.tcx.mk_float_var(self.next_float_var_id()),
};
Kind::from(ty)
}
CanonicalVarKind::Region => {
Kind::from(self.next_region_var(RegionVariableOrigin::MiscVariable(span)))
}
}
}
/// Given the (canonicalized) result to a canonical query,
/// instantiates the result so it can be used, plugging in the
/// values from the canonical query. (Note that the result may
/// have been ambiguous; you should check the certainty level of
/// the query before applying this function.)
///
/// To get a good understanding of what is happening here, check
/// out the [chapter in the rustc guide][c].
///
/// [c]: https://rust-lang-nursery.github.io/rustc-guide/traits-canonicalization.html#processing-the-canonicalized-query-result
pub fn instantiate_query_result<R>(
&self,
cause: &ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
original_values: &CanonicalVarValues<'tcx>,
query_result: &Canonical<'tcx, QueryResult<'tcx, R>>,
) -> InferResult<'tcx, R>
where
R: Debug + TypeFoldable<'tcx>,
{
debug!(
"instantiate_query_result(original_values={:#?}, query_result={:#?})",
original_values, query_result,
);
// Every canonical query result includes values for each of
// the inputs to the query. Therefore, we begin by unifying
// these values with the original inputs that were
// canonicalized.
let result_values = &query_result.value.var_values;
assert_eq!(original_values.len(), result_values.len());
// Quickly try to find initial values for the canonical
// variables in the result in terms of the query. We do this
// by iterating down the values that the query gave to each of
// the canonical inputs. If we find that one of those values
// is directly equal to one of the canonical variables in the
// result, then we can type the corresponding value from the
// input. See the example above.
let mut opt_values: IndexVec<CanonicalVar, Option<Kind<'tcx>>> =
IndexVec::from_elem_n(None, query_result.variables.len());
// In terms of our example above, we are iterating over pairs like:
// [(?A, Vec<?0>), ('static, '?1), (?B, ?0)]
for (original_value, result_value) in original_values.iter().zip(result_values) {
match result_value.unpack() {
UnpackedKind::Type(result_value) => {
// e.g., here `result_value` might be `?0` in the example above...
if let ty::TyInfer(ty::InferTy::CanonicalTy(index)) = result_value.sty {
// in which case we would set `canonical_vars[0]` to `Some(?U)`.
opt_values[index] = Some(original_value);
}
}
UnpackedKind::Lifetime(result_value) => {
// e.g., here `result_value` might be `'?1` in the example above...
if let &ty::RegionKind::ReCanonical(index) = result_value {
// in which case we would set `canonical_vars[0]` to `Some('static)`.
opt_values[index] = Some(original_value);
}
}
}
}
// Create a result substitution: if we found a value for a
// given variable in the loop above, use that. Otherwise, use
// a fresh inference variable.
let result_subst = &CanonicalVarValues {
var_values: query_result
.variables
.iter()
.enumerate()
.map(|(index, info)| match opt_values[CanonicalVar::new(index)] {
Some(k) => k,
None => self.fresh_inference_var_for_canonical_var(cause.span, *info),
})
.collect(),
};
// Unify the original values for the canonical variables in
// the input with the value found in the query
// post-substitution. Often, but not always, this is a no-op,
// because we already found the mapping in the first step.
let substituted_values = |index: CanonicalVar| -> Kind<'tcx> {
query_result.substitute_projected(self.tcx, result_subst, |v| &v.var_values[index])
};
let mut obligations =
self.unify_canonical_vars(cause, param_env, original_values, substituted_values)?
.into_obligations();
obligations.extend(self.query_region_constraints_into_obligations(
cause,
param_env,
&query_result.value.region_constraints,
result_subst,
));
let user_result: R =
query_result.substitute_projected(self.tcx, result_subst, |q_r| &q_r.value);
Ok(InferOk {
value: user_result,
obligations,
})
}
/// Converts the region constraints resulting from a query into an
/// iterator of obligations.
fn query_region_constraints_into_obligations<'a>(
&'a self,
cause: &'a ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
unsubstituted_region_constraints: &'a QueryRegionConstraints<'tcx>,
result_subst: &'a CanonicalVarValues<'tcx>,
) -> impl Iterator<Item = PredicateObligation<'tcx>> + 'a {
let QueryRegionConstraints {
region_outlives,
ty_outlives,
} = unsubstituted_region_constraints;
let region_obligations = region_outlives.iter().map(move |(r1, r2)| {
let r1 = substitute_value(self.tcx, result_subst, r1);
let r2 = substitute_value(self.tcx, result_subst, r2);
Obligation::new(
cause.clone(),
param_env,
ty::Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(r1, r2))),
)
});
let ty_obligations = ty_outlives.iter().map(move |(t1, r2)| {
let t1 = substitute_value(self.tcx, result_subst, t1);
let r2 = substitute_value(self.tcx, result_subst, r2);
Obligation::new(
cause.clone(),
param_env,
ty::Predicate::TypeOutlives(ty::Binder(ty::OutlivesPredicate(t1, r2))),
)
});
region_obligations.chain(ty_obligations)
}
/// Given two sets of values for the same set of canonical variables, unify them.
/// The second set is produced lazilly by supplying indices from the first set.
fn unify_canonical_vars(
&self,
cause: &ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
variables1: &CanonicalVarValues<'tcx>,
variables2: impl Fn(CanonicalVar) -> Kind<'tcx>,
) -> InferResult<'tcx, ()> {
self.commit_if_ok(|_| {
let mut obligations = vec![];
for (index, value1) in variables1.var_values.iter_enumerated() {
let value2 = variables2(index);
match (value1.unpack(), value2.unpack()) {
(UnpackedKind::Type(v1), UnpackedKind::Type(v2)) => {
obligations
.extend(self.at(cause, param_env).eq(v1, v2)?.into_obligations());
}
(
UnpackedKind::Lifetime(ty::ReErased),
UnpackedKind::Lifetime(ty::ReErased),
) => {
// no action needed
}
(UnpackedKind::Lifetime(v1), UnpackedKind::Lifetime(v2)) => {
obligations
.extend(self.at(cause, param_env).eq(v1, v2)?.into_obligations());
}
_ => {
bug!("kind mismatch, cannot unify {:?} and {:?}", value1, value2,);
}
}
}
Ok(InferOk {
value: (),
obligations,
})
})
}
/// Canonicalizes a query value `V`. When we canonicalize a query,
/// we not only canonicalize unbound inference variables, but we
/// *also* replace all free regions whatsoever. So for example a
/// query like `T: Trait<'static>` would be canonicalized to
///
/// ```text
/// T: Trait<'?0>
/// ```
///
/// with a mapping M that maps `'?0` to `'static`.
///
/// To get a good understanding of what is happening here, check
/// out the [chapter in the rustc guide][c].
///
/// [c]: https://rust-lang-nursery.github.io/rustc-guide/traits-canonicalization.html#canonicalizing-the-query
pub fn canonicalize_query<V>(&self, value: &V) -> (V::Canonicalized, CanonicalVarValues<'tcx>)
where
V: Canonicalize<'gcx, 'tcx>,
{
self.tcx.sess.perf_stats.queries_canonicalized.increment();
Canonicalizer::canonicalize(
value,
Some(self),
self.tcx,
CanonicalizeAllFreeRegions(true),
)
}
/// Canonicalizes a query *response* `V`. When we canonicalize a
/// query response, we only canonicalize unbound inference
/// variables, and we leave other free regions alone. So,
/// continuing with the example from `canonicalize_query`, if
/// there was an input query `T: Trait<'static>`, it would have
/// been canonicalized to
///
/// ```text
/// T: Trait<'?0>
/// ```
///
/// with a mapping M that maps `'?0` to `'static`. But if we found that there
/// exists only one possible impl of `Trait`, and it looks like
///
/// impl<T> Trait<'static> for T { .. }
///
/// then we would prepare a query result R that (among other
/// things) includes a mapping to `'?0 := 'static`. When
/// canonicalizing this query result R, we would leave this
/// reference to `'static` alone.
///
/// To get a good understanding of what is happening here, check
/// out the [chapter in the rustc guide][c].
///
/// [c]: https://rust-lang-nursery.github.io/rustc-guide/traits-canonicalization.html#canonicalizing-the-query-result
pub fn canonicalize_response<V>(
&self,
value: &V,
) -> (V::Canonicalized, CanonicalVarValues<'tcx>)
where
V: Canonicalize<'gcx, 'tcx>,
{
Canonicalizer::canonicalize(
value,
Some(self),
self.tcx,
CanonicalizeAllFreeRegions(false),
)
}
}
/// If this flag is true, then all free regions will be replaced with
/// a canonical var. This is used to make queries as generic as
/// possible. For example, the query `F: Foo<'static>` would be
/// canonicalized to `F: Foo<'0>`.
struct CanonicalizeAllFreeRegions(bool);
struct Canonicalizer<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
infcx: Option<&'cx InferCtxt<'cx, 'gcx, 'tcx>>,
tcx: TyCtxt<'cx, 'gcx, 'tcx>,
variables: IndexVec<CanonicalVar, CanonicalVarInfo>,
indices: FxHashMap<Kind<'tcx>, CanonicalVar>,
var_values: IndexVec<CanonicalVar, Kind<'tcx>>,
canonicalize_all_free_regions: CanonicalizeAllFreeRegions,
needs_canonical_flags: TypeFlags,
}
impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Canonicalizer<'cx, 'gcx, 'tcx> {
fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> {
self.tcx
}
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
match *r {
ty::ReLateBound(..) => {
// leave bound regions alone
r
}
ty::ReVar(vid) => {
let r = self.infcx
.unwrap()
.borrow_region_constraints()
.opportunistic_resolve_var(self.tcx, vid);
let info = CanonicalVarInfo {
kind: CanonicalVarKind::Region,
};
debug!(
"canonical: region var found with vid {:?}, \
opportunistically resolved to {:?}",
vid, r
);
let cvar = self.canonical_var(info, Kind::from(r));
self.tcx().mk_region(ty::ReCanonical(cvar))
}
ty::ReStatic
| ty::ReEarlyBound(..)
| ty::ReFree(_)
| ty::ReScope(_)
| ty::ReSkolemized(..)
| ty::ReEmpty
| ty::ReErased => {
if self.canonicalize_all_free_regions.0 {
let info = CanonicalVarInfo {
kind: CanonicalVarKind::Region,
};
let cvar = self.canonical_var(info, Kind::from(r));
self.tcx().mk_region(ty::ReCanonical(cvar))
} else {
r
}
}
ty::ReClosureBound(..) | ty::ReCanonical(_) => {
bug!("canonical region encountered during canonicalization")
}
}
}
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
match t.sty {
ty::TyInfer(ty::TyVar(_)) => self.canonicalize_ty_var(CanonicalTyVarKind::General, t),
ty::TyInfer(ty::IntVar(_)) => self.canonicalize_ty_var(CanonicalTyVarKind::Int, t),
ty::TyInfer(ty::FloatVar(_)) => self.canonicalize_ty_var(CanonicalTyVarKind::Float, t),
ty::TyInfer(ty::FreshTy(_))
| ty::TyInfer(ty::FreshIntTy(_))
| ty::TyInfer(ty::FreshFloatTy(_)) => {
bug!("encountered a fresh type during canonicalization")
}
ty::TyInfer(ty::CanonicalTy(_)) => {
bug!("encountered a canonical type during canonicalization")
}
// Replace a `()` that "would've fallen back" to `!` with just `()`.
ty::TyTuple(ref tys, true) => {
assert!(tys.is_empty());
self.tcx().mk_nil()
}
ty::TyClosure(..)
| ty::TyGenerator(..)
| ty::TyGeneratorWitness(..)
| ty::TyBool
| ty::TyChar
| ty::TyInt(..)
| ty::TyUint(..)
| ty::TyFloat(..)
| ty::TyAdt(..)
| ty::TyStr
| ty::TyError
| ty::TyArray(..)
| ty::TySlice(..)
| ty::TyRawPtr(..)
| ty::TyRef(..)
| ty::TyFnDef(..)
| ty::TyFnPtr(_)
| ty::TyDynamic(..)
| ty::TyNever
| ty::TyTuple(_, false)
| ty::TyProjection(..)
| ty::TyForeign(..)
| ty::TyParam(..)
| ty::TyAnon(..) => {
if t.flags.intersects(self.needs_canonical_flags) {
t.super_fold_with(self)
} else {
t
}
}
}
}
}
impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> {
/// The main `canonicalize` method, shared impl of
/// `canonicalize_query` and `canonicalize_response`.
fn canonicalize<V>(
value: &V,
infcx: Option<&'cx InferCtxt<'cx, 'gcx, 'tcx>>,
tcx: TyCtxt<'cx, 'gcx, 'tcx>,
canonicalize_all_free_regions: CanonicalizeAllFreeRegions,
) -> (V::Canonicalized, CanonicalVarValues<'tcx>)
where
V: Canonicalize<'gcx, 'tcx>,
{
debug_assert!(
!value.has_type_flags(TypeFlags::HAS_CANONICAL_VARS),
"canonicalizing a canonical value: {:?}",
value,
);
let needs_canonical_flags = if canonicalize_all_free_regions.0 {
TypeFlags::HAS_FREE_REGIONS | TypeFlags::KEEP_IN_LOCAL_TCX
} else {
TypeFlags::KEEP_IN_LOCAL_TCX
};
let gcx = tcx.global_tcx();
// Fast path: nothing that needs to be canonicalized.
if !value.has_type_flags(needs_canonical_flags) {
let out_value = gcx.lift(value).unwrap();
let canon_value = V::intern(
gcx,
Canonical {
variables: Slice::empty(),
value: out_value,
},
);
let values = CanonicalVarValues {
var_values: IndexVec::default(),
};
return (canon_value, values);
}
let mut canonicalizer = Canonicalizer {
infcx,
tcx,
canonicalize_all_free_regions,
needs_canonical_flags,
variables: IndexVec::default(),
indices: FxHashMap::default(),
var_values: IndexVec::default(),
};
let out_value = value.fold_with(&mut canonicalizer);
// Once we have canonicalized `out_value`, it should not
// contain anything that ties it to this inference context
// anymore, so it should live in the global arena.
let out_value = gcx.lift(&out_value).unwrap_or_else(|| {
bug!(
"failed to lift `{:?}`, canonicalized from `{:?}`",
out_value,
value
)
});
let canonical_variables = tcx.intern_canonical_var_infos(&canonicalizer.variables.raw);
let canonical_value = V::intern(
gcx,
Canonical {
variables: canonical_variables,
value: out_value,
},
);
let canonical_var_values = CanonicalVarValues {
var_values: canonicalizer.var_values,
};
(canonical_value, canonical_var_values)
}
/// Creates a canonical variable replacing `kind` from the input,
/// or returns an existing variable if `kind` has already been
/// seen. `kind` is expected to be an unbound variable (or
/// potentially a free region).
fn canonical_var(&mut self, info: CanonicalVarInfo, kind: Kind<'tcx>) -> CanonicalVar {
let Canonicalizer {
indices,
variables,
var_values,
..
} = self;
indices
.entry(kind)
.or_insert_with(|| {
let cvar1 = variables.push(info);
let cvar2 = var_values.push(kind);
assert_eq!(cvar1, cvar2);
cvar1
})
.clone()
}
/// Given a type variable `ty_var` of the given kind, first check
/// if `ty_var` is bound to anything; if so, canonicalize
/// *that*. Otherwise, create a new canonical variable for
/// `ty_var`.
fn canonicalize_ty_var(&mut self, ty_kind: CanonicalTyVarKind, ty_var: Ty<'tcx>) -> Ty<'tcx> {
let infcx = self.infcx.expect("encountered ty-var without infcx");
let bound_to = infcx.shallow_resolve(ty_var);
if bound_to != ty_var {
self.fold_ty(bound_to)
} else {
let info = CanonicalVarInfo {
kind: CanonicalVarKind::Ty(ty_kind),
};
let cvar = self.canonical_var(info, Kind::from(ty_var));
self.tcx().mk_infer(ty::InferTy::CanonicalTy(cvar))
}
}
}
impl<'tcx, V> Canonical<'tcx, V> {
/// Instantiate the wrapped value, replacing each canonical value
/// with the value given in `var_values`.
fn substitute(&self, tcx: TyCtxt<'_, '_, 'tcx>, var_values: &CanonicalVarValues<'tcx>) -> V
where
V: TypeFoldable<'tcx>,
{
self.substitute_projected(tcx, var_values, |value| value)
}
/// Invoke `projection_fn` with `self.value` to get a value V that
/// is expressed in terms of the same canonical variables bound in
/// `self`. Apply the substitution `var_values` to this value V,
/// replacing each of the canonical variables.
fn substitute_projected<T>(
&self,
tcx: TyCtxt<'_, '_, 'tcx>,
var_values: &CanonicalVarValues<'tcx>,
projection_fn: impl FnOnce(&V) -> &T,
) -> T
where
T: TypeFoldable<'tcx>,
{
assert_eq!(self.variables.len(), var_values.var_values.len());
let value = projection_fn(&self.value);
substitute_value(tcx, var_values, value)
}
}
/// Substitute the values from `var_values` into `value`. `var_values`
/// must be values for the set of cnaonical variables that appear in
/// `value`.
fn substitute_value<'a, 'tcx, T>(
tcx: TyCtxt<'_, '_, 'tcx>,
var_values: &CanonicalVarValues<'tcx>,
value: &'a T,
) -> T
where
T: TypeFoldable<'tcx>,
{
if var_values.var_values.is_empty() {
debug_assert!(!value.has_type_flags(TypeFlags::HAS_CANONICAL_VARS));
value.clone()
} else if !value.has_type_flags(TypeFlags::HAS_CANONICAL_VARS) {
value.clone()
} else {
value.fold_with(&mut CanonicalVarValuesSubst { tcx, var_values })
}
}
struct CanonicalVarValuesSubst<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
tcx: TyCtxt<'cx, 'gcx, 'tcx>,
var_values: &'cx CanonicalVarValues<'tcx>,
}
impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for CanonicalVarValuesSubst<'cx, 'gcx, 'tcx> {
fn tcx(&self) -> TyCtxt<'_, 'gcx, 'tcx> {
self.tcx
}
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
match t.sty {
ty::TyInfer(ty::InferTy::CanonicalTy(c)) => {
match self.var_values.var_values[c].unpack() {
UnpackedKind::Type(ty) => ty,
r => bug!("{:?} is a type but value is {:?}", c, r),
}
}
_ => {
if !t.has_type_flags(TypeFlags::HAS_CANONICAL_VARS) {
t
} else {
t.super_fold_with(self)
}
}
}
}
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
match r {
ty::RegionKind::ReCanonical(c) => match self.var_values.var_values[*c].unpack() {
UnpackedKind::Lifetime(l) => l,
r => bug!("{:?} is a region but value is {:?}", c, r),
},
_ => r.super_fold_with(self),
}
}
}
CloneTypeFoldableAndLiftImpls! {
for <'tcx> {
::infer::canonical::Certainty,
::infer::canonical::CanonicalVarInfo,
::infer::canonical::CanonicalVarInfos<'tcx>,
::infer::canonical::CanonicalVarKind,
}
}
BraceStructTypeFoldableImpl! {
impl<'tcx, C> TypeFoldable<'tcx> for Canonical<'tcx, C> {
variables,
value,
} where C: TypeFoldable<'tcx>
}
impl<'tcx> CanonicalVarValues<'tcx> {
fn iter<'a>(&'a self) -> impl Iterator<Item = Kind<'tcx>> + 'a {
self.var_values.iter().cloned()
}
fn len(&self) -> usize {
self.var_values.len()
}
}
impl<'a, 'tcx> IntoIterator for &'a CanonicalVarValues<'tcx> {
type Item = Kind<'tcx>;
type IntoIter = ::std::iter::Cloned<::std::slice::Iter<'a, Kind<'tcx>>>;
fn into_iter(self) -> Self::IntoIter {
self.var_values.iter().cloned()
}
}
BraceStructLiftImpl! {
impl<'a, 'tcx> Lift<'tcx> for CanonicalVarValues<'a> {
type Lifted = CanonicalVarValues<'tcx>;
var_values,
}
}
BraceStructTypeFoldableImpl! {
impl<'tcx> TypeFoldable<'tcx> for CanonicalVarValues<'tcx> {
var_values,
}
}
BraceStructTypeFoldableImpl! {
impl<'tcx> TypeFoldable<'tcx> for QueryRegionConstraints<'tcx> {
region_outlives, ty_outlives
}
}
BraceStructLiftImpl! {
impl<'a, 'tcx> Lift<'tcx> for QueryRegionConstraints<'a> {
type Lifted = QueryRegionConstraints<'tcx>;
region_outlives, ty_outlives
}
}
BraceStructTypeFoldableImpl! {
impl<'tcx, R> TypeFoldable<'tcx> for QueryResult<'tcx, R> {
var_values, region_constraints, certainty, value
} where R: TypeFoldable<'tcx>,
}
BraceStructLiftImpl! {
impl<'a, 'tcx, R> Lift<'tcx> for QueryResult<'a, R> {
type Lifted = QueryResult<'tcx, R::Lifted>;
var_values, region_constraints, certainty, value
} where R: Lift<'tcx>
}
impl<'tcx> Index<CanonicalVar> for CanonicalVarValues<'tcx> {
type Output = Kind<'tcx>;
fn index(&self, value: CanonicalVar) -> &Kind<'tcx> {
&self.var_values[value]
}
}
+1
View File
@@ -476,6 +476,7 @@ fn regions(&mut self, r: ty::Region<'tcx>, r2: ty::Region<'tcx>)
}
}
ty::ReCanonical(..) |
ty::ReClosureBound(..) => {
span_bug!(
self.span,
@@ -154,6 +154,7 @@ pub fn note_and_explain_region(
}
// We shouldn't encounter an error message with ReClosureBound.
ty::ReCanonical(..) |
ty::ReClosureBound(..) => {
bug!("encountered unexpected ReClosureBound: {:?}", region,);
}
@@ -975,6 +976,7 @@ fn values_str(
) -> Option<(DiagnosticStyledString, DiagnosticStyledString)> {
match *values {
infer::Types(ref exp_found) => self.expected_found_str_ty(exp_found),
infer::Regions(ref exp_found) => self.expected_found_str(exp_found),
infer::TraitRefs(ref exp_found) => self.expected_found_str(exp_found),
infer::PolyTraitRefs(ref exp_found) => self.expected_found_str(exp_found),
}
+5 -1
View File
@@ -114,9 +114,10 @@ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
self.tcx().types.re_erased
}
ty::ReCanonical(..) |
ty::ReClosureBound(..) => {
bug!(
"encountered unexpected ReClosureBound: {:?}",
"encountered unexpected region: {:?}",
r,
);
}
@@ -170,6 +171,9 @@ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
t
}
ty::TyInfer(ty::CanonicalTy(..)) =>
bug!("encountered canonical ty during freshening"),
ty::TyGenerator(..) |
ty::TyBool |
ty::TyChar |
@@ -258,6 +258,8 @@ fn expand_node(
fn lub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> Region<'tcx> {
let tcx = self.region_rels.tcx;
match (a, b) {
(&ty::ReCanonical(..), _) |
(_, &ty::ReCanonical(..)) |
(&ty::ReClosureBound(..), _) |
(_, &ty::ReClosureBound(..)) |
(&ReLateBound(..), _) |
+29 -209
View File
@@ -21,21 +21,20 @@
use middle::free_region::RegionRelations;
use middle::region;
use middle::lang_items;
use mir::tcx::PlaceTy;
use ty::subst::Substs;
use ty::{TyVid, IntVid, FloatVid};
use ty::{self, Ty, TyCtxt};
use ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric};
use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
use ty::fold::TypeFoldable;
use ty::relate::RelateResult;
use traits::{self, ObligationCause, PredicateObligations, Reveal};
use traits::{self, ObligationCause, PredicateObligations};
use rustc_data_structures::unify as ut;
use std::cell::{Cell, RefCell, Ref, RefMut};
use std::collections::BTreeMap;
use std::fmt;
use syntax::ast;
use errors::DiagnosticBuilder;
use syntax_pos::{self, Span, DUMMY_SP};
use syntax_pos::{self, Span};
use util::nodemap::FxHashMap;
use arena::DroplessArena;
@@ -50,6 +49,7 @@
pub mod anon_types;
pub mod at;
pub mod canonical;
mod combine;
mod equate;
pub mod error_reporting;
@@ -68,6 +68,7 @@
pub mod unify_key;
#[must_use]
#[derive(Debug)]
pub struct InferOk<'tcx, T> {
pub value: T,
pub obligations: PredicateObligations<'tcx>,
@@ -191,6 +192,7 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
#[derive(Clone, Debug)]
pub enum ValuePairs<'tcx> {
Types(ExpectedFound<Ty<'tcx>>),
Regions(ExpectedFound<ty::Region<'tcx>>),
TraitRefs(ExpectedFound<ty::TraitRef<'tcx>>),
PolyTraitRefs(ExpectedFound<ty::PolyTraitRef<'tcx>>),
}
@@ -472,6 +474,12 @@ pub fn unit(self) -> InferOk<'tcx, ()> {
}
}
impl<'tcx> InferOk<'tcx, ()> {
pub fn into_obligations(self) -> PredicateObligations<'tcx> {
self.obligations
}
}
#[must_use = "once you start a snapshot, you should always consume it"]
pub struct CombinedSnapshot<'a, 'tcx:'a> {
projection_cache_snapshot: traits::ProjectionCacheSnapshot,
@@ -484,176 +492,7 @@ pub struct CombinedSnapshot<'a, 'tcx:'a> {
_in_progress_tables: Option<Ref<'a, ty::TypeckTables<'tcx>>>,
}
/// Helper trait for shortening the lifetimes inside a
/// value for post-type-checking normalization.
pub trait TransNormalize<'gcx>: TypeFoldable<'gcx> {
fn trans_normalize<'a, 'tcx>(&self,
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>)
-> Self;
}
macro_rules! items { ($($item:item)+) => ($($item)+) }
macro_rules! impl_trans_normalize {
($lt_gcx:tt, $($ty:ty),+) => {
items!($(impl<$lt_gcx> TransNormalize<$lt_gcx> for $ty {
fn trans_normalize<'a, 'tcx>(&self,
infcx: &InferCtxt<'a, $lt_gcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>)
-> Self {
infcx.normalize_projections_in(param_env, self)
}
})+);
}
}
impl_trans_normalize!('gcx,
Ty<'gcx>,
&'gcx ty::Const<'gcx>,
&'gcx Substs<'gcx>,
ty::FnSig<'gcx>,
ty::PolyFnSig<'gcx>,
ty::ClosureSubsts<'gcx>,
ty::PolyTraitRef<'gcx>,
ty::ExistentialTraitRef<'gcx>
);
impl<'gcx> TransNormalize<'gcx> for PlaceTy<'gcx> {
fn trans_normalize<'a, 'tcx>(&self,
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>)
-> Self {
match *self {
PlaceTy::Ty { ty } => PlaceTy::Ty { ty: ty.trans_normalize(infcx, param_env) },
PlaceTy::Downcast { adt_def, substs, variant_index } => {
PlaceTy::Downcast {
adt_def,
substs: substs.trans_normalize(infcx, param_env),
variant_index,
}
}
}
}
}
// NOTE: Callable from trans only!
impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
/// Currently, higher-ranked type bounds inhibit normalization. Therefore,
/// each time we erase them in translation, we need to normalize
/// the contents.
pub fn erase_late_bound_regions_and_normalize<T>(self, value: &ty::Binder<T>)
-> T
where T: TransNormalize<'tcx>
{
assert!(!value.needs_subst());
let value = self.erase_late_bound_regions(value);
self.fully_normalize_associated_types_in(&value)
}
/// Fully normalizes any associated types in `value`, using an
/// empty environment and `Reveal::All` mode (therefore, suitable
/// only for monomorphized code during trans, basically).
pub fn fully_normalize_associated_types_in<T>(self, value: &T) -> T
where T: TransNormalize<'tcx>
{
debug!("fully_normalize_associated_types_in(t={:?})", value);
let param_env = ty::ParamEnv::empty(Reveal::All);
let value = self.erase_regions(value);
if !value.has_projections() {
return value;
}
self.infer_ctxt().enter(|infcx| {
value.trans_normalize(&infcx, param_env)
})
}
/// Does a best-effort to normalize any associated types in
/// `value`; this includes revealing specializable types, so this
/// should be not be used during type-checking, but only during
/// optimization and code generation.
pub fn normalize_associated_type_in_env<T>(
self, value: &T, env: ty::ParamEnv<'tcx>
) -> T
where T: TransNormalize<'tcx>
{
debug!("normalize_associated_type_in_env(t={:?})", value);
let value = self.erase_regions(value);
if !value.has_projections() {
return value;
}
self.infer_ctxt().enter(|infcx| {
value.trans_normalize(&infcx, env.reveal_all())
})
}
}
impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
fn normalize_projections_in<T>(&self, param_env: ty::ParamEnv<'tcx>, value: &T) -> T::Lifted
where T: TypeFoldable<'tcx> + ty::Lift<'gcx>
{
let mut selcx = traits::SelectionContext::new(self);
let cause = traits::ObligationCause::dummy();
let traits::Normalized { value: result, obligations } =
traits::normalize(&mut selcx, param_env, cause, value);
debug!("normalize_projections_in: result={:?} obligations={:?}",
result, obligations);
let mut fulfill_cx = traits::FulfillmentContext::new();
for obligation in obligations {
fulfill_cx.register_predicate_obligation(self, obligation);
}
self.drain_fulfillment_cx_or_panic(DUMMY_SP, &mut fulfill_cx, &result)
}
/// Finishes processes any obligations that remain in the
/// fulfillment context, and then returns the result with all type
/// variables removed and regions erased. Because this is intended
/// for use after type-check has completed, if any errors occur,
/// it will panic. It is used during normalization and other cases
/// where processing the obligations in `fulfill_cx` may cause
/// type inference variables that appear in `result` to be
/// unified, and hence we need to process those obligations to get
/// the complete picture of the type.
pub fn drain_fulfillment_cx_or_panic<T>(&self,
span: Span,
fulfill_cx: &mut traits::FulfillmentContext<'tcx>,
result: &T)
-> T::Lifted
where T: TypeFoldable<'tcx> + ty::Lift<'gcx>
{
debug!("drain_fulfillment_cx_or_panic()");
// In principle, we only need to do this so long as `result`
// contains unbound type parameters. It could be a slight
// optimization to stop iterating early.
match fulfill_cx.select_all_or_error(self) {
Ok(()) => { }
Err(errors) => {
span_bug!(span, "Encountered errors `{:?}` resolving bounds after type-checking",
errors);
}
}
let result = self.resolve_type_vars_if_possible(result);
let result = self.tcx.erase_regions(&result);
match self.tcx.lift_to_global(&result) {
Some(result) => result,
None => {
span_bug!(span, "Uninferred types/regions in `{:?}`", result);
}
}
}
pub fn is_in_snapshot(&self) -> bool {
self.in_snapshot.get()
}
@@ -1212,6 +1051,16 @@ pub fn take_and_reset_region_constraints(&self) -> RegionConstraintData<'tcx> {
self.borrow_region_constraints().take_and_reset_data()
}
/// Gives temporary access to the region constraint data.
#[allow(non_camel_case_types)] // bug with impl trait
pub fn with_region_constraints<R>(
&self,
op: impl FnOnce(&RegionConstraintData<'tcx>) -> R,
) -> R {
let region_constraints = self.borrow_region_constraints();
op(region_constraints.data())
}
/// Takes ownership of the list of variable regions. This implies
/// that all the region constriants have already been taken, and
/// hence that `resolve_regions_and_report_errors` can never be
@@ -1246,7 +1095,7 @@ pub fn shallow_resolve(&self, typ: Ty<'tcx>) -> Ty<'tcx> {
// it can be resolved to an int/float variable, which
// can then be recursively resolved, hence the
// recursion. Note though that we prevent type
// variables from unifying to other type variables
// variables from unifyxing to other type variables
// directly (though they may be embedded
// structurally), and we prevent cycles in any case,
// so this recursion should always be of very limited
@@ -1623,40 +1472,12 @@ pub fn span(&self) -> Span {
}
}
impl<'tcx> TypeFoldable<'tcx> for ValuePairs<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
match *self {
ValuePairs::Types(ref ef) => {
ValuePairs::Types(ef.fold_with(folder))
}
ValuePairs::TraitRefs(ref ef) => {
ValuePairs::TraitRefs(ef.fold_with(folder))
}
ValuePairs::PolyTraitRefs(ref ef) => {
ValuePairs::PolyTraitRefs(ef.fold_with(folder))
}
}
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
match *self {
ValuePairs::Types(ref ef) => ef.visit_with(visitor),
ValuePairs::TraitRefs(ref ef) => ef.visit_with(visitor),
ValuePairs::PolyTraitRefs(ref ef) => ef.visit_with(visitor),
}
}
}
impl<'tcx> TypeFoldable<'tcx> for TypeTrace<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
TypeTrace {
cause: self.cause.fold_with(folder),
values: self.values.fold_with(folder)
}
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
self.cause.visit_with(visitor) || self.values.visit_with(visitor)
EnumTypeFoldableImpl! {
impl<'tcx> TypeFoldable<'tcx> for ValuePairs<'tcx> {
(ValuePairs::Types)(a),
(ValuePairs::Regions)(a),
(ValuePairs::TraitRefs)(a),
(ValuePairs::PolyTraitRefs)(a),
}
}
@@ -1667,4 +1488,3 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.sup_type)
}
}
@@ -99,6 +99,16 @@ pub fn register_region_obligation(
.push((body_id, obligation));
}
/// Trait queries just want to pass back type obligations "as is"
pub fn take_registered_region_obligations(
&self,
) -> Vec<(ast::NodeId, RegionObligation<'tcx>)> {
::std::mem::replace(
&mut *self.region_obligations.borrow_mut(),
vec![],
)
}
/// Process the region obligations that must be proven (during
/// `regionck`) for the given `body_id`, given information about
/// the region bounds in scope and so forth. This function must be
@@ -350,6 +350,10 @@ pub fn take_and_reset_data(&mut self) -> RegionConstraintData<'tcx> {
mem::replace(data, RegionConstraintData::default())
}
pub fn data(&self) -> &RegionConstraintData<'tcx> {
&self.data
}
fn in_snapshot(&self) -> bool {
!self.undo_log.is_empty()
}
+2 -1
View File
@@ -57,8 +57,9 @@
#![feature(inclusive_range)]
#![feature(inclusive_range_syntax)]
#![cfg_attr(windows, feature(libc))]
#![feature(macro_vis_matcher)]
#![feature(match_default_bindings)]
#![feature(macro_lifetime_matcher)]
#![feature(macro_vis_matcher)]
#![feature(never_type)]
#![feature(non_exhaustive)]
#![feature(nonzero)]
+1 -2
View File
@@ -34,7 +34,6 @@
use middle::privacy::AccessLevels;
use rustc_serialize::{Decoder, Decodable, Encoder, Encodable};
use session::{config, early_error, Session};
use traits::Reveal;
use ty::{self, TyCtxt, Ty};
use ty::layout::{LayoutError, LayoutOf, TyLayout};
use util::nodemap::FxHashMap;
@@ -1055,7 +1054,7 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
let mut cx = LateContext {
tcx,
tables: &ty::TypeckTables::empty(None),
param_env: ty::ParamEnv::empty(Reveal::UserFacing),
param_env: ty::ParamEnv::empty(),
access_levels,
lint_sess: LintSession::new(&tcx.sess.lint_store),
last_ast_node_with_lint_attrs: ast::CRATE_NODE_ID,
+319
View File
@@ -119,6 +119,25 @@ fn hash_stable<W: ::rustc_data_structures::stable_hasher::StableHasherResult>(&s
}
}
};
(impl<$tcx:lifetime $(, $T:ident)*> for struct $struct_name:path {
$($field:ident),* $(,)*
}) => {
impl<'a, $tcx, $($T,)*> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a>> for $struct_name
where $($T: ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a>>),*
{
#[inline]
fn hash_stable<W: ::rustc_data_structures::stable_hasher::StableHasherResult>(&self,
__ctx: &mut $crate::ich::StableHashingContext<'a>,
__hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher<W>) {
let $struct_name {
$(ref $field),*
} = *self;
$( $field.hash_stable(__ctx, __hasher));*
}
}
};
}
#[macro_export]
@@ -138,3 +157,303 @@ fn hash_stable<W: StableHasherResult>(&self,
);
}
///////////////////////////////////////////////////////////////////////////
// Lift and TypeFoldable macros
//
// When possible, use one of these (relatively) convenient macros to write
// the impls for you.
#[macro_export]
macro_rules! CloneLiftImpls {
(for <$tcx:lifetime> { $($ty:ty,)+ }) => {
$(
impl<$tcx> $crate::ty::Lift<$tcx> for $ty {
type Lifted = Self;
fn lift_to_tcx<'a, 'gcx>(&self, _: $crate::ty::TyCtxt<'a, 'gcx, $tcx>) -> Option<Self> {
Some(Clone::clone(self))
}
}
)+
};
($($ty:ty,)+) => {
CloneLiftImpls! {
for <'tcx> {
$($ty,)+
}
}
};
}
/// Used for types that are `Copy` and which **do not care arena
/// allocated data** (i.e., don't need to be folded).
#[macro_export]
macro_rules! CloneTypeFoldableImpls {
(for <$tcx:lifetime> { $($ty:ty,)+ }) => {
$(
impl<$tcx> $crate::ty::fold::TypeFoldable<$tcx> for $ty {
fn super_fold_with<'gcx: $tcx, F: $crate::ty::fold::TypeFolder<'gcx, $tcx>>(
&self,
_: &mut F
) -> $ty {
Clone::clone(self)
}
fn super_visit_with<F: $crate::ty::fold::TypeVisitor<$tcx>>(
&self,
_: &mut F)
-> bool
{
false
}
}
)+
};
($($ty:ty,)+) => {
CloneTypeFoldableImpls! {
for <'tcx> {
$($ty,)+
}
}
};
}
#[macro_export]
macro_rules! CloneTypeFoldableAndLiftImpls {
($($t:tt)*) => {
CloneTypeFoldableImpls! { $($t)* }
CloneLiftImpls! { $($t)* }
}
}
#[macro_export]
macro_rules! BraceStructLiftImpl {
(impl<$($p:tt),*> Lift<$tcx:tt> for $s:path {
type Lifted = $lifted:ty;
$($field:ident),* $(,)*
} $(where $($wc:tt)*)*) => {
impl<$($p),*> $crate::ty::Lift<$tcx> for $s
$(where $($wc)*)*
{
type Lifted = $lifted;
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<$lifted> {
$(let $field = tcx.lift(&self.$field)?;)*
Some(Self::Lifted { $($field),* })
}
}
};
}
#[macro_export]
macro_rules! EnumLiftImpl {
(impl<$($p:tt),*> Lift<$tcx:tt> for $s:path {
type Lifted = $lifted:ty;
$(
($variant:path) ( $( $variant_arg:ident),* )
),*
$(,)*
} $(where $($wc:tt)*)*) => {
impl<$($p),*> $crate::ty::Lift<$tcx> for $s
$(where $($wc)*)*
{
type Lifted = $lifted;
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<$lifted> {
match self {
$($variant ( $($variant_arg),* ) => {
Some($variant ( $(tcx.lift($variant_arg)?),* ))
})*
}
}
}
};
}
#[macro_export]
macro_rules! BraceStructTypeFoldableImpl {
(impl<$($p:tt),*> TypeFoldable<$tcx:tt> for $s:path {
$($field:ident),* $(,)*
} $(where $($wc:tt)*)*) => {
impl<$($p),*> $crate::ty::fold::TypeFoldable<$tcx> for $s
$(where $($wc)*)*
{
fn super_fold_with<'gcx: $tcx, V: $crate::ty::fold::TypeFolder<'gcx, $tcx>>(
&self,
folder: &mut V,
) -> Self {
let $s { $($field,)* } = self;
$s { $($field: $crate::ty::fold::TypeFoldable::fold_with($field, folder),)* }
}
fn super_visit_with<V: $crate::ty::fold::TypeVisitor<$tcx>>(
&self,
visitor: &mut V,
) -> bool {
let $s { $($field,)* } = self;
false $(|| $crate::ty::fold::TypeFoldable::visit_with($field, visitor))*
}
}
};
}
#[macro_export]
macro_rules! TupleStructTypeFoldableImpl {
(impl<$($p:tt),*> TypeFoldable<$tcx:tt> for $s:path {
$($field:ident),* $(,)*
} $(where $($wc:tt)*)*) => {
impl<$($p),*> $crate::ty::fold::TypeFoldable<$tcx> for $s
$(where $($wc)*)*
{
fn super_fold_with<'gcx: $tcx, V: $crate::ty::fold::TypeFolder<'gcx, $tcx>>(
&self,
folder: &mut V,
) -> Self {
let $s($($field,)*)= self;
$s($($crate::ty::fold::TypeFoldable::fold_with($field, folder),)*)
}
fn super_visit_with<V: $crate::ty::fold::TypeVisitor<$tcx>>(
&self,
visitor: &mut V,
) -> bool {
let $s($($field,)*) = self;
false $(|| $crate::ty::fold::TypeFoldable::visit_with($field, visitor))*
}
}
};
}
#[macro_export]
macro_rules! EnumTypeFoldableImpl {
(impl<$($p:tt),*> TypeFoldable<$tcx:tt> for $s:path {
$($variants:tt)*
} $(where $($wc:tt)*)*) => {
impl<$($p),*> $crate::ty::fold::TypeFoldable<$tcx> for $s
$(where $($wc)*)*
{
fn super_fold_with<'gcx: $tcx, V: $crate::ty::fold::TypeFolder<'gcx, $tcx>>(
&self,
folder: &mut V,
) -> Self {
EnumTypeFoldableImpl!(@FoldVariants(self, folder) input($($variants)*) output())
}
fn super_visit_with<V: $crate::ty::fold::TypeVisitor<$tcx>>(
&self,
visitor: &mut V,
) -> bool {
EnumTypeFoldableImpl!(@VisitVariants(self, visitor) input($($variants)*) output())
}
}
};
(@FoldVariants($this:expr, $folder:expr) input() output($($output:tt)*)) => {
match $this {
$($output)*
}
};
(@FoldVariants($this:expr, $folder:expr)
input( ($variant:path) ( $($variant_arg:ident),* ) , $($input:tt)*)
output( $($output:tt)*) ) => {
EnumTypeFoldableImpl!(
@FoldVariants($this, $folder)
input($($input)*)
output(
$variant ( $($variant_arg),* ) => {
$variant (
$($crate::ty::fold::TypeFoldable::fold_with($variant_arg, $folder)),*
)
}
$($output)*
)
)
};
(@FoldVariants($this:expr, $folder:expr)
input( ($variant:path) { $($variant_arg:ident),* $(,)* } , $($input:tt)*)
output( $($output:tt)*) ) => {
EnumTypeFoldableImpl!(
@FoldVariants($this, $folder)
input($($input)*)
output(
$variant { $($variant_arg),* } => {
$variant {
$($variant_arg: $crate::ty::fold::TypeFoldable::fold_with(
$variant_arg, $folder
)),* }
}
$($output)*
)
)
};
(@FoldVariants($this:expr, $folder:expr)
input( ($variant:path), $($input:tt)*)
output( $($output:tt)*) ) => {
EnumTypeFoldableImpl!(
@FoldVariants($this, $folder)
input($($input)*)
output(
$variant => { $variant }
$($output)*
)
)
};
(@VisitVariants($this:expr, $visitor:expr) input() output($($output:tt)*)) => {
match $this {
$($output)*
}
};
(@VisitVariants($this:expr, $visitor:expr)
input( ($variant:path) ( $($variant_arg:ident),* ) , $($input:tt)*)
output( $($output:tt)*) ) => {
EnumTypeFoldableImpl!(
@VisitVariants($this, $visitor)
input($($input)*)
output(
$variant ( $($variant_arg),* ) => {
false $(|| $crate::ty::fold::TypeFoldable::visit_with(
$variant_arg, $visitor
))*
}
$($output)*
)
)
};
(@VisitVariants($this:expr, $visitor:expr)
input( ($variant:path) { $($variant_arg:ident),* $(,)* } , $($input:tt)*)
output( $($output:tt)*) ) => {
EnumTypeFoldableImpl!(
@VisitVariants($this, $visitor)
input($($input)*)
output(
$variant { $($variant_arg),* } => {
false $(|| $crate::ty::fold::TypeFoldable::visit_with(
$variant_arg, $visitor
))*
}
$($output)*
)
)
};
(@VisitVariants($this:expr, $visitor:expr)
input( ($variant:path), $($input:tt)*)
output( $($output:tt)*) ) => {
EnumTypeFoldableImpl!(
@VisitVariants($this, $visitor)
input($($input)*)
output(
$variant => { false }
$($output)*
)
)
};
}
+4
View File
@@ -76,3 +76,7 @@ fn calculate_predecessors(mir: &Mir) -> IndexVec<BasicBlock, Vec<BasicBlock>> {
result
}
CloneTypeFoldableAndLiftImpls! {
Cache,
}
+65 -123
View File
@@ -2109,150 +2109,92 @@ pub enum ClosureOutlivesSubject<'tcx> {
* TypeFoldable implementations for MIR types
*/
impl<'tcx> TypeFoldable<'tcx> for Mir<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
Mir {
basic_blocks: self.basic_blocks.fold_with(folder),
visibility_scopes: self.visibility_scopes.clone(),
visibility_scope_info: self.visibility_scope_info.clone(),
promoted: self.promoted.fold_with(folder),
yield_ty: self.yield_ty.fold_with(folder),
generator_drop: self.generator_drop.fold_with(folder),
generator_layout: self.generator_layout.fold_with(folder),
local_decls: self.local_decls.fold_with(folder),
arg_count: self.arg_count,
upvar_decls: self.upvar_decls.clone(),
spread_arg: self.spread_arg,
span: self.span,
cache: cache::Cache::new()
}
}
CloneTypeFoldableAndLiftImpls! {
Mutability,
SourceInfo,
UpvarDecl,
ValidationOp,
VisibilityScopeData,
VisibilityScope,
VisibilityScopeInfo,
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
self.basic_blocks.visit_with(visitor) ||
self.generator_drop.visit_with(visitor) ||
self.generator_layout.visit_with(visitor) ||
self.yield_ty.visit_with(visitor) ||
self.promoted.visit_with(visitor) ||
self.local_decls.visit_with(visitor)
BraceStructTypeFoldableImpl! {
impl<'tcx> TypeFoldable<'tcx> for Mir<'tcx> {
basic_blocks,
visibility_scopes,
visibility_scope_info,
promoted,
yield_ty,
generator_drop,
generator_layout,
local_decls,
arg_count,
upvar_decls,
spread_arg,
span,
cache,
}
}
impl<'tcx> TypeFoldable<'tcx> for GeneratorLayout<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
GeneratorLayout {
fields: self.fields.fold_with(folder),
}
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
self.fields.visit_with(visitor)
BraceStructTypeFoldableImpl! {
impl<'tcx> TypeFoldable<'tcx> for GeneratorLayout<'tcx> {
fields
}
}
impl<'tcx> TypeFoldable<'tcx> for LocalDecl<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
LocalDecl {
ty: self.ty.fold_with(folder),
..self.clone()
}
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
self.ty.visit_with(visitor)
BraceStructTypeFoldableImpl! {
impl<'tcx> TypeFoldable<'tcx> for LocalDecl<'tcx> {
mutability,
is_user_variable,
internal,
ty,
name,
source_info,
syntactic_scope,
}
}
impl<'tcx> TypeFoldable<'tcx> for BasicBlockData<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
BasicBlockData {
statements: self.statements.fold_with(folder),
terminator: self.terminator.fold_with(folder),
is_cleanup: self.is_cleanup
}
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
self.statements.visit_with(visitor) || self.terminator.visit_with(visitor)
BraceStructTypeFoldableImpl! {
impl<'tcx> TypeFoldable<'tcx> for BasicBlockData<'tcx> {
statements,
terminator,
is_cleanup,
}
}
impl<'tcx> TypeFoldable<'tcx> for ValidationOperand<'tcx, Place<'tcx>> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
ValidationOperand {
place: self.place.fold_with(folder),
ty: self.ty.fold_with(folder),
re: self.re,
mutbl: self.mutbl,
}
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
self.place.visit_with(visitor) || self.ty.visit_with(visitor)
BraceStructTypeFoldableImpl! {
impl<'tcx> TypeFoldable<'tcx> for ValidationOperand<'tcx, Place<'tcx>> {
place, ty, re, mutbl
}
}
impl<'tcx> TypeFoldable<'tcx> for Statement<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
use mir::StatementKind::*;
let kind = match self.kind {
Assign(ref place, ref rval) => Assign(place.fold_with(folder), rval.fold_with(folder)),
SetDiscriminant { ref place, variant_index } => SetDiscriminant {
place: place.fold_with(folder),
variant_index,
},
StorageLive(ref local) => StorageLive(local.fold_with(folder)),
StorageDead(ref local) => StorageDead(local.fold_with(folder)),
InlineAsm { ref asm, ref outputs, ref inputs } => InlineAsm {
asm: asm.clone(),
outputs: outputs.fold_with(folder),
inputs: inputs.fold_with(folder)
},
// Note for future: If we want to expose the region scopes
// during the fold, we need to either generalize EndRegion
// to carry `[ty::Region]`, or extend the `TypeFolder`
// trait with a `fn fold_scope`.
EndRegion(ref region_scope) => EndRegion(region_scope.clone()),
Validate(ref op, ref places) =>
Validate(op.clone(),
places.iter().map(|operand| operand.fold_with(folder)).collect()),
Nop => Nop,
};
Statement {
source_info: self.source_info,
kind,
}
BraceStructTypeFoldableImpl! {
impl<'tcx> TypeFoldable<'tcx> for Statement<'tcx> {
source_info, kind
}
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
use mir::StatementKind::*;
match self.kind {
Assign(ref place, ref rval) => { place.visit_with(visitor) || rval.visit_with(visitor) }
SetDiscriminant { ref place, .. } => place.visit_with(visitor),
StorageLive(ref local) |
StorageDead(ref local) => local.visit_with(visitor),
InlineAsm { ref outputs, ref inputs, .. } =>
outputs.visit_with(visitor) || inputs.visit_with(visitor),
// Note for future: If we want to expose the region scopes
// during the visit, we need to either generalize EndRegion
// to carry `[ty::Region]`, or extend the `TypeVisitor`
// trait with a `fn visit_scope`.
EndRegion(ref _scope) => false,
Validate(ref _op, ref places) =>
places.iter().any(|ty_and_place| ty_and_place.visit_with(visitor)),
Nop => false,
}
EnumTypeFoldableImpl! {
impl<'tcx> TypeFoldable<'tcx> for StatementKind<'tcx> {
(StatementKind::Assign)(a, b),
(StatementKind::SetDiscriminant) { place, variant_index },
(StatementKind::StorageLive)(a),
(StatementKind::StorageDead)(a),
(StatementKind::InlineAsm) { asm, outputs, inputs },
(StatementKind::Validate)(a, b),
(StatementKind::EndRegion)(a),
(StatementKind::Nop),
}
}
EnumTypeFoldableImpl! {
impl<'tcx, T> TypeFoldable<'tcx> for ClearCrossCrate<T> {
(ClearCrossCrate::Clear),
(ClearCrossCrate::Set)(a),
} where T: TypeFoldable<'tcx>
}
impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
use mir::TerminatorKind::*;
+4 -20
View File
@@ -16,7 +16,6 @@
use mir::*;
use ty::subst::{Subst, Substs};
use ty::{self, AdtDef, Ty, TyCtxt};
use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
use hir;
use ty::util::IntTypeExt;
@@ -100,25 +99,10 @@ pub fn projection_ty(self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
}
}
impl<'tcx> TypeFoldable<'tcx> for PlaceTy<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
match *self {
PlaceTy::Ty { ty } => PlaceTy::Ty { ty: ty.fold_with(folder) },
PlaceTy::Downcast { adt_def, substs, variant_index } => {
PlaceTy::Downcast {
adt_def,
substs: substs.fold_with(folder),
variant_index,
}
}
}
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
match *self {
PlaceTy::Ty { ty } => ty.visit_with(visitor),
PlaceTy::Downcast { substs, .. } => substs.visit_with(visitor)
}
EnumTypeFoldableImpl! {
impl<'tcx> TypeFoldable<'tcx> for PlaceTy<'tcx> {
(PlaceTy::Ty) { ty },
(PlaceTy::Downcast) { adt_def, substs, variant_index },
}
}
+21
View File
@@ -173,6 +173,15 @@ pub struct PerfStats {
pub symbol_hash_time: Cell<Duration>,
/// The accumulated time spent decoding def path tables from metadata
pub decode_def_path_tables_time: Cell<Duration>,
/// Total number of values canonicalized queries constructed.
pub queries_canonicalized: Cell<usize>,
/// Number of times we canonicalized a value and found that the
/// result had already been canonicalized.
pub canonicalized_values_allocated: Cell<usize>,
/// Number of times this query is invoked.
pub normalize_ty_after_erasing_regions: Cell<usize>,
/// Number of times this query is invoked.
pub normalize_projection_ty: Cell<usize>,
}
/// Enum to support dispatch of one-time diagnostics (in Session.diag_once)
@@ -858,6 +867,14 @@ pub fn print_perf_stats(&self) {
"Total time spent decoding DefPath tables: {}",
duration_to_secs_str(self.perf_stats.decode_def_path_tables_time.get())
);
println!("Total queries canonicalized: {}",
self.perf_stats.queries_canonicalized.get());
println!("Total canonical values interned: {}",
self.perf_stats.canonicalized_values_allocated.get());
println!("normalize_ty_after_erasing_regions: {}",
self.perf_stats.normalize_ty_after_erasing_regions.get());
println!("normalize_projection_ty: {}",
self.perf_stats.normalize_projection_ty.get());
}
/// We want to know if we're allowed to do an optimization for crate foo from -z fuel=foo=n.
@@ -1144,6 +1161,10 @@ pub fn build_session_(
incr_comp_bytes_hashed: Cell::new(0),
symbol_hash_time: Cell::new(Duration::from_secs(0)),
decode_def_path_tables_time: Cell::new(Duration::from_secs(0)),
queries_canonicalized: Cell::new(0),
canonicalized_values_allocated: Cell::new(0),
normalize_ty_after_erasing_regions: Cell::new(0),
normalize_projection_ty: Cell::new(0),
},
code_stats: RefCell::new(CodeStats::new()),
optimization_fuel_crate,
+2 -2
View File
@@ -16,7 +16,7 @@
use hir::def_id::{DefId, LOCAL_CRATE};
use syntax_pos::DUMMY_SP;
use traits::{self, Normalized, SelectionContext, Obligation, ObligationCause, Reveal};
use traits::{self, Normalized, SelectionContext, Obligation, ObligationCause};
use traits::IntercrateMode;
use traits::select::IntercrateAmbiguityCause;
use ty::{self, Ty, TyCtxt};
@@ -125,7 +125,7 @@ fn overlap<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
// types into scope; instead, we replace the generic types with
// fresh type variables, and hence we do our evaluations in an
// empty environment.
let param_env = ty::ParamEnv::empty(Reveal::UserFacing);
let param_env = ty::ParamEnv::empty();
let a_impl_header = with_fresh_ty_vars(selcx, param_env, a_def_id);
let b_impl_header = with_fresh_ty_vars(selcx, param_env, b_def_id);
+1 -2
View File
@@ -21,7 +21,6 @@
TraitNotObjectSafe,
ConstEvalFailure,
PredicateObligation,
Reveal,
SelectionContext,
SelectionError,
ObjectSafetyViolation,
@@ -140,7 +139,7 @@ fn error_implies(&self,
// FIXME: I'm just not taking associated types at all here.
// Eventually I'll need to implement param-env-aware
// `Γ₁ ⊦ φ₁ => Γ₂ ⊦ φ₂` logic.
let param_env = ty::ParamEnv::empty(Reveal::UserFacing);
let param_env = ty::ParamEnv::empty();
if let Ok(_) = self.can_sub(param_env, error, implication) {
debug!("error_implies: {:?} -> {:?} -> {:?}", cond, error, implication);
return true
+7 -2
View File
@@ -63,6 +63,8 @@
pub mod trans;
mod util;
pub mod query;
// Whether to enable bug compatibility with issue #43355
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum IntercrateMode {
@@ -695,7 +697,7 @@ fn normalize_and_test_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
predicates);
let result = tcx.infer_ctxt().enter(|infcx| {
let param_env = ty::ParamEnv::empty(Reveal::All);
let param_env = ty::ParamEnv::reveal_all();
let mut selcx = SelectionContext::new(&infcx);
let mut fulfill_cx = FulfillmentContext::new();
let cause = ObligationCause::dummy();
@@ -768,7 +770,10 @@ fn vtable_methods<'a, 'tcx>(
// the trait type may have higher-ranked lifetimes in it;
// so erase them if they appear, so that we get the type
// at some particular call site
let substs = tcx.erase_late_bound_regions_and_normalize(&ty::Binder(substs));
let substs = tcx.normalize_erasing_late_bound_regions(
ty::ParamEnv::reveal_all(),
&ty::Binder(substs),
);
// It's possible that the method relies on where clauses that
// do not hold for this particular set of type parameters.
@@ -0,0 +1,264 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use infer::at::At;
use infer::canonical::{Canonical, Canonicalize, QueryResult};
use infer::InferOk;
use std::iter::FromIterator;
use traits::query::CanonicalTyGoal;
use ty::{self, Ty, TyCtxt};
use ty::subst::Kind;
use std::rc::Rc;
impl<'cx, 'gcx, 'tcx> At<'cx, 'gcx, 'tcx> {
/// Given a type `ty` of some value being dropped, computes a set
/// of "kinds" (types, regions) that must be outlive the execution
/// of the destructor. These basically correspond to data that the
/// destructor might access. This is used during regionck to
/// impose "outlives" constraints on any lifetimes referenced
/// within.
///
/// The rules here are given by the "dropck" RFCs, notably [#1238]
/// and [#1327]. This is a fixed-point computation, where we
/// explore all the data that will be dropped (transitively) when
/// a value of type `ty` is dropped. For each type T that will be
/// dropped and which has a destructor, we must assume that all
/// the types/regions of T are live during the destructor, unless
/// they are marked with a special attribute (`#[may_dangle]`).
///
/// [#1238]: https://github.com/rust-lang/rfcs/blob/master/text/1238-nonparametric-dropck.md
/// [#1327]: https://github.com/rust-lang/rfcs/blob/master/text/1327-dropck-param-eyepatch.md
pub fn dropck_outlives(&self, ty: Ty<'tcx>) -> InferOk<'tcx, Vec<Kind<'tcx>>> {
debug!(
"dropck_outlives(ty={:?}, param_env={:?})",
ty, self.param_env,
);
// Quick check: there are a number of cases that we know do not require
// any destructor.
let tcx = self.infcx.tcx;
if trivial_dropck_outlives(tcx, ty) {
return InferOk { value: vec![], obligations: vec![] };
}
let gcx = tcx.global_tcx();
let (c_ty, orig_values) = self.infcx.canonicalize_query(&self.param_env.and(ty));
let span = self.cause.span;
match &gcx.dropck_outlives(c_ty) {
Ok(result) if result.is_proven() => {
match self.infcx.instantiate_query_result(
self.cause,
self.param_env,
&orig_values,
result,
) {
Ok(InferOk {
value: DropckOutlivesResult { kinds, overflows },
obligations,
}) => {
for overflow_ty in overflows.into_iter().take(1) {
let mut err = struct_span_err!(
tcx.sess,
span,
E0320,
"overflow while adding drop-check rules for {}",
self.infcx.resolve_type_vars_if_possible(&ty),
);
err.note(&format!("overflowed on {}", overflow_ty));
err.emit();
}
return InferOk {
value: kinds,
obligations,
};
}
Err(_) => { /* fallthrough to error-handling code below */ }
}
}
_ => { /* fallthrough to error-handling code below */ }
}
// Errors and ambiuity in dropck occur in two cases:
// - unresolved inference variables at the end of typeck
// - non well-formed types where projections cannot be resolved
// Either of these should hvae created an error before.
tcx.sess
.delay_span_bug(span, "dtorck encountered internal error");
return InferOk {
value: vec![],
obligations: vec![],
};
}
}
#[derive(Clone, Debug)]
pub struct DropckOutlivesResult<'tcx> {
pub kinds: Vec<Kind<'tcx>>,
pub overflows: Vec<Ty<'tcx>>,
}
/// A set of constraints that need to be satisfied in order for
/// a type to be valid for destruction.
#[derive(Clone, Debug)]
pub struct DtorckConstraint<'tcx> {
/// Types that are required to be alive in order for this
/// type to be valid for destruction.
pub outlives: Vec<ty::subst::Kind<'tcx>>,
/// Types that could not be resolved: projections and params.
pub dtorck_types: Vec<Ty<'tcx>>,
/// If, during the computation of the dtorck constraint, we
/// overflow, that gets recorded here. The caller is expected to
/// report an error.
pub overflows: Vec<Ty<'tcx>>,
}
impl<'tcx> DtorckConstraint<'tcx> {
pub fn empty() -> DtorckConstraint<'tcx> {
DtorckConstraint {
outlives: vec![],
dtorck_types: vec![],
overflows: vec![],
}
}
}
impl<'tcx> FromIterator<DtorckConstraint<'tcx>> for DtorckConstraint<'tcx> {
fn from_iter<I: IntoIterator<Item = DtorckConstraint<'tcx>>>(iter: I) -> Self {
let mut result = Self::empty();
for DtorckConstraint {
outlives,
dtorck_types,
overflows,
} in iter
{
result.outlives.extend(outlives);
result.dtorck_types.extend(dtorck_types);
result.overflows.extend(overflows);
}
result
}
}
impl<'gcx: 'tcx, 'tcx> Canonicalize<'gcx, 'tcx> for ty::ParamEnvAnd<'tcx, Ty<'tcx>> {
type Canonicalized = CanonicalTyGoal<'gcx>;
fn intern(
_gcx: TyCtxt<'_, 'gcx, 'gcx>,
value: Canonical<'gcx, Self::Lifted>,
) -> Self::Canonicalized {
value
}
}
BraceStructTypeFoldableImpl! {
impl<'tcx> TypeFoldable<'tcx> for DropckOutlivesResult<'tcx> {
kinds, overflows
}
}
BraceStructLiftImpl! {
impl<'a, 'tcx> Lift<'tcx> for DropckOutlivesResult<'a> {
type Lifted = DropckOutlivesResult<'tcx>;
kinds, overflows
}
}
impl_stable_hash_for!(struct DropckOutlivesResult<'tcx> {
kinds, overflows
});
impl<'gcx: 'tcx, 'tcx> Canonicalize<'gcx, 'tcx> for QueryResult<'tcx, DropckOutlivesResult<'tcx>> {
// we ought to intern this, but I'm too lazy just now
type Canonicalized = Rc<Canonical<'gcx, QueryResult<'gcx, DropckOutlivesResult<'gcx>>>>;
fn intern(
_gcx: TyCtxt<'_, 'gcx, 'gcx>,
value: Canonical<'gcx, Self::Lifted>,
) -> Self::Canonicalized {
Rc::new(value)
}
}
impl_stable_hash_for!(struct DtorckConstraint<'tcx> {
outlives,
dtorck_types,
overflows
});
/// This returns true if the type `ty` is "trivial" for
/// dropck-outlives -- that is, if it doesn't require any types to
/// outlive. This is similar but not *quite* the same as the
/// `needs_drop` test in the compiler already -- that is, for every
/// type T for which this function return true, needs-drop would
/// return false. But the reverse does not hold: in particular,
/// `needs_drop` returns false for `PhantomData`, but it is not
/// trivial for dropck-outlives.
///
/// Note also that `needs_drop` requires a "global" type (i.e., one
/// with erased regions), but this funtcion does not.
fn trivial_dropck_outlives<'cx, 'tcx>(tcx: TyCtxt<'cx, '_, 'tcx>, ty: Ty<'tcx>) -> bool {
match ty.sty {
// None of these types have a destructor and hence they do not
// require anything in particular to outlive the dtor's
// execution.
ty::TyInfer(ty::FreshIntTy(_))
| ty::TyInfer(ty::FreshFloatTy(_))
| ty::TyBool
| ty::TyInt(_)
| ty::TyUint(_)
| ty::TyFloat(_)
| ty::TyNever
| ty::TyFnDef(..)
| ty::TyFnPtr(_)
| ty::TyChar
| ty::TyGeneratorWitness(..)
| ty::TyRawPtr(_)
| ty::TyRef(..)
| ty::TyStr
| ty::TyForeign(..)
| ty::TyError => true,
// [T; N] and [T] have same properties as T.
ty::TyArray(ty, _) | ty::TySlice(ty) => trivial_dropck_outlives(tcx, ty),
// (T1..Tn) and closures have same properties as T1..Tn --
// check if *any* of those are trivial.
ty::TyTuple(ref tys, _) => tys.iter().cloned().all(|t| trivial_dropck_outlives(tcx, t)),
ty::TyClosure(def_id, ref substs) => substs
.upvar_tys(def_id, tcx)
.all(|t| trivial_dropck_outlives(tcx, t)),
ty::TyAdt(def, _) => {
if def.is_union() {
// Unions never run have a dtor.
true
} else {
// Other types might. Moreover, PhantomData doesn't
// have a dtor, but it is considered to own its
// content, so it is non-trivial.
false
}
}
// The following *might* require a destructor: it would deeper inspection to tell.
ty::TyDynamic(..)
| ty::TyProjection(..)
| ty::TyParam(_)
| ty::TyAnon(..)
| ty::TyInfer(_)
| ty::TyGenerator(..) => false,
}
}
+35
View File
@@ -0,0 +1,35 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Experimental types for the trait query interface. The methods
//! defined in this module are all based on **canonicalization**,
//! which makes a canonical query by replacing unbound inference
//! variables and regions, so that results can be reused more broadly.
//! The providers for the queries defined here can be found in
//! `librustc_traits`.
use infer::canonical::Canonical;
use ty::{self, Ty};
pub mod dropck_outlives;
pub mod normalize;
pub mod normalize_erasing_regions;
pub type CanonicalProjectionGoal<'tcx> =
Canonical<'tcx, ty::ParamEnvAnd<'tcx, ty::ProjectionTy<'tcx>>>;
pub type CanonicalTyGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, Ty<'tcx>>>;
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub struct NoSolution;
pub type Fallible<T> = Result<T, NoSolution>;
impl_stable_hash_for!(struct NoSolution { });
+274
View File
@@ -0,0 +1,274 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Code for the 'normalization' query. This consists of a wrapper
//! which folds deeply, invoking the underlying
//! `normalize_projection_ty` query when it encounters projections.
use infer::{InferCtxt, InferOk};
use infer::at::At;
use infer::canonical::{Canonical, Canonicalize, QueryResult};
use middle::const_val::ConstVal;
use mir::interpret::GlobalId;
use std::rc::Rc;
use traits::{Obligation, ObligationCause, PredicateObligation, Reveal};
use traits::query::CanonicalProjectionGoal;
use traits::project::Normalized;
use ty::{self, Ty, TyCtxt};
use ty::fold::{TypeFoldable, TypeFolder};
use ty::subst::{Subst, Substs};
use super::NoSolution;
impl<'cx, 'gcx, 'tcx> At<'cx, 'gcx, 'tcx> {
/// Normalize `value` in the context of the inference context,
/// yielding a resulting type, or an error if `value` cannot be
/// normalized. If you don't care about regions, you should prefer
/// `normalize_erasing_regions`, which is more efficient.
///
/// If the normalization succeeds and is unambigious, returns back
/// the normalized value along with various outlives relations (in
/// the form of obligations that must be discharged).
///
/// NB. This will *eventually* be the main means of
/// normalizing, but for now should be used only when we actually
/// know that normalization will succeed, since error reporting
/// and other details are still "under development".
pub fn normalize<T>(&self, value: &T) -> Result<Normalized<'tcx, T>, NoSolution>
where
T: TypeFoldable<'tcx>,
{
debug!(
"normalize::<{}>(value={:?}, param_env={:?})",
unsafe { ::std::intrinsics::type_name::<T>() },
value,
self.param_env,
);
let mut normalizer = QueryNormalizer {
infcx: self.infcx,
cause: self.cause,
param_env: self.param_env,
obligations: vec![],
error: false,
anon_depth: 0,
};
if !value.has_projections() {
return Ok(Normalized {
value: value.clone(),
obligations: vec![],
});
}
let value1 = value.fold_with(&mut normalizer);
if normalizer.error {
Err(NoSolution)
} else {
Ok(Normalized {
value: value1,
obligations: normalizer.obligations,
})
}
}
}
/// Result from the `normalize_projection_ty` query.
#[derive(Clone, Debug)]
pub struct NormalizationResult<'tcx> {
/// Result of normalization.
pub normalized_ty: Ty<'tcx>,
}
struct QueryNormalizer<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
cause: &'cx ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
obligations: Vec<PredicateObligation<'tcx>>,
error: bool,
anon_depth: usize,
}
impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for QueryNormalizer<'cx, 'gcx, 'tcx> {
fn tcx<'c>(&'c self) -> TyCtxt<'c, 'gcx, 'tcx> {
self.infcx.tcx
}
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
let ty = ty.super_fold_with(self);
match ty.sty {
ty::TyAnon(def_id, substs) if !substs.has_escaping_regions() => {
// (*)
// Only normalize `impl Trait` after type-checking, usually in trans.
match self.param_env.reveal {
Reveal::UserFacing => ty,
Reveal::All => {
let recursion_limit = self.tcx().sess.recursion_limit.get();
if self.anon_depth >= recursion_limit {
let obligation = Obligation::with_depth(
self.cause.clone(),
recursion_limit,
self.param_env,
ty,
);
self.infcx.report_overflow_error(&obligation, true);
}
let generic_ty = self.tcx().type_of(def_id);
let concrete_ty = generic_ty.subst(self.tcx(), substs);
self.anon_depth += 1;
let folded_ty = self.fold_ty(concrete_ty);
self.anon_depth -= 1;
folded_ty
}
}
}
ty::TyProjection(ref data) if !data.has_escaping_regions() => {
// (*)
// (*) This is kind of hacky -- we need to be able to
// handle normalization within binders because
// otherwise we wind up a need to normalize when doing
// trait matching (since you can have a trait
// obligation like `for<'a> T::B : Fn(&'a int)`), but
// we can't normalize with bound regions in scope. So
// far now we just ignore binders but only normalize
// if all bound regions are gone (and then we still
// have to renormalize whenever we instantiate a
// binder). It would be better to normalize in a
// binding-aware fashion.
let gcx = self.infcx.tcx.global_tcx();
let (c_data, orig_values) =
self.infcx.canonicalize_query(&self.param_env.and(*data));
debug!("QueryNormalizer: c_data = {:#?}", c_data);
debug!("QueryNormalizer: orig_values = {:#?}", orig_values);
match gcx.normalize_projection_ty(c_data) {
Ok(result) => {
// We don't expect ambiguity.
if result.is_ambiguous() {
self.error = true;
return ty;
}
match self.infcx.instantiate_query_result(
self.cause,
self.param_env,
&orig_values,
&result,
) {
Ok(InferOk {
value: result,
obligations,
}) => {
debug!("QueryNormalizer: result = {:#?}", result);
debug!("QueryNormalizer: obligations = {:#?}", obligations);
self.obligations.extend(obligations);
return result.normalized_ty;
}
Err(_) => {
self.error = true;
return ty;
}
}
}
Err(NoSolution) => {
self.error = true;
ty
}
}
}
_ => ty,
}
}
fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
if let ConstVal::Unevaluated(def_id, substs) = constant.val {
let tcx = self.infcx.tcx.global_tcx();
if let Some(param_env) = self.tcx().lift_to_global(&self.param_env) {
if substs.needs_infer() {
let identity_substs = Substs::identity_for_item(tcx, def_id);
let instance = ty::Instance::resolve(tcx, param_env, def_id, identity_substs);
if let Some(instance) = instance {
let cid = GlobalId {
instance,
promoted: None,
};
match tcx.const_eval(param_env.and(cid)) {
Ok(evaluated) => {
let evaluated = evaluated.subst(self.tcx(), substs);
return self.fold_const(evaluated);
}
Err(_) => {}
}
}
} else {
if let Some(substs) = self.tcx().lift_to_global(&substs) {
let instance = ty::Instance::resolve(tcx, param_env, def_id, substs);
if let Some(instance) = instance {
let cid = GlobalId {
instance,
promoted: None,
};
match tcx.const_eval(param_env.and(cid)) {
Ok(evaluated) => return self.fold_const(evaluated),
Err(_) => {}
}
}
}
}
}
}
constant
}
}
BraceStructTypeFoldableImpl! {
impl<'tcx> TypeFoldable<'tcx> for NormalizationResult<'tcx> {
normalized_ty
}
}
BraceStructLiftImpl! {
impl<'a, 'tcx> Lift<'tcx> for NormalizationResult<'a> {
type Lifted = NormalizationResult<'tcx>;
normalized_ty
}
}
impl<'gcx: 'tcx, 'tcx> Canonicalize<'gcx, 'tcx> for ty::ParamEnvAnd<'tcx, ty::ProjectionTy<'tcx>> {
type Canonicalized = CanonicalProjectionGoal<'gcx>;
fn intern(
_gcx: TyCtxt<'_, 'gcx, 'gcx>,
value: Canonical<'gcx, Self::Lifted>,
) -> Self::Canonicalized {
value
}
}
impl<'gcx: 'tcx, 'tcx> Canonicalize<'gcx, 'tcx> for QueryResult<'tcx, NormalizationResult<'tcx>> {
// we ought to intern this, but I'm too lazy just now
type Canonicalized = Rc<Canonical<'gcx, QueryResult<'gcx, NormalizationResult<'gcx>>>>;
fn intern(
_gcx: TyCtxt<'_, 'gcx, 'gcx>,
value: Canonical<'gcx, Self::Lifted>,
) -> Self::Canonicalized {
Rc::new(value)
}
}
impl_stable_hash_for!(struct NormalizationResult<'tcx> {
normalized_ty
});
@@ -0,0 +1,88 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Methods for normalizing when you don't care about regions (and
//! aren't doing type inference). If either of those things don't
//! apply to you, use `infcx.normalize(...)`.
//!
//! The methods in this file use a `TypeFolder` to recursively process
//! contents, invoking the underlying
//! `normalize_ty_after_erasing_regions` query for each type found
//! within. (This underlying query is what is cached.)
use ty::{self, Ty, TyCtxt};
use ty::fold::{TypeFoldable, TypeFolder};
impl<'cx, 'tcx> TyCtxt<'cx, 'tcx, 'tcx> {
/// Erase the regions in `value` and then fully normalize all the
/// types found within. The result will also have regions erased.
///
/// This is appropriate to use only after type-check: it assumes
/// that normalization will succeed, for example.
pub fn normalize_erasing_regions<T>(self, param_env: ty::ParamEnv<'tcx>, value: T) -> T
where
T: TypeFoldable<'tcx>,
{
debug!(
"normalize_erasing_regions::<{}>(value={:?}, param_env={:?})",
unsafe { ::std::intrinsics::type_name::<T>() },
value,
param_env,
);
// Erase first before we do the real query -- this keeps the
// cache from being too polluted.
let value = self.erase_regions(&value);
if !value.has_projections() {
value
} else {
value.fold_with(&mut NormalizeAfterErasingRegionsFolder {
tcx: self,
param_env: param_env,
})
}
}
/// If you have a `Binder<T>`, you can do this to strip out the
/// late-bound regions and then normalize the result, yielding up
/// a `T` (with regions erased). This is appropriate when the
/// binder is being instantiated at the call site.
///
/// NB. Currently, higher-ranked type bounds inhibit
/// normalization. Therefore, each time we erase them in
/// translation, we need to normalize the contents.
pub fn normalize_erasing_late_bound_regions<T>(
self,
param_env: ty::ParamEnv<'tcx>,
value: &ty::Binder<T>,
) -> T
where
T: TypeFoldable<'tcx>,
{
assert!(!value.needs_subst());
let value = self.erase_late_bound_regions(value);
self.normalize_erasing_regions(param_env, value)
}
}
struct NormalizeAfterErasingRegionsFolder<'cx, 'tcx: 'cx> {
tcx: TyCtxt<'cx, 'tcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
}
impl<'cx, 'tcx> TypeFolder<'tcx, 'tcx> for NormalizeAfterErasingRegionsFolder<'cx, 'tcx> {
fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx> {
self.tcx
}
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
self.tcx.normalize_ty_after_erasing_regions(self.param_env.and(ty))
}
}
+10 -7
View File
@@ -777,7 +777,7 @@ fn evaluate_trait_predicate_recursively<'o>(&mut self,
// value in order to work, so we can clear out the param env and get better
// caching. (If the current param env is inconsistent, we don't care what happens).
debug!("evaluate_trait_predicate_recursively({:?}) - in global", obligation);
obligation.param_env = ty::ParamEnv::empty(obligation.param_env.reveal);
obligation.param_env = obligation.param_env.without_caller_bounds();
}
let stack = self.push_stack(previous_stack, &obligation);
@@ -2083,9 +2083,10 @@ fn sized_conditions(&mut self, obligation: &TraitObligation<'tcx>)
ty::TyProjection(_) | ty::TyParam(_) | ty::TyAnon(..) => None,
ty::TyInfer(ty::TyVar(_)) => Ambiguous,
ty::TyInfer(ty::FreshTy(_))
| ty::TyInfer(ty::FreshIntTy(_))
| ty::TyInfer(ty::FreshFloatTy(_)) => {
ty::TyInfer(ty::CanonicalTy(_)) |
ty::TyInfer(ty::FreshTy(_)) |
ty::TyInfer(ty::FreshIntTy(_)) |
ty::TyInfer(ty::FreshFloatTy(_)) => {
bug!("asked to assemble builtin bounds of unexpected type: {:?}",
self_ty);
}
@@ -2154,9 +2155,10 @@ fn copy_clone_conditions(&mut self, obligation: &TraitObligation<'tcx>)
Ambiguous
}
ty::TyInfer(ty::FreshTy(_))
| ty::TyInfer(ty::FreshIntTy(_))
| ty::TyInfer(ty::FreshFloatTy(_)) => {
ty::TyInfer(ty::CanonicalTy(_)) |
ty::TyInfer(ty::FreshTy(_)) |
ty::TyInfer(ty::FreshIntTy(_)) |
ty::TyInfer(ty::FreshFloatTy(_)) => {
bug!("asked to assemble builtin bounds of unexpected type: {:?}",
self_ty);
}
@@ -2195,6 +2197,7 @@ fn constituent_types_for_ty(&self, t: Ty<'tcx>) -> Vec<Ty<'tcx>> {
ty::TyParam(..) |
ty::TyForeign(..) |
ty::TyProjection(..) |
ty::TyInfer(ty::CanonicalTy(_)) |
ty::TyInfer(ty::TyVar(_)) |
ty::TyInfer(ty::FreshTy(_)) |
ty::TyInfer(ty::FreshIntTy(_)) |
+2 -2
View File
@@ -26,7 +26,7 @@
use hir::def_id::DefId;
use infer::{InferCtxt, InferOk};
use ty::subst::{Subst, Substs};
use traits::{self, Reveal, ObligationCause};
use traits::{self, ObligationCause};
use traits::select::IntercrateAmbiguityCause;
use ty::{self, TyCtxt, TypeFoldable};
use syntax_pos::DUMMY_SP;
@@ -132,7 +132,7 @@ pub fn find_associated_item<'a, 'tcx>(
match ancestors.defs(tcx, item.name, item.kind, trait_def_id).next() {
Some(node_item) => {
let substs = tcx.infer_ctxt().enter(|infcx| {
let param_env = ty::ParamEnv::empty(Reveal::All);
let param_env = ty::ParamEnv::reveal_all();
let substs = substs.rebase_onto(tcx, trait_def_id, impl_data.substs);
let substs = translate_substs(&infcx, param_env, impl_data.impl_def_id,
substs, node_item.node);
+45 -238
View File
@@ -363,258 +363,65 @@ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
}
}
impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableImplData<'tcx, N> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
traits::VtableImplData {
impl_def_id: self.impl_def_id,
substs: self.substs.fold_with(folder),
nested: self.nested.fold_with(folder),
}
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
self.substs.visit_with(visitor) || self.nested.visit_with(visitor)
}
BraceStructTypeFoldableImpl! {
impl<'tcx, N> TypeFoldable<'tcx> for traits::VtableImplData<'tcx, N> {
impl_def_id, substs, nested
} where N: TypeFoldable<'tcx>
}
impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableGeneratorData<'tcx, N> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
traits::VtableGeneratorData {
closure_def_id: self.closure_def_id,
substs: self.substs.fold_with(folder),
nested: self.nested.fold_with(folder),
}
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
self.substs.visit_with(visitor) || self.nested.visit_with(visitor)
}
BraceStructTypeFoldableImpl! {
impl<'tcx, N> TypeFoldable<'tcx> for traits::VtableGeneratorData<'tcx, N> {
closure_def_id, substs, nested
} where N: TypeFoldable<'tcx>
}
impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableClosureData<'tcx, N> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
traits::VtableClosureData {
closure_def_id: self.closure_def_id,
substs: self.substs.fold_with(folder),
nested: self.nested.fold_with(folder),
}
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
self.substs.visit_with(visitor) || self.nested.visit_with(visitor)
}
BraceStructTypeFoldableImpl! {
impl<'tcx, N> TypeFoldable<'tcx> for traits::VtableClosureData<'tcx, N> {
closure_def_id, substs, nested
} where N: TypeFoldable<'tcx>
}
impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableAutoImplData<N> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
traits::VtableAutoImplData {
trait_def_id: self.trait_def_id,
nested: self.nested.fold_with(folder),
}
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
self.nested.visit_with(visitor)
}
BraceStructTypeFoldableImpl! {
impl<'tcx, N> TypeFoldable<'tcx> for traits::VtableAutoImplData<N> {
trait_def_id, nested
} where N: TypeFoldable<'tcx>
}
impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableBuiltinData<N> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
traits::VtableBuiltinData {
nested: self.nested.fold_with(folder),
}
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
self.nested.visit_with(visitor)
}
BraceStructTypeFoldableImpl! {
impl<'tcx, N> TypeFoldable<'tcx> for traits::VtableBuiltinData<N> {
nested
} where N: TypeFoldable<'tcx>
}
impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableObjectData<'tcx, N> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
traits::VtableObjectData {
upcast_trait_ref: self.upcast_trait_ref.fold_with(folder),
vtable_base: self.vtable_base,
nested: self.nested.fold_with(folder),
}
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
self.upcast_trait_ref.visit_with(visitor) || self.nested.visit_with(visitor)
}
BraceStructTypeFoldableImpl! {
impl<'tcx, N> TypeFoldable<'tcx> for traits::VtableObjectData<'tcx, N> {
upcast_trait_ref, vtable_base, nested
} where N: TypeFoldable<'tcx>
}
impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableFnPointerData<'tcx, N> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
traits::VtableFnPointerData {
fn_ty: self.fn_ty.fold_with(folder),
nested: self.nested.fold_with(folder),
}
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
self.fn_ty.visit_with(visitor) || self.nested.visit_with(visitor)
}
BraceStructTypeFoldableImpl! {
impl<'tcx, N> TypeFoldable<'tcx> for traits::VtableFnPointerData<'tcx, N> {
fn_ty,
nested
} where N: TypeFoldable<'tcx>
}
impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Vtable<'tcx, N> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
match *self {
traits::VtableImpl(ref v) => traits::VtableImpl(v.fold_with(folder)),
traits::VtableAutoImpl(ref t) => traits::VtableAutoImpl(t.fold_with(folder)),
traits::VtableGenerator(ref d) => {
traits::VtableGenerator(d.fold_with(folder))
}
traits::VtableClosure(ref d) => {
traits::VtableClosure(d.fold_with(folder))
}
traits::VtableFnPointer(ref d) => {
traits::VtableFnPointer(d.fold_with(folder))
}
traits::VtableParam(ref n) => traits::VtableParam(n.fold_with(folder)),
traits::VtableBuiltin(ref d) => traits::VtableBuiltin(d.fold_with(folder)),
traits::VtableObject(ref d) => traits::VtableObject(d.fold_with(folder)),
}
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
match *self {
traits::VtableImpl(ref v) => v.visit_with(visitor),
traits::VtableAutoImpl(ref t) => t.visit_with(visitor),
traits::VtableGenerator(ref d) => d.visit_with(visitor),
traits::VtableClosure(ref d) => d.visit_with(visitor),
traits::VtableFnPointer(ref d) => d.visit_with(visitor),
traits::VtableParam(ref n) => n.visit_with(visitor),
traits::VtableBuiltin(ref d) => d.visit_with(visitor),
traits::VtableObject(ref d) => d.visit_with(visitor),
}
}
EnumTypeFoldableImpl! {
impl<'tcx, N> TypeFoldable<'tcx> for traits::Vtable<'tcx, N> {
(traits::VtableImpl)(a),
(traits::VtableAutoImpl)(a),
(traits::VtableGenerator)(a),
(traits::VtableClosure)(a),
(traits::VtableFnPointer)(a),
(traits::VtableParam)(a),
(traits::VtableBuiltin)(a),
(traits::VtableObject)(a),
} where N: TypeFoldable<'tcx>
}
impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Normalized<'tcx, T> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
Normalized {
value: self.value.fold_with(folder),
obligations: self.obligations.fold_with(folder),
}
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
self.value.visit_with(visitor) || self.obligations.visit_with(visitor)
}
}
impl<'tcx> TypeFoldable<'tcx> for traits::ObligationCauseCode<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
match *self {
super::ExprAssignable |
super::MatchExpressionArm { arm_span: _, source: _ } |
super::IfExpression |
super::IfExpressionWithNoElse |
super::MainFunctionType |
super::StartFunctionType |
super::IntrinsicType |
super::MethodReceiver |
super::MiscObligation |
super::SliceOrArrayElem |
super::TupleElem |
super::ItemObligation(_) |
super::AssignmentLhsSized |
super::TupleInitializerSized |
super::StructInitializerSized |
super::VariableType(_) |
super::ReturnType(_) |
super::SizedReturnType |
super::SizedYieldType |
super::ReturnNoExpression |
super::RepeatVec |
super::FieldSized(_) |
super::ConstSized |
super::SharedStatic |
super::BlockTailExpression(_) |
super::CompareImplMethodObligation { .. } => self.clone(),
super::ProjectionWf(proj) => super::ProjectionWf(proj.fold_with(folder)),
super::ReferenceOutlivesReferent(ty) => {
super::ReferenceOutlivesReferent(ty.fold_with(folder))
}
super::ObjectTypeBound(ty, r) => {
super::ObjectTypeBound(ty.fold_with(folder), r.fold_with(folder))
}
super::ObjectCastObligation(ty) => {
super::ObjectCastObligation(ty.fold_with(folder))
}
super::BuiltinDerivedObligation(ref cause) => {
super::BuiltinDerivedObligation(cause.fold_with(folder))
}
super::ImplDerivedObligation(ref cause) => {
super::ImplDerivedObligation(cause.fold_with(folder))
}
}
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
match *self {
super::ExprAssignable |
super::MatchExpressionArm { arm_span: _, source: _ } |
super::IfExpression |
super::IfExpressionWithNoElse |
super::MainFunctionType |
super::StartFunctionType |
super::IntrinsicType |
super::MethodReceiver |
super::MiscObligation |
super::SliceOrArrayElem |
super::TupleElem |
super::ItemObligation(_) |
super::AssignmentLhsSized |
super::TupleInitializerSized |
super::StructInitializerSized |
super::VariableType(_) |
super::ReturnType(_) |
super::SizedReturnType |
super::SizedYieldType |
super::ReturnNoExpression |
super::RepeatVec |
super::FieldSized(_) |
super::ConstSized |
super::SharedStatic |
super::BlockTailExpression(_) |
super::CompareImplMethodObligation { .. } => false,
super::ProjectionWf(proj) => proj.visit_with(visitor),
super::ReferenceOutlivesReferent(ty) => ty.visit_with(visitor),
super::ObjectTypeBound(ty, r) => ty.visit_with(visitor) || r.visit_with(visitor),
super::ObjectCastObligation(ty) => ty.visit_with(visitor),
super::BuiltinDerivedObligation(ref cause) => cause.visit_with(visitor),
super::ImplDerivedObligation(ref cause) => cause.visit_with(visitor)
}
}
}
impl<'tcx> TypeFoldable<'tcx> for traits::DerivedObligationCause<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
traits::DerivedObligationCause {
parent_trait_ref: self.parent_trait_ref.fold_with(folder),
parent_code: self.parent_code.fold_with(folder)
}
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
self.parent_trait_ref.visit_with(visitor) || self.parent_code.visit_with(visitor)
}
}
impl<'tcx> TypeFoldable<'tcx> for traits::ObligationCause<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
traits::ObligationCause {
span: self.span,
body_id: self.body_id,
code: self.code.fold_with(folder),
}
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
self.code.visit_with(visitor)
}
BraceStructTypeFoldableImpl! {
impl<'tcx, T> TypeFoldable<'tcx> for Normalized<'tcx, T> {
value,
obligations
} where T: TypeFoldable<'tcx>
}
+56 -96
View File
@@ -14,14 +14,14 @@
// general routines.
use dep_graph::{DepKind, DepTrackingMapConfig};
use infer::TransNormalize;
use std::marker::PhantomData;
use syntax_pos::DUMMY_SP;
use hir::def_id::DefId;
use infer::InferCtxt;
use syntax_pos::Span;
use traits::{FulfillmentContext, Obligation, ObligationCause, SelectionContext, Vtable};
use ty::{self, Ty, TyCtxt};
use ty::subst::{Subst, Substs};
use ty::fold::{TypeFoldable, TypeFolder};
use ty::fold::TypeFoldable;
/// Attempts to resolve an obligation to a vtable.. The result is
/// a shallow vtable resolution -- meaning that we do not
@@ -87,111 +87,29 @@ pub fn trans_fulfill_obligation<'a, 'tcx>(ty: TyCtxt<'a, 'tcx, 'tcx>,
}
impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
/// Monomorphizes a type from the AST by first applying the in-scope
/// substitutions and then normalizing any associated types.
pub fn trans_apply_param_substs<T>(self,
param_substs: &Substs<'tcx>,
value: &T)
-> T
where T: TransNormalize<'tcx>
{
debug!("apply_param_substs(param_substs={:?}, value={:?})", param_substs, value);
let substituted = value.subst(self, param_substs);
let substituted = self.erase_regions(&substituted);
AssociatedTypeNormalizer::new(self).fold(&substituted)
}
pub fn trans_apply_param_substs_env<T>(
/// Monomorphizes a type from the AST by first applying the
/// in-scope substitutions and then normalizing any associated
/// types.
pub fn subst_and_normalize_erasing_regions<T>(
self,
param_substs: &Substs<'tcx>,
param_env: ty::ParamEnv<'tcx>,
value: &T,
value: &T
) -> T
where
T: TransNormalize<'tcx>,
T: TypeFoldable<'tcx>,
{
debug!(
"apply_param_substs_env(param_substs={:?}, value={:?}, param_env={:?})",
"subst_and_normalize_erasing_regions(\
param_substs={:?}, \
value={:?}, \
param_env={:?})",
param_substs,
value,
param_env,
);
let substituted = value.subst(self, param_substs);
let substituted = self.erase_regions(&substituted);
AssociatedTypeNormalizerEnv::new(self, param_env).fold(&substituted)
}
pub fn trans_impl_self_ty(&self, def_id: DefId, substs: &'tcx Substs<'tcx>)
-> Ty<'tcx>
{
self.trans_apply_param_substs(substs, &self.type_of(def_id))
}
}
struct AssociatedTypeNormalizer<'a, 'gcx: 'a> {
tcx: TyCtxt<'a, 'gcx, 'gcx>,
}
impl<'a, 'gcx> AssociatedTypeNormalizer<'a, 'gcx> {
fn new(tcx: TyCtxt<'a, 'gcx, 'gcx>) -> Self {
AssociatedTypeNormalizer { tcx }
}
fn fold<T:TypeFoldable<'gcx>>(&mut self, value: &T) -> T {
if !value.has_projections() {
value.clone()
} else {
value.fold_with(self)
}
}
}
impl<'a, 'gcx> TypeFolder<'gcx, 'gcx> for AssociatedTypeNormalizer<'a, 'gcx> {
fn tcx<'c>(&'c self) -> TyCtxt<'c, 'gcx, 'gcx> {
self.tcx
}
fn fold_ty(&mut self, ty: Ty<'gcx>) -> Ty<'gcx> {
if !ty.has_projections() {
ty
} else {
debug!("AssociatedTypeNormalizer: ty={:?}", ty);
self.tcx.fully_normalize_monormophic_ty(ty)
}
}
}
struct AssociatedTypeNormalizerEnv<'a, 'gcx: 'a> {
tcx: TyCtxt<'a, 'gcx, 'gcx>,
param_env: ty::ParamEnv<'gcx>,
}
impl<'a, 'gcx> AssociatedTypeNormalizerEnv<'a, 'gcx> {
fn new(tcx: TyCtxt<'a, 'gcx, 'gcx>, param_env: ty::ParamEnv<'gcx>) -> Self {
Self { tcx, param_env }
}
fn fold<T: TypeFoldable<'gcx>>(&mut self, value: &T) -> T {
if !value.has_projections() {
value.clone()
} else {
value.fold_with(self)
}
}
}
impl<'a, 'gcx> TypeFolder<'gcx, 'gcx> for AssociatedTypeNormalizerEnv<'a, 'gcx> {
fn tcx<'c>(&'c self) -> TyCtxt<'c, 'gcx, 'gcx> {
self.tcx
}
fn fold_ty(&mut self, ty: Ty<'gcx>) -> Ty<'gcx> {
if !ty.has_projections() {
ty
} else {
debug!("AssociatedTypeNormalizerEnv: ty={:?}", ty);
self.tcx.normalize_associated_type_in_env(&ty, self.param_env)
}
self.normalize_erasing_regions(param_env, substituted)
}
}
@@ -221,3 +139,45 @@ fn to_dep_kind() -> DepKind {
DepKind::TraitSelect
}
}
impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
/// Finishes processes any obligations that remain in the
/// fulfillment context, and then returns the result with all type
/// variables removed and regions erased. Because this is intended
/// for use after type-check has completed, if any errors occur,
/// it will panic. It is used during normalization and other cases
/// where processing the obligations in `fulfill_cx` may cause
/// type inference variables that appear in `result` to be
/// unified, and hence we need to process those obligations to get
/// the complete picture of the type.
fn drain_fulfillment_cx_or_panic<T>(&self,
span: Span,
fulfill_cx: &mut FulfillmentContext<'tcx>,
result: &T)
-> T::Lifted
where T: TypeFoldable<'tcx> + ty::Lift<'gcx>
{
debug!("drain_fulfillment_cx_or_panic()");
// In principle, we only need to do this so long as `result`
// contains unbound type parameters. It could be a slight
// optimization to stop iterating early.
match fulfill_cx.select_all_or_error(self) {
Ok(()) => { }
Err(errors) => {
span_bug!(span, "Encountered errors `{:?}` resolving bounds after type-checking",
errors);
}
}
let result = self.resolve_type_vars_if_possible(result);
let result = self.tcx.erase_regions(&result);
match self.tcx.lift_to_global(&result) {
Some(result) => result,
None => {
span_bug!(span, "Uninferred types/regions in `{:?}`", result);
}
}
}
}
+34 -4
View File
@@ -23,6 +23,7 @@
use hir::map::DefPathHash;
use lint::{self, Lint};
use ich::{StableHashingContext, NodeIdHashingMode};
use infer::canonical::{CanonicalVarInfo, CanonicalVarInfos};
use infer::outlives::free_region_map::FreeRegionMap;
use middle::const_val::ConstVal;
use middle::cstore::{CrateStore, LinkMeta};
@@ -131,6 +132,7 @@ pub struct CtxtInterners<'tcx> {
type_: RefCell<FxHashSet<Interned<'tcx, TyS<'tcx>>>>,
type_list: RefCell<FxHashSet<Interned<'tcx, Slice<Ty<'tcx>>>>>,
substs: RefCell<FxHashSet<Interned<'tcx, Substs<'tcx>>>>,
canonical_var_infos: RefCell<FxHashSet<Interned<'tcx, Slice<CanonicalVarInfo>>>>,
region: RefCell<FxHashSet<Interned<'tcx, RegionKind>>>,
existential_predicates: RefCell<FxHashSet<Interned<'tcx, Slice<ExistentialPredicate<'tcx>>>>>,
predicates: RefCell<FxHashSet<Interned<'tcx, Slice<Predicate<'tcx>>>>>,
@@ -146,6 +148,7 @@ fn new(arena: &'tcx DroplessArena) -> CtxtInterners<'tcx> {
substs: RefCell::new(FxHashSet()),
region: RefCell::new(FxHashSet()),
existential_predicates: RefCell::new(FxHashSet()),
canonical_var_infos: RefCell::new(FxHashSet()),
predicates: RefCell::new(FxHashSet()),
const_: RefCell::new(FxHashSet()),
}
@@ -1508,7 +1511,7 @@ pub fn enter_local<F, R>(&self, arena: &'tcx DroplessArena, f: F) -> R
/// pointer differs. The latter case is possible if a primitive type,
/// e.g. `()` or `u8`, was interned in a different context.
pub trait Lift<'tcx> {
type Lifted;
type Lifted: 'tcx;
fn lift_to_tcx<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<Self::Lifted>;
}
@@ -1838,6 +1841,12 @@ fn borrow<'a>(&'a self) -> &'a [Ty<'lcx>] {
}
}
impl<'tcx: 'lcx, 'lcx> Borrow<[CanonicalVarInfo]> for Interned<'tcx, Slice<CanonicalVarInfo>> {
fn borrow<'a>(&'a self) -> &'a [CanonicalVarInfo] {
&self.0[..]
}
}
impl<'tcx: 'lcx, 'lcx> Borrow<[Kind<'lcx>]> for Interned<'tcx, Substs<'tcx>> {
fn borrow<'a>(&'a self) -> &'a [Kind<'lcx>] {
&self.0[..]
@@ -1970,6 +1979,22 @@ macro_rules! slice_interners {
substs: _intern_substs(Kind)
);
// This isn't a perfect fit: CanonicalVarInfo slices are always
// allocated in the global arena, so this `intern_method!` macro is
// overly general. But we just return false for the code that checks
// whether they belong in the thread-local arena, so no harm done, and
// seems better than open-coding the rest.
intern_method! {
'tcx,
canonical_var_infos: _intern_canonical_var_infos(
&[CanonicalVarInfo],
alloc_slice,
Deref::deref,
|xs: &[CanonicalVarInfo]| -> &Slice<CanonicalVarInfo> { unsafe { mem::transmute(xs) } },
|_xs: &[CanonicalVarInfo]| -> bool { false }
) -> Slice<CanonicalVarInfo>
}
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
/// Given a `fn` type, returns an equivalent `unsafe fn` type;
/// that is, a `fn` type that is equivalent in every way for being
@@ -2257,6 +2282,14 @@ pub fn intern_substs(self, ts: &[Kind<'tcx>]) -> &'tcx Slice<Kind<'tcx>> {
}
}
pub fn intern_canonical_var_infos(self, ts: &[CanonicalVarInfo]) -> CanonicalVarInfos<'gcx> {
if ts.len() == 0 {
Slice::empty()
} else {
self.global_tcx()._intern_canonical_var_infos(ts)
}
}
pub fn mk_fn_sig<I>(self,
inputs: I,
output: I::Item,
@@ -2504,9 +2537,6 @@ pub fn provide(providers: &mut ty::maps::Providers) {
assert_eq!(cnum, LOCAL_CRATE);
tcx.features().clone_closures
};
providers.fully_normalize_monormophic_ty = |tcx, ty| {
tcx.fully_normalize_associated_types_in(&ty)
};
providers.features_query = |tcx, cnum| {
assert_eq!(cnum, LOCAL_CRATE);
Lrc::new(tcx.sess.features_untracked().clone())
+1
View File
@@ -220,6 +220,7 @@ pub fn sort_string(&self, tcx: TyCtxt<'a, 'gcx, 'lcx>) -> String {
ty::TyInfer(ty::TyVar(_)) => "inferred type".to_string(),
ty::TyInfer(ty::IntVar(_)) => "integral variable".to_string(),
ty::TyInfer(ty::FloatVar(_)) => "floating-point variable".to_string(),
ty::TyInfer(ty::CanonicalTy(_)) |
ty::TyInfer(ty::FreshTy(_)) => "skolemized type".to_string(),
ty::TyInfer(ty::FreshIntTy(_)) => "skolemized integral type".to_string(),
ty::TyInfer(ty::FreshFloatTy(_)) => "skolemized floating-point type".to_string(),
+10 -2
View File
@@ -112,8 +112,16 @@ fn add_sty(&mut self, st: &ty::TypeVariants) {
match infer {
ty::FreshTy(_) |
ty::FreshIntTy(_) |
ty::FreshFloatTy(_) => {}
_ => self.add_flags(TypeFlags::KEEP_IN_LOCAL_TCX)
ty::FreshFloatTy(_) |
ty::CanonicalTy(_) => {
self.add_flags(TypeFlags::HAS_CANONICAL_VARS);
}
ty::TyVar(_) |
ty::IntVar(_) |
ty::FloatVar(_) => {
self.add_flags(TypeFlags::KEEP_IN_LOCAL_TCX)
}
}
}
+3
View File
@@ -49,6 +49,9 @@
/// The TypeFoldable trait is implemented for every type that can be folded.
/// Basically, every type that has a corresponding method in TypeFolder.
///
/// To implement this conveniently, use the
/// `BraceStructTypeFoldableImpl` etc macros found in `macros.rs`.
pub trait TypeFoldable<'tcx>: fmt::Debug + Clone {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self;
fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
+12 -4
View File
@@ -51,7 +51,11 @@ pub fn ty(&self,
-> Ty<'tcx>
{
let ty = tcx.type_of(self.def.def_id());
tcx.trans_apply_param_substs(self.substs, &ty)
tcx.subst_and_normalize_erasing_regions(
self.substs,
ty::ParamEnv::reveal_all(),
&ty,
)
}
}
@@ -184,7 +188,11 @@ pub fn resolve(tcx: TyCtxt<'a, 'tcx, 'tcx>,
resolve_associated_item(tcx, &item, param_env, trait_def_id, substs)
} else {
let ty = tcx.type_of(def_id);
let item_type = tcx.trans_apply_param_substs_env(substs, param_env, &ty);
let item_type = tcx.subst_and_normalize_erasing_regions(
substs,
param_env,
&ty,
);
let def = match item_type.sty {
ty::TyFnDef(..) if {
@@ -199,7 +207,7 @@ pub fn resolve(tcx: TyCtxt<'a, 'tcx, 'tcx>,
_ => {
if Some(def_id) == tcx.lang_items().drop_in_place_fn() {
let ty = substs.type_at(0);
if ty.needs_drop(tcx, ty::ParamEnv::empty(traits::Reveal::All)) {
if ty.needs_drop(tcx, ty::ParamEnv::reveal_all()) {
debug!(" => nontrivial drop glue");
ty::InstanceDef::DropGlue(def_id, Some(ty))
} else {
@@ -352,7 +360,7 @@ fn fn_once_adapter_instance<'a, 'tcx>(
closure_did, substs);
let sig = substs.closure_sig(closure_did, tcx);
let sig = tcx.erase_late_bound_regions_and_normalize(&sig);
let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
assert_eq!(sig.inputs().len(), 1);
let substs = tcx.mk_substs([Kind::from(self_ty), sig.inputs()[0].into()].iter().cloned());
+9 -9
View File
@@ -1213,7 +1213,7 @@ enum StructKind {
data_ptr.valid_range.start = 1;
}
let pointee = tcx.normalize_associated_type_in_env(&pointee, param_env);
let pointee = tcx.normalize_erasing_regions(param_env, pointee);
if pointee.is_sized(tcx.at(DUMMY_SP), param_env) {
return Ok(tcx.intern_layout(LayoutDetails::scalar(self, data_ptr)));
}
@@ -1241,7 +1241,7 @@ enum StructKind {
// Arrays and slices.
ty::TyArray(element, mut count) => {
if count.has_projections() {
count = tcx.normalize_associated_type_in_env(&count, param_env);
count = tcx.normalize_erasing_regions(param_env, count);
if count.has_projections() {
return Err(LayoutError::Unknown(ty));
}
@@ -1686,7 +1686,7 @@ enum StructKind {
// Types with no meaningful known layout.
ty::TyProjection(_) | ty::TyAnon(..) => {
let normalized = tcx.normalize_associated_type_in_env(&ty, param_env);
let normalized = tcx.normalize_erasing_regions(param_env, ty);
if ty == normalized {
return Err(LayoutError::Unknown(ty));
}
@@ -1953,7 +1953,7 @@ pub fn compute(ty: Ty<'tcx>,
}
ty::TyProjection(_) | ty::TyAnon(..) => {
let normalized = tcx.normalize_associated_type_in_env(&ty, param_env);
let normalized = tcx.normalize_erasing_regions(param_env, ty);
if ty == normalized {
Err(err)
} else {
@@ -2058,8 +2058,8 @@ impl<'a, 'tcx> LayoutOf<Ty<'tcx>> for LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> {
/// Computes the layout of a type. Note that this implicitly
/// executes in "reveal all" mode.
fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
let param_env = self.param_env.reveal_all();
let ty = self.tcx.normalize_associated_type_in_env(&ty, param_env);
let param_env = self.param_env.with_reveal_all();
let ty = self.tcx.normalize_erasing_regions(param_env, ty);
let details = self.tcx.layout_raw(param_env.and(ty))?;
let layout = TyLayout {
ty,
@@ -2084,9 +2084,9 @@ impl<'a, 'tcx> LayoutOf<Ty<'tcx>> for LayoutCx<'tcx, ty::maps::TyCtxtAt<'a, 'tcx
/// Computes the layout of a type. Note that this implicitly
/// executes in "reveal all" mode.
fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
let param_env = self.param_env.reveal_all();
let ty = self.tcx.normalize_associated_type_in_env(&ty, param_env.reveal_all());
let details = self.tcx.layout_raw(param_env.reveal_all().and(ty))?;
let param_env = self.param_env.with_reveal_all();
let ty = self.tcx.normalize_erasing_regions(param_env, ty);
let details = self.tcx.layout_raw(param_env.and(ty))?;
let layout = TyLayout {
ty,
details
+23 -7
View File
@@ -11,7 +11,8 @@
use dep_graph::SerializedDepNodeIndex;
use hir::def_id::{CrateNum, DefId, DefIndex};
use mir::interpret::{GlobalId};
use ty::{self, Ty, TyCtxt};
use traits::query::{CanonicalProjectionGoal, CanonicalTyGoal};
use ty::{self, ParamEnvAnd, Ty, TyCtxt};
use ty::subst::Substs;
use ty::maps::queries;
@@ -51,6 +52,27 @@ impl<'tcx, M: QueryConfig<Key=DefId>> QueryDescription<'tcx> for M {
}
}
impl<'tcx> QueryDescription<'tcx> for queries::normalize_projection_ty<'tcx> {
fn describe(
_tcx: TyCtxt,
goal: CanonicalProjectionGoal<'tcx>,
) -> String {
format!("normalizing `{:?}`", goal)
}
}
impl<'tcx> QueryDescription<'tcx> for queries::dropck_outlives<'tcx> {
fn describe(_tcx: TyCtxt, goal: CanonicalTyGoal<'tcx>) -> String {
format!("computing dropck types for `{:?}`", goal)
}
}
impl<'tcx> QueryDescription<'tcx> for queries::normalize_ty_after_erasing_regions<'tcx> {
fn describe(_tcx: TyCtxt, goal: ParamEnvAnd<'tcx, Ty<'tcx>>) -> String {
format!("normalizing `{:?}`", goal)
}
}
impl<'tcx> QueryDescription<'tcx> for queries::is_copy_raw<'tcx> {
fn describe(_tcx: TyCtxt, env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> String {
format!("computing whether `{}` is `Copy`", env.value)
@@ -588,12 +610,6 @@ fn describe(_tcx: TyCtxt, _: CrateNum) -> String {
}
}
impl<'tcx> QueryDescription<'tcx> for queries::fully_normalize_monormophic_ty<'tcx> {
fn describe(_tcx: TyCtxt, _: Ty) -> String {
format!("normalizing types")
}
}
impl<'tcx> QueryDescription<'tcx> for queries::features_query<'tcx> {
fn describe(_tcx: TyCtxt, _: CrateNum) -> String {
format!("looking up enabled feature gates")
+21
View File
@@ -11,6 +11,7 @@
//! Defines the set of legal keys that can be used in queries.
use hir::def_id::{CrateNum, DefId, LOCAL_CRATE, DefIndex};
use traits::query::{CanonicalProjectionGoal, CanonicalTyGoal};
use ty::{self, Ty, TyCtxt};
use ty::subst::Substs;
use ty::fast_reject::SimplifiedType;
@@ -170,3 +171,23 @@ fn default_span(&self, _tcx: TyCtxt) -> Span {
DUMMY_SP
}
}
impl<'tcx> Key for CanonicalProjectionGoal<'tcx> {
fn map_crate(&self) -> CrateNum {
LOCAL_CRATE
}
fn default_span(&self, _tcx: TyCtxt) -> Span {
DUMMY_SP
}
}
impl<'tcx> Key for CanonicalTyGoal<'tcx> {
fn map_crate(&self) -> CrateNum {
LOCAL_CRATE
}
fn default_span(&self, _tcx: TyCtxt) -> Span {
DUMMY_SP
}
}
+29 -6
View File
@@ -14,6 +14,7 @@
use hir::def::{Def, Export};
use hir::{self, TraitCandidate, ItemLocalId, TransFnAttrs};
use hir::svh::Svh;
use infer::canonical::{Canonical, QueryResult};
use lint;
use middle::borrowck::BorrowCheckResult;
use middle::cstore::{ExternCrate, LinkagePreference, NativeLibrary,
@@ -33,8 +34,11 @@
use session::{CompileResult, CrateDisambiguator};
use session::config::OutputFilenames;
use traits::Vtable;
use traits::query::{CanonicalProjectionGoal, CanonicalTyGoal, NoSolution};
use traits::query::dropck_outlives::{DtorckConstraint, DropckOutlivesResult};
use traits::query::normalize::NormalizationResult;
use traits::specialization_graph;
use ty::{self, CrateInherentImpls, Ty, TyCtxt};
use ty::{self, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt};
use ty::steal::Steal;
use ty::subst::Substs;
use util::nodemap::{DefIdSet, DefIdMap, ItemLocalSet};
@@ -111,7 +115,9 @@
[] fn adt_def: AdtDefOfItem(DefId) -> &'tcx ty::AdtDef,
[] fn adt_destructor: AdtDestructor(DefId) -> Option<ty::Destructor>,
[] fn adt_sized_constraint: SizedConstraint(DefId) -> &'tcx [Ty<'tcx>],
[] fn adt_dtorck_constraint: DtorckConstraint(DefId) -> ty::DtorckConstraint<'tcx>,
[] fn adt_dtorck_constraint: DtorckConstraint(
DefId
) -> Result<DtorckConstraint<'tcx>, NoSolution>,
/// True if this is a const fn
[] fn is_const_fn: IsConstFn(DefId) -> bool,
@@ -378,7 +384,27 @@
// Normally you would just use `tcx.erase_regions(&value)`,
// however, which uses this query as a kind of cache.
[] fn erase_regions_ty: erase_regions_ty(Ty<'tcx>) -> Ty<'tcx>,
[] fn fully_normalize_monormophic_ty: normalize_ty_node(Ty<'tcx>) -> Ty<'tcx>,
/// Do not call this query directly: invoke `normalize` instead.
[] fn normalize_projection_ty: NormalizeProjectionTy(
CanonicalProjectionGoal<'tcx>
) -> Result<
Lrc<Canonical<'tcx, QueryResult<'tcx, NormalizationResult<'tcx>>>>,
NoSolution,
>,
/// Do not call this query directly: invoke `normalize_erasing_regions` instead.
[] fn normalize_ty_after_erasing_regions: NormalizeTyAfterErasingRegions(
ParamEnvAnd<'tcx, Ty<'tcx>>
) -> Ty<'tcx>,
/// Do not call this query directly: invoke `infcx.at().dropck_outlives()` instead.
[] fn dropck_outlives: DropckOutlives(
CanonicalTyGoal<'tcx>
) -> Result<
Lrc<Canonical<'tcx, QueryResult<'tcx, DropckOutlivesResult<'tcx>>>>,
NoSolution,
>,
[] fn substitute_normalize_and_test_predicates:
substitute_normalize_and_test_predicates_node((DefId, &'tcx Substs<'tcx>)) -> bool,
@@ -537,9 +563,6 @@ fn output_filenames_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> {
fn vtable_methods_node<'tcx>(trait_ref: ty::PolyTraitRef<'tcx>) -> DepConstructor<'tcx> {
DepConstructor::VtableMethods{ trait_ref }
}
fn normalize_ty_node<'tcx>(_: Ty<'tcx>) -> DepConstructor<'tcx> {
DepConstructor::NormalizeTy
}
fn substitute_normalize_and_test_predicates_node<'tcx>(key: (DefId, &'tcx Substs<'tcx>))
-> DepConstructor<'tcx> {
+3 -1
View File
@@ -772,7 +772,9 @@ macro_rules! force {
DepKind::FulfillObligation |
DepKind::VtableMethods |
DepKind::EraseRegionsTy |
DepKind::NormalizeTy |
DepKind::NormalizeProjectionTy |
DepKind::NormalizeTyAfterErasingRegions |
DepKind::DropckOutlives |
DepKind::SubstituteNormalizeAndTestPredicates |
DepKind::InstanceDefSizeEstimate |
-6
View File
@@ -35,12 +35,6 @@ fn from_cycle_error<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Ty<'tcx> {
}
}
impl<'tcx> Value<'tcx> for ty::DtorckConstraint<'tcx> {
fn from_cycle_error<'a>(_: TyCtxt<'a, 'tcx, 'tcx>) -> Self {
Self::empty()
}
}
impl<'tcx> Value<'tcx> for ty::SymbolName {
fn from_cycle_error<'a>(_: TyCtxt<'a, 'tcx, 'tcx>) -> Self {
ty::SymbolName { name: Symbol::intern("<error>").as_str() }
+81 -105
View File
@@ -29,20 +29,18 @@
use mir::interpret::{GlobalId, Value, PrimVal};
use mir::GeneratorLayout;
use session::CrateDisambiguator;
use traits;
use traits::{self, Reveal};
use ty;
use ty::subst::{Subst, Substs};
use ty::util::{IntTypeExt, Discr};
use ty::walk::TypeWalker;
use util::common::ErrorReported;
use util::nodemap::{NodeSet, DefIdMap, FxHashMap, FxHashSet};
use util::nodemap::{NodeSet, DefIdMap, FxHashMap};
use serialize::{self, Encodable, Encoder};
use std::cell::RefCell;
use std::cmp;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::iter::FromIterator;
use std::ops::Deref;
use rustc_data_structures::sync::Lrc;
use std::slice;
@@ -60,7 +58,7 @@
use hir;
pub use self::sty::{Binder, DebruijnIndex};
pub use self::sty::{Binder, CanonicalVar, DebruijnIndex};
pub use self::sty::{FnSig, GenSig, PolyFnSig, PolyGenSig};
pub use self::sty::{InferTy, ParamTy, ProjectionTy, ExistentialPredicate};
pub use self::sty::{ClosureSubsts, GeneratorInterior, TypeAndMut};
@@ -452,6 +450,10 @@ pub struct TypeFlags: u32 {
// Currently we can't normalize projections w/ bound regions.
const HAS_NORMALIZABLE_PROJECTION = 1 << 12;
// Set if this includes a "canonical" type or region var --
// ought to be true only for the results of canonicalization.
const HAS_CANONICAL_VARS = 1 << 13;
const NEEDS_SUBST = TypeFlags::HAS_PARAMS.bits |
TypeFlags::HAS_SELF.bits |
TypeFlags::HAS_RE_EARLY_BOUND.bits;
@@ -470,7 +472,8 @@ pub struct TypeFlags: u32 {
TypeFlags::HAS_PROJECTION.bits |
TypeFlags::HAS_TY_CLOSURE.bits |
TypeFlags::HAS_LOCAL_NAMES.bits |
TypeFlags::KEEP_IN_LOCAL_TCX.bits;
TypeFlags::KEEP_IN_LOCAL_TCX.bits |
TypeFlags::HAS_CANONICAL_VARS.bits;
}
}
@@ -1396,32 +1399,81 @@ pub struct ParamEnv<'tcx> {
}
impl<'tcx> ParamEnv<'tcx> {
/// Creates a suitable environment in which to perform trait
/// queries on the given value. This will either be `self` *or*
/// the empty environment, depending on whether `value` references
/// type parameters that are in scope. (If it doesn't, then any
/// judgements should be completely independent of the context,
/// and hence we can safely use the empty environment so as to
/// enable more sharing across functions.)
/// Construct a trait environment suitable for contexts where
/// there are no where clauses in scope. Hidden types (like `impl
/// Trait`) are left hidden, so this is suitable for ordinary
/// type-checking.
pub fn empty() -> Self {
Self::new(ty::Slice::empty(), Reveal::UserFacing, ty::UniverseIndex::ROOT)
}
/// Construct a trait environment with no where clauses in scope
/// where the values of all `impl Trait` and other hidden types
/// are revealed. This is suitable for monomorphized, post-typeck
/// environments like trans or doing optimizations.
///
/// NB: This is a mildly dubious thing to do, in that a function
/// (or other environment) might have wacky where-clauses like
/// NB. If you want to have predicates in scope, use `ParamEnv::new`,
/// or invoke `param_env.with_reveal_all()`.
pub fn reveal_all() -> Self {
Self::new(ty::Slice::empty(), Reveal::All, ty::UniverseIndex::ROOT)
}
/// Construct a trait environment with the given set of predicates.
pub fn new(caller_bounds: &'tcx ty::Slice<ty::Predicate<'tcx>>,
reveal: Reveal,
universe: ty::UniverseIndex)
-> Self {
ty::ParamEnv { caller_bounds, reveal, universe }
}
/// Returns a new parameter environment with the same clauses, but
/// which "reveals" the true results of projections in all cases
/// (even for associated types that are specializable). This is
/// the desired behavior during trans and certain other special
/// contexts; normally though we want to use `Reveal::UserFacing`,
/// which is the default.
pub fn with_reveal_all(self) -> Self {
ty::ParamEnv { reveal: Reveal::All, ..self }
}
/// Returns this same environment but with no caller bounds.
pub fn without_caller_bounds(self) -> Self {
ty::ParamEnv { caller_bounds: ty::Slice::empty(), ..self }
}
/// Creates a suitable environment in which to perform trait
/// queries on the given value. When type-checking, this is simply
/// the pair of the environment plus value. But when reveal is set to
/// All, then if `value` does not reference any type parameters, we will
/// pair it with the empty environment. This improves caching and is generally
/// invisible.
///
/// NB: We preserve the environment when type-checking because it
/// is possible for the user to have wacky where-clauses like
/// `where Box<u32>: Copy`, which are clearly never
/// satisfiable. The code will at present ignore these,
/// effectively, when type-checking the body of said
/// function. This preserves existing behavior in any
/// case. --nmatsakis
/// satisfiable. We generally want to behave as if they were true,
/// although the surrounding function is never reachable.
pub fn and<T: TypeFoldable<'tcx>>(self, value: T) -> ParamEnvAnd<'tcx, T> {
assert!(!value.needs_infer());
if value.has_param_types() || value.has_self_ty() {
ParamEnvAnd {
param_env: self,
value,
match self.reveal {
Reveal::UserFacing => {
ParamEnvAnd {
param_env: self,
value,
}
}
} else {
ParamEnvAnd {
param_env: ParamEnv::empty(self.reveal),
value,
Reveal::All => {
if value.needs_infer() || value.has_param_types() || value.has_self_ty() {
ParamEnvAnd {
param_env: self,
value,
}
} else {
ParamEnvAnd {
param_env: self.without_caller_bounds(),
value,
}
}
}
}
}
@@ -1829,7 +1881,7 @@ pub fn eval_explicit_discr(
tcx: TyCtxt<'a, 'gcx, 'tcx>,
expr_did: DefId,
) -> Option<Discr<'tcx>> {
let param_env = ParamEnv::empty(traits::Reveal::UserFacing);
let param_env = ParamEnv::empty();
let repr_type = self.repr.discr_type();
let bit_size = layout::Integer::from_attr(tcx, repr_type).size().bits();
let substs = Substs::identity_for_item(tcx.global_tcx(), expr_did);
@@ -2607,38 +2659,6 @@ fn adt_sized_constraint<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
result
}
/// Calculates the dtorck constraint for a type.
fn adt_dtorck_constraint<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId)
-> DtorckConstraint<'tcx> {
let def = tcx.adt_def(def_id);
let span = tcx.def_span(def_id);
debug!("dtorck_constraint: {:?}", def);
if def.is_phantom_data() {
let result = DtorckConstraint {
outlives: vec![],
dtorck_types: vec![
tcx.mk_param_from_def(&tcx.generics_of(def_id).types[0])
]
};
debug!("dtorck_constraint: {:?} => {:?}", def, result);
return result;
}
let mut result = def.all_fields()
.map(|field| tcx.type_of(field.did))
.map(|fty| tcx.dtorck_constraint_for_ty(span, fty, 0, fty))
.collect::<Result<DtorckConstraint, ErrorReported>>()
.unwrap_or(DtorckConstraint::empty());
result.outlives.extend(tcx.destructor_constraints(def));
result.dedup();
debug!("dtorck_constraint: {:?} => {:?}", def, result);
result
}
fn associated_item_def_ids<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId)
-> Lrc<Vec<DefId>> {
@@ -2754,7 +2774,6 @@ pub fn provide(providers: &mut ty::maps::Providers) {
associated_item,
associated_item_def_ids,
adt_sized_constraint,
adt_dtorck_constraint,
def_span,
param_env,
trait_of_item,
@@ -2777,49 +2796,6 @@ pub struct CrateInherentImpls {
pub inherent_impls: DefIdMap<Lrc<Vec<DefId>>>,
}
/// A set of constraints that need to be satisfied in order for
/// a type to be valid for destruction.
#[derive(Clone, Debug)]
pub struct DtorckConstraint<'tcx> {
/// Types that are required to be alive in order for this
/// type to be valid for destruction.
pub outlives: Vec<ty::subst::Kind<'tcx>>,
/// Types that could not be resolved: projections and params.
pub dtorck_types: Vec<Ty<'tcx>>,
}
impl<'tcx> FromIterator<DtorckConstraint<'tcx>> for DtorckConstraint<'tcx>
{
fn from_iter<I: IntoIterator<Item=DtorckConstraint<'tcx>>>(iter: I) -> Self {
let mut result = Self::empty();
for constraint in iter {
result.outlives.extend(constraint.outlives);
result.dtorck_types.extend(constraint.dtorck_types);
}
result
}
}
impl<'tcx> DtorckConstraint<'tcx> {
fn empty() -> DtorckConstraint<'tcx> {
DtorckConstraint {
outlives: vec![],
dtorck_types: vec![]
}
}
fn dedup<'a>(&mut self) {
let mut outlives = FxHashSet();
let mut dtorck_types = FxHashSet();
self.outlives.retain(|&val| outlives.replace(val).is_none());
self.dtorck_types.retain(|&val| dtorck_types.replace(val).is_none());
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, RustcEncodable, RustcDecodable)]
pub struct SymbolName {
// FIXME: we don't rely on interning or equality here - better have
+27 -20
View File
@@ -15,10 +15,8 @@
use hir::def_id::DefId;
use middle::const_val::ConstVal;
use traits::Reveal;
use ty::subst::{UnpackedKind, Substs};
use ty::subst::{Kind, UnpackedKind, Substs};
use ty::{self, Ty, TyCtxt, TypeFoldable};
use ty::fold::{TypeVisitor, TypeFolder};
use ty::error::{ExpectedFound, TypeError};
use mir::interpret::{GlobalId, Value, PrimVal};
use util::common::ErrorReported;
@@ -143,15 +141,7 @@ pub fn relate_substs<'a, 'gcx, 'tcx, R>(relation: &mut R,
let params = a_subst.iter().zip(b_subst).enumerate().map(|(i, (a, b))| {
let variance = variances.map_or(ty::Invariant, |v| v[i]);
match (a.unpack(), b.unpack()) {
(UnpackedKind::Lifetime(a_lt), UnpackedKind::Lifetime(b_lt)) => {
Ok(relation.relate_with_variance(variance, &a_lt, &b_lt)?.into())
}
(UnpackedKind::Type(a_ty), UnpackedKind::Type(b_ty)) => {
Ok(relation.relate_with_variance(variance, &a_ty, &b_ty)?.into())
}
(UnpackedKind::Lifetime(_), _) | (UnpackedKind::Type(_), _) => bug!()
}
relation.relate_with_variance(variance, a, b)
});
Ok(tcx.mk_substs(params)?)
@@ -326,13 +316,9 @@ fn relate<'a, 'gcx, R>(relation: &mut R,
#[derive(Debug, Clone)]
struct GeneratorWitness<'tcx>(&'tcx ty::Slice<Ty<'tcx>>);
impl<'tcx> TypeFoldable<'tcx> for GeneratorWitness<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
GeneratorWitness(self.0.fold_with(folder))
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
self.0.visit_with(visitor)
TupleStructTypeFoldableImpl! {
impl<'tcx> TypeFoldable<'tcx> for GeneratorWitness<'tcx> {
a
}
}
@@ -486,7 +472,7 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R,
ConstVal::Value(Value::ByVal(prim)) => Ok(prim.to_u64().unwrap()),
ConstVal::Unevaluated(def_id, substs) => {
// FIXME(eddyb) get the right param_env.
let param_env = ty::ParamEnv::empty(Reveal::UserFacing);
let param_env = ty::ParamEnv::empty();
match tcx.lift_to_global(&substs) {
Some(substs) => {
let instance = ty::Instance::resolve(
@@ -698,6 +684,27 @@ fn relate<'a, 'gcx, R>(relation: &mut R,
}
}
impl<'tcx> Relate<'tcx> for Kind<'tcx> {
fn relate<'a, 'gcx, R>(
relation: &mut R,
a: &Kind<'tcx>,
b: &Kind<'tcx>
) -> RelateResult<'tcx, Kind<'tcx>>
where
R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a,
{
match (a.unpack(), b.unpack()) {
(UnpackedKind::Lifetime(a_lt), UnpackedKind::Lifetime(b_lt)) => {
Ok(relation.relate(&a_lt, &b_lt)?.into())
}
(UnpackedKind::Type(a_ty), UnpackedKind::Type(b_ty)) => {
Ok(relation.relate(&a_ty, &b_ty)?.into())
}
(UnpackedKind::Lifetime(_), _) | (UnpackedKind::Type(_), _) => bug!()
}
}
}
///////////////////////////////////////////////////////////////////////////
// Error handling
+128 -415
View File
@@ -28,153 +28,37 @@
// For things that don't carry any arena-allocated data (and are
// copy...), just add them to this list.
macro_rules! CopyImpls {
($($ty:ty,)+) => {
$(
impl<'tcx> Lift<'tcx> for $ty {
type Lifted = Self;
fn lift_to_tcx<'a, 'gcx>(&self, _: TyCtxt<'a, 'gcx, 'tcx>) -> Option<Self> {
Some(*self)
}
}
impl<'tcx> TypeFoldable<'tcx> for $ty {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, _: &mut F) -> $ty {
*self
}
fn super_visit_with<F: TypeVisitor<'tcx>>(&self, _: &mut F) -> bool {
false
}
}
)+
}
}
CopyImpls! {
CloneTypeFoldableAndLiftImpls! {
(),
bool,
usize,
u64,
::middle::region::Scope,
::syntax::ast::FloatTy,
::syntax::ast::NodeId,
::syntax_pos::symbol::Symbol,
::hir::def::Def,
::hir::def_id::DefId,
::hir::InlineAsm,
::hir::MatchSource,
::hir::Mutability,
::hir::Unsafety,
::syntax::abi::Abi,
::hir::def_id::DefId,
::mir::Local,
::mir::Promoted,
::traits::Reveal,
::ty::adjustment::AutoBorrowMutability,
::ty::AdtKind,
// Including `BoundRegion` is a *bit* dubious, but direct
// references to bound region appear in `ty::Error`, and aren't
// really meant to be folded. In general, we can only fold a fully
// general `Region`.
::ty::BoundRegion,
::ty::ClosureKind,
::ty::IntVarValue,
::syntax_pos::Span,
}
///////////////////////////////////////////////////////////////////////////
// Macros
//
// When possible, use one of these (relatively) convenient macros to write
// the impls for you.
#[macro_export]
macro_rules! BraceStructLiftImpl {
(impl<$($p:tt),*> Lift<$tcx:tt> for $s:path {
type Lifted = $lifted:ty;
$($field:ident),* $(,)*
} $(where $($wc:tt)*)*) => {
impl<$($p),*> $crate::ty::Lift<$tcx> for $s
$(where $($wc)*)*
{
type Lifted = $lifted;
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<$lifted> {
$(let $field = tcx.lift(&self.$field)?;)*
Some(Self::Lifted { $($field),* })
}
}
};
}
#[macro_export]
macro_rules! EnumLiftImpl {
(impl<$($p:tt),*> Lift<$tcx:tt> for $s:path {
type Lifted = $lifted:ty;
$(
($variant:path) ( $( $variant_arg:ident),* )
),*
$(,)*
} $(where $($wc:tt)*)*) => {
impl<$($p),*> $crate::ty::Lift<$tcx> for $s
$(where $($wc)*)*
{
type Lifted = $lifted;
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<$lifted> {
match self {
$($variant ( $($variant_arg),* ) => {
Some($variant ( $(tcx.lift($variant_arg)?),* ))
})*
}
}
}
};
}
#[macro_export]
macro_rules! BraceStructTypeFoldableImpl {
(impl<$($p:tt),*> TypeFoldable<$tcx:tt> for $s:path {
$($field:ident),* $(,)*
} $(where $($wc:tt)*)*) => {
impl<$($p),*> $crate::ty::fold::TypeFoldable<$tcx> for $s
$(where $($wc)*)*
{
fn super_fold_with<'gcx: $tcx, V: $crate::ty::fold::TypeFolder<'gcx, $tcx>>(
&self,
folder: &mut V,
) -> Self {
let $s { $($field,)* } = self;
$s { $($field: $field.fold_with(folder),)* }
}
fn super_visit_with<V: $crate::ty::fold::TypeVisitor<$tcx>>(
&self,
visitor: &mut V,
) -> bool {
let $s { $($field,)* } = self;
false $(|| $field.visit_with(visitor))*
}
}
};
}
#[macro_export]
macro_rules! EnumTypeFoldableImpl {
(impl<$($p:tt),*> TypeFoldable<$tcx:tt> for $s:path {
$(
($variant:path) ( $( $variant_arg:ident),* )
),*
$(,)*
} $(where $($wc:tt)*)*) => {
impl<$($p),*> $crate::ty::fold::TypeFoldable<$tcx> for $s
$(where $($wc)*)*
{
fn super_fold_with<'gcx: $tcx, V: $crate::ty::fold::TypeFolder<'gcx, $tcx>>(
&self,
folder: &mut V,
) -> Self {
match self {
$($variant ( $($variant_arg),* ) => {
$variant ( $($variant_arg.fold_with(folder)),* )
})*
}
}
fn super_visit_with<V: $crate::ty::fold::TypeVisitor<$tcx>>(
&self,
visitor: &mut V,
) -> bool {
match self {
$($variant ( $($variant_arg),* ) => {
false $(|| $variant_arg.visit_with(visitor))*
})*
}
}
}
};
}
///////////////////////////////////////////////////////////////////////////
// Lift implementations
@@ -776,6 +660,17 @@ impl<'a, 'tcx> Lift<'tcx> for interpret::GlobalId<'a> {
// can easily refactor the folding into the TypeFolder trait as
// needed.
/// AdtDefs are basically the same as a DefId.
impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::AdtDef {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, _folder: &mut F) -> Self {
*self
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> bool {
false
}
}
impl<'tcx, T:TypeFoldable<'tcx>, U:TypeFoldable<'tcx>> TypeFoldable<'tcx> for (T, U) {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> (T, U) {
(self.0.fold_with(folder), self.1.fold_with(folder))
@@ -786,14 +681,11 @@ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
}
}
impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Option<T> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
self.as_ref().map(|t| t.fold_with(folder))
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
self.iter().any(|t| t.visit_with(visitor))
}
EnumTypeFoldableImpl! {
impl<'tcx, T> TypeFoldable<'tcx> for Option<T> {
(Some)(a),
(None),
} where T: TypeFoldable<'tcx>
}
impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Rc<T> {
@@ -881,22 +773,11 @@ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
}
}
impl<'tcx> TypeFoldable<'tcx> for ty::ExistentialPredicate<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
use ty::ExistentialPredicate::*;
match *self {
Trait(ref tr) => Trait(tr.fold_with(folder)),
Projection(ref p) => Projection(p.fold_with(folder)),
AutoTrait(did) => AutoTrait(did),
}
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
match *self {
ty::ExistentialPredicate::Trait(ref tr) => tr.visit_with(visitor),
ty::ExistentialPredicate::Projection(ref p) => p.visit_with(visitor),
ty::ExistentialPredicate::AutoTrait(_) => false,
}
EnumTypeFoldableImpl! {
impl<'tcx> TypeFoldable<'tcx> for ty::ExistentialPredicate<'tcx> {
(ty::ExistentialPredicate::Trait)(a),
(ty::ExistentialPredicate::Projection)(a),
(ty::ExistentialPredicate::AutoTrait)(a),
}
}
@@ -1049,13 +930,9 @@ fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
}
}
impl<'tcx> TypeFoldable<'tcx> for ty::TypeAndMut<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
ty::TypeAndMut { ty: self.ty.fold_with(folder), mutbl: self.mutbl }
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
self.ty.visit_with(visitor)
BraceStructTypeFoldableImpl! {
impl<'tcx> TypeFoldable<'tcx> for ty::TypeAndMut<'tcx> {
ty, mutbl
}
}
@@ -1065,20 +942,9 @@ impl<'tcx> TypeFoldable<'tcx> for ty::GenSig<'tcx> {
}
}
impl<'tcx> TypeFoldable<'tcx> for ty::FnSig<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
let inputs_and_output = self.inputs_and_output.fold_with(folder);
ty::FnSig {
inputs_and_output: folder.tcx().intern_type_list(&inputs_and_output),
variadic: self.variadic,
unsafety: self.unsafety,
abi: self.abi,
}
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
self.inputs().iter().any(|i| i.visit_with(visitor)) ||
self.output().visit_with(visitor)
BraceStructTypeFoldableImpl! {
impl<'tcx> TypeFoldable<'tcx> for ty::FnSig<'tcx> {
inputs_and_output, variadic, unsafety, abi
}
}
@@ -1117,28 +983,15 @@ fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
}
}
impl<'tcx> TypeFoldable<'tcx> for ty::ClosureSubsts<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
ty::ClosureSubsts {
substs: self.substs.fold_with(folder),
}
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
self.substs.visit_with(visitor)
BraceStructTypeFoldableImpl! {
impl<'tcx> TypeFoldable<'tcx> for ty::ClosureSubsts<'tcx> {
substs,
}
}
impl<'tcx> TypeFoldable<'tcx> for ty::GeneratorInterior<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
ty::GeneratorInterior {
witness: self.witness.fold_with(folder),
movable: self.movable,
}
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
self.witness.visit_with(visitor)
BraceStructTypeFoldableImpl! {
impl<'tcx> TypeFoldable<'tcx> for ty::GeneratorInterior<'tcx> {
witness, movable,
}
}
@@ -1149,74 +1002,32 @@ impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::Adjustment<'tcx> {
}
}
impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::Adjust<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
match *self {
ty::adjustment::Adjust::NeverToAny |
ty::adjustment::Adjust::ReifyFnPointer |
ty::adjustment::Adjust::UnsafeFnPointer |
ty::adjustment::Adjust::ClosureFnPointer |
ty::adjustment::Adjust::MutToConstPointer |
ty::adjustment::Adjust::Unsize => self.clone(),
ty::adjustment::Adjust::Deref(ref overloaded) => {
ty::adjustment::Adjust::Deref(overloaded.fold_with(folder))
}
ty::adjustment::Adjust::Borrow(ref autoref) => {
ty::adjustment::Adjust::Borrow(autoref.fold_with(folder))
}
}
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
match *self {
ty::adjustment::Adjust::NeverToAny |
ty::adjustment::Adjust::ReifyFnPointer |
ty::adjustment::Adjust::UnsafeFnPointer |
ty::adjustment::Adjust::ClosureFnPointer |
ty::adjustment::Adjust::MutToConstPointer |
ty::adjustment::Adjust::Unsize => false,
ty::adjustment::Adjust::Deref(ref overloaded) => {
overloaded.visit_with(visitor)
}
ty::adjustment::Adjust::Borrow(ref autoref) => {
autoref.visit_with(visitor)
}
}
EnumTypeFoldableImpl! {
impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::Adjust<'tcx> {
(ty::adjustment::Adjust::NeverToAny),
(ty::adjustment::Adjust::ReifyFnPointer),
(ty::adjustment::Adjust::UnsafeFnPointer),
(ty::adjustment::Adjust::ClosureFnPointer),
(ty::adjustment::Adjust::MutToConstPointer),
(ty::adjustment::Adjust::Unsize),
(ty::adjustment::Adjust::Deref)(a),
(ty::adjustment::Adjust::Borrow)(a),
}
}
impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::OverloadedDeref<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
ty::adjustment::OverloadedDeref {
region: self.region.fold_with(folder),
mutbl: self.mutbl,
}
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
self.region.visit_with(visitor)
BraceStructTypeFoldableImpl! {
impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::OverloadedDeref<'tcx> {
region, mutbl,
}
}
impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::AutoBorrow<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
match *self {
ty::adjustment::AutoBorrow::Ref(ref r, m) => {
ty::adjustment::AutoBorrow::Ref(r.fold_with(folder), m)
}
ty::adjustment::AutoBorrow::RawPtr(m) => ty::adjustment::AutoBorrow::RawPtr(m)
}
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
match *self {
ty::adjustment::AutoBorrow::Ref(r, _m) => r.visit_with(visitor),
ty::adjustment::AutoBorrow::RawPtr(_m) => false,
}
EnumTypeFoldableImpl! {
impl<'tcx> TypeFoldable<'tcx> for ty::adjustment::AutoBorrow<'tcx> {
(ty::adjustment::AutoBorrow::Ref)(a, b),
(ty::adjustment::AutoBorrow::RawPtr)(m),
}
}
BraceStructTypeFoldableImpl! {
impl<'tcx> TypeFoldable<'tcx> for ty::GenericPredicates<'tcx> {
parent, predicates
@@ -1234,43 +1045,17 @@ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
}
}
impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
match *self {
ty::Predicate::Trait(ref a) =>
ty::Predicate::Trait(a.fold_with(folder)),
ty::Predicate::Subtype(ref binder) =>
ty::Predicate::Subtype(binder.fold_with(folder)),
ty::Predicate::RegionOutlives(ref binder) =>
ty::Predicate::RegionOutlives(binder.fold_with(folder)),
ty::Predicate::TypeOutlives(ref binder) =>
ty::Predicate::TypeOutlives(binder.fold_with(folder)),
ty::Predicate::Projection(ref binder) =>
ty::Predicate::Projection(binder.fold_with(folder)),
ty::Predicate::WellFormed(data) =>
ty::Predicate::WellFormed(data.fold_with(folder)),
ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) =>
ty::Predicate::ClosureKind(closure_def_id, closure_substs.fold_with(folder), kind),
ty::Predicate::ObjectSafe(trait_def_id) =>
ty::Predicate::ObjectSafe(trait_def_id),
ty::Predicate::ConstEvaluatable(def_id, substs) =>
ty::Predicate::ConstEvaluatable(def_id, substs.fold_with(folder)),
}
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
match *self {
ty::Predicate::Trait(ref a) => a.visit_with(visitor),
ty::Predicate::Subtype(ref binder) => binder.visit_with(visitor),
ty::Predicate::RegionOutlives(ref binder) => binder.visit_with(visitor),
ty::Predicate::TypeOutlives(ref binder) => binder.visit_with(visitor),
ty::Predicate::Projection(ref binder) => binder.visit_with(visitor),
ty::Predicate::WellFormed(data) => data.visit_with(visitor),
ty::Predicate::ClosureKind(_closure_def_id, closure_substs, _kind) =>
closure_substs.visit_with(visitor),
ty::Predicate::ObjectSafe(_trait_def_id) => false,
ty::Predicate::ConstEvaluatable(_def_id, substs) => substs.visit_with(visitor),
}
EnumTypeFoldableImpl! {
impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> {
(ty::Predicate::Trait)(a),
(ty::Predicate::Subtype)(a),
(ty::Predicate::RegionOutlives)(a),
(ty::Predicate::TypeOutlives)(a),
(ty::Predicate::Projection)(a),
(ty::Predicate::WellFormed)(a),
(ty::Predicate::ClosureKind)(a, b, c),
(ty::Predicate::ObjectSafe)(a),
(ty::Predicate::ConstEvaluatable)(a, b),
}
}
@@ -1298,71 +1083,40 @@ impl<'tcx> TypeFoldable<'tcx> for ty::InstantiatedPredicates<'tcx> {
}
}
impl<'tcx> TypeFoldable<'tcx> for ty::SubtypePredicate<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
ty::SubtypePredicate {
a_is_expected: self.a_is_expected,
a: self.a.fold_with(folder),
b: self.b.fold_with(folder)
}
}
BraceStructTypeFoldableImpl! {
impl<'tcx, T> TypeFoldable<'tcx> for ty::ParamEnvAnd<'tcx, T> {
param_env, value
} where T: TypeFoldable<'tcx>
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
self.a.visit_with(visitor) || self.b.visit_with(visitor)
BraceStructTypeFoldableImpl! {
impl<'tcx> TypeFoldable<'tcx> for ty::SubtypePredicate<'tcx> {
a_is_expected, a, b
}
}
impl<'tcx> TypeFoldable<'tcx> for ty::TraitPredicate<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
ty::TraitPredicate {
trait_ref: self.trait_ref.fold_with(folder)
}
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
self.trait_ref.visit_with(visitor)
BraceStructTypeFoldableImpl! {
impl<'tcx> TypeFoldable<'tcx> for ty::TraitPredicate<'tcx> {
trait_ref
}
}
impl<'tcx,T,U> TypeFoldable<'tcx> for ty::OutlivesPredicate<T,U>
where T : TypeFoldable<'tcx>,
U : TypeFoldable<'tcx>,
{
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
ty::OutlivesPredicate(self.0.fold_with(folder),
self.1.fold_with(folder))
}
TupleStructTypeFoldableImpl! {
impl<'tcx,T,U> TypeFoldable<'tcx> for ty::OutlivesPredicate<T,U> {
a, b
} where T : TypeFoldable<'tcx>, U : TypeFoldable<'tcx>,
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
self.0.visit_with(visitor) || self.1.visit_with(visitor)
BraceStructTypeFoldableImpl! {
impl<'tcx> TypeFoldable<'tcx> for ty::ClosureUpvar<'tcx> {
def, span, ty
}
}
impl<'tcx> TypeFoldable<'tcx> for ty::ClosureUpvar<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
ty::ClosureUpvar {
def: self.def,
span: self.span,
ty: self.ty.fold_with(folder),
}
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
self.ty.visit_with(visitor)
}
}
impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::error::ExpectedFound<T> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
ty::error::ExpectedFound {
expected: self.expected.fold_with(folder),
found: self.found.fold_with(folder),
}
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
self.expected.visit_with(visitor) || self.found.visit_with(visitor)
}
BraceStructTypeFoldableImpl! {
impl<'tcx, T> TypeFoldable<'tcx> for ty::error::ExpectedFound<T> {
expected, found
} where T: TypeFoldable<'tcx>
}
impl<'tcx, T: TypeFoldable<'tcx>, I: Idx> TypeFoldable<'tcx> for IndexVec<I, T> {
@@ -1375,69 +1129,28 @@ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
}
}
impl<'tcx> TypeFoldable<'tcx> for ty::error::TypeError<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
use ty::error::TypeError::*;
match *self {
Mismatch => Mismatch,
UnsafetyMismatch(x) => UnsafetyMismatch(x.fold_with(folder)),
AbiMismatch(x) => AbiMismatch(x.fold_with(folder)),
Mutability => Mutability,
TupleSize(x) => TupleSize(x),
FixedArraySize(x) => FixedArraySize(x),
ArgCount => ArgCount,
RegionsDoesNotOutlive(a, b) => {
RegionsDoesNotOutlive(a.fold_with(folder), b.fold_with(folder))
},
RegionsInsufficientlyPolymorphic(a, b) => {
RegionsInsufficientlyPolymorphic(a, b.fold_with(folder))
},
RegionsOverlyPolymorphic(a, b) => {
RegionsOverlyPolymorphic(a, b.fold_with(folder))
},
IntMismatch(x) => IntMismatch(x),
FloatMismatch(x) => FloatMismatch(x),
Traits(x) => Traits(x),
VariadicMismatch(x) => VariadicMismatch(x),
CyclicTy(t) => CyclicTy(t.fold_with(folder)),
ProjectionMismatched(x) => ProjectionMismatched(x),
ProjectionBoundsLength(x) => ProjectionBoundsLength(x),
Sorts(x) => Sorts(x.fold_with(folder)),
ExistentialMismatch(x) => ExistentialMismatch(x.fold_with(folder)),
OldStyleLUB(ref x) => OldStyleLUB(x.fold_with(folder)),
}
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
use ty::error::TypeError::*;
match *self {
UnsafetyMismatch(x) => x.visit_with(visitor),
AbiMismatch(x) => x.visit_with(visitor),
RegionsDoesNotOutlive(a, b) => {
a.visit_with(visitor) || b.visit_with(visitor)
},
RegionsInsufficientlyPolymorphic(_, b) |
RegionsOverlyPolymorphic(_, b) => {
b.visit_with(visitor)
},
Sorts(x) => x.visit_with(visitor),
OldStyleLUB(ref x) => x.visit_with(visitor),
ExistentialMismatch(x) => x.visit_with(visitor),
CyclicTy(t) => t.visit_with(visitor),
Mismatch |
Mutability |
TupleSize(_) |
FixedArraySize(_) |
ArgCount |
IntMismatch(_) |
FloatMismatch(_) |
Traits(_) |
VariadicMismatch(_) |
ProjectionMismatched(_) |
ProjectionBoundsLength(_) => false,
}
EnumTypeFoldableImpl! {
impl<'tcx> TypeFoldable<'tcx> for ty::error::TypeError<'tcx> {
(ty::error::TypeError::Mismatch),
(ty::error::TypeError::UnsafetyMismatch)(x),
(ty::error::TypeError::AbiMismatch)(x),
(ty::error::TypeError::Mutability),
(ty::error::TypeError::TupleSize)(x),
(ty::error::TypeError::FixedArraySize)(x),
(ty::error::TypeError::ArgCount),
(ty::error::TypeError::RegionsDoesNotOutlive)(a, b),
(ty::error::TypeError::RegionsInsufficientlyPolymorphic)(a, b),
(ty::error::TypeError::RegionsOverlyPolymorphic)(a, b),
(ty::error::TypeError::IntMismatch)(x),
(ty::error::TypeError::FloatMismatch)(x),
(ty::error::TypeError::Traits)(x),
(ty::error::TypeError::VariadicMismatch)(x),
(ty::error::TypeError::CyclicTy)(t),
(ty::error::TypeError::ProjectionMismatched)(x),
(ty::error::TypeError::ProjectionBoundsLength)(x),
(ty::error::TypeError::Sorts)(x),
(ty::error::TypeError::ExistentialMismatch)(x),
(ty::error::TypeError::OldStyleLUB)(x),
}
}
+12
View File
@@ -1047,6 +1047,9 @@ pub enum RegionKind {
/// `ClosureRegionRequirements` that are produced by MIR borrowck.
/// See `ClosureRegionRequirements` for more details.
ReClosureBound(RegionVid),
/// Canonicalized region, used only when preparing a trait query.
ReCanonical(CanonicalVar),
}
impl<'tcx> serialize::UseSpecializedDecodable for Region<'tcx> {}
@@ -1091,8 +1094,13 @@ pub enum InferTy {
FreshTy(u32),
FreshIntTy(u32),
FreshFloatTy(u32),
/// Canonicalized type variable, used only when preparing a trait query.
CanonicalTy(CanonicalVar),
}
newtype_index!(CanonicalVar);
/// A `ProjectionPredicate` for an `ExistentialTraitRef`.
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
pub struct ExistentialProjection<'tcx> {
@@ -1213,6 +1221,10 @@ pub fn type_flags(&self) -> TypeFlags {
}
ty::ReErased => {
}
ty::ReCanonical(..) => {
flags = flags | TypeFlags::HAS_FREE_REGIONS;
flags = flags | TypeFlags::HAS_CANONICAL_VARS;
}
ty::ReClosureBound(..) => {
flags = flags | TypeFlags::HAS_FREE_REGIONS;
}
+13 -1
View File
@@ -11,7 +11,7 @@
// Type substitutions.
use hir::def_id::DefId;
use ty::{self, Slice, Region, Ty, TyCtxt};
use ty::{self, Lift, Slice, Region, Ty, TyCtxt};
use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
use serialize::{self, Encodable, Encoder, Decodable, Decoder};
@@ -40,6 +40,7 @@ pub struct Kind<'tcx> {
const TYPE_TAG: usize = 0b00;
const REGION_TAG: usize = 0b01;
#[derive(Debug)]
pub enum UnpackedKind<'tcx> {
Lifetime(ty::Region<'tcx>),
Type(Ty<'tcx>),
@@ -113,6 +114,17 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
}
}
impl<'a, 'tcx> Lift<'tcx> for Kind<'a> {
type Lifted = Kind<'tcx>;
fn lift_to_tcx<'cx, 'gcx>(&self, tcx: TyCtxt<'cx, 'gcx, 'tcx>) -> Option<Self::Lifted> {
match self.unpack() {
UnpackedKind::Lifetime(a) => a.lift_to_tcx(tcx).map(|a| a.into()),
UnpackedKind::Type(a) => a.lift_to_tcx(tcx).map(|a| a.into()),
}
}
}
impl<'tcx> TypeFoldable<'tcx> for Kind<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
match self.unpack() {
+5 -119
View File
@@ -16,10 +16,10 @@
use hir;
use ich::NodeIdHashingMode;
use middle::const_val::ConstVal;
use traits::{self, Reveal};
use traits;
use ty::{self, Ty, TyCtxt, TypeFoldable};
use ty::fold::TypeVisitor;
use ty::subst::{Subst, UnpackedKind};
use ty::subst::UnpackedKind;
use ty::maps::TyCtxtAt;
use ty::TypeVariants::*;
use ty::layout::Integer;
@@ -182,30 +182,6 @@ pub enum Representability {
}
impl<'tcx> ty::ParamEnv<'tcx> {
/// Construct a trait environment suitable for contexts where
/// there are no where clauses in scope.
pub fn empty(reveal: Reveal) -> Self {
Self::new(ty::Slice::empty(), reveal, ty::UniverseIndex::ROOT)
}
/// Construct a trait environment with the given set of predicates.
pub fn new(caller_bounds: &'tcx ty::Slice<ty::Predicate<'tcx>>,
reveal: Reveal,
universe: ty::UniverseIndex)
-> Self {
ty::ParamEnv { caller_bounds, reveal, universe }
}
/// Returns a new parameter environment with the same clauses, but
/// which "reveals" the true results of projections in all cases
/// (even for associated types that are specializable). This is
/// the desired behavior during trans and certain other special
/// contexts; normally though we want to use `Reveal::UserFacing`,
/// which is the default.
pub fn reveal_all(self) -> Self {
ty::ParamEnv { reveal: Reveal::All, ..self }
}
pub fn can_type_implement_copy<'a>(self,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
self_type: Ty<'tcx>, span: Span)
@@ -561,99 +537,6 @@ pub fn destructor_constraints(self, def: &'tcx ty::AdtDef)
result
}
/// Return a set of constraints that needs to be satisfied in
/// order for `ty` to be valid for destruction.
pub fn dtorck_constraint_for_ty(self,
span: Span,
for_ty: Ty<'tcx>,
depth: usize,
ty: Ty<'tcx>)
-> Result<ty::DtorckConstraint<'tcx>, ErrorReported>
{
debug!("dtorck_constraint_for_ty({:?}, {:?}, {:?}, {:?})",
span, for_ty, depth, ty);
if depth >= self.sess.recursion_limit.get() {
let mut err = struct_span_err!(
self.sess, span, E0320,
"overflow while adding drop-check rules for {}", for_ty);
err.note(&format!("overflowed on {}", ty));
err.emit();
return Err(ErrorReported);
}
let result = match ty.sty {
ty::TyBool | ty::TyChar | ty::TyInt(_) | ty::TyUint(_) |
ty::TyFloat(_) | ty::TyStr | ty::TyNever | ty::TyForeign(..) |
ty::TyRawPtr(..) | ty::TyRef(..) | ty::TyFnDef(..) | ty::TyFnPtr(_) |
ty::TyGeneratorWitness(..) => {
// these types never have a destructor
Ok(ty::DtorckConstraint::empty())
}
ty::TyArray(ety, _) | ty::TySlice(ety) => {
// single-element containers, behave like their element
self.dtorck_constraint_for_ty(span, for_ty, depth+1, ety)
}
ty::TyTuple(tys, _) => {
tys.iter().map(|ty| {
self.dtorck_constraint_for_ty(span, for_ty, depth+1, ty)
}).collect()
}
ty::TyClosure(def_id, substs) => {
substs.upvar_tys(def_id, self).map(|ty| {
self.dtorck_constraint_for_ty(span, for_ty, depth+1, ty)
}).collect()
}
ty::TyGenerator(def_id, substs, _) => {
// Note that the interior types are ignored here.
// Any type reachable inside the interior must also be reachable
// through the upvars.
substs.upvar_tys(def_id, self).map(|ty| {
self.dtorck_constraint_for_ty(span, for_ty, depth+1, ty)
}).collect()
}
ty::TyAdt(def, substs) => {
let ty::DtorckConstraint {
dtorck_types, outlives
} = self.at(span).adt_dtorck_constraint(def.did);
Ok(ty::DtorckConstraint {
// FIXME: we can try to recursively `dtorck_constraint_on_ty`
// there, but that needs some way to handle cycles.
dtorck_types: dtorck_types.subst(self, substs),
outlives: outlives.subst(self, substs)
})
}
// Objects must be alive in order for their destructor
// to be called.
ty::TyDynamic(..) => Ok(ty::DtorckConstraint {
outlives: vec![ty.into()],
dtorck_types: vec![],
}),
// Types that can't be resolved. Pass them forward.
ty::TyProjection(..) | ty::TyAnon(..) | ty::TyParam(..) => {
Ok(ty::DtorckConstraint {
outlives: vec![],
dtorck_types: vec![ty],
})
}
ty::TyInfer(..) | ty::TyError => {
self.sess.delay_span_bug(span, "unresolved type in dtorck");
Err(ErrorReported)
}
};
debug!("dtorck_constraint_for_ty({:?}) = {:?}", ty, result);
result
}
pub fn is_closure(self, def_id: DefId) -> bool {
self.def_key(def_id).disambiguated_data.data == DefPathData::ClosureExpr
}
@@ -858,6 +741,9 @@ fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
ty::ReEmpty => {
// No variant fields to hash for these ...
}
ty::ReCanonical(c) => {
self.hash(c);
}
ty::ReLateBound(db, ty::BrAnon(i)) => {
self.hash(db.depth);
self.hash(i);
+10
View File
@@ -373,3 +373,13 @@ fn test_to_readable_str() {
assert_eq!("1_000_000", to_readable_str(1_000_000));
assert_eq!("1_234_567", to_readable_str(1_234_567));
}
pub trait CellUsizeExt {
fn increment(&self);
}
impl CellUsizeExt for Cell<usize> {
fn increment(&self) {
self.set(self.get() + 1);
}
}
+9
View File
@@ -721,6 +721,9 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
ty::ReEarlyBound(ref data) => {
write!(f, "{}", data.name)
}
ty::ReCanonical(_) => {
write!(f, "'_")
}
ty::ReLateBound(_, br) |
ty::ReFree(ty::FreeRegion { bound_region: br, .. }) |
ty::ReSkolemized(_, br) => {
@@ -785,6 +788,10 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}", vid)
}
ty::ReCanonical(c) => {
write!(f, "'?{}", c.index())
}
ty::ReSkolemized(id, ref bound_region) => {
write!(f, "ReSkolemized({:?}, {:?})", id, bound_region)
}
@@ -888,6 +895,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
ty::TyVar(_) => write!(f, "_"),
ty::IntVar(_) => write!(f, "{}", "{integer}"),
ty::FloatVar(_) => write!(f, "{}", "{float}"),
ty::CanonicalTy(_) => write!(f, "_"),
ty::FreshTy(v) => write!(f, "FreshTy({})", v),
ty::FreshIntTy(v) => write!(f, "FreshIntTy({})", v),
ty::FreshFloatTy(v) => write!(f, "FreshFloatTy({})", v)
@@ -899,6 +907,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
ty::TyVar(ref v) => write!(f, "{:?}", v),
ty::IntVar(ref v) => write!(f, "{:?}", v),
ty::FloatVar(ref v) => write!(f, "{:?}", v),
ty::CanonicalTy(v) => write!(f, "?{:?}", v.index()),
ty::FreshTy(v) => write!(f, "FreshTy({:?})", v),
ty::FreshIntTy(v) => write!(f, "FreshIntTy({:?})", v),
ty::FreshFloatTy(v) => write!(f, "FreshFloatTy({:?})", v)
@@ -427,6 +427,7 @@ pub fn borrow_of_local_data<'tcx>(cmt: &mc::cmt<'tcx>) -> bool {
// These cannot exist in borrowck
RegionKind::ReVar(..) |
RegionKind::ReCanonical(..) |
RegionKind::ReSkolemized(..) |
RegionKind::ReClosureBound(..) |
RegionKind::ReErased => span_bug!(borrow_span,
@@ -366,6 +366,7 @@ fn guarantee_valid(&mut self,
ty::ReStatic => self.item_ub,
ty::ReCanonical(_) |
ty::ReEmpty |
ty::ReClosureBound(..) |
ty::ReLateBound(..) |
+1
View File
@@ -23,6 +23,7 @@
#![feature(slice_patterns)]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(macro_lifetime_matcher)]
#![feature(i128_type)]
#![feature(from_ref)]
+1 -1
View File
@@ -330,7 +330,7 @@ fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
);
}
#[derive(Clone, PartialEq, Eq)]
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct IndexVec<I: Idx, T> {
pub raw: Vec<T>,
_marker: PhantomData<fn(&I)>
+1
View File
@@ -28,6 +28,7 @@ rustc_plugin = { path = "../librustc_plugin" }
rustc_privacy = { path = "../librustc_privacy" }
rustc_resolve = { path = "../librustc_resolve" }
rustc_save_analysis = { path = "../librustc_save_analysis" }
rustc_traits = { path = "../librustc_traits" }
rustc_trans_utils = { path = "../librustc_trans_utils" }
rustc_typeck = { path = "../librustc_typeck" }
serialize = { path = "../libserialize" }
+2
View File
@@ -31,6 +31,7 @@
use rustc_resolve::{MakeGlobMap, Resolver, ResolverArenas};
use rustc_metadata::creader::CrateLoader;
use rustc_metadata::cstore::{self, CStore};
use rustc_traits;
use rustc_trans_utils::trans_crate::TransCrate;
use rustc_typeck as typeck;
use rustc_privacy;
@@ -942,6 +943,7 @@ pub fn default_provide(providers: &mut ty::maps::Providers) {
traits::provide(providers);
reachable::provide(providers);
rustc_passes::provide(providers);
rustc_traits::provide(providers);
middle::region::provide(providers);
cstore::provide(providers);
lint::provide(providers);
+1
View File
@@ -46,6 +46,7 @@
extern crate rustc_mir;
extern crate rustc_resolve;
extern crate rustc_save_analysis;
extern crate rustc_traits;
extern crate rustc_trans_utils;
extern crate rustc_typeck;
extern crate serialize;
+2 -2
View File
@@ -18,7 +18,7 @@
use rustc_resolve::MakeGlobMap;
use rustc::middle::region;
use rustc::ty::subst::Subst;
use rustc::traits::{ObligationCause, Reveal};
use rustc::traits::ObligationCause;
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
use rustc::ty::maps::OnDiskCache;
use rustc::infer::{self, InferOk, InferResult};
@@ -153,7 +153,7 @@ fn test_env<F>(source_string: &str,
|tcx| {
tcx.infer_ctxt().enter(|infcx| {
let mut region_scope_tree = region::ScopeTree::default();
let param_env = ty::ParamEnv::empty(Reveal::UserFacing);
let param_env = ty::ParamEnv::empty();
body(Env {
infcx: &infcx,
region_scope_tree: &mut region_scope_tree,
+2 -2
View File
@@ -33,7 +33,7 @@
use rustc::cfg;
use rustc::ty::subst::Substs;
use rustc::ty::{self, Ty};
use rustc::traits::{self, Reveal};
use rustc::traits;
use rustc::hir::map as hir_map;
use util::nodemap::NodeSet;
use lint::{LateContext, LintContext, LintArray};
@@ -525,7 +525,7 @@ fn check_item(&mut self, cx: &LateContext, item: &hir::Item) {
if def.has_dtor(cx.tcx) {
return;
}
let param_env = ty::ParamEnv::empty(Reveal::UserFacing);
let param_env = ty::ParamEnv::empty();
if !ty.moves_by_default(cx.tcx, param_env, item.span) {
return;
}
+11 -8
View File
@@ -12,7 +12,7 @@
use rustc::hir::map as hir_map;
use rustc::ty::subst::Substs;
use rustc::ty::{self, AdtKind, Ty, TyCtxt};
use rustc::ty::{self, AdtKind, ParamEnv, Ty, TyCtxt};
use rustc::ty::layout::{self, LayoutOf};
use util::nodemap::FxHashSet;
use lint::{LateContext, LintContext, LintArray};
@@ -509,8 +509,9 @@ fn check_type_for_ffi(&self,
// make sure the fields are actually safe.
let mut all_phantom = true;
for field in &def.non_enum_variant().fields {
let field_ty = cx.fully_normalize_associated_types_in(
&field.ty(cx, substs)
let field_ty = cx.normalize_erasing_regions(
ParamEnv::reveal_all(),
field.ty(cx, substs),
);
// repr(transparent) types are allowed to have arbitrary ZSTs, not just
// PhantomData -- skip checking all ZST fields
@@ -556,8 +557,9 @@ fn check_type_for_ffi(&self,
let mut all_phantom = true;
for field in &def.non_enum_variant().fields {
let field_ty = cx.fully_normalize_associated_types_in(
&field.ty(cx, substs)
let field_ty = cx.normalize_erasing_regions(
ParamEnv::reveal_all(),
field.ty(cx, substs),
);
let r = self.check_type_for_ffi(cache, field_ty);
match r {
@@ -596,8 +598,9 @@ fn check_type_for_ffi(&self,
// Check the contained variants.
for variant in &def.variants {
for field in &variant.fields {
let arg = cx.fully_normalize_associated_types_in(
&field.ty(cx, substs)
let arg = cx.normalize_erasing_regions(
ParamEnv::reveal_all(),
field.ty(cx, substs),
);
let r = self.check_type_for_ffi(cache, arg);
match r {
@@ -716,7 +719,7 @@ fn check_type_for_ffi(&self,
fn check_type_for_ffi_and_report_errors(&mut self, sp: Span, ty: Ty<'tcx>) {
// it is only OK to use this function because extern fns cannot have
// any generic types right now:
let ty = self.cx.tcx.fully_normalize_associated_types_in(&ty);
let ty = self.cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty);
match self.check_type_for_ffi(&mut FxHashSet(), ty) {
FfiResult::FfiSafe => {}
+2
View File
@@ -18,7 +18,9 @@
#![feature(fs_read_write)]
#![feature(i128_type)]
#![feature(libc)]
#![feature(macro_lifetime_matcher)]
#![feature(proc_macro_internals)]
#![feature(macro_lifetime_matcher)]
#![feature(quote)]
#![feature(rustc_diagnostic_macros)]
#![feature(specialization)]
@@ -457,6 +457,7 @@ pub(super) fn report_borrowed_value_does_not_live_long_enough(
(RegionKind::ReLateBound(_, _), _)
| (RegionKind::ReSkolemized(_, _), _)
| (RegionKind::ReClosureBound(_), _)
| (RegionKind::ReCanonical(_), _)
| (RegionKind::ReErased, _) => {
span_bug!(drop_span, "region does not make sense in this context");
}
+1 -1
View File
@@ -732,7 +732,7 @@ fn visit_terminator_drop(
for (index, field) in def.all_fields().enumerate() {
let gcx = self.tcx.global_tcx();
let field_ty = field.ty(gcx, substs);
let field_ty = gcx.normalize_associated_type_in_env(&field_ty, self.param_env);
let field_ty = gcx.normalize_erasing_regions(self.param_env, field_ty);
let place = drop_place.clone().field(Field::new(index), field_ty);
self.visit_terminator_drop(loc, term, flow_state, &place, field_ty, span);
@@ -14,13 +14,9 @@
use dataflow::move_paths::{HasMoveData, MoveData};
use rustc::mir::{BasicBlock, Location, Mir};
use rustc::mir::Local;
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
use rustc::traits;
use rustc::ty::{Ty, TyCtxt, TypeFoldable};
use rustc::infer::InferOk;
use rustc::util::common::ErrorReported;
use borrow_check::nll::type_check::AtLocation;
use rustc_data_structures::fx::FxHashSet;
use syntax::codemap::DUMMY_SP;
use util::liveness::LivenessResults;
use super::TypeChecker;
@@ -105,8 +101,7 @@ fn add_liveness_constraints(&mut self, bb: BasicBlock) {
for live_local in live_locals {
debug!(
"add_liveness_constraints: location={:?} live_local={:?}",
location,
live_local
location, live_local
);
self.flow_inits.each_state_bit(|mpi_init| {
@@ -157,8 +152,7 @@ fn push_type_live_constraint<T>(&mut self, value: T, location: Location, cause:
{
debug!(
"push_type_live_constraint(live_ty={:?}, location={:?})",
value,
location
value, location
);
self.tcx.for_each_free_region(&value, |live_region| {
@@ -182,9 +176,7 @@ fn add_drop_live_constraint(
) {
debug!(
"add_drop_live_constraint(dropped_local={:?}, dropped_ty={:?}, location={:?})",
dropped_local,
dropped_ty,
location
dropped_local, dropped_ty, location
);
// If we end visiting the same type twice (usually due to a cycle involving
@@ -197,73 +189,34 @@ fn add_drop_live_constraint(
//
// For this reason, we avoid calling TypeChecker.normalize, instead doing all normalization
// ourselves in one large 'fully_perform_op' callback.
let (type_constraints, kind_constraints) = self.cx.fully_perform_op(location.at_self(),
|cx| {
let kind_constraints = self.cx
.fully_perform_op(location.at_self(), |cx| {
let span = cx.last_span;
let tcx = cx.infcx.tcx;
let mut selcx = traits::SelectionContext::new(cx.infcx);
let cause = cx.misc(cx.last_span);
let mut final_obligations = Vec::new();
let mut kind_constraints = Vec::new();
let mut types = vec![(dropped_ty, 0)];
let mut final_obligations = Vec::new();
let mut type_constraints = Vec::new();
let mut kind_constraints = Vec::new();
let mut known = FxHashSet();
while let Some((ty, depth)) = types.pop() {
let span = DUMMY_SP; // FIXME
let result = match tcx.dtorck_constraint_for_ty(span, dropped_ty, depth, ty) {
Ok(result) => result,
Err(ErrorReported) => {
continue;
}
};
let ty::DtorckConstraint {
outlives,
dtorck_types,
} = result;
// All things in the `outlives` array may be touched by
// the destructor and must be live at this point.
for outlive in outlives {
let InferOk {
value: kinds,
obligations,
} = cx.infcx
.at(&cx.misc(span), cx.param_env)
.dropck_outlives(dropped_ty);
for kind in kinds {
// All things in the `outlives` array may be touched by
// the destructor and must be live at this point.
let cause = Cause::DropVar(dropped_local, location);
kind_constraints.push((outlive, location, cause));
kind_constraints.push((kind, location, cause));
}
// However, there may also be some types that
// `dtorck_constraint_for_ty` could not resolve (e.g.,
// associated types and parameters). We need to normalize
// associated types here and possibly recursively process.
for ty in dtorck_types {
let traits::Normalized { value: ty, obligations } =
traits::normalize(&mut selcx, cx.param_env, cause.clone(), &ty);
final_obligations.extend(obligations);
final_obligations.extend(obligations);
let ty = cx.infcx.resolve_type_and_region_vars_if_possible(&ty);
match ty.sty {
ty::TyParam(..) | ty::TyProjection(..) | ty::TyAnon(..) => {
let cause = Cause::DropVar(dropped_local, location);
type_constraints.push((ty, location, cause));
}
_ => if known.insert(ty) {
types.push((ty, depth + 1));
},
}
}
}
Ok(InferOk {
value: (type_constraints, kind_constraints), obligations: final_obligations
Ok(InferOk {
value: kind_constraints,
obligations: final_obligations,
})
})
}).unwrap();
for (ty, location, cause) in type_constraints {
self.push_type_live_constraint(ty, location, cause);
}
.unwrap();
for (kind, location, cause) in kind_constraints {
self.push_type_live_constraint(kind, location, cause);
@@ -20,7 +20,8 @@
use rustc::hir::def_id::DefId;
use rustc::infer::{InferCtxt, InferOk, InferResult, LateBoundRegionConversionTime, UnitResult};
use rustc::infer::region_constraints::{GenericKind, RegionConstraintData};
use rustc::traits::{self, FulfillmentContext};
use rustc::traits::{self, Normalized, FulfillmentContext};
use rustc::traits::query::NoSolution;
use rustc::ty::error::TypeError;
use rustc::ty::fold::TypeFoldable;
use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, TypeVariants};
@@ -243,8 +244,7 @@ fn sanitize_type(&mut self, parent: &dyn fmt::Debug, ty: Ty<'tcx>) -> Ty<'tcx> {
fn sanitize_constant(&mut self, constant: &Constant<'tcx>, location: Location) {
debug!(
"sanitize_constant(constant={:?}, location={:?})",
constant,
location
constant, location
);
let expected_ty = match constant.literal {
@@ -678,8 +678,10 @@ fn fully_perform_op<OP, R>(
let data = self.infcx.take_and_reset_region_constraints();
if !data.is_empty() {
debug!("fully_perform_op: constraints generated at {:?} are {:#?}",
locations, data);
debug!(
"fully_perform_op: constraints generated at {:?} are {:#?}",
locations, data
);
self.constraints
.outlives_sets
.push(OutlivesSet { locations, data });
@@ -1137,12 +1139,16 @@ fn check_iscleanup(&mut self, mir: &Mir<'tcx>, block_data: &BasicBlockData<'tcx>
}
TerminatorKind::FalseUnwind {
real_target,
unwind
unwind,
} => {
self.assert_iscleanup(mir, block_data, real_target, is_cleanup);
if let Some(unwind) = unwind {
if is_cleanup {
span_mirbug!(self, block_data, "cleanup in cleanup block via false unwind");
span_mirbug!(
self,
block_data,
"cleanup in cleanup block via false unwind"
);
}
self.assert_iscleanup(mir, block_data, unwind, true);
}
@@ -1435,8 +1441,7 @@ fn prove_aggregate_predicates(
debug!(
"prove_aggregate_predicates(aggregate_kind={:?}, location={:?})",
aggregate_kind,
location
aggregate_kind, location
);
let instantiated_predicates = match aggregate_kind {
@@ -1502,8 +1507,7 @@ fn prove_trait_ref(&mut self, trait_ref: ty::TraitRef<'tcx>, location: Location)
fn prove_predicates(&mut self, predicates: &[ty::Predicate<'tcx>], location: Location) {
debug!(
"prove_predicates(predicates={:?}, location={:?})",
predicates,
location
predicates, location
);
self.fully_perform_op(location.at_self(), |this| {
let cause = this.misc(this.last_span);
@@ -1550,10 +1554,17 @@ fn normalize<T>(&mut self, value: &T, location: Location) -> T
{
debug!("normalize(value={:?}, location={:?})", value, location);
self.fully_perform_op(location.at_self(), |this| {
let mut selcx = traits::SelectionContext::new(this.infcx);
let cause = this.misc(this.last_span);
let traits::Normalized { value, obligations } =
traits::normalize(&mut selcx, this.param_env, cause, value);
let Normalized { value, obligations } = this.infcx
.at(&this.misc(this.last_span), this.param_env)
.normalize(value)
.unwrap_or_else(|NoSolution| {
span_bug!(
this.last_span,
"normalization of `{:?}` failed at {:?}",
value,
location,
);
});
Ok(InferOk { value, obligations })
}).unwrap()
}
+13 -8
View File
@@ -249,7 +249,11 @@ pub(super) fn resolve(&self, def_id: DefId, substs: &'tcx Substs<'tcx>) -> EvalR
trace!("resolve: {:?}, {:#?}", def_id, substs);
trace!("substs: {:#?}", self.substs());
trace!("param_env: {:#?}", self.param_env);
let substs = self.tcx.trans_apply_param_substs_env(self.substs(), self.param_env, &substs);
let substs = self.tcx.subst_and_normalize_erasing_regions(
self.substs(),
self.param_env,
&substs,
);
ty::Instance::resolve(
*self.tcx,
self.param_env,
@@ -285,10 +289,8 @@ pub fn load_mir(
pub fn monomorphize(&self, ty: Ty<'tcx>, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> {
// miri doesn't care about lifetimes, and will choke on some crazy ones
// let's simply get rid of them
let without_lifetimes = self.tcx.erase_regions(&ty);
let substituted = without_lifetimes.subst(*self.tcx, substs);
let substituted = self.tcx.fully_normalize_monormophic_ty(&substituted);
substituted
let substituted = ty.subst(*self.tcx, substs);
self.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), substituted)
}
/// Return the size and aligment of the value at the given type.
@@ -724,7 +726,11 @@ pub(super) fn eval_rvalue_into_place(
ClosureFnPointer => {
match self.eval_operand(operand)?.ty.sty {
ty::TyClosure(def_id, substs) => {
let substs = self.tcx.trans_apply_param_substs(self.substs(), &substs);
let substs = self.tcx.subst_and_normalize_erasing_regions(
self.substs(),
ty::ParamEnv::reveal_all(),
&substs,
);
let instance = ty::Instance::resolve_closure(
*self.tcx,
def_id,
@@ -949,8 +955,7 @@ pub fn read_global_as_value(&self, gid: GlobalId<'tcx>, ty: Ty<'tcx>) -> EvalRes
pub fn const_eval(&self, gid: GlobalId<'tcx>) -> EvalResult<'tcx, &'tcx ty::Const<'tcx>> {
let param_env = if self.tcx.is_static(gid.instance.def_id()).is_some() {
use rustc::traits;
ty::ParamEnv::empty(traits::Reveal::All)
ty::ParamEnv::reveal_all()
} else {
self.param_env
};
+17 -4
View File
@@ -75,8 +75,14 @@ pub(super) fn eval_terminator(
match instance_ty.sty {
ty::TyFnDef(..) => {
let real_sig = instance_ty.fn_sig(*self.tcx);
let sig = self.tcx.erase_late_bound_regions_and_normalize(&sig);
let real_sig = self.tcx.erase_late_bound_regions_and_normalize(&real_sig);
let sig = self.tcx.normalize_erasing_late_bound_regions(
ty::ParamEnv::reveal_all(),
&sig,
);
let real_sig = self.tcx.normalize_erasing_late_bound_regions(
ty::ParamEnv::reveal_all(),
&real_sig,
);
if !self.check_sig_compat(sig, real_sig)? {
return err!(FunctionPointerTyMismatch(real_sig, sig));
}
@@ -95,7 +101,10 @@ pub(super) fn eval_terminator(
}
};
let args = self.operands_to_args(args)?;
let sig = self.tcx.erase_late_bound_regions_and_normalize(&sig);
let sig = self.tcx.normalize_erasing_late_bound_regions(
ty::ParamEnv::reveal_all(),
&sig,
);
self.eval_fn_call(
fn_def,
destination,
@@ -113,7 +122,11 @@ pub(super) fn eval_terminator(
// FIXME(CTFE): forbid drop in const eval
let place = self.eval_place(location)?;
let ty = self.place_ty(location);
let ty = self.tcx.trans_apply_param_substs(self.substs(), &ty);
let ty = self.tcx.subst_and_normalize_erasing_regions(
self.substs(),
ty::ParamEnv::reveal_all(),
&ty,
);
trace!("TerminatorKind::drop: {:?}, type {}", location, ty);
let instance = ::monomorphize::resolve_drop_in_place(*self.tcx, ty);
+43 -21
View File
@@ -196,7 +196,6 @@
use rustc::middle::const_val::ConstVal;
use rustc::mir::interpret::{Value, PrimVal, AllocId, Pointer};
use rustc::middle::lang_items::{ExchangeMallocFnLangItem, StartFnLangItem};
use rustc::traits;
use rustc::ty::subst::{Substs, Kind};
use rustc::ty::{self, TypeFoldable, Ty, TyCtxt};
use rustc::ty::adjustment::CustomCoerceUnsized;
@@ -383,7 +382,7 @@ fn collect_items_rec<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
instance,
promoted: None,
};
let param_env = ty::ParamEnv::empty(traits::Reveal::All);
let param_env = ty::ParamEnv::reveal_all();
match tcx.const_eval(param_env.and(cid)) {
Ok(val) => collect_const(tcx, val, instance.substs, &mut neighbors),
@@ -524,11 +523,17 @@ fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) {
// have to instantiate all methods of the trait being cast to, so we
// can build the appropriate vtable.
mir::Rvalue::Cast(mir::CastKind::Unsize, ref operand, target_ty) => {
let target_ty = self.tcx.trans_apply_param_substs(self.param_substs,
&target_ty);
let target_ty = self.tcx.subst_and_normalize_erasing_regions(
self.param_substs,
ty::ParamEnv::reveal_all(),
&target_ty,
);
let source_ty = operand.ty(self.mir, self.tcx);
let source_ty = self.tcx.trans_apply_param_substs(self.param_substs,
&source_ty);
let source_ty = self.tcx.subst_and_normalize_erasing_regions(
self.param_substs,
ty::ParamEnv::reveal_all(),
&source_ty,
);
let (source_ty, target_ty) = find_vtable_types_for_unsizing(self.tcx,
source_ty,
target_ty);
@@ -544,14 +549,20 @@ fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) {
}
mir::Rvalue::Cast(mir::CastKind::ReifyFnPointer, ref operand, _) => {
let fn_ty = operand.ty(self.mir, self.tcx);
let fn_ty = self.tcx.trans_apply_param_substs(self.param_substs,
&fn_ty);
let fn_ty = self.tcx.subst_and_normalize_erasing_regions(
self.param_substs,
ty::ParamEnv::reveal_all(),
&fn_ty,
);
visit_fn_use(self.tcx, fn_ty, false, &mut self.output);
}
mir::Rvalue::Cast(mir::CastKind::ClosureFnPointer, ref operand, _) => {
let source_ty = operand.ty(self.mir, self.tcx);
let source_ty = self.tcx.trans_apply_param_substs(self.param_substs,
&source_ty);
let source_ty = self.tcx.subst_and_normalize_erasing_regions(
self.param_substs,
ty::ParamEnv::reveal_all(),
&source_ty,
);
match source_ty.sty {
ty::TyClosure(def_id, substs) => {
let instance = monomorphize::resolve_closure(
@@ -596,14 +607,22 @@ fn visit_terminator_kind(&mut self,
match *kind {
mir::TerminatorKind::Call { ref func, .. } => {
let callee_ty = func.ty(self.mir, tcx);
let callee_ty = tcx.trans_apply_param_substs(self.param_substs, &callee_ty);
let callee_ty = tcx.subst_and_normalize_erasing_regions(
self.param_substs,
ty::ParamEnv::reveal_all(),
&callee_ty,
);
visit_fn_use(self.tcx, callee_ty, true, &mut self.output);
}
mir::TerminatorKind::Drop { ref location, .. } |
mir::TerminatorKind::DropAndReplace { ref location, .. } => {
let ty = location.ty(self.mir, self.tcx)
.to_ty(self.tcx);
let ty = tcx.trans_apply_param_substs(self.param_substs, &ty);
let ty = tcx.subst_and_normalize_erasing_regions(
self.param_substs,
ty::ParamEnv::reveal_all(),
&ty,
);
visit_drop_use(self.tcx, ty, true, self.output);
}
mir::TerminatorKind::Goto { .. } |
@@ -654,7 +673,7 @@ fn visit_fn_use<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
{
if let ty::TyFnDef(def_id, substs) = ty.sty {
let instance = ty::Instance::resolve(tcx,
ty::ParamEnv::empty(traits::Reveal::All),
ty::ParamEnv::reveal_all(),
def_id,
substs).unwrap();
visit_instance_use(tcx, instance, is_direct_call, output);
@@ -776,7 +795,7 @@ fn find_vtable_types_for_unsizing<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let ptr_vtable = |inner_source: Ty<'tcx>, inner_target: Ty<'tcx>| {
let type_has_metadata = |ty: Ty<'tcx>| -> bool {
use syntax_pos::DUMMY_SP;
if ty.is_sized(tcx.at(DUMMY_SP), ty::ParamEnv::empty(traits::Reveal::All)) {
if ty.is_sized(tcx.at(DUMMY_SP), ty::ParamEnv::reveal_all()) {
return false;
}
let tail = tcx.struct_tail(ty);
@@ -859,7 +878,7 @@ fn create_mono_items_for_vtable_methods<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let methods = methods.iter().cloned().filter_map(|method| method)
.map(|(def_id, substs)| ty::Instance::resolve(
tcx,
ty::ParamEnv::empty(traits::Reveal::All),
ty::ParamEnv::reveal_all(),
def_id,
substs).unwrap())
.filter(|&instance| should_monomorphize_locally(tcx, &instance))
@@ -1013,7 +1032,7 @@ fn push_extra_entry_roots(&mut self, def_id: DefId) {
let start_instance = Instance::resolve(
self.tcx,
ty::ParamEnv::empty(traits::Reveal::All),
ty::ParamEnv::reveal_all(),
start_def_id,
self.tcx.mk_substs(iter::once(Kind::from(main_ret_ty)))
).unwrap();
@@ -1062,7 +1081,7 @@ fn create_mono_items_for_default_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
}
let instance = ty::Instance::resolve(tcx,
ty::ParamEnv::empty(traits::Reveal::All),
ty::ParamEnv::reveal_all(),
method.def_id,
callee_substs).unwrap();
@@ -1120,7 +1139,7 @@ fn collect_neighbours<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
output,
param_substs: instance.substs,
}.visit_mir(&mir);
let param_env = ty::ParamEnv::empty(traits::Reveal::All);
let param_env = ty::ParamEnv::reveal_all();
for (i, promoted) in mir.promoted.iter().enumerate() {
use rustc_data_structures::indexed_vec::Idx;
let cid = GlobalId {
@@ -1155,9 +1174,12 @@ fn collect_const<'a, 'tcx>(
let val = match constant.val {
ConstVal::Unevaluated(def_id, substs) => {
let param_env = ty::ParamEnv::empty(traits::Reveal::All);
let substs = tcx.trans_apply_param_substs(param_substs,
&substs);
let param_env = ty::ParamEnv::reveal_all();
let substs = tcx.subst_and_normalize_erasing_regions(
param_substs,
param_env,
&substs,
);
let instance = ty::Instance::resolve(tcx,
param_env,
def_id,
+4 -1
View File
@@ -347,7 +347,10 @@ pub fn push_type_name(&self, t: Ty<'tcx>, output: &mut String) {
output.push_str("fn(");
let sig = self.tcx.erase_late_bound_regions_and_normalize(&sig);
let sig = self.tcx.normalize_erasing_late_bound_regions(
ty::ParamEnv::reveal_all(),
&sig,
);
if !sig.inputs().is_empty() {
for &parameter_type in sig.inputs() {
+3 -3
View File
@@ -88,7 +88,7 @@ fn fn_once_adapter_instance<'a, 'tcx>(
closure_did, substs);
let sig = substs.closure_sig(closure_did, tcx);
let sig = tcx.erase_late_bound_regions_and_normalize(&sig);
let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
assert_eq!(sig.inputs().len(), 1);
let substs = tcx.mk_substs([
Kind::from(self_ty),
@@ -154,7 +154,7 @@ pub fn resolve_drop_in_place<'a, 'tcx>(
{
let def_id = tcx.require_lang_item(DropInPlaceFnLangItem);
let substs = tcx.intern_substs(&[ty.into()]);
Instance::resolve(tcx, ty::ParamEnv::empty(traits::Reveal::All), def_id, substs).unwrap()
Instance::resolve(tcx, ty::ParamEnv::reveal_all(), def_id, substs).unwrap()
}
pub fn custom_coerce_unsize_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
@@ -168,7 +168,7 @@ pub fn custom_coerce_unsize_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
substs: tcx.mk_substs_trait(source_ty, &[target_ty])
});
match tcx.trans_fulfill_obligation( (ty::ParamEnv::empty(traits::Reveal::All), trait_ref)) {
match tcx.trans_fulfill_obligation( (ty::ParamEnv::reveal_all(), trait_ref)) {
traits::VtableImpl(traits::VtableImplData { impl_def_id, .. }) => {
tcx.coerce_unsized_info(impl_def_id).custom_kind.unwrap()
}
@@ -645,7 +645,11 @@ fn characteristic_def_id_of_trans_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
if let Some(impl_def_id) = tcx.impl_of_method(def_id) {
// This is a method within an inherent impl, find out what the
// self-type is:
let impl_self_ty = tcx.trans_impl_self_ty(impl_def_id, instance.substs);
let impl_self_ty = tcx.subst_and_normalize_erasing_regions(
instance.substs,
ty::ParamEnv::reveal_all(),
&tcx.type_of(impl_def_id),
);
if let Some(def_id) = characteristic_def_id_of_type(impl_self_ty) {
return Some(def_id);
}
+3 -6
View File
@@ -832,14 +832,11 @@ pub fn build_adt_ctor<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>,
let tcx = infcx.tcx;
let gcx = tcx.global_tcx();
let def_id = tcx.hir.local_def_id(ctor_id);
let sig = gcx.fn_sig(def_id).no_late_bound_regions()
.expect("LBR in ADT constructor signature");
let sig = gcx.erase_regions(&sig);
let param_env = gcx.param_env(def_id);
// Normalize the sig now that we have liberated the late-bound
// regions.
let sig = gcx.normalize_associated_type_in_env(&sig, param_env);
// Normalize the sig.
let sig = gcx.fn_sig(def_id).no_late_bound_regions().expect("LBR in ADT constructor signature");
let sig = gcx.normalize_erasing_regions(param_env, sig);
let (adt_def, substs) = match sig.output().sty {
ty::TyAdt(adt_def, substs) => (adt_def, substs),
+7 -27
View File
@@ -19,7 +19,7 @@
use rustc::mir::*;
use rustc::mir::visit::*;
use rustc::ty::{self, Instance, Ty, TyCtxt, TypeFoldable};
use rustc::ty::{self, Instance, Ty, TyCtxt};
use rustc::ty::subst::{Subst,Substs};
use std::collections::VecDeque;
@@ -129,8 +129,12 @@ fn run_pass(&self, caller_mir: &mut Mir<'tcx>) {
let callee_mir = match ty::queries::optimized_mir::try_get(self.tcx,
callsite.location.span,
callsite.callee) {
Ok(ref callee_mir) if self.should_inline(callsite, callee_mir) => {
subst_and_normalize(callee_mir, self.tcx, &callsite.substs, param_env)
Ok(callee_mir) if self.should_inline(callsite, callee_mir) => {
self.tcx.subst_and_normalize_erasing_regions(
&callsite.substs,
param_env,
callee_mir,
)
}
Ok(_) => continue,
@@ -664,30 +668,6 @@ fn type_size_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
tcx.layout_of(param_env.and(ty)).ok().map(|layout| layout.size.bytes())
}
fn subst_and_normalize<'a, 'tcx: 'a>(
mir: &Mir<'tcx>,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
substs: &'tcx ty::subst::Substs<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> Mir<'tcx> {
struct Folder<'a, 'tcx: 'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
substs: &'tcx ty::subst::Substs<'tcx>,
}
impl<'a, 'tcx: 'a> ty::fold::TypeFolder<'tcx, 'tcx> for Folder<'a, 'tcx> {
fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> {
self.tcx
}
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
self.tcx.trans_apply_param_substs_env(&self.substs, self.param_env, &t)
}
}
let mut f = Folder { tcx, param_env, substs };
mir.fold_with(&mut f)
}
/**
* Integrator.
*
+2 -2
View File
@@ -21,7 +21,7 @@
use rustc::hir;
use rustc::hir::def_id::DefId;
use rustc::middle::const_val::ConstVal;
use rustc::traits::{self, Reveal};
use rustc::traits;
use rustc::ty::{self, TyCtxt, Ty, TypeFoldable};
use rustc::ty::cast::CastTy;
use rustc::ty::maps::Providers;
@@ -1237,7 +1237,7 @@ fn run_pass<'a, 'tcx>(&self,
}
let ty = mir.return_ty();
tcx.infer_ctxt().enter(|infcx| {
let param_env = ty::ParamEnv::empty(Reveal::UserFacing);
let param_env = ty::ParamEnv::empty();
let cause = traits::ObligationCause::new(mir.span, id, traits::SharedStatic);
let mut fulfillment_cx = traits::FulfillmentContext::new();
fulfillment_cx.register_bound(&infcx,
+4 -5
View File
@@ -206,11 +206,10 @@ fn move_paths_for_fields(&self,
let field = Field::new(i);
let subpath = self.elaborator.field_subpath(variant_path, field);
let field_ty =
self.tcx().normalize_associated_type_in_env(
&f.ty(self.tcx(), substs),
self.elaborator.param_env()
);
let field_ty = self.tcx().normalize_erasing_regions(
self.elaborator.param_env(),
f.ty(self.tcx(), substs),
);
(base_place.clone().field(field, field_ty), subpath)
}).collect()
}
+1 -2
View File
@@ -34,7 +34,6 @@
use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::maps::Providers;
use rustc::ty::subst::Substs;
use rustc::traits::Reveal;
use rustc::util::nodemap::{ItemLocalSet, NodeSet};
use rustc::hir;
use rustc_data_structures::sync::Lrc;
@@ -87,7 +86,7 @@ fn rvalue_promotable_map<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
in_static: false,
promotable: false,
mut_rvalue_borrows: NodeSet(),
param_env: ty::ParamEnv::empty(Reveal::UserFacing),
param_env: ty::ParamEnv::empty(),
identity_substs: Substs::empty(),
result: ItemLocalSet(),
};
+1
View File
@@ -13,6 +13,7 @@
html_root_url = "https://doc.rust-lang.org/nightly/")]
#![deny(warnings)]
#![feature(custom_attribute)]
#![feature(macro_lifetime_matcher)]
#![allow(unused_attributes)]
#[macro_use]
+18
View File
@@ -0,0 +1,18 @@
[package]
authors = ["The Rust Project Developers"]
name = "rustc_traits"
version = "0.0.0"
[lib]
name = "rustc_traits"
path = "lib.rs"
crate-type = ["dylib"]
[dependencies]
bitflags = "1.0"
graphviz = { path = "../libgraphviz" }
log = { version = "0.4" }
rustc = { path = "../librustc" }
rustc_data_structures = { path = "../librustc_data_structures" }
syntax = { path = "../libsyntax" }
syntax_pos = { path = "../libsyntax_pos" }
+285
View File
@@ -0,0 +1,285 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use rustc::infer::canonical::{Canonical, QueryResult};
use rustc::hir::def_id::DefId;
use rustc::traits::{FulfillmentContext, Normalized, ObligationCause};
use rustc::traits::query::{CanonicalTyGoal, NoSolution};
use rustc::traits::query::dropck_outlives::{DtorckConstraint, DropckOutlivesResult};
use rustc::ty::{self, ParamEnvAnd, Ty, TyCtxt};
use rustc::ty::subst::Subst;
use rustc::util::nodemap::FxHashSet;
use std::rc::Rc;
use syntax::codemap::{Span, DUMMY_SP};
use util;
crate fn dropck_outlives<'tcx>(
tcx: TyCtxt<'_, 'tcx, 'tcx>,
goal: CanonicalTyGoal<'tcx>,
) -> Result<Rc<Canonical<'tcx, QueryResult<'tcx, DropckOutlivesResult<'tcx>>>>, NoSolution> {
debug!("dropck_outlives(goal={:#?})", goal);
tcx.infer_ctxt().enter(|ref infcx| {
let tcx = infcx.tcx;
let (
ParamEnvAnd {
param_env,
value: for_ty,
},
canonical_inference_vars,
) = infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &goal);
let mut result = DropckOutlivesResult { kinds: vec![], overflows: vec![] };
// A stack of types left to process. Each round, we pop
// something from the stack and invoke
// `dtorck_constraint_for_ty`. This may produce new types that
// have to be pushed on the stack. This continues until we have explored
// all the reachable types from the type `for_ty`.
//
// Example: Imagine that we have the following code:
//
// ```rust
// struct A {
// value: B,
// children: Vec<A>,
// }
//
// struct B {
// value: u32
// }
//
// fn f() {
// let a: A = ...;
// ..
// } // here, `a` is dropped
// ```
//
// at the point where `a` is dropped, we need to figure out
// which types inside of `a` contain region data that may be
// accessed by any destructors in `a`. We begin by pushing `A`
// onto the stack, as that is the type of `a`. We will then
// invoke `dtorck_constraint_for_ty` which will expand `A`
// into the types of its fields `(B, Vec<A>)`. These will get
// pushed onto the stack. Eventually, expanding `Vec<A>` will
// lead to us trying to push `A` a second time -- to prevent
// infinite recusion, we notice that `A` was already pushed
// once and stop.
let mut ty_stack = vec![(for_ty, 0)];
// Set used to detect infinite recursion.
let mut ty_set = FxHashSet();
let fulfill_cx = &mut FulfillmentContext::new();
let cause = ObligationCause::dummy();
while let Some((ty, depth)) = ty_stack.pop() {
let DtorckConstraint {
dtorck_types,
outlives,
overflows,
} = dtorck_constraint_for_ty(tcx, DUMMY_SP, for_ty, depth, ty)?;
// "outlives" represent types/regions that may be touched
// by a destructor.
result.kinds.extend(outlives);
result.overflows.extend(overflows);
// dtorck types are "types that will get dropped but which
// do not themselves define a destructor", more or less. We have
// to push them onto the stack to be expanded.
for ty in dtorck_types {
match infcx.at(&cause, param_env).normalize(&ty) {
Ok(Normalized {
value: ty,
obligations,
}) => {
fulfill_cx.register_predicate_obligations(infcx, obligations);
debug!("dropck_outlives: ty from dtorck_types = {:?}", ty);
match ty.sty {
// All parameters live for the duration of the
// function.
ty::TyParam(..) => {}
// A projection that we couldn't resolve - it
// might have a destructor.
ty::TyProjection(..) | ty::TyAnon(..) => {
result.kinds.push(ty.into());
}
_ => {
if ty_set.insert(ty) {
ty_stack.push((ty, depth + 1));
}
}
}
}
// We don't actually expect to fail to normalize.
// That implies a WF error somewhere else.
Err(NoSolution) => {
return Err(NoSolution);
}
}
}
}
debug!("dropck_outlives: result = {:#?}", result);
util::make_query_response(infcx, canonical_inference_vars, result, fulfill_cx)
})
}
/// Return a set of constraints that needs to be satisfied in
/// order for `ty` to be valid for destruction.
fn dtorck_constraint_for_ty<'a, 'gcx, 'tcx>(
tcx: TyCtxt<'a, 'gcx, 'tcx>,
span: Span,
for_ty: Ty<'tcx>,
depth: usize,
ty: Ty<'tcx>,
) -> Result<DtorckConstraint<'tcx>, NoSolution> {
debug!(
"dtorck_constraint_for_ty({:?}, {:?}, {:?}, {:?})",
span, for_ty, depth, ty
);
if depth >= tcx.sess.recursion_limit.get() {
return Ok(DtorckConstraint {
outlives: vec![],
dtorck_types: vec![],
overflows: vec![ty],
});
}
let result = match ty.sty {
ty::TyBool
| ty::TyChar
| ty::TyInt(_)
| ty::TyUint(_)
| ty::TyFloat(_)
| ty::TyStr
| ty::TyNever
| ty::TyForeign(..)
| ty::TyRawPtr(..)
| ty::TyRef(..)
| ty::TyFnDef(..)
| ty::TyFnPtr(_)
| ty::TyGeneratorWitness(..) => {
// these types never have a destructor
Ok(DtorckConstraint::empty())
}
ty::TyArray(ety, _) | ty::TySlice(ety) => {
// single-element containers, behave like their element
dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ety)
}
ty::TyTuple(tys, _) => tys.iter()
.map(|ty| dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty))
.collect(),
ty::TyClosure(def_id, substs) => substs
.upvar_tys(def_id, tcx)
.map(|ty| dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty))
.collect(),
ty::TyGenerator(def_id, substs, _) => {
// Note that the interior types are ignored here.
// Any type reachable inside the interior must also be reachable
// through the upvars.
substs
.upvar_tys(def_id, tcx)
.map(|ty| dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty))
.collect()
}
ty::TyAdt(def, substs) => {
let DtorckConstraint {
dtorck_types,
outlives,
overflows,
} = tcx.at(span).adt_dtorck_constraint(def.did)?;
Ok(DtorckConstraint {
// FIXME: we can try to recursively `dtorck_constraint_on_ty`
// there, but that needs some way to handle cycles.
dtorck_types: dtorck_types.subst(tcx, substs),
outlives: outlives.subst(tcx, substs),
overflows: overflows.subst(tcx, substs),
})
}
// Objects must be alive in order for their destructor
// to be called.
ty::TyDynamic(..) => Ok(DtorckConstraint {
outlives: vec![ty.into()],
dtorck_types: vec![],
overflows: vec![],
}),
// Types that can't be resolved. Pass them forward.
ty::TyProjection(..) | ty::TyAnon(..) | ty::TyParam(..) => Ok(DtorckConstraint {
outlives: vec![],
dtorck_types: vec![ty],
overflows: vec![],
}),
ty::TyInfer(..) | ty::TyError => {
// By the time this code runs, all type variables ought to
// be fully resolved.
Err(NoSolution)
}
};
debug!("dtorck_constraint_for_ty({:?}) = {:?}", ty, result);
result
}
/// Calculates the dtorck constraint for a type.
crate fn adt_dtorck_constraint<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId,
) -> Result<DtorckConstraint<'tcx>, NoSolution> {
let def = tcx.adt_def(def_id);
let span = tcx.def_span(def_id);
debug!("dtorck_constraint: {:?}", def);
if def.is_phantom_data() {
let result = DtorckConstraint {
outlives: vec![],
dtorck_types: vec![tcx.mk_param_from_def(&tcx.generics_of(def_id).types[0])],
overflows: vec![],
};
debug!("dtorck_constraint: {:?} => {:?}", def, result);
return Ok(result);
}
let mut result = def.all_fields()
.map(|field| tcx.type_of(field.did))
.map(|fty| dtorck_constraint_for_ty(tcx, span, fty, 0, fty))
.collect::<Result<DtorckConstraint, NoSolution>>()?;
result.outlives.extend(tcx.destructor_constraints(def));
dedup_dtorck_constraint(&mut result);
debug!("dtorck_constraint: {:?} => {:?}", def, result);
Ok(result)
}
fn dedup_dtorck_constraint<'tcx>(c: &mut DtorckConstraint<'tcx>) {
let mut outlives = FxHashSet();
let mut dtorck_types = FxHashSet();
c.outlives.retain(|&val| outlives.replace(val).is_none());
c.dtorck_types
.retain(|&val| dtorck_types.replace(val).is_none());
}
+44
View File
@@ -0,0 +1,44 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! New recursive solver modeled on Chalk's recursive solver. Most of
//! the guts are broken up into modules; see the comments in those modules.
#![deny(warnings)]
#![feature(crate_visibility_modifier)]
#![feature(match_default_bindings)]
#![feature(underscore_lifetimes)]
#[macro_use]
extern crate log;
#[macro_use]
extern crate rustc;
extern crate rustc_data_structures;
extern crate syntax;
extern crate syntax_pos;
mod dropck_outlives;
mod normalize_projection_ty;
mod normalize_erasing_regions;
mod util;
use rustc::ty::maps::Providers;
pub fn provide(p: &mut Providers) {
*p = Providers {
dropck_outlives: dropck_outlives::dropck_outlives,
adt_dtorck_constraint: dropck_outlives::adt_dtorck_constraint,
normalize_projection_ty: normalize_projection_ty::normalize_projection_ty,
normalize_ty_after_erasing_regions:
normalize_erasing_regions::normalize_ty_after_erasing_regions,
..*p
};
}
@@ -0,0 +1,62 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use rustc::traits::{Normalized, ObligationCause};
use rustc::traits::query::NoSolution;
use rustc::ty::{self, ParamEnvAnd, Ty, TyCtxt};
use rustc::util::common::CellUsizeExt;
crate fn normalize_ty_after_erasing_regions<'tcx>(
tcx: TyCtxt<'_, 'tcx, 'tcx>,
goal: ParamEnvAnd<'tcx, Ty<'tcx>>,
) -> Ty<'tcx> {
let ParamEnvAnd { param_env, value } = goal;
tcx.sess
.perf_stats
.normalize_ty_after_erasing_regions
.increment();
tcx.infer_ctxt().enter(|infcx| {
let cause = ObligationCause::dummy();
match infcx.at(&cause, param_env).normalize(&value) {
Ok(Normalized {
value: normalized_value,
obligations: normalized_obligations,
}) => {
// We don't care about the `obligations`; they are
// always only region relations, and we are about to
// erase those anyway:
debug_assert_eq!(
normalized_obligations
.iter()
.find(|p| not_outlives_predicate(&p.predicate)),
None,
);
let normalized_value = infcx.resolve_type_vars_if_possible(&normalized_value);
let normalized_value = infcx.tcx.erase_regions(&normalized_value);
tcx.lift_to_global(&normalized_value).unwrap()
}
Err(NoSolution) => bug!("could not fully normalize `{:?}`", value),
}
})
}
fn not_outlives_predicate(p: &ty::Predicate<'_>) -> bool {
match p {
ty::Predicate::RegionOutlives(..) | ty::Predicate::TypeOutlives(..) => false,
ty::Predicate::Trait(..)
| ty::Predicate::Projection(..)
| ty::Predicate::WellFormed(..)
| ty::Predicate::ObjectSafe(..)
| ty::Predicate::ClosureKind(..)
| ty::Predicate::Subtype(..)
| ty::Predicate::ConstEvaluatable(..) => true,
}
}
@@ -0,0 +1,55 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use rustc::infer::canonical::{Canonical, QueryResult};
use rustc::traits::{self, FulfillmentContext, Normalized, ObligationCause,
SelectionContext};
use rustc::traits::query::{CanonicalProjectionGoal, NoSolution, normalize::NormalizationResult};
use rustc::ty::{ParamEnvAnd, TyCtxt};
use rustc::util::common::CellUsizeExt;
use std::rc::Rc;
use syntax::ast::DUMMY_NODE_ID;
use syntax_pos::DUMMY_SP;
use util;
crate fn normalize_projection_ty<'tcx>(
tcx: TyCtxt<'_, 'tcx, 'tcx>,
goal: CanonicalProjectionGoal<'tcx>,
) -> Result<Rc<Canonical<'tcx, QueryResult<'tcx, NormalizationResult<'tcx>>>>, NoSolution> {
debug!("normalize_provider(goal={:#?})", goal);
tcx.sess.perf_stats.normalize_projection_ty.increment();
tcx.infer_ctxt().enter(|ref infcx| {
let (
ParamEnvAnd {
param_env,
value: goal,
},
canonical_inference_vars,
) = infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &goal);
let fulfill_cx = &mut FulfillmentContext::new();
let selcx = &mut SelectionContext::new(infcx);
let cause = ObligationCause::misc(DUMMY_SP, DUMMY_NODE_ID);
let Normalized {
value: answer,
obligations,
} = traits::normalize_projection_type(selcx, param_env, goal, cause, 0);
fulfill_cx.register_predicate_obligations(infcx, obligations);
// Now that we have fulfilled as much as we can, create a solution
// from what we've learned.
util::make_query_response(
infcx,
canonical_inference_vars,
NormalizationResult { normalized_ty: answer },
fulfill_cx,
)
})
}
+117
View File
@@ -0,0 +1,117 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use rustc::infer::InferCtxt;
use rustc::infer::canonical::{CanonicalVarValues, Canonicalize, Certainty, QueryRegionConstraints,
QueryResult};
use rustc::infer::region_constraints::{Constraint, RegionConstraintData};
use rustc::traits::FulfillmentContext;
use rustc::traits::query::NoSolution;
use rustc::ty;
use std::fmt::Debug;
/// The canonicalization form of `QueryResult<'tcx, T>`.
type CanonicalizedQueryResult<'gcx, 'tcx, T> =
<QueryResult<'tcx, T> as Canonicalize<'gcx, 'tcx>>::Canonicalized;
crate fn make_query_response<'gcx, 'tcx, T>(
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
inference_vars: CanonicalVarValues<'tcx>,
answer: T,
fulfill_cx: &mut FulfillmentContext<'tcx>,
) -> Result<CanonicalizedQueryResult<'gcx, 'tcx, T>, NoSolution>
where
T: Debug,
QueryResult<'tcx, T>: Canonicalize<'gcx, 'tcx>,
{
let tcx = infcx.tcx;
debug!(
"make_query_response(\
inference_vars={:?}, \
answer={:?})",
inference_vars, answer,
);
// Select everything, returning errors.
let true_errors = match fulfill_cx.select_where_possible(infcx) {
Ok(()) => vec![],
Err(errors) => errors,
};
debug!("true_errors = {:#?}", true_errors);
if !true_errors.is_empty() {
// FIXME -- we don't indicate *why* we failed to solve
debug!("make_query_response: true_errors={:#?}", true_errors);
return Err(NoSolution);
}
// Anything left unselected *now* must be an ambiguity.
let ambig_errors = match fulfill_cx.select_all_or_error(infcx) {
Ok(()) => vec![],
Err(errors) => errors,
};
debug!("ambig_errors = {:#?}", ambig_errors);
let region_obligations = infcx.take_registered_region_obligations();
let (region_outlives, ty_outlives) = infcx.with_region_constraints(|region_constraints| {
let RegionConstraintData {
constraints,
verifys,
givens,
} = region_constraints;
assert!(verifys.is_empty());
assert!(givens.is_empty());
let region_outlives: Vec<_> = constraints
.into_iter()
.map(|(k, _)| match *k {
Constraint::VarSubVar(v1, v2) => {
(tcx.mk_region(ty::ReVar(v1)), tcx.mk_region(ty::ReVar(v2)))
}
Constraint::VarSubReg(v1, r2) => (tcx.mk_region(ty::ReVar(v1)), r2),
Constraint::RegSubVar(r1, v2) => (r1, tcx.mk_region(ty::ReVar(v2))),
Constraint::RegSubReg(r1, r2) => (r1, r2),
})
.collect();
let ty_outlives: Vec<_> = region_obligations
.into_iter()
.map(|(_, r_o)| (r_o.sup_type, r_o.sub_region))
.collect();
(region_outlives, ty_outlives)
});
let certainty = if ambig_errors.is_empty() {
Certainty::Proven
} else {
Certainty::Ambiguous
};
let (canonical_result, _) = infcx.canonicalize_response(&QueryResult {
var_values: inference_vars,
region_constraints: QueryRegionConstraints {
region_outlives,
ty_outlives,
},
certainty,
value: answer,
});
debug!(
"make_query_response: canonical_result = {:#?}",
canonical_result
);
Ok(canonical_result)
}
+1 -1
View File
@@ -650,7 +650,7 @@ pub fn of_instance(cx: &CodegenCx<'a, 'tcx>, instance: &ty::Instance<'tcx>)
-> Self {
let fn_ty = instance.ty(cx.tcx);
let sig = ty_fn_sig(cx, fn_ty);
let sig = cx.tcx.erase_late_bound_regions_and_normalize(&sig);
let sig = cx.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
FnType::new(cx, sig, &[])
}
+1 -1
View File
@@ -462,7 +462,7 @@ pub fn trans_instance<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, instance: Instance<'tc
let fn_ty = instance.ty(cx.tcx);
let sig = common::ty_fn_sig(cx, fn_ty);
let sig = cx.tcx.erase_late_bound_regions_and_normalize(&sig);
let sig = cx.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
let lldecl = match cx.instances.borrow().get(&instance) {
Some(&val) => val,
+1 -2
View File
@@ -25,7 +25,6 @@
use rustc::hir::def_id::DefId;
use rustc::ty::{self, TypeFoldable};
use rustc::ty::layout::LayoutOf;
use rustc::traits;
use rustc::ty::subst::Substs;
use rustc_back::PanicStrategy;
@@ -185,7 +184,7 @@ pub fn resolve_and_get_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
cx,
ty::Instance::resolve(
cx.tcx,
ty::ParamEnv::empty(traits::Reveal::All),
ty::ParamEnv::reveal_all(),
def_id,
substs
).unwrap()
+3 -4
View File
@@ -25,7 +25,6 @@
use type_::Type;
use type_of::LayoutLlvmExt;
use value::Value;
use rustc::traits;
use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::layout::{HasDataLayout, LayoutOf};
use rustc::hir;
@@ -40,15 +39,15 @@
pub use context::CodegenCx;
pub fn type_needs_drop<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bool {
ty.needs_drop(tcx, ty::ParamEnv::empty(traits::Reveal::All))
ty.needs_drop(tcx, ty::ParamEnv::reveal_all())
}
pub fn type_is_sized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bool {
ty.is_sized(tcx.at(DUMMY_SP), ty::ParamEnv::empty(traits::Reveal::All))
ty.is_sized(tcx.at(DUMMY_SP), ty::ParamEnv::reveal_all())
}
pub fn type_is_freeze<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bool {
ty.is_freeze(tcx, ty::ParamEnv::empty(traits::Reveal::All), DUMMY_SP)
ty.is_freeze(tcx, ty::ParamEnv::reveal_all(), DUMMY_SP)
}
/*
+2 -3
View File
@@ -14,7 +14,6 @@
use rustc::dep_graph::DepGraphSafe;
use rustc::hir;
use rustc::hir::def_id::DefId;
use rustc::traits;
use debuginfo;
use callee;
use base;
@@ -435,7 +434,7 @@ pub fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool {
pub fn type_has_metadata(&self, ty: Ty<'tcx>) -> bool {
use syntax_pos::DUMMY_SP;
if ty.is_sized(self.tcx.at(DUMMY_SP), ty::ParamEnv::empty(traits::Reveal::All)) {
if ty.is_sized(self.tcx.at(DUMMY_SP), ty::ParamEnv::reveal_all()) {
return false;
}
@@ -464,7 +463,7 @@ impl<'a, 'tcx> LayoutOf<Ty<'tcx>> for &'a CodegenCx<'a, 'tcx> {
type TyLayout = TyLayout<'tcx>;
fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
self.tcx.layout_of(ty::ParamEnv::empty(traits::Reveal::All).and(ty))
self.tcx.layout_of(ty::ParamEnv::reveal_all().and(ty))
.unwrap_or_else(|e| match e {
LayoutError::SizeOverflow(_) => self.sess().fatal(&e.to_string()),
_ => bug!("failed to get layout for `{}`: {}", ty, e)
+6 -3
View File
@@ -30,7 +30,7 @@
use rustc::ich::Fingerprint;
use rustc::ty::Instance;
use common::CodegenCx;
use rustc::ty::{self, AdtKind, Ty, TyCtxt};
use rustc::ty::{self, AdtKind, ParamEnv, Ty, TyCtxt};
use rustc::ty::layout::{self, Align, LayoutOf, Size, TyLayout};
use rustc::session::config;
use rustc::util::nodemap::FxHashMap;
@@ -353,7 +353,10 @@ fn subroutine_type_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
span: Span)
-> MetadataCreationResult
{
let signature = cx.tcx.erase_late_bound_regions_and_normalize(&signature);
let signature = cx.tcx.normalize_erasing_late_bound_regions(
ty::ParamEnv::reveal_all(),
&signature,
);
let mut signature_metadata: Vec<DIType> = Vec::with_capacity(signature.inputs().len() + 1);
@@ -589,7 +592,7 @@ pub fn type_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
}
ty::TyGenerator(def_id, substs, _) => {
let upvar_tys : Vec<_> = substs.field_tys(def_id, cx.tcx).map(|t| {
cx.tcx.fully_normalize_associated_types_in(&t)
cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), t)
}).collect();
prepare_tuple_metadata(cx,
t,
+8 -4
View File
@@ -30,7 +30,7 @@
use common::CodegenCx;
use builder::Builder;
use monomorphize::Instance;
use rustc::ty::{self, Ty};
use rustc::ty::{self, ParamEnv, Ty};
use rustc::mir;
use rustc::session::config::{self, FullDebugInfo, LimitedDebugInfo, NoDebugInfo};
use rustc::util::nodemap::{DefIdMap, FxHashMap, FxHashSet};
@@ -378,7 +378,7 @@ fn get_template_parameters<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
name_to_append_suffix_to.push_str(",");
}
let actual_type = cx.tcx.fully_normalize_associated_types_in(&actual_type);
let actual_type = cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), actual_type);
// Add actual type name to <...> clause of function name
let actual_type_name = compute_debuginfo_type_name(cx,
actual_type,
@@ -391,7 +391,7 @@ fn get_template_parameters<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
let template_params: Vec<_> = if cx.sess().opts.debuginfo == FullDebugInfo {
let names = get_type_parameter_names(cx, generics);
substs.types().zip(names).map(|(ty, name)| {
let actual_type = cx.tcx.fully_normalize_associated_types_in(&ty);
let actual_type = cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty);
let actual_type_metadata = type_metadata(cx, actual_type, syntax_pos::DUMMY_SP);
let name = CString::new(name.as_str().as_bytes()).unwrap();
unsafe {
@@ -429,7 +429,11 @@ fn get_containing_scope<'cx, 'tcx>(cx: &CodegenCx<'cx, 'tcx>,
let self_type = cx.tcx.impl_of_method(instance.def_id()).and_then(|impl_def_id| {
// If the method does *not* belong to a trait, proceed
if cx.tcx.trait_id_of_impl(impl_def_id).is_none() {
let impl_self_ty = cx.tcx.trans_impl_self_ty(impl_def_id, instance.substs);
let impl_self_ty = cx.tcx.subst_and_normalize_erasing_regions(
instance.substs,
ty::ParamEnv::reveal_all(),
&cx.tcx.type_of(impl_def_id),
);
// Only "class" methods are generally understood by LLVM,
// so avoid methods on other types (e.g. `<*mut T>::null`).
+5 -3
View File
@@ -117,8 +117,10 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
},
ty::TyDynamic(ref trait_data, ..) => {
if let Some(principal) = trait_data.principal() {
let principal = cx.tcx.erase_late_bound_regions_and_normalize(
&principal);
let principal = cx.tcx.normalize_erasing_late_bound_regions(
ty::ParamEnv::reveal_all(),
&principal,
);
push_item_name(cx, principal.def_id, false, output);
push_type_params(cx, principal.substs, output);
}
@@ -138,7 +140,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
output.push_str("fn(");
let sig = cx.tcx.erase_late_bound_regions_and_normalize(&sig);
let sig = cx.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
if !sig.inputs().is_empty() {
for &parameter_type in sig.inputs() {
push_debuginfo_type_name(cx, parameter_type, true, output);
+2 -2
View File
@@ -22,7 +22,7 @@
use llvm::{self, ValueRef};
use llvm::AttributePlace::Function;
use rustc::ty::Ty;
use rustc::ty::{self, Ty};
use rustc::session::config::Sanitizer;
use rustc_back::PanicStrategy;
use abi::{Abi, FnType};
@@ -127,7 +127,7 @@ pub fn declare_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, name: &str,
fn_type: Ty<'tcx>) -> ValueRef {
debug!("declare_rust_fn(name={:?}, fn_type={:?})", name, fn_type);
let sig = common::ty_fn_sig(cx, fn_type);
let sig = cx.tcx.erase_late_bound_regions_and_normalize(&sig);
let sig = cx.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
debug!("declare_rust_fn (after region erasure) sig={:?}", sig);
let fty = FnType::new(cx, sig, &[]);
+5 -2
View File
@@ -100,7 +100,7 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bx: &Builder<'a, 'tcx>,
};
let sig = callee_ty.fn_sig(tcx);
let sig = tcx.erase_late_bound_regions_and_normalize(&sig);
let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
let arg_tys = sig.inputs();
let ret_ty = sig.output();
let name = &*tcx.item_name(def_id);
@@ -1035,7 +1035,10 @@ macro_rules! require_simd {
let tcx = bx.tcx();
let sig = tcx.erase_late_bound_regions_and_normalize(&callee_ty.fn_sig(tcx));
let sig = tcx.normalize_erasing_late_bound_regions(
ty::ParamEnv::reveal_all(),
&callee_ty.fn_sig(tcx),
);
let arg_tys = sig.inputs();
// every intrinsic takes a SIMD vector as its first argument
+9 -4
View File
@@ -12,7 +12,6 @@
use rustc::middle::lang_items;
use rustc::ty::{self, TypeFoldable};
use rustc::ty::layout::{self, LayoutOf};
use rustc::traits;
use rustc::mir;
use abi::{Abi, FnType, ArgType, PassMode};
use base;
@@ -282,7 +281,10 @@ fn trans_terminator(&mut self,
ty::TyDynamic(..) => {
let fn_ty = drop_fn.ty(bx.cx.tcx);
let sig = common::ty_fn_sig(bx.cx, fn_ty);
let sig = bx.tcx().erase_late_bound_regions_and_normalize(&sig);
let sig = bx.tcx().normalize_erasing_late_bound_regions(
ty::ParamEnv::reveal_all(),
&sig,
);
let fn_ty = FnType::new_vtable(bx.cx, sig, &[]);
args = &args[..1];
(meth::DESTRUCTOR.get_fn(&bx, place.llextra, &fn_ty), fn_ty)
@@ -419,7 +421,7 @@ fn trans_terminator(&mut self,
let (instance, mut llfn) = match callee.layout.ty.sty {
ty::TyFnDef(def_id, substs) => {
(Some(ty::Instance::resolve(bx.cx.tcx,
ty::ParamEnv::empty(traits::Reveal::All),
ty::ParamEnv::reveal_all(),
def_id,
substs).unwrap()),
None)
@@ -431,7 +433,10 @@ fn trans_terminator(&mut self,
};
let def = instance.map(|i| i.def);
let sig = callee.layout.ty.fn_sig(bx.tcx());
let sig = bx.tcx().erase_late_bound_regions_and_normalize(&sig);
let sig = bx.tcx().normalize_erasing_late_bound_regions(
ty::ParamEnv::reveal_all(),
&sig,
);
let abi = sig.abi;
// Handle intrinsics old trans wants Expr's for, ourselves.
+4 -5
View File
@@ -12,7 +12,6 @@
use rustc::middle::const_val::{ConstVal, ConstEvalErr};
use rustc_mir::interpret::{read_target_uint, const_val_field};
use rustc::hir::def_id::DefId;
use rustc::traits;
use rustc::mir;
use rustc_data_structures::indexed_vec::Idx;
use rustc::mir::interpret::{Allocation, GlobalId, MemoryPointer, PrimVal, Value as MiriValue};
@@ -126,7 +125,7 @@ pub fn trans_static_initializer<'a, 'tcx>(
instance,
promoted: None
};
let param_env = ty::ParamEnv::empty(traits::Reveal::All);
let param_env = ty::ParamEnv::reveal_all();
cx.tcx.const_eval(param_env.and(cid))?;
let alloc_id = cx
@@ -152,7 +151,7 @@ fn const_to_miri_value(
match constant.val {
ConstVal::Unevaluated(def_id, ref substs) => {
let tcx = bx.tcx();
let param_env = ty::ParamEnv::empty(traits::Reveal::All);
let param_env = ty::ParamEnv::reveal_all();
let instance = ty::Instance::resolve(tcx, param_env, def_id, substs).unwrap();
let cid = GlobalId {
instance,
@@ -172,7 +171,7 @@ pub fn mir_constant_to_miri_value(
) -> Result<MiriValue, ConstEvalErr<'tcx>> {
match constant.literal {
mir::Literal::Promoted { index } => {
let param_env = ty::ParamEnv::empty(traits::Reveal::All);
let param_env = ty::ParamEnv::reveal_all();
let cid = mir::interpret::GlobalId {
instance: self.instance,
promoted: Some(index),
@@ -201,7 +200,7 @@ pub fn simd_shuffle_indices(
let values: Result<Vec<ValueRef>, _> = (0..fields).map(|field| {
let field = const_val_field(
bx.tcx(),
ty::ParamEnv::empty(traits::Reveal::All),
ty::ParamEnv::reveal_all(),
self.instance,
None,
mir::Field::new(field as usize),
+6 -3
View File
@@ -16,7 +16,6 @@
use rustc::ty::layout::{LayoutOf, TyLayout};
use rustc::mir::{self, Mir};
use rustc::ty::subst::Substs;
use rustc::infer::TransNormalize;
use rustc::session::config::FullDebugInfo;
use base;
use builder::Builder;
@@ -108,9 +107,13 @@ pub struct FunctionCx<'a, 'tcx:'a> {
impl<'a, 'tcx> FunctionCx<'a, 'tcx> {
pub fn monomorphize<T>(&self, value: &T) -> T
where T: TransNormalize<'tcx>
where T: TypeFoldable<'tcx>
{
self.cx.tcx.trans_apply_param_substs(self.param_substs, value)
self.cx.tcx.subst_and_normalize_erasing_regions(
self.param_substs,
ty::ParamEnv::reveal_all(),
value,
)
}
pub fn set_debug_loc(&mut self, bx: &Builder, source_info: mir::SourceInfo) {
+4 -1
View File
@@ -258,7 +258,10 @@ fn llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> Type {
cx.layout_of(self.ty.boxed_ty()).llvm_type(cx).ptr_to()
}
ty::TyFnPtr(sig) => {
let sig = cx.tcx.erase_late_bound_regions_and_normalize(&sig);
let sig = cx.tcx.normalize_erasing_late_bound_regions(
ty::ParamEnv::reveal_all(),
&sig,
);
FnType::new(cx, sig, &[]).llvm_type(cx).ptr_to()
}
_ => self.scalar_llvm_type_at(cx, scalar, Size::from_bytes(0))
+2 -2
View File
@@ -501,7 +501,7 @@ fn compare_self_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
ty::TraitContainer(_) => tcx.mk_self_type()
};
let self_arg_ty = *tcx.fn_sig(method.def_id).input(0).skip_binder();
let param_env = ty::ParamEnv::empty(Reveal::All);
let param_env = ty::ParamEnv::reveal_all();
tcx.infer_ctxt().enter(|infcx| {
let self_arg_ty = tcx.liberate_late_bound_regions(
@@ -759,7 +759,7 @@ pub fn compare_const_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
debug!("compare_const_impl(impl_trait_ref={:?})", impl_trait_ref);
tcx.infer_ctxt().enter(|infcx| {
let param_env = ty::ParamEnv::empty(Reveal::UserFacing);
let param_env = ty::ParamEnv::empty();
let inh = Inherited::new(infcx, impl_c.def_id);
let infcx = &inh.infcx;
+12 -42
View File
@@ -16,10 +16,10 @@
use rustc::middle::region;
use rustc::ty::subst::{Subst, Substs, UnpackedKind};
use rustc::ty::{self, Ty, TyCtxt};
use rustc::traits::{self, Reveal, ObligationCause};
use rustc::traits::{self, ObligationCause};
use util::common::ErrorReported;
use util::nodemap::FxHashSet;
use syntax::ast;
use syntax_pos::Span;
/// check_drop_impl confirms that the Drop implementation identified by
@@ -126,7 +126,7 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>(
// it did the wrong thing, so I chose to preserve existing
// behavior, since it ought to be simply more
// conservative. -nmatsakis
let outlives_env = OutlivesEnvironment::new(ty::ParamEnv::empty(Reveal::UserFacing));
let outlives_env = OutlivesEnvironment::new(ty::ParamEnv::empty());
infcx.resolve_regions_and_report_errors(drop_impl_did, &region_scope_tree, &outlives_env);
Ok(())
@@ -282,6 +282,7 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'gcx, 'tcx>(
rcx: &mut RegionCtxt<'a, 'gcx, 'tcx>,
ty: Ty<'tcx>,
span: Span,
body_id: ast::NodeId,
scope: region::Scope)
-> Result<(), ErrorReported>
{
@@ -297,46 +298,15 @@ pub fn check_safety_of_destructor_if_necessary<'a, 'gcx, 'tcx>(
};
let parent_scope = rcx.tcx.mk_region(ty::ReScope(parent_scope));
let origin = || infer::SubregionOrigin::SafeDestructor(span);
let ty = rcx.fcx.resolve_type_vars_if_possible(&ty);
let for_ty = ty;
let mut types = vec![(ty, 0)];
let mut known = FxHashSet();
while let Some((ty, depth)) = types.pop() {
let ty::DtorckConstraint {
dtorck_types, outlives
} = rcx.tcx.dtorck_constraint_for_ty(span, for_ty, depth, ty)?;
for ty in dtorck_types {
let ty = rcx.fcx.normalize_associated_types_in(span, &ty);
let ty = rcx.fcx.resolve_type_vars_with_obligations(ty);
let ty = rcx.fcx.resolve_type_and_region_vars_if_possible(&ty);
match ty.sty {
// All parameters live for the duration of the
// function.
ty::TyParam(..) => {}
// A projection that we couldn't resolve - it
// might have a destructor.
ty::TyProjection(..) | ty::TyAnon(..) => {
rcx.type_must_outlive(origin(), ty, parent_scope);
}
_ => {
if let None = known.replace(ty) {
types.push((ty, depth+1));
}
}
}
}
for outlive in outlives {
match outlive.unpack() {
UnpackedKind::Lifetime(lt) => rcx.sub_regions(origin(), parent_scope, lt),
UnpackedKind::Type(ty) => rcx.type_must_outlive(origin(), ty, parent_scope),
}
let cause = &ObligationCause::misc(span, body_id);
let infer_ok = rcx.infcx.at(cause, rcx.fcx.param_env).dropck_outlives(ty);
debug!("dropck_outlives = {:#?}", infer_ok);
let kinds = rcx.fcx.register_infer_ok_obligations(infer_ok);
for kind in kinds {
match kind.unpack() {
UnpackedKind::Lifetime(r) => rcx.sub_regions(origin(), parent_scope, r),
UnpackedKind::Type(ty) => rcx.type_must_outlive(origin(), ty, parent_scope),
}
}
Ok(())
}
+1 -1
View File
@@ -3997,7 +3997,7 @@ fn check_expr_kind(&self,
}
hir::ExprRepeat(ref element, count) => {
let count_def_id = tcx.hir.body_owner_def_id(count);
let param_env = ty::ParamEnv::empty(traits::Reveal::UserFacing);
let param_env = ty::ParamEnv::empty();
let substs = Substs::identity_for_item(tcx.global_tcx(), count_def_id);
let instance = ty::Instance::resolve(
tcx.global_tcx(),
+4 -2
View File
@@ -411,8 +411,9 @@ fn constrain_bindings_in_pat(&mut self, pat: &hir::Pat) {
self.type_of_node_must_outlive(origin, hir_id, var_region);
let typ = self.resolve_node_type(hir_id);
let body_id = self.body_id;
let _ = dropck::check_safety_of_destructor_if_necessary(
self, typ, span, var_scope);
self, typ, span, body_id, var_scope);
})
}
}
@@ -884,8 +885,9 @@ fn check_safety_of_rvalue_destructor_if_necessary(&mut self,
match *region {
ty::ReScope(rvalue_scope) => {
let typ = self.resolve_type(cmt.ty);
let body_id = self.body_id;
let _ = dropck::check_safety_of_destructor_if_necessary(
self, typ, span, rvalue_scope);
self, typ, span, body_id, rvalue_scope);
}
ty::ReStatic => {}
_ => {

Some files were not shown because too many files have changed in this diff Show More