Skip to content

Commit

Permalink
Only do check for trait objects, not trait or trait alias definitions.
Browse files Browse the repository at this point in the history
  • Loading branch information
Alexander Regueiro committed Nov 7, 2018
1 parent 6d3ee41 commit 7d9ee03
Show file tree
Hide file tree
Showing 13 changed files with 112 additions and 163 deletions.
5 changes: 3 additions & 2 deletions src/librustc/ty/mod.rs
Expand Up @@ -1195,6 +1195,7 @@ impl<'a, 'gcx, 'tcx> Predicate<'tcx> {
pub struct TraitPredicate<'tcx> {
pub trait_ref: TraitRef<'tcx>
}

pub type PolyTraitPredicate<'tcx> = ty::Binder<TraitPredicate<'tcx>>;

impl<'tcx> TraitPredicate<'tcx> {
Expand Down Expand Up @@ -1516,14 +1517,14 @@ impl UniverseIndex {
UniverseIndex::from_u32(self.private.checked_add(1).unwrap())
}

/// `true` if `self` can name a name from `other` -- in other words,
/// Returns `true` if `self` can name a name from `other` -- in other words,
/// if the set of names in `self` is a superset of those in
/// `other` (`self >= other`).
pub fn can_name(self, other: UniverseIndex) -> bool {
self.private >= other.private
}

/// `true` if `self` cannot name some names from `other` -- in other
/// Returns `true` if `self` cannot name some names from `other` -- in other
/// words, if the set of names in `self` is a strict subset of
/// those in `other` (`self < other`).
pub fn cannot_name(self, other: UniverseIndex) -> bool {
Expand Down
117 changes: 44 additions & 73 deletions src/librustc_typeck/astconv.rs
Expand Up @@ -719,8 +719,6 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
speculative: bool)
-> ty::PolyTraitRef<'tcx>
{
let tcx = self.tcx();

let trait_def_id = self.trait_def_id(trait_ref);

debug!("instantiate_poly_trait_ref({:?}, def_id={:?})", trait_ref, trait_def_id);
Expand All @@ -734,74 +732,16 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
trait_ref.path.segments.last().unwrap());
let poly_trait_ref = ty::Binder::bind(ty::TraitRef::new(trait_def_id, substs));

let mut dup_bindings = FxHashMap::default();
poly_projections.extend(assoc_bindings.iter().filter_map(|binding| {
// specify type to assert that error was already reported in Err case:
let predicate: Result<_, ErrorReported> =
self.ast_type_binding_to_poly_projection_predicate(
trait_ref.ref_id, poly_trait_ref, binding, speculative);
trait_ref.ref_id, poly_trait_ref, binding, speculative, &mut dup_bindings);
// okay to ignore Err because of ErrorReported (see above)
Some((predicate.ok()?, binding.span))
}));

// make flat_map:
// for tr in traits::supertraits(tcx, poly_trait_ref) {
// let sup_trait_ref = tr.skip_binder();
// poly_projections.extend(sup_trait_ref.substs.types().filter_map(|t| {
// if let TyKind::Projection(proj) = t.sty {
// Some((proj, span))
// } else {
// None
// }
// });
// }

// Include all projections from associated type bindings of supertraits.
poly_projections.extend(traits::elaborate_trait_ref(tcx, poly_trait_ref)
.into_iter()
.filter_map(|pred| {
if let ty::Predicate::Projection(proj) = pred {
Some(proj)
} else {
None
}
})
.map(|proj| (proj, DUMMY_SP))
);

// // Include associated type bindings from supertraits.
// let mut foo = poly_projections.clone();
// foo.extend(tcx.predicates_of(trait_def_id)
// .predicates.into_iter()
// .filter_map(|(pred, span)| {
// debug!("pred: {:?}", pred);
// if let ty::Predicate::Projection(proj) = pred {
// Some((proj, span))
// } else {
// None
// }
// }));

// Check for multiple bindings of associated types.
let mut seen_projection_bounds = FxHashMap::default();
for (projection_bound, span) in poly_projections.iter().rev() {
let bound_def_id = projection_bound.projection_def_id();
let assoc_item = tcx.associated_item(bound_def_id);
let trait_def_id = assoc_item.container.id();
// let trait_ref = tcx.associated_item(proj.projection_type.item_def_id).container;
seen_projection_bounds.entry((assoc_item.def_id, bound_def_id))
.and_modify(|prev_span| {
struct_span_err!(tcx.sess, *span, E0719,
"the value of the associated type `{}` (from the trait `{}`) \
is already specified",
assoc_item.ident,
tcx.item_path_str(trait_def_id))
.span_label(*span, "re-bound here")
.span_label(*prev_span, format!("`{}` bound here first", assoc_item.ident))
.emit();
})
.or_insert(*span);
}

debug!("instantiate_poly_trait_ref({:?}, projections={:?}) -> {:?}",
trait_ref, poly_projections, poly_trait_ref);
poly_trait_ref
Expand Down Expand Up @@ -884,7 +824,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
ref_id: ast::NodeId,
trait_ref: ty::PolyTraitRef<'tcx>,
binding: &ConvertedBinding<'tcx>,
speculative: bool)
speculative: bool,
dup_bindings: &mut FxHashMap<DefId, Span>)
-> Result<ty::PolyProjectionPredicate<'tcx>, ErrorReported>
{
let tcx = self.tcx();
Expand Down Expand Up @@ -948,7 +889,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
let candidates = traits::supertraits(tcx, trait_ref).filter(|r| {
self.trait_defines_associated_type_named(r.def_id(), binding.item_name)
});
self.one_bound_for_assoc_type(candidates.into_iter(), &trait_ref.to_string(),
self.one_bound_for_assoc_type(candidates, &trait_ref.to_string(),
binding.item_name, binding.span)
}?;

Expand All @@ -964,6 +905,21 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
}
tcx.check_stability(assoc_ty.def_id, Some(ref_id), binding.span);

if !speculative {
dup_bindings.entry(assoc_ty.def_id)
.and_modify(|prev_span| {
struct_span_err!(self.tcx().sess, binding.span, E0719,
"the value of the associated type `{}` (from the trait `{}`) \
is already specified",
binding.item_name,
tcx.item_path_str(assoc_ty.container.id()))
.span_label(binding.span, "re-bound here")
.span_label(*prev_span, format!("`{}` bound here first", binding.item_name))
.emit();
})
.or_insert(binding.span);
}

Ok(candidate.map_bound(|trait_ref| {
ty::ProjectionPredicate {
projection_ty: ty::ProjectionTy::from_ref_and_name(
Expand All @@ -989,6 +945,14 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
)
}

/// Transform a `PolyTraitRef` into a `PolyExistentialTraitRef` by
/// removing the dummy `Self` type (`TRAIT_OBJECT_DUMMY_SELF`).
fn trait_ref_to_existential(&self, trait_ref: ty::TraitRef<'tcx>)
-> ty::ExistentialTraitRef<'tcx> {
assert_eq!(trait_ref.self_ty().sty, TRAIT_OBJECT_DUMMY_SELF);
ty::ExistentialTraitRef::erase_self_ty(self.tcx(), trait_ref)
}

fn conv_object_ty_poly_trait_ref(&self,
span: Span,
trait_bounds: &[hir::PolyTraitRef],
Expand Down Expand Up @@ -1043,13 +1007,22 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {
// Use a `BTreeSet` to keep output in a more consistent order.
let mut associated_types = BTreeSet::default();

for tr in traits::supertraits(tcx, principal) {
associated_types.extend(tcx.associated_items(tr.def_id())
.filter(|item| item.kind == ty::AssociatedKind::Type)
.map(|item| item.def_id));
for tr in traits::elaborate_trait_ref(tcx, principal) {
match tr {
ty::Predicate::Trait(pred) => {
associated_types.extend(tcx.associated_items(pred.def_id())
.filter(|item| item.kind == ty::AssociatedKind::Type)
.map(|item| item.def_id));
}
ty::Predicate::Projection(pred) => {
// Include projections defined on supertraits.
projection_bounds.push((pred, DUMMY_SP))
}
_ => ()
}
}

for (projection_bound, _) in projection_bounds.iter().rev() {
for (projection_bound, _) in &projection_bounds {
associated_types.remove(&projection_bound.projection_def_id());
}

Expand All @@ -1067,13 +1040,11 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o {

// Erase the `dummy_self` (`TRAIT_OBJECT_DUMMY_SELF`) used above.
let existential_principal = principal.map_bound(|trait_ref| {
assert_eq!(trait_ref.self_ty().sty, TRAIT_OBJECT_DUMMY_SELF);
ty::ExistentialTraitRef::erase_self_ty(self.tcx(), trait_ref)
self.trait_ref_to_existential(trait_ref)
});
let existential_projections = projection_bounds.iter().map(|(bound, _)| {
bound.map_bound(|b| {
let trait_ref = ty::ExistentialTraitRef::erase_self_ty(self.tcx(),
b.projection_ty.trait_ref(tcx));
let trait_ref = self.trait_ref_to_existential(b.projection_ty.trait_ref(tcx));
ty::ExistentialProjection {
ty: b.ty,
item_def_id: b.projection_ty.item_def_id,
Expand Down
Expand Up @@ -8,16 +8,9 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// compile-pass

use std::iter::Iterator;

type Unit = ();

fn test() -> Box<Iterator<Item = (), Item = Unit>> {
Box::new(None.into_iter())
}
trait Foo: Iterator<Item = i32> {}
trait Bar: Foo {}

fn main() {
test();
let _: &dyn Bar;
}
Expand Up @@ -13,5 +13,5 @@
trait I32Iterator = Iterator<Item = i32>;

fn main() {
let _: &I32Iterator<Item = u32>; //~ ERROR E0719
let _: &I32Iterator<Item = u32> = &vec![42].into_iter();
}
@@ -0,0 +1,13 @@
error[E0271]: type mismatch resolving `<std::vec::IntoIter<u32> as std::iter::Iterator>::Item == i32`
--> $DIR/associated-types-overridden-binding-2.rs:16:39
|
LL | let _: &I32Iterator<Item = u32> = &vec![42].into_iter();
| ^^^^^^^^^^^^^^^^^^^^^ expected u32, found i32
|
= note: expected type `u32`
found type `i32`
= note: required for the cast to the object type `dyn I32Iterator<Item=u32, Item=i32>`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0271`.
Expand Up @@ -10,9 +10,12 @@

#![feature(trait_alias)]

trait Foo: Iterator<Item = i32> {}
trait Bar: Foo<Item = u32> {}

trait I32Iterator = Iterator<Item = i32>;
trait I32Iterator2 = I32Iterator<Item = i32>; //~ ERROR E0719
trait U32Iterator = I32Iterator2<Item = i32>; //~ ERROR E0719
trait U32Iterator2 = U32Iterator<Item = u32>; //~ ERROR E0719
trait U32Iterator = I32Iterator<Item = u32>;

fn main() {}
fn main() {
let _: &I32Iterator<Item = u32>;
}
@@ -0,0 +1,15 @@
error[E0284]: type annotations required: cannot resolve `<Self as std::iter::Iterator>::Item == i32`
--> $DIR/associated-types-overridden-binding.rs:14:1
|
LL | trait Bar: Foo<Item = u32> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: required by `Foo`
--> $DIR/associated-types-overridden-binding.rs:13:1
|
LL | trait Foo: Iterator<Item = i32> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error

For more information about this error, try `rustc --explain E0284`.
12 changes: 0 additions & 12 deletions src/test/ui/error-codes/E0719-trait-alias-object.stderr

This file was deleted.

29 changes: 0 additions & 29 deletions src/test/ui/error-codes/E0719-trait-alias.stderr

This file was deleted.

11 changes: 10 additions & 1 deletion src/test/ui/error-codes/E0719.rs
Expand Up @@ -8,6 +8,15 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

trait Foo: Iterator<Item = i32, Item = i32> {}

type Unit = ();

fn test() -> Box<Iterator<Item = (), Item = Unit>> {
Box::new(None.into_iter())
}

fn main() {
let _: &Iterator<Item = i32, Item = i32>; //~ ERROR E0719
let _: &Iterator<Item = i32, Item = i32>;
test();
}
20 changes: 14 additions & 6 deletions src/test/ui/error-codes/E0719.stderr
@@ -1,11 +1,19 @@
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
--> $DIR/E0719.rs:12:22
--> $DIR/E0719.rs:11:33
|
LL | let _: &Iterator<Item = i32, Item = i32>; //~ ERROR E0719
| ^^^^^^^^^^ ---------- `Item` bound here first
| |
| re-bound here
LL | trait Foo: Iterator<Item = i32, Item = i32> {}
| ---------- ^^^^^^^^^^ re-bound here
| |
| `Item` bound here first

error: aborting due to previous error
error[E0719]: the value of the associated type `Item` (from the trait `std::iter::Iterator`) is already specified
--> $DIR/E0719.rs:15:38
|
LL | fn test() -> Box<Iterator<Item = (), Item = Unit>> {
| --------- ^^^^^^^^^^^ re-bound here
| |
| `Item` bound here first

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0719`.
23 changes: 0 additions & 23 deletions src/test/ui/lint/issue-50589-multiple-associated-types.stderr

This file was deleted.

0 comments on commit 7d9ee03

Please sign in to comment.