]> git.lizzy.rs Git - rust.git/commitdiff
traits: consider whether origin is RFC1214 when caching, ensuring
authorNiko Matsakis <niko@alum.mit.edu>
Tue, 11 Aug 2015 14:48:34 +0000 (10:48 -0400)
committerNiko Matsakis <niko@alum.mit.edu>
Wed, 12 Aug 2015 21:58:57 +0000 (17:58 -0400)
that the test rfc1214-warn-and-error.rs reports an error

src/librustc/middle/traits/fulfill.rs
src/librustc/middle/traits/mod.rs
src/librustc/middle/traits/select.rs
src/test/compile-fail/rfc1214-warn-and-error.rs [new file with mode: 0644]

index 96637b92cef414d65cf5be4d9612bdbccf0f7cf8..1fca66f1379189ac3b205e199f457e33dded7cce 100644 (file)
 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
@@ -190,7 +191,9 @@ pub fn register_predicate_obligation<'a>(&mut self,
 
         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;
         }
@@ -253,7 +256,9 @@ pub fn pending_obligations(&self) -> &[PredicateObligation<'tcx>] {
         &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"
@@ -268,10 +273,12 @@ fn is_duplicate_or_add(&mut self, tcx: &ty::ctxt<'tcx>,
         // 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)
         }
     }
 
@@ -537,11 +544,13 @@ pub fn new() -> FulfilledPredicates<'tcx> {
         }
     }
 
-    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)
     }
 }
index 14ab6c505d05cb95bff978333b4eefbf8e26c2c4..6c501b1a609c4feeae55abe9e0e65d357f71b1d7 100644 (file)
@@ -528,6 +528,15 @@ pub fn dummy() -> ObligationCause<'tcx> {
     }
 }
 
+/// 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 {
index 713b7394b59a12dca02743339620ffe60b1137c8..f63523b77d60f64cb0ff04d965263f88a27c6b9f 100644 (file)
@@ -27,6 +27,7 @@
 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,
@@ -445,7 +446,8 @@ fn evaluate_predicate_recursively<'o>(&mut self,
         // 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;
         }
 
diff --git a/src/test/compile-fail/rfc1214-warn-and-error.rs b/src/test/compile-fail/rfc1214-warn-and-error.rs
new file mode 100644 (file)
index 0000000..50fd3fc
--- /dev/null
@@ -0,0 +1,37 @@
+// 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() { }