mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-24 12:54:00 +00:00
Auto merge of #113522 - fmease:generic-consts, r=cjgillot
Implement generic const items
This implements generic parameters and where-clauses on free and associated const items under the experimental feature gate `generic_const_items`. See rust-lang/lang-team#214.
Tracking issue: #113521.
Fixes #104400.
This PR doesn't include rustfmt support as per [nightly style procedure](https://github.com/rust-lang/style-team/blob/master/nightly-style-procedure.md) and it doesn't add rustdoc JSON support (see [related Zulip topic](https://rust-lang.zulipchat.com/#narrow/stream/266220-rustdoc/topic/Rustdoc.20JSON.3A.20Experimental.20rustc.20features)).
CC `@scottmcm` `@compiler-errors` `@WalterSmuts`
r? `@oli-obk`
<details><summary>Resolved Questions</summary>
* Q: Should `const ADD<const N: usize, const M: usize>: usize = N + M; ADD::<0, 1>` trigger the error *generic parameters may not be used in const operations* (which can be unlocked with `#![feature(generic_const_exprs)]`). Currently it doesn't. Or does this fall under [this paragraph](71f71a5397/compiler/rustc_resolve/src/late.rs (L191)
)?
* A: No, https://github.com/rust-lang/rust/pull/113522#issuecomment-1628634092
* Q: Should `const UNUSED: () = () where String: Copy;` (with `#![feature(trivial_bounds)]` and with `UNUSED` unused) succeed compilation? Currently it doesn't: *evaluation of constant value failed // entering unreachable code*
* A: Yes, but postponed until stabilization (latest), https://github.com/rust-lang/rust/pull/113522#issuecomment-1628634092
</details>
This commit is contained in:
commit
04abc370b9
compiler
rustc_ast/src
rustc_ast_lowering/src
rustc_ast_passes/src
rustc_ast_pretty/src/pprust/state
rustc_builtin_macros/src
rustc_expand/src
rustc_feature/src
rustc_hir/src
rustc_hir_analysis/src
rustc_hir_pretty/src
rustc_hir_typeck/src
rustc_infer/src/infer/error_reporting
rustc_lint/src
rustc_middle/src/hir/map
rustc_mir_build/src/build
rustc_parse
rustc_passes/src
rustc_resolve/src
rustc_span/src
rustc_trait_selection/src/traits/error_reporting
src
librustdoc
tools
clippy
clippy_lints/src
clippy_utils/src
tidy/src
tests
rustdoc
ui
generic-const-items
associated-const-equality.rsbasic.rscompare-impl-item.rscompare-impl-item.stderrconst-trait-impl.rsduplicate-where-clause.rsduplicate-where-clause.stderrelided-lifetimes.rselided-lifetimes.stderrevaluatable-bounds.rsevaluatable-bounds.unconstrained.stderrfeature-gate-generic_const_items.rsfeature-gate-generic_const_items.stderrinference-failure.rsinference-failure.stderrmisplaced-where-clause.fixedmisplaced-where-clause.rsmisplaced-where-clause.stderrparameter-defaults.rsparameter-defaults.stderrrecursive.rstrivially-unsatisfied-bounds-0.rstrivially-unsatisfied-bounds-0.stderrtrivially-unsatisfied-bounds-1.rstrivially-unsatisfied-bounds-1.stderrunsatisfied-bounds.rsunsatisfied-bounds.stderrunsatisfied-evaluatable-bounds.rsunsatisfied-evaluatable-bounds.stderrunsatisfied-outlives-bounds.rsunsatisfied-outlives-bounds.stderr
object-safety
assoc_const_bounds.rsassoc_const_bounds.stderrassoc_const_bounds_sized.rsassoc_const_bounds_sized.stderr
parser
suggestions
@ -2947,6 +2947,7 @@ pub struct StaticItem {
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub struct ConstItem {
|
||||
pub defaultness: Defaultness,
|
||||
pub generics: Generics,
|
||||
pub ty: P<Ty>,
|
||||
pub expr: Option<P<Expr>>,
|
||||
}
|
||||
@ -3058,6 +3059,7 @@ impl ItemKind {
|
||||
match self {
|
||||
Self::Fn(box Fn { generics, .. })
|
||||
| Self::TyAlias(box TyAlias { generics, .. })
|
||||
| Self::Const(box ConstItem { generics, .. })
|
||||
| Self::Enum(_, generics)
|
||||
| Self::Struct(_, generics)
|
||||
| Self::Union(_, generics)
|
||||
|
@ -1149,10 +1149,11 @@ pub fn noop_flat_map_assoc_item<T: MutVisitor>(
|
||||
}
|
||||
|
||||
fn visit_const_item<T: MutVisitor>(
|
||||
ConstItem { defaultness, ty, expr }: &mut ConstItem,
|
||||
ConstItem { defaultness, generics, ty, expr }: &mut ConstItem,
|
||||
visitor: &mut T,
|
||||
) {
|
||||
visit_defaultness(defaultness, visitor);
|
||||
visitor.visit_generics(generics);
|
||||
visitor.visit_ty(ty);
|
||||
visit_opt(expr, |expr| visitor.visit_expr(expr));
|
||||
}
|
||||
|
@ -308,8 +308,12 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) {
|
||||
match &item.kind {
|
||||
ItemKind::ExternCrate(_) => {}
|
||||
ItemKind::Use(use_tree) => visitor.visit_use_tree(use_tree, item.id, false),
|
||||
ItemKind::Static(box StaticItem { ty, mutability: _, expr })
|
||||
| ItemKind::Const(box ConstItem { ty, expr, .. }) => {
|
||||
ItemKind::Static(box StaticItem { ty, mutability: _, expr }) => {
|
||||
visitor.visit_ty(ty);
|
||||
walk_list!(visitor, visit_expr, expr);
|
||||
}
|
||||
ItemKind::Const(box ConstItem { defaultness: _, generics, ty, expr }) => {
|
||||
visitor.visit_generics(generics);
|
||||
visitor.visit_ty(ty);
|
||||
walk_list!(visitor, visit_expr, expr);
|
||||
}
|
||||
@ -677,7 +681,8 @@ pub fn walk_assoc_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a AssocItem,
|
||||
visitor.visit_ident(ident);
|
||||
walk_list!(visitor, visit_attribute, attrs);
|
||||
match kind {
|
||||
AssocItemKind::Const(box ConstItem { ty, expr, .. }) => {
|
||||
AssocItemKind::Const(box ConstItem { defaultness: _, generics, ty, expr }) => {
|
||||
visitor.visit_generics(generics);
|
||||
visitor.visit_ty(ty);
|
||||
walk_list!(visitor, visit_expr, expr);
|
||||
}
|
||||
|
@ -231,9 +231,15 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
let (ty, body_id) = self.lower_const_item(t, span, e.as_deref());
|
||||
hir::ItemKind::Static(ty, *m, body_id)
|
||||
}
|
||||
ItemKind::Const(box ast::ConstItem { ty, expr, .. }) => {
|
||||
let (ty, body_id) = self.lower_const_item(ty, span, expr.as_deref());
|
||||
hir::ItemKind::Const(ty, body_id)
|
||||
ItemKind::Const(box ast::ConstItem { generics, ty, expr, .. }) => {
|
||||
let (generics, (ty, body_id)) = self.lower_generics(
|
||||
generics,
|
||||
Const::No,
|
||||
id,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
|this| this.lower_const_item(ty, span, expr.as_deref()),
|
||||
);
|
||||
hir::ItemKind::Const(ty, generics, body_id)
|
||||
}
|
||||
ItemKind::Fn(box Fn {
|
||||
sig: FnSig { decl, header, span: fn_sig_span },
|
||||
@ -715,11 +721,23 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
let trait_item_def_id = hir_id.expect_owner();
|
||||
|
||||
let (generics, kind, has_default) = match &i.kind {
|
||||
AssocItemKind::Const(box ConstItem { ty, expr, .. }) => {
|
||||
let ty =
|
||||
self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy));
|
||||
let body = expr.as_ref().map(|x| self.lower_const_body(i.span, Some(x)));
|
||||
(hir::Generics::empty(), hir::TraitItemKind::Const(ty, body), body.is_some())
|
||||
AssocItemKind::Const(box ConstItem { generics, ty, expr, .. }) => {
|
||||
let (generics, kind) = self.lower_generics(
|
||||
&generics,
|
||||
Const::No,
|
||||
i.id,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
|this| {
|
||||
let ty = this.lower_ty(
|
||||
ty,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy),
|
||||
);
|
||||
let body = expr.as_ref().map(|x| this.lower_const_body(i.span, Some(x)));
|
||||
|
||||
hir::TraitItemKind::Const(ty, body)
|
||||
},
|
||||
);
|
||||
(generics, kind, expr.is_some())
|
||||
}
|
||||
AssocItemKind::Fn(box Fn { sig, generics, body: None, .. }) => {
|
||||
let asyncness = sig.header.asyncness;
|
||||
@ -817,14 +835,19 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
self.lower_attrs(hir_id, &i.attrs);
|
||||
|
||||
let (generics, kind) = match &i.kind {
|
||||
AssocItemKind::Const(box ConstItem { ty, expr, .. }) => {
|
||||
let ty =
|
||||
self.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy));
|
||||
(
|
||||
hir::Generics::empty(),
|
||||
hir::ImplItemKind::Const(ty, self.lower_const_body(i.span, expr.as_deref())),
|
||||
)
|
||||
}
|
||||
AssocItemKind::Const(box ConstItem { generics, ty, expr, .. }) => self.lower_generics(
|
||||
&generics,
|
||||
Const::No,
|
||||
i.id,
|
||||
&ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|
||||
|this| {
|
||||
let ty = this
|
||||
.lower_ty(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy));
|
||||
let body = this.lower_const_body(i.span, expr.as_deref());
|
||||
|
||||
hir::ImplItemKind::Const(ty, body)
|
||||
},
|
||||
),
|
||||
AssocItemKind::Fn(box Fn { sig, generics, body, .. }) => {
|
||||
self.current_item = Some(i.span);
|
||||
let asyncness = sig.header.asyncness;
|
||||
|
@ -569,6 +569,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
|
||||
gate_all!(const_closures, "const closures are experimental");
|
||||
gate_all!(builtin_syntax, "`builtin #` syntax is unstable");
|
||||
gate_all!(explicit_tail_calls, "`become` expression is experimental");
|
||||
gate_all!(generic_const_items, "generic const items are experimental");
|
||||
|
||||
if !visitor.features.negative_bounds {
|
||||
for &span in spans.get(&sym::negative_bounds).iter().copied().flatten() {
|
||||
|
@ -30,10 +30,15 @@ impl<'a> State<'a> {
|
||||
ast::ForeignItemKind::Fn(box ast::Fn { defaultness, sig, generics, body }) => {
|
||||
self.print_fn_full(sig, ident, generics, vis, *defaultness, body.as_deref(), attrs);
|
||||
}
|
||||
ast::ForeignItemKind::Static(ty, mutbl, body) => {
|
||||
let def = ast::Defaultness::Final;
|
||||
self.print_item_const(ident, Some(*mutbl), ty, body.as_deref(), vis, def);
|
||||
}
|
||||
ast::ForeignItemKind::Static(ty, mutbl, body) => self.print_item_const(
|
||||
ident,
|
||||
Some(*mutbl),
|
||||
&ast::Generics::default(),
|
||||
ty,
|
||||
body.as_deref(),
|
||||
vis,
|
||||
ast::Defaultness::Final,
|
||||
),
|
||||
ast::ForeignItemKind::TyAlias(box ast::TyAlias {
|
||||
defaultness,
|
||||
generics,
|
||||
@ -67,6 +72,7 @@ impl<'a> State<'a> {
|
||||
&mut self,
|
||||
ident: Ident,
|
||||
mutbl: Option<ast::Mutability>,
|
||||
generics: &ast::Generics,
|
||||
ty: &ast::Ty,
|
||||
body: Option<&ast::Expr>,
|
||||
vis: &ast::Visibility,
|
||||
@ -82,6 +88,7 @@ impl<'a> State<'a> {
|
||||
};
|
||||
self.word_space(leading);
|
||||
self.print_ident(ident);
|
||||
self.print_generic_params(&generics.params);
|
||||
self.word_space(":");
|
||||
self.print_type(ty);
|
||||
if body.is_some() {
|
||||
@ -92,6 +99,7 @@ impl<'a> State<'a> {
|
||||
self.word_space("=");
|
||||
self.print_expr(body);
|
||||
}
|
||||
self.print_where_clause(&generics.where_clause);
|
||||
self.word(";");
|
||||
self.end(); // end the outer cbox
|
||||
}
|
||||
@ -158,20 +166,21 @@ impl<'a> State<'a> {
|
||||
self.word(";");
|
||||
}
|
||||
ast::ItemKind::Static(box StaticItem { ty, mutability: mutbl, expr: body }) => {
|
||||
let def = ast::Defaultness::Final;
|
||||
self.print_item_const(
|
||||
item.ident,
|
||||
Some(*mutbl),
|
||||
&ast::Generics::default(),
|
||||
ty,
|
||||
body.as_deref(),
|
||||
&item.vis,
|
||||
def,
|
||||
ast::Defaultness::Final,
|
||||
);
|
||||
}
|
||||
ast::ItemKind::Const(box ast::ConstItem { defaultness, ty, expr }) => {
|
||||
ast::ItemKind::Const(box ast::ConstItem { defaultness, generics, ty, expr }) => {
|
||||
self.print_item_const(
|
||||
item.ident,
|
||||
None,
|
||||
generics,
|
||||
ty,
|
||||
expr.as_deref(),
|
||||
&item.vis,
|
||||
@ -515,8 +524,16 @@ impl<'a> State<'a> {
|
||||
ast::AssocItemKind::Fn(box ast::Fn { defaultness, sig, generics, body }) => {
|
||||
self.print_fn_full(sig, ident, generics, vis, *defaultness, body.as_deref(), attrs);
|
||||
}
|
||||
ast::AssocItemKind::Const(box ast::ConstItem { defaultness, ty, expr }) => {
|
||||
self.print_item_const(ident, None, ty, expr.as_deref(), vis, *defaultness);
|
||||
ast::AssocItemKind::Const(box ast::ConstItem { defaultness, generics, ty, expr }) => {
|
||||
self.print_item_const(
|
||||
ident,
|
||||
None,
|
||||
generics,
|
||||
ty,
|
||||
expr.as_deref(),
|
||||
vis,
|
||||
*defaultness,
|
||||
);
|
||||
}
|
||||
ast::AssocItemKind::Type(box ast::TyAlias {
|
||||
defaultness,
|
||||
|
@ -255,6 +255,7 @@ pub fn expand_test_or_bench(
|
||||
ast::ItemKind::Const(
|
||||
ast::ConstItem {
|
||||
defaultness: ast::Defaultness::Final,
|
||||
generics: ast::Generics::default(),
|
||||
ty: cx.ty(sp, ast::TyKind::Path(None, test_path("TestDescAndFn"))),
|
||||
// test::TestDescAndFn {
|
||||
expr: Some(
|
||||
|
@ -643,7 +643,16 @@ impl<'a> ExtCtxt<'a> {
|
||||
span,
|
||||
name,
|
||||
AttrVec::new(),
|
||||
ast::ItemKind::Const(ast::ConstItem { defaultness, ty, expr: Some(expr) }.into()),
|
||||
ast::ItemKind::Const(
|
||||
ast::ConstItem {
|
||||
defaultness,
|
||||
// FIXME(generic_const_items): Pass the generics as a parameter.
|
||||
generics: ast::Generics::default(),
|
||||
ty,
|
||||
expr: Some(expr),
|
||||
}
|
||||
.into(),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -424,6 +424,8 @@ declare_features! (
|
||||
(incomplete, generic_associated_types_extended, "1.61.0", Some(95451), None),
|
||||
/// Allows non-trivial generic constants which have to have wfness manually propagated to callers
|
||||
(incomplete, generic_const_exprs, "1.56.0", Some(76560), None),
|
||||
/// Allows generic parameters and where-clauses on free & associated const items.
|
||||
(incomplete, generic_const_items, "CURRENT_RUSTC_VERSION", Some(113521), None),
|
||||
/// Allows using `..=X` as a patterns in slices.
|
||||
(active, half_open_range_patterns_in_slices, "1.66.0", Some(67264), None),
|
||||
/// Allows `if let` guard in match arms.
|
||||
|
@ -3130,9 +3130,9 @@ impl<'hir> Item<'hir> {
|
||||
}
|
||||
/// Expect an [`ItemKind::Const`] or panic.
|
||||
#[track_caller]
|
||||
pub fn expect_const(&self) -> (&'hir Ty<'hir>, BodyId) {
|
||||
let ItemKind::Const(ty, body) = self.kind else { self.expect_failed("a constant") };
|
||||
(ty, body)
|
||||
pub fn expect_const(&self) -> (&'hir Ty<'hir>, &'hir Generics<'hir>, BodyId) {
|
||||
let ItemKind::Const(ty, gen, body) = self.kind else { self.expect_failed("a constant") };
|
||||
(ty, gen, body)
|
||||
}
|
||||
/// Expect an [`ItemKind::Fn`] or panic.
|
||||
#[track_caller]
|
||||
@ -3319,7 +3319,7 @@ pub enum ItemKind<'hir> {
|
||||
/// A `static` item.
|
||||
Static(&'hir Ty<'hir>, Mutability, BodyId),
|
||||
/// A `const` item.
|
||||
Const(&'hir Ty<'hir>, BodyId),
|
||||
Const(&'hir Ty<'hir>, &'hir Generics<'hir>, BodyId),
|
||||
/// A function declaration.
|
||||
Fn(FnSig<'hir>, &'hir Generics<'hir>, BodyId),
|
||||
/// A MBE macro definition (`macro_rules!` or `macro`).
|
||||
@ -3372,6 +3372,7 @@ impl ItemKind<'_> {
|
||||
Some(match *self {
|
||||
ItemKind::Fn(_, ref generics, _)
|
||||
| ItemKind::TyAlias(_, ref generics)
|
||||
| ItemKind::Const(_, ref generics, _)
|
||||
| ItemKind::OpaqueTy(OpaqueTy { ref generics, .. })
|
||||
| ItemKind::Enum(_, ref generics)
|
||||
| ItemKind::Struct(_, ref generics)
|
||||
@ -3567,7 +3568,9 @@ impl<'hir> OwnerNode<'hir> {
|
||||
match self {
|
||||
OwnerNode::Item(Item {
|
||||
kind:
|
||||
ItemKind::Static(_, _, body) | ItemKind::Const(_, body) | ItemKind::Fn(_, _, body),
|
||||
ItemKind::Static(_, _, body)
|
||||
| ItemKind::Const(_, _, body)
|
||||
| ItemKind::Fn(_, _, body),
|
||||
..
|
||||
})
|
||||
| OwnerNode::TraitItem(TraitItem {
|
||||
@ -3770,9 +3773,9 @@ impl<'hir> Node<'hir> {
|
||||
pub fn ty(self) -> Option<&'hir Ty<'hir>> {
|
||||
match self {
|
||||
Node::Item(it) => match it.kind {
|
||||
ItemKind::TyAlias(ty, _) | ItemKind::Static(ty, _, _) | ItemKind::Const(ty, _) => {
|
||||
Some(ty)
|
||||
}
|
||||
ItemKind::TyAlias(ty, _)
|
||||
| ItemKind::Static(ty, _, _)
|
||||
| ItemKind::Const(ty, _, _) => Some(ty),
|
||||
_ => None,
|
||||
},
|
||||
Node::TraitItem(it) => match it.kind {
|
||||
@ -3800,7 +3803,9 @@ impl<'hir> Node<'hir> {
|
||||
match self {
|
||||
Node::Item(Item {
|
||||
kind:
|
||||
ItemKind::Static(_, _, body) | ItemKind::Const(_, body) | ItemKind::Fn(_, _, body),
|
||||
ItemKind::Static(_, _, body)
|
||||
| ItemKind::Const(_, _, body)
|
||||
| ItemKind::Fn(_, _, body),
|
||||
..
|
||||
})
|
||||
| Node::TraitItem(TraitItem {
|
||||
|
@ -467,11 +467,17 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) {
|
||||
ItemKind::Use(ref path, _) => {
|
||||
visitor.visit_use(path, item.hir_id());
|
||||
}
|
||||
ItemKind::Static(ref typ, _, body) | ItemKind::Const(ref typ, body) => {
|
||||
ItemKind::Static(ref typ, _, body) => {
|
||||
visitor.visit_id(item.hir_id());
|
||||
visitor.visit_ty(typ);
|
||||
visitor.visit_nested_body(body);
|
||||
}
|
||||
ItemKind::Const(ref typ, ref generics, body) => {
|
||||
visitor.visit_id(item.hir_id());
|
||||
visitor.visit_ty(typ);
|
||||
visitor.visit_generics(generics);
|
||||
visitor.visit_nested_body(body);
|
||||
}
|
||||
ItemKind::Fn(ref sig, ref generics, body_id) => {
|
||||
visitor.visit_id(item.hir_id());
|
||||
visitor.visit_fn(
|
||||
|
@ -76,7 +76,7 @@ fn check_method_is_structurally_compatible<'tcx>(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// This function is best explained by example. Consider a trait with it's implementation:
|
||||
/// This function is best explained by example. Consider a trait with its implementation:
|
||||
///
|
||||
/// ```rust
|
||||
/// trait Trait<'t, T> {
|
||||
@ -120,7 +120,7 @@ fn check_method_is_structurally_compatible<'tcx>(
|
||||
/// types:
|
||||
///
|
||||
/// ```rust,ignore (pseudo-Rust)
|
||||
/// <'b> fn(t: &'i0 U0, m: &'b) -> Foo
|
||||
/// <'b> fn(t: &'i0 U0, m: &'b N0) -> Foo
|
||||
/// ```
|
||||
///
|
||||
/// We now want to extract and substitute the type of the *trait*
|
||||
@ -137,7 +137,7 @@ fn check_method_is_structurally_compatible<'tcx>(
|
||||
/// Applying this to the trait method type yields:
|
||||
///
|
||||
/// ```rust,ignore (pseudo-Rust)
|
||||
/// <'a> fn(t: &'i0 U0, m: &'a) -> Foo
|
||||
/// <'a> fn(t: &'i0 U0, m: &'a N0) -> Foo
|
||||
/// ```
|
||||
///
|
||||
/// This type is also the same but the name of the bound region (`'a`
|
||||
@ -258,8 +258,6 @@ fn compare_method_predicate_entailment<'tcx>(
|
||||
// type.
|
||||
|
||||
// Compute placeholder form of impl and trait method tys.
|
||||
let tcx = infcx.tcx;
|
||||
|
||||
let mut wf_tys = FxIndexSet::default();
|
||||
|
||||
let unnormalized_impl_sig = infcx.instantiate_binder_with_fresh_vars(
|
||||
@ -1668,19 +1666,19 @@ fn compare_synthetic_generics<'tcx>(
|
||||
/// ```rust,ignore (pseudo-Rust)
|
||||
/// trait Foo {
|
||||
/// fn foo<const N: u8>();
|
||||
/// type bar<const N: u8>;
|
||||
/// type Bar<const N: u8>;
|
||||
/// fn baz<const N: u32>();
|
||||
/// type blah<T>;
|
||||
/// type Blah<T>;
|
||||
/// }
|
||||
///
|
||||
/// impl Foo for () {
|
||||
/// fn foo<const N: u64>() {}
|
||||
/// //~^ error
|
||||
/// type bar<const N: u64> {}
|
||||
/// type Bar<const N: u64> = ();
|
||||
/// //~^ error
|
||||
/// fn baz<T>() {}
|
||||
/// //~^ error
|
||||
/// type blah<const N: i64> = u32;
|
||||
/// type Blah<const N: i64> = u32;
|
||||
/// //~^ error
|
||||
/// }
|
||||
/// ```
|
||||
@ -1769,36 +1767,82 @@ pub(super) fn compare_impl_const_raw(
|
||||
let trait_const_item = tcx.associated_item(trait_const_item_def);
|
||||
let impl_trait_ref =
|
||||
tcx.impl_trait_ref(impl_const_item.container_id(tcx)).unwrap().instantiate_identity();
|
||||
debug!("compare_const_impl(impl_trait_ref={:?})", impl_trait_ref);
|
||||
|
||||
let impl_c_span = tcx.def_span(impl_const_item_def.to_def_id());
|
||||
debug!("compare_impl_const(impl_trait_ref={:?})", impl_trait_ref);
|
||||
|
||||
let infcx = tcx.infer_ctxt().build();
|
||||
let param_env = tcx.param_env(impl_const_item_def.to_def_id());
|
||||
let ocx = ObligationCtxt::new(&infcx);
|
||||
compare_number_of_generics(tcx, impl_const_item, trait_const_item, false)?;
|
||||
compare_generic_param_kinds(tcx, impl_const_item, trait_const_item, false)?;
|
||||
compare_const_predicate_entailment(tcx, impl_const_item, trait_const_item, impl_trait_ref)
|
||||
}
|
||||
|
||||
/// The equivalent of [compare_method_predicate_entailment], but for associated constants
|
||||
/// instead of associated functions.
|
||||
// FIXME(generic_const_items): If possible extract the common parts of `compare_{type,const}_predicate_entailment`.
|
||||
fn compare_const_predicate_entailment<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
impl_ct: ty::AssocItem,
|
||||
trait_ct: ty::AssocItem,
|
||||
impl_trait_ref: ty::TraitRef<'tcx>,
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
let impl_ct_def_id = impl_ct.def_id.expect_local();
|
||||
let impl_ct_span = tcx.def_span(impl_ct_def_id);
|
||||
|
||||
// The below is for the most part highly similar to the procedure
|
||||
// for methods above. It is simpler in many respects, especially
|
||||
// because we shouldn't really have to deal with lifetimes or
|
||||
// predicates. In fact some of this should probably be put into
|
||||
// shared functions because of DRY violations...
|
||||
let trait_to_impl_args = impl_trait_ref.args;
|
||||
let impl_args = GenericArgs::identity_for_item(tcx, impl_ct.def_id);
|
||||
let trait_to_impl_args =
|
||||
impl_args.rebase_onto(tcx, impl_ct.container_id(tcx), impl_trait_ref.args);
|
||||
|
||||
// Create a parameter environment that represents the implementation's
|
||||
// method.
|
||||
// Compute placeholder form of impl and trait const tys.
|
||||
let impl_ty = tcx.type_of(impl_const_item_def.to_def_id()).instantiate_identity();
|
||||
let trait_ty = tcx.type_of(trait_const_item_def).instantiate(tcx, trait_to_impl_args);
|
||||
let mut cause = ObligationCause::new(
|
||||
impl_c_span,
|
||||
impl_const_item_def,
|
||||
ObligationCauseCode::CompareImplItemObligation {
|
||||
impl_item_def_id: impl_const_item_def,
|
||||
trait_item_def_id: trait_const_item_def,
|
||||
kind: impl_const_item.kind,
|
||||
},
|
||||
let impl_ty = tcx.type_of(impl_ct_def_id).instantiate_identity();
|
||||
|
||||
let trait_ty = tcx.type_of(trait_ct.def_id).instantiate(tcx, trait_to_impl_args);
|
||||
let code = ObligationCauseCode::CompareImplItemObligation {
|
||||
impl_item_def_id: impl_ct_def_id,
|
||||
trait_item_def_id: trait_ct.def_id,
|
||||
kind: impl_ct.kind,
|
||||
};
|
||||
let mut cause = ObligationCause::new(impl_ct_span, impl_ct_def_id, code.clone());
|
||||
|
||||
let impl_ct_predicates = tcx.predicates_of(impl_ct.def_id);
|
||||
let trait_ct_predicates = tcx.predicates_of(trait_ct.def_id);
|
||||
|
||||
check_region_bounds_on_impl_item(tcx, impl_ct, trait_ct, false)?;
|
||||
|
||||
// The predicates declared by the impl definition, the trait and the
|
||||
// associated const in the trait are assumed.
|
||||
let impl_predicates = tcx.predicates_of(impl_ct_predicates.parent.unwrap());
|
||||
let mut hybrid_preds = impl_predicates.instantiate_identity(tcx);
|
||||
hybrid_preds.predicates.extend(
|
||||
trait_ct_predicates
|
||||
.instantiate_own(tcx, trait_to_impl_args)
|
||||
.map(|(predicate, _)| predicate),
|
||||
);
|
||||
|
||||
let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds.predicates), Reveal::UserFacing);
|
||||
let param_env = traits::normalize_param_env_or_error(
|
||||
tcx,
|
||||
param_env,
|
||||
ObligationCause::misc(impl_ct_span, impl_ct_def_id),
|
||||
);
|
||||
|
||||
let infcx = tcx.infer_ctxt().build();
|
||||
let ocx = ObligationCtxt::new(&infcx);
|
||||
|
||||
let impl_ct_own_bounds = impl_ct_predicates.instantiate_own(tcx, impl_args);
|
||||
for (predicate, span) in impl_ct_own_bounds {
|
||||
let cause = ObligationCause::misc(span, impl_ct_def_id);
|
||||
let predicate = ocx.normalize(&cause, param_env, predicate);
|
||||
|
||||
let cause = ObligationCause::new(span, impl_ct_def_id, code.clone());
|
||||
ocx.register_obligation(traits::Obligation::new(tcx, cause, param_env, predicate));
|
||||
}
|
||||
|
||||
// There is no "body" here, so just pass dummy id.
|
||||
let impl_ty = ocx.normalize(&cause, param_env, impl_ty);
|
||||
|
||||
@ -1817,7 +1861,7 @@ pub(super) fn compare_impl_const_raw(
|
||||
);
|
||||
|
||||
// Locate the Span containing just the type of the offending impl
|
||||
let (ty, _) = tcx.hir().expect_impl_item(impl_const_item_def).expect_const();
|
||||
let (ty, _) = tcx.hir().expect_impl_item(impl_ct_def_id).expect_const();
|
||||
cause.span = ty.span;
|
||||
|
||||
let mut diag = struct_span_err!(
|
||||
@ -1825,12 +1869,12 @@ pub(super) fn compare_impl_const_raw(
|
||||
cause.span,
|
||||
E0326,
|
||||
"implemented const `{}` has an incompatible type for trait",
|
||||
trait_const_item.name
|
||||
trait_ct.name
|
||||
);
|
||||
|
||||
let trait_c_span = trait_const_item_def.as_local().map(|trait_c_def_id| {
|
||||
let trait_c_span = trait_ct.def_id.as_local().map(|trait_ct_def_id| {
|
||||
// Add a label to the Span containing just the type of the const
|
||||
let (ty, _) = tcx.hir().expect_trait_item(trait_c_def_id).expect_const();
|
||||
let (ty, _) = tcx.hir().expect_trait_item(trait_ct_def_id).expect_const();
|
||||
ty.span
|
||||
});
|
||||
|
||||
@ -1857,7 +1901,7 @@ pub(super) fn compare_impl_const_raw(
|
||||
}
|
||||
|
||||
let outlives_env = OutlivesEnvironment::new(param_env);
|
||||
ocx.resolve_regions_and_report_errors(impl_const_item_def, &outlives_env)
|
||||
ocx.resolve_regions_and_report_errors(impl_ct_def_id, &outlives_env)
|
||||
}
|
||||
|
||||
pub(super) fn compare_impl_ty<'tcx>(
|
||||
@ -1899,7 +1943,7 @@ fn compare_type_predicate_entailment<'tcx>(
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// This `HirId` should be used for the `body_id` field on each
|
||||
// This `DefId` should be used for the `body_id` field on each
|
||||
// `ObligationCause` (and the `FnCtxt`). This is what
|
||||
// `regionck_item` expects.
|
||||
let impl_ty_def_id = impl_ty.def_id.expect_local();
|
||||
@ -1918,7 +1962,7 @@ fn compare_type_predicate_entailment<'tcx>(
|
||||
debug!("compare_type_predicate_entailment: bounds={:?}", hybrid_preds);
|
||||
|
||||
let impl_ty_span = tcx.def_span(impl_ty_def_id);
|
||||
let normalize_cause = traits::ObligationCause::misc(impl_ty_span, impl_ty_def_id);
|
||||
let normalize_cause = ObligationCause::misc(impl_ty_span, impl_ty_def_id);
|
||||
let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds.predicates), Reveal::UserFacing);
|
||||
let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause);
|
||||
let infcx = tcx.infer_ctxt().build();
|
||||
@ -1963,7 +2007,7 @@ fn compare_type_predicate_entailment<'tcx>(
|
||||
///
|
||||
/// trait X { type Y: Copy } impl X for T { type Y = S; }
|
||||
///
|
||||
/// We are able to normalize `<T as X>::U` to `S`, and so when we check the
|
||||
/// We are able to normalize `<T as X>::Y` to `S`, and so when we check the
|
||||
/// impl is well-formed we have to prove `S: Copy`.
|
||||
///
|
||||
/// For default associated types the normalization is not possible (the value
|
||||
|
@ -209,6 +209,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
|
||||
| ItemKind::Struct(..)
|
||||
| ItemKind::OpaqueTy(..)
|
||||
| ItemKind::Union(..) => (None, Defaults::Allowed),
|
||||
ItemKind::Const(..) => (None, Defaults::Deny),
|
||||
_ => (None, Defaults::FutureCompatDisallowed),
|
||||
}
|
||||
}
|
||||
|
@ -156,6 +156,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
|
||||
}
|
||||
ItemKind::Fn(.., generics, _)
|
||||
| ItemKind::TyAlias(_, generics)
|
||||
| ItemKind::Const(_, generics, _)
|
||||
| ItemKind::Enum(_, generics)
|
||||
| ItemKind::Struct(_, generics)
|
||||
| ItemKind::Union(_, generics) => generics,
|
||||
@ -762,6 +763,7 @@ pub(super) fn type_param_predicates(
|
||||
ItemKind::Fn(.., generics, _)
|
||||
| ItemKind::Impl(&hir::Impl { generics, .. })
|
||||
| ItemKind::TyAlias(_, generics)
|
||||
| ItemKind::Const(_, generics, _)
|
||||
| ItemKind::OpaqueTy(&OpaqueTy {
|
||||
generics,
|
||||
origin: hir::OpaqueTyOrigin::TyAlias { .. },
|
||||
|
@ -518,7 +518,6 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
||||
| hir::ItemKind::Mod(..)
|
||||
| hir::ItemKind::ForeignMod { .. }
|
||||
| hir::ItemKind::Static(..)
|
||||
| hir::ItemKind::Const(..)
|
||||
| hir::ItemKind::GlobalAsm(..) => {
|
||||
// These sorts of items have no lifetime parameters at all.
|
||||
intravisit::walk_item(self, item);
|
||||
@ -583,6 +582,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
||||
})
|
||||
}
|
||||
hir::ItemKind::TyAlias(_, generics)
|
||||
| hir::ItemKind::Const(_, generics, _)
|
||||
| hir::ItemKind::Enum(_, generics)
|
||||
| hir::ItemKind::Struct(_, generics)
|
||||
| hir::ItemKind::Union(_, generics)
|
||||
@ -590,21 +590,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
||||
| hir::ItemKind::TraitAlias(generics, ..)
|
||||
| hir::ItemKind::Impl(&hir::Impl { generics, .. }) => {
|
||||
// These kinds of items have only early-bound lifetime parameters.
|
||||
let bound_vars = generics.params.iter().map(ResolvedArg::early).collect();
|
||||
self.record_late_bound_vars(item.hir_id(), vec![]);
|
||||
let scope = Scope::Binder {
|
||||
hir_id: item.hir_id(),
|
||||
bound_vars,
|
||||
scope_type: BinderScopeType::Normal,
|
||||
s: self.scope,
|
||||
where_bound_origin: None,
|
||||
};
|
||||
self.with(scope, |this| {
|
||||
let scope = Scope::TraitRefBoundary { s: this.scope };
|
||||
this.with(scope, |this| {
|
||||
intravisit::walk_item(this, item);
|
||||
});
|
||||
});
|
||||
self.visit_early(item.hir_id(), generics, |this| intravisit::walk_item(this, item));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -777,39 +763,24 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
||||
use self::hir::TraitItemKind::*;
|
||||
match trait_item.kind {
|
||||
Fn(_, _) => {
|
||||
self.visit_early_late(trait_item.hir_id(), &trait_item.generics, |this| {
|
||||
self.visit_early_late(trait_item.hir_id(), trait_item.generics, |this| {
|
||||
intravisit::walk_trait_item(this, trait_item)
|
||||
});
|
||||
}
|
||||
Type(bounds, ty) => {
|
||||
let generics = &trait_item.generics;
|
||||
let bound_vars = generics.params.iter().map(ResolvedArg::early).collect();
|
||||
self.record_late_bound_vars(trait_item.hir_id(), vec![]);
|
||||
let scope = Scope::Binder {
|
||||
hir_id: trait_item.hir_id(),
|
||||
bound_vars,
|
||||
s: self.scope,
|
||||
scope_type: BinderScopeType::Normal,
|
||||
where_bound_origin: None,
|
||||
};
|
||||
self.with(scope, |this| {
|
||||
let scope = Scope::TraitRefBoundary { s: this.scope };
|
||||
this.with(scope, |this| {
|
||||
this.visit_generics(generics);
|
||||
for bound in bounds {
|
||||
this.visit_param_bound(bound);
|
||||
}
|
||||
if let Some(ty) = ty {
|
||||
this.visit_ty(ty);
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
Const(_, _) => {
|
||||
// Only methods and types support generics.
|
||||
assert!(trait_item.generics.params.is_empty());
|
||||
intravisit::walk_trait_item(self, trait_item);
|
||||
self.visit_early(trait_item.hir_id(), trait_item.generics, |this| {
|
||||
this.visit_generics(&trait_item.generics);
|
||||
for bound in bounds {
|
||||
this.visit_param_bound(bound);
|
||||
}
|
||||
if let Some(ty) = ty {
|
||||
this.visit_ty(ty);
|
||||
}
|
||||
})
|
||||
}
|
||||
Const(_, _) => self.visit_early(trait_item.hir_id(), trait_item.generics, |this| {
|
||||
intravisit::walk_trait_item(this, trait_item)
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
@ -817,34 +788,16 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
|
||||
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
|
||||
use self::hir::ImplItemKind::*;
|
||||
match impl_item.kind {
|
||||
Fn(..) => self.visit_early_late(impl_item.hir_id(), &impl_item.generics, |this| {
|
||||
Fn(..) => self.visit_early_late(impl_item.hir_id(), impl_item.generics, |this| {
|
||||
intravisit::walk_impl_item(this, impl_item)
|
||||
}),
|
||||
Type(ty) => self.visit_early(impl_item.hir_id(), impl_item.generics, |this| {
|
||||
this.visit_generics(impl_item.generics);
|
||||
this.visit_ty(ty);
|
||||
}),
|
||||
Const(_, _) => self.visit_early(impl_item.hir_id(), impl_item.generics, |this| {
|
||||
intravisit::walk_impl_item(this, impl_item)
|
||||
}),
|
||||
Type(ty) => {
|
||||
let generics = &impl_item.generics;
|
||||
let bound_vars: FxIndexMap<LocalDefId, ResolvedArg> =
|
||||
generics.params.iter().map(ResolvedArg::early).collect();
|
||||
self.record_late_bound_vars(impl_item.hir_id(), vec![]);
|
||||
let scope = Scope::Binder {
|
||||
hir_id: impl_item.hir_id(),
|
||||
bound_vars,
|
||||
s: self.scope,
|
||||
scope_type: BinderScopeType::Normal,
|
||||
where_bound_origin: None,
|
||||
};
|
||||
self.with(scope, |this| {
|
||||
let scope = Scope::TraitRefBoundary { s: this.scope };
|
||||
this.with(scope, |this| {
|
||||
this.visit_generics(generics);
|
||||
this.visit_ty(ty);
|
||||
})
|
||||
});
|
||||
}
|
||||
Const(_, _) => {
|
||||
// Only methods and types support generics.
|
||||
assert!(impl_item.generics.params.is_empty());
|
||||
intravisit::walk_impl_item(self, impl_item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1180,6 +1133,25 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
|
||||
self.with(scope, walk);
|
||||
}
|
||||
|
||||
fn visit_early<F>(&mut self, hir_id: hir::HirId, generics: &'tcx hir::Generics<'tcx>, walk: F)
|
||||
where
|
||||
F: for<'b, 'c> FnOnce(&'b mut BoundVarContext<'c, 'tcx>),
|
||||
{
|
||||
let bound_vars = generics.params.iter().map(ResolvedArg::early).collect();
|
||||
self.record_late_bound_vars(hir_id, vec![]);
|
||||
let scope = Scope::Binder {
|
||||
hir_id,
|
||||
bound_vars,
|
||||
s: self.scope,
|
||||
scope_type: BinderScopeType::Normal,
|
||||
where_bound_origin: None,
|
||||
};
|
||||
self.with(scope, |this| {
|
||||
let scope = Scope::TraitRefBoundary { s: this.scope };
|
||||
this.with(scope, walk)
|
||||
});
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self))]
|
||||
fn resolve_lifetime_ref(
|
||||
&mut self,
|
||||
|
@ -404,7 +404,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
|
||||
icx.to_ty(ty)
|
||||
}
|
||||
}
|
||||
ItemKind::Const(ty, body_id) => {
|
||||
ItemKind::Const(ty, _, body_id) => {
|
||||
if is_suggestable_infer_ty(ty) {
|
||||
infer_placeholder_type(
|
||||
tcx, def_id, body_id, ty.span, item.ident, "constant",
|
||||
|
@ -130,7 +130,7 @@ fn diagnostic_hir_wf_check<'tcx>(
|
||||
hir::Node::Item(item) => match item.kind {
|
||||
hir::ItemKind::TyAlias(ty, _)
|
||||
| hir::ItemKind::Static(ty, _, _)
|
||||
| hir::ItemKind::Const(ty, _) => vec![ty],
|
||||
| hir::ItemKind::Const(ty, _, _) => vec![ty],
|
||||
hir::ItemKind::Impl(impl_) => match &impl_.of_trait {
|
||||
Some(t) => t
|
||||
.path
|
||||
|
@ -420,12 +420,13 @@ impl<'a> State<'a> {
|
||||
fn print_associated_const(
|
||||
&mut self,
|
||||
ident: Ident,
|
||||
generics: &hir::Generics<'_>,
|
||||
ty: &hir::Ty<'_>,
|
||||
default: Option<hir::BodyId>,
|
||||
) {
|
||||
self.head("");
|
||||
self.word_space("const");
|
||||
self.print_ident(ident);
|
||||
self.print_generic_params(generics.params);
|
||||
self.word_space(":");
|
||||
self.print_type(ty);
|
||||
if let Some(expr) = default {
|
||||
@ -433,6 +434,7 @@ impl<'a> State<'a> {
|
||||
self.word_space("=");
|
||||
self.ann.nested(self, Nested::Body(expr));
|
||||
}
|
||||
self.print_where_clause(generics);
|
||||
self.word(";")
|
||||
}
|
||||
|
||||
@ -532,9 +534,10 @@ impl<'a> State<'a> {
|
||||
self.word(";");
|
||||
self.end(); // end the outer cbox
|
||||
}
|
||||
hir::ItemKind::Const(ty, expr) => {
|
||||
hir::ItemKind::Const(ty, generics, expr) => {
|
||||
self.head("const");
|
||||
self.print_ident(item.ident);
|
||||
self.print_generic_params(generics.params);
|
||||
self.word_space(":");
|
||||
self.print_type(ty);
|
||||
self.space();
|
||||
@ -542,6 +545,7 @@ impl<'a> State<'a> {
|
||||
|
||||
self.word_space("=");
|
||||
self.ann.nested(self, Nested::Body(expr));
|
||||
self.print_where_clause(generics);
|
||||
self.word(";");
|
||||
self.end(); // end the outer cbox
|
||||
}
|
||||
@ -836,7 +840,7 @@ impl<'a> State<'a> {
|
||||
self.print_outer_attributes(self.attrs(ti.hir_id()));
|
||||
match ti.kind {
|
||||
hir::TraitItemKind::Const(ty, default) => {
|
||||
self.print_associated_const(ti.ident, ty, default);
|
||||
self.print_associated_const(ti.ident, ti.generics, ty, default);
|
||||
}
|
||||
hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(arg_names)) => {
|
||||
self.print_method_sig(ti.ident, sig, ti.generics, arg_names, None);
|
||||
@ -865,7 +869,7 @@ impl<'a> State<'a> {
|
||||
|
||||
match ii.kind {
|
||||
hir::ImplItemKind::Const(ty, expr) => {
|
||||
self.print_associated_const(ii.ident, ty, Some(expr));
|
||||
self.print_associated_const(ii.ident, ii.generics, ty, Some(expr));
|
||||
}
|
||||
hir::ImplItemKind::Fn(ref sig, body) => {
|
||||
self.head("");
|
||||
|
@ -1394,7 +1394,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
let Some((
|
||||
_,
|
||||
hir::Node::Local(hir::Local { ty: Some(ty), .. })
|
||||
| hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(ty, _), .. }),
|
||||
| hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(ty, _, _), .. }),
|
||||
)) = parent_node
|
||||
else {
|
||||
return;
|
||||
|
@ -101,7 +101,7 @@ fn primary_body_of(
|
||||
) -> Option<(hir::BodyId, Option<&hir::Ty<'_>>, Option<&hir::FnSig<'_>>)> {
|
||||
match node {
|
||||
Node::Item(item) => match item.kind {
|
||||
hir::ItemKind::Const(ty, body) | hir::ItemKind::Static(ty, _, body) => {
|
||||
hir::ItemKind::Const(ty, _, body) | hir::ItemKind::Static(ty, _, body) => {
|
||||
Some((body, Some(ty), None))
|
||||
}
|
||||
hir::ItemKind::Fn(ref sig, .., body) => Some((body, None, Some(sig))),
|
||||
|
@ -924,7 +924,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
match opt_def_id {
|
||||
Some(def_id) => match self.tcx.hir().get_if_local(def_id) {
|
||||
Some(hir::Node::Item(hir::Item {
|
||||
kind: hir::ItemKind::Const(_, body_id), ..
|
||||
kind: hir::ItemKind::Const(_, _, body_id),
|
||||
..
|
||||
})) => match self.tcx.hir().get(body_id.hir_id) {
|
||||
hir::Node::Expr(expr) => {
|
||||
if hir::is_range_literal(expr) {
|
||||
|
@ -2068,7 +2068,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
|
||||
visitor.visit_body(body);
|
||||
visitor.result.map(|r| &r.peel_refs().kind)
|
||||
}
|
||||
Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(ty, _), .. })) => {
|
||||
Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Const(ty, _, _), .. })) => {
|
||||
Some(&ty.peel_refs().kind)
|
||||
}
|
||||
_ => None,
|
||||
|
@ -1529,9 +1529,10 @@ declare_lint_pass!(
|
||||
impl<'tcx> LateLintPass<'tcx> for UnusedBrokenConst {
|
||||
fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
|
||||
match it.kind {
|
||||
hir::ItemKind::Const(_, body_id) => {
|
||||
hir::ItemKind::Const(_, _, body_id) => {
|
||||
let def_id = cx.tcx.hir().body_owner_def_id(body_id).to_def_id();
|
||||
// trigger the query once for all constants since that will already report the errors
|
||||
// FIXME(generic_const_items): Does this work properly with generic const items?
|
||||
cx.tcx.ensure().const_eval_poly(def_id);
|
||||
}
|
||||
hir::ItemKind::Static(_, _, body_id) => {
|
||||
|
@ -24,7 +24,7 @@ pub fn associated_body(node: Node<'_>) -> Option<(LocalDefId, BodyId)> {
|
||||
match node {
|
||||
Node::Item(Item {
|
||||
owner_id,
|
||||
kind: ItemKind::Const(_, body) | ItemKind::Static(.., body) | ItemKind::Fn(.., body),
|
||||
kind: ItemKind::Const(_, _, body) | ItemKind::Static(.., body) | ItemKind::Fn(.., body),
|
||||
..
|
||||
})
|
||||
| Node::TraitItem(TraitItem {
|
||||
|
@ -570,7 +570,7 @@ fn construct_const<'a, 'tcx>(
|
||||
// Figure out what primary body this item has.
|
||||
let (span, const_ty_span) = match tcx.hir().get(hir_id) {
|
||||
Node::Item(hir::Item {
|
||||
kind: hir::ItemKind::Static(ty, _, _) | hir::ItemKind::Const(ty, _),
|
||||
kind: hir::ItemKind::Static(ty, _, _) | hir::ItemKind::Const(ty, _, _),
|
||||
span,
|
||||
..
|
||||
})
|
||||
|
@ -690,6 +690,8 @@ parse_single_colon_import_path = expected `::`, found `:`
|
||||
parse_single_colon_struct_type = found single colon in a struct field type path
|
||||
.suggestion = write a path separator here
|
||||
|
||||
parse_static_with_generics = static items may not have generic parameters
|
||||
|
||||
parse_struct_literal_body_without_path =
|
||||
struct literal body without path
|
||||
.suggestion = you might have forgotten to add the struct literal inside the block
|
||||
@ -847,6 +849,12 @@ parse_visibility_not_followed_by_item = visibility `{$vis}` is not followed by a
|
||||
.label = the visibility
|
||||
.help = you likely meant to define an item, e.g., `{$vis} fn foo() {"{}"}`
|
||||
|
||||
parse_where_clause_before_const_body = where clauses are not allowed before const item bodies
|
||||
.label = unexpected where clause
|
||||
.name_label = while parsing this const item
|
||||
.body_label = the item body
|
||||
.suggestion = move the body before the where clause
|
||||
|
||||
parse_where_clause_before_tuple_struct_body = where clauses are not allowed before tuple struct bodies
|
||||
.label = unexpected where clause
|
||||
.name_label = while parsing this tuple struct
|
||||
|
@ -2692,3 +2692,34 @@ pub(crate) struct ExpectedBuiltinIdent {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(parse_static_with_generics)]
|
||||
pub(crate) struct StaticWithGenerics {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(parse_where_clause_before_const_body)]
|
||||
pub(crate) struct WhereClauseBeforeConstBody {
|
||||
#[primary_span]
|
||||
#[label]
|
||||
pub span: Span,
|
||||
#[label(parse_name_label)]
|
||||
pub name: Span,
|
||||
#[label(parse_body_label)]
|
||||
pub body: Span,
|
||||
#[subdiagnostic]
|
||||
pub sugg: Option<WhereClauseBeforeConstBodySugg>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[multipart_suggestion(parse_suggestion, applicability = "machine-applicable")]
|
||||
pub(crate) struct WhereClauseBeforeConstBodySugg {
|
||||
#[suggestion_part(code = "= {snippet} ")]
|
||||
pub left: Span,
|
||||
pub snippet: String,
|
||||
#[suggestion_part(code = "")]
|
||||
pub right: Span,
|
||||
}
|
||||
|
@ -226,9 +226,9 @@ impl<'a> Parser<'a> {
|
||||
} else if self.is_static_global() {
|
||||
// STATIC ITEM
|
||||
self.bump(); // `static`
|
||||
let m = self.parse_mutability();
|
||||
let (ident, ty, expr) = self.parse_item_global(Some(m))?;
|
||||
(ident, ItemKind::Static(Box::new(StaticItem { ty, mutability: m, expr })))
|
||||
let mutability = self.parse_mutability();
|
||||
let (ident, item) = self.parse_static_item(mutability)?;
|
||||
(ident, ItemKind::Static(Box::new(item)))
|
||||
} else if let Const::Yes(const_span) = self.parse_constness(Case::Sensitive) {
|
||||
// CONST ITEM
|
||||
if self.token.is_keyword(kw::Impl) {
|
||||
@ -236,8 +236,16 @@ impl<'a> Parser<'a> {
|
||||
self.recover_const_impl(const_span, attrs, def_())?
|
||||
} else {
|
||||
self.recover_const_mut(const_span);
|
||||
let (ident, ty, expr) = self.parse_item_global(None)?;
|
||||
(ident, ItemKind::Const(Box::new(ConstItem { defaultness: def_(), ty, expr })))
|
||||
let (ident, generics, ty, expr) = self.parse_const_item()?;
|
||||
(
|
||||
ident,
|
||||
ItemKind::Const(Box::new(ConstItem {
|
||||
defaultness: def_(),
|
||||
generics,
|
||||
ty,
|
||||
expr,
|
||||
})),
|
||||
)
|
||||
}
|
||||
} else if self.check_keyword(kw::Trait) || self.check_auto_or_unsafe_trait_item() {
|
||||
// TRAIT ITEM
|
||||
@ -878,6 +886,7 @@ impl<'a> Parser<'a> {
|
||||
self.sess.emit_err(errors::AssociatedStaticItemNotAllowed { span });
|
||||
AssocItemKind::Const(Box::new(ConstItem {
|
||||
defaultness: Defaultness::Final,
|
||||
generics: Generics::default(),
|
||||
ty,
|
||||
expr,
|
||||
}))
|
||||
@ -892,7 +901,7 @@ impl<'a> Parser<'a> {
|
||||
|
||||
/// Parses a `type` alias with the following grammar:
|
||||
/// ```ebnf
|
||||
/// TypeAlias = "type" Ident Generics {":" GenericBounds}? {"=" Ty}? ";" ;
|
||||
/// TypeAlias = "type" Ident Generics (":" GenericBounds)? WhereClause ("=" Ty)? WhereClause ";" ;
|
||||
/// ```
|
||||
/// The `"type"` has already been eaten.
|
||||
fn parse_type_alias(&mut self, defaultness: Defaultness) -> PResult<'a, ItemInfo> {
|
||||
@ -1220,33 +1229,132 @@ impl<'a> Parser<'a> {
|
||||
Ok(impl_info)
|
||||
}
|
||||
|
||||
/// Parse `["const" | ("static" "mut"?)] $ident ":" $ty (= $expr)?` with
|
||||
/// `["const" | ("static" "mut"?)]` already parsed and stored in `m`.
|
||||
/// Parse a static item with the prefix `"static" "mut"?` already parsed and stored in `mutability`.
|
||||
///
|
||||
/// When `m` is `"const"`, `$ident` may also be `"_"`.
|
||||
fn parse_item_global(
|
||||
&mut self,
|
||||
m: Option<Mutability>,
|
||||
) -> PResult<'a, (Ident, P<Ty>, Option<P<ast::Expr>>)> {
|
||||
let id = if m.is_none() { self.parse_ident_or_underscore() } else { self.parse_ident() }?;
|
||||
/// ```ebnf
|
||||
/// Static = "static" "mut"? $ident ":" $ty (= $expr)? ";" ;
|
||||
/// ```
|
||||
fn parse_static_item(&mut self, mutability: Mutability) -> PResult<'a, (Ident, StaticItem)> {
|
||||
let ident = self.parse_ident()?;
|
||||
|
||||
// Parse the type of a `const` or `static mut?` item.
|
||||
// That is, the `":" $ty` fragment.
|
||||
if self.token.kind == TokenKind::Lt && self.may_recover() {
|
||||
let generics = self.parse_generics()?;
|
||||
self.sess.emit_err(errors::StaticWithGenerics { span: generics.span });
|
||||
}
|
||||
|
||||
// Parse the type of a static item. That is, the `":" $ty` fragment.
|
||||
// FIXME: This could maybe benefit from `.may_recover()`?
|
||||
let ty = match (self.eat(&token::Colon), self.check(&token::Eq) | self.check(&token::Semi))
|
||||
{
|
||||
// If there wasn't a `:` or the colon was followed by a `=` or `;` recover a missing type.
|
||||
(true, false) => self.parse_ty()?,
|
||||
(colon, _) => self.recover_missing_const_type(colon, m),
|
||||
// If there wasn't a `:` or the colon was followed by a `=` or `;`, recover a missing type.
|
||||
(colon, _) => self.recover_missing_global_item_type(colon, Some(mutability)),
|
||||
};
|
||||
|
||||
let expr = if self.eat(&token::Eq) { Some(self.parse_expr()?) } else { None };
|
||||
|
||||
self.expect_semi()?;
|
||||
Ok((id, ty, expr))
|
||||
|
||||
Ok((ident, StaticItem { ty, mutability, expr }))
|
||||
}
|
||||
|
||||
/// Parse a constant item with the prefix `"const"` already parsed.
|
||||
///
|
||||
/// ```ebnf
|
||||
/// Const = "const" ($ident | "_") Generics ":" $ty (= $expr)? WhereClause ";" ;
|
||||
/// ```
|
||||
fn parse_const_item(&mut self) -> PResult<'a, (Ident, Generics, P<Ty>, Option<P<ast::Expr>>)> {
|
||||
let ident = self.parse_ident_or_underscore()?;
|
||||
|
||||
let mut generics = self.parse_generics()?;
|
||||
|
||||
// Check the span for emptiness instead of the list of parameters in order to correctly
|
||||
// recognize and subsequently flag empty parameter lists (`<>`) as unstable.
|
||||
if !generics.span.is_empty() {
|
||||
self.sess.gated_spans.gate(sym::generic_const_items, generics.span);
|
||||
}
|
||||
|
||||
// Parse the type of a constant item. That is, the `":" $ty` fragment.
|
||||
// FIXME: This could maybe benefit from `.may_recover()`?
|
||||
let ty = match (
|
||||
self.eat(&token::Colon),
|
||||
self.check(&token::Eq) | self.check(&token::Semi) | self.check_keyword(kw::Where),
|
||||
) {
|
||||
(true, false) => self.parse_ty()?,
|
||||
// If there wasn't a `:` or the colon was followed by a `=`, `;` or `where`, recover a missing type.
|
||||
(colon, _) => self.recover_missing_global_item_type(colon, None),
|
||||
};
|
||||
|
||||
// Proactively parse a where-clause to be able to provide a good error message in case we
|
||||
// encounter the item body following it.
|
||||
let before_where_clause =
|
||||
if self.may_recover() { self.parse_where_clause()? } else { WhereClause::default() };
|
||||
|
||||
let expr = if self.eat(&token::Eq) { Some(self.parse_expr()?) } else { None };
|
||||
|
||||
let after_where_clause = self.parse_where_clause()?;
|
||||
|
||||
// Provide a nice error message if the user placed a where-clause before the item body.
|
||||
// Users may be tempted to write such code if they are still used to the deprecated
|
||||
// where-clause location on type aliases and associated types. See also #89122.
|
||||
if before_where_clause.has_where_token && let Some(expr) = &expr {
|
||||
self.sess.emit_err(errors::WhereClauseBeforeConstBody {
|
||||
span: before_where_clause.span,
|
||||
name: ident.span,
|
||||
body: expr.span,
|
||||
sugg: if !after_where_clause.has_where_token {
|
||||
self.sess.source_map().span_to_snippet(expr.span).ok().map(|body| {
|
||||
errors::WhereClauseBeforeConstBodySugg {
|
||||
left: before_where_clause.span.shrink_to_lo(),
|
||||
snippet: body,
|
||||
right: before_where_clause.span.shrink_to_hi().to(expr.span),
|
||||
}
|
||||
})
|
||||
} else {
|
||||
// FIXME(generic_const_items): Provide a structured suggestion to merge the first
|
||||
// where-clause into the second one.
|
||||
None
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// Merge the predicates of both where-clauses since either one can be relevant.
|
||||
// If we didn't parse a body (which is valid for associated consts in traits) and we were
|
||||
// allowed to recover, `before_where_clause` contains the predicates, otherwise they are
|
||||
// in `after_where_clause`. Further, both of them might contain predicates iff two
|
||||
// where-clauses were provided which is syntactically ill-formed but we want to recover from
|
||||
// it and treat them as one large where-clause.
|
||||
let mut predicates = before_where_clause.predicates;
|
||||
predicates.extend(after_where_clause.predicates);
|
||||
let where_clause = WhereClause {
|
||||
has_where_token: before_where_clause.has_where_token
|
||||
|| after_where_clause.has_where_token,
|
||||
predicates,
|
||||
span: if after_where_clause.has_where_token {
|
||||
after_where_clause.span
|
||||
} else {
|
||||
before_where_clause.span
|
||||
},
|
||||
};
|
||||
|
||||
if where_clause.has_where_token {
|
||||
self.sess.gated_spans.gate(sym::generic_const_items, where_clause.span);
|
||||
}
|
||||
|
||||
generics.where_clause = where_clause;
|
||||
|
||||
self.expect_semi()?;
|
||||
|
||||
Ok((ident, generics, ty, expr))
|
||||
}
|
||||
|
||||
/// We were supposed to parse `":" $ty` but the `:` or the type was missing.
|
||||
/// This means that the type is missing.
|
||||
fn recover_missing_const_type(&mut self, colon_present: bool, m: Option<Mutability>) -> P<Ty> {
|
||||
fn recover_missing_global_item_type(
|
||||
&mut self,
|
||||
colon_present: bool,
|
||||
m: Option<Mutability>,
|
||||
) -> P<Ty> {
|
||||
// Construct the error and stash it away with the hope
|
||||
// that typeck will later enrich the error with a type.
|
||||
let kind = match m {
|
||||
|
@ -236,7 +236,7 @@ impl<'tcx> ReachableContext<'tcx> {
|
||||
// Reachable constants will be inlined into other crates
|
||||
// unconditionally, so we need to make sure that their
|
||||
// contents are also reachable.
|
||||
hir::ItemKind::Const(_, init) | hir::ItemKind::Static(_, _, init) => {
|
||||
hir::ItemKind::Const(_, _, init) | hir::ItemKind::Static(_, _, init) => {
|
||||
self.visit_nested_body(init);
|
||||
}
|
||||
|
||||
|
@ -337,6 +337,7 @@ enum LifetimeBinderKind {
|
||||
PolyTrait,
|
||||
WhereBound,
|
||||
Item,
|
||||
ConstItem,
|
||||
Function,
|
||||
Closure,
|
||||
ImplBlock,
|
||||
@ -349,7 +350,7 @@ impl LifetimeBinderKind {
|
||||
BareFnType => "type",
|
||||
PolyTrait => "bound",
|
||||
WhereBound => "bound",
|
||||
Item => "item",
|
||||
Item | ConstItem => "item",
|
||||
ImplBlock => "impl block",
|
||||
Function => "function",
|
||||
Closure => "closure",
|
||||
@ -2404,30 +2405,44 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
||||
});
|
||||
}
|
||||
|
||||
ItemKind::Static(box ast::StaticItem { ref ty, ref expr, .. })
|
||||
| ItemKind::Const(box ast::ConstItem { ref ty, ref expr, .. }) => {
|
||||
ItemKind::Static(box ast::StaticItem { ref ty, ref expr, .. }) => {
|
||||
self.with_static_rib(|this| {
|
||||
this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Static), |this| {
|
||||
this.visit_ty(ty);
|
||||
});
|
||||
this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| {
|
||||
if let Some(expr) = expr {
|
||||
// We already forbid generic params because of the above item rib,
|
||||
// so it doesn't matter whether this is a trivial constant.
|
||||
this.resolve_const_body(expr, Some((item.ident, ConstantItemKind::Static)));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ItemKind::Const(box ast::ConstItem { ref generics, ref ty, ref expr, .. }) => {
|
||||
self.with_generic_param_rib(
|
||||
&generics.params,
|
||||
RibKind::Item(HasGenericParams::Yes(generics.span)),
|
||||
LifetimeRibKind::Generics {
|
||||
binder: item.id,
|
||||
kind: LifetimeBinderKind::ConstItem,
|
||||
span: generics.span,
|
||||
},
|
||||
|this| {
|
||||
this.visit_generics(generics);
|
||||
|
||||
this.with_lifetime_rib(
|
||||
LifetimeRibKind::Elided(LifetimeRes::Static),
|
||||
|this| this.visit_ty(ty),
|
||||
);
|
||||
|
||||
if let Some(expr) = expr {
|
||||
let constant_item_kind = match item.kind {
|
||||
ItemKind::Const(..) => ConstantItemKind::Const,
|
||||
ItemKind::Static(..) => ConstantItemKind::Static,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
// We already forbid generic params because of the above item rib,
|
||||
// so it doesn't matter whether this is a trivial constant.
|
||||
this.with_constant_rib(
|
||||
IsRepeatExpr::No,
|
||||
ConstantHasGenerics::Yes,
|
||||
Some((item.ident, constant_item_kind)),
|
||||
|this| this.visit_expr(expr),
|
||||
this.resolve_const_body(
|
||||
expr,
|
||||
Some((item.ident, ConstantItemKind::Const)),
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
ItemKind::Use(ref use_tree) => {
|
||||
@ -2700,28 +2715,31 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
||||
for item in trait_items {
|
||||
self.resolve_doc_links(&item.attrs, MaybeExported::Ok(item.id));
|
||||
match &item.kind {
|
||||
AssocItemKind::Const(box ast::ConstItem { ty, expr, .. }) => {
|
||||
self.visit_ty(ty);
|
||||
// Only impose the restrictions of `ConstRibKind` for an
|
||||
// actual constant expression in a provided default.
|
||||
if let Some(expr) = expr {
|
||||
// We allow arbitrary const expressions inside of associated consts,
|
||||
// even if they are potentially not const evaluatable.
|
||||
//
|
||||
// Type parameters can already be used and as associated consts are
|
||||
// not used as part of the type system, this is far less surprising.
|
||||
self.with_lifetime_rib(
|
||||
LifetimeRibKind::Elided(LifetimeRes::Infer),
|
||||
|this| {
|
||||
this.with_constant_rib(
|
||||
IsRepeatExpr::No,
|
||||
ConstantHasGenerics::Yes,
|
||||
None,
|
||||
|this| this.visit_expr(expr),
|
||||
)
|
||||
},
|
||||
);
|
||||
}
|
||||
AssocItemKind::Const(box ast::ConstItem { generics, ty, expr, .. }) => {
|
||||
self.with_generic_param_rib(
|
||||
&generics.params,
|
||||
RibKind::AssocItem,
|
||||
LifetimeRibKind::Generics {
|
||||
binder: item.id,
|
||||
span: generics.span,
|
||||
kind: LifetimeBinderKind::ConstItem,
|
||||
},
|
||||
|this| {
|
||||
this.visit_generics(generics);
|
||||
this.visit_ty(ty);
|
||||
|
||||
// Only impose the restrictions of `ConstRibKind` for an
|
||||
// actual constant expression in a provided default.
|
||||
if let Some(expr) = expr {
|
||||
// We allow arbitrary const expressions inside of associated consts,
|
||||
// even if they are potentially not const evaluatable.
|
||||
//
|
||||
// Type parameters can already be used and as associated consts are
|
||||
// not used as part of the type system, this is far less surprising.
|
||||
this.resolve_const_body(expr, None);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
AssocItemKind::Fn(box Fn { generics, .. }) => {
|
||||
walk_assoc_item(self, generics, LifetimeBinderKind::Function, item);
|
||||
@ -2876,36 +2894,42 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
||||
use crate::ResolutionError::*;
|
||||
self.resolve_doc_links(&item.attrs, MaybeExported::ImplItem(trait_id.ok_or(&item.vis)));
|
||||
match &item.kind {
|
||||
AssocItemKind::Const(box ast::ConstItem { ty, expr, .. }) => {
|
||||
AssocItemKind::Const(box ast::ConstItem { generics, ty, expr, .. }) => {
|
||||
debug!("resolve_implementation AssocItemKind::Const");
|
||||
// If this is a trait impl, ensure the const
|
||||
// exists in trait
|
||||
self.check_trait_item(
|
||||
item.id,
|
||||
item.ident,
|
||||
&item.kind,
|
||||
ValueNS,
|
||||
item.span,
|
||||
seen_trait_items,
|
||||
|i, s, c| ConstNotMemberOfTrait(i, s, c),
|
||||
);
|
||||
|
||||
self.visit_ty(ty);
|
||||
if let Some(expr) = expr {
|
||||
// We allow arbitrary const expressions inside of associated consts,
|
||||
// even if they are potentially not const evaluatable.
|
||||
//
|
||||
// Type parameters can already be used and as associated consts are
|
||||
// not used as part of the type system, this is far less surprising.
|
||||
self.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| {
|
||||
this.with_constant_rib(
|
||||
IsRepeatExpr::No,
|
||||
ConstantHasGenerics::Yes,
|
||||
None,
|
||||
|this| this.visit_expr(expr),
|
||||
)
|
||||
});
|
||||
}
|
||||
self.with_generic_param_rib(
|
||||
&generics.params,
|
||||
RibKind::AssocItem,
|
||||
LifetimeRibKind::Generics {
|
||||
binder: item.id,
|
||||
span: generics.span,
|
||||
kind: LifetimeBinderKind::ConstItem,
|
||||
},
|
||||
|this| {
|
||||
// If this is a trait impl, ensure the const
|
||||
// exists in trait
|
||||
this.check_trait_item(
|
||||
item.id,
|
||||
item.ident,
|
||||
&item.kind,
|
||||
ValueNS,
|
||||
item.span,
|
||||
seen_trait_items,
|
||||
|i, s, c| ConstNotMemberOfTrait(i, s, c),
|
||||
);
|
||||
|
||||
this.visit_generics(generics);
|
||||
this.visit_ty(ty);
|
||||
if let Some(expr) = expr {
|
||||
// We allow arbitrary const expressions inside of associated consts,
|
||||
// even if they are potentially not const evaluatable.
|
||||
//
|
||||
// Type parameters can already be used and as associated consts are
|
||||
// not used as part of the type system, this is far less surprising.
|
||||
this.resolve_const_body(expr, None);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
AssocItemKind::Fn(box Fn { generics, .. }) => {
|
||||
debug!("resolve_implementation AssocItemKind::Fn");
|
||||
@ -3063,6 +3087,14 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|
||||
);
|
||||
}
|
||||
|
||||
fn resolve_const_body(&mut self, expr: &'ast Expr, item: Option<(Ident, ConstantItemKind)>) {
|
||||
self.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| {
|
||||
this.with_constant_rib(IsRepeatExpr::No, ConstantHasGenerics::Yes, item, |this| {
|
||||
this.visit_expr(expr)
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
fn resolve_params(&mut self, params: &'ast [Param]) {
|
||||
let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())];
|
||||
self.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| {
|
||||
@ -4448,6 +4480,7 @@ impl<'ast> Visitor<'ast> for LifetimeCountVisitor<'_, '_, '_> {
|
||||
fn visit_item(&mut self, item: &'ast Item) {
|
||||
match &item.kind {
|
||||
ItemKind::TyAlias(box TyAlias { ref generics, .. })
|
||||
| ItemKind::Const(box ConstItem { ref generics, .. })
|
||||
| ItemKind::Fn(box Fn { ref generics, .. })
|
||||
| ItemKind::Enum(_, ref generics)
|
||||
| ItemKind::Struct(_, ref generics)
|
||||
@ -4467,7 +4500,6 @@ impl<'ast> Visitor<'ast> for LifetimeCountVisitor<'_, '_, '_> {
|
||||
ItemKind::Mod(..)
|
||||
| ItemKind::ForeignMod(..)
|
||||
| ItemKind::Static(..)
|
||||
| ItemKind::Const(..)
|
||||
| ItemKind::Use(..)
|
||||
| ItemKind::ExternCrate(..)
|
||||
| ItemKind::MacroDef(..)
|
||||
|
@ -2348,6 +2348,14 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
|
||||
let mut should_continue = true;
|
||||
match rib.kind {
|
||||
LifetimeRibKind::Generics { binder: _, span, kind } => {
|
||||
// Avoid suggesting placing lifetime parameters on constant items unless the relevant
|
||||
// feature is enabled. Suggest the parent item as a possible location if applicable.
|
||||
if let LifetimeBinderKind::ConstItem = kind
|
||||
&& !self.r.tcx().features().generic_const_items
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if !span.can_be_used_for_suggestions() && suggest_note && let Some(name) = name {
|
||||
suggest_note = false; // Avoid displaying the same help multiple times.
|
||||
err.span_label(
|
||||
|
@ -783,6 +783,7 @@ symbols! {
|
||||
generic_associated_types,
|
||||
generic_associated_types_extended,
|
||||
generic_const_exprs,
|
||||
generic_const_items,
|
||||
generic_param_attrs,
|
||||
get_context,
|
||||
global_allocator,
|
||||
|
@ -655,6 +655,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||
| hir::ItemKind::Impl(hir::Impl { generics, .. })
|
||||
| hir::ItemKind::Fn(_, generics, _)
|
||||
| hir::ItemKind::TyAlias(_, generics)
|
||||
| hir::ItemKind::Const(_, generics, _)
|
||||
| hir::ItemKind::TraitAlias(generics, _)
|
||||
| hir::ItemKind::OpaqueTy(hir::OpaqueTy { generics, .. }),
|
||||
..
|
||||
@ -720,6 +721,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
||||
| hir::ItemKind::Impl(hir::Impl { generics, .. })
|
||||
| hir::ItemKind::Fn(_, generics, _)
|
||||
| hir::ItemKind::TyAlias(_, generics)
|
||||
| hir::ItemKind::Const(_, generics, _)
|
||||
| hir::ItemKind::TraitAlias(generics, _)
|
||||
| hir::ItemKind::OpaqueTy(hir::OpaqueTy { generics, .. }),
|
||||
..
|
||||
|
@ -644,6 +644,10 @@ pub(crate) fn print_inlined_const(tcx: TyCtxt<'_>, did: DefId) -> String {
|
||||
}
|
||||
|
||||
fn build_const(cx: &mut DocContext<'_>, def_id: DefId) -> clean::Constant {
|
||||
let mut generics =
|
||||
clean_ty_generics(cx, cx.tcx.generics_of(def_id), cx.tcx.explicit_predicates_of(def_id));
|
||||
clean::simplify::move_bounds_to_generic_parameters(&mut generics);
|
||||
|
||||
clean::Constant {
|
||||
type_: clean_middle_ty(
|
||||
ty::Binder::dummy(cx.tcx.type_of(def_id).instantiate_identity()),
|
||||
@ -651,6 +655,7 @@ fn build_const(cx: &mut DocContext<'_>, def_id: DefId) -> clean::Constant {
|
||||
Some(def_id),
|
||||
None,
|
||||
),
|
||||
generics: Box::new(generics),
|
||||
kind: clean::ConstantKind::Extern { def_id },
|
||||
}
|
||||
}
|
||||
|
@ -273,6 +273,7 @@ pub(crate) fn clean_const<'tcx>(constant: &hir::ConstArg, cx: &mut DocContext<'t
|
||||
Some(def_id),
|
||||
None,
|
||||
),
|
||||
generics: Box::new(Generics::default()),
|
||||
kind: ConstantKind::Anonymous { body: constant.value.body },
|
||||
}
|
||||
}
|
||||
@ -284,6 +285,7 @@ pub(crate) fn clean_middle_const<'tcx>(
|
||||
// FIXME: instead of storing the stringified expression, store `self` directly instead.
|
||||
Constant {
|
||||
type_: clean_middle_ty(constant.map_bound(|c| c.ty()), cx, None, None),
|
||||
generics: Box::new(Generics::default()),
|
||||
kind: ConstantKind::TyConst { expr: constant.skip_binder().to_string().into() },
|
||||
}
|
||||
}
|
||||
@ -1188,11 +1190,18 @@ fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext
|
||||
let local_did = trait_item.owner_id.to_def_id();
|
||||
cx.with_param_env(local_did, |cx| {
|
||||
let inner = match trait_item.kind {
|
||||
hir::TraitItemKind::Const(ty, Some(default)) => AssocConstItem(
|
||||
clean_ty(ty, cx),
|
||||
ConstantKind::Local { def_id: local_did, body: default },
|
||||
),
|
||||
hir::TraitItemKind::Const(ty, None) => TyAssocConstItem(clean_ty(ty, cx)),
|
||||
hir::TraitItemKind::Const(ty, Some(default)) => {
|
||||
let generics = enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx));
|
||||
AssocConstItem(
|
||||
Box::new(generics),
|
||||
clean_ty(ty, cx),
|
||||
ConstantKind::Local { def_id: local_did, body: default },
|
||||
)
|
||||
}
|
||||
hir::TraitItemKind::Const(ty, None) => {
|
||||
let generics = enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx));
|
||||
TyAssocConstItem(Box::new(generics), clean_ty(ty, cx))
|
||||
}
|
||||
hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
|
||||
let m = clean_function(cx, sig, trait_item.generics, FunctionArgs::Body(body));
|
||||
MethodItem(m, None)
|
||||
@ -1237,8 +1246,9 @@ pub(crate) fn clean_impl_item<'tcx>(
|
||||
cx.with_param_env(local_did, |cx| {
|
||||
let inner = match impl_.kind {
|
||||
hir::ImplItemKind::Const(ty, expr) => {
|
||||
let generics = clean_generics(impl_.generics, cx);
|
||||
let default = ConstantKind::Local { def_id: local_did, body: expr };
|
||||
AssocConstItem(clean_ty(ty, cx), default)
|
||||
AssocConstItem(Box::new(generics), clean_ty(ty, cx), default)
|
||||
}
|
||||
hir::ImplItemKind::Fn(ref sig, body) => {
|
||||
let m = clean_function(cx, sig, impl_.generics, FunctionArgs::Body(body));
|
||||
@ -1279,14 +1289,21 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
|
||||
None,
|
||||
);
|
||||
|
||||
let mut generics = Box::new(clean_ty_generics(
|
||||
cx,
|
||||
tcx.generics_of(assoc_item.def_id),
|
||||
tcx.explicit_predicates_of(assoc_item.def_id),
|
||||
));
|
||||
simplify::move_bounds_to_generic_parameters(&mut generics);
|
||||
|
||||
let provided = match assoc_item.container {
|
||||
ty::ImplContainer => true,
|
||||
ty::TraitContainer => tcx.defaultness(assoc_item.def_id).has_value(),
|
||||
};
|
||||
if provided {
|
||||
AssocConstItem(ty, ConstantKind::Extern { def_id: assoc_item.def_id })
|
||||
AssocConstItem(generics, ty, ConstantKind::Extern { def_id: assoc_item.def_id })
|
||||
} else {
|
||||
TyAssocConstItem(ty)
|
||||
TyAssocConstItem(generics, ty)
|
||||
}
|
||||
}
|
||||
ty::AssocKind::Fn => {
|
||||
@ -1379,34 +1396,7 @@ pub(crate) fn clean_middle_assoc_item<'tcx>(
|
||||
tcx.generics_of(assoc_item.def_id),
|
||||
ty::GenericPredicates { parent: None, predicates },
|
||||
);
|
||||
// Move bounds that are (likely) directly attached to the parameters of the
|
||||
// (generic) associated type from the where clause to the respective parameter.
|
||||
// There is no guarantee that this is what the user actually wrote but we have
|
||||
// no way of knowing.
|
||||
let mut where_predicates = ThinVec::new();
|
||||
for mut pred in generics.where_predicates {
|
||||
if let WherePredicate::BoundPredicate { ty: Generic(arg), bounds, .. } = &mut pred
|
||||
&& let Some(GenericParamDef {
|
||||
kind: GenericParamDefKind::Type { bounds: param_bounds, .. },
|
||||
..
|
||||
}) = generics.params.iter_mut().find(|param| ¶m.name == arg)
|
||||
{
|
||||
param_bounds.append(bounds);
|
||||
} else if let WherePredicate::RegionPredicate { lifetime: Lifetime(arg), bounds } = &mut pred
|
||||
&& let Some(GenericParamDef {
|
||||
kind: GenericParamDefKind::Lifetime { outlives: param_bounds },
|
||||
..
|
||||
}) = generics.params.iter_mut().find(|param| ¶m.name == arg)
|
||||
{
|
||||
param_bounds.extend(bounds.drain(..).map(|bound| match bound {
|
||||
GenericBound::Outlives(lifetime) => lifetime,
|
||||
_ => unreachable!(),
|
||||
}));
|
||||
} else {
|
||||
where_predicates.push(pred);
|
||||
}
|
||||
}
|
||||
generics.where_predicates = where_predicates;
|
||||
simplify::move_bounds_to_generic_parameters(&mut generics);
|
||||
|
||||
if let ty::TraitContainer = assoc_item.container {
|
||||
// Move bounds that are (likely) directly attached to the associated type
|
||||
@ -2603,8 +2593,9 @@ fn clean_maybe_renamed_item<'tcx>(
|
||||
ItemKind::Static(ty, mutability, body_id) => {
|
||||
StaticItem(Static { type_: clean_ty(ty, cx), mutability, expr: Some(body_id) })
|
||||
}
|
||||
ItemKind::Const(ty, body_id) => ConstantItem(Constant {
|
||||
ItemKind::Const(ty, generics, body_id) => ConstantItem(Constant {
|
||||
type_: clean_ty(ty, cx),
|
||||
generics: Box::new(clean_generics(generics, cx)),
|
||||
kind: ConstantKind::Local { body: body_id, def_id },
|
||||
}),
|
||||
ItemKind::OpaqueTy(ref ty) => OpaqueTyItem(OpaqueTy {
|
||||
|
@ -138,3 +138,38 @@ fn trait_is_same_or_supertrait(cx: &DocContext<'_>, child: DefId, trait_: DefId)
|
||||
})
|
||||
.any(|did| trait_is_same_or_supertrait(cx, did, trait_))
|
||||
}
|
||||
|
||||
/// Move bounds that are (likely) directly attached to generic parameters from the where-clause to
|
||||
/// the respective parameter.
|
||||
///
|
||||
/// There is no guarantee that this is what the user actually wrote but we have no way of knowing.
|
||||
// FIXME(fmease): It'd make a lot of sense to just incorporate this logic into `clean_ty_generics`
|
||||
// making every of its users benefit from it.
|
||||
pub(crate) fn move_bounds_to_generic_parameters(generics: &mut clean::Generics) {
|
||||
use clean::types::*;
|
||||
|
||||
let mut where_predicates = ThinVec::new();
|
||||
for mut pred in generics.where_predicates.drain(..) {
|
||||
if let WherePredicate::BoundPredicate { ty: Generic(arg), bounds, .. } = &mut pred
|
||||
&& let Some(GenericParamDef {
|
||||
kind: GenericParamDefKind::Type { bounds: param_bounds, .. },
|
||||
..
|
||||
}) = generics.params.iter_mut().find(|param| ¶m.name == arg)
|
||||
{
|
||||
param_bounds.append(bounds);
|
||||
} else if let WherePredicate::RegionPredicate { lifetime: Lifetime(arg), bounds } = &mut pred
|
||||
&& let Some(GenericParamDef {
|
||||
kind: GenericParamDefKind::Lifetime { outlives: param_bounds },
|
||||
..
|
||||
}) = generics.params.iter_mut().find(|param| ¶m.name == arg)
|
||||
{
|
||||
param_bounds.extend(bounds.drain(..).map(|bound| match bound {
|
||||
GenericBound::Outlives(lifetime) => lifetime,
|
||||
_ => unreachable!(),
|
||||
}));
|
||||
} else {
|
||||
where_predicates.push(pred);
|
||||
}
|
||||
}
|
||||
generics.where_predicates = where_predicates;
|
||||
}
|
||||
|
@ -824,9 +824,9 @@ pub(crate) enum ItemKind {
|
||||
ProcMacroItem(ProcMacro),
|
||||
PrimitiveItem(PrimitiveType),
|
||||
/// A required associated constant in a trait declaration.
|
||||
TyAssocConstItem(Type),
|
||||
TyAssocConstItem(Box<Generics>, Type),
|
||||
/// An associated constant in a trait impl or a provided one in a trait declaration.
|
||||
AssocConstItem(Type, ConstantKind),
|
||||
AssocConstItem(Box<Generics>, Type, ConstantKind),
|
||||
/// A required associated type in a trait declaration.
|
||||
///
|
||||
/// The bounds may be non-empty if there is a `where` clause.
|
||||
@ -871,8 +871,8 @@ impl ItemKind {
|
||||
| MacroItem(_)
|
||||
| ProcMacroItem(_)
|
||||
| PrimitiveItem(_)
|
||||
| TyAssocConstItem(_)
|
||||
| AssocConstItem(_, _)
|
||||
| TyAssocConstItem(..)
|
||||
| AssocConstItem(..)
|
||||
| TyAssocTypeItem(..)
|
||||
| AssocTypeItem(..)
|
||||
| StrippedItem(_)
|
||||
@ -1278,7 +1278,7 @@ impl Lifetime {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
|
||||
pub(crate) enum WherePredicate {
|
||||
BoundPredicate { ty: Type, bounds: Vec<GenericBound>, bound_params: Vec<GenericParamDef> },
|
||||
RegionPredicate { lifetime: Lifetime, bounds: Vec<GenericBound> },
|
||||
@ -1348,7 +1348,7 @@ impl GenericParamDef {
|
||||
}
|
||||
|
||||
// maybe use a Generic enum and use Vec<Generic>?
|
||||
#[derive(Clone, Debug, Default)]
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Debug, Default)]
|
||||
pub(crate) struct Generics {
|
||||
pub(crate) params: ThinVec<GenericParamDef>,
|
||||
pub(crate) where_predicates: ThinVec<WherePredicate>,
|
||||
@ -2266,6 +2266,7 @@ pub(crate) struct Static {
|
||||
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
|
||||
pub(crate) struct Constant {
|
||||
pub(crate) type_: Type,
|
||||
pub(crate) generics: Box<Generics>,
|
||||
pub(crate) kind: ConstantKind,
|
||||
}
|
||||
|
||||
@ -2515,7 +2516,8 @@ mod size_asserts {
|
||||
static_assert_size!(GenericParamDef, 56);
|
||||
static_assert_size!(Generics, 16);
|
||||
static_assert_size!(Item, 56);
|
||||
static_assert_size!(ItemKind, 64);
|
||||
// FIXME(generic_const_items): Further reduce the size.
|
||||
static_assert_size!(ItemKind, 72);
|
||||
static_assert_size!(PathSegment, 40);
|
||||
static_assert_size!(Type, 32);
|
||||
// tidy-alphabetical-end
|
||||
|
@ -748,20 +748,22 @@ fn assoc_href_attr(it: &clean::Item, link: AssocItemLink<'_>, cx: &Context<'_>)
|
||||
fn assoc_const(
|
||||
w: &mut Buffer,
|
||||
it: &clean::Item,
|
||||
generics: &clean::Generics,
|
||||
ty: &clean::Type,
|
||||
default: Option<&clean::ConstantKind>,
|
||||
link: AssocItemLink<'_>,
|
||||
extra: &str,
|
||||
indent: usize,
|
||||
cx: &Context<'_>,
|
||||
) {
|
||||
let tcx = cx.tcx();
|
||||
write!(
|
||||
w,
|
||||
"{extra}{vis}const <a{href} class=\"constant\">{name}</a>: {ty}",
|
||||
extra = extra,
|
||||
"{indent}{vis}const <a{href} class=\"constant\">{name}</a>{generics}: {ty}",
|
||||
indent = " ".repeat(indent),
|
||||
vis = visibility_print_with_space(it.visibility(tcx), it.item_id, cx),
|
||||
href = assoc_href_attr(it, link, cx),
|
||||
name = it.name.as_ref().unwrap(),
|
||||
generics = generics.print(cx),
|
||||
ty = ty.print(cx),
|
||||
);
|
||||
if let Some(default) = default {
|
||||
@ -774,6 +776,7 @@ fn assoc_const(
|
||||
// Find a way to print constants here without all that jazz.
|
||||
write!(w, "{}", Escape(&default.value(tcx).unwrap_or_else(|| default.expr(tcx))));
|
||||
}
|
||||
write!(w, "{}", print_where_clause(generics, cx, indent, Ending::NoNewline));
|
||||
}
|
||||
|
||||
fn assoc_type(
|
||||
@ -986,19 +989,22 @@ fn render_assoc_item(
|
||||
clean::MethodItem(m, _) => {
|
||||
assoc_method(w, item, &m.generics, &m.decl, link, parent, cx, render_mode)
|
||||
}
|
||||
kind @ (clean::TyAssocConstItem(ty) | clean::AssocConstItem(ty, _)) => assoc_const(
|
||||
w,
|
||||
item,
|
||||
ty,
|
||||
match kind {
|
||||
clean::TyAssocConstItem(_) => None,
|
||||
clean::AssocConstItem(_, default) => Some(default),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
link,
|
||||
if parent == ItemType::Trait { " " } else { "" },
|
||||
cx,
|
||||
),
|
||||
kind @ (clean::TyAssocConstItem(generics, ty) | clean::AssocConstItem(generics, ty, _)) => {
|
||||
assoc_const(
|
||||
w,
|
||||
item,
|
||||
generics,
|
||||
ty,
|
||||
match kind {
|
||||
clean::TyAssocConstItem(..) => None,
|
||||
clean::AssocConstItem(.., default) => Some(default),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
link,
|
||||
if parent == ItemType::Trait { 4 } else { 0 },
|
||||
cx,
|
||||
)
|
||||
}
|
||||
clean::TyAssocTypeItem(ref generics, ref bounds) => assoc_type(
|
||||
w,
|
||||
item,
|
||||
@ -1565,7 +1571,8 @@ fn render_impl(
|
||||
w.write_str("</section>");
|
||||
}
|
||||
}
|
||||
kind @ (clean::TyAssocConstItem(ty) | clean::AssocConstItem(ty, _)) => {
|
||||
kind @ (clean::TyAssocConstItem(generics, ty)
|
||||
| clean::AssocConstItem(generics, ty, _)) => {
|
||||
let source_id = format!("{}.{}", item_type, name);
|
||||
let id = cx.derive_id(source_id.clone());
|
||||
write!(w, "<section id=\"{}\" class=\"{}{}\">", id, item_type, in_trait_class);
|
||||
@ -1578,14 +1585,15 @@ fn render_impl(
|
||||
assoc_const(
|
||||
w,
|
||||
item,
|
||||
generics,
|
||||
ty,
|
||||
match kind {
|
||||
clean::TyAssocConstItem(_) => None,
|
||||
clean::AssocConstItem(_, default) => Some(default),
|
||||
clean::TyAssocConstItem(..) => None,
|
||||
clean::AssocConstItem(.., default) => Some(default),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
link.anchor(if trait_.is_some() { &source_id } else { &id }),
|
||||
"",
|
||||
0,
|
||||
cx,
|
||||
);
|
||||
w.write_str("</h4>");
|
||||
|
@ -1543,10 +1543,12 @@ fn item_constant(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, c: &cle
|
||||
|
||||
write!(
|
||||
w,
|
||||
"{vis}const {name}: {typ}",
|
||||
"{vis}const {name}{generics}: {typ}{where_clause}",
|
||||
vis = visibility_print_with_space(it.visibility(tcx), it.item_id, cx),
|
||||
name = it.name.unwrap(),
|
||||
generics = c.generics.print(cx),
|
||||
typ = c.type_.print(cx),
|
||||
where_clause = print_where_clause(&c.generics, cx, 0, Ending::NoNewline),
|
||||
);
|
||||
|
||||
// FIXME: The code below now prints
|
||||
|
@ -219,7 +219,7 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> {
|
||||
fn visit_item(&mut self, item: &'tcx Item<'tcx>) {
|
||||
match item.kind {
|
||||
ItemKind::Static(_, _, _)
|
||||
| ItemKind::Const(_, _)
|
||||
| ItemKind::Const(_, _, _)
|
||||
| ItemKind::Fn(_, _, _)
|
||||
| ItemKind::Macro(_, _)
|
||||
| ItemKind::TyAlias(_, _)
|
||||
|
@ -171,6 +171,7 @@ impl FromWithTcx<clean::GenericArg> for GenericArg {
|
||||
}
|
||||
|
||||
impl FromWithTcx<clean::Constant> for Constant {
|
||||
// FIXME(generic_const_items): Add support for generic const items.
|
||||
fn from_tcx(constant: clean::Constant, tcx: TyCtxt<'_>) -> Self {
|
||||
let expr = constant.expr(tcx);
|
||||
let value = constant.value(tcx);
|
||||
@ -321,8 +322,12 @@ fn from_clean_item(item: clean::Item, tcx: TyCtxt<'_>) -> ItemEnum {
|
||||
impls: Vec::new(), // Added in JsonRenderer::item
|
||||
})
|
||||
}
|
||||
TyAssocConstItem(ty) => ItemEnum::AssocConst { type_: ty.into_tcx(tcx), default: None },
|
||||
AssocConstItem(ty, default) => {
|
||||
// FIXME(generic_const_items): Add support for generic associated consts.
|
||||
TyAssocConstItem(_generics, ty) => {
|
||||
ItemEnum::AssocConst { type_: ty.into_tcx(tcx), default: None }
|
||||
}
|
||||
// FIXME(generic_const_items): Add support for generic associated consts.
|
||||
AssocConstItem(_generics, ty, default) => {
|
||||
ItemEnum::AssocConst { type_: ty.into_tcx(tcx), default: Some(default.expr(tcx)) }
|
||||
}
|
||||
TyAssocTypeItem(g, b) => ItemEnum::AssocType {
|
||||
|
@ -50,7 +50,11 @@ impl<'tcx> LateLintPass<'tcx> for LargeConstArrays {
|
||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
|
||||
if_chain! {
|
||||
if !item.span.from_expansion();
|
||||
if let ItemKind::Const(hir_ty, _) = &item.kind;
|
||||
if let ItemKind::Const(hir_ty, generics, _) = &item.kind;
|
||||
// Since static items may not have generics, skip generic const items.
|
||||
// FIXME(generic_const_items): I don't think checking `generics.hwcp` suffices as it
|
||||
// doesn't account for empty where-clauses that only consist of keyword `where` IINM.
|
||||
if generics.params.is_empty() && !generics.has_where_clause_predicates;
|
||||
let ty = hir_ty_to_ty(cx.tcx, hir_ty);
|
||||
if let ty::Array(element_type, cst) = ty.kind();
|
||||
if let ConstKind::Value(ty::ValTree::Leaf(element_count)) = cst.kind();
|
||||
|
@ -302,7 +302,7 @@ declare_lint_pass!(NonCopyConst => [DECLARE_INTERIOR_MUTABLE_CONST, BORROW_INTER
|
||||
|
||||
impl<'tcx> LateLintPass<'tcx> for NonCopyConst {
|
||||
fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx Item<'_>) {
|
||||
if let ItemKind::Const(hir_ty, body_id) = it.kind {
|
||||
if let ItemKind::Const(hir_ty, _generics, body_id) = it.kind {
|
||||
let ty = hir_ty_to_ty(cx.tcx, hir_ty);
|
||||
if !ignored_macro(cx, it) && is_unfrozen(cx, ty) && is_value_unfrozen_poly(cx, body_id, ty) {
|
||||
lint(cx, Source::Item { item: it.span });
|
||||
|
@ -349,7 +349,7 @@ impl<'tcx> LateLintPass<'tcx> for Types {
|
||||
let is_exported = cx.effective_visibilities.is_exported(item.owner_id.def_id);
|
||||
|
||||
match item.kind {
|
||||
ItemKind::Static(ty, _, _) | ItemKind::Const(ty, _) => self.check_ty(
|
||||
ItemKind::Static(ty, _, _) | ItemKind::Const(ty, _, _) => self.check_ty(
|
||||
cx,
|
||||
ty,
|
||||
CheckTyContext {
|
||||
|
@ -301,15 +301,17 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
|
||||
(
|
||||
Const(box ast::ConstItem {
|
||||
defaultness: ld,
|
||||
generics: lg,
|
||||
ty: lt,
|
||||
expr: le,
|
||||
}),
|
||||
Const(box ast::ConstItem {
|
||||
defaultness: rd,
|
||||
generics: rg,
|
||||
ty: rt,
|
||||
expr: re,
|
||||
}),
|
||||
) => eq_defaultness(*ld, *rd) && eq_ty(lt, rt) && eq_expr_opt(le, re),
|
||||
) => eq_defaultness(*ld, *rd) && eq_generics(lg, rg) && eq_ty(lt, rt) && eq_expr_opt(le, re),
|
||||
(
|
||||
Fn(box ast::Fn {
|
||||
defaultness: ld,
|
||||
@ -476,15 +478,17 @@ pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool {
|
||||
(
|
||||
Const(box ast::ConstItem {
|
||||
defaultness: ld,
|
||||
generics: lg,
|
||||
ty: lt,
|
||||
expr: le,
|
||||
}),
|
||||
Const(box ast::ConstItem {
|
||||
defaultness: rd,
|
||||
generics: rg,
|
||||
ty: rt,
|
||||
expr: re,
|
||||
}),
|
||||
) => eq_defaultness(*ld, *rd) && eq_ty(lt, rt) && eq_expr_opt(le, re),
|
||||
) => eq_defaultness(*ld, *rd) && eq_generics(lg, rg) && eq_ty(lt, rt) && eq_expr_opt(le, re),
|
||||
(
|
||||
Fn(box ast::Fn {
|
||||
defaultness: ld,
|
||||
|
@ -461,7 +461,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
|
||||
// Check if this constant is based on `cfg!(..)`,
|
||||
// which is NOT constant for our purposes.
|
||||
if let Some(node) = self.lcx.tcx.hir().get_if_local(def_id)
|
||||
&& let Node::Item(Item { kind: ItemKind::Const(_, body_id), .. }) = node
|
||||
&& let Node::Item(Item { kind: ItemKind::Const(.., body_id), .. }) = node
|
||||
&& let Node::Expr(Expr { kind: ExprKind::Lit(_), span, .. }) = self.lcx
|
||||
.tcx
|
||||
.hir()
|
||||
|
@ -2380,7 +2380,7 @@ fn with_test_item_names(tcx: TyCtxt<'_>, module: LocalDefId, f: impl Fn(&[Symbol
|
||||
for id in tcx.hir().module_items(module) {
|
||||
if matches!(tcx.def_kind(id.owner_id), DefKind::Const)
|
||||
&& let item = tcx.hir().item(id)
|
||||
&& let ItemKind::Const(ty, _body) = item.kind {
|
||||
&& let ItemKind::Const(ty, _generics, _body) = item.kind {
|
||||
if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind {
|
||||
// We could also check for the type name `test::TestDescAndFn`
|
||||
if let Res::Def(DefKind::Struct, _) = path.res {
|
||||
|
@ -11,7 +11,7 @@ use std::path::{Path, PathBuf};
|
||||
const ENTRY_LIMIT: usize = 900;
|
||||
// FIXME: The following limits should be reduced eventually.
|
||||
const ISSUES_ENTRY_LIMIT: usize = 1893;
|
||||
const ROOT_ENTRY_LIMIT: usize = 871;
|
||||
const ROOT_ENTRY_LIMIT: usize = 872;
|
||||
|
||||
const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[
|
||||
"rs", // test source files
|
||||
|
38
tests/rustdoc/generic-const-items.rs
Normal file
38
tests/rustdoc/generic-const-items.rs
Normal file
@ -0,0 +1,38 @@
|
||||
#![feature(generic_const_items)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
// @has 'generic_const_items/constant.K.html'
|
||||
// @has - '//*[@class="rust item-decl"]//code' \
|
||||
// "pub const K<'a, T: 'a + Copy, const N: usize>: Option<[T; N]> \
|
||||
// where \
|
||||
// String: From<T>;"
|
||||
pub const K<'a, T: 'a + Copy, const N: usize>: Option<[T; N]> = None
|
||||
where
|
||||
String: From<T>;
|
||||
|
||||
// @has generic_const_items/trait.Trait.html
|
||||
pub trait Trait<T: ?Sized> {
|
||||
// @has - '//*[@id="associatedconstant.C"]' \
|
||||
// "const C<'a>: &'a T \
|
||||
// where \
|
||||
// T: 'a + Eq"
|
||||
const C<'a>: &'a T
|
||||
where
|
||||
T: 'a + Eq;
|
||||
}
|
||||
|
||||
pub struct Implementor;
|
||||
|
||||
// @has generic_const_items/struct.Implementor.html
|
||||
// @has - '//h3[@class="code-header"]' 'impl Trait<str> for Implementor'
|
||||
impl Trait<str> for Implementor {
|
||||
// @has - '//*[@id="associatedconstant.C"]' \
|
||||
// "const C<'a>: &'a str = \"C\" \
|
||||
// where \
|
||||
// str: 'a"
|
||||
const C<'a>: &'a str = "C"
|
||||
// In real code we could've left off this bound but adding it explicitly allows us to test if
|
||||
// we render where-clauses on associated consts inside impl blocks correctly.
|
||||
where
|
||||
str: 'a;
|
||||
}
|
22
tests/rustdoc/inline_cross/auxiliary/generic-const-items.rs
Normal file
22
tests/rustdoc/inline_cross/auxiliary/generic-const-items.rs
Normal file
@ -0,0 +1,22 @@
|
||||
#![feature(generic_const_items)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
pub const K<'a, T: 'a + Copy, const N: usize>: Option<[T; N]> = None
|
||||
where
|
||||
String: From<T>;
|
||||
|
||||
pub trait Trait<T: ?Sized> {
|
||||
const C<'a>: &'a T
|
||||
where
|
||||
T: 'a + Eq;
|
||||
}
|
||||
|
||||
pub struct Implementor;
|
||||
|
||||
impl Trait<str> for Implementor {
|
||||
const C<'a>: &'a str = "C"
|
||||
// In real code we could've left off this bound but adding it explicitly allows us to test if
|
||||
// we render where-clauses on associated consts inside impl blocks correctly.
|
||||
where
|
||||
str: 'a;
|
||||
}
|
26
tests/rustdoc/inline_cross/generic-const-items.rs
Normal file
26
tests/rustdoc/inline_cross/generic-const-items.rs
Normal file
@ -0,0 +1,26 @@
|
||||
#![crate_name = "user"]
|
||||
|
||||
// aux-crate:generic_const_items=generic-const-items.rs
|
||||
// edition:2021
|
||||
|
||||
// @has 'user/constant.K.html'
|
||||
// @has - '//*[@class="rust item-decl"]//code' \
|
||||
// "pub const K<'a, T: 'a + Copy, const N: usize>: Option<[T; N]> \
|
||||
// where \
|
||||
// String: From<T>;"
|
||||
pub use generic_const_items::K;
|
||||
|
||||
// @has user/trait.Trait.html
|
||||
// @has - '//*[@id="associatedconstant.C"]' \
|
||||
// "const C<'a>: &'a T \
|
||||
// where \
|
||||
// T: 'a + Eq"
|
||||
pub use generic_const_items::Trait;
|
||||
|
||||
// @has user/struct.Implementor.html
|
||||
// @has - '//h3[@class="code-header"]' 'impl Trait<str> for Implementor'
|
||||
// @has - '//*[@id="associatedconstant.C"]' \
|
||||
// "const C<'a>: &'a str = \"C\" \
|
||||
// where \
|
||||
// str: 'a"
|
||||
pub use generic_const_items::Implementor;
|
22
tests/ui/generic-const-items/associated-const-equality.rs
Normal file
22
tests/ui/generic-const-items/associated-const-equality.rs
Normal file
@ -0,0 +1,22 @@
|
||||
// check-pass
|
||||
|
||||
#![feature(generic_const_items, associated_const_equality)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
trait Owner {
|
||||
const C<const N: u32>: u32;
|
||||
const K<const N: u32>: u32;
|
||||
}
|
||||
|
||||
impl Owner for () {
|
||||
const C<const N: u32>: u32 = N;
|
||||
const K<const N: u32>: u32 = N + 1;
|
||||
}
|
||||
|
||||
fn take0<const N: u32>(_: impl Owner<C<N> = { N }>) {}
|
||||
fn take1(_: impl Owner<K<99> = 100>) {}
|
||||
|
||||
fn main() {
|
||||
take0::<128>(());
|
||||
take1(());
|
||||
}
|
61
tests/ui/generic-const-items/basic.rs
Normal file
61
tests/ui/generic-const-items/basic.rs
Normal file
@ -0,0 +1,61 @@
|
||||
// check-pass
|
||||
|
||||
// Basic usage patterns of free & associated generic const items.
|
||||
|
||||
#![feature(generic_const_items)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
fn main() {
|
||||
const NULL<T>: Option<T> = None::<T>;
|
||||
const NOTHING<T>: Option<T> = None; // arg inferred
|
||||
|
||||
let _ = NOTHING::<String>;
|
||||
let _: Option<u8> = NULL; // arg inferred
|
||||
|
||||
const IDENTITY<const X: u64>: u64 = X;
|
||||
|
||||
const COUNT: u64 = IDENTITY::<48>;
|
||||
const AMOUNT: u64 = IDENTITY::<COUNT>;
|
||||
const NUMBER: u64 = IDENTITY::<{ AMOUNT * 2 }>;
|
||||
let _ = NUMBER;
|
||||
let _ = IDENTITY::<0>;
|
||||
|
||||
let _ = match 0 {
|
||||
IDENTITY::<1> => 2,
|
||||
IDENTITY::<{ 1 + 1 }> => 4,
|
||||
_ => 0,
|
||||
};
|
||||
|
||||
const CREATE<I: Inhabited>: I = I::PROOF;
|
||||
let _ = CREATE::<u64>;
|
||||
let _: u64 = CREATE; // arg inferred
|
||||
|
||||
let _ = <() as Main<u64>>::MAKE::<u64>;
|
||||
let _: (u64, u64) = <()>::MAKE; // args inferred
|
||||
}
|
||||
|
||||
pub fn usage<'any>() {
|
||||
const REGION_POLY<'a>: &'a () = &();
|
||||
|
||||
let _: &'any () = REGION_POLY::<'any>;
|
||||
let _: &'any () = REGION_POLY::<'_>;
|
||||
let _: &'static () = REGION_POLY;
|
||||
}
|
||||
|
||||
trait Main<O> {
|
||||
type Output<I>;
|
||||
const MAKE<I: Inhabited>: Self::Output<I>;
|
||||
}
|
||||
|
||||
impl<O: Inhabited> Main<O> for () {
|
||||
type Output<I> = (O, I);
|
||||
const MAKE<I: Inhabited>: Self::Output<I> = (O::PROOF, I::PROOF);
|
||||
}
|
||||
|
||||
trait Inhabited {
|
||||
const PROOF: Self;
|
||||
}
|
||||
|
||||
impl Inhabited for u64 {
|
||||
const PROOF: Self = 512;
|
||||
}
|
30
tests/ui/generic-const-items/compare-impl-item.rs
Normal file
30
tests/ui/generic-const-items/compare-impl-item.rs
Normal file
@ -0,0 +1,30 @@
|
||||
#![feature(generic_const_items)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
trait Trait<P> {
|
||||
const A: ();
|
||||
const B<const K: u64, const Q: u64>: u64;
|
||||
const C<T>: T;
|
||||
const D<const N: usize>: usize;
|
||||
|
||||
const E: usize;
|
||||
const F<T: PartialEq>: ();
|
||||
}
|
||||
|
||||
impl<P> Trait<P> for () {
|
||||
const A<T>: () = ();
|
||||
//~^ ERROR const `A` has 1 type parameter but its trait declaration has 0 type parameters
|
||||
const B<const K: u64>: u64 = 0;
|
||||
//~^ ERROR const `B` has 1 const parameter but its trait declaration has 2 const parameters
|
||||
const C<'a>: &'a str = "";
|
||||
//~^ ERROR const `C` has 0 type parameters but its trait declaration has 1 type parameter
|
||||
const D<const N: u16>: u16 = N;
|
||||
//~^ ERROR const `D` has an incompatible generic parameter for trait `Trait`
|
||||
|
||||
const E: usize = 1024
|
||||
where
|
||||
P: Copy; //~ ERROR impl has stricter requirements than trait
|
||||
const F<T: Eq>: () = (); //~ ERROR impl has stricter requirements than trait
|
||||
}
|
||||
|
||||
fn main() {}
|
66
tests/ui/generic-const-items/compare-impl-item.stderr
Normal file
66
tests/ui/generic-const-items/compare-impl-item.stderr
Normal file
@ -0,0 +1,66 @@
|
||||
error[E0049]: const `A` has 1 type parameter but its trait declaration has 0 type parameters
|
||||
--> $DIR/compare-impl-item.rs:15:13
|
||||
|
|
||||
LL | const A: ();
|
||||
| - expected 0 type parameters
|
||||
...
|
||||
LL | const A<T>: () = ();
|
||||
| ^ found 1 type parameter
|
||||
|
||||
error[E0049]: const `B` has 1 const parameter but its trait declaration has 2 const parameters
|
||||
--> $DIR/compare-impl-item.rs:17:13
|
||||
|
|
||||
LL | const B<const K: u64, const Q: u64>: u64;
|
||||
| ------------ ------------
|
||||
| |
|
||||
| expected 2 const parameters
|
||||
...
|
||||
LL | const B<const K: u64>: u64 = 0;
|
||||
| ^^^^^^^^^^^^ found 1 const parameter
|
||||
|
||||
error[E0049]: const `C` has 0 type parameters but its trait declaration has 1 type parameter
|
||||
--> $DIR/compare-impl-item.rs:19:13
|
||||
|
|
||||
LL | const C<T>: T;
|
||||
| - expected 1 type parameter
|
||||
...
|
||||
LL | const C<'a>: &'a str = "";
|
||||
| ^^ found 0 type parameters
|
||||
|
||||
error[E0053]: const `D` has an incompatible generic parameter for trait `Trait`
|
||||
--> $DIR/compare-impl-item.rs:21:13
|
||||
|
|
||||
LL | trait Trait<P> {
|
||||
| -----
|
||||
...
|
||||
LL | const D<const N: usize>: usize;
|
||||
| -------------- expected const parameter of type `usize`
|
||||
...
|
||||
LL | impl<P> Trait<P> for () {
|
||||
| -----------------------
|
||||
...
|
||||
LL | const D<const N: u16>: u16 = N;
|
||||
| ^^^^^^^^^^^^ found const parameter of type `u16`
|
||||
|
||||
error[E0276]: impl has stricter requirements than trait
|
||||
--> $DIR/compare-impl-item.rs:26:12
|
||||
|
|
||||
LL | const E: usize;
|
||||
| -------------- definition of `E` from trait
|
||||
...
|
||||
LL | P: Copy;
|
||||
| ^^^^ impl has extra requirement `P: Copy`
|
||||
|
||||
error[E0276]: impl has stricter requirements than trait
|
||||
--> $DIR/compare-impl-item.rs:27:16
|
||||
|
|
||||
LL | const F<T: PartialEq>: ();
|
||||
| ------------------------- definition of `F` from trait
|
||||
...
|
||||
LL | const F<T: Eq>: () = ();
|
||||
| ^^ impl has extra requirement `T: Eq`
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0049, E0053, E0276.
|
||||
For more information about an error, try `rustc --explain E0049`.
|
24
tests/ui/generic-const-items/const-trait-impl.rs
Normal file
24
tests/ui/generic-const-items/const-trait-impl.rs
Normal file
@ -0,0 +1,24 @@
|
||||
// check-pass
|
||||
|
||||
// Test that we can call methods from const trait impls inside of generic const items.
|
||||
|
||||
#![feature(generic_const_items, const_trait_impl)]
|
||||
#![allow(incomplete_features)]
|
||||
#![crate_type = "lib"]
|
||||
|
||||
// FIXME(generic_const_items): Interpret `~const` as always-const.
|
||||
const CREATE<T: ~const Create>: T = T::create();
|
||||
|
||||
pub const K0: i32 = CREATE::<i32>;
|
||||
pub const K1: i32 = CREATE; // arg inferred
|
||||
|
||||
#[const_trait]
|
||||
trait Create {
|
||||
fn create() -> Self;
|
||||
}
|
||||
|
||||
impl const Create for i32 {
|
||||
fn create() -> i32 {
|
||||
4096
|
||||
}
|
||||
}
|
27
tests/ui/generic-const-items/duplicate-where-clause.rs
Normal file
27
tests/ui/generic-const-items/duplicate-where-clause.rs
Normal file
@ -0,0 +1,27 @@
|
||||
#![feature(generic_const_items)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
trait Tr<P> {
|
||||
const K: ()
|
||||
where
|
||||
P: Copy
|
||||
where
|
||||
P: Eq;
|
||||
//~^ ERROR cannot define duplicate `where` clauses on an item
|
||||
}
|
||||
|
||||
// Test that we error on the first where-clause but also that we don't suggest to swap it with the
|
||||
// body as it would conflict with the second where-clause.
|
||||
// FIXME(generic_const_items): We should provide a structured sugg to merge the 1st into the 2nd WC.
|
||||
|
||||
impl<P> Tr<P> for () {
|
||||
const K: ()
|
||||
where
|
||||
P: Eq
|
||||
= ()
|
||||
where
|
||||
P: Copy;
|
||||
//~^^^^^ ERROR where clauses are not allowed before const item bodies
|
||||
}
|
||||
|
||||
fn main() {}
|
27
tests/ui/generic-const-items/duplicate-where-clause.stderr
Normal file
27
tests/ui/generic-const-items/duplicate-where-clause.stderr
Normal file
@ -0,0 +1,27 @@
|
||||
error: cannot define duplicate `where` clauses on an item
|
||||
--> $DIR/duplicate-where-clause.rs:9:9
|
||||
|
|
||||
LL | P: Copy
|
||||
| - previous `where` clause starts here
|
||||
LL | where
|
||||
LL | P: Eq;
|
||||
| ^
|
||||
|
|
||||
help: consider joining the two `where` clauses into one
|
||||
|
|
||||
LL | P: Copy,
|
||||
| ~
|
||||
|
||||
error: where clauses are not allowed before const item bodies
|
||||
--> $DIR/duplicate-where-clause.rs:19:5
|
||||
|
|
||||
LL | const K: ()
|
||||
| - while parsing this const item
|
||||
LL | / where
|
||||
LL | | P: Eq
|
||||
| |_____________^ unexpected where clause
|
||||
LL | = ()
|
||||
| -- the item body
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
18
tests/ui/generic-const-items/elided-lifetimes.rs
Normal file
18
tests/ui/generic-const-items/elided-lifetimes.rs
Normal file
@ -0,0 +1,18 @@
|
||||
#![feature(generic_const_items)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
// Check that we forbid elided lifetimes inside the generics of const items.
|
||||
|
||||
const K<T>: () = ()
|
||||
where
|
||||
&T: Copy; //~ ERROR `&` without an explicit lifetime name cannot be used here
|
||||
|
||||
const I<const S: &str>: &str = "";
|
||||
//~^ ERROR `&` without an explicit lifetime name cannot be used here
|
||||
//~| ERROR `&str` is forbidden as the type of a const generic parameter
|
||||
|
||||
const B<T: Trait<'_>>: () = (); //~ ERROR `'_` cannot be used here
|
||||
|
||||
trait Trait<'a> {}
|
||||
|
||||
fn main() {}
|
35
tests/ui/generic-const-items/elided-lifetimes.stderr
Normal file
35
tests/ui/generic-const-items/elided-lifetimes.stderr
Normal file
@ -0,0 +1,35 @@
|
||||
error[E0637]: `&` without an explicit lifetime name cannot be used here
|
||||
--> $DIR/elided-lifetimes.rs:8:5
|
||||
|
|
||||
LL | &T: Copy;
|
||||
| ^ explicit lifetime name needed here
|
||||
|
|
||||
help: consider introducing a higher-ranked lifetime here
|
||||
|
|
||||
LL | for<'a> &'a T: Copy;
|
||||
| +++++++ ++
|
||||
|
||||
error[E0637]: `&` without an explicit lifetime name cannot be used here
|
||||
--> $DIR/elided-lifetimes.rs:10:18
|
||||
|
|
||||
LL | const I<const S: &str>: &str = "";
|
||||
| ^ explicit lifetime name needed here
|
||||
|
||||
error[E0637]: `'_` cannot be used here
|
||||
--> $DIR/elided-lifetimes.rs:14:18
|
||||
|
|
||||
LL | const B<T: Trait<'_>>: () = ();
|
||||
| ^^ `'_` is a reserved lifetime name
|
||||
|
||||
error: `&str` is forbidden as the type of a const generic parameter
|
||||
--> $DIR/elided-lifetimes.rs:10:18
|
||||
|
|
||||
LL | const I<const S: &str>: &str = "";
|
||||
| ^^^^
|
||||
|
|
||||
= note: the only supported types are integers, `bool` and `char`
|
||||
= help: more complex types are supported with `#![feature(adt_const_params)]`
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0637`.
|
31
tests/ui/generic-const-items/evaluatable-bounds.rs
Normal file
31
tests/ui/generic-const-items/evaluatable-bounds.rs
Normal file
@ -0,0 +1,31 @@
|
||||
// This is a regression test for issue #104400.
|
||||
|
||||
// revisions: unconstrained constrained
|
||||
//[constrained] check-pass
|
||||
|
||||
// Test that we can constrain generic const items that appear inside associated consts by
|
||||
// adding a (makeshift) "evaluatable"-bound to the item.
|
||||
|
||||
#![feature(generic_const_items, generic_const_exprs)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
trait Trait {
|
||||
const LEN: usize;
|
||||
|
||||
#[cfg(unconstrained)]
|
||||
const ARRAY: [i32; Self::LEN]; //[unconstrained]~ ERROR unconstrained generic constant
|
||||
|
||||
#[cfg(constrained)]
|
||||
const ARRAY: [i32; Self::LEN]
|
||||
where
|
||||
[(); Self::LEN]:;
|
||||
}
|
||||
|
||||
impl Trait for () {
|
||||
const LEN: usize = 2;
|
||||
const ARRAY: [i32; Self::LEN] = [360, 720];
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let [_, _] = <() as Trait>::ARRAY;
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
error: unconstrained generic constant
|
||||
--> $DIR/evaluatable-bounds.rs:16:5
|
||||
|
|
||||
LL | const ARRAY: [i32; Self::LEN];
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= help: try adding a `where` bound using this expression: `where [(); Self::LEN]:`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
@ -0,0 +1,37 @@
|
||||
pub trait Trait<A> {
|
||||
const ONE<T>: i32;
|
||||
//~^ ERROR generic const items are experimental
|
||||
|
||||
const TWO: ()
|
||||
where
|
||||
A: Copy;
|
||||
//~^^ ERROR generic const items are experimental
|
||||
}
|
||||
|
||||
const CONST<T>: i32 = 0;
|
||||
//~^ ERROR generic const items are experimental
|
||||
|
||||
const EMPTY<>: i32 = 0;
|
||||
//~^ ERROR generic const items are experimental
|
||||
|
||||
const TRUE: () = ()
|
||||
where
|
||||
String: Clone;
|
||||
//~^^ ERROR generic const items are experimental
|
||||
|
||||
// Ensure that we flag generic const items inside macro calls as well:
|
||||
|
||||
macro_rules! discard {
|
||||
($item:item) => {}
|
||||
}
|
||||
|
||||
discard! { const FREE<T>: () = (); }
|
||||
//~^ ERROR generic const items are experimental
|
||||
|
||||
discard! { impl () { const ASSOC<const N: ()>: () = (); } }
|
||||
//~^ ERROR generic const items are experimental
|
||||
|
||||
discard! { impl () { const ASSOC: i32 = 0 where String: Copy; } }
|
||||
//~^ ERROR generic const items are experimental
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,77 @@
|
||||
error[E0658]: generic const items are experimental
|
||||
--> $DIR/feature-gate-generic_const_items.rs:2:14
|
||||
|
|
||||
LL | const ONE<T>: i32;
|
||||
| ^^^
|
||||
|
|
||||
= note: see issue #113521 <https://github.com/rust-lang/rust/issues/113521> for more information
|
||||
= help: add `#![feature(generic_const_items)]` to the crate attributes to enable
|
||||
|
||||
error[E0658]: generic const items are experimental
|
||||
--> $DIR/feature-gate-generic_const_items.rs:6:5
|
||||
|
|
||||
LL | / where
|
||||
LL | | A: Copy;
|
||||
| |_______________^
|
||||
|
|
||||
= note: see issue #113521 <https://github.com/rust-lang/rust/issues/113521> for more information
|
||||
= help: add `#![feature(generic_const_items)]` to the crate attributes to enable
|
||||
|
||||
error[E0658]: generic const items are experimental
|
||||
--> $DIR/feature-gate-generic_const_items.rs:11:12
|
||||
|
|
||||
LL | const CONST<T>: i32 = 0;
|
||||
| ^^^
|
||||
|
|
||||
= note: see issue #113521 <https://github.com/rust-lang/rust/issues/113521> for more information
|
||||
= help: add `#![feature(generic_const_items)]` to the crate attributes to enable
|
||||
|
||||
error[E0658]: generic const items are experimental
|
||||
--> $DIR/feature-gate-generic_const_items.rs:14:12
|
||||
|
|
||||
LL | const EMPTY<>: i32 = 0;
|
||||
| ^^
|
||||
|
|
||||
= note: see issue #113521 <https://github.com/rust-lang/rust/issues/113521> for more information
|
||||
= help: add `#![feature(generic_const_items)]` to the crate attributes to enable
|
||||
|
||||
error[E0658]: generic const items are experimental
|
||||
--> $DIR/feature-gate-generic_const_items.rs:18:1
|
||||
|
|
||||
LL | / where
|
||||
LL | | String: Clone;
|
||||
| |_________________^
|
||||
|
|
||||
= note: see issue #113521 <https://github.com/rust-lang/rust/issues/113521> for more information
|
||||
= help: add `#![feature(generic_const_items)]` to the crate attributes to enable
|
||||
|
||||
error[E0658]: generic const items are experimental
|
||||
--> $DIR/feature-gate-generic_const_items.rs:28:22
|
||||
|
|
||||
LL | discard! { const FREE<T>: () = (); }
|
||||
| ^^^
|
||||
|
|
||||
= note: see issue #113521 <https://github.com/rust-lang/rust/issues/113521> for more information
|
||||
= help: add `#![feature(generic_const_items)]` to the crate attributes to enable
|
||||
|
||||
error[E0658]: generic const items are experimental
|
||||
--> $DIR/feature-gate-generic_const_items.rs:31:33
|
||||
|
|
||||
LL | discard! { impl () { const ASSOC<const N: ()>: () = (); } }
|
||||
| ^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #113521 <https://github.com/rust-lang/rust/issues/113521> for more information
|
||||
= help: add `#![feature(generic_const_items)]` to the crate attributes to enable
|
||||
|
||||
error[E0658]: generic const items are experimental
|
||||
--> $DIR/feature-gate-generic_const_items.rs:34:43
|
||||
|
|
||||
LL | discard! { impl () { const ASSOC: i32 = 0 where String: Copy; } }
|
||||
| ^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #113521 <https://github.com/rust-lang/rust/issues/113521> for more information
|
||||
= help: add `#![feature(generic_const_items)]` to the crate attributes to enable
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
15
tests/ui/generic-const-items/inference-failure.rs
Normal file
15
tests/ui/generic-const-items/inference-failure.rs
Normal file
@ -0,0 +1,15 @@
|
||||
#![feature(generic_const_items)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
const NONE<T>: Option<T> = None::<T>;
|
||||
const IGNORE<T>: () = ();
|
||||
|
||||
fn none() {
|
||||
let _ = NONE; //~ ERROR type annotations needed
|
||||
}
|
||||
|
||||
fn ignore() {
|
||||
let _ = IGNORE; //~ ERROR type annotations needed
|
||||
}
|
||||
|
||||
fn main() {}
|
20
tests/ui/generic-const-items/inference-failure.stderr
Normal file
20
tests/ui/generic-const-items/inference-failure.stderr
Normal file
@ -0,0 +1,20 @@
|
||||
error[E0282]: type annotations needed for `Option<T>`
|
||||
--> $DIR/inference-failure.rs:8:9
|
||||
|
|
||||
LL | let _ = NONE;
|
||||
| ^
|
||||
|
|
||||
help: consider giving this pattern a type, where the type for type parameter `T` is specified
|
||||
|
|
||||
LL | let _: Option<T> = NONE;
|
||||
| +++++++++++
|
||||
|
||||
error[E0282]: type annotations needed
|
||||
--> $DIR/inference-failure.rs:12:13
|
||||
|
|
||||
LL | let _ = IGNORE;
|
||||
| ^^^^^^ cannot infer type for type parameter `T` declared on the constant `IGNORE`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0282`.
|
18
tests/ui/generic-const-items/misplaced-where-clause.fixed
Normal file
18
tests/ui/generic-const-items/misplaced-where-clause.fixed
Normal file
@ -0,0 +1,18 @@
|
||||
// run-rustfix
|
||||
|
||||
#![feature(generic_const_items)]
|
||||
#![allow(incomplete_features, dead_code)]
|
||||
|
||||
const K<T>: u64
|
||||
= T::K where
|
||||
T: Tr<()>;
|
||||
//~^^^ ERROR where clauses are not allowed before const item bodies
|
||||
|
||||
trait Tr<P> {
|
||||
const K: u64
|
||||
= 0 where
|
||||
P: Copy;
|
||||
//~^^^ ERROR where clauses are not allowed before const item bodies
|
||||
}
|
||||
|
||||
fn main() {}
|
20
tests/ui/generic-const-items/misplaced-where-clause.rs
Normal file
20
tests/ui/generic-const-items/misplaced-where-clause.rs
Normal file
@ -0,0 +1,20 @@
|
||||
// run-rustfix
|
||||
|
||||
#![feature(generic_const_items)]
|
||||
#![allow(incomplete_features, dead_code)]
|
||||
|
||||
const K<T>: u64
|
||||
where
|
||||
T: Tr<()>
|
||||
= T::K;
|
||||
//~^^^ ERROR where clauses are not allowed before const item bodies
|
||||
|
||||
trait Tr<P> {
|
||||
const K: u64
|
||||
where
|
||||
P: Copy
|
||||
= 0;
|
||||
//~^^^ ERROR where clauses are not allowed before const item bodies
|
||||
}
|
||||
|
||||
fn main() {}
|
36
tests/ui/generic-const-items/misplaced-where-clause.stderr
Normal file
36
tests/ui/generic-const-items/misplaced-where-clause.stderr
Normal file
@ -0,0 +1,36 @@
|
||||
error: where clauses are not allowed before const item bodies
|
||||
--> $DIR/misplaced-where-clause.rs:7:1
|
||||
|
|
||||
LL | const K<T>: u64
|
||||
| - while parsing this const item
|
||||
LL | / where
|
||||
LL | | T: Tr<()>
|
||||
| |_____________^ unexpected where clause
|
||||
LL | = T::K;
|
||||
| ---- the item body
|
||||
|
|
||||
help: move the body before the where clause
|
||||
|
|
||||
LL ~ = T::K where
|
||||
LL ~ T: Tr<()>;
|
||||
|
|
||||
|
||||
error: where clauses are not allowed before const item bodies
|
||||
--> $DIR/misplaced-where-clause.rs:14:5
|
||||
|
|
||||
LL | const K: u64
|
||||
| - while parsing this const item
|
||||
LL | / where
|
||||
LL | | P: Copy
|
||||
| |_______________^ unexpected where clause
|
||||
LL | = 0;
|
||||
| - the item body
|
||||
|
|
||||
help: move the body before the where clause
|
||||
|
|
||||
LL ~ = 0 where
|
||||
LL ~ P: Copy;
|
||||
|
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
14
tests/ui/generic-const-items/parameter-defaults.rs
Normal file
14
tests/ui/generic-const-items/parameter-defaults.rs
Normal file
@ -0,0 +1,14 @@
|
||||
#![feature(generic_const_items)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
// Check that we emit a *hard* error (not just a lint warning or error for example) for generic
|
||||
// parameter defaults on free const items since we are not limited by backward compatibility.
|
||||
#![allow(invalid_type_param_default)] // Should have no effect here.
|
||||
|
||||
// FIXME(default_type_parameter_fallback): Consider reallowing them once they work properly.
|
||||
|
||||
const NONE<T = ()>: Option<T> = None::<T>; //~ ERROR defaults for type parameters are only allowed
|
||||
|
||||
fn main() {
|
||||
let _ = NONE;
|
||||
}
|
8
tests/ui/generic-const-items/parameter-defaults.stderr
Normal file
8
tests/ui/generic-const-items/parameter-defaults.stderr
Normal file
@ -0,0 +1,8 @@
|
||||
error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
|
||||
--> $DIR/parameter-defaults.rs:10:12
|
||||
|
|
||||
LL | const NONE<T = ()>: Option<T> = None::<T>;
|
||||
| ^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
12
tests/ui/generic-const-items/recursive.rs
Normal file
12
tests/ui/generic-const-items/recursive.rs
Normal file
@ -0,0 +1,12 @@
|
||||
// FIXME(generic_const_items): This leads to a stack overflow in the compiler!
|
||||
// known-bug: unknown
|
||||
// ignore-test
|
||||
|
||||
#![feature(generic_const_items)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
const RECUR<T>: () = RECUR::<(T,)>;
|
||||
|
||||
fn main() {
|
||||
let _ = RECUR::<()>;
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
#![feature(generic_const_items, trivial_bounds)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
// Ensure that we check if trivial bounds on const items hold or not.
|
||||
|
||||
const UNUSABLE: () = ()
|
||||
where
|
||||
String: Copy;
|
||||
|
||||
fn main() {
|
||||
let _ = UNUSABLE; //~ ERROR the trait bound `String: Copy` is not satisfied
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
error[E0277]: the trait bound `String: Copy` is not satisfied
|
||||
--> $DIR/trivially-unsatisfied-bounds-0.rs:11:13
|
||||
|
|
||||
LL | let _ = UNUSABLE;
|
||||
| ^^^^^^^^ the trait `Copy` is not implemented for `String`
|
||||
|
|
||||
note: required by a bound in `UNUSABLE`
|
||||
--> $DIR/trivially-unsatisfied-bounds-0.rs:8:13
|
||||
|
|
||||
LL | const UNUSABLE: () = ()
|
||||
| -------- required by a bound in this constant
|
||||
LL | where
|
||||
LL | String: Copy;
|
||||
| ^^^^ required by this bound in `UNUSABLE`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
@ -0,0 +1,12 @@
|
||||
#![feature(generic_const_items, trivial_bounds)]
|
||||
#![allow(incomplete_features, dead_code, trivial_bounds)]
|
||||
|
||||
// FIXME(generic_const_items): This looks like a bug to me. I expected that we wouldn't emit any
|
||||
// errors. I thought we'd skip the evaluation of consts whose bounds don't hold.
|
||||
|
||||
const UNUSED: () = ()
|
||||
where
|
||||
String: Copy;
|
||||
//~^^^ ERROR evaluation of constant value failed
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,11 @@
|
||||
error[E0080]: evaluation of constant value failed
|
||||
--> $DIR/trivially-unsatisfied-bounds-1.rs:7:1
|
||||
|
|
||||
LL | / const UNUSED: () = ()
|
||||
LL | | where
|
||||
LL | | String: Copy;
|
||||
| |_________________^ entering unreachable code
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0080`.
|
34
tests/ui/generic-const-items/unsatisfied-bounds.rs
Normal file
34
tests/ui/generic-const-items/unsatisfied-bounds.rs
Normal file
@ -0,0 +1,34 @@
|
||||
#![feature(generic_const_items)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
// Ensure that we check if bounds on const items hold or not.
|
||||
|
||||
use std::convert::Infallible;
|
||||
|
||||
const C<T: Copy>: () = ();
|
||||
|
||||
const K<T>: () = ()
|
||||
where
|
||||
Infallible: From<T>;
|
||||
|
||||
trait Trait<P> {
|
||||
const A: u32
|
||||
where
|
||||
P: Copy;
|
||||
|
||||
const B<T>: u32
|
||||
where
|
||||
Infallible: From<T>;
|
||||
}
|
||||
|
||||
impl<P> Trait<P> for () {
|
||||
const A: u32 = 0;
|
||||
const B<T>: u32 = 1;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let () = C::<String>; //~ ERROR the trait bound `String: Copy` is not satisfied
|
||||
let () = K::<()>; //~ ERROR the trait bound `Infallible: From<()>` is not satisfied
|
||||
let _ = <() as Trait<Vec<u8>>>::A; //~ ERROR the trait bound `Vec<u8>: Copy` is not satisfied
|
||||
let _ = <() as Trait<&'static str>>::B::<()>; //~ ERROR the trait bound `Infallible: From<()>` is not satisfied
|
||||
}
|
62
tests/ui/generic-const-items/unsatisfied-bounds.stderr
Normal file
62
tests/ui/generic-const-items/unsatisfied-bounds.stderr
Normal file
@ -0,0 +1,62 @@
|
||||
error[E0277]: the trait bound `String: Copy` is not satisfied
|
||||
--> $DIR/unsatisfied-bounds.rs:30:18
|
||||
|
|
||||
LL | let () = C::<String>;
|
||||
| ^^^^^^ the trait `Copy` is not implemented for `String`
|
||||
|
|
||||
note: required by a bound in `C`
|
||||
--> $DIR/unsatisfied-bounds.rs:8:12
|
||||
|
|
||||
LL | const C<T: Copy>: () = ();
|
||||
| ^^^^ required by this bound in `C`
|
||||
|
||||
error[E0277]: the trait bound `Infallible: From<()>` is not satisfied
|
||||
--> $DIR/unsatisfied-bounds.rs:31:18
|
||||
|
|
||||
LL | let () = K::<()>;
|
||||
| ^^ the trait `From<()>` is not implemented for `Infallible`
|
||||
|
|
||||
= help: the trait `From<!>` is implemented for `Infallible`
|
||||
note: required by a bound in `K`
|
||||
--> $DIR/unsatisfied-bounds.rs:12:17
|
||||
|
|
||||
LL | const K<T>: () = ()
|
||||
| - required by a bound in this constant
|
||||
LL | where
|
||||
LL | Infallible: From<T>;
|
||||
| ^^^^^^^ required by this bound in `K`
|
||||
|
||||
error[E0277]: the trait bound `Vec<u8>: Copy` is not satisfied
|
||||
--> $DIR/unsatisfied-bounds.rs:32:13
|
||||
|
|
||||
LL | let _ = <() as Trait<Vec<u8>>>::A;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Vec<u8>`
|
||||
|
|
||||
note: required by a bound in `Trait::A`
|
||||
--> $DIR/unsatisfied-bounds.rs:17:12
|
||||
|
|
||||
LL | const A: u32
|
||||
| - required by a bound in this associated constant
|
||||
LL | where
|
||||
LL | P: Copy;
|
||||
| ^^^^ required by this bound in `Trait::A`
|
||||
|
||||
error[E0277]: the trait bound `Infallible: From<()>` is not satisfied
|
||||
--> $DIR/unsatisfied-bounds.rs:33:46
|
||||
|
|
||||
LL | let _ = <() as Trait<&'static str>>::B::<()>;
|
||||
| ^^ the trait `From<()>` is not implemented for `Infallible`
|
||||
|
|
||||
= help: the trait `From<!>` is implemented for `Infallible`
|
||||
note: required by a bound in `Trait::B`
|
||||
--> $DIR/unsatisfied-bounds.rs:21:21
|
||||
|
|
||||
LL | const B<T>: u32
|
||||
| - required by a bound in this associated constant
|
||||
LL | where
|
||||
LL | Infallible: From<T>;
|
||||
| ^^^^^^^ required by this bound in `Trait::B`
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
@ -0,0 +1,12 @@
|
||||
#![feature(generic_const_items, generic_const_exprs)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
// Ensure that we check if (makeshift) "evaluatable"-bounds on const items hold or not.
|
||||
|
||||
const POSITIVE<const N: usize>: usize = N
|
||||
where
|
||||
[(); N - 1]:; //~ ERROR evaluation of `POSITIVE::<0>::{constant#0}` failed
|
||||
|
||||
fn main() {
|
||||
let _ = POSITIVE::<0>;
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
error[E0080]: evaluation of `POSITIVE::<0>::{constant#0}` failed
|
||||
--> $DIR/unsatisfied-evaluatable-bounds.rs:8:10
|
||||
|
|
||||
LL | [(); N - 1]:;
|
||||
| ^^^^^ attempt to compute `0_usize - 1_usize`, which would overflow
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0080`.
|
17
tests/ui/generic-const-items/unsatisfied-outlives-bounds.rs
Normal file
17
tests/ui/generic-const-items/unsatisfied-outlives-bounds.rs
Normal file
@ -0,0 +1,17 @@
|
||||
#![feature(generic_const_items)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
// Ensure that we check if outlives-bounds on const items hold or not.
|
||||
|
||||
const C<'a, T: 'a>: () = ();
|
||||
const K<'a, 'b: 'a>: () = ();
|
||||
|
||||
fn parametrized0<'any>() {
|
||||
let () = C::<'static, &'any ()>; //~ ERROR lifetime may not live long enough
|
||||
}
|
||||
|
||||
fn parametrized1<'any>() {
|
||||
let () = K::<'static, 'any>; //~ ERROR lifetime may not live long enough
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,18 @@
|
||||
error: lifetime may not live long enough
|
||||
--> $DIR/unsatisfied-outlives-bounds.rs:10:14
|
||||
|
|
||||
LL | fn parametrized0<'any>() {
|
||||
| ---- lifetime `'any` defined here
|
||||
LL | let () = C::<'static, &'any ()>;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ requires that `'any` must outlive `'static`
|
||||
|
||||
error: lifetime may not live long enough
|
||||
--> $DIR/unsatisfied-outlives-bounds.rs:14:14
|
||||
|
|
||||
LL | fn parametrized1<'any>() {
|
||||
| ---- lifetime `'any` defined here
|
||||
LL | let () = K::<'static, 'any>;
|
||||
| ^^^^^^^^^^^^^^^^^^ requires that `'any` must outlive `'static`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
@ -1,7 +1,12 @@
|
||||
#![feature(generic_const_items)]
|
||||
#![allow(incomplete_features, dead_code)]
|
||||
|
||||
// check-pass
|
||||
|
||||
trait Foo<T> {
|
||||
const BAR: bool
|
||||
where //~ ERROR: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `=`, found keyword `where`
|
||||
Self: Sized;
|
||||
where
|
||||
Self: Sized;
|
||||
}
|
||||
|
||||
trait Cake {}
|
||||
|
@ -1,15 +0,0 @@
|
||||
error: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `=`, found keyword `where`
|
||||
--> $DIR/assoc_const_bounds.rs:3:9
|
||||
|
|
||||
LL | trait Foo<T> {
|
||||
| - while parsing this item list starting here
|
||||
LL | const BAR: bool
|
||||
| - expected one of 7 possible tokens
|
||||
LL | where
|
||||
| ^^^^^ unexpected token
|
||||
LL | Self: Sized;
|
||||
LL | }
|
||||
| - the item list ends here
|
||||
|
||||
error: aborting due to previous error
|
||||
|
@ -1,7 +1,12 @@
|
||||
#![feature(generic_const_items)]
|
||||
#![allow(incomplete_features, dead_code)]
|
||||
|
||||
// check-pass
|
||||
|
||||
trait Foo {
|
||||
const BAR: bool
|
||||
where //~ ERROR: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `=`, found keyword `where`
|
||||
Self: Sized;
|
||||
where
|
||||
Self: Sized;
|
||||
}
|
||||
|
||||
fn foo(_: &dyn Foo) {}
|
||||
|
@ -1,15 +0,0 @@
|
||||
error: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `=`, found keyword `where`
|
||||
--> $DIR/assoc_const_bounds_sized.rs:3:9
|
||||
|
|
||||
LL | trait Foo {
|
||||
| - while parsing this item list starting here
|
||||
LL | const BAR: bool
|
||||
| - expected one of 7 possible tokens
|
||||
LL | where
|
||||
| ^^^^^ unexpected token
|
||||
LL | Self: Sized;
|
||||
LL | }
|
||||
| - the item list ends here
|
||||
|
||||
error: aborting due to previous error
|
||||
|
4
tests/ui/parser/generic-statics.rs
Normal file
4
tests/ui/parser/generic-statics.rs
Normal file
@ -0,0 +1,4 @@
|
||||
static S<T>: i32 = 0;
|
||||
//~^ ERROR static items may not have generic parameters
|
||||
|
||||
fn main() {}
|
8
tests/ui/parser/generic-statics.stderr
Normal file
8
tests/ui/parser/generic-statics.stderr
Normal file
@ -0,0 +1,8 @@
|
||||
error: static items may not have generic parameters
|
||||
--> $DIR/generic-statics.rs:1:9
|
||||
|
|
||||
LL | static S<T>: i32 = 0;
|
||||
| ^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
@ -1,5 +1,5 @@
|
||||
error[E0106]: missing lifetime specifier
|
||||
--> $DIR/missing-lifetime-in-assoc-const-type.rs:2:14
|
||||
--> $DIR/missing-lifetime-in-assoc-const-type.rs:6:14
|
||||
|
|
||||
LL | const A: &str = "";
|
||||
| ^ expected named lifetime parameter
|
||||
@ -11,7 +11,7 @@ LL ~ const A: &'a str = "";
|
||||
|
|
||||
|
||||
error[E0106]: missing lifetime specifier
|
||||
--> $DIR/missing-lifetime-in-assoc-const-type.rs:3:14
|
||||
--> $DIR/missing-lifetime-in-assoc-const-type.rs:7:14
|
||||
|
|
||||
LL | const B: S = S { s: &() };
|
||||
| ^ expected named lifetime parameter
|
||||
@ -24,7 +24,7 @@ LL ~ const B: S<'a> = S { s: &() };
|
||||
|
|
||||
|
||||
error[E0106]: missing lifetime specifier
|
||||
--> $DIR/missing-lifetime-in-assoc-const-type.rs:4:15
|
||||
--> $DIR/missing-lifetime-in-assoc-const-type.rs:8:15
|
||||
|
|
||||
LL | const C: &'_ str = "";
|
||||
| ^^ expected named lifetime parameter
|
||||
@ -38,7 +38,7 @@ LL ~ const C: &'a str = "";
|
||||
|
|
||||
|
||||
error[E0106]: missing lifetime specifiers
|
||||
--> $DIR/missing-lifetime-in-assoc-const-type.rs:5:14
|
||||
--> $DIR/missing-lifetime-in-assoc-const-type.rs:9:14
|
||||
|
|
||||
LL | const D: T = T { a: &(), b: &() };
|
||||
| ^ expected 2 lifetime parameters
|
@ -0,0 +1,47 @@
|
||||
error[E0106]: missing lifetime specifier
|
||||
--> $DIR/missing-lifetime-in-assoc-const-type.rs:6:14
|
||||
|
|
||||
LL | const A: &str = "";
|
||||
| ^ expected named lifetime parameter
|
||||
|
|
||||
help: consider introducing a named lifetime parameter
|
||||
|
|
||||
LL | const A<'a>: &'a str = "";
|
||||
| ++++ ++
|
||||
|
||||
error[E0106]: missing lifetime specifier
|
||||
--> $DIR/missing-lifetime-in-assoc-const-type.rs:7:14
|
||||
|
|
||||
LL | const B: S = S { s: &() };
|
||||
| ^ expected named lifetime parameter
|
||||
|
|
||||
help: consider introducing a named lifetime parameter
|
||||
|
|
||||
LL | const B<'a>: S<'a> = S { s: &() };
|
||||
| ++++ ++++
|
||||
|
||||
error[E0106]: missing lifetime specifier
|
||||
--> $DIR/missing-lifetime-in-assoc-const-type.rs:8:15
|
||||
|
|
||||
LL | const C: &'_ str = "";
|
||||
| ^^ expected named lifetime parameter
|
||||
|
|
||||
help: consider introducing a named lifetime parameter
|
||||
|
|
||||
LL | const C<'a>: &'a str = "";
|
||||
| ++++ ~~
|
||||
|
||||
error[E0106]: missing lifetime specifiers
|
||||
--> $DIR/missing-lifetime-in-assoc-const-type.rs:9:14
|
||||
|
|
||||
LL | const D: T = T { a: &(), b: &() };
|
||||
| ^ expected 2 lifetime parameters
|
||||
|
|
||||
help: consider introducing a named lifetime parameter
|
||||
|
|
||||
LL | const D<'a>: T<'a, 'a> = T { a: &(), b: &() };
|
||||
| ++++ ++++++++
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0106`.
|
@ -1,3 +1,7 @@
|
||||
// revisions: default generic_const_items
|
||||
|
||||
#![cfg_attr(generic_const_items, feature(generic_const_items), allow(incomplete_features))]
|
||||
|
||||
trait ZstAssert: Sized {
|
||||
const A: &str = ""; //~ ERROR missing lifetime specifier
|
||||
const B: S = S { s: &() }; //~ ERROR missing lifetime specifier
|
||||
|
Loading…
Reference in New Issue
Block a user