Skip to content

Commit 638ffec

Browse files
committed
Auto merge of #26728 - arielb1:assoc-maybe, r=nrc
r? @nrc
2 parents 0dc0824 + 6b27005 commit 638ffec

File tree

3 files changed

+122
-115
lines changed

3 files changed

+122
-115
lines changed

src/librustc_typeck/check/mod.rs

+94-114
Original file line numberDiff line numberDiff line change
@@ -846,128 +846,82 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
846846
// Locate trait methods
847847
let tcx = ccx.tcx;
848848
let trait_items = tcx.trait_items(impl_trait_ref.def_id);
849+
let mut overridden_associated_type = None;
849850

850851
// Check existing impl methods to see if they are both present in trait
851852
// and compatible with trait signature
852853
for impl_item in impl_items {
854+
let ty_impl_item = ccx.tcx.impl_or_trait_item(local_def(impl_item.id));
855+
let ty_trait_item = trait_items.iter()
856+
.find(|ac| ac.name() == ty_impl_item.name())
857+
.unwrap_or_else(|| {
858+
// This is checked by resolve
859+
tcx.sess.span_bug(impl_item.span,
860+
&format!("impl-item `{}` is not a member of `{:?}`",
861+
token::get_name(ty_impl_item.name()),
862+
impl_trait_ref));
863+
});
853864
match impl_item.node {
854865
ast::ConstImplItem(..) => {
855-
let impl_const_def_id = local_def(impl_item.id);
856-
let impl_const_ty = ccx.tcx.impl_or_trait_item(impl_const_def_id);
866+
let impl_const = match ty_impl_item {
867+
ty::ConstTraitItem(ref cti) => cti,
868+
_ => tcx.sess.span_bug(impl_item.span, "non-const impl-item for const")
869+
};
857870

858871
// Find associated const definition.
859-
let opt_associated_const =
860-
trait_items.iter()
861-
.find(|ac| ac.name() == impl_const_ty.name());
862-
match opt_associated_const {
863-
Some(associated_const) => {
864-
match (associated_const, &impl_const_ty) {
865-
(&ty::ConstTraitItem(ref const_trait),
866-
&ty::ConstTraitItem(ref const_impl)) => {
867-
compare_const_impl(ccx.tcx,
868-
&const_impl,
869-
impl_item.span,
870-
&const_trait,
871-
&*impl_trait_ref);
872-
}
873-
_ => {
874-
span_err!(tcx.sess, impl_item.span, E0323,
875-
"item `{}` is an associated const, \
876-
which doesn't match its trait `{:?}`",
877-
token::get_name(impl_const_ty.name()),
878-
impl_trait_ref)
879-
}
880-
}
881-
}
882-
None => {
883-
// This is `span_bug` as it should have already been
884-
// caught in resolve.
885-
tcx.sess.span_bug(
886-
impl_item.span,
887-
&format!(
888-
"associated const `{}` is not a member of \
889-
trait `{:?}`",
890-
token::get_name(impl_const_ty.name()),
891-
impl_trait_ref));
892-
}
872+
if let &ty::ConstTraitItem(ref trait_const) = ty_trait_item {
873+
compare_const_impl(ccx.tcx,
874+
&impl_const,
875+
impl_item.span,
876+
trait_const,
877+
&*impl_trait_ref);
878+
} else {
879+
span_err!(tcx.sess, impl_item.span, E0323,
880+
"item `{}` is an associated const, \
881+
which doesn't match its trait `{:?}`",
882+
token::get_name(impl_const.name),
883+
impl_trait_ref)
893884
}
894885
}
895886
ast::MethodImplItem(ref sig, ref body) => {
896887
check_trait_fn_not_const(ccx, impl_item.span, sig.constness);
897888

898-
let impl_method_def_id = local_def(impl_item.id);
899-
let impl_item_ty = ccx.tcx.impl_or_trait_item(impl_method_def_id);
900-
901-
// If this is an impl of a trait method, find the
902-
// corresponding method definition in the trait.
903-
let opt_trait_method_ty =
904-
trait_items.iter()
905-
.find(|ti| ti.name() == impl_item_ty.name());
906-
match opt_trait_method_ty {
907-
Some(trait_method_ty) => {
908-
match (trait_method_ty, &impl_item_ty) {
909-
(&ty::MethodTraitItem(ref trait_method_ty),
910-
&ty::MethodTraitItem(ref impl_method_ty)) => {
911-
compare_impl_method(ccx.tcx,
912-
&**impl_method_ty,
913-
impl_item.span,
914-
body.id,
915-
&**trait_method_ty,
916-
&*impl_trait_ref);
917-
}
918-
_ => {
919-
span_err!(tcx.sess, impl_item.span, E0324,
920-
"item `{}` is an associated method, \
921-
which doesn't match its trait `{:?}`",
922-
token::get_name(impl_item_ty.name()),
923-
impl_trait_ref)
924-
}
925-
}
926-
}
927-
None => {
928-
// This is span_bug as it should have already been
929-
// caught in resolve.
930-
tcx.sess.span_bug(
931-
impl_item.span,
932-
&format!("method `{}` is not a member of trait `{:?}`",
933-
token::get_name(impl_item_ty.name()),
934-
impl_trait_ref));
935-
}
889+
let impl_method = match ty_impl_item {
890+
ty::MethodTraitItem(ref mti) => mti,
891+
_ => tcx.sess.span_bug(impl_item.span, "non-method impl-item for method")
892+
};
893+
894+
if let &ty::MethodTraitItem(ref trait_method) = ty_trait_item {
895+
compare_impl_method(ccx.tcx,
896+
&impl_method,
897+
impl_item.span,
898+
body.id,
899+
&trait_method,
900+
&impl_trait_ref);
901+
} else {
902+
span_err!(tcx.sess, impl_item.span, E0324,
903+
"item `{}` is an associated method, \
904+
which doesn't match its trait `{:?}`",
905+
token::get_name(impl_method.name),
906+
impl_trait_ref)
936907
}
937908
}
938909
ast::TypeImplItem(_) => {
939-
let typedef_def_id = local_def(impl_item.id);
940-
let typedef_ty = ccx.tcx.impl_or_trait_item(typedef_def_id);
941-
942-
// If this is an impl of an associated type, find the
943-
// corresponding type definition in the trait.
944-
let opt_associated_type =
945-
trait_items.iter()
946-
.find(|ti| ti.name() == typedef_ty.name());
947-
match opt_associated_type {
948-
Some(associated_type) => {
949-
match (associated_type, &typedef_ty) {
950-
(&ty::TypeTraitItem(_), &ty::TypeTraitItem(_)) => {}
951-
_ => {
952-
span_err!(tcx.sess, impl_item.span, E0325,
953-
"item `{}` is an associated type, \
954-
which doesn't match its trait `{:?}`",
955-
token::get_name(typedef_ty.name()),
956-
impl_trait_ref)
957-
}
958-
}
959-
}
960-
None => {
961-
// This is `span_bug` as it should have already been
962-
// caught in resolve.
963-
tcx.sess.span_bug(
964-
impl_item.span,
965-
&format!(
966-
"associated type `{}` is not a member of \
967-
trait `{:?}`",
968-
token::get_name(typedef_ty.name()),
969-
impl_trait_ref));
910+
let impl_type = match ty_impl_item {
911+
ty::TypeTraitItem(ref tti) => tti,
912+
_ => tcx.sess.span_bug(impl_item.span, "non-type impl-item for type")
913+
};
914+
915+
if let &ty::TypeTraitItem(ref at) = ty_trait_item {
916+
if let Some(_) = at.ty {
917+
overridden_associated_type = Some(impl_item);
970918
}
919+
} else {
920+
span_err!(tcx.sess, impl_item.span, E0325,
921+
"item `{}` is an associated type, \
922+
which doesn't match its trait `{:?}`",
923+
token::get_name(impl_type.name),
924+
impl_trait_ref)
971925
}
972926
}
973927
ast::MacImplItem(_) => tcx.sess.span_bug(impl_item.span,
@@ -979,6 +933,8 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
979933
let provided_methods = tcx.provided_trait_methods(impl_trait_ref.def_id);
980934
let associated_consts = tcx.associated_consts(impl_trait_ref.def_id);
981935
let mut missing_items = Vec::new();
936+
let mut invalidated_items = Vec::new();
937+
let associated_type_overridden = overridden_associated_type.is_some();
982938
for trait_item in trait_items.iter() {
983939
match *trait_item {
984940
ty::ConstTraitItem(ref associated_const) => {
@@ -993,9 +949,12 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
993949
let is_provided =
994950
associated_consts.iter().any(|ac| ac.default.is_some() &&
995951
ac.name == associated_const.name);
996-
if !is_implemented && !is_provided {
997-
missing_items.push(format!("`{}`",
998-
token::get_name(associated_const.name)));
952+
if !is_implemented {
953+
if !is_provided {
954+
missing_items.push(associated_const.name);
955+
} else if associated_type_overridden {
956+
invalidated_items.push(associated_const.name);
957+
}
999958
}
1000959
}
1001960
ty::MethodTraitItem(ref trait_method) => {
@@ -1010,8 +969,12 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
1010969
});
1011970
let is_provided =
1012971
provided_methods.iter().any(|m| m.name == trait_method.name);
1013-
if !is_implemented && !is_provided {
1014-
missing_items.push(format!("`{}`", token::get_name(trait_method.name)));
972+
if !is_implemented {
973+
if !is_provided {
974+
missing_items.push(trait_method.name);
975+
} else if associated_type_overridden {
976+
invalidated_items.push(trait_method.name);
977+
}
1015978
}
1016979
}
1017980
ty::TypeTraitItem(ref associated_type) => {
@@ -1024,17 +987,34 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
1024987
}
1025988
});
1026989
let is_provided = associated_type.ty.is_some();
1027-
if !is_implemented && !is_provided {
1028-
missing_items.push(format!("`{}`", token::get_name(associated_type.name)));
990+
if !is_implemented {
991+
if !is_provided {
992+
missing_items.push(associated_type.name);
993+
} else if associated_type_overridden {
994+
invalidated_items.push(associated_type.name);
995+
}
1029996
}
1030997
}
1031998
}
1032999
}
10331000

10341001
if !missing_items.is_empty() {
10351002
span_err!(tcx.sess, impl_span, E0046,
1036-
"not all trait items implemented, missing: {}",
1037-
missing_items.connect(", "));
1003+
"not all trait items implemented, missing: `{}`",
1004+
missing_items.iter()
1005+
.map(<ast::Name>::as_str)
1006+
.collect::<Vec<_>>().connect("`, `"))
1007+
}
1008+
1009+
if !invalidated_items.is_empty() {
1010+
let invalidator = overridden_associated_type.unwrap();
1011+
span_err!(tcx.sess, invalidator.span, E0399,
1012+
"the following trait items need to be reimplemented \
1013+
as `{}` was overridden: `{}`",
1014+
invalidator.ident.as_str(),
1015+
invalidated_items.iter()
1016+
.map(<ast::Name>::as_str)
1017+
.collect::<Vec<_>>().connect("`, `"))
10381018
}
10391019
}
10401020

src/librustc_typeck/diagnostics.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -2066,6 +2066,8 @@ register_diagnostics! {
20662066
// `#[lang = \"{}\"]` is allowed for the `{}` primitive
20672067
E0391, // unsupported cyclic reference between types/traits detected
20682068
E0392, // parameter `{}` is never used
2069-
E0393 // the type parameter `{}` must be explicitly specified in an object
2069+
E0393, // the type parameter `{}` must be explicitly specified in an object
20702070
// type because its default value `{}` references the type `Self`"
2071+
E0399 // trait items need to be implemented because the associated
2072+
// type `{}` was overridden
20712073
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(associated_consts)]
12+
13+
pub trait Tr {
14+
type Assoc = u8;
15+
type Assoc2 = Self::Assoc;
16+
const C: u8 = 11;
17+
fn foo(&self) {}
18+
}
19+
20+
impl Tr for () {
21+
type Assoc = ();
22+
//~^ ERROR need to be reimplemented as `Assoc` was overridden: `Assoc2`, `C`, `foo`
23+
}
24+
25+
fn main() {}

0 commit comments

Comments
 (0)