Split librustc_infer.
This commit is contained in:
parent
c1e3d556bf
commit
0535dd3721
32 changed files with 1846 additions and 1065 deletions
|
@ -4129,11 +4129,13 @@ name = "rustc_trait_selection"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fmt_macros",
|
"fmt_macros",
|
||||||
|
"graphviz",
|
||||||
"log",
|
"log",
|
||||||
"rustc",
|
"rustc",
|
||||||
"rustc_ast",
|
"rustc_ast",
|
||||||
"rustc_attr",
|
"rustc_attr",
|
||||||
"rustc_data_structures",
|
"rustc_data_structures",
|
||||||
|
"rustc_error_codes",
|
||||||
"rustc_errors",
|
"rustc_errors",
|
||||||
"rustc_hir",
|
"rustc_hir",
|
||||||
"rustc_index",
|
"rustc_index",
|
||||||
|
|
|
@ -14,7 +14,7 @@ use crate::infer::canonical::{
|
||||||
};
|
};
|
||||||
use crate::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelatingDelegate};
|
use crate::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelatingDelegate};
|
||||||
use crate::infer::region_constraints::{Constraint, RegionConstraintData};
|
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::query::{Fallible, NoSolution};
|
||||||
use crate::traits::{DomainGoal, TraitEngine};
|
use crate::traits::{DomainGoal, TraitEngine};
|
||||||
use crate::traits::{Obligation, ObligationCause, PredicateObligation};
|
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_data_structures::captures::Captures;
|
||||||
use rustc_index::vec::Idx;
|
use rustc_index::vec::Idx;
|
||||||
use rustc_index::vec::IndexVec;
|
use rustc_index::vec::IndexVec;
|
||||||
use rustc_span::DUMMY_SP;
|
|
||||||
use std::fmt::Debug;
|
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> {
|
impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
|
||||||
/// This method is meant to be invoked as the final step of a canonical query
|
/// This method is meant to be invoked as the final step of a canonical query
|
||||||
/// implementation. It is given:
|
/// implementation. It is given:
|
||||||
|
|
|
@ -2156,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
|
/// 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.
|
/// extra information about each type, but we only care about the category.
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
crate enum TyCategory {
|
pub enum TyCategory {
|
||||||
Closure,
|
Closure,
|
||||||
Opaque,
|
Opaque,
|
||||||
Generator,
|
Generator,
|
||||||
|
|
|
@ -13,11 +13,11 @@ use rustc::infer::canonical::{Canonical, CanonicalVarValues};
|
||||||
use rustc::infer::unify_key::{ConstVarValue, ConstVariableValue};
|
use rustc::infer::unify_key::{ConstVarValue, ConstVariableValue};
|
||||||
use rustc::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType};
|
use rustc::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType};
|
||||||
use rustc::middle::free_region::RegionRelations;
|
use rustc::middle::free_region::RegionRelations;
|
||||||
use rustc::middle::lang_items;
|
|
||||||
use rustc::middle::region;
|
use rustc::middle::region;
|
||||||
use rustc::mir;
|
use rustc::mir;
|
||||||
use rustc::mir::interpret::ConstEvalResult;
|
use rustc::mir::interpret::ConstEvalResult;
|
||||||
use rustc::session::config::BorrowckMode;
|
use rustc::session::config::BorrowckMode;
|
||||||
|
use rustc::traits::select;
|
||||||
use rustc::ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric};
|
use rustc::ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric};
|
||||||
use rustc::ty::fold::{TypeFoldable, TypeFolder};
|
use rustc::ty::fold::{TypeFoldable, TypeFolder};
|
||||||
use rustc::ty::relate::RelateResult;
|
use rustc::ty::relate::RelateResult;
|
||||||
|
@ -58,7 +58,6 @@ pub mod lattice;
|
||||||
mod lexical_region_resolve;
|
mod lexical_region_resolve;
|
||||||
mod lub;
|
mod lub;
|
||||||
pub mod nll_relate;
|
pub mod nll_relate;
|
||||||
pub mod opaque_types;
|
|
||||||
pub mod outlives;
|
pub mod outlives;
|
||||||
pub mod region_constraints;
|
pub mod region_constraints;
|
||||||
pub mod resolve;
|
pub mod resolve;
|
||||||
|
@ -215,10 +214,10 @@ pub struct InferCtxt<'a, 'tcx> {
|
||||||
|
|
||||||
/// Caches the results of trait selection. This cache is used
|
/// Caches the results of trait selection. This cache is used
|
||||||
/// for things that have to do with the parameters in scope.
|
/// 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.
|
/// 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
|
/// the set of predicates on which errors have been reported, to
|
||||||
/// avoid reporting the same error twice.
|
/// avoid reporting the same error twice.
|
||||||
|
@ -1474,27 +1473,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
.verify_generic_bound(origin, kind, a, bound);
|
.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
|
/// Obtains the latest type of the given closure; this may be a
|
||||||
/// closure in the current function, in which case its
|
/// closure in the current function, in which case its
|
||||||
/// `ClosureKind` may not yet be known.
|
/// `ClosureKind` may not yet be known.
|
||||||
|
@ -1518,30 +1496,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
closure_sig_ty.fn_sig(self.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
|
/// Clears the selection, evaluation, and projection caches. This is useful when
|
||||||
/// repeatedly attempting to select an `Obligation` while changing only
|
/// repeatedly attempting to select an `Obligation` while changing only
|
||||||
/// its `ParamEnv`, since `FulfillmentContext` doesn't use probing.
|
/// its `ParamEnv`, since `FulfillmentContext` doesn't use probing.
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
use crate::infer::{GenericKind, InferCtxt};
|
use crate::infer::{GenericKind, InferCtxt};
|
||||||
use crate::traits::query::OutlivesBound;
|
use crate::traits::query::OutlivesBound;
|
||||||
|
use rustc::ty;
|
||||||
use rustc::ty::free_region_map::FreeRegionMap;
|
use rustc::ty::free_region_map::FreeRegionMap;
|
||||||
use rustc::ty::{self, Ty};
|
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_span::Span;
|
|
||||||
|
|
||||||
use super::explicit_outlives_bounds;
|
use super::explicit_outlives_bounds;
|
||||||
|
|
||||||
|
@ -144,39 +143,6 @@ impl<'a, 'tcx> OutlivesEnvironment<'tcx> {
|
||||||
self.region_bound_pairs_accum.truncate(len);
|
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`.
|
/// Save the current set of region-bound pairs under the given `body_id`.
|
||||||
pub fn save_implied_bounds(&mut self, body_id: hir::HirId) {
|
pub fn save_implied_bounds(&mut self, body_id: hir::HirId) {
|
||||||
let old =
|
let old =
|
||||||
|
@ -190,8 +156,11 @@ impl<'a, 'tcx> OutlivesEnvironment<'tcx> {
|
||||||
/// contain inference variables, it must be supplied, in which
|
/// contain inference variables, it must be supplied, in which
|
||||||
/// case we will register "givens" on the inference context. (See
|
/// case we will register "givens" on the inference context. (See
|
||||||
/// `RegionConstraintData`.)
|
/// `RegionConstraintData`.)
|
||||||
fn add_outlives_bounds<I>(&mut self, infcx: Option<&InferCtxt<'a, 'tcx>>, outlives_bounds: I)
|
pub fn add_outlives_bounds<I>(
|
||||||
where
|
&mut self,
|
||||||
|
infcx: Option<&InferCtxt<'a, 'tcx>>,
|
||||||
|
outlives_bounds: I,
|
||||||
|
) where
|
||||||
I: IntoIterator<Item = OutlivesBound<'tcx>>,
|
I: IntoIterator<Item = OutlivesBound<'tcx>>,
|
||||||
{
|
{
|
||||||
// Record relationships such as `T:'x` that don't go into the
|
// Record relationships such as `T:'x` that don't go into the
|
||||||
|
|
78
src/librustc_infer/traits/engine.rs
Normal file
78
src/librustc_infer/traits/engine.rs
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
use crate::infer::InferCtxt;
|
||||||
|
use crate::traits::Obligation;
|
||||||
|
use rustc::ty::{self, ToPredicate, Ty, WithConstness};
|
||||||
|
use rustc_hir::def_id::DefId;
|
||||||
|
|
||||||
|
use super::FulfillmentError;
|
||||||
|
use super::{ObligationCause, PredicateObligation};
|
||||||
|
|
||||||
|
pub trait TraitEngine<'tcx>: 'tcx {
|
||||||
|
fn normalize_projection_type(
|
||||||
|
&mut self,
|
||||||
|
infcx: &InferCtxt<'_, 'tcx>,
|
||||||
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
|
projection_ty: ty::ProjectionTy<'tcx>,
|
||||||
|
cause: ObligationCause<'tcx>,
|
||||||
|
) -> Ty<'tcx>;
|
||||||
|
|
||||||
|
/// Requires that `ty` must implement the trait with `def_id` in
|
||||||
|
/// the given environment. This trait must not have any type
|
||||||
|
/// parameters (except for `Self`).
|
||||||
|
fn register_bound(
|
||||||
|
&mut self,
|
||||||
|
infcx: &InferCtxt<'_, 'tcx>,
|
||||||
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
|
ty: Ty<'tcx>,
|
||||||
|
def_id: DefId,
|
||||||
|
cause: ObligationCause<'tcx>,
|
||||||
|
) {
|
||||||
|
let trait_ref = ty::TraitRef { def_id, substs: infcx.tcx.mk_substs_trait(ty, &[]) };
|
||||||
|
self.register_predicate_obligation(
|
||||||
|
infcx,
|
||||||
|
Obligation {
|
||||||
|
cause,
|
||||||
|
recursion_depth: 0,
|
||||||
|
param_env,
|
||||||
|
predicate: trait_ref.without_const().to_predicate(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn register_predicate_obligation(
|
||||||
|
&mut self,
|
||||||
|
infcx: &InferCtxt<'_, 'tcx>,
|
||||||
|
obligation: PredicateObligation<'tcx>,
|
||||||
|
);
|
||||||
|
|
||||||
|
fn select_all_or_error(
|
||||||
|
&mut self,
|
||||||
|
infcx: &InferCtxt<'_, 'tcx>,
|
||||||
|
) -> Result<(), Vec<FulfillmentError<'tcx>>>;
|
||||||
|
|
||||||
|
fn select_where_possible(
|
||||||
|
&mut self,
|
||||||
|
infcx: &InferCtxt<'_, 'tcx>,
|
||||||
|
) -> Result<(), Vec<FulfillmentError<'tcx>>>;
|
||||||
|
|
||||||
|
fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait TraitEngineExt<'tcx> {
|
||||||
|
fn register_predicate_obligations(
|
||||||
|
&mut self,
|
||||||
|
infcx: &InferCtxt<'_, 'tcx>,
|
||||||
|
obligations: impl IntoIterator<Item = PredicateObligation<'tcx>>,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: ?Sized + TraitEngine<'tcx>> TraitEngineExt<'tcx> for T {
|
||||||
|
fn register_predicate_obligations(
|
||||||
|
&mut self,
|
||||||
|
infcx: &InferCtxt<'_, 'tcx>,
|
||||||
|
obligations: impl IntoIterator<Item = PredicateObligation<'tcx>>,
|
||||||
|
) {
|
||||||
|
for obligation in obligations {
|
||||||
|
self.register_predicate_obligation(infcx, obligation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
106
src/librustc_infer/traits/error_reporting/mod.rs
Normal file
106
src/librustc_infer/traits/error_reporting/mod.rs
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
use super::ObjectSafetyViolation;
|
||||||
|
|
||||||
|
use crate::infer::InferCtxt;
|
||||||
|
use rustc::ty::TyCtxt;
|
||||||
|
use rustc_ast::ast;
|
||||||
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
|
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
|
||||||
|
use rustc_hir as hir;
|
||||||
|
use rustc_hir::def_id::DefId;
|
||||||
|
use rustc_span::Span;
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
|
pub fn report_extra_impl_obligation(
|
||||||
|
&self,
|
||||||
|
error_span: Span,
|
||||||
|
item_name: ast::Name,
|
||||||
|
_impl_item_def_id: DefId,
|
||||||
|
trait_item_def_id: DefId,
|
||||||
|
requirement: &dyn fmt::Display,
|
||||||
|
) -> DiagnosticBuilder<'tcx> {
|
||||||
|
let msg = "impl has stricter requirements than trait";
|
||||||
|
let sp = self.tcx.sess.source_map().def_span(error_span);
|
||||||
|
|
||||||
|
let mut err = struct_span_err!(self.tcx.sess, sp, E0276, "{}", msg);
|
||||||
|
|
||||||
|
if let Some(trait_item_span) = self.tcx.hir().span_if_local(trait_item_def_id) {
|
||||||
|
let span = self.tcx.sess.source_map().def_span(trait_item_span);
|
||||||
|
err.span_label(span, format!("definition of `{}` from trait", item_name));
|
||||||
|
}
|
||||||
|
|
||||||
|
err.span_label(sp, format!("impl has extra requirement {}", requirement));
|
||||||
|
|
||||||
|
err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn report_object_safety_error(
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
span: Span,
|
||||||
|
trait_def_id: DefId,
|
||||||
|
violations: Vec<ObjectSafetyViolation>,
|
||||||
|
) -> DiagnosticBuilder<'tcx> {
|
||||||
|
let trait_str = tcx.def_path_str(trait_def_id);
|
||||||
|
let trait_span = tcx.hir().get_if_local(trait_def_id).and_then(|node| match node {
|
||||||
|
hir::Node::Item(item) => Some(item.ident.span),
|
||||||
|
_ => None,
|
||||||
|
});
|
||||||
|
let span = tcx.sess.source_map().def_span(span);
|
||||||
|
let mut err = struct_span_err!(
|
||||||
|
tcx.sess,
|
||||||
|
span,
|
||||||
|
E0038,
|
||||||
|
"the trait `{}` cannot be made into an object",
|
||||||
|
trait_str
|
||||||
|
);
|
||||||
|
err.span_label(span, format!("the trait `{}` cannot be made into an object", trait_str));
|
||||||
|
|
||||||
|
let mut reported_violations = FxHashSet::default();
|
||||||
|
let mut had_span_label = false;
|
||||||
|
for violation in violations {
|
||||||
|
if let ObjectSafetyViolation::SizedSelf(sp) = &violation {
|
||||||
|
if !sp.is_empty() {
|
||||||
|
// Do not report `SizedSelf` without spans pointing at `SizedSelf` obligations
|
||||||
|
// with a `Span`.
|
||||||
|
reported_violations.insert(ObjectSafetyViolation::SizedSelf(vec![].into()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if reported_violations.insert(violation.clone()) {
|
||||||
|
let spans = violation.spans();
|
||||||
|
let msg = if trait_span.is_none() || spans.is_empty() {
|
||||||
|
format!("the trait cannot be made into an object because {}", violation.error_msg())
|
||||||
|
} else {
|
||||||
|
had_span_label = true;
|
||||||
|
format!("...because {}", violation.error_msg())
|
||||||
|
};
|
||||||
|
if spans.is_empty() {
|
||||||
|
err.note(&msg);
|
||||||
|
} else {
|
||||||
|
for span in spans {
|
||||||
|
err.span_label(span, &msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
match (trait_span, violation.solution()) {
|
||||||
|
(Some(_), Some((note, None))) => {
|
||||||
|
err.help(¬e);
|
||||||
|
}
|
||||||
|
(Some(_), Some((note, Some((sugg, span))))) => {
|
||||||
|
err.span_suggestion(span, ¬e, sugg, Applicability::MachineApplicable);
|
||||||
|
}
|
||||||
|
// Only provide the help if its a local trait, otherwise it's not actionable.
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let (Some(trait_span), true) = (trait_span, had_span_label) {
|
||||||
|
err.span_label(trait_span, "this trait cannot be made into an object...");
|
||||||
|
}
|
||||||
|
|
||||||
|
if tcx.sess.trait_methods_not_found.borrow().contains(&span) {
|
||||||
|
// Avoid emitting error caused by non-existing method (#58734)
|
||||||
|
err.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
err
|
||||||
|
}
|
136
src/librustc_infer/traits/mod.rs
Normal file
136
src/librustc_infer/traits/mod.rs
Normal file
|
@ -0,0 +1,136 @@
|
||||||
|
//! Trait Resolution. See the [rustc guide] for more information on how this works.
|
||||||
|
//!
|
||||||
|
//! [rustc guide]: https://rust-lang.github.io/rustc-guide/traits/resolution.html
|
||||||
|
|
||||||
|
mod engine;
|
||||||
|
pub mod error_reporting;
|
||||||
|
mod project;
|
||||||
|
mod structural_impls;
|
||||||
|
mod util;
|
||||||
|
|
||||||
|
use rustc::ty::error::{ExpectedFound, TypeError};
|
||||||
|
use rustc::ty::{self, Ty};
|
||||||
|
use rustc_hir as hir;
|
||||||
|
use rustc_span::Span;
|
||||||
|
|
||||||
|
pub use self::FulfillmentErrorCode::*;
|
||||||
|
pub use self::ObligationCauseCode::*;
|
||||||
|
pub use self::SelectionError::*;
|
||||||
|
pub use self::Vtable::*;
|
||||||
|
|
||||||
|
pub use self::engine::{TraitEngine, TraitEngineExt};
|
||||||
|
pub use self::project::MismatchedProjectionTypes;
|
||||||
|
pub use self::project::{
|
||||||
|
Normalized, NormalizedTy, ProjectionCache, ProjectionCacheEntry, ProjectionCacheKey,
|
||||||
|
ProjectionCacheSnapshot, Reveal,
|
||||||
|
};
|
||||||
|
crate use self::util::elaborate_predicates;
|
||||||
|
|
||||||
|
pub use rustc::traits::*;
|
||||||
|
|
||||||
|
/// An `Obligation` represents some trait reference (e.g., `int: Eq`) for
|
||||||
|
/// which the vtable must be found. The process of finding a vtable is
|
||||||
|
/// called "resolving" the `Obligation`. This process consists of
|
||||||
|
/// either identifying an `impl` (e.g., `impl Eq for int`) that
|
||||||
|
/// provides the required vtable, or else finding a bound that is in
|
||||||
|
/// scope. The eventual result is usually a `Selection` (defined below).
|
||||||
|
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct Obligation<'tcx, T> {
|
||||||
|
/// The reason we have to prove this thing.
|
||||||
|
pub cause: ObligationCause<'tcx>,
|
||||||
|
|
||||||
|
/// The environment in which we should prove this thing.
|
||||||
|
pub param_env: ty::ParamEnv<'tcx>,
|
||||||
|
|
||||||
|
/// The thing we are trying to prove.
|
||||||
|
pub predicate: T,
|
||||||
|
|
||||||
|
/// If we started proving this as a result of trying to prove
|
||||||
|
/// something else, track the total depth to ensure termination.
|
||||||
|
/// If this goes over a certain threshold, we abort compilation --
|
||||||
|
/// in such cases, we can not say whether or not the predicate
|
||||||
|
/// holds for certain. Stupid halting problem; such a drag.
|
||||||
|
pub recursion_depth: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type PredicateObligation<'tcx> = Obligation<'tcx, ty::Predicate<'tcx>>;
|
||||||
|
pub type TraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitPredicate<'tcx>>;
|
||||||
|
|
||||||
|
// `PredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger.
|
||||||
|
#[cfg(target_arch = "x86_64")]
|
||||||
|
static_assert_size!(PredicateObligation<'_>, 112);
|
||||||
|
|
||||||
|
pub type Obligations<'tcx, O> = Vec<Obligation<'tcx, O>>;
|
||||||
|
pub type PredicateObligations<'tcx> = Vec<PredicateObligation<'tcx>>;
|
||||||
|
pub type TraitObligations<'tcx> = Vec<TraitObligation<'tcx>>;
|
||||||
|
|
||||||
|
pub type Selection<'tcx> = Vtable<'tcx, PredicateObligation<'tcx>>;
|
||||||
|
|
||||||
|
pub struct FulfillmentError<'tcx> {
|
||||||
|
pub obligation: PredicateObligation<'tcx>,
|
||||||
|
pub code: FulfillmentErrorCode<'tcx>,
|
||||||
|
/// Diagnostics only: we opportunistically change the `code.span` when we encounter an
|
||||||
|
/// obligation error caused by a call argument. When this is the case, we also signal that in
|
||||||
|
/// this field to ensure accuracy of suggestions.
|
||||||
|
pub points_at_arg_span: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum FulfillmentErrorCode<'tcx> {
|
||||||
|
CodeSelectionError(SelectionError<'tcx>),
|
||||||
|
CodeProjectionError(MismatchedProjectionTypes<'tcx>),
|
||||||
|
CodeSubtypeError(ExpectedFound<Ty<'tcx>>, TypeError<'tcx>), // always comes from a SubtypePredicate
|
||||||
|
CodeAmbiguity,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx, O> Obligation<'tcx, O> {
|
||||||
|
pub fn new(
|
||||||
|
cause: ObligationCause<'tcx>,
|
||||||
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
|
predicate: O,
|
||||||
|
) -> Obligation<'tcx, O> {
|
||||||
|
Obligation { cause, param_env, recursion_depth: 0, predicate }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_depth(
|
||||||
|
cause: ObligationCause<'tcx>,
|
||||||
|
recursion_depth: usize,
|
||||||
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
|
predicate: O,
|
||||||
|
) -> Obligation<'tcx, O> {
|
||||||
|
Obligation { cause, param_env, recursion_depth, predicate }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn misc(
|
||||||
|
span: Span,
|
||||||
|
body_id: hir::HirId,
|
||||||
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
|
trait_ref: O,
|
||||||
|
) -> Obligation<'tcx, O> {
|
||||||
|
Obligation::new(ObligationCause::misc(span, body_id), param_env, trait_ref)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with<P>(&self, value: P) -> Obligation<'tcx, P> {
|
||||||
|
Obligation {
|
||||||
|
cause: self.cause.clone(),
|
||||||
|
param_env: self.param_env,
|
||||||
|
recursion_depth: self.recursion_depth,
|
||||||
|
predicate: value,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> FulfillmentError<'tcx> {
|
||||||
|
pub fn new(
|
||||||
|
obligation: PredicateObligation<'tcx>,
|
||||||
|
code: FulfillmentErrorCode<'tcx>,
|
||||||
|
) -> FulfillmentError<'tcx> {
|
||||||
|
FulfillmentError { obligation, code, points_at_arg_span: false }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> TraitObligation<'tcx> {
|
||||||
|
pub fn self_ty(&self) -> ty::Binder<Ty<'tcx>> {
|
||||||
|
self.predicate.map_bound(|p| p.self_ty())
|
||||||
|
}
|
||||||
|
}
|
|
@ -65,7 +65,13 @@ pub struct ProjectionCache<'tcx> {
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
|
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
|
||||||
pub struct ProjectionCacheKey<'tcx> {
|
pub struct ProjectionCacheKey<'tcx> {
|
||||||
pub ty: ty::ProjectionTy<'tcx>,
|
ty: ty::ProjectionTy<'tcx>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ProjectionCacheKey<'tcx> {
|
||||||
|
pub fn new(ty: ty::ProjectionTy<'tcx>) -> Self {
|
||||||
|
Self { ty }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::traits;
|
use crate::traits;
|
||||||
use crate::traits::Normalized;
|
use crate::traits::project::Normalized;
|
||||||
use rustc::ty;
|
use rustc::ty;
|
||||||
use rustc::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
|
use rustc::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
|
||||||
|
|
225
src/librustc_infer/traits/util.rs
Normal file
225
src/librustc_infer/traits/util.rs
Normal file
|
@ -0,0 +1,225 @@
|
||||||
|
use smallvec::smallvec;
|
||||||
|
|
||||||
|
use rustc::ty::outlives::Component;
|
||||||
|
use rustc::ty::{self, ToPolyTraitRef, TyCtxt};
|
||||||
|
use rustc_data_structures::fx::FxHashSet;
|
||||||
|
|
||||||
|
fn anonymize_predicate<'tcx>(tcx: TyCtxt<'tcx>, pred: &ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
|
||||||
|
match *pred {
|
||||||
|
ty::Predicate::Trait(ref data, constness) => {
|
||||||
|
ty::Predicate::Trait(tcx.anonymize_late_bound_regions(data), constness)
|
||||||
|
}
|
||||||
|
|
||||||
|
ty::Predicate::RegionOutlives(ref data) => {
|
||||||
|
ty::Predicate::RegionOutlives(tcx.anonymize_late_bound_regions(data))
|
||||||
|
}
|
||||||
|
|
||||||
|
ty::Predicate::TypeOutlives(ref data) => {
|
||||||
|
ty::Predicate::TypeOutlives(tcx.anonymize_late_bound_regions(data))
|
||||||
|
}
|
||||||
|
|
||||||
|
ty::Predicate::Projection(ref data) => {
|
||||||
|
ty::Predicate::Projection(tcx.anonymize_late_bound_regions(data))
|
||||||
|
}
|
||||||
|
|
||||||
|
ty::Predicate::WellFormed(data) => ty::Predicate::WellFormed(data),
|
||||||
|
|
||||||
|
ty::Predicate::ObjectSafe(data) => ty::Predicate::ObjectSafe(data),
|
||||||
|
|
||||||
|
ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => {
|
||||||
|
ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind)
|
||||||
|
}
|
||||||
|
|
||||||
|
ty::Predicate::Subtype(ref data) => {
|
||||||
|
ty::Predicate::Subtype(tcx.anonymize_late_bound_regions(data))
|
||||||
|
}
|
||||||
|
|
||||||
|
ty::Predicate::ConstEvaluatable(def_id, substs) => {
|
||||||
|
ty::Predicate::ConstEvaluatable(def_id, substs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct PredicateSet<'tcx> {
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
set: FxHashSet<ty::Predicate<'tcx>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PredicateSet<'tcx> {
|
||||||
|
fn new(tcx: TyCtxt<'tcx>) -> Self {
|
||||||
|
Self { tcx: tcx, set: Default::default() }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn insert(&mut self, pred: &ty::Predicate<'tcx>) -> bool {
|
||||||
|
// We have to be careful here because we want
|
||||||
|
//
|
||||||
|
// for<'a> Foo<&'a int>
|
||||||
|
//
|
||||||
|
// and
|
||||||
|
//
|
||||||
|
// for<'b> Foo<&'b int>
|
||||||
|
//
|
||||||
|
// to be considered equivalent. So normalize all late-bound
|
||||||
|
// regions before we throw things into the underlying set.
|
||||||
|
self.set.insert(anonymize_predicate(self.tcx, pred))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: AsRef<ty::Predicate<'tcx>>> Extend<T> for PredicateSet<'tcx> {
|
||||||
|
fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
|
||||||
|
for pred in iter {
|
||||||
|
self.insert(pred.as_ref());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// `Elaboration` iterator
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/// "Elaboration" is the process of identifying all the predicates that
|
||||||
|
/// are implied by a source predicate. Currently, this basically means
|
||||||
|
/// walking the "supertraits" and other similar assumptions. For example,
|
||||||
|
/// if we know that `T: Ord`, the elaborator would deduce that `T: PartialOrd`
|
||||||
|
/// holds as well. Similarly, if we have `trait Foo: 'static`, and we know that
|
||||||
|
/// `T: Foo`, then we know that `T: 'static`.
|
||||||
|
pub struct Elaborator<'tcx> {
|
||||||
|
stack: Vec<ty::Predicate<'tcx>>,
|
||||||
|
visited: PredicateSet<'tcx>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn elaborate_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> {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,12 +11,14 @@ doctest = false
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
fmt_macros = { path = "../libfmt_macros" }
|
fmt_macros = { path = "../libfmt_macros" }
|
||||||
|
graphviz = { path = "../libgraphviz" }
|
||||||
log = { version = "0.4", features = ["release_max_level_info", "std"] }
|
log = { version = "0.4", features = ["release_max_level_info", "std"] }
|
||||||
rustc_attr = { path = "../librustc_attr" }
|
rustc_attr = { path = "../librustc_attr" }
|
||||||
rustc = { path = "../librustc" }
|
rustc = { path = "../librustc" }
|
||||||
rustc_ast = { path = "../librustc_ast" }
|
rustc_ast = { path = "../librustc_ast" }
|
||||||
rustc_data_structures = { path = "../librustc_data_structures" }
|
rustc_data_structures = { path = "../librustc_data_structures" }
|
||||||
rustc_errors = { path = "../librustc_errors" }
|
rustc_errors = { path = "../librustc_errors" }
|
||||||
|
rustc_error_codes = { path = "../librustc_error_codes" }
|
||||||
rustc_hir = { path = "../librustc_hir" }
|
rustc_hir = { path = "../librustc_hir" }
|
||||||
rustc_index = { path = "../librustc_index" }
|
rustc_index = { path = "../librustc_index" }
|
||||||
rustc_infer = { path = "../librustc_infer" }
|
rustc_infer = { path = "../librustc_infer" }
|
||||||
|
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
39
src/librustc_trait_selection/lib.rs
Normal file
39
src/librustc_trait_selection/lib.rs
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
//! This crates defines the trait resolution method and 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.
|
||||||
|
//!
|
||||||
|
//! 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(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"]
|
||||||
|
|
||||||
|
#[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,5 +1,4 @@
|
||||||
use crate::infer::error_reporting::unexpected_hidden_region_diagnostic;
|
use crate::infer::InferCtxtExt as _;
|
||||||
use crate::infer::{self, InferCtxt, InferOk, TypeVariableOrigin, TypeVariableOriginKind};
|
|
||||||
use crate::traits::{self, PredicateObligation};
|
use crate::traits::{self, PredicateObligation};
|
||||||
use rustc::session::config::nightly_options;
|
use rustc::session::config::nightly_options;
|
||||||
use rustc::ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder, TypeVisitor};
|
use rustc::ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder, TypeVisitor};
|
||||||
|
@ -11,6 +10,9 @@ use rustc_data_structures::sync::Lrc;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def_id::{DefId, DefIdMap};
|
use rustc_hir::def_id::{DefId, DefIdMap};
|
||||||
use rustc_hir::Node;
|
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;
|
use rustc_span::Span;
|
||||||
|
|
||||||
pub type OpaqueTypeMap<'tcx> = DefIdMap<OpaqueTypeDecl<'tcx>>;
|
pub type OpaqueTypeMap<'tcx> = DefIdMap<OpaqueTypeDecl<'tcx>>;
|
||||||
|
@ -103,7 +105,58 @@ pub enum GenerateMemberConstraints {
|
||||||
IfNoStaticBound,
|
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
|
/// Replaces all opaque types in `value` with fresh inference variables
|
||||||
/// and creates appropriate obligations. For example, given the input:
|
/// and creates appropriate obligations. For example, given the input:
|
||||||
///
|
///
|
||||||
|
@ -129,7 +182,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
/// obligations
|
/// obligations
|
||||||
/// - `value` -- the value within which we are instantiating opaque types
|
/// - `value` -- the value within which we are instantiating opaque types
|
||||||
/// - `value_span` -- the span where the value came from, used in error reporting
|
/// - `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,
|
&self,
|
||||||
parent_def_id: DefId,
|
parent_def_id: DefId,
|
||||||
body_id: hir::HirId,
|
body_id: hir::HirId,
|
||||||
|
@ -317,7 +370,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
/// - `opaque_types` -- the map produced by `instantiate_opaque_types`
|
/// - `opaque_types` -- the map produced by `instantiate_opaque_types`
|
||||||
/// - `free_region_relations` -- something that can be used to relate
|
/// - `free_region_relations` -- something that can be used to relate
|
||||||
/// the free regions (`'a`) that appear in the impl trait.
|
/// 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,
|
&self,
|
||||||
opaque_types: &OpaqueTypeMap<'tcx>,
|
opaque_types: &OpaqueTypeMap<'tcx>,
|
||||||
free_region_relations: &FRR,
|
free_region_relations: &FRR,
|
||||||
|
@ -335,7 +388,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// See `constrain_opaque_types` for documentation.
|
/// See `constrain_opaque_types` for documentation.
|
||||||
pub fn constrain_opaque_type<FRR: FreeRegionRelations<'tcx>>(
|
fn constrain_opaque_type<FRR: FreeRegionRelations<'tcx>>(
|
||||||
&self,
|
&self,
|
||||||
def_id: DefId,
|
def_id: DefId,
|
||||||
opaque_defn: &OpaqueTypeDecl<'tcx>,
|
opaque_defn: &OpaqueTypeDecl<'tcx>,
|
||||||
|
@ -577,7 +630,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
/// - `substs`, the substs used to instantiate this opaque type
|
/// - `substs`, the substs used to instantiate this opaque type
|
||||||
/// - `instantiated_ty`, the inferred type C1 -- fully resolved, lifted version of
|
/// - `instantiated_ty`, the inferred type C1 -- fully resolved, lifted version of
|
||||||
/// `opaque_defn.concrete_ty`
|
/// `opaque_defn.concrete_ty`
|
||||||
pub fn infer_opaque_definition_from_instantiation(
|
fn infer_opaque_definition_from_instantiation(
|
||||||
&self,
|
&self,
|
||||||
def_id: DefId,
|
def_id: DefId,
|
||||||
substs: SubstsRef<'tcx>,
|
substs: SubstsRef<'tcx>,
|
||||||
|
|
|
@ -72,7 +72,7 @@ pub fn codegen_fulfill_obligation<'tcx>(
|
||||||
debug!("fulfill_obligation: register_predicate_obligation {:?}", predicate);
|
debug!("fulfill_obligation: register_predicate_obligation {:?}", predicate);
|
||||||
fulfill_cx.register_predicate_obligation(&infcx, 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);
|
info!("Cache miss: {:?} => {:?}", trait_ref, vtable);
|
||||||
Some(vtable)
|
Some(vtable)
|
||||||
|
@ -81,34 +81,32 @@ pub fn codegen_fulfill_obligation<'tcx>(
|
||||||
|
|
||||||
// # Global Cache
|
// # Global Cache
|
||||||
|
|
||||||
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
/// Finishes processes any obligations that remain in the
|
||||||
/// Finishes processes any obligations that remain in the
|
/// fulfillment context, and then returns the result with all type
|
||||||
/// fulfillment context, and then returns the result with all type
|
/// variables removed and regions erased. Because this is intended
|
||||||
/// variables removed and regions erased. Because this is intended
|
/// for use after type-check has completed, if any errors occur,
|
||||||
/// for use after type-check has completed, if any errors occur,
|
/// it will panic. It is used during normalization and other cases
|
||||||
/// it will panic. It is used during normalization and other cases
|
/// where processing the obligations in `fulfill_cx` may cause
|
||||||
/// where processing the obligations in `fulfill_cx` may cause
|
/// type inference variables that appear in `result` to be
|
||||||
/// type inference variables that appear in `result` to be
|
/// unified, and hence we need to process those obligations to get
|
||||||
/// unified, and hence we need to process those obligations to get
|
/// the complete picture of the type.
|
||||||
/// the complete picture of the type.
|
fn drain_fulfillment_cx_or_panic<T>(
|
||||||
fn drain_fulfillment_cx_or_panic<T>(
|
infcx: &InferCtxt<'_, 'tcx>,
|
||||||
&self,
|
fulfill_cx: &mut FulfillmentContext<'tcx>,
|
||||||
fulfill_cx: &mut FulfillmentContext<'tcx>,
|
result: &T,
|
||||||
result: &T,
|
) -> T
|
||||||
) -> T
|
where
|
||||||
where
|
T: TypeFoldable<'tcx>,
|
||||||
T: TypeFoldable<'tcx>,
|
{
|
||||||
{
|
debug!("drain_fulfillment_cx_or_panic()");
|
||||||
debug!("drain_fulfillment_cx_or_panic()");
|
|
||||||
|
|
||||||
// In principle, we only need to do this so long as `result`
|
// In principle, we only need to do this so long as `result`
|
||||||
// contains unbound type parameters. It could be a slight
|
// contains unbound type parameters. It could be a slight
|
||||||
// optimization to stop iterating early.
|
// optimization to stop iterating early.
|
||||||
if let Err(errors) = fulfill_cx.select_all_or_error(self) {
|
if let Err(errors) = fulfill_cx.select_all_or_error(infcx) {
|
||||||
bug!("Encountered errors `{:?}` resolving bounds after type-checking", errors);
|
bug!("Encountered errors `{:?}` resolving bounds after type-checking", errors);
|
||||||
}
|
|
||||||
|
|
||||||
let result = self.resolve_vars_if_possible(result);
|
|
||||||
self.tcx.erase_regions(&result)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let result = infcx.resolve_vars_if_possible(result);
|
||||||
|
infcx.tcx.erase_regions(&result)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,84 +1,14 @@
|
||||||
use crate::infer::InferCtxt;
|
use rustc::ty::TyCtxt;
|
||||||
use crate::traits::Obligation;
|
|
||||||
use rustc::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness};
|
|
||||||
use rustc_hir::def_id::DefId;
|
|
||||||
|
|
||||||
use super::{FulfillmentContext, FulfillmentError};
|
use super::FulfillmentContext;
|
||||||
use super::{ObligationCause, PredicateObligation};
|
use super::TraitEngine;
|
||||||
|
|
||||||
pub trait TraitEngine<'tcx>: 'tcx {
|
|
||||||
fn normalize_projection_type(
|
|
||||||
&mut self,
|
|
||||||
infcx: &InferCtxt<'_, 'tcx>,
|
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
|
||||||
projection_ty: ty::ProjectionTy<'tcx>,
|
|
||||||
cause: ObligationCause<'tcx>,
|
|
||||||
) -> Ty<'tcx>;
|
|
||||||
|
|
||||||
/// Requires that `ty` must implement the trait with `def_id` in
|
|
||||||
/// the given environment. This trait must not have any type
|
|
||||||
/// parameters (except for `Self`).
|
|
||||||
fn register_bound(
|
|
||||||
&mut self,
|
|
||||||
infcx: &InferCtxt<'_, 'tcx>,
|
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
|
||||||
ty: Ty<'tcx>,
|
|
||||||
def_id: DefId,
|
|
||||||
cause: ObligationCause<'tcx>,
|
|
||||||
) {
|
|
||||||
let trait_ref = ty::TraitRef { def_id, substs: infcx.tcx.mk_substs_trait(ty, &[]) };
|
|
||||||
self.register_predicate_obligation(
|
|
||||||
infcx,
|
|
||||||
Obligation {
|
|
||||||
cause,
|
|
||||||
recursion_depth: 0,
|
|
||||||
param_env,
|
|
||||||
predicate: trait_ref.without_const().to_predicate(),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn register_predicate_obligation(
|
|
||||||
&mut self,
|
|
||||||
infcx: &InferCtxt<'_, 'tcx>,
|
|
||||||
obligation: PredicateObligation<'tcx>,
|
|
||||||
);
|
|
||||||
|
|
||||||
fn select_all_or_error(
|
|
||||||
&mut self,
|
|
||||||
infcx: &InferCtxt<'_, 'tcx>,
|
|
||||||
) -> Result<(), Vec<FulfillmentError<'tcx>>>;
|
|
||||||
|
|
||||||
fn select_where_possible(
|
|
||||||
&mut self,
|
|
||||||
infcx: &InferCtxt<'_, 'tcx>,
|
|
||||||
) -> Result<(), Vec<FulfillmentError<'tcx>>>;
|
|
||||||
|
|
||||||
fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>>;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait TraitEngineExt<'tcx> {
|
pub trait TraitEngineExt<'tcx> {
|
||||||
fn register_predicate_obligations(
|
fn new(tcx: TyCtxt<'tcx>) -> Box<Self>;
|
||||||
&mut self,
|
|
||||||
infcx: &InferCtxt<'_, 'tcx>,
|
|
||||||
obligations: impl IntoIterator<Item = PredicateObligation<'tcx>>,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: ?Sized + TraitEngine<'tcx>> TraitEngineExt<'tcx> for T {
|
impl<'tcx> TraitEngineExt<'tcx> for dyn TraitEngine<'tcx> {
|
||||||
fn register_predicate_obligations(
|
fn new(_tcx: TyCtxt<'tcx>) -> Box<Self> {
|
||||||
&mut self,
|
|
||||||
infcx: &InferCtxt<'_, 'tcx>,
|
|
||||||
obligations: impl IntoIterator<Item = PredicateObligation<'tcx>>,
|
|
||||||
) {
|
|
||||||
for obligation in obligations {
|
|
||||||
self.register_predicate_obligation(infcx, obligation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl dyn TraitEngine<'tcx> {
|
|
||||||
pub fn new(_tcx: TyCtxt<'tcx>) -> Box<Self> {
|
|
||||||
Box::new(FulfillmentContext::new())
|
Box::new(FulfillmentContext::new())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
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_hir::def_id::DefId;
|
||||||
use rustc_span::symbol::sym;
|
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(
|
fn impl_similar_to(
|
||||||
&self,
|
&self,
|
||||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
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,
|
&self,
|
||||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||||
obligation: &PredicateObligation<'tcx>,
|
obligation: &PredicateObligation<'tcx>,
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
use super::{
|
use super::{
|
||||||
ArgKind, EvaluationResult, Obligation, ObligationCause, ObligationCauseCode,
|
EvaluationResult, Obligation, ObligationCause, ObligationCauseCode, PredicateObligation,
|
||||||
PredicateObligation,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::infer::InferCtxt;
|
use crate::infer::InferCtxt;
|
||||||
|
@ -8,9 +7,7 @@ use crate::traits::error_reporting::suggest_constraining_type_param;
|
||||||
|
|
||||||
use rustc::ty::TypeckTables;
|
use rustc::ty::TypeckTables;
|
||||||
use rustc::ty::{self, AdtKind, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
|
use rustc::ty::{self, AdtKind, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
|
||||||
use rustc_errors::{
|
use rustc_errors::{error_code, struct_span_err, Applicability, DiagnosticBuilder, Style};
|
||||||
error_code, pluralize, struct_span_err, Applicability, DiagnosticBuilder, Style,
|
|
||||||
};
|
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::DefKind;
|
use rustc_hir::def::DefKind;
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
|
@ -20,8 +17,136 @@ use rustc_span::symbol::{kw, sym};
|
||||||
use rustc_span::{MultiSpan, Span, DUMMY_SP};
|
use rustc_span::{MultiSpan, Span, DUMMY_SP};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
use super::InferCtxtPrivExt;
|
||||||
crate fn suggest_restricting_param_bound(
|
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,
|
&self,
|
||||||
mut err: &mut DiagnosticBuilder<'_>,
|
mut err: &mut DiagnosticBuilder<'_>,
|
||||||
trait_ref: &ty::PolyTraitRef<'_>,
|
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
|
/// 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.
|
/// 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,
|
&self,
|
||||||
code: &ObligationCauseCode<'tcx>,
|
code: &ObligationCauseCode<'tcx>,
|
||||||
err: &mut DiagnosticBuilder<'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.
|
/// 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.
|
/// This doesn't account for reassignments, but it's only used for suggestions.
|
||||||
crate fn get_closure_name(
|
fn get_closure_name(
|
||||||
&self,
|
&self,
|
||||||
def_id: DefId,
|
def_id: DefId,
|
||||||
err: &mut DiagnosticBuilder<'_>,
|
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
|
/// 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
|
/// 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`.
|
/// 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,
|
&self,
|
||||||
obligation: &PredicateObligation<'tcx>,
|
obligation: &PredicateObligation<'tcx>,
|
||||||
err: &mut DiagnosticBuilder<'_>,
|
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,
|
&self,
|
||||||
obligation: &PredicateObligation<'tcx>,
|
obligation: &PredicateObligation<'tcx>,
|
||||||
err: &mut DiagnosticBuilder<'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()`,
|
/// 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.
|
/// suggest removing these references until we reach a type that implements the trait.
|
||||||
crate fn suggest_remove_reference(
|
fn suggest_remove_reference(
|
||||||
&self,
|
&self,
|
||||||
obligation: &PredicateObligation<'tcx>,
|
obligation: &PredicateObligation<'tcx>,
|
||||||
err: &mut DiagnosticBuilder<'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
|
/// Check if the trait bound is implemented for a different mutability and note it in the
|
||||||
/// final error.
|
/// final error.
|
||||||
crate fn suggest_change_mut(
|
fn suggest_change_mut(
|
||||||
&self,
|
&self,
|
||||||
obligation: &PredicateObligation<'tcx>,
|
obligation: &PredicateObligation<'tcx>,
|
||||||
err: &mut DiagnosticBuilder<'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,
|
&self,
|
||||||
obligation: &PredicateObligation<'tcx>,
|
obligation: &PredicateObligation<'tcx>,
|
||||||
err: &mut DiagnosticBuilder<'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
|
/// 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
|
/// applicable and signal that the error has been expanded appropriately and needs to be
|
||||||
/// emitted.
|
/// emitted.
|
||||||
crate fn suggest_impl_trait(
|
fn suggest_impl_trait(
|
||||||
&self,
|
&self,
|
||||||
err: &mut DiagnosticBuilder<'tcx>,
|
err: &mut DiagnosticBuilder<'tcx>,
|
||||||
span: Span,
|
span: Span,
|
||||||
|
@ -723,7 +848,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
crate fn point_at_returns_when_relevant(
|
fn point_at_returns_when_relevant(
|
||||||
&self,
|
&self,
|
||||||
err: &mut DiagnosticBuilder<'tcx>,
|
err: &mut DiagnosticBuilder<'tcx>,
|
||||||
obligation: &PredicateObligation<'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,
|
fn report_closure_arg_mismatch(
|
||||||
/// 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(
|
|
||||||
&self,
|
&self,
|
||||||
span: Span,
|
span: Span,
|
||||||
found_span: Option<Span>,
|
found_span: Option<Span>,
|
||||||
|
@ -1022,10 +934,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
|
|
||||||
err
|
err
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
fn suggest_fully_qualified_path(
|
||||||
crate fn suggest_fully_qualified_path(
|
|
||||||
&self,
|
&self,
|
||||||
err: &mut DiagnosticBuilder<'_>,
|
err: &mut DiagnosticBuilder<'_>,
|
||||||
def_id: DefId,
|
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.
|
/// 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,
|
&self,
|
||||||
err: &mut DiagnosticBuilder<'_>,
|
err: &mut DiagnosticBuilder<'_>,
|
||||||
obligation: &PredicateObligation<'tcx>,
|
obligation: &PredicateObligation<'tcx>,
|
||||||
|
@ -1271,7 +1181,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||||
|
|
||||||
/// Unconditionally adds the diagnostic note described in
|
/// Unconditionally adds the diagnostic note described in
|
||||||
/// `maybe_note_obligation_cause_for_async_await`'s documentation comment.
|
/// `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,
|
&self,
|
||||||
err: &mut DiagnosticBuilder<'_>,
|
err: &mut DiagnosticBuilder<'_>,
|
||||||
target_span: Span,
|
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,
|
&self,
|
||||||
err: &mut DiagnosticBuilder<'_>,
|
err: &mut DiagnosticBuilder<'_>,
|
||||||
predicate: &T,
|
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 current_limit = self.tcx.sess.recursion_limit.get();
|
||||||
let suggested_limit = current_limit * 2;
|
let suggested_limit = current_limit * 2;
|
||||||
err.help(&format!(
|
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::ProcessResult;
|
||||||
use rustc_data_structures::obligation_forest::{DoCompleted, Error, ForestObligation};
|
use rustc_data_structures::obligation_forest::{DoCompleted, Error, ForestObligation};
|
||||||
use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor};
|
use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor};
|
||||||
|
use rustc_infer::traits::{TraitEngine, TraitEngineExt as _};
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
use super::engine::{TraitEngine, TraitEngineExt};
|
|
||||||
use super::project;
|
use super::project;
|
||||||
use super::select::SelectionContext;
|
use super::select::SelectionContext;
|
||||||
use super::wf;
|
use super::wf;
|
||||||
|
@ -17,6 +17,9 @@ use super::{ConstEvalFailure, Unimplemented};
|
||||||
use super::{FulfillmentError, FulfillmentErrorCode};
|
use super::{FulfillmentError, FulfillmentErrorCode};
|
||||||
use super::{ObligationCause, PredicateObligation};
|
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> {
|
impl<'tcx> ForestObligation for PendingPredicateObligation<'tcx> {
|
||||||
/// Note that we include both the `ParamEnv` and the `Predicate`,
|
/// Note that we include both the `ParamEnv` and the `Predicate`,
|
||||||
/// as the `ParamEnv` can influence whether fulfillment succeeds
|
/// 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.
|
//! 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 crate::traits::{self, ObligationCause};
|
||||||
|
|
||||||
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
|
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
|
use rustc_infer::infer::TyCtxtInferExt;
|
||||||
|
|
||||||
|
use crate::traits::error_reporting::InferCtxtExt;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum CopyImplementationError<'tcx> {
|
pub enum CopyImplementationError<'tcx> {
|
||||||
|
|
|
@ -13,19 +13,18 @@ pub mod misc;
|
||||||
mod object_safety;
|
mod object_safety;
|
||||||
mod on_unimplemented;
|
mod on_unimplemented;
|
||||||
mod project;
|
mod project;
|
||||||
mod projection_cache;
|
|
||||||
pub mod query;
|
pub mod query;
|
||||||
mod select;
|
mod select;
|
||||||
mod specialize;
|
mod specialize;
|
||||||
mod structural_impls;
|
|
||||||
mod structural_match;
|
mod structural_match;
|
||||||
mod util;
|
mod util;
|
||||||
pub mod wf;
|
pub mod wf;
|
||||||
|
|
||||||
use crate::infer::outlives::env::OutlivesEnvironment;
|
use crate::infer::outlives::env::OutlivesEnvironment;
|
||||||
use crate::infer::{InferCtxt, SuppressRegionErrors, TyCtxtInferExt};
|
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::middle::region;
|
||||||
use rustc::ty::error::{ExpectedFound, TypeError};
|
|
||||||
use rustc::ty::fold::TypeFoldable;
|
use rustc::ty::fold::TypeFoldable;
|
||||||
use rustc::ty::subst::{InternalSubsts, SubstsRef};
|
use rustc::ty::subst::{InternalSubsts, SubstsRef};
|
||||||
use rustc::ty::{self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, WithConstness};
|
use rustc::ty::{self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, WithConstness};
|
||||||
|
@ -43,7 +42,7 @@ pub use self::Vtable::*;
|
||||||
|
|
||||||
pub use self::coherence::{add_placeholder_note, orphan_check, overlapping_impls};
|
pub use self::coherence::{add_placeholder_note, orphan_check, overlapping_impls};
|
||||||
pub use self::coherence::{OrphanCheckErr, OverlapResult};
|
pub use self::coherence::{OrphanCheckErr, OverlapResult};
|
||||||
pub use self::engine::{TraitEngine, TraitEngineExt};
|
pub use self::engine::TraitEngineExt;
|
||||||
pub use self::fulfill::{FulfillmentContext, PendingPredicateObligation};
|
pub use self::fulfill::{FulfillmentContext, PendingPredicateObligation};
|
||||||
pub use self::object_safety::astconv_object_safety_violations;
|
pub use self::object_safety::astconv_object_safety_violations;
|
||||||
pub use self::object_safety::is_vtable_safe_method;
|
pub use self::object_safety::is_vtable_safe_method;
|
||||||
|
@ -53,11 +52,6 @@ pub use self::on_unimplemented::{OnUnimplementedDirective, OnUnimplementedNote};
|
||||||
pub use self::project::{
|
pub use self::project::{
|
||||||
normalize, normalize_projection_type, normalize_to, poly_project_and_unify_type,
|
normalize, normalize_projection_type, normalize_to, poly_project_and_unify_type,
|
||||||
};
|
};
|
||||||
pub use self::projection_cache::MismatchedProjectionTypes;
|
|
||||||
pub use self::projection_cache::{
|
|
||||||
Normalized, ProjectionCache, ProjectionCacheEntry, ProjectionCacheKey, ProjectionCacheSnapshot,
|
|
||||||
Reveal,
|
|
||||||
};
|
|
||||||
pub use self::select::{EvaluationCache, SelectionCache, SelectionContext};
|
pub use self::select::{EvaluationCache, SelectionCache, SelectionContext};
|
||||||
pub use self::select::{EvaluationResult, IntercrateAmbiguityCause, OverflowError};
|
pub use self::select::{EvaluationResult, IntercrateAmbiguityCause, OverflowError};
|
||||||
pub use self::specialize::find_associated_item;
|
pub use self::specialize::find_associated_item;
|
||||||
|
@ -77,7 +71,7 @@ pub use self::util::{
|
||||||
supertrait_def_ids, supertraits, transitive_bounds, SupertraitDefIds, Supertraits,
|
supertrait_def_ids, supertraits, transitive_bounds, SupertraitDefIds, Supertraits,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use rustc::traits::*;
|
pub use rustc_infer::traits::*;
|
||||||
|
|
||||||
/// Whether to skip the leak check, as part of a future compatibility warning step.
|
/// Whether to skip the leak check, as part of a future compatibility warning step.
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||||
|
@ -114,61 +108,6 @@ pub enum TraitQueryMode {
|
||||||
Canonical,
|
Canonical,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An `Obligation` represents some trait reference (e.g., `int: Eq`) for
|
|
||||||
/// which the vtable must be found. The process of finding a vtable is
|
|
||||||
/// called "resolving" the `Obligation`. This process consists of
|
|
||||||
/// either identifying an `impl` (e.g., `impl Eq for int`) that
|
|
||||||
/// provides the required vtable, or else finding a bound that is in
|
|
||||||
/// scope. The eventual result is usually a `Selection` (defined below).
|
|
||||||
#[derive(Clone, PartialEq, Eq, Hash)]
|
|
||||||
pub struct Obligation<'tcx, T> {
|
|
||||||
/// The reason we have to prove this thing.
|
|
||||||
pub cause: ObligationCause<'tcx>,
|
|
||||||
|
|
||||||
/// The environment in which we should prove this thing.
|
|
||||||
pub param_env: ty::ParamEnv<'tcx>,
|
|
||||||
|
|
||||||
/// The thing we are trying to prove.
|
|
||||||
pub predicate: T,
|
|
||||||
|
|
||||||
/// If we started proving this as a result of trying to prove
|
|
||||||
/// something else, track the total depth to ensure termination.
|
|
||||||
/// If this goes over a certain threshold, we abort compilation --
|
|
||||||
/// in such cases, we can not say whether or not the predicate
|
|
||||||
/// holds for certain. Stupid halting problem; such a drag.
|
|
||||||
pub recursion_depth: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type PredicateObligation<'tcx> = Obligation<'tcx, ty::Predicate<'tcx>>;
|
|
||||||
pub type TraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitPredicate<'tcx>>;
|
|
||||||
|
|
||||||
// `PredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger.
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
|
||||||
static_assert_size!(PredicateObligation<'_>, 112);
|
|
||||||
|
|
||||||
pub type Obligations<'tcx, O> = Vec<Obligation<'tcx, O>>;
|
|
||||||
pub type PredicateObligations<'tcx> = Vec<PredicateObligation<'tcx>>;
|
|
||||||
pub type TraitObligations<'tcx> = Vec<TraitObligation<'tcx>>;
|
|
||||||
|
|
||||||
pub type Selection<'tcx> = Vtable<'tcx, PredicateObligation<'tcx>>;
|
|
||||||
|
|
||||||
pub struct FulfillmentError<'tcx> {
|
|
||||||
pub obligation: PredicateObligation<'tcx>,
|
|
||||||
pub code: FulfillmentErrorCode<'tcx>,
|
|
||||||
/// Diagnostics only: we opportunistically change the `code.span` when we encounter an
|
|
||||||
/// obligation error caused by a call argument. When this is the case, we also signal that in
|
|
||||||
/// this field to ensure accuracy of suggestions.
|
|
||||||
pub points_at_arg_span: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub enum FulfillmentErrorCode<'tcx> {
|
|
||||||
CodeSelectionError(SelectionError<'tcx>),
|
|
||||||
CodeProjectionError(MismatchedProjectionTypes<'tcx>),
|
|
||||||
CodeSubtypeError(ExpectedFound<Ty<'tcx>>, TypeError<'tcx>), // always comes from a SubtypePredicate
|
|
||||||
CodeAmbiguity,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates predicate obligations from the generic bounds.
|
/// Creates predicate obligations from the generic bounds.
|
||||||
pub fn predicates_for_generics<'tcx>(
|
pub fn predicates_for_generics<'tcx>(
|
||||||
cause: ObligationCause<'tcx>,
|
cause: ObligationCause<'tcx>,
|
||||||
|
@ -581,58 +520,6 @@ fn vtable_methods<'tcx>(
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx, O> Obligation<'tcx, O> {
|
|
||||||
pub fn new(
|
|
||||||
cause: ObligationCause<'tcx>,
|
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
|
||||||
predicate: O,
|
|
||||||
) -> Obligation<'tcx, O> {
|
|
||||||
Obligation { cause, param_env, recursion_depth: 0, predicate }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn with_depth(
|
|
||||||
cause: ObligationCause<'tcx>,
|
|
||||||
recursion_depth: usize,
|
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
|
||||||
predicate: O,
|
|
||||||
) -> Obligation<'tcx, O> {
|
|
||||||
Obligation { cause, param_env, recursion_depth, predicate }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn misc(
|
|
||||||
span: Span,
|
|
||||||
body_id: hir::HirId,
|
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
|
||||||
trait_ref: O,
|
|
||||||
) -> Obligation<'tcx, O> {
|
|
||||||
Obligation::new(ObligationCause::misc(span, body_id), param_env, trait_ref)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with<P>(&self, value: P) -> Obligation<'tcx, P> {
|
|
||||||
Obligation {
|
|
||||||
cause: self.cause.clone(),
|
|
||||||
param_env: self.param_env,
|
|
||||||
recursion_depth: self.recursion_depth,
|
|
||||||
predicate: value,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> FulfillmentError<'tcx> {
|
|
||||||
fn new(
|
|
||||||
obligation: PredicateObligation<'tcx>,
|
|
||||||
code: FulfillmentErrorCode<'tcx>,
|
|
||||||
) -> FulfillmentError<'tcx> {
|
|
||||||
FulfillmentError { obligation, code, points_at_arg_span: false }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> TraitObligation<'tcx> {
|
|
||||||
fn self_ty(&self) -> ty::Binder<Ty<'tcx>> {
|
|
||||||
self.predicate.map_bound(|p| p.self_ty())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn provide(providers: &mut ty::query::Providers<'_>) {
|
pub fn provide(providers: &mut ty::query::Providers<'_>) {
|
||||||
object_safety::provide(providers);
|
object_safety::provide(providers);
|
||||||
*providers = ty::query::Providers {
|
*providers = ty::query::Providers {
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
use super::elaborate_predicates;
|
use super::elaborate_predicates;
|
||||||
|
|
||||||
use crate::infer::TyCtxtInferExt;
|
use crate::infer::TyCtxtInferExt;
|
||||||
|
use crate::traits::query::evaluate_obligation::InferCtxtExt;
|
||||||
use crate::traits::{self, Obligation, ObligationCause};
|
use crate::traits::{self, Obligation, ObligationCause};
|
||||||
use rustc::ty::subst::{InternalSubsts, Subst};
|
use rustc::ty::subst::{InternalSubsts, Subst};
|
||||||
use rustc::ty::{self, Predicate, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
|
use rustc::ty::{self, Predicate, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
//! Code for projecting associated types out of trait references.
|
//! Code for projecting associated types out of trait references.
|
||||||
|
|
||||||
use super::elaborate_predicates;
|
use super::elaborate_predicates;
|
||||||
use super::projection_cache::NormalizedTy;
|
|
||||||
use super::specialization_graph;
|
use super::specialization_graph;
|
||||||
use super::translate_substs;
|
use super::translate_substs;
|
||||||
use super::util;
|
use super::util;
|
||||||
|
@ -12,11 +11,12 @@ use super::PredicateObligation;
|
||||||
use super::Selection;
|
use super::Selection;
|
||||||
use super::SelectionContext;
|
use super::SelectionContext;
|
||||||
use super::SelectionError;
|
use super::SelectionError;
|
||||||
use super::{Normalized, ProjectionCacheEntry, ProjectionCacheKey};
|
use super::{Normalized, NormalizedTy, ProjectionCacheEntry, ProjectionCacheKey};
|
||||||
use super::{VtableClosureData, VtableFnPointerData, VtableGeneratorData, VtableImplData};
|
use super::{VtableClosureData, VtableFnPointerData, VtableGeneratorData, VtableImplData};
|
||||||
|
|
||||||
use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
|
||||||
use crate::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime};
|
use crate::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime};
|
||||||
|
use crate::traits::error_reporting::InferCtxtExt;
|
||||||
use rustc::ty::fold::{TypeFoldable, TypeFolder};
|
use rustc::ty::fold::{TypeFoldable, TypeFolder};
|
||||||
use rustc::ty::subst::{InternalSubsts, Subst};
|
use rustc::ty::subst::{InternalSubsts, Subst};
|
||||||
use rustc::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, WithConstness};
|
use rustc::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, WithConstness};
|
||||||
|
@ -452,7 +452,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>(
|
||||||
let infcx = selcx.infcx();
|
let infcx = selcx.infcx();
|
||||||
|
|
||||||
let projection_ty = infcx.resolve_vars_if_possible(&projection_ty);
|
let projection_ty = infcx.resolve_vars_if_possible(&projection_ty);
|
||||||
let cache_key = ProjectionCacheKey { ty: projection_ty };
|
let cache_key = ProjectionCacheKey::new(projection_ty);
|
||||||
|
|
||||||
debug!(
|
debug!(
|
||||||
"opt_normalize_projection_type(\
|
"opt_normalize_projection_type(\
|
||||||
|
@ -1483,20 +1483,29 @@ fn assoc_ty_def(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'cx, 'tcx> ProjectionCacheKey<'tcx> {
|
crate trait ProjectionCacheKeyExt<'tcx>: Sized {
|
||||||
pub fn from_poly_projection_predicate(
|
fn from_poly_projection_predicate(
|
||||||
|
selcx: &mut SelectionContext<'cx, 'tcx>,
|
||||||
|
predicate: &ty::PolyProjectionPredicate<'tcx>,
|
||||||
|
) -> Option<Self>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> ProjectionCacheKeyExt<'tcx> for ProjectionCacheKey<'tcx> {
|
||||||
|
fn from_poly_projection_predicate(
|
||||||
selcx: &mut SelectionContext<'cx, 'tcx>,
|
selcx: &mut SelectionContext<'cx, 'tcx>,
|
||||||
predicate: &ty::PolyProjectionPredicate<'tcx>,
|
predicate: &ty::PolyProjectionPredicate<'tcx>,
|
||||||
) -> Option<Self> {
|
) -> Option<Self> {
|
||||||
let infcx = selcx.infcx();
|
let infcx = selcx.infcx();
|
||||||
// We don't do cross-snapshot caching of obligations with escaping regions,
|
// We don't do cross-snapshot caching of obligations with escaping regions,
|
||||||
// so there's no cache key to use
|
// so there's no cache key to use
|
||||||
predicate.no_bound_vars().map(|predicate| ProjectionCacheKey {
|
predicate.no_bound_vars().map(|predicate| {
|
||||||
// We don't attempt to match up with a specific type-variable state
|
ProjectionCacheKey::new(
|
||||||
// from a specific call to `opt_normalize_projection_type` - if
|
// We don't attempt to match up with a specific type-variable state
|
||||||
// there's no precise match, the original cache entry is "stranded"
|
// from a specific call to `opt_normalize_projection_type` - if
|
||||||
// anyway.
|
// there's no precise match, the original cache entry is "stranded"
|
||||||
ty: infcx.resolve_vars_if_possible(&predicate.projection_ty),
|
// anyway.
|
||||||
|
infcx.resolve_vars_if_possible(&predicate.projection_ty),
|
||||||
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,11 @@ use rustc::ty::{self, Ty, TyCtxt};
|
||||||
|
|
||||||
pub use rustc::traits::query::{DropckOutlivesResult, DtorckConstraint};
|
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
|
/// Given a type `ty` of some value being dropped, computes a set
|
||||||
/// of "kinds" (types, regions) that must be outlive the execution
|
/// of "kinds" (types, regions) that must be outlive the execution
|
||||||
/// of the destructor. These basically correspond to data that the
|
/// 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
|
/// [#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
|
/// [#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,);
|
debug!("dropck_outlives(ty={:?}, param_env={:?})", ty, self.param_env,);
|
||||||
|
|
||||||
// Quick check: there are a number of cases that we know do not require
|
// 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,
|
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)
|
/// Evaluates whether the predicate can be satisfied (by any means)
|
||||||
/// in the given `ParamEnv`.
|
/// 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()
|
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
|
/// This version may conservatively fail when outlives obligations
|
||||||
/// are required.
|
/// are required.
|
||||||
pub fn predicate_must_hold_considering_regions(
|
fn predicate_must_hold_considering_regions(
|
||||||
&self,
|
&self,
|
||||||
obligation: &PredicateObligation<'tcx>,
|
obligation: &PredicateObligation<'tcx>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
|
@ -29,15 +54,12 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
|
||||||
/// not entirely accurate if inference variables are involved.
|
/// not entirely accurate if inference variables are involved.
|
||||||
///
|
///
|
||||||
/// This version ignores all outlives constraints.
|
/// This version ignores all outlives constraints.
|
||||||
pub fn predicate_must_hold_modulo_regions(
|
fn predicate_must_hold_modulo_regions(&self, obligation: &PredicateObligation<'tcx>) -> bool {
|
||||||
&self,
|
|
||||||
obligation: &PredicateObligation<'tcx>,
|
|
||||||
) -> bool {
|
|
||||||
self.evaluate_obligation_no_overflow(obligation).must_apply_modulo_regions()
|
self.evaluate_obligation_no_overflow(obligation).must_apply_modulo_regions()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluate a given predicate, capturing overflow and propagating it back.
|
/// Evaluate a given predicate, capturing overflow and propagating it back.
|
||||||
pub fn evaluate_obligation(
|
fn evaluate_obligation(
|
||||||
&self,
|
&self,
|
||||||
obligation: &PredicateObligation<'tcx>,
|
obligation: &PredicateObligation<'tcx>,
|
||||||
) -> Result<EvaluationResult, OverflowError> {
|
) -> Result<EvaluationResult, OverflowError> {
|
||||||
|
@ -53,7 +75,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
|
||||||
// Helper function that canonicalizes and runs the query. If an
|
// Helper function that canonicalizes and runs the query. If an
|
||||||
// overflow results, we re-run it in the local context so we can
|
// overflow results, we re-run it in the local context so we can
|
||||||
// report a nice error.
|
// report a nice error.
|
||||||
crate fn evaluate_obligation_no_overflow(
|
fn evaluate_obligation_no_overflow(
|
||||||
&self,
|
&self,
|
||||||
obligation: &PredicateObligation<'tcx>,
|
obligation: &PredicateObligation<'tcx>,
|
||||||
) -> EvaluationResult {
|
) -> EvaluationResult {
|
||||||
|
|
|
@ -5,17 +5,24 @@
|
||||||
use crate::infer::at::At;
|
use crate::infer::at::At;
|
||||||
use crate::infer::canonical::OriginalQueryValues;
|
use crate::infer::canonical::OriginalQueryValues;
|
||||||
use crate::infer::{InferCtxt, InferOk};
|
use crate::infer::{InferCtxt, InferOk};
|
||||||
use crate::traits::Normalized;
|
use crate::traits::error_reporting::InferCtxtExt;
|
||||||
use crate::traits::{Obligation, ObligationCause, PredicateObligation, Reveal};
|
use crate::traits::{Obligation, ObligationCause, PredicateObligation, Reveal};
|
||||||
use rustc::ty::fold::{TypeFoldable, TypeFolder};
|
use rustc::ty::fold::{TypeFoldable, TypeFolder};
|
||||||
use rustc::ty::subst::Subst;
|
use rustc::ty::subst::Subst;
|
||||||
use rustc::ty::{self, Ty, TyCtxt};
|
use rustc::ty::{self, Ty, TyCtxt};
|
||||||
|
use rustc_infer::traits::Normalized;
|
||||||
|
|
||||||
use super::NoSolution;
|
use super::NoSolution;
|
||||||
|
|
||||||
pub use rustc::traits::query::NormalizationResult;
|
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,
|
/// Normalize `value` in the context of the inference context,
|
||||||
/// yielding a resulting type, or an error if `value` cannot be
|
/// yielding a resulting type, or an error if `value` cannot be
|
||||||
/// normalized. If you don't care about regions, you should prefer
|
/// 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
|
/// normalizing, but for now should be used only when we actually
|
||||||
/// know that normalization will succeed, since error reporting
|
/// know that normalization will succeed, since error reporting
|
||||||
/// and other details are still "under development".
|
/// 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
|
where
|
||||||
T: TypeFoldable<'tcx>,
|
T: TypeFoldable<'tcx>,
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,14 +1,25 @@
|
||||||
use crate::infer::canonical::OriginalQueryValues;
|
use crate::infer::canonical::OriginalQueryValues;
|
||||||
use crate::infer::InferCtxt;
|
use crate::infer::InferCtxt;
|
||||||
use crate::traits::query::NoSolution;
|
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::ty::{self, Ty};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
|
use rustc_infer::traits::TraitEngineExt as _;
|
||||||
use rustc_span::source_map::Span;
|
use rustc_span::source_map::Span;
|
||||||
|
|
||||||
pub use rustc::traits::query::OutlivesBound;
|
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
|
/// Implied bounds are region relationships that we deduce
|
||||||
/// automatically. The idea is that (e.g.) a caller must check that a
|
/// automatically. The idea is that (e.g.) a caller must check that a
|
||||||
/// function's argument types are well-formed immediately before
|
/// 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.
|
/// - `ty`, the type that we are supposed to assume is WF.
|
||||||
/// - `span`, a span to use when normalizing, hopefully not important,
|
/// - `span`, a span to use when normalizing, hopefully not important,
|
||||||
/// might be useful if a `bug!` occurs.
|
/// might be useful if a `bug!` occurs.
|
||||||
pub fn implied_outlives_bounds(
|
fn implied_outlives_bounds(
|
||||||
&self,
|
&self,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
body_id: hir::HirId,
|
body_id: hir::HirId,
|
||||||
|
|
|
@ -4,7 +4,9 @@ use std::fmt;
|
||||||
|
|
||||||
use crate::infer::canonical::query_response;
|
use crate::infer::canonical::query_response;
|
||||||
use crate::infer::canonical::QueryRegionConstraints;
|
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 rustc_span::source_map::DUMMY_SP;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,8 @@ use super::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::infer::{CombinedSnapshot, InferCtxt, InferOk, PlaceholderMap, TypeFreshener};
|
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::dep_graph::{DepKind, DepNodeIndex};
|
||||||
use rustc::middle::lang_items;
|
use rustc::middle::lang_items;
|
||||||
use rustc::ty::fast_reject;
|
use rustc::ty::fast_reject;
|
||||||
|
@ -3464,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)]
|
#[allow(unused_comparisons)]
|
||||||
pub fn derived_cause(
|
fn derived_cause(
|
||||||
&self,
|
&self,
|
||||||
variant: fn(DerivedObligationCause<'tcx>) -> ObligationCauseCode<'tcx>,
|
variant: fn(DerivedObligationCause<'tcx>) -> ObligationCauseCode<'tcx>,
|
||||||
) -> ObligationCause<'tcx> {
|
) -> ObligationCause<'tcx> {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::infer::opaque_types::required_region_bounds;
|
|
||||||
use crate::infer::InferCtxt;
|
use crate::infer::InferCtxt;
|
||||||
|
use crate::opaque_types::required_region_bounds;
|
||||||
use crate::traits::{self, AssocTypeBoundData};
|
use crate::traits::{self, AssocTypeBoundData};
|
||||||
use rustc::middle::lang_items;
|
use rustc::middle::lang_items;
|
||||||
use rustc::ty::subst::SubstsRef;
|
use rustc::ty::subst::SubstsRef;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue