Auto merge of #48995 - aravind-pg:canonical-query, r=nikomatsakis
Create a canonical trait query for `evaluate_obligation` This builds on the canonical query machinery introduced in #48411 to introduce a new canonical trait query for `evaluate_obligation` in the trait selector. Also ports most callers of the original `evaluate_obligation` to the new system (except in coherence, which requires support for intercrate mode). Closes #48537. r? @nikomatsakis
This commit is contained in:
commit
8a09bc6a77
@ -70,7 +70,8 @@ use rustc_data_structures::stable_hasher::{StableHasher, HashStable};
|
||||
use std::fmt;
|
||||
use std::hash::Hash;
|
||||
use syntax_pos::symbol::InternedString;
|
||||
use traits::query::{CanonicalProjectionGoal, CanonicalTyGoal};
|
||||
use traits::query::{CanonicalProjectionGoal,
|
||||
CanonicalTyGoal, CanonicalPredicateGoal};
|
||||
use ty::{TyCtxt, Instance, InstanceDef, ParamEnv, ParamEnvAnd, PolyTraitRef, Ty};
|
||||
use ty::subst::Substs;
|
||||
|
||||
@ -643,6 +644,7 @@ define_dep_nodes!( <'tcx>
|
||||
[] NormalizeProjectionTy(CanonicalProjectionGoal<'tcx>),
|
||||
[] NormalizeTyAfterErasingRegions(ParamEnvAnd<'tcx, Ty<'tcx>>),
|
||||
[] DropckOutlives(CanonicalTyGoal<'tcx>),
|
||||
[] EvaluateObligation(CanonicalPredicateGoal<'tcx>),
|
||||
|
||||
[] SubstituteNormalizeAndTestPredicates { key: (DefId, &'tcx Substs<'tcx>) },
|
||||
|
||||
|
@ -154,7 +154,10 @@ fn overlap<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
|
||||
recursion_depth: 0,
|
||||
predicate: p })
|
||||
.chain(obligations)
|
||||
.find(|o| !selcx.evaluate_obligation(o));
|
||||
.find(|o| !selcx.predicate_may_hold_fatal(o));
|
||||
// FIXME: the call to `selcx.predicate_may_hold_fatal` above should be ported
|
||||
// to the canonical trait query form, `infcx.predicate_may_hold`, once
|
||||
// the new system supports intercrate mode (which coherence needs).
|
||||
|
||||
if let Some(failing_obligation) = opt_failing_obligation {
|
||||
debug!("overlap: obligation unsatisfiable {:?}", failing_obligation);
|
||||
|
@ -24,6 +24,7 @@ use super::{
|
||||
SelectionContext,
|
||||
SelectionError,
|
||||
ObjectSafetyViolation,
|
||||
Overflow,
|
||||
};
|
||||
|
||||
use errors::DiagnosticBuilder;
|
||||
@ -659,8 +660,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
predicate: ty::Predicate::Trait(predicate),
|
||||
.. obligation.clone()
|
||||
};
|
||||
let mut selcx = SelectionContext::new(self);
|
||||
if selcx.evaluate_obligation(&unit_obligation) {
|
||||
if self.predicate_may_hold(&unit_obligation) {
|
||||
err.note("the trait is implemented for `()`. \
|
||||
Possibly this error has been caused by changes to \
|
||||
Rust's type-inference algorithm \
|
||||
@ -830,6 +830,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
err.struct_error(self.tcx, span, "constant expression")
|
||||
}
|
||||
|
||||
Overflow => {
|
||||
bug!("overflow should be handled before the `report_selection_error` path");
|
||||
}
|
||||
};
|
||||
self.note_obligation_cause(&mut err, obligation);
|
||||
err.emit();
|
||||
@ -872,7 +876,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
.count();
|
||||
|
||||
let mut trait_type = trait_ref.self_ty();
|
||||
let mut selcx = SelectionContext::new(self);
|
||||
|
||||
for refs_remaining in 0..refs_number {
|
||||
if let ty::TypeVariants::TyRef(_, ty::TypeAndMut{ ty: t_type, mutbl: _ }) =
|
||||
@ -886,7 +889,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
obligation.param_env,
|
||||
new_trait_ref.to_predicate());
|
||||
|
||||
if selcx.evaluate_obligation(&new_obligation) {
|
||||
if self.predicate_may_hold(&new_obligation) {
|
||||
let sp = self.tcx.sess.codemap()
|
||||
.span_take_while(span, |c| c.is_whitespace() || *c == '&');
|
||||
|
||||
@ -1322,7 +1325,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
cleaned_pred.to_predicate()
|
||||
);
|
||||
|
||||
selcx.evaluate_obligation(&obligation)
|
||||
self.predicate_may_hold(&obligation)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -333,7 +333,7 @@ fn process_predicate<'a, 'gcx, 'tcx>(
|
||||
if data.is_global() {
|
||||
// no type variables present, can use evaluation for better caching.
|
||||
// FIXME: consider caching errors too.
|
||||
if selcx.evaluate_obligation_conservatively(&obligation) {
|
||||
if selcx.infcx().predicate_must_hold(&obligation) {
|
||||
debug!("selecting trait `{:?}` at depth {} evaluated to holds",
|
||||
data, obligation.recursion_depth);
|
||||
return Ok(Some(vec![]))
|
||||
|
@ -41,7 +41,7 @@ pub use self::object_safety::ObjectSafetyViolation;
|
||||
pub use self::object_safety::MethodViolationCode;
|
||||
pub use self::on_unimplemented::{OnUnimplementedDirective, OnUnimplementedNote};
|
||||
pub use self::select::{EvaluationCache, SelectionContext, SelectionCache};
|
||||
pub use self::select::IntercrateAmbiguityCause;
|
||||
pub use self::select::{EvaluationResult, IntercrateAmbiguityCause, OverflowError};
|
||||
pub use self::specialize::{OverlapError, specialization_graph, translate_substs};
|
||||
pub use self::specialize::{SpecializesCache, find_associated_item};
|
||||
pub use self::engine::TraitEngine;
|
||||
@ -74,6 +74,19 @@ pub enum IntercrateMode {
|
||||
Fixed
|
||||
}
|
||||
|
||||
// The mode that trait queries run in
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
pub enum TraitQueryMode {
|
||||
// Standard/un-canonicalized queries get accurate
|
||||
// spans etc. passed in and hence can do reasonable
|
||||
// error reporting on their own.
|
||||
Standard,
|
||||
// Canonicalized queries get dummy spans and hence
|
||||
// must generally propagate errors to
|
||||
// pre-canonicalization callsites.
|
||||
Canonical,
|
||||
}
|
||||
|
||||
/// An `Obligation` represents some trait reference (e.g. `int:Eq`) for
|
||||
/// which the vtable must be found. The process of finding a vtable is
|
||||
/// called "resolving" the `Obligation`. This process consists of
|
||||
@ -349,6 +362,7 @@ pub enum SelectionError<'tcx> {
|
||||
ty::error::TypeError<'tcx>),
|
||||
TraitNotObjectSafe(DefId),
|
||||
ConstEvalFailure(ConstEvalErr<'tcx>),
|
||||
Overflow,
|
||||
}
|
||||
|
||||
pub struct FulfillmentError<'tcx> {
|
||||
@ -550,8 +564,7 @@ pub fn type_known_to_meet_bound<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx
|
||||
predicate: trait_ref.to_predicate(),
|
||||
};
|
||||
|
||||
let result = SelectionContext::new(infcx)
|
||||
.evaluate_obligation_conservatively(&obligation);
|
||||
let result = infcx.predicate_must_hold(&obligation);
|
||||
debug!("type_known_to_meet_ty={:?} bound={} => {:?}",
|
||||
ty, infcx.tcx.item_path_str(def_id), result);
|
||||
|
||||
|
70
src/librustc/traits/query/evaluate_obligation.rs
Normal file
70
src/librustc/traits/query/evaluate_obligation.rs
Normal file
@ -0,0 +1,70 @@
|
||||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use infer::InferCtxt;
|
||||
use infer::canonical::{Canonical, Canonicalize};
|
||||
use traits::{EvaluationResult, PredicateObligation, SelectionContext,
|
||||
TraitQueryMode, OverflowError};
|
||||
use traits::query::CanonicalPredicateGoal;
|
||||
use ty::{ParamEnvAnd, Predicate, TyCtxt};
|
||||
|
||||
impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
|
||||
/// Evaluates whether the predicate can be satisfied (by any means)
|
||||
/// in the given `ParamEnv`.
|
||||
pub fn predicate_may_hold(
|
||||
&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
) -> bool {
|
||||
self.evaluate_obligation(obligation).may_apply()
|
||||
}
|
||||
|
||||
/// Evaluates whether the predicate can be satisfied in the given
|
||||
/// `ParamEnv`, and returns `false` if not certain. However, this is
|
||||
/// not entirely accurate if inference variables are involved.
|
||||
pub fn predicate_must_hold(
|
||||
&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
) -> bool {
|
||||
self.evaluate_obligation(obligation) == EvaluationResult::EvaluatedToOk
|
||||
}
|
||||
|
||||
// Helper function that canonicalizes and runs the query, as well as handles
|
||||
// overflow.
|
||||
fn evaluate_obligation(
|
||||
&self,
|
||||
obligation: &PredicateObligation<'tcx>,
|
||||
) -> EvaluationResult {
|
||||
let (c_pred, _) =
|
||||
self.canonicalize_query(&obligation.param_env.and(obligation.predicate));
|
||||
// Run canonical query. If overflow occurs, rerun from scratch but this time
|
||||
// in standard trait query mode so that overflow is handled appropriately
|
||||
// within `SelectionContext`.
|
||||
match self.tcx.global_tcx().evaluate_obligation(c_pred) {
|
||||
Ok(result) => result,
|
||||
Err(OverflowError) => {
|
||||
let mut selcx =
|
||||
SelectionContext::with_query_mode(&self, TraitQueryMode::Standard);
|
||||
selcx.evaluate_obligation_recursively(obligation)
|
||||
.expect("Overflow should be caught earlier in standard query mode")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'gcx: 'tcx, 'tcx> Canonicalize<'gcx, 'tcx> for ParamEnvAnd<'tcx, Predicate<'tcx>> {
|
||||
type Canonicalized = CanonicalPredicateGoal<'gcx>;
|
||||
|
||||
fn intern(
|
||||
_gcx: TyCtxt<'_, 'gcx, 'gcx>,
|
||||
value: Canonical<'gcx, Self::Lifted>,
|
||||
) -> Self::Canonicalized {
|
||||
value
|
||||
}
|
||||
}
|
@ -19,6 +19,7 @@ use infer::canonical::Canonical;
|
||||
use ty::{self, Ty};
|
||||
|
||||
pub mod dropck_outlives;
|
||||
pub mod evaluate_obligation;
|
||||
pub mod normalize;
|
||||
pub mod normalize_erasing_regions;
|
||||
|
||||
@ -27,6 +28,9 @@ pub type CanonicalProjectionGoal<'tcx> =
|
||||
|
||||
pub type CanonicalTyGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, Ty<'tcx>>>;
|
||||
|
||||
pub type CanonicalPredicateGoal<'tcx> =
|
||||
Canonical<'tcx, ty::ParamEnvAnd<'tcx, ty::Predicate<'tcx>>>;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct NoSolution;
|
||||
|
||||
|
@ -17,12 +17,12 @@ use self::EvaluationResult::*;
|
||||
|
||||
use super::coherence::{self, Conflict};
|
||||
use super::DerivedObligationCause;
|
||||
use super::IntercrateMode;
|
||||
use super::{IntercrateMode, TraitQueryMode};
|
||||
use super::project;
|
||||
use super::project::{normalize_with_depth, Normalized, ProjectionCacheKey};
|
||||
use super::{PredicateObligation, TraitObligation, ObligationCause};
|
||||
use super::{ObligationCauseCode, BuiltinDerivedObligation, ImplDerivedObligation};
|
||||
use super::{SelectionError, Unimplemented, OutputTypeParameterMismatch};
|
||||
use super::{SelectionError, Unimplemented, OutputTypeParameterMismatch, Overflow};
|
||||
use super::{ObjectCastObligation, Obligation};
|
||||
use super::TraitNotObjectSafe;
|
||||
use super::Selection;
|
||||
@ -87,7 +87,12 @@ pub struct SelectionContext<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> {
|
||||
/// Controls whether or not to filter out negative impls when selecting.
|
||||
/// This is used in librustdoc to distinguish between the lack of an impl
|
||||
/// and a negative impl
|
||||
allow_negative_impls: bool
|
||||
allow_negative_impls: bool,
|
||||
|
||||
/// The mode that trait queries run in, which informs our error handling
|
||||
/// policy. In essence, canonicalized queries need their errors propagated
|
||||
/// rather than immediately reported because we do not have accurate spans.
|
||||
query_mode: TraitQueryMode,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
@ -319,7 +324,7 @@ enum BuiltinImplConditions<'tcx> {
|
||||
/// all the "potential success" candidates can potentially succeed,
|
||||
/// so they are no-ops when unioned with a definite error, and within
|
||||
/// the categories it's easy to see that the unions are correct.
|
||||
enum EvaluationResult {
|
||||
pub enum EvaluationResult {
|
||||
/// Evaluation successful
|
||||
EvaluatedToOk,
|
||||
/// Evaluation is known to be ambiguous - it *might* hold for some
|
||||
@ -385,7 +390,7 @@ enum EvaluationResult {
|
||||
}
|
||||
|
||||
impl EvaluationResult {
|
||||
fn may_apply(self) -> bool {
|
||||
pub fn may_apply(self) -> bool {
|
||||
match self {
|
||||
EvaluatedToOk |
|
||||
EvaluatedToAmbig |
|
||||
@ -408,6 +413,26 @@ impl EvaluationResult {
|
||||
}
|
||||
}
|
||||
|
||||
impl_stable_hash_for!(enum self::EvaluationResult {
|
||||
EvaluatedToOk,
|
||||
EvaluatedToAmbig,
|
||||
EvaluatedToUnknown,
|
||||
EvaluatedToRecur,
|
||||
EvaluatedToErr
|
||||
});
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
/// Indicates that trait evaluation caused overflow.
|
||||
pub struct OverflowError;
|
||||
|
||||
impl_stable_hash_for!(struct OverflowError { });
|
||||
|
||||
impl<'tcx> From<OverflowError> for SelectionError<'tcx> {
|
||||
fn from(OverflowError: OverflowError) -> SelectionError<'tcx> {
|
||||
SelectionError::Overflow
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct EvaluationCache<'tcx> {
|
||||
hashmap: RefCell<FxHashMap<ty::PolyTraitRef<'tcx>, WithDepNode<EvaluationResult>>>
|
||||
@ -421,6 +446,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
intercrate: None,
|
||||
intercrate_ambiguity_causes: None,
|
||||
allow_negative_impls: false,
|
||||
query_mode: TraitQueryMode::Standard,
|
||||
}
|
||||
}
|
||||
|
||||
@ -433,6 +459,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
intercrate: Some(mode),
|
||||
intercrate_ambiguity_causes: None,
|
||||
allow_negative_impls: false,
|
||||
query_mode: TraitQueryMode::Standard,
|
||||
}
|
||||
}
|
||||
|
||||
@ -445,6 +472,20 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
intercrate: None,
|
||||
intercrate_ambiguity_causes: None,
|
||||
allow_negative_impls,
|
||||
query_mode: TraitQueryMode::Standard,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_query_mode(infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
|
||||
query_mode: TraitQueryMode) -> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
debug!("with_query_mode({:?})", query_mode);
|
||||
SelectionContext {
|
||||
infcx,
|
||||
freshener: infcx.freshener(),
|
||||
intercrate: None,
|
||||
intercrate_ambiguity_causes: None,
|
||||
allow_negative_impls: false,
|
||||
query_mode,
|
||||
}
|
||||
}
|
||||
|
||||
@ -528,12 +569,27 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
assert!(!obligation.predicate.has_escaping_regions());
|
||||
|
||||
let stack = self.push_stack(TraitObligationStackList::empty(), obligation);
|
||||
let ret = match self.candidate_from_obligation(&stack)? {
|
||||
None => None,
|
||||
Some(candidate) => Some(self.confirm_candidate(obligation, candidate)?)
|
||||
|
||||
let candidate = match self.candidate_from_obligation(&stack) {
|
||||
Err(SelectionError::Overflow) => {
|
||||
// In standard mode, overflow must have been caught and reported
|
||||
// earlier.
|
||||
assert!(self.query_mode == TraitQueryMode::Canonical);
|
||||
return Err(SelectionError::Overflow);
|
||||
},
|
||||
Err(e) => { return Err(e); },
|
||||
Ok(None) => { return Ok(None); },
|
||||
Ok(Some(candidate)) => candidate
|
||||
};
|
||||
|
||||
Ok(ret)
|
||||
match self.confirm_candidate(obligation, candidate) {
|
||||
Err(SelectionError::Overflow) => {
|
||||
assert!(self.query_mode == TraitQueryMode::Canonical);
|
||||
return Err(SelectionError::Overflow);
|
||||
},
|
||||
Err(e) => Err(e),
|
||||
Ok(candidate) => Ok(Some(candidate))
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
@ -547,32 +603,30 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
// we can be sure it does not.
|
||||
|
||||
/// Evaluates whether the obligation `obligation` can be satisfied (by any means).
|
||||
pub fn evaluate_obligation(&mut self,
|
||||
obligation: &PredicateObligation<'tcx>)
|
||||
-> bool
|
||||
pub fn predicate_may_hold_fatal(&mut self,
|
||||
obligation: &PredicateObligation<'tcx>)
|
||||
-> bool
|
||||
{
|
||||
debug!("evaluate_obligation({:?})",
|
||||
debug!("predicate_may_hold_fatal({:?})",
|
||||
obligation);
|
||||
|
||||
self.probe(|this, _| {
|
||||
this.evaluate_predicate_recursively(TraitObligationStackList::empty(), obligation)
|
||||
.may_apply()
|
||||
})
|
||||
// This fatal query is a stopgap that should only be used in standard mode,
|
||||
// where we do not expect overflow to be propagated.
|
||||
assert!(self.query_mode == TraitQueryMode::Standard);
|
||||
|
||||
self.evaluate_obligation_recursively(obligation)
|
||||
.expect("Overflow should be caught earlier in standard query mode")
|
||||
.may_apply()
|
||||
}
|
||||
|
||||
/// Evaluates whether the obligation `obligation` can be satisfied,
|
||||
/// and returns `false` if not certain. However, this is not entirely
|
||||
/// accurate if inference variables are involved.
|
||||
pub fn evaluate_obligation_conservatively(&mut self,
|
||||
obligation: &PredicateObligation<'tcx>)
|
||||
-> bool
|
||||
/// Evaluates whether the obligation `obligation` can be satisfied and returns
|
||||
/// an `EvaluationResult`.
|
||||
pub fn evaluate_obligation_recursively(&mut self,
|
||||
obligation: &PredicateObligation<'tcx>)
|
||||
-> Result<EvaluationResult, OverflowError>
|
||||
{
|
||||
debug!("evaluate_obligation_conservatively({:?})",
|
||||
obligation);
|
||||
|
||||
self.probe(|this, _| {
|
||||
this.evaluate_predicate_recursively(TraitObligationStackList::empty(), obligation)
|
||||
== EvaluatedToOk
|
||||
})
|
||||
}
|
||||
|
||||
@ -582,29 +636,29 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
fn evaluate_predicates_recursively<'a,'o,I>(&mut self,
|
||||
stack: TraitObligationStackList<'o, 'tcx>,
|
||||
predicates: I)
|
||||
-> EvaluationResult
|
||||
-> Result<EvaluationResult, OverflowError>
|
||||
where I : IntoIterator<Item=&'a PredicateObligation<'tcx>>, 'tcx:'a
|
||||
{
|
||||
let mut result = EvaluatedToOk;
|
||||
for obligation in predicates {
|
||||
let eval = self.evaluate_predicate_recursively(stack, obligation);
|
||||
let eval = self.evaluate_predicate_recursively(stack, obligation)?;
|
||||
debug!("evaluate_predicate_recursively({:?}) = {:?}",
|
||||
obligation, eval);
|
||||
if let EvaluatedToErr = eval {
|
||||
// fast-path - EvaluatedToErr is the top of the lattice,
|
||||
// so we don't need to look on the other predicates.
|
||||
return EvaluatedToErr;
|
||||
return Ok(EvaluatedToErr);
|
||||
} else {
|
||||
result = cmp::max(result, eval);
|
||||
}
|
||||
}
|
||||
result
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
fn evaluate_predicate_recursively<'o>(&mut self,
|
||||
previous_stack: TraitObligationStackList<'o, 'tcx>,
|
||||
obligation: &PredicateObligation<'tcx>)
|
||||
-> EvaluationResult
|
||||
-> Result<EvaluationResult, OverflowError>
|
||||
{
|
||||
debug!("evaluate_predicate_recursively({:?})",
|
||||
obligation);
|
||||
@ -620,11 +674,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
// does this code ever run?
|
||||
match self.infcx.subtype_predicate(&obligation.cause, obligation.param_env, p) {
|
||||
Some(Ok(InferOk { obligations, .. })) => {
|
||||
self.evaluate_predicates_recursively(previous_stack, &obligations);
|
||||
EvaluatedToOk
|
||||
self.evaluate_predicates_recursively(previous_stack, &obligations)
|
||||
},
|
||||
Some(Err(_)) => EvaluatedToErr,
|
||||
None => EvaluatedToAmbig,
|
||||
Some(Err(_)) => Ok(EvaluatedToErr),
|
||||
None => Ok(EvaluatedToAmbig),
|
||||
}
|
||||
}
|
||||
|
||||
@ -636,21 +689,21 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
Some(obligations) =>
|
||||
self.evaluate_predicates_recursively(previous_stack, obligations.iter()),
|
||||
None =>
|
||||
EvaluatedToAmbig,
|
||||
Ok(EvaluatedToAmbig),
|
||||
}
|
||||
}
|
||||
|
||||
ty::Predicate::TypeOutlives(..) | ty::Predicate::RegionOutlives(..) => {
|
||||
// we do not consider region relationships when
|
||||
// evaluating trait matches
|
||||
EvaluatedToOk
|
||||
Ok(EvaluatedToOk)
|
||||
}
|
||||
|
||||
ty::Predicate::ObjectSafe(trait_def_id) => {
|
||||
if self.tcx().is_object_safe(trait_def_id) {
|
||||
EvaluatedToOk
|
||||
Ok(EvaluatedToOk)
|
||||
} else {
|
||||
EvaluatedToErr
|
||||
Ok(EvaluatedToErr)
|
||||
}
|
||||
}
|
||||
|
||||
@ -668,10 +721,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
result
|
||||
}
|
||||
Ok(None) => {
|
||||
EvaluatedToAmbig
|
||||
Ok(EvaluatedToAmbig)
|
||||
}
|
||||
Err(_) => {
|
||||
EvaluatedToErr
|
||||
Ok(EvaluatedToErr)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -680,13 +733,13 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
match self.infcx.closure_kind(closure_def_id, closure_substs) {
|
||||
Some(closure_kind) => {
|
||||
if closure_kind.extends(kind) {
|
||||
EvaluatedToOk
|
||||
Ok(EvaluatedToOk)
|
||||
} else {
|
||||
EvaluatedToErr
|
||||
Ok(EvaluatedToErr)
|
||||
}
|
||||
}
|
||||
None => {
|
||||
EvaluatedToAmbig
|
||||
Ok(EvaluatedToAmbig)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -707,16 +760,16 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
promoted: None
|
||||
};
|
||||
match self.tcx().const_eval(param_env.and(cid)) {
|
||||
Ok(_) => EvaluatedToOk,
|
||||
Err(_) => EvaluatedToErr
|
||||
Ok(_) => Ok(EvaluatedToOk),
|
||||
Err(_) => Ok(EvaluatedToErr)
|
||||
}
|
||||
} else {
|
||||
EvaluatedToErr
|
||||
Ok(EvaluatedToErr)
|
||||
}
|
||||
}
|
||||
None => {
|
||||
// Inference variables still left in param_env or substs.
|
||||
EvaluatedToAmbig
|
||||
Ok(EvaluatedToAmbig)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -726,7 +779,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
fn evaluate_trait_predicate_recursively<'o>(&mut self,
|
||||
previous_stack: TraitObligationStackList<'o, 'tcx>,
|
||||
mut obligation: TraitObligation<'tcx>)
|
||||
-> EvaluationResult
|
||||
-> Result<EvaluationResult, OverflowError>
|
||||
{
|
||||
debug!("evaluate_trait_predicate_recursively({:?})",
|
||||
obligation);
|
||||
@ -745,22 +798,23 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
debug!("CACHE HIT: EVAL({:?})={:?}",
|
||||
fresh_trait_ref,
|
||||
result);
|
||||
return result;
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
let (result, dep_node) = self.in_task(|this| this.evaluate_stack(&stack));
|
||||
let result = result?;
|
||||
|
||||
debug!("CACHE MISS: EVAL({:?})={:?}",
|
||||
fresh_trait_ref,
|
||||
result);
|
||||
self.insert_evaluation_cache(obligation.param_env, fresh_trait_ref, dep_node, result);
|
||||
|
||||
result
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
fn evaluate_stack<'o>(&mut self,
|
||||
stack: &TraitObligationStack<'o, 'tcx>)
|
||||
-> EvaluationResult
|
||||
-> Result<EvaluationResult, OverflowError>
|
||||
{
|
||||
// In intercrate mode, whenever any of the types are unbound,
|
||||
// there can always be an impl. Even if there are no impls in
|
||||
@ -815,7 +869,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
}
|
||||
}
|
||||
}
|
||||
return EvaluatedToAmbig;
|
||||
return Ok(EvaluatedToAmbig);
|
||||
}
|
||||
if unbound_input_types &&
|
||||
stack.iter().skip(1).any(
|
||||
@ -825,7 +879,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
{
|
||||
debug!("evaluate_stack({:?}) --> unbound argument, recursive --> giving up",
|
||||
stack.fresh_trait_ref);
|
||||
return EvaluatedToUnknown;
|
||||
return Ok(EvaluatedToUnknown);
|
||||
}
|
||||
|
||||
// If there is any previous entry on the stack that precisely
|
||||
@ -860,18 +914,19 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
if self.coinductive_match(cycle) {
|
||||
debug!("evaluate_stack({:?}) --> recursive, coinductive",
|
||||
stack.fresh_trait_ref);
|
||||
return EvaluatedToOk;
|
||||
return Ok(EvaluatedToOk);
|
||||
} else {
|
||||
debug!("evaluate_stack({:?}) --> recursive, inductive",
|
||||
stack.fresh_trait_ref);
|
||||
return EvaluatedToRecur;
|
||||
return Ok(EvaluatedToRecur);
|
||||
}
|
||||
}
|
||||
|
||||
match self.candidate_from_obligation(stack) {
|
||||
Ok(Some(c)) => self.evaluate_candidate(stack, &c),
|
||||
Ok(None) => EvaluatedToAmbig,
|
||||
Err(..) => EvaluatedToErr
|
||||
Ok(None) => Ok(EvaluatedToAmbig),
|
||||
Err(Overflow) => Err(OverflowError),
|
||||
Err(..) => Ok(EvaluatedToErr)
|
||||
}
|
||||
}
|
||||
|
||||
@ -909,7 +964,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
fn evaluate_candidate<'o>(&mut self,
|
||||
stack: &TraitObligationStack<'o, 'tcx>,
|
||||
candidate: &SelectionCandidate<'tcx>)
|
||||
-> EvaluationResult
|
||||
-> Result<EvaluationResult, OverflowError>
|
||||
{
|
||||
debug!("evaluate_candidate: depth={} candidate={:?}",
|
||||
stack.obligation.recursion_depth, candidate);
|
||||
@ -921,12 +976,12 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
stack.list(),
|
||||
selection.nested_obligations().iter())
|
||||
}
|
||||
Err(..) => EvaluatedToErr
|
||||
Err(..) => Ok(EvaluatedToErr)
|
||||
}
|
||||
});
|
||||
})?;
|
||||
debug!("evaluate_candidate: depth={} result={:?}",
|
||||
stack.obligation.recursion_depth, result);
|
||||
result
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
fn check_evaluation_cache(&self,
|
||||
@ -1000,7 +1055,14 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
// not update) the cache.
|
||||
let recursion_limit = *self.infcx.tcx.sess.recursion_limit.get();
|
||||
if stack.obligation.recursion_depth >= recursion_limit {
|
||||
self.infcx().report_overflow_error(&stack.obligation, true);
|
||||
match self.query_mode {
|
||||
TraitQueryMode::Standard => {
|
||||
self.infcx().report_overflow_error(&stack.obligation, true);
|
||||
},
|
||||
TraitQueryMode::Canonical => {
|
||||
return Err(Overflow);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Check the cache. Note that we skolemize the trait-ref
|
||||
@ -1081,9 +1143,15 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
debug!("evaluate_stack: intercrate_ambiguity_causes is some");
|
||||
// Heuristics: show the diagnostics when there are no candidates in crate.
|
||||
if let Ok(candidate_set) = self.assemble_candidates(stack) {
|
||||
if !candidate_set.ambiguous && candidate_set.vec.iter().all(|c| {
|
||||
!self.evaluate_candidate(stack, &c).may_apply()
|
||||
}) {
|
||||
let no_candidates_apply =
|
||||
candidate_set
|
||||
.vec
|
||||
.iter()
|
||||
.map(|c| self.evaluate_candidate(stack, &c))
|
||||
.collect::<Result<Vec<_>, OverflowError>>()?
|
||||
.iter()
|
||||
.all(|r| !r.may_apply());
|
||||
if !candidate_set.ambiguous && no_candidates_apply {
|
||||
let trait_ref = stack.obligation.predicate.skip_binder().trait_ref;
|
||||
let self_ty = trait_ref.self_ty();
|
||||
let trait_desc = trait_ref.to_string();
|
||||
@ -1151,18 +1219,21 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
}
|
||||
|
||||
// Winnow, but record the exact outcome of evaluation, which
|
||||
// is needed for specialization.
|
||||
let mut candidates: Vec<_> = candidates.into_iter().filter_map(|c| {
|
||||
let eval = self.evaluate_candidate(stack, &c);
|
||||
if eval.may_apply() {
|
||||
Some(EvaluatedCandidate {
|
||||
// is needed for specialization. Propagate overflow if it occurs.
|
||||
let candidates: Result<Vec<Option<EvaluatedCandidate>>, _> = candidates
|
||||
.into_iter()
|
||||
.map(|c| match self.evaluate_candidate(stack, &c) {
|
||||
Ok(eval) if eval.may_apply() => Ok(Some(EvaluatedCandidate {
|
||||
candidate: c,
|
||||
evaluation: eval,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}).collect();
|
||||
})),
|
||||
Ok(_) => Ok(None),
|
||||
Err(OverflowError) => Err(Overflow),
|
||||
})
|
||||
.collect();
|
||||
|
||||
let mut candidates: Vec<EvaluatedCandidate> =
|
||||
candidates?.into_iter().filter_map(|c| c).collect();
|
||||
|
||||
// If there are STILL multiple candidate, we can further
|
||||
// reduce the list by dropping duplicates -- including
|
||||
@ -1537,12 +1608,14 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
let matching_bounds =
|
||||
all_bounds.filter(|p| p.def_id() == stack.obligation.predicate.def_id());
|
||||
|
||||
let matching_bounds =
|
||||
matching_bounds.filter(
|
||||
|bound| self.evaluate_where_clause(stack, bound.clone()).may_apply());
|
||||
|
||||
let param_candidates =
|
||||
matching_bounds.map(|bound| ParamCandidate(bound));
|
||||
// keep only those bounds which may apply, and propagate overflow if it occurs
|
||||
let mut param_candidates = vec![];
|
||||
for bound in matching_bounds {
|
||||
let wc = self.evaluate_where_clause(stack, bound.clone())?;
|
||||
if wc.may_apply() {
|
||||
param_candidates.push(ParamCandidate(bound));
|
||||
}
|
||||
}
|
||||
|
||||
candidates.vec.extend(param_candidates);
|
||||
|
||||
@ -1552,14 +1625,14 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
|
||||
fn evaluate_where_clause<'o>(&mut self,
|
||||
stack: &TraitObligationStack<'o, 'tcx>,
|
||||
where_clause_trait_ref: ty::PolyTraitRef<'tcx>)
|
||||
-> EvaluationResult
|
||||
-> Result<EvaluationResult, OverflowError>
|
||||
{
|
||||
self.probe(move |this, _| {
|
||||
match this.match_where_clause_trait_ref(stack.obligation, where_clause_trait_ref) {
|
||||
Ok(obligations) => {
|
||||
this.evaluate_predicates_recursively(stack.list(), obligations.iter())
|
||||
}
|
||||
Err(()) => EvaluatedToErr
|
||||
Err(()) => Ok(EvaluatedToErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -177,6 +177,7 @@ impl<'a, 'tcx> Lift<'tcx> for traits::SelectionError<'a> {
|
||||
super::ConstEvalFailure(ref err) => {
|
||||
tcx.lift(err).map(super::ConstEvalFailure)
|
||||
}
|
||||
super::Overflow => bug!() // FIXME: ape ConstEvalFailure?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,7 @@
|
||||
use dep_graph::SerializedDepNodeIndex;
|
||||
use hir::def_id::{CrateNum, DefId, DefIndex};
|
||||
use mir::interpret::{GlobalId};
|
||||
use traits::query::{CanonicalProjectionGoal, CanonicalTyGoal};
|
||||
use traits::query::{CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal};
|
||||
use ty::{self, ParamEnvAnd, Ty, TyCtxt};
|
||||
use ty::subst::Substs;
|
||||
use ty::maps::queries;
|
||||
@ -73,6 +73,12 @@ impl<'tcx> QueryDescription<'tcx> for queries::normalize_ty_after_erasing_region
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> QueryDescription<'tcx> for queries::evaluate_obligation<'tcx> {
|
||||
fn describe(_tcx: TyCtxt, goal: CanonicalPredicateGoal<'tcx>) -> String {
|
||||
format!("evaluating trait selection obligation `{}`", goal.value.value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> QueryDescription<'tcx> for queries::is_copy_raw<'tcx> {
|
||||
fn describe(_tcx: TyCtxt, env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> String {
|
||||
format!("computing whether `{}` is `Copy`", env.value)
|
||||
|
@ -11,7 +11,7 @@
|
||||
//! Defines the set of legal keys that can be used in queries.
|
||||
|
||||
use hir::def_id::{CrateNum, DefId, LOCAL_CRATE, DefIndex};
|
||||
use traits::query::{CanonicalProjectionGoal, CanonicalTyGoal};
|
||||
use traits::query::{CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal};
|
||||
use ty::{self, Ty, TyCtxt};
|
||||
use ty::subst::Substs;
|
||||
use ty::fast_reject::SimplifiedType;
|
||||
@ -200,3 +200,13 @@ impl<'tcx> Key for CanonicalTyGoal<'tcx> {
|
||||
DUMMY_SP
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Key for CanonicalPredicateGoal<'tcx> {
|
||||
fn map_crate(&self) -> CrateNum {
|
||||
LOCAL_CRATE
|
||||
}
|
||||
|
||||
fn default_span(&self, _tcx: TyCtxt) -> Span {
|
||||
DUMMY_SP
|
||||
}
|
||||
}
|
||||
|
@ -32,8 +32,9 @@ use mir;
|
||||
use mir::interpret::{GlobalId};
|
||||
use session::{CompileResult, CrateDisambiguator};
|
||||
use session::config::OutputFilenames;
|
||||
use traits::Vtable;
|
||||
use traits::query::{CanonicalProjectionGoal, CanonicalTyGoal, NoSolution};
|
||||
use traits::{self, Vtable};
|
||||
use traits::query::{CanonicalPredicateGoal, CanonicalProjectionGoal,
|
||||
CanonicalTyGoal, NoSolution};
|
||||
use traits::query::dropck_outlives::{DtorckConstraint, DropckOutlivesResult};
|
||||
use traits::query::normalize::NormalizationResult;
|
||||
use traits::specialization_graph;
|
||||
@ -433,6 +434,12 @@ define_maps! { <'tcx>
|
||||
NoSolution,
|
||||
>,
|
||||
|
||||
/// Do not call this query directly: invoke `infcx.predicate_may_hold()` or
|
||||
/// `infcx.predicate_must_hold()` instead.
|
||||
[] fn evaluate_obligation: EvaluateObligation(
|
||||
CanonicalPredicateGoal<'tcx>
|
||||
) -> Result<traits::EvaluationResult, traits::OverflowError>,
|
||||
|
||||
[] fn substitute_normalize_and_test_predicates:
|
||||
substitute_normalize_and_test_predicates_node((DefId, &'tcx Substs<'tcx>)) -> bool,
|
||||
|
||||
|
@ -977,6 +977,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
|
||||
DepKind::NormalizeProjectionTy |
|
||||
DepKind::NormalizeTyAfterErasingRegions |
|
||||
DepKind::DropckOutlives |
|
||||
DepKind::EvaluateObligation |
|
||||
DepKind::SubstituteNormalizeAndTestPredicates |
|
||||
DepKind::InstanceDefSizeEstimate |
|
||||
DepKind::ProgramClausesForEnv |
|
||||
|
35
src/librustc_traits/evaluate_obligation.rs
Normal file
35
src/librustc_traits/evaluate_obligation.rs
Normal file
@ -0,0 +1,35 @@
|
||||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use rustc::traits::{EvaluationResult, Obligation, ObligationCause,
|
||||
OverflowError, SelectionContext, TraitQueryMode};
|
||||
use rustc::traits::query::CanonicalPredicateGoal;
|
||||
use rustc::ty::{ParamEnvAnd, TyCtxt};
|
||||
use syntax::codemap::DUMMY_SP;
|
||||
|
||||
crate fn evaluate_obligation<'tcx>(
|
||||
tcx: TyCtxt<'_, 'tcx, 'tcx>,
|
||||
goal: CanonicalPredicateGoal<'tcx>,
|
||||
) -> Result<EvaluationResult, OverflowError> {
|
||||
tcx.infer_ctxt().enter(|ref infcx| {
|
||||
let (
|
||||
ParamEnvAnd {
|
||||
param_env,
|
||||
value: predicate,
|
||||
},
|
||||
_canonical_inference_vars,
|
||||
) = infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &goal);
|
||||
|
||||
let mut selcx = SelectionContext::with_query_mode(&infcx, TraitQueryMode::Canonical);
|
||||
let obligation = Obligation::new(ObligationCause::dummy(), param_env, predicate);
|
||||
|
||||
selcx.evaluate_obligation_recursively(&obligation)
|
||||
})
|
||||
}
|
@ -22,6 +22,7 @@ extern crate syntax;
|
||||
extern crate syntax_pos;
|
||||
|
||||
mod dropck_outlives;
|
||||
mod evaluate_obligation;
|
||||
mod normalize_projection_ty;
|
||||
mod normalize_erasing_regions;
|
||||
mod util;
|
||||
@ -38,6 +39,7 @@ pub fn provide(p: &mut Providers) {
|
||||
normalize_erasing_regions::normalize_ty_after_erasing_regions,
|
||||
program_clauses_for: lowering::program_clauses_for,
|
||||
program_clauses_for_env: lowering::program_clauses_for_env,
|
||||
evaluate_obligation: evaluate_obligation::evaluate_obligation,
|
||||
..*p
|
||||
};
|
||||
}
|
||||
|
@ -120,15 +120,15 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> {
|
||||
|
||||
let cause = traits::ObligationCause::misc(self.span, self.fcx.body_id);
|
||||
|
||||
let mut selcx = traits::SelectionContext::new(self.fcx);
|
||||
let obligation = traits::Obligation::new(cause.clone(),
|
||||
self.fcx.param_env,
|
||||
trait_ref.to_predicate());
|
||||
if !selcx.evaluate_obligation(&obligation) {
|
||||
if !self.fcx.predicate_may_hold(&obligation) {
|
||||
debug!("overloaded_deref_ty: cannot match obligation");
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut selcx = traits::SelectionContext::new(self.fcx);
|
||||
let normalized = traits::normalize_projection_type(&mut selcx,
|
||||
self.fcx.param_env,
|
||||
ty::ProjectionTy::from_ref_and_name(
|
||||
|
@ -277,8 +277,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
poly_trait_ref.to_predicate());
|
||||
|
||||
// Now we want to know if this can be matched
|
||||
let mut selcx = traits::SelectionContext::new(self);
|
||||
if !selcx.evaluate_obligation(&obligation) {
|
||||
if !self.predicate_may_hold(&obligation) {
|
||||
debug!("--> Cannot match obligation");
|
||||
return None; // Cannot be matched, no such method resolution is possible.
|
||||
}
|
||||
|
@ -1173,7 +1173,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
||||
let predicate = trait_ref.to_predicate();
|
||||
let obligation =
|
||||
traits::Obligation::new(cause.clone(), self.param_env, predicate);
|
||||
if !selcx.evaluate_obligation(&obligation) {
|
||||
if !self.predicate_may_hold(&obligation) {
|
||||
if self.probe(|_| self.select_trait_candidate(trait_ref).is_err()) {
|
||||
// This candidate's primary obligation doesn't even
|
||||
// select - don't bother registering anything in
|
||||
@ -1201,7 +1201,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
|
||||
// Evaluate those obligations to see if they might possibly hold.
|
||||
for o in candidate_obligations.into_iter().chain(sub_obligations) {
|
||||
let o = self.resolve_type_vars_if_possible(&o);
|
||||
if !selcx.evaluate_obligation(&o) {
|
||||
if !self.predicate_may_hold(&o) {
|
||||
result = ProbeResult::NoMatch;
|
||||
if let &ty::Predicate::Trait(ref pred) = &o.predicate {
|
||||
possibly_unsatisfied_predicates.push(pred.skip_binder().trait_ref);
|
||||
|
@ -19,7 +19,7 @@ use hir::def::Def;
|
||||
use hir::def_id::{CRATE_DEF_INDEX, DefId};
|
||||
use middle::lang_items::FnOnceTraitLangItem;
|
||||
use namespace::Namespace;
|
||||
use rustc::traits::{Obligation, SelectionContext};
|
||||
use rustc::traits::Obligation;
|
||||
use util::nodemap::FxHashSet;
|
||||
|
||||
use syntax::ast;
|
||||
@ -65,7 +65,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
||||
self.body_id,
|
||||
self.param_env,
|
||||
poly_trait_ref.to_predicate());
|
||||
SelectionContext::new(self).evaluate_obligation(&obligation)
|
||||
self.predicate_may_hold(&obligation)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
@ -10,6 +10,8 @@
|
||||
|
||||
// ignore-tidy-linelength
|
||||
|
||||
//~^^^^^^^^^^^^ ERROR
|
||||
|
||||
#![feature(optin_builtin_traits)]
|
||||
|
||||
unsafe auto trait Trait {
|
||||
@ -22,5 +24,4 @@ fn call_method<T: Trait>(x: T) {}
|
||||
fn main() {
|
||||
// ICE
|
||||
call_method(());
|
||||
//~^ ERROR
|
||||
}
|
||||
|
@ -34,6 +34,7 @@ error[E0391]: cycle detected when processing `cycle1`
|
||||
LL | fn cycle1() -> impl Clone {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`...
|
||||
note: ...which requires processing `cycle2::{{impl-Trait}}`...
|
||||
--> $DIR/auto-trait-leak.rs:49:16
|
||||
|
|
||||
@ -44,6 +45,7 @@ note: ...which requires processing `cycle2`...
|
||||
|
|
||||
LL | fn cycle2() -> impl Clone {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`...
|
||||
note: ...which requires processing `cycle1::{{impl-Trait}}`...
|
||||
--> $DIR/auto-trait-leak.rs:42:16
|
||||
|
|
||||
|
Loading…
x
Reference in New Issue
Block a user