mirror of
https://github.com/rust-lang/rust.git
synced 2026-05-29 20:46:07 +03:00
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:
Generated
+14
@@ -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"
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
});
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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]
|
||||
}
|
||||
}
|
||||
@@ -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),
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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)]
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)*
|
||||
)
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -76,3 +76,7 @@ fn calculate_predecessors(mir: &Mir) -> IndexVec<BasicBlock, Vec<BasicBlock>> {
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
CloneTypeFoldableAndLiftImpls! {
|
||||
Cache,
|
||||
}
|
||||
|
||||
+65
-123
@@ -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
@@ -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 },
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
@@ -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 { });
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
@@ -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(_)) |
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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());
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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> {
|
||||
|
||||
@@ -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 |
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(..) |
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#![feature(slice_patterns)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(box_syntax)]
|
||||
#![feature(macro_lifetime_matcher)]
|
||||
#![feature(i128_type)]
|
||||
#![feature(from_ref)]
|
||||
|
||||
|
||||
@@ -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)>
|
||||
|
||||
@@ -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" }
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 => {}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 ¶meter_type in sig.inputs() {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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(),
|
||||
};
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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" }
|
||||
@@ -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());
|
||||
}
|
||||
@@ -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,
|
||||
)
|
||||
})
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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, &[])
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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`).
|
||||
|
||||
@@ -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 ¶meter_type in sig.inputs() {
|
||||
push_debuginfo_type_name(cx, parameter_type, true, output);
|
||||
|
||||
@@ -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, &[]);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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, ®ion_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(())
|
||||
}
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user