require reimplementations of all items when a defaulted associated type is overriden

This is a
[breaking-change]
but it follows the RFC (not sure whether it will be accepted).
This commit is contained in:
Ariel Ben-Yehuda 2015-06-30 20:30:47 +03:00
parent ace86701a9
commit 6b27005f2f
3 changed files with 68 additions and 12 deletions

View file

@ -846,6 +846,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
// Locate trait methods
let tcx = ccx.tcx;
let trait_items = tcx.trait_items(impl_trait_ref.def_id);
let mut overridden_associated_type = None;
// Check existing impl methods to see if they are both present in trait
// and compatible with trait signature
@ -911,8 +912,10 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
_ => tcx.sess.span_bug(impl_item.span, "non-type impl-item for type")
};
if let &ty::TypeTraitItem(..) = ty_trait_item {
// ...
if let &ty::TypeTraitItem(ref at) = ty_trait_item {
if let Some(_) = at.ty {
overridden_associated_type = Some(impl_item);
}
} else {
span_err!(tcx.sess, impl_item.span, E0325,
"item `{}` is an associated type, \
@ -930,6 +933,8 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
let provided_methods = tcx.provided_trait_methods(impl_trait_ref.def_id);
let associated_consts = tcx.associated_consts(impl_trait_ref.def_id);
let mut missing_items = Vec::new();
let mut invalidated_items = Vec::new();
let associated_type_overridden = overridden_associated_type.is_some();
for trait_item in trait_items.iter() {
match *trait_item {
ty::ConstTraitItem(ref associated_const) => {
@ -944,9 +949,12 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
let is_provided =
associated_consts.iter().any(|ac| ac.default.is_some() &&
ac.name == associated_const.name);
if !is_implemented && !is_provided {
missing_items.push(format!("`{}`",
token::get_name(associated_const.name)));
if !is_implemented {
if !is_provided {
missing_items.push(associated_const.name);
} else if associated_type_overridden {
invalidated_items.push(associated_const.name);
}
}
}
ty::MethodTraitItem(ref trait_method) => {
@ -961,8 +969,12 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
});
let is_provided =
provided_methods.iter().any(|m| m.name == trait_method.name);
if !is_implemented && !is_provided {
missing_items.push(format!("`{}`", token::get_name(trait_method.name)));
if !is_implemented {
if !is_provided {
missing_items.push(trait_method.name);
} else if associated_type_overridden {
invalidated_items.push(trait_method.name);
}
}
}
ty::TypeTraitItem(ref associated_type) => {
@ -975,8 +987,12 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
}
});
let is_provided = associated_type.ty.is_some();
if !is_implemented && !is_provided {
missing_items.push(format!("`{}`", token::get_name(associated_type.name)));
if !is_implemented {
if !is_provided {
missing_items.push(associated_type.name);
} else if associated_type_overridden {
invalidated_items.push(associated_type.name);
}
}
}
}
@ -984,8 +1000,21 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
if !missing_items.is_empty() {
span_err!(tcx.sess, impl_span, E0046,
"not all trait items implemented, missing: {}",
missing_items.connect(", "));
"not all trait items implemented, missing: `{}`",
missing_items.iter()
.map(<ast::Name>::as_str)
.collect::<Vec<_>>().connect("`, `"))
}
if !invalidated_items.is_empty() {
let invalidator = overridden_associated_type.unwrap();
span_err!(tcx.sess, invalidator.span, E0399,
"the following trait items need to be reimplemented \
as `{}` was overridden: `{}`",
invalidator.ident.as_str(),
invalidated_items.iter()
.map(<ast::Name>::as_str)
.collect::<Vec<_>>().connect("`, `"))
}
}

View file

@ -2066,6 +2066,8 @@ register_diagnostics! {
// `#[lang = \"{}\"]` is allowed for the `{}` primitive
E0391, // unsupported cyclic reference between types/traits detected
E0392, // parameter `{}` is never used
E0393 // the type parameter `{}` must be explicitly specified in an object
E0393, // the type parameter `{}` must be explicitly specified in an object
// type because its default value `{}` references the type `Self`"
E0399 // trait items need to be implemented because the associated
// type `{}` was overridden
}

View file

@ -0,0 +1,25 @@
// 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.
#![feature(associated_consts)]
pub trait Tr {
type Assoc = u8;
type Assoc2 = Self::Assoc;
const C: u8 = 11;
fn foo(&self) {}
}
impl Tr for () {
type Assoc = ();
//~^ ERROR need to be reimplemented as `Assoc` was overridden: `Assoc2`, `C`, `foo`
}
fn main() {}