mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-14 02:49:40 +00:00
Require that marker impls are empty, but allow them to overlap
This commit is contained in:
parent
6149a83c0b
commit
7cee7eee72
@ -2652,23 +2652,32 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
as Box<dyn Iterator<Item = AssociatedItem> + 'a>
|
||||
}
|
||||
|
||||
/// Returns true if the impls are the same polarity and are implementing
|
||||
/// a trait which contains no items
|
||||
/// Returns true if the impls are the same polarity and the trait either
|
||||
/// has no items or is annotated #[marker] and prevents item overrides.
|
||||
pub fn impls_are_allowed_to_overlap(self, def_id1: DefId, def_id2: DefId) -> bool {
|
||||
if !self.features().overlapping_marker_traits {
|
||||
return false;
|
||||
if self.features().overlapping_marker_traits {
|
||||
let trait1_is_empty = self.impl_trait_ref(def_id1)
|
||||
.map_or(false, |trait_ref| {
|
||||
self.associated_item_def_ids(trait_ref.def_id).is_empty()
|
||||
});
|
||||
let trait2_is_empty = self.impl_trait_ref(def_id2)
|
||||
.map_or(false, |trait_ref| {
|
||||
self.associated_item_def_ids(trait_ref.def_id).is_empty()
|
||||
});
|
||||
self.impl_polarity(def_id1) == self.impl_polarity(def_id2)
|
||||
&& trait1_is_empty
|
||||
&& trait2_is_empty
|
||||
} else if self.features().marker_trait_attr {
|
||||
let is_marker_impl = |def_id: DefId| -> bool {
|
||||
let trait_ref = self.impl_trait_ref(def_id);
|
||||
trait_ref.map_or(false, |tr| self.trait_def(tr.def_id).is_marker)
|
||||
};
|
||||
self.impl_polarity(def_id1) == self.impl_polarity(def_id2)
|
||||
&& is_marker_impl(def_id1)
|
||||
&& is_marker_impl(def_id2)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
let trait1_is_empty = self.impl_trait_ref(def_id1)
|
||||
.map_or(false, |trait_ref| {
|
||||
self.associated_item_def_ids(trait_ref.def_id).is_empty()
|
||||
});
|
||||
let trait2_is_empty = self.impl_trait_ref(def_id2)
|
||||
.map_or(false, |trait_ref| {
|
||||
self.associated_item_def_ids(trait_ref.def_id).is_empty()
|
||||
});
|
||||
self.impl_polarity(def_id1) == self.impl_polarity(def_id2)
|
||||
&& trait1_is_empty
|
||||
&& trait2_is_empty
|
||||
}
|
||||
|
||||
// Returns `ty::VariantDef` if `def` refers to a struct,
|
||||
|
@ -46,6 +46,7 @@ fn check_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, node_id: ast::NodeId) {
|
||||
}
|
||||
|
||||
enforce_trait_manually_implementable(tcx, impl_def_id, trait_ref.def_id);
|
||||
enforce_empty_impls_for_marker_traits(tcx, impl_def_id, trait_ref.def_id);
|
||||
}
|
||||
}
|
||||
|
||||
@ -99,6 +100,25 @@ fn enforce_trait_manually_implementable(tcx: TyCtxt, impl_def_id: DefId, trait_d
|
||||
.emit();
|
||||
}
|
||||
|
||||
/// We allow impls of marker traits to overlap, so they can't override impls
|
||||
/// as that could make it ambiguous which associated item to use.
|
||||
fn enforce_empty_impls_for_marker_traits(tcx: TyCtxt, impl_def_id: DefId, trait_def_id: DefId) {
|
||||
if !tcx.trait_def(trait_def_id).is_marker {
|
||||
return;
|
||||
}
|
||||
|
||||
if tcx.associated_item_def_ids(trait_def_id).is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let span = tcx.sess.source_map().def_span(tcx.span_of_impl(impl_def_id).unwrap());
|
||||
struct_span_err!(tcx.sess,
|
||||
span,
|
||||
E0715,
|
||||
"impls for marker traits cannot contain items")
|
||||
.emit();
|
||||
}
|
||||
|
||||
pub fn provide(providers: &mut Providers) {
|
||||
use self::builtin::coerce_unsized_info;
|
||||
use self::inherent_impls::{crate_inherent_impls, inherent_impls};
|
||||
|
@ -4833,4 +4833,5 @@ register_diagnostics! {
|
||||
E0641, // cannot cast to/from a pointer with an unknown kind
|
||||
E0645, // trait aliases not finished
|
||||
E0698, // type inside generator must be known in this context
|
||||
E0715, // impls for marker traits cannot contain items
|
||||
}
|
||||
|
@ -0,0 +1,35 @@
|
||||
// Copyright 2017 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.
|
||||
|
||||
// Tests for RFC 1268: we allow overlapping impls of marker traits,
|
||||
// that is, traits with #[marker]. In this case, a type `T` is
|
||||
// `MyMarker` if it is either `Debug` or `Display`.
|
||||
|
||||
#![feature(marker_trait_attr)]
|
||||
|
||||
use std::fmt::{Debug, Display};
|
||||
|
||||
#[marker] trait MyMarker {}
|
||||
|
||||
impl<T: Debug> MyMarker for T {}
|
||||
impl<T: Display> MyMarker for T {}
|
||||
|
||||
fn foo<T: MyMarker>(t: T) -> T {
|
||||
t
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// Debug && Display:
|
||||
assert_eq!(1, foo(1));
|
||||
assert_eq!(2.0, foo(2.0));
|
||||
|
||||
// Debug && !Display:
|
||||
assert_eq!(vec![1], foo(vec![1]));
|
||||
}
|
38
src/test/ui/marker_trait_attr/overlap-marker-trait.rs
Normal file
38
src/test/ui/marker_trait_attr/overlap-marker-trait.rs
Normal file
@ -0,0 +1,38 @@
|
||||
// Copyright 2018 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 for RFC 1268: we allow overlapping impls of marker traits,
|
||||
// that is, traits with #[marker]. In this case, a type `T` is
|
||||
// `MyMarker` if it is either `Debug` or `Display`. This test just
|
||||
// checks that we don't consider **all** types to be `MyMarker`.
|
||||
|
||||
#![feature(marker_trait_attr)]
|
||||
|
||||
use std::fmt::{Debug, Display};
|
||||
|
||||
#[marker] trait Marker {}
|
||||
|
||||
impl<T: Debug> Marker for T {}
|
||||
impl<T: Display> Marker for T {}
|
||||
|
||||
fn is_marker<T: Marker>() { }
|
||||
|
||||
struct NotDebugOrDisplay;
|
||||
|
||||
fn main() {
|
||||
// Debug && Display:
|
||||
is_marker::<i32>();
|
||||
|
||||
// Debug && !Display:
|
||||
is_marker::<Vec<i32>>();
|
||||
|
||||
// !Debug && !Display
|
||||
is_marker::<NotDebugOrDisplay>(); //~ ERROR
|
||||
}
|
15
src/test/ui/marker_trait_attr/overlap-marker-trait.stderr
Normal file
15
src/test/ui/marker_trait_attr/overlap-marker-trait.stderr
Normal file
@ -0,0 +1,15 @@
|
||||
error[E0277]: the trait bound `NotDebugOrDisplay: Marker` is not satisfied
|
||||
--> $DIR/overlap-marker-trait.rs:37:5
|
||||
|
|
||||
LL | is_marker::<NotDebugOrDisplay>(); //~ ERROR
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Marker` is not implemented for `NotDebugOrDisplay`
|
||||
|
|
||||
note: required by `is_marker`
|
||||
--> $DIR/overlap-marker-trait.rs:25:1
|
||||
|
|
||||
LL | fn is_marker<T: Marker>() { }
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
@ -0,0 +1,33 @@
|
||||
// Copyright 2018 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(marker_trait_attr)]
|
||||
|
||||
#[marker]
|
||||
trait Marker {
|
||||
const N: usize = 0;
|
||||
fn do_something() {}
|
||||
}
|
||||
|
||||
struct OverrideConst;
|
||||
impl Marker for OverrideConst {
|
||||
//~^ ERROR impls for marker traits cannot contain items
|
||||
const N: usize = 1;
|
||||
}
|
||||
|
||||
struct OverrideFn;
|
||||
impl Marker for OverrideFn {
|
||||
//~^ ERROR impls for marker traits cannot contain items
|
||||
fn do_something() {
|
||||
println!("Hello world!");
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,15 @@
|
||||
error[E0715]: impls for marker traits cannot contain items
|
||||
--> $DIR/override-item-on-marker-trait.rs:20:1
|
||||
|
|
||||
LL | impl Marker for OverrideConst {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0715]: impls for marker traits cannot contain items
|
||||
--> $DIR/override-item-on-marker-trait.rs:26:1
|
||||
|
|
||||
LL | impl Marker for OverrideFn {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0715`.
|
Loading…
Reference in New Issue
Block a user