Rollup merge of #151783 - mu001999-contrib:impl/final-method, r=fee1-dead
Implement RFC 3678: Final trait methods Tracking: https://github.com/rust-lang/rust/issues/131179 This PR is based on rust-lang/rust#130802, with some minor changes and conflict resolution. Futhermore, this PR excludes final methods from the vtable of a dyn Trait. And some excerpt from the original PR description: > Implements the surface part of https://github.com/rust-lang/rfcs/pull/3678. > > I'm using the word "method" in the title, but in the diagnostics and the feature gate I used "associated function", since that's more accurate. cc @joshtriplett
This commit is contained in:
commit
1367126837
57 changed files with 755 additions and 117 deletions
|
|
@ -3131,8 +3131,16 @@ pub enum Const {
|
||||||
/// For details see the [RFC #2532](https://github.com/rust-lang/rfcs/pull/2532).
|
/// For details see the [RFC #2532](https://github.com/rust-lang/rfcs/pull/2532).
|
||||||
#[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic, Walkable)]
|
#[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic, Walkable)]
|
||||||
pub enum Defaultness {
|
pub enum Defaultness {
|
||||||
|
/// Item is unmarked. Implicitly determined based off of position.
|
||||||
|
/// For impls, this is `final`; for traits, this is `default`.
|
||||||
|
///
|
||||||
|
/// If you're expanding an item in a built-in macro or parsing an item
|
||||||
|
/// by hand, you probably want to use this.
|
||||||
|
Implicit,
|
||||||
|
/// `default`
|
||||||
Default(Span),
|
Default(Span),
|
||||||
Final,
|
/// `final`; per RFC 3678, only trait items may be *explicitly* marked final.
|
||||||
|
Final(Span),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Encodable, Decodable, HashStable_Generic, Walkable)]
|
#[derive(Copy, Clone, PartialEq, Encodable, Decodable, HashStable_Generic, Walkable)]
|
||||||
|
|
@ -4140,7 +4148,7 @@ impl AssocItemKind {
|
||||||
| Self::Fn(box Fn { defaultness, .. })
|
| Self::Fn(box Fn { defaultness, .. })
|
||||||
| Self::Type(box TyAlias { defaultness, .. }) => defaultness,
|
| Self::Type(box TyAlias { defaultness, .. }) => defaultness,
|
||||||
Self::MacCall(..) | Self::Delegation(..) | Self::DelegationMac(..) => {
|
Self::MacCall(..) | Self::Delegation(..) | Self::DelegationMac(..) => {
|
||||||
Defaultness::Final
|
Defaultness::Implicit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -939,7 +939,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
);
|
);
|
||||||
let trait_item_def_id = hir_id.expect_owner();
|
let trait_item_def_id = hir_id.expect_owner();
|
||||||
|
|
||||||
let (ident, generics, kind, has_default) = match &i.kind {
|
let (ident, generics, kind, has_value) = match &i.kind {
|
||||||
AssocItemKind::Const(box ConstItem {
|
AssocItemKind::Const(box ConstItem {
|
||||||
ident,
|
ident,
|
||||||
generics,
|
generics,
|
||||||
|
|
@ -1088,13 +1088,17 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value, || {
|
||||||
|
hir::Defaultness::Default { has_value }
|
||||||
|
});
|
||||||
|
|
||||||
let item = hir::TraitItem {
|
let item = hir::TraitItem {
|
||||||
owner_id: trait_item_def_id,
|
owner_id: trait_item_def_id,
|
||||||
ident: self.lower_ident(ident),
|
ident: self.lower_ident(ident),
|
||||||
generics,
|
generics,
|
||||||
kind,
|
kind,
|
||||||
span: self.lower_span(i.span),
|
span: self.lower_span(i.span),
|
||||||
defaultness: hir::Defaultness::Default { has_value: has_default },
|
defaultness,
|
||||||
has_delayed_lints: !self.delayed_lints.is_empty(),
|
has_delayed_lints: !self.delayed_lints.is_empty(),
|
||||||
};
|
};
|
||||||
self.arena.alloc(item)
|
self.arena.alloc(item)
|
||||||
|
|
@ -1122,7 +1126,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
// `defaultness.has_value()` is never called for an `impl`, always `true` in order
|
// `defaultness.has_value()` is never called for an `impl`, always `true` in order
|
||||||
// to not cause an assertion failure inside the `lower_defaultness` function.
|
// to not cause an assertion failure inside the `lower_defaultness` function.
|
||||||
let has_val = true;
|
let has_val = true;
|
||||||
let (defaultness, defaultness_span) = self.lower_defaultness(defaultness, has_val);
|
let (defaultness, defaultness_span) =
|
||||||
|
self.lower_defaultness(defaultness, has_val, || hir::Defaultness::Final);
|
||||||
let modifiers = TraitBoundModifiers {
|
let modifiers = TraitBoundModifiers {
|
||||||
constness: BoundConstness::Never,
|
constness: BoundConstness::Never,
|
||||||
asyncness: BoundAsyncness::Normal,
|
asyncness: BoundAsyncness::Normal,
|
||||||
|
|
@ -1151,7 +1156,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
) -> &'hir hir::ImplItem<'hir> {
|
) -> &'hir hir::ImplItem<'hir> {
|
||||||
// Since `default impl` is not yet implemented, this is always true in impls.
|
// Since `default impl` is not yet implemented, this is always true in impls.
|
||||||
let has_value = true;
|
let has_value = true;
|
||||||
let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value);
|
let (defaultness, _) =
|
||||||
|
self.lower_defaultness(i.kind.defaultness(), has_value, || hir::Defaultness::Final);
|
||||||
let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id);
|
let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id);
|
||||||
let attrs = self.lower_attrs(
|
let attrs = self.lower_attrs(
|
||||||
hir_id,
|
hir_id,
|
||||||
|
|
@ -1304,15 +1310,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
&self,
|
&self,
|
||||||
d: Defaultness,
|
d: Defaultness,
|
||||||
has_value: bool,
|
has_value: bool,
|
||||||
|
implicit: impl FnOnce() -> hir::Defaultness,
|
||||||
) -> (hir::Defaultness, Option<Span>) {
|
) -> (hir::Defaultness, Option<Span>) {
|
||||||
match d {
|
match d {
|
||||||
|
Defaultness::Implicit => (implicit(), None),
|
||||||
Defaultness::Default(sp) => {
|
Defaultness::Default(sp) => {
|
||||||
(hir::Defaultness::Default { has_value }, Some(self.lower_span(sp)))
|
(hir::Defaultness::Default { has_value }, Some(self.lower_span(sp)))
|
||||||
}
|
}
|
||||||
Defaultness::Final => {
|
Defaultness::Final(sp) => (hir::Defaultness::Final, Some(self.lower_span(sp))),
|
||||||
assert!(has_value);
|
|
||||||
(hir::Defaultness::Final, None)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,28 @@ impl TraitOrImpl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum AllowDefault {
|
||||||
|
Yes,
|
||||||
|
No,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AllowDefault {
|
||||||
|
fn when(b: bool) -> Self {
|
||||||
|
if b { Self::Yes } else { Self::No }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum AllowFinal {
|
||||||
|
Yes,
|
||||||
|
No,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AllowFinal {
|
||||||
|
fn when(b: bool) -> Self {
|
||||||
|
if b { Self::Yes } else { Self::No }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct AstValidator<'a> {
|
struct AstValidator<'a> {
|
||||||
sess: &'a Session,
|
sess: &'a Session,
|
||||||
features: &'a Features,
|
features: &'a Features,
|
||||||
|
|
@ -563,10 +585,32 @@ impl<'a> AstValidator<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_defaultness(&self, span: Span, defaultness: Defaultness) {
|
fn check_defaultness(
|
||||||
if let Defaultness::Default(def_span) = defaultness {
|
&self,
|
||||||
let span = self.sess.source_map().guess_head_span(span);
|
span: Span,
|
||||||
self.dcx().emit_err(errors::ForbiddenDefault { span, def_span });
|
defaultness: Defaultness,
|
||||||
|
allow_default: AllowDefault,
|
||||||
|
allow_final: AllowFinal,
|
||||||
|
) {
|
||||||
|
match defaultness {
|
||||||
|
Defaultness::Default(def_span) if matches!(allow_default, AllowDefault::No) => {
|
||||||
|
let span = self.sess.source_map().guess_head_span(span);
|
||||||
|
self.dcx().emit_err(errors::ForbiddenDefault { span, def_span });
|
||||||
|
}
|
||||||
|
Defaultness::Final(def_span) if matches!(allow_final, AllowFinal::No) => {
|
||||||
|
let span = self.sess.source_map().guess_head_span(span);
|
||||||
|
self.dcx().emit_err(errors::ForbiddenFinal { span, def_span });
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_final_has_body(&self, item: &Item<AssocItemKind>, defaultness: Defaultness) {
|
||||||
|
if let AssocItemKind::Fn(box Fn { body: None, .. }) = &item.kind
|
||||||
|
&& let Defaultness::Final(def_span) = defaultness
|
||||||
|
{
|
||||||
|
let span = self.sess.source_map().guess_head_span(item.span);
|
||||||
|
self.dcx().emit_err(errors::ForbiddenFinalWithoutBody { span, def_span });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1190,7 +1234,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||||
},
|
},
|
||||||
) => {
|
) => {
|
||||||
self.visit_attrs_vis_ident(&item.attrs, &item.vis, ident);
|
self.visit_attrs_vis_ident(&item.attrs, &item.vis, ident);
|
||||||
self.check_defaultness(item.span, *defaultness);
|
self.check_defaultness(item.span, *defaultness, AllowDefault::No, AllowFinal::No);
|
||||||
|
|
||||||
for EiiImpl { eii_macro_path, .. } in eii_impls {
|
for EiiImpl { eii_macro_path, .. } in eii_impls {
|
||||||
self.visit_path(eii_macro_path);
|
self.visit_path(eii_macro_path);
|
||||||
|
|
@ -1360,7 +1404,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
ItemKind::Const(box ConstItem { defaultness, ident, rhs_kind, .. }) => {
|
ItemKind::Const(box ConstItem { defaultness, ident, rhs_kind, .. }) => {
|
||||||
self.check_defaultness(item.span, *defaultness);
|
self.check_defaultness(item.span, *defaultness, AllowDefault::No, AllowFinal::No);
|
||||||
if !rhs_kind.has_expr() {
|
if !rhs_kind.has_expr() {
|
||||||
self.dcx().emit_err(errors::ConstWithoutBody {
|
self.dcx().emit_err(errors::ConstWithoutBody {
|
||||||
span: item.span,
|
span: item.span,
|
||||||
|
|
@ -1398,7 +1442,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||||
ItemKind::TyAlias(
|
ItemKind::TyAlias(
|
||||||
ty_alias @ box TyAlias { defaultness, bounds, after_where_clause, ty, .. },
|
ty_alias @ box TyAlias { defaultness, bounds, after_where_clause, ty, .. },
|
||||||
) => {
|
) => {
|
||||||
self.check_defaultness(item.span, *defaultness);
|
self.check_defaultness(item.span, *defaultness, AllowDefault::No, AllowFinal::No);
|
||||||
if ty.is_none() {
|
if ty.is_none() {
|
||||||
self.dcx().emit_err(errors::TyAliasWithoutBody {
|
self.dcx().emit_err(errors::TyAliasWithoutBody {
|
||||||
span: item.span,
|
span: item.span,
|
||||||
|
|
@ -1428,7 +1472,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||||
fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
|
fn visit_foreign_item(&mut self, fi: &'a ForeignItem) {
|
||||||
match &fi.kind {
|
match &fi.kind {
|
||||||
ForeignItemKind::Fn(box Fn { defaultness, ident, sig, body, .. }) => {
|
ForeignItemKind::Fn(box Fn { defaultness, ident, sig, body, .. }) => {
|
||||||
self.check_defaultness(fi.span, *defaultness);
|
self.check_defaultness(fi.span, *defaultness, AllowDefault::No, AllowFinal::No);
|
||||||
self.check_foreign_fn_bodyless(*ident, body.as_deref());
|
self.check_foreign_fn_bodyless(*ident, body.as_deref());
|
||||||
self.check_foreign_fn_headerless(sig.header);
|
self.check_foreign_fn_headerless(sig.header);
|
||||||
self.check_foreign_item_ascii_only(*ident);
|
self.check_foreign_item_ascii_only(*ident);
|
||||||
|
|
@ -1448,7 +1492,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||||
ty,
|
ty,
|
||||||
..
|
..
|
||||||
}) => {
|
}) => {
|
||||||
self.check_defaultness(fi.span, *defaultness);
|
self.check_defaultness(fi.span, *defaultness, AllowDefault::No, AllowFinal::No);
|
||||||
self.check_foreign_kind_bodyless(*ident, "type", ty.as_ref().map(|b| b.span));
|
self.check_foreign_kind_bodyless(*ident, "type", ty.as_ref().map(|b| b.span));
|
||||||
self.check_type_no_bounds(bounds, "`extern` blocks");
|
self.check_type_no_bounds(bounds, "`extern` blocks");
|
||||||
self.check_foreign_ty_genericless(generics, after_where_clause);
|
self.check_foreign_ty_genericless(generics, after_where_clause);
|
||||||
|
|
@ -1707,9 +1751,19 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||||
self.check_nomangle_item_asciionly(ident, item.span);
|
self.check_nomangle_item_asciionly(ident, item.span);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ctxt == AssocCtxt::Trait || self.outer_trait_or_trait_impl.is_none() {
|
let defaultness = item.kind.defaultness();
|
||||||
self.check_defaultness(item.span, item.kind.defaultness());
|
self.check_defaultness(
|
||||||
}
|
item.span,
|
||||||
|
defaultness,
|
||||||
|
// `default` is allowed on all associated items in impls.
|
||||||
|
AllowDefault::when(matches!(ctxt, AssocCtxt::Impl { .. })),
|
||||||
|
// `final` is allowed on all associated *functions* in traits.
|
||||||
|
AllowFinal::when(
|
||||||
|
ctxt == AssocCtxt::Trait && matches!(item.kind, AssocItemKind::Fn(..)),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
self.check_final_has_body(item, defaultness);
|
||||||
|
|
||||||
if let AssocCtxt::Impl { .. } = ctxt {
|
if let AssocCtxt::Impl { .. } = ctxt {
|
||||||
match &item.kind {
|
match &item.kind {
|
||||||
|
|
|
||||||
|
|
@ -159,6 +159,24 @@ pub(crate) struct ForbiddenDefault {
|
||||||
pub def_span: Span,
|
pub def_span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag("`final` is only allowed on associated functions in traits")]
|
||||||
|
pub(crate) struct ForbiddenFinal {
|
||||||
|
#[primary_span]
|
||||||
|
pub span: Span,
|
||||||
|
#[label("`final` because of this")]
|
||||||
|
pub def_span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag("`final` is only allowed on associated functions if they have a body")]
|
||||||
|
pub(crate) struct ForbiddenFinalWithoutBody {
|
||||||
|
#[primary_span]
|
||||||
|
pub span: Span,
|
||||||
|
#[label("`final` because of this")]
|
||||||
|
pub def_span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("associated constant in `impl` without body")]
|
#[diag("associated constant in `impl` without body")]
|
||||||
pub(crate) struct AssocConstWithoutBody {
|
pub(crate) struct AssocConstWithoutBody {
|
||||||
|
|
|
||||||
|
|
@ -580,6 +580,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
|
||||||
gate_all!(frontmatter, "frontmatters are experimental");
|
gate_all!(frontmatter, "frontmatters are experimental");
|
||||||
gate_all!(coroutines, "coroutine syntax is experimental");
|
gate_all!(coroutines, "coroutine syntax is experimental");
|
||||||
gate_all!(const_block_items, "const block items are experimental");
|
gate_all!(const_block_items, "const block items are experimental");
|
||||||
|
gate_all!(final_associated_functions, "`final` on trait functions is experimental");
|
||||||
|
|
||||||
if !visitor.features.never_patterns() {
|
if !visitor.features.never_patterns() {
|
||||||
if let Some(spans) = spans.get(&sym::never_patterns) {
|
if let Some(spans) = spans.get(&sym::never_patterns) {
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ impl<'a> State<'a> {
|
||||||
expr.as_deref(),
|
expr.as_deref(),
|
||||||
vis,
|
vis,
|
||||||
*safety,
|
*safety,
|
||||||
ast::Defaultness::Final,
|
ast::Defaultness::Implicit,
|
||||||
define_opaque.as_deref(),
|
define_opaque.as_deref(),
|
||||||
),
|
),
|
||||||
ast::ForeignItemKind::TyAlias(box ast::TyAlias {
|
ast::ForeignItemKind::TyAlias(box ast::TyAlias {
|
||||||
|
|
@ -201,7 +201,7 @@ impl<'a> State<'a> {
|
||||||
body.as_deref(),
|
body.as_deref(),
|
||||||
&item.vis,
|
&item.vis,
|
||||||
ast::Safety::Default,
|
ast::Safety::Default,
|
||||||
ast::Defaultness::Final,
|
ast::Defaultness::Implicit,
|
||||||
define_opaque.as_deref(),
|
define_opaque.as_deref(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,7 @@ fn generate_handler(cx: &ExtCtxt<'_>, handler: Ident, span: Span, sig_span: Span
|
||||||
|
|
||||||
let body = Some(cx.block_expr(call));
|
let body = Some(cx.block_expr(call));
|
||||||
let kind = ItemKind::Fn(Box::new(Fn {
|
let kind = ItemKind::Fn(Box::new(Fn {
|
||||||
defaultness: ast::Defaultness::Final,
|
defaultness: ast::Defaultness::Implicit,
|
||||||
sig,
|
sig,
|
||||||
ident: Ident::from_str_and_span(&global_fn_name(ALLOC_ERROR_HANDLER), span),
|
ident: Ident::from_str_and_span(&global_fn_name(ALLOC_ERROR_HANDLER), span),
|
||||||
generics: Generics::default(),
|
generics: Generics::default(),
|
||||||
|
|
|
||||||
|
|
@ -334,7 +334,7 @@ mod llvm_enzyme {
|
||||||
|
|
||||||
// The first element of it is the name of the function to be generated
|
// The first element of it is the name of the function to be generated
|
||||||
let d_fn = Box::new(ast::Fn {
|
let d_fn = Box::new(ast::Fn {
|
||||||
defaultness: ast::Defaultness::Final,
|
defaultness: ast::Defaultness::Implicit,
|
||||||
sig: d_sig,
|
sig: d_sig,
|
||||||
ident: first_ident(&meta_item_vec[0]),
|
ident: first_ident(&meta_item_vec[0]),
|
||||||
generics,
|
generics,
|
||||||
|
|
|
||||||
|
|
@ -136,7 +136,7 @@ pub(crate) fn expand_deriving_coerce_pointee(
|
||||||
of_trait: Some(Box::new(ast::TraitImplHeader {
|
of_trait: Some(Box::new(ast::TraitImplHeader {
|
||||||
safety: ast::Safety::Default,
|
safety: ast::Safety::Default,
|
||||||
polarity: ast::ImplPolarity::Positive,
|
polarity: ast::ImplPolarity::Positive,
|
||||||
defaultness: ast::Defaultness::Final,
|
defaultness: ast::Defaultness::Implicit,
|
||||||
trait_ref,
|
trait_ref,
|
||||||
})),
|
})),
|
||||||
constness: ast::Const::No,
|
constness: ast::Const::No,
|
||||||
|
|
@ -159,7 +159,7 @@ pub(crate) fn expand_deriving_coerce_pointee(
|
||||||
of_trait: Some(Box::new(ast::TraitImplHeader {
|
of_trait: Some(Box::new(ast::TraitImplHeader {
|
||||||
safety: ast::Safety::Default,
|
safety: ast::Safety::Default,
|
||||||
polarity: ast::ImplPolarity::Positive,
|
polarity: ast::ImplPolarity::Positive,
|
||||||
defaultness: ast::Defaultness::Final,
|
defaultness: ast::Defaultness::Implicit,
|
||||||
trait_ref,
|
trait_ref,
|
||||||
})),
|
})),
|
||||||
constness: ast::Const::No,
|
constness: ast::Const::No,
|
||||||
|
|
|
||||||
|
|
@ -614,7 +614,7 @@ impl<'a> TraitDef<'a> {
|
||||||
},
|
},
|
||||||
attrs: ast::AttrVec::new(),
|
attrs: ast::AttrVec::new(),
|
||||||
kind: ast::AssocItemKind::Type(Box::new(ast::TyAlias {
|
kind: ast::AssocItemKind::Type(Box::new(ast::TyAlias {
|
||||||
defaultness: ast::Defaultness::Final,
|
defaultness: ast::Defaultness::Implicit,
|
||||||
ident,
|
ident,
|
||||||
generics: Generics::default(),
|
generics: Generics::default(),
|
||||||
after_where_clause: ast::WhereClause::default(),
|
after_where_clause: ast::WhereClause::default(),
|
||||||
|
|
@ -851,7 +851,7 @@ impl<'a> TraitDef<'a> {
|
||||||
of_trait: Some(Box::new(ast::TraitImplHeader {
|
of_trait: Some(Box::new(ast::TraitImplHeader {
|
||||||
safety: self.safety,
|
safety: self.safety,
|
||||||
polarity: ast::ImplPolarity::Positive,
|
polarity: ast::ImplPolarity::Positive,
|
||||||
defaultness: ast::Defaultness::Final,
|
defaultness: ast::Defaultness::Implicit,
|
||||||
trait_ref,
|
trait_ref,
|
||||||
})),
|
})),
|
||||||
constness: if self.is_const { ast::Const::Yes(DUMMY_SP) } else { ast::Const::No },
|
constness: if self.is_const { ast::Const::Yes(DUMMY_SP) } else { ast::Const::No },
|
||||||
|
|
@ -1073,7 +1073,7 @@ impl<'a> MethodDef<'a> {
|
||||||
let trait_lo_sp = span.shrink_to_lo();
|
let trait_lo_sp = span.shrink_to_lo();
|
||||||
|
|
||||||
let sig = ast::FnSig { header: ast::FnHeader::default(), decl: fn_decl, span };
|
let sig = ast::FnSig { header: ast::FnHeader::default(), decl: fn_decl, span };
|
||||||
let defaultness = ast::Defaultness::Final;
|
let defaultness = ast::Defaultness::Implicit;
|
||||||
|
|
||||||
// Create the method.
|
// Create the method.
|
||||||
Box::new(ast::AssocItem {
|
Box::new(ast::AssocItem {
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,7 @@ impl AllocFnFactory<'_, '_> {
|
||||||
let sig = FnSig { decl, header, span: self.span };
|
let sig = FnSig { decl, header, span: self.span };
|
||||||
let body = Some(self.cx.block_expr(result));
|
let body = Some(self.cx.block_expr(result));
|
||||||
let kind = ItemKind::Fn(Box::new(Fn {
|
let kind = ItemKind::Fn(Box::new(Fn {
|
||||||
defaultness: ast::Defaultness::Final,
|
defaultness: ast::Defaultness::Implicit,
|
||||||
sig,
|
sig,
|
||||||
ident: Ident::from_str_and_span(&global_fn_name(method.name), self.span),
|
ident: Ident::from_str_and_span(&global_fn_name(method.name), self.span),
|
||||||
generics: Generics::default(),
|
generics: Generics::default(),
|
||||||
|
|
|
||||||
|
|
@ -283,7 +283,7 @@ pub(crate) fn expand_test_or_bench(
|
||||||
// const $ident: test::TestDescAndFn =
|
// const $ident: test::TestDescAndFn =
|
||||||
ast::ItemKind::Const(
|
ast::ItemKind::Const(
|
||||||
ast::ConstItem {
|
ast::ConstItem {
|
||||||
defaultness: ast::Defaultness::Final,
|
defaultness: ast::Defaultness::Implicit,
|
||||||
ident: Ident::new(fn_.ident.name, sp),
|
ident: Ident::new(fn_.ident.name, sp),
|
||||||
generics: ast::Generics::default(),
|
generics: ast::Generics::default(),
|
||||||
ty: cx.ty(sp, ast::TyKind::Path(None, test_path("TestDescAndFn"))),
|
ty: cx.ty(sp, ast::TyKind::Path(None, test_path("TestDescAndFn"))),
|
||||||
|
|
|
||||||
|
|
@ -330,7 +330,7 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> Box<ast::Item> {
|
||||||
|
|
||||||
let decl = ecx.fn_decl(ThinVec::new(), ast::FnRetTy::Ty(main_ret_ty));
|
let decl = ecx.fn_decl(ThinVec::new(), ast::FnRetTy::Ty(main_ret_ty));
|
||||||
let sig = ast::FnSig { decl, header: ast::FnHeader::default(), span: sp };
|
let sig = ast::FnSig { decl, header: ast::FnHeader::default(), span: sp };
|
||||||
let defaultness = ast::Defaultness::Final;
|
let defaultness = ast::Defaultness::Implicit;
|
||||||
|
|
||||||
// Honor the reexport_test_harness_main attribute
|
// Honor the reexport_test_harness_main attribute
|
||||||
let main_ident = match cx.reexport_test_harness_main {
|
let main_ident = match cx.reexport_test_harness_main {
|
||||||
|
|
|
||||||
|
|
@ -729,7 +729,7 @@ impl<'a> ExtCtxt<'a> {
|
||||||
ty: Box<ast::Ty>,
|
ty: Box<ast::Ty>,
|
||||||
rhs_kind: ast::ConstItemRhsKind,
|
rhs_kind: ast::ConstItemRhsKind,
|
||||||
) -> Box<ast::Item> {
|
) -> Box<ast::Item> {
|
||||||
let defaultness = ast::Defaultness::Final;
|
let defaultness = ast::Defaultness::Implicit;
|
||||||
self.item(
|
self.item(
|
||||||
span,
|
span,
|
||||||
AttrVec::new(),
|
AttrVec::new(),
|
||||||
|
|
|
||||||
|
|
@ -494,6 +494,8 @@ declare_features! (
|
||||||
(unstable, ffi_const, "1.45.0", Some(58328)),
|
(unstable, ffi_const, "1.45.0", Some(58328)),
|
||||||
/// Allows the use of `#[ffi_pure]` on foreign functions.
|
/// Allows the use of `#[ffi_pure]` on foreign functions.
|
||||||
(unstable, ffi_pure, "1.45.0", Some(58329)),
|
(unstable, ffi_pure, "1.45.0", Some(58329)),
|
||||||
|
/// Allows marking trait functions as `final` to prevent overriding impls
|
||||||
|
(unstable, final_associated_functions, "CURRENT_RUSTC_VERSION", Some(1)),
|
||||||
/// Controlling the behavior of fmt::Debug
|
/// Controlling the behavior of fmt::Debug
|
||||||
(unstable, fmt_debug, "1.82.0", Some(129709)),
|
(unstable, fmt_debug, "1.82.0", Some(129709)),
|
||||||
/// Allows using `#[align(...)]` on function items
|
/// Allows using `#[align(...)]` on function items
|
||||||
|
|
|
||||||
|
|
@ -1175,13 +1175,35 @@ pub(super) fn check_specialization_validity<'tcx>(
|
||||||
|
|
||||||
if let Err(parent_impl) = result {
|
if let Err(parent_impl) = result {
|
||||||
if !tcx.is_impl_trait_in_trait(impl_item) {
|
if !tcx.is_impl_trait_in_trait(impl_item) {
|
||||||
report_forbidden_specialization(tcx, impl_item, parent_impl);
|
let span = tcx.def_span(impl_item);
|
||||||
|
let ident = tcx.item_ident(impl_item);
|
||||||
|
|
||||||
|
let err = match tcx.span_of_impl(parent_impl) {
|
||||||
|
Ok(sp) => errors::ImplNotMarkedDefault::Ok { span, ident, ok_label: sp },
|
||||||
|
Err(cname) => errors::ImplNotMarkedDefault::Err { span, ident, cname },
|
||||||
|
};
|
||||||
|
|
||||||
|
tcx.dcx().emit_err(err);
|
||||||
} else {
|
} else {
|
||||||
tcx.dcx().delayed_bug(format!("parent item: {parent_impl:?} not marked as default"));
|
tcx.dcx().delayed_bug(format!("parent item: {parent_impl:?} not marked as default"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn check_overriding_final_trait_item<'tcx>(
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
trait_item: ty::AssocItem,
|
||||||
|
impl_item: ty::AssocItem,
|
||||||
|
) {
|
||||||
|
if trait_item.defaultness(tcx).is_final() {
|
||||||
|
tcx.dcx().emit_err(errors::OverridingFinalTraitFunction {
|
||||||
|
impl_span: tcx.def_span(impl_item.def_id),
|
||||||
|
trait_span: tcx.def_span(trait_item.def_id),
|
||||||
|
ident: tcx.item_ident(impl_item.def_id),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn check_impl_items_against_trait<'tcx>(
|
fn check_impl_items_against_trait<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
impl_id: LocalDefId,
|
impl_id: LocalDefId,
|
||||||
|
|
@ -1259,6 +1281,8 @@ fn check_impl_items_against_trait<'tcx>(
|
||||||
impl_id.to_def_id(),
|
impl_id.to_def_id(),
|
||||||
impl_item,
|
impl_item,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
check_overriding_final_trait_item(tcx, ty_trait_item, ty_impl_item);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Ok(ancestors) = trait_def.ancestors(tcx, impl_id.to_def_id()) {
|
if let Ok(ancestors) = trait_def.ancestors(tcx, impl_id.to_def_id()) {
|
||||||
|
|
|
||||||
|
|
@ -197,18 +197,6 @@ pub(super) fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDef
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn report_forbidden_specialization(tcx: TyCtxt<'_>, impl_item: DefId, parent_impl: DefId) {
|
|
||||||
let span = tcx.def_span(impl_item);
|
|
||||||
let ident = tcx.item_ident(impl_item);
|
|
||||||
|
|
||||||
let err = match tcx.span_of_impl(parent_impl) {
|
|
||||||
Ok(sp) => errors::ImplNotMarkedDefault::Ok { span, ident, ok_label: sp },
|
|
||||||
Err(cname) => errors::ImplNotMarkedDefault::Err { span, ident, cname },
|
|
||||||
};
|
|
||||||
|
|
||||||
tcx.dcx().emit_err(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn missing_items_err(
|
fn missing_items_err(
|
||||||
tcx: TyCtxt<'_>,
|
tcx: TyCtxt<'_>,
|
||||||
impl_def_id: LocalDefId,
|
impl_def_id: LocalDefId,
|
||||||
|
|
|
||||||
|
|
@ -892,6 +892,16 @@ pub(crate) enum ImplNotMarkedDefault {
|
||||||
#[diag("this item cannot be used as its where bounds are not satisfied for the `Self` type")]
|
#[diag("this item cannot be used as its where bounds are not satisfied for the `Self` type")]
|
||||||
pub(crate) struct UselessImplItem;
|
pub(crate) struct UselessImplItem;
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag("cannot override `{$ident}` because it already has a `final` definition in the trait")]
|
||||||
|
pub(crate) struct OverridingFinalTraitFunction {
|
||||||
|
#[primary_span]
|
||||||
|
pub impl_span: Span,
|
||||||
|
#[note("`{$ident}` is marked final here")]
|
||||||
|
pub trait_span: Span,
|
||||||
|
pub ident: Ident,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("not all trait items implemented, missing: `{$missing_items_msg}`", code = E0046)]
|
#[diag("not all trait items implemented, missing: `{$missing_items_msg}`", code = E0046)]
|
||||||
pub(crate) struct MissingTraitItem {
|
pub(crate) struct MissingTraitItem {
|
||||||
|
|
|
||||||
|
|
@ -3787,6 +3787,17 @@ pub(crate) struct RecoverImportAsUse {
|
||||||
pub token_name: String,
|
pub token_name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag("{$article} {$descr} cannot be `final`")]
|
||||||
|
#[note("only associated functions in traits can be `final`")]
|
||||||
|
pub(crate) struct InappropriateFinal {
|
||||||
|
#[primary_span]
|
||||||
|
#[label("`final` because of this")]
|
||||||
|
pub span: Span,
|
||||||
|
pub article: &'static str,
|
||||||
|
pub descr: &'static str,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag("expected `::`, found `:`")]
|
#[diag("expected `::`, found `:`")]
|
||||||
#[note("import paths are delimited using `::`")]
|
#[note("import paths are delimited using `::`")]
|
||||||
|
|
|
||||||
|
|
@ -206,14 +206,24 @@ impl<'a> Parser<'a> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Error in-case `default` was parsed in an in-appropriate context.
|
/// Error in-case `default`/`final` was parsed in an in-appropriate context.
|
||||||
fn error_on_unconsumed_default(&self, def: Defaultness, kind: &ItemKind) {
|
fn error_on_unconsumed_default(&self, def: Defaultness, kind: &ItemKind) {
|
||||||
if let Defaultness::Default(span) = def {
|
match def {
|
||||||
self.dcx().emit_err(errors::InappropriateDefault {
|
Defaultness::Default(span) => {
|
||||||
span,
|
self.dcx().emit_err(errors::InappropriateDefault {
|
||||||
article: kind.article(),
|
span,
|
||||||
descr: kind.descr(),
|
article: kind.article(),
|
||||||
});
|
descr: kind.descr(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Defaultness::Final(span) => {
|
||||||
|
self.dcx().emit_err(errors::InappropriateFinal {
|
||||||
|
span,
|
||||||
|
article: kind.article(),
|
||||||
|
descr: kind.descr(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Defaultness::Implicit => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -229,8 +239,8 @@ impl<'a> Parser<'a> {
|
||||||
fn_parse_mode: FnParseMode,
|
fn_parse_mode: FnParseMode,
|
||||||
case: Case,
|
case: Case,
|
||||||
) -> PResult<'a, Option<ItemKind>> {
|
) -> PResult<'a, Option<ItemKind>> {
|
||||||
let check_pub = def == &Defaultness::Final;
|
let check_pub = def == &Defaultness::Implicit;
|
||||||
let mut def_ = || mem::replace(def, Defaultness::Final);
|
let mut def_ = || mem::replace(def, Defaultness::Implicit);
|
||||||
|
|
||||||
let info = if !self.is_use_closure() && self.eat_keyword_case(exp!(Use), case) {
|
let info = if !self.is_use_closure() && self.eat_keyword_case(exp!(Use), case) {
|
||||||
self.parse_use_item()?
|
self.parse_use_item()?
|
||||||
|
|
@ -1005,8 +1015,11 @@ impl<'a> Parser<'a> {
|
||||||
{
|
{
|
||||||
self.bump(); // `default`
|
self.bump(); // `default`
|
||||||
Defaultness::Default(self.prev_token_uninterpolated_span())
|
Defaultness::Default(self.prev_token_uninterpolated_span())
|
||||||
|
} else if self.eat_keyword(exp!(Final)) {
|
||||||
|
self.psess.gated_spans.gate(sym::final_associated_functions, self.prev_token.span);
|
||||||
|
Defaultness::Final(self.prev_token_uninterpolated_span())
|
||||||
} else {
|
} else {
|
||||||
Defaultness::Final
|
Defaultness::Implicit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1130,7 +1143,7 @@ impl<'a> Parser<'a> {
|
||||||
}) => {
|
}) => {
|
||||||
self.dcx().emit_err(errors::AssociatedStaticItemNotAllowed { span });
|
self.dcx().emit_err(errors::AssociatedStaticItemNotAllowed { span });
|
||||||
AssocItemKind::Const(Box::new(ConstItem {
|
AssocItemKind::Const(Box::new(ConstItem {
|
||||||
defaultness: Defaultness::Final,
|
defaultness: Defaultness::Implicit,
|
||||||
ident,
|
ident,
|
||||||
generics: Generics::default(),
|
generics: Generics::default(),
|
||||||
ty,
|
ty,
|
||||||
|
|
|
||||||
|
|
@ -91,6 +91,7 @@ pub enum TokenType {
|
||||||
KwElse,
|
KwElse,
|
||||||
KwEnum,
|
KwEnum,
|
||||||
KwExtern,
|
KwExtern,
|
||||||
|
KwFinal,
|
||||||
KwFn,
|
KwFn,
|
||||||
KwFor,
|
KwFor,
|
||||||
KwGen,
|
KwGen,
|
||||||
|
|
@ -233,6 +234,7 @@ impl TokenType {
|
||||||
KwExtern,
|
KwExtern,
|
||||||
KwFn,
|
KwFn,
|
||||||
KwFor,
|
KwFor,
|
||||||
|
KwFinal,
|
||||||
KwGen,
|
KwGen,
|
||||||
KwIf,
|
KwIf,
|
||||||
KwImpl,
|
KwImpl,
|
||||||
|
|
@ -309,6 +311,7 @@ impl TokenType {
|
||||||
TokenType::KwExtern => Some(kw::Extern),
|
TokenType::KwExtern => Some(kw::Extern),
|
||||||
TokenType::KwFn => Some(kw::Fn),
|
TokenType::KwFn => Some(kw::Fn),
|
||||||
TokenType::KwFor => Some(kw::For),
|
TokenType::KwFor => Some(kw::For),
|
||||||
|
TokenType::KwFinal => Some(kw::Final),
|
||||||
TokenType::KwGen => Some(kw::Gen),
|
TokenType::KwGen => Some(kw::Gen),
|
||||||
TokenType::KwIf => Some(kw::If),
|
TokenType::KwIf => Some(kw::If),
|
||||||
TokenType::KwImpl => Some(kw::Impl),
|
TokenType::KwImpl => Some(kw::Impl),
|
||||||
|
|
@ -524,6 +527,7 @@ macro_rules! exp {
|
||||||
(Extern) => { exp!(@kw, Extern, KwExtern) };
|
(Extern) => { exp!(@kw, Extern, KwExtern) };
|
||||||
(Fn) => { exp!(@kw, Fn, KwFn) };
|
(Fn) => { exp!(@kw, Fn, KwFn) };
|
||||||
(For) => { exp!(@kw, For, KwFor) };
|
(For) => { exp!(@kw, For, KwFor) };
|
||||||
|
(Final) => { exp!(@kw, Final, KwFinal) };
|
||||||
(Gen) => { exp!(@kw, Gen, KwGen) };
|
(Gen) => { exp!(@kw, Gen, KwGen) };
|
||||||
(If) => { exp!(@kw, If, KwIf) };
|
(If) => { exp!(@kw, If, KwIf) };
|
||||||
(Impl) => { exp!(@kw, Impl, KwImpl) };
|
(Impl) => { exp!(@kw, Impl, KwImpl) };
|
||||||
|
|
|
||||||
|
|
@ -1096,6 +1096,7 @@ symbols! {
|
||||||
fields,
|
fields,
|
||||||
file,
|
file,
|
||||||
file_options,
|
file_options,
|
||||||
|
final_associated_functions,
|
||||||
flags,
|
flags,
|
||||||
float,
|
float,
|
||||||
float_to_int_unchecked,
|
float_to_int_unchecked,
|
||||||
|
|
|
||||||
|
|
@ -314,6 +314,11 @@ pub fn dyn_compatibility_violations_for_assoc_item(
|
||||||
trait_def_id: DefId,
|
trait_def_id: DefId,
|
||||||
item: ty::AssocItem,
|
item: ty::AssocItem,
|
||||||
) -> Vec<DynCompatibilityViolation> {
|
) -> Vec<DynCompatibilityViolation> {
|
||||||
|
// `final` assoc functions don't prevent a trait from being dyn-compatible
|
||||||
|
if tcx.defaultness(item.def_id).is_final() {
|
||||||
|
return Vec::new();
|
||||||
|
}
|
||||||
|
|
||||||
// Any item that has a `Self: Sized` requisite is otherwise exempt from the regulations.
|
// Any item that has a `Self: Sized` requisite is otherwise exempt from the regulations.
|
||||||
if tcx.generics_require_sized_self(item.def_id) {
|
if tcx.generics_require_sized_self(item.def_id) {
|
||||||
return Vec::new();
|
return Vec::new();
|
||||||
|
|
|
||||||
|
|
@ -210,6 +210,11 @@ fn own_existential_vtable_entries_iter(
|
||||||
debug!("own_existential_vtable_entry: trait_method={:?}", trait_method);
|
debug!("own_existential_vtable_entry: trait_method={:?}", trait_method);
|
||||||
let def_id = trait_method.def_id;
|
let def_id = trait_method.def_id;
|
||||||
|
|
||||||
|
// Final methods should not be included in the vtable.
|
||||||
|
if trait_method.defaultness(tcx).is_final() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
// Some methods cannot be called on an object; skip those.
|
// Some methods cannot be called on an object; skip those.
|
||||||
if !is_vtable_safe_method(tcx, trait_def_id, trait_method) {
|
if !is_vtable_safe_method(tcx, trait_def_id, trait_method) {
|
||||||
debug!("own_existential_vtable_entry: not vtable safe");
|
debug!("own_existential_vtable_entry: not vtable safe");
|
||||||
|
|
|
||||||
|
|
@ -237,6 +237,12 @@ fn resolve_associated_item<'tcx>(
|
||||||
}
|
}
|
||||||
traits::ImplSource::Builtin(BuiltinImplSource::Object(_), _) => {
|
traits::ImplSource::Builtin(BuiltinImplSource::Object(_), _) => {
|
||||||
let trait_ref = ty::TraitRef::from_assoc(tcx, trait_id, rcvr_args);
|
let trait_ref = ty::TraitRef::from_assoc(tcx, trait_id, rcvr_args);
|
||||||
|
|
||||||
|
// `final` methods should be called directly.
|
||||||
|
if tcx.defaultness(trait_item_id).is_final() {
|
||||||
|
return Ok(Some(ty::Instance::new_raw(trait_item_id, rcvr_args)));
|
||||||
|
}
|
||||||
|
|
||||||
if trait_ref.has_non_region_infer() || trait_ref.has_non_region_param() {
|
if trait_ref.has_non_region_infer() || trait_ref.has_non_region_param() {
|
||||||
// We only resolve totally substituted vtable entries.
|
// We only resolve totally substituted vtable entries.
|
||||||
None
|
None
|
||||||
|
|
|
||||||
|
|
@ -1222,11 +1222,11 @@ fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext
|
||||||
}
|
}
|
||||||
hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
|
hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
|
||||||
let m = clean_function(cx, sig, trait_item.generics, ParamsSrc::Body(body));
|
let m = clean_function(cx, sig, trait_item.generics, ParamsSrc::Body(body));
|
||||||
MethodItem(m, None)
|
MethodItem(m, Defaultness::from_trait_item(trait_item.defaultness))
|
||||||
}
|
}
|
||||||
hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(idents)) => {
|
hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(idents)) => {
|
||||||
let m = clean_function(cx, sig, trait_item.generics, ParamsSrc::Idents(idents));
|
let m = clean_function(cx, sig, trait_item.generics, ParamsSrc::Idents(idents));
|
||||||
RequiredMethodItem(m)
|
RequiredMethodItem(m, Defaultness::from_trait_item(trait_item.defaultness))
|
||||||
}
|
}
|
||||||
hir::TraitItemKind::Type(bounds, Some(default)) => {
|
hir::TraitItemKind::Type(bounds, Some(default)) => {
|
||||||
let generics = enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx));
|
let generics = enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx));
|
||||||
|
|
@ -1271,7 +1271,7 @@ pub(crate) fn clean_impl_item<'tcx>(
|
||||||
hir::ImplItemImplKind::Inherent { .. } => hir::Defaultness::Final,
|
hir::ImplItemImplKind::Inherent { .. } => hir::Defaultness::Final,
|
||||||
hir::ImplItemImplKind::Trait { defaultness, .. } => defaultness,
|
hir::ImplItemImplKind::Trait { defaultness, .. } => defaultness,
|
||||||
};
|
};
|
||||||
MethodItem(m, Some(defaultness))
|
MethodItem(m, Defaultness::from_impl_item(defaultness))
|
||||||
}
|
}
|
||||||
hir::ImplItemKind::Type(hir_ty) => {
|
hir::ImplItemKind::Type(hir_ty) => {
|
||||||
let type_ = clean_ty(hir_ty, cx);
|
let type_ = clean_ty(hir_ty, cx);
|
||||||
|
|
@ -1353,18 +1353,20 @@ pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocCo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let provided = match assoc_item.container {
|
let defaultness = assoc_item.defaultness(tcx);
|
||||||
ty::AssocContainer::InherentImpl | ty::AssocContainer::TraitImpl(_) => true,
|
let (provided, defaultness) = match assoc_item.container {
|
||||||
ty::AssocContainer::Trait => assoc_item.defaultness(tcx).has_value(),
|
ty::AssocContainer::Trait => {
|
||||||
|
(defaultness.has_value(), Defaultness::from_trait_item(defaultness))
|
||||||
|
}
|
||||||
|
ty::AssocContainer::InherentImpl | ty::AssocContainer::TraitImpl(_) => {
|
||||||
|
(true, Defaultness::from_impl_item(defaultness))
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if provided {
|
if provided {
|
||||||
let defaultness = match assoc_item.container {
|
|
||||||
ty::AssocContainer::TraitImpl(_) => Some(assoc_item.defaultness(tcx)),
|
|
||||||
ty::AssocContainer::InherentImpl | ty::AssocContainer::Trait => None,
|
|
||||||
};
|
|
||||||
MethodItem(item, defaultness)
|
MethodItem(item, defaultness)
|
||||||
} else {
|
} else {
|
||||||
RequiredMethodItem(item)
|
RequiredMethodItem(item, defaultness)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ty::AssocKind::Type { .. } => {
|
ty::AssocKind::Type { .. } => {
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,29 @@ pub(crate) enum ItemId {
|
||||||
Blanket { impl_id: DefId, for_: DefId },
|
Blanket { impl_id: DefId, for_: DefId },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
|
pub(crate) enum Defaultness {
|
||||||
|
Implicit,
|
||||||
|
Default,
|
||||||
|
Final,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Defaultness {
|
||||||
|
pub(crate) fn from_trait_item(defaultness: hir::Defaultness) -> Self {
|
||||||
|
match defaultness {
|
||||||
|
hir::Defaultness::Default { .. } => Self::Implicit,
|
||||||
|
hir::Defaultness::Final => Self::Final,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn from_impl_item(defaultness: hir::Defaultness) -> Self {
|
||||||
|
match defaultness {
|
||||||
|
hir::Defaultness::Default { .. } => Self::Default,
|
||||||
|
hir::Defaultness::Final => Self::Implicit,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ItemId {
|
impl ItemId {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn is_local(self) -> bool {
|
pub(crate) fn is_local(self) -> bool {
|
||||||
|
|
@ -707,12 +730,12 @@ impl Item {
|
||||||
ItemType::from(self)
|
ItemType::from(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn is_default(&self) -> bool {
|
pub(crate) fn defaultness(&self) -> Option<Defaultness> {
|
||||||
match self.kind {
|
match self.kind {
|
||||||
ItemKind::MethodItem(_, Some(defaultness)) => {
|
ItemKind::MethodItem(_, defaultness) | ItemKind::RequiredMethodItem(_, defaultness) => {
|
||||||
defaultness.has_value() && !defaultness.is_final()
|
Some(defaultness)
|
||||||
}
|
}
|
||||||
_ => false,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -774,8 +797,8 @@ impl Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ItemKind::FunctionItem(_)
|
ItemKind::FunctionItem(_)
|
||||||
| ItemKind::MethodItem(_, _)
|
| ItemKind::MethodItem(..)
|
||||||
| ItemKind::RequiredMethodItem(_) => {
|
| ItemKind::RequiredMethodItem(..) => {
|
||||||
let def_id = self.def_id().unwrap();
|
let def_id = self.def_id().unwrap();
|
||||||
build_fn_header(def_id, tcx, tcx.asyncness(def_id))
|
build_fn_header(def_id, tcx, tcx.asyncness(def_id))
|
||||||
}
|
}
|
||||||
|
|
@ -859,11 +882,11 @@ pub(crate) enum ItemKind {
|
||||||
TraitAliasItem(TraitAlias),
|
TraitAliasItem(TraitAlias),
|
||||||
ImplItem(Box<Impl>),
|
ImplItem(Box<Impl>),
|
||||||
/// A required method in a trait declaration meaning it's only a function signature.
|
/// A required method in a trait declaration meaning it's only a function signature.
|
||||||
RequiredMethodItem(Box<Function>),
|
RequiredMethodItem(Box<Function>, Defaultness),
|
||||||
/// A method in a trait impl or a provided method in a trait declaration.
|
/// A method in a trait impl or a provided method in a trait declaration.
|
||||||
///
|
///
|
||||||
/// Compared to [RequiredMethodItem], it also contains a method body.
|
/// Compared to [RequiredMethodItem], it also contains a method body.
|
||||||
MethodItem(Box<Function>, Option<hir::Defaultness>),
|
MethodItem(Box<Function>, Defaultness),
|
||||||
StructFieldItem(Type),
|
StructFieldItem(Type),
|
||||||
VariantItem(Variant),
|
VariantItem(Variant),
|
||||||
/// `fn`s from an extern block
|
/// `fn`s from an extern block
|
||||||
|
|
@ -921,8 +944,8 @@ impl ItemKind {
|
||||||
| StaticItem(_)
|
| StaticItem(_)
|
||||||
| ConstantItem(_)
|
| ConstantItem(_)
|
||||||
| TraitAliasItem(_)
|
| TraitAliasItem(_)
|
||||||
| RequiredMethodItem(_)
|
| RequiredMethodItem(..)
|
||||||
| MethodItem(_, _)
|
| MethodItem(..)
|
||||||
| StructFieldItem(_)
|
| StructFieldItem(_)
|
||||||
| ForeignFunctionItem(_, _)
|
| ForeignFunctionItem(_, _)
|
||||||
| ForeignStaticItem(_, _)
|
| ForeignStaticItem(_, _)
|
||||||
|
|
|
||||||
|
|
@ -82,8 +82,8 @@ pub(crate) trait DocFolder: Sized {
|
||||||
| StaticItem(_)
|
| StaticItem(_)
|
||||||
| ConstantItem(..)
|
| ConstantItem(..)
|
||||||
| TraitAliasItem(_)
|
| TraitAliasItem(_)
|
||||||
| RequiredMethodItem(_)
|
| RequiredMethodItem(..)
|
||||||
| MethodItem(_, _)
|
| MethodItem(..)
|
||||||
| StructFieldItem(_)
|
| StructFieldItem(_)
|
||||||
| ForeignFunctionItem(..)
|
| ForeignFunctionItem(..)
|
||||||
| ForeignStaticItem(..)
|
| ForeignStaticItem(..)
|
||||||
|
|
|
||||||
|
|
@ -1566,10 +1566,6 @@ pub(crate) fn print_abi_with_space(abi: ExternAbi) -> impl Display {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn print_default_space(v: bool) -> &'static str {
|
|
||||||
if v { "default " } else { "" }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn print_generic_arg(generic_arg: &clean::GenericArg, cx: &Context<'_>) -> impl Display {
|
fn print_generic_arg(generic_arg: &clean::GenericArg, cx: &Context<'_>) -> impl Display {
|
||||||
fmt::from_fn(move |f| match generic_arg {
|
fmt::from_fn(move |f| match generic_arg {
|
||||||
clean::GenericArg::Lifetime(lt) => f.write_str(print_lifetime(lt)),
|
clean::GenericArg::Lifetime(lt) => f.write_str(print_lifetime(lt)),
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,7 @@ use tracing::{debug, info};
|
||||||
pub(crate) use self::context::*;
|
pub(crate) use self::context::*;
|
||||||
pub(crate) use self::span_map::{LinkFromSrc, collect_spans_and_sources};
|
pub(crate) use self::span_map::{LinkFromSrc, collect_spans_and_sources};
|
||||||
pub(crate) use self::write_shared::*;
|
pub(crate) use self::write_shared::*;
|
||||||
use crate::clean::{self, ItemId, RenderedLink};
|
use crate::clean::{self, Defaultness, ItemId, RenderedLink};
|
||||||
use crate::display::{Joined as _, MaybeDisplay as _};
|
use crate::display::{Joined as _, MaybeDisplay as _};
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
use crate::formats::Impl;
|
use crate::formats::Impl;
|
||||||
|
|
@ -75,8 +75,8 @@ use crate::formats::item_type::ItemType;
|
||||||
use crate::html::escape::Escape;
|
use crate::html::escape::Escape;
|
||||||
use crate::html::format::{
|
use crate::html::format::{
|
||||||
Ending, HrefError, HrefInfo, PrintWithSpace, full_print_fn_decl, href, print_abi_with_space,
|
Ending, HrefError, HrefInfo, PrintWithSpace, full_print_fn_decl, href, print_abi_with_space,
|
||||||
print_constness_with_space, print_default_space, print_generic_bounds, print_generics,
|
print_constness_with_space, print_generic_bounds, print_generics, print_impl, print_path,
|
||||||
print_impl, print_path, print_type, print_where_clause, visibility_print_with_space,
|
print_type, print_where_clause, visibility_print_with_space,
|
||||||
};
|
};
|
||||||
use crate::html::markdown::{
|
use crate::html::markdown::{
|
||||||
HeadingOffset, IdMap, Markdown, MarkdownItemInfo, MarkdownSummaryLine,
|
HeadingOffset, IdMap, Markdown, MarkdownItemInfo, MarkdownSummaryLine,
|
||||||
|
|
@ -1110,7 +1110,11 @@ fn assoc_method(
|
||||||
let header = meth.fn_header(tcx).expect("Trying to get header from a non-function item");
|
let header = meth.fn_header(tcx).expect("Trying to get header from a non-function item");
|
||||||
let name = meth.name.as_ref().unwrap();
|
let name = meth.name.as_ref().unwrap();
|
||||||
let vis = visibility_print_with_space(meth, cx).to_string();
|
let vis = visibility_print_with_space(meth, cx).to_string();
|
||||||
let defaultness = print_default_space(meth.is_default());
|
let defaultness = match meth.defaultness().expect("Expected assoc method to have defaultness") {
|
||||||
|
Defaultness::Implicit => "",
|
||||||
|
Defaultness::Final => "final ",
|
||||||
|
Defaultness::Default => "default ",
|
||||||
|
};
|
||||||
// FIXME: Once https://github.com/rust-lang/rust/issues/143874 is implemented, we can remove
|
// FIXME: Once https://github.com/rust-lang/rust/issues/143874 is implemented, we can remove
|
||||||
// this condition.
|
// this condition.
|
||||||
let constness = match render_mode {
|
let constness = match render_mode {
|
||||||
|
|
@ -1261,7 +1265,7 @@ fn render_assoc_item(
|
||||||
) -> impl fmt::Display {
|
) -> impl fmt::Display {
|
||||||
fmt::from_fn(move |f| match &item.kind {
|
fmt::from_fn(move |f| match &item.kind {
|
||||||
clean::StrippedItem(..) => Ok(()),
|
clean::StrippedItem(..) => Ok(()),
|
||||||
clean::RequiredMethodItem(m) | clean::MethodItem(m, _) => {
|
clean::RequiredMethodItem(m, _) | clean::MethodItem(m, _) => {
|
||||||
assoc_method(item, &m.generics, &m.decl, link, parent, cx, render_mode).fmt(f)
|
assoc_method(item, &m.generics, &m.decl, link, parent, cx, render_mode).fmt(f)
|
||||||
}
|
}
|
||||||
clean::RequiredAssocConstItem(generics, ty) => assoc_const(
|
clean::RequiredAssocConstItem(generics, ty) => assoc_const(
|
||||||
|
|
@ -1586,7 +1590,7 @@ fn render_deref_methods(
|
||||||
fn should_render_item(item: &clean::Item, deref_mut_: bool, tcx: TyCtxt<'_>) -> bool {
|
fn should_render_item(item: &clean::Item, deref_mut_: bool, tcx: TyCtxt<'_>) -> bool {
|
||||||
let self_type_opt = match item.kind {
|
let self_type_opt = match item.kind {
|
||||||
clean::MethodItem(ref method, _) => method.decl.receiver_type(),
|
clean::MethodItem(ref method, _) => method.decl.receiver_type(),
|
||||||
clean::RequiredMethodItem(ref method) => method.decl.receiver_type(),
|
clean::RequiredMethodItem(ref method, _) => method.decl.receiver_type(),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -1856,7 +1860,7 @@ fn render_impl(
|
||||||
deprecation_class = "";
|
deprecation_class = "";
|
||||||
}
|
}
|
||||||
match &item.kind {
|
match &item.kind {
|
||||||
clean::MethodItem(..) | clean::RequiredMethodItem(_) => {
|
clean::MethodItem(..) | clean::RequiredMethodItem(..) => {
|
||||||
// Only render when the method is not static or we allow static methods
|
// Only render when the method is not static or we allow static methods
|
||||||
if render_method_item {
|
if render_method_item {
|
||||||
let id = cx.derive_id(format!("{item_type}.{name}"));
|
let id = cx.derive_id(format!("{item_type}.{name}"));
|
||||||
|
|
@ -2034,7 +2038,9 @@ fn render_impl(
|
||||||
if !impl_.is_negative_trait_impl() {
|
if !impl_.is_negative_trait_impl() {
|
||||||
for impl_item in &impl_.items {
|
for impl_item in &impl_.items {
|
||||||
match impl_item.kind {
|
match impl_item.kind {
|
||||||
clean::MethodItem(..) | clean::RequiredMethodItem(_) => methods.push(impl_item),
|
clean::MethodItem(..) | clean::RequiredMethodItem(..) => {
|
||||||
|
methods.push(impl_item)
|
||||||
|
}
|
||||||
clean::RequiredAssocTypeItem(..) | clean::AssocTypeItem(..) => {
|
clean::RequiredAssocTypeItem(..) | clean::AssocTypeItem(..) => {
|
||||||
assoc_types.push(impl_item)
|
assoc_types.push(impl_item)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1977,7 +1977,7 @@ pub(crate) fn get_function_type_for_search(
|
||||||
clean::ForeignFunctionItem(ref f, _)
|
clean::ForeignFunctionItem(ref f, _)
|
||||||
| clean::FunctionItem(ref f)
|
| clean::FunctionItem(ref f)
|
||||||
| clean::MethodItem(ref f, _)
|
| clean::MethodItem(ref f, _)
|
||||||
| clean::RequiredMethodItem(ref f) => {
|
| clean::RequiredMethodItem(ref f, _) => {
|
||||||
get_fn_inputs_and_outputs(f, tcx, impl_or_trait_generics, cache)
|
get_fn_inputs_and_outputs(f, tcx, impl_or_trait_generics, cache)
|
||||||
}
|
}
|
||||||
clean::ConstantItem(ref c) => make_nullary_fn(&c.type_),
|
clean::ConstantItem(ref c) => make_nullary_fn(&c.type_),
|
||||||
|
|
|
||||||
|
|
@ -296,7 +296,7 @@ fn from_clean_item(item: &clean::Item, renderer: &JsonRenderer<'_>) -> ItemEnum
|
||||||
MethodItem(m, _) => {
|
MethodItem(m, _) => {
|
||||||
ItemEnum::Function(from_clean_function(m, true, header.unwrap(), renderer))
|
ItemEnum::Function(from_clean_function(m, true, header.unwrap(), renderer))
|
||||||
}
|
}
|
||||||
RequiredMethodItem(m) => {
|
RequiredMethodItem(m, _) => {
|
||||||
ItemEnum::Function(from_clean_function(m, false, header.unwrap(), renderer))
|
ItemEnum::Function(from_clean_function(m, false, header.unwrap(), renderer))
|
||||||
}
|
}
|
||||||
ImplItem(i) => ItemEnum::Impl(i.into_json(renderer)),
|
ImplItem(i) => ItemEnum::Impl(i.into_json(renderer)),
|
||||||
|
|
|
||||||
|
|
@ -35,8 +35,8 @@ pub(crate) trait DocVisitor<'a>: Sized {
|
||||||
| StaticItem(_)
|
| StaticItem(_)
|
||||||
| ConstantItem(..)
|
| ConstantItem(..)
|
||||||
| TraitAliasItem(_)
|
| TraitAliasItem(_)
|
||||||
| RequiredMethodItem(_)
|
| RequiredMethodItem(..)
|
||||||
| MethodItem(_, _)
|
| MethodItem(..)
|
||||||
| StructFieldItem(_)
|
| StructFieldItem(_)
|
||||||
| ForeignFunctionItem(..)
|
| ForeignFunctionItem(..)
|
||||||
| ForeignStaticItem(..)
|
| ForeignStaticItem(..)
|
||||||
|
|
|
||||||
|
|
@ -819,7 +819,9 @@ pub fn eq_use_tree_kind(l: &UseTreeKind, r: &UseTreeKind) -> bool {
|
||||||
pub fn eq_defaultness(l: Defaultness, r: Defaultness) -> bool {
|
pub fn eq_defaultness(l: Defaultness, r: Defaultness) -> bool {
|
||||||
matches!(
|
matches!(
|
||||||
(l, r),
|
(l, r),
|
||||||
(Defaultness::Final, Defaultness::Final) | (Defaultness::Default(_), Defaultness::Default(_))
|
(Defaultness::Implicit, Defaultness::Implicit)
|
||||||
|
| (Defaultness::Default(_), Defaultness::Default(_))
|
||||||
|
| (Defaultness::Final(_), Defaultness::Final(_))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -319,12 +319,13 @@ impl<'a> FnSig<'a> {
|
||||||
method_sig: &'a ast::FnSig,
|
method_sig: &'a ast::FnSig,
|
||||||
generics: &'a ast::Generics,
|
generics: &'a ast::Generics,
|
||||||
visibility: &'a ast::Visibility,
|
visibility: &'a ast::Visibility,
|
||||||
|
defaultness: ast::Defaultness,
|
||||||
) -> FnSig<'a> {
|
) -> FnSig<'a> {
|
||||||
FnSig {
|
FnSig {
|
||||||
safety: method_sig.header.safety,
|
safety: method_sig.header.safety,
|
||||||
coroutine_kind: Cow::Borrowed(&method_sig.header.coroutine_kind),
|
coroutine_kind: Cow::Borrowed(&method_sig.header.coroutine_kind),
|
||||||
constness: method_sig.header.constness,
|
constness: method_sig.header.constness,
|
||||||
defaultness: ast::Defaultness::Final,
|
defaultness,
|
||||||
ext: method_sig.header.ext,
|
ext: method_sig.header.ext,
|
||||||
decl: &*method_sig.decl,
|
decl: &*method_sig.decl,
|
||||||
generics,
|
generics,
|
||||||
|
|
@ -339,9 +340,7 @@ impl<'a> FnSig<'a> {
|
||||||
) -> FnSig<'a> {
|
) -> FnSig<'a> {
|
||||||
match *fn_kind {
|
match *fn_kind {
|
||||||
visit::FnKind::Fn(visit::FnCtxt::Assoc(..), vis, ast::Fn { sig, generics, .. }) => {
|
visit::FnKind::Fn(visit::FnCtxt::Assoc(..), vis, ast::Fn { sig, generics, .. }) => {
|
||||||
let mut fn_sig = FnSig::from_method_sig(sig, generics, vis);
|
FnSig::from_method_sig(sig, generics, vis, defaultness)
|
||||||
fn_sig.defaultness = defaultness;
|
|
||||||
fn_sig
|
|
||||||
}
|
}
|
||||||
visit::FnKind::Fn(_, vis, ast::Fn { sig, generics, .. }) => FnSig {
|
visit::FnKind::Fn(_, vis, ast::Fn { sig, generics, .. }) => FnSig {
|
||||||
decl,
|
decl,
|
||||||
|
|
@ -459,6 +458,7 @@ impl<'a> FmtVisitor<'a> {
|
||||||
sig: &ast::FnSig,
|
sig: &ast::FnSig,
|
||||||
vis: &ast::Visibility,
|
vis: &ast::Visibility,
|
||||||
generics: &ast::Generics,
|
generics: &ast::Generics,
|
||||||
|
defaultness: ast::Defaultness,
|
||||||
span: Span,
|
span: Span,
|
||||||
) -> RewriteResult {
|
) -> RewriteResult {
|
||||||
// Drop semicolon or it will be interpreted as comment.
|
// Drop semicolon or it will be interpreted as comment.
|
||||||
|
|
@ -469,7 +469,7 @@ impl<'a> FmtVisitor<'a> {
|
||||||
&context,
|
&context,
|
||||||
indent,
|
indent,
|
||||||
ident,
|
ident,
|
||||||
&FnSig::from_method_sig(sig, generics, vis),
|
&FnSig::from_method_sig(sig, generics, vis, defaultness),
|
||||||
span,
|
span,
|
||||||
FnBraceStyle::None,
|
FnBraceStyle::None,
|
||||||
)?;
|
)?;
|
||||||
|
|
@ -3495,7 +3495,7 @@ impl Rewrite for ast::ForeignItem {
|
||||||
context,
|
context,
|
||||||
shape.indent,
|
shape.indent,
|
||||||
ident,
|
ident,
|
||||||
&FnSig::from_method_sig(sig, generics, &self.vis),
|
&FnSig::from_method_sig(sig, generics, &self.vis, defaultness),
|
||||||
span,
|
span,
|
||||||
FnBraceStyle::None,
|
FnBraceStyle::None,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -102,8 +102,9 @@ pub(crate) fn format_constness_right(constness: ast::Const) -> &'static str {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn format_defaultness(defaultness: ast::Defaultness) -> &'static str {
|
pub(crate) fn format_defaultness(defaultness: ast::Defaultness) -> &'static str {
|
||||||
match defaultness {
|
match defaultness {
|
||||||
|
ast::Defaultness::Implicit => "",
|
||||||
ast::Defaultness::Default(..) => "default ",
|
ast::Defaultness::Default(..) => "default ",
|
||||||
ast::Defaultness::Final => "",
|
ast::Defaultness::Final(..) => "final ",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -583,7 +583,15 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
|
||||||
} else {
|
} else {
|
||||||
let indent = self.block_indent;
|
let indent = self.block_indent;
|
||||||
let rewrite = self
|
let rewrite = self
|
||||||
.rewrite_required_fn(indent, ident, sig, &item.vis, generics, item.span)
|
.rewrite_required_fn(
|
||||||
|
indent,
|
||||||
|
ident,
|
||||||
|
sig,
|
||||||
|
&item.vis,
|
||||||
|
generics,
|
||||||
|
defaultness,
|
||||||
|
item.span,
|
||||||
|
)
|
||||||
.ok();
|
.ok();
|
||||||
self.push_rewrite(item.span, rewrite);
|
self.push_rewrite(item.span, rewrite);
|
||||||
}
|
}
|
||||||
|
|
@ -686,7 +694,15 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
|
||||||
} else {
|
} else {
|
||||||
let indent = self.block_indent;
|
let indent = self.block_indent;
|
||||||
let rewrite = self
|
let rewrite = self
|
||||||
.rewrite_required_fn(indent, fn_kind.ident, sig, &ai.vis, generics, ai.span)
|
.rewrite_required_fn(
|
||||||
|
indent,
|
||||||
|
fn_kind.ident,
|
||||||
|
sig,
|
||||||
|
&ai.vis,
|
||||||
|
generics,
|
||||||
|
defaultness,
|
||||||
|
ai.span,
|
||||||
|
)
|
||||||
.ok();
|
.ok();
|
||||||
self.push_rewrite(ai.span, rewrite);
|
self.push_rewrite(ai.span, rewrite);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
5
src/tools/rustfmt/tests/target/final-kw.rs
Normal file
5
src/tools/rustfmt/tests/target/final-kw.rs
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
trait Foo {
|
||||||
|
final fn final_() {}
|
||||||
|
|
||||||
|
fn not_final() {}
|
||||||
|
}
|
||||||
22
tests/rustdoc-html/final-trait-method.rs
Normal file
22
tests/rustdoc-html/final-trait-method.rs
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
#![feature(final_associated_functions)]
|
||||||
|
|
||||||
|
//@ has final_trait_method/trait.Item.html
|
||||||
|
pub trait Item {
|
||||||
|
//@ has - '//*[@id="method.foo"]' 'final fn foo()'
|
||||||
|
//@ !has - '//*[@id="method.foo"]' 'default fn foo()'
|
||||||
|
final fn foo() {}
|
||||||
|
|
||||||
|
//@ has - '//*[@id="method.bar"]' 'fn bar()'
|
||||||
|
//@ !has - '//*[@id="method.bar"]' 'default fn bar()'
|
||||||
|
//@ !has - '//*[@id="method.bar"]' 'final fn bar()'
|
||||||
|
fn bar() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
//@ has final_trait_method/struct.Foo.html
|
||||||
|
pub struct Foo;
|
||||||
|
impl Item for Foo {
|
||||||
|
//@ has - '//*[@id="method.bar"]' 'fn bar()'
|
||||||
|
//@ !has - '//*[@id="method.bar"]' 'final fn bar()'
|
||||||
|
//@ !has - '//*[@id="method.bar"]' 'default fn bar()'
|
||||||
|
fn bar() {}
|
||||||
|
}
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
error: expected one of `#`, `async`, `const`, `default`, `extern`, `fn`, `pub`, `safe`, `unsafe`, or `use`, found `gen`
|
error: expected one of `#`, `async`, `const`, `default`, `extern`, `final`, `fn`, `pub`, `safe`, `unsafe`, or `use`, found `gen`
|
||||||
--> $DIR/gen_fn.rs:4:1
|
--> $DIR/gen_fn.rs:4:1
|
||||||
|
|
|
|
||||||
LL | gen fn foo() {}
|
LL | gen fn foo() {}
|
||||||
| ^^^ expected one of 10 possible tokens
|
| ^^^ expected one of 11 possible tokens
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
//@[e2024] edition: 2024
|
//@[e2024] edition: 2024
|
||||||
|
|
||||||
gen fn foo() {}
|
gen fn foo() {}
|
||||||
//[none]~^ ERROR: expected one of `#`, `async`, `const`, `default`, `extern`, `fn`, `pub`, `safe`, `unsafe`, or `use`, found `gen`
|
//[none]~^ ERROR: expected one of `#`, `async`, `const`, `default`, `extern`, `final`, `fn`, `pub`, `safe`, `unsafe`, or `use`, found `gen`
|
||||||
//[e2024]~^^ ERROR: gen blocks are experimental
|
//[e2024]~^^ ERROR: gen blocks are experimental
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
trait Foo {
|
||||||
|
final fn bar() {}
|
||||||
|
//~^ ERROR `final` on trait functions is experimental
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
error[E0658]: `final` on trait functions is experimental
|
||||||
|
--> $DIR/feature-gate-final-associated-functions.rs:2:5
|
||||||
|
|
|
||||||
|
LL | final fn bar() {}
|
||||||
|
| ^^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
|
||||||
|
= help: add `#![feature(final_associated_functions)]` to the crate attributes to enable
|
||||||
|
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0658`.
|
||||||
|
|
@ -2,8 +2,8 @@ fn main() {}
|
||||||
|
|
||||||
extern "C" { //~ NOTE while parsing this item list starting here
|
extern "C" { //~ NOTE while parsing this item list starting here
|
||||||
pub pub fn foo();
|
pub pub fn foo();
|
||||||
//~^ ERROR expected one of `(`, `async`, `const`, `default`, `extern`, `fn`, `safe`, `unsafe`, or `use`, found keyword `pub`
|
//~^ ERROR expected one of `(`, `async`, `const`, `default`, `extern`, `final`, `fn`, `safe`, `unsafe`, or `use`, found keyword `pub`
|
||||||
//~| NOTE expected one of 9 possible tokens
|
//~| NOTE expected one of 10 possible tokens
|
||||||
//~| HELP there is already a visibility modifier, remove one
|
//~| HELP there is already a visibility modifier, remove one
|
||||||
//~| NOTE explicit visibility first seen here
|
//~| NOTE explicit visibility first seen here
|
||||||
} //~ NOTE the item list ends here
|
} //~ NOTE the item list ends here
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
error: expected one of `(`, `async`, `const`, `default`, `extern`, `fn`, `safe`, `unsafe`, or `use`, found keyword `pub`
|
error: expected one of `(`, `async`, `const`, `default`, `extern`, `final`, `fn`, `safe`, `unsafe`, or `use`, found keyword `pub`
|
||||||
--> $DIR/duplicate-visibility.rs:4:9
|
--> $DIR/duplicate-visibility.rs:4:9
|
||||||
|
|
|
|
||||||
LL | extern "C" {
|
LL | extern "C" {
|
||||||
|
|
@ -6,7 +6,7 @@ LL | extern "C" {
|
||||||
LL | pub pub fn foo();
|
LL | pub pub fn foo();
|
||||||
| ^^^
|
| ^^^
|
||||||
| |
|
| |
|
||||||
| expected one of 9 possible tokens
|
| expected one of 10 possible tokens
|
||||||
| help: there is already a visibility modifier, remove one
|
| help: there is already a visibility modifier, remove one
|
||||||
...
|
...
|
||||||
LL | }
|
LL | }
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
error: expected one of `#`, `async`, `auto`, `const`, `default`, `enum`, `extern`, `fn`, `gen`, `impl`, `macro_rules`, `macro`, `mod`, `pub`, `safe`, `static`, `struct`, `trait`, `type`, `unsafe`, or `use`, found `puB`
|
error: expected one of `#`, `async`, `auto`, `const`, `default`, `enum`, `extern`, `final`, `fn`, `gen`, `impl`, `macro_rules`, `macro`, `mod`, `pub`, `safe`, `static`, `struct`, `trait`, `type`, `unsafe`, or `use`, found `puB`
|
||||||
--> $DIR/pub-fn.rs:1:1
|
--> $DIR/pub-fn.rs:1:1
|
||||||
|
|
|
|
||||||
LL | puB fn code() {}
|
LL | puB fn code() {}
|
||||||
| ^^^ expected one of 21 possible tokens
|
| ^^^ expected one of 22 possible tokens
|
||||||
|
|
|
|
||||||
help: write keyword `pub` in lowercase
|
help: write keyword `pub` in lowercase
|
||||||
|
|
|
|
||||||
|
|
|
||||||
40
tests/ui/traits/final/dyn-compat.rs
Normal file
40
tests/ui/traits/final/dyn-compat.rs
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
//@ run-pass
|
||||||
|
|
||||||
|
#![feature(final_associated_functions)]
|
||||||
|
|
||||||
|
trait FinalNoReceiver {
|
||||||
|
final fn no_receiver() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
trait FinalGeneric {
|
||||||
|
final fn generic<T>(&self, _value: T) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
trait FinalSelfParam {
|
||||||
|
final fn self_param(&self, _other: &Self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
trait FinalSelfReturn {
|
||||||
|
final fn self_return(&self) -> &Self {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct S;
|
||||||
|
|
||||||
|
impl FinalNoReceiver for S {}
|
||||||
|
impl FinalGeneric for S {}
|
||||||
|
impl FinalSelfParam for S {}
|
||||||
|
impl FinalSelfReturn for S {}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let s = S;
|
||||||
|
<S as FinalNoReceiver>::no_receiver();
|
||||||
|
let obj_generic: &dyn FinalGeneric = &s;
|
||||||
|
let obj_param: &dyn FinalSelfParam = &s;
|
||||||
|
let obj_return: &dyn FinalSelfReturn = &s;
|
||||||
|
obj_generic.generic(1u8);
|
||||||
|
obj_param.self_param(obj_param);
|
||||||
|
let _ = obj_return.self_return();
|
||||||
|
let _: &dyn FinalNoReceiver = &s;
|
||||||
|
}
|
||||||
13
tests/ui/traits/final/final-kw.gated.stderr
Normal file
13
tests/ui/traits/final/final-kw.gated.stderr
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
error[E0658]: `final` on trait functions is experimental
|
||||||
|
--> $DIR/final-kw.rs:5:5
|
||||||
|
|
|
||||||
|
LL | final fn foo() {}
|
||||||
|
| ^^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
|
||||||
|
= help: add `#![feature(final_associated_functions)]` to the crate attributes to enable
|
||||||
|
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0658`.
|
||||||
9
tests/ui/traits/final/final-kw.rs
Normal file
9
tests/ui/traits/final/final-kw.rs
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
//@ revisions: ungated gated
|
||||||
|
|
||||||
|
#[cfg(ungated)]
|
||||||
|
trait Trait {
|
||||||
|
final fn foo() {}
|
||||||
|
//~^ ERROR `final` on trait functions is experimental
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
13
tests/ui/traits/final/final-kw.ungated.stderr
Normal file
13
tests/ui/traits/final/final-kw.ungated.stderr
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
error[E0658]: `final` on trait functions is experimental
|
||||||
|
--> $DIR/final-kw.rs:5:5
|
||||||
|
|
|
||||||
|
LL | final fn foo() {}
|
||||||
|
| ^^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #1 <https://github.com/rust-lang/rust/issues/1> for more information
|
||||||
|
= help: add `#![feature(final_associated_functions)]` to the crate attributes to enable
|
||||||
|
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0658`.
|
||||||
8
tests/ui/traits/final/final-must-have-body.rs
Normal file
8
tests/ui/traits/final/final-must-have-body.rs
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
#![feature(final_associated_functions)]
|
||||||
|
|
||||||
|
trait Foo {
|
||||||
|
final fn method();
|
||||||
|
//~^ ERROR `final` is only allowed on associated functions if they have a body
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
10
tests/ui/traits/final/final-must-have-body.stderr
Normal file
10
tests/ui/traits/final/final-must-have-body.stderr
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
error: `final` is only allowed on associated functions if they have a body
|
||||||
|
--> $DIR/final-must-have-body.rs:4:5
|
||||||
|
|
|
||||||
|
LL | final fn method();
|
||||||
|
| -----^^^^^^^^^^^^^
|
||||||
|
| |
|
||||||
|
| `final` because of this
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
12
tests/ui/traits/final/overriding.rs
Normal file
12
tests/ui/traits/final/overriding.rs
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
#![feature(final_associated_functions)]
|
||||||
|
|
||||||
|
trait Foo {
|
||||||
|
final fn method() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Foo for () {
|
||||||
|
fn method() {}
|
||||||
|
//~^ ERROR cannot override `method` because it already has a `final` definition in the trait
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
14
tests/ui/traits/final/overriding.stderr
Normal file
14
tests/ui/traits/final/overriding.stderr
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
error: cannot override `method` because it already has a `final` definition in the trait
|
||||||
|
--> $DIR/overriding.rs:8:5
|
||||||
|
|
|
||||||
|
LL | fn method() {}
|
||||||
|
| ^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
note: `method` is marked final here
|
||||||
|
--> $DIR/overriding.rs:4:5
|
||||||
|
|
|
||||||
|
LL | final fn method() {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
72
tests/ui/traits/final/positions.rs
Normal file
72
tests/ui/traits/final/positions.rs
Normal file
|
|
@ -0,0 +1,72 @@
|
||||||
|
#![feature(final_associated_functions)]
|
||||||
|
|
||||||
|
// Just for exercising the syntax positions
|
||||||
|
#![feature(associated_type_defaults, extern_types, inherent_associated_types)]
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
|
||||||
|
final struct Foo {}
|
||||||
|
//~^ ERROR a struct cannot be `final`
|
||||||
|
|
||||||
|
final trait Trait {
|
||||||
|
//~^ ERROR a trait cannot be `final`
|
||||||
|
|
||||||
|
final fn method() {}
|
||||||
|
// OK!
|
||||||
|
|
||||||
|
final type Foo = ();
|
||||||
|
//~^ ERROR `final` is only allowed on associated functions in traits
|
||||||
|
|
||||||
|
final const FOO: usize = 1;
|
||||||
|
//~^ ERROR `final` is only allowed on associated functions in traits
|
||||||
|
}
|
||||||
|
|
||||||
|
final impl Foo {
|
||||||
|
final fn method() {}
|
||||||
|
//~^ ERROR `final` is only allowed on associated functions in traits
|
||||||
|
|
||||||
|
final type Foo = ();
|
||||||
|
//~^ ERROR `final` is only allowed on associated functions in traits
|
||||||
|
|
||||||
|
final const FOO: usize = 1;
|
||||||
|
//~^ ERROR `final` is only allowed on associated functions in traits
|
||||||
|
}
|
||||||
|
|
||||||
|
final impl Trait for Foo {
|
||||||
|
final fn method() {}
|
||||||
|
//~^ ERROR `final` is only allowed on associated functions in traits
|
||||||
|
//~^^ ERROR cannot override `method` because it already has a `final` definition in the trait
|
||||||
|
|
||||||
|
final type Foo = ();
|
||||||
|
//~^ ERROR `final` is only allowed on associated functions in traits
|
||||||
|
//~^^ ERROR cannot override `Foo` because it already has a `final` definition in the trait
|
||||||
|
|
||||||
|
final const FOO: usize = 1;
|
||||||
|
//~^ ERROR `final` is only allowed on associated functions in traits
|
||||||
|
//~^^ ERROR cannot override `FOO` because it already has a `final` definition in the trait
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
final fn foo() {}
|
||||||
|
//~^ ERROR `final` is only allowed on associated functions in traits
|
||||||
|
|
||||||
|
final type FooTy = ();
|
||||||
|
//~^ ERROR `final` is only allowed on associated functions in traits
|
||||||
|
|
||||||
|
final const FOO: usize = 0;
|
||||||
|
//~^ ERROR `final` is only allowed on associated functions in traits
|
||||||
|
|
||||||
|
final unsafe extern "C" {
|
||||||
|
//~^ ERROR an extern block cannot be `final`
|
||||||
|
|
||||||
|
final fn foo_extern();
|
||||||
|
//~^ ERROR `final` is only allowed on associated functions in traits
|
||||||
|
|
||||||
|
final type FooExtern;
|
||||||
|
//~^ ERROR `final` is only allowed on associated functions in traits
|
||||||
|
|
||||||
|
final static FOO_EXTERN: usize = 0;
|
||||||
|
//~^ ERROR a static item cannot be `final`
|
||||||
|
//~| ERROR incorrect `static` inside `extern` block
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
187
tests/ui/traits/final/positions.stderr
Normal file
187
tests/ui/traits/final/positions.stderr
Normal file
|
|
@ -0,0 +1,187 @@
|
||||||
|
error: a struct cannot be `final`
|
||||||
|
--> $DIR/positions.rs:7:1
|
||||||
|
|
|
||||||
|
LL | final struct Foo {}
|
||||||
|
| ^^^^^ `final` because of this
|
||||||
|
|
|
||||||
|
= note: only associated functions in traits can be `final`
|
||||||
|
|
||||||
|
error: a trait cannot be `final`
|
||||||
|
--> $DIR/positions.rs:10:1
|
||||||
|
|
|
||||||
|
LL | final trait Trait {
|
||||||
|
| ^^^^^ `final` because of this
|
||||||
|
|
|
||||||
|
= note: only associated functions in traits can be `final`
|
||||||
|
|
||||||
|
error: a static item cannot be `final`
|
||||||
|
--> $DIR/positions.rs:67:5
|
||||||
|
|
|
||||||
|
LL | final static FOO_EXTERN: usize = 0;
|
||||||
|
| ^^^^^ `final` because of this
|
||||||
|
|
|
||||||
|
= note: only associated functions in traits can be `final`
|
||||||
|
|
||||||
|
error: an extern block cannot be `final`
|
||||||
|
--> $DIR/positions.rs:58:1
|
||||||
|
|
|
||||||
|
LL | final unsafe extern "C" {
|
||||||
|
| ^^^^^ `final` because of this
|
||||||
|
|
|
||||||
|
= note: only associated functions in traits can be `final`
|
||||||
|
|
||||||
|
error: `final` is only allowed on associated functions in traits
|
||||||
|
--> $DIR/positions.rs:16:5
|
||||||
|
|
|
||||||
|
LL | final type Foo = ();
|
||||||
|
| -----^^^^^^^^^^^^^^^
|
||||||
|
| |
|
||||||
|
| `final` because of this
|
||||||
|
|
||||||
|
error: `final` is only allowed on associated functions in traits
|
||||||
|
--> $DIR/positions.rs:19:5
|
||||||
|
|
|
||||||
|
LL | final const FOO: usize = 1;
|
||||||
|
| -----^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
| |
|
||||||
|
| `final` because of this
|
||||||
|
|
||||||
|
error: `final` is only allowed on associated functions in traits
|
||||||
|
--> $DIR/positions.rs:24:5
|
||||||
|
|
|
||||||
|
LL | final fn method() {}
|
||||||
|
| -----^^^^^^^^^^^^
|
||||||
|
| |
|
||||||
|
| `final` because of this
|
||||||
|
|
||||||
|
error: `final` is only allowed on associated functions in traits
|
||||||
|
--> $DIR/positions.rs:27:5
|
||||||
|
|
|
||||||
|
LL | final type Foo = ();
|
||||||
|
| -----^^^^^^^^^^^^^^^
|
||||||
|
| |
|
||||||
|
| `final` because of this
|
||||||
|
|
||||||
|
error: `final` is only allowed on associated functions in traits
|
||||||
|
--> $DIR/positions.rs:30:5
|
||||||
|
|
|
||||||
|
LL | final const FOO: usize = 1;
|
||||||
|
| -----^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
| |
|
||||||
|
| `final` because of this
|
||||||
|
|
||||||
|
error: `final` is only allowed on associated functions in traits
|
||||||
|
--> $DIR/positions.rs:35:5
|
||||||
|
|
|
||||||
|
LL | final fn method() {}
|
||||||
|
| -----^^^^^^^^^^^^
|
||||||
|
| |
|
||||||
|
| `final` because of this
|
||||||
|
|
||||||
|
error: `final` is only allowed on associated functions in traits
|
||||||
|
--> $DIR/positions.rs:39:5
|
||||||
|
|
|
||||||
|
LL | final type Foo = ();
|
||||||
|
| -----^^^^^^^^^^^^^^^
|
||||||
|
| |
|
||||||
|
| `final` because of this
|
||||||
|
|
||||||
|
error: `final` is only allowed on associated functions in traits
|
||||||
|
--> $DIR/positions.rs:43:5
|
||||||
|
|
|
||||||
|
LL | final const FOO: usize = 1;
|
||||||
|
| -----^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
| |
|
||||||
|
| `final` because of this
|
||||||
|
|
||||||
|
error: `final` is only allowed on associated functions in traits
|
||||||
|
--> $DIR/positions.rs:49:1
|
||||||
|
|
|
||||||
|
LL | final fn foo() {}
|
||||||
|
| -----^^^^^^^^^
|
||||||
|
| |
|
||||||
|
| `final` because of this
|
||||||
|
|
||||||
|
error: `final` is only allowed on associated functions in traits
|
||||||
|
--> $DIR/positions.rs:52:1
|
||||||
|
|
|
||||||
|
LL | final type FooTy = ();
|
||||||
|
| -----^^^^^^^^^^^^^^^^^
|
||||||
|
| |
|
||||||
|
| `final` because of this
|
||||||
|
|
||||||
|
error: `final` is only allowed on associated functions in traits
|
||||||
|
--> $DIR/positions.rs:55:1
|
||||||
|
|
|
||||||
|
LL | final const FOO: usize = 0;
|
||||||
|
| -----^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
| |
|
||||||
|
| `final` because of this
|
||||||
|
|
||||||
|
error: `final` is only allowed on associated functions in traits
|
||||||
|
--> $DIR/positions.rs:61:5
|
||||||
|
|
|
||||||
|
LL | final fn foo_extern();
|
||||||
|
| -----^^^^^^^^^^^^^^^^^
|
||||||
|
| |
|
||||||
|
| `final` because of this
|
||||||
|
|
||||||
|
error: `final` is only allowed on associated functions in traits
|
||||||
|
--> $DIR/positions.rs:64:5
|
||||||
|
|
|
||||||
|
LL | final type FooExtern;
|
||||||
|
| -----^^^^^^^^^^^^^^^^
|
||||||
|
| |
|
||||||
|
| `final` because of this
|
||||||
|
|
||||||
|
error: incorrect `static` inside `extern` block
|
||||||
|
--> $DIR/positions.rs:67:18
|
||||||
|
|
|
||||||
|
LL | final unsafe extern "C" {
|
||||||
|
| ----------------------- `extern` blocks define existing foreign statics and statics inside of them cannot have a body
|
||||||
|
...
|
||||||
|
LL | final static FOO_EXTERN: usize = 0;
|
||||||
|
| ^^^^^^^^^^ - the invalid body
|
||||||
|
| |
|
||||||
|
| cannot have a body
|
||||||
|
|
|
||||||
|
= note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
|
||||||
|
|
||||||
|
error: cannot override `method` because it already has a `final` definition in the trait
|
||||||
|
--> $DIR/positions.rs:35:5
|
||||||
|
|
|
||||||
|
LL | final fn method() {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
note: `method` is marked final here
|
||||||
|
--> $DIR/positions.rs:13:5
|
||||||
|
|
|
||||||
|
LL | final fn method() {}
|
||||||
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: cannot override `Foo` because it already has a `final` definition in the trait
|
||||||
|
--> $DIR/positions.rs:39:5
|
||||||
|
|
|
||||||
|
LL | final type Foo = ();
|
||||||
|
| ^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
note: `Foo` is marked final here
|
||||||
|
--> $DIR/positions.rs:16:5
|
||||||
|
|
|
||||||
|
LL | final type Foo = ();
|
||||||
|
| ^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: cannot override `FOO` because it already has a `final` definition in the trait
|
||||||
|
--> $DIR/positions.rs:43:5
|
||||||
|
|
|
||||||
|
LL | final const FOO: usize = 1;
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
note: `FOO` is marked final here
|
||||||
|
--> $DIR/positions.rs:19:5
|
||||||
|
|
|
||||||
|
LL | final const FOO: usize = 1;
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 21 previous errors
|
||||||
|
|
||||||
13
tests/ui/traits/final/works.rs
Normal file
13
tests/ui/traits/final/works.rs
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
//@ check-pass
|
||||||
|
|
||||||
|
#![feature(final_associated_functions)]
|
||||||
|
|
||||||
|
trait Foo {
|
||||||
|
final fn bar(&self) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Foo for () {}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
().bar();
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue