1
Fork 0

Split librustc_infer.

This commit is contained in:
Camille GILLOT 2020-02-22 11:44:18 +01:00
parent c1e3d556bf
commit 0535dd3721
32 changed files with 1846 additions and 1065 deletions

View file

@ -4129,11 +4129,13 @@ name = "rustc_trait_selection"
version = "0.0.0"
dependencies = [
"fmt_macros",
"graphviz",
"log",
"rustc",
"rustc_ast",
"rustc_attr",
"rustc_data_structures",
"rustc_error_codes",
"rustc_errors",
"rustc_hir",
"rustc_index",

View file

@ -14,7 +14,7 @@ use crate::infer::canonical::{
};
use crate::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelatingDelegate};
use crate::infer::region_constraints::{Constraint, RegionConstraintData};
use crate::infer::{InferCtxt, InferCtxtBuilder, InferOk, InferResult, NLLRegionVariableOrigin};
use crate::infer::{InferCtxt, InferOk, InferResult, NLLRegionVariableOrigin};
use crate::traits::query::{Fallible, NoSolution};
use crate::traits::{DomainGoal, TraitEngine};
use crate::traits::{Obligation, ObligationCause, PredicateObligation};
@ -26,52 +26,8 @@ use rustc::ty::{self, BoundVar, Ty, TyCtxt};
use rustc_data_structures::captures::Captures;
use rustc_index::vec::Idx;
use rustc_index::vec::IndexVec;
use rustc_span::DUMMY_SP;
use std::fmt::Debug;
impl<'tcx> InferCtxtBuilder<'tcx> {
/// The "main method" for a canonicalized trait query. Given the
/// canonical key `canonical_key`, this method will create a new
/// inference context, instantiate the key, and run your operation
/// `op`. The operation should yield up a result (of type `R`) as
/// well as a set of trait obligations that must be fully
/// satisfied. These obligations will be processed and the
/// canonical result created.
///
/// Returns `NoSolution` in the event of any error.
///
/// (It might be mildly nicer to implement this on `TyCtxt`, and
/// not `InferCtxtBuilder`, but that is a bit tricky right now.
/// In part because we would need a `for<'tcx>` sort of
/// bound for the closure and in part because it is convenient to
/// have `'tcx` be free on this function so that we can talk about
/// `K: TypeFoldable<'tcx>`.)
pub fn enter_canonical_trait_query<K, R>(
&mut self,
canonical_key: &Canonical<'tcx, K>,
operation: impl FnOnce(&InferCtxt<'_, 'tcx>, &mut dyn TraitEngine<'tcx>, K) -> Fallible<R>,
) -> Fallible<CanonicalizedQueryResponse<'tcx, R>>
where
K: TypeFoldable<'tcx>,
R: Debug + TypeFoldable<'tcx>,
Canonical<'tcx, QueryResponse<'tcx, R>>: ArenaAllocatable,
{
self.enter_with_canonical(
DUMMY_SP,
canonical_key,
|ref infcx, key, canonical_inference_vars| {
let mut fulfill_cx = TraitEngine::new(infcx.tcx);
let value = operation(infcx, &mut *fulfill_cx, key)?;
infcx.make_canonicalized_query_response(
canonical_inference_vars,
value,
&mut *fulfill_cx,
)
},
)
}
}
impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
/// This method is meant to be invoked as the final step of a canonical query
/// implementation. It is given:

View file

@ -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
/// extra information about each type, but we only care about the category.
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
crate enum TyCategory {
pub enum TyCategory {
Closure,
Opaque,
Generator,

View file

@ -13,11 +13,11 @@ use rustc::infer::canonical::{Canonical, CanonicalVarValues};
use rustc::infer::unify_key::{ConstVarValue, ConstVariableValue};
use rustc::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType};
use rustc::middle::free_region::RegionRelations;
use rustc::middle::lang_items;
use rustc::middle::region;
use rustc::mir;
use rustc::mir::interpret::ConstEvalResult;
use rustc::session::config::BorrowckMode;
use rustc::traits::select;
use rustc::ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric};
use rustc::ty::fold::{TypeFoldable, TypeFolder};
use rustc::ty::relate::RelateResult;
@ -58,7 +58,6 @@ pub mod lattice;
mod lexical_region_resolve;
mod lub;
pub mod nll_relate;
pub mod opaque_types;
pub mod outlives;
pub mod region_constraints;
pub mod resolve;
@ -215,10 +214,10 @@ pub struct InferCtxt<'a, 'tcx> {
/// Caches the results of trait selection. This cache is used
/// for things that have to do with the parameters in scope.
pub selection_cache: traits::SelectionCache<'tcx>,
pub selection_cache: select::SelectionCache<'tcx>,
/// Caches the results of trait evaluation.
pub evaluation_cache: traits::EvaluationCache<'tcx>,
pub evaluation_cache: select::EvaluationCache<'tcx>,
/// the set of predicates on which errors have been reported, to
/// avoid reporting the same error twice.
@ -1474,27 +1473,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
.verify_generic_bound(origin, kind, a, bound);
}
pub fn type_is_copy_modulo_regions(
&self,
param_env: ty::ParamEnv<'tcx>,
ty: Ty<'tcx>,
span: Span,
) -> bool {
let ty = self.resolve_vars_if_possible(&ty);
if !(param_env, ty).has_local_value() {
return ty.is_copy_modulo_regions(self.tcx, param_env, span);
}
let copy_def_id = self.tcx.require_lang_item(lang_items::CopyTraitLangItem, None);
// This can get called from typeck (by euv), and `moves_by_default`
// rightly refuses to work with inference variables, but
// moves_by_default has a cache, which we want to use in other
// cases.
traits::type_known_to_meet_bound_modulo_regions(self, param_env, ty, copy_def_id, span)
}
/// Obtains the latest type of the given closure; this may be a
/// closure in the current function, in which case its
/// `ClosureKind` may not yet be known.
@ -1518,30 +1496,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
closure_sig_ty.fn_sig(self.tcx)
}
/// Normalizes associated types in `value`, potentially returning
/// new obligations that must further be processed.
pub fn partially_normalize_associated_types_in<T>(
&self,
span: Span,
body_id: hir::HirId,
param_env: ty::ParamEnv<'tcx>,
value: &T,
) -> InferOk<'tcx, T>
where
T: TypeFoldable<'tcx>,
{
debug!("partially_normalize_associated_types_in(value={:?})", value);
let mut selcx = traits::SelectionContext::new(self);
let cause = ObligationCause::misc(span, body_id);
let traits::Normalized { value, obligations } =
traits::normalize(&mut selcx, param_env, cause, value);
debug!(
"partially_normalize_associated_types_in: result={:?} predicates={:?}",
value, obligations
);
InferOk { value, obligations }
}
/// Clears the selection, evaluation, and projection caches. This is useful when
/// repeatedly attempting to select an `Obligation` while changing only
/// its `ParamEnv`, since `FulfillmentContext` doesn't use probing.

View file

@ -1,10 +1,9 @@
use crate::infer::{GenericKind, InferCtxt};
use crate::traits::query::OutlivesBound;
use rustc::ty;
use rustc::ty::free_region_map::FreeRegionMap;
use rustc::ty::{self, Ty};
use rustc_data_structures::fx::FxHashMap;
use rustc_hir as hir;
use rustc_span::Span;
use super::explicit_outlives_bounds;
@ -144,39 +143,6 @@ impl<'a, 'tcx> OutlivesEnvironment<'tcx> {
self.region_bound_pairs_accum.truncate(len);
}
/// This method adds "implied bounds" into the outlives environment.
/// Implied bounds are outlives relationships that we can deduce
/// on the basis that certain types must be well-formed -- these are
/// either the types that appear in the function signature or else
/// the input types to an impl. For example, if you have a function
/// like
///
/// ```
/// fn foo<'a, 'b, T>(x: &'a &'b [T]) { }
/// ```
///
/// we can assume in the caller's body that `'b: 'a` and that `T:
/// 'b` (and hence, transitively, that `T: 'a`). This method would
/// add those assumptions into the outlives-environment.
///
/// Tests: `src/test/compile-fail/regions-free-region-ordering-*.rs`
pub fn add_implied_bounds(
&mut self,
infcx: &InferCtxt<'a, 'tcx>,
fn_sig_tys: &[Ty<'tcx>],
body_id: hir::HirId,
span: Span,
) {
debug!("add_implied_bounds()");
for &ty in fn_sig_tys {
let ty = infcx.resolve_vars_if_possible(&ty);
debug!("add_implied_bounds: ty = {}", ty);
let implied_bounds = infcx.implied_outlives_bounds(self.param_env, body_id, ty, span);
self.add_outlives_bounds(Some(infcx), implied_bounds)
}
}
/// Save the current set of region-bound pairs under the given `body_id`.
pub fn save_implied_bounds(&mut self, body_id: hir::HirId) {
let old =
@ -190,8 +156,11 @@ impl<'a, 'tcx> OutlivesEnvironment<'tcx> {
/// contain inference variables, it must be supplied, in which
/// case we will register "givens" on the inference context. (See
/// `RegionConstraintData`.)
fn add_outlives_bounds<I>(&mut self, infcx: Option<&InferCtxt<'a, 'tcx>>, outlives_bounds: I)
where
pub fn add_outlives_bounds<I>(
&mut self,
infcx: Option<&InferCtxt<'a, 'tcx>>,
outlives_bounds: I,
) where
I: IntoIterator<Item = OutlivesBound<'tcx>>,
{
// Record relationships such as `T:'x` that don't go into the

View 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);
}
}
}

View 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(&note);
}
(Some(_), Some((note, Some((sugg, span))))) => {
err.span_suggestion(span, &note, 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
}

View 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())
}
}

View file

@ -65,7 +65,13 @@ pub struct ProjectionCache<'tcx> {
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
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)]

View file

@ -1,5 +1,5 @@
use crate::traits;
use crate::traits::Normalized;
use crate::traits::project::Normalized;
use rustc::ty;
use rustc::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};

View 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
}
}
}

View file

@ -11,12 +11,14 @@ doctest = false
[dependencies]
fmt_macros = { path = "../libfmt_macros" }
graphviz = { path = "../libgraphviz" }
log = { version = "0.4", features = ["release_max_level_info", "std"] }
rustc_attr = { path = "../librustc_attr" }
rustc = { path = "../librustc" }
rustc_ast = { path = "../librustc_ast" }
rustc_data_structures = { path = "../librustc_data_structures" }
rustc_errors = { path = "../librustc_errors" }
rustc_error_codes = { path = "../librustc_error_codes" }
rustc_hir = { path = "../librustc_hir" }
rustc_index = { path = "../librustc_index" }
rustc_infer = { path = "../librustc_infer" }

View 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)
}
}
}

View 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;

View file

