Rollup merge of #28681 - arielb1:destructor-fixes, r=eddyb

Fixes #28568 

r? @eddyb
This commit is contained in:
Manish Goregaokar 2015-09-27 15:05:17 +05:30
commit 7e6e64b12d
36 changed files with 172 additions and 84 deletions

View File

@ -43,7 +43,7 @@ use std::rc::Rc;
use syntax::ast;
use syntax::codemap;
use syntax::codemap::{Span, DUMMY_SP};
use util::nodemap::{FnvHashMap, NodeMap};
use util::nodemap::{FnvHashMap, FnvHashSet, NodeMap};
use self::combine::CombineFields;
use self::region_inference::{RegionVarBindings, RegionSnapshot};
@ -92,6 +92,10 @@ pub struct InferCtxt<'a, 'tcx: 'a> {
pub fulfillment_cx: RefCell<traits::FulfillmentContext<'tcx>>,
// the set of predicates on which errors have been reported, to
// avoid reporting the same error twice.
pub reported_trait_errors: RefCell<FnvHashSet<traits::TraitErrorKey<'tcx>>>,
// This is a temporary field used for toggling on normalization in the inference context,
// as we move towards the approach described here:
// https://internals.rust-lang.org/t/flattening-the-contexts-for-fun-and-profit/2293
@ -374,6 +378,7 @@ pub fn new_infer_ctxt<'a, 'tcx>(tcx: &'a ty::ctxt<'tcx>,
region_vars: RegionVarBindings::new(tcx),
parameter_environment: param_env.unwrap_or(tcx.empty_parameter_environment()),
fulfillment_cx: RefCell::new(traits::FulfillmentContext::new(errors_will_be_reported)),
reported_trait_errors: RefCell::new(FnvHashSet()),
normalize: false,
err_count_on_creation: tcx.sess.err_count()
}

View File

@ -348,13 +348,17 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
// this properly would result in the necessity of computing *type*
// reachability, which might result in a compile time loss.
fn mark_destructors_reachable(&mut self) {
for adt in self.tcx.adt_defs() {
if let Some(destructor_def_id) = adt.destructor() {
if destructor_def_id.is_local() {
self.reachable_symbols.insert(destructor_def_id.node);
let drop_trait = match self.tcx.lang_items.drop_trait() {
Some(id) => self.tcx.lookup_trait_def(id), None => { return }
};
drop_trait.for_each_impl(self.tcx, |drop_impl| {
for destructor in &self.tcx.impl_items.borrow()[&drop_impl] {
let destructor_did = destructor.def_id();
if destructor_did.is_local() {
self.reachable_symbols.insert(destructor_did.node);
}
}
}
})
}
}

View File

@ -28,11 +28,32 @@ use middle::def_id::DefId;
use middle::infer::InferCtxt;
use middle::ty::{self, ToPredicate, HasTypeFlags, ToPolyTraitRef, TraitRef, Ty};
use middle::ty::fold::TypeFoldable;
use std::collections::HashMap;
use util::nodemap::{FnvHashMap, FnvHashSet};
use std::fmt;
use syntax::codemap::Span;
use syntax::attr::{AttributeMethods, AttrMetaMethods};
#[derive(Debug, PartialEq, Eq, Hash)]
pub struct TraitErrorKey<'tcx> {
is_warning: bool,
span: Span,
predicate: ty::Predicate<'tcx>
}
impl<'tcx> TraitErrorKey<'tcx> {
fn from_error<'a>(infcx: &InferCtxt<'a, 'tcx>,
e: &FulfillmentError<'tcx>) -> Self {
let predicate =
infcx.resolve_type_vars_if_possible(&e.obligation.predicate);
TraitErrorKey {
is_warning: is_warning(&e.obligation),
span: e.obligation.cause.span,
predicate: infcx.tcx.erase_regions(&predicate)
}
}
}
pub fn report_fulfillment_errors<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
errors: &Vec<FulfillmentError<'tcx>>) {
for error in errors {
@ -42,6 +63,13 @@ pub fn report_fulfillment_errors<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
fn report_fulfillment_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
error: &FulfillmentError<'tcx>) {
let error_key = TraitErrorKey::from_error(infcx, error);
debug!("report_fulfillment_errors({:?}) - key={:?}",
error, error_key);
if !infcx.reported_trait_errors.borrow_mut().insert(error_key) {
debug!("report_fulfillment_errors: skipping duplicate");
return;
}
match error.code {
FulfillmentErrorCode::CodeSelectionError(ref e) => {
report_selection_error(infcx, &error.obligation, e);
@ -97,7 +125,7 @@ fn report_on_unimplemented<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
(gen.name.as_str().to_string(),
trait_ref.substs.types.get(param, i)
.to_string())
}).collect::<HashMap<String, String>>();
}).collect::<FnvHashMap<String, String>>();
generic_map.insert("Self".to_string(),
trait_ref.self_ty().to_string());
let parser = Parser::new(&istring);
@ -308,7 +336,11 @@ pub fn report_object_safety_error<'tcx>(tcx: &ty::ctxt<'tcx>,
"the trait `{}` cannot be made into an object",
tcx.item_path_str(trait_def_id));
let mut reported_violations = FnvHashSet();
for violation in violations {
if !reported_violations.insert(violation.clone()) {
continue;
}
match violation {
ObjectSafetyViolation::SizedSelf => {
tcx.sess.fileline_note(

View File

@ -49,6 +49,12 @@ pub struct FulfillmentContext<'tcx> {
// than the `SelectionCache`: it avoids duplicate errors and
// permits recursive obligations, which are often generated from
// traits like `Send` et al.
//
// Note that because of type inference, a predicate can still
// occur twice in the predicates list, for example when 2
// initially-distinct type variables are unified after being
// inserted. Deduplicating the predicate set on selection had a
// significant performance cost the last time I checked.
duplicate_set: FulfilledPredicates<'tcx>,
// A list of all obligations that have been registered with this

View File

@ -21,10 +21,12 @@ use middle::subst;
use middle::ty::{self, HasTypeFlags, Ty};
use middle::ty::fold::TypeFoldable;
use middle::infer::{self, fixup_err_to_string, InferCtxt};
use std::rc::Rc;
use syntax::ast;
use syntax::codemap::{Span, DUMMY_SP};
pub use self::error_reporting::TraitErrorKey;
pub use self::error_reporting::report_fulfillment_errors;
pub use self::error_reporting::report_overflow_error;
pub use self::error_reporting::report_selection_error;

View File

@ -27,7 +27,7 @@ use middle::ty::{self, ToPolyTraitRef, Ty};
use std::rc::Rc;
use syntax::ast;
#[derive(Debug)]
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum ObjectSafetyViolation<'tcx> {
/// Self : Sized declared on the trait
SizedSelf,

View File

@ -245,9 +245,6 @@ pub struct ctxt<'tcx> {
/// True if the variance has been computed yet; false otherwise.
pub variance_computed: Cell<bool>,
/// A method will be in this list if and only if it is a destructor.
pub destructors: RefCell<DefIdSet>,
/// Maps a DefId of a type to a list of its inherent impls.
/// Contains implementations of methods that are inherent to a type.
/// Methods in these implementations don't need to be exported.
@ -475,7 +472,6 @@ impl<'tcx> ctxt<'tcx> {
normalized_cache: RefCell::new(FnvHashMap()),
lang_items: lang_items,
provided_method_sources: RefCell::new(DefIdMap()),
destructors: RefCell::new(DefIdSet()),
inherent_impls: RefCell::new(DefIdMap()),
impl_items: RefCell::new(DefIdMap()),
used_unsafe: RefCell::new(NodeSet()),

View File

@ -272,6 +272,20 @@ impl<'tcx> Method<'tcx> {
}
}
impl<'tcx> PartialEq for Method<'tcx> {
#[inline]
fn eq(&self, other: &Self) -> bool { self.def_id == other.def_id }
}
impl<'tcx> Eq for Method<'tcx> {}
impl<'tcx> Hash for Method<'tcx> {
#[inline]
fn hash<H: Hasher>(&self, s: &mut H) {
self.def_id.hash(s)
}
}
#[derive(Clone, Copy, Debug)]
pub struct AssociatedConst<'tcx> {
pub name: Name,
@ -1681,7 +1695,6 @@ impl<'tcx, 'container> AdtDefData<'tcx, 'container> {
}
pub fn set_destructor(&self, dtor: DefId) {
assert!(self.destructor.get().is_none());
self.destructor.set(Some(dtor));
}
@ -2315,11 +2328,6 @@ impl<'tcx> ctxt<'tcx> {
self.lookup_adt_def_master(did)
}
/// Return the list of all interned ADT definitions
pub fn adt_defs(&self) -> Vec<AdtDef<'tcx>> {
self.adt_defs.borrow().values().cloned().collect()
}
/// Given the did of an item, returns its full set of predicates.
pub fn lookup_predicates(&self, did: DefId) -> GenericPredicates<'tcx> {
lookup_locally_or_in_crate_store(

View File

@ -1210,15 +1210,14 @@ impl LintPass for DropWithReprExtern {
impl LateLintPass for DropWithReprExtern {
fn check_crate(&mut self, ctx: &LateContext, _: &hir::Crate) {
for dtor_did in ctx.tcx.destructors.borrow().iter() {
let (drop_impl_did, dtor_self_type) =
if dtor_did.is_local() {
let impl_did = ctx.tcx.map.get_parent_did(dtor_did.node);
let ty = ctx.tcx.lookup_item_type(impl_did).ty;
(impl_did, ty)
} else {
continue;
};
let drop_trait = match ctx.tcx.lang_items.drop_trait() {
Some(id) => ctx.tcx.lookup_trait_def(id), None => { return }
};
drop_trait.for_each_impl(ctx.tcx, |drop_impl_did| {
if !drop_impl_did.is_local() {
return;
}
let dtor_self_type = ctx.tcx.lookup_item_type(drop_impl_did).ty;
match dtor_self_type.sty {
ty::TyEnum(self_type_def, _) |
@ -1244,6 +1243,6 @@ impl LateLintPass for DropWithReprExtern {
}
_ => {}
}
}
})
}
}

View File

@ -620,13 +620,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
ty::TraitContainer(trait_def_id) => {
callee::check_legal_trait_for_method_call(self.fcx.ccx, self.span, trait_def_id)
}
ty::ImplContainer(..) => {
// Since `drop` is a trait method, we expect that any
// potential calls to it will wind up in the other
// arm. But just to be sure, check that the method id
// does not appear in the list of destructors.
assert!(!self.tcx().destructors.borrow().contains(&pick.item.def_id()));
}
ty::ImplContainer(..) => {}
}
}

View File

@ -431,9 +431,11 @@ pub fn check_item_bodies(ccx: &CrateCtxt) {
}
pub fn check_drop_impls(ccx: &CrateCtxt) {
for drop_method_did in ccx.tcx.destructors.borrow().iter() {
if drop_method_did.is_local() {
let drop_impl_did = ccx.tcx.map.get_parent_did(drop_method_did.node);
let drop_trait = match ccx.tcx.lang_items.drop_trait() {
Some(id) => ccx.tcx.lookup_trait_def(id), None => { return }
};
drop_trait.for_each_impl(ccx.tcx, |drop_impl_did| {
if drop_impl_did.is_local() {
match dropck::check_drop_impl(ccx.tcx, drop_impl_did) {
Ok(()) => {}
Err(()) => {
@ -441,7 +443,7 @@ pub fn check_drop_impls(ccx: &CrateCtxt) {
}
}
}
}
});
ccx.tcx.sess.abort_if_errors();
}

View File

@ -126,7 +126,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
// Populate the table of destructors. It might seem a bit strange to
// do this here, but it's actually the most convenient place, since
// the coherence tables contain the trait -> type mappings.
self.populate_destructor_table();
self.populate_destructors();
// Check to make sure implementations of `Copy` are legal.
self.check_implementations_of_copy();
@ -286,7 +286,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
// Destructors
//
fn populate_destructor_table(&self) {
fn populate_destructors(&self) {
let tcx = self.crate_context.tcx;
let drop_trait = match tcx.lang_items.drop_trait() {
Some(id) => id, None => { return }
@ -309,9 +309,6 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
ty::TyEnum(type_def, _) |
ty::TyStruct(type_def, _) => {
type_def.set_destructor(method_def_id.def_id());
tcx.destructors
.borrow_mut()
.insert(method_def_id.def_id());
}
_ => {
// Destructors only work on nominal types.

View File

@ -32,5 +32,4 @@ fn ice<A>(a: A) {
let r = loop {};
r = r + a;
//~^ ERROR not implemented
//~| ERROR not implemented
}

View File

@ -39,7 +39,6 @@ pub fn f1_int_uint() {
pub fn f1_uint_uint() {
f1(2u32, 4u32);
//~^ ERROR the trait `Foo` is not implemented
//~| ERROR the trait `Foo` is not implemented
}
pub fn f1_uint_int() {

View File

@ -11,5 +11,4 @@
fn main() {
let x: Option<&[u8]> = Some("foo").map(std::mem::transmute);
//~^ ERROR E0277
//~| ERROR E0277
}

View File

@ -23,7 +23,6 @@ const A_I8_T
: [u32; (i8::MAX as i8 + 1u8) as usize]
//~^ ERROR mismatched types
//~| the trait `core::ops::Add<u8>` is not implemented for the type `i8`
//~| the trait `core::ops::Add<u8>` is not implemented for the type `i8`
= [0; (i8::MAX as usize) + 1];
fn main() {
@ -33,4 +32,3 @@ fn main() {
fn foo<T:fmt::Debug>(x: T) {
println!("{:?}", x);
}

View File

@ -20,10 +20,8 @@ fn main() {
apply(&3, takes_imm);
apply(&3, takes_mut);
//~^ ERROR (values differ in mutability)
//~| ERROR (values differ in mutability)
apply(&mut 3, takes_mut);
apply(&mut 3, takes_imm);
//~^ ERROR (values differ in mutability)
//~| ERROR (values differ in mutability)
}

View File

@ -25,9 +25,6 @@ pub fn main() {
y: 2,
};
for x in bogus { //~ ERROR `core::iter::Iterator` is not implemented for the type `MyStruct`
//~^ ERROR
//~^^ ERROR
// FIXME(#21528) not fulfilled obligation error should be reported once, not thrice
drop(x);
}
}

View File

@ -14,7 +14,6 @@
fn main() {
fn bar<T>(_: T) {}
[0][0u8]; //~ ERROR: the trait `core::ops::Index<u8>` is not implemented
//~^ ERROR: the trait `core::ops::Index<u8>` is not implemented
[0][0]; // should infer to be a usize

View File

@ -14,21 +14,13 @@ pub fn main() {
v[3_usize];
v[3];
v[3u8]; //~ERROR the trait `core::ops::Index<u8>` is not implemented
//~^ ERROR the trait `core::ops::Index<u8>` is not implemented
v[3i8]; //~ERROR the trait `core::ops::Index<i8>` is not implemented
//~^ ERROR the trait `core::ops::Index<i8>` is not implemented
v[3u32]; //~ERROR the trait `core::ops::Index<u32>` is not implemented
//~^ ERROR the trait `core::ops::Index<u32>` is not implemented
v[3i32]; //~ERROR the trait `core::ops::Index<i32>` is not implemented
//~^ ERROR the trait `core::ops::Index<i32>` is not implemented
s.as_bytes()[3_usize];
s.as_bytes()[3];
s.as_bytes()[3u8]; //~ERROR the trait `core::ops::Index<u8>` is not implemented
//~^ ERROR the trait `core::ops::Index<u8>` is not implemented
s.as_bytes()[3i8]; //~ERROR the trait `core::ops::Index<i8>` is not implemented
//~^ ERROR the trait `core::ops::Index<i8>` is not implemented
s.as_bytes()[3u32]; //~ERROR the trait `core::ops::Index<u32>` is not implemented
//~^ ERROR the trait `core::ops::Index<u32>` is not implemented
s.as_bytes()[3i32]; //~ERROR the trait `core::ops::Index<i32>` is not implemented
//~^ ERROR the trait `core::ops::Index<i32>` is not implemented
}

View File

@ -12,12 +12,10 @@ fn main() {
let x = ();
1 +
x //~^ ERROR E0277
//~| ERROR E0277
;
let x: () = ();
1 +
x //~^ ERROR E0277
//~| ERROR E0277
;
}

View File

@ -18,5 +18,4 @@ fn main() {
});
2_usize + (loop {});
//~^ ERROR E0277
//~| ERROR E0277
}

View File

@ -14,5 +14,4 @@
fn main() {
in () { 0 };
//~^ ERROR: the trait `core::ops::Placer<_>` is not implemented
//~| ERROR: the trait `core::ops::Placer<_>` is not implemented
}

View File

@ -11,9 +11,6 @@
fn changer<'a>(mut things: Box<Iterator<Item=&'a mut u8>>) {
for item in *things { *item = 0 }
//~^ ERROR the trait `core::marker::Sized` is not implemented for the type `core::iter::Iterator
//~^^ ERROR
//~^^^ ERROR
// FIXME(#21528) error should be reported once, not thrice
}
fn main() {}

View File

@ -0,0 +1,23 @@
// 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.
trait Array: Sized {}
fn f<T: Array>(x: &T) {
let _ = x
//~^ ERROR `Array` cannot be made into an object
//~| NOTE the trait cannot require that `Self : Sized`
as
&Array;
//~^ ERROR `Array` cannot be made into an object
//~| NOTE the trait cannot require that `Self : Sized`
}
fn main() {}

View File

@ -17,7 +17,6 @@ impl<A> vec_monad<A> for Vec<A> {
let mut r = panic!();
for elt in self { r = r + f(*elt); }
//~^ ERROR E0277
//~| ERROR E0277
}
}
fn main() {

View File

@ -23,7 +23,5 @@ impl<RHS: Scalar> Add <RHS> for Bob {
fn main() {
let b = Bob + 3.5;
b + 3 //~ ERROR: is not implemented
//~^ ERROR: is not implemented
//~^^ ERROR: is not implemented
//~^^^ ERROR: mismatched types
//~^ ERROR: mismatched types
}

View File

@ -11,5 +11,4 @@
fn main() {
1.0f64 - 1.0;
1.0f64 - 1 //~ ERROR: is not implemented
//~^ ERROR: is not implemented
}

View File

@ -0,0 +1,35 @@
// 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.
fn main() {
let _ = Iterator::next(&mut ());
//~^ ERROR the trait `core::iter::Iterator` is not implemented
for _ in false {}
//~^ ERROR the trait `core::iter::Iterator` is not implemented
let _ = Iterator::next(&mut ());
//~^ ERROR the trait `core::iter::Iterator` is not implemented
other()
}
pub fn other() {
// check errors are still reported globally
let _ = Iterator::next(&mut ());
//~^ ERROR the trait `core::iter::Iterator` is not implemented
let _ = Iterator::next(&mut ());
//~^ ERROR the trait `core::iter::Iterator` is not implemented
for _ in false {}
//~^ ERROR the trait `core::iter::Iterator` is not implemented
}

View File

@ -0,0 +1,23 @@
// 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.
struct MyStruct;
impl Drop for MyStruct {
//~^ ERROR conflicting implementations for trait
fn drop(&mut self) { }
}
impl Drop for MyStruct {
//~^ NOTE conflicting implementation here
fn drop(&mut self) { }
}
fn main() {}

View File

@ -18,15 +18,12 @@ struct Panolpy {
fn foo(p: &Panolpy) {
22 >> p.char;
//~^ ERROR E0277
//~| ERROR E0277
22 >> p.str;
//~^ ERROR E0277
//~| ERROR E0277
22 >> p;
//~^ ERROR E0277
//~| ERROR E0277
let x;
22 >> x; // ambiguity error winds up being suppressed

View File

@ -11,5 +11,4 @@
pub fn main() {
let s: &str = "hello";
let c: u8 = s[4]; //~ ERROR the trait `core::ops::Index<_>` is not implemented
//~^ ERROR the trait `core::ops::Index<_>` is not implemented
}

View File

@ -17,7 +17,6 @@ fn mutate(s: &mut str) {
s[1usize] = bot();
//~^ ERROR `core::ops::Index<usize>` is not implemented for the type `str`
//~| ERROR `core::ops::IndexMut<usize>` is not implemented for the type `str`
//~| ERROR `core::ops::Index<usize>` is not implemented for the type `str`
}
pub fn main() {}

View File

@ -35,7 +35,6 @@ fn b() {
fn c() {
let z = call_it_once(square, 22);
//~^ ERROR not implemented
//~| ERROR not implemented
}
fn main() { }

View File

@ -35,7 +35,6 @@ fn b() {
fn c() {
let z = call_it_once(square, 22);
//~^ ERROR not implemented
//~| ERROR not implemented
}
fn main() { }

View File

@ -36,7 +36,6 @@ fn b() {
fn c() {
let z = call_it_once(square, 22);
//~^ ERROR not implemented
//~| ERROR not implemented
}
fn main() { }