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:
commit
a25d58b41b
30 changed files with 2725 additions and 2557 deletions
|
@ -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]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 }
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
357
src/librustc/infer/types/canonical.rs
Normal file
357
src/librustc/infer/types/canonical.rs
Normal 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]
|
||||
}
|
||||
}
|
31
src/librustc/infer/types/mod.rs
Normal file
31
src/librustc/infer/types/mod.rs
Normal 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>>>,
|
||||
}
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>;
|
||||
}
|
||||
|
|
|
@ -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>>;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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::*;
|
||||
|
|
|
@ -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>,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 = ();
|
||||
|
|
|
@ -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 = ();
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 = ();
|
||||
|
|
|
@ -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 = ();
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
736
src/librustc/traits/types/mod.rs
Normal file
736
src/librustc/traits/types/mod.rs
Normal 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>;
|
||||
}
|
332
src/librustc/traits/types/query.rs
Normal file
332
src/librustc/traits/types/query.rs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
290
src/librustc/traits/types/select.rs
Normal file
290
src/librustc/traits/types/select.rs
Normal 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()
|
||||
}
|
||||
}
|
199
src/librustc/traits/types/specialization_graph.rs
Normal file
199
src/librustc/traits/types/specialization_graph.rs
Normal 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);
|
||||
}
|
||||
}
|
712
src/librustc/traits/types/structural_impls.rs
Normal file
712
src/librustc/traits/types/structural_impls.rs
Normal 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,
|
||||
}
|
|
@ -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> {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue