Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/hir-def/src/generics.rs8
-rw-r--r--crates/hir-def/src/hir/type_ref.rs11
-rw-r--r--crates/hir-ty/src/lib.rs17
-rw-r--r--crates/hir-ty/src/lower.rs81
-rw-r--r--crates/hir/src/lib.rs22
-rw-r--r--crates/ide-assists/src/handlers/add_missing_impl_members.rs105
-rw-r--r--crates/ide-assists/src/handlers/extract_function.rs2
-rw-r--r--crates/ide-db/src/imports/import_assets.rs4
-rw-r--r--crates/ide-db/src/path_transform.rs44
-rw-r--r--crates/ide-db/src/use_trivial_constructor.rs16
-rw-r--r--crates/parser/src/grammar/generic_params.rs2
-rw-r--r--crates/parser/test_data/parser/inline/err/0022_recover_from_missing_const_default.rast6
-rw-r--r--crates/parser/test_data/parser/inline/ok/0188_const_param_default_path.rast15
-rw-r--r--crates/parser/test_data/parser/inline/ok/0199_const_param_default_expression.rast17
-rw-r--r--crates/parser/test_data/parser/inline/ok/0200_const_param_default_literal.rast9
-rw-r--r--crates/syntax/rust.ungram2
-rw-r--r--crates/syntax/src/ast/generated/nodes.rs2
-rw-r--r--crates/syntax/src/ast/make.rs5
18 files changed, 265 insertions, 103 deletions
diff --git a/crates/hir-def/src/generics.rs b/crates/hir-def/src/generics.rs
index 540fa115a0..1e2535a8a9 100644
--- a/crates/hir-def/src/generics.rs
+++ b/crates/hir-def/src/generics.rs
@@ -25,7 +25,7 @@ use crate::{
lower::LowerCtx,
nameres::{DefMap, MacroSubNs},
src::{HasChildSource, HasSource},
- type_ref::{LifetimeRef, TypeBound, TypeRef},
+ type_ref::{ConstRef, LifetimeRef, TypeBound, TypeRef},
AdtId, ConstParamId, GenericDefId, HasModule, LifetimeParamId, LocalLifetimeParamId,
LocalTypeOrConstParamId, Lookup, TypeOrConstParamId, TypeParamId,
};
@@ -49,7 +49,7 @@ pub struct LifetimeParamData {
pub struct ConstParamData {
pub name: Name,
pub ty: Interned<TypeRef>,
- pub has_default: bool,
+ pub default: Option<ConstRef>,
}
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
@@ -76,7 +76,7 @@ impl TypeOrConstParamData {
pub fn has_default(&self) -> bool {
match self {
TypeOrConstParamData::TypeParamData(it) => it.default.is_some(),
- TypeOrConstParamData::ConstParamData(it) => it.has_default,
+ TypeOrConstParamData::ConstParamData(it) => it.default.is_some(),
}
}
@@ -307,7 +307,7 @@ impl GenericParams {
let param = ConstParamData {
name,
ty: Interned::new(ty),
- has_default: const_param.default_val().is_some(),
+ default: ConstRef::from_const_param(lower_ctx, &const_param),
};
let idx = self.type_or_consts.alloc(param.into());
add_param_attrs(idx.into(), ast::GenericParam::ConstParam(const_param));
diff --git a/crates/hir-def/src/hir/type_ref.rs b/crates/hir-def/src/hir/type_ref.rs
index 57f023ef35..75adf21abd 100644
--- a/crates/hir-def/src/hir/type_ref.rs
+++ b/crates/hir-def/src/hir/type_ref.rs
@@ -393,6 +393,17 @@ impl ConstRef {
Self::Scalar(LiteralConstRef::Unknown)
}
+ pub(crate) fn from_const_param(
+ lower_ctx: &LowerCtx<'_>,
+ param: &ast::ConstParam,
+ ) -> Option<Self> {
+ let default = param.default_val();
+ match default {
+ Some(_) => Some(Self::from_const_arg(lower_ctx, default)),
+ None => None,
+ }
+ }
+
pub fn display<'a>(&'a self, db: &'a dyn ExpandDatabase) -> impl fmt::Display + 'a {
struct Display<'a>(&'a dyn ExpandDatabase, &'a ConstRef);
impl fmt::Display for Display<'_> {
diff --git a/crates/hir-ty/src/lib.rs b/crates/hir-ty/src/lib.rs
index b3ca2a2225..405bb001b5 100644
--- a/crates/hir-ty/src/lib.rs
+++ b/crates/hir-ty/src/lib.rs
@@ -52,12 +52,14 @@ use hir_expand::name;
use la_arena::{Arena, Idx};
use mir::{MirEvalError, VTableMap};
use rustc_hash::FxHashSet;
+use syntax::ast::{make, ConstArg};
use traits::FnTrait;
use triomphe::Arc;
use utils::Generics;
use crate::{
- consteval::unknown_const, db::HirDatabase, infer::unify::InferenceTable, utils::generics,
+ consteval::unknown_const, db::HirDatabase, display::HirDisplay, infer::unify::InferenceTable,
+ utils::generics,
};
pub use autoderef::autoderef;
@@ -719,3 +721,16 @@ where
value.visit_with(&mut collector, DebruijnIndex::INNERMOST);
collector.placeholders.into_iter().collect()
}
+
+pub fn known_const_to_ast(konst: &Const, db: &dyn HirDatabase) -> Option<ConstArg> {
+ if let ConstValue::Concrete(c) = &konst.interned().value {
+ match c.interned {
+ ConstScalar::UnevaluatedConst(GeneralConstId::InTypeConstId(cid), _) => {
+ return Some(cid.source(db.upcast()));
+ }
+ ConstScalar::Unknown => return None,
+ _ => (),
+ }
+ }
+ Some(make::expr_const_value(konst.display(db).to_string().as_str()))
+}
diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs
index 20dccfafb3..eb57311bd7 100644
--- a/crates/hir-ty/src/lower.rs
+++ b/crates/hir-ty/src/lower.rs
@@ -212,6 +212,19 @@ impl<'a> TyLoweringContext<'a> {
self.lower_ty_ext(type_ref).0
}
+ pub fn lower_const(&self, const_ref: &ConstRef, const_type: Ty) -> Const {
+ const_or_path_to_chalk(
+ self.db,
+ self.resolver,
+ self.owner,
+ const_type,
+ const_ref,
+ self.type_param_mode,
+ || self.generics(),
+ self.in_binders,
+ )
+ }
+
fn generics(&self) -> Generics {
generics(
self.db.upcast(),
@@ -241,17 +254,7 @@ impl<'a> TyLoweringContext<'a> {
}
TypeRef::Array(inner, len) => {
let inner_ty = self.lower_ty(inner);
- let const_len = const_or_path_to_chalk(
- self.db,
- self.resolver,
- self.owner,
- TyBuilder::usize(),
- len,
- self.type_param_mode,
- || self.generics(),
- self.in_binders,
- );
-
+ let const_len = self.lower_const(len, TyBuilder::usize());
TyKind::Array(inner_ty, const_len).intern(Interner)
}
TypeRef::Slice(inner) => {
@@ -846,18 +849,7 @@ impl<'a> TyLoweringContext<'a> {
arg,
&mut (),
|_, type_ref| self.lower_ty(type_ref),
- |_, c, ty| {
- const_or_path_to_chalk(
- self.db,
- self.resolver,
- self.owner,
- ty,
- c,
- self.type_param_mode,
- || self.generics(),
- self.in_binders,
- )
- },
+ |_, const_ref, ty| self.lower_const(const_ref, ty),
) {
had_explicit_args = true;
substs.push(x);
@@ -1603,24 +1595,35 @@ pub(crate) fn generic_defaults_query(
.iter()
.enumerate()
.map(|(idx, (id, p))| {
- let p = match p {
- TypeOrConstParamData::TypeParamData(p) => p,
- TypeOrConstParamData::ConstParamData(_) => {
- // FIXME: implement const generic defaults
- let val = unknown_const_as_generic(
- db.const_param_ty(ConstParamId::from_unchecked(id)),
+ match p {
+ TypeOrConstParamData::TypeParamData(p) => {
+ let mut ty = p
+ .default
+ .as_ref()
+ .map_or(TyKind::Error.intern(Interner), |t| ctx.lower_ty(t));
+ // Each default can only refer to previous parameters.
+ // Type variable default referring to parameter coming
+ // after it is forbidden (FIXME: report diagnostic)
+ ty = fallback_bound_vars(ty, idx, parent_start_idx);
+ crate::make_binders(db, &generic_params, ty.cast(Interner))
+ }
+ TypeOrConstParamData::ConstParamData(p) => {
+ let mut val = p.default.as_ref().map_or_else(
+ || {
+ unknown_const_as_generic(
+ db.const_param_ty(ConstParamId::from_unchecked(id)),
+ )
+ },
+ |c| {
+ let c = ctx.lower_const(c, ctx.lower_ty(&p.ty));
+ c.cast(Interner)
+ },
);
- return make_binders(db, &generic_params, val);
+ // Each default can only refer to previous parameters, see above.
+ val = fallback_bound_vars(val, idx, parent_start_idx);
+ make_binders(db, &generic_params, val)
}
- };
- let mut ty =
- p.default.as_ref().map_or(TyKind::Error.intern(Interner), |t| ctx.lower_ty(t));
-
- // Each default can only refer to previous parameters.
- // Type variable default referring to parameter coming
- // after it is forbidden (FIXME: report diagnostic)
- ty = fallback_bound_vars(ty, idx, parent_start_idx);
- crate::make_binders(db, &generic_params, ty.cast(Interner))
+ }
})
// FIXME: use `Arc::from_iter` when it becomes available
.collect::<Vec<_>>(),
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index b40b81fe0f..583e26c136 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -63,12 +63,13 @@ use hir_ty::{
all_super_traits, autoderef,
consteval::{try_const_usize, unknown_const_as_generic, ConstEvalError, ConstExt},
diagnostics::BodyValidationDiagnostic,
+ known_const_to_ast,
layout::{Layout as TyLayout, RustcEnumVariantIdx, TagEncoding},
method_resolution::{self, TyFingerprint},
mir::{self, interpret_mir},
primitive::UintTy,
traits::FnTrait,
- AliasTy, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast, ClosureId,
+ AliasTy, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast, ClosureId, GenericArg,
GenericArgData, Interner, ParamKind, QuantifiedWhereClause, Scalar, Substitution,
TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyDefId, TyExt, TyKind, ValueTyDefId,
WhereClause,
@@ -3128,12 +3129,8 @@ impl TypeParam {
}
pub fn default(self, db: &dyn HirDatabase) -> Option<Type> {
- let params = db.generic_defaults(self.id.parent());
- let local_idx = hir_ty::param_idx(db, self.id.into())?;
+ let ty = generic_arg_from_param(db, self.id.into())?;
let resolver = self.id.parent().resolver(db.upcast());
- let ty = params.get(local_idx)?.clone();
- let subst = TyBuilder::placeholder_subst(db, self.id.parent());
- let ty = ty.substitute(Interner, &subst);
match ty.data(Interner) {
GenericArgData::Ty(it) => {
Some(Type::new_with_resolver_inner(db, &resolver, it.clone()))
@@ -3195,6 +3192,19 @@ impl ConstParam {
pub fn ty(self, db: &dyn HirDatabase) -> Type {
Type::new(db, self.id.parent(), db.const_param_ty(self.id))
}
+
+ pub fn default(self, db: &dyn HirDatabase) -> Option<ast::ConstArg> {
+ let arg = generic_arg_from_param(db, self.id.into())?;
+ known_const_to_ast(arg.constant(Interner)?, db)
+ }
+}
+
+fn generic_arg_from_param(db: &dyn HirDatabase, id: TypeOrConstParamId) -> Option<GenericArg> {
+ let params = db.generic_defaults(id.parent);
+ let local_idx = hir_ty::param_idx(db, id)?;
+ let ty = params.get(local_idx)?.clone();
+ let subst = TyBuilder::placeholder_subst(db, id.parent);
+ Some(ty.substitute(Interner, &subst))
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
diff --git a/crates/ide-assists/src/handlers/add_missing_impl_members.rs b/crates/ide-assists/src/handlers/add_missing_impl_members.rs
index 6aca716bb6..c0e5429a22 100644
--- a/crates/ide-assists/src/handlers/add_missing_impl_members.rs
+++ b/crates/ide-assists/src/handlers/add_missing_impl_members.rs
@@ -422,7 +422,7 @@ impl<'x, 'y, T, V, U: Default> Trait<'x, 'y, T, V, U> for () {
check_assist(
add_missing_default_members,
r#"
-struct Bar<const: N: bool> {
+struct Bar<const N: usize> {
bar: [i32, N]
}
@@ -439,7 +439,7 @@ impl<const X: usize, Y, Z> Foo<X, Z> for S<Y> {
$0
}"#,
r#"
-struct Bar<const: N: bool> {
+struct Bar<const N: usize> {
bar: [i32, N]
}
@@ -484,6 +484,107 @@ impl<X> Foo<42, {20 + 22}, X> for () {
}
#[test]
+ fn test_const_substitution_with_defaults() {
+ check_assist(
+ add_missing_default_members,
+ r#"
+trait Foo<T, const N: usize = 42, const M: bool = false, const P: char = 'a'> {
+ fn get_n(&self) -> usize { N }
+ fn get_m(&self) -> bool { M }
+ fn get_p(&self) -> char { P }
+ fn get_array(&self, arg: &T) -> [bool; N] { [M; N] }
+}
+
+impl<X> Foo<X> for () {
+ $0
+}"#,
+ r#"
+trait Foo<T, const N: usize = 42, const M: bool = false, const P: char = 'a'> {
+ fn get_n(&self) -> usize { N }
+ fn get_m(&self) -> bool { M }
+ fn get_p(&self) -> char { P }
+ fn get_array(&self, arg: &T) -> [bool; N] { [M; N] }
+}
+
+impl<X> Foo<X> for () {
+ $0fn get_n(&self) -> usize { 42 }
+
+ fn get_m(&self) -> bool { false }
+
+ fn get_p(&self) -> char { 'a' }
+
+ fn get_array(&self, arg: &X) -> [bool; 42] { [false; 42] }
+}"#,
+ );
+ }
+
+ #[test]
+ fn test_const_substitution_with_defaults_2() {
+ check_assist(
+ add_missing_impl_members,
+ r#"
+mod m {
+ pub const LEN: usize = 42;
+ pub trait Foo<const M: usize = LEN, const N: usize = M, T = [bool; N]> {
+ fn get_t(&self) -> T;
+ }
+}
+
+impl m::Foo for () {
+ $0
+}"#,
+ r#"
+mod m {
+ pub const LEN: usize = 42;
+ pub trait Foo<const M: usize = LEN, const N: usize = M, T = [bool; N]> {
+ fn get_t(&self) -> T;
+ }
+}
+
+impl m::Foo for () {
+ fn get_t(&self) -> [bool; m::LEN] {
+ ${0:todo!()}
+ }
+}"#,
+ )
+ }
+
+ #[test]
+ fn test_const_substitution_with_defaults_3() {
+ check_assist(
+ add_missing_default_members,
+ r#"
+mod m {
+ pub const VAL: usize = 0;
+
+ pub trait Foo<const N: usize = {40 + 2}, const M: usize = {VAL + 1}> {
+ fn get_n(&self) -> usize { N }
+ fn get_m(&self) -> usize { M }
+ }
+}
+
+impl m::Foo for () {
+ $0
+}"#,
+ r#"
+mod m {
+ pub const VAL: usize = 0;
+
+ pub trait Foo<const N: usize = {40 + 2}, const M: usize = {VAL + 1}> {
+ fn get_n(&self) -> usize { N }
+ fn get_m(&self) -> usize { M }
+ }
+}
+
+impl m::Foo for () {
+ $0fn get_n(&self) -> usize { {40 + 2} }
+
+ fn get_m(&self) -> usize { {m::VAL + 1} }
+}"#,
+ )
+ }
+
+ #[test]
fn test_cursor_after_empty_impl_def() {
check_assist(
add_missing_impl_members,
diff --git a/crates/ide-assists/src/handlers/extract_function.rs b/crates/ide-assists/src/handlers/extract_function.rs
index 7f61a68284..1340681cca 100644
--- a/crates/ide-assists/src/handlers/extract_function.rs
+++ b/crates/ide-assists/src/handlers/extract_function.rs
@@ -810,7 +810,7 @@ impl FunctionBody {
(true, konst.body(), Some(sema.to_def(&konst)?.ty(sema.db)))
},
ast::ConstParam(cp) => {
- (true, cp.default_val(), Some(sema.to_def(&cp)?.ty(sema.db)))
+ (true, cp.default_val()?.expr(), Some(sema.to_def(&cp)?.ty(sema.db)))
},
ast::ConstBlockPat(cbp) => {
let expr = cbp.block_expr().map(ast::Expr::BlockExpr);
diff --git a/crates/ide-db/src/imports/import_assets.rs b/crates/ide-db/src/imports/import_assets.rs
index e52dc35677..e475c5cd66 100644
--- a/crates/ide-db/src/imports/import_assets.rs
+++ b/crates/ide-db/src/imports/import_assets.rs
@@ -6,7 +6,7 @@ use hir::{
use itertools::Itertools;
use rustc_hash::FxHashSet;
use syntax::{
- ast::{self, HasName},
+ ast::{self, make, HasName},
utils::path_to_string_stripping_turbo_fish,
AstNode, SyntaxNode,
};
@@ -607,7 +607,7 @@ impl ImportCandidate {
fn for_name(sema: &Semantics<'_, RootDatabase>, name: &ast::Name) -> Option<Self> {
if sema
.scope(name.syntax())?
- .speculative_resolve(&ast::make::ext::ident_path(&name.text()))
+ .speculative_resolve(&make::ext::ident_path(&name.text()))
.is_some()
{
return None;
diff --git a/crates/ide-db/src/path_transform.rs b/crates/ide-db/src/path_transform.rs
index 1d0cb426a5..fb75b5b458 100644
--- a/crates/ide-db/src/path_transform.rs
+++ b/crates/ide-db/src/path_transform.rs
@@ -5,7 +5,7 @@ use either::Either;
use hir::{AsAssocItem, HirDisplay, SemanticsScope};
use rustc_hash::FxHashMap;
use syntax::{
- ast::{self, AstNode},
+ ast::{self, make, AstNode},
ted, SyntaxNode,
};
@@ -21,6 +21,7 @@ enum TypeOrConst {
}
type LifetimeName = String;
+type DefaultedParam = Either<hir::TypeParam, hir::ConstParam>;
/// `PathTransform` substitutes path in SyntaxNodes in bulk.
///
@@ -115,7 +116,7 @@ impl<'a> PathTransform<'a> {
};
let mut type_substs: FxHashMap<hir::TypeParam, ast::Type> = Default::default();
let mut const_substs: FxHashMap<hir::ConstParam, SyntaxNode> = Default::default();
- let mut default_types: Vec<hir::TypeParam> = Default::default();
+ let mut defaulted_params: Vec<DefaultedParam> = Default::default();
self.generic_def
.into_iter()
.flat_map(|it| it.type_params(db))
@@ -138,8 +139,8 @@ impl<'a> PathTransform<'a> {
if let Some(default) =
&default.display_source_code(db, source_module.into(), false).ok()
{
- type_substs.insert(k, ast::make::ty(default).clone_for_update());
- default_types.push(k);
+ type_substs.insert(k, make::ty(default).clone_for_update());
+ defaulted_params.push(Either::Left(k));
}
}
}
@@ -155,11 +156,19 @@ impl<'a> PathTransform<'a> {
// is a standalone statement or a part of another expresson)
// and sometimes require slight modifications; see
// https://doc.rust-lang.org/reference/statements.html#expression-statements
+ // (default values in curly brackets can cause the same problem)
const_substs.insert(k, expr.syntax().clone());
}
}
- (Either::Left(_), None) => (), // FIXME: get default const value
- _ => (), // ignore mismatching params
+ (Either::Left(k), None) => {
+ if let Some(default) = k.default(db) {
+ if let Some(default) = default.expr() {
+ const_substs.insert(k, default.syntax().clone_for_update());
+ defaulted_params.push(Either::Right(k));
+ }
+ }
+ }
+ _ => (), // ignore mismatching params
});
let lifetime_substs: FxHashMap<_, _> = self
.generic_def
@@ -175,7 +184,7 @@ impl<'a> PathTransform<'a> {
target_module,
source_scope: self.source_scope,
};
- ctx.transform_default_type_substs(default_types);
+ ctx.transform_default_values(defaulted_params);
ctx
}
}
@@ -212,13 +221,19 @@ impl Ctx<'_> {
});
}
- fn transform_default_type_substs(&self, default_types: Vec<hir::TypeParam>) {
- for k in default_types {
- let v = self.type_substs.get(&k).unwrap();
+ fn transform_default_values(&self, defaulted_params: Vec<DefaultedParam>) {
+ // By now the default values are simply copied from where they are declared
+ // and should be transformed. As any value is allowed to refer to previous
+ // generic (both type and const) parameters, they should be all iterated left-to-right.
+ for param in defaulted_params {
+ let value = match param {
+ Either::Left(k) => self.type_substs.get(&k).unwrap().syntax(),
+ Either::Right(k) => self.const_substs.get(&k).unwrap(),
+ };
// `transform_path` may update a node's parent and that would break the
// tree traversal. Thus all paths in the tree are collected into a vec
// so that such operation is safe.
- let paths = postorder(&v.syntax()).filter_map(ast::Path::cast).collect::<Vec<_>>();
+ let paths = postorder(value).filter_map(ast::Path::cast).collect::<Vec<_>>();
for path in paths {
self.transform_path(path);
}
@@ -263,15 +278,14 @@ impl Ctx<'_> {
hir::ModuleDef::Trait(trait_ref),
false,
)?;
- match ast::make::ty_path(mod_path_to_ast(&found_path)) {
+ match make::ty_path(mod_path_to_ast(&found_path)) {
ast::Type::PathType(path_ty) => Some(path_ty),
_ => None,
}
});
- let segment = ast::make::path_segment_ty(subst.clone(), trait_ref);
- let qualified =
- ast::make::path_from_segments(std::iter::once(segment), false);
+ let segment = make::path_segment_ty(subst.clone(), trait_ref);
+ let qualified = make::path_from_segments(std::iter::once(segment), false);
ted::replace(path.syntax(), qualified.clone_for_update().syntax());
} else if let Some(path_ty) = ast::PathType::cast(parent) {
ted::replace(
diff --git a/crates/ide-db/src/use_trivial_constructor.rs b/crates/ide-db/src/use_trivial_constructor.rs
index f96ea29ae2..a915391ad9 100644
--- a/crates/ide-db/src/use_trivial_constructor.rs
+++ b/crates/ide-db/src/use_trivial_constructor.rs
@@ -1,31 +1,29 @@
//! Functionality for generating trivial constructors
use hir::StructKind;
-use syntax::ast;
+use syntax::ast::{make, Expr, Path};
/// given a type return the trivial constructor (if one exists)
pub fn use_trivial_constructor(
db: &crate::RootDatabase,
- path: ast::Path,
+ path: Path,
ty: &hir::Type,
-) -> Option<ast::Expr> {
+) -> Option<Expr> {
match ty.as_adt() {
Some(hir::Adt::Enum(x)) => {
if let &[variant] = &*x.variants(db) {
if variant.kind(db) == hir::StructKind::Unit {
- let path = ast::make::path_qualified(
+ let path = make::path_qualified(
path,
- syntax::ast::make::path_segment(ast::make::name_ref(
- &variant.name(db).to_smol_str(),
- )),
+ make::path_segment(make::name_ref(&variant.name(db).to_smol_str())),
);
- return Some(syntax::ast::make::expr_path(path));
+ return Some(make::expr_path(path));
}
}
}
Some(hir::Adt::Struct(x)) if x.kind(db) == StructKind::Unit => {
- return Some(syntax::ast::make::expr_path(path));
+ return Some(make::expr_path(path));
}
_ => {}
}
diff --git a/crates/parser/src/grammar/generic_params.rs b/crates/parser/src/grammar/generic_params.rs
index 8ed1c84c4c..29d9b05d3f 100644
--- a/crates/parser/src/grammar/generic_params.rs
+++ b/crates/parser/src/grammar/generic_params.rs
@@ -88,7 +88,7 @@ fn const_param(p: &mut Parser<'_>, m: Marker) {
// test const_param_default_path
// struct A<const N: i32 = i32::MAX>;
- generic_args::const_arg_expr(p);
+ generic_args::const_arg(p);
}
m.complete(p, CONST_PARAM);
diff --git a/crates/parser/test_data/parser/inline/err/0022_recover_from_missing_const_default.rast b/crates/parser/test_data/parser/inline/err/0022_recover_from_missing_const_default.rast
index 809ad1b8d5..49f163b164 100644
--- a/crates/parser/test_data/parser/inline/err/0022_recover_from_missing_const_default.rast
+++ b/crates/parser/test_data/parser/inline/err/0022_recover_from_missing_const_default.rast
@@ -20,7 +20,8 @@ SOURCE_FILE
IDENT "i32"
WHITESPACE " "
EQ "="
- WHITESPACE " "
+ WHITESPACE " "
+ CONST_ARG
COMMA ","
WHITESPACE " "
CONST_PARAM
@@ -37,8 +38,9 @@ SOURCE_FILE
IDENT "i32"
WHITESPACE " "
EQ "="
+ CONST_ARG
R_ANGLE ">"
SEMICOLON ";"
WHITESPACE "\n"
-error 23: expected a generic const argument
+error 24: expected a generic const argument
error 40: expected a generic const argument
diff --git a/crates/parser/test_data/parser/inline/ok/0188_const_param_default_path.rast b/crates/parser/test_data/parser/inline/ok/0188_const_param_default_path.rast
index 11002bf98d..3f5fb47d28 100644
--- a/crates/parser/test_data/parser/inline/ok/0188_const_param_default_path.rast
+++ b/crates/parser/test_data/parser/inline/ok/0188_const_param_default_path.rast
@@ -21,16 +21,17 @@ SOURCE_FILE
WHITESPACE " "
EQ "="
WHITESPACE " "
- PATH_EXPR
- PATH
+ CONST_ARG
+ PATH_EXPR
PATH
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "i32"
+ COLON2 "::"
PATH_SEGMENT
NAME_REF
- IDENT "i32"
- COLON2 "::"
- PATH_SEGMENT
- NAME_REF
- IDENT "MAX"
+ IDENT "MAX"
R_ANGLE ">"
SEMICOLON ";"
WHITESPACE "\n"
diff --git a/crates/parser/test_data/parser/inline/ok/0199_const_param_default_expression.rast b/crates/parser/test_data/parser/inline/ok/0199_const_param_default_expression.rast
index 0607ff54fb..d650113749 100644
--- a/crates/parser/test_data/parser/inline/ok/0199_const_param_default_expression.rast
+++ b/crates/parser/test_data/parser/inline/ok/0199_const_param_default_expression.rast
@@ -21,14 +21,15 @@ SOURCE_FILE
WHITESPACE " "
EQ "="
WHITESPACE " "
- BLOCK_EXPR
- STMT_LIST
- L_CURLY "{"
- WHITESPACE " "
- LITERAL
- INT_NUMBER "1"
- WHITESPACE " "
- R_CURLY "}"
+ CONST_ARG
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "1"
+ WHITESPACE " "
+ R_CURLY "}"
R_ANGLE ">"
SEMICOLON ";"
WHITESPACE "\n"
diff --git a/crates/parser/test_data/parser/inline/ok/0200_const_param_default_literal.rast b/crates/parser/test_data/parser/inline/ok/0200_const_param_default_literal.rast
index 8e52313651..6de10353bf 100644
--- a/crates/parser/test_data/parser/inline/ok/0200_const_param_default_literal.rast
+++ b/crates/parser/test_data/parser/inline/ok/0200_const_param_default_literal.rast
@@ -21,10 +21,11 @@ SOURCE_FILE
WHITESPACE " "
EQ "="
WHITESPACE " "
- PREFIX_EXPR
- MINUS "-"
- LITERAL
- INT_NUMBER "1"
+ CONST_ARG
+ PREFIX_EXPR
+ MINUS "-"
+ LITERAL
+ INT_NUMBER "1"
R_ANGLE ">"
SEMICOLON ";"
WHITESPACE "\n"
diff --git a/crates/syntax/rust.ungram b/crates/syntax/rust.ungram
index 138ddd2089..ea7ebd85b3 100644
--- a/crates/syntax/rust.ungram
+++ b/crates/syntax/rust.ungram
@@ -296,7 +296,7 @@ TypeParam =
ConstParam =
Attr* 'const' Name ':' Type
- ('=' default_val:Expr)?
+ ('=' default_val:ConstArg)?
LifetimeParam =
Attr* Lifetime (':' TypeBoundList?)?
diff --git a/crates/syntax/src/ast/generated/nodes.rs b/crates/syntax/src/ast/generated/nodes.rs
index 0b27faa535..16448db04f 100644
--- a/crates/syntax/src/ast/generated/nodes.rs
+++ b/crates/syntax/src/ast/generated/nodes.rs
@@ -709,7 +709,7 @@ impl ConstParam {
pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) }
pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
- pub fn default_val(&self) -> Option<Expr> { support::child(&self.syntax) }
+ pub fn default_val(&self) -> Option<ConstArg> { support::child(&self.syntax) }
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs
index c240008e7a..17e311c0c5 100644
--- a/crates/syntax/src/ast/make.rs
+++ b/crates/syntax/src/ast/make.rs
@@ -503,11 +503,16 @@ pub fn hacky_block_expr(
pub fn expr_unit() -> ast::Expr {
expr_from_text("()")
}
+
pub fn expr_literal(text: &str) -> ast::Literal {
assert_eq!(text.trim(), text);
ast_from_text(&format!("fn f() {{ let _ = {text}; }}"))
}
+pub fn expr_const_value(text: &str) -> ast::ConstArg {
+ ast_from_text(&format!("trait Foo<const N: usize = {text}> {{}}"))
+}
+
pub fn expr_empty_block() -> ast::Expr {
expr_from_text("{}")
}