Auto merge of #42189 - nikomatsakis:chalk-trait-env-param-env, r=eddyb

querify layout and move param env out of the infcx

The main goal of this PR is to move the parameter environment *out* of the inference context. This is because the inference environment will soon be changing over the course of inference --- for example, when we enter into a `for<'a> fn(...)` type, we will push a new environment with an increasing universe index, rather than skolemizing the `'a` references. Similarly, each obligation will soon be able to have a distinct parameter environment, and therefore the `Obligation` struct is extended to carry a `ParamEnv<'tcx>`. (I debated about putting it into the cause; seems plausible, but also weird.)

Along the way, I also reworked how layout works, moving the layout cache into a proper query along the lines of needs-drop and friends.

Finally, tweaks the inference context API. It seemed to be accumulating parameters at an alarming rate. The main way to e.g. make a subtype or equality relationship is to do the following:

    infcx.at(cause, param_env).sub(a, b)
    infcx.at(cause, param_env).eq(a, b)

In both cases, `a` is considered the "expected" type (this used to be specified by a boolean). I tried hard to preserve the existing notion of what was "expected", although in some cases I'm not convinced it was being set on purpose one way or the other. This is why in some cases you will see me do `sup(b, a)`, which is otherwise equivalent to `sub(a, b)`, but sets the "expected type" differently.

r? @eddyb
cc @arielb1
This commit is contained in:
bors 2017-06-02 19:23:14 +00:00
commit 107bd67ef7
64 changed files with 1573 additions and 1040 deletions

View File

