diff options
| author | bors <bors@rust-lang.org> | 2020-02-16 22:24:54 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2020-02-16 22:24:54 +0000 |
| commit | a643ee8d693b8100e6f54f2a01ff7cde05eb65c5 (patch) | |
| tree | 7559e86bc309ebcd88293a4d9832b0eecd566bf6 /src/librustc | |
| parent | 5e7af4669f80e5f682141f050193ab679afdb4b1 (diff) | |
| parent | e88500b5e18bbbad2323944d3c23f8a4465eb147 (diff) | |
Auto merge of #67953 - cjgillot:split_infer, r=Zoxc
Split librustc::{traits,infer} to a separate crate rustc_infer
This is still very much work in progress.
Three functions are between dimensions (at the end of `rustc::traits`), waiting for some dependency breaking scheme.
Please tell me if the approach seems sound, and how you would like to split this PR up.
The formatting is deliberately off, to ease rebasing.
cc #65031
Diffstat (limited to 'src/librustc')
89 files changed, 1622 insertions, 35489 deletions
diff --git a/src/librustc/Cargo.toml b/src/librustc/Cargo.toml index 782c6879ac5..af2be30cc0a 100644 --- a/src/librustc/Cargo.toml +++ b/src/librustc/Cargo.toml @@ -12,8 +12,6 @@ doctest = false [dependencies] arena = { path = "../libarena" } bitflags = "1.2.1" -fmt_macros = { path = "../libfmt_macros" } -graphviz = { path = "../libgraphviz" } jobserver = "0.1" scoped-tls = "1.0" log = { version = "0.4", features = ["release_max_level_info", "std"] } diff --git a/src/librustc/arena.rs b/src/librustc/arena.rs index 33cbf6ede0a..f5c83fed1fc 100644 --- a/src/librustc/arena.rs +++ b/src/librustc/arena.rs @@ -51,19 +51,19 @@ macro_rules! arena_types { [] dropck_outlives: rustc::infer::canonical::Canonical<'tcx, rustc::infer::canonical::QueryResponse<'tcx, - rustc::traits::query::dropck_outlives::DropckOutlivesResult<'tcx> + rustc::traits::query::DropckOutlivesResult<'tcx> > >, [] normalize_projection_ty: rustc::infer::canonical::Canonical<'tcx, rustc::infer::canonical::QueryResponse<'tcx, - rustc::traits::query::normalize::NormalizationResult<'tcx> + rustc::traits::query::NormalizationResult<'tcx> > >, [] implied_outlives_bounds: rustc::infer::canonical::Canonical<'tcx, rustc::infer::canonical::QueryResponse<'tcx, - Vec<rustc::traits::query::outlives_bounds::OutlivesBound<'tcx>> + Vec<rustc::traits::query::OutlivesBound<'tcx>> > >, [] type_op_subtype: diff --git a/src/librustc/infer/at.rs b/src/librustc/infer/at.rs deleted file mode 100644 index c58f1bd87bd..00000000000 --- a/src/librustc/infer/at.rs +++ /dev/null @@ -1,312 +0,0 @@ -//! A nice interface for working with the infcx. The basic idea is to -//! do `infcx.at(cause, param_env)`, which sets the "cause" of the -//! operation as well as the surrounding parameter environment. Then -//! you can do something like `.sub(a, b)` or `.eq(a, b)` to create a -//! subtype or equality relationship respectively. The first argument -//! is always the "expected" output from the POV of diagnostics. -//! -//! Examples: -//! -//! infcx.at(cause, param_env).sub(a, b) -//! // requires that `a <: b`, with `a` considered the "expected" type -//! -//! infcx.at(cause, param_env).sup(a, b) -//! // requires that `b <: a`, with `a` considered the "expected" type -//! -//! infcx.at(cause, param_env).eq(a, b) -//! // requires that `a == b`, with `a` considered the "expected" type -//! -//! For finer-grained control, you can also do use `trace`: -//! -//! infcx.at(...).trace(a, b).sub(&c, &d) -//! -//! This will set `a` and `b` as the "root" values for -//! error-reporting, but actually operate on `c` and `d`. This is -//! sometimes useful when the types of `c` and `d` are not traceable -//! things. (That system should probably be refactored.) - -use super::*; - -use crate::ty::relate::{Relate, TypeRelation}; -use crate::ty::Const; - -pub struct At<'a, 'tcx> { - pub infcx: &'a InferCtxt<'a, 'tcx>, - pub cause: &'a ObligationCause<'tcx>, - pub param_env: ty::ParamEnv<'tcx>, -} - -pub struct Trace<'a, 'tcx> { - at: At<'a, 'tcx>, - a_is_expected: bool, - trace: TypeTrace<'tcx>, -} - -impl<'a, 'tcx> InferCtxt<'a, 'tcx> { - #[inline] - pub fn at( - &'a self, - cause: &'a ObligationCause<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ) -> At<'a, 'tcx> { - At { infcx: self, cause, param_env } - } -} - -pub trait ToTrace<'tcx>: Relate<'tcx> + Copy { - fn to_trace( - cause: &ObligationCause<'tcx>, - a_is_expected: bool, - a: Self, - b: Self, - ) -> TypeTrace<'tcx>; -} - -impl<'a, 'tcx> At<'a, 'tcx> { - /// Hacky routine for equating two impl headers in coherence. - pub fn eq_impl_headers( - self, - expected: &ty::ImplHeader<'tcx>, - actual: &ty::ImplHeader<'tcx>, - ) -> InferResult<'tcx, ()> { - debug!("eq_impl_header({:?} = {:?})", expected, actual); - match (expected.trait_ref, actual.trait_ref) { - (Some(a_ref), Some(b_ref)) => self.eq(a_ref, b_ref), - (None, None) => self.eq(expected.self_ty, actual.self_ty), - _ => bug!("mk_eq_impl_headers given mismatched impl kinds"), - } - } - - /// Makes `a <: b`, where `a` may or may not be expected. - pub fn sub_exp<T>(self, a_is_expected: bool, a: T, b: T) -> InferResult<'tcx, ()> - where - T: ToTrace<'tcx>, - { - self.trace_exp(a_is_expected, a, b).sub(&a, &b) - } - - /// Makes `actual <: expected`. For example, if type-checking a - /// call like `foo(x)`, where `foo: fn(i32)`, you might have - /// `sup(i32, x)`, since the "expected" type is the type that - /// appears in the signature. - pub fn sup<T>(self, expected: T, actual: T) -> InferResult<'tcx, ()> - where - T: ToTrace<'tcx>, - { - self.sub_exp(false, actual, expected) - } - - /// Makes `expected <: actual`. - pub fn sub<T>(self, expected: T, actual: T) -> InferResult<'tcx, ()> - where - T: ToTrace<'tcx>, - { - self.sub_exp(true, expected, actual) - } - - /// Makes `expected <: actual`. - pub fn eq_exp<T>(self, a_is_expected: bool, a: T, b: T) -> InferResult<'tcx, ()> - where - T: ToTrace<'tcx>, - { - self.trace_exp(a_is_expected, a, b).eq(&a, &b) - } - - /// Makes `expected <: actual`. - pub fn eq<T>(self, expected: T, actual: T) -> InferResult<'tcx, ()> - where - T: ToTrace<'tcx>, - { - self.trace(expected, actual).eq(&expected, &actual) - } - - pub fn relate<T>(self, expected: T, variance: ty::Variance, actual: T) -> InferResult<'tcx, ()> - where - T: ToTrace<'tcx>, - { - match variance { - ty::Variance::Covariant => self.sub(expected, actual), - ty::Variance::Invariant => self.eq(expected, actual), - ty::Variance::Contravariant => self.sup(expected, actual), - - // We could make this make sense but it's not readily - // exposed and I don't feel like dealing with it. Note - // that bivariance in general does a bit more than just - // *nothing*, it checks that the types are the same - // "modulo variance" basically. - ty::Variance::Bivariant => panic!("Bivariant given to `relate()`"), - } - } - - /// Computes the least-upper-bound, or mutual supertype, of two - /// values. The order of the arguments doesn't matter, but since - /// this can result in an error (e.g., if asked to compute LUB of - /// u32 and i32), it is meaningful to call one of them the - /// "expected type". - pub fn lub<T>(self, expected: T, actual: T) -> InferResult<'tcx, T> - where - T: ToTrace<'tcx>, - { - self.trace(expected, actual).lub(&expected, &actual) - } - - /// Computes the greatest-lower-bound, or mutual subtype, of two - /// values. As with `lub` order doesn't matter, except for error - /// cases. - pub fn glb<T>(self, expected: T, actual: T) -> InferResult<'tcx, T> - where - T: ToTrace<'tcx>, - { - self.trace(expected, actual).glb(&expected, &actual) - } - - /// Sets the "trace" values that will be used for - /// error-reporting, but doesn't actually perform any operation - /// yet (this is useful when you want to set the trace using - /// distinct values from those you wish to operate upon). - pub fn trace<T>(self, expected: T, actual: T) -> Trace<'a, 'tcx> - where - T: ToTrace<'tcx>, - { - self.trace_exp(true, expected, actual) - } - - /// Like `trace`, but the expected value is determined by the - /// boolean argument (if true, then the first argument `a` is the - /// "expected" value). - pub fn trace_exp<T>(self, a_is_expected: bool, a: T, b: T) -> Trace<'a, 'tcx> - where - T: ToTrace<'tcx>, - { - let trace = ToTrace::to_trace(self.cause, a_is_expected, a, b); - Trace { at: self, trace: trace, a_is_expected } - } -} - -impl<'a, 'tcx> Trace<'a, 'tcx> { - /// Makes `a <: b` where `a` may or may not be expected (if - /// `a_is_expected` is true, then `a` is expected). - /// Makes `expected <: actual`. - pub fn sub<T>(self, a: &T, b: &T) -> InferResult<'tcx, ()> - where - T: Relate<'tcx>, - { - debug!("sub({:?} <: {:?})", a, b); - let Trace { at, trace, a_is_expected } = self; - at.infcx.commit_if_ok(|_| { - let mut fields = at.infcx.combine_fields(trace, at.param_env); - fields - .sub(a_is_expected) - .relate(a, b) - .map(move |_| InferOk { value: (), obligations: fields.obligations }) - }) - } - - /// Makes `a == b`; the expectation is set by the call to - /// `trace()`. - pub fn eq<T>(self, a: &T, b: &T) -> InferResult<'tcx, ()> - where - T: Relate<'tcx>, - { - debug!("eq({:?} == {:?})", a, b); - let Trace { at, trace, a_is_expected } = self; - at.infcx.commit_if_ok(|_| { - let mut fields = at.infcx.combine_fields(trace, at.param_env); - fields - .equate(a_is_expected) - .relate(a, b) - .map(move |_| InferOk { value: (), obligations: fields.obligations }) - }) - } - - pub fn lub<T>(self, a: &T, b: &T) -> InferResult<'tcx, T> - where - T: Relate<'tcx>, - { - debug!("lub({:?} \\/ {:?})", a, b); - let Trace { at, trace, a_is_expected } = self; - at.infcx.commit_if_ok(|_| { - let mut fields = at.infcx.combine_fields(trace, at.param_env); - fields - .lub(a_is_expected) - .relate(a, b) - .map(move |t| InferOk { value: t, obligations: fields.obligations }) - }) - } - - pub fn glb<T>(self, a: &T, b: &T) -> InferResult<'tcx, T> - where - T: Relate<'tcx>, - { - debug!("glb({:?} /\\ {:?})", a, b); - let Trace { at, trace, a_is_expected } = self; - at.infcx.commit_if_ok(|_| { - let mut fields = at.infcx.combine_fields(trace, at.param_env); - fields - .glb(a_is_expected) - .relate(a, b) - .map(move |t| InferOk { value: t, obligations: fields.obligations }) - }) - } -} - -impl<'tcx> ToTrace<'tcx> for Ty<'tcx> { - fn to_trace( - cause: &ObligationCause<'tcx>, - a_is_expected: bool, - a: Self, - b: Self, - ) -> TypeTrace<'tcx> { - TypeTrace { cause: cause.clone(), values: Types(ExpectedFound::new(a_is_expected, a, b)) } - } -} - -impl<'tcx> ToTrace<'tcx> for ty::Region<'tcx> { - fn to_trace( - cause: &ObligationCause<'tcx>, - a_is_expected: bool, - a: Self, - b: Self, - ) -> TypeTrace<'tcx> { - TypeTrace { cause: cause.clone(), values: Regions(ExpectedFound::new(a_is_expected, a, b)) } - } -} - -impl<'tcx> ToTrace<'tcx> for &'tcx Const<'tcx> { - fn to_trace( - cause: &ObligationCause<'tcx>, - a_is_expected: bool, - a: Self, - b: Self, - ) -> TypeTrace<'tcx> { - TypeTrace { cause: cause.clone(), values: Consts(ExpectedFound::new(a_is_expected, a, b)) } - } -} - -impl<'tcx> ToTrace<'tcx> for ty::TraitRef<'tcx> { - fn to_trace( - cause: &ObligationCause<'tcx>, - a_is_expected: bool, - a: Self, - b: Self, - ) -> TypeTrace<'tcx> { - TypeTrace { - cause: cause.clone(), - values: TraitRefs(ExpectedFound::new(a_is_expected, a, b)), - } - } -} - -impl<'tcx> ToTrace<'tcx> for ty::PolyTraitRef<'tcx> { - fn to_trace( - cause: &ObligationCause<'tcx>, - a_is_expected: bool, - a: Self, - b: Self, - ) -> TypeTrace<'tcx> { - TypeTrace { - cause: cause.clone(), - values: PolyTraitRefs(ExpectedFound::new(a_is_expected, a, b)), - } - } -} diff --git a/src/librustc/infer/types/canonical.rs b/src/librustc/infer/canonical.rs index 133cf1b5928..76d0d57e233 100644 --- a/src/librustc/infer/types/canonical.rs +++ b/src/librustc/infer/canonical.rs @@ -21,7 +21,7 @@ //! //! [c]: https://rust-lang.github.io/rustc-guide/traits/canonicalization.html -use crate::infer::region_constraints::MemberConstraint; +use crate::infer::MemberConstraint; use crate::ty::subst::GenericArg; use crate::ty::{self, BoundVar, List, Region, TyCtxt}; use rustc_index::vec::IndexVec; diff --git a/src/librustc/infer/canonical/canonicalizer.rs b/src/librustc/infer/canonical/canonicalizer.rs deleted file mode 100644 index 85fafa34915..00000000000 --- a/src/librustc/infer/canonical/canonicalizer.rs +++ /dev/null @@ -1,677 +0,0 @@ -//! This module contains the "canonicalizer" itself. -//! -//! For an overview of what canonicalization is and how it fits into -//! rustc, check out the [chapter in the rustc guide][c]. -//! -//! [c]: https://rust-lang.github.io/rustc-guide/traits/canonicalization.html - -use crate::infer::canonical::{ - Canonical, CanonicalTyVarKind, CanonicalVarInfo, CanonicalVarKind, Canonicalized, - OriginalQueryValues, -}; -use crate::infer::InferCtxt; -use crate::ty::flags::FlagComputation; -use crate::ty::fold::{TypeFoldable, TypeFolder}; -use crate::ty::subst::GenericArg; -use crate::ty::{self, BoundVar, InferConst, List, Ty, TyCtxt, TypeFlags}; -use std::sync::atomic::Ordering; - -use rustc_data_structures::fx::FxHashMap; -use rustc_index::vec::Idx; -use smallvec::SmallVec; - -impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { - /// Canonicalizes a query value `V`. When we canonicalize a query, - /// we not only canonicalize unbound inference variables, but we - /// *also* replace all free regions whatsoever. So for example a - /// query like `T: Trait<'static>` would be canonicalized to - /// - /// ```text - /// T: Trait<'?0> - /// ``` - /// - /// with a mapping M that maps `'?0` to `'static`. - /// - /// To get a good understanding of what is happening here, check - /// out the [chapter in the rustc guide][c]. - /// - /// [c]: https://rust-lang.github.io/rustc-guide/traits/canonicalization.html#canonicalizing-the-query - pub fn canonicalize_query<V>( - &self, - value: &V, - query_state: &mut OriginalQueryValues<'tcx>, - ) -> Canonicalized<'tcx, V> - where - V: TypeFoldable<'tcx>, - { - self.tcx.sess.perf_stats.queries_canonicalized.fetch_add(1, Ordering::Relaxed); - - Canonicalizer::canonicalize( - value, - Some(self), - self.tcx, - &CanonicalizeAllFreeRegions, - query_state, - ) - } - - /// Canonicalizes a query *response* `V`. When we canonicalize a - /// query response, we only canonicalize unbound inference - /// variables, and we leave other free regions alone. So, - /// continuing with the example from `canonicalize_query`, if - /// there was an input query `T: Trait<'static>`, it would have - /// been canonicalized to - /// - /// ```text - /// T: Trait<'?0> - /// ``` - /// - /// with a mapping M that maps `'?0` to `'static`. But if we found that there - /// exists only one possible impl of `Trait`, and it looks like - /// - /// impl<T> Trait<'static> for T { .. } - /// - /// then we would prepare a query result R that (among other - /// things) includes a mapping to `'?0 := 'static`. When - /// canonicalizing this query result R, we would leave this - /// reference to `'static` alone. - /// - /// To get a good understanding of what is happening here, check - /// out the [chapter in the rustc guide][c]. - /// - /// [c]: https://rust-lang.github.io/rustc-guide/traits/canonicalization.html#canonicalizing-the-query-result - pub fn canonicalize_response<V>(&self, value: &V) -> Canonicalized<'tcx, V> - where - V: TypeFoldable<'tcx>, - { - let mut query_state = OriginalQueryValues::default(); - Canonicalizer::canonicalize( - value, - Some(self), - self.tcx, - &CanonicalizeQueryResponse, - &mut query_state, - ) - } - - pub fn canonicalize_user_type_annotation<V>(&self, value: &V) -> Canonicalized<'tcx, V> - where - V: TypeFoldable<'tcx>, - { - let mut query_state = OriginalQueryValues::default(); - Canonicalizer::canonicalize( - value, - Some(self), - self.tcx, - &CanonicalizeUserTypeAnnotation, - &mut query_state, - ) - } - - /// A hacky variant of `canonicalize_query` that does not - /// canonicalize `'static`. Unfortunately, the existing leak - /// check treats `'static` differently in some cases (see also - /// #33684), so if we are performing an operation that may need to - /// prove "leak-check" related things, we leave `'static` - /// alone. - /// - /// `'static` is also special cased when winnowing candidates when - /// selecting implementation candidates, so we also have to leave `'static` - /// alone for queries that do selection. - // - // FIXME(#48536): once the above issues are resolved, we can remove this - // and just use `canonicalize_query`. - pub fn canonicalize_hr_query_hack<V>( - &self, - value: &V, - query_state: &mut OriginalQueryValues<'tcx>, - ) -> Canonicalized<'tcx, V> - where - V: TypeFoldable<'tcx>, - { - self.tcx.sess.perf_stats.queries_canonicalized.fetch_add(1, Ordering::Relaxed); - - Canonicalizer::canonicalize( - value, - Some(self), - self.tcx, - &CanonicalizeFreeRegionsOtherThanStatic, - query_state, - ) - } -} - -/// Controls how we canonicalize "free regions" that are not inference -/// variables. This depends on what we are canonicalizing *for* -- -/// e.g., if we are canonicalizing to create a query, we want to -/// replace those with inference variables, since we want to make a -/// maximally general query. But if we are canonicalizing a *query -/// response*, then we don't typically replace free regions, as they -/// must have been introduced from other parts of the system. -trait CanonicalizeRegionMode { - fn canonicalize_free_region( - &self, - canonicalizer: &mut Canonicalizer<'_, 'tcx>, - r: ty::Region<'tcx>, - ) -> ty::Region<'tcx>; - - fn any(&self) -> bool; -} - -struct CanonicalizeQueryResponse; - -impl CanonicalizeRegionMode for CanonicalizeQueryResponse { - fn canonicalize_free_region( - &self, - canonicalizer: &mut Canonicalizer<'_, 'tcx>, - r: ty::Region<'tcx>, - ) -> ty::Region<'tcx> { - match r { - ty::ReFree(_) - | ty::ReErased - | ty::ReStatic - | ty::ReEmpty(ty::UniverseIndex::ROOT) - | ty::ReEarlyBound(..) => r, - - ty::RePlaceholder(placeholder) => canonicalizer.canonical_var_for_region( - CanonicalVarInfo { kind: CanonicalVarKind::PlaceholderRegion(*placeholder) }, - r, - ), - - ty::ReVar(vid) => { - let universe = canonicalizer.region_var_universe(*vid); - canonicalizer.canonical_var_for_region( - CanonicalVarInfo { kind: CanonicalVarKind::Region(universe) }, - r, - ) - } - - ty::ReEmpty(ui) => { - bug!("canonicalizing 'empty in universe {:?}", ui) // FIXME - } - - _ => { - // Other than `'static` or `'empty`, the query - // response should be executing in a fully - // canonicalized environment, so there shouldn't be - // any other region names it can come up. - // - // rust-lang/rust#57464: `impl Trait` can leak local - // scopes (in manner violating typeck). Therefore, use - // `delay_span_bug` to allow type error over an ICE. - ty::tls::with_context(|c| { - c.tcx.sess.delay_span_bug( - rustc_span::DUMMY_SP, - &format!("unexpected region in query response: `{:?}`", r), - ); - }); - r - } - } - } - - fn any(&self) -> bool { - false - } -} - -struct CanonicalizeUserTypeAnnotation; - -impl CanonicalizeRegionMode for CanonicalizeUserTypeAnnotation { - fn canonicalize_free_region( - &self, - canonicalizer: &mut Canonicalizer<'_, 'tcx>, - r: ty::Region<'tcx>, - ) -> ty::Region<'tcx> { - match r { - ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReErased | ty::ReStatic => r, - ty::ReVar(_) => canonicalizer.canonical_var_for_region_in_root_universe(r), - _ => { - // We only expect region names that the user can type. - bug!("unexpected region in query response: `{:?}`", r) - } - } - } - - fn any(&self) -> bool { - false - } -} - -struct CanonicalizeAllFreeRegions; - -impl CanonicalizeRegionMode for CanonicalizeAllFreeRegions { - fn canonicalize_free_region( - &self, - canonicalizer: &mut Canonicalizer<'_, 'tcx>, - r: ty::Region<'tcx>, - ) -> ty::Region<'tcx> { - canonicalizer.canonical_var_for_region_in_root_universe(r) - } - - fn any(&self) -> bool { - true - } -} - -struct CanonicalizeFreeRegionsOtherThanStatic; - -impl CanonicalizeRegionMode for CanonicalizeFreeRegionsOtherThanStatic { - fn canonicalize_free_region( - &self, - canonicalizer: &mut Canonicalizer<'_, 'tcx>, - r: ty::Region<'tcx>, - ) -> ty::Region<'tcx> { - if let ty::ReStatic = r { - r - } else { - canonicalizer.canonical_var_for_region_in_root_universe(r) - } - } - - fn any(&self) -> bool { - true - } -} - -struct Canonicalizer<'cx, 'tcx> { - infcx: Option<&'cx InferCtxt<'cx, 'tcx>>, - tcx: TyCtxt<'tcx>, - variables: SmallVec<[CanonicalVarInfo; 8]>, - query_state: &'cx mut OriginalQueryValues<'tcx>, - // Note that indices is only used once `var_values` is big enough to be - // heap-allocated. - indices: FxHashMap<GenericArg<'tcx>, BoundVar>, - canonicalize_region_mode: &'cx dyn CanonicalizeRegionMode, - needs_canonical_flags: TypeFlags, - - binder_index: ty::DebruijnIndex, -} - -impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> { - fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { - self.tcx - } - - fn fold_binder<T>(&mut self, t: &ty::Binder<T>) -> ty::Binder<T> - where - T: TypeFoldable<'tcx>, - { - self.binder_index.shift_in(1); - let t = t.super_fold_with(self); - self.binder_index.shift_out(1); - t - } - - fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { - match *r { - ty::ReLateBound(index, ..) => { - if index >= self.binder_index { - bug!("escaping late-bound region during canonicalization"); - } else { - r - } - } - - ty::ReVar(vid) => { - let r = self - .infcx - .unwrap() - .inner - .borrow_mut() - .unwrap_region_constraints() - .opportunistic_resolve_var(self.tcx, vid); - debug!( - "canonical: region var found with vid {:?}, \ - opportunistically resolved to {:?}", - vid, r - ); - self.canonicalize_region_mode.canonicalize_free_region(self, r) - } - - ty::ReStatic - | ty::ReEarlyBound(..) - | ty::ReFree(_) - | ty::ReScope(_) - | ty::ReEmpty(_) - | ty::RePlaceholder(..) - | ty::ReErased => self.canonicalize_region_mode.canonicalize_free_region(self, r), - - ty::ReClosureBound(..) => { - bug!("closure bound region encountered during canonicalization"); - } - } - } - - fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - match t.kind { - ty::Infer(ty::TyVar(vid)) => { - debug!("canonical: type var found with vid {:?}", vid); - match self.infcx.unwrap().probe_ty_var(vid) { - // `t` could be a float / int variable; canonicalize that instead. - Ok(t) => { - debug!("(resolved to {:?})", t); - self.fold_ty(t) - } - - // `TyVar(vid)` is unresolved, track its universe index in the canonicalized - // result. - Err(mut ui) => { - if !self.infcx.unwrap().tcx.sess.opts.debugging_opts.chalk { - // FIXME: perf problem described in #55921. - ui = ty::UniverseIndex::ROOT; - } - self.canonicalize_ty_var( - CanonicalVarInfo { - kind: CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)), - }, - t, - ) - } - } - } - - ty::Infer(ty::IntVar(_)) => self.canonicalize_ty_var( - CanonicalVarInfo { kind: CanonicalVarKind::Ty(CanonicalTyVarKind::Int) }, - t, - ), - - ty::Infer(ty::FloatVar(_)) => self.canonicalize_ty_var( - CanonicalVarInfo { kind: CanonicalVarKind::Ty(CanonicalTyVarKind::Float) }, - t, - ), - - ty::Infer(ty::FreshTy(_)) - | ty::Infer(ty::FreshIntTy(_)) - | ty::Infer(ty::FreshFloatTy(_)) => { - bug!("encountered a fresh type during canonicalization") - } - - ty::Placeholder(placeholder) => self.canonicalize_ty_var( - CanonicalVarInfo { kind: CanonicalVarKind::PlaceholderTy(placeholder) }, - t, - ), - - ty::Bound(debruijn, _) => { - if debruijn >= self.binder_index { - bug!("escaping bound type during canonicalization") - } else { - t - } - } - - ty::Closure(..) - | ty::Generator(..) - | ty::GeneratorWitness(..) - | ty::Bool - | ty::Char - | ty::Int(..) - | ty::Uint(..) - | ty::Float(..) - | ty::Adt(..) - | ty::Str - | ty::Error - | ty::Array(..) - | ty::Slice(..) - | ty::RawPtr(..) - | ty::Ref(..) - | ty::FnDef(..) - | ty::FnPtr(_) - | ty::Dynamic(..) - | ty::Never - | ty::Tuple(..) - | ty::Projection(..) - | ty::UnnormalizedProjection(..) - | ty::Foreign(..) - | ty::Param(..) - | ty::Opaque(..) => { - if t.flags.intersects(self.needs_canonical_flags) { - t.super_fold_with(self) - } else { - t - } - } - } - } - - fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { - match ct.val { - ty::ConstKind::Infer(InferConst::Var(vid)) => { - debug!("canonical: const var found with vid {:?}", vid); - match self.infcx.unwrap().probe_const_var(vid) { - Ok(c) => { - debug!("(resolved to {:?})", c); - return self.fold_const(c); - } - - // `ConstVar(vid)` is unresolved, track its universe index in the - // canonicalized result - Err(mut ui) => { - if !self.infcx.unwrap().tcx.sess.opts.debugging_opts.chalk { - // FIXME: perf problem described in #55921. - ui = ty::UniverseIndex::ROOT; - } - return self.canonicalize_const_var( - CanonicalVarInfo { kind: CanonicalVarKind::Const(ui) }, - ct, - ); - } - } - } - ty::ConstKind::Infer(InferConst::Fresh(_)) => { - bug!("encountered a fresh const during canonicalization") - } - ty::ConstKind::Bound(debruijn, _) => { - if debruijn >= self.binder_index { - bug!("escaping bound type during canonicalization") - } else { - return ct; - } - } - ty::ConstKind::Placeholder(placeholder) => { - return self.canonicalize_const_var( - CanonicalVarInfo { kind: CanonicalVarKind::PlaceholderConst(placeholder) }, - ct, - ); - } - _ => {} - } - - let flags = FlagComputation::for_const(ct); - if flags.intersects(self.needs_canonical_flags) { ct.super_fold_with(self) } else { ct } - } -} - -impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { - /// The main `canonicalize` method, shared impl of - /// `canonicalize_query` and `canonicalize_response`. - fn canonicalize<V>( - value: &V, - infcx: Option<&InferCtxt<'_, 'tcx>>, - tcx: TyCtxt<'tcx>, - canonicalize_region_mode: &dyn CanonicalizeRegionMode, - query_state: &mut OriginalQueryValues<'tcx>, - ) -> Canonicalized<'tcx, V> - where - V: TypeFoldable<'tcx>, - { - let needs_canonical_flags = if canonicalize_region_mode.any() { - TypeFlags::KEEP_IN_LOCAL_TCX | - TypeFlags::HAS_FREE_REGIONS | // `HAS_RE_PLACEHOLDER` implies `HAS_FREE_REGIONS` - TypeFlags::HAS_TY_PLACEHOLDER | - TypeFlags::HAS_CT_PLACEHOLDER - } else { - TypeFlags::KEEP_IN_LOCAL_TCX - | TypeFlags::HAS_RE_PLACEHOLDER - | TypeFlags::HAS_TY_PLACEHOLDER - | TypeFlags::HAS_CT_PLACEHOLDER - }; - - // Fast path: nothing that needs to be canonicalized. - if !value.has_type_flags(needs_canonical_flags) { - let canon_value = Canonical { - max_universe: ty::UniverseIndex::ROOT, - variables: List::empty(), - value: value.clone(), - }; - return canon_value; - } - - let mut canonicalizer = Canonicalizer { - infcx, - tcx, - canonicalize_region_mode, - needs_canonical_flags, - variables: SmallVec::new(), - query_state, - indices: FxHashMap::default(), - binder_index: ty::INNERMOST, - }; - let out_value = value.fold_with(&mut canonicalizer); - - // Once we have canonicalized `out_value`, it should not - // contain anything that ties it to this inference context - // anymore, so it should live in the global arena. - debug_assert!(!out_value.has_type_flags(TypeFlags::KEEP_IN_LOCAL_TCX)); - - let canonical_variables = tcx.intern_canonical_var_infos(&canonicalizer.variables); - - let max_universe = canonical_variables - .iter() - .map(|cvar| cvar.universe()) - .max() - .unwrap_or(ty::UniverseIndex::ROOT); - - Canonical { max_universe, variables: canonical_variables, value: out_value } - } - - /// Creates a canonical variable replacing `kind` from the input, - /// or returns an existing variable if `kind` has already been - /// seen. `kind` is expected to be an unbound variable (or - /// potentially a free region). - fn canonical_var(&mut self, info: CanonicalVarInfo, kind: GenericArg<'tcx>) -> BoundVar { - let Canonicalizer { variables, query_state, indices, .. } = self; - - let var_values = &mut query_state.var_values; - - // This code is hot. `variables` and `var_values` are usually small - // (fewer than 8 elements ~95% of the time). They are SmallVec's to - // avoid allocations in those cases. We also don't use `indices` to - // determine if a kind has been seen before until the limit of 8 has - // been exceeded, to also avoid allocations for `indices`. - let var = if !var_values.spilled() { - // `var_values` is stack-allocated. `indices` isn't used yet. Do a - // direct linear search of `var_values`. - if let Some(idx) = var_values.iter().position(|&k| k == kind) { - // `kind` is already present in `var_values`. - BoundVar::new(idx) - } else { - // `kind` isn't present in `var_values`. Append it. Likewise - // for `info` and `variables`. - variables.push(info); - var_values.push(kind); - assert_eq!(variables.len(), var_values.len()); - - // If `var_values` has become big enough to be heap-allocated, - // fill up `indices` to facilitate subsequent lookups. - if var_values.spilled() { - assert!(indices.is_empty()); - *indices = var_values - .iter() - .enumerate() - .map(|(i, &kind)| (kind, BoundVar::new(i))) - .collect(); - } - // The cv is the index of the appended element. - BoundVar::new(var_values.len() - 1) - } - } else { - // `var_values` is large. Do a hashmap search via `indices`. - *indices.entry(kind).or_insert_with(|| { - variables.push(info); - var_values.push(kind); - assert_eq!(variables.len(), var_values.len()); - BoundVar::new(variables.len() - 1) - }) - }; - - var - } - - /// Shorthand helper that creates a canonical region variable for - /// `r` (always in the root universe). The reason that we always - /// put these variables into the root universe is because this - /// method is used during **query construction:** in that case, we - /// are taking all the regions and just putting them into the most - /// generic context we can. This may generate solutions that don't - /// fit (e.g., that equate some region variable with a placeholder - /// it can't name) on the caller side, but that's ok, the caller - /// can figure that out. In the meantime, it maximizes our - /// caching. - /// - /// (This works because unification never fails -- and hence trait - /// selection is never affected -- due to a universe mismatch.) - fn canonical_var_for_region_in_root_universe( - &mut self, - r: ty::Region<'tcx>, - ) -> ty::Region<'tcx> { - self.canonical_var_for_region( - CanonicalVarInfo { kind: CanonicalVarKind::Region(ty::UniverseIndex::ROOT) }, - r, - ) - } - - /// Returns the universe in which `vid` is defined. - fn region_var_universe(&self, vid: ty::RegionVid) -> ty::UniverseIndex { - self.infcx.unwrap().inner.borrow_mut().unwrap_region_constraints().var_universe(vid) - } - - /// Creates a canonical variable (with the given `info`) - /// representing the region `r`; return a region referencing it. - fn canonical_var_for_region( - &mut self, - info: CanonicalVarInfo, - r: ty::Region<'tcx>, - ) -> ty::Region<'tcx> { - let var = self.canonical_var(info, r.into()); - let region = ty::ReLateBound(self.binder_index, ty::BoundRegion::BrAnon(var.as_u32())); - self.tcx().mk_region(region) - } - - /// Given a type variable `ty_var` of the given kind, first check - /// if `ty_var` is bound to anything; if so, canonicalize - /// *that*. Otherwise, create a new canonical variable for - /// `ty_var`. - fn canonicalize_ty_var(&mut self, info: CanonicalVarInfo, ty_var: Ty<'tcx>) -> Ty<'tcx> { - let infcx = self.infcx.expect("encountered ty-var without infcx"); - let bound_to = infcx.shallow_resolve(ty_var); - if bound_to != ty_var { - self.fold_ty(bound_to) - } else { - let var = self.canonical_var(info, ty_var.into()); - self.tcx().mk_ty(ty::Bound(self.binder_index, var.into())) - } - } - - /// Given a type variable `const_var` of the given kind, first check - /// if `const_var` is bound to anything; if so, canonicalize - /// *that*. Otherwise, create a new canonical variable for - /// `const_var`. - fn canonicalize_const_var( - &mut self, - info: CanonicalVarInfo, - const_var: &'tcx ty::Const<'tcx>, - ) -> &'tcx ty::Const<'tcx> { - let infcx = self.infcx.expect("encountered const-var without infcx"); - let bound_to = infcx.shallow_resolve(const_var); - if bound_to != const_var { - self.fold_const(bound_to) - } else { - let var = self.canonical_var(info, const_var.into()); - self.tcx().mk_const(ty::Const { - val: ty::ConstKind::Bound(self.binder_index, var.into()), - ty: self.fold_ty(const_var.ty), - }) - } - } -} diff --git a/src/librustc/infer/canonical/mod.rs b/src/librustc/infer/canonical/mod.rs deleted file mode 100644 index f157d805bcd..00000000000 --- a/src/librustc/infer/canonical/mod.rs +++ /dev/null @@ -1,164 +0,0 @@ -//! **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::{ConstVariableOrigin, ConstVariableOriginKind}; -use crate::infer::{InferCtxt, RegionVariableOrigin, TypeVariableOrigin, TypeVariableOriginKind}; -use rustc::ty::fold::TypeFoldable; -use rustc::ty::subst::GenericArg; -use rustc::ty::{self, BoundVar, List}; -use rustc_index::vec::IndexVec; -use rustc_span::source_map::Span; - -pub use rustc::infer::types::canonical::*; - -mod canonicalizer; - -pub mod query_response; - -mod substitute; - -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. - /// Returns both the instantiated result *and* the substitution S. - /// - /// This is only meant to be invoked as part of constructing an - /// inference context at the start of a query (see - /// `InferCtxtBuilder::enter_with_canonical`). It basically - /// brings the canonical value "into scope" within your new infcx. - /// - /// At the end of processing, the substitution S (once - /// canonicalized) then represents the values that you computed - /// for each of the canonical inputs to your query. - - pub fn instantiate_canonical_with_fresh_inference_vars<T>( - &self, - span: Span, - canonical: &Canonical<'tcx, T>, - ) -> (T, CanonicalVarValues<'tcx>) - where - T: TypeFoldable<'tcx>, - { - // For each universe that is referred to in the incoming - // query, create a universe in our local inference context. In - // practice, as of this writing, all queries have no universes - // in them, so this code has no effect, but it is looking - // forward to the day when we *do* want to carry universes - // through into queries. - let universes: IndexVec<ty::UniverseIndex, _> = std::iter::once(ty::UniverseIndex::ROOT) - .chain((0..canonical.max_universe.as_u32()).map(|_| self.create_next_universe())) - .collect(); - - let canonical_inference_vars = - self.instantiate_canonical_vars(span, canonical.variables, |ui| universes[ui]); - let result = canonical.substitute(self.tcx, &canonical_inference_vars); - (result, canonical_inference_vars) - } - - /// Given the "infos" about the canonical variables from some - /// canonical, creates fresh variables with the same - /// characteristics (see `instantiate_canonical_var` for - /// details). You can then use `substitute` to instantiate the - /// canonical variable with these inference variables. - fn instantiate_canonical_vars( - &self, - span: Span, - variables: &List<CanonicalVarInfo>, - universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex, - ) -> CanonicalVarValues<'tcx> { - let var_values: IndexVec<BoundVar, GenericArg<'tcx>> = variables - .iter() - .map(|info| self.instantiate_canonical_var(span, *info, &universe_map)) - .collect(); - - CanonicalVarValues { var_values } - } - - /// Given the "info" about a canonical variable, creates a fresh - /// variable for it. If this is an existentially quantified - /// variable, then you'll get a new inference variable; if it is a - /// universally quantified variable, you get a placeholder. - fn instantiate_canonical_var( - &self, - span: Span, - cv_info: CanonicalVarInfo, - universe_map: impl Fn(ty::UniverseIndex) -> ty::UniverseIndex, - ) -> GenericArg<'tcx> { - match cv_info.kind { - CanonicalVarKind::Ty(ty_kind) => { - let ty = match ty_kind { - CanonicalTyVarKind::General(ui) => self.next_ty_var_in_universe( - TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span }, - universe_map(ui), - ), - - CanonicalTyVarKind::Int => self.next_int_var(), - - CanonicalTyVarKind::Float => self.next_float_var(), - }; - ty.into() - } - - CanonicalVarKind::PlaceholderTy(ty::PlaceholderType { universe, name }) => { - let universe_mapped = universe_map(universe); - let placeholder_mapped = ty::PlaceholderType { universe: universe_mapped, name }; - self.tcx.mk_ty(ty::Placeholder(placeholder_mapped)).into() - } - - CanonicalVarKind::Region(ui) => self - .next_region_var_in_universe( - RegionVariableOrigin::MiscVariable(span), - universe_map(ui), - ) - .into(), - - CanonicalVarKind::PlaceholderRegion(ty::PlaceholderRegion { universe, name }) => { - let universe_mapped = universe_map(universe); - let placeholder_mapped = ty::PlaceholderRegion { universe: universe_mapped, name }; - self.tcx.mk_region(ty::RePlaceholder(placeholder_mapped)).into() - } - - CanonicalVarKind::Const(ui) => self - .next_const_var_in_universe( - self.next_ty_var_in_universe( - TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span }, - universe_map(ui), - ), - ConstVariableOrigin { kind: ConstVariableOriginKind::MiscVariable, span }, - universe_map(ui), - ) - .into(), - - CanonicalVarKind::PlaceholderConst(ty::PlaceholderConst { universe, name }) => { - let universe_mapped = universe_map(universe); - let placeholder_mapped = ty::PlaceholderConst { universe: universe_mapped, name }; - self.tcx - .mk_const(ty::Const { - val: ty::ConstKind::Placeholder(placeholder_mapped), - ty: self.tcx.types.err, // FIXME(const_generics) - }) - .into() - } - } - } -} diff --git a/src/librustc/infer/canonical/query_response.rs b/src/librustc/infer/canonical/query_response.rs deleted file mode 100644 index 012900f8af5..00000000000 --- a/src/librustc/infer/canonical/query_response.rs +++ /dev/null @@ -1,658 +0,0 @@ -//! This module contains the code to instantiate a "query result", and -//! in particular to extract out the resulting region obligations and -//! encode them therein. -//! -//! For an overview of what canonicaliation is and how it fits into -//! rustc, check out the [chapter in the rustc guide][c]. -//! -//! [c]: https://rust-lang.github.io/rustc-guide/traits/canonicalization.html - -use crate::arena::ArenaAllocatable; -use crate::infer::canonical::substitute::substitute_value; -use crate::infer::canonical::{ - Canonical, CanonicalVarValues, CanonicalizedQueryResponse, Certainty, OriginalQueryValues, - QueryOutlivesConstraint, QueryRegionConstraints, QueryResponse, -}; -use crate::infer::region_constraints::{Constraint, RegionConstraintData}; -use crate::infer::InferCtxtBuilder; -use crate::infer::{InferCtxt, InferOk, InferResult}; -use crate::traits::query::{Fallible, NoSolution}; -use crate::traits::TraitEngine; -use crate::traits::{Obligation, ObligationCause, PredicateObligation}; -use crate::ty::fold::TypeFoldable; -use crate::ty::subst::{GenericArg, GenericArgKind}; -use crate::ty::{self, BoundVar, Ty, TyCtxt}; -use rustc_data_structures::captures::Captures; -use rustc_index::vec::Idx; -use rustc_index::vec::IndexVec; -use rustc_span::DUMMY_SP; -use std::fmt::Debug; - -impl<'tcx> InferCtxtBuilder<'tcx> { - /// The "main method" for a canonicalized trait query. Given the - /// canonical key `canonical_key`, this method will create a new - /// inference context, instantiate the key, and run your operation - /// `op`. The operation should yield up a result (of type `R`) as - /// well as a set of trait obligations that must be fully - /// satisfied. These obligations will be processed and the - /// canonical result created. - /// - /// Returns `NoSolution` in the event of any error. - /// - /// (It might be mildly nicer to implement this on `TyCtxt`, and - /// not `InferCtxtBuilder`, but that is a bit tricky right now. - /// In part because we would need a `for<'tcx>` sort of - /// bound for the closure and in part because it is convenient to - /// have `'tcx` be free on this function so that we can talk about - /// `K: TypeFoldable<'tcx>`.) - pub fn enter_canonical_trait_query<K, R>( - &mut self, - canonical_key: &Canonical<'tcx, K>, - operation: impl FnOnce(&InferCtxt<'_, 'tcx>, &mut dyn TraitEngine<'tcx>, K) -> Fallible<R>, - ) -> Fallible<CanonicalizedQueryResponse<'tcx, R>> - where - K: TypeFoldable<'tcx>, - R: Debug + TypeFoldable<'tcx>, - Canonical<'tcx, QueryResponse<'tcx, R>>: ArenaAllocatable, - { - self.enter_with_canonical( - DUMMY_SP, - canonical_key, - |ref infcx, key, canonical_inference_vars| { - let mut fulfill_cx = TraitEngine::new(infcx.tcx); - let value = operation(infcx, &mut *fulfill_cx, key)?; - infcx.make_canonicalized_query_response( - canonical_inference_vars, - value, - &mut *fulfill_cx, - ) - }, - ) - } -} - -impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { - /// This method is meant to be invoked as the final step of a canonical query - /// implementation. It is given: - /// - /// - the instantiated variables `inference_vars` created from the query key - /// - the result `answer` of the query - /// - a fulfillment context `fulfill_cx` that may contain various obligations which - /// have yet to be proven. - /// - /// Given this, the function will process the obligations pending - /// in `fulfill_cx`: - /// - /// - If all the obligations can be proven successfully, it will - /// package up any resulting region obligations (extracted from - /// `infcx`) along with the fully resolved value `answer` into a - /// query result (which is then itself canonicalized). - /// - If some obligations can be neither proven nor disproven, then - /// the same thing happens, but the resulting query is marked as ambiguous. - /// - Finally, if any of the obligations result in a hard error, - /// then `Err(NoSolution)` is returned. - pub fn make_canonicalized_query_response<T>( - &self, - inference_vars: CanonicalVarValues<'tcx>, - answer: T, - fulfill_cx: &mut dyn TraitEngine<'tcx>, - ) -> Fallible<CanonicalizedQueryResponse<'tcx, T>> - where - T: Debug + TypeFoldable<'tcx>, - Canonical<'tcx, QueryResponse<'tcx, T>>: ArenaAllocatable, - { - let query_response = self.make_query_response(inference_vars, answer, fulfill_cx)?; - let canonical_result = self.canonicalize_response(&query_response); - - debug!("make_canonicalized_query_response: canonical_result = {:#?}", canonical_result); - - Ok(self.tcx.arena.alloc(canonical_result)) - } - - /// A version of `make_canonicalized_query_response` that does - /// not pack in obligations, for contexts that want to drop - /// pending obligations instead of treating them as an ambiguity (e.g. - /// typeck "probing" contexts). - /// - /// If you DO want to keep track of pending obligations (which - /// include all region obligations, so this includes all cases - /// that care about regions) with this function, you have to - /// do it yourself, by e.g., having them be a part of the answer. - pub fn make_query_response_ignoring_pending_obligations<T>( - &self, - inference_vars: CanonicalVarValues<'tcx>, - answer: T, - ) -> Canonical<'tcx, QueryResponse<'tcx, T>> - where - T: Debug + TypeFoldable<'tcx>, - { - self.canonicalize_response(&QueryResponse { - var_values: inference_vars, - region_constraints: QueryRegionConstraints::default(), - certainty: Certainty::Proven, // Ambiguities are OK! - value: answer, - }) - } - - /// Helper for `make_canonicalized_query_response` that does - /// everything up until the final canonicalization. - fn make_query_response<T>( - &self, - inference_vars: CanonicalVarValues<'tcx>, - answer: T, - fulfill_cx: &mut dyn TraitEngine<'tcx>, - ) -> Result<QueryResponse<'tcx, T>, NoSolution> - where - T: Debug + TypeFoldable<'tcx>, - { - let tcx = self.tcx; - - debug!( - "make_query_response(\ - inference_vars={:?}, \ - answer={:?})", - inference_vars, answer, - ); - - // Select everything, returning errors. - let true_errors = fulfill_cx.select_where_possible(self).err().unwrap_or_else(Vec::new); - debug!("true_errors = {:#?}", true_errors); - - if !true_errors.is_empty() { - // FIXME -- we don't indicate *why* we failed to solve - debug!("make_query_response: true_errors={:#?}", true_errors); - return Err(NoSolution); - } - - // Anything left unselected *now* must be an ambiguity. - let ambig_errors = fulfill_cx.select_all_or_error(self).err().unwrap_or_else(Vec::new); - debug!("ambig_errors = {:#?}", ambig_errors); - - let region_obligations = self.take_registered_region_obligations(); - let region_constraints = self.with_region_constraints(|region_constraints| { - make_query_region_constraints( - tcx, - region_obligations.iter().map(|(_, r_o)| (r_o.sup_type, r_o.sub_region)), - region_constraints, - ) - }); - - let certainty = - if ambig_errors.is_empty() { Certainty::Proven } else { Certainty::Ambiguous }; - - Ok(QueryResponse { - var_values: inference_vars, - region_constraints, - certainty, - value: answer, - }) - } - - /// Given the (canonicalized) result to a canonical query, - /// instantiates the result so it can be used, plugging in the - /// values from the canonical query. (Note that the result may - /// have been ambiguous; you should check the certainty level of - /// the query before applying this function.) - /// - /// To get a good understanding of what is happening here, check - /// out the [chapter in the rustc guide][c]. - /// - /// [c]: https://rust-lang.github.io/rustc-guide/traits/canonicalization.html#processing-the-canonicalized-query-result - pub fn instantiate_query_response_and_region_obligations<R>( - &self, - cause: &ObligationCause<'tcx>, - param_env: ty::ParamEnv<'tcx>, - original_values: &OriginalQueryValues<'tcx>, - query_response: &Canonical<'tcx, QueryResponse<'tcx, R>>, - ) -> InferResult<'tcx, R> - where - R: Debug + TypeFoldable<'tcx>, - { - let InferOk { value: result_subst, mut obligations } = - self.query_response_substitution(cause, param_env, original_values, query_response)?; - - obligations.extend(self.query_outlives_constraints_into_obligations( - cause, - param_env, - &query_response.value.region_constraints.outlives, - &result_subst, - )); - - let user_result: R = - query_response.substitute_projected(self.tcx, &result_subst, |q_r| &q_r.value); - - Ok(InferOk { value: user_result, obligations }) - } - - /// An alternative to - /// `instantiate_query_response_and_region_obligations` that is more - /// efficient for NLL. NLL is a bit more advanced in the - /// "transition to chalk" than the rest of the compiler. During - /// the NLL type check, all of the "processing" of types and - /// things happens in queries -- the NLL checker itself is only - /// interested in the region obligations (`'a: 'b` or `T: 'b`) - /// that come out of these queries, which it wants to convert into - /// MIR-based constraints and solve. Therefore, it is most - /// convenient for the NLL Type Checker to **directly consume** - /// the `QueryOutlivesConstraint` values that arise from doing a - /// query. This is contrast to other parts of the compiler, which - /// would prefer for those `QueryOutlivesConstraint` to be converted - /// into the older infcx-style constraints (e.g., calls to - /// `sub_regions` or `register_region_obligation`). - /// - /// Therefore, `instantiate_nll_query_response_and_region_obligations` performs the same - /// basic operations as `instantiate_query_response_and_region_obligations` but - /// it returns its result differently: - /// - /// - It creates a substitution `S` that maps from the original - /// query variables to the values computed in the query - /// result. If any errors arise, they are propagated back as an - /// `Err` result. - /// - In the case of a successful substitution, we will append - /// `QueryOutlivesConstraint` values onto the - /// `output_query_region_constraints` vector for the solver to - /// use (if an error arises, some values may also be pushed, but - /// they should be ignored). - /// - It **can happen** (though it rarely does currently) that - /// equating types and things will give rise to subobligations - /// that must be processed. In this case, those subobligations - /// are propagated back in the return value. - /// - Finally, the query result (of type `R`) is propagated back, - /// after applying the substitution `S`. - pub fn instantiate_nll_query_response_and_region_obligations<R>( - &self, - cause: &ObligationCause<'tcx>, - param_env: ty::ParamEnv<'tcx>, - original_values: &OriginalQueryValues<'tcx>, - query_response: &Canonical<'tcx, QueryResponse<'tcx, R>>, - output_query_region_constraints: &mut QueryRegionConstraints<'tcx>, - ) -> InferResult<'tcx, R> - where - R: Debug + TypeFoldable<'tcx>, - { - let result_subst = - self.query_response_substitution_guess(cause, original_values, query_response); - - // Compute `QueryOutlivesConstraint` values that unify each of - // the original values `v_o` that was canonicalized into a - // variable... - let mut obligations = vec![]; - - for (index, original_value) in original_values.var_values.iter().enumerate() { - // ...with the value `v_r` of that variable from the query. - let result_value = query_response.substitute_projected(self.tcx, &result_subst, |v| { - &v.var_values[BoundVar::new(index)] - }); - match (original_value.unpack(), result_value.unpack()) { - ( - GenericArgKind::Lifetime(ty::ReErased), - GenericArgKind::Lifetime(ty::ReErased), - ) => { - // No action needed. - } - - (GenericArgKind::Lifetime(v_o), GenericArgKind::Lifetime(v_r)) => { - // To make `v_o = v_r`, we emit `v_o: v_r` and `v_r: v_o`. - if v_o != v_r { - output_query_region_constraints - .outlives - .push(ty::Binder::dummy(ty::OutlivesPredicate(v_o.into(), v_r))); - output_query_region_constraints - .outlives - .push(ty::Binder::dummy(ty::OutlivesPredicate(v_r.into(), v_o))); - } - } - - (GenericArgKind::Type(v1), GenericArgKind::Type(v2)) => { - let ok = self.at(cause, param_env).eq(v1, v2)?; - obligations.extend(ok.into_obligations()); - } - - (GenericArgKind::Const(v1), GenericArgKind::Const(v2)) => { - let ok = self.at(cause, param_env).eq(v1, v2)?; - obligations.extend(ok.into_obligations()); - } - - _ => { - bug!("kind mismatch, cannot unify {:?} and {:?}", original_value, result_value); - } - } - } - - // ...also include the other query region constraints from the query. - output_query_region_constraints.outlives.extend( - query_response.value.region_constraints.outlives.iter().filter_map(|r_c| { - let r_c = substitute_value(self.tcx, &result_subst, r_c); - - // Screen out `'a: 'a` cases -- we skip the binder here but - // only compare the inner values to one another, so they are still at - // consistent binding levels. - let &ty::OutlivesPredicate(k1, r2) = r_c.skip_binder(); - if k1 != r2.into() { Some(r_c) } else { None } - }), - ); - - // ...also include the query member constraints. - output_query_region_constraints.member_constraints.extend( - query_response - .value - .region_constraints - .member_constraints - .iter() - .map(|p_c| substitute_value(self.tcx, &result_subst, p_c)), - ); - - let user_result: R = - query_response.substitute_projected(self.tcx, &result_subst, |q_r| &q_r.value); - - Ok(InferOk { value: user_result, obligations }) - } - - /// Given the original values and the (canonicalized) result from - /// computing a query, returns a substitution that can be applied - /// to the query result to convert the result back into the - /// original namespace. - /// - /// The substitution also comes accompanied with subobligations - /// that arose from unification; these might occur if (for - /// example) we are doing lazy normalization and the value - /// assigned to a type variable is unified with an unnormalized - /// projection. - fn query_response_substitution<R>( - &self, - cause: &ObligationCause<'tcx>, - param_env: ty::ParamEnv<'tcx>, - original_values: &OriginalQueryValues<'tcx>, - query_response: &Canonical<'tcx, QueryResponse<'tcx, R>>, - ) -> InferResult<'tcx, CanonicalVarValues<'tcx>> - where - R: Debug + TypeFoldable<'tcx>, - { - debug!( - "query_response_substitution(original_values={:#?}, query_response={:#?})", - original_values, query_response, - ); - - let result_subst = - self.query_response_substitution_guess(cause, original_values, query_response); - - let obligations = self - .unify_query_response_substitution_guess( - cause, - param_env, - original_values, - &result_subst, - query_response, - )? - .into_obligations(); - - Ok(InferOk { value: result_subst, obligations }) - } - - /// Given the original values and the (canonicalized) result from - /// computing a query, returns a **guess** at a substitution that - /// can be applied to the query result to convert the result back - /// into the original namespace. This is called a **guess** - /// because it uses a quick heuristic to find the values for each - /// canonical variable; if that quick heuristic fails, then we - /// will instantiate fresh inference variables for each canonical - /// variable instead. Therefore, the result of this method must be - /// properly unified - fn query_response_substitution_guess<R>( - &self, - cause: &ObligationCause<'tcx>, - original_values: &OriginalQueryValues<'tcx>, - query_response: &Canonical<'tcx, QueryResponse<'tcx, R>>, - ) -> CanonicalVarValues<'tcx> - where - R: Debug + TypeFoldable<'tcx>, - { - debug!( - "query_response_substitution_guess(original_values={:#?}, query_response={:#?})", - original_values, query_response, - ); - - // For each new universe created in the query result that did - // not appear in the original query, create a local - // superuniverse. - let mut universe_map = original_values.universe_map.clone(); - let num_universes_in_query = original_values.universe_map.len(); - let num_universes_in_response = query_response.max_universe.as_usize() + 1; - for _ in num_universes_in_query..num_universes_in_response { - universe_map.push(self.create_next_universe()); - } - assert!(universe_map.len() >= 1); // always have the root universe - assert_eq!(universe_map[ty::UniverseIndex::ROOT.as_usize()], ty::UniverseIndex::ROOT); - - // Every canonical query result includes values for each of - // the inputs to the query. Therefore, we begin by unifying - // these values with the original inputs that were - // canonicalized. - let result_values = &query_response.value.var_values; - assert_eq!(original_values.var_values.len(), result_values.len()); - - // Quickly try to find initial values for the canonical - // variables in the result in terms of the query. We do this - // by iterating down the values that the query gave to each of - // the canonical inputs. If we find that one of those values - // is directly equal to one of the canonical variables in the - // result, then we can type the corresponding value from the - // input. See the example above. - let mut opt_values: IndexVec<BoundVar, Option<GenericArg<'tcx>>> = - IndexVec::from_elem_n(None, query_response.variables.len()); - - // In terms of our example above, we are iterating over pairs like: - // [(?A, Vec<?0>), ('static, '?1), (?B, ?0)] - for (original_value, result_value) in original_values.var_values.iter().zip(result_values) { - match result_value.unpack() { - GenericArgKind::Type(result_value) => { - // e.g., here `result_value` might be `?0` in the example above... - if let ty::Bound(debruijn, b) = result_value.kind { - // ...in which case we would set `canonical_vars[0]` to `Some(?U)`. - - // We only allow a `ty::INNERMOST` index in substitutions. - assert_eq!(debruijn, ty::INNERMOST); - opt_values[b.var] = Some(*original_value); - } - } - GenericArgKind::Lifetime(result_value) => { - // e.g., here `result_value` might be `'?1` in the example above... - if let &ty::RegionKind::ReLateBound(debruijn, br) = result_value { - // ... in which case we would set `canonical_vars[0]` to `Some('static)`. - - // We only allow a `ty::INNERMOST` index in substitutions. - assert_eq!(debruijn, ty::INNERMOST); - opt_values[br.assert_bound_var()] = Some(*original_value); - } - } - GenericArgKind::Const(result_value) => { - if let ty::Const { val: ty::ConstKind::Bound(debrujin, b), .. } = result_value { - // ...in which case we would set `canonical_vars[0]` to `Some(const X)`. - - // We only allow a `ty::INNERMOST` index in substitutions. - assert_eq!(*debrujin, ty::INNERMOST); - opt_values[*b] = Some(*original_value); - } - } - } - } - - // Create a result substitution: if we found a value for a - // given variable in the loop above, use that. Otherwise, use - // a fresh inference variable. - let result_subst = CanonicalVarValues { - var_values: query_response - .variables - .iter() - .enumerate() - .map(|(index, info)| { - if info.is_existential() { - match opt_values[BoundVar::new(index)] { - Some(k) => k, - None => self.instantiate_canonical_var(cause.span, *info, |u| { - universe_map[u.as_usize()] - }), - } - } else { - self.instantiate_canonical_var(cause.span, *info, |u| { - universe_map[u.as_usize()] - }) - } - }) - .collect(), - }; - - result_subst - } - - /// Given a "guess" at the values for the canonical variables in - /// the input, try to unify with the *actual* values found in the - /// query result. Often, but not always, this is a no-op, because - /// we already found the mapping in the "guessing" step. - /// - /// See also: `query_response_substitution_guess` - fn unify_query_response_substitution_guess<R>( - &self, - cause: &ObligationCause<'tcx>, - param_env: ty::ParamEnv<'tcx>, - original_values: &OriginalQueryValues<'tcx>, - result_subst: &CanonicalVarValues<'tcx>, - query_response: &Canonical<'tcx, QueryResponse<'tcx, R>>, - ) -> InferResult<'tcx, ()> - where - R: Debug + TypeFoldable<'tcx>, - { - // A closure that yields the result value for the given - // canonical variable; this is taken from - // `query_response.var_values` after applying the substitution - // `result_subst`. - let substituted_query_response = |index: BoundVar| -> GenericArg<'tcx> { - query_response.substitute_projected(self.tcx, &result_subst, |v| &v.var_values[index]) - }; - - // Unify the original value for each variable with the value - // taken from `query_response` (after applying `result_subst`). - Ok(self.unify_canonical_vars( - cause, - param_env, - original_values, - substituted_query_response, - )?) - } - - /// Converts the region constraints resulting from a query into an - /// iterator of obligations. - fn query_outlives_constraints_into_obligations<'a>( - &'a self, - cause: &'a ObligationCause<'tcx>, - param_env: ty::ParamEnv<'tcx>, - unsubstituted_region_constraints: &'a [QueryOutlivesConstraint<'tcx>], - result_subst: &'a CanonicalVarValues<'tcx>, - ) -> impl Iterator<Item = PredicateObligation<'tcx>> + 'a + Captures<'tcx> { - unsubstituted_region_constraints.iter().map(move |constraint| { - let constraint = substitute_value(self.tcx, result_subst, constraint); - let &ty::OutlivesPredicate(k1, r2) = constraint.skip_binder(); // restored below - - Obligation::new( - cause.clone(), - param_env, - match k1.unpack() { - GenericArgKind::Lifetime(r1) => ty::Predicate::RegionOutlives( - ty::Binder::bind(ty::OutlivesPredicate(r1, r2)), - ), - GenericArgKind::Type(t1) => { - ty::Predicate::TypeOutlives(ty::Binder::bind(ty::OutlivesPredicate(t1, r2))) - } - GenericArgKind::Const(..) => { - // Consts cannot outlive one another, so we don't expect to - // ecounter this branch. - span_bug!(cause.span, "unexpected const outlives {:?}", constraint); - } - }, - ) - }) - } - - /// Given two sets of values for the same set of canonical variables, unify them. - /// The second set is produced lazily by supplying indices from the first set. - fn unify_canonical_vars( - &self, - cause: &ObligationCause<'tcx>, - param_env: ty::ParamEnv<'tcx>, - variables1: &OriginalQueryValues<'tcx>, - variables2: impl Fn(BoundVar) -> GenericArg<'tcx>, - ) -> InferResult<'tcx, ()> { - self.commit_if_ok(|_| { - let mut obligations = vec![]; - for (index, value1) in variables1.var_values.iter().enumerate() { - let value2 = variables2(BoundVar::new(index)); - - match (value1.unpack(), value2.unpack()) { - (GenericArgKind::Type(v1), GenericArgKind::Type(v2)) => { - obligations - .extend(self.at(cause, param_env).eq(v1, v2)?.into_obligations()); - } - ( - GenericArgKind::Lifetime(ty::ReErased), - GenericArgKind::Lifetime(ty::ReErased), - ) => { - // no action needed - } - (GenericArgKind::Lifetime(v1), GenericArgKind::Lifetime(v2)) => { - obligations - .extend(self.at(cause, param_env).eq(v1, v2)?.into_obligations()); - } - (GenericArgKind::Const(v1), GenericArgKind::Const(v2)) => { - let ok = self.at(cause, param_env).eq(v1, v2)?; - obligations.extend(ok.into_obligations()); - } - _ => { - bug!("kind mismatch, cannot unify {:?} and {:?}", value1, value2,); - } - } - } - Ok(InferOk { value: (), obligations }) - }) - } -} - -/// Given the region obligations and constraints scraped from the infcx, -/// creates query region constraints. -pub fn make_query_region_constraints<'tcx>( - tcx: TyCtxt<'tcx>, - outlives_obligations: impl Iterator<Item = (Ty<'tcx>, ty::Region<'tcx>)>, - region_constraints: &RegionConstraintData<'tcx>, -) -> QueryRegionConstraints<'tcx> { - let RegionConstraintData { constraints, verifys, givens, member_constraints } = - region_constraints; - - assert!(verifys.is_empty()); - assert!(givens.is_empty()); - - let outlives: Vec<_> = constraints - .into_iter() - .map(|(k, _)| match *k { - // Swap regions because we are going from sub (<=) to outlives - // (>=). - Constraint::VarSubVar(v1, v2) => ty::OutlivesPredicate( - tcx.mk_region(ty::ReVar(v2)).into(), - tcx.mk_region(ty::ReVar(v1)), - ), - Constraint::VarSubReg(v1, r2) => { - ty::OutlivesPredicate(r2.into(), tcx.mk_region(ty::ReVar(v1))) - } - Constraint::RegSubVar(r1, v2) => { - ty::OutlivesPredicate(tcx.mk_region(ty::ReVar(v2)).into(), r1) - } - Constraint::RegSubReg(r1, r2) => ty::OutlivesPredicate(r2.into(), r1), - }) - .map(ty::Binder::dummy) // no bound vars in the code above - .chain( - outlives_obligations - .map(|(ty, r)| ty::OutlivesPredicate(ty.into(), r)) - .map(ty::Binder::dummy), // no bound vars in the code above - ) - .collect(); - - QueryRegionConstraints { outlives, member_constraints: member_constraints.clone() } -} diff --git a/src/librustc/infer/canonical/substitute.rs b/src/librustc/infer/canonical/substitute.rs deleted file mode 100644 index 92516345633..00000000000 --- a/src/librustc/infer/canonical/substitute.rs +++ /dev/null @@ -1,77 +0,0 @@ -//! This module contains code to substitute new values into a -//! `Canonical<'tcx, T>`. -//! -//! For an overview of what canonicalization is and how it fits into -//! rustc, check out the [chapter in the rustc guide][c]. -//! -//! [c]: https://rust-lang.github.io/rustc-guide/traits/canonicalization.html - -use crate::infer::canonical::{Canonical, CanonicalVarValues}; -use crate::ty::fold::TypeFoldable; -use crate::ty::subst::GenericArgKind; -use crate::ty::{self, TyCtxt}; - -impl<'tcx, V> Canonical<'tcx, V> { - /// Instantiate the wrapped value, replacing each canonical value - /// with the value given in `var_values`. - pub fn substitute(&self, tcx: TyCtxt<'tcx>, var_values: &CanonicalVarValues<'tcx>) -> V - where - V: TypeFoldable<'tcx>, - { - self.substitute_projected(tcx, var_values, |value| value) - } - - /// Allows one to apply a substitute to some subset of - /// `self.value`. Invoke `projection_fn` with `self.value` to get - /// a value V that is expressed in terms of the same canonical - /// variables bound in `self` (usually this extracts from subset - /// of `self`). Apply the substitution `var_values` to this value - /// V, replacing each of the canonical variables. - pub fn substitute_projected<T>( - &self, - tcx: TyCtxt<'tcx>, - var_values: &CanonicalVarValues<'tcx>, - projection_fn: impl FnOnce(&V) -> &T, - ) -> T - where - T: TypeFoldable<'tcx>, - { - assert_eq!(self.variables.len(), var_values.len()); - let value = projection_fn(&self.value); - substitute_value(tcx, var_values, value) - } -} - -/// Substitute the values from `var_values` into `value`. `var_values` -/// must be values for the set of canonical variables that appear in -/// `value`. -pub(super) fn substitute_value<'a, 'tcx, T>( - tcx: TyCtxt<'tcx>, - var_values: &CanonicalVarValues<'tcx>, - value: &'a T, -) -> T -where - T: TypeFoldable<'tcx>, -{ - if var_values.var_values.is_empty() { - value.clone() - } else { - let fld_r = - |br: ty::BoundRegion| match var_values.var_values[br.assert_bound_var()].unpack() { - GenericArgKind::Lifetime(l) => l, - r => bug!("{:?} is a region but value is {:?}", br, r), - }; - - let fld_t = |bound_ty: ty::BoundTy| match var_values.var_values[bound_ty.var].unpack() { - GenericArgKind::Type(ty) => ty, - r => bug!("{:?} is a type but value is {:?}", bound_ty, r), - }; - - let fld_c = |bound_ct: ty::BoundVar, _| match var_values.var_values[bound_ct].unpack() { - GenericArgKind::Const(ct) => ct, - c => bug!("{:?} is a const but value is {:?}", bound_ct, c), - }; - - tcx.replace_escaping_bound_vars(value, fld_r, fld_t, fld_c).0 - } -} diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs deleted file mode 100644 index 9eb961255c2..00000000000 --- a/src/librustc/infer/combine.rs +++ /dev/null @@ -1,683 +0,0 @@ -/////////////////////////////////////////////////////////////////////////// -// # Type combining -// -// There are four type combiners: equate, sub, lub, and glb. Each -// implements the trait `Combine` and contains methods for combining -// two instances of various things and yielding a new instance. These -// combiner methods always yield a `Result<T>`. There is a lot of -// common code for these operations, implemented as default methods on -// the `Combine` trait. -// -// Each operation may have side-effects on the inference context, -// though these can be unrolled using snapshots. On success, the -// LUB/GLB operations return the appropriate bound. The Eq and Sub -// operations generally return the first operand. -// -// ## Contravariance -// -// When you are relating two things which have a contravariant -// relationship, you should use `contratys()` or `contraregions()`, -// rather than inversing the order of arguments! This is necessary -// because the order of arguments is not relevant for LUB and GLB. It -// is also useful to track which value is the "expected" value in -// terms of error reporting. - -use super::equate::Equate; -use super::glb::Glb; -use super::lub::Lub; -use super::sub::Sub; -use super::type_variable::TypeVariableValue; -use super::unify_key::replace_if_possible; -use super::unify_key::{ConstVarValue, ConstVariableValue}; -use super::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; -use super::{InferCtxt, MiscVariable, TypeTrace}; - -use crate::traits::{Obligation, PredicateObligations}; -use crate::ty::error::TypeError; -use crate::ty::relate::{self, Relate, RelateResult, TypeRelation}; -use crate::ty::subst::SubstsRef; -use crate::ty::{self, InferConst, Ty, TyCtxt}; -use crate::ty::{IntType, UintType}; - -use rustc_hir::def_id::DefId; -use rustc_span::{Span, DUMMY_SP}; -use syntax::ast; - -#[derive(Clone)] -pub struct CombineFields<'infcx, 'tcx> { - pub infcx: &'infcx InferCtxt<'infcx, 'tcx>, - pub trace: TypeTrace<'tcx>, - pub cause: Option<ty::relate::Cause>, - pub param_env: ty::ParamEnv<'tcx>, - pub obligations: PredicateObligations<'tcx>, -} - -#[derive(Copy, Clone, Debug)] -pub enum RelationDir { - SubtypeOf, - SupertypeOf, - EqTo, -} - -impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> { - pub fn super_combine_tys<R>( - &self, - relation: &mut R, - a: Ty<'tcx>, - b: Ty<'tcx>, - ) -> RelateResult<'tcx, Ty<'tcx>> - where - R: TypeRelation<'tcx>, - { - let a_is_expected = relation.a_is_expected(); - - match (&a.kind, &b.kind) { - // Relate integral variables to other types - (&ty::Infer(ty::IntVar(a_id)), &ty::Infer(ty::IntVar(b_id))) => { - self.inner - .borrow_mut() - .int_unification_table - .unify_var_var(a_id, b_id) - .map_err(|e| int_unification_error(a_is_expected, e))?; - Ok(a) - } - (&ty::Infer(ty::IntVar(v_id)), &ty::Int(v)) => { - self.unify_integral_variable(a_is_expected, v_id, IntType(v)) - } - (&ty::Int(v), &ty::Infer(ty::IntVar(v_id))) => { - self.unify_integral_variable(!a_is_expected, v_id, IntType(v)) - } - (&ty::Infer(ty::IntVar(v_id)), &ty::Uint(v)) => { - self.unify_integral_variable(a_is_expected, v_id, UintType(v)) - } - (&ty::Uint(v), &ty::Infer(ty::IntVar(v_id))) => { - self.unify_integral_variable(!a_is_expected, v_id, UintType(v)) - } - - // Relate floating-point variables to other types - (&ty::Infer(ty::FloatVar(a_id)), &ty::Infer(ty::FloatVar(b_id))) => { - self.inner - .borrow_mut() - .float_unification_table - .unify_var_var(a_id, b_id) - .map_err(|e| float_unification_error(relation.a_is_expected(), e))?; - Ok(a) - } - (&ty::Infer(ty::FloatVar(v_id)), &ty::Float(v)) => { - self.unify_float_variable(a_is_expected, v_id, v) - } - (&ty::Float(v), &ty::Infer(ty::FloatVar(v_id))) => { - self.unify_float_variable(!a_is_expected, v_id, v) - } - - // All other cases of inference are errors - (&ty::Infer(_), _) | (_, &ty::Infer(_)) => { - Err(TypeError::Sorts(ty::relate::expected_found(relation, &a, &b))) - } - - _ => ty::relate::super_relate_tys(relation, a, b), - } - } - - pub fn super_combine_consts<R>( - &self, - relation: &mut R, - a: &'tcx ty::Const<'tcx>, - b: &'tcx ty::Const<'tcx>, - ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> - where - R: TypeRelation<'tcx>, - { - debug!("{}.consts({:?}, {:?})", relation.tag(), a, b); - if a == b { - return Ok(a); - } - - let a = replace_if_possible(&mut self.inner.borrow_mut().const_unification_table, a); - let b = replace_if_possible(&mut self.inner.borrow_mut().const_unification_table, b); - - let a_is_expected = relation.a_is_expected(); - - match (a.val, b.val) { - ( - ty::ConstKind::Infer(InferConst::Var(a_vid)), - ty::ConstKind::Infer(InferConst::Var(b_vid)), - ) => { - self.inner - .borrow_mut() - .const_unification_table - .unify_var_var(a_vid, b_vid) - .map_err(|e| const_unification_error(a_is_expected, e))?; - return Ok(a); - } - - // All other cases of inference with other variables are errors. - (ty::ConstKind::Infer(InferConst::Var(_)), ty::ConstKind::Infer(_)) - | (ty::ConstKind::Infer(_), ty::ConstKind::Infer(InferConst::Var(_))) => { - bug!("tried to combine ConstKind::Infer/ConstKind::Infer(InferConst::Var)") - } - - (ty::ConstKind::Infer(InferConst::Var(vid)), _) => { - return self.unify_const_variable(a_is_expected, vid, b); - } - - (_, ty::ConstKind::Infer(InferConst::Var(vid))) => { - return self.unify_const_variable(!a_is_expected, vid, a); - } - - _ => {} - } - - ty::relate::super_relate_consts(relation, a, b) - } - - pub fn unify_const_variable( - &self, - vid_is_expected: bool, - vid: ty::ConstVid<'tcx>, - value: &'tcx ty::Const<'tcx>, - ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> { - self.inner - .borrow_mut() - .const_unification_table - .unify_var_value( - vid, - ConstVarValue { - origin: ConstVariableOrigin { - kind: ConstVariableOriginKind::ConstInference, - span: DUMMY_SP, - }, - val: ConstVariableValue::Known { value }, - }, - ) - .map_err(|e| const_unification_error(vid_is_expected, e))?; - Ok(value) - } - - fn unify_integral_variable( - &self, - vid_is_expected: bool, - vid: ty::IntVid, - val: ty::IntVarValue, - ) -> RelateResult<'tcx, Ty<'tcx>> { - self.inner - .borrow_mut() - .int_unification_table - .unify_var_value(vid, Some(val)) - .map_err(|e| int_unification_error(vid_is_expected, e))?; - match val { - IntType(v) => Ok(self.tcx.mk_mach_int(v)), - UintType(v) => Ok(self.tcx.mk_mach_uint(v)), - } - } - - fn unify_float_variable( - &self, - vid_is_expected: bool, - vid: ty::FloatVid, - val: ast::FloatTy, - ) -> RelateResult<'tcx, Ty<'tcx>> { - self.inner - .borrow_mut() - .float_unification_table - .unify_var_value(vid, Some(ty::FloatVarValue(val))) - .map_err(|e| float_unification_error(vid_is_expected, e))?; - Ok(self.tcx.mk_mach_float(val)) - } -} - -impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { - pub fn tcx(&self) -> TyCtxt<'tcx> { - self.infcx.tcx - } - - pub fn equate<'a>(&'a mut self, a_is_expected: bool) -> Equate<'a, 'infcx, 'tcx> { - Equate::new(self, a_is_expected) - } - - pub fn sub<'a>(&'a mut self, a_is_expected: bool) -> Sub<'a, 'infcx, 'tcx> { - Sub::new(self, a_is_expected) - } - - pub fn lub<'a>(&'a mut self, a_is_expected: bool) -> Lub<'a, 'infcx, 'tcx> { - Lub::new(self, a_is_expected) - } - - pub fn glb<'a>(&'a mut self, a_is_expected: bool) -> Glb<'a, 'infcx, 'tcx> { - Glb::new(self, a_is_expected) - } - - /// Here, `dir` is either `EqTo`, `SubtypeOf`, or `SupertypeOf`. - /// The idea is that we should ensure that the type `a_ty` is equal - /// to, a subtype of, or a supertype of (respectively) the type - /// to which `b_vid` is bound. - /// - /// Since `b_vid` has not yet been instantiated with a type, we - /// will first instantiate `b_vid` with a *generalized* version - /// of `a_ty`. Generalization introduces other inference - /// variables wherever subtyping could occur. - pub fn instantiate( - &mut self, - a_ty: Ty<'tcx>, - dir: RelationDir, - b_vid: ty::TyVid, - a_is_expected: bool, - ) -> RelateResult<'tcx, ()> { - use self::RelationDir::*; - - // Get the actual variable that b_vid has been inferred to - debug_assert!(self.infcx.inner.borrow_mut().type_variables.probe(b_vid).is_unknown()); - - debug!("instantiate(a_ty={:?} dir={:?} b_vid={:?})", a_ty, dir, b_vid); - - // Generalize type of `a_ty` appropriately depending on the - // direction. As an example, assume: - // - // - `a_ty == &'x ?1`, where `'x` is some free region and `?1` is an - // inference variable, - // - and `dir` == `SubtypeOf`. - // - // Then the generalized form `b_ty` would be `&'?2 ?3`, where - // `'?2` and `?3` are fresh region/type inference - // variables. (Down below, we will relate `a_ty <: b_ty`, - // adding constraints like `'x: '?2` and `?1 <: ?3`.) - let Generalization { ty: b_ty, needs_wf } = self.generalize(a_ty, b_vid, dir)?; - debug!( - "instantiate(a_ty={:?}, dir={:?}, b_vid={:?}, generalized b_ty={:?})", - a_ty, dir, b_vid, b_ty - ); - self.infcx.inner.borrow_mut().type_variables.instantiate(b_vid, b_ty); - - if needs_wf { - self.obligations.push(Obligation::new( - self.trace.cause.clone(), - self.param_env, - ty::Predicate::WellFormed(b_ty), - )); - } - - // Finally, relate `b_ty` to `a_ty`, as described in previous comment. - // - // FIXME(#16847): This code is non-ideal because all these subtype - // relations wind up attributed to the same spans. We need - // to associate causes/spans with each of the relations in - // the stack to get this right. - match dir { - EqTo => self.equate(a_is_expected).relate(&a_ty, &b_ty), - SubtypeOf => self.sub(a_is_expected).relate(&a_ty, &b_ty), - SupertypeOf => { - self.sub(a_is_expected).relate_with_variance(ty::Contravariant, &a_ty, &b_ty) - } - }?; - - Ok(()) - } - - /// Attempts to generalize `ty` for the type variable `for_vid`. - /// This checks for cycle -- that is, whether the type `ty` - /// references `for_vid`. The `dir` is the "direction" for which we - /// a performing the generalization (i.e., are we producing a type - /// that can be used as a supertype etc). - /// - /// Preconditions: - /// - /// - `for_vid` is a "root vid" - fn generalize( - &self, - ty: Ty<'tcx>, - for_vid: ty::TyVid, - dir: RelationDir, - ) -> RelateResult<'tcx, Generalization<'tcx>> { - debug!("generalize(ty={:?}, for_vid={:?}, dir={:?}", ty, for_vid, dir); - // Determine the ambient variance within which `ty` appears. - // The surrounding equation is: - // - // ty [op] ty2 - // - // where `op` is either `==`, `<:`, or `:>`. This maps quite - // naturally. - let ambient_variance = match dir { - RelationDir::EqTo => ty::Invariant, - RelationDir::SubtypeOf => ty::Covariant, - RelationDir::SupertypeOf => ty::Contravariant, - }; - - debug!("generalize: ambient_variance = {:?}", ambient_variance); - - let for_universe = match self.infcx.inner.borrow_mut().type_variables.probe(for_vid) { - v @ TypeVariableValue::Known { .. } => { - panic!("instantiating {:?} which has a known value {:?}", for_vid, v,) - } - TypeVariableValue::Unknown { universe } => universe, - }; - - debug!("generalize: for_universe = {:?}", for_universe); - - let mut generalize = Generalizer { - infcx: self.infcx, - span: self.trace.cause.span, - for_vid_sub_root: self.infcx.inner.borrow_mut().type_variables.sub_root_var(for_vid), - for_universe, - ambient_variance, - needs_wf: false, - root_ty: ty, - param_env: self.param_env, - }; - - let ty = match generalize.relate(&ty, &ty) { - Ok(ty) => ty, - Err(e) => { - debug!("generalize: failure {:?}", e); - return Err(e); - } - }; - let needs_wf = generalize.needs_wf; - debug!("generalize: success {{ {:?}, {:?} }}", ty, needs_wf); - Ok(Generalization { ty, needs_wf }) - } -} - -struct Generalizer<'cx, 'tcx> { - infcx: &'cx InferCtxt<'cx, 'tcx>, - - /// The span, used when creating new type variables and things. - span: Span, - - /// The vid of the type variable that is in the process of being - /// instantiated; if we find this within the type we are folding, - /// that means we would have created a cyclic type. - for_vid_sub_root: ty::TyVid, - - /// The universe of the type variable that is in the process of - /// being instantiated. Any fresh variables that we create in this - /// process should be in that same universe. - for_universe: ty::UniverseIndex, - - /// Track the variance as we descend into the type. - ambient_variance: ty::Variance, - - /// See the field `needs_wf` in `Generalization`. - needs_wf: bool, - - /// The root type that we are generalizing. Used when reporting cycles. - root_ty: Ty<'tcx>, - - param_env: ty::ParamEnv<'tcx>, -} - -/// Result from a generalization operation. This includes -/// not only the generalized type, but also a bool flag -/// indicating whether further WF checks are needed. -struct Generalization<'tcx> { - ty: Ty<'tcx>, - - /// If true, then the generalized type may not be well-formed, - /// even if the source type is well-formed, so we should add an - /// additional check to enforce that it is. This arises in - /// particular around 'bivariant' type parameters that are only - /// constrained by a where-clause. As an example, imagine a type: - /// - /// struct Foo<A, B> where A: Iterator<Item = B> { - /// data: A - /// } - /// - /// here, `A` will be covariant, but `B` is - /// unconstrained. However, whatever it is, for `Foo` to be WF, it - /// must be equal to `A::Item`. If we have an input `Foo<?A, ?B>`, - /// then after generalization we will wind up with a type like - /// `Foo<?C, ?D>`. When we enforce that `Foo<?A, ?B> <: Foo<?C, - /// ?D>` (or `>:`), we will wind up with the requirement that `?A - /// <: ?C`, but no particular relationship between `?B` and `?D` - /// (after all, we do not know the variance of the normalized form - /// of `A::Item` with respect to `A`). If we do nothing else, this - /// may mean that `?D` goes unconstrained (as in #41677). So, in - /// this scenario where we create a new type variable in a - /// bivariant context, we set the `needs_wf` flag to true. This - /// will force the calling code to check that `WF(Foo<?C, ?D>)` - /// holds, which in turn implies that `?C::Item == ?D`. So once - /// `?C` is constrained, that should suffice to restrict `?D`. - needs_wf: bool, -} - -impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> { - fn tcx(&self) -> TyCtxt<'tcx> { - self.infcx.tcx - } - fn param_env(&self) -> ty::ParamEnv<'tcx> { - self.param_env - } - - fn tag(&self) -> &'static str { - "Generalizer" - } - - fn a_is_expected(&self) -> bool { - true - } - - fn binders<T>( - &mut self, - a: &ty::Binder<T>, - b: &ty::Binder<T>, - ) -> RelateResult<'tcx, ty::Binder<T>> - where - T: Relate<'tcx>, - { - Ok(ty::Binder::bind(self.relate(a.skip_binder(), b.skip_binder())?)) - } - - fn relate_item_substs( - &mut self, - item_def_id: DefId, - a_subst: SubstsRef<'tcx>, - b_subst: SubstsRef<'tcx>, - ) -> RelateResult<'tcx, SubstsRef<'tcx>> { - if self.ambient_variance == ty::Variance::Invariant { - // Avoid fetching the variance if we are in an invariant - // context; no need, and it can induce dependency cycles - // (e.g., #41849). - relate::relate_substs(self, None, a_subst, b_subst) - } else { - let opt_variances = self.tcx().variances_of(item_def_id); - relate::relate_substs(self, Some(&opt_variances), a_subst, b_subst) - } - } - - fn relate_with_variance<T: Relate<'tcx>>( - &mut self, - variance: ty::Variance, - a: &T, - b: &T, - ) -> RelateResult<'tcx, T> { - let old_ambient_variance = self.ambient_variance; - self.ambient_variance = self.ambient_variance.xform(variance); - - let result = self.relate(a, b); - self.ambient_variance = old_ambient_variance; - result - } - - fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { - assert_eq!(t, t2); // we are abusing TypeRelation here; both LHS and RHS ought to be == - - debug!("generalize: t={:?}", t); - - // Check to see whether the type we are generalizing references - // any other type variable related to `vid` via - // subtyping. This is basically our "occurs check", preventing - // us from creating infinitely sized types. - match t.kind { - ty::Infer(ty::TyVar(vid)) => { - let vid = self.infcx.inner.borrow_mut().type_variables.root_var(vid); - let sub_vid = self.infcx.inner.borrow_mut().type_variables.sub_root_var(vid); - if sub_vid == self.for_vid_sub_root { - // If sub-roots are equal, then `for_vid` and - // `vid` are related via subtyping. - Err(TypeError::CyclicTy(self.root_ty)) - } else { - let probe = self.infcx.inner.borrow_mut().type_variables.probe(vid); - match probe { - TypeVariableValue::Known { value: u } => { - debug!("generalize: known value {:?}", u); - self.relate(&u, &u) - } - TypeVariableValue::Unknown { universe } => { - match self.ambient_variance { - // Invariant: no need to make a fresh type variable. - ty::Invariant => { - if self.for_universe.can_name(universe) { - return Ok(t); - } - } - - // Bivariant: make a fresh var, but we - // may need a WF predicate. See - // comment on `needs_wf` field for - // more info. - ty::Bivariant => self.needs_wf = true, - - // Co/contravariant: this will be - // sufficiently constrained later on. - ty::Covariant | ty::Contravariant => (), - } - - let origin = - *self.infcx.inner.borrow_mut().type_variables.var_origin(vid); - let new_var_id = self.infcx.inner.borrow_mut().type_variables.new_var( - self.for_universe, - false, - origin, - ); - let u = self.tcx().mk_ty_var(new_var_id); - debug!("generalize: replacing original vid={:?} with new={:?}", vid, u); - Ok(u) - } - } - } - } - ty::Infer(ty::IntVar(_)) | ty::Infer(ty::FloatVar(_)) => { - // No matter what mode we are in, - // integer/floating-point types must be equal to be - // relatable. - Ok(t) - } - _ => relate::super_relate_tys(self, t, t), - } - } - - fn regions( - &mut self, - r: ty::Region<'tcx>, - r2: ty::Region<'tcx>, - ) -> RelateResult<'tcx, ty::Region<'tcx>> { - assert_eq!(r, r2); // we are abusing TypeRelation here; both LHS and RHS ought to be == - - debug!("generalize: regions r={:?}", r); - - match *r { - // Never make variables for regions bound within the type itself, - // nor for erased regions. - ty::ReLateBound(..) | ty::ReErased => { - return Ok(r); - } - - ty::ReClosureBound(..) => { - span_bug!(self.span, "encountered unexpected ReClosureBound: {:?}", r,); - } - - ty::RePlaceholder(..) - | ty::ReVar(..) - | ty::ReEmpty(_) - | ty::ReStatic - | ty::ReScope(..) - | ty::ReEarlyBound(..) - | ty::ReFree(..) => { - // see common code below - } - } - - // If we are in an invariant context, we can re-use the region - // as is, unless it happens to be in some universe that we - // can't name. (In the case of a region *variable*, we could - // use it if we promoted it into our universe, but we don't - // bother.) - if let ty::Invariant = self.ambient_variance { - let r_universe = self.infcx.universe_of_region(r); - if self.for_universe.can_name(r_universe) { - return Ok(r); - } - } - - // FIXME: This is non-ideal because we don't give a - // very descriptive origin for this region variable. - Ok(self.infcx.next_region_var_in_universe(MiscVariable(self.span), self.for_universe)) - } - - fn consts( - &mut self, - c: &'tcx ty::Const<'tcx>, - c2: &'tcx ty::Const<'tcx>, - ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> { - assert_eq!(c, c2); // we are abusing TypeRelation here; both LHS and RHS ought to be == - - match c.val { - ty::ConstKind::Infer(InferConst::Var(vid)) => { - let variable_table = &mut self.infcx.inner.borrow_mut().const_unification_table; - let var_value = variable_table.probe_value(vid); - match var_value.val { - ConstVariableValue::Known { value: u } => self.relate(&u, &u), - ConstVariableValue::Unknown { universe } => { - if self.for_universe.can_name(universe) { - Ok(c) - } else { - let new_var_id = variable_table.new_key(ConstVarValue { - origin: var_value.origin, - val: ConstVariableValue::Unknown { universe: self.for_universe }, - }); - Ok(self.tcx().mk_const_var(new_var_id, c.ty)) - } - } - } - } - _ => relate::super_relate_consts(self, c, c), - } - } -} - -pub trait RelateResultCompare<'tcx, T> { - fn compare<F>(&self, t: T, f: F) -> RelateResult<'tcx, T> - where - F: FnOnce() -> TypeError<'tcx>; -} - -impl<'tcx, T: Clone + PartialEq> RelateResultCompare<'tcx, T> for RelateResult<'tcx, T> { - fn compare<F>(&self, t: T, f: F) -> RelateResult<'tcx, T> - where - F: FnOnce() -> TypeError<'tcx>, - { - self.clone().and_then(|s| if s == t { self.clone() } else { Err(f()) }) - } -} - -pub fn const_unification_error<'tcx>( - a_is_expected: bool, - (a, b): (&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>), -) -> TypeError<'tcx> { - TypeError::ConstMismatch(ty::relate::expected_found_bool(a_is_expected, &a, &b)) -} - -fn int_unification_error<'tcx>( - a_is_expected: bool, - v: (ty::IntVarValue, ty::IntVarValue), -) -> TypeError<'tcx> { - let (a, b) = v; - TypeError::IntMismatch(ty::relate::expected_found_bool(a_is_expected, &a, &b)) -} - -fn float_unification_error<'tcx>( - a_is_expected: bool, - v: (ty::FloatVarValue, ty::FloatVarValue), -) -> TypeError<'tcx> { - let (ty::FloatVarValue(a), ty::FloatVarValue(b)) = v; - TypeError::FloatMismatch(ty::relate::expected_found_bool(a_is_expected, &a, &b)) -} diff --git a/src/librustc/infer/equate.rs b/src/librustc/infer/equate.rs deleted file mode 100644 index 018bbe03543..00000000000 --- a/src/librustc/infer/equate.rs +++ /dev/null @@ -1,142 +0,0 @@ -use super::combine::{CombineFields, RelationDir}; -use super::Subtype; - -use crate::ty::relate::{self, Relate, RelateResult, TypeRelation}; -use crate::ty::subst::SubstsRef; -use crate::ty::TyVar; -use crate::ty::{self, Ty, TyCtxt}; - -use rustc_hir::def_id::DefId; - -/// Ensures `a` is made equal to `b`. Returns `a` on success. -pub struct Equate<'combine, 'infcx, 'tcx> { - fields: &'combine mut CombineFields<'infcx, 'tcx>, - a_is_expected: bool, -} - -impl<'combine, 'infcx, 'tcx> Equate<'combine, 'infcx, 'tcx> { - pub fn new( - fields: &'combine mut CombineFields<'infcx, 'tcx>, - a_is_expected: bool, - ) -> Equate<'combine, 'infcx, 'tcx> { - Equate { fields: fields, a_is_expected: a_is_expected } - } -} - -impl TypeRelation<'tcx> for Equate<'combine, 'infcx, 'tcx> { - fn tag(&self) -> &'static str { - "Equate" - } - - fn tcx(&self) -> TyCtxt<'tcx> { - self.fields.tcx() - } - - fn param_env(&self) -> ty::ParamEnv<'tcx> { - self.fields.param_env - } - - fn a_is_expected(&self) -> bool { - self.a_is_expected - } - - fn relate_item_substs( - &mut self, - _item_def_id: DefId, - a_subst: SubstsRef<'tcx>, - b_subst: SubstsRef<'tcx>, - ) -> RelateResult<'tcx, SubstsRef<'tcx>> { - // N.B., once we are equating types, we don't care about - // variance, so don't try to lookup the variance here. This - // also avoids some cycles (e.g., #41849) since looking up - // variance requires computing types which can require - // performing trait matching (which then performs equality - // unification). - - relate::relate_substs(self, None, a_subst, b_subst) - } - - fn relate_with_variance<T: Relate<'tcx>>( - &mut self, - _: ty::Variance, - a: &T, - b: &T, - ) -> RelateResult<'tcx, T> { - self.relate(a, b) - } - - fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { - debug!("{}.tys({:?}, {:?})", self.tag(), a, b); - if a == b { - return Ok(a); - } - - let infcx = self.fields.infcx; - let a = infcx.inner.borrow_mut().type_variables.replace_if_possible(a); - let b = infcx.inner.borrow_mut().type_variables.replace_if_possible(b); - - debug!("{}.tys: replacements ({:?}, {:?})", self.tag(), a, b); - - match (&a.kind, &b.kind) { - (&ty::Infer(TyVar(a_id)), &ty::Infer(TyVar(b_id))) => { - infcx.inner.borrow_mut().type_variables.equate(a_id, b_id); - } - - (&ty::Infer(TyVar(a_id)), _) => { - self.fields.instantiate(b, RelationDir::EqTo, a_id, self.a_is_expected)?; - } - - (_, &ty::Infer(TyVar(b_id))) => { - self.fields.instantiate(a, RelationDir::EqTo, b_id, self.a_is_expected)?; - } - - _ => { - self.fields.infcx.super_combine_tys(self, a, b)?; - } - } - - Ok(a) - } - - fn regions( - &mut self, - a: ty::Region<'tcx>, - b: ty::Region<'tcx>, - ) -> RelateResult<'tcx, ty::Region<'tcx>> { - debug!("{}.regions({:?}, {:?})", self.tag(), a, b); - let origin = Subtype(box self.fields.trace.clone()); - self.fields - .infcx - .inner - .borrow_mut() - .unwrap_region_constraints() - .make_eqregion(origin, a, b); - Ok(a) - } - - fn consts( - &mut self, - a: &'tcx ty::Const<'tcx>, - b: &'tcx ty::Const<'tcx>, - ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> { - self.fields.infcx.super_combine_consts(self, a, b) - } - - fn binders<T>( - &mut self, - a: &ty::Binder<T>, - b: &ty::Binder<T>, - ) -> RelateResult<'tcx, ty::Binder<T>> - where - T: Relate<'tcx>, - { - if a.skip_binder().has_escaping_bound_vars() || b.skip_binder().has_escaping_bound_vars() { - self.fields.higher_ranked_sub(a, b, self.a_is_expected)?; - self.fields.higher_ranked_sub(b, a, self.a_is_expected) - } else { - // Fast path for the common case. - self.relate(a.skip_binder(), b.skip_binder())?; - return Ok(a.clone()); - } - } -} diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs deleted file mode 100644 index 327e1da64c4..00000000000 --- a/src/librustc/infer/error_reporting/mod.rs +++ /dev/null @@ -1,2099 +0,0 @@ -//! Error Reporting Code for the inference engine -//! -//! Because of the way inference, and in particular region inference, -//! works, it often happens that errors are not detected until far after -//! the relevant line of code has been type-checked. Therefore, there is -//! an elaborate system to track why a particular constraint in the -//! inference graph arose so that we can explain to the user what gave -//! rise to a particular error. -//! -//! The basis of the system are the "origin" types. An "origin" is the -//! reason that a constraint or inference variable arose. There are -//! different "origin" enums for different kinds of constraints/variables -//! (e.g., `TypeOrigin`, `RegionVariableOrigin`). An origin always has -//! a span, but also more information so that we can generate a meaningful -//! error message. -//! -//! Having a catalog of all the different reasons an error can arise is -//! also useful for other reasons, like cross-referencing FAQs etc, though -//! we are not really taking advantage of this yet. -//! -//! # Region Inference -//! -//! Region inference is particularly tricky because it always succeeds "in -//! the moment" and simply registers a constraint. Then, at the end, we -//! can compute the full graph and report errors, so we need to be able to -//! store and later report what gave rise to the conflicting constraints. -//! -//! # Subtype Trace -//! -//! Determining whether `T1 <: T2` often involves a number of subtypes and -//! subconstraints along the way. A "TypeTrace" is an extended version -//! of an origin that traces the types and other values that were being -//! compared. It is not necessarily comprehensive (in fact, at the time of -//! this writing it only tracks the root values being compared) but I'd -//! like to extend it to include significant "waypoints". For example, if -//! you are comparing `(T1, T2) <: (T3, T4)`, and the problem is that `T2 -//! <: T4` fails, I'd like the trace to include enough information to say -//! "in the 2nd element of the tuple". Similarly, failures when comparing -//! arguments or return types in fn types should be able to cite the -//! specific position, etc. -//! -//! # Reality vs plan -//! -//! Of course, there is still a LOT of code in typeck that has yet to be -//! ported to this system, and which relies on string concatenation at the -//! time of error detection. - -use super::lexical_region_resolve::RegionResolutionError; -use super::region_constraints::GenericKind; -use super::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TypeTrace, ValuePairs}; - -use crate::hir::map; -use crate::infer::opaque_types; -use crate::infer::{self, SuppressRegionErrors}; -use crate::middle::region; -use crate::traits::error_reporting::report_object_safety_error; -use crate::traits::object_safety_violations; -use crate::traits::{ - IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode, -}; -use crate::ty::error::TypeError; -use crate::ty::{ - self, - subst::{Subst, SubstsRef}, - Region, Ty, TyCtxt, TypeFoldable, -}; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_errors::{pluralize, struct_span_err}; -use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString}; -use rustc_hir as hir; -use rustc_hir::def_id::DefId; -use rustc_hir::Node; -use rustc_span::{DesugaringKind, Pos, Span}; -use rustc_target::spec::abi; -use std::{cmp, fmt}; - -mod note; - -mod need_type_info; -pub use need_type_info::TypeAnnotationNeeded; - -pub mod nice_region_error; - -pub(super) fn note_and_explain_region( - tcx: TyCtxt<'tcx>, - region_scope_tree: ®ion::ScopeTree, - err: &mut DiagnosticBuilder<'_>, - prefix: &str, - region: ty::Region<'tcx>, - suffix: &str, -) { - let (description, span) = match *region { - ty::ReScope(scope) => { - let new_string; - let unknown_scope = - || format!("{}unknown scope: {:?}{}. Please report a bug.", prefix, scope, suffix); - let span = scope.span(tcx, region_scope_tree); - let tag = match tcx.hir().find(scope.hir_id(region_scope_tree)) { - Some(Node::Block(_)) => "block", - Some(Node::Expr(expr)) => match expr.kind { - hir::ExprKind::Call(..) => "call", - hir::ExprKind::MethodCall(..) => "method call", - hir::ExprKind::Match(.., hir::MatchSource::IfLetDesugar { .. }) => "if let", - hir::ExprKind::Match(.., hir::MatchSource::WhileLetDesugar) => "while let", - hir::ExprKind::Match(.., hir::MatchSource::ForLoopDesugar) => "for", - hir::ExprKind::Match(..) => "match", - _ => "expression", - }, - Some(Node::Stmt(_)) => "statement", - Some(Node::Item(it)) => item_scope_tag(&it), - Some(Node::TraitItem(it)) => trait_item_scope_tag(&it), - Some(Node::ImplItem(it)) => impl_item_scope_tag(&it), - Some(_) | None => { - err.span_note(span, &unknown_scope()); - return; - } - }; - let scope_decorated_tag = match scope.data { - region::ScopeData::Node => tag, - region::ScopeData::CallSite => "scope of call-site for function", - region::ScopeData::Arguments => "scope of function body", - region::ScopeData::Destruction => { - new_string = format!("destruction scope surrounding {}", tag); - &new_string[..] - } - region::ScopeData::Remainder(first_statement_index) => { - new_string = format!( - "block suffix following statement {}", - first_statement_index.index() - ); - &new_string[..] - } - }; - explain_span(tcx, scope_decorated_tag, span) - } - - ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReStatic => { - msg_span_from_free_region(tcx, region) - } - - ty::ReEmpty(ty::UniverseIndex::ROOT) => ("the empty lifetime".to_owned(), None), - - // uh oh, hope no user ever sees THIS - ty::ReEmpty(ui) => (format!("the empty lifetime in universe {:?}", ui), None), - - ty::RePlaceholder(_) => (format!("any other region"), None), - - // FIXME(#13998) RePlaceholder should probably print like - // ReFree rather than dumping Debug output on the user. - // - // We shouldn't really be having unification failures with ReVar - // and ReLateBound though. - ty::ReVar(_) | ty::ReLateBound(..) | ty::ReErased => { - (format!("lifetime {:?}", region), None) - } - - // We shouldn't encounter an error message with ReClosureBound. - ty::ReClosureBound(..) => { - bug!("encountered unexpected ReClosureBound: {:?}", region,); - } - }; - - emit_msg_span(err, prefix, description, span, suffix); -} - -pub(super) fn note_and_explain_free_region( - tcx: TyCtxt<'tcx>, - err: &mut DiagnosticBuilder<'_>, - prefix: &str, - region: ty::Region<'tcx>, - suffix: &str, -) { - let (description, span) = msg_span_from_free_region(tcx, region); - - emit_msg_span(err, prefix, description, span, suffix); -} - -fn msg_span_from_free_region( - tcx: TyCtxt<'tcx>, - region: ty::Region<'tcx>, -) -> (String, Option<Span>) { - match *region { - ty::ReEarlyBound(_) | ty::ReFree(_) => { - msg_span_from_early_bound_and_free_regions(tcx, region) - } - ty::ReStatic => ("the static lifetime".to_owned(), None), - ty::ReEmpty(ty::UniverseIndex::ROOT) => ("an empty lifetime".to_owned(), None), - ty::ReEmpty(ui) => (format!("an empty lifetime in universe {:?}", ui), None), - _ => bug!("{:?}", region), - } -} - -fn msg_span_from_early_bound_and_free_regions( - tcx: TyCtxt<'tcx>, - region: ty::Region<'tcx>, -) -> (String, Option<Span>) { - let cm = tcx.sess.source_map(); - - let scope = region.free_region_binding_scope(tcx); - let node = tcx.hir().as_local_hir_id(scope).unwrap_or(hir::DUMMY_HIR_ID); - let tag = match tcx.hir().find(node) { - Some(Node::Block(_)) | Some(Node::Expr(_)) => "body", - Some(Node::Item(it)) => item_scope_tag(&it), - Some(Node::TraitItem(it)) => trait_item_scope_tag(&it), - Some(Node::ImplItem(it)) => impl_item_scope_tag(&it), - _ => unreachable!(), - }; - let (prefix, span) = match *region { - ty::ReEarlyBound(ref br) => { - let mut sp = cm.def_span(tcx.hir().span(node)); - if let Some(param) = - tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(br.name)) - { - sp = param.span; - } - (format!("the lifetime `{}` as defined on", br.name), sp) - } - ty::ReFree(ty::FreeRegion { bound_region: ty::BoundRegion::BrNamed(_, name), .. }) => { - let mut sp = cm.def_span(tcx.hir().span(node)); - if let Some(param) = - tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(name)) - { - sp = param.span; - } - (format!("the lifetime `{}` as defined on", name), sp) - } - ty::ReFree(ref fr) => match fr.bound_region { - ty::BrAnon(idx) => { - (format!("the anonymous lifetime #{} defined on", idx + 1), tcx.hir().span(node)) - } - _ => ( - format!("the lifetime `{}` as defined on", region), - cm.def_span(tcx.hir().span(node)), - ), - }, - _ => bug!(), - }; - let (msg, opt_span) = explain_span(tcx, tag, span); - (format!("{} {}", prefix, msg), opt_span) -} - -fn emit_msg_span( - err: &mut DiagnosticBuilder<'_>, - prefix: &str, - description: String, - span: Option<Span>, - suffix: &str, -) { - let message = format!("{}{}{}", prefix, description, suffix); - - if let Some(span) = span { - err.span_note(span, &message); - } else { - err.note(&message); - } -} - -fn item_scope_tag(item: &hir::Item<'_>) -> &'static str { - match item.kind { - hir::ItemKind::Impl { .. } => "impl", - hir::ItemKind::Struct(..) => "struct", - hir::ItemKind::Union(..) => "union", - hir::ItemKind::Enum(..) => "enum", - hir::ItemKind::Trait(..) => "trait", - hir::ItemKind::Fn(..) => "function body", - _ => "item", - } -} - -fn trait_item_scope_tag(item: &hir::TraitItem<'_>) -> &'static str { - match item.kind { - hir::TraitItemKind::Method(..) => "method body", - hir::TraitItemKind::Const(..) | hir::TraitItemKind::Type(..) => "associated item", - } -} - -fn impl_item_scope_tag(item: &hir::ImplItem<'_>) -> &'static str { - match item.kind { - hir::ImplItemKind::Method(..) => "method body", - hir::ImplItemKind::Const(..) - | hir::ImplItemKind::OpaqueTy(..) - | hir::ImplItemKind::TyAlias(..) => "associated item", - } -} - -fn explain_span(tcx: TyCtxt<'tcx>, heading: &str, span: Span) -> (String, Option<Span>) { - let lo = tcx.sess.source_map().lookup_char_pos(span.lo()); - (format!("the {} at {}:{}", heading, lo.line, lo.col.to_usize() + 1), Some(span)) -} - -impl<'a, 'tcx> InferCtxt<'a, 'tcx> { - pub fn report_region_errors( - &self, - region_scope_tree: ®ion::ScopeTree, - errors: &Vec<RegionResolutionError<'tcx>>, - suppress: SuppressRegionErrors, - ) { - debug!( - "report_region_errors(): {} errors to start, suppress = {:?}", - errors.len(), - suppress - ); - - if suppress.suppressed() { - return; - } - - // try to pre-process the errors, which will group some of them - // together into a `ProcessedErrors` group: - let errors = self.process_errors(errors); - - debug!("report_region_errors: {} errors after preprocessing", errors.len()); - - for error in errors { - debug!("report_region_errors: error = {:?}", error); - - if !self.try_report_nice_region_error(&error) { - match error.clone() { - // These errors could indicate all manner of different - // problems with many different solutions. Rather - // than generate a "one size fits all" error, what we - // attempt to do is go through a number of specific - // scenarios and try to find the best way to present - // the error. If all of these fails, we fall back to a rather - // general bit of code that displays the error information - RegionResolutionError::ConcreteFailure(origin, sub, sup) => { - if sub.is_placeholder() || sup.is_placeholder() { - self.report_placeholder_failure(region_scope_tree, origin, sub, sup) - .emit(); - } else { - self.report_concrete_failure(region_scope_tree, origin, sub, sup) - .emit(); - } - } - - RegionResolutionError::GenericBoundFailure(origin, param_ty, sub) => { - self.report_generic_bound_failure( - region_scope_tree, - origin.span(), - Some(origin), - param_ty, - sub, - ); - } - - RegionResolutionError::SubSupConflict( - _, - var_origin, - sub_origin, - sub_r, - sup_origin, - sup_r, - ) => { - if sub_r.is_placeholder() { - self.report_placeholder_failure( - region_scope_tree, - sub_origin, - sub_r, - sup_r, - ) - .emit(); - } else if sup_r.is_placeholder() { - self.report_placeholder_failure( - region_scope_tree, - sup_origin, - sub_r, - sup_r, - ) - .emit(); - } else { - self.report_sub_sup_conflict( - region_scope_tree, - var_origin, - sub_origin, - sub_r, - sup_origin, - sup_r, - ); - } - } - - RegionResolutionError::UpperBoundUniverseConflict( - _, - _, - var_universe, - sup_origin, - sup_r, - ) => { - assert!(sup_r.is_placeholder()); - - // Make a dummy value for the "sub region" -- - // this is the initial value of the - // placeholder. In practice, we expect more - // tailored errors that don't really use this - // value. - let sub_r = self.tcx.mk_region(ty::ReEmpty(var_universe)); - - self.report_placeholder_failure( - region_scope_tree, - sup_origin, - sub_r, - sup_r, - ) - .emit(); - } - - RegionResolutionError::MemberConstraintFailure { - hidden_ty, - member_region, - span, - } => { - let hidden_ty = self.resolve_vars_if_possible(&hidden_ty); - opaque_types::unexpected_hidden_region_diagnostic( - self.tcx, - Some(region_scope_tree), - span, - hidden_ty, - member_region, - ) - .emit(); - } - } - } - } - } - - // This method goes through all the errors and try to group certain types - // of error together, for the purpose of suggesting explicit lifetime - // parameters to the user. This is done so that we can have a more - // complete view of what lifetimes should be the same. - // If the return value is an empty vector, it means that processing - // failed (so the return value of this method should not be used). - // - // The method also attempts to weed out messages that seem like - // duplicates that will be unhelpful to the end-user. But - // obviously it never weeds out ALL errors. - fn process_errors( - &self, - errors: &Vec<RegionResolutionError<'tcx>>, - ) -> Vec<RegionResolutionError<'tcx>> { - debug!("process_errors()"); - - // We want to avoid reporting generic-bound failures if we can - // avoid it: these have a very high rate of being unhelpful in - // practice. This is because they are basically secondary - // checks that test the state of the region graph after the - // rest of inference is done, and the other kinds of errors - // indicate that the region constraint graph is internally - // inconsistent, so these test results are likely to be - // meaningless. - // - // Therefore, we filter them out of the list unless they are - // the only thing in the list. - - let is_bound_failure = |e: &RegionResolutionError<'tcx>| match *e { - RegionResolutionError::GenericBoundFailure(..) => true, - RegionResolutionError::ConcreteFailure(..) - | RegionResolutionError::SubSupConflict(..) - | RegionResolutionError::UpperBoundUniverseConflict(..) - | RegionResolutionError::MemberConstraintFailure { .. } => false, - }; - - let mut errors = if errors.iter().all(|e| is_bound_failure(e)) { - errors.clone() - } else { - errors.iter().filter(|&e| !is_bound_failure(e)).cloned().collect() - }; - - // sort the errors by span, for better error message stability. - errors.sort_by_key(|u| match *u { - RegionResolutionError::ConcreteFailure(ref sro, _, _) => sro.span(), - RegionResolutionError::GenericBoundFailure(ref sro, _, _) => sro.span(), - RegionResolutionError::SubSupConflict(_, ref rvo, _, _, _, _) => rvo.span(), - RegionResolutionError::UpperBoundUniverseConflict(_, ref rvo, _, _, _) => rvo.span(), - RegionResolutionError::MemberConstraintFailure { span, .. } => span, - }); - errors - } - - /// Adds a note if the types come from similarly named crates - fn check_and_note_conflicting_crates( - &self, - err: &mut DiagnosticBuilder<'_>, - terr: &TypeError<'tcx>, - ) { - use hir::def_id::CrateNum; - use map::DisambiguatedDefPathData; - use ty::print::Printer; - use ty::subst::GenericArg; - - struct AbsolutePathPrinter<'tcx> { - tcx: TyCtxt<'tcx>, - } - - struct NonTrivialPath; - - impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { - type Error = NonTrivialPath; - - type Path = Vec<String>; - type Region = !; - type Type = !; - type DynExistential = !; - type Const = !; - - fn tcx<'a>(&'a self) -> TyCtxt<'tcx> { - self.tcx - } - - fn print_region(self, _region: ty::Region<'_>) -> Result<Self::Region, Self::Error> { - Err(NonTrivialPath) - } - - fn print_type(self, _ty: Ty<'tcx>) -> Result<Self::Type, Self::Error> { - Err(NonTrivialPath) - } - - fn print_dyn_existential( - self, - _predicates: &'tcx ty::List<ty::ExistentialPredicate<'tcx>>, - ) -> Result<Self::DynExistential, Self::Error> { - Err(NonTrivialPath) - } - - fn print_const(self, _ct: &'tcx ty::Const<'tcx>) -> Result<Self::Const, Self::Error> { - Err(NonTrivialPath) - } - - fn path_crate(self, cnum: CrateNum) -> Result<Self::Path, Self::Error> { - Ok(vec![self.tcx.original_crate_name(cnum).to_string()]) - } - fn path_qualified( - self, - _self_ty: Ty<'tcx>, - _trait_ref: Option<ty::TraitRef<'tcx>>, - ) -> Result<Self::Path, Self::Error> { - Err(NonTrivialPath) - } - - fn path_append_impl( - self, - _print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, - _disambiguated_data: &DisambiguatedDefPathData, - _self_ty: Ty<'tcx>, - _trait_ref: Option<ty::TraitRef<'tcx>>, - ) -> Result<Self::Path, Self::Error> { - Err(NonTrivialPath) - } - fn path_append( - self, - print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, - disambiguated_data: &DisambiguatedDefPathData, - ) -> Result<Self::Path, Self::Error> { - let mut path = print_prefix(self)?; - path.push(disambiguated_data.data.as_symbol().to_string()); - Ok(path) - } - fn path_generic_args( - self, - print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, - _args: &[GenericArg<'tcx>], - ) -> Result<Self::Path, Self::Error> { - print_prefix(self) - } - } - - let report_path_match = |err: &mut DiagnosticBuilder<'_>, did1: DefId, did2: DefId| { - // Only external crates, if either is from a local - // module we could have false positives - if !(did1.is_local() || did2.is_local()) && did1.krate != did2.krate { - let abs_path = - |def_id| AbsolutePathPrinter { tcx: self.tcx }.print_def_path(def_id, &[]); - - // We compare strings because DefPath can be different - // for imported and non-imported crates - let same_path = || -> Result<_, NonTrivialPath> { - Ok(self.tcx.def_path_str(did1) == self.tcx.def_path_str(did2) - || abs_path(did1)? == abs_path(did2)?) - }; - if same_path().unwrap_or(false) { - let crate_name = self.tcx.crate_name(did1.krate); - err.note(&format!( - "perhaps two different versions of crate `{}` are being used?", - crate_name - )); - } - } - }; - match *terr { - TypeError::Sorts(ref exp_found) => { - // if they are both "path types", there's a chance of ambiguity - // due to different versions of the same crate - if let (&ty::Adt(exp_adt, _), &ty::Adt(found_adt, _)) = - (&exp_found.expected.kind, &exp_found.found.kind) - { - report_path_match(err, exp_adt.did, found_adt.did); - } - } - TypeError::Traits(ref exp_found) => { - report_path_match(err, exp_found.expected, exp_found.found); - } - _ => (), // FIXME(#22750) handle traits and stuff - } - } - - fn note_error_origin( - &self, - err: &mut DiagnosticBuilder<'tcx>, - cause: &ObligationCause<'tcx>, - exp_found: Option<ty::error::ExpectedFound<Ty<'tcx>>>, - ) { - match cause.code { - ObligationCauseCode::Pattern { origin_expr: true, span: Some(span), root_ty } => { - let ty = self.resolve_vars_if_possible(&root_ty); - if ty.is_suggestable() { - // don't show type `_` - err.span_label(span, format!("this expression has type `{}`", ty)); - } - if let Some(ty::error::ExpectedFound { found, .. }) = exp_found { - if ty.is_box() && ty.boxed_ty() == found { - if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { - err.span_suggestion( - span, - "consider dereferencing the boxed value", - format!("*{}", snippet), - Applicability::MachineApplicable, - ); - } - } - } - } - ObligationCauseCode::Pattern { origin_expr: false, span: Some(span), .. } => { - err.span_label(span, "expected due to this"); - } - ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause { - source, - ref prior_arms, - last_ty, - scrut_hir_id, - .. - }) => match source { - hir::MatchSource::IfLetDesugar { .. } => { - let msg = "`if let` arms have incompatible types"; - err.span_label(cause.span, msg); - } - hir::MatchSource::TryDesugar => { - if let Some(ty::error::ExpectedFound { expected, .. }) = exp_found { - let scrut_expr = self.tcx.hir().expect_expr(scrut_hir_id); - let scrut_ty = if let hir::ExprKind::Call(_, args) = &scrut_expr.kind { - let arg_expr = args.first().expect("try desugaring call w/out arg"); - self.in_progress_tables - .and_then(|tables| tables.borrow().expr_ty_opt(arg_expr)) - } else { - bug!("try desugaring w/out call expr as scrutinee"); - }; - - match scrut_ty { - Some(ty) if expected == ty => { - let source_map = self.tcx.sess.source_map(); - err.span_suggestion( - source_map.end_point(cause.span), - "try removing this `?`", - "".to_string(), - Applicability::MachineApplicable, - ); - } - _ => {} - } - } - } - _ => { - // `last_ty` can be `!`, `expected` will have better info when present. - let t = self.resolve_vars_if_possible(&match exp_found { - Some(ty::error::ExpectedFound { expected, .. }) => expected, - _ => last_ty, - }); - let msg = "`match` arms have incompatible types"; - err.span_label(cause.span, msg); - if prior_arms.len() <= 4 { - for sp in prior_arms { - err.span_label(*sp, format!("this is found to be of type `{}`", t)); - } - } else if let Some(sp) = prior_arms.last() { - err.span_label( - *sp, - format!("this and all prior arms are found to be of type `{}`", t), - ); - } - } - }, - ObligationCauseCode::IfExpression(box IfExpressionCause { then, outer, semicolon }) => { - err.span_label(then, "expected because of this"); - outer.map(|sp| err.span_label(sp, "`if` and `else` have incompatible types")); - if let Some(sp) = semicolon { - err.span_suggestion_short( - sp, - "consider removing this semicolon", - String::new(), - Applicability::MachineApplicable, - ); - } - } - _ => (), - } - } - - /// Given that `other_ty` is the same as a type argument for `name` in `sub`, populate `value` - /// highlighting `name` and every type argument that isn't at `pos` (which is `other_ty`), and - /// populate `other_value` with `other_ty`. - /// - /// ```text - /// Foo<Bar<Qux>> - /// ^^^^--------^ this is highlighted - /// | | - /// | this type argument is exactly the same as the other type, not highlighted - /// this is highlighted - /// Bar<Qux> - /// -------- this type is the same as a type argument in the other type, not highlighted - /// ``` - fn highlight_outer( - &self, - value: &mut DiagnosticStyledString, - other_value: &mut DiagnosticStyledString, - name: String, - sub: ty::subst::SubstsRef<'tcx>, - pos: usize, - other_ty: Ty<'tcx>, - ) { - // `value` and `other_value` hold two incomplete type representation for display. - // `name` is the path of both types being compared. `sub` - value.push_highlighted(name); - let len = sub.len(); - if len > 0 { - value.push_highlighted("<"); - } - - // Output the lifetimes for the first type - let lifetimes = sub - .regions() - .map(|lifetime| { - let s = lifetime.to_string(); - if s.is_empty() { "'_".to_string() } else { s } - }) - .collect::<Vec<_>>() - .join(", "); - if !lifetimes.is_empty() { - if sub.regions().count() < len { - value.push_normal(lifetimes + &", "); - } else { - value.push_normal(lifetimes); - } - } - - // Highlight all the type arguments that aren't at `pos` and compare the type argument at - // `pos` and `other_ty`. - for (i, type_arg) in sub.types().enumerate() { - if i == pos { - let values = self.cmp(type_arg, other_ty); - value.0.extend((values.0).0); - other_value.0.extend((values.1).0); - } else { - value.push_highlighted(type_arg.to_string()); - } - - if len > 0 && i != len - 1 { - value.push_normal(", "); - } - } - if len > 0 { - value.push_highlighted(">"); - } - } - - /// If `other_ty` is the same as a type argument present in `sub`, highlight `path` in `t1_out`, - /// as that is the difference to the other type. - /// - /// For the following code: - /// - /// ```norun - /// let x: Foo<Bar<Qux>> = foo::<Bar<Qux>>(); - /// ``` - /// - /// The type error output will behave in the following way: - /// - /// ```text - /// Foo<Bar<Qux>> - /// ^^^^--------^ this is highlighted - /// | | - /// | this type argument is exactly the same as the other type, not highlighted - /// this is highlighted - /// Bar<Qux> - /// -------- this type is the same as a type argument in the other type, not highlighted - /// ``` - fn cmp_type_arg( - &self, - mut t1_out: &mut DiagnosticStyledString, - mut t2_out: &mut DiagnosticStyledString, - path: String, - sub: ty::subst::SubstsRef<'tcx>, - other_path: String, - other_ty: Ty<'tcx>, - ) -> Option<()> { - for (i, ta) in sub.types().enumerate() { - if ta == other_ty { - self.highlight_outer(&mut t1_out, &mut t2_out, path, sub, i, &other_ty); - return Some(()); - } - if let &ty::Adt(def, _) = &ta.kind { - let path_ = self.tcx.def_path_str(def.did.clone()); - if path_ == other_path { - self.highlight_outer(&mut t1_out, &mut t2_out, path, sub, i, &other_ty); - return Some(()); - } - } - } - None - } - - /// Adds a `,` to the type representation only if it is appropriate. - fn push_comma( - &self, - value: &mut DiagnosticStyledString, - other_value: &mut DiagnosticStyledString, - len: usize, - pos: usize, - ) { - if len > 0 && pos != len - 1 { - value.push_normal(", "); - other_value.push_normal(", "); - } - } - - /// For generic types with parameters with defaults, remove the parameters corresponding to - /// the defaults. This repeats a lot of the logic found in `ty::print::pretty`. - fn strip_generic_default_params( - &self, - def_id: DefId, - substs: ty::subst::SubstsRef<'tcx>, - ) -> SubstsRef<'tcx> { - let generics = self.tcx.generics_of(def_id); - let mut num_supplied_defaults = 0; - let mut type_params = generics - .params - .iter() - .rev() - .filter_map(|param| match param.kind { - ty::GenericParamDefKind::Lifetime => None, - ty::GenericParamDefKind::Type { has_default, .. } => { - Some((param.def_id, has_default)) - } - ty::GenericParamDefKind::Const => None, // FIXME(const_generics:defaults) - }) - .peekable(); - let has_default = { - let has_default = type_params.peek().map(|(_, has_default)| has_default); - *has_default.unwrap_or(&false) - }; - if has_default { - let types = substs.types().rev(); - for ((def_id, has_default), actual) in type_params.zip(types) { - if !has_default { - break; - } - if self.tcx.type_of(def_id).subst(self.tcx, substs) != actual { - break; - } - num_supplied_defaults += 1; - } - } - let len = generics.params.len(); - let mut generics = generics.clone(); - generics.params.truncate(len - num_supplied_defaults); - substs.truncate_to(self.tcx, &generics) - } - - /// Given two `fn` signatures highlight only sub-parts that are different. - fn cmp_fn_sig( - &self, - sig1: &ty::PolyFnSig<'tcx>, - sig2: &ty::PolyFnSig<'tcx>, - ) -> (DiagnosticStyledString, DiagnosticStyledString) { - let get_lifetimes = |sig| { - use rustc_hir::def::Namespace; - let mut s = String::new(); - let (_, (sig, reg)) = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS) - .name_all_regions(sig) - .unwrap(); - let lts: Vec<String> = reg.into_iter().map(|(_, kind)| kind.to_string()).collect(); - (if lts.is_empty() { String::new() } else { format!("for<{}> ", lts.join(", ")) }, sig) - }; - - let (lt1, sig1) = get_lifetimes(sig1); - let (lt2, sig2) = get_lifetimes(sig2); - - // unsafe extern "C" for<'a> fn(&'a T) -> &'a T - let mut values = ( - DiagnosticStyledString::normal("".to_string()), - DiagnosticStyledString::normal("".to_string()), - ); - - // unsafe extern "C" for<'a> fn(&'a T) -> &'a T - // ^^^^^^ - values.0.push(sig1.unsafety.prefix_str(), sig1.unsafety != sig2.unsafety); - values.1.push(sig2.unsafety.prefix_str(), sig1.unsafety != sig2.unsafety); - - // unsafe extern "C" for<'a> fn(&'a T) -> &'a T - // ^^^^^^^^^^ - if sig1.abi != abi::Abi::Rust { - values.0.push(format!("extern {} ", sig1.abi), sig1.abi != sig2.abi); - } - if sig2.abi != abi::Abi::Rust { - values.1.push(format!("extern {} ", sig2.abi), sig1.abi != sig2.abi); - } - - // unsafe extern "C" for<'a> fn(&'a T) -> &'a T - // ^^^^^^^^ - let lifetime_diff = lt1 != lt2; - values.0.push(lt1, lifetime_diff); - values.1.push(lt2, lifetime_diff); - - // unsafe extern "C" for<'a> fn(&'a T) -> &'a T - // ^^^ - values.0.push_normal("fn("); - values.1.push_normal("fn("); - - // unsafe extern "C" for<'a> fn(&'a T) -> &'a T - // ^^^^^ - let len1 = sig1.inputs().len(); - let len2 = sig2.inputs().len(); - if len1 == len2 { - for (i, (l, r)) in sig1.inputs().iter().zip(sig2.inputs().iter()).enumerate() { - let (x1, x2) = self.cmp(l, r); - (values.0).0.extend(x1.0); - (values.1).0.extend(x2.0); - self.push_comma(&mut values.0, &mut values.1, len1, i); - } - } else { - for (i, l) in sig1.inputs().iter().enumerate() { - values.0.push_highlighted(l.to_string()); - if i != len1 - 1 { - values.0.push_highlighted(", "); - } - } - for (i, r) in sig2.inputs().iter().enumerate() { - values.1.push_highlighted(r.to_string()); - if i != len2 - 1 { - values.1.push_highlighted(", "); - } - } - } - - if sig1.c_variadic { - if len1 > 0 { - values.0.push_normal(", "); - } - values.0.push("...", !sig2.c_variadic); - } - if sig2.c_variadic { - if len2 > 0 { - values.1.push_normal(", "); - } - values.1.push("...", !sig1.c_variadic); - } - - // unsafe extern "C" for<'a> fn(&'a T) -> &'a T - // ^ - values.0.push_normal(")"); - values.1.push_normal(")"); - - // unsafe extern "C" for<'a> fn(&'a T) -> &'a T - // ^^^^^^^^ - let output1 = sig1.output(); - let output2 = sig2.output(); - let (x1, x2) = self.cmp(output1, output2); - if !output1.is_unit() { - values.0.push_normal(" -> "); - (values.0).0.extend(x1.0); - } - if !output2.is_unit() { - values.1.push_normal(" -> "); - (values.1).0.extend(x2.0); - } - values - } - - /// Compares two given types, eliding parts that are the same between them and highlighting - /// relevant differences, and return two representation of those types for highlighted printing. - fn cmp(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) -> (DiagnosticStyledString, DiagnosticStyledString) { - debug!("cmp(t1={}, t1.kind={:?}, t2={}, t2.kind={:?})", t1, t1.kind, t2, t2.kind); - - // helper functions - fn equals<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool { - match (&a.kind, &b.kind) { - (a, b) if *a == *b => true, - (&ty::Int(_), &ty::Infer(ty::InferTy::IntVar(_))) - | (&ty::Infer(ty::InferTy::IntVar(_)), &ty::Int(_)) - | (&ty::Infer(ty::InferTy::IntVar(_)), &ty::Infer(ty::InferTy::IntVar(_))) - | (&ty::Float(_), &ty::Infer(ty::InferTy::FloatVar(_))) - | (&ty::Infer(ty::InferTy::FloatVar(_)), &ty::Float(_)) - | (&ty::Infer(ty::InferTy::FloatVar(_)), &ty::Infer(ty::InferTy::FloatVar(_))) => { - true - } - _ => false, - } - } - - fn push_ty_ref<'tcx>( - r: &ty::Region<'tcx>, - ty: Ty<'tcx>, - mutbl: hir::Mutability, - s: &mut DiagnosticStyledString, - ) { - let mut r = r.to_string(); - if r == "'_" { - r.clear(); - } else { - r.push(' '); - } - s.push_highlighted(format!("&{}{}", r, mutbl.prefix_str())); - s.push_normal(ty.to_string()); - } - - // process starts here - match (&t1.kind, &t2.kind) { - (&ty::Adt(def1, sub1), &ty::Adt(def2, sub2)) => { - let sub_no_defaults_1 = self.strip_generic_default_params(def1.did, sub1); - let sub_no_defaults_2 = self.strip_generic_default_params(def2.did, sub2); - let mut values = (DiagnosticStyledString::new(), DiagnosticStyledString::new()); - let path1 = self.tcx.def_path_str(def1.did.clone()); - let path2 = self.tcx.def_path_str(def2.did.clone()); - if def1.did == def2.did { - // Easy case. Replace same types with `_` to shorten the output and highlight - // the differing ones. - // let x: Foo<Bar, Qux> = y::<Foo<Quz, Qux>>(); - // Foo<Bar, _> - // Foo<Quz, _> - // --- ^ type argument elided - // | - // highlighted in output - values.0.push_normal(path1); - values.1.push_normal(path2); - - // Avoid printing out default generic parameters that are common to both - // types. - let len1 = sub_no_defaults_1.len(); - let len2 = sub_no_defaults_2.len(); - let common_len = cmp::min(len1, len2); - let remainder1: Vec<_> = sub1.types().skip(common_len).collect(); - let remainder2: Vec<_> = sub2.types().skip(common_len).collect(); - let common_default_params = remainder1 - .iter() - .rev() - .zip(remainder2.iter().rev()) - .filter(|(a, b)| a == b) - .count(); - let len = sub1.len() - common_default_params; - let consts_offset = len - sub1.consts().count(); - - // Only draw `<...>` if there're lifetime/type arguments. - if len > 0 { - values.0.push_normal("<"); - values.1.push_normal("<"); - } - - fn lifetime_display(lifetime: Region<'_>) -> String { - let s = lifetime.to_string(); - if s.is_empty() { "'_".to_string() } else { s } - } - // At one point we'd like to elide all lifetimes here, they are irrelevant for - // all diagnostics that use this output - // - // Foo<'x, '_, Bar> - // Foo<'y, '_, Qux> - // ^^ ^^ --- type arguments are not elided - // | | - // | elided as they were the same - // not elided, they were different, but irrelevant - let lifetimes = sub1.regions().zip(sub2.regions()); - for (i, lifetimes) in lifetimes.enumerate() { - let l1 = lifetime_display(lifetimes.0); - let l2 = lifetime_display(lifetimes.1); - if lifetimes.0 == lifetimes.1 { - values.0.push_normal("'_"); - values.1.push_normal("'_"); - } else { - values.0.push_highlighted(l1); - values.1.push_highlighted(l2); - } - self.push_comma(&mut values.0, &mut values.1, len, i); - } - - // We're comparing two types with the same path, so we compare the type - // arguments for both. If they are the same, do not highlight and elide from the - // output. - // Foo<_, Bar> - // Foo<_, Qux> - // ^ elided type as this type argument was the same in both sides - let type_arguments = sub1.types().zip(sub2.types()); - let regions_len = sub1.regions().count(); - let num_display_types = consts_offset - regions_len; - for (i, (ta1, ta2)) in type_arguments.take(num_display_types).enumerate() { - let i = i + regions_len; - if ta1 == ta2 { - values.0.push_normal("_"); - values.1.push_normal("_"); - } else { - let (x1, x2) = self.cmp(ta1, ta2); - (values.0).0.extend(x1.0); - (values.1).0.extend(x2.0); - } - self.push_comma(&mut values.0, &mut values.1, len, i); - } - - // Do the same for const arguments, if they are equal, do not highlight and - // elide them from the output. - let const_arguments = sub1.consts().zip(sub2.consts()); - for (i, (ca1, ca2)) in const_arguments.enumerate() { - let i = i + consts_offset; - if ca1 == ca2 { - values.0.push_normal("_"); - values.1.push_normal("_"); - } else { - values.0.push_highlighted(ca1.to_string()); - values.1.push_highlighted(ca2.to_string()); - } - self.push_comma(&mut values.0, &mut values.1, len, i); - } - - // Close the type argument bracket. - // Only draw `<...>` if there're lifetime/type arguments. - if len > 0 { - values.0.push_normal(">"); - values.1.push_normal(">"); - } - values - } else { - // Check for case: - // let x: Foo<Bar<Qux> = foo::<Bar<Qux>>(); - // Foo<Bar<Qux> - // ------- this type argument is exactly the same as the other type - // Bar<Qux> - if self - .cmp_type_arg( - &mut values.0, - &mut values.1, - path1.clone(), - sub_no_defaults_1, - path2.clone(), - &t2, - ) - .is_some() - { - return values; - } - // Check for case: - // let x: Bar<Qux> = y:<Foo<Bar<Qux>>>(); - // Bar<Qux> - // Foo<Bar<Qux>> - // ------- this type argument is exactly the same as the other type - if self - .cmp_type_arg( - &mut values.1, - &mut values.0, - path2, - sub_no_defaults_2, - path1, - &t1, - ) - .is_some() - { - return values; - } - - // We can't find anything in common, highlight relevant part of type path. - // let x: foo::bar::Baz<Qux> = y:<foo::bar::Bar<Zar>>(); - // foo::bar::Baz<Qux> - // foo::bar::Bar<Zar> - // -------- this part of the path is different - - let t1_str = t1.to_string(); - let t2_str = t2.to_string(); - let min_len = t1_str.len().min(t2_str.len()); - - const SEPARATOR: &str = "::"; - let separator_len = SEPARATOR.len(); - let split_idx: usize = t1_str - .split(SEPARATOR) - .zip(t2_str.split(SEPARATOR)) - .take_while(|(mod1_str, mod2_str)| mod1_str == mod2_str) - .map(|(mod_str, _)| mod_str.len() + separator_len) - .sum(); - - debug!( - "cmp: separator_len={}, split_idx={}, min_len={}", - separator_len, split_idx, min_len - ); - - if split_idx >= min_len { - // paths are identical, highlight everything - ( - DiagnosticStyledString::highlighted(t1_str), - DiagnosticStyledString::highlighted(t2_str), - ) - } else { - let (common, uniq1) = t1_str.split_at(split_idx); - let (_, uniq2) = t2_str.split_at(split_idx); - debug!("cmp: common={}, uniq1={}, uniq2={}", common, uniq1, uniq2); - - values.0.push_normal(common); - values.0.push_highlighted(uniq1); - values.1.push_normal(common); - values.1.push_highlighted(uniq2); - - values - } - } - } - - // When finding T != &T, highlight only the borrow - (&ty::Ref(r1, ref_ty1, mutbl1), _) if equals(&ref_ty1, &t2) => { - let mut values = (DiagnosticStyledString::new(), DiagnosticStyledString::new()); - push_ty_ref(&r1, ref_ty1, mutbl1, &mut values.0); - values.1.push_normal(t2.to_string()); - values - } - (_, &ty::Ref(r2, ref_ty2, mutbl2)) if equals(&t1, &ref_ty2) => { - let mut values = (DiagnosticStyledString::new(), DiagnosticStyledString::new()); - values.0.push_normal(t1.to_string()); - push_ty_ref(&r2, ref_ty2, mutbl2, &mut values.1); - values - } - - // When encountering &T != &mut T, highlight only the borrow - (&ty::Ref(r1, ref_ty1, mutbl1), &ty::Ref(r2, ref_ty2, mutbl2)) - if equals(&ref_ty1, &ref_ty2) => - { - let mut values = (DiagnosticStyledString::new(), DiagnosticStyledString::new()); - push_ty_ref(&r1, ref_ty1, mutbl1, &mut values.0); - push_ty_ref(&r2, ref_ty2, mutbl2, &mut values.1); - values - } - - // When encountering tuples of the same size, highlight only the differing types - (&ty::Tuple(substs1), &ty::Tuple(substs2)) if substs1.len() == substs2.len() => { - let mut values = - (DiagnosticStyledString::normal("("), DiagnosticStyledString::normal("(")); - let len = substs1.len(); - for (i, (left, right)) in substs1.types().zip(substs2.types()).enumerate() { - let (x1, x2) = self.cmp(left, right); - (values.0).0.extend(x1.0); - (values.1).0.extend(x2.0); - self.push_comma(&mut values.0, &mut values.1, len, i); - } - if len == 1 { - // Keep the output for single element tuples as `(ty,)`. - values.0.push_normal(","); - values.1.push_normal(","); - } - values.0.push_normal(")"); - values.1.push_normal(")"); - values - } - - (ty::FnDef(did1, substs1), ty::FnDef(did2, substs2)) => { - let sig1 = self.tcx.fn_sig(*did1).subst(self.tcx, substs1); - let sig2 = self.tcx.fn_sig(*did2).subst(self.tcx, substs2); - let mut values = self.cmp_fn_sig(&sig1, &sig2); - let path1 = format!(" {{{}}}", self.tcx.def_path_str_with_substs(*did1, substs1)); - let path2 = format!(" {{{}}}", self.tcx.def_path_str_with_substs(*did2, substs2)); - let same_path = path1 == path2; - values.0.push(path1, !same_path); - values.1.push(path2, !same_path); - values - } - - (ty::FnDef(did1, substs1), ty::FnPtr(sig2)) => { - let sig1 = self.tcx.fn_sig(*did1).subst(self.tcx, substs1); - let mut values = self.cmp_fn_sig(&sig1, sig2); - values.0.push_normal(format!( - " {{{}}}", - self.tcx.def_path_str_with_substs(*did1, substs1) - )); - values - } - - (ty::FnPtr(sig1), ty::FnDef(did2, substs2)) => { - let sig2 = self.tcx.fn_sig(*did2).subst(self.tcx, substs2); - let mut values = self.cmp_fn_sig(sig1, &sig2); - values.1.push_normal(format!( - " {{{}}}", - self.tcx.def_path_str_with_substs(*did2, substs2) - )); - values - } - - (ty::FnPtr(sig1), ty::FnPtr(sig2)) => self.cmp_fn_sig(sig1, sig2), - - _ => { - if t1 == t2 { - // The two types are the same, elide and don't highlight. - (DiagnosticStyledString::normal("_"), DiagnosticStyledString::normal("_")) - } else { - // We couldn't find anything in common, highlight everything. - ( - DiagnosticStyledString::highlighted(t1.to_string()), - DiagnosticStyledString::highlighted(t2.to_string()), - ) - } - } - } - } - - pub fn note_type_err( - &self, - diag: &mut DiagnosticBuilder<'tcx>, - cause: &ObligationCause<'tcx>, - secondary_span: Option<(Span, String)>, - mut values: Option<ValuePairs<'tcx>>, - terr: &TypeError<'tcx>, - ) { - let span = cause.span(self.tcx); - - // For some types of errors, expected-found does not make - // sense, so just ignore the values we were given. - match terr { - TypeError::CyclicTy(_) => { - values = None; - } - _ => {} - } - - struct OpaqueTypesVisitor<'tcx> { - types: FxHashMap<TyCategory, FxHashSet<Span>>, - expected: FxHashMap<TyCategory, FxHashSet<Span>>, - found: FxHashMap<TyCategory, FxHashSet<Span>>, - ignore_span: Span, - tcx: TyCtxt<'tcx>, - } - - impl<'tcx> OpaqueTypesVisitor<'tcx> { - fn visit_expected_found( - tcx: TyCtxt<'tcx>, - expected: Ty<'tcx>, - found: Ty<'tcx>, - ignore_span: Span, - ) -> Self { - let mut types_visitor = OpaqueTypesVisitor { - types: Default::default(), - expected: Default::default(), - found: Default::default(), - ignore_span, - tcx, - }; - // The visitor puts all the relevant encountered types in `self.types`, but in - // here we want to visit two separate types with no relation to each other, so we - // move the results from `types` to `expected` or `found` as appropriate. - expected.visit_with(&mut types_visitor); - std::mem::swap(&mut types_visitor.expected, &mut types_visitor.types); - found.visit_with(&mut types_visitor); - std::mem::swap(&mut types_visitor.found, &mut types_visitor.types); - types_visitor - } - - fn report(&self, err: &mut DiagnosticBuilder<'_>) { - self.add_labels_for_types(err, "expected", &self.expected); - self.add_labels_for_types(err, "found", &self.found); - } - - fn add_labels_for_types( - &self, - err: &mut DiagnosticBuilder<'_>, - target: &str, - types: &FxHashMap<TyCategory, FxHashSet<Span>>, - ) { - for (key, values) in types.iter() { - let count = values.len(); - let kind = key.descr(); - for sp in values { - err.span_label( - *sp, - format!( - "{}{}{} {}{}", - if sp.is_desugaring(DesugaringKind::Async) { - "the `Output` of this `async fn`'s " - } else if count == 1 { - "the " - } else { - "" - }, - if count > 1 { "one of the " } else { "" }, - target, - kind, - pluralize!(count), - ), - ); - } - } - } - } - - impl<'tcx> ty::fold::TypeVisitor<'tcx> for OpaqueTypesVisitor<'tcx> { - fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { - if let Some((kind, def_id)) = TyCategory::from_ty(t) { - let span = self.tcx.def_span(def_id); - // Avoid cluttering the output when the "found" and error span overlap: - // - // error[E0308]: mismatched types - // --> $DIR/issue-20862.rs:2:5 - // | - // LL | |y| x + y - // | ^^^^^^^^^ - // | | - // | the found closure - // | expected `()`, found closure - // | - // = note: expected unit type `()` - // found closure `[closure@$DIR/issue-20862.rs:2:5: 2:14 x:_]` - if !self.ignore_span.overlaps(span) { - self.types.entry(kind).or_default().insert(span); - } - } - t.super_visit_with(self) - } - } - - debug!("note_type_err(diag={:?})", diag); - let (expected_found, exp_found, is_simple_error) = match values { - None => (None, None, false), - Some(values) => { - let (is_simple_error, exp_found) = match values { - ValuePairs::Types(exp_found) => { - let is_simple_err = - exp_found.expected.is_simple_text() && exp_found.found.is_simple_text(); - OpaqueTypesVisitor::visit_expected_found( - self.tcx, - exp_found.expected, - exp_found.found, - span, - ) - .report(diag); - - (is_simple_err, Some(exp_found)) - } - _ => (false, None), - }; - let vals = match self.values_str(&values) { - Some((expected, found)) => Some((expected, found)), - None => { - // Derived error. Cancel the emitter. - diag.cancel(); - return; - } - }; - (vals, exp_found, is_simple_error) - } - }; - - // Ignore msg for object safe coercion - // since E0038 message will be printed - match terr { - TypeError::ObjectUnsafeCoercion(_) => {} - _ => { - diag.span_label(span, terr.to_string()); - if let Some((sp, msg)) = secondary_span { - diag.span_label(sp, msg); - } - } - }; - if let Some((expected, found)) = expected_found { - let expected_label = exp_found.map_or("type".into(), |ef| ef.expected.prefix_string()); - let found_label = exp_found.map_or("type".into(), |ef| ef.found.prefix_string()); - match (&terr, expected == found) { - (TypeError::Sorts(values), extra) => { - let sort_string = |ty: Ty<'tcx>| match (extra, &ty.kind) { - (true, ty::Opaque(def_id, _)) => format!( - " (opaque type at {})", - self.tcx - .sess - .source_map() - .mk_substr_filename(self.tcx.def_span(*def_id)), - ), - (true, _) => format!(" ({})", ty.sort_string(self.tcx)), - (false, _) => "".to_string(), - }; - if !(values.expected.is_simple_text() && values.found.is_simple_text()) - || (exp_found.map_or(false, |ef| { - // This happens when the type error is a subset of the expectation, - // like when you have two references but one is `usize` and the other - // is `f32`. In those cases we still want to show the `note`. If the - // value from `ef` is `Infer(_)`, then we ignore it. - if !ef.expected.is_ty_infer() { - ef.expected != values.expected - } else if !ef.found.is_ty_infer() { - ef.found != values.found - } else { - false - } - })) - { - diag.note_expected_found_extra( - &expected_label, - expected, - &found_label, - found, - &sort_string(values.expected), - &sort_string(values.found), - ); - } - } - (TypeError::ObjectUnsafeCoercion(_), _) => { - diag.note_unsuccessfull_coercion(found, expected); - } - (_, _) => { - debug!( - "note_type_err: exp_found={:?}, expected={:?} found={:?}", - exp_found, expected, found - ); - if !is_simple_error || terr.must_include_note() { - diag.note_expected_found(&expected_label, expected, &found_label, found); - } - } - } - } - if let Some(exp_found) = exp_found { - self.suggest_as_ref_where_appropriate(span, &exp_found, diag); - } - - // In some (most?) cases cause.body_id points to actual body, but in some cases - // it's a actual definition. According to the comments (e.g. in - // librustc_typeck/check/compare_method.rs:compare_predicate_entailment) the latter - // is relied upon by some other code. This might (or might not) need cleanup. - let body_owner_def_id = - self.tcx.hir().opt_local_def_id(cause.body_id).unwrap_or_else(|| { - self.tcx.hir().body_owner_def_id(hir::BodyId { hir_id: cause.body_id }) - }); - self.check_and_note_conflicting_crates(diag, terr); - self.tcx.note_and_explain_type_err(diag, terr, span, body_owner_def_id); - - // It reads better to have the error origin as the final - // thing. - self.note_error_origin(diag, &cause, exp_found); - } - - /// When encountering a case where `.as_ref()` on a `Result` or `Option` would be appropriate, - /// suggests it. - fn suggest_as_ref_where_appropriate( - &self, - span: Span, - exp_found: &ty::error::ExpectedFound<Ty<'tcx>>, - diag: &mut DiagnosticBuilder<'tcx>, - ) { - match (&exp_found.expected.kind, &exp_found.found.kind) { - (ty::Adt(exp_def, exp_substs), ty::Ref(_, found_ty, _)) => { - if let ty::Adt(found_def, found_substs) = found_ty.kind { - let path_str = format!("{:?}", exp_def); - if exp_def == &found_def { - let opt_msg = "you can convert from `&Option<T>` to `Option<&T>` using \ - `.as_ref()`"; - let result_msg = "you can convert from `&Result<T, E>` to \ - `Result<&T, &E>` using `.as_ref()`"; - let have_as_ref = &[ - ("std::option::Option", opt_msg), - ("core::option::Option", opt_msg), - ("std::result::Result", result_msg), - ("core::result::Result", result_msg), - ]; - if let Some(msg) = have_as_ref - .iter() - .filter_map( - |(path, msg)| if &path_str == path { Some(msg) } else { None }, - ) - .next() - { - let mut show_suggestion = true; - for (exp_ty, found_ty) in exp_substs.types().zip(found_substs.types()) { - match exp_ty.kind { - ty::Ref(_, exp_ty, _) => { - match (&exp_ty.kind, &found_ty.kind) { - (_, ty::Param(_)) - | (_, ty::Infer(_)) - | (ty::Param(_), _) - | (ty::Infer(_), _) => {} - _ if ty::TyS::same_type(exp_ty, found_ty) => {} - _ => show_suggestion = false, - }; - } - ty::Param(_) | ty::Infer(_) => {} - _ => show_suggestion = false, - } - } - if let (Ok(snippet), true) = - (self.tcx.sess.source_map().span_to_snippet(span), show_suggestion) - { - diag.span_suggestion( - span, - msg, - format!("{}.as_ref()", snippet), - Applicability::MachineApplicable, - ); - } - } - } - } - } - _ => {} - } - } - - pub fn report_and_explain_type_error( - &self, - trace: TypeTrace<'tcx>, - terr: &TypeError<'tcx>, - ) -> DiagnosticBuilder<'tcx> { - debug!("report_and_explain_type_error(trace={:?}, terr={:?})", trace, terr); - - let span = trace.cause.span(self.tcx); - let failure_code = trace.cause.as_failure_code(terr); - let mut diag = match failure_code { - FailureCode::Error0038(did) => { - let violations = object_safety_violations(self.tcx, did); - report_object_safety_error(self.tcx, span, did, violations) - } - FailureCode::Error0317(failure_str) => { - struct_span_err!(self.tcx.sess, span, E0317, "{}", failure_str) - } - FailureCode::Error0580(failure_str) => { - struct_span_err!(self.tcx.sess, span, E0580, "{}", failure_str) - } - FailureCode::Error0308(failure_str) => { - struct_span_err!(self.tcx.sess, span, E0308, "{}", failure_str) - } - FailureCode::Error0644(failure_str) => { - struct_span_err!(self.tcx.sess, span, E0644, "{}", failure_str) - } - }; - self.note_type_err(&mut diag, &trace.cause, None, Some(trace.values), terr); - diag - } - - fn values_str( - &self, - values: &ValuePairs<'tcx>, - ) -> Option<(DiagnosticStyledString, DiagnosticStyledString)> { - match *values { - infer::Types(ref exp_found) => self.expected_found_str_ty(exp_found), - infer::Regions(ref exp_found) => self.expected_found_str(exp_found), - infer::Consts(ref exp_found) => self.expected_found_str(exp_found), - infer::TraitRefs(ref exp_found) => { - let pretty_exp_found = ty::error::ExpectedFound { - expected: exp_found.expected.print_only_trait_path(), - found: exp_found.found.print_only_trait_path(), - }; - self.expected_found_str(&pretty_exp_found) - } - infer::PolyTraitRefs(ref exp_found) => { - let pretty_exp_found = ty::error::ExpectedFound { - expected: exp_found.expected.print_only_trait_path(), - found: exp_found.found.print_only_trait_path(), - }; - self.expected_found_str(&pretty_exp_found) - } - } - } - - fn expected_found_str_ty( - &self, - exp_found: &ty::error::ExpectedFound<Ty<'tcx>>, - ) -> Option<(DiagnosticStyledString, DiagnosticStyledString)> { - let exp_found = self.resolve_vars_if_possible(exp_found); - if exp_found.references_error() { - return None; - } - - Some(self.cmp(exp_found.expected, exp_found.found)) - } - - /// Returns a string of the form "expected `{}`, found `{}`". - fn expected_found_str<T: fmt::Display + TypeFoldable<'tcx>>( - &self, - exp_found: &ty::error::ExpectedFound<T>, - ) -> Option<(DiagnosticStyledString, DiagnosticStyledString)> { - let exp_found = self.resolve_vars_if_possible(exp_found); - if exp_found.references_error() { - return None; - } - - Some(( - DiagnosticStyledString::highlighted(exp_found.expected.to_string()), - DiagnosticStyledString::highlighted(exp_found.found.to_string()), - )) - } - - pub fn report_generic_bound_failure( - &self, - region_scope_tree: ®ion::ScopeTree, - span: Span, - origin: Option<SubregionOrigin<'tcx>>, - bound_kind: GenericKind<'tcx>, - sub: Region<'tcx>, - ) { - self.construct_generic_bound_failure(region_scope_tree, span, origin, bound_kind, sub) - .emit(); - } - - pub fn construct_generic_bound_failure( - &self, - region_scope_tree: ®ion::ScopeTree, - span: Span, - origin: Option<SubregionOrigin<'tcx>>, - bound_kind: GenericKind<'tcx>, - sub: Region<'tcx>, - ) -> DiagnosticBuilder<'a> { - // Attempt to obtain the span of the parameter so we can - // suggest adding an explicit lifetime bound to it. - let type_param_span = match (self.in_progress_tables, bound_kind) { - (Some(ref table), GenericKind::Param(ref param)) => { - let table = table.borrow(); - table.local_id_root.and_then(|did| { - let generics = self.tcx.generics_of(did); - // Account for the case where `did` corresponds to `Self`, which doesn't have - // the expected type argument. - if !(generics.has_self && param.index == 0) { - let type_param = generics.type_param(param, self.tcx); - let hir = &self.tcx.hir(); - hir.as_local_hir_id(type_param.def_id).map(|id| { - // Get the `hir::Param` to verify whether it already has any bounds. - // We do this to avoid suggesting code that ends up as `T: 'a'b`, - // instead we suggest `T: 'a + 'b` in that case. - let mut has_bounds = false; - if let Node::GenericParam(param) = hir.get(id) { - has_bounds = !param.bounds.is_empty(); - } - let sp = hir.span(id); - // `sp` only covers `T`, change it so that it covers - // `T:` when appropriate - let is_impl_trait = bound_kind.to_string().starts_with("impl "); - let sp = if has_bounds && !is_impl_trait { - sp.to(self - .tcx - .sess - .source_map() - .next_point(self.tcx.sess.source_map().next_point(sp))) - } else { - sp - }; - (sp, has_bounds, is_impl_trait) - }) - } else { - None - } - }) - } - _ => None, - }; - - let labeled_user_string = match bound_kind { - GenericKind::Param(ref p) => format!("the parameter type `{}`", p), - GenericKind::Projection(ref p) => format!("the associated type `{}`", p), - }; - - if let Some(SubregionOrigin::CompareImplMethodObligation { - span, - item_name, - impl_item_def_id, - trait_item_def_id, - }) = origin - { - return self.report_extra_impl_obligation( - span, - item_name, - impl_item_def_id, - trait_item_def_id, - &format!("`{}: {}`", bound_kind, sub), - ); - } - - fn binding_suggestion<'tcx, S: fmt::Display>( - err: &mut DiagnosticBuilder<'tcx>, - type_param_span: Option<(Span, bool, bool)>, - bound_kind: GenericKind<'tcx>, - sub: S, - ) { - let consider = format!( - "consider adding an explicit lifetime bound {}", - if type_param_span.map(|(_, _, is_impl_trait)| is_impl_trait).unwrap_or(false) { - format!(" `{}` to `{}`...", sub, bound_kind) - } else { - format!("`{}: {}`...", bound_kind, sub) - }, - ); - if let Some((sp, has_lifetimes, is_impl_trait)) = type_param_span { - let suggestion = if is_impl_trait { - format!("{} + {}", bound_kind, sub) - } else { - let tail = if has_lifetimes { " + " } else { "" }; - format!("{}: {}{}", bound_kind, sub, tail) - }; - err.span_suggestion_short( - sp, - &consider, - suggestion, - Applicability::MaybeIncorrect, // Issue #41966 - ); - } else { - err.help(&consider); - } - } - - let mut err = match *sub { - ty::ReEarlyBound(ty::EarlyBoundRegion { name, .. }) - | ty::ReFree(ty::FreeRegion { bound_region: ty::BrNamed(_, name), .. }) => { - // Does the required lifetime have a nice name we can print? - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0309, - "{} may not live long enough", - labeled_user_string - ); - // Explicitely use the name instead of `sub`'s `Display` impl. The `Display` impl - // for the bound is not suitable for suggestions when `-Zverbose` is set because it - // uses `Debug` output, so we handle it specially here so that suggestions are - // always correct. - binding_suggestion(&mut err, type_param_span, bound_kind, name); - err - } - - ty::ReStatic => { - // Does the required lifetime have a nice name we can print? - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0310, - "{} may not live long enough", - labeled_user_string - ); - binding_suggestion(&mut err, type_param_span, bound_kind, "'static"); - err - } - - _ => { - // If not, be less specific. - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0311, - "{} may not live long enough", - labeled_user_string - ); - err.help(&format!( - "consider adding an explicit lifetime bound for `{}`", - bound_kind - )); - note_and_explain_region( - self.tcx, - region_scope_tree, - &mut err, - &format!("{} must be valid for ", labeled_user_string), - sub, - "...", - ); - err - } - }; - - if let Some(origin) = origin { - self.note_region_origin(&mut err, &origin); - } - err - } - - fn report_sub_sup_conflict( - &self, - region_scope_tree: ®ion::ScopeTree, - var_origin: RegionVariableOrigin, - sub_origin: SubregionOrigin<'tcx>, - sub_region: Region<'tcx>, - sup_origin: SubregionOrigin<'tcx>, - sup_region: Region<'tcx>, - ) { - let mut err = self.report_inference_failure(var_origin); - - note_and_explain_region( - self.tcx, - region_scope_tree, - &mut err, - "first, the lifetime cannot outlive ", - sup_region, - "...", - ); - - match (&sup_origin, &sub_origin) { - (&infer::Subtype(ref sup_trace), &infer::Subtype(ref sub_trace)) => { - debug!("report_sub_sup_conflict: var_origin={:?}", var_origin); - debug!("report_sub_sup_conflict: sub_region={:?}", sub_region); - debug!("report_sub_sup_conflict: sub_origin={:?}", sub_origin); - debug!("report_sub_sup_conflict: sup_region={:?}", sup_region); - debug!("report_sub_sup_conflict: sup_origin={:?}", sup_origin); - debug!("report_sub_sup_conflict: sup_trace={:?}", sup_trace); - debug!("report_sub_sup_conflict: sub_trace={:?}", sub_trace); - debug!("report_sub_sup_conflict: sup_trace.values={:?}", sup_trace.values); - debug!("report_sub_sup_conflict: sub_trace.values={:?}", sub_trace.values); - - if let (Some((sup_expected, sup_found)), Some((sub_expected, sub_found))) = - (self.values_str(&sup_trace.values), self.values_str(&sub_trace.values)) - { - if sub_expected == sup_expected && sub_found == sup_found { - note_and_explain_region( - self.tcx, - region_scope_tree, - &mut err, - "...but the lifetime must also be valid for ", - sub_region, - "...", - ); - err.span_note( - sup_trace.cause.span, - &format!("...so that the {}", sup_trace.cause.as_requirement_str()), - ); - - err.note_expected_found(&"", sup_expected, &"", sup_found); - err.emit(); - return; - } - } - } - _ => {} - } - - self.note_region_origin(&mut err, &sup_origin); - - note_and_explain_region( - self.tcx, - region_scope_tree, - &mut err, - "but, the lifetime must be valid for ", - sub_region, - "...", - ); - - self.note_region_origin(&mut err, &sub_origin); - err.emit(); - } -} - -impl<'a, 'tcx> InferCtxt<'a, 'tcx> { - fn report_inference_failure( - &self, - var_origin: RegionVariableOrigin, - ) -> DiagnosticBuilder<'tcx> { - let br_string = |br: ty::BoundRegion| { - let mut s = match br { - ty::BrNamed(_, name) => name.to_string(), - _ => String::new(), - }; - if !s.is_empty() { - s.push_str(" "); - } - s - }; - let var_description = match var_origin { - infer::MiscVariable(_) => String::new(), - infer::PatternRegion(_) => " for pattern".to_string(), - infer::AddrOfRegion(_) => " for borrow expression".to_string(), - infer::Autoref(_) => " for autoref".to_string(), - infer::Coercion(_) => " for automatic coercion".to_string(), - infer::LateBoundRegion(_, br, infer::FnCall) => { - format!(" for lifetime parameter {}in function call", br_string(br)) - } - infer::LateBoundRegion(_, br, infer::HigherRankedType) => { - format!(" for lifetime parameter {}in generic type", br_string(br)) - } - infer::LateBoundRegion(_, br, infer::AssocTypeProjection(def_id)) => format!( - " for lifetime parameter {}in trait containing associated type `{}`", - br_string(br), - self.tcx.associated_item(def_id).ident - ), - infer::EarlyBoundRegion(_, name) => format!(" for lifetime parameter `{}`", name), - infer::BoundRegionInCoherence(name) => { - format!(" for lifetime parameter `{}` in coherence check", name) - } - infer::UpvarRegion(ref upvar_id, _) => { - let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id); - format!(" for capture of `{}` by closure", var_name) - } - infer::NLL(..) => bug!("NLL variable found in lexical phase"), - }; - - struct_span_err!( - self.tcx.sess, - var_origin.span(), - E0495, - "cannot infer an appropriate lifetime{} \ - due to conflicting requirements", - var_description - ) - } -} - -enum FailureCode { - Error0038(DefId), - Error0317(&'static str), - Error0580(&'static str), - Error0308(&'static str), - Error0644(&'static str), -} - -impl<'tcx> ObligationCause<'tcx> { - fn as_failure_code(&self, terr: &TypeError<'tcx>) -> FailureCode { - use self::FailureCode::*; - use crate::traits::ObligationCauseCode::*; - match self.code { - CompareImplMethodObligation { .. } => Error0308("method not compatible with trait"), - CompareImplTypeObligation { .. } => Error0308("type not compatible with trait"), - MatchExpressionArm(box MatchExpressionArmCause { source, .. }) => { - Error0308(match source { - hir::MatchSource::IfLetDesugar { .. } => { - "`if let` arms have incompatible types" - } - hir::MatchSource::TryDesugar => { - "try expression alternatives have incompatible types" - } - _ => "`match` arms have incompatible types", - }) - } - IfExpression { .. } => Error0308("`if` and `else` have incompatible types"), - IfExpressionWithNoElse => Error0317("`if` may be missing an `else` clause"), - MainFunctionType => Error0580("`main` function has wrong type"), - StartFunctionType => Error0308("`#[start]` function has wrong type"), - IntrinsicType => Error0308("intrinsic has wrong type"), - MethodReceiver => Error0308("mismatched `self` parameter type"), - - // In the case where we have no more specific thing to - // say, also take a look at the error code, maybe we can - // tailor to that. - _ => match terr { - TypeError::CyclicTy(ty) if ty.is_closure() || ty.is_generator() => { - Error0644("closure/generator type that references itself") - } - TypeError::IntrinsicCast => { - Error0308("cannot coerce intrinsics to function pointers") - } - TypeError::ObjectUnsafeCoercion(did) => Error0038(*did), - _ => Error0308("mismatched types"), - }, - } - } - - fn as_requirement_str(&self) -> &'static str { - use crate::traits::ObligationCauseCode::*; - match self.code { - CompareImplMethodObligation { .. } => "method type is compatible with trait", - CompareImplTypeObligation { .. } => "associated type is compatible with trait", - ExprAssignable => "expression is assignable", - MatchExpressionArm(box MatchExpressionArmCause { source, .. }) => match source { - hir::MatchSource::IfLetDesugar { .. } => "`if let` arms have compatible types", - _ => "`match` arms have compatible types", - }, - IfExpression { .. } => "`if` and `else` have incompatible types", - IfExpressionWithNoElse => "`if` missing an `else` returns `()`", - MainFunctionType => "`main` function has the correct type", - StartFunctionType => "`#[start]` function has the correct type", - IntrinsicType => "intrinsic has the correct type", - MethodReceiver => "method receiver has the correct type", - _ => "types are compatible", - } - } -} - -/// This is a bare signal of what kind of type we're dealing with. `ty::TyKind` tracks -/// extra information about each type, but we only care about the category. -#[derive(Clone, Copy, PartialEq, Eq, Hash)] -crate enum TyCategory { - Closure, - Opaque, - Generator, - Foreign, -} - -impl TyCategory { - fn descr(&self) -> &'static str { - match self { - Self::Closure => "closure", - Self::Opaque => "opaque type", - Self::Generator => "generator", - Self::Foreign => "foreign type", - } - } - - pub fn from_ty(ty: Ty<'_>) -> Option<(Self, DefId)> { - match ty.kind { - ty::Closure(def_id, _) => Some((Self::Closure, def_id)), - ty::Opaque(def_id, _) => Some((Self::Opaque, def_id)), - ty::Generator(def_id, ..) => Some((Self::Generator, def_id)), - ty::Foreign(def_id) => Some((Self::Foreign, def_id)), - _ => None, - } - } -} diff --git a/src/librustc/infer/error_reporting/need_type_info.rs b/src/librustc/infer/error_reporting/need_type_info.rs deleted file mode 100644 index 0d7fce7eac6..00000000000 --- a/src/librustc/infer/error_reporting/need_type_info.rs +++ /dev/null @@ -1,552 +0,0 @@ -use crate::hir::map::Map; -use crate::infer::type_variable::TypeVariableOriginKind; -use crate::infer::InferCtxt; -use crate::ty::print::Print; -use crate::ty::{self, DefIdTree, Infer, Ty, TyVar}; -use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; -use rustc_hir as hir; -use rustc_hir::def::{DefKind, Namespace}; -use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; -use rustc_hir::{Body, Expr, ExprKind, FunctionRetTy, HirId, Local, Pat}; -use rustc_span::source_map::DesugaringKind; -use rustc_span::symbol::kw; -use rustc_span::Span; -use std::borrow::Cow; - -struct FindLocalByTypeVisitor<'a, 'tcx> { - infcx: &'a InferCtxt<'a, 'tcx>, - target_ty: Ty<'tcx>, - hir_map: &'a Map<'tcx>, - found_local_pattern: Option<&'tcx Pat<'tcx>>, - found_arg_pattern: Option<&'tcx Pat<'tcx>>, - found_ty: Option<Ty<'tcx>>, - found_closure: Option<&'tcx ExprKind<'tcx>>, - found_method_call: Option<&'tcx Expr<'tcx>>, -} - -impl<'a, 'tcx> FindLocalByTypeVisitor<'a, 'tcx> { - fn new(infcx: &'a InferCtxt<'a, 'tcx>, target_ty: Ty<'tcx>, hir_map: &'a Map<'tcx>) -> Self { - Self { - infcx, - target_ty, - hir_map, - found_local_pattern: None, - found_arg_pattern: None, - found_ty: None, - found_closure: None, - found_method_call: None, - } - } - - fn node_matches_type(&mut self, hir_id: HirId) -> Option<Ty<'tcx>> { - let ty_opt = - self.infcx.in_progress_tables.and_then(|tables| tables.borrow().node_type_opt(hir_id)); - match ty_opt { - Some(ty) => { - let ty = self.infcx.resolve_vars_if_possible(&ty); - if ty.walk().any(|inner_ty| { - inner_ty == self.target_ty - || match (&inner_ty.kind, &self.target_ty.kind) { - (&Infer(TyVar(a_vid)), &Infer(TyVar(b_vid))) => self - .infcx - .inner - .borrow_mut() - .type_variables - .sub_unified(a_vid, b_vid), - _ => false, - } - }) { - Some(ty) - } else { - None - } - } - None => None, - } - } -} - -impl<'a, 'tcx> Visitor<'tcx> for FindLocalByTypeVisitor<'a, 'tcx> { - type Map = Map<'tcx>; - - fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, Self::Map> { - NestedVisitorMap::OnlyBodies(&self.hir_map) - } - - fn visit_local(&mut self, local: &'tcx Local<'tcx>) { - if let (None, Some(ty)) = (self.found_local_pattern, self.node_matches_type(local.hir_id)) { - self.found_local_pattern = Some(&*local.pat); - self.found_ty = Some(ty); - } - intravisit::walk_local(self, local); - } - - fn visit_body(&mut self, body: &'tcx Body<'tcx>) { - for param in body.params { - if let (None, Some(ty)) = (self.found_arg_pattern, self.node_matches_type(param.hir_id)) - { - self.found_arg_pattern = Some(&*param.pat); - self.found_ty = Some(ty); - } - } - intravisit::walk_body(self, body); - } - - fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { - if self.node_matches_type(expr.hir_id).is_some() { - match expr.kind { - ExprKind::Closure(..) => self.found_closure = Some(&expr.kind), - ExprKind::MethodCall(..) => self.found_method_call = Some(&expr), - _ => {} - } - } - intravisit::walk_expr(self, expr); - } -} - -/// Suggest giving an appropriate return type to a closure expression. -fn closure_return_type_suggestion( - span: Span, - err: &mut DiagnosticBuilder<'_>, - output: &FunctionRetTy<'_>, - body: &Body<'_>, - descr: &str, - name: &str, - ret: &str, - parent_name: Option<String>, - parent_descr: Option<&str>, -) { - let (arrow, post) = match output { - FunctionRetTy::DefaultReturn(_) => ("-> ", " "), - _ => ("", ""), - }; - let suggestion = match body.value.kind { - ExprKind::Block(..) => vec![(output.span(), format!("{}{}{}", arrow, ret, post))], - _ => vec![ - (output.span(), format!("{}{}{}{{ ", arrow, ret, post)), - (body.value.span.shrink_to_hi(), " }".to_string()), - ], - }; - err.multipart_suggestion( - "give this closure an explicit return type without `_` placeholders", - suggestion, - Applicability::HasPlaceholders, - ); - err.span_label(span, InferCtxt::missing_type_msg(&name, &descr, parent_name, parent_descr)); -} - -/// Given a closure signature, return a `String` containing a list of all its argument types. -fn closure_args(fn_sig: &ty::PolyFnSig<'_>) -> String { - fn_sig - .inputs() - .skip_binder() - .iter() - .next() - .map(|args| args.tuple_fields().map(|arg| arg.to_string()).collect::<Vec<_>>().join(", ")) - .unwrap_or_default() -} - -pub enum TypeAnnotationNeeded { - E0282, - E0283, - E0284, -} - -impl Into<rustc_errors::DiagnosticId> for TypeAnnotationNeeded { - fn into(self) -> rustc_errors::DiagnosticId { - match self { - Self::E0282 => rustc_errors::error_code!(E0282), - Self::E0283 => rustc_errors::error_code!(E0283), - Self::E0284 => rustc_errors::error_code!(E0284), - } - } -} - -impl<'a, 'tcx> InferCtxt<'a, 'tcx> { - pub fn extract_type_name( - &self, - ty: Ty<'tcx>, - highlight: Option<ty::print::RegionHighlightMode>, - ) -> (String, Option<Span>, Cow<'static, str>, Option<String>, Option<&'static str>) { - if let ty::Infer(ty::TyVar(ty_vid)) = ty.kind { - let ty_vars = &self.inner.borrow().type_variables; - let var_origin = ty_vars.var_origin(ty_vid); - if let TypeVariableOriginKind::TypeParameterDefinition(name, def_id) = var_origin.kind { - let parent_def_id = def_id.and_then(|def_id| self.tcx.parent(def_id)); - let (parent_name, parent_desc) = if let Some(parent_def_id) = parent_def_id { - let parent_name = self - .tcx - .def_key(parent_def_id) - .disambiguated_data - .data - .get_opt_name() - .map(|parent_symbol| parent_symbol.to_string()); - - let type_parent_desc = self - .tcx - .def_kind(parent_def_id) - .map(|parent_def_kind| parent_def_kind.descr(parent_def_id)); - - (parent_name, type_parent_desc) - } else { - (None, None) - }; - - if name != kw::SelfUpper { - return ( - name.to_string(), - Some(var_origin.span), - "type parameter".into(), - parent_name, - parent_desc, - ); - } - } - } - - let mut s = String::new(); - let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS); - if let Some(highlight) = highlight { - printer.region_highlight_mode = highlight; - } - let _ = ty.print(printer); - (s, None, ty.prefix_string(), None, None) - } - - pub fn need_type_info_err( - &self, - body_id: Option<hir::BodyId>, - span: Span, - ty: Ty<'tcx>, - error_code: TypeAnnotationNeeded, - ) -> DiagnosticBuilder<'tcx> { - let ty = self.resolve_vars_if_possible(&ty); - let (name, name_sp, descr, parent_name, parent_descr) = self.extract_type_name(&ty, None); - - let mut local_visitor = FindLocalByTypeVisitor::new(&self, ty, &self.tcx.hir()); - let ty_to_string = |ty: Ty<'tcx>| -> String { - let mut s = String::new(); - let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS); - let ty_vars = &self.inner.borrow().type_variables; - let getter = move |ty_vid| { - let var_origin = ty_vars.var_origin(ty_vid); - if let TypeVariableOriginKind::TypeParameterDefinition(name, _) = var_origin.kind { - return Some(name.to_string()); - } - None - }; - printer.name_resolver = Some(Box::new(&getter)); - let _ = ty.print(printer); - s - }; - - if let Some(body_id) = body_id { - let expr = self.tcx.hir().expect_expr(body_id.hir_id); - local_visitor.visit_expr(expr); - } - let err_span = if let Some(pattern) = local_visitor.found_arg_pattern { - pattern.span - } else if let Some(span) = name_sp { - // `span` here lets us point at `sum` instead of the entire right hand side expr: - // error[E0282]: type annotations needed - // --> file2.rs:3:15 - // | - // 3 | let _ = x.sum() as f64; - // | ^^^ cannot infer type for `S` - span - } else if let Some(ExprKind::MethodCall(_, call_span, _)) = - local_visitor.found_method_call.map(|e| &e.kind) - { - // Point at the call instead of the whole expression: - // error[E0284]: type annotations needed - // --> file.rs:2:5 - // | - // 2 | vec![Ok(2)].into_iter().collect()?; - // | ^^^^^^^ cannot infer type - // | - // = note: cannot resolve `<_ as std::ops::Try>::Ok == _` - if span.contains(*call_span) { *call_span } else { span } - } else { - span - }; - - let is_named_and_not_impl_trait = |ty: Ty<'_>| { - &ty.to_string() != "_" && - // FIXME: Remove this check after `impl_trait_in_bindings` is stabilized. #63527 - (!ty.is_impl_trait() || self.tcx.features().impl_trait_in_bindings) - }; - - let ty_msg = match local_visitor.found_ty { - Some(ty::TyS { kind: ty::Closure(def_id, substs), .. }) => { - let fn_sig = substs.as_closure().sig(*def_id, self.tcx); - let args = closure_args(&fn_sig); - let ret = fn_sig.output().skip_binder().to_string(); - format!(" for the closure `fn({}) -> {}`", args, ret) - } - Some(ty) if is_named_and_not_impl_trait(ty) => { - let ty = ty_to_string(ty); - format!(" for `{}`", ty) - } - _ => String::new(), - }; - - // When `name` corresponds to a type argument, show the path of the full type we're - // trying to infer. In the following example, `ty_msg` contains - // " in `std::result::Result<i32, E>`": - // ``` - // error[E0282]: type annotations needed for `std::result::Result<i32, E>` - // --> file.rs:L:CC - // | - // L | let b = Ok(4); - // | - ^^ cannot infer type for `E` in `std::result::Result<i32, E>` - // | | - // | consider giving `b` the explicit type `std::result::Result<i32, E>`, where - // | the type parameter `E` is specified - // ``` - let error_code = error_code.into(); - let mut err = self.tcx.sess.struct_span_err_with_code( - err_span, - &format!("type annotations needed{}", ty_msg), - error_code, - ); - - let suffix = match local_visitor.found_ty { - Some(ty::TyS { kind: ty::Closure(def_id, substs), .. }) => { - let fn_sig = substs.as_closure().sig(*def_id, self.tcx); - let ret = fn_sig.output().skip_binder().to_string(); - - if let Some(ExprKind::Closure(_, decl, body_id, ..)) = local_visitor.found_closure { - if let Some(body) = self.tcx.hir().krate().bodies.get(body_id) { - closure_return_type_suggestion( - span, - &mut err, - &decl.output, - &body, - &descr, - &name, - &ret, - parent_name, - parent_descr, - ); - // We don't want to give the other suggestions when the problem is the - // closure return type. - return err; - } - } - - // This shouldn't be reachable, but just in case we leave a reasonable fallback. - let args = closure_args(&fn_sig); - // This suggestion is incomplete, as the user will get further type inference - // errors due to the `_` placeholders and the introduction of `Box`, but it does - // nudge them in the right direction. - format!("a boxed closure type like `Box<dyn Fn({}) -> {}>`", args, ret) - } - Some(ty) if is_named_and_not_impl_trait(ty) && name == "_" => { - let ty = ty_to_string(ty); - format!("the explicit type `{}`, with the type parameters specified", ty) - } - Some(ty) if is_named_and_not_impl_trait(ty) && ty.to_string() != name => { - let ty = ty_to_string(ty); - format!( - "the explicit type `{}`, where the type parameter `{}` is specified", - ty, name, - ) - } - _ => "a type".to_string(), - }; - - if let Some(pattern) = local_visitor.found_arg_pattern { - // We don't want to show the default label for closures. - // - // So, before clearing, the output would look something like this: - // ``` - // let x = |_| { }; - // - ^^^^ cannot infer type for `[_; 0]` - // | - // consider giving this closure parameter a type - // ``` - // - // After clearing, it looks something like this: - // ``` - // let x = |_| { }; - // ^ consider giving this closure parameter the type `[_; 0]` - // with the type parameter `_` specified - // ``` - err.span_label( - pattern.span, - format!("consider giving this closure parameter {}", suffix), - ); - } else if let Some(pattern) = local_visitor.found_local_pattern { - let msg = if let Some(simple_ident) = pattern.simple_ident() { - match pattern.span.desugaring_kind() { - None => format!("consider giving `{}` {}", simple_ident, suffix), - Some(DesugaringKind::ForLoop) => { - "the element type for this iterator is not specified".to_string() - } - _ => format!("this needs {}", suffix), - } - } else { - format!("consider giving this pattern {}", suffix) - }; - err.span_label(pattern.span, msg); - } else if let Some(e) = local_visitor.found_method_call { - if let ExprKind::MethodCall(segment, ..) = &e.kind { - // Suggest specifiying type params or point out the return type of the call: - // - // error[E0282]: type annotations needed - // --> $DIR/type-annotations-needed-expr.rs:2:39 - // | - // LL | let _ = x.into_iter().sum() as f64; - // | ^^^ - // | | - // | cannot infer type for `S` - // | help: consider specifying the type argument in - // | the method call: `sum::<S>` - // | - // = note: type must be known at this point - // - // or - // - // error[E0282]: type annotations needed - // --> $DIR/issue-65611.rs:59:20 - // | - // LL | let x = buffer.last().unwrap().0.clone(); - // | -------^^^^-- - // | | | - // | | cannot infer type for `T` - // | this method call resolves to `std::option::Option<&T>` - // | - // = note: type must be known at this point - self.annotate_method_call(segment, e, &mut err); - } - } - // Instead of the following: - // error[E0282]: type annotations needed - // --> file2.rs:3:15 - // | - // 3 | let _ = x.sum() as f64; - // | --^^^--------- cannot infer type for `S` - // | - // = note: type must be known at this point - // We want: - // error[E0282]: type annotations needed - // --> file2.rs:3:15 - // | - // 3 | let _ = x.sum() as f64; - // | ^^^ cannot infer type for `S` - // | - // = note: type must be known at this point - let span = name_sp.unwrap_or(err_span); - if !err - .span - .span_labels() - .iter() - .any(|span_label| span_label.label.is_some() && span_label.span == span) - && local_visitor.found_arg_pattern.is_none() - { - // Avoid multiple labels pointing at `span`. - err.span_label( - span, - InferCtxt::missing_type_msg(&name, &descr, parent_name, parent_descr), - ); - } - - err - } - - /// If the `FnSig` for the method call can be found and type arguments are identified as - /// needed, suggest annotating the call, otherwise point out the resulting type of the call. - fn annotate_method_call( - &self, - segment: &hir::PathSegment<'_>, - e: &Expr<'_>, - err: &mut DiagnosticBuilder<'_>, - ) { - if let (Ok(snippet), Some(tables), None) = ( - self.tcx.sess.source_map().span_to_snippet(segment.ident.span), - self.in_progress_tables, - &segment.args, - ) { - let borrow = tables.borrow(); - if let Some((DefKind::Method, did)) = borrow.type_dependent_def(e.hir_id) { - let generics = self.tcx.generics_of(did); - if !generics.params.is_empty() { - err.span_suggestion( - segment.ident.span, - &format!( - "consider specifying the type argument{} in the method call", - if generics.params.len() > 1 { "s" } else { "" }, - ), - format!( - "{}::<{}>", - snippet, - generics - .params - .iter() - .map(|p| p.name.to_string()) - .collect::<Vec<String>>() - .join(", ") - ), - Applicability::HasPlaceholders, - ); - } else { - let sig = self.tcx.fn_sig(did); - let bound_output = sig.output(); - let output = bound_output.skip_binder(); - err.span_label(e.span, &format!("this method call resolves to `{:?}`", output)); - let kind = &output.kind; - if let ty::Projection(proj) | ty::UnnormalizedProjection(proj) = kind { - if let Some(span) = self.tcx.hir().span_if_local(proj.item_def_id) { - err.span_label(span, &format!("`{:?}` defined here", output)); - } - } - } - } - } - } - - pub fn need_type_info_err_in_generator( - &self, - kind: hir::GeneratorKind, - span: Span, - ty: Ty<'tcx>, - ) -> DiagnosticBuilder<'tcx> { - let ty = self.resolve_vars_if_possible(&ty); - let (name, _, descr, parent_name, parent_descr) = self.extract_type_name(&ty, None); - - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0698, - "type inside {} must be known in this context", - kind, - ); - err.span_label(span, InferCtxt::missing_type_msg(&name, &descr, parent_name, parent_descr)); - err - } - - fn missing_type_msg( - type_name: &str, - descr: &str, - parent_name: Option<String>, - parent_descr: Option<&str>, - ) -> Cow<'static, str> { - if type_name == "_" { - "cannot infer type".into() - } else { - let parent_desc = if let Some(parent_name) = parent_name { - let parent_type_descr = if let Some(parent_descr) = parent_descr { - format!(" the {}", parent_descr) - } else { - "".into() - }; - - format!(" declared on{} `{}`", parent_type_descr, parent_name) - } else { - "".to_string() - }; - - format!("cannot infer type for {} `{}`{}", descr, type_name, parent_desc).into() - } - } -} diff --git a/src/librustc/infer/error_reporting/nice_region_error/different_lifetimes.rs b/src/librustc/infer/error_reporting/nice_region_error/different_lifetimes.rs deleted file mode 100644 index 6a9fe19e1ac..00000000000 --- a/src/librustc/infer/error_reporting/nice_region_error/different_lifetimes.rs +++ /dev/null @@ -1,136 +0,0 @@ -//! Error Reporting for Anonymous Region Lifetime Errors -//! where both the regions are anonymous. - -use crate::infer::error_reporting::nice_region_error::util::AnonymousParamInfo; -use crate::infer::error_reporting::nice_region_error::NiceRegionError; -use crate::util::common::ErrorReported; - -use rustc_errors::struct_span_err; - -impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { - /// Print the error message for lifetime errors when both the concerned regions are anonymous. - /// - /// Consider a case where we have - /// - /// ```no_run - /// fn foo(x: &mut Vec<&u8>, y: &u8) { - /// x.push(y); - /// } - /// ``` - /// - /// The example gives - /// - /// ```text - /// fn foo(x: &mut Vec<&u8>, y: &u8) { - /// --- --- these references are declared with different lifetimes... - /// x.push(y); - /// ^ ...but data from `y` flows into `x` here - /// ``` - /// - /// It has been extended for the case of structs too. - /// - /// Consider the example - /// - /// ```no_run - /// struct Ref<'a> { x: &'a u32 } - /// ``` - /// - /// ```text - /// fn foo(mut x: Vec<Ref>, y: Ref) { - /// --- --- these structs are declared with different lifetimes... - /// x.push(y); - /// ^ ...but data from `y` flows into `x` here - /// } - /// ``` - /// - /// It will later be extended to trait objects. - pub(super) fn try_report_anon_anon_conflict(&self) -> Option<ErrorReported> { - let (span, sub, sup) = self.regions()?; - - // Determine whether the sub and sup consist of both anonymous (elided) regions. - let anon_reg_sup = self.tcx().is_suitable_region(sup)?; - - let anon_reg_sub = self.tcx().is_suitable_region(sub)?; - let scope_def_id_sup = anon_reg_sup.def_id; - let bregion_sup = anon_reg_sup.boundregion; - let scope_def_id_sub = anon_reg_sub.def_id; - let bregion_sub = anon_reg_sub.boundregion; - - let ty_sup = self.find_anon_type(sup, &bregion_sup)?; - - let ty_sub = self.find_anon_type(sub, &bregion_sub)?; - - debug!( - "try_report_anon_anon_conflict: found_param1={:?} sup={:?} br1={:?}", - ty_sub, sup, bregion_sup - ); - debug!( - "try_report_anon_anon_conflict: found_param2={:?} sub={:?} br2={:?}", - ty_sup, sub, bregion_sub - ); - - let (ty_sup, ty_fndecl_sup) = ty_sup; - let (ty_sub, ty_fndecl_sub) = ty_sub; - - let AnonymousParamInfo { param: anon_param_sup, .. } = - self.find_param_with_region(sup, sup)?; - let AnonymousParamInfo { param: anon_param_sub, .. } = - self.find_param_with_region(sub, sub)?; - - let sup_is_ret_type = - self.is_return_type_anon(scope_def_id_sup, bregion_sup, ty_fndecl_sup); - let sub_is_ret_type = - self.is_return_type_anon(scope_def_id_sub, bregion_sub, ty_fndecl_sub); - - let span_label_var1 = match anon_param_sup.pat.simple_ident() { - Some(simple_ident) => format!(" from `{}`", simple_ident), - None => String::new(), - }; - - let span_label_var2 = match anon_param_sub.pat.simple_ident() { - Some(simple_ident) => format!(" into `{}`", simple_ident), - None => String::new(), - }; - - let (span_1, span_2, main_label, span_label) = match (sup_is_ret_type, sub_is_ret_type) { - (None, None) => { - let (main_label_1, span_label_1) = if ty_sup.hir_id == ty_sub.hir_id { - ( - "this type is declared with multiple lifetimes...".to_owned(), - "...but data with one lifetime flows into the other here".to_owned(), - ) - } else { - ( - "these two types are declared with different lifetimes...".to_owned(), - format!("...but data{} flows{} here", span_label_var1, span_label_var2), - ) - }; - (ty_sup.span, ty_sub.span, main_label_1, span_label_1) - } - - (Some(ret_span), _) => ( - ty_sub.span, - ret_span, - "this parameter and the return type are declared \ - with different lifetimes..." - .to_owned(), - format!("...but data{} is returned here", span_label_var1), - ), - (_, Some(ret_span)) => ( - ty_sup.span, - ret_span, - "this parameter and the return type are declared \ - with different lifetimes..." - .to_owned(), - format!("...but data{} is returned here", span_label_var1), - ), - }; - - struct_span_err!(self.tcx().sess, span, E0623, "lifetime mismatch") - .span_label(span_1, main_label) - .span_label(span_2, String::new()) - .span_label(span, span_label) - .emit(); - return Some(ErrorReported); - } -} diff --git a/src/librustc/infer/error_reporting/nice_region_error/find_anon_type.rs b/src/librustc/infer/error_reporting/nice_region_error/find_anon_type.rs deleted file mode 100644 index 8e2592b5318..00000000000 --- a/src/librustc/infer/error_reporting/nice_region_error/find_anon_type.rs +++ /dev/null @@ -1,268 +0,0 @@ -use crate::hir::map::Map; -use crate::infer::error_reporting::nice_region_error::NiceRegionError; -use crate::middle::resolve_lifetime as rl; -use crate::ty::{self, Region, TyCtxt}; -use rustc_hir as hir; -use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; -use rustc_hir::Node; - -impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { - /// This function calls the `visit_ty` method for the parameters - /// corresponding to the anonymous regions. The `nested_visitor.found_type` - /// contains the anonymous type. - /// - /// # Arguments - /// region - the anonymous region corresponding to the anon_anon conflict - /// br - the bound region corresponding to the above region which is of type `BrAnon(_)` - /// - /// # Example - /// ``` - /// fn foo(x: &mut Vec<&u8>, y: &u8) - /// { x.push(y); } - /// ``` - /// The function returns the nested type corresponding to the anonymous region - /// for e.g., `&u8` and Vec<`&u8`. - pub(super) fn find_anon_type( - &self, - region: Region<'tcx>, - br: &ty::BoundRegion, - ) -> Option<(&hir::Ty<'_>, &hir::FnDecl<'_>)> { - if let Some(anon_reg) = self.tcx().is_suitable_region(region) { - let def_id = anon_reg.def_id; - if let Some(hir_id) = self.tcx().hir().as_local_hir_id(def_id) { - let fndecl = match self.tcx().hir().get(hir_id) { - Node::Item(&hir::Item { kind: hir::ItemKind::Fn(ref m, ..), .. }) - | Node::TraitItem(&hir::TraitItem { - kind: hir::TraitItemKind::Method(ref m, ..), - .. - }) - | Node::ImplItem(&hir::ImplItem { - kind: hir::ImplItemKind::Method(ref m, ..), - .. - }) => &m.decl, - _ => return None, - }; - - return fndecl - .inputs - .iter() - .filter_map(|arg| self.find_component_for_bound_region(arg, br)) - .next() - .map(|ty| (ty, &**fndecl)); - } - } - None - } - - // This method creates a FindNestedTypeVisitor which returns the type corresponding - // to the anonymous region. - fn find_component_for_bound_region( - &self, - arg: &'tcx hir::Ty<'tcx>, - br: &ty::BoundRegion, - ) -> Option<&'tcx hir::Ty<'tcx>> { - let mut nested_visitor = FindNestedTypeVisitor { - tcx: self.tcx(), - bound_region: *br, - found_type: None, - current_index: ty::INNERMOST, - }; - nested_visitor.visit_ty(arg); - nested_visitor.found_type - } -} - -// The FindNestedTypeVisitor captures the corresponding `hir::Ty` of the -// anonymous region. The example above would lead to a conflict between -// the two anonymous lifetimes for &u8 in x and y respectively. This visitor -// would be invoked twice, once for each lifetime, and would -// walk the types like &mut Vec<&u8> and &u8 looking for the HIR -// where that lifetime appears. This allows us to highlight the -// specific part of the type in the error message. -struct FindNestedTypeVisitor<'tcx> { - tcx: TyCtxt<'tcx>, - // The bound_region corresponding to the Refree(freeregion) - // associated with the anonymous region we are looking for. - bound_region: ty::BoundRegion, - // The type where the anonymous lifetime appears - // for e.g., Vec<`&u8`> and <`&u8`> - found_type: Option<&'tcx hir::Ty<'tcx>>, - current_index: ty::DebruijnIndex, -} - -impl Visitor<'tcx> for FindNestedTypeVisitor<'tcx> { - type Map = Map<'tcx>; - - fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, Self::Map> { - NestedVisitorMap::OnlyBodies(&self.tcx.hir()) - } - - fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) { - match arg.kind { - hir::TyKind::BareFn(_) => { - self.current_index.shift_in(1); - intravisit::walk_ty(self, arg); - self.current_index.shift_out(1); - return; - } - - hir::TyKind::TraitObject(bounds, _) => { - for bound in bounds { - self.current_index.shift_in(1); - self.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None); - self.current_index.shift_out(1); - } - } - - hir::TyKind::Rptr(ref lifetime, _) => { - // the lifetime of the TyRptr - let hir_id = lifetime.hir_id; - match (self.tcx.named_region(hir_id), self.bound_region) { - // Find the index of the anonymous region that was part of the - // error. We will then search the function parameters for a bound - // region at the right depth with the same index - ( - Some(rl::Region::LateBoundAnon(debruijn_index, anon_index)), - ty::BrAnon(br_index), - ) => { - debug!( - "LateBoundAnon depth = {:?} anon_index = {:?} br_index={:?}", - debruijn_index, anon_index, br_index - ); - if debruijn_index == self.current_index && anon_index == br_index { - self.found_type = Some(arg); - return; // we can stop visiting now - } - } - - // Find the index of the named region that was part of the - // error. We will then search the function parameters for a bound - // region at the right depth with the same index - (Some(rl::Region::EarlyBound(_, id, _)), ty::BrNamed(def_id, _)) => { - debug!("EarlyBound id={:?} def_id={:?}", id, def_id); - if id == def_id { - self.found_type = Some(arg); - return; // we can stop visiting now - } - } - - // Find the index of the named region that was part of the - // error. We will then search the function parameters for a bound - // region at the right depth with the same index - ( - Some(rl::Region::LateBound(debruijn_index, id, _)), - ty::BrNamed(def_id, _), - ) => { - debug!( - "FindNestedTypeVisitor::visit_ty: LateBound depth = {:?}", - debruijn_index - ); - debug!("LateBound id={:?} def_id={:?}", id, def_id); - if debruijn_index == self.current_index && id == def_id { - self.found_type = Some(arg); - return; // we can stop visiting now - } - } - - (Some(rl::Region::Static), _) - | (Some(rl::Region::Free(_, _)), _) - | (Some(rl::Region::EarlyBound(_, _, _)), _) - | (Some(rl::Region::LateBound(_, _, _)), _) - | (Some(rl::Region::LateBoundAnon(_, _)), _) - | (None, _) => { - debug!("no arg found"); - } - } - } - // Checks if it is of type `hir::TyKind::Path` which corresponds to a struct. - hir::TyKind::Path(_) => { - let subvisitor = &mut TyPathVisitor { - tcx: self.tcx, - found_it: false, - bound_region: self.bound_region, - current_index: self.current_index, - }; - intravisit::walk_ty(subvisitor, arg); // call walk_ty; as visit_ty is empty, - // this will visit only outermost type - if subvisitor.found_it { - self.found_type = Some(arg); - } - } - _ => {} - } - // walk the embedded contents: e.g., if we are visiting `Vec<&Foo>`, - // go on to visit `&Foo` - intravisit::walk_ty(self, arg); - } -} - -// The visitor captures the corresponding `hir::Ty` of the anonymous region -// in the case of structs ie. `hir::TyKind::Path`. -// This visitor would be invoked for each lifetime corresponding to a struct, -// and would walk the types like Vec<Ref> in the above example and Ref looking for the HIR -// where that lifetime appears. This allows us to highlight the -// specific part of the type in the error message. -struct TyPathVisitor<'tcx> { - tcx: TyCtxt<'tcx>, - found_it: bool, - bound_region: ty::BoundRegion, - current_index: ty::DebruijnIndex, -} - -impl Visitor<'tcx> for TyPathVisitor<'tcx> { - type Map = Map<'tcx>; - - fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, Map<'tcx>> { - NestedVisitorMap::OnlyBodies(&self.tcx.hir()) - } - - fn visit_lifetime(&mut self, lifetime: &hir::Lifetime) { - match (self.tcx.named_region(lifetime.hir_id), self.bound_region) { - // the lifetime of the TyPath! - (Some(rl::Region::LateBoundAnon(debruijn_index, anon_index)), ty::BrAnon(br_index)) => { - if debruijn_index == self.current_index && anon_index == br_index { - self.found_it = true; - return; - } - } - - (Some(rl::Region::EarlyBound(_, id, _)), ty::BrNamed(def_id, _)) => { - debug!("EarlyBound id={:?} def_id={:?}", id, def_id); - if id == def_id { - self.found_it = true; - return; // we can stop visiting now - } - } - - (Some(rl::Region::LateBound(debruijn_index, id, _)), ty::BrNamed(def_id, _)) => { - debug!("FindNestedTypeVisitor::visit_ty: LateBound depth = {:?}", debruijn_index,); - debug!("id={:?}", id); - debug!("def_id={:?}", def_id); - if debruijn_index == self.current_index && id == def_id { - self.found_it = true; - return; // we can stop visiting now - } - } - - (Some(rl::Region::Static), _) - | (Some(rl::Region::EarlyBound(_, _, _)), _) - | (Some(rl::Region::LateBound(_, _, _)), _) - | (Some(rl::Region::LateBoundAnon(_, _)), _) - | (Some(rl::Region::Free(_, _)), _) - | (None, _) => { - debug!("no arg found"); - } - } - } - - fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) { - // ignore nested types - // - // If you have a type like `Foo<'a, &Ty>` we - // are only interested in the immediate lifetimes ('a). - // - // Making `visit_ty` empty will ignore the `&Ty` embedded - // inside, it will get reached by the outer visitor. - debug!("`Ty` corresponding to a struct is {:?}", arg); - } -} diff --git a/src/librustc/infer/error_reporting/nice_region_error/mod.rs b/src/librustc/infer/error_reporting/nice_region_error/mod.rs deleted file mode 100644 index b10a60ef6f1..00000000000 --- a/src/librustc/infer/error_reporting/nice_region_error/mod.rs +++ /dev/null @@ -1,87 +0,0 @@ -use crate::infer::lexical_region_resolve::RegionResolutionError; -use crate::infer::lexical_region_resolve::RegionResolutionError::*; -use crate::infer::InferCtxt; -use crate::ty::{self, TyCtxt}; -use crate::util::common::ErrorReported; -use rustc_errors::DiagnosticBuilder; -use rustc_span::source_map::Span; - -mod different_lifetimes; -mod find_anon_type; -mod named_anon_conflict; -mod outlives_closure; -mod placeholder_error; -mod static_impl_trait; -mod trait_impl_difference; -mod util; - -impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { - pub fn try_report_nice_region_error(&self, error: &RegionResolutionError<'tcx>) -> bool { - if let Some(tables) = self.in_progress_tables { - let tables = tables.borrow(); - NiceRegionError::new(self, error.clone(), Some(&tables)).try_report().is_some() - } else { - NiceRegionError::new(self, error.clone(), None).try_report().is_some() - } - } -} - -pub struct NiceRegionError<'cx, 'tcx> { - infcx: &'cx InferCtxt<'cx, 'tcx>, - error: Option<RegionResolutionError<'tcx>>, - regions: Option<(Span, ty::Region<'tcx>, ty::Region<'tcx>)>, - tables: Option<&'cx ty::TypeckTables<'tcx>>, -} - -impl<'cx, 'tcx> NiceRegionError<'cx, 'tcx> { - pub fn new( - infcx: &'cx InferCtxt<'cx, 'tcx>, - error: RegionResolutionError<'tcx>, - tables: Option<&'cx ty::TypeckTables<'tcx>>, - ) -> Self { - Self { infcx, error: Some(error), regions: None, tables } - } - - pub fn new_from_span( - infcx: &'cx InferCtxt<'cx, 'tcx>, - span: Span, - sub: ty::Region<'tcx>, - sup: ty::Region<'tcx>, - tables: Option<&'cx ty::TypeckTables<'tcx>>, - ) -> Self { - Self { infcx, error: None, regions: Some((span, sub, sup)), tables } - } - - fn tcx(&self) -> TyCtxt<'tcx> { - self.infcx.tcx - } - - pub fn try_report_from_nll(&self) -> Option<DiagnosticBuilder<'cx>> { - // Due to the improved diagnostics returned by the MIR borrow checker, only a subset of - // the nice region errors are required when running under the MIR borrow checker. - self.try_report_named_anon_conflict().or_else(|| self.try_report_placeholder_conflict()) - } - - pub fn try_report(&self) -> Option<ErrorReported> { - self.try_report_from_nll() - .map(|mut diag| { - diag.emit(); - ErrorReported - }) - .or_else(|| self.try_report_anon_anon_conflict()) - .or_else(|| self.try_report_outlives_closure()) - .or_else(|| self.try_report_static_impl_trait()) - .or_else(|| self.try_report_impl_not_conforming_to_trait()) - } - - pub fn regions(&self) -> Option<(Span, ty::Region<'tcx>, ty::Region<'tcx>)> { - match (&self.error, self.regions) { - (Some(ConcreteFailure(origin, sub, sup)), None) => Some((origin.span(), sub, sup)), - (Some(SubSupConflict(_, _, origin, sub, _, sup)), None) => { - Some((origin.span(), sub, sup)) - } - (None, Some((span, sub, sup))) => Some((span, sub, sup)), - _ => None, - } - } -} diff --git a/src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs b/src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs deleted file mode 100644 index 250dcff372c..00000000000 --- a/src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs +++ /dev/null @@ -1,130 +0,0 @@ -//! Error Reporting for Anonymous Region Lifetime Errors -//! where one region is named and the other is anonymous. -use crate::infer::error_reporting::nice_region_error::NiceRegionError; -use crate::ty; -use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; -use rustc_hir::{FunctionRetTy, TyKind}; - -impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { - /// When given a `ConcreteFailure` for a function with parameters containing a named region and - /// an anonymous region, emit an descriptive diagnostic error. - pub(super) fn try_report_named_anon_conflict(&self) -> Option<DiagnosticBuilder<'a>> { - let (span, sub, sup) = self.regions()?; - - debug!( - "try_report_named_anon_conflict(sub={:?}, sup={:?}, error={:?})", - sub, sup, self.error, - ); - - // Determine whether the sub and sup consist of one named region ('a) - // and one anonymous (elided) region. If so, find the parameter arg - // where the anonymous region appears (there must always be one; we - // only introduced anonymous regions in parameters) as well as a - // version new_ty of its type where the anonymous region is replaced - // with the named one.//scope_def_id - let (named, anon, anon_param_info, region_info) = if self.is_named_region(sub) - && self.tcx().is_suitable_region(sup).is_some() - && self.find_param_with_region(sup, sub).is_some() - { - ( - sub, - sup, - self.find_param_with_region(sup, sub).unwrap(), - self.tcx().is_suitable_region(sup).unwrap(), - ) - } else if self.is_named_region(sup) - && self.tcx().is_suitable_region(sub).is_some() - && self.find_param_with_region(sub, sup).is_some() - { - ( - sup, - sub, - self.find_param_with_region(sub, sup).unwrap(), - self.tcx().is_suitable_region(sub).unwrap(), - ) - } else { - return None; // inapplicable - }; - - debug!("try_report_named_anon_conflict: named = {:?}", named); - debug!("try_report_named_anon_conflict: anon_param_info = {:?}", anon_param_info); - debug!("try_report_named_anon_conflict: region_info = {:?}", region_info); - - let (param, new_ty, new_ty_span, br, is_first, scope_def_id, is_impl_item) = ( - anon_param_info.param, - anon_param_info.param_ty, - anon_param_info.param_ty_span, - anon_param_info.bound_region, - anon_param_info.is_first, - region_info.def_id, - region_info.is_impl_item, - ); - match br { - ty::BrAnon(_) => {} - _ => { - /* not an anonymous region */ - debug!("try_report_named_anon_conflict: not an anonymous region"); - return None; - } - } - - if is_impl_item { - debug!("try_report_named_anon_conflict: impl item, bail out"); - return None; - } - - if let Some((_, fndecl)) = self.find_anon_type(anon, &br) { - if self.is_return_type_anon(scope_def_id, br, fndecl).is_some() - || self.is_self_anon(is_first, scope_def_id) - { - return None; - } - if let FunctionRetTy::Return(ty) = &fndecl.output { - if let (TyKind::Def(_, _), ty::ReStatic) = (&ty.kind, sub) { - // This is an impl Trait return that evaluates de need of 'static. - // We handle this case better in `static_impl_trait`. - return None; - } - } - } - - let (error_var, span_label_var) = match param.pat.simple_ident() { - Some(simple_ident) => ( - format!("the type of `{}`", simple_ident), - format!("the type of `{}`", simple_ident), - ), - None => ("parameter type".to_owned(), "type".to_owned()), - }; - - let mut diag = struct_span_err!( - self.tcx().sess, - span, - E0621, - "explicit lifetime required in {}", - error_var - ); - - diag.span_label(span, format!("lifetime `{}` required", named)); - diag.span_suggestion( - new_ty_span, - &format!("add explicit lifetime `{}` to {}", named, span_label_var), - new_ty.to_string(), - Applicability::Unspecified, - ); - - Some(diag) - } - - // This method returns whether the given Region is Named - pub(super) fn is_named_region(&self, region: ty::Region<'tcx>) -> bool { - match *region { - ty::ReStatic => true, - ty::ReFree(ref free_region) => match free_region.bound_region { - ty::BrNamed(..) => true, - _ => false, - }, - ty::ReEarlyBound(ebr) => ebr.has_name(), - _ => false, - } - } -} diff --git a/src/librustc/infer/error_reporting/nice_region_error/outlives_closure.rs b/src/librustc/infer/error_reporting/nice_region_error/outlives_closure.rs deleted file mode 100644 index af0e5ef8005..00000000000 --- a/src/librustc/infer/error_reporting/nice_region_error/outlives_closure.rs +++ /dev/null @@ -1,116 +0,0 @@ -//! Error Reporting for Anonymous Region Lifetime Errors -//! where both the regions are anonymous. - -use crate::infer::error_reporting::nice_region_error::NiceRegionError; -use crate::infer::lexical_region_resolve::RegionResolutionError::SubSupConflict; -use crate::infer::SubregionOrigin; -use crate::ty::RegionKind; -use crate::util::common::ErrorReported; -use rustc_hir::{Expr, ExprKind::Closure, Node}; - -impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { - /// Print the error message for lifetime errors when binding escapes a closure. - /// - /// Consider a case where we have - /// - /// ```no_run - /// fn with_int<F>(f: F) where F: FnOnce(&isize) { - /// let x = 3; - /// f(&x); - /// } - /// fn main() { - /// let mut x = None; - /// with_int(|y| x = Some(y)); - /// } - /// ``` - /// - /// the output will be - /// - /// ```text - /// let mut x = None; - /// ----- borrowed data cannot be stored into here... - /// with_int(|y| x = Some(y)); - /// --- ^ cannot be stored outside of its closure - /// | - /// ...because it cannot outlive this closure - /// ``` - pub(super) fn try_report_outlives_closure(&self) -> Option<ErrorReported> { - if let Some(SubSupConflict(_, origin, ref sub_origin, _, ref sup_origin, sup_region)) = - self.error - { - // #45983: when trying to assign the contents of an argument to a binding outside of a - // closure, provide a specific message pointing this out. - if let ( - &SubregionOrigin::BindingTypeIsNotValidAtDecl(ref external_span), - &RegionKind::ReFree(ref free_region), - ) = (&sub_origin, sup_region) - { - let hir = &self.tcx().hir(); - if let Some(hir_id) = hir.as_local_hir_id(free_region.scope) { - if let Node::Expr(Expr { kind: Closure(_, _, _, closure_span, None), .. }) = - hir.get(hir_id) - { - let sup_sp = sup_origin.span(); - let origin_sp = origin.span(); - let mut err = self.tcx().sess.struct_span_err( - sup_sp, - "borrowed data cannot be stored outside of its closure", - ); - err.span_label(sup_sp, "cannot be stored outside of its closure"); - if origin_sp == sup_sp || origin_sp.contains(sup_sp) { - // // sup_sp == origin.span(): - // - // let mut x = None; - // ----- borrowed data cannot be stored into here... - // with_int(|y| x = Some(y)); - // --- ^ cannot be stored outside of its closure - // | - // ...because it cannot outlive this closure - // - // // origin.contains(&sup_sp): - // - // let mut f: Option<&u32> = None; - // ----- borrowed data cannot be stored into here... - // closure_expecting_bound(|x: &'x u32| { - // ------------ ... because it cannot outlive this closure - // f = Some(x); - // ^ cannot be stored outside of its closure - err.span_label( - *external_span, - "borrowed data cannot be stored into here...", - ); - err.span_label( - *closure_span, - "...because it cannot outlive this closure", - ); - } else { - // FIXME: the wording for this case could be much improved - // - // let mut lines_to_use: Vec<&CrateId> = Vec::new(); - // - cannot infer an appropriate lifetime... - // let push_id = |installed_id: &CrateId| { - // ------- ------------------------ borrowed data cannot outlive this closure - // | - // ...so that variable is valid at time of its declaration - // lines_to_use.push(installed_id); - // ^^^^^^^^^^^^ cannot be stored outside of its closure - err.span_label(origin_sp, "cannot infer an appropriate lifetime..."); - err.span_label( - *external_span, - "...so that variable is valid at time of its \ - declaration", - ); - err.span_label( - *closure_span, - "borrowed data cannot outlive this closure", - ); - } - err.emit(); - return Some(ErrorReported); - } - } - } - } - None - } -} diff --git a/src/librustc/infer/error_reporting/nice_region_error/placeholder_error.rs b/src/librustc/infer/error_reporting/nice_region_error/placeholder_error.rs deleted file mode 100644 index 0b0bd61ce77..00000000000 --- a/src/librustc/infer/error_reporting/nice_region_error/placeholder_error.rs +++ /dev/null @@ -1,474 +0,0 @@ -use crate::infer::error_reporting::nice_region_error::NiceRegionError; -use crate::infer::lexical_region_resolve::RegionResolutionError; -use crate::infer::ValuePairs; -use crate::infer::{SubregionOrigin, TypeTrace}; -use crate::traits::{ObligationCause, ObligationCauseCode}; -use crate::ty::error::ExpectedFound; -use crate::ty::print::{FmtPrinter, Print, RegionHighlightMode}; -use crate::ty::subst::SubstsRef; -use crate::ty::{self, TyCtxt}; -use rustc_errors::DiagnosticBuilder; -use rustc_hir::def::Namespace; -use rustc_hir::def_id::DefId; - -use std::fmt::{self, Write}; - -impl NiceRegionError<'me, 'tcx> { - /// When given a `ConcreteFailure` for a function with arguments containing a named region and - /// an anonymous region, emit a descriptive diagnostic error. - pub(super) fn try_report_placeholder_conflict(&self) -> Option<DiagnosticBuilder<'me>> { - match &self.error { - /////////////////////////////////////////////////////////////////////////// - // NB. The ordering of cases in this match is very - // sensitive, because we are often matching against - // specific cases and then using an `_` to match all - // others. - - /////////////////////////////////////////////////////////////////////////// - // Check for errors from comparing trait failures -- first - // with two placeholders, then with one. - Some(RegionResolutionError::SubSupConflict( - vid, - _, - SubregionOrigin::Subtype(box TypeTrace { - cause, - values: ValuePairs::TraitRefs(ExpectedFound { expected, found }), - }), - sub_placeholder @ ty::RePlaceholder(_), - _, - sup_placeholder @ ty::RePlaceholder(_), - )) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait( - Some(self.tcx().mk_region(ty::ReVar(*vid))), - cause, - Some(sub_placeholder), - Some(sup_placeholder), - expected.def_id, - expected.substs, - found.substs, - )), - - Some(RegionResolutionError::SubSupConflict( - vid, - _, - SubregionOrigin::Subtype(box TypeTrace { - cause, - values: ValuePairs::TraitRefs(ExpectedFound { expected, found }), - }), - sub_placeholder @ ty::RePlaceholder(_), - _, - _, - )) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait( - Some(self.tcx().mk_region(ty::ReVar(*vid))), - cause, - Some(sub_placeholder), - None, - expected.def_id, - expected.substs, - found.substs, - )), - - Some(RegionResolutionError::SubSupConflict( - vid, - _, - SubregionOrigin::Subtype(box TypeTrace { - cause, - values: ValuePairs::TraitRefs(ExpectedFound { expected, found }), - }), - _, - _, - sup_placeholder @ ty::RePlaceholder(_), - )) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait( - Some(self.tcx().mk_region(ty::ReVar(*vid))), - cause, - None, - Some(*sup_placeholder), - expected.def_id, - expected.substs, - found.substs, - )), - - Some(RegionResolutionError::SubSupConflict( - vid, - _, - _, - _, - SubregionOrigin::Subtype(box TypeTrace { - cause, - values: ValuePairs::TraitRefs(ExpectedFound { expected, found }), - }), - sup_placeholder @ ty::RePlaceholder(_), - )) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait( - Some(self.tcx().mk_region(ty::ReVar(*vid))), - cause, - None, - Some(*sup_placeholder), - expected.def_id, - expected.substs, - found.substs, - )), - - Some(RegionResolutionError::UpperBoundUniverseConflict( - vid, - _, - _, - SubregionOrigin::Subtype(box TypeTrace { - cause, - values: ValuePairs::TraitRefs(ExpectedFound { expected, found }), - }), - sup_placeholder @ ty::RePlaceholder(_), - )) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait( - Some(self.tcx().mk_region(ty::ReVar(*vid))), - cause, - None, - Some(*sup_placeholder), - expected.def_id, - expected.substs, - found.substs, - )), - - Some(RegionResolutionError::ConcreteFailure( - SubregionOrigin::Subtype(box TypeTrace { - cause, - values: ValuePairs::TraitRefs(ExpectedFound { expected, found }), - }), - sub_region @ ty::RePlaceholder(_), - sup_region @ ty::RePlaceholder(_), - )) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait( - None, - cause, - Some(*sub_region), - Some(*sup_region), - expected.def_id, - expected.substs, - found.substs, - )), - - Some(RegionResolutionError::ConcreteFailure( - SubregionOrigin::Subtype(box TypeTrace { - cause, - values: ValuePairs::TraitRefs(ExpectedFound { expected, found }), - }), - sub_region @ ty::RePlaceholder(_), - sup_region, - )) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait( - Some(sup_region), - cause, - Some(*sub_region), - None, - expected.def_id, - expected.substs, - found.substs, - )), - - Some(RegionResolutionError::ConcreteFailure( - SubregionOrigin::Subtype(box TypeTrace { - cause, - values: ValuePairs::TraitRefs(ExpectedFound { expected, found }), - }), - sub_region, - sup_region @ ty::RePlaceholder(_), - )) if expected.def_id == found.def_id => Some(self.try_report_placeholders_trait( - Some(sub_region), - cause, - None, - Some(*sup_region), - expected.def_id, - expected.substs, - found.substs, - )), - - _ => None, - } - } - - // error[E0308]: implementation of `Foo` does not apply to enough lifetimes - // --> /home/nmatsakis/tmp/foo.rs:12:5 - // | - // 12 | all::<&'static u32>(); - // | ^^^^^^^^^^^^^^^^^^^ lifetime mismatch - // | - // = note: Due to a where-clause on the function `all`, - // = note: `T` must implement `...` for any two lifetimes `'1` and `'2`. - // = note: However, the type `T` only implements `...` for some specific lifetime `'2`. - fn try_report_placeholders_trait( - &self, - vid: Option<ty::Region<'tcx>>, - cause: &ObligationCause<'tcx>, - sub_placeholder: Option<ty::Region<'tcx>>, - sup_placeholder: Option<ty::Region<'tcx>>, - trait_def_id: DefId, - expected_substs: SubstsRef<'tcx>, - actual_substs: SubstsRef<'tcx>, - ) -> DiagnosticBuilder<'me> { - debug!( - "try_report_placeholders_trait(\ - vid={:?}, \ - sub_placeholder={:?}, \ - sup_placeholder={:?}, \ - trait_def_id={:?}, \ - expected_substs={:?}, \ - actual_substs={:?})", - vid, sub_placeholder, sup_placeholder, trait_def_id, expected_substs, actual_substs - ); - - let span = cause.span(self.tcx()); - let msg = format!( - "implementation of `{}` is not general enough", - self.tcx().def_path_str(trait_def_id), - ); - let mut err = self.tcx().sess.struct_span_err(span, &msg); - err.span_label( - self.tcx().def_span(trait_def_id), - format!("trait `{}` defined here", self.tcx().def_path_str(trait_def_id)), - ); - - let leading_ellipsis = if let ObligationCauseCode::ItemObligation(def_id) = cause.code { - err.span_label(span, "doesn't satisfy where-clause"); - err.span_label( - self.tcx().def_span(def_id), - &format!("due to a where-clause on `{}`...", self.tcx().def_path_str(def_id)), - ); - true - } else { - err.span_label(span, &msg); - false - }; - - let expected_trait_ref = self.infcx.resolve_vars_if_possible(&ty::TraitRef { - def_id: trait_def_id, - substs: expected_substs, - }); - let actual_trait_ref = self.infcx.resolve_vars_if_possible(&ty::TraitRef { - def_id: trait_def_id, - substs: actual_substs, - }); - - // Search the expected and actual trait references to see (a) - // whether the sub/sup placeholders appear in them (sometimes - // you have a trait ref like `T: Foo<fn(&u8)>`, where the - // placeholder was created as part of an inner type) and (b) - // whether the inference variable appears. In each case, - // assign a counter value in each case if so. - let mut counter = 0; - let mut has_sub = None; - let mut has_sup = None; - - let mut actual_has_vid = None; - let mut expected_has_vid = None; - - self.tcx().for_each_free_region(&expected_trait_ref, |r| { - if Some(r) == sub_placeholder && has_sub.is_none() { - has_sub = Some(counter); - counter += 1; - } else if Some(r) == sup_placeholder && has_sup.is_none() { - has_sup = Some(counter); - counter += 1; - } - - if Some(r) == vid && expected_has_vid.is_none() { - expected_has_vid = Some(counter); - counter += 1; - } - }); - - self.tcx().for_each_free_region(&actual_trait_ref, |r| { - if Some(r) == vid && actual_has_vid.is_none() { - actual_has_vid = Some(counter); - counter += 1; - } - }); - - let actual_self_ty_has_vid = - self.tcx().any_free_region_meets(&actual_trait_ref.self_ty(), |r| Some(r) == vid); - - let expected_self_ty_has_vid = - self.tcx().any_free_region_meets(&expected_trait_ref.self_ty(), |r| Some(r) == vid); - - let any_self_ty_has_vid = actual_self_ty_has_vid || expected_self_ty_has_vid; - - debug!("try_report_placeholders_trait: actual_has_vid={:?}", actual_has_vid); - debug!("try_report_placeholders_trait: expected_has_vid={:?}", expected_has_vid); - debug!("try_report_placeholders_trait: has_sub={:?}", has_sub); - debug!("try_report_placeholders_trait: has_sup={:?}", has_sup); - debug!( - "try_report_placeholders_trait: actual_self_ty_has_vid={:?}", - actual_self_ty_has_vid - ); - debug!( - "try_report_placeholders_trait: expected_self_ty_has_vid={:?}", - expected_self_ty_has_vid - ); - - self.explain_actual_impl_that_was_found( - &mut err, - sub_placeholder, - sup_placeholder, - has_sub, - has_sup, - expected_trait_ref, - actual_trait_ref, - vid, - expected_has_vid, - actual_has_vid, - any_self_ty_has_vid, - leading_ellipsis, - ); - - err - } - - /// Add notes with details about the expected and actual trait refs, with attention to cases - /// when placeholder regions are involved: either the trait or the self type containing - /// them needs to be mentioned the closest to the placeholders. - /// This makes the error messages read better, however at the cost of some complexity - /// due to the number of combinations we have to deal with. - fn explain_actual_impl_that_was_found( - &self, - err: &mut DiagnosticBuilder<'_>, - sub_placeholder: Option<ty::Region<'tcx>>, - sup_placeholder: Option<ty::Region<'tcx>>, - has_sub: Option<usize>, - has_sup: Option<usize>, - expected_trait_ref: ty::TraitRef<'tcx>, - actual_trait_ref: ty::TraitRef<'tcx>, - vid: Option<ty::Region<'tcx>>, - expected_has_vid: Option<usize>, - actual_has_vid: Option<usize>, - any_self_ty_has_vid: bool, - leading_ellipsis: bool, - ) { - // HACK(eddyb) maybe move this in a more central location. - #[derive(Copy, Clone)] - struct Highlighted<'tcx, T> { - tcx: TyCtxt<'tcx>, - highlight: RegionHighlightMode, - value: T, - } - - impl<'tcx, T> Highlighted<'tcx, T> { - fn map<U>(self, f: impl FnOnce(T) -> U) -> Highlighted<'tcx, U> { - Highlighted { tcx: self.tcx, highlight: self.highlight, value: f(self.value) } - } - } - - impl<'tcx, T> fmt::Display for Highlighted<'tcx, T> - where - T: for<'a, 'b, 'c> Print< - 'tcx, - FmtPrinter<'a, 'tcx, &'b mut fmt::Formatter<'c>>, - Error = fmt::Error, - >, - { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut printer = ty::print::FmtPrinter::new(self.tcx, f, Namespace::TypeNS); - printer.region_highlight_mode = self.highlight; - - self.value.print(printer)?; - Ok(()) - } - } - - // The weird thing here with the `maybe_highlighting_region` calls and the - // the match inside is meant to be like this: - // - // - The match checks whether the given things (placeholders, etc) appear - // in the types are about to print - // - Meanwhile, the `maybe_highlighting_region` calls set up - // highlights so that, if they do appear, we will replace - // them `'0` and whatever. (This replacement takes place - // inside the closure given to `maybe_highlighting_region`.) - // - // There is some duplication between the calls -- i.e., the - // `maybe_highlighting_region` checks if (e.g.) `has_sub` is - // None, an then we check again inside the closure, but this - // setup sort of minimized the number of calls and so form. - - let highlight_trait_ref = |trait_ref| Highlighted { - tcx: self.tcx(), - highlight: RegionHighlightMode::default(), - value: trait_ref, - }; - - let mut expected_trait_ref = highlight_trait_ref(expected_trait_ref); - expected_trait_ref.highlight.maybe_highlighting_region(sub_placeholder, has_sub); - expected_trait_ref.highlight.maybe_highlighting_region(sup_placeholder, has_sup); - err.note(&{ - let passive_voice = match (has_sub, has_sup) { - (Some(_), _) | (_, Some(_)) => any_self_ty_has_vid, - (None, None) => { - expected_trait_ref.highlight.maybe_highlighting_region(vid, expected_has_vid); - match expected_has_vid { - Some(_) => true, - None => any_self_ty_has_vid, - } - } - }; - - let mut note = if passive_voice { - format!( - "{}`{}` would have to be implemented for the type `{}`", - if leading_ellipsis { "..." } else { "" }, - expected_trait_ref.map(|tr| tr.print_only_trait_path()), - expected_trait_ref.map(|tr| tr.self_ty()), - ) - } else { - format!( - "{}`{}` must implement `{}`", - if leading_ellipsis { "..." } else { "" }, - expected_trait_ref.map(|tr| tr.self_ty()), - expected_trait_ref.map(|tr| tr.print_only_trait_path()), - ) - }; - - match (has_sub, has_sup) { - (Some(n1), Some(n2)) => { - let _ = write!( - note, - ", for any two lifetimes `'{}` and `'{}`...", - std::cmp::min(n1, n2), - std::cmp::max(n1, n2), - ); - } - (Some(n), _) | (_, Some(n)) => { - let _ = write!(note, ", for any lifetime `'{}`...", n,); - } - (None, None) => { - if let Some(n) = expected_has_vid { - let _ = write!(note, ", for some specific lifetime `'{}`...", n,); - } - } - } - - note - }); - - let mut actual_trait_ref = highlight_trait_ref(actual_trait_ref); - actual_trait_ref.highlight.maybe_highlighting_region(vid, actual_has_vid); - err.note(&{ - let passive_voice = match actual_has_vid { - Some(_) => any_self_ty_has_vid, - None => true, - }; - - let mut note = if passive_voice { - format!( - "...but `{}` is actually implemented for the type `{}`", - actual_trait_ref.map(|tr| tr.print_only_trait_path()), - actual_trait_ref.map(|tr| tr.self_ty()), - ) - } else { - format!( - "...but `{}` actually implements `{}`", - actual_trait_ref.map(|tr| tr.self_ty()), - actual_trait_ref.map(|tr| tr.print_only_trait_path()), - ) - }; - - if let Some(n) = actual_has_vid { - let _ = write!(note, ", for some specific lifetime `'{}`", n); - } - - note - }); - } -} diff --git a/src/librustc/infer/error_reporting/nice_region_error/static_impl_trait.rs b/src/librustc/infer/error_reporting/nice_region_error/static_impl_trait.rs deleted file mode 100644 index c6fc4cd3c15..00000000000 --- a/src/librustc/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ /dev/null @@ -1,74 +0,0 @@ -//! Error Reporting for static impl Traits. - -use crate::infer::error_reporting::msg_span_from_free_region; -use crate::infer::error_reporting::nice_region_error::NiceRegionError; -use crate::infer::lexical_region_resolve::RegionResolutionError; -use crate::ty::{BoundRegion, FreeRegion, RegionKind}; -use crate::util::common::ErrorReported; -use rustc_errors::Applicability; - -impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { - /// Print the error message for lifetime errors when the return type is a static impl Trait. - pub(super) fn try_report_static_impl_trait(&self) -> Option<ErrorReported> { - if let Some(ref error) = self.error { - if let RegionResolutionError::SubSupConflict( - _, - var_origin, - sub_origin, - sub_r, - sup_origin, - sup_r, - ) = error.clone() - { - let anon_reg_sup = self.tcx().is_suitable_region(sup_r)?; - let return_ty = self.tcx().return_type_impl_trait(anon_reg_sup.def_id); - if sub_r == &RegionKind::ReStatic && return_ty.is_some() { - let sp = var_origin.span(); - let return_sp = sub_origin.span(); - let mut err = - self.tcx().sess.struct_span_err(sp, "cannot infer an appropriate lifetime"); - err.span_label( - return_sp, - "this return type evaluates to the `'static` lifetime...", - ); - err.span_label(sup_origin.span(), "...but this borrow..."); - - let (lifetime, lt_sp_opt) = msg_span_from_free_region(self.tcx(), sup_r); - if let Some(lifetime_sp) = lt_sp_opt { - err.span_note(lifetime_sp, &format!("...can't outlive {}", lifetime)); - } - - let lifetime_name = match sup_r { - RegionKind::ReFree(FreeRegion { - bound_region: BoundRegion::BrNamed(_, ref name), - .. - }) => name.to_string(), - _ => "'_".to_owned(), - }; - let fn_return_span = return_ty.unwrap().1; - if let Ok(snippet) = - self.tcx().sess.source_map().span_to_snippet(fn_return_span) - { - // only apply this suggestion onto functions with - // explicit non-desugar'able return. - if fn_return_span.desugaring_kind().is_none() { - err.span_suggestion( - fn_return_span, - &format!( - "you can add a bound to the return type to make it last \ - less than `'static` and match {}", - lifetime, - ), - format!("{} + {}", snippet, lifetime_name), - Applicability::Unspecified, - ); - } - } - err.emit(); - return Some(ErrorReported); - } - } - } - None - } -} diff --git a/src/librustc/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/src/librustc/infer/error_reporting/nice_region_error/trait_impl_difference.rs deleted file mode 100644 index a33cb511133..00000000000 --- a/src/librustc/infer/error_reporting/nice_region_error/trait_impl_difference.rs +++ /dev/null @@ -1,61 +0,0 @@ -//! Error Reporting for `impl` items that do not match the obligations from their `trait`. - -use crate::infer::error_reporting::nice_region_error::NiceRegionError; -use crate::infer::lexical_region_resolve::RegionResolutionError; -use crate::infer::{Subtype, ValuePairs}; -use crate::traits::ObligationCauseCode::CompareImplMethodObligation; -use crate::ty::Ty; -use crate::util::common::ErrorReported; -use rustc_span::Span; - -impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { - /// Print the error message for lifetime errors when the `impl` doesn't conform to the `trait`. - pub(super) fn try_report_impl_not_conforming_to_trait(&self) -> Option<ErrorReported> { - if let Some(ref error) = self.error { - debug!("try_report_impl_not_conforming_to_trait {:?}", error); - if let RegionResolutionError::SubSupConflict( - _, - var_origin, - sub_origin, - _sub, - sup_origin, - _sup, - ) = error.clone() - { - match (&sup_origin, &sub_origin) { - (&Subtype(ref sup_trace), &Subtype(ref sub_trace)) => { - if let ( - ValuePairs::Types(sub_expected_found), - ValuePairs::Types(sup_expected_found), - CompareImplMethodObligation { trait_item_def_id, .. }, - ) = (&sub_trace.values, &sup_trace.values, &sub_trace.cause.code) - { - if sup_expected_found == sub_expected_found { - self.emit_err( - var_origin.span(), - sub_expected_found.expected, - sub_expected_found.found, - self.tcx().def_span(*trait_item_def_id), - ); - return Some(ErrorReported); - } - } - } - _ => {} - } - } - } - None - } - - fn emit_err(&self, sp: Span, expected: Ty<'tcx>, found: Ty<'tcx>, impl_sp: Span) { - let mut err = self - .tcx() - .sess - .struct_span_err(sp, "`impl` item signature doesn't match `trait` item signature"); - err.note(&format!("expected `{:?}`\n found `{:?}`", expected, found)); - err.span_label(sp, &format!("found {:?}", found)); - err.span_label(impl_sp, &format!("expected {:?}", expected)); - err.emit(); - } -} diff --git a/src/librustc/infer/error_reporting/nice_region_error/util.rs b/src/librustc/infer/error_reporting/nice_region_error/util.rs deleted file mode 100644 index 52ccb1454ee..00000000000 --- a/src/librustc/infer/error_reporting/nice_region_error/util.rs +++ /dev/null @@ -1,132 +0,0 @@ -//! Helper functions corresponding to lifetime errors due to -//! anonymous regions. - -use crate::infer::error_reporting::nice_region_error::NiceRegionError; -use crate::ty::{self, DefIdTree, Region, Ty}; -use rustc_hir as hir; -use rustc_hir::def_id::DefId; -use rustc_span::Span; - -// The struct contains the information about the anonymous region -// we are searching for. -#[derive(Debug)] -pub(super) struct AnonymousParamInfo<'tcx> { - // the parameter corresponding to the anonymous region - pub param: &'tcx hir::Param<'tcx>, - // the type corresponding to the anonymopus region parameter - pub param_ty: Ty<'tcx>, - // the ty::BoundRegion corresponding to the anonymous region - pub bound_region: ty::BoundRegion, - // param_ty_span contains span of parameter type - pub param_ty_span: Span, - // corresponds to id the argument is the first parameter - // in the declaration - pub is_first: bool, -} - -impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { - // This method walks the Type of the function body parameters using - // `fold_regions()` function and returns the - // &hir::Param of the function parameter corresponding to the anonymous - // region and the Ty corresponding to the named region. - // Currently only the case where the function declaration consists of - // one named region and one anonymous region is handled. - // Consider the example `fn foo<'a>(x: &'a i32, y: &i32) -> &'a i32` - // Here, we would return the hir::Param for y, we return the type &'a - // i32, which is the type of y but with the anonymous region replaced - // with 'a, the corresponding bound region and is_first which is true if - // the hir::Param is the first parameter in the function declaration. - pub(super) fn find_param_with_region( - &self, - anon_region: Region<'tcx>, - replace_region: Region<'tcx>, - ) -> Option<AnonymousParamInfo<'_>> { - let (id, bound_region) = match *anon_region { - ty::ReFree(ref free_region) => (free_region.scope, free_region.bound_region), - ty::ReEarlyBound(ebr) => ( - self.tcx().parent(ebr.def_id).unwrap(), - ty::BoundRegion::BrNamed(ebr.def_id, ebr.name), - ), - _ => return None, // not a free region - }; - - let hir = &self.tcx().hir(); - if let Some(hir_id) = hir.as_local_hir_id(id) { - if let Some(body_id) = hir.maybe_body_owned_by(hir_id) { - let body = hir.body(body_id); - let owner_id = hir.body_owner(body_id); - let fn_decl = hir.fn_decl_by_hir_id(owner_id).unwrap(); - if let Some(tables) = self.tables { - body.params - .iter() - .enumerate() - .filter_map(|(index, param)| { - // May return None; sometimes the tables are not yet populated. - let ty_hir_id = fn_decl.inputs[index].hir_id; - let param_ty_span = hir.span(ty_hir_id); - let ty = tables.node_type_opt(param.hir_id)?; - let mut found_anon_region = false; - let new_param_ty = self.tcx().fold_regions(&ty, &mut false, |r, _| { - if *r == *anon_region { - found_anon_region = true; - replace_region - } else { - r - } - }); - if found_anon_region { - let is_first = index == 0; - Some(AnonymousParamInfo { - param: param, - param_ty: new_param_ty, - param_ty_span: param_ty_span, - bound_region: bound_region, - is_first: is_first, - }) - } else { - None - } - }) - .next() - } else { - None - } - } else { - None - } - } else { - None - } - } - - // Here, we check for the case where the anonymous region - // is in the return type. - // FIXME(#42703) - Need to handle certain cases here. - pub(super) fn is_return_type_anon( - &self, - scope_def_id: DefId, - br: ty::BoundRegion, - decl: &hir::FnDecl<'_>, - ) -> Option<Span> { - let ret_ty = self.tcx().type_of(scope_def_id); - if let ty::FnDef(_, _) = ret_ty.kind { - let sig = ret_ty.fn_sig(self.tcx()); - let late_bound_regions = - self.tcx().collect_referenced_late_bound_regions(&sig.output()); - if late_bound_regions.iter().any(|r| *r == br) { - return Some(decl.output.span()); - } - } - None - } - - // Here we check for the case where anonymous region - // corresponds to self and if yes, we display E0312. - // FIXME(#42700) - Need to format self properly to - // enable E0621 for it. - pub(super) fn is_self_anon(&self, is_first: bool, scope_def_id: DefId) -> bool { - is_first - && self.tcx().opt_associated_item(scope_def_id).map(|i| i.method_has_self_argument) - == Some(true) - } -} diff --git a/src/librustc/infer/error_reporting/note.rs b/src/librustc/infer/error_reporting/note.rs deleted file mode 100644 index 11dda71b8cb..00000000000 --- a/src/librustc/infer/error_reporting/note.rs +++ /dev/null @@ -1,702 +0,0 @@ -use crate::infer::error_reporting::note_and_explain_region; -use crate::infer::{self, InferCtxt, SubregionOrigin}; -use crate::middle::region; -use crate::ty::error::TypeError; -use crate::ty::{self, Region}; -use rustc_errors::{struct_span_err, DiagnosticBuilder}; - -impl<'a, 'tcx> InferCtxt<'a, 'tcx> { - pub(super) fn note_region_origin( - &self, - err: &mut DiagnosticBuilder<'_>, - origin: &SubregionOrigin<'tcx>, - ) { - match *origin { - infer::Subtype(ref trace) => { - if let Some((expected, found)) = self.values_str(&trace.values) { - err.span_note( - trace.cause.span, - &format!("...so that the {}", trace.cause.as_requirement_str()), - ); - - err.note_expected_found(&"", expected, &"", found); - } else { - // FIXME: this really should be handled at some earlier stage. Our - // handling of region checking when type errors are present is - // *terrible*. - - err.span_note( - trace.cause.span, - &format!("...so that {}", trace.cause.as_requirement_str()), - ); - } - } - infer::Reborrow(span) => { - err.span_note(span, "...so that reference does not outlive borrowed content"); - } - infer::ReborrowUpvar(span, ref upvar_id) => { - let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id); - err.span_note(span, &format!("...so that closure can access `{}`", var_name)); - } - infer::InfStackClosure(span) => { - err.span_note(span, "...so that closure does not outlive its stack frame"); - } - infer::InvokeClosure(span) => { - err.span_note(span, "...so that closure is not invoked outside its lifetime"); - } - infer::DerefPointer(span) => { - err.span_note(span, "...so that pointer is not dereferenced outside its lifetime"); - } - infer::ClosureCapture(span, id) => { - err.span_note( - span, - &format!( - "...so that captured variable `{}` does not outlive the \ - enclosing closure", - self.tcx.hir().name(id) - ), - ); - } - infer::IndexSlice(span) => { - err.span_note(span, "...so that slice is not indexed outside the lifetime"); - } - infer::RelateObjectBound(span) => { - err.span_note(span, "...so that it can be closed over into an object"); - } - infer::CallRcvr(span) => { - err.span_note(span, "...so that method receiver is valid for the method call"); - } - infer::CallArg(span) => { - err.span_note(span, "...so that argument is valid for the call"); - } - infer::CallReturn(span) => { - err.span_note(span, "...so that return value is valid for the call"); - } - infer::Operand(span) => { - err.span_note(span, "...so that operand is valid for operation"); - } - infer::AddrOf(span) => { - err.span_note(span, "...so that reference is valid at the time of borrow"); - } - infer::AutoBorrow(span) => { - err.span_note(span, "...so that auto-reference is valid at the time of borrow"); - } - infer::ExprTypeIsNotInScope(t, span) => { - err.span_note( - span, - &format!( - "...so type `{}` of expression is valid during the \ - expression", - self.ty_to_string(t) - ), - ); - } - infer::BindingTypeIsNotValidAtDecl(span) => { - err.span_note(span, "...so that variable is valid at time of its declaration"); - } - infer::ParameterInScope(_, span) => { - err.span_note(span, "...so that a type/lifetime parameter is in scope here"); - } - infer::DataBorrowed(ty, span) => { - err.span_note( - span, - &format!( - "...so that the type `{}` is not borrowed for too long", - self.ty_to_string(ty) - ), - ); - } - infer::ReferenceOutlivesReferent(ty, span) => { - err.span_note( - span, - &format!( - "...so that the reference type `{}` does not outlive the \ - data it points at", - self.ty_to_string(ty) - ), - ); - } - infer::RelateParamBound(span, t) => { - err.span_note( - span, - &format!( - "...so that the type `{}` will meet its required \ - lifetime bounds", - self.ty_to_string(t) - ), - ); - } - infer::RelateDefaultParamBound(span, t) => { - err.span_note( - span, - &format!( - "...so that type parameter instantiated with `{}`, will \ - meet its declared lifetime bounds", - self.ty_to_string(t) - ), - ); - } - infer::RelateRegionParamBound(span) => { - err.span_note( - span, - "...so that the declared lifetime parameter bounds are satisfied", - ); - } - infer::SafeDestructor(span) => { - err.span_note(span, "...so that references are valid when the destructor runs"); - } - infer::CompareImplMethodObligation { span, .. } => { - err.span_note( - span, - "...so that the definition in impl matches the definition from the \ - trait", - ); - } - } - } - - pub(super) fn report_concrete_failure( - &self, - region_scope_tree: ®ion::ScopeTree, - origin: SubregionOrigin<'tcx>, - sub: Region<'tcx>, - sup: Region<'tcx>, - ) -> DiagnosticBuilder<'tcx> { - match origin { - infer::Subtype(box trace) => { - let terr = TypeError::RegionsDoesNotOutlive(sup, sub); - let mut err = self.report_and_explain_type_error(trace, &terr); - note_and_explain_region(self.tcx, region_scope_tree, &mut err, "", sup, "..."); - note_and_explain_region( - self.tcx, - region_scope_tree, - &mut err, - "...does not necessarily outlive ", - sub, - "", - ); - err - } - infer::Reborrow(span) => { - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0312, - "lifetime of reference outlives lifetime of \ - borrowed content..." - ); - note_and_explain_region( - self.tcx, - region_scope_tree, - &mut err, - "...the reference is valid for ", - sub, - "...", - ); - note_and_explain_region( - self.tcx, - region_scope_tree, - &mut err, - "...but the borrowed content is only valid for ", - sup, - "", - ); - err - } - infer::ReborrowUpvar(span, ref upvar_id) => { - let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id); - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0313, - "lifetime of borrowed pointer outlives lifetime \ - of captured variable `{}`...", - var_name - ); - note_and_explain_region( - self.tcx, - region_scope_tree, - &mut err, - "...the borrowed pointer is valid for ", - sub, - "...", - ); - note_and_explain_region( - self.tcx, - region_scope_tree, - &mut err, - &format!("...but `{}` is only valid for ", var_name), - sup, - "", - ); - err - } - infer::InfStackClosure(span) => { - let mut err = - struct_span_err!(self.tcx.sess, span, E0314, "closure outlives stack frame"); - note_and_explain_region( - self.tcx, - region_scope_tree, - &mut err, - "...the closure must be valid for ", - sub, - "...", - ); - note_and_explain_region( - self.tcx, - region_scope_tree, - &mut err, - "...but the closure's stack frame is only valid \ - for ", - sup, - "", - ); - err - } - infer::InvokeClosure(span) => { - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0315, - "cannot invoke closure outside of its lifetime" - ); - note_and_explain_region( - self.tcx, - region_scope_tree, - &mut err, - "the closure is only valid for ", - sup, - "", - ); - err - } - infer::DerefPointer(span) => { - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0473, - "dereference of reference outside its lifetime" - ); - note_and_explain_region( - self.tcx, - region_scope_tree, - &mut err, - "the reference is only valid for ", - sup, - "", - ); - err - } - infer::ClosureCapture(span, id) => { - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0474, - "captured variable `{}` does not outlive the \ - enclosing closure", - self.tcx.hir().name(id) - ); - note_and_explain_region( - self.tcx, - region_scope_tree, - &mut err, - "captured variable is valid for ", - sup, - "", - ); - note_and_explain_region( - self.tcx, - region_scope_tree, - &mut err, - "closure is valid for ", - sub, - "", - ); - err - } - infer::IndexSlice(span) => { - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0475, - "index of slice outside its lifetime" - ); - note_and_explain_region( - self.tcx, - region_scope_tree, - &mut err, - "the slice is only valid for ", - sup, - "", - ); - err - } - infer::RelateObjectBound(span) => { - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0476, - "lifetime of the source pointer does not outlive \ - lifetime bound of the object type" - ); - note_and_explain_region( - self.tcx, - region_scope_tree, - &mut err, - "object type is valid for ", - sub, - "", - ); - note_and_explain_region( - self.tcx, - region_scope_tree, - &mut err, - "source pointer is only valid for ", - sup, - "", - ); - err - } - infer::RelateParamBound(span, ty) => { - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0477, - "the type `{}` does not fulfill the required \ - lifetime", - self.ty_to_string(ty) - ); - match *sub { - ty::ReStatic => note_and_explain_region( - self.tcx, - region_scope_tree, - &mut err, - "type must satisfy ", - sub, - "", - ), - _ => note_and_explain_region( - self.tcx, - region_scope_tree, - &mut err, - "type must outlive ", - sub, - "", - ), - } - err - } - infer::RelateRegionParamBound(span) => { - let mut err = - struct_span_err!(self.tcx.sess, span, E0478, "lifetime bound not satisfied"); - note_and_explain_region( - self.tcx, - region_scope_tree, - &mut err, - "lifetime parameter instantiated with ", - sup, - "", - ); - note_and_explain_region( - self.tcx, - region_scope_tree, - &mut err, - "but lifetime parameter must outlive ", - sub, - "", - ); - err - } - infer::RelateDefaultParamBound(span, ty) => { - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0479, - "the type `{}` (provided as the value of a type \ - parameter) is not valid at this point", - self.ty_to_string(ty) - ); - note_and_explain_region( - self.tcx, - region_scope_tree, - &mut err, - "type must outlive ", - sub, - "", - ); - err - } - infer::CallRcvr(span) => { - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0480, - "lifetime of method receiver does not outlive the \ - method call" - ); - note_and_explain_region( - self.tcx, - region_scope_tree, - &mut err, - "the receiver is only valid for ", - sup, - "", - ); - err - } - infer::CallArg(span) => { - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0481, - "lifetime of function argument does not outlive \ - the function call" - ); - note_and_explain_region( - self.tcx, - region_scope_tree, - &mut err, - "the function argument is only valid for ", - sup, - "", - ); - err - } - infer::CallReturn(span) => { - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0482, - "lifetime of return value does not outlive the \ - function call" - ); - note_and_explain_region( - self.tcx, - region_scope_tree, - &mut err, - "the return value is only valid for ", - sup, - "", - ); - err - } - infer::Operand(span) => { - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0483, - "lifetime of operand does not outlive the \ - operation" - ); - note_and_explain_region( - self.tcx, - region_scope_tree, - &mut err, - "the operand is only valid for ", - sup, - "", - ); - err - } - infer::AddrOf(span) => { - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0484, - "reference is not valid at the time of borrow" - ); - note_and_explain_region( - self.tcx, - region_scope_tree, - &mut err, - "the borrow is only valid for ", - sup, - "", - ); - err - } - infer::AutoBorrow(span) => { - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0485, - "automatically reference is not valid at the time \ - of borrow" - ); - note_and_explain_region( - self.tcx, - region_scope_tree, - &mut err, - "the automatic borrow is only valid for ", - sup, - "", - ); - err - } - infer::ExprTypeIsNotInScope(t, span) => { - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0486, - "type of expression contains references that are \ - not valid during the expression: `{}`", - self.ty_to_string(t) - ); - note_and_explain_region( - self.tcx, - region_scope_tree, - &mut err, - "type is only valid for ", - sup, - "", - ); - err - } - infer::SafeDestructor(span) => { - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0487, - "unsafe use of destructor: destructor might be \ - called while references are dead" - ); - // FIXME (22171): terms "super/subregion" are suboptimal - note_and_explain_region( - self.tcx, - region_scope_tree, - &mut err, - "superregion: ", - sup, - "", - ); - note_and_explain_region( - self.tcx, - region_scope_tree, - &mut err, - "subregion: ", - sub, - "", - ); - err - } - infer::BindingTypeIsNotValidAtDecl(span) => { - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0488, - "lifetime of variable does not enclose its \ - declaration" - ); - note_and_explain_region( - self.tcx, - region_scope_tree, - &mut err, - "the variable is only valid for ", - sup, - "", - ); - err - } - infer::ParameterInScope(_, span) => { - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0489, - "type/lifetime parameter not in scope here" - ); - note_and_explain_region( - self.tcx, - region_scope_tree, - &mut err, - "the parameter is only valid for ", - sub, - "", - ); - err - } - infer::DataBorrowed(ty, span) => { - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0490, - "a value of type `{}` is borrowed for too long", - self.ty_to_string(ty) - ); - note_and_explain_region( - self.tcx, - region_scope_tree, - &mut err, - "the type is valid for ", - sub, - "", - ); - note_and_explain_region( - self.tcx, - region_scope_tree, - &mut err, - "but the borrow lasts for ", - sup, - "", - ); - err - } - infer::ReferenceOutlivesReferent(ty, span) => { - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0491, - "in type `{}`, reference has a longer lifetime \ - than the data it references", - self.ty_to_string(ty) - ); - note_and_explain_region( - self.tcx, - region_scope_tree, - &mut err, - "the pointer is valid for ", - sub, - "", - ); - note_and_explain_region( - self.tcx, - region_scope_tree, - &mut err, - "but the referenced data is only valid for ", - sup, - "", - ); - err - } - infer::CompareImplMethodObligation { - span, - item_name, - impl_item_def_id, - trait_item_def_id, - } => self.report_extra_impl_obligation( - span, - item_name, - impl_item_def_id, - trait_item_def_id, - &format!("`{}: {}`", sup, sub), - ), - } - } - - pub(super) fn report_placeholder_failure( - &self, - region_scope_tree: ®ion::ScopeTree, - placeholder_origin: SubregionOrigin<'tcx>, - sub: Region<'tcx>, - sup: Region<'tcx>, - ) -> DiagnosticBuilder<'tcx> { - // I can't think how to do better than this right now. -nikomatsakis - match placeholder_origin { - infer::Subtype(box trace) => { - let terr = TypeError::RegionsPlaceholderMismatch; - self.report_and_explain_type_error(trace, &terr) - } - - _ => self.report_concrete_failure(region_scope_tree, placeholder_origin, sub, sup), - } - } -} diff --git a/src/librustc/infer/freshen.rs b/src/librustc/infer/freshen.rs deleted file mode 100644 index 0190989267b..00000000000 --- a/src/librustc/infer/freshen.rs +++ /dev/null @@ -1,266 +0,0 @@ -//! Freshening is the process of replacing unknown variables with fresh types. The idea is that -//! the type, after freshening, contains no inference variables but instead contains either a -//! value for each variable or fresh "arbitrary" types wherever a variable would have been. -//! -//! Freshening is used primarily to get a good type for inserting into a cache. The result -//! summarizes what the type inferencer knows "so far". The primary place it is used right now is -//! in the trait matching algorithm, which needs to be able to cache whether an `impl` self type -//! matches some other type X -- *without* affecting `X`. That means if that if the type `X` is in -//! fact an unbound type variable, we want the match to be regarded as ambiguous, because depending -//! on what type that type variable is ultimately assigned, the match may or may not succeed. -//! -//! To handle closures, freshened types also have to contain the signature and kind of any -//! closure in the local inference context, as otherwise the cache key might be invalidated. -//! The way this is done is somewhat hacky - the closure signature is appended to the substs, -//! as well as the closure kind "encoded" as a type. Also, special handling is needed when -//! the closure signature contains a reference to the original closure. -//! -//! Note that you should be careful not to allow the output of freshening to leak to the user in -//! error messages or in any other form. Freshening is only really useful as an internal detail. -//! -//! Because of the manipulation required to handle closures, doing arbitrary operations on -//! freshened types is not recommended. However, in addition to doing equality/hash -//! comparisons (for caching), it is possible to do a `ty::_match` operation between -//! 2 freshened types - this works even with the closure encoding. -//! -//! __An important detail concerning regions.__ The freshener also replaces *all* free regions with -//! 'erased. The reason behind this is that, in general, we do not take region relationships into -//! account when making type-overloaded decisions. This is important because of the design of the -//! region inferencer, which is not based on unification but rather on accumulating and then -//! solving a set of constraints. In contrast, the type inferencer assigns a value to each type -//! variable only once, and it does so as soon as it can, so it is reasonable to ask what the type -//! inferencer knows "so far". - -use crate::ty::fold::TypeFolder; -use crate::ty::{self, Ty, TyCtxt, TypeFoldable}; - -use rustc_data_structures::fx::FxHashMap; - -use std::collections::hash_map::Entry; - -use super::unify_key::ToType; -use super::InferCtxt; - -pub struct TypeFreshener<'a, 'tcx> { - infcx: &'a InferCtxt<'a, 'tcx>, - ty_freshen_count: u32, - const_freshen_count: u32, - ty_freshen_map: FxHashMap<ty::InferTy, Ty<'tcx>>, - const_freshen_map: FxHashMap<ty::InferConst<'tcx>, &'tcx ty::Const<'tcx>>, -} - -impl<'a, 'tcx> TypeFreshener<'a, 'tcx> { - pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> TypeFreshener<'a, 'tcx> { - TypeFreshener { - infcx, - ty_freshen_count: 0, - const_freshen_count: 0, - ty_freshen_map: Default::default(), - const_freshen_map: Default::default(), - } - } - - fn freshen_ty<F>( - &mut self, - opt_ty: Option<Ty<'tcx>>, - key: ty::InferTy, - freshener: F, - ) -> Ty<'tcx> - where - F: FnOnce(u32) -> ty::InferTy, - { - if let Some(ty) = opt_ty { - return ty.fold_with(self); - } - - match self.ty_freshen_map.entry(key) { - Entry::Occupied(entry) => *entry.get(), - Entry::Vacant(entry) => { - let index = self.ty_freshen_count; - self.ty_freshen_count += 1; - let t = self.infcx.tcx.mk_ty_infer(freshener(index)); - entry.insert(t); - t - } - } - } - - fn freshen_const<F>( - &mut self, - opt_ct: Option<&'tcx ty::Const<'tcx>>, - key: ty::InferConst<'tcx>, - freshener: F, - ty: Ty<'tcx>, - ) -> &'tcx ty::Const<'tcx> - where - F: FnOnce(u32) -> ty::InferConst<'tcx>, - { - if let Some(ct) = opt_ct { - return ct.fold_with(self); - } - - match self.const_freshen_map.entry(key) { - Entry::Occupied(entry) => *entry.get(), - Entry::Vacant(entry) => { - let index = self.const_freshen_count; - self.const_freshen_count += 1; - let ct = self.infcx.tcx.mk_const_infer(freshener(index), ty); - entry.insert(ct); - ct - } - } - } -} - -impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> { - fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { - self.infcx.tcx - } - - fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { - match *r { - ty::ReLateBound(..) => { - // leave bound regions alone - r - } - - ty::ReStatic - | ty::ReEarlyBound(..) - | ty::ReFree(_) - | ty::ReScope(_) - | ty::ReVar(_) - | ty::RePlaceholder(..) - | ty::ReEmpty(_) - | ty::ReErased => { - // replace all free regions with 'erased - self.tcx().lifetimes.re_erased - } - - ty::ReClosureBound(..) => { - bug!("encountered unexpected region: {:?}", r,); - } - } - } - - fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - if !t.needs_infer() - && !t.has_erasable_regions() - && !(t.has_closure_types() && self.infcx.in_progress_tables.is_some()) - { - return t; - } - - let tcx = self.infcx.tcx; - - match t.kind { - ty::Infer(ty::TyVar(v)) => { - let opt_ty = self.infcx.inner.borrow_mut().type_variables.probe(v).known(); - self.freshen_ty(opt_ty, ty::TyVar(v), ty::FreshTy) - } - - ty::Infer(ty::IntVar(v)) => self.freshen_ty( - self.infcx - .inner - .borrow_mut() - .int_unification_table - .probe_value(v) - .map(|v| v.to_type(tcx)), - ty::IntVar(v), - ty::FreshIntTy, - ), - - ty::Infer(ty::FloatVar(v)) => self.freshen_ty( - self.infcx - .inner - .borrow_mut() - .float_unification_table - .probe_value(v) - .map(|v| v.to_type(tcx)), - ty::FloatVar(v), - ty::FreshFloatTy, - ), - - ty::Infer(ty::FreshTy(ct)) - | ty::Infer(ty::FreshIntTy(ct)) - | ty::Infer(ty::FreshFloatTy(ct)) => { - if ct >= self.ty_freshen_count { - bug!( - "Encountered a freshend type with id {} \ - but our counter is only at {}", - ct, - self.ty_freshen_count - ); - } - t - } - - ty::Generator(..) - | ty::Bool - | ty::Char - | ty::Int(..) - | ty::Uint(..) - | ty::Float(..) - | ty::Adt(..) - | ty::Str - | ty::Error - | ty::Array(..) - | ty::Slice(..) - | ty::RawPtr(..) - | ty::Ref(..) - | ty::FnDef(..) - | ty::FnPtr(_) - | ty::Dynamic(..) - | ty::Never - | ty::Tuple(..) - | ty::Projection(..) - | ty::UnnormalizedProjection(..) - | ty::Foreign(..) - | ty::Param(..) - | ty::Closure(..) - | ty::GeneratorWitness(..) - | ty::Opaque(..) => t.super_fold_with(self), - - ty::Placeholder(..) | ty::Bound(..) => bug!("unexpected type {:?}", t), - } - } - - fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { - match ct.val { - ty::ConstKind::Infer(ty::InferConst::Var(v)) => { - let opt_ct = self - .infcx - .inner - .borrow_mut() - .const_unification_table - .probe_value(v) - .val - .known(); - return self.freshen_const( - opt_ct, - ty::InferConst::Var(v), - ty::InferConst::Fresh, - ct.ty, - ); - } - ty::ConstKind::Infer(ty::InferConst::Fresh(i)) => { - if i >= self.const_freshen_count { - bug!( - "Encountered a freshend const with id {} \ - but our counter is only at {}", - i, - self.const_freshen_count, - ); - } - return ct; - } - - ty::ConstKind::Bound(..) | ty::ConstKind::Placeholder(_) => { - bug!("unexpected const {:?}", ct) - } - - ty::ConstKind::Param(_) | ty::ConstKind::Value(_) | ty::ConstKind::Unevaluated(..) => {} - } - - ct.super_fold_with(self) - } -} diff --git a/src/librustc/infer/fudge.rs b/src/librustc/infer/fudge.rs deleted file mode 100644 index d0b7bb32b98..00000000000 --- a/src/librustc/infer/fudge.rs +++ /dev/null @@ -1,213 +0,0 @@ -use crate::ty::fold::{TypeFoldable, TypeFolder}; -use crate::ty::{self, ConstVid, FloatVid, IntVid, RegionVid, Ty, TyCtxt, TyVid}; - -use super::type_variable::TypeVariableOrigin; -use super::InferCtxt; -use super::{ConstVariableOrigin, RegionVariableOrigin}; - -use rustc_data_structures::unify as ut; -use ut::UnifyKey; - -use std::ops::Range; - -fn const_vars_since_snapshot<'tcx>( - table: &mut ut::UnificationTable<ut::InPlace<ConstVid<'tcx>>>, - snapshot: &ut::Snapshot<ut::InPlace<ConstVid<'tcx>>>, -) -> (Range<ConstVid<'tcx>>, Vec<ConstVariableOrigin>) { - let range = table.vars_since_snapshot(snapshot); - ( - range.start..range.end, - (range.start.index..range.end.index) - .map(|index| table.probe_value(ConstVid::from_index(index)).origin) - .collect(), - ) -} - -impl<'a, 'tcx> InferCtxt<'a, 'tcx> { - /// This rather funky routine is used while processing expected - /// types. What happens here is that we want to propagate a - /// coercion through the return type of a fn to its - /// argument. Consider the type of `Option::Some`, which is - /// basically `for<T> fn(T) -> Option<T>`. So if we have an - /// expression `Some(&[1, 2, 3])`, and that has the expected type - /// `Option<&[u32]>`, we would like to type check `&[1, 2, 3]` - /// with the expectation of `&[u32]`. This will cause us to coerce - /// from `&[u32; 3]` to `&[u32]` and make the users life more - /// pleasant. - /// - /// The way we do this is using `fudge_inference_if_ok`. What the - /// routine actually does is to start a snapshot and execute the - /// closure `f`. In our example above, what this closure will do - /// is to unify the expectation (`Option<&[u32]>`) with the actual - /// return type (`Option<?T>`, where `?T` represents the variable - /// instantiated for `T`). This will cause `?T` to be unified - /// with `&?a [u32]`, where `?a` is a fresh lifetime variable. The - /// input type (`?T`) is then returned by `f()`. - /// - /// At this point, `fudge_inference_if_ok` will normalize all type - /// variables, converting `?T` to `&?a [u32]` and end the - /// snapshot. The problem is that we can't just return this type - /// out, because it references the region variable `?a`, and that - /// region variable was popped when we popped the snapshot. - /// - /// So what we do is to keep a list (`region_vars`, in the code below) - /// of region variables created during the snapshot (here, `?a`). We - /// fold the return value and replace any such regions with a *new* - /// region variable (e.g., `?b`) and return the result (`&?b [u32]`). - /// This can then be used as the expectation for the fn argument. - /// - /// The important point here is that, for soundness purposes, the - /// regions in question are not particularly important. We will - /// use the expected types to guide coercions, but we will still - /// type-check the resulting types from those coercions against - /// the actual types (`?T`, `Option<?T>`) -- and remember that - /// after the snapshot is popped, the variable `?T` is no longer - /// unified. - pub fn fudge_inference_if_ok<T, E, F>(&self, f: F) -> Result<T, E> - where - F: FnOnce() -> Result<T, E>, - T: TypeFoldable<'tcx>, - { - debug!("fudge_inference_if_ok()"); - - let (mut fudger, value) = self.probe(|snapshot| { - match f() { - Ok(value) => { - let value = self.resolve_vars_if_possible(&value); - - // At this point, `value` could in principle refer - // to inference variables that have been created during - // the snapshot. Once we exit `probe()`, those are - // going to be popped, so we will have to - // eliminate any references to them. - - let mut inner = self.inner.borrow_mut(); - let type_vars = - inner.type_variables.vars_since_snapshot(&snapshot.type_snapshot); - let int_vars = - inner.int_unification_table.vars_since_snapshot(&snapshot.int_snapshot); - let float_vars = - inner.float_unification_table.vars_since_snapshot(&snapshot.float_snapshot); - let region_vars = inner - .unwrap_region_constraints() - .vars_since_snapshot(&snapshot.region_constraints_snapshot); - let const_vars = const_vars_since_snapshot( - &mut inner.const_unification_table, - &snapshot.const_snapshot, - ); - - let fudger = InferenceFudger { - infcx: self, - type_vars, - int_vars, - float_vars, - region_vars, - const_vars, - }; - - Ok((fudger, value)) - } - Err(e) => Err(e), - } - })?; - - // At this point, we need to replace any of the now-popped - // type/region variables that appear in `value` with a fresh - // variable of the appropriate kind. We can't do this during - // the probe because they would just get popped then too. =) - - // Micro-optimization: if no variables have been created, then - // `value` can't refer to any of them. =) So we can just return it. - if fudger.type_vars.0.is_empty() - && fudger.int_vars.is_empty() - && fudger.float_vars.is_empty() - && fudger.region_vars.0.is_empty() - && fudger.const_vars.0.is_empty() - { - Ok(value) - } else { - Ok(value.fold_with(&mut fudger)) - } - } -} - -pub struct InferenceFudger<'a, 'tcx> { - infcx: &'a InferCtxt<'a, 'tcx>, - type_vars: (Range<TyVid>, Vec<TypeVariableOrigin>), - int_vars: Range<IntVid>, - float_vars: Range<FloatVid>, - region_vars: (Range<RegionVid>, Vec<RegionVariableOrigin>), - const_vars: (Range<ConstVid<'tcx>>, Vec<ConstVariableOrigin>), -} - -impl<'a, 'tcx> TypeFolder<'tcx> for InferenceFudger<'a, 'tcx> { - fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { - self.infcx.tcx - } - - fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - match ty.kind { - ty::Infer(ty::InferTy::TyVar(vid)) => { - if self.type_vars.0.contains(&vid) { - // This variable was created during the fudging. - // Recreate it with a fresh variable here. - let idx = (vid.index - self.type_vars.0.start.index) as usize; - let origin = self.type_vars.1[idx]; - self.infcx.next_ty_var(origin) - } else { - // This variable was created before the - // "fudging". Since we refresh all type - // variables to their binding anyhow, we know - // that it is unbound, so we can just return - // it. - debug_assert!( - self.infcx.inner.borrow_mut().type_variables.probe(vid).is_unknown() - ); - ty - } - } - ty::Infer(ty::InferTy::IntVar(vid)) => { - if self.int_vars.contains(&vid) { - self.infcx.next_int_var() - } else { - ty - } - } - ty::Infer(ty::InferTy::FloatVar(vid)) => { - if self.float_vars.contains(&vid) { - self.infcx.next_float_var() - } else { - ty - } - } - _ => ty.super_fold_with(self), - } - } - - fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { - if let ty::ReVar(vid) = *r { - if self.region_vars.0.contains(&vid) { - let idx = vid.index() - self.region_vars.0.start.index(); - let origin = self.region_vars.1[idx]; - return self.infcx.next_region_var(origin); - } - } - r - } - - fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { - if let ty::Const { val: ty::ConstKind::Infer(ty::InferConst::Var(vid)), ty } = ct { - if self.const_vars.0.contains(&vid) { - // This variable was created during the fudging. - // Recreate it with a fresh variable here. - let idx = (vid.index - self.const_vars.0.start.index) as usize; - let origin = self.const_vars.1[idx]; - self.infcx.next_const_var(ty, origin) - } else { - ct - } - } else { - ct.super_fold_with(self) - } - } -} diff --git a/src/librustc/infer/glb.rs b/src/librustc/infer/glb.rs deleted file mode 100644 index 6ef92132bc7..00000000000 --- a/src/librustc/infer/glb.rs +++ /dev/null @@ -1,118 +0,0 @@ -use super::combine::CombineFields; -use super::lattice::{self, LatticeDir}; -use super::InferCtxt; -use super::Subtype; - -use crate::traits::ObligationCause; -use crate::ty::relate::{Relate, RelateResult, TypeRelation}; -use crate::ty::{self, Ty, TyCtxt}; - -/// "Greatest lower bound" (common subtype) -pub struct Glb<'combine, 'infcx, 'tcx> { - fields: &'combine mut CombineFields<'infcx, 'tcx>, - a_is_expected: bool, -} - -impl<'combine, 'infcx, 'tcx> Glb<'combine, 'infcx, 'tcx> { - pub fn new( - fields: &'combine mut CombineFields<'infcx, 'tcx>, - a_is_expected: bool, - ) -> Glb<'combine, 'infcx, 'tcx> { - Glb { fields: fields, a_is_expected: a_is_expected } - } -} - -impl TypeRelation<'tcx> for Glb<'combine, 'infcx, 'tcx> { - fn tag(&self) -> &'static str { - "Glb" - } - - fn tcx(&self) -> TyCtxt<'tcx> { - self.fields.tcx() - } - - fn param_env(&self) -> ty::ParamEnv<'tcx> { - self.fields.param_env - } - - fn a_is_expected(&self) -> bool { - self.a_is_expected - } - - fn relate_with_variance<T: Relate<'tcx>>( - &mut self, - variance: ty::Variance, - a: &T, - b: &T, - ) -> RelateResult<'tcx, T> { - match variance { - ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b), - ty::Covariant => self.relate(a, b), - // FIXME(#41044) -- not correct, need test - ty::Bivariant => Ok(a.clone()), - ty::Contravariant => self.fields.lub(self.a_is_expected).relate(a, b), - } - } - - fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { - lattice::super_lattice_tys(self, a, b) - } - - fn regions( - &mut self, - a: ty::Region<'tcx>, - b: ty::Region<'tcx>, - ) -> RelateResult<'tcx, ty::Region<'tcx>> { - debug!("{}.regions({:?}, {:?})", self.tag(), a, b); - - let origin = Subtype(box self.fields.trace.clone()); - Ok(self.fields.infcx.inner.borrow_mut().unwrap_region_constraints().glb_regions( - self.tcx(), - origin, - a, - b, - )) - } - - fn consts( - &mut self, - a: &'tcx ty::Const<'tcx>, - b: &'tcx ty::Const<'tcx>, - ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> { - self.fields.infcx.super_combine_consts(self, a, b) - } - - fn binders<T>( - &mut self, - a: &ty::Binder<T>, - b: &ty::Binder<T>, - ) -> RelateResult<'tcx, ty::Binder<T>> - where - T: Relate<'tcx>, - { - debug!("binders(a={:?}, b={:?})", a, b); - - // When higher-ranked types are involved, computing the LUB is - // very challenging, switch to invariance. This is obviously - // overly conservative but works ok in practice. - self.relate_with_variance(ty::Variance::Invariant, a, b)?; - Ok(a.clone()) - } -} - -impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Glb<'combine, 'infcx, 'tcx> { - fn infcx(&self) -> &'infcx InferCtxt<'infcx, 'tcx> { - self.fields.infcx - } - - fn cause(&self) -> &ObligationCause<'tcx> { - &self.fields.trace.cause - } - - fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> { - let mut sub = self.fields.sub(self.a_is_expected); - sub.relate(&v, &a)?; - sub.relate(&v, &b)?; - Ok(()) - } -} diff --git a/src/librustc/infer/higher_ranked/README.md b/src/librustc/infer/higher_ranked/README.md deleted file mode 100644 index e7afaa5beb0..00000000000 --- a/src/librustc/infer/higher_ranked/README.md +++ /dev/null @@ -1,8 +0,0 @@ -To learn more about how Higher-ranked trait bounds work in the _old_ trait -solver, see [this chapter][oldhrtb] of the rustc-guide. - -To learn more about how they work in the _new_ trait solver, see [this -chapter][newhrtb]. - -[oldhrtb]: https://rust-lang.github.io/rustc-guide/traits/hrtb.html -[newhrtb]: https://rust-lang.github.io/rustc-guide/borrow_check/region_inference.html#placeholders-and-universes diff --git a/src/librustc/infer/higher_ranked/mod.rs b/src/librustc/infer/higher_ranked/mod.rs deleted file mode 100644 index 1b0f399ca33..00000000000 --- a/src/librustc/infer/higher_ranked/mod.rs +++ /dev/null @@ -1,148 +0,0 @@ -//! Helper routines for higher-ranked things. See the `doc` module at -//! the end of the file for details. - -use super::combine::CombineFields; -use super::{HigherRankedType, InferCtxt, PlaceholderMap}; - -use crate::infer::CombinedSnapshot; -use crate::ty::relate::{Relate, RelateResult, TypeRelation}; -use crate::ty::{self, Binder, TypeFoldable}; - -impl<'a, 'tcx> CombineFields<'a, 'tcx> { - pub fn higher_ranked_sub<T>( - &mut self, - a: &Binder<T>, - b: &Binder<T>, - a_is_expected: bool, - ) -> RelateResult<'tcx, Binder<T>> - where - T: Relate<'tcx>, - { - debug!("higher_ranked_sub(a={:?}, b={:?})", a, b); - - // Rather than checking the subtype relationship between `a` and `b` - // as-is, we need to do some extra work here in order to make sure - // that function subtyping works correctly with respect to regions - // - // Note: this is a subtle algorithm. For a full explanation, - // please see the large comment at the end of the file in the (inlined) module - // `doc`. - - let span = self.trace.cause.span; - - return self.infcx.commit_if_ok(|snapshot| { - // First, we instantiate each bound region in the supertype with a - // fresh placeholder region. - let (b_prime, placeholder_map) = self.infcx.replace_bound_vars_with_placeholders(b); - - // Next, we instantiate each bound region in the subtype - // with a fresh region variable. These region variables -- - // but no other pre-existing region variables -- can name - // the placeholders. - let (a_prime, _) = - self.infcx.replace_bound_vars_with_fresh_vars(span, HigherRankedType, a); - - debug!("a_prime={:?}", a_prime); - debug!("b_prime={:?}", b_prime); - - // Compare types now that bound regions have been replaced. - let result = self.sub(a_is_expected).relate(&a_prime, &b_prime)?; - - self.infcx.leak_check(!a_is_expected, &placeholder_map, snapshot)?; - - debug!("higher_ranked_sub: OK result={:?}", result); - - Ok(ty::Binder::bind(result)) - }); - } -} - -impl<'a, 'tcx> InferCtxt<'a, 'tcx> { - /// Replaces all regions (resp. types) bound by `binder` with placeholder - /// regions (resp. types) and return a map indicating which bound-region - /// placeholder region. This is the first step of checking subtyping - /// when higher-ranked things are involved. - /// - /// **Important:** you must call this function from within a snapshot. - /// Moreover, before committing the snapshot, you must eventually call - /// either `plug_leaks` or `pop_placeholders` to remove the placeholder - /// regions. If you rollback the snapshot (or are using a probe), then - /// the pop occurs as part of the rollback, so an explicit call is not - /// needed (but is also permitted). - /// - /// For more information about how placeholders and HRTBs work, see - /// the [rustc guide]. - /// - /// [rustc guide]: https://rust-lang.github.io/rustc-guide/traits/hrtb.html - pub fn replace_bound_vars_with_placeholders<T>( - &self, - binder: &ty::Binder<T>, - ) -> (T, PlaceholderMap<'tcx>) - where - T: TypeFoldable<'tcx>, - { - let next_universe = self.create_next_universe(); - - let fld_r = |br| { - self.tcx.mk_region(ty::RePlaceholder(ty::PlaceholderRegion { - universe: next_universe, - name: br, - })) - }; - - let fld_t = |bound_ty: ty::BoundTy| { - self.tcx.mk_ty(ty::Placeholder(ty::PlaceholderType { - universe: next_universe, - name: bound_ty.var, - })) - }; - - let fld_c = |bound_var: ty::BoundVar, ty| { - self.tcx.mk_const(ty::Const { - val: ty::ConstKind::Placeholder(ty::PlaceholderConst { - universe: next_universe, - name: bound_var, - }), - ty, - }) - }; - - let (result, map) = self.tcx.replace_bound_vars(binder, fld_r, fld_t, fld_c); - - debug!( - "replace_bound_vars_with_placeholders(\ - next_universe={:?}, \ - binder={:?}, \ - result={:?}, \ - map={:?})", - next_universe, binder, result, map, - ); - - (result, map) - } - - /// See `infer::region_constraints::RegionConstraintCollector::leak_check`. - pub fn leak_check( - &self, - overly_polymorphic: bool, - placeholder_map: &PlaceholderMap<'tcx>, - snapshot: &CombinedSnapshot<'_, 'tcx>, - ) -> RelateResult<'tcx, ()> { - // If the user gave `-Zno-leak-check`, or we have been - // configured to skip the leak check, then skip the leak check - // completely. The leak check is deprecated. Any legitimate - // subtyping errors that it would have caught will now be - // caught later on, during region checking. However, we - // continue to use it for a transition period. - if self.tcx.sess.opts.debugging_opts.no_leak_check || self.skip_leak_check.get() { - return Ok(()); - } - - self.inner.borrow_mut().unwrap_region_constraints().leak_check( - self.tcx, - overly_polymorphic, - placeholder_map, - snapshot, - ) - } -} diff --git a/src/librustc/infer/lattice.rs b/src/librustc/infer/lattice.rs deleted file mode 100644 index df475af1151..00000000000 --- a/src/librustc/infer/lattice.rs +++ /dev/null @@ -1,99 +0,0 @@ -//! # Lattice Variables -//! -//! This file contains generic code for operating on inference variables -//! that are characterized by an upper- and lower-bound. The logic and -//! reasoning is explained in detail in the large comment in `infer.rs`. -//! -//! The code in here is defined quite generically so that it can be -//! applied both to type variables, which represent types being inferred, -//! and fn variables, which represent function types being inferred. -//! It may eventually be applied to their types as well, who knows. -//! In some cases, the functions are also generic with respect to the -//! operation on the lattice (GLB vs LUB). -//! -//! Although all the functions are generic, we generally write the -//! comments in a way that is specific to type variables and the LUB -//! operation. It's just easier that way. -//! -//! In general all of the functions are defined parametrically -//! over a `LatticeValue`, which is a value defined with respect to -//! a lattice. - -use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use super::InferCtxt; - -use crate::traits::ObligationCause; -use crate::ty::relate::{RelateResult, TypeRelation}; -use crate::ty::TyVar; -use crate::ty::{self, Ty}; - -pub trait LatticeDir<'f, 'tcx>: TypeRelation<'tcx> { - fn infcx(&self) -> &'f InferCtxt<'f, 'tcx>; - - fn cause(&self) -> &ObligationCause<'tcx>; - - // Relates the type `v` to `a` and `b` such that `v` represents - // the LUB/GLB of `a` and `b` as appropriate. - // - // Subtle hack: ordering *may* be significant here. This method - // relates `v` to `a` first, which may help us to avoid unnecessary - // type variable obligations. See caller for details. - fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()>; -} - -pub fn super_lattice_tys<'a, 'tcx: 'a, L>( - this: &mut L, - a: Ty<'tcx>, - b: Ty<'tcx>, -) -> RelateResult<'tcx, Ty<'tcx>> -where - L: LatticeDir<'a, 'tcx>, -{ - debug!("{}.lattice_tys({:?}, {:?})", this.tag(), a, b); - - if a == b { - return Ok(a); - } - - let infcx = this.infcx(); - let a = infcx.inner.borrow_mut().type_variables.replace_if_possible(a); - let b = infcx.inner.borrow_mut().type_variables.replace_if_possible(b); - match (&a.kind, &b.kind) { - // If one side is known to be a variable and one is not, - // create a variable (`v`) to represent the LUB. Make sure to - // relate `v` to the non-type-variable first (by passing it - // first to `relate_bound`). Otherwise, we would produce a - // subtype obligation that must then be processed. - // - // Example: if the LHS is a type variable, and RHS is - // `Box<i32>`, then we current compare `v` to the RHS first, - // which will instantiate `v` with `Box<i32>`. Then when `v` - // is compared to the LHS, we instantiate LHS with `Box<i32>`. - // But if we did in reverse order, we would create a `v <: - // LHS` (or vice versa) constraint and then instantiate - // `v`. This would require further processing to achieve same - // end-result; in partiular, this screws up some of the logic - // in coercion, which expects LUB to figure out that the LHS - // is (e.g.) `Box<i32>`. A more obvious solution might be to - // iterate on the subtype obligations that are returned, but I - // think this suffices. -nmatsakis - (&ty::Infer(TyVar(..)), _) => { - let v = infcx.next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::LatticeVariable, - span: this.cause().span, - }); - this.relate_bound(v, b, a)?; - Ok(v) - } - (_, &ty::Infer(TyVar(..))) => { - let v = infcx.next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::LatticeVariable, - span: this.cause().span, - }); - this.relate_bound(v, a, b)?; - Ok(v) - } - - _ => infcx.super_combine_tys(this, a, b), - } -} diff --git a/src/librustc/infer/lexical_region_resolve/README.md b/src/librustc/infer/lexical_region_resolve/README.md deleted file mode 100644 index c26b5625a90..00000000000 --- a/src/librustc/infer/lexical_region_resolve/README.md +++ /dev/null @@ -1,7 +0,0 @@ - -Lexical Region Resolution was removed in https://github.com/rust-lang/rust/pull/64790. - -Rust now uses Non-lexical lifetimes. For more info, please see the [borrowck -chapter][bc] in the rustc-guide. - -[bc]: https://rust-lang.github.io/rustc-guide/borrow_check/region_inference.html diff --git a/src/librustc/infer/lexical_region_resolve/graphviz.rs b/src/librustc/infer/lexical_region_resolve/graphviz.rs deleted file mode 100644 index a930e707c5c..00000000000 --- a/src/librustc/infer/lexical_region_resolve/graphviz.rs +++ /dev/null @@ -1,253 +0,0 @@ -//! This module provides linkage between libgraphviz traits and -//! `rustc::middle::typeck::infer::region_constraints`, generating a -//! rendering of the graph represented by the list of `Constraint` -//! instances (which make up the edges of the graph), as well as the -//! origin for each constraint (which are attached to the labels on -//! each edge). - -/// For clarity, rename the graphviz crate locally to dot. -use graphviz as dot; - -use super::Constraint; -use crate::infer::region_constraints::RegionConstraintData; -use crate::infer::SubregionOrigin; -use crate::middle::free_region::RegionRelations; -use crate::middle::region; -use crate::ty; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_hir::def_id::DefIndex; - -use std::borrow::Cow; -use std::collections::btree_map::BTreeMap; -use std::collections::hash_map::Entry::Vacant; -use std::env; -use std::fs; -use std::io; -use std::sync::atomic::{AtomicBool, Ordering}; - -fn print_help_message() { - println!( - "\ --Z print-region-graph by default prints a region constraint graph for every \n\ -function body, to the path `constraints.nodeXXX.dot`, where the XXX is \n\ -replaced with the node id of the function under analysis. \n\ - \n\ -To select one particular function body, set `RUST_REGION_GRAPH_NODE=XXX`, \n\ -where XXX is the node id desired. \n\ - \n\ -To generate output to some path other than the default \n\ -`constraints.nodeXXX.dot`, set `RUST_REGION_GRAPH=/path/desired.dot`; \n\ -occurrences of the character `%` in the requested path will be replaced with\n\ -the node id of the function under analysis. \n\ - \n\ -(Since you requested help via RUST_REGION_GRAPH=help, no region constraint \n\ -graphs will be printed. \n\ -" - ); -} - -pub fn maybe_print_constraints_for<'a, 'tcx>( - region_data: &RegionConstraintData<'tcx>, - region_rels: &RegionRelations<'a, 'tcx>, -) { - let tcx = region_rels.tcx; - let context = region_rels.context; - - if !tcx.sess.opts.debugging_opts.print_region_graph { - return; - } - - let requested_node = env::var("RUST_REGION_GRAPH_NODE") - .ok() - .and_then(|s| s.parse().map(DefIndex::from_u32).ok()); - - if requested_node.is_some() && requested_node != Some(context.index) { - return; - } - - let requested_output = env::var("RUST_REGION_GRAPH"); - debug!("requested_output: {:?} requested_node: {:?}", requested_output, requested_node); - - let output_path = { - let output_template = match requested_output { - Ok(ref s) if s == "help" => { - static PRINTED_YET: AtomicBool = AtomicBool::new(false); - if !PRINTED_YET.load(Ordering::SeqCst) { - print_help_message(); - PRINTED_YET.store(true, Ordering::SeqCst); - } - return; - } - - Ok(other_path) => other_path, - Err(_) => "constraints.node%.dot".to_string(), - }; - - if output_template.is_empty() { - panic!("empty string provided as RUST_REGION_GRAPH"); - } - - if output_template.contains('%') { - let mut new_str = String::new(); - for c in output_template.chars() { - if c == '%' { - new_str.push_str(&context.index.as_u32().to_string()); - } else { - new_str.push(c); - } - } - new_str - } else { - output_template - } - }; - - if let Err(e) = dump_region_data_to(region_rels, ®ion_data.constraints, &output_path) { - let msg = format!("io error dumping region constraints: {}", e); - tcx.sess.err(&msg) - } -} - -struct ConstraintGraph<'a, 'tcx> { - graph_name: String, - region_rels: &'a RegionRelations<'a, 'tcx>, - map: &'a BTreeMap<Constraint<'tcx>, SubregionOrigin<'tcx>>, - node_ids: FxHashMap<Node, usize>, -} - -#[derive(Clone, Hash, PartialEq, Eq, Debug, Copy)] -enum Node { - RegionVid(ty::RegionVid), - Region(ty::RegionKind), -} - -#[derive(Clone, PartialEq, Eq, Debug, Copy)] -enum Edge<'tcx> { - Constraint(Constraint<'tcx>), - EnclScope(region::Scope, region::Scope), -} - -impl<'a, 'tcx> ConstraintGraph<'a, 'tcx> { - fn new( - name: String, - region_rels: &'a RegionRelations<'a, 'tcx>, - map: &'a ConstraintMap<'tcx>, - ) -> ConstraintGraph<'a, 'tcx> { - let mut i = 0; - let mut node_ids = FxHashMap::default(); - { - let mut add_node = |node| { - if let Vacant(e) = node_ids.entry(node) { - e.insert(i); - i += 1; - } - }; - - for (n1, n2) in map.keys().map(|c| constraint_to_nodes(c)) { - add_node(n1); - add_node(n2); - } - - region_rels.region_scope_tree.each_encl_scope(|sub, sup| { - add_node(Node::Region(ty::ReScope(sub))); - add_node(Node::Region(ty::ReScope(sup))); - }); - } - - ConstraintGraph { map, node_ids, region_rels, graph_name: name } - } -} - -impl<'a, 'tcx> dot::Labeller<'a> for ConstraintGraph<'a, 'tcx> { - type Node = Node; - type Edge = Edge<'tcx>; - fn graph_id(&self) -> dot::Id<'_> { - dot::Id::new(&*self.graph_name).unwrap() - } - fn node_id(&self, n: &Node) -> dot::Id<'_> { - let node_id = match self.node_ids.get(n) { - Some(node_id) => node_id, - None => bug!("no node_id found for node: {:?}", n), - }; - let name = || format!("node_{}", node_id); - - dot::Id::new(name()) - .unwrap_or_else(|_| bug!("failed to create graphviz node identified by {}", name())) - } - fn node_label(&self, n: &Node) -> dot::LabelText<'_> { - match *n { - Node::RegionVid(n_vid) => dot::LabelText::label(format!("{:?}", n_vid)), - Node::Region(n_rgn) => dot::LabelText::label(format!("{:?}", n_rgn)), - } - } - fn edge_label(&self, e: &Edge<'_>) -> dot::LabelText<'_> { - match *e { - Edge::Constraint(ref c) => { - dot::LabelText::label(format!("{:?}", self.map.get(c).unwrap())) - } - Edge::EnclScope(..) => dot::LabelText::label("(enclosed)".to_owned()), - } - } -} - -fn constraint_to_nodes(c: &Constraint<'_>) -> (Node, Node) { - match *c { - Constraint::VarSubVar(rv_1, rv_2) => (Node::RegionVid(rv_1), Node::RegionVid(rv_2)), - Constraint::RegSubVar(r_1, rv_2) => (Node::Region(*r_1), Node::RegionVid(rv_2)), - Constraint::VarSubReg(rv_1, r_2) => (Node::RegionVid(rv_1), Node::Region(*r_2)), - Constraint::RegSubReg(r_1, r_2) => (Node::Region(*r_1), Node::Region(*r_2)), - } -} - -fn edge_to_nodes(e: &Edge<'_>) -> (Node, Node) { - match *e { - Edge::Constraint(ref c) => constraint_to_nodes(c), - Edge::EnclScope(sub, sup) => { - (Node::Region(ty::ReScope(sub)), Node::Region(ty::ReScope(sup))) - } - } -} - -impl<'a, 'tcx> dot::GraphWalk<'a> for ConstraintGraph<'a, 'tcx> { - type Node = Node; - type Edge = Edge<'tcx>; - fn nodes(&self) -> dot::Nodes<'_, Node> { - let set = self.node_ids.keys().cloned().collect::<FxHashSet<_>>(); - debug!("constraint graph has {} nodes", set.len()); - set.into_iter().collect() - } - fn edges(&self) -> dot::Edges<'_, Edge<'tcx>> { - debug!("constraint graph has {} edges", self.map.len()); - let mut v: Vec<_> = self.map.keys().map(|e| Edge::Constraint(*e)).collect(); - self.region_rels - .region_scope_tree - .each_encl_scope(|sub, sup| v.push(Edge::EnclScope(sub, sup))); - debug!("region graph has {} edges", v.len()); - Cow::Owned(v) - } - fn source(&self, edge: &Edge<'tcx>) -> Node { - let (n1, _) = edge_to_nodes(edge); - debug!("edge {:?} has source {:?}", edge, n1); - n1 - } - fn target(&self, edge: &Edge<'tcx>) -> Node { - let (_, n2) = edge_to_nodes(edge); - debug!("edge {:?} has target {:?}", edge, n2); - n2 - } -} - -pub type ConstraintMap<'tcx> = BTreeMap<Constraint<'tcx>, SubregionOrigin<'tcx>>; - -fn dump_region_data_to<'a, 'tcx>( - region_rels: &RegionRelations<'a, 'tcx>, - map: &ConstraintMap<'tcx>, - path: &str, -) -> io::Result<()> { - debug!("dump_region_data map (len: {}) path: {}", map.len(), path); - let g = ConstraintGraph::new("region_data".to_string(), region_rels, map); - debug!("dump_region_data calling render"); - let mut v = Vec::new(); - dot::render(&g, &mut v).unwrap(); - fs::write(path, &v) -} diff --git a/src/librustc/infer/lexical_region_resolve/mod.rs b/src/librustc/infer/lexical_region_resolve/mod.rs deleted file mode 100644 index 1b204e5ba6c..00000000000 --- a/src/librustc/infer/lexical_region_resolve/mod.rs +++ /dev/null @@ -1,1029 +0,0 @@ -//! Lexical region resolution. - -use crate::infer::region_constraints::Constraint; -use crate::infer::region_constraints::GenericKind; -use crate::infer::region_constraints::MemberConstraint; -use crate::infer::region_constraints::RegionConstraintData; -use crate::infer::region_constraints::VarInfos; -use crate::infer::region_constraints::VerifyBound; -use crate::infer::RegionVariableOrigin; -use crate::infer::SubregionOrigin; -use crate::middle::free_region::RegionRelations; -use crate::ty::fold::TypeFoldable; -use crate::ty::{self, Ty, TyCtxt}; -use crate::ty::{ReEarlyBound, ReEmpty, ReErased, ReFree, ReStatic}; -use crate::ty::{ReLateBound, RePlaceholder, ReScope, ReVar}; -use crate::ty::{Region, RegionVid}; -use rustc_data_structures::fx::FxHashSet; -use rustc_data_structures::graph::implementation::{ - Direction, Graph, NodeIndex, INCOMING, OUTGOING, -}; -use rustc_index::vec::{Idx, IndexVec}; -use rustc_span::Span; -use std::fmt; - -mod graphviz; - -/// This function performs lexical region resolution given a complete -/// set of constraints and variable origins. It performs a fixed-point -/// iteration to find region values which satisfy all constraints, -/// assuming such values can be found. It returns the final values of -/// all the variables as well as a set of errors that must be reported. -pub fn resolve<'tcx>( - region_rels: &RegionRelations<'_, 'tcx>, - var_infos: VarInfos, - data: RegionConstraintData<'tcx>, -) -> (LexicalRegionResolutions<'tcx>, Vec<RegionResolutionError<'tcx>>) { - debug!("RegionConstraintData: resolve_regions()"); - let mut errors = vec![]; - let mut resolver = LexicalResolver { region_rels, var_infos, data }; - let values = resolver.infer_variable_values(&mut errors); - (values, errors) -} - -/// Contains the result of lexical region resolution. Offers methods -/// to lookup up the final value of a region variable. -pub struct LexicalRegionResolutions<'tcx> { - values: IndexVec<RegionVid, VarValue<'tcx>>, - error_region: ty::Region<'tcx>, -} - -#[derive(Copy, Clone, Debug)] -enum VarValue<'tcx> { - Value(Region<'tcx>), - ErrorValue, -} - -#[derive(Clone, Debug)] -pub enum RegionResolutionError<'tcx> { - /// `ConcreteFailure(o, a, b)`: - /// - /// `o` requires that `a <= b`, but this does not hold - ConcreteFailure(SubregionOrigin<'tcx>, Region<'tcx>, Region<'tcx>), - - /// `GenericBoundFailure(p, s, a) - /// - /// The parameter/associated-type `p` must be known to outlive the lifetime - /// `a` (but none of the known bounds are sufficient). - GenericBoundFailure(SubregionOrigin<'tcx>, GenericKind<'tcx>, Region<'tcx>), - - /// `SubSupConflict(v, v_origin, sub_origin, sub_r, sup_origin, sup_r)`: - /// - /// Could not infer a value for `v` (which has origin `v_origin`) - /// because `sub_r <= v` (due to `sub_origin`) but `v <= sup_r` (due to `sup_origin`) and - /// `sub_r <= sup_r` does not hold. - SubSupConflict( - RegionVid, - RegionVariableOrigin, - SubregionOrigin<'tcx>, - Region<'tcx>, - SubregionOrigin<'tcx>, - Region<'tcx>, - ), - - /// Indicates a `'b: 'a` constraint where `'a` is in a universe that - /// cannot name the placeholder `'b`. - UpperBoundUniverseConflict( - RegionVid, - RegionVariableOrigin, - ty::UniverseIndex, // the universe index of the region variable - SubregionOrigin<'tcx>, // cause of the constraint - Region<'tcx>, // the placeholder `'b` - ), - - /// Indicates a failure of a `MemberConstraint`. These arise during - /// impl trait processing explicitly -- basically, the impl trait's hidden type - /// included some region that it was not supposed to. - MemberConstraintFailure { span: Span, hidden_ty: Ty<'tcx>, member_region: Region<'tcx> }, -} - -struct RegionAndOrigin<'tcx> { - region: Region<'tcx>, - origin: SubregionOrigin<'tcx>, -} - -type RegionGraph<'tcx> = Graph<(), Constraint<'tcx>>; - -struct LexicalResolver<'cx, 'tcx> { - region_rels: &'cx RegionRelations<'cx, 'tcx>, - var_infos: VarInfos, - data: RegionConstraintData<'tcx>, -} - -impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { - fn tcx(&self) -> TyCtxt<'tcx> { - self.region_rels.tcx - } - - fn infer_variable_values( - &mut self, - errors: &mut Vec<RegionResolutionError<'tcx>>, - ) -> LexicalRegionResolutions<'tcx> { - let mut var_data = self.construct_var_data(self.tcx()); - - // Dorky hack to cause `dump_constraints` to only get called - // if debug mode is enabled: - debug!( - "----() End constraint listing (context={:?}) {:?}---", - self.region_rels.context, - self.dump_constraints(self.region_rels) - ); - graphviz::maybe_print_constraints_for(&self.data, self.region_rels); - - let graph = self.construct_graph(); - self.expand_givens(&graph); - loop { - self.expansion(&mut var_data); - if !self.enforce_member_constraints(&graph, &mut var_data) { - break; - } - } - self.collect_errors(&mut var_data, errors); - self.collect_var_errors(&var_data, &graph, errors); - var_data - } - - fn num_vars(&self) -> usize { - self.var_infos.len() - } - - /// Initially, the value for all variables is set to `'empty`, the - /// empty region. The `expansion` phase will grow this larger. - fn construct_var_data(&self, tcx: TyCtxt<'tcx>) -> LexicalRegionResolutions<'tcx> { - LexicalRegionResolutions { - error_region: tcx.lifetimes.re_static, - values: IndexVec::from_fn_n( - |vid| { - let vid_universe = self.var_infos[vid].universe; - let re_empty = tcx.mk_region(ty::ReEmpty(vid_universe)); - VarValue::Value(re_empty) - }, - self.num_vars(), - ), - } - } - - fn dump_constraints(&self, free_regions: &RegionRelations<'_, 'tcx>) { - debug!("----() Start constraint listing (context={:?}) ()----", free_regions.context); - for (idx, (constraint, _)) in self.data.constraints.iter().enumerate() { - debug!("Constraint {} => {:?}", idx, constraint); - } - } - - fn expand_givens(&mut self, graph: &RegionGraph<'_>) { - // Givens are a kind of horrible hack to account for - // constraints like 'c <= '0 that are known to hold due to - // closure signatures (see the comment above on the `givens` - // field). They should go away. But until they do, the role - // of this fn is to account for the transitive nature: - // - // Given 'c <= '0 - // and '0 <= '1 - // then 'c <= '1 - - let seeds: Vec<_> = self.data.givens.iter().cloned().collect(); - for (r, vid) in seeds { - // While all things transitively reachable in the graph - // from the variable (`'0` in the example above). - let seed_index = NodeIndex(vid.index() as usize); - for succ_index in graph.depth_traverse(seed_index, OUTGOING) { - let succ_index = succ_index.0; - - // The first N nodes correspond to the region - // variables. Other nodes correspond to constant - // regions. - if succ_index < self.num_vars() { - let succ_vid = RegionVid::new(succ_index); - - // Add `'c <= '1`. - self.data.givens.insert((r, succ_vid)); - } - } - } - } - - /// Enforce all member constraints and return true if anything - /// changed. See `enforce_member_constraint` for more details. - fn enforce_member_constraints( - &self, - graph: &RegionGraph<'tcx>, - var_values: &mut LexicalRegionResolutions<'tcx>, - ) -> bool { - // Note: we don't use the `any` combinator because we don't - // want to stop at the first constraint that makes a change. - let mut any_changed = false; - for member_constraint in &self.data.member_constraints { - any_changed |= self.enforce_member_constraint(graph, member_constraint, var_values); - } - any_changed - } - - /// Enforce a constraint like - /// - /// ``` - /// 'r member of ['c...] - /// ``` - /// - /// We look for all choice regions from the list `'c...` that: - /// - /// (a) are greater than the current value of `'r` (which is a lower bound) - /// - /// and - /// - /// (b) are compatible with the upper bounds of `'r` that we can - /// find by traversing the graph. - /// - /// From that list, we look for a *minimal* option `'c_min`. If we - /// find one, then we can enforce that `'r: 'c_min`. - fn enforce_member_constraint( - &self, - graph: &RegionGraph<'tcx>, - member_constraint: &MemberConstraint<'tcx>, - var_values: &mut LexicalRegionResolutions<'tcx>, - ) -> bool { - debug!("enforce_member_constraint(member_constraint={:#?})", member_constraint); - - // The constraint is some inference variable (`vid`) which - // must be equal to one of the options. - let member_vid = match member_constraint.member_region { - ty::ReVar(vid) => *vid, - _ => return false, - }; - - // The current value of `vid` is a lower bound LB -- i.e., we - // know that `LB <= vid` must be true. - let member_lower_bound: ty::Region<'tcx> = match var_values.value(member_vid) { - VarValue::ErrorValue => return false, - VarValue::Value(r) => r, - }; - - // Find all the "upper bounds" -- that is, each region `b` such that - // `r0 <= b` must hold. - let (member_upper_bounds, _) = - self.collect_concrete_regions(graph, member_vid, OUTGOING, None); - - // Get an iterator over the *available choice* -- that is, - // each choice region `c` where `lb <= c` and `c <= ub` for all the - // upper bounds `ub`. - debug!("enforce_member_constraint: upper_bounds={:#?}", member_upper_bounds); - let mut options = member_constraint.choice_regions.iter().filter(|option| { - self.sub_concrete_regions(member_lower_bound, option) - && member_upper_bounds - .iter() - .all(|upper_bound| self.sub_concrete_regions(option, upper_bound.region)) - }); - - // If there is more than one option, we only make a choice if - // there is a single *least* choice -- i.e., some available - // region that is `<=` all the others. - let mut least_choice: ty::Region<'tcx> = match options.next() { - Some(&r) => r, - None => return false, - }; - debug!("enforce_member_constraint: least_choice={:?}", least_choice); - for &option in options { - debug!("enforce_member_constraint: option={:?}", option); - if !self.sub_concrete_regions(least_choice, option) { - if self.sub_concrete_regions(option, least_choice) { - debug!("enforce_member_constraint: new least choice"); - least_choice = option; - } else { - debug!("enforce_member_constraint: no least choice"); - return false; - } - } - } - - debug!("enforce_member_constraint: final least choice = {:?}", least_choice); - if least_choice != member_lower_bound { - *var_values.value_mut(member_vid) = VarValue::Value(least_choice); - true - } else { - false - } - } - - fn expansion(&self, var_values: &mut LexicalRegionResolutions<'tcx>) { - let mut constraints = IndexVec::from_elem_n(Vec::new(), var_values.values.len()); - let mut changes = Vec::new(); - for constraint in self.data.constraints.keys() { - let (a_vid, a_region, b_vid, b_data) = match *constraint { - Constraint::RegSubVar(a_region, b_vid) => { - let b_data = var_values.value_mut(b_vid); - (None, a_region, b_vid, b_data) - } - Constraint::VarSubVar(a_vid, b_vid) => match *var_values.value(a_vid) { - VarValue::ErrorValue => continue, - VarValue::Value(a_region) => { - let b_data = var_values.value_mut(b_vid); - (Some(a_vid), a_region, b_vid, b_data) - } - }, - Constraint::RegSubReg(..) | Constraint::VarSubReg(..) => { - // These constraints are checked after expansion - // is done, in `collect_errors`. - continue; - } - }; - if self.expand_node(a_region, b_vid, b_data) { - changes.push(b_vid); - } - if let Some(a_vid) = a_vid { - match *b_data { - VarValue::Value(ReStatic) | VarValue::ErrorValue => (), - _ => { - constraints[a_vid].push((a_vid, b_vid)); - constraints[b_vid].push((a_vid, b_vid)); - } - } - } - } - - while let Some(vid) = changes.pop() { - constraints[vid].retain(|&(a_vid, b_vid)| { - let a_region = match *var_values.value(a_vid) { - VarValue::ErrorValue => return false, - VarValue::Value(a_region) => a_region, - }; - let b_data = var_values.value_mut(b_vid); - if self.expand_node(a_region, b_vid, b_data) { - changes.push(b_vid); - } - match *b_data { - VarValue::Value(ReStatic) | VarValue::ErrorValue => false, - _ => true, - } - }); - } - } - - fn expand_node( - &self, - a_region: Region<'tcx>, - b_vid: RegionVid, - b_data: &mut VarValue<'tcx>, - ) -> bool { - debug!("expand_node({:?}, {:?} == {:?})", a_region, b_vid, b_data); - - match *a_region { - // Check if this relationship is implied by a given. - ty::ReEarlyBound(_) | ty::ReFree(_) => { - if self.data.givens.contains(&(a_region, b_vid)) { - debug!("given"); - return false; - } - } - - _ => {} - } - - match *b_data { - VarValue::Value(cur_region) => { - // Identical scopes can show up quite often, if the fixed point - // iteration converges slowly. Skip them. This is purely an - // optimization. - if let (ReScope(a_scope), ReScope(cur_scope)) = (a_region, cur_region) { - if a_scope == cur_scope { - return false; - } - } - - // This is a specialized version of the `lub_concrete_regions` - // check below for a common case, here purely as an - // optimization. - let b_universe = self.var_infos[b_vid].universe; - if let ReEmpty(a_universe) = a_region { - if *a_universe == b_universe { - return false; - } - } - - let mut lub = self.lub_concrete_regions(a_region, cur_region); - if lub == cur_region { - return false; - } - - // Watch out for `'b: !1` relationships, where the - // universe of `'b` can't name the placeholder `!1`. In - // that case, we have to grow `'b` to be `'static` for the - // relationship to hold. This is obviously a kind of sub-optimal - // choice -- in the future, when we incorporate a knowledge - // of the parameter environment, we might be able to find a - // tighter bound than `'static`. - // - // (This might e.g. arise from being asked to prove `for<'a> { 'b: 'a }`.) - if let ty::RePlaceholder(p) = lub { - if b_universe.cannot_name(p.universe) { - lub = self.tcx().lifetimes.re_static; - } - } - - debug!("Expanding value of {:?} from {:?} to {:?}", b_vid, cur_region, lub); - - *b_data = VarValue::Value(lub); - return true; - } - - VarValue::ErrorValue => { - return false; - } - } - } - - /// True if `a <= b`, but not defined over inference variables. - fn sub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> bool { - let tcx = self.tcx(); - let sub_free_regions = |r1, r2| self.region_rels.free_regions.sub_free_regions(tcx, r1, r2); - - // Check for the case where we know that `'b: 'static` -- in that case, - // `a <= b` for all `a`. - let b_free_or_static = self.region_rels.free_regions.is_free_or_static(b); - if b_free_or_static && sub_free_regions(tcx.lifetimes.re_static, b) { - return true; - } - - // If both `a` and `b` are free, consult the declared - // relationships. Note that this can be more precise than the - // `lub` relationship defined below, since sometimes the "lub" - // is actually the `postdom_upper_bound` (see - // `TransitiveRelation` for more details). - let a_free_or_static = self.region_rels.free_regions.is_free_or_static(a); - if a_free_or_static && b_free_or_static { - return sub_free_regions(a, b); - } - - // For other cases, leverage the LUB code to find the LUB and - // check if it is equal to `b`. - self.lub_concrete_regions(a, b) == b - } - - /// Returns the least-upper-bound of `a` and `b`; i.e., the - /// smallest region `c` such that `a <= c` and `b <= c`. - /// - /// Neither `a` nor `b` may be an inference variable (hence the - /// term "concrete regions"). - fn lub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> Region<'tcx> { - let r = match (a, b) { - (&ty::ReClosureBound(..), _) - | (_, &ty::ReClosureBound(..)) - | (&ReLateBound(..), _) - | (_, &ReLateBound(..)) - | (&ReErased, _) - | (_, &ReErased) => { - bug!("cannot relate region: LUB({:?}, {:?})", a, b); - } - - (&ReVar(v_id), _) | (_, &ReVar(v_id)) => { - span_bug!( - self.var_infos[v_id].origin.span(), - "lub_concrete_regions invoked with non-concrete \ - regions: {:?}, {:?}", - a, - b - ); - } - - (&ReStatic, _) | (_, &ReStatic) => { - // nothing lives longer than `'static` - self.tcx().lifetimes.re_static - } - - (&ReEmpty(_), r @ ReEarlyBound(_)) - | (r @ ReEarlyBound(_), &ReEmpty(_)) - | (&ReEmpty(_), r @ ReFree(_)) - | (r @ ReFree(_), &ReEmpty(_)) - | (&ReEmpty(_), r @ ReScope(_)) - | (r @ ReScope(_), &ReEmpty(_)) => { - // All empty regions are less than early-bound, free, - // and scope regions. - r - } - - (&ReEmpty(a_ui), &ReEmpty(b_ui)) => { - // Empty regions are ordered according to the universe - // they are associated with. - let ui = a_ui.min(b_ui); - self.tcx().mk_region(ReEmpty(ui)) - } - - (&ReEmpty(empty_ui), &RePlaceholder(placeholder)) - | (&RePlaceholder(placeholder), &ReEmpty(empty_ui)) => { - // If this empty region is from a universe that can - // name the placeholder, then the placeholder is - // larger; otherwise, the only ancestor is `'static`. - if empty_ui.can_name(placeholder.universe) { - self.tcx().mk_region(RePlaceholder(placeholder)) - } else { - self.tcx().lifetimes.re_static - } - } - - (&ReEarlyBound(_), &ReScope(s_id)) - | (&ReScope(s_id), &ReEarlyBound(_)) - | (&ReFree(_), &ReScope(s_id)) - | (&ReScope(s_id), &ReFree(_)) => { - // A "free" region can be interpreted as "some region - // at least as big as fr.scope". So, we can - // reasonably compare free regions and scopes: - let fr_scope = match (a, b) { - (&ReEarlyBound(ref br), _) | (_, &ReEarlyBound(ref br)) => { - self.region_rels.region_scope_tree.early_free_scope(self.tcx(), br) - } - (&ReFree(ref fr), _) | (_, &ReFree(ref fr)) => { - self.region_rels.region_scope_tree.free_scope(self.tcx(), fr) - } - _ => bug!(), - }; - let r_id = - self.region_rels.region_scope_tree.nearest_common_ancestor(fr_scope, s_id); - if r_id == fr_scope { - // if the free region's scope `fr.scope` is bigger than - // the scope region `s_id`, then the LUB is the free - // region itself: - match (a, b) { - (_, &ReScope(_)) => return a, - (&ReScope(_), _) => return b, - _ => bug!(), - } - } - - // otherwise, we don't know what the free region is, - // so we must conservatively say the LUB is static: - self.tcx().lifetimes.re_static - } - - (&ReScope(a_id), &ReScope(b_id)) => { - // The region corresponding to an outer block is a - // subtype of the region corresponding to an inner - // block. - let lub = self.region_rels.region_scope_tree.nearest_common_ancestor(a_id, b_id); - self.tcx().mk_region(ReScope(lub)) - } - - (&ReEarlyBound(_), &ReEarlyBound(_)) - | (&ReFree(_), &ReEarlyBound(_)) - | (&ReEarlyBound(_), &ReFree(_)) - | (&ReFree(_), &ReFree(_)) => self.region_rels.lub_free_regions(a, b), - - // For these types, we cannot define any additional - // relationship: - (&RePlaceholder(..), _) | (_, &RePlaceholder(..)) => { - if a == b { - a - } else { - self.tcx().lifetimes.re_static - } - } - }; - - debug!("lub_concrete_regions({:?}, {:?}) = {:?}", a, b, r); - - r - } - - /// After expansion is complete, go and check upper bounds (i.e., - /// cases where the region cannot grow larger than a fixed point) - /// and check that they are satisfied. - fn collect_errors( - &self, - var_data: &mut LexicalRegionResolutions<'tcx>, - errors: &mut Vec<RegionResolutionError<'tcx>>, - ) { - for (constraint, origin) in &self.data.constraints { - debug!("collect_errors: constraint={:?} origin={:?}", constraint, origin); - match *constraint { - Constraint::RegSubVar(..) | Constraint::VarSubVar(..) => { - // Expansion will ensure that these constraints hold. Ignore. - } - - Constraint::RegSubReg(sub, sup) => { - if self.sub_concrete_regions(sub, sup) { - continue; - } - - debug!( - "collect_errors: region error at {:?}: \ - cannot verify that {:?} <= {:?}", - origin, sub, sup - ); - - errors.push(RegionResolutionError::ConcreteFailure( - (*origin).clone(), - sub, - sup, - )); - } - - Constraint::VarSubReg(a_vid, b_region) => { - let a_data = var_data.value_mut(a_vid); - debug!("contraction: {:?} == {:?}, {:?}", a_vid, a_data, b_region); - - let a_region = match *a_data { - VarValue::ErrorValue => continue, - VarValue::Value(a_region) => a_region, - }; - - // Do not report these errors immediately: - // instead, set the variable value to error and - // collect them later. - if !self.sub_concrete_regions(a_region, b_region) { - debug!( - "collect_errors: region error at {:?}: \ - cannot verify that {:?}={:?} <= {:?}", - origin, a_vid, a_region, b_region - ); - *a_data = VarValue::ErrorValue; - } - } - } - } - - // Check that all member constraints are satisfied. - for member_constraint in &self.data.member_constraints { - let member_region = var_data.normalize(self.tcx(), member_constraint.member_region); - let choice_regions = member_constraint - .choice_regions - .iter() - .map(|&choice_region| var_data.normalize(self.tcx(), choice_region)); - if !choice_regions.clone().any(|choice_region| member_region == choice_region) { - let span = self.tcx().def_span(member_constraint.opaque_type_def_id); - errors.push(RegionResolutionError::MemberConstraintFailure { - span, - hidden_ty: member_constraint.hidden_ty, - member_region, - }); - } - } - - for verify in &self.data.verifys { - debug!("collect_errors: verify={:?}", verify); - let sub = var_data.normalize(self.tcx(), verify.region); - - let verify_kind_ty = verify.kind.to_ty(self.tcx()); - if self.bound_is_met(&verify.bound, var_data, verify_kind_ty, sub) { - continue; - } - - debug!( - "collect_errors: region error at {:?}: \ - cannot verify that {:?} <= {:?}", - verify.origin, verify.region, verify.bound - ); - - errors.push(RegionResolutionError::GenericBoundFailure( - verify.origin.clone(), - verify.kind, - sub, - )); - } - } - - /// Go over the variables that were declared to be error variables - /// and create a `RegionResolutionError` for each of them. - fn collect_var_errors( - &self, - var_data: &LexicalRegionResolutions<'tcx>, - graph: &RegionGraph<'tcx>, - errors: &mut Vec<RegionResolutionError<'tcx>>, - ) { - debug!("collect_var_errors"); - - // This is the best way that I have found to suppress - // duplicate and related errors. Basically we keep a set of - // flags for every node. Whenever an error occurs, we will - // walk some portion of the graph looking to find pairs of - // conflicting regions to report to the user. As we walk, we - // trip the flags from false to true, and if we find that - // we've already reported an error involving any particular - // node we just stop and don't report the current error. The - // idea is to report errors that derive from independent - // regions of the graph, but not those that derive from - // overlapping locations. - let mut dup_vec = IndexVec::from_elem_n(None, self.num_vars()); - - for (node_vid, value) in var_data.values.iter_enumerated() { - match *value { - VarValue::Value(_) => { /* Inference successful */ } - VarValue::ErrorValue => { - // Inference impossible: this value contains - // inconsistent constraints. - // - // I think that in this case we should report an - // error now -- unlike the case above, we can't - // wait to see whether the user needs the result - // of this variable. The reason is that the mere - // existence of this variable implies that the - // region graph is inconsistent, whether or not it - // is used. - // - // For example, we may have created a region - // variable that is the GLB of two other regions - // which do not have a GLB. Even if that variable - // is not used, it implies that those two regions - // *should* have a GLB. - // - // At least I think this is true. It may be that - // the mere existence of a conflict in a region - // variable that is not used is not a problem, so - // if this rule starts to create problems we'll - // have to revisit this portion of the code and - // think hard about it. =) -- nikomatsakis - self.collect_error_for_expanding_node(graph, &mut dup_vec, node_vid, errors); - } - } - } - } - - fn construct_graph(&self) -> RegionGraph<'tcx> { - let num_vars = self.num_vars(); - - let mut graph = Graph::new(); - - for _ in 0..num_vars { - graph.add_node(()); - } - - // Issue #30438: two distinct dummy nodes, one for incoming - // edges (dummy_source) and another for outgoing edges - // (dummy_sink). In `dummy -> a -> b -> dummy`, using one - // dummy node leads one to think (erroneously) there exists a - // path from `b` to `a`. Two dummy nodes sidesteps the issue. - let dummy_source = graph.add_node(()); - let dummy_sink = graph.add_node(()); - - for (constraint, _) in &self.data.constraints { - match *constraint { - Constraint::VarSubVar(a_id, b_id) => { - graph.add_edge( - NodeIndex(a_id.index() as usize), - NodeIndex(b_id.index() as usize), - *constraint, - ); - } - Constraint::RegSubVar(_, b_id) => { - graph.add_edge(dummy_source, NodeIndex(b_id.index() as usize), *constraint); - } - Constraint::VarSubReg(a_id, _) => { - graph.add_edge(NodeIndex(a_id.index() as usize), dummy_sink, *constraint); - } - Constraint::RegSubReg(..) => { - // this would be an edge from `dummy_source` to - // `dummy_sink`; just ignore it. - } - } - } - - return graph; - } - - fn collect_error_for_expanding_node( - &self, - graph: &RegionGraph<'tcx>, - dup_vec: &mut IndexVec<RegionVid, Option<RegionVid>>, - node_idx: RegionVid, - errors: &mut Vec<RegionResolutionError<'tcx>>, - ) { - // Errors in expanding nodes result from a lower-bound that is - // not contained by an upper-bound. - let (mut lower_bounds, lower_dup) = - self.collect_concrete_regions(graph, node_idx, INCOMING, Some(dup_vec)); - let (mut upper_bounds, upper_dup) = - self.collect_concrete_regions(graph, node_idx, OUTGOING, Some(dup_vec)); - - if lower_dup || upper_dup { - return; - } - - // We place free regions first because we are special casing - // SubSupConflict(ReFree, ReFree) when reporting error, and so - // the user will more likely get a specific suggestion. - fn region_order_key(x: &RegionAndOrigin<'_>) -> u8 { - match *x.region { - ReEarlyBound(_) => 0, - ReFree(_) => 1, - _ => 2, - } - } - lower_bounds.sort_by_key(region_order_key); - upper_bounds.sort_by_key(region_order_key); - - let node_universe = self.var_infos[node_idx].universe; - - for lower_bound in &lower_bounds { - let effective_lower_bound = if let ty::RePlaceholder(p) = lower_bound.region { - if node_universe.cannot_name(p.universe) { - self.tcx().lifetimes.re_static - } else { - lower_bound.region - } - } else { - lower_bound.region - }; - - for upper_bound in &upper_bounds { - if !self.sub_concrete_regions(effective_lower_bound, upper_bound.region) { - let origin = self.var_infos[node_idx].origin; - debug!( - "region inference error at {:?} for {:?}: SubSupConflict sub: {:?} \ - sup: {:?}", - origin, node_idx, lower_bound.region, upper_bound.region - ); - errors.push(RegionResolutionError::SubSupConflict( - node_idx, - origin, - lower_bound.origin.clone(), - lower_bound.region, - upper_bound.origin.clone(), - upper_bound.region, - )); - return; - } - } - } - - // If we have a scenario like `exists<'a> { forall<'b> { 'b: - // 'a } }`, we wind up without any lower-bound -- all we have - // are placeholders as upper bounds, but the universe of the - // variable `'a` doesn't permit those placeholders. - for upper_bound in &upper_bounds { - if let ty::RePlaceholder(p) = upper_bound.region { - if node_universe.cannot_name(p.universe) { - let origin = self.var_infos[node_idx].origin.clone(); - errors.push(RegionResolutionError::UpperBoundUniverseConflict( - node_idx, - origin, - node_universe, - upper_bound.origin.clone(), - upper_bound.region, - )); - return; - } - } - } - - // Errors in earlier passes can yield error variables without - // resolution errors here; delay ICE in favor of those errors. - self.tcx().sess.delay_span_bug( - self.var_infos[node_idx].origin.span(), - &format!( - "collect_error_for_expanding_node() could not find \ - error for var {:?} in universe {:?}, lower_bounds={:#?}, \ - upper_bounds={:#?}", - node_idx, node_universe, lower_bounds, upper_bounds - ), - ); - } - - fn collect_concrete_regions( - &self, - graph: &RegionGraph<'tcx>, - orig_node_idx: RegionVid, - dir: Direction, - mut dup_vec: Option<&mut IndexVec<RegionVid, Option<RegionVid>>>, - ) -> (Vec<RegionAndOrigin<'tcx>>, bool) { - struct WalkState<'tcx> { - set: FxHashSet<RegionVid>, - stack: Vec<RegionVid>, - result: Vec<RegionAndOrigin<'tcx>>, - dup_found: bool, - } - let mut state = WalkState { - set: Default::default(), - stack: vec![orig_node_idx], - result: Vec::new(), - dup_found: false, - }; - state.set.insert(orig_node_idx); - - // to start off the process, walk the source node in the - // direction specified - process_edges(&self.data, &mut state, graph, orig_node_idx, dir); - - while !state.stack.is_empty() { - let node_idx = state.stack.pop().unwrap(); - - // check whether we've visited this node on some previous walk - if let Some(dup_vec) = &mut dup_vec { - if dup_vec[node_idx].is_none() { - dup_vec[node_idx] = Some(orig_node_idx); - } else if dup_vec[node_idx] != Some(orig_node_idx) { - state.dup_found = true; - } - - debug!( - "collect_concrete_regions(orig_node_idx={:?}, node_idx={:?})", - orig_node_idx, node_idx - ); - } - - process_edges(&self.data, &mut state, graph, node_idx, dir); - } - - let WalkState { result, dup_found, .. } = state; - return (result, dup_found); - - fn process_edges<'tcx>( - this: &RegionConstraintData<'tcx>, - state: &mut WalkState<'tcx>, - graph: &RegionGraph<'tcx>, - source_vid: RegionVid, - dir: Direction, - ) { - debug!("process_edges(source_vid={:?}, dir={:?})", source_vid, dir); - - let source_node_index = NodeIndex(source_vid.index() as usize); - for (_, edge) in graph.adjacent_edges(source_node_index, dir) { - match edge.data { - Constraint::VarSubVar(from_vid, to_vid) => { - let opp_vid = if from_vid == source_vid { to_vid } else { from_vid }; - if state.set.insert(opp_vid) { - state.stack.push(opp_vid); - } - } - - Constraint::RegSubVar(region, _) | Constraint::VarSubReg(_, region) => { - state.result.push(RegionAndOrigin { - region, - origin: this.constraints.get(&edge.data).unwrap().clone(), - }); - } - - Constraint::RegSubReg(..) => panic!( - "cannot reach reg-sub-reg edge in region inference \ - post-processing" - ), - } - } - } - } - - fn bound_is_met( - &self, - bound: &VerifyBound<'tcx>, - var_values: &LexicalRegionResolutions<'tcx>, - generic_ty: Ty<'tcx>, - min: ty::Region<'tcx>, - ) -> bool { - match bound { - VerifyBound::IfEq(k, b) => { - (var_values.normalize(self.region_rels.tcx, *k) == generic_ty) - && self.bound_is_met(b, var_values, generic_ty, min) - } - - VerifyBound::OutlivedBy(r) => { - self.sub_concrete_regions(min, var_values.normalize(self.tcx(), r)) - } - - VerifyBound::IsEmpty => { - if let ty::ReEmpty(_) = min { - true - } else { - false - } - } - - VerifyBound::AnyBound(bs) => { - bs.iter().any(|b| self.bound_is_met(b, var_values, generic_ty, min)) - } - - VerifyBound::AllBounds(bs) => { - bs.iter().all(|b| self.bound_is_met(b, var_values, generic_ty, min)) - } - } - } -} - -impl<'tcx> fmt::Debug for RegionAndOrigin<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "RegionAndOrigin({:?},{:?})", self.region, self.origin) - } -} - -impl<'tcx> LexicalRegionResolutions<'tcx> { - fn normalize<T>(&self, tcx: TyCtxt<'tcx>, value: T) -> T - where - T: TypeFoldable<'tcx>, - { - tcx.fold_regions(&value, &mut false, |r, _db| match r { - ty::ReVar(rid) => self.resolve_var(*rid), - _ => r, - }) - } - - fn value(&self, rid: RegionVid) -> &VarValue<'tcx> { - &self.values[rid] - } - - fn value_mut(&mut self, rid: RegionVid) -> &mut VarValue<'tcx> { - &mut self.values[rid] - } - - pub fn resolve_var(&self, rid: RegionVid) -> ty::Region<'tcx> { - let result = match self.values[rid] { - VarValue::Value(r) => r, - VarValue::ErrorValue => self.error_region, - }; - debug!("resolve_var({:?}) = {:?}", rid, result); - result - } -} diff --git a/src/librustc/infer/lub.rs b/src/librustc/infer/lub.rs deleted file mode 100644 index 6a699f803c7..00000000000 --- a/src/librustc/infer/lub.rs +++ /dev/null @@ -1,118 +0,0 @@ -use super::combine::CombineFields; -use super::lattice::{self, LatticeDir}; -use super::InferCtxt; -use super::Subtype; - -use crate::traits::ObligationCause; -use crate::ty::relate::{Relate, RelateResult, TypeRelation}; -use crate::ty::{self, Ty, TyCtxt}; - -/// "Least upper bound" (common supertype) -pub struct Lub<'combine, 'infcx, 'tcx> { - fields: &'combine mut CombineFields<'infcx, 'tcx>, - a_is_expected: bool, -} - -impl<'combine, 'infcx, 'tcx> Lub<'combine, 'infcx, 'tcx> { - pub fn new( - fields: &'combine mut CombineFields<'infcx, 'tcx>, - a_is_expected: bool, - ) -> Lub<'combine, 'infcx, 'tcx> { - Lub { fields: fields, a_is_expected: a_is_expected } - } -} - -impl TypeRelation<'tcx> for Lub<'combine, 'infcx, 'tcx> { - fn tag(&self) -> &'static str { - "Lub" - } - - fn tcx(&self) -> TyCtxt<'tcx> { - self.fields.tcx() - } - - fn param_env(&self) -> ty::ParamEnv<'tcx> { - self.fields.param_env - } - - fn a_is_expected(&self) -> bool { - self.a_is_expected - } - - fn relate_with_variance<T: Relate<'tcx>>( - &mut self, - variance: ty::Variance, - a: &T, - b: &T, - ) -> RelateResult<'tcx, T> { - match variance { - ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b), - ty::Covariant => self.relate(a, b), - // FIXME(#41044) -- not correct, need test - ty::Bivariant => Ok(a.clone()), - ty::Contravariant => self.fields.glb(self.a_is_expected).relate(a, b), - } - } - - fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { - lattice::super_lattice_tys(self, a, b) - } - - fn regions( - &mut self, - a: ty::Region<'tcx>, - b: ty::Region<'tcx>, - ) -> RelateResult<'tcx, ty::Region<'tcx>> { - debug!("{}.regions({:?}, {:?})", self.tag(), a, b); - - let origin = Subtype(box self.fields.trace.clone()); - Ok(self.fields.infcx.inner.borrow_mut().unwrap_region_constraints().lub_regions( - self.tcx(), - origin, - a, - b, - )) - } - - fn consts( - &mut self, - a: &'tcx ty::Const<'tcx>, - b: &'tcx ty::Const<'tcx>, - ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> { - self.fields.infcx.super_combine_consts(self, a, b) - } - - fn binders<T>( - &mut self, - a: &ty::Binder<T>, - b: &ty::Binder<T>, - ) -> RelateResult<'tcx, ty::Binder<T>> - where - T: Relate<'tcx>, - { - debug!("binders(a={:?}, b={:?})", a, b); - - // When higher-ranked types are involved, computing the LUB is - // very challenging, switch to invariance. This is obviously - // overly conservative but works ok in practice. - self.relate_with_variance(ty::Variance::Invariant, a, b)?; - Ok(a.clone()) - } -} - -impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Lub<'combine, 'infcx, 'tcx> { - fn infcx(&self) -> &'infcx InferCtxt<'infcx, 'tcx> { - self.fields.infcx - } - - fn cause(&self) -> &ObligationCause<'tcx> { - &self.fields.trace.cause - } - - fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> { - let mut sub = self.fields.sub(self.a_is_expected); - sub.relate(&a, &v)?; - sub.relate(&b, &v)?; - Ok(()) - } -} diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index be58de996a5..497d3811f28 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -1,1785 +1,32 @@ -//! See the Book for more information. - -pub use self::freshen::TypeFreshener; -pub use self::LateBoundRegionConversionTime::*; -pub use self::RegionVariableOrigin::*; -pub use self::SubregionOrigin::*; -pub use self::ValuePairs::*; -pub use crate::ty::IntVarValue; - -use crate::infer::canonical::{Canonical, CanonicalVarValues}; -use crate::infer::unify_key::{ConstVarValue, ConstVariableValue}; -use crate::middle::free_region::RegionRelations; -use crate::middle::lang_items; -use crate::middle::region; -use crate::session::config::BorrowckMode; -use crate::traits::{self, ObligationCause, PredicateObligations, TraitEngine}; -use crate::ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric}; -use crate::ty::fold::{TypeFoldable, TypeFolder}; -use crate::ty::relate::RelateResult; -use crate::ty::subst::{GenericArg, InternalSubsts, SubstsRef}; -use crate::ty::{self, GenericParamDefKind, InferConst, Ty, TyCtxt}; -use crate::ty::{ConstVid, FloatVid, IntVid, TyVid}; +pub mod canonical; +pub mod unify_key; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use crate::ty::Region; +use crate::ty::Ty; use rustc_data_structures::sync::Lrc; -use rustc_data_structures::unify as ut; -use rustc_errors::DiagnosticBuilder; -use rustc_hir as hir; use rustc_hir::def_id::DefId; -use rustc_span::symbol::Symbol; use rustc_span::Span; -use std::cell::{Cell, Ref, RefCell}; -use std::collections::BTreeMap; -use std::fmt; -use syntax::ast; - -use self::combine::CombineFields; -use self::lexical_region_resolve::LexicalRegionResolutions; -use self::outlives::env::OutlivesEnvironment; -use self::region_constraints::{GenericKind, RegionConstraintData, VarInfos, VerifyBound}; -use self::region_constraints::{RegionConstraintCollector, RegionSnapshot}; -use self::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use self::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType}; - -pub mod at; -pub mod canonical; -mod combine; -mod equate; -pub mod error_reporting; -mod freshen; -mod fudge; -mod glb; -mod higher_ranked; -pub mod lattice; -mod lexical_region_resolve; -mod lub; -pub mod nll_relate; -pub mod opaque_types; -pub mod outlives; -pub mod region_constraints; -pub mod resolve; -mod sub; -pub mod type_variable; -mod types; -pub mod unify_key; - -#[must_use] -#[derive(Debug)] -pub struct InferOk<'tcx, T> { - pub value: T, - pub obligations: PredicateObligations<'tcx>, -} -pub type InferResult<'tcx, T> = Result<InferOk<'tcx, T>, TypeError<'tcx>>; - -pub type Bound<T> = Option<T>; -pub type UnitResult<'tcx> = RelateResult<'tcx, ()>; // "unify result" -pub type FixupResult<'tcx, T> = Result<T, FixupError<'tcx>>; // "fixup result" - -/// A flag that is used to suppress region errors. This is normally -/// false, but sometimes -- when we are doing region checks that the -/// NLL borrow checker will also do -- it might be set to true. -#[derive(Copy, Clone, Default, Debug)] -pub struct SuppressRegionErrors { - suppressed: bool, -} - -impl SuppressRegionErrors { - pub fn suppressed(self) -> bool { - self.suppressed - } - - /// Indicates that the MIR borrowck will repeat these region - /// checks, so we should ignore errors if NLL is (unconditionally) - /// enabled. - pub fn when_nll_is_enabled(tcx: TyCtxt<'_>) -> Self { - // FIXME(Centril): Once we actually remove `::Migrate` also make - // this always `true` and then proceed to eliminate the dead code. - match tcx.borrowck_mode() { - // If we're on Migrate mode, report AST region errors - BorrowckMode::Migrate => SuppressRegionErrors { suppressed: false }, - - // If we're on MIR, don't report AST region errors as they should be reported by NLL - BorrowckMode::Mir => SuppressRegionErrors { suppressed: true }, - } - } -} - -/// This type contains all the things within `InferCtxt` that sit within a -/// `RefCell` and are involved with taking/rolling back snapshots. Snapshot -/// operations are hot enough that we want only one call to `borrow_mut` per -/// call to `start_snapshot` and `rollback_to`. -pub struct InferCtxtInner<'tcx> { - /// Cache for projections. This cache is snapshotted along with the infcx. - /// - /// Public so that `traits::project` can use it. - pub projection_cache: traits::ProjectionCache<'tcx>, - - /// We instantiate `UnificationTable` with `bounds<Ty>` because the types - /// that might instantiate a general type variable have an order, - /// represented by its upper and lower bounds. - type_variables: type_variable::TypeVariableTable<'tcx>, - - /// Map from const parameter variable to the kind of const it represents. - const_unification_table: ut::UnificationTable<ut::InPlace<ty::ConstVid<'tcx>>>, - - /// Map from integral variable to the kind of integer it represents. - int_unification_table: ut::UnificationTable<ut::InPlace<ty::IntVid>>, - - /// Map from floating variable to the kind of float it represents. - float_unification_table: ut::UnificationTable<ut::InPlace<ty::FloatVid>>, - - /// Tracks the set of region variables and the constraints between them. - /// This is initially `Some(_)` but when - /// `resolve_regions_and_report_errors` is invoked, this gets set to `None` - /// -- further attempts to perform unification, etc., may fail if new - /// region constraints would've been added. - region_constraints: Option<RegionConstraintCollector<'tcx>>, - - /// A set of constraints that regionck must validate. Each - /// constraint has the form `T:'a`, meaning "some type `T` must - /// outlive the lifetime 'a". These constraints derive from - /// instantiated type parameters. So if you had a struct defined - /// like - /// - /// struct Foo<T:'static> { ... } - /// - /// then in some expression `let x = Foo { ... }` it will - /// instantiate the type parameter `T` with a fresh type `$0`. At - /// the same time, it will record a region obligation of - /// `$0:'static`. This will get checked later by regionck. (We - /// can't generally check these things right away because we have - /// to wait until types are resolved.) - /// - /// These are stored in a map keyed to the id of the innermost - /// enclosing fn body / static initializer expression. This is - /// because the location where the obligation was incurred can be - /// relevant with respect to which sublifetime assumptions are in - /// place. The reason that we store under the fn-id, and not - /// something more fine-grained, is so that it is easier for - /// regionck to be sure that it has found *all* the region - /// obligations (otherwise, it's easy to fail to walk to a - /// particular node-id). - /// - /// Before running `resolve_regions_and_report_errors`, the creator - /// of the inference context is expected to invoke - /// `process_region_obligations` (defined in `self::region_obligations`) - /// for each body-id in this map, which will process the - /// obligations within. This is expected to be done 'late enough' - /// that all type inference variables have been bound and so forth. - pub region_obligations: Vec<(hir::HirId, RegionObligation<'tcx>)>, -} - -impl<'tcx> InferCtxtInner<'tcx> { - fn new() -> InferCtxtInner<'tcx> { - InferCtxtInner { - projection_cache: Default::default(), - type_variables: type_variable::TypeVariableTable::new(), - const_unification_table: ut::UnificationTable::new(), - int_unification_table: ut::UnificationTable::new(), - float_unification_table: ut::UnificationTable::new(), - region_constraints: Some(RegionConstraintCollector::new()), - region_obligations: vec![], - } - } - - pub fn unwrap_region_constraints(&mut self) -> &mut RegionConstraintCollector<'tcx> { - self.region_constraints.as_mut().expect("region constraints already solved") - } -} - -pub struct InferCtxt<'a, 'tcx> { - pub tcx: TyCtxt<'tcx>, - - /// During type-checking/inference of a body, `in_progress_tables` - /// contains a reference to the tables being built up, which are - /// used for reading closure kinds/signatures as they are inferred, - /// and for error reporting logic to read arbitrary node types. - pub in_progress_tables: Option<&'a RefCell<ty::TypeckTables<'tcx>>>, - - pub inner: RefCell<InferCtxtInner<'tcx>>, - - /// If set, this flag causes us to skip the 'leak check' during - /// higher-ranked subtyping operations. This flag is a temporary one used - /// to manage the removal of the leak-check: for the time being, we still run the - /// leak-check, but we issue warnings. This flag can only be set to true - /// when entering a snapshot. - skip_leak_check: Cell<bool>, - - /// Once region inference is done, the values for each variable. - lexical_region_resolutions: RefCell<Option<LexicalRegionResolutions<'tcx>>>, - - /// Caches the results of trait selection. This cache is used - /// for things that have to do with the parameters in scope. - pub selection_cache: traits::SelectionCache<'tcx>, - - /// Caches the results of trait evaluation. - pub evaluation_cache: traits::EvaluationCache<'tcx>, - - /// the set of predicates on which errors have been reported, to - /// avoid reporting the same error twice. - pub reported_trait_errors: RefCell<FxHashMap<Span, Vec<ty::Predicate<'tcx>>>>, - - pub reported_closure_mismatch: RefCell<FxHashSet<(Span, Option<Span>)>>, - - /// When an error occurs, we want to avoid reporting "derived" - /// errors that are due to this original failure. Normally, we - /// handle this with the `err_count_on_creation` count, which - /// basically just tracks how many errors were reported when we - /// started type-checking a fn and checks to see if any new errors - /// have been reported since then. Not great, but it works. - /// - /// However, when errors originated in other passes -- notably - /// resolve -- this heuristic breaks down. Therefore, we have this - /// auxiliary flag that one can set whenever one creates a - /// type-error that is due to an error in a prior pass. - /// - /// Don't read this flag directly, call `is_tainted_by_errors()` - /// and `set_tainted_by_errors()`. - tainted_by_errors_flag: Cell<bool>, - - /// Track how many errors were reported when this infcx is created. - /// If the number of errors increases, that's also a sign (line - /// `tained_by_errors`) to avoid reporting certain kinds of errors. - // FIXME(matthewjasper) Merge into `tainted_by_errors_flag` - err_count_on_creation: usize, - - /// This flag is true while there is an active snapshot. - in_snapshot: Cell<bool>, - - /// What is the innermost universe we have created? Starts out as - /// `UniverseIndex::root()` but grows from there as we enter - /// universal quantifiers. - /// - /// N.B., at present, we exclude the universal quantifiers on the - /// item we are type-checking, and just consider those names as - /// part of the root universe. So this would only get incremented - /// when we enter into a higher-ranked (`for<..>`) type or trait - /// bound. - universe: Cell<ty::UniverseIndex>, -} - -/// A map returned by `replace_bound_vars_with_placeholders()` -/// indicating the placeholder region that each late-bound region was -/// replaced with. -pub type PlaceholderMap<'tcx> = BTreeMap<ty::BoundRegion, ty::Region<'tcx>>; - -/// See the `error_reporting` module for more details. -#[derive(Clone, Debug, PartialEq, Eq, TypeFoldable)] -pub enum ValuePairs<'tcx> { - Types(ExpectedFound<Ty<'tcx>>), - Regions(ExpectedFound<ty::Region<'tcx>>), - Consts(ExpectedFound<&'tcx ty::Const<'tcx>>), - TraitRefs(ExpectedFound<ty::TraitRef<'tcx>>), - PolyTraitRefs(ExpectedFound<ty::PolyTraitRef<'tcx>>), -} - -/// The trace designates the path through inference that we took to -/// encounter an error or subtyping constraint. -/// -/// See the `error_reporting` module for more details. -#[derive(Clone, Debug)] -pub struct TypeTrace<'tcx> { - cause: ObligationCause<'tcx>, - values: ValuePairs<'tcx>, -} - -/// The origin of a `r1 <= r2` constraint. -/// -/// See `error_reporting` module for more details -#[derive(Clone, Debug)] -pub enum SubregionOrigin<'tcx> { - /// Arose from a subtyping relation - Subtype(Box<TypeTrace<'tcx>>), - - /// Stack-allocated closures cannot outlive innermost loop - /// or function so as to ensure we only require finite stack - InfStackClosure(Span), - - /// Invocation of closure must be within its lifetime - InvokeClosure(Span), - - /// Dereference of reference must be within its lifetime - DerefPointer(Span), - - /// Closure bound must not outlive captured variables - ClosureCapture(Span, hir::HirId), - - /// Index into slice must be within its lifetime - IndexSlice(Span), - - /// When casting `&'a T` to an `&'b Trait` object, - /// relating `'a` to `'b` - RelateObjectBound(Span), - - /// Some type parameter was instantiated with the given type, - /// and that type must outlive some region. - RelateParamBound(Span, Ty<'tcx>), - - /// The given region parameter was instantiated with a region - /// that must outlive some other region. - RelateRegionParamBound(Span), - - /// A bound placed on type parameters that states that must outlive - /// the moment of their instantiation. - RelateDefaultParamBound(Span, Ty<'tcx>), - - /// Creating a pointer `b` to contents of another reference - Reborrow(Span), - - /// Creating a pointer `b` to contents of an upvar - ReborrowUpvar(Span, ty::UpvarId), - /// Data with type `Ty<'tcx>` was borrowed - DataBorrowed(Ty<'tcx>, Span), - - /// (&'a &'b T) where a >= b - ReferenceOutlivesReferent(Ty<'tcx>, Span), - - /// Type or region parameters must be in scope. - ParameterInScope(ParameterOrigin, Span), - - /// The type T of an expression E must outlive the lifetime for E. - ExprTypeIsNotInScope(Ty<'tcx>, Span), - - /// A `ref b` whose region does not enclose the decl site - BindingTypeIsNotValidAtDecl(Span), - - /// Regions appearing in a method receiver must outlive method call - CallRcvr(Span), - - /// Regions appearing in a function argument must outlive func call - CallArg(Span), - - /// Region in return type of invoked fn must enclose call - CallReturn(Span), - - /// Operands must be in scope - Operand(Span), - - /// Region resulting from a `&` expr must enclose the `&` expr - AddrOf(Span), - - /// An auto-borrow that does not enclose the expr where it occurs - AutoBorrow(Span), - - /// Region constraint arriving from destructor safety - SafeDestructor(Span), - - /// Comparing the signature and requirements of an impl method against - /// the containing trait. - CompareImplMethodObligation { - span: Span, - item_name: ast::Name, - impl_item_def_id: DefId, - trait_item_def_id: DefId, - }, -} - -// `SubregionOrigin` is used a lot. Make sure it doesn't unintentionally get bigger. -#[cfg(target_arch = "x86_64")] -static_assert_size!(SubregionOrigin<'_>, 32); - -/// Places that type/region parameters can appear. -#[derive(Clone, Copy, Debug)] -pub enum ParameterOrigin { - Path, // foo::bar - MethodCall, // foo.bar() <-- parameters on impl providing bar() - OverloadedOperator, // a + b when overloaded - OverloadedDeref, // *a when overloaded -} - -/// Times when we replace late-bound regions with variables: -#[derive(Clone, Copy, Debug)] -pub enum LateBoundRegionConversionTime { - /// when a fn is called - FnCall, - - /// when two higher-ranked types are compared - HigherRankedType, - - /// when projecting an associated type - AssocTypeProjection(DefId), -} - -/// Reasons to create a region inference variable +/// Requires that `region` must be equal to one of the regions in `choice_regions`. +/// We often denote this using the syntax: /// -/// See `error_reporting` module for more details -#[derive(Copy, Clone, Debug)] -pub enum RegionVariableOrigin { - /// Region variables created for ill-categorized reasons, - /// mostly indicates places in need of refactoring - MiscVariable(Span), - - /// Regions created by a `&P` or `[...]` pattern - PatternRegion(Span), - - /// Regions created by `&` operator - AddrOfRegion(Span), - - /// Regions created as part of an autoref of a method receiver - Autoref(Span), - - /// Regions created as part of an automatic coercion - Coercion(Span), - - /// Region variables created as the values for early-bound regions - EarlyBoundRegion(Span, Symbol), - - /// Region variables created for bound regions - /// in a function or method that is called - LateBoundRegion(Span, ty::BoundRegion, LateBoundRegionConversionTime), - - UpvarRegion(ty::UpvarId, Span), - - BoundRegionInCoherence(ast::Name), - - /// This origin is used for the inference variables that we create - /// during NLL region processing. - NLL(NLLRegionVariableOrigin), -} - -#[derive(Copy, Clone, Debug)] -pub enum NLLRegionVariableOrigin { - /// During NLL region processing, we create variables for free - /// regions that we encounter in the function signature and - /// elsewhere. This origin indices we've got one of those. - FreeRegion, - - /// "Universal" instantiation of a higher-ranked region (e.g., - /// from a `for<'a> T` binder). Meant to represent "any region". - Placeholder(ty::PlaceholderRegion), - - Existential { - /// If this is true, then this variable was created to represent a lifetime - /// bound in a `for` binder. For example, it might have been created to - /// represent the lifetime `'a` in a type like `for<'a> fn(&'a u32)`. - /// Such variables are created when we are trying to figure out if there - /// is any valid instantiation of `'a` that could fit into some scenario. - /// - /// This is used to inform error reporting: in the case that we are trying to - /// determine whether there is any valid instantiation of a `'a` variable that meets - /// some constraint C, we want to blame the "source" of that `for` type, - /// rather than blaming the source of the constraint C. - from_forall: bool, - }, -} - -impl NLLRegionVariableOrigin { - pub fn is_universal(self) -> bool { - match self { - NLLRegionVariableOrigin::FreeRegion => true, - NLLRegionVariableOrigin::Placeholder(..) => true, - NLLRegionVariableOrigin::Existential { .. } => false, - } - } - - pub fn is_existential(self) -> bool { - !self.is_universal() - } -} - -#[derive(Copy, Clone, Debug)] -pub enum FixupError<'tcx> { - UnresolvedIntTy(IntVid), - UnresolvedFloatTy(FloatVid), - UnresolvedTy(TyVid), - UnresolvedConst(ConstVid<'tcx>), -} - -/// See the `region_obligations` field for more information. -#[derive(Clone)] -pub struct RegionObligation<'tcx> { - pub sub_region: ty::Region<'tcx>, - pub sup_type: Ty<'tcx>, - pub origin: SubregionOrigin<'tcx>, -} - -impl<'tcx> fmt::Display for FixupError<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - use self::FixupError::*; - - match *self { - UnresolvedIntTy(_) => write!( - f, - "cannot determine the type of this integer; \ - add a suffix to specify the type explicitly" - ), - UnresolvedFloatTy(_) => write!( - f, - "cannot determine the type of this number; \ - add a suffix to specify the type explicitly" - ), - UnresolvedTy(_) => write!(f, "unconstrained type"), - UnresolvedConst(_) => write!(f, "unconstrained const value"), - } - } -} - -/// Helper type of a temporary returned by `tcx.infer_ctxt()`. -/// Necessary because we can't write the following bound: -/// `F: for<'b, 'tcx> where 'tcx FnOnce(InferCtxt<'b, 'tcx>)`. -pub struct InferCtxtBuilder<'tcx> { - global_tcx: TyCtxt<'tcx>, - fresh_tables: Option<RefCell<ty::TypeckTables<'tcx>>>, -} - -impl TyCtxt<'tcx> { - pub fn infer_ctxt(self) -> InferCtxtBuilder<'tcx> { - InferCtxtBuilder { global_tcx: self, fresh_tables: None } - } -} - -impl<'tcx> InferCtxtBuilder<'tcx> { - /// Used only by `rustc_typeck` during body type-checking/inference, - /// will initialize `in_progress_tables` with fresh `TypeckTables`. - pub fn with_fresh_in_progress_tables(mut self, table_owner: DefId) -> Self { - self.fresh_tables = Some(RefCell::new(ty::TypeckTables::empty(Some(table_owner)))); - self - } - - /// Given a canonical value `C` as a starting point, create an - /// inference context that contains each of the bound values - /// within instantiated as a fresh variable. The `f` closure is - /// invoked with the new infcx, along with the instantiated value - /// `V` and a substitution `S`. This substitution `S` maps from - /// the bound values in `C` to their instantiated values in `V` - /// (in other words, `S(C) = V`). - pub fn enter_with_canonical<T, R>( - &mut self, - span: Span, - canonical: &Canonical<'tcx, T>, - f: impl for<'a> FnOnce(InferCtxt<'a, 'tcx>, T, CanonicalVarValues<'tcx>) -> R, - ) -> R - where - T: TypeFoldable<'tcx>, - { - self.enter(|infcx| { - let (value, subst) = - infcx.instantiate_canonical_with_fresh_inference_vars(span, canonical); - f(infcx, value, subst) - }) - } - - pub fn enter<R>(&mut self, f: impl for<'a> FnOnce(InferCtxt<'a, 'tcx>) -> R) -> R { - let InferCtxtBuilder { global_tcx, ref fresh_tables } = *self; - let in_progress_tables = fresh_tables.as_ref(); - global_tcx.enter_local(|tcx| { - f(InferCtxt { - tcx, - in_progress_tables, - inner: RefCell::new(InferCtxtInner::new()), - lexical_region_resolutions: RefCell::new(None), - selection_cache: Default::default(), - evaluation_cache: Default::default(), - reported_trait_errors: Default::default(), - reported_closure_mismatch: Default::default(), - tainted_by_errors_flag: Cell::new(false), - err_count_on_creation: tcx.sess.err_count(), - in_snapshot: Cell::new(false), - skip_leak_check: Cell::new(false), - universe: Cell::new(ty::UniverseIndex::ROOT), - }) - }) - } -} - -impl<'tcx, T> InferOk<'tcx, T> { - pub fn unit(self) -> InferOk<'tcx, ()> { - InferOk { value: (), obligations: self.obligations } - } - - /// Extracts `value`, registering any obligations into `fulfill_cx`. - pub fn into_value_registering_obligations( - self, - infcx: &InferCtxt<'_, 'tcx>, - fulfill_cx: &mut dyn TraitEngine<'tcx>, - ) -> T { - let InferOk { value, obligations } = self; - for obligation in obligations { - fulfill_cx.register_predicate_obligation(infcx, obligation); - } - value - } -} - -impl<'tcx> InferOk<'tcx, ()> { - pub fn into_obligations(self) -> PredicateObligations<'tcx> { - self.obligations - } -} - -#[must_use = "once you start a snapshot, you should always consume it"] -pub struct CombinedSnapshot<'a, 'tcx> { - projection_cache_snapshot: traits::ProjectionCacheSnapshot, - type_snapshot: type_variable::Snapshot<'tcx>, - const_snapshot: ut::Snapshot<ut::InPlace<ty::ConstVid<'tcx>>>, - int_snapshot: ut::Snapshot<ut::InPlace<ty::IntVid>>, - float_snapshot: ut::Snapshot<ut::InPlace<ty::FloatVid>>, - region_constraints_snapshot: RegionSnapshot, - region_obligations_snapshot: usize, - universe: ty::UniverseIndex, - was_in_snapshot: bool, - was_skip_leak_check: bool, - _in_progress_tables: Option<Ref<'a, ty::TypeckTables<'tcx>>>, -} - -impl<'a, 'tcx> InferCtxt<'a, 'tcx> { - pub fn is_in_snapshot(&self) -> bool { - self.in_snapshot.get() - } +/// ``` +/// 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, - pub fn freshen<T: TypeFoldable<'tcx>>(&self, t: T) -> T { - t.fold_with(&mut self.freshener()) - } + /// The span where the hidden type was instantiated. + pub definition_span: Span, - pub fn type_var_diverges(&'a self, ty: Ty<'_>) -> bool { - match ty.kind { - ty::Infer(ty::TyVar(vid)) => self.inner.borrow().type_variables.var_diverges(vid), - _ => false, - } - } + /// The hidden type in which `member_region` appears: used for error reporting. + pub hidden_ty: Ty<'tcx>, - pub fn freshener<'b>(&'b self) -> TypeFreshener<'b, 'tcx> { - freshen::TypeFreshener::new(self) - } - - pub fn type_is_unconstrained_numeric(&'a self, ty: Ty<'_>) -> UnconstrainedNumeric { - use crate::ty::error::UnconstrainedNumeric::Neither; - use crate::ty::error::UnconstrainedNumeric::{UnconstrainedFloat, UnconstrainedInt}; - match ty.kind { - ty::Infer(ty::IntVar(vid)) => { - if self.inner.borrow_mut().int_unification_table.probe_value(vid).is_some() { - Neither - } else { - UnconstrainedInt - } - } - ty::Infer(ty::FloatVar(vid)) => { - if self.inner.borrow_mut().float_unification_table.probe_value(vid).is_some() { - Neither - } else { - UnconstrainedFloat - } - } - _ => Neither, - } - } - - pub fn unsolved_variables(&self) -> Vec<Ty<'tcx>> { - let mut inner = self.inner.borrow_mut(); - // FIXME(const_generics): should there be an equivalent function for const variables? - - let mut vars: Vec<Ty<'_>> = inner - .type_variables - .unsolved_variables() - .into_iter() - .map(|t| self.tcx.mk_ty_var(t)) - .collect(); - vars.extend( - (0..inner.int_unification_table.len()) - .map(|i| ty::IntVid { index: i as u32 }) - .filter(|&vid| inner.int_unification_table.probe_value(vid).is_none()) - .map(|v| self.tcx.mk_int_var(v)), - ); - vars.extend( - (0..inner.float_unification_table.len()) - .map(|i| ty::FloatVid { index: i as u32 }) - .filter(|&vid| inner.float_unification_table.probe_value(vid).is_none()) - .map(|v| self.tcx.mk_float_var(v)), - ); - vars - } - - fn combine_fields( - &'a self, - trace: TypeTrace<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ) -> CombineFields<'a, 'tcx> { - CombineFields { - infcx: self, - trace, - cause: None, - param_env, - obligations: PredicateObligations::new(), - } - } - - /// Clear the "currently in a snapshot" flag, invoke the closure, - /// then restore the flag to its original value. This flag is a - /// debugging measure designed to detect cases where we start a - /// snapshot, create type variables, and register obligations - /// which may involve those type variables in the fulfillment cx, - /// potentially leaving "dangling type variables" behind. - /// In such cases, an assertion will fail when attempting to - /// register obligations, within a snapshot. Very useful, much - /// better than grovelling through megabytes of `RUSTC_LOG` output. - /// - /// HOWEVER, in some cases the flag is unhelpful. In particular, we - /// sometimes create a "mini-fulfilment-cx" in which we enroll - /// obligations. As long as this fulfillment cx is fully drained - /// before we return, this is not a problem, as there won't be any - /// escaping obligations in the main cx. In those cases, you can - /// use this function. - pub fn save_and_restore_in_snapshot_flag<F, R>(&self, func: F) -> R - where - F: FnOnce(&Self) -> R, - { - let flag = self.in_snapshot.get(); - self.in_snapshot.set(false); - let result = func(self); - self.in_snapshot.set(flag); - result - } - - fn start_snapshot(&self) -> CombinedSnapshot<'a, 'tcx> { - debug!("start_snapshot()"); - - let in_snapshot = self.in_snapshot.get(); - self.in_snapshot.set(true); - - let mut inner = self.inner.borrow_mut(); - CombinedSnapshot { - projection_cache_snapshot: inner.projection_cache.snapshot(), - type_snapshot: inner.type_variables.snapshot(), - const_snapshot: inner.const_unification_table.snapshot(), - int_snapshot: inner.int_unification_table.snapshot(), - float_snapshot: inner.float_unification_table.snapshot(), - region_constraints_snapshot: inner.unwrap_region_constraints().start_snapshot(), - region_obligations_snapshot: inner.region_obligations.len(), - universe: self.universe(), - was_in_snapshot: in_snapshot, - was_skip_leak_check: self.skip_leak_check.get(), - // Borrow tables "in progress" (i.e., during typeck) - // to ban writes from within a snapshot to them. - _in_progress_tables: self.in_progress_tables.map(|tables| tables.borrow()), - } - } - - fn rollback_to(&self, cause: &str, snapshot: CombinedSnapshot<'a, 'tcx>) { - debug!("rollback_to(cause={})", cause); - let CombinedSnapshot { - projection_cache_snapshot, - type_snapshot, - const_snapshot, - int_snapshot, - float_snapshot, - region_constraints_snapshot, - region_obligations_snapshot, - universe, - was_in_snapshot, - was_skip_leak_check, - _in_progress_tables, - } = snapshot; - - self.in_snapshot.set(was_in_snapshot); - self.universe.set(universe); - self.skip_leak_check.set(was_skip_leak_check); - - let mut inner = self.inner.borrow_mut(); - inner.projection_cache.rollback_to(projection_cache_snapshot); - inner.type_variables.rollback_to(type_snapshot); - inner.const_unification_table.rollback_to(const_snapshot); - inner.int_unification_table.rollback_to(int_snapshot); - inner.float_unification_table.rollback_to(float_snapshot); - inner.unwrap_region_constraints().rollback_to(region_constraints_snapshot); - inner.region_obligations.truncate(region_obligations_snapshot); - } - - fn commit_from(&self, snapshot: CombinedSnapshot<'a, 'tcx>) { - debug!("commit_from()"); - let CombinedSnapshot { - projection_cache_snapshot, - type_snapshot, - const_snapshot, - int_snapshot, - float_snapshot, - region_constraints_snapshot, - region_obligations_snapshot: _, - universe: _, - was_in_snapshot, - was_skip_leak_check, - _in_progress_tables, - } = snapshot; - - self.in_snapshot.set(was_in_snapshot); - self.skip_leak_check.set(was_skip_leak_check); - - let mut inner = self.inner.borrow_mut(); - inner.projection_cache.commit(projection_cache_snapshot); - inner.type_variables.commit(type_snapshot); - inner.const_unification_table.commit(const_snapshot); - inner.int_unification_table.commit(int_snapshot); - inner.float_unification_table.commit(float_snapshot); - inner.unwrap_region_constraints().commit(region_constraints_snapshot); - } - - /// Executes `f` and commit the bindings. - pub fn commit_unconditionally<R, F>(&self, f: F) -> R - where - F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> R, - { - debug!("commit_unconditionally()"); - let snapshot = self.start_snapshot(); - let r = f(&snapshot); - self.commit_from(snapshot); - r - } - - /// Execute `f` and commit the bindings if closure `f` returns `Ok(_)`. - pub fn commit_if_ok<T, E, F>(&self, f: F) -> Result<T, E> - where - F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> Result<T, E>, - { - debug!("commit_if_ok()"); - let snapshot = self.start_snapshot(); - let r = f(&snapshot); - debug!("commit_if_ok() -- r.is_ok() = {}", r.is_ok()); - match r { - Ok(_) => { - self.commit_from(snapshot); - } - Err(_) => { - self.rollback_to("commit_if_ok -- error", snapshot); - } - } - r - } - - /// Execute `f` then unroll any bindings it creates. - pub fn probe<R, F>(&self, f: F) -> R - where - F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> R, - { - debug!("probe()"); - let snapshot = self.start_snapshot(); - let r = f(&snapshot); - self.rollback_to("probe", snapshot); - r - } - - /// If `should_skip` is true, then execute `f` then unroll any bindings it creates. - pub fn probe_maybe_skip_leak_check<R, F>(&self, should_skip: bool, f: F) -> R - where - F: FnOnce(&CombinedSnapshot<'a, 'tcx>) -> R, - { - debug!("probe()"); - let snapshot = self.start_snapshot(); - let skip_leak_check = should_skip || self.skip_leak_check.get(); - self.skip_leak_check.set(skip_leak_check); - let r = f(&snapshot); - self.rollback_to("probe", snapshot); - r - } - - /// Scan the constraints produced since `snapshot` began and returns: - /// - /// - `None` -- if none of them involve "region outlives" constraints - /// - `Some(true)` -- if there are `'a: 'b` constraints where `'a` or `'b` is a placeholder - /// - `Some(false)` -- if there are `'a: 'b` constraints but none involve placeholders - pub fn region_constraints_added_in_snapshot( - &self, - snapshot: &CombinedSnapshot<'a, 'tcx>, - ) -> Option<bool> { - self.inner - .borrow_mut() - .unwrap_region_constraints() - .region_constraints_added_in_snapshot(&snapshot.region_constraints_snapshot) - } - - pub fn add_given(&self, sub: ty::Region<'tcx>, sup: ty::RegionVid) { - self.inner.borrow_mut().unwrap_region_constraints().add_given(sub, sup); - } - - pub fn can_sub<T>(&self, param_env: ty::ParamEnv<'tcx>, a: T, b: T) -> UnitResult<'tcx> - where - T: at::ToTrace<'tcx>, - { - let origin = &ObligationCause::dummy(); - self.probe(|_| { - self.at(origin, param_env).sub(a, b).map(|InferOk { obligations: _, .. }| { - // Ignore obligations, since we are unrolling - // everything anyway. - }) - }) - } - - pub fn can_eq<T>(&self, param_env: ty::ParamEnv<'tcx>, a: T, b: T) -> UnitResult<'tcx> - where - T: at::ToTrace<'tcx>, - { - let origin = &ObligationCause::dummy(); - self.probe(|_| { - self.at(origin, param_env).eq(a, b).map(|InferOk { obligations: _, .. }| { - // Ignore obligations, since we are unrolling - // everything anyway. - }) - }) - } - - pub fn sub_regions( - &self, - origin: SubregionOrigin<'tcx>, - a: ty::Region<'tcx>, - b: ty::Region<'tcx>, - ) { - debug!("sub_regions({:?} <: {:?})", a, b); - self.inner.borrow_mut().unwrap_region_constraints().make_subregion(origin, a, b); - } - - /// Require that the region `r` be equal to one of the regions in - /// the set `regions`. - pub fn member_constraint( - &self, - opaque_type_def_id: DefId, - definition_span: Span, - hidden_ty: Ty<'tcx>, - region: ty::Region<'tcx>, - in_regions: &Lrc<Vec<ty::Region<'tcx>>>, - ) { - debug!("member_constraint({:?} <: {:?})", region, in_regions); - self.inner.borrow_mut().unwrap_region_constraints().member_constraint( - opaque_type_def_id, - definition_span, - hidden_ty, - region, - in_regions, - ); - } - - pub fn subtype_predicate( - &self, - cause: &ObligationCause<'tcx>, - param_env: ty::ParamEnv<'tcx>, - predicate: &ty::PolySubtypePredicate<'tcx>, - ) -> Option<InferResult<'tcx, ()>> { - // Subtle: it's ok to skip the binder here and resolve because - // `shallow_resolve` just ignores anything that is not a type - // variable, and because type variable's can't (at present, at - // least) capture any of the things bound by this binder. - // - // NOTE(nmatsakis): really, there is no *particular* reason to do this - // `shallow_resolve` here except as a micro-optimization. - // Naturally I could not resist. - let two_unbound_type_vars = { - let a = self.shallow_resolve(predicate.skip_binder().a); - let b = self.shallow_resolve(predicate.skip_binder().b); - a.is_ty_var() && b.is_ty_var() - }; - - if two_unbound_type_vars { - // Two unbound type variables? Can't make progress. - return None; - } - - Some(self.commit_if_ok(|snapshot| { - let (ty::SubtypePredicate { a_is_expected, a, b }, placeholder_map) = - self.replace_bound_vars_with_placeholders(predicate); - - let ok = self.at(cause, param_env).sub_exp(a_is_expected, a, b)?; - - self.leak_check(false, &placeholder_map, snapshot)?; - - Ok(ok.unit()) - })) - } - - pub fn region_outlives_predicate( - &self, - cause: &traits::ObligationCause<'tcx>, - predicate: &ty::PolyRegionOutlivesPredicate<'tcx>, - ) -> UnitResult<'tcx> { - self.commit_if_ok(|snapshot| { - let (ty::OutlivesPredicate(r_a, r_b), placeholder_map) = - self.replace_bound_vars_with_placeholders(predicate); - let origin = SubregionOrigin::from_obligation_cause(cause, || { - RelateRegionParamBound(cause.span) - }); - self.sub_regions(origin, r_b, r_a); // `b : a` ==> `a <= b` - self.leak_check(false, &placeholder_map, snapshot)?; - Ok(()) - }) - } - - pub fn next_ty_var_id(&self, diverging: bool, origin: TypeVariableOrigin) -> TyVid { - self.inner.borrow_mut().type_variables.new_var(self.universe(), diverging, origin) - } - - pub fn next_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> { - self.tcx.mk_ty_var(self.next_ty_var_id(false, origin)) - } - - pub fn next_ty_var_in_universe( - &self, - origin: TypeVariableOrigin, - universe: ty::UniverseIndex, - ) -> Ty<'tcx> { - let vid = self.inner.borrow_mut().type_variables.new_var(universe, false, origin); - self.tcx.mk_ty_var(vid) - } - - pub fn next_diverging_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> { - self.tcx.mk_ty_var(self.next_ty_var_id(true, origin)) - } - - pub fn next_const_var( - &self, - ty: Ty<'tcx>, - origin: ConstVariableOrigin, - ) -> &'tcx ty::Const<'tcx> { - self.tcx.mk_const_var(self.next_const_var_id(origin), ty) - } - - pub fn next_const_var_in_universe( - &self, - ty: Ty<'tcx>, - origin: ConstVariableOrigin, - universe: ty::UniverseIndex, - ) -> &'tcx ty::Const<'tcx> { - let vid = self - .inner - .borrow_mut() - .const_unification_table - .new_key(ConstVarValue { origin, val: ConstVariableValue::Unknown { universe } }); - self.tcx.mk_const_var(vid, ty) - } - - pub fn next_const_var_id(&self, origin: ConstVariableOrigin) -> ConstVid<'tcx> { - self.inner.borrow_mut().const_unification_table.new_key(ConstVarValue { - origin, - val: ConstVariableValue::Unknown { universe: self.universe() }, - }) - } - - fn next_int_var_id(&self) -> IntVid { - self.inner.borrow_mut().int_unification_table.new_key(None) - } - - pub fn next_int_var(&self) -> Ty<'tcx> { - self.tcx.mk_int_var(self.next_int_var_id()) - } - - fn next_float_var_id(&self) -> FloatVid { - self.inner.borrow_mut().float_unification_table.new_key(None) - } - - pub fn next_float_var(&self) -> Ty<'tcx> { - self.tcx.mk_float_var(self.next_float_var_id()) - } - - /// Creates a fresh region variable with the next available index. - /// The variable will be created in the maximum universe created - /// thus far, allowing it to name any region created thus far. - pub fn next_region_var(&self, origin: RegionVariableOrigin) -> ty::Region<'tcx> { - self.next_region_var_in_universe(origin, self.universe()) - } - - /// Creates a fresh region variable with the next available index - /// in the given universe; typically, you can use - /// `next_region_var` and just use the maximal universe. - pub fn next_region_var_in_universe( - &self, - origin: RegionVariableOrigin, - universe: ty::UniverseIndex, - ) -> ty::Region<'tcx> { - let region_var = - self.inner.borrow_mut().unwrap_region_constraints().new_region_var(universe, origin); - self.tcx.mk_region(ty::ReVar(region_var)) - } - - /// Return the universe that the region `r` was created in. For - /// most regions (e.g., `'static`, named regions from the user, - /// etc) this is the root universe U0. For inference variables or - /// placeholders, however, it will return the universe which which - /// they are associated. - fn universe_of_region(&self, r: ty::Region<'tcx>) -> ty::UniverseIndex { - self.inner.borrow_mut().unwrap_region_constraints().universe(r) - } - - /// Number of region variables created so far. - pub fn num_region_vars(&self) -> usize { - self.inner.borrow_mut().unwrap_region_constraints().num_region_vars() - } - - /// Just a convenient wrapper of `next_region_var` for using during NLL. - pub fn next_nll_region_var(&self, origin: NLLRegionVariableOrigin) -> ty::Region<'tcx> { - self.next_region_var(RegionVariableOrigin::NLL(origin)) - } - - /// Just a convenient wrapper of `next_region_var` for using during NLL. - pub fn next_nll_region_var_in_universe( - &self, - origin: NLLRegionVariableOrigin, - universe: ty::UniverseIndex, - ) -> ty::Region<'tcx> { - self.next_region_var_in_universe(RegionVariableOrigin::NLL(origin), universe) - } - - pub fn var_for_def(&self, span: Span, param: &ty::GenericParamDef) -> GenericArg<'tcx> { - match param.kind { - GenericParamDefKind::Lifetime => { - // Create a region inference variable for the given - // region parameter definition. - self.next_region_var(EarlyBoundRegion(span, param.name)).into() - } - GenericParamDefKind::Type { .. } => { - // Create a type inference variable for the given - // type parameter definition. The substitutions are - // for actual parameters that may be referred to by - // the default of this type parameter, if it exists. - // e.g., `struct Foo<A, B, C = (A, B)>(...);` when - // used in a path such as `Foo::<T, U>::new()` will - // use an inference variable for `C` with `[T, U]` - // as the substitutions for the default, `(T, U)`. - let ty_var_id = self.inner.borrow_mut().type_variables.new_var( - self.universe(), - false, - TypeVariableOrigin { - kind: TypeVariableOriginKind::TypeParameterDefinition( - param.name, - Some(param.def_id), - ), - span, - }, - ); - - self.tcx.mk_ty_var(ty_var_id).into() - } - GenericParamDefKind::Const { .. } => { - let origin = ConstVariableOrigin { - kind: ConstVariableOriginKind::ConstParameterDefinition(param.name), - span, - }; - let const_var_id = - self.inner.borrow_mut().const_unification_table.new_key(ConstVarValue { - origin, - val: ConstVariableValue::Unknown { universe: self.universe() }, - }); - self.tcx.mk_const_var(const_var_id, self.tcx.type_of(param.def_id)).into() - } - } - } - - /// Given a set of generics defined on a type or impl, returns a substitution mapping each - /// type/region parameter to a fresh inference variable. - pub fn fresh_substs_for_item(&self, span: Span, def_id: DefId) -> SubstsRef<'tcx> { - InternalSubsts::for_item(self.tcx, def_id, |param, _| self.var_for_def(span, param)) - } - - /// Returns `true` if errors have been reported since this infcx was - /// created. This is sometimes used as a heuristic to skip - /// reporting errors that often occur as a result of earlier - /// errors, but where it's hard to be 100% sure (e.g., unresolved - /// inference variables, regionck errors). - pub fn is_tainted_by_errors(&self) -> bool { - debug!( - "is_tainted_by_errors(err_count={}, err_count_on_creation={}, \ - tainted_by_errors_flag={})", - self.tcx.sess.err_count(), - self.err_count_on_creation, - self.tainted_by_errors_flag.get() - ); - - if self.tcx.sess.err_count() > self.err_count_on_creation { - return true; // errors reported since this infcx was made - } - self.tainted_by_errors_flag.get() - } - - /// Set the "tainted by errors" flag to true. We call this when we - /// observe an error from a prior pass. - pub fn set_tainted_by_errors(&self) { - debug!("set_tainted_by_errors()"); - self.tainted_by_errors_flag.set(true) - } - - /// Process the region constraints and report any errors that - /// result. After this, no more unification operations should be - /// done -- or the compiler will panic -- but it is legal to use - /// `resolve_vars_if_possible` as well as `fully_resolve`. - pub fn resolve_regions_and_report_errors( - &self, - region_context: DefId, - region_map: ®ion::ScopeTree, - outlives_env: &OutlivesEnvironment<'tcx>, - suppress: SuppressRegionErrors, - ) { - assert!( - self.is_tainted_by_errors() || self.inner.borrow().region_obligations.is_empty(), - "region_obligations not empty: {:#?}", - self.inner.borrow().region_obligations - ); - - let region_rels = &RegionRelations::new( - self.tcx, - region_context, - region_map, - outlives_env.free_region_map(), - ); - let (var_infos, data) = self - .inner - .borrow_mut() - .region_constraints - .take() - .expect("regions already resolved") - .into_infos_and_data(); - let (lexical_region_resolutions, errors) = - lexical_region_resolve::resolve(region_rels, var_infos, data); - - let old_value = self.lexical_region_resolutions.replace(Some(lexical_region_resolutions)); - assert!(old_value.is_none()); - - if !self.is_tainted_by_errors() { - // As a heuristic, just skip reporting region errors - // altogether if other errors have been reported while - // this infcx was in use. This is totally hokey but - // otherwise we have a hard time separating legit region - // errors from silly ones. - self.report_region_errors(region_map, &errors, suppress); - } - } - - /// Obtains (and clears) the current set of region - /// constraints. The inference context is still usable: further - /// unifications will simply add new constraints. - /// - /// This method is not meant to be used with normal lexical region - /// resolution. Rather, it is used in the NLL mode as a kind of - /// interim hack: basically we run normal type-check and generate - /// region constraints as normal, but then we take them and - /// translate them into the form that the NLL solver - /// understands. See the NLL module for mode details. - pub fn take_and_reset_region_constraints(&self) -> RegionConstraintData<'tcx> { - assert!( - self.inner.borrow().region_obligations.is_empty(), - "region_obligations not empty: {:#?}", - self.inner.borrow().region_obligations - ); - - self.inner.borrow_mut().unwrap_region_constraints().take_and_reset_data() - } - - /// Gives temporary access to the region constraint data. - #[allow(non_camel_case_types)] // bug with impl trait - pub fn with_region_constraints<R>( - &self, - op: impl FnOnce(&RegionConstraintData<'tcx>) -> R, - ) -> R { - let mut inner = self.inner.borrow_mut(); - op(inner.unwrap_region_constraints().data()) - } - - /// Takes ownership of the list of variable regions. This implies - /// that all the region constraints have already been taken, and - /// hence that `resolve_regions_and_report_errors` can never be - /// called. This is used only during NLL processing to "hand off" ownership - /// of the set of region variables into the NLL region context. - pub fn take_region_var_origins(&self) -> VarInfos { - let (var_infos, data) = self - .inner - .borrow_mut() - .region_constraints - .take() - .expect("regions already resolved") - .into_infos_and_data(); - assert!(data.is_empty()); - var_infos - } - - pub fn ty_to_string(&self, t: Ty<'tcx>) -> String { - self.resolve_vars_if_possible(&t).to_string() - } - - pub fn tys_to_string(&self, ts: &[Ty<'tcx>]) -> String { - let tstrs: Vec<String> = ts.iter().map(|t| self.ty_to_string(*t)).collect(); - format!("({})", tstrs.join(", ")) - } - - pub fn trait_ref_to_string(&self, t: &ty::TraitRef<'tcx>) -> String { - self.resolve_vars_if_possible(t).print_only_trait_path().to_string() - } - - /// If `TyVar(vid)` resolves to a type, return that type. Else, return the - /// universe index of `TyVar(vid)`. - pub fn probe_ty_var(&self, vid: TyVid) -> Result<Ty<'tcx>, ty::UniverseIndex> { - use self::type_variable::TypeVariableValue; - - match self.inner.borrow_mut().type_variables.probe(vid) { - TypeVariableValue::Known { value } => Ok(value), - TypeVariableValue::Unknown { universe } => Err(universe), - } - } - - /// Resolve any type variables found in `value` -- but only one - /// level. So, if the variable `?X` is bound to some type - /// `Foo<?Y>`, then this would return `Foo<?Y>` (but `?Y` may - /// itself be bound to a type). - /// - /// Useful when you only need to inspect the outermost level of - /// the type and don't care about nested types (or perhaps you - /// will be resolving them as well, e.g. in a loop). - pub fn shallow_resolve<T>(&self, value: T) -> T - where - T: TypeFoldable<'tcx>, - { - let mut r = ShallowResolver::new(self); - value.fold_with(&mut r) - } - - pub fn root_var(&self, var: ty::TyVid) -> ty::TyVid { - self.inner.borrow_mut().type_variables.root_var(var) - } - - /// Where possible, replaces type/const variables in - /// `value` with their final value. Note that region variables - /// are unaffected. If a type/const variable has not been unified, it - /// is left as is. This is an idempotent operation that does - /// not affect inference state in any way and so you can do it - /// at will. - pub fn resolve_vars_if_possible<T>(&self, value: &T) -> T - where - T: TypeFoldable<'tcx>, - { - if !value.needs_infer() { - return value.clone(); // Avoid duplicated subst-folding. - } - let mut r = resolve::OpportunisticVarResolver::new(self); - value.fold_with(&mut r) - } - - /// Returns the first unresolved variable contained in `T`. In the - /// process of visiting `T`, this will resolve (where possible) - /// type variables in `T`, but it never constructs the final, - /// resolved type, so it's more efficient than - /// `resolve_vars_if_possible()`. - pub fn unresolved_type_vars<T>(&self, value: &T) -> Option<(Ty<'tcx>, Option<Span>)> - where - T: TypeFoldable<'tcx>, - { - let mut r = resolve::UnresolvedTypeFinder::new(self); - value.visit_with(&mut r); - r.first_unresolved - } - - pub fn probe_const_var( - &self, - vid: ty::ConstVid<'tcx>, - ) -> Result<&'tcx ty::Const<'tcx>, ty::UniverseIndex> { - match self.inner.borrow_mut().const_unification_table.probe_value(vid).val { - ConstVariableValue::Known { value } => Ok(value), - ConstVariableValue::Unknown { universe } => Err(universe), - } - } - - pub fn fully_resolve<T: TypeFoldable<'tcx>>(&self, value: &T) -> FixupResult<'tcx, T> { - /*! - * Attempts to resolve all type/region/const variables in - * `value`. Region inference must have been run already (e.g., - * by calling `resolve_regions_and_report_errors`). If some - * variable was never unified, an `Err` results. - * - * This method is idempotent, but it not typically not invoked - * except during the writeback phase. - */ - - resolve::fully_resolve(self, value) - } - - // [Note-Type-error-reporting] - // An invariant is that anytime the expected or actual type is Error (the special - // error type, meaning that an error occurred when typechecking this expression), - // this is a derived error. The error cascaded from another error (that was already - // reported), so it's not useful to display it to the user. - // The following methods implement this logic. - // They check if either the actual or expected type is Error, and don't print the error - // in this case. The typechecker should only ever report type errors involving mismatched - // types using one of these methods, and should not call span_err directly for such - // errors. - - pub fn type_error_struct_with_diag<M>( - &self, - sp: Span, - mk_diag: M, - actual_ty: Ty<'tcx>, - ) -> DiagnosticBuilder<'tcx> - where - M: FnOnce(String) -> DiagnosticBuilder<'tcx>, - { - let actual_ty = self.resolve_vars_if_possible(&actual_ty); - debug!("type_error_struct_with_diag({:?}, {:?})", sp, actual_ty); - - // Don't report an error if actual type is `Error`. - if actual_ty.references_error() { - return self.tcx.sess.diagnostic().struct_dummy(); - } - - mk_diag(self.ty_to_string(actual_ty)) - } - - pub fn report_mismatched_types( - &self, - cause: &ObligationCause<'tcx>, - expected: Ty<'tcx>, - actual: Ty<'tcx>, - err: TypeError<'tcx>, - ) -> DiagnosticBuilder<'tcx> { - let trace = TypeTrace::types(cause, true, expected, actual); - self.report_and_explain_type_error(trace, &err) - } - - pub fn replace_bound_vars_with_fresh_vars<T>( - &self, - span: Span, - lbrct: LateBoundRegionConversionTime, - value: &ty::Binder<T>, - ) -> (T, BTreeMap<ty::BoundRegion, ty::Region<'tcx>>) - where - T: TypeFoldable<'tcx>, - { - let fld_r = |br| self.next_region_var(LateBoundRegion(span, br, lbrct)); - let fld_t = |_| { - self.next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::MiscVariable, - span, - }) - }; - let fld_c = |_, ty| { - self.next_const_var( - ty, - ConstVariableOrigin { kind: ConstVariableOriginKind::MiscVariable, span }, - ) - }; - self.tcx.replace_bound_vars(value, fld_r, fld_t, fld_c) - } - - /// See the [`region_constraints::verify_generic_bound`] method. - pub fn verify_generic_bound( - &self, - origin: SubregionOrigin<'tcx>, - kind: GenericKind<'tcx>, - a: ty::Region<'tcx>, - bound: VerifyBound<'tcx>, - ) { - debug!("verify_generic_bound({:?}, {:?} <: {:?})", kind, a, bound); - - self.inner - .borrow_mut() - .unwrap_region_constraints() - .verify_generic_bound(origin, kind, a, bound); - } - - pub fn type_is_copy_modulo_regions( - &self, - param_env: ty::ParamEnv<'tcx>, - ty: Ty<'tcx>, - span: Span, - ) -> bool { - let ty = self.resolve_vars_if_possible(&ty); - - // Even if the type may have no inference variables, during - // type-checking closure types are in local tables only. - if !self.in_progress_tables.is_some() || !ty.has_closure_types() { - if !(param_env, ty).has_local_value() { - return ty.is_copy_modulo_regions(self.tcx, param_env, span); - } - } - - let copy_def_id = self.tcx.require_lang_item(lang_items::CopyTraitLangItem, None); - - // This can get called from typeck (by euv), and `moves_by_default` - // rightly refuses to work with inference variables, but - // moves_by_default has a cache, which we want to use in other - // cases. - traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, copy_def_id, span) - } - - /// Obtains the latest type of the given closure; this may be a - /// closure in the current function, in which case its - /// `ClosureKind` may not yet be known. - pub fn closure_kind( - &self, - closure_def_id: DefId, - closure_substs: SubstsRef<'tcx>, - ) -> Option<ty::ClosureKind> { - let closure_kind_ty = closure_substs.as_closure().kind_ty(closure_def_id, self.tcx); - let closure_kind_ty = self.shallow_resolve(closure_kind_ty); - closure_kind_ty.to_opt_closure_kind() - } - - /// Obtains the signature of a closure. For closures, unlike - /// `tcx.fn_sig(def_id)`, this method will work during the - /// type-checking of the enclosing function and return the closure - /// signature in its partially inferred state. - pub fn closure_sig(&self, def_id: DefId, substs: SubstsRef<'tcx>) -> ty::PolyFnSig<'tcx> { - let closure_sig_ty = substs.as_closure().sig_ty(def_id, self.tcx); - let closure_sig_ty = self.shallow_resolve(closure_sig_ty); - closure_sig_ty.fn_sig(self.tcx) - } - - /// Normalizes associated types in `value`, potentially returning - /// new obligations that must further be processed. - pub fn partially_normalize_associated_types_in<T>( - &self, - span: Span, - body_id: hir::HirId, - param_env: ty::ParamEnv<'tcx>, - value: &T, - ) -> InferOk<'tcx, T> - where - T: TypeFoldable<'tcx>, - { - debug!("partially_normalize_associated_types_in(value={:?})", value); - let mut selcx = traits::SelectionContext::new(self); - let cause = ObligationCause::misc(span, body_id); - let traits::Normalized { value, obligations } = - traits::normalize(&mut selcx, param_env, cause, value); - debug!( - "partially_normalize_associated_types_in: result={:?} predicates={:?}", - value, obligations - ); - InferOk { value, obligations } - } - - /// Clears the selection, evaluation, and projection caches. This is useful when - /// repeatedly attempting to select an `Obligation` while changing only - /// its `ParamEnv`, since `FulfillmentContext` doesn't use probing. - pub fn clear_caches(&self) { - self.selection_cache.clear(); - self.evaluation_cache.clear(); - self.inner.borrow_mut().projection_cache.clear(); - } - - fn universe(&self) -> ty::UniverseIndex { - self.universe.get() - } - - /// Creates and return a fresh universe that extends all previous - /// universes. Updates `self.universe` to that new universe. - pub fn create_next_universe(&self) -> ty::UniverseIndex { - let u = self.universe.get().next_universe(); - self.universe.set(u); - u - } -} - -pub struct ShallowResolver<'a, 'tcx> { - infcx: &'a InferCtxt<'a, 'tcx>, -} - -impl<'a, 'tcx> ShallowResolver<'a, 'tcx> { - #[inline(always)] - pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> Self { - ShallowResolver { infcx } - } - - /// If `typ` is a type variable of some kind, resolve it one level - /// (but do not resolve types found in the result). If `typ` is - /// not a type variable, just return it unmodified. - pub fn shallow_resolve(&mut self, typ: Ty<'tcx>) -> Ty<'tcx> { - match typ.kind { - ty::Infer(ty::TyVar(v)) => { - // Not entirely obvious: if `typ` is a type variable, - // it can be resolved to an int/float variable, which - // can then be recursively resolved, hence the - // recursion. Note though that we prevent type - // variables from unifying to other type variables - // directly (though they may be embedded - // structurally), and we prevent cycles in any case, - // so this recursion should always be of very limited - // depth. - // - // Note: if these two lines are combined into one we get - // dynamic borrow errors on `self.infcx.inner`. - let known = self.infcx.inner.borrow_mut().type_variables.probe(v).known(); - known.map(|t| self.fold_ty(t)).unwrap_or(typ) - } - - ty::Infer(ty::IntVar(v)) => self - .infcx - .inner - .borrow_mut() - .int_unification_table - .probe_value(v) - .map(|v| v.to_type(self.infcx.tcx)) - .unwrap_or(typ), - - ty::Infer(ty::FloatVar(v)) => self - .infcx - .inner - .borrow_mut() - .float_unification_table - .probe_value(v) - .map(|v| v.to_type(self.infcx.tcx)) - .unwrap_or(typ), - - _ => typ, - } - } - - // `resolver.shallow_resolve_changed(ty)` is equivalent to - // `resolver.shallow_resolve(ty) != ty`, but more efficient. It's always - // inlined, despite being large, because it has only two call sites that - // are extremely hot. - #[inline(always)] - pub fn shallow_resolve_changed(&self, infer: ty::InferTy) -> bool { - match infer { - ty::TyVar(v) => { - use self::type_variable::TypeVariableValue; - - // If `inlined_probe` returns a `Known` value its `kind` never - // matches `infer`. - match self.infcx.inner.borrow_mut().type_variables.inlined_probe(v) { - TypeVariableValue::Unknown { .. } => false, - TypeVariableValue::Known { .. } => true, - } - } - - ty::IntVar(v) => { - // If inlined_probe_value returns a value it's always a - // `ty::Int(_)` or `ty::UInt(_)`, which nevers matches a - // `ty::Infer(_)`. - self.infcx.inner.borrow_mut().int_unification_table.inlined_probe_value(v).is_some() - } - - ty::FloatVar(v) => { - // If inlined_probe_value returns a value it's always a - // `ty::Float(_)`, which nevers matches a `ty::Infer(_)`. - // - // Not `inlined_probe_value(v)` because this call site is colder. - self.infcx.inner.borrow_mut().float_unification_table.probe_value(v).is_some() - } - - _ => unreachable!(), - } - } -} - -impl<'a, 'tcx> TypeFolder<'tcx> for ShallowResolver<'a, 'tcx> { - fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { - self.infcx.tcx - } - - fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - self.shallow_resolve(ty) - } - - fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { - if let ty::Const { val: ty::ConstKind::Infer(InferConst::Var(vid)), .. } = ct { - self.infcx - .inner - .borrow_mut() - .const_unification_table - .probe_value(*vid) - .val - .known() - .unwrap_or(ct) - } else { - ct - } - } -} - -impl<'tcx> TypeTrace<'tcx> { - pub fn span(&self) -> Span { - self.cause.span - } - - pub fn types( - cause: &ObligationCause<'tcx>, - a_is_expected: bool, - a: Ty<'tcx>, - b: Ty<'tcx>, - ) -> TypeTrace<'tcx> { - TypeTrace { cause: cause.clone(), values: Types(ExpectedFound::new(a_is_expected, a, b)) } - } - - pub fn dummy(tcx: TyCtxt<'tcx>) -> TypeTrace<'tcx> { - TypeTrace { - cause: ObligationCause::dummy(), - values: Types(ExpectedFound { expected: tcx.types.err, found: tcx.types.err }), - } - } -} - -impl<'tcx> SubregionOrigin<'tcx> { - pub fn span(&self) -> Span { - match *self { - Subtype(ref a) => a.span(), - InfStackClosure(a) => a, - InvokeClosure(a) => a, - DerefPointer(a) => a, - ClosureCapture(a, _) => a, - IndexSlice(a) => a, - RelateObjectBound(a) => a, - RelateParamBound(a, _) => a, - RelateRegionParamBound(a) => a, - RelateDefaultParamBound(a, _) => a, - Reborrow(a) => a, - ReborrowUpvar(a, _) => a, - DataBorrowed(_, a) => a, - ReferenceOutlivesReferent(_, a) => a, - ParameterInScope(_, a) => a, - ExprTypeIsNotInScope(_, a) => a, - BindingTypeIsNotValidAtDecl(a) => a, - CallRcvr(a) => a, - CallArg(a) => a, - CallReturn(a) => a, - Operand(a) => a, - AddrOf(a) => a, - AutoBorrow(a) => a, - SafeDestructor(a) => a, - CompareImplMethodObligation { span, .. } => span, - } - } - - pub fn from_obligation_cause<F>(cause: &traits::ObligationCause<'tcx>, default: F) -> Self - where - F: FnOnce() -> Self, - { - match cause.code { - traits::ObligationCauseCode::ReferenceOutlivesReferent(ref_type) => { - SubregionOrigin::ReferenceOutlivesReferent(ref_type, cause.span) - } - - traits::ObligationCauseCode::CompareImplMethodObligation { - item_name, - impl_item_def_id, - trait_item_def_id, - } => SubregionOrigin::CompareImplMethodObligation { - span: cause.span, - item_name, - impl_item_def_id, - trait_item_def_id, - }, - - _ => default(), - } - } -} - -impl RegionVariableOrigin { - pub fn span(&self) -> Span { - match *self { - MiscVariable(a) => a, - PatternRegion(a) => a, - AddrOfRegion(a) => a, - Autoref(a) => a, - Coercion(a) => a, - EarlyBoundRegion(a, ..) => a, - LateBoundRegion(a, ..) => a, - BoundRegionInCoherence(_) => rustc_span::DUMMY_SP, - UpvarRegion(_, a) => a, - NLL(..) => bug!("NLL variable used with `span`"), - } - } -} + /// The region `R0`. + pub member_region: Region<'tcx>, -impl<'tcx> fmt::Debug for RegionObligation<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "RegionObligation(sub_region={:?}, sup_type={:?})", - self.sub_region, self.sup_type - ) - } + /// The options `O1..On`. + pub choice_regions: Lrc<Vec<Region<'tcx>>>, } diff --git a/src/librustc/infer/nll_relate/mod.rs b/src/librustc/infer/nll_relate/mod.rs deleted file mode 100644 index 77e20e6ad8f..00000000000 --- a/src/librustc/infer/nll_relate/mod.rs +++ /dev/null @@ -1,1007 +0,0 @@ -//! This code is kind of an alternate way of doing subtyping, -//! supertyping, and type equating, distinct from the `combine.rs` -//! code but very similar in its effect and design. Eventually the two -//! ought to be merged. This code is intended for use in NLL and chalk. -//! -//! Here are the key differences: -//! -//! - This code may choose to bypass some checks (e.g., the occurs check) -//! in the case where we know that there are no unbound type inference -//! variables. This is the case for NLL, because at NLL time types are fully -//! inferred up-to regions. -//! - This code uses "universes" to handle higher-ranked regions and -//! not the leak-check. This is "more correct" than what rustc does -//! and we are generally migrating in this direction, but NLL had to -//! get there first. -//! -//! Also, this code assumes that there are no bound types at all, not even -//! free ones. This is ok because: -//! - we are not relating anything quantified over some type variable -//! - we will have instantiated all the bound type vars already (the one -//! thing we relate in chalk are basically domain goals and their -//! constituents) - -use crate::infer::InferCtxt; -use crate::infer::{ConstVarValue, ConstVariableValue}; -use crate::traits::DomainGoal; -use crate::ty::error::TypeError; -use crate::ty::fold::{TypeFoldable, TypeVisitor}; -use crate::ty::relate::{self, Relate, RelateResult, TypeRelation}; -use crate::ty::subst::GenericArg; -use crate::ty::{self, InferConst, Ty, TyCtxt}; -use rustc_data_structures::fx::FxHashMap; -use std::fmt::Debug; - -#[derive(PartialEq)] -pub enum NormalizationStrategy { - Lazy, - Eager, -} - -pub struct TypeRelating<'me, 'tcx, D> -where - D: TypeRelatingDelegate<'tcx>, -{ - infcx: &'me InferCtxt<'me, 'tcx>, - - /// Callback to use when we deduce an outlives relationship - delegate: D, - - /// How are we relating `a` and `b`? - /// - /// - Covariant means `a <: b`. - /// - Contravariant means `b <: a`. - /// - Invariant means `a == b. - /// - Bivariant means that it doesn't matter. - ambient_variance: ty::Variance, - - /// When we pass through a set of binders (e.g., when looking into - /// a `fn` type), we push a new bound region scope onto here. This - /// will contain the instantiated region for each region in those - /// binders. When we then encounter a `ReLateBound(d, br)`, we can - /// use the De Bruijn index `d` to find the right scope, and then - /// bound region name `br` to find the specific instantiation from - /// within that scope. See `replace_bound_region`. - /// - /// This field stores the instantiations for late-bound regions in - /// the `a` type. - a_scopes: Vec<BoundRegionScope<'tcx>>, - - /// Same as `a_scopes`, but for the `b` type. - b_scopes: Vec<BoundRegionScope<'tcx>>, -} - -pub trait TypeRelatingDelegate<'tcx> { - /// Push a constraint `sup: sub` -- this constraint must be - /// satisfied for the two types to be related. `sub` and `sup` may - /// be regions from the type or new variables created through the - /// delegate. - fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>); - - /// Push a domain goal that will need to be proved for the two types to - /// be related. Used for lazy normalization. - fn push_domain_goal(&mut self, domain_goal: DomainGoal<'tcx>); - - /// Creates a new universe index. Used when instantiating placeholders. - fn create_next_universe(&mut self) -> ty::UniverseIndex; - - /// Creates a new region variable representing a higher-ranked - /// region that is instantiated existentially. This creates an - /// inference variable, typically. - /// - /// So e.g., if you have `for<'a> fn(..) <: for<'b> fn(..)`, then - /// we will invoke this method to instantiate `'a` with an - /// inference variable (though `'b` would be instantiated first, - /// as a placeholder). - fn next_existential_region_var(&mut self, was_placeholder: bool) -> ty::Region<'tcx>; - - /// Creates a new region variable representing a - /// higher-ranked region that is instantiated universally. - /// This creates a new region placeholder, typically. - /// - /// So e.g., if you have `for<'a> fn(..) <: for<'b> fn(..)`, then - /// we will invoke this method to instantiate `'b` with a - /// placeholder region. - fn next_placeholder_region(&mut self, placeholder: ty::PlaceholderRegion) -> ty::Region<'tcx>; - - /// Creates a new existential region in the given universe. This - /// is used when handling subtyping and type variables -- if we - /// have that `?X <: Foo<'a>`, for example, we would instantiate - /// `?X` with a type like `Foo<'?0>` where `'?0` is a fresh - /// existential variable created by this function. We would then - /// relate `Foo<'?0>` with `Foo<'a>` (and probably add an outlives - /// relation stating that `'?0: 'a`). - fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx>; - - /// Define the normalization strategy to use, eager or lazy. - fn normalization() -> NormalizationStrategy; - - /// Enables some optimizations if we do not expect inference variables - /// in the RHS of the relation. - fn forbid_inference_vars() -> bool; -} - -#[derive(Clone, Debug)] -struct ScopesAndKind<'tcx> { - scopes: Vec<BoundRegionScope<'tcx>>, - kind: GenericArg<'tcx>, -} - -#[derive(Clone, Debug, Default)] -struct BoundRegionScope<'tcx> { - map: FxHashMap<ty::BoundRegion, ty::Region<'tcx>>, -} - -#[derive(Copy, Clone)] -struct UniversallyQuantified(bool); - -impl<'me, 'tcx, D> TypeRelating<'me, 'tcx, D> -where - D: TypeRelatingDelegate<'tcx>, -{ - pub fn new( - infcx: &'me InferCtxt<'me, 'tcx>, - delegate: D, - ambient_variance: ty::Variance, - ) -> Self { - Self { infcx, delegate, ambient_variance, a_scopes: vec![], b_scopes: vec![] } - } - - fn ambient_covariance(&self) -> bool { - match self.ambient_variance { - ty::Variance::Covariant | ty::Variance::Invariant => true, - ty::Variance::Contravariant | ty::Variance::Bivariant => false, - } - } - - fn ambient_contravariance(&self) -> bool { - match self.ambient_variance { - ty::Variance::Contravariant | ty::Variance::Invariant => true, - ty::Variance::Covariant | ty::Variance::Bivariant => false, - } - } - - fn create_scope( - &mut self, - value: &ty::Binder<impl TypeFoldable<'tcx>>, - universally_quantified: UniversallyQuantified, - ) -> BoundRegionScope<'tcx> { - let mut scope = BoundRegionScope::default(); - - // Create a callback that creates (via the delegate) either an - // existential or placeholder region as needed. - let mut next_region = { - let delegate = &mut self.delegate; - let mut lazy_universe = None; - move |br: ty::BoundRegion| { - if universally_quantified.0 { - // The first time this closure is called, create a - // new universe for the placeholders we will make - // from here out. - let universe = lazy_universe.unwrap_or_else(|| { - let universe = delegate.create_next_universe(); - lazy_universe = Some(universe); - universe - }); - - let placeholder = ty::PlaceholderRegion { universe, name: br }; - delegate.next_placeholder_region(placeholder) - } else { - delegate.next_existential_region_var(true) - } - } - }; - - value.skip_binder().visit_with(&mut ScopeInstantiator { - next_region: &mut next_region, - target_index: ty::INNERMOST, - bound_region_scope: &mut scope, - }); - - scope - } - - /// When we encounter binders during the type traversal, we record - /// the value to substitute for each of the things contained in - /// that binder. (This will be either a universal placeholder or - /// an existential inference variable.) Given the De Bruijn index - /// `debruijn` (and name `br`) of some binder we have now - /// encountered, this routine finds the value that we instantiated - /// the region with; to do so, it indexes backwards into the list - /// of ambient scopes `scopes`. - fn lookup_bound_region( - debruijn: ty::DebruijnIndex, - br: &ty::BoundRegion, - first_free_index: ty::DebruijnIndex, - scopes: &[BoundRegionScope<'tcx>], - ) -> ty::Region<'tcx> { - // The debruijn index is a "reverse index" into the - // scopes listing. So when we have INNERMOST (0), we - // want the *last* scope pushed, and so forth. - let debruijn_index = debruijn.index() - first_free_index.index(); - let scope = &scopes[scopes.len() - debruijn_index - 1]; - - // Find this bound region in that scope to map to a - // particular region. - scope.map[br] - } - - /// If `r` is a bound region, find the scope in which it is bound - /// (from `scopes`) and return the value that we instantiated it - /// with. Otherwise just return `r`. - fn replace_bound_region( - &self, - r: ty::Region<'tcx>, - first_free_index: ty::DebruijnIndex, - scopes: &[BoundRegionScope<'tcx>], - ) -> ty::Region<'tcx> { - debug!("replace_bound_regions(scopes={:?})", scopes); - if let ty::ReLateBound(debruijn, br) = r { - Self::lookup_bound_region(*debruijn, br, first_free_index, scopes) - } else { - r - } - } - - /// Push a new outlives requirement into our output set of - /// constraints. - fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>) { - debug!("push_outlives({:?}: {:?})", sup, sub); - - self.delegate.push_outlives(sup, sub); - } - - /// Relate a projection type and some value type lazily. This will always - /// succeed, but we push an additional `ProjectionEq` goal depending - /// on the value type: - /// - if the value type is any type `T` which is not a projection, we push - /// `ProjectionEq(projection = T)`. - /// - if the value type is another projection `other_projection`, we create - /// a new inference variable `?U` and push the two goals - /// `ProjectionEq(projection = ?U)`, `ProjectionEq(other_projection = ?U)`. - fn relate_projection_ty( - &mut self, - projection_ty: ty::ProjectionTy<'tcx>, - value_ty: Ty<'tcx>, - ) -> Ty<'tcx> { - use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; - use crate::traits::WhereClause; - use rustc_span::DUMMY_SP; - - match value_ty.kind { - ty::Projection(other_projection_ty) => { - let var = self.infcx.next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::MiscVariable, - span: DUMMY_SP, - }); - self.relate_projection_ty(projection_ty, var); - self.relate_projection_ty(other_projection_ty, var); - var - } - - _ => { - let projection = ty::ProjectionPredicate { projection_ty, ty: value_ty }; - self.delegate - .push_domain_goal(DomainGoal::Holds(WhereClause::ProjectionEq(projection))); - value_ty - } - } - } - - /// Relate a type inference variable with a value type. This works - /// by creating a "generalization" G of the value where all the - /// lifetimes are replaced with fresh inference values. This - /// genearlization G becomes the value of the inference variable, - /// and is then related in turn to the value. So e.g. if you had - /// `vid = ?0` and `value = &'a u32`, we might first instantiate - /// `?0` to a type like `&'0 u32` where `'0` is a fresh variable, - /// and then relate `&'0 u32` with `&'a u32` (resulting in - /// relations between `'0` and `'a`). - /// - /// The variable `pair` can be either a `(vid, ty)` or `(ty, vid)` - /// -- in other words, it is always a (unresolved) inference - /// variable `vid` and a type `ty` that are being related, but the - /// vid may appear either as the "a" type or the "b" type, - /// depending on where it appears in the tuple. The trait - /// `VidValuePair` lets us work with the vid/type while preserving - /// the "sidedness" when necessary -- the sidedness is relevant in - /// particular for the variance and set of in-scope things. - fn relate_ty_var<PAIR: VidValuePair<'tcx>>( - &mut self, - pair: PAIR, - ) -> RelateResult<'tcx, Ty<'tcx>> { - debug!("relate_ty_var({:?})", pair); - - let vid = pair.vid(); - let value_ty = pair.value_ty(); - - // FIXME(invariance) -- this logic assumes invariance, but that is wrong. - // This only presently applies to chalk integration, as NLL - // doesn't permit type variables to appear on both sides (and - // doesn't use lazy norm). - match value_ty.kind { - ty::Infer(ty::TyVar(value_vid)) => { - // Two type variables: just equate them. - self.infcx.inner.borrow_mut().type_variables.equate(vid, value_vid); - return Ok(value_ty); - } - - ty::Projection(projection_ty) if D::normalization() == NormalizationStrategy::Lazy => { - return Ok(self.relate_projection_ty(projection_ty, self.infcx.tcx.mk_ty_var(vid))); - } - - _ => (), - } - - let generalized_ty = self.generalize_value(value_ty, vid)?; - debug!("relate_ty_var: generalized_ty = {:?}", generalized_ty); - - if D::forbid_inference_vars() { - // In NLL, we don't have type inference variables - // floating around, so we can do this rather imprecise - // variant of the occurs-check. - assert!(!generalized_ty.has_infer_types()); - } - - self.infcx.inner.borrow_mut().type_variables.instantiate(vid, generalized_ty); - - // The generalized values we extract from `canonical_var_values` have - // been fully instantiated and hence the set of scopes we have - // doesn't matter -- just to be sure, put an empty vector - // in there. - let old_a_scopes = ::std::mem::take(pair.vid_scopes(self)); - - // Relate the generalized kind to the original one. - let result = pair.relate_generalized_ty(self, generalized_ty); - - // Restore the old scopes now. - *pair.vid_scopes(self) = old_a_scopes; - - debug!("relate_ty_var: complete, result = {:?}", result); - result - } - - fn generalize_value<T: Relate<'tcx>>( - &mut self, - value: T, - for_vid: ty::TyVid, - ) -> RelateResult<'tcx, T> { - let universe = self.infcx.probe_ty_var(for_vid).unwrap_err(); - - let mut generalizer = TypeGeneralizer { - infcx: self.infcx, - delegate: &mut self.delegate, - first_free_index: ty::INNERMOST, - ambient_variance: self.ambient_variance, - for_vid_sub_root: self.infcx.inner.borrow_mut().type_variables.sub_root_var(for_vid), - universe, - }; - - generalizer.relate(&value, &value) - } -} - -/// When we instantiate a inference variable with a value in -/// `relate_ty_var`, we always have the pair of a `TyVid` and a `Ty`, -/// but the ordering may vary (depending on whether the inference -/// variable was found on the `a` or `b` sides). Therefore, this trait -/// allows us to factor out common code, while preserving the order -/// when needed. -trait VidValuePair<'tcx>: Debug { - /// Extract the inference variable (which could be either the - /// first or second part of the tuple). - fn vid(&self) -> ty::TyVid; - - /// Extract the value it is being related to (which will be the - /// opposite part of the tuple from the vid). - fn value_ty(&self) -> Ty<'tcx>; - - /// Extract the scopes that apply to whichever side of the tuple - /// the vid was found on. See the comment where this is called - /// for more details on why we want them. - fn vid_scopes<D: TypeRelatingDelegate<'tcx>>( - &self, - relate: &'r mut TypeRelating<'_, 'tcx, D>, - ) -> &'r mut Vec<BoundRegionScope<'tcx>>; - - /// Given a generalized type G that should replace the vid, relate - /// G to the value, putting G on whichever side the vid would have - /// appeared. - fn relate_generalized_ty<D>( - &self, - relate: &mut TypeRelating<'_, 'tcx, D>, - generalized_ty: Ty<'tcx>, - ) -> RelateResult<'tcx, Ty<'tcx>> - where - D: TypeRelatingDelegate<'tcx>; -} - -impl VidValuePair<'tcx> for (ty::TyVid, Ty<'tcx>) { - fn vid(&self) -> ty::TyVid { - self.0 - } - - fn value_ty(&self) -> Ty<'tcx> { - self.1 - } - - fn vid_scopes<D>( - &self, - relate: &'r mut TypeRelating<'_, 'tcx, D>, - ) -> &'r mut Vec<BoundRegionScope<'tcx>> - where - D: TypeRelatingDelegate<'tcx>, - { - &mut relate.a_scopes - } - - fn relate_generalized_ty<D>( - &self, - relate: &mut TypeRelating<'_, 'tcx, D>, - generalized_ty: Ty<'tcx>, - ) -> RelateResult<'tcx, Ty<'tcx>> - where - D: TypeRelatingDelegate<'tcx>, - { - relate.relate(&generalized_ty, &self.value_ty()) - } -} - -// In this case, the "vid" is the "b" type. -impl VidValuePair<'tcx> for (Ty<'tcx>, ty::TyVid) { - fn vid(&self) -> ty::TyVid { - self.1 - } - - fn value_ty(&self) -> Ty<'tcx> { - self.0 - } - - fn vid_scopes<D>( - &self, - relate: &'r mut TypeRelating<'_, 'tcx, D>, - ) -> &'r mut Vec<BoundRegionScope<'tcx>> - where - D: TypeRelatingDelegate<'tcx>, - { - &mut relate.b_scopes - } - - fn relate_generalized_ty<D>( - &self, - relate: &mut TypeRelating<'_, 'tcx, D>, - generalized_ty: Ty<'tcx>, - ) -> RelateResult<'tcx, Ty<'tcx>> - where - D: TypeRelatingDelegate<'tcx>, - { - relate.relate(&self.value_ty(), &generalized_ty) - } -} - -impl<D> TypeRelation<'tcx> for TypeRelating<'me, 'tcx, D> -where - D: TypeRelatingDelegate<'tcx>, -{ - fn tcx(&self) -> TyCtxt<'tcx> { - self.infcx.tcx - } - - // FIXME(oli-obk): not sure how to get the correct ParamEnv - fn param_env(&self) -> ty::ParamEnv<'tcx> { - ty::ParamEnv::empty() - } - - fn tag(&self) -> &'static str { - "nll::subtype" - } - - fn a_is_expected(&self) -> bool { - true - } - - fn relate_with_variance<T: Relate<'tcx>>( - &mut self, - variance: ty::Variance, - a: &T, - b: &T, - ) -> RelateResult<'tcx, T> { - debug!("relate_with_variance(variance={:?}, a={:?}, b={:?})", variance, a, b); - - let old_ambient_variance = self.ambient_variance; - self.ambient_variance = self.ambient_variance.xform(variance); - - debug!("relate_with_variance: ambient_variance = {:?}", self.ambient_variance); - - let r = self.relate(a, b)?; - - self.ambient_variance = old_ambient_variance; - - debug!("relate_with_variance: r={:?}", r); - - Ok(r) - } - - fn tys(&mut self, a: Ty<'tcx>, mut b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { - let a = self.infcx.shallow_resolve(a); - - if !D::forbid_inference_vars() { - b = self.infcx.shallow_resolve(b); - } - - if a == b { - return Ok(a); - } - - match (&a.kind, &b.kind) { - (_, &ty::Infer(ty::TyVar(vid))) => { - if D::forbid_inference_vars() { - // Forbid inference variables in the RHS. - bug!("unexpected inference var {:?}", b) - } else { - self.relate_ty_var((a, vid)) - } - } - - (&ty::Infer(ty::TyVar(vid)), _) => self.relate_ty_var((vid, b)), - - (&ty::Projection(projection_ty), _) - if D::normalization() == NormalizationStrategy::Lazy => - { - Ok(self.relate_projection_ty(projection_ty, b)) - } - - (_, &ty::Projection(projection_ty)) - if D::normalization() == NormalizationStrategy::Lazy => - { - Ok(self.relate_projection_ty(projection_ty, a)) - } - - _ => { - debug!("tys(a={:?}, b={:?}, variance={:?})", a, b, self.ambient_variance); - - // Will also handle unification of `IntVar` and `FloatVar`. - self.infcx.super_combine_tys(self, a, b) - } - } - } - - fn regions( - &mut self, - a: ty::Region<'tcx>, - b: ty::Region<'tcx>, - ) -> RelateResult<'tcx, ty::Region<'tcx>> { - debug!("regions(a={:?}, b={:?}, variance={:?})", a, b, self.ambient_variance); - - let v_a = self.replace_bound_region(a, ty::INNERMOST, &self.a_scopes); - let v_b = self.replace_bound_region(b, ty::INNERMOST, &self.b_scopes); - - debug!("regions: v_a = {:?}", v_a); - debug!("regions: v_b = {:?}", v_b); - - if self.ambient_covariance() { - // Covariance: a <= b. Hence, `b: a`. - self.push_outlives(v_b, v_a); - } - - if self.ambient_contravariance() { - // Contravariant: b <= a. Hence, `a: b`. - self.push_outlives(v_a, v_b); - } - - Ok(a) - } - - fn consts( - &mut self, - a: &'tcx ty::Const<'tcx>, - mut b: &'tcx ty::Const<'tcx>, - ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> { - let a = self.infcx.shallow_resolve(a); - - if !D::forbid_inference_vars() { - b = self.infcx.shallow_resolve(b); - } - - match b.val { - ty::ConstKind::Infer(InferConst::Var(_)) if D::forbid_inference_vars() => { - // Forbid inference variables in the RHS. - bug!("unexpected inference var {:?}", b) - } - // FIXME(invariance): see the related FIXME above. - _ => self.infcx.super_combine_consts(self, a, b), - } - } - - fn binders<T>( - &mut self, - a: &ty::Binder<T>, - b: &ty::Binder<T>, - ) -> RelateResult<'tcx, ty::Binder<T>> - where - T: Relate<'tcx>, - { - // We want that - // - // ``` - // for<'a> fn(&'a u32) -> &'a u32 <: - // fn(&'b u32) -> &'b u32 - // ``` - // - // but not - // - // ``` - // fn(&'a u32) -> &'a u32 <: - // for<'b> fn(&'b u32) -> &'b u32 - // ``` - // - // We therefore proceed as follows: - // - // - Instantiate binders on `b` universally, yielding a universe U1. - // - Instantiate binders on `a` existentially in U1. - - debug!("binders({:?}: {:?}, ambient_variance={:?})", a, b, self.ambient_variance); - - if !a.skip_binder().has_escaping_bound_vars() && !b.skip_binder().has_escaping_bound_vars() - { - // Fast path for the common case. - self.relate(a.skip_binder(), b.skip_binder())?; - return Ok(a.clone()); - } - - if self.ambient_covariance() { - // Covariance, so we want `for<..> A <: for<..> B` -- - // therefore we compare any instantiation of A (i.e., A - // instantiated with existentials) against every - // instantiation of B (i.e., B instantiated with - // universals). - - let b_scope = self.create_scope(b, UniversallyQuantified(true)); - let a_scope = self.create_scope(a, UniversallyQuantified(false)); - - debug!("binders: a_scope = {:?} (existential)", a_scope); - debug!("binders: b_scope = {:?} (universal)", b_scope); - - self.b_scopes.push(b_scope); - self.a_scopes.push(a_scope); - - // Reset the ambient variance to covariant. This is needed - // to correctly handle cases like - // - // for<'a> fn(&'a u32, &'a u3) == for<'b, 'c> fn(&'b u32, &'c u32) - // - // Somewhat surprisingly, these two types are actually - // **equal**, even though the one on the right looks more - // polymorphic. The reason is due to subtyping. To see it, - // consider that each function can call the other: - // - // - The left function can call the right with `'b` and - // `'c` both equal to `'a` - // - // - The right function can call the left with `'a` set to - // `{P}`, where P is the point in the CFG where the call - // itself occurs. Note that `'b` and `'c` must both - // include P. At the point, the call works because of - // subtyping (i.e., `&'b u32 <: &{P} u32`). - let variance = ::std::mem::replace(&mut self.ambient_variance, ty::Variance::Covariant); - - self.relate(a.skip_binder(), b.skip_binder())?; - - self.ambient_variance = variance; - - self.b_scopes.pop().unwrap(); - self.a_scopes.pop().unwrap(); - } - - if self.ambient_contravariance() { - // Contravariance, so we want `for<..> A :> for<..> B` - // -- therefore we compare every instantiation of A (i.e., - // A instantiated with universals) against any - // instantiation of B (i.e., B instantiated with - // existentials). Opposite of above. - - let a_scope = self.create_scope(a, UniversallyQuantified(true)); - let b_scope = self.create_scope(b, UniversallyQuantified(false)); - - debug!("binders: a_scope = {:?} (universal)", a_scope); - debug!("binders: b_scope = {:?} (existential)", b_scope); - - self.a_scopes.push(a_scope); - self.b_scopes.push(b_scope); - - // Reset ambient variance to contravariance. See the - // covariant case above for an explanation. - let variance = - ::std::mem::replace(&mut self.ambient_variance, ty::Variance::Contravariant); - - self.relate(a.skip_binder(), b.skip_binder())?; - - self.ambient_variance = variance; - - self.b_scopes.pop().unwrap(); - self.a_scopes.pop().unwrap(); - } - - Ok(a.clone()) - } -} - -/// When we encounter a binder like `for<..> fn(..)`, we actually have -/// to walk the `fn` value to find all the values bound by the `for` -/// (these are not explicitly present in the ty representation right -/// now). This visitor handles that: it descends the type, tracking -/// binder depth, and finds late-bound regions targeting the -/// `for<..`>. For each of those, it creates an entry in -/// `bound_region_scope`. -struct ScopeInstantiator<'me, 'tcx> { - next_region: &'me mut dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx>, - // The debruijn index of the scope we are instantiating. - target_index: ty::DebruijnIndex, - bound_region_scope: &'me mut BoundRegionScope<'tcx>, -} - -impl<'me, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'me, 'tcx> { - fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> bool { - self.target_index.shift_in(1); - t.super_visit_with(self); - self.target_index.shift_out(1); - - false - } - - fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { - let ScopeInstantiator { bound_region_scope, next_region, .. } = self; - - match r { - ty::ReLateBound(debruijn, br) if *debruijn == self.target_index => { - bound_region_scope.map.entry(*br).or_insert_with(|| next_region(*br)); - } - - _ => {} - } - - false - } -} - -/// The "type generalize" is used when handling inference variables. -/// -/// The basic strategy for handling a constraint like `?A <: B` is to -/// apply a "generalization strategy" to the type `B` -- this replaces -/// all the lifetimes in the type `B` with fresh inference -/// variables. (You can read more about the strategy in this [blog -/// post].) -/// -/// As an example, if we had `?A <: &'x u32`, we would generalize `&'x -/// u32` to `&'0 u32` where `'0` is a fresh variable. This becomes the -/// value of `A`. Finally, we relate `&'0 u32 <: &'x u32`, which -/// establishes `'0: 'x` as a constraint. -/// -/// As a side-effect of this generalization procedure, we also replace -/// all the bound regions that we have traversed with concrete values, -/// so that the resulting generalized type is independent from the -/// scopes. -/// -/// [blog post]: https://is.gd/0hKvIr -struct TypeGeneralizer<'me, 'tcx, D> -where - D: TypeRelatingDelegate<'tcx>, -{ - infcx: &'me InferCtxt<'me, 'tcx>, - - delegate: &'me mut D, - - /// After we generalize this type, we are going to relative it to - /// some other type. What will be the variance at this point? - ambient_variance: ty::Variance, - - first_free_index: ty::DebruijnIndex, - - /// The vid of the type variable that is in the process of being - /// instantiated. If we find this within the value we are folding, - /// that means we would have created a cyclic value. - for_vid_sub_root: ty::TyVid, - - /// The universe of the type variable that is in the process of being - /// instantiated. If we find anything that this universe cannot name, - /// we reject the relation. - universe: ty::UniverseIndex, -} - -impl<D> TypeRelation<'tcx> for TypeGeneralizer<'me, 'tcx, D> -where - D: TypeRelatingDelegate<'tcx>, -{ - fn tcx(&self) -> TyCtxt<'tcx> { - self.infcx.tcx - } - - // FIXME(oli-obk): not sure how to get the correct ParamEnv - fn param_env(&self) -> ty::ParamEnv<'tcx> { - ty::ParamEnv::empty() - } - - fn tag(&self) -> &'static str { - "nll::generalizer" - } - - fn a_is_expected(&self) -> bool { - true - } - - fn relate_with_variance<T: Relate<'tcx>>( - &mut self, - variance: ty::Variance, - a: &T, - b: &T, - ) -> RelateResult<'tcx, T> { - debug!( - "TypeGeneralizer::relate_with_variance(variance={:?}, a={:?}, b={:?})", - variance, a, b - ); - - let old_ambient_variance = self.ambient_variance; - self.ambient_variance = self.ambient_variance.xform(variance); - - debug!( - "TypeGeneralizer::relate_with_variance: ambient_variance = {:?}", - self.ambient_variance - ); - - let r = self.relate(a, b)?; - - self.ambient_variance = old_ambient_variance; - - debug!("TypeGeneralizer::relate_with_variance: r={:?}", r); - - Ok(r) - } - - fn tys(&mut self, a: Ty<'tcx>, _: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { - use crate::infer::type_variable::TypeVariableValue; - - debug!("TypeGeneralizer::tys(a={:?})", a); - - match a.kind { - ty::Infer(ty::TyVar(_)) | ty::Infer(ty::IntVar(_)) | ty::Infer(ty::FloatVar(_)) - if D::forbid_inference_vars() => - { - bug!("unexpected inference variable encountered in NLL generalization: {:?}", a); - } - - ty::Infer(ty::TyVar(vid)) => { - let variables = &mut self.infcx.inner.borrow_mut().type_variables; - let vid = variables.root_var(vid); - let sub_vid = variables.sub_root_var(vid); - if sub_vid == self.for_vid_sub_root { - // If sub-roots are equal, then `for_vid` and - // `vid` are related via subtyping. - debug!("TypeGeneralizer::tys: occurs check failed"); - return Err(TypeError::Mismatch); - } else { - match variables.probe(vid) { - TypeVariableValue::Known { value: u } => { - drop(variables); - self.relate(&u, &u) - } - TypeVariableValue::Unknown { universe: _universe } => { - if self.ambient_variance == ty::Bivariant { - // FIXME: we may need a WF predicate (related to #54105). - } - - let origin = *variables.var_origin(vid); - - // Replacing with a new variable in the universe `self.universe`, - // it will be unified later with the original type variable in - // the universe `_universe`. - let new_var_id = variables.new_var(self.universe, false, origin); - - let u = self.tcx().mk_ty_var(new_var_id); - debug!("generalize: replacing original vid={:?} with new={:?}", vid, u); - return Ok(u); - } - } - } - } - - ty::Infer(ty::IntVar(_)) | ty::Infer(ty::FloatVar(_)) => { - // No matter what mode we are in, - // integer/floating-point types must be equal to be - // relatable. - Ok(a) - } - - ty::Placeholder(placeholder) => { - if self.universe.cannot_name(placeholder.universe) { - debug!( - "TypeGeneralizer::tys: root universe {:?} cannot name\ - placeholder in universe {:?}", - self.universe, placeholder.universe - ); - Err(TypeError::Mismatch) - } else { - Ok(a) - } - } - - _ => relate::super_relate_tys(self, a, a), - } - } - - fn regions( - &mut self, - a: ty::Region<'tcx>, - _: ty::Region<'tcx>, - ) -> RelateResult<'tcx, ty::Region<'tcx>> { - debug!("TypeGeneralizer::regions(a={:?})", a); - - if let ty::ReLateBound(debruijn, _) = a { - if *debruijn < self.first_free_index { - return Ok(a); - } - } - - // For now, we just always create a fresh region variable to - // replace all the regions in the source type. In the main - // type checker, we special case the case where the ambient - // variance is `Invariant` and try to avoid creating a fresh - // region variable, but since this comes up so much less in - // NLL (only when users use `_` etc) it is much less - // important. - // - // As an aside, since these new variables are created in - // `self.universe` universe, this also serves to enforce the - // universe scoping rules. - // - // FIXME(#54105) -- if the ambient variance is bivariant, - // though, we may however need to check well-formedness or - // risk a problem like #41677 again. - - let replacement_region_vid = self.delegate.generalize_existential(self.universe); - - Ok(replacement_region_vid) - } - - fn consts( - &mut self, - a: &'tcx ty::Const<'tcx>, - _: &'tcx ty::Const<'tcx>, - ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> { - match a.val { - ty::ConstKind::Infer(InferConst::Var(_)) if D::forbid_inference_vars() => { - bug!("unexpected inference variable encountered in NLL generalization: {:?}", a); - } - ty::ConstKind::Infer(InferConst::Var(vid)) => { - let variable_table = &mut self.infcx.inner.borrow_mut().const_unification_table; - let var_value = variable_table.probe_value(vid); - match var_value.val.known() { - Some(u) => self.relate(&u, &u), - None => { - let new_var_id = variable_table.new_key(ConstVarValue { - origin: var_value.origin, - val: ConstVariableValue::Unknown { universe: self.universe }, - }); - Ok(self.tcx().mk_const_var(new_var_id, a.ty)) - } - } - } - _ => relate::super_relate_consts(self, a, a), - } - } - - fn binders<T>( - &mut self, - a: &ty::Binder<T>, - _: &ty::Binder<T>, - ) -> RelateResult<'tcx, ty::Binder<T>> - where - T: Relate<'tcx>, - { - debug!("TypeGeneralizer::binders(a={:?})", a); - - self.first_free_index.shift_in(1); - let result = self.relate(a.skip_binder(), a.skip_binder())?; - self.first_free_index.shift_out(1); - Ok(ty::Binder::bind(result)) - } -} diff --git a/src/librustc/infer/opaque_types/mod.rs b/src/librustc/infer/opaque_types/mod.rs deleted file mode 100644 index 5ecd03e4123..00000000000 --- a/src/librustc/infer/opaque_types/mod.rs +++ /dev/null @@ -1,1328 +0,0 @@ -use crate::infer::error_reporting::{note_and_explain_free_region, note_and_explain_region}; -use crate::infer::{self, InferCtxt, InferOk, TypeVariableOrigin, TypeVariableOriginKind}; -use crate::middle::region; -use crate::traits::{self, PredicateObligation}; -use crate::ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder, TypeVisitor}; -use crate::ty::free_region_map::FreeRegionRelations; -use crate::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, SubstsRef}; -use crate::ty::{self, GenericParamDefKind, Ty, TyCtxt}; -use rustc::session::config::nightly_options; -use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::sync::Lrc; -use rustc_errors::{struct_span_err, DiagnosticBuilder}; -use rustc_hir as hir; -use rustc_hir::def_id::{DefId, DefIdMap}; -use rustc_hir::Node; -use rustc_span::Span; - -pub type OpaqueTypeMap<'tcx> = DefIdMap<OpaqueTypeDecl<'tcx>>; - -/// Information about the opaque types whose values we -/// are inferring in this function (these are the `impl Trait` that -/// appear in the return type). -#[derive(Copy, Clone, Debug)] -pub struct OpaqueTypeDecl<'tcx> { - /// The opaque type (`ty::Opaque`) for this declaration. - pub opaque_type: Ty<'tcx>, - - /// The substitutions that we apply to the opaque type that this - /// `impl Trait` desugars to. e.g., if: - /// - /// fn foo<'a, 'b, T>() -> impl Trait<'a> - /// - /// winds up desugared to: - /// - /// type Foo<'x, X> = impl Trait<'x> - /// fn foo<'a, 'b, T>() -> Foo<'a, T> - /// - /// then `substs` would be `['a, T]`. - pub substs: SubstsRef<'tcx>, - - /// The span of this particular definition of the opaque type. So - /// for example: - /// - /// ``` - /// type Foo = impl Baz; - /// fn bar() -> Foo { - /// ^^^ This is the span we are looking for! - /// ``` - /// - /// In cases where the fn returns `(impl Trait, impl Trait)` or - /// other such combinations, the result is currently - /// over-approximated, but better than nothing. - pub definition_span: Span, - - /// The type variable that represents the value of the opaque type - /// that we require. In other words, after we compile this function, - /// we will be created a constraint like: - /// - /// Foo<'a, T> = ?C - /// - /// where `?C` is the value of this type variable. =) It may - /// naturally refer to the type and lifetime parameters in scope - /// in this function, though ultimately it should only reference - /// those that are arguments to `Foo` in the constraint above. (In - /// other words, `?C` should not include `'b`, even though it's a - /// lifetime parameter on `foo`.) - pub concrete_ty: Ty<'tcx>, - - /// Returns `true` if the `impl Trait` bounds include region bounds. - /// For example, this would be true for: - /// - /// fn foo<'a, 'b, 'c>() -> impl Trait<'c> + 'a + 'b - /// - /// but false for: - /// - /// fn foo<'c>() -> impl Trait<'c> - /// - /// unless `Trait` was declared like: - /// - /// trait Trait<'c>: 'c - /// - /// in which case it would be true. - /// - /// This is used during regionck to decide whether we need to - /// impose any additional constraints to ensure that region - /// variables in `concrete_ty` wind up being constrained to - /// something from `substs` (or, at minimum, things that outlive - /// the fn body). (Ultimately, writeback is responsible for this - /// check.) - pub has_required_region_bounds: bool, - - /// The origin of the opaque type. - pub origin: hir::OpaqueTyOrigin, -} - -/// Whether member constraints should be generated for all opaque types -pub enum GenerateMemberConstraints { - /// The default, used by typeck - WhenRequired, - /// The borrow checker needs member constraints in any case where we don't - /// have a `'static` bound. This is because the borrow checker has more - /// flexibility in the values of regions. For example, given `f<'a, 'b>` - /// the borrow checker can have an inference variable outlive `'a` and `'b`, - /// but not be equal to `'static`. - IfNoStaticBound, -} - -impl<'a, 'tcx> InferCtxt<'a, 'tcx> { - /// Replaces all opaque types in `value` with fresh inference variables - /// and creates appropriate obligations. For example, given the input: - /// - /// impl Iterator<Item = impl Debug> - /// - /// this method would create two type variables, `?0` and `?1`. It would - /// return the type `?0` but also the obligations: - /// - /// ?0: Iterator<Item = ?1> - /// ?1: Debug - /// - /// Moreover, it returns a `OpaqueTypeMap` that would map `?0` to - /// info about the `impl Iterator<..>` type and `?1` to info about - /// the `impl Debug` type. - /// - /// # Parameters - /// - /// - `parent_def_id` -- the `DefId` of the function in which the opaque type - /// is defined - /// - `body_id` -- the body-id with which the resulting obligations should - /// be associated - /// - `param_env` -- the in-scope parameter environment to be used for - /// obligations - /// - `value` -- the value within which we are instantiating opaque types - /// - `value_span` -- the span where the value came from, used in error reporting - pub fn instantiate_opaque_types<T: TypeFoldable<'tcx>>( - &self, - parent_def_id: DefId, - body_id: hir::HirId, - param_env: ty::ParamEnv<'tcx>, - value: &T, - value_span: Span, - ) -> InferOk<'tcx, (T, OpaqueTypeMap<'tcx>)> { - debug!( - "instantiate_opaque_types(value={:?}, parent_def_id={:?}, body_id={:?}, \ - param_env={:?}, value_span={:?})", - value, parent_def_id, body_id, param_env, value_span, - ); - let mut instantiator = Instantiator { - infcx: self, - parent_def_id, - body_id, - param_env, - value_span, - opaque_types: Default::default(), - obligations: vec![], - }; - let value = instantiator.instantiate_opaque_types_in_map(value); - InferOk { value: (value, instantiator.opaque_types), obligations: instantiator.obligations } - } - - /// Given the map `opaque_types` containing the opaque - /// `impl Trait` types whose underlying, hidden types are being - /// inferred, this method adds constraints to the regions - /// appearing in those underlying hidden types to ensure that they - /// at least do not refer to random scopes within the current - /// function. These constraints are not (quite) sufficient to - /// guarantee that the regions are actually legal values; that - /// final condition is imposed after region inference is done. - /// - /// # The Problem - /// - /// Let's work through an example to explain how it works. Assume - /// the current function is as follows: - /// - /// ```text - /// fn foo<'a, 'b>(..) -> (impl Bar<'a>, impl Bar<'b>) - /// ``` - /// - /// Here, we have two `impl Trait` types whose values are being - /// inferred (the `impl Bar<'a>` and the `impl - /// Bar<'b>`). Conceptually, this is sugar for a setup where we - /// define underlying opaque types (`Foo1`, `Foo2`) and then, in - /// the return type of `foo`, we *reference* those definitions: - /// - /// ```text - /// type Foo1<'x> = impl Bar<'x>; - /// type Foo2<'x> = impl Bar<'x>; - /// fn foo<'a, 'b>(..) -> (Foo1<'a>, Foo2<'b>) { .. } - /// // ^^^^ ^^ - /// // | | - /// // | substs - /// // def_id - /// ``` - /// - /// As indicating in the comments above, each of those references - /// is (in the compiler) basically a substitution (`substs`) - /// applied to the type of a suitable `def_id` (which identifies - /// `Foo1` or `Foo2`). - /// - /// Now, at this point in compilation, what we have done is to - /// replace each of the references (`Foo1<'a>`, `Foo2<'b>`) with - /// fresh inference variables C1 and C2. We wish to use the values - /// of these variables to infer the underlying types of `Foo1` and - /// `Foo2`. That is, this gives rise to higher-order (pattern) unification - /// constraints like: - /// - /// ```text - /// for<'a> (Foo1<'a> = C1) - /// for<'b> (Foo1<'b> = C2) - /// ``` - /// - /// For these equation to be satisfiable, the types `C1` and `C2` - /// can only refer to a limited set of regions. For example, `C1` - /// can only refer to `'static` and `'a`, and `C2` can only refer - /// to `'static` and `'b`. The job of this function is to impose that - /// constraint. - /// - /// Up to this point, C1 and C2 are basically just random type - /// inference variables, and hence they may contain arbitrary - /// regions. In fact, it is fairly likely that they do! Consider - /// this possible definition of `foo`: - /// - /// ```text - /// fn foo<'a, 'b>(x: &'a i32, y: &'b i32) -> (impl Bar<'a>, impl Bar<'b>) { - /// (&*x, &*y) - /// } - /// ``` - /// - /// Here, the values for the concrete types of the two impl - /// traits will include inference variables: - /// - /// ```text - /// &'0 i32 - /// &'1 i32 - /// ``` - /// - /// Ordinarily, the subtyping rules would ensure that these are - /// sufficiently large. But since `impl Bar<'a>` isn't a specific - /// type per se, we don't get such constraints by default. This - /// is where this function comes into play. It adds extra - /// constraints to ensure that all the regions which appear in the - /// inferred type are regions that could validly appear. - /// - /// This is actually a bit of a tricky constraint in general. We - /// want to say that each variable (e.g., `'0`) can only take on - /// values that were supplied as arguments to the opaque type - /// (e.g., `'a` for `Foo1<'a>`) or `'static`, which is always in - /// scope. We don't have a constraint quite of this kind in the current - /// region checker. - /// - /// # The Solution - /// - /// We generally prefer to make `<=` constraints, since they - /// integrate best into the region solver. To do that, we find the - /// "minimum" of all the arguments that appear in the substs: that - /// is, some region which is less than all the others. In the case - /// of `Foo1<'a>`, that would be `'a` (it's the only choice, after - /// all). Then we apply that as a least bound to the variables - /// (e.g., `'a <= '0`). - /// - /// In some cases, there is no minimum. Consider this example: - /// - /// ```text - /// fn baz<'a, 'b>() -> impl Trait<'a, 'b> { ... } - /// ``` - /// - /// Here we would report a more complex "in constraint", like `'r - /// in ['a, 'b, 'static]` (where `'r` is some regon appearing in - /// the hidden type). - /// - /// # Constrain regions, not the hidden concrete type - /// - /// Note that generating constraints on each region `Rc` is *not* - /// the same as generating an outlives constraint on `Tc` iself. - /// For example, if we had a function like this: - /// - /// ```rust - /// fn foo<'a, T>(x: &'a u32, y: T) -> impl Foo<'a> { - /// (x, y) - /// } - /// - /// // Equivalent to: - /// type FooReturn<'a, T> = impl Foo<'a>; - /// fn foo<'a, T>(..) -> FooReturn<'a, T> { .. } - /// ``` - /// - /// then the hidden type `Tc` would be `(&'0 u32, T)` (where `'0` - /// is an inference variable). If we generated a constraint that - /// `Tc: 'a`, then this would incorrectly require that `T: 'a` -- - /// but this is not necessary, because the opaque type we - /// create will be allowed to reference `T`. So we only generate a - /// constraint that `'0: 'a`. - /// - /// # The `free_region_relations` parameter - /// - /// The `free_region_relations` argument is used to find the - /// "minimum" of the regions supplied to a given opaque type. - /// It must be a relation that can answer whether `'a <= 'b`, - /// where `'a` and `'b` are regions that appear in the "substs" - /// for the opaque type references (the `<'a>` in `Foo1<'a>`). - /// - /// Note that we do not impose the constraints based on the - /// generic regions from the `Foo1` definition (e.g., `'x`). This - /// is because the constraints we are imposing here is basically - /// the concern of the one generating the constraining type C1, - /// which is the current function. It also means that we can - /// take "implied bounds" into account in some cases: - /// - /// ```text - /// trait SomeTrait<'a, 'b> { } - /// fn foo<'a, 'b>(_: &'a &'b u32) -> impl SomeTrait<'a, 'b> { .. } - /// ``` - /// - /// Here, the fact that `'b: 'a` is known only because of the - /// implied bounds from the `&'a &'b u32` parameter, and is not - /// "inherent" to the opaque type definition. - /// - /// # Parameters - /// - /// - `opaque_types` -- the map produced by `instantiate_opaque_types` - /// - `free_region_relations` -- something that can be used to relate - /// the free regions (`'a`) that appear in the impl trait. - pub fn constrain_opaque_types<FRR: FreeRegionRelations<'tcx>>( - &self, - opaque_types: &OpaqueTypeMap<'tcx>, - free_region_relations: &FRR, - ) { - debug!("constrain_opaque_types()"); - - for (&def_id, opaque_defn) in opaque_types { - self.constrain_opaque_type( - def_id, - opaque_defn, - GenerateMemberConstraints::WhenRequired, - free_region_relations, - ); - } - } - - /// See `constrain_opaque_types` for documentation. - pub fn constrain_opaque_type<FRR: FreeRegionRelations<'tcx>>( - &self, - def_id: DefId, - opaque_defn: &OpaqueTypeDecl<'tcx>, - mode: GenerateMemberConstraints, - free_region_relations: &FRR, - ) { - debug!("constrain_opaque_type()"); - debug!("constrain_opaque_type: def_id={:?}", def_id); - debug!("constrain_opaque_type: opaque_defn={:#?}", opaque_defn); - - let tcx = self.tcx; - - let concrete_ty = self.resolve_vars_if_possible(&opaque_defn.concrete_ty); - - debug!("constrain_opaque_type: concrete_ty={:?}", concrete_ty); - - let opaque_type_generics = tcx.generics_of(def_id); - - let span = tcx.def_span(def_id); - - // If there are required region bounds, we can use them. - if opaque_defn.has_required_region_bounds { - let predicates_of = tcx.predicates_of(def_id); - debug!("constrain_opaque_type: predicates: {:#?}", predicates_of,); - let bounds = predicates_of.instantiate(tcx, opaque_defn.substs); - debug!("constrain_opaque_type: bounds={:#?}", bounds); - let opaque_type = tcx.mk_opaque(def_id, opaque_defn.substs); - - let required_region_bounds = - required_region_bounds(tcx, opaque_type, bounds.predicates); - debug_assert!(!required_region_bounds.is_empty()); - - for required_region in required_region_bounds { - concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor { - tcx: self.tcx, - op: |r| self.sub_regions(infer::CallReturn(span), required_region, r), - }); - } - if let GenerateMemberConstraints::IfNoStaticBound = mode { - self.generate_member_constraint( - concrete_ty, - opaque_type_generics, - opaque_defn, - def_id, - ); - } - return; - } - - // There were no `required_region_bounds`, - // so we have to search for a `least_region`. - // Go through all the regions used as arguments to the - // opaque type. These are the parameters to the opaque - // type; so in our example above, `substs` would contain - // `['a]` for the first impl trait and `'b` for the - // second. - let mut least_region = None; - for param in &opaque_type_generics.params { - match param.kind { - GenericParamDefKind::Lifetime => {} - _ => continue, - } - - // Get the value supplied for this region from the substs. - let subst_arg = opaque_defn.substs.region_at(param.index as usize); - - // Compute the least upper bound of it with the other regions. - debug!("constrain_opaque_types: least_region={:?}", least_region); - debug!("constrain_opaque_types: subst_arg={:?}", subst_arg); - match least_region { - None => least_region = Some(subst_arg), - Some(lr) => { - if free_region_relations.sub_free_regions(self.tcx, lr, subst_arg) { - // keep the current least region - } else if free_region_relations.sub_free_regions(self.tcx, subst_arg, lr) { - // switch to `subst_arg` - least_region = Some(subst_arg); - } else { - // There are two regions (`lr` and - // `subst_arg`) which are not relatable. We - // can't find a best choice. Therefore, - // instead of creating a single bound like - // `'r: 'a` (which is our preferred choice), - // we will create a "in bound" like `'r in - // ['a, 'b, 'c]`, where `'a..'c` are the - // regions that appear in the impl trait. - - // For now, enforce a feature gate outside of async functions. - self.member_constraint_feature_gate(opaque_defn, def_id, lr, subst_arg); - - return self.generate_member_constraint( - concrete_ty, - opaque_type_generics, - opaque_defn, - def_id, - ); - } - } - } - } - - let least_region = least_region.unwrap_or(tcx.lifetimes.re_static); - debug!("constrain_opaque_types: least_region={:?}", least_region); - - if let GenerateMemberConstraints::IfNoStaticBound = mode { - if least_region != tcx.lifetimes.re_static { - self.generate_member_constraint( - concrete_ty, - opaque_type_generics, - opaque_defn, - def_id, - ); - } - } - concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor { - tcx: self.tcx, - op: |r| self.sub_regions(infer::CallReturn(span), least_region, r), - }); - } - - /// As a fallback, we sometimes generate an "in constraint". For - /// a case like `impl Foo<'a, 'b>`, where `'a` and `'b` cannot be - /// related, we would generate a constraint `'r in ['a, 'b, - /// 'static]` for each region `'r` that appears in the hidden type - /// (i.e., it must be equal to `'a`, `'b`, or `'static`). - /// - /// `conflict1` and `conflict2` are the two region bounds that we - /// detected which were unrelated. They are used for diagnostics. - fn generate_member_constraint( - &self, - concrete_ty: Ty<'tcx>, - opaque_type_generics: &ty::Generics, - opaque_defn: &OpaqueTypeDecl<'tcx>, - opaque_type_def_id: DefId, - ) { - // Create the set of choice regions: each region in the hidden - // type can be equal to any of the region parameters of the - // opaque type definition. - let choice_regions: Lrc<Vec<ty::Region<'tcx>>> = Lrc::new( - opaque_type_generics - .params - .iter() - .filter(|param| match param.kind { - GenericParamDefKind::Lifetime => true, - GenericParamDefKind::Type { .. } | GenericParamDefKind::Const => false, - }) - .map(|param| opaque_defn.substs.region_at(param.index as usize)) - .chain(std::iter::once(self.tcx.lifetimes.re_static)) - .collect(), - ); - - concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor { - tcx: self.tcx, - op: |r| { - self.member_constraint( - opaque_type_def_id, - opaque_defn.definition_span, - concrete_ty, - r, - &choice_regions, - ) - }, - }); - } - - /// Member constraints are presently feature-gated except for - /// async-await. We expect to lift this once we've had a bit more - /// time. - fn member_constraint_feature_gate( - &self, - opaque_defn: &OpaqueTypeDecl<'tcx>, - opaque_type_def_id: DefId, - conflict1: ty::Region<'tcx>, - conflict2: ty::Region<'tcx>, - ) -> bool { - // If we have `#![feature(member_constraints)]`, no problems. - if self.tcx.features().member_constraints { - return false; - } - - let span = self.tcx.def_span(opaque_type_def_id); - - // Without a feature-gate, we only generate member-constraints for async-await. - let context_name = match opaque_defn.origin { - // No feature-gate required for `async fn`. - hir::OpaqueTyOrigin::AsyncFn => return false, - - // Otherwise, generate the label we'll use in the error message. - hir::OpaqueTyOrigin::TypeAlias - | hir::OpaqueTyOrigin::FnReturn - | hir::OpaqueTyOrigin::Misc => "impl Trait", - }; - let msg = format!("ambiguous lifetime bound in `{}`", context_name); - let mut err = self.tcx.sess.struct_span_err(span, &msg); - - let conflict1_name = conflict1.to_string(); - let conflict2_name = conflict2.to_string(); - let label_owned; - let label = match (&*conflict1_name, &*conflict2_name) { - ("'_", "'_") => "the elided lifetimes here do not outlive one another", - _ => { - label_owned = format!( - "neither `{}` nor `{}` outlives the other", - conflict1_name, conflict2_name, - ); - &label_owned - } - }; - err.span_label(span, label); - - if nightly_options::is_nightly_build() { - err.help("add #![feature(member_constraints)] to the crate attributes to enable"); - } - - err.emit(); - true - } - - /// Given the fully resolved, instantiated type for an opaque - /// type, i.e., the value of an inference variable like C1 or C2 - /// (*), computes the "definition type" for an opaque type - /// definition -- that is, the inferred value of `Foo1<'x>` or - /// `Foo2<'x>` that we would conceptually use in its definition: - /// - /// type Foo1<'x> = impl Bar<'x> = AAA; <-- this type AAA - /// type Foo2<'x> = impl Bar<'x> = BBB; <-- or this type BBB - /// fn foo<'a, 'b>(..) -> (Foo1<'a>, Foo2<'b>) { .. } - /// - /// Note that these values are defined in terms of a distinct set of - /// generic parameters (`'x` instead of `'a`) from C1 or C2. The main - /// purpose of this function is to do that translation. - /// - /// (*) C1 and C2 were introduced in the comments on - /// `constrain_opaque_types`. Read that comment for more context. - /// - /// # Parameters - /// - /// - `def_id`, the `impl Trait` type - /// - `substs`, the substs used to instantiate this opaque type - /// - `instantiated_ty`, the inferred type C1 -- fully resolved, lifted version of - /// `opaque_defn.concrete_ty` - pub fn infer_opaque_definition_from_instantiation( - &self, - def_id: DefId, - substs: SubstsRef<'tcx>, - instantiated_ty: Ty<'tcx>, - span: Span, - ) -> Ty<'tcx> { - debug!( - "infer_opaque_definition_from_instantiation(def_id={:?}, instantiated_ty={:?})", - def_id, instantiated_ty - ); - - // Use substs to build up a reverse map from regions to their - // identity mappings. This is necessary because of `impl - // Trait` lifetimes are computed by replacing existing - // lifetimes with 'static and remapping only those used in the - // `impl Trait` return type, resulting in the parameters - // shifting. - let id_substs = InternalSubsts::identity_for_item(self.tcx, def_id); - let map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>> = - substs.iter().enumerate().map(|(index, subst)| (*subst, id_substs[index])).collect(); - - // Convert the type from the function into a type valid outside - // the function, by replacing invalid regions with 'static, - // after producing an error for each of them. - let definition_ty = instantiated_ty.fold_with(&mut ReverseMapper::new( - self.tcx, - self.is_tainted_by_errors(), - def_id, - map, - instantiated_ty, - span, - )); - debug!("infer_opaque_definition_from_instantiation: definition_ty={:?}", definition_ty); - - definition_ty - } -} - -pub fn unexpected_hidden_region_diagnostic( - tcx: TyCtxt<'tcx>, - region_scope_tree: Option<®ion::ScopeTree>, - span: Span, - hidden_ty: Ty<'tcx>, - hidden_region: ty::Region<'tcx>, -) -> DiagnosticBuilder<'tcx> { - let mut err = struct_span_err!( - tcx.sess, - span, - E0700, - "hidden type for `impl Trait` captures lifetime that does not appear in bounds", - ); - - // Explain the region we are capturing. - if let ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReStatic | ty::ReEmpty(_) = hidden_region { - // Assuming regionck succeeded (*), we ought to always be - // capturing *some* region from the fn header, and hence it - // ought to be free. So under normal circumstances, we will go - // down this path which gives a decent human readable - // explanation. - // - // (*) if not, the `tainted_by_errors` flag would be set to - // true in any case, so we wouldn't be here at all. - note_and_explain_free_region( - tcx, - &mut err, - &format!("hidden type `{}` captures ", hidden_ty), - hidden_region, - "", - ); - } else { - // Ugh. This is a painful case: the hidden region is not one - // that we can easily summarize or explain. This can happen - // in a case like - // `src/test/ui/multiple-lifetimes/ordinary-bounds-unsuited.rs`: - // - // ``` - // fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b> { - // if condition() { a } else { b } - // } - // ``` - // - // Here the captured lifetime is the intersection of `'a` and - // `'b`, which we can't quite express. - - if let Some(region_scope_tree) = region_scope_tree { - // If the `region_scope_tree` is available, this is being - // invoked from the "region inferencer error". We can at - // least report a really cryptic error for now. - note_and_explain_region( - tcx, - region_scope_tree, - &mut err, - &format!("hidden type `{}` captures ", hidden_ty), - hidden_region, - "", - ); - } else { - // If the `region_scope_tree` is *unavailable*, this is - // being invoked by the code that comes *after* region - // inferencing. This is a bug, as the region inferencer - // ought to have noticed the failed constraint and invoked - // error reporting, which in turn should have prevented us - // from getting trying to infer the hidden type - // completely. - tcx.sess.delay_span_bug( - span, - &format!( - "hidden type captures unexpected lifetime `{:?}` \ - but no region inference failure", - hidden_region, - ), - ); - } - } - - err -} - -// Visitor that requires that (almost) all regions in the type visited outlive -// `least_region`. We cannot use `push_outlives_components` because regions in -// closure signatures are not included in their outlives components. We need to -// ensure all regions outlive the given bound so that we don't end up with, -// say, `ReScope` appearing in a return type and causing ICEs when other -// functions end up with region constraints involving regions from other -// functions. -// -// We also cannot use `for_each_free_region` because for closures it includes -// the regions parameters from the enclosing item. -// -// We ignore any type parameters because impl trait values are assumed to -// capture all the in-scope type parameters. -struct ConstrainOpaqueTypeRegionVisitor<'tcx, OP> -where - OP: FnMut(ty::Region<'tcx>), -{ - tcx: TyCtxt<'tcx>, - op: OP, -} - -impl<'tcx, OP> TypeVisitor<'tcx> for ConstrainOpaqueTypeRegionVisitor<'tcx, OP> -where - OP: FnMut(ty::Region<'tcx>), -{ - fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &ty::Binder<T>) -> bool { - t.skip_binder().visit_with(self); - false // keep visiting - } - - fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { - match *r { - // ignore bound regions, keep visiting - ty::ReLateBound(_, _) => false, - _ => { - (self.op)(r); - false - } - } - } - - fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { - // We're only interested in types involving regions - if !ty.flags.intersects(ty::TypeFlags::HAS_FREE_REGIONS) { - return false; // keep visiting - } - - match ty.kind { - ty::Closure(def_id, ref substs) => { - // Skip lifetime parameters of the enclosing item(s) - - for upvar_ty in substs.as_closure().upvar_tys(def_id, self.tcx) { - upvar_ty.visit_with(self); - } - - substs.as_closure().sig_ty(def_id, self.tcx).visit_with(self); - } - - ty::Generator(def_id, ref substs, _) => { - // Skip lifetime parameters of the enclosing item(s) - // Also skip the witness type, because that has no free regions. - - for upvar_ty in substs.as_generator().upvar_tys(def_id, self.tcx) { - upvar_ty.visit_with(self); - } - - substs.as_generator().return_ty(def_id, self.tcx).visit_with(self); - substs.as_generator().yield_ty(def_id, self.tcx).visit_with(self); - substs.as_generator().resume_ty(def_id, self.tcx).visit_with(self); - } - _ => { - ty.super_visit_with(self); - } - } - - false - } -} - -struct ReverseMapper<'tcx> { - tcx: TyCtxt<'tcx>, - - /// If errors have already been reported in this fn, we suppress - /// our own errors because they are sometimes derivative. - tainted_by_errors: bool, - - opaque_type_def_id: DefId, - map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>, - map_missing_regions_to_empty: bool, - - /// initially `Some`, set to `None` once error has been reported - hidden_ty: Option<Ty<'tcx>>, - - /// Span of function being checked. - span: Span, -} - -impl ReverseMapper<'tcx> { - fn new( - tcx: TyCtxt<'tcx>, - tainted_by_errors: bool, - opaque_type_def_id: DefId, - map: FxHashMap<GenericArg<'tcx>, GenericArg<'tcx>>, - hidden_ty: Ty<'tcx>, - span: Span, - ) -> Self { - Self { - tcx, - tainted_by_errors, - opaque_type_def_id, - map, - map_missing_regions_to_empty: false, - hidden_ty: Some(hidden_ty), - span, - } - } - - fn fold_kind_mapping_missing_regions_to_empty( - &mut self, - kind: GenericArg<'tcx>, - ) -> GenericArg<'tcx> { - assert!(!self.map_missing_regions_to_empty); - self.map_missing_regions_to_empty = true; - let kind = kind.fold_with(self); - self.map_missing_regions_to_empty = false; - kind - } - - fn fold_kind_normally(&mut self, kind: GenericArg<'tcx>) -> GenericArg<'tcx> { - assert!(!self.map_missing_regions_to_empty); - kind.fold_with(self) - } -} - -impl TypeFolder<'tcx> for ReverseMapper<'tcx> { - fn tcx(&self) -> TyCtxt<'tcx> { - self.tcx - } - - fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { - match r { - // Ignore bound regions and `'static` regions that appear in the - // type, we only need to remap regions that reference lifetimes - // from the function declaraion. - // This would ignore `'r` in a type like `for<'r> fn(&'r u32)`. - ty::ReLateBound(..) | ty::ReStatic => return r, - - // If regions have been erased (by writeback), don't try to unerase - // them. - ty::ReErased => return r, - - // The regions that we expect from borrow checking. - ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReEmpty(ty::UniverseIndex::ROOT) => {} - - ty::ReEmpty(_) - | ty::RePlaceholder(_) - | ty::ReVar(_) - | ty::ReScope(_) - | ty::ReClosureBound(_) => { - // All of the regions in the type should either have been - // erased by writeback, or mapped back to named regions by - // borrow checking. - bug!("unexpected region kind in opaque type: {:?}", r); - } - } - - let generics = self.tcx().generics_of(self.opaque_type_def_id); - match self.map.get(&r.into()).map(|k| k.unpack()) { - Some(GenericArgKind::Lifetime(r1)) => r1, - Some(u) => panic!("region mapped to unexpected kind: {:?}", u), - None if self.map_missing_regions_to_empty || self.tainted_by_errors => { - self.tcx.lifetimes.re_root_empty - } - None if generics.parent.is_some() => { - if let Some(hidden_ty) = self.hidden_ty.take() { - unexpected_hidden_region_diagnostic( - self.tcx, - None, - self.tcx.def_span(self.opaque_type_def_id), - hidden_ty, - r, - ) - .emit(); - } - self.tcx.lifetimes.re_root_empty - } - None => { - self.tcx - .sess - .struct_span_err(self.span, "non-defining opaque type use in defining scope") - .span_label( - self.span, - format!( - "lifetime `{}` is part of concrete type but not used in \ - parameter list of the `impl Trait` type alias", - r - ), - ) - .emit(); - - self.tcx().lifetimes.re_static - } - } - } - - fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - match ty.kind { - ty::Closure(def_id, substs) => { - // I am a horrible monster and I pray for death. When - // we encounter a closure here, it is always a closure - // from within the function that we are currently - // type-checking -- one that is now being encapsulated - // in an opaque type. Ideally, we would - // go through the types/lifetimes that it references - // and treat them just like we would any other type, - // which means we would error out if we find any - // reference to a type/region that is not in the - // "reverse map". - // - // **However,** in the case of closures, there is a - // somewhat subtle (read: hacky) consideration. The - // problem is that our closure types currently include - // all the lifetime parameters declared on the - // enclosing function, even if they are unused by the - // closure itself. We can't readily filter them out, - // so here we replace those values with `'empty`. This - // can't really make a difference to the rest of the - // compiler; those regions are ignored for the - // outlives relation, and hence don't affect trait - // selection or auto traits, and they are erased - // during codegen. - - let generics = self.tcx.generics_of(def_id); - let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, &kind)| { - if index < generics.parent_count { - // Accommodate missing regions in the parent kinds... - self.fold_kind_mapping_missing_regions_to_empty(kind) - } else { - // ...but not elsewhere. - self.fold_kind_normally(kind) - } - })); - - self.tcx.mk_closure(def_id, substs) - } - - ty::Generator(def_id, substs, movability) => { - let generics = self.tcx.generics_of(def_id); - let substs = self.tcx.mk_substs(substs.iter().enumerate().map(|(index, &kind)| { - if index < generics.parent_count { - // Accommodate missing regions in the parent kinds... - self.fold_kind_mapping_missing_regions_to_empty(kind) - } else { - // ...but not elsewhere. - self.fold_kind_normally(kind) - } - })); - - self.tcx.mk_generator(def_id, substs, movability) - } - - ty::Param(..) => { - // Look it up in the substitution list. - match self.map.get(&ty.into()).map(|k| k.unpack()) { - // Found it in the substitution list; replace with the parameter from the - // opaque type. - Some(GenericArgKind::Type(t1)) => t1, - Some(u) => panic!("type mapped to unexpected kind: {:?}", u), - None => { - self.tcx - .sess - .struct_span_err( - self.span, - &format!( - "type parameter `{}` is part of concrete type but not \ - used in parameter list for the `impl Trait` type alias", - ty - ), - ) - .emit(); - - self.tcx().types.err - } - } - } - - _ => ty.super_fold_with(self), - } - } - - fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { - trace!("checking const {:?}", ct); - // Find a const parameter - match ct.val { - ty::ConstKind::Param(..) => { - // Look it up in the substitution list. - match self.map.get(&ct.into()).map(|k| k.unpack()) { - // Found it in the substitution list, replace with the parameter from the - // opaque type. - Some(GenericArgKind::Const(c1)) => c1, - Some(u) => panic!("const mapped to unexpected kind: {:?}", u), - None => { - self.tcx - .sess - .struct_span_err( - self.span, - &format!( - "const parameter `{}` is part of concrete type but not \ - used in parameter list for the `impl Trait` type alias", - ct - ), - ) - .emit(); - - self.tcx().consts.err - } - } - } - - _ => ct, - } - } -} - -struct Instantiator<'a, 'tcx> { - infcx: &'a InferCtxt<'a, 'tcx>, - parent_def_id: DefId, - body_id: hir::HirId, - param_env: ty::ParamEnv<'tcx>, - value_span: Span, - opaque_types: OpaqueTypeMap<'tcx>, - obligations: Vec<PredicateObligation<'tcx>>, -} - -impl<'a, 'tcx> Instantiator<'a, 'tcx> { - fn instantiate_opaque_types_in_map<T: TypeFoldable<'tcx>>(&mut self, value: &T) -> T { - debug!("instantiate_opaque_types_in_map(value={:?})", value); - let tcx = self.infcx.tcx; - value.fold_with(&mut BottomUpFolder { - tcx, - ty_op: |ty| { - if ty.references_error() { - return tcx.types.err; - } else if let ty::Opaque(def_id, substs) = ty.kind { - // Check that this is `impl Trait` type is - // declared by `parent_def_id` -- i.e., one whose - // value we are inferring. At present, this is - // always true during the first phase of - // type-check, but not always true later on during - // NLL. Once we support named opaque types more fully, - // this same scenario will be able to arise during all phases. - // - // Here is an example using type alias `impl Trait` - // that indicates the distinction we are checking for: - // - // ```rust - // mod a { - // pub type Foo = impl Iterator; - // pub fn make_foo() -> Foo { .. } - // } - // - // mod b { - // fn foo() -> a::Foo { a::make_foo() } - // } - // ``` - // - // Here, the return type of `foo` references a - // `Opaque` indeed, but not one whose value is - // presently being inferred. You can get into a - // similar situation with closure return types - // today: - // - // ```rust - // fn foo() -> impl Iterator { .. } - // fn bar() { - // let x = || foo(); // returns the Opaque assoc with `foo` - // } - // ``` - if let Some(opaque_hir_id) = tcx.hir().as_local_hir_id(def_id) { - let parent_def_id = self.parent_def_id; - let def_scope_default = || { - let opaque_parent_hir_id = tcx.hir().get_parent_item(opaque_hir_id); - parent_def_id == tcx.hir().local_def_id(opaque_parent_hir_id) - }; - let (in_definition_scope, origin) = match tcx.hir().find(opaque_hir_id) { - Some(Node::Item(item)) => match item.kind { - // Anonymous `impl Trait` - hir::ItemKind::OpaqueTy(hir::OpaqueTy { - impl_trait_fn: Some(parent), - origin, - .. - }) => (parent == self.parent_def_id, origin), - // Named `type Foo = impl Bar;` - hir::ItemKind::OpaqueTy(hir::OpaqueTy { - impl_trait_fn: None, - origin, - .. - }) => ( - may_define_opaque_type(tcx, self.parent_def_id, opaque_hir_id), - origin, - ), - _ => (def_scope_default(), hir::OpaqueTyOrigin::TypeAlias), - }, - Some(Node::ImplItem(item)) => match item.kind { - hir::ImplItemKind::OpaqueTy(_) => ( - may_define_opaque_type(tcx, self.parent_def_id, opaque_hir_id), - hir::OpaqueTyOrigin::TypeAlias, - ), - _ => (def_scope_default(), hir::OpaqueTyOrigin::TypeAlias), - }, - _ => bug!( - "expected (impl) item, found {}", - tcx.hir().node_to_string(opaque_hir_id), - ), - }; - if in_definition_scope { - return self.fold_opaque_ty(ty, def_id, substs, origin); - } - - debug!( - "instantiate_opaque_types_in_map: \ - encountered opaque outside its definition scope \ - def_id={:?}", - def_id, - ); - } - } - - ty - }, - lt_op: |lt| lt, - ct_op: |ct| ct, - }) - } - - fn fold_opaque_ty( - &mut self, - ty: Ty<'tcx>, - def_id: DefId, - substs: SubstsRef<'tcx>, - origin: hir::OpaqueTyOrigin, - ) -> Ty<'tcx> { - let infcx = self.infcx; - let tcx = infcx.tcx; - - debug!("instantiate_opaque_types: Opaque(def_id={:?}, substs={:?})", def_id, substs); - - // Use the same type variable if the exact same opaque type appears more - // than once in the return type (e.g., if it's passed to a type alias). - if let Some(opaque_defn) = self.opaque_types.get(&def_id) { - debug!("instantiate_opaque_types: returning concrete ty {:?}", opaque_defn.concrete_ty); - return opaque_defn.concrete_ty; - } - let span = tcx.def_span(def_id); - debug!("fold_opaque_ty {:?} {:?}", self.value_span, span); - let ty_var = infcx - .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span }); - - let predicates_of = tcx.predicates_of(def_id); - debug!("instantiate_opaque_types: predicates={:#?}", predicates_of,); - let bounds = predicates_of.instantiate(tcx, substs); - - let param_env = tcx.param_env(def_id); - let InferOk { value: bounds, obligations } = - infcx.partially_normalize_associated_types_in(span, self.body_id, param_env, &bounds); - self.obligations.extend(obligations); - - debug!("instantiate_opaque_types: bounds={:?}", bounds); - - let required_region_bounds = required_region_bounds(tcx, ty, bounds.predicates.clone()); - debug!("instantiate_opaque_types: required_region_bounds={:?}", required_region_bounds); - - // Make sure that we are in fact defining the *entire* type - // (e.g., `type Foo<T: Bound> = impl Bar;` needs to be - // defined by a function like `fn foo<T: Bound>() -> Foo<T>`). - debug!("instantiate_opaque_types: param_env={:#?}", self.param_env,); - debug!("instantiate_opaque_types: generics={:#?}", tcx.generics_of(def_id),); - - // Ideally, we'd get the span where *this specific `ty` came - // from*, but right now we just use the span from the overall - // value being folded. In simple cases like `-> impl Foo`, - // these are the same span, but not in cases like `-> (impl - // Foo, impl Bar)`. - let definition_span = self.value_span; - - self.opaque_types.insert( - def_id, - OpaqueTypeDecl { - opaque_type: ty, - substs, - definition_span, - concrete_ty: ty_var, - has_required_region_bounds: !required_region_bounds.is_empty(), - origin, - }, - ); - debug!("instantiate_opaque_types: ty_var={:?}", ty_var); - - for predicate in &bounds.predicates { - if let ty::Predicate::Projection(projection) = &predicate { - if projection.skip_binder().ty.references_error() { - // No point on adding these obligations since there's a type error involved. - return ty_var; - } - } - } - - self.obligations.reserve(bounds.predicates.len()); - for predicate in bounds.predicates { - // Change the predicate to refer to the type variable, - // which will be the concrete type instead of the opaque type. - // This also instantiates nested instances of `impl Trait`. - let predicate = self.instantiate_opaque_types_in_map(&predicate); - - let cause = traits::ObligationCause::new(span, self.body_id, traits::SizedReturnType); - - // Require that the predicate holds for the concrete type. - debug!("instantiate_opaque_types: predicate={:?}", predicate); - self.obligations.push(traits::Obligation::new(cause, self.param_env, predicate)); - } - - ty_var - } -} - -/// Returns `true` if `opaque_hir_id` is a sibling or a child of a sibling of `def_id`. -/// -/// Example: -/// ```rust -/// pub mod foo { -/// pub mod bar { -/// pub trait Bar { .. } -/// -/// pub type Baz = impl Bar; -/// -/// fn f1() -> Baz { .. } -/// } -/// -/// fn f2() -> bar::Baz { .. } -/// } -/// ``` -/// -/// Here, `def_id` is the `DefId` of the defining use of the opaque type (e.g., `f1` or `f2`), -/// and `opaque_hir_id` is the `HirId` of the definition of the opaque type `Baz`. -/// For the above example, this function returns `true` for `f1` and `false` for `f2`. -pub fn may_define_opaque_type(tcx: TyCtxt<'_>, def_id: DefId, opaque_hir_id: hir::HirId) -> bool { - let mut hir_id = tcx.hir().as_local_hir_id(def_id).unwrap(); - - // Named opaque types can be defined by any siblings or children of siblings. - let scope = tcx.hir().get_defining_scope(opaque_hir_id); - // We walk up the node tree until we hit the root or the scope of the opaque type. - while hir_id != scope && hir_id != hir::CRATE_HIR_ID { - hir_id = tcx.hir().get_parent_item(hir_id); - } - // Syntactically, we are allowed to define the concrete type if: - let res = hir_id == scope; - trace!( - "may_define_opaque_type(def={:?}, opaque_node={:?}) = {}", - tcx.hir().find(hir_id), - tcx.hir().get(opaque_hir_id), - res - ); - res -} - -/// Given a set of predicates that apply to an object type, returns -/// the region bounds that the (erased) `Self` type must -/// outlive. Precisely *because* the `Self` type is erased, the -/// parameter `erased_self_ty` must be supplied to indicate what type -/// has been used to represent `Self` in the predicates -/// themselves. This should really be a unique type; `FreshTy(0)` is a -/// popular choice. -/// -/// N.B., in some cases, particularly around higher-ranked bounds, -/// this function returns a kind of conservative approximation. -/// That is, all regions returned by this function are definitely -/// required, but there may be other region bounds that are not -/// returned, as well as requirements like `for<'a> T: 'a`. -/// -/// Requires that trait definitions have been processed so that we can -/// elaborate predicates and walk supertraits. -// -// FIXME: callers may only have a `&[Predicate]`, not a `Vec`, so that's -// what this code should accept. -crate fn required_region_bounds( - tcx: TyCtxt<'tcx>, - erased_self_ty: Ty<'tcx>, - predicates: Vec<ty::Predicate<'tcx>>, -) -> Vec<ty::Region<'tcx>> { - debug!( - "required_region_bounds(erased_self_ty={:?}, predicates={:?})", - erased_self_ty, predicates - ); - - assert!(!erased_self_ty.has_escaping_bound_vars()); - - traits::elaborate_predicates(tcx, predicates) - .filter_map(|predicate| { - match predicate { - ty::Predicate::Projection(..) - | ty::Predicate::Trait(..) - | ty::Predicate::Subtype(..) - | ty::Predicate::WellFormed(..) - | ty::Predicate::ObjectSafe(..) - | ty::Predicate::ClosureKind(..) - | ty::Predicate::RegionOutlives(..) - | ty::Predicate::ConstEvaluatable(..) => None, - ty::Predicate::TypeOutlives(predicate) => { - // Search for a bound of the form `erased_self_ty - // : 'a`, but be wary of something like `for<'a> - // erased_self_ty : 'a` (we interpret a - // higher-ranked bound like that as 'static, - // though at present the code in `fulfill.rs` - // considers such bounds to be unsatisfiable, so - // it's kind of a moot point since you could never - // construct such an object, but this seems - // correct even if that code changes). - let ty::OutlivesPredicate(ref t, ref r) = predicate.skip_binder(); - if t == &erased_self_ty && !r.has_escaping_bound_vars() { - Some(*r) - } else { - None - } - } - } - }) - .collect() -} diff --git a/src/librustc/infer/outlives/env.rs b/src/librustc/infer/outlives/env.rs deleted file mode 100644 index ee2e629c2fc..00000000000 --- a/src/librustc/infer/outlives/env.rs +++ /dev/null @@ -1,227 +0,0 @@ -use crate::infer::{GenericKind, InferCtxt}; -use crate::traits::query::outlives_bounds::{self, OutlivesBound}; -use crate::ty::free_region_map::FreeRegionMap; -use crate::ty::{self, Ty}; -use rustc_data_structures::fx::FxHashMap; -use rustc_hir as hir; -use rustc_span::Span; - -/// The `OutlivesEnvironment` collects information about what outlives -/// what in a given type-checking setting. For example, if we have a -/// where-clause like `where T: 'a` in scope, then the -/// `OutlivesEnvironment` would record that (in its -/// `region_bound_pairs` field). Similarly, it contains methods for -/// processing and adding implied bounds into the outlives -/// environment. -/// -/// Other code at present does not typically take a -/// `&OutlivesEnvironment`, but rather takes some of its fields (e.g., -/// `process_registered_region_obligations` wants the -/// region-bound-pairs). There is no mistaking it: the current setup -/// of tracking region information is quite scattered! The -/// `OutlivesEnvironment`, for example, needs to sometimes be combined -/// with the `middle::RegionRelations`, to yield a full picture of how -/// (lexical) lifetimes interact. However, I'm reluctant to do more -/// refactoring here, since the setup with NLL is quite different. -/// For example, NLL has no need of `RegionRelations`, and is solely -/// interested in the `OutlivesEnvironment`. -nmatsakis -#[derive(Clone)] -pub struct OutlivesEnvironment<'tcx> { - pub param_env: ty::ParamEnv<'tcx>, - free_region_map: FreeRegionMap<'tcx>, - - // Contains, for each body B that we are checking (that is, the fn - // item, but also any nested closures), the set of implied region - // bounds that are in scope in that particular body. - // - // Example: - // - // ``` - // fn foo<'a, 'b, T>(x: &'a T, y: &'b ()) { - // bar(x, y, |y: &'b T| { .. } // body B1) - // } // body B0 - // ``` - // - // Here, for body B0, the list would be `[T: 'a]`, because we - // infer that `T` must outlive `'a` from the implied bounds on the - // fn declaration. - // - // For the body B1, the list would be `[T: 'a, T: 'b]`, because we - // also can see that -- within the closure body! -- `T` must - // outlive `'b`. This is not necessarily true outside the closure - // body, since the closure may never be called. - // - // We collect this map as we descend the tree. We then use the - // results when proving outlives obligations like `T: 'x` later - // (e.g., if `T: 'x` must be proven within the body B1, then we - // know it is true if either `'a: 'x` or `'b: 'x`). - region_bound_pairs_map: FxHashMap<hir::HirId, RegionBoundPairs<'tcx>>, - - // Used to compute `region_bound_pairs_map`: contains the set of - // in-scope region-bound pairs thus far. - region_bound_pairs_accum: RegionBoundPairs<'tcx>, -} - -/// "Region-bound pairs" tracks outlives relations that are known to -/// be true, either because of explicit where-clauses like `T: 'a` or -/// because of implied bounds. -pub type RegionBoundPairs<'tcx> = Vec<(ty::Region<'tcx>, GenericKind<'tcx>)>; - -impl<'a, 'tcx> OutlivesEnvironment<'tcx> { - pub fn new(param_env: ty::ParamEnv<'tcx>) -> Self { - let mut env = OutlivesEnvironment { - param_env, - free_region_map: Default::default(), - region_bound_pairs_map: Default::default(), - region_bound_pairs_accum: vec![], - }; - - env.add_outlives_bounds(None, outlives_bounds::explicit_outlives_bounds(param_env)); - - env - } - - /// Borrows current value of the `free_region_map`. - pub fn free_region_map(&self) -> &FreeRegionMap<'tcx> { - &self.free_region_map - } - - /// Borrows current value of the `region_bound_pairs`. - pub fn region_bound_pairs_map(&self) -> &FxHashMap<hir::HirId, RegionBoundPairs<'tcx>> { - &self.region_bound_pairs_map - } - - /// Returns ownership of the `free_region_map`. - pub fn into_free_region_map(self) -> FreeRegionMap<'tcx> { - self.free_region_map - } - - /// This is a hack to support the old-skool regionck, which - /// processes region constraints from the main function and the - /// closure together. In that context, when we enter a closure, we - /// want to be able to "save" the state of the surrounding a - /// function. We can then add implied bounds and the like from the - /// closure arguments into the environment -- these should only - /// apply in the closure body, so once we exit, we invoke - /// `pop_snapshot_post_closure` to remove them. - /// - /// Example: - /// - /// ``` - /// fn foo<T>() { - /// callback(for<'a> |x: &'a T| { - /// // ^^^^^^^ not legal syntax, but probably should be - /// // within this closure body, `T: 'a` holds - /// }) - /// } - /// ``` - /// - /// This "containment" of closure's effects only works so well. In - /// particular, we (intentionally) leak relationships between free - /// regions that are created by the closure's bounds. The case - /// where this is useful is when you have (e.g.) a closure with a - /// signature like `for<'a, 'b> fn(x: &'a &'b u32)` -- in this - /// case, we want to keep the relationship `'b: 'a` in the - /// free-region-map, so that later if we have to take `LUB('b, - /// 'a)` we can get the result `'b`. - /// - /// I have opted to keep **all modifications** to the - /// free-region-map, however, and not just those that concern free - /// variables bound in the closure. The latter seems more correct, - /// but it is not the existing behavior, and I could not find a - /// case where the existing behavior went wrong. In any case, it - /// seems like it'd be readily fixed if we wanted. There are - /// similar leaks around givens that seem equally suspicious, to - /// be honest. --nmatsakis - pub fn push_snapshot_pre_closure(&self) -> usize { - self.region_bound_pairs_accum.len() - } - - /// See `push_snapshot_pre_closure`. - pub fn pop_snapshot_post_closure(&mut self, len: usize) { - self.region_bound_pairs_accum.truncate(len); - } - - /// This method adds "implied bounds" into the outlives environment. - /// Implied bounds are outlives relationships that we can deduce - /// on the basis that certain types must be well-formed -- these are - /// either the types that appear in the function signature or else - /// the input types to an impl. For example, if you have a function - /// like - /// - /// ``` - /// fn foo<'a, 'b, T>(x: &'a &'b [T]) { } - /// ``` - /// - /// we can assume in the caller's body that `'b: 'a` and that `T: - /// 'b` (and hence, transitively, that `T: 'a`). This method would - /// add those assumptions into the outlives-environment. - /// - /// Tests: `src/test/compile-fail/regions-free-region-ordering-*.rs` - pub fn add_implied_bounds( - &mut self, - infcx: &InferCtxt<'a, 'tcx>, - fn_sig_tys: &[Ty<'tcx>], - body_id: hir::HirId, - span: Span, - ) { - debug!("add_implied_bounds()"); - - for &ty in fn_sig_tys { - let ty = infcx.resolve_vars_if_possible(&ty); - debug!("add_implied_bounds: ty = {}", ty); - let implied_bounds = infcx.implied_outlives_bounds(self.param_env, body_id, ty, span); - self.add_outlives_bounds(Some(infcx), implied_bounds) - } - } - - /// Save the current set of region-bound pairs under the given `body_id`. - pub fn save_implied_bounds(&mut self, body_id: hir::HirId) { - let old = - self.region_bound_pairs_map.insert(body_id, self.region_bound_pairs_accum.clone()); - assert!(old.is_none()); - } - - /// Processes outlives bounds that are known to hold, whether from implied or other sources. - /// - /// The `infcx` parameter is optional; if the implied bounds may - /// contain inference variables, it must be supplied, in which - /// case we will register "givens" on the inference context. (See - /// `RegionConstraintData`.) - fn add_outlives_bounds<I>(&mut self, infcx: Option<&InferCtxt<'a, 'tcx>>, outlives_bounds: I) - where - I: IntoIterator<Item = OutlivesBound<'tcx>>, - { - // Record relationships such as `T:'x` that don't go into the - // free-region-map but which we use here. - for outlives_bound in outlives_bounds { - debug!("add_outlives_bounds: outlives_bound={:?}", outlives_bound); - match outlives_bound { - OutlivesBound::RegionSubRegion(r_a @ &ty::ReEarlyBound(_), &ty::ReVar(vid_b)) - | OutlivesBound::RegionSubRegion(r_a @ &ty::ReFree(_), &ty::ReVar(vid_b)) => { - infcx.expect("no infcx provided but region vars found").add_given(r_a, vid_b); - } - OutlivesBound::RegionSubParam(r_a, param_b) => { - self.region_bound_pairs_accum.push((r_a, GenericKind::Param(param_b))); - } - OutlivesBound::RegionSubProjection(r_a, projection_b) => { - self.region_bound_pairs_accum - .push((r_a, GenericKind::Projection(projection_b))); - } - OutlivesBound::RegionSubRegion(r_a, r_b) => { - // In principle, we could record (and take - // advantage of) every relationship here, but - // we are also free not to -- it simply means - // strictly less that we can successfully type - // check. Right now we only look for things - // relationships between free regions. (It may - // also be that we should revise our inference - // system to be more general and to make use - // of *every* relationship that arises here, - // but presently we do not.) - self.free_region_map.relate_regions(r_a, r_b); - } - } - } - } -} diff --git a/src/librustc/infer/outlives/mod.rs b/src/librustc/infer/outlives/mod.rs deleted file mode 100644 index 6fc72470c9f..00000000000 --- a/src/librustc/infer/outlives/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -//! Various code related to computing outlives relations. - -pub mod env; -pub mod obligations; -pub mod verify; diff --git a/src/librustc/infer/outlives/obligations.rs b/src/librustc/infer/outlives/obligations.rs deleted file mode 100644 index 17153ef9724..00000000000 --- a/src/librustc/infer/outlives/obligations.rs +++ /dev/null @@ -1,476 +0,0 @@ -//! Code that handles "type-outlives" constraints like `T: 'a`. This -//! is based on the `push_outlives_components` function defined on the tcx, -//! but it adds a bit of heuristics on top, in particular to deal with -//! associated types and projections. -//! -//! When we process a given `T: 'a` obligation, we may produce two -//! kinds of constraints for the region inferencer: -//! -//! - Relationships between inference variables and other regions. -//! For example, if we have `&'?0 u32: 'a`, then we would produce -//! a constraint that `'a <= '?0`. -//! - "Verifys" that must be checked after inferencing is done. -//! For example, if we know that, for some type parameter `T`, -//! `T: 'a + 'b`, and we have a requirement that `T: '?1`, -//! then we add a "verify" that checks that `'?1 <= 'a || '?1 <= 'b`. -//! - Note the difference with the previous case: here, the region -//! variable must be less than something else, so this doesn't -//! affect how inference works (it finds the smallest region that -//! will do); it's just a post-condition that we have to check. -//! -//! **The key point is that once this function is done, we have -//! reduced all of our "type-region outlives" obligations into relationships -//! between individual regions.** -//! -//! One key input to this function is the set of "region-bound pairs". -//! These are basically the relationships between type parameters and -//! regions that are in scope at the point where the outlives -//! obligation was incurred. **When type-checking a function, -//! particularly in the face of closures, this is not known until -//! regionck runs!** This is because some of those bounds come -//! from things we have yet to infer. -//! -//! Consider: -//! -//! ``` -//! fn bar<T>(a: T, b: impl for<'a> Fn(&'a T)); -//! fn foo<T>(x: T) { -//! bar(x, |y| { ... }) -//! // ^ closure arg -//! } -//! ``` -//! -//! Here, the type of `y` may involve inference variables and the -//! like, and it may also contain implied bounds that are needed to -//! type-check the closure body (e.g., here it informs us that `T` -//! outlives the late-bound region `'a`). -//! -//! Note that by delaying the gathering of implied bounds until all -//! inference information is known, we may find relationships between -//! bound regions and other regions in the environment. For example, -//! when we first check a closure like the one expected as argument -//! to `foo`: -//! -//! ``` -//! fn foo<U, F: for<'a> FnMut(&'a U)>(_f: F) {} -//! ``` -//! -//! the type of the closure's first argument would be `&'a ?U`. We -//! might later infer `?U` to something like `&'b u32`, which would -//! imply that `'b: 'a`. - -use crate::infer::outlives::env::RegionBoundPairs; -use crate::infer::outlives::verify::VerifyBoundCx; -use crate::infer::{self, GenericKind, InferCtxt, RegionObligation, SubregionOrigin, VerifyBound}; -use crate::traits::ObligationCause; -use crate::ty::outlives::Component; -use crate::ty::subst::GenericArgKind; -use crate::ty::{self, Region, Ty, TyCtxt, TypeFoldable}; -use rustc_data_structures::fx::FxHashMap; -use rustc_hir as hir; - -impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { - /// Registers that the given region obligation must be resolved - /// from within the scope of `body_id`. These regions are enqueued - /// and later processed by regionck, when full type information is - /// available (see `region_obligations` field for more - /// information). - pub fn register_region_obligation( - &self, - body_id: hir::HirId, - obligation: RegionObligation<'tcx>, - ) { - debug!("register_region_obligation(body_id={:?}, obligation={:?})", body_id, obligation); - - self.inner.borrow_mut().region_obligations.push((body_id, obligation)); - } - - pub fn register_region_obligation_with_cause( - &self, - sup_type: Ty<'tcx>, - sub_region: Region<'tcx>, - cause: &ObligationCause<'tcx>, - ) { - let origin = SubregionOrigin::from_obligation_cause(cause, || { - infer::RelateParamBound(cause.span, sup_type) - }); - - self.register_region_obligation( - cause.body_id, - RegionObligation { sup_type, sub_region, origin }, - ); - } - - /// Trait queries just want to pass back type obligations "as is" - pub fn take_registered_region_obligations(&self) -> Vec<(hir::HirId, RegionObligation<'tcx>)> { - ::std::mem::take(&mut self.inner.borrow_mut().region_obligations) - } - - /// Process the region obligations that must be proven (during - /// `regionck`) for the given `body_id`, given information about - /// the region bounds in scope and so forth. This function must be - /// invoked for all relevant body-ids before region inference is - /// done (or else an assert will fire). - /// - /// See the `region_obligations` field of `InferCtxt` for some - /// comments about how this function fits into the overall expected - /// flow of the inferencer. The key point is that it is - /// invoked after all type-inference variables have been bound -- - /// towards the end of regionck. This also ensures that the - /// region-bound-pairs are available (see comments above regarding - /// closures). - /// - /// # Parameters - /// - /// - `region_bound_pairs`: the set of region bounds implied by - /// the parameters and where-clauses. In particular, each pair - /// `('a, K)` in this list tells us that the bounds in scope - /// indicate that `K: 'a`, where `K` is either a generic - /// parameter like `T` or a projection like `T::Item`. - /// - `implicit_region_bound`: if some, this is a region bound - /// that is considered to hold for all type parameters (the - /// function body). - /// - `param_env` is the parameter environment for the enclosing function. - /// - `body_id` is the body-id whose region obligations are being - /// processed. - /// - /// # Returns - /// - /// This function may have to perform normalizations, and hence it - /// returns an `InferOk` with subobligations that must be - /// processed. - pub fn process_registered_region_obligations( - &self, - region_bound_pairs_map: &FxHashMap<hir::HirId, RegionBoundPairs<'tcx>>, - implicit_region_bound: Option<ty::Region<'tcx>>, - param_env: ty::ParamEnv<'tcx>, - ) { - assert!( - !self.in_snapshot.get(), - "cannot process registered region obligations in a snapshot" - ); - - debug!("process_registered_region_obligations()"); - - let my_region_obligations = self.take_registered_region_obligations(); - - for (body_id, RegionObligation { sup_type, sub_region, origin }) in my_region_obligations { - debug!( - "process_registered_region_obligations: sup_type={:?} sub_region={:?} origin={:?}", - sup_type, sub_region, origin - ); - - let sup_type = self.resolve_vars_if_possible(&sup_type); - - if let Some(region_bound_pairs) = region_bound_pairs_map.get(&body_id) { - let outlives = &mut TypeOutlives::new( - self, - self.tcx, - ®ion_bound_pairs, - implicit_region_bound, - param_env, - ); - outlives.type_must_outlive(origin, sup_type, sub_region); - } else { - self.tcx.sess.delay_span_bug( - origin.span(), - &format!("no region-bound-pairs for {:?}", body_id), - ) - } - } - } - - /// Processes a single ad-hoc region obligation that was not - /// registered in advance. - pub fn type_must_outlive( - &self, - region_bound_pairs: &RegionBoundPairs<'tcx>, - implicit_region_bound: Option<ty::Region<'tcx>>, - param_env: ty::ParamEnv<'tcx>, - origin: infer::SubregionOrigin<'tcx>, - ty: Ty<'tcx>, - region: ty::Region<'tcx>, - ) { - let outlives = &mut TypeOutlives::new( - self, - self.tcx, - region_bound_pairs, - implicit_region_bound, - param_env, - ); - let ty = self.resolve_vars_if_possible(&ty); - outlives.type_must_outlive(origin, ty, region); - } -} - -/// The `TypeOutlives` struct has the job of "lowering" a `T: 'a` -/// obligation into a series of `'a: 'b` constraints and "verify"s, as -/// described on the module comment. The final constraints are emitted -/// via a "delegate" of type `D` -- this is usually the `infcx`, which -/// accrues them into the `region_obligations` code, but for NLL we -/// use something else. -pub struct TypeOutlives<'cx, 'tcx, D> -where - D: TypeOutlivesDelegate<'tcx>, -{ - // See the comments on `process_registered_region_obligations` for the meaning - // of these fields. - delegate: D, - tcx: TyCtxt<'tcx>, - verify_bound: VerifyBoundCx<'cx, 'tcx>, -} - -pub trait TypeOutlivesDelegate<'tcx> { - fn push_sub_region_constraint( - &mut self, - origin: SubregionOrigin<'tcx>, - a: ty::Region<'tcx>, - b: ty::Region<'tcx>, - ); - - fn push_verify( - &mut self, - origin: SubregionOrigin<'tcx>, - kind: GenericKind<'tcx>, - a: ty::Region<'tcx>, - bound: VerifyBound<'tcx>, - ); -} - -impl<'cx, 'tcx, D> TypeOutlives<'cx, 'tcx, D> -where - D: TypeOutlivesDelegate<'tcx>, -{ - pub fn new( - delegate: D, - tcx: TyCtxt<'tcx>, - region_bound_pairs: &'cx RegionBoundPairs<'tcx>, - implicit_region_bound: Option<ty::Region<'tcx>>, - param_env: ty::ParamEnv<'tcx>, - ) -> Self { - Self { - delegate, - tcx, - verify_bound: VerifyBoundCx::new( - tcx, - region_bound_pairs, - implicit_region_bound, - param_env, - ), - } - } - - /// Adds constraints to inference such that `T: 'a` holds (or - /// reports an error if it cannot). - /// - /// # Parameters - /// - /// - `origin`, the reason we need this constraint - /// - `ty`, the type `T` - /// - `region`, the region `'a` - pub fn type_must_outlive( - &mut self, - origin: infer::SubregionOrigin<'tcx>, - ty: Ty<'tcx>, - region: ty::Region<'tcx>, - ) { - debug!("type_must_outlive(ty={:?}, region={:?}, origin={:?})", ty, region, origin); - - assert!(!ty.has_escaping_bound_vars()); - - let mut components = smallvec![]; - self.tcx.push_outlives_components(ty, &mut components); - self.components_must_outlive(origin, &components, region); - } - - fn components_must_outlive( - &mut self, - origin: infer::SubregionOrigin<'tcx>, - components: &[Component<'tcx>], - region: ty::Region<'tcx>, - ) { - for component in components.iter() { - let origin = origin.clone(); - match component { - Component::Region(region1) => { - self.delegate.push_sub_region_constraint(origin, region, region1); - } - Component::Param(param_ty) => { - self.param_ty_must_outlive(origin, region, *param_ty); - } - Component::Projection(projection_ty) => { - self.projection_must_outlive(origin, region, *projection_ty); - } - Component::EscapingProjection(subcomponents) => { - self.components_must_outlive(origin, &subcomponents, region); - } - Component::UnresolvedInferenceVariable(v) => { - // ignore this, we presume it will yield an error - // later, since if a type variable is not resolved by - // this point it never will be - self.tcx.sess.delay_span_bug( - origin.span(), - &format!("unresolved inference variable in outlives: {:?}", v), - ); - } - } - } - } - - fn param_ty_must_outlive( - &mut self, - origin: infer::SubregionOrigin<'tcx>, - region: ty::Region<'tcx>, - param_ty: ty::ParamTy, - ) { - debug!( - "param_ty_must_outlive(region={:?}, param_ty={:?}, origin={:?})", - region, param_ty, origin - ); - - let generic = GenericKind::Param(param_ty); - let verify_bound = self.verify_bound.generic_bound(generic); - self.delegate.push_verify(origin, generic, region, verify_bound); - } - - fn projection_must_outlive( - &mut self, - origin: infer::SubregionOrigin<'tcx>, - region: ty::Region<'tcx>, - projection_ty: ty::ProjectionTy<'tcx>, - ) { - debug!( - "projection_must_outlive(region={:?}, projection_ty={:?}, origin={:?})", - region, projection_ty, origin - ); - - // This case is thorny for inference. The fundamental problem is - // that there are many cases where we have choice, and inference - // doesn't like choice (the current region inference in - // particular). :) First off, we have to choose between using the - // OutlivesProjectionEnv, OutlivesProjectionTraitDef, and - // OutlivesProjectionComponent rules, any one of which is - // sufficient. If there are no inference variables involved, it's - // not hard to pick the right rule, but if there are, we're in a - // bit of a catch 22: if we picked which rule we were going to - // use, we could add constraints to the region inference graph - // that make it apply, but if we don't add those constraints, the - // rule might not apply (but another rule might). For now, we err - // on the side of adding too few edges into the graph. - - // Compute the bounds we can derive from the trait definition. - // These are guaranteed to apply, no matter the inference - // results. - let trait_bounds: Vec<_> = - self.verify_bound.projection_declared_bounds_from_trait(projection_ty).collect(); - - // Compute the bounds we can derive from the environment. This - // is an "approximate" match -- in some cases, these bounds - // may not apply. - let mut approx_env_bounds = - self.verify_bound.projection_approx_declared_bounds_from_env(projection_ty); - debug!("projection_must_outlive: approx_env_bounds={:?}", approx_env_bounds); - - // Remove outlives bounds that we get from the environment but - // which are also deducable from the trait. This arises (cc - // #55756) in cases where you have e.g., `<T as Foo<'a>>::Item: - // 'a` in the environment but `trait Foo<'b> { type Item: 'b - // }` in the trait definition. - approx_env_bounds.retain(|bound| match bound.0.kind { - ty::Projection(projection_ty) => self - .verify_bound - .projection_declared_bounds_from_trait(projection_ty) - .all(|r| r != bound.1), - - _ => panic!("expected only projection types from env, not {:?}", bound.0), - }); - - // If declared bounds list is empty, the only applicable rule is - // OutlivesProjectionComponent. If there are inference variables, - // then, we can break down the outlives into more primitive - // components without adding unnecessary edges. - // - // If there are *no* inference variables, however, we COULD do - // this, but we choose not to, because the error messages are less - // good. For example, a requirement like `T::Item: 'r` would be - // translated to a requirement that `T: 'r`; when this is reported - // to the user, it will thus say "T: 'r must hold so that T::Item: - // 'r holds". But that makes it sound like the only way to fix - // the problem is to add `T: 'r`, which isn't true. So, if there are no - // inference variables, we use a verify constraint instead of adding - // edges, which winds up enforcing the same condition. - let needs_infer = projection_ty.needs_infer(); - if approx_env_bounds.is_empty() && trait_bounds.is_empty() && needs_infer { - debug!("projection_must_outlive: no declared bounds"); - - for k in projection_ty.substs { - match k.unpack() { - GenericArgKind::Lifetime(lt) => { - self.delegate.push_sub_region_constraint(origin.clone(), region, lt); - } - GenericArgKind::Type(ty) => { - self.type_must_outlive(origin.clone(), ty, region); - } - GenericArgKind::Const(_) => { - // Const parameters don't impose constraints. - } - } - } - - return; - } - - // If we found a unique bound `'b` from the trait, and we - // found nothing else from the environment, then the best - // action is to require that `'b: 'r`, so do that. - // - // This is best no matter what rule we use: - // - // - OutlivesProjectionEnv: these would translate to the requirement that `'b:'r` - // - OutlivesProjectionTraitDef: these would translate to the requirement that `'b:'r` - // - OutlivesProjectionComponent: this would require `'b:'r` - // in addition to other conditions - if !trait_bounds.is_empty() - && trait_bounds[1..] - .iter() - .chain(approx_env_bounds.iter().map(|b| &b.1)) - .all(|b| *b == trait_bounds[0]) - { - let unique_bound = trait_bounds[0]; - debug!("projection_must_outlive: unique trait bound = {:?}", unique_bound); - debug!("projection_must_outlive: unique declared bound appears in trait ref"); - self.delegate.push_sub_region_constraint(origin, region, unique_bound); - return; - } - - // Fallback to verifying after the fact that there exists a - // declared bound, or that all the components appearing in the - // projection outlive; in some cases, this may add insufficient - // edges into the inference graph, leading to inference failures - // even though a satisfactory solution exists. - let generic = GenericKind::Projection(projection_ty); - let verify_bound = self.verify_bound.generic_bound(generic); - self.delegate.push_verify(origin, generic.clone(), region, verify_bound); - } -} - -impl<'cx, 'tcx> TypeOutlivesDelegate<'tcx> for &'cx InferCtxt<'cx, 'tcx> { - fn push_sub_region_constraint( - &mut self, - origin: SubregionOrigin<'tcx>, - a: ty::Region<'tcx>, - b: ty::Region<'tcx>, - ) { - self.sub_regions(origin, a, b) - } - - fn push_verify( - &mut self, - origin: SubregionOrigin<'tcx>, - kind: GenericKind<'tcx>, - a: ty::Region<'tcx>, - bound: VerifyBound<'tcx>, - ) { - self.verify_generic_bound(origin, kind, a, bound) - } -} diff --git a/src/librustc/infer/outlives/verify.rs b/src/librustc/infer/outlives/verify.rs deleted file mode 100644 index a2c99064caa..00000000000 --- a/src/librustc/infer/outlives/verify.rs +++ /dev/null @@ -1,314 +0,0 @@ -use crate::infer::outlives::env::RegionBoundPairs; -use crate::infer::{GenericKind, VerifyBound}; -use crate::traits; -use crate::ty::subst::{InternalSubsts, Subst}; -use crate::ty::{self, Ty, TyCtxt}; -use rustc_data_structures::captures::Captures; -use rustc_hir::def_id::DefId; - -/// The `TypeOutlives` struct has the job of "lowering" a `T: 'a` -/// obligation into a series of `'a: 'b` constraints and "verifys", as -/// described on the module comment. The final constraints are emitted -/// via a "delegate" of type `D` -- this is usually the `infcx`, which -/// accrues them into the `region_obligations` code, but for NLL we -/// use something else. -pub struct VerifyBoundCx<'cx, 'tcx> { - tcx: TyCtxt<'tcx>, - region_bound_pairs: &'cx RegionBoundPairs<'tcx>, - implicit_region_bound: Option<ty::Region<'tcx>>, - param_env: ty::ParamEnv<'tcx>, -} - -impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { - pub fn new( - tcx: TyCtxt<'tcx>, - region_bound_pairs: &'cx RegionBoundPairs<'tcx>, - implicit_region_bound: Option<ty::Region<'tcx>>, - param_env: ty::ParamEnv<'tcx>, - ) -> Self { - Self { tcx, region_bound_pairs, implicit_region_bound, param_env } - } - - /// Returns a "verify bound" that encodes what we know about - /// `generic` and the regions it outlives. - pub fn generic_bound(&self, generic: GenericKind<'tcx>) -> VerifyBound<'tcx> { - match generic { - GenericKind::Param(param_ty) => self.param_bound(param_ty), - GenericKind::Projection(projection_ty) => self.projection_bound(projection_ty), - } - } - - fn type_bound(&self, ty: Ty<'tcx>) -> VerifyBound<'tcx> { - match ty.kind { - ty::Param(p) => self.param_bound(p), - ty::Projection(data) => self.projection_bound(data), - _ => self.recursive_type_bound(ty), - } - } - - fn param_bound(&self, param_ty: ty::ParamTy) -> VerifyBound<'tcx> { - debug!("param_bound(param_ty={:?})", param_ty); - - // Start with anything like `T: 'a` we can scrape from the - // environment - let param_bounds = self - .declared_generic_bounds_from_env(GenericKind::Param(param_ty)) - .into_iter() - .map(|outlives| outlives.1); - - // Add in the default bound of fn body that applies to all in - // scope type parameters: - let param_bounds = param_bounds.chain(self.implicit_region_bound); - - let any_bounds: Vec<_> = param_bounds.map(|r| VerifyBound::OutlivedBy(r)).collect(); - - if any_bounds.is_empty() { - // We know that all types `T` outlive `'empty`, so if we - // can find no other bound, then check that the region - // being tested is `'empty`. - VerifyBound::IsEmpty - } else { - // If we can find any other bound `R` such that `T: R`, then - // we don't need to check for `'empty`, because `R: 'empty`. - VerifyBound::AnyBound(any_bounds) - } - } - - /// Given a projection like `T::Item`, searches the environment - /// for where-clauses like `T::Item: 'a`. Returns the set of - /// regions `'a` that it finds. - /// - /// This is an "approximate" check -- it may not find all - /// applicable bounds, and not all the bounds it returns can be - /// relied upon. In particular, this check ignores region - /// identity. So, for example, if we have `<T as - /// Trait<'0>>::Item` where `'0` is a region variable, and the - /// user has `<T as Trait<'a>>::Item: 'b` in the environment, then - /// the clause from the environment only applies if `'0 = 'a`, - /// which we don't know yet. But we would still include `'b` in - /// this list. - pub fn projection_approx_declared_bounds_from_env( - &self, - projection_ty: ty::ProjectionTy<'tcx>, - ) -> Vec<ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>> { - let projection_ty = GenericKind::Projection(projection_ty).to_ty(self.tcx); - let erased_projection_ty = self.tcx.erase_regions(&projection_ty); - self.declared_generic_bounds_from_env_with_compare_fn(|ty| { - if let ty::Projection(..) = ty.kind { - let erased_ty = self.tcx.erase_regions(&ty); - erased_ty == erased_projection_ty - } else { - false - } - }) - } - - /// Searches the where-clauses in scope for regions that - /// `projection_ty` is known to outlive. Currently requires an - /// exact match. - pub fn projection_declared_bounds_from_trait( - &self, - projection_ty: ty::ProjectionTy<'tcx>, - ) -> impl Iterator<Item = ty::Region<'tcx>> + 'cx + Captures<'tcx> { - self.declared_projection_bounds_from_trait(projection_ty) - } - - pub fn projection_bound(&self, projection_ty: ty::ProjectionTy<'tcx>) -> VerifyBound<'tcx> { - debug!("projection_bound(projection_ty={:?})", projection_ty); - - let projection_ty_as_ty = - self.tcx.mk_projection(projection_ty.item_def_id, projection_ty.substs); - - // Search the env for where clauses like `P: 'a`. - let env_bounds = self - .projection_approx_declared_bounds_from_env(projection_ty) - .into_iter() - .map(|ty::OutlivesPredicate(ty, r)| { - let vb = VerifyBound::OutlivedBy(r); - if ty == projection_ty_as_ty { - // Micro-optimize if this is an exact match (this - // occurs often when there are no region variables - // involved). - vb - } else { - VerifyBound::IfEq(ty, Box::new(vb)) - } - }); - - // Extend with bounds that we can find from the trait. - let trait_bounds = self - .projection_declared_bounds_from_trait(projection_ty) - .into_iter() - .map(|r| VerifyBound::OutlivedBy(r)); - - // see the extensive comment in projection_must_outlive - let ty = self.tcx.mk_projection(projection_ty.item_def_id, projection_ty.substs); - let recursive_bound = self.recursive_type_bound(ty); - - VerifyBound::AnyBound(env_bounds.chain(trait_bounds).collect()).or(recursive_bound) - } - - fn recursive_type_bound(&self, ty: Ty<'tcx>) -> VerifyBound<'tcx> { - let mut bounds = ty.walk_shallow().map(|subty| self.type_bound(subty)).collect::<Vec<_>>(); - - let mut regions = smallvec![]; - ty.push_regions(&mut regions); - regions.retain(|r| !r.is_late_bound()); // ignore late-bound regions - bounds.push(VerifyBound::AllBounds( - regions.into_iter().map(|r| VerifyBound::OutlivedBy(r)).collect(), - )); - - // remove bounds that must hold, since they are not interesting - bounds.retain(|b| !b.must_hold()); - - if bounds.len() == 1 { bounds.pop().unwrap() } else { VerifyBound::AllBounds(bounds) } - } - - /// Searches the environment for where-clauses like `G: 'a` where - /// `G` is either some type parameter `T` or a projection like - /// `T::Item`. Returns a vector of the `'a` bounds it can find. - /// - /// This is a conservative check -- it may not find all applicable - /// bounds, but all the bounds it returns can be relied upon. - fn declared_generic_bounds_from_env( - &self, - generic: GenericKind<'tcx>, - ) -> Vec<ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>> { - let generic_ty = generic.to_ty(self.tcx); - self.declared_generic_bounds_from_env_with_compare_fn(|ty| ty == generic_ty) - } - - fn declared_generic_bounds_from_env_with_compare_fn( - &self, - compare_ty: impl Fn(Ty<'tcx>) -> bool, - ) -> Vec<ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>> { - let tcx = self.tcx; - - // To start, collect bounds from user environment. Note that - // parameter environments are already elaborated, so we don't - // have to worry about that. Comparing using `==` is a bit - // dubious for projections, but it will work for simple cases - // like `T` and `T::Item`. It may not work as well for things - // like `<T as Foo<'a>>::Item`. - let c_b = self.param_env.caller_bounds; - let param_bounds = self.collect_outlives_from_predicate_list(&compare_ty, c_b); - - // Next, collect regions we scraped from the well-formedness - // constraints in the fn signature. To do that, we walk the list - // of known relations from the fn ctxt. - // - // This is crucial because otherwise code like this fails: - // - // fn foo<'a, A>(x: &'a A) { x.bar() } - // - // The problem is that the type of `x` is `&'a A`. To be - // well-formed, then, A must be lower-generic by `'a`, but we - // don't know that this holds from first principles. - let from_region_bound_pairs = self.region_bound_pairs.iter().filter_map(|&(r, p)| { - debug!( - "declared_generic_bounds_from_env_with_compare_fn: region_bound_pair = {:?}", - (r, p) - ); - let p_ty = p.to_ty(tcx); - compare_ty(p_ty).then_some(ty::OutlivesPredicate(p_ty, r)) - }); - - param_bounds - .chain(from_region_bound_pairs) - .inspect(|bound| { - debug!( - "declared_generic_bounds_from_env_with_compare_fn: result predicate = {:?}", - bound - ) - }) - .collect() - } - - /// Given a projection like `<T as Foo<'x>>::Bar`, returns any bounds - /// declared in the trait definition. For example, if the trait were - /// - /// ```rust - /// trait Foo<'a> { - /// type Bar: 'a; - /// } - /// ``` - /// - /// then this function would return `'x`. This is subject to the - /// limitations around higher-ranked bounds described in - /// `region_bounds_declared_on_associated_item`. - fn declared_projection_bounds_from_trait( - &self, - projection_ty: ty::ProjectionTy<'tcx>, - ) -> impl Iterator<Item = ty::Region<'tcx>> + 'cx + Captures<'tcx> { - debug!("projection_bounds(projection_ty={:?})", projection_ty); - let tcx = self.tcx; - self.region_bounds_declared_on_associated_item(projection_ty.item_def_id) - .map(move |r| r.subst(tcx, projection_ty.substs)) - } - - /// Given the `DefId` of an associated item, returns any region - /// bounds attached to that associated item from the trait definition. - /// - /// For example: - /// - /// ```rust - /// trait Foo<'a> { - /// type Bar: 'a; - /// } - /// ``` - /// - /// If we were given the `DefId` of `Foo::Bar`, we would return - /// `'a`. You could then apply the substitutions from the - /// projection to convert this into your namespace. This also - /// works if the user writes `where <Self as Foo<'a>>::Bar: 'a` on - /// the trait. In fact, it works by searching for just such a - /// where-clause. - /// - /// It will not, however, work for higher-ranked bounds like: - /// - /// ```rust - /// trait Foo<'a, 'b> - /// where for<'x> <Self as Foo<'x, 'b>>::Bar: 'x - /// { - /// type Bar; - /// } - /// ``` - /// - /// This is for simplicity, and because we are not really smart - /// enough to cope with such bounds anywhere. - fn region_bounds_declared_on_associated_item( - &self, - assoc_item_def_id: DefId, - ) -> impl Iterator<Item = ty::Region<'tcx>> + 'cx + Captures<'tcx> { - let tcx = self.tcx; - let assoc_item = tcx.associated_item(assoc_item_def_id); - let trait_def_id = assoc_item.container.assert_trait(); - let trait_predicates = - tcx.predicates_of(trait_def_id).predicates.iter().map(|(p, _)| *p).collect(); - let identity_substs = InternalSubsts::identity_for_item(tcx, assoc_item_def_id); - let identity_proj = tcx.mk_projection(assoc_item_def_id, identity_substs); - self.collect_outlives_from_predicate_list( - move |ty| ty == identity_proj, - traits::elaborate_predicates(tcx, trait_predicates), - ) - .map(|b| b.1) - } - - /// Searches through a predicate list for a predicate `T: 'a`. - /// - /// Careful: does not elaborate predicates, and just uses `==` - /// when comparing `ty` for equality, so `ty` must be something - /// that does not involve inference variables and where you - /// otherwise want a precise match. - fn collect_outlives_from_predicate_list( - &self, - compare_ty: impl Fn(Ty<'tcx>) -> bool, - predicates: impl IntoIterator<Item = impl AsRef<ty::Predicate<'tcx>>>, - ) -> impl Iterator<Item = ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>> { - predicates - .into_iter() - .filter_map(|p| p.as_ref().to_opt_type_outlives()) - .filter_map(|p| p.no_bound_vars()) - .filter(move |p| compare_ty(p.0)) - } -} diff --git a/src/librustc/infer/region_constraints/README.md b/src/librustc/infer/region_constraints/README.md deleted file mode 100644 index d789fb0de10..00000000000 --- a/src/librustc/infer/region_constraints/README.md +++ /dev/null @@ -1,3 +0,0 @@ -For info on how the current borrowck works, see the [rustc guide]. - -[rustc guide]: https://rust-lang.github.io/rustc-guide/borrow_check.html diff --git a/src/librustc/infer/region_constraints/leak_check.rs b/src/librustc/infer/region_constraints/leak_check.rs deleted file mode 100644 index 29290cef2d2..00000000000 --- a/src/librustc/infer/region_constraints/leak_check.rs +++ /dev/null @@ -1,151 +0,0 @@ -use super::*; -use crate::infer::{CombinedSnapshot, PlaceholderMap}; -use crate::ty::error::TypeError; -use crate::ty::relate::RelateResult; - -impl<'tcx> RegionConstraintCollector<'tcx> { - /// Searches region constraints created since `snapshot` that - /// affect one of the placeholders in `placeholder_map`, returning - /// an error if any of the placeholders are related to another - /// placeholder or would have to escape into some parent universe - /// that cannot name them. - /// - /// This is a temporary backwards compatibility measure to try and - /// retain the older (arguably incorrect) behavior of the - /// compiler. - /// - /// NB. Although `_snapshot` isn't used, it's passed in to prove - /// that we are in a snapshot, which guarantees that we can just - /// search the "undo log" for edges. This is mostly an efficiency - /// thing -- we could search *all* region constraints, but that'd be - /// a bigger set and the data structures are not setup for that. If - /// we wind up keeping some form of this check long term, it would - /// probably be better to remove the snapshot parameter and to - /// refactor the constraint set. - pub fn leak_check( - &mut self, - tcx: TyCtxt<'tcx>, - overly_polymorphic: bool, - placeholder_map: &PlaceholderMap<'tcx>, - _snapshot: &CombinedSnapshot<'_, 'tcx>, - ) -> RelateResult<'tcx, ()> { - debug!("leak_check(placeholders={:?})", placeholder_map); - - assert!(self.in_snapshot()); - - // Go through each placeholder that we created. - for (_, &placeholder_region) in placeholder_map { - // Find the universe this placeholder inhabits. - let placeholder = match placeholder_region { - ty::RePlaceholder(p) => p, - _ => bug!("leak_check: expected placeholder found {:?}", placeholder_region,), - }; - - // Find all regions that are related to this placeholder - // in some way. This means any region that either outlives - // or is outlived by a placeholder. - let mut taint_set = TaintSet::new(TaintDirections::both(), placeholder_region); - taint_set.fixed_point(tcx, &self.undo_log, &self.data.verifys); - let tainted_regions = taint_set.into_set(); - - // Report an error if two placeholders in the same universe - // are related to one another, or if a placeholder is related - // to something from a parent universe. - for &tainted_region in &tainted_regions { - if let ty::RePlaceholder(_) = tainted_region { - // Two placeholders cannot be related: - if tainted_region == placeholder_region { - continue; - } - } else if self.universe(tainted_region).can_name(placeholder.universe) { - continue; - } - - return Err(if overly_polymorphic { - debug!("overly polymorphic!"); - TypeError::RegionsOverlyPolymorphic(placeholder.name, tainted_region) - } else { - debug!("not as polymorphic!"); - TypeError::RegionsInsufficientlyPolymorphic(placeholder.name, tainted_region) - }); - } - } - - Ok(()) - } -} - -#[derive(Debug)] -struct TaintSet<'tcx> { - directions: TaintDirections, - regions: FxHashSet<ty::Region<'tcx>>, -} - -impl<'tcx> TaintSet<'tcx> { - fn new(directions: TaintDirections, initial_region: ty::Region<'tcx>) -> Self { - let mut regions = FxHashSet::default(); - regions.insert(initial_region); - TaintSet { directions: directions, regions: regions } - } - - fn fixed_point( - &mut self, - tcx: TyCtxt<'tcx>, - undo_log: &[UndoLog<'tcx>], - verifys: &[Verify<'tcx>], - ) { - let mut prev_len = 0; - while prev_len < self.len() { - debug!("tainted: prev_len = {:?} new_len = {:?}", prev_len, self.len()); - - prev_len = self.len(); - - for undo_entry in undo_log { - match undo_entry { - &AddConstraint(Constraint::VarSubVar(a, b)) => { - self.add_edge(tcx.mk_region(ReVar(a)), tcx.mk_region(ReVar(b))); - } - &AddConstraint(Constraint::RegSubVar(a, b)) => { - self.add_edge(a, tcx.mk_region(ReVar(b))); - } - &AddConstraint(Constraint::VarSubReg(a, b)) => { - self.add_edge(tcx.mk_region(ReVar(a)), b); - } - &AddConstraint(Constraint::RegSubReg(a, b)) => { - self.add_edge(a, b); - } - &AddGiven(a, b) => { - self.add_edge(a, tcx.mk_region(ReVar(b))); - } - &AddVerify(i) => span_bug!( - verifys[i].origin.span(), - "we never add verifications while doing higher-ranked things", - ), - &Purged | &AddCombination(..) | &AddVar(..) => {} - } - } - } - } - - fn into_set(self) -> FxHashSet<ty::Region<'tcx>> { - self.regions - } - - fn len(&self) -> usize { - self.regions.len() - } - - fn add_edge(&mut self, source: ty::Region<'tcx>, target: ty::Region<'tcx>) { - if self.directions.incoming { - if self.regions.contains(&target) { - self.regions.insert(source); - } - } - - if self.directions.outgoing { - if self.regions.contains(&source) { - self.regions.insert(target); - } - } - } -} diff --git a/src/librustc/infer/region_constraints/mod.rs b/src/librustc/infer/region_constraints/mod.rs deleted file mode 100644 index 8379a73bb9e..00000000000 --- a/src/librustc/infer/region_constraints/mod.rs +++ /dev/null @@ -1,918 +0,0 @@ -//! See `README.md`. - -use self::CombineMapType::*; -use self::UndoLog::*; - -use super::unify_key; -use super::{MiscVariable, RegionVariableOrigin, SubregionOrigin}; - -use crate::ty::ReStatic; -use crate::ty::{self, Ty, TyCtxt}; -use crate::ty::{ReLateBound, ReVar}; -use crate::ty::{Region, RegionVid}; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::sync::Lrc; -use rustc_data_structures::unify as ut; -use rustc_hir::def_id::DefId; -use rustc_index::vec::IndexVec; -use rustc_span::Span; - -use std::collections::BTreeMap; -use std::ops::Range; -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`. - var_infos: IndexVec<RegionVid, RegionVariableInfo>, - - data: RegionConstraintData<'tcx>, - - /// For a given pair of regions (R1, R2), maps to a region R3 that - /// is designated as their LUB (edges R1 <= R3 and R2 <= R3 - /// exist). This prevents us from making many such regions. - lubs: CombineMap<'tcx>, - - /// For a given pair of regions (R1, R2), maps to a region R3 that - /// is designated as their GLB (edges R3 <= R1 and R3 <= R2 - /// exist). This prevents us from making many such regions. - glbs: CombineMap<'tcx>, - - /// The undo log records actions that might later be undone. - /// - /// Note: `num_open_snapshots` is used to track if we are actively - /// snapshotting. When the `start_snapshot()` method is called, we - /// increment `num_open_snapshots` to indicate that we are now actively - /// snapshotting. The reason for this is that otherwise we end up adding - /// entries for things like the lower bound on a variable and so forth, - /// which can never be rolled back. - undo_log: Vec<UndoLog<'tcx>>, - - /// The number of open snapshots, i.e., those that haven't been committed or - /// rolled back. - num_open_snapshots: usize, - - /// When we add a R1 == R2 constriant, we currently add (a) edges - /// R1 <= R2 and R2 <= R1 and (b) we unify the two regions in this - /// table. You can then call `opportunistic_resolve_var` early - /// which will map R1 and R2 to some common region (i.e., either - /// R1 or R2). This is important when dropck and other such code - /// is iterating to a fixed point, because otherwise we sometimes - /// would wind up with a fresh stream of region variables that - /// have been equated but appear distinct. - unification_table: ut::UnificationTable<ut::InPlace<ty::RegionVid>>, - - /// a flag set to true when we perform any unifications; this is used - /// to micro-optimize `take_and_reset_data` - any_unifications: bool, -} - -pub type VarInfos = IndexVec<RegionVid, RegionVariableInfo>; - -/// The full set of region constraints gathered up by the collector. -/// Describes constraints between the region variables and other -/// regions, as well as other conditions that must be verified, or -/// assumptions that can be made. -#[derive(Debug, Default, Clone)] -pub struct RegionConstraintData<'tcx> { - /// Constraints of the form `A <= B`, where either `A` or `B` can - /// be a region variable (or neither, as it happens). - pub constraints: BTreeMap<Constraint<'tcx>, SubregionOrigin<'tcx>>, - - /// Constraints of the form `R0 member of [R1, ..., Rn]`, meaning that - /// `R0` must be equal to one of the regions `R1..Rn`. These occur - /// with `impl Trait` quite frequently. - pub member_constraints: Vec<MemberConstraint<'tcx>>, - - /// A "verify" is something that we need to verify after inference - /// is done, but which does not directly affect inference in any - /// way. - /// - /// An example is a `A <= B` where neither `A` nor `B` are - /// inference variables. - pub verifys: Vec<Verify<'tcx>>, - - /// A "given" is a relationship that is known to hold. In - /// particular, we often know from closure fn signatures that a - /// particular free region must be a subregion of a region - /// variable: - /// - /// foo.iter().filter(<'a> |x: &'a &'b T| ...) - /// - /// In situations like this, `'b` is in fact a region variable - /// introduced by the call to `iter()`, and `'a` is a bound region - /// on the closure (as indicated by the `<'a>` prefix). If we are - /// naive, we wind up inferring that `'b` must be `'static`, - /// because we require that it be greater than `'a` and we do not - /// know what `'a` is precisely. - /// - /// This hashmap is used to avoid that naive scenario. Basically - /// we record the fact that `'a <= 'b` is implied by the fn - /// signature, and then ignore the constraint when solving - /// equations. This is a bit of a hack but seems to work. - pub givens: FxHashSet<(Region<'tcx>, ty::RegionVid)>, -} - -/// Represents a constraint that influences the inference process. -#[derive(Clone, Copy, PartialEq, Eq, Debug, PartialOrd, Ord)] -pub enum Constraint<'tcx> { - /// A region variable is a subregion of another. - VarSubVar(RegionVid, RegionVid), - - /// A concrete region is a subregion of region variable. - RegSubVar(Region<'tcx>, RegionVid), - - /// A region variable is a subregion of a concrete region. This does not - /// directly affect inference, but instead is checked after - /// inference is complete. - VarSubReg(RegionVid, Region<'tcx>), - - /// A constraint where neither side is a variable. This does not - /// directly affect inference, but instead is checked after - /// inference is complete. - RegSubReg(Region<'tcx>, Region<'tcx>), -} - -impl Constraint<'_> { - pub fn involves_placeholders(&self) -> bool { - match self { - Constraint::VarSubVar(_, _) => false, - Constraint::VarSubReg(_, r) | Constraint::RegSubVar(r, _) => r.is_placeholder(), - Constraint::RegSubReg(r, s) => r.is_placeholder() || s.is_placeholder(), - } - } -} - -/// `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 -/// `i`. Inference variables may be involved (but this verification -/// step doesn't influence inference). -#[derive(Debug, Clone)] -pub struct Verify<'tcx> { - pub kind: GenericKind<'tcx>, - pub origin: SubregionOrigin<'tcx>, - pub region: Region<'tcx>, - pub bound: VerifyBound<'tcx>, -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, TypeFoldable)] -pub enum GenericKind<'tcx> { - Param(ty::ParamTy), - Projection(ty::ProjectionTy<'tcx>), -} - -/// Describes the things that some `GenericKind` value `G` is known to -/// outlive. Each variant of `VerifyBound` can be thought of as a -/// function: -/// -/// fn(min: Region) -> bool { .. } -/// -/// where `true` means that the region `min` meets that `G: min`. -/// (False means nothing.) -/// -/// So, for example, if we have the type `T` and we have in scope that -/// `T: 'a` and `T: 'b`, then the verify bound might be: -/// -/// fn(min: Region) -> bool { -/// ('a: min) || ('b: min) -/// } -/// -/// This is described with a `AnyRegion('a, 'b)` node. -#[derive(Debug, Clone)] -pub enum VerifyBound<'tcx> { - /// Given a kind K and a bound B, expands to a function like the - /// following, where `G` is the generic for which this verify - /// bound was created: - /// - /// ```rust - /// fn(min) -> bool { - /// if G == K { - /// B(min) - /// } else { - /// false - /// } - /// } - /// ``` - /// - /// In other words, if the generic `G` that we are checking is - /// equal to `K`, then check the associated verify bound - /// (otherwise, false). - /// - /// This is used when we have something in the environment that - /// may or may not be relevant, depending on the region inference - /// results. For example, we may have `where <T as - /// Trait<'a>>::Item: 'b` in our where-clauses. If we are - /// generating the verify-bound for `<T as Trait<'0>>::Item`, then - /// this where-clause is only relevant if `'0` winds up inferred - /// to `'a`. - /// - /// So we would compile to a verify-bound like - /// - /// ``` - /// IfEq(<T as Trait<'a>>::Item, AnyRegion('a)) - /// ``` - /// - /// meaning, if the subject G is equal to `<T as Trait<'a>>::Item` - /// (after inference), and `'a: min`, then `G: min`. - IfEq(Ty<'tcx>, Box<VerifyBound<'tcx>>), - - /// Given a region `R`, expands to the function: - /// - /// ``` - /// fn(min) -> bool { - /// R: min - /// } - /// ``` - /// - /// This is used when we can establish that `G: R` -- therefore, - /// if `R: min`, then by transitivity `G: min`. - OutlivedBy(Region<'tcx>), - - /// Given a region `R`, true if it is `'empty`. - IsEmpty, - - /// Given a set of bounds `B`, expands to the function: - /// - /// ```rust - /// fn(min) -> bool { - /// exists (b in B) { b(min) } - /// } - /// ``` - /// - /// In other words, if we meet some bound in `B`, that suffices. - /// This is used when all the bounds in `B` are known to apply to `G`. - AnyBound(Vec<VerifyBound<'tcx>>), - - /// Given a set of bounds `B`, expands to the function: - /// - /// ```rust - /// fn(min) -> bool { - /// forall (b in B) { b(min) } - /// } - /// ``` - /// - /// In other words, if we meet *all* bounds in `B`, that suffices. - /// This is used when *some* bound in `B` is known to suffice, but - /// we don't know which. - AllBounds(Vec<VerifyBound<'tcx>>), -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash)] -struct TwoRegions<'tcx> { - a: Region<'tcx>, - b: Region<'tcx>, -} - -#[derive(Copy, Clone, PartialEq)] -enum UndoLog<'tcx> { - /// We added `RegionVid`. - AddVar(RegionVid), - - /// We added the given `constraint`. - AddConstraint(Constraint<'tcx>), - - /// We added the given `verify`. - AddVerify(usize), - - /// We added the given `given`. - AddGiven(Region<'tcx>, ty::RegionVid), - - /// We added a GLB/LUB "combination variable". - AddCombination(CombineMapType, TwoRegions<'tcx>), - - /// During skolemization, we sometimes purge entries from the undo - /// log in a kind of minisnapshot (unlike other snapshots, this - /// purging actually takes place *on success*). In that case, we - /// replace the corresponding entry with `Noop` so as to avoid the - /// need to do a bunch of swapping. (We can't use `swap_remove` as - /// the order of the vector is important.) - Purged, -} - -#[derive(Copy, Clone, PartialEq)] -enum CombineMapType { - Lub, - Glb, -} - -type CombineMap<'tcx> = FxHashMap<TwoRegions<'tcx>, RegionVid>; - -#[derive(Debug, Clone, Copy)] -pub struct RegionVariableInfo { - pub origin: RegionVariableOrigin, - pub universe: ty::UniverseIndex, -} - -pub struct RegionSnapshot { - length: usize, - region_snapshot: ut::Snapshot<ut::InPlace<ty::RegionVid>>, - any_unifications: bool, -} - -/// When working with placeholder regions, we often wish to find all of -/// the regions that are either reachable from a placeholder region, or -/// which can reach a placeholder region, or both. We call such regions -/// *tainted* regions. This struct allows you to decide what set of -/// tainted regions you want. -#[derive(Debug)] -pub struct TaintDirections { - incoming: bool, - outgoing: bool, -} - -impl TaintDirections { - pub fn incoming() -> Self { - TaintDirections { incoming: true, outgoing: false } - } - - pub fn outgoing() -> Self { - TaintDirections { incoming: false, outgoing: true } - } - - pub fn both() -> Self { - TaintDirections { incoming: true, outgoing: true } - } -} - -impl<'tcx> RegionConstraintCollector<'tcx> { - pub fn new() -> Self { - Self::default() - } - - pub fn num_region_vars(&self) -> usize { - self.var_infos.len() - } - - pub fn region_constraint_data(&self) -> &RegionConstraintData<'tcx> { - &self.data - } - - /// Once all the constraints have been gathered, extract out the final data. - /// - /// Not legal during a snapshot. - pub fn into_infos_and_data(self) -> (VarInfos, RegionConstraintData<'tcx>) { - assert!(!self.in_snapshot()); - (self.var_infos, self.data) - } - - /// Takes (and clears) the current set of constraints. Note that - /// the set of variables remains intact, but all relationships - /// between them are reset. This is used during NLL checking to - /// grab the set of constraints that arose from a particular - /// operation. - /// - /// We don't want to leak relationships between variables between - /// points because just because (say) `r1 == r2` was true at some - /// point P in the graph doesn't imply that it will be true at - /// some other point Q, in NLL. - /// - /// Not legal during a snapshot. - pub fn take_and_reset_data(&mut self) -> RegionConstraintData<'tcx> { - assert!(!self.in_snapshot()); - - // If you add a new field to `RegionConstraintCollector`, you - // should think carefully about whether it needs to be cleared - // or updated in some way. - let RegionConstraintCollector { - var_infos: _, - data, - lubs, - glbs, - undo_log: _, - num_open_snapshots: _, - unification_table, - any_unifications, - } = self; - - // Clear the tables of (lubs, glbs), so that we will create - // fresh regions if we do a LUB operation. As it happens, - // LUB/GLB are not performed by the MIR type-checker, which is - // the one that uses this method, but it's good to be correct. - lubs.clear(); - glbs.clear(); - - // Clear all unifications and recreate the variables a "now - // un-unified" state. Note that when we unify `a` and `b`, we - // also insert `a <= b` and a `b <= a` edges, so the - // `RegionConstraintData` contains the relationship here. - if *any_unifications { - unification_table.reset_unifications(|vid| unify_key::RegionVidKey { min_vid: vid }); - *any_unifications = false; - } - - mem::take(data) - } - - pub fn data(&self) -> &RegionConstraintData<'tcx> { - &self.data - } - - fn in_snapshot(&self) -> bool { - self.num_open_snapshots > 0 - } - - pub fn start_snapshot(&mut self) -> RegionSnapshot { - let length = self.undo_log.len(); - debug!("RegionConstraintCollector: start_snapshot({})", length); - self.num_open_snapshots += 1; - RegionSnapshot { - length, - region_snapshot: self.unification_table.snapshot(), - any_unifications: self.any_unifications, - } - } - - fn assert_open_snapshot(&self, snapshot: &RegionSnapshot) { - assert!(self.undo_log.len() >= snapshot.length); - assert!(self.num_open_snapshots > 0); - } - - pub fn commit(&mut self, snapshot: RegionSnapshot) { - debug!("RegionConstraintCollector: commit({})", snapshot.length); - self.assert_open_snapshot(&snapshot); - - if self.num_open_snapshots == 1 { - // The root snapshot. It's safe to clear the undo log because - // there's no snapshot further out that we might need to roll back - // to. - assert!(snapshot.length == 0); - self.undo_log.clear(); - } - - self.num_open_snapshots -= 1; - - self.unification_table.commit(snapshot.region_snapshot); - } - - pub fn rollback_to(&mut self, snapshot: RegionSnapshot) { - debug!("RegionConstraintCollector: rollback_to({:?})", snapshot); - self.assert_open_snapshot(&snapshot); - - while self.undo_log.len() > snapshot.length { - let undo_entry = self.undo_log.pop().unwrap(); - self.rollback_undo_entry(undo_entry); - } - - self.num_open_snapshots -= 1; - - self.unification_table.rollback_to(snapshot.region_snapshot); - self.any_unifications = snapshot.any_unifications; - } - - fn rollback_undo_entry(&mut self, undo_entry: UndoLog<'tcx>) { - match undo_entry { - Purged => { - // nothing to do here - } - AddVar(vid) => { - self.var_infos.pop().unwrap(); - assert_eq!(self.var_infos.len(), vid.index() as usize); - } - AddConstraint(ref constraint) => { - self.data.constraints.remove(constraint); - } - AddVerify(index) => { - self.data.verifys.pop(); - assert_eq!(self.data.verifys.len(), index); - } - AddGiven(sub, sup) => { - self.data.givens.remove(&(sub, sup)); - } - AddCombination(Glb, ref regions) => { - self.glbs.remove(regions); - } - AddCombination(Lub, ref regions) => { - self.lubs.remove(regions); - } - } - } - - pub fn new_region_var( - &mut self, - universe: ty::UniverseIndex, - origin: RegionVariableOrigin, - ) -> RegionVid { - let vid = self.var_infos.push(RegionVariableInfo { origin, universe }); - - let u_vid = self.unification_table.new_key(unify_key::RegionVidKey { min_vid: vid }); - assert_eq!(vid, u_vid); - if self.in_snapshot() { - self.undo_log.push(AddVar(vid)); - } - debug!("created new region variable {:?} in {:?} with origin {:?}", vid, universe, origin); - return vid; - } - - /// Returns the universe for the given variable. - pub fn var_universe(&self, vid: RegionVid) -> ty::UniverseIndex { - self.var_infos[vid].universe - } - - /// Returns the origin for the given variable. - pub fn var_origin(&self, vid: RegionVid) -> RegionVariableOrigin { - self.var_infos[vid].origin - } - - /// Removes all the edges to/from the placeholder regions that are - /// in `skols`. This is used after a higher-ranked operation - /// completes to remove all trace of the placeholder regions - /// created in that time. - pub fn pop_placeholders(&mut self, placeholders: &FxHashSet<ty::Region<'tcx>>) { - debug!("pop_placeholders(placeholders={:?})", placeholders); - - assert!(self.in_snapshot()); - - let constraints_to_kill: Vec<usize> = self - .undo_log - .iter() - .enumerate() - .rev() - .filter(|&(_, undo_entry)| kill_constraint(placeholders, undo_entry)) - .map(|(index, _)| index) - .collect(); - - for index in constraints_to_kill { - let undo_entry = mem::replace(&mut self.undo_log[index], Purged); - self.rollback_undo_entry(undo_entry); - } - - return; - - fn kill_constraint<'tcx>( - placeholders: &FxHashSet<ty::Region<'tcx>>, - undo_entry: &UndoLog<'tcx>, - ) -> bool { - match undo_entry { - &AddConstraint(Constraint::VarSubVar(..)) => false, - &AddConstraint(Constraint::RegSubVar(a, _)) => placeholders.contains(&a), - &AddConstraint(Constraint::VarSubReg(_, b)) => placeholders.contains(&b), - &AddConstraint(Constraint::RegSubReg(a, b)) => { - placeholders.contains(&a) || placeholders.contains(&b) - } - &AddGiven(..) => false, - &AddVerify(_) => false, - &AddCombination(_, ref two_regions) => { - placeholders.contains(&two_regions.a) || placeholders.contains(&two_regions.b) - } - &AddVar(..) | &Purged => false, - } - } - } - - fn add_constraint(&mut self, constraint: Constraint<'tcx>, origin: SubregionOrigin<'tcx>) { - // cannot add constraints once regions are resolved - debug!("RegionConstraintCollector: add_constraint({:?})", constraint); - - // never overwrite an existing (constraint, origin) - only insert one if it isn't - // present in the map yet. This prevents origins from outside the snapshot being - // replaced with "less informative" origins e.g., during calls to `can_eq` - let in_snapshot = self.in_snapshot(); - let undo_log = &mut self.undo_log; - self.data.constraints.entry(constraint).or_insert_with(|| { - if in_snapshot { - undo_log.push(AddConstraint(constraint)); - } - origin - }); - } - - fn add_verify(&mut self, verify: Verify<'tcx>) { - // cannot add verifys once regions are resolved - debug!("RegionConstraintCollector: add_verify({:?})", verify); - - // skip no-op cases known to be satisfied - if let VerifyBound::AllBounds(ref bs) = verify.bound { - if bs.len() == 0 { - return; - } - } - - let index = self.data.verifys.len(); - self.data.verifys.push(verify); - if self.in_snapshot() { - self.undo_log.push(AddVerify(index)); - } - } - - pub fn add_given(&mut self, sub: Region<'tcx>, sup: ty::RegionVid) { - // cannot add givens once regions are resolved - if self.data.givens.insert((sub, sup)) { - debug!("add_given({:?} <= {:?})", sub, sup); - - if self.in_snapshot() { - self.undo_log.push(AddGiven(sub, sup)); - } - } - } - - pub fn make_eqregion( - &mut self, - origin: SubregionOrigin<'tcx>, - sub: Region<'tcx>, - sup: Region<'tcx>, - ) { - if sub != sup { - // Eventually, it would be nice to add direct support for - // equating regions. - self.make_subregion(origin.clone(), sub, sup); - self.make_subregion(origin, sup, sub); - - if let (ty::ReVar(sub), ty::ReVar(sup)) = (*sub, *sup) { - debug!("make_eqregion: uniying {:?} with {:?}", sub, sup); - self.unification_table.union(sub, sup); - self.any_unifications = true; - } - } - } - - pub fn member_constraint( - &mut self, - opaque_type_def_id: DefId, - definition_span: Span, - hidden_ty: Ty<'tcx>, - member_region: ty::Region<'tcx>, - choice_regions: &Lrc<Vec<ty::Region<'tcx>>>, - ) { - debug!("member_constraint({:?} in {:#?})", member_region, choice_regions); - - if choice_regions.iter().any(|&r| r == member_region) { - return; - } - - self.data.member_constraints.push(MemberConstraint { - opaque_type_def_id, - definition_span, - hidden_ty, - member_region, - choice_regions: choice_regions.clone(), - }); - } - - pub fn make_subregion( - &mut self, - origin: SubregionOrigin<'tcx>, - sub: Region<'tcx>, - sup: Region<'tcx>, - ) { - // cannot add constraints once regions are resolved - debug!( - "RegionConstraintCollector: make_subregion({:?}, {:?}) due to {:?}", - sub, sup, origin - ); - - match (sub, sup) { - (&ReLateBound(..), _) | (_, &ReLateBound(..)) => { - span_bug!(origin.span(), "cannot relate bound region: {:?} <= {:?}", sub, sup); - } - (_, &ReStatic) => { - // all regions are subregions of static, so we can ignore this - } - (&ReVar(sub_id), &ReVar(sup_id)) => { - self.add_constraint(Constraint::VarSubVar(sub_id, sup_id), origin); - } - (_, &ReVar(sup_id)) => { - self.add_constraint(Constraint::RegSubVar(sub, sup_id), origin); - } - (&ReVar(sub_id), _) => { - self.add_constraint(Constraint::VarSubReg(sub_id, sup), origin); - } - _ => { - self.add_constraint(Constraint::RegSubReg(sub, sup), origin); - } - } - } - - /// See [`Verify::VerifyGenericBound`]. - pub fn verify_generic_bound( - &mut self, - origin: SubregionOrigin<'tcx>, - kind: GenericKind<'tcx>, - sub: Region<'tcx>, - bound: VerifyBound<'tcx>, - ) { - self.add_verify(Verify { kind, origin, region: sub, bound }); - } - - pub fn lub_regions( - &mut self, - tcx: TyCtxt<'tcx>, - origin: SubregionOrigin<'tcx>, - a: Region<'tcx>, - b: Region<'tcx>, - ) -> Region<'tcx> { - // cannot add constraints once regions are resolved - debug!("RegionConstraintCollector: lub_regions({:?}, {:?})", a, b); - match (a, b) { - (r @ &ReStatic, _) | (_, r @ &ReStatic) => { - r // nothing lives longer than static - } - - _ if a == b => { - a // LUB(a,a) = a - } - - _ => self.combine_vars(tcx, Lub, a, b, origin), - } - } - - pub fn glb_regions( - &mut self, - tcx: TyCtxt<'tcx>, - origin: SubregionOrigin<'tcx>, - a: Region<'tcx>, - b: Region<'tcx>, - ) -> Region<'tcx> { - // cannot add constraints once regions are resolved - debug!("RegionConstraintCollector: glb_regions({:?}, {:?})", a, b); - match (a, b) { - (&ReStatic, r) | (r, &ReStatic) => { - r // static lives longer than everything else - } - - _ if a == b => { - a // GLB(a,a) = a - } - - _ => self.combine_vars(tcx, Glb, a, b, origin), - } - } - - pub fn opportunistic_resolve_var( - &mut self, - tcx: TyCtxt<'tcx>, - rid: RegionVid, - ) -> ty::Region<'tcx> { - let vid = self.unification_table.probe_value(rid).min_vid; - tcx.mk_region(ty::ReVar(vid)) - } - - fn combine_map(&mut self, t: CombineMapType) -> &mut CombineMap<'tcx> { - match t { - Glb => &mut self.glbs, - Lub => &mut self.lubs, - } - } - - fn combine_vars( - &mut self, - tcx: TyCtxt<'tcx>, - t: CombineMapType, - a: Region<'tcx>, - b: Region<'tcx>, - origin: SubregionOrigin<'tcx>, - ) -> Region<'tcx> { - let vars = TwoRegions { a: a, b: b }; - if let Some(&c) = self.combine_map(t).get(&vars) { - return tcx.mk_region(ReVar(c)); - } - let a_universe = self.universe(a); - let b_universe = self.universe(b); - let c_universe = cmp::max(a_universe, b_universe); - let c = self.new_region_var(c_universe, MiscVariable(origin.span())); - self.combine_map(t).insert(vars, c); - if self.in_snapshot() { - self.undo_log.push(AddCombination(t, vars)); - } - let new_r = tcx.mk_region(ReVar(c)); - for &old_r in &[a, b] { - match t { - Glb => self.make_subregion(origin.clone(), new_r, old_r), - Lub => self.make_subregion(origin.clone(), old_r, new_r), - } - } - debug!("combine_vars() c={:?}", c); - new_r - } - - pub fn universe(&self, region: Region<'tcx>) -> ty::UniverseIndex { - match *region { - ty::ReScope(..) - | ty::ReStatic - | ty::ReErased - | ty::ReFree(..) - | ty::ReEarlyBound(..) => ty::UniverseIndex::ROOT, - ty::ReEmpty(ui) => ui, - ty::RePlaceholder(placeholder) => placeholder.universe, - ty::ReClosureBound(vid) | ty::ReVar(vid) => self.var_universe(vid), - ty::ReLateBound(..) => bug!("universe(): encountered bound region {:?}", region), - } - } - - pub fn vars_since_snapshot( - &self, - mark: &RegionSnapshot, - ) -> (Range<RegionVid>, Vec<RegionVariableOrigin>) { - let range = self.unification_table.vars_since_snapshot(&mark.region_snapshot); - ( - range.clone(), - (range.start.index()..range.end.index()) - .map(|index| self.var_infos[ty::RegionVid::from(index)].origin) - .collect(), - ) - } - - /// See [`RegionInference::region_constraints_added_in_snapshot`]. - pub fn region_constraints_added_in_snapshot(&self, mark: &RegionSnapshot) -> Option<bool> { - self.undo_log[mark.length..] - .iter() - .map(|&elt| match elt { - AddConstraint(constraint) => Some(constraint.involves_placeholders()), - _ => None, - }) - .max() - .unwrap_or(None) - } -} - -impl fmt::Debug for RegionSnapshot { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "RegionSnapshot(length={})", self.length) - } -} - -impl<'tcx> fmt::Debug for GenericKind<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { - GenericKind::Param(ref p) => write!(f, "{:?}", p), - GenericKind::Projection(ref p) => write!(f, "{:?}", p), - } - } -} - -impl<'tcx> fmt::Display for GenericKind<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { - GenericKind::Param(ref p) => write!(f, "{}", p), - GenericKind::Projection(ref p) => write!(f, "{}", p), - } - } -} - -impl<'tcx> GenericKind<'tcx> { - pub fn to_ty(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { - match *self { - GenericKind::Param(ref p) => p.to_ty(tcx), - GenericKind::Projection(ref p) => tcx.mk_projection(p.item_def_id, p.substs), - } - } -} - -impl<'tcx> VerifyBound<'tcx> { - pub fn must_hold(&self) -> bool { - match self { - VerifyBound::IfEq(..) => false, - VerifyBound::OutlivedBy(ty::ReStatic) => true, - VerifyBound::OutlivedBy(_) => false, - VerifyBound::IsEmpty => false, - VerifyBound::AnyBound(bs) => bs.iter().any(|b| b.must_hold()), - VerifyBound::AllBounds(bs) => bs.iter().all(|b| b.must_hold()), - } - } - - pub fn cannot_hold(&self) -> bool { - match self { - VerifyBound::IfEq(_, b) => b.cannot_hold(), - VerifyBound::IsEmpty => false, - VerifyBound::OutlivedBy(_) => false, - VerifyBound::AnyBound(bs) => bs.iter().all(|b| b.cannot_hold()), - VerifyBound::AllBounds(bs) => bs.iter().any(|b| b.cannot_hold()), - } - } - - pub fn or(self, vb: VerifyBound<'tcx>) -> VerifyBound<'tcx> { - if self.must_hold() || vb.cannot_hold() { - self - } else if self.cannot_hold() || vb.must_hold() { - vb - } else { - VerifyBound::AnyBound(vec![self, vb]) - } - } - - pub fn and(self, vb: VerifyBound<'tcx>) -> VerifyBound<'tcx> { - if self.must_hold() && vb.must_hold() { - self - } else if self.cannot_hold() && vb.cannot_hold() { - self - } else { - VerifyBound::AllBounds(vec![self, vb]) - } - } -} - -impl<'tcx> RegionConstraintData<'tcx> { - /// Returns `true` if this region constraint data contains no constraints, and `false` - /// otherwise. - pub fn is_empty(&self) -> bool { - let RegionConstraintData { constraints, member_constraints, verifys, givens } = self; - constraints.is_empty() - && member_constraints.is_empty() - && verifys.is_empty() - && givens.is_empty() - } -} diff --git a/src/librustc/infer/resolve.rs b/src/librustc/infer/resolve.rs deleted file mode 100644 index c9acd1cf4a1..00000000000 --- a/src/librustc/infer/resolve.rs +++ /dev/null @@ -1,244 +0,0 @@ -use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use super::{FixupError, FixupResult, InferCtxt, Span}; -use crate::ty::fold::{TypeFolder, TypeVisitor}; -use crate::ty::{self, Const, InferConst, Ty, TyCtxt, TypeFoldable}; - -/////////////////////////////////////////////////////////////////////////// -// OPPORTUNISTIC VAR RESOLVER - -/// The opportunistic resolver can be used at any time. It simply replaces -/// type/const variables that have been unified with the things they have -/// been unified with (similar to `shallow_resolve`, but deep). This is -/// useful for printing messages etc but also required at various -/// points for correctness. -pub struct OpportunisticVarResolver<'a, 'tcx> { - infcx: &'a InferCtxt<'a, 'tcx>, -} - -impl<'a, 'tcx> OpportunisticVarResolver<'a, 'tcx> { - #[inline] - pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> Self { - OpportunisticVarResolver { infcx } - } -} - -impl<'a, 'tcx> TypeFolder<'tcx> for OpportunisticVarResolver<'a, 'tcx> { - fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { - self.infcx.tcx - } - - fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - if !t.has_infer_types() && !t.has_infer_consts() { - t // micro-optimize -- if there is nothing in this type that this fold affects... - } else { - let t = self.infcx.shallow_resolve(t); - t.super_fold_with(self) - } - } - - fn fold_const(&mut self, ct: &'tcx Const<'tcx>) -> &'tcx Const<'tcx> { - if !ct.has_infer_consts() { - ct // micro-optimize -- if there is nothing in this const that this fold affects... - } else { - let ct = self.infcx.shallow_resolve(ct); - ct.super_fold_with(self) - } - } -} - -/// The opportunistic type and region resolver is similar to the -/// opportunistic type resolver, but also opportunistically resolves -/// regions. It is useful for canonicalization. -pub struct OpportunisticTypeAndRegionResolver<'a, 'tcx> { - infcx: &'a InferCtxt<'a, 'tcx>, -} - -impl<'a, 'tcx> OpportunisticTypeAndRegionResolver<'a, 'tcx> { - pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> Self { - OpportunisticTypeAndRegionResolver { infcx } - } -} - -impl<'a, 'tcx> TypeFolder<'tcx> for OpportunisticTypeAndRegionResolver<'a, 'tcx> { - fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { - self.infcx.tcx - } - - fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - if !t.needs_infer() { - t // micro-optimize -- if there is nothing in this type that this fold affects... - } else { - let t0 = self.infcx.shallow_resolve(t); - t0.super_fold_with(self) - } - } - - fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { - match *r { - ty::ReVar(rid) => self - .infcx - .inner - .borrow_mut() - .unwrap_region_constraints() - .opportunistic_resolve_var(self.tcx(), rid), - _ => r, - } - } - - fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { - if !ct.needs_infer() { - ct // micro-optimize -- if there is nothing in this const that this fold affects... - } else { - let c0 = self.infcx.shallow_resolve(ct); - c0.super_fold_with(self) - } - } -} - -/////////////////////////////////////////////////////////////////////////// -// UNRESOLVED TYPE FINDER - -/// The unresolved type **finder** walks a type searching for -/// type variables that don't yet have a value. The first unresolved type is stored. -/// It does not construct the fully resolved type (which might -/// involve some hashing and so forth). -pub struct UnresolvedTypeFinder<'a, 'tcx> { - infcx: &'a InferCtxt<'a, 'tcx>, - - /// Used to find the type parameter name and location for error reporting. - pub first_unresolved: Option<(Ty<'tcx>, Option<Span>)>, -} - -impl<'a, 'tcx> UnresolvedTypeFinder<'a, 'tcx> { - pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> Self { - UnresolvedTypeFinder { infcx, first_unresolved: None } - } -} - -impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeFinder<'a, 'tcx> { - fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { - let t = self.infcx.shallow_resolve(t); - if t.has_infer_types() { - if let ty::Infer(infer_ty) = t.kind { - // Since we called `shallow_resolve` above, this must - // be an (as yet...) unresolved inference variable. - let ty_var_span = if let ty::TyVar(ty_vid) = infer_ty { - let ty_vars = &self.infcx.inner.borrow().type_variables; - if let TypeVariableOrigin { - kind: TypeVariableOriginKind::TypeParameterDefinition(_, _), - span, - } = *ty_vars.var_origin(ty_vid) - { - Some(span) - } else { - None - } - } else { - None - }; - self.first_unresolved = Some((t, ty_var_span)); - true // Halt visiting. - } else { - // Otherwise, visit its contents. - t.super_visit_with(self) - } - } else { - // All type variables in inference types must already be resolved, - // - no need to visit the contents, continue visiting. - false - } - } -} - -/////////////////////////////////////////////////////////////////////////// -// FULL TYPE RESOLUTION - -/// Full type resolution replaces all type and region variables with -/// their concrete results. If any variable cannot be replaced (never unified, etc) -/// then an `Err` result is returned. -pub fn fully_resolve<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>, value: &T) -> FixupResult<'tcx, T> -where - T: TypeFoldable<'tcx>, -{ - let mut full_resolver = FullTypeResolver { infcx: infcx, err: None }; - let result = value.fold_with(&mut full_resolver); - match full_resolver.err { - None => Ok(result), - Some(e) => Err(e), - } -} - -// N.B. This type is not public because the protocol around checking the -// `err` field is not enforcable otherwise. -struct FullTypeResolver<'a, 'tcx> { - infcx: &'a InferCtxt<'a, 'tcx>, - err: Option<FixupError<'tcx>>, -} - -impl<'a, 'tcx> TypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> { - fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { - self.infcx.tcx - } - - fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - if !t.needs_infer() && !ty::keep_local(&t) { - t // micro-optimize -- if there is nothing in this type that this fold affects... - // ^ we need to have the `keep_local` check to un-default - // defaulted tuples. - } else { - let t = self.infcx.shallow_resolve(t); - match t.kind { - ty::Infer(ty::TyVar(vid)) => { - self.err = Some(FixupError::UnresolvedTy(vid)); - self.tcx().types.err - } - ty::Infer(ty::IntVar(vid)) => { - self.err = Some(FixupError::UnresolvedIntTy(vid)); - self.tcx().types.err - } - ty::Infer(ty::FloatVar(vid)) => { - self.err = Some(FixupError::UnresolvedFloatTy(vid)); - self.tcx().types.err - } - ty::Infer(_) => { - bug!("Unexpected type in full type resolver: {:?}", t); - } - _ => t.super_fold_with(self), - } - } - } - - fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { - match *r { - ty::ReVar(rid) => self - .infcx - .lexical_region_resolutions - .borrow() - .as_ref() - .expect("region resolution not performed") - .resolve_var(rid), - _ => r, - } - } - - fn fold_const(&mut self, c: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { - if !c.needs_infer() && !ty::keep_local(&c) { - c // micro-optimize -- if there is nothing in this const that this fold affects... - // ^ we need to have the `keep_local` check to un-default - // defaulted tuples. - } else { - let c = self.infcx.shallow_resolve(c); - match c.val { - ty::ConstKind::Infer(InferConst::Var(vid)) => { - self.err = Some(FixupError::UnresolvedConst(vid)); - return self.tcx().consts.err; - } - ty::ConstKind::Infer(InferConst::Fresh(_)) => { - bug!("Unexpected const in full const resolver: {:?}", c); - } - _ => {} - } - c.super_fold_with(self) - } - } -} diff --git a/src/librustc/infer/sub.rs b/src/librustc/infer/sub.rs deleted file mode 100644 index ef4903358d5..00000000000 --- a/src/librustc/infer/sub.rs +++ /dev/null @@ -1,171 +0,0 @@ -use super::combine::{CombineFields, RelationDir}; -use super::SubregionOrigin; - -use crate::traits::Obligation; -use crate::ty::fold::TypeFoldable; -use crate::ty::relate::{Cause, Relate, RelateResult, TypeRelation}; -use crate::ty::TyVar; -use crate::ty::{self, Ty, TyCtxt}; -use std::mem; - -/// Ensures `a` is made a subtype of `b`. Returns `a` on success. -pub struct Sub<'combine, 'infcx, 'tcx> { - fields: &'combine mut CombineFields<'infcx, 'tcx>, - a_is_expected: bool, -} - -impl<'combine, 'infcx, 'tcx> Sub<'combine, 'infcx, 'tcx> { - pub fn new( - f: &'combine mut CombineFields<'infcx, 'tcx>, - a_is_expected: bool, - ) -> Sub<'combine, 'infcx, 'tcx> { - Sub { fields: f, a_is_expected: a_is_expected } - } - - fn with_expected_switched<R, F: FnOnce(&mut Self) -> R>(&mut self, f: F) -> R { - self.a_is_expected = !self.a_is_expected; - let result = f(self); - self.a_is_expected = !self.a_is_expected; - result - } -} - -impl TypeRelation<'tcx> for Sub<'combine, 'infcx, 'tcx> { - fn tag(&self) -> &'static str { - "Sub" - } - fn tcx(&self) -> TyCtxt<'tcx> { - self.fields.infcx.tcx - } - - fn param_env(&self) -> ty::ParamEnv<'tcx> { - self.fields.param_env - } - - fn a_is_expected(&self) -> bool { - self.a_is_expected - } - - fn with_cause<F, R>(&mut self, cause: Cause, f: F) -> R - where - F: FnOnce(&mut Self) -> R, - { - debug!("sub with_cause={:?}", cause); - let old_cause = mem::replace(&mut self.fields.cause, Some(cause)); - let r = f(self); - debug!("sub old_cause={:?}", old_cause); - self.fields.cause = old_cause; - r - } - - fn relate_with_variance<T: Relate<'tcx>>( - &mut self, - variance: ty::Variance, - a: &T, - b: &T, - ) -> RelateResult<'tcx, T> { - match variance { - ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b), - ty::Covariant => self.relate(a, b), - ty::Bivariant => Ok(a.clone()), - ty::Contravariant => self.with_expected_switched(|this| this.relate(b, a)), - } - } - - fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { - debug!("{}.tys({:?}, {:?})", self.tag(), a, b); - - if a == b { - return Ok(a); - } - - let infcx = self.fields.infcx; - let a = infcx.inner.borrow_mut().type_variables.replace_if_possible(a); - let b = infcx.inner.borrow_mut().type_variables.replace_if_possible(b); - match (&a.kind, &b.kind) { - (&ty::Infer(TyVar(a_vid)), &ty::Infer(TyVar(b_vid))) => { - // Shouldn't have any LBR here, so we can safely put - // this under a binder below without fear of accidental - // capture. - assert!(!a.has_escaping_bound_vars()); - assert!(!b.has_escaping_bound_vars()); - - // can't make progress on `A <: B` if both A and B are - // type variables, so record an obligation. We also - // have to record in the `type_variables` tracker that - // the two variables are equal modulo subtyping, which - // is important to the occurs check later on. - infcx.inner.borrow_mut().type_variables.sub(a_vid, b_vid); - self.fields.obligations.push(Obligation::new( - self.fields.trace.cause.clone(), - self.fields.param_env, - ty::Predicate::Subtype(ty::Binder::dummy(ty::SubtypePredicate { - a_is_expected: self.a_is_expected, - a, - b, - })), - )); - - Ok(a) - } - (&ty::Infer(TyVar(a_id)), _) => { - self.fields.instantiate(b, RelationDir::SupertypeOf, a_id, !self.a_is_expected)?; - Ok(a) - } - (_, &ty::Infer(TyVar(b_id))) => { - self.fields.instantiate(a, RelationDir::SubtypeOf, b_id, self.a_is_expected)?; - Ok(a) - } - - (&ty::Error, _) | (_, &ty::Error) => { - infcx.set_tainted_by_errors(); - Ok(self.tcx().types.err) - } - - _ => { - self.fields.infcx.super_combine_tys(self, a, b)?; - Ok(a) - } - } - } - - fn regions( - &mut self, - a: ty::Region<'tcx>, - b: ty::Region<'tcx>, - ) -> RelateResult<'tcx, ty::Region<'tcx>> { - debug!("{}.regions({:?}, {:?}) self.cause={:?}", self.tag(), a, b, self.fields.cause); - - // FIXME -- we have more fine-grained information available - // from the "cause" field, we could perhaps give more tailored - // error messages. - let origin = SubregionOrigin::Subtype(box self.fields.trace.clone()); - self.fields - .infcx - .inner - .borrow_mut() - .unwrap_region_constraints() - .make_subregion(origin, a, b); - - Ok(a) - } - - fn consts( - &mut self, - a: &'tcx ty::Const<'tcx>, - b: &'tcx ty::Const<'tcx>, - ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> { - self.fields.infcx.super_combine_consts(self, a, b) - } - - fn binders<T>( - &mut self, - a: &ty::Binder<T>, - b: &ty::Binder<T>, - ) -> RelateResult<'tcx, ty::Binder<T>> - where - T: Relate<'tcx>, - { - self.fields.higher_ranked_sub(a, b, self.a_is_expected) - } -} diff --git a/src/librustc/infer/type_variable.rs b/src/librustc/infer/type_variable.rs deleted file mode 100644 index f391a054a2a..00000000000 --- a/src/librustc/infer/type_variable.rs +++ /dev/null @@ -1,455 +0,0 @@ -use crate::ty::{self, Ty, TyVid}; -use rustc_hir::def_id::DefId; -use rustc_span::symbol::Symbol; -use rustc_span::Span; - -use rustc_data_structures::snapshot_vec as sv; -use rustc_data_structures::unify as ut; -use std::cmp; -use std::marker::PhantomData; -use std::ops::Range; -use std::u32; - -pub struct TypeVariableTable<'tcx> { - values: sv::SnapshotVec<Delegate>, - - /// Two variables are unified in `eq_relations` when we have a - /// constraint `?X == ?Y`. This table also stores, for each key, - /// the known value. - eq_relations: ut::UnificationTable<ut::InPlace<TyVidEqKey<'tcx>>>, - - /// Two variables are unified in `sub_relations` when we have a - /// constraint `?X <: ?Y` *or* a constraint `?Y <: ?X`. This second - /// table exists only to help with the occurs check. In particular, - /// we want to report constraints like these as an occurs check - /// violation: - /// - /// ?1 <: ?3 - /// Box<?3> <: ?1 - /// - /// This works because `?1` and `?3` are unified in the - /// `sub_relations` relation (not in `eq_relations`). Then when we - /// process the `Box<?3> <: ?1` constraint, we do an occurs check - /// on `Box<?3>` and find a potential cycle. - /// - /// This is reasonable because, in Rust, subtypes have the same - /// "skeleton" and hence there is no possible type such that - /// (e.g.) `Box<?3> <: ?3` for any `?3`. - sub_relations: ut::UnificationTable<ut::InPlace<ty::TyVid>>, -} - -#[derive(Copy, Clone, Debug)] -pub struct TypeVariableOrigin { - pub kind: TypeVariableOriginKind, - pub span: Span, -} - -/// Reasons to create a type inference variable -#[derive(Copy, Clone, Debug)] -pub enum TypeVariableOriginKind { - MiscVariable, - NormalizeProjectionType, - TypeInference, - TypeParameterDefinition(Symbol, Option<DefId>), - - /// One of the upvars or closure kind parameters in a `ClosureSubsts` - /// (before it has been determined). - ClosureSynthetic, - SubstitutionPlaceholder, - AutoDeref, - AdjustmentType, - DivergingFn, - LatticeVariable, -} - -struct TypeVariableData { - origin: TypeVariableOrigin, - diverging: bool, -} - -#[derive(Copy, Clone, Debug)] -pub enum TypeVariableValue<'tcx> { - Known { value: Ty<'tcx> }, - Unknown { universe: ty::UniverseIndex }, -} - -impl<'tcx> TypeVariableValue<'tcx> { - /// If this value is known, returns the type it is known to be. - /// Otherwise, `None`. - pub fn known(&self) -> Option<Ty<'tcx>> { - match *self { - TypeVariableValue::Unknown { .. } => None, - TypeVariableValue::Known { value } => Some(value), - } - } - - pub fn is_unknown(&self) -> bool { - match *self { - TypeVariableValue::Unknown { .. } => true, - TypeVariableValue::Known { .. } => false, - } - } -} - -pub struct Snapshot<'tcx> { - snapshot: sv::Snapshot, - eq_snapshot: ut::Snapshot<ut::InPlace<TyVidEqKey<'tcx>>>, - sub_snapshot: ut::Snapshot<ut::InPlace<ty::TyVid>>, -} - -struct Instantiate { - vid: ty::TyVid, -} - -struct Delegate; - -impl<'tcx> TypeVariableTable<'tcx> { - pub fn new() -> TypeVariableTable<'tcx> { - TypeVariableTable { - values: sv::SnapshotVec::new(), - eq_relations: ut::UnificationTable::new(), - sub_relations: ut::UnificationTable::new(), - } - } - - /// Returns the diverges flag given when `vid` was created. - /// - /// Note that this function does not return care whether - /// `vid` has been unified with something else or not. - pub fn var_diverges(&self, vid: ty::TyVid) -> bool { - self.values.get(vid.index as usize).diverging - } - - /// Returns the origin that was given when `vid` was created. - /// - /// Note that this function does not return care whether - /// `vid` has been unified with something else or not. - pub fn var_origin(&self, vid: ty::TyVid) -> &TypeVariableOrigin { - &self.values.get(vid.index as usize).origin - } - - /// Records that `a == b`, depending on `dir`. - /// - /// Precondition: neither `a` nor `b` are known. - pub fn equate(&mut self, a: ty::TyVid, b: ty::TyVid) { - debug_assert!(self.probe(a).is_unknown()); - debug_assert!(self.probe(b).is_unknown()); - self.eq_relations.union(a, b); - self.sub_relations.union(a, b); - } - - /// Records that `a <: b`, depending on `dir`. - /// - /// Precondition: neither `a` nor `b` are known. - pub fn sub(&mut self, a: ty::TyVid, b: ty::TyVid) { - debug_assert!(self.probe(a).is_unknown()); - debug_assert!(self.probe(b).is_unknown()); - self.sub_relations.union(a, b); - } - - /// Instantiates `vid` with the type `ty`. - /// - /// Precondition: `vid` must not have been previously instantiated. - pub fn instantiate(&mut self, vid: ty::TyVid, ty: Ty<'tcx>) { - let vid = self.root_var(vid); - debug_assert!(self.probe(vid).is_unknown()); - debug_assert!( - self.eq_relations.probe_value(vid).is_unknown(), - "instantiating type variable `{:?}` twice: new-value = {:?}, old-value={:?}", - vid, - ty, - self.eq_relations.probe_value(vid) - ); - self.eq_relations.union_value(vid, TypeVariableValue::Known { value: ty }); - - // Hack: we only need this so that `types_escaping_snapshot` - // can see what has been unified; see the Delegate impl for - // more details. - self.values.record(Instantiate { vid }); - } - - /// Creates a new type variable. - /// - /// - `diverging`: indicates if this is a "diverging" type - /// variable, e.g., one created as the type of a `return` - /// expression. The code in this module doesn't care if a - /// variable is diverging, but the main Rust type-checker will - /// sometimes "unify" such variables with the `!` or `()` types. - /// - `origin`: indicates *why* the type variable was created. - /// The code in this module doesn't care, but it can be useful - /// for improving error messages. - pub fn new_var( - &mut self, - universe: ty::UniverseIndex, - diverging: bool, - origin: TypeVariableOrigin, - ) -> ty::TyVid { - let eq_key = self.eq_relations.new_key(TypeVariableValue::Unknown { universe }); - - let sub_key = self.sub_relations.new_key(()); - assert_eq!(eq_key.vid, sub_key); - - let index = self.values.push(TypeVariableData { origin, diverging }); - assert_eq!(eq_key.vid.index, index as u32); - - debug!( - "new_var(index={:?}, universe={:?}, diverging={:?}, origin={:?}", - eq_key.vid, universe, diverging, origin, - ); - - eq_key.vid - } - - /// Returns the number of type variables created thus far. - pub fn num_vars(&self) -> usize { - self.values.len() - } - - /// Returns the "root" variable of `vid` in the `eq_relations` - /// equivalence table. All type variables that have been equated - /// will yield the same root variable (per the union-find - /// algorithm), so `root_var(a) == root_var(b)` implies that `a == - /// b` (transitively). - pub fn root_var(&mut self, vid: ty::TyVid) -> ty::TyVid { - self.eq_relations.find(vid).vid - } - - /// Returns the "root" variable of `vid` in the `sub_relations` - /// equivalence table. All type variables that have been are - /// related via equality or subtyping will yield the same root - /// variable (per the union-find algorithm), so `sub_root_var(a) - /// == sub_root_var(b)` implies that: - /// - /// exists X. (a <: X || X <: a) && (b <: X || X <: b) - pub fn sub_root_var(&mut self, vid: ty::TyVid) -> ty::TyVid { - self.sub_relations.find(vid) - } - - /// Returns `true` if `a` and `b` have same "sub-root" (i.e., exists some - /// type X such that `forall i in {a, b}. (i <: X || X <: i)`. - pub fn sub_unified(&mut self, a: ty::TyVid, b: ty::TyVid) -> bool { - self.sub_root_var(a) == self.sub_root_var(b) - } - - /// Retrieves the type to which `vid` has been instantiated, if - /// any. - pub fn probe(&mut self, vid: ty::TyVid) -> TypeVariableValue<'tcx> { - self.inlined_probe(vid) - } - - /// An always-inlined variant of `probe`, for very hot call sites. - #[inline(always)] - pub fn inlined_probe(&mut self, vid: ty::TyVid) -> TypeVariableValue<'tcx> { - self.eq_relations.inlined_probe_value(vid) - } - - /// If `t` is a type-inference variable, and it has been - /// instantiated, then return the with which it was - /// instantiated. Otherwise, returns `t`. - pub fn replace_if_possible(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - match t.kind { - ty::Infer(ty::TyVar(v)) => match self.probe(v) { - TypeVariableValue::Unknown { .. } => t, - TypeVariableValue::Known { value } => value, - }, - _ => t, - } - } - - /// Creates a snapshot of the type variable state. This snapshot - /// must later be committed (`commit()`) or rolled back - /// (`rollback_to()`). Nested snapshots are permitted, but must - /// be processed in a stack-like fashion. - pub fn snapshot(&mut self) -> Snapshot<'tcx> { - Snapshot { - snapshot: self.values.start_snapshot(), - eq_snapshot: self.eq_relations.snapshot(), - sub_snapshot: self.sub_relations.snapshot(), - } - } - - /// Undoes all changes since the snapshot was created. Any - /// snapshots created since that point must already have been - /// committed or rolled back. - pub fn rollback_to(&mut self, s: Snapshot<'tcx>) { - debug!("rollback_to{:?}", { - for action in self.values.actions_since_snapshot(&s.snapshot) { - if let sv::UndoLog::NewElem(index) = *action { - debug!("inference variable _#{}t popped", index) - } - } - }); - - let Snapshot { snapshot, eq_snapshot, sub_snapshot } = s; - self.values.rollback_to(snapshot); - self.eq_relations.rollback_to(eq_snapshot); - self.sub_relations.rollback_to(sub_snapshot); - } - - /// Commits all changes since the snapshot was created, making - /// them permanent (unless this snapshot was created within - /// another snapshot). Any snapshots created since that point - /// must already have been committed or rolled back. - pub fn commit(&mut self, s: Snapshot<'tcx>) { - let Snapshot { snapshot, eq_snapshot, sub_snapshot } = s; - self.values.commit(snapshot); - self.eq_relations.commit(eq_snapshot); - self.sub_relations.commit(sub_snapshot); - } - - /// Returns a range of the type variables created during the snapshot. - pub fn vars_since_snapshot( - &mut self, - s: &Snapshot<'tcx>, - ) -> (Range<TyVid>, Vec<TypeVariableOrigin>) { - let range = self.eq_relations.vars_since_snapshot(&s.eq_snapshot); - ( - range.start.vid..range.end.vid, - (range.start.vid.index..range.end.vid.index) - .map(|index| self.values.get(index as usize).origin) - .collect(), - ) - } - - /// Finds the set of type variables that existed *before* `s` - /// but which have only been unified since `s` started, and - /// return the types with which they were unified. So if we had - /// a type variable `V0`, then we started the snapshot, then we - /// created a type variable `V1`, unified `V0` with `T0`, and - /// unified `V1` with `T1`, this function would return `{T0}`. - pub fn types_escaping_snapshot(&mut self, s: &Snapshot<'tcx>) -> Vec<Ty<'tcx>> { - let mut new_elem_threshold = u32::MAX; - let mut escaping_types = Vec::new(); - let actions_since_snapshot = self.values.actions_since_snapshot(&s.snapshot); - debug!("actions_since_snapshot.len() = {}", actions_since_snapshot.len()); - for action in actions_since_snapshot { - match *action { - sv::UndoLog::NewElem(index) => { - // if any new variables were created during the - // snapshot, remember the lower index (which will - // always be the first one we see). Note that this - // action must precede those variables being - // specified. - new_elem_threshold = cmp::min(new_elem_threshold, index as u32); - debug!("NewElem({}) new_elem_threshold={}", index, new_elem_threshold); - } - - sv::UndoLog::Other(Instantiate { vid, .. }) => { - if vid.index < new_elem_threshold { - // quick check to see if this variable was - // created since the snapshot started or not. - let escaping_type = match self.eq_relations.probe_value(vid) { - TypeVariableValue::Unknown { .. } => bug!(), - TypeVariableValue::Known { value } => value, - }; - escaping_types.push(escaping_type); - } - debug!("SpecifyVar({:?}) new_elem_threshold={}", vid, new_elem_threshold); - } - - _ => {} - } - } - - escaping_types - } - - /// Returns indices of all variables that are not yet - /// instantiated. - pub fn unsolved_variables(&mut self) -> Vec<ty::TyVid> { - (0..self.values.len()) - .filter_map(|i| { - let vid = ty::TyVid { index: i as u32 }; - match self.probe(vid) { - TypeVariableValue::Unknown { .. } => Some(vid), - TypeVariableValue::Known { .. } => None, - } - }) - .collect() - } -} - -impl sv::SnapshotVecDelegate for Delegate { - type Value = TypeVariableData; - type Undo = Instantiate; - - fn reverse(_values: &mut Vec<TypeVariableData>, _action: Instantiate) { - // We don't actually have to *do* anything to reverse an - // instantiation; the value for a variable is stored in the - // `eq_relations` and hence its rollback code will handle - // it. In fact, we could *almost* just remove the - // `SnapshotVec` entirely, except that we would have to - // reproduce *some* of its logic, since we want to know which - // type variables have been instantiated since the snapshot - // was started, so we can implement `types_escaping_snapshot`. - // - // (If we extended the `UnificationTable` to let us see which - // values have been unified and so forth, that might also - // suffice.) - } -} - -/////////////////////////////////////////////////////////////////////////// - -/// These structs (a newtyped TyVid) are used as the unification key -/// for the `eq_relations`; they carry a `TypeVariableValue` along -/// with them. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -struct TyVidEqKey<'tcx> { - vid: ty::TyVid, - - // in the table, we map each ty-vid to one of these: - phantom: PhantomData<TypeVariableValue<'tcx>>, -} - -impl<'tcx> From<ty::TyVid> for TyVidEqKey<'tcx> { - fn from(vid: ty::TyVid) -> Self { - TyVidEqKey { vid, phantom: PhantomData } - } -} - -impl<'tcx> ut::UnifyKey for TyVidEqKey<'tcx> { - type Value = TypeVariableValue<'tcx>; - fn index(&self) -> u32 { - self.vid.index - } - fn from_index(i: u32) -> Self { - TyVidEqKey::from(ty::TyVid { index: i }) - } - fn tag() -> &'static str { - "TyVidEqKey" - } -} - -impl<'tcx> ut::UnifyValue for TypeVariableValue<'tcx> { - type Error = ut::NoError; - - fn unify_values(value1: &Self, value2: &Self) -> Result<Self, ut::NoError> { - match (value1, value2) { - // We never equate two type variables, both of which - // have known types. Instead, we recursively equate - // those types. - (&TypeVariableValue::Known { .. }, &TypeVariableValue::Known { .. }) => { - bug!("equating two type variables, both of which have known types") - } - - // If one side is known, prefer that one. - (&TypeVariableValue::Known { .. }, &TypeVariableValue::Unknown { .. }) => Ok(*value1), - (&TypeVariableValue::Unknown { .. }, &TypeVariableValue::Known { .. }) => Ok(*value2), - - // If both sides are *unknown*, it hardly matters, does it? - ( - &TypeVariableValue::Unknown { universe: universe1 }, - &TypeVariableValue::Unknown { universe: universe2 }, - ) => { - // If we unify two unbound variables, ?T and ?U, then whatever - // value they wind up taking (which must be the same value) must - // be nameable by both universes. Therefore, the resulting - // universe is the minimum of the two universes, because that is - // the one which contains the fewest names in scope. - let universe = cmp::min(universe1, universe2); - Ok(TypeVariableValue::Unknown { universe }) - } - } - } -} diff --git a/src/librustc/infer/types/mod.rs b/src/librustc/infer/types/mod.rs deleted file mode 100644 index 534f4cb179c..00000000000 --- a/src/librustc/infer/types/mod.rs +++ /dev/null @@ -1,31 +0,0 @@ -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>>>, -} diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index ceac68704d2..e1e774b853c 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -13,10 +13,6 @@ //! defined in the `ty` module. This includes the **type context** //! (or `tcx`), which is the central context during most of //! compilation, containing the interners and other things. -//! - **Traits.** Trait resolution is implemented in the `traits` module. -//! - **Type inference.** The type inference code can be found in the `infer` module; -//! this code handles low-level equality and subtyping operations. The -//! type check pass in the compiler is found in the `librustc_typeck` crate. //! //! For more information about how rustc works, see the [rustc guide]. //! diff --git a/src/librustc/traits/auto_trait.rs b/src/librustc/traits/auto_trait.rs deleted file mode 100644 index 3ab87ce8eb4..00000000000 --- a/src/librustc/traits/auto_trait.rs +++ /dev/null @@ -1,837 +0,0 @@ -//! Support code for rustdoc and external tools. -//! You really don't want to be using this unless you need to. - -use super::*; - -use crate::infer::region_constraints::{Constraint, RegionConstraintData}; -use crate::infer::InferCtxt; -use crate::ty::fold::TypeFolder; -use crate::ty::{Region, RegionVid}; - -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; - -use std::collections::hash_map::Entry; -use std::collections::VecDeque; - -// FIXME(twk): this is obviously not nice to duplicate like that -#[derive(Eq, PartialEq, Hash, Copy, Clone, Debug)] -pub enum RegionTarget<'tcx> { - Region(Region<'tcx>), - RegionVid(RegionVid), -} - -#[derive(Default, Debug, Clone)] -pub struct RegionDeps<'tcx> { - larger: FxHashSet<RegionTarget<'tcx>>, - smaller: FxHashSet<RegionTarget<'tcx>>, -} - -pub enum AutoTraitResult<A> { - ExplicitImpl, - PositiveImpl(A), - NegativeImpl, -} - -impl<A> AutoTraitResult<A> { - fn is_auto(&self) -> bool { - match *self { - AutoTraitResult::PositiveImpl(_) | AutoTraitResult::NegativeImpl => true, - _ => false, - } - } -} - -pub struct AutoTraitInfo<'cx> { - pub full_user_env: ty::ParamEnv<'cx>, - pub region_data: RegionConstraintData<'cx>, - pub vid_to_region: FxHashMap<ty::RegionVid, ty::Region<'cx>>, -} - -pub struct AutoTraitFinder<'tcx> { - tcx: TyCtxt<'tcx>, -} - -impl<'tcx> AutoTraitFinder<'tcx> { - pub fn new(tcx: TyCtxt<'tcx>) -> Self { - AutoTraitFinder { tcx } - } - - /// Makes a best effort to determine whether and under which conditions an auto trait is - /// implemented for a type. For example, if you have - /// - /// ``` - /// struct Foo<T> { data: Box<T> } - /// ``` - /// - /// then this might return that Foo<T>: Send if T: Send (encoded in the AutoTraitResult type). - /// The analysis attempts to account for custom impls as well as other complex cases. This - /// result is intended for use by rustdoc and other such consumers. - /// - /// (Note that due to the coinductive nature of Send, the full and correct result is actually - /// quite simple to generate. That is, when a type has no custom impl, it is Send iff its field - /// types are all Send. So, in our example, we might have that Foo<T>: Send if Box<T>: Send. - /// But this is often not the best way to present to the user.) - /// - /// Warning: The API should be considered highly unstable, and it may be refactored or removed - /// in the future. - pub fn find_auto_trait_generics<A>( - &self, - ty: Ty<'tcx>, - orig_env: ty::ParamEnv<'tcx>, - trait_did: DefId, - auto_trait_callback: impl Fn(&InferCtxt<'_, 'tcx>, AutoTraitInfo<'tcx>) -> A, - ) -> AutoTraitResult<A> { - let tcx = self.tcx; - - let trait_ref = ty::TraitRef { def_id: trait_did, substs: tcx.mk_substs_trait(ty, &[]) }; - - let trait_pred = ty::Binder::bind(trait_ref); - - let bail_out = tcx.infer_ctxt().enter(|infcx| { - let mut selcx = SelectionContext::with_negative(&infcx, true); - let result = selcx.select(&Obligation::new( - ObligationCause::dummy(), - orig_env, - trait_pred.to_poly_trait_predicate(), - )); - - match result { - Ok(Some(Vtable::VtableImpl(_))) => { - debug!( - "find_auto_trait_generics({:?}): \ - manual impl found, bailing out", - trait_ref - ); - true - } - _ => false, - } - }); - - // If an explicit impl exists, it always takes priority over an auto impl - if bail_out { - return AutoTraitResult::ExplicitImpl; - } - - return tcx.infer_ctxt().enter(|mut infcx| { - let mut fresh_preds = FxHashSet::default(); - - // Due to the way projections are handled by SelectionContext, we need to run - // evaluate_predicates twice: once on the original param env, and once on the result of - // the first evaluate_predicates call. - // - // The problem is this: most of rustc, including SelectionContext and traits::project, - // are designed to work with a concrete usage of a type (e.g., Vec<u8> - // fn<T>() { Vec<T> }. This information will generally never change - given - // the 'T' in fn<T>() { ... }, we'll never know anything else about 'T'. - // If we're unable to prove that 'T' implements a particular trait, we're done - - // there's nothing left to do but error out. - // - // However, synthesizing an auto trait impl works differently. Here, we start out with - // a set of initial conditions - the ParamEnv of the struct/enum/union we're dealing - // with - and progressively discover the conditions we need to fulfill for it to - // implement a certain auto trait. This ends up breaking two assumptions made by trait - // selection and projection: - // - // * We can always cache the result of a particular trait selection for the lifetime of - // an InfCtxt - // * Given a projection bound such as '<T as SomeTrait>::SomeItem = K', if 'T: - // SomeTrait' doesn't hold, then we don't need to care about the 'SomeItem = K' - // - // We fix the first assumption by manually clearing out all of the InferCtxt's caches - // in between calls to SelectionContext.select. This allows us to keep all of the - // intermediate types we create bound to the 'tcx lifetime, rather than needing to lift - // them between calls. - // - // We fix the second assumption by reprocessing the result of our first call to - // evaluate_predicates. Using the example of '<T as SomeTrait>::SomeItem = K', our first - // pass will pick up 'T: SomeTrait', but not 'SomeItem = K'. On our second pass, - // traits::project will see that 'T: SomeTrait' is in our ParamEnv, allowing - // SelectionContext to return it back to us. - - let (new_env, user_env) = match self.evaluate_predicates( - &mut infcx, - trait_did, - ty, - orig_env, - orig_env, - &mut fresh_preds, - false, - ) { - Some(e) => e, - None => return AutoTraitResult::NegativeImpl, - }; - - let (full_env, full_user_env) = self - .evaluate_predicates( - &mut infcx, - trait_did, - ty, - new_env, - user_env, - &mut fresh_preds, - true, - ) - .unwrap_or_else(|| { - panic!("Failed to fully process: {:?} {:?} {:?}", ty, trait_did, orig_env) - }); - - debug!( - "find_auto_trait_generics({:?}): fulfilling \ - with {:?}", - trait_ref, full_env - ); - infcx.clear_caches(); - - // At this point, we already have all of the bounds we need. FulfillmentContext is used - // to store all of the necessary region/lifetime bounds in the InferContext, as well as - // an additional sanity check. - let mut fulfill = FulfillmentContext::new(); - fulfill.register_bound( - &infcx, - full_env, - ty, - trait_did, - ObligationCause::misc(DUMMY_SP, hir::DUMMY_HIR_ID), - ); - fulfill.select_all_or_error(&infcx).unwrap_or_else(|e| { - panic!("Unable to fulfill trait {:?} for '{:?}': {:?}", trait_did, ty, e) - }); - - let body_id_map: FxHashMap<_, _> = infcx - .inner - .borrow() - .region_obligations - .iter() - .map(|&(id, _)| (id, vec![])) - .collect(); - - infcx.process_registered_region_obligations(&body_id_map, None, full_env); - - let region_data = infcx - .inner - .borrow_mut() - .unwrap_region_constraints() - .region_constraint_data() - .clone(); - - let vid_to_region = self.map_vid_to_region(®ion_data); - - let info = AutoTraitInfo { full_user_env, region_data, vid_to_region }; - - return AutoTraitResult::PositiveImpl(auto_trait_callback(&infcx, info)); - }); - } -} - -impl AutoTraitFinder<'tcx> { - /// The core logic responsible for computing the bounds for our synthesized impl. - /// - /// To calculate the bounds, we call `SelectionContext.select` in a loop. Like - /// `FulfillmentContext`, we recursively select the nested obligations of predicates we - /// encounter. However, whenever we encounter an `UnimplementedError` involving a type - /// parameter, we add it to our `ParamEnv`. Since our goal is to determine when a particular - /// type implements an auto trait, Unimplemented errors tell us what conditions need to be met. - /// - /// This method ends up working somewhat similarly to `FulfillmentContext`, but with a few key - /// differences. `FulfillmentContext` works under the assumption that it's dealing with concrete - /// user code. According, it considers all possible ways that a `Predicate` could be met, which - /// isn't always what we want for a synthesized impl. For example, given the predicate `T: - /// Iterator`, `FulfillmentContext` can end up reporting an Unimplemented error for `T: - /// IntoIterator` -- since there's an implementation of `Iterator` where `T: IntoIterator`, - /// `FulfillmentContext` will drive `SelectionContext` to consider that impl before giving up. - /// If we were to rely on `FulfillmentContext`s decision, we might end up synthesizing an impl - /// like this: - /// - /// impl<T> Send for Foo<T> where T: IntoIterator - /// - /// While it might be technically true that Foo implements Send where `T: IntoIterator`, - /// the bound is overly restrictive - it's really only necessary that `T: Iterator`. - /// - /// For this reason, `evaluate_predicates` handles predicates with type variables specially. - /// When we encounter an `Unimplemented` error for a bound such as `T: Iterator`, we immediately - /// add it to our `ParamEnv`, and add it to our stack for recursive evaluation. When we later - /// select it, we'll pick up any nested bounds, without ever inferring that `T: IntoIterator` - /// needs to hold. - /// - /// One additional consideration is supertrait bounds. Normally, a `ParamEnv` is only ever - /// constructed once for a given type. As part of the construction process, the `ParamEnv` will - /// have any supertrait bounds normalized -- e.g., if we have a type `struct Foo<T: Copy>`, the - /// `ParamEnv` will contain `T: Copy` and `T: Clone`, since `Copy: Clone`. When we construct our - /// own `ParamEnv`, we need to do this ourselves, through `traits::elaborate_predicates`, or - /// else `SelectionContext` will choke on the missing predicates. However, this should never - /// show up in the final synthesized generics: we don't want our generated docs page to contain - /// something like `T: Copy + Clone`, as that's redundant. Therefore, we keep track of a - /// separate `user_env`, which only holds the predicates that will actually be displayed to the - /// user. - fn evaluate_predicates( - &self, - infcx: &InferCtxt<'_, 'tcx>, - trait_did: DefId, - ty: Ty<'tcx>, - param_env: ty::ParamEnv<'tcx>, - user_env: ty::ParamEnv<'tcx>, - fresh_preds: &mut FxHashSet<ty::Predicate<'tcx>>, - only_projections: bool, - ) -> Option<(ty::ParamEnv<'tcx>, ty::ParamEnv<'tcx>)> { - let tcx = infcx.tcx; - - let mut select = SelectionContext::with_negative(&infcx, true); - - let mut already_visited = FxHashSet::default(); - let mut predicates = VecDeque::new(); - predicates.push_back(ty::Binder::bind(ty::TraitPredicate { - trait_ref: ty::TraitRef { - def_id: trait_did, - substs: infcx.tcx.mk_substs_trait(ty, &[]), - }, - })); - - let mut computed_preds: FxHashSet<_> = param_env.caller_bounds.iter().cloned().collect(); - let mut user_computed_preds: FxHashSet<_> = - user_env.caller_bounds.iter().cloned().collect(); - - let mut new_env = param_env; - let dummy_cause = ObligationCause::misc(DUMMY_SP, hir::DUMMY_HIR_ID); - - while let Some(pred) = predicates.pop_front() { - infcx.clear_caches(); - - if !already_visited.insert(pred) { - continue; - } - - // Call `infcx.resolve_vars_if_possible` to see if we can - // get rid of any inference variables. - let obligation = infcx.resolve_vars_if_possible(&Obligation::new( - dummy_cause.clone(), - new_env, - pred, - )); - let result = select.select(&obligation); - - match &result { - &Ok(Some(ref vtable)) => { - // If we see an explicit negative impl (e.g., `impl !Send for MyStruct`), - // we immediately bail out, since it's impossible for us to continue. - match vtable { - Vtable::VtableImpl(VtableImplData { impl_def_id, .. }) => { - // Blame 'tidy' for the weird bracket placement. - if infcx.tcx.impl_polarity(*impl_def_id) == ty::ImplPolarity::Negative { - debug!( - "evaluate_nested_obligations: found explicit negative impl\ - {:?}, bailing out", - impl_def_id - ); - return None; - } - } - _ => {} - } - - let obligations = vtable.clone().nested_obligations().into_iter(); - - if !self.evaluate_nested_obligations( - ty, - obligations, - &mut user_computed_preds, - fresh_preds, - &mut predicates, - &mut select, - only_projections, - ) { - return None; - } - } - &Ok(None) => {} - &Err(SelectionError::Unimplemented) => { - if self.is_param_no_infer(pred.skip_binder().trait_ref.substs) { - already_visited.remove(&pred); - self.add_user_pred( - &mut user_computed_preds, - ty::Predicate::Trait(pred, hir::Constness::NotConst), - ); - predicates.push_back(pred); - } else { - debug!( - "evaluate_nested_obligations: `Unimplemented` found, bailing: \ - {:?} {:?} {:?}", - ty, - pred, - pred.skip_binder().trait_ref.substs - ); - return None; - } - } - _ => panic!("Unexpected error for '{:?}': {:?}", ty, result), - }; - - computed_preds.extend(user_computed_preds.iter().cloned()); - let normalized_preds = - elaborate_predicates(tcx, computed_preds.iter().cloned().collect()); - new_env = - ty::ParamEnv::new(tcx.mk_predicates(normalized_preds), param_env.reveal, None); - } - - let final_user_env = ty::ParamEnv::new( - tcx.mk_predicates(user_computed_preds.into_iter()), - user_env.reveal, - None, - ); - debug!( - "evaluate_nested_obligations(ty={:?}, trait_did={:?}): succeeded with '{:?}' \ - '{:?}'", - ty, trait_did, new_env, final_user_env - ); - - return Some((new_env, final_user_env)); - } - - /// This method is designed to work around the following issue: - /// When we compute auto trait bounds, we repeatedly call `SelectionContext.select`, - /// progressively building a `ParamEnv` based on the results we get. - /// However, our usage of `SelectionContext` differs from its normal use within the compiler, - /// in that we capture and re-reprocess predicates from `Unimplemented` errors. - /// - /// This can lead to a corner case when dealing with region parameters. - /// During our selection loop in `evaluate_predicates`, we might end up with - /// two trait predicates that differ only in their region parameters: - /// one containing a HRTB lifetime parameter, and one containing a 'normal' - /// lifetime parameter. For example: - /// - /// T as MyTrait<'a> - /// T as MyTrait<'static> - /// - /// If we put both of these predicates in our computed `ParamEnv`, we'll - /// confuse `SelectionContext`, since it will (correctly) view both as being applicable. - /// - /// To solve this, we pick the 'more strict' lifetime bound -- i.e., the HRTB - /// Our end goal is to generate a user-visible description of the conditions - /// under which a type implements an auto trait. A trait predicate involving - /// a HRTB means that the type needs to work with any choice of lifetime, - /// not just one specific lifetime (e.g., `'static`). - fn add_user_pred<'c>( - &self, - user_computed_preds: &mut FxHashSet<ty::Predicate<'c>>, - new_pred: ty::Predicate<'c>, - ) { - let mut should_add_new = true; - user_computed_preds.retain(|&old_pred| { - match (&new_pred, old_pred) { - (&ty::Predicate::Trait(new_trait, _), ty::Predicate::Trait(old_trait, _)) => { - if new_trait.def_id() == old_trait.def_id() { - let new_substs = new_trait.skip_binder().trait_ref.substs; - let old_substs = old_trait.skip_binder().trait_ref.substs; - - if !new_substs.types().eq(old_substs.types()) { - // We can't compare lifetimes if the types are different, - // so skip checking `old_pred`. - return true; - } - - for (new_region, old_region) in - new_substs.regions().zip(old_substs.regions()) - { - match (new_region, old_region) { - // If both predicates have an `ReLateBound` (a HRTB) in the - // same spot, we do nothing. - ( - ty::RegionKind::ReLateBound(_, _), - ty::RegionKind::ReLateBound(_, _), - ) => {} - - (ty::RegionKind::ReLateBound(_, _), _) - | (_, ty::RegionKind::ReVar(_)) => { - // One of these is true: - // The new predicate has a HRTB in a spot where the old - // predicate does not (if they both had a HRTB, the previous - // match arm would have executed). A HRBT is a 'stricter' - // bound than anything else, so we want to keep the newer - // predicate (with the HRBT) in place of the old predicate. - // - // OR - // - // The old predicate has a region variable where the new - // predicate has some other kind of region. An region - // variable isn't something we can actually display to a user, - // so we choose their new predicate (which doesn't have a region - // varaible). - // - // In both cases, we want to remove the old predicate, - // from `user_computed_preds`, and replace it with the new - // one. Having both the old and the new - // predicate in a `ParamEnv` would confuse `SelectionContext`. - // - // We're currently in the predicate passed to 'retain', - // so we return `false` to remove the old predicate from - // `user_computed_preds`. - return false; - } - (_, ty::RegionKind::ReLateBound(_, _)) - | (ty::RegionKind::ReVar(_), _) => { - // This is the opposite situation as the previous arm. - // One of these is true: - // - // The old predicate has a HRTB lifetime in a place where the - // new predicate does not. - // - // OR - // - // The new predicate has a region variable where the old - // predicate has some other type of region. - // - // We want to leave the old - // predicate in `user_computed_preds`, and skip adding - // new_pred to `user_computed_params`. - should_add_new = false - } - _ => {} - } - } - } - } - _ => {} - } - return true; - }); - - if should_add_new { - user_computed_preds.insert(new_pred); - } - } - - /// This is very similar to `handle_lifetimes`. However, instead of matching `ty::Region`s - /// to each other, we match `ty::RegionVid`s to `ty::Region`s. - fn map_vid_to_region<'cx>( - &self, - regions: &RegionConstraintData<'cx>, - ) -> FxHashMap<ty::RegionVid, ty::Region<'cx>> { - let mut vid_map: FxHashMap<RegionTarget<'cx>, RegionDeps<'cx>> = FxHashMap::default(); - let mut finished_map = FxHashMap::default(); - - for constraint in regions.constraints.keys() { - match constraint { - &Constraint::VarSubVar(r1, r2) => { - { - let deps1 = vid_map.entry(RegionTarget::RegionVid(r1)).or_default(); - deps1.larger.insert(RegionTarget::RegionVid(r2)); - } - - let deps2 = vid_map.entry(RegionTarget::RegionVid(r2)).or_default(); - deps2.smaller.insert(RegionTarget::RegionVid(r1)); - } - &Constraint::RegSubVar(region, vid) => { - { - let deps1 = vid_map.entry(RegionTarget::Region(region)).or_default(); - deps1.larger.insert(RegionTarget::RegionVid(vid)); - } - - let deps2 = vid_map.entry(RegionTarget::RegionVid(vid)).or_default(); - deps2.smaller.insert(RegionTarget::Region(region)); - } - &Constraint::VarSubReg(vid, region) => { - finished_map.insert(vid, region); - } - &Constraint::RegSubReg(r1, r2) => { - { - let deps1 = vid_map.entry(RegionTarget::Region(r1)).or_default(); - deps1.larger.insert(RegionTarget::Region(r2)); - } - - let deps2 = vid_map.entry(RegionTarget::Region(r2)).or_default(); - deps2.smaller.insert(RegionTarget::Region(r1)); - } - } - } - - while !vid_map.is_empty() { - let target = *vid_map.keys().next().expect("Keys somehow empty"); - let deps = vid_map.remove(&target).expect("Entry somehow missing"); - - for smaller in deps.smaller.iter() { - for larger in deps.larger.iter() { - match (smaller, larger) { - (&RegionTarget::Region(_), &RegionTarget::Region(_)) => { - if let Entry::Occupied(v) = vid_map.entry(*smaller) { - let smaller_deps = v.into_mut(); - smaller_deps.larger.insert(*larger); - smaller_deps.larger.remove(&target); - } - - if let Entry::Occupied(v) = vid_map.entry(*larger) { - let larger_deps = v.into_mut(); - larger_deps.smaller.insert(*smaller); - larger_deps.smaller.remove(&target); - } - } - (&RegionTarget::RegionVid(v1), &RegionTarget::Region(r1)) => { - finished_map.insert(v1, r1); - } - (&RegionTarget::Region(_), &RegionTarget::RegionVid(_)) => { - // Do nothing; we don't care about regions that are smaller than vids. - } - (&RegionTarget::RegionVid(_), &RegionTarget::RegionVid(_)) => { - if let Entry::Occupied(v) = vid_map.entry(*smaller) { - let smaller_deps = v.into_mut(); - smaller_deps.larger.insert(*larger); - smaller_deps.larger.remove(&target); - } - - if let Entry::Occupied(v) = vid_map.entry(*larger) { - let larger_deps = v.into_mut(); - larger_deps.smaller.insert(*smaller); - larger_deps.smaller.remove(&target); - } - } - } - } - } - } - finished_map - } - - fn is_param_no_infer(&self, substs: SubstsRef<'_>) -> bool { - return self.is_of_param(substs.type_at(0)) && !substs.types().any(|t| t.has_infer_types()); - } - - pub fn is_of_param(&self, ty: Ty<'_>) -> bool { - return match ty.kind { - ty::Param(_) => true, - ty::Projection(p) => self.is_of_param(p.self_ty()), - _ => false, - }; - } - - fn is_self_referential_projection(&self, p: ty::PolyProjectionPredicate<'_>) -> bool { - match p.ty().skip_binder().kind { - ty::Projection(proj) if proj == p.skip_binder().projection_ty => true, - _ => false, - } - } - - fn evaluate_nested_obligations( - &self, - ty: Ty<'_>, - nested: impl Iterator<Item = Obligation<'tcx, ty::Predicate<'tcx>>>, - computed_preds: &mut FxHashSet<ty::Predicate<'tcx>>, - fresh_preds: &mut FxHashSet<ty::Predicate<'tcx>>, - predicates: &mut VecDeque<ty::PolyTraitPredicate<'tcx>>, - select: &mut SelectionContext<'_, 'tcx>, - only_projections: bool, - ) -> bool { - let dummy_cause = ObligationCause::misc(DUMMY_SP, hir::DUMMY_HIR_ID); - - for (obligation, mut predicate) in nested.map(|o| (o.clone(), o.predicate)) { - let is_new_pred = fresh_preds.insert(self.clean_pred(select.infcx(), predicate)); - - // Resolve any inference variables that we can, to help selection succeed - predicate = select.infcx().resolve_vars_if_possible(&predicate); - - // We only add a predicate as a user-displayable bound if - // it involves a generic parameter, and doesn't contain - // any inference variables. - // - // Displaying a bound involving a concrete type (instead of a generic - // parameter) would be pointless, since it's always true - // (e.g. u8: Copy) - // Displaying an inference variable is impossible, since they're - // an internal compiler detail without a defined visual representation - // - // We check this by calling is_of_param on the relevant types - // from the various possible predicates - match &predicate { - &ty::Predicate::Trait(p, _) => { - if self.is_param_no_infer(p.skip_binder().trait_ref.substs) - && !only_projections - && is_new_pred - { - self.add_user_pred(computed_preds, predicate); - } - predicates.push_back(p); - } - &ty::Predicate::Projection(p) => { - debug!( - "evaluate_nested_obligations: examining projection predicate {:?}", - predicate - ); - - // As described above, we only want to display - // bounds which include a generic parameter but don't include - // an inference variable. - // Additionally, we check if we've seen this predicate before, - // to avoid rendering duplicate bounds to the user. - if self.is_param_no_infer(p.skip_binder().projection_ty.substs) - && !p.ty().skip_binder().has_infer_types() - && is_new_pred - { - debug!( - "evaluate_nested_obligations: adding projection predicate\ - to computed_preds: {:?}", - predicate - ); - - // Under unusual circumstances, we can end up with a self-refeential - // projection predicate. For example: - // <T as MyType>::Value == <T as MyType>::Value - // Not only is displaying this to the user pointless, - // having it in the ParamEnv will cause an issue if we try to call - // poly_project_and_unify_type on the predicate, since this kind of - // predicate will normally never end up in a ParamEnv. - // - // For these reasons, we ignore these weird predicates, - // ensuring that we're able to properly synthesize an auto trait impl - if self.is_self_referential_projection(p) { - debug!( - "evaluate_nested_obligations: encountered a projection - predicate equating a type with itself! Skipping" - ); - } else { - self.add_user_pred(computed_preds, predicate); - } - } - - // There are three possible cases when we project a predicate: - // - // 1. We encounter an error. This means that it's impossible for - // our current type to implement the auto trait - there's bound - // that we could add to our ParamEnv that would 'fix' this kind - // of error, as it's not caused by an unimplemented type. - // - // 2. We successfully project the predicate (Ok(Some(_))), generating - // some subobligations. We then process these subobligations - // like any other generated sub-obligations. - // - // 3. We receieve an 'ambiguous' result (Ok(None)) - // If we were actually trying to compile a crate, - // we would need to re-process this obligation later. - // However, all we care about is finding out what bounds - // are needed for our type to implement a particular auto trait. - // We've already added this obligation to our computed ParamEnv - // above (if it was necessary). Therefore, we don't need - // to do any further processing of the obligation. - // - // Note that we *must* try to project *all* projection predicates - // we encounter, even ones without inference variable. - // This ensures that we detect any projection errors, - // which indicate that our type can *never* implement the given - // auto trait. In that case, we will generate an explicit negative - // impl (e.g. 'impl !Send for MyType'). However, we don't - // try to process any of the generated subobligations - - // they contain no new information, since we already know - // that our type implements the projected-through trait, - // and can lead to weird region issues. - // - // Normally, we'll generate a negative impl as a result of encountering - // a type with an explicit negative impl of an auto trait - // (for example, raw pointers have !Send and !Sync impls) - // However, through some **interesting** manipulations of the type - // system, it's actually possible to write a type that never - // implements an auto trait due to a projection error, not a normal - // negative impl error. To properly handle this case, we need - // to ensure that we catch any potential projection errors, - // and turn them into an explicit negative impl for our type. - debug!("Projecting and unifying projection predicate {:?}", predicate); - - match poly_project_and_unify_type(select, &obligation.with(p)) { - Err(e) => { - debug!( - "evaluate_nested_obligations: Unable to unify predicate \ - '{:?}' '{:?}', bailing out", - ty, e - ); - return false; - } - Ok(Some(v)) => { - // We only care about sub-obligations - // when we started out trying to unify - // some inference variables. See the comment above - // for more infomration - if p.ty().skip_binder().has_infer_types() { - if !self.evaluate_nested_obligations( - ty, - v.clone().iter().cloned(), - computed_preds, - fresh_preds, - predicates, - select, - only_projections, - ) { - return false; - } - } - } - Ok(None) => { - // It's ok not to make progress when hvave no inference variables - - // in that case, we were only performing unifcation to check if an - // error occurred (which would indicate that it's impossible for our - // type to implement the auto trait). - // However, we should always make progress (either by generating - // subobligations or getting an error) when we started off with - // inference variables - if p.ty().skip_binder().has_infer_types() { - panic!("Unexpected result when selecting {:?} {:?}", ty, obligation) - } - } - } - } - &ty::Predicate::RegionOutlives(ref binder) => { - if select.infcx().region_outlives_predicate(&dummy_cause, binder).is_err() { - return false; - } - } - &ty::Predicate::TypeOutlives(ref binder) => { - match ( - binder.no_bound_vars(), - binder.map_bound_ref(|pred| pred.0).no_bound_vars(), - ) { - (None, Some(t_a)) => { - select.infcx().register_region_obligation_with_cause( - t_a, - select.infcx().tcx.lifetimes.re_static, - &dummy_cause, - ); - } - (Some(ty::OutlivesPredicate(t_a, r_b)), _) => { - select.infcx().register_region_obligation_with_cause( - t_a, - r_b, - &dummy_cause, - ); - } - _ => {} - }; - } - _ => panic!("Unexpected predicate {:?} {:?}", ty, predicate), - }; - } - return true; - } - - pub fn clean_pred( - &self, - infcx: &InferCtxt<'_, 'tcx>, - p: ty::Predicate<'tcx>, - ) -> ty::Predicate<'tcx> { - infcx.freshen(p) - } -} - -// Replaces all ReVars in a type with ty::Region's, using the provided map -pub struct RegionReplacer<'a, 'tcx> { - vid_to_region: &'a FxHashMap<ty::RegionVid, ty::Region<'tcx>>, - tcx: TyCtxt<'tcx>, -} - -impl<'a, 'tcx> TypeFolder<'tcx> for RegionReplacer<'a, 'tcx> { - fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { - self.tcx - } - - fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { - (match r { - &ty::ReVar(vid) => self.vid_to_region.get(&vid).cloned(), - _ => None, - }) - .unwrap_or_else(|| r.super_fold_with(self)) - } -} diff --git a/src/librustc/traits/chalk_fulfill.rs b/src/librustc/traits/chalk_fulfill.rs deleted file mode 100644 index a765e55d99f..00000000000 --- a/src/librustc/traits/chalk_fulfill.rs +++ /dev/null @@ -1,159 +0,0 @@ -use crate::infer::canonical::{Canonical, OriginalQueryValues}; -use crate::infer::InferCtxt; -use crate::traits::query::NoSolution; -use crate::traits::{ - Environment, FulfillmentError, FulfillmentErrorCode, InEnvironment, ObligationCause, - PredicateObligation, SelectionError, TraitEngine, -}; -use crate::ty::{self, Ty}; -use rustc_data_structures::fx::FxHashSet; - -pub type CanonicalGoal<'tcx> = Canonical<'tcx, InEnvironment<'tcx, ty::Predicate<'tcx>>>; - -pub struct FulfillmentContext<'tcx> { - obligations: FxHashSet<InEnvironment<'tcx, PredicateObligation<'tcx>>>, -} - -impl FulfillmentContext<'tcx> { - crate fn new() -> Self { - FulfillmentContext { obligations: FxHashSet::default() } - } -} - -fn in_environment( - infcx: &InferCtxt<'_, 'tcx>, - obligation: PredicateObligation<'tcx>, -) -> InEnvironment<'tcx, PredicateObligation<'tcx>> { - assert!(!infcx.is_in_snapshot()); - let obligation = infcx.resolve_vars_if_possible(&obligation); - - let environment = match obligation.param_env.def_id { - Some(def_id) => infcx.tcx.environment(def_id), - None if obligation.param_env.caller_bounds.is_empty() => { - Environment { clauses: ty::List::empty() } - } - _ => bug!("non-empty `ParamEnv` with no def-id"), - }; - - InEnvironment { environment, goal: obligation } -} - -impl TraitEngine<'tcx> for FulfillmentContext<'tcx> { - fn normalize_projection_type( - &mut self, - infcx: &InferCtxt<'_, 'tcx>, - _param_env: ty::ParamEnv<'tcx>, - projection_ty: ty::ProjectionTy<'tcx>, - _cause: ObligationCause<'tcx>, - ) -> Ty<'tcx> { - infcx.tcx.mk_ty(ty::Projection(projection_ty)) - } - - fn register_predicate_obligation( - &mut self, - infcx: &InferCtxt<'_, 'tcx>, - obligation: PredicateObligation<'tcx>, - ) { - self.obligations.insert(in_environment(infcx, obligation)); - } - - fn select_all_or_error( - &mut self, - infcx: &InferCtxt<'_, 'tcx>, - ) -> Result<(), Vec<FulfillmentError<'tcx>>> { - self.select_where_possible(infcx)?; - - if self.obligations.is_empty() { - Ok(()) - } else { - let errors = self - .obligations - .iter() - .map(|obligation| FulfillmentError { - obligation: obligation.goal.clone(), - code: FulfillmentErrorCode::CodeAmbiguity, - points_at_arg_span: false, - }) - .collect(); - Err(errors) - } - } - - fn select_where_possible( - &mut self, - infcx: &InferCtxt<'_, 'tcx>, - ) -> Result<(), Vec<FulfillmentError<'tcx>>> { - let mut errors = Vec::new(); - let mut next_round = FxHashSet::default(); - let mut making_progress; - - loop { - making_progress = false; - - // We iterate over all obligations, and record if we are able - // to unambiguously prove at least one obligation. - for obligation in self.obligations.drain() { - let mut orig_values = OriginalQueryValues::default(); - let canonical_goal = infcx.canonicalize_query( - &InEnvironment { - environment: obligation.environment, - goal: obligation.goal.predicate, - }, - &mut orig_values, - ); - - match infcx.tcx.evaluate_goal(canonical_goal) { - Ok(response) => { - if response.is_proven() { - making_progress = true; - - match infcx.instantiate_query_response_and_region_obligations( - &obligation.goal.cause, - obligation.goal.param_env, - &orig_values, - &response, - ) { - Ok(infer_ok) => next_round.extend( - infer_ok - .obligations - .into_iter() - .map(|obligation| in_environment(infcx, obligation)), - ), - - Err(_err) => errors.push(FulfillmentError { - obligation: obligation.goal, - code: FulfillmentErrorCode::CodeSelectionError( - SelectionError::Unimplemented, - ), - points_at_arg_span: false, - }), - } - } else { - // Ambiguous: retry at next round. - next_round.insert(obligation); - } - } - - Err(NoSolution) => errors.push(FulfillmentError { - obligation: obligation.goal, - code: FulfillmentErrorCode::CodeSelectionError( - SelectionError::Unimplemented, - ), - points_at_arg_span: false, - }), - } - } - next_round = std::mem::replace(&mut self.obligations, next_round); - - if !making_progress { - break; - } - } - - if errors.is_empty() { Ok(()) } else { Err(errors) } - } - - fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> { - self.obligations.iter().map(|obligation| obligation.goal.clone()).collect() - } -} diff --git a/src/librustc/traits/codegen/mod.rs b/src/librustc/traits/codegen/mod.rs deleted file mode 100644 index 8a264a79fb6..00000000000 --- a/src/librustc/traits/codegen/mod.rs +++ /dev/null @@ -1,110 +0,0 @@ -// This file contains various trait resolution methods used by codegen. -// They all assume regions can be erased and monomorphic types. It -// seems likely that they should eventually be merged into more -// general routines. - -use crate::infer::InferCtxt; -use crate::traits::{ - FulfillmentContext, Obligation, ObligationCause, SelectionContext, TraitEngine, Vtable, -}; -use crate::ty::fold::TypeFoldable; -use crate::ty::{self, TyCtxt}; - -/// Attempts to resolve an obligation to a vtable. The result is -/// a shallow vtable resolution, meaning that we do not -/// (necessarily) resolve all nested obligations on the impl. Note -/// that type check should guarantee to us that all nested -/// obligations *could be* resolved if we wanted to. -/// Assumes that this is run after the entire crate has been successfully type-checked. -pub fn codegen_fulfill_obligation<'tcx>( - ty: TyCtxt<'tcx>, - (param_env, trait_ref): (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>), -) -> Vtable<'tcx, ()> { - // Remove any references to regions; this helps improve caching. - let trait_ref = ty.erase_regions(&trait_ref); - - debug!( - "codegen_fulfill_obligation(trait_ref={:?}, def_id={:?})", - (param_env, trait_ref), - trait_ref.def_id() - ); - - // Do the initial selection for the obligation. This yields the - // shallow result we are looking for -- that is, what specific impl. - ty.infer_ctxt().enter(|infcx| { - let mut selcx = SelectionContext::new(&infcx); - - let obligation_cause = ObligationCause::dummy(); - let obligation = - Obligation::new(obligation_cause, param_env, trait_ref.to_poly_trait_predicate()); - - let selection = match selcx.select(&obligation) { - Ok(Some(selection)) => selection, - Ok(None) => { - // Ambiguity can happen when monomorphizing during trans - // expands to some humongo type that never occurred - // statically -- this humongo type can then overflow, - // leading to an ambiguous result. So report this as an - // overflow bug, since I believe this is the only case - // where ambiguity can result. - bug!( - "Encountered ambiguity selecting `{:?}` during codegen, \ - presuming due to overflow", - trait_ref - ) - } - Err(e) => { - bug!("Encountered error `{:?}` selecting `{:?}` during codegen", e, trait_ref) - } - }; - - debug!("fulfill_obligation: selection={:?}", selection); - - // Currently, we use a fulfillment context to completely resolve - // all nested obligations. This is because they can inform the - // inference of the impl's type parameters. - let mut fulfill_cx = FulfillmentContext::new(); - let vtable = selection.map(|predicate| { - debug!("fulfill_obligation: register_predicate_obligation {:?}", predicate); - fulfill_cx.register_predicate_obligation(&infcx, predicate); - }); - let vtable = infcx.drain_fulfillment_cx_or_panic(&mut fulfill_cx, &vtable); - - info!("Cache miss: {:?} => {:?}", trait_ref, vtable); - vtable - }) -} - -// # Global Cache - -impl<'a, 'tcx> InferCtxt<'a, 'tcx> { - /// Finishes processes any obligations that remain in the - /// fulfillment context, and then returns the result with all type - /// variables removed and regions erased. Because this is intended - /// for use after type-check has completed, if any errors occur, - /// it will panic. It is used during normalization and other cases - /// where processing the obligations in `fulfill_cx` may cause - /// type inference variables that appear in `result` to be - /// unified, and hence we need to process those obligations to get - /// the complete picture of the type. - fn drain_fulfillment_cx_or_panic<T>( - &self, - fulfill_cx: &mut FulfillmentContext<'tcx>, - result: &T, - ) -> T - where - T: TypeFoldable<'tcx>, - { - debug!("drain_fulfillment_cx_or_panic()"); - - // In principle, we only need to do this so long as `result` - // contains unbound type parameters. It could be a slight - // optimization to stop iterating early. - if let Err(errors) = fulfill_cx.select_all_or_error(self) { - bug!("Encountered errors `{:?}` resolving bounds after type-checking", errors); - } - - let result = self.resolve_vars_if_possible(result); - self.tcx.erase_regions(&result) - } -} diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs deleted file mode 100644 index 2a667b53550..00000000000 --- a/src/librustc/traits/coherence.rs +++ /dev/null @@ -1,541 +0,0 @@ -//! See Rustc Guide chapters on [trait-resolution] and [trait-specialization] for more info on how -//! this works. -//! -//! [trait-resolution]: https://rust-lang.github.io/rustc-guide/traits/resolution.html -//! [trait-specialization]: https://rust-lang.github.io/rustc-guide/traits/specialization.html - -use crate::infer::{CombinedSnapshot, InferOk}; -use crate::traits::select::IntercrateAmbiguityCause; -use crate::traits::SkipLeakCheck; -use crate::traits::{self, Normalized, Obligation, ObligationCause, SelectionContext}; -use crate::ty::fold::TypeFoldable; -use crate::ty::subst::Subst; -use crate::ty::{self, Ty, TyCtxt}; -use rustc_hir::def_id::{DefId, LOCAL_CRATE}; -use rustc_span::symbol::sym; -use rustc_span::DUMMY_SP; - -/// Whether we do the orphan check relative to this crate or -/// to some remote crate. -#[derive(Copy, Clone, Debug)] -enum InCrate { - Local, - Remote, -} - -#[derive(Debug, Copy, Clone)] -pub enum Conflict { - Upstream, - Downstream, -} - -pub struct OverlapResult<'tcx> { - pub impl_header: ty::ImplHeader<'tcx>, - pub intercrate_ambiguity_causes: Vec<IntercrateAmbiguityCause>, - - /// `true` if the overlap might've been permitted before the shift - /// to universes. - pub involves_placeholder: bool, -} - -pub fn add_placeholder_note(err: &mut rustc_errors::DiagnosticBuilder<'_>) { - err.note(&format!( - "this behavior recently changed as a result of a bug fix; \ - see rust-lang/rust#56105 for details" - )); -} - -/// If there are types that satisfy both impls, invokes `on_overlap` -/// with a suitably-freshened `ImplHeader` with those types -/// substituted. Otherwise, invokes `no_overlap`. -pub fn overlapping_impls<F1, F2, R>( - tcx: TyCtxt<'_>, - impl1_def_id: DefId, - impl2_def_id: DefId, - skip_leak_check: SkipLeakCheck, - on_overlap: F1, - no_overlap: F2, -) -> R -where - F1: FnOnce(OverlapResult<'_>) -> R, - F2: FnOnce() -> R, -{ - debug!( - "overlapping_impls(\ - impl1_def_id={:?}, \ - impl2_def_id={:?})", - impl1_def_id, impl2_def_id, - ); - - let overlaps = tcx.infer_ctxt().enter(|infcx| { - let selcx = &mut SelectionContext::intercrate(&infcx); - overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id).is_some() - }); - - if !overlaps { - return no_overlap(); - } - - // In the case where we detect an error, run the check again, but - // this time tracking intercrate ambuiguity causes for better - // diagnostics. (These take time and can lead to false errors.) - tcx.infer_ctxt().enter(|infcx| { - let selcx = &mut SelectionContext::intercrate(&infcx); - selcx.enable_tracking_intercrate_ambiguity_causes(); - on_overlap(overlap(selcx, skip_leak_check, impl1_def_id, impl2_def_id).unwrap()) - }) -} - -fn with_fresh_ty_vars<'cx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - impl_def_id: DefId, -) -> ty::ImplHeader<'tcx> { - let tcx = selcx.tcx(); - let impl_substs = selcx.infcx().fresh_substs_for_item(DUMMY_SP, impl_def_id); - - let header = ty::ImplHeader { - impl_def_id, - self_ty: tcx.type_of(impl_def_id).subst(tcx, impl_substs), - trait_ref: tcx.impl_trait_ref(impl_def_id).subst(tcx, impl_substs), - predicates: tcx.predicates_of(impl_def_id).instantiate(tcx, impl_substs).predicates, - }; - - let Normalized { value: mut header, obligations } = - traits::normalize(selcx, param_env, ObligationCause::dummy(), &header); - - header.predicates.extend(obligations.into_iter().map(|o| o.predicate)); - header -} - -/// Can both impl `a` and impl `b` be satisfied by a common type (including -/// where-clauses)? If so, returns an `ImplHeader` that unifies the two impls. -fn overlap<'cx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'tcx>, - skip_leak_check: SkipLeakCheck, - a_def_id: DefId, - b_def_id: DefId, -) -> Option<OverlapResult<'tcx>> { - debug!("overlap(a_def_id={:?}, b_def_id={:?})", a_def_id, b_def_id); - - selcx.infcx().probe_maybe_skip_leak_check(skip_leak_check.is_yes(), |snapshot| { - overlap_within_probe(selcx, a_def_id, b_def_id, snapshot) - }) -} - -fn overlap_within_probe( - selcx: &mut SelectionContext<'cx, 'tcx>, - a_def_id: DefId, - b_def_id: DefId, - snapshot: &CombinedSnapshot<'_, 'tcx>, -) -> Option<OverlapResult<'tcx>> { - // For the purposes of this check, we don't bring any placeholder - // types into scope; instead, we replace the generic types with - // fresh type variables, and hence we do our evaluations in an - // empty environment. - let param_env = ty::ParamEnv::empty(); - - let a_impl_header = with_fresh_ty_vars(selcx, param_env, a_def_id); - let b_impl_header = with_fresh_ty_vars(selcx, param_env, b_def_id); - - debug!("overlap: a_impl_header={:?}", a_impl_header); - debug!("overlap: b_impl_header={:?}", b_impl_header); - - // Do `a` and `b` unify? If not, no overlap. - let obligations = match selcx - .infcx() - .at(&ObligationCause::dummy(), param_env) - .eq_impl_headers(&a_impl_header, &b_impl_header) - { - Ok(InferOk { obligations, value: () }) => obligations, - Err(_) => { - return None; - } - }; - - debug!("overlap: unification check succeeded"); - - // Are any of the obligations unsatisfiable? If so, no overlap. - let infcx = selcx.infcx(); - let opt_failing_obligation = a_impl_header - .predicates - .iter() - .chain(&b_impl_header.predicates) - .map(|p| infcx.resolve_vars_if_possible(p)) - .map(|p| Obligation { - cause: ObligationCause::dummy(), - param_env, - recursion_depth: 0, - predicate: p, - }) - .chain(obligations) - .find(|o| !selcx.predicate_may_hold_fatal(o)); - // FIXME: the call to `selcx.predicate_may_hold_fatal` above should be ported - // to the canonical trait query form, `infcx.predicate_may_hold`, once - // the new system supports intercrate mode (which coherence needs). - - if let Some(failing_obligation) = opt_failing_obligation { - debug!("overlap: obligation unsatisfiable {:?}", failing_obligation); - return None; - } - - let impl_header = selcx.infcx().resolve_vars_if_possible(&a_impl_header); - let intercrate_ambiguity_causes = selcx.take_intercrate_ambiguity_causes(); - debug!("overlap: intercrate_ambiguity_causes={:#?}", intercrate_ambiguity_causes); - - let involves_placeholder = match selcx.infcx().region_constraints_added_in_snapshot(snapshot) { - Some(true) => true, - _ => false, - }; - - Some(OverlapResult { impl_header, intercrate_ambiguity_causes, involves_placeholder }) -} - -pub fn trait_ref_is_knowable<'tcx>( - tcx: TyCtxt<'tcx>, - trait_ref: ty::TraitRef<'tcx>, -) -> Option<Conflict> { - debug!("trait_ref_is_knowable(trait_ref={:?})", trait_ref); - if orphan_check_trait_ref(tcx, trait_ref, InCrate::Remote).is_ok() { - // A downstream or cousin crate is allowed to implement some - // substitution of this trait-ref. - return Some(Conflict::Downstream); - } - - if trait_ref_is_local_or_fundamental(tcx, trait_ref) { - // This is a local or fundamental trait, so future-compatibility - // is no concern. We know that downstream/cousin crates are not - // allowed to implement a substitution of this trait ref, which - // means impls could only come from dependencies of this crate, - // which we already know about. - return None; - } - - // This is a remote non-fundamental trait, so if another crate - // can be the "final owner" of a substitution of this trait-ref, - // they are allowed to implement it future-compatibly. - // - // However, if we are a final owner, then nobody else can be, - // and if we are an intermediate owner, then we don't care - // about future-compatibility, which means that we're OK if - // we are an owner. - if orphan_check_trait_ref(tcx, trait_ref, InCrate::Local).is_ok() { - debug!("trait_ref_is_knowable: orphan check passed"); - return None; - } else { - debug!("trait_ref_is_knowable: nonlocal, nonfundamental, unowned"); - return Some(Conflict::Upstream); - } -} - -pub fn trait_ref_is_local_or_fundamental<'tcx>( - tcx: TyCtxt<'tcx>, - trait_ref: ty::TraitRef<'tcx>, -) -> bool { - trait_ref.def_id.krate == LOCAL_CRATE || tcx.has_attr(trait_ref.def_id, sym::fundamental) -} - -pub enum OrphanCheckErr<'tcx> { - NonLocalInputType(Vec<(Ty<'tcx>, bool /* Is this the first input type? */)>), - UncoveredTy(Ty<'tcx>, Option<Ty<'tcx>>), -} - -/// Checks the coherence orphan rules. `impl_def_id` should be the -/// `DefId` of a trait impl. To pass, either the trait must be local, or else -/// two conditions must be satisfied: -/// -/// 1. All type parameters in `Self` must be "covered" by some local type constructor. -/// 2. Some local type must appear in `Self`. -pub fn orphan_check(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Result<(), OrphanCheckErr<'_>> { - debug!("orphan_check({:?})", impl_def_id); - - // We only except this routine to be invoked on implementations - // of a trait, not inherent implementations. - let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap(); - debug!("orphan_check: trait_ref={:?}", trait_ref); - - // If the *trait* is local to the crate, ok. - if trait_ref.def_id.is_local() { - debug!("trait {:?} is local to current crate", trait_ref.def_id); - return Ok(()); - } - - orphan_check_trait_ref(tcx, trait_ref, InCrate::Local) -} - -/// Checks whether a trait-ref is potentially implementable by a crate. -/// -/// The current rule is that a trait-ref orphan checks in a crate C: -/// -/// 1. Order the parameters in the trait-ref in subst order - Self first, -/// others linearly (e.g., `<U as Foo<V, W>>` is U < V < W). -/// 2. Of these type parameters, there is at least one type parameter -/// in which, walking the type as a tree, you can reach a type local -/// to C where all types in-between are fundamental types. Call the -/// first such parameter the "local key parameter". -/// - e.g., `Box<LocalType>` is OK, because you can visit LocalType -/// going through `Box`, which is fundamental. -/// - similarly, `FundamentalPair<Vec<()>, Box<LocalType>>` is OK for -/// the same reason. -/// - but (knowing that `Vec<T>` is non-fundamental, and assuming it's -/// not local), `Vec<LocalType>` is bad, because `Vec<->` is between -/// the local type and the type parameter. -/// 3. Every type parameter before the local key parameter is fully known in C. -/// - e.g., `impl<T> T: Trait<LocalType>` is bad, because `T` might be -/// an unknown type. -/// - but `impl<T> LocalType: Trait<T>` is OK, because `LocalType` -/// occurs before `T`. -/// 4. Every type in the local key parameter not known in C, going -/// through the parameter's type tree, must appear only as a subtree of -/// a type local to C, with only fundamental types between the type -/// local to C and the local key parameter. -/// - e.g., `Vec<LocalType<T>>>` (or equivalently `Box<Vec<LocalType<T>>>`) -/// is bad, because the only local type with `T` as a subtree is -/// `LocalType<T>`, and `Vec<->` is between it and the type parameter. -/// - similarly, `FundamentalPair<LocalType<T>, T>` is bad, because -/// the second occurrence of `T` is not a subtree of *any* local type. -/// - however, `LocalType<Vec<T>>` is OK, because `T` is a subtree of -/// `LocalType<Vec<T>>`, which is local and has no types between it and -/// the type parameter. -/// -/// The orphan rules actually serve several different purposes: -/// -/// 1. They enable link-safety - i.e., 2 mutually-unknowing crates (where -/// every type local to one crate is unknown in the other) can't implement -/// the same trait-ref. This follows because it can be seen that no such -/// type can orphan-check in 2 such crates. -/// -/// To check that a local impl follows the orphan rules, we check it in -/// InCrate::Local mode, using type parameters for the "generic" types. -/// -/// 2. They ground negative reasoning for coherence. If a user wants to -/// write both a conditional blanket impl and a specific impl, we need to -/// make sure they do not overlap. For example, if we write -/// ``` -/// impl<T> IntoIterator for Vec<T> -/// impl<T: Iterator> IntoIterator for T -/// ``` -/// We need to be able to prove that `Vec<$0>: !Iterator` for every type $0. -/// We can observe that this holds in the current crate, but we need to make -/// sure this will also hold in all unknown crates (both "independent" crates, -/// which we need for link-safety, and also child crates, because we don't want -/// child crates to get error for impl conflicts in a *dependency*). -/// -/// For that, we only allow negative reasoning if, for every assignment to the -/// inference variables, every unknown crate would get an orphan error if they -/// try to implement this trait-ref. To check for this, we use InCrate::Remote -/// mode. That is sound because we already know all the impls from known crates. -/// -/// 3. For non-#[fundamental] traits, they guarantee that parent crates can -/// add "non-blanket" impls without breaking negative reasoning in dependent -/// crates. This is the "rebalancing coherence" (RFC 1023) restriction. -/// -/// For that, we only a allow crate to perform negative reasoning on -/// non-local-non-#[fundamental] only if there's a local key parameter as per (2). -/// -/// Because we never perform negative reasoning generically (coherence does -/// not involve type parameters), this can be interpreted as doing the full -/// orphan check (using InCrate::Local mode), substituting non-local known -/// types for all inference variables. -/// -/// This allows for crates to future-compatibly add impls as long as they -/// can't apply to types with a key parameter in a child crate - applying -/// the rules, this basically means that every type parameter in the impl -/// must appear behind a non-fundamental type (because this is not a -/// type-system requirement, crate owners might also go for "semantic -/// future-compatibility" involving things such as sealed traits, but -/// the above requirement is sufficient, and is necessary in "open world" -/// cases). -/// -/// Note that this function is never called for types that have both type -/// parameters and inference variables. -fn orphan_check_trait_ref<'tcx>( - tcx: TyCtxt<'tcx>, - trait_ref: ty::TraitRef<'tcx>, - in_crate: InCrate, -) -> Result<(), OrphanCheckErr<'tcx>> { - debug!("orphan_check_trait_ref(trait_ref={:?}, in_crate={:?})", trait_ref, in_crate); - - if trait_ref.needs_infer() && trait_ref.needs_subst() { - bug!( - "can't orphan check a trait ref with both params and inference variables {:?}", - trait_ref - ); - } - - // Given impl<P1..=Pn> Trait<T1..=Tn> for T0, an impl is valid only - // if at least one of the following is true: - // - // - Trait is a local trait - // (already checked in orphan_check prior to calling this function) - // - All of - // - At least one of the types T0..=Tn must be a local type. - // Let Ti be the first such type. - // - No uncovered type parameters P1..=Pn may appear in T0..Ti (excluding Ti) - // - fn uncover_fundamental_ty<'tcx>( - tcx: TyCtxt<'tcx>, - ty: Ty<'tcx>, - in_crate: InCrate, - ) -> Vec<Ty<'tcx>> { - if fundamental_ty(ty) && ty_is_non_local(ty, in_crate).is_some() { - ty.walk_shallow().flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate)).collect() - } else { - vec![ty] - } - } - - let mut non_local_spans = vec![]; - for (i, input_ty) in - trait_ref.input_types().flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate)).enumerate() - { - debug!("orphan_check_trait_ref: check ty `{:?}`", input_ty); - let non_local_tys = ty_is_non_local(input_ty, in_crate); - if non_local_tys.is_none() { - debug!("orphan_check_trait_ref: ty_is_local `{:?}`", input_ty); - return Ok(()); - } else if let ty::Param(_) = input_ty.kind { - debug!("orphan_check_trait_ref: uncovered ty: `{:?}`", input_ty); - let local_type = trait_ref - .input_types() - .flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate)) - .filter(|ty| ty_is_non_local_constructor(ty, in_crate).is_none()) - .next(); - - debug!("orphan_check_trait_ref: uncovered ty local_type: `{:?}`", local_type); - - return Err(OrphanCheckErr::UncoveredTy(input_ty, local_type)); - } - if let Some(non_local_tys) = non_local_tys { - for input_ty in non_local_tys { - non_local_spans.push((input_ty, i == 0)); - } - } - } - // If we exit above loop, never found a local type. - debug!("orphan_check_trait_ref: no local type"); - Err(OrphanCheckErr::NonLocalInputType(non_local_spans)) -} - -fn ty_is_non_local<'t>(ty: Ty<'t>, in_crate: InCrate) -> Option<Vec<Ty<'t>>> { - match ty_is_non_local_constructor(ty, in_crate) { - Some(ty) => { - if !fundamental_ty(ty) { - Some(vec![ty]) - } else { - let tys: Vec<_> = ty - .walk_shallow() - .filter_map(|t| ty_is_non_local(t, in_crate)) - .flat_map(|i| i) - .collect(); - if tys.is_empty() { None } else { Some(tys) } - } - } - None => None, - } -} - -fn fundamental_ty(ty: Ty<'_>) -> bool { - match ty.kind { - ty::Ref(..) => true, - ty::Adt(def, _) => def.is_fundamental(), - _ => false, - } -} - -fn def_id_is_local(def_id: DefId, in_crate: InCrate) -> bool { - match in_crate { - // The type is local to *this* crate - it will not be - // local in any other crate. - InCrate::Remote => false, - InCrate::Local => def_id.is_local(), - } -} - -fn ty_is_non_local_constructor<'tcx>(ty: Ty<'tcx>, in_crate: InCrate) -> Option<Ty<'tcx>> { - debug!("ty_is_non_local_constructor({:?})", ty); - - match ty.kind { - ty::Bool - | ty::Char - | ty::Int(..) - | ty::Uint(..) - | ty::Float(..) - | ty::Str - | ty::FnDef(..) - | ty::FnPtr(_) - | ty::Array(..) - | ty::Slice(..) - | ty::RawPtr(..) - | ty::Ref(..) - | ty::Never - | ty::Tuple(..) - | ty::Param(..) - | ty::Projection(..) => Some(ty), - - ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) => match in_crate { - InCrate::Local => Some(ty), - // The inference variable might be unified with a local - // type in that remote crate. - InCrate::Remote => None, - }, - - ty::Adt(def, _) => { - if def_id_is_local(def.did, in_crate) { - None - } else { - Some(ty) - } - } - ty::Foreign(did) => { - if def_id_is_local(did, in_crate) { - None - } else { - Some(ty) - } - } - ty::Opaque(..) => { - // This merits some explanation. - // Normally, opaque types are not involed when performing - // coherence checking, since it is illegal to directly - // implement a trait on an opaque type. However, we might - // end up looking at an opaque type during coherence checking - // if an opaque type gets used within another type (e.g. as - // a type parameter). This requires us to decide whether or - // not an opaque type should be considered 'local' or not. - // - // We choose to treat all opaque types as non-local, even - // those that appear within the same crate. This seems - // somewhat suprising at first, but makes sense when - // you consider that opaque types are supposed to hide - // the underlying type *within the same crate*. When an - // opaque type is used from outside the module - // where it is declared, it should be impossible to observe - // anyything about it other than the traits that it implements. - // - // The alternative would be to look at the underlying type - // to determine whether or not the opaque type itself should - // be considered local. However, this could make it a breaking change - // to switch the underlying ('defining') type from a local type - // to a remote type. This would violate the rule that opaque - // types should be completely opaque apart from the traits - // that they implement, so we don't use this behavior. - Some(ty) - } - - ty::Dynamic(ref tt, ..) => { - if let Some(principal) = tt.principal() { - if def_id_is_local(principal.def_id(), in_crate) { None } else { Some(ty) } - } else { - Some(ty) - } - } - - ty::Error => None, - - ty::UnnormalizedProjection(..) - | ty::Closure(..) - | ty::Generator(..) - | ty::GeneratorWitness(..) => bug!("ty_is_local invoked on unexpected type: {:?}", ty), - } -} diff --git a/src/librustc/traits/engine.rs b/src/librustc/traits/engine.rs deleted file mode 100644 index 84bfc86e6a9..00000000000 --- a/src/librustc/traits/engine.rs +++ /dev/null @@ -1,88 +0,0 @@ -use crate::infer::InferCtxt; -use crate::traits::Obligation; -use crate::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness}; -use rustc_hir::def_id::DefId; - -use super::{ChalkFulfillmentContext, FulfillmentContext, FulfillmentError}; -use super::{ObligationCause, PredicateObligation}; - -pub trait TraitEngine<'tcx>: 'tcx { - fn normalize_projection_type( - &mut self, - infcx: &InferCtxt<'_, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - projection_ty: ty::ProjectionTy<'tcx>, - cause: ObligationCause<'tcx>, - ) -> Ty<'tcx>; - - /// Requires that `ty` must implement the trait with `def_id` in - /// the given environment. This trait must not have any type - /// parameters (except for `Self`). - fn register_bound( - &mut self, - infcx: &InferCtxt<'_, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - ty: Ty<'tcx>, - def_id: DefId, - cause: ObligationCause<'tcx>, - ) { - let trait_ref = ty::TraitRef { def_id, substs: infcx.tcx.mk_substs_trait(ty, &[]) }; - self.register_predicate_obligation( - infcx, - Obligation { - cause, - recursion_depth: 0, - param_env, - predicate: trait_ref.without_const().to_predicate(), - }, - ); - } - - fn register_predicate_obligation( - &mut self, - infcx: &InferCtxt<'_, 'tcx>, - obligation: PredicateObligation<'tcx>, - ); - - fn select_all_or_error( - &mut self, - infcx: &InferCtxt<'_, 'tcx>, - ) -> Result<(), Vec<FulfillmentError<'tcx>>>; - - fn select_where_possible( - &mut self, - infcx: &InferCtxt<'_, 'tcx>, - ) -> Result<(), Vec<FulfillmentError<'tcx>>>; - - fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>>; -} - -pub trait TraitEngineExt<'tcx> { - fn register_predicate_obligations( - &mut self, - infcx: &InferCtxt<'_, 'tcx>, - obligations: impl IntoIterator<Item = PredicateObligation<'tcx>>, - ); -} - -impl<T: ?Sized + TraitEngine<'tcx>> TraitEngineExt<'tcx> for T { - fn register_predicate_obligations( - &mut self, - infcx: &InferCtxt<'_, 'tcx>, - obligations: impl IntoIterator<Item = PredicateObligation<'tcx>>, - ) { - for obligation in obligations { - self.register_predicate_obligation(infcx, obligation); - } - } -} - -impl dyn TraitEngine<'tcx> { - pub fn new(tcx: TyCtxt<'tcx>) -> Box<Self> { - if tcx.sess.opts.debugging_opts.chalk { - Box::new(ChalkFulfillmentContext::new()) - } else { - Box::new(FulfillmentContext::new()) - } - } -} diff --git a/src/librustc/traits/error_reporting/mod.rs b/src/librustc/traits/error_reporting/mod.rs deleted file mode 100644 index c25b392ec23..00000000000 --- a/src/librustc/traits/error_reporting/mod.rs +++ /dev/null @@ -1,1656 +0,0 @@ -pub mod on_unimplemented; -pub mod suggestions; - -use super::{ - ConstEvalFailure, EvaluationResult, FulfillmentError, FulfillmentErrorCode, - MismatchedProjectionTypes, ObjectSafetyViolation, Obligation, ObligationCause, - ObligationCauseCode, OnUnimplementedDirective, OnUnimplementedNote, - OutputTypeParameterMismatch, Overflow, PredicateObligation, SelectionContext, SelectionError, - TraitNotObjectSafe, -}; - -use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode}; -use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use crate::infer::{self, InferCtxt}; -use crate::mir::interpret::ErrorHandled; -use crate::session::DiagnosticMessageId; -use crate::traits::object_safety_violations; -use crate::ty::error::ExpectedFound; -use crate::ty::fast_reject; -use crate::ty::fold::TypeFolder; -use crate::ty::SubtypePredicate; -use crate::ty::{ - self, AdtKind, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness, -}; - -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; -use rustc_hir as hir; -use rustc_hir::def_id::{DefId, LOCAL_CRATE}; -use rustc_hir::{QPath, TyKind, WhereBoundPredicate, WherePredicate}; -use rustc_span::source_map::SourceMap; -use rustc_span::{ExpnKind, Span, DUMMY_SP}; -use std::fmt; -use syntax::ast; - -impl<'a, 'tcx> InferCtxt<'a, 'tcx> { - pub fn report_fulfillment_errors( - &self, - errors: &[FulfillmentError<'tcx>], - body_id: Option<hir::BodyId>, - fallback_has_occurred: bool, - ) { - #[derive(Debug)] - struct ErrorDescriptor<'tcx> { - predicate: ty::Predicate<'tcx>, - index: Option<usize>, // None if this is an old error - } - - let mut error_map: FxHashMap<_, Vec<_>> = self - .reported_trait_errors - .borrow() - .iter() - .map(|(&span, predicates)| { - ( - span, - predicates - .iter() - .map(|&predicate| ErrorDescriptor { predicate, index: None }) - .collect(), - ) - }) - .collect(); - - for (index, error) in errors.iter().enumerate() { - // We want to ignore desugarings here: spans are equivalent even - // if one is the result of a desugaring and the other is not. - let mut span = error.obligation.cause.span; - let expn_data = span.ctxt().outer_expn_data(); - if let ExpnKind::Desugaring(_) = expn_data.kind { - span = expn_data.call_site; - } - - error_map.entry(span).or_default().push(ErrorDescriptor { - predicate: error.obligation.predicate, - index: Some(index), - }); - - self.reported_trait_errors - .borrow_mut() - .entry(span) - .or_default() - .push(error.obligation.predicate.clone()); - } - - // We do this in 2 passes because we want to display errors in order, though - // maybe it *is* better to sort errors by span or something. - let mut is_suppressed = vec![false; errors.len()]; - for (_, error_set) in error_map.iter() { - // We want to suppress "duplicate" errors with the same span. - for error in error_set { - if let Some(index) = error.index { - // Suppress errors that are either: - // 1) strictly implied by another error. - // 2) implied by an error with a smaller index. - for error2 in error_set { - if error2.index.map_or(false, |index2| is_suppressed[index2]) { - // Avoid errors being suppressed by already-suppressed - // errors, to prevent all errors from being suppressed - // at once. - continue; - } - - if self.error_implies(&error2.predicate, &error.predicate) - && !(error2.index >= error.index - && self.error_implies(&error.predicate, &error2.predicate)) - { - info!("skipping {:?} (implied by {:?})", error, error2); - is_suppressed[index] = true; - break; - } - } - } - } - } - - for (error, suppressed) in errors.iter().zip(is_suppressed) { - if !suppressed { - self.report_fulfillment_error(error, body_id, fallback_has_occurred); - } - } - } - - // returns if `cond` not occurring implies that `error` does not occur - i.e., that - // `error` occurring implies that `cond` occurs. - fn error_implies(&self, cond: &ty::Predicate<'tcx>, error: &ty::Predicate<'tcx>) -> bool { - if cond == error { - return true; - } - - let (cond, error) = match (cond, error) { - (&ty::Predicate::Trait(..), &ty::Predicate::Trait(ref error, _)) => (cond, error), - _ => { - // FIXME: make this work in other cases too. - return false; - } - }; - - for implication in super::elaborate_predicates(self.tcx, vec![*cond]) { - if let ty::Predicate::Trait(implication, _) = implication { - let error = error.to_poly_trait_ref(); - let implication = implication.to_poly_trait_ref(); - // FIXME: I'm just not taking associated types at all here. - // Eventually I'll need to implement param-env-aware - // `Γ₁ ⊦ φ₁ => Γ₂ ⊦ φ₂` logic. - let param_env = ty::ParamEnv::empty(); - if self.can_sub(param_env, error, implication).is_ok() { - debug!("error_implies: {:?} -> {:?} -> {:?}", cond, error, implication); - return true; - } - } - } - - false - } - - fn report_fulfillment_error( - &self, - error: &FulfillmentError<'tcx>, - body_id: Option<hir::BodyId>, - fallback_has_occurred: bool, - ) { - debug!("report_fulfillment_error({:?})", error); - match error.code { - FulfillmentErrorCode::CodeSelectionError(ref selection_error) => { - self.report_selection_error( - &error.obligation, - selection_error, - fallback_has_occurred, - error.points_at_arg_span, - ); - } - FulfillmentErrorCode::CodeProjectionError(ref e) => { - self.report_projection_error(&error.obligation, e); - } - FulfillmentErrorCode::CodeAmbiguity => { - self.maybe_report_ambiguity(&error.obligation, body_id); - } - FulfillmentErrorCode::CodeSubtypeError(ref expected_found, ref err) => { - self.report_mismatched_types( - &error.obligation.cause, - expected_found.expected, - expected_found.found, - err.clone(), - ) - .emit(); - } - } - } - - fn report_projection_error( - &self, - obligation: &PredicateObligation<'tcx>, - error: &MismatchedProjectionTypes<'tcx>, - ) { - let predicate = self.resolve_vars_if_possible(&obligation.predicate); - - if predicate.references_error() { - return; - } - - self.probe(|_| { - let err_buf; - let mut err = &error.err; - let mut values = None; - - // try to find the mismatched types to report the error with. - // - // this can fail if the problem was higher-ranked, in which - // cause I have no idea for a good error message. - if let ty::Predicate::Projection(ref data) = predicate { - let mut selcx = SelectionContext::new(self); - let (data, _) = self.replace_bound_vars_with_fresh_vars( - obligation.cause.span, - infer::LateBoundRegionConversionTime::HigherRankedType, - data, - ); - let mut obligations = vec![]; - let normalized_ty = super::normalize_projection_type( - &mut selcx, - obligation.param_env, - data.projection_ty, - obligation.cause.clone(), - 0, - &mut obligations, - ); - - debug!( - "report_projection_error obligation.cause={:?} obligation.param_env={:?}", - obligation.cause, obligation.param_env - ); - - debug!( - "report_projection_error normalized_ty={:?} data.ty={:?}", - normalized_ty, data.ty - ); - - let is_normalized_ty_expected = match &obligation.cause.code { - ObligationCauseCode::ItemObligation(_) - | ObligationCauseCode::BindingObligation(_, _) - | ObligationCauseCode::ObjectCastObligation(_) => false, - _ => true, - }; - - if let Err(error) = self.at(&obligation.cause, obligation.param_env).eq_exp( - is_normalized_ty_expected, - normalized_ty, - data.ty, - ) { - values = Some(infer::ValuePairs::Types(ExpectedFound::new( - is_normalized_ty_expected, - normalized_ty, - data.ty, - ))); - - err_buf = error; - err = &err_buf; - } - } - - let msg = format!("type mismatch resolving `{}`", predicate); - let error_id = (DiagnosticMessageId::ErrorId(271), Some(obligation.cause.span), msg); - let fresh = self.tcx.sess.one_time_diagnostics.borrow_mut().insert(error_id); - if fresh { - let mut diag = struct_span_err!( - self.tcx.sess, - obligation.cause.span, - E0271, - "type mismatch resolving `{}`", - predicate - ); - self.note_type_err(&mut diag, &obligation.cause, None, values, err); - self.note_obligation_cause(&mut diag, obligation); - diag.emit(); - } - }); - } - - fn fuzzy_match_tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool { - /// returns the fuzzy category of a given type, or None - /// if the type can be equated to any type. - fn type_category(t: Ty<'_>) -> Option<u32> { - match t.kind { - ty::Bool => Some(0), - ty::Char => Some(1), - ty::Str => Some(2), - ty::Int(..) | ty::Uint(..) | ty::Infer(ty::IntVar(..)) => Some(3), - ty::Float(..) | ty::Infer(ty::FloatVar(..)) => Some(4), - ty::Ref(..) | ty::RawPtr(..) => Some(5), - ty::Array(..) | ty::Slice(..) => Some(6), - ty::FnDef(..) | ty::FnPtr(..) => Some(7), - ty::Dynamic(..) => Some(8), - ty::Closure(..) => Some(9), - ty::Tuple(..) => Some(10), - ty::Projection(..) => Some(11), - ty::Param(..) => Some(12), - ty::Opaque(..) => Some(13), - ty::Never => Some(14), - ty::Adt(adt, ..) => match adt.adt_kind() { - AdtKind::Struct => Some(15), - AdtKind::Union => Some(16), - AdtKind::Enum => Some(17), - }, - ty::Generator(..) => Some(18), - ty::Foreign(..) => Some(19), - ty::GeneratorWitness(..) => Some(20), - ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error => None, - ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"), - } - } - - match (type_category(a), type_category(b)) { - (Some(cat_a), Some(cat_b)) => match (&a.kind, &b.kind) { - (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => def_a == def_b, - _ => cat_a == cat_b, - }, - // infer and error can be equated to all types - _ => true, - } - } - - fn describe_generator(&self, body_id: hir::BodyId) -> Option<&'static str> { - self.tcx.hir().body(body_id).generator_kind.map(|gen_kind| match gen_kind { - hir::GeneratorKind::Gen => "a generator", - hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block) => "an async block", - hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Fn) => "an async function", - hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Closure) => "an async closure", - }) - } - - fn find_similar_impl_candidates( - &self, - trait_ref: ty::PolyTraitRef<'tcx>, - ) -> Vec<ty::TraitRef<'tcx>> { - let simp = fast_reject::simplify_type(self.tcx, trait_ref.skip_binder().self_ty(), true); - let all_impls = self.tcx.all_impls(trait_ref.def_id()); - - match simp { - Some(simp) => all_impls - .iter() - .filter_map(|&def_id| { - let imp = self.tcx.impl_trait_ref(def_id).unwrap(); - let imp_simp = fast_reject::simplify_type(self.tcx, imp.self_ty(), true); - if let Some(imp_simp) = imp_simp { - if simp != imp_simp { - return None; - } - } - - Some(imp) - }) - .collect(), - None => { - all_impls.iter().map(|&def_id| self.tcx.impl_trait_ref(def_id).unwrap()).collect() - } - } - } - - fn report_similar_impl_candidates( - &self, - impl_candidates: Vec<ty::TraitRef<'tcx>>, - err: &mut DiagnosticBuilder<'_>, - ) { - if impl_candidates.is_empty() { - return; - } - - let len = impl_candidates.len(); - let end = if impl_candidates.len() <= 5 { impl_candidates.len() } else { 4 }; - - let normalize = |candidate| { - self.tcx.infer_ctxt().enter(|ref infcx| { - let normalized = infcx - .at(&ObligationCause::dummy(), ty::ParamEnv::empty()) - .normalize(candidate) - .ok(); - match normalized { - Some(normalized) => format!("\n {:?}", normalized.value), - None => format!("\n {:?}", candidate), - } - }) - }; - - // Sort impl candidates so that ordering is consistent for UI tests. - let mut normalized_impl_candidates = - impl_candidates.iter().map(normalize).collect::<Vec<String>>(); - - // Sort before taking the `..end` range, - // because the ordering of `impl_candidates` may not be deterministic: - // https://github.com/rust-lang/rust/pull/57475#issuecomment-455519507 - normalized_impl_candidates.sort(); - - err.help(&format!( - "the following implementations were found:{}{}", - normalized_impl_candidates[..end].join(""), - if len > 5 { format!("\nand {} others", len - 4) } else { String::new() } - )); - } - - /// Reports that an overflow has occurred and halts compilation. We - /// halt compilation unconditionally because it is important that - /// overflows never be masked -- they basically represent computations - /// whose result could not be truly determined and thus we can't say - /// if the program type checks or not -- and they are unusual - /// occurrences in any case. - pub fn report_overflow_error<T>( - &self, - obligation: &Obligation<'tcx, T>, - suggest_increasing_limit: bool, - ) -> ! - where - T: fmt::Display + TypeFoldable<'tcx>, - { - let predicate = self.resolve_vars_if_possible(&obligation.predicate); - let mut err = struct_span_err!( - self.tcx.sess, - obligation.cause.span, - E0275, - "overflow evaluating the requirement `{}`", - predicate - ); - - if suggest_increasing_limit { - self.suggest_new_overflow_limit(&mut err); - } - - self.note_obligation_cause_code( - &mut err, - &obligation.predicate, - &obligation.cause.code, - &mut vec![], - ); - - err.emit(); - self.tcx.sess.abort_if_errors(); - bug!(); - } - - /// Reports that a cycle was detected which led to overflow and halts - /// compilation. This is equivalent to `report_overflow_error` except - /// that we can give a more helpful error message (and, in particular, - /// we do not suggest increasing the overflow limit, which is not - /// going to help). - pub fn report_overflow_error_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> ! { - let cycle = self.resolve_vars_if_possible(&cycle.to_owned()); - assert!(cycle.len() > 0); - - debug!("report_overflow_error_cycle: cycle={:?}", cycle); - - self.report_overflow_error(&cycle[0], false); - } - - pub fn report_extra_impl_obligation( - &self, - error_span: Span, - item_name: ast::Name, - _impl_item_def_id: DefId, - trait_item_def_id: DefId, - requirement: &dyn fmt::Display, - ) -> DiagnosticBuilder<'tcx> { - let msg = "impl has stricter requirements than trait"; - let sp = self.tcx.sess.source_map().def_span(error_span); - - let mut err = struct_span_err!(self.tcx.sess, sp, E0276, "{}", msg); - - if let Some(trait_item_span) = self.tcx.hir().span_if_local(trait_item_def_id) { - let span = self.tcx.sess.source_map().def_span(trait_item_span); - err.span_label(span, format!("definition of `{}` from trait", item_name)); - } - - err.span_label(sp, format!("impl has extra requirement {}", requirement)); - - err - } - - /// Gets the parent trait chain start - fn get_parent_trait_ref( - &self, - code: &ObligationCauseCode<'tcx>, - ) -> Option<(String, Option<Span>)> { - match code { - &ObligationCauseCode::BuiltinDerivedObligation(ref data) => { - let parent_trait_ref = self.resolve_vars_if_possible(&data.parent_trait_ref); - match self.get_parent_trait_ref(&data.parent_code) { - Some(t) => Some(t), - None => { - let ty = parent_trait_ref.skip_binder().self_ty(); - let span = - TyCategory::from_ty(ty).map(|(_, def_id)| self.tcx.def_span(def_id)); - Some((ty.to_string(), span)) - } - } - } - _ => None, - } - } - - pub fn report_selection_error( - &self, - obligation: &PredicateObligation<'tcx>, - error: &SelectionError<'tcx>, - fallback_has_occurred: bool, - points_at_arg: bool, - ) { - let tcx = self.tcx; - let span = obligation.cause.span; - - let mut err = match *error { - SelectionError::Unimplemented => { - if let ObligationCauseCode::CompareImplMethodObligation { - item_name, - impl_item_def_id, - trait_item_def_id, - } - | ObligationCauseCode::CompareImplTypeObligation { - item_name, - impl_item_def_id, - trait_item_def_id, - } = obligation.cause.code - { - self.report_extra_impl_obligation( - span, - item_name, - impl_item_def_id, - trait_item_def_id, - &format!("`{}`", obligation.predicate), - ) - .emit(); - return; - } - match obligation.predicate { - ty::Predicate::Trait(ref trait_predicate, _) => { - let trait_predicate = self.resolve_vars_if_possible(trait_predicate); - - if self.tcx.sess.has_errors() && trait_predicate.references_error() { - return; - } - let trait_ref = trait_predicate.to_poly_trait_ref(); - let (post_message, pre_message, type_def) = self - .get_parent_trait_ref(&obligation.cause.code) - .map(|(t, s)| { - ( - format!(" in `{}`", t), - format!("within `{}`, ", t), - s.map(|s| (format!("within this `{}`", t), s)), - ) - }) - .unwrap_or_default(); - - let OnUnimplementedNote { message, label, note, enclosing_scope } = - self.on_unimplemented_note(trait_ref, obligation); - let have_alt_message = message.is_some() || label.is_some(); - let is_try = self - .tcx - .sess - .source_map() - .span_to_snippet(span) - .map(|s| &s == "?") - .unwrap_or(false); - let is_from = format!("{}", trait_ref.print_only_trait_path()) - .starts_with("std::convert::From<"); - let (message, note) = if is_try && is_from { - ( - Some(format!( - "`?` couldn't convert the error to `{}`", - trait_ref.self_ty(), - )), - Some( - "the question mark operation (`?`) implicitly performs a \ - conversion on the error value using the `From` trait" - .to_owned(), - ), - ) - } else { - (message, note) - }; - - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0277, - "{}", - message.unwrap_or_else(|| format!( - "the trait bound `{}` is not satisfied{}", - trait_ref.without_const().to_predicate(), - post_message, - )) - ); - - let explanation = - if obligation.cause.code == ObligationCauseCode::MainFunctionType { - "consider using `()`, or a `Result`".to_owned() - } else { - format!( - "{}the trait `{}` is not implemented for `{}`", - pre_message, - trait_ref.print_only_trait_path(), - trait_ref.self_ty(), - ) - }; - - if self.suggest_add_reference_to_arg( - &obligation, - &mut err, - &trait_ref, - points_at_arg, - have_alt_message, - ) { - self.note_obligation_cause(&mut err, obligation); - err.emit(); - return; - } - if let Some(ref s) = label { - // If it has a custom `#[rustc_on_unimplemented]` - // error message, let's display it as the label! - err.span_label(span, s.as_str()); - err.help(&explanation); - } else { - err.span_label(span, explanation); - } - if let Some((msg, span)) = type_def { - err.span_label(span, &msg); - } - if let Some(ref s) = note { - // If it has a custom `#[rustc_on_unimplemented]` note, let's display it - err.note(s.as_str()); - } - if let Some(ref s) = enclosing_scope { - let enclosing_scope_span = tcx.def_span( - tcx.hir() - .opt_local_def_id(obligation.cause.body_id) - .unwrap_or_else(|| { - tcx.hir().body_owner_def_id(hir::BodyId { - hir_id: obligation.cause.body_id, - }) - }), - ); - - err.span_label(enclosing_scope_span, s.as_str()); - } - - self.suggest_borrow_on_unsized_slice(&obligation.cause.code, &mut err); - self.suggest_fn_call(&obligation, &mut err, &trait_ref, points_at_arg); - self.suggest_remove_reference(&obligation, &mut err, &trait_ref); - self.suggest_semicolon_removal(&obligation, &mut err, span, &trait_ref); - self.note_version_mismatch(&mut err, &trait_ref); - if self.suggest_impl_trait(&mut err, span, &obligation, &trait_ref) { - err.emit(); - return; - } - - // Try to report a help message - if !trait_ref.has_infer_types() - && self.predicate_can_apply(obligation.param_env, trait_ref) - { - // If a where-clause may be useful, remind the - // user that they can add it. - // - // don't display an on-unimplemented note, as - // these notes will often be of the form - // "the type `T` can't be frobnicated" - // which is somewhat confusing. - self.suggest_restricting_param_bound( - &mut err, - &trait_ref, - obligation.cause.body_id, - ); - } else { - if !have_alt_message { - // Can't show anything else useful, try to find similar impls. - let impl_candidates = self.find_similar_impl_candidates(trait_ref); - self.report_similar_impl_candidates(impl_candidates, &mut err); - } - self.suggest_change_mut( - &obligation, - &mut err, - &trait_ref, - points_at_arg, - ); - } - - // If this error is due to `!: Trait` not implemented but `(): Trait` is - // implemented, and fallback has occurred, then it could be due to a - // variable that used to fallback to `()` now falling back to `!`. Issue a - // note informing about the change in behaviour. - if trait_predicate.skip_binder().self_ty().is_never() - && fallback_has_occurred - { - let predicate = trait_predicate.map_bound(|mut trait_pred| { - trait_pred.trait_ref.substs = self.tcx.mk_substs_trait( - self.tcx.mk_unit(), - &trait_pred.trait_ref.substs[1..], - ); - trait_pred - }); - let unit_obligation = Obligation { - predicate: ty::Predicate::Trait( - predicate, - hir::Constness::NotConst, - ), - ..obligation.clone() - }; - if self.predicate_may_hold(&unit_obligation) { - err.note( - "the trait is implemented for `()`. \ - Possibly this error has been caused by changes to \ - Rust's type-inference algorithm (see issue #48950 \ - <https://github.com/rust-lang/rust/issues/48950> \ - for more information). Consider whether you meant to use \ - the type `()` here instead.", - ); - } - } - - err - } - - ty::Predicate::Subtype(ref predicate) => { - // Errors for Subtype predicates show up as - // `FulfillmentErrorCode::CodeSubtypeError`, - // not selection error. - span_bug!(span, "subtype requirement gave wrong error: `{:?}`", predicate) - } - - ty::Predicate::RegionOutlives(ref predicate) => { - let predicate = self.resolve_vars_if_possible(predicate); - let err = self - .region_outlives_predicate(&obligation.cause, &predicate) - .err() - .unwrap(); - struct_span_err!( - self.tcx.sess, - span, - E0279, - "the requirement `{}` is not satisfied (`{}`)", - predicate, - err, - ) - } - - ty::Predicate::Projection(..) | ty::Predicate::TypeOutlives(..) => { - let predicate = self.resolve_vars_if_possible(&obligation.predicate); - struct_span_err!( - self.tcx.sess, - span, - E0280, - "the requirement `{}` is not satisfied", - predicate - ) - } - - ty::Predicate::ObjectSafe(trait_def_id) => { - let violations = object_safety_violations(self.tcx, trait_def_id); - report_object_safety_error(self.tcx, span, trait_def_id, violations) - } - - ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => { - let found_kind = self.closure_kind(closure_def_id, closure_substs).unwrap(); - let closure_span = self - .tcx - .sess - .source_map() - .def_span(self.tcx.hir().span_if_local(closure_def_id).unwrap()); - let hir_id = self.tcx.hir().as_local_hir_id(closure_def_id).unwrap(); - let mut err = struct_span_err!( - self.tcx.sess, - closure_span, - E0525, - "expected a closure that implements the `{}` trait, \ - but this closure only implements `{}`", - kind, - found_kind - ); - - err.span_label( - closure_span, - format!("this closure implements `{}`, not `{}`", found_kind, kind), - ); - err.span_label( - obligation.cause.span, - format!("the requirement to implement `{}` derives from here", kind), - ); - - // Additional context information explaining why the closure only implements - // a particular trait. - if let Some(tables) = self.in_progress_tables { - let tables = tables.borrow(); - match (found_kind, tables.closure_kind_origins().get(hir_id)) { - (ty::ClosureKind::FnOnce, Some((span, name))) => { - err.span_label( - *span, - format!( - "closure is `FnOnce` because it moves the \ - variable `{}` out of its environment", - name - ), - ); - } - (ty::ClosureKind::FnMut, Some((span, name))) => { - err.span_label( - *span, - format!( - "closure is `FnMut` because it mutates the \ - variable `{}` here", - name - ), - ); - } - _ => {} - } - } - - err.emit(); - return; - } - - ty::Predicate::WellFormed(ty) => { - if !self.tcx.sess.opts.debugging_opts.chalk { - // WF predicates cannot themselves make - // errors. They can only block due to - // ambiguity; otherwise, they always - // degenerate into other obligations - // (which may fail). - span_bug!(span, "WF predicate not satisfied for {:?}", ty); - } else { - // FIXME: we'll need a better message which takes into account - // which bounds actually failed to hold. - self.tcx.sess.struct_span_err( - span, - &format!("the type `{}` is not well-formed (chalk)", ty), - ) - } - } - - ty::Predicate::ConstEvaluatable(..) => { - // Errors for `ConstEvaluatable` predicates show up as - // `SelectionError::ConstEvalFailure`, - // not `Unimplemented`. - span_bug!( - span, - "const-evaluatable requirement gave wrong error: `{:?}`", - obligation - ) - } - } - } - - OutputTypeParameterMismatch(ref found_trait_ref, ref expected_trait_ref, _) => { - let found_trait_ref = self.resolve_vars_if_possible(&*found_trait_ref); - let expected_trait_ref = self.resolve_vars_if_possible(&*expected_trait_ref); - - if expected_trait_ref.self_ty().references_error() { - return; - } - - let found_trait_ty = found_trait_ref.self_ty(); - - let found_did = match found_trait_ty.kind { - ty::Closure(did, _) | ty::Foreign(did) | ty::FnDef(did, _) => Some(did), - ty::Adt(def, _) => Some(def.did), - _ => None, - }; - - let found_span = found_did - .and_then(|did| self.tcx.hir().span_if_local(did)) - .map(|sp| self.tcx.sess.source_map().def_span(sp)); // the sp could be an fn def - - if self.reported_closure_mismatch.borrow().contains(&(span, found_span)) { - // We check closures twice, with obligations flowing in different directions, - // but we want to complain about them only once. - return; - } - - self.reported_closure_mismatch.borrow_mut().insert((span, found_span)); - - let found = match found_trait_ref.skip_binder().substs.type_at(1).kind { - ty::Tuple(ref tys) => vec![ArgKind::empty(); tys.len()], - _ => vec![ArgKind::empty()], - }; - - let expected_ty = expected_trait_ref.skip_binder().substs.type_at(1); - let expected = match expected_ty.kind { - ty::Tuple(ref tys) => tys - .iter() - .map(|t| ArgKind::from_expected_ty(t.expect_ty(), Some(span))) - .collect(), - _ => vec![ArgKind::Arg("_".to_owned(), expected_ty.to_string())], - }; - - if found.len() == expected.len() { - self.report_closure_arg_mismatch( - span, - found_span, - found_trait_ref, - expected_trait_ref, - ) - } else { - let (closure_span, found) = found_did - .and_then(|did| self.tcx.hir().get_if_local(did)) - .map(|node| { - let (found_span, found) = self.get_fn_like_arguments(node); - (Some(found_span), found) - }) - .unwrap_or((found_span, found)); - - self.report_arg_count_mismatch( - span, - closure_span, - expected, - found, - found_trait_ty.is_closure(), - ) - } - } - - TraitNotObjectSafe(did) => { - let violations = object_safety_violations(self.tcx, did); - report_object_safety_error(self.tcx, span, did, violations) - } - - ConstEvalFailure(ErrorHandled::TooGeneric) => { - // In this instance, we have a const expression containing an unevaluated - // generic parameter. We have no idea whether this expression is valid or - // not (e.g. it might result in an error), but we don't want to just assume - // that it's okay, because that might result in post-monomorphisation time - // errors. The onus is really on the caller to provide values that it can - // prove are well-formed. - let mut err = self - .tcx - .sess - .struct_span_err(span, "constant expression depends on a generic parameter"); - // FIXME(const_generics): we should suggest to the user how they can resolve this - // issue. However, this is currently not actually possible - // (see https://github.com/rust-lang/rust/issues/66962#issuecomment-575907083). - err.note("this may fail depending on what value the parameter takes"); - err - } - - // Already reported in the query. - ConstEvalFailure(ErrorHandled::Reported) => { - self.tcx - .sess - .delay_span_bug(span, &format!("constant in type had an ignored error")); - return; - } - - Overflow => { - bug!("overflow should be handled before the `report_selection_error` path"); - } - }; - - self.note_obligation_cause(&mut err, obligation); - self.point_at_returns_when_relevant(&mut err, &obligation); - - err.emit(); - } - - /// If the `Self` type of the unsatisfied trait `trait_ref` implements a trait - /// with the same path as `trait_ref`, a help message about - /// a probable version mismatch is added to `err` - fn note_version_mismatch( - &self, - err: &mut DiagnosticBuilder<'_>, - trait_ref: &ty::PolyTraitRef<'tcx>, - ) { - let get_trait_impl = |trait_def_id| { - let mut trait_impl = None; - self.tcx.for_each_relevant_impl(trait_def_id, trait_ref.self_ty(), |impl_def_id| { - if trait_impl.is_none() { - trait_impl = Some(impl_def_id); - } - }); - trait_impl - }; - let required_trait_path = self.tcx.def_path_str(trait_ref.def_id()); - let all_traits = self.tcx.all_traits(LOCAL_CRATE); - let traits_with_same_path: std::collections::BTreeSet<_> = all_traits - .iter() - .filter(|trait_def_id| **trait_def_id != trait_ref.def_id()) - .filter(|trait_def_id| self.tcx.def_path_str(**trait_def_id) == required_trait_path) - .collect(); - for trait_with_same_path in traits_with_same_path { - if let Some(impl_def_id) = get_trait_impl(*trait_with_same_path) { - let impl_span = self.tcx.def_span(impl_def_id); - err.span_help(impl_span, "trait impl with same name found"); - let trait_crate = self.tcx.crate_name(trait_with_same_path.krate); - let crate_msg = format!( - "perhaps two different versions of crate `{}` are being used?", - trait_crate - ); - err.note(&crate_msg); - } - } - } - - fn mk_obligation_for_def_id( - &self, - def_id: DefId, - output_ty: Ty<'tcx>, - cause: ObligationCause<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ) -> PredicateObligation<'tcx> { - let new_trait_ref = - ty::TraitRef { def_id, substs: self.tcx.mk_substs_trait(output_ty, &[]) }; - Obligation::new(cause, param_env, new_trait_ref.without_const().to_predicate()) - } -} - -pub fn recursive_type_with_infinite_size_error( - tcx: TyCtxt<'tcx>, - type_def_id: DefId, -) -> DiagnosticBuilder<'tcx> { - assert!(type_def_id.is_local()); - let span = tcx.hir().span_if_local(type_def_id).unwrap(); - let span = tcx.sess.source_map().def_span(span); - let mut err = struct_span_err!( - tcx.sess, - span, - E0072, - "recursive type `{}` has infinite size", - tcx.def_path_str(type_def_id) - ); - err.span_label(span, "recursive type has infinite size"); - err.help(&format!( - "insert indirection (e.g., a `Box`, `Rc`, or `&`) \ - at some point to make `{}` representable", - tcx.def_path_str(type_def_id) - )); - err -} - -pub fn report_object_safety_error( - tcx: TyCtxt<'tcx>, - span: Span, - trait_def_id: DefId, - violations: Vec<ObjectSafetyViolation>, -) -> DiagnosticBuilder<'tcx> { - let trait_str = tcx.def_path_str(trait_def_id); - let trait_span = tcx.hir().get_if_local(trait_def_id).and_then(|node| match node { - hir::Node::Item(item) => Some(item.ident.span), - _ => None, - }); - let span = tcx.sess.source_map().def_span(span); - let mut err = struct_span_err!( - tcx.sess, - span, - E0038, - "the trait `{}` cannot be made into an object", - trait_str - ); - err.span_label(span, format!("the trait `{}` cannot be made into an object", trait_str)); - - let mut reported_violations = FxHashSet::default(); - let mut had_span_label = false; - for violation in violations { - if let ObjectSafetyViolation::SizedSelf(sp) = &violation { - if !sp.is_empty() { - // Do not report `SizedSelf` without spans pointing at `SizedSelf` obligations - // with a `Span`. - reported_violations.insert(ObjectSafetyViolation::SizedSelf(vec![].into())); - } - } - if reported_violations.insert(violation.clone()) { - let spans = violation.spans(); - let msg = if trait_span.is_none() || spans.is_empty() { - format!("the trait cannot be made into an object because {}", violation.error_msg()) - } else { - had_span_label = true; - format!("...because {}", violation.error_msg()) - }; - if spans.is_empty() { - err.note(&msg); - } else { - for span in spans { - err.span_label(span, &msg); - } - } - match (trait_span, violation.solution()) { - (Some(_), Some((note, None))) => { - err.help(¬e); - } - (Some(_), Some((note, Some((sugg, span))))) => { - err.span_suggestion(span, ¬e, sugg, Applicability::MachineApplicable); - } - // Only provide the help if its a local trait, otherwise it's not actionable. - _ => {} - } - } - } - if let (Some(trait_span), true) = (trait_span, had_span_label) { - err.span_label(trait_span, "this trait cannot be made into an object..."); - } - - if tcx.sess.trait_methods_not_found.borrow().contains(&span) { - // Avoid emitting error caused by non-existing method (#58734) - err.cancel(); - } - - err -} - -impl<'a, 'tcx> InferCtxt<'a, 'tcx> { - fn maybe_report_ambiguity( - &self, - obligation: &PredicateObligation<'tcx>, - body_id: Option<hir::BodyId>, - ) { - // Unable to successfully determine, probably means - // insufficient type information, but could mean - // ambiguous impls. The latter *ought* to be a - // coherence violation, so we don't report it here. - - let predicate = self.resolve_vars_if_possible(&obligation.predicate); - let span = obligation.cause.span; - - debug!( - "maybe_report_ambiguity(predicate={:?}, obligation={:?} body_id={:?}, code={:?})", - predicate, obligation, body_id, obligation.cause.code, - ); - - // Ambiguity errors are often caused as fallout from earlier - // errors. So just ignore them if this infcx is tainted. - if self.is_tainted_by_errors() { - return; - } - - let mut err = match predicate { - ty::Predicate::Trait(ref data, _) => { - let trait_ref = data.to_poly_trait_ref(); - let self_ty = trait_ref.self_ty(); - debug!("self_ty {:?} {:?} trait_ref {:?}", self_ty, self_ty.kind, trait_ref); - - if predicate.references_error() { - return; - } - // Typically, this ambiguity should only happen if - // there are unresolved type inference variables - // (otherwise it would suggest a coherence - // failure). But given #21974 that is not necessarily - // the case -- we can have multiple where clauses that - // are only distinguished by a region, which results - // in an ambiguity even when all types are fully - // known, since we don't dispatch based on region - // relationships. - - // This is kind of a hack: it frequently happens that some earlier - // error prevents types from being fully inferred, and then we get - // a bunch of uninteresting errors saying something like "<generic - // #0> doesn't implement Sized". It may even be true that we - // could just skip over all checks where the self-ty is an - // inference variable, but I was afraid that there might be an - // inference variable created, registered as an obligation, and - // then never forced by writeback, and hence by skipping here we'd - // be ignoring the fact that we don't KNOW the type works - // out. Though even that would probably be harmless, given that - // we're only talking about builtin traits, which are known to be - // inhabited. We used to check for `self.tcx.sess.has_errors()` to - // avoid inundating the user with unnecessary errors, but we now - // check upstream for type errors and dont add the obligations to - // begin with in those cases. - if self - .tcx - .lang_items() - .sized_trait() - .map_or(false, |sized_id| sized_id == trait_ref.def_id()) - { - self.need_type_info_err(body_id, span, self_ty, ErrorCode::E0282).emit(); - return; - } - let mut err = self.need_type_info_err(body_id, span, self_ty, ErrorCode::E0283); - err.note(&format!("cannot resolve `{}`", predicate)); - if let ObligationCauseCode::ItemObligation(def_id) = obligation.cause.code { - self.suggest_fully_qualified_path(&mut err, def_id, span, trait_ref.def_id()); - } else if let ( - Ok(ref snippet), - ObligationCauseCode::BindingObligation(ref def_id, _), - ) = - (self.tcx.sess.source_map().span_to_snippet(span), &obligation.cause.code) - { - let generics = self.tcx.generics_of(*def_id); - if !generics.params.is_empty() && !snippet.ends_with('>') { - // FIXME: To avoid spurious suggestions in functions where type arguments - // where already supplied, we check the snippet to make sure it doesn't - // end with a turbofish. Ideally we would have access to a `PathSegment` - // instead. Otherwise we would produce the following output: - // - // error[E0283]: type annotations needed - // --> $DIR/issue-54954.rs:3:24 - // | - // LL | const ARR_LEN: usize = Tt::const_val::<[i8; 123]>(); - // | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - // | | - // | cannot infer type - // | help: consider specifying the type argument - // | in the function call: - // | `Tt::const_val::<[i8; 123]>::<T>` - // ... - // LL | const fn const_val<T: Sized>() -> usize { - // | --------- - required by this bound in `Tt::const_val` - // | - // = note: cannot resolve `_: Tt` - - err.span_suggestion( - span, - &format!( - "consider specifying the type argument{} in the function call", - if generics.params.len() > 1 { "s" } else { "" }, - ), - format!( - "{}::<{}>", - snippet, - generics - .params - .iter() - .map(|p| p.name.to_string()) - .collect::<Vec<String>>() - .join(", ") - ), - Applicability::HasPlaceholders, - ); - } - } - err - } - - ty::Predicate::WellFormed(ty) => { - // Same hacky approach as above to avoid deluging user - // with error messages. - if ty.references_error() || self.tcx.sess.has_errors() { - return; - } - self.need_type_info_err(body_id, span, ty, ErrorCode::E0282) - } - - ty::Predicate::Subtype(ref data) => { - if data.references_error() || self.tcx.sess.has_errors() { - // no need to overload user in such cases - return; - } - let &SubtypePredicate { a_is_expected: _, a, b } = data.skip_binder(); - // both must be type variables, or the other would've been instantiated - assert!(a.is_ty_var() && b.is_ty_var()); - self.need_type_info_err(body_id, span, a, ErrorCode::E0282) - } - ty::Predicate::Projection(ref data) => { - let trait_ref = data.to_poly_trait_ref(self.tcx); - let self_ty = trait_ref.self_ty(); - if predicate.references_error() { - return; - } - let mut err = self.need_type_info_err(body_id, span, self_ty, ErrorCode::E0284); - err.note(&format!("cannot resolve `{}`", predicate)); - err - } - - _ => { - if self.tcx.sess.has_errors() { - return; - } - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0284, - "type annotations needed: cannot resolve `{}`", - predicate, - ); - err.span_label(span, &format!("cannot resolve `{}`", predicate)); - err - } - }; - self.note_obligation_cause(&mut err, obligation); - err.emit(); - } - - /// Returns `true` if the trait predicate may apply for *some* assignment - /// to the type parameters. - fn predicate_can_apply( - &self, - param_env: ty::ParamEnv<'tcx>, - pred: ty::PolyTraitRef<'tcx>, - ) -> bool { - struct ParamToVarFolder<'a, 'tcx> { - infcx: &'a InferCtxt<'a, 'tcx>, - var_map: FxHashMap<Ty<'tcx>, Ty<'tcx>>, - } - - impl<'a, 'tcx> TypeFolder<'tcx> for ParamToVarFolder<'a, 'tcx> { - fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { - self.infcx.tcx - } - - fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - if let ty::Param(ty::ParamTy { name, .. }) = ty.kind { - let infcx = self.infcx; - self.var_map.entry(ty).or_insert_with(|| { - infcx.next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::TypeParameterDefinition(name, None), - span: DUMMY_SP, - }) - }) - } else { - ty.super_fold_with(self) - } - } - } - - self.probe(|_| { - let mut selcx = SelectionContext::new(self); - - let cleaned_pred = - pred.fold_with(&mut ParamToVarFolder { infcx: self, var_map: Default::default() }); - - let cleaned_pred = super::project::normalize( - &mut selcx, - param_env, - ObligationCause::dummy(), - &cleaned_pred, - ) - .value; - - let obligation = Obligation::new( - ObligationCause::dummy(), - param_env, - cleaned_pred.without_const().to_predicate(), - ); - - self.predicate_may_hold(&obligation) - }) - } - - fn note_obligation_cause( - &self, - err: &mut DiagnosticBuilder<'_>, - obligation: &PredicateObligation<'tcx>, - ) { - // First, attempt to add note to this error with an async-await-specific - // message, and fall back to regular note otherwise. - if !self.maybe_note_obligation_cause_for_async_await(err, obligation) { - self.note_obligation_cause_code( - err, - &obligation.predicate, - &obligation.cause.code, - &mut vec![], - ); - self.suggest_unsized_bound_if_applicable(err, obligation); - } - } - - fn suggest_unsized_bound_if_applicable( - &self, - err: &mut DiagnosticBuilder<'_>, - obligation: &PredicateObligation<'tcx>, - ) { - if let ( - ty::Predicate::Trait(pred, _), - ObligationCauseCode::BindingObligation(item_def_id, span), - ) = (&obligation.predicate, &obligation.cause.code) - { - if let (Some(generics), true) = ( - self.tcx.hir().get_if_local(*item_def_id).as_ref().and_then(|n| n.generics()), - Some(pred.def_id()) == self.tcx.lang_items().sized_trait(), - ) { - for param in generics.params { - if param.span == *span - && !param.bounds.iter().any(|bound| { - bound.trait_def_id() == self.tcx.lang_items().sized_trait() - }) - { - let (span, separator) = match param.bounds { - [] => (span.shrink_to_hi(), ":"), - [.., bound] => (bound.span().shrink_to_hi(), " + "), - }; - err.span_suggestion( - span, - "consider relaxing the implicit `Sized` restriction", - format!("{} ?Sized", separator), - Applicability::MachineApplicable, - ); - return; - } - } - } - } - } - - fn is_recursive_obligation( - &self, - obligated_types: &mut Vec<&ty::TyS<'tcx>>, - cause_code: &ObligationCauseCode<'tcx>, - ) -> bool { - if let ObligationCauseCode::BuiltinDerivedObligation(ref data) = cause_code { - let parent_trait_ref = self.resolve_vars_if_possible(&data.parent_trait_ref); - - if obligated_types.iter().any(|ot| ot == &parent_trait_ref.skip_binder().self_ty()) { - return true; - } - } - false - } -} - -/// Summarizes information -#[derive(Clone)] -pub enum ArgKind { - /// An argument of non-tuple type. Parameters are (name, ty) - Arg(String, String), - - /// An argument of tuple type. For a "found" argument, the span is - /// the locationo in the source of the pattern. For a "expected" - /// argument, it will be None. The vector is a list of (name, ty) - /// strings for the components of the tuple. - Tuple(Option<Span>, Vec<(String, String)>), -} - -impl ArgKind { - fn empty() -> ArgKind { - ArgKind::Arg("_".to_owned(), "_".to_owned()) - } - - /// Creates an `ArgKind` from the expected type of an - /// argument. It has no name (`_`) and an optional source span. - pub fn from_expected_ty(t: Ty<'_>, span: Option<Span>) -> ArgKind { - match t.kind { - ty::Tuple(ref tys) => ArgKind::Tuple( - span, - tys.iter().map(|ty| ("_".to_owned(), ty.to_string())).collect::<Vec<_>>(), - ), - _ => ArgKind::Arg("_".to_owned(), t.to_string()), - } - } -} - -/// Suggest restricting a type param with a new bound. -pub fn suggest_constraining_type_param( - tcx: TyCtxt<'_>, - generics: &hir::Generics<'_>, - err: &mut DiagnosticBuilder<'_>, - param_name: &str, - constraint: &str, - source_map: &SourceMap, - span: Span, - def_id: Option<DefId>, -) -> bool { - const MSG_RESTRICT_BOUND_FURTHER: &str = "consider further restricting this bound with"; - const MSG_RESTRICT_TYPE: &str = "consider restricting this type parameter with"; - const MSG_RESTRICT_TYPE_FURTHER: &str = "consider further restricting this type parameter with"; - - let param = generics.params.iter().filter(|p| p.name.ident().as_str() == param_name).next(); - - let param = if let Some(param) = param { - param - } else { - return false; - }; - - if def_id == tcx.lang_items().sized_trait() { - // Type parameters are already `Sized` by default. - err.span_label(param.span, &format!("this type parameter needs to be `{}`", constraint)); - return true; - } - - if param_name.starts_with("impl ") { - // If there's an `impl Trait` used in argument position, suggest - // restricting it: - // - // fn foo(t: impl Foo) { ... } - // -------- - // | - // help: consider further restricting this bound with `+ Bar` - // - // Suggestion for tools in this case is: - // - // fn foo(t: impl Foo) { ... } - // -------- - // | - // replace with: `impl Foo + Bar` - - err.span_help(param.span, &format!("{} `+ {}`", MSG_RESTRICT_BOUND_FURTHER, constraint)); - - err.tool_only_span_suggestion( - param.span, - MSG_RESTRICT_BOUND_FURTHER, - format!("{} + {}", param_name, constraint), - Applicability::MachineApplicable, - ); - - return true; - } - - if generics.where_clause.predicates.is_empty() { - if let Some(bounds_span) = param.bounds_span() { - // If user has provided some bounds, suggest restricting them: - // - // fn foo<T: Foo>(t: T) { ... } - // --- - // | - // help: consider further restricting this bound with `+ Bar` - // - // Suggestion for tools in this case is: - // - // fn foo<T: Foo>(t: T) { ... } - // -- - // | - // replace with: `T: Bar +` - - err.span_help( - bounds_span, - &format!("{} `+ {}`", MSG_RESTRICT_BOUND_FURTHER, constraint), - ); - - let span_hi = param.span.with_hi(span.hi()); - let span_with_colon = source_map.span_through_char(span_hi, ':'); - - if span_hi != param.span && span_with_colon != span_hi { - err.tool_only_span_suggestion( - span_with_colon, - MSG_RESTRICT_BOUND_FURTHER, - format!("{}: {} + ", param_name, constraint), - Applicability::MachineApplicable, - ); - } - } else { - // If user hasn't provided any bounds, suggest adding a new one: - // - // fn foo<T>(t: T) { ... } - // - help: consider restricting this type parameter with `T: Foo` - - err.span_help( - param.span, - &format!("{} `{}: {}`", MSG_RESTRICT_TYPE, param_name, constraint), - ); - - err.tool_only_span_suggestion( - param.span, - MSG_RESTRICT_TYPE, - format!("{}: {}", param_name, constraint), - Applicability::MachineApplicable, - ); - } - - true - } else { - // This part is a bit tricky, because using the `where` clause user can - // provide zero, one or many bounds for the same type parameter, so we - // have following cases to consider: - // - // 1) When the type parameter has been provided zero bounds - // - // Message: - // fn foo<X, Y>(x: X, y: Y) where Y: Foo { ... } - // - help: consider restricting this type parameter with `where X: Bar` - // - // Suggestion: - // fn foo<X, Y>(x: X, y: Y) where Y: Foo { ... } - // - insert: `, X: Bar` - // - // - // 2) When the type parameter has been provided one bound - // - // Message: - // fn foo<T>(t: T) where T: Foo { ... } - // ^^^^^^ - // | - // help: consider further restricting this bound with `+ Bar` - // - // Suggestion: - // fn foo<T>(t: T) where T: Foo { ... } - // ^^ - // | - // replace with: `T: Bar +` - // - // - // 3) When the type parameter has been provided many bounds - // - // Message: - // fn foo<T>(t: T) where T: Foo, T: Bar {... } - // - help: consider further restricting this type parameter with `where T: Zar` - // - // Suggestion: - // fn foo<T>(t: T) where T: Foo, T: Bar {... } - // - insert: `, T: Zar` - - let mut param_spans = Vec::new(); - - for predicate in generics.where_clause.predicates { - if let WherePredicate::BoundPredicate(WhereBoundPredicate { - span, bounded_ty, .. - }) = predicate - { - if let TyKind::Path(QPath::Resolved(_, path)) = &bounded_ty.kind { - if let Some(segment) = path.segments.first() { - if segment.ident.to_string() == param_name { - param_spans.push(span); - } - } - } - } - } - - let where_clause_span = - generics.where_clause.span_for_predicates_or_empty_place().shrink_to_hi(); - - match ¶m_spans[..] { - &[] => { - err.span_help( - param.span, - &format!("{} `where {}: {}`", MSG_RESTRICT_TYPE, param_name, constraint), - ); - - err.tool_only_span_suggestion( - where_clause_span, - MSG_RESTRICT_TYPE, - format!(", {}: {}", param_name, constraint), - Applicability::MachineApplicable, - ); - } - - &[¶m_span] => { - err.span_help( - param_span, - &format!("{} `+ {}`", MSG_RESTRICT_BOUND_FURTHER, constraint), - ); - - let span_hi = param_span.with_hi(span.hi()); - let span_with_colon = source_map.span_through_char(span_hi, ':'); - - if span_hi != param_span && span_with_colon != span_hi { - err.tool_only_span_suggestion( - span_with_colon, - MSG_RESTRICT_BOUND_FURTHER, - format!("{}: {} +", param_name, constraint), - Applicability::MachineApplicable, - ); - } - } - - _ => { - err.span_help( - param.span, - &format!( - "{} `where {}: {}`", - MSG_RESTRICT_TYPE_FURTHER, param_name, constraint, - ), - ); - - err.tool_only_span_suggestion( - where_clause_span, - MSG_RESTRICT_BOUND_FURTHER, - format!(", {}: {}", param_name, constraint), - Applicability::MachineApplicable, - ); - } - } - - true - } -} diff --git a/src/librustc/traits/error_reporting/on_unimplemented.rs b/src/librustc/traits/error_reporting/on_unimplemented.rs deleted file mode 100644 index ab2d74b1c8d..00000000000 --- a/src/librustc/traits/error_reporting/on_unimplemented.rs +++ /dev/null @@ -1,223 +0,0 @@ -use super::{ - ObligationCauseCode, OnUnimplementedDirective, OnUnimplementedNote, PredicateObligation, -}; -use crate::infer::InferCtxt; -use crate::ty::subst::Subst; -use crate::ty::{self, GenericParamDefKind}; -use rustc_hir as hir; -use rustc_hir::def_id::DefId; -use rustc_span::symbol::sym; - -impl<'a, 'tcx> InferCtxt<'a, 'tcx> { - fn impl_similar_to( - &self, - trait_ref: ty::PolyTraitRef<'tcx>, - obligation: &PredicateObligation<'tcx>, - ) -> Option<DefId> { - let tcx = self.tcx; - let param_env = obligation.param_env; - let trait_ref = tcx.erase_late_bound_regions(&trait_ref); - let trait_self_ty = trait_ref.self_ty(); - - let mut self_match_impls = vec![]; - let mut fuzzy_match_impls = vec![]; - - self.tcx.for_each_relevant_impl(trait_ref.def_id, trait_self_ty, |def_id| { - let impl_substs = self.fresh_substs_for_item(obligation.cause.span, def_id); - let impl_trait_ref = tcx.impl_trait_ref(def_id).unwrap().subst(tcx, impl_substs); - - let impl_self_ty = impl_trait_ref.self_ty(); - - if let Ok(..) = self.can_eq(param_env, trait_self_ty, impl_self_ty) { - self_match_impls.push(def_id); - - if trait_ref - .substs - .types() - .skip(1) - .zip(impl_trait_ref.substs.types().skip(1)) - .all(|(u, v)| self.fuzzy_match_tys(u, v)) - { - fuzzy_match_impls.push(def_id); - } - } - }); - - let impl_def_id = if self_match_impls.len() == 1 { - self_match_impls[0] - } else if fuzzy_match_impls.len() == 1 { - fuzzy_match_impls[0] - } else { - return None; - }; - - tcx.has_attr(impl_def_id, sym::rustc_on_unimplemented).then_some(impl_def_id) - } - - /// Used to set on_unimplemented's `ItemContext` - /// to be the enclosing (async) block/function/closure - fn describe_enclosure(&self, hir_id: hir::HirId) -> Option<&'static str> { - let hir = &self.tcx.hir(); - let node = hir.find(hir_id)?; - match &node { - hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, _, body_id), .. }) => { - self.describe_generator(*body_id).or_else(|| { - Some(if let hir::FnHeader { asyncness: hir::IsAsync::Async, .. } = sig.header { - "an async function" - } else { - "a function" - }) - }) - } - hir::Node::TraitItem(hir::TraitItem { - kind: hir::TraitItemKind::Method(_, hir::TraitMethod::Provided(body_id)), - .. - }) => self.describe_generator(*body_id).or_else(|| Some("a trait method")), - hir::Node::ImplItem(hir::ImplItem { - kind: hir::ImplItemKind::Method(sig, body_id), - .. - }) => self.describe_generator(*body_id).or_else(|| { - Some(if let hir::FnHeader { asyncness: hir::IsAsync::Async, .. } = sig.header { - "an async method" - } else { - "a method" - }) - }), - hir::Node::Expr(hir::Expr { - kind: hir::ExprKind::Closure(_is_move, _, body_id, _, gen_movability), - .. - }) => self.describe_generator(*body_id).or_else(|| { - Some(if gen_movability.is_some() { "an async closure" } else { "a closure" }) - }), - hir::Node::Expr(hir::Expr { .. }) => { - let parent_hid = hir.get_parent_node(hir_id); - if parent_hid != hir_id { - return self.describe_enclosure(parent_hid); - } else { - None - } - } - _ => None, - } - } - - crate fn on_unimplemented_note( - &self, - trait_ref: ty::PolyTraitRef<'tcx>, - obligation: &PredicateObligation<'tcx>, - ) -> OnUnimplementedNote { - let def_id = - self.impl_similar_to(trait_ref, obligation).unwrap_or_else(|| trait_ref.def_id()); - let trait_ref = *trait_ref.skip_binder(); - - let mut flags = vec![]; - flags.push(( - sym::item_context, - self.describe_enclosure(obligation.cause.body_id).map(|s| s.to_owned()), - )); - - match obligation.cause.code { - ObligationCauseCode::BuiltinDerivedObligation(..) - | ObligationCauseCode::ImplDerivedObligation(..) => {} - _ => { - // this is a "direct", user-specified, rather than derived, - // obligation. - flags.push((sym::direct, None)); - } - } - - if let ObligationCauseCode::ItemObligation(item) = obligation.cause.code { - // FIXME: maybe also have some way of handling methods - // from other traits? That would require name resolution, - // which we might want to be some sort of hygienic. - // - // Currently I'm leaving it for what I need for `try`. - if self.tcx.trait_of_item(item) == Some(trait_ref.def_id) { - let method = self.tcx.item_name(item); - flags.push((sym::from_method, None)); - flags.push((sym::from_method, Some(method.to_string()))); - } - } - if let Some((t, _)) = self.get_parent_trait_ref(&obligation.cause.code) { - flags.push((sym::parent_trait, Some(t))); - } - - if let Some(k) = obligation.cause.span.desugaring_kind() { - flags.push((sym::from_desugaring, None)); - flags.push((sym::from_desugaring, Some(format!("{:?}", k)))); - } - let generics = self.tcx.generics_of(def_id); - let self_ty = trait_ref.self_ty(); - // This is also included through the generics list as `Self`, - // but the parser won't allow you to use it - flags.push((sym::_Self, Some(self_ty.to_string()))); - if let Some(def) = self_ty.ty_adt_def() { - // We also want to be able to select self's original - // signature with no type arguments resolved - flags.push((sym::_Self, Some(self.tcx.type_of(def.did).to_string()))); - } - - for param in generics.params.iter() { - let value = match param.kind { - GenericParamDefKind::Type { .. } | GenericParamDefKind::Const => { - trait_ref.substs[param.index as usize].to_string() - } - GenericParamDefKind::Lifetime => continue, - }; - let name = param.name; - flags.push((name, Some(value))); - } - - if let Some(true) = self_ty.ty_adt_def().map(|def| def.did.is_local()) { - flags.push((sym::crate_local, None)); - } - - // Allow targeting all integers using `{integral}`, even if the exact type was resolved - if self_ty.is_integral() { - flags.push((sym::_Self, Some("{integral}".to_owned()))); - } - - if let ty::Array(aty, len) = self_ty.kind { - flags.push((sym::_Self, Some("[]".to_owned()))); - flags.push((sym::_Self, Some(format!("[{}]", aty)))); - if let Some(def) = aty.ty_adt_def() { - // We also want to be able to select the array's type's original - // signature with no type arguments resolved - flags.push(( - sym::_Self, - Some(format!("[{}]", self.tcx.type_of(def.did).to_string())), - )); - let tcx = self.tcx; - if let Some(len) = len.try_eval_usize(tcx, ty::ParamEnv::empty()) { - flags.push(( - sym::_Self, - Some(format!("[{}; {}]", self.tcx.type_of(def.did).to_string(), len)), - )); - } else { - flags.push(( - sym::_Self, - Some(format!("[{}; _]", self.tcx.type_of(def.did).to_string())), - )); - } - } - } - if let ty::Dynamic(traits, _) = self_ty.kind { - for t in *traits.skip_binder() { - match t { - ty::ExistentialPredicate::Trait(trait_ref) => { - flags.push((sym::_Self, Some(self.tcx.def_path_str(trait_ref.def_id)))) - } - _ => {} - } - } - } - - if let Ok(Some(command)) = - OnUnimplementedDirective::of_item(self.tcx, trait_ref.def_id, def_id) - { - command.evaluate(self.tcx, trait_ref, &flags[..]) - } else { - OnUnimplementedNote::default() - } - } -} diff --git a/src/librustc/traits/error_reporting/suggestions.rs b/src/librustc/traits/error_reporting/suggestions.rs deleted file mode 100644 index 82b73518d09..00000000000 --- a/src/librustc/traits/error_reporting/suggestions.rs +++ /dev/null @@ -1,1711 +0,0 @@ -use super::{ - ArgKind, EvaluationResult, Obligation, ObligationCause, ObligationCauseCode, - PredicateObligation, -}; - -use crate::infer::InferCtxt; -use crate::traits::error_reporting::suggest_constraining_type_param; -use crate::traits::object_safety::object_safety_violations; -use crate::ty::TypeckTables; -use crate::ty::{self, AdtKind, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness}; -use rustc_errors::{ - error_code, pluralize, struct_span_err, Applicability, DiagnosticBuilder, Style, -}; -use rustc_hir as hir; -use rustc_hir::def::DefKind; -use rustc_hir::def_id::DefId; -use rustc_hir::intravisit::Visitor; -use rustc_hir::Node; -use rustc_span::symbol::{kw, sym}; -use rustc_span::{MultiSpan, Span, DUMMY_SP}; -use std::fmt; - -impl<'a, 'tcx> InferCtxt<'a, 'tcx> { - crate fn suggest_restricting_param_bound( - &self, - mut err: &mut DiagnosticBuilder<'_>, - trait_ref: &ty::PolyTraitRef<'_>, - body_id: hir::HirId, - ) { - let self_ty = trait_ref.self_ty(); - let (param_ty, projection) = match &self_ty.kind { - ty::Param(_) => (true, None), - ty::Projection(projection) => (false, Some(projection)), - _ => return, - }; - - let suggest_restriction = - |generics: &hir::Generics<'_>, msg, err: &mut DiagnosticBuilder<'_>| { - let span = generics.where_clause.span_for_predicates_or_empty_place(); - if !span.from_expansion() && span.desugaring_kind().is_none() { - err.span_suggestion( - generics.where_clause.span_for_predicates_or_empty_place().shrink_to_hi(), - &format!("consider further restricting {}", msg), - format!( - "{} {} ", - if !generics.where_clause.predicates.is_empty() { - "," - } else { - " where" - }, - trait_ref.without_const().to_predicate(), - ), - Applicability::MachineApplicable, - ); - } - }; - - // FIXME: Add check for trait bound that is already present, particularly `?Sized` so we - // don't suggest `T: Sized + ?Sized`. - let mut hir_id = body_id; - while let Some(node) = self.tcx.hir().find(hir_id) { - match node { - hir::Node::TraitItem(hir::TraitItem { - generics, - kind: hir::TraitItemKind::Method(..), - .. - }) if param_ty && self_ty == self.tcx.types.self_param => { - // Restricting `Self` for a single method. - suggest_restriction(&generics, "`Self`", err); - return; - } - - hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, generics, _), .. }) - | hir::Node::TraitItem(hir::TraitItem { - generics, - kind: hir::TraitItemKind::Method(..), - .. - }) - | hir::Node::ImplItem(hir::ImplItem { - generics, - kind: hir::ImplItemKind::Method(..), - .. - }) - | hir::Node::Item(hir::Item { - kind: hir::ItemKind::Trait(_, _, generics, _, _), - .. - }) - | hir::Node::Item(hir::Item { - kind: hir::ItemKind::Impl { generics, .. }, .. - }) if projection.is_some() => { - // Missing associated type bound. - suggest_restriction(&generics, "the associated type", err); - return; - } - - hir::Node::Item(hir::Item { - kind: hir::ItemKind::Struct(_, generics), - span, - .. - }) - | hir::Node::Item(hir::Item { - kind: hir::ItemKind::Enum(_, generics), span, .. - }) - | hir::Node::Item(hir::Item { - kind: hir::ItemKind::Union(_, generics), - span, - .. - }) - | hir::Node::Item(hir::Item { - kind: hir::ItemKind::Trait(_, _, generics, ..), - span, - .. - }) - | hir::Node::Item(hir::Item { - kind: hir::ItemKind::Impl { generics, .. }, - span, - .. - }) - | hir::Node::Item(hir::Item { - kind: hir::ItemKind::Fn(_, generics, _), - span, - .. - }) - | hir::Node::Item(hir::Item { - kind: hir::ItemKind::TyAlias(_, generics), - span, - .. - }) - | hir::Node::Item(hir::Item { - kind: hir::ItemKind::TraitAlias(generics, _), - span, - .. - }) - | hir::Node::Item(hir::Item { - kind: hir::ItemKind::OpaqueTy(hir::OpaqueTy { generics, .. }), - span, - .. - }) - | hir::Node::TraitItem(hir::TraitItem { generics, span, .. }) - | hir::Node::ImplItem(hir::ImplItem { generics, span, .. }) - if param_ty => - { - // Missing generic type parameter bound. - let param_name = self_ty.to_string(); - let constraint = trait_ref.print_only_trait_path().to_string(); - if suggest_constraining_type_param( - self.tcx, - generics, - &mut err, - ¶m_name, - &constraint, - self.tcx.sess.source_map(), - *span, - Some(trait_ref.def_id()), - ) { - return; - } - } - - hir::Node::Crate => return, - - _ => {} - } - - hir_id = self.tcx.hir().get_parent_item(hir_id); - } - } - - /// When encountering an assignment of an unsized trait, like `let x = ""[..];`, provide a - /// suggestion to borrow the initializer in order to use have a slice instead. - crate fn suggest_borrow_on_unsized_slice( - &self, - code: &ObligationCauseCode<'tcx>, - err: &mut DiagnosticBuilder<'tcx>, - ) { - if let &ObligationCauseCode::VariableType(hir_id) = code { - let parent_node = self.tcx.hir().get_parent_node(hir_id); - if let Some(Node::Local(ref local)) = self.tcx.hir().find(parent_node) { - if let Some(ref expr) = local.init { - if let hir::ExprKind::Index(_, _) = expr.kind { - if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(expr.span) { - err.span_suggestion( - expr.span, - "consider borrowing here", - format!("&{}", snippet), - Applicability::MachineApplicable, - ); - } - } - } - } - } - } - - /// Given a closure's `DefId`, return the given name of the closure. - /// - /// This doesn't account for reassignments, but it's only used for suggestions. - crate fn get_closure_name( - &self, - def_id: DefId, - err: &mut DiagnosticBuilder<'_>, - msg: &str, - ) -> Option<String> { - let get_name = - |err: &mut DiagnosticBuilder<'_>, kind: &hir::PatKind<'_>| -> Option<String> { - // Get the local name of this closure. This can be inaccurate because - // of the possibility of reassignment, but this should be good enough. - match &kind { - hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, _, name, None) => { - Some(format!("{}", name)) - } - _ => { - err.note(&msg); - None - } - } - }; - - let hir = self.tcx.hir(); - let hir_id = hir.as_local_hir_id(def_id)?; - let parent_node = hir.get_parent_node(hir_id); - match hir.find(parent_node) { - Some(hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Local(local), .. })) => { - get_name(err, &local.pat.kind) - } - // Different to previous arm because one is `&hir::Local` and the other - // is `P<hir::Local>`. - Some(hir::Node::Local(local)) => get_name(err, &local.pat.kind), - _ => return None, - } - } - - /// We tried to apply the bound to an `fn` or closure. Check whether calling it would - /// evaluate to a type that *would* satisfy the trait binding. If it would, suggest calling - /// it: `bar(foo)` → `bar(foo())`. This case is *very* likely to be hit if `foo` is `async`. - crate fn suggest_fn_call( - &self, - obligation: &PredicateObligation<'tcx>, - err: &mut DiagnosticBuilder<'_>, - trait_ref: &ty::Binder<ty::TraitRef<'tcx>>, - points_at_arg: bool, - ) { - let self_ty = trait_ref.self_ty(); - let (def_id, output_ty, callable) = match self_ty.kind { - ty::Closure(def_id, substs) => { - (def_id, self.closure_sig(def_id, substs).output(), "closure") - } - ty::FnDef(def_id, _) => (def_id, self_ty.fn_sig(self.tcx).output(), "function"), - _ => return, - }; - let msg = format!("use parentheses to call the {}", callable); - - let obligation = self.mk_obligation_for_def_id( - trait_ref.def_id(), - output_ty.skip_binder(), - obligation.cause.clone(), - obligation.param_env, - ); - - match self.evaluate_obligation(&obligation) { - Ok(EvaluationResult::EvaluatedToOk) - | Ok(EvaluationResult::EvaluatedToOkModuloRegions) - | Ok(EvaluationResult::EvaluatedToAmbig) => {} - _ => return, - } - let hir = self.tcx.hir(); - // Get the name of the callable and the arguments to be used in the suggestion. - let snippet = match hir.get_if_local(def_id) { - Some(hir::Node::Expr(hir::Expr { - kind: hir::ExprKind::Closure(_, decl, _, span, ..), - .. - })) => { - err.span_label(*span, "consider calling this closure"); - let name = match self.get_closure_name(def_id, err, &msg) { - Some(name) => name, - None => return, - }; - let args = decl.inputs.iter().map(|_| "_").collect::<Vec<_>>().join(", "); - format!("{}({})", name, args) - } - Some(hir::Node::Item(hir::Item { - ident, - kind: hir::ItemKind::Fn(.., body_id), - .. - })) => { - err.span_label(ident.span, "consider calling this function"); - let body = hir.body(*body_id); - let args = body - .params - .iter() - .map(|arg| match &arg.pat.kind { - hir::PatKind::Binding(_, _, ident, None) - // FIXME: provide a better suggestion when encountering `SelfLower`, it - // should suggest a method call. - if ident.name != kw::SelfLower => ident.to_string(), - _ => "_".to_string(), - }) - .collect::<Vec<_>>() - .join(", "); - format!("{}({})", ident, args) - } - _ => return, - }; - if points_at_arg { - // When the obligation error has been ensured to have been caused by - // an argument, the `obligation.cause.span` points at the expression - // of the argument, so we can provide a suggestion. This is signaled - // by `points_at_arg`. Otherwise, we give a more general note. - err.span_suggestion( - obligation.cause.span, - &msg, - snippet, - Applicability::HasPlaceholders, - ); - } else { - err.help(&format!("{}: `{}`", msg, snippet)); - } - } - - crate fn suggest_add_reference_to_arg( - &self, - obligation: &PredicateObligation<'tcx>, - err: &mut DiagnosticBuilder<'tcx>, - trait_ref: &ty::Binder<ty::TraitRef<'tcx>>, - points_at_arg: bool, - has_custom_message: bool, - ) -> bool { - if !points_at_arg { - return false; - } - - let span = obligation.cause.span; - let param_env = obligation.param_env; - let trait_ref = trait_ref.skip_binder(); - - if let ObligationCauseCode::ImplDerivedObligation(obligation) = &obligation.cause.code { - // Try to apply the original trait binding obligation by borrowing. - let self_ty = trait_ref.self_ty(); - let found = self_ty.to_string(); - let new_self_ty = self.tcx.mk_imm_ref(self.tcx.lifetimes.re_static, self_ty); - let substs = self.tcx.mk_substs_trait(new_self_ty, &[]); - let new_trait_ref = ty::TraitRef::new(obligation.parent_trait_ref.def_id(), substs); - let new_obligation = Obligation::new( - ObligationCause::dummy(), - param_env, - new_trait_ref.without_const().to_predicate(), - ); - if self.predicate_must_hold_modulo_regions(&new_obligation) { - if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { - // We have a very specific type of error, where just borrowing this argument - // might solve the problem. In cases like this, the important part is the - // original type obligation, not the last one that failed, which is arbitrary. - // Because of this, we modify the error to refer to the original obligation and - // return early in the caller. - let msg = format!( - "the trait bound `{}: {}` is not satisfied", - found, - obligation.parent_trait_ref.skip_binder().print_only_trait_path(), - ); - if has_custom_message { - err.note(&msg); - } else { - err.message = vec![(msg, Style::NoStyle)]; - } - if snippet.starts_with('&') { - // This is already a literal borrow and the obligation is failing - // somewhere else in the obligation chain. Do not suggest non-sense. - return false; - } - err.span_label( - span, - &format!( - "expected an implementor of trait `{}`", - obligation.parent_trait_ref.skip_binder().print_only_trait_path(), - ), - ); - err.span_suggestion( - span, - "consider borrowing here", - format!("&{}", snippet), - Applicability::MaybeIncorrect, - ); - return true; - } - } - } - false - } - - /// Whenever references are used by mistake, like `for (i, e) in &vec.iter().enumerate()`, - /// suggest removing these references until we reach a type that implements the trait. - crate fn suggest_remove_reference( - &self, - obligation: &PredicateObligation<'tcx>, - err: &mut DiagnosticBuilder<'tcx>, - trait_ref: &ty::Binder<ty::TraitRef<'tcx>>, - ) { - let trait_ref = trait_ref.skip_binder(); - let span = obligation.cause.span; - - if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { - let refs_number = - snippet.chars().filter(|c| !c.is_whitespace()).take_while(|c| *c == '&').count(); - if let Some('\'') = - snippet.chars().filter(|c| !c.is_whitespace()).skip(refs_number).next() - { - // Do not suggest removal of borrow from type arguments. - return; - } - - let mut trait_type = trait_ref.self_ty(); - - for refs_remaining in 0..refs_number { - if let ty::Ref(_, t_type, _) = trait_type.kind { - trait_type = t_type; - - let new_obligation = self.mk_obligation_for_def_id( - trait_ref.def_id, - trait_type, - ObligationCause::dummy(), - obligation.param_env, - ); - - if self.predicate_may_hold(&new_obligation) { - let sp = self - .tcx - .sess - .source_map() - .span_take_while(span, |c| c.is_whitespace() || *c == '&'); - - let remove_refs = refs_remaining + 1; - - let msg = if remove_refs == 1 { - "consider removing the leading `&`-reference".to_string() - } else { - format!("consider removing {} leading `&`-references", remove_refs) - }; - - err.span_suggestion_short( - sp, - &msg, - String::new(), - Applicability::MachineApplicable, - ); - break; - } - } else { - break; - } - } - } - } - - /// Check if the trait bound is implemented for a different mutability and note it in the - /// final error. - crate fn suggest_change_mut( - &self, - obligation: &PredicateObligation<'tcx>, - err: &mut DiagnosticBuilder<'tcx>, - trait_ref: &ty::Binder<ty::TraitRef<'tcx>>, - points_at_arg: bool, - ) { - let span = obligation.cause.span; - if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { - let refs_number = - snippet.chars().filter(|c| !c.is_whitespace()).take_while(|c| *c == '&').count(); - if let Some('\'') = - snippet.chars().filter(|c| !c.is_whitespace()).skip(refs_number).next() - { - // Do not suggest removal of borrow from type arguments. - return; - } - let trait_ref = self.resolve_vars_if_possible(trait_ref); - if trait_ref.has_infer_types() { - // Do not ICE while trying to find if a reborrow would succeed on a trait with - // unresolved bindings. - return; - } - - if let ty::Ref(region, t_type, mutability) = trait_ref.skip_binder().self_ty().kind { - let trait_type = match mutability { - hir::Mutability::Mut => self.tcx.mk_imm_ref(region, t_type), - hir::Mutability::Not => self.tcx.mk_mut_ref(region, t_type), - }; - - let new_obligation = self.mk_obligation_for_def_id( - trait_ref.skip_binder().def_id, - trait_type, - ObligationCause::dummy(), - obligation.param_env, - ); - - if self.evaluate_obligation_no_overflow(&new_obligation).must_apply_modulo_regions() - { - let sp = self - .tcx - .sess - .source_map() - .span_take_while(span, |c| c.is_whitespace() || *c == '&'); - if points_at_arg && mutability == hir::Mutability::Not && refs_number > 0 { - err.span_suggestion( - sp, - "consider changing this borrow's mutability", - "&mut ".to_string(), - Applicability::MachineApplicable, - ); - } else { - err.note(&format!( - "`{}` is implemented for `{:?}`, but not for `{:?}`", - trait_ref.print_only_trait_path(), - trait_type, - trait_ref.skip_binder().self_ty(), - )); - } - } - } - } - } - - crate fn suggest_semicolon_removal( - &self, - obligation: &PredicateObligation<'tcx>, - err: &mut DiagnosticBuilder<'tcx>, - span: Span, - trait_ref: &ty::Binder<ty::TraitRef<'tcx>>, - ) { - let hir = self.tcx.hir(); - let parent_node = hir.get_parent_node(obligation.cause.body_id); - let node = hir.find(parent_node); - if let Some(hir::Node::Item(hir::Item { - kind: hir::ItemKind::Fn(sig, _, body_id), .. - })) = node - { - let body = hir.body(*body_id); - if let hir::ExprKind::Block(blk, _) = &body.value.kind { - if sig.decl.output.span().overlaps(span) - && blk.expr.is_none() - && "()" == &trait_ref.self_ty().to_string() - { - // FIXME(estebank): When encountering a method with a trait - // bound not satisfied in the return type with a body that has - // no return, suggest removal of semicolon on last statement. - // Once that is added, close #54771. - if let Some(ref stmt) = blk.stmts.last() { - let sp = self.tcx.sess.source_map().end_point(stmt.span); - err.span_label(sp, "consider removing this semicolon"); - } - } - } - } - } - - /// If all conditions are met to identify a returned `dyn Trait`, suggest using `impl Trait` if - /// applicable and signal that the error has been expanded appropriately and needs to be - /// emitted. - crate fn suggest_impl_trait( - &self, - err: &mut DiagnosticBuilder<'tcx>, - span: Span, - obligation: &PredicateObligation<'tcx>, - trait_ref: &ty::Binder<ty::TraitRef<'tcx>>, - ) -> bool { - match obligation.cause.code.peel_derives() { - // Only suggest `impl Trait` if the return type is unsized because it is `dyn Trait`. - ObligationCauseCode::SizedReturnType => {} - _ => return false, - } - - let hir = self.tcx.hir(); - let parent_node = hir.get_parent_node(obligation.cause.body_id); - let node = hir.find(parent_node); - let (sig, body_id) = if let Some(hir::Node::Item(hir::Item { - kind: hir::ItemKind::Fn(sig, _, body_id), - .. - })) = node - { - (sig, body_id) - } else { - return false; - }; - let body = hir.body(*body_id); - let trait_ref = self.resolve_vars_if_possible(trait_ref); - let ty = trait_ref.skip_binder().self_ty(); - let is_object_safe = match ty.kind { - ty::Dynamic(predicates, _) => { - // If the `dyn Trait` is not object safe, do not suggest `Box<dyn Trait>`. - predicates - .principal_def_id() - .map_or(true, |def_id| object_safety_violations(self.tcx, def_id).is_empty()) - } - // We only want to suggest `impl Trait` to `dyn Trait`s. - // For example, `fn foo() -> str` needs to be filtered out. - _ => return false, - }; - - let ret_ty = if let hir::FunctionRetTy::Return(ret_ty) = sig.decl.output { - ret_ty - } else { - return false; - }; - - // Use `TypeVisitor` instead of the output type directly to find the span of `ty` for - // cases like `fn foo() -> (dyn Trait, i32) {}`. - // Recursively look for `TraitObject` types and if there's only one, use that span to - // suggest `impl Trait`. - - // Visit to make sure there's a single `return` type to suggest `impl Trait`, - // otherwise suggest using `Box<dyn Trait>` or an enum. - let mut visitor = ReturnsVisitor::default(); - visitor.visit_body(&body); - - let tables = self.in_progress_tables.map(|t| t.borrow()).unwrap(); - - let mut ret_types = visitor - .returns - .iter() - .filter_map(|expr| tables.node_type_opt(expr.hir_id)) - .map(|ty| self.resolve_vars_if_possible(&ty)); - let (last_ty, all_returns_have_same_type) = ret_types.clone().fold( - (None, true), - |(last_ty, mut same): (std::option::Option<Ty<'_>>, bool), ty| { - let ty = self.resolve_vars_if_possible(&ty); - same &= last_ty.map_or(true, |last_ty| last_ty == ty) && ty.kind != ty::Error; - (Some(ty), same) - }, - ); - let all_returns_conform_to_trait = - if let Some(ty_ret_ty) = tables.node_type_opt(ret_ty.hir_id) { - match ty_ret_ty.kind { - ty::Dynamic(predicates, _) => { - let cause = ObligationCause::misc(ret_ty.span, ret_ty.hir_id); - let param_env = ty::ParamEnv::empty(); - ret_types.all(|returned_ty| { - predicates.iter().all(|predicate| { - let pred = predicate.with_self_ty(self.tcx, returned_ty); - let obl = Obligation::new(cause.clone(), param_env, pred); - self.predicate_may_hold(&obl) - }) - }) - } - _ => false, - } - } else { - true - }; - - let (snippet, last_ty) = - if let (true, hir::TyKind::TraitObject(..), Ok(snippet), true, Some(last_ty)) = ( - // Verify that we're dealing with a return `dyn Trait` - ret_ty.span.overlaps(span), - &ret_ty.kind, - self.tcx.sess.source_map().span_to_snippet(ret_ty.span), - // If any of the return types does not conform to the trait, then we can't - // suggest `impl Trait` nor trait objects, it is a type mismatch error. - all_returns_conform_to_trait, - last_ty, - ) { - (snippet, last_ty) - } else { - return false; - }; - err.code(error_code!(E0746)); - err.set_primary_message("return type cannot have an unboxed trait object"); - err.children.clear(); - let impl_trait_msg = "for information on `impl Trait`, see \ - <https://doc.rust-lang.org/book/ch10-02-traits.html\ - #returning-types-that-implement-traits>"; - let trait_obj_msg = "for information on trait objects, see \ - <https://doc.rust-lang.org/book/ch17-02-trait-objects.html\ - #using-trait-objects-that-allow-for-values-of-different-types>"; - let has_dyn = snippet.split_whitespace().next().map_or(false, |s| s == "dyn"); - let trait_obj = if has_dyn { &snippet[4..] } else { &snippet[..] }; - if all_returns_have_same_type { - // Suggest `-> impl Trait`. - err.span_suggestion( - ret_ty.span, - &format!( - "return `impl {1}` instead, as all return paths are of type `{}`, \ - which implements `{1}`", - last_ty, trait_obj, - ), - format!("impl {}", trait_obj), - Applicability::MachineApplicable, - ); - err.note(impl_trait_msg); - } else { - if is_object_safe { - // Suggest `-> Box<dyn Trait>` and `Box::new(returned_value)`. - // Get all the return values and collect their span and suggestion. - let mut suggestions = visitor - .returns - .iter() - .map(|expr| { - ( - expr.span, - format!( - "Box::new({})", - self.tcx.sess.source_map().span_to_snippet(expr.span).unwrap() - ), - ) - }) - .collect::<Vec<_>>(); - // Add the suggestion for the return type. - suggestions.push((ret_ty.span, format!("Box<dyn {}>", trait_obj))); - err.multipart_suggestion( - "return a boxed trait object instead", - suggestions, - Applicability::MaybeIncorrect, - ); - } else { - // This is currently not possible to trigger because E0038 takes precedence, but - // leave it in for completeness in case anything changes in an earlier stage. - err.note(&format!( - "if trait `{}` was object safe, you could return a trait object", - trait_obj, - )); - } - err.note(trait_obj_msg); - err.note(&format!( - "if all the returned values were of the same type you could use \ - `impl {}` as the return type", - trait_obj, - )); - err.note(impl_trait_msg); - err.note("you can create a new `enum` with a variant for each returned type"); - } - true - } - - crate fn point_at_returns_when_relevant( - &self, - err: &mut DiagnosticBuilder<'tcx>, - obligation: &PredicateObligation<'tcx>, - ) { - match obligation.cause.code.peel_derives() { - ObligationCauseCode::SizedReturnType => {} - _ => return, - } - - let hir = self.tcx.hir(); - let parent_node = hir.get_parent_node(obligation.cause.body_id); - let node = hir.find(parent_node); - if let Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. })) = - node - { - let body = hir.body(*body_id); - // Point at all the `return`s in the function as they have failed trait bounds. - let mut visitor = ReturnsVisitor::default(); - visitor.visit_body(&body); - let tables = self.in_progress_tables.map(|t| t.borrow()).unwrap(); - for expr in &visitor.returns { - if let Some(returned_ty) = tables.node_type_opt(expr.hir_id) { - let ty = self.resolve_vars_if_possible(&returned_ty); - err.span_label(expr.span, &format!("this returned value is of type `{}`", ty)); - } - } - } - } - - /// Given some node representing a fn-like thing in the HIR map, - /// returns a span and `ArgKind` information that describes the - /// arguments it expects. This can be supplied to - /// `report_arg_count_mismatch`. - pub fn get_fn_like_arguments(&self, node: Node<'_>) -> (Span, Vec<ArgKind>) { - match node { - Node::Expr(&hir::Expr { - kind: hir::ExprKind::Closure(_, ref _decl, id, span, _), - .. - }) => ( - self.tcx.sess.source_map().def_span(span), - self.tcx - .hir() - .body(id) - .params - .iter() - .map(|arg| { - if let hir::Pat { kind: hir::PatKind::Tuple(ref args, _), span, .. } = - *arg.pat - { - ArgKind::Tuple( - Some(span), - args.iter() - .map(|pat| { - let snippet = self - .tcx - .sess - .source_map() - .span_to_snippet(pat.span) - .unwrap(); - (snippet, "_".to_owned()) - }) - .collect::<Vec<_>>(), - ) - } else { - let name = - self.tcx.sess.source_map().span_to_snippet(arg.pat.span).unwrap(); - ArgKind::Arg(name, "_".to_owned()) - } - }) - .collect::<Vec<ArgKind>>(), - ), - Node::Item(&hir::Item { span, kind: hir::ItemKind::Fn(ref sig, ..), .. }) - | Node::ImplItem(&hir::ImplItem { - span, - kind: hir::ImplItemKind::Method(ref sig, _), - .. - }) - | Node::TraitItem(&hir::TraitItem { - span, - kind: hir::TraitItemKind::Method(ref sig, _), - .. - }) => ( - self.tcx.sess.source_map().def_span(span), - sig.decl - .inputs - .iter() - .map(|arg| match arg.clone().kind { - hir::TyKind::Tup(ref tys) => ArgKind::Tuple( - Some(arg.span), - vec![("_".to_owned(), "_".to_owned()); tys.len()], - ), - _ => ArgKind::empty(), - }) - .collect::<Vec<ArgKind>>(), - ), - Node::Ctor(ref variant_data) => { - let span = variant_data - .ctor_hir_id() - .map(|hir_id| self.tcx.hir().span(hir_id)) - .unwrap_or(DUMMY_SP); - let span = self.tcx.sess.source_map().def_span(span); - - (span, vec![ArgKind::empty(); variant_data.fields().len()]) - } - _ => panic!("non-FnLike node found: {:?}", node), - } - } - - /// Reports an error when the number of arguments needed by a - /// trait match doesn't match the number that the expression - /// provides. - pub fn report_arg_count_mismatch( - &self, - span: Span, - found_span: Option<Span>, - expected_args: Vec<ArgKind>, - found_args: Vec<ArgKind>, - is_closure: bool, - ) -> DiagnosticBuilder<'tcx> { - let kind = if is_closure { "closure" } else { "function" }; - - let args_str = |arguments: &[ArgKind], other: &[ArgKind]| { - let arg_length = arguments.len(); - let distinct = match &other[..] { - &[ArgKind::Tuple(..)] => true, - _ => false, - }; - match (arg_length, arguments.get(0)) { - (1, Some(&ArgKind::Tuple(_, ref fields))) => { - format!("a single {}-tuple as argument", fields.len()) - } - _ => format!( - "{} {}argument{}", - arg_length, - if distinct && arg_length > 1 { "distinct " } else { "" }, - pluralize!(arg_length) - ), - } - }; - - let expected_str = args_str(&expected_args, &found_args); - let found_str = args_str(&found_args, &expected_args); - - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0593, - "{} is expected to take {}, but it takes {}", - kind, - expected_str, - found_str, - ); - - err.span_label(span, format!("expected {} that takes {}", kind, expected_str)); - - if let Some(found_span) = found_span { - err.span_label(found_span, format!("takes {}", found_str)); - - // move |_| { ... } - // ^^^^^^^^-- def_span - // - // move |_| { ... } - // ^^^^^-- prefix - let prefix_span = self.tcx.sess.source_map().span_until_non_whitespace(found_span); - // move |_| { ... } - // ^^^-- pipe_span - let pipe_span = - if let Some(span) = found_span.trim_start(prefix_span) { span } else { found_span }; - - // Suggest to take and ignore the arguments with expected_args_length `_`s if - // found arguments is empty (assume the user just wants to ignore args in this case). - // For example, if `expected_args_length` is 2, suggest `|_, _|`. - if found_args.is_empty() && is_closure { - let underscores = vec!["_"; expected_args.len()].join(", "); - err.span_suggestion( - pipe_span, - &format!( - "consider changing the closure to take and ignore the expected argument{}", - if expected_args.len() < 2 { "" } else { "s" } - ), - format!("|{}|", underscores), - Applicability::MachineApplicable, - ); - } - - if let &[ArgKind::Tuple(_, ref fields)] = &found_args[..] { - if fields.len() == expected_args.len() { - let sugg = fields - .iter() - .map(|(name, _)| name.to_owned()) - .collect::<Vec<String>>() - .join(", "); - err.span_suggestion( - found_span, - "change the closure to take multiple arguments instead of a single tuple", - format!("|{}|", sugg), - Applicability::MachineApplicable, - ); - } - } - if let &[ArgKind::Tuple(_, ref fields)] = &expected_args[..] { - if fields.len() == found_args.len() && is_closure { - let sugg = format!( - "|({}){}|", - found_args - .iter() - .map(|arg| match arg { - ArgKind::Arg(name, _) => name.to_owned(), - _ => "_".to_owned(), - }) - .collect::<Vec<String>>() - .join(", "), - // add type annotations if available - if found_args.iter().any(|arg| match arg { - ArgKind::Arg(_, ty) => ty != "_", - _ => false, - }) { - format!( - ": ({})", - fields - .iter() - .map(|(_, ty)| ty.to_owned()) - .collect::<Vec<String>>() - .join(", ") - ) - } else { - String::new() - }, - ); - err.span_suggestion( - found_span, - "change the closure to accept a tuple instead of individual arguments", - sugg, - Applicability::MachineApplicable, - ); - } - } - } - - err - } - - crate fn report_closure_arg_mismatch( - &self, - span: Span, - found_span: Option<Span>, - expected_ref: ty::PolyTraitRef<'tcx>, - found: ty::PolyTraitRef<'tcx>, - ) -> DiagnosticBuilder<'tcx> { - crate fn build_fn_sig_string<'tcx>( - tcx: TyCtxt<'tcx>, - trait_ref: &ty::TraitRef<'tcx>, - ) -> String { - let inputs = trait_ref.substs.type_at(1); - let sig = if let ty::Tuple(inputs) = inputs.kind { - tcx.mk_fn_sig( - inputs.iter().map(|k| k.expect_ty()), - tcx.mk_ty_infer(ty::TyVar(ty::TyVid { index: 0 })), - false, - hir::Unsafety::Normal, - ::rustc_target::spec::abi::Abi::Rust, - ) - } else { - tcx.mk_fn_sig( - ::std::iter::once(inputs), - tcx.mk_ty_infer(ty::TyVar(ty::TyVid { index: 0 })), - false, - hir::Unsafety::Normal, - ::rustc_target::spec::abi::Abi::Rust, - ) - }; - ty::Binder::bind(sig).to_string() - } - - let argument_is_closure = expected_ref.skip_binder().substs.type_at(0).is_closure(); - let mut err = struct_span_err!( - self.tcx.sess, - span, - E0631, - "type mismatch in {} arguments", - if argument_is_closure { "closure" } else { "function" } - ); - - let found_str = format!( - "expected signature of `{}`", - build_fn_sig_string(self.tcx, found.skip_binder()) - ); - err.span_label(span, found_str); - - let found_span = found_span.unwrap_or(span); - let expected_str = format!( - "found signature of `{}`", - build_fn_sig_string(self.tcx, expected_ref.skip_binder()) - ); - err.span_label(found_span, expected_str); - - err - } -} - -impl<'a, 'tcx> InferCtxt<'a, 'tcx> { - crate fn suggest_fully_qualified_path( - &self, - err: &mut DiagnosticBuilder<'_>, - def_id: DefId, - span: Span, - trait_ref: DefId, - ) { - if let Some(assoc_item) = self.tcx.opt_associated_item(def_id) { - if let ty::AssocKind::Const | ty::AssocKind::Type = assoc_item.kind { - err.note(&format!( - "{}s cannot be accessed directly on a `trait`, they can only be \ - accessed through a specific `impl`", - assoc_item.kind.suggestion_descr(), - )); - err.span_suggestion( - span, - "use the fully qualified path to an implementation", - format!("<Type as {}>::{}", self.tcx.def_path_str(trait_ref), assoc_item.ident), - Applicability::HasPlaceholders, - ); - } - } - } - - /// Adds an async-await specific note to the diagnostic when the future does not implement - /// an auto trait because of a captured type. - /// - /// ```ignore (diagnostic) - /// note: future does not implement `Qux` as this value is used across an await - /// --> $DIR/issue-64130-3-other.rs:17:5 - /// | - /// LL | let x = Foo; - /// | - has type `Foo` - /// LL | baz().await; - /// | ^^^^^^^^^^^ await occurs here, with `x` maybe used later - /// LL | } - /// | - `x` is later dropped here - /// ``` - /// - /// When the diagnostic does not implement `Send` or `Sync` specifically, then the diagnostic - /// is "replaced" with a different message and a more specific error. - /// - /// ```ignore (diagnostic) - /// error: future cannot be sent between threads safely - /// --> $DIR/issue-64130-2-send.rs:21:5 - /// | - /// LL | fn is_send<T: Send>(t: T) { } - /// | ------- ---- required by this bound in `is_send` - /// ... - /// LL | is_send(bar()); - /// | ^^^^^^^ future returned by `bar` is not send - /// | - /// = help: within `impl std::future::Future`, the trait `std::marker::Send` is not - /// implemented for `Foo` - /// note: future is not send as this value is used across an await - /// --> $DIR/issue-64130-2-send.rs:15:5 - /// | - /// LL | let x = Foo; - /// | - has type `Foo` - /// LL | baz().await; - /// | ^^^^^^^^^^^ await occurs here, with `x` maybe used later - /// LL | } - /// | - `x` is later dropped here - /// ``` - /// - /// Returns `true` if an async-await specific note was added to the diagnostic. - crate fn maybe_note_obligation_cause_for_async_await( - &self, - err: &mut DiagnosticBuilder<'_>, - obligation: &PredicateObligation<'tcx>, - ) -> bool { - debug!( - "maybe_note_obligation_cause_for_async_await: obligation.predicate={:?} \ - obligation.cause.span={:?}", - obligation.predicate, obligation.cause.span - ); - let source_map = self.tcx.sess.source_map(); - - // Attempt to detect an async-await error by looking at the obligation causes, looking - // for a generator to be present. - // - // When a future does not implement a trait because of a captured type in one of the - // generators somewhere in the call stack, then the result is a chain of obligations. - // - // Given a `async fn` A that calls a `async fn` B which captures a non-send type and that - // future is passed as an argument to a function C which requires a `Send` type, then the - // chain looks something like this: - // - // - `BuiltinDerivedObligation` with a generator witness (B) - // - `BuiltinDerivedObligation` with a generator (B) - // - `BuiltinDerivedObligation` with `std::future::GenFuture` (B) - // - `BuiltinDerivedObligation` with `impl std::future::Future` (B) - // - `BuiltinDerivedObligation` with `impl std::future::Future` (B) - // - `BuiltinDerivedObligation` with a generator witness (A) - // - `BuiltinDerivedObligation` with a generator (A) - // - `BuiltinDerivedObligation` with `std::future::GenFuture` (A) - // - `BuiltinDerivedObligation` with `impl std::future::Future` (A) - // - `BuiltinDerivedObligation` with `impl std::future::Future` (A) - // - `BindingObligation` with `impl_send (Send requirement) - // - // The first obligation in the chain is the most useful and has the generator that captured - // the type. The last generator has information about where the bound was introduced. At - // least one generator should be present for this diagnostic to be modified. - let (mut trait_ref, mut target_ty) = match obligation.predicate { - ty::Predicate::Trait(p, _) => { - (Some(p.skip_binder().trait_ref), Some(p.skip_binder().self_ty())) - } - _ => (None, None), - }; - let mut generator = None; - let mut last_generator = None; - let mut next_code = Some(&obligation.cause.code); - while let Some(code) = next_code { - debug!("maybe_note_obligation_cause_for_async_await: code={:?}", code); - match code { - ObligationCauseCode::BuiltinDerivedObligation(derived_obligation) - | ObligationCauseCode::ImplDerivedObligation(derived_obligation) => { - let ty = derived_obligation.parent_trait_ref.self_ty(); - debug!( - "maybe_note_obligation_cause_for_async_await: \ - parent_trait_ref={:?} self_ty.kind={:?}", - derived_obligation.parent_trait_ref, ty.kind - ); - - match ty.kind { - ty::Generator(did, ..) => { - generator = generator.or(Some(did)); - last_generator = Some(did); - } - ty::GeneratorWitness(..) => {} - _ if generator.is_none() => { - trait_ref = Some(*derived_obligation.parent_trait_ref.skip_binder()); - target_ty = Some(ty); - } - _ => {} - } - - next_code = Some(derived_obligation.parent_code.as_ref()); - } - _ => break, - } - } - - // Only continue if a generator was found. - debug!( - "maybe_note_obligation_cause_for_async_await: generator={:?} trait_ref={:?} \ - target_ty={:?}", - generator, trait_ref, target_ty - ); - let (generator_did, trait_ref, target_ty) = match (generator, trait_ref, target_ty) { - (Some(generator_did), Some(trait_ref), Some(target_ty)) => { - (generator_did, trait_ref, target_ty) - } - _ => return false, - }; - - let span = self.tcx.def_span(generator_did); - - // Do not ICE on closure typeck (#66868). - if self.tcx.hir().as_local_hir_id(generator_did).is_none() { - return false; - } - - // Get the tables from the infcx if the generator is the function we are - // currently type-checking; otherwise, get them by performing a query. - // This is needed to avoid cycles. - let in_progress_tables = self.in_progress_tables.map(|t| t.borrow()); - let generator_did_root = self.tcx.closure_base_def_id(generator_did); - debug!( - "maybe_note_obligation_cause_for_async_await: generator_did={:?} \ - generator_did_root={:?} in_progress_tables.local_id_root={:?} span={:?}", - generator_did, - generator_did_root, - in_progress_tables.as_ref().map(|t| t.local_id_root), - span - ); - let query_tables; - let tables: &TypeckTables<'tcx> = match &in_progress_tables { - Some(t) if t.local_id_root == Some(generator_did_root) => t, - _ => { - query_tables = self.tcx.typeck_tables_of(generator_did); - &query_tables - } - }; - - // Look for a type inside the generator interior that matches the target type to get - // a span. - let target_ty_erased = self.tcx.erase_regions(&target_ty); - let target_span = tables - .generator_interior_types - .iter() - .find(|ty::GeneratorInteriorTypeCause { ty, .. }| { - // Careful: the regions for types that appear in the - // generator interior are not generally known, so we - // want to erase them when comparing (and anyway, - // `Send` and other bounds are generally unaffected by - // the choice of region). When erasing regions, we - // also have to erase late-bound regions. This is - // because the types that appear in the generator - // interior generally contain "bound regions" to - // represent regions that are part of the suspended - // generator frame. Bound regions are preserved by - // `erase_regions` and so we must also call - // `erase_late_bound_regions`. - let ty_erased = self.tcx.erase_late_bound_regions(&ty::Binder::bind(*ty)); - let ty_erased = self.tcx.erase_regions(&ty_erased); - let eq = ty::TyS::same_type(ty_erased, target_ty_erased); - debug!( - "maybe_note_obligation_cause_for_async_await: ty_erased={:?} \ - target_ty_erased={:?} eq={:?}", - ty_erased, target_ty_erased, eq - ); - eq - }) - .map(|ty::GeneratorInteriorTypeCause { span, scope_span, expr, .. }| { - (span, source_map.span_to_snippet(*span), scope_span, expr) - }); - - debug!( - "maybe_note_obligation_cause_for_async_await: target_ty={:?} \ - generator_interior_types={:?} target_span={:?}", - target_ty, tables.generator_interior_types, target_span - ); - if let Some((target_span, Ok(snippet), scope_span, expr)) = target_span { - self.note_obligation_cause_for_async_await( - err, - *target_span, - scope_span, - *expr, - snippet, - generator_did, - last_generator, - trait_ref, - target_ty, - tables, - obligation, - next_code, - ); - true - } else { - false - } - } - - /// Unconditionally adds the diagnostic note described in - /// `maybe_note_obligation_cause_for_async_await`'s documentation comment. - crate fn note_obligation_cause_for_async_await( - &self, - err: &mut DiagnosticBuilder<'_>, - target_span: Span, - scope_span: &Option<Span>, - expr: Option<hir::HirId>, - snippet: String, - first_generator: DefId, - last_generator: Option<DefId>, - trait_ref: ty::TraitRef<'_>, - target_ty: Ty<'tcx>, - tables: &ty::TypeckTables<'_>, - obligation: &PredicateObligation<'tcx>, - next_code: Option<&ObligationCauseCode<'tcx>>, - ) { - let source_map = self.tcx.sess.source_map(); - - let is_async_fn = self - .tcx - .parent(first_generator) - .map(|parent_did| self.tcx.asyncness(parent_did)) - .map(|parent_asyncness| parent_asyncness == hir::IsAsync::Async) - .unwrap_or(false); - let is_async_move = self - .tcx - .hir() - .as_local_hir_id(first_generator) - .and_then(|hir_id| self.tcx.hir().maybe_body_owned_by(hir_id)) - .map(|body_id| self.tcx.hir().body(body_id)) - .and_then(|body| body.generator_kind()) - .map(|generator_kind| match generator_kind { - hir::GeneratorKind::Async(..) => true, - _ => false, - }) - .unwrap_or(false); - let await_or_yield = if is_async_fn || is_async_move { "await" } else { "yield" }; - - // Special case the primary error message when send or sync is the trait that was - // not implemented. - let is_send = self.tcx.is_diagnostic_item(sym::send_trait, trait_ref.def_id); - let is_sync = self.tcx.is_diagnostic_item(sym::sync_trait, trait_ref.def_id); - let hir = self.tcx.hir(); - let trait_explanation = if is_send || is_sync { - let (trait_name, trait_verb) = - if is_send { ("`Send`", "sent") } else { ("`Sync`", "shared") }; - - err.clear_code(); - err.set_primary_message(format!( - "future cannot be {} between threads safely", - trait_verb - )); - - let original_span = err.span.primary_span().unwrap(); - let mut span = MultiSpan::from_span(original_span); - - let message = if let Some(name) = last_generator - .and_then(|generator_did| self.tcx.parent(generator_did)) - .and_then(|parent_did| hir.as_local_hir_id(parent_did)) - .and_then(|parent_hir_id| hir.opt_name(parent_hir_id)) - { - format!("future returned by `{}` is not {}", name, trait_name) - } else { - format!("future is not {}", trait_name) - }; - - span.push_span_label(original_span, message); - err.set_span(span); - - format!("is not {}", trait_name) - } else { - format!("does not implement `{}`", trait_ref.print_only_trait_path()) - }; - - // Look at the last interior type to get a span for the `.await`. - let await_span = tables.generator_interior_types.iter().map(|t| t.span).last().unwrap(); - let mut span = MultiSpan::from_span(await_span); - span.push_span_label( - await_span, - format!("{} occurs here, with `{}` maybe used later", await_or_yield, snippet), - ); - - span.push_span_label(target_span, format!("has type `{}`", target_ty)); - - // If available, use the scope span to annotate the drop location. - if let Some(scope_span) = scope_span { - span.push_span_label( - source_map.end_point(*scope_span), - format!("`{}` is later dropped here", snippet), - ); - } - - err.span_note( - span, - &format!( - "future {} as this value is used across an {}", - trait_explanation, await_or_yield, - ), - ); - - if let Some(expr_id) = expr { - let expr = hir.expect_expr(expr_id); - debug!("target_ty evaluated from {:?}", expr); - - let parent = hir.get_parent_node(expr_id); - if let Some(hir::Node::Expr(e)) = hir.find(parent) { - let parent_span = hir.span(parent); - let parent_did = parent.owner_def_id(); - // ```rust - // impl T { - // fn foo(&self) -> i32 {} - // } - // T.foo(); - // ^^^^^^^ a temporary `&T` created inside this method call due to `&self` - // ``` - // - let is_region_borrow = - tables.expr_adjustments(expr).iter().any(|adj| adj.is_region_borrow()); - - // ```rust - // struct Foo(*const u8); - // bar(Foo(std::ptr::null())).await; - // ^^^^^^^^^^^^^^^^^^^^^ raw-ptr `*T` created inside this struct ctor. - // ``` - debug!("parent_def_kind: {:?}", self.tcx.def_kind(parent_did)); - let is_raw_borrow_inside_fn_like_call = match self.tcx.def_kind(parent_did) { - Some(DefKind::Fn) | Some(DefKind::Ctor(..)) => target_ty.is_unsafe_ptr(), - _ => false, - }; - - if (tables.is_method_call(e) && is_region_borrow) - || is_raw_borrow_inside_fn_like_call - { - err.span_help( - parent_span, - "consider moving this into a `let` \ - binding to create a shorter lived borrow", - ); - } - } - } - - // Add a note for the item obligation that remains - normally a note pointing to the - // bound that introduced the obligation (e.g. `T: Send`). - debug!("note_obligation_cause_for_async_await: next_code={:?}", next_code); - self.note_obligation_cause_code( - err, - &obligation.predicate, - next_code.unwrap(), - &mut Vec::new(), - ); - } - - crate fn note_obligation_cause_code<T>( - &self, - err: &mut DiagnosticBuilder<'_>, - predicate: &T, - cause_code: &ObligationCauseCode<'tcx>, - obligated_types: &mut Vec<&ty::TyS<'tcx>>, - ) where - T: fmt::Display, - { - let tcx = self.tcx; - match *cause_code { - ObligationCauseCode::ExprAssignable - | ObligationCauseCode::MatchExpressionArm { .. } - | ObligationCauseCode::Pattern { .. } - | ObligationCauseCode::IfExpression { .. } - | ObligationCauseCode::IfExpressionWithNoElse - | ObligationCauseCode::MainFunctionType - | ObligationCauseCode::StartFunctionType - | ObligationCauseCode::IntrinsicType - | ObligationCauseCode::MethodReceiver - | ObligationCauseCode::ReturnNoExpression - | ObligationCauseCode::MiscObligation => {} - ObligationCauseCode::SliceOrArrayElem => { - err.note("slice and array elements must have `Sized` type"); - } - ObligationCauseCode::TupleElem => { - err.note("only the last element of a tuple may have a dynamically sized type"); - } - ObligationCauseCode::ProjectionWf(data) => { - err.note(&format!("required so that the projection `{}` is well-formed", data,)); - } - ObligationCauseCode::ReferenceOutlivesReferent(ref_ty) => { - err.note(&format!( - "required so that reference `{}` does not outlive its referent", - ref_ty, - )); - } - ObligationCauseCode::ObjectTypeBound(object_ty, region) => { - err.note(&format!( - "required so that the lifetime bound of `{}` for `{}` is satisfied", - region, object_ty, - )); - } - ObligationCauseCode::ItemObligation(item_def_id) => { - let item_name = tcx.def_path_str(item_def_id); - let msg = format!("required by `{}`", item_name); - - if let Some(sp) = tcx.hir().span_if_local(item_def_id) { - let sp = tcx.sess.source_map().def_span(sp); - err.span_label(sp, &msg); - } else { - err.note(&msg); - } - } - ObligationCauseCode::BindingObligation(item_def_id, span) => { - let item_name = tcx.def_path_str(item_def_id); - let msg = format!("required by this bound in `{}`", item_name); - if let Some(ident) = tcx.opt_item_name(item_def_id) { - err.span_label(ident.span, ""); - } - if span != DUMMY_SP { - err.span_label(span, &msg); - } else { - err.note(&msg); - } - } - ObligationCauseCode::ObjectCastObligation(object_ty) => { - err.note(&format!( - "required for the cast to the object type `{}`", - self.ty_to_string(object_ty) - )); - } - ObligationCauseCode::Coercion { source: _, target } => { - err.note(&format!("required by cast to type `{}`", self.ty_to_string(target))); - } - ObligationCauseCode::RepeatVec(suggest_const_in_array_repeat_expressions) => { - err.note( - "the `Copy` trait is required because the repeated element will be copied", - ); - if suggest_const_in_array_repeat_expressions { - err.note( - "this array initializer can be evaluated at compile-time, see issue \ - #48147 <https://github.com/rust-lang/rust/issues/49147> \ - for more information", - ); - if tcx.sess.opts.unstable_features.is_nightly_build() { - err.help( - "add `#![feature(const_in_array_repeat_expressions)]` to the \ - crate attributes to enable", - ); - } - } - } - ObligationCauseCode::VariableType(_) => { - err.note("all local variables must have a statically known size"); - if !self.tcx.features().unsized_locals { - err.help("unsized locals are gated as an unstable feature"); - } - } - ObligationCauseCode::SizedArgumentType => { - err.note("all function arguments must have a statically known size"); - if !self.tcx.features().unsized_locals { - err.help("unsized locals are gated as an unstable feature"); - } - } - ObligationCauseCode::SizedReturnType => { - err.note("the return type of a function must have a statically known size"); - } - ObligationCauseCode::SizedYieldType => { - err.note("the yield type of a generator must have a statically known size"); - } - ObligationCauseCode::AssignmentLhsSized => { - err.note("the left-hand-side of an assignment must have a statically known size"); - } - ObligationCauseCode::TupleInitializerSized => { - err.note("tuples must have a statically known size to be initialized"); - } - ObligationCauseCode::StructInitializerSized => { - err.note("structs must have a statically known size to be initialized"); - } - ObligationCauseCode::FieldSized { adt_kind: ref item, last } => match *item { - AdtKind::Struct => { - if last { - err.note( - "the last field of a packed struct may only have a \ - dynamically sized type if it does not need drop to be run", - ); - } else { - err.note( - "only the last field of a struct may have a dynamically sized type", - ); - } - } - AdtKind::Union => { - err.note("no field of a union may have a dynamically sized type"); - } - AdtKind::Enum => { - err.note("no field of an enum variant may have a dynamically sized type"); - } - }, - ObligationCauseCode::ConstSized => { - err.note("constant expressions must have a statically known size"); - } - ObligationCauseCode::ConstPatternStructural => { - err.note("constants used for pattern-matching must derive `PartialEq` and `Eq`"); - } - ObligationCauseCode::SharedStatic => { - err.note("shared static variables must have a type that implements `Sync`"); - } - ObligationCauseCode::BuiltinDerivedObligation(ref data) => { - let parent_trait_ref = self.resolve_vars_if_possible(&data.parent_trait_ref); - let ty = parent_trait_ref.skip_binder().self_ty(); - err.note(&format!("required because it appears within the type `{}`", ty)); - obligated_types.push(ty); - - let parent_predicate = parent_trait_ref.without_const().to_predicate(); - if !self.is_recursive_obligation(obligated_types, &data.parent_code) { - self.note_obligation_cause_code( - err, - &parent_predicate, - &data.parent_code, - obligated_types, - ); - } - } - ObligationCauseCode::ImplDerivedObligation(ref data) => { - let parent_trait_ref = self.resolve_vars_if_possible(&data.parent_trait_ref); - err.note(&format!( - "required because of the requirements on the impl of `{}` for `{}`", - parent_trait_ref.print_only_trait_path(), - parent_trait_ref.skip_binder().self_ty() - )); - let parent_predicate = parent_trait_ref.without_const().to_predicate(); - self.note_obligation_cause_code( - err, - &parent_predicate, - &data.parent_code, - obligated_types, - ); - } - ObligationCauseCode::CompareImplMethodObligation { .. } => { - err.note(&format!( - "the requirement `{}` appears on the impl method \ - but not on the corresponding trait method", - predicate - )); - } - ObligationCauseCode::CompareImplTypeObligation { .. } => { - err.note(&format!( - "the requirement `{}` appears on the associated impl type \ - but not on the corresponding associated trait type", - predicate - )); - } - ObligationCauseCode::ReturnType - | ObligationCauseCode::ReturnValue(_) - | ObligationCauseCode::BlockTailExpression(_) => (), - ObligationCauseCode::TrivialBound => { - err.help("see issue #48214"); - if tcx.sess.opts.unstable_features.is_nightly_build() { - err.help("add `#![feature(trivial_bounds)]` to the crate attributes to enable"); - } - } - ObligationCauseCode::AssocTypeBound(ref data) => { - err.span_label(data.original, "associated type defined here"); - if let Some(sp) = data.impl_span { - err.span_label(sp, "in this `impl` item"); - } - for sp in &data.bounds { - err.span_label(*sp, "restricted in this bound"); - } - } - } - } - - crate fn suggest_new_overflow_limit(&self, err: &mut DiagnosticBuilder<'_>) { - let current_limit = self.tcx.sess.recursion_limit.get(); - let suggested_limit = current_limit * 2; - err.help(&format!( - "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate (`{}`)", - suggested_limit, self.tcx.crate_name, - )); - } -} - -/// Collect all the returned expressions within the input expression. -/// Used to point at the return spans when we want to suggest some change to them. -#[derive(Default)] -struct ReturnsVisitor<'v> { - returns: Vec<&'v hir::Expr<'v>>, - in_block_tail: bool, -} - -impl<'v> Visitor<'v> for ReturnsVisitor<'v> { - type Map = rustc::hir::map::Map<'v>; - - fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<'_, Self::Map> { - hir::intravisit::NestedVisitorMap::None - } - - fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) { - // Visit every expression to detect `return` paths, either through the function's tail - // expression or `return` statements. We walk all nodes to find `return` statements, but - // we only care about tail expressions when `in_block_tail` is `true`, which means that - // they're in the return path of the function body. - match ex.kind { - hir::ExprKind::Ret(Some(ex)) => { - self.returns.push(ex); - } - hir::ExprKind::Block(block, _) if self.in_block_tail => { - self.in_block_tail = false; - for stmt in block.stmts { - hir::intravisit::walk_stmt(self, stmt); - } - self.in_block_tail = true; - if let Some(expr) = block.expr { - self.visit_expr(expr); - } - } - hir::ExprKind::Match(_, arms, _) if self.in_block_tail => { - for arm in arms { - self.visit_expr(arm.body); - } - } - // We need to walk to find `return`s in the entire body. - _ if !self.in_block_tail => hir::intravisit::walk_expr(self, ex), - _ => self.returns.push(ex), - } - } - - fn visit_body(&mut self, body: &'v hir::Body<'v>) { - assert!(!self.in_block_tail); - if body.generator_kind().is_none() { - if let hir::ExprKind::Block(block, None) = body.value.kind { - if block.expr.is_some() { - self.in_block_tail = true; - } - } - } - hir::intravisit::walk_body(self, body); - } -} diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs deleted file mode 100644 index 07352a3f947..00000000000 --- a/src/librustc/traits/fulfill.rs +++ /dev/null @@ -1,577 +0,0 @@ -use crate::infer::{InferCtxt, ShallowResolver}; -use crate::ty::error::ExpectedFound; -use crate::ty::{self, ToPolyTraitRef, Ty, TypeFoldable}; -use rustc_data_structures::obligation_forest::ProcessResult; -use rustc_data_structures::obligation_forest::{DoCompleted, Error, ForestObligation}; -use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor}; -use std::marker::PhantomData; - -use super::engine::{TraitEngine, TraitEngineExt}; -use super::project; -use super::select::SelectionContext; -use super::wf; -use super::CodeAmbiguity; -use super::CodeProjectionError; -use super::CodeSelectionError; -use super::{ConstEvalFailure, Unimplemented}; -use super::{FulfillmentError, FulfillmentErrorCode}; -use super::{ObligationCause, PredicateObligation}; - -impl<'tcx> ForestObligation for PendingPredicateObligation<'tcx> { - /// Note that we include both the `ParamEnv` and the `Predicate`, - /// as the `ParamEnv` can influence whether fulfillment succeeds - /// or fails. - type CacheKey = ty::ParamEnvAnd<'tcx, ty::Predicate<'tcx>>; - - fn as_cache_key(&self) -> Self::CacheKey { - self.obligation.param_env.and(self.obligation.predicate) - } -} - -/// The fulfillment context is used to drive trait resolution. It -/// consists of a list of obligations that must be (eventually) -/// satisfied. The job is to track which are satisfied, which yielded -/// errors, and which are still pending. At any point, users can call -/// `select_where_possible`, and the fulfillment context will try to do -/// selection, retaining only those obligations that remain -/// ambiguous. This may be helpful in pushing type inference -/// along. Once all type inference constraints have been generated, the -/// method `select_all_or_error` can be used to report any remaining -/// ambiguous cases as errors. -pub struct FulfillmentContext<'tcx> { - // A list of all obligations that have been registered with this - // fulfillment context. - predicates: ObligationForest<PendingPredicateObligation<'tcx>>, - // Should this fulfillment context register type-lives-for-region - // obligations on its parent infcx? In some cases, region - // obligations are either already known to hold (normalization) or - // hopefully verifed elsewhere (type-impls-bound), and therefore - // should not be checked. - // - // Note that if we are normalizing a type that we already - // know is well-formed, there should be no harm setting this - // to true - all the region variables should be determinable - // using the RFC 447 rules, which don't depend on - // type-lives-for-region constraints, and because the type - // is well-formed, the constraints should hold. - register_region_obligations: bool, - // Is it OK to register obligations into this infcx inside - // an infcx snapshot? - // - // The "primary fulfillment" in many cases in typeck lives - // outside of any snapshot, so any use of it inside a snapshot - // will lead to trouble and therefore is checked against, but - // other fulfillment contexts sometimes do live inside of - // a snapshot (they don't *straddle* a snapshot, so there - // is no trouble there). - usable_in_snapshot: bool, -} - -#[derive(Clone, Debug)] -pub struct PendingPredicateObligation<'tcx> { - pub obligation: PredicateObligation<'tcx>, - pub stalled_on: Vec<ty::InferTy>, -} - -// `PendingPredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger. -#[cfg(target_arch = "x86_64")] -static_assert_size!(PendingPredicateObligation<'_>, 136); - -impl<'a, 'tcx> FulfillmentContext<'tcx> { - /// Creates a new fulfillment context. - pub fn new() -> FulfillmentContext<'tcx> { - FulfillmentContext { - predicates: ObligationForest::new(), - register_region_obligations: true, - usable_in_snapshot: false, - } - } - - pub fn new_in_snapshot() -> FulfillmentContext<'tcx> { - FulfillmentContext { - predicates: ObligationForest::new(), - register_region_obligations: true, - usable_in_snapshot: true, - } - } - - pub fn new_ignoring_regions() -> FulfillmentContext<'tcx> { - FulfillmentContext { - predicates: ObligationForest::new(), - register_region_obligations: false, - usable_in_snapshot: false, - } - } - - /// Attempts to select obligations using `selcx`. - fn select( - &mut self, - selcx: &mut SelectionContext<'a, 'tcx>, - ) -> Result<(), Vec<FulfillmentError<'tcx>>> { - debug!("select(obligation-forest-size={})", self.predicates.len()); - - let mut errors = Vec::new(); - - loop { - debug!("select: starting another iteration"); - - // Process pending obligations. - let outcome = self.predicates.process_obligations( - &mut FulfillProcessor { - selcx, - register_region_obligations: self.register_region_obligations, - }, - DoCompleted::No, - ); - debug!("select: outcome={:#?}", outcome); - - // FIXME: if we kept the original cache key, we could mark projection - // obligations as complete for the projection cache here. - - errors.extend(outcome.errors.into_iter().map(|e| to_fulfillment_error(e))); - - // If nothing new was added, no need to keep looping. - if outcome.stalled { - break; - } - } - - debug!( - "select({} predicates remaining, {} errors) done", - self.predicates.len(), - errors.len() - ); - - if errors.is_empty() { Ok(()) } else { Err(errors) } - } -} - -impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { - /// "Normalize" a projection type `<SomeType as SomeTrait>::X` by - /// creating a fresh type variable `$0` as well as a projection - /// predicate `<SomeType as SomeTrait>::X == $0`. When the - /// inference engine runs, it will attempt to find an impl of - /// `SomeTrait` or a where-clause that lets us unify `$0` with - /// something concrete. If this fails, we'll unify `$0` with - /// `projection_ty` again. - fn normalize_projection_type( - &mut self, - infcx: &InferCtxt<'_, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - projection_ty: ty::ProjectionTy<'tcx>, - cause: ObligationCause<'tcx>, - ) -> Ty<'tcx> { - debug!("normalize_projection_type(projection_ty={:?})", projection_ty); - - debug_assert!(!projection_ty.has_escaping_bound_vars()); - - // FIXME(#20304) -- cache - - let mut selcx = SelectionContext::new(infcx); - let mut obligations = vec![]; - let normalized_ty = project::normalize_projection_type( - &mut selcx, - param_env, - projection_ty, - cause, - 0, - &mut obligations, - ); - self.register_predicate_obligations(infcx, obligations); - - debug!("normalize_projection_type: result={:?}", normalized_ty); - - normalized_ty - } - - fn register_predicate_obligation( - &mut self, - infcx: &InferCtxt<'_, 'tcx>, - obligation: PredicateObligation<'tcx>, - ) { - // this helps to reduce duplicate errors, as well as making - // debug output much nicer to read and so on. - let obligation = infcx.resolve_vars_if_possible(&obligation); - - debug!("register_predicate_obligation(obligation={:?})", obligation); - - assert!(!infcx.is_in_snapshot() || self.usable_in_snapshot); - - self.predicates - .register_obligation(PendingPredicateObligation { obligation, stalled_on: vec![] }); - } - - fn select_all_or_error( - &mut self, - infcx: &InferCtxt<'_, 'tcx>, - ) -> Result<(), Vec<FulfillmentError<'tcx>>> { - self.select_where_possible(infcx)?; - - let errors: Vec<_> = self - .predicates - .to_errors(CodeAmbiguity) - .into_iter() - .map(|e| to_fulfillment_error(e)) - .collect(); - if errors.is_empty() { Ok(()) } else { Err(errors) } - } - - fn select_where_possible( - &mut self, - infcx: &InferCtxt<'_, 'tcx>, - ) -> Result<(), Vec<FulfillmentError<'tcx>>> { - let mut selcx = SelectionContext::new(infcx); - self.select(&mut selcx) - } - - fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> { - self.predicates.map_pending_obligations(|o| o.obligation.clone()) - } -} - -struct FulfillProcessor<'a, 'b, 'tcx> { - selcx: &'a mut SelectionContext<'b, 'tcx>, - register_region_obligations: bool, -} - -fn mk_pending(os: Vec<PredicateObligation<'tcx>>) -> Vec<PendingPredicateObligation<'tcx>> { - os.into_iter() - .map(|o| PendingPredicateObligation { obligation: o, stalled_on: vec![] }) - .collect() -} - -impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { - type Obligation = PendingPredicateObligation<'tcx>; - type Error = FulfillmentErrorCode<'tcx>; - - /// Processes a predicate obligation and returns either: - /// - `Changed(v)` if the predicate is true, presuming that `v` are also true - /// - `Unchanged` if we don't have enough info to be sure - /// - `Error(e)` if the predicate does not hold - /// - /// This is always inlined, despite its size, because it has a single - /// callsite and it is called *very* frequently. - #[inline(always)] - fn process_obligation( - &mut self, - pending_obligation: &mut Self::Obligation, - ) -> ProcessResult<Self::Obligation, Self::Error> { - // If we were stalled on some unresolved variables, first check whether - // any of them have been resolved; if not, don't bother doing more work - // yet. - let change = match pending_obligation.stalled_on.len() { - // Match arms are in order of frequency, which matters because this - // code is so hot. 1 and 0 dominate; 2+ is fairly rare. - 1 => { - let infer = pending_obligation.stalled_on[0]; - ShallowResolver::new(self.selcx.infcx()).shallow_resolve_changed(infer) - } - 0 => { - // In this case we haven't changed, but wish to make a change. - true - } - _ => { - // This `for` loop was once a call to `all()`, but this lower-level - // form was a perf win. See #64545 for details. - (|| { - for &infer in &pending_obligation.stalled_on { - if ShallowResolver::new(self.selcx.infcx()).shallow_resolve_changed(infer) { - return true; - } - } - false - })() - } - }; - - if !change { - debug!( - "process_predicate: pending obligation {:?} still stalled on {:?}", - self.selcx.infcx().resolve_vars_if_possible(&pending_obligation.obligation), - pending_obligation.stalled_on - ); - return ProcessResult::Unchanged; - } - - // This part of the code is much colder. - - pending_obligation.stalled_on.truncate(0); - - let obligation = &mut pending_obligation.obligation; - - if obligation.predicate.has_infer_types() { - obligation.predicate = - self.selcx.infcx().resolve_vars_if_possible(&obligation.predicate); - } - - debug!("process_obligation: obligation = {:?} cause = {:?}", obligation, obligation.cause); - - fn infer_ty(ty: Ty<'tcx>) -> ty::InferTy { - match ty.kind { - ty::Infer(infer) => infer, - _ => panic!(), - } - } - - match obligation.predicate { - ty::Predicate::Trait(ref data, _) => { - let trait_obligation = obligation.with(data.clone()); - - if data.is_global() { - // no type variables present, can use evaluation for better caching. - // FIXME: consider caching errors too. - if self.selcx.infcx().predicate_must_hold_considering_regions(&obligation) { - debug!( - "selecting trait `{:?}` at depth {} evaluated to holds", - data, obligation.recursion_depth - ); - return ProcessResult::Changed(vec![]); - } - } - - match self.selcx.select(&trait_obligation) { - Ok(Some(vtable)) => { - debug!( - "selecting trait `{:?}` at depth {} yielded Ok(Some)", - data, obligation.recursion_depth - ); - ProcessResult::Changed(mk_pending(vtable.nested_obligations())) - } - Ok(None) => { - debug!( - "selecting trait `{:?}` at depth {} yielded Ok(None)", - data, obligation.recursion_depth - ); - - // This is a bit subtle: for the most part, the - // only reason we can fail to make progress on - // trait selection is because we don't have enough - // information about the types in the trait. One - // exception is that we sometimes haven't decided - // what kind of closure a closure is. *But*, in - // that case, it turns out, the type of the - // closure will also change, because the closure - // also includes references to its upvars as part - // of its type, and those types are resolved at - // the same time. - // - // FIXME(#32286) logic seems false if no upvars - pending_obligation.stalled_on = - trait_ref_type_vars(self.selcx, data.to_poly_trait_ref()); - - debug!( - "process_predicate: pending obligation {:?} now stalled on {:?}", - self.selcx.infcx().resolve_vars_if_possible(obligation), - pending_obligation.stalled_on - ); - - ProcessResult::Unchanged - } - Err(selection_err) => { - info!( - "selecting trait `{:?}` at depth {} yielded Err", - data, obligation.recursion_depth - ); - - ProcessResult::Error(CodeSelectionError(selection_err)) - } - } - } - - ty::Predicate::RegionOutlives(ref binder) => { - match self.selcx.infcx().region_outlives_predicate(&obligation.cause, binder) { - Ok(()) => ProcessResult::Changed(vec![]), - Err(_) => ProcessResult::Error(CodeSelectionError(Unimplemented)), - } - } - - ty::Predicate::TypeOutlives(ref binder) => { - // Check if there are higher-ranked vars. - match binder.no_bound_vars() { - // If there are, inspect the underlying type further. - None => { - // Convert from `Binder<OutlivesPredicate<Ty, Region>>` to `Binder<Ty>`. - let binder = binder.map_bound_ref(|pred| pred.0); - - // Check if the type has any bound vars. - match binder.no_bound_vars() { - // If so, this obligation is an error (for now). Eventually we should be - // able to support additional cases here, like `for<'a> &'a str: 'a`. - // NOTE: this is duplicate-implemented between here and fulfillment. - None => ProcessResult::Error(CodeSelectionError(Unimplemented)), - // Otherwise, we have something of the form - // `for<'a> T: 'a where 'a not in T`, which we can treat as - // `T: 'static`. - Some(t_a) => { - let r_static = self.selcx.tcx().lifetimes.re_static; - if self.register_region_obligations { - self.selcx.infcx().register_region_obligation_with_cause( - t_a, - r_static, - &obligation.cause, - ); - } - ProcessResult::Changed(vec![]) - } - } - } - // If there aren't, register the obligation. - Some(ty::OutlivesPredicate(t_a, r_b)) => { - if self.register_region_obligations { - self.selcx.infcx().register_region_obligation_with_cause( - t_a, - r_b, - &obligation.cause, - ); - } - ProcessResult::Changed(vec![]) - } - } - } - - ty::Predicate::Projection(ref data) => { - let project_obligation = obligation.with(data.clone()); - match project::poly_project_and_unify_type(self.selcx, &project_obligation) { - Ok(None) => { - let tcx = self.selcx.tcx(); - pending_obligation.stalled_on = - trait_ref_type_vars(self.selcx, data.to_poly_trait_ref(tcx)); - ProcessResult::Unchanged - } - Ok(Some(os)) => ProcessResult::Changed(mk_pending(os)), - Err(e) => ProcessResult::Error(CodeProjectionError(e)), - } - } - - ty::Predicate::ObjectSafe(trait_def_id) => { - if !self.selcx.tcx().is_object_safe(trait_def_id) { - ProcessResult::Error(CodeSelectionError(Unimplemented)) - } else { - ProcessResult::Changed(vec![]) - } - } - - ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => { - match self.selcx.infcx().closure_kind(closure_def_id, closure_substs) { - Some(closure_kind) => { - if closure_kind.extends(kind) { - ProcessResult::Changed(vec![]) - } else { - ProcessResult::Error(CodeSelectionError(Unimplemented)) - } - } - None => ProcessResult::Unchanged, - } - } - - ty::Predicate::WellFormed(ty) => { - match wf::obligations( - self.selcx.infcx(), - obligation.param_env, - obligation.cause.body_id, - ty, - obligation.cause.span, - ) { - None => { - pending_obligation.stalled_on = vec![infer_ty(ty)]; - ProcessResult::Unchanged - } - Some(os) => ProcessResult::Changed(mk_pending(os)), - } - } - - ty::Predicate::Subtype(ref subtype) => { - match self.selcx.infcx().subtype_predicate( - &obligation.cause, - obligation.param_env, - subtype, - ) { - None => { - // None means that both are unresolved. - pending_obligation.stalled_on = vec![ - infer_ty(subtype.skip_binder().a), - infer_ty(subtype.skip_binder().b), - ]; - ProcessResult::Unchanged - } - Some(Ok(ok)) => ProcessResult::Changed(mk_pending(ok.obligations)), - Some(Err(err)) => { - let expected_found = ExpectedFound::new( - subtype.skip_binder().a_is_expected, - subtype.skip_binder().a, - subtype.skip_binder().b, - ); - ProcessResult::Error(FulfillmentErrorCode::CodeSubtypeError( - expected_found, - err, - )) - } - } - } - - ty::Predicate::ConstEvaluatable(def_id, substs) => { - if obligation.param_env.has_local_value() { - ProcessResult::Unchanged - } else { - if !substs.has_local_value() { - match self.selcx.tcx().const_eval_resolve( - obligation.param_env, - def_id, - substs, - None, - Some(obligation.cause.span), - ) { - Ok(_) => ProcessResult::Changed(vec![]), - Err(err) => { - ProcessResult::Error(CodeSelectionError(ConstEvalFailure(err))) - } - } - } else { - pending_obligation.stalled_on = - substs.types().map(|ty| infer_ty(ty)).collect(); - ProcessResult::Unchanged - } - } - } - } - } - - fn process_backedge<'c, I>( - &mut self, - cycle: I, - _marker: PhantomData<&'c PendingPredicateObligation<'tcx>>, - ) where - I: Clone + Iterator<Item = &'c PendingPredicateObligation<'tcx>>, - { - if self.selcx.coinductive_match(cycle.clone().map(|s| s.obligation.predicate)) { - debug!("process_child_obligations: coinductive match"); - } else { - let cycle: Vec<_> = cycle.map(|c| c.obligation.clone()).collect(); - self.selcx.infcx().report_overflow_error_cycle(&cycle); - } - } -} - -/// Returns the set of type variables contained in a trait ref -fn trait_ref_type_vars<'a, 'tcx>( - selcx: &mut SelectionContext<'a, 'tcx>, - t: ty::PolyTraitRef<'tcx>, -) -> Vec<ty::InferTy> { - t.skip_binder() // ok b/c this check doesn't care about regions - .input_types() - .map(|t| selcx.infcx().resolve_vars_if_possible(&t)) - .filter(|t| t.has_infer_types()) - .flat_map(|t| t.walk()) - .filter_map(|t| match t.kind { - ty::Infer(infer) => Some(infer), - _ => None, - }) - .collect() -} - -fn to_fulfillment_error<'tcx>( - error: Error<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>>, -) -> FulfillmentError<'tcx> { - let obligation = error.backtrace.into_iter().next().unwrap().obligation; - FulfillmentError::new(obligation, error.error) -} diff --git a/src/librustc/traits/misc.rs b/src/librustc/traits/misc.rs deleted file mode 100644 index 3fd0d12c626..00000000000 --- a/src/librustc/traits/misc.rs +++ /dev/null @@ -1,70 +0,0 @@ -//! Miscellaneous type-system utilities that are too small to deserve their own modules. - -use crate::traits::{self, ObligationCause}; -use crate::ty::{self, Ty, TyCtxt, TypeFoldable}; - -use rustc_hir as hir; - -#[derive(Clone)] -pub enum CopyImplementationError<'tcx> { - InfrigingFields(Vec<&'tcx ty::FieldDef>), - NotAnAdt, - HasDestructor, -} - -pub fn can_type_implement_copy( - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - self_type: Ty<'tcx>, -) -> Result<(), CopyImplementationError<'tcx>> { - // FIXME: (@jroesch) float this code up - tcx.infer_ctxt().enter(|infcx| { - let (adt, substs) = match self_type.kind { - // These types used to have a builtin impl. - // Now libcore provides that impl. - ty::Uint(_) - | ty::Int(_) - | ty::Bool - | ty::Float(_) - | ty::Char - | ty::RawPtr(..) - | ty::Never - | ty::Ref(_, _, hir::Mutability::Not) => return Ok(()), - - ty::Adt(adt, substs) => (adt, substs), - - _ => return Err(CopyImplementationError::NotAnAdt), - }; - - let mut infringing = Vec::new(); - for variant in &adt.variants { - for field in &variant.fields { - let ty = field.ty(tcx, substs); - if ty.references_error() { - continue; - } - let span = tcx.def_span(field.did); - let cause = ObligationCause { span, ..ObligationCause::dummy() }; - let ctx = traits::FulfillmentContext::new(); - match traits::fully_normalize(&infcx, ctx, cause, param_env, &ty) { - Ok(ty) => { - if !infcx.type_is_copy_modulo_regions(param_env, ty, span) { - infringing.push(field); - } - } - Err(errors) => { - infcx.report_fulfillment_errors(&errors, None, false); - } - }; - } - } - if !infringing.is_empty() { - return Err(CopyImplementationError::InfrigingFields(infringing)); - } - if adt.has_dtor(tcx) { - return Err(CopyImplementationError::HasDestructor); - } - - Ok(()) - }) -} diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 556e69b04f8..c000aa7c25e 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -2,644 +2,738 @@ //! //! [rustc guide]: https://rust-lang.github.io/rustc-guide/traits/resolution.html -#[allow(dead_code)] -pub mod auto_trait; -mod chalk_fulfill; -pub mod codegen; -mod coherence; -mod engine; -pub mod error_reporting; -mod fulfill; -pub mod misc; -mod object_safety; -mod on_unimplemented; -mod project; pub mod query; -mod select; -mod specialize; +pub mod select; +pub mod specialization_graph; 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::ty::error::{ExpectedFound, TypeError}; -use crate::ty::fold::TypeFoldable; -use crate::ty::subst::{InternalSubsts, SubstsRef}; -use crate::ty::{self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, WithConstness}; -use crate::util::common::ErrorReported; + +use crate::infer::canonical::Canonical; +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 type ChalkCanonicalGoal<'tcx> = Canonical<'tcx, InEnvironment<'tcx, ty::Predicate<'tcx>>>; + +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>, +} -pub use self::FulfillmentErrorCode::*; - -pub use self::coherence::{add_placeholder_note, orphan_check, overlapping_impls}; -pub use self::coherence::{OrphanCheckErr, OverlapResult}; -pub use self::engine::{TraitEngine, TraitEngineExt}; -pub use self::fulfill::{FulfillmentContext, PendingPredicateObligation}; -pub use self::object_safety::astconv_object_safety_violations; -pub use self::object_safety::is_vtable_safe_method; -pub use self::object_safety::object_safety_violations; -pub use self::object_safety::MethodViolationCode; -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, normalize_to, poly_project_and_unify_type, -}; -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; -pub use self::specialize::{specialization_graph, translate_substs, OverlapError}; -pub use self::structural_match::search_for_structural_match_violation; -pub use self::structural_match::type_marked_structural; -pub use self::structural_match::NonStructuralMatchTy; -pub use self::util::{elaborate_predicates, elaborate_trait_ref, elaborate_trait_refs}; -pub use self::util::{expand_trait_aliases, TraitAliasExpander}; -pub use self::util::{ - get_vtable_index_of_object_method, impl_is_default, impl_item_is_final, - predicate_for_trait_def, upcast_choices, -}; -pub use self::util::{ - supertrait_def_ids, supertraits, transitive_bounds, SupertraitDefIds, Supertraits, -}; - -pub use self::chalk_fulfill::{ - CanonicalGoal as ChalkCanonicalGoal, FulfillmentContext as ChalkFulfillmentContext, -}; - -pub use self::types::*; - -/// Whether to skip the leak check, as part of a future compatibility warning step. -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub enum SkipLeakCheck { - Yes, - No, -} - -impl SkipLeakCheck { - fn is_yes(self) -> bool { - self == SkipLeakCheck::Yes +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>), } -/// The "default" for skip-leak-check corresponds to the current -/// behavior (do not skip the leak check) -- not the behavior we are -/// transitioning into. -impl Default for SkipLeakCheck { - fn default() -> Self { - SkipLeakCheck::No +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 } } -/// The mode that trait queries run in. -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub enum TraitQueryMode { - // Standard/un-canonicalized queries get accurate - // spans etc. passed in and hence can do reasonable - // error reporting on their own. - Standard, - // Canonicalized queries get dummy spans and hence - // must generally propagate errors to - // pre-canonicalization callsites. - Canonical, -} - -/// An `Obligation` represents some trait reference (e.g., `int: Eq`) for -/// which the vtable must be found. The process of finding a vtable is -/// called "resolving" the `Obligation`. This process consists of -/// either identifying an `impl` (e.g., `impl Eq for int`) that -/// provides the required vtable, or else finding a bound that is in -/// scope. The eventual result is usually a `Selection` (defined below). -#[derive(Clone, PartialEq, Eq, Hash)] -pub struct Obligation<'tcx, T> { - /// The reason we have to prove this thing. - pub cause: ObligationCause<'tcx>, - - /// The environment in which we should prove this thing. - pub param_env: ty::ParamEnv<'tcx>, - - /// The thing we are trying to prove. - pub predicate: T, - - /// If we started proving this as a result of trying to prove - /// something else, track the total depth to ensure termination. - /// If this goes over a certain threshold, we abort compilation -- - /// in such cases, we can not say whether or not the predicate - /// holds for certain. Stupid halting problem; such a drag. - pub recursion_depth: usize, -} - -pub type PredicateObligation<'tcx> = Obligation<'tcx, ty::Predicate<'tcx>>; -pub type TraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitPredicate<'tcx>>; - -// `PredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger. +#[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!(PredicateObligation<'_>, 112); - -pub type Obligations<'tcx, O> = Vec<Obligation<'tcx, O>>; -pub type PredicateObligations<'tcx> = Vec<PredicateObligation<'tcx>>; -pub type TraitObligations<'tcx> = Vec<TraitObligation<'tcx>>; - -pub type Selection<'tcx> = Vtable<'tcx, PredicateObligation<'tcx>>; - -pub struct FulfillmentError<'tcx> { - pub obligation: PredicateObligation<'tcx>, - pub code: FulfillmentErrorCode<'tcx>, - /// Diagnostics only: we opportunistically change the `code.span` when we encounter an - /// obligation error caused by a call argument. When this is the case, we also signal that in - /// this field to ensure accuracy of suggestions. - pub points_at_arg_span: bool, -} - -#[derive(Clone)] -pub enum FulfillmentErrorCode<'tcx> { - CodeSelectionError(SelectionError<'tcx>), - CodeProjectionError(MismatchedProjectionTypes<'tcx>), - CodeSubtypeError(ExpectedFound<Ty<'tcx>>, TypeError<'tcx>), // always comes from a SubtypePredicate - CodeAmbiguity, -} - -/// Creates predicate obligations from the generic bounds. -pub fn predicates_for_generics<'tcx>( - cause: ObligationCause<'tcx>, - param_env: ty::ParamEnv<'tcx>, - generic_bounds: &ty::InstantiatedPredicates<'tcx>, -) -> PredicateObligations<'tcx> { - util::predicates_for_generics(cause, 0, param_env, generic_bounds) -} - -/// Determines whether the type `ty` is known to meet `bound` and -/// returns true if so. Returns false if `ty` either does not meet -/// `bound` or is not known to meet bound (note that this is -/// conservative towards *no impl*, which is the opposite of the -/// `evaluate` methods). -pub fn type_known_to_meet_bound_modulo_regions<'a, 'tcx>( - infcx: &InferCtxt<'a, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - ty: Ty<'tcx>, - def_id: DefId, - span: Span, -) -> bool { - debug!( - "type_known_to_meet_bound_modulo_regions(ty={:?}, bound={:?})", - ty, - infcx.tcx.def_path_str(def_id) - ); - - let trait_ref = ty::TraitRef { def_id, substs: infcx.tcx.mk_substs_trait(ty, &[]) }; - let obligation = Obligation { - param_env, - cause: ObligationCause::misc(span, hir::DUMMY_HIR_ID), - recursion_depth: 0, - predicate: trait_ref.without_const().to_predicate(), - }; - - let result = infcx.predicate_must_hold_modulo_regions(&obligation); - debug!( - "type_known_to_meet_ty={:?} bound={} => {:?}", - ty, - infcx.tcx.def_path_str(def_id), - result - ); - - if result && (ty.has_infer_types() || ty.has_closure_types()) { - // Because of inference "guessing", selection can sometimes claim - // to succeed while the success requires a guess. To ensure - // this function's result remains infallible, we must confirm - // that guess. While imperfect, I believe this is sound. - - // The handling of regions in this area of the code is terrible, - // see issue #29149. We should be able to improve on this with - // NLL. - let mut fulfill_cx = FulfillmentContext::new_ignoring_regions(); - - // We can use a dummy node-id here because we won't pay any mind - // to region obligations that arise (there shouldn't really be any - // anyhow). - let cause = ObligationCause::misc(span, hir::DUMMY_HIR_ID); - - fulfill_cx.register_bound(infcx, param_env, ty, def_id, cause); - - // Note: we only assume something is `Copy` if we can - // *definitively* show that it implements `Copy`. Otherwise, - // assume it is move; linear is always ok. - match fulfill_cx.select_all_or_error(infcx) { - Ok(()) => { - debug!( - "type_known_to_meet_bound_modulo_regions: ty={:?} bound={} success", - ty, - infcx.tcx.def_path_str(def_id) - ); - true - } - Err(e) => { - debug!( - "type_known_to_meet_bound_modulo_regions: ty={:?} bound={} errors={:?}", - ty, - infcx.tcx.def_path_str(def_id), - e - ); - false - } +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, } - } else { - result } } -fn do_normalize_predicates<'tcx>( - tcx: TyCtxt<'tcx>, - region_context: DefId, - cause: ObligationCause<'tcx>, - elaborated_env: ty::ParamEnv<'tcx>, - predicates: Vec<ty::Predicate<'tcx>>, -) -> Result<Vec<ty::Predicate<'tcx>>, ErrorReported> { - debug!( - "do_normalize_predicates(predicates={:?}, region_context={:?}, cause={:?})", - predicates, region_context, cause, - ); - let span = cause.span; - tcx.infer_ctxt().enter(|infcx| { - // FIXME. We should really... do something with these region - // obligations. But this call just continues the older - // behavior (i.e., doesn't cause any new bugs), and it would - // take some further refactoring to actually solve them. In - // particular, we would have to handle implied bounds - // properly, and that code is currently largely confined to - // regionck (though I made some efforts to extract it - // out). -nmatsakis - // - // @arielby: In any case, these obligations are checked - // by wfcheck anyway, so I'm not sure we have to check - // them here too, and we will remove this function when - // we move over to lazy normalization *anyway*. - let fulfill_cx = FulfillmentContext::new_ignoring_regions(); - let predicates = - match fully_normalize(&infcx, fulfill_cx, cause, elaborated_env, &predicates) { - Ok(predicates) => predicates, - Err(errors) => { - infcx.report_fulfillment_errors(&errors, None, false); - return Err(ErrorReported); - } - }; - - debug!("do_normalize_predictes: normalized predicates = {:?}", predicates); - - let region_scope_tree = region::ScopeTree::default(); - - // We can use the `elaborated_env` here; the region code only - // cares about declarations like `'a: 'b`. - let outlives_env = OutlivesEnvironment::new(elaborated_env); - - infcx.resolve_regions_and_report_errors( - region_context, - ®ion_scope_tree, - &outlives_env, - SuppressRegionErrors::default(), - ); - - let predicates = match infcx.fully_resolve(&predicates) { - Ok(predicates) => predicates, - Err(fixup_err) => { - // If we encounter a fixup error, it means that some type - // variable wound up unconstrained. I actually don't know - // if this can happen, and I certainly don't expect it to - // happen often, but if it did happen it probably - // represents a legitimate failure due to some kind of - // unconstrained variable, and it seems better not to ICE, - // all things considered. - tcx.sess.span_err(span, &fixup_err.to_string()); - return Err(ErrorReported); - } - }; - if predicates.has_local_value() { - // FIXME: shouldn't we, you know, actually report an error here? or an ICE? - Err(ErrorReported) - } else { - Ok(predicates) - } - }) -} - -// FIXME: this is gonna need to be removed ... -/// Normalizes the parameter environment, reporting errors if they occur. -pub fn normalize_param_env_or_error<'tcx>( - tcx: TyCtxt<'tcx>, - region_context: DefId, - unnormalized_env: ty::ParamEnv<'tcx>, - cause: ObligationCause<'tcx>, -) -> ty::ParamEnv<'tcx> { - // I'm not wild about reporting errors here; I'd prefer to - // have the errors get reported at a defined place (e.g., - // during typeck). Instead I have all parameter - // environments, in effect, going through this function - // and hence potentially reporting errors. This ensures of - // course that we never forget to normalize (the - // alternative seemed like it would involve a lot of - // manual invocations of this fn -- and then we'd have to - // deal with the errors at each of those sites). - // - // In any case, in practice, typeck constructs all the - // parameter environments once for every fn as it goes, - // and errors will get reported then; so after typeck we - // can be sure that no errors should occur. - - debug!( - "normalize_param_env_or_error(region_context={:?}, unnormalized_env={:?}, cause={:?})", - region_context, unnormalized_env, cause - ); - - let mut predicates: Vec<_> = - util::elaborate_predicates(tcx, unnormalized_env.caller_bounds.to_vec()).collect(); - - debug!("normalize_param_env_or_error: elaborated-predicates={:?}", predicates); - - let elaborated_env = ty::ParamEnv::new( - tcx.intern_predicates(&predicates), - unnormalized_env.reveal, - unnormalized_env.def_id, - ); - - // HACK: we are trying to normalize the param-env inside *itself*. The problem is that - // normalization expects its param-env to be already normalized, which means we have - // a circularity. - // - // The way we handle this is by normalizing the param-env inside an unnormalized version - // of the param-env, which means that if the param-env contains unnormalized projections, - // we'll have some normalization failures. This is unfortunate. - // - // Lazy normalization would basically handle this by treating just the - // normalizing-a-trait-ref-requires-itself cycles as evaluation failures. - // - // Inferred outlives bounds can create a lot of `TypeOutlives` predicates for associated - // types, so to make the situation less bad, we normalize all the predicates *but* - // the `TypeOutlives` predicates first inside the unnormalized parameter environment, and - // then we normalize the `TypeOutlives` bounds inside the normalized parameter environment. - // - // This works fairly well because trait matching does not actually care about param-env - // TypeOutlives predicates - these are normally used by regionck. - let outlives_predicates: Vec<_> = predicates - .drain_filter(|predicate| match predicate { - ty::Predicate::TypeOutlives(..) => true, - _ => false, - }) - .collect(); - - debug!( - "normalize_param_env_or_error: predicates=(non-outlives={:?}, outlives={:?})", - predicates, outlives_predicates - ); - let non_outlives_predicates = match do_normalize_predicates( - tcx, - region_context, - cause.clone(), - elaborated_env, - predicates, - ) { - Ok(predicates) => predicates, - // An unnormalized env is better than nothing. - Err(ErrorReported) => { - debug!("normalize_param_env_or_error: errored resolving non-outlives predicates"); - return elaborated_env; +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())), + ), } - }; - - debug!("normalize_param_env_or_error: non-outlives predicates={:?}", non_outlives_predicates); - - // Not sure whether it is better to include the unnormalized TypeOutlives predicates - // here. I believe they should not matter, because we are ignoring TypeOutlives param-env - // predicates here anyway. Keeping them here anyway because it seems safer. - let outlives_env: Vec<_> = - non_outlives_predicates.iter().chain(&outlives_predicates).cloned().collect(); - let outlives_env = - ty::ParamEnv::new(tcx.intern_predicates(&outlives_env), unnormalized_env.reveal, None); - let outlives_predicates = match do_normalize_predicates( - tcx, - region_context, - cause, - outlives_env, - outlives_predicates, - ) { - Ok(predicates) => predicates, - // An unnormalized env is better than nothing. - Err(ErrorReported) => { - debug!("normalize_param_env_or_error: errored resolving outlives predicates"); - return elaborated_env; - } - }; - debug!("normalize_param_env_or_error: outlives predicates={:?}", outlives_predicates); - - let mut predicates = non_outlives_predicates; - predicates.extend(outlives_predicates); - debug!("normalize_param_env_or_error: final predicates={:?}", predicates); - ty::ParamEnv::new( - tcx.intern_predicates(&predicates), - unnormalized_env.reveal, - unnormalized_env.def_id, - ) -} - -pub fn fully_normalize<'a, 'tcx, T>( - infcx: &InferCtxt<'a, 'tcx>, - mut fulfill_cx: FulfillmentContext<'tcx>, - cause: ObligationCause<'tcx>, - param_env: ty::ParamEnv<'tcx>, - value: &T, -) -> Result<T, Vec<FulfillmentError<'tcx>>> -where - T: TypeFoldable<'tcx>, -{ - debug!("fully_normalize_with_fulfillcx(value={:?})", value); - let selcx = &mut SelectionContext::new(infcx); - let Normalized { value: normalized_value, obligations } = - project::normalize(selcx, param_env, cause, value); - debug!( - "fully_normalize: normalized_value={:?} obligations={:?}", - normalized_value, obligations - ); - for obligation in obligations { - fulfill_cx.register_predicate_obligation(selcx.infcx(), obligation); } +} - debug!("fully_normalize: select_all_or_error start"); - fulfill_cx.select_all_or_error(infcx)?; - debug!("fully_normalize: select_all_or_error complete"); - let resolved_value = infcx.resolve_vars_if_possible(&normalized_value); - debug!("fully_normalize: resolved_value={:?}", resolved_value); - Ok(resolved_value) -} - -/// Normalizes the predicates and checks whether they hold in an empty -/// environment. If this returns false, then either normalize -/// encountered an error or one of the predicates did not hold. Used -/// when creating vtables to check for unsatisfiable methods. -pub fn normalize_and_test_predicates<'tcx>( - tcx: TyCtxt<'tcx>, - predicates: Vec<ty::Predicate<'tcx>>, -) -> bool { - debug!("normalize_and_test_predicates(predicates={:?})", predicates); - - let result = tcx.infer_ctxt().enter(|infcx| { - let param_env = ty::ParamEnv::reveal_all(); - let mut selcx = SelectionContext::new(&infcx); - let mut fulfill_cx = FulfillmentContext::new(); - let cause = ObligationCause::dummy(); - let Normalized { value: predicates, obligations } = - normalize(&mut selcx, param_env, cause.clone(), &predicates); - for obligation in obligations { - fulfill_cx.register_predicate_obligation(&infcx, obligation); - } - for predicate in predicates { - let obligation = Obligation::new(cause.clone(), param_env, predicate); - fulfill_cx.register_predicate_obligation(&infcx, obligation); +/// 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, } + } +} - fulfill_cx.select_all_or_error(&infcx).is_ok() - }); - debug!("normalize_and_test_predicates(predicates={:?}) = {:?}", predicates, result); - result -} - -fn substitute_normalize_and_test_predicates<'tcx>( - tcx: TyCtxt<'tcx>, - key: (DefId, SubstsRef<'tcx>), -) -> bool { - debug!("substitute_normalize_and_test_predicates(key={:?})", key); - - let predicates = tcx.predicates_of(key.0).instantiate(tcx, key.1).predicates; - let result = normalize_and_test_predicates(tcx, predicates); - - debug!("substitute_normalize_and_test_predicates(key={:?}) = {:?}", key, result); - result -} - -/// Given a trait `trait_ref`, iterates the vtable entries -/// that come from `trait_ref`, including its supertraits. -#[inline] // FIXME(#35870): avoid closures being unexported due to `impl Trait`. -fn vtable_methods<'tcx>( - tcx: TyCtxt<'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>, -) -> &'tcx [Option<(DefId, SubstsRef<'tcx>)>] { - debug!("vtable_methods({:?})", trait_ref); - - tcx.arena.alloc_from_iter(supertraits(tcx, trait_ref).flat_map(move |trait_ref| { - let trait_methods = tcx - .associated_items(trait_ref.def_id()) - .iter() - .filter(|item| item.kind == ty::AssocKind::Method); - - // Now list each method's DefId and InternalSubsts (for within its trait). - // If the method can never be called from this object, produce None. - trait_methods.map(move |trait_method| { - debug!("vtable_methods: trait_method={:?}", trait_method); - let def_id = trait_method.def_id; - - // Some methods cannot be called on an object; skip those. - if !is_vtable_safe_method(tcx, trait_ref.def_id(), &trait_method) { - debug!("vtable_methods: not vtable safe"); - return None; - } +/// 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, +} - // The method may have some early-bound lifetimes; add regions for those. - let substs = trait_ref.map_bound(|trait_ref| { - InternalSubsts::for_item(tcx, def_id, |param, _| match param.kind { - GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(), - GenericParamDefKind::Type { .. } | GenericParamDefKind::Const => { - trait_ref.substs[param.index as usize] - } - }) - }); - - // The trait type may have higher-ranked lifetimes in it; - // erase them if they appear, so that we get the type - // at some particular call site. - let substs = - tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &substs); - - // It's possible that the method relies on where-clauses that - // do not hold for this particular set of type parameters. - // Note that this method could then never be called, so we - // do not want to try and codegen it, in that case (see #23435). - let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs); - if !normalize_and_test_predicates(tcx, predicates.predicates) { - debug!("vtable_methods: predicates do not hold"); - return None; - } +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable)] +pub enum ProgramClauseCategory { + ImpliedBound, + WellFormed, + Other, +} - Some((def_id, substs)) - }) - })) +/// 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<'tcx, O> Obligation<'tcx, O> { - pub fn new( - cause: ObligationCause<'tcx>, - param_env: ty::ParamEnv<'tcx>, - predicate: O, - ) -> Obligation<'tcx, O> { - Obligation { cause, param_env, recursion_depth: 0, predicate } +impl Environment<'tcx> { + pub fn with<G>(self, goal: G) -> InEnvironment<'tcx, G> { + InEnvironment { environment: self, goal } } +} - fn with_depth( - cause: ObligationCause<'tcx>, - recursion_depth: usize, - param_env: ty::ParamEnv<'tcx>, - predicate: O, - ) -> Obligation<'tcx, O> { - Obligation { cause, param_env, recursion_depth, predicate } - } +/// 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 fn misc( - span: Span, - body_id: hir::HirId, - param_env: ty::ParamEnv<'tcx>, - trait_ref: O, - ) -> Obligation<'tcx, O> { - Obligation::new(ObligationCause::misc(span, body_id), param_env, trait_ref) +#[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 with<P>(&self, value: P) -> Obligation<'tcx, P> { - Obligation { - cause: self.cause.clone(), - param_env: self.param_env, - recursion_depth: self.recursion_depth, - predicate: value, + 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>, - code: FulfillmentErrorCode<'tcx>, - ) -> FulfillmentError<'tcx> { - FulfillmentError { obligation: obligation, code: code, points_at_arg_span: false } - } +/// 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>, } -impl<'tcx> TraitObligation<'tcx> { - fn self_ty(&self) -> ty::Binder<Ty<'tcx>> { - self.predicate.map_bound(|p| p.self_ty()) - } +#[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 fn provide(providers: &mut ty::query::Providers<'_>) { - *providers = ty::query::Providers { - is_object_safe: object_safety::is_object_safe_provider, - specialization_graph_of: specialize::specialization_graph_provider, - specializes: specialize::specializes, - codegen_fulfill_obligation: codegen::codegen_fulfill_obligation, - vtable_methods, - substitute_normalize_and_test_predicates, - ..*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>; } diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs deleted file mode 100644 index 4c5cd866b4a..00000000000 --- a/src/librustc/traits/object_safety.rs +++ /dev/null @@ -1,909 +0,0 @@ -//! "Object safety" refers to the ability for a trait to be converted -//! to an object. In general, traits may only be converted to an -//! object if all of their methods meet certain criteria. In particular, -//! they must: -//! -//! - have a suitable receiver from which we can extract a vtable and coerce to a "thin" version -//! that doesn't contain the vtable; -//! - not reference the erased type `Self` except for in this receiver; -//! - not have generic type parameters. - -use super::elaborate_predicates; - -use crate::traits::{self, Obligation, ObligationCause}; -use crate::ty::subst::{InternalSubsts, Subst}; -use crate::ty::{self, Predicate, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness}; -use rustc_errors::Applicability; -use rustc_hir as hir; -use rustc_hir::def_id::DefId; -use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY; -use rustc_span::symbol::Symbol; -use rustc_span::{Span, DUMMY_SP}; -use smallvec::{smallvec, SmallVec}; -use syntax::ast; - -use std::borrow::Cow; -use std::iter::{self}; - -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub enum ObjectSafetyViolation { - /// `Self: Sized` declared on the trait. - SizedSelf(SmallVec<[Span; 1]>), - - /// Supertrait reference references `Self` an in illegal location - /// (e.g., `trait Foo : Bar<Self>`). - SupertraitSelf(SmallVec<[Span; 1]>), - - /// Method has something illegal. - Method(ast::Name, MethodViolationCode, Span), - - /// Associated const. - AssocConst(ast::Name, Span), -} - -impl ObjectSafetyViolation { - pub fn error_msg(&self) -> Cow<'static, str> { - match *self { - ObjectSafetyViolation::SizedSelf(_) => "it requires `Self: Sized`".into(), - ObjectSafetyViolation::SupertraitSelf(ref spans) => { - if spans.iter().any(|sp| *sp != DUMMY_SP) { - "it uses `Self` as a type parameter in this".into() - } else { - "it cannot use `Self` as a type parameter in a supertrait or `where`-clause" - .into() - } - } - ObjectSafetyViolation::Method(name, MethodViolationCode::StaticMethod(_), _) => { - format!("associated function `{}` has no `self` parameter", name).into() - } - ObjectSafetyViolation::Method( - name, - MethodViolationCode::ReferencesSelfInput(_), - DUMMY_SP, - ) => format!("method `{}` references the `Self` type in its parameters", name).into(), - ObjectSafetyViolation::Method(name, MethodViolationCode::ReferencesSelfInput(_), _) => { - format!("method `{}` references the `Self` type in this parameter", name).into() - } - ObjectSafetyViolation::Method(name, MethodViolationCode::ReferencesSelfOutput, _) => { - format!("method `{}` references the `Self` type in its return type", name).into() - } - ObjectSafetyViolation::Method( - name, - MethodViolationCode::WhereClauseReferencesSelf, - _, - ) => { - format!("method `{}` references the `Self` type in its `where` clause", name).into() - } - ObjectSafetyViolation::Method(name, MethodViolationCode::Generic, _) => { - format!("method `{}` has generic type parameters", name).into() - } - ObjectSafetyViolation::Method(name, MethodViolationCode::UndispatchableReceiver, _) => { - format!("method `{}`'s `self` parameter cannot be dispatched on", name).into() - } - ObjectSafetyViolation::AssocConst(name, DUMMY_SP) => { - format!("it contains associated `const` `{}`", name).into() - } - ObjectSafetyViolation::AssocConst(..) => "it contains this associated `const`".into(), - } - } - - pub fn solution(&self) -> Option<(String, Option<(String, Span)>)> { - Some(match *self { - ObjectSafetyViolation::SizedSelf(_) | ObjectSafetyViolation::SupertraitSelf(_) => { - return None; - } - ObjectSafetyViolation::Method(name, MethodViolationCode::StaticMethod(sugg), _) => ( - format!( - "consider turning `{}` into a method by giving it a `&self` argument or \ - constraining it so it does not apply to trait objects", - name - ), - sugg.map(|(sugg, sp)| (sugg.to_string(), sp)), - ), - ObjectSafetyViolation::Method( - name, - MethodViolationCode::UndispatchableReceiver, - span, - ) => ( - format!("consider changing method `{}`'s `self` parameter to be `&self`", name) - .into(), - Some(("&Self".to_string(), span)), - ), - ObjectSafetyViolation::AssocConst(name, _) - | ObjectSafetyViolation::Method(name, ..) => { - (format!("consider moving `{}` to another trait", name), None) - } - }) - } - - pub fn spans(&self) -> SmallVec<[Span; 1]> { - // When `span` comes from a separate crate, it'll be `DUMMY_SP`. Treat it as `None` so - // diagnostics use a `note` instead of a `span_label`. - match self { - ObjectSafetyViolation::SupertraitSelf(spans) - | ObjectSafetyViolation::SizedSelf(spans) => spans.clone(), - ObjectSafetyViolation::AssocConst(_, span) - | ObjectSafetyViolation::Method(_, _, span) - if *span != DUMMY_SP => - { - smallvec![*span] - } - _ => smallvec![], - } - } -} - -/// Reasons a method might not be object-safe. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -pub enum MethodViolationCode { - /// e.g., `fn foo()` - StaticMethod(Option<(&'static str, Span)>), - - /// e.g., `fn foo(&self, x: Self)` - ReferencesSelfInput(usize), - - /// e.g., `fn foo(&self) -> Self` - ReferencesSelfOutput, - - /// e.g., `fn foo(&self) where Self: Clone` - WhereClauseReferencesSelf, - - /// e.g., `fn foo<A>()` - Generic, - - /// the method's receiver (`self` argument) can't be dispatched on - UndispatchableReceiver, -} - -/// Returns the object safety violations that affect -/// astconv -- currently, `Self` in supertraits. This is needed -/// because `object_safety_violations` can't be used during -/// type collection. -pub fn astconv_object_safety_violations( - tcx: TyCtxt<'_>, - trait_def_id: DefId, -) -> Vec<ObjectSafetyViolation> { - debug_assert!(tcx.generics_of(trait_def_id).has_self); - let violations = traits::supertrait_def_ids(tcx, trait_def_id) - .map(|def_id| predicates_reference_self(tcx, def_id, true)) - .filter(|spans| !spans.is_empty()) - .map(|spans| ObjectSafetyViolation::SupertraitSelf(spans)) - .collect(); - - debug!("astconv_object_safety_violations(trait_def_id={:?}) = {:?}", trait_def_id, violations); - - violations -} - -pub fn object_safety_violations( - tcx: TyCtxt<'_>, - trait_def_id: DefId, -) -> Vec<ObjectSafetyViolation> { - debug_assert!(tcx.generics_of(trait_def_id).has_self); - debug!("object_safety_violations: {:?}", trait_def_id); - - traits::supertrait_def_ids(tcx, trait_def_id) - .flat_map(|def_id| object_safety_violations_for_trait(tcx, def_id)) - .collect() -} - -/// We say a method is *vtable safe* if it can be invoked on a trait -/// object. Note that object-safe traits can have some -/// non-vtable-safe methods, so long as they require `Self: Sized` or -/// otherwise ensure that they cannot be used when `Self = Trait`. -pub fn is_vtable_safe_method(tcx: TyCtxt<'_>, trait_def_id: DefId, method: &ty::AssocItem) -> bool { - debug_assert!(tcx.generics_of(trait_def_id).has_self); - debug!("is_vtable_safe_method({:?}, {:?})", trait_def_id, method); - // Any method that has a `Self: Sized` bound cannot be called. - if generics_require_sized_self(tcx, method.def_id) { - return false; - } - - match virtual_call_violation_for_method(tcx, trait_def_id, method) { - None | Some(MethodViolationCode::WhereClauseReferencesSelf) => true, - Some(_) => false, - } -} - -fn object_safety_violations_for_trait( - tcx: TyCtxt<'_>, - trait_def_id: DefId, -) -> Vec<ObjectSafetyViolation> { - // Check methods for violations. - let mut violations: Vec<_> = tcx - .associated_items(trait_def_id) - .iter() - .filter(|item| item.kind == ty::AssocKind::Method) - .filter_map(|item| { - object_safety_violation_for_method(tcx, trait_def_id, &item) - .map(|(code, span)| ObjectSafetyViolation::Method(item.ident.name, code, span)) - }) - .filter(|violation| { - if let ObjectSafetyViolation::Method( - _, - MethodViolationCode::WhereClauseReferencesSelf, - span, - ) = violation - { - // Using `CRATE_NODE_ID` is wrong, but it's hard to get a more precise id. - // It's also hard to get a use site span, so we use the method definition span. - tcx.struct_span_lint_hir( - WHERE_CLAUSES_OBJECT_SAFETY, - hir::CRATE_HIR_ID, - *span, - |lint| { - let mut err = lint.build(&format!( - "the trait `{}` cannot be made into an object", - tcx.def_path_str(trait_def_id) - )); - let node = tcx.hir().get_if_local(trait_def_id); - let msg = if let Some(hir::Node::Item(item)) = node { - err.span_label( - item.ident.span, - "this trait cannot be made into an object...", - ); - format!("...because {}", violation.error_msg()) - } else { - format!( - "the trait cannot be made into an object because {}", - violation.error_msg() - ) - }; - err.span_label(*span, &msg); - match (node, violation.solution()) { - (Some(_), Some((note, None))) => { - err.help(¬e); - } - (Some(_), Some((note, Some((sugg, span))))) => { - err.span_suggestion( - span, - ¬e, - sugg, - Applicability::MachineApplicable, - ); - } - // Only provide the help if its a local trait, otherwise it's not actionable. - _ => {} - } - err.emit(); - }, - ); - false - } else { - true - } - }) - .collect(); - - // Check the trait itself. - if trait_has_sized_self(tcx, trait_def_id) { - // We don't want to include the requirement from `Sized` itself to be `Sized` in the list. - let spans = get_sized_bounds(tcx, trait_def_id); - violations.push(ObjectSafetyViolation::SizedSelf(spans)); - } - let spans = predicates_reference_self(tcx, trait_def_id, false); - if !spans.is_empty() { - violations.push(ObjectSafetyViolation::SupertraitSelf(spans)); - } - - violations.extend( - tcx.associated_items(trait_def_id) - .iter() - .filter(|item| item.kind == ty::AssocKind::Const) - .map(|item| ObjectSafetyViolation::AssocConst(item.ident.name, item.ident.span)), - ); - - debug!( - "object_safety_violations_for_trait(trait_def_id={:?}) = {:?}", - trait_def_id, violations - ); - - violations -} - -fn get_sized_bounds(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span; 1]> { - tcx.hir() - .get_if_local(trait_def_id) - .and_then(|node| match node { - hir::Node::Item(hir::Item { - kind: hir::ItemKind::Trait(.., generics, bounds, _), - .. - }) => Some( - generics - .where_clause - .predicates - .iter() - .filter_map(|pred| { - match pred { - hir::WherePredicate::BoundPredicate(pred) - if pred.bounded_ty.hir_id.owner_def_id() == trait_def_id => - { - // Fetch spans for trait bounds that are Sized: - // `trait T where Self: Pred` - Some(pred.bounds.iter().filter_map(|b| match b { - hir::GenericBound::Trait( - trait_ref, - hir::TraitBoundModifier::None, - ) if trait_has_sized_self( - tcx, - trait_ref.trait_ref.trait_def_id(), - ) => - { - Some(trait_ref.span) - } - _ => None, - })) - } - _ => None, - } - }) - .flatten() - .chain(bounds.iter().filter_map(|b| match b { - hir::GenericBound::Trait(trait_ref, hir::TraitBoundModifier::None) - if trait_has_sized_self(tcx, trait_ref.trait_ref.trait_def_id()) => - { - // Fetch spans for supertraits that are `Sized`: `trait T: Super` - Some(trait_ref.span) - } - _ => None, - })) - .collect::<SmallVec<[Span; 1]>>(), - ), - _ => None, - }) - .unwrap_or_else(SmallVec::new) -} - -fn predicates_reference_self( - tcx: TyCtxt<'_>, - trait_def_id: DefId, - supertraits_only: bool, -) -> SmallVec<[Span; 1]> { - let trait_ref = ty::Binder::dummy(ty::TraitRef::identity(tcx, trait_def_id)); - let predicates = if supertraits_only { - tcx.super_predicates_of(trait_def_id) - } else { - tcx.predicates_of(trait_def_id) - }; - let self_ty = tcx.types.self_param; - let has_self_ty = |t: Ty<'_>| t.walk().any(|t| t == self_ty); - predicates - .predicates - .iter() - .map(|(predicate, sp)| (predicate.subst_supertrait(tcx, &trait_ref), sp)) - .filter_map(|(predicate, &sp)| { - match predicate { - ty::Predicate::Trait(ref data, _) => { - // In the case of a trait predicate, we can skip the "self" type. - if data.skip_binder().input_types().skip(1).any(has_self_ty) { - Some(sp) - } else { - None - } - } - ty::Predicate::Projection(ref data) => { - // And similarly for projections. This should be redundant with - // the previous check because any projection should have a - // matching `Trait` predicate with the same inputs, but we do - // the check to be safe. - // - // Note that we *do* allow projection *outputs* to contain - // `self` (i.e., `trait Foo: Bar<Output=Self::Result> { type Result; }`), - // we just require the user to specify *both* outputs - // in the object type (i.e., `dyn Foo<Output=(), Result=()>`). - // - // This is ALT2 in issue #56288, see that for discussion of the - // possible alternatives. - if data - .skip_binder() - .projection_ty - .trait_ref(tcx) - .input_types() - .skip(1) - .any(has_self_ty) - { - Some(sp) - } else { - None - } - } - ty::Predicate::WellFormed(..) - | ty::Predicate::ObjectSafe(..) - | ty::Predicate::TypeOutlives(..) - | ty::Predicate::RegionOutlives(..) - | ty::Predicate::ClosureKind(..) - | ty::Predicate::Subtype(..) - | ty::Predicate::ConstEvaluatable(..) => None, - } - }) - .collect() -} - -fn trait_has_sized_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool { - generics_require_sized_self(tcx, trait_def_id) -} - -fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool { - let sized_def_id = match tcx.lang_items().sized_trait() { - Some(def_id) => def_id, - None => { - return false; /* No Sized trait, can't require it! */ - } - }; - - // Search for a predicate like `Self : Sized` amongst the trait bounds. - let predicates = tcx.predicates_of(def_id); - let predicates = predicates.instantiate_identity(tcx).predicates; - elaborate_predicates(tcx, predicates).any(|predicate| match predicate { - ty::Predicate::Trait(ref trait_pred, _) => { - trait_pred.def_id() == sized_def_id && trait_pred.skip_binder().self_ty().is_param(0) - } - ty::Predicate::Projection(..) - | ty::Predicate::Subtype(..) - | ty::Predicate::RegionOutlives(..) - | ty::Predicate::WellFormed(..) - | ty::Predicate::ObjectSafe(..) - | ty::Predicate::ClosureKind(..) - | ty::Predicate::TypeOutlives(..) - | ty::Predicate::ConstEvaluatable(..) => false, - }) -} - -/// Returns `Some(_)` if this method makes the containing trait not object safe. -fn object_safety_violation_for_method( - tcx: TyCtxt<'_>, - trait_def_id: DefId, - method: &ty::AssocItem, -) -> Option<(MethodViolationCode, Span)> { - debug!("object_safety_violation_for_method({:?}, {:?})", trait_def_id, method); - // Any method that has a `Self : Sized` requisite is otherwise - // exempt from the regulations. - if generics_require_sized_self(tcx, method.def_id) { - return None; - } - - let violation = virtual_call_violation_for_method(tcx, trait_def_id, method); - // Get an accurate span depending on the violation. - violation.map(|v| { - let node = tcx.hir().get_if_local(method.def_id); - let span = match (v, node) { - (MethodViolationCode::ReferencesSelfInput(arg), Some(node)) => node - .fn_decl() - .and_then(|decl| decl.inputs.get(arg + 1)) - .map_or(method.ident.span, |arg| arg.span), - (MethodViolationCode::UndispatchableReceiver, Some(node)) => node - .fn_decl() - .and_then(|decl| decl.inputs.get(0)) - .map_or(method.ident.span, |arg| arg.span), - (MethodViolationCode::ReferencesSelfOutput, Some(node)) => { - node.fn_decl().map_or(method.ident.span, |decl| decl.output.span()) - } - _ => method.ident.span, - }; - (v, span) - }) -} - -/// Returns `Some(_)` if this method cannot be called on a trait -/// object; this does not necessarily imply that the enclosing trait -/// is not object safe, because the method might have a where clause -/// `Self:Sized`. -fn virtual_call_violation_for_method<'tcx>( - tcx: TyCtxt<'tcx>, - trait_def_id: DefId, - method: &ty::AssocItem, -) -> Option<MethodViolationCode> { - // The method's first parameter must be named `self` - if !method.method_has_self_argument { - // We'll attempt to provide a structured suggestion for `Self: Sized`. - let sugg = - tcx.hir().get_if_local(method.def_id).as_ref().and_then(|node| node.generics()).map( - |generics| match generics.where_clause.predicates { - [] => (" where Self: Sized", generics.where_clause.span), - [.., pred] => (", Self: Sized", pred.span().shrink_to_hi()), - }, - ); - return Some(MethodViolationCode::StaticMethod(sugg)); - } - - let sig = tcx.fn_sig(method.def_id); - - for (i, input_ty) in sig.skip_binder().inputs()[1..].iter().enumerate() { - if contains_illegal_self_type_reference(tcx, trait_def_id, input_ty) { - return Some(MethodViolationCode::ReferencesSelfInput(i)); - } - } - if contains_illegal_self_type_reference(tcx, trait_def_id, sig.output().skip_binder()) { - return Some(MethodViolationCode::ReferencesSelfOutput); - } - - // We can't monomorphize things like `fn foo<A>(...)`. - let own_counts = tcx.generics_of(method.def_id).own_counts(); - if own_counts.types + own_counts.consts != 0 { - return Some(MethodViolationCode::Generic); - } - - if tcx - .predicates_of(method.def_id) - .predicates - .iter() - // A trait object can't claim to live more than the concrete type, - // so outlives predicates will always hold. - .cloned() - .filter(|(p, _)| p.to_opt_type_outlives().is_none()) - .collect::<Vec<_>>() - // Do a shallow visit so that `contains_illegal_self_type_reference` - // may apply it's custom visiting. - .visit_tys_shallow(|t| contains_illegal_self_type_reference(tcx, trait_def_id, t)) - { - return Some(MethodViolationCode::WhereClauseReferencesSelf); - } - - let receiver_ty = - tcx.liberate_late_bound_regions(method.def_id, &sig.map_bound(|sig| sig.inputs()[0])); - - // Until `unsized_locals` is fully implemented, `self: Self` can't be dispatched on. - // However, this is already considered object-safe. We allow it as a special case here. - // FIXME(mikeyhew) get rid of this `if` statement once `receiver_is_dispatchable` allows - // `Receiver: Unsize<Receiver[Self => dyn Trait]>`. - if receiver_ty != tcx.types.self_param { - if !receiver_is_dispatchable(tcx, method, receiver_ty) { - return Some(MethodViolationCode::UndispatchableReceiver); - } else { - // Do sanity check to make sure the receiver actually has the layout of a pointer. - - use crate::ty::layout::Abi; - - let param_env = tcx.param_env(method.def_id); - - let abi_of_ty = |ty: Ty<'tcx>| -> &Abi { - match tcx.layout_of(param_env.and(ty)) { - Ok(layout) => &layout.abi, - Err(err) => bug!("error: {}\n while computing layout for type {:?}", err, ty), - } - }; - - // e.g., `Rc<()>` - let unit_receiver_ty = - receiver_for_self_ty(tcx, receiver_ty, tcx.mk_unit(), method.def_id); - - match abi_of_ty(unit_receiver_ty) { - &Abi::Scalar(..) => (), - abi => { - tcx.sess.delay_span_bug( - tcx.def_span(method.def_id), - &format!( - "receiver when `Self = ()` should have a Scalar ABI; found {:?}", - abi - ), - ); - } - } - - let trait_object_ty = - object_ty_for_trait(tcx, trait_def_id, tcx.mk_region(ty::ReStatic)); - - // e.g., `Rc<dyn Trait>` - let trait_object_receiver = - receiver_for_self_ty(tcx, receiver_ty, trait_object_ty, method.def_id); - - match abi_of_ty(trait_object_receiver) { - &Abi::ScalarPair(..) => (), - abi => { - tcx.sess.delay_span_bug( - tcx.def_span(method.def_id), - &format!( - "receiver when `Self = {}` should have a ScalarPair ABI; \ - found {:?}", - trait_object_ty, abi - ), - ); - } - } - } - } - - None -} - -/// Performs a type substitution to produce the version of `receiver_ty` when `Self = self_ty`. -/// For example, for `receiver_ty = Rc<Self>` and `self_ty = Foo`, returns `Rc<Foo>`. -fn receiver_for_self_ty<'tcx>( - tcx: TyCtxt<'tcx>, - receiver_ty: Ty<'tcx>, - self_ty: Ty<'tcx>, - method_def_id: DefId, -) -> Ty<'tcx> { - debug!("receiver_for_self_ty({:?}, {:?}, {:?})", receiver_ty, self_ty, method_def_id); - let substs = InternalSubsts::for_item(tcx, method_def_id, |param, _| { - if param.index == 0 { self_ty.into() } else { tcx.mk_param_from_def(param) } - }); - - let result = receiver_ty.subst(tcx, substs); - debug!( - "receiver_for_self_ty({:?}, {:?}, {:?}) = {:?}", - receiver_ty, self_ty, method_def_id, result - ); - result -} - -/// Creates the object type for the current trait. For example, -/// if the current trait is `Deref`, then this will be -/// `dyn Deref<Target = Self::Target> + 'static`. -fn object_ty_for_trait<'tcx>( - tcx: TyCtxt<'tcx>, - trait_def_id: DefId, - lifetime: ty::Region<'tcx>, -) -> Ty<'tcx> { - debug!("object_ty_for_trait: trait_def_id={:?}", trait_def_id); - - let trait_ref = ty::TraitRef::identity(tcx, trait_def_id); - - let trait_predicate = - ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)); - - let mut associated_types = traits::supertraits(tcx, ty::Binder::dummy(trait_ref)) - .flat_map(|super_trait_ref| { - tcx.associated_items(super_trait_ref.def_id()) - .iter() - .map(move |item| (super_trait_ref, item)) - }) - .filter(|(_, item)| item.kind == ty::AssocKind::Type) - .collect::<Vec<_>>(); - - // existential predicates need to be in a specific order - associated_types.sort_by_cached_key(|(_, item)| tcx.def_path_hash(item.def_id)); - - let projection_predicates = associated_types.into_iter().map(|(super_trait_ref, item)| { - // We *can* get bound lifetimes here in cases like - // `trait MyTrait: for<'s> OtherTrait<&'s T, Output=bool>`. - // - // binder moved to (*)... - let super_trait_ref = super_trait_ref.skip_binder(); - ty::ExistentialPredicate::Projection(ty::ExistentialProjection { - ty: tcx.mk_projection(item.def_id, super_trait_ref.substs), - item_def_id: item.def_id, - substs: super_trait_ref.substs, - }) - }); - - let existential_predicates = - tcx.mk_existential_predicates(iter::once(trait_predicate).chain(projection_predicates)); - - let object_ty = tcx.mk_dynamic( - // (*) ... binder re-introduced here - ty::Binder::bind(existential_predicates), - lifetime, - ); - - debug!("object_ty_for_trait: object_ty=`{}`", object_ty); - - object_ty -} - -/// Checks the method's receiver (the `self` argument) can be dispatched on when `Self` is a -/// trait object. We require that `DispatchableFromDyn` be implemented for the receiver type -/// in the following way: -/// - let `Receiver` be the type of the `self` argument, i.e `Self`, `&Self`, `Rc<Self>`, -/// - require the following bound: -/// -/// ``` -/// Receiver[Self => T]: DispatchFromDyn<Receiver[Self => dyn Trait]> -/// ``` -/// -/// where `Foo[X => Y]` means "the same type as `Foo`, but with `X` replaced with `Y`" -/// (substitution notation). -/// -/// Some examples of receiver types and their required obligation: -/// - `&'a mut self` requires `&'a mut Self: DispatchFromDyn<&'a mut dyn Trait>`, -/// - `self: Rc<Self>` requires `Rc<Self>: DispatchFromDyn<Rc<dyn Trait>>`, -/// - `self: Pin<Box<Self>>` requires `Pin<Box<Self>>: DispatchFromDyn<Pin<Box<dyn Trait>>>`. -/// -/// The only case where the receiver is not dispatchable, but is still a valid receiver -/// type (just not object-safe), is when there is more than one level of pointer indirection. -/// E.g., `self: &&Self`, `self: &Rc<Self>`, `self: Box<Box<Self>>`. In these cases, there -/// is no way, or at least no inexpensive way, to coerce the receiver from the version where -/// `Self = dyn Trait` to the version where `Self = T`, where `T` is the unknown erased type -/// contained by the trait object, because the object that needs to be coerced is behind -/// a pointer. -/// -/// In practice, we cannot use `dyn Trait` explicitly in the obligation because it would result -/// in a new check that `Trait` is object safe, creating a cycle (until object_safe_for_dispatch -/// is stabilized, see tracking issue https://github.com/rust-lang/rust/issues/43561). -/// Instead, we fudge a little by introducing a new type parameter `U` such that -/// `Self: Unsize<U>` and `U: Trait + ?Sized`, and use `U` in place of `dyn Trait`. -/// Written as a chalk-style query: -/// -/// forall (U: Trait + ?Sized) { -/// if (Self: Unsize<U>) { -/// Receiver: DispatchFromDyn<Receiver[Self => U]> -/// } -/// } -/// -/// for `self: &'a mut Self`, this means `&'a mut Self: DispatchFromDyn<&'a mut U>` -/// for `self: Rc<Self>`, this means `Rc<Self>: DispatchFromDyn<Rc<U>>` -/// for `self: Pin<Box<Self>>`, this means `Pin<Box<Self>>: DispatchFromDyn<Pin<Box<U>>>` -// -// FIXME(mikeyhew) when unsized receivers are implemented as part of unsized rvalues, add this -// fallback query: `Receiver: Unsize<Receiver[Self => U]>` to support receivers like -// `self: Wrapper<Self>`. -#[allow(dead_code)] -fn receiver_is_dispatchable<'tcx>( - tcx: TyCtxt<'tcx>, - method: &ty::AssocItem, - receiver_ty: Ty<'tcx>, -) -> bool { - debug!("receiver_is_dispatchable: method = {:?}, receiver_ty = {:?}", method, receiver_ty); - - let traits = (tcx.lang_items().unsize_trait(), tcx.lang_items().dispatch_from_dyn_trait()); - let (unsize_did, dispatch_from_dyn_did) = if let (Some(u), Some(cu)) = traits { - (u, cu) - } else { - debug!("receiver_is_dispatchable: Missing Unsize or DispatchFromDyn traits"); - return false; - }; - - // the type `U` in the query - // use a bogus type parameter to mimick a forall(U) query using u32::MAX for now. - // FIXME(mikeyhew) this is a total hack. Once object_safe_for_dispatch is stabilized, we can - // replace this with `dyn Trait` - let unsized_self_ty: Ty<'tcx> = - tcx.mk_ty_param(::std::u32::MAX, Symbol::intern("RustaceansAreAwesome")); - - // `Receiver[Self => U]` - let unsized_receiver_ty = - receiver_for_self_ty(tcx, receiver_ty, unsized_self_ty, method.def_id); - - // create a modified param env, with `Self: Unsize<U>` and `U: Trait` added to caller bounds - // `U: ?Sized` is already implied here - let param_env = { - let mut param_env = tcx.param_env(method.def_id); - - // Self: Unsize<U> - let unsize_predicate = ty::TraitRef { - def_id: unsize_did, - substs: tcx.mk_substs_trait(tcx.types.self_param, &[unsized_self_ty.into()]), - } - .without_const() - .to_predicate(); - - // U: Trait<Arg1, ..., ArgN> - let trait_predicate = { - let substs = - InternalSubsts::for_item(tcx, method.container.assert_trait(), |param, _| { - if param.index == 0 { - unsized_self_ty.into() - } else { - tcx.mk_param_from_def(param) - } - }); - - ty::TraitRef { def_id: unsize_did, substs }.without_const().to_predicate() - }; - - let caller_bounds: Vec<Predicate<'tcx>> = param_env - .caller_bounds - .iter() - .cloned() - .chain(iter::once(unsize_predicate)) - .chain(iter::once(trait_predicate)) - .collect(); - - param_env.caller_bounds = tcx.intern_predicates(&caller_bounds); - - param_env - }; - - // Receiver: DispatchFromDyn<Receiver[Self => U]> - let obligation = { - let predicate = ty::TraitRef { - def_id: dispatch_from_dyn_did, - substs: tcx.mk_substs_trait(receiver_ty, &[unsized_receiver_ty.into()]), - } - .without_const() - .to_predicate(); - - Obligation::new(ObligationCause::dummy(), param_env, predicate) - }; - - tcx.infer_ctxt().enter(|ref infcx| { - // the receiver is dispatchable iff the obligation holds - infcx.predicate_must_hold_modulo_regions(&obligation) - }) -} - -fn contains_illegal_self_type_reference<'tcx>( - tcx: TyCtxt<'tcx>, - trait_def_id: DefId, - ty: Ty<'tcx>, -) -> bool { - // This is somewhat subtle. In general, we want to forbid - // references to `Self` in the argument and return types, - // since the value of `Self` is erased. However, there is one - // exception: it is ok to reference `Self` in order to access - // an associated type of the current trait, since we retain - // the value of those associated types in the object type - // itself. - // - // ```rust - // trait SuperTrait { - // type X; - // } - // - // trait Trait : SuperTrait { - // type Y; - // fn foo(&self, x: Self) // bad - // fn foo(&self) -> Self // bad - // fn foo(&self) -> Option<Self> // bad - // fn foo(&self) -> Self::Y // OK, desugars to next example - // fn foo(&self) -> <Self as Trait>::Y // OK - // fn foo(&self) -> Self::X // OK, desugars to next example - // fn foo(&self) -> <Self as SuperTrait>::X // OK - // } - // ``` - // - // However, it is not as simple as allowing `Self` in a projected - // type, because there are illegal ways to use `Self` as well: - // - // ```rust - // trait Trait : SuperTrait { - // ... - // fn foo(&self) -> <Self as SomeOtherTrait>::X; - // } - // ``` - // - // Here we will not have the type of `X` recorded in the - // object type, and we cannot resolve `Self as SomeOtherTrait` - // without knowing what `Self` is. - - let mut supertraits: Option<Vec<ty::PolyTraitRef<'tcx>>> = None; - let mut error = false; - let self_ty = tcx.types.self_param; - ty.maybe_walk(|ty| { - match ty.kind { - ty::Param(_) => { - if ty == self_ty { - error = true; - } - - false // no contained types to walk - } - - ty::Projection(ref data) => { - // This is a projected type `<Foo as SomeTrait>::X`. - - // Compute supertraits of current trait lazily. - if supertraits.is_none() { - let trait_ref = ty::Binder::bind(ty::TraitRef::identity(tcx, trait_def_id)); - supertraits = Some(traits::supertraits(tcx, trait_ref).collect()); - } - - // Determine whether the trait reference `Foo as - // SomeTrait` is in fact a supertrait of the - // current trait. In that case, this type is - // legal, because the type `X` will be specified - // in the object type. Note that we can just use - // direct equality here because all of these types - // are part of the formal parameter listing, and - // hence there should be no inference variables. - let projection_trait_ref = ty::Binder::bind(data.trait_ref(tcx)); - let is_supertrait_of_current_trait = - supertraits.as_ref().unwrap().contains(&projection_trait_ref); - - if is_supertrait_of_current_trait { - false // do not walk contained types, do not report error, do collect $200 - } else { - true // DO walk contained types, POSSIBLY reporting an error - } - } - - _ => true, // walk contained types, if any - } - }); - - error -} - -pub(super) fn is_object_safe_provider(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool { - object_safety_violations(tcx, trait_def_id).is_empty() -} diff --git a/src/librustc/traits/on_unimplemented.rs b/src/librustc/traits/on_unimplemented.rs deleted file mode 100644 index ca824d40e38..00000000000 --- a/src/librustc/traits/on_unimplemented.rs +++ /dev/null @@ -1,385 +0,0 @@ -use fmt_macros::{Parser, Piece, Position}; - -use crate::ty::{self, GenericParamDefKind, TyCtxt}; -use crate::util::common::ErrorReported; - -use rustc_attr as attr; -use rustc_data_structures::fx::FxHashMap; -use rustc_errors::struct_span_err; -use rustc_hir::def_id::DefId; -use rustc_span::symbol::{kw, sym, Symbol}; -use rustc_span::Span; -use syntax::ast::{MetaItem, NestedMetaItem}; - -#[derive(Clone, Debug)] -pub struct OnUnimplementedFormatString(Symbol); - -#[derive(Debug)] -pub struct OnUnimplementedDirective { - pub condition: Option<MetaItem>, - pub subcommands: Vec<OnUnimplementedDirective>, - pub message: Option<OnUnimplementedFormatString>, - pub label: Option<OnUnimplementedFormatString>, - pub note: Option<OnUnimplementedFormatString>, - pub enclosing_scope: Option<OnUnimplementedFormatString>, -} - -#[derive(Default)] -pub struct OnUnimplementedNote { - pub message: Option<String>, - pub label: Option<String>, - pub note: Option<String>, - pub enclosing_scope: Option<String>, -} - -fn parse_error( - tcx: TyCtxt<'_>, - span: Span, - message: &str, - label: &str, - note: Option<&str>, -) -> ErrorReported { - let mut diag = struct_span_err!(tcx.sess, span, E0232, "{}", message); - diag.span_label(span, label); - if let Some(note) = note { - diag.note(note); - } - diag.emit(); - ErrorReported -} - -impl<'tcx> OnUnimplementedDirective { - fn parse( - tcx: TyCtxt<'tcx>, - trait_def_id: DefId, - items: &[NestedMetaItem], - span: Span, - is_root: bool, - ) -> Result<Self, ErrorReported> { - let mut errored = false; - let mut item_iter = items.iter(); - - let condition = if is_root { - None - } else { - let cond = item_iter - .next() - .ok_or_else(|| { - parse_error( - tcx, - span, - "empty `on`-clause in `#[rustc_on_unimplemented]`", - "empty on-clause here", - None, - ) - })? - .meta_item() - .ok_or_else(|| { - parse_error( - tcx, - span, - "invalid `on`-clause in `#[rustc_on_unimplemented]`", - "invalid on-clause here", - None, - ) - })?; - attr::eval_condition(cond, &tcx.sess.parse_sess, &mut |_| true); - Some(cond.clone()) - }; - - let mut message = None; - let mut label = None; - let mut note = None; - let mut enclosing_scope = None; - let mut subcommands = vec![]; - - let parse_value = |value_str| { - OnUnimplementedFormatString::try_parse(tcx, trait_def_id, value_str, span).map(Some) - }; - - for item in item_iter { - if item.check_name(sym::message) && message.is_none() { - if let Some(message_) = item.value_str() { - message = parse_value(message_)?; - continue; - } - } else if item.check_name(sym::label) && label.is_none() { - if let Some(label_) = item.value_str() { - label = parse_value(label_)?; - continue; - } - } else if item.check_name(sym::note) && note.is_none() { - if let Some(note_) = item.value_str() { - note = parse_value(note_)?; - continue; - } - } else if item.check_name(sym::enclosing_scope) && enclosing_scope.is_none() { - if let Some(enclosing_scope_) = item.value_str() { - enclosing_scope = parse_value(enclosing_scope_)?; - continue; - } - } else if item.check_name(sym::on) - && is_root - && message.is_none() - && label.is_none() - && note.is_none() - { - if let Some(items) = item.meta_item_list() { - if let Ok(subcommand) = - Self::parse(tcx, trait_def_id, &items, item.span(), false) - { - subcommands.push(subcommand); - } else { - errored = true; - } - continue; - } - } - - // nothing found - parse_error( - tcx, - item.span(), - "this attribute must have a valid value", - "expected value here", - Some(r#"eg `#[rustc_on_unimplemented(message="foo")]`"#), - ); - } - - if errored { - Err(ErrorReported) - } else { - Ok(OnUnimplementedDirective { - condition, - subcommands, - message, - label, - note, - enclosing_scope, - }) - } - } - - pub fn of_item( - tcx: TyCtxt<'tcx>, - trait_def_id: DefId, - impl_def_id: DefId, - ) -> Result<Option<Self>, ErrorReported> { - let attrs = tcx.get_attrs(impl_def_id); - - let attr = if let Some(item) = attr::find_by_name(&attrs, sym::rustc_on_unimplemented) { - item - } else { - return Ok(None); - }; - - let result = if let Some(items) = attr.meta_item_list() { - Self::parse(tcx, trait_def_id, &items, attr.span, true).map(Some) - } else if let Some(value) = attr.value_str() { - Ok(Some(OnUnimplementedDirective { - condition: None, - message: None, - subcommands: vec![], - label: Some(OnUnimplementedFormatString::try_parse( - tcx, - trait_def_id, - value, - attr.span, - )?), - note: None, - enclosing_scope: None, - })) - } else { - return Err(ErrorReported); - }; - debug!("of_item({:?}/{:?}) = {:?}", trait_def_id, impl_def_id, result); - result - } - - pub fn evaluate( - &self, - tcx: TyCtxt<'tcx>, - trait_ref: ty::TraitRef<'tcx>, - options: &[(Symbol, Option<String>)], - ) -> OnUnimplementedNote { - let mut message = None; - let mut label = None; - let mut note = None; - let mut enclosing_scope = None; - info!("evaluate({:?}, trait_ref={:?}, options={:?})", self, trait_ref, options); - - for command in self.subcommands.iter().chain(Some(self)).rev() { - if let Some(ref condition) = command.condition { - if !attr::eval_condition(condition, &tcx.sess.parse_sess, &mut |c| { - c.ident().map_or(false, |ident| { - options.contains(&(ident.name, c.value_str().map(|s| s.to_string()))) - }) - }) { - debug!("evaluate: skipping {:?} due to condition", command); - continue; - } - } - debug!("evaluate: {:?} succeeded", command); - if let Some(ref message_) = command.message { - message = Some(message_.clone()); - } - - if let Some(ref label_) = command.label { - label = Some(label_.clone()); - } - - if let Some(ref note_) = command.note { - note = Some(note_.clone()); - } - - if let Some(ref enclosing_scope_) = command.enclosing_scope { - enclosing_scope = Some(enclosing_scope_.clone()); - } - } - - let options: FxHashMap<Symbol, String> = options - .into_iter() - .filter_map(|(k, v)| v.as_ref().map(|v| (*k, v.to_owned()))) - .collect(); - OnUnimplementedNote { - label: label.map(|l| l.format(tcx, trait_ref, &options)), - message: message.map(|m| m.format(tcx, trait_ref, &options)), - note: note.map(|n| n.format(tcx, trait_ref, &options)), - enclosing_scope: enclosing_scope.map(|e_s| e_s.format(tcx, trait_ref, &options)), - } - } -} - -impl<'tcx> OnUnimplementedFormatString { - fn try_parse( - tcx: TyCtxt<'tcx>, - trait_def_id: DefId, - from: Symbol, - err_sp: Span, - ) -> Result<Self, ErrorReported> { - let result = OnUnimplementedFormatString(from); - result.verify(tcx, trait_def_id, err_sp)?; - Ok(result) - } - - fn verify( - &self, - tcx: TyCtxt<'tcx>, - trait_def_id: DefId, - span: Span, - ) -> Result<(), ErrorReported> { - let name = tcx.item_name(trait_def_id); - let generics = tcx.generics_of(trait_def_id); - let s = self.0.as_str(); - let parser = Parser::new(&s, None, vec![], false); - let mut result = Ok(()); - for token in parser { - match token { - Piece::String(_) => (), // Normal string, no need to check it - Piece::NextArgument(a) => match a.position { - // `{Self}` is allowed - Position::ArgumentNamed(s) if s == kw::SelfUpper => (), - // `{ThisTraitsName}` is allowed - Position::ArgumentNamed(s) if s == name => (), - // `{from_method}` is allowed - Position::ArgumentNamed(s) if s == sym::from_method => (), - // `{from_desugaring}` is allowed - Position::ArgumentNamed(s) if s == sym::from_desugaring => (), - // `{ItemContext}` is allowed - Position::ArgumentNamed(s) if s == sym::item_context => (), - // So is `{A}` if A is a type parameter - Position::ArgumentNamed(s) => { - match generics.params.iter().find(|param| param.name == s) { - Some(_) => (), - None => { - struct_span_err!( - tcx.sess, - span, - E0230, - "there is no parameter `{}` on trait `{}`", - s, - name - ) - .emit(); - result = Err(ErrorReported); - } - } - } - // `{:1}` and `{}` are not to be used - Position::ArgumentIs(_) | Position::ArgumentImplicitlyIs(_) => { - struct_span_err!( - tcx.sess, - span, - E0231, - "only named substitution parameters are allowed" - ) - .emit(); - result = Err(ErrorReported); - } - }, - } - } - - result - } - - pub fn format( - &self, - tcx: TyCtxt<'tcx>, - trait_ref: ty::TraitRef<'tcx>, - options: &FxHashMap<Symbol, String>, - ) -> String { - let name = tcx.item_name(trait_ref.def_id); - let trait_str = tcx.def_path_str(trait_ref.def_id); - let generics = tcx.generics_of(trait_ref.def_id); - let generic_map = generics - .params - .iter() - .filter_map(|param| { - let value = match param.kind { - GenericParamDefKind::Type { .. } | GenericParamDefKind::Const => { - trait_ref.substs[param.index as usize].to_string() - } - GenericParamDefKind::Lifetime => return None, - }; - let name = param.name; - Some((name, value)) - }) - .collect::<FxHashMap<Symbol, String>>(); - let empty_string = String::new(); - - let s = self.0.as_str(); - let parser = Parser::new(&s, None, vec![], false); - let item_context = (options.get(&sym::item_context)).unwrap_or(&empty_string); - parser - .map(|p| match p { - Piece::String(s) => s, - Piece::NextArgument(a) => match a.position { - Position::ArgumentNamed(s) => match generic_map.get(&s) { - Some(val) => val, - None if s == name => &trait_str, - None => { - if let Some(val) = options.get(&s) { - val - } else if s == sym::from_desugaring || s == sym::from_method { - // don't break messages using these two arguments incorrectly - &empty_string - } else if s == sym::item_context { - &item_context - } else { - bug!( - "broken on_unimplemented {:?} for {:?}: \ - no argument matching {:?}", - self.0, - trait_ref, - s - ) - } - } - }, - _ => bug!("broken on_unimplemented {:?} - bad format arg", self.0), - }, - }) - .collect() - } -} diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs deleted file mode 100644 index 5d9f4ddfd16..00000000000 --- a/src/librustc/traits/project.rs +++ /dev/null @@ -1,1669 +0,0 @@ -//! Code for projecting associated types out of trait references. - -use super::elaborate_predicates; -use super::specialization_graph; -use super::translate_substs; -use super::util; -use super::Obligation; -use super::ObligationCause; -use super::PredicateObligation; -use super::Selection; -use super::SelectionContext; -use super::SelectionError; -use super::{VtableClosureData, VtableFnPointerData, VtableGeneratorData, VtableImplData}; - -use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use crate::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime}; -use crate::ty::fold::{TypeFoldable, TypeFolder}; -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_span::symbol::sym; -use rustc_span::DUMMY_SP; -use syntax::ast::Ident; - -pub use rustc::traits::Reveal; - -pub type PolyProjectionObligation<'tcx> = Obligation<'tcx, ty::PolyProjectionPredicate<'tcx>>; - -pub type ProjectionObligation<'tcx> = Obligation<'tcx, ty::ProjectionPredicate<'tcx>>; - -pub type ProjectionTyObligation<'tcx> = Obligation<'tcx, ty::ProjectionTy<'tcx>>; - -/// When attempting to resolve `<T as TraitRef>::Name` ... -#[derive(Debug)] -pub enum ProjectionTyError<'tcx> { - /// ...we found multiple sources of information and couldn't resolve the ambiguity. - TooManyCandidates, - - /// ...an error occurred matching `T : TraitRef` - TraitSelectionError(SelectionError<'tcx>), -} - -#[derive(Clone)] -pub struct MismatchedProjectionTypes<'tcx> { - pub err: ty::error::TypeError<'tcx>, -} - -#[derive(PartialEq, Eq, Debug)] -enum ProjectionTyCandidate<'tcx> { - // from a where-clause in the env or object type - ParamEnv(ty::PolyProjectionPredicate<'tcx>), - - // from the definition of `Trait` when you have something like <<A as Trait>::B as Trait2>::C - TraitDef(ty::PolyProjectionPredicate<'tcx>), - - // from a "impl" (or a "pseudo-impl" returned by select) - Select(Selection<'tcx>), -} - -enum ProjectionTyCandidateSet<'tcx> { - None, - Single(ProjectionTyCandidate<'tcx>), - Ambiguous, - Error(SelectionError<'tcx>), -} - -impl<'tcx> ProjectionTyCandidateSet<'tcx> { - fn mark_ambiguous(&mut self) { - *self = ProjectionTyCandidateSet::Ambiguous; - } - - fn mark_error(&mut self, err: SelectionError<'tcx>) { - *self = ProjectionTyCandidateSet::Error(err); - } - - // Returns true if the push was successful, or false if the candidate - // was discarded -- this could be because of ambiguity, or because - // a higher-priority candidate is already there. - fn push_candidate(&mut self, candidate: ProjectionTyCandidate<'tcx>) -> bool { - use self::ProjectionTyCandidate::*; - use self::ProjectionTyCandidateSet::*; - - // This wacky variable is just used to try and - // make code readable and avoid confusing paths. - // It is assigned a "value" of `()` only on those - // paths in which we wish to convert `*self` to - // ambiguous (and return false, because the candidate - // was not used). On other paths, it is not assigned, - // and hence if those paths *could* reach the code that - // comes after the match, this fn would not compile. - let convert_to_ambiguous; - - match self { - None => { - *self = Single(candidate); - return true; - } - - Single(current) => { - // Duplicates can happen inside ParamEnv. In the case, we - // perform a lazy deduplication. - if current == &candidate { - return false; - } - - // Prefer where-clauses. As in select, if there are multiple - // candidates, we prefer where-clause candidates over impls. This - // may seem a bit surprising, since impls are the source of - // "truth" in some sense, but in fact some of the impls that SEEM - // applicable are not, because of nested obligations. Where - // clauses are the safer choice. See the comment on - // `select::SelectionCandidate` and #21974 for more details. - match (current, candidate) { - (ParamEnv(..), ParamEnv(..)) => convert_to_ambiguous = (), - (ParamEnv(..), _) => return false, - (_, ParamEnv(..)) => unreachable!(), - (_, _) => convert_to_ambiguous = (), - } - } - - Ambiguous | Error(..) => { - return false; - } - } - - // We only ever get here when we moved from a single candidate - // to ambiguous. - let () = convert_to_ambiguous; - *self = Ambiguous; - false - } -} - -/// Evaluates constraints of the form: -/// -/// for<...> <T as Trait>::U == V -/// -/// If successful, this may result in additional obligations. Also returns -/// the projection cache key used to track these additional obligations. -pub fn poly_project_and_unify_type<'cx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'tcx>, - obligation: &PolyProjectionObligation<'tcx>, -) -> Result<Option<Vec<PredicateObligation<'tcx>>>, MismatchedProjectionTypes<'tcx>> { - debug!("poly_project_and_unify_type(obligation={:?})", obligation); - - let infcx = selcx.infcx(); - infcx.commit_if_ok(|snapshot| { - let (placeholder_predicate, placeholder_map) = - infcx.replace_bound_vars_with_placeholders(&obligation.predicate); - - let placeholder_obligation = obligation.with(placeholder_predicate); - let result = project_and_unify_type(selcx, &placeholder_obligation)?; - infcx - .leak_check(false, &placeholder_map, snapshot) - .map_err(|err| MismatchedProjectionTypes { err })?; - Ok(result) - }) -} - -/// Evaluates constraints of the form: -/// -/// <T as Trait>::U == V -/// -/// If successful, this may result in additional obligations. -fn project_and_unify_type<'cx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'tcx>, - obligation: &ProjectionObligation<'tcx>, -) -> Result<Option<Vec<PredicateObligation<'tcx>>>, MismatchedProjectionTypes<'tcx>> { - debug!("project_and_unify_type(obligation={:?})", obligation); - - let mut obligations = vec![]; - let normalized_ty = match opt_normalize_projection_type( - selcx, - obligation.param_env, - obligation.predicate.projection_ty, - obligation.cause.clone(), - obligation.recursion_depth, - &mut obligations, - ) { - Some(n) => n, - None => return Ok(None), - }; - - debug!( - "project_and_unify_type: normalized_ty={:?} obligations={:?}", - normalized_ty, obligations - ); - - let infcx = selcx.infcx(); - match infcx - .at(&obligation.cause, obligation.param_env) - .eq(normalized_ty, obligation.predicate.ty) - { - Ok(InferOk { obligations: inferred_obligations, value: () }) => { - obligations.extend(inferred_obligations); - Ok(Some(obligations)) - } - Err(err) => { - debug!("project_and_unify_type: equating types encountered error {:?}", err); - Err(MismatchedProjectionTypes { err }) - } - } -} - -/// Normalizes any associated type projections in `value`, replacing -/// them with a fully resolved type where possible. The return value -/// combines the normalized result and any additional obligations that -/// were incurred as result. -pub fn normalize<'a, 'b, 'tcx, T>( - selcx: &'a mut SelectionContext<'b, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - cause: ObligationCause<'tcx>, - value: &T, -) -> Normalized<'tcx, T> -where - T: TypeFoldable<'tcx>, -{ - let mut obligations = Vec::new(); - let value = normalize_to(selcx, param_env, cause, value, &mut obligations); - Normalized { value, obligations } -} - -pub fn normalize_to<'a, 'b, 'tcx, T>( - selcx: &'a mut SelectionContext<'b, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - cause: ObligationCause<'tcx>, - value: &T, - obligations: &mut Vec<PredicateObligation<'tcx>>, -) -> T -where - T: TypeFoldable<'tcx>, -{ - normalize_with_depth_to(selcx, param_env, cause, 0, value, obligations) -} - -/// As `normalize`, but with a custom depth. -pub fn normalize_with_depth<'a, 'b, 'tcx, T>( - selcx: &'a mut SelectionContext<'b, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - cause: ObligationCause<'tcx>, - depth: usize, - value: &T, -) -> Normalized<'tcx, T> -where - T: TypeFoldable<'tcx>, -{ - let mut obligations = Vec::new(); - let value = normalize_with_depth_to(selcx, param_env, cause, depth, value, &mut obligations); - Normalized { value, obligations } -} - -pub fn normalize_with_depth_to<'a, 'b, 'tcx, T>( - selcx: &'a mut SelectionContext<'b, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - cause: ObligationCause<'tcx>, - depth: usize, - value: &T, - obligations: &mut Vec<PredicateObligation<'tcx>>, -) -> T -where - T: TypeFoldable<'tcx>, -{ - debug!("normalize_with_depth(depth={}, value={:?})", depth, value); - let mut normalizer = AssocTypeNormalizer::new(selcx, param_env, cause, depth, obligations); - let result = normalizer.fold(value); - debug!( - "normalize_with_depth: depth={} result={:?} with {} obligations", - depth, - result, - normalizer.obligations.len() - ); - debug!("normalize_with_depth: depth={} obligations={:?}", depth, normalizer.obligations); - result -} - -struct AssocTypeNormalizer<'a, 'b, 'tcx> { - selcx: &'a mut SelectionContext<'b, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - cause: ObligationCause<'tcx>, - obligations: &'a mut Vec<PredicateObligation<'tcx>>, - depth: usize, -} - -impl<'a, 'b, 'tcx> AssocTypeNormalizer<'a, 'b, 'tcx> { - fn new( - selcx: &'a mut SelectionContext<'b, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - cause: ObligationCause<'tcx>, - depth: usize, - obligations: &'a mut Vec<PredicateObligation<'tcx>>, - ) -> AssocTypeNormalizer<'a, 'b, 'tcx> { - AssocTypeNormalizer { selcx, param_env, cause, obligations, depth } - } - - fn fold<T: TypeFoldable<'tcx>>(&mut self, value: &T) -> T { - let value = self.selcx.infcx().resolve_vars_if_possible(value); - - if !value.has_projections() { value } else { value.fold_with(self) } - } -} - -impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { - fn tcx<'c>(&'c self) -> TyCtxt<'tcx> { - self.selcx.tcx() - } - - fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - if !ty.has_projections() { - return ty; - } - // We don't want to normalize associated types that occur inside of region - // binders, because they may contain bound regions, and we can't cope with that. - // - // Example: - // - // for<'a> fn(<T as Foo<&'a>>::A) - // - // Instead of normalizing `<T as Foo<&'a>>::A` here, we'll - // normalize it when we instantiate those bound regions (which - // should occur eventually). - - let ty = ty.super_fold_with(self); - match ty.kind { - ty::Opaque(def_id, substs) if !substs.has_escaping_bound_vars() => { - // (*) - // Only normalize `impl Trait` after type-checking, usually in codegen. - match self.param_env.reveal { - Reveal::UserFacing => ty, - - Reveal::All => { - let recursion_limit = *self.tcx().sess.recursion_limit.get(); - if self.depth >= recursion_limit { - let obligation = Obligation::with_depth( - self.cause.clone(), - recursion_limit, - self.param_env, - ty, - ); - self.selcx.infcx().report_overflow_error(&obligation, true); - } - - let generic_ty = self.tcx().type_of(def_id); - let concrete_ty = generic_ty.subst(self.tcx(), substs); - self.depth += 1; - let folded_ty = self.fold_ty(concrete_ty); - self.depth -= 1; - folded_ty - } - } - } - - ty::Projection(ref data) if !data.has_escaping_bound_vars() => { - // (*) - - // (*) This is kind of hacky -- we need to be able to - // handle normalization within binders because - // otherwise we wind up a need to normalize when doing - // trait matching (since you can have a trait - // obligation like `for<'a> T::B : Fn(&'a int)`), but - // we can't normalize with bound regions in scope. So - // far now we just ignore binders but only normalize - // if all bound regions are gone (and then we still - // have to renormalize whenever we instantiate a - // binder). It would be better to normalize in a - // binding-aware fashion. - - let normalized_ty = normalize_projection_type( - self.selcx, - self.param_env, - *data, - self.cause.clone(), - self.depth, - &mut self.obligations, - ); - debug!( - "AssocTypeNormalizer: depth={} normalized {:?} to {:?}, \ - now with {} obligations", - self.depth, - ty, - normalized_ty, - self.obligations.len() - ); - normalized_ty - } - - _ => ty, - } - } - - fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { - constant.eval(self.selcx.tcx(), self.param_env) - } -} - -#[derive(Clone, TypeFoldable)] -pub struct Normalized<'tcx, T> { - pub value: T, - pub obligations: Vec<PredicateObligation<'tcx>>, -} - -pub type NormalizedTy<'tcx> = Normalized<'tcx, Ty<'tcx>>; - -impl<'tcx, T> Normalized<'tcx, T> { - pub fn with<U>(self, value: U) -> Normalized<'tcx, U> { - Normalized { value: value, obligations: self.obligations } - } -} - -/// The guts of `normalize`: normalize a specific projection like `<T -/// as Trait>::Item`. The result is always a type (and possibly -/// additional obligations). If ambiguity arises, which implies that -/// there are unresolved type variables in the projection, we will -/// substitute a fresh type variable `$X` and generate a new -/// obligation `<T as Trait>::Item == $X` for later. -pub fn normalize_projection_type<'a, 'b, 'tcx>( - selcx: &'a mut SelectionContext<'b, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - projection_ty: ty::ProjectionTy<'tcx>, - cause: ObligationCause<'tcx>, - depth: usize, - obligations: &mut Vec<PredicateObligation<'tcx>>, -) -> Ty<'tcx> { - opt_normalize_projection_type( - selcx, - param_env, - projection_ty, - cause.clone(), - depth, - obligations, - ) - .unwrap_or_else(move || { - // if we bottom out in ambiguity, create a type variable - // and a deferred predicate to resolve this when more type - // information is available. - - let tcx = selcx.infcx().tcx; - let def_id = projection_ty.item_def_id; - let ty_var = selcx.infcx().next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::NormalizeProjectionType, - span: tcx.def_span(def_id), - }); - let projection = ty::Binder::dummy(ty::ProjectionPredicate { projection_ty, ty: ty_var }); - let obligation = - Obligation::with_depth(cause, depth + 1, param_env, projection.to_predicate()); - obligations.push(obligation); - ty_var - }) -} - -/// The guts of `normalize`: normalize a specific projection like `<T -/// as Trait>::Item`. The result is always a type (and possibly -/// additional obligations). Returns `None` in the case of ambiguity, -/// which indicates that there are unbound type variables. -/// -/// This function used to return `Option<NormalizedTy<'tcx>>`, which contains a -/// `Ty<'tcx>` and an obligations vector. But that obligation vector was very -/// often immediately appended to another obligations vector. So now this -/// function takes an obligations vector and appends to it directly, which is -/// slightly uglier but avoids the need for an extra short-lived allocation. -fn opt_normalize_projection_type<'a, 'b, 'tcx>( - selcx: &'a mut SelectionContext<'b, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - projection_ty: ty::ProjectionTy<'tcx>, - cause: ObligationCause<'tcx>, - depth: usize, - obligations: &mut Vec<PredicateObligation<'tcx>>, -) -> Option<Ty<'tcx>> { - let infcx = selcx.infcx(); - - let projection_ty = infcx.resolve_vars_if_possible(&projection_ty); - let cache_key = ProjectionCacheKey { ty: projection_ty }; - - debug!( - "opt_normalize_projection_type(\ - projection_ty={:?}, \ - depth={})", - projection_ty, depth - ); - - // FIXME(#20304) For now, I am caching here, which is good, but it - // means we don't capture the type variables that are created in - // the case of ambiguity. Which means we may create a large stream - // of such variables. OTOH, if we move the caching up a level, we - // would not benefit from caching when proving `T: Trait<U=Foo>` - // bounds. It might be the case that we want two distinct caches, - // or else another kind of cache entry. - - let cache_result = infcx.inner.borrow_mut().projection_cache.try_start(cache_key); - match cache_result { - Ok(()) => {} - Err(ProjectionCacheEntry::Ambiguous) => { - // If we found ambiguity the last time, that generally - // means we will continue to do so until some type in the - // key changes (and we know it hasn't, because we just - // fully resolved it). One exception though is closure - // types, which can transition from having a fixed kind to - // no kind with no visible change in the key. - // - // FIXME(#32286) refactor this so that closure type - // changes - debug!( - "opt_normalize_projection_type: \ - found cache entry: ambiguous" - ); - if !projection_ty.has_closure_types() { - return None; - } - } - Err(ProjectionCacheEntry::InProgress) => { - // If while normalized A::B, we are asked to normalize - // A::B, just return A::B itself. This is a conservative - // answer, in the sense that A::B *is* clearly equivalent - // to A::B, though there may be a better value we can - // find. - - // Under lazy normalization, this can arise when - // bootstrapping. That is, imagine an environment with a - // where-clause like `A::B == u32`. Now, if we are asked - // to normalize `A::B`, we will want to check the - // where-clauses in scope. So we will try to unify `A::B` - // with `A::B`, which can trigger a recursive - // normalization. In that case, I think we will want this code: - // - // ``` - // let ty = selcx.tcx().mk_projection(projection_ty.item_def_id, - // projection_ty.substs; - // return Some(NormalizedTy { value: v, obligations: vec![] }); - // ``` - - debug!( - "opt_normalize_projection_type: \ - found cache entry: in-progress" - ); - - // But for now, let's classify this as an overflow: - let recursion_limit = *selcx.tcx().sess.recursion_limit.get(); - let obligation = - Obligation::with_depth(cause, recursion_limit, param_env, projection_ty); - selcx.infcx().report_overflow_error(&obligation, false); - } - Err(ProjectionCacheEntry::NormalizedTy(ty)) => { - // This is the hottest path in this function. - // - // If we find the value in the cache, then return it along - // with the obligations that went along with it. Note - // that, when using a fulfillment context, these - // obligations could in principle be ignored: they have - // already been registered when the cache entry was - // created (and hence the new ones will quickly be - // discarded as duplicated). But when doing trait - // evaluation this is not the case, and dropping the trait - // evaluations can causes ICEs (e.g., #43132). - debug!( - "opt_normalize_projection_type: \ - found normalized ty `{:?}`", - ty - ); - - // Once we have inferred everything we need to know, we - // can ignore the `obligations` from that point on. - if infcx.unresolved_type_vars(&ty.value).is_none() { - infcx.inner.borrow_mut().projection_cache.complete_normalized(cache_key, &ty); - // No need to extend `obligations`. - } else { - obligations.extend(ty.obligations); - } - - obligations.push(get_paranoid_cache_value_obligation( - infcx, - param_env, - projection_ty, - cause, - depth, - )); - return Some(ty.value); - } - Err(ProjectionCacheEntry::Error) => { - debug!( - "opt_normalize_projection_type: \ - found error" - ); - let result = normalize_to_error(selcx, param_env, projection_ty, cause, depth); - obligations.extend(result.obligations); - return Some(result.value); - } - } - - let obligation = Obligation::with_depth(cause.clone(), depth, param_env, projection_ty); - match project_type(selcx, &obligation) { - Ok(ProjectedTy::Progress(Progress { - ty: projected_ty, - obligations: mut projected_obligations, - })) => { - // if projection succeeded, then what we get out of this - // is also non-normalized (consider: it was derived from - // an impl, where-clause etc) and hence we must - // re-normalize it - - debug!( - "opt_normalize_projection_type: \ - projected_ty={:?} \ - depth={} \ - projected_obligations={:?}", - projected_ty, depth, projected_obligations - ); - - let result = if projected_ty.has_projections() { - let mut normalizer = AssocTypeNormalizer::new( - selcx, - param_env, - cause, - depth + 1, - &mut projected_obligations, - ); - let normalized_ty = normalizer.fold(&projected_ty); - - debug!( - "opt_normalize_projection_type: \ - normalized_ty={:?} depth={}", - normalized_ty, depth - ); - - Normalized { value: normalized_ty, obligations: projected_obligations } - } else { - Normalized { value: projected_ty, obligations: projected_obligations } - }; - - let cache_value = prune_cache_value_obligations(infcx, &result); - infcx.inner.borrow_mut().projection_cache.insert_ty(cache_key, cache_value); - obligations.extend(result.obligations); - Some(result.value) - } - Ok(ProjectedTy::NoProgress(projected_ty)) => { - debug!( - "opt_normalize_projection_type: \ - projected_ty={:?} no progress", - projected_ty - ); - let result = Normalized { value: projected_ty, obligations: vec![] }; - infcx.inner.borrow_mut().projection_cache.insert_ty(cache_key, result.clone()); - // No need to extend `obligations`. - Some(result.value) - } - Err(ProjectionTyError::TooManyCandidates) => { - debug!( - "opt_normalize_projection_type: \ - too many candidates" - ); - infcx.inner.borrow_mut().projection_cache.ambiguous(cache_key); - None - } - Err(ProjectionTyError::TraitSelectionError(_)) => { - debug!("opt_normalize_projection_type: ERROR"); - // if we got an error processing the `T as Trait` part, - // just return `ty::err` but add the obligation `T : - // Trait`, which when processed will cause the error to be - // reported later - - infcx.inner.borrow_mut().projection_cache.error(cache_key); - let result = normalize_to_error(selcx, param_env, projection_ty, cause, depth); - obligations.extend(result.obligations); - Some(result.value) - } - } -} - -/// If there are unresolved type variables, then we need to include -/// any subobligations that bind them, at least until those type -/// variables are fully resolved. -fn prune_cache_value_obligations<'a, 'tcx>( - infcx: &'a InferCtxt<'a, 'tcx>, - result: &NormalizedTy<'tcx>, -) -> NormalizedTy<'tcx> { - if infcx.unresolved_type_vars(&result.value).is_none() { - return NormalizedTy { value: result.value, obligations: vec![] }; - } - - let mut obligations: Vec<_> = result - .obligations - .iter() - .filter(|obligation| match obligation.predicate { - // We found a `T: Foo<X = U>` predicate, let's check - // if `U` references any unresolved type - // variables. In principle, we only care if this - // projection can help resolve any of the type - // variables found in `result.value` -- but we just - // check for any type variables here, for fear of - // indirect obligations (e.g., we project to `?0`, - // but we have `T: Foo<X = ?1>` and `?1: Bar<X = - // ?0>`). - ty::Predicate::Projection(ref data) => infcx.unresolved_type_vars(&data.ty()).is_some(), - - // We are only interested in `T: Foo<X = U>` predicates, whre - // `U` references one of `unresolved_type_vars`. =) - _ => false, - }) - .cloned() - .collect(); - - obligations.shrink_to_fit(); - - NormalizedTy { value: result.value, obligations } -} - -/// Whenever we give back a cache result for a projection like `<T as -/// Trait>::Item ==> X`, we *always* include the obligation to prove -/// that `T: Trait` (we may also include some other obligations). This -/// may or may not be necessary -- in principle, all the obligations -/// that must be proven to show that `T: Trait` were also returned -/// when the cache was first populated. But there are some vague concerns, -/// and so we take the precautionary measure of including `T: Trait` in -/// the result: -/// -/// Concern #1. The current setup is fragile. Perhaps someone could -/// have failed to prove the concerns from when the cache was -/// populated, but also not have used a snapshot, in which case the -/// cache could remain populated even though `T: Trait` has not been -/// shown. In this case, the "other code" is at fault -- when you -/// project something, you are supposed to either have a snapshot or -/// else prove all the resulting obligations -- but it's still easy to -/// get wrong. -/// -/// Concern #2. Even within the snapshot, if those original -/// obligations are not yet proven, then we are able to do projections -/// that may yet turn out to be wrong. This *may* lead to some sort -/// of trouble, though we don't have a concrete example of how that -/// can occur yet. But it seems risky at best. -fn get_paranoid_cache_value_obligation<'a, 'tcx>( - infcx: &'a InferCtxt<'a, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - projection_ty: ty::ProjectionTy<'tcx>, - cause: ObligationCause<'tcx>, - depth: usize, -) -> PredicateObligation<'tcx> { - let trait_ref = projection_ty.trait_ref(infcx.tcx).to_poly_trait_ref(); - Obligation { - cause, - recursion_depth: depth, - param_env, - predicate: trait_ref.without_const().to_predicate(), - } -} - -/// If we are projecting `<T as Trait>::Item`, but `T: Trait` does not -/// hold. In various error cases, we cannot generate a valid -/// normalized projection. Therefore, we create an inference variable -/// return an associated obligation that, when fulfilled, will lead to -/// an error. -/// -/// Note that we used to return `Error` here, but that was quite -/// dubious -- the premise was that an error would *eventually* be -/// reported, when the obligation was processed. But in general once -/// you see a `Error` you are supposed to be able to assume that an -/// error *has been* reported, so that you can take whatever heuristic -/// paths you want to take. To make things worse, it was possible for -/// cycles to arise, where you basically had a setup like `<MyType<$0> -/// as Trait>::Foo == $0`. Here, normalizing `<MyType<$0> as -/// Trait>::Foo> to `[type error]` would lead to an obligation of -/// `<MyType<[type error]> as Trait>::Foo`. We are supposed to report -/// an error for this obligation, but we legitimately should not, -/// because it contains `[type error]`. Yuck! (See issue #29857 for -/// one case where this arose.) -fn normalize_to_error<'a, 'tcx>( - selcx: &mut SelectionContext<'a, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - projection_ty: ty::ProjectionTy<'tcx>, - cause: ObligationCause<'tcx>, - depth: usize, -) -> NormalizedTy<'tcx> { - let trait_ref = projection_ty.trait_ref(selcx.tcx()).to_poly_trait_ref(); - let trait_obligation = Obligation { - cause, - recursion_depth: depth, - param_env, - predicate: trait_ref.without_const().to_predicate(), - }; - let tcx = selcx.infcx().tcx; - let def_id = projection_ty.item_def_id; - let new_value = selcx.infcx().next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::NormalizeProjectionType, - span: tcx.def_span(def_id), - }); - Normalized { value: new_value, obligations: vec![trait_obligation] } -} - -enum ProjectedTy<'tcx> { - Progress(Progress<'tcx>), - NoProgress(Ty<'tcx>), -} - -struct Progress<'tcx> { - ty: Ty<'tcx>, - obligations: Vec<PredicateObligation<'tcx>>, -} - -impl<'tcx> Progress<'tcx> { - fn error(tcx: TyCtxt<'tcx>) -> Self { - Progress { ty: tcx.types.err, obligations: vec![] } - } - - fn with_addl_obligations(mut self, mut obligations: Vec<PredicateObligation<'tcx>>) -> Self { - debug!( - "with_addl_obligations: self.obligations.len={} obligations.len={}", - self.obligations.len(), - obligations.len() - ); - - debug!( - "with_addl_obligations: self.obligations={:?} obligations={:?}", - self.obligations, obligations - ); - - self.obligations.append(&mut obligations); - self - } -} - -/// Computes the result of a projection type (if we can). -/// -/// IMPORTANT: -/// - `obligation` must be fully normalized -fn project_type<'cx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'tcx>, - obligation: &ProjectionTyObligation<'tcx>, -) -> Result<ProjectedTy<'tcx>, ProjectionTyError<'tcx>> { - debug!("project(obligation={:?})", obligation); - - let recursion_limit = *selcx.tcx().sess.recursion_limit.get(); - if obligation.recursion_depth >= recursion_limit { - debug!("project: overflow!"); - return Err(ProjectionTyError::TraitSelectionError(SelectionError::Overflow)); - } - - let obligation_trait_ref = &obligation.predicate.trait_ref(selcx.tcx()); - - debug!("project: obligation_trait_ref={:?}", obligation_trait_ref); - - if obligation_trait_ref.references_error() { - return Ok(ProjectedTy::Progress(Progress::error(selcx.tcx()))); - } - - let mut candidates = ProjectionTyCandidateSet::None; - - // Make sure that the following procedures are kept in order. ParamEnv - // needs to be first because it has highest priority, and Select checks - // the return value of push_candidate which assumes it's ran at last. - assemble_candidates_from_param_env(selcx, obligation, &obligation_trait_ref, &mut candidates); - - assemble_candidates_from_trait_def(selcx, obligation, &obligation_trait_ref, &mut candidates); - - assemble_candidates_from_impls(selcx, obligation, &obligation_trait_ref, &mut candidates); - - match candidates { - ProjectionTyCandidateSet::Single(candidate) => Ok(ProjectedTy::Progress( - confirm_candidate(selcx, obligation, &obligation_trait_ref, candidate), - )), - ProjectionTyCandidateSet::None => Ok(ProjectedTy::NoProgress( - selcx - .tcx() - .mk_projection(obligation.predicate.item_def_id, obligation.predicate.substs), - )), - // Error occurred while trying to processing impls. - ProjectionTyCandidateSet::Error(e) => Err(ProjectionTyError::TraitSelectionError(e)), - // Inherent ambiguity that prevents us from even enumerating the - // candidates. - ProjectionTyCandidateSet::Ambiguous => Err(ProjectionTyError::TooManyCandidates), - } -} - -/// The first thing we have to do is scan through the parameter -/// environment to see whether there are any projection predicates -/// there that can answer this question. -fn assemble_candidates_from_param_env<'cx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'tcx>, - obligation: &ProjectionTyObligation<'tcx>, - obligation_trait_ref: &ty::TraitRef<'tcx>, - candidate_set: &mut ProjectionTyCandidateSet<'tcx>, -) { - debug!("assemble_candidates_from_param_env(..)"); - assemble_candidates_from_predicates( - selcx, - obligation, - obligation_trait_ref, - candidate_set, - ProjectionTyCandidate::ParamEnv, - obligation.param_env.caller_bounds.iter().cloned(), - ); -} - -/// In the case of a nested projection like <<A as Foo>::FooT as Bar>::BarT, we may find -/// that the definition of `Foo` has some clues: -/// -/// ``` -/// trait Foo { -/// type FooT : Bar<BarT=i32> -/// } -/// ``` -/// -/// Here, for example, we could conclude that the result is `i32`. -fn assemble_candidates_from_trait_def<'cx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'tcx>, - obligation: &ProjectionTyObligation<'tcx>, - obligation_trait_ref: &ty::TraitRef<'tcx>, - candidate_set: &mut ProjectionTyCandidateSet<'tcx>, -) { - debug!("assemble_candidates_from_trait_def(..)"); - - let tcx = selcx.tcx(); - // Check whether the self-type is itself a projection. - let (def_id, substs) = match obligation_trait_ref.self_ty().kind { - ty::Projection(ref data) => (data.trait_ref(tcx).def_id, data.substs), - ty::Opaque(def_id, substs) => (def_id, substs), - ty::Infer(ty::TyVar(_)) => { - // If the self-type is an inference variable, then it MAY wind up - // being a projected type, so induce an ambiguity. - candidate_set.mark_ambiguous(); - return; - } - _ => return, - }; - - // If so, extract what we know from the trait and try to come up with a good answer. - let trait_predicates = tcx.predicates_of(def_id); - let bounds = trait_predicates.instantiate(tcx, substs); - let bounds = elaborate_predicates(tcx, bounds.predicates); - assemble_candidates_from_predicates( - selcx, - obligation, - obligation_trait_ref, - candidate_set, - ProjectionTyCandidate::TraitDef, - bounds, - ) -} - -fn assemble_candidates_from_predicates<'cx, 'tcx, I>( - selcx: &mut SelectionContext<'cx, 'tcx>, - obligation: &ProjectionTyObligation<'tcx>, - obligation_trait_ref: &ty::TraitRef<'tcx>, - candidate_set: &mut ProjectionTyCandidateSet<'tcx>, - ctor: fn(ty::PolyProjectionPredicate<'tcx>) -> ProjectionTyCandidate<'tcx>, - env_predicates: I, -) where - I: IntoIterator<Item = ty::Predicate<'tcx>>, -{ - debug!("assemble_candidates_from_predicates(obligation={:?})", obligation); - let infcx = selcx.infcx(); - for predicate in env_predicates { - debug!("assemble_candidates_from_predicates: predicate={:?}", predicate); - if let ty::Predicate::Projection(data) = predicate { - let same_def_id = data.projection_def_id() == obligation.predicate.item_def_id; - - let is_match = same_def_id - && infcx.probe(|_| { - let data_poly_trait_ref = data.to_poly_trait_ref(infcx.tcx); - let obligation_poly_trait_ref = obligation_trait_ref.to_poly_trait_ref(); - infcx - .at(&obligation.cause, obligation.param_env) - .sup(obligation_poly_trait_ref, data_poly_trait_ref) - .map(|InferOk { obligations: _, value: () }| { - // FIXME(#32730) -- do we need to take obligations - // into account in any way? At the moment, no. - }) - .is_ok() - }); - - debug!( - "assemble_candidates_from_predicates: candidate={:?} \ - is_match={} same_def_id={}", - data, is_match, same_def_id - ); - - if is_match { - candidate_set.push_candidate(ctor(data)); - } - } - } -} - -fn assemble_candidates_from_impls<'cx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'tcx>, - obligation: &ProjectionTyObligation<'tcx>, - obligation_trait_ref: &ty::TraitRef<'tcx>, - candidate_set: &mut ProjectionTyCandidateSet<'tcx>, -) { - // If we are resolving `<T as TraitRef<...>>::Item == Type`, - // start out by selecting the predicate `T as TraitRef<...>`: - let poly_trait_ref = obligation_trait_ref.to_poly_trait_ref(); - let trait_obligation = obligation.with(poly_trait_ref.to_poly_trait_predicate()); - let _ = selcx.infcx().commit_if_ok(|_| { - let vtable = match selcx.select(&trait_obligation) { - Ok(Some(vtable)) => vtable, - Ok(None) => { - candidate_set.mark_ambiguous(); - return Err(()); - } - Err(e) => { - debug!("assemble_candidates_from_impls: selection error {:?}", e); - candidate_set.mark_error(e); - return Err(()); - } - }; - - let eligible = match &vtable { - super::VtableClosure(_) - | super::VtableGenerator(_) - | super::VtableFnPointer(_) - | super::VtableObject(_) - | super::VtableTraitAlias(_) => { - debug!("assemble_candidates_from_impls: vtable={:?}", vtable); - true - } - super::VtableImpl(impl_data) => { - // We have to be careful when projecting out of an - // impl because of specialization. If we are not in - // codegen (i.e., projection mode is not "any"), and the - // impl's type is declared as default, then we disable - // projection (even if the trait ref is fully - // monomorphic). In the case where trait ref is not - // fully monomorphic (i.e., includes type parameters), - // this is because those type parameters may - // ultimately be bound to types from other crates that - // may have specialized impls we can't see. In the - // case where the trait ref IS fully monomorphic, this - // is a policy decision that we made in the RFC in - // order to preserve flexibility for the crate that - // defined the specializable impl to specialize later - // for existing types. - // - // In either case, we handle this by not adding a - // candidate for an impl if it contains a `default` - // type. - // - // NOTE: This should be kept in sync with the similar code in - // `rustc::ty::instance::resolve_associated_item()`. - let node_item = - assoc_ty_def(selcx, impl_data.impl_def_id, obligation.predicate.item_def_id); - - let is_default = if node_item.node.is_from_trait() { - // If true, the impl inherited a `type Foo = Bar` - // given in the trait, which is implicitly default. - // Otherwise, the impl did not specify `type` and - // neither did the trait: - // - // ```rust - // trait Foo { type T; } - // impl Foo for Bar { } - // ``` - // - // This is an error, but it will be - // reported in `check_impl_items_against_trait`. - // We accept it here but will flag it as - // an error when we confirm the candidate - // (which will ultimately lead to `normalize_to_error` - // being invoked). - node_item.item.defaultness.has_value() - } else { - node_item.item.defaultness.is_default() - || super::util::impl_is_default(selcx.tcx(), node_item.node.def_id()) - }; - - // Only reveal a specializable default if we're past type-checking - // and the obligations is monomorphic, otherwise passes such as - // transmute checking and polymorphic MIR optimizations could - // get a result which isn't correct for all monomorphizations. - if !is_default { - true - } else if obligation.param_env.reveal == Reveal::All { - // NOTE(eddyb) inference variables can resolve to parameters, so - // assume `poly_trait_ref` isn't monomorphic, if it contains any. - let poly_trait_ref = selcx.infcx().resolve_vars_if_possible(&poly_trait_ref); - !poly_trait_ref.needs_infer() && !poly_trait_ref.needs_subst() - } else { - false - } - } - super::VtableParam(..) => { - // This case tell us nothing about the value of an - // associated type. Consider: - // - // ``` - // trait SomeTrait { type Foo; } - // fn foo<T:SomeTrait>(...) { } - // ``` - // - // If the user writes `<T as SomeTrait>::Foo`, then the `T - // : SomeTrait` binding does not help us decide what the - // type `Foo` is (at least, not more specifically than - // what we already knew). - // - // But wait, you say! What about an example like this: - // - // ``` - // fn bar<T:SomeTrait<Foo=usize>>(...) { ... } - // ``` - // - // Doesn't the `T : Sometrait<Foo=usize>` predicate help - // resolve `T::Foo`? And of course it does, but in fact - // that single predicate is desugared into two predicates - // in the compiler: a trait predicate (`T : SomeTrait`) and a - // projection. And the projection where clause is handled - // in `assemble_candidates_from_param_env`. - false - } - super::VtableAutoImpl(..) | super::VtableBuiltin(..) => { - // These traits have no associated types. - span_bug!( - obligation.cause.span, - "Cannot project an associated type from `{:?}`", - vtable - ); - } - }; - - if eligible { - if candidate_set.push_candidate(ProjectionTyCandidate::Select(vtable)) { - Ok(()) - } else { - Err(()) - } - } else { - Err(()) - } - }); -} - -fn confirm_candidate<'cx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'tcx>, - obligation: &ProjectionTyObligation<'tcx>, - obligation_trait_ref: &ty::TraitRef<'tcx>, - candidate: ProjectionTyCandidate<'tcx>, -) -> Progress<'tcx> { - debug!("confirm_candidate(candidate={:?}, obligation={:?})", candidate, obligation); - - match candidate { - ProjectionTyCandidate::ParamEnv(poly_projection) - | ProjectionTyCandidate::TraitDef(poly_projection) => { - confirm_param_env_candidate(selcx, obligation, poly_projection) - } - - ProjectionTyCandidate::Select(vtable) => { - confirm_select_candidate(selcx, obligation, obligation_trait_ref, vtable) - } - } -} - -fn confirm_select_candidate<'cx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'tcx>, - obligation: &ProjectionTyObligation<'tcx>, - obligation_trait_ref: &ty::TraitRef<'tcx>, - vtable: Selection<'tcx>, -) -> Progress<'tcx> { - match vtable { - super::VtableImpl(data) => confirm_impl_candidate(selcx, obligation, data), - super::VtableGenerator(data) => confirm_generator_candidate(selcx, obligation, data), - super::VtableClosure(data) => confirm_closure_candidate(selcx, obligation, data), - super::VtableFnPointer(data) => confirm_fn_pointer_candidate(selcx, obligation, data), - super::VtableObject(_) => confirm_object_candidate(selcx, obligation, obligation_trait_ref), - super::VtableAutoImpl(..) - | super::VtableParam(..) - | super::VtableBuiltin(..) - | super::VtableTraitAlias(..) => - // we don't create Select candidates with this kind of resolution - { - span_bug!( - obligation.cause.span, - "Cannot project an associated type from `{:?}`", - vtable - ) - } - } -} - -fn confirm_object_candidate<'cx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'tcx>, - obligation: &ProjectionTyObligation<'tcx>, - obligation_trait_ref: &ty::TraitRef<'tcx>, -) -> Progress<'tcx> { - let self_ty = obligation_trait_ref.self_ty(); - let object_ty = selcx.infcx().shallow_resolve(self_ty); - debug!("confirm_object_candidate(object_ty={:?})", object_ty); - let data = match object_ty.kind { - ty::Dynamic(ref data, ..) => data, - _ => span_bug!( - obligation.cause.span, - "confirm_object_candidate called with non-object: {:?}", - object_ty - ), - }; - let env_predicates = data - .projection_bounds() - .map(|p| p.with_self_ty(selcx.tcx(), object_ty).to_predicate()) - .collect(); - let env_predicate = { - let env_predicates = elaborate_predicates(selcx.tcx(), env_predicates); - - // select only those projections that are actually projecting an - // item with the correct name - let env_predicates = env_predicates.filter_map(|p| match p { - ty::Predicate::Projection(data) => { - if data.projection_def_id() == obligation.predicate.item_def_id { - Some(data) - } else { - None - } - } - _ => None, - }); - - // select those with a relevant trait-ref - let mut env_predicates = env_predicates.filter(|data| { - let data_poly_trait_ref = data.to_poly_trait_ref(selcx.tcx()); - let obligation_poly_trait_ref = obligation_trait_ref.to_poly_trait_ref(); - selcx.infcx().probe(|_| { - selcx - .infcx() - .at(&obligation.cause, obligation.param_env) - .sup(obligation_poly_trait_ref, data_poly_trait_ref) - .is_ok() - }) - }); - - // select the first matching one; there really ought to be one or - // else the object type is not WF, since an object type should - // include all of its projections explicitly - match env_predicates.next() { - Some(env_predicate) => env_predicate, - None => { - debug!( - "confirm_object_candidate: no env-predicate \ - found in object type `{:?}`; ill-formed", - object_ty - ); - return Progress::error(selcx.tcx()); - } - } - }; - - confirm_param_env_candidate(selcx, obligation, env_predicate) -} - -fn confirm_generator_candidate<'cx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'tcx>, - obligation: &ProjectionTyObligation<'tcx>, - vtable: VtableGeneratorData<'tcx, PredicateObligation<'tcx>>, -) -> Progress<'tcx> { - let gen_sig = vtable.substs.as_generator().poly_sig(vtable.generator_def_id, selcx.tcx()); - let Normalized { value: gen_sig, obligations } = normalize_with_depth( - selcx, - obligation.param_env, - obligation.cause.clone(), - obligation.recursion_depth + 1, - &gen_sig, - ); - - debug!( - "confirm_generator_candidate: obligation={:?},gen_sig={:?},obligations={:?}", - obligation, gen_sig, obligations - ); - - let tcx = selcx.tcx(); - - let gen_def_id = tcx.lang_items().gen_trait().unwrap(); - - let predicate = super::util::generator_trait_ref_and_outputs( - tcx, - gen_def_id, - obligation.predicate.self_ty(), - gen_sig, - ) - .map_bound(|(trait_ref, yield_ty, return_ty)| { - let name = tcx.associated_item(obligation.predicate.item_def_id).ident.name; - let ty = if name == sym::Return { - return_ty - } else if name == sym::Yield { - yield_ty - } else { - bug!() - }; - - ty::ProjectionPredicate { - projection_ty: ty::ProjectionTy { - substs: trait_ref.substs, - item_def_id: obligation.predicate.item_def_id, - }, - ty: ty, - } - }); - - confirm_param_env_candidate(selcx, obligation, predicate) - .with_addl_obligations(vtable.nested) - .with_addl_obligations(obligations) -} - -fn confirm_fn_pointer_candidate<'cx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'tcx>, - obligation: &ProjectionTyObligation<'tcx>, - fn_pointer_vtable: VtableFnPointerData<'tcx, PredicateObligation<'tcx>>, -) -> Progress<'tcx> { - let fn_type = selcx.infcx().shallow_resolve(fn_pointer_vtable.fn_ty); - let sig = fn_type.fn_sig(selcx.tcx()); - let Normalized { value: sig, obligations } = normalize_with_depth( - selcx, - obligation.param_env, - obligation.cause.clone(), - obligation.recursion_depth + 1, - &sig, - ); - - confirm_callable_candidate(selcx, obligation, sig, util::TupleArgumentsFlag::Yes) - .with_addl_obligations(fn_pointer_vtable.nested) - .with_addl_obligations(obligations) -} - -fn confirm_closure_candidate<'cx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'tcx>, - obligation: &ProjectionTyObligation<'tcx>, - vtable: VtableClosureData<'tcx, PredicateObligation<'tcx>>, -) -> Progress<'tcx> { - let tcx = selcx.tcx(); - let infcx = selcx.infcx(); - let closure_sig_ty = vtable.substs.as_closure().sig_ty(vtable.closure_def_id, tcx); - let closure_sig = infcx.shallow_resolve(closure_sig_ty).fn_sig(tcx); - let Normalized { value: closure_sig, obligations } = normalize_with_depth( - selcx, - obligation.param_env, - obligation.cause.clone(), - obligation.recursion_depth + 1, - &closure_sig, - ); - - debug!( - "confirm_closure_candidate: obligation={:?},closure_sig={:?},obligations={:?}", - obligation, closure_sig, obligations - ); - - confirm_callable_candidate(selcx, obligation, closure_sig, util::TupleArgumentsFlag::No) - .with_addl_obligations(vtable.nested) - .with_addl_obligations(obligations) -} - -fn confirm_callable_candidate<'cx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'tcx>, - obligation: &ProjectionTyObligation<'tcx>, - fn_sig: ty::PolyFnSig<'tcx>, - flag: util::TupleArgumentsFlag, -) -> Progress<'tcx> { - let tcx = selcx.tcx(); - - debug!("confirm_callable_candidate({:?},{:?})", obligation, fn_sig); - - // the `Output` associated type is declared on `FnOnce` - let fn_once_def_id = tcx.lang_items().fn_once_trait().unwrap(); - - let predicate = super::util::closure_trait_ref_and_return_type( - tcx, - fn_once_def_id, - obligation.predicate.self_ty(), - fn_sig, - flag, - ) - .map_bound(|(trait_ref, ret_type)| ty::ProjectionPredicate { - projection_ty: ty::ProjectionTy::from_ref_and_name( - tcx, - trait_ref, - Ident::with_dummy_span(rustc_hir::FN_OUTPUT_NAME), - ), - ty: ret_type, - }); - - confirm_param_env_candidate(selcx, obligation, predicate) -} - -fn confirm_param_env_candidate<'cx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'tcx>, - obligation: &ProjectionTyObligation<'tcx>, - poly_cache_entry: ty::PolyProjectionPredicate<'tcx>, -) -> Progress<'tcx> { - let infcx = selcx.infcx(); - let cause = &obligation.cause; - let param_env = obligation.param_env; - - let (cache_entry, _) = infcx.replace_bound_vars_with_fresh_vars( - cause.span, - LateBoundRegionConversionTime::HigherRankedType, - &poly_cache_entry, - ); - - let cache_trait_ref = cache_entry.projection_ty.trait_ref(infcx.tcx); - let obligation_trait_ref = obligation.predicate.trait_ref(infcx.tcx); - match infcx.at(cause, param_env).eq(cache_trait_ref, obligation_trait_ref) { - Ok(InferOk { value: _, obligations }) => Progress { ty: cache_entry.ty, obligations }, - Err(e) => { - let msg = format!( - "Failed to unify obligation `{:?}` with poly_projection `{:?}`: {:?}", - obligation, poly_cache_entry, e, - ); - debug!("confirm_param_env_candidate: {}", msg); - infcx.tcx.sess.delay_span_bug(obligation.cause.span, &msg); - Progress { ty: infcx.tcx.types.err, obligations: vec![] } - } - } -} - -fn confirm_impl_candidate<'cx, 'tcx>( - selcx: &mut SelectionContext<'cx, 'tcx>, - obligation: &ProjectionTyObligation<'tcx>, - impl_vtable: VtableImplData<'tcx, PredicateObligation<'tcx>>, -) -> Progress<'tcx> { - let tcx = selcx.tcx(); - - let VtableImplData { impl_def_id, substs, nested } = impl_vtable; - let assoc_item_id = obligation.predicate.item_def_id; - let trait_def_id = tcx.trait_id_of_impl(impl_def_id).unwrap(); - - let param_env = obligation.param_env; - let assoc_ty = assoc_ty_def(selcx, impl_def_id, assoc_item_id); - - if !assoc_ty.item.defaultness.has_value() { - // This means that the impl is missing a definition for the - // associated type. This error will be reported by the type - // checker method `check_impl_items_against_trait`, so here we - // just return Error. - debug!( - "confirm_impl_candidate: no associated type {:?} for {:?}", - assoc_ty.item.ident, obligation.predicate - ); - return Progress { ty: tcx.types.err, obligations: nested }; - } - let substs = obligation.predicate.substs.rebase_onto(tcx, trait_def_id, substs); - let substs = translate_substs(selcx.infcx(), param_env, impl_def_id, substs, assoc_ty.node); - let ty = if let ty::AssocKind::OpaqueTy = assoc_ty.item.kind { - let item_substs = InternalSubsts::identity_for_item(tcx, assoc_ty.item.def_id); - tcx.mk_opaque(assoc_ty.item.def_id, item_substs) - } else { - tcx.type_of(assoc_ty.item.def_id) - }; - if substs.len() != tcx.generics_of(assoc_ty.item.def_id).count() { - tcx.sess - .delay_span_bug(DUMMY_SP, "impl item and trait item have different parameter counts"); - Progress { ty: tcx.types.err, obligations: nested } - } else { - Progress { ty: ty.subst(tcx, substs), obligations: nested } - } -} - -/// Locate the definition of an associated type in the specialization hierarchy, -/// starting from the given impl. -/// -/// Based on the "projection mode", this lookup may in fact only examine the -/// topmost impl. See the comments for `Reveal` for more details. -fn assoc_ty_def( - selcx: &SelectionContext<'_, '_>, - impl_def_id: DefId, - assoc_ty_def_id: DefId, -) -> specialization_graph::NodeItem<ty::AssocItem> { - let tcx = selcx.tcx(); - let assoc_ty_name = tcx.associated_item(assoc_ty_def_id).ident; - let trait_def_id = tcx.impl_trait_ref(impl_def_id).unwrap().def_id; - let trait_def = tcx.trait_def(trait_def_id); - - // This function may be called while we are still building the - // specialization graph that is queried below (via TraidDef::ancestors()), - // so, in order to avoid unnecessary infinite recursion, we manually look - // for the associated item at the given impl. - // If there is no such item in that impl, this function will fail with a - // cycle error if the specialization graph is currently being built. - let impl_node = specialization_graph::Node::Impl(impl_def_id); - for item in impl_node.items(tcx) { - if matches!(item.kind, ty::AssocKind::Type | ty::AssocKind::OpaqueTy) - && tcx.hygienic_eq(item.ident, assoc_ty_name, trait_def_id) - { - return specialization_graph::NodeItem { - node: specialization_graph::Node::Impl(impl_def_id), - item: *item, - }; - } - } - - if let Some(assoc_item) = - trait_def.ancestors(tcx, impl_def_id).leaf_def(tcx, assoc_ty_name, ty::AssocKind::Type) - { - assoc_item - } else { - // This is saying that neither the trait nor - // the impl contain a definition for this - // associated type. Normally this situation - // could only arise through a compiler bug -- - // if the user wrote a bad item name, it - // should have failed in astconv. - bug!("No associated type `{}` for {}", assoc_ty_name, tcx.def_path_str(impl_def_id)) - } -} - -// # Cache - -/// The projection cache. Unlike the standard caches, this can include -/// infcx-dependent type variables, therefore we have to roll the -/// cache back each time we roll a snapshot back, to avoid assumptions -/// on yet-unresolved inference variables. Types with placeholder -/// regions also have to be removed when the respective snapshot ends. -/// -/// Because of that, projection cache entries can be "stranded" and left -/// inaccessible when type variables inside the key are resolved. We make no -/// attempt to recover or remove "stranded" entries, but rather let them be -/// (for the lifetime of the infcx). -/// -/// Entries in the projection cache might contain inference variables -/// that will be resolved by obligations on the projection cache entry (e.g., -/// when a type parameter in the associated type is constrained through -/// an "RFC 447" projection on the impl). -/// -/// When working with a fulfillment context, the derived obligations of each -/// projection cache entry will be registered on the fulfillcx, so any users -/// that can wait for a fulfillcx fixed point need not care about this. However, -/// users that don't wait for a fixed point (e.g., trait evaluation) have to -/// resolve the obligations themselves to make sure the projected result is -/// ok and avoid issues like #43132. -/// -/// If that is done, after evaluation the obligations, it is a good idea to -/// call `ProjectionCache::complete` to make sure the obligations won't be -/// re-evaluated and avoid an exponential worst-case. -// -// FIXME: we probably also want some sort of cross-infcx cache here to -// reduce the amount of duplication. Let's see what we get with the Chalk reforms. -#[derive(Default)] -pub struct ProjectionCache<'tcx> { - map: SnapshotMap<ProjectionCacheKey<'tcx>, ProjectionCacheEntry<'tcx>>, -} - -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] -pub struct ProjectionCacheKey<'tcx> { - ty: ty::ProjectionTy<'tcx>, -} - -impl<'cx, 'tcx> ProjectionCacheKey<'tcx> { - pub fn from_poly_projection_predicate( - selcx: &mut SelectionContext<'cx, 'tcx>, - predicate: &ty::PolyProjectionPredicate<'tcx>, - ) -> Option<Self> { - let infcx = selcx.infcx(); - // We don't do cross-snapshot caching of obligations with escaping regions, - // so there's no cache key to use - predicate.no_bound_vars().map(|predicate| ProjectionCacheKey { - // We don't attempt to match up with a specific type-variable state - // from a specific call to `opt_normalize_projection_type` - if - // there's no precise match, the original cache entry is "stranded" - // anyway. - ty: infcx.resolve_vars_if_possible(&predicate.projection_ty), - }) - } -} - -#[derive(Clone, Debug)] -enum ProjectionCacheEntry<'tcx> { - InProgress, - Ambiguous, - Error, - NormalizedTy(NormalizedTy<'tcx>), -} - -// N.B., intentionally not Clone -pub struct ProjectionCacheSnapshot { - snapshot: Snapshot, -} - -impl<'tcx> ProjectionCache<'tcx> { - pub fn clear(&mut self) { - self.map.clear(); - } - - pub fn snapshot(&mut self) -> ProjectionCacheSnapshot { - ProjectionCacheSnapshot { snapshot: self.map.snapshot() } - } - - pub fn rollback_to(&mut self, snapshot: ProjectionCacheSnapshot) { - self.map.rollback_to(snapshot.snapshot); - } - - pub fn rollback_placeholder(&mut self, snapshot: &ProjectionCacheSnapshot) { - self.map.partial_rollback(&snapshot.snapshot, &|k| k.ty.has_re_placeholders()); - } - - pub fn commit(&mut self, snapshot: ProjectionCacheSnapshot) { - self.map.commit(snapshot.snapshot); - } - - /// Try to start normalize `key`; returns an error if - /// normalization already occurred (this error corresponds to a - /// cache hit, so it's actually a good thing). - fn try_start( - &mut self, - key: ProjectionCacheKey<'tcx>, - ) -> Result<(), ProjectionCacheEntry<'tcx>> { - if let Some(entry) = self.map.get(&key) { - return Err(entry.clone()); - } - - self.map.insert(key, ProjectionCacheEntry::InProgress); - Ok(()) - } - - /// Indicates that `key` was normalized to `value`. - fn insert_ty(&mut self, key: ProjectionCacheKey<'tcx>, value: NormalizedTy<'tcx>) { - debug!( - "ProjectionCacheEntry::insert_ty: adding cache entry: key={:?}, value={:?}", - key, value - ); - let fresh_key = self.map.insert(key, ProjectionCacheEntry::NormalizedTy(value)); - assert!(!fresh_key, "never started projecting `{:?}`", key); - } - - /// Mark the relevant projection cache key as having its derived obligations - /// complete, so they won't have to be re-computed (this is OK to do in a - /// snapshot - if the snapshot is rolled back, the obligations will be - /// marked as incomplete again). - pub fn complete(&mut self, key: ProjectionCacheKey<'tcx>) { - let ty = match self.map.get(&key) { - Some(&ProjectionCacheEntry::NormalizedTy(ref ty)) => { - debug!("ProjectionCacheEntry::complete({:?}) - completing {:?}", key, ty); - ty.value - } - ref value => { - // Type inference could "strand behind" old cache entries. Leave - // them alone for now. - debug!("ProjectionCacheEntry::complete({:?}) - ignoring {:?}", key, value); - return; - } - }; - - self.map.insert( - key, - ProjectionCacheEntry::NormalizedTy(Normalized { value: ty, obligations: vec![] }), - ); - } - - /// A specialized version of `complete` for when the key's value is known - /// to be a NormalizedTy. - pub fn complete_normalized(&mut self, key: ProjectionCacheKey<'tcx>, ty: &NormalizedTy<'tcx>) { - // We want to insert `ty` with no obligations. If the existing value - // already has no obligations (as is common) we don't insert anything. - if !ty.obligations.is_empty() { - self.map.insert( - key, - ProjectionCacheEntry::NormalizedTy(Normalized { - value: ty.value, - obligations: vec![], - }), - ); - } - } - - /// Indicates that trying to normalize `key` resulted in - /// ambiguity. No point in trying it again then until we gain more - /// type information (in which case, the "fully resolved" key will - /// be different). - fn ambiguous(&mut self, key: ProjectionCacheKey<'tcx>) { - let fresh = self.map.insert(key, ProjectionCacheEntry::Ambiguous); - assert!(!fresh, "never started projecting `{:?}`", key); - } - - /// Indicates that trying to normalize `key` resulted in - /// error. - fn error(&mut self, key: ProjectionCacheKey<'tcx>) { - let fresh = self.map.insert(key, ProjectionCacheEntry::Error); - assert!(!fresh, "never started projecting `{:?}`", key); - } -} diff --git a/src/librustc/traits/types/query.rs b/src/librustc/traits/query.rs index c9055182620..c9055182620 100644 --- a/src/librustc/traits/types/query.rs +++ b/src/librustc/traits/query.rs diff --git a/src/librustc/traits/query/dropck_outlives.rs b/src/librustc/traits/query/dropck_outlives.rs deleted file mode 100644 index a1d7a2836e4..00000000000 --- a/src/librustc/traits/query/dropck_outlives.rs +++ /dev/null @@ -1,137 +0,0 @@ -use crate::infer::at::At; -use crate::infer::canonical::OriginalQueryValues; -use crate::infer::InferOk; - -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 - /// of "kinds" (types, regions) that must be outlive the execution - /// of the destructor. These basically correspond to data that the - /// destructor might access. This is used during regionck to - /// impose "outlives" constraints on any lifetimes referenced - /// within. - /// - /// The rules here are given by the "dropck" RFCs, notably [#1238] - /// and [#1327]. This is a fixed-point computation, where we - /// explore all the data that will be dropped (transitively) when - /// a value of type `ty` is dropped. For each type T that will be - /// dropped and which has a destructor, we must assume that all - /// the types/regions of T are live during the destructor, unless - /// they are marked with a special attribute (`#[may_dangle]`). - /// - /// [#1238]: https://github.com/rust-lang/rfcs/blob/master/text/1238-nonparametric-dropck.md - /// [#1327]: https://github.com/rust-lang/rfcs/blob/master/text/1327-dropck-param-eyepatch.md - pub fn dropck_outlives(&self, ty: Ty<'tcx>) -> InferOk<'tcx, Vec<GenericArg<'tcx>>> { - debug!("dropck_outlives(ty={:?}, param_env={:?})", ty, self.param_env,); - - // Quick check: there are a number of cases that we know do not require - // any destructor. - let tcx = self.infcx.tcx; - if trivial_dropck_outlives(tcx, ty) { - return InferOk { value: vec![], obligations: vec![] }; - } - - let mut orig_values = OriginalQueryValues::default(); - let c_ty = self.infcx.canonicalize_query(&self.param_env.and(ty), &mut orig_values); - let span = self.cause.span; - debug!("c_ty = {:?}", c_ty); - if let Ok(result) = &tcx.dropck_outlives(c_ty) { - if result.is_proven() { - if let Ok(InferOk { value, obligations }) = - self.infcx.instantiate_query_response_and_region_obligations( - self.cause, - self.param_env, - &orig_values, - result, - ) - { - let ty = self.infcx.resolve_vars_if_possible(&ty); - let kinds = value.into_kinds_reporting_overflows(tcx, span, ty); - return InferOk { value: kinds, obligations }; - } - } - } - - // Errors and ambiuity in dropck occur in two cases: - // - unresolved inference variables at the end of typeck - // - non well-formed types where projections cannot be resolved - // Either of these should have created an error before. - tcx.sess.delay_span_bug(span, "dtorck encountered internal error"); - - InferOk { value: vec![], obligations: vec![] } - } -} - -/// 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"), - } -} diff --git a/src/librustc/traits/query/evaluate_obligation.rs b/src/librustc/traits/query/evaluate_obligation.rs deleted file mode 100644 index b9ce3ccff27..00000000000 --- a/src/librustc/traits/query/evaluate_obligation.rs +++ /dev/null @@ -1,75 +0,0 @@ -use crate::infer::canonical::OriginalQueryValues; -use crate::infer::InferCtxt; -use crate::traits::{ - EvaluationResult, OverflowError, PredicateObligation, SelectionContext, TraitQueryMode, -}; - -impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { - /// Evaluates whether the predicate can be satisfied (by any means) - /// in the given `ParamEnv`. - pub fn predicate_may_hold(&self, obligation: &PredicateObligation<'tcx>) -> bool { - self.evaluate_obligation_no_overflow(obligation).may_apply() - } - - /// Evaluates whether the predicate can be satisfied in the given - /// `ParamEnv`, and returns `false` if not certain. However, this is - /// not entirely accurate if inference variables are involved. - /// - /// This version may conservatively fail when outlives obligations - /// are required. - pub fn predicate_must_hold_considering_regions( - &self, - obligation: &PredicateObligation<'tcx>, - ) -> bool { - self.evaluate_obligation_no_overflow(obligation).must_apply_considering_regions() - } - - /// Evaluates whether the predicate can be satisfied in the given - /// `ParamEnv`, and returns `false` if not certain. However, this is - /// not entirely accurate if inference variables are involved. - /// - /// This version ignores all outlives constraints. - pub fn predicate_must_hold_modulo_regions( - &self, - obligation: &PredicateObligation<'tcx>, - ) -> bool { - self.evaluate_obligation_no_overflow(obligation).must_apply_modulo_regions() - } - - /// Evaluate a given predicate, capturing overflow and propagating it back. - pub fn evaluate_obligation( - &self, - obligation: &PredicateObligation<'tcx>, - ) -> Result<EvaluationResult, OverflowError> { - let mut _orig_values = OriginalQueryValues::default(); - let c_pred = self - .canonicalize_query(&obligation.param_env.and(obligation.predicate), &mut _orig_values); - // Run canonical query. If overflow occurs, rerun from scratch but this time - // in standard trait query mode so that overflow is handled appropriately - // within `SelectionContext`. - self.tcx.evaluate_obligation(c_pred) - } - - // Helper function that canonicalizes and runs the query. If an - // overflow results, we re-run it in the local context so we can - // report a nice error. - crate fn evaluate_obligation_no_overflow( - &self, - obligation: &PredicateObligation<'tcx>, - ) -> EvaluationResult { - match self.evaluate_obligation(obligation) { - Ok(result) => result, - Err(OverflowError) => { - let mut selcx = SelectionContext::with_query_mode(&self, TraitQueryMode::Standard); - selcx.evaluate_root_obligation(obligation).unwrap_or_else(|r| { - span_bug!( - obligation.cause.span, - "Overflow should be caught earlier in standard query mode: {:?}, {:?}", - obligation, - r, - ) - }) - } - } - } -} diff --git a/src/librustc/traits/query/method_autoderef.rs b/src/librustc/traits/query/method_autoderef.rs deleted file mode 100644 index 80748c5ef38..00000000000 --- a/src/librustc/traits/query/method_autoderef.rs +++ /dev/null @@ -1 +0,0 @@ -pub use rustc::traits::query::{CandidateStep, MethodAutoderefBadTy, MethodAutoderefStepsResult}; diff --git a/src/librustc/traits/query/mod.rs b/src/librustc/traits/query/mod.rs deleted file mode 100644 index 20a873dc4c6..00000000000 --- a/src/librustc/traits/query/mod.rs +++ /dev/null @@ -1,15 +0,0 @@ -//! 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`. - -pub mod dropck_outlives; -pub mod evaluate_obligation; -pub mod method_autoderef; -pub mod normalize; -pub mod outlives_bounds; -pub mod type_op; - -pub use rustc::traits::types::query::*; diff --git a/src/librustc/traits/query/normalize.rs b/src/librustc/traits/query/normalize.rs deleted file mode 100644 index 737b4fc6bb9..00000000000 --- a/src/librustc/traits/query/normalize.rs +++ /dev/null @@ -1,189 +0,0 @@ -//! Code for the 'normalization' query. This consists of a wrapper -//! which folds deeply, invoking the underlying -//! `normalize_projection_ty` query when it encounters projections. - -use crate::infer::at::At; -use crate::infer::canonical::OriginalQueryValues; -use crate::infer::{InferCtxt, InferOk}; -use crate::traits::project::Normalized; -use crate::traits::{Obligation, ObligationCause, PredicateObligation, Reveal}; -use crate::ty::fold::{TypeFoldable, TypeFolder}; -use crate::ty::subst::Subst; -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 - /// normalized. If you don't care about regions, you should prefer - /// `normalize_erasing_regions`, which is more efficient. - /// - /// If the normalization succeeds and is unambiguous, returns back - /// the normalized value along with various outlives relations (in - /// the form of obligations that must be discharged). - /// - /// N.B., this will *eventually* be the main means of - /// normalizing, but for now should be used only when we actually - /// know that normalization will succeed, since error reporting - /// and other details are still "under development". - pub fn normalize<T>(&self, value: &T) -> Result<Normalized<'tcx, T>, NoSolution> - where - T: TypeFoldable<'tcx>, - { - debug!( - "normalize::<{}>(value={:?}, param_env={:?})", - ::std::any::type_name::<T>(), - value, - self.param_env, - ); - if !value.has_projections() { - return Ok(Normalized { value: value.clone(), obligations: vec![] }); - } - - let mut normalizer = QueryNormalizer { - infcx: self.infcx, - cause: self.cause, - param_env: self.param_env, - obligations: vec![], - error: false, - anon_depth: 0, - }; - - let value1 = value.fold_with(&mut normalizer); - if normalizer.error { - Err(NoSolution) - } else { - Ok(Normalized { value: value1, obligations: normalizer.obligations }) - } - } -} - -struct QueryNormalizer<'cx, 'tcx> { - infcx: &'cx InferCtxt<'cx, 'tcx>, - cause: &'cx ObligationCause<'tcx>, - param_env: ty::ParamEnv<'tcx>, - obligations: Vec<PredicateObligation<'tcx>>, - error: bool, - anon_depth: usize, -} - -impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { - fn tcx<'c>(&'c self) -> TyCtxt<'tcx> { - self.infcx.tcx - } - - fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - if !ty.has_projections() { - return ty; - } - - let ty = ty.super_fold_with(self); - match ty.kind { - ty::Opaque(def_id, substs) if !substs.has_escaping_bound_vars() => { - // (*) - // Only normalize `impl Trait` after type-checking, usually in codegen. - match self.param_env.reveal { - Reveal::UserFacing => ty, - - Reveal::All => { - let recursion_limit = *self.tcx().sess.recursion_limit.get(); - if self.anon_depth >= recursion_limit { - let obligation = Obligation::with_depth( - self.cause.clone(), - recursion_limit, - self.param_env, - ty, - ); - self.infcx.report_overflow_error(&obligation, true); - } - - let generic_ty = self.tcx().type_of(def_id); - let concrete_ty = generic_ty.subst(self.tcx(), substs); - self.anon_depth += 1; - if concrete_ty == ty { - bug!( - "infinite recursion generic_ty: {:#?}, substs: {:#?}, \ - concrete_ty: {:#?}, ty: {:#?}", - generic_ty, - substs, - concrete_ty, - ty - ); - } - let folded_ty = self.fold_ty(concrete_ty); - self.anon_depth -= 1; - folded_ty - } - } - } - - ty::Projection(ref data) if !data.has_escaping_bound_vars() => { - // (*) - // (*) This is kind of hacky -- we need to be able to - // handle normalization within binders because - // otherwise we wind up a need to normalize when doing - // trait matching (since you can have a trait - // obligation like `for<'a> T::B : Fn(&'a int)`), but - // we can't normalize with bound regions in scope. So - // far now we just ignore binders but only normalize - // if all bound regions are gone (and then we still - // have to renormalize whenever we instantiate a - // binder). It would be better to normalize in a - // binding-aware fashion. - - let tcx = self.infcx.tcx; - - let mut orig_values = OriginalQueryValues::default(); - // HACK(matthewjasper) `'static` is special-cased in selection, - // so we cannot canonicalize it. - let c_data = self - .infcx - .canonicalize_hr_query_hack(&self.param_env.and(*data), &mut orig_values); - debug!("QueryNormalizer: c_data = {:#?}", c_data); - debug!("QueryNormalizer: orig_values = {:#?}", orig_values); - match tcx.normalize_projection_ty(c_data) { - Ok(result) => { - // We don't expect ambiguity. - if result.is_ambiguous() { - self.error = true; - return ty; - } - - match self.infcx.instantiate_query_response_and_region_obligations( - self.cause, - self.param_env, - &orig_values, - &result, - ) { - Ok(InferOk { value: result, obligations }) => { - debug!("QueryNormalizer: result = {:#?}", result); - debug!("QueryNormalizer: obligations = {:#?}", obligations); - self.obligations.extend(obligations); - return result.normalized_ty; - } - - Err(_) => { - self.error = true; - return ty; - } - } - } - - Err(NoSolution) => { - self.error = true; - ty - } - } - } - - _ => ty, - } - } - - fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { - constant.eval(self.infcx.tcx, self.param_env) - } -} diff --git a/src/librustc/traits/query/outlives_bounds.rs b/src/librustc/traits/query/outlives_bounds.rs deleted file mode 100644 index 594faffa5f3..00000000000 --- a/src/librustc/traits/query/outlives_bounds.rs +++ /dev/null @@ -1,103 +0,0 @@ -use crate::infer::canonical::OriginalQueryValues; -use crate::infer::InferCtxt; -use crate::traits::query::NoSolution; -use crate::traits::{FulfillmentContext, ObligationCause, TraitEngine, TraitEngineExt}; -use crate::ty::{self, Ty}; -use rustc_hir as hir; -use rustc_span::source_map::Span; - -pub use rustc::traits::query::OutlivesBound; - -impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { - /// Implied bounds are region relationships that we deduce - /// automatically. The idea is that (e.g.) a caller must check that a - /// function's argument types are well-formed immediately before - /// calling that fn, and hence the *callee* can assume that its - /// argument types are well-formed. This may imply certain relationships - /// between generic parameters. For example: - /// - /// fn foo<'a,T>(x: &'a T) - /// - /// can only be called with a `'a` and `T` such that `&'a T` is WF. - /// For `&'a T` to be WF, `T: 'a` must hold. So we can assume `T: 'a`. - /// - /// # Parameters - /// - /// - `param_env`, the where-clauses in scope - /// - `body_id`, the body-id to use when normalizing assoc types. - /// Note that this may cause outlives obligations to be injected - /// into the inference context with this body-id. - /// - `ty`, the type that we are supposed to assume is WF. - /// - `span`, a span to use when normalizing, hopefully not important, - /// might be useful if a `bug!` occurs. - pub fn implied_outlives_bounds( - &self, - param_env: ty::ParamEnv<'tcx>, - body_id: hir::HirId, - ty: Ty<'tcx>, - span: Span, - ) -> Vec<OutlivesBound<'tcx>> { - debug!("implied_outlives_bounds(ty = {:?})", ty); - - let mut orig_values = OriginalQueryValues::default(); - let key = self.canonicalize_query(¶m_env.and(ty), &mut orig_values); - let result = match self.tcx.implied_outlives_bounds(key) { - Ok(r) => r, - Err(NoSolution) => { - self.tcx.sess.delay_span_bug( - span, - "implied_outlives_bounds failed to solve all obligations", - ); - return vec![]; - } - }; - assert!(result.value.is_proven()); - - let result = self.instantiate_query_response_and_region_obligations( - &ObligationCause::misc(span, body_id), - param_env, - &orig_values, - &result, - ); - debug!("implied_outlives_bounds for {:?}: {:#?}", ty, result); - let result = match result { - Ok(v) => v, - Err(_) => { - self.tcx.sess.delay_span_bug(span, "implied_outlives_bounds failed to instantiate"); - return vec![]; - } - }; - - // Instantiation may have produced new inference variables and constraints on those - // variables. Process these constraints. - let mut fulfill_cx = FulfillmentContext::new(); - fulfill_cx.register_predicate_obligations(self, result.obligations); - if fulfill_cx.select_all_or_error(self).is_err() { - self.tcx.sess.delay_span_bug( - span, - "implied_outlives_bounds failed to solve obligations from instantiation", - ); - } - - result.value - } -} - -pub fn explicit_outlives_bounds<'tcx>( - param_env: ty::ParamEnv<'tcx>, -) -> impl Iterator<Item = OutlivesBound<'tcx>> + 'tcx { - debug!("explicit_outlives_bounds()"); - param_env.caller_bounds.into_iter().filter_map(move |predicate| match predicate { - ty::Predicate::Projection(..) - | ty::Predicate::Trait(..) - | ty::Predicate::Subtype(..) - | ty::Predicate::WellFormed(..) - | ty::Predicate::ObjectSafe(..) - | ty::Predicate::ClosureKind(..) - | ty::Predicate::TypeOutlives(..) - | ty::Predicate::ConstEvaluatable(..) => None, - ty::Predicate::RegionOutlives(ref data) => data - .no_bound_vars() - .map(|ty::OutlivesPredicate(r_a, r_b)| OutlivesBound::RegionSubRegion(r_b, r_a)), - }) -} diff --git a/src/librustc/traits/query/type_op/ascribe_user_type.rs b/src/librustc/traits/query/type_op/ascribe_user_type.rs deleted file mode 100644 index b14b79f0907..00000000000 --- a/src/librustc/traits/query/type_op/ascribe_user_type.rs +++ /dev/null @@ -1,23 +0,0 @@ -use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse}; -use crate::traits::query::Fallible; -use rustc::ty::{ParamEnvAnd, TyCtxt}; - -pub use rustc::traits::query::type_op::AscribeUserType; - -impl<'tcx> super::QueryTypeOp<'tcx> for AscribeUserType<'tcx> { - type QueryResponse = (); - - fn try_fast_path( - _tcx: TyCtxt<'tcx>, - _key: &ParamEnvAnd<'tcx, Self>, - ) -> Option<Self::QueryResponse> { - None - } - - fn perform_query( - tcx: TyCtxt<'tcx>, - canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Self>>, - ) -> Fallible<CanonicalizedQueryResponse<'tcx, ()>> { - tcx.type_op_ascribe_user_type(canonicalized) - } -} diff --git a/src/librustc/traits/query/type_op/custom.rs b/src/librustc/traits/query/type_op/custom.rs deleted file mode 100644 index c1c9030b888..00000000000 --- a/src/librustc/traits/query/type_op/custom.rs +++ /dev/null @@ -1,106 +0,0 @@ -use crate::infer::{InferCtxt, InferOk}; -use crate::traits::query::Fallible; -use std::fmt; - -use crate::infer::canonical::query_response; -use crate::infer::canonical::QueryRegionConstraints; -use crate::traits::{ObligationCause, TraitEngine, TraitEngineExt}; -use rustc_span::source_map::DUMMY_SP; -use std::rc::Rc; - -pub struct CustomTypeOp<F, G> { - closure: F, - description: G, -} - -impl<F, G> CustomTypeOp<F, G> { - pub fn new<'tcx, R>(closure: F, description: G) -> Self - where - F: FnOnce(&InferCtxt<'_, 'tcx>) -> Fallible<InferOk<'tcx, R>>, - G: Fn() -> String, - { - CustomTypeOp { closure, description } - } -} - -impl<'tcx, F, R, G> super::TypeOp<'tcx> for CustomTypeOp<F, G> -where - F: for<'a, 'cx> FnOnce(&'a InferCtxt<'cx, 'tcx>) -> Fallible<InferOk<'tcx, R>>, - G: Fn() -> String, -{ - type Output = R; - - /// Processes the operation and all resulting obligations, - /// returning the final result along with any region constraints - /// (they will be given over to the NLL region solver). - fn fully_perform( - self, - infcx: &InferCtxt<'_, 'tcx>, - ) -> Fallible<(Self::Output, Option<Rc<QueryRegionConstraints<'tcx>>>)> { - if cfg!(debug_assertions) { - info!("fully_perform({:?})", self); - } - - scrape_region_constraints(infcx, || Ok((self.closure)(infcx)?)) - } -} - -impl<F, G> fmt::Debug for CustomTypeOp<F, G> -where - G: Fn() -> String, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", (self.description)()) - } -} - -/// Executes `op` and then scrapes out all the "old style" region -/// constraints that result, creating query-region-constraints. -fn scrape_region_constraints<'tcx, R>( - infcx: &InferCtxt<'_, 'tcx>, - op: impl FnOnce() -> Fallible<InferOk<'tcx, R>>, -) -> Fallible<(R, Option<Rc<QueryRegionConstraints<'tcx>>>)> { - let mut fulfill_cx = TraitEngine::new(infcx.tcx); - let dummy_body_id = ObligationCause::dummy().body_id; - - // During NLL, we expect that nobody will register region - // obligations **except** as part of a custom type op (and, at the - // end of each custom type op, we scrape out the region - // obligations that resulted). So this vector should be empty on - // entry. - let pre_obligations = infcx.take_registered_region_obligations(); - assert!( - pre_obligations.is_empty(), - "scrape_region_constraints: incoming region obligations = {:#?}", - pre_obligations, - ); - - let InferOk { value, obligations } = infcx.commit_if_ok(|_| op())?; - debug_assert!(obligations.iter().all(|o| o.cause.body_id == dummy_body_id)); - fulfill_cx.register_predicate_obligations(infcx, obligations); - if let Err(e) = fulfill_cx.select_all_or_error(infcx) { - infcx.tcx.sess.diagnostic().delay_span_bug( - DUMMY_SP, - &format!("errors selecting obligation during MIR typeck: {:?}", e), - ); - } - - let region_obligations = infcx.take_registered_region_obligations(); - - let region_constraint_data = infcx.take_and_reset_region_constraints(); - - let region_constraints = query_response::make_query_region_constraints( - infcx.tcx, - region_obligations - .iter() - .map(|(_, r_o)| (r_o.sup_type, r_o.sub_region)) - .map(|(ty, r)| (infcx.resolve_vars_if_possible(&ty), r)), - ®ion_constraint_data, - ); - - if region_constraints.is_empty() { - Ok((value, None)) - } else { - Ok((value, Some(Rc::new(region_constraints)))) - } -} diff --git a/src/librustc/traits/query/type_op/eq.rs b/src/librustc/traits/query/type_op/eq.rs deleted file mode 100644 index 1de13430d46..00000000000 --- a/src/librustc/traits/query/type_op/eq.rs +++ /dev/null @@ -1,23 +0,0 @@ -use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse}; -use crate::traits::query::Fallible; -use crate::ty::{ParamEnvAnd, TyCtxt}; - -pub use rustc::traits::query::type_op::Eq; - -impl<'tcx> super::QueryTypeOp<'tcx> for Eq<'tcx> { - type QueryResponse = (); - - fn try_fast_path( - _tcx: TyCtxt<'tcx>, - key: &ParamEnvAnd<'tcx, Eq<'tcx>>, - ) -> Option<Self::QueryResponse> { - if key.value.a == key.value.b { Some(()) } else { None } - } - - fn perform_query( - tcx: TyCtxt<'tcx>, - canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Self>>, - ) -> Fallible<CanonicalizedQueryResponse<'tcx, ()>> { - tcx.type_op_eq(canonicalized) - } -} diff --git a/src/librustc/traits/query/type_op/implied_outlives_bounds.rs b/src/librustc/traits/query/type_op/implied_outlives_bounds.rs deleted file mode 100644 index 6f45d76a8e9..00000000000 --- a/src/librustc/traits/query/type_op/implied_outlives_bounds.rs +++ /dev/null @@ -1,41 +0,0 @@ -use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse}; -use crate::traits::query::outlives_bounds::OutlivesBound; -use crate::traits::query::Fallible; -use crate::ty::{ParamEnvAnd, Ty, TyCtxt}; - -#[derive(Clone, Debug, HashStable, TypeFoldable, Lift)] -pub struct ImpliedOutlivesBounds<'tcx> { - pub ty: Ty<'tcx>, -} - -impl<'tcx> ImpliedOutlivesBounds<'tcx> { - pub fn new(ty: Ty<'tcx>) -> Self { - ImpliedOutlivesBounds { ty } - } -} - -impl<'tcx> super::QueryTypeOp<'tcx> for ImpliedOutlivesBounds<'tcx> { - type QueryResponse = Vec<OutlivesBound<'tcx>>; - - fn try_fast_path( - _tcx: TyCtxt<'tcx>, - _key: &ParamEnvAnd<'tcx, Self>, - ) -> Option<Self::QueryResponse> { - None - } - - fn perform_query( - tcx: TyCtxt<'tcx>, - canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Self>>, - ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self::QueryResponse>> { - // FIXME this `unchecked_map` is only necessary because the - // query is defined as taking a `ParamEnvAnd<Ty>`; it should - // take a `ImpliedOutlivesBounds` instead - let canonicalized = canonicalized.unchecked_map(|ParamEnvAnd { param_env, value }| { - let ImpliedOutlivesBounds { ty } = value; - param_env.and(ty) - }); - - tcx.implied_outlives_bounds(canonicalized) - } -} diff --git a/src/librustc/traits/query/type_op/mod.rs b/src/librustc/traits/query/type_op/mod.rs deleted file mode 100644 index 2d03d77cf66..00000000000 --- a/src/librustc/traits/query/type_op/mod.rs +++ /dev/null @@ -1,136 +0,0 @@ -use crate::infer::canonical::{ - Canonicalized, CanonicalizedQueryResponse, OriginalQueryValues, QueryRegionConstraints, -}; -use crate::infer::{InferCtxt, InferOk}; -use crate::traits::query::Fallible; -use crate::traits::ObligationCause; -use crate::ty::fold::TypeFoldable; -use crate::ty::{ParamEnvAnd, TyCtxt}; -use std::fmt; -use std::rc::Rc; - -pub mod ascribe_user_type; -pub mod custom; -pub mod eq; -pub mod implied_outlives_bounds; -pub mod normalize; -pub mod outlives; -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). -pub trait TypeOp<'tcx>: Sized + fmt::Debug { - type Output; - - /// Processes the operation and all resulting obligations, - /// returning the final result along with any region constraints - /// (they will be given over to the NLL region solver). - fn fully_perform( - self, - infcx: &InferCtxt<'_, 'tcx>, - ) -> Fallible<(Self::Output, Option<Rc<QueryRegionConstraints<'tcx>>>)>; -} - -/// "Query type ops" are type ops that are implemented using a -/// [canonical query][c]. The `Self` type here contains the kernel of -/// information needed to do the operation -- `TypeOp` is actually -/// implemented for `ParamEnvAnd<Self>`, since we always need to bring -/// along a parameter environment as well. For query type-ops, we will -/// first canonicalize the key and then invoke the query on the tcx, -/// which produces the resulting query region constraints. -/// -/// [c]: https://rust-lang.github.io/rustc-guide/traits/canonicalization.html -pub trait QueryTypeOp<'tcx>: fmt::Debug + Sized + TypeFoldable<'tcx> + 'tcx { - type QueryResponse: TypeFoldable<'tcx>; - - /// Give query the option for a simple fast path that never - /// actually hits the tcx cache lookup etc. Return `Some(r)` with - /// a final result or `None` to do the full path. - fn try_fast_path( - tcx: TyCtxt<'tcx>, - key: &ParamEnvAnd<'tcx, Self>, - ) -> Option<Self::QueryResponse>; - - /// Performs the actual query with the canonicalized key -- the - /// real work happens here. This method is not given an `infcx` - /// because it shouldn't need one -- and if it had access to one, - /// it might do things like invoke `sub_regions`, which would be - /// bad, because it would create subregion relationships that are - /// not captured in the return value. - fn perform_query( - tcx: TyCtxt<'tcx>, - canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Self>>, - ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self::QueryResponse>>; - - fn fully_perform_into( - query_key: ParamEnvAnd<'tcx, Self>, - infcx: &InferCtxt<'_, 'tcx>, - output_query_region_constraints: &mut QueryRegionConstraints<'tcx>, - ) -> Fallible<Self::QueryResponse> { - if let Some(result) = QueryTypeOp::try_fast_path(infcx.tcx, &query_key) { - return Ok(result); - } - - // FIXME(#33684) -- We need to use - // `canonicalize_hr_query_hack` here because of things - // like the subtype query, which go awry around - // `'static` otherwise. - let mut canonical_var_values = OriginalQueryValues::default(); - let canonical_self = - infcx.canonicalize_hr_query_hack(&query_key, &mut canonical_var_values); - let canonical_result = Self::perform_query(infcx.tcx, canonical_self)?; - - let param_env = query_key.param_env; - - let InferOk { value, obligations } = infcx - .instantiate_nll_query_response_and_region_obligations( - &ObligationCause::dummy(), - param_env, - &canonical_var_values, - canonical_result, - output_query_region_constraints, - )?; - - // Typically, instantiating NLL query results does not - // create obligations. However, in some cases there - // are unresolved type variables, and unify them *can* - // create obligations. In that case, we have to go - // fulfill them. We do this via a (recursive) query. - for obligation in obligations { - let () = ProvePredicate::fully_perform_into( - obligation.param_env.and(ProvePredicate::new(obligation.predicate)), - infcx, - output_query_region_constraints, - )?; - } - - Ok(value) - } -} - -impl<'tcx, Q> TypeOp<'tcx> for ParamEnvAnd<'tcx, Q> -where - Q: QueryTypeOp<'tcx>, -{ - type Output = Q::QueryResponse; - - fn fully_perform( - self, - infcx: &InferCtxt<'_, 'tcx>, - ) -> Fallible<(Self::Output, Option<Rc<QueryRegionConstraints<'tcx>>>)> { - let mut region_constraints = QueryRegionConstraints::default(); - let r = Q::fully_perform_into(self, infcx, &mut region_constraints)?; - - // Promote the final query-region-constraints into a - // (optional) ref-counted vector: - let opt_qrc = - if region_constraints.is_empty() { None } else { Some(Rc::new(region_constraints)) }; - - Ok((r, opt_qrc)) - } -} diff --git a/src/librustc/traits/query/type_op/normalize.rs b/src/librustc/traits/query/type_op/normalize.rs deleted file mode 100644 index b1e0e29620d..00000000000 --- a/src/librustc/traits/query/type_op/normalize.rs +++ /dev/null @@ -1,68 +0,0 @@ -use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse}; -use crate::traits::query::Fallible; -use crate::ty::fold::TypeFoldable; -use crate::ty::{self, Lift, ParamEnvAnd, Ty, TyCtxt}; -use std::fmt; - -pub use rustc::traits::query::type_op::Normalize; - -impl<'tcx, T> super::QueryTypeOp<'tcx> for Normalize<T> -where - T: Normalizable<'tcx> + 'tcx, -{ - type QueryResponse = T; - - fn try_fast_path(_tcx: TyCtxt<'tcx>, key: &ParamEnvAnd<'tcx, Self>) -> Option<T> { - if !key.value.value.has_projections() { Some(key.value.value) } else { None } - } - - fn perform_query( - tcx: TyCtxt<'tcx>, - canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Self>>, - ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self::QueryResponse>> { - T::type_op_method(tcx, canonicalized) - } -} - -pub trait Normalizable<'tcx>: fmt::Debug + TypeFoldable<'tcx> + Lift<'tcx> + Copy { - fn type_op_method( - tcx: TyCtxt<'tcx>, - canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>, - ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self>>; -} - -impl Normalizable<'tcx> for Ty<'tcx> { - fn type_op_method( - tcx: TyCtxt<'tcx>, - canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>, - ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self>> { - tcx.type_op_normalize_ty(canonicalized) - } -} - -impl Normalizable<'tcx> for ty::Predicate<'tcx> { - fn type_op_method( - tcx: TyCtxt<'tcx>, - canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>, - ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self>> { - tcx.type_op_normalize_predicate(canonicalized) - } -} - -impl Normalizable<'tcx> for ty::PolyFnSig<'tcx> { - fn type_op_method( - tcx: TyCtxt<'tcx>, - canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>, - ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self>> { - tcx.type_op_normalize_poly_fn_sig(canonicalized) - } -} - -impl Normalizable<'tcx> for ty::FnSig<'tcx> { - fn type_op_method( - tcx: TyCtxt<'tcx>, - canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>, - ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self>> { - tcx.type_op_normalize_fn_sig(canonicalized) - } -} diff --git a/src/librustc/traits/query/type_op/outlives.rs b/src/librustc/traits/query/type_op/outlives.rs deleted file mode 100644 index 35afa637968..00000000000 --- a/src/librustc/traits/query/type_op/outlives.rs +++ /dev/null @@ -1,55 +0,0 @@ -use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse}; -use crate::traits::query::dropck_outlives::{trivial_dropck_outlives, DropckOutlivesResult}; -use crate::traits::query::Fallible; -use crate::ty::{ParamEnvAnd, Ty, TyCtxt}; - -#[derive(Copy, Clone, Debug, HashStable, TypeFoldable, Lift)] -pub struct DropckOutlives<'tcx> { - dropped_ty: Ty<'tcx>, -} - -impl<'tcx> DropckOutlives<'tcx> { - pub fn new(dropped_ty: Ty<'tcx>) -> Self { - DropckOutlives { dropped_ty } - } -} - -impl super::QueryTypeOp<'tcx> for DropckOutlives<'tcx> { - type QueryResponse = DropckOutlivesResult<'tcx>; - - fn try_fast_path( - tcx: TyCtxt<'tcx>, - key: &ParamEnvAnd<'tcx, Self>, - ) -> Option<Self::QueryResponse> { - if trivial_dropck_outlives(tcx, key.value.dropped_ty) { - Some(DropckOutlivesResult::default()) - } else { - None - } - } - - fn perform_query( - tcx: TyCtxt<'tcx>, - canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Self>>, - ) -> Fallible<CanonicalizedQueryResponse<'tcx, Self::QueryResponse>> { - // Subtle: note that we are not invoking - // `infcx.at(...).dropck_outlives(...)` here, but rather the - // underlying `dropck_outlives` query. This same underlying - // query is also used by the - // `infcx.at(...).dropck_outlives(...)` fn. Avoiding the - // wrapper means we don't need an infcx in this code, which is - // good because the interface doesn't give us one (so that we - // know we are not registering any subregion relations or - // other things). - - // FIXME convert to the type expected by the `dropck_outlives` - // query. This should eventually be fixed by changing the - // *underlying query*. - let canonicalized = canonicalized.unchecked_map(|ParamEnvAnd { param_env, value }| { - let DropckOutlives { dropped_ty } = value; - param_env.and(dropped_ty) - }); - - tcx.dropck_outlives(canonicalized) - } -} diff --git a/src/librustc/traits/query/type_op/prove_predicate.rs b/src/librustc/traits/query/type_op/prove_predicate.rs deleted file mode 100644 index 92cfb82e27e..00000000000 --- a/src/librustc/traits/query/type_op/prove_predicate.rs +++ /dev/null @@ -1,37 +0,0 @@ -use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse}; -use crate::traits::query::Fallible; -use crate::ty::{ParamEnvAnd, Predicate, TyCtxt}; - -pub use rustc::traits::query::type_op::ProvePredicate; - -impl<'tcx> super::QueryTypeOp<'tcx> for ProvePredicate<'tcx> { - type QueryResponse = (); - - fn try_fast_path( - tcx: TyCtxt<'tcx>, - key: &ParamEnvAnd<'tcx, Self>, - ) -> Option<Self::QueryResponse> { - // Proving Sized, very often on "obviously sized" types like - // `&T`, accounts for about 60% percentage of the predicates - // we have to prove. No need to canonicalize and all that for - // such cases. - if let Predicate::Trait(trait_ref, _) = key.value.predicate { - if let Some(sized_def_id) = tcx.lang_items().sized_trait() { - if trait_ref.def_id() == sized_def_id { - if trait_ref.skip_binder().self_ty().is_trivially_sized(tcx) { - return Some(()); - } - } - } - } - - None - } - - fn perform_query( - tcx: TyCtxt<'tcx>, - canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Self>>, - ) -> Fallible<CanonicalizedQueryResponse<'tcx, ()>> { - tcx.type_op_prove_predicate(canonicalized) - } -} diff --git a/src/librustc/traits/query/type_op/subtype.rs b/src/librustc/traits/query/type_op/subtype.rs deleted file mode 100644 index 2877a74aaff..00000000000 --- a/src/librustc/traits/query/type_op/subtype.rs +++ /dev/null @@ -1,20 +0,0 @@ -use crate::infer::canonical::{Canonicalized, CanonicalizedQueryResponse}; -use crate::traits::query::Fallible; -use crate::ty::{ParamEnvAnd, TyCtxt}; - -pub use rustc::traits::query::type_op::Subtype; - -impl<'tcx> super::QueryTypeOp<'tcx> for Subtype<'tcx> { - type QueryResponse = (); - - fn try_fast_path(_tcx: TyCtxt<'tcx>, key: &ParamEnvAnd<'tcx, Self>) -> Option<()> { - if key.value.sub == key.value.sup { Some(()) } else { None } - } - - fn perform_query( - tcx: TyCtxt<'tcx>, - canonicalized: Canonicalized<'tcx, ParamEnvAnd<'tcx, Self>>, - ) -> Fallible<CanonicalizedQueryResponse<'tcx, ()>> { - tcx.type_op_subtype(canonicalized) - } -} diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 1fe8ab58d15..ac3d0049c0c 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1,3832 +1,290 @@ -// ignore-tidy-filelength - //! 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 self::SelectionCandidate::*; - -use super::coherence::{self, Conflict}; -use super::project; -use super::project::{ - normalize_with_depth, normalize_with_depth_to, Normalized, ProjectionCacheKey, -}; -use super::util; -use super::util::{closure_trait_ref_and_return_type, predicate_for_trait_def}; -use super::wf; -use super::DerivedObligationCause; -use super::Selection; -use super::SelectionResult; -use super::TraitNotObjectSafe; -use super::TraitQueryMode; -use super::{BuiltinDerivedObligation, ImplDerivedObligation, ObligationCauseCode}; -use super::{ObjectCastObligation, Obligation}; -use super::{ObligationCause, PredicateObligation, TraitObligation}; -use super::{OutputTypeParameterMismatch, Overflow, SelectionError, Unimplemented}; -use super::{ - VtableAutoImpl, VtableBuiltin, VtableClosure, VtableFnPointer, VtableGenerator, VtableImpl, - VtableObject, VtableParam, VtableTraitAlias, -}; -use super::{ - VtableAutoImplData, VtableBuiltinData, VtableClosureData, VtableFnPointerData, - VtableGeneratorData, VtableImplData, VtableObjectData, VtableTraitAliasData, -}; - -use crate::dep_graph::{DepKind, DepNodeIndex}; -use crate::infer::{CombinedSnapshot, InferCtxt, InferOk, PlaceholderMap, TypeFreshener}; -use crate::middle::lang_items; -use crate::ty::fast_reject; -use crate::ty::relate::TypeRelation; -use crate::ty::subst::{Subst, SubstsRef}; -use crate::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness}; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_hir as hir; -use rustc_hir::def_id::DefId; -use rustc_index::bit_set::GrowableBitSet; -use rustc_span::symbol::sym; -use rustc_target::spec::abi::Abi; -use syntax::attr; - -use std::cell::{Cell, RefCell}; -use std::cmp; -use std::fmt::{self, Display}; -use std::iter; -use std::rc::Rc; - -pub use rustc::traits::types::select::*; -pub struct SelectionContext<'cx, 'tcx> { - infcx: &'cx InferCtxt<'cx, 'tcx>, +use super::{SelectionError, SelectionResult}; - /// Freshener used specifically for entries on the obligation - /// stack. This ensures that all entries on the stack at one time - /// will have the same set of placeholder entries, which is - /// important for checking for trait bounds that recursively - /// require themselves. - freshener: TypeFreshener<'cx, 'tcx>, +use crate::dep_graph::DepNodeIndex; +use crate::ty::{self, TyCtxt}; - /// If `true`, indicates that the evaluation should be conservative - /// and consider the possibility of types outside this crate. - /// This comes up primarily when resolving ambiguity. Imagine - /// there is some trait reference `$0: Bar` where `$0` is an - /// inference variable. If `intercrate` is true, then we can never - /// say for sure that this reference is not implemented, even if - /// there are *no impls at all for `Bar`*, because `$0` could be - /// bound to some type that in a downstream crate that implements - /// `Bar`. This is the suitable mode for coherence. Elsewhere, - /// though, we set this to false, because we are only interested - /// in types that the user could actually have written --- in - /// other words, we consider `$0: Bar` to be unimplemented if - /// there is no type that the user could *actually name* that - /// would satisfy it. This avoids crippling inference, basically. - intercrate: bool, - - intercrate_ambiguity_causes: Option<Vec<IntercrateAmbiguityCause>>, - - /// Controls whether or not to filter out negative impls when selecting. - /// This is used in librustdoc to distinguish between the lack of an impl - /// and a negative impl - allow_negative_impls: bool, - - /// The mode that trait queries run in, which informs our error handling - /// policy. In essence, canonicalized queries need their errors propagated - /// rather than immediately reported because we do not have accurate spans. - query_mode: TraitQueryMode, -} +use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::sync::Lock; +use rustc_hir::def_id::DefId; -#[derive(Clone, Debug)] -pub enum IntercrateAmbiguityCause { - DownstreamCrate { trait_desc: String, self_desc: Option<String> }, - UpstreamCrateUpdate { trait_desc: String, self_desc: Option<String> }, - ReservationImpl { message: String }, +#[derive(Clone, Default)] +pub struct SelectionCache<'tcx> { + pub hashmap: Lock< + FxHashMap< + ty::ParamEnvAnd<'tcx, ty::TraitRef<'tcx>>, + WithDepNode<SelectionResult<'tcx, SelectionCandidate<'tcx>>>, + >, + >, } -impl IntercrateAmbiguityCause { - /// Emits notes when the overlap is caused by complex intercrate ambiguities. - /// See #23980 for details. - pub fn add_intercrate_ambiguity_hint(&self, err: &mut rustc_errors::DiagnosticBuilder<'_>) { - err.note(&self.intercrate_ambiguity_hint()); - } - - pub fn intercrate_ambiguity_hint(&self) -> String { - match self { - &IntercrateAmbiguityCause::DownstreamCrate { ref trait_desc, ref self_desc } => { - let self_desc = if let &Some(ref ty) = self_desc { - format!(" for type `{}`", ty) - } else { - String::new() - }; - format!("downstream crates may implement trait `{}`{}", trait_desc, self_desc) - } - &IntercrateAmbiguityCause::UpstreamCrateUpdate { ref trait_desc, ref self_desc } => { - let self_desc = if let &Some(ref ty) = self_desc { - format!(" for type `{}`", ty) - } else { - String::new() - }; - format!( - "upstream crates may add a new impl of trait `{}`{} \ - in future versions", - trait_desc, self_desc - ) - } - &IntercrateAmbiguityCause::ReservationImpl { ref message } => message.clone(), - } +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(); } } -// A stack that walks back up the stack frame. -struct TraitObligationStack<'prev, 'tcx> { - obligation: &'prev TraitObligation<'tcx>, - - /// The trait ref from `obligation` but "freshened" with the - /// selection-context's freshener. Used to check for recursion. - fresh_trait_ref: ty::PolyTraitRef<'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)] +pub enum SelectionCandidate<'tcx> { + BuiltinCandidate { + /// `false` if there are no *further* obligations. + has_nested: bool, + }, + ParamCandidate(ty::PolyTraitRef<'tcx>), + ImplCandidate(DefId), + AutoImplCandidate(DefId), - /// Starts out equal to `depth` -- if, during evaluation, we - /// encounter a cycle, then we will set this flag to the minimum - /// depth of that cycle for all participants in the cycle. These - /// participants will then forego caching their results. This is - /// not the most efficient solution, but it addresses #60010. The - /// problem we are trying to prevent: - /// - /// - If you have `A: AutoTrait` requires `B: AutoTrait` and `C: NonAutoTrait` - /// - `B: AutoTrait` requires `A: AutoTrait` (coinductive cycle, ok) - /// - `C: NonAutoTrait` requires `A: AutoTrait` (non-coinductive cycle, not ok) - /// - /// you don't want to cache that `B: AutoTrait` or `A: AutoTrait` - /// is `EvaluatedToOk`; this is because they were only considered - /// ok on the premise that if `A: AutoTrait` held, but we indeed - /// encountered a problem (later on) with `A: AutoTrait. So we - /// currently set a flag on the stack node for `B: AutoTrait` (as - /// well as the second instance of `A: AutoTrait`) to suppress - /// caching. - /// - /// This is a simple, targeted fix. A more-performant fix requires - /// deeper changes, but would permit more caching: we could - /// basically defer caching until we have fully evaluated the - /// tree, and then cache the entire tree at once. In any case, the - /// performance impact here shouldn't be so horrible: every time - /// this is hit, we do cache at least one trait, so we only - /// evaluate each member of a cycle up to N times, where N is the - /// length of the cycle. This means the performance impact is - /// bounded and we shouldn't have any terrible worst-cases. - reached_depth: Cell<usize>, + /// This is a trait matching with a projected type as `Self`, and + /// we found an applicable bound in the trait definition. + ProjectionCandidate, - previous: TraitObligationStackList<'prev, 'tcx>, + /// Implementation of a `Fn`-family trait by one of the anonymous types + /// generated for a `||` expression. + ClosureCandidate, - /// The number of parent frames plus one (thus, the topmost frame has depth 1). - depth: usize, + /// Implementation of a `Generator` trait by one of the anonymous types + /// generated for a generator. + GeneratorCandidate, - /// The depth-first number of this node in the search graph -- a - /// pre-order index. Basically, a freshly incremented counter. - dfn: usize, -} + /// Implementation of a `Fn`-family trait by one of the anonymous + /// types generated for a fn pointer type (e.g., `fn(int) -> int`) + FnPointerCandidate, -struct SelectionCandidateSet<'tcx> { - // A list of candidates that definitely apply to the current - // obligation (meaning: types unify). - vec: Vec<SelectionCandidate<'tcx>>, + TraitAliasCandidate(DefId), - // If `true`, then there were candidates that might or might - // not have applied, but we couldn't tell. This occurs when some - // of the input types are type variables, in which case there are - // various "builtin" rules that might or might not trigger. - ambiguous: bool, -} + ObjectCandidate, -#[derive(PartialEq, Eq, Debug, Clone)] -struct EvaluatedCandidate<'tcx> { - candidate: SelectionCandidate<'tcx>, - evaluation: EvaluationResult, -} + BuiltinObjectCandidate, -/// When does the builtin impl for `T: Trait` apply? -enum BuiltinImplConditions<'tcx> { - /// The impl is conditional on `T1, T2, ...: Trait`. - Where(ty::Binder<Vec<Ty<'tcx>>>), - /// There is no built-in impl. There may be some other - /// candidate (a where-clause or user-defined impl). - None, - /// It is unknown whether there is an impl. - Ambiguous, + BuiltinUnsizeCandidate, } -impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { - pub fn new(infcx: &'cx InferCtxt<'cx, 'tcx>) -> SelectionContext<'cx, 'tcx> { - SelectionContext { - infcx, - freshener: infcx.freshener(), - intercrate: false, - intercrate_ambiguity_causes: None, - allow_negative_impls: false, - query_mode: TraitQueryMode::Standard, - } - } - - pub fn intercrate(infcx: &'cx InferCtxt<'cx, 'tcx>) -> SelectionContext<'cx, 'tcx> { - SelectionContext { - infcx, - freshener: infcx.freshener(), - intercrate: true, - intercrate_ambiguity_causes: None, - allow_negative_impls: false, - query_mode: TraitQueryMode::Standard, - } - } - - pub fn with_negative( - infcx: &'cx InferCtxt<'cx, 'tcx>, - allow_negative_impls: bool, - ) -> SelectionContext<'cx, 'tcx> { - debug!("with_negative({:?})", allow_negative_impls); - SelectionContext { - infcx, - freshener: infcx.freshener(), - intercrate: false, - intercrate_ambiguity_causes: None, - allow_negative_impls, - query_mode: TraitQueryMode::Standard, - } - } - - pub fn with_query_mode( - infcx: &'cx InferCtxt<'cx, 'tcx>, - query_mode: TraitQueryMode, - ) -> SelectionContext<'cx, 'tcx> { - debug!("with_query_mode({:?})", query_mode); - SelectionContext { - infcx, - freshener: infcx.freshener(), - intercrate: false, - intercrate_ambiguity_causes: None, - allow_negative_impls: false, - query_mode, - } - } - - /// Enables tracking of intercrate ambiguity causes. These are - /// used in coherence to give improved diagnostics. We don't do - /// this until we detect a coherence error because it can lead to - /// false overflow results (#47139) and because it costs - /// computation time. - pub fn enable_tracking_intercrate_ambiguity_causes(&mut self) { - assert!(self.intercrate); - assert!(self.intercrate_ambiguity_causes.is_none()); - self.intercrate_ambiguity_causes = Some(vec![]); - debug!("selcx: enable_tracking_intercrate_ambiguity_causes"); - } - - /// Gets the intercrate ambiguity causes collected since tracking - /// was enabled and disables tracking at the same time. If - /// tracking is not enabled, just returns an empty vector. - pub fn take_intercrate_ambiguity_causes(&mut self) -> Vec<IntercrateAmbiguityCause> { - assert!(self.intercrate); - self.intercrate_ambiguity_causes.take().unwrap_or(vec![]) - } - - pub fn infcx(&self) -> &'cx InferCtxt<'cx, 'tcx> { - self.infcx - } - - pub fn tcx(&self) -> TyCtxt<'tcx> { - self.infcx.tcx - } - - pub fn closure_typer(&self) -> &'cx InferCtxt<'cx, 'tcx> { - self.infcx - } - - /////////////////////////////////////////////////////////////////////////// - // Selection - // - // The selection phase tries to identify *how* an obligation will - // be resolved. For example, it will identify which impl or - // parameter bound is to be used. The process can be inconclusive - // if the self type in the obligation is not fully inferred. Selection - // can result in an error in one of two ways: - // - // 1. If no applicable impl or parameter bound can be found. - // 2. If the output type parameters in the obligation do not match - // those specified by the impl/bound. For example, if the obligation - // is `Vec<Foo>: Iterable<Bar>`, but the impl specifies - // `impl<T> Iterable<T> for Vec<T>`, than an error would result. - - /// Attempts to satisfy the obligation. If successful, this will affect the surrounding - /// type environment by performing unification. - pub fn select( - &mut self, - obligation: &TraitObligation<'tcx>, - ) -> SelectionResult<'tcx, Selection<'tcx>> { - debug!("select({:?})", obligation); - debug_assert!(!obligation.predicate.has_escaping_bound_vars()); - - let pec = &ProvisionalEvaluationCache::default(); - let stack = self.push_stack(TraitObligationStackList::empty(pec), obligation); - - let candidate = match self.candidate_from_obligation(&stack) { - Err(SelectionError::Overflow) => { - // In standard mode, overflow must have been caught and reported - // earlier. - assert!(self.query_mode == TraitQueryMode::Canonical); - return Err(SelectionError::Overflow); - } - Err(e) => { - return Err(e); - } - Ok(None) => { - return Ok(None); - } - Ok(Some(candidate)) => candidate, - }; - - match self.confirm_candidate(obligation, candidate) { - Err(SelectionError::Overflow) => { - assert!(self.query_mode == TraitQueryMode::Canonical); - Err(SelectionError::Overflow) - } - Err(e) => Err(e), - Ok(candidate) => Ok(Some(candidate)), - } - } - - /////////////////////////////////////////////////////////////////////////// - // EVALUATION - // - // Tests whether an obligation can be selected or whether an impl - // can be applied to particular types. It skips the "confirmation" - // step and hence completely ignores output type parameters. - // - // The result is "true" if the obligation *may* hold and "false" if - // we can be sure it does not. - - /// Evaluates whether the obligation `obligation` can be satisfied (by any means). - pub fn predicate_may_hold_fatal(&mut self, obligation: &PredicateObligation<'tcx>) -> bool { - debug!("predicate_may_hold_fatal({:?})", obligation); - - // This fatal query is a stopgap that should only be used in standard mode, - // where we do not expect overflow to be propagated. - assert!(self.query_mode == TraitQueryMode::Standard); - - self.evaluate_root_obligation(obligation) - .expect("Overflow should be caught earlier in standard query mode") - .may_apply() - } - - /// Evaluates whether the obligation `obligation` can be satisfied - /// and returns an `EvaluationResult`. This is meant for the - /// *initial* call. - pub fn evaluate_root_obligation( - &mut self, - obligation: &PredicateObligation<'tcx>, - ) -> Result<EvaluationResult, OverflowError> { - self.evaluation_probe(|this| { - this.evaluate_predicate_recursively( - TraitObligationStackList::empty(&ProvisionalEvaluationCache::default()), - obligation.clone(), - ) - }) - } - - fn evaluation_probe( - &mut self, - op: impl FnOnce(&mut Self) -> Result<EvaluationResult, OverflowError>, - ) -> Result<EvaluationResult, OverflowError> { - self.infcx.probe(|snapshot| -> Result<EvaluationResult, OverflowError> { - let result = op(self)?; - match self.infcx.region_constraints_added_in_snapshot(snapshot) { - None => Ok(result), - Some(_) => Ok(result.max(EvaluatedToOkModuloRegions)), - } - }) - } - - /// Evaluates the predicates in `predicates` recursively. Note that - /// this applies projections in the predicates, and therefore - /// is run within an inference probe. - fn evaluate_predicates_recursively<'o, I>( - &mut self, - stack: TraitObligationStackList<'o, 'tcx>, - predicates: I, - ) -> Result<EvaluationResult, OverflowError> - where - I: IntoIterator<Item = PredicateObligation<'tcx>>, - { - let mut result = EvaluatedToOk; - for obligation in predicates { - let eval = self.evaluate_predicate_recursively(stack, obligation.clone())?; - debug!("evaluate_predicate_recursively({:?}) = {:?}", obligation, eval); - if let EvaluatedToErr = eval { - // fast-path - EvaluatedToErr is the top of the lattice, - // so we don't need to look on the other predicates. - return Ok(EvaluatedToErr); - } else { - result = cmp::max(result, eval); - } - } - Ok(result) - } - - fn evaluate_predicate_recursively<'o>( - &mut self, - previous_stack: TraitObligationStackList<'o, 'tcx>, - obligation: PredicateObligation<'tcx>, - ) -> Result<EvaluationResult, OverflowError> { - debug!( - "evaluate_predicate_recursively(previous_stack={:?}, obligation={:?})", - previous_stack.head(), - obligation - ); - - // `previous_stack` stores a `TraitObligatiom`, while `obligation` is - // a `PredicateObligation`. These are distinct types, so we can't - // use any `Option` combinator method that would force them to be - // the same. - match previous_stack.head() { - Some(h) => self.check_recursion_limit(&obligation, h.obligation)?, - None => self.check_recursion_limit(&obligation, &obligation)?, - } - - match obligation.predicate { - ty::Predicate::Trait(ref t, _) => { - debug_assert!(!t.has_escaping_bound_vars()); - let obligation = obligation.with(t.clone()); - self.evaluate_trait_predicate_recursively(previous_stack, obligation) - } - - ty::Predicate::Subtype(ref p) => { - // Does this code ever run? - match self.infcx.subtype_predicate(&obligation.cause, obligation.param_env, p) { - Some(Ok(InferOk { mut obligations, .. })) => { - self.add_depth(obligations.iter_mut(), obligation.recursion_depth); - self.evaluate_predicates_recursively( - previous_stack, - obligations.into_iter(), - ) - } - Some(Err(_)) => Ok(EvaluatedToErr), - None => Ok(EvaluatedToAmbig), - } - } - - ty::Predicate::WellFormed(ty) => match wf::obligations( - self.infcx, - obligation.param_env, - obligation.cause.body_id, - ty, - obligation.cause.span, - ) { - Some(mut obligations) => { - self.add_depth(obligations.iter_mut(), obligation.recursion_depth); - self.evaluate_predicates_recursively(previous_stack, obligations.into_iter()) - } - None => Ok(EvaluatedToAmbig), - }, - - ty::Predicate::TypeOutlives(..) | ty::Predicate::RegionOutlives(..) => { - // We do not consider region relationships when evaluating trait matches. - Ok(EvaluatedToOkModuloRegions) - } - - ty::Predicate::ObjectSafe(trait_def_id) => { - if self.tcx().is_object_safe(trait_def_id) { - Ok(EvaluatedToOk) - } else { - Ok(EvaluatedToErr) - } - } - - ty::Predicate::Projection(ref data) => { - let project_obligation = obligation.with(data.clone()); - match project::poly_project_and_unify_type(self, &project_obligation) { - Ok(Some(mut subobligations)) => { - self.add_depth(subobligations.iter_mut(), obligation.recursion_depth); - let result = self.evaluate_predicates_recursively( - previous_stack, - subobligations.into_iter(), - ); - if let Some(key) = - ProjectionCacheKey::from_poly_projection_predicate(self, data) - { - self.infcx.inner.borrow_mut().projection_cache.complete(key); - } - result - } - Ok(None) => Ok(EvaluatedToAmbig), - Err(_) => Ok(EvaluatedToErr), - } - } - - ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => { - match self.infcx.closure_kind(closure_def_id, closure_substs) { - Some(closure_kind) => { - if closure_kind.extends(kind) { - Ok(EvaluatedToOk) - } else { - Ok(EvaluatedToErr) - } - } - None => Ok(EvaluatedToAmbig), - } - } - - ty::Predicate::ConstEvaluatable(def_id, substs) => { - if !(obligation.param_env, substs).has_local_value() { - match self.tcx().const_eval_resolve( - obligation.param_env, - def_id, - substs, - None, - None, - ) { - Ok(_) => Ok(EvaluatedToOk), - Err(_) => Ok(EvaluatedToErr), - } - } else { - // Inference variables still left in param_env or substs. - Ok(EvaluatedToAmbig) - } - } - } - } - - fn evaluate_trait_predicate_recursively<'o>( - &mut self, - previous_stack: TraitObligationStackList<'o, 'tcx>, - mut obligation: TraitObligation<'tcx>, - ) -> Result<EvaluationResult, OverflowError> { - debug!("evaluate_trait_predicate_recursively({:?})", obligation); - - if !self.intercrate - && obligation.is_global() - && obligation.param_env.caller_bounds.iter().all(|bound| bound.needs_subst()) - { - // If a param env has no global bounds, global obligations do not - // depend on its particular value in order to work, so we can clear - // out the param env and get better caching. - debug!("evaluate_trait_predicate_recursively({:?}) - in global", obligation); - obligation.param_env = obligation.param_env.without_caller_bounds(); - } - - let stack = self.push_stack(previous_stack, &obligation); - let fresh_trait_ref = stack.fresh_trait_ref; - if let Some(result) = self.check_evaluation_cache(obligation.param_env, fresh_trait_ref) { - debug!("CACHE HIT: EVAL({:?})={:?}", fresh_trait_ref, result); - return Ok(result); - } - - if let Some(result) = stack.cache().get_provisional(fresh_trait_ref) { - debug!("PROVISIONAL CACHE HIT: EVAL({:?})={:?}", fresh_trait_ref, result); - stack.update_reached_depth(stack.cache().current_reached_depth()); - return Ok(result); - } - - // Check if this is a match for something already on the - // stack. If so, we don't want to insert the result into the - // main cache (it is cycle dependent) nor the provisional - // cache (which is meant for things that have completed but - // for a "backedge" -- this result *is* the backedge). - if let Some(cycle_result) = self.check_evaluation_cycle(&stack) { - return Ok(cycle_result); - } - - let (result, dep_node) = self.in_task(|this| this.evaluate_stack(&stack)); - let result = result?; - - if !result.must_apply_modulo_regions() { - stack.cache().on_failure(stack.dfn); - } - - let reached_depth = stack.reached_depth.get(); - if reached_depth >= stack.depth { - debug!("CACHE MISS: EVAL({:?})={:?}", fresh_trait_ref, result); - self.insert_evaluation_cache(obligation.param_env, fresh_trait_ref, dep_node, result); - - stack.cache().on_completion(stack.depth, |fresh_trait_ref, provisional_result| { - self.insert_evaluation_cache( - obligation.param_env, - fresh_trait_ref, - dep_node, - provisional_result.max(result), - ); - }); - } else { - debug!("PROVISIONAL: {:?}={:?}", fresh_trait_ref, result); - debug!( - "evaluate_trait_predicate_recursively: caching provisionally because {:?} \ - is a cycle participant (at depth {}, reached depth {})", - fresh_trait_ref, stack.depth, reached_depth, - ); - - stack.cache().insert_provisional(stack.dfn, reached_depth, fresh_trait_ref, result); - } - - Ok(result) - } - - /// If there is any previous entry on the stack that precisely - /// matches this obligation, then we can assume that the - /// obligation is satisfied for now (still all other conditions - /// must be met of course). One obvious case this comes up is - /// marker traits like `Send`. Think of a linked list: - /// - /// struct List<T> { data: T, next: Option<Box<List<T>>> } - /// - /// `Box<List<T>>` will be `Send` if `T` is `Send` and - /// `Option<Box<List<T>>>` is `Send`, and in turn - /// `Option<Box<List<T>>>` is `Send` if `Box<List<T>>` is - /// `Send`. - /// - /// Note that we do this comparison using the `fresh_trait_ref` - /// fields. Because these have all been freshened using - /// `self.freshener`, we can be sure that (a) this will not - /// affect the inferencer state and (b) that if we see two - /// fresh regions with the same index, they refer to the same - /// unbound type variable. - fn check_evaluation_cycle( - &mut self, - stack: &TraitObligationStack<'_, 'tcx>, - ) -> Option<EvaluationResult> { - if let Some(cycle_depth) = stack - .iter() - .skip(1) // Skip top-most frame. - .find(|prev| { - stack.obligation.param_env == prev.obligation.param_env - && stack.fresh_trait_ref == prev.fresh_trait_ref - }) - .map(|stack| stack.depth) - { - debug!( - "evaluate_stack({:?}) --> recursive at depth {}", - stack.fresh_trait_ref, cycle_depth, - ); - - // If we have a stack like `A B C D E A`, where the top of - // the stack is the final `A`, then this will iterate over - // `A, E, D, C, B` -- i.e., all the participants apart - // from the cycle head. We mark them as participating in a - // cycle. This suppresses caching for those nodes. See - // `in_cycle` field for more details. - stack.update_reached_depth(cycle_depth); - - // Subtle: when checking for a coinductive cycle, we do - // not compare using the "freshened trait refs" (which - // have erased regions) but rather the fully explicit - // trait refs. This is important because it's only a cycle - // if the regions match exactly. - let cycle = stack.iter().skip(1).take_while(|s| s.depth >= cycle_depth); - let cycle = cycle.map(|stack| { - ty::Predicate::Trait(stack.obligation.predicate, hir::Constness::NotConst) - }); - if self.coinductive_match(cycle) { - debug!("evaluate_stack({:?}) --> recursive, coinductive", stack.fresh_trait_ref); - Some(EvaluatedToOk) - } else { - debug!("evaluate_stack({:?}) --> recursive, inductive", stack.fresh_trait_ref); - Some(EvaluatedToRecur) - } - } else { - None - } - } - - fn evaluate_stack<'o>( - &mut self, - stack: &TraitObligationStack<'o, 'tcx>, - ) -> Result<EvaluationResult, OverflowError> { - // In intercrate mode, whenever any of the types are unbound, - // there can always be an impl. Even if there are no impls in - // this crate, perhaps the type would be unified with - // something from another crate that does provide an impl. - // - // In intra mode, we must still be conservative. The reason is - // that we want to avoid cycles. Imagine an impl like: - // - // impl<T:Eq> Eq for Vec<T> - // - // and a trait reference like `$0 : Eq` where `$0` is an - // unbound variable. When we evaluate this trait-reference, we - // will unify `$0` with `Vec<$1>` (for some fresh variable - // `$1`), on the condition that `$1 : Eq`. We will then wind - // up with many candidates (since that are other `Eq` impls - // that apply) and try to winnow things down. This results in - // a recursive evaluation that `$1 : Eq` -- as you can - // imagine, this is just where we started. To avoid that, we - // check for unbound variables and return an ambiguous (hence possible) - // match if we've seen this trait before. - // - // This suffices to allow chains like `FnMut` implemented in - // terms of `Fn` etc, but we could probably make this more - // precise still. - let unbound_input_types = - stack.fresh_trait_ref.skip_binder().input_types().any(|ty| ty.is_fresh()); - // This check was an imperfect workaround for a bug in the old - // intercrate mode; it should be removed when that goes away. - if unbound_input_types && self.intercrate { - debug!( - "evaluate_stack({:?}) --> unbound argument, intercrate --> ambiguous", - stack.fresh_trait_ref - ); - // Heuristics: show the diagnostics when there are no candidates in crate. - if self.intercrate_ambiguity_causes.is_some() { - debug!("evaluate_stack: intercrate_ambiguity_causes is some"); - if let Ok(candidate_set) = self.assemble_candidates(stack) { - if !candidate_set.ambiguous && candidate_set.vec.is_empty() { - let trait_ref = stack.obligation.predicate.skip_binder().trait_ref; - let self_ty = trait_ref.self_ty(); - let cause = IntercrateAmbiguityCause::DownstreamCrate { - trait_desc: trait_ref.print_only_trait_path().to_string(), - self_desc: if self_ty.has_concrete_skeleton() { - Some(self_ty.to_string()) - } else { - None - }, - }; - debug!("evaluate_stack: pushing cause = {:?}", cause); - self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause); - } - } - } - return Ok(EvaluatedToAmbig); - } - if unbound_input_types - && stack.iter().skip(1).any(|prev| { - stack.obligation.param_env == prev.obligation.param_env - && self.match_fresh_trait_refs( - &stack.fresh_trait_ref, - &prev.fresh_trait_ref, - prev.obligation.param_env, - ) - }) - { - debug!( - "evaluate_stack({:?}) --> unbound argument, recursive --> giving up", - stack.fresh_trait_ref - ); - return Ok(EvaluatedToUnknown); - } - - match self.candidate_from_obligation(stack) { - Ok(Some(c)) => self.evaluate_candidate(stack, &c), - Ok(None) => Ok(EvaluatedToAmbig), - Err(Overflow) => Err(OverflowError), - Err(..) => Ok(EvaluatedToErr), - } - } - - /// For defaulted traits, we use a co-inductive strategy to solve, so - /// that recursion is ok. This routine returns `true` if the top of the - /// stack (`cycle[0]`): - /// - /// - is a defaulted trait, - /// - it also appears in the backtrace at some position `X`, - /// - all the predicates at positions `X..` between `X` and the top are - /// also defaulted traits. - pub fn coinductive_match<I>(&mut self, cycle: I) -> bool - where - I: Iterator<Item = ty::Predicate<'tcx>>, - { - let mut cycle = cycle; - cycle.all(|predicate| self.coinductive_predicate(predicate)) - } - - fn coinductive_predicate(&self, predicate: ty::Predicate<'tcx>) -> bool { - let result = match predicate { - ty::Predicate::Trait(ref data, _) => self.tcx().trait_is_auto(data.def_id()), - _ => false, - }; - debug!("coinductive_predicate({:?}) = {:?}", predicate, result); - result - } - - /// Further evaluates `candidate` to decide whether all type parameters match and whether nested - /// obligations are met. Returns whether `candidate` remains viable after this further - /// scrutiny. - fn evaluate_candidate<'o>( - &mut self, - stack: &TraitObligationStack<'o, 'tcx>, - candidate: &SelectionCandidate<'tcx>, - ) -> Result<EvaluationResult, OverflowError> { - debug!( - "evaluate_candidate: depth={} candidate={:?}", - stack.obligation.recursion_depth, candidate - ); - let result = self.evaluation_probe(|this| { - let candidate = (*candidate).clone(); - match this.confirm_candidate(stack.obligation, candidate) { - Ok(selection) => this.evaluate_predicates_recursively( - stack.list(), - selection.nested_obligations().into_iter(), - ), - Err(..) => Ok(EvaluatedToErr), - } - })?; - debug!( - "evaluate_candidate: depth={} result={:?}", - stack.obligation.recursion_depth, result - ); - Ok(result) - } - - fn check_evaluation_cache( - &self, - param_env: ty::ParamEnv<'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>, - ) -> Option<EvaluationResult> { - let tcx = self.tcx(); - if self.can_use_global_caches(param_env) { - let cache = tcx.evaluation_cache.hashmap.borrow(); - if let Some(cached) = cache.get(¶m_env.and(trait_ref)) { - return Some(cached.get(tcx)); - } - } - self.infcx - .evaluation_cache - .hashmap - .borrow() - .get(¶m_env.and(trait_ref)) - .map(|v| v.get(tcx)) - } - - fn insert_evaluation_cache( - &mut self, - param_env: ty::ParamEnv<'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>, - dep_node: DepNodeIndex, - result: EvaluationResult, - ) { - // Avoid caching results that depend on more than just the trait-ref - // - the stack can create recursion. - if result.is_stack_dependent() { - return; - } - - if self.can_use_global_caches(param_env) { - if !trait_ref.has_local_value() { - debug!( - "insert_evaluation_cache(trait_ref={:?}, candidate={:?}) global", - trait_ref, result, - ); - // This may overwrite the cache with the same value - // FIXME: Due to #50507 this overwrites the different values - // This should be changed to use HashMapExt::insert_same - // when that is fixed - self.tcx() - .evaluation_cache - .hashmap - .borrow_mut() - .insert(param_env.and(trait_ref), WithDepNode::new(dep_node, result)); - return; - } - } - - debug!("insert_evaluation_cache(trait_ref={:?}, candidate={:?})", trait_ref, result,); - self.infcx - .evaluation_cache - .hashmap - .borrow_mut() - .insert(param_env.and(trait_ref), WithDepNode::new(dep_node, result)); - } - - /// For various reasons, it's possible for a subobligation - /// to have a *lower* recursion_depth than the obligation used to create it. - /// Projection sub-obligations may be returned from the projection cache, - /// which results in obligations with an 'old' `recursion_depth`. - /// Additionally, methods like `wf::obligations` and - /// `InferCtxt.subtype_predicate` produce subobligations without - /// taking in a 'parent' depth, causing the generated subobligations - /// to have a `recursion_depth` of `0`. +/// 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. /// - /// To ensure that obligation_depth never decreasees, we force all subobligations - /// to have at least the depth of the original obligation. - fn add_depth<T: 'cx, I: Iterator<Item = &'cx mut Obligation<'tcx, T>>>( - &self, - it: I, - min_depth: usize, - ) { - it.for_each(|o| o.recursion_depth = cmp::max(min_depth, o.recursion_depth) + 1); - } - - /// Checks that the recursion limit has not been exceeded. + /// 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. /// - /// The weird return type of this function allows it to be used with the `try` (`?`) - /// operator within certain functions. - fn check_recursion_limit<T: Display + TypeFoldable<'tcx>, V: Display + TypeFoldable<'tcx>>( - &self, - obligation: &Obligation<'tcx, T>, - error_obligation: &Obligation<'tcx, V>, - ) -> Result<(), OverflowError> { - let recursion_limit = *self.infcx.tcx.sess.recursion_limit.get(); - if obligation.recursion_depth >= recursion_limit { - match self.query_mode { - TraitQueryMode::Standard => { - self.infcx().report_overflow_error(error_obligation, true); - } - TraitQueryMode::Canonical => { - return Err(OverflowError); - } - } - } - Ok(()) - } - - /////////////////////////////////////////////////////////////////////////// - // CANDIDATE ASSEMBLY - // - // The selection process begins by examining all in-scope impls, - // caller obligations, and so forth and assembling a list of - // candidates. See the [rustc guide] for more details. - // - // [rustc guide]: - // https://rust-lang.github.io/rustc-guide/traits/resolution.html#candidate-assembly - - fn candidate_from_obligation<'o>( - &mut self, - stack: &TraitObligationStack<'o, 'tcx>, - ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> { - // Watch out for overflow. This intentionally bypasses (and does - // not update) the cache. - self.check_recursion_limit(&stack.obligation, &stack.obligation)?; - - // Check the cache. Note that we freshen the trait-ref - // separately rather than using `stack.fresh_trait_ref` -- - // this is because we want the unbound variables to be - // replaced with fresh types starting from index 0. - let cache_fresh_trait_pred = self.infcx.freshen(stack.obligation.predicate.clone()); - debug!( - "candidate_from_obligation(cache_fresh_trait_pred={:?}, obligation={:?})", - cache_fresh_trait_pred, stack - ); - debug_assert!(!stack.obligation.predicate.has_escaping_bound_vars()); - - if let Some(c) = - self.check_candidate_cache(stack.obligation.param_env, &cache_fresh_trait_pred) - { - debug!("CACHE HIT: SELECT({:?})={:?}", cache_fresh_trait_pred, c); - return c; - } - - // If no match, compute result and insert into cache. - // - // FIXME(nikomatsakis) -- this cache is not taking into - // account cycles that may have occurred in forming the - // candidate. I don't know of any specific problems that - // result but it seems awfully suspicious. - let (candidate, dep_node) = - self.in_task(|this| this.candidate_from_obligation_no_cache(stack)); - - debug!("CACHE MISS: SELECT({:?})={:?}", cache_fresh_trait_pred, candidate); - self.insert_candidate_cache( - stack.obligation.param_env, - cache_fresh_trait_pred, - dep_node, - candidate.clone(), - ); - candidate - } - - fn in_task<OP, R>(&mut self, op: OP) -> (R, DepNodeIndex) - where - OP: FnOnce(&mut Self) -> R, - { - let (result, dep_node) = - self.tcx().dep_graph.with_anon_task(DepKind::TraitSelect, || op(self)); - self.tcx().dep_graph.read_index(dep_node); - (result, dep_node) - } - - // Treat negative impls as unimplemented, and reservation impls as ambiguity. - fn filter_negative_and_reservation_impls( - &mut self, - candidate: SelectionCandidate<'tcx>, - ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> { - if let ImplCandidate(def_id) = candidate { - let tcx = self.tcx(); - match tcx.impl_polarity(def_id) { - ty::ImplPolarity::Negative if !self.allow_negative_impls => { - return Err(Unimplemented); - } - ty::ImplPolarity::Reservation => { - if let Some(intercrate_ambiguity_clauses) = - &mut self.intercrate_ambiguity_causes - { - let attrs = tcx.get_attrs(def_id); - let attr = attr::find_by_name(&attrs, sym::rustc_reservation_impl); - let value = attr.and_then(|a| a.value_str()); - if let Some(value) = value { - debug!( - "filter_negative_and_reservation_impls: \ - reservation impl ambiguity on {:?}", - def_id - ); - intercrate_ambiguity_clauses.push( - IntercrateAmbiguityCause::ReservationImpl { - message: value.to_string(), - }, - ); - } - } - return Ok(None); - } - _ => {} - }; - } - Ok(Some(candidate)) - } - - fn candidate_from_obligation_no_cache<'o>( - &mut self, - stack: &TraitObligationStack<'o, 'tcx>, - ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> { - if stack.obligation.predicate.references_error() { - // If we encounter a `Error`, we generally prefer the - // most "optimistic" result in response -- that is, the - // one least likely to report downstream errors. But - // because this routine is shared by coherence and by - // trait selection, there isn't an obvious "right" choice - // here in that respect, so we opt to just return - // ambiguity and let the upstream clients sort it out. - return Ok(None); - } - - if let Some(conflict) = self.is_knowable(stack) { - debug!("coherence stage: not knowable"); - if self.intercrate_ambiguity_causes.is_some() { - debug!("evaluate_stack: intercrate_ambiguity_causes is some"); - // Heuristics: show the diagnostics when there are no candidates in crate. - if let Ok(candidate_set) = self.assemble_candidates(stack) { - let mut no_candidates_apply = true; - { - let evaluated_candidates = - candidate_set.vec.iter().map(|c| self.evaluate_candidate(stack, &c)); - - for ec in evaluated_candidates { - match ec { - Ok(c) => { - if c.may_apply() { - no_candidates_apply = false; - break; - } - } - Err(e) => return Err(e.into()), - } - } - } - - if !candidate_set.ambiguous && no_candidates_apply { - let trait_ref = stack.obligation.predicate.skip_binder().trait_ref; - let self_ty = trait_ref.self_ty(); - let trait_desc = trait_ref.print_only_trait_path().to_string(); - let self_desc = if self_ty.has_concrete_skeleton() { - Some(self_ty.to_string()) - } else { - None - }; - let cause = if let Conflict::Upstream = conflict { - IntercrateAmbiguityCause::UpstreamCrateUpdate { trait_desc, self_desc } - } else { - IntercrateAmbiguityCause::DownstreamCrate { trait_desc, self_desc } - }; - debug!("evaluate_stack: pushing cause = {:?}", cause); - self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause); - } - } - } - return Ok(None); - } - - let candidate_set = self.assemble_candidates(stack)?; - - if candidate_set.ambiguous { - debug!("candidate set contains ambig"); - return Ok(None); - } - - let mut candidates = candidate_set.vec; - - debug!("assembled {} candidates for {:?}: {:?}", candidates.len(), stack, candidates); - - // At this point, we know that each of the entries in the - // candidate set is *individually* applicable. Now we have to - // figure out if they contain mutual incompatibilities. This - // frequently arises if we have an unconstrained input type -- - // for example, we are looking for `$0: Eq` where `$0` is some - // unconstrained type variable. In that case, we'll get a - // candidate which assumes $0 == int, one that assumes `$0 == - // usize`, etc. This spells an ambiguity. - - // If there is more than one candidate, first winnow them down - // by considering extra conditions (nested obligations and so - // forth). We don't winnow if there is exactly one - // candidate. This is a relatively minor distinction but it - // can lead to better inference and error-reporting. An - // example would be if there was an impl: - // - // impl<T:Clone> Vec<T> { fn push_clone(...) { ... } } - // - // and we were to see some code `foo.push_clone()` where `boo` - // is a `Vec<Bar>` and `Bar` does not implement `Clone`. If - // we were to winnow, we'd wind up with zero candidates. - // Instead, we select the right impl now but report "`Bar` does - // not implement `Clone`". - if candidates.len() == 1 { - return self.filter_negative_and_reservation_impls(candidates.pop().unwrap()); - } - - // Winnow, but record the exact outcome of evaluation, which - // is needed for specialization. Propagate overflow if it occurs. - let mut candidates = candidates - .into_iter() - .map(|c| match self.evaluate_candidate(stack, &c) { - Ok(eval) if eval.may_apply() => { - Ok(Some(EvaluatedCandidate { candidate: c, evaluation: eval })) - } - Ok(_) => Ok(None), - Err(OverflowError) => Err(Overflow), - }) - .flat_map(Result::transpose) - .collect::<Result<Vec<_>, _>>()?; - - debug!("winnowed to {} candidates for {:?}: {:?}", candidates.len(), stack, candidates); - - let needs_infer = stack.obligation.predicate.needs_infer(); - - // If there are STILL multiple candidates, we can further - // reduce the list by dropping duplicates -- including - // resolving specializations. - if candidates.len() > 1 { - let mut i = 0; - while i < candidates.len() { - let is_dup = (0..candidates.len()).filter(|&j| i != j).any(|j| { - self.candidate_should_be_dropped_in_favor_of( - &candidates[i], - &candidates[j], - needs_infer, - ) - }); - if is_dup { - debug!("Dropping candidate #{}/{}: {:?}", i, candidates.len(), candidates[i]); - candidates.swap_remove(i); - } else { - debug!("Retaining candidate #{}/{}: {:?}", i, candidates.len(), candidates[i]); - i += 1; - - // If there are *STILL* multiple candidates, give up - // and report ambiguity. - if i > 1 { - debug!("multiple matches, ambig"); - return Ok(None); - } - } - } - } - - // If there are *NO* candidates, then there are no impls -- - // that we know of, anyway. Note that in the case where there - // are unbound type variables within the obligation, it might - // be the case that you could still satisfy the obligation - // from another crate by instantiating the type variables with - // a type from another crate that does have an impl. This case - // is checked for in `evaluate_stack` (and hence users - // who might care about this case, like coherence, should use - // that function). - if candidates.is_empty() { - return Err(Unimplemented); - } - - // Just one candidate left. - self.filter_negative_and_reservation_impls(candidates.pop().unwrap().candidate) - } - - fn is_knowable<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>) -> Option<Conflict> { - debug!("is_knowable(intercrate={:?})", self.intercrate); - - if !self.intercrate { - return None; - } - - let obligation = &stack.obligation; - let predicate = self.infcx().resolve_vars_if_possible(&obligation.predicate); - - // Okay to skip binder because of the nature of the - // trait-ref-is-knowable check, which does not care about - // bound regions. - let trait_ref = predicate.skip_binder().trait_ref; - - coherence::trait_ref_is_knowable(self.tcx(), trait_ref) - } - - /// Returns `true` if the global caches can be used. - /// Do note that if the type itself is not in the - /// global tcx, the local caches will be used. - fn can_use_global_caches(&self, param_env: ty::ParamEnv<'tcx>) -> bool { - // If there are any e.g. inference variables in the `ParamEnv`, then we - // always use a cache local to this particular scope. Otherwise, we - // switch to a global cache. - if param_env.has_local_value() { - return false; - } - - // Avoid using the master cache during coherence and just rely - // on the local cache. This effectively disables caching - // during coherence. It is really just a simplification to - // avoid us having to fear that coherence results "pollute" - // the master cache. Since coherence executes pretty quickly, - // it's not worth going to more trouble to increase the - // hit-rate, I don't think. - if self.intercrate { - return false; - } - - // Otherwise, we can use the global cache. - true - } - - fn check_candidate_cache( - &mut self, - param_env: ty::ParamEnv<'tcx>, - cache_fresh_trait_pred: &ty::PolyTraitPredicate<'tcx>, - ) -> Option<SelectionResult<'tcx, SelectionCandidate<'tcx>>> { - let tcx = self.tcx(); - let trait_ref = &cache_fresh_trait_pred.skip_binder().trait_ref; - if self.can_use_global_caches(param_env) { - let cache = tcx.selection_cache.hashmap.borrow(); - if let Some(cached) = cache.get(¶m_env.and(*trait_ref)) { - return Some(cached.get(tcx)); - } - } - self.infcx - .selection_cache - .hashmap - .borrow() - .get(¶m_env.and(*trait_ref)) - .map(|v| v.get(tcx)) - } - - /// Determines whether can we safely cache the result - /// of selecting an obligation. This is almost always `true`, - /// except when dealing with certain `ParamCandidate`s. + /// 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. /// - /// Ordinarily, a `ParamCandidate` will contain no inference variables, - /// since it was usually produced directly from a `DefId`. However, - /// certain cases (currently only librustdoc's blanket impl finder), - /// a `ParamEnv` may be explicitly constructed with inference types. - /// When this is the case, we do *not* want to cache the resulting selection - /// candidate. This is due to the fact that it might not always be possible - /// to equate the obligation's trait ref and the candidate's trait ref, - /// if more constraints end up getting added to an inference variable. + /// 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. /// - /// Because of this, we always want to re-run the full selection - /// process for our obligation the next time we see it, since - /// we might end up picking a different `SelectionCandidate` (or none at all). - fn can_cache_candidate( - &self, - result: &SelectionResult<'tcx, SelectionCandidate<'tcx>>, - ) -> bool { - match result { - Ok(Some(SelectionCandidate::ParamCandidate(trait_ref))) => { - !trait_ref.skip_binder().input_types().any(|t| t.walk().any(|t_| t_.is_ty_infer())) - } - _ => true, - } - } - - fn insert_candidate_cache( - &mut self, - param_env: ty::ParamEnv<'tcx>, - cache_fresh_trait_pred: ty::PolyTraitPredicate<'tcx>, - dep_node: DepNodeIndex, - candidate: SelectionResult<'tcx, SelectionCandidate<'tcx>>, - ) { - let tcx = self.tcx(); - let trait_ref = cache_fresh_trait_pred.skip_binder().trait_ref; - - if !self.can_cache_candidate(&candidate) { - debug!( - "insert_candidate_cache(trait_ref={:?}, candidate={:?} -\ - candidate is not cacheable", - trait_ref, candidate - ); - return; - } - - if self.can_use_global_caches(param_env) { - if let Err(Overflow) = candidate { - // Don't cache overflow globally; we only produce this in certain modes. - } else if !trait_ref.has_local_value() { - if !candidate.has_local_value() { - debug!( - "insert_candidate_cache(trait_ref={:?}, candidate={:?}) global", - trait_ref, candidate, - ); - // This may overwrite the cache with the same value. - tcx.selection_cache - .hashmap - .borrow_mut() - .insert(param_env.and(trait_ref), WithDepNode::new(dep_node, candidate)); - return; - } - } - } - - debug!( - "insert_candidate_cache(trait_ref={:?}, candidate={:?}) local", - trait_ref, candidate, - ); - self.infcx - .selection_cache - .hashmap - .borrow_mut() - .insert(param_env.and(trait_ref), WithDepNode::new(dep_node, candidate)); - } - - fn assemble_candidates<'o>( - &mut self, - stack: &TraitObligationStack<'o, 'tcx>, - ) -> Result<SelectionCandidateSet<'tcx>, SelectionError<'tcx>> { - let TraitObligationStack { obligation, .. } = *stack; - let ref obligation = Obligation { - param_env: obligation.param_env, - cause: obligation.cause.clone(), - recursion_depth: obligation.recursion_depth, - predicate: self.infcx().resolve_vars_if_possible(&obligation.predicate), - }; - - if obligation.predicate.skip_binder().self_ty().is_ty_var() { - // Self is a type variable (e.g., `_: AsRef<str>`). - // - // This is somewhat problematic, as the current scheme can't really - // handle it turning to be a projection. This does end up as truly - // ambiguous in most cases anyway. - // - // Take the fast path out - this also improves - // performance by preventing assemble_candidates_from_impls from - // matching every impl for this trait. - return Ok(SelectionCandidateSet { vec: vec![], ambiguous: true }); - } - - let mut candidates = SelectionCandidateSet { vec: Vec::new(), ambiguous: false }; - - self.assemble_candidates_for_trait_alias(obligation, &mut candidates)?; - - // Other bounds. Consider both in-scope bounds from fn decl - // and applicable impls. There is a certain set of precedence rules here. - let def_id = obligation.predicate.def_id(); - let lang_items = self.tcx().lang_items(); - - if lang_items.copy_trait() == Some(def_id) { - debug!("obligation self ty is {:?}", obligation.predicate.skip_binder().self_ty()); - - // User-defined copy impls are permitted, but only for - // structs and enums. - self.assemble_candidates_from_impls(obligation, &mut candidates)?; - - // For other types, we'll use the builtin rules. - let copy_conditions = self.copy_clone_conditions(obligation); - self.assemble_builtin_bound_candidates(copy_conditions, &mut candidates)?; - } else if lang_items.sized_trait() == Some(def_id) { - // Sized is never implementable by end-users, it is - // always automatically computed. - let sized_conditions = self.sized_conditions(obligation); - self.assemble_builtin_bound_candidates(sized_conditions, &mut candidates)?; - } else if lang_items.unsize_trait() == Some(def_id) { - self.assemble_candidates_for_unsizing(obligation, &mut candidates); - } else { - if lang_items.clone_trait() == Some(def_id) { - // Same builtin conditions as `Copy`, i.e., every type which has builtin support - // for `Copy` also has builtin support for `Clone`, and tuples/arrays of `Clone` - // types have builtin support for `Clone`. - let clone_conditions = self.copy_clone_conditions(obligation); - self.assemble_builtin_bound_candidates(clone_conditions, &mut candidates)?; - } - - self.assemble_generator_candidates(obligation, &mut candidates)?; - self.assemble_closure_candidates(obligation, &mut candidates)?; - self.assemble_fn_pointer_candidates(obligation, &mut candidates)?; - self.assemble_candidates_from_impls(obligation, &mut candidates)?; - self.assemble_candidates_from_object_ty(obligation, &mut candidates); - } - - self.assemble_candidates_from_projected_tys(obligation, &mut candidates); - self.assemble_candidates_from_caller_bounds(stack, &mut candidates)?; - // Auto implementations have lower priority, so we only - // consider triggering a default if there is no other impl that can apply. - if candidates.vec.is_empty() { - self.assemble_candidates_from_auto_impls(obligation, &mut candidates)?; - } - debug!("candidate list size: {}", candidates.vec.len()); - Ok(candidates) - } - - fn assemble_candidates_from_projected_tys( - &mut self, - obligation: &TraitObligation<'tcx>, - candidates: &mut SelectionCandidateSet<'tcx>, - ) { - debug!("assemble_candidates_for_projected_tys({:?})", obligation); - - // Before we go into the whole placeholder thing, just - // quickly check if the self-type is a projection at all. - match obligation.predicate.skip_binder().trait_ref.self_ty().kind { - ty::Projection(_) | ty::Opaque(..) => {} - ty::Infer(ty::TyVar(_)) => { - span_bug!( - obligation.cause.span, - "Self=_ should have been handled by assemble_candidates" - ); - } - _ => return, - } - - let result = self.infcx.probe(|snapshot| { - self.match_projection_obligation_against_definition_bounds(obligation, snapshot) - }); - - if result { - candidates.vec.push(ProjectionCandidate); - } - } - - fn match_projection_obligation_against_definition_bounds( - &mut self, - obligation: &TraitObligation<'tcx>, - snapshot: &CombinedSnapshot<'_, 'tcx>, - ) -> bool { - let poly_trait_predicate = self.infcx().resolve_vars_if_possible(&obligation.predicate); - let (placeholder_trait_predicate, placeholder_map) = - self.infcx().replace_bound_vars_with_placeholders(&poly_trait_predicate); - debug!( - "match_projection_obligation_against_definition_bounds: \ - placeholder_trait_predicate={:?}", - placeholder_trait_predicate, - ); - - let (def_id, substs) = match placeholder_trait_predicate.trait_ref.self_ty().kind { - ty::Projection(ref data) => (data.trait_ref(self.tcx()).def_id, data.substs), - ty::Opaque(def_id, substs) => (def_id, substs), - _ => { - span_bug!( - obligation.cause.span, - "match_projection_obligation_against_definition_bounds() called \ - but self-ty is not a projection: {:?}", - placeholder_trait_predicate.trait_ref.self_ty() - ); - } - }; - debug!( - "match_projection_obligation_against_definition_bounds: \ - def_id={:?}, substs={:?}", - def_id, substs - ); - - let predicates_of = self.tcx().predicates_of(def_id); - let bounds = predicates_of.instantiate(self.tcx(), substs); - debug!( - "match_projection_obligation_against_definition_bounds: \ - bounds={:?}", - bounds - ); - - let elaborated_predicates = util::elaborate_predicates(self.tcx(), bounds.predicates); - let matching_bound = elaborated_predicates.filter_to_traits().find(|bound| { - self.infcx.probe(|_| { - self.match_projection( - obligation, - bound.clone(), - placeholder_trait_predicate.trait_ref.clone(), - &placeholder_map, - snapshot, - ) - }) - }); - - debug!( - "match_projection_obligation_against_definition_bounds: \ - matching_bound={:?}", - matching_bound - ); - match matching_bound { - None => false, - Some(bound) => { - // Repeat the successful match, if any, this time outside of a probe. - let result = self.match_projection( - obligation, - bound, - placeholder_trait_predicate.trait_ref.clone(), - &placeholder_map, - snapshot, - ); - - assert!(result); - true - } - } - } - - fn match_projection( - &mut self, - obligation: &TraitObligation<'tcx>, - trait_bound: ty::PolyTraitRef<'tcx>, - placeholder_trait_ref: ty::TraitRef<'tcx>, - placeholder_map: &PlaceholderMap<'tcx>, - snapshot: &CombinedSnapshot<'_, 'tcx>, - ) -> bool { - debug_assert!(!placeholder_trait_ref.has_escaping_bound_vars()); - self.infcx - .at(&obligation.cause, obligation.param_env) - .sup(ty::Binder::dummy(placeholder_trait_ref), trait_bound) - .is_ok() - && self.infcx.leak_check(false, placeholder_map, snapshot).is_ok() - } - - /// Given an obligation like `<SomeTrait for T>`, searches the obligations that the caller - /// supplied to find out whether it is listed among them. + /// For example, suppose we have this: /// - /// Never affects the inference environment. - fn assemble_candidates_from_caller_bounds<'o>( - &mut self, - stack: &TraitObligationStack<'o, 'tcx>, - candidates: &mut SelectionCandidateSet<'tcx>, - ) -> Result<(), SelectionError<'tcx>> { - debug!("assemble_candidates_from_caller_bounds({:?})", stack.obligation); - - let all_bounds = stack - .obligation - .param_env - .caller_bounds - .iter() - .filter_map(|o| o.to_opt_poly_trait_ref()); - - // Micro-optimization: filter out predicates relating to different traits. - let matching_bounds = - all_bounds.filter(|p| p.def_id() == stack.obligation.predicate.def_id()); - - // Keep only those bounds which may apply, and propagate overflow if it occurs. - let mut param_candidates = vec![]; - for bound in matching_bounds { - let wc = self.evaluate_where_clause(stack, bound.clone())?; - if wc.may_apply() { - param_candidates.push(ParamCandidate(bound)); - } - } - - candidates.vec.extend(param_candidates); - - Ok(()) - } - - fn evaluate_where_clause<'o>( - &mut self, - stack: &TraitObligationStack<'o, 'tcx>, - where_clause_trait_ref: ty::PolyTraitRef<'tcx>, - ) -> Result<EvaluationResult, OverflowError> { - self.evaluation_probe(|this| { - match this.match_where_clause_trait_ref(stack.obligation, where_clause_trait_ref) { - Ok(obligations) => { - this.evaluate_predicates_recursively(stack.list(), obligations.into_iter()) - } - Err(()) => Ok(EvaluatedToErr), - } - }) - } - - fn assemble_generator_candidates( - &mut self, - obligation: &TraitObligation<'tcx>, - candidates: &mut SelectionCandidateSet<'tcx>, - ) -> Result<(), SelectionError<'tcx>> { - if self.tcx().lang_items().gen_trait() != Some(obligation.predicate.def_id()) { - return Ok(()); - } - - // Okay to skip binder because the substs on generator types never - // touch bound regions, they just capture the in-scope - // type/region parameters. - let self_ty = *obligation.self_ty().skip_binder(); - match self_ty.kind { - ty::Generator(..) => { - debug!( - "assemble_generator_candidates: self_ty={:?} obligation={:?}", - self_ty, obligation - ); - - candidates.vec.push(GeneratorCandidate); - } - ty::Infer(ty::TyVar(_)) => { - debug!("assemble_generator_candidates: ambiguous self-type"); - candidates.ambiguous = true; - } - _ => {} - } - - Ok(()) - } - - /// Checks for the artificial impl that the compiler will create for an obligation like `X : - /// FnMut<..>` where `X` is a closure type. + /// ```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() {} } /// - /// Note: the type parameters on a closure candidate are modeled as *output* type - /// parameters and hence do not affect whether this trait is a match or not. They will be - /// unified during the confirmation step. - fn assemble_closure_candidates( - &mut self, - obligation: &TraitObligation<'tcx>, - candidates: &mut SelectionCandidateSet<'tcx>, - ) -> Result<(), SelectionError<'tcx>> { - let kind = match self.tcx().fn_trait_kind_from_lang_item(obligation.predicate.def_id()) { - Some(k) => k, - None => { - return Ok(()); - } - }; - - // Okay to skip binder because the substs on closure types never - // touch bound regions, they just capture the in-scope - // type/region parameters - match obligation.self_ty().skip_binder().kind { - ty::Closure(closure_def_id, closure_substs) => { - debug!("assemble_unboxed_candidates: kind={:?} obligation={:?}", kind, obligation); - match self.infcx.closure_kind(closure_def_id, closure_substs) { - Some(closure_kind) => { - debug!("assemble_unboxed_candidates: closure_kind = {:?}", closure_kind); - if closure_kind.extends(kind) { - candidates.vec.push(ClosureCandidate); - } - } - None => { - debug!("assemble_unboxed_candidates: closure_kind not yet known"); - candidates.vec.push(ClosureCandidate); - } - } - } - ty::Infer(ty::TyVar(_)) => { - debug!("assemble_unboxed_closure_candidates: ambiguous self-type"); - candidates.ambiguous = true; - } - _ => {} - } - - Ok(()) - } - - /// Implements one of the `Fn()` family for a fn pointer. - fn assemble_fn_pointer_candidates( - &mut self, - obligation: &TraitObligation<'tcx>, - candidates: &mut SelectionCandidateSet<'tcx>, - ) -> Result<(), SelectionError<'tcx>> { - // We provide impl of all fn traits for fn pointers. - if self.tcx().fn_trait_kind_from_lang_item(obligation.predicate.def_id()).is_none() { - return Ok(()); - } - - // Okay to skip binder because what we are inspecting doesn't involve bound regions. - let self_ty = *obligation.self_ty().skip_binder(); - match self_ty.kind { - ty::Infer(ty::TyVar(_)) => { - debug!("assemble_fn_pointer_candidates: ambiguous self-type"); - candidates.ambiguous = true; // Could wind up being a fn() type. - } - // Provide an impl, but only for suitable `fn` pointers. - ty::FnDef(..) | ty::FnPtr(_) => { - if let ty::FnSig { - unsafety: hir::Unsafety::Normal, - abi: Abi::Rust, - c_variadic: false, - .. - } = self_ty.fn_sig(self.tcx()).skip_binder() - { - candidates.vec.push(FnPointerCandidate); - } - } - _ => {} - } - - Ok(()) - } - - /// Searches for impls that might apply to `obligation`. - fn assemble_candidates_from_impls( - &mut self, - obligation: &TraitObligation<'tcx>, - candidates: &mut SelectionCandidateSet<'tcx>, - ) -> Result<(), SelectionError<'tcx>> { - debug!("assemble_candidates_from_impls(obligation={:?})", obligation); - - self.tcx().for_each_relevant_impl( - obligation.predicate.def_id(), - obligation.predicate.skip_binder().trait_ref.self_ty(), - |impl_def_id| { - self.infcx.probe(|snapshot| { - if let Ok(_substs) = self.match_impl(impl_def_id, obligation, snapshot) { - candidates.vec.push(ImplCandidate(impl_def_id)); - } - }); - }, - ); - - Ok(()) - } - - fn assemble_candidates_from_auto_impls( - &mut self, - obligation: &TraitObligation<'tcx>, - candidates: &mut SelectionCandidateSet<'tcx>, - ) -> Result<(), SelectionError<'tcx>> { - // Okay to skip binder here because the tests we do below do not involve bound regions. - let self_ty = *obligation.self_ty().skip_binder(); - debug!("assemble_candidates_from_auto_impls(self_ty={:?})", self_ty); - - let def_id = obligation.predicate.def_id(); - - if self.tcx().trait_is_auto(def_id) { - match self_ty.kind { - ty::Dynamic(..) => { - // For object types, we don't know what the closed - // over types are. This means we conservatively - // say nothing; a candidate may be added by - // `assemble_candidates_from_object_ty`. - } - ty::Foreign(..) => { - // Since the contents of foreign types is unknown, - // we don't add any `..` impl. Default traits could - // still be provided by a manual implementation for - // this trait and type. - } - ty::Param(..) | ty::Projection(..) => { - // In these cases, we don't know what the actual - // type is. Therefore, we cannot break it down - // into its constituent types. So we don't - // consider the `..` impl but instead just add no - // candidates: this means that typeck will only - // succeed if there is another reason to believe - // that this obligation holds. That could be a - // where-clause or, in the case of an object type, - // it could be that the object type lists the - // trait (e.g., `Foo+Send : Send`). See - // `compile-fail/typeck-default-trait-impl-send-param.rs` - // for an example of a test case that exercises - // this path. - } - ty::Infer(ty::TyVar(_)) => { - // The auto impl might apply; we don't know. - candidates.ambiguous = true; - } - ty::Generator(_, _, movability) - if self.tcx().lang_items().unpin_trait() == Some(def_id) => - { - match movability { - hir::Movability::Static => { - // Immovable generators are never `Unpin`, so - // suppress the normal auto-impl candidate for it. - } - hir::Movability::Movable => { - // Movable generators are always `Unpin`, so add an - // unconditional builtin candidate. - candidates.vec.push(BuiltinCandidate { has_nested: false }); - } - } - } - - _ => candidates.vec.push(AutoImplCandidate(def_id)), - } - } - - Ok(()) - } - - /// Searches for impls that might apply to `obligation`. - fn assemble_candidates_from_object_ty( - &mut self, - obligation: &TraitObligation<'tcx>, - candidates: &mut SelectionCandidateSet<'tcx>, - ) { - debug!( - "assemble_candidates_from_object_ty(self_ty={:?})", - obligation.self_ty().skip_binder() - ); - - self.infcx.probe(|_snapshot| { - // The code below doesn't care about regions, and the - // self-ty here doesn't escape this probe, so just erase - // any LBR. - let self_ty = self.tcx().erase_late_bound_regions(&obligation.self_ty()); - let poly_trait_ref = match self_ty.kind { - ty::Dynamic(ref data, ..) => { - if data.auto_traits().any(|did| did == obligation.predicate.def_id()) { - debug!( - "assemble_candidates_from_object_ty: matched builtin bound, \ - pushing candidate" - ); - candidates.vec.push(BuiltinObjectCandidate); - return; - } - - if let Some(principal) = data.principal() { - if !self.infcx.tcx.features().object_safe_for_dispatch { - principal.with_self_ty(self.tcx(), self_ty) - } else if self.tcx().is_object_safe(principal.def_id()) { - principal.with_self_ty(self.tcx(), self_ty) - } else { - return; - } - } else { - // Only auto trait bounds exist. - return; - } - } - ty::Infer(ty::TyVar(_)) => { - debug!("assemble_candidates_from_object_ty: ambiguous"); - candidates.ambiguous = true; // could wind up being an object type - return; - } - _ => return, - }; - - debug!("assemble_candidates_from_object_ty: poly_trait_ref={:?}", poly_trait_ref); - - // Count only those upcast versions that match the trait-ref - // we are looking for. Specifically, do not only check for the - // correct trait, but also the correct type parameters. - // For example, we may be trying to upcast `Foo` to `Bar<i32>`, - // but `Foo` is declared as `trait Foo: Bar<u32>`. - let upcast_trait_refs = util::supertraits(self.tcx(), poly_trait_ref) - .filter(|upcast_trait_ref| { - self.infcx - .probe(|_| self.match_poly_trait_ref(obligation, *upcast_trait_ref).is_ok()) - }) - .count(); - - if upcast_trait_refs > 1 { - // Can be upcast in many ways; need more type information. - candidates.ambiguous = true; - } else if upcast_trait_refs == 1 { - candidates.vec.push(ObjectCandidate); - } - }) - } - - /// Searches for unsizing that might apply to `obligation`. - fn assemble_candidates_for_unsizing( - &mut self, - obligation: &TraitObligation<'tcx>, - candidates: &mut SelectionCandidateSet<'tcx>, - ) { - // We currently never consider higher-ranked obligations e.g. - // `for<'a> &'a T: Unsize<Trait+'a>` to be implemented. This is not - // because they are a priori invalid, and we could potentially add support - // for them later, it's just that there isn't really a strong need for it. - // A `T: Unsize<U>` obligation is always used as part of a `T: CoerceUnsize<U>` - // impl, and those are generally applied to concrete types. - // - // That said, one might try to write a fn with a where clause like - // for<'a> Foo<'a, T>: Unsize<Foo<'a, Trait>> - // where the `'a` is kind of orthogonal to the relevant part of the `Unsize`. - // Still, you'd be more likely to write that where clause as - // T: Trait - // so it seems ok if we (conservatively) fail to accept that `Unsize` - // obligation above. Should be possible to extend this in the future. - let source = match obligation.self_ty().no_bound_vars() { - Some(t) => t, - None => { - // Don't add any candidates if there are bound regions. - return; - } - }; - let target = obligation.predicate.skip_binder().trait_ref.substs.type_at(1); - - debug!("assemble_candidates_for_unsizing(source={:?}, target={:?})", source, target); - - let may_apply = match (&source.kind, &target.kind) { - // Trait+Kx+'a -> Trait+Ky+'b (upcasts). - (&ty::Dynamic(ref data_a, ..), &ty::Dynamic(ref data_b, ..)) => { - // Upcasts permit two things: - // - // 1. Dropping auto traits, e.g., `Foo + Send` to `Foo` - // 2. Tightening the region bound, e.g., `Foo + 'a` to `Foo + 'b` if `'a: 'b` - // - // Note that neither of these changes requires any - // change at runtime. Eventually this will be - // generalized. - // - // We always upcast when we can because of reason - // #2 (region bounds). - data_a.principal_def_id() == data_b.principal_def_id() - && data_b - .auto_traits() - // All of a's auto traits need to be in b's auto traits. - .all(|b| data_a.auto_traits().any(|a| a == b)) - } - - // `T` -> `Trait` - (_, &ty::Dynamic(..)) => true, - - // Ambiguous handling is below `T` -> `Trait`, because inference - // variables can still implement `Unsize<Trait>` and nested - // obligations will have the final say (likely deferred). - (&ty::Infer(ty::TyVar(_)), _) | (_, &ty::Infer(ty::TyVar(_))) => { - debug!("assemble_candidates_for_unsizing: ambiguous"); - candidates.ambiguous = true; - false - } - - // `[T; n]` -> `[T]` - (&ty::Array(..), &ty::Slice(_)) => true, - - // `Struct<T>` -> `Struct<U>` - (&ty::Adt(def_id_a, _), &ty::Adt(def_id_b, _)) if def_id_a.is_struct() => { - def_id_a == def_id_b - } - - // `(.., T)` -> `(.., U)` - (&ty::Tuple(tys_a), &ty::Tuple(tys_b)) => tys_a.len() == tys_b.len(), - - _ => false, - }; - - if may_apply { - candidates.vec.push(BuiltinUnsizeCandidate); - } - } - - fn assemble_candidates_for_trait_alias( - &mut self, - obligation: &TraitObligation<'tcx>, - candidates: &mut SelectionCandidateSet<'tcx>, - ) -> Result<(), SelectionError<'tcx>> { - // Okay to skip binder here because the tests we do below do not involve bound regions. - let self_ty = *obligation.self_ty().skip_binder(); - debug!("assemble_candidates_for_trait_alias(self_ty={:?})", self_ty); - - let def_id = obligation.predicate.def_id(); - - if self.tcx().is_trait_alias(def_id) { - candidates.vec.push(TraitAliasCandidate(def_id)); - } - - Ok(()) - } - - /////////////////////////////////////////////////////////////////////////// - // WINNOW - // - // Winnowing is the process of attempting to resolve ambiguity by - // probing further. During the winnowing process, we unify all - // type variables and then we also attempt to evaluate recursive - // bounds to see if they are satisfied. - - /// Returns `true` if `victim` should be dropped in favor of - /// `other`. Generally speaking we will drop duplicate - /// candidates and prefer where-clause candidates. - /// - /// See the comment for "SelectionCandidate" for more details. - fn candidate_should_be_dropped_in_favor_of( - &mut self, - victim: &EvaluatedCandidate<'tcx>, - other: &EvaluatedCandidate<'tcx>, - needs_infer: bool, - ) -> bool { - if victim.candidate == other.candidate { - return true; - } - - // Check if a bound would previously have been removed when normalizing - // the param_env so that it can be given the lowest priority. See - // #50825 for the motivation for this. - let is_global = - |cand: &ty::PolyTraitRef<'_>| cand.is_global() && !cand.has_late_bound_regions(); - - match other.candidate { - // Prefer `BuiltinCandidate { has_nested: false }` to anything else. - // This is a fix for #53123 and prevents winnowing from accidentally extending the - // lifetime of a variable. - BuiltinCandidate { has_nested: false } => true, - ParamCandidate(ref cand) => match victim.candidate { - AutoImplCandidate(..) => { - bug!( - "default implementations shouldn't be recorded \ - when there are other valid candidates" - ); - } - // Prefer `BuiltinCandidate { has_nested: false }` to anything else. - // This is a fix for #53123 and prevents winnowing from accidentally extending the - // lifetime of a variable. - BuiltinCandidate { has_nested: false } => false, - ImplCandidate(..) - | ClosureCandidate - | GeneratorCandidate - | FnPointerCandidate - | BuiltinObjectCandidate - | BuiltinUnsizeCandidate - | BuiltinCandidate { .. } - | TraitAliasCandidate(..) => { - // Global bounds from the where clause should be ignored - // here (see issue #50825). Otherwise, we have a where - // clause so don't go around looking for impls. - !is_global(cand) - } - ObjectCandidate | ProjectionCandidate => { - // Arbitrarily give param candidates priority - // over projection and object candidates. - !is_global(cand) - } - ParamCandidate(..) => false, - }, - ObjectCandidate | ProjectionCandidate => match victim.candidate { - AutoImplCandidate(..) => { - bug!( - "default implementations shouldn't be recorded \ - when there are other valid candidates" - ); - } - // Prefer `BuiltinCandidate { has_nested: false }` to anything else. - // This is a fix for #53123 and prevents winnowing from accidentally extending the - // lifetime of a variable. - BuiltinCandidate { has_nested: false } => false, - ImplCandidate(..) - | ClosureCandidate - | GeneratorCandidate - | FnPointerCandidate - | BuiltinObjectCandidate - | BuiltinUnsizeCandidate - | BuiltinCandidate { .. } - | TraitAliasCandidate(..) => true, - ObjectCandidate | ProjectionCandidate => { - // Arbitrarily give param candidates priority - // over projection and object candidates. - true - } - ParamCandidate(ref cand) => is_global(cand), - }, - ImplCandidate(other_def) => { - // See if we can toss out `victim` based on specialization. - // This requires us to know *for sure* that the `other` impl applies - // i.e., `EvaluatedToOk`. - if other.evaluation.must_apply_modulo_regions() { - match victim.candidate { - ImplCandidate(victim_def) => { - let tcx = self.tcx(); - if tcx.specializes((other_def, victim_def)) { - return true; - } - return match tcx.impls_are_allowed_to_overlap(other_def, victim_def) { - Some(ty::ImplOverlapKind::Permitted { marker: true }) => { - // Subtle: If the predicate we are evaluating has inference - // variables, do *not* allow discarding candidates due to - // marker trait impls. - // - // Without this restriction, we could end up accidentally - // constrainting inference variables based on an arbitrarily - // chosen trait impl. - // - // Imagine we have the following code: - // - // ```rust - // #[marker] trait MyTrait {} - // impl MyTrait for u8 {} - // impl MyTrait for bool {} - // ``` - // - // And we are evaluating the predicate `<_#0t as MyTrait>`. - // - // During selection, we will end up with one candidate for each - // impl of `MyTrait`. If we were to discard one impl in favor - // of the other, we would be left with one candidate, causing - // us to "successfully" select the predicate, unifying - // _#0t with (for example) `u8`. - // - // However, we have no reason to believe that this unification - // is correct - we've essentially just picked an arbitrary - // *possibility* for _#0t, and required that this be the *only* - // possibility. - // - // Eventually, we will either: - // 1) Unify all inference variables in the predicate through - // some other means (e.g. type-checking of a function). We will - // then be in a position to drop marker trait candidates - // without constraining inference variables (since there are - // none left to constrin) - // 2) Be left with some unconstrained inference variables. We - // will then correctly report an inference error, since the - // existence of multiple marker trait impls tells us nothing - // about which one should actually apply. - !needs_infer - } - Some(_) => true, - None => false, - }; - } - ParamCandidate(ref cand) => { - // Prefer the impl to a global where clause candidate. - return is_global(cand); - } - _ => (), - } - } - - false - } - ClosureCandidate - | GeneratorCandidate - | FnPointerCandidate - | BuiltinObjectCandidate - | BuiltinUnsizeCandidate - | BuiltinCandidate { has_nested: true } => { - match victim.candidate { - ParamCandidate(ref cand) => { - // Prefer these to a global where-clause bound - // (see issue #50825). - is_global(cand) && other.evaluation.must_apply_modulo_regions() - } - _ => false, - } - } - _ => false, - } - } - - /////////////////////////////////////////////////////////////////////////// - // BUILTIN BOUNDS - // - // These cover the traits that are built-in to the language - // itself: `Copy`, `Clone` and `Sized`. - - fn assemble_builtin_bound_candidates( - &mut self, - conditions: BuiltinImplConditions<'tcx>, - candidates: &mut SelectionCandidateSet<'tcx>, - ) -> Result<(), SelectionError<'tcx>> { - match conditions { - BuiltinImplConditions::Where(nested) => { - debug!("builtin_bound: nested={:?}", nested); - candidates - .vec - .push(BuiltinCandidate { has_nested: nested.skip_binder().len() > 0 }); - } - BuiltinImplConditions::None => {} - BuiltinImplConditions::Ambiguous => { - debug!("assemble_builtin_bound_candidates: ambiguous builtin"); - candidates.ambiguous = true; - } - } - - Ok(()) - } - - fn sized_conditions( - &mut self, - obligation: &TraitObligation<'tcx>, - ) -> BuiltinImplConditions<'tcx> { - use self::BuiltinImplConditions::{Ambiguous, None, Where}; - - // NOTE: binder moved to (*) - let self_ty = self.infcx.shallow_resolve(obligation.predicate.skip_binder().self_ty()); - - match self_ty.kind { - ty::Infer(ty::IntVar(_)) - | ty::Infer(ty::FloatVar(_)) - | ty::Uint(_) - | ty::Int(_) - | ty::Bool - | ty::Float(_) - | ty::FnDef(..) - | ty::FnPtr(_) - | ty::RawPtr(..) - | ty::Char - | ty::Ref(..) - | ty::Generator(..) - | ty::GeneratorWitness(..) - | ty::Array(..) - | ty::Closure(..) - | ty::Never - | ty::Error => { - // safe for everything - Where(ty::Binder::dummy(Vec::new())) - } - - ty::Str | ty::Slice(_) | ty::Dynamic(..) | ty::Foreign(..) => None, - - ty::Tuple(tys) => { - Where(ty::Binder::bind(tys.last().into_iter().map(|k| k.expect_ty()).collect())) - } - - ty::Adt(def, substs) => { - let sized_crit = def.sized_constraint(self.tcx()); - // (*) binder moved here - Where(ty::Binder::bind( - sized_crit.iter().map(|ty| ty.subst(self.tcx(), substs)).collect(), - )) - } - - ty::Projection(_) | ty::Param(_) | ty::Opaque(..) => None, - ty::Infer(ty::TyVar(_)) => Ambiguous, - - ty::UnnormalizedProjection(..) - | ty::Placeholder(..) - | ty::Bound(..) - | ty::Infer(ty::FreshTy(_)) - | ty::Infer(ty::FreshIntTy(_)) - | ty::Infer(ty::FreshFloatTy(_)) => { - bug!("asked to assemble builtin bounds of unexpected type: {:?}", self_ty); - } - } - } - - fn copy_clone_conditions( - &mut self, - obligation: &TraitObligation<'tcx>, - ) -> BuiltinImplConditions<'tcx> { - // NOTE: binder moved to (*) - let self_ty = self.infcx.shallow_resolve(obligation.predicate.skip_binder().self_ty()); - - use self::BuiltinImplConditions::{Ambiguous, None, Where}; - - match self_ty.kind { - ty::Infer(ty::IntVar(_)) - | ty::Infer(ty::FloatVar(_)) - | ty::FnDef(..) - | ty::FnPtr(_) - | ty::Error => Where(ty::Binder::dummy(Vec::new())), - - ty::Uint(_) - | ty::Int(_) - | ty::Bool - | ty::Float(_) - | ty::Char - | ty::RawPtr(..) - | ty::Never - | ty::Ref(_, _, hir::Mutability::Not) => { - // Implementations provided in libcore - None - } - - ty::Dynamic(..) - | ty::Str - | ty::Slice(..) - | ty::Generator(..) - | ty::GeneratorWitness(..) - | ty::Foreign(..) - | ty::Ref(_, _, hir::Mutability::Mut) => None, - - ty::Array(element_ty, _) => { - // (*) binder moved here - Where(ty::Binder::bind(vec![element_ty])) - } - - ty::Tuple(tys) => { - // (*) binder moved here - Where(ty::Binder::bind(tys.iter().map(|k| k.expect_ty()).collect())) - } - - ty::Closure(def_id, substs) => { - // (*) binder moved here - Where(ty::Binder::bind(substs.as_closure().upvar_tys(def_id, self.tcx()).collect())) - } - - ty::Adt(..) | ty::Projection(..) | ty::Param(..) | ty::Opaque(..) => { - // Fallback to whatever user-defined impls exist in this case. - None - } - - ty::Infer(ty::TyVar(_)) => { - // Unbound type variable. Might or might not have - // applicable impls and so forth, depending on what - // those type variables wind up being bound to. - Ambiguous - } - - ty::UnnormalizedProjection(..) - | ty::Placeholder(..) - | ty::Bound(..) - | ty::Infer(ty::FreshTy(_)) - | ty::Infer(ty::FreshIntTy(_)) - | ty::Infer(ty::FreshFloatTy(_)) => { - bug!("asked to assemble builtin bounds of unexpected type: {:?}", self_ty); - } - } - } - - /// For default impls, we need to break apart a type into its - /// "constituent types" -- meaning, the types that it contains. - /// - /// Here are some (simple) examples: - /// - /// ``` - /// (i32, u32) -> [i32, u32] - /// Foo where struct Foo { x: i32, y: u32 } -> [i32, u32] - /// Bar<i32> where struct Bar<T> { x: T, y: u32 } -> [i32, u32] - /// Zed<i32> where enum Zed { A(T), B(u32) } -> [i32, u32] + /// pub fn foo<T: Trait + ?Sized>() { + /// <T as Trait>::xyz(); + /// } /// ``` - fn constituent_types_for_ty(&self, t: Ty<'tcx>) -> Vec<Ty<'tcx>> { - match t.kind { - ty::Uint(_) - | ty::Int(_) - | ty::Bool - | ty::Float(_) - | ty::FnDef(..) - | ty::FnPtr(_) - | ty::Str - | ty::Error - | ty::Infer(ty::IntVar(_)) - | ty::Infer(ty::FloatVar(_)) - | ty::Never - | ty::Char => Vec::new(), - - ty::UnnormalizedProjection(..) - | ty::Placeholder(..) - | ty::Dynamic(..) - | ty::Param(..) - | ty::Foreign(..) - | ty::Projection(..) - | ty::Bound(..) - | ty::Infer(ty::TyVar(_)) - | ty::Infer(ty::FreshTy(_)) - | ty::Infer(ty::FreshIntTy(_)) - | ty::Infer(ty::FreshFloatTy(_)) => { - bug!("asked to assemble constituent types of unexpected type: {:?}", t); - } - - ty::RawPtr(ty::TypeAndMut { ty: element_ty, .. }) | ty::Ref(_, element_ty, _) => { - vec![element_ty] - } - - ty::Array(element_ty, _) | ty::Slice(element_ty) => vec![element_ty], - - ty::Tuple(ref tys) => { - // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet - tys.iter().map(|k| k.expect_ty()).collect() - } - - ty::Closure(def_id, ref substs) => { - substs.as_closure().upvar_tys(def_id, self.tcx()).collect() - } - - ty::Generator(def_id, ref substs, _) => { - let witness = substs.as_generator().witness(def_id, self.tcx()); - substs - .as_generator() - .upvar_tys(def_id, self.tcx()) - .chain(iter::once(witness)) - .collect() - } - - ty::GeneratorWitness(types) => { - // This is sound because no regions in the witness can refer to - // the binder outside the witness. So we'll effectivly reuse - // the implicit binder around the witness. - types.skip_binder().to_vec() - } - - // For `PhantomData<T>`, we pass `T`. - ty::Adt(def, substs) if def.is_phantom_data() => substs.types().collect(), - - ty::Adt(def, substs) => def.all_fields().map(|f| f.ty(self.tcx(), substs)).collect(), - - ty::Opaque(def_id, substs) => { - // We can resolve the `impl Trait` to its concrete type, - // which enforces a DAG between the functions requiring - // the auto trait bounds in question. - vec![self.tcx().type_of(def_id).subst(self.tcx(), substs)] - } - } - } - - fn collect_predicates_for_types( - &mut self, - param_env: ty::ParamEnv<'tcx>, - cause: ObligationCause<'tcx>, - recursion_depth: usize, - trait_def_id: DefId, - types: ty::Binder<Vec<Ty<'tcx>>>, - ) -> Vec<PredicateObligation<'tcx>> { - // Because the types were potentially derived from - // higher-ranked obligations they may reference late-bound - // regions. For example, `for<'a> Foo<&'a int> : Copy` would - // yield a type like `for<'a> &'a int`. In general, we - // maintain the invariant that we never manipulate bound - // regions, so we have to process these bound regions somehow. - // - // The strategy is to: - // - // 1. Instantiate those regions to placeholder regions (e.g., - // `for<'a> &'a int` becomes `&0 int`. - // 2. Produce something like `&'0 int : Copy` - // 3. Re-bind the regions back to `for<'a> &'a int : Copy` - - types - .skip_binder() - .into_iter() - .flat_map(|ty| { - // binder moved -\ - let ty: ty::Binder<Ty<'tcx>> = ty::Binder::bind(ty); // <----/ - - self.infcx.commit_unconditionally(|_| { - let (skol_ty, _) = self.infcx.replace_bound_vars_with_placeholders(&ty); - let Normalized { value: normalized_ty, mut obligations } = - project::normalize_with_depth( - self, - param_env, - cause.clone(), - recursion_depth, - &skol_ty, - ); - let skol_obligation = predicate_for_trait_def( - self.tcx(), - param_env, - cause.clone(), - trait_def_id, - recursion_depth, - normalized_ty, - &[], - ); - obligations.push(skol_obligation); - obligations - }) - }) - .collect() - } - - /////////////////////////////////////////////////////////////////////////// - // CONFIRMATION - // - // Confirmation unifies the output type parameters of the trait - // with the values found in the obligation, possibly yielding a - // type error. See the [rustc guide] for more details. - // - // [rustc guide]: - // https://rust-lang.github.io/rustc-guide/traits/resolution.html#confirmation - - fn confirm_candidate( - &mut self, - obligation: &TraitObligation<'tcx>, - candidate: SelectionCandidate<'tcx>, - ) -> Result<Selection<'tcx>, SelectionError<'tcx>> { - debug!("confirm_candidate({:?}, {:?})", obligation, candidate); - - match candidate { - BuiltinCandidate { has_nested } => { - let data = self.confirm_builtin_candidate(obligation, has_nested); - Ok(VtableBuiltin(data)) - } - - ParamCandidate(param) => { - let obligations = self.confirm_param_candidate(obligation, param); - Ok(VtableParam(obligations)) - } - - ImplCandidate(impl_def_id) => { - Ok(VtableImpl(self.confirm_impl_candidate(obligation, impl_def_id))) - } - - AutoImplCandidate(trait_def_id) => { - let data = self.confirm_auto_impl_candidate(obligation, trait_def_id); - Ok(VtableAutoImpl(data)) - } - - ProjectionCandidate => { - self.confirm_projection_candidate(obligation); - Ok(VtableParam(Vec::new())) - } - - ClosureCandidate => { - let vtable_closure = self.confirm_closure_candidate(obligation)?; - Ok(VtableClosure(vtable_closure)) - } - - GeneratorCandidate => { - let vtable_generator = self.confirm_generator_candidate(obligation)?; - Ok(VtableGenerator(vtable_generator)) - } - - FnPointerCandidate => { - let data = self.confirm_fn_pointer_candidate(obligation)?; - Ok(VtableFnPointer(data)) - } - - TraitAliasCandidate(alias_def_id) => { - let data = self.confirm_trait_alias_candidate(obligation, alias_def_id); - Ok(VtableTraitAlias(data)) - } - - ObjectCandidate => { - let data = self.confirm_object_candidate(obligation); - Ok(VtableObject(data)) - } - - BuiltinObjectCandidate => { - // This indicates something like `Trait + Send: Send`. In this case, we know that - // this holds because that's what the object type is telling us, and there's really - // no additional obligations to prove and no types in particular to unify, etc. - Ok(VtableParam(Vec::new())) - } - - BuiltinUnsizeCandidate => { - let data = self.confirm_builtin_unsize_candidate(obligation)?; - Ok(VtableBuiltin(data)) - } - } - } - - fn confirm_projection_candidate(&mut self, obligation: &TraitObligation<'tcx>) { - self.infcx.commit_unconditionally(|snapshot| { - let result = - self.match_projection_obligation_against_definition_bounds(obligation, snapshot); - assert!(result); - }) - } - - fn confirm_param_candidate( - &mut self, - obligation: &TraitObligation<'tcx>, - param: ty::PolyTraitRef<'tcx>, - ) -> Vec<PredicateObligation<'tcx>> { - debug!("confirm_param_candidate({:?},{:?})", obligation, param); - - // During evaluation, we already checked that this - // where-clause trait-ref could be unified with the obligation - // trait-ref. Repeat that unification now without any - // transactional boundary; it should not fail. - match self.match_where_clause_trait_ref(obligation, param.clone()) { - Ok(obligations) => obligations, - Err(()) => { - bug!( - "Where clause `{:?}` was applicable to `{:?}` but now is not", - param, - obligation - ); - } - } - } - - fn confirm_builtin_candidate( - &mut self, - obligation: &TraitObligation<'tcx>, - has_nested: bool, - ) -> VtableBuiltinData<PredicateObligation<'tcx>> { - debug!("confirm_builtin_candidate({:?}, {:?})", obligation, has_nested); - - let lang_items = self.tcx().lang_items(); - let obligations = if has_nested { - let trait_def = obligation.predicate.def_id(); - let conditions = if Some(trait_def) == lang_items.sized_trait() { - self.sized_conditions(obligation) - } else if Some(trait_def) == lang_items.copy_trait() { - self.copy_clone_conditions(obligation) - } else if Some(trait_def) == lang_items.clone_trait() { - self.copy_clone_conditions(obligation) - } else { - bug!("unexpected builtin trait {:?}", trait_def) - }; - let nested = match conditions { - BuiltinImplConditions::Where(nested) => nested, - _ => bug!("obligation {:?} had matched a builtin impl but now doesn't", obligation), - }; - - let cause = obligation.derived_cause(BuiltinDerivedObligation); - self.collect_predicates_for_types( - obligation.param_env, - cause, - obligation.recursion_depth + 1, - trait_def, - nested, - ) - } else { - vec![] - }; - - debug!("confirm_builtin_candidate: obligations={:?}", obligations); - - VtableBuiltinData { nested: obligations } - } - - /// This handles the case where a `auto trait Foo` impl is being used. - /// The idea is that the impl applies to `X : Foo` if the following conditions are met: /// - /// 1. For each constituent type `Y` in `X`, `Y : Foo` holds - /// 2. For each where-clause `C` declared on `Foo`, `[Self => X] C` holds. - fn confirm_auto_impl_candidate( - &mut self, - obligation: &TraitObligation<'tcx>, - trait_def_id: DefId, - ) -> VtableAutoImplData<PredicateObligation<'tcx>> { - debug!("confirm_auto_impl_candidate({:?}, {:?})", obligation, trait_def_id); - - let types = obligation.predicate.map_bound(|inner| { - let self_ty = self.infcx.shallow_resolve(inner.self_ty()); - self.constituent_types_for_ty(self_ty) - }); - self.vtable_auto_impl(obligation, trait_def_id, types) - } - - /// See `confirm_auto_impl_candidate`. - fn vtable_auto_impl( - &mut self, - obligation: &TraitObligation<'tcx>, - trait_def_id: DefId, - nested: ty::Binder<Vec<Ty<'tcx>>>, - ) -> VtableAutoImplData<PredicateObligation<'tcx>> { - debug!("vtable_auto_impl: nested={:?}", nested); - - let cause = obligation.derived_cause(BuiltinDerivedObligation); - let mut obligations = self.collect_predicates_for_types( - obligation.param_env, - cause, - obligation.recursion_depth + 1, - trait_def_id, - nested, - ); - - let trait_obligations: Vec<PredicateObligation<'_>> = - self.infcx.commit_unconditionally(|_| { - let poly_trait_ref = obligation.predicate.to_poly_trait_ref(); - let (trait_ref, _) = - self.infcx.replace_bound_vars_with_placeholders(&poly_trait_ref); - let cause = obligation.derived_cause(ImplDerivedObligation); - self.impl_or_trait_obligations( - cause, - obligation.recursion_depth + 1, - obligation.param_env, - trait_def_id, - &trait_ref.substs, - ) - }); - - // Adds the predicates from the trait. Note that this contains a `Self: Trait` - // predicate as usual. It won't have any effect since auto traits are coinductive. - obligations.extend(trait_obligations); - - debug!("vtable_auto_impl: obligations={:?}", obligations); - - VtableAutoImplData { trait_def_id, nested: obligations } - } - - fn confirm_impl_candidate( - &mut self, - obligation: &TraitObligation<'tcx>, - impl_def_id: DefId, - ) -> VtableImplData<'tcx, PredicateObligation<'tcx>> { - debug!("confirm_impl_candidate({:?},{:?})", obligation, impl_def_id); - - // First, create the substitutions by matching the impl again, - // this time not in a probe. - self.infcx.commit_unconditionally(|snapshot| { - let substs = self.rematch_impl(impl_def_id, obligation, snapshot); - debug!("confirm_impl_candidate: substs={:?}", substs); - let cause = obligation.derived_cause(ImplDerivedObligation); - self.vtable_impl( - impl_def_id, - substs, - cause, - obligation.recursion_depth + 1, - obligation.param_env, - ) - }) - } - - fn vtable_impl( - &mut self, - impl_def_id: DefId, - mut substs: Normalized<'tcx, SubstsRef<'tcx>>, - cause: ObligationCause<'tcx>, - recursion_depth: usize, - param_env: ty::ParamEnv<'tcx>, - ) -> VtableImplData<'tcx, PredicateObligation<'tcx>> { - debug!( - "vtable_impl(impl_def_id={:?}, substs={:?}, recursion_depth={})", - impl_def_id, substs, recursion_depth, - ); - - let mut impl_obligations = self.impl_or_trait_obligations( - cause, - recursion_depth, - param_env, - impl_def_id, - &substs.value, - ); - - debug!( - "vtable_impl: impl_def_id={:?} impl_obligations={:?}", - impl_def_id, impl_obligations - ); - - // Because of RFC447, the impl-trait-ref and obligations - // are sufficient to determine the impl substs, without - // relying on projections in the impl-trait-ref. - // - // e.g., `impl<U: Tr, V: Iterator<Item=U>> Foo<<U as Tr>::T> for V` - impl_obligations.append(&mut substs.obligations); - - VtableImplData { impl_def_id, substs: substs.value, nested: impl_obligations } - } - - fn confirm_object_candidate( - &mut self, - obligation: &TraitObligation<'tcx>, - ) -> VtableObjectData<'tcx, PredicateObligation<'tcx>> { - debug!("confirm_object_candidate({:?})", obligation); - - // FIXME(nmatsakis) skipping binder here seems wrong -- we should - // probably flatten the binder from the obligation and the binder - // from the object. Have to try to make a broken test case that - // results. - let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder()); - let poly_trait_ref = match self_ty.kind { - ty::Dynamic(ref data, ..) => data - .principal() - .unwrap_or_else(|| { - span_bug!(obligation.cause.span, "object candidate with no principal") - }) - .with_self_ty(self.tcx(), self_ty), - _ => span_bug!(obligation.cause.span, "object candidate with non-object"), - }; - - let mut upcast_trait_ref = None; - let mut nested = vec![]; - let vtable_base; - - { - let tcx = self.tcx(); - - // We want to find the first supertrait in the list of - // supertraits that we can unify with, and do that - // unification. We know that there is exactly one in the list - // where we can unify, because otherwise select would have - // reported an ambiguity. (When we do find a match, also - // record it for later.) - let nonmatching = util::supertraits(tcx, poly_trait_ref).take_while(|&t| { - match self.infcx.commit_if_ok(|_| self.match_poly_trait_ref(obligation, t)) { - Ok(obligations) => { - upcast_trait_ref = Some(t); - nested.extend(obligations); - false - } - Err(_) => true, - } - }); - - // Additionally, for each of the non-matching predicates that - // we pass over, we sum up the set of number of vtable - // entries, so that we can compute the offset for the selected - // trait. - vtable_base = nonmatching.map(|t| super::util::count_own_vtable_entries(tcx, t)).sum(); - } - - VtableObjectData { upcast_trait_ref: upcast_trait_ref.unwrap(), vtable_base, nested } - } - - fn confirm_fn_pointer_candidate( - &mut self, - obligation: &TraitObligation<'tcx>, - ) -> Result<VtableFnPointerData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>> { - debug!("confirm_fn_pointer_candidate({:?})", obligation); - - // Okay to skip binder; it is reintroduced below. - let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder()); - let sig = self_ty.fn_sig(self.tcx()); - let trait_ref = closure_trait_ref_and_return_type( - self.tcx(), - obligation.predicate.def_id(), - self_ty, - sig, - util::TupleArgumentsFlag::Yes, - ) - .map_bound(|(trait_ref, _)| trait_ref); - - let Normalized { value: trait_ref, obligations } = project::normalize_with_depth( - self, - obligation.param_env, - obligation.cause.clone(), - obligation.recursion_depth + 1, - &trait_ref, - ); - - self.confirm_poly_trait_refs( - obligation.cause.clone(), - obligation.param_env, - obligation.predicate.to_poly_trait_ref(), - trait_ref, - )?; - Ok(VtableFnPointerData { fn_ty: self_ty, nested: obligations }) - } - - fn confirm_trait_alias_candidate( - &mut self, - obligation: &TraitObligation<'tcx>, - alias_def_id: DefId, - ) -> VtableTraitAliasData<'tcx, PredicateObligation<'tcx>> { - debug!("confirm_trait_alias_candidate({:?}, {:?})", obligation, alias_def_id); - - self.infcx.commit_unconditionally(|_| { - let (predicate, _) = - self.infcx().replace_bound_vars_with_placeholders(&obligation.predicate); - let trait_ref = predicate.trait_ref; - let trait_def_id = trait_ref.def_id; - let substs = trait_ref.substs; - - let trait_obligations = self.impl_or_trait_obligations( - obligation.cause.clone(), - obligation.recursion_depth, - obligation.param_env, - trait_def_id, - &substs, - ); - - debug!( - "confirm_trait_alias_candidate: trait_def_id={:?} trait_obligations={:?}", - trait_def_id, trait_obligations - ); - - VtableTraitAliasData { alias_def_id, substs: substs, nested: trait_obligations } - }) - } - - fn confirm_generator_candidate( - &mut self, - obligation: &TraitObligation<'tcx>, - ) -> Result<VtableGeneratorData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>> { - // Okay to skip binder because the substs on generator types never - // touch bound regions, they just capture the in-scope - // type/region parameters. - let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder()); - let (generator_def_id, substs) = match self_ty.kind { - ty::Generator(id, substs, _) => (id, substs), - _ => bug!("closure candidate for non-closure {:?}", obligation), - }; - - debug!("confirm_generator_candidate({:?},{:?},{:?})", obligation, generator_def_id, substs); - - let trait_ref = self.generator_trait_ref_unnormalized(obligation, generator_def_id, substs); - let Normalized { value: trait_ref, mut obligations } = normalize_with_depth( - self, - obligation.param_env, - obligation.cause.clone(), - obligation.recursion_depth + 1, - &trait_ref, - ); - - debug!( - "confirm_generator_candidate(generator_def_id={:?}, \ - trait_ref={:?}, obligations={:?})", - generator_def_id, trait_ref, obligations - ); - - obligations.extend(self.confirm_poly_trait_refs( - obligation.cause.clone(), - obligation.param_env, - obligation.predicate.to_poly_trait_ref(), - trait_ref, - )?); - - Ok(VtableGeneratorData { generator_def_id, substs, nested: obligations }) - } - - fn confirm_closure_candidate( - &mut self, - obligation: &TraitObligation<'tcx>, - ) -> Result<VtableClosureData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>> { - debug!("confirm_closure_candidate({:?})", obligation); - - let kind = self - .tcx() - .fn_trait_kind_from_lang_item(obligation.predicate.def_id()) - .unwrap_or_else(|| bug!("closure candidate for non-fn trait {:?}", obligation)); - - // Okay to skip binder because the substs on closure types never - // touch bound regions, they just capture the in-scope - // type/region parameters. - let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder()); - let (closure_def_id, substs) = match self_ty.kind { - ty::Closure(id, substs) => (id, substs), - _ => bug!("closure candidate for non-closure {:?}", obligation), - }; - - let trait_ref = self.closure_trait_ref_unnormalized(obligation, closure_def_id, substs); - let Normalized { value: trait_ref, mut obligations } = normalize_with_depth( - self, - obligation.param_env, - obligation.cause.clone(), - obligation.recursion_depth + 1, - &trait_ref, - ); - - debug!( - "confirm_closure_candidate(closure_def_id={:?}, trait_ref={:?}, obligations={:?})", - closure_def_id, trait_ref, obligations - ); - - obligations.extend(self.confirm_poly_trait_refs( - obligation.cause.clone(), - obligation.param_env, - obligation.predicate.to_poly_trait_ref(), - trait_ref, - )?); - - // FIXME: Chalk - - if !self.tcx().sess.opts.debugging_opts.chalk { - obligations.push(Obligation::new( - obligation.cause.clone(), - obligation.param_env, - ty::Predicate::ClosureKind(closure_def_id, substs, kind), - )); - } - - Ok(VtableClosureData { closure_def_id, substs: substs, nested: obligations }) - } - - /// In the case of closure types and fn pointers, - /// we currently treat the input type parameters on the trait as - /// outputs. This means that when we have a match we have only - /// considered the self type, so we have to go back and make sure - /// to relate the argument types too. This is kind of wrong, but - /// since we control the full set of impls, also not that wrong, - /// and it DOES yield better error messages (since we don't report - /// errors as if there is no applicable impl, but rather report - /// errors are about mismatched argument types. + /// When checking `foo`, we have to prove `T: Trait`. This basically + /// translates into this: /// - /// Here is an example. Imagine we have a closure expression - /// and we desugared it so that the type of the expression is - /// `Closure`, and `Closure` expects an int as argument. Then it - /// is "as if" the compiler generated this impl: - /// - /// impl Fn(int) for Closure { ... } - /// - /// Now imagine our obligation is `Fn(usize) for Closure`. So far - /// we have matched the self type `Closure`. At this point we'll - /// compare the `int` to `usize` and generate an error. + /// ```plain,ignore + /// (T: Trait + Sized →_\impl T: Trait), T: Trait ⊢ T: Trait + /// ``` /// - /// Note that this checking occurs *after* the impl has selected, - /// because these output type parameters should not affect the - /// selection of the impl. Therefore, if there is a mismatch, we - /// report an error to the user. - fn confirm_poly_trait_refs( - &mut self, - obligation_cause: ObligationCause<'tcx>, - obligation_param_env: ty::ParamEnv<'tcx>, - obligation_trait_ref: ty::PolyTraitRef<'tcx>, - expected_trait_ref: ty::PolyTraitRef<'tcx>, - ) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> { - self.infcx - .at(&obligation_cause, obligation_param_env) - .sup(obligation_trait_ref, expected_trait_ref) - .map(|InferOk { obligations, .. }| obligations) - .map_err(|e| OutputTypeParameterMismatch(expected_trait_ref, obligation_trait_ref, e)) - } - - fn confirm_builtin_unsize_candidate( - &mut self, - obligation: &TraitObligation<'tcx>, - ) -> Result<VtableBuiltinData<PredicateObligation<'tcx>>, SelectionError<'tcx>> { - let tcx = self.tcx(); - - // `assemble_candidates_for_unsizing` should ensure there are no late-bound - // regions here. See the comment there for more details. - let source = self.infcx.shallow_resolve(obligation.self_ty().no_bound_vars().unwrap()); - let target = obligation.predicate.skip_binder().trait_ref.substs.type_at(1); - let target = self.infcx.shallow_resolve(target); - - debug!("confirm_builtin_unsize_candidate(source={:?}, target={:?})", source, target); - - let mut nested = vec![]; - match (&source.kind, &target.kind) { - // Trait+Kx+'a -> Trait+Ky+'b (upcasts). - (&ty::Dynamic(ref data_a, r_a), &ty::Dynamic(ref data_b, r_b)) => { - // See `assemble_candidates_for_unsizing` for more info. - let existential_predicates = data_a.map_bound(|data_a| { - let iter = data_a - .principal() - .map(|x| ty::ExistentialPredicate::Trait(x)) - .into_iter() - .chain( - data_a - .projection_bounds() - .map(|x| ty::ExistentialPredicate::Projection(x)), - ) - .chain(data_b.auto_traits().map(ty::ExistentialPredicate::AutoTrait)); - tcx.mk_existential_predicates(iter) - }); - let source_trait = tcx.mk_dynamic(existential_predicates, r_b); - - // Require that the traits involved in this upcast are **equal**; - // only the **lifetime bound** is changed. - // - // FIXME: This condition is arguably too strong -- it would - // suffice for the source trait to be a *subtype* of the target - // trait. In particular, changing from something like - // `for<'a, 'b> Foo<'a, 'b>` to `for<'a> Foo<'a, 'a>` should be - // permitted. And, indeed, in the in commit - // 904a0bde93f0348f69914ee90b1f8b6e4e0d7cbc, this - // condition was loosened. However, when the leak check was - // added back, using subtype here actually guides the coercion - // code in such a way that it accepts `old-lub-glb-object.rs`. - // This is probably a good thing, but I've modified this to `.eq` - // because I want to continue rejecting that test (as we have - // done for quite some time) before we are firmly comfortable - // with what our behavior should be there. -nikomatsakis - let InferOk { obligations, .. } = self - .infcx - .at(&obligation.cause, obligation.param_env) - .eq(target, source_trait) // FIXME -- see below - .map_err(|_| Unimplemented)?; - nested.extend(obligations); - - // Register one obligation for 'a: 'b. - let cause = ObligationCause::new( - obligation.cause.span, - obligation.cause.body_id, - ObjectCastObligation(target), - ); - let outlives = ty::OutlivesPredicate(r_a, r_b); - nested.push(Obligation::with_depth( - cause, - obligation.recursion_depth + 1, - obligation.param_env, - ty::Binder::bind(outlives).to_predicate(), - )); - } - - // `T` -> `Trait` - (_, &ty::Dynamic(ref data, r)) => { - let mut object_dids = data.auto_traits().chain(data.principal_def_id()); - if let Some(did) = object_dids.find(|did| !tcx.is_object_safe(*did)) { - return Err(TraitNotObjectSafe(did)); - } - - let cause = ObligationCause::new( - obligation.cause.span, - obligation.cause.body_id, - ObjectCastObligation(target), - ); - - let predicate_to_obligation = |predicate| { - Obligation::with_depth( - cause.clone(), - obligation.recursion_depth + 1, - obligation.param_env, - predicate, - ) - }; - - // Create obligations: - // - Casting `T` to `Trait` - // - For all the various builtin bounds attached to the object cast. (In other - // words, if the object type is `Foo + Send`, this would create an obligation for - // the `Send` check.) - // - Projection predicates - nested.extend( - data.iter().map(|predicate| { - predicate_to_obligation(predicate.with_self_ty(tcx, source)) - }), - ); - - // We can only make objects from sized types. - let tr = ty::TraitRef::new( - tcx.require_lang_item(lang_items::SizedTraitLangItem, None), - tcx.mk_substs_trait(source, &[]), - ); - nested.push(predicate_to_obligation(tr.without_const().to_predicate())); - - // If the type is `Foo + 'a`, ensure that the type - // being cast to `Foo + 'a` outlives `'a`: - let outlives = ty::OutlivesPredicate(source, r); - nested.push(predicate_to_obligation(ty::Binder::dummy(outlives).to_predicate())); - } - - // `[T; n]` -> `[T]` - (&ty::Array(a, _), &ty::Slice(b)) => { - let InferOk { obligations, .. } = self - .infcx - .at(&obligation.cause, obligation.param_env) - .eq(b, a) - .map_err(|_| Unimplemented)?; - nested.extend(obligations); - } - - // `Struct<T>` -> `Struct<U>` - (&ty::Adt(def, substs_a), &ty::Adt(_, substs_b)) => { - let fields = - def.all_fields().map(|field| tcx.type_of(field.did)).collect::<Vec<_>>(); - - // The last field of the structure has to exist and contain type parameters. - let field = if let Some(&field) = fields.last() { - field - } else { - return Err(Unimplemented); - }; - let mut ty_params = GrowableBitSet::new_empty(); - let mut found = false; - for ty in field.walk() { - if let ty::Param(p) = ty.kind { - ty_params.insert(p.index as usize); - found = true; - } - } - if !found { - return Err(Unimplemented); - } - - // Replace type parameters used in unsizing with - // Error and ensure they do not affect any other fields. - // This could be checked after type collection for any struct - // with a potentially unsized trailing field. - let params = substs_a - .iter() - .enumerate() - .map(|(i, &k)| if ty_params.contains(i) { tcx.types.err.into() } else { k }); - let substs = tcx.mk_substs(params); - for &ty in fields.split_last().unwrap().1 { - if ty.subst(tcx, substs).references_error() { - return Err(Unimplemented); - } - } - - // Extract `Field<T>` and `Field<U>` from `Struct<T>` and `Struct<U>`. - let inner_source = field.subst(tcx, substs_a); - let inner_target = field.subst(tcx, substs_b); - - // Check that the source struct with the target's - // unsized parameters is equal to the target. - let params = substs_a.iter().enumerate().map(|(i, &k)| { - if ty_params.contains(i) { substs_b.type_at(i).into() } else { k } - }); - let new_struct = tcx.mk_adt(def, tcx.mk_substs(params)); - let InferOk { obligations, .. } = self - .infcx - .at(&obligation.cause, obligation.param_env) - .eq(target, new_struct) - .map_err(|_| Unimplemented)?; - nested.extend(obligations); - - // Construct the nested `Field<T>: Unsize<Field<U>>` predicate. - nested.push(predicate_for_trait_def( - tcx, - obligation.param_env, - obligation.cause.clone(), - obligation.predicate.def_id(), - obligation.recursion_depth + 1, - inner_source, - &[inner_target.into()], - )); - } - - // `(.., T)` -> `(.., U)` - (&ty::Tuple(tys_a), &ty::Tuple(tys_b)) => { - assert_eq!(tys_a.len(), tys_b.len()); - - // The last field of the tuple has to exist. - let (&a_last, a_mid) = if let Some(x) = tys_a.split_last() { - x - } else { - return Err(Unimplemented); - }; - let &b_last = tys_b.last().unwrap(); - - // Check that the source tuple with the target's - // last element is equal to the target. - let new_tuple = tcx.mk_tup( - a_mid.iter().map(|k| k.expect_ty()).chain(iter::once(b_last.expect_ty())), - ); - let InferOk { obligations, .. } = self - .infcx - .at(&obligation.cause, obligation.param_env) - .eq(target, new_tuple) - .map_err(|_| Unimplemented)?; - nested.extend(obligations); - - // Construct the nested `T: Unsize<U>` predicate. - nested.push(predicate_for_trait_def( - tcx, - obligation.param_env, - obligation.cause.clone(), - obligation.predicate.def_id(), - obligation.recursion_depth + 1, - a_last.expect_ty(), - &[b_last.into()], - )); - } - - _ => bug!(), - }; - - Ok(VtableBuiltinData { nested }) - } - - /////////////////////////////////////////////////////////////////////////// - // Matching + /// 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). // - // Matching is a common path used for both evaluation and - // confirmation. It basically unifies types that appear in impls - // and traits. This does affect the surrounding environment; - // therefore, when used during evaluation, match routines must be - // run inside of a `probe()` so that their side-effects are - // contained. - - fn rematch_impl( - &mut self, - impl_def_id: DefId, - obligation: &TraitObligation<'tcx>, - snapshot: &CombinedSnapshot<'_, 'tcx>, - ) -> Normalized<'tcx, SubstsRef<'tcx>> { - match self.match_impl(impl_def_id, obligation, snapshot) { - Ok(substs) => substs, - Err(()) => { - bug!( - "Impl {:?} was matchable against {:?} but now is not", - impl_def_id, - obligation - ); - } - } - } - - fn match_impl( - &mut self, - impl_def_id: DefId, - obligation: &TraitObligation<'tcx>, - snapshot: &CombinedSnapshot<'_, 'tcx>, - ) -> Result<Normalized<'tcx, SubstsRef<'tcx>>, ()> { - let impl_trait_ref = self.tcx().impl_trait_ref(impl_def_id).unwrap(); - - // Before we create the substitutions and everything, first - // consider a "quick reject". This avoids creating more types - // and so forth that we need to. - if self.fast_reject_trait_refs(obligation, &impl_trait_ref) { - return Err(()); - } - - let (skol_obligation, placeholder_map) = - self.infcx().replace_bound_vars_with_placeholders(&obligation.predicate); - let skol_obligation_trait_ref = skol_obligation.trait_ref; - - let impl_substs = self.infcx.fresh_substs_for_item(obligation.cause.span, impl_def_id); - - let impl_trait_ref = impl_trait_ref.subst(self.tcx(), impl_substs); - - let Normalized { value: impl_trait_ref, obligations: mut nested_obligations } = - project::normalize_with_depth( - self, - obligation.param_env, - obligation.cause.clone(), - obligation.recursion_depth + 1, - &impl_trait_ref, - ); - - debug!( - "match_impl(impl_def_id={:?}, obligation={:?}, \ - impl_trait_ref={:?}, skol_obligation_trait_ref={:?})", - impl_def_id, obligation, impl_trait_ref, skol_obligation_trait_ref - ); - - let InferOk { obligations, .. } = self - .infcx - .at(&obligation.cause, obligation.param_env) - .eq(skol_obligation_trait_ref, impl_trait_ref) - .map_err(|e| debug!("match_impl: failed eq_trait_refs due to `{}`", e))?; - nested_obligations.extend(obligations); - - if let Err(e) = self.infcx.leak_check(false, &placeholder_map, snapshot) { - debug!("match_impl: failed leak check due to `{}`", e); - return Err(()); - } - - if !self.intercrate - && self.tcx().impl_polarity(impl_def_id) == ty::ImplPolarity::Reservation - { - debug!("match_impl: reservation impls only apply in intercrate mode"); - return Err(()); - } - - debug!("match_impl: success impl_substs={:?}", impl_substs); - Ok(Normalized { value: impl_substs, obligations: nested_obligations }) - } - - fn fast_reject_trait_refs( - &mut self, - obligation: &TraitObligation<'_>, - impl_trait_ref: &ty::TraitRef<'_>, - ) -> bool { - // We can avoid creating type variables and doing the full - // substitution if we find that any of the input types, when - // simplified, do not match. - - obligation.predicate.skip_binder().input_types().zip(impl_trait_ref.input_types()).any( - |(obligation_ty, impl_ty)| { - let simplified_obligation_ty = - fast_reject::simplify_type(self.tcx(), obligation_ty, true); - let simplified_impl_ty = fast_reject::simplify_type(self.tcx(), impl_ty, false); - - simplified_obligation_ty.is_some() - && simplified_impl_ty.is_some() - && simplified_obligation_ty != simplified_impl_ty - }, - ) - } - - /// Normalize `where_clause_trait_ref` and try to match it against - /// `obligation`. If successful, return any predicates that - /// result from the normalization. Normalization is necessary - /// because where-clauses are stored in the parameter environment - /// unnormalized. - fn match_where_clause_trait_ref( - &mut self, - obligation: &TraitObligation<'tcx>, - where_clause_trait_ref: ty::PolyTraitRef<'tcx>, - ) -> Result<Vec<PredicateObligation<'tcx>>, ()> { - self.match_poly_trait_ref(obligation, where_clause_trait_ref) - } - - /// Returns `Ok` if `poly_trait_ref` being true implies that the - /// obligation is satisfied. - fn match_poly_trait_ref( - &mut self, - obligation: &TraitObligation<'tcx>, - poly_trait_ref: ty::PolyTraitRef<'tcx>, - ) -> Result<Vec<PredicateObligation<'tcx>>, ()> { - debug!( - "match_poly_trait_ref: obligation={:?} poly_trait_ref={:?}", - obligation, poly_trait_ref - ); - - self.infcx - .at(&obligation.cause, obligation.param_env) - .sup(obligation.predicate.to_poly_trait_ref(), poly_trait_ref) - .map(|InferOk { obligations, .. }| obligations) - .map_err(|_| ()) - } - - /////////////////////////////////////////////////////////////////////////// - // Miscellany - - fn match_fresh_trait_refs( - &self, - previous: &ty::PolyTraitRef<'tcx>, - current: &ty::PolyTraitRef<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ) -> bool { - let mut matcher = ty::_match::Match::new(self.tcx(), param_env); - matcher.relate(previous, current).is_ok() - } - - fn push_stack<'o>( - &mut self, - previous_stack: TraitObligationStackList<'o, 'tcx>, - obligation: &'o TraitObligation<'tcx>, - ) -> TraitObligationStack<'o, 'tcx> { - let fresh_trait_ref = - obligation.predicate.to_poly_trait_ref().fold_with(&mut self.freshener); - - let dfn = previous_stack.cache.next_dfn(); - let depth = previous_stack.depth() + 1; - TraitObligationStack { - obligation, - fresh_trait_ref, - reached_depth: Cell::new(depth), - previous: previous_stack, - dfn, - depth, - } - } - - fn closure_trait_ref_unnormalized( - &mut self, - obligation: &TraitObligation<'tcx>, - closure_def_id: DefId, - substs: SubstsRef<'tcx>, - ) -> ty::PolyTraitRef<'tcx> { - debug!( - "closure_trait_ref_unnormalized(obligation={:?}, closure_def_id={:?}, substs={:?})", - obligation, closure_def_id, substs, - ); - let closure_type = self.infcx.closure_sig(closure_def_id, substs); - - debug!("closure_trait_ref_unnormalized: closure_type = {:?}", closure_type); - - // (1) Feels icky to skip the binder here, but OTOH we know - // that the self-type is an unboxed closure type and hence is - // in fact unparameterized (or at least does not reference any - // regions bound in the obligation). Still probably some - // refactoring could make this nicer. - closure_trait_ref_and_return_type( - self.tcx(), - obligation.predicate.def_id(), - obligation.predicate.skip_binder().self_ty(), // (1) - closure_type, - util::TupleArgumentsFlag::No, - ) - .map_bound(|(trait_ref, _)| trait_ref) - } - - fn generator_trait_ref_unnormalized( - &mut self, - obligation: &TraitObligation<'tcx>, - closure_def_id: DefId, - substs: SubstsRef<'tcx>, - ) -> ty::PolyTraitRef<'tcx> { - let gen_sig = substs.as_generator().poly_sig(closure_def_id, self.tcx()); - - // (1) Feels icky to skip the binder here, but OTOH we know - // that the self-type is an generator type and hence is - // in fact unparameterized (or at least does not reference any - // regions bound in the obligation). Still probably some - // refactoring could make this nicer. - - super::util::generator_trait_ref_and_outputs( - self.tcx(), - obligation.predicate.def_id(), - obligation.predicate.skip_binder().self_ty(), // (1) - gen_sig, - ) - .map_bound(|(trait_ref, ..)| trait_ref) - } - - /// Returns the obligations that are implied by instantiating an - /// impl or trait. The obligations are substituted and fully - /// normalized. This is used when confirming an impl or default - /// impl. - fn impl_or_trait_obligations( - &mut self, - cause: ObligationCause<'tcx>, - recursion_depth: usize, - param_env: ty::ParamEnv<'tcx>, - def_id: DefId, // of impl or trait - substs: SubstsRef<'tcx>, // for impl or trait - ) -> Vec<PredicateObligation<'tcx>> { - debug!("impl_or_trait_obligations(def_id={:?})", def_id); - let tcx = self.tcx(); - - // To allow for one-pass evaluation of the nested obligation, - // each predicate must be preceded by the obligations required - // to normalize it. - // for example, if we have: - // impl<U: Iterator<Item: Copy>, V: Iterator<Item = U>> Foo for V - // the impl will have the following predicates: - // <V as Iterator>::Item = U, - // U: Iterator, U: Sized, - // V: Iterator, V: Sized, - // <U as Iterator>::Item: Copy - // When we substitute, say, `V => IntoIter<u32>, U => $0`, the last - // obligation will normalize to `<$0 as Iterator>::Item = $1` and - // `$1: Copy`, so we must ensure the obligations are emitted in - // that order. - let predicates = tcx.predicates_of(def_id); - assert_eq!(predicates.parent, None); - let mut obligations = Vec::with_capacity(predicates.predicates.len()); - for (predicate, _) in predicates.predicates { - let predicate = normalize_with_depth_to( - self, - param_env, - cause.clone(), - recursion_depth, - &predicate.subst(tcx, substs), - &mut obligations, - ); - obligations.push(Obligation { - cause: cause.clone(), - recursion_depth, - param_env, - predicate, - }); - } - - // We are performing deduplication here to avoid exponential blowups - // (#38528) from happening, but the real cause of the duplication is - // unknown. What we know is that the deduplication avoids exponential - // amount of predicates being propagated when processing deeply nested - // types. - // - // This code is hot enough that it's worth avoiding the allocation - // required for the FxHashSet when possible. Special-casing lengths 0, - // 1 and 2 covers roughly 75-80% of the cases. - if obligations.len() <= 1 { - // No possibility of duplicates. - } else if obligations.len() == 2 { - // Only two elements. Drop the second if they are equal. - if obligations[0] == obligations[1] { - obligations.truncate(1); - } - } else { - // Three or more elements. Use a general deduplication process. - let mut seen = FxHashSet::default(); - obligations.retain(|i| seen.insert(i.clone())); - } - - obligations - } -} - -impl<'tcx> TraitObligation<'tcx> { - #[allow(unused_comparisons)] - pub fn derived_cause( - &self, - variant: fn(DerivedObligationCause<'tcx>) -> ObligationCauseCode<'tcx>, - ) -> ObligationCause<'tcx> { - /*! - * Creates a cause for obligations that are derived from - * `obligation` by a recursive search (e.g., for a builtin - * bound, or eventually a `auto trait Foo`). If `obligation` - * is itself a derived obligation, this is just a clone, but - * otherwise we create a "derived obligation" cause so as to - * keep track of the original root obligation for error - * reporting. - */ - - let obligation = self; - - // NOTE(flaper87): As of now, it keeps track of the whole error - // chain. Ideally, we should have a way to configure this either - // by using -Z verbose or just a CLI argument. - let derived_cause = DerivedObligationCause { - parent_trait_ref: obligation.predicate.to_poly_trait_ref(), - parent_code: Rc::new(obligation.cause.code.clone()), - }; - let derived_code = variant(derived_cause); - ObligationCause::new(obligation.cause.span, obligation.cause.body_id, derived_code) - } + // 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<'o, 'tcx> TraitObligationStack<'o, 'tcx> { - fn list(&'o self) -> TraitObligationStackList<'o, 'tcx> { - TraitObligationStackList::with(self) +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 } - fn cache(&self) -> &'o ProvisionalEvaluationCache<'tcx> { - self.previous.cache + /// Returns `true` if this evaluation result is known to apply, ignoring + /// outlives constraints. + pub fn must_apply_modulo_regions(self) -> bool { + self <= EvaluatedToOkModuloRegions } - fn iter(&'o self) -> TraitObligationStackList<'o, 'tcx> { - self.list() - } + pub fn may_apply(self) -> bool { + match self { + EvaluatedToOk | EvaluatedToOkModuloRegions | EvaluatedToAmbig | EvaluatedToUnknown => { + true + } - /// Indicates that attempting to evaluate this stack entry - /// required accessing something from the stack at depth `reached_depth`. - fn update_reached_depth(&self, reached_depth: usize) { - assert!( - self.depth > reached_depth, - "invoked `update_reached_depth` with something under this stack: \ - self.depth={} reached_depth={}", - self.depth, - reached_depth, - ); - debug!("update_reached_depth(reached_depth={})", reached_depth); - let mut p = self; - while reached_depth < p.depth { - debug!("update_reached_depth: marking {:?} as cycle participant", p.fresh_trait_ref); - p.reached_depth.set(p.reached_depth.get().min(reached_depth)); - p = p.previous.head.unwrap(); + EvaluatedToErr | EvaluatedToRecur => false, } } -} - -/// The "provisional evaluation cache" is used to store intermediate cache results -/// when solving auto traits. Auto traits are unusual in that they can support -/// cycles. So, for example, a "proof tree" like this would be ok: -/// -/// - `Foo<T>: Send` :- -/// - `Bar<T>: Send` :- -/// - `Foo<T>: Send` -- cycle, but ok -/// - `Baz<T>: Send` -/// -/// Here, to prove `Foo<T>: Send`, we have to prove `Bar<T>: Send` and -/// `Baz<T>: Send`. Proving `Bar<T>: Send` in turn required `Foo<T>: Send`. -/// For non-auto traits, this cycle would be an error, but for auto traits (because -/// they are coinductive) it is considered ok. -/// -/// However, there is a complication: at the point where we have -/// "proven" `Bar<T>: Send`, we have in fact only proven it -/// *provisionally*. In particular, we proved that `Bar<T>: Send` -/// *under the assumption* that `Foo<T>: Send`. But what if we later -/// find out this assumption is wrong? Specifically, we could -/// encounter some kind of error proving `Baz<T>: Send`. In that case, -/// `Bar<T>: Send` didn't turn out to be true. -/// -/// In Issue #60010, we found a bug in rustc where it would cache -/// these intermediate results. This was fixed in #60444 by disabling -/// *all* caching for things involved in a cycle -- in our example, -/// that would mean we don't cache that `Bar<T>: Send`. But this led -/// to large slowdowns. -/// -/// Specifically, imagine this scenario, where proving `Baz<T>: Send` -/// first requires proving `Bar<T>: Send` (which is true: -/// -/// - `Foo<T>: Send` :- -/// - `Bar<T>: Send` :- -/// - `Foo<T>: Send` -- cycle, but ok -/// - `Baz<T>: Send` -/// - `Bar<T>: Send` -- would be nice for this to be a cache hit! -/// - `*const T: Send` -- but what if we later encounter an error? -/// -/// The *provisional evaluation cache* resolves this issue. It stores -/// cache results that we've proven but which were involved in a cycle -/// in some way. We track the minimal stack depth (i.e., the -/// farthest from the top of the stack) that we are dependent on. -/// The idea is that the cache results within are all valid -- so long as -/// none of the nodes in between the current node and the node at that minimum -/// depth result in an error (in which case the cached results are just thrown away). -/// -/// During evaluation, we consult this provisional cache and rely on -/// it. Accessing a cached value is considered equivalent to accessing -/// a result at `reached_depth`, so it marks the *current* solution as -/// provisional as well. If an error is encountered, we toss out any -/// provisional results added from the subtree that encountered the -/// error. When we pop the node at `reached_depth` from the stack, we -/// can commit all the things that remain in the provisional cache. -struct ProvisionalEvaluationCache<'tcx> { - /// next "depth first number" to issue -- just a counter - dfn: Cell<usize>, - - /// Stores the "coldest" depth (bottom of stack) reached by any of - /// the evaluation entries. The idea here is that all things in the provisional - /// cache are always dependent on *something* that is colder in the stack: - /// therefore, if we add a new entry that is dependent on something *colder still*, - /// we have to modify the depth for all entries at once. - /// - /// Example: - /// - /// Imagine we have a stack `A B C D E` (with `E` being the top of - /// the stack). We cache something with depth 2, which means that - /// it was dependent on C. Then we pop E but go on and process a - /// new node F: A B C D F. Now F adds something to the cache with - /// depth 1, meaning it is dependent on B. Our original cache - /// entry is also dependent on B, because there is a path from E - /// to C and then from C to F and from F to B. - reached_depth: Cell<usize>, - - /// Map from cache key to the provisionally evaluated thing. - /// The cache entries contain the result but also the DFN in which they - /// were added. The DFN is used to clear out values on failure. - /// - /// Imagine we have a stack like: - /// - /// - `A B C` and we add a cache for the result of C (DFN 2) - /// - Then we have a stack `A B D` where `D` has DFN 3 - /// - We try to solve D by evaluating E: `A B D E` (DFN 4) - /// - `E` generates various cache entries which have cyclic dependices on `B` - /// - `A B D E F` and so forth - /// - the DFN of `F` for example would be 5 - /// - then we determine that `E` is in error -- we will then clear - /// all cache values whose DFN is >= 4 -- in this case, that - /// means the cached value for `F`. - map: RefCell<FxHashMap<ty::PolyTraitRef<'tcx>, ProvisionalEvaluation>>, -} -/// A cache value for the provisional cache: contains the depth-first -/// number (DFN) and result. -#[derive(Copy, Clone, Debug)] -struct ProvisionalEvaluation { - from_dfn: usize, - result: EvaluationResult, -} + pub fn is_stack_dependent(self) -> bool { + match self { + EvaluatedToUnknown | EvaluatedToRecur => true, -impl<'tcx> Default for ProvisionalEvaluationCache<'tcx> { - fn default() -> Self { - Self { - dfn: Cell::new(0), - reached_depth: Cell::new(std::usize::MAX), - map: Default::default(), + EvaluatedToOk | EvaluatedToOkModuloRegions | EvaluatedToAmbig | EvaluatedToErr => false, } } } -impl<'tcx> ProvisionalEvaluationCache<'tcx> { - /// Get the next DFN in sequence (basically a counter). - fn next_dfn(&self) -> usize { - let result = self.dfn.get(); - self.dfn.set(result + 1); - result - } - - /// Check the provisional cache for any result for - /// `fresh_trait_ref`. If there is a hit, then you must consider - /// it an access to the stack slots at depth - /// `self.current_reached_depth()` and above. - fn get_provisional(&self, fresh_trait_ref: ty::PolyTraitRef<'tcx>) -> Option<EvaluationResult> { - debug!( - "get_provisional(fresh_trait_ref={:?}) = {:#?} with reached-depth {}", - fresh_trait_ref, - self.map.borrow().get(&fresh_trait_ref), - self.reached_depth.get(), - ); - Some(self.map.borrow().get(&fresh_trait_ref)?.result) - } - - /// Current value of the `reached_depth` counter -- all the - /// provisional cache entries are dependent on the item at this - /// depth. - fn current_reached_depth(&self) -> usize { - self.reached_depth.get() - } - - /// Insert a provisional result into the cache. The result came - /// from the node with the given DFN. It accessed a minimum depth - /// of `reached_depth` to compute. It evaluated `fresh_trait_ref` - /// and resulted in `result`. - fn insert_provisional( - &self, - from_dfn: usize, - reached_depth: usize, - fresh_trait_ref: ty::PolyTraitRef<'tcx>, - result: EvaluationResult, - ) { - debug!( - "insert_provisional(from_dfn={}, reached_depth={}, fresh_trait_ref={:?}, result={:?})", - from_dfn, reached_depth, fresh_trait_ref, result, - ); - let r_d = self.reached_depth.get(); - self.reached_depth.set(r_d.min(reached_depth)); - - debug!("insert_provisional: reached_depth={:?}", self.reached_depth.get()); - - self.map.borrow_mut().insert(fresh_trait_ref, ProvisionalEvaluation { from_dfn, result }); - } - - /// Invoked when the node with dfn `dfn` does not get a successful - /// result. This will clear out any provisional cache entries - /// that were added since `dfn` was created. This is because the - /// provisional entries are things which must assume that the - /// things on the stack at the time of their creation succeeded -- - /// since the failing node is presently at the top of the stack, - /// these provisional entries must either depend on it or some - /// ancestor of it. - fn on_failure(&self, dfn: usize) { - debug!("on_failure(dfn={:?})", dfn,); - self.map.borrow_mut().retain(|key, eval| { - if !eval.from_dfn >= dfn { - debug!("on_failure: removing {:?}", key); - false - } else { - true - } - }); - } - - /// Invoked when the node at depth `depth` completed without - /// depending on anything higher in the stack (if that completion - /// was a failure, then `on_failure` should have been invoked - /// already). The callback `op` will be invoked for each - /// provisional entry that we can now confirm. - fn on_completion( - &self, - depth: usize, - mut op: impl FnMut(ty::PolyTraitRef<'tcx>, EvaluationResult), - ) { - debug!("on_completion(depth={}, reached_depth={})", depth, self.reached_depth.get(),); - - if self.reached_depth.get() < depth { - debug!("on_completion: did not yet reach depth to complete"); - return; - } - - for (fresh_trait_ref, eval) in self.map.borrow_mut().drain() { - debug!("on_completion: fresh_trait_ref={:?} eval={:?}", fresh_trait_ref, eval,); - - op(fresh_trait_ref, eval.result); - } +/// Indicates that trait evaluation caused overflow. +#[derive(Copy, Clone, Debug, PartialEq, Eq, HashStable)] +pub struct OverflowError; - self.reached_depth.set(std::usize::MAX); +impl<'tcx> From<OverflowError> for SelectionError<'tcx> { + fn from(OverflowError: OverflowError) -> SelectionError<'tcx> { + SelectionError::Overflow } } -#[derive(Copy, Clone)] -struct TraitObligationStackList<'o, 'tcx> { - cache: &'o ProvisionalEvaluationCache<'tcx>, - head: Option<&'o TraitObligationStack<'o, 'tcx>>, +#[derive(Clone, Default)] +pub struct EvaluationCache<'tcx> { + pub hashmap: Lock< + FxHashMap<ty::ParamEnvAnd<'tcx, ty::PolyTraitRef<'tcx>>, WithDepNode<EvaluationResult>>, + >, } -impl<'o, 'tcx> TraitObligationStackList<'o, 'tcx> { - fn empty(cache: &'o ProvisionalEvaluationCache<'tcx>) -> TraitObligationStackList<'o, 'tcx> { - TraitObligationStackList { cache, head: None } - } - - fn with(r: &'o TraitObligationStack<'o, 'tcx>) -> TraitObligationStackList<'o, 'tcx> { - TraitObligationStackList { cache: r.cache(), head: Some(r) } - } - - fn head(&self) -> Option<&'o TraitObligationStack<'o, 'tcx>> { - self.head - } - - fn depth(&self) -> usize { - if let Some(head) = self.head { head.depth } else { 0 } +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> Iterator for TraitObligationStackList<'o, 'tcx> { - type Item = &'o TraitObligationStack<'o, 'tcx>; +#[derive(Clone, Eq, PartialEq)] +pub struct WithDepNode<T> { + dep_node: DepNodeIndex, + cached_value: T, +} - fn next(&mut self) -> Option<&'o TraitObligationStack<'o, 'tcx>> { - match self.head { - Some(o) => { - *self = o.previous; - Some(o) - } - None => None, - } +impl<T: Clone> WithDepNode<T> { + pub fn new(dep_node: DepNodeIndex, cached_value: T) -> Self { + WithDepNode { dep_node, cached_value } } -} -impl<'o, 'tcx> fmt::Debug for TraitObligationStack<'o, 'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "TraitObligationStack({:?})", self.obligation) + pub fn get(&self, tcx: TyCtxt<'_>) -> T { + tcx.dep_graph.read_index(self.dep_node); + self.cached_value.clone() } } diff --git a/src/librustc/traits/types/specialization_graph.rs b/src/librustc/traits/specialization_graph.rs index 36a84369d4a..36a84369d4a 100644 --- a/src/librustc/traits/types/specialization_graph.rs +++ b/src/librustc/traits/specialization_graph.rs diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs deleted file mode 100644 index 7c93a35158b..00000000000 --- a/src/librustc/traits/specialize/mod.rs +++ /dev/null @@ -1,471 +0,0 @@ -//! Logic and data structures related to impl specialization, explained in -//! greater detail below. -//! -//! At the moment, this implementation support only the simple "chain" rule: -//! If any two impls overlap, one must be a strict subset of the other. -//! -//! See the [rustc guide] for a bit more detail on how specialization -//! fits together with the rest of the trait machinery. -//! -//! [rustc guide]: https://rust-lang.github.io/rustc-guide/traits/specialization.html - -pub mod specialization_graph; - -use crate::infer::{InferCtxt, InferOk}; -use crate::traits::select::IntercrateAmbiguityCause; -use crate::traits::{self, coherence, FutureCompatOverlapErrorKind, ObligationCause, TraitEngine}; -use crate::ty::subst::{InternalSubsts, Subst, SubstsRef}; -use crate::ty::{self, TyCtxt, TypeFoldable}; -use rustc::lint::LintDiagnosticBuilder; -use rustc_data_structures::fx::FxHashSet; -use rustc_errors::struct_span_err; -use rustc_hir::def_id::DefId; -use rustc_session::lint::builtin::COHERENCE_LEAK_CHECK; -use rustc_session::lint::builtin::ORDER_DEPENDENT_TRAIT_OBJECTS; -use rustc_span::DUMMY_SP; - -use super::util::impl_trait_ref_and_oblig; -use super::{FulfillmentContext, SelectionContext}; - -/// Information pertinent to an overlapping impl error. -#[derive(Debug)] -pub struct OverlapError { - pub with_impl: DefId, - pub trait_desc: String, - pub self_desc: Option<String>, - pub intercrate_ambiguity_causes: Vec<IntercrateAmbiguityCause>, - pub involves_placeholder: bool, -} - -/// Given a subst for the requested impl, translate it to a subst -/// appropriate for the actual item definition (whether it be in that impl, -/// a parent impl, or the trait). -/// -/// When we have selected one impl, but are actually using item definitions from -/// a parent impl providing a default, we need a way to translate between the -/// type parameters of the two impls. Here the `source_impl` is the one we've -/// selected, and `source_substs` is a substitution of its generics. -/// And `target_node` is the impl/trait we're actually going to get the -/// definition from. The resulting substitution will map from `target_node`'s -/// generics to `source_impl`'s generics as instantiated by `source_subst`. -/// -/// For example, consider the following scenario: -/// -/// ```rust -/// trait Foo { ... } -/// impl<T, U> Foo for (T, U) { ... } // target impl -/// impl<V> Foo for (V, V) { ... } // source impl -/// ``` -/// -/// Suppose we have selected "source impl" with `V` instantiated with `u32`. -/// This function will produce a substitution with `T` and `U` both mapping to `u32`. -/// -/// where-clauses add some trickiness here, because they can be used to "define" -/// an argument indirectly: -/// -/// ```rust -/// impl<'a, I, T: 'a> Iterator for Cloned<I> -/// where I: Iterator<Item = &'a T>, T: Clone -/// ``` -/// -/// In a case like this, the substitution for `T` is determined indirectly, -/// through associated type projection. We deal with such cases by using -/// *fulfillment* to relate the two impls, requiring that all projections are -/// resolved. -pub fn translate_substs<'a, 'tcx>( - infcx: &InferCtxt<'a, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - source_impl: DefId, - source_substs: SubstsRef<'tcx>, - target_node: specialization_graph::Node, -) -> SubstsRef<'tcx> { - debug!( - "translate_substs({:?}, {:?}, {:?}, {:?})", - param_env, source_impl, source_substs, target_node - ); - let source_trait_ref = - infcx.tcx.impl_trait_ref(source_impl).unwrap().subst(infcx.tcx, &source_substs); - - // translate the Self and Param parts of the substitution, since those - // vary across impls - let target_substs = match target_node { - specialization_graph::Node::Impl(target_impl) => { - // no need to translate if we're targeting the impl we started with - if source_impl == target_impl { - return source_substs; - } - - fulfill_implication(infcx, param_env, source_trait_ref, target_impl).unwrap_or_else( - |_| { - bug!( - "When translating substitutions for specialization, the expected \ - specialization failed to hold" - ) - }, - ) - } - specialization_graph::Node::Trait(..) => source_trait_ref.substs, - }; - - // directly inherent the method generics, since those do not vary across impls - source_substs.rebase_onto(infcx.tcx, source_impl, target_substs) -} - -/// Given a selected impl described by `impl_data`, returns the -/// definition and substitutions for the method with the name `name` -/// the kind `kind`, and trait method substitutions `substs`, in -/// that impl, a less specialized impl, or the trait default, -/// whichever applies. -pub fn find_associated_item<'tcx>( - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - item: &ty::AssocItem, - substs: SubstsRef<'tcx>, - impl_data: &super::VtableImplData<'tcx, ()>, -) -> (DefId, SubstsRef<'tcx>) { - debug!("find_associated_item({:?}, {:?}, {:?}, {:?})", param_env, item, substs, impl_data); - assert!(!substs.needs_infer()); - - let trait_def_id = tcx.trait_id_of_impl(impl_data.impl_def_id).unwrap(); - let trait_def = tcx.trait_def(trait_def_id); - - let ancestors = trait_def.ancestors(tcx, impl_data.impl_def_id); - match ancestors.leaf_def(tcx, item.ident, item.kind) { - Some(node_item) => { - let substs = tcx.infer_ctxt().enter(|infcx| { - let param_env = param_env.with_reveal_all(); - let substs = substs.rebase_onto(tcx, trait_def_id, impl_data.substs); - let substs = translate_substs( - &infcx, - param_env, - impl_data.impl_def_id, - substs, - node_item.node, - ); - infcx.tcx.erase_regions(&substs) - }); - (node_item.item.def_id, substs) - } - None => bug!("{:?} not found in {:?}", item, impl_data.impl_def_id), - } -} - -/// Is `impl1` a specialization of `impl2`? -/// -/// Specialization is determined by the sets of types to which the impls apply; -/// `impl1` specializes `impl2` if it applies to a subset of the types `impl2` applies -/// to. -pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId, DefId)) -> bool { - debug!("specializes({:?}, {:?})", impl1_def_id, impl2_def_id); - - // The feature gate should prevent introducing new specializations, but not - // taking advantage of upstream ones. - if !tcx.features().specialization && (impl1_def_id.is_local() || impl2_def_id.is_local()) { - return false; - } - - // We determine whether there's a subset relationship by: - // - // - skolemizing impl1, - // - assuming the where clauses for impl1, - // - instantiating impl2 with fresh inference variables, - // - unifying, - // - attempting to prove the where clauses for impl2 - // - // The last three steps are encapsulated in `fulfill_implication`. - // - // See RFC 1210 for more details and justification. - - // Currently we do not allow e.g., a negative impl to specialize a positive one - if tcx.impl_polarity(impl1_def_id) != tcx.impl_polarity(impl2_def_id) { - return false; - } - - // create a parameter environment corresponding to a (placeholder) instantiation of impl1 - let penv = tcx.param_env(impl1_def_id); - let impl1_trait_ref = tcx.impl_trait_ref(impl1_def_id).unwrap(); - - // Create a infcx, taking the predicates of impl1 as assumptions: - tcx.infer_ctxt().enter(|infcx| { - // Normalize the trait reference. The WF rules ought to ensure - // that this always succeeds. - let impl1_trait_ref = match traits::fully_normalize( - &infcx, - FulfillmentContext::new(), - ObligationCause::dummy(), - penv, - &impl1_trait_ref, - ) { - Ok(impl1_trait_ref) => impl1_trait_ref, - Err(err) => { - bug!("failed to fully normalize {:?}: {:?}", impl1_trait_ref, err); - } - }; - - // Attempt to prove that impl2 applies, given all of the above. - fulfill_implication(&infcx, penv, impl1_trait_ref, impl2_def_id).is_ok() - }) -} - -/// Attempt to fulfill all obligations of `target_impl` after unification with -/// `source_trait_ref`. If successful, returns a substitution for *all* the -/// generics of `target_impl`, including both those needed to unify with -/// `source_trait_ref` and those whose identity is determined via a where -/// clause in the impl. -fn fulfill_implication<'a, 'tcx>( - infcx: &InferCtxt<'a, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - source_trait_ref: ty::TraitRef<'tcx>, - target_impl: DefId, -) -> Result<SubstsRef<'tcx>, ()> { - debug!( - "fulfill_implication({:?}, trait_ref={:?} |- {:?} applies)", - param_env, source_trait_ref, target_impl - ); - - let selcx = &mut SelectionContext::new(&infcx); - let target_substs = infcx.fresh_substs_for_item(DUMMY_SP, target_impl); - let (target_trait_ref, mut obligations) = - impl_trait_ref_and_oblig(selcx, param_env, target_impl, target_substs); - debug!( - "fulfill_implication: target_trait_ref={:?}, obligations={:?}", - target_trait_ref, obligations - ); - - // do the impls unify? If not, no specialization. - match infcx.at(&ObligationCause::dummy(), param_env).eq(source_trait_ref, target_trait_ref) { - Ok(InferOk { obligations: o, .. }) => { - obligations.extend(o); - } - Err(_) => { - debug!( - "fulfill_implication: {:?} does not unify with {:?}", - source_trait_ref, target_trait_ref - ); - return Err(()); - } - } - - // attempt to prove all of the predicates for impl2 given those for impl1 - // (which are packed up in penv) - - infcx.save_and_restore_in_snapshot_flag(|infcx| { - // If we came from `translate_substs`, we already know that the - // predicates for our impl hold (after all, we know that a more - // specialized impl holds, so our impl must hold too), and - // we only want to process the projections to determine the - // the types in our substs using RFC 447, so we can safely - // ignore region obligations, which allows us to avoid threading - // a node-id to assign them with. - // - // If we came from specialization graph construction, then - // we already make a mockery out of the region system, so - // why not ignore them a bit earlier? - let mut fulfill_cx = FulfillmentContext::new_ignoring_regions(); - for oblig in obligations.into_iter() { - fulfill_cx.register_predicate_obligation(&infcx, oblig); - } - match fulfill_cx.select_all_or_error(infcx) { - Err(errors) => { - // no dice! - debug!( - "fulfill_implication: for impls on {:?} and {:?}, \ - could not fulfill: {:?} given {:?}", - source_trait_ref, target_trait_ref, errors, param_env.caller_bounds - ); - Err(()) - } - - Ok(()) => { - debug!( - "fulfill_implication: an impl for {:?} specializes {:?}", - source_trait_ref, target_trait_ref - ); - - // Now resolve the *substitution* we built for the target earlier, replacing - // the inference variables inside with whatever we got from fulfillment. - Ok(infcx.resolve_vars_if_possible(&target_substs)) - } - } - }) -} - -// Query provider for `specialization_graph_of`. -pub(super) fn specialization_graph_provider( - tcx: TyCtxt<'_>, - trait_id: DefId, -) -> &specialization_graph::Graph { - let mut sg = specialization_graph::Graph::new(); - - let mut trait_impls = tcx.all_impls(trait_id); - - // The coherence checking implementation seems to rely on impls being - // iterated over (roughly) in definition order, so we are sorting by - // negated `CrateNum` (so remote definitions are visited first) and then - // by a flattened version of the `DefIndex`. - trait_impls - .sort_unstable_by_key(|def_id| (-(def_id.krate.as_u32() as i64), def_id.index.index())); - - for impl_def_id in trait_impls { - if impl_def_id.is_local() { - // This is where impl overlap checking happens: - let insert_result = sg.insert(tcx, impl_def_id); - // Report error if there was one. - let (overlap, used_to_be_allowed) = match insert_result { - Err(overlap) => (Some(overlap), None), - Ok(Some(overlap)) => (Some(overlap.error), Some(overlap.kind)), - Ok(None) => (None, None), - }; - - if let Some(overlap) = overlap { - let impl_span = - tcx.sess.source_map().def_span(tcx.span_of_impl(impl_def_id).unwrap()); - - // Work to be done after we've built the DiagnosticBuilder. We have to define it - // now because the struct_lint methods don't return back the DiagnosticBuilder - // that's passed in. - let decorate = |err: LintDiagnosticBuilder<'_>| { - let msg = format!( - "conflicting implementations of trait `{}`{}:{}", - overlap.trait_desc, - overlap - .self_desc - .clone() - .map_or(String::new(), |ty| { format!(" for type `{}`", ty) }), - match used_to_be_allowed { - Some(FutureCompatOverlapErrorKind::Issue33140) => " (E0119)", - _ => "", - } - ); - let mut err = err.build(&msg); - match tcx.span_of_impl(overlap.with_impl) { - Ok(span) => { - err.span_label( - tcx.sess.source_map().def_span(span), - "first implementation here".to_string(), - ); - - err.span_label( - impl_span, - format!( - "conflicting implementation{}", - overlap - .self_desc - .map_or(String::new(), |ty| format!(" for `{}`", ty)) - ), - ); - } - Err(cname) => { - let msg = match to_pretty_impl_header(tcx, overlap.with_impl) { - Some(s) => format!( - "conflicting implementation in crate `{}`:\n- {}", - cname, s - ), - None => format!("conflicting implementation in crate `{}`", cname), - }; - err.note(&msg); - } - } - - for cause in &overlap.intercrate_ambiguity_causes { - cause.add_intercrate_ambiguity_hint(&mut err); - } - - if overlap.involves_placeholder { - coherence::add_placeholder_note(&mut err); - } - err.emit() - }; - - match used_to_be_allowed { - None => { - let err = struct_span_err!(tcx.sess, impl_span, E0119, ""); - decorate(LintDiagnosticBuilder::new(err)); - } - Some(kind) => { - let lint = match kind { - FutureCompatOverlapErrorKind::Issue33140 => { - ORDER_DEPENDENT_TRAIT_OBJECTS - } - FutureCompatOverlapErrorKind::LeakCheck => COHERENCE_LEAK_CHECK, - }; - tcx.struct_span_lint_hir( - lint, - tcx.hir().as_local_hir_id(impl_def_id).unwrap(), - impl_span, - decorate, - ) - } - }; - } - } else { - let parent = tcx.impl_parent(impl_def_id).unwrap_or(trait_id); - sg.record_impl_from_cstore(tcx, parent, impl_def_id) - } - } - - tcx.arena.alloc(sg) -} - -/// Recovers the "impl X for Y" signature from `impl_def_id` and returns it as a -/// string. -fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Option<String> { - use std::fmt::Write; - - let trait_ref = if let Some(tr) = tcx.impl_trait_ref(impl_def_id) { - tr - } else { - return None; - }; - - let mut w = "impl".to_owned(); - - let substs = InternalSubsts::identity_for_item(tcx, impl_def_id); - - // FIXME: Currently only handles ?Sized. - // Needs to support ?Move and ?DynSized when they are implemented. - let mut types_without_default_bounds = FxHashSet::default(); - let sized_trait = tcx.lang_items().sized_trait(); - - if !substs.is_noop() { - types_without_default_bounds.extend(substs.types()); - w.push('<'); - w.push_str( - &substs - .iter() - .map(|k| k.to_string()) - .filter(|k| k != "'_") - .collect::<Vec<_>>() - .join(", "), - ); - w.push('>'); - } - - write!(w, " {} for {}", trait_ref.print_only_trait_path(), tcx.type_of(impl_def_id)).unwrap(); - - // The predicates will contain default bounds like `T: Sized`. We need to - // remove these bounds, and add `T: ?Sized` to any untouched type parameters. - let predicates = tcx.predicates_of(impl_def_id).predicates; - let mut pretty_predicates = - Vec::with_capacity(predicates.len() + types_without_default_bounds.len()); - - for (p, _) in predicates { - if let Some(poly_trait_ref) = p.to_opt_poly_trait_ref() { - if Some(poly_trait_ref.def_id()) == sized_trait { - types_without_default_bounds.remove(poly_trait_ref.self_ty()); - continue; - } - } - pretty_predicates.push(p.to_string()); - } - - pretty_predicates - .extend(types_without_default_bounds.iter().map(|ty| format!("{}: ?Sized", ty))); - - if !pretty_predicates.is_empty() { - write!(w, "\n where {}", pretty_predicates.join(", ")).unwrap(); - } - - w.push(';'); - Some(w) -} diff --git a/src/librustc/traits/specialize/specialization_graph.rs b/src/librustc/traits/specialize/specialization_graph.rs deleted file mode 100644 index e09bcdcbc62..00000000000 --- a/src/librustc/traits/specialize/specialization_graph.rs +++ /dev/null @@ -1,350 +0,0 @@ -use super::OverlapError; - -use crate::traits; -use rustc::ty::fast_reject::{self, SimplifiedType}; -use rustc::ty::{self, TyCtxt, TypeFoldable}; -use rustc_hir::def_id::DefId; - -pub use rustc::traits::types::specialization_graph::*; - -#[derive(Copy, Clone, Debug)] -pub enum FutureCompatOverlapErrorKind { - Issue33140, - LeakCheck, -} - -#[derive(Debug)] -pub struct FutureCompatOverlapError { - pub error: OverlapError, - pub kind: FutureCompatOverlapErrorKind, -} - -/// The result of attempting to insert an impl into a group of children. -enum Inserted { - /// The impl was inserted as a new child in this group of children. - BecameNewSibling(Option<FutureCompatOverlapError>), - - /// The impl should replace existing impls [X1, ..], because the impl specializes X1, X2, etc. - ReplaceChildren(Vec<DefId>), - - /// The impl is a specialization of an existing child. - ShouldRecurseOn(DefId), -} - -impl<'tcx> Children { - /// Insert an impl into this set of children without comparing to any existing impls. - fn insert_blindly(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId) { - let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap(); - if let Some(st) = fast_reject::simplify_type(tcx, trait_ref.self_ty(), false) { - debug!("insert_blindly: impl_def_id={:?} st={:?}", impl_def_id, st); - self.nonblanket_impls.entry(st).or_default().push(impl_def_id) - } else { - debug!("insert_blindly: impl_def_id={:?} st=None", impl_def_id); - self.blanket_impls.push(impl_def_id) - } - } - - /// Removes an impl from this set of children. Used when replacing - /// an impl with a parent. The impl must be present in the list of - /// children already. - fn remove_existing(&mut self, tcx: TyCtxt<'tcx>, impl_def_id: DefId) { - let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap(); - let vec: &mut Vec<DefId>; - if let Some(st) = fast_reject::simplify_type(tcx, trait_ref.self_ty(), false) { - debug!("remove_existing: impl_def_id={:?} st={:?}", impl_def_id, st); - vec = self.nonblanket_impls.get_mut(&st).unwrap(); - } else { - debug!("remove_existing: impl_def_id={:?} st=None", impl_def_id); - vec = &mut self.blanket_impls; - } - - let index = vec.iter().position(|d| *d == impl_def_id).unwrap(); - vec.remove(index); - } - - /// Attempt to insert an impl into this set of children, while comparing for - /// specialization relationships. - fn insert( - &mut self, - tcx: TyCtxt<'tcx>, - impl_def_id: DefId, - simplified_self: Option<SimplifiedType>, - ) -> Result<Inserted, OverlapError> { - let mut last_lint = None; - let mut replace_children = Vec::new(); - - debug!("insert(impl_def_id={:?}, simplified_self={:?})", impl_def_id, simplified_self,); - - let possible_siblings = match simplified_self { - Some(st) => PotentialSiblings::Filtered(self.filtered(st)), - None => PotentialSiblings::Unfiltered(self.iter()), - }; - - for possible_sibling in possible_siblings { - debug!( - "insert: impl_def_id={:?}, simplified_self={:?}, possible_sibling={:?}", - impl_def_id, simplified_self, possible_sibling, - ); - - let create_overlap_error = |overlap: traits::coherence::OverlapResult<'_>| { - let trait_ref = overlap.impl_header.trait_ref.unwrap(); - let self_ty = trait_ref.self_ty(); - - OverlapError { - with_impl: possible_sibling, - trait_desc: trait_ref.print_only_trait_path().to_string(), - // Only report the `Self` type if it has at least - // some outer concrete shell; otherwise, it's - // not adding much information. - self_desc: if self_ty.has_concrete_skeleton() { - Some(self_ty.to_string()) - } else { - None - }, - intercrate_ambiguity_causes: overlap.intercrate_ambiguity_causes, - involves_placeholder: overlap.involves_placeholder, - } - }; - - let report_overlap_error = |overlap: traits::coherence::OverlapResult<'_>, - last_lint: &mut _| { - // Found overlap, but no specialization; error out or report future-compat warning. - - // Do we *still* get overlap if we disable the future-incompatible modes? - let should_err = traits::overlapping_impls( - tcx, - possible_sibling, - impl_def_id, - traits::SkipLeakCheck::default(), - |_| true, - || false, - ); - - let error = create_overlap_error(overlap); - - if should_err { - Err(error) - } else { - *last_lint = Some(FutureCompatOverlapError { - error, - kind: FutureCompatOverlapErrorKind::LeakCheck, - }); - - Ok((false, false)) - } - }; - - let last_lint_mut = &mut last_lint; - let (le, ge) = traits::overlapping_impls( - tcx, - possible_sibling, - impl_def_id, - traits::SkipLeakCheck::Yes, - |overlap| { - if let Some(overlap_kind) = - tcx.impls_are_allowed_to_overlap(impl_def_id, possible_sibling) - { - match overlap_kind { - ty::ImplOverlapKind::Permitted { marker: _ } => {} - ty::ImplOverlapKind::Issue33140 => { - *last_lint_mut = Some(FutureCompatOverlapError { - error: create_overlap_error(overlap), - kind: FutureCompatOverlapErrorKind::Issue33140, - }); - } - } - - return Ok((false, false)); - } - - let le = tcx.specializes((impl_def_id, possible_sibling)); - let ge = tcx.specializes((possible_sibling, impl_def_id)); - - if le == ge { - report_overlap_error(overlap, last_lint_mut) - } else { - Ok((le, ge)) - } - }, - || Ok((false, false)), - )?; - - if le && !ge { - debug!( - "descending as child of TraitRef {:?}", - tcx.impl_trait_ref(possible_sibling).unwrap() - ); - - // The impl specializes `possible_sibling`. - return Ok(Inserted::ShouldRecurseOn(possible_sibling)); - } else if ge && !le { - debug!( - "placing as parent of TraitRef {:?}", - tcx.impl_trait_ref(possible_sibling).unwrap() - ); - - replace_children.push(possible_sibling); - } else { - // Either there's no overlap, or the overlap was already reported by - // `overlap_error`. - } - } - - if !replace_children.is_empty() { - return Ok(Inserted::ReplaceChildren(replace_children)); - } - - // No overlap with any potential siblings, so add as a new sibling. - debug!("placing as new sibling"); - self.insert_blindly(tcx, impl_def_id); - Ok(Inserted::BecameNewSibling(last_lint)) - } - - fn iter(&mut self) -> impl Iterator<Item = DefId> + '_ { - let nonblanket = self.nonblanket_impls.iter_mut().flat_map(|(_, v)| v.iter()); - self.blanket_impls.iter().chain(nonblanket).cloned() - } - - fn filtered(&mut self, st: SimplifiedType) -> impl Iterator<Item = DefId> + '_ { - let nonblanket = self.nonblanket_impls.entry(st).or_default().iter(); - self.blanket_impls.iter().chain(nonblanket).cloned() - } -} - -// A custom iterator used by Children::insert -enum PotentialSiblings<I, J> -where - I: Iterator<Item = DefId>, - J: Iterator<Item = DefId>, -{ - Unfiltered(I), - Filtered(J), -} - -impl<I, J> Iterator for PotentialSiblings<I, J> -where - I: Iterator<Item = DefId>, - J: Iterator<Item = DefId>, -{ - type Item = DefId; - - fn next(&mut self) -> Option<Self::Item> { - match *self { - PotentialSiblings::Unfiltered(ref mut iter) => iter.next(), - PotentialSiblings::Filtered(ref mut iter) => iter.next(), - } - } -} - -impl<'tcx> Graph { - /// 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`. - pub fn insert( - &mut self, - tcx: TyCtxt<'tcx>, - impl_def_id: DefId, - ) -> Result<Option<FutureCompatOverlapError>, OverlapError> { - assert!(impl_def_id.is_local()); - - let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap(); - let trait_def_id = trait_ref.def_id; - - debug!( - "insert({:?}): inserting TraitRef {:?} into specialization graph", - impl_def_id, trait_ref - ); - - // If the reference itself contains an earlier error (e.g., due to a - // resolution failure), then we just insert the impl at the top level of - // the graph and claim that there's no overlap (in order to suppress - // bogus errors). - if trait_ref.references_error() { - debug!( - "insert: inserting dummy node for erroneous TraitRef {:?}, \ - impl_def_id={:?}, trait_def_id={:?}", - trait_ref, impl_def_id, trait_def_id - ); - - self.parent.insert(impl_def_id, trait_def_id); - self.children.entry(trait_def_id).or_default().insert_blindly(tcx, impl_def_id); - return Ok(None); - } - - let mut parent = trait_def_id; - let mut last_lint = None; - let simplified = fast_reject::simplify_type(tcx, trait_ref.self_ty(), false); - - // Descend the specialization tree, where `parent` is the current parent node. - loop { - use self::Inserted::*; - - let insert_result = - self.children.entry(parent).or_default().insert(tcx, impl_def_id, simplified)?; - - match insert_result { - BecameNewSibling(opt_lint) => { - last_lint = opt_lint; - break; - } - ReplaceChildren(grand_children_to_be) => { - // We currently have - // - // P - // | - // G - // - // and we are inserting the impl N. We want to make it: - // - // P - // | - // N - // | - // G - - // Adjust P's list of children: remove G and then add N. - { - let siblings = self.children.get_mut(&parent).unwrap(); - for &grand_child_to_be in &grand_children_to_be { - siblings.remove_existing(tcx, grand_child_to_be); - } - siblings.insert_blindly(tcx, impl_def_id); - } - - // Set G's parent to N and N's parent to P. - for &grand_child_to_be in &grand_children_to_be { - self.parent.insert(grand_child_to_be, impl_def_id); - } - self.parent.insert(impl_def_id, parent); - - // Add G as N's child. - for &grand_child_to_be in &grand_children_to_be { - self.children - .entry(impl_def_id) - .or_default() - .insert_blindly(tcx, grand_child_to_be); - } - break; - } - ShouldRecurseOn(new_parent) => { - parent = new_parent; - } - } - } - - self.parent.insert(impl_def_id, parent); - Ok(last_lint) - } - - /// Insert cached metadata mapping from a child impl back to its parent. - pub fn record_impl_from_cstore(&mut self, tcx: TyCtxt<'tcx>, parent: DefId, child: DefId) { - if self.parent.insert(child, parent).is_some() { - bug!( - "When recording an impl from the crate store, information about its parent \ - was already present." - ); - } - - self.children.entry(parent).or_default().insert_blindly(tcx, child); - } -} diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index 80731c7b189..48ed29f2bb3 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -1,71 +1,712 @@ 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`. -impl<'tcx, T: fmt::Debug> fmt::Debug for Normalized<'tcx, T> { +impl<'tcx, N: fmt::Debug> fmt::Debug for traits::Vtable<'tcx, N> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "Normalized({:?}, {:?})", self.value, self.obligations) + 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, O: fmt::Debug> fmt::Debug for traits::Obligation<'tcx, O> { +impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableImplData<'tcx, N> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if ty::tls::with(|tcx| tcx.sess.verbose()) { - write!( - f, - "Obligation(predicate={:?}, cause={:?}, param_env={:?}, depth={})", - self.predicate, self.cause, self.param_env, self.recursion_depth - ) - } else { - write!(f, "Obligation(predicate={:?}, depth={})", self.predicate, self.recursion_depth) - } + 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> fmt::Debug for traits::FulfillmentError<'tcx> { +impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableObjectData<'tcx, N> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "FulfillmentError({:?},{:?})", self.obligation, self.code) + write!( + f, + "VtableObjectData(upcast={:?}, vtable_base={}, nested={:?})", + self.upcast_trait_ref, self.vtable_base, self.nested + ) } } -impl<'tcx> fmt::Debug for traits::FulfillmentErrorCode<'tcx> { +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::CodeSelectionError(ref e) => write!(f, "{:?}", e), - super::CodeProjectionError(ref e) => write!(f, "{:?}", e), - super::CodeSubtypeError(ref a, ref b) => { - write!(f, "CodeSubtypeError({:?}, {:?})", a, b) + 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::CodeAmbiguity => write!(f, "Ambiguity"), + super::TraitNotObjectSafe(def_id) => Some(super::TraitNotObjectSafe(def_id)), + super::ConstEvalFailure(err) => Some(super::ConstEvalFailure(err)), + super::Overflow => Some(super::Overflow), } } } -impl<'tcx> fmt::Debug for traits::MismatchedProjectionTypes<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "MismatchedProjectionTypes({:?})", self.err) +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. -impl<'tcx, O: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Obligation<'tcx, O> { +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 { - traits::Obligation { - cause: self.cause.clone(), - recursion_depth: self.recursion_depth, - predicate: self.predicate.fold_with(folder), - param_env: self.param_env.fold_with(folder), - } + 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.predicate.visit_with(visitor) + 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, } diff --git a/src/librustc/traits/structural_match.rs b/src/librustc/traits/structural_match.rs deleted file mode 100644 index b2c3c23b4e3..00000000000 --- a/src/librustc/traits/structural_match.rs +++ /dev/null @@ -1,217 +0,0 @@ -use crate::ty::fold::{TypeFoldable, TypeVisitor}; -use crate::ty::{self, AdtDef, Ty, TyCtxt}; - -use rustc::infer::InferCtxt; -use rustc::traits::ObligationCause; -use rustc::traits::{self, ConstPatternStructural, TraitEngine}; -use rustc_data_structures::fx::FxHashSet; -use rustc_hir as hir; -use rustc_span::Span; - -#[derive(Debug)] -pub enum NonStructuralMatchTy<'tcx> { - Adt(&'tcx AdtDef), - Param, -} - -/// This method traverses the structure of `ty`, trying to find an -/// instance of an ADT (i.e. struct or enum) that was declared without -/// the `#[structural_match]` attribute, or a generic type parameter -/// (which cannot be determined to be `structural_match`). -/// -/// The "structure of a type" includes all components that would be -/// considered when doing a pattern match on a constant of that -/// type. -/// -/// * This means this method descends into fields of structs/enums, -/// and also descends into the inner type `T` of `&T` and `&mut T` -/// -/// * The traversal doesn't dereference unsafe pointers (`*const T`, -/// `*mut T`), and it does not visit the type arguments of an -/// instantiated generic like `PhantomData<T>`. -/// -/// The reason we do this search is Rust currently require all ADTs -/// reachable from a constant's type to be annotated with -/// `#[structural_match]`, an attribute which essentially says that -/// the implementation of `PartialEq::eq` behaves *equivalently* to a -/// comparison against the unfolded structure. -/// -/// For more background on why Rust has this requirement, and issues -/// that arose when the requirement was not enforced completely, see -/// Rust RFC 1445, rust-lang/rust#61188, and rust-lang/rust#62307. -pub fn search_for_structural_match_violation<'tcx>( - id: hir::HirId, - span: Span, - tcx: TyCtxt<'tcx>, - ty: Ty<'tcx>, -) -> Option<NonStructuralMatchTy<'tcx>> { - // FIXME: we should instead pass in an `infcx` from the outside. - tcx.infer_ctxt().enter(|infcx| { - let mut search = Search { id, span, infcx, found: None, seen: FxHashSet::default() }; - ty.visit_with(&mut search); - search.found - }) -} - -/// This method returns true if and only if `adt_ty` itself has been marked as -/// eligible for structural-match: namely, if it implements both -/// `StructuralPartialEq` and `StructuralEq` (which are respectively injected by -/// `#[derive(PartialEq)]` and `#[derive(Eq)]`). -/// -/// Note that this does *not* recursively check if the substructure of `adt_ty` -/// implements the traits. -pub fn type_marked_structural( - id: hir::HirId, - span: Span, - infcx: &InferCtxt<'_, 'tcx>, - adt_ty: Ty<'tcx>, -) -> bool { - let mut fulfillment_cx = traits::FulfillmentContext::new(); - let cause = ObligationCause::new(span, id, ConstPatternStructural); - // require `#[derive(PartialEq)]` - let structural_peq_def_id = infcx.tcx.lang_items().structural_peq_trait().unwrap(); - fulfillment_cx.register_bound( - infcx, - ty::ParamEnv::empty(), - adt_ty, - structural_peq_def_id, - cause, - ); - // for now, require `#[derive(Eq)]`. (Doing so is a hack to work around - // the type `for<'a> fn(&'a ())` failing to implement `Eq` itself.) - let cause = ObligationCause::new(span, id, ConstPatternStructural); - let structural_teq_def_id = infcx.tcx.lang_items().structural_teq_trait().unwrap(); - fulfillment_cx.register_bound( - infcx, - ty::ParamEnv::empty(), - adt_ty, - structural_teq_def_id, - cause, - ); - - // We deliberately skip *reporting* fulfillment errors (via - // `report_fulfillment_errors`), for two reasons: - // - // 1. The error messages would mention `std::marker::StructuralPartialEq` - // (a trait which is solely meant as an implementation detail - // for now), and - // - // 2. We are sometimes doing future-incompatibility lints for - // now, so we do not want unconditional errors here. - fulfillment_cx.select_all_or_error(infcx).is_ok() -} - -/// This implements the traversal over the structure of a given type to try to -/// find instances of ADTs (specifically structs or enums) that do not implement -/// the structural-match traits (`StructuralPartialEq` and `StructuralEq`). -struct Search<'a, 'tcx> { - id: hir::HirId, - span: Span, - - infcx: InferCtxt<'a, 'tcx>, - - /// Records first ADT that does not implement a structural-match trait. - found: Option<NonStructuralMatchTy<'tcx>>, - - /// Tracks ADTs previously encountered during search, so that - /// we will not recur on them again. - seen: FxHashSet<hir::def_id::DefId>, -} - -impl Search<'a, 'tcx> { - fn tcx(&self) -> TyCtxt<'tcx> { - self.infcx.tcx - } - - fn type_marked_structural(&self, adt_ty: Ty<'tcx>) -> bool { - type_marked_structural(self.id, self.span, &self.infcx, adt_ty) - } -} - -impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> { - fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { - debug!("Search visiting ty: {:?}", ty); - - let (adt_def, substs) = match ty.kind { - ty::Adt(adt_def, substs) => (adt_def, substs), - ty::Param(_) => { - self.found = Some(NonStructuralMatchTy::Param); - return true; // Stop visiting. - } - ty::RawPtr(..) => { - // structural-match ignores substructure of - // `*const _`/`*mut _`, so skip `super_visit_with`. - // - // For example, if you have: - // ``` - // struct NonStructural; - // #[derive(PartialEq, Eq)] - // struct T(*const NonStructural); - // const C: T = T(std::ptr::null()); - // ``` - // - // Even though `NonStructural` does not implement `PartialEq`, - // structural equality on `T` does not recur into the raw - // pointer. Therefore, one can still use `C` in a pattern. - - // (But still tell caller to continue search.) - return false; - } - ty::FnDef(..) | ty::FnPtr(..) => { - // types of formals and return in `fn(_) -> _` are also irrelevant; - // so we do not recur into them via `super_visit_with` - // - // (But still tell caller to continue search.) - return false; - } - ty::Array(_, n) - if { n.try_eval_usize(self.tcx(), ty::ParamEnv::reveal_all()) == Some(0) } => - { - // rust-lang/rust#62336: ignore type of contents - // for empty array. - return false; - } - _ => { - ty.super_visit_with(self); - return false; - } - }; - - if !self.seen.insert(adt_def.did) { - debug!("Search already seen adt_def: {:?}", adt_def); - // let caller continue its search - return false; - } - - if !self.type_marked_structural(ty) { - debug!("Search found ty: {:?}", ty); - self.found = Some(NonStructuralMatchTy::Adt(&adt_def)); - return true; // Halt visiting! - } - - // structural-match does not care about the - // instantiation of the generics in an ADT (it - // instead looks directly at its fields outside - // this match), so we skip super_visit_with. - // - // (Must not recur on substs for `PhantomData<T>` cf - // rust-lang/rust#55028 and rust-lang/rust#55837; but also - // want to skip substs when only uses of generic are - // behind unsafe pointers `*const T`/`*mut T`.) - - // even though we skip super_visit_with, we must recur on - // fields of ADT. - let tcx = self.tcx(); - for field_ty in adt_def.all_fields().map(|field| field.ty(tcx, substs)) { - if field_ty.visit_with(self) { - // found an ADT without structural-match; halt visiting! - assert!(self.found.is_some()); - return true; - } - } - - // Even though we do not want to recur on substs, we do - // want our caller to continue its own search. - false - } -} diff --git a/src/librustc/traits/types/mod.rs b/src/librustc/traits/types/mod.rs deleted file mode 100644 index 571fb505779..00000000000 --- a/src/librustc/traits/types/mod.rs +++ /dev/null @@ -1,736 +0,0 @@ -//! 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>; -} diff --git a/src/librustc/traits/types/select.rs b/src/librustc/traits/types/select.rs deleted file mode 100644 index ac3d0049c0c..00000000000 --- a/src/librustc/traits/types/select.rs +++ /dev/null @@ -1,290 +0,0 @@ -//! 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() - } -} diff --git a/src/librustc/traits/types/structural_impls.rs b/src/librustc/traits/types/structural_impls.rs deleted file mode 100644 index 48ed29f2bb3..00000000000 --- a/src/librustc/traits/types/structural_impls.rs +++ /dev/null @@ -1,712 +0,0 @@ -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, -} diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs deleted file mode 100644 index d4c3518260c..00000000000 --- a/src/librustc/traits/util.rs +++ /dev/null @@ -1,674 +0,0 @@ -use rustc_errors::DiagnosticBuilder; -use rustc_span::Span; -use smallvec::SmallVec; - -use crate::ty::outlives::Component; -use crate::ty::subst::{GenericArg, Subst, SubstsRef}; -use crate::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, WithConstness}; -use rustc_data_structures::fx::FxHashSet; -use rustc_hir as hir; -use rustc_hir::def_id::DefId; - -use super::{Normalized, Obligation, ObligationCause, PredicateObligation, SelectionContext}; - -fn anonymize_predicate<'tcx>(tcx: TyCtxt<'tcx>, pred: &ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { - match *pred { - ty::Predicate::Trait(ref data, constness) => { - ty::Predicate::Trait(tcx.anonymize_late_bound_regions(data), constness) - } - - ty::Predicate::RegionOutlives(ref data) => { - ty::Predicate::RegionOutlives(tcx.anonymize_late_bound_regions(data)) - } - - ty::Predicate::TypeOutlives(ref data) => { - ty::Predicate::TypeOutlives(tcx.anonymize_late_bound_regions(data)) - } - - ty::Predicate::Projection(ref data) => { - ty::Predicate::Projection(tcx.anonymize_late_bound_regions(data)) - } - - ty::Predicate::WellFormed(data) => ty::Predicate::WellFormed(data), - - ty::Predicate::ObjectSafe(data) => ty::Predicate::ObjectSafe(data), - - ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => { - ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) - } - - ty::Predicate::Subtype(ref data) => { - ty::Predicate::Subtype(tcx.anonymize_late_bound_regions(data)) - } - - ty::Predicate::ConstEvaluatable(def_id, substs) => { - ty::Predicate::ConstEvaluatable(def_id, substs) - } - } -} - -struct PredicateSet<'tcx> { - tcx: TyCtxt<'tcx>, - set: FxHashSet<ty::Predicate<'tcx>>, -} - -impl PredicateSet<'tcx> { - fn new(tcx: TyCtxt<'tcx>) -> Self { - Self { tcx: tcx, set: Default::default() } - } - - fn insert(&mut self, pred: &ty::Predicate<'tcx>) -> bool { - // We have to be careful here because we want - // - // for<'a> Foo<&'a int> - // - // and - // - // for<'b> Foo<&'b int> - // - // to be considered equivalent. So normalize all late-bound - // regions before we throw things into the underlying set. - self.set.insert(anonymize_predicate(self.tcx, pred)) - } -} - -impl<T: AsRef<ty::Predicate<'tcx>>> Extend<T> for PredicateSet<'tcx> { - fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) { - for pred in iter { - self.insert(pred.as_ref()); - } - } -} - -/////////////////////////////////////////////////////////////////////////// -// `Elaboration` iterator -/////////////////////////////////////////////////////////////////////////// - -/// "Elaboration" is the process of identifying all the predicates that -/// are implied by a source predicate. Currently, this basically means -/// walking the "supertraits" and other similar assumptions. For example, -/// if we know that `T: Ord`, the elaborator would deduce that `T: PartialOrd` -/// holds as well. Similarly, if we have `trait Foo: 'static`, and we know that -/// `T: Foo`, then we know that `T: 'static`. -pub struct Elaborator<'tcx> { - stack: Vec<ty::Predicate<'tcx>>, - visited: PredicateSet<'tcx>, -} - -pub fn elaborate_trait_ref<'tcx>( - tcx: TyCtxt<'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>, -) -> Elaborator<'tcx> { - elaborate_predicates(tcx, vec![trait_ref.without_const().to_predicate()]) -} - -pub fn elaborate_trait_refs<'tcx>( - tcx: TyCtxt<'tcx>, - trait_refs: impl Iterator<Item = ty::PolyTraitRef<'tcx>>, -) -> Elaborator<'tcx> { - let predicates = trait_refs.map(|trait_ref| trait_ref.without_const().to_predicate()).collect(); - elaborate_predicates(tcx, predicates) -} - -pub fn elaborate_predicates<'tcx>( - tcx: TyCtxt<'tcx>, - mut predicates: Vec<ty::Predicate<'tcx>>, -) -> Elaborator<'tcx> { - let mut visited = PredicateSet::new(tcx); - predicates.retain(|pred| visited.insert(pred)); - Elaborator { stack: predicates, visited } -} - -impl Elaborator<'tcx> { - pub fn filter_to_traits(self) -> FilterToTraits<Self> { - FilterToTraits::new(self) - } - - fn elaborate(&mut self, predicate: &ty::Predicate<'tcx>) { - let tcx = self.visited.tcx; - match *predicate { - ty::Predicate::Trait(ref data, _) => { - // Get predicates declared on the trait. - let predicates = tcx.super_predicates_of(data.def_id()); - - let predicates = predicates - .predicates - .iter() - .map(|(pred, _)| pred.subst_supertrait(tcx, &data.to_poly_trait_ref())); - debug!("super_predicates: data={:?} predicates={:?}", data, predicates.clone()); - - // Only keep those bounds that we haven't already seen. - // This is necessary to prevent infinite recursion in some - // cases. One common case is when people define - // `trait Sized: Sized { }` rather than `trait Sized { }`. - let visited = &mut self.visited; - let predicates = predicates.filter(|pred| visited.insert(pred)); - - self.stack.extend(predicates); - } - ty::Predicate::WellFormed(..) => { - // Currently, we do not elaborate WF predicates, - // although we easily could. - } - ty::Predicate::ObjectSafe(..) => { - // Currently, we do not elaborate object-safe - // predicates. - } - ty::Predicate::Subtype(..) => { - // Currently, we do not "elaborate" predicates like `X <: Y`, - // though conceivably we might. - } - ty::Predicate::Projection(..) => { - // Nothing to elaborate in a projection predicate. - } - ty::Predicate::ClosureKind(..) => { - // Nothing to elaborate when waiting for a closure's kind to be inferred. - } - ty::Predicate::ConstEvaluatable(..) => { - // Currently, we do not elaborate const-evaluatable - // predicates. - } - ty::Predicate::RegionOutlives(..) => { - // Nothing to elaborate from `'a: 'b`. - } - ty::Predicate::TypeOutlives(ref data) => { - // We know that `T: 'a` for some type `T`. We can - // often elaborate this. For example, if we know that - // `[U]: 'a`, that implies that `U: 'a`. Similarly, if - // we know `&'a U: 'b`, then we know that `'a: 'b` and - // `U: 'b`. - // - // We can basically ignore bound regions here. So for - // example `for<'c> Foo<'a,'c>: 'b` can be elaborated to - // `'a: 'b`. - - // Ignore `for<'a> T: 'a` -- we might in the future - // consider this as evidence that `T: 'static`, but - // I'm a bit wary of such constructions and so for now - // I want to be conservative. --nmatsakis - let ty_max = data.skip_binder().0; - let r_min = data.skip_binder().1; - if r_min.is_late_bound() { - return; - } - - let visited = &mut self.visited; - let mut components = smallvec![]; - tcx.push_outlives_components(ty_max, &mut components); - self.stack.extend( - components - .into_iter() - .filter_map(|component| match component { - Component::Region(r) => { - if r.is_late_bound() { - None - } else { - Some(ty::Predicate::RegionOutlives(ty::Binder::dummy( - ty::OutlivesPredicate(r, r_min), - ))) - } - } - - Component::Param(p) => { - let ty = tcx.mk_ty_param(p.index, p.name); - Some(ty::Predicate::TypeOutlives(ty::Binder::dummy( - ty::OutlivesPredicate(ty, r_min), - ))) - } - - Component::UnresolvedInferenceVariable(_) => None, - - Component::Projection(_) | Component::EscapingProjection(_) => { - // We can probably do more here. This - // corresponds to a case like `<T as - // Foo<'a>>::U: 'b`. - None - } - }) - .filter(|p| visited.insert(p)), - ); - } - } - } -} - -impl Iterator for Elaborator<'tcx> { - type Item = ty::Predicate<'tcx>; - - fn size_hint(&self) -> (usize, Option<usize>) { - (self.stack.len(), None) - } - - fn next(&mut self) -> Option<ty::Predicate<'tcx>> { - // Extract next item from top-most stack frame, if any. - if let Some(pred) = self.stack.pop() { - self.elaborate(&pred); - Some(pred) - } else { - None - } - } -} - -/////////////////////////////////////////////////////////////////////////// -// Supertrait iterator -/////////////////////////////////////////////////////////////////////////// - -pub type Supertraits<'tcx> = FilterToTraits<Elaborator<'tcx>>; - -pub fn supertraits<'tcx>( - tcx: TyCtxt<'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>, -) -> Supertraits<'tcx> { - elaborate_trait_ref(tcx, trait_ref).filter_to_traits() -} - -pub fn transitive_bounds<'tcx>( - tcx: TyCtxt<'tcx>, - bounds: impl Iterator<Item = ty::PolyTraitRef<'tcx>>, -) -> Supertraits<'tcx> { - elaborate_trait_refs(tcx, bounds).filter_to_traits() -} - -/////////////////////////////////////////////////////////////////////////// -// `TraitAliasExpander` iterator -/////////////////////////////////////////////////////////////////////////// - -/// "Trait alias expansion" is the process of expanding a sequence of trait -/// references into another sequence by transitively following all trait -/// aliases. e.g. If you have bounds like `Foo + Send`, a trait alias -/// `trait Foo = Bar + Sync;`, and another trait alias -/// `trait Bar = Read + Write`, then the bounds would expand to -/// `Read + Write + Sync + Send`. -/// Expansion is done via a DFS (depth-first search), and the `visited` field -/// is used to avoid cycles. -pub struct TraitAliasExpander<'tcx> { - tcx: TyCtxt<'tcx>, - stack: Vec<TraitAliasExpansionInfo<'tcx>>, -} - -/// Stores information about the expansion of a trait via a path of zero or more trait aliases. -#[derive(Debug, Clone)] -pub struct TraitAliasExpansionInfo<'tcx> { - pub path: SmallVec<[(ty::PolyTraitRef<'tcx>, Span); 4]>, -} - -impl<'tcx> TraitAliasExpansionInfo<'tcx> { - fn new(trait_ref: ty::PolyTraitRef<'tcx>, span: Span) -> Self { - Self { path: smallvec![(trait_ref, span)] } - } - - /// Adds diagnostic labels to `diag` for the expansion path of a trait through all intermediate - /// trait aliases. - pub fn label_with_exp_info( - &self, - diag: &mut DiagnosticBuilder<'_>, - top_label: &str, - use_desc: &str, - ) { - diag.span_label(self.top().1, top_label); - if self.path.len() > 1 { - for (_, sp) in self.path.iter().rev().skip(1).take(self.path.len() - 2) { - diag.span_label(*sp, format!("referenced here ({})", use_desc)); - } - } - diag.span_label( - self.bottom().1, - format!("trait alias used in trait object type ({})", use_desc), - ); - } - - pub fn trait_ref(&self) -> &ty::PolyTraitRef<'tcx> { - &self.top().0 - } - - pub fn top(&self) -> &(ty::PolyTraitRef<'tcx>, Span) { - self.path.last().unwrap() - } - - pub fn bottom(&self) -> &(ty::PolyTraitRef<'tcx>, Span) { - self.path.first().unwrap() - } - - fn clone_and_push(&self, trait_ref: ty::PolyTraitRef<'tcx>, span: Span) -> Self { - let mut path = self.path.clone(); - path.push((trait_ref, span)); - - Self { path } - } -} - -pub fn expand_trait_aliases<'tcx>( - tcx: TyCtxt<'tcx>, - trait_refs: impl IntoIterator<Item = (ty::PolyTraitRef<'tcx>, Span)>, -) -> TraitAliasExpander<'tcx> { - let items: Vec<_> = trait_refs - .into_iter() - .map(|(trait_ref, span)| TraitAliasExpansionInfo::new(trait_ref, span)) - .collect(); - TraitAliasExpander { tcx, stack: items } -} - -impl<'tcx> TraitAliasExpander<'tcx> { - /// If `item` is a trait alias and its predicate has not yet been visited, then expands `item` - /// to the definition, pushes the resulting expansion onto `self.stack`, and returns `false`. - /// Otherwise, immediately returns `true` if `item` is a regular trait, or `false` if it is a - /// trait alias. - /// The return value indicates whether `item` should be yielded to the user. - fn expand(&mut self, item: &TraitAliasExpansionInfo<'tcx>) -> bool { - let tcx = self.tcx; - let trait_ref = item.trait_ref(); - let pred = trait_ref.without_const().to_predicate(); - - debug!("expand_trait_aliases: trait_ref={:?}", trait_ref); - - // Don't recurse if this bound is not a trait alias. - let is_alias = tcx.is_trait_alias(trait_ref.def_id()); - if !is_alias { - return true; - } - - // Don't recurse if this trait alias is already on the stack for the DFS search. - let anon_pred = anonymize_predicate(tcx, &pred); - if item.path.iter().rev().skip(1).any(|(tr, _)| { - anonymize_predicate(tcx, &tr.without_const().to_predicate()) == anon_pred - }) { - return false; - } - - // Get components of trait alias. - let predicates = tcx.super_predicates_of(trait_ref.def_id()); - - let items = predicates.predicates.iter().rev().filter_map(|(pred, span)| { - pred.subst_supertrait(tcx, &trait_ref) - .to_opt_poly_trait_ref() - .map(|trait_ref| item.clone_and_push(trait_ref, *span)) - }); - debug!("expand_trait_aliases: items={:?}", items.clone()); - - self.stack.extend(items); - - false - } -} - -impl<'tcx> Iterator for TraitAliasExpander<'tcx> { - type Item = TraitAliasExpansionInfo<'tcx>; - - fn size_hint(&self) -> (usize, Option<usize>) { - (self.stack.len(), None) - } - - fn next(&mut self) -> Option<TraitAliasExpansionInfo<'tcx>> { - while let Some(item) = self.stack.pop() { - if self.expand(&item) { - return Some(item); - } - } - None - } -} - -/////////////////////////////////////////////////////////////////////////// -// Iterator over def-IDs of supertraits -/////////////////////////////////////////////////////////////////////////// - -pub struct SupertraitDefIds<'tcx> { - tcx: TyCtxt<'tcx>, - stack: Vec<DefId>, - visited: FxHashSet<DefId>, -} - -pub fn supertrait_def_ids(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SupertraitDefIds<'_> { - SupertraitDefIds { - tcx, - stack: vec![trait_def_id], - visited: Some(trait_def_id).into_iter().collect(), - } -} - -impl Iterator for SupertraitDefIds<'tcx> { - type Item = DefId; - - fn next(&mut self) -> Option<DefId> { - let def_id = self.stack.pop()?; - let predicates = self.tcx.super_predicates_of(def_id); - let visited = &mut self.visited; - self.stack.extend( - predicates - .predicates - .iter() - .filter_map(|(pred, _)| pred.to_opt_poly_trait_ref()) - .map(|trait_ref| trait_ref.def_id()) - .filter(|&super_def_id| visited.insert(super_def_id)), - ); - Some(def_id) - } -} - -/////////////////////////////////////////////////////////////////////////// -// Other -/////////////////////////////////////////////////////////////////////////// - -/// A filter around an iterator of predicates that makes it yield up -/// just trait references. -pub struct FilterToTraits<I> { - base_iterator: I, -} - -impl<I> FilterToTraits<I> { - fn new(base: I) -> FilterToTraits<I> { - FilterToTraits { base_iterator: base } - } -} - -impl<'tcx, I: Iterator<Item = ty::Predicate<'tcx>>> Iterator for FilterToTraits<I> { - type Item = ty::PolyTraitRef<'tcx>; - - fn next(&mut self) -> Option<ty::PolyTraitRef<'tcx>> { - while let Some(pred) = self.base_iterator.next() { - if let ty::Predicate::Trait(data, _) = pred { - return Some(data.to_poly_trait_ref()); - } - } - None - } - - fn size_hint(&self) -> (usize, Option<usize>) { - let (_, upper) = self.base_iterator.size_hint(); - (0, upper) - } -} - -/////////////////////////////////////////////////////////////////////////// -// Other -/////////////////////////////////////////////////////////////////////////// - -/// Instantiate all bound parameters of the impl with the given substs, -/// returning the resulting trait ref and all obligations that arise. -/// The obligations are closed under normalization. -pub fn impl_trait_ref_and_oblig<'a, 'tcx>( - selcx: &mut SelectionContext<'a, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - impl_def_id: DefId, - impl_substs: SubstsRef<'tcx>, -) -> (ty::TraitRef<'tcx>, Vec<PredicateObligation<'tcx>>) { - let impl_trait_ref = selcx.tcx().impl_trait_ref(impl_def_id).unwrap(); - let impl_trait_ref = impl_trait_ref.subst(selcx.tcx(), impl_substs); - let Normalized { value: impl_trait_ref, obligations: normalization_obligations1 } = - super::normalize(selcx, param_env, ObligationCause::dummy(), &impl_trait_ref); - - let predicates = selcx.tcx().predicates_of(impl_def_id); - let predicates = predicates.instantiate(selcx.tcx(), impl_substs); - let Normalized { value: predicates, obligations: normalization_obligations2 } = - super::normalize(selcx, param_env, ObligationCause::dummy(), &predicates); - let impl_obligations = - predicates_for_generics(ObligationCause::dummy(), 0, param_env, &predicates); - - let impl_obligations: Vec<_> = impl_obligations - .into_iter() - .chain(normalization_obligations1) - .chain(normalization_obligations2) - .collect(); - - (impl_trait_ref, impl_obligations) -} - -/// See [`super::obligations_for_generics`]. -pub fn predicates_for_generics<'tcx>( - cause: ObligationCause<'tcx>, - recursion_depth: usize, - param_env: ty::ParamEnv<'tcx>, - generic_bounds: &ty::InstantiatedPredicates<'tcx>, -) -> Vec<PredicateObligation<'tcx>> { - debug!("predicates_for_generics(generic_bounds={:?})", generic_bounds); - - generic_bounds - .predicates - .iter() - .map(|&predicate| Obligation { - cause: cause.clone(), - recursion_depth, - param_env, - predicate, - }) - .collect() -} - -pub fn predicate_for_trait_ref<'tcx>( - cause: ObligationCause<'tcx>, - param_env: ty::ParamEnv<'tcx>, - trait_ref: ty::TraitRef<'tcx>, - recursion_depth: usize, -) -> PredicateObligation<'tcx> { - Obligation { - cause, - param_env, - recursion_depth, - predicate: trait_ref.without_const().to_predicate(), - } -} - -pub fn predicate_for_trait_def( - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - cause: ObligationCause<'tcx>, - trait_def_id: DefId, - recursion_depth: usize, - self_ty: Ty<'tcx>, - params: &[GenericArg<'tcx>], -) -> PredicateObligation<'tcx> { - let trait_ref = - ty::TraitRef { def_id: trait_def_id, substs: tcx.mk_substs_trait(self_ty, params) }; - predicate_for_trait_ref(cause, param_env, trait_ref, recursion_depth) -} - -/// Casts a trait reference into a reference to one of its super -/// traits; returns `None` if `target_trait_def_id` is not a -/// supertrait. -pub fn upcast_choices( - tcx: TyCtxt<'tcx>, - source_trait_ref: ty::PolyTraitRef<'tcx>, - target_trait_def_id: DefId, -) -> Vec<ty::PolyTraitRef<'tcx>> { - if source_trait_ref.def_id() == target_trait_def_id { - return vec![source_trait_ref]; // Shortcut the most common case. - } - - supertraits(tcx, source_trait_ref).filter(|r| r.def_id() == target_trait_def_id).collect() -} - -/// Given a trait `trait_ref`, returns the number of vtable entries -/// that come from `trait_ref`, excluding its supertraits. Used in -/// computing the vtable base for an upcast trait of a trait object. -pub fn count_own_vtable_entries(tcx: TyCtxt<'tcx>, trait_ref: ty::PolyTraitRef<'tcx>) -> usize { - let mut entries = 0; - // Count number of methods and add them to the total offset. - // Skip over associated types and constants. - for trait_item in tcx.associated_items(trait_ref.def_id()) { - if trait_item.kind == ty::AssocKind::Method { - entries += 1; - } - } - entries -} - -/// Given an upcast trait object described by `object`, returns the -/// index of the method `method_def_id` (which should be part of -/// `object.upcast_trait_ref`) within the vtable for `object`. -pub fn get_vtable_index_of_object_method<N>( - tcx: TyCtxt<'tcx>, - object: &super::VtableObjectData<'tcx, N>, - method_def_id: DefId, -) -> usize { - // Count number of methods preceding the one we are selecting and - // add them to the total offset. - // Skip over associated types and constants. - let mut entries = object.vtable_base; - for trait_item in tcx.associated_items(object.upcast_trait_ref.def_id()) { - if trait_item.def_id == method_def_id { - // The item with the ID we were given really ought to be a method. - assert_eq!(trait_item.kind, ty::AssocKind::Method); - return entries; - } - if trait_item.kind == ty::AssocKind::Method { - entries += 1; - } - } - - bug!("get_vtable_index_of_object_method: {:?} was not found", method_def_id); -} - -pub fn closure_trait_ref_and_return_type( - tcx: TyCtxt<'tcx>, - fn_trait_def_id: DefId, - self_ty: Ty<'tcx>, - sig: ty::PolyFnSig<'tcx>, - tuple_arguments: TupleArgumentsFlag, -) -> ty::Binder<(ty::TraitRef<'tcx>, Ty<'tcx>)> { - let arguments_tuple = match tuple_arguments { - TupleArgumentsFlag::No => sig.skip_binder().inputs()[0], - TupleArgumentsFlag::Yes => tcx.intern_tup(sig.skip_binder().inputs()), - }; - let trait_ref = ty::TraitRef { - def_id: fn_trait_def_id, - substs: tcx.mk_substs_trait(self_ty, &[arguments_tuple.into()]), - }; - ty::Binder::bind((trait_ref, sig.skip_binder().output())) -} - -pub fn generator_trait_ref_and_outputs( - tcx: TyCtxt<'tcx>, - fn_trait_def_id: DefId, - self_ty: Ty<'tcx>, - sig: ty::PolyGenSig<'tcx>, -) -> ty::Binder<(ty::TraitRef<'tcx>, Ty<'tcx>, Ty<'tcx>)> { - let trait_ref = ty::TraitRef { - def_id: fn_trait_def_id, - substs: tcx.mk_substs_trait(self_ty, &[sig.skip_binder().resume_ty.into()]), - }; - ty::Binder::bind((trait_ref, sig.skip_binder().yield_ty, sig.skip_binder().return_ty)) -} - -pub fn impl_is_default(tcx: TyCtxt<'_>, node_item_def_id: DefId) -> bool { - match tcx.hir().as_local_hir_id(node_item_def_id) { - Some(hir_id) => { - let item = tcx.hir().expect_item(hir_id); - if let hir::ItemKind::Impl { defaultness, .. } = item.kind { - defaultness.is_default() - } else { - false - } - } - None => tcx.impl_defaultness(node_item_def_id).is_default(), - } -} - -pub fn impl_item_is_final(tcx: TyCtxt<'_>, assoc_item: &ty::AssocItem) -> bool { - assoc_item.defaultness.is_final() && !impl_is_default(tcx, assoc_item.container.id()) -} - -pub enum TupleArgumentsFlag { - Yes, - No, -} diff --git a/src/librustc/traits/wf.rs b/src/librustc/traits/wf.rs deleted file mode 100644 index 48721ec04e7..00000000000 --- a/src/librustc/traits/wf.rs +++ /dev/null @@ -1,754 +0,0 @@ -use crate::infer::opaque_types::required_region_bounds; -use crate::infer::InferCtxt; -use crate::middle::lang_items; -use crate::traits::{self, AssocTypeBoundData}; -use crate::ty::subst::SubstsRef; -use crate::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness}; -use rustc_hir as hir; -use rustc_hir::def_id::DefId; -use rustc_span::symbol::{kw, Ident}; -use rustc_span::Span; - -/// Returns the set of obligations needed to make `ty` well-formed. -/// If `ty` contains unresolved inference variables, this may include -/// further WF obligations. However, if `ty` IS an unresolved -/// inference variable, returns `None`, because we are not able to -/// make any progress at all. This is to prevent "livelock" where we -/// say "$0 is WF if $0 is WF". -pub fn obligations<'a, 'tcx>( - infcx: &InferCtxt<'a, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - body_id: hir::HirId, - ty: Ty<'tcx>, - span: Span, -) -> Option<Vec<traits::PredicateObligation<'tcx>>> { - let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![], item: None }; - if wf.compute(ty) { - debug!("wf::obligations({:?}, body_id={:?}) = {:?}", ty, body_id, wf.out); - - let result = wf.normalize(); - debug!("wf::obligations({:?}, body_id={:?}) ~~> {:?}", ty, body_id, result); - Some(result) - } else { - None // no progress made, return None - } -} - -/// Returns the obligations that make this trait reference -/// well-formed. For example, if there is a trait `Set` defined like -/// `trait Set<K:Eq>`, then the trait reference `Foo: Set<Bar>` is WF -/// if `Bar: Eq`. -pub fn trait_obligations<'a, 'tcx>( - infcx: &InferCtxt<'a, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - body_id: hir::HirId, - trait_ref: &ty::TraitRef<'tcx>, - span: Span, - item: Option<&'tcx hir::Item<'tcx>>, -) -> Vec<traits::PredicateObligation<'tcx>> { - let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![], item }; - wf.compute_trait_ref(trait_ref, Elaborate::All); - wf.normalize() -} - -pub fn predicate_obligations<'a, 'tcx>( - infcx: &InferCtxt<'a, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - body_id: hir::HirId, - predicate: &ty::Predicate<'tcx>, - span: Span, -) -> Vec<traits::PredicateObligation<'tcx>> { - let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![], item: None }; - - // (*) ok to skip binders, because wf code is prepared for it - match *predicate { - ty::Predicate::Trait(ref t, _) => { - wf.compute_trait_ref(&t.skip_binder().trait_ref, Elaborate::None); // (*) - } - ty::Predicate::RegionOutlives(..) => {} - ty::Predicate::TypeOutlives(ref t) => { - wf.compute(t.skip_binder().0); - } - ty::Predicate::Projection(ref t) => { - let t = t.skip_binder(); // (*) - wf.compute_projection(t.projection_ty); - wf.compute(t.ty); - } - ty::Predicate::WellFormed(t) => { - wf.compute(t); - } - ty::Predicate::ObjectSafe(_) => {} - ty::Predicate::ClosureKind(..) => {} - ty::Predicate::Subtype(ref data) => { - wf.compute(data.skip_binder().a); // (*) - wf.compute(data.skip_binder().b); // (*) - } - ty::Predicate::ConstEvaluatable(def_id, substs) => { - let obligations = wf.nominal_obligations(def_id, substs); - wf.out.extend(obligations); - - for ty in substs.types() { - wf.compute(ty); - } - } - } - - wf.normalize() -} - -struct WfPredicates<'a, 'tcx> { - infcx: &'a InferCtxt<'a, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - body_id: hir::HirId, - span: Span, - out: Vec<traits::PredicateObligation<'tcx>>, - item: Option<&'tcx hir::Item<'tcx>>, -} - -/// Controls whether we "elaborate" supertraits and so forth on the WF -/// predicates. This is a kind of hack to address #43784. The -/// underlying problem in that issue was a trait structure like: -/// -/// ``` -/// trait Foo: Copy { } -/// trait Bar: Foo { } -/// impl<T: Bar> Foo for T { } -/// impl<T> Bar for T { } -/// ``` -/// -/// Here, in the `Foo` impl, we will check that `T: Copy` holds -- but -/// we decide that this is true because `T: Bar` is in the -/// where-clauses (and we can elaborate that to include `T: -/// Copy`). This wouldn't be a problem, except that when we check the -/// `Bar` impl, we decide that `T: Foo` must hold because of the `Foo` -/// impl. And so nowhere did we check that `T: Copy` holds! -/// -/// To resolve this, we elaborate the WF requirements that must be -/// proven when checking impls. This means that (e.g.) the `impl Bar -/// for T` will be forced to prove not only that `T: Foo` but also `T: -/// Copy` (which it won't be able to do, because there is no `Copy` -/// impl for `T`). -#[derive(Debug, PartialEq, Eq, Copy, Clone)] -enum Elaborate { - All, - None, -} - -impl<'a, 'tcx> WfPredicates<'a, 'tcx> { - fn cause(&mut self, code: traits::ObligationCauseCode<'tcx>) -> traits::ObligationCause<'tcx> { - traits::ObligationCause::new(self.span, self.body_id, code) - } - - fn normalize(&mut self) -> Vec<traits::PredicateObligation<'tcx>> { - let cause = self.cause(traits::MiscObligation); - let infcx = &mut self.infcx; - let param_env = self.param_env; - let mut obligations = Vec::with_capacity(self.out.len()); - for pred in &self.out { - assert!(!pred.has_escaping_bound_vars()); - let mut selcx = traits::SelectionContext::new(infcx); - let i = obligations.len(); - let value = - traits::normalize_to(&mut selcx, param_env, cause.clone(), pred, &mut obligations); - obligations.insert(i, value); - } - obligations - } - - /// Pushes the obligations required for `trait_ref` to be WF into `self.out`. - fn compute_trait_ref(&mut self, trait_ref: &ty::TraitRef<'tcx>, elaborate: Elaborate) { - let tcx = self.infcx.tcx; - let obligations = self.nominal_obligations(trait_ref.def_id, trait_ref.substs); - - let cause = self.cause(traits::MiscObligation); - let param_env = self.param_env; - - let item = &self.item; - let extend_cause_with_original_assoc_item_obligation = - |cause: &mut traits::ObligationCause<'_>, - pred: &ty::Predicate<'_>, - trait_assoc_items: &[ty::AssocItem]| { - let trait_item = tcx - .hir() - .as_local_hir_id(trait_ref.def_id) - .and_then(|trait_id| tcx.hir().find(trait_id)); - let (trait_name, trait_generics) = match trait_item { - Some(hir::Node::Item(hir::Item { - ident, - kind: hir::ItemKind::Trait(.., generics, _, _), - .. - })) - | Some(hir::Node::Item(hir::Item { - ident, - kind: hir::ItemKind::TraitAlias(generics, _), - .. - })) => (Some(ident), Some(generics)), - _ => (None, None), - }; - - let item_span = item.map(|i| tcx.sess.source_map().def_span(i.span)); - match pred { - ty::Predicate::Projection(proj) => { - // The obligation comes not from the current `impl` nor the `trait` being - // implemented, but rather from a "second order" obligation, like in - // `src/test/ui/associated-types/point-at-type-on-obligation-failure.rs`: - // - // error[E0271]: type mismatch resolving `<Foo2 as Bar2>::Ok == ()` - // --> $DIR/point-at-type-on-obligation-failure.rs:13:5 - // | - // LL | type Ok; - // | -- associated type defined here - // ... - // LL | impl Bar for Foo { - // | ---------------- in this `impl` item - // LL | type Ok = (); - // | ^^^^^^^^^^^^^ expected `u32`, found `()` - // | - // = note: expected type `u32` - // found type `()` - // - // FIXME: we would want to point a span to all places that contributed to this - // obligation. In the case above, it should be closer to: - // - // error[E0271]: type mismatch resolving `<Foo2 as Bar2>::Ok == ()` - // --> $DIR/point-at-type-on-obligation-failure.rs:13:5 - // | - // LL | type Ok; - // | -- associated type defined here - // LL | type Sibling: Bar2<Ok=Self::Ok>; - // | -------------------------------- obligation set here - // ... - // LL | impl Bar for Foo { - // | ---------------- in this `impl` item - // LL | type Ok = (); - // | ^^^^^^^^^^^^^ expected `u32`, found `()` - // ... - // LL | impl Bar2 for Foo2 { - // | ---------------- in this `impl` item - // LL | type Ok = u32; - // | -------------- obligation set here - // | - // = note: expected type `u32` - // found type `()` - if let Some(hir::ItemKind::Impl { items, .. }) = item.map(|i| &i.kind) { - let trait_assoc_item = tcx.associated_item(proj.projection_def_id()); - if let Some(impl_item) = items - .iter() - .filter(|item| item.ident == trait_assoc_item.ident) - .next() - { - cause.span = impl_item.span; - cause.code = traits::AssocTypeBound(Box::new(AssocTypeBoundData { - impl_span: item_span, - original: trait_assoc_item.ident.span, - bounds: vec![], - })); - } - } - } - ty::Predicate::Trait(proj, _) => { - // An associated item obligation born out of the `trait` failed to be met. - // Point at the `impl` that failed the obligation, the associated item that - // needed to meet the obligation, and the definition of that associated item, - // which should hold the obligation in most cases. An example can be seen in - // `src/test/ui/associated-types/point-at-type-on-obligation-failure-2.rs`: - // - // error[E0277]: the trait bound `bool: Bar` is not satisfied - // --> $DIR/point-at-type-on-obligation-failure-2.rs:8:5 - // | - // LL | type Assoc: Bar; - // | ----- associated type defined here - // ... - // LL | impl Foo for () { - // | --------------- in this `impl` item - // LL | type Assoc = bool; - // | ^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `bool` - // - // If the obligation comes from the where clause in the `trait`, we point at it: - // - // error[E0277]: the trait bound `bool: Bar` is not satisfied - // --> $DIR/point-at-type-on-obligation-failure-2.rs:8:5 - // | - // | trait Foo where <Self as Foo>>::Assoc: Bar { - // | -------------------------- restricted in this bound - // LL | type Assoc; - // | ----- associated type defined here - // ... - // LL | impl Foo for () { - // | --------------- in this `impl` item - // LL | type Assoc = bool; - // | ^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `bool` - if let ( - ty::Projection(ty::ProjectionTy { item_def_id, .. }), - Some(hir::ItemKind::Impl { items, .. }), - ) = (&proj.skip_binder().self_ty().kind, item.map(|i| &i.kind)) - { - if let Some((impl_item, trait_assoc_item)) = trait_assoc_items - .iter() - .filter(|i| i.def_id == *item_def_id) - .next() - .and_then(|trait_assoc_item| { - items - .iter() - .filter(|i| i.ident == trait_assoc_item.ident) - .next() - .map(|impl_item| (impl_item, trait_assoc_item)) - }) - { - let bounds = trait_generics - .map(|generics| { - get_generic_bound_spans( - &generics, - trait_name, - trait_assoc_item.ident, - ) - }) - .unwrap_or_else(Vec::new); - cause.span = impl_item.span; - cause.code = traits::AssocTypeBound(Box::new(AssocTypeBoundData { - impl_span: item_span, - original: trait_assoc_item.ident.span, - bounds, - })); - } - } - } - _ => {} - } - }; - - if let Elaborate::All = elaborate { - let trait_assoc_items = tcx.associated_items(trait_ref.def_id); - - let predicates = obligations.iter().map(|obligation| obligation.predicate).collect(); - let implied_obligations = traits::elaborate_predicates(tcx, predicates); - let implied_obligations = implied_obligations.map(|pred| { - let mut cause = cause.clone(); - extend_cause_with_original_assoc_item_obligation( - &mut cause, - &pred, - trait_assoc_items, - ); - traits::Obligation::new(cause, param_env, pred) - }); - self.out.extend(implied_obligations); - } - - self.out.extend(obligations); - - self.out.extend(trait_ref.substs.types().filter(|ty| !ty.has_escaping_bound_vars()).map( - |ty| traits::Obligation::new(cause.clone(), param_env, ty::Predicate::WellFormed(ty)), - )); - } - - /// Pushes the obligations required for `trait_ref::Item` to be WF - /// into `self.out`. - fn compute_projection(&mut self, data: ty::ProjectionTy<'tcx>) { - // A projection is well-formed if (a) the trait ref itself is - // WF and (b) the trait-ref holds. (It may also be - // normalizable and be WF that way.) - let trait_ref = data.trait_ref(self.infcx.tcx); - self.compute_trait_ref(&trait_ref, Elaborate::None); - - if !data.has_escaping_bound_vars() { - let predicate = trait_ref.without_const().to_predicate(); - let cause = self.cause(traits::ProjectionWf(data)); - self.out.push(traits::Obligation::new(cause, self.param_env, predicate)); - } - } - - /// Pushes the obligations required for an array length to be WF - /// into `self.out`. - fn compute_array_len(&mut self, constant: ty::Const<'tcx>) { - if let ty::ConstKind::Unevaluated(def_id, substs, promoted) = constant.val { - assert!(promoted.is_none()); - - let obligations = self.nominal_obligations(def_id, substs); - self.out.extend(obligations); - - let predicate = ty::Predicate::ConstEvaluatable(def_id, substs); - let cause = self.cause(traits::MiscObligation); - self.out.push(traits::Obligation::new(cause, self.param_env, predicate)); - } - } - - fn require_sized(&mut self, subty: Ty<'tcx>, cause: traits::ObligationCauseCode<'tcx>) { - if !subty.has_escaping_bound_vars() { - let cause = self.cause(cause); - let trait_ref = ty::TraitRef { - def_id: self.infcx.tcx.require_lang_item(lang_items::SizedTraitLangItem, None), - substs: self.infcx.tcx.mk_substs_trait(subty, &[]), - }; - self.out.push(traits::Obligation::new( - cause, - self.param_env, - trait_ref.without_const().to_predicate(), - )); - } - } - - /// Pushes new obligations into `out`. Returns `true` if it was able - /// to generate all the predicates needed to validate that `ty0` - /// is WF. Returns false if `ty0` is an unresolved type variable, - /// in which case we are not able to simplify at all. - fn compute(&mut self, ty0: Ty<'tcx>) -> bool { - let mut subtys = ty0.walk(); - let param_env = self.param_env; - while let Some(ty) = subtys.next() { - match ty.kind { - ty::Bool - | ty::Char - | ty::Int(..) - | ty::Uint(..) - | ty::Float(..) - | ty::Error - | ty::Str - | ty::GeneratorWitness(..) - | ty::Never - | ty::Param(_) - | ty::Bound(..) - | ty::Placeholder(..) - | ty::Foreign(..) => { - // WfScalar, WfParameter, etc - } - - ty::Slice(subty) => { - self.require_sized(subty, traits::SliceOrArrayElem); - } - - ty::Array(subty, len) => { - self.require_sized(subty, traits::SliceOrArrayElem); - self.compute_array_len(*len); - } - - ty::Tuple(ref tys) => { - if let Some((_last, rest)) = tys.split_last() { - for elem in rest { - self.require_sized(elem.expect_ty(), traits::TupleElem); - } - } - } - - ty::RawPtr(_) => { - // simple cases that are WF if their type args are WF - } - - ty::Projection(data) => { - subtys.skip_current_subtree(); // subtree handled by compute_projection - self.compute_projection(data); - } - - ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"), - - ty::Adt(def, substs) => { - // WfNominalType - let obligations = self.nominal_obligations(def.did, substs); - self.out.extend(obligations); - } - - ty::FnDef(did, substs) => { - let obligations = self.nominal_obligations(did, substs); - self.out.extend(obligations); - } - - ty::Ref(r, rty, _) => { - // WfReference - if !r.has_escaping_bound_vars() && !rty.has_escaping_bound_vars() { - let cause = self.cause(traits::ReferenceOutlivesReferent(ty)); - self.out.push(traits::Obligation::new( - cause, - param_env, - ty::Predicate::TypeOutlives(ty::Binder::dummy(ty::OutlivesPredicate( - rty, r, - ))), - )); - } - } - - ty::Generator(..) => { - // Walk ALL the types in the generator: this will - // include the upvar types as well as the yield - // type. Note that this is mildly distinct from - // the closure case, where we have to be careful - // about the signature of the closure. We don't - // have the problem of implied bounds here since - // generators don't take arguments. - } - - ty::Closure(def_id, substs) => { - // Only check the upvar types for WF, not the rest - // of the types within. This is needed because we - // capture the signature and it may not be WF - // without the implied bounds. Consider a closure - // like `|x: &'a T|` -- it may be that `T: 'a` is - // not known to hold in the creator's context (and - // indeed the closure may not be invoked by its - // creator, but rather turned to someone who *can* - // verify that). - // - // The special treatment of closures here really - // ought not to be necessary either; the problem - // is related to #25860 -- there is no way for us - // to express a fn type complete with the implied - // bounds that it is assuming. I think in reality - // the WF rules around fn are a bit messed up, and - // that is the rot problem: `fn(&'a T)` should - // probably always be WF, because it should be - // shorthand for something like `where(T: 'a) { - // fn(&'a T) }`, as discussed in #25860. - // - // Note that we are also skipping the generic - // types. This is consistent with the `outlives` - // code, but anyway doesn't matter: within the fn - // body where they are created, the generics will - // always be WF, and outside of that fn body we - // are not directly inspecting closure types - // anyway, except via auto trait matching (which - // only inspects the upvar types). - subtys.skip_current_subtree(); // subtree handled by compute_projection - for upvar_ty in substs.as_closure().upvar_tys(def_id, self.infcx.tcx) { - self.compute(upvar_ty); - } - } - - ty::FnPtr(_) => { - // let the loop iterate into the argument/return - // types appearing in the fn signature - } - - ty::Opaque(did, substs) => { - // all of the requirements on type parameters - // should've been checked by the instantiation - // of whatever returned this exact `impl Trait`. - - // for named opaque `impl Trait` types we still need to check them - if ty::is_impl_trait_defn(self.infcx.tcx, did).is_none() { - let obligations = self.nominal_obligations(did, substs); - self.out.extend(obligations); - } - } - - ty::Dynamic(data, r) => { - // WfObject - // - // Here, we defer WF checking due to higher-ranked - // regions. This is perhaps not ideal. - self.from_object_ty(ty, data, r); - - // FIXME(#27579) RFC also considers adding trait - // obligations that don't refer to Self and - // checking those - - let defer_to_coercion = self.infcx.tcx.features().object_safe_for_dispatch; - - if !defer_to_coercion { - let cause = self.cause(traits::MiscObligation); - let component_traits = data.auto_traits().chain(data.principal_def_id()); - self.out.extend(component_traits.map(|did| { - traits::Obligation::new( - cause.clone(), - param_env, - ty::Predicate::ObjectSafe(did), - ) - })); - } - } - - // Inference variables are the complicated case, since we don't - // know what type they are. We do two things: - // - // 1. Check if they have been resolved, and if so proceed with - // THAT type. - // 2. If not, check whether this is the type that we - // started with (ty0). In that case, we've made no - // progress at all, so return false. Otherwise, - // we've at least simplified things (i.e., we went - // from `Vec<$0>: WF` to `$0: WF`, so we can - // register a pending obligation and keep - // moving. (Goal is that an "inductive hypothesis" - // is satisfied to ensure termination.) - ty::Infer(_) => { - let ty = self.infcx.shallow_resolve(ty); - if let ty::Infer(_) = ty.kind { - // not yet resolved... - if ty == ty0 { - // ...this is the type we started from! no progress. - return false; - } - - let cause = self.cause(traits::MiscObligation); - self.out.push( - // ...not the type we started from, so we made progress. - traits::Obligation::new( - cause, - self.param_env, - ty::Predicate::WellFormed(ty), - ), - ); - } else { - // Yes, resolved, proceed with the - // result. Should never return false because - // `ty` is not a Infer. - assert!(self.compute(ty)); - } - } - } - } - - // if we made it through that loop above, we made progress! - return true; - } - - fn nominal_obligations( - &mut self, - def_id: DefId, - substs: SubstsRef<'tcx>, - ) -> Vec<traits::PredicateObligation<'tcx>> { - let predicates = self.infcx.tcx.predicates_of(def_id).instantiate(self.infcx.tcx, substs); - let cause = self.cause(traits::ItemObligation(def_id)); - predicates - .predicates - .into_iter() - .map(|pred| traits::Obligation::new(cause.clone(), self.param_env, pred)) - .filter(|pred| !pred.has_escaping_bound_vars()) - .collect() - } - - fn from_object_ty( - &mut self, - ty: Ty<'tcx>, - data: ty::Binder<&'tcx ty::List<ty::ExistentialPredicate<'tcx>>>, - region: ty::Region<'tcx>, - ) { - // Imagine a type like this: - // - // trait Foo { } - // trait Bar<'c> : 'c { } - // - // &'b (Foo+'c+Bar<'d>) - // ^ - // - // In this case, the following relationships must hold: - // - // 'b <= 'c - // 'd <= 'c - // - // The first conditions is due to the normal region pointer - // rules, which say that a reference cannot outlive its - // referent. - // - // The final condition may be a bit surprising. In particular, - // you may expect that it would have been `'c <= 'd`, since - // usually lifetimes of outer things are conservative - // approximations for inner things. However, it works somewhat - // differently with trait objects: here the idea is that if the - // user specifies a region bound (`'c`, in this case) it is the - // "master bound" that *implies* that bounds from other traits are - // all met. (Remember that *all bounds* in a type like - // `Foo+Bar+Zed` must be met, not just one, hence if we write - // `Foo<'x>+Bar<'y>`, we know that the type outlives *both* 'x and - // 'y.) - // - // Note: in fact we only permit builtin traits, not `Bar<'d>`, I - // am looking forward to the future here. - if !data.has_escaping_bound_vars() && !region.has_escaping_bound_vars() { - let implicit_bounds = object_region_bounds(self.infcx.tcx, data); - - let explicit_bound = region; - - self.out.reserve(implicit_bounds.len()); - for implicit_bound in implicit_bounds { - let cause = self.cause(traits::ObjectTypeBound(ty, explicit_bound)); - let outlives = - ty::Binder::dummy(ty::OutlivesPredicate(explicit_bound, implicit_bound)); - self.out.push(traits::Obligation::new( - cause, - self.param_env, - outlives.to_predicate(), - )); - } - } - } -} - -/// Given an object type like `SomeTrait + Send`, computes the lifetime -/// bounds that must hold on the elided self type. These are derived -/// from the declarations of `SomeTrait`, `Send`, and friends -- if -/// they declare `trait SomeTrait : 'static`, for example, then -/// `'static` would appear in the list. The hard work is done by -/// `infer::required_region_bounds`, see that for more information. -pub fn object_region_bounds<'tcx>( - tcx: TyCtxt<'tcx>, - existential_predicates: ty::Binder<&'tcx ty::List<ty::ExistentialPredicate<'tcx>>>, -) -> Vec<ty::Region<'tcx>> { - // Since we don't actually *know* the self type for an object, - // this "open(err)" serves as a kind of dummy standin -- basically - // a placeholder type. - let open_ty = tcx.mk_ty_infer(ty::FreshTy(0)); - - let predicates = existential_predicates - .iter() - .filter_map(|predicate| { - if let ty::ExistentialPredicate::Projection(_) = *predicate.skip_binder() { - None - } else { - Some(predicate.with_self_ty(tcx, open_ty)) - } - }) - .collect(); - - required_region_bounds(tcx, open_ty, predicates) -} - -/// Find the span of a generic bound affecting an associated type. -fn get_generic_bound_spans( - generics: &hir::Generics<'_>, - trait_name: Option<&Ident>, - assoc_item_name: Ident, -) -> Vec<Span> { - let mut bounds = vec![]; - for clause in generics.where_clause.predicates.iter() { - if let hir::WherePredicate::BoundPredicate(pred) = clause { - match &pred.bounded_ty.kind { - hir::TyKind::Path(hir::QPath::Resolved(Some(ty), path)) => { - let mut s = path.segments.iter(); - if let (a, Some(b), None) = (s.next(), s.next(), s.next()) { - if a.map(|s| &s.ident) == trait_name - && b.ident == assoc_item_name - && is_self_path(&ty.kind) - { - // `<Self as Foo>::Bar` - bounds.push(pred.span); - } - } - } - hir::TyKind::Path(hir::QPath::TypeRelative(ty, segment)) => { - if segment.ident == assoc_item_name { - if is_self_path(&ty.kind) { - // `Self::Bar` - bounds.push(pred.span); - } - } - } - _ => {} - } - } - } - bounds -} - -fn is_self_path(kind: &hir::TyKind<'_>) -> bool { - match kind { - hir::TyKind::Path(hir::QPath::Resolved(None, path)) => { - let mut s = path.segments.iter(); - if let (Some(segment), None) = (s.next(), s.next()) { - if segment.ident.name == kw::SelfUpper { - // `type(Self)` - return true; - } - } - } - _ => {} - } - false -} diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs index ddaaab412a4..125ee316ed8 100644 --- a/src/librustc/ty/query/mod.rs +++ b/src/librustc/ty/query/mod.rs @@ -19,15 +19,15 @@ use crate::mir::interpret::{LitToConstError, LitToConstInput}; use crate::mir::mono::CodegenUnit; use crate::session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolManglingVersion}; use crate::session::CrateDisambiguator; -use crate::traits::query::dropck_outlives::{DropckOutlivesResult, DtorckConstraint}; -use crate::traits::query::method_autoderef::MethodAutoderefStepsResult; -use crate::traits::query::normalize::NormalizationResult; -use crate::traits::query::outlives_bounds::OutlivesBound; use crate::traits::query::{ CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal, CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal, CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal, NoSolution, }; +use crate::traits::query::{ + DropckOutlivesResult, DtorckConstraint, MethodAutoderefStepsResult, NormalizationResult, + OutlivesBound, +}; use crate::traits::specialization_graph; use crate::traits::Clauses; use crate::traits::{self, Vtable}; |
