1
Fork 0

Auto merge of #68461 - cjgillot:split_infer_prelude, r=matthewjasper

Move datatypes definitions in specific modules inside rustc::{traits, infer}

Prelude to #67953

Some data types inside `rustc::traits` and `rustc::infer` are used in other parts of `librustc`. These cannot go to a separate crate `librustc_infer`.

This PR moves those data types to `traits::types` and `infer::types` modules, from where everything is reexported.

Note for review: some imports feature the `crate -> rustc` substitution. This is cruft from the splitting out of #67953. This can be reverted, but are bound to be put back by #67953.

r? @Centril
cc @Zoxc
This commit is contained in:
bors 2020-02-05 22:41:54 +00:00
commit a25d58b41b
30 changed files with 2725 additions and 2557 deletions

View file

@ -21,18 +21,15 @@
//!
//! [c]: https://rust-lang.github.io/rustc-guide/traits/canonicalization.html
use crate::infer::region_constraints::MemberConstraint;
use crate::infer::{ConstVariableOrigin, ConstVariableOriginKind};
use crate::infer::{InferCtxt, RegionVariableOrigin, TypeVariableOrigin, TypeVariableOriginKind};
use crate::ty::fold::TypeFoldable;
use crate::ty::subst::GenericArg;
use crate::ty::{self, BoundVar, List, Region, TyCtxt};
use rustc::ty::fold::TypeFoldable;
use rustc::ty::subst::GenericArg;
use rustc::ty::{self, BoundVar, List};
use rustc_index::vec::IndexVec;
use rustc_macros::HashStable;
use rustc_serialize::UseSpecializedDecodable;
use rustc_span::source_map::Span;
use smallvec::SmallVec;
use std::ops::Index;
pub use rustc::infer::types::canonical::*;
mod canonicalizer;
@ -40,265 +37,6 @@ pub mod query_response;
mod substitute;
/// A "canonicalized" type `V` is one where all free inference
/// variables have been rewritten to "canonical vars". These are
/// numbered starting from 0 in order of first appearance.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)]
#[derive(HashStable, TypeFoldable, Lift)]
pub struct Canonical<'tcx, V> {
pub max_universe: ty::UniverseIndex,
pub variables: CanonicalVarInfos<'tcx>,
pub value: V,
}
pub type CanonicalVarInfos<'tcx> = &'tcx List<CanonicalVarInfo>;
impl<'tcx> UseSpecializedDecodable for CanonicalVarInfos<'tcx> {}
/// A set of values corresponding to the canonical variables from some
/// `Canonical`. You can give these values to
/// `canonical_value.substitute` to substitute them into the canonical
/// value at the right places.
///
/// When you canonicalize a value `V`, you get back one of these
/// vectors with the original values that were replaced by canonical
/// variables. You will need to supply it later to instantiate the
/// canonicalized query response.
#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)]
#[derive(HashStable, TypeFoldable, Lift)]
pub struct CanonicalVarValues<'tcx> {
pub var_values: IndexVec<BoundVar, GenericArg<'tcx>>,
}
/// When we canonicalize a value to form a query, we wind up replacing
/// various parts of it with canonical variables. This struct stores
/// those replaced bits to remember for when we process the query
/// result.
#[derive(Clone, Debug)]
pub struct OriginalQueryValues<'tcx> {
/// Map from the universes that appear in the query to the
/// universes in the caller context. For the time being, we only
/// ever put ROOT values into the query, so this map is very
/// simple.
pub universe_map: SmallVec<[ty::UniverseIndex; 4]>,
/// This is equivalent to `CanonicalVarValues`, but using a
/// `SmallVec` yields a significant performance win.
pub var_values: SmallVec<[GenericArg<'tcx>; 8]>,
}
impl Default for OriginalQueryValues<'tcx> {
fn default() -> Self {
let mut universe_map = SmallVec::default();
universe_map.push(ty::UniverseIndex::ROOT);
Self { universe_map, var_values: SmallVec::default() }
}
}
/// Information about a canonical variable that is included with the
/// canonical value. This is sufficient information for code to create
/// a copy of the canonical value in some other inference context,
/// with fresh inference variables replacing the canonical values.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable, HashStable)]
pub struct CanonicalVarInfo {
pub kind: CanonicalVarKind,
}
impl CanonicalVarInfo {
pub fn universe(&self) -> ty::UniverseIndex {
self.kind.universe()
}
pub fn is_existential(&self) -> bool {
match self.kind {
CanonicalVarKind::Ty(_) => true,
CanonicalVarKind::PlaceholderTy(_) => false,
CanonicalVarKind::Region(_) => true,
CanonicalVarKind::PlaceholderRegion(..) => false,
CanonicalVarKind::Const(_) => true,
CanonicalVarKind::PlaceholderConst(_) => false,
}
}
}
/// Describes the "kind" of the canonical variable. This is a "kind"
/// in the type-theory sense of the term -- i.e., a "meta" type system
/// that analyzes type-like values.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable, HashStable)]
pub enum CanonicalVarKind {
/// Some kind of type inference variable.
Ty(CanonicalTyVarKind),
/// A "placeholder" that represents "any type".
PlaceholderTy(ty::PlaceholderType),
/// Region variable `'?R`.
Region(ty::UniverseIndex),
/// A "placeholder" that represents "any region". Created when you
/// are solving a goal like `for<'a> T: Foo<'a>` to represent the
/// bound region `'a`.
PlaceholderRegion(ty::PlaceholderRegion),
/// Some kind of const inference variable.
Const(ty::UniverseIndex),
/// A "placeholder" that represents "any const".
PlaceholderConst(ty::PlaceholderConst),
}
impl CanonicalVarKind {
pub fn universe(self) -> ty::UniverseIndex {
match self {
CanonicalVarKind::Ty(kind) => match kind {
CanonicalTyVarKind::General(ui) => ui,
CanonicalTyVarKind::Float | CanonicalTyVarKind::Int => ty::UniverseIndex::ROOT,
},
CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.universe,
CanonicalVarKind::Region(ui) => ui,
CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.universe,
CanonicalVarKind::Const(ui) => ui,
CanonicalVarKind::PlaceholderConst(placeholder) => placeholder.universe,
}
}
}
/// Rust actually has more than one category of type variables;
/// notably, the type variables we create for literals (e.g., 22 or
/// 22.) can only be instantiated with integral/float types (e.g.,
/// usize or f32). In order to faithfully reproduce a type, we need to
/// know what set of types a given type variable can be unified with.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable, HashStable)]
pub enum CanonicalTyVarKind {
/// General type variable `?T` that can be unified with arbitrary types.
General(ty::UniverseIndex),
/// Integral type variable `?I` (that can only be unified with integral types).
Int,
/// Floating-point type variable `?F` (that can only be unified with float types).
Float,
}
/// After we execute a query with a canonicalized key, we get back a
/// `Canonical<QueryResponse<..>>`. You can use
/// `instantiate_query_result` to access the data in this result.
#[derive(Clone, Debug, HashStable, TypeFoldable, Lift)]
pub struct QueryResponse<'tcx, R> {
pub var_values: CanonicalVarValues<'tcx>,
pub region_constraints: QueryRegionConstraints<'tcx>,
pub certainty: Certainty,
pub value: R,
}
#[derive(Clone, Debug, Default, HashStable, TypeFoldable, Lift)]
pub struct QueryRegionConstraints<'tcx> {
pub outlives: Vec<QueryOutlivesConstraint<'tcx>>,
pub member_constraints: Vec<MemberConstraint<'tcx>>,
}
impl QueryRegionConstraints<'_> {
/// Represents an empty (trivially true) set of region
/// constraints.
pub fn is_empty(&self) -> bool {
self.outlives.is_empty() && self.member_constraints.is_empty()
}
}
pub type Canonicalized<'tcx, V> = Canonical<'tcx, V>;
pub type CanonicalizedQueryResponse<'tcx, T> = &'tcx Canonical<'tcx, QueryResponse<'tcx, T>>;
/// Indicates whether or not we were able to prove the query to be
/// true.
#[derive(Copy, Clone, Debug, HashStable)]
pub enum Certainty {
/// The query is known to be true, presuming that you apply the
/// given `var_values` and the region-constraints are satisfied.
Proven,
/// The query is not known to be true, but also not known to be
/// false. The `var_values` represent *either* values that must
/// hold in order for the query to be true, or helpful tips that
/// *might* make it true. Currently rustc's trait solver cannot
/// distinguish the two (e.g., due to our preference for where
/// clauses over impls).
///
/// After some unifiations and things have been done, it makes
/// sense to try and prove again -- of course, at that point, the
/// canonical form will be different, making this a distinct
/// query.
Ambiguous,
}
impl Certainty {
pub fn is_proven(&self) -> bool {
match self {
Certainty::Proven => true,
Certainty::Ambiguous => false,
}
}
pub fn is_ambiguous(&self) -> bool {
!self.is_proven()
}
}
impl<'tcx, R> QueryResponse<'tcx, R> {
pub fn is_proven(&self) -> bool {
self.certainty.is_proven()
}
pub fn is_ambiguous(&self) -> bool {
!self.is_proven()
}
}
impl<'tcx, R> Canonical<'tcx, QueryResponse<'tcx, R>> {
pub fn is_proven(&self) -> bool {
self.value.is_proven()
}
pub fn is_ambiguous(&self) -> bool {
!self.is_proven()
}
}
impl<'tcx, V> Canonical<'tcx, V> {
/// Allows you to map the `value` of a canonical while keeping the
/// same set of bound variables.
///
/// **WARNING:** This function is very easy to mis-use, hence the
/// name! In particular, the new value `W` must use all **the
/// same type/region variables** in **precisely the same order**
/// as the original! (The ordering is defined by the
/// `TypeFoldable` implementation of the type in question.)
///
/// An example of a **correct** use of this:
///
/// ```rust,ignore (not real code)
/// let a: Canonical<'_, T> = ...;
/// let b: Canonical<'_, (T,)> = a.unchecked_map(|v| (v, ));
/// ```
///
/// An example of an **incorrect** use of this:
///
/// ```rust,ignore (not real code)
/// let a: Canonical<'tcx, T> = ...;
/// let ty: Ty<'tcx> = ...;
/// let b: Canonical<'tcx, (T, Ty<'tcx>)> = a.unchecked_map(|v| (v, ty));
/// ```
pub fn unchecked_map<W>(self, map_op: impl FnOnce(V) -> W) -> Canonical<'tcx, W> {
let Canonical { max_universe, variables, value } = self;
Canonical { max_universe, variables, value: map_op(value) }
}
}
pub type QueryOutlivesConstraint<'tcx> =
ty::Binder<ty::OutlivesPredicate<GenericArg<'tcx>, Region<'tcx>>>;
impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
/// Creates a substitution S for the canonical value with fresh
/// inference variables and applies it to the canonical value.
@ -424,70 +162,3 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
}
}
}
CloneTypeFoldableAndLiftImpls! {
crate::infer::canonical::Certainty,
crate::infer::canonical::CanonicalVarInfo,
crate::infer::canonical::CanonicalVarKind,
}
CloneTypeFoldableImpls! {
for <'tcx> {
crate::infer::canonical::CanonicalVarInfos<'tcx>,
}
}
impl<'tcx> CanonicalVarValues<'tcx> {
pub fn len(&self) -> usize {
self.var_values.len()
}
/// Makes an identity substitution from this one: each bound var
/// is matched to the same bound var, preserving the original kinds.
/// For example, if we have:
/// `self.var_values == [Type(u32), Lifetime('a), Type(u64)]`
/// we'll return a substitution `subst` with:
/// `subst.var_values == [Type(^0), Lifetime(^1), Type(^2)]`.
pub fn make_identity(&self, tcx: TyCtxt<'tcx>) -> Self {
use crate::ty::subst::GenericArgKind;
CanonicalVarValues {
var_values: self
.var_values
.iter()
.zip(0..)
.map(|(kind, i)| match kind.unpack() {
GenericArgKind::Type(..) => {
tcx.mk_ty(ty::Bound(ty::INNERMOST, ty::BoundVar::from_u32(i).into())).into()
}
GenericArgKind::Lifetime(..) => tcx
.mk_region(ty::ReLateBound(ty::INNERMOST, ty::BoundRegion::BrAnon(i)))
.into(),
GenericArgKind::Const(ct) => tcx
.mk_const(ty::Const {
ty: ct.ty,
val: ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from_u32(i)),
})
.into(),
})
.collect(),
}
}
}
impl<'a, 'tcx> IntoIterator for &'a CanonicalVarValues<'tcx> {
type Item = GenericArg<'tcx>;
type IntoIter = ::std::iter::Cloned<::std::slice::Iter<'a, GenericArg<'tcx>>>;
fn into_iter(self) -> Self::IntoIter {
self.var_values.iter().cloned()
}
}
impl<'tcx> Index<BoundVar> for CanonicalVarValues<'tcx> {
type Output = GenericArg<'tcx>;
fn index(&self, value: BoundVar) -> &GenericArg<'tcx> {
&self.var_values[value]
}
}

View file

@ -61,6 +61,7 @@ pub mod region_constraints;
pub mod resolve;
mod sub;
pub mod type_variable;
mod types;
pub mod unify_key;
#[must_use]
@ -556,16 +557,6 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
}
}
impl<T> ExpectedFound<T> {
pub fn new(a_is_expected: bool, a: T, b: T) -> Self {
if a_is_expected {
ExpectedFound { expected: a, found: b }
} else {
ExpectedFound { expected: b, found: a }
}
}
}
impl<'tcx, T> InferOk<'tcx, T> {
pub fn unit(self) -> InferOk<'tcx, ()> {
InferOk { value: (), obligations: self.obligations }

View file

@ -23,6 +23,8 @@ use std::{cmp, fmt, mem};
mod leak_check;
pub use rustc::infer::types::MemberConstraint;
#[derive(Default)]
pub struct RegionConstraintCollector<'tcx> {
/// For each `RegionVid`, the corresponding `RegionVariableOrigin`.
@ -145,30 +147,6 @@ impl Constraint<'_> {
}
}
/// Requires that `region` must be equal to one of the regions in `choice_regions`.
/// We often denote this using the syntax:
///
/// ```
/// R0 member of [O1..On]
/// ```
#[derive(Debug, Clone, HashStable, TypeFoldable, Lift)]
pub struct MemberConstraint<'tcx> {
/// The `DefId` of the opaque type causing this constraint: used for error reporting.
pub opaque_type_def_id: DefId,
/// The span where the hidden type was instantiated.
pub definition_span: Span,
/// The hidden type in which `member_region` appears: used for error reporting.
pub hidden_ty: Ty<'tcx>,
/// The region `R0`.
pub member_region: Region<'tcx>,
/// The options `O1..On`.
pub choice_regions: Lrc<Vec<Region<'tcx>>>,
}
/// `VerifyGenericBound(T, _, R, RS)`: the parameter type `T` (or
/// associated type) must outlive the region `R`. `T` is known to
/// outlive `RS`. Therefore, verify that `R <= RS[i]` for some

View file

@ -453,18 +453,3 @@ impl<'tcx> ut::UnifyValue for TypeVariableValue<'tcx> {
}
}
}
/// Raw `TyVid` are used as the unification key for `sub_relations`;
/// they carry no values.
impl ut::UnifyKey for ty::TyVid {
type Value = ();
fn index(&self) -> u32 {
self.index
}
fn from_index(i: u32) -> ty::TyVid {
ty::TyVid { index: i }
}
fn tag() -> &'static str {
"TyVid"
}
}

View file

@ -0,0 +1,357 @@
//! **Canonicalization** is the key to constructing a query in the
//! middle of type inference. Ordinarily, it is not possible to store
//! types from type inference in query keys, because they contain
//! references to inference variables whose lifetimes are too short
//! and so forth. Canonicalizing a value T1 using `canonicalize_query`
//! produces two things:
//!
//! - a value T2 where each unbound inference variable has been
//! replaced with a **canonical variable**;
//! - a map M (of type `CanonicalVarValues`) from those canonical
//! variables back to the original.
//!
//! We can then do queries using T2. These will give back constraints
//! on the canonical variables which can be translated, using the map
//! M, into constraints in our source context. This process of
//! translating the results back is done by the
//! `instantiate_query_result` method.
//!
//! For a more detailed look at what is happening here, check
//! out the [chapter in the rustc guide][c].
//!
//! [c]: https://rust-lang.github.io/rustc-guide/traits/canonicalization.html
use crate::infer::region_constraints::MemberConstraint;
use crate::ty::subst::GenericArg;
use crate::ty::{self, BoundVar, List, Region, TyCtxt};
use rustc_index::vec::IndexVec;
use rustc_macros::HashStable;
use rustc_serialize::UseSpecializedDecodable;
use smallvec::SmallVec;
use std::ops::Index;
/// A "canonicalized" type `V` is one where all free inference
/// variables have been rewritten to "canonical vars". These are
/// numbered starting from 0 in order of first appearance.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)]
#[derive(HashStable, TypeFoldable, Lift)]
pub struct Canonical<'tcx, V> {
pub max_universe: ty::UniverseIndex,
pub variables: CanonicalVarInfos<'tcx>,
pub value: V,
}
pub type CanonicalVarInfos<'tcx> = &'tcx List<CanonicalVarInfo>;
impl<'tcx> UseSpecializedDecodable for CanonicalVarInfos<'tcx> {}
/// A set of values corresponding to the canonical variables from some
/// `Canonical`. You can give these values to
/// `canonical_value.substitute` to substitute them into the canonical
/// value at the right places.
///
/// When you canonicalize a value `V`, you get back one of these
/// vectors with the original values that were replaced by canonical
/// variables. You will need to supply it later to instantiate the
/// canonicalized query response.
#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)]
#[derive(HashStable, TypeFoldable, Lift)]
pub struct CanonicalVarValues<'tcx> {
pub var_values: IndexVec<BoundVar, GenericArg<'tcx>>,
}
/// When we canonicalize a value to form a query, we wind up replacing
/// various parts of it with canonical variables. This struct stores
/// those replaced bits to remember for when we process the query
/// result.
#[derive(Clone, Debug)]
pub struct OriginalQueryValues<'tcx> {
/// Map from the universes that appear in the query to the
/// universes in the caller context. For the time being, we only
/// ever put ROOT values into the query, so this map is very
/// simple.
pub universe_map: SmallVec<[ty::UniverseIndex; 4]>,
/// This is equivalent to `CanonicalVarValues`, but using a
/// `SmallVec` yields a significant performance win.
pub var_values: SmallVec<[GenericArg<'tcx>; 8]>,
}
impl Default for OriginalQueryValues<'tcx> {
fn default() -> Self {
let mut universe_map = SmallVec::default();
universe_map.push(ty::UniverseIndex::ROOT);
Self { universe_map, var_values: SmallVec::default() }
}
}
/// Information about a canonical variable that is included with the
/// canonical value. This is sufficient information for code to create
/// a copy of the canonical value in some other inference context,
/// with fresh inference variables replacing the canonical values.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable, HashStable)]
pub struct CanonicalVarInfo {
pub kind: CanonicalVarKind,
}
impl CanonicalVarInfo {
pub fn universe(&self) -> ty::UniverseIndex {
self.kind.universe()
}
pub fn is_existential(&self) -> bool {
match self.kind {
CanonicalVarKind::Ty(_) => true,
CanonicalVarKind::PlaceholderTy(_) => false,
CanonicalVarKind::Region(_) => true,
CanonicalVarKind::PlaceholderRegion(..) => false,
CanonicalVarKind::Const(_) => true,
CanonicalVarKind::PlaceholderConst(_) => false,
}
}
}
/// Describes the "kind" of the canonical variable. This is a "kind"
/// in the type-theory sense of the term -- i.e., a "meta" type system
/// that analyzes type-like values.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable, HashStable)]
pub enum CanonicalVarKind {
/// Some kind of type inference variable.
Ty(CanonicalTyVarKind),
/// A "placeholder" that represents "any type".
PlaceholderTy(ty::PlaceholderType),
/// Region variable `'?R`.
Region(ty::UniverseIndex),
/// A "placeholder" that represents "any region". Created when you
/// are solving a goal like `for<'a> T: Foo<'a>` to represent the
/// bound region `'a`.
PlaceholderRegion(ty::PlaceholderRegion),
/// Some kind of const inference variable.
Const(ty::UniverseIndex),
/// A "placeholder" that represents "any const".
PlaceholderConst(ty::PlaceholderConst),
}
impl CanonicalVarKind {
pub fn universe(self) -> ty::UniverseIndex {
match self {
CanonicalVarKind::Ty(kind) => match kind {
CanonicalTyVarKind::General(ui) => ui,
CanonicalTyVarKind::Float | CanonicalTyVarKind::Int => ty::UniverseIndex::ROOT,
},
CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.universe,
CanonicalVarKind::Region(ui) => ui,
CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.universe,
CanonicalVarKind::Const(ui) => ui,
CanonicalVarKind::PlaceholderConst(placeholder) => placeholder.universe,
}
}
}
/// Rust actually has more than one category of type variables;
/// notably, the type variables we create for literals (e.g., 22 or
/// 22.) can only be instantiated with integral/float types (e.g.,
/// usize or f32). In order to faithfully reproduce a type, we need to
/// know what set of types a given type variable can be unified with.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable, HashStable)]
pub enum CanonicalTyVarKind {
/// General type variable `?T` that can be unified with arbitrary types.
General(ty::UniverseIndex),
/// Integral type variable `?I` (that can only be unified with integral types).
Int,
/// Floating-point type variable `?F` (that can only be unified with float types).
Float,
}
/// After we execute a query with a canonicalized key, we get back a
/// `Canonical<QueryResponse<..>>`. You can use
/// `instantiate_query_result` to access the data in this result.
#[derive(Clone, Debug, HashStable, TypeFoldable, Lift)]
pub struct QueryResponse<'tcx, R> {
pub var_values: CanonicalVarValues<'tcx>,
pub region_constraints: QueryRegionConstraints<'tcx>,
pub certainty: Certainty,
pub value: R,
}
#[derive(Clone, Debug, Default, HashStable, TypeFoldable, Lift)]
pub struct QueryRegionConstraints<'tcx> {
pub outlives: Vec<QueryOutlivesConstraint<'tcx>>,
pub member_constraints: Vec<MemberConstraint<'tcx>>,
}
impl QueryRegionConstraints<'_> {
/// Represents an empty (trivially true) set of region
/// constraints.
pub fn is_empty(&self) -> bool {
self.outlives.is_empty() && self.member_constraints.is_empty()
}
}
pub type Canonicalized<'tcx, V> = Canonical<'tcx, V>;
pub type CanonicalizedQueryResponse<'tcx, T> = &'tcx Canonical<'tcx, QueryResponse<'tcx, T>>;
/// Indicates whether or not we were able to prove the query to be
/// true.
#[derive(Copy, Clone, Debug, HashStable)]
pub enum Certainty {
/// The query is known to be true, presuming that you apply the
/// given `var_values` and the region-constraints are satisfied.
Proven,
/// The query is not known to be true, but also not known to be
/// false. The `var_values` represent *either* values that must
/// hold in order for the query to be true, or helpful tips that
/// *might* make it true. Currently rustc's trait solver cannot
/// distinguish the two (e.g., due to our preference for where
/// clauses over impls).
///
/// After some unifiations and things have been done, it makes
/// sense to try and prove again -- of course, at that point, the
/// canonical form will be different, making this a distinct
/// query.
Ambiguous,
}
impl Certainty {
pub fn is_proven(&self) -> bool {
match self {
Certainty::Proven => true,
Certainty::Ambiguous => false,
}
}
pub fn is_ambiguous(&self) -> bool {
!self.is_proven()
}
}
impl<'tcx, R> QueryResponse<'tcx, R> {
pub fn is_proven(&self) -> bool {
self.certainty.is_proven()
}
pub fn is_ambiguous(&self) -> bool {
!self.is_proven()
}
}
impl<'tcx, R> Canonical<'tcx, QueryResponse<'tcx, R>> {
pub fn is_proven(&self) -> bool {
self.value.is_proven()
}
pub fn is_ambiguous(&self) -> bool {
!self.is_proven()
}
}
impl<'tcx, V> Canonical<'tcx, V> {
/// Allows you to map the `value` of a canonical while keeping the
/// same set of bound variables.
///
/// **WARNING:** This function is very easy to mis-use, hence the
/// name! In particular, the new value `W` must use all **the
/// same type/region variables** in **precisely the same order**
/// as the original! (The ordering is defined by the
/// `TypeFoldable` implementation of the type in question.)
///
/// An example of a **correct** use of this:
///
/// ```rust,ignore (not real code)
/// let a: Canonical<'_, T> = ...;
/// let b: Canonical<'_, (T,)> = a.unchecked_map(|v| (v, ));
/// ```
///
/// An example of an **incorrect** use of this:
///
/// ```rust,ignore (not real code)
/// let a: Canonical<'tcx, T> = ...;
/// let ty: Ty<'tcx> = ...;
/// let b: Canonical<'tcx, (T, Ty<'tcx>)> = a.unchecked_map(|v| (v, ty));
/// ```
pub fn unchecked_map<W>(self, map_op: impl FnOnce(V) -> W) -> Canonical<'tcx, W> {
let Canonical { max_universe, variables, value } = self;
Canonical { max_universe, variables, value: map_op(value) }
}
}
pub type QueryOutlivesConstraint<'tcx> =
ty::Binder<ty::OutlivesPredicate<GenericArg<'tcx>, Region<'tcx>>>;
CloneTypeFoldableAndLiftImpls! {
crate::infer::canonical::Certainty,
crate::infer::canonical::CanonicalVarInfo,
crate::infer::canonical::CanonicalVarKind,
}
CloneTypeFoldableImpls! {
for <'tcx> {
crate::infer::canonical::CanonicalVarInfos<'tcx>,
}
}
impl<'tcx> CanonicalVarValues<'tcx> {
pub fn len(&self) -> usize {
self.var_values.len()
}
/// Makes an identity substitution from this one: each bound var
/// is matched to the same bound var, preserving the original kinds.
/// For example, if we have:
/// `self.var_values == [Type(u32), Lifetime('a), Type(u64)]`
/// we'll return a substitution `subst` with:
/// `subst.var_values == [Type(^0), Lifetime(^1), Type(^2)]`.
pub fn make_identity(&self, tcx: TyCtxt<'tcx>) -> Self {
use crate::ty::subst::GenericArgKind;
CanonicalVarValues {
var_values: self
.var_values
.iter()
.zip(0..)
.map(|(kind, i)| match kind.unpack() {
GenericArgKind::Type(..) => {
tcx.mk_ty(ty::Bound(ty::INNERMOST, ty::BoundVar::from_u32(i).into())).into()
}
GenericArgKind::Lifetime(..) => tcx
.mk_region(ty::ReLateBound(ty::INNERMOST, ty::BoundRegion::BrAnon(i)))
.into(),
GenericArgKind::Const(ct) => tcx
.mk_const(ty::Const {
ty: ct.ty,
val: ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from_u32(i)),
})
.into(),
})
.collect(),
}
}
}
impl<'a, 'tcx> IntoIterator for &'a CanonicalVarValues<'tcx> {
type Item = GenericArg<'tcx>;
type IntoIter = ::std::iter::Cloned<::std::slice::Iter<'a, GenericArg<'tcx>>>;
fn into_iter(self) -> Self::IntoIter {
self.var_values.iter().cloned()
}
}
impl<'tcx> Index<BoundVar> for CanonicalVarValues<'tcx> {
type Output = GenericArg<'tcx>;
fn index(&self, value: BoundVar) -> &GenericArg<'tcx> {
&self.var_values[value]
}
}

View file

@ -0,0 +1,31 @@
pub mod canonical;
use crate::ty::Region;
use crate::ty::Ty;
use rustc_data_structures::sync::Lrc;
use rustc_hir::def_id::DefId;
use rustc_span::Span;
/// Requires that `region` must be equal to one of the regions in `choice_regions`.
/// We often denote this using the syntax:
///
/// ```
/// R0 member of [O1..On]
/// ```
#[derive(Debug, Clone, HashStable, TypeFoldable, Lift)]
pub struct MemberConstraint<'tcx> {
/// The `DefId` of the opaque type causing this constraint: used for error reporting.
pub opaque_type_def_id: DefId,
/// The span where the hidden type was instantiated.
pub definition_span: Span,
/// The hidden type in which `member_region` appears: used for error reporting.
pub hidden_ty: Ty<'tcx>,
/// The region `R0`.
pub member_region: Region<'tcx>,
/// The options `O1..On`.
pub choice_regions: Lrc<Vec<Region<'tcx>>>,
}

View file

@ -12,6 +12,21 @@ pub trait ToType {
fn to_type<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx>;
}
/// Raw `TyVid` are used as the unification key for `sub_relations`;
/// they carry no values.
impl UnifyKey for ty::TyVid {
type Value = ();
fn index(&self) -> u32 {
self.index
}
fn from_index(i: u32) -> ty::TyVid {
ty::TyVid { index: i }
}
fn tag() -> &'static str {
"TyVid"
}
}
impl UnifyKey for ty::IntVid {
type Value = Option<IntVarValue>;
fn index(&self) -> u32 {

View file

@ -9,6 +9,7 @@ use crate::ty::fold::TypeFolder;
use crate::ty::{Region, RegionVid};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use syntax::ast;
use std::collections::hash_map::Entry;
use std::collections::VecDeque;

View file

@ -19,31 +19,25 @@ mod select;
mod specialize;
mod structural_impls;
mod structural_match;
mod types;
mod util;
pub mod wf;
use crate::infer::outlives::env::OutlivesEnvironment;
use crate::infer::{InferCtxt, SuppressRegionErrors};
use crate::middle::region;
use crate::mir::interpret::ErrorHandled;
use crate::ty::error::{ExpectedFound, TypeError};
use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
use crate::ty::fold::TypeFoldable;
use crate::ty::subst::{InternalSubsts, SubstsRef};
use crate::ty::{self, AdtKind, GenericParamDefKind, List, ToPredicate, Ty, TyCtxt, WithConstness};
use crate::ty::{self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, WithConstness};
use crate::util::common::ErrorReported;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_macros::HashStable;
use rustc_span::{Span, DUMMY_SP};
use syntax::ast;
use std::fmt::Debug;
use std::rc::Rc;
pub use self::FulfillmentErrorCode::*;
pub use self::ObligationCauseCode::*;
pub use self::SelectionError::*;
pub use self::Vtable::*;
pub use self::coherence::{add_placeholder_note, orphan_check, overlapping_impls};
pub use self::coherence::{OrphanCheckErr, OverlapResult};
@ -57,9 +51,8 @@ pub use self::object_safety::ObjectSafetyViolation;
pub use self::on_unimplemented::{OnUnimplementedDirective, OnUnimplementedNote};
pub use self::project::MismatchedProjectionTypes;
pub use self::project::{normalize, normalize_projection_type, poly_project_and_unify_type};
pub use self::project::{Normalized, ProjectionCache, ProjectionCacheSnapshot, Reveal};
pub use self::select::{EvaluationCache, SelectionCache, SelectionContext};
pub use self::select::{EvaluationResult, IntercrateAmbiguityCause, OverflowError};
pub use self::project::{Normalized, ProjectionCache, ProjectionCacheSnapshot};
pub use self::select::{IntercrateAmbiguityCause, SelectionContext};
pub use self::specialize::find_associated_item;
pub use self::specialize::specialization_graph::FutureCompatOverlapError;
pub use self::specialize::specialization_graph::FutureCompatOverlapErrorKind;
@ -81,10 +74,7 @@ pub use self::chalk_fulfill::{
CanonicalGoal as ChalkCanonicalGoal, FulfillmentContext as ChalkFulfillmentContext,
};
pub use self::FulfillmentErrorCode::*;
pub use self::ObligationCauseCode::*;
pub use self::SelectionError::*;
pub use self::Vtable::*;
pub use self::types::*;
/// Whether to enable bug compatibility with issue #43355.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
@ -138,392 +128,12 @@ pub type TraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitPredicate<'tcx>>;
#[cfg(target_arch = "x86_64")]
static_assert_size!(PredicateObligation<'_>, 112);
/// The reason why we incurred this obligation; used for error reporting.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct ObligationCause<'tcx> {
pub span: Span,
/// The ID of the fn body that triggered this obligation. This is
/// used for region obligations to determine the precise
/// environment in which the region obligation should be evaluated
/// (in particular, closures can add new assumptions). See the
/// field `region_obligations` of the `FulfillmentContext` for more
/// information.
pub body_id: hir::HirId,
pub code: ObligationCauseCode<'tcx>,
}
impl ObligationCause<'_> {
pub fn span(&self, tcx: TyCtxt<'_>) -> Span {
match self.code {
ObligationCauseCode::CompareImplMethodObligation { .. }
| ObligationCauseCode::MainFunctionType
| ObligationCauseCode::StartFunctionType => tcx.sess.source_map().def_span(self.span),
ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
arm_span,
..
}) => arm_span,
_ => self.span,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum ObligationCauseCode<'tcx> {
/// Not well classified or should be obvious from the span.
MiscObligation,
/// A slice or array is WF only if `T: Sized`.
SliceOrArrayElem,
/// A tuple is WF only if its middle elements are `Sized`.
TupleElem,
/// This is the trait reference from the given projection.
ProjectionWf(ty::ProjectionTy<'tcx>),
/// In an impl of trait `X` for type `Y`, type `Y` must
/// also implement all supertraits of `X`.
ItemObligation(DefId),
/// Like `ItemObligation`, but with extra detail on the source of the obligation.
BindingObligation(DefId, Span),
/// A type like `&'a T` is WF only if `T: 'a`.
ReferenceOutlivesReferent(Ty<'tcx>),
/// A type like `Box<Foo<'a> + 'b>` is WF only if `'b: 'a`.
ObjectTypeBound(Ty<'tcx>, ty::Region<'tcx>),
/// Obligation incurred due to an object cast.
ObjectCastObligation(/* Object type */ Ty<'tcx>),
/// Obligation incurred due to a coercion.
Coercion {
source: Ty<'tcx>,
target: Ty<'tcx>,
},
/// Various cases where expressions must be `Sized` / `Copy` / etc.
/// `L = X` implies that `L` is `Sized`.
AssignmentLhsSized,
/// `(x1, .., xn)` must be `Sized`.
TupleInitializerSized,
/// `S { ... }` must be `Sized`.
StructInitializerSized,
/// Type of each variable must be `Sized`.
VariableType(hir::HirId),
/// Argument type must be `Sized`.
SizedArgumentType,
/// Return type must be `Sized`.
SizedReturnType,
/// Yield type must be `Sized`.
SizedYieldType,
/// `[T, ..n]` implies that `T` must be `Copy`.
/// If `true`, suggest `const_in_array_repeat_expressions` feature flag.
RepeatVec(bool),
/// Types of fields (other than the last, except for packed structs) in a struct must be sized.
FieldSized {
adt_kind: AdtKind,
last: bool,
},
/// Constant expressions must be sized.
ConstSized,
/// `static` items must have `Sync` type.
SharedStatic,
BuiltinDerivedObligation(DerivedObligationCause<'tcx>),
ImplDerivedObligation(DerivedObligationCause<'tcx>),
/// Error derived when matching traits/impls; see ObligationCause for more details
CompareImplMethodObligation {
item_name: ast::Name,
impl_item_def_id: DefId,
trait_item_def_id: DefId,
},
/// Error derived when matching traits/impls; see ObligationCause for more details
CompareImplTypeObligation {
item_name: ast::Name,
impl_item_def_id: DefId,
trait_item_def_id: DefId,
},
/// Checking that this expression can be assigned where it needs to be
// FIXME(eddyb) #11161 is the original Expr required?
ExprAssignable,
/// Computing common supertype in the arms of a match expression
MatchExpressionArm(Box<MatchExpressionArmCause<'tcx>>),
/// Type error arising from type checking a pattern against an expected type.
Pattern {
/// The span of the scrutinee or type expression which caused the `root_ty` type.
span: Option<Span>,
/// The root expected type induced by a scrutinee or type expression.
root_ty: Ty<'tcx>,
/// Whether the `Span` came from an expression or a type expression.
origin_expr: bool,
},
/// Constants in patterns must have `Structural` type.
ConstPatternStructural,
/// Computing common supertype in an if expression
IfExpression(Box<IfExpressionCause>),
/// Computing common supertype of an if expression with no else counter-part
IfExpressionWithNoElse,
/// `main` has wrong type
MainFunctionType,
/// `start` has wrong type
StartFunctionType,
/// Intrinsic has wrong type
IntrinsicType,
/// Method receiver
MethodReceiver,
/// `return` with no expression
ReturnNoExpression,
/// `return` with an expression
ReturnValue(hir::HirId),
/// Return type of this function
ReturnType,
/// Block implicit return
BlockTailExpression(hir::HirId),
/// #[feature(trivial_bounds)] is not enabled
TrivialBound,
AssocTypeBound(Box<AssocTypeBoundData>),
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct AssocTypeBoundData {
pub impl_span: Option<Span>,
pub original: Span,
pub bounds: Vec<Span>,
}
// `ObligationCauseCode` is used a lot. Make sure it doesn't unintentionally get bigger.
#[cfg(target_arch = "x86_64")]
static_assert_size!(ObligationCauseCode<'_>, 32);
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct MatchExpressionArmCause<'tcx> {
pub arm_span: Span,
pub source: hir::MatchSource,
pub prior_arms: Vec<Span>,
pub last_ty: Ty<'tcx>,
pub scrut_hir_id: hir::HirId,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct IfExpressionCause {
pub then: Span,
pub outer: Option<Span>,
pub semicolon: Option<Span>,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct DerivedObligationCause<'tcx> {
/// The trait reference of the parent obligation that led to the
/// current obligation. Note that only trait obligations lead to
/// derived obligations, so we just store the trait reference here
/// directly.
parent_trait_ref: ty::PolyTraitRef<'tcx>,
/// The parent trait had this cause.
parent_code: Rc<ObligationCauseCode<'tcx>>,
}
pub type Obligations<'tcx, O> = Vec<Obligation<'tcx, O>>;
pub type PredicateObligations<'tcx> = Vec<PredicateObligation<'tcx>>;
pub type TraitObligations<'tcx> = Vec<TraitObligation<'tcx>>;
/// The following types:
/// * `WhereClause`,
/// * `WellFormed`,
/// * `FromEnv`,
/// * `DomainGoal`,
/// * `Goal`,
/// * `Clause`,
/// * `Environment`,
/// * `InEnvironment`,
/// are used for representing the trait system in the form of
/// logic programming clauses. They are part of the interface
/// for the chalk SLG solver.
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable, Lift)]
pub enum WhereClause<'tcx> {
Implemented(ty::TraitPredicate<'tcx>),
ProjectionEq(ty::ProjectionPredicate<'tcx>),
RegionOutlives(ty::RegionOutlivesPredicate<'tcx>),
TypeOutlives(ty::TypeOutlivesPredicate<'tcx>),
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable, Lift)]
pub enum WellFormed<'tcx> {
Trait(ty::TraitPredicate<'tcx>),
Ty(Ty<'tcx>),
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable, Lift)]
pub enum FromEnv<'tcx> {
Trait(ty::TraitPredicate<'tcx>),
Ty(Ty<'tcx>),
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable, Lift)]
pub enum DomainGoal<'tcx> {
Holds(WhereClause<'tcx>),
WellFormed(WellFormed<'tcx>),
FromEnv(FromEnv<'tcx>),
Normalize(ty::ProjectionPredicate<'tcx>),
}
pub type PolyDomainGoal<'tcx> = ty::Binder<DomainGoal<'tcx>>;
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable)]
pub enum QuantifierKind {
Universal,
Existential,
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable, Lift)]
pub enum GoalKind<'tcx> {
Implies(Clauses<'tcx>, Goal<'tcx>),
And(Goal<'tcx>, Goal<'tcx>),
Not(Goal<'tcx>),
DomainGoal(DomainGoal<'tcx>),
Quantified(QuantifierKind, ty::Binder<Goal<'tcx>>),
Subtype(Ty<'tcx>, Ty<'tcx>),
CannotProve,
}
pub type Goal<'tcx> = &'tcx GoalKind<'tcx>;
pub type Goals<'tcx> = &'tcx List<Goal<'tcx>>;
impl<'tcx> DomainGoal<'tcx> {
pub fn into_goal(self) -> GoalKind<'tcx> {
GoalKind::DomainGoal(self)
}
pub fn into_program_clause(self) -> ProgramClause<'tcx> {
ProgramClause {
goal: self,
hypotheses: ty::List::empty(),
category: ProgramClauseCategory::Other,
}
}
}
impl<'tcx> GoalKind<'tcx> {
pub fn from_poly_domain_goal(
domain_goal: PolyDomainGoal<'tcx>,
tcx: TyCtxt<'tcx>,
) -> GoalKind<'tcx> {
match domain_goal.no_bound_vars() {
Some(p) => p.into_goal(),
None => GoalKind::Quantified(
QuantifierKind::Universal,
domain_goal.map_bound(|p| tcx.mk_goal(p.into_goal())),
),
}
}
}
/// This matches the definition from Page 7 of "A Proof Procedure for the Logic of Hereditary
/// Harrop Formulas".
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable)]
pub enum Clause<'tcx> {
Implies(ProgramClause<'tcx>),
ForAll(ty::Binder<ProgramClause<'tcx>>),
}
impl Clause<'tcx> {
pub fn category(self) -> ProgramClauseCategory {
match self {
Clause::Implies(clause) => clause.category,
Clause::ForAll(clause) => clause.skip_binder().category,
}
}
}
/// Multiple clauses.
pub type Clauses<'tcx> = &'tcx List<Clause<'tcx>>;
/// A "program clause" has the form `D :- G1, ..., Gn`. It is saying
/// that the domain goal `D` is true if `G1...Gn` are provable. This
/// is equivalent to the implication `G1..Gn => D`; we usually write
/// it with the reverse implication operator `:-` to emphasize the way
/// that programs are actually solved (via backchaining, which starts
/// with the goal to solve and proceeds from there).
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable)]
pub struct ProgramClause<'tcx> {
/// This goal will be considered true ...
pub goal: DomainGoal<'tcx>,
/// ... if we can prove these hypotheses (there may be no hypotheses at all):
pub hypotheses: Goals<'tcx>,
/// Useful for filtering clauses.
pub category: ProgramClauseCategory,
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable)]
pub enum ProgramClauseCategory {
ImpliedBound,
WellFormed,
Other,
}
/// A set of clauses that we assume to be true.
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable)]
pub struct Environment<'tcx> {
pub clauses: Clauses<'tcx>,
}
impl Environment<'tcx> {
pub fn with<G>(self, goal: G) -> InEnvironment<'tcx, G> {
InEnvironment { environment: self, goal }
}
}
/// Something (usually a goal), along with an environment.
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable)]
pub struct InEnvironment<'tcx, G> {
pub environment: Environment<'tcx>,
pub goal: G,
}
pub type Selection<'tcx> = Vtable<'tcx, PredicateObligation<'tcx>>;
#[derive(Clone, Debug, TypeFoldable)]
pub enum SelectionError<'tcx> {
Unimplemented,
OutputTypeParameterMismatch(
ty::PolyTraitRef<'tcx>,
ty::PolyTraitRef<'tcx>,
ty::error::TypeError<'tcx>,
),
TraitNotObjectSafe(DefId),
ConstEvalFailure(ErrorHandled),
Overflow,
}
pub struct FulfillmentError<'tcx> {
pub obligation: PredicateObligation<'tcx>,
pub code: FulfillmentErrorCode<'tcx>,
@ -541,164 +151,6 @@ pub enum FulfillmentErrorCode<'tcx> {
CodeAmbiguity,
}
/// When performing resolution, it is typically the case that there
/// can be one of three outcomes:
///
/// - `Ok(Some(r))`: success occurred with result `r`
/// - `Ok(None)`: could not definitely determine anything, usually due
/// to inconclusive type inference.
/// - `Err(e)`: error `e` occurred
pub type SelectionResult<'tcx, T> = Result<Option<T>, SelectionError<'tcx>>;
/// Given the successful resolution of an obligation, the `Vtable`
/// indicates where the vtable comes from. Note that while we call this
/// a "vtable", it does not necessarily indicate dynamic dispatch at
/// runtime. `Vtable` instances just tell the compiler where to find
/// methods, but in generic code those methods are typically statically
/// dispatched -- only when an object is constructed is a `Vtable`
/// instance reified into an actual vtable.
///
/// For example, the vtable may be tied to a specific impl (case A),
/// or it may be relative to some bound that is in scope (case B).
///
/// ```
/// impl<T:Clone> Clone<T> for Option<T> { ... } // Impl_1
/// impl<T:Clone> Clone<T> for Box<T> { ... } // Impl_2
/// impl Clone for int { ... } // Impl_3
///
/// fn foo<T:Clone>(concrete: Option<Box<int>>,
/// param: T,
/// mixed: Option<T>) {
///
/// // Case A: Vtable points at a specific impl. Only possible when
/// // type is concretely known. If the impl itself has bounded
/// // type parameters, Vtable will carry resolutions for those as well:
/// concrete.clone(); // Vtable(Impl_1, [Vtable(Impl_2, [Vtable(Impl_3)])])
///
/// // Case B: Vtable must be provided by caller. This applies when
/// // type is a type parameter.
/// param.clone(); // VtableParam
///
/// // Case C: A mix of cases A and B.
/// mixed.clone(); // Vtable(Impl_1, [VtableParam])
/// }
/// ```
///
/// ### The type parameter `N`
///
/// See explanation on `VtableImplData`.
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
pub enum Vtable<'tcx, N> {
/// Vtable identifying a particular impl.
VtableImpl(VtableImplData<'tcx, N>),
/// Vtable for auto trait implementations.
/// This carries the information and nested obligations with regards
/// to an auto implementation for a trait `Trait`. The nested obligations
/// ensure the trait implementation holds for all the constituent types.
VtableAutoImpl(VtableAutoImplData<N>),
/// Successful resolution to an obligation provided by the caller
/// for some type parameter. The `Vec<N>` represents the
/// obligations incurred from normalizing the where-clause (if
/// any).
VtableParam(Vec<N>),
/// Virtual calls through an object.
VtableObject(VtableObjectData<'tcx, N>),
/// Successful resolution for a builtin trait.
VtableBuiltin(VtableBuiltinData<N>),
/// Vtable automatically generated for a closure. The `DefId` is the ID
/// of the closure expression. This is a `VtableImpl` in spirit, but the
/// impl is generated by the compiler and does not appear in the source.
VtableClosure(VtableClosureData<'tcx, N>),
/// Same as above, but for a function pointer type with the given signature.
VtableFnPointer(VtableFnPointerData<'tcx, N>),
/// Vtable automatically generated for a generator.
VtableGenerator(VtableGeneratorData<'tcx, N>),
/// Vtable for a trait alias.
VtableTraitAlias(VtableTraitAliasData<'tcx, N>),
}
/// Identifies a particular impl in the source, along with a set of
/// substitutions from the impl's type/lifetime parameters. The
/// `nested` vector corresponds to the nested obligations attached to
/// the impl's type parameters.
///
/// The type parameter `N` indicates the type used for "nested
/// obligations" that are required by the impl. During type-check, this
/// is `Obligation`, as one might expect. During codegen, however, this
/// is `()`, because codegen only requires a shallow resolution of an
/// impl, and nested obligations are satisfied later.
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
pub struct VtableImplData<'tcx, N> {
pub impl_def_id: DefId,
pub substs: SubstsRef<'tcx>,
pub nested: Vec<N>,
}
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
pub struct VtableGeneratorData<'tcx, N> {
pub generator_def_id: DefId,
pub substs: SubstsRef<'tcx>,
/// Nested obligations. This can be non-empty if the generator
/// signature contains associated types.
pub nested: Vec<N>,
}
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
pub struct VtableClosureData<'tcx, N> {
pub closure_def_id: DefId,
pub substs: SubstsRef<'tcx>,
/// Nested obligations. This can be non-empty if the closure
/// signature contains associated types.
pub nested: Vec<N>,
}
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
pub struct VtableAutoImplData<N> {
pub trait_def_id: DefId,
pub nested: Vec<N>,
}
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
pub struct VtableBuiltinData<N> {
pub nested: Vec<N>,
}
/// A vtable for some object-safe trait `Foo` automatically derived
/// for the object type `Foo`.
#[derive(PartialEq, Eq, Clone, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
pub struct VtableObjectData<'tcx, N> {
/// `Foo` upcast to the obligation trait. This will be some supertrait of `Foo`.
pub upcast_trait_ref: ty::PolyTraitRef<'tcx>,
/// The vtable is formed by concatenating together the method lists of
/// the base object trait and all supertraits; this is the start of
/// `upcast_trait_ref`'s methods in that vtable.
pub vtable_base: usize,
pub nested: Vec<N>,
}
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
pub struct VtableFnPointerData<'tcx, N> {
pub fn_ty: Ty<'tcx>,
pub nested: Vec<N>,
}
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
pub struct VtableTraitAliasData<'tcx, N> {
pub alias_def_id: DefId,
pub substs: SubstsRef<'tcx>,
pub nested: Vec<N>,
}
/// Creates predicate obligations from the generic bounds.
pub fn predicates_for_generics<'tcx>(
cause: ObligationCause<'tcx>,
@ -1147,97 +599,6 @@ impl<'tcx, O> Obligation<'tcx, O> {
}
}
impl<'tcx> ObligationCause<'tcx> {
#[inline]
pub fn new(
span: Span,
body_id: hir::HirId,
code: ObligationCauseCode<'tcx>,
) -> ObligationCause<'tcx> {
ObligationCause { span, body_id, code }
}
pub fn misc(span: Span, body_id: hir::HirId) -> ObligationCause<'tcx> {
ObligationCause { span, body_id, code: MiscObligation }
}
pub fn dummy() -> ObligationCause<'tcx> {
ObligationCause { span: DUMMY_SP, body_id: hir::CRATE_HIR_ID, code: MiscObligation }
}
}
impl ObligationCauseCode<'_> {
// Return the base obligation, ignoring derived obligations.
pub fn peel_derives(&self) -> &Self {
let mut base_cause = self;
while let BuiltinDerivedObligation(cause) | ImplDerivedObligation(cause) = base_cause {
base_cause = &cause.parent_code;
}
base_cause
}
}
impl<'tcx, N> Vtable<'tcx, N> {
pub fn nested_obligations(self) -> Vec<N> {
match self {
VtableImpl(i) => i.nested,
VtableParam(n) => n,
VtableBuiltin(i) => i.nested,
VtableAutoImpl(d) => d.nested,
VtableClosure(c) => c.nested,
VtableGenerator(c) => c.nested,
VtableObject(d) => d.nested,
VtableFnPointer(d) => d.nested,
VtableTraitAlias(d) => d.nested,
}
}
pub fn map<M, F>(self, f: F) -> Vtable<'tcx, M>
where
F: FnMut(N) -> M,
{
match self {
VtableImpl(i) => VtableImpl(VtableImplData {
impl_def_id: i.impl_def_id,
substs: i.substs,
nested: i.nested.into_iter().map(f).collect(),
}),
VtableParam(n) => VtableParam(n.into_iter().map(f).collect()),
VtableBuiltin(i) => {
VtableBuiltin(VtableBuiltinData { nested: i.nested.into_iter().map(f).collect() })
}
VtableObject(o) => VtableObject(VtableObjectData {
upcast_trait_ref: o.upcast_trait_ref,
vtable_base: o.vtable_base,
nested: o.nested.into_iter().map(f).collect(),
}),
VtableAutoImpl(d) => VtableAutoImpl(VtableAutoImplData {
trait_def_id: d.trait_def_id,
nested: d.nested.into_iter().map(f).collect(),
}),
VtableClosure(c) => VtableClosure(VtableClosureData {
closure_def_id: c.closure_def_id,
substs: c.substs,
nested: c.nested.into_iter().map(f).collect(),
}),
VtableGenerator(c) => VtableGenerator(VtableGeneratorData {
generator_def_id: c.generator_def_id,
substs: c.substs,
nested: c.nested.into_iter().map(f).collect(),
}),
VtableFnPointer(p) => VtableFnPointer(VtableFnPointerData {
fn_ty: p.fn_ty,
nested: p.nested.into_iter().map(f).collect(),
}),
VtableTraitAlias(d) => VtableTraitAlias(VtableTraitAliasData {
alias_def_id: d.alias_def_id,
substs: d.substs,
nested: d.nested.into_iter().map(f).collect(),
}),
}
}
}
impl<'tcx> FulfillmentError<'tcx> {
fn new(
obligation: PredicateObligation<'tcx>,
@ -1265,42 +626,3 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) {
..*providers
};
}
pub trait ExClauseFold<'tcx>
where
Self: chalk_engine::context::Context + Clone,
{
fn fold_ex_clause_with<F: TypeFolder<'tcx>>(
ex_clause: &chalk_engine::ExClause<Self>,
folder: &mut F,
) -> chalk_engine::ExClause<Self>;
fn visit_ex_clause_with<V: TypeVisitor<'tcx>>(
ex_clause: &chalk_engine::ExClause<Self>,
visitor: &mut V,
) -> bool;
}
pub trait ChalkContextLift<'tcx>
where
Self: chalk_engine::context::Context + Clone,
{
type LiftedExClause: Debug + 'tcx;
type LiftedDelayedLiteral: Debug + 'tcx;
type LiftedLiteral: Debug + 'tcx;
fn lift_ex_clause_to_tcx(
ex_clause: &chalk_engine::ExClause<Self>,
tcx: TyCtxt<'tcx>,
) -> Option<Self::LiftedExClause>;
fn lift_delayed_literal_to_tcx(
ex_clause: &chalk_engine::DelayedLiteral<Self>,
tcx: TyCtxt<'tcx>,
) -> Option<Self::LiftedDelayedLiteral>;
fn lift_literal_to_tcx(
ex_clause: &chalk_engine::Literal<Self>,
tcx: TyCtxt<'tcx>,
) -> Option<Self::LiftedLiteral>;
}

View file

@ -19,52 +19,11 @@ use crate::ty::subst::{InternalSubsts, Subst};
use crate::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, WithConstness};
use rustc_data_structures::snapshot_map::{Snapshot, SnapshotMap};
use rustc_hir::def_id::DefId;
use rustc_macros::HashStable;
use rustc_span::symbol::sym;
use rustc_span::DUMMY_SP;
use syntax::ast::Ident;
/// Depending on the stage of compilation, we want projection to be
/// more or less conservative.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, HashStable)]
pub enum Reveal {
/// At type-checking time, we refuse to project any associated
/// type that is marked `default`. Non-`default` ("final") types
/// are always projected. This is necessary in general for
/// soundness of specialization. However, we *could* allow
/// projections in fully-monomorphic cases. We choose not to,
/// because we prefer for `default type` to force the type
/// definition to be treated abstractly by any consumers of the
/// impl. Concretely, that means that the following example will
/// fail to compile:
///
/// ```
/// trait Assoc {
/// type Output;
/// }
///
/// impl<T> Assoc for T {
/// default type Output = bool;
/// }
///
/// fn main() {
/// let <() as Assoc>::Output = true;
/// }
UserFacing,
/// At codegen time, all monomorphic projections will succeed.
/// Also, `impl Trait` is normalized to the concrete type,
/// which has to be already collected by type-checking.
///
/// NOTE: as `impl Trait`'s concrete type should *never*
/// be observable directly by the user, `Reveal::All`
/// should not be used by checks which may expose
/// type equality or type contents to the user.
/// There are some exceptions, e.g., around OIBITS and
/// transmute-checking, which expose some details, but
/// not the whole concrete type of the `impl Trait`.
All,
}
pub use rustc::traits::Reveal;
pub type PolyProjectionObligation<'tcx> = Obligation<'tcx, ty::PolyProjectionPredicate<'tcx>>;

View file

@ -1,10 +1,11 @@
use crate::infer::at::At;
use crate::infer::canonical::OriginalQueryValues;
use crate::infer::InferOk;
use crate::ty::subst::GenericArg;
use crate::ty::{self, Ty, TyCtxt};
use rustc_span::source_map::Span;
use std::iter::FromIterator;
use rustc::ty::subst::GenericArg;
use rustc::ty::{self, Ty, TyCtxt};
pub use rustc::traits::query::{DropckOutlivesResult, DtorckConstraint};
impl<'cx, 'tcx> At<'cx, 'tcx> {
/// Given a type `ty` of some value being dropped, computes a set
@ -65,76 +66,6 @@ impl<'cx, 'tcx> At<'cx, 'tcx> {
}
}
#[derive(Clone, Debug, Default, HashStable, TypeFoldable, Lift)]
pub struct DropckOutlivesResult<'tcx> {
pub kinds: Vec<GenericArg<'tcx>>,
pub overflows: Vec<Ty<'tcx>>,
}
impl<'tcx> DropckOutlivesResult<'tcx> {
pub fn report_overflows(&self, tcx: TyCtxt<'tcx>, span: Span, ty: Ty<'tcx>) {
if let Some(overflow_ty) = self.overflows.iter().next() {
rustc_errors::struct_span_err!(
tcx.sess,
span,
E0320,
"overflow while adding drop-check rules for {}",
ty,
)
.note(&format!("overflowed on {}", overflow_ty))
.emit();
}
}
pub fn into_kinds_reporting_overflows(
self,
tcx: TyCtxt<'tcx>,
span: Span,
ty: Ty<'tcx>,
) -> Vec<GenericArg<'tcx>> {
self.report_overflows(tcx, span, ty);
let DropckOutlivesResult { kinds, overflows: _ } = self;
kinds
}
}
/// A set of constraints that need to be satisfied in order for
/// a type to be valid for destruction.
#[derive(Clone, Debug, HashStable)]
pub struct DtorckConstraint<'tcx> {
/// Types that are required to be alive in order for this
/// type to be valid for destruction.
pub outlives: Vec<ty::subst::GenericArg<'tcx>>,
/// Types that could not be resolved: projections and params.
pub dtorck_types: Vec<Ty<'tcx>>,
/// If, during the computation of the dtorck constraint, we
/// overflow, that gets recorded here. The caller is expected to
/// report an error.
pub overflows: Vec<Ty<'tcx>>,
}
impl<'tcx> DtorckConstraint<'tcx> {
pub fn empty() -> DtorckConstraint<'tcx> {
DtorckConstraint { outlives: vec![], dtorck_types: vec![], overflows: vec![] }
}
}
impl<'tcx> FromIterator<DtorckConstraint<'tcx>> for DtorckConstraint<'tcx> {
fn from_iter<I: IntoIterator<Item = DtorckConstraint<'tcx>>>(iter: I) -> Self {
let mut result = Self::empty();
for DtorckConstraint { outlives, dtorck_types, overflows } in iter {
result.outlives.extend(outlives);
result.dtorck_types.extend(dtorck_types);
result.overflows.extend(overflows);
}
result
}
}
/// This returns true if the type `ty` is "trivial" for
/// dropck-outlives -- that is, if it doesn't require any types to
/// outlive. This is similar but not *quite* the same as the

View file

@ -1,33 +1 @@
use crate::infer::canonical::{Canonical, QueryResponse};
use crate::ty::Ty;
use rustc_data_structures::sync::Lrc;
#[derive(Debug, HashStable)]
pub struct CandidateStep<'tcx> {
pub self_ty: Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>,
pub autoderefs: usize,
/// `true` if the type results from a dereference of a raw pointer.
/// when assembling candidates, we include these steps, but not when
/// picking methods. This so that if we have `foo: *const Foo` and `Foo` has methods
/// `fn by_raw_ptr(self: *const Self)` and `fn by_ref(&self)`, then
/// `foo.by_raw_ptr()` will work and `foo.by_ref()` won't.
pub from_unsafe_deref: bool,
pub unsize: bool,
}
#[derive(Clone, Debug, HashStable)]
pub struct MethodAutoderefStepsResult<'tcx> {
/// The valid autoderef steps that could be find.
pub steps: Lrc<Vec<CandidateStep<'tcx>>>,
/// If Some(T), a type autoderef reported an error on.
pub opt_bad_ty: Option<Lrc<MethodAutoderefBadTy<'tcx>>>,
/// If `true`, `steps` has been truncated due to reaching the
/// recursion limit.
pub reached_recursion_limit: bool,
}
#[derive(Debug, HashStable)]
pub struct MethodAutoderefBadTy<'tcx> {
pub reached_raw_pointer: bool,
pub ty: Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>,
}
pub use rustc::traits::query::{CandidateStep, MethodAutoderefBadTy, MethodAutoderefStepsResult};

View file

@ -5,10 +5,6 @@
//! The providers for the queries defined here can be found in
//! `librustc_traits`.
use crate::infer::canonical::Canonical;
use crate::ty::error::TypeError;
use crate::ty::{self, Ty};
pub mod dropck_outlives;
pub mod evaluate_obligation;
pub mod method_autoderef;
@ -16,35 +12,4 @@ pub mod normalize;
pub mod outlives_bounds;
pub mod type_op;
pub type CanonicalProjectionGoal<'tcx> =
Canonical<'tcx, ty::ParamEnvAnd<'tcx, ty::ProjectionTy<'tcx>>>;
pub type CanonicalTyGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, Ty<'tcx>>>;
pub type CanonicalPredicateGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, ty::Predicate<'tcx>>>;
pub type CanonicalTypeOpAscribeUserTypeGoal<'tcx> =
Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::ascribe_user_type::AscribeUserType<'tcx>>>;
pub type CanonicalTypeOpEqGoal<'tcx> =
Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::eq::Eq<'tcx>>>;
pub type CanonicalTypeOpSubtypeGoal<'tcx> =
Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::subtype::Subtype<'tcx>>>;
pub type CanonicalTypeOpProvePredicateGoal<'tcx> =
Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::prove_predicate::ProvePredicate<'tcx>>>;
pub type CanonicalTypeOpNormalizeGoal<'tcx, T> =
Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::normalize::Normalize<T>>>;
#[derive(Clone, Debug, HashStable)]
pub struct NoSolution;
pub type Fallible<T> = Result<T, NoSolution>;
impl<'tcx> From<TypeError<'tcx>> for NoSolution {
fn from(_: TypeError<'tcx>) -> NoSolution {
NoSolution
}
}
pub use rustc::traits::types::query::*;

View file

@ -13,6 +13,8 @@ use crate::ty::{self, Ty, TyCtxt};
use super::NoSolution;
pub use rustc::traits::query::NormalizationResult;
impl<'cx, 'tcx> At<'cx, 'tcx> {
/// Normalize `value` in the context of the inference context,
/// yielding a resulting type, or an error if `value` cannot be
@ -59,13 +61,6 @@ impl<'cx, 'tcx> At<'cx, 'tcx> {
}
}
/// Result from the `normalize_projection_ty` query.
#[derive(Clone, Debug, HashStable, TypeFoldable, Lift)]
pub struct NormalizationResult<'tcx> {
/// Result of normalization.
pub normalized_ty: Ty<'tcx>,
}
struct QueryNormalizer<'cx, 'tcx> {
infcx: &'cx InferCtxt<'cx, 'tcx>,
cause: &'cx ObligationCause<'tcx>,

View file

@ -6,43 +6,7 @@ use crate::ty::{self, Ty};
use rustc_hir as hir;
use rustc_span::source_map::Span;
use crate::ich::StableHashingContext;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use std::mem;
/// Outlives bounds are relationships between generic parameters,
/// whether they both be regions (`'a: 'b`) or whether types are
/// involved (`T: 'a`). These relationships can be extracted from the
/// full set of predicates we understand or also from types (in which
/// case they are called implied bounds). They are fed to the
/// `OutlivesEnv` which in turn is supplied to the region checker and
/// other parts of the inference system.
#[derive(Clone, Debug, TypeFoldable, Lift)]
pub enum OutlivesBound<'tcx> {
RegionSubRegion(ty::Region<'tcx>, ty::Region<'tcx>),
RegionSubParam(ty::Region<'tcx>, ty::ParamTy),
RegionSubProjection(ty::Region<'tcx>, ty::ProjectionTy<'tcx>),
}
impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for OutlivesBound<'tcx> {
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
mem::discriminant(self).hash_stable(hcx, hasher);
match *self {
OutlivesBound::RegionSubRegion(ref a, ref b) => {
a.hash_stable(hcx, hasher);
b.hash_stable(hcx, hasher);
}
OutlivesBound::RegionSubParam(ref a, ref b) => {
a.hash_stable(hcx, hasher);
b.hash_stable(hcx, hasher);
}
OutlivesBound::RegionSubProjection(ref a, ref b) => {
a.hash_stable(hcx, hasher);
b.hash_stable(hcx, hasher);
}
}
}
}
pub use rustc::traits::query::OutlivesBound;
impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
/// Implied bounds are region relationships that we deduce

View file

@ -1,21 +1,8 @@
use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse};
use crate::traits::query::Fallible;
use crate::ty::subst::UserSubsts;
use crate::ty::{ParamEnvAnd, Ty, TyCtxt};
use rustc_hir::def_id::DefId;
use rustc::ty::{ParamEnvAnd, TyCtxt};
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, Lift)]
pub struct AscribeUserType<'tcx> {
pub mir_ty: Ty<'tcx>,
pub def_id: DefId,
pub user_substs: UserSubsts<'tcx>,
}
impl<'tcx> AscribeUserType<'tcx> {
pub fn new(mir_ty: Ty<'tcx>, def_id: DefId, user_substs: UserSubsts<'tcx>) -> Self {
Self { mir_ty, def_id, user_substs }
}
}
pub use rustc::traits::query::type_op::AscribeUserType;
impl<'tcx> super::QueryTypeOp<'tcx> for AscribeUserType<'tcx> {
type QueryResponse = ();

View file

@ -1,18 +1,8 @@
use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse};
use crate::traits::query::Fallible;
use crate::ty::{ParamEnvAnd, Ty, TyCtxt};
use crate::ty::{ParamEnvAnd, TyCtxt};
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, Lift)]
pub struct Eq<'tcx> {
pub a: Ty<'tcx>,
pub b: Ty<'tcx>,
}
impl<'tcx> Eq<'tcx> {
pub fn new(a: Ty<'tcx>, b: Ty<'tcx>) -> Self {
Self { a, b }
}
}
pub use rustc::traits::query::type_op::Eq;
impl<'tcx> super::QueryTypeOp<'tcx> for Eq<'tcx> {
type QueryResponse = ();

View file

@ -19,6 +19,8 @@ pub mod prove_predicate;
use self::prove_predicate::ProvePredicate;
pub mod subtype;
pub use crate::traits::types::query::type_op::*;
/// "Type ops" are used in NLL to perform some particular action and
/// extract out the resulting region constraints (or an error if it
/// cannot be completed).

View file

@ -4,19 +4,7 @@ use crate::ty::fold::TypeFoldable;
use crate::ty::{self, Lift, ParamEnvAnd, Ty, TyCtxt};
use std::fmt;
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, Lift)]
pub struct Normalize<T> {
pub value: T,
}
impl<'tcx, T> Normalize<T>
where
T: fmt::Debug + TypeFoldable<'tcx>,
{
pub fn new(value: T) -> Self {
Self { value }
}
}
pub use rustc::traits::query::type_op::Normalize;
impl<'tcx, T> super::QueryTypeOp<'tcx> for Normalize<T>
where

View file

@ -2,16 +2,7 @@ use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse};
use crate::traits::query::Fallible;
use crate::ty::{ParamEnvAnd, Predicate, TyCtxt};
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, Lift)]
pub struct ProvePredicate<'tcx> {
pub predicate: Predicate<'tcx>,
}
impl<'tcx> ProvePredicate<'tcx> {
pub fn new(predicate: Predicate<'tcx>) -> Self {
ProvePredicate { predicate }
}
}
pub use rustc::traits::query::type_op::ProvePredicate;
impl<'tcx> super::QueryTypeOp<'tcx> for ProvePredicate<'tcx> {
type QueryResponse = ();

View file

@ -1,18 +1,8 @@
use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse};
use crate::traits::query::Fallible;
use crate::ty::{ParamEnvAnd, Ty, TyCtxt};
use crate::ty::{ParamEnvAnd, TyCtxt};
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, Lift)]
pub struct Subtype<'tcx> {
pub sub: Ty<'tcx>,
pub sup: Ty<'tcx>,
}
impl<'tcx> Subtype<'tcx> {
pub fn new(sub: Ty<'tcx>, sup: Ty<'tcx>) -> Self {
Self { sub, sup }
}
}
pub use rustc::traits::query::type_op::Subtype;
impl<'tcx> super::QueryTypeOp<'tcx> for Subtype<'tcx> {
type QueryResponse = ();

View file

@ -41,7 +41,6 @@ use crate::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, Wit
use rustc_hir::def_id::DefId;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::sync::Lock;
use rustc_hir as hir;
use rustc_index::bit_set::GrowableBitSet;
use rustc_span::symbol::sym;
@ -53,6 +52,8 @@ use std::iter;
use std::rc::Rc;
use syntax::{ast, attr};
pub use rustc::traits::types::select::*;
pub struct SelectionContext<'cx, 'tcx> {
infcx: &'cx InferCtxt<'cx, 'tcx>,
@ -181,146 +182,6 @@ struct TraitObligationStack<'prev, 'tcx> {
dfn: usize,
}
#[derive(Clone, Default)]
pub struct SelectionCache<'tcx> {
hashmap: Lock<
FxHashMap<
ty::ParamEnvAnd<'tcx, ty::TraitRef<'tcx>>,
WithDepNode<SelectionResult<'tcx, SelectionCandidate<'tcx>>>,
>,
>,
}
/// The selection process begins by considering all impls, where
/// clauses, and so forth that might resolve an obligation. Sometimes
/// we'll be able to say definitively that (e.g.) an impl does not
/// apply to the obligation: perhaps it is defined for `usize` but the
/// obligation is for `int`. In that case, we drop the impl out of the
/// list. But the other cases are considered *candidates*.
///
/// For selection to succeed, there must be exactly one matching
/// candidate. If the obligation is fully known, this is guaranteed
/// by coherence. However, if the obligation contains type parameters
/// or variables, there may be multiple such impls.
///
/// It is not a real problem if multiple matching impls exist because
/// of type variables - it just means the obligation isn't sufficiently
/// elaborated. In that case we report an ambiguity, and the caller can
/// try again after more type information has been gathered or report a
/// "type annotations needed" error.
///
/// However, with type parameters, this can be a real problem - type
/// parameters don't unify with regular types, but they *can* unify
/// with variables from blanket impls, and (unless we know its bounds
/// will always be satisfied) picking the blanket impl will be wrong
/// for at least *some* substitutions. To make this concrete, if we have
///
/// trait AsDebug { type Out : fmt::Debug; fn debug(self) -> Self::Out; }
/// impl<T: fmt::Debug> AsDebug for T {
/// type Out = T;
/// fn debug(self) -> fmt::Debug { self }
/// }
/// fn foo<T: AsDebug>(t: T) { println!("{:?}", <T as AsDebug>::debug(t)); }
///
/// we can't just use the impl to resolve the `<T as AsDebug>` obligation
/// -- a type from another crate (that doesn't implement `fmt::Debug`) could
/// implement `AsDebug`.
///
/// Because where-clauses match the type exactly, multiple clauses can
/// only match if there are unresolved variables, and we can mostly just
/// report this ambiguity in that case. This is still a problem - we can't
/// *do anything* with ambiguities that involve only regions. This is issue
/// #21974.
///
/// If a single where-clause matches and there are no inference
/// variables left, then it definitely matches and we can just select
/// it.
///
/// In fact, we even select the where-clause when the obligation contains
/// inference variables. The can lead to inference making "leaps of logic",
/// for example in this situation:
///
/// pub trait Foo<T> { fn foo(&self) -> T; }
/// impl<T> Foo<()> for T { fn foo(&self) { } }
/// impl Foo<bool> for bool { fn foo(&self) -> bool { *self } }
///
/// pub fn foo<T>(t: T) where T: Foo<bool> {
/// println!("{:?}", <T as Foo<_>>::foo(&t));
/// }
/// fn main() { foo(false); }
///
/// Here the obligation `<T as Foo<$0>>` can be matched by both the blanket
/// impl and the where-clause. We select the where-clause and unify `$0=bool`,
/// so the program prints "false". However, if the where-clause is omitted,
/// the blanket impl is selected, we unify `$0=()`, and the program prints
/// "()".
///
/// Exactly the same issues apply to projection and object candidates, except
/// that we can have both a projection candidate and a where-clause candidate
/// for the same obligation. In that case either would do (except that
/// different "leaps of logic" would occur if inference variables are
/// present), and we just pick the where-clause. This is, for example,
/// required for associated types to work in default impls, as the bounds
/// are visible both as projection bounds and as where-clauses from the
/// parameter environment.
#[derive(PartialEq, Eq, Debug, Clone, TypeFoldable)]
enum SelectionCandidate<'tcx> {
BuiltinCandidate {
/// `false` if there are no *further* obligations.
has_nested: bool,
},
ParamCandidate(ty::PolyTraitRef<'tcx>),
ImplCandidate(DefId),
AutoImplCandidate(DefId),
/// This is a trait matching with a projected type as `Self`, and
/// we found an applicable bound in the trait definition.
ProjectionCandidate,
/// Implementation of a `Fn`-family trait by one of the anonymous types
/// generated for a `||` expression.
ClosureCandidate,
/// Implementation of a `Generator` trait by one of the anonymous types
/// generated for a generator.
GeneratorCandidate,
/// Implementation of a `Fn`-family trait by one of the anonymous
/// types generated for a fn pointer type (e.g., `fn(int) -> int`)
FnPointerCandidate,
TraitAliasCandidate(DefId),
ObjectCandidate,
BuiltinObjectCandidate,
BuiltinUnsizeCandidate,
}
impl<'a, 'tcx> ty::Lift<'tcx> for SelectionCandidate<'a> {
type Lifted = SelectionCandidate<'tcx>;
fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
Some(match *self {
BuiltinCandidate { has_nested } => BuiltinCandidate { has_nested },
ImplCandidate(def_id) => ImplCandidate(def_id),
AutoImplCandidate(def_id) => AutoImplCandidate(def_id),
ProjectionCandidate => ProjectionCandidate,
ClosureCandidate => ClosureCandidate,
GeneratorCandidate => GeneratorCandidate,
FnPointerCandidate => FnPointerCandidate,
TraitAliasCandidate(def_id) => TraitAliasCandidate(def_id),
ObjectCandidate => ObjectCandidate,
BuiltinObjectCandidate => BuiltinObjectCandidate,
BuiltinUnsizeCandidate => BuiltinUnsizeCandidate,
ParamCandidate(ref trait_ref) => {
return tcx.lift(trait_ref).map(ParamCandidate);
}
})
}
}
struct SelectionCandidateSet<'tcx> {
// A list of candidates that definitely apply to the current
// obligation (meaning: types unify).
@ -350,134 +211,6 @@ enum BuiltinImplConditions<'tcx> {
Ambiguous,
}
/// The result of trait evaluation. The order is important
/// here as the evaluation of a list is the maximum of the
/// evaluations.
///
/// The evaluation results are ordered:
/// - `EvaluatedToOk` implies `EvaluatedToOkModuloRegions`
/// implies `EvaluatedToAmbig` implies `EvaluatedToUnknown`
/// - `EvaluatedToErr` implies `EvaluatedToRecur`
/// - the "union" of evaluation results is equal to their maximum -
/// all the "potential success" candidates can potentially succeed,
/// so they are noops when unioned with a definite error, and within
/// the categories it's easy to see that the unions are correct.
#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq, HashStable)]
pub enum EvaluationResult {
/// Evaluation successful.
EvaluatedToOk,
/// Evaluation successful, but there were unevaluated region obligations.
EvaluatedToOkModuloRegions,
/// Evaluation is known to be ambiguous -- it *might* hold for some
/// assignment of inference variables, but it might not.
///
/// While this has the same meaning as `EvaluatedToUnknown` -- we can't
/// know whether this obligation holds or not -- it is the result we
/// would get with an empty stack, and therefore is cacheable.
EvaluatedToAmbig,
/// Evaluation failed because of recursion involving inference
/// variables. We are somewhat imprecise there, so we don't actually
/// know the real result.
///
/// This can't be trivially cached for the same reason as `EvaluatedToRecur`.
EvaluatedToUnknown,
/// Evaluation failed because we encountered an obligation we are already
/// trying to prove on this branch.
///
/// We know this branch can't be a part of a minimal proof-tree for
/// the "root" of our cycle, because then we could cut out the recursion
/// and maintain a valid proof tree. However, this does not mean
/// that all the obligations on this branch do not hold -- it's possible
/// that we entered this branch "speculatively", and that there
/// might be some other way to prove this obligation that does not
/// go through this cycle -- so we can't cache this as a failure.
///
/// For example, suppose we have this:
///
/// ```rust,ignore (pseudo-Rust)
/// pub trait Trait { fn xyz(); }
/// // This impl is "useless", but we can still have
/// // an `impl Trait for SomeUnsizedType` somewhere.
/// impl<T: Trait + Sized> Trait for T { fn xyz() {} }
///
/// pub fn foo<T: Trait + ?Sized>() {
/// <T as Trait>::xyz();
/// }
/// ```
///
/// When checking `foo`, we have to prove `T: Trait`. This basically
/// translates into this:
///
/// ```plain,ignore
/// (T: Trait + Sized →_\impl T: Trait), T: Trait ⊢ T: Trait
/// ```
///
/// When we try to prove it, we first go the first option, which
/// recurses. This shows us that the impl is "useless" -- it won't
/// tell us that `T: Trait` unless it already implemented `Trait`
/// by some other means. However, that does not prevent `T: Trait`
/// does not hold, because of the bound (which can indeed be satisfied
/// by `SomeUnsizedType` from another crate).
//
// FIXME: when an `EvaluatedToRecur` goes past its parent root, we
// ought to convert it to an `EvaluatedToErr`, because we know
// there definitely isn't a proof tree for that obligation. Not
// doing so is still sound -- there isn't any proof tree, so the
// branch still can't be a part of a minimal one -- but does not re-enable caching.
EvaluatedToRecur,
/// Evaluation failed.
EvaluatedToErr,
}
impl EvaluationResult {
/// Returns `true` if this evaluation result is known to apply, even
/// considering outlives constraints.
pub fn must_apply_considering_regions(self) -> bool {
self == EvaluatedToOk
}
/// Returns `true` if this evaluation result is known to apply, ignoring
/// outlives constraints.
pub fn must_apply_modulo_regions(self) -> bool {
self <= EvaluatedToOkModuloRegions
}
pub fn may_apply(self) -> bool {
match self {
EvaluatedToOk | EvaluatedToOkModuloRegions | EvaluatedToAmbig | EvaluatedToUnknown => {
true
}
EvaluatedToErr | EvaluatedToRecur => false,
}
}
fn is_stack_dependent(self) -> bool {
match self {
EvaluatedToUnknown | EvaluatedToRecur => true,
EvaluatedToOk | EvaluatedToOkModuloRegions | EvaluatedToAmbig | EvaluatedToErr => false,
}
}
}
/// Indicates that trait evaluation caused overflow.
#[derive(Copy, Clone, Debug, PartialEq, Eq, HashStable)]
pub struct OverflowError;
impl<'tcx> From<OverflowError> for SelectionError<'tcx> {
fn from(OverflowError: OverflowError) -> SelectionError<'tcx> {
SelectionError::Overflow
}
}
#[derive(Clone, Default)]
pub struct EvaluationCache<'tcx> {
hashmap: Lock<
FxHashMap<ty::ParamEnvAnd<'tcx, ty::PolyTraitRef<'tcx>>, WithDepNode<EvaluationResult>>,
>,
}
impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
pub fn new(infcx: &'cx InferCtxt<'cx, 'tcx>) -> SelectionContext<'cx, 'tcx> {
SelectionContext {
@ -3827,20 +3560,6 @@ impl<'tcx> TraitObligation<'tcx> {
}
}
impl<'tcx> SelectionCache<'tcx> {
/// Actually frees the underlying memory in contrast to what stdlib containers do on `clear`
pub fn clear(&self) {
*self.hashmap.borrow_mut() = Default::default();
}
}
impl<'tcx> EvaluationCache<'tcx> {
/// Actually frees the underlying memory in contrast to what stdlib containers do on `clear`
pub fn clear(&self) {
*self.hashmap.borrow_mut() = Default::default();
}
}
impl<'o, 'tcx> TraitObligationStack<'o, 'tcx> {
fn list(&'o self) -> TraitObligationStackList<'o, 'tcx> {
TraitObligationStackList::with(self)
@ -4126,20 +3845,3 @@ impl<'o, 'tcx> fmt::Debug for TraitObligationStack<'o, 'tcx> {
write!(f, "TraitObligationStack({:?})", self.obligation)
}
}
#[derive(Clone, Eq, PartialEq)]
pub struct WithDepNode<T> {
dep_node: DepNodeIndex,
cached_value: T,
}
impl<T: Clone> WithDepNode<T> {
pub fn new(dep_node: DepNodeIndex, cached_value: T) -> Self {
WithDepNode { dep_node, cached_value }
}
pub fn get(&self, tcx: TyCtxt<'_>) -> T {
tcx.dep_graph.read_index(self.dep_node);
self.cached_value.clone()
}
}

View file

@ -1,58 +1,11 @@
use super::OverlapError;
use crate::ich::{self, StableHashingContext};
use crate::traits;
use crate::ty::fast_reject::{self, SimplifiedType};
use crate::ty::{self, TyCtxt, TypeFoldable};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_hir::def_id::{DefId, DefIdMap};
use syntax::ast::Ident;
use rustc::ty::fast_reject::{self, SimplifiedType};
use rustc::ty::{self, TyCtxt, TypeFoldable};
use rustc_hir::def_id::DefId;
/// A per-trait graph of impls in specialization order. At the moment, this
/// graph forms a tree rooted with the trait itself, with all other nodes
/// representing impls, and parent-child relationships representing
/// specializations.
///
/// The graph provides two key services:
///
/// - Construction. This implicitly checks for overlapping impls (i.e., impls
/// that overlap but where neither specializes the other -- an artifact of the
/// simple "chain" rule.
///
/// - Parent extraction. In particular, the graph can give you the *immediate*
/// parents of a given specializing impl, which is needed for extracting
/// default items amongst other things. In the simple "chain" rule, every impl
/// has at most one parent.
#[derive(RustcEncodable, RustcDecodable, HashStable)]
pub struct Graph {
// All impls have a parent; the "root" impls have as their parent the `def_id`
// of the trait.
parent: DefIdMap<DefId>,
// The "root" impls are found by looking up the trait's def_id.
children: DefIdMap<Children>,
}
/// Children of a given impl, grouped into blanket/non-blanket varieties as is
/// done in `TraitDef`.
#[derive(Default, RustcEncodable, RustcDecodable)]
struct Children {
// Impls of a trait (or specializations of a given impl). To allow for
// quicker lookup, the impls are indexed by a simplified version of their
// `Self` type: impls with a simplifiable `Self` are stored in
// `nonblanket_impls` keyed by it, while all other impls are stored in
// `blanket_impls`.
//
// A similar division is used within `TraitDef`, but the lists there collect
// together *all* the impls for a trait, and are populated prior to building
// the specialization graph.
/// Impls of the trait.
nonblanket_impls: FxHashMap<fast_reject::SimplifiedType, Vec<DefId>>,
/// Blanket impls associated with the trait.
blanket_impls: Vec<DefId>,
}
pub use rustc::traits::types::specialization_graph::*;
#[derive(Copy, Clone, Debug)]
pub enum FutureCompatOverlapErrorKind {
@ -269,10 +222,6 @@ where
}
impl<'tcx> Graph {
pub fn new() -> Graph {
Graph { parent: Default::default(), children: Default::default() }
}
/// Insert a local impl into the specialization graph. If an existing impl
/// conflicts with it (has overlap, but neither specializes the other),
/// information about the area of overlap is returned in the `Err`.
@ -383,145 +332,4 @@ impl<'tcx> Graph {
self.children.entry(parent).or_default().insert_blindly(tcx, child);
}
/// The parent of a given impl, which is the `DefId` of the trait when the
/// impl is a "specialization root".
pub fn parent(&self, child: DefId) -> DefId {
*self.parent.get(&child).unwrap_or_else(|| panic!("Failed to get parent for {:?}", child))
}
}
/// A node in the specialization graph is either an impl or a trait
/// definition; either can serve as a source of item definitions.
/// There is always exactly one trait definition node: the root.
#[derive(Debug, Copy, Clone)]
pub enum Node {
Impl(DefId),
Trait(DefId),
}
impl<'tcx> Node {
pub fn is_from_trait(&self) -> bool {
match *self {
Node::Trait(..) => true,
_ => false,
}
}
/// Iterate over the items defined directly by the given (impl or trait) node.
pub fn items(&self, tcx: TyCtxt<'tcx>) -> ty::AssocItemsIterator<'tcx> {
tcx.associated_items(self.def_id())
}
/// Finds an associated item defined in this node.
///
/// If this returns `None`, the item can potentially still be found in
/// parents of this node.
pub fn item(
&self,
tcx: TyCtxt<'tcx>,
trait_item_name: Ident,
trait_item_kind: ty::AssocKind,
trait_def_id: DefId,
) -> Option<ty::AssocItem> {
use crate::ty::AssocKind::*;
tcx.associated_items(self.def_id()).find(move |impl_item| {
match (trait_item_kind, impl_item.kind) {
| (Const, Const)
| (Method, Method)
| (Type, Type)
| (Type, OpaqueTy) // assoc. types can be made opaque in impls
=> tcx.hygienic_eq(impl_item.ident, trait_item_name, trait_def_id),
| (Const, _)
| (Method, _)
| (Type, _)
| (OpaqueTy, _)
=> false,
}
})
}
pub fn def_id(&self) -> DefId {
match *self {
Node::Impl(did) => did,
Node::Trait(did) => did,
}
}
}
#[derive(Copy, Clone)]
pub struct Ancestors<'tcx> {
trait_def_id: DefId,
specialization_graph: &'tcx Graph,
current_source: Option<Node>,
}
impl Iterator for Ancestors<'_> {
type Item = Node;
fn next(&mut self) -> Option<Node> {
let cur = self.current_source.take();
if let Some(Node::Impl(cur_impl)) = cur {
let parent = self.specialization_graph.parent(cur_impl);
self.current_source = if parent == self.trait_def_id {
Some(Node::Trait(parent))
} else {
Some(Node::Impl(parent))
};
}
cur
}
}
pub struct NodeItem<T> {
pub node: Node,
pub item: T,
}
impl<T> NodeItem<T> {
pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> NodeItem<U> {
NodeItem { node: self.node, item: f(self.item) }
}
}
impl<'tcx> Ancestors<'tcx> {
/// Finds the bottom-most (ie. most specialized) definition of an associated
/// item.
pub fn leaf_def(
mut self,
tcx: TyCtxt<'tcx>,
trait_item_name: Ident,
trait_item_kind: ty::AssocKind,
) -> Option<NodeItem<ty::AssocItem>> {
let trait_def_id = self.trait_def_id;
self.find_map(|node| {
node.item(tcx, trait_item_name, trait_item_kind, trait_def_id)
.map(|item| NodeItem { node, item })
})
}
}
/// Walk up the specialization ancestors of a given impl, starting with that
/// impl itself.
pub fn ancestors(
tcx: TyCtxt<'tcx>,
trait_def_id: DefId,
start_from_impl: DefId,
) -> Ancestors<'tcx> {
let specialization_graph = tcx.specialization_graph_of(trait_def_id);
Ancestors {
trait_def_id,
specialization_graph,
current_source: Some(Node::Impl(start_from_impl)),
}
}
impl<'a> HashStable<StableHashingContext<'a>> for Children {
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
let Children { ref nonblanket_impls, ref blanket_impls } = *self;
ich::hash_stable_trait_impls(hcx, hasher, blanket_impls, nonblanket_impls);
}
}

View file

@ -1,13 +1,9 @@
use crate::traits;
use crate::traits::project::Normalized;
use crate::ty;
use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
use crate::ty::{self, Lift, Ty, TyCtxt};
use rustc_span::symbol::Symbol;
use smallvec::SmallVec;
use std::collections::{BTreeMap, BTreeSet};
use std::fmt;
use std::rc::Rc;
// Structural impls for the structs in `traits`.
@ -31,102 +27,6 @@ impl<'tcx, O: fmt::Debug> fmt::Debug for traits::Obligation<'tcx, O> {
}
}
impl<'tcx, N: fmt::Debug> fmt::Debug for traits::Vtable<'tcx, N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
super::VtableImpl(ref v) => write!(f, "{:?}", v),
super::VtableAutoImpl(ref t) => write!(f, "{:?}", t),
super::VtableClosure(ref d) => write!(f, "{:?}", d),
super::VtableGenerator(ref d) => write!(f, "{:?}", d),
super::VtableFnPointer(ref d) => write!(f, "VtableFnPointer({:?})", d),
super::VtableObject(ref d) => write!(f, "{:?}", d),
super::VtableParam(ref n) => write!(f, "VtableParam({:?})", n),
super::VtableBuiltin(ref d) => write!(f, "{:?}", d),
super::VtableTraitAlias(ref d) => write!(f, "{:?}", d),
}
}
}
impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableImplData<'tcx, N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"VtableImplData(impl_def_id={:?}, substs={:?}, nested={:?})",
self.impl_def_id, self.substs, self.nested
)
}
}
impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableGeneratorData<'tcx, N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"VtableGeneratorData(generator_def_id={:?}, substs={:?}, nested={:?})",
self.generator_def_id, self.substs, self.nested
)
}
}
impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableClosureData<'tcx, N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"VtableClosureData(closure_def_id={:?}, substs={:?}, nested={:?})",
self.closure_def_id, self.substs, self.nested
)
}
}
impl<N: fmt::Debug> fmt::Debug for traits::VtableBuiltinData<N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "VtableBuiltinData(nested={:?})", self.nested)
}
}
impl<N: fmt::Debug> fmt::Debug for traits::VtableAutoImplData<N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"VtableAutoImplData(trait_def_id={:?}, nested={:?})",
self.trait_def_id, self.nested
)
}
}
impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableObjectData<'tcx, N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"VtableObjectData(upcast={:?}, vtable_base={}, nested={:?})",
self.upcast_trait_ref, self.vtable_base, self.nested
)
}
}
impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableFnPointerData<'tcx, N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "VtableFnPointerData(fn_ty={:?}, nested={:?})", self.fn_ty, self.nested)
}
}
impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableTraitAliasData<'tcx, N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"VtableTraitAlias(alias_def_id={:?}, substs={:?}, nested={:?})",
self.alias_def_id, self.substs, self.nested
)
}
}
impl<'tcx> fmt::Debug for traits::FulfillmentError<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "FulfillmentError({:?},{:?})", self.obligation, self.code)
@ -152,531 +52,6 @@ impl<'tcx> fmt::Debug for traits::MismatchedProjectionTypes<'tcx> {
}
}
impl<'tcx> fmt::Display for traits::WhereClause<'tcx> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
use crate::traits::WhereClause::*;
// Bypass `ty::print` because it does not print out anonymous regions.
// FIXME(eddyb) implement a custom `PrettyPrinter`, or move this to `ty::print`.
fn write_region_name<'tcx>(
r: ty::Region<'tcx>,
fmt: &mut fmt::Formatter<'_>,
) -> fmt::Result {
match r {
ty::ReLateBound(index, br) => match br {
ty::BoundRegion::BrNamed(_, name) => write!(fmt, "{}", name),
ty::BoundRegion::BrAnon(var) => {
if *index == ty::INNERMOST {
write!(fmt, "'^{}", var)
} else {
write!(fmt, "'^{}_{}", index.index(), var)
}
}
_ => write!(fmt, "'_"),
},
_ => write!(fmt, "{}", r),
}
}
match self {
Implemented(trait_ref) => write!(fmt, "Implemented({})", trait_ref),
ProjectionEq(projection) => write!(fmt, "ProjectionEq({})", projection),
RegionOutlives(predicate) => {
write!(fmt, "RegionOutlives({}: ", predicate.0)?;
write_region_name(predicate.1, fmt)?;
write!(fmt, ")")
}
TypeOutlives(predicate) => {
write!(fmt, "TypeOutlives({}: ", predicate.0)?;
write_region_name(predicate.1, fmt)?;
write!(fmt, ")")
}
}
}
}
impl<'tcx> fmt::Display for traits::WellFormed<'tcx> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
use crate::traits::WellFormed::*;
match self {
Trait(trait_ref) => write!(fmt, "WellFormed({})", trait_ref),
Ty(ty) => write!(fmt, "WellFormed({})", ty),
}
}
}
impl<'tcx> fmt::Display for traits::FromEnv<'tcx> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
use crate::traits::FromEnv::*;
match self {
Trait(trait_ref) => write!(fmt, "FromEnv({})", trait_ref),
Ty(ty) => write!(fmt, "FromEnv({})", ty),
}
}
}
impl<'tcx> fmt::Display for traits::DomainGoal<'tcx> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
use crate::traits::DomainGoal::*;
match self {
Holds(wc) => write!(fmt, "{}", wc),
WellFormed(wf) => write!(fmt, "{}", wf),
FromEnv(from_env) => write!(fmt, "{}", from_env),
Normalize(projection) => {
write!(fmt, "Normalize({} -> {})", projection.projection_ty, projection.ty)
}
}
}
}
impl fmt::Display for traits::QuantifierKind {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
use crate::traits::QuantifierKind::*;
match self {
Universal => write!(fmt, "forall"),
Existential => write!(fmt, "exists"),
}
}
}
/// Collect names for regions / types bound by a quantified goal / clause.
/// This collector does not try to do anything clever like in `ty::print`, it's just used
/// for debug output in tests anyway.
struct BoundNamesCollector {
// Just sort by name because `BoundRegion::BrNamed` does not have a `BoundVar` index anyway.
regions: BTreeSet<Symbol>,
// Sort by `BoundVar` index, so usually this should be equivalent to the order given
// by the list of type parameters.
types: BTreeMap<u32, Symbol>,
binder_index: ty::DebruijnIndex,
}
impl BoundNamesCollector {
fn new() -> Self {
BoundNamesCollector {
regions: BTreeSet::new(),
types: BTreeMap::new(),
binder_index: ty::INNERMOST,
}
}
fn is_empty(&self) -> bool {
self.regions.is_empty() && self.types.is_empty()
}
fn write_names(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut start = true;
for r in &self.regions {
if !start {
write!(fmt, ", ")?;
}
start = false;
write!(fmt, "{}", r)?;
}
for (_, t) in &self.types {
if !start {
write!(fmt, ", ")?;
}
start = false;
write!(fmt, "{}", t)?;
}
Ok(())
}
}
impl<'tcx> TypeVisitor<'tcx> for BoundNamesCollector {
fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> bool {
self.binder_index.shift_in(1);
let result = t.super_visit_with(self);
self.binder_index.shift_out(1);
result
}
fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
match t.kind {
ty::Bound(debruijn, bound_ty) if debruijn == self.binder_index => {
self.types.insert(
bound_ty.var.as_u32(),
match bound_ty.kind {
ty::BoundTyKind::Param(name) => name,
ty::BoundTyKind::Anon => {
Symbol::intern(&format!("^{}", bound_ty.var.as_u32()))
}
},
);
}
_ => (),
};
t.super_visit_with(self)
}
fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
match r {
ty::ReLateBound(index, br) if *index == self.binder_index => match br {
ty::BoundRegion::BrNamed(_, name) => {
self.regions.insert(*name);
}
ty::BoundRegion::BrAnon(var) => {
self.regions.insert(Symbol::intern(&format!("'^{}", var)));
}
_ => (),
},
_ => (),
};
r.super_visit_with(self)
}
}
impl<'tcx> fmt::Display for traits::Goal<'tcx> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
use crate::traits::GoalKind::*;
match self {
Implies(hypotheses, goal) => {
write!(fmt, "if (")?;
for (index, hyp) in hypotheses.iter().enumerate() {
if index > 0 {
write!(fmt, ", ")?;
}
write!(fmt, "{}", hyp)?;
}
write!(fmt, ") {{ {} }}", goal)
}
And(goal1, goal2) => write!(fmt, "({} && {})", goal1, goal2),
Not(goal) => write!(fmt, "not {{ {} }}", goal),
DomainGoal(goal) => write!(fmt, "{}", goal),
Quantified(qkind, goal) => {
let mut collector = BoundNamesCollector::new();
goal.skip_binder().visit_with(&mut collector);
if !collector.is_empty() {
write!(fmt, "{}<", qkind)?;
collector.write_names(fmt)?;
write!(fmt, "> {{ ")?;
}
write!(fmt, "{}", goal.skip_binder())?;
if !collector.is_empty() {
write!(fmt, " }}")?;
}
Ok(())
}
Subtype(a, b) => write!(fmt, "{} <: {}", a, b),
CannotProve => write!(fmt, "CannotProve"),
}
}
}
impl<'tcx> fmt::Display for traits::ProgramClause<'tcx> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
let traits::ProgramClause { goal, hypotheses, .. } = self;
write!(fmt, "{}", goal)?;
if !hypotheses.is_empty() {
write!(fmt, " :- ")?;
for (index, condition) in hypotheses.iter().enumerate() {
if index > 0 {
write!(fmt, ", ")?;
}
write!(fmt, "{}", condition)?;
}
}
write!(fmt, ".")
}
}
impl<'tcx> fmt::Display for traits::Clause<'tcx> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
use crate::traits::Clause::*;
match self {
Implies(clause) => write!(fmt, "{}", clause),
ForAll(clause) => {
let mut collector = BoundNamesCollector::new();
clause.skip_binder().visit_with(&mut collector);
if !collector.is_empty() {
write!(fmt, "forall<")?;
collector.write_names(fmt)?;
write!(fmt, "> {{ ")?;
}
write!(fmt, "{}", clause.skip_binder())?;
if !collector.is_empty() {
write!(fmt, " }}")?;
}
Ok(())
}
}
}
}
///////////////////////////////////////////////////////////////////////////
// Lift implementations
impl<'a, 'tcx> Lift<'tcx> for traits::SelectionError<'a> {
type Lifted = traits::SelectionError<'tcx>;
fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
match *self {
super::Unimplemented => Some(super::Unimplemented),
super::OutputTypeParameterMismatch(a, b, ref err) => {
tcx.lift(&(a, b)).and_then(|(a, b)| {
tcx.lift(err).map(|err| super::OutputTypeParameterMismatch(a, b, err))
})
}
super::TraitNotObjectSafe(def_id) => Some(super::TraitNotObjectSafe(def_id)),
super::ConstEvalFailure(err) => Some(super::ConstEvalFailure(err)),
super::Overflow => Some(super::Overflow),
}
}
}
impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> {
type Lifted = traits::ObligationCauseCode<'tcx>;
fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
match *self {
super::ReturnNoExpression => Some(super::ReturnNoExpression),
super::MiscObligation => Some(super::MiscObligation),
super::SliceOrArrayElem => Some(super::SliceOrArrayElem),
super::TupleElem => Some(super::TupleElem),
super::ProjectionWf(proj) => tcx.lift(&proj).map(super::ProjectionWf),
super::ItemObligation(def_id) => Some(super::ItemObligation(def_id)),
super::BindingObligation(def_id, span) => Some(super::BindingObligation(def_id, span)),
super::ReferenceOutlivesReferent(ty) => {
tcx.lift(&ty).map(super::ReferenceOutlivesReferent)
}
super::ObjectTypeBound(ty, r) => tcx
.lift(&ty)
.and_then(|ty| tcx.lift(&r).and_then(|r| Some(super::ObjectTypeBound(ty, r)))),
super::ObjectCastObligation(ty) => tcx.lift(&ty).map(super::ObjectCastObligation),
super::Coercion { source, target } => {
Some(super::Coercion { source: tcx.lift(&source)?, target: tcx.lift(&target)? })
}
super::AssignmentLhsSized => Some(super::AssignmentLhsSized),
super::TupleInitializerSized => Some(super::TupleInitializerSized),
super::StructInitializerSized => Some(super::StructInitializerSized),
super::VariableType(id) => Some(super::VariableType(id)),
super::ReturnValue(id) => Some(super::ReturnValue(id)),
super::ReturnType => Some(super::ReturnType),
super::SizedArgumentType => Some(super::SizedArgumentType),
super::SizedReturnType => Some(super::SizedReturnType),
super::SizedYieldType => Some(super::SizedYieldType),
super::RepeatVec(suggest_flag) => Some(super::RepeatVec(suggest_flag)),
super::FieldSized { adt_kind, last } => Some(super::FieldSized { adt_kind, last }),
super::ConstSized => Some(super::ConstSized),
super::ConstPatternStructural => Some(super::ConstPatternStructural),
super::SharedStatic => Some(super::SharedStatic),
super::BuiltinDerivedObligation(ref cause) => {
tcx.lift(cause).map(super::BuiltinDerivedObligation)
}
super::ImplDerivedObligation(ref cause) => {
tcx.lift(cause).map(super::ImplDerivedObligation)
}
super::CompareImplMethodObligation {
item_name,
impl_item_def_id,
trait_item_def_id,
} => Some(super::CompareImplMethodObligation {
item_name,
impl_item_def_id,
trait_item_def_id,
}),
super::CompareImplTypeObligation { item_name, impl_item_def_id, trait_item_def_id } => {
Some(super::CompareImplTypeObligation {
item_name,
impl_item_def_id,
trait_item_def_id,
})
}
super::ExprAssignable => Some(super::ExprAssignable),
super::MatchExpressionArm(box super::MatchExpressionArmCause {
arm_span,
source,
ref prior_arms,
last_ty,
scrut_hir_id,
}) => tcx.lift(&last_ty).map(|last_ty| {
super::MatchExpressionArm(box super::MatchExpressionArmCause {
arm_span,
source,
prior_arms: prior_arms.clone(),
last_ty,
scrut_hir_id,
})
}),
super::Pattern { span, root_ty, origin_expr } => {
tcx.lift(&root_ty).map(|root_ty| super::Pattern { span, root_ty, origin_expr })
}
super::IfExpression(box super::IfExpressionCause { then, outer, semicolon }) => {
Some(super::IfExpression(box super::IfExpressionCause { then, outer, semicolon }))
}
super::IfExpressionWithNoElse => Some(super::IfExpressionWithNoElse),
super::MainFunctionType => Some(super::MainFunctionType),
super::StartFunctionType => Some(super::StartFunctionType),
super::IntrinsicType => Some(super::IntrinsicType),
super::MethodReceiver => Some(super::MethodReceiver),
super::BlockTailExpression(id) => Some(super::BlockTailExpression(id)),
super::TrivialBound => Some(super::TrivialBound),
super::AssocTypeBound(ref data) => Some(super::AssocTypeBound(data.clone())),
}
}
}
impl<'a, 'tcx> Lift<'tcx> for traits::DerivedObligationCause<'a> {
type Lifted = traits::DerivedObligationCause<'tcx>;
fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
tcx.lift(&self.parent_trait_ref).and_then(|trait_ref| {
tcx.lift(&*self.parent_code).map(|code| traits::DerivedObligationCause {
parent_trait_ref: trait_ref,
parent_code: Rc::new(code),
})
})
}
}
impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCause<'a> {
type Lifted = traits::ObligationCause<'tcx>;
fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
tcx.lift(&self.code).map(|code| traits::ObligationCause {
span: self.span,
body_id: self.body_id,
code,
})
}
}
// For codegen only.
impl<'a, 'tcx> Lift<'tcx> for traits::Vtable<'a, ()> {
type Lifted = traits::Vtable<'tcx, ()>;
fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
match self.clone() {
traits::VtableImpl(traits::VtableImplData { impl_def_id, substs, nested }) => {
tcx.lift(&substs).map(|substs| {
traits::VtableImpl(traits::VtableImplData { impl_def_id, substs, nested })
})
}
traits::VtableAutoImpl(t) => Some(traits::VtableAutoImpl(t)),
traits::VtableGenerator(traits::VtableGeneratorData {
generator_def_id,
substs,
nested,
}) => tcx.lift(&substs).map(|substs| {
traits::VtableGenerator(traits::VtableGeneratorData {
generator_def_id: generator_def_id,
substs: substs,
nested: nested,
})
}),
traits::VtableClosure(traits::VtableClosureData { closure_def_id, substs, nested }) => {
tcx.lift(&substs).map(|substs| {
traits::VtableClosure(traits::VtableClosureData {
closure_def_id,
substs,
nested,
})
})
}
traits::VtableFnPointer(traits::VtableFnPointerData { fn_ty, nested }) => {
tcx.lift(&fn_ty).map(|fn_ty| {
traits::VtableFnPointer(traits::VtableFnPointerData { fn_ty, nested })
})
}
traits::VtableParam(n) => Some(traits::VtableParam(n)),
traits::VtableBuiltin(n) => Some(traits::VtableBuiltin(n)),
traits::VtableObject(traits::VtableObjectData {
upcast_trait_ref,
vtable_base,
nested,
}) => tcx.lift(&upcast_trait_ref).map(|trait_ref| {
traits::VtableObject(traits::VtableObjectData {
upcast_trait_ref: trait_ref,
vtable_base,
nested,
})
}),
traits::VtableTraitAlias(traits::VtableTraitAliasData {
alias_def_id,
substs,
nested,
}) => tcx.lift(&substs).map(|substs| {
traits::VtableTraitAlias(traits::VtableTraitAliasData {
alias_def_id,
substs,
nested,
})
}),
}
}
}
impl<'a, 'tcx> Lift<'tcx> for traits::Environment<'a> {
type Lifted = traits::Environment<'tcx>;
fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
tcx.lift(&self.clauses).map(|clauses| traits::Environment { clauses })
}
}
impl<'a, 'tcx, G: Lift<'tcx>> Lift<'tcx> for traits::InEnvironment<'a, G> {
type Lifted = traits::InEnvironment<'tcx, G::Lifted>;
fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
tcx.lift(&self.environment).and_then(|environment| {
tcx.lift(&self.goal).map(|goal| traits::InEnvironment { environment, goal })
})
}
}
impl<'tcx, C> Lift<'tcx> for chalk_engine::ExClause<C>
where
C: chalk_engine::context::Context + Clone,
C: traits::ChalkContextLift<'tcx>,
{
type Lifted = C::LiftedExClause;
fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
<C as traits::ChalkContextLift>::lift_ex_clause_to_tcx(self, tcx)
}
}
impl<'tcx, C> Lift<'tcx> for chalk_engine::DelayedLiteral<C>
where
C: chalk_engine::context::Context + Clone,
C: traits::ChalkContextLift<'tcx>,
{
type Lifted = C::LiftedDelayedLiteral;
fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
<C as traits::ChalkContextLift>::lift_delayed_literal_to_tcx(self, tcx)
}
}
impl<'tcx, C> Lift<'tcx> for chalk_engine::Literal<C>
where
C: chalk_engine::context::Context + Clone,
C: traits::ChalkContextLift<'tcx>,
{
type Lifted = C::LiftedLiteral;
fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
<C as traits::ChalkContextLift>::lift_literal_to_tcx(self, tcx)
}
}
///////////////////////////////////////////////////////////////////////////
// TypeFoldable implementations.
@ -694,80 +69,3 @@ impl<'tcx, O: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Obligation<'tcx
self.predicate.visit_with(visitor)
}
}
CloneTypeFoldableAndLiftImpls! {
traits::QuantifierKind,
}
impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<traits::Goal<'tcx>> {
fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
let v = self.iter().map(|t| t.fold_with(folder)).collect::<SmallVec<[_; 8]>>();
folder.tcx().intern_goals(&v)
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
self.iter().any(|t| t.visit_with(visitor))
}
}
impl<'tcx> TypeFoldable<'tcx> for traits::Goal<'tcx> {
fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
let v = (**self).fold_with(folder);
folder.tcx().mk_goal(v)
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
(**self).visit_with(visitor)
}
}
CloneTypeFoldableAndLiftImpls! {
traits::ProgramClauseCategory,
}
impl<'tcx> TypeFoldable<'tcx> for traits::Clauses<'tcx> {
fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
let v = self.iter().map(|t| t.fold_with(folder)).collect::<SmallVec<[_; 8]>>();
folder.tcx().intern_clauses(&v)
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
self.iter().any(|t| t.visit_with(visitor))
}
}
impl<'tcx, C> TypeFoldable<'tcx> for chalk_engine::ExClause<C>
where
C: traits::ExClauseFold<'tcx>,
C::Substitution: Clone,
C::RegionConstraint: Clone,
{
fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
<C as traits::ExClauseFold>::fold_ex_clause_with(self, folder)
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
<C as traits::ExClauseFold>::visit_ex_clause_with(self, visitor)
}
}
EnumTypeFoldableImpl! {
impl<'tcx, C> TypeFoldable<'tcx> for chalk_engine::DelayedLiteral<C> {
(chalk_engine::DelayedLiteral::CannotProve)(a),
(chalk_engine::DelayedLiteral::Negative)(a),
(chalk_engine::DelayedLiteral::Positive)(a, b),
} where
C: chalk_engine::context::Context<CanonicalConstrainedSubst: TypeFoldable<'tcx>> + Clone,
}
EnumTypeFoldableImpl! {
impl<'tcx, C> TypeFoldable<'tcx> for chalk_engine::Literal<C> {
(chalk_engine::Literal::Negative)(a),
(chalk_engine::Literal::Positive)(a),
} where
C: chalk_engine::context::Context<GoalInEnvironment: Clone + TypeFoldable<'tcx>> + Clone,
}
CloneTypeFoldableAndLiftImpls! {
chalk_engine::TableIndex,
}

View file

@ -0,0 +1,736 @@
//! Trait Resolution. See the [rustc guide] for more information on how this works.
//!
//! [rustc guide]: https://rust-lang.github.io/rustc-guide/traits/resolution.html
pub mod query;
pub mod select;
pub mod specialization_graph;
mod structural_impls;
use crate::mir::interpret::ErrorHandled;
use crate::ty::fold::{TypeFolder, TypeVisitor};
use crate::ty::subst::SubstsRef;
use crate::ty::{self, AdtKind, List, Ty, TyCtxt};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_span::{Span, DUMMY_SP};
use syntax::ast;
use std::fmt::Debug;
use std::rc::Rc;
pub use self::select::{EvaluationCache, EvaluationResult, OverflowError, SelectionCache};
pub use self::ObligationCauseCode::*;
pub use self::SelectionError::*;
pub use self::Vtable::*;
/// Depending on the stage of compilation, we want projection to be
/// more or less conservative.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, HashStable)]
pub enum Reveal {
/// At type-checking time, we refuse to project any associated
/// type that is marked `default`. Non-`default` ("final") types
/// are always projected. This is necessary in general for
/// soundness of specialization. However, we *could* allow
/// projections in fully-monomorphic cases. We choose not to,
/// because we prefer for `default type` to force the type
/// definition to be treated abstractly by any consumers of the
/// impl. Concretely, that means that the following example will
/// fail to compile:
///
/// ```
/// trait Assoc {
/// type Output;
/// }
///
/// impl<T> Assoc for T {
/// default type Output = bool;
/// }
///
/// fn main() {
/// let <() as Assoc>::Output = true;
/// }
/// ```
UserFacing,
/// At codegen time, all monomorphic projections will succeed.
/// Also, `impl Trait` is normalized to the concrete type,
/// which has to be already collected by type-checking.
///
/// NOTE: as `impl Trait`'s concrete type should *never*
/// be observable directly by the user, `Reveal::All`
/// should not be used by checks which may expose
/// type equality or type contents to the user.
/// There are some exceptions, e.g., around OIBITS and
/// transmute-checking, which expose some details, but
/// not the whole concrete type of the `impl Trait`.
All,
}
/// The reason why we incurred this obligation; used for error reporting.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct ObligationCause<'tcx> {
pub span: Span,
/// The ID of the fn body that triggered this obligation. This is
/// used for region obligations to determine the precise
/// environment in which the region obligation should be evaluated
/// (in particular, closures can add new assumptions). See the
/// field `region_obligations` of the `FulfillmentContext` for more
/// information.
pub body_id: hir::HirId,
pub code: ObligationCauseCode<'tcx>,
}
impl<'tcx> ObligationCause<'tcx> {
#[inline]
pub fn new(
span: Span,
body_id: hir::HirId,
code: ObligationCauseCode<'tcx>,
) -> ObligationCause<'tcx> {
ObligationCause { span, body_id, code }
}
pub fn misc(span: Span, body_id: hir::HirId) -> ObligationCause<'tcx> {
ObligationCause { span, body_id, code: MiscObligation }
}
pub fn dummy() -> ObligationCause<'tcx> {
ObligationCause { span: DUMMY_SP, body_id: hir::CRATE_HIR_ID, code: MiscObligation }
}
pub fn span(&self, tcx: TyCtxt<'tcx>) -> Span {
match self.code {
ObligationCauseCode::CompareImplMethodObligation { .. }
| ObligationCauseCode::MainFunctionType
| ObligationCauseCode::StartFunctionType => tcx.sess.source_map().def_span(self.span),
ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
arm_span,
..
}) => arm_span,
_ => self.span,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum ObligationCauseCode<'tcx> {
/// Not well classified or should be obvious from the span.
MiscObligation,
/// A slice or array is WF only if `T: Sized`.
SliceOrArrayElem,
/// A tuple is WF only if its middle elements are `Sized`.
TupleElem,
/// This is the trait reference from the given projection.
ProjectionWf(ty::ProjectionTy<'tcx>),
/// In an impl of trait `X` for type `Y`, type `Y` must
/// also implement all supertraits of `X`.
ItemObligation(DefId),
/// Like `ItemObligation`, but with extra detail on the source of the obligation.
BindingObligation(DefId, Span),
/// A type like `&'a T` is WF only if `T: 'a`.
ReferenceOutlivesReferent(Ty<'tcx>),
/// A type like `Box<Foo<'a> + 'b>` is WF only if `'b: 'a`.
ObjectTypeBound(Ty<'tcx>, ty::Region<'tcx>),
/// Obligation incurred due to an object cast.
ObjectCastObligation(/* Object type */ Ty<'tcx>),
/// Obligation incurred due to a coercion.
Coercion {
source: Ty<'tcx>,
target: Ty<'tcx>,
},
/// Various cases where expressions must be `Sized` / `Copy` / etc.
/// `L = X` implies that `L` is `Sized`.
AssignmentLhsSized,
/// `(x1, .., xn)` must be `Sized`.
TupleInitializerSized,
/// `S { ... }` must be `Sized`.
StructInitializerSized,
/// Type of each variable must be `Sized`.
VariableType(hir::HirId),
/// Argument type must be `Sized`.
SizedArgumentType,
/// Return type must be `Sized`.
SizedReturnType,
/// Yield type must be `Sized`.
SizedYieldType,
/// `[T, ..n]` implies that `T` must be `Copy`.
/// If `true`, suggest `const_in_array_repeat_expressions` feature flag.
RepeatVec(bool),
/// Types of fields (other than the last, except for packed structs) in a struct must be sized.
FieldSized {
adt_kind: AdtKind,
last: bool,
},
/// Constant expressions must be sized.
ConstSized,
/// `static` items must have `Sync` type.
SharedStatic,
BuiltinDerivedObligation(DerivedObligationCause<'tcx>),
ImplDerivedObligation(DerivedObligationCause<'tcx>),
/// Error derived when matching traits/impls; see ObligationCause for more details
CompareImplMethodObligation {
item_name: ast::Name,
impl_item_def_id: DefId,
trait_item_def_id: DefId,
},
/// Error derived when matching traits/impls; see ObligationCause for more details
CompareImplTypeObligation {
item_name: ast::Name,
impl_item_def_id: DefId,
trait_item_def_id: DefId,
},
/// Checking that this expression can be assigned where it needs to be
// FIXME(eddyb) #11161 is the original Expr required?
ExprAssignable,
/// Computing common supertype in the arms of a match expression
MatchExpressionArm(Box<MatchExpressionArmCause<'tcx>>),
/// Type error arising from type checking a pattern against an expected type.
Pattern {
/// The span of the scrutinee or type expression which caused the `root_ty` type.
span: Option<Span>,
/// The root expected type induced by a scrutinee or type expression.
root_ty: Ty<'tcx>,
/// Whether the `Span` came from an expression or a type expression.
origin_expr: bool,
},
/// Constants in patterns must have `Structural` type.
ConstPatternStructural,
/// Computing common supertype in an if expression
IfExpression(Box<IfExpressionCause>),
/// Computing common supertype of an if expression with no else counter-part
IfExpressionWithNoElse,
/// `main` has wrong type
MainFunctionType,
/// `start` has wrong type
StartFunctionType,
/// Intrinsic has wrong type
IntrinsicType,
/// Method receiver
MethodReceiver,
/// `return` with no expression
ReturnNoExpression,
/// `return` with an expression
ReturnValue(hir::HirId),
/// Return type of this function
ReturnType,
/// Block implicit return
BlockTailExpression(hir::HirId),
/// #[feature(trivial_bounds)] is not enabled
TrivialBound,
AssocTypeBound(Box<AssocTypeBoundData>),
}
impl ObligationCauseCode<'_> {
// Return the base obligation, ignoring derived obligations.
pub fn peel_derives(&self) -> &Self {
let mut base_cause = self;
while let BuiltinDerivedObligation(cause) | ImplDerivedObligation(cause) = base_cause {
base_cause = &cause.parent_code;
}
base_cause
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct AssocTypeBoundData {
pub impl_span: Option<Span>,
pub original: Span,
pub bounds: Vec<Span>,
}
// `ObligationCauseCode` is used a lot. Make sure it doesn't unintentionally get bigger.
#[cfg(target_arch = "x86_64")]
static_assert_size!(ObligationCauseCode<'_>, 32);
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct MatchExpressionArmCause<'tcx> {
pub arm_span: Span,
pub source: hir::MatchSource,
pub prior_arms: Vec<Span>,
pub last_ty: Ty<'tcx>,
pub scrut_hir_id: hir::HirId,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct IfExpressionCause {
pub then: Span,
pub outer: Option<Span>,
pub semicolon: Option<Span>,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct DerivedObligationCause<'tcx> {
/// The trait reference of the parent obligation that led to the
/// current obligation. Note that only trait obligations lead to
/// derived obligations, so we just store the trait reference here
/// directly.
pub parent_trait_ref: ty::PolyTraitRef<'tcx>,
/// The parent trait had this cause.
pub parent_code: Rc<ObligationCauseCode<'tcx>>,
}
/// The following types:
/// * `WhereClause`,
/// * `WellFormed`,
/// * `FromEnv`,
/// * `DomainGoal`,
/// * `Goal`,
/// * `Clause`,
/// * `Environment`,
/// * `InEnvironment`,
/// are used for representing the trait system in the form of
/// logic programming clauses. They are part of the interface
/// for the chalk SLG solver.
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable, Lift)]
pub enum WhereClause<'tcx> {
Implemented(ty::TraitPredicate<'tcx>),
ProjectionEq(ty::ProjectionPredicate<'tcx>),
RegionOutlives(ty::RegionOutlivesPredicate<'tcx>),
TypeOutlives(ty::TypeOutlivesPredicate<'tcx>),
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable, Lift)]
pub enum WellFormed<'tcx> {
Trait(ty::TraitPredicate<'tcx>),
Ty(Ty<'tcx>),
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable, Lift)]
pub enum FromEnv<'tcx> {
Trait(ty::TraitPredicate<'tcx>),
Ty(Ty<'tcx>),
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable, Lift)]
pub enum DomainGoal<'tcx> {
Holds(WhereClause<'tcx>),
WellFormed(WellFormed<'tcx>),
FromEnv(FromEnv<'tcx>),
Normalize(ty::ProjectionPredicate<'tcx>),
}
pub type PolyDomainGoal<'tcx> = ty::Binder<DomainGoal<'tcx>>;
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable)]
pub enum QuantifierKind {
Universal,
Existential,
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable, Lift)]
pub enum GoalKind<'tcx> {
Implies(Clauses<'tcx>, Goal<'tcx>),
And(Goal<'tcx>, Goal<'tcx>),
Not(Goal<'tcx>),
DomainGoal(DomainGoal<'tcx>),
Quantified(QuantifierKind, ty::Binder<Goal<'tcx>>),
Subtype(Ty<'tcx>, Ty<'tcx>),
CannotProve,
}
pub type Goal<'tcx> = &'tcx GoalKind<'tcx>;
pub type Goals<'tcx> = &'tcx List<Goal<'tcx>>;
impl<'tcx> DomainGoal<'tcx> {
pub fn into_goal(self) -> GoalKind<'tcx> {
GoalKind::DomainGoal(self)
}
pub fn into_program_clause(self) -> ProgramClause<'tcx> {
ProgramClause {
goal: self,
hypotheses: ty::List::empty(),
category: ProgramClauseCategory::Other,
}
}
}
impl<'tcx> GoalKind<'tcx> {
pub fn from_poly_domain_goal(
domain_goal: PolyDomainGoal<'tcx>,
tcx: TyCtxt<'tcx>,
) -> GoalKind<'tcx> {
match domain_goal.no_bound_vars() {
Some(p) => p.into_goal(),
None => GoalKind::Quantified(
QuantifierKind::Universal,
domain_goal.map_bound(|p| tcx.mk_goal(p.into_goal())),
),
}
}
}
/// This matches the definition from Page 7 of "A Proof Procedure for the Logic of Hereditary
/// Harrop Formulas".
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable)]
pub enum Clause<'tcx> {
Implies(ProgramClause<'tcx>),
ForAll(ty::Binder<ProgramClause<'tcx>>),
}
impl Clause<'tcx> {
pub fn category(self) -> ProgramClauseCategory {
match self {
Clause::Implies(clause) => clause.category,
Clause::ForAll(clause) => clause.skip_binder().category,
}
}
}
/// Multiple clauses.
pub type Clauses<'tcx> = &'tcx List<Clause<'tcx>>;
/// A "program clause" has the form `D :- G1, ..., Gn`. It is saying
/// that the domain goal `D` is true if `G1...Gn` are provable. This
/// is equivalent to the implication `G1..Gn => D`; we usually write
/// it with the reverse implication operator `:-` to emphasize the way
/// that programs are actually solved (via backchaining, which starts
/// with the goal to solve and proceeds from there).
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable)]
pub struct ProgramClause<'tcx> {
/// This goal will be considered true ...
pub goal: DomainGoal<'tcx>,
/// ... if we can prove these hypotheses (there may be no hypotheses at all):
pub hypotheses: Goals<'tcx>,
/// Useful for filtering clauses.
pub category: ProgramClauseCategory,
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable)]
pub enum ProgramClauseCategory {
ImpliedBound,
WellFormed,
Other,
}
/// A set of clauses that we assume to be true.
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable)]
pub struct Environment<'tcx> {
pub clauses: Clauses<'tcx>,
}
impl Environment<'tcx> {
pub fn with<G>(self, goal: G) -> InEnvironment<'tcx, G> {
InEnvironment { environment: self, goal }
}
}
/// Something (usually a goal), along with an environment.
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable)]
pub struct InEnvironment<'tcx, G> {
pub environment: Environment<'tcx>,
pub goal: G,
}
#[derive(Clone, Debug, TypeFoldable)]
pub enum SelectionError<'tcx> {
Unimplemented,
OutputTypeParameterMismatch(
ty::PolyTraitRef<'tcx>,
ty::PolyTraitRef<'tcx>,
ty::error::TypeError<'tcx>,
),
TraitNotObjectSafe(DefId),
ConstEvalFailure(ErrorHandled),
Overflow,
}
/// When performing resolution, it is typically the case that there
/// can be one of three outcomes:
///
/// - `Ok(Some(r))`: success occurred with result `r`
/// - `Ok(None)`: could not definitely determine anything, usually due
/// to inconclusive type inference.
/// - `Err(e)`: error `e` occurred
pub type SelectionResult<'tcx, T> = Result<Option<T>, SelectionError<'tcx>>;
/// Given the successful resolution of an obligation, the `Vtable`
/// indicates where the vtable comes from. Note that while we call this
/// a "vtable", it does not necessarily indicate dynamic dispatch at
/// runtime. `Vtable` instances just tell the compiler where to find
/// methods, but in generic code those methods are typically statically
/// dispatched -- only when an object is constructed is a `Vtable`
/// instance reified into an actual vtable.
///
/// For example, the vtable may be tied to a specific impl (case A),
/// or it may be relative to some bound that is in scope (case B).
///
/// ```
/// impl<T:Clone> Clone<T> for Option<T> { ... } // Impl_1
/// impl<T:Clone> Clone<T> for Box<T> { ... } // Impl_2
/// impl Clone for int { ... } // Impl_3
///
/// fn foo<T:Clone>(concrete: Option<Box<int>>,
/// param: T,
/// mixed: Option<T>) {
///
/// // Case A: Vtable points at a specific impl. Only possible when
/// // type is concretely known. If the impl itself has bounded
/// // type parameters, Vtable will carry resolutions for those as well:
/// concrete.clone(); // Vtable(Impl_1, [Vtable(Impl_2, [Vtable(Impl_3)])])
///
/// // Case B: Vtable must be provided by caller. This applies when
/// // type is a type parameter.
/// param.clone(); // VtableParam
///
/// // Case C: A mix of cases A and B.
/// mixed.clone(); // Vtable(Impl_1, [VtableParam])
/// }
/// ```
///
/// ### The type parameter `N`
///
/// See explanation on `VtableImplData`.
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
pub enum Vtable<'tcx, N> {
/// Vtable identifying a particular impl.
VtableImpl(VtableImplData<'tcx, N>),
/// Vtable for auto trait implementations.
/// This carries the information and nested obligations with regards
/// to an auto implementation for a trait `Trait`. The nested obligations
/// ensure the trait implementation holds for all the constituent types.
VtableAutoImpl(VtableAutoImplData<N>),
/// Successful resolution to an obligation provided by the caller
/// for some type parameter. The `Vec<N>` represents the
/// obligations incurred from normalizing the where-clause (if
/// any).
VtableParam(Vec<N>),
/// Virtual calls through an object.
VtableObject(VtableObjectData<'tcx, N>),
/// Successful resolution for a builtin trait.
VtableBuiltin(VtableBuiltinData<N>),
/// Vtable automatically generated for a closure. The `DefId` is the ID
/// of the closure expression. This is a `VtableImpl` in spirit, but the
/// impl is generated by the compiler and does not appear in the source.
VtableClosure(VtableClosureData<'tcx, N>),
/// Same as above, but for a function pointer type with the given signature.
VtableFnPointer(VtableFnPointerData<'tcx, N>),
/// Vtable automatically generated for a generator.
VtableGenerator(VtableGeneratorData<'tcx, N>),
/// Vtable for a trait alias.
VtableTraitAlias(VtableTraitAliasData<'tcx, N>),
}
impl<'tcx, N> Vtable<'tcx, N> {
pub fn nested_obligations(self) -> Vec<N> {
match self {
VtableImpl(i) => i.nested,
VtableParam(n) => n,
VtableBuiltin(i) => i.nested,
VtableAutoImpl(d) => d.nested,
VtableClosure(c) => c.nested,
VtableGenerator(c) => c.nested,
VtableObject(d) => d.nested,
VtableFnPointer(d) => d.nested,
VtableTraitAlias(d) => d.nested,
}
}
pub fn map<M, F>(self, f: F) -> Vtable<'tcx, M>
where
F: FnMut(N) -> M,
{
match self {
VtableImpl(i) => VtableImpl(VtableImplData {
impl_def_id: i.impl_def_id,
substs: i.substs,
nested: i.nested.into_iter().map(f).collect(),
}),
VtableParam(n) => VtableParam(n.into_iter().map(f).collect()),
VtableBuiltin(i) => {
VtableBuiltin(VtableBuiltinData { nested: i.nested.into_iter().map(f).collect() })
}
VtableObject(o) => VtableObject(VtableObjectData {
upcast_trait_ref: o.upcast_trait_ref,
vtable_base: o.vtable_base,
nested: o.nested.into_iter().map(f).collect(),
}),
VtableAutoImpl(d) => VtableAutoImpl(VtableAutoImplData {
trait_def_id: d.trait_def_id,
nested: d.nested.into_iter().map(f).collect(),
}),
VtableClosure(c) => VtableClosure(VtableClosureData {
closure_def_id: c.closure_def_id,
substs: c.substs,
nested: c.nested.into_iter().map(f).collect(),
}),
VtableGenerator(c) => VtableGenerator(VtableGeneratorData {
generator_def_id: c.generator_def_id,
substs: c.substs,
nested: c.nested.into_iter().map(f).collect(),
}),
VtableFnPointer(p) => VtableFnPointer(VtableFnPointerData {
fn_ty: p.fn_ty,
nested: p.nested.into_iter().map(f).collect(),
}),
VtableTraitAlias(d) => VtableTraitAlias(VtableTraitAliasData {
alias_def_id: d.alias_def_id,
substs: d.substs,
nested: d.nested.into_iter().map(f).collect(),
}),
}
}
}
/// Identifies a particular impl in the source, along with a set of
/// substitutions from the impl's type/lifetime parameters. The
/// `nested` vector corresponds to the nested obligations attached to
/// the impl's type parameters.
///
/// The type parameter `N` indicates the type used for "nested
/// obligations" that are required by the impl. During type-check, this
/// is `Obligation`, as one might expect. During codegen, however, this
/// is `()`, because codegen only requires a shallow resolution of an
/// impl, and nested obligations are satisfied later.
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
pub struct VtableImplData<'tcx, N> {
pub impl_def_id: DefId,
pub substs: SubstsRef<'tcx>,
pub nested: Vec<N>,
}
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
pub struct VtableGeneratorData<'tcx, N> {
pub generator_def_id: DefId,
pub substs: SubstsRef<'tcx>,
/// Nested obligations. This can be non-empty if the generator
/// signature contains associated types.
pub nested: Vec<N>,
}
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
pub struct VtableClosureData<'tcx, N> {
pub closure_def_id: DefId,
pub substs: SubstsRef<'tcx>,
/// Nested obligations. This can be non-empty if the closure
/// signature contains associated types.
pub nested: Vec<N>,
}
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
pub struct VtableAutoImplData<N> {
pub trait_def_id: DefId,
pub nested: Vec<N>,
}
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
pub struct VtableBuiltinData<N> {
pub nested: Vec<N>,
}
/// A vtable for some object-safe trait `Foo` automatically derived
/// for the object type `Foo`.
#[derive(PartialEq, Eq, Clone, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
pub struct VtableObjectData<'tcx, N> {
/// `Foo` upcast to the obligation trait. This will be some supertrait of `Foo`.
pub upcast_trait_ref: ty::PolyTraitRef<'tcx>,
/// The vtable is formed by concatenating together the method lists of
/// the base object trait and all supertraits; this is the start of
/// `upcast_trait_ref`'s methods in that vtable.
pub vtable_base: usize,
pub nested: Vec<N>,
}
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
pub struct VtableFnPointerData<'tcx, N> {
pub fn_ty: Ty<'tcx>,
pub nested: Vec<N>,
}
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, HashStable, TypeFoldable)]
pub struct VtableTraitAliasData<'tcx, N> {
pub alias_def_id: DefId,
pub substs: SubstsRef<'tcx>,
pub nested: Vec<N>,
}
pub trait ExClauseFold<'tcx>
where
Self: chalk_engine::context::Context + Clone,
{
fn fold_ex_clause_with<F: TypeFolder<'tcx>>(
ex_clause: &chalk_engine::ExClause<Self>,
folder: &mut F,
) -> chalk_engine::ExClause<Self>;
fn visit_ex_clause_with<V: TypeVisitor<'tcx>>(
ex_clause: &chalk_engine::ExClause<Self>,
visitor: &mut V,
) -> bool;
}
pub trait ChalkContextLift<'tcx>
where
Self: chalk_engine::context::Context + Clone,
{
type LiftedExClause: Debug + 'tcx;
type LiftedDelayedLiteral: Debug + 'tcx;
type LiftedLiteral: Debug + 'tcx;
fn lift_ex_clause_to_tcx(
ex_clause: &chalk_engine::ExClause<Self>,
tcx: TyCtxt<'tcx>,
) -> Option<Self::LiftedExClause>;
fn lift_delayed_literal_to_tcx(
ex_clause: &chalk_engine::DelayedLiteral<Self>,
tcx: TyCtxt<'tcx>,
) -> Option<Self::LiftedDelayedLiteral>;
fn lift_literal_to_tcx(
ex_clause: &chalk_engine::Literal<Self>,
tcx: TyCtxt<'tcx>,
) -> Option<Self::LiftedLiteral>;
}

View file

@ -0,0 +1,332 @@
//! Experimental types for the trait query interface. The methods
//! defined in this module are all based on **canonicalization**,
//! which makes a canonical query by replacing unbound inference
//! variables and regions, so that results can be reused more broadly.
//! The providers for the queries defined here can be found in
//! `librustc_traits`.
use crate::ich::StableHashingContext;
use crate::infer::canonical::{Canonical, QueryResponse};
use crate::ty::error::TypeError;
use crate::ty::subst::GenericArg;
use crate::ty::{self, Ty, TyCtxt};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::sync::Lrc;
use rustc_errors::struct_span_err;
use rustc_span::source_map::Span;
use std::iter::FromIterator;
use std::mem;
pub mod type_op {
use crate::ty::fold::TypeFoldable;
use crate::ty::subst::UserSubsts;
use crate::ty::{Predicate, Ty};
use rustc_hir::def_id::DefId;
use std::fmt;
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, Lift)]
pub struct AscribeUserType<'tcx> {
pub mir_ty: Ty<'tcx>,
pub def_id: DefId,
pub user_substs: UserSubsts<'tcx>,
}
impl<'tcx> AscribeUserType<'tcx> {
pub fn new(mir_ty: Ty<'tcx>, def_id: DefId, user_substs: UserSubsts<'tcx>) -> Self {
Self { mir_ty, def_id, user_substs }
}
}
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, Lift)]
pub struct Eq<'tcx> {
pub a: Ty<'tcx>,
pub b: Ty<'tcx>,
}
impl<'tcx> Eq<'tcx> {
pub fn new(a: Ty<'tcx>, b: Ty<'tcx>) -> Self {
Self { a, b }
}
}
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, Lift)]
pub struct Subtype<'tcx> {
pub sub: Ty<'tcx>,
pub sup: Ty<'tcx>,
}
impl<'tcx> Subtype<'tcx> {
pub fn new(sub: Ty<'tcx>, sup: Ty<'tcx>) -> Self {
Self { sub, sup }
}
}
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, Lift)]
pub struct ProvePredicate<'tcx> {
pub predicate: Predicate<'tcx>,
}
impl<'tcx> ProvePredicate<'tcx> {
pub fn new(predicate: Predicate<'tcx>) -> Self {
ProvePredicate { predicate }
}
}
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable, TypeFoldable, Lift)]
pub struct Normalize<T> {
pub value: T,
}
impl<'tcx, T> Normalize<T>
where
T: fmt::Debug + TypeFoldable<'tcx>,
{
pub fn new(value: T) -> Self {
Self { value }
}
}
}
pub type CanonicalProjectionGoal<'tcx> =
Canonical<'tcx, ty::ParamEnvAnd<'tcx, ty::ProjectionTy<'tcx>>>;
pub type CanonicalTyGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, Ty<'tcx>>>;
pub type CanonicalPredicateGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, ty::Predicate<'tcx>>>;
pub type CanonicalTypeOpAscribeUserTypeGoal<'tcx> =
Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::AscribeUserType<'tcx>>>;
pub type CanonicalTypeOpEqGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Eq<'tcx>>>;
pub type CanonicalTypeOpSubtypeGoal<'tcx> =
Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Subtype<'tcx>>>;
pub type CanonicalTypeOpProvePredicateGoal<'tcx> =
Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::ProvePredicate<'tcx>>>;
pub type CanonicalTypeOpNormalizeGoal<'tcx, T> =
Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Normalize<T>>>;
#[derive(Clone, Debug, HashStable)]
pub struct NoSolution;
pub type Fallible<T> = Result<T, NoSolution>;
impl<'tcx> From<TypeError<'tcx>> for NoSolution {
fn from(_: TypeError<'tcx>) -> NoSolution {
NoSolution
}
}
#[derive(Clone, Debug, Default, HashStable, TypeFoldable, Lift)]
pub struct DropckOutlivesResult<'tcx> {
pub kinds: Vec<GenericArg<'tcx>>,
pub overflows: Vec<Ty<'tcx>>,
}
impl<'tcx> DropckOutlivesResult<'tcx> {
pub fn report_overflows(&self, tcx: TyCtxt<'tcx>, span: Span, ty: Ty<'tcx>) {
if let Some(overflow_ty) = self.overflows.iter().next() {
let mut err = struct_span_err!(
tcx.sess,
span,
E0320,
"overflow while adding drop-check rules for {}",
ty,
);
err.note(&format!("overflowed on {}", overflow_ty));
err.emit();
}
}
pub fn into_kinds_reporting_overflows(
self,
tcx: TyCtxt<'tcx>,
span: Span,
ty: Ty<'tcx>,
) -> Vec<GenericArg<'tcx>> {
self.report_overflows(tcx, span, ty);
let DropckOutlivesResult { kinds, overflows: _ } = self;
kinds
}
}
/// A set of constraints that need to be satisfied in order for
/// a type to be valid for destruction.
#[derive(Clone, Debug, HashStable)]
pub struct DtorckConstraint<'tcx> {
/// Types that are required to be alive in order for this
/// type to be valid for destruction.
pub outlives: Vec<ty::subst::GenericArg<'tcx>>,
/// Types that could not be resolved: projections and params.
pub dtorck_types: Vec<Ty<'tcx>>,
/// If, during the computation of the dtorck constraint, we
/// overflow, that gets recorded here. The caller is expected to
/// report an error.
pub overflows: Vec<Ty<'tcx>>,
}
impl<'tcx> DtorckConstraint<'tcx> {
pub fn empty() -> DtorckConstraint<'tcx> {
DtorckConstraint { outlives: vec![], dtorck_types: vec![], overflows: vec![] }
}
}
impl<'tcx> FromIterator<DtorckConstraint<'tcx>> for DtorckConstraint<'tcx> {
fn from_iter<I: IntoIterator<Item = DtorckConstraint<'tcx>>>(iter: I) -> Self {
let mut result = Self::empty();
for DtorckConstraint { outlives, dtorck_types, overflows } in iter {
result.outlives.extend(outlives);
result.dtorck_types.extend(dtorck_types);
result.overflows.extend(overflows);
}
result
}
}
/// This returns true if the type `ty` is "trivial" for
/// dropck-outlives -- that is, if it doesn't require any types to
/// outlive. This is similar but not *quite* the same as the
/// `needs_drop` test in the compiler already -- that is, for every
/// type T for which this function return true, needs-drop would
/// return `false`. But the reverse does not hold: in particular,
/// `needs_drop` returns false for `PhantomData`, but it is not
/// trivial for dropck-outlives.
///
/// Note also that `needs_drop` requires a "global" type (i.e., one
/// with erased regions), but this function does not.
pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
match ty.kind {
// None of these types have a destructor and hence they do not
// require anything in particular to outlive the dtor's
// execution.
ty::Infer(ty::FreshIntTy(_))
| ty::Infer(ty::FreshFloatTy(_))
| ty::Bool
| ty::Int(_)
| ty::Uint(_)
| ty::Float(_)
| ty::Never
| ty::FnDef(..)
| ty::FnPtr(_)
| ty::Char
| ty::GeneratorWitness(..)
| ty::RawPtr(_)
| ty::Ref(..)
| ty::Str
| ty::Foreign(..)
| ty::Error => true,
// [T; N] and [T] have same properties as T.
ty::Array(ty, _) | ty::Slice(ty) => trivial_dropck_outlives(tcx, ty),
// (T1..Tn) and closures have same properties as T1..Tn --
// check if *any* of those are trivial.
ty::Tuple(ref tys) => tys.iter().all(|t| trivial_dropck_outlives(tcx, t.expect_ty())),
ty::Closure(def_id, ref substs) => {
substs.as_closure().upvar_tys(def_id, tcx).all(|t| trivial_dropck_outlives(tcx, t))
}
ty::Adt(def, _) => {
if Some(def.did) == tcx.lang_items().manually_drop() {
// `ManuallyDrop` never has a dtor.
true
} else {
// Other types might. Moreover, PhantomData doesn't
// have a dtor, but it is considered to own its
// content, so it is non-trivial. Unions can have `impl Drop`,
// and hence are non-trivial as well.
false
}
}
// The following *might* require a destructor: needs deeper inspection.
ty::Dynamic(..)
| ty::Projection(..)
| ty::Param(_)
| ty::Opaque(..)
| ty::Placeholder(..)
| ty::Infer(_)
| ty::Bound(..)
| ty::Generator(..) => false,
ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"),
}
}
#[derive(Debug, HashStable)]
pub struct CandidateStep<'tcx> {
pub self_ty: Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>,
pub autoderefs: usize,
/// `true` if the type results from a dereference of a raw pointer.
/// when assembling candidates, we include these steps, but not when
/// picking methods. This so that if we have `foo: *const Foo` and `Foo` has methods
/// `fn by_raw_ptr(self: *const Self)` and `fn by_ref(&self)`, then
/// `foo.by_raw_ptr()` will work and `foo.by_ref()` won't.
pub from_unsafe_deref: bool,
pub unsize: bool,
}
#[derive(Clone, Debug, HashStable)]
pub struct MethodAutoderefStepsResult<'tcx> {
/// The valid autoderef steps that could be find.
pub steps: Lrc<Vec<CandidateStep<'tcx>>>,
/// If Some(T), a type autoderef reported an error on.
pub opt_bad_ty: Option<Lrc<MethodAutoderefBadTy<'tcx>>>,
/// If `true`, `steps` has been truncated due to reaching the
/// recursion limit.
pub reached_recursion_limit: bool,
}
#[derive(Debug, HashStable)]
pub struct MethodAutoderefBadTy<'tcx> {
pub reached_raw_pointer: bool,
pub ty: Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>,
}
/// Result from the `normalize_projection_ty` query.
#[derive(Clone, Debug, HashStable, TypeFoldable, Lift)]
pub struct NormalizationResult<'tcx> {
/// Result of normalization.
pub normalized_ty: Ty<'tcx>,
}
/// Outlives bounds are relationships between generic parameters,
/// whether they both be regions (`'a: 'b`) or whether types are
/// involved (`T: 'a`). These relationships can be extracted from the
/// full set of predicates we understand or also from types (in which
/// case they are called implied bounds). They are fed to the
/// `OutlivesEnv` which in turn is supplied to the region checker and
/// other parts of the inference system.
#[derive(Clone, Debug, TypeFoldable, Lift)]
pub enum OutlivesBound<'tcx> {
RegionSubRegion(ty::Region<'tcx>, ty::Region<'tcx>),
RegionSubParam(ty::Region<'tcx>, ty::ParamTy),
RegionSubProjection(ty::Region<'tcx>, ty::ProjectionTy<'tcx>),
}
impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for OutlivesBound<'tcx> {
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
mem::discriminant(self).hash_stable(hcx, hasher);
match *self {
OutlivesBound::RegionSubRegion(ref a, ref b) => {
a.hash_stable(hcx, hasher);
b.hash_stable(hcx, hasher);
}
OutlivesBound::RegionSubParam(ref a, ref b) => {
a.hash_stable(hcx, hasher);
b.hash_stable(hcx, hasher);
}
OutlivesBound::RegionSubProjection(ref a, ref b) => {
a.hash_stable(hcx, hasher);
b.hash_stable(hcx, hasher);
}
}
}
}

View file

@ -0,0 +1,290 @@
//! Candidate selection. See the [rustc guide] for more information on how this works.
//!
//! [rustc guide]: https://rust-lang.github.io/rustc-guide/traits/resolution.html#selection
use self::EvaluationResult::*;
use super::{SelectionError, SelectionResult};
use crate::dep_graph::DepNodeIndex;
use crate::ty::{self, TyCtxt};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync::Lock;
use rustc_hir::def_id::DefId;
#[derive(Clone, Default)]
pub struct SelectionCache<'tcx> {
pub hashmap: Lock<
FxHashMap<
ty::ParamEnvAnd<'tcx, ty::TraitRef<'tcx>>,
WithDepNode<SelectionResult<'tcx, SelectionCandidate<'tcx>>>,
>,
>,
}
impl<'tcx> SelectionCache<'tcx> {
/// Actually frees the underlying memory in contrast to what stdlib containers do on `clear`
pub fn clear(&self) {
*self.hashmap.borrow_mut() = Default::default();
}
}
/// The selection process begins by considering all impls, where
/// clauses, and so forth that might resolve an obligation. Sometimes
/// we'll be able to say definitively that (e.g.) an impl does not
/// apply to the obligation: perhaps it is defined for `usize` but the
/// obligation is for `int`. In that case, we drop the impl out of the
/// list. But the other cases are considered *candidates*.
///
/// For selection to succeed, there must be exactly one matching
/// candidate. If the obligation is fully known, this is guaranteed
/// by coherence. However, if the obligation contains type parameters
/// or variables, there may be multiple such impls.
///
/// It is not a real problem if multiple matching impls exist because
/// of type variables - it just means the obligation isn't sufficiently
/// elaborated. In that case we report an ambiguity, and the caller can
/// try again after more type information has been gathered or report a
/// "type annotations needed" error.
///
/// However, with type parameters, this can be a real problem - type
/// parameters don't unify with regular types, but they *can* unify
/// with variables from blanket impls, and (unless we know its bounds
/// will always be satisfied) picking the blanket impl will be wrong
/// for at least *some* substitutions. To make this concrete, if we have
///
/// trait AsDebug { type Out : fmt::Debug; fn debug(self) -> Self::Out; }
/// impl<T: fmt::Debug> AsDebug for T {
/// type Out = T;
/// fn debug(self) -> fmt::Debug { self }
/// }
/// fn foo<T: AsDebug>(t: T) { println!("{:?}", <T as AsDebug>::debug(t)); }
///
/// we can't just use the impl to resolve the `<T as AsDebug>` obligation
/// -- a type from another crate (that doesn't implement `fmt::Debug`) could
/// implement `AsDebug`.
///
/// Because where-clauses match the type exactly, multiple clauses can
/// only match if there are unresolved variables, and we can mostly just
/// report this ambiguity in that case. This is still a problem - we can't
/// *do anything* with ambiguities that involve only regions. This is issue
/// #21974.
///
/// If a single where-clause matches and there are no inference
/// variables left, then it definitely matches and we can just select
/// it.
///
/// In fact, we even select the where-clause when the obligation contains
/// inference variables. The can lead to inference making "leaps of logic",
/// for example in this situation:
///
/// pub trait Foo<T> { fn foo(&self) -> T; }
/// impl<T> Foo<()> for T { fn foo(&self) { } }
/// impl Foo<bool> for bool { fn foo(&self) -> bool { *self } }
///
/// pub fn foo<T>(t: T) where T: Foo<bool> {
/// println!("{:?}", <T as Foo<_>>::foo(&t));
/// }
/// fn main() { foo(false); }
///
/// Here the obligation `<T as Foo<$0>>` can be matched by both the blanket
/// impl and the where-clause. We select the where-clause and unify `$0=bool`,
/// so the program prints "false". However, if the where-clause is omitted,
/// the blanket impl is selected, we unify `$0=()`, and the program prints
/// "()".
///
/// Exactly the same issues apply to projection and object candidates, except
/// that we can have both a projection candidate and a where-clause candidate
/// for the same obligation. In that case either would do (except that
/// different "leaps of logic" would occur if inference variables are
/// present), and we just pick the where-clause. This is, for example,
/// required for associated types to work in default impls, as the bounds
/// are visible both as projection bounds and as where-clauses from the
/// parameter environment.
#[derive(PartialEq, Eq, Debug, Clone, TypeFoldable)]
pub enum SelectionCandidate<'tcx> {
BuiltinCandidate {
/// `false` if there are no *further* obligations.
has_nested: bool,
},
ParamCandidate(ty::PolyTraitRef<'tcx>),
ImplCandidate(DefId),
AutoImplCandidate(DefId),
/// This is a trait matching with a projected type as `Self`, and
/// we found an applicable bound in the trait definition.
ProjectionCandidate,
/// Implementation of a `Fn`-family trait by one of the anonymous types
/// generated for a `||` expression.
ClosureCandidate,
/// Implementation of a `Generator` trait by one of the anonymous types
/// generated for a generator.
GeneratorCandidate,
/// Implementation of a `Fn`-family trait by one of the anonymous
/// types generated for a fn pointer type (e.g., `fn(int) -> int`)
FnPointerCandidate,
TraitAliasCandidate(DefId),
ObjectCandidate,
BuiltinObjectCandidate,
BuiltinUnsizeCandidate,
}
/// The result of trait evaluation. The order is important
/// here as the evaluation of a list is the maximum of the
/// evaluations.
///
/// The evaluation results are ordered:
/// - `EvaluatedToOk` implies `EvaluatedToOkModuloRegions`
/// implies `EvaluatedToAmbig` implies `EvaluatedToUnknown`
/// - `EvaluatedToErr` implies `EvaluatedToRecur`
/// - the "union" of evaluation results is equal to their maximum -
/// all the "potential success" candidates can potentially succeed,
/// so they are noops when unioned with a definite error, and within
/// the categories it's easy to see that the unions are correct.
#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq, HashStable)]
pub enum EvaluationResult {
/// Evaluation successful.
EvaluatedToOk,
/// Evaluation successful, but there were unevaluated region obligations.
EvaluatedToOkModuloRegions,
/// Evaluation is known to be ambiguous -- it *might* hold for some
/// assignment of inference variables, but it might not.
///
/// While this has the same meaning as `EvaluatedToUnknown` -- we can't
/// know whether this obligation holds or not -- it is the result we
/// would get with an empty stack, and therefore is cacheable.
EvaluatedToAmbig,
/// Evaluation failed because of recursion involving inference
/// variables. We are somewhat imprecise there, so we don't actually
/// know the real result.
///
/// This can't be trivially cached for the same reason as `EvaluatedToRecur`.
EvaluatedToUnknown,
/// Evaluation failed because we encountered an obligation we are already
/// trying to prove on this branch.
///
/// We know this branch can't be a part of a minimal proof-tree for
/// the "root" of our cycle, because then we could cut out the recursion
/// and maintain a valid proof tree. However, this does not mean
/// that all the obligations on this branch do not hold -- it's possible
/// that we entered this branch "speculatively", and that there
/// might be some other way to prove this obligation that does not
/// go through this cycle -- so we can't cache this as a failure.
///
/// For example, suppose we have this:
///
/// ```rust,ignore (pseudo-Rust)
/// pub trait Trait { fn xyz(); }
/// // This impl is "useless", but we can still have
/// // an `impl Trait for SomeUnsizedType` somewhere.
/// impl<T: Trait + Sized> Trait for T { fn xyz() {} }
///
/// pub fn foo<T: Trait + ?Sized>() {
/// <T as Trait>::xyz();
/// }
/// ```
///
/// When checking `foo`, we have to prove `T: Trait`. This basically
/// translates into this:
///
/// ```plain,ignore
/// (T: Trait + Sized →_\impl T: Trait), T: Trait ⊢ T: Trait
/// ```
///
/// When we try to prove it, we first go the first option, which
/// recurses. This shows us that the impl is "useless" -- it won't
/// tell us that `T: Trait` unless it already implemented `Trait`
/// by some other means. However, that does not prevent `T: Trait`
/// does not hold, because of the bound (which can indeed be satisfied
/// by `SomeUnsizedType` from another crate).
//
// FIXME: when an `EvaluatedToRecur` goes past its parent root, we
// ought to convert it to an `EvaluatedToErr`, because we know
// there definitely isn't a proof tree for that obligation. Not
// doing so is still sound -- there isn't any proof tree, so the
// branch still can't be a part of a minimal one -- but does not re-enable caching.
EvaluatedToRecur,
/// Evaluation failed.
EvaluatedToErr,
}
impl EvaluationResult {
/// Returns `true` if this evaluation result is known to apply, even
/// considering outlives constraints.
pub fn must_apply_considering_regions(self) -> bool {
self == EvaluatedToOk
}
/// Returns `true` if this evaluation result is known to apply, ignoring
/// outlives constraints.
pub fn must_apply_modulo_regions(self) -> bool {
self <= EvaluatedToOkModuloRegions
}
pub fn may_apply(self) -> bool {
match self {
EvaluatedToOk | EvaluatedToOkModuloRegions | EvaluatedToAmbig | EvaluatedToUnknown => {
true
}
EvaluatedToErr | EvaluatedToRecur => false,
}
}
pub fn is_stack_dependent(self) -> bool {
match self {
EvaluatedToUnknown | EvaluatedToRecur => true,
EvaluatedToOk | EvaluatedToOkModuloRegions | EvaluatedToAmbig | EvaluatedToErr => false,
}
}
}
/// Indicates that trait evaluation caused overflow.
#[derive(Copy, Clone, Debug, PartialEq, Eq, HashStable)]
pub struct OverflowError;
impl<'tcx> From<OverflowError> for SelectionError<'tcx> {
fn from(OverflowError: OverflowError) -> SelectionError<'tcx> {
SelectionError::Overflow
}
}
#[derive(Clone, Default)]
pub struct EvaluationCache<'tcx> {
pub hashmap: Lock<
FxHashMap<ty::ParamEnvAnd<'tcx, ty::PolyTraitRef<'tcx>>, WithDepNode<EvaluationResult>>,
>,
}
impl<'tcx> EvaluationCache<'tcx> {
/// Actually frees the underlying memory in contrast to what stdlib containers do on `clear`
pub fn clear(&self) {
*self.hashmap.borrow_mut() = Default::default();
}
}
#[derive(Clone, Eq, PartialEq)]
pub struct WithDepNode<T> {
dep_node: DepNodeIndex,
cached_value: T,
}
impl<T: Clone> WithDepNode<T> {
pub fn new(dep_node: DepNodeIndex, cached_value: T) -> Self {
WithDepNode { dep_node, cached_value }
}
pub fn get(&self, tcx: TyCtxt<'_>) -> T {
tcx.dep_graph.read_index(self.dep_node);
self.cached_value.clone()
}
}

View file

@ -0,0 +1,199 @@
use crate::ich::{self, StableHashingContext};
use crate::ty::fast_reject::SimplifiedType;
use crate::ty::{self, TyCtxt};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_hir::def_id::{DefId, DefIdMap};
use syntax::ast::Ident;
/// A per-trait graph of impls in specialization order. At the moment, this
/// graph forms a tree rooted with the trait itself, with all other nodes
/// representing impls, and parent-child relationships representing
/// specializations.
///
/// The graph provides two key services:
///
/// - Construction. This implicitly checks for overlapping impls (i.e., impls
/// that overlap but where neither specializes the other -- an artifact of the
/// simple "chain" rule.
///
/// - Parent extraction. In particular, the graph can give you the *immediate*
/// parents of a given specializing impl, which is needed for extracting
/// default items amongst other things. In the simple "chain" rule, every impl
/// has at most one parent.
#[derive(RustcEncodable, RustcDecodable, HashStable)]
pub struct Graph {
// All impls have a parent; the "root" impls have as their parent the `def_id`
// of the trait.
pub parent: DefIdMap<DefId>,
// The "root" impls are found by looking up the trait's def_id.
pub children: DefIdMap<Children>,
}
impl Graph {
pub fn new() -> Graph {
Graph { parent: Default::default(), children: Default::default() }
}
/// The parent of a given impl, which is the `DefId` of the trait when the
/// impl is a "specialization root".
pub fn parent(&self, child: DefId) -> DefId {
*self.parent.get(&child).unwrap_or_else(|| panic!("Failed to get parent for {:?}", child))
}
}
/// Children of a given impl, grouped into blanket/non-blanket varieties as is
/// done in `TraitDef`.
#[derive(Default, RustcEncodable, RustcDecodable)]
pub struct Children {
// Impls of a trait (or specializations of a given impl). To allow for
// quicker lookup, the impls are indexed by a simplified version of their
// `Self` type: impls with a simplifiable `Self` are stored in
// `nonblanket_impls` keyed by it, while all other impls are stored in
// `blanket_impls`.
//
// A similar division is used within `TraitDef`, but the lists there collect
// together *all* the impls for a trait, and are populated prior to building
// the specialization graph.
/// Impls of the trait.
pub nonblanket_impls: FxHashMap<SimplifiedType, Vec<DefId>>,
/// Blanket impls associated with the trait.
pub blanket_impls: Vec<DefId>,
}
/// A node in the specialization graph is either an impl or a trait
/// definition; either can serve as a source of item definitions.
/// There is always exactly one trait definition node: the root.
#[derive(Debug, Copy, Clone)]
pub enum Node {
Impl(DefId),
Trait(DefId),
}
impl<'tcx> Node {
pub fn is_from_trait(&self) -> bool {
match *self {
Node::Trait(..) => true,
_ => false,
}
}
/// Iterate over the items defined directly by the given (impl or trait) node.
pub fn items(&self, tcx: TyCtxt<'tcx>) -> ty::AssocItemsIterator<'tcx> {
tcx.associated_items(self.def_id())
}
/// Finds an associated item defined in this node.
///
/// If this returns `None`, the item can potentially still be found in
/// parents of this node.
pub fn item(
&self,
tcx: TyCtxt<'tcx>,
trait_item_name: Ident,
trait_item_kind: ty::AssocKind,
trait_def_id: DefId,
) -> Option<ty::AssocItem> {
use crate::ty::AssocKind::*;
tcx.associated_items(self.def_id()).find(move |impl_item| {
match (trait_item_kind, impl_item.kind) {
| (Const, Const)
| (Method, Method)
| (Type, Type)
| (Type, OpaqueTy) // assoc. types can be made opaque in impls
=> tcx.hygienic_eq(impl_item.ident, trait_item_name, trait_def_id),
| (Const, _)
| (Method, _)
| (Type, _)
| (OpaqueTy, _)
=> false,
}
})
}
pub fn def_id(&self) -> DefId {
match *self {
Node::Impl(did) => did,
Node::Trait(did) => did,
}
}
}
#[derive(Copy, Clone)]
pub struct Ancestors<'tcx> {
trait_def_id: DefId,
specialization_graph: &'tcx Graph,
current_source: Option<Node>,
}
impl Iterator for Ancestors<'_> {
type Item = Node;
fn next(&mut self) -> Option<Node> {
let cur = self.current_source.take();
if let Some(Node::Impl(cur_impl)) = cur {
let parent = self.specialization_graph.parent(cur_impl);
self.current_source = if parent == self.trait_def_id {
Some(Node::Trait(parent))
} else {
Some(Node::Impl(parent))
};
}
cur
}
}
pub struct NodeItem<T> {
pub node: Node,
pub item: T,
}
impl<T> NodeItem<T> {
pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> NodeItem<U> {
NodeItem { node: self.node, item: f(self.item) }
}
}
impl<'tcx> Ancestors<'tcx> {
/// Finds the bottom-most (ie. most specialized) definition of an associated
/// item.
pub fn leaf_def(
mut self,
tcx: TyCtxt<'tcx>,
trait_item_name: Ident,
trait_item_kind: ty::AssocKind,
) -> Option<NodeItem<ty::AssocItem>> {
let trait_def_id = self.trait_def_id;
self.find_map(|node| {
node.item(tcx, trait_item_name, trait_item_kind, trait_def_id)
.map(|item| NodeItem { node, item })
})
}
}
/// Walk up the specialization ancestors of a given impl, starting with that
/// impl itself.
pub fn ancestors(
tcx: TyCtxt<'tcx>,
trait_def_id: DefId,
start_from_impl: DefId,
) -> Ancestors<'tcx> {
let specialization_graph = tcx.specialization_graph_of(trait_def_id);
Ancestors {
trait_def_id,
specialization_graph,
current_source: Some(Node::Impl(start_from_impl)),
}
}
impl<'a> HashStable<StableHashingContext<'a>> for Children {
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
let Children { ref nonblanket_impls, ref blanket_impls } = *self;
ich::hash_stable_trait_impls(hcx, hasher, blanket_impls, nonblanket_impls);
}
}

View file

@ -0,0 +1,712 @@
use crate::traits;
use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
use crate::ty::{self, Lift, Ty, TyCtxt};
use rustc_span::symbol::Symbol;
use smallvec::SmallVec;
use std::collections::{BTreeMap, BTreeSet};
use std::fmt;
use std::rc::Rc;
// Structural impls for the structs in `traits`.
impl<'tcx, N: fmt::Debug> fmt::Debug for traits::Vtable<'tcx, N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
super::VtableImpl(ref v) => write!(f, "{:?}", v),
super::VtableAutoImpl(ref t) => write!(f, "{:?}", t),
super::VtableClosure(ref d) => write!(f, "{:?}", d),
super::VtableGenerator(ref d) => write!(f, "{:?}", d),
super::VtableFnPointer(ref d) => write!(f, "VtableFnPointer({:?})", d),
super::VtableObject(ref d) => write!(f, "{:?}", d),
super::VtableParam(ref n) => write!(f, "VtableParam({:?})", n),
super::VtableBuiltin(ref d) => write!(f, "{:?}", d),
super::VtableTraitAlias(ref d) => write!(f, "{:?}", d),
}
}
}
impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableImplData<'tcx, N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"VtableImplData(impl_def_id={:?}, substs={:?}, nested={:?})",
self.impl_def_id, self.substs, self.nested
)
}
}
impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableGeneratorData<'tcx, N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"VtableGeneratorData(generator_def_id={:?}, substs={:?}, nested={:?})",
self.generator_def_id, self.substs, self.nested
)
}
}
impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableClosureData<'tcx, N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"VtableClosureData(closure_def_id={:?}, substs={:?}, nested={:?})",
self.closure_def_id, self.substs, self.nested
)
}
}
impl<N: fmt::Debug> fmt::Debug for traits::VtableBuiltinData<N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "VtableBuiltinData(nested={:?})", self.nested)
}
}
impl<N: fmt::Debug> fmt::Debug for traits::VtableAutoImplData<N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"VtableAutoImplData(trait_def_id={:?}, nested={:?})",
self.trait_def_id, self.nested
)
}
}
impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableObjectData<'tcx, N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"VtableObjectData(upcast={:?}, vtable_base={}, nested={:?})",
self.upcast_trait_ref, self.vtable_base, self.nested
)
}
}
impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableFnPointerData<'tcx, N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "VtableFnPointerData(fn_ty={:?}, nested={:?})", self.fn_ty, self.nested)
}
}
impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableTraitAliasData<'tcx, N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"VtableTraitAlias(alias_def_id={:?}, substs={:?}, nested={:?})",
self.alias_def_id, self.substs, self.nested
)
}
}
impl<'tcx> fmt::Display for traits::WhereClause<'tcx> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
use crate::traits::WhereClause::*;
// Bypass `ty::print` because it does not print out anonymous regions.
// FIXME(eddyb) implement a custom `PrettyPrinter`, or move this to `ty::print`.
fn write_region_name<'tcx>(
r: ty::Region<'tcx>,
fmt: &mut fmt::Formatter<'_>,
) -> fmt::Result {
match r {
ty::ReLateBound(index, br) => match br {
ty::BoundRegion::BrNamed(_, name) => write!(fmt, "{}", name),
ty::BoundRegion::BrAnon(var) => {
if *index == ty::INNERMOST {
write!(fmt, "'^{}", var)
} else {
write!(fmt, "'^{}_{}", index.index(), var)
}
}
_ => write!(fmt, "'_"),
},
_ => write!(fmt, "{}", r),
}
}
match self {
Implemented(trait_ref) => write!(fmt, "Implemented({})", trait_ref),
ProjectionEq(projection) => write!(fmt, "ProjectionEq({})", projection),
RegionOutlives(predicate) => {
write!(fmt, "RegionOutlives({}: ", predicate.0)?;
write_region_name(predicate.1, fmt)?;
write!(fmt, ")")
}
TypeOutlives(predicate) => {
write!(fmt, "TypeOutlives({}: ", predicate.0)?;
write_region_name(predicate.1, fmt)?;
write!(fmt, ")")
}
}
}
}
impl<'tcx> fmt::Display for traits::WellFormed<'tcx> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
use crate::traits::WellFormed::*;
match self {
Trait(trait_ref) => write!(fmt, "WellFormed({})", trait_ref),
Ty(ty) => write!(fmt, "WellFormed({})", ty),
}
}
}
impl<'tcx> fmt::Display for traits::FromEnv<'tcx> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
use crate::traits::FromEnv::*;
match self {
Trait(trait_ref) => write!(fmt, "FromEnv({})", trait_ref),
Ty(ty) => write!(fmt, "FromEnv({})", ty),
}
}
}
impl<'tcx> fmt::Display for traits::DomainGoal<'tcx> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
use crate::traits::DomainGoal::*;
match self {
Holds(wc) => write!(fmt, "{}", wc),
WellFormed(wf) => write!(fmt, "{}", wf),
FromEnv(from_env) => write!(fmt, "{}", from_env),
Normalize(projection) => {
write!(fmt, "Normalize({} -> {})", projection.projection_ty, projection.ty)
}
}
}
}
impl fmt::Display for traits::QuantifierKind {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
use crate::traits::QuantifierKind::*;
match self {
Universal => write!(fmt, "forall"),
Existential => write!(fmt, "exists"),
}
}
}
/// Collect names for regions / types bound by a quantified goal / clause.
/// This collector does not try to do anything clever like in `ty::print`, it's just used
/// for debug output in tests anyway.
struct BoundNamesCollector {
// Just sort by name because `BoundRegion::BrNamed` does not have a `BoundVar` index anyway.
regions: BTreeSet<Symbol>,
// Sort by `BoundVar` index, so usually this should be equivalent to the order given
// by the list of type parameters.
types: BTreeMap<u32, Symbol>,
binder_index: ty::DebruijnIndex,
}
impl BoundNamesCollector {
fn new() -> Self {
BoundNamesCollector {
regions: BTreeSet::new(),
types: BTreeMap::new(),
binder_index: ty::INNERMOST,
}
}
fn is_empty(&self) -> bool {
self.regions.is_empty() && self.types.is_empty()
}
fn write_names(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut start = true;
for r in &self.regions {
if !start {
write!(fmt, ", ")?;
}
start = false;
write!(fmt, "{}", r)?;
}
for (_, t) in &self.types {
if !start {
write!(fmt, ", ")?;
}
start = false;
write!(fmt, "{}", t)?;
}
Ok(())
}
}
impl<'tcx> TypeVisitor<'tcx> for BoundNamesCollector {
fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> bool {
self.binder_index.shift_in(1);
let result = t.super_visit_with(self);
self.binder_index.shift_out(1);
result
}
fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
match t.kind {
ty::Bound(debruijn, bound_ty) if debruijn == self.binder_index => {
self.types.insert(
bound_ty.var.as_u32(),
match bound_ty.kind {
ty::BoundTyKind::Param(name) => name,
ty::BoundTyKind::Anon => {
Symbol::intern(&format!("^{}", bound_ty.var.as_u32()))
}
},
);
}
_ => (),
};
t.super_visit_with(self)
}
fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool {
match r {
ty::ReLateBound(index, br) if *index == self.binder_index => match br {
ty::BoundRegion::BrNamed(_, name) => {
self.regions.insert(*name);
}
ty::BoundRegion::BrAnon(var) => {
self.regions.insert(Symbol::intern(&format!("'^{}", var)));
}
_ => (),
},
_ => (),
};
r.super_visit_with(self)
}
}
impl<'tcx> fmt::Display for traits::Goal<'tcx> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
use crate::traits::GoalKind::*;
match self {
Implies(hypotheses, goal) => {
write!(fmt, "if (")?;
for (index, hyp) in hypotheses.iter().enumerate() {
if index > 0 {
write!(fmt, ", ")?;
}
write!(fmt, "{}", hyp)?;
}
write!(fmt, ") {{ {} }}", goal)
}
And(goal1, goal2) => write!(fmt, "({} && {})", goal1, goal2),
Not(goal) => write!(fmt, "not {{ {} }}", goal),
DomainGoal(goal) => write!(fmt, "{}", goal),
Quantified(qkind, goal) => {
let mut collector = BoundNamesCollector::new();
goal.skip_binder().visit_with(&mut collector);
if !collector.is_empty() {
write!(fmt, "{}<", qkind)?;
collector.write_names(fmt)?;
write!(fmt, "> {{ ")?;
}
write!(fmt, "{}", goal.skip_binder())?;
if !collector.is_empty() {
write!(fmt, " }}")?;
}
Ok(())
}
Subtype(a, b) => write!(fmt, "{} <: {}", a, b),
CannotProve => write!(fmt, "CannotProve"),
}
}
}
impl<'tcx> fmt::Display for traits::ProgramClause<'tcx> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
let traits::ProgramClause { goal, hypotheses, .. } = self;
write!(fmt, "{}", goal)?;
if !hypotheses.is_empty() {
write!(fmt, " :- ")?;
for (index, condition) in hypotheses.iter().enumerate() {
if index > 0 {
write!(fmt, ", ")?;
}
write!(fmt, "{}", condition)?;
}
}
write!(fmt, ".")
}
}
impl<'tcx> fmt::Display for traits::Clause<'tcx> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
use crate::traits::Clause::*;
match self {
Implies(clause) => write!(fmt, "{}", clause),
ForAll(clause) => {
let mut collector = BoundNamesCollector::new();
clause.skip_binder().visit_with(&mut collector);
if !collector.is_empty() {
write!(fmt, "forall<")?;
collector.write_names(fmt)?;
write!(fmt, "> {{ ")?;
}
write!(fmt, "{}", clause.skip_binder())?;
if !collector.is_empty() {
write!(fmt, " }}")?;
}
Ok(())
}
}
}
}
///////////////////////////////////////////////////////////////////////////
// Lift implementations
impl<'a, 'tcx> Lift<'tcx> for traits::SelectionError<'a> {
type Lifted = traits::SelectionError<'tcx>;
fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
match *self {
super::Unimplemented => Some(super::Unimplemented),
super::OutputTypeParameterMismatch(a, b, ref err) => {
tcx.lift(&(a, b)).and_then(|(a, b)| {
tcx.lift(err).map(|err| super::OutputTypeParameterMismatch(a, b, err))
})
}
super::TraitNotObjectSafe(def_id) => Some(super::TraitNotObjectSafe(def_id)),
super::ConstEvalFailure(err) => Some(super::ConstEvalFailure(err)),
super::Overflow => Some(super::Overflow),
}
}
}
impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> {
type Lifted = traits::ObligationCauseCode<'tcx>;
fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
match *self {
super::ReturnNoExpression => Some(super::ReturnNoExpression),
super::MiscObligation => Some(super::MiscObligation),
super::SliceOrArrayElem => Some(super::SliceOrArrayElem),
super::TupleElem => Some(super::TupleElem),
super::ProjectionWf(proj) => tcx.lift(&proj).map(super::ProjectionWf),
super::ItemObligation(def_id) => Some(super::ItemObligation(def_id)),
super::BindingObligation(def_id, span) => Some(super::BindingObligation(def_id, span)),
super::ReferenceOutlivesReferent(ty) => {
tcx.lift(&ty).map(super::ReferenceOutlivesReferent)
}
super::ObjectTypeBound(ty, r) => tcx
.lift(&ty)
.and_then(|ty| tcx.lift(&r).and_then(|r| Some(super::ObjectTypeBound(ty, r)))),
super::ObjectCastObligation(ty) => tcx.lift(&ty).map(super::ObjectCastObligation),
super::Coercion { source, target } => {
Some(super::Coercion { source: tcx.lift(&source)?, target: tcx.lift(&target)? })
}
super::AssignmentLhsSized => Some(super::AssignmentLhsSized),
super::TupleInitializerSized => Some(super::TupleInitializerSized),
super::StructInitializerSized => Some(super::StructInitializerSized),
super::VariableType(id) => Some(super::VariableType(id)),
super::ReturnValue(id) => Some(super::ReturnValue(id)),
super::ReturnType => Some(super::ReturnType),
super::SizedArgumentType => Some(super::SizedArgumentType),
super::SizedReturnType => Some(super::SizedReturnType),
super::SizedYieldType => Some(super::SizedYieldType),
super::RepeatVec(suggest_flag) => Some(super::RepeatVec(suggest_flag)),
super::FieldSized { adt_kind, last } => Some(super::FieldSized { adt_kind, last }),
super::ConstSized => Some(super::ConstSized),
super::ConstPatternStructural => Some(super::ConstPatternStructural),
super::SharedStatic => Some(super::SharedStatic),
super::BuiltinDerivedObligation(ref cause) => {
tcx.lift(cause).map(super::BuiltinDerivedObligation)
}
super::ImplDerivedObligation(ref cause) => {
tcx.lift(cause).map(super::ImplDerivedObligation)
}
super::CompareImplMethodObligation {
item_name,
impl_item_def_id,
trait_item_def_id,
} => Some(super::CompareImplMethodObligation {
item_name,
impl_item_def_id,
trait_item_def_id,
}),
super::CompareImplTypeObligation { item_name, impl_item_def_id, trait_item_def_id } => {
Some(super::CompareImplTypeObligation {
item_name,
impl_item_def_id,
trait_item_def_id,
})
}
super::ExprAssignable => Some(super::ExprAssignable),
super::MatchExpressionArm(box super::MatchExpressionArmCause {
arm_span,
source,
ref prior_arms,
last_ty,
scrut_hir_id,
}) => tcx.lift(&last_ty).map(|last_ty| {
super::MatchExpressionArm(box super::MatchExpressionArmCause {
arm_span,
source,
prior_arms: prior_arms.clone(),
last_ty,
scrut_hir_id,
})
}),
super::Pattern { span, root_ty, origin_expr } => {
tcx.lift(&root_ty).map(|root_ty| super::Pattern { span, root_ty, origin_expr })
}
super::IfExpression(box super::IfExpressionCause { then, outer, semicolon }) => {
Some(super::IfExpression(box super::IfExpressionCause { then, outer, semicolon }))
}
super::IfExpressionWithNoElse => Some(super::IfExpressionWithNoElse),
super::MainFunctionType => Some(super::MainFunctionType),
super::StartFunctionType => Some(super::StartFunctionType),
super::IntrinsicType => Some(super::IntrinsicType),
super::MethodReceiver => Some(super::MethodReceiver),
super::BlockTailExpression(id) => Some(super::BlockTailExpression(id)),
super::TrivialBound => Some(super::TrivialBound),
super::AssocTypeBound(ref data) => Some(super::AssocTypeBound(data.clone())),
}
}
}
impl<'a, 'tcx> Lift<'tcx> for traits::DerivedObligationCause<'a> {
type Lifted = traits::DerivedObligationCause<'tcx>;
fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
tcx.lift(&self.parent_trait_ref).and_then(|trait_ref| {
tcx.lift(&*self.parent_code).map(|code| traits::DerivedObligationCause {
parent_trait_ref: trait_ref,
parent_code: Rc::new(code),
})
})
}
}
impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCause<'a> {
type Lifted = traits::ObligationCause<'tcx>;
fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
tcx.lift(&self.code).map(|code| traits::ObligationCause {
span: self.span,
body_id: self.body_id,
code,
})
}
}
// For codegen only.
impl<'a, 'tcx> Lift<'tcx> for traits::Vtable<'a, ()> {
type Lifted = traits::Vtable<'tcx, ()>;
fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
match self.clone() {
traits::VtableImpl(traits::VtableImplData { impl_def_id, substs, nested }) => {
tcx.lift(&substs).map(|substs| {
traits::VtableImpl(traits::VtableImplData { impl_def_id, substs, nested })
})
}
traits::VtableAutoImpl(t) => Some(traits::VtableAutoImpl(t)),
traits::VtableGenerator(traits::VtableGeneratorData {
generator_def_id,
substs,
nested,
}) => tcx.lift(&substs).map(|substs| {
traits::VtableGenerator(traits::VtableGeneratorData {
generator_def_id: generator_def_id,
substs: substs,
nested: nested,
})
}),
traits::VtableClosure(traits::VtableClosureData { closure_def_id, substs, nested }) => {
tcx.lift(&substs).map(|substs| {
traits::VtableClosure(traits::VtableClosureData {
closure_def_id,
substs,
nested,
})
})
}
traits::VtableFnPointer(traits::VtableFnPointerData { fn_ty, nested }) => {
tcx.lift(&fn_ty).map(|fn_ty| {
traits::VtableFnPointer(traits::VtableFnPointerData { fn_ty, nested })
})
}
traits::VtableParam(n) => Some(traits::VtableParam(n)),
traits::VtableBuiltin(n) => Some(traits::VtableBuiltin(n)),
traits::VtableObject(traits::VtableObjectData {
upcast_trait_ref,
vtable_base,
nested,
}) => tcx.lift(&upcast_trait_ref).map(|trait_ref| {
traits::VtableObject(traits::VtableObjectData {
upcast_trait_ref: trait_ref,
vtable_base,
nested,
})
}),
traits::VtableTraitAlias(traits::VtableTraitAliasData {
alias_def_id,
substs,
nested,
}) => tcx.lift(&substs).map(|substs| {
traits::VtableTraitAlias(traits::VtableTraitAliasData {
alias_def_id,
substs,
nested,
})
}),
}
}
}
impl<'a, 'tcx> Lift<'tcx> for traits::Environment<'a> {
type Lifted = traits::Environment<'tcx>;
fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
tcx.lift(&self.clauses).map(|clauses| traits::Environment { clauses })
}
}
impl<'a, 'tcx, G: Lift<'tcx>> Lift<'tcx> for traits::InEnvironment<'a, G> {
type Lifted = traits::InEnvironment<'tcx, G::Lifted>;
fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
tcx.lift(&self.environment).and_then(|environment| {
tcx.lift(&self.goal).map(|goal| traits::InEnvironment { environment, goal })
})
}
}
impl<'tcx, C> Lift<'tcx> for chalk_engine::ExClause<C>
where
C: chalk_engine::context::Context + Clone,
C: traits::ChalkContextLift<'tcx>,
{
type Lifted = C::LiftedExClause;
fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
<C as traits::ChalkContextLift>::lift_ex_clause_to_tcx(self, tcx)
}
}
impl<'tcx, C> Lift<'tcx> for chalk_engine::DelayedLiteral<C>
where
C: chalk_engine::context::Context + Clone,
C: traits::ChalkContextLift<'tcx>,
{
type Lifted = C::LiftedDelayedLiteral;
fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
<C as traits::ChalkContextLift>::lift_delayed_literal_to_tcx(self, tcx)
}
}
impl<'tcx, C> Lift<'tcx> for chalk_engine::Literal<C>
where
C: chalk_engine::context::Context + Clone,
C: traits::ChalkContextLift<'tcx>,
{
type Lifted = C::LiftedLiteral;
fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
<C as traits::ChalkContextLift>::lift_literal_to_tcx(self, tcx)
}
}
///////////////////////////////////////////////////////////////////////////
// TypeFoldable implementations.
CloneTypeFoldableAndLiftImpls! {
traits::QuantifierKind,
}
impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<traits::Goal<'tcx>> {
fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
let v = self.iter().map(|t| t.fold_with(folder)).collect::<SmallVec<[_; 8]>>();
folder.tcx().intern_goals(&v)
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
self.iter().any(|t| t.visit_with(visitor))
}
}
impl<'tcx> TypeFoldable<'tcx> for traits::Goal<'tcx> {
fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
let v = (**self).fold_with(folder);
folder.tcx().mk_goal(v)
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
(**self).visit_with(visitor)
}
}
CloneTypeFoldableAndLiftImpls! {
traits::ProgramClauseCategory,
}
impl<'tcx> TypeFoldable<'tcx> for traits::Clauses<'tcx> {
fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
let v = self.iter().map(|t| t.fold_with(folder)).collect::<SmallVec<[_; 8]>>();
folder.tcx().intern_clauses(&v)
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
self.iter().any(|t| t.visit_with(visitor))
}
}
impl<'tcx, C> TypeFoldable<'tcx> for chalk_engine::ExClause<C>
where
C: traits::ExClauseFold<'tcx>,
C::Substitution: Clone,
C::RegionConstraint: Clone,
{
fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
<C as traits::ExClauseFold>::fold_ex_clause_with(self, folder)
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
<C as traits::ExClauseFold>::visit_ex_clause_with(self, visitor)
}
}
EnumTypeFoldableImpl! {
impl<'tcx, C> TypeFoldable<'tcx> for chalk_engine::DelayedLiteral<C> {
(chalk_engine::DelayedLiteral::CannotProve)(a),
(chalk_engine::DelayedLiteral::Negative)(a),
(chalk_engine::DelayedLiteral::Positive)(a, b),
} where
C: chalk_engine::context::Context<CanonicalConstrainedSubst: TypeFoldable<'tcx>> + Clone,
}
EnumTypeFoldableImpl! {
impl<'tcx, C> TypeFoldable<'tcx> for chalk_engine::Literal<C> {
(chalk_engine::Literal::Negative)(a),
(chalk_engine::Literal::Positive)(a),
} where
C: chalk_engine::context::Context<GoalInEnvironment: Clone + TypeFoldable<'tcx>> + Clone,
}
CloneTypeFoldableAndLiftImpls! {
chalk_engine::TableIndex,
}

View file

@ -15,6 +15,16 @@ pub struct ExpectedFound<T> {
pub found: T,
}
impl<T> ExpectedFound<T> {
pub fn new(a_is_expected: bool, a: T, b: T) -> Self {
if a_is_expected {
ExpectedFound { expected: a, found: b }
} else {
ExpectedFound { expected: b, found: a }
}
}
}
// Data structures used in type unification
#[derive(Clone, Debug, TypeFoldable)]
pub enum TypeError<'tcx> {