@ -1,5 +1,4 @@
use crate::infer::error_reporting::unexpected_hidden_region_diagnostic;
use crate::infer::{self, InferCtxt, InferOk, TypeVariableOrigin, TypeVariableOriginKind};
use crate::infer::InferCtxtExt as _;
use crate::traits::{self, PredicateObligation};
use rustc::session::config::nightly_options;
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::def_id::{DefId, DefIdMap};
use rustc_hir::Node;
use rustc_infer::infer::error_reporting::unexpected_hidden_region_diagnostic;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::{self, InferCtxt, InferOk};
use rustc_span::Span;
pub type OpaqueTypeMap<'tcx> = DefIdMap<OpaqueTypeDecl<'tcx>>;
@ -103,7 +105,58 @@ pub enum GenerateMemberConstraints {
IfNoStaticBound,
}
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
pub trait InferCtxtExt<'tcx> {
fn instantiate_opaque_types<T: TypeFoldable<'tcx>>(
&self,
parent_def_id: DefId,
body_id: hir::HirId,
param_env: ty::ParamEnv<'tcx>,
value: &T,
value_span: Span,
) -> InferOk<'tcx, (T, OpaqueTypeMap<'tcx>)>;
fn constrain_opaque_types<FRR: FreeRegionRelations<'tcx>>(
&self,
opaque_types: &OpaqueTypeMap<'tcx>,
free_region_relations: &FRR,
);
fn constrain_opaque_type<FRR: FreeRegionRelations<'tcx>>(
&self,
def_id: DefId,
opaque_defn: &OpaqueTypeDecl<'tcx>,
mode: GenerateMemberConstraints,
free_region_relations: &FRR,
);
/*private*/
fn generate_member_constraint(
&self,
concrete_ty: Ty<'tcx>,
opaque_type_generics: &ty::Generics,
opaque_defn: &OpaqueTypeDecl<'tcx>,
opaque_type_def_id: DefId,
);
/*private*/
fn member_constraint_feature_gate(
&self,
opaque_defn: &OpaqueTypeDecl<'tcx>,
opaque_type_def_id: DefId,
conflict1: ty::Region<'tcx>,
conflict2: ty::Region<'tcx>,
) -> bool;
fn infer_opaque_definition_from_instantiation(
&self,
def_id: DefId,
substs: SubstsRef<'tcx>,
instantiated_ty: Ty<'tcx>,
span: Span,
) -> Ty<'tcx>;
}
impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
/// Replaces all opaque types in `value` with fresh inference variables
/// and creates appropriate obligations. For example, given the input:
///
@ -129,7 +182,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
/// obligations
/// - `value` -- the value within which we are instantiating opaque types
/// - `value_span` -- the span where the value came from, used in error reporting
pub fn instantiate_opaque_types<T: TypeFoldable<'tcx>>(
fn instantiate_opaque_types<T: TypeFoldable<'tcx>>(
&self,
parent_def_id: DefId,
body_id: hir::HirId,
@ -317,7 +370,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
/// - `opaque_types` -- the map produced by `instantiate_opaque_types`
/// - `free_region_relations` -- something that can be used to relate
/// the free regions (`'a`) that appear in the impl trait.
pub fn constrain_opaque_types<FRR: FreeRegionRelations<'tcx>>(
fn constrain_opaque_types<FRR: FreeRegionRelations<'tcx>>(
&self,
opaque_types: &OpaqueTypeMap<'tcx>,
free_region_relations: &FRR,
@ -335,7 +388,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}
/// See `constrain_opaque_types` for documentation.
pub fn constrain_opaque_type<FRR: FreeRegionRelations<'tcx>>(
fn constrain_opaque_type<FRR: FreeRegionRelations<'tcx>>(
&self,
def_id: DefId,
opaque_defn: &OpaqueTypeDecl<'tcx>,
@ -577,7 +630,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
/// - `substs`, the substs used to instantiate this opaque type
/// - `instantiated_ty`, the inferred type C1 -- fully resolved, lifted version of
/// `opaque_defn.concrete_ty`
pub fn infer_opaque_definition_from_instantiation(
fn infer_opaque_definition_from_instantiation(
&self,
def_id: DefId,
substs: SubstsRef<'tcx>,

View file

@ -72,7 +72,7 @@ pub fn codegen_fulfill_obligation<'tcx>(
debug!("fulfill_obligation: register_predicate_obligation {:?}", predicate);
fulfill_cx.register_predicate_obligation(&infcx, predicate);
});
let vtable = infcx.drain_fulfillment_cx_or_panic(&mut fulfill_cx, &vtable);
let vtable = drain_fulfillment_cx_or_panic(&infcx, &mut fulfill_cx, &vtable);
info!("Cache miss: {:?} => {:?}", trait_ref, vtable);
Some(vtable)
@ -81,7 +81,6 @@ pub fn codegen_fulfill_obligation<'tcx>(
// # Global Cache
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
/// Finishes processes any obligations that remain in the
/// fulfillment context, and then returns the result with all type
/// variables removed and regions erased. Because this is intended
@ -92,7 +91,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
/// unified, and hence we need to process those obligations to get
/// the complete picture of the type.
fn drain_fulfillment_cx_or_panic<T>(
&self,
infcx: &InferCtxt<'_, 'tcx>,
fulfill_cx: &mut FulfillmentContext<'tcx>,
result: &T,
) -> T
@ -104,11 +103,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
// In principle, we only need to do this so long as `result`
// contains unbound type parameters. It could be a slight
// optimization to stop iterating early.
if let Err(errors) = fulfill_cx.select_all_or_error(self) {
if let Err(errors) = fulfill_cx.select_all_or_error(infcx) {
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)
}

View file

@ -1,84 +1,14 @@
use crate::infer::InferCtxt;
use crate::traits::Obligation;
use rustc::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness};
use rustc_hir::def_id::DefId;
use rustc::ty::TyCtxt;
use super::{FulfillmentContext, FulfillmentError};
use super::{ObligationCause, PredicateObligation};
pub trait TraitEngine<'tcx>: 'tcx {
fn normalize_projection_type(
&mut self,
infcx: &InferCtxt<'_, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
projection_ty: ty::ProjectionTy<'tcx>,
cause: ObligationCause<'tcx>,
) -> Ty<'tcx>;
/// Requires that `ty` must implement the trait with `def_id` in
/// the given environment. This trait must not have any type
/// parameters (except for `Self`).
fn register_bound(
&mut self,
infcx: &InferCtxt<'_, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
ty: Ty<'tcx>,
def_id: DefId,
cause: ObligationCause<'tcx>,
) {
let trait_ref = ty::TraitRef { def_id, substs: infcx.tcx.mk_substs_trait(ty, &[]) };
self.register_predicate_obligation(
infcx,
Obligation {
cause,
recursion_depth: 0,
param_env,
predicate: trait_ref.without_const().to_predicate(),
},
);
}
fn register_predicate_obligation(
&mut self,
infcx: &InferCtxt<'_, 'tcx>,
obligation: PredicateObligation<'tcx>,
);
fn select_all_or_error(
&mut self,
infcx: &InferCtxt<'_, 'tcx>,
) -> Result<(), Vec<FulfillmentError<'tcx>>>;
fn select_where_possible(
&mut self,
infcx: &InferCtxt<'_, 'tcx>,
) -> Result<(), Vec<FulfillmentError<'tcx>>>;
fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>>;
}
use super::FulfillmentContext;
use super::TraitEngine;
pub trait TraitEngineExt<'tcx> {
fn register_predicate_obligations(
&mut self,
infcx: &InferCtxt<'_, 'tcx>,
obligations: impl IntoIterator<Item = PredicateObligation<'tcx>>,
);
fn new(tcx: TyCtxt<'tcx>) -> Box<Self>;
}
impl<T: ?Sized + TraitEngine<'tcx>> TraitEngineExt<'tcx> for T {
fn register_predicate_obligations(
&mut self,
infcx: &InferCtxt<'_, 'tcx>,
obligations: impl IntoIterator<Item = PredicateObligation<'tcx>>,
) {
for obligation in obligations {
self.register_predicate_obligation(infcx, obligation);
}
}
}
impl dyn TraitEngine<'tcx> {
pub fn new(_tcx: TyCtxt<'tcx>) -> Box<Self> {
impl<'tcx> TraitEngineExt<'tcx> for dyn TraitEngine<'tcx> {
fn new(_tcx: TyCtxt<'tcx>) -> Box<Self> {
Box::new(FulfillmentContext::new())
}
}

File diff suppressed because it is too large Load diff

View file

@ -8,7 +8,27 @@ use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_span::symbol::sym;
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
use super::InferCtxtPrivExt;
crate trait InferCtxtExt<'tcx> {
/*private*/
fn impl_similar_to(
&self,
trait_ref: ty::PolyTraitRef<'tcx>,
obligation: &PredicateObligation<'tcx>,
) -> Option<DefId>;
/*private*/
fn describe_enclosure(&self, hir_id: hir::HirId) -> Option<&'static str>;
fn on_unimplemented_note(
&self,
trait_ref: ty::PolyTraitRef<'tcx>,
obligation: &PredicateObligation<'tcx>,
) -> OnUnimplementedNote;
}
impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
fn impl_similar_to(
&self,
trait_ref: ty::PolyTraitRef<'tcx>,
@ -101,7 +121,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}
}
crate fn on_unimplemented_note(
fn on_unimplemented_note(
&self,
trait_ref: ty::PolyTraitRef<'tcx>,
obligation: &PredicateObligation<'tcx>,

View file

@ -1,6 +1,5 @@
use super::{
ArgKind, EvaluationResult, Obligation, ObligationCause, ObligationCauseCode,
PredicateObligation,
EvaluationResult, Obligation, ObligationCause, ObligationCauseCode, PredicateObligation,
};
use crate::infer::InferCtxt;
@ -8,9 +7,7 @@ use crate::traits::error_reporting::suggest_constraining_type_param;
use rustc::ty::TypeckTables;
use rustc::ty::{self, AdtKind, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
use rustc_errors::{
error_code, pluralize, struct_span_err, Applicability, DiagnosticBuilder, Style,
};
use rustc_errors::{error_code, struct_span_err, Applicability, DiagnosticBuilder, Style};
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::DefId;
@ -20,8 +17,136 @@ use rustc_span::symbol::{kw, sym};
use rustc_span::{MultiSpan, Span, DUMMY_SP};
use std::fmt;
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
crate fn suggest_restricting_param_bound(
use super::InferCtxtPrivExt;
use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
crate trait InferCtxtExt<'tcx> {
fn suggest_restricting_param_bound(
&self,
err: &mut DiagnosticBuilder<'_>,
trait_ref: &ty::PolyTraitRef<'_>,
body_id: hir::HirId,
);
fn suggest_borrow_on_unsized_slice(
&self,
code: &ObligationCauseCode<'tcx>,
err: &mut DiagnosticBuilder<'tcx>,
);
fn get_closure_name(
&self,
def_id: DefId,
err: &mut DiagnosticBuilder<'_>,
msg: &str,
) -> Option<String>;
fn suggest_fn_call(
&self,
obligation: &PredicateObligation<'tcx>,
err: &mut DiagnosticBuilder<'_>,
trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
points_at_arg: bool,
);
fn suggest_add_reference_to_arg(
&self,
obligation: &PredicateObligation<'tcx>,
err: &mut DiagnosticBuilder<'tcx>,
trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
points_at_arg: bool,
has_custom_message: bool,
) -> bool;
fn suggest_remove_reference(
&self,
obligation: &PredicateObligation<'tcx>,
err: &mut DiagnosticBuilder<'tcx>,
trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
);
fn suggest_change_mut(
&self,
obligation: &PredicateObligation<'tcx>,
err: &mut DiagnosticBuilder<'tcx>,
trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
points_at_arg: bool,
);
fn suggest_semicolon_removal(
&self,
obligation: &PredicateObligation<'tcx>,
err: &mut DiagnosticBuilder<'tcx>,
span: Span,
trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
);
fn suggest_impl_trait(
&self,
err: &mut DiagnosticBuilder<'tcx>,
span: Span,
obligation: &PredicateObligation<'tcx>,
trait_ref: &ty::Binder<ty::TraitRef<'tcx>>,
) -> bool;
fn point_at_returns_when_relevant(
&self,
err: &mut DiagnosticBuilder<'tcx>,
obligation: &PredicateObligation<'tcx>,
);
fn report_closure_arg_mismatch(
&self,
span: Span,
found_span: Option<Span>,
expected_ref: ty::PolyTraitRef<'tcx>,
found: ty::PolyTraitRef<'tcx>,
) -> DiagnosticBuilder<'tcx>;
fn suggest_fully_qualified_path(
&self,
err: &mut DiagnosticBuilder<'_>,
def_id: DefId,
span: Span,
trait_ref: DefId,
);
fn maybe_note_obligation_cause_for_async_await(
&self,
err: &mut DiagnosticBuilder<'_>,
obligation: &PredicateObligation<'tcx>,
) -> bool;
fn note_obligation_cause_for_async_await(
&self,
err: &mut DiagnosticBuilder<'_>,
target_span: Span,
scope_span: &Option<Span>,
expr: Option<hir::HirId>,
snippet: String,
first_generator: DefId,
last_generator: Option<DefId>,
trait_ref: ty::TraitRef<'_>,
target_ty: Ty<'tcx>,
tables: &ty::TypeckTables<'_>,
obligation: &PredicateObligation<'tcx>,
next_code: Option<&ObligationCauseCode<'tcx>>,
);
fn note_obligation_cause_code<T>(
&self,
err: &mut DiagnosticBuilder<'_>,
predicate: &T,
cause_code: &ObligationCauseCode<'tcx>,
obligated_types: &mut Vec<&ty::TyS<'tcx>>,
) where
T: fmt::Display;
fn suggest_new_overflow_limit(&self, err: &mut DiagnosticBuilder<'_>);
}
impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
fn suggest_restricting_param_bound(
&self,
mut err: &mut DiagnosticBuilder<'_>,
trait_ref: &ty::PolyTraitRef<'_>,
@ -168,7 +293,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
/// When encountering an assignment of an unsized trait, like `let x = ""[..];`, provide a
/// suggestion to borrow the initializer in order to use have a slice instead.
crate fn suggest_borrow_on_unsized_slice(
fn suggest_borrow_on_unsized_slice(
&self,
code: &ObligationCauseCode<'tcx>,
err: &mut DiagnosticBuilder<'tcx>,
@ -195,7 +320,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
/// Given a closure's `DefId`, return the given name of the closure.
///
/// This doesn't account for reassignments, but it's only used for suggestions.
crate fn get_closure_name(
fn get_closure_name(
&self,
def_id: DefId,
err: &mut DiagnosticBuilder<'_>,
@ -233,7 +358,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
/// We tried to apply the bound to an `fn` or closure. Check whether calling it would
/// evaluate to a type that *would* satisfy the trait binding. If it would, suggest calling
/// it: `bar(foo)` → `bar(foo())`. This case is *very* likely to be hit if `foo` is `async`.
crate fn suggest_fn_call(
fn suggest_fn_call(
&self,
obligation: &PredicateObligation<'tcx>,
err: &mut DiagnosticBuilder<'_>,
@ -317,7 +442,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}
}
crate fn suggest_add_reference_to_arg(
fn suggest_add_reference_to_arg(
&self,
obligation: &PredicateObligation<'tcx>,
err: &mut DiagnosticBuilder<'tcx>,
@ -389,7 +514,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
/// Whenever references are used by mistake, like `for (i, e) in &vec.iter().enumerate()`,
/// suggest removing these references until we reach a type that implements the trait.
crate fn suggest_remove_reference(
fn suggest_remove_reference(
&self,
obligation: &PredicateObligation<'tcx>,
err: &mut DiagnosticBuilder<'tcx>,
@ -451,7 +576,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
/// Check if the trait bound is implemented for a different mutability and note it in the
/// final error.
crate fn suggest_change_mut(
fn suggest_change_mut(
&self,
obligation: &PredicateObligation<'tcx>,
err: &mut DiagnosticBuilder<'tcx>,
@ -513,7 +638,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}
}
crate fn suggest_semicolon_removal(
fn suggest_semicolon_removal(
&self,
obligation: &PredicateObligation<'tcx>,
err: &mut DiagnosticBuilder<'tcx>,
@ -549,7 +674,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
/// If all conditions are met to identify a returned `dyn Trait`, suggest using `impl Trait` if
/// applicable and signal that the error has been expanded appropriately and needs to be
/// emitted.
crate fn suggest_impl_trait(
fn suggest_impl_trait(
&self,
err: &mut DiagnosticBuilder<'tcx>,
span: Span,
@ -723,7 +848,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
true
}
crate fn point_at_returns_when_relevant(
fn point_at_returns_when_relevant(
&self,
err: &mut DiagnosticBuilder<'tcx>,
obligation: &PredicateObligation<'tcx>,
@ -753,220 +878,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}
}
/// Given some node representing a fn-like thing in the HIR map,
/// returns a span and `ArgKind` information that describes the
/// arguments it expects. This can be supplied to
/// `report_arg_count_mismatch`.
pub fn get_fn_like_arguments(&self, node: Node<'_>) -> (Span, Vec<ArgKind>) {
match node {
Node::Expr(&hir::Expr {
kind: hir::ExprKind::Closure(_, ref _decl, id, span, _),
..
}) => (
self.tcx.sess.source_map().def_span(span),
self.tcx
.hir()
.body(id)
.params
.iter()
.map(|arg| {
if let hir::Pat { kind: hir::PatKind::Tuple(ref args, _), span, .. } =
*arg.pat
{
ArgKind::Tuple(
Some(span),
args.iter()
.map(|pat| {
let snippet = self
.tcx
.sess
.source_map()
.span_to_snippet(pat.span)
.unwrap();
(snippet, "_".to_owned())
})
.collect::<Vec<_>>(),
)
} else {
let name =
self.tcx.sess.source_map().span_to_snippet(arg.pat.span).unwrap();
ArgKind::Arg(name, "_".to_owned())
}
})
.collect::<Vec<ArgKind>>(),
),
Node::Item(&hir::Item { span, kind: hir::ItemKind::Fn(ref sig, ..), .. })
| Node::ImplItem(&hir::ImplItem {
span,
kind: hir::ImplItemKind::Method(ref sig, _),
..
})
| Node::TraitItem(&hir::TraitItem {
span,
kind: hir::TraitItemKind::Fn(ref sig, _),
..
}) => (
self.tcx.sess.source_map().def_span(span),
sig.decl
.inputs
.iter()
.map(|arg| match arg.clone().kind {
hir::TyKind::Tup(ref tys) => ArgKind::Tuple(
Some(arg.span),
vec![("_".to_owned(), "_".to_owned()); tys.len()],
),
_ => ArgKind::empty(),
})
.collect::<Vec<ArgKind>>(),
),
Node::Ctor(ref variant_data) => {
let span = variant_data
.ctor_hir_id()
.map(|hir_id| self.tcx.hir().span(hir_id))
.unwrap_or(DUMMY_SP);
let span = self.tcx.sess.source_map().def_span(span);
(span, vec![ArgKind::empty(); variant_data.fields().len()])
}
_ => panic!("non-FnLike node found: {:?}", node),
}
}
/// Reports an error when the number of arguments needed by a
/// trait match doesn't match the number that the expression
/// provides.
pub fn report_arg_count_mismatch(
&self,
span: Span,
found_span: Option<Span>,
expected_args: Vec<ArgKind>,
found_args: Vec<ArgKind>,
is_closure: bool,
) -> DiagnosticBuilder<'tcx> {
let kind = if is_closure { "closure" } else { "function" };
let args_str = |arguments: &[ArgKind], other: &[ArgKind]| {
let arg_length = arguments.len();
let distinct = match &other[..] {
&[ArgKind::Tuple(..)] => true,
_ => false,
};
match (arg_length, arguments.get(0)) {
(1, Some(&ArgKind::Tuple(_, ref fields))) => {
format!("a single {}-tuple as argument", fields.len())
}
_ => format!(
"{} {}argument{}",
arg_length,
if distinct && arg_length > 1 { "distinct " } else { "" },
pluralize!(arg_length)
),
}
};
let expected_str = args_str(&expected_args, &found_args);
let found_str = args_str(&found_args, &expected_args);
let mut err = struct_span_err!(
self.tcx.sess,
span,
E0593,
"{} is expected to take {}, but it takes {}",
kind,
expected_str,
found_str,
);
err.span_label(span, format!("expected {} that takes {}", kind, expected_str));
if let Some(found_span) = found_span {
err.span_label(found_span, format!("takes {}", found_str));
// move |_| { ... }
// ^^^^^^^^-- def_span
//
// move |_| { ... }
// ^^^^^-- prefix
let prefix_span = self.tcx.sess.source_map().span_until_non_whitespace(found_span);
// move |_| { ... }
// ^^^-- pipe_span
let pipe_span =
if let Some(span) = found_span.trim_start(prefix_span) { span } else { found_span };
// Suggest to take and ignore the arguments with expected_args_length `_`s if
// found arguments is empty (assume the user just wants to ignore args in this case).
// For example, if `expected_args_length` is 2, suggest `|_, _|`.
if found_args.is_empty() && is_closure {
let underscores = vec!["_"; expected_args.len()].join(", ");
err.span_suggestion(
pipe_span,
&format!(
"consider changing the closure to take and ignore the expected argument{}",
if expected_args.len() < 2 { "" } else { "s" }
),
format!("|{}|", underscores),
Applicability::MachineApplicable,
);
}
if let &[ArgKind::Tuple(_, ref fields)] = &found_args[..] {
if fields.len() == expected_args.len() {
let sugg = fields
.iter()
.map(|(name, _)| name.to_owned())
.collect::<Vec<String>>()
.join(", ");
err.span_suggestion(
found_span,
"change the closure to take multiple arguments instead of a single tuple",
format!("|{}|", sugg),
Applicability::MachineApplicable,
);
}
}
if let &[ArgKind::Tuple(_, ref fields)] = &expected_args[..] {
if fields.len() == found_args.len() && is_closure {
let sugg = format!(
"|({}){}|",
found_args
.iter()
.map(|arg| match arg {
ArgKind::Arg(name, _) => name.to_owned(),
_ => "_".to_owned(),
})
.collect::<Vec<String>>()
.join(", "),
// add type annotations if available
if found_args.iter().any(|arg| match arg {
ArgKind::Arg(_, ty) => ty != "_",
_ => false,
}) {
format!(
": ({})",
fields
.iter()
.map(|(_, ty)| ty.to_owned())
.collect::<Vec<String>>()
.join(", ")
)
} else {
String::new()
},
);
err.span_suggestion(
found_span,
"change the closure to accept a tuple instead of individual arguments",
sugg,
Applicability::MachineApplicable,
);
}
}
}
err
}
crate fn report_closure_arg_mismatch(
fn report_closure_arg_mismatch(
&self,
span: Span,
found_span: Option<Span>,
@ -1022,10 +934,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
err
}
}
impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
crate fn suggest_fully_qualified_path(
fn suggest_fully_qualified_path(
&self,
err: &mut DiagnosticBuilder<'_>,
def_id: DefId,
@ -1091,7 +1001,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
/// ```
///
/// Returns `true` if an async-await specific note was added to the diagnostic.
crate fn maybe_note_obligation_cause_for_async_await(
fn maybe_note_obligation_cause_for_async_await(
&self,
err: &mut DiagnosticBuilder<'_>,
obligation: &PredicateObligation<'tcx>,
@ -1271,7 +1181,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
/// Unconditionally adds the diagnostic note described in
/// `maybe_note_obligation_cause_for_async_await`'s documentation comment.
crate fn note_obligation_cause_for_async_await(
fn note_obligation_cause_for_async_await(
&self,
err: &mut DiagnosticBuilder<'_>,
target_span: Span,
@ -1423,7 +1333,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
);
}
crate fn note_obligation_cause_code<T>(
fn note_obligation_cause_code<T>(
&self,
err: &mut DiagnosticBuilder<'_>,
predicate: &T,
@ -1638,7 +1548,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}
}
crate fn suggest_new_overflow_limit(&self, err: &mut DiagnosticBuilder<'_>) {
fn suggest_new_overflow_limit(&self, err: &mut DiagnosticBuilder<'_>) {
let current_limit = self.tcx.sess.recursion_limit.get();
let suggested_limit = current_limit * 2;
err.help(&format!(

View file

@ -4,9 +4,9 @@ use rustc::ty::{self, ToPolyTraitRef, Ty, TypeFoldable};
use rustc_data_structures::obligation_forest::ProcessResult;
use rustc_data_structures::obligation_forest::{DoCompleted, Error, ForestObligation};
use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor};
use rustc_infer::traits::{TraitEngine, TraitEngineExt as _};
use std::marker::PhantomData;
use super::engine::{TraitEngine, TraitEngineExt};
use super::project;
use super::select::SelectionContext;
use super::wf;
@ -17,6 +17,9 @@ use super::{ConstEvalFailure, Unimplemented};
use super::{FulfillmentError, FulfillmentErrorCode};
use super::{ObligationCause, PredicateObligation};
use crate::traits::error_reporting::InferCtxtExt as _;
use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
impl<'tcx> ForestObligation for PendingPredicateObligation<'tcx> {
/// Note that we include both the `ParamEnv` and the `Predicate`,
/// as the `ParamEnv` can influence whether fulfillment succeeds

View file

@ -1,10 +1,13 @@
//! Miscellaneous type-system utilities that are too small to deserve their own modules.
use crate::infer::TyCtxtInferExt;
use crate::infer::InferCtxtExt as _;
use crate::traits::{self, ObligationCause};
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
use rustc_hir as hir;
use rustc_infer::infer::TyCtxtInferExt;
use crate::traits::error_reporting::InferCtxtExt;
#[derive(Clone)]
pub enum CopyImplementationError<'tcx> {

View file

@ -13,19 +13,18 @@ pub mod misc;
mod object_safety;
mod on_unimplemented;
mod project;
mod projection_cache;
pub mod query;
mod select;
mod specialize;
mod structural_impls;
mod structural_match;
mod util;
pub mod wf;
use crate::infer::outlives::env::OutlivesEnvironment;
use crate::infer::{InferCtxt, SuppressRegionErrors, TyCtxtInferExt};
use crate::traits::error_reporting::InferCtxtExt as _;
use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
use rustc::middle::region;
use rustc::ty::error::{ExpectedFound, TypeError};
use rustc::ty::fold::TypeFoldable;
use rustc::ty::subst::{InternalSubsts, SubstsRef};
use rustc::ty::{self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, WithConstness};
@ -43,7 +42,7 @@ pub use self::Vtable::*;
pub use self::coherence::{add_placeholder_note, orphan_check, overlapping_impls};
pub use self::coherence::{OrphanCheckErr, OverlapResult};
pub use self::engine::{TraitEngine, TraitEngineExt};
pub use self::engine::TraitEngineExt;
pub use self::fulfill::{FulfillmentContext, PendingPredicateObligation};
pub use self::object_safety::astconv_object_safety_violations;
pub use self::object_safety::is_vtable_safe_method;
@ -53,11 +52,6 @@ pub use self::on_unimplemented::{OnUnimplementedDirective, OnUnimplementedNote};
pub use self::project::{
normalize, normalize_projection_type, normalize_to, poly_project_and_unify_type,
};
pub use self::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::{EvaluationResult, IntercrateAmbiguityCause, OverflowError};
pub use self::specialize::find_associated_item;
@ -77,7 +71,7 @@ pub use self::util::{
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.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
@ -114,61 +108,6 @@ pub enum TraitQueryMode {
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.
pub fn predicates_for_generics<'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<'_>) {
object_safety::provide(providers);
*providers = ty::query::Providers {

View file

@ -11,6 +11,7 @@
use super::elaborate_predicates;
use crate::infer::TyCtxtInferExt;
use crate::traits::query::evaluate_obligation::InferCtxtExt;
use crate::traits::{self, Obligation, ObligationCause};
use rustc::ty::subst::{InternalSubsts, Subst};
use rustc::ty::{self, Predicate, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};

View file

@ -1,7 +1,6 @@
//! Code for projecting associated types out of trait references.
use super::elaborate_predicates;
use super::projection_cache::NormalizedTy;
use super::specialization_graph;
use super::translate_substs;
use super::util;
@ -12,11 +11,12 @@ use super::PredicateObligation;
use super::Selection;
use super::SelectionContext;
use super::SelectionError;
use super::{Normalized, ProjectionCacheEntry, ProjectionCacheKey};
use super::{Normalized, NormalizedTy, ProjectionCacheEntry, ProjectionCacheKey};
use super::{VtableClosureData, VtableFnPointerData, VtableGeneratorData, VtableImplData};
use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use crate::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime};
use crate::traits::error_reporting::InferCtxtExt;
use rustc::ty::fold::{TypeFoldable, TypeFolder};
use rustc::ty::subst::{InternalSubsts, Subst};
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 projection_ty = infcx.resolve_vars_if_possible(&projection_ty);
let cache_key = ProjectionCacheKey { ty: projection_ty };
let cache_key = ProjectionCacheKey::new(projection_ty);
debug!(
"opt_normalize_projection_type(\
@ -1483,20 +1483,29 @@ fn assoc_ty_def(
}
}
impl<'cx, 'tcx> ProjectionCacheKey<'tcx> {
pub fn from_poly_projection_predicate(
crate trait ProjectionCacheKeyExt<'tcx>: Sized {
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>,
predicate: &ty::PolyProjectionPredicate<'tcx>,
) -> Option<Self> {
let infcx = selcx.infcx();
// We don't do cross-snapshot caching of obligations with escaping regions,
// so there's no cache key to use
predicate.no_bound_vars().map(|predicate| ProjectionCacheKey {
predicate.no_bound_vars().map(|predicate| {
ProjectionCacheKey::new(
// We don't attempt to match up with a specific type-variable state
// from a specific call to `opt_normalize_projection_type` - if
// there's no precise match, the original cache entry is "stranded"
// anyway.
ty: infcx.resolve_vars_if_possible(&predicate.projection_ty),
infcx.resolve_vars_if_possible(&predicate.projection_ty),
)
})
}
}

View file

@ -7,7 +7,11 @@ use rustc::ty::{self, Ty, TyCtxt};
pub use rustc::traits::query::{DropckOutlivesResult, DtorckConstraint};
impl<'cx, 'tcx> At<'cx, 'tcx> {
pub trait AtExt<'tcx> {
fn dropck_outlives(&self, ty: Ty<'tcx>) -> InferOk<'tcx, Vec<GenericArg<'tcx>>>;
}
impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> {
/// Given a type `ty` of some value being dropped, computes a set
/// of "kinds" (types, regions) that must be outlive the execution
/// of the destructor. These basically correspond to data that the
@ -25,7 +29,7 @@ impl<'cx, 'tcx> At<'cx, 'tcx> {
///
/// [#1238]: https://github.com/rust-lang/rfcs/blob/master/text/1238-nonparametric-dropck.md
/// [#1327]: https://github.com/rust-lang/rfcs/blob/master/text/1327-dropck-param-eyepatch.md
pub fn dropck_outlives(&self, ty: Ty<'tcx>) -> InferOk<'tcx, Vec<GenericArg<'tcx>>> {
fn dropck_outlives(&self, ty: Ty<'tcx>) -> InferOk<'tcx, Vec<GenericArg<'tcx>>> {
debug!("dropck_outlives(ty={:?}, param_env={:?})", ty, self.param_env,);
// Quick check: there are a number of cases that we know do not require

View file

@ -4,10 +4,35 @@ use crate::traits::{
EvaluationResult, OverflowError, PredicateObligation, SelectionContext, TraitQueryMode,
};
impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
pub trait InferCtxtExt<'tcx> {
fn predicate_may_hold(&self, obligation: &PredicateObligation<'tcx>) -> bool;
fn predicate_must_hold_considering_regions(
&self,
obligation: &PredicateObligation<'tcx>,
) -> bool;
fn predicate_must_hold_modulo_regions(&self, obligation: &PredicateObligation<'tcx>) -> bool;
fn evaluate_obligation(
&self,
obligation: &PredicateObligation<'tcx>,
) -> Result<EvaluationResult, OverflowError>;
// Helper function that canonicalizes and runs the query. If an
// overflow results, we re-run it in the local context so we can
// report a nice error.
/*crate*/
fn evaluate_obligation_no_overflow(
&self,
obligation: &PredicateObligation<'tcx>,
) -> EvaluationResult;
}
impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
/// Evaluates whether the predicate can be satisfied (by any means)
/// in the given `ParamEnv`.
pub fn predicate_may_hold(&self, obligation: &PredicateObligation<'tcx>) -> bool {
fn predicate_may_hold(&self, obligation: &PredicateObligation<'tcx>) -> bool {
self.evaluate_obligation_no_overflow(obligation).may_apply()
}
@ -17,7 +42,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
///
/// This version may conservatively fail when outlives obligations
/// are required.
pub fn predicate_must_hold_considering_regions(
fn predicate_must_hold_considering_regions(
&self,
obligation: &PredicateObligation<'tcx>,
) -> bool {
@ -29,15 +54,12 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
/// not entirely accurate if inference variables are involved.
///
/// This version ignores all outlives constraints.
pub fn predicate_must_hold_modulo_regions(
&self,
obligation: &PredicateObligation<'tcx>,
) -> bool {
fn predicate_must_hold_modulo_regions(&self, obligation: &PredicateObligation<'tcx>) -> bool {
self.evaluate_obligation_no_overflow(obligation).must_apply_modulo_regions()
}
/// Evaluate a given predicate, capturing overflow and propagating it back.
pub fn evaluate_obligation(
fn evaluate_obligation(
&self,
obligation: &PredicateObligation<'tcx>,
) -> Result<EvaluationResult, OverflowError> {
@ -53,7 +75,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
// Helper function that canonicalizes and runs the query. If an
// overflow results, we re-run it in the local context so we can
// report a nice error.
crate fn evaluate_obligation_no_overflow(
fn evaluate_obligation_no_overflow(
&self,
obligation: &PredicateObligation<'tcx>,
) -> EvaluationResult {

View file

@ -5,17 +5,24 @@
use crate::infer::at::At;
use crate::infer::canonical::OriginalQueryValues;
use crate::infer::{InferCtxt, InferOk};
use crate::traits::Normalized;
use crate::traits::error_reporting::InferCtxtExt;
use crate::traits::{Obligation, ObligationCause, PredicateObligation, Reveal};
use rustc::ty::fold::{TypeFoldable, TypeFolder};
use rustc::ty::subst::Subst;
use rustc::ty::{self, Ty, TyCtxt};
use rustc_infer::traits::Normalized;
use super::NoSolution;
pub use rustc::traits::query::NormalizationResult;
impl<'cx, 'tcx> At<'cx, 'tcx> {
pub trait AtExt<'tcx> {
fn normalize<T>(&self, value: &T) -> Result<Normalized<'tcx, T>, NoSolution>
where
T: TypeFoldable<'tcx>;
}
impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> {
/// Normalize `value` in the context of the inference context,
/// yielding a resulting type, or an error if `value` cannot be
/// normalized. If you don't care about regions, you should prefer
@ -29,7 +36,7 @@ impl<'cx, 'tcx> At<'cx, 'tcx> {
/// normalizing, but for now should be used only when we actually
/// know that normalization will succeed, since error reporting
/// and other details are still "under development".
pub fn normalize<T>(&self, value: &T) -> Result<Normalized<'tcx, T>, NoSolution>
fn normalize<T>(&self, value: &T) -> Result<Normalized<'tcx, T>, NoSolution>
where
T: TypeFoldable<'tcx>,
{

View file

@ -1,14 +1,25 @@
use crate::infer::canonical::OriginalQueryValues;
use crate::infer::InferCtxt;
use crate::traits::query::NoSolution;
use crate::traits::{FulfillmentContext, ObligationCause, TraitEngine, TraitEngineExt};
use crate::traits::{FulfillmentContext, ObligationCause, TraitEngine};
use rustc::ty::{self, Ty};
use rustc_hir as hir;
use rustc_infer::traits::TraitEngineExt as _;
use rustc_span::source_map::Span;
pub use rustc::traits::query::OutlivesBound;
impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
pub trait InferCtxtExt<'tcx> {
fn implied_outlives_bounds(
&self,
param_env: ty::ParamEnv<'tcx>,
body_id: hir::HirId,
ty: Ty<'tcx>,
span: Span,
) -> Vec<OutlivesBound<'tcx>>;
}
impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
/// Implied bounds are region relationships that we deduce
/// automatically. The idea is that (e.g.) a caller must check that a
/// function's argument types are well-formed immediately before
@ -30,7 +41,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
/// - `ty`, the type that we are supposed to assume is WF.
/// - `span`, a span to use when normalizing, hopefully not important,
/// might be useful if a `bug!` occurs.
pub fn implied_outlives_bounds(
fn implied_outlives_bounds(
&self,
param_env: ty::ParamEnv<'tcx>,
body_id: hir::HirId,

View file

@ -4,7 +4,9 @@ use std::fmt;
use crate::infer::canonical::query_response;
use crate::infer::canonical::QueryRegionConstraints;
use crate::traits::{ObligationCause, TraitEngine, TraitEngineExt};
use crate::traits::engine::TraitEngineExt as _;
use crate::traits::{ObligationCause, TraitEngine};
use rustc_infer::traits::TraitEngineExt as _;
use rustc_span::source_map::DUMMY_SP;
use std::rc::Rc;

View file

@ -33,6 +33,8 @@ use super::{
};
use crate::infer::{CombinedSnapshot, InferCtxt, InferOk, PlaceholderMap, TypeFreshener};
use crate::traits::error_reporting::InferCtxtExt;
use crate::traits::project::ProjectionCacheKeyExt;
use rustc::dep_graph::{DepKind, DepNodeIndex};
use rustc::middle::lang_items;
use rustc::ty::fast_reject;
@ -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)]
pub fn derived_cause(
fn derived_cause(
&self,
variant: fn(DerivedObligationCause<'tcx>) -> ObligationCauseCode<'tcx>,
) -> ObligationCause<'tcx> {

View file

@ -1,5 +1,5 @@
use crate::infer::opaque_types::required_region_bounds;
use crate::infer::InferCtxt;
use crate::opaque_types::required_region_bounds;
use crate::traits::{self, AssocTypeBoundData};
use rustc::middle::lang_items;
use rustc::ty::subst::SubstsRef;