Auto merge of #148434 - oli-obk:inherent-const-impl, r=fee1-dead
Inherent const impl Some constifications are annoying because we need to repeat `T: Trait` bounds from an impl block on the individual constified `const fn`s as `T: [const] Trait`. We've brainstormed solutions before, and one would be to have separate `const impl` blocks or sth. However the final syntax will look, I decided to just impl this syntax and either have sth nice on nightly to work with or at least move the discussion along. Also interacts with the discussion around `impl const Trait for Type` vs `const impl Trait for Type`, as we may want to use the latter to keep inherent and trait impls in sync (unless we come up with even another scheme). * [ ] rustdoc + tests * [ ] macro stability /regression tests r? `@fee1-dead` cc `@traviscross` `@rust-lang/project-const-traits`
This commit is contained in:
commit
6159a44067
41 changed files with 369 additions and 276 deletions
|
|
@ -3699,6 +3699,7 @@ pub struct TyAlias {
|
|||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub struct Impl {
|
||||
pub generics: Generics,
|
||||
pub constness: Const,
|
||||
pub of_trait: Option<Box<TraitImplHeader>>,
|
||||
pub self_ty: Box<Ty>,
|
||||
pub items: ThinVec<Box<AssocItem>>,
|
||||
|
|
@ -3708,7 +3709,6 @@ pub struct Impl {
|
|||
pub struct TraitImplHeader {
|
||||
pub defaultness: Defaultness,
|
||||
pub safety: Safety,
|
||||
pub constness: Const,
|
||||
pub polarity: ImplPolarity,
|
||||
pub trait_ref: TraitRef,
|
||||
}
|
||||
|
|
@ -4103,9 +4103,9 @@ mod size_asserts {
|
|||
static_assert_size!(GenericArg, 24);
|
||||
static_assert_size!(GenericBound, 88);
|
||||
static_assert_size!(Generics, 40);
|
||||
static_assert_size!(Impl, 64);
|
||||
static_assert_size!(Item, 136);
|
||||
static_assert_size!(ItemKind, 72);
|
||||
static_assert_size!(Impl, 80);
|
||||
static_assert_size!(Item, 152);
|
||||
static_assert_size!(ItemKind, 88);
|
||||
static_assert_size!(LitKind, 24);
|
||||
static_assert_size!(Local, 96);
|
||||
static_assert_size!(MetaItemLit, 40);
|
||||
|
|
@ -4116,7 +4116,7 @@ mod size_asserts {
|
|||
static_assert_size!(PathSegment, 24);
|
||||
static_assert_size!(Stmt, 32);
|
||||
static_assert_size!(StmtKind, 16);
|
||||
static_assert_size!(TraitImplHeader, 80);
|
||||
static_assert_size!(TraitImplHeader, 72);
|
||||
static_assert_size!(Ty, 64);
|
||||
static_assert_size!(TyKind, 40);
|
||||
// tidy-alphabetical-end
|
||||
|
|
|
|||
|
|
@ -934,11 +934,11 @@ macro_rules! common_visitor_and_walkers {
|
|||
}
|
||||
|
||||
impl_walkable!(|&$($mut)? $($lt)? self: Impl, vis: &mut V| {
|
||||
let Impl { generics, of_trait, self_ty, items } = self;
|
||||
let Impl { generics, of_trait, self_ty, items, constness: _ } = self;
|
||||
try_visit!(vis.visit_generics(generics));
|
||||
if let Some(box of_trait) = of_trait {
|
||||
let TraitImplHeader { defaultness, safety, constness, polarity, trait_ref } = of_trait;
|
||||
visit_visitable!($($mut)? vis, defaultness, safety, constness, polarity, trait_ref);
|
||||
let TraitImplHeader { defaultness, safety, polarity, trait_ref } = of_trait;
|
||||
visit_visitable!($($mut)? vis, defaultness, safety, polarity, trait_ref);
|
||||
}
|
||||
try_visit!(vis.visit_ty(self_ty));
|
||||
visit_visitable_with!($($mut)? vis, items, AssocCtxt::Impl { of_trait: of_trait.is_some() });
|
||||
|
|
|
|||
|
|
@ -344,6 +344,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
of_trait,
|
||||
self_ty: ty,
|
||||
items: impl_items,
|
||||
constness,
|
||||
}) => {
|
||||
// Lower the "impl header" first. This ordering is important
|
||||
// for in-band lifetimes! Consider `'a` here:
|
||||
|
|
@ -377,11 +378,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
.arena
|
||||
.alloc_from_iter(impl_items.iter().map(|item| self.lower_impl_item_ref(item)));
|
||||
|
||||
let constness = self.lower_constness(*constness);
|
||||
|
||||
hir::ItemKind::Impl(hir::Impl {
|
||||
generics,
|
||||
of_trait,
|
||||
self_ty: lowered_ty,
|
||||
items: new_impl_items,
|
||||
constness,
|
||||
})
|
||||
}
|
||||
ItemKind::Trait(box Trait {
|
||||
|
|
@ -954,9 +958,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
&mut self,
|
||||
trait_impl_header: &TraitImplHeader,
|
||||
) -> &'hir hir::TraitImplHeader<'hir> {
|
||||
let TraitImplHeader { constness, safety, polarity, defaultness, ref trait_ref } =
|
||||
*trait_impl_header;
|
||||
let constness = self.lower_constness(constness);
|
||||
let TraitImplHeader { safety, polarity, defaultness, ref trait_ref } = *trait_impl_header;
|
||||
let safety = self.lower_safety(safety, hir::Safety::Safe);
|
||||
let polarity = match polarity {
|
||||
ImplPolarity::Positive => ImplPolarity::Positive,
|
||||
|
|
@ -979,7 +981,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
);
|
||||
|
||||
self.arena.alloc(hir::TraitImplHeader {
|
||||
constness,
|
||||
safety,
|
||||
polarity,
|
||||
defaultness,
|
||||
|
|
|
|||
|
|
@ -204,6 +204,11 @@ ast_passes_generic_before_constraints = generic arguments must come before the f
|
|||
|
||||
ast_passes_generic_default_trailing = generic parameters with a default must be trailing
|
||||
|
||||
ast_passes_impl_fn_const =
|
||||
redundant `const` fn marker in const impl
|
||||
.parent_constness = this declares all associated functions implicitly const
|
||||
.label = remove the `const`
|
||||
|
||||
ast_passes_incompatible_features = `{$f1}` and `{$f2}` are incompatible, using them at the same time is not allowed
|
||||
.help = remove one of these features
|
||||
|
||||
|
|
|
|||
|
|
@ -48,15 +48,17 @@ enum SelfSemantic {
|
|||
No,
|
||||
}
|
||||
|
||||
enum TraitOrTraitImpl {
|
||||
enum TraitOrImpl {
|
||||
Trait { vis: Span, constness: Const },
|
||||
TraitImpl { constness: Const, polarity: ImplPolarity, trait_ref_span: Span },
|
||||
Impl { constness: Const },
|
||||
}
|
||||
|
||||
impl TraitOrTraitImpl {
|
||||
impl TraitOrImpl {
|
||||
fn constness(&self) -> Option<Span> {
|
||||
match self {
|
||||
Self::Trait { constness: Const::Yes(span), .. }
|
||||
| Self::Impl { constness: Const::Yes(span), .. }
|
||||
| Self::TraitImpl { constness: Const::Yes(span), .. } => Some(*span),
|
||||
_ => None,
|
||||
}
|
||||
|
|
@ -70,7 +72,7 @@ struct AstValidator<'a> {
|
|||
/// The span of the `extern` in an `extern { ... }` block, if any.
|
||||
extern_mod_span: Option<Span>,
|
||||
|
||||
outer_trait_or_trait_impl: Option<TraitOrTraitImpl>,
|
||||
outer_trait_or_trait_impl: Option<TraitOrImpl>,
|
||||
|
||||
has_proc_macro_decls: bool,
|
||||
|
||||
|
|
@ -93,19 +95,12 @@ struct AstValidator<'a> {
|
|||
}
|
||||
|
||||
impl<'a> AstValidator<'a> {
|
||||
fn with_in_trait_impl(
|
||||
fn with_in_trait_or_impl(
|
||||
&mut self,
|
||||
trait_: Option<(Const, ImplPolarity, &'a TraitRef)>,
|
||||
in_trait_or_impl: Option<TraitOrImpl>,
|
||||
f: impl FnOnce(&mut Self),
|
||||
) {
|
||||
let old = mem::replace(
|
||||
&mut self.outer_trait_or_trait_impl,
|
||||
trait_.map(|(constness, polarity, trait_ref)| TraitOrTraitImpl::TraitImpl {
|
||||
constness,
|
||||
polarity,
|
||||
trait_ref_span: trait_ref.path.span,
|
||||
}),
|
||||
);
|
||||
let old = mem::replace(&mut self.outer_trait_or_trait_impl, in_trait_or_impl);
|
||||
f(self);
|
||||
self.outer_trait_or_trait_impl = old;
|
||||
}
|
||||
|
|
@ -113,7 +108,7 @@ impl<'a> AstValidator<'a> {
|
|||
fn with_in_trait(&mut self, vis: Span, constness: Const, f: impl FnOnce(&mut Self)) {
|
||||
let old = mem::replace(
|
||||
&mut self.outer_trait_or_trait_impl,
|
||||
Some(TraitOrTraitImpl::Trait { vis, constness }),
|
||||
Some(TraitOrImpl::Trait { vis, constness }),
|
||||
);
|
||||
f(self);
|
||||
self.outer_trait_or_trait_impl = old;
|
||||
|
|
@ -247,14 +242,28 @@ impl<'a> AstValidator<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_trait_fn_not_const(&self, constness: Const, parent: &TraitOrTraitImpl) {
|
||||
fn check_impl_fn_not_const(&self, constness: Const, parent_constness: Const) {
|
||||
let Const::Yes(span) = constness else {
|
||||
return;
|
||||
};
|
||||
|
||||
let span = self.sess.source_map().span_extend_while_whitespace(span);
|
||||
|
||||
let Const::Yes(parent_constness) = parent_constness else {
|
||||
return;
|
||||
};
|
||||
|
||||
self.dcx().emit_err(errors::ImplFnConst { span, parent_constness });
|
||||
}
|
||||
|
||||
fn check_trait_fn_not_const(&self, constness: Const, parent: &TraitOrImpl) {
|
||||
let Const::Yes(span) = constness else {
|
||||
return;
|
||||
};
|
||||
|
||||
let const_trait_impl = self.features.const_trait_impl();
|
||||
let make_impl_const_sugg = if const_trait_impl
|
||||
&& let TraitOrTraitImpl::TraitImpl {
|
||||
&& let TraitOrImpl::TraitImpl {
|
||||
constness: Const::No,
|
||||
polarity: ImplPolarity::Positive,
|
||||
trait_ref_span,
|
||||
|
|
@ -269,7 +278,7 @@ impl<'a> AstValidator<'a> {
|
|||
let map = self.sess.source_map();
|
||||
|
||||
let make_trait_const_sugg = if const_trait_impl
|
||||
&& let &TraitOrTraitImpl::Trait { vis, constness: ast::Const::No } = parent
|
||||
&& let &TraitOrImpl::Trait { vis, constness: ast::Const::No } = parent
|
||||
{
|
||||
Some(map.span_extend_while_whitespace(vis).shrink_to_hi())
|
||||
} else {
|
||||
|
|
@ -279,7 +288,7 @@ impl<'a> AstValidator<'a> {
|
|||
let parent_constness = parent.constness();
|
||||
self.dcx().emit_err(errors::TraitFnConst {
|
||||
span,
|
||||
in_impl: matches!(parent, TraitOrTraitImpl::TraitImpl { .. }),
|
||||
in_impl: matches!(parent, TraitOrImpl::TraitImpl { .. }),
|
||||
const_context_label: parent_constness,
|
||||
remove_const_sugg: (
|
||||
map.span_extend_while_whitespace(span),
|
||||
|
|
@ -295,7 +304,7 @@ impl<'a> AstValidator<'a> {
|
|||
});
|
||||
}
|
||||
|
||||
fn check_async_fn_in_const_trait_or_impl(&self, sig: &FnSig, parent: &TraitOrTraitImpl) {
|
||||
fn check_async_fn_in_const_trait_or_impl(&self, sig: &FnSig, parent: &TraitOrImpl) {
|
||||
let Some(const_keyword) = parent.constness() else { return };
|
||||
|
||||
let Some(CoroutineKind::Async { span: async_keyword, .. }) = sig.header.coroutine_kind
|
||||
|
|
@ -305,7 +314,7 @@ impl<'a> AstValidator<'a> {
|
|||
|
||||
self.dcx().emit_err(errors::AsyncFnInConstTraitOrTraitImpl {
|
||||
async_keyword,
|
||||
in_impl: matches!(parent, TraitOrTraitImpl::TraitImpl { .. }),
|
||||
in_impl: matches!(parent, TraitOrImpl::TraitImpl { .. }),
|
||||
const_keyword,
|
||||
});
|
||||
}
|
||||
|
|
@ -1070,14 +1079,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
match &item.kind {
|
||||
ItemKind::Impl(Impl {
|
||||
generics,
|
||||
constness,
|
||||
of_trait:
|
||||
Some(box TraitImplHeader {
|
||||
safety,
|
||||
polarity,
|
||||
defaultness: _,
|
||||
constness,
|
||||
trait_ref: t,
|
||||
}),
|
||||
Some(box TraitImplHeader { safety, polarity, defaultness: _, trait_ref: t }),
|
||||
self_ty,
|
||||
items,
|
||||
}) => {
|
||||
|
|
@ -1105,24 +1109,46 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
self.visit_trait_ref(t);
|
||||
self.visit_ty(self_ty);
|
||||
|
||||
self.with_in_trait_impl(Some((*constness, *polarity, t)), |this| {
|
||||
walk_list!(this, visit_assoc_item, items, AssocCtxt::Impl { of_trait: true });
|
||||
});
|
||||
self.with_in_trait_or_impl(
|
||||
Some(TraitOrImpl::TraitImpl {
|
||||
constness: *constness,
|
||||
polarity: *polarity,
|
||||
trait_ref_span: t.path.span,
|
||||
}),
|
||||
|this| {
|
||||
walk_list!(
|
||||
this,
|
||||
visit_assoc_item,
|
||||
items,
|
||||
AssocCtxt::Impl { of_trait: true }
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
ItemKind::Impl(Impl { generics, of_trait: None, self_ty, items }) => {
|
||||
ItemKind::Impl(Impl { generics, of_trait: None, self_ty, items, constness }) => {
|
||||
self.visit_attrs_vis(&item.attrs, &item.vis);
|
||||
self.visibility_not_permitted(
|
||||
&item.vis,
|
||||
errors::VisibilityNotPermittedNote::IndividualImplItems,
|
||||
);
|
||||
|
||||
self.with_tilde_const(Some(TildeConstReason::Impl { span: item.span }), |this| {
|
||||
this.visit_generics(generics)
|
||||
});
|
||||
let disallowed = matches!(constness, ast::Const::No)
|
||||
.then(|| TildeConstReason::Impl { span: item.span });
|
||||
|
||||
self.with_tilde_const(disallowed, |this| this.visit_generics(generics));
|
||||
|
||||
self.visit_ty(self_ty);
|
||||
self.with_in_trait_impl(None, |this| {
|
||||
walk_list!(this, visit_assoc_item, items, AssocCtxt::Impl { of_trait: false });
|
||||
});
|
||||
self.with_in_trait_or_impl(
|
||||
Some(TraitOrImpl::Impl { constness: *constness }),
|
||||
|this| {
|
||||
walk_list!(
|
||||
this,
|
||||
visit_assoc_item,
|
||||
items,
|
||||
AssocCtxt::Impl { of_trait: false }
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
ItemKind::Fn(
|
||||
func @ box Fn {
|
||||
|
|
@ -1240,7 +1266,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
this.visit_generics(generics);
|
||||
walk_list!(this, visit_param_bound, bounds, BoundKind::SuperTraits)
|
||||
});
|
||||
self.with_in_trait(item.vis.span, *constness, |this| {
|
||||
self.with_in_trait(item.span, *constness, |this| {
|
||||
walk_list!(this, visit_assoc_item, items, AssocCtxt::Trait);
|
||||
});
|
||||
}
|
||||
|
|
@ -1610,7 +1636,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
&& self
|
||||
.outer_trait_or_trait_impl
|
||||
.as_ref()
|
||||
.and_then(TraitOrTraitImpl::constness)
|
||||
.and_then(TraitOrImpl::constness)
|
||||
.is_some();
|
||||
|
||||
let disallowed = (!tilde_const_allowed).then(|| match fk {
|
||||
|
|
@ -1677,12 +1703,23 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
);
|
||||
}
|
||||
|
||||
if let Some(parent) = &self.outer_trait_or_trait_impl {
|
||||
self.visibility_not_permitted(&item.vis, errors::VisibilityNotPermittedNote::TraitImpl);
|
||||
if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind {
|
||||
self.check_trait_fn_not_const(sig.header.constness, parent);
|
||||
self.check_async_fn_in_const_trait_or_impl(sig, parent);
|
||||
match &self.outer_trait_or_trait_impl {
|
||||
Some(parent @ (TraitOrImpl::Trait { .. } | TraitOrImpl::TraitImpl { .. })) => {
|
||||
self.visibility_not_permitted(
|
||||
&item.vis,
|
||||
errors::VisibilityNotPermittedNote::TraitImpl,
|
||||
);
|
||||
if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind {
|
||||
self.check_trait_fn_not_const(sig.header.constness, parent);
|
||||
self.check_async_fn_in_const_trait_or_impl(sig, parent);
|
||||
}
|
||||
}
|
||||
Some(TraitOrImpl::Impl { constness }) => {
|
||||
if let AssocItemKind::Fn(box Fn { sig, .. }) = &item.kind {
|
||||
self.check_impl_fn_not_const(sig.header.constness, *constness);
|
||||
}
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
|
||||
if let AssocItemKind::Const(ci) = &item.kind {
|
||||
|
|
@ -1690,7 +1727,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
}
|
||||
|
||||
let parent_is_const =
|
||||
self.outer_trait_or_trait_impl.as_ref().and_then(TraitOrTraitImpl::constness).is_some();
|
||||
self.outer_trait_or_trait_impl.as_ref().and_then(TraitOrImpl::constness).is_some();
|
||||
|
||||
match &item.kind {
|
||||
AssocItemKind::Fn(func)
|
||||
|
|
@ -1704,19 +1741,23 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
}
|
||||
AssocItemKind::Type(_) => {
|
||||
let disallowed = (!parent_is_const).then(|| match self.outer_trait_or_trait_impl {
|
||||
Some(TraitOrTraitImpl::Trait { .. }) => {
|
||||
Some(TraitOrImpl::Trait { .. }) => {
|
||||
TildeConstReason::TraitAssocTy { span: item.span }
|
||||
}
|
||||
Some(TraitOrTraitImpl::TraitImpl { .. }) => {
|
||||
Some(TraitOrImpl::TraitImpl { .. }) => {
|
||||
TildeConstReason::TraitImplAssocTy { span: item.span }
|
||||
}
|
||||
None => TildeConstReason::InherentAssocTy { span: item.span },
|
||||
Some(TraitOrImpl::Impl { .. }) | None => {
|
||||
TildeConstReason::InherentAssocTy { span: item.span }
|
||||
}
|
||||
});
|
||||
self.with_tilde_const(disallowed, |this| {
|
||||
this.with_in_trait_impl(None, |this| visit::walk_assoc_item(this, item, ctxt))
|
||||
this.with_in_trait_or_impl(None, |this| {
|
||||
visit::walk_assoc_item(this, item, ctxt)
|
||||
})
|
||||
})
|
||||
}
|
||||
_ => self.with_in_trait_impl(None, |this| visit::walk_assoc_item(this, item, ctxt)),
|
||||
_ => self.with_in_trait_or_impl(None, |this| visit::walk_assoc_item(this, item, ctxt)),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,15 @@ pub(crate) enum VisibilityNotPermittedNote {
|
|||
#[note(ast_passes_individual_foreign_items)]
|
||||
IndividualForeignItems,
|
||||
}
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_impl_fn_const)]
|
||||
pub(crate) struct ImplFnConst {
|
||||
#[primary_span]
|
||||
#[suggestion(ast_passes_label, code = "", applicability = "machine-applicable")]
|
||||
pub span: Span,
|
||||
#[label(ast_passes_parent_constness)]
|
||||
pub parent_constness: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_trait_fn_const, code = E0379)]
|
||||
|
|
|
|||
|
|
@ -305,7 +305,7 @@ impl<'a> State<'a> {
|
|||
let (cb, ib) = self.head(visibility_qualified(&item.vis, "union"));
|
||||
self.print_struct(struct_def, generics, *ident, item.span, true, cb, ib);
|
||||
}
|
||||
ast::ItemKind::Impl(ast::Impl { generics, of_trait, self_ty, items }) => {
|
||||
ast::ItemKind::Impl(ast::Impl { generics, of_trait, self_ty, items, constness }) => {
|
||||
let (cb, ib) = self.head("");
|
||||
self.print_visibility(&item.vis);
|
||||
|
||||
|
|
@ -321,17 +321,12 @@ impl<'a> State<'a> {
|
|||
};
|
||||
|
||||
if let Some(box of_trait) = of_trait {
|
||||
let ast::TraitImplHeader {
|
||||
defaultness,
|
||||
safety,
|
||||
constness,
|
||||
polarity,
|
||||
ref trait_ref,
|
||||
} = *of_trait;
|
||||
let ast::TraitImplHeader { defaultness, safety, polarity, ref trait_ref } =
|
||||
*of_trait;
|
||||
self.print_defaultness(defaultness);
|
||||
self.print_safety(safety);
|
||||
impl_generics(self);
|
||||
self.print_constness(constness);
|
||||
self.print_constness(*constness);
|
||||
if let ast::ImplPolarity::Negative(_) = polarity {
|
||||
self.word("!");
|
||||
}
|
||||
|
|
@ -339,6 +334,7 @@ impl<'a> State<'a> {
|
|||
self.space();
|
||||
self.word_space("for");
|
||||
} else {
|
||||
self.print_constness(*constness);
|
||||
impl_generics(self);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -137,9 +137,9 @@ pub(crate) fn expand_deriving_coerce_pointee(
|
|||
safety: ast::Safety::Default,
|
||||
polarity: ast::ImplPolarity::Positive,
|
||||
defaultness: ast::Defaultness::Final,
|
||||
constness: ast::Const::No,
|
||||
trait_ref,
|
||||
})),
|
||||
constness: ast::Const::No,
|
||||
self_ty: self_type.clone(),
|
||||
items: ThinVec::new(),
|
||||
}),
|
||||
|
|
@ -160,9 +160,9 @@ pub(crate) fn expand_deriving_coerce_pointee(
|
|||
safety: ast::Safety::Default,
|
||||
polarity: ast::ImplPolarity::Positive,
|
||||
defaultness: ast::Defaultness::Final,
|
||||
constness: ast::Const::No,
|
||||
trait_ref,
|
||||
})),
|
||||
constness: ast::Const::No,
|
||||
self_ty: self_type.clone(),
|
||||
items: ThinVec::new(),
|
||||
}),
|
||||
|
|
|
|||
|
|
@ -845,13 +845,9 @@ impl<'a> TraitDef<'a> {
|
|||
safety: self.safety,
|
||||
polarity: ast::ImplPolarity::Positive,
|
||||
defaultness: ast::Defaultness::Final,
|
||||
constness: if self.is_const {
|
||||
ast::Const::Yes(DUMMY_SP)
|
||||
} else {
|
||||
ast::Const::No
|
||||
},
|
||||
trait_ref,
|
||||
})),
|
||||
constness: if self.is_const { ast::Const::Yes(DUMMY_SP) } else { ast::Const::No },
|
||||
self_ty: self_type,
|
||||
items: methods.into_iter().chain(associated_types).collect(),
|
||||
}),
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ fn parent_impl_or_trait_constness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::C
|
|||
let parent_id = tcx.local_parent(def_id);
|
||||
match tcx.def_kind(parent_id) {
|
||||
DefKind::Impl { of_trait: true } => tcx.impl_trait_header(parent_id).constness,
|
||||
DefKind::Impl { of_trait: false } => tcx.constness(parent_id),
|
||||
DefKind::Trait => {
|
||||
if tcx.is_const_trait(parent_id.into()) {
|
||||
hir::Constness::Const
|
||||
|
|
@ -30,6 +31,7 @@ fn constness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Constness {
|
|||
hir::Constness::NotConst
|
||||
}
|
||||
hir::Node::Expr(e) if let hir::ExprKind::Closure(c) = e.kind => c.constness,
|
||||
hir::Node::Item(i) if let hir::ItemKind::Impl(impl_) = i.kind => impl_.constness,
|
||||
_ => {
|
||||
if let Some(fn_kind) = node.fn_kind() {
|
||||
if fn_kind.constness() == hir::Constness::Const {
|
||||
|
|
|
|||
|
|
@ -2386,10 +2386,10 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
|
|||
) -> SmallVec<[Box<ast::AssocItem>; 1]> {
|
||||
match ctxt {
|
||||
AssocCtxt::Trait => self.flat_map_node(AstNodeWrapper::new(node, TraitItemTag)),
|
||||
AssocCtxt::Impl { of_trait: false } => {
|
||||
AssocCtxt::Impl { of_trait: false, .. } => {
|
||||
self.flat_map_node(AstNodeWrapper::new(node, ImplItemTag))
|
||||
}
|
||||
AssocCtxt::Impl { of_trait: true } => {
|
||||
AssocCtxt::Impl { of_trait: true, .. } => {
|
||||
self.flat_map_node(AstNodeWrapper::new(node, TraitImplItemTag))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4372,11 +4372,11 @@ pub struct Impl<'hir> {
|
|||
pub of_trait: Option<&'hir TraitImplHeader<'hir>>,
|
||||
pub self_ty: &'hir Ty<'hir>,
|
||||
pub items: &'hir [ImplItemId],
|
||||
pub constness: Constness,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, HashStable_Generic)]
|
||||
pub struct TraitImplHeader<'hir> {
|
||||
pub constness: Constness,
|
||||
pub safety: Safety,
|
||||
pub polarity: ImplPolarity,
|
||||
pub defaultness: Defaultness,
|
||||
|
|
@ -4948,7 +4948,7 @@ mod size_asserts {
|
|||
static_assert_size!(GenericArg<'_>, 16);
|
||||
static_assert_size!(GenericBound<'_>, 64);
|
||||
static_assert_size!(Generics<'_>, 56);
|
||||
static_assert_size!(Impl<'_>, 40);
|
||||
static_assert_size!(Impl<'_>, 48);
|
||||
static_assert_size!(ImplItem<'_>, 88);
|
||||
static_assert_size!(ImplItemKind<'_>, 40);
|
||||
static_assert_size!(Item<'_>, 88);
|
||||
|
|
|
|||
|
|
@ -594,10 +594,9 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::
|
|||
try_visit!(visitor.visit_generics(generics));
|
||||
try_visit!(visitor.visit_enum_def(enum_definition));
|
||||
}
|
||||
ItemKind::Impl(Impl { generics, of_trait, self_ty, items }) => {
|
||||
ItemKind::Impl(Impl { generics, of_trait, self_ty, items, constness: _ }) => {
|
||||
try_visit!(visitor.visit_generics(generics));
|
||||
if let Some(TraitImplHeader {
|
||||
constness: _,
|
||||
safety: _,
|
||||
polarity: _,
|
||||
defaultness: _,
|
||||
|
|
|
|||
|
|
@ -240,7 +240,7 @@ impl Target {
|
|||
AssocItemKind::Const(_) => Target::AssocConst,
|
||||
AssocItemKind::Fn(f) => Target::Method(match assoc_ctxt {
|
||||
AssocCtxt::Trait => MethodKind::Trait { body: f.body.is_some() },
|
||||
AssocCtxt::Impl { of_trait } => {
|
||||
AssocCtxt::Impl { of_trait, .. } => {
|
||||
if of_trait {
|
||||
MethodKind::TraitImpl
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -1346,7 +1346,7 @@ fn impl_trait_header(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::ImplTraitHeader
|
|||
let selfty = tcx.type_of(def_id).instantiate_identity();
|
||||
let is_rustc_reservation = tcx.has_attr(def_id, sym::rustc_reservation_impl);
|
||||
|
||||
check_impl_constness(tcx, of_trait.constness, &of_trait.trait_ref);
|
||||
check_impl_constness(tcx, impl_.constness, &of_trait.trait_ref);
|
||||
|
||||
let trait_ref = icx.lowerer().lower_impl_trait_ref(&of_trait.trait_ref, selfty);
|
||||
|
||||
|
|
@ -1354,7 +1354,7 @@ fn impl_trait_header(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::ImplTraitHeader
|
|||
trait_ref: ty::EarlyBinder::bind(trait_ref),
|
||||
safety: of_trait.safety,
|
||||
polarity: polarity_of_impl(tcx, of_trait, is_rustc_reservation),
|
||||
constness: of_trait.constness,
|
||||
constness: impl_.constness,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -690,7 +690,7 @@ impl<'a> State<'a> {
|
|||
let (cb, ib) = self.head("union");
|
||||
self.print_struct(ident.name, generics, struct_def, item.span, true, cb, ib);
|
||||
}
|
||||
hir::ItemKind::Impl(hir::Impl { generics, of_trait, self_ty, items }) => {
|
||||
hir::ItemKind::Impl(hir::Impl { generics, of_trait, self_ty, items, constness }) => {
|
||||
let (cb, ib) = self.head("");
|
||||
|
||||
let impl_generics = |this: &mut Self| {
|
||||
|
|
@ -702,9 +702,13 @@ impl<'a> State<'a> {
|
|||
};
|
||||
|
||||
match of_trait {
|
||||
None => impl_generics(self),
|
||||
None => {
|
||||
if let hir::Constness::Const = constness {
|
||||
self.word_nbsp("const");
|
||||
}
|
||||
impl_generics(self)
|
||||
}
|
||||
Some(&hir::TraitImplHeader {
|
||||
constness,
|
||||
safety,
|
||||
polarity,
|
||||
defaultness,
|
||||
|
|
|
|||
|
|
@ -1315,7 +1315,11 @@ fn should_encode_fn_sig(def_kind: DefKind) -> bool {
|
|||
|
||||
fn should_encode_constness(def_kind: DefKind) -> bool {
|
||||
match def_kind {
|
||||
DefKind::Fn | DefKind::AssocFn | DefKind::Closure | DefKind::Ctor(_, CtorKind::Fn) => true,
|
||||
DefKind::Fn
|
||||
| DefKind::AssocFn
|
||||
| DefKind::Closure
|
||||
| DefKind::Ctor(_, CtorKind::Fn)
|
||||
| DefKind::Impl { of_trait: false } => true,
|
||||
|
||||
DefKind::Struct
|
||||
| DefKind::Union
|
||||
|
|
|
|||
|
|
@ -2153,6 +2153,7 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
header.constness == hir::Constness::Const
|
||||
&& self.is_const_trait(header.trait_ref.skip_binder().def_id)
|
||||
}
|
||||
DefKind::Impl { of_trait: false } => self.constness(def_id) == hir::Constness::Const,
|
||||
DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn) => {
|
||||
self.constness(def_id) == hir::Constness::Const
|
||||
}
|
||||
|
|
@ -2191,7 +2192,6 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
false
|
||||
}
|
||||
DefKind::Ctor(_, CtorKind::Const)
|
||||
| DefKind::Impl { of_trait: false }
|
||||
| DefKind::Mod
|
||||
| DefKind::Struct
|
||||
| DefKind::Union
|
||||
|
|
|
|||
|
|
@ -250,29 +250,22 @@ impl<'a> Parser<'a> {
|
|||
} else if self.check_keyword(exp!(Trait)) || self.check_trait_front_matter() {
|
||||
// TRAIT ITEM
|
||||
self.parse_item_trait(attrs, lo)?
|
||||
} else if let Const::Yes(const_span) = self.parse_constness(Case::Sensitive) {
|
||||
// CONST ITEM
|
||||
if self.token.is_keyword(kw::Impl) {
|
||||
// recover from `const impl`, suggest `impl const`
|
||||
self.recover_const_impl(const_span, attrs, def_())?
|
||||
} else {
|
||||
self.recover_const_mut(const_span);
|
||||
self.recover_missing_kw_before_item()?;
|
||||
let (ident, generics, ty, rhs) = self.parse_const_item(attrs)?;
|
||||
ItemKind::Const(Box::new(ConstItem {
|
||||
defaultness: def_(),
|
||||
ident,
|
||||
generics,
|
||||
ty,
|
||||
rhs,
|
||||
define_opaque: None,
|
||||
}))
|
||||
}
|
||||
} else if self.check_keyword(exp!(Impl))
|
||||
|| self.check_keyword(exp!(Unsafe)) && self.is_keyword_ahead(1, &[kw::Impl])
|
||||
{
|
||||
} else if self.check_impl_frontmatter() {
|
||||
// IMPL ITEM
|
||||
self.parse_item_impl(attrs, def_())?
|
||||
} else if let Const::Yes(const_span) = self.parse_constness(Case::Sensitive) {
|
||||
// CONST ITEM
|
||||
self.recover_const_mut(const_span);
|
||||
self.recover_missing_kw_before_item()?;
|
||||
let (ident, generics, ty, rhs) = self.parse_const_item(attrs)?;
|
||||
ItemKind::Const(Box::new(ConstItem {
|
||||
defaultness: def_(),
|
||||
ident,
|
||||
generics,
|
||||
ty,
|
||||
rhs,
|
||||
define_opaque: None,
|
||||
}))
|
||||
} else if self.is_reuse_path_item() {
|
||||
self.parse_item_delegation()?
|
||||
} else if self.check_keyword(exp!(Mod))
|
||||
|
|
@ -569,6 +562,7 @@ impl<'a> Parser<'a> {
|
|||
attrs: &mut AttrVec,
|
||||
defaultness: Defaultness,
|
||||
) -> PResult<'a, ItemKind> {
|
||||
let mut constness = self.parse_constness(Case::Sensitive);
|
||||
let safety = self.parse_safety(Case::Sensitive);
|
||||
self.expect_keyword(exp!(Impl))?;
|
||||
|
||||
|
|
@ -583,7 +577,11 @@ impl<'a> Parser<'a> {
|
|||
generics
|
||||
};
|
||||
|
||||
let constness = self.parse_constness(Case::Sensitive);
|
||||
if let Const::No = constness {
|
||||
// FIXME(const_trait_impl): disallow `impl const Trait`
|
||||
constness = self.parse_constness(Case::Sensitive);
|
||||
}
|
||||
|
||||
if let Const::Yes(span) = constness {
|
||||
self.psess.gated_spans.gate(sym::const_trait_impl, span);
|
||||
}
|
||||
|
|
@ -667,13 +665,8 @@ impl<'a> Parser<'a> {
|
|||
};
|
||||
let trait_ref = TraitRef { path, ref_id: ty_first.id };
|
||||
|
||||
let of_trait = Some(Box::new(TraitImplHeader {
|
||||
defaultness,
|
||||
safety,
|
||||
constness,
|
||||
polarity,
|
||||
trait_ref,
|
||||
}));
|
||||
let of_trait =
|
||||
Some(Box::new(TraitImplHeader { defaultness, safety, polarity, trait_ref }));
|
||||
(of_trait, ty_second)
|
||||
}
|
||||
None => {
|
||||
|
|
@ -698,13 +691,13 @@ impl<'a> Parser<'a> {
|
|||
error("default", "default", def_span).emit();
|
||||
}
|
||||
if let Const::Yes(span) = constness {
|
||||
error("const", "const", span).emit();
|
||||
self.psess.gated_spans.gate(sym::const_trait_impl, span);
|
||||
}
|
||||
(None, self_ty)
|
||||
}
|
||||
};
|
||||
|
||||
Ok(ItemKind::Impl(Impl { generics, of_trait, self_ty, items: impl_items }))
|
||||
Ok(ItemKind::Impl(Impl { generics, of_trait, self_ty, items: impl_items, constness }))
|
||||
}
|
||||
|
||||
fn parse_item_delegation(&mut self) -> PResult<'a, ItemKind> {
|
||||
|
|
@ -1359,46 +1352,6 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Recover on `const impl` with `const` already eaten.
|
||||
fn recover_const_impl(
|
||||
&mut self,
|
||||
const_span: Span,
|
||||
attrs: &mut AttrVec,
|
||||
defaultness: Defaultness,
|
||||
) -> PResult<'a, ItemKind> {
|
||||
let impl_span = self.token.span;
|
||||
let err = self.expected_ident_found_err();
|
||||
|
||||
// Only try to recover if this is implementing a trait for a type
|
||||
let mut item_kind = match self.parse_item_impl(attrs, defaultness) {
|
||||
Ok(item_kind) => item_kind,
|
||||
Err(recovery_error) => {
|
||||
// Recovery failed, raise the "expected identifier" error
|
||||
recovery_error.cancel();
|
||||
return Err(err);
|
||||
}
|
||||
};
|
||||
|
||||
match &mut item_kind {
|
||||
ItemKind::Impl(Impl { of_trait: Some(of_trait), .. }) => {
|
||||
of_trait.constness = Const::Yes(const_span);
|
||||
|
||||
let before_trait = of_trait.trait_ref.path.span.shrink_to_lo();
|
||||
let const_up_to_impl = const_span.with_hi(impl_span.lo());
|
||||
err.with_multipart_suggestion(
|
||||
"you might have meant to write a const trait impl",
|
||||
vec![(const_up_to_impl, "".to_owned()), (before_trait, "const ".to_owned())],
|
||||
Applicability::MaybeIncorrect,
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
ItemKind::Impl { .. } => return Err(err),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
Ok(item_kind)
|
||||
}
|
||||
|
||||
/// Parse a static item with the prefix `"static" "mut"?` already parsed and stored in
|
||||
/// `mutability`.
|
||||
///
|
||||
|
|
@ -2624,6 +2577,33 @@ impl<'a> Parser<'a> {
|
|||
Ok(body)
|
||||
}
|
||||
|
||||
fn check_impl_frontmatter(&mut self) -> bool {
|
||||
const ALL_QUALS: &[Symbol] = &[kw::Const, kw::Unsafe];
|
||||
// In contrast to the loop below, this call inserts `impl` into the
|
||||
// list of expected tokens shown in diagnostics.
|
||||
if self.check_keyword(exp!(Impl)) {
|
||||
return true;
|
||||
}
|
||||
let mut i = 0;
|
||||
while i < ALL_QUALS.len() {
|
||||
let action = self.look_ahead(i, |token| {
|
||||
if token.is_keyword(kw::Impl) {
|
||||
return Some(true);
|
||||
}
|
||||
if ALL_QUALS.iter().any(|&qual| token.is_keyword(qual)) {
|
||||
// Ok, we found a legal keyword, keep looking for `impl`
|
||||
return None;
|
||||
}
|
||||
Some(false)
|
||||
});
|
||||
if let Some(ret) = action {
|
||||
return ret;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
self.is_keyword_ahead(i, &[kw::Impl])
|
||||
}
|
||||
|
||||
/// Is the current token the start of an `FnHeader` / not a valid parse?
|
||||
///
|
||||
/// `check_pub` adds additional `pub` to the checks in case users place it
|
||||
|
|
|
|||
|
|
@ -589,7 +589,13 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
|
|||
// For implementations of traits, check the stability of each item
|
||||
// individually as it's possible to have a stable trait with unstable
|
||||
// items.
|
||||
hir::ItemKind::Impl(hir::Impl { of_trait: Some(of_trait), self_ty, items, .. }) => {
|
||||
hir::ItemKind::Impl(hir::Impl {
|
||||
of_trait: Some(of_trait),
|
||||
self_ty,
|
||||
items,
|
||||
constness,
|
||||
..
|
||||
}) => {
|
||||
let features = self.tcx.features();
|
||||
if features.staged_api() {
|
||||
let attrs = self.tcx.hir_attrs(item.hir_id());
|
||||
|
|
@ -652,7 +658,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
|
|||
}
|
||||
|
||||
if features.const_trait_impl()
|
||||
&& let hir::Constness::Const = of_trait.constness
|
||||
&& let hir::Constness::Const = constness
|
||||
{
|
||||
let stable_or_implied_stable = match const_stab {
|
||||
None => true,
|
||||
|
|
@ -696,7 +702,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
if let hir::Constness::Const = of_trait.constness
|
||||
if let hir::Constness::Const = constness
|
||||
&& let Some(def_id) = of_trait.trait_ref.trait_def_id()
|
||||
{
|
||||
// FIXME(const_trait_impl): Improve the span here.
|
||||
|
|
|
|||
|
|
@ -232,6 +232,7 @@ impl<'tcx> LateLintPass<'tcx> for DerivableImpls {
|
|||
of_trait: Some(of_trait),
|
||||
items: [child],
|
||||
self_ty,
|
||||
constness,
|
||||
..
|
||||
}) = item.kind
|
||||
&& !cx.tcx.is_automatically_derived(item.owner_id.to_def_id())
|
||||
|
|
@ -247,7 +248,7 @@ impl<'tcx> LateLintPass<'tcx> for DerivableImpls {
|
|||
&& !attrs.iter().any(|attr| attr.doc_str().is_some())
|
||||
&& cx.tcx.hir_attrs(impl_item_hir).is_empty()
|
||||
{
|
||||
let is_const = of_trait.constness == hir::Constness::Const;
|
||||
let is_const = constness == hir::Constness::Const;
|
||||
if adt_def.is_struct() {
|
||||
check_struct(
|
||||
cx,
|
||||
|
|
|
|||
|
|
@ -495,12 +495,14 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
|
|||
of_trait: lot,
|
||||
self_ty: lst,
|
||||
items: li,
|
||||
constness: lc,
|
||||
}),
|
||||
Impl(ast::Impl {
|
||||
generics: rg,
|
||||
of_trait: rot,
|
||||
self_ty: rst,
|
||||
items: ri,
|
||||
constness: rc,
|
||||
}),
|
||||
) => {
|
||||
eq_generics(lg, rg)
|
||||
|
|
@ -508,7 +510,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
|
|||
matches!(l.safety, Safety::Default) == matches!(r.safety, Safety::Default)
|
||||
&& matches!(l.polarity, ImplPolarity::Positive) == matches!(r.polarity, ImplPolarity::Positive)
|
||||
&& eq_defaultness(l.defaultness, r.defaultness)
|
||||
&& matches!(l.constness, ast::Const::No) == matches!(r.constness, ast::Const::No)
|
||||
&& matches!(lc, ast::Const::No) == matches!(rc, ast::Const::No)
|
||||
&& eq_path(&l.trait_ref.path, &r.trait_ref.path)
|
||||
})
|
||||
&& eq_ty(lst, rst)
|
||||
|
|
|
|||
|
|
@ -961,6 +961,7 @@ fn format_impl_ref_and_type(
|
|||
of_trait,
|
||||
self_ty,
|
||||
items: _,
|
||||
constness,
|
||||
} = iimpl;
|
||||
let mut result = String::with_capacity(128);
|
||||
|
||||
|
|
@ -969,6 +970,8 @@ fn format_impl_ref_and_type(
|
|||
if let Some(of_trait) = of_trait.as_deref() {
|
||||
result.push_str(format_defaultness(of_trait.defaultness));
|
||||
result.push_str(format_safety(of_trait.safety));
|
||||
} else {
|
||||
result.push_str(format_constness_right(*constness));
|
||||
}
|
||||
|
||||
let shape = if context.config.style_edition() >= StyleEdition::Edition2024 {
|
||||
|
|
@ -985,7 +988,7 @@ fn format_impl_ref_and_type(
|
|||
|
||||
let trait_ref_overhead;
|
||||
if let Some(of_trait) = of_trait.as_deref() {
|
||||
result.push_str(format_constness_right(of_trait.constness));
|
||||
result.push_str(format_constness_right(*constness));
|
||||
let polarity_str = match of_trait.polarity {
|
||||
ast::ImplPolarity::Negative(_) => "!",
|
||||
ast::ImplPolarity::Positive => "",
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
trait T { const
|
||||
impl //~ ERROR: expected identifier, found keyword `impl`
|
||||
}
|
||||
trait T {
|
||||
const //~ ERROR: const trait impls are experimental
|
||||
impl
|
||||
} //~ ERROR: expected type, found `}`
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,25 @@
|
|||
error: expected identifier, found keyword `impl`
|
||||
error: expected type, found `}`
|
||||
--> $DIR/issue-81806.rs:4:1
|
||||
|
|
||||
LL | trait T {
|
||||
| - while parsing this item list starting here
|
||||
...
|
||||
LL | }
|
||||
| ^
|
||||
| |
|
||||
| expected type
|
||||
| the item list ends here
|
||||
|
||||
error[E0658]: const trait impls are experimental
|
||||
--> $DIR/issue-81806.rs:2:1
|
||||
|
|
||||
LL | trait T { const
|
||||
| - while parsing this item list starting here
|
||||
LL | impl
|
||||
| ^^^^ expected identifier, found keyword
|
||||
LL | }
|
||||
| - the item list ends here
|
||||
LL | const
|
||||
| ^^^^^
|
||||
|
|
||||
help: escape `impl` to use it as an identifier
|
||||
|
|
||||
LL | r#impl
|
||||
| ++
|
||||
= note: see issue #143874 <https://github.com/rust-lang/rust/issues/143874> for more information
|
||||
= help: add `#![feature(const_trait_impl)]` 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
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
||||
|
|
|
|||
|
|
@ -2,14 +2,14 @@ ast-stats ================================================================
|
|||
ast-stats POST EXPANSION AST STATS: input_stats
|
||||
ast-stats Name Accumulated Size Count Item Size
|
||||
ast-stats ----------------------------------------------------------------
|
||||
ast-stats Item 1_496 (NN.N%) 11 136
|
||||
ast-stats - Enum 136 (NN.N%) 1
|
||||
ast-stats - ExternCrate 136 (NN.N%) 1
|
||||
ast-stats - ForeignMod 136 (NN.N%) 1
|
||||
ast-stats - Impl 136 (NN.N%) 1
|
||||
ast-stats - Trait 136 (NN.N%) 1
|
||||
ast-stats - Fn 272 (NN.N%) 2
|
||||
ast-stats - Use 544 (NN.N%) 4
|
||||
ast-stats Item 1_672 (NN.N%) 11 152
|
||||
ast-stats - Enum 152 (NN.N%) 1
|
||||
ast-stats - ExternCrate 152 (NN.N%) 1
|
||||
ast-stats - ForeignMod 152 (NN.N%) 1
|
||||
ast-stats - Impl 152 (NN.N%) 1
|
||||
ast-stats - Trait 152 (NN.N%) 1
|
||||
ast-stats - Fn 304 (NN.N%) 2
|
||||
ast-stats - Use 608 (NN.N%) 4
|
||||
ast-stats Ty 896 (NN.N%) 14 64
|
||||
ast-stats - Ptr 64 (NN.N%) 1
|
||||
ast-stats - Ref 64 (NN.N%) 1
|
||||
|
|
@ -57,7 +57,7 @@ ast-stats GenericArgs 40 (NN.N%) 1 40
|
|||
ast-stats - AngleBracketed 40 (NN.N%) 1
|
||||
ast-stats Crate 40 (NN.N%) 1 40
|
||||
ast-stats ----------------------------------------------------------------
|
||||
ast-stats Total 7_440 129
|
||||
ast-stats Total 7_616 129
|
||||
ast-stats ================================================================
|
||||
hir-stats ================================================================
|
||||
hir-stats HIR STATS: input_stats
|
||||
|
|
|
|||
24
tests/ui/traits/const-traits/const-impl-inherent-bounds.rs
Normal file
24
tests/ui/traits/const-traits/const-impl-inherent-bounds.rs
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
#![feature(const_trait_impl)]
|
||||
//! Test that we can actually use `[const] Trait` bounds written on the impl block
|
||||
|
||||
//@ check-pass
|
||||
|
||||
struct Foo<T>(T);
|
||||
|
||||
const trait Trait {
|
||||
fn method() {}
|
||||
}
|
||||
|
||||
const impl Trait for () {}
|
||||
|
||||
const impl<T: [const] Trait> Foo<T> {
|
||||
fn bar() {
|
||||
T::method();
|
||||
}
|
||||
}
|
||||
|
||||
const _: () = Foo::<()>::bar();
|
||||
|
||||
fn main() {
|
||||
Foo::<()>::bar();
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
//@run-rustfix
|
||||
|
||||
#![feature(const_trait_impl)]
|
||||
struct Foo;
|
||||
|
||||
const impl Foo {
|
||||
fn bar() {}
|
||||
fn baz() {}
|
||||
//~^ ERROR: redundant `const`
|
||||
}
|
||||
|
||||
const _: () = {
|
||||
Foo::bar();
|
||||
Foo::baz();
|
||||
};
|
||||
|
||||
fn main() {
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
//@run-rustfix
|
||||
|
||||
#![feature(const_trait_impl)]
|
||||
struct Foo;
|
||||
|
||||
const impl Foo {
|
||||
fn bar() {}
|
||||
const fn baz() {}
|
||||
//~^ ERROR: redundant `const`
|
||||
}
|
||||
|
||||
const _: () = {
|
||||
Foo::bar();
|
||||
Foo::baz();
|
||||
};
|
||||
|
||||
fn main() {
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
error: redundant `const` fn marker in const impl
|
||||
--> $DIR/const-impl-inherent-double-const.rs:8:5
|
||||
|
|
||||
LL | const impl Foo {
|
||||
| ----- this declares all associated functions implicitly const
|
||||
LL | fn bar() {}
|
||||
LL | const fn baz() {}
|
||||
| ^^^^^^ help: remove the `const`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
15
tests/ui/traits/const-traits/const-impl-inherent.rs
Normal file
15
tests/ui/traits/const-traits/const-impl-inherent.rs
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
#![feature(const_trait_impl)]
|
||||
|
||||
//@ check-pass
|
||||
|
||||
struct Foo;
|
||||
|
||||
const impl Foo {
|
||||
fn bar() {}
|
||||
}
|
||||
|
||||
const _: () = Foo::bar();
|
||||
|
||||
fn main() {
|
||||
Foo::bar();
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
#![feature(const_trait_impl)]
|
||||
|
||||
struct Foo;
|
||||
|
||||
const impl Foo { //~ ERROR: expected identifier, found keyword
|
||||
fn bar() {}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// shouldn't error here because we shouldn't have been able to recover above
|
||||
Foo::bar();
|
||||
}
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
error: expected identifier, found keyword `impl`
|
||||
--> $DIR/const-impl-norecover.rs:5:7
|
||||
|
|
||||
LL | const impl Foo {
|
||||
| ^^^^ expected identifier, found keyword
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
|
|
@ -1,12 +1,14 @@
|
|||
#![feature(const_trait_impl)]
|
||||
|
||||
//@ check-pass
|
||||
|
||||
const trait Foo {}
|
||||
|
||||
const impl Foo for i32 {} //~ ERROR: expected identifier, found keyword
|
||||
const impl Foo for i32 {}
|
||||
|
||||
const trait Bar {}
|
||||
|
||||
const impl<T: Foo> Bar for T {} //~ ERROR: expected identifier, found keyword
|
||||
const impl<T: Foo> Bar for T {}
|
||||
|
||||
const fn still_implements<T: Bar>() {}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,26 +0,0 @@
|
|||
error: expected identifier, found keyword `impl`
|
||||
--> $DIR/const-impl-recovery.rs:5:7
|
||||
|
|
||||
LL | const impl Foo for i32 {}
|
||||
| ^^^^ expected identifier, found keyword
|
||||
|
|
||||
help: you might have meant to write a const trait impl
|
||||
|
|
||||
LL - const impl Foo for i32 {}
|
||||
LL + impl const Foo for i32 {}
|
||||
|
|
||||
|
||||
error: expected identifier, found keyword `impl`
|
||||
--> $DIR/const-impl-recovery.rs:9:7
|
||||
|
|
||||
LL | const impl<T: Foo> Bar for T {}
|
||||
| ^^^^ expected identifier, found keyword
|
||||
|
|
||||
help: you might have meant to write a const trait impl
|
||||
|
|
||||
LL - const impl<T: Foo> Bar for T {}
|
||||
LL + impl<T: Foo> const Bar for T {}
|
||||
|
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
#![feature(const_trait_impl)]
|
||||
|
||||
//@check-pass
|
||||
|
||||
const trait Foo {}
|
||||
|
||||
const impl Foo for i32 {}
|
||||
|
||||
const trait Bar {}
|
||||
|
||||
const impl<T: Foo> Bar for T {}
|
||||
|
||||
const fn still_implements<T: Bar>() {}
|
||||
|
||||
const _: () = still_implements::<i32>();
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -1,13 +1,13 @@
|
|||
#![feature(const_trait_impl)]
|
||||
#![allow(bare_trait_objects)]
|
||||
|
||||
//@ check-pass
|
||||
|
||||
struct S;
|
||||
trait T {}
|
||||
|
||||
impl const S {}
|
||||
//~^ ERROR inherent impls cannot be const
|
||||
|
||||
impl const dyn T {}
|
||||
//~^ ERROR inherent impls cannot be const
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -1,22 +0,0 @@
|
|||
error: inherent impls cannot be const
|
||||
--> $DIR/inherent-impl.rs:7:12
|
||||
|
|
||||
LL | impl const S {}
|
||||
| ----- ^ inherent impl for this type
|
||||
| |
|
||||
| const because of this
|
||||
|
|
||||
= note: only trait implementations may be annotated with `const`
|
||||
|
||||
error: inherent impls cannot be const
|
||||
--> $DIR/inherent-impl.rs:10:12
|
||||
|
|
||||
LL | impl const dyn T {}
|
||||
| ----- ^^^^^ inherent impl for this type
|
||||
| |
|
||||
| const because of this
|
||||
|
|
||||
= note: only trait implementations may be annotated with `const`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
@ -4,10 +4,10 @@ struct S;
|
|||
trait T {}
|
||||
|
||||
impl const dyn T {
|
||||
//~^ ERROR inherent impls cannot be const
|
||||
pub const fn new() -> std::sync::Mutex<dyn T> {}
|
||||
//~^ ERROR mismatched types
|
||||
//~| ERROR cannot be known at compilation time
|
||||
//~| ERROR redundant `const` fn marker in const impl
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,13 @@
|
|||
error: inherent impls cannot be const
|
||||
--> $DIR/span-bug-issue-121418.rs:6:12
|
||||
error: redundant `const` fn marker in const impl
|
||||
--> $DIR/span-bug-issue-121418.rs:7:9
|
||||
|
|
||||
LL | impl const dyn T {
|
||||
| ----- ^^^^^ inherent impl for this type
|
||||
| |
|
||||
| const because of this
|
||||
|
|
||||
= note: only trait implementations may be annotated with `const`
|
||||
| ----- this declares all associated functions implicitly const
|
||||
LL | pub const fn new() -> std::sync::Mutex<dyn T> {}
|
||||
| ^^^^^^ help: remove the `const`
|
||||
|
||||
error[E0277]: the size for values of type `(dyn T + 'static)` cannot be known at compilation time
|
||||
--> $DIR/span-bug-issue-121418.rs:8:27
|
||||
--> $DIR/span-bug-issue-121418.rs:7:27
|
||||
|
|
||||
LL | pub const fn new() -> std::sync::Mutex<dyn T> {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
||||
|
|
@ -20,7 +18,7 @@ note: required because it appears within the type `std::sync::Mutex<(dyn T + 'st
|
|||
= note: the return type of a function must have a statically known size
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/span-bug-issue-121418.rs:8:27
|
||||
--> $DIR/span-bug-issue-121418.rs:7:27
|
||||
|
|
||||
LL | pub const fn new() -> std::sync::Mutex<dyn T> {}
|
||||
| --- ^^^^^^^^^^^^^^^^^^^^^^^ expected `Mutex<dyn T>`, found `()`
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ LL + fn fun();
|
|||
|
|
||||
help: ... and declare the trait to be const instead
|
||||
|
|
||||
LL | const trait NonConst {
|
||||
LL | const fn main() {}
|
||||
| +++++
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue