mirror of
https://github.com/rust-lang/rust.git
synced 2025-06-04 19:29:07 +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>
|
as Box<dyn Iterator<Item = AssociatedItem> + 'a>
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if the impls are the same polarity and are implementing
|
/// Returns true if the impls are the same polarity and the trait either
|
||||||
/// a trait which contains no items
|
/// 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 {
|
pub fn impls_are_allowed_to_overlap(self, def_id1: DefId, def_id2: DefId) -> bool {
|
||||||
if !self.features().overlapping_marker_traits {
|
if self.features().overlapping_marker_traits {
|
||||||
return 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
|
||||||
|
} 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,
|
// 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_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();
|
.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) {
|
pub fn provide(providers: &mut Providers) {
|
||||||
use self::builtin::coerce_unsized_info;
|
use self::builtin::coerce_unsized_info;
|
||||||
use self::inherent_impls::{crate_inherent_impls, inherent_impls};
|
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
|
E0641, // cannot cast to/from a pointer with an unknown kind
|
||||||
E0645, // trait aliases not finished
|
E0645, // trait aliases not finished
|
||||||
E0698, // type inside generator must be known in this context
|
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