diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index 7da726ef40868..0408f6ad54359 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -152,8 +152,6 @@ ast_passes_impl_trait_path = `impl Trait` is not allowed in path parameters ast_passes_incompatible_features = `{$f1}` and `{$f2}` are incompatible, using them at the same time is not allowed .help = remove one of these features -ast_passes_incompatible_trait_bound_modifiers = `{$left}` and `{$right}` are mutually exclusive - ast_passes_inherent_cannot_be = inherent impls cannot be {$annotation} .because = {$annotation} because of this .type = inherent impl for this type diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index dd0d904c52cc2..8041b89abe258 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -1435,17 +1435,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> { }; self.dcx().emit_err(errors::TildeConstDisallowed { span, reason }); } - ( - _, - BoundConstness::Always(_) | BoundConstness::Maybe(_), - BoundPolarity::Negative(_) | BoundPolarity::Maybe(_), - ) => { - self.dcx().emit_err(errors::IncompatibleTraitBoundModifiers { - span: bound.span(), - left: modifiers.constness.as_str(), - right: modifiers.polarity.as_str(), - }); - } _ => {} } diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index bfb9047645011..51f80b9ad4acb 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -657,15 +657,6 @@ pub enum TildeConstReason { Item, } -#[derive(Diagnostic)] -#[diag(ast_passes_incompatible_trait_bound_modifiers)] -pub struct IncompatibleTraitBoundModifiers { - #[primary_span] - pub span: Span, - pub left: &'static str, - pub right: &'static str, -} - #[derive(Diagnostic)] #[diag(ast_passes_const_and_async)] pub struct ConstAndAsync { diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 02c3c87313bcd..f0cdb6c63a498 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -53,6 +53,12 @@ parse_bare_cr = {$double_quotes -> parse_bare_cr_in_raw_string = bare CR not allowed in raw string +parse_binder_and_polarity = `for<...>` binder not allowed with `{$polarity}` trait polarity modifier + .label = there is not a well-defined meaning for a higher-ranked `{$polarity}` trait + +parse_binder_before_modifiers = `for<...>` binder should be placed before trait bound modifiers + .label = place the `for<...>` binder before any modifiers + parse_bounds_not_allowed_on_trait_aliases = bounds are not allowed on trait aliases parse_box_not_pat = expected pattern, found {$descr} @@ -569,6 +575,9 @@ parse_missing_trait_in_trait_impl = missing trait in a trait impl parse_modifier_lifetime = `{$modifier}` may only modify trait bounds, not lifetime bounds .suggestion = remove the `{$modifier}` +parse_modifiers_and_polarity = `{$modifiers_concatenated}` trait not allowed with `{$polarity}` trait polarity modifier + .label = there is not a well-defined meaning for a `{$modifiers_concatenated} {$polarity}` trait + parse_more_than_one_char = character literal may only contain one codepoint .followed_by = this `{$chr}` is followed by the combining {$len -> [one] mark diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 3ae9b6dad998d..75417885d2aff 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -3041,3 +3041,33 @@ pub struct UnsafeAttrOutsideUnsafeSuggestion { #[suggestion_part(code = ")")] pub right: Span, } + +#[derive(Diagnostic)] +#[diag(parse_binder_before_modifiers)] +pub struct BinderBeforeModifiers { + #[primary_span] + pub binder_span: Span, + #[label] + pub modifiers_span: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_binder_and_polarity)] +pub struct BinderAndPolarity { + #[primary_span] + pub polarity_span: Span, + #[label] + pub binder_span: Span, + pub polarity: &'static str, +} + +#[derive(Diagnostic)] +#[diag(parse_modifiers_and_polarity)] +pub struct PolarityAndModifiers { + #[primary_span] + pub polarity_span: Span, + #[label] + pub modifiers_span: Span, + pub polarity: &'static str, + pub modifiers_concatenated: String, +} diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 1e5b227aaa9be..b2a0742f21198 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -927,9 +927,14 @@ impl<'a> Parser<'a> { /// If no modifiers are present, this does not consume any tokens. /// /// ```ebnf - /// TRAIT_BOUND_MODIFIERS = [["~"] "const"] ["async"] ["?" | "!"] + /// CONSTNESS = [["~"] "const"] + /// ASYNCNESS = ["async"] + /// POLARITY = ["?" | "!"] /// ``` + /// + /// See `parse_generic_ty_bound` for the complete grammar of trait bound modifiers. fn parse_trait_bound_modifiers(&mut self) -> PResult<'a, TraitBoundModifiers> { + let modifier_lo = self.token.span; let constness = if self.eat(&token::Tilde) { let tilde = self.prev_token.span; self.expect_keyword(kw::Const)?; @@ -962,6 +967,7 @@ impl<'a> Parser<'a> { } else { BoundAsyncness::Normal }; + let modifier_hi = self.prev_token.span; let polarity = if self.eat(&token::Question) { BoundPolarity::Maybe(self.prev_token.span) @@ -972,13 +978,40 @@ impl<'a> Parser<'a> { BoundPolarity::Positive }; + // Enforce the mutual-exclusivity of `const`/`async` and `?`/`!`. + match polarity { + BoundPolarity::Positive => { + // All trait bound modifiers allowed to combine with positive polarity + } + BoundPolarity::Maybe(polarity_span) | BoundPolarity::Negative(polarity_span) => { + match (asyncness, constness) { + (BoundAsyncness::Normal, BoundConstness::Never) => { + // Ok, no modifiers. + } + (_, _) => { + let constness = constness.as_str(); + let asyncness = asyncness.as_str(); + let glue = + if !constness.is_empty() && !asyncness.is_empty() { " " } else { "" }; + let modifiers_concatenated = format!("{constness}{glue}{asyncness}"); + self.dcx().emit_err(errors::PolarityAndModifiers { + polarity_span, + polarity: polarity.as_str(), + modifiers_span: modifier_lo.to(modifier_hi), + modifiers_concatenated, + }); + } + } + } + } + Ok(TraitBoundModifiers { constness, asyncness, polarity }) } /// Parses a type bound according to: /// ```ebnf /// TY_BOUND = TY_BOUND_NOPAREN | (TY_BOUND_NOPAREN) - /// TY_BOUND_NOPAREN = [TRAIT_BOUND_MODIFIERS] [for] SIMPLE_PATH + /// TY_BOUND_NOPAREN = [for CONSTNESS ASYNCNESS | POLARITY] SIMPLE_PATH /// ``` /// /// For example, this grammar accepts `for<'a: 'b> ~const ?m::Trait<'a>`. @@ -988,9 +1021,25 @@ impl<'a> Parser<'a> { has_parens: bool, leading_token: &Token, ) -> PResult<'a, GenericBound> { - let modifiers = self.parse_trait_bound_modifiers()?; let (mut lifetime_defs, binder_span) = self.parse_late_bound_lifetime_defs()?; + let modifiers_lo = self.token.span; + let modifiers = self.parse_trait_bound_modifiers()?; + let modifiers_span = modifiers_lo.to(self.prev_token.span); + + if let Some(binder_span) = binder_span { + match modifiers.polarity { + BoundPolarity::Negative(polarity_span) | BoundPolarity::Maybe(polarity_span) => { + self.dcx().emit_err(errors::BinderAndPolarity { + binder_span, + polarity_span, + polarity: modifiers.polarity.as_str(), + }); + } + BoundPolarity::Positive => {} + } + } + // Recover erroneous lifetime bound with modifiers or binder. // e.g. `T: for<'a> 'a` or `T: ~const 'a`. if self.token.is_lifetime() { @@ -998,6 +1047,11 @@ impl<'a> Parser<'a> { return self.parse_generic_lt_bound(lo, has_parens); } + if let (more_lifetime_defs, Some(binder_span)) = self.parse_late_bound_lifetime_defs()? { + lifetime_defs.extend(more_lifetime_defs); + self.dcx().emit_err(errors::BinderBeforeModifiers { binder_span, modifiers_span }); + } + let mut path = if self.token.is_keyword(kw::Fn) && self.look_ahead(1, |tok| tok.kind == TokenKind::OpenDelim(Delimiter::Parenthesis)) && let Some(path) = self.recover_path_from_fn() diff --git a/src/tools/rustfmt/tests/source/type.rs b/src/tools/rustfmt/tests/source/type.rs index 61ef73a3cab1c..7a232f85198a8 100644 --- a/src/tools/rustfmt/tests/source/type.rs +++ b/src/tools/rustfmt/tests/source/type.rs @@ -146,8 +146,6 @@ trait T: ~ const Super {} const fn not_quite_const() -> i32 { ::CONST } -struct S(std::marker::PhantomData); - impl ~ const T {} fn apit(_: impl ~ const T) {} diff --git a/src/tools/rustfmt/tests/target/negative-bounds.rs b/src/tools/rustfmt/tests/target/negative-bounds.rs index 4fb35cccf6684..9fcb86ef4a429 100644 --- a/src/tools/rustfmt/tests/target/negative-bounds.rs +++ b/src/tools/rustfmt/tests/target/negative-bounds.rs @@ -3,9 +3,3 @@ where i32: !Copy, { } - -fn maybe_const_negative() -where - i32: ~const !Copy, -{ -} diff --git a/src/tools/rustfmt/tests/target/type.rs b/src/tools/rustfmt/tests/target/type.rs index c789ecb055a7d..325adb52f3f99 100644 --- a/src/tools/rustfmt/tests/target/type.rs +++ b/src/tools/rustfmt/tests/target/type.rs @@ -153,8 +153,6 @@ const fn not_quite_const() -> i32 { ::CONST } -struct S(std::marker::PhantomData); - impl ~const T {} fn apit(_: impl ~const T) {} diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index 5e6992038e395..0ae0356b2c452 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -16,7 +16,7 @@ use std::path::{Path, PathBuf}; const ENTRY_LIMIT: u32 = 901; // FIXME: The following limits should be reduced eventually. -const ISSUES_ENTRY_LIMIT: u32 = 1672; +const ISSUES_ENTRY_LIMIT: u32 = 1673; const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[ "rs", // test source files diff --git a/tests/ui/async-await/async-fn/higher-ranked-async-fn.rs b/tests/ui/async-await/async-fn/higher-ranked-async-fn.rs index be338ddeb7dbf..f8da517213aee 100644 --- a/tests/ui/async-await/async-fn/higher-ranked-async-fn.rs +++ b/tests/ui/async-await/async-fn/higher-ranked-async-fn.rs @@ -15,7 +15,7 @@ async fn f(arg: &i32) {} async fn func(f: F) where - F: async for<'a> Fn(&'a i32), + F: for<'a> async Fn(&'a i32), { let x: i32 = 0; f(&x).await; diff --git a/tests/ui/impl-trait/normalize-tait-in-const.rs b/tests/ui/impl-trait/normalize-tait-in-const.rs index fc90139d64095..e3f53e5f8a82a 100644 --- a/tests/ui/impl-trait/normalize-tait-in-const.rs +++ b/tests/ui/impl-trait/normalize-tait-in-const.rs @@ -24,7 +24,7 @@ mod foo { } use foo::*; -const fn with_positive Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) { +const fn with_positive ~const Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) { fun(filter_positive()); } diff --git a/tests/ui/impl-trait/normalize-tait-in-const.stderr b/tests/ui/impl-trait/normalize-tait-in-const.stderr index 73f4d4c388563..b20dabe7b25ac 100644 --- a/tests/ui/impl-trait/normalize-tait-in-const.stderr +++ b/tests/ui/impl-trait/normalize-tait-in-const.stderr @@ -1,13 +1,13 @@ error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/normalize-tait-in-const.rs:27:42 | -LL | const fn with_positive Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) { +LL | const fn with_positive ~const Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) { | ^^^^^^^^^^^^^^^^^ error: `~const` can only be applied to `#[const_trait]` traits --> $DIR/normalize-tait-in-const.rs:27:69 | -LL | const fn with_positive Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) { +LL | const fn with_positive ~const Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) { | ^^^^^^^^ error[E0015]: cannot call non-const closure in constant functions @@ -19,7 +19,7 @@ LL | fun(filter_positive()); = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants help: consider further restricting this bound | -LL | const fn with_positive Fn(&'a Alias<'a>) + ~const Destruct + ~const Fn(&foo::Alias<'_>)>(fun: F) { +LL | const fn with_positive ~const Fn(&'a Alias<'a>) + ~const Destruct + ~const Fn(&foo::Alias<'_>)>(fun: F) { | ++++++++++++++++++++++++++++ help: add `#![feature(effects)]` to the crate attributes to enable | @@ -29,7 +29,7 @@ LL + #![feature(effects)] error[E0493]: destructor of `F` cannot be evaluated at compile-time --> $DIR/normalize-tait-in-const.rs:27:79 | -LL | const fn with_positive Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) { +LL | const fn with_positive ~const Fn(&'a Alias<'a>) + ~const Destruct>(fun: F) { | ^^^ the destructor for this type cannot be evaluated in constant functions LL | fun(filter_positive()); LL | } diff --git a/tests/ui/issues/issue-39089.rs b/tests/ui/issues/issue-39089.rs index b00b842380235..822c47503afe9 100644 --- a/tests/ui/issues/issue-39089.rs +++ b/tests/ui/issues/issue-39089.rs @@ -1,5 +1,4 @@ -//@ check-pass -#![allow(dead_code)] fn f Sized>() {} +//~^ ERROR `for<...>` binder should be placed before trait bound modifiers fn main() {} diff --git a/tests/ui/issues/issue-39089.stderr b/tests/ui/issues/issue-39089.stderr new file mode 100644 index 0000000000000..a81010aedff5a --- /dev/null +++ b/tests/ui/issues/issue-39089.stderr @@ -0,0 +1,10 @@ +error: `for<...>` binder should be placed before trait bound modifiers + --> $DIR/issue-39089.rs:1:13 + | +LL | fn f Sized>() {} + | - ^^^^ + | | + | place the `for<...>` binder before any modifiers + +error: aborting due to 1 previous error + diff --git a/tests/ui/parser/bounds-type.rs b/tests/ui/parser/bounds-type.rs index a1971fa3146d1..7cee6def32f83 100644 --- a/tests/ui/parser/bounds-type.rs +++ b/tests/ui/parser/bounds-type.rs @@ -1,19 +1,30 @@ //@ compile-flags: -Z parse-only +//@ edition: 2021 struct S< T: 'a + Tr, // OK T: Tr + 'a, // OK T: 'a, // OK T:, // OK - T: ?for<'a> Trait, // OK + T: for<'a> ?Trait, //~ ERROR `for<...>` binder not allowed with `?` trait polarity modifier T: Tr +, // OK T: ?'a, //~ ERROR `?` may only modify trait bounds, not lifetime bounds T: ~const Tr, // OK - T: ~const ?Tr, // OK + T: ~const ?Tr, //~ ERROR `~const` trait not allowed with `?` trait polarity modifier T: ~const Tr + 'a, // OK T: ~const 'a, //~ ERROR `~const` may only modify trait bounds, not lifetime bounds T: const 'a, //~ ERROR `const` may only modify trait bounds, not lifetime bounds + + T: async Tr, // OK + T: async ?Tr, //~ ERROR `async` trait not allowed with `?` trait polarity modifier + T: async Tr + 'a, // OK + T: async 'a, //~ ERROR `async` may only modify trait bounds, not lifetime bounds + + T: const async Tr, // OK + T: const async ?Tr, //~ ERROR `const async` trait not allowed with `?` trait polarity modifier + T: const async Tr + 'a, // OK + T: const async 'a, //~ ERROR `const` may only modify trait bounds, not lifetime bounds >; fn main() {} diff --git a/tests/ui/parser/bounds-type.stderr b/tests/ui/parser/bounds-type.stderr index d1210e88d6678..09c35c12b000a 100644 --- a/tests/ui/parser/bounds-type.stderr +++ b/tests/ui/parser/bounds-type.stderr @@ -1,20 +1,64 @@ +error: `for<...>` binder not allowed with `?` trait polarity modifier + --> $DIR/bounds-type.rs:9:16 + | +LL | T: for<'a> ?Trait, + | ---- ^ + | | + | there is not a well-defined meaning for a higher-ranked `?` trait + error: `?` may only modify trait bounds, not lifetime bounds - --> $DIR/bounds-type.rs:10:8 + --> $DIR/bounds-type.rs:11:8 | LL | T: ?'a, | ^ +error: `~const` trait not allowed with `?` trait polarity modifier + --> $DIR/bounds-type.rs:14:15 + | +LL | T: ~const ?Tr, + | ------ ^ + | | + | there is not a well-defined meaning for a `~const ?` trait + error: `~const` may only modify trait bounds, not lifetime bounds - --> $DIR/bounds-type.rs:15:8 + --> $DIR/bounds-type.rs:16:8 | LL | T: ~const 'a, | ^^^^^^ error: `const` may only modify trait bounds, not lifetime bounds - --> $DIR/bounds-type.rs:16:8 + --> $DIR/bounds-type.rs:17:8 | LL | T: const 'a, | ^^^^^ -error: aborting due to 3 previous errors +error: `async` trait not allowed with `?` trait polarity modifier + --> $DIR/bounds-type.rs:20:14 + | +LL | T: async ?Tr, + | ----- ^ + | | + | there is not a well-defined meaning for a `async ?` trait + +error: `async` may only modify trait bounds, not lifetime bounds + --> $DIR/bounds-type.rs:22:8 + | +LL | T: async 'a, + | ^^^^^ + +error: `const async` trait not allowed with `?` trait polarity modifier + --> $DIR/bounds-type.rs:25:20 + | +LL | T: const async ?Tr, + | ----------- ^ + | | + | there is not a well-defined meaning for a `const async ?` trait + +error: `const` may only modify trait bounds, not lifetime bounds + --> $DIR/bounds-type.rs:27:8 + | +LL | T: const async 'a, + | ^^^^^ + +error: aborting due to 9 previous errors diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/mutually-exclusive-trait-bound-modifiers.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/mutually-exclusive-trait-bound-modifiers.rs index 37e285f2c6590..aaab8e819a39c 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/mutually-exclusive-trait-bound-modifiers.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/mutually-exclusive-trait-bound-modifiers.rs @@ -1,17 +1,17 @@ #![feature(const_trait_impl)] const fn maybe_const_maybe() {} -//~^ ERROR `~const` and `?` are mutually exclusive +//~^ ERROR `~const` trait not allowed with `?` trait polarity modifier fn const_maybe() {} -//~^ ERROR `const` and `?` are mutually exclusive +//~^ ERROR `const` trait not allowed with `?` trait polarity modifier const fn maybe_const_negative() {} -//~^ ERROR `~const` and `!` are mutually exclusive +//~^ ERROR `~const` trait not allowed with `!` trait polarity modifier //~| ERROR negative bounds are not supported fn const_negative() {} -//~^ ERROR `const` and `!` are mutually exclusive +//~^ ERROR `const` trait not allowed with `!` trait polarity modifier //~| ERROR negative bounds are not supported #[const_trait] diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/mutually-exclusive-trait-bound-modifiers.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/mutually-exclusive-trait-bound-modifiers.stderr index 1938f740170b5..18e4d160f5f46 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/mutually-exclusive-trait-bound-modifiers.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/mutually-exclusive-trait-bound-modifiers.stderr @@ -1,26 +1,34 @@ -error: `~const` and `?` are mutually exclusive - --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:3:31 +error: `~const` trait not allowed with `?` trait polarity modifier + --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:3:38 | LL | const fn maybe_const_maybe() {} - | ^^^^^^^^^^^^^ + | ------ ^ + | | + | there is not a well-defined meaning for a `~const ?` trait -error: `const` and `?` are mutually exclusive - --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:6:19 +error: `const` trait not allowed with `?` trait polarity modifier + --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:6:25 | LL | fn const_maybe() {} - | ^^^^^^^^^^^^ + | ----- ^ + | | + | there is not a well-defined meaning for a `const ?` trait -error: `~const` and `!` are mutually exclusive - --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:9:34 +error: `~const` trait not allowed with `!` trait polarity modifier + --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:9:41 | LL | const fn maybe_const_negative() {} - | ^^^^^^^^^^^^^ + | ------ ^ + | | + | there is not a well-defined meaning for a `~const !` trait -error: `const` and `!` are mutually exclusive - --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:13:22 +error: `const` trait not allowed with `!` trait polarity modifier + --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:13:28 | LL | fn const_negative() {} - | ^^^^^^^^^^^^ + | ----- ^ + | | + | there is not a well-defined meaning for a `const !` trait error: negative bounds are not supported --> $DIR/mutually-exclusive-trait-bound-modifiers.rs:9:41 diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-syntax.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-syntax.rs index 496f97b5e24aa..d65ecae3d067c 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-syntax.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-syntax.rs @@ -4,6 +4,6 @@ #![feature(const_trait_impl)] struct S< - T: ~const ?for<'a> Tr<'a> + 'static + ~const std::ops::Add, - T: ~const ?for<'a: 'b> m::Trait<'a>, + T: for<'a> ~const Tr<'a> + 'static + ~const std::ops::Add, + T: for<'a: 'b> ~const m::Trait<'a>, >;