use super::ObligationCauseCode;
use super::PredicateObligation;
use super::project;
+use super::RFC1214Warning;
use super::select::SelectionContext;
use super::Unimplemented;
use super::util::predicate_for_builtin_bound;
pub struct FulfilledPredicates<'tcx> {
- set: HashSet<ty::Predicate<'tcx>>
+ set: HashSet<(RFC1214Warning, ty::Predicate<'tcx>)>
}
/// The fulfillment context is used to drive trait resolution. It
assert!(!obligation.has_escaping_regions());
- if self.is_duplicate_or_add(infcx.tcx, &obligation.predicate) {
+ let w = RFC1214Warning(obligation.cause.code.is_rfc1214());
+
+ if self.is_duplicate_or_add(infcx.tcx, w, &obligation.predicate) {
debug!("register_predicate({:?}) -- already seen, skip", obligation);
return;
}
&self.predicates
}
- fn is_duplicate_or_add(&mut self, tcx: &ty::ctxt<'tcx>,
+ fn is_duplicate_or_add(&mut self,
+ tcx: &ty::ctxt<'tcx>,
+ w: RFC1214Warning,
predicate: &ty::Predicate<'tcx>)
-> bool {
// This is a kind of dirty hack to allow us to avoid "rederiving"
// evaluating the 'nested obligations'. This cache lets us
// skip those.
- if self.errors_will_be_reported && predicate.is_global() {
- tcx.fulfilled_predicates.borrow_mut().is_duplicate_or_add(predicate)
+ let will_warn_due_to_rfc1214 = w.0;
+ let errors_will_be_reported = self.errors_will_be_reported && !will_warn_due_to_rfc1214;
+ if errors_will_be_reported && predicate.is_global() {
+ tcx.fulfilled_predicates.borrow_mut().is_duplicate_or_add(w, predicate)
} else {
- self.duplicate_set.is_duplicate_or_add(predicate)
+ self.duplicate_set.is_duplicate_or_add(w, predicate)
}
}
}
}
- pub fn is_duplicate(&self, p: &ty::Predicate<'tcx>) -> bool {
- self.set.contains(p)
+ pub fn is_duplicate(&self, w: RFC1214Warning, p: &ty::Predicate<'tcx>) -> bool {
+ let key = (w, p.clone());
+ self.set.contains(&key)
}
- fn is_duplicate_or_add(&mut self, p: &ty::Predicate<'tcx>) -> bool {
- !self.set.insert(p.clone())
+ fn is_duplicate_or_add(&mut self, w: RFC1214Warning, p: &ty::Predicate<'tcx>) -> bool {
+ let key = (w, p.clone());
+ !self.set.insert(key)
}
}
}
}
+/// This marker is used in some caches to record whether the
+/// predicate, if it is found to be false, will yield a warning (due
+/// to RFC1214) or an error. We separate these two cases in the cache
+/// so that if we see the same predicate twice, first resulting in a
+/// warning, and next resulting in an error, we still report the
+/// error, rather than considering it a duplicate.
+#[derive(Copy, Clone, PartialEq, Eq, Hash)]
+pub struct RFC1214Warning(bool);
+
impl<'tcx> ObligationCauseCode<'tcx> {
pub fn is_rfc1214(&self) -> bool {
match *self {
use super::{SelectionError, Unimplemented, OutputTypeParameterMismatch};
use super::{ObjectCastObligation, Obligation};
use super::TraitNotObjectSafe;
+use super::RFC1214Warning;
use super::Selection;
use super::SelectionResult;
use super::{VtableBuiltin, VtableImpl, VtableParam, VtableClosure,
// have been proven elsewhere. This cache only contains
// predicates that are global in scope and hence unaffected by
// the current environment.
- if self.tcx().fulfilled_predicates.borrow().is_duplicate(&obligation.predicate) {
+ let w = RFC1214Warning(false);
+ if self.tcx().fulfilled_predicates.borrow().is_duplicate(w, &obligation.predicate) {
return EvaluatedToOk;
}
--- /dev/null
+// Copyright 2015 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.
+
+// Test that an RFC1214 warning from an earlier function (`foo`) does
+// not suppress an error for the same problem (`WantEq<NotEq>`,
+// `NotEq: !Eq`) in a later function (`bar)`. Earlier versions of the
+// warning mechanism had an issue due to caching.
+
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+struct WantEq<T:Eq> { t: T }
+
+struct NotEq;
+
+trait Trait<T> { }
+
+fn foo() {
+ let x: Box<Trait<WantEq<NotEq>>> = loop { };
+ //~^ WARN E0277
+}
+
+fn bar() {
+ wf::<WantEq<NotEq>>();
+ //~^ ERROR E0277
+}
+
+fn wf<T>() { }
+
+fn main() { }