@ -112,6 +112,7 @@ pub enum DepNode<D: Clone + Debug> {
IsSized(D),
IsFreeze(D),
NeedsDrop(D),
Layout(D),
// The set of impls for a given trait. Ultimately, it would be
// nice to get more fine-grained here (e.g., to include a
@ -241,6 +242,7 @@ impl<D: Clone + Debug> DepNode<D> {
IsSized(ref d) => op(d).map(IsSized),
IsFreeze(ref d) => op(d).map(IsFreeze),
NeedsDrop(ref d) => op(d).map(NeedsDrop),
Layout(ref d) => op(d).map(Layout),
Hir(ref d) => op(d).map(Hir),
HirBody(ref d) => op(d).map(HirBody),
MetaData(ref d) => op(d).map(MetaData),

310
src/librustc/infer/at.rs Normal file
View File

@ -0,0 +1,310 @@
// Copyright 2012-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.
//! A nice interface for working with the infcx. The basic idea is to
//! do `infcx.at(cause, param_env)`, which sets the "cause" of the
//! operation as well as the surrounding parameter environment. Then
//! you can do something like `.sub(a, b)` or `.eq(a, b)` to create a
//! subtype or equality relationship respectively. The first argument
//! is always the "expected" output from the POV of diagnostics.
//!
//! Examples:
//!
//! infcx.at(cause, param_env).sub(a, b)
//! // requires that `a <: b`, with `a` considered the "expected" type
//!
//! infcx.at(cause, param_env).sup(a, b)
//! // requires that `b <: a`, with `a` considered the "expected" type
//!
//! infcx.at(cause, param_env).eq(a, b)
//! // requires that `a == b`, with `a` considered the "expected" type
//!
//! For finer-grained control, you can also do use `trace`:
//!
//! infcx.at(...).trace(a, b).sub(&c, &d)
//!
//! This will set `a` and `b` as the "root" values for
//! error-reporting, but actually operate on `c` and `d`. This is
//! sometimes useful when the types of `c` and `d` are not traceable
//! things. (That system should probably be refactored.)
use super::*;
use ty::relate::{Relate, TypeRelation};
pub struct At<'a, 'gcx: 'tcx, 'tcx: 'a> {
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
cause: &'a ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
}
pub struct Trace<'a, 'gcx: 'tcx, 'tcx: 'a> {
at: At<'a, 'gcx, 'tcx>,
a_is_expected: bool,
trace: TypeTrace<'tcx>,
}
impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
pub fn at(&'a self,
cause: &'a ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>)
-> At<'a, 'gcx, 'tcx>
{
At { infcx: self, cause, param_env }
}
}
pub trait ToTrace<'tcx>: Relate<'tcx> + Copy {
fn to_trace(cause: &ObligationCause<'tcx>,
a_is_expected: bool,
a: Self,
b: Self)
-> TypeTrace<'tcx>;
}
impl<'a, 'gcx, 'tcx> At<'a, 'gcx, 'tcx> {
/// Hacky routine for equating two impl headers in coherence.
pub fn eq_impl_headers(self,
expected: &ty::ImplHeader<'tcx>,
actual: &ty::ImplHeader<'tcx>)
-> InferResult<'tcx, ()>
{
debug!("eq_impl_header({:?} = {:?})", expected, actual);
match (expected.trait_ref, actual.trait_ref) {
(Some(a_ref), Some(b_ref)) =>
self.eq(a_ref, b_ref),
(None, None) =>
self.eq(expected.self_ty, actual.self_ty),
_ =>
bug!("mk_eq_impl_headers given mismatched impl kinds"),
}
}
/// Make `a <: b` where `a` may or may not be expected
pub fn sub_exp<T>(self,
a_is_expected: bool,
a: T,
b: T)
-> InferResult<'tcx, ()>
where T: ToTrace<'tcx>
{
self.trace_exp(a_is_expected, a, b).sub(&a, &b)
}
/// Make `actual <: expected`. For example, if type-checking a
/// call like `foo(x)`, where `foo: fn(i32)`, you might have
/// `sup(i32, x)`, since the "expected" type is the type that
/// appears in the signature.
pub fn sup<T>(self,
expected: T,
actual: T)
-> InferResult<'tcx, ()>
where T: ToTrace<'tcx>
{
self.sub_exp(false, actual, expected)
}
/// Make `expected <: actual`
pub fn sub<T>(self,
expected: T,
actual: T)
-> InferResult<'tcx, ()>
where T: ToTrace<'tcx>
{
self.sub_exp(true, expected, actual)
}
/// Make `expected <: actual`
pub fn eq_exp<T>(self,
a_is_expected: bool,
a: T,
b: T)
-> InferResult<'tcx, ()>
where T: ToTrace<'tcx>
{
self.trace_exp(a_is_expected, a, b).eq(&a, &b)
}
/// Make `expected <: actual`
pub fn eq<T>(self,
expected: T,
actual: T)
-> InferResult<'tcx, ()>
where T: ToTrace<'tcx>
{
self.trace(expected, actual).eq(&expected, &actual)
}
/// Compute the least-upper-bound, or mutual supertype, of two
/// values. The order of the arguments doesn't matter, but since
/// this can result in an error (e.g., if asked to compute LUB of
/// u32 and i32), it is meaningful to call one of them the
/// "expected type".
pub fn lub<T>(self,
expected: T,
actual: T)
-> InferResult<'tcx, T>
where T: ToTrace<'tcx>
{
self.trace(expected, actual).lub(&expected, &actual)
}
/// Compute the greatest-lower-bound, or mutual subtype, of two
/// values. As with `lub` order doesn't matter, except for error
/// cases.
pub fn glb<T>(self,
expected: T,
actual: T)
-> InferResult<'tcx, T>
where T: ToTrace<'tcx>
{
self.trace(expected, actual).glb(&expected, &actual)
}
/// Sets the "trace" values that will be used for
/// error-repporting, but doesn't actually perform any operation
/// yet (this is useful when you want to set the trace using
/// distinct values from those you wish to operate upon).
pub fn trace<T>(self,
expected: T,
actual: T)
-> Trace<'a, 'gcx, 'tcx>
where T: ToTrace<'tcx>
{
self.trace_exp(true, expected, actual)
}
/// Like `trace`, but the expected value is determined by the
/// boolean argument (if true, then the first argument `a` is the
/// "expected" value).
pub fn trace_exp<T>(self,
a_is_expected: bool,
a: T,
b: T)
-> Trace<'a, 'gcx, 'tcx>
where T: ToTrace<'tcx>
{
let trace = ToTrace::to_trace(self.cause, a_is_expected, a, b);
Trace { at: self, trace: trace, a_is_expected }
}
}
impl<'a, 'gcx, 'tcx> Trace<'a, 'gcx, 'tcx> {
/// Make `a <: b` where `a` may or may not be expected (if
/// `a_is_expected` is true, then `a` is expected).
/// Make `expected <: actual`
pub fn sub<T>(self,
a: &T,
b: &T)
-> InferResult<'tcx, ()>
where T: Relate<'tcx>
{
debug!("sub({:?} <: {:?})", a, b);
let Trace { at, trace, a_is_expected } = self;
at.infcx.commit_if_ok(|_| {
let mut fields = at.infcx.combine_fields(trace, at.param_env);
fields.sub(a_is_expected)
.relate(a, b)
.map(move |_| InferOk { value: (), obligations: fields.obligations })
})
}
/// Make `a == b`; the expectation is set by the call to
/// `trace()`.
pub fn eq<T>(self,
a: &T,
b: &T)
-> InferResult<'tcx, ()>
where T: Relate<'tcx>
{
debug!("eq({:?} == {:?})", a, b);
let Trace { at, trace, a_is_expected } = self;
at.infcx.commit_if_ok(|_| {
let mut fields = at.infcx.combine_fields(trace, at.param_env);
fields.equate(a_is_expected)
.relate(a, b)
.map(move |_| InferOk { value: (), obligations: fields.obligations })
})
}
pub fn lub<T>(self,
a: &T,
b: &T)
-> InferResult<'tcx, T>
where T: Relate<'tcx>
{
debug!("lub({:?} \\/ {:?})", a, b);
let Trace { at, trace, a_is_expected } = self;
at.infcx.commit_if_ok(|_| {
let mut fields = at.infcx.combine_fields(trace, at.param_env);
fields.lub(a_is_expected)
.relate(a, b)
.map(move |t| InferOk { value: t, obligations: fields.obligations })
})
}
pub fn glb<T>(self,
a: &T,
b: &T)
-> InferResult<'tcx, T>
where T: Relate<'tcx>
{
debug!("glb({:?} /\\ {:?})", a, b);
let Trace { at, trace, a_is_expected } = self;
at.infcx.commit_if_ok(|_| {
let mut fields = at.infcx.combine_fields(trace, at.param_env);
fields.glb(a_is_expected)
.relate(a, b)
.map(move |t| InferOk { value: t, obligations: fields.obligations })
})
}
}
impl<'tcx> ToTrace<'tcx> for Ty<'tcx> {
fn to_trace(cause: &ObligationCause<'tcx>,
a_is_expected: bool,
a: Self,
b: Self)
-> TypeTrace<'tcx>
{
TypeTrace {
cause: cause.clone(),
values: Types(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,
a: Self,
b: Self)
-> TypeTrace<'tcx>
{
TypeTrace {
cause: cause.clone(),
values: TraitRefs(ExpectedFound::new(a_is_expected, a, b))
}
}
}
impl<'tcx> ToTrace<'tcx> for ty::PolyTraitRef<'tcx> {
fn to_trace(cause: &ObligationCause<'tcx>,
a_is_expected: bool,
a: Self,
b: Self)
-> TypeTrace<'tcx>
{
TypeTrace {
cause: cause.clone(),
values: PolyTraitRefs(ExpectedFound::new(a_is_expected, a, b))
}
}
}

View File

@ -55,6 +55,7 @@ pub struct CombineFields<'infcx, 'gcx: 'infcx+'tcx, 'tcx: 'infcx> {
pub infcx: &'infcx InferCtxt<'infcx, 'gcx, 'tcx>,
pub trace: TypeTrace<'tcx>,
pub cause: Option<ty::relate::Cause>,
pub param_env: ty::ParamEnv<'tcx>,
pub obligations: PredicateObligations<'tcx>,
}
@ -215,6 +216,7 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> {
if needs_wf {
self.obligations.push(Obligation::new(self.trace.cause.clone(),
self.param_env,
ty::Predicate::WellFormed(b_ty)));
}

View File

@ -31,7 +31,7 @@ use ty::{TyVid, IntVid, FloatVid};
use ty::{self, Ty, TyCtxt};
use ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric};
use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
use ty::relate::{Relate, RelateResult, TypeRelation};
use ty::relate::RelateResult;
use traits::{self, ObligationCause, PredicateObligations, Reveal};
use rustc_data_structures::unify::{self, UnificationTable};
use std::cell::{Cell, RefCell, Ref, RefMut};
@ -49,6 +49,7 @@ use self::region_inference::{RegionVarBindings, RegionSnapshot};
use self::type_variable::TypeVariableOrigin;
use self::unify_key::ToType;
pub mod at;
mod combine;
mod equate;
pub mod error_reporting;
@ -161,8 +162,6 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
// For region variables.
region_vars: RegionVarBindings<'a, 'gcx, 'tcx>,
pub param_env: ty::ParamEnv<'gcx>,
/// Caches the results of trait selection. This cache is used
/// for things that have to do with the parameters in scope.
pub selection_cache: traits::SelectionCache<'tcx>,
@ -174,11 +173,6 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
// avoid reporting the same error twice.
pub reported_trait_errors: RefCell<FxHashSet<traits::TraitErrorKey<'tcx>>>,
// Sadly, the behavior of projection varies a bit depending on the
// stage of compilation. The specifics are given in the
// documentation for `Reveal`.
projection_mode: Reveal,
// When an error occurs, we want to avoid reporting "derived"
// errors that are due to this original failure. Normally, we
// handle this with the `err_count_on_creation` count, which
@ -405,55 +399,39 @@ impl fmt::Display for FixupError {
pub trait InferEnv<'a, 'tcx> {
fn to_parts(self, tcx: TyCtxt<'a, 'tcx, 'tcx>)
-> (Option<&'a ty::TypeckTables<'tcx>>,
Option<ty::TypeckTables<'tcx>>,
Option<ty::ParamEnv<'tcx>>);
Option<ty::TypeckTables<'tcx>>);
}
impl<'a, 'tcx> InferEnv<'a, 'tcx> for () {
fn to_parts(self, _: TyCtxt<'a, 'tcx, 'tcx>)
-> (Option<&'a ty::TypeckTables<'tcx>>,
Option<ty::TypeckTables<'tcx>>,
Option<ty::ParamEnv<'tcx>>) {
(None, None, None)
Option<ty::TypeckTables<'tcx>>) {
(None, None)
}
}
impl<'a, 'tcx> InferEnv<'a, 'tcx> for ty::ParamEnv<'tcx> {
impl<'a, 'tcx> InferEnv<'a, 'tcx> for &'a ty::TypeckTables<'tcx> {
fn to_parts(self, _: TyCtxt<'a, 'tcx, 'tcx>)
-> (Option<&'a ty::TypeckTables<'tcx>>,
Option<ty::TypeckTables<'tcx>>,
Option<ty::ParamEnv<'tcx>>) {
(None, None, Some(self))
Option<ty::TypeckTables<'tcx>>) {
(Some(self), None)
}
}
impl<'a, 'tcx> InferEnv<'a, 'tcx> for (&'a ty::TypeckTables<'tcx>, ty::ParamEnv<'tcx>) {
impl<'a, 'tcx> InferEnv<'a, 'tcx> for ty::TypeckTables<'tcx> {
fn to_parts(self, _: TyCtxt<'a, 'tcx, 'tcx>)
-> (Option<&'a ty::TypeckTables<'tcx>>,
Option<ty::TypeckTables<'tcx>>,
Option<ty::ParamEnv<'tcx>>) {
(Some(self.0), None, Some(self.1))
}
}
impl<'a, 'tcx> InferEnv<'a, 'tcx> for (ty::TypeckTables<'tcx>, ty::ParamEnv<'tcx>) {
fn to_parts(self, _: TyCtxt<'a, 'tcx, 'tcx>)
-> (Option<&'a ty::TypeckTables<'tcx>>,
Option<ty::TypeckTables<'tcx>>,
Option<ty::ParamEnv<'tcx>>) {
(None, Some(self.0), Some(self.1))
Option<ty::TypeckTables<'tcx>>) {
(None, Some(self))
}
}
impl<'a, 'tcx> InferEnv<'a, 'tcx> for hir::BodyId {
fn to_parts(self, tcx: TyCtxt<'a, 'tcx, 'tcx>)
-> (Option<&'a ty::TypeckTables<'tcx>>,
Option<ty::TypeckTables<'tcx>>,
Option<ty::ParamEnv<'tcx>>) {
Option<ty::TypeckTables<'tcx>>) {
let def_id = tcx.hir.body_owner_def_id(self);
(Some(tcx.typeck_tables_of(def_id)),
None,
Some(tcx.param_env(def_id)))
(Some(tcx.typeck_tables_of(def_id)), None)
}
}
@ -465,23 +443,16 @@ pub struct InferCtxtBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
arena: DroplessArena,
fresh_tables: Option<RefCell<ty::TypeckTables<'tcx>>>,
tables: Option<&'a ty::TypeckTables<'gcx>>,
param_env: Option<ty::ParamEnv<'gcx>>,
projection_mode: Reveal,
}
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> {
pub fn infer_ctxt<E: InferEnv<'a, 'gcx>>(self,
env: E,
projection_mode: Reveal)
-> InferCtxtBuilder<'a, 'gcx, 'tcx> {
let (tables, fresh_tables, param_env) = env.to_parts(self);
pub fn infer_ctxt<E: InferEnv<'a, 'gcx>>(self, env: E) -> InferCtxtBuilder<'a, 'gcx, 'tcx> {
let (tables, fresh_tables) = env.to_parts(self);
InferCtxtBuilder {
global_tcx: self,
arena: DroplessArena::new(),
fresh_tables: fresh_tables.map(RefCell::new),
tables: tables,
param_env: param_env,
projection_mode: projection_mode,
}
}
@ -490,7 +461,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> {
/// If any inference functionality is used, ICEs will occur.
pub fn borrowck_fake_infer_ctxt(self, body: hir::BodyId)
-> InferCtxt<'a, 'gcx, 'gcx> {
let (tables, _, param_env) = body.to_parts(self);
let (tables, _) = body.to_parts(self);
InferCtxt {
tcx: self,
tables: InferTables::Interned(tables.unwrap()),
@ -498,12 +469,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> {
int_unification_table: RefCell::new(UnificationTable::new()),
float_unification_table: RefCell::new(UnificationTable::new()),
region_vars: RegionVarBindings::new(self),
param_env: param_env.unwrap(),
selection_cache: traits::SelectionCache::new(),
evaluation_cache: traits::EvaluationCache::new(),
projection_cache: RefCell::new(traits::ProjectionCache::new()),
reported_trait_errors: RefCell::new(FxHashSet()),
projection_mode: Reveal::UserFacing,
tainted_by_errors_flag: Cell::new(false),
err_count_on_creation: self.sess.err_count(),
in_snapshot: Cell::new(false),
@ -520,13 +489,10 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> {
ref arena,
ref fresh_tables,
tables,
ref mut param_env,
projection_mode,
} = *self;
let tables = tables.map(InferTables::Interned).unwrap_or_else(|| {
fresh_tables.as_ref().map_or(InferTables::Missing, InferTables::InProgress)
});
let param_env = param_env.take().unwrap_or_else(|| ty::ParamEnv::empty());
global_tcx.enter_local(arena, |tcx| f(InferCtxt {
tcx: tcx,
tables: tables,
@ -535,11 +501,9 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> {
int_unification_table: RefCell::new(UnificationTable::new()),
float_unification_table: RefCell::new(UnificationTable::new()),
region_vars: RegionVarBindings::new(tcx),
param_env: param_env,
selection_cache: traits::SelectionCache::new(),
evaluation_cache: traits::EvaluationCache::new(),
reported_trait_errors: RefCell::new(FxHashSet()),
projection_mode: projection_mode,
tainted_by_errors_flag: Cell::new(false),
err_count_on_creation: tcx.sess.err_count(),
in_snapshot: Cell::new(false),
@ -577,7 +541,10 @@ pub struct CombinedSnapshot<'a, 'tcx:'a> {
/// 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>) -> Self;
fn trans_normalize<'a, 'tcx>(&self,
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>)
-> Self;
}
macro_rules! items { ($($item:item)+) => ($($item)+) }
@ -585,9 +552,10 @@ 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>)
infcx: &InferCtxt<'a, $lt_gcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>)
-> Self {
infcx.normalize_projections_in(self)
infcx.normalize_projections_in(param_env, self)
}
})+);
}
@ -604,13 +572,16 @@ impl_trans_normalize!('gcx,
);
impl<'gcx> TransNormalize<'gcx> for LvalueTy<'gcx> {
fn trans_normalize<'a, 'tcx>(&self, infcx: &InferCtxt<'a, 'gcx, 'tcx>) -> Self {
fn trans_normalize<'a, 'tcx>(&self,
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>)
-> Self {
match *self {
LvalueTy::Ty { ty } => LvalueTy::Ty { ty: ty.trans_normalize(infcx) },
LvalueTy::Ty { ty } => LvalueTy::Ty { ty: ty.trans_normalize(infcx, param_env) },
LvalueTy::Downcast { adt_def, substs, variant_index } => {
LvalueTy::Downcast {
adt_def: adt_def,
substs: substs.trans_normalize(infcx),
substs: substs.trans_normalize(infcx, param_env),
variant_index: variant_index
}
}
@ -632,22 +603,30 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
self.normalize_associated_type(&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 normalize_associated_type<T>(self, value: &T) -> T
where T: TransNormalize<'tcx>
{
debug!("normalize_associated_type(t={:?})", value);
let param_env = ty::ParamEnv::empty(Reveal::All);
let value = self.erase_regions(value);
if !value.has_projection_types() {
return value;
}
self.infer_ctxt((), Reveal::All).enter(|infcx| {
value.trans_normalize(&infcx)
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
@ -661,20 +640,20 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
return value;
}
self.infer_ctxt(env, Reveal::All).enter(|infcx| {
value.trans_normalize(&infcx)
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, value: &T) -> T::Lifted
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, cause, value);
traits::normalize(&mut selcx, param_env, cause, value);
debug!("normalize_projections_in: result={:?} obligations={:?}",
result, obligations);
@ -728,10 +707,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
}
}
pub fn projection_mode(&self) -> Reveal {
self.projection_mode
}
pub fn is_in_snapshot(&self) -> bool {
self.in_snapshot.get()
}
@ -817,52 +792,17 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
return variables;
}
fn combine_fields(&'a self, trace: TypeTrace<'tcx>)
fn combine_fields(&'a self, trace: TypeTrace<'tcx>, param_env: ty::ParamEnv<'tcx>)
-> CombineFields<'a, 'gcx, 'tcx> {
CombineFields {
infcx: self,
trace: trace,
cause: None,
param_env,
obligations: PredicateObligations::new(),
}
}
pub fn equate<T>(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>, a: &T, b: &T)
-> InferResult<'tcx, T>
where T: Relate<'tcx>
{
let mut fields = self.combine_fields(trace);
let result = fields.equate(a_is_expected).relate(a, b);
result.map(move |t| InferOk { value: t, obligations: fields.obligations })
}
pub fn sub<T>(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>, a: &T, b: &T)
-> InferResult<'tcx, T>
where T: Relate<'tcx>
{
let mut fields = self.combine_fields(trace);
let result = fields.sub(a_is_expected).relate(a, b);
result.map(move |t| InferOk { value: t, obligations: fields.obligations })
}
pub fn lub<T>(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>, a: &T, b: &T)
-> InferResult<'tcx, T>
where T: Relate<'tcx>
{
let mut fields = self.combine_fields(trace);
let result = fields.lub(a_is_expected).relate(a, b);
result.map(move |t| InferOk { value: t, obligations: fields.obligations })
}
pub fn glb<T>(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>, a: &T, b: &T)
-> InferResult<'tcx, T>
where T: Relate<'tcx>
{
let mut fields = self.combine_fields(trace);
let result = fields.glb(a_is_expected).relate(a, b);
result.map(move |t| InferOk { value: t, obligations: fields.obligations })
}
// Clear the "currently in a snapshot" flag, invoke the closure,
// then restore the flag to its original value. This flag is a
// debugging measure designed to detect cases where we start a
@ -1022,94 +962,35 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
self.region_vars.add_given(sub, sup);
}
pub fn sub_types(&self,
a_is_expected: bool,
cause: &ObligationCause<'tcx>,
a: Ty<'tcx>,
b: Ty<'tcx>)
-> InferResult<'tcx, ()>
{
debug!("sub_types({:?} <: {:?})", a, b);
self.commit_if_ok(|_| {
let trace = TypeTrace::types(cause, a_is_expected, a, b);
self.sub(a_is_expected, trace, &a, &b).map(|ok| ok.unit())
})
}
pub fn can_sub_types(&self,
a: Ty<'tcx>,
b: Ty<'tcx>)
-> UnitResult<'tcx>
pub fn can_sub<T>(&self,
param_env: ty::ParamEnv<'tcx>,
a: T,
b: T)
-> UnitResult<'tcx>
where T: at::ToTrace<'tcx>
{
let origin = &ObligationCause::dummy();
self.probe(|_| {
let origin = &ObligationCause::dummy();
let trace = TypeTrace::types(origin, true, a, b);
self.sub(true, trace, &a, &b).map(|InferOk { obligations: _, .. }| {
self.at(origin, param_env).sub(a, b).map(|InferOk { obligations: _, .. }| {
// Ignore obligations, since we are unrolling
// everything anyway.
})
})
}
pub fn eq_types(&self,
a_is_expected: bool,
cause: &ObligationCause<'tcx>,
a: Ty<'tcx>,
b: Ty<'tcx>)
-> InferResult<'tcx, ()>
pub fn can_eq<T>(&self,
param_env: ty::ParamEnv<'tcx>,
a: T,
b: T)
-> UnitResult<'tcx>
where T: at::ToTrace<'tcx>
{
self.commit_if_ok(|_| {
let trace = TypeTrace::types(cause, a_is_expected, a, b);
self.equate(a_is_expected, trace, &a, &b).map(|ok| ok.unit())
})
}
pub fn eq_trait_refs(&self,
a_is_expected: bool,
cause: &ObligationCause<'tcx>,
a: ty::TraitRef<'tcx>,
b: ty::TraitRef<'tcx>)
-> InferResult<'tcx, ()>
{
debug!("eq_trait_refs({:?} = {:?})", a, b);
self.commit_if_ok(|_| {
let trace = TypeTrace {
cause: cause.clone(),
values: TraitRefs(ExpectedFound::new(a_is_expected, a, b))
};
self.equate(a_is_expected, trace, &a, &b).map(|ok| ok.unit())
})
}
pub fn eq_impl_headers(&self,
a_is_expected: bool,
cause: &ObligationCause<'tcx>,
a: &ty::ImplHeader<'tcx>,
b: &ty::ImplHeader<'tcx>)
-> InferResult<'tcx, ()>
{
debug!("eq_impl_header({:?} = {:?})", a, b);
match (a.trait_ref, b.trait_ref) {
(Some(a_ref), Some(b_ref)) => self.eq_trait_refs(a_is_expected, cause, a_ref, b_ref),
(None, None) => self.eq_types(a_is_expected, cause, a.self_ty, b.self_ty),
_ => bug!("mk_eq_impl_headers given mismatched impl kinds"),
}
}
pub fn sub_poly_trait_refs(&self,
a_is_expected: bool,
cause: ObligationCause<'tcx>,
a: ty::PolyTraitRef<'tcx>,
b: ty::PolyTraitRef<'tcx>)
-> InferResult<'tcx, ()>
{
debug!("sub_poly_trait_refs({:?} <: {:?})", a, b);
self.commit_if_ok(|_| {
let trace = TypeTrace {
cause: cause,
values: PolyTraitRefs(ExpectedFound::new(a_is_expected, a, b))
};
self.sub(a_is_expected, trace, &a, &b).map(|ok| ok.unit())
let origin = &ObligationCause::dummy();
self.probe(|_| {
self.at(origin, param_env).eq(a, b).map(|InferOk { obligations: _, .. }| {
// Ignore obligations, since we are unrolling
// everything anyway.
})
})
}
@ -1123,6 +1004,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
pub fn equality_predicate(&self,
cause: &ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
predicate: &ty::PolyEquatePredicate<'tcx>)
-> InferResult<'tcx, ()>
{
@ -1130,7 +1012,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
let (ty::EquatePredicate(a, b), skol_map) =
self.skolemize_late_bound_regions(predicate, snapshot);
let cause_span = cause.span;
let eqty_ok = self.eq_types(false, cause, a, b)?;
let eqty_ok = self.at(cause, param_env).eq(b, a)?;
self.leak_check(false, cause_span, &skol_map, snapshot)?;
self.pop_skolemized(skol_map, snapshot);
Ok(eqty_ok.unit())
@ -1139,6 +1021,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
pub fn subtype_predicate(&self,
cause: &ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
predicate: &ty::PolySubtypePredicate<'tcx>)
-> Option<InferResult<'tcx, ()>>
{
@ -1167,7 +1050,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
self.skolemize_late_bound_regions(predicate, snapshot);
let cause_span = cause.span;
let ok = self.sub_types(a_is_expected, cause, a, b)?;
let ok = self.at(cause, param_env).sub_exp(a_is_expected, a, b)?;
self.leak_check(false, cause_span, &skol_map, snapshot)?;
self.pop_skolemized(skol_map, snapshot);
Ok(ok.unit())
@ -1569,6 +1452,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
/// details.
pub fn match_poly_projection_predicate(&self,
cause: ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
match_a: ty::PolyProjectionPredicate<'tcx>,
match_b: ty::TraitRef<'tcx>)
-> InferResult<'tcx, HrMatchResult<Ty<'tcx>>>
@ -1581,7 +1465,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
};
let match_pair = match_a.map_bound(|p| (p.projection_ty.trait_ref, p.ty));
let mut combine = self.combine_fields(trace);
let mut combine = self.combine_fields(trace, param_env);
let result = combine.higher_ranked_match(span, &match_pair, &match_b, true)?;
Ok(InferOk { value: result, obligations: combine.obligations })
}
@ -1600,27 +1484,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
self.region_vars.verify_generic_bound(origin, kind, a, bound);
}
pub fn can_equate<T>(&self, a: &T, b: &T) -> UnitResult<'tcx>
where T: Relate<'tcx> + fmt::Debug
{
debug!("can_equate({:?}, {:?})", a, b);
self.probe(|_| {
// Gin up a dummy trace, since this won't be committed
// anyhow. We should make this typetrace stuff more
// generic so we don't have to do anything quite this
// terrible.
let trace = TypeTrace::dummy(self.tcx);
self.equate(true, trace, a, b).map(|InferOk { obligations: _, .. }| {
// We can intentionally ignore obligations here, since
// this is part of a simple test for general
// "equatability". However, it's not entirely clear
// that we *ought* to be, perhaps a better thing would
// be to use a mini-fulfillment context or something
// like that.
})
})
}
pub fn node_ty(&self, id: ast::NodeId) -> McResult<Ty<'tcx>> {
let ty = self.node_type(id);
self.resolve_type_vars_or_error(&ty)
@ -1631,9 +1494,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
self.resolve_type_vars_or_error(&ty)
}
pub fn type_moves_by_default(&self, ty: Ty<'tcx>, span: Span) -> bool {
pub fn type_moves_by_default(&self,
param_env: ty::ParamEnv<'tcx>,
ty: Ty<'tcx>,
span: Span)
-> bool {
let ty = self.resolve_type_vars_if_possible(&ty);
if let Some(ty) = self.tcx.lift_to_global(&ty) {
if let Some((param_env, ty)) = self.tcx.lift_to_global(&(param_env, ty)) {
// Even if the type may have no inference variables, during
// type-checking closure types are in local tables only.
let local_closures = match self.tables {
@ -1641,7 +1508,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
_ => false
};
if !local_closures {
return ty.moves_by_default(self.tcx.global_tcx(), self.param_env(), span);
return ty.moves_by_default(self.tcx.global_tcx(), param_env, span);
}
}
@ -1651,17 +1518,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
// rightly refuses to work with inference variables, but
// moves_by_default has a cache, which we want to use in other
// cases.
!traits::type_known_to_meet_bound(self, ty, copy_def_id, span)
!traits::type_known_to_meet_bound(self, param_env, ty, copy_def_id, span)
}
pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option<ty::UpvarCapture<'tcx>> {
self.tables.borrow().upvar_capture_map.get(&upvar_id).cloned()
}
pub fn param_env(&self) -> ty::ParamEnv<'gcx> {
self.param_env
}
pub fn closure_kind(&self,
def_id: DefId)
-> Option<ty::ClosureKind>

View File

@ -96,6 +96,7 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx>
self.fields.obligations.push(
Obligation::new(
self.fields.trace.cause.clone(),
self.fields.param_env,
ty::Predicate::Subtype(
ty::Binder(ty::SubtypePredicate {
a_is_expected: self.a_is_expected,

View File

@ -47,7 +47,7 @@
#![cfg_attr(stage0, feature(staged_api))]
#![cfg_attr(stage0, feature(loop_break_value))]
#![recursion_limit="192"]
#![recursion_limit="256"]
extern crate arena;
extern crate core;

View File

@ -242,6 +242,7 @@ impl OverloadedCallType {
pub struct ExprUseVisitor<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
mc: mc::MemCategorizationContext<'a, 'gcx, 'tcx>,
delegate: &'a mut Delegate<'tcx>,
param_env: ty::ParamEnv<'tcx>,
}
// If the TYPER results in an error, it's because the type check
@ -266,24 +267,28 @@ macro_rules! return_if_err {
impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
pub fn new(delegate: &'a mut (Delegate<'tcx>+'a),
region_maps: &'a RegionMaps,
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>)
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>)
-> Self
{
ExprUseVisitor::with_options(delegate,
infcx,
param_env,
region_maps,
mc::MemCategorizationOptions::default())
}
pub fn with_options(delegate: &'a mut (Delegate<'tcx>+'a),
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
region_maps: &'a RegionMaps,
options: mc::MemCategorizationOptions)
-> Self
{
ExprUseVisitor {
mc: mc::MemCategorizationContext::with_options(infcx, region_maps, options),
delegate: delegate
delegate,
param_env,
}
}
@ -318,7 +323,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
debug!("delegate_consume(consume_id={}, cmt={:?})",
consume_id, cmt);
let mode = copy_or_move(self.mc.infcx, &cmt, DirectRefMove);
let mode = copy_or_move(self.mc.infcx, self.param_env, &cmt, DirectRefMove);
self.delegate.consume(consume_id, consume_span, cmt, mode);
}
@ -797,7 +802,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
PatKind::Binding(hir::BindByRef(..), ..) =>
mode.lub(BorrowingMatch),
PatKind::Binding(hir::BindByValue(..), ..) => {
match copy_or_move(self.mc.infcx, &cmt_pat, PatBindingMove) {
match copy_or_move(self.mc.infcx, self.param_env, &cmt_pat, PatBindingMove) {
Copy => mode.lub(CopyingMatch),
Move(..) => mode.lub(MovingMatch),
}
@ -813,10 +818,9 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
fn walk_pat(&mut self, cmt_discr: mc::cmt<'tcx>, pat: &hir::Pat, match_mode: MatchMode) {
debug!("walk_pat cmt_discr={:?} pat={:?}", cmt_discr, pat);
let tcx = &self.tcx();
let mc = &self.mc;
let tcx = self.tcx();
let infcx = self.mc.infcx;
let delegate = &mut self.delegate;
let ExprUseVisitor { ref mc, ref mut delegate, param_env } = *self;
return_if_err!(mc.cat_pattern(cmt_discr.clone(), pat, |mc, cmt_pat, pat| {
if let PatKind::Binding(bmode, def_id, ..) = pat.node {
debug!("binding cmt_pat={:?} pat={:?} match_mode={:?}", cmt_pat, pat, match_mode);
@ -840,7 +844,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
}
}
hir::BindByValue(..) => {
let mode = copy_or_move(infcx, &cmt_pat, PatBindingMove);
let mode = copy_or_move(infcx, param_env, &cmt_pat, PatBindingMove);
debug!("walk_pat binding consuming pat");
delegate.consume_pat(pat, cmt_pat, mode);
}
@ -899,7 +903,10 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
freevar.def));
match upvar_capture {
ty::UpvarCapture::ByValue => {
let mode = copy_or_move(self.mc.infcx, &cmt_var, CaptureMove);
let mode = copy_or_move(self.mc.infcx,
self.param_env,
&cmt_var,
CaptureMove);
self.delegate.consume(closure_expr.id, freevar.span, cmt_var, mode);
}
ty::UpvarCapture::ByRef(upvar_borrow) => {
@ -929,11 +936,12 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
}
fn copy_or_move<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
cmt: &mc::cmt<'tcx>,
move_reason: MoveReason)
-> ConsumeMode
{
if infcx.type_moves_by_default(cmt.ty, cmt.span) {
if infcx.type_moves_by_default(param_env, cmt.ty, cmt.span) {
Move(move_reason)
} else {
Copy

View File

@ -10,8 +10,6 @@
use hir::def::Def;
use hir::def_id::DefId;
use infer::InferCtxt;
use traits::Reveal;
use ty::{self, Ty, TyCtxt};
use ty::layout::{LayoutError, Pointer, SizeSkeleton};
@ -31,8 +29,10 @@ struct ItemVisitor<'a, 'tcx: 'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx>
}
struct ExprVisitor<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>
struct ExprVisitor<'a, 'tcx: 'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
tables: &'tcx ty::TypeckTables<'tcx>,
param_env: ty::ParamEnv<'tcx>,
}
/// If the type is `Option<T>`, it will return `T`, otherwise
@ -64,18 +64,18 @@ fn unpack_option_like<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
ty
}
impl<'a, 'gcx, 'tcx> ExprVisitor<'a, 'gcx, 'tcx> {
impl<'a, 'tcx> ExprVisitor<'a, 'tcx> {
fn def_id_is_transmute(&self, def_id: DefId) -> bool {
let intrinsic = match self.infcx.tcx.type_of(def_id).sty {
let intrinsic = match self.tcx.type_of(def_id).sty {
ty::TyFnDef(.., bfty) => bfty.abi() == RustIntrinsic,
_ => return false
};
intrinsic && self.infcx.tcx.item_name(def_id) == "transmute"
intrinsic && self.tcx.item_name(def_id) == "transmute"
}
fn check_transmute(&self, span: Span, from: Ty<'gcx>, to: Ty<'gcx>) {
let sk_from = SizeSkeleton::compute(from, self.infcx);
let sk_to = SizeSkeleton::compute(to, self.infcx);
fn check_transmute(&self, span: Span, from: Ty<'tcx>, to: Ty<'tcx>) {
let sk_from = SizeSkeleton::compute(from, self.tcx, self.param_env);
let sk_to = SizeSkeleton::compute(to, self.tcx, self.param_env);
// Check for same size using the skeletons.
if let (Ok(sk_from), Ok(sk_to)) = (sk_from, sk_to) {
@ -85,11 +85,11 @@ impl<'a, 'gcx, 'tcx> ExprVisitor<'a, 'gcx, 'tcx> {
// Special-case transmutting from `typeof(function)` and
// `Option<typeof(function)>` to present a clearer error.
let from = unpack_option_like(self.infcx.tcx.global_tcx(), from);
let from = unpack_option_like(self.tcx.global_tcx(), from);
match (&from.sty, sk_to) {
(&ty::TyFnDef(..), SizeSkeleton::Known(size_to))
if size_to == Pointer.size(self.infcx) => {
struct_span_err!(self.infcx.tcx.sess, span, E0591,
if size_to == Pointer.size(self.tcx) => {
struct_span_err!(self.tcx.sess, span, E0591,
"`{}` is zero-sized and can't be transmuted to `{}`",
from, to)
.span_note(span, "cast with `as` to a pointer instead")
@ -101,7 +101,7 @@ impl<'a, 'gcx, 'tcx> ExprVisitor<'a, 'gcx, 'tcx> {
}
// Try to display a sensible error with as much information as possible.
let skeleton_string = |ty: Ty<'gcx>, sk| {
let skeleton_string = |ty: Ty<'tcx>, sk| {
match sk {
Ok(SizeSkeleton::Known(size)) => {
format!("{} bits", size.bits())
@ -120,7 +120,7 @@ impl<'a, 'gcx, 'tcx> ExprVisitor<'a, 'gcx, 'tcx> {
}
};
struct_span_err!(self.infcx.tcx.sess, span, E0512,
struct_span_err!(self.tcx.sess, span, E0512,
"transmute called with differently sized types: \
{} ({}) to {} ({})",
from, skeleton_string(from, sk_from),
@ -139,32 +139,30 @@ impl<'a, 'tcx> Visitor<'tcx> for ItemVisitor<'a, 'tcx> {
}
fn visit_nested_body(&mut self, body_id: hir::BodyId) {
let owner_def_id = self.tcx.hir.body_owner_def_id(body_id);
let body = self.tcx.hir.body(body_id);
self.tcx.infer_ctxt(body_id, Reveal::All).enter(|infcx| {
let mut visitor = ExprVisitor {
infcx: &infcx
};
visitor.visit_body(body);
});
let param_env = self.tcx.param_env(owner_def_id);
let tables = self.tcx.typeck_tables_of(owner_def_id);
ExprVisitor { tcx: self.tcx, param_env, tables }.visit_body(body);
self.visit_body(body);
}
}
impl<'a, 'gcx, 'tcx> Visitor<'gcx> for ExprVisitor<'a, 'gcx, 'tcx> {
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> {
impl<'a, 'tcx> Visitor<'tcx> for ExprVisitor<'a, 'tcx> {
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
NestedVisitorMap::None
}
fn visit_expr(&mut self, expr: &'gcx hir::Expr) {
fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
let def = if let hir::ExprPath(ref qpath) = expr.node {
self.infcx.tables.borrow().qpath_def(qpath, expr.id)
self.tables.qpath_def(qpath, expr.id)
} else {
Def::Err
};
match def {
Def::Fn(did) if self.def_id_is_transmute(did) => {
let typ = self.infcx.tables.borrow().node_id_to_type(expr.id);
let typ = self.infcx.tcx.lift_to_global(&typ).unwrap();
let typ = self.tables.node_id_to_type(expr.id);
let typ = self.tcx.lift_to_global(&typ).unwrap();
match typ.sty {
ty::TyFnDef(.., sig) if sig.abi() == RustIntrinsic => {
let from = sig.inputs().skip_binder()[0];

View File

@ -10,10 +10,11 @@
//! See `README.md` for high-level documentation
use super::{SelectionContext, Obligation, ObligationCause};
use hir::def_id::{DefId, LOCAL_CRATE};
use syntax_pos::DUMMY_SP;
use traits::{self, Normalized, SelectionContext, Obligation, ObligationCause, Reveal};
use ty::{self, Ty, TyCtxt};
use ty::subst::Subst;
use infer::{InferCtxt, InferOk};
@ -37,6 +38,28 @@ pub fn overlapping_impls<'cx, 'gcx, 'tcx>(infcx: &InferCtxt<'cx, 'gcx, 'tcx>,
overlap(selcx, impl1_def_id, impl2_def_id)
}
fn with_fresh_ty_vars<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
impl_def_id: DefId)
-> ty::ImplHeader<'tcx>
{
let tcx = selcx.tcx();
let impl_substs = selcx.infcx().fresh_substs_for_item(DUMMY_SP, impl_def_id);
let header = ty::ImplHeader {
impl_def_id: impl_def_id,
self_ty: tcx.type_of(impl_def_id),
trait_ref: tcx.impl_trait_ref(impl_def_id),
predicates: tcx.predicates_of(impl_def_id).predicates
}.subst(tcx, impl_substs);
let Normalized { value: mut header, obligations } =
traits::normalize(selcx, param_env, ObligationCause::dummy(), &header);
header.predicates.extend(obligations.into_iter().map(|o| o.predicate));
header
}
/// Can both impl `a` and impl `b` be satisfied by a common type (including
/// `where` clauses)? If so, returns an `ImplHeader` that unifies the two impls.
fn overlap<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
@ -48,18 +71,22 @@ fn overlap<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
a_def_id,
b_def_id);
let a_impl_header = ty::ImplHeader::with_fresh_ty_vars(selcx, a_def_id);
let b_impl_header = ty::ImplHeader::with_fresh_ty_vars(selcx, b_def_id);
// For the purposes of this check, we don't bring any skolemized
// 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 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);
debug!("overlap: a_impl_header={:?}", a_impl_header);
debug!("overlap: b_impl_header={:?}", b_impl_header);
// Do `a` and `b` unify? If not, no overlap.
let obligations = match selcx.infcx().eq_impl_headers(true,
&ObligationCause::dummy(),
&a_impl_header,
&b_impl_header) {
Ok(InferOk { obligations, .. }) => {
let obligations = match selcx.infcx().at(&ObligationCause::dummy(), param_env)
.eq_impl_headers(&a_impl_header, &b_impl_header) {
Ok(InferOk { obligations, value: () }) => {
obligations
}
Err(_) => return None
@ -75,6 +102,7 @@ fn overlap<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
.chain(&b_impl_header.predicates)
.map(|p| infcx.resolve_type_vars_if_possible(p))
.map(|p| Obligation { cause: ObligationCause::dummy(),
param_env: param_env,
recursion_depth: 0,
predicate: p })
.chain(obligations)

View File

@ -179,14 +179,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
data);
let normalized = super::normalize_projection_type(
&mut selcx,
obligation.param_env,
data.projection_ty,
obligation.cause.clone(),
0
);
if let Err(error) = self.eq_types(
false, &obligation.cause,
data.ty, normalized.value
) {
if let Err(error) = self.at(&obligation.cause, obligation.param_env)
.eq(normalized.value, data.ty) {
values = Some(infer::ValuePairs::Types(ExpectedFound {
expected: normalized.value,
found: data.ty,
@ -251,7 +250,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
-> Option<DefId>
{
let tcx = self.tcx;
let param_env = obligation.param_env;
let trait_ref = tcx.erase_late_bound_regions(&trait_ref);
let trait_self_ty = trait_ref.self_ty();
@ -268,7 +267,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
let impl_self_ty = impl_trait_ref.self_ty();
if let Ok(..) = self.can_equate(&trait_self_ty, &impl_self_ty) {
if let Ok(..) = self.can_eq(param_env, trait_self_ty, impl_self_ty) {
self_match_impls.push(def_id);
if trait_ref.substs.types().skip(1)
@ -578,7 +577,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
// Try to report a help message
if !trait_ref.has_infer_types() &&
self.predicate_can_apply(trait_ref) {
self.predicate_can_apply(obligation.param_env, trait_ref) {
// If a where-clause may be useful, remind the
// user that they can add it.
//
@ -607,7 +606,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
ty::Predicate::Equate(ref predicate) => {
let predicate = self.resolve_type_vars_if_possible(predicate);
let err = self.equality_predicate(&obligation.cause,
&predicate).err().unwrap();
obligation.param_env,
&predicate).err().unwrap();
struct_span_err!(self.tcx.sess, span, E0278,
"the requirement `{}` is not satisfied (`{}`)",
predicate, err)
@ -936,7 +936,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
/// Returns whether the trait predicate may apply for *some* assignment
/// to the type parameters.
fn predicate_can_apply(&self, pred: ty::PolyTraitRef<'tcx>) -> bool {
fn predicate_can_apply(&self,
param_env: ty::ParamEnv<'tcx>,
pred: ty::PolyTraitRef<'tcx>)
-> bool {
struct ParamToVarFolder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
var_map: FxHashMap<Ty<'tcx>, Ty<'tcx>>
@ -967,12 +970,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
let cleaned_pred = super::project::normalize(
&mut selcx,
param_env,
ObligationCause::dummy(),
&cleaned_pred
).value;
let obligation = Obligation::new(
ObligationCause::dummy(),
param_env,
cleaned_pred.to_predicate()
);

View File

@ -113,6 +113,7 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> {
/// `projection_ty` again.
pub fn normalize_projection_type(&mut self,
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
projection_ty: ty::ProjectionTy<'tcx>,
cause: ObligationCause<'tcx>)
-> Ty<'tcx>
@ -125,7 +126,11 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> {
// FIXME(#20304) -- cache
let mut selcx = SelectionContext::new(infcx);
let normalized = project::normalize_projection_type(&mut selcx, projection_ty, cause, 0);
let normalized = project::normalize_projection_type(&mut selcx,
param_env,
projection_ty,
cause,
0);
for obligation in normalized.obligations {
self.register_predicate_obligation(infcx, obligation);
@ -136,8 +141,12 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> {
normalized.value
}
/// Requires that `ty` must implement the trait with `def_id` in
/// the given environment. This trait must not have any type
/// parameters (except for `Self`).
pub fn register_bound(&mut self,
infcx: &InferCtxt<'a, 'gcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
ty: Ty<'tcx>,
def_id: DefId,
cause: ObligationCause<'tcx>)
@ -149,6 +158,7 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> {
self.register_predicate_obligation(infcx, Obligation {
cause: cause,
recursion_depth: 0,
param_env,
predicate: trait_ref.to_predicate()
});
}
@ -410,7 +420,9 @@ fn process_predicate<'a, 'gcx, 'tcx>(
}
ty::Predicate::Equate(ref binder) => {
match selcx.infcx().equality_predicate(&obligation.cause, binder) {
match selcx.infcx().equality_predicate(&obligation.cause,
obligation.param_env,
binder) {
Ok(InferOk { obligations, value: () }) => {
Ok(Some(obligations))
},
@ -498,7 +510,9 @@ fn process_predicate<'a, 'gcx, 'tcx>(
}
ty::Predicate::WellFormed(ty) => {
match ty::wf::obligations(selcx.infcx(), obligation.cause.body_id,
match ty::wf::obligations(selcx.infcx(),
obligation.param_env,
obligation.cause.body_id,
ty, obligation.cause.span) {
None => {
pending_obligation.stalled_on = vec![ty];
@ -509,7 +523,9 @@ fn process_predicate<'a, 'gcx, 'tcx>(
}
ty::Predicate::Subtype(ref subtype) => {
match selcx.infcx().subtype_predicate(&obligation.cause, subtype) {
match selcx.infcx().subtype_predicate(&obligation.cause,
obligation.param_env,
subtype) {
None => {
// none means that both are unresolved
pending_obligation.stalled_on = vec![subtype.skip_binder().a,

View File

@ -68,6 +68,7 @@ mod util;
#[derive(Clone, PartialEq, Eq)]
pub struct Obligation<'tcx, T> {
pub cause: ObligationCause<'tcx>,
pub param_env: ty::ParamEnv<'tcx>,
pub recursion_depth: usize,
pub predicate: T,
}
@ -359,10 +360,11 @@ pub struct VtableFnPointerData<'tcx, N> {
/// Creates predicate obligations from the generic bounds.
pub fn predicates_for_generics<'tcx>(cause: ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
generic_bounds: &ty::InstantiatedPredicates<'tcx>)
-> PredicateObligations<'tcx>
{
util::predicates_for_generics(cause, 0, generic_bounds)
util::predicates_for_generics(cause, 0, param_env, generic_bounds)
}
/// Determines whether the type `ty` is known to meet `bound` and
@ -371,6 +373,7 @@ pub fn predicates_for_generics<'tcx>(cause: ObligationCause<'tcx>,
/// conservative towards *no impl*, which is the opposite of the
/// `evaluate` methods).
pub fn type_known_to_meet_bound<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
ty: Ty<'tcx>,
def_id: DefId,
span: Span)
@ -385,6 +388,7 @@ pub fn type_known_to_meet_bound<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx
substs: infcx.tcx.mk_substs_trait(ty, &[]),
};
let obligation = Obligation {
param_env,
cause: ObligationCause::misc(span, ast::DUMMY_NODE_ID),
recursion_depth: 0,
predicate: trait_ref.to_predicate(),
@ -408,7 +412,7 @@ pub fn type_known_to_meet_bound<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx
// anyhow).
let cause = ObligationCause::misc(span, ast::DUMMY_NODE_ID);
fulfill_cx.register_bound(infcx, ty, def_id, cause);
fulfill_cx.register_bound(infcx, param_env, ty, def_id, cause);
// Note: we only assume something is `Copy` if we can
// *definitively* show that it implements `Copy`. Otherwise,
@ -477,24 +481,27 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
debug!("normalize_param_env_or_error: elaborated-predicates={:?}",
predicates);
let elaborated_env = ty::ParamEnv::new(tcx.intern_predicates(&predicates));
let elaborated_env = ty::ParamEnv::new(tcx.intern_predicates(&predicates),
unnormalized_env.reveal);
tcx.infer_ctxt(elaborated_env, Reveal::UserFacing).enter(|infcx| {
tcx.infer_ctxt(()).enter(|infcx| {
let predicates = match fully_normalize(
&infcx, cause,
// You would really want to pass infcx.param_env.caller_bounds here,
// but that is an interned slice, and fully_normalize takes &T and returns T, so
// without further refactoring, a slice can't be used. Luckily, we still have the
// predicate vector from which we created the ParamEnv in infcx, so we
// can pass that instead. It's roundabout and a bit brittle, but this code path
// ought to be refactored anyway, and until then it saves us from having to copy.
&predicates,
&infcx,
cause,
elaborated_env,
// You would really want to pass infcx.param_env.caller_bounds here,
// but that is an interned slice, and fully_normalize takes &T and returns T, so
// without further refactoring, a slice can't be used. Luckily, we still have the
// predicate vector from which we created the ParamEnv in infcx, so we
// can pass that instead. It's roundabout and a bit brittle, but this code path
// ought to be refactored anyway, and until then it saves us from having to copy.
&predicates,
) {
Ok(predicates) => predicates,
Err(errors) => {
infcx.report_fulfillment_errors(&errors);
// An unnormalized env is better than nothing.
return infcx.param_env;
return elaborated_env;
}
};
@ -516,24 +523,25 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
// all things considered.
tcx.sess.span_err(span, &fixup_err.to_string());
// An unnormalized env is better than nothing.
return infcx.param_env;
return elaborated_env;
}
};
let predicates = match tcx.lift_to_global(&predicates) {
Some(predicates) => predicates,
None => return infcx.param_env
None => return elaborated_env,
};
debug!("normalize_param_env_or_error: resolved predicates={:?}",
predicates);
predicates);
ty::ParamEnv::new(tcx.intern_predicates(&predicates))
ty::ParamEnv::new(tcx.intern_predicates(&predicates), unnormalized_env.reveal)
})
}
pub fn fully_normalize<'a, 'gcx, 'tcx, T>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
cause: ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
value: &T)
-> Result<T, Vec<FulfillmentError<'tcx>>>
where T : TypeFoldable<'tcx>
@ -557,7 +565,7 @@ pub fn fully_normalize<'a, 'gcx, 'tcx, T>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
let mut fulfill_cx = FulfillmentContext::new();
let Normalized { value: normalized_value, obligations } =
project::normalize(selcx, cause, value);
project::normalize(selcx, param_env, cause, value);
debug!("fully_normalize: normalized_value={:?} obligations={:?}",
normalized_value,
obligations);
@ -579,10 +587,10 @@ pub fn fully_normalize<'a, 'gcx, 'tcx, T>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
Ok(resolved_value)
}
/// Normalizes the predicates and checks whether they hold. If this
/// returns false, then either normalize encountered an error or one
/// of the predicates did not hold. Used when creating vtables to
/// check for unsatisfiable methods.
/// Normalizes the predicates and checks whether they hold in an empty
/// environment. If this returns false, then either normalize
/// encountered an error or one of the predicates did not hold. Used
/// when creating vtables to check for unsatisfiable methods.
pub fn normalize_and_test_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
predicates: Vec<ty::Predicate<'tcx>>)
-> bool
@ -590,17 +598,18 @@ pub fn normalize_and_test_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
debug!("normalize_and_test_predicates(predicates={:?})",
predicates);
tcx.infer_ctxt((), Reveal::All).enter(|infcx| {
tcx.infer_ctxt(()).enter(|infcx| {
let param_env = ty::ParamEnv::empty(Reveal::All);
let mut selcx = SelectionContext::new(&infcx);
let mut fulfill_cx = FulfillmentContext::new();
let cause = ObligationCause::dummy();
let Normalized { value: predicates, obligations } =
normalize(&mut selcx, cause.clone(), &predicates);
normalize(&mut selcx, param_env, cause.clone(), &predicates);
for obligation in obligations {
fulfill_cx.register_predicate_obligation(&infcx, obligation);
}
for predicate in predicates {
let obligation = Obligation::new(cause.clone(), predicate);
let obligation = Obligation::new(cause.clone(), param_env, predicate);
fulfill_cx.register_predicate_obligation(&infcx, obligation);
}
@ -662,30 +671,33 @@ pub fn get_vtable_methods<'a, 'tcx>(
impl<'tcx,O> Obligation<'tcx,O> {
pub fn new(cause: ObligationCause<'tcx>,
trait_ref: O)
param_env: ty::ParamEnv<'tcx>,
predicate: O)
-> Obligation<'tcx, O>
{
Obligation { cause: cause,
recursion_depth: 0,
predicate: trait_ref }
Obligation { cause, param_env, recursion_depth: 0, predicate }
}
fn with_depth(cause: ObligationCause<'tcx>,
recursion_depth: usize,
trait_ref: O)
param_env: ty::ParamEnv<'tcx>,
predicate: O)
-> Obligation<'tcx, O>
{
Obligation { cause: cause,
recursion_depth: recursion_depth,
predicate: trait_ref }
Obligation { cause, param_env, recursion_depth, predicate }
}
pub fn misc(span: Span, body_id: ast::NodeId, trait_ref: O) -> Obligation<'tcx, O> {
Obligation::new(ObligationCause::misc(span, body_id), trait_ref)
pub fn misc(span: Span,
body_id: ast::NodeId,
param_env: ty::ParamEnv<'tcx>,
trait_ref: O)
-> Obligation<'tcx, O> {
Obligation::new(ObligationCause::misc(span, body_id), param_env, trait_ref)
}
pub fn with<P>(&self, value: P) -> Obligation<'tcx,P> {
Obligation { cause: self.cause.clone(),
param_env: self.param_env,
recursion_depth: self.recursion_depth,
predicate: value }
}

View File

@ -36,7 +36,7 @@ use util::common::FN_OUTPUT_NAME;
/// Depending on the stage of compilation, we want projection to be
/// more or less conservative.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum Reveal {
/// At type-checking time, we refuse to project any associated
/// type that is marked `default`. Non-`default` ("final") types
@ -168,7 +168,8 @@ fn project_and_unify_type<'cx, 'gcx, 'tcx>(
let Normalized { value: normalized_ty, mut obligations } =
match opt_normalize_projection_type(selcx,
obligation.predicate.projection_ty.clone(),
obligation.param_env,
obligation.predicate.projection_ty,
obligation.cause.clone(),
obligation.recursion_depth) {
Some(n) => n,
@ -180,7 +181,8 @@ fn project_and_unify_type<'cx, 'gcx, 'tcx>(
obligations);
let infcx = selcx.infcx();
match infcx.eq_types(true, &obligation.cause, normalized_ty, obligation.predicate.ty) {
match infcx.at(&obligation.cause, obligation.param_env)
.eq(normalized_ty, obligation.predicate.ty) {
Ok(InferOk { obligations: inferred_obligations, value: () }) => {
obligations.extend(inferred_obligations);
Ok(Some(obligations))
@ -194,17 +196,19 @@ fn project_and_unify_type<'cx, 'gcx, 'tcx>(
/// combines the normalized result and any additional obligations that
/// were incurred as result.
pub fn normalize<'a, 'b, 'gcx, 'tcx, T>(selcx: &'a mut SelectionContext<'b, 'gcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
cause: ObligationCause<'tcx>,
value: &T)
-> Normalized<'tcx, T>
where T : TypeFoldable<'tcx>
{
normalize_with_depth(selcx, cause, 0, value)
normalize_with_depth(selcx, param_env, cause, 0, value)
}
/// As `normalize`, but with a custom depth.
pub fn normalize_with_depth<'a, 'b, 'gcx, 'tcx, T>(
selcx: &'a mut SelectionContext<'b, 'gcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
cause: ObligationCause<'tcx>,
depth: usize,
value: &T)
@ -213,7 +217,7 @@ pub fn normalize_with_depth<'a, 'b, 'gcx, 'tcx, T>(
where T : TypeFoldable<'tcx>
{
debug!("normalize_with_depth(depth={}, value={:?})", depth, value);
let mut normalizer = AssociatedTypeNormalizer::new(selcx, cause, depth);
let mut normalizer = AssociatedTypeNormalizer::new(selcx, param_env, cause, depth);
let result = normalizer.fold(value);
debug!("normalize_with_depth: depth={} result={:?} with {} obligations",
depth, result, normalizer.obligations.len());
@ -227,6 +231,7 @@ pub fn normalize_with_depth<'a, 'b, 'gcx, 'tcx, T>(
struct AssociatedTypeNormalizer<'a, 'b: 'a, 'gcx: 'b+'tcx, 'tcx: 'b> {
selcx: &'a mut SelectionContext<'b, 'gcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
cause: ObligationCause<'tcx>,
obligations: Vec<PredicateObligation<'tcx>>,
depth: usize,
@ -234,12 +239,14 @@ struct AssociatedTypeNormalizer<'a, 'b: 'a, 'gcx: 'b+'tcx, 'tcx: 'b> {
impl<'a, 'b, 'gcx, 'tcx> AssociatedTypeNormalizer<'a, 'b, 'gcx, 'tcx> {
fn new(selcx: &'a mut SelectionContext<'b, 'gcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
cause: ObligationCause<'tcx>,
depth: usize)
-> AssociatedTypeNormalizer<'a, 'b, 'gcx, 'tcx>
{
AssociatedTypeNormalizer {
selcx: selcx,
param_env: param_env,
cause: cause,
obligations: vec![],
depth: depth,
@ -278,12 +285,14 @@ impl<'a, 'b, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for AssociatedTypeNormalizer<'a,
match ty.sty {
ty::TyAnon(def_id, substs) if !substs.has_escaping_regions() => { // (*)
// Only normalize `impl Trait` after type-checking, usually in trans.
if self.selcx.projection_mode() == Reveal::All {
let generic_ty = self.tcx().type_of(def_id);
let concrete_ty = generic_ty.subst(self.tcx(), substs);
self.fold_ty(concrete_ty)
} else {
ty
match self.param_env.reveal {
Reveal::UserFacing => ty,
Reveal::All => {
let generic_ty = self.tcx().type_of(def_id);
let concrete_ty = generic_ty.subst(self.tcx(), substs);
self.fold_ty(concrete_ty)
}
}
}
@ -303,6 +312,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for AssociatedTypeNormalizer<'a,
let Normalized { value: normalized_ty, obligations } =
normalize_projection_type(self.selcx,
self.param_env,
data.clone(),
self.cause.clone(),
self.depth);
@ -342,12 +352,13 @@ impl<'tcx,T> Normalized<'tcx,T> {
/// obligation `<T as Trait>::Item == $X` for later.
pub fn normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
selcx: &'a mut SelectionContext<'b, 'gcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
projection_ty: ty::ProjectionTy<'tcx>,
cause: ObligationCause<'tcx>,
depth: usize)
-> NormalizedTy<'tcx>
{
opt_normalize_projection_type(selcx, projection_ty.clone(), cause.clone(), depth)
opt_normalize_projection_type(selcx, param_env, projection_ty.clone(), cause.clone(), depth)
.unwrap_or_else(move || {
// if we bottom out in ambiguity, create a type variable
// and a deferred predicate to resolve this when more type
@ -364,7 +375,7 @@ pub fn normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
ty: ty_var
});
let obligation = Obligation::with_depth(
cause, depth + 1, projection.to_predicate());
cause, depth + 1, param_env, projection.to_predicate());
Normalized {
value: ty_var,
obligations: vec![obligation]
@ -378,6 +389,7 @@ pub fn normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
/// which indicates that there are unbound type variables.
fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
selcx: &'a mut SelectionContext<'b, 'gcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
projection_ty: ty::ProjectionTy<'tcx>,
cause: ObligationCause<'tcx>,
depth: usize)
@ -447,6 +459,7 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
let recursion_limit = selcx.tcx().sess.recursion_limit.get();
let obligation = Obligation::with_depth(cause.clone(),
recursion_limit,
param_env,
projection_ty);
selcx.infcx().report_overflow_error(&obligation, false);
}
@ -462,11 +475,11 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
Err(ProjectionCacheEntry::Error) => {
debug!("opt_normalize_projection_type: \
found error");
return Some(normalize_to_error(selcx, projection_ty, cause, depth));
return Some(normalize_to_error(selcx, param_env, projection_ty, cause, depth));
}
}
let obligation = Obligation::with_depth(cause.clone(), depth, projection_ty.clone());
let obligation = Obligation::with_depth(cause.clone(), depth, param_env, projection_ty);
match project_type(selcx, &obligation) {
Ok(ProjectedTy::Progress(Progress { ty: projected_ty,
mut obligations,
@ -487,7 +500,10 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
cacheable);
let result = if projected_ty.has_projection_types() {
let mut normalizer = AssociatedTypeNormalizer::new(selcx, cause, depth+1);
let mut normalizer = AssociatedTypeNormalizer::new(selcx,
param_env,
cause,
depth+1);
let normalized_ty = normalizer.fold(&projected_ty);
debug!("opt_normalize_projection_type: \
@ -538,7 +554,7 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
infcx.projection_cache.borrow_mut()
.error(projection_ty);
Some(normalize_to_error(selcx, projection_ty, cause, depth))
Some(normalize_to_error(selcx, param_env, projection_ty, cause, depth))
}
}
}
@ -563,6 +579,7 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
/// because it contains `[type error]`. Yuck! (See issue #29857 for
/// one case where this arose.)
fn normalize_to_error<'a, 'gcx, 'tcx>(selcx: &mut SelectionContext<'a, 'gcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
projection_ty: ty::ProjectionTy<'tcx>,
cause: ObligationCause<'tcx>,
depth: usize)
@ -571,6 +588,7 @@ fn normalize_to_error<'a, 'gcx, 'tcx>(selcx: &mut SelectionContext<'a, 'gcx, 'tc
let trait_ref = projection_ty.trait_ref.to_poly_trait_ref();
let trait_obligation = Obligation { cause: cause,
recursion_depth: depth,
param_env,
predicate: trait_ref.to_predicate() };
let tcx = selcx.infcx().tcx;
let def_id = tcx.associated_items(projection_ty.trait_ref.def_id).find(|i|
@ -744,13 +762,12 @@ fn assemble_candidates_from_param_env<'cx, 'gcx, 'tcx>(
candidate_set: &mut ProjectionTyCandidateSet<'tcx>)
{
debug!("assemble_candidates_from_param_env(..)");
let env_predicates = selcx.param_env().caller_bounds.iter().cloned();
assemble_candidates_from_predicates(selcx,
obligation,
obligation_trait_ref,
candidate_set,
ProjectionTyCandidate::ParamEnv,
env_predicates);
obligation.param_env.caller_bounds.iter().cloned());
}
/// In the case of a nested projection like <<A as Foo>::FooT as Bar>::BarT, we may find
@ -805,7 +822,7 @@ fn assemble_candidates_from_predicates<'cx, 'gcx, 'tcx, I>(
candidate_set: &mut ProjectionTyCandidateSet<'tcx>,
ctor: fn(ty::PolyProjectionPredicate<'tcx>) -> ProjectionTyCandidate<'tcx>,
env_predicates: I)
where I: Iterator<Item=ty::Predicate<'tcx>>
where I: IntoIterator<Item=ty::Predicate<'tcx>>
{
debug!("assemble_candidates_from_predicates(obligation={:?})",
obligation);
@ -823,15 +840,13 @@ fn assemble_candidates_from_predicates<'cx, 'gcx, 'tcx, I>(
data.to_poly_trait_ref();
let obligation_poly_trait_ref =
obligation_trait_ref.to_poly_trait_ref();
infcx.sub_poly_trait_refs(false,
obligation.cause.clone(),
data_poly_trait_ref,
obligation_poly_trait_ref)
.map(|InferOk { obligations: _, value: () }| {
// FIXME(#32730) -- do we need to take obligations
// into account in any way? At the moment, no.
})
.is_ok()
infcx.at(&obligation.cause, obligation.param_env)
.sup(obligation_poly_trait_ref, data_poly_trait_ref)
.map(|InferOk { obligations: _, value: () }| {
// FIXME(#32730) -- do we need to take obligations
// into account in any way? At the moment, no.
})
.is_ok()
});
debug!("assemble_candidates_from_predicates: candidate={:?} \
@ -934,7 +949,7 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>(
// get a result which isn't correct for all monomorphizations.
let new_candidate = if !is_default {
Some(ProjectionTyCandidate::Select)
} else if selcx.projection_mode() == Reveal::All {
} else if obligation.param_env.reveal == Reveal::All {
assert!(!poly_trait_ref.needs_infer());
if !poly_trait_ref.needs_subst() {
Some(ProjectionTyCandidate::Select)
@ -1092,10 +1107,9 @@ fn confirm_object_candidate<'cx, 'gcx, 'tcx>(
let data_poly_trait_ref = data.to_poly_trait_ref();
let obligation_poly_trait_ref = obligation_trait_ref.to_poly_trait_ref();
selcx.infcx().probe(|_| {
selcx.infcx().sub_poly_trait_refs(false,
obligation.cause.clone(),
data_poly_trait_ref,
obligation_poly_trait_ref).is_ok()
selcx.infcx().at(&obligation.cause, obligation.param_env)
.sup(obligation_poly_trait_ref, data_poly_trait_ref)
.is_ok()
})
});
@ -1141,6 +1155,7 @@ fn confirm_closure_candidate<'cx, 'gcx, 'tcx>(
value: closure_type,
obligations
} = normalize_with_depth(selcx,
obligation.param_env,
obligation.cause.clone(),
obligation.recursion_depth+1,
&closure_type);
@ -1201,8 +1216,9 @@ fn confirm_param_env_candidate<'cx, 'gcx, 'tcx>(
{
let infcx = selcx.infcx();
let cause = obligation.cause.clone();
let param_env = obligation.param_env;
let trait_ref = obligation.predicate.trait_ref;
match infcx.match_poly_projection_predicate(cause, poly_projection, trait_ref) {
match infcx.match_poly_projection_predicate(cause, param_env, poly_projection, trait_ref) {
Ok(InferOk { value: ty_match, obligations }) => {
Progress {
ty: ty_match.value,
@ -1231,6 +1247,7 @@ fn confirm_impl_candidate<'cx, 'gcx, 'tcx>(
let VtableImplData { substs, nested, impl_def_id } = impl_vtable;
let tcx = selcx.tcx();
let param_env = obligation.param_env;
let assoc_ty = assoc_ty_def(selcx, impl_def_id, obligation.predicate.item_name(tcx));
let ty = if !assoc_ty.item.defaultness.has_value() {
@ -1245,7 +1262,7 @@ fn confirm_impl_candidate<'cx, 'gcx, 'tcx>(
} else {
tcx.type_of(assoc_ty.item.def_id)
};
let substs = translate_substs(selcx.infcx(), impl_def_id, substs, assoc_ty.node);
let substs = translate_substs(selcx.infcx(), param_env, impl_def_id, substs, assoc_ty.node);
Progress {
ty: ty.subst(tcx, substs),
obligations: nested,

View File

@ -21,7 +21,6 @@ use super::{PredicateObligation, TraitObligation, ObligationCause};
use super::{ObligationCauseCode, BuiltinDerivedObligation, ImplDerivedObligation};
use super::{SelectionError, Unimplemented, OutputTypeParameterMismatch};
use super::{ObjectCastObligation, Obligation};
use super::Reveal;
use super::TraitNotObjectSafe;
use super::Selection;
use super::SelectionResult;
@ -315,18 +314,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
self.infcx.tcx
}
pub fn param_env(&self) -> ty::ParamEnv<'gcx> {
self.infcx.param_env()
}
pub fn closure_typer(&self) -> &'cx InferCtxt<'cx, 'gcx, 'tcx> {
self.infcx
}
pub fn projection_mode(&self) -> Reveal {
self.infcx.projection_mode()
}
/// Wraps the inference context's in_snapshot s.t. snapshot handling is only from the selection
/// context's self.
fn in_snapshot<R, F>(&mut self, f: F) -> R
@ -540,7 +531,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
ty::Predicate::Equate(ref p) => {
// does this code ever run?
match self.infcx.equality_predicate(&obligation.cause, p) {
match self.infcx.equality_predicate(&obligation.cause, obligation.param_env, p) {
Ok(InferOk { obligations, .. }) => {
self.inferred_obligations.extend(obligations);
EvaluatedToOk
@ -551,7 +542,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
ty::Predicate::Subtype(ref p) => {
// does this code ever run?
match self.infcx.subtype_predicate(&obligation.cause, p) {
match self.infcx.subtype_predicate(&obligation.cause, obligation.param_env, p) {
Some(Ok(InferOk { obligations, .. })) => {
self.inferred_obligations.extend(obligations);
EvaluatedToOk
@ -562,7 +553,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
}
ty::Predicate::WellFormed(ty) => {
match ty::wf::obligations(self.infcx, obligation.cause.body_id,
match ty::wf::obligations(self.infcx,
obligation.param_env,
obligation.cause.body_id,
ty, obligation.cause.span) {
Some(obligations) =>
self.evaluate_predicates_recursively(previous_stack, obligations.iter()),
@ -628,7 +621,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
let stack = self.push_stack(previous_stack, obligation);
let fresh_trait_ref = stack.fresh_trait_ref;
if let Some(result) = self.check_evaluation_cache(fresh_trait_ref) {
if let Some(result) = self.check_evaluation_cache(obligation.param_env, fresh_trait_ref) {
debug!("CACHE HIT: EVAL({:?})={:?}",
fresh_trait_ref,
result);
@ -640,7 +633,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
debug!("CACHE MISS: EVAL({:?})={:?}",
fresh_trait_ref,
result);
self.insert_evaluation_cache(fresh_trait_ref, result);
self.insert_evaluation_cache(obligation.param_env, fresh_trait_ref, result);
result
}
@ -751,10 +744,12 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
result
}
fn check_evaluation_cache(&self, trait_ref: ty::PolyTraitRef<'tcx>)
fn check_evaluation_cache(&self,
param_env: ty::ParamEnv<'tcx>,
trait_ref: ty::PolyTraitRef<'tcx>)
-> Option<EvaluationResult>
{
if self.can_use_global_caches() {
if self.can_use_global_caches(param_env) {
let cache = self.tcx().evaluation_cache.hashmap.borrow();
if let Some(cached) = cache.get(&trait_ref) {
return Some(cached.clone());
@ -764,6 +759,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
}
fn insert_evaluation_cache(&mut self,
param_env: ty::ParamEnv<'tcx>,
trait_ref: ty::PolyTraitRef<'tcx>,
result: EvaluationResult)
{
@ -778,7 +774,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
return;
}
if self.can_use_global_caches() {
if self.can_use_global_caches(param_env) {
let mut cache = self.tcx().evaluation_cache.hashmap.borrow_mut();
if let Some(trait_ref) = self.tcx().lift_to_global(&trait_ref) {
cache.insert(trait_ref, result);
@ -819,7 +815,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
stack);
assert!(!stack.obligation.predicate.has_escaping_regions());
if let Some(c) = self.check_candidate_cache(&cache_fresh_trait_pred) {
if let Some(c) = self.check_candidate_cache(stack.obligation.param_env,
&cache_fresh_trait_pred) {
debug!("CACHE HIT: SELECT({:?})={:?}",
cache_fresh_trait_pred,
c);
@ -832,7 +829,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
if self.should_update_candidate_cache(&cache_fresh_trait_pred, &candidate) {
debug!("CACHE MISS: SELECT({:?})={:?}",
cache_fresh_trait_pred, candidate);
self.insert_candidate_cache(cache_fresh_trait_pred, candidate.clone());
self.insert_candidate_cache(stack.obligation.param_env,
cache_fresh_trait_pred,
candidate.clone());
}
candidate
@ -995,7 +994,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
/// Returns true if the global caches can be used.
/// Do note that if the type itself is not in the
/// global tcx, the local caches will be used.
fn can_use_global_caches(&self) -> bool {
fn can_use_global_caches(&self, param_env: ty::ParamEnv<'tcx>) -> bool {
// If there are any where-clauses in scope, then we always use
// a cache local to this particular scope. Otherwise, we
// switch to a global cache. We used to try and draw
@ -1003,7 +1002,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
// annoying and weird bugs like #22019 and #18290. This simple
// rule seems to be pretty clearly safe and also still retains
// a very high hit rate (~95% when compiling rustc).
if !self.param_env().caller_bounds.is_empty() {
if !param_env.caller_bounds.is_empty() {
return false;
}
@ -1023,11 +1022,12 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
}
fn check_candidate_cache(&mut self,
param_env: ty::ParamEnv<'tcx>,
cache_fresh_trait_pred: &ty::PolyTraitPredicate<'tcx>)
-> Option<SelectionResult<'tcx, SelectionCandidate<'tcx>>>
{
let trait_ref = &cache_fresh_trait_pred.0.trait_ref;
if self.can_use_global_caches() {
if self.can_use_global_caches(param_env) {
let cache = self.tcx().selection_cache.hashmap.borrow();
if let Some(cached) = cache.get(&trait_ref) {
return Some(cached.clone());
@ -1037,11 +1037,12 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
}
fn insert_candidate_cache(&mut self,
param_env: ty::ParamEnv<'tcx>,
cache_fresh_trait_pred: ty::PolyTraitPredicate<'tcx>,
candidate: SelectionResult<'tcx, SelectionCandidate<'tcx>>)
{
let trait_ref = cache_fresh_trait_pred.0.trait_ref;
if self.can_use_global_caches() {
if self.can_use_global_caches(param_env) {
let mut cache = self.tcx().selection_cache.hashmap.borrow_mut();
if let Some(trait_ref) = self.tcx().lift_to_global(&trait_ref) {
if let Some(candidate) = self.tcx().lift_to_global(&candidate) {
@ -1099,6 +1100,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
{
let TraitObligationStack { obligation, .. } = *stack;
let ref obligation = Obligation {
param_env: obligation.param_env,
cause: obligation.cause.clone(),
recursion_depth: obligation.recursion_depth,
predicate: self.infcx().resolve_type_vars_if_possible(&obligation.predicate)
@ -1269,11 +1271,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
-> bool
{
assert!(!skol_trait_ref.has_escaping_regions());
let cause = obligation.cause.clone();
match self.infcx.sub_poly_trait_refs(false,
cause,
trait_bound.clone(),
ty::Binder(skol_trait_ref.clone())) {
match self.infcx.at(&obligation.cause, obligation.param_env)
.sup(ty::Binder(skol_trait_ref), trait_bound) {
Ok(InferOk { obligations, .. }) => {
self.inferred_obligations.extend(obligations);
}
@ -1296,9 +1295,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
stack.obligation);
let all_bounds =
self.param_env().caller_bounds
.iter()
.filter_map(|o| o.to_opt_poly_trait_ref());
stack.obligation.param_env.caller_bounds
.iter()
.filter_map(|o| o.to_opt_poly_trait_ref());
// micro-optimization: filter out predicates relating to different
// traits.
@ -1953,6 +1952,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
}
fn collect_predicates_for_types(&mut self,
param_env: ty::ParamEnv<'tcx>,
cause: ObligationCause<'tcx>,
recursion_depth: usize,
trait_def_id: DefId,
@ -1981,16 +1981,17 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
this.infcx().skolemize_late_bound_regions(&ty, snapshot);
let Normalized { value: normalized_ty, mut obligations } =
project::normalize_with_depth(this,
param_env,
cause.clone(),
recursion_depth,
&skol_ty);
let skol_obligation =
this.tcx().predicate_for_trait_def(
cause.clone(),
trait_def_id,
recursion_depth,
normalized_ty,
&[]);
this.tcx().predicate_for_trait_def(param_env,
cause.clone(),
trait_def_id,
recursion_depth,
normalized_ty,
&[]);
obligations.push(skol_obligation);
this.infcx().plug_leaks(skol_map, snapshot, obligations)
})
@ -2131,7 +2132,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
};
let cause = obligation.derived_cause(BuiltinDerivedObligation);
self.collect_predicates_for_types(cause,
self.collect_predicates_for_types(obligation.param_env,
cause,
obligation.recursion_depth+1,
trait_def,
nested)
@ -2175,6 +2177,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
let cause = obligation.derived_cause(BuiltinDerivedObligation);
let mut obligations = self.collect_predicates_for_types(
obligation.param_env,
cause,
obligation.recursion_depth+1,
trait_def_id,
@ -2187,6 +2190,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
let cause = obligation.derived_cause(ImplDerivedObligation);
this.impl_or_trait_obligations(cause,
obligation.recursion_depth + 1,
obligation.param_env,
trait_def_id,
&trait_ref.substs,
skol_map,
@ -2220,9 +2224,13 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
snapshot);
debug!("confirm_impl_candidate substs={:?}", substs);
let cause = obligation.derived_cause(ImplDerivedObligation);
this.vtable_impl(impl_def_id, substs, cause,
this.vtable_impl(impl_def_id,
substs,
cause,
obligation.recursion_depth + 1,
skol_map, snapshot)
obligation.param_env,
skol_map,
snapshot)
})
}
@ -2231,6 +2239,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
mut substs: Normalized<'tcx, &'tcx Substs<'tcx>>,
cause: ObligationCause<'tcx>,
recursion_depth: usize,
param_env: ty::ParamEnv<'tcx>,
skol_map: infer::SkolemizationMap<'tcx>,
snapshot: &infer::CombinedSnapshot)
-> VtableImplData<'tcx, PredicateObligation<'tcx>>
@ -2244,6 +2253,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
let mut impl_obligations =
self.impl_or_trait_obligations(cause,
recursion_depth,
param_env,
impl_def_id,
&substs.value,
skol_map,
@ -2345,6 +2355,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
.map_bound(|(trait_ref, _)| trait_ref);
self.confirm_poly_trait_refs(obligation.cause.clone(),
obligation.param_env,
obligation.predicate.to_poly_trait_ref(),
trait_ref)?;
Ok(VtableFnPointerData { fn_ty: self_ty, nested: vec![] })
@ -2374,12 +2385,14 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
obligations);
self.confirm_poly_trait_refs(obligation.cause.clone(),
obligation.param_env,
obligation.predicate.to_poly_trait_ref(),
trait_ref)?;
obligations.push(Obligation::new(
obligation.cause.clone(),
ty::Predicate::ClosureKind(closure_def_id, kind)));
obligation.cause.clone(),
obligation.param_env,
ty::Predicate::ClosureKind(closure_def_id, kind)));
Ok(VtableClosureData {
closure_def_id: closure_def_id,
@ -2415,15 +2428,15 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
/// report an error to the user.
fn confirm_poly_trait_refs(&mut self,
obligation_cause: ObligationCause<'tcx>,
obligation_param_env: ty::ParamEnv<'tcx>,
obligation_trait_ref: ty::PolyTraitRef<'tcx>,
expected_trait_ref: ty::PolyTraitRef<'tcx>)
-> Result<(), SelectionError<'tcx>>
{
let obligation_trait_ref = obligation_trait_ref.clone();
self.infcx.sub_poly_trait_refs(false,
obligation_cause.clone(),
expected_trait_ref.clone(),
obligation_trait_ref.clone())
self.infcx
.at(&obligation_cause, obligation_param_env)
.sup(obligation_trait_ref, expected_trait_ref)
.map(|InferOk { obligations, .. }| self.inferred_obligations.extend(obligations))
.map_err(|e| OutputTypeParameterMismatch(expected_trait_ref, obligation_trait_ref, e))
}
@ -2458,8 +2471,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
let new_trait = tcx.mk_dynamic(
ty::Binder(tcx.mk_existential_predicates(iter)), r_b);
let InferOk { obligations, .. } =
self.infcx.eq_types(false, &obligation.cause, new_trait, target)
.map_err(|_| Unimplemented)?;
self.infcx.at(&obligation.cause, obligation.param_env)
.eq(target, new_trait)
.map_err(|_| Unimplemented)?;
self.inferred_obligations.extend(obligations);
// Register one obligation for 'a: 'b.
@ -2469,6 +2483,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
let outlives = ty::OutlivesPredicate(r_a, r_b);
nested.push(Obligation::with_depth(cause,
obligation.recursion_depth + 1,
obligation.param_env,
ty::Binder(outlives).to_predicate()));
}
@ -2488,6 +2503,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
let mut push = |predicate| {
nested.push(Obligation::with_depth(cause.clone(),
obligation.recursion_depth + 1,
obligation.param_env,
predicate));
};
@ -2517,8 +2533,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
// [T; n] -> [T].
(&ty::TyArray(a, _), &ty::TySlice(b)) => {
let InferOk { obligations, .. } =
self.infcx.eq_types(false, &obligation.cause, a, b)
.map_err(|_| Unimplemented)?;
self.infcx.at(&obligation.cause, obligation.param_env)
.eq(b, a)
.map_err(|_| Unimplemented)?;
self.inferred_obligations.extend(obligations);
}
@ -2580,12 +2597,14 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
});
let new_struct = tcx.mk_adt(def, tcx.mk_substs(params));
let InferOk { obligations, .. } =
self.infcx.eq_types(false, &obligation.cause, new_struct, target)
.map_err(|_| Unimplemented)?;
self.infcx.at(&obligation.cause, obligation.param_env)
.eq(target, new_struct)
.map_err(|_| Unimplemented)?;
self.inferred_obligations.extend(obligations);
// Construct the nested Field<T>: Unsize<Field<U>> predicate.
nested.push(tcx.predicate_for_trait_def(
obligation.param_env,
obligation.cause.clone(),
obligation.predicate.def_id(),
obligation.recursion_depth + 1,
@ -2655,6 +2674,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
let impl_trait_ref =
project::normalize_with_depth(self,
obligation.param_env,
obligation.cause.clone(),
obligation.recursion_depth + 1,
&impl_trait_ref);
@ -2667,14 +2687,12 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
skol_obligation_trait_ref);
let InferOk { obligations, .. } =
self.infcx.eq_trait_refs(false,
&obligation.cause,
impl_trait_ref.value.clone(),
skol_obligation_trait_ref)
.map_err(|e| {
debug!("match_impl: failed eq_trait_refs due to `{}`", e);
()
})?;
self.infcx.at(&obligation.cause, obligation.param_env)
.eq(skol_obligation_trait_ref, impl_trait_ref.value)
.map_err(|e| {
debug!("match_impl: failed eq_trait_refs due to `{}`", e);
()
})?;
self.inferred_obligations.extend(obligations);
if let Err(e) = self.infcx.leak_check(false,
@ -2740,12 +2758,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
obligation,
poly_trait_ref);
self.infcx.sub_poly_trait_refs(false,
obligation.cause.clone(),
poly_trait_ref,
obligation.predicate.to_poly_trait_ref())
.map(|InferOk { obligations, .. }| self.inferred_obligations.extend(obligations))
.map_err(|_| ())
self.infcx.at(&obligation.cause, obligation.param_env)
.sup(obligation.predicate.to_poly_trait_ref(), poly_trait_ref)
.map(|InferOk { obligations, .. }| self.inferred_obligations.extend(obligations))
.map_err(|_| ())
}
///////////////////////////////////////////////////////////////////////////
@ -2809,6 +2825,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
// A closure signature can contain associated types which
// must be normalized.
normalize_with_depth(self,
obligation.param_env,
obligation.cause.clone(),
obligation.recursion_depth+1,
&trait_ref)
@ -2821,6 +2838,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
fn impl_or_trait_obligations(&mut self,
cause: ObligationCause<'tcx>,
recursion_depth: usize,
param_env: ty::ParamEnv<'tcx>,
def_id: DefId, // of impl or trait
substs: &Substs<'tcx>, // for impl or trait
skol_map: infer::SkolemizationMap<'tcx>,
@ -2847,12 +2865,13 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
let predicates = tcx.predicates_of(def_id);
assert_eq!(predicates.parent, None);
let predicates = predicates.predicates.iter().flat_map(|predicate| {
let predicate = normalize_with_depth(self, cause.clone(), recursion_depth,
let predicate = normalize_with_depth(self, param_env, cause.clone(), recursion_depth,
&predicate.subst(tcx, substs));
predicate.obligations.into_iter().chain(
Some(Obligation {
cause: cause.clone(),
recursion_depth: recursion_depth,
param_env,
predicate: predicate.value
}))
}).collect();

View File

@ -41,6 +41,7 @@ pub struct OverlapError {
/// Given a subst for the requested impl, translate it to a subst
/// appropriate for the actual item definition (whether it be in that impl,
/// a parent impl, or the trait).
///
/// When we have selected one impl, but are actually using item definitions from
/// a parent impl providing a default, we need a way to translate between the
/// type parameters of the two impls. Here the `source_impl` is the one we've
@ -73,6 +74,7 @@ pub struct OverlapError {
/// *fulfillment* to relate the two impls, requiring that all projections are
/// resolved.
pub fn translate_substs<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
source_impl: DefId,
source_substs: &'tcx Substs<'tcx>,
target_node: specialization_graph::Node)
@ -91,10 +93,11 @@ pub fn translate_substs<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
return source_substs;
}
fulfill_implication(infcx, source_trait_ref, target_impl).unwrap_or_else(|_| {
bug!("When translating substitutions for specialization, the expected \
specializaiton failed to hold")
})
fulfill_implication(infcx, param_env, source_trait_ref, target_impl)
.unwrap_or_else(|_| {
bug!("When translating substitutions for specialization, the expected \
specializaiton failed to hold")
})
}
specialization_graph::Node::Trait(..) => source_trait_ref.substs,
};
@ -122,9 +125,10 @@ pub fn find_associated_item<'a, 'tcx>(
let ancestors = trait_def.ancestors(tcx, impl_data.impl_def_id);
match ancestors.defs(tcx, item.name, item.kind).next() {
Some(node_item) => {
let substs = tcx.infer_ctxt((), Reveal::All).enter(|infcx| {
let substs = tcx.infer_ctxt(()).enter(|infcx| {
let param_env = ty::ParamEnv::empty(Reveal::All);
let substs = substs.rebase_onto(tcx, trait_def_id, impl_data.substs);
let substs = translate_substs(&infcx, impl_data.impl_def_id,
let substs = translate_substs(&infcx, param_env, impl_data.impl_def_id,
substs, node_item.node);
let substs = infcx.tcx.erase_regions(&substs);
tcx.lift(&substs).unwrap_or_else(|| {
@ -184,11 +188,14 @@ pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let impl1_trait_ref = tcx.impl_trait_ref(impl1_def_id).unwrap();
// Create a infcx, taking the predicates of impl1 as assumptions:
let result = tcx.infer_ctxt(penv, Reveal::UserFacing).enter(|infcx| {
let result = tcx.infer_ctxt(()).enter(|infcx| {
// Normalize the trait reference. The WF rules ought to ensure
// that this always succeeds.
let impl1_trait_ref =
match traits::fully_normalize(&infcx, ObligationCause::dummy(), &impl1_trait_ref) {
match traits::fully_normalize(&infcx,
ObligationCause::dummy(),
penv,
&impl1_trait_ref) {
Ok(impl1_trait_ref) => impl1_trait_ref,
Err(err) => {
bug!("failed to fully normalize {:?}: {:?}", impl1_trait_ref, err);
@ -196,7 +203,7 @@ pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
};
// Attempt to prove that impl2 applies, given all of the above.
fulfill_implication(&infcx, impl1_trait_ref, impl2_def_id).is_ok()
fulfill_implication(&infcx, penv, impl1_trait_ref, impl2_def_id).is_ok()
});
tcx.specializes_cache.borrow_mut().insert(impl1_def_id, impl2_def_id, result);
@ -209,20 +216,20 @@ pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
/// `source_trait_ref` and those whose identity is determined via a where
/// clause in the impl.
fn fulfill_implication<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
source_trait_ref: ty::TraitRef<'tcx>,
target_impl: DefId)
-> Result<&'tcx Substs<'tcx>, ()> {
let selcx = &mut SelectionContext::new(&infcx);
let target_substs = infcx.fresh_substs_for_item(DUMMY_SP, target_impl);
let (target_trait_ref, mut obligations) = impl_trait_ref_and_oblig(selcx,
target_impl,
target_substs);
param_env,
target_impl,
target_substs);
// do the impls unify? If not, no specialization.
match infcx.eq_trait_refs(true,
&ObligationCause::dummy(),
source_trait_ref,
target_trait_ref) {
match infcx.at(&ObligationCause::dummy(), param_env)
.eq(source_trait_ref, target_trait_ref) {
Ok(InferOk { obligations: o, .. }) => {
obligations.extend(o);
}
@ -250,7 +257,7 @@ fn fulfill_implication<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
source_trait_ref,
target_trait_ref,
errors,
infcx.param_env.caller_bounds);
param_env.caller_bounds);
Err(())
}

View File

@ -11,7 +11,7 @@
use super::{OverlapError, specializes};
use hir::def_id::DefId;
use traits::{self, Reveal};
use traits;
use ty::{self, TyCtxt, TypeFoldable};
use ty::fast_reject::{self, SimplifiedType};
use std::rc::Rc;
@ -109,7 +109,7 @@ impl<'a, 'gcx, 'tcx> Children {
let possible_sibling = *slot;
let tcx = tcx.global_tcx();
let (le, ge) = tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| {
let (le, ge) = tcx.infer_ctxt(()).enter(|infcx| {
let overlap = traits::overlapping_impls(&infcx,
possible_sibling,
impl_def_id);

View File

@ -341,6 +341,7 @@ impl<'tcx, O: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Obligation<'tcx
cause: self.cause.clone(),
recursion_depth: self.recursion_depth,
predicate: self.predicate.fold_with(folder),
param_env: self.param_env.fold_with(folder),
}
}

View File

@ -46,12 +46,14 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
// Do the initial selection for the obligation. This yields the
// shallow result we are looking for -- that is, what specific impl.
self.infer_ctxt((), Reveal::All).enter(|infcx| {
self.infer_ctxt(()).enter(|infcx| {
let mut selcx = SelectionContext::new(&infcx);
let param_env = ty::ParamEnv::empty(Reveal::All);
let obligation_cause = ObligationCause::misc(span,
ast::DUMMY_NODE_ID);
let obligation = Obligation::new(obligation_cause,
param_env,
trait_ref.to_poly_trait_predicate());
let selection = match selcx.select(&obligation) {

View File

@ -358,6 +358,7 @@ impl<'tcx,I:Iterator<Item=ty::Predicate<'tcx>>> Iterator for FilterToTraits<I> {
/// returning the resulting trait ref and all obligations that arise.
/// The obligations are closed under normalization.
pub fn impl_trait_ref_and_oblig<'a, 'gcx, 'tcx>(selcx: &mut SelectionContext<'a, 'gcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
impl_def_id: DefId,
impl_substs: &Substs<'tcx>)
-> (ty::TraitRef<'tcx>,
@ -368,14 +369,14 @@ pub fn impl_trait_ref_and_oblig<'a, 'gcx, 'tcx>(selcx: &mut SelectionContext<'a,
let impl_trait_ref =
impl_trait_ref.subst(selcx.tcx(), impl_substs);
let Normalized { value: impl_trait_ref, obligations: normalization_obligations1 } =
super::normalize(selcx, ObligationCause::dummy(), &impl_trait_ref);
super::normalize(selcx, param_env, ObligationCause::dummy(), &impl_trait_ref);
let predicates = selcx.tcx().predicates_of(impl_def_id);
let predicates = predicates.instantiate(selcx.tcx(), impl_substs);
let Normalized { value: predicates, obligations: normalization_obligations2 } =
super::normalize(selcx, ObligationCause::dummy(), &predicates);
super::normalize(selcx, param_env, ObligationCause::dummy(), &predicates);
let impl_obligations =
predicates_for_generics(ObligationCause::dummy(), 0, &predicates);
predicates_for_generics(ObligationCause::dummy(), 0, param_env, &predicates);
let impl_obligations: Vec<_> =
impl_obligations.into_iter()
@ -389,6 +390,7 @@ pub fn impl_trait_ref_and_oblig<'a, 'gcx, 'tcx>(selcx: &mut SelectionContext<'a,
/// See `super::obligations_for_generics`
pub fn predicates_for_generics<'tcx>(cause: ObligationCause<'tcx>,
recursion_depth: usize,
param_env: ty::ParamEnv<'tcx>,
generic_bounds: &ty::InstantiatedPredicates<'tcx>)
-> Vec<PredicateObligation<'tcx>>
{
@ -398,18 +400,21 @@ pub fn predicates_for_generics<'tcx>(cause: ObligationCause<'tcx>,
generic_bounds.predicates.iter().map(|predicate| {
Obligation { cause: cause.clone(),
recursion_depth: recursion_depth,
param_env: param_env,
predicate: predicate.clone() }
}).collect()
}
pub fn predicate_for_trait_ref<'tcx>(
cause: ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
trait_ref: ty::TraitRef<'tcx>,
recursion_depth: usize)
-> PredicateObligation<'tcx>
{
Obligation {
cause: cause,
param_env: param_env,
recursion_depth: recursion_depth,
predicate: trait_ref.to_predicate(),
}
@ -417,18 +422,19 @@ pub fn predicate_for_trait_ref<'tcx>(
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
pub fn predicate_for_trait_def(self,
cause: ObligationCause<'tcx>,
trait_def_id: DefId,
recursion_depth: usize,
param_ty: Ty<'tcx>,
ty_params: &[Ty<'tcx>])
param_env: ty::ParamEnv<'tcx>,
cause: ObligationCause<'tcx>,
trait_def_id: DefId,
recursion_depth: usize,
param_ty: Ty<'tcx>,
ty_params: &[Ty<'tcx>])
-> PredicateObligation<'tcx>
{
let trait_ref = ty::TraitRef {
def_id: trait_def_id,
substs: self.mk_substs_trait(param_ty, ty_params)
};
predicate_for_trait_ref(cause, trait_ref, recursion_depth)
predicate_for_trait_ref(cause, param_env, trait_ref, recursion_depth)
}
/// Cast a trait reference into a reference to one of its super

View File

@ -519,9 +519,6 @@ pub struct GlobalCtxt<'tcx> {
/// Data layout specification for the current target.
pub data_layout: TargetDataLayout,
/// Cache for layouts computed from types.
pub layout_cache: RefCell<FxHashMap<Ty<'tcx>, &'tcx Layout>>,
/// Used to prevent layout from recursing too deeply.
pub layout_depth: Cell<usize>,
@ -718,7 +715,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
rvalue_promotable_to_static: RefCell::new(NodeMap()),
crate_name: Symbol::intern(crate_name),
data_layout: data_layout,
layout_cache: RefCell::new(FxHashMap()),
layout_interner: RefCell::new(FxHashSet()),
layout_depth: Cell::new(0),
derive_macros: RefCell::new(NodeMap()),
@ -765,6 +761,18 @@ pub trait Lift<'tcx> {
fn lift_to_tcx<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<Self::Lifted>;
}
impl<'a, 'tcx> Lift<'tcx> for ty::ParamEnv<'a> {
type Lifted = ty::ParamEnv<'tcx>;
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<ty::ParamEnv<'tcx>> {
self.caller_bounds.lift_to_tcx(tcx).and_then(|caller_bounds| {
Some(ty::ParamEnv {
reveal: self.reveal,
caller_bounds,
})
})
}
}
impl<'a, 'tcx> Lift<'tcx> for Ty<'a> {
type Lifted = Ty<'tcx>;
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Ty<'tcx>> {
@ -851,6 +859,25 @@ impl<'a, 'tcx> Lift<'tcx> for &'a Slice<ExistentialPredicate<'a>> {
}
}
impl<'a, 'tcx> Lift<'tcx> for &'a Slice<Predicate<'a>> {
type Lifted = &'tcx Slice<Predicate<'tcx>>;
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>)
-> Option<&'tcx Slice<Predicate<'tcx>>> {
if self.is_empty() {
return Some(Slice::empty());
}
if tcx.interners.arena.in_arena(*self as *const _) {
return Some(unsafe { mem::transmute(*self) });
}
// Also try in the global tcx if we're not that.
if !tcx.is_global() {
self.lift_to_tcx(tcx.global_tcx())
} else {
None
}
}
}
pub mod tls {
use super::{CtxtInterners, GlobalCtxt, TyCtxt};

View File

@ -12,12 +12,10 @@ pub use self::Integer::*;
pub use self::Layout::*;
pub use self::Primitive::*;
use infer::InferCtxt;
use session::Session;
use traits;
use session::{self, DataTypeKind, Session};
use ty::{self, Ty, TyCtxt, TypeFoldable, ReprOptions, ReprFlags};
use syntax::ast::{FloatTy, IntTy, UintTy};
use syntax::ast::{self, FloatTy, IntTy, UintTy};
use syntax::attr;
use syntax_pos::DUMMY_SP;
@ -212,6 +210,12 @@ impl<'a> HasDataLayout for &'a TargetDataLayout {
}
}
impl<'a, 'tcx> HasDataLayout for TyCtxt<'a, 'tcx, 'tcx> {
fn data_layout(&self) -> &TargetDataLayout {
&self.data_layout
}
}
/// Endianness of the target, which must match cfg(target-endian).
#[derive(Copy, Clone)]
pub enum Endian {
@ -457,8 +461,12 @@ impl Integer {
/// signed discriminant range and #[repr] attribute.
/// N.B.: u64 values above i64::MAX will be treated as signed, but
/// that shouldn't affect anything, other than maybe debuginfo.
fn repr_discr(tcx: TyCtxt, ty: Ty, repr: &ReprOptions, min: i64, max: i64)
-> (Integer, bool) {
fn repr_discr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
ty: Ty<'tcx>,
repr: &ReprOptions,
min: i64,
max: i64)
-> (Integer, bool) {
// Theoretically, negative values could be larger in unsigned representation
// than the unsigned representation of the signed minimum. However, if there
// are any negative values, the only valid unsigned representation is u64
@ -583,10 +591,13 @@ enum StructKind {
EnumVariant,
}
impl<'a, 'gcx, 'tcx> Struct {
fn new(dl: &TargetDataLayout, fields: &Vec<&'a Layout>,
repr: &ReprOptions, kind: StructKind,
scapegoat: Ty<'gcx>) -> Result<Struct, LayoutError<'gcx>> {
impl<'a, 'tcx> Struct {
fn new(dl: &TargetDataLayout,
fields: &Vec<&'a Layout>,
repr: &ReprOptions,
kind: StructKind,
scapegoat: Ty<'tcx>)
-> Result<Struct, LayoutError<'tcx>> {
if repr.packed() && repr.align > 0 {
bug!("Struct cannot be packed and aligned");
}
@ -723,8 +734,8 @@ impl<'a, 'gcx, 'tcx> Struct {
/// Determine whether a structure would be zero-sized, given its fields.
fn would_be_zero_sized<I>(dl: &TargetDataLayout, fields: I)
-> Result<bool, LayoutError<'gcx>>
where I: Iterator<Item=Result<&'a Layout, LayoutError<'gcx>>> {
-> Result<bool, LayoutError<'tcx>>
where I: Iterator<Item=Result<&'a Layout, LayoutError<'tcx>>> {
for field in fields {
let field = field?;
if field.is_unsized() || field.size(dl).bytes() > 0 {
@ -764,11 +775,11 @@ impl<'a, 'gcx, 'tcx> Struct {
/// The tuple is `(path, source_path)`,
/// where `path` is in memory order and `source_path` in source order.
// FIXME(eddyb) track value ranges and traverse already optimized enums.
fn non_zero_field_in_type(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
ty: Ty<'gcx>)
-> Result<Option<(FieldPath, FieldPath)>, LayoutError<'gcx>> {
let tcx = infcx.tcx.global_tcx();
match (ty.layout(infcx)?, &ty.sty) {
fn non_zero_field_in_type(tcx: TyCtxt<'a, 'tcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
ty: Ty<'tcx>)
-> Result<Option<(FieldPath, FieldPath)>, LayoutError<'tcx>> {
match (ty.layout(tcx, param_env)?, &ty.sty) {
(&Scalar { non_zero: true, .. }, _) |
(&CEnum { non_zero: true, .. }, _) => Ok(Some((vec![], vec![]))),
(&FatPointer { non_zero: true, .. }, _) => {
@ -779,7 +790,7 @@ impl<'a, 'gcx, 'tcx> Struct {
(&Univariant { non_zero: true, .. }, &ty::TyAdt(def, substs)) => {
let fields = &def.struct_variant().fields;
assert_eq!(fields.len(), 1);
match *fields[0].ty(tcx, substs).layout(infcx)? {
match *fields[0].ty(tcx, substs).layout(tcx, param_env)? {
// FIXME(eddyb) also allow floating-point types here.
Scalar { value: Int(_), non_zero: false } |
Scalar { value: Pointer, non_zero: false } => {
@ -796,37 +807,49 @@ impl<'a, 'gcx, 'tcx> Struct {
// Perhaps one of the fields of this struct is non-zero
// let's recurse and find out
(&Univariant { ref variant, .. }, &ty::TyAdt(def, substs)) if def.is_struct() => {
Struct::non_zero_field_paths(infcx, def.struct_variant().fields
.iter().map(|field| {
field.ty(tcx, substs)
}),
Some(&variant.memory_index[..]))
Struct::non_zero_field_paths(
tcx,
param_env,
def.struct_variant().fields.iter().map(|field| {
field.ty(tcx, substs)
}),
Some(&variant.memory_index[..]))
}
// Perhaps one of the upvars of this closure is non-zero
(&Univariant { ref variant, .. }, &ty::TyClosure(def, substs)) => {
let upvar_tys = substs.upvar_tys(def, tcx);
Struct::non_zero_field_paths(infcx, upvar_tys,
Struct::non_zero_field_paths(
tcx,
param_env,
upvar_tys,
Some(&variant.memory_index[..]))
}
// Can we use one of the fields in this tuple?
(&Univariant { ref variant, .. }, &ty::TyTuple(tys, _)) => {
Struct::non_zero_field_paths(infcx, tys.iter().cloned(),
Struct::non_zero_field_paths(
tcx,
param_env,
tys.iter().cloned(),
Some(&variant.memory_index[..]))
}
// Is this a fixed-size array of something non-zero
// with at least one element?
(_, &ty::TyArray(ety, d)) if d > 0 => {
Struct::non_zero_field_paths(infcx, Some(ety).into_iter(), None)
Struct::non_zero_field_paths(
tcx,
param_env,
Some(ety).into_iter(),
None)
}
(_, &ty::TyProjection(_)) | (_, &ty::TyAnon(..)) => {
let normalized = infcx.normalize_projections(ty);
let normalized = tcx.normalize_associated_type_in_env(&ty, param_env);
if ty == normalized {
return Ok(None);
}
return Struct::non_zero_field_in_type(infcx, normalized);
return Struct::non_zero_field_in_type(tcx, param_env, normalized);
}
// Anything else is not a non-zero type.
@ -838,13 +861,15 @@ impl<'a, 'gcx, 'tcx> Struct {
/// the given set of fields and recursing through aggregates.
/// Returns Some((path, source_path)) on success.
/// `path` is translated to memory order. `source_path` is not.
fn non_zero_field_paths<I>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
fields: I,
permutation: Option<&[u32]>)
-> Result<Option<(FieldPath, FieldPath)>, LayoutError<'gcx>>
where I: Iterator<Item=Ty<'gcx>> {
fn non_zero_field_paths<I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
fields: I,
permutation: Option<&[u32]>)
-> Result<Option<(FieldPath, FieldPath)>, LayoutError<'tcx>>
where I: Iterator<Item=Ty<'tcx>> {
for (i, ty) in fields.enumerate() {
if let Some((mut path, mut source_path)) = Struct::non_zero_field_in_type(infcx, ty)? {
let r = Struct::non_zero_field_in_type(tcx, param_env, ty)?;
if let Some((mut path, mut source_path)) = r {
source_path.push(i as u32);
let index = if let Some(p) = permutation {
p[i] as usize
@ -881,7 +906,7 @@ pub struct Union {
pub packed: bool,
}
impl<'a, 'gcx, 'tcx> Union {
impl<'a, 'tcx> Union {
fn new(dl: &TargetDataLayout, packed: bool) -> Union {
let align = if packed { dl.i8_align } else { dl.aggregate_align };
Union {
@ -895,9 +920,9 @@ impl<'a, 'gcx, 'tcx> Union {
/// Extend the Struct with more fields.
fn extend<I>(&mut self, dl: &TargetDataLayout,
fields: I,
scapegoat: Ty<'gcx>)
-> Result<(), LayoutError<'gcx>>
where I: Iterator<Item=Result<&'a Layout, LayoutError<'gcx>>> {
scapegoat: Ty<'tcx>)
-> Result<(), LayoutError<'tcx>>
where I: Iterator<Item=Result<&'a Layout, LayoutError<'tcx>>> {
for (index, field) in fields.enumerate() {
let field = field?;
if field.is_unsized() {
@ -1067,19 +1092,19 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> {
}
}
impl<'a, 'gcx, 'tcx> Layout {
pub fn compute_uncached(ty: Ty<'gcx>,
infcx: &InferCtxt<'a, 'gcx, 'tcx>)
-> Result<&'gcx Layout, LayoutError<'gcx>> {
let tcx = infcx.tcx.global_tcx();
impl<'a, 'tcx> Layout {
pub fn compute_uncached(tcx: TyCtxt<'a, 'tcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
ty: Ty<'tcx>)
-> Result<&'tcx Layout, LayoutError<'tcx>> {
let success = |layout| Ok(tcx.intern_layout(layout));
let dl = &tcx.data_layout;
assert!(!ty.has_infer_types());
let ptr_layout = |pointee: Ty<'gcx>| {
let ptr_layout = |pointee: Ty<'tcx>| {
let non_zero = !ty.is_unsafe_ptr();
let pointee = infcx.normalize_projections(pointee);
if pointee.is_sized(tcx, infcx.param_env, DUMMY_SP) {
let pointee = tcx.normalize_associated_type_in_env(&pointee, param_env);
if pointee.is_sized(tcx, param_env, DUMMY_SP) {
Ok(Scalar { value: Pointer, non_zero: non_zero })
} else {
let unsized_part = tcx.struct_tail(pointee);
@ -1132,7 +1157,7 @@ impl<'a, 'gcx, 'tcx> Layout {
// Arrays and slices.
ty::TyArray(element, count) => {
let element = element.layout(infcx)?;
let element = element.layout(tcx, param_env)?;
let element_size = element.size(dl);
// FIXME(eddyb) Don't use host `usize` for array lengths.
let usize_count: usize = count;
@ -1149,7 +1174,7 @@ impl<'a, 'gcx, 'tcx> Layout {
}
}
ty::TySlice(element) => {
let element = element.layout(infcx)?;
let element = element.layout(tcx, param_env)?;
Array {
sized: false,
align: element.align(dl),
@ -1187,7 +1212,7 @@ impl<'a, 'gcx, 'tcx> Layout {
ty::TyClosure(def_id, ref substs) => {
let tys = substs.upvar_tys(def_id, tcx);
let st = Struct::new(dl,
&tys.map(|ty| ty.layout(infcx))
&tys.map(|ty| ty.layout(tcx, param_env))
.collect::<Result<Vec<_>, _>>()?,
&ReprOptions::default(),
StructKind::AlwaysSizedUnivariant, ty)?;
@ -1198,7 +1223,7 @@ impl<'a, 'gcx, 'tcx> Layout {
// FIXME(camlorn): if we ever allow unsized tuples, this needs to be checked.
// See the univariant case below to learn how.
let st = Struct::new(dl,
&tys.iter().map(|ty| ty.layout(infcx))
&tys.iter().map(|ty| ty.layout(tcx, param_env))
.collect::<Result<Vec<_>, _>>()?,
&ReprOptions::default(), StructKind::AlwaysSizedUnivariant, ty)?;
Univariant { variant: st, non_zero: false }
@ -1207,7 +1232,7 @@ impl<'a, 'gcx, 'tcx> Layout {
// SIMD vector types.
ty::TyAdt(def, ..) if def.repr.simd() => {
let element = ty.simd_type(tcx);
match *element.layout(infcx)? {
match *element.layout(tcx, param_env)? {
Scalar { value, .. } => {
return success(Vector {
element: value,
@ -1278,7 +1303,7 @@ impl<'a, 'gcx, 'tcx> Layout {
};
let fields = def.variants[0].fields.iter().map(|field| {
field.ty(tcx, substs).layout(infcx)
field.ty(tcx, substs).layout(tcx, param_env)
}).collect::<Result<Vec<_>, _>>()?;
let layout = if def.is_union() {
let mut un = Union::new(dl, def.repr.packed());
@ -1312,20 +1337,21 @@ impl<'a, 'gcx, 'tcx> Layout {
// Nullable pointer optimization
for discr in 0..2 {
let other_fields = variants[1 - discr].iter().map(|ty| {
ty.layout(infcx)
ty.layout(tcx, param_env)
});
if !Struct::would_be_zero_sized(dl, other_fields)? {
continue;
}
let paths = Struct::non_zero_field_paths(infcx,
variants[discr].iter().cloned(),
None)?;
let paths = Struct::non_zero_field_paths(tcx,
param_env,
variants[discr].iter().cloned(),
None)?;
let (mut path, mut path_source) = if let Some(p) = paths { p }
else { continue };
// FIXME(eddyb) should take advantage of a newtype.
if path == &[0] && variants[discr].len() == 1 {
let value = match *variants[discr][0].layout(infcx)? {
let value = match *variants[discr][0].layout(tcx, param_env)? {
Scalar { value, .. } => value,
CEnum { discr, .. } => Int(discr),
_ => bug!("Layout::compute: `{}`'s non-zero \
@ -1339,7 +1365,7 @@ impl<'a, 'gcx, 'tcx> Layout {
}
let st = Struct::new(dl,
&variants[discr].iter().map(|ty| ty.layout(infcx))
&variants[discr].iter().map(|ty| ty.layout(tcx, param_env))
.collect::<Result<Vec<_>, _>>()?,
&def.repr, StructKind::AlwaysSizedUnivariant, ty)?;
@ -1377,7 +1403,7 @@ impl<'a, 'gcx, 'tcx> Layout {
let discr = Scalar { value: Int(min_ity), non_zero: false };
let mut variants = variants.into_iter().map(|fields| {
let mut fields = fields.into_iter().map(|field| {
field.layout(infcx)
field.layout(tcx, param_env)
}).collect::<Result<Vec<_>, _>>()?;
fields.insert(0, &discr);
let st = Struct::new(dl,
@ -1470,11 +1496,11 @@ impl<'a, 'gcx, 'tcx> Layout {
// Types with no meaningful known layout.
ty::TyProjection(_) | ty::TyAnon(..) => {
let normalized = infcx.normalize_projections(ty);
let normalized = tcx.normalize_associated_type_in_env(&ty, param_env);
if ty == normalized {
return Err(LayoutError::Unknown(ty));
}
return normalized.layout(infcx);
return normalized.layout(tcx, param_env);
}
ty::TyParam(_) => {
return Err(LayoutError::Unknown(ty));
@ -1664,6 +1690,225 @@ impl<'a, 'gcx, 'tcx> Layout {
}
}
}
/// This is invoked by the `layout_raw` query to record the final
/// layout of each type.
#[inline]
pub fn record_layout_for_printing(tcx: TyCtxt<'a, 'tcx, 'tcx>,
ty: Ty<'tcx>,
param_env: ty::ParamEnv<'tcx>,
layout: &Layout) {
// If we are running with `-Zprint-type-sizes`, record layouts for
// dumping later. Ignore layouts that are done with non-empty
// environments or non-monomorphic layouts, as the user only wants
// to see the stuff resulting from the final trans session.
if
!tcx.sess.opts.debugging_opts.print_type_sizes ||
ty.has_param_types() ||
ty.has_self_ty() ||
!param_env.caller_bounds.is_empty()
{
return;
}
Self::record_layout_for_printing_outlined(tcx, ty, param_env, layout)
}
fn record_layout_for_printing_outlined(tcx: TyCtxt<'a, 'tcx, 'tcx>,
ty: Ty<'tcx>,
param_env: ty::ParamEnv<'tcx>,
layout: &Layout) {
// (delay format until we actually need it)
let record = |kind, opt_discr_size, variants| {
let type_desc = format!("{:?}", ty);
let overall_size = layout.size(tcx);
let align = layout.align(tcx);
tcx.sess.code_stats.borrow_mut().record_type_size(kind,
type_desc,
align,
overall_size,
opt_discr_size,
variants);
};
let (adt_def, substs) = match ty.sty {
ty::TyAdt(ref adt_def, substs) => {
debug!("print-type-size t: `{:?}` process adt", ty);
(adt_def, substs)
}
ty::TyClosure(..) => {
debug!("print-type-size t: `{:?}` record closure", ty);
record(DataTypeKind::Closure, None, vec![]);
return;
}
_ => {
debug!("print-type-size t: `{:?}` skip non-nominal", ty);
return;
}
};
let adt_kind = adt_def.adt_kind();
let build_field_info = |(field_name, field_ty): (ast::Name, Ty<'tcx>), offset: &Size| {
let layout = field_ty.layout(tcx, param_env);
match layout {
Err(_) => bug!("no layout found for field {} type: `{:?}`", field_name, field_ty),
Ok(field_layout) => {
session::FieldInfo {
name: field_name.to_string(),
offset: offset.bytes(),
size: field_layout.size(tcx).bytes(),
align: field_layout.align(tcx).abi(),
}
}
}
};
let build_primitive_info = |name: ast::Name, value: &Primitive| {
session::VariantInfo {
name: Some(name.to_string()),
kind: session::SizeKind::Exact,
align: value.align(tcx).abi(),
size: value.size(tcx).bytes(),
fields: vec![],
}
};
enum Fields<'a> {
WithDiscrim(&'a Struct),
NoDiscrim(&'a Struct),
}
let build_variant_info = |n: Option<ast::Name>,
flds: &[(ast::Name, Ty<'tcx>)],
layout: Fields| {
let (s, field_offsets) = match layout {
Fields::WithDiscrim(s) => (s, &s.offsets[1..]),
Fields::NoDiscrim(s) => (s, &s.offsets[0..]),
};
let field_info: Vec<_> =
flds.iter()
.zip(field_offsets.iter())
.map(|(&field_name_ty, offset)| build_field_info(field_name_ty, offset))
.collect();
session::VariantInfo {
name: n.map(|n|n.to_string()),
kind: if s.sized {
session::SizeKind::Exact
} else {
session::SizeKind::Min
},
align: s.align.abi(),
size: s.min_size.bytes(),
fields: field_info,
}
};
match *layout {
Layout::StructWrappedNullablePointer { nonnull: ref variant_layout,
nndiscr,
discrfield: _,
discrfield_source: _ } => {
debug!("print-type-size t: `{:?}` adt struct-wrapped nullable nndiscr {} is {:?}",
ty, nndiscr, variant_layout);
let variant_def = &adt_def.variants[nndiscr as usize];
let fields: Vec<_> =
variant_def.fields.iter()
.map(|field_def| (field_def.name, field_def.ty(tcx, substs)))
.collect();
record(adt_kind.into(),
None,
vec![build_variant_info(Some(variant_def.name),
&fields,
Fields::NoDiscrim(variant_layout))]);
}
Layout::RawNullablePointer { nndiscr, value } => {
debug!("print-type-size t: `{:?}` adt raw nullable nndiscr {} is {:?}",
ty, nndiscr, value);
let variant_def = &adt_def.variants[nndiscr as usize];
record(adt_kind.into(), None,
vec![build_primitive_info(variant_def.name, &value)]);
}
Layout::Univariant { variant: ref variant_layout, non_zero: _ } => {
let variant_names = || {
adt_def.variants.iter().map(|v|format!("{}", v.name)).collect::<Vec<_>>()
};
debug!("print-type-size t: `{:?}` adt univariant {:?} variants: {:?}",
ty, variant_layout, variant_names());
assert!(adt_def.variants.len() <= 1,
"univariant with variants {:?}", variant_names());
if adt_def.variants.len() == 1 {
let variant_def = &adt_def.variants[0];
let fields: Vec<_> =
variant_def.fields.iter()
.map(|f| (f.name, f.ty(tcx, substs)))
.collect();
record(adt_kind.into(),
None,
vec![build_variant_info(Some(variant_def.name),
&fields,
Fields::NoDiscrim(variant_layout))]);
} else {
// (This case arises for *empty* enums; so give it
// zero variants.)
record(adt_kind.into(), None, vec![]);
}
}
Layout::General { ref variants, discr, .. } => {
debug!("print-type-size t: `{:?}` adt general variants def {} layouts {} {:?}",
ty, adt_def.variants.len(), variants.len(), variants);
let variant_infos: Vec<_> =
adt_def.variants.iter()
.zip(variants.iter())
.map(|(variant_def, variant_layout)| {
let fields: Vec<_> =
variant_def.fields
.iter()
.map(|f| (f.name, f.ty(tcx, substs)))
.collect();
build_variant_info(Some(variant_def.name),
&fields,
Fields::WithDiscrim(variant_layout))
})
.collect();
record(adt_kind.into(), Some(discr.size()), variant_infos);
}
Layout::UntaggedUnion { ref variants } => {
debug!("print-type-size t: `{:?}` adt union variants {:?}",
ty, variants);
// layout does not currently store info about each
// variant...
record(adt_kind.into(), None, Vec::new());
}
Layout::CEnum { discr, .. } => {
debug!("print-type-size t: `{:?}` adt c-like enum", ty);
let variant_infos: Vec<_> =
adt_def.variants.iter()
.map(|variant_def| {
build_primitive_info(variant_def.name,
&Primitive::Int(discr))
})
.collect();
record(adt_kind.into(), Some(discr.size()), variant_infos);
}
// other cases provide little interesting (i.e. adjustable
// via representation tweaks) size info beyond total size.
Layout::Scalar { .. } |
Layout::Vector { .. } |
Layout::Array { .. } |
Layout::FatPointer { .. } => {
debug!("print-type-size t: `{:?}` adt other", ty);
record(adt_kind.into(), None, Vec::new())
}
}
}
}
/// Type size "skeleton", i.e. the only information determining a type's size.
@ -1686,21 +1931,22 @@ pub enum SizeSkeleton<'tcx> {
}
}
impl<'a, 'gcx, 'tcx> SizeSkeleton<'gcx> {
pub fn compute(ty: Ty<'gcx>, infcx: &InferCtxt<'a, 'gcx, 'tcx>)
-> Result<SizeSkeleton<'gcx>, LayoutError<'gcx>> {
let tcx = infcx.tcx.global_tcx();
impl<'a, 'tcx> SizeSkeleton<'tcx> {
pub fn compute(ty: Ty<'tcx>,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>)
-> Result<SizeSkeleton<'tcx>, LayoutError<'tcx>> {
assert!(!ty.has_infer_types());
// First try computing a static layout.
let err = match ty.layout(infcx) {
let err = match ty.layout(tcx, param_env) {
Ok(layout) => {
return Ok(SizeSkeleton::Known(layout.size(tcx)));
}
Err(err) => err
};
let ptr_skeleton = |pointee: Ty<'gcx>| {
let ptr_skeleton = |pointee: Ty<'tcx>| {
let non_zero = !ty.is_unsafe_ptr();
let tail = tcx.struct_tail(pointee);
match tail.sty {
@ -1737,7 +1983,7 @@ impl<'a, 'gcx, 'tcx> SizeSkeleton<'gcx> {
// Get a zero-sized variant or a pointer newtype.
let zero_or_ptr_variant = |i: usize| {
let fields = def.variants[i].fields.iter().map(|field| {
SizeSkeleton::compute(field.ty(tcx, substs), infcx)
SizeSkeleton::compute(field.ty(tcx, substs), tcx, param_env)
});
let mut ptr = None;
for field in fields {
@ -1788,11 +2034,11 @@ impl<'a, 'gcx, 'tcx> SizeSkeleton<'gcx> {
}
ty::TyProjection(_) | ty::TyAnon(..) => {
let normalized = infcx.normalize_projections(ty);
let normalized = tcx.normalize_associated_type_in_env(&ty, param_env);
if ty == normalized {
Err(err)
} else {
SizeSkeleton::compute(normalized, infcx)
SizeSkeleton::compute(normalized, tcx, param_env)
}
}
@ -1826,71 +2072,53 @@ impl<'tcx> Deref for TyLayout<'tcx> {
}
}
pub trait HasTyCtxt<'tcx>: HasDataLayout {
pub trait LayoutTyper<'tcx>: HasDataLayout {
type TyLayout;
fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx>;
fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout;
fn normalize_projections(self, ty: Ty<'tcx>) -> Ty<'tcx>;
}
impl<'a, 'gcx, 'tcx> HasDataLayout for TyCtxt<'a, 'gcx, 'tcx> {
fn data_layout(&self) -> &TargetDataLayout {
&self.data_layout
/// Combines a tcx with the parameter environment so that you can
/// compute layout operations.
#[derive(Copy, Clone)]
pub struct LayoutCx<'a, 'tcx: 'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
}
impl<'a, 'tcx> LayoutCx<'a, 'tcx> {
pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self {
LayoutCx { tcx, param_env }
}
}
impl<'a, 'gcx, 'tcx> HasTyCtxt<'gcx> for TyCtxt<'a, 'gcx, 'tcx> {
fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'gcx> {
self.global_tcx()
}
}
impl<'a, 'gcx, 'tcx> HasDataLayout for &'a InferCtxt<'a, 'gcx, 'tcx> {
impl<'a, 'tcx> HasDataLayout for LayoutCx<'a, 'tcx> {
fn data_layout(&self) -> &TargetDataLayout {
&self.tcx.data_layout
}
}
impl<'a, 'gcx, 'tcx> HasTyCtxt<'gcx> for &'a InferCtxt<'a, 'gcx, 'tcx> {
fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'gcx> {
self.tcx.global_tcx()
impl<'a, 'tcx> LayoutTyper<'tcx> for LayoutCx<'a, 'tcx> {
type TyLayout = Result<TyLayout<'tcx>, LayoutError<'tcx>>;
fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> {
self.tcx
}
}
pub trait LayoutTyper<'tcx>: HasTyCtxt<'tcx> {
type TyLayout;
fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout;
fn normalize_projections(self, ty: Ty<'tcx>) -> Ty<'tcx>;
}
impl<'a, 'gcx, 'tcx> LayoutTyper<'gcx> for &'a InferCtxt<'a, 'gcx, 'tcx> {
type TyLayout = Result<TyLayout<'gcx>, LayoutError<'gcx>>;
fn layout_of(self, ty: Ty<'gcx>) -> Self::TyLayout {
fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
let ty = self.normalize_projections(ty);
Ok(TyLayout {
ty: ty,
layout: ty.layout(self)?,
layout: ty.layout(self.tcx, self.param_env)?,
variant_index: None
})
}
fn normalize_projections(self, ty: Ty<'gcx>) -> Ty<'gcx> {
if !ty.has_projection_types() {
return ty;
}
let mut selcx = traits::SelectionContext::new(self);
let cause = traits::ObligationCause::dummy();
let traits::Normalized { value: result, obligations } =
traits::normalize(&mut selcx, cause, &ty);
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)
fn normalize_projections(self, ty: Ty<'tcx>) -> Ty<'tcx> {
self.tcx.normalize_associated_type_in_env(&ty, self.param_env)
}
}
@ -1943,7 +2171,7 @@ impl<'a, 'tcx> TyLayout<'tcx> {
}
}
pub fn field_type<C: HasTyCtxt<'tcx>>(&self, cx: C, i: usize) -> Ty<'tcx> {
pub fn field_type<C: LayoutTyper<'tcx>>(&self, cx: C, i: usize) -> Ty<'tcx> {
let tcx = cx.tcx();
let ptr_field_type = |pointee: Ty<'tcx>| {
@ -2014,7 +2242,10 @@ impl<'a, 'tcx> TyLayout<'tcx> {
}
}
pub fn field<C: LayoutTyper<'tcx>>(&self, cx: C, i: usize) -> C::TyLayout {
pub fn field<C: LayoutTyper<'tcx>>(&self,
cx: C,
i: usize)
-> C::TyLayout {
cx.layout_of(cx.normalize_projections(self.field_type(cx, i)))
}
}

View File

@ -20,6 +20,7 @@ use mir::transform::{MirSuite, MirPassIndex};
use session::CompileResult;
use traits::specialization_graph;
use ty::{self, CrateInherentImpls, Ty, TyCtxt};
use ty::layout::{Layout, LayoutError};
use ty::item_path;
use ty::steal::Steal;
use ty::subst::Substs;
@ -293,6 +294,12 @@ impl<'tcx> QueryDescription for queries::needs_drop_raw<'tcx> {
}
}
impl<'tcx> QueryDescription for queries::layout_raw<'tcx> {
fn describe(_tcx: TyCtxt, env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> String {
format!("computing layout of `{}`", env.value)
}
}
impl<'tcx> QueryDescription for queries::super_predicates_of<'tcx> {
fn describe(tcx: TyCtxt, def_id: DefId) -> String {
format!("computing the supertraits of `{}`",
@ -906,6 +913,12 @@ define_maps! { <'tcx>
[] specialization_graph_of: SpecializationGraph(DefId) -> Rc<specialization_graph::Graph>,
[] is_object_safe: ObjectSafety(DefId) -> bool,
// Get the ParameterEnvironment for a given item; this environment
// will be in "user-facing" mode, meaning that it is suitabe for
// type-checking etc, and it does not normalize specializable
// associated types. This is almost always what you want,
// unless you are doing MIR optimizations, in which case you
// might want to use `reveal_all()` method to change modes.
[] param_env: ParamEnv(DefId) -> ty::ParamEnv<'tcx>,
// Trait selection queries. These are best used by invoking `ty.moves_by_default()`,
@ -914,6 +927,8 @@ define_maps! { <'tcx>
[] is_sized_raw: is_sized_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool,
[] is_freeze_raw: is_freeze_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool,
[] needs_drop_raw: needs_drop_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool,
[] layout_raw: layout_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>)
-> Result<&'tcx Layout, LayoutError<'tcx>>,
}
fn coherent_trait_dep_node((_, def_id): (CrateNum, DefId)) -> DepNode<DefId> {
@ -981,3 +996,9 @@ fn needs_drop_dep_node<'tcx>(key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepNode<De
.unwrap_or(DefId::local(CRATE_DEF_INDEX));
DepNode::NeedsDrop(def_id)
}
fn layout_dep_node<'tcx>(key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepNode<DefId> {
let def_id = ty::item_path::characteristic_def_id_of_type(key.value)
.unwrap_or(DefId::local(CRATE_DEF_INDEX));
DepNode::Layout(def_id)
}

View File

@ -158,29 +158,6 @@ pub struct ImplHeader<'tcx> {
pub predicates: Vec<Predicate<'tcx>>,
}
impl<'a, 'gcx, 'tcx> ImplHeader<'tcx> {
pub fn with_fresh_ty_vars(selcx: &mut traits::SelectionContext<'a, 'gcx, 'tcx>,
impl_def_id: DefId)
-> ImplHeader<'tcx>
{
let tcx = selcx.tcx();
let impl_substs = selcx.infcx().fresh_substs_for_item(DUMMY_SP, impl_def_id);
let header = ImplHeader {
impl_def_id: impl_def_id,
self_ty: tcx.type_of(impl_def_id),
trait_ref: tcx.impl_trait_ref(impl_def_id),
predicates: tcx.predicates_of(impl_def_id).predicates
}.subst(tcx, impl_substs);
let traits::Normalized { value: mut header, obligations } =
traits::normalize(selcx, traits::ObligationCause::dummy(), &header);
header.predicates.extend(obligations.into_iter().map(|o| o.predicate));
header
}
}
#[derive(Copy, Clone, Debug)]
pub struct AssociatedItem {
pub def_id: DefId,
@ -1191,6 +1168,11 @@ pub struct ParamEnv<'tcx> {
/// the set of bounds on the in-scope type parameters, translated
/// into Obligations, and elaborated and normalized.
pub caller_bounds: &'tcx Slice<ty::Predicate<'tcx>>,
/// Typically, this is `Reveal::UserFacing`, but during trans we
/// want `Reveal::All` -- note that this is always paired with an
/// empty environment. To get that, use `ParamEnv::reveal()`.
pub reveal: traits::Reveal,
}
impl<'tcx> ParamEnv<'tcx> {
@ -1218,7 +1200,7 @@ impl<'tcx> ParamEnv<'tcx> {
}
} else {
ParamEnvAnd {
param_env: ParamEnv::empty(),
param_env: ParamEnv::empty(self.reveal),
value: value,
}
}
@ -2467,8 +2449,8 @@ fn trait_of_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Option
/// See `ParamEnv` struct def'n for details.
fn param_env<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId)
-> ParamEnv<'tcx> {
def_id: DefId)
-> ParamEnv<'tcx> {
// Compute the bounds on Self and the type parameters.
let bounds = tcx.predicates_of(def_id).instantiate_identity(tcx);
@ -2486,7 +2468,8 @@ fn param_env<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
// are any errors at that point, so after type checking you can be
// sure that this will succeed without errors anyway.
let unnormalized_env = ty::ParamEnv::new(tcx.intern_predicates(&predicates));
let unnormalized_env = ty::ParamEnv::new(tcx.intern_predicates(&predicates),
traits::Reveal::UserFacing);
let body_id = tcx.hir.as_local_node_id(def_id).map_or(DUMMY_NODE_ID, |id| {
tcx.hir.maybe_body_owned_by(id).map_or(id, |body| body.node_id)

View File

@ -466,6 +466,20 @@ impl<'tcx, T:TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::Binder<T> {
}
}
impl<'tcx> TypeFoldable<'tcx> for ty::ParamEnv<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
ty::ParamEnv {
reveal: self.reveal,
caller_bounds: self.caller_bounds.fold_with(folder),
}
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
let &ty::ParamEnv { reveal: _, ref caller_bounds } = self;
caller_bounds.super_visit_with(visitor)
}
}
impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Slice<ty::ExistentialPredicate<'tcx>> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
let v = self.iter().map(|p| p.fold_with(folder)).collect::<AccumulateVec<[_; 8]>>();
@ -771,6 +785,17 @@ impl<'tcx> TypeFoldable<'tcx> for ty::GenericPredicates<'tcx> {
}
}
impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Slice<ty::Predicate<'tcx>> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
let v = self.iter().map(|p| p.fold_with(folder)).collect::<AccumulateVec<[_; 8]>>();
folder.tcx().intern_predicates(&v)
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
self.iter().any(|p| p.visit_with(visitor))
}
}
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 {

View File

@ -12,7 +12,6 @@
use hir::def_id::{DefId, LOCAL_CRATE};
use hir::map::DefPathData;
use infer::InferCtxt;
use ich::{StableHashingContext, NodeIdHashingMode};
use traits::{self, Reveal};
use ty::{self, Ty, TyCtxt, TypeFoldable};
@ -150,20 +149,33 @@ 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() -> Self {
Self::new(ty::Slice::empty())
pub fn empty(reveal: Reveal) -> Self {
Self::new(ty::Slice::empty(), reveal)
}
/// Construct a trait environment with the given set of predicates.
pub fn new(caller_bounds: &'tcx ty::Slice<ty::Predicate<'tcx>>) -> Self {
ty::ParamEnv { caller_bounds }
pub fn new(caller_bounds: &'tcx ty::Slice<ty::Predicate<'tcx>>,
reveal: Reveal)
-> Self {
ty::ParamEnv { caller_bounds, reveal }
}
pub fn can_type_implement_copy<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
/// 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)
-> Result<(), CopyImplementationError> {
-> Result<(), CopyImplementationError<'tcx>> {
// FIXME: (@jroesch) float this code up
tcx.infer_ctxt(self.clone(), Reveal::UserFacing).enter(|infcx| {
tcx.infer_ctxt(()).enter(|infcx| {
let (adt, substs) = match self_type.sty {
ty::TyAdt(adt, substs) => (adt, substs),
_ => return Err(CopyImplementationError::NotAnAdt),
@ -171,8 +183,8 @@ impl<'tcx> ty::ParamEnv<'tcx> {
let field_implements_copy = |field: &ty::FieldDef| {
let cause = traits::ObligationCause::dummy();
match traits::fully_normalize(&infcx, cause, &field.ty(tcx, substs)) {
Ok(ty) => !infcx.type_moves_by_default(ty, span),
match traits::fully_normalize(&infcx, cause, self, &field.ty(tcx, substs)) {
Ok(ty) => !infcx.type_moves_by_default(self, ty, span),
Err(..) => false,
}
};
@ -779,32 +791,27 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
tcx.needs_drop_raw(param_env.and(self))
}
/// Computes the layout of a type. Note that this implicitly
/// executes in "reveal all" mode.
#[inline]
pub fn layout<'lcx>(&'tcx self, infcx: &InferCtxt<'a, 'tcx, 'lcx>)
pub fn layout<'lcx>(&'tcx self,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>)
-> Result<&'tcx Layout, LayoutError<'tcx>> {
let tcx = infcx.tcx.global_tcx();
let can_cache = !self.has_param_types() && !self.has_self_ty();
if can_cache {
if let Some(&cached) = tcx.layout_cache.borrow().get(&self) {
return Ok(cached);
}
let ty = tcx.erase_regions(&self);
let layout = tcx.layout_raw(param_env.reveal_all().and(ty));
// NB: This recording is normally disabled; when enabled, it
// can however trigger recursive invocations of `layout()`.
// Therefore, we execute it *after* the main query has
// completed, to avoid problems around recursive structures
// and the like. (Admitedly, I wasn't able to reproduce a problem
// here, but it seems like the right thing to do. -nmatsakis)
if let Ok(l) = layout {
Layout::record_layout_for_printing(tcx, ty, param_env, l);
}
let rec_limit = tcx.sess.recursion_limit.get();
let depth = tcx.layout_depth.get();
if depth > rec_limit {
tcx.sess.fatal(
&format!("overflow representing the type `{}`", self));
}
tcx.layout_depth.set(depth+1);
let layout = Layout::compute_uncached(self, infcx);
tcx.layout_depth.set(depth);
let layout = layout?;
if can_cache {
tcx.layout_cache.borrow_mut().insert(self, layout);
}
Ok(layout)
layout
}
@ -970,8 +977,12 @@ fn is_copy_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
{
let (param_env, ty) = query.into_parts();
let trait_def_id = tcx.require_lang_item(lang_items::CopyTraitLangItem);
tcx.infer_ctxt(param_env, Reveal::UserFacing)
.enter(|infcx| traits::type_known_to_meet_bound(&infcx, ty, trait_def_id, DUMMY_SP))
tcx.infer_ctxt(())
.enter(|infcx| traits::type_known_to_meet_bound(&infcx,
param_env,
ty,
trait_def_id,
DUMMY_SP))
}
fn is_sized_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
@ -980,8 +991,12 @@ fn is_sized_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
{
let (param_env, ty) = query.into_parts();
let trait_def_id = tcx.require_lang_item(lang_items::SizedTraitLangItem);
tcx.infer_ctxt(param_env, Reveal::UserFacing)
.enter(|infcx| traits::type_known_to_meet_bound(&infcx, ty, trait_def_id, DUMMY_SP))
tcx.infer_ctxt(())
.enter(|infcx| traits::type_known_to_meet_bound(&infcx,
param_env,
ty,
trait_def_id,
DUMMY_SP))
}
fn is_freeze_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
@ -990,8 +1005,12 @@ fn is_freeze_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
{
let (param_env, ty) = query.into_parts();
let trait_def_id = tcx.require_lang_item(lang_items::FreezeTraitLangItem);
tcx.infer_ctxt(param_env, Reveal::UserFacing)
.enter(|infcx| traits::type_known_to_meet_bound(&infcx, ty, trait_def_id, DUMMY_SP))
tcx.infer_ctxt(())
.enter(|infcx| traits::type_known_to_meet_bound(&infcx,
param_env,
ty,
trait_def_id,
DUMMY_SP))
}
fn needs_drop_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
@ -1062,6 +1081,25 @@ fn needs_drop_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
}
}
fn layout_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>)
-> Result<&'tcx Layout, LayoutError<'tcx>>
{
let (param_env, ty) = query.into_parts();
let rec_limit = tcx.sess.recursion_limit.get();
let depth = tcx.layout_depth.get();
if depth > rec_limit {
tcx.sess.fatal(
&format!("overflow representing the type `{}`", ty));
}
tcx.layout_depth.set(depth+1);
let layout = Layout::compute_uncached(tcx, param_env, ty);
tcx.layout_depth.set(depth);
layout
}
pub fn provide(providers: &mut ty::maps::Providers) {
*providers = ty::maps::Providers {
@ -1069,6 +1107,7 @@ pub fn provide(providers: &mut ty::maps::Providers) {
is_sized_raw,
is_freeze_raw,
needs_drop_raw,
layout_raw,
..*providers
};
}

View File

@ -26,12 +26,14 @@ use middle::lang_items;
/// make any progress at all. This is to prevent "livelock" where we
/// say "$0 is WF if $0 is WF".
pub fn obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
body_id: ast::NodeId,
ty: Ty<'tcx>,
span: Span)
-> Option<Vec<traits::PredicateObligation<'tcx>>>
{
let mut wf = WfPredicates { infcx: infcx,
param_env: param_env,
body_id: body_id,
span: span,
out: vec![] };
@ -50,23 +52,25 @@ pub fn obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
/// `trait Set<K:Eq>`, then the trait reference `Foo: Set<Bar>` is WF
/// if `Bar: Eq`.
pub fn trait_obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
body_id: ast::NodeId,
trait_ref: &ty::TraitRef<'tcx>,
span: Span)
-> Vec<traits::PredicateObligation<'tcx>>
{
let mut wf = WfPredicates { infcx: infcx, body_id: body_id, span: span, out: vec![] };
let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![] };
wf.compute_trait_ref(trait_ref);
wf.normalize()
}
pub fn predicate_obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
body_id: ast::NodeId,
predicate: &ty::Predicate<'tcx>,
span: Span)
-> Vec<traits::PredicateObligation<'tcx>>
{
let mut wf = WfPredicates { infcx: infcx, body_id: body_id, span: span, out: vec![] };
let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![] };
// (*) ok to skip binders, because wf code is prepared for it
match *predicate {
@ -126,6 +130,7 @@ pub enum ImpliedBound<'tcx> {
/// the `ImpliedBound` type for more details.
pub fn implied_bounds<'a, 'gcx, 'tcx>(
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
body_id: ast::NodeId,
ty: Ty<'tcx>,
span: Span)
@ -148,7 +153,7 @@ pub fn implied_bounds<'a, 'gcx, 'tcx>(
// than the ultimate set. (Note: normally there won't be
// unresolved inference variables here anyway, but there might be
// during typeck under some circumstances.)
let obligations = obligations(infcx, body_id, ty, span).unwrap_or(vec![]);
let obligations = obligations(infcx, param_env, body_id, ty, span).unwrap_or(vec![]);
// From the full set of obligations, just filter down to the
// region relationships.
@ -231,6 +236,7 @@ fn implied_bounds_from_components<'tcx>(sub_region: ty::Region<'tcx>,
struct WfPredicates<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
body_id: ast::NodeId,
span: Span,
out: Vec<traits::PredicateObligation<'tcx>>,
@ -244,11 +250,12 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
fn normalize(&mut self) -> Vec<traits::PredicateObligation<'tcx>> {
let cause = self.cause(traits::MiscObligation);
let infcx = &mut self.infcx;
let param_env = self.param_env;
self.out.iter()
.inspect(|pred| assert!(!pred.has_escaping_regions()))
.flat_map(|pred| {
let mut selcx = traits::SelectionContext::new(infcx);
let pred = traits::normalize(&mut selcx, cause.clone(), pred);
let pred = traits::normalize(&mut selcx, param_env, cause.clone(), pred);
once(pred.value).chain(pred.obligations)
})
.collect()
@ -261,10 +268,12 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
self.out.extend(obligations);
let cause = self.cause(traits::MiscObligation);
let param_env = self.param_env;
self.out.extend(
trait_ref.substs.types()
.filter(|ty| !ty.has_escaping_regions())
.map(|ty| traits::Obligation::new(cause.clone(),
param_env,
ty::Predicate::WellFormed(ty))));
}
@ -280,7 +289,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
if !data.has_escaping_regions() {
let predicate = data.trait_ref.to_predicate();
let cause = self.cause(traits::ProjectionWf(data));
self.out.push(traits::Obligation::new(cause, predicate));
self.out.push(traits::Obligation::new(cause, self.param_env, predicate));
}
}
@ -291,7 +300,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
def_id: self.infcx.tcx.require_lang_item(lang_items::SizedTraitLangItem),
substs: self.infcx.tcx.mk_substs_trait(subty, &[]),
};
self.out.push(traits::Obligation::new(cause, trait_ref.to_predicate()));
self.out.push(traits::Obligation::new(cause, self.param_env, trait_ref.to_predicate()));
}
}
@ -301,6 +310,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
/// in which case we are not able to simplify at all.
fn compute(&mut self, ty0: Ty<'tcx>) -> bool {
let mut subtys = ty0.walk();
let param_env = self.param_env;
while let Some(ty) = subtys.next() {
match ty.sty {
ty::TyBool |
@ -350,6 +360,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
self.out.push(
traits::Obligation::new(
cause,
param_env,
ty::Predicate::TypeOutlives(
ty::Binder(
ty::OutlivesPredicate(mt.ty, r)))));
@ -389,12 +400,12 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
// checking those
let cause = self.cause(traits::MiscObligation);
let component_traits =
data.auto_traits().chain(data.principal().map(|p| p.def_id()));
self.out.extend(
component_traits.map(|did| traits::Obligation::new(
cause.clone(),
param_env,
ty::Predicate::ObjectSafe(did)
))
);
@ -422,7 +433,9 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
let cause = self.cause(traits::MiscObligation);
self.out.push( // ...not the type we started from, so we made progress.
traits::Obligation::new(cause, ty::Predicate::WellFormed(ty)));
traits::Obligation::new(cause,
self.param_env,
ty::Predicate::WellFormed(ty)));
} else {
// Yes, resolved, proceed with the
// result. Should never return false because
@ -448,7 +461,9 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
let cause = self.cause(traits::ItemObligation(def_id));
predicates.predicates
.into_iter()
.map(|pred| traits::Obligation::new(cause.clone(), pred))
.map(|pred| traits::Obligation::new(cause.clone(),
self.param_env,
pred))
.filter(|pred| !pred.has_escaping_regions())
.collect()
}
@ -497,7 +512,9 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> {
for implicit_bound in implicit_bounds {
let cause = self.cause(traits::ObjectTypeBound(ty, explicit_bound));
let outlives = ty::Binder(ty::OutlivesPredicate(explicit_bound, implicit_bound));
self.out.push(traits::Obligation::new(cause, outlives.to_predicate()));
self.out.push(traits::Obligation::new(cause,
self.param_env,
outlives.to_predicate()));
}
}
}

View File

@ -90,7 +90,7 @@ struct CheckLoanCtxt<'a, 'tcx: 'a> {
dfcx_loans: &'a LoanDataFlow<'a, 'tcx>,
move_data: &'a move_data::FlowedMoveData<'a, 'tcx>,
all_loans: &'a [Loan<'tcx>],
param_env: &'a ty::ParamEnv<'tcx>,
param_env: ty::ParamEnv<'tcx>,
}
impl<'a, 'tcx> euv::Delegate<'tcx> for CheckLoanCtxt<'a, 'tcx> {
@ -191,15 +191,17 @@ pub fn check_loans<'a, 'b, 'c, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
body: &hir::Body) {
debug!("check_loans(body id={})", body.value.id);
let def_id = bccx.tcx.hir.body_owner_def_id(body.id());
let infcx = bccx.tcx.borrowck_fake_infer_ctxt(body.id());
let param_env = bccx.tcx.param_env(def_id);
let mut clcx = CheckLoanCtxt {
bccx: bccx,
dfcx_loans: dfcx_loans,
move_data: move_data,
all_loans: all_loans,
param_env: &infcx.param_env
param_env,
};
euv::ExprUseVisitor::new(&mut clcx, &bccx.region_maps, &infcx).consume_body(body);
euv::ExprUseVisitor::new(&mut clcx, &bccx.region_maps, &infcx, param_env).consume_body(body);
}
#[derive(PartialEq)]

View File

@ -38,9 +38,10 @@ mod move_error;
pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
body: hir::BodyId)
-> (Vec<Loan<'tcx>>,
move_data::MoveData<'tcx>) {
-> (Vec<Loan<'tcx>>, move_data::MoveData<'tcx>) {
let def_id = bccx.tcx.hir.body_owner_def_id(body);
let infcx = bccx.tcx.borrowck_fake_infer_ctxt(body);
let param_env = bccx.tcx.param_env(def_id);
let mut glcx = GatherLoanCtxt {
bccx: bccx,
infcx: &infcx,
@ -51,7 +52,7 @@ pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
};
let body = glcx.bccx.tcx.hir.body(body);
euv::ExprUseVisitor::new(&mut glcx, &bccx.region_maps, &infcx).consume_body(body);
euv::ExprUseVisitor::new(&mut glcx, &bccx.region_maps, &infcx, param_env).consume_body(body);
glcx.report_potential_errors();
let GatherLoanCtxt { all_loans, move_data, .. } = glcx;

View File

@ -526,7 +526,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
lp: &LoanPath<'tcx>,
the_move: &move_data::Move,
moved_lp: &LoanPath<'tcx>,
_param_env: &ty::ParamEnv<'tcx>) {
_param_env: ty::ParamEnv<'tcx>) {
let (verb, verb_participle) = match use_kind {
MovedInUse => ("use", "used"),
MovedInCapture => ("capture", "captured"),

View File

@ -20,7 +20,6 @@ use rustc::middle::expr_use_visitor as euv;
use rustc::middle::mem_categorization::{cmt};
use rustc::middle::region::RegionMaps;
use rustc::session::Session;
use rustc::traits::Reveal;
use rustc::ty::{self, Ty, TyCtxt};
use rustc::lint;
use rustc_errors::{Diagnostic, Level, DiagnosticBuilder};
@ -518,11 +517,11 @@ fn check_legality_of_move_bindings(cx: &MatchVisitor,
///
/// FIXME: this should be done by borrowck.
fn check_for_mutation_in_guard(cx: &MatchVisitor, guard: &hir::Expr) {
cx.tcx.infer_ctxt((cx.tables, cx.param_env), Reveal::UserFacing).enter(|infcx| {
cx.tcx.infer_ctxt(cx.tables).enter(|infcx| {
let mut checker = MutationChecker {
cx: cx,
};
ExprUseVisitor::new(&mut checker, cx.region_maps, &infcx).walk_expr(guard);
ExprUseVisitor::new(&mut checker, cx.region_maps, &infcx, cx.param_env).walk_expr(guard);
});
}

View File

@ -483,9 +483,11 @@ fn resolve_trait_associated_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
debug!("resolve_trait_associated_const: trait_ref={:?}",
trait_ref);
tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| {
tcx.infer_ctxt(()).enter(|infcx| {
let param_env = ty::ParamEnv::empty(Reveal::UserFacing);
let mut selcx = traits::SelectionContext::new(&infcx);
let obligation = traits::Obligation::new(traits::ObligationCause::dummy(),
param_env,
trait_ref.to_poly_trait_predicate());
let selection = match selcx.select(&obligation) {
Ok(Some(vtable)) => vtable,

View File

@ -46,6 +46,7 @@ use rustc::hir;
struct Env<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
infcx: &'a infer::InferCtxt<'a, 'gcx, 'tcx>,
region_maps: &'a mut RegionMaps,
param_env: ty::ParamEnv<'tcx>,
}
struct RH<'a> {
@ -153,9 +154,13 @@ fn test_env<F>(source_string: &str,
index,
"test_crate",
|tcx| {
tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| {
tcx.infer_ctxt(()).enter(|infcx| {
let mut region_maps = RegionMaps::new();
body(Env { infcx: &infcx, region_maps: &mut region_maps });
body(Env {
infcx: &infcx,
region_maps: &mut region_maps,
param_env: ty::ParamEnv::empty(Reveal::UserFacing),
});
let free_regions = FreeRegionMap::new();
let def_id = tcx.hir.local_def_id(ast::CRATE_NODE_ID);
infcx.resolve_regions_and_report_errors(def_id, &region_maps, &free_regions);
@ -250,14 +255,14 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
}
pub fn make_subtype(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
match self.infcx.sub_types(true, &ObligationCause::dummy(), a, b) {
match self.infcx.at(&ObligationCause::dummy(), self.param_env).sub(a, b) {
Ok(_) => true,
Err(ref e) => panic!("Encountered error: {}", e),
}
}
pub fn is_subtype(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
self.infcx.can_sub_types(a, b).is_ok()
self.infcx.can_sub(self.param_env, a, b).is_ok()
}
pub fn assert_subtype(&self, a: Ty<'tcx>, b: Ty<'tcx>) {
@ -354,30 +359,23 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
self.tcx().types.isize)
}
pub fn dummy_type_trace(&self) -> infer::TypeTrace<'tcx> {
infer::TypeTrace::dummy(self.tcx())
}
pub fn sub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> {
let trace = self.dummy_type_trace();
self.infcx.sub(true, trace, &t1, &t2)
pub fn sub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) -> InferResult<'tcx, ()> {
self.infcx.at(&ObligationCause::dummy(), self.param_env).sub(t1, t2)
}
pub fn lub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> {
let trace = self.dummy_type_trace();
self.infcx.lub(true, trace, &t1, &t2)
self.infcx.at(&ObligationCause::dummy(), self.param_env).lub(t1, t2)
}
pub fn glb(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> {
let trace = self.dummy_type_trace();
self.infcx.glb(true, trace, &t1, &t2)
self.infcx.at(&ObligationCause::dummy(), self.param_env).glb(t1, t2)
}
/// Checks that `t1 <: t2` is true (this may register additional
/// region checks).
pub fn check_sub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) {
match self.sub(t1, t2) {
Ok(InferOk { obligations, .. }) => {
Ok(InferOk { obligations, value: () }) => {
// None of these tests should require nested obligations:
assert!(obligations.is_empty());
}

View File

@ -488,7 +488,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MissingCopyImplementations {
if def.has_dtor(cx.tcx) {
return;
}
let param_env = ty::ParamEnv::empty();
let param_env = ty::ParamEnv::empty(Reveal::UserFacing);
if !ty.moves_by_default(cx.tcx, param_env, item.span) {
return;
}
@ -951,12 +951,13 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnconditionalRecursion {
let trait_ref = ty::TraitRef::from_method(tcx, trait_def_id, callee_substs);
let trait_ref = ty::Binder(trait_ref);
let span = tcx.hir.span(expr_id);
let param_env = tcx.param_env(method.def_id);
let obligation =
traits::Obligation::new(traits::ObligationCause::misc(span, expr_id),
param_env,
trait_ref.to_poly_trait_predicate());
let param_env = tcx.param_env(method.def_id);
tcx.infer_ctxt(param_env, Reveal::UserFacing).enter(|infcx| {
tcx.infer_ctxt(()).enter(|infcx| {
let mut selcx = traits::SelectionContext::new(&infcx);
match selcx.select(&obligation) {
// The method comes from a `T: Trait` bound.

View File

@ -14,7 +14,6 @@ use rustc::hir::def_id::DefId;
use rustc::ty::subst::Substs;
use rustc::ty::{self, AdtKind, Ty, TyCtxt};
use rustc::ty::layout::{Layout, Primitive};
use rustc::traits::Reveal;
use middle::const_val::ConstVal;
use rustc_const_eval::ConstContext;
use util::nodemap::FxHashSet;
@ -724,12 +723,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for VariantSizeDifferences {
if let hir::ItemEnum(ref enum_definition, ref gens) = it.node {
if gens.ty_params.is_empty() {
// sizes only make sense for non-generic types
let t = cx.tcx.type_of(cx.tcx.hir.local_def_id(it.id));
let layout = cx.tcx.infer_ctxt((), Reveal::All).enter(|infcx| {
let ty = cx.tcx.erase_regions(&t);
ty.layout(&infcx).unwrap_or_else(|e| {
bug!("failed to get layout for `{}`: {}", t, e)
})
let item_def_id = cx.tcx.hir.local_def_id(it.id);
let t = cx.tcx.type_of(item_def_id);
let param_env = cx.tcx.param_env(item_def_id).reveal_all();
let ty = cx.tcx.erase_regions(&t);
let layout = ty.layout(cx.tcx, param_env).unwrap_or_else(|e| {
bug!("failed to get layout for `{}`: {}", t, e)
});
if let Layout::General { ref variants, ref size, discr, .. } = *layout {

View File

@ -18,7 +18,6 @@ use rustc::middle::region::CodeExtent;
use rustc::mir::*;
use rustc::mir::transform::MirSource;
use rustc::mir::visit::MutVisitor;
use rustc::traits::Reveal;
use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::subst::Substs;
use rustc::util::nodemap::NodeMap;
@ -84,7 +83,7 @@ pub fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Mir<'t
};
let src = MirSource::from_node(tcx, id);
tcx.infer_ctxt(body_id, Reveal::UserFacing).enter(|infcx| {
tcx.infer_ctxt(body_id).enter(|infcx| {
let cx = Cx::new(&infcx, src);
let mut mir = if cx.tables().tainted_by_errors {
build::construct_error(cx, body_id)
@ -172,8 +171,7 @@ fn create_constructor_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
{
let span = tcx.hir.span(ctor_id);
if let hir::VariantData::Tuple(ref fields, ctor_id) = *v {
let pe = tcx.param_env(tcx.hir.local_def_id(ctor_id));
tcx.infer_ctxt(pe, Reveal::UserFacing).enter(|infcx| {
tcx.infer_ctxt(()).enter(|infcx| {
let (mut mir, src) =
shim::build_adt_ctor(&infcx, ctor_id, fields, span);

View File

@ -35,6 +35,7 @@ use std::rc::Rc;
pub struct Cx<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
tcx: TyCtxt<'a, 'gcx, 'tcx>,
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
pub param_env: ty::ParamEnv<'tcx>,
pub region_maps: Rc<RegionMaps>,
/// This is `Constness::Const` if we are compiling a `static`,
@ -64,6 +65,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
let src_id = src.item_id();
let src_def_id = tcx.hir.local_def_id(src_id);
let param_env = tcx.param_env(src_def_id);
let region_maps = tcx.region_maps(src_def_id);
let attrs = tcx.hir.attrs(src_id);
@ -80,7 +82,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
// Constants and const fn's always need overflow checks.
check_overflow |= constness == hir::Constness::Const;
Cx { tcx, infcx, region_maps, constness, src, check_overflow }
Cx { tcx, infcx, param_env, region_maps, constness, src, check_overflow }
}
}
@ -169,12 +171,12 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
}
pub fn needs_drop(&mut self, ty: Ty<'tcx>) -> bool {
let ty = self.tcx.lift_to_global(&ty).unwrap_or_else(|| {
bug!("MIR: Cx::needs_drop({}) got \
let (ty, param_env) = self.tcx.lift_to_global(&(ty, self.param_env)).unwrap_or_else(|| {
bug!("MIR: Cx::needs_drop({:?}, {:?}) got \
type with inference types/regions",
ty);
ty, self.param_env);
});
ty.needs_drop(self.tcx.global_tcx(), self.infcx.param_env)
ty.needs_drop(self.tcx.global_tcx(), param_env)
}
pub fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> {

View File

@ -18,7 +18,6 @@ use rustc_data_structures::indexed_vec::{Idx, IndexVec};
use rustc::mir::*;
use rustc::mir::transform::{MirPass, MirSource};
use rustc::mir::visit::*;
use rustc::traits;
use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::subst::{Subst,Substs};
@ -545,12 +544,11 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
}
}
fn type_size_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, param_env: ty::ParamEnv<'tcx>,
fn type_size_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
ty: Ty<'tcx>) -> Option<u64> {
tcx.infer_ctxt(param_env, traits::Reveal::All).enter(|infcx| {
ty.layout(&infcx).ok().map(|layout| {
layout.size(&tcx.data_layout).bytes()
})
ty.layout(tcx, param_env).ok().map(|layout| {
layout.size(&tcx.data_layout).bytes()
})
}

View File

@ -998,10 +998,13 @@ impl MirPass for QualifyAndPromoteConstants {
// Statics must be Sync.
if mode == Mode::Static {
let ty = mir.return_ty;
tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| {
tcx.infer_ctxt(()).enter(|infcx| {
let param_env = ty::ParamEnv::empty(Reveal::UserFacing);
let cause = traits::ObligationCause::new(mir.span, id, traits::SharedStatic);
let mut fulfillment_cx = traits::FulfillmentContext::new();
fulfillment_cx.register_bound(&infcx, ty,
fulfillment_cx.register_bound(&infcx,
param_env,
ty,
tcx.require_lang_item(lang_items::SyncTraitLangItem),
cause);
if let Err(err) = fulfillment_cx.select_all_or_error(&infcx) {

View File

@ -12,7 +12,7 @@
#![allow(unreachable_code)]
use rustc::infer::{self, InferCtxt, InferOk};
use rustc::traits::{self, Reveal};
use rustc::traits;
use rustc::ty::fold::TypeFoldable;
use rustc::ty::{self, Ty, TyCtxt, TypeVariants};
use rustc::middle::const_val::ConstVal;
@ -320,6 +320,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
pub struct TypeChecker<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
param_env: ty::ParamEnv<'gcx>,
fulfillment_cx: traits::FulfillmentContext<'tcx>,
last_span: Span,
body_id: ast::NodeId,
@ -327,12 +328,16 @@ pub struct TypeChecker<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
}
impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, body_id: ast::NodeId) -> Self {
fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
body_id: ast::NodeId,
param_env: ty::ParamEnv<'gcx>)
-> Self {
TypeChecker {
infcx: infcx,
fulfillment_cx: traits::FulfillmentContext::new(),
last_span: DUMMY_SP,
body_id: body_id,
body_id,
param_env,
reported_errors: FxHashSet(),
}
}
@ -348,18 +353,20 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
infer_ok.value
}
fn sub_types(&mut self, sup: Ty<'tcx>, sub: Ty<'tcx>)
fn sub_types(&mut self, sub: Ty<'tcx>, sup: Ty<'tcx>)
-> infer::UnitResult<'tcx>
{
self.infcx.sub_types(false, &self.misc(self.last_span), sup, sub)
.map(|ok| self.register_infer_ok_obligations(ok))
self.infcx.at(&self.misc(self.last_span), self.param_env)
.sup(sup, sub)
.map(|ok| self.register_infer_ok_obligations(ok))
}
fn eq_types(&mut self, span: Span, a: Ty<'tcx>, b: Ty<'tcx>)
-> infer::UnitResult<'tcx>
{
self.infcx.eq_types(false, &self.misc(span), a, b)
.map(|ok| self.register_infer_ok_obligations(ok))
self.infcx.at(&self.misc(span), self.param_env)
.eq(b, a)
.map(|ok| self.register_infer_ok_obligations(ok))
}
fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> {
@ -665,7 +672,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
let span = local_decl.source_info.span;
let ty = local_decl.ty;
if !ty.is_sized(self.tcx().global_tcx(), self.infcx.param_env(), span) {
if !ty.is_sized(self.tcx().global_tcx(), self.param_env, span) {
// in current MIR construction, all non-control-flow rvalue
// expressions evaluate through `as_temp` or `into` a return
// slot or local, so to find all unsized rvalues it is enough
@ -706,7 +713,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
let mut selcx = traits::SelectionContext::new(self.infcx);
let cause = traits::ObligationCause::misc(self.last_span, ast::CRATE_NODE_ID);
let traits::Normalized { value, obligations } =
traits::normalize(&mut selcx, cause, value);
traits::normalize(&mut selcx, self.param_env, cause, value);
debug!("normalize: value={:?} obligations={:?}",
value,
@ -752,8 +759,8 @@ impl MirPass for TypeckMir {
return;
}
let param_env = tcx.param_env(def_id);
tcx.infer_ctxt(param_env, Reveal::UserFacing).enter(|infcx| {
let mut checker = TypeChecker::new(&infcx, item_id);
tcx.infer_ctxt(()).enter(|infcx| {
let mut checker = TypeChecker::new(&infcx, item_id, param_env);
{
let mut verifier = TypeVerifier::new(&mut checker, mir);
verifier.visit_mir(mir);

View File

@ -138,11 +138,11 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> {
self.check_const_eval(&body.value);
}
let outer_penv = self.tcx.infer_ctxt(body_id, Reveal::UserFacing).enter(|infcx| {
let param_env = infcx.param_env.clone();
let outer_penv = self.tcx.infer_ctxt(body_id).enter(|infcx| {
let param_env = self.tcx.param_env(item_def_id);
let outer_penv = mem::replace(&mut self.param_env, param_env);
let region_maps = &self.tcx.region_maps(item_def_id);
euv::ExprUseVisitor::new(self, region_maps, &infcx).consume_body(body);
euv::ExprUseVisitor::new(self, region_maps, &infcx, param_env).consume_body(body);
outer_penv
});
@ -468,7 +468,7 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
in_fn: false,
promotable: false,
mut_rvalue_borrows: NodeSet(),
param_env: ty::ParamEnv::empty(),
param_env: ty::ParamEnv::empty(Reveal::UserFacing),
}.as_deep_visitor());
tcx.sess.abort_if_errors();
}

View File

@ -44,7 +44,7 @@ use rustc::middle::cstore::LinkMeta;
use rustc::hir::map as hir_map;
use rustc::util::common::time;
use rustc::session::config::{self, NoDebugInfo};
use rustc::session::{self, DataTypeKind, Session};
use rustc::session::Session;
use rustc_incremental::IncrementalHashesMap;
use abi;
use mir::lvalue::LvalueRef;
@ -80,7 +80,6 @@ use std::i32;
use syntax_pos::Span;
use syntax::attr;
use rustc::hir;
use rustc::ty::layout::{self, Layout};
use syntax::ast;
use mir::lvalue::Alignment;
@ -1287,10 +1286,6 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
&exported_symbols);
});
if tcx.sess.opts.debugging_opts.print_type_sizes {
gather_type_sizes(tcx);
}
if sess.target.target.options.is_like_msvc &&
sess.crate_types.borrow().iter().any(|ct| *ct == config::CrateTypeRlib) {
create_imps(sess, &llvm_modules);
@ -1322,193 +1317,6 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
}
}
fn gather_type_sizes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
let layout_cache = tcx.layout_cache.borrow();
for (ty, layout) in layout_cache.iter() {
// (delay format until we actually need it)
let record = |kind, opt_discr_size, variants| {
let type_desc = format!("{:?}", ty);
let overall_size = layout.size(tcx);
let align = layout.align(tcx);
tcx.sess.code_stats.borrow_mut().record_type_size(kind,
type_desc,
align,
overall_size,
opt_discr_size,
variants);
};
let (adt_def, substs) = match ty.sty {
ty::TyAdt(ref adt_def, substs) => {
debug!("print-type-size t: `{:?}` process adt", ty);
(adt_def, substs)
}
ty::TyClosure(..) => {
debug!("print-type-size t: `{:?}` record closure", ty);
record(DataTypeKind::Closure, None, vec![]);
continue;
}
_ => {
debug!("print-type-size t: `{:?}` skip non-nominal", ty);
continue;
}
};
let adt_kind = adt_def.adt_kind();
let build_field_info = |(field_name, field_ty): (ast::Name, Ty), offset: &layout::Size| {
match layout_cache.get(&field_ty) {
None => bug!("no layout found for field {} type: `{:?}`", field_name, field_ty),
Some(field_layout) => {
session::FieldInfo {
name: field_name.to_string(),
offset: offset.bytes(),
size: field_layout.size(tcx).bytes(),
align: field_layout.align(tcx).abi(),
}
}
}
};
let build_primitive_info = |name: ast::Name, value: &layout::Primitive| {
session::VariantInfo {
name: Some(name.to_string()),
kind: session::SizeKind::Exact,
align: value.align(tcx).abi(),
size: value.size(tcx).bytes(),
fields: vec![],
}
};
enum Fields<'a> {
WithDiscrim(&'a layout::Struct),
NoDiscrim(&'a layout::Struct),
}
let build_variant_info = |n: Option<ast::Name>, flds: &[(ast::Name, Ty)], layout: Fields| {
let (s, field_offsets) = match layout {
Fields::WithDiscrim(s) => (s, &s.offsets[1..]),
Fields::NoDiscrim(s) => (s, &s.offsets[0..]),
};
let field_info: Vec<_> = flds.iter()
.zip(field_offsets.iter())
.map(|(&field_name_ty, offset)| build_field_info(field_name_ty, offset))
.collect();
session::VariantInfo {
name: n.map(|n|n.to_string()),
kind: if s.sized {
session::SizeKind::Exact
} else {
session::SizeKind::Min
},
align: s.align.abi(),
size: s.min_size.bytes(),
fields: field_info,
}
};
match **layout {
Layout::StructWrappedNullablePointer { nonnull: ref variant_layout,
nndiscr,
discrfield: _,
discrfield_source: _ } => {
debug!("print-type-size t: `{:?}` adt struct-wrapped nullable nndiscr {} is {:?}",
ty, nndiscr, variant_layout);
let variant_def = &adt_def.variants[nndiscr as usize];
let fields: Vec<_> = variant_def.fields.iter()
.map(|field_def| (field_def.name, field_def.ty(tcx, substs)))
.collect();
record(adt_kind.into(),
None,
vec![build_variant_info(Some(variant_def.name),
&fields,
Fields::NoDiscrim(variant_layout))]);
}
Layout::RawNullablePointer { nndiscr, value } => {
debug!("print-type-size t: `{:?}` adt raw nullable nndiscr {} is {:?}",
ty, nndiscr, value);
let variant_def = &adt_def.variants[nndiscr as usize];
record(adt_kind.into(), None,
vec![build_primitive_info(variant_def.name, &value)]);
}
Layout::Univariant { variant: ref variant_layout, non_zero: _ } => {
let variant_names = || {
adt_def.variants.iter().map(|v|format!("{}", v.name)).collect::<Vec<_>>()
};
debug!("print-type-size t: `{:?}` adt univariant {:?} variants: {:?}",
ty, variant_layout, variant_names());
assert!(adt_def.variants.len() <= 1,
"univariant with variants {:?}", variant_names());
if adt_def.variants.len() == 1 {
let variant_def = &adt_def.variants[0];
let fields: Vec<_> = variant_def.fields.iter()
.map(|field_def| (field_def.name, field_def.ty(tcx, substs)))
.collect();
record(adt_kind.into(),
None,
vec![build_variant_info(Some(variant_def.name),
&fields,
Fields::NoDiscrim(variant_layout))]);
} else {
// (This case arises for *empty* enums; so give it
// zero variants.)
record(adt_kind.into(), None, vec![]);
}
}
Layout::General { ref variants, discr, .. } => {
debug!("print-type-size t: `{:?}` adt general variants def {} layouts {} {:?}",
ty, adt_def.variants.len(), variants.len(), variants);
let variant_infos: Vec<_> = adt_def.variants.iter()
.zip(variants.iter())
.map(|(variant_def, variant_layout)| {
let fields: Vec<_> = variant_def.fields.iter()
.map(|field_def| (field_def.name, field_def.ty(tcx, substs)))
.collect();
build_variant_info(Some(variant_def.name),
&fields,
Fields::WithDiscrim(variant_layout))
})
.collect();
record(adt_kind.into(), Some(discr.size()), variant_infos);
}
Layout::UntaggedUnion { ref variants } => {
debug!("print-type-size t: `{:?}` adt union variants {:?}",
ty, variants);
// layout does not currently store info about each
// variant...
record(adt_kind.into(), None, Vec::new());
}
Layout::CEnum { discr, .. } => {
debug!("print-type-size t: `{:?}` adt c-like enum", ty);
let variant_infos: Vec<_> = adt_def.variants.iter()
.map(|variant_def| {
build_primitive_info(variant_def.name,
&layout::Primitive::Int(discr))
})
.collect();
record(adt_kind.into(), Some(discr.size()), variant_infos);
}
// other cases provide little interesting (i.e. adjustable
// via representation tweaks) size info beyond total size.
Layout::Scalar { .. } |
Layout::Vector { .. } |
Layout::Array { .. } |
Layout::FatPointer { .. } => {
debug!("print-type-size t: `{:?}` adt other", ty);
record(adt_kind.into(), None, Vec::new())
}
}
}
}
#[inline(never)] // give this a place in the profiler
fn assert_symbols_are_distinct<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trans_items: I)
where I: Iterator<Item=&'a TransItem<'tcx>>

View File

@ -23,11 +23,11 @@ use monomorphize::Instance;
use partitioning::CodegenUnit;
use type_::Type;
use rustc_data_structures::base_n;
use rustc::ty::subst::Substs;
use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::layout::{LayoutTyper, TyLayout};
use rustc::session::config::{self, NoDebugInfo};
use rustc::session::Session;
use rustc::ty::subst::Substs;
use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::layout::{LayoutCx, LayoutError, LayoutTyper, TyLayout};
use rustc::util::nodemap::{NodeSet, DefIdMap, FxHashMap};
use std::ffi::{CStr, CString};
@ -320,15 +320,15 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> {
}
pub fn type_needs_drop(&self, ty: Ty<'tcx>) -> bool {
ty.needs_drop(self.tcx, ty::ParamEnv::empty())
ty.needs_drop(self.tcx, ty::ParamEnv::empty(traits::Reveal::All))
}
pub fn type_is_sized(&self, ty: Ty<'tcx>) -> bool {
ty.is_sized(self.tcx, ty::ParamEnv::empty(), DUMMY_SP)
ty.is_sized(self.tcx, ty::ParamEnv::empty(traits::Reveal::All), DUMMY_SP)
}
pub fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool {
ty.is_freeze(self.tcx, ty::ParamEnv::empty(), DUMMY_SP)
ty.is_freeze(self.tcx, ty::ParamEnv::empty(traits::Reveal::All), DUMMY_SP)
}
pub fn exported_symbols<'a>(&'a self) -> &'a NodeSet {
@ -709,41 +709,27 @@ impl<'a, 'tcx> ty::layout::HasDataLayout for &'a SharedCrateContext<'a, 'tcx> {
}
}
impl<'a, 'tcx> ty::layout::HasTyCtxt<'tcx> for &'a SharedCrateContext<'a, 'tcx> {
fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> {
self.tcx
}
}
impl<'a, 'tcx> ty::layout::HasDataLayout for &'a CrateContext<'a, 'tcx> {
fn data_layout(&self) -> &ty::layout::TargetDataLayout {
&self.shared.tcx.data_layout
}
}
impl<'a, 'tcx> ty::layout::HasTyCtxt<'tcx> for &'a CrateContext<'a, 'tcx> {
fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> {
self.shared.tcx
}
}
impl<'a, 'tcx> LayoutTyper<'tcx> for &'a SharedCrateContext<'a, 'tcx> {
type TyLayout = TyLayout<'tcx>;
fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
if let Some(&layout) = self.tcx().layout_cache.borrow().get(&ty) {
return TyLayout { ty: ty, layout: layout, variant_index: None };
}
fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> {
self.tcx
}
self.tcx().infer_ctxt((), traits::Reveal::All).enter(|infcx| {
infcx.layout_of(ty).unwrap_or_else(|e| {
match e {
ty::layout::LayoutError::SizeOverflow(_) =>
self.sess().fatal(&e.to_string()),
_ => bug!("failed to get layout for `{}`: {}", ty, e)
}
fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
let param_env = ty::ParamEnv::empty(traits::Reveal::All);
LayoutCx::new(self.tcx, param_env)
.layout_of(ty)
.unwrap_or_else(|e| match e {
LayoutError::SizeOverflow(_) => self.sess().fatal(&e.to_string()),
_ => bug!("failed to get layout for `{}`: {}", ty, e)
})
})
}
fn normalize_projections(self, ty: Ty<'tcx>) -> Ty<'tcx> {
@ -754,6 +740,10 @@ impl<'a, 'tcx> LayoutTyper<'tcx> for &'a SharedCrateContext<'a, 'tcx> {
impl<'a, 'tcx> LayoutTyper<'tcx> for &'a CrateContext<'a, 'tcx> {
type TyLayout = TyLayout<'tcx>;
fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> {
self.shared.tcx
}
fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
self.shared.layout_of(ty)
}

View File

@ -46,15 +46,13 @@ pub fn needs_drop_glue<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, t: Ty<'tcx>
ty::TyAdt(def, _) if def.is_box() => {
let typ = t.boxed_ty();
if !scx.type_needs_drop(typ) && scx.type_is_sized(typ) {
scx.tcx().infer_ctxt((), traits::Reveal::All).enter(|infcx| {
let layout = t.layout(&infcx).unwrap();
if layout.size(scx).bytes() == 0 {
// `Box<ZeroSizeType>` does not allocate.
false
} else {
true
}
})
let layout = t.layout(scx.tcx(), ty::ParamEnv::empty(traits::Reveal::All)).unwrap();
if layout.size(scx).bytes() == 0 {
// `Box<ZeroSizeType>` does not allocate.
false
} else {
true
}
} else {
true
}

View File

@ -118,13 +118,16 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> {
let cause = traits::ObligationCause::misc(self.span, self.fcx.body_id);
let mut selcx = traits::SelectionContext::new(self.fcx);
let obligation = traits::Obligation::new(cause.clone(), trait_ref.to_predicate());
let obligation = traits::Obligation::new(cause.clone(),
self.fcx.param_env,
trait_ref.to_predicate());
if !selcx.evaluate_obligation(&obligation) {
debug!("overloaded_deref_ty: cannot match obligation");
return None;
}
let normalized = traits::normalize_projection_type(&mut selcx,
self.fcx.param_env,
ty::ProjectionTy::from_ref_and_name(
tcx,
trait_ref,

View File

@ -555,6 +555,6 @@ impl<'a, 'gcx, 'tcx> CastCheck<'tcx> {
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
fn type_is_known_to_be_sized(&self, ty: Ty<'tcx>, span: Span) -> bool {
let lang_item = self.tcx.require_lang_item(lang_items::SizedTraitLangItem);
traits::type_known_to_meet_bound(self, ty, lang_item, span)
traits::type_known_to_meet_bound(self, self.param_env, ty, lang_item, span)
}
}

View File

@ -81,9 +81,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
let fn_sig = self.liberate_late_bound_regions(expr_def_id, &sig);
let fn_sig = self.inh.normalize_associated_types_in(body.value.span,
body.value.id, &fn_sig);
body.value.id,
self.param_env,
&fn_sig);
check_fn(self, fn_sig, decl, expr.id, body);
check_fn(self, self.param_env, fn_sig, decl, expr.id, body);
// Tuple up the arguments and insert the resulting function type into
// the `closures` table.

View File

@ -64,7 +64,7 @@ use check::{Diverges, FnCtxt};
use rustc::hir;
use rustc::hir::def_id::DefId;
use rustc::infer::{Coercion, InferResult, InferOk, TypeTrace};
use rustc::infer::{Coercion, InferResult, InferOk};
use rustc::infer::type_variable::TypeVariableOrigin;
use rustc::traits::{self, ObligationCause, ObligationCauseCode};
use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow};
@ -135,11 +135,13 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> {
self.commit_if_ok(|_| {
let trace = TypeTrace::types(&self.cause, false, a, b);
if self.use_lub {
self.lub(false, trace, &a, &b)
self.at(&self.cause, self.fcx.param_env)
.lub(b, a)
} else {
self.sub(false, trace, &a, &b)
self.at(&self.cause, self.fcx.param_env)
.sup(b, a)
.map(|InferOk { value: (), obligations }| InferOk { value: a, obligations })
}
})
}
@ -511,9 +513,12 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
// Create an obligation for `Source: CoerceUnsized<Target>`.
let cause = ObligationCause::misc(self.cause.span, self.body_id);
queue.push_back(self.tcx
.predicate_for_trait_def(cause, coerce_unsized_did, 0,
coerce_source, &[coerce_target]));
queue.push_back(self.tcx.predicate_for_trait_def(self.fcx.param_env,
cause,
coerce_unsized_did,
0,
coerce_source,
&[coerce_target]));
// Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid
// emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where
@ -768,20 +773,22 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
return Ok(prev_ty);
}
let trace = TypeTrace::types(cause, true, prev_ty, new_ty);
// Special-case that coercion alone cannot handle:
// Two function item types of differing IDs or Substs.
match (&prev_ty.sty, &new_ty.sty) {
(&ty::TyFnDef(a_def_id, a_substs, a_fty), &ty::TyFnDef(b_def_id, b_substs, b_fty)) => {
// The signature must always match.
let fty = self.lub(true, trace.clone(), &a_fty, &b_fty)
let fty = self.at(cause, self.param_env)
.trace(prev_ty, new_ty)
.lub(&a_fty, &b_fty)
.map(|ok| self.register_infer_ok_obligations(ok))?;
if a_def_id == b_def_id {
// Same function, maybe the parameters match.
let substs = self.commit_if_ok(|_| {
self.lub(true, trace.clone(), &a_substs, &b_substs)
self.at(cause, self.param_env)
.trace(prev_ty, new_ty)
.lub(&a_substs, &b_substs)
.map(|ok| self.register_infer_ok_obligations(ok))
});
@ -850,7 +857,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
if !noop {
return self.commit_if_ok(|_| {
self.lub(true, trace.clone(), &prev_ty, &new_ty)
self.at(cause, self.param_env)
.lub(prev_ty, new_ty)
.map(|ok| self.register_infer_ok_obligations(ok))
});
}
@ -863,7 +871,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
Err(e)
} else {
self.commit_if_ok(|_| {
self.lub(true, trace, &prev_ty, &new_ty)
self.at(cause, self.param_env)
.lub(prev_ty, new_ty)
.map(|ok| self.register_infer_ok_obligations(ok))
})
}
@ -1106,7 +1115,8 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E>
// Another example is `break` with no argument expression.
assert!(expression_ty.is_nil());
assert!(expression_ty.is_nil(), "if let hack without unit type");
fcx.eq_types(label_expression_as_expected, cause, expression_ty, self.merged_ty())
fcx.at(cause, fcx.param_env)
.eq_exp(label_expression_as_expected, expression_ty, self.merged_ty())
.map(|infer_ok| {
fcx.register_infer_ok_obligations(infer_ok);
expression_ty

View File

@ -212,18 +212,19 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
// The key step here is to update the caller_bounds's predicates to be
// the new hybrid bounds we computed.
let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_node_id);
let param_env = ty::ParamEnv::new(tcx.intern_predicates(&hybrid_preds.predicates));
let param_env = ty::ParamEnv::new(tcx.intern_predicates(&hybrid_preds.predicates),
Reveal::UserFacing);
let param_env = traits::normalize_param_env_or_error(tcx,
impl_m.def_id,
param_env,
normalize_cause.clone());
tcx.infer_ctxt(param_env, Reveal::UserFacing).enter(|infcx| {
tcx.infer_ctxt(()).enter(|infcx| {
let inh = Inherited::new(infcx, impl_m.def_id);
let infcx = &inh.infcx;
debug!("compare_impl_method: caller_bounds={:?}",
infcx.param_env.caller_bounds);
param_env.caller_bounds);
let mut selcx = traits::SelectionContext::new(&infcx);
@ -233,10 +234,10 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
&ty::Binder(impl_m_own_bounds.predicates));
for predicate in impl_m_own_bounds {
let traits::Normalized { value: predicate, obligations } =
traits::normalize(&mut selcx, normalize_cause.clone(), &predicate);
traits::normalize(&mut selcx, param_env, normalize_cause.clone(), &predicate);
inh.register_predicates(obligations);
inh.register_predicate(traits::Obligation::new(cause.clone(), predicate));
inh.register_predicate(traits::Obligation::new(cause.clone(), param_env, predicate));
}
// We now need to check that the signature of the impl method is
@ -269,6 +270,7 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let impl_sig =
inh.normalize_associated_types_in(impl_m_span,
impl_m_node_id,
param_env,
&impl_sig);
let impl_fty = tcx.mk_fn_ptr(ty::Binder(impl_sig));
debug!("compare_impl_method: impl_fty={:?}", impl_fty);
@ -281,12 +283,14 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let trait_sig =
inh.normalize_associated_types_in(impl_m_span,
impl_m_node_id,
param_env,
&trait_sig);
let trait_fty = tcx.mk_fn_ptr(ty::Binder(trait_sig));
debug!("compare_impl_method: trait_fty={:?}", trait_fty);
let sub_result = infcx.sub_types(false, &cause, impl_fty, trait_fty)
let sub_result = infcx.at(&cause, param_env)
.sup(trait_fty, impl_fty)
.map(|InferOk { obligations, .. }| {
inh.register_predicates(obligations);
});
@ -297,6 +301,7 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
trait_fty);
let (impl_err_span, trait_err_span) = extract_spans_for_error_reporting(&infcx,
param_env,
&terr,
&cause,
impl_m,
@ -344,11 +349,10 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
// pass around temporarily.
let region_maps = RegionMaps::new();
let mut free_regions = FreeRegionMap::new();
free_regions.relate_free_regions_from_predicates(
&infcx.param_env.caller_bounds);
free_regions.relate_free_regions_from_predicates(&param_env.caller_bounds);
infcx.resolve_regions_and_report_errors(impl_m.def_id, &region_maps, &free_regions);
} else {
let fcx = FnCtxt::new(&inh, impl_m_node_id);
let fcx = FnCtxt::new(&inh, param_env, impl_m_node_id);
fcx.regionck_item(impl_m_node_id, impl_m_span, &[]);
}
@ -399,6 +403,7 @@ fn check_region_bounds_on_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
}
fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
terr: &TypeError,
cause: &ObligationCause<'tcx>,
impl_m: &ty::AssociatedItem,
@ -456,21 +461,23 @@ fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a
impl_iter.zip(trait_iter)
.zip(impl_m_iter)
.zip(trait_m_iter)
.filter_map(|(((impl_arg_ty, trait_arg_ty), impl_arg), trait_arg)| {
match infcx.sub_types(true, &cause, trait_arg_ty, impl_arg_ty) {
.filter_map(|(((&impl_arg_ty, &trait_arg_ty), impl_arg), trait_arg)| {
match infcx.at(&cause, param_env).sub(trait_arg_ty, impl_arg_ty) {
Ok(_) => None,
Err(_) => Some((impl_arg.span, Some(trait_arg.span))),
}
})
.next()
.unwrap_or_else(|| {
if infcx.sub_types(false, &cause, impl_sig.output(),
trait_sig.output())
.is_err() {
(impl_m_output.span(), Some(trait_m_output.span()))
} else {
(cause.span, tcx.hir.span_if_local(trait_m.def_id))
}
if
infcx.at(&cause, param_env)
.sup(trait_sig.output(), impl_sig.output())
.is_err()
{
(impl_m_output.span(), Some(trait_m_output.span()))
} else {
(cause.span, tcx.hir.span_if_local(trait_m.def_id))
}
})
} else {
(cause.span, tcx.hir.span_if_local(trait_m.def_id))
@ -713,7 +720,8 @@ pub fn compare_const_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
impl_trait_ref: ty::TraitRef<'tcx>) {
debug!("compare_const_impl(impl_trait_ref={:?})", impl_trait_ref);
tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| {
tcx.infer_ctxt(()).enter(|infcx| {
let param_env = ty::ParamEnv::empty(Reveal::UserFacing);
let inh = Inherited::new(infcx, impl_c.def_id);
let infcx = &inh.infcx;
@ -736,18 +744,21 @@ pub fn compare_const_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
// There is no "body" here, so just pass dummy id.
let impl_ty = inh.normalize_associated_types_in(impl_c_span,
impl_c_node_id,
param_env,
&impl_ty);
debug!("compare_const_impl: impl_ty={:?}", impl_ty);
let trait_ty = inh.normalize_associated_types_in(impl_c_span,
impl_c_node_id,
param_env,
&trait_ty);
debug!("compare_const_impl: trait_ty={:?}", trait_ty);
let err = infcx.sub_types(false, &cause, impl_ty, trait_ty)
.map(|ok| inh.register_infer_ok_obligations(ok));
let err = infcx.at(&cause, param_env)
.sup(trait_ty, impl_ty)
.map(|ok| inh.register_infer_ok_obligations(ok));
if let Err(terr) = err {
debug!("checking associated const for compatibility: impl ty {:?}, trait ty {:?}",
@ -794,7 +805,7 @@ pub fn compare_const_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
return;
}
let fcx = FnCtxt::new(&inh, impl_c_node_id);
let fcx = FnCtxt::new(&inh, param_env, impl_c_node_id);
fcx.regionck_item(impl_c_node_id, impl_c_span, &[]);
});
}

View File

@ -26,8 +26,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
// Requires that the two types unify, and prints an error message if
// they don't.
pub fn demand_suptype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) {
let cause = self.misc(sp);
match self.sub_types(false, &cause, actual, expected) {
let cause = &self.misc(sp);
match self.at(cause, self.param_env).sup(expected, actual) {
Ok(InferOk { obligations, value: () }) => {
self.register_predicates(obligations);
},
@ -54,7 +54,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
cause: &ObligationCause<'tcx>,
expected: Ty<'tcx>,
actual: Ty<'tcx>) -> Option<DiagnosticBuilder<'tcx>> {
match self.eq_types(false, cause, actual, expected) {
match self.at(cause, self.param_env).eq(expected, actual) {
Ok(InferOk { obligations, value: () }) => {
self.register_predicates(obligations);
None

View File

@ -16,7 +16,7 @@ use rustc::infer::{self, InferOk};
use rustc::middle::region::{self, RegionMaps};
use rustc::ty::subst::{Subst, Substs};
use rustc::ty::{self, Ty, TyCtxt};
use rustc::traits::{self, ObligationCause, Reveal};
use rustc::traits::{self, ObligationCause};
use util::common::ErrorReported;
use util::nodemap::FxHashSet;
@ -79,8 +79,8 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>(
// check that the impl type can be made to match the trait type.
let impl_param_env = tcx.param_env(self_type_did);
tcx.infer_ctxt(impl_param_env, Reveal::UserFacing).enter(|ref infcx| {
tcx.infer_ctxt(()).enter(|ref infcx| {
let impl_param_env = tcx.param_env(self_type_did);
let tcx = infcx.tcx;
let mut fulfillment_cx = traits::FulfillmentContext::new();
@ -92,7 +92,7 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>(
let fresh_impl_self_ty = drop_impl_ty.subst(tcx, fresh_impl_substs);
let cause = &ObligationCause::misc(drop_impl_span, drop_impl_node_id);
match infcx.eq_types(true, cause, named_type, fresh_impl_self_ty) {
match infcx.at(cause, impl_param_env).eq(named_type, fresh_impl_self_ty) {
Ok(InferOk { obligations, .. }) => {
fulfillment_cx.register_predicate_obligations(infcx, obligations);
}

View File

@ -340,7 +340,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
}
fn unify_receivers(&mut self, self_ty: Ty<'tcx>, method_self_ty: Ty<'tcx>) {
match self.sub_types(false, &self.misc(self.span), self_ty, method_self_ty) {
match self.at(&self.misc(self.span), self.param_env).sup(method_self_ty, self_ty) {
Ok(InferOk { obligations, value: () }) => {
self.register_predicates(obligations);
}

View File

@ -205,7 +205,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
// Construct an obligation
let poly_trait_ref = trait_ref.to_poly_trait_ref();
let obligation =
traits::Obligation::misc(span, self.body_id, poly_trait_ref.to_predicate());
traits::Obligation::misc(span,
self.body_id,
self.param_env,
poly_trait_ref.to_predicate());
// Now we want to know if this can be matched
let mut selcx = traits::SelectionContext::new(self);
@ -262,14 +265,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
assert!(!bounds.has_escaping_regions());
let cause = traits::ObligationCause::misc(span, self.body_id);
obligations.extend(traits::predicates_for_generics(cause.clone(), &bounds));
obligations.extend(traits::predicates_for_generics(cause.clone(),
self.param_env,
&bounds));
// Also add an obligation for the method type being well-formed.
let method_ty = tcx.mk_fn_ptr(ty::Binder(fn_sig));
debug!("lookup_in_trait_adjusted: matched method method_ty={:?} obligation={:?}",
method_ty,
obligation);
obligations.push(traits::Obligation::new(cause, ty::Predicate::WellFormed(method_ty)));
obligations.push(traits::Obligation::new(cause,
self.param_env,
ty::Predicate::WellFormed(method_ty)));
let callee = MethodCallee {
def_id: def_id,

View File

@ -540,7 +540,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
let cause = traits::ObligationCause::misc(self.span, self.body_id);
let mut selcx = &mut traits::SelectionContext::new(self.fcx);
let traits::Normalized { value: xform_self_ty, obligations } =
traits::normalize(selcx, cause, &xform_self_ty);
traits::normalize(selcx, self.param_env, cause, &xform_self_ty);
debug!("assemble_inherent_impl_probe: xform_self_ty = {:?}",
xform_self_ty);
@ -679,7 +679,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
let output = fty.output().subst(self.tcx, substs);
let (output, _) = self.replace_late_bound_regions_with_fresh_var(
self.span, infer::FnCall, &output);
self.can_sub_types(output, expected).is_ok()
self.can_sub(self.param_env, output, expected).is_ok()
})
}
_ => false,
@ -751,7 +751,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
let cause = traits::ObligationCause::misc(self.span, self.body_id);
let mut selcx = &mut traits::SelectionContext::new(self.fcx);
let traits::Normalized { value: xform_self_ty, obligations } =
traits::normalize(selcx, cause, &xform_self_ty);
traits::normalize(selcx, self.param_env, cause, &xform_self_ty);
debug!("xform_self_ty={:?}", xform_self_ty);
@ -885,7 +885,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
substs,
bound);
if self.can_equate(&step.self_ty, &bound.self_ty()).is_ok() {
if self.can_eq(self.param_env, step.self_ty, bound.self_ty()).is_ok() {
let xform_self_ty = self.xform_self_ty(&item, bound.self_ty(), bound.substs);
debug!("assemble_projection_candidates: bound={:?} xform_self_ty={:?}",
@ -1143,10 +1143,8 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
self.probe(|_| {
// First check that the self type can be related.
let sub_obligations = match self.sub_types(false,
&ObligationCause::dummy(),
self_ty,
probe.xform_self_ty) {
let sub_obligations = match self.at(&ObligationCause::dummy(), self.param_env)
.sup(probe.xform_self_ty, self_ty) {
Ok(InferOk { obligations, value: () }) => obligations,
Err(_) => {
debug!("--> cannot relate self-types");
@ -1182,10 +1180,12 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
let impl_bounds = self.tcx.predicates_of(impl_def_id);
let impl_bounds = impl_bounds.instantiate(self.tcx, substs);
let traits::Normalized { value: impl_bounds, obligations: norm_obligations } =
traits::normalize(selcx, cause.clone(), &impl_bounds);
traits::normalize(selcx, self.param_env, cause.clone(), &impl_bounds);
// Convert the bounds into obligations.
let obligations = traits::predicates_for_generics(cause.clone(), &impl_bounds);
let obligations = traits::predicates_for_generics(cause.clone(),
self.param_env,
&impl_bounds);
debug!("impl_obligations={:?}", obligations);
// Evaluate those obligations to see if they might possibly hold.

View File

@ -57,7 +57,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
let trait_ref = ty::TraitRef::new(fn_once, fn_once_substs);
let poly_trait_ref = trait_ref.to_poly_trait_ref();
let obligation =
Obligation::misc(span, self.body_id, poly_trait_ref.to_predicate());
Obligation::misc(span,
self.body_id,
self.param_env,
poly_trait_ref.to_predicate());
SelectionContext::new(self).evaluate_obligation(&obligation)
})
})

View File

@ -93,7 +93,7 @@ use rustc::infer::{self, InferCtxt, InferOk, RegionVariableOrigin};
use rustc::infer::type_variable::{TypeVariableOrigin};
use rustc::middle::region::CodeExtent;
use rustc::ty::subst::{Kind, Subst, Substs};
use rustc::traits::{self, FulfillmentContext, ObligationCause, ObligationCauseCode, Reveal};
use rustc::traits::{self, FulfillmentContext, ObligationCause, ObligationCauseCode};
use rustc::ty::{ParamTy, LvaluePreference, NoPreference, PreferMutLvalue};
use rustc::ty::{self, Ty, TyCtxt, Visibility};
use rustc::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
@ -450,6 +450,14 @@ impl<'gcx, 'tcx> EnclosingBreakables<'gcx, 'tcx> {
pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
body_id: ast::NodeId,
/// The parameter environment used for proving trait obligations
/// in this function. This can change when we descend into
/// closures (as they bring new things into scope), hence it is
/// not part of `Inherited` (as of the time of this writing,
/// closures do not yet change the environment, but they will
/// eventually).
param_env: ty::ParamEnv<'tcx>,
// Number of errors that had been reported when we started
// checking this function. On exit, if we find that *more* errors
// have been reported, we will skip regionck and other work that
@ -528,9 +536,8 @@ impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> {
pub fn build(tcx: TyCtxt<'a, 'gcx, 'gcx>, def_id: DefId)
-> InheritedBuilder<'a, 'gcx, 'tcx> {
let tables = ty::TypeckTables::empty();
let param_env = tcx.param_env(def_id);
InheritedBuilder {
infcx: tcx.infer_ctxt((tables, param_env), Reveal::UserFacing),
infcx: tcx.infer_ctxt(tables),
def_id,
}
}
@ -590,16 +597,18 @@ impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> {
fn normalize_associated_types_in<T>(&self,
span: Span,
body_id: ast::NodeId,
param_env: ty::ParamEnv<'tcx>,
value: &T) -> T
where T : TypeFoldable<'tcx>
{
let ok = self.normalize_associated_types_in_as_infer_ok(span, body_id, value);
let ok = self.normalize_associated_types_in_as_infer_ok(span, body_id, param_env, value);
self.register_infer_ok_obligations(ok)
}
fn normalize_associated_types_in_as_infer_ok<T>(&self,
span: Span,
body_id: ast::NodeId,
param_env: ty::ParamEnv<'tcx>,
value: &T)
-> InferOk<'tcx, T>
where T : TypeFoldable<'tcx>
@ -608,7 +617,7 @@ impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> {
let mut selcx = traits::SelectionContext::new(self);
let cause = ObligationCause::misc(span, body_id);
let traits::Normalized { value, obligations } =
traits::normalize(&mut selcx, cause, value);
traits::normalize(&mut selcx, param_env, cause, value);
debug!("normalize_associated_types_in: result={:?} predicates={:?}",
value,
obligations);
@ -797,6 +806,7 @@ fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let body = tcx.hir.body(body_id);
Inherited::build(tcx, def_id).enter(|inh| {
let param_env = tcx.param_env(def_id);
let fcx = if let Some(decl) = fn_decl {
let fn_sig = tcx.type_of(def_id).fn_sig();
@ -806,11 +816,14 @@ fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let fn_sig =
inh.liberate_late_bound_regions(def_id, &fn_sig);
let fn_sig =
inh.normalize_associated_types_in(body.value.span, body_id.node_id, &fn_sig);
inh.normalize_associated_types_in(body.value.span,
body_id.node_id,
param_env,
&fn_sig);
check_fn(&inh, fn_sig, decl, id, body)
check_fn(&inh, param_env, fn_sig, decl, id, body)
} else {
let fcx = FnCtxt::new(&inh, body.value.id);
let fcx = FnCtxt::new(&inh, param_env, body.value.id);
let expected_type = tcx.type_of(def_id);
let expected_type = fcx.normalize_associated_types_in(body.value.span, &expected_type);
fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized);
@ -919,6 +932,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for GatherLocalsVisitor<'a, 'gcx, 'tcx> {
/// * ...
/// * inherited: other fields inherited from the enclosing fn (if any)
fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
fn_sig: ty::FnSig<'tcx>,
decl: &'gcx hir::FnDecl,
fn_id: ast::NodeId,
@ -927,11 +941,11 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
{
let mut fn_sig = fn_sig.clone();
debug!("check_fn(sig={:?}, fn_id={})", fn_sig, fn_id);
debug!("check_fn(sig={:?}, fn_id={}, param_env={:?})", fn_sig, fn_id, param_env);
// Create the function context. This is either derived from scratch or,
// in the case of function expressions, based on the outer context.
let mut fcx = FnCtxt::new(inherited, body.value.id);
let mut fcx = FnCtxt::new(inherited, param_env, body.value.id);
*fcx.ps.borrow_mut() = UnsafetyState::function(fn_sig.unsafety, fn_id);
let ret_ty = fn_sig.output();
@ -1633,10 +1647,12 @@ enum TupleArgumentsFlag {
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
pub fn new(inh: &'a Inherited<'a, 'gcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
body_id: ast::NodeId)
-> FnCtxt<'a, 'gcx, 'tcx> {
FnCtxt {
body_id: body_id,
param_env,
err_count_on_creation: inh.tcx.sess.err_count(),
ret_coercion: None,
ps: RefCell::new(UnsafetyState::function(hir::Unsafety::Normal,
@ -1870,7 +1886,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
// Require that the predicate holds for the concrete type.
let cause = traits::ObligationCause::new(span, self.body_id,
traits::ReturnType);
self.register_predicate(traits::Obligation::new(cause, predicate));
self.register_predicate(traits::Obligation::new(cause,
self.param_env,
predicate));
}
ty_var
@ -1883,15 +1901,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
fn normalize_associated_types_in<T>(&self, span: Span, value: &T) -> T
where T : TypeFoldable<'tcx>
{
let ok = self.normalize_associated_types_in_as_infer_ok(span, value);
self.register_infer_ok_obligations(ok)
self.inh.normalize_associated_types_in(span, self.body_id, self.param_env, value)
}
fn normalize_associated_types_in_as_infer_ok<T>(&self, span: Span, value: &T)
-> InferOk<'tcx, T>
where T : TypeFoldable<'tcx>
{
self.inh.normalize_associated_types_in_as_infer_ok(span, self.body_id, value)
self.inh.normalize_associated_types_in_as_infer_ok(span,
self.body_id,
self.param_env,
value)
}
pub fn write_nil(&self, node_id: ast::NodeId) {
@ -1929,7 +1949,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
cause: traits::ObligationCause<'tcx>)
{
self.fulfillment_cx.borrow_mut()
.register_bound(self, ty, def_id, cause);
.register_bound(self, self.param_env, ty, def_id, cause);
}
pub fn to_ty(&self, ast_t: &hir::Ty) -> Ty<'tcx> {
@ -1970,7 +1990,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
{
// WF obligations never themselves fail, so no real need to give a detailed cause:
let cause = traits::ObligationCause::new(span, self.body_id, code);
self.register_predicate(traits::Obligation::new(cause, ty::Predicate::WellFormed(ty)));
self.register_predicate(traits::Obligation::new(cause,
self.param_env,
ty::Predicate::WellFormed(ty)));
}
pub fn register_old_wf_obligation(&self,
@ -2023,7 +2045,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
debug!("add_obligations_for_parameters(predicates={:?})",
predicates);
for obligation in traits::predicates_for_generics(cause, predicates) {
for obligation in traits::predicates_for_generics(cause, self.param_env, predicates) {
self.register_predicate(obligation);
}
}
@ -2704,7 +2726,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
// is polymorphic) and the expected return type.
// No argument expectations are produced if unification fails.
let origin = self.misc(call_span);
let ures = self.sub_types(false, &origin, formal_ret, ret_ty);
let ures = self.at(&origin, self.param_env).sup(ret_ty, formal_ret);
// FIXME(#15760) can't use try! here, FromError doesn't default
// to identity so the resulting type is not constrained.
@ -4199,7 +4221,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
_ => return,
};
let last_expr_ty = self.expr_ty(last_expr);
if self.can_sub_types(last_expr_ty, expected_ty).is_err() {
if self.can_sub(self.param_env, last_expr_ty, expected_ty).is_err() {
return;
}
let original_span = original_sp(last_stmt.span, blk.span);
@ -4459,7 +4481,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
let ty = self.tcx.type_of(impl_def_id);
let impl_ty = self.instantiate_type_scheme(span, &substs, &ty);
match self.sub_types(false, &self.misc(span), self_ty, impl_ty) {
match self.at(&self.misc(span), self.param_env).sup(impl_ty, self_ty) {
Ok(ok) => self.register_infer_ok_obligations(ok),
Err(_) => {
span_bug!(span,

View File

@ -238,9 +238,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
lhs_ty);
if let TypeVariants::TyRef(_, ref ty_mut) = lhs_ty.sty {
if !self.infcx.type_moves_by_default(ty_mut.ty, lhs_expr.span) &&
self.lookup_op_method(ty_mut.ty, &[rhs_ty],
Op::Binary(op, is_assign)).is_ok() {
if {
!self.infcx.type_moves_by_default(self.param_env,
ty_mut.ty,
lhs_expr.span) &&
self.lookup_op_method(ty_mut.ty,
&[rhs_ty],
Op::Binary(op, is_assign))
.is_ok()
} {
err.note(
&format!(
"this is a reference to a type that `{}` can be applied \

View File

@ -386,7 +386,8 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
for &ty in fn_sig_tys {
let ty = self.resolve_type(ty);
debug!("relate_free_regions(t={:?})", ty);
let implied_bounds = ty::wf::implied_bounds(self, body_id, ty, span);
let implied_bounds =
ty::wf::implied_bounds(self, self.fcx.param_env, body_id, ty, span);
// Record any relations between free regions that we observe into the free-region-map.
self.free_region_map.relate_free_regions_from_implied_bounds(&implied_bounds);
@ -1660,7 +1661,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
// check whether this predicate applies to our current projection
let cause = self.fcx.misc(span);
match self.eq_types(false, &cause, ty, outlives.0) {
match self.at(&cause, self.fcx.param_env).eq(outlives.0, ty) {
Ok(ok) => {
self.register_infer_ok_obligations(ok);
Ok(outlives.1)

View File

@ -166,9 +166,11 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> {
{
let body_owner_def_id = self.fcx.tcx.hir.body_owner_def_id(body.id());
let region_maps = &self.fcx.tcx.region_maps(body_owner_def_id);
let param_env = self.fcx.param_env;
let mut euv =
euv::ExprUseVisitor::with_options(self,
self.fcx,
param_env,
region_maps,
mc::MemCategorizationOptions {
during_closure_kind_inference: true

View File

@ -37,7 +37,8 @@ struct CheckWfFcxBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
inherited: super::InheritedBuilder<'a, 'gcx, 'tcx>,
code: ObligationCauseCode<'gcx>,
id: ast::NodeId,
span: Span
span: Span,
param_env: ty::ParamEnv<'tcx>,
}
impl<'a, 'gcx, 'tcx> CheckWfFcxBuilder<'a, 'gcx, 'tcx> {
@ -48,8 +49,9 @@ impl<'a, 'gcx, 'tcx> CheckWfFcxBuilder<'a, 'gcx, 'tcx> {
let code = self.code.clone();
let id = self.id;
let span = self.span;
let param_env = self.param_env;
self.inherited.enter(|inh| {
let fcx = FnCtxt::new(&inh, id);
let fcx = FnCtxt::new(&inh, param_env, id);
let wf_tys = f(&fcx, &mut CheckTypeWellFormedVisitor {
tcx: fcx.tcx.global_tcx(),
code: code
@ -206,11 +208,13 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
fn for_id<'tcx>(&self, id: ast::NodeId, span: Span)
-> CheckWfFcxBuilder<'a, 'gcx, 'tcx> {
let def_id = self.tcx.hir.local_def_id(id);
CheckWfFcxBuilder {
inherited: Inherited::build(self.tcx, self.tcx.hir.local_def_id(id)),
inherited: Inherited::build(self.tcx, def_id),
code: self.code.clone(),
id: id,
span: span
span: span,
param_env: self.tcx.param_env(def_id),
}
}
@ -374,6 +378,7 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
ast_trait_ref.path.span, &trait_ref);
let obligations =
ty::wf::trait_obligations(fcx,
fcx.param_env,
fcx.body_id,
&trait_ref,
ast_trait_ref.path.span);
@ -405,6 +410,7 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
predicates.predicates
.iter()
.flat_map(|p| ty::wf::predicate_obligations(fcx,
fcx.param_env,
fcx.body_id,
p,
span));

View File

@ -15,7 +15,7 @@ use rustc::middle::free_region::FreeRegionMap;
use rustc::middle::region::RegionMaps;
use rustc::middle::lang_items::UnsizeTraitLangItem;
use rustc::traits::{self, ObligationCause, Reveal};
use rustc::traits::{self, ObligationCause};
use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::TypeFoldable;
use rustc::ty::adjustment::CoerceUnsizedInfo;
@ -208,7 +208,7 @@ pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
source,
target);
tcx.infer_ctxt(param_env, Reveal::UserFacing).enter(|infcx| {
tcx.infer_ctxt(()).enter(|infcx| {
let cause = ObligationCause::misc(span, impl_node_id);
let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>,
mt_b: ty::TypeAndMut<'tcx>,
@ -308,7 +308,7 @@ pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
// we may have to evaluate constraint
// expressions in the course of execution.)
// See e.g. #41936.
if let Ok(ok) = infcx.eq_types(false, &cause, b, a) {
if let Ok(ok) = infcx.at(&cause, param_env).eq(a, b) {
if ok.obligations.is_empty() {
return None;
}
@ -376,7 +376,12 @@ pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
// Register an obligation for `A: Trait<B>`.
let cause = traits::ObligationCause::misc(span, impl_node_id);
let predicate = tcx.predicate_for_trait_def(cause, trait_def_id, 0, source, &[target]);
let predicate = tcx.predicate_for_trait_def(param_env,
cause,
trait_def_id,
0,
source,
&[target]);
fulfill_cx.register_predicate_obligation(&infcx, predicate);
// Check that all transitive obligations are satisfied.
@ -387,8 +392,7 @@ pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
// Finally, resolve all regions.
let region_maps = RegionMaps::new();
let mut free_regions = FreeRegionMap::new();
free_regions.relate_free_regions_from_predicates(&infcx.param_env
.caller_bounds);
free_regions.relate_free_regions_from_predicates(&param_env.caller_bounds);
infcx.resolve_regions_and_report_errors(impl_did, &region_maps, &free_regions);
CoerceUnsizedInfo {

View File

@ -11,7 +11,7 @@
use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
use rustc::hir;
use rustc::hir::itemlikevisit::ItemLikeVisitor;
use rustc::traits::{self, Reveal};
use rustc::traits;
use rustc::ty::{self, TyCtxt};
pub fn crate_inherent_impls_overlap_check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
@ -70,7 +70,7 @@ impl<'a, 'tcx> InherentOverlapChecker<'a, 'tcx> {
for (i, &impl1_def_id) in impls.iter().enumerate() {
for &impl2_def_id in &impls[(i + 1)..] {
self.tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| {
self.tcx.infer_ctxt(()).enter(|infcx| {
if traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id).is_some() {
self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id)
}

View File

@ -155,9 +155,10 @@ fn require_same_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
expected: Ty<'tcx>,
actual: Ty<'tcx>)
-> bool {
tcx.infer_ctxt((), Reveal::UserFacing).enter(|ref infcx| {
tcx.infer_ctxt(()).enter(|ref infcx| {
let param_env = ty::ParamEnv::empty(Reveal::UserFacing);
let mut fulfill_cx = FulfillmentContext::new();
match infcx.eq_types(false, &cause, expected, actual) {
match infcx.at(&cause, param_env).eq(expected, actual) {
Ok(InferOk { obligations, .. }) => {
fulfill_cx.register_predicate_obligations(infcx, obligations);
}

View File

@ -0,0 +1,9 @@
error[E0391]: unsupported cyclic reference between types/traits detected
|
note: the cycle begins when computing layout of `S`...
note: ...which then requires computing layout of `std::option::Option<<S as Mirror>::It>`...
note: ...which then requires computing layout of `<S as Mirror>::It`...
= note: ...which then again requires computing layout of `S`, completing the cycle.
error: aborting due to previous error(s)