mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 08:13:41 +00:00
Implement negative bounds
This commit is contained in:
parent
98c33e47a4
commit
6e01e910cb
@ -287,12 +287,20 @@ pub enum TraitBoundModifier {
|
||||
/// No modifiers
|
||||
None,
|
||||
|
||||
/// `!Trait`
|
||||
Negative,
|
||||
|
||||
/// `?Trait`
|
||||
Maybe,
|
||||
|
||||
/// `~const Trait`
|
||||
MaybeConst,
|
||||
|
||||
/// `~const !Trait`
|
||||
//
|
||||
// This parses but will be rejected during AST validation.
|
||||
MaybeConstNegative,
|
||||
|
||||
/// `~const ?Trait`
|
||||
//
|
||||
// This parses but will be rejected during AST validation.
|
||||
@ -2446,6 +2454,16 @@ impl fmt::Debug for ImplPolarity {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Encodable, Decodable, HashStable_Generic)]
|
||||
pub enum BoundPolarity {
|
||||
/// `Type: Trait`
|
||||
Positive,
|
||||
/// `Type: !Trait`
|
||||
Negative(Span),
|
||||
/// `Type: ?Trait`
|
||||
Maybe(Span),
|
||||
}
|
||||
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub enum FnRetTy {
|
||||
/// Returns type is not specified.
|
||||
|
@ -1368,13 +1368,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
this.arena.alloc_from_iter(bounds.iter().filter_map(|bound| match bound {
|
||||
GenericBound::Trait(
|
||||
ty,
|
||||
TraitBoundModifier::None | TraitBoundModifier::MaybeConst,
|
||||
TraitBoundModifier::None
|
||||
| TraitBoundModifier::MaybeConst
|
||||
| TraitBoundModifier::Negative,
|
||||
) => Some(this.lower_poly_trait_ref(ty, itctx)),
|
||||
// `~const ?Bound` will cause an error during AST validation
|
||||
// anyways, so treat it like `?Bound` as compilation proceeds.
|
||||
GenericBound::Trait(
|
||||
_,
|
||||
TraitBoundModifier::Maybe | TraitBoundModifier::MaybeConstMaybe,
|
||||
TraitBoundModifier::Maybe
|
||||
| TraitBoundModifier::MaybeConstMaybe
|
||||
| TraitBoundModifier::MaybeConstNegative,
|
||||
) => None,
|
||||
GenericBound::Outlives(lifetime) => {
|
||||
if lifetime_bound.is_none() {
|
||||
@ -2421,11 +2425,20 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
TraitBoundModifier::None => hir::TraitBoundModifier::None,
|
||||
TraitBoundModifier::MaybeConst => hir::TraitBoundModifier::MaybeConst,
|
||||
|
||||
TraitBoundModifier::Negative => {
|
||||
if self.tcx.features().negative_bounds {
|
||||
hir::TraitBoundModifier::Negative
|
||||
} else {
|
||||
hir::TraitBoundModifier::None
|
||||
}
|
||||
}
|
||||
|
||||
// `MaybeConstMaybe` will cause an error during AST validation, but we need to pick a
|
||||
// placeholder for compilation to proceed.
|
||||
TraitBoundModifier::MaybeConstMaybe | TraitBoundModifier::Maybe => {
|
||||
hir::TraitBoundModifier::Maybe
|
||||
}
|
||||
TraitBoundModifier::MaybeConstNegative => hir::TraitBoundModifier::MaybeConst,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -206,7 +206,7 @@ ast_passes_tilde_const_disallowed = `~const` is not allowed here
|
||||
.closure = closures cannot have `~const` trait bounds
|
||||
.function = this function is not `const`, so it cannot have `~const` trait bounds
|
||||
|
||||
ast_passes_optional_const_exclusive = `~const` and `?` are mutually exclusive
|
||||
ast_passes_optional_const_exclusive = `~const` and `{$modifier}` are mutually exclusive
|
||||
|
||||
ast_passes_const_and_async = functions cannot be both `const` and `async`
|
||||
.const = `const` because of this
|
||||
@ -235,3 +235,6 @@ ast_passes_incompatible_features = `{$f1}` and `{$f2}` are incompatible, using t
|
||||
.help = remove one of these features
|
||||
|
||||
ast_passes_show_span = {$msg}
|
||||
|
||||
ast_passes_negative_bound_not_supported =
|
||||
negative bounds are not supported
|
||||
|
@ -1168,7 +1168,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
});
|
||||
}
|
||||
(_, TraitBoundModifier::MaybeConstMaybe) => {
|
||||
self.err_handler().emit_err(errors::OptionalConstExclusive {span: bound.span()});
|
||||
self.err_handler().emit_err(errors::OptionalConstExclusive {span: bound.span(), modifier: "?" });
|
||||
}
|
||||
(_, TraitBoundModifier::MaybeConstNegative) => {
|
||||
self.err_handler().emit_err(errors::OptionalConstExclusive {span: bound.span(), modifier: "!" });
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
@ -567,6 +567,7 @@ pub enum TildeConstReason {
|
||||
pub struct OptionalConstExclusive {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
pub modifier: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
@ -693,3 +694,10 @@ pub struct ShowSpan {
|
||||
pub span: Span,
|
||||
pub msg: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_negative_bound_not_supported)]
|
||||
pub struct NegativeBoundUnsupported {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
@ -603,6 +603,12 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
|
||||
gate_all!(dyn_star, "`dyn*` trait objects are experimental");
|
||||
gate_all!(const_closures, "const closures are experimental");
|
||||
|
||||
if !visitor.features.negative_bounds {
|
||||
for &span in spans.get(&sym::negative_bounds).iter().copied().flatten() {
|
||||
sess.emit_err(errors::NegativeBoundUnsupported { span });
|
||||
}
|
||||
}
|
||||
|
||||
// All uses of `gate_all!` below this point were added in #65742,
|
||||
// and subsequently disabled (with the non-early gating readded).
|
||||
// We emit an early future-incompatible warning for these.
|
||||
|
@ -1570,12 +1570,19 @@ impl<'a> State<'a> {
|
||||
GenericBound::Trait(tref, modifier) => {
|
||||
match modifier {
|
||||
TraitBoundModifier::None => {}
|
||||
TraitBoundModifier::Negative => {
|
||||
self.word("!");
|
||||
}
|
||||
TraitBoundModifier::Maybe => {
|
||||
self.word("?");
|
||||
}
|
||||
TraitBoundModifier::MaybeConst => {
|
||||
self.word_space("~const");
|
||||
}
|
||||
TraitBoundModifier::MaybeConstNegative => {
|
||||
self.word_space("~const");
|
||||
self.word("!");
|
||||
}
|
||||
TraitBoundModifier::MaybeConstMaybe => {
|
||||
self.word_space("~const");
|
||||
self.word("?");
|
||||
|
@ -164,6 +164,8 @@ declare_features! (
|
||||
(active, link_cfg, "1.14.0", None, None),
|
||||
/// Allows the `multiple_supertrait_upcastable` lint.
|
||||
(active, multiple_supertrait_upcastable, "1.69.0", None, None),
|
||||
/// Allow negative trait bounds. This is an internal-only feature for testing the trait solver!
|
||||
(incomplete, negative_bounds, "CURRENT_RUSTC_VERSION", None, None),
|
||||
/// Allows using `#[omit_gdb_pretty_printer_section]`.
|
||||
(active, omit_gdb_pretty_printer_section, "1.5.0", None, None),
|
||||
/// Allows using `#[prelude_import]` on glob `use` items.
|
||||
|
@ -435,6 +435,7 @@ pub enum GenericArgsParentheses {
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
|
||||
pub enum TraitBoundModifier {
|
||||
None,
|
||||
Negative,
|
||||
Maybe,
|
||||
MaybeConst,
|
||||
}
|
||||
|
@ -665,6 +665,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
span: Span,
|
||||
binding_span: Option<Span>,
|
||||
constness: ty::BoundConstness,
|
||||
polarity: ty::ImplPolarity,
|
||||
bounds: &mut Bounds<'tcx>,
|
||||
speculative: bool,
|
||||
trait_ref_span: Span,
|
||||
@ -696,10 +697,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
ty::Binder::bind_with_vars(tcx.mk_trait_ref(trait_def_id, substs), bound_vars);
|
||||
|
||||
debug!(?poly_trait_ref, ?assoc_bindings);
|
||||
bounds.push_trait_bound(tcx, poly_trait_ref, span, constness);
|
||||
bounds.push_trait_bound(tcx, poly_trait_ref, span, constness, polarity);
|
||||
|
||||
let mut dup_bindings = FxHashMap::default();
|
||||
for binding in &assoc_bindings {
|
||||
// TODO: negative polarity can't have associated type bindings!
|
||||
|
||||
// Specify type to assert that error was already reported in `Err` case.
|
||||
let _: Result<_, ErrorGuaranteed> = self.add_predicates_for_ast_type_binding(
|
||||
hir_id,
|
||||
@ -711,6 +714,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
binding_span.unwrap_or(binding.span),
|
||||
constness,
|
||||
only_self_bounds,
|
||||
polarity,
|
||||
);
|
||||
// Okay to ignore `Err` because of `ErrorGuaranteed` (see above).
|
||||
}
|
||||
@ -743,6 +747,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
trait_ref: &hir::TraitRef<'_>,
|
||||
span: Span,
|
||||
constness: ty::BoundConstness,
|
||||
polarity: ty::ImplPolarity,
|
||||
self_ty: Ty<'tcx>,
|
||||
bounds: &mut Bounds<'tcx>,
|
||||
speculative: bool,
|
||||
@ -764,6 +769,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
span,
|
||||
binding_span,
|
||||
constness,
|
||||
polarity,
|
||||
bounds,
|
||||
speculative,
|
||||
trait_ref_span,
|
||||
@ -799,6 +805,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
span,
|
||||
binding_span,
|
||||
constness,
|
||||
ty::ImplPolarity::Positive,
|
||||
bounds,
|
||||
speculative,
|
||||
trait_ref_span,
|
||||
@ -961,16 +968,23 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
for ast_bound in ast_bounds {
|
||||
match ast_bound {
|
||||
hir::GenericBound::Trait(poly_trait_ref, modifier) => {
|
||||
let constness = match modifier {
|
||||
hir::TraitBoundModifier::MaybeConst => ty::BoundConstness::ConstIfConst,
|
||||
hir::TraitBoundModifier::None => ty::BoundConstness::NotConst,
|
||||
let (constness, polarity) = match modifier {
|
||||
hir::TraitBoundModifier::MaybeConst => {
|
||||
(ty::BoundConstness::ConstIfConst, ty::ImplPolarity::Positive)
|
||||
}
|
||||
hir::TraitBoundModifier::None => {
|
||||
(ty::BoundConstness::NotConst, ty::ImplPolarity::Positive)
|
||||
}
|
||||
hir::TraitBoundModifier::Negative => {
|
||||
(ty::BoundConstness::NotConst, ty::ImplPolarity::Negative)
|
||||
}
|
||||
hir::TraitBoundModifier::Maybe => continue,
|
||||
};
|
||||
|
||||
let _ = self.instantiate_poly_trait_ref(
|
||||
&poly_trait_ref.trait_ref,
|
||||
poly_trait_ref.span,
|
||||
constness,
|
||||
polarity,
|
||||
param_ty,
|
||||
bounds,
|
||||
false,
|
||||
@ -1088,6 +1102,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
path_span: Span,
|
||||
constness: ty::BoundConstness,
|
||||
only_self_bounds: OnlySelfBounds,
|
||||
polarity: ty::ImplPolarity,
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
// Given something like `U: SomeTrait<T = X>`, we want to produce a
|
||||
// predicate like `<U as SomeTrait>::T = X`. This is somewhat
|
||||
@ -1438,6 +1453,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
&trait_bound.trait_ref,
|
||||
trait_bound.span,
|
||||
ty::BoundConstness::NotConst,
|
||||
ty::ImplPolarity::Positive,
|
||||
dummy_self,
|
||||
&mut bounds,
|
||||
false,
|
||||
|
@ -42,8 +42,14 @@ impl<'tcx> Bounds<'tcx> {
|
||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
span: Span,
|
||||
constness: ty::BoundConstness,
|
||||
polarity: ty::ImplPolarity,
|
||||
) {
|
||||
self.predicates.push((trait_ref.with_constness(constness).to_predicate(tcx), span));
|
||||
self.predicates.push((
|
||||
trait_ref
|
||||
.map_bound(|trait_ref| ty::TraitPredicate { trait_ref, constness, polarity })
|
||||
.to_predicate(tcx),
|
||||
span,
|
||||
));
|
||||
}
|
||||
|
||||
pub fn push_projection_bound(
|
||||
|
@ -528,6 +528,7 @@ pub fn hir_trait_to_predicates<'tcx>(
|
||||
hir_trait,
|
||||
DUMMY_SP,
|
||||
ty::BoundConstness::NotConst,
|
||||
ty::ImplPolarity::Positive,
|
||||
self_ty,
|
||||
&mut bounds,
|
||||
true,
|
||||
|
@ -2816,6 +2816,9 @@ define_print_and_forward_display! {
|
||||
if let ty::BoundConstness::ConstIfConst = self.constness && cx.tcx().features().const_trait_impl {
|
||||
p!("~const ");
|
||||
}
|
||||
if let ty::ImplPolarity::Negative = self.polarity {
|
||||
p!("!");
|
||||
}
|
||||
p!(print(self.trait_ref.print_only_trait_path()))
|
||||
}
|
||||
|
||||
|
@ -615,13 +615,6 @@ parse_invalid_dyn_keyword = invalid `dyn` keyword
|
||||
.help = `dyn` is only needed at the start of a trait `+`-separated list
|
||||
.suggestion = remove this keyword
|
||||
|
||||
parse_negative_bounds_not_supported = negative bounds are not supported
|
||||
.label = negative bounds are not supported
|
||||
.suggestion = {$num_bounds ->
|
||||
[one] remove the bound
|
||||
*[other] remove the bounds
|
||||
}
|
||||
|
||||
parse_help_set_edition_cargo = set `edition = "{$edition}"` in `Cargo.toml`
|
||||
parse_help_set_edition_standalone = pass `--edition {$edition}` to `rustc`
|
||||
parse_note_edition_guide = for more on editions, read https://doc.rust-lang.org/edition-guide
|
||||
@ -772,7 +765,8 @@ parse_assoc_lifetime = associated lifetimes are not supported
|
||||
|
||||
parse_tilde_const_lifetime = `~const` may only modify trait bounds, not lifetime bounds
|
||||
|
||||
parse_maybe_lifetime = `?` may only modify trait bounds, not lifetime bounds
|
||||
parse_modifier_lifetime = `{$sigil}` may only modify trait bounds, not lifetime bounds
|
||||
.suggestion = remove the `{$sigil}`
|
||||
|
||||
parse_parenthesized_lifetime = parenthesized lifetime bounds are not supported
|
||||
.suggestion = remove the parentheses
|
||||
|
@ -2280,31 +2280,6 @@ pub(crate) struct InvalidDynKeyword {
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(parse_negative_bounds_not_supported)]
|
||||
pub(crate) struct NegativeBoundsNotSupported {
|
||||
#[primary_span]
|
||||
pub negative_bounds: Vec<Span>,
|
||||
#[label]
|
||||
pub last_span: Span,
|
||||
#[subdiagnostic]
|
||||
pub sub: Option<NegativeBoundsNotSupportedSugg>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[suggestion(
|
||||
parse_suggestion,
|
||||
style = "tool-only",
|
||||
code = "{fixed}",
|
||||
applicability = "machine-applicable"
|
||||
)]
|
||||
pub(crate) struct NegativeBoundsNotSupportedSugg {
|
||||
#[primary_span]
|
||||
pub bound_list: Span,
|
||||
pub num_bounds: usize,
|
||||
pub fixed: String,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
pub enum HelpUseLatestEdition {
|
||||
#[help(parse_help_set_edition_cargo)]
|
||||
@ -2412,10 +2387,12 @@ pub(crate) struct TildeConstLifetime {
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(parse_maybe_lifetime)]
|
||||
pub(crate) struct MaybeLifetime {
|
||||
#[diag(parse_modifier_lifetime)]
|
||||
pub(crate) struct ModifierLifetime {
|
||||
#[primary_span]
|
||||
#[suggestion(style = "tool-only", applicability = "maybe-incorrect", code = "")]
|
||||
pub span: Span,
|
||||
pub sigil: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
@ -1284,7 +1284,7 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
|
||||
self.bump(); // `+`
|
||||
let bounds = self.parse_generic_bounds(None)?;
|
||||
let bounds = self.parse_generic_bounds()?;
|
||||
let sum_span = ty.span.to(self.prev_token.span);
|
||||
|
||||
let sub = match &ty.kind {
|
||||
|
@ -78,7 +78,7 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
self.restore_snapshot(snapshot);
|
||||
}
|
||||
self.parse_generic_bounds(colon_span)?
|
||||
self.parse_generic_bounds()?
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
@ -419,7 +419,7 @@ impl<'a> Parser<'a> {
|
||||
// or with mandatory equality sign and the second type.
|
||||
let ty = self.parse_ty_for_where_clause()?;
|
||||
if self.eat(&token::Colon) {
|
||||
let bounds = self.parse_generic_bounds(Some(self.prev_token.span))?;
|
||||
let bounds = self.parse_generic_bounds()?;
|
||||
Ok(ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
|
||||
span: lo.to(self.prev_token.span),
|
||||
bound_generic_params: lifetime_defs,
|
||||
|
@ -788,11 +788,7 @@ impl<'a> Parser<'a> {
|
||||
// Parse optional colon and supertrait bounds.
|
||||
let had_colon = self.eat(&token::Colon);
|
||||
let span_at_colon = self.prev_token.span;
|
||||
let bounds = if had_colon {
|
||||
self.parse_generic_bounds(Some(self.prev_token.span))?
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
let bounds = if had_colon { self.parse_generic_bounds()? } else { Vec::new() };
|
||||
|
||||
let span_before_eq = self.prev_token.span;
|
||||
if self.eat(&token::Eq) {
|
||||
@ -802,7 +798,7 @@ impl<'a> Parser<'a> {
|
||||
self.sess.emit_err(errors::BoundsNotAllowedOnTraitAliases { span });
|
||||
}
|
||||
|
||||
let bounds = self.parse_generic_bounds(None)?;
|
||||
let bounds = self.parse_generic_bounds()?;
|
||||
generics.where_clause = self.parse_where_clause()?;
|
||||
self.expect_semi()?;
|
||||
|
||||
@ -883,7 +879,7 @@ impl<'a> Parser<'a> {
|
||||
|
||||
// Parse optional colon and param bounds.
|
||||
let bounds =
|
||||
if self.eat(&token::Colon) { self.parse_generic_bounds(None)? } else { Vec::new() };
|
||||
if self.eat(&token::Colon) { self.parse_generic_bounds()? } else { Vec::new() };
|
||||
let before_where_clause = self.parse_where_clause()?;
|
||||
|
||||
let ty = if self.eat(&token::Eq) { Some(self.parse_ty()?) } else { None };
|
||||
|
@ -606,7 +606,7 @@ impl<'a> Parser<'a> {
|
||||
let kind = if self.eat(&token::Colon) {
|
||||
// Parse associated type constraint bound.
|
||||
|
||||
let bounds = self.parse_generic_bounds(Some(self.prev_token.span))?;
|
||||
let bounds = self.parse_generic_bounds()?;
|
||||
AssocConstraintKind::Bound { bounds }
|
||||
} else if self.eat(&token::Eq) {
|
||||
self.parse_assoc_equality_term(ident, self.prev_token.span)?
|
||||
|
@ -3,8 +3,7 @@ use super::{Parser, PathStyle, TokenType};
|
||||
use crate::errors::{
|
||||
self, DynAfterMut, ExpectedFnPathFoundFnKeyword, ExpectedMutOrConstInRawPointerType,
|
||||
FnPointerCannotBeAsync, FnPointerCannotBeConst, FnPtrWithGenerics, FnPtrWithGenericsSugg,
|
||||
InvalidDynKeyword, LifetimeAfterMut, NeedPlusAfterTraitObjectLifetime,
|
||||
NegativeBoundsNotSupported, NegativeBoundsNotSupportedSugg, NestedCVariadicType,
|
||||
InvalidDynKeyword, LifetimeAfterMut, NeedPlusAfterTraitObjectLifetime, NestedCVariadicType,
|
||||
ReturnTypesUseThinArrow,
|
||||
};
|
||||
use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
|
||||
@ -14,8 +13,9 @@ use rustc_ast::ptr::P;
|
||||
use rustc_ast::token::{self, Delimiter, Token, TokenKind};
|
||||
use rustc_ast::util::case::Case;
|
||||
use rustc_ast::{
|
||||
self as ast, BareFnTy, FnRetTy, GenericBound, GenericBounds, GenericParam, Generics, Lifetime,
|
||||
MacCall, MutTy, Mutability, PolyTraitRef, TraitBoundModifier, TraitObjectSyntax, Ty, TyKind,
|
||||
self as ast, BareFnTy, BoundPolarity, FnRetTy, GenericBound, GenericBounds, GenericParam,
|
||||
Generics, Lifetime, MacCall, MutTy, Mutability, PolyTraitRef, TraitBoundModifier,
|
||||
TraitObjectSyntax, Ty, TyKind,
|
||||
};
|
||||
use rustc_errors::{Applicability, PResult};
|
||||
use rustc_span::source_map::Span;
|
||||
@ -23,10 +23,10 @@ use rustc_span::symbol::{kw, sym, Ident};
|
||||
use rustc_span::Symbol;
|
||||
use thin_vec::{thin_vec, ThinVec};
|
||||
|
||||
/// Any `?` or `~const` modifiers that appear at the start of a bound.
|
||||
/// Any `?`, `!`, or `~const` modifiers that appear at the start of a bound.
|
||||
struct BoundModifiers {
|
||||
/// `?Trait`.
|
||||
maybe: Option<Span>,
|
||||
bound_polarity: BoundPolarity,
|
||||
|
||||
/// `~const Trait`.
|
||||
maybe_const: Option<Span>,
|
||||
@ -34,11 +34,13 @@ struct BoundModifiers {
|
||||
|
||||
impl BoundModifiers {
|
||||
fn to_trait_bound_modifier(&self) -> TraitBoundModifier {
|
||||
match (self.maybe, self.maybe_const) {
|
||||
(None, None) => TraitBoundModifier::None,
|
||||
(Some(_), None) => TraitBoundModifier::Maybe,
|
||||
(None, Some(_)) => TraitBoundModifier::MaybeConst,
|
||||
(Some(_), Some(_)) => TraitBoundModifier::MaybeConstMaybe,
|
||||
match (self.bound_polarity, self.maybe_const) {
|
||||
(BoundPolarity::Positive, None) => TraitBoundModifier::None,
|
||||
(BoundPolarity::Negative(_), None) => TraitBoundModifier::Negative,
|
||||
(BoundPolarity::Maybe(_), None) => TraitBoundModifier::Maybe,
|
||||
(BoundPolarity::Positive, Some(_)) => TraitBoundModifier::MaybeConst,
|
||||
(BoundPolarity::Negative(_), Some(_)) => TraitBoundModifier::MaybeConstNegative,
|
||||
(BoundPolarity::Maybe(_), Some(_)) => TraitBoundModifier::MaybeConstMaybe,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -368,7 +370,7 @@ impl<'a> Parser<'a> {
|
||||
|
||||
fn parse_bare_trait_object(&mut self, lo: Span, allow_plus: AllowPlus) -> PResult<'a, TyKind> {
|
||||
let lt_no_plus = self.check_lifetime() && !self.look_ahead(1, |t| t.is_like_plus());
|
||||
let bounds = self.parse_generic_bounds_common(allow_plus, None)?;
|
||||
let bounds = self.parse_generic_bounds_common(allow_plus)?;
|
||||
if lt_no_plus {
|
||||
self.sess.emit_err(NeedPlusAfterTraitObjectLifetime { span: lo });
|
||||
}
|
||||
@ -395,7 +397,7 @@ impl<'a> Parser<'a> {
|
||||
) -> PResult<'a, TyKind> {
|
||||
if plus {
|
||||
self.eat_plus(); // `+`, or `+=` gets split and `+` is discarded
|
||||
bounds.append(&mut self.parse_generic_bounds(Some(self.prev_token.span))?);
|
||||
bounds.append(&mut self.parse_generic_bounds()?);
|
||||
}
|
||||
Ok(TyKind::TraitObject(bounds, TraitObjectSyntax::None))
|
||||
}
|
||||
@ -598,7 +600,7 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
})
|
||||
}
|
||||
let bounds = self.parse_generic_bounds(None)?;
|
||||
let bounds = self.parse_generic_bounds()?;
|
||||
*impl_dyn_multi = bounds.len() > 1 || self.prev_token.kind == TokenKind::BinOp(token::Plus);
|
||||
Ok(TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds))
|
||||
}
|
||||
@ -629,7 +631,7 @@ impl<'a> Parser<'a> {
|
||||
};
|
||||
|
||||
// Always parse bounds greedily for better error recovery.
|
||||
let bounds = self.parse_generic_bounds(None)?;
|
||||
let bounds = self.parse_generic_bounds()?;
|
||||
*impl_dyn_multi = bounds.len() > 1 || self.prev_token.kind == TokenKind::BinOp(token::Plus);
|
||||
Ok(TyKind::TraitObject(bounds, syntax))
|
||||
}
|
||||
@ -660,23 +662,15 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn parse_generic_bounds(
|
||||
&mut self,
|
||||
colon_span: Option<Span>,
|
||||
) -> PResult<'a, GenericBounds> {
|
||||
self.parse_generic_bounds_common(AllowPlus::Yes, colon_span)
|
||||
pub(super) fn parse_generic_bounds(&mut self) -> PResult<'a, GenericBounds> {
|
||||
self.parse_generic_bounds_common(AllowPlus::Yes)
|
||||
}
|
||||
|
||||
/// Parses bounds of a type parameter `BOUND + BOUND + ...`, possibly with trailing `+`.
|
||||
///
|
||||
/// See `parse_generic_bound` for the `BOUND` grammar.
|
||||
fn parse_generic_bounds_common(
|
||||
&mut self,
|
||||
allow_plus: AllowPlus,
|
||||
colon_span: Option<Span>,
|
||||
) -> PResult<'a, GenericBounds> {
|
||||
fn parse_generic_bounds_common(&mut self, allow_plus: AllowPlus) -> PResult<'a, GenericBounds> {
|
||||
let mut bounds = Vec::new();
|
||||
let mut negative_bounds = Vec::new();
|
||||
|
||||
// In addition to looping while we find generic bounds:
|
||||
// We continue even if we find a keyword. This is necessary for error recovery on,
|
||||
@ -693,19 +687,12 @@ impl<'a> Parser<'a> {
|
||||
self.sess.emit_err(InvalidDynKeyword { span: self.token.span });
|
||||
self.bump();
|
||||
}
|
||||
match self.parse_generic_bound()? {
|
||||
Ok(bound) => bounds.push(bound),
|
||||
Err(neg_sp) => negative_bounds.push(neg_sp),
|
||||
}
|
||||
bounds.push(self.parse_generic_bound()?);
|
||||
if allow_plus == AllowPlus::No || !self.eat_plus() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if !negative_bounds.is_empty() {
|
||||
self.error_negative_bounds(colon_span, &bounds, negative_bounds);
|
||||
}
|
||||
|
||||
Ok(bounds)
|
||||
}
|
||||
|
||||
@ -713,55 +700,22 @@ impl<'a> Parser<'a> {
|
||||
fn can_begin_bound(&mut self) -> bool {
|
||||
// This needs to be synchronized with `TokenKind::can_begin_bound`.
|
||||
self.check_path()
|
||||
|| self.check_lifetime()
|
||||
|| self.check(&token::Not) // Used for error reporting only.
|
||||
|| self.check(&token::Question)
|
||||
|| self.check(&token::Tilde)
|
||||
|| self.check_keyword(kw::For)
|
||||
|| self.check(&token::OpenDelim(Delimiter::Parenthesis))
|
||||
}
|
||||
|
||||
fn error_negative_bounds(
|
||||
&self,
|
||||
colon_span: Option<Span>,
|
||||
bounds: &[GenericBound],
|
||||
negative_bounds: Vec<Span>,
|
||||
) {
|
||||
let sub = if let Some(bound_list) = colon_span {
|
||||
let bound_list = bound_list.to(self.prev_token.span);
|
||||
let mut new_bound_list = String::new();
|
||||
if !bounds.is_empty() {
|
||||
let mut snippets = bounds.iter().map(|bound| self.span_to_snippet(bound.span()));
|
||||
while let Some(Ok(snippet)) = snippets.next() {
|
||||
new_bound_list.push_str(" + ");
|
||||
new_bound_list.push_str(&snippet);
|
||||
}
|
||||
new_bound_list = new_bound_list.replacen(" +", ":", 1);
|
||||
}
|
||||
|
||||
Some(NegativeBoundsNotSupportedSugg {
|
||||
bound_list,
|
||||
num_bounds: negative_bounds.len(),
|
||||
fixed: new_bound_list,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let last_span = *negative_bounds.last().expect("no negative bounds, but still error?");
|
||||
self.sess.emit_err(NegativeBoundsNotSupported { negative_bounds, last_span, sub });
|
||||
|| self.check_lifetime()
|
||||
|| self.check(&token::Not)
|
||||
|| self.check(&token::Question)
|
||||
|| self.check(&token::Tilde)
|
||||
|| self.check_keyword(kw::For)
|
||||
|| self.check(&token::OpenDelim(Delimiter::Parenthesis))
|
||||
}
|
||||
|
||||
/// Parses a bound according to the grammar:
|
||||
/// ```ebnf
|
||||
/// BOUND = TY_BOUND | LT_BOUND
|
||||
/// ```
|
||||
fn parse_generic_bound(&mut self) -> PResult<'a, Result<GenericBound, Span>> {
|
||||
let anchor_lo = self.prev_token.span;
|
||||
fn parse_generic_bound(&mut self) -> PResult<'a, GenericBound> {
|
||||
let lo = self.token.span;
|
||||
let has_parens = self.eat(&token::OpenDelim(Delimiter::Parenthesis));
|
||||
let inner_lo = self.token.span;
|
||||
let is_negative = self.eat(&token::Not);
|
||||
|
||||
let modifiers = self.parse_ty_bound_modifiers()?;
|
||||
let bound = if self.token.is_lifetime() {
|
||||
@ -771,7 +725,7 @@ impl<'a> Parser<'a> {
|
||||
self.parse_generic_ty_bound(lo, has_parens, modifiers)?
|
||||
};
|
||||
|
||||
Ok(if is_negative { Err(anchor_lo.to(self.prev_token.span)) } else { Ok(bound) })
|
||||
Ok(bound)
|
||||
}
|
||||
|
||||
/// Parses a lifetime ("outlives") bound, e.g. `'a`, according to:
|
||||
@ -799,8 +753,14 @@ impl<'a> Parser<'a> {
|
||||
self.sess.emit_err(errors::TildeConstLifetime { span });
|
||||
}
|
||||
|
||||
if let Some(span) = modifiers.maybe {
|
||||
self.sess.emit_err(errors::MaybeLifetime { span });
|
||||
match modifiers.bound_polarity {
|
||||
BoundPolarity::Positive => {}
|
||||
BoundPolarity::Negative(span) => {
|
||||
self.sess.emit_err(errors::ModifierLifetime { span, sigil: "!" });
|
||||
}
|
||||
BoundPolarity::Maybe(span) => {
|
||||
self.sess.emit_err(errors::ModifierLifetime { span, sigil: "?" });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -843,9 +803,16 @@ impl<'a> Parser<'a> {
|
||||
None
|
||||
};
|
||||
|
||||
let maybe = self.eat(&token::Question).then_some(self.prev_token.span);
|
||||
let bound_polarity = if self.eat(&token::Question) {
|
||||
BoundPolarity::Maybe(self.prev_token.span)
|
||||
} else if self.eat(&token::Not) {
|
||||
self.sess.gated_spans.gate(sym::negative_bounds, self.prev_token.span);
|
||||
BoundPolarity::Negative(self.prev_token.span)
|
||||
} else {
|
||||
BoundPolarity::Positive
|
||||
};
|
||||
|
||||
Ok(BoundModifiers { maybe, maybe_const })
|
||||
Ok(BoundModifiers { bound_polarity, maybe_const })
|
||||
}
|
||||
|
||||
/// Parses a type bound according to:
|
||||
|
@ -984,6 +984,7 @@ symbols! {
|
||||
needs_panic_runtime,
|
||||
neg,
|
||||
negate_unsigned,
|
||||
negative_bounds,
|
||||
negative_impls,
|
||||
neon,
|
||||
never,
|
||||
|
@ -530,6 +530,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||
associated_ty: Option<(&'static str, Ty<'tcx>)>,
|
||||
mut body_id: LocalDefId,
|
||||
) {
|
||||
if trait_pred.skip_binder().polarity == ty::ImplPolarity::Negative {
|
||||
return;
|
||||
}
|
||||
|
||||
let trait_pred = self.resolve_numeric_literals_with_default(trait_pred);
|
||||
|
||||
let self_ty = trait_pred.skip_binder().self_ty();
|
||||
|
4
tests/ui/feature-gates/feature-gate-negative_bounds.rs
Normal file
4
tests/ui/feature-gates/feature-gate-negative_bounds.rs
Normal file
@ -0,0 +1,4 @@
|
||||
fn test<T: !Copy>() {}
|
||||
//~^ ERROR negative bounds are not supported
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,8 @@
|
||||
error: negative bounds are not supported
|
||||
--> $DIR/feature-gate-negative_bounds.rs:1:12
|
||||
|
|
||||
LL | fn test<T: !Copy>() {}
|
||||
| ^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
@ -1,8 +1,8 @@
|
||||
error: negative bounds are not supported
|
||||
--> $DIR/issue-58857.rs:4:7
|
||||
--> $DIR/issue-58857.rs:4:9
|
||||
|
|
||||
LL | impl<A: !Valid> Conj<A>{}
|
||||
| ^^^^^^^^ negative bounds are not supported
|
||||
| ^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
|
@ -1,19 +0,0 @@
|
||||
// run-rustfix
|
||||
|
||||
trait Tr {}
|
||||
//~^ ERROR negative bounds are not supported
|
||||
trait Tr2: SuperA {}
|
||||
//~^ ERROR negative bounds are not supported
|
||||
trait Tr3: SuperB {}
|
||||
//~^ ERROR negative bounds are not supported
|
||||
trait Tr4: SuperB + SuperD {}
|
||||
//~^ ERROR negative bounds are not supported
|
||||
trait Tr5 {}
|
||||
//~^ ERROR negative bounds are not supported
|
||||
|
||||
trait SuperA {}
|
||||
trait SuperB {}
|
||||
trait SuperC {}
|
||||
trait SuperD {}
|
||||
|
||||
fn main() {}
|
@ -1,5 +1,3 @@
|
||||
// run-rustfix
|
||||
|
||||
trait Tr: !SuperA {}
|
||||
//~^ ERROR negative bounds are not supported
|
||||
trait Tr2: SuperA + !SuperB {}
|
||||
@ -7,10 +5,12 @@ trait Tr2: SuperA + !SuperB {}
|
||||
trait Tr3: !SuperA + SuperB {}
|
||||
//~^ ERROR negative bounds are not supported
|
||||
trait Tr4: !SuperA + SuperB
|
||||
+ !SuperC + SuperD {}
|
||||
//~^ ERROR negative bounds are not supported
|
||||
+ !SuperC + SuperD {}
|
||||
//~^ ERROR negative bounds are not supported
|
||||
trait Tr5: !SuperA
|
||||
+ !SuperB {}
|
||||
//~^ ERROR negative bounds are not supported
|
||||
+ !SuperB {}
|
||||
//~^ ERROR negative bounds are not supported
|
||||
|
||||
trait SuperA {}
|
||||
|
@ -1,36 +1,44 @@
|
||||
error: negative bounds are not supported
|
||||
--> $DIR/issue-33418.rs:3:9
|
||||
--> $DIR/issue-33418.rs:1:11
|
||||
|
|
||||
LL | trait Tr: !SuperA {}
|
||||
| ^^^^^^^^^ negative bounds are not supported
|
||||
| ^
|
||||
|
||||
error: negative bounds are not supported
|
||||
--> $DIR/issue-33418.rs:5:19
|
||||
--> $DIR/issue-33418.rs:3:21
|
||||
|
|
||||
LL | trait Tr2: SuperA + !SuperB {}
|
||||
| ^^^^^^^^^ negative bounds are not supported
|
||||
| ^
|
||||
|
||||
error: negative bounds are not supported
|
||||
--> $DIR/issue-33418.rs:7:10
|
||||
--> $DIR/issue-33418.rs:5:12
|
||||
|
|
||||
LL | trait Tr3: !SuperA + SuperB {}
|
||||
| ^^^^^^^^^ negative bounds are not supported
|
||||
| ^
|
||||
|
||||
error: negative bounds are not supported
|
||||
--> $DIR/issue-33418.rs:9:10
|
||||
--> $DIR/issue-33418.rs:7:12
|
||||
|
|
||||
LL | trait Tr4: !SuperA + SuperB
|
||||
| ^^^^^^^^^
|
||||
LL | + !SuperC + SuperD {}
|
||||
| ^^^^^^^^^ negative bounds are not supported
|
||||
| ^
|
||||
|
||||
error: negative bounds are not supported
|
||||
--> $DIR/issue-33418.rs:12:10
|
||||
--> $DIR/issue-33418.rs:9:3
|
||||
|
|
||||
LL | + !SuperC + SuperD {}
|
||||
| ^
|
||||
|
||||
error: negative bounds are not supported
|
||||
--> $DIR/issue-33418.rs:11:12
|
||||
|
|
||||
LL | trait Tr5: !SuperA
|
||||
| ^^^^^^^^^
|
||||
LL | + !SuperB {}
|
||||
| ^^^^^^^^^ negative bounds are not supported
|
||||
| ^
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
error: negative bounds are not supported
|
||||
--> $DIR/issue-33418.rs:13:3
|
||||
|
|
||||
LL | + !SuperB {}
|
||||
| ^
|
||||
|
||||
error: aborting due to 7 previous errors
|
||||
|
||||
|
@ -6,9 +6,12 @@
|
||||
|
||||
fn main() {}
|
||||
|
||||
pub fn f1<T>() {}
|
||||
pub fn f1<T: 'static>() {}
|
||||
//~^ ERROR negative bounds are not supported
|
||||
pub fn f2<'a, T: Ord>() {}
|
||||
//~| ERROR `!` may only modify trait bounds, not lifetime bound
|
||||
pub fn f2<'a, T: Ord + 'a>() {}
|
||||
//~^ ERROR negative bounds are not supported
|
||||
pub fn f3<'a, T: Ord>() {}
|
||||
//~| ERROR `!` may only modify trait bounds, not lifetime bound
|
||||
pub fn f3<'a, T: 'a + Ord>() {}
|
||||
//~^ ERROR negative bounds are not supported
|
||||
//~| ERROR `!` may only modify trait bounds, not lifetime bound
|
||||
|
@ -8,7 +8,10 @@ fn main() {}
|
||||
|
||||
pub fn f1<T: !'static>() {}
|
||||
//~^ ERROR negative bounds are not supported
|
||||
//~| ERROR `!` may only modify trait bounds, not lifetime bound
|
||||
pub fn f2<'a, T: Ord + !'a>() {}
|
||||
//~^ ERROR negative bounds are not supported
|
||||
//~| ERROR `!` may only modify trait bounds, not lifetime bound
|
||||
pub fn f3<'a, T: !'a + Ord>() {}
|
||||
//~^ ERROR negative bounds are not supported
|
||||
//~| ERROR `!` may only modify trait bounds, not lifetime bound
|
||||
|
@ -1,20 +1,38 @@
|
||||
error: negative bounds are not supported
|
||||
--> $DIR/issue-67146-negative-outlives-bound-syntactic-fail.rs:9:12
|
||||
error: `!` may only modify trait bounds, not lifetime bounds
|
||||
--> $DIR/issue-67146-negative-outlives-bound-syntactic-fail.rs:9:14
|
||||
|
|
||||
LL | pub fn f1<T: !'static>() {}
|
||||
| ^^^^^^^^^^ negative bounds are not supported
|
||||
| ^
|
||||
|
||||
error: negative bounds are not supported
|
||||
--> $DIR/issue-67146-negative-outlives-bound-syntactic-fail.rs:11:22
|
||||
error: `!` may only modify trait bounds, not lifetime bounds
|
||||
--> $DIR/issue-67146-negative-outlives-bound-syntactic-fail.rs:12:24
|
||||
|
|
||||
LL | pub fn f2<'a, T: Ord + !'a>() {}
|
||||
| ^^^^^ negative bounds are not supported
|
||||
| ^
|
||||
|
||||
error: negative bounds are not supported
|
||||
--> $DIR/issue-67146-negative-outlives-bound-syntactic-fail.rs:13:16
|
||||
error: `!` may only modify trait bounds, not lifetime bounds
|
||||
--> $DIR/issue-67146-negative-outlives-bound-syntactic-fail.rs:15:18
|
||||
|
|
||||
LL | pub fn f3<'a, T: !'a + Ord>() {}
|
||||
| ^^^^^ negative bounds are not supported
|
||||
| ^
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
error: negative bounds are not supported
|
||||
--> $DIR/issue-67146-negative-outlives-bound-syntactic-fail.rs:9:14
|
||||
|
|
||||
LL | pub fn f1<T: !'static>() {}
|
||||
| ^
|
||||
|
||||
error: negative bounds are not supported
|
||||
--> $DIR/issue-67146-negative-outlives-bound-syntactic-fail.rs:12:24
|
||||
|
|
||||
LL | pub fn f2<'a, T: Ord + !'a>() {}
|
||||
| ^
|
||||
|
||||
error: negative bounds are not supported
|
||||
--> $DIR/issue-67146-negative-outlives-bound-syntactic-fail.rs:15:18
|
||||
|
|
||||
LL | pub fn f3<'a, T: !'a + Ord>() {}
|
||||
| ^
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
|
||||
|
42
tests/ui/traits/negative-bounds/simple.rs
Normal file
42
tests/ui/traits/negative-bounds/simple.rs
Normal file
@ -0,0 +1,42 @@
|
||||
#![feature(negative_bounds, negative_impls)]
|
||||
//~^ WARN the feature `negative_bounds` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
|
||||
fn not_copy<T: !Copy>() {}
|
||||
|
||||
fn neg_param_env<T: !Copy>() {
|
||||
not_copy::<T>();
|
||||
}
|
||||
|
||||
fn pos_param_env<T: Copy>() {
|
||||
not_copy::<T>();
|
||||
//~^ ERROR the trait bound `T: !Copy` is not satisfied
|
||||
}
|
||||
|
||||
fn unknown<T>() {
|
||||
not_copy::<T>();
|
||||
//~^ ERROR the trait bound `T: !Copy` is not satisfied
|
||||
}
|
||||
|
||||
struct NotCopyable;
|
||||
impl !Copy for NotCopyable {}
|
||||
|
||||
fn neg_impl() {
|
||||
not_copy::<NotCopyable>();
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
struct Copyable;
|
||||
|
||||
fn pos_impl() {
|
||||
not_copy::<Copyable>();
|
||||
//~^ ERROR the trait bound `Copyable: !Copy` is not satisfied
|
||||
}
|
||||
|
||||
struct NotNecessarilyCopyable;
|
||||
|
||||
fn unknown_impl() {
|
||||
not_copy::<NotNecessarilyCopyable>();
|
||||
//~^ ERROR the trait bound `NotNecessarilyCopyable: !Copy` is not satisfied
|
||||
}
|
||||
|
||||
fn main() {}
|
82
tests/ui/traits/negative-bounds/simple.stderr
Normal file
82
tests/ui/traits/negative-bounds/simple.stderr
Normal file
@ -0,0 +1,82 @@
|
||||
warning: the feature `negative_bounds` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/simple.rs:1:12
|
||||
|
|
||||
LL | #![feature(negative_bounds, negative_impls)]
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
|
||||
error[E0277]: the trait bound `T: !Copy` is not satisfied
|
||||
--> $DIR/simple.rs:6:16
|
||||
|
|
||||
LL | not_copy::<T>();
|
||||
| ^ the trait `!Copy` is not implemented for `T`
|
||||
|
|
||||
note: required by a bound in `not_copy`
|
||||
--> $DIR/simple.rs:3:16
|
||||
|
|
||||
LL | fn not_copy<T: !Copy>() {}
|
||||
| ^^^^^ required by this bound in `not_copy`
|
||||
|
||||
error[E0277]: the trait bound `T: !Copy` is not satisfied
|
||||
--> $DIR/simple.rs:10:16
|
||||
|
|
||||
LL | not_copy::<T>();
|
||||
| ^ the trait `!Copy` is not implemented for `T`
|
||||
|
|
||||
note: required by a bound in `not_copy`
|
||||
--> $DIR/simple.rs:4:16
|
||||
|
|
||||
LL | fn not_copy<T: !Copy>() {}
|
||||
| ^^^^^ required by this bound in `not_copy`
|
||||
|
||||
error[E0277]: the trait bound `T: !Copy` is not satisfied
|
||||
--> $DIR/simple.rs:16:16
|
||||
|
|
||||
LL | not_copy::<T>();
|
||||
| ^ the trait `!Copy` is not implemented for `T`
|
||||
|
|
||||
note: required by a bound in `not_copy`
|
||||
--> $DIR/simple.rs:4:16
|
||||
|
|
||||
LL | fn not_copy<T: !Copy>() {}
|
||||
| ^^^^^ required by this bound in `not_copy`
|
||||
|
||||
error[E0277]: the trait bound `Copyable: !Copy` is not satisfied
|
||||
--> $DIR/simple.rs:31:16
|
||||
|
|
||||
LL | not_copy::<Copyable>();
|
||||
| ^^^^^^^^ the trait `!Copy` is not implemented for `Copyable`
|
||||
|
|
||||
= help: the trait `Copy` is implemented for `Copyable`
|
||||
note: required by a bound in `not_copy`
|
||||
--> $DIR/simple.rs:4:16
|
||||
|
|
||||
LL | fn not_copy<T: !Copy>() {}
|
||||
| ^^^^^ required by this bound in `not_copy`
|
||||
help: consider annotating `Copyable` with `#[derive(Copy)]`
|
||||
|
|
||||
LL + #[derive(Copy)]
|
||||
LL | struct Copyable;
|
||||
|
|
||||
|
||||
error[E0277]: the trait bound `NotNecessarilyCopyable: !Copy` is not satisfied
|
||||
--> $DIR/simple.rs:38:16
|
||||
|
|
||||
LL | not_copy::<NotNecessarilyCopyable>();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ the trait `!Copy` is not implemented for `NotNecessarilyCopyable`
|
||||
|
|
||||
note: required by a bound in `not_copy`
|
||||
--> $DIR/simple.rs:4:16
|
||||
|
|
||||
LL | fn not_copy<T: !Copy>() {}
|
||||
| ^^^^^ required by this bound in `not_copy`
|
||||
help: consider annotating `NotNecessarilyCopyable` with `#[derive(Copy)]`
|
||||
|
|
||||
LL + #[derive(Copy)]
|
||||
LL | struct NotNecessarilyCopyable;
|
||||
|
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
Loading…
Reference in New Issue
Block a user