traits: consider whether origin is RFC1214 when caching, ensuring

that the test rfc1214-warn-and-error.rs reports an error
This commit is contained in:
Niko Matsakis 2015-08-11 10:48:34 -04:00
parent fb1b6fca36
commit 9c5cfea43d
4 changed files with 68 additions and 11 deletions

View file

@ -27,12 +27,13 @@ use super::ObligationCause;
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 @@ impl<'tcx> FulfillmentContext<'tcx> {
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 @@ impl<'tcx> FulfillmentContext<'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 @@ impl<'tcx> FulfillmentContext<'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 @@ impl<'tcx> 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)
}
}

View file

@ -528,6 +528,15 @@ impl<'tcx> 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 {

View file

@ -27,6 +27,7 @@ use super::{ObligationCauseCode, BuiltinDerivedObligation, ImplDerivedObligation
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 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// 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;
}

View file

@ -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() { }