Auto merge of #69076 - cjgillot:split_trait, r=matthewjasper
Split librustc::{traits,infer} to their respective crates Followup on #67953. I tried to follow the existing module structures. cc @eddyb r? @Zoxc
This commit is contained in:
commit
131772c5e0
114 changed files with 5588 additions and 4695 deletions
34
Cargo.lock
34
Cargo.lock
|
@ -3783,19 +3783,15 @@ dependencies = [
|
|||
name = "rustc_infer"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"fmt_macros",
|
||||
"graphviz",
|
||||
"log",
|
||||
"rustc",
|
||||
"rustc_ast",
|
||||
"rustc_attr",
|
||||
"rustc_data_structures",
|
||||
"rustc_error_codes",
|
||||
"rustc_errors",
|
||||
"rustc_hir",
|
||||
"rustc_index",
|
||||
"rustc_macros",
|
||||
"rustc_session",
|
||||
"rustc_span",
|
||||
"rustc_target",
|
||||
"smallvec 1.0.0",
|
||||
|
@ -3835,6 +3831,7 @@ dependencies = [
|
|||
"rustc_session",
|
||||
"rustc_span",
|
||||
"rustc_target",
|
||||
"rustc_trait_selection",
|
||||
"rustc_traits",
|
||||
"rustc_ty",
|
||||
"rustc_typeck",
|
||||
|
@ -3869,6 +3866,7 @@ dependencies = [
|
|||
"rustc_session",
|
||||
"rustc_span",
|
||||
"rustc_target",
|
||||
"rustc_trait_selection",
|
||||
"unicode-security",
|
||||
]
|
||||
|
||||
|
@ -3938,6 +3936,7 @@ dependencies = [
|
|||
"rustc_macros",
|
||||
"rustc_span",
|
||||
"rustc_target",
|
||||
"rustc_trait_selection",
|
||||
"serialize",
|
||||
"smallvec 1.0.0",
|
||||
]
|
||||
|
@ -3961,6 +3960,7 @@ dependencies = [
|
|||
"rustc_session",
|
||||
"rustc_span",
|
||||
"rustc_target",
|
||||
"rustc_trait_selection",
|
||||
"serialize",
|
||||
"smallvec 1.0.0",
|
||||
]
|
||||
|
@ -4001,6 +4001,7 @@ dependencies = [
|
|||
"rustc_session",
|
||||
"rustc_span",
|
||||
"rustc_target",
|
||||
"rustc_trait_selection",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -4048,7 +4049,6 @@ dependencies = [
|
|||
"rustc_expand",
|
||||
"rustc_feature",
|
||||
"rustc_hir",
|
||||
"rustc_infer",
|
||||
"rustc_metadata",
|
||||
"rustc_session",
|
||||
"rustc_span",
|
||||
|
@ -4128,6 +4128,27 @@ version = "0.2.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b725dadae9fabc488df69a287f5a99c5eaf5d10853842a8a3dfac52476f544ee"
|
||||
|
||||
[[package]]
|
||||
name = "rustc_trait_selection"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"fmt_macros",
|
||||
"log",
|
||||
"rustc",
|
||||
"rustc_ast",
|
||||
"rustc_attr",
|
||||
"rustc_data_structures",
|
||||
"rustc_errors",
|
||||
"rustc_hir",
|
||||
"rustc_index",
|
||||
"rustc_infer",
|
||||
"rustc_macros",
|
||||
"rustc_session",
|
||||
"rustc_span",
|
||||
"rustc_target",
|
||||
"smallvec 1.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_traits"
|
||||
version = "0.0.0"
|
||||
|
@ -4141,6 +4162,7 @@ dependencies = [
|
|||
"rustc_macros",
|
||||
"rustc_span",
|
||||
"rustc_target",
|
||||
"rustc_trait_selection",
|
||||
"smallvec 1.0.0",
|
||||
]
|
||||
|
||||
|
@ -4155,6 +4177,7 @@ dependencies = [
|
|||
"rustc_infer",
|
||||
"rustc_span",
|
||||
"rustc_target",
|
||||
"rustc_trait_selection",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -4173,6 +4196,7 @@ dependencies = [
|
|||
"rustc_infer",
|
||||
"rustc_span",
|
||||
"rustc_target",
|
||||
"rustc_trait_selection",
|
||||
"smallvec 1.0.0",
|
||||
]
|
||||
|
||||
|
|
|
@ -288,3 +288,44 @@ impl<T: Clone> WithDepNode<T> {
|
|||
self.cached_value.clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[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 },
|
||||
}
|
||||
|
||||
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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,18 +10,14 @@ path = "lib.rs"
|
|||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
fmt_macros = { path = "../libfmt_macros" }
|
||||
graphviz = { path = "../libgraphviz" }
|
||||
log = { version = "0.4", features = ["release_max_level_info", "std"] }
|
||||
rustc_attr = { path = "../librustc_attr" }
|
||||
rustc = { path = "../librustc" }
|
||||
rustc_data_structures = { path = "../librustc_data_structures" }
|
||||
rustc_errors = { path = "../librustc_errors" }
|
||||
rustc_error_codes = { path = "../librustc_error_codes" }
|
||||
rustc_hir = { path = "../librustc_hir" }
|
||||
rustc_index = { path = "../librustc_index" }
|
||||
rustc_macros = { path = "../librustc_macros" }
|
||||
rustc_session = { path = "../librustc_session" }
|
||||
rustc_span = { path = "../librustc_span" }
|
||||
rustc_target = { path = "../librustc_target" }
|
||||
smallvec = { version = "1.0", features = ["union", "may_dangle"] }
|
||||
|
|
|
@ -14,7 +14,7 @@ use crate::infer::canonical::{
|
|||
};
|
||||
use crate::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelatingDelegate};
|
||||
use crate::infer::region_constraints::{Constraint, RegionConstraintData};
|
||||
use crate::infer::{InferCtxt, InferCtxtBuilder, InferOk, InferResult, NLLRegionVariableOrigin};
|
||||
use crate::infer::{InferCtxt, InferOk, InferResult, NLLRegionVariableOrigin};
|
||||
use crate::traits::query::{Fallible, NoSolution};
|
||||
use crate::traits::{DomainGoal, TraitEngine};
|
||||
use crate::traits::{Obligation, ObligationCause, PredicateObligation};
|
||||
|
@ -26,52 +26,8 @@ use rustc::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:
|
||||
|
|
|
@ -49,7 +49,6 @@ use super::lexical_region_resolve::RegionResolutionError;
|
|||
use super::region_constraints::GenericKind;
|
||||
use super::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TypeTrace, ValuePairs};
|
||||
|
||||
use crate::infer::opaque_types;
|
||||
use crate::infer::{self, SuppressRegionErrors};
|
||||
use crate::traits::error_reporting::report_object_safety_error;
|
||||
use crate::traits::{
|
||||
|
@ -288,6 +287,86 @@ fn explain_span(tcx: TyCtxt<'tcx>, heading: &str, span: Span) -> (String, Option
|
|||
(format!("the {} at {}:{}", heading, lo.line, lo.col.to_usize() + 1), Some(span))
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
pub fn report_region_errors(
|
||||
&self,
|
||||
|
@ -410,7 +489,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
span,
|
||||
} => {
|
||||
let hidden_ty = self.resolve_vars_if_possible(&hidden_ty);
|
||||
opaque_types::unexpected_hidden_region_diagnostic(
|
||||
unexpected_hidden_region_diagnostic(
|
||||
self.tcx,
|
||||
Some(region_scope_tree),
|
||||
span,
|
||||
|
@ -2077,7 +2156,7 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> {
|
|||
/// 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 {
|
||||
pub enum TyCategory {
|
||||
Closure,
|
||||
Opaque,
|
||||
Generator,
|
||||
|
|
|
@ -13,11 +13,11 @@ use rustc::infer::canonical::{Canonical, CanonicalVarValues};
|
|||
use rustc::infer::unify_key::{ConstVarValue, ConstVariableValue};
|
||||
use rustc::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType};
|
||||
use rustc::middle::free_region::RegionRelations;
|
||||
use rustc::middle::lang_items;
|
||||
use rustc::middle::region;
|
||||
use rustc::mir;
|
||||
use rustc::mir::interpret::ConstEvalResult;
|
||||
use rustc::session::config::BorrowckMode;
|
||||
use rustc::traits::select;
|
||||
use rustc::ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric};
|
||||
use rustc::ty::fold::{TypeFoldable, TypeFolder};
|
||||
use rustc::ty::relate::RelateResult;
|
||||
|
@ -58,7 +58,6 @@ 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;
|
||||
|
@ -215,10 +214,10 @@ pub struct InferCtxt<'a, '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>,
|
||||
pub selection_cache: select::SelectionCache<'tcx>,
|
||||
|
||||
/// Caches the results of trait evaluation.
|
||||
pub evaluation_cache: traits::EvaluationCache<'tcx>,
|
||||
pub evaluation_cache: select::EvaluationCache<'tcx>,
|
||||
|
||||
/// the set of predicates on which errors have been reported, to
|
||||
/// avoid reporting the same error twice.
|
||||
|
@ -1474,27 +1473,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
.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);
|
||||
|
||||
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.
|
||||
|
@ -1518,30 +1496,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
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.
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
use crate::infer::{GenericKind, InferCtxt};
|
||||
use crate::traits::query::outlives_bounds::{self, OutlivesBound};
|
||||
use crate::traits::query::OutlivesBound;
|
||||
use rustc::ty;
|
||||
use rustc::ty::free_region_map::FreeRegionMap;
|
||||
use rustc::ty::{self, Ty};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_hir as hir;
|
||||
use rustc_span::Span;
|
||||
|
||||
use super::explicit_outlives_bounds;
|
||||
|
||||
/// The `OutlivesEnvironment` collects information about what outlives
|
||||
/// what in a given type-checking setting. For example, if we have a
|
||||
|
@ -76,7 +77,7 @@ impl<'a, 'tcx> OutlivesEnvironment<'tcx> {
|
|||
region_bound_pairs_accum: vec![],
|
||||
};
|
||||
|
||||
env.add_outlives_bounds(None, outlives_bounds::explicit_outlives_bounds(param_env));
|
||||
env.add_outlives_bounds(None, explicit_outlives_bounds(param_env));
|
||||
|
||||
env
|
||||
}
|
||||
|
@ -142,39 +143,6 @@ impl<'a, 'tcx> OutlivesEnvironment<'tcx> {
|
|||
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 =
|
||||
|
@ -188,8 +156,11 @@ impl<'a, 'tcx> OutlivesEnvironment<'tcx> {
|
|||
/// 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
|
||||
pub 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
|
||||
|
|
|
@ -3,3 +3,25 @@
|
|||
pub mod env;
|
||||
pub mod obligations;
|
||||
pub mod verify;
|
||||
|
||||
use rustc::traits::query::OutlivesBound;
|
||||
use rustc::ty;
|
||||
|
||||
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)),
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
//! This crates defines the trait resolution method and the type inference engine.
|
||||
//! This crates defines the type inference engine.
|
||||
//!
|
||||
//! - **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.
|
||||
|
@ -17,12 +16,11 @@
|
|||
#![feature(bool_to_option)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(box_syntax)]
|
||||
#![feature(drain_filter)]
|
||||
#![feature(never_type)]
|
||||
#![feature(range_is_empty)]
|
||||
#![feature(in_band_lifetimes)]
|
||||
#![feature(crate_visibility_modifier)]
|
||||
#![recursion_limit = "512"]
|
||||
#![recursion_limit = "512"] // For rustdoc
|
||||
|
||||
#[macro_use]
|
||||
extern crate rustc_macros;
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use crate::infer::InferCtxt;
|
||||
use crate::traits::Obligation;
|
||||
use rustc::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness};
|
||||
use rustc::ty::{self, ToPredicate, Ty, WithConstness};
|
||||
use rustc_hir::def_id::DefId;
|
||||
|
||||
use super::{FulfillmentContext, FulfillmentError};
|
||||
use super::FulfillmentError;
|
||||
use super::{ObligationCause, PredicateObligation};
|
||||
|
||||
pub trait TraitEngine<'tcx>: 'tcx {
|
||||
|
@ -76,9 +76,3 @@ impl<T: ?Sized + TraitEngine<'tcx>> TraitEngineExt<'tcx> for T {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl dyn TraitEngine<'tcx> {
|
||||
pub fn new(_tcx: TyCtxt<'tcx>) -> Box<Self> {
|
||||
Box::new(FulfillmentContext::new())
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,115 +1,33 @@
|
|||
//! Trait Resolution. See the [rustc dev guide] for more information on how this works.
|
||||
//! Trait Resolution. See the [rustc guide] for more information on how this works.
|
||||
//!
|
||||
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/resolution.html
|
||||
//! [rustc guide]: https://rust-lang.github.io/rustc-guide/traits/resolution.html
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub mod auto_trait;
|
||||
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;
|
||||
mod structural_impls;
|
||||
mod structural_match;
|
||||
mod util;
|
||||
pub mod wf;
|
||||
|
||||
use crate::infer::outlives::env::OutlivesEnvironment;
|
||||
use crate::infer::{InferCtxt, SuppressRegionErrors, TyCtxtInferExt};
|
||||
use rustc::middle::region;
|
||||
use rustc::ty::error::{ExpectedFound, TypeError};
|
||||
use rustc::ty::fold::TypeFoldable;
|
||||
use rustc::ty::subst::{InternalSubsts, SubstsRef};
|
||||
use rustc::ty::{self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, WithConstness};
|
||||
use rustc::util::common::ErrorReported;
|
||||
use rustc::ty::{self, Ty};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
|
||||
use std::fmt::Debug;
|
||||
use rustc_span::Span;
|
||||
|
||||
pub use self::FulfillmentErrorCode::*;
|
||||
pub use self::ObligationCauseCode::*;
|
||||
pub use self::SelectionError::*;
|
||||
pub use self::Vtable::*;
|
||||
|
||||
pub use self::coherence::{add_placeholder_note, orphan_check, overlapping_impls};
|
||||
pub use self::coherence::{OrphanCheckErr, OverlapResult};
|
||||
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::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, Reveal};
|
||||
pub use self::select::{EvaluationCache, SelectionCache, SelectionContext};
|
||||
pub use self::select::{EvaluationResult, IntercrateAmbiguityCause, OverflowError};
|
||||
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,
|
||||
Normalized, NormalizedTy, ProjectionCache, ProjectionCacheEntry, ProjectionCacheKey,
|
||||
ProjectionCacheSnapshot, Reveal,
|
||||
};
|
||||
crate use self::util::elaborate_predicates;
|
||||
|
||||
pub use rustc::traits::*;
|
||||
|
||||
/// 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
|
||||
}
|
||||
}
|
||||
|
||||
/// 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
|
||||
}
|
||||
}
|
||||
|
||||
/// 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
|
||||
|
@ -165,418 +83,6 @@ pub enum FulfillmentErrorCode<'tcx> {
|
|||
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_or_consts() {
|
||||
// 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
|
||||
}
|
||||
}
|
||||
} 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;
|
||||
}
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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())
|
||||
.in_definition_order()
|
||||
.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;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
Some((def_id, substs))
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
impl<'tcx, O> Obligation<'tcx, O> {
|
||||
pub fn new(
|
||||
cause: ObligationCause<'tcx>,
|
||||
|
@ -586,7 +92,7 @@ impl<'tcx, O> Obligation<'tcx, O> {
|
|||
Obligation { cause, param_env, recursion_depth: 0, predicate }
|
||||
}
|
||||
|
||||
fn with_depth(
|
||||
pub fn with_depth(
|
||||
cause: ObligationCause<'tcx>,
|
||||
recursion_depth: usize,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
|
@ -615,7 +121,7 @@ impl<'tcx, O> Obligation<'tcx, O> {
|
|||
}
|
||||
|
||||
impl<'tcx> FulfillmentError<'tcx> {
|
||||
fn new(
|
||||
pub fn new(
|
||||
obligation: PredicateObligation<'tcx>,
|
||||
code: FulfillmentErrorCode<'tcx>,
|
||||
) -> FulfillmentError<'tcx> {
|
||||
|
@ -624,19 +130,7 @@ impl<'tcx> FulfillmentError<'tcx> {
|
|||
}
|
||||
|
||||
impl<'tcx> TraitObligation<'tcx> {
|
||||
fn self_ty(&self) -> ty::Binder<Ty<'tcx>> {
|
||||
pub fn self_ty(&self) -> ty::Binder<Ty<'tcx>> {
|
||||
self.predicate.map_bound(|p| p.self_ty())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn provide(providers: &mut ty::query::Providers<'_>) {
|
||||
object_safety::provide(providers);
|
||||
*providers = ty::query::Providers {
|
||||
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
|
||||
};
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,16 +1,8 @@
|
|||
use rustc_errors::DiagnosticBuilder;
|
||||
use rustc_span::Span;
|
||||
use smallvec::smallvec;
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use rustc::ty::outlives::Component;
|
||||
use rustc::ty::subst::{GenericArg, Subst, SubstsRef};
|
||||
use rustc::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, WithConstness};
|
||||
use rustc::ty::{self, ToPolyTraitRef, TyCtxt};
|
||||
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 {
|
||||
|
@ -55,7 +47,7 @@ struct PredicateSet<'tcx> {
|
|||
|
||||
impl PredicateSet<'tcx> {
|
||||
fn new(tcx: TyCtxt<'tcx>) -> Self {
|
||||
Self { tcx, set: Default::default() }
|
||||
Self { tcx: tcx, set: Default::default() }
|
||||
}
|
||||
|
||||
fn insert(&mut self, pred: &ty::Predicate<'tcx>) -> bool {
|
||||
|
@ -96,21 +88,6 @@ pub struct Elaborator<'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>>,
|
||||
|
@ -121,10 +98,6 @@ pub fn elaborate_predicates<'tcx>(
|
|||
}
|
||||
|
||||
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 {
|
||||
|
@ -250,426 +223,3 @@ impl Iterator for Elaborator<'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// 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()).in_definition_order() {
|
||||
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()).in_definition_order() {
|
||||
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,
|
||||
}
|
||||
|
|
|
@ -42,6 +42,7 @@ rustc_errors = { path = "../librustc_errors" }
|
|||
rustc_plugin_impl = { path = "../librustc_plugin_impl" }
|
||||
rustc_privacy = { path = "../librustc_privacy" }
|
||||
rustc_resolve = { path = "../librustc_resolve" }
|
||||
rustc_trait_selection = { path = "../librustc_trait_selection" }
|
||||
rustc_ty = { path = "../librustc_ty" }
|
||||
tempfile = "3.0.5"
|
||||
once_cell = "1"
|
||||
|
|
|
@ -27,7 +27,6 @@ use rustc_errors::PResult;
|
|||
use rustc_expand::base::ExtCtxt;
|
||||
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
|
||||
use rustc_hir::Crate;
|
||||
use rustc_infer::traits;
|
||||
use rustc_lint::LintStore;
|
||||
use rustc_mir as mir;
|
||||
use rustc_mir_build as mir_build;
|
||||
|
@ -37,6 +36,7 @@ use rustc_plugin_impl as plugin;
|
|||
use rustc_resolve::{Resolver, ResolverArenas};
|
||||
use rustc_span::symbol::Symbol;
|
||||
use rustc_span::FileName;
|
||||
use rustc_trait_selection::traits;
|
||||
use rustc_typeck as typeck;
|
||||
|
||||
use rustc_serialize::json;
|
||||
|
|
|
@ -24,3 +24,4 @@ rustc_feature = { path = "../librustc_feature" }
|
|||
rustc_index = { path = "../librustc_index" }
|
||||
rustc_session = { path = "../librustc_session" }
|
||||
rustc_infer = { path = "../librustc_infer" }
|
||||
rustc_trait_selection = { path = "../librustc_trait_selection" }
|
||||
|
|
|
@ -39,12 +39,12 @@ use rustc_hir::def::{DefKind, Res};
|
|||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::{GenericParamKind, PatKind};
|
||||
use rustc_hir::{HirIdSet, Node};
|
||||
use rustc_infer::traits::misc::can_type_implement_copy;
|
||||
use rustc_session::lint::FutureIncompatibleInfo;
|
||||
use rustc_span::edition::Edition;
|
||||
use rustc_span::source_map::Spanned;
|
||||
use rustc_span::symbol::{kw, sym, Symbol};
|
||||
use rustc_span::{BytePos, Span};
|
||||
use rustc_trait_selection::traits::misc::can_type_implement_copy;
|
||||
|
||||
use crate::nonstandard_style::{method_context, MethodLateContext};
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ rustc_lexer = { path = "../librustc_lexer" }
|
|||
rustc_macros = { path = "../librustc_macros" }
|
||||
rustc_serialize = { path = "../libserialize", package = "serialize" }
|
||||
rustc_target = { path = "../librustc_target" }
|
||||
rustc_trait_selection = { path = "../librustc_trait_selection" }
|
||||
rustc_ast = { path = "../librustc_ast" }
|
||||
rustc_span = { path = "../librustc_span" }
|
||||
rustc_apfloat = { path = "../librustc_apfloat" }
|
||||
|
|
|
@ -10,9 +10,9 @@ use rustc_hir as hir;
|
|||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::{AsyncGeneratorKind, GeneratorKind};
|
||||
use rustc_index::vec::Idx;
|
||||
use rustc_infer::traits::error_reporting::suggest_constraining_type_param;
|
||||
use rustc_span::source_map::DesugaringKind;
|
||||
use rustc_span::Span;
|
||||
use rustc_trait_selection::traits::error_reporting::suggest_constraining_type_param;
|
||||
|
||||
use crate::dataflow::drop_flag_effects;
|
||||
use crate::dataflow::indexes::{MoveOutIndex, MovePathIndex};
|
||||
|
|
|
@ -4,7 +4,8 @@ use rustc::mir::ConstraintCategory;
|
|||
use rustc::ty::{self, RegionVid, Ty};
|
||||
use rustc_errors::{Applicability, DiagnosticBuilder};
|
||||
use rustc_infer::infer::{
|
||||
error_reporting::nice_region_error::NiceRegionError, opaque_types, NLLRegionVariableOrigin,
|
||||
error_reporting::nice_region_error::NiceRegionError,
|
||||
error_reporting::unexpected_hidden_region_diagnostic, NLLRegionVariableOrigin,
|
||||
};
|
||||
use rustc_span::symbol::kw;
|
||||
use rustc_span::Span;
|
||||
|
@ -197,7 +198,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
|
|||
let region_scope_tree = &self.infcx.tcx.region_scope_tree(self.mir_def_id);
|
||||
let named_ty = self.regioncx.name_regions(self.infcx.tcx, hidden_ty);
|
||||
let named_region = self.regioncx.name_regions(self.infcx.tcx, member_region);
|
||||
opaque_types::unexpected_hidden_region_diagnostic(
|
||||
unexpected_hidden_region_diagnostic(
|
||||
self.infcx.tcx,
|
||||
Some(region_scope_tree),
|
||||
span,
|
||||
|
|
|
@ -3,6 +3,7 @@ use rustc_data_structures::fx::FxHashMap;
|
|||
use rustc_hir::def_id::DefId;
|
||||
use rustc_infer::infer::InferCtxt;
|
||||
use rustc_span::Span;
|
||||
use rustc_trait_selection::opaque_types::InferCtxtExt;
|
||||
|
||||
use super::RegionInferenceContext;
|
||||
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
use rustc::mir::ConstraintCategory;
|
||||
use rustc::traits::query::OutlivesBound;
|
||||
use rustc::ty::free_region_map::FreeRegionRelations;
|
||||
use rustc::ty::{self, RegionVid, Ty, TyCtxt};
|
||||
use rustc_data_structures::transitive_relation::TransitiveRelation;
|
||||
use rustc_infer::infer::canonical::QueryRegionConstraints;
|
||||
use rustc_infer::infer::outlives;
|
||||
use rustc_infer::infer::region_constraints::GenericKind;
|
||||
use rustc_infer::infer::InferCtxt;
|
||||
use rustc_infer::traits::query::outlives_bounds::{self, OutlivesBound};
|
||||
use rustc_infer::traits::query::type_op::{self, TypeOp};
|
||||
use rustc_span::DUMMY_SP;
|
||||
use rustc_trait_selection::traits::query::type_op::{self, TypeOp};
|
||||
use std::rc::Rc;
|
||||
|
||||
use crate::borrow_check::{
|
||||
|
@ -266,7 +267,7 @@ impl UniversalRegionRelationsBuilder<'cx, 'tcx> {
|
|||
|
||||
// Insert the facts we know from the predicates. Why? Why not.
|
||||
let param_env = self.param_env;
|
||||
self.add_outlives_bounds(outlives_bounds::explicit_outlives_bounds(param_env));
|
||||
self.add_outlives_bounds(outlives::explicit_outlives_bounds(param_env));
|
||||
|
||||
// Finally:
|
||||
// - outlives is reflexive, so `'r: 'r` for every region `'r`
|
||||
|
|
|
@ -3,9 +3,9 @@ use rustc::ty::{Ty, TypeFoldable};
|
|||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_index::bit_set::HybridBitSet;
|
||||
use rustc_infer::infer::canonical::QueryRegionConstraints;
|
||||
use rustc_infer::traits::query::dropck_outlives::DropckOutlivesResult;
|
||||
use rustc_infer::traits::query::type_op::outlives::DropckOutlives;
|
||||
use rustc_infer::traits::query::type_op::TypeOp;
|
||||
use rustc_trait_selection::traits::query::dropck_outlives::DropckOutlivesResult;
|
||||
use rustc_trait_selection::traits::query::type_op::outlives::DropckOutlives;
|
||||
use rustc_trait_selection::traits::query::type_op::TypeOp;
|
||||
use std::rc::Rc;
|
||||
|
||||
use crate::dataflow::generic::ResultsCursor;
|
||||
|
|
|
@ -24,17 +24,19 @@ use rustc_hir as hir;
|
|||
use rustc_hir::def_id::DefId;
|
||||
use rustc_index::vec::{Idx, IndexVec};
|
||||
use rustc_infer::infer::canonical::QueryRegionConstraints;
|
||||
use rustc_infer::infer::opaque_types::GenerateMemberConstraints;
|
||||
use rustc_infer::infer::outlives::env::RegionBoundPairs;
|
||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use rustc_infer::infer::{
|
||||
InferCtxt, InferOk, LateBoundRegionConversionTime, NLLRegionVariableOrigin,
|
||||
};
|
||||
use rustc_infer::traits::query::type_op;
|
||||
use rustc_infer::traits::query::type_op::custom::CustomTypeOp;
|
||||
use rustc_infer::traits::query::{Fallible, NoSolution};
|
||||
use rustc_infer::traits::{self, ObligationCause, PredicateObligations};
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
use rustc_trait_selection::infer::InferCtxtExt as _;
|
||||
use rustc_trait_selection::opaque_types::{GenerateMemberConstraints, InferCtxtExt};
|
||||
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
|
||||
use rustc_trait_selection::traits::query::type_op;
|
||||
use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
|
||||
use rustc_trait_selection::traits::query::{Fallible, NoSolution};
|
||||
use rustc_trait_selection::traits::{self, ObligationCause, PredicateObligations};
|
||||
|
||||
use crate::dataflow::generic::ResultsCursor;
|
||||
use crate::dataflow::move_paths::MoveData;
|
||||
|
|
|
@ -3,8 +3,8 @@ use rustc::ty::relate::TypeRelation;
|
|||
use rustc::ty::{self, Ty};
|
||||
use rustc_infer::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelatingDelegate};
|
||||
use rustc_infer::infer::{InferCtxt, NLLRegionVariableOrigin};
|
||||
use rustc_infer::traits::query::Fallible;
|
||||
use rustc_infer::traits::DomainGoal;
|
||||
use rustc_trait_selection::traits::query::Fallible;
|
||||
use rustc_trait_selection::traits::DomainGoal;
|
||||
|
||||
use crate::borrow_check::constraints::OutlivesConstraint;
|
||||
use crate::borrow_check::type_check::{BorrowCheckContext, Locations};
|
||||
|
|
|
@ -9,9 +9,10 @@ use rustc_errors::struct_span_err;
|
|||
use rustc_hir::{def_id::DefId, HirId};
|
||||
use rustc_index::bit_set::BitSet;
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_infer::traits::{self, TraitEngine};
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::Span;
|
||||
use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
|
||||
use rustc_trait_selection::traits::{self, TraitEngine};
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::ops::Deref;
|
||||
|
|
|
@ -25,8 +25,8 @@ use rustc_data_structures::fx::FxHashMap;
|
|||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::HirId;
|
||||
use rustc_index::vec::IndexVec;
|
||||
use rustc_infer::traits;
|
||||
use rustc_span::Span;
|
||||
use rustc_trait_selection::traits;
|
||||
|
||||
use crate::const_eval::error_to_const_error;
|
||||
use crate::interpret::{
|
||||
|
|
|
@ -25,5 +25,6 @@ rustc_serialize = { path = "../libserialize", package = "serialize" }
|
|||
rustc_session = { path = "../librustc_session" }
|
||||
rustc_span = { path = "../librustc_span" }
|
||||
rustc_target = { path = "../librustc_target" }
|
||||
rustc_trait_selection = { path = "../librustc_trait_selection" }
|
||||
rustc_ast = { path = "../librustc_ast" }
|
||||
smallvec = { version = "1.0", features = ["union", "may_dangle"] }
|
||||
|
|
|
@ -19,6 +19,7 @@ use rustc_hir::Node;
|
|||
use rustc_index::vec::Idx;
|
||||
use rustc_infer::infer::InferCtxt;
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
use rustc_trait_selection::infer::InferCtxtExt;
|
||||
|
||||
#[derive(Clone)]
|
||||
crate struct Cx<'a, 'tcx> {
|
||||
|
|
|
@ -3,8 +3,9 @@ use rustc::mir::Field;
|
|||
use rustc::ty::{self, Ty, TyCtxt};
|
||||
use rustc_hir as hir;
|
||||
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
|
||||
use rustc_infer::traits::predicate_for_trait_def;
|
||||
use rustc_infer::traits::{self, ObligationCause, PredicateObligation};
|
||||
use rustc_trait_selection::traits::predicate_for_trait_def;
|
||||
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
|
||||
use rustc_trait_selection::traits::{self, ObligationCause, PredicateObligation};
|
||||
|
||||
use rustc_index::vec::Idx;
|
||||
|
||||
|
|
|
@ -22,3 +22,4 @@ rustc_session = { path = "../librustc_session" }
|
|||
rustc_target = { path = "../librustc_target" }
|
||||
rustc_ast = { path = "../librustc_ast" }
|
||||
rustc_span = { path = "../librustc_span" }
|
||||
rustc_trait_selection = { path = "../librustc_trait_selection" }
|
||||
|
|
|
@ -18,9 +18,9 @@ use rustc_hir::def::{DefKind, Res};
|
|||
use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
|
||||
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
|
||||
use rustc_hir::{Generics, HirId, Item, StructField, Variant};
|
||||
use rustc_infer::traits::misc::can_type_implement_copy;
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
use rustc_span::Span;
|
||||
use rustc_trait_selection::traits::misc::can_type_implement_copy;
|
||||
|
||||
use std::cmp::Ordering;
|
||||
use std::mem::replace;
|
||||
|
|
|
@ -24,7 +24,6 @@ rustc_errors = { path = "../librustc_errors" }
|
|||
rustc_expand = { path = "../librustc_expand" }
|
||||
rustc_feature = { path = "../librustc_feature" }
|
||||
rustc_hir = { path = "../librustc_hir" }
|
||||
rustc_infer = { path = "../librustc_infer" }
|
||||
rustc_metadata = { path = "../librustc_metadata" }
|
||||
rustc_session = { path = "../librustc_session" }
|
||||
rustc_span = { path = "../librustc_span" }
|
||||
|
|
27
src/librustc_trait_selection/Cargo.toml
Normal file
27
src/librustc_trait_selection/Cargo.toml
Normal file
|
@ -0,0 +1,27 @@
|
|||
[package]
|
||||
authors = ["The Rust Project Developers"]
|
||||
name = "rustc_trait_selection"
|
||||
version = "0.0.0"
|
||||
edition = "2018"
|
||||
|
||||
[lib]
|
||||
name = "rustc_trait_selection"
|
||||
path = "lib.rs"
|
||||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
fmt_macros = { path = "../libfmt_macros" }
|
||||
log = { version = "0.4", features = ["release_max_level_info", "std"] }
|
||||
rustc_attr = { path = "../librustc_attr" }
|
||||
rustc = { path = "../librustc" }
|
||||
rustc_ast = { path = "../librustc_ast" }
|
||||
rustc_data_structures = { path = "../librustc_data_structures" }
|
||||
rustc_errors = { path = "../librustc_errors" }
|
||||
rustc_hir = { path = "../librustc_hir" }
|
||||
rustc_index = { path = "../librustc_index" }
|
||||
rustc_infer = { path = "../librustc_infer" }
|
||||
rustc_macros = { path = "../librustc_macros" }
|
||||
rustc_session = { path = "../librustc_session" }
|
||||
rustc_span = { path = "../librustc_span" }
|
||||
rustc_target = { path = "../librustc_target" }
|
||||
smallvec = { version = "1.0", features = ["union", "may_dangle"] }
|
182
src/librustc_trait_selection/infer.rs
Normal file
182
src/librustc_trait_selection/infer.rs
Normal file
|
@ -0,0 +1,182 @@
|
|||
use crate::traits::query::outlives_bounds::InferCtxtExt as _;
|
||||
use crate::traits::{self, TraitEngine, TraitEngineExt};
|
||||
|
||||
use rustc::arena::ArenaAllocatable;
|
||||
use rustc::infer::canonical::{Canonical, CanonicalizedQueryResponse, QueryResponse};
|
||||
use rustc::middle::lang_items;
|
||||
use rustc::traits::query::Fallible;
|
||||
use rustc::ty::{self, Ty, TypeFoldable};
|
||||
use rustc_hir as hir;
|
||||
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
|
||||
use rustc_infer::traits::ObligationCause;
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
|
||||
use std::fmt::Debug;
|
||||
|
||||
pub use rustc_infer::infer::*;
|
||||
|
||||
pub trait InferCtxtExt<'tcx> {
|
||||
fn type_is_copy_modulo_regions(
|
||||
&self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
span: Span,
|
||||
) -> bool;
|
||||
|
||||
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>;
|
||||
}
|
||||
|
||||
impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
|
||||
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);
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
/// Normalizes associated types in `value`, potentially returning
|
||||
/// new obligations that must further be processed.
|
||||
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 }
|
||||
}
|
||||
}
|
||||
|
||||
pub trait InferCtxtBuilderExt<'tcx> {
|
||||
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;
|
||||
}
|
||||
|
||||
impl<'tcx> InferCtxtBuilderExt<'tcx> for 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>`.)
|
||||
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,
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait OutlivesEnvironmentExt<'tcx> {
|
||||
fn add_implied_bounds(
|
||||
&mut self,
|
||||
infcx: &InferCtxt<'a, 'tcx>,
|
||||
fn_sig_tys: &[Ty<'tcx>],
|
||||
body_id: hir::HirId,
|
||||
span: Span,
|
||||
);
|
||||
}
|
||||
|
||||
impl<'tcx> OutlivesEnvironmentExt<'tcx> for OutlivesEnvironment<'tcx> {
|
||||
/// 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`
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
32
src/librustc_trait_selection/lib.rs
Normal file
32
src/librustc_trait_selection/lib.rs
Normal file
|
@ -0,0 +1,32 @@
|
|||
//! This crates defines the trait resolution method.
|
||||
//!
|
||||
//! - **Traits.** Trait resolution is implemented in the `traits` module.
|
||||
//!
|
||||
//! For more information about how rustc works, see the [rustc guide].
|
||||
//!
|
||||
//! [rustc guide]: https://rust-lang.github.io/rustc-guide/
|
||||
//!
|
||||
//! # Note
|
||||
//!
|
||||
//! This API is completely unstable and subject to change.
|
||||
|
||||
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
|
||||
#![feature(bool_to_option)]
|
||||
#![feature(drain_filter)]
|
||||
#![feature(in_band_lifetimes)]
|
||||
#![feature(crate_visibility_modifier)]
|
||||
#![recursion_limit = "512"] // For rustdoc
|
||||
|
||||
#[macro_use]
|
||||
extern crate rustc_macros;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
#[macro_use]
|
||||
extern crate rustc_data_structures;
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
#[macro_use]
|
||||
extern crate rustc;
|
||||
|
||||
pub mod infer;
|
||||
pub mod opaque_types;
|
||||
pub mod traits;
|
|
@ -1,7 +1,5 @@
|
|||
use crate::infer::error_reporting::{note_and_explain_free_region, note_and_explain_region};
|
||||
use crate::infer::{self, InferCtxt, InferOk, TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use crate::infer::InferCtxtExt as _;
|
||||
use crate::traits::{self, PredicateObligation};
|
||||
use rustc::middle::region;
|
||||
use rustc::session::config::nightly_options;
|
||||
use rustc::ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder, TypeVisitor};
|
||||
use rustc::ty::free_region_map::FreeRegionRelations;
|
||||
|
@ -9,10 +7,12 @@ use rustc::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, SubstsRef};
|
|||
use rustc::ty::{self, GenericParamDefKind, Ty, TyCtxt};
|
||||
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_infer::infer::error_reporting::unexpected_hidden_region_diagnostic;
|
||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use rustc_infer::infer::{self, InferCtxt, InferOk};
|
||||
use rustc_span::Span;
|
||||
|
||||
pub type OpaqueTypeMap<'tcx> = DefIdMap<OpaqueTypeDecl<'tcx>>;
|
||||
|
@ -105,7 +105,58 @@ pub enum GenerateMemberConstraints {
|
|||
IfNoStaticBound,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
pub trait InferCtxtExt<'tcx> {
|
||||
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>)>;
|
||||
|
||||
fn constrain_opaque_types<FRR: FreeRegionRelations<'tcx>>(
|
||||
&self,
|
||||
opaque_types: &OpaqueTypeMap<'tcx>,
|
||||
free_region_relations: &FRR,
|
||||
);
|
||||
|
||||
fn constrain_opaque_type<FRR: FreeRegionRelations<'tcx>>(
|
||||
&self,
|
||||
def_id: DefId,
|
||||
opaque_defn: &OpaqueTypeDecl<'tcx>,
|
||||
mode: GenerateMemberConstraints,
|
||||
free_region_relations: &FRR,
|
||||
);
|
||||
|
||||
/*private*/
|
||||
fn generate_member_constraint(
|
||||
&self,
|
||||
concrete_ty: Ty<'tcx>,
|
||||
opaque_type_generics: &ty::Generics,
|
||||
opaque_defn: &OpaqueTypeDecl<'tcx>,
|
||||
opaque_type_def_id: DefId,
|
||||
);
|
||||
|
||||
/*private*/
|
||||
fn member_constraint_feature_gate(
|
||||
&self,
|
||||
opaque_defn: &OpaqueTypeDecl<'tcx>,
|
||||
opaque_type_def_id: DefId,
|
||||
conflict1: ty::Region<'tcx>,
|
||||
conflict2: ty::Region<'tcx>,
|
||||
) -> bool;
|
||||
|
||||
fn infer_opaque_definition_from_instantiation(
|
||||
&self,
|
||||
def_id: DefId,
|
||||
substs: SubstsRef<'tcx>,
|
||||
instantiated_ty: Ty<'tcx>,
|
||||
span: Span,
|
||||
) -> Ty<'tcx>;
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
/// Replaces all opaque types in `value` with fresh inference variables
|
||||
/// and creates appropriate obligations. For example, given the input:
|
||||
///
|
||||
|
@ -131,7 +182,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
/// 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>>(
|
||||
fn instantiate_opaque_types<T: TypeFoldable<'tcx>>(
|
||||
&self,
|
||||
parent_def_id: DefId,
|
||||
body_id: hir::HirId,
|
||||
|
@ -319,7 +370,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
/// - `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>>(
|
||||
fn constrain_opaque_types<FRR: FreeRegionRelations<'tcx>>(
|
||||
&self,
|
||||
opaque_types: &OpaqueTypeMap<'tcx>,
|
||||
free_region_relations: &FRR,
|
||||
|
@ -337,7 +388,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
}
|
||||
|
||||
/// See `constrain_opaque_types` for documentation.
|
||||
pub fn constrain_opaque_type<FRR: FreeRegionRelations<'tcx>>(
|
||||
fn constrain_opaque_type<FRR: FreeRegionRelations<'tcx>>(
|
||||
&self,
|
||||
def_id: DefId,
|
||||
opaque_defn: &OpaqueTypeDecl<'tcx>,
|
||||
|
@ -579,7 +630,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
/// - `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(
|
||||
fn infer_opaque_definition_from_instantiation(
|
||||
&self,
|
||||
def_id: DefId,
|
||||
substs: SubstsRef<'tcx>,
|
||||
|
@ -618,86 +669,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
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
|
|
@ -72,7 +72,7 @@ pub fn codegen_fulfill_obligation<'tcx>(
|
|||
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);
|
||||
let vtable = drain_fulfillment_cx_or_panic(&infcx, &mut fulfill_cx, &vtable);
|
||||
|
||||
info!("Cache miss: {:?} => {:?}", trait_ref, vtable);
|
||||
Some(vtable)
|
||||
|
@ -81,34 +81,32 @@ pub fn codegen_fulfill_obligation<'tcx>(
|
|||
|
||||
// # 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()");
|
||||
/// 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>(
|
||||
infcx: &InferCtxt<'_, 'tcx>,
|
||||
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)
|
||||
// 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(infcx) {
|
||||
bug!("Encountered errors `{:?}` resolving bounds after type-checking", errors);
|
||||
}
|
||||
|
||||
let result = infcx.resolve_vars_if_possible(result);
|
||||
infcx.tcx.erase_regions(&result)
|
||||
}
|
14
src/librustc_trait_selection/traits/engine.rs
Normal file
14
src/librustc_trait_selection/traits/engine.rs
Normal file
|
@ -0,0 +1,14 @@
|
|||
use rustc::ty::TyCtxt;
|
||||
|
||||
use super::FulfillmentContext;
|
||||
use super::TraitEngine;
|
||||
|
||||
pub trait TraitEngineExt<'tcx> {
|
||||
fn new(tcx: TyCtxt<'tcx>) -> Box<Self>;
|
||||
}
|
||||
|
||||
impl<'tcx> TraitEngineExt<'tcx> for dyn TraitEngine<'tcx> {
|
||||
fn new(_tcx: TyCtxt<'tcx>) -> Box<Self> {
|
||||
Box::new(FulfillmentContext::new())
|
||||
}
|
||||
}
|
1900
src/librustc_trait_selection/traits/error_reporting/mod.rs
Normal file
1900
src/librustc_trait_selection/traits/error_reporting/mod.rs
Normal file
File diff suppressed because it is too large
Load diff
|
@ -8,7 +8,27 @@ use rustc_hir as hir;
|
|||
use rustc_hir::def_id::DefId;
|
||||
use rustc_span::symbol::sym;
|
||||
|
||||
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
use super::InferCtxtPrivExt;
|
||||
|
||||
crate trait InferCtxtExt<'tcx> {
|
||||
/*private*/
|
||||
fn impl_similar_to(
|
||||
&self,
|
||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
) -> Option<DefId>;
|
||||
|
||||
/*private*/
|
||||
fn describe_enclosure(&self, hir_id: hir::HirId) -> Option<&'static str>;
|
||||
|
||||
fn on_unimplemented_note(
|
||||
&self,
|
||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
) -> OnUnimplementedNote;
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
fn impl_similar_to(
|
||||
&self,
|
||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
|
@ -101,7 +121,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
crate fn on_unimplemented_note(
|
||||
fn on_unimplemented_note(
|
||||
&self,
|
||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
obligation: &PredicateObligation<'tcx>,
|
|
@ -1,6 +1,5 @@
|
|||
use super::{
|
||||
ArgKind, EvaluationResult, Obligation, ObligationCause, ObligationCauseCode,
|
||||
PredicateObligation,
|
||||
EvaluationResult, Obligation, ObligationCause, ObligationCauseCode, PredicateObligation,
|
||||
};
|
||||
|
||||
use crate::infer::InferCtxt;
|
||||
|
@ -8,9 +7,7 @@ use crate::traits::error_reporting::suggest_constraining_type_param;
|
|||
|
||||
use rustc::ty::TypeckTables;
|
||||
use rustc::ty::{self, AdtKind, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
|
||||
use rustc_errors::{
|
||||
error_code, pluralize, struct_span_err, Applicability, DiagnosticBuilder, Style,
|
||||
};
|
||||
use rustc_errors::{error_code, struct_span_err, Applicability, DiagnosticBuilder, Style};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::DefId;
|
||||
|
@ -20,8 +17,136 @@ 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(
|
||||
use super::InferCtxtPrivExt;
|
||||
use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
|
||||
|
||||
crate trait InferCtxtExt<'tcx> {
|
||||
fn suggest_restricting_param_bound(
|
||||
&self,
|
||||
err: &mut DiagnosticBuilder<'_>,
|
||||
trait_ref: &ty::PolyTraitRef<'_>,
|
||||
body_id: hir::HirId,
|
||||
);
|
||||
|
||||
fn suggest_borrow_on_unsized_slice(
|
||||
&self,
|
||||
code: &ObligationCauseCode<'tcx>,
|
||||
err: &mut DiagnosticBuilder<'tcx>,
|
||||
);
|
||||
|
||||
fn get_closure_name(
|
||||
&self,
|
||||
def_id: DefId,
|
||||
err: &mut DiagnosticBuilder<'_>,
|
||||
msg: &str,
|
||||
) -> Option<String>;
|
||||
|
||||
fn suggest_fn_call(
|
||||
&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
err: &mut DiagnosticBuilder<'_>,
|
||||
trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
|
||||
points_at_arg: bool,
|
||||
);
|
||||
|
||||
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;
|
||||
|
||||
fn suggest_remove_reference(
|
||||
&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
err: &mut DiagnosticBuilder<'tcx>,
|
||||
trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
|
||||
);
|
||||
|
||||
fn suggest_change_mut(
|
||||
&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
err: &mut DiagnosticBuilder<'tcx>,
|
||||
trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
|
||||
points_at_arg: bool,
|
||||
);
|
||||
|
||||
fn suggest_semicolon_removal(
|
||||
&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
err: &mut DiagnosticBuilder<'tcx>,
|
||||
span: Span,
|
||||
trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
|
||||
);
|
||||
|
||||
fn suggest_impl_trait(
|
||||
&self,
|
||||
err: &mut DiagnosticBuilder<'tcx>,
|
||||
span: Span,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
|
||||
) -> bool;
|
||||
|
||||
fn point_at_returns_when_relevant(
|
||||
&self,
|
||||
err: &mut DiagnosticBuilder<'tcx>,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
);
|
||||
|
||||
fn report_closure_arg_mismatch(
|
||||
&self,
|
||||
span: Span,
|
||||
found_span: Option<Span>,
|
||||
expected_ref: ty::PolyTraitRef<'tcx>,
|
||||
found: ty::PolyTraitRef<'tcx>,
|
||||
) -> DiagnosticBuilder<'tcx>;
|
||||
|
||||
fn suggest_fully_qualified_path(
|
||||
&self,
|
||||
err: &mut DiagnosticBuilder<'_>,
|
||||
def_id: DefId,
|
||||
span: Span,
|
||||
trait_ref: DefId,
|
||||
);
|
||||
|
||||
fn maybe_note_obligation_cause_for_async_await(
|
||||
&self,
|
||||
err: &mut DiagnosticBuilder<'_>,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
) -> bool;
|
||||
|
||||
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>>,
|
||||
);
|
||||
|
||||
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;
|
||||
|
||||
fn suggest_new_overflow_limit(&self, err: &mut DiagnosticBuilder<'_>);
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
|
||||
fn suggest_restricting_param_bound(
|
||||
&self,
|
||||
mut err: &mut DiagnosticBuilder<'_>,
|
||||
trait_ref: &ty::PolyTraitRef<'_>,
|
||||
|
@ -168,7 +293,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
|
||||
/// 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(
|
||||
fn suggest_borrow_on_unsized_slice(
|
||||
&self,
|
||||
code: &ObligationCauseCode<'tcx>,
|
||||
err: &mut DiagnosticBuilder<'tcx>,
|
||||
|
@ -195,7 +320,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
/// 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(
|
||||
fn get_closure_name(
|
||||
&self,
|
||||
def_id: DefId,
|
||||
err: &mut DiagnosticBuilder<'_>,
|
||||
|
@ -233,7 +358,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
/// 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(
|
||||
fn suggest_fn_call(
|
||||
&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
err: &mut DiagnosticBuilder<'_>,
|
||||
|
@ -317,7 +442,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
crate fn suggest_add_reference_to_arg(
|
||||
fn suggest_add_reference_to_arg(
|
||||
&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
err: &mut DiagnosticBuilder<'tcx>,
|
||||
|
@ -389,7 +514,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
|
||||
/// 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(
|
||||
fn suggest_remove_reference(
|
||||
&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
err: &mut DiagnosticBuilder<'tcx>,
|
||||
|
@ -451,7 +576,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
|
||||
/// Check if the trait bound is implemented for a different mutability and note it in the
|
||||
/// final error.
|
||||
crate fn suggest_change_mut(
|
||||
fn suggest_change_mut(
|
||||
&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
err: &mut DiagnosticBuilder<'tcx>,
|
||||
|
@ -513,7 +638,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
crate fn suggest_semicolon_removal(
|
||||
fn suggest_semicolon_removal(
|
||||
&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
err: &mut DiagnosticBuilder<'tcx>,
|
||||
|
@ -549,7 +674,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
/// 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(
|
||||
fn suggest_impl_trait(
|
||||
&self,
|
||||
err: &mut DiagnosticBuilder<'tcx>,
|
||||
span: Span,
|
||||
|
@ -723,7 +848,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
true
|
||||
}
|
||||
|
||||
crate fn point_at_returns_when_relevant(
|
||||
fn point_at_returns_when_relevant(
|
||||
&self,
|
||||
err: &mut DiagnosticBuilder<'tcx>,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
|
@ -753,220 +878,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// 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::Fn(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(
|
||||
fn report_closure_arg_mismatch(
|
||||
&self,
|
||||
span: Span,
|
||||
found_span: Option<Span>,
|
||||
|
@ -1022,10 +934,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
|
||||
err
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
crate fn suggest_fully_qualified_path(
|
||||
fn suggest_fully_qualified_path(
|
||||
&self,
|
||||
err: &mut DiagnosticBuilder<'_>,
|
||||
def_id: DefId,
|
||||
|
@ -1091,7 +1001,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
/// ```
|
||||
///
|
||||
/// Returns `true` if an async-await specific note was added to the diagnostic.
|
||||
crate fn maybe_note_obligation_cause_for_async_await(
|
||||
fn maybe_note_obligation_cause_for_async_await(
|
||||
&self,
|
||||
err: &mut DiagnosticBuilder<'_>,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
|
@ -1271,7 +1181,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
|
||||
/// 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(
|
||||
fn note_obligation_cause_for_async_await(
|
||||
&self,
|
||||
err: &mut DiagnosticBuilder<'_>,
|
||||
target_span: Span,
|
||||
|
@ -1423,7 +1333,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
);
|
||||
}
|
||||
|
||||
crate fn note_obligation_cause_code<T>(
|
||||
fn note_obligation_cause_code<T>(
|
||||
&self,
|
||||
err: &mut DiagnosticBuilder<'_>,
|
||||
predicate: &T,
|
||||
|
@ -1638,7 +1548,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
crate fn suggest_new_overflow_limit(&self, err: &mut DiagnosticBuilder<'_>) {
|
||||
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!(
|
|
@ -4,9 +4,9 @@ use rustc::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 rustc_infer::traits::{TraitEngine, TraitEngineExt as _};
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use super::engine::{TraitEngine, TraitEngineExt};
|
||||
use super::project;
|
||||
use super::select::SelectionContext;
|
||||
use super::wf;
|
||||
|
@ -17,6 +17,9 @@ use super::{ConstEvalFailure, Unimplemented};
|
|||
use super::{FulfillmentError, FulfillmentErrorCode};
|
||||
use super::{ObligationCause, PredicateObligation};
|
||||
|
||||
use crate::traits::error_reporting::InferCtxtExt as _;
|
||||
use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
|
||||
|
||||
impl<'tcx> ForestObligation for PendingPredicateObligation<'tcx> {
|
||||
/// Note that we include both the `ParamEnv` and the `Predicate`,
|
||||
/// as the `ParamEnv` can influence whether fulfillment succeeds
|
|
@ -1,10 +1,13 @@
|
|||
//! Miscellaneous type-system utilities that are too small to deserve their own modules.
|
||||
|
||||
use crate::infer::TyCtxtInferExt;
|
||||
use crate::infer::InferCtxtExt as _;
|
||||
use crate::traits::{self, ObligationCause};
|
||||
|
||||
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
|
||||
use rustc_hir as hir;
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
|
||||
use crate::traits::error_reporting::InferCtxtExt;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum CopyImplementationError<'tcx> {
|
533
src/librustc_trait_selection/traits/mod.rs
Normal file
533
src/librustc_trait_selection/traits/mod.rs
Normal file
|
@ -0,0 +1,533 @@
|
|||
//! Trait Resolution. See the [rustc dev guide] for more information on how this works.
|
||||
//!
|
||||
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/resolution.html
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub mod auto_trait;
|
||||
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;
|
||||
mod structural_match;
|
||||
mod util;
|
||||
pub mod wf;
|
||||
|
||||
use crate::infer::outlives::env::OutlivesEnvironment;
|
||||
use crate::infer::{InferCtxt, SuppressRegionErrors, TyCtxtInferExt};
|
||||
use crate::traits::error_reporting::InferCtxtExt as _;
|
||||
use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
|
||||
use rustc::middle::region;
|
||||
use rustc::ty::fold::TypeFoldable;
|
||||
use rustc::ty::subst::{InternalSubsts, SubstsRef};
|
||||
use rustc::ty::{self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, WithConstness};
|
||||
use rustc::util::common::ErrorReported;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
|
||||
use std::fmt::Debug;
|
||||
|
||||
pub use self::FulfillmentErrorCode::*;
|
||||
pub use self::ObligationCauseCode::*;
|
||||
pub use self::SelectionError::*;
|
||||
pub use self::Vtable::*;
|
||||
|
||||
pub use self::coherence::{add_placeholder_note, orphan_check, overlapping_impls};
|
||||
pub use self::coherence::{OrphanCheckErr, OverlapResult};
|
||||
pub use self::engine::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::MethodViolationCode;
|
||||
pub use self::object_safety::ObjectSafetyViolation;
|
||||
pub use self::on_unimplemented::{OnUnimplementedDirective, OnUnimplementedNote};
|
||||
pub use self::project::{
|
||||
normalize, normalize_projection_type, normalize_to, poly_project_and_unify_type,
|
||||
};
|
||||
pub use self::select::{EvaluationCache, SelectionCache, SelectionContext};
|
||||
pub use self::select::{EvaluationResult, IntercrateAmbiguityCause, OverflowError};
|
||||
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 rustc_infer::traits::*;
|
||||
|
||||
/// 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
|
||||
}
|
||||
}
|
||||
|
||||
/// 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
|
||||
}
|
||||
}
|
||||
|
||||
/// 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,
|
||||
}
|
||||
|
||||
/// 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_or_consts() {
|
||||
// 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
|
||||
}
|
||||
}
|
||||
} 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;
|
||||
}
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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())
|
||||
.in_definition_order()
|
||||
.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;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
Some((def_id, substs))
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn provide(providers: &mut ty::query::Providers<'_>) {
|
||||
object_safety::provide(providers);
|
||||
*providers = ty::query::Providers {
|
||||
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
|
||||
};
|
||||
}
|
|
@ -11,6 +11,7 @@
|
|||
use super::elaborate_predicates;
|
||||
|
||||
use crate::infer::TyCtxtInferExt;
|
||||
use crate::traits::query::evaluate_obligation::InferCtxtExt;
|
||||
use crate::traits::{self, Obligation, ObligationCause};
|
||||
use rustc::ty::subst::{InternalSubsts, Subst};
|
||||
use rustc::ty::{self, Predicate, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
|
1511
src/librustc_trait_selection/traits/project.rs
Normal file
1511
src/librustc_trait_selection/traits/project.rs
Normal file
File diff suppressed because it is too large
Load diff
|
@ -7,7 +7,11 @@ use rustc::ty::{self, Ty, TyCtxt};
|
|||
|
||||
pub use rustc::traits::query::{DropckOutlivesResult, DtorckConstraint};
|
||||
|
||||
impl<'cx, 'tcx> At<'cx, 'tcx> {
|
||||
pub trait AtExt<'tcx> {
|
||||
fn dropck_outlives(&self, ty: Ty<'tcx>) -> InferOk<'tcx, Vec<GenericArg<'tcx>>>;
|
||||
}
|
||||
|
||||
impl<'cx, 'tcx> AtExt<'tcx> for 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
|
||||
|
@ -25,7 +29,7 @@ impl<'cx, 'tcx> At<'cx, 'tcx> {
|
|||
///
|
||||
/// [#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>>> {
|
||||
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
|
|
@ -4,10 +4,35 @@ use crate::traits::{
|
|||
EvaluationResult, OverflowError, PredicateObligation, SelectionContext, TraitQueryMode,
|
||||
};
|
||||
|
||||
impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
|
||||
pub trait InferCtxtExt<'tcx> {
|
||||
fn predicate_may_hold(&self, obligation: &PredicateObligation<'tcx>) -> bool;
|
||||
|
||||
fn predicate_must_hold_considering_regions(
|
||||
&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
) -> bool;
|
||||
|
||||
fn predicate_must_hold_modulo_regions(&self, obligation: &PredicateObligation<'tcx>) -> bool;
|
||||
|
||||
fn evaluate_obligation(
|
||||
&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
) -> Result<EvaluationResult, OverflowError>;
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
impl<'cx, 'tcx> InferCtxtExt<'tcx> for 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 {
|
||||
fn predicate_may_hold(&self, obligation: &PredicateObligation<'tcx>) -> bool {
|
||||
self.evaluate_obligation_no_overflow(obligation).may_apply()
|
||||
}
|
||||
|
||||
|
@ -17,7 +42,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
|
|||
///
|
||||
/// This version may conservatively fail when outlives obligations
|
||||
/// are required.
|
||||
pub fn predicate_must_hold_considering_regions(
|
||||
fn predicate_must_hold_considering_regions(
|
||||
&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
) -> bool {
|
||||
|
@ -29,15 +54,12 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
|
|||
/// 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 {
|
||||
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(
|
||||
fn evaluate_obligation(
|
||||
&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
) -> Result<EvaluationResult, OverflowError> {
|
||||
|
@ -53,7 +75,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
|
|||
// 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(
|
||||
fn evaluate_obligation_no_overflow(
|
||||
&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
) -> EvaluationResult {
|
|
@ -5,17 +5,24 @@
|
|||
use crate::infer::at::At;
|
||||
use crate::infer::canonical::OriginalQueryValues;
|
||||
use crate::infer::{InferCtxt, InferOk};
|
||||
use crate::traits::project::Normalized;
|
||||
use crate::traits::error_reporting::InferCtxtExt;
|
||||
use crate::traits::{Obligation, ObligationCause, PredicateObligation, Reveal};
|
||||
use rustc::ty::fold::{TypeFoldable, TypeFolder};
|
||||
use rustc::ty::subst::Subst;
|
||||
use rustc::ty::{self, Ty, TyCtxt};
|
||||
use rustc_infer::traits::Normalized;
|
||||
|
||||
use super::NoSolution;
|
||||
|
||||
pub use rustc::traits::query::NormalizationResult;
|
||||
|
||||
impl<'cx, 'tcx> At<'cx, 'tcx> {
|
||||
pub trait AtExt<'tcx> {
|
||||
fn normalize<T>(&self, value: &T) -> Result<Normalized<'tcx, T>, NoSolution>
|
||||
where
|
||||
T: TypeFoldable<'tcx>;
|
||||
}
|
||||
|
||||
impl<'cx, 'tcx> AtExt<'tcx> for 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
|
||||
|
@ -29,7 +36,7 @@ impl<'cx, 'tcx> At<'cx, 'tcx> {
|
|||
/// 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>
|
||||
fn normalize<T>(&self, value: &T) -> Result<Normalized<'tcx, T>, NoSolution>
|
||||
where
|
||||
T: TypeFoldable<'tcx>,
|
||||
{
|
|
@ -1,14 +1,25 @@
|
|||
use crate::infer::canonical::OriginalQueryValues;
|
||||
use crate::infer::InferCtxt;
|
||||
use crate::traits::query::NoSolution;
|
||||
use crate::traits::{FulfillmentContext, ObligationCause, TraitEngine, TraitEngineExt};
|
||||
use crate::traits::{FulfillmentContext, ObligationCause, TraitEngine};
|
||||
use rustc::ty::{self, Ty};
|
||||
use rustc_hir as hir;
|
||||
use rustc_infer::traits::TraitEngineExt as _;
|
||||
use rustc_span::source_map::Span;
|
||||
|
||||
pub use rustc::traits::query::OutlivesBound;
|
||||
|
||||
impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
|
||||
pub trait InferCtxtExt<'tcx> {
|
||||
fn implied_outlives_bounds(
|
||||
&self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
body_id: hir::HirId,
|
||||
ty: Ty<'tcx>,
|
||||
span: Span,
|
||||
) -> Vec<OutlivesBound<'tcx>>;
|
||||
}
|
||||
|
||||
impl<'cx, 'tcx> InferCtxtExt<'tcx> for 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
|
||||
|
@ -30,7 +41,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
|
|||
/// - `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(
|
||||
fn implied_outlives_bounds(
|
||||
&self,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
body_id: hir::HirId,
|
||||
|
@ -82,22 +93,3 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
|
|||
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)),
|
||||
})
|
||||
}
|
|
@ -4,7 +4,9 @@ use std::fmt;
|
|||
|
||||
use crate::infer::canonical::query_response;
|
||||
use crate::infer::canonical::QueryRegionConstraints;
|
||||
use crate::traits::{ObligationCause, TraitEngine, TraitEngineExt};
|
||||
use crate::traits::engine::TraitEngineExt as _;
|
||||
use crate::traits::{ObligationCause, TraitEngine};
|
||||
use rustc_infer::traits::TraitEngineExt as _;
|
||||
use rustc_span::source_map::DUMMY_SP;
|
||||
use std::rc::Rc;
|
||||
|
|
@ -9,9 +9,7 @@ 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::project::{normalize_with_depth, normalize_with_depth_to};
|
||||
use super::util;
|
||||
use super::util::{closure_trait_ref_and_return_type, predicate_for_trait_def};
|
||||
use super::wf;
|
||||
|
@ -21,6 +19,7 @@ use super::SelectionResult;
|
|||
use super::TraitNotObjectSafe;
|
||||
use super::TraitQueryMode;
|
||||
use super::{BuiltinDerivedObligation, ImplDerivedObligation, ObligationCauseCode};
|
||||
use super::{Normalized, ProjectionCacheKey};
|
||||
use super::{ObjectCastObligation, Obligation};
|
||||
use super::{ObligationCause, PredicateObligation, TraitObligation};
|
||||
use super::{OutputTypeParameterMismatch, Overflow, SelectionError, Unimplemented};
|
||||
|
@ -34,6 +33,8 @@ use super::{
|
|||
};
|
||||
|
||||
use crate::infer::{CombinedSnapshot, InferCtxt, InferOk, PlaceholderMap, TypeFreshener};
|
||||
use crate::traits::error_reporting::InferCtxtExt;
|
||||
use crate::traits::project::ProjectionCacheKeyExt;
|
||||
use rustc::dep_graph::{DepKind, DepNodeIndex};
|
||||
use rustc::middle::lang_items;
|
||||
use rustc::ty::fast_reject;
|
||||
|
@ -95,47 +96,6 @@ pub struct SelectionContext<'cx, 'tcx> {
|
|||
query_mode: TraitQueryMode,
|
||||
}
|
||||
|
||||
#[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 },
|
||||
}
|
||||
|
||||
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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A stack that walks back up the stack frame.
|
||||
struct TraitObligationStack<'prev, 'tcx> {
|
||||
obligation: &'prev TraitObligation<'tcx>,
|
||||
|
@ -3506,9 +3466,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> TraitObligation<'tcx> {
|
||||
trait TraitObligationExt<'tcx> {
|
||||
fn derived_cause(
|
||||
&self,
|
||||
variant: fn(DerivedObligationCause<'tcx>) -> ObligationCauseCode<'tcx>,
|
||||
) -> ObligationCause<'tcx>;
|
||||
}
|
||||
|
||||
impl<'tcx> TraitObligationExt<'tcx> for TraitObligation<'tcx> {
|
||||
#[allow(unused_comparisons)]
|
||||
pub fn derived_cause(
|
||||
fn derived_cause(
|
||||
&self,
|
||||
variant: fn(DerivedObligationCause<'tcx>) -> ObligationCauseCode<'tcx>,
|
||||
) -> ObligationCause<'tcx> {
|
675
src/librustc_trait_selection/traits/util.rs
Normal file
675
src/librustc_trait_selection/traits/util.rs
Normal file
|
@ -0,0 +1,675 @@
|
|||
use rustc_errors::DiagnosticBuilder;
|
||||
use rustc_span::Span;
|
||||
use smallvec::smallvec;
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use rustc::ty::outlives::Component;
|
||||
use rustc::ty::subst::{GenericArg, Subst, SubstsRef};
|
||||
use rustc::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, 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()).in_definition_order() {
|
||||
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()).in_definition_order() {
|
||||
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,
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
use crate::infer::opaque_types::required_region_bounds;
|
||||
use crate::infer::InferCtxt;
|
||||
use crate::opaque_types::required_region_bounds;
|
||||
use crate::traits::{self, AssocTypeBoundData};
|
||||
use rustc::middle::lang_items;
|
||||
use rustc::ty::subst::SubstsRef;
|
|
@ -19,3 +19,4 @@ rustc_ast = { path = "../librustc_ast" }
|
|||
rustc_span = { path = "../librustc_span" }
|
||||
smallvec = { version = "1.0", features = ["union", "may_dangle"] }
|
||||
rustc_infer = { path = "../librustc_infer" }
|
||||
rustc_trait_selection = { path = "../librustc_trait_selection" }
|
||||
|
|
|
@ -5,11 +5,17 @@ use rustc_data_structures::fx::FxHashSet;
|
|||
use rustc_hir::def_id::DefId;
|
||||
use rustc_infer::infer::canonical::{Canonical, QueryResponse};
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_infer::traits::query::dropck_outlives::trivial_dropck_outlives;
|
||||
use rustc_infer::traits::query::dropck_outlives::{DropckOutlivesResult, DtorckConstraint};
|
||||
use rustc_infer::traits::query::{CanonicalTyGoal, NoSolution};
|
||||
use rustc_infer::traits::{Normalized, ObligationCause, TraitEngine, TraitEngineExt};
|
||||
use rustc_infer::traits::TraitEngineExt as _;
|
||||
use rustc_span::source_map::{Span, DUMMY_SP};
|
||||
use rustc_trait_selection::traits::query::dropck_outlives::trivial_dropck_outlives;
|
||||
use rustc_trait_selection::traits::query::dropck_outlives::{
|
||||
DropckOutlivesResult, DtorckConstraint,
|
||||
};
|
||||
use rustc_trait_selection::traits::query::normalize::AtExt;
|
||||
use rustc_trait_selection::traits::query::{CanonicalTyGoal, NoSolution};
|
||||
use rustc_trait_selection::traits::{
|
||||
Normalized, ObligationCause, TraitEngine, TraitEngineExt as _,
|
||||
};
|
||||
|
||||
crate fn provide(p: &mut Providers<'_>) {
|
||||
*p = Providers { dropck_outlives, adt_dtorck_constraint, ..*p };
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
use rustc::ty::query::Providers;
|
||||
use rustc::ty::{ParamEnvAnd, TyCtxt};
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_infer::traits::query::CanonicalPredicateGoal;
|
||||
use rustc_infer::traits::{
|
||||
use rustc_span::source_map::DUMMY_SP;
|
||||
use rustc_trait_selection::traits::query::CanonicalPredicateGoal;
|
||||
use rustc_trait_selection::traits::{
|
||||
EvaluationResult, Obligation, ObligationCause, OverflowError, SelectionContext, TraitQueryMode,
|
||||
};
|
||||
use rustc_span::source_map::DUMMY_SP;
|
||||
|
||||
crate fn provide(p: &mut Providers<'_>) {
|
||||
*p = Providers { evaluate_obligation, ..*p };
|
||||
|
|
|
@ -7,12 +7,14 @@ use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
|
|||
use rustc_hir as hir;
|
||||
use rustc_infer::infer::canonical::{self, Canonical};
|
||||
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
|
||||
use rustc_infer::traits::query::outlives_bounds::OutlivesBound;
|
||||
use rustc_infer::traits::query::{CanonicalTyGoal, Fallible, NoSolution};
|
||||
use rustc_infer::traits::wf;
|
||||
use rustc_infer::traits::FulfillmentContext;
|
||||
use rustc_infer::traits::{TraitEngine, TraitEngineExt};
|
||||
use rustc_infer::traits::TraitEngineExt as _;
|
||||
use rustc_span::source_map::DUMMY_SP;
|
||||
use rustc_trait_selection::infer::InferCtxtBuilderExt;
|
||||
use rustc_trait_selection::traits::query::outlives_bounds::OutlivesBound;
|
||||
use rustc_trait_selection::traits::query::{CanonicalTyGoal, Fallible, NoSolution};
|
||||
use rustc_trait_selection::traits::wf;
|
||||
use rustc_trait_selection::traits::FulfillmentContext;
|
||||
use rustc_trait_selection::traits::TraitEngine;
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
|
||||
crate fn provide(p: &mut Providers<'_>) {
|
||||
|
|
|
@ -2,7 +2,8 @@ use rustc::traits::query::NoSolution;
|
|||
use rustc::ty::query::Providers;
|
||||
use rustc::ty::{self, ParamEnvAnd, Ty, TyCtxt};
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_infer::traits::{Normalized, ObligationCause};
|
||||
use rustc_trait_selection::traits::query::normalize::AtExt;
|
||||
use rustc_trait_selection::traits::{Normalized, ObligationCause};
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
crate fn provide(p: &mut Providers<'_>) {
|
||||
|
|
|
@ -3,11 +3,13 @@ use rustc::ty::{ParamEnvAnd, TyCtxt};
|
|||
use rustc_hir as hir;
|
||||
use rustc_infer::infer::canonical::{Canonical, QueryResponse};
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_infer::traits::query::{
|
||||
use rustc_infer::traits::TraitEngineExt as _;
|
||||
use rustc_span::DUMMY_SP;
|
||||
use rustc_trait_selection::infer::InferCtxtBuilderExt;
|
||||
use rustc_trait_selection::traits::query::{
|
||||
normalize::NormalizationResult, CanonicalProjectionGoal, NoSolution,
|
||||
};
|
||||
use rustc_infer::traits::{self, ObligationCause, SelectionContext, TraitEngineExt};
|
||||
use rustc_span::DUMMY_SP;
|
||||
use rustc_trait_selection::traits::{self, ObligationCause, SelectionContext};
|
||||
use std::sync::atomic::Ordering;
|
||||
|
||||
crate fn provide(p: &mut Providers<'_>) {
|
||||
|
|
|
@ -8,14 +8,18 @@ use rustc_hir::def_id::DefId;
|
|||
use rustc_infer::infer::at::ToTrace;
|
||||
use rustc_infer::infer::canonical::{Canonical, QueryResponse};
|
||||
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
|
||||
use rustc_infer::traits::query::type_op::ascribe_user_type::AscribeUserType;
|
||||
use rustc_infer::traits::query::type_op::eq::Eq;
|
||||
use rustc_infer::traits::query::type_op::normalize::Normalize;
|
||||
use rustc_infer::traits::query::type_op::prove_predicate::ProvePredicate;
|
||||
use rustc_infer::traits::query::type_op::subtype::Subtype;
|
||||
use rustc_infer::traits::query::{Fallible, NoSolution};
|
||||
use rustc_infer::traits::{Normalized, Obligation, ObligationCause, TraitEngine, TraitEngineExt};
|
||||
use rustc_infer::traits::TraitEngineExt as _;
|
||||
use rustc_span::DUMMY_SP;
|
||||
use rustc_trait_selection::infer::InferCtxtBuilderExt;
|
||||
use rustc_trait_selection::infer::InferCtxtExt;
|
||||
use rustc_trait_selection::traits::query::normalize::AtExt;
|
||||
use rustc_trait_selection::traits::query::type_op::ascribe_user_type::AscribeUserType;
|
||||
use rustc_trait_selection::traits::query::type_op::eq::Eq;
|
||||
use rustc_trait_selection::traits::query::type_op::normalize::Normalize;
|
||||
use rustc_trait_selection::traits::query::type_op::prove_predicate::ProvePredicate;
|
||||
use rustc_trait_selection::traits::query::type_op::subtype::Subtype;
|
||||
use rustc_trait_selection::traits::query::{Fallible, NoSolution};
|
||||
use rustc_trait_selection::traits::{Normalized, Obligation, ObligationCause, TraitEngine};
|
||||
use std::fmt;
|
||||
|
||||
crate fn provide(p: &mut Providers<'_>) {
|
||||
|
|
|
@ -16,3 +16,4 @@ rustc_hir = { path = "../librustc_hir" }
|
|||
rustc_infer = { path = "../librustc_infer" }
|
||||
rustc_span = { path = "../librustc_span" }
|
||||
rustc_target = { path = "../librustc_target" }
|
||||
rustc_trait_selection = { path = "../librustc_trait_selection" }
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
use rustc::middle::lang_items;
|
||||
use rustc::ty::{self, Ty, TyCtxt};
|
||||
use rustc_infer::infer::TyCtxtInferExt;
|
||||
use rustc_infer::traits;
|
||||
use rustc_span::DUMMY_SP;
|
||||
use rustc_trait_selection::traits;
|
||||
|
||||
fn is_copy_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
|
||||
is_item_raw(tcx, query, lang_items::CopyTraitLangItem)
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use rustc::ty::subst::SubstsRef;
|
||||
use rustc::ty::{self, Instance, TyCtxt, TypeFoldable};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_infer::traits;
|
||||
use rustc_target::spec::abi::Abi;
|
||||
use rustc_trait_selection::traits;
|
||||
|
||||
use log::debug;
|
||||
|
||||
|
|
|
@ -5,9 +5,9 @@ use rustc::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness};
|
|||
use rustc_data_structures::svh::Svh;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
|
||||
use rustc_infer::traits;
|
||||
use rustc_span::symbol::Symbol;
|
||||
use rustc_span::Span;
|
||||
use rustc_trait_selection::traits;
|
||||
|
||||
fn sized_constraint_for_ty<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
|
|
|
@ -24,3 +24,4 @@ rustc_ast = { path = "../librustc_ast" }
|
|||
rustc_span = { path = "../librustc_span" }
|
||||
rustc_index = { path = "../librustc_index" }
|
||||
rustc_infer = { path = "../librustc_infer" }
|
||||
rustc_trait_selection = { path = "../librustc_trait_selection" }
|
||||
|
|
|
@ -26,13 +26,13 @@ use rustc_hir::def_id::DefId;
|
|||
use rustc_hir::intravisit::Visitor;
|
||||
use rustc_hir::print;
|
||||
use rustc_hir::{Constness, ExprKind, GenericArg, GenericArgs};
|
||||
use rustc_infer::traits;
|
||||
use rustc_infer::traits::astconv_object_safety_violations;
|
||||
use rustc_infer::traits::error_reporting::report_object_safety_error;
|
||||
use rustc_infer::traits::wf::object_region_bounds;
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::{MultiSpan, Span, DUMMY_SP};
|
||||
use rustc_target::spec::abi;
|
||||
use rustc_trait_selection::traits;
|
||||
use rustc_trait_selection::traits::astconv_object_safety_violations;
|
||||
use rustc_trait_selection::traits::error_reporting::report_object_safety_error;
|
||||
use rustc_trait_selection::traits::wf::object_region_bounds;
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use std::collections::BTreeSet;
|
||||
|
|
|
@ -4,9 +4,9 @@ use rustc::ty::Ty;
|
|||
use rustc_hir as hir;
|
||||
use rustc_hir::ExprKind;
|
||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use rustc_infer::traits::ObligationCauseCode;
|
||||
use rustc_infer::traits::{IfExpressionCause, MatchExpressionArmCause, ObligationCause};
|
||||
use rustc_span::Span;
|
||||
use rustc_trait_selection::traits::ObligationCauseCode;
|
||||
use rustc_trait_selection::traits::{IfExpressionCause, MatchExpressionArmCause, ObligationCause};
|
||||
|
||||
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
pub fn check_match(
|
||||
|
|
|
@ -8,7 +8,8 @@ use rustc::ty::{ToPredicate, TypeFoldable};
|
|||
use rustc_errors::struct_span_err;
|
||||
use rustc_hir as hir;
|
||||
use rustc_infer::infer::{InferCtxt, InferOk};
|
||||
use rustc_infer::traits::{self, TraitEngine};
|
||||
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
|
||||
use rustc_trait_selection::traits::{self, TraitEngine};
|
||||
|
||||
use rustc_ast::ast::Ident;
|
||||
use rustc_span::Span;
|
||||
|
|
|
@ -44,9 +44,9 @@ use rustc::ty::{self, Ty, TypeAndMut, TypeFoldable};
|
|||
use rustc_ast::ast;
|
||||
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
|
||||
use rustc_hir as hir;
|
||||
use rustc_infer::traits;
|
||||
use rustc_infer::traits::error_reporting::report_object_safety_error;
|
||||
use rustc_span::Span;
|
||||
use rustc_trait_selection::traits;
|
||||
use rustc_trait_selection::traits::error_reporting::report_object_safety_error;
|
||||
|
||||
/// Reifies a cast check to be checked once we have full type information for
|
||||
/// a function context.
|
||||
|
|
|
@ -12,10 +12,11 @@ use rustc_hir::def_id::DefId;
|
|||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use rustc_infer::infer::LateBoundRegionConversionTime;
|
||||
use rustc_infer::infer::{InferOk, InferResult};
|
||||
use rustc_infer::traits::error_reporting::ArgKind;
|
||||
use rustc_infer::traits::Obligation;
|
||||
use rustc_span::source_map::Span;
|
||||
use rustc_target::spec::abi::Abi;
|
||||
use rustc_trait_selection::traits::error_reporting::ArgKind;
|
||||
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
|
||||
use rustc_trait_selection::traits::Obligation;
|
||||
use std::cmp;
|
||||
use std::iter;
|
||||
|
||||
|
|
|
@ -66,10 +66,11 @@ use rustc_hir as hir;
|
|||
use rustc_hir::def_id::DefId;
|
||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use rustc_infer::infer::{Coercion, InferOk, InferResult};
|
||||
use rustc_infer::traits::{self, ObligationCause, ObligationCauseCode};
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::{self, Span};
|
||||
use rustc_target::spec::abi::Abi;
|
||||
use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
|
||||
use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode};
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
use std::ops::Deref;
|
||||
|
||||
|
|
|
@ -10,8 +10,9 @@ use rustc_hir::def::{DefKind, Res};
|
|||
use rustc_hir::intravisit;
|
||||
use rustc_hir::{GenericParamKind, ImplItemKind, TraitItemKind};
|
||||
use rustc_infer::infer::{self, InferOk, TyCtxtInferExt};
|
||||
use rustc_infer::traits::{self, ObligationCause, ObligationCauseCode, Reveal};
|
||||
use rustc_span::Span;
|
||||
use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
|
||||
use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode, Reveal};
|
||||
|
||||
use super::{potentially_plural_count, FnCtxt, Inherited};
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
use crate::check::FnCtxt;
|
||||
use rustc_infer::infer::InferOk;
|
||||
use rustc_infer::traits::{self, ObligationCause};
|
||||
use rustc_trait_selection::infer::InferCtxtExt as _;
|
||||
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
|
||||
use rustc_trait_selection::traits::{self, ObligationCause};
|
||||
|
||||
use rustc::ty::adjustment::AllowTwoPhase;
|
||||
use rustc::ty::{self, AssocItem, Ty};
|
||||
|
|
|
@ -10,8 +10,11 @@ use rustc::ty::{self, Predicate, Ty, TyCtxt};
|
|||
use rustc_errors::struct_span_err;
|
||||
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
|
||||
use rustc_infer::infer::{InferOk, SuppressRegionErrors, TyCtxtInferExt};
|
||||
use rustc_infer::traits::{ObligationCause, TraitEngine, TraitEngineExt};
|
||||
use rustc_infer::traits::TraitEngineExt as _;
|
||||
use rustc_span::Span;
|
||||
use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
|
||||
use rustc_trait_selection::traits::query::dropck_outlives::AtExt;
|
||||
use rustc_trait_selection::traits::{ObligationCause, TraitEngine, TraitEngineExt};
|
||||
|
||||
/// This function confirms that the `Drop` implementation identified by
|
||||
/// `drop_impl_did` is not any more specialized than the type it is
|
||||
|
|
|
@ -34,10 +34,10 @@ use rustc_hir::def_id::DefId;
|
|||
use rustc_hir::{ExprKind, QPath};
|
||||
use rustc_infer::infer;
|
||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use rustc_infer::traits::{self, ObligationCauseCode};
|
||||
use rustc_span::hygiene::DesugaringKind;
|
||||
use rustc_span::source_map::Span;
|
||||
use rustc_span::symbol::{kw, sym, Symbol};
|
||||
use rustc_trait_selection::traits::{self, ObligationCauseCode};
|
||||
|
||||
use std::fmt::Display;
|
||||
|
||||
|
|
|
@ -11,8 +11,8 @@ use rustc::ty::subst::{Subst, SubstsRef};
|
|||
use rustc::ty::{self, GenericParamDefKind, Ty};
|
||||
use rustc_hir as hir;
|
||||
use rustc_infer::infer::{self, InferOk};
|
||||
use rustc_infer::traits;
|
||||
use rustc_span::Span;
|
||||
use rustc_trait_selection::traits;
|
||||
|
||||
use std::ops::Deref;
|
||||
|
||||
|
|
|
@ -22,8 +22,9 @@ use rustc_hir as hir;
|
|||
use rustc_hir::def::{CtorOf, DefKind, Namespace};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_infer::infer::{self, InferOk};
|
||||
use rustc_infer::traits;
|
||||
use rustc_span::Span;
|
||||
use rustc_trait_selection::traits;
|
||||
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
|
||||
|
||||
use self::probe::{IsSuggestion, ProbeScope};
|
||||
|
||||
|
|
|
@ -28,11 +28,14 @@ use rustc_infer::infer::canonical::{Canonical, QueryResponse};
|
|||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use rustc_infer::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
|
||||
use rustc_infer::infer::{self, InferOk, TyCtxtInferExt};
|
||||
use rustc_infer::traits::query::method_autoderef::MethodAutoderefBadTy;
|
||||
use rustc_infer::traits::query::method_autoderef::{CandidateStep, MethodAutoderefStepsResult};
|
||||
use rustc_infer::traits::query::CanonicalTyGoal;
|
||||
use rustc_infer::traits::{self, ObligationCause};
|
||||
use rustc_span::{symbol::Symbol, Span, DUMMY_SP};
|
||||
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
|
||||
use rustc_trait_selection::traits::query::method_autoderef::MethodAutoderefBadTy;
|
||||
use rustc_trait_selection::traits::query::method_autoderef::{
|
||||
CandidateStep, MethodAutoderefStepsResult,
|
||||
};
|
||||
use rustc_trait_selection::traits::query::CanonicalTyGoal;
|
||||
use rustc_trait_selection::traits::{self, ObligationCause};
|
||||
use std::cmp::max;
|
||||
use std::iter;
|
||||
use std::mem;
|
||||
|
|
|
@ -17,9 +17,10 @@ use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
|
|||
use rustc_hir::intravisit;
|
||||
use rustc_hir::{ExprKind, Node, QPath};
|
||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use rustc_infer::traits::Obligation;
|
||||
use rustc_span::symbol::kw;
|
||||
use rustc_span::{source_map, FileName, Span};
|
||||
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
|
||||
use rustc_trait_selection::traits::Obligation;
|
||||
|
||||
use std::cmp::Ordering;
|
||||
|
||||
|
|
|
@ -121,17 +121,22 @@ use rustc_hir::{ExprKind, GenericArg, HirIdMap, Item, ItemKind, Node, PatKind, Q
|
|||
use rustc_index::vec::Idx;
|
||||
use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse};
|
||||
use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282;
|
||||
use rustc_infer::infer::opaque_types::OpaqueTypeDecl;
|
||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use rustc_infer::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
|
||||
use rustc_infer::infer::{self, InferCtxt, InferOk, InferResult, TyCtxtInferExt};
|
||||
use rustc_infer::traits::error_reporting::recursive_type_with_infinite_size_error;
|
||||
use rustc_infer::traits::{self, ObligationCause, ObligationCauseCode, TraitEngine};
|
||||
use rustc_span::hygiene::DesugaringKind;
|
||||
use rustc_span::source_map::{original_sp, DUMMY_SP};
|
||||
use rustc_span::symbol::{kw, sym, Ident};
|
||||
use rustc_span::{self, BytePos, MultiSpan, Span};
|
||||
use rustc_target::spec::abi::Abi;
|
||||
use rustc_trait_selection::infer::InferCtxtExt as _;
|
||||
use rustc_trait_selection::opaque_types::{InferCtxtExt as _, OpaqueTypeDecl};
|
||||
use rustc_trait_selection::traits::error_reporting::recursive_type_with_infinite_size_error;
|
||||
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
|
||||
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
|
||||
use rustc_trait_selection::traits::{
|
||||
self, ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt,
|
||||
};
|
||||
|
||||
use std::cell::{Cell, Ref, RefCell, RefMut};
|
||||
use std::cmp;
|
||||
|
|
|
@ -10,6 +10,7 @@ use rustc_errors::{self, struct_span_err, Applicability, DiagnosticBuilder};
|
|||
use rustc_hir as hir;
|
||||
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||
use rustc_span::Span;
|
||||
use rustc_trait_selection::infer::InferCtxtExt;
|
||||
|
||||
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
/// Checks a `a <op>= b`
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue