Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/hir-def/src/db.rs25
-rw-r--r--crates/hir-def/src/expr_store.rs51
-rw-r--r--crates/hir-def/src/expr_store/body.rs2
-rw-r--r--crates/hir-def/src/expr_store/lower.rs77
-rw-r--r--crates/hir-def/src/expr_store/lower/generics.rs17
-rw-r--r--crates/hir-def/src/expr_store/lower/path/tests.rs2
-rw-r--r--crates/hir-def/src/expr_store/scope.rs51
-rw-r--r--crates/hir-def/src/lib.rs73
-rw-r--r--crates/hir-def/src/resolver.rs44
-rw-r--r--crates/hir-def/src/signatures.rs10
-rw-r--r--crates/hir-def/src/test_db.rs2
-rw-r--r--crates/hir-ty/src/consteval.rs5
-rw-r--r--crates/hir-ty/src/db.rs10
-rw-r--r--crates/hir-ty/src/display.rs14
-rw-r--r--crates/hir-ty/src/drop.rs7
-rw-r--r--crates/hir-ty/src/infer.rs124
-rw-r--r--crates/hir-ty/src/infer/closure/analysis.rs2
-rw-r--r--crates/hir-ty/src/infer/coerce.rs5
-rw-r--r--crates/hir-ty/src/infer/pat.rs2
-rw-r--r--crates/hir-ty/src/layout.rs5
-rw-r--r--crates/hir-ty/src/lower.rs73
-rw-r--r--crates/hir-ty/src/mir/borrowck.rs11
-rw-r--r--crates/hir-ty/src/mir/eval.rs8
-rw-r--r--crates/hir-ty/src/mir/eval/shim.rs5
-rw-r--r--crates/hir-ty/src/mir/lower.rs14
-rw-r--r--crates/hir-ty/src/next_solver/def_id.rs17
-rw-r--r--crates/hir-ty/src/next_solver/interner.rs52
-rw-r--r--crates/hir-ty/src/next_solver/solver.rs7
-rw-r--r--crates/hir-ty/src/next_solver/ty.rs2
-rw-r--r--crates/hir-ty/src/tests/closure_captures.rs7
-rw-r--r--crates/hir-ty/src/tests/incremental.rs14
-rw-r--r--crates/hir/src/has_source.rs5
-rw-r--r--crates/hir/src/lib.rs26
-rw-r--r--crates/hir/src/source_analyzer.rs6
-rw-r--r--crates/ide-assists/src/handlers/add_explicit_enum_discriminant.rs6
-rw-r--r--crates/ide/src/inlay_hints/discriminant.rs2
-rw-r--r--crates/parser/src/grammar/items/adt.rs4
-rw-r--r--crates/parser/test_data/parser/inline/ok/record_field_default_values.rast5
-rw-r--r--crates/parser/test_data/parser/inline/ok/variant_discriminant.rast5
-rw-r--r--crates/parser/test_data/parser/ok/0019_enums.rast5
-rw-r--r--crates/syntax/rust.ungram4
-rw-r--r--crates/syntax/src/ast/generated/nodes.rs4
-rw-r--r--crates/syntax/src/ast/syntax_factory/constructors.rs6
43 files changed, 632 insertions, 184 deletions
diff --git a/crates/hir-def/src/db.rs b/crates/hir-def/src/db.rs
index b0b652a150..ba0efe0ff1 100644
--- a/crates/hir-def/src/db.rs
+++ b/crates/hir-def/src/db.rs
@@ -8,12 +8,13 @@ use la_arena::ArenaMap;
use triomphe::Arc;
use crate::{
- AssocItemId, AttrDefId, BlockId, BlockLoc, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc,
- EnumVariantId, EnumVariantLoc, ExternBlockId, ExternBlockLoc, ExternCrateId, ExternCrateLoc,
- FunctionId, FunctionLoc, GenericDefId, ImplId, ImplLoc, LocalFieldId, Macro2Id, Macro2Loc,
- MacroExpander, MacroId, MacroRulesId, MacroRulesLoc, MacroRulesLocFlags, ProcMacroId,
- ProcMacroLoc, StaticId, StaticLoc, StructId, StructLoc, TraitId, TraitLoc, TypeAliasId,
- TypeAliasLoc, UnionId, UnionLoc, UseId, UseLoc, VariantId,
+ AnonConstId, AnonConstLoc, AssocItemId, AttrDefId, BlockId, BlockLoc, ConstId, ConstLoc,
+ DefWithBodyId, EnumId, EnumLoc, EnumVariantId, EnumVariantLoc, ExpressionStoreOwner,
+ ExternBlockId, ExternBlockLoc, ExternCrateId, ExternCrateLoc, FunctionId, FunctionLoc,
+ GenericDefId, ImplId, ImplLoc, LocalFieldId, Macro2Id, Macro2Loc, MacroExpander, MacroId,
+ MacroRulesId, MacroRulesLoc, MacroRulesLocFlags, ProcMacroId, ProcMacroLoc, StaticId,
+ StaticLoc, StructId, StructLoc, TraitId, TraitLoc, TypeAliasId, TypeAliasLoc, UnionId,
+ UnionLoc, UseId, UseLoc, VariantId,
attrs::AttrFlags,
expr_store::{
Body, BodySourceMap, ExpressionStore, ExpressionStoreSourceMap, scope::ExprScopes,
@@ -62,6 +63,9 @@ pub trait InternDatabase: RootQueryDb {
fn intern_static(&self, loc: StaticLoc) -> StaticId;
#[salsa::interned]
+ fn intern_anon_const(&self, loc: AnonConstLoc) -> AnonConstId;
+
+ #[salsa::interned]
fn intern_trait(&self, loc: TraitLoc) -> TraitId;
#[salsa::interned]
@@ -212,8 +216,15 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + SourceDatabase {
#[salsa::invoke(Body::body_query)]
fn body(&self, def: DefWithBodyId) -> Arc<Body>;
+ #[salsa::invoke(ExprScopes::body_expr_scopes_query)]
+ fn body_expr_scopes(&self, def: DefWithBodyId) -> Arc<ExprScopes>;
+
+ #[salsa::invoke(ExprScopes::sig_expr_scopes_query)]
+ fn sig_expr_scopes(&self, def: GenericDefId) -> Arc<ExprScopes>;
+
+ #[salsa::transparent]
#[salsa::invoke(ExprScopes::expr_scopes_query)]
- fn expr_scopes(&self, def: DefWithBodyId) -> Arc<ExprScopes>;
+ fn expr_scopes(&self, def: ExpressionStoreOwner) -> Arc<ExprScopes>;
#[salsa::transparent]
#[salsa::invoke(GenericParams::new)]
diff --git a/crates/hir-def/src/expr_store.rs b/crates/hir-def/src/expr_store.rs
index 1ce4c881e7..8552c72845 100644
--- a/crates/hir-def/src/expr_store.rs
+++ b/crates/hir-def/src/expr_store.rs
@@ -94,9 +94,24 @@ pub type TypeSource = InFile<TypePtr>;
pub type LifetimePtr = AstPtr<ast::Lifetime>;
pub type LifetimeSource = InFile<LifetimePtr>;
+/// Describes where a const expression originated from.
+///
+/// Used by signature/body inference to determine the expected type for each
+/// const expression root.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub enum ConstExprOrigin {
+ /// Array length expression: `[T; <expr>]` — expected type is `usize`.
+ ArrayLength,
+ /// Const parameter default value: `const N: usize = <expr>`.
+ ConstParam(crate::hir::generics::LocalTypeOrConstParamId),
+ /// Const generic argument in a path: `SomeType::<{ <expr> }>` or `some_fn::<{ <expr> }>()`.
+ /// Determining the expected type requires path resolution, so it is deferred.
+ GenericArgsPath,
+}
+
// We split the store into types-only and expressions, because most stores (e.g. generics)
// don't store any expressions and this saves memory. Same thing for the source map.
-#[derive(Debug, PartialEq, Eq)]
+#[derive(Debug, Clone, PartialEq, Eq)]
struct ExpressionOnlyStore {
exprs: Arena<Expr>,
pats: Arena<Pat>,
@@ -113,9 +128,15 @@ struct ExpressionOnlyStore {
/// Expressions (and destructuing patterns) that can be recorded here are single segment path, although not all single segments path refer
/// to variables and have hygiene (some refer to items, we don't know at this stage).
ident_hygiene: FxHashMap<ExprOrPatId, HygieneId>,
+
+ /// Maps const expression roots to their origin.
+ ///
+ /// Populated during lowering. Used by signature inference to determine expected types,
+ /// and by `signature_const_expr_roots()` to enumerate roots for scope computation.
+ const_expr_origins: ThinVec<(ExprId, ConstExprOrigin)>,
}
-#[derive(Debug, PartialEq, Eq)]
+#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ExpressionStore {
expr_only: Option<Box<ExpressionOnlyStore>>,
pub types: Arena<TypeRef>,
@@ -226,6 +247,7 @@ pub struct ExpressionStoreBuilder {
pub types: Arena<TypeRef>,
block_scopes: Vec<BlockId>,
ident_hygiene: FxHashMap<ExprOrPatId, HygieneId>,
+ pub const_expr_origins: Option<ThinVec<(ExprId, ConstExprOrigin)>>,
// AST expressions can create patterns in destructuring assignments. Therefore, `ExprSource` can also map
// to `PatId`, and `PatId` can also map to `ExprSource` (the other way around is unaffected).
@@ -297,6 +319,7 @@ impl ExpressionStoreBuilder {
mut bindings,
mut binding_owners,
mut ident_hygiene,
+ const_expr_origins,
mut types,
mut lifetimes,
@@ -364,6 +387,7 @@ impl ExpressionStoreBuilder {
binding_owners,
block_scopes: block_scopes.into_boxed_slice(),
ident_hygiene,
+ const_expr_origins: const_expr_origins.unwrap_or_default(),
}))
} else {
None
@@ -413,6 +437,29 @@ impl ExpressionStore {
EMPTY.clone()
}
+ /// Returns all const expression root `ExprId`s found in this store.
+ ///
+ /// Used to compute expression scopes for signature stores.
+ pub fn signature_const_expr_roots(&self) -> impl Iterator<Item = ExprId> {
+ self.const_expr_origins().iter().map(|&(id, _)| id)
+ }
+
+ /// Like [`Self::signature_const_expr_roots`], but also returns the origin
+ /// of each const expression.
+ ///
+ /// This is used by signature inference to determine the expected type for
+ /// each root expression.
+ pub fn signature_const_expr_roots_with_origins(
+ &self,
+ ) -> impl Iterator<Item = (ExprId, ConstExprOrigin)> {
+ self.const_expr_origins().iter().map(|&(id, origin)| (id, origin))
+ }
+
+ /// Returns the map of const expression roots to their origins.
+ pub fn const_expr_origins(&self) -> &[(ExprId, ConstExprOrigin)] {
+ self.expr_only.as_ref().map_or(&[], |it| &it.const_expr_origins)
+ }
+
/// Returns an iterator over all block expressions in this store that define inner items.
pub fn blocks<'a>(
&'a self,
diff --git a/crates/hir-def/src/expr_store/body.rs b/crates/hir-def/src/expr_store/body.rs
index c955393b9c..ad8fa73ad8 100644
--- a/crates/hir-def/src/expr_store/body.rs
+++ b/crates/hir-def/src/expr_store/body.rs
@@ -99,7 +99,7 @@ impl Body {
DefWithBodyId::VariantId(v) => {
let s = v.lookup(db);
let src = s.source(db);
- src.map(|it| it.expr())
+ src.map(|it| it.const_arg()?.expr())
}
}
};
diff --git a/crates/hir-def/src/expr_store/lower.rs b/crates/hir-def/src/expr_store/lower.rs
index 1cecd1976b..67ce5eafc6 100644
--- a/crates/hir-def/src/expr_store/lower.rs
+++ b/crates/hir-def/src/expr_store/lower.rs
@@ -37,7 +37,7 @@ use crate::{
attrs::AttrFlags,
db::DefDatabase,
expr_store::{
- Body, BodySourceMap, ExprPtr, ExpressionStore, ExpressionStoreBuilder,
+ Body, BodySourceMap, ConstExprOrigin, ExprPtr, ExpressionStore, ExpressionStoreBuilder,
ExpressionStoreDiagnostics, ExpressionStoreSourceMap, HygieneId, LabelPtr, LifetimePtr,
PatPtr, TypePtr,
expander::Expander,
@@ -79,7 +79,7 @@ pub(super) fn lower_body(
let mut self_param = None;
let mut source_map_self_param = None;
let mut params = vec![];
- let mut collector = ExprCollector::new(db, module, current_file_id);
+ let mut collector = ExprCollector::body(db, module, current_file_id);
let skip_body = AttrFlags::query(
db,
@@ -186,7 +186,7 @@ pub(crate) fn lower_type_ref(
module: ModuleId,
type_ref: InFile<Option<ast::Type>>,
) -> (ExpressionStore, ExpressionStoreSourceMap, TypeRefId) {
- let mut expr_collector = ExprCollector::new(db, module, type_ref.file_id);
+ let mut expr_collector = ExprCollector::signature(db, module, type_ref.file_id);
let type_ref =
expr_collector.lower_type_ref_opt(type_ref.value, &mut ExprCollector::impl_trait_allocator);
let (store, source_map) = expr_collector.store.finish();
@@ -201,7 +201,7 @@ pub(crate) fn lower_generic_params(
param_list: Option<ast::GenericParamList>,
where_clause: Option<ast::WhereClause>,
) -> (Arc<ExpressionStore>, Arc<GenericParams>, ExpressionStoreSourceMap) {
- let mut expr_collector = ExprCollector::new(db, module, file_id);
+ let mut expr_collector = ExprCollector::signature(db, module, file_id);
let mut collector = generics::GenericParamsCollector::new(def);
collector.lower(&mut expr_collector, param_list, where_clause);
let params = collector.finish();
@@ -215,7 +215,7 @@ pub(crate) fn lower_impl(
impl_syntax: InFile<ast::Impl>,
impl_id: ImplId,
) -> (ExpressionStore, ExpressionStoreSourceMap, TypeRefId, Option<TraitRef>, Arc<GenericParams>) {
- let mut expr_collector = ExprCollector::new(db, module, impl_syntax.file_id);
+ let mut expr_collector = ExprCollector::signature(db, module, impl_syntax.file_id);
let self_ty =
expr_collector.lower_type_ref_opt_disallow_impl_trait(impl_syntax.value.self_ty());
let trait_ = impl_syntax.value.trait_().and_then(|it| match &it {
@@ -243,7 +243,7 @@ pub(crate) fn lower_trait(
trait_syntax: InFile<ast::Trait>,
trait_id: TraitId,
) -> (ExpressionStore, ExpressionStoreSourceMap, Arc<GenericParams>) {
- let mut expr_collector = ExprCollector::new(db, module, trait_syntax.file_id);
+ let mut expr_collector = ExprCollector::signature(db, module, trait_syntax.file_id);
let mut collector = generics::GenericParamsCollector::with_self_param(
&mut expr_collector,
trait_id.into(),
@@ -271,7 +271,7 @@ pub(crate) fn lower_type_alias(
Box<[TypeBound]>,
Option<TypeRefId>,
) {
- let mut expr_collector = ExprCollector::new(db, module, alias.file_id);
+ let mut expr_collector = ExprCollector::signature(db, module, alias.file_id);
let bounds = alias
.value
.type_bound_list()
@@ -313,7 +313,7 @@ pub(crate) fn lower_function(
bool,
bool,
) {
- let mut expr_collector = ExprCollector::new(db, module, fn_.file_id);
+ let mut expr_collector = ExprCollector::signature(db, module, fn_.file_id);
let mut collector = generics::GenericParamsCollector::new(function_id.into());
collector.lower(&mut expr_collector, fn_.value.generic_param_list(), fn_.value.where_clause());
let mut params = vec![];
@@ -532,7 +532,20 @@ impl BindingList {
}
impl<'db> ExprCollector<'db> {
- pub fn new(
+ /// Creates a collector for a signature store, this will populate `const_expr_origins` to any
+ /// top level const arg roots.
+ pub fn signature(
+ db: &dyn DefDatabase,
+ module: ModuleId,
+ current_file_id: HirFileId,
+ ) -> ExprCollector<'_> {
+ let mut this = Self::body(db, module, current_file_id);
+ this.store.const_expr_origins = Some(Default::default());
+ this
+ }
+
+ /// Creates a collector for a bidy store.
+ pub fn body(
db: &dyn DefDatabase,
module: ModuleId,
current_file_id: HirFileId,
@@ -577,7 +590,10 @@ impl<'db> ExprCollector<'db> {
self.expander.span_map()
}
- pub fn lower_lifetime_ref(&mut self, lifetime: ast::Lifetime) -> LifetimeRefId {
+ pub(in crate::expr_store) fn lower_lifetime_ref(
+ &mut self,
+ lifetime: ast::Lifetime,
+ ) -> LifetimeRefId {
// FIXME: Keyword check?
let lifetime_ref = match &*lifetime.text() {
"" | "'" => LifetimeRef::Error,
@@ -588,7 +604,10 @@ impl<'db> ExprCollector<'db> {
self.alloc_lifetime_ref(lifetime_ref, AstPtr::new(&lifetime))
}
- pub fn lower_lifetime_ref_opt(&mut self, lifetime: Option<ast::Lifetime>) -> LifetimeRefId {
+ pub(in crate::expr_store) fn lower_lifetime_ref_opt(
+ &mut self,
+ lifetime: Option<ast::Lifetime>,
+ ) -> LifetimeRefId {
match lifetime {
Some(lifetime) => self.lower_lifetime_ref(lifetime),
None => self.alloc_lifetime_ref_desugared(LifetimeRef::Placeholder),
@@ -596,7 +615,7 @@ impl<'db> ExprCollector<'db> {
}
/// Converts an `ast::TypeRef` to a `hir::TypeRef`.
- pub fn lower_type_ref(
+ pub(in crate::expr_store) fn lower_type_ref(
&mut self,
node: ast::Type,
impl_trait_lower_fn: ImplTraitLowerFn<'_>,
@@ -621,6 +640,9 @@ impl<'db> ExprCollector<'db> {
}
ast::Type::ArrayType(inner) => {
let len = self.lower_const_arg_opt(inner.const_arg());
+ if let Some(const_expr_origins) = &mut self.store.const_expr_origins {
+ const_expr_origins.push((len.expr, ConstExprOrigin::ArrayLength));
+ }
TypeRef::Array(ArrayType {
ty: self.lower_type_ref_opt(inner.ty(), impl_trait_lower_fn),
len,
@@ -810,7 +832,7 @@ impl<'db> ExprCollector<'db> {
/// Collect `GenericArgs` from the parts of a fn-like path, i.e. `Fn(X, Y)
/// -> Z` (which desugars to `Fn<(X, Y), Output=Z>`).
- pub fn lower_generic_args_from_fn_path(
+ pub(in crate::expr_store) fn lower_generic_args_from_fn_path(
&mut self,
args: Option<ast::ParenthesizedArgList>,
ret_type: Option<ast::RetType>,
@@ -905,6 +927,9 @@ impl<'db> ExprCollector<'db> {
}
ast::GenericArg::ConstArg(arg) => {
let arg = self.lower_const_arg(arg);
+ if let Some(const_expr_origins) = &mut self.store.const_expr_origins {
+ const_expr_origins.push((arg.expr, ConstExprOrigin::GenericArgsPath));
+ }
args.push(GenericArg::Const(arg))
}
}
@@ -1045,17 +1070,30 @@ impl<'db> ExprCollector<'db> {
}
fn lower_const_arg_opt(&mut self, arg: Option<ast::ConstArg>) -> ConstRef {
- ConstRef { expr: self.collect_expr_opt(arg.and_then(|it| it.expr())) }
+ let const_expr_origins = self.store.const_expr_origins.take();
+ let r = ConstRef { expr: self.collect_expr_opt(arg.and_then(|it| it.expr())) };
+ self.store.const_expr_origins = const_expr_origins;
+ r
}
- fn lower_const_arg(&mut self, arg: ast::ConstArg) -> ConstRef {
- ConstRef { expr: self.collect_expr_opt(arg.expr()) }
+ pub fn lower_const_arg(&mut self, arg: ast::ConstArg) -> ConstRef {
+ let const_expr_origins = self.store.const_expr_origins.take();
+ let r = ConstRef { expr: self.collect_expr_opt(arg.expr()) };
+ self.store.const_expr_origins = const_expr_origins;
+ r
}
fn collect_expr(&mut self, expr: ast::Expr) -> ExprId {
self.maybe_collect_expr(expr).unwrap_or_else(|| self.missing_expr())
}
+ pub(in crate::expr_store) fn collect_expr_opt(&mut self, expr: Option<ast::Expr>) -> ExprId {
+ match expr {
+ Some(expr) => self.collect_expr(expr),
+ None => self.missing_expr(),
+ }
+ }
+
/// Returns `None` if and only if the expression is `#[cfg]`d out.
fn maybe_collect_expr(&mut self, expr: ast::Expr) -> Option<ExprId> {
let syntax_ptr = AstPtr::new(&expr);
@@ -2065,13 +2103,6 @@ impl<'db> ExprCollector<'db> {
}
}
- pub fn collect_expr_opt(&mut self, expr: Option<ast::Expr>) -> ExprId {
- match expr {
- Some(expr) => self.collect_expr(expr),
- None => self.missing_expr(),
- }
- }
-
fn collect_macro_as_stmt(
&mut self,
statements: &mut Vec<Statement>,
diff --git a/crates/hir-def/src/expr_store/lower/generics.rs b/crates/hir-def/src/expr_store/lower/generics.rs
index c570df42b2..03de7937ba 100644
--- a/crates/hir-def/src/expr_store/lower/generics.rs
+++ b/crates/hir-def/src/expr_store/lower/generics.rs
@@ -141,12 +141,17 @@ impl GenericParamsCollector {
const_param.ty(),
&mut ExprCollector::impl_trait_error_allocator,
);
- let param = ConstParamData {
- name,
- ty,
- default: const_param.default_val().map(|it| ec.lower_const_arg(it)),
- };
- let _idx = self.type_or_consts.alloc(param.into());
+ let default = const_param.default_val().map(|it| ec.lower_const_arg(it));
+ let param = ConstParamData { name, ty, default };
+ let idx = self.type_or_consts.alloc(param.into());
+ if let Some(default) = default
+ && let Some(const_expr_origins) = &mut ec.store.const_expr_origins
+ {
+ const_expr_origins.push((
+ default.expr,
+ crate::expr_store::ConstExprOrigin::ConstParam(idx),
+ ));
+ }
}
ast::GenericParam::LifetimeParam(lifetime_param) => {
let lifetime = ec.lower_lifetime_ref_opt(lifetime_param.lifetime());
diff --git a/crates/hir-def/src/expr_store/lower/path/tests.rs b/crates/hir-def/src/expr_store/lower/path/tests.rs
index f507841a91..6819eb3deb 100644
--- a/crates/hir-def/src/expr_store/lower/path/tests.rs
+++ b/crates/hir-def/src/expr_store/lower/path/tests.rs
@@ -21,7 +21,7 @@ fn lower_path(path: ast::Path) -> (TestDB, ExpressionStore, Option<Path>) {
let (db, file_id) = TestDB::with_single_file("");
let krate = db.fetch_test_crate();
let mut ctx =
- ExprCollector::new(&db, crate_def_map(&db, krate).root_module_id(), file_id.into());
+ ExprCollector::signature(&db, crate_def_map(&db, krate).root_module_id(), file_id.into());
let lowered_path = ctx.lower_path(path, &mut ExprCollector::impl_trait_allocator);
let (store, _) = ctx.store.finish();
(db, store, lowered_path)
diff --git a/crates/hir-def/src/expr_store/scope.rs b/crates/hir-def/src/expr_store/scope.rs
index 1952dae9d7..43ce053836 100644
--- a/crates/hir-def/src/expr_store/scope.rs
+++ b/crates/hir-def/src/expr_store/scope.rs
@@ -4,7 +4,7 @@ use la_arena::{Arena, ArenaMap, Idx, IdxRange, RawIdx};
use triomphe::Arc;
use crate::{
- BlockId, DefWithBodyId,
+ BlockId, DefWithBodyId, ExpressionStoreOwner, GenericDefId,
db::DefDatabase,
expr_store::{Body, ExpressionStore, HygieneId},
hir::{Binding, BindingId, Expr, ExprId, Item, LabelId, Pat, PatId, Statement},
@@ -51,13 +51,37 @@ pub struct ScopeData {
}
impl ExprScopes {
- pub(crate) fn expr_scopes_query(db: &dyn DefDatabase, def: DefWithBodyId) -> Arc<ExprScopes> {
+ pub(crate) fn expr_scopes_query(
+ db: &dyn DefDatabase,
+ def: ExpressionStoreOwner,
+ ) -> Arc<ExprScopes> {
+ match def {
+ ExpressionStoreOwner::Body(def) => db.body_expr_scopes(def),
+ ExpressionStoreOwner::Signature(def) => db.sig_expr_scopes(def),
+ }
+ }
+
+ pub(crate) fn body_expr_scopes_query(
+ db: &dyn DefDatabase,
+ def: DefWithBodyId,
+ ) -> Arc<ExprScopes> {
let body = db.body(def);
let mut scopes = ExprScopes::new_body(&body);
scopes.shrink_to_fit();
Arc::new(scopes)
}
+ pub(crate) fn sig_expr_scopes_query(
+ db: &dyn DefDatabase,
+ def: GenericDefId,
+ ) -> Arc<ExprScopes> {
+ let (_, store) = db.generic_params_and_store(def);
+ let roots = store.signature_const_expr_roots();
+ let mut scopes = ExprScopes::new_store(&store, roots);
+ scopes.shrink_to_fit();
+ Arc::new(scopes)
+ }
+
pub fn entries(&self, scope: ScopeId) -> &[ScopeEntry] {
&self.scope_entries[self.scopes[scope].entries.clone()]
}
@@ -119,6 +143,22 @@ impl ExprScopes {
scopes
}
+ fn new_store(store: &ExpressionStore, roots: impl IntoIterator<Item = ExprId>) -> ExprScopes {
+ let mut scopes = ExprScopes {
+ scopes: Arena::default(),
+ scope_entries: Arena::default(),
+ scope_by_expr: ArenaMap::with_capacity(
+ store.expr_only.as_ref().map_or(0, |it| it.exprs.len()),
+ ),
+ };
+ let root = scopes.root_scope();
+ for root_expr in roots {
+ let mut scope = scopes.new_scope(root);
+ compute_expr_scopes(root_expr, store, &mut scopes, &mut scope);
+ }
+ scopes
+ }
+
fn root_scope(&mut self) -> ScopeId {
self.scopes.alloc(ScopeData {
parent: None,
@@ -327,7 +367,8 @@ mod tests {
use test_utils::{assert_eq_text, extract_offset};
use crate::{
- FunctionId, ModuleDefId, db::DefDatabase, nameres::crate_def_map, test_db::TestDB,
+ DefWithBodyId, FunctionId, ModuleDefId, db::DefDatabase, nameres::crate_def_map,
+ test_db::TestDB,
};
fn find_function(db: &TestDB, file_id: FileId) -> FunctionId {
@@ -363,7 +404,7 @@ mod tests {
let marker: ast::PathExpr = find_node_at_offset(&file_syntax, offset).unwrap();
let function = find_function(&db, file_id);
- let scopes = db.expr_scopes(function.into());
+ let scopes = db.expr_scopes(DefWithBodyId::from(function).into());
let (_body, source_map) = db.body_with_source_map(function.into());
let expr_id = source_map
@@ -522,7 +563,7 @@ fn foo() {
let function = find_function(&db, file_id);
- let scopes = db.expr_scopes(function.into());
+ let scopes = db.expr_scopes(DefWithBodyId::from(function).into());
let (_, source_map) = db.body_with_source_map(function.into());
let expr_scope = {
diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs
index de674be05f..ffad5fee47 100644
--- a/crates/hir-def/src/lib.rs
+++ b/crates/hir-def/src/lib.rs
@@ -86,7 +86,10 @@ use crate::{
builtin_type::BuiltinType,
db::DefDatabase,
expr_store::ExpressionStoreSourceMap,
- hir::generics::{GenericParams, LocalLifetimeParamId, LocalTypeOrConstParamId},
+ hir::{
+ ExprId,
+ generics::{GenericParams, LocalLifetimeParamId, LocalTypeOrConstParamId},
+ },
nameres::{
LocalDefMap,
assoc::{ImplItems, TraitItems},
@@ -306,6 +309,19 @@ impl_intern!(ConstId, ConstLoc, intern_const, lookup_intern_const);
pub type StaticLoc = AssocItemLoc<ast::Static>;
impl_intern!(StaticId, StaticLoc, intern_static, lookup_intern_static);
+/// An anonymous const expression that appears in a type position (e.g., array lengths,
+/// const generic arguments like `{ N + 1 }`). Unlike named constants, these don't have
+/// their own `Body` — their expressions live in the parent's signature `ExpressionStore`.
+#[derive(Debug, Hash, PartialEq, Eq, Clone)]
+pub struct AnonConstLoc {
+ /// The owner store containing this expression.
+ pub owner: ExpressionStoreOwner,
+ /// The ExprId within the owner's ExpressionStore that is the root
+ /// of this anonymous const expression.
+ pub expr: ExprId,
+}
+impl_intern!(AnonConstId, AnonConstLoc, intern_anon_const, lookup_intern_anon_const);
+
pub type TraitLoc = ItemLoc<ast::Trait>;
impl_intern!(TraitId, TraitLoc, intern_trait, lookup_intern_trait);
@@ -706,15 +722,17 @@ impl From<DefWithBodyId> for ModuleDefId {
pub enum GeneralConstId {
ConstId(ConstId),
StaticId(StaticId),
+ AnonConstId(AnonConstId),
}
-impl_from!(ConstId, StaticId for GeneralConstId);
+impl_from!(ConstId, StaticId, AnonConstId for GeneralConstId);
impl GeneralConstId {
- pub fn generic_def(self, _db: &dyn DefDatabase) -> Option<GenericDefId> {
+ pub fn generic_def(self, db: &dyn DefDatabase) -> Option<GenericDefId> {
match self {
GeneralConstId::ConstId(it) => Some(it.into()),
GeneralConstId::StaticId(it) => Some(it.into()),
+ GeneralConstId::AnonConstId(it) => Some(it.lookup(db).owner.generic_def(db)),
}
}
@@ -729,6 +747,7 @@ impl GeneralConstId {
|name| name.display(db, Edition::CURRENT).to_string(),
)
}
+ GeneralConstId::AnonConstId(_) => "{anon const}".to_owned(),
}
}
}
@@ -814,6 +833,45 @@ impl_from!(
for GenericDefId
);
+/// Owner of an expression store - either a body or a signature.
+/// This is used for queries that operate on expression stores generically,
+/// such as `expr_scopes`.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
+pub enum ExpressionStoreOwner {
+ Signature(GenericDefId),
+ Body(DefWithBodyId),
+}
+
+impl ExpressionStoreOwner {
+ pub fn as_def_with_body(self) -> Option<DefWithBodyId> {
+ if let Self::Body(v) = self { Some(v) } else { None }
+ }
+
+ pub fn generic_def(self, db: &dyn DefDatabase) -> GenericDefId {
+ match self {
+ ExpressionStoreOwner::Signature(generic_def_id) => generic_def_id,
+ ExpressionStoreOwner::Body(def_with_body_id) => match def_with_body_id {
+ DefWithBodyId::FunctionId(id) => GenericDefId::FunctionId(id),
+ DefWithBodyId::StaticId(id) => GenericDefId::StaticId(id),
+ DefWithBodyId::ConstId(id) => GenericDefId::ConstId(id),
+ DefWithBodyId::VariantId(it) => it.lookup(db).parent.into(),
+ },
+ }
+ }
+}
+
+impl From<GenericDefId> for ExpressionStoreOwner {
+ fn from(id: GenericDefId) -> Self {
+ ExpressionStoreOwner::Signature(id)
+ }
+}
+
+impl From<DefWithBodyId> for ExpressionStoreOwner {
+ fn from(id: DefWithBodyId) -> Self {
+ ExpressionStoreOwner::Body(id)
+ }
+}
+
impl GenericDefId {
pub fn file_id_and_params_of(
self,
@@ -1172,6 +1230,15 @@ impl HasModule for DefWithBodyId {
}
}
+impl HasModule for ExpressionStoreOwner {
+ fn module(&self, db: &dyn DefDatabase) -> ModuleId {
+ match self {
+ ExpressionStoreOwner::Signature(def) => def.module(db),
+ ExpressionStoreOwner::Body(def) => def.module(db),
+ }
+ }
+}
+
impl HasModule for GenericDefId {
fn module(&self, db: &dyn DefDatabase) -> ModuleId {
match self {
diff --git a/crates/hir-def/src/resolver.rs b/crates/hir-def/src/resolver.rs
index d32e53fc6b..392010df85 100644
--- a/crates/hir-def/src/resolver.rs
+++ b/crates/hir-def/src/resolver.rs
@@ -16,11 +16,11 @@ use syntax::ast::HasName;
use triomphe::Arc;
use crate::{
- AdtId, AstIdLoc, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, ExternBlockId,
- ExternCrateId, FunctionId, FxIndexMap, GenericDefId, GenericParamId, HasModule, ImplId,
- ItemContainerId, LifetimeParamId, Lookup, Macro2Id, MacroId, MacroRulesId, ModuleDefId,
- ModuleId, ProcMacroId, StaticId, StructId, TraitId, TypeAliasId, TypeOrConstParamId,
- TypeParamId, UseId, VariantId,
+ AdtId, AstIdLoc, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId,
+ ExpressionStoreOwner, ExternBlockId, ExternCrateId, FunctionId, FxIndexMap, GenericDefId,
+ GenericParamId, HasModule, ImplId, ItemContainerId, LifetimeParamId, Lookup, Macro2Id, MacroId,
+ MacroRulesId, ModuleDefId, ModuleId, ProcMacroId, StaticId, StructId, TraitId, TypeAliasId,
+ TypeOrConstParamId, TypeParamId, UseId, VariantId,
builtin_type::BuiltinType,
db::DefDatabase,
expr_store::{
@@ -66,7 +66,7 @@ impl fmt::Debug for ModuleItemMap<'_> {
#[derive(Clone)]
struct ExprScope {
- owner: DefWithBodyId,
+ owner: ExpressionStoreOwner,
expr_scopes: Arc<ExprScopes>,
scope_id: ScopeId,
}
@@ -738,7 +738,10 @@ impl<'db> Resolver<'db> {
pub fn body_owner(&self) -> Option<DefWithBodyId> {
self.scopes().find_map(|scope| match scope {
- Scope::ExprScope(it) => Some(it.owner),
+ Scope::ExprScope(it) => match it.owner {
+ ExpressionStoreOwner::Body(def) => Some(def),
+ ExpressionStoreOwner::Signature(_) => None,
+ },
_ => None,
})
}
@@ -854,14 +857,15 @@ impl<'db> Resolver<'db> {
pub fn update_to_inner_scope(
&mut self,
db: &'db dyn DefDatabase,
- owner: DefWithBodyId,
+ owner: impl Into<ExpressionStoreOwner>,
expr_id: ExprId,
) -> UpdateGuard {
+ let owner = owner.into();
#[inline(always)]
fn append_expr_scope<'db>(
db: &'db dyn DefDatabase,
resolver: &mut Resolver<'db>,
- owner: DefWithBodyId,
+ owner: ExpressionStoreOwner,
expr_scopes: &Arc<ExprScopes>,
scope_id: ScopeId,
) {
@@ -1060,12 +1064,13 @@ impl<'db> Scope<'db> {
pub fn resolver_for_scope(
db: &dyn DefDatabase,
- owner: DefWithBodyId,
+ owner: impl Into<ExpressionStoreOwner> + HasResolver,
scope_id: Option<ScopeId>,
) -> Resolver<'_> {
- let r = owner.resolver(db);
- let scopes = db.expr_scopes(owner);
- resolver_for_scope_(db, scopes, scope_id, r, owner)
+ let store_owner = owner.into();
+ let r = store_owner.resolver(db);
+ let scopes = db.expr_scopes(store_owner);
+ resolver_for_scope_(db, scopes, scope_id, r, store_owner)
}
fn resolver_for_scope_<'db>(
@@ -1073,7 +1078,7 @@ fn resolver_for_scope_<'db>(
scopes: Arc<ExprScopes>,
scope_id: Option<ScopeId>,
mut r: Resolver<'db>,
- owner: DefWithBodyId,
+ owner: ExpressionStoreOwner,
) -> Resolver<'db> {
let scope_chain = scopes.scope_chain(scope_id).collect::<Vec<_>>();
r.scopes.reserve(scope_chain.len());
@@ -1124,7 +1129,7 @@ impl<'db> Resolver<'db> {
fn push_expr_scope(
self,
- owner: DefWithBodyId,
+ owner: ExpressionStoreOwner,
expr_scopes: Arc<ExprScopes>,
scope_id: ScopeId,
) -> Resolver<'db> {
@@ -1409,6 +1414,15 @@ impl HasResolver for GenericDefId {
}
}
+impl HasResolver for ExpressionStoreOwner {
+ fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
+ match self {
+ ExpressionStoreOwner::Signature(def) => def.resolver(db),
+ ExpressionStoreOwner::Body(def) => def.resolver(db),
+ }
+ }
+}
+
impl HasResolver for EnumVariantId {
fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
self.lookup(db).parent.resolver(db)
diff --git a/crates/hir-def/src/signatures.rs b/crates/hir-def/src/signatures.rs
index 37c8f762fe..ce76158151 100644
--- a/crates/hir-def/src/signatures.rs
+++ b/crates/hir-def/src/signatures.rs
@@ -32,7 +32,7 @@ use crate::{
hir::{ExprId, PatId, generics::GenericParams},
item_tree::{FieldsShape, RawVisibility, visibility_from_ast},
src::HasSource,
- type_ref::{TraitRef, TypeBound, TypeRefId},
+ type_ref::{ConstRef, TraitRef, TypeBound, TypeRefId},
};
#[inline]
@@ -754,7 +754,7 @@ pub struct FieldData {
pub type_ref: TypeRefId,
pub visibility: RawVisibility,
pub is_unsafe: bool,
- pub default_value: Option<ExprId>,
+ pub default_value: Option<ConstRef>,
}
pub type LocalFieldId = Idx<FieldData>;
@@ -873,7 +873,7 @@ fn lower_fields<Field: ast::HasAttrs + ast::HasVisibility>(
override_visibility: Option<Option<ast::Visibility>>,
) -> Option<(Arena<FieldData>, ExpressionStore, ExpressionStoreSourceMap)> {
let cfg_options = module.krate(db).cfg_options(db);
- let mut col = ExprCollector::new(db, module, fields.file_id);
+ let mut col = ExprCollector::signature(db, module, fields.file_id);
let override_visibility = override_visibility.map(|vis| {
LazyCell::new(|| {
let span_map = db.span_map(fields.file_id);
@@ -907,9 +907,9 @@ fn lower_fields<Field: ast::HasAttrs + ast::HasVisibility>(
// Check if field has default value (only for record fields)
let default_value = ast::RecordField::cast(field.syntax().clone())
- .and_then(|rf| rf.eq_token().is_some().then_some(rf.expr()))
+ .and_then(|rf| rf.eq_token().is_some().then_some(rf.default_val()))
.flatten()
- .map(|expr| col.collect_expr_opt(Some(expr)));
+ .map(|expr| col.lower_const_arg(expr));
arena.alloc(FieldData { name, type_ref, visibility, is_unsafe, default_value });
idx += 1;
diff --git a/crates/hir-def/src/test_db.rs b/crates/hir-def/src/test_db.rs
index e8377fde49..d2921db6f4 100644
--- a/crates/hir-def/src/test_db.rs
+++ b/crates/hir-def/src/test_db.rs
@@ -285,7 +285,7 @@ impl TestDB {
let (def_with_body, file_id) = fn_def?;
let def_with_body = def_with_body.into();
let source_map = self.body_with_source_map(def_with_body).1;
- let scopes = self.expr_scopes(def_with_body);
+ let scopes = self.expr_scopes(def_with_body.into());
let root_syntax_node = self.parse(file_id).syntax_node();
let scope_iter =
diff --git a/crates/hir-ty/src/consteval.rs b/crates/hir-ty/src/consteval.rs
index 07e9f70fae..9ff788c2e2 100644
--- a/crates/hir-ty/src/consteval.rs
+++ b/crates/hir-ty/src/consteval.rs
@@ -235,6 +235,7 @@ pub fn try_const_usize<'db>(db: &'db dyn HirDatabase, c: Const<'db>) -> Option<u
let ec = db.const_eval_static(id).ok()?;
try_const_usize(db, ec)
}
+ GeneralConstId::AnonConstId(_) => None,
},
ConstKind::Value(val) => Some(u128::from_le_bytes(pad16(&val.value.inner().memory, false))),
ConstKind::Error(_) => None,
@@ -258,6 +259,7 @@ pub fn try_const_isize<'db>(db: &'db dyn HirDatabase, c: &Const<'db>) -> Option<
let ec = db.const_eval_static(id).ok()?;
try_const_isize(db, &ec)
}
+ GeneralConstId::AnonConstId(_) => None,
},
ConstKind::Value(val) => Some(i128::from_le_bytes(pad16(&val.value.inner().memory, true))),
ConstKind::Error(_) => None,
@@ -333,7 +335,8 @@ pub(crate) fn eval_to_const<'db>(expr: ExprId, ctx: &mut InferenceContext<'_, 'd
return c;
}
}
- if let Ok(mir_body) = lower_body_to_mir(ctx.db, ctx.owner, ctx.body, &infer, expr)
+ if let Some(body_owner) = ctx.owner.as_def_with_body()
+ && let Ok(mir_body) = lower_body_to_mir(ctx.db, body_owner, ctx.body, &infer, expr)
&& let Ok((Ok(result), _)) = interpret_mir(ctx.db, Arc::new(mir_body), true, None)
{
return result;
diff --git a/crates/hir-ty/src/db.rs b/crates/hir-ty/src/db.rs
index 70474fc469..ca5b1b7716 100644
--- a/crates/hir-ty/src/db.rs
+++ b/crates/hir-ty/src/db.rs
@@ -5,9 +5,9 @@ use base_db::{Crate, target::TargetLoadError};
use either::Either;
use hir_def::{
AdtId, BuiltinDeriveImplId, CallableDefId, ConstId, ConstParamId, DefWithBodyId, EnumVariantId,
- FunctionId, GenericDefId, ImplId, LifetimeParamId, LocalFieldId, StaticId, TraitId,
- TypeAliasId, VariantId, builtin_derive::BuiltinDeriveImplMethod, db::DefDatabase, hir::ExprId,
- layout::TargetDataLayout,
+ ExpressionStoreOwner, FunctionId, GenericDefId, ImplId, LifetimeParamId, LocalFieldId,
+ StaticId, TraitId, TypeAliasId, VariantId, builtin_derive::BuiltinDeriveImplMethod,
+ db::DefDatabase, hir::ExprId, layout::TargetDataLayout,
};
use la_arena::ArenaMap;
use salsa::plumbing::AsId;
@@ -240,7 +240,7 @@ pub struct InternedOpaqueTyId {
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
-pub struct InternedClosure(pub DefWithBodyId, pub ExprId);
+pub struct InternedClosure(pub ExpressionStoreOwner, pub ExprId);
#[salsa_macros::interned(no_lifetime, debug, revisions = usize::MAX)]
#[derive(PartialOrd, Ord)]
@@ -249,7 +249,7 @@ pub struct InternedClosureId {
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
-pub struct InternedCoroutine(pub DefWithBodyId, pub ExprId);
+pub struct InternedCoroutine(pub ExpressionStoreOwner, pub ExprId);
#[salsa_macros::interned(no_lifetime, debug, revisions = usize::MAX)]
#[derive(PartialOrd, Ord)]
diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs
index 4e77e8be36..f4d0ed1484 100644
--- a/crates/hir-ty/src/display.rs
+++ b/crates/hir-ty/src/display.rs
@@ -1336,7 +1336,11 @@ impl<'db> HirDisplay<'db> for Ty<'db> {
}
let sig = interner.signature_unclosure(substs.as_closure().sig(), Safety::Safe);
let sig = sig.skip_binder();
- let InternedClosure(def, _) = db.lookup_intern_closure(id);
+ let InternedClosure(owner, _) = db.lookup_intern_closure(id);
+ let Some(def) = owner.as_def_with_body() else {
+ write!(f, "{{closure}}")?;
+ return Ok(());
+ };
let infer = InferenceResult::for_body(db, def);
let (_, kind) = infer.closure_info(id);
match f.closure_style {
@@ -1526,7 +1530,13 @@ impl<'db> HirDisplay<'db> for Ty<'db> {
let InternedCoroutine(owner, expr_id) = coroutine_id.0.loc(db);
let CoroutineArgsParts { resume_ty, yield_ty, return_ty, .. } =
subst.split_coroutine_args();
- let body = db.body(owner);
+ let Some(body_owner) = owner.as_def_with_body() else {
+ write!(f, "impl Future<Output = ")?;
+ return_ty.hir_fmt(f)?;
+ write!(f, ">")?;
+ return Ok(());
+ };
+ let body = db.body(body_owner);
let expr = &body[expr_id];
match expr {
hir_def::hir::Expr::Closure {
diff --git a/crates/hir-ty/src/drop.rs b/crates/hir-ty/src/drop.rs
index 9d6869eee9..1303e08801 100644
--- a/crates/hir-ty/src/drop.rs
+++ b/crates/hir-ty/src/drop.rs
@@ -132,9 +132,12 @@ fn has_drop_glue_impl<'db>(
TyKind::Slice(ty) => has_drop_glue_impl(infcx, ty, env, visited),
TyKind::Closure(closure_id, subst) => {
let owner = db.lookup_intern_closure(closure_id.0).0;
- let infer = InferenceResult::for_body(db, owner);
+ let Some(body_owner) = owner.as_def_with_body() else {
+ return DropGlue::None;
+ };
+ let infer = InferenceResult::for_body(db, body_owner);
let (captures, _) = infer.closure_info(closure_id.0);
- let env = db.trait_environment_for_body(owner);
+ let env = db.trait_environment_for_body(body_owner);
captures
.iter()
.map(|capture| has_drop_glue_impl(infcx, capture.ty(db, subst), env, visited))
diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs
index 991acda14b..a4fcded42b 100644
--- a/crates/hir-ty/src/infer.rs
+++ b/crates/hir-ty/src/infer.rs
@@ -33,9 +33,10 @@ use std::{cell::OnceCell, convert::identity, iter};
use base_db::Crate;
use either::Either;
use hir_def::{
- AdtId, AssocItemId, ConstId, DefWithBodyId, FieldId, FunctionId, GenericDefId, GenericParamId,
- ItemContainerId, LocalFieldId, Lookup, TraitId, TupleFieldId, TupleId, TypeAliasId, VariantId,
- expr_store::{Body, ExpressionStore, HygieneId, path::Path},
+ AdtId, AnonConstId, AssocItemId, ConstId, ConstParamId, DefWithBodyId, ExpressionStoreOwner,
+ FieldId, FunctionId, GenericDefId, GenericParamId, ItemContainerId, LocalFieldId, Lookup,
+ TraitId, TupleFieldId, TupleId, TypeAliasId, TypeOrConstParamId, VariantId,
+ expr_store::{Body, ConstExprOrigin, ExpressionStore, HygieneId, path::Path},
hir::{BindingAnnotation, BindingId, ExprId, ExprOrPatId, LabelId, PatId},
lang_item::LangItems,
layout::Integer,
@@ -105,7 +106,7 @@ pub fn infer_query_with_inspect<'db>(
let _p = tracing::info_span!("infer_query").entered();
let resolver = def.resolver(db);
let body = db.body(def);
- let mut ctx = InferenceContext::new(db, def, &body, resolver);
+ let mut ctx = InferenceContext::new(db, ExpressionStoreOwner::Body(def), &body, resolver);
if let Some(inspect) = inspect {
ctx.table.infer_ctxt.attach_obligation_inspector(inspect);
@@ -179,6 +180,68 @@ fn infer_cycle_result(db: &dyn HirDatabase, _: salsa::Id, _: DefWithBodyId) -> I
}
}
+/// Infer types for all const expressions in an item's signature.
+///
+/// This handles const expressions that appear in type positions within a generic
+/// item's signature, such as array lengths (`[T; N]`) and const generic arguments
+/// (`Foo<{ expr }>`). Each root expression is inferred independently within
+/// a shared `InferenceContext`, accumulating results into a single `InferenceResult`.
+fn infer_signature_query(db: &dyn HirDatabase, def: GenericDefId) -> InferenceResult {
+ let _p = tracing::info_span!("infer_signature_query").entered();
+ let (_, store) = db.generic_params_and_store(def);
+ let mut roots = store.signature_const_expr_roots_with_origins().peekable();
+ let Some(&(first, _)) = roots.peek() else {
+ return InferenceResult::new(crate::next_solver::default_types(db).types.error);
+ };
+
+ let resolver = def.resolver(db);
+ let owner = ExpressionStoreOwner::Signature(def);
+
+ // Construct a synthetic `Body` to satisfy `InferenceContext`.
+ // The `body_expr` is set to the first root as a placeholder; we infer
+ // each root expression individually below rather than calling `infer_body`.
+ let body = Body {
+ // FIXME: Get rid of this clone
+ store: (*store).clone(),
+ params: Box::new([]),
+ self_param: None,
+ body_expr: first,
+ };
+
+ let mut ctx = InferenceContext::new(db, owner, &body, resolver);
+
+ for (root_expr, origin) in roots {
+ let expected = match origin {
+ // Array lengths are always `usize`.
+ ConstExprOrigin::ArrayLength => Expectation::has_type(ctx.types.types.usize),
+ // Const parameter default: look up the param's declared type.
+ ConstExprOrigin::ConstParam(local_id) => Expectation::has_type(db.const_param_ty_ns(
+ ConstParamId::from_unchecked(TypeOrConstParamId { parent: def, local_id }),
+ )),
+ // Path const generic args: determining the expected type requires
+ // path resolution.
+ // FIXME
+ ConstExprOrigin::GenericArgsPath => Expectation::None,
+ };
+ ctx.infer_expr(root_expr, &expected, ExprIsRead::Yes);
+ }
+
+ ctx.type_inference_fallback();
+ ctx.table.select_obligations_where_possible();
+ ctx.resolve_all()
+}
+
+fn infer_signature_cycle_result(
+ db: &dyn HirDatabase,
+ _: salsa::Id,
+ _: GenericDefId,
+) -> InferenceResult {
+ InferenceResult {
+ has_errors: true,
+ ..InferenceResult::new(Ty::new_error(DbInterner::new_no_crate(db), ErrorGuaranteed))
+ }
+}
+
/// Binding modes inferred for patterns.
/// <https://doc.rust-lang.org/reference/patterns.html#binding-modes>
#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
@@ -555,9 +618,37 @@ impl InferenceResult {
pub fn for_body(db: &dyn HirDatabase, def: DefWithBodyId) -> InferenceResult {
infer_query(db, def)
}
+
+ /// Infer types for all const expressions in an item's signature.
+ ///
+ /// Returns an `InferenceResult` containing type information for array lengths,
+ /// const generic arguments, and other const expressions appearing in type
+ /// positions within the item's signature.
+ #[salsa::tracked(returns(ref), cycle_result = infer_signature_cycle_result)]
+ pub fn for_signature(db: &dyn HirDatabase, def: GenericDefId) -> InferenceResult {
+ infer_signature_query(db, def)
+ }
}
impl InferenceResult {
+ /// Look up inference results for a specific anonymous const in a signature.
+ ///
+ /// This delegates to [`Self::for_signature`] on the anon const's owner.
+ /// The returned `InferenceResult` contains types for *all* expressions in
+ /// the owner's signature store, not just this anon const's sub-tree.
+ /// Callers should index into it with `loc.expr` to get the root expression's
+ /// type.
+ // FIXME: This function doesn't make sense in that we can't return a full inference result here
+ // as the anon const is just part of an inference result.
+ pub fn for_anon_const(db: &dyn HirDatabase, id: AnonConstId) -> &InferenceResult {
+ match id.lookup(db).owner {
+ ExpressionStoreOwner::Signature(generic_def_id) => {
+ Self::for_signature(db, generic_def_id)
+ }
+ ExpressionStoreOwner::Body(def_with_body_id) => Self::for_body(db, def_with_body_id),
+ }
+ }
+
fn new(error_ty: Ty<'_>) -> Self {
Self {
method_resolutions: Default::default(),
@@ -754,7 +845,7 @@ impl InferenceResult {
#[derive(Clone, Debug)]
pub(crate) struct InferenceContext<'body, 'db> {
pub(crate) db: &'db dyn HirDatabase,
- pub(crate) owner: DefWithBodyId,
+ pub(crate) owner: ExpressionStoreOwner,
pub(crate) body: &'body Body,
/// Generally you should not resolve things via this resolver. Instead create a TyLoweringContext
/// and resolve the path via its methods. This will ensure proper error reporting.
@@ -855,12 +946,18 @@ fn find_continuable<'a, 'db>(
impl<'body, 'db> InferenceContext<'body, 'db> {
fn new(
db: &'db dyn HirDatabase,
- owner: DefWithBodyId,
+ owner: ExpressionStoreOwner,
body: &'body Body,
resolver: Resolver<'db>,
) -> Self {
- let trait_env = db.trait_environment_for_body(owner);
- let table = unify::InferenceTable::new(db, trait_env, resolver.krate(), Some(owner));
+ let trait_env = match owner {
+ ExpressionStoreOwner::Signature(generic_def_id) => db.trait_environment(generic_def_id),
+ ExpressionStoreOwner::Body(def_with_body_id) => {
+ db.trait_environment_for_body(def_with_body_id)
+ }
+ };
+ let table =
+ unify::InferenceTable::new(db, trait_env, resolver.krate(), owner.as_def_with_body());
let types = crate::next_solver::default_types(db);
InferenceContext {
result: InferenceResult::new(types.types.error),
@@ -878,12 +975,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
return_coercion: None,
db,
owner,
- generic_def: match owner {
- DefWithBodyId::FunctionId(it) => it.into(),
- DefWithBodyId::StaticId(it) => it.into(),
- DefWithBodyId::ConstId(it) => it.into(),
- DefWithBodyId::VariantId(it) => it.lookup(db).parent.into(),
- },
+ generic_def: owner.generic_def(db),
body,
traits_in_scope: resolver.traits_in_scope(db),
resolver,
@@ -908,7 +1000,9 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
fn target_features(&self) -> (&TargetFeatures<'db>, TargetFeatureIsSafeInTarget) {
let (target_features, target_feature_is_safe) = self.target_features.get_or_init(|| {
let target_features = match self.owner {
- DefWithBodyId::FunctionId(id) => TargetFeatures::from_fn(self.db, id),
+ ExpressionStoreOwner::Body(DefWithBodyId::FunctionId(id)) => {
+ TargetFeatures::from_fn(self.db, id)
+ }
_ => TargetFeatures::default(),
};
let target_feature_is_safe = match &self.krate().workspace_data(self.db).target {
diff --git a/crates/hir-ty/src/infer/closure/analysis.rs b/crates/hir-ty/src/infer/closure/analysis.rs
index 5a3eba1a71..b4cc2ab4ae 100644
--- a/crates/hir-ty/src/infer/closure/analysis.rs
+++ b/crates/hir-ty/src/infer/closure/analysis.rs
@@ -866,7 +866,7 @@ impl<'db> InferenceContext<'_, 'db> {
&self.table.infer_ctxt,
self.table.param_env,
ty,
- self.owner.module(self.db).krate(self.db),
+ self.owner.krate(self.db),
);
if ty.is_raw_ptr() || ty.is_union() {
capture.kind = CaptureKind::ByRef(BorrowKind::Shared);
diff --git a/crates/hir-ty/src/infer/coerce.rs b/crates/hir-ty/src/infer/coerce.rs
index e79868f4ae..47a7049248 100644
--- a/crates/hir-ty/src/infer/coerce.rs
+++ b/crates/hir-ty/src/infer/coerce.rs
@@ -1718,6 +1718,9 @@ fn coerce<'db>(
fn is_capturing_closure(db: &dyn HirDatabase, closure: InternedClosureId) -> bool {
let InternedClosure(owner, expr) = closure.loc(db);
- upvars_mentioned(db, owner)
+ let Some(body_owner) = owner.as_def_with_body() else {
+ return false;
+ };
+ upvars_mentioned(db, body_owner)
.is_some_and(|upvars| upvars.get(&expr).is_some_and(|upvars| !upvars.is_empty()))
}
diff --git a/crates/hir-ty/src/infer/pat.rs b/crates/hir-ty/src/infer/pat.rs
index 87fd0dace3..9ba2d634d5 100644
--- a/crates/hir-ty/src/infer/pat.rs
+++ b/crates/hir-ty/src/infer/pat.rs
@@ -3,7 +3,7 @@
use std::{cmp, iter};
use hir_def::{
- HasModule,
+ HasModule as _,
expr_store::{Body, path::Path},
hir::{Binding, BindingAnnotation, BindingId, Expr, ExprId, Literal, Pat, PatId},
};
diff --git a/crates/hir-ty/src/layout.rs b/crates/hir-ty/src/layout.rs
index 525100439f..a325b2e174 100644
--- a/crates/hir-ty/src/layout.rs
+++ b/crates/hir-ty/src/layout.rs
@@ -333,7 +333,10 @@ pub fn layout_of_ty_query(
}
TyKind::Closure(id, args) => {
let def = db.lookup_intern_closure(id.0);
- let infer = InferenceResult::for_body(db, def.0);
+ let Some(body_owner) = def.0.as_def_with_body() else {
+ return Err(LayoutError::HasErrorType);
+ };
+ let infer = InferenceResult::for_body(db, body_owner);
let (captures, _) = infer.closure_info(id.0);
let fields = captures
.iter()
diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs
index 49594f34fd..45500cfd22 100644
--- a/crates/hir-ty/src/lower.rs
+++ b/crates/hir-ty/src/lower.rs
@@ -279,11 +279,12 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> {
}
pub(crate) fn lower_const(&mut self, const_ref: ConstRef, const_type: Ty<'db>) -> Const<'db> {
- let const_ref = &self.store[const_ref.expr];
- match const_ref {
- hir_def::hir::Expr::Path(path) => {
- self.path_to_const(path).unwrap_or_else(|| unknown_const(const_type))
- }
+ let expr_id = const_ref.expr;
+ let expr = &self.store[expr_id];
+ match expr {
+ hir_def::hir::Expr::Path(path) => self
+ .path_to_const(path)
+ .unwrap_or_else(|| Const::new(self.interner, ConstKind::Error(ErrorGuaranteed))),
hir_def::hir::Expr::Literal(literal) => {
intern_const_ref(self.db, literal, const_type, self.resolver.krate())
}
@@ -300,20 +301,74 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> {
self.resolver.krate(),
)
} else {
- unknown_const(const_type)
+ Const::new(self.interner, ConstKind::Error(ErrorGuaranteed))
}
}
// For unsigned integers, chars, bools, etc., negation is not meaningful
- _ => unknown_const(const_type),
+ _ => Const::new(self.interner, ConstKind::Error(ErrorGuaranteed)),
}
} else {
- unknown_const(const_type)
+ // Complex negation expression (e.g. `-N` where N is a const param)
+ self.lower_const_as_unevaluated(expr_id, const_type)
}
}
- _ => unknown_const(const_type),
+ hir_def::hir::Expr::Underscore => {
+ Const::new(self.interner, ConstKind::Error(ErrorGuaranteed))
+ }
+ // Any other complex expression becomes an unevaluated anonymous const.
+ _ => self.lower_const_as_unevaluated(expr_id, const_type),
}
}
+ /// Lower a complex const expression to an `UnevaluatedConst` backed by an `AnonConstId`.
+ ///
+ /// The `expected_ty_ref` is `None` for array lengths (implicitly `usize`) or
+ /// `Some(type_ref_id)` for const generic arguments where the expected type comes
+ /// from the const parameter declaration.
+ fn lower_const_as_unevaluated(
+ &mut self,
+ _expr: hir_def::hir::ExprId,
+ _expected_ty: Ty<'db>,
+ ) -> Const<'db> {
+ // /// Build the identity generic args for the current generic context.
+ // ///
+ // /// This maps each generic parameter to itself (as a `ParamTy`, `ParamConst`,
+ // /// or `EarlyParamRegion`), which is the correct substitution when creating
+ // /// an `UnevaluatedConst` during type lowering — the anon const inherits the
+ // /// parent's generics and they haven't been substituted yet.
+ // fn current_generic_args(&self) -> GenericArgs<'db> {
+ // let generics = self.generics();
+ // let interner = self.interner;
+ // GenericArgs::new_from_iter(
+ // interner,
+ // generics.iter_id().enumerate().map(|(index, id)| match id {
+ // GenericParamId::TypeParamId(id) => {
+ // GenericArg::from(Ty::new_param(interner, id, index as u32))
+ // }
+ // GenericParamId::ConstParamId(id) => GenericArg::from(Const::new_param(
+ // interner,
+ // ParamConst { id, index: index as u32 },
+ // )),
+ // GenericParamId::LifetimeParamId(id) => GenericArg::from(Region::new_early_param(
+ // interner,
+ // EarlyParamRegion { id, index: index as u32 },
+ // )),
+ // }),
+ // )
+ // }
+ // let loc = AnonConstLoc { owner: self.def, expr };
+ // let id = loc.intern(self.db);
+ // let args = self.current_generic_args();
+ // Const::new(
+ // self.interner,
+ // ConstKind::Unevaluated(UnevaluatedConst::new(
+ // GeneralConstId::AnonConstId(id).into(),
+ // args,
+ // )),
+ // )
+ Const::new(self.interner, ConstKind::Error(ErrorGuaranteed))
+ }
+
pub(crate) fn path_to_const(&mut self, path: &Path) -> Option<Const<'db>> {
match self.resolver.resolve_path_in_value_ns_fully(self.db, path, HygieneId::ROOT) {
Some(ValueNs::GenericParam(p)) => {
diff --git a/crates/hir-ty/src/mir/borrowck.rs b/crates/hir-ty/src/mir/borrowck.rs
index dece61a57d..2dcc2d1062 100644
--- a/crates/hir-ty/src/mir/borrowck.rs
+++ b/crates/hir-ty/src/mir/borrowck.rs
@@ -8,7 +8,7 @@ use std::iter;
use hir_def::{DefWithBodyId, HasModule};
use la_arena::ArenaMap;
use rustc_hash::FxHashMap;
-use rustc_type_ir::inherent::GenericArgs as _;
+use rustc_type_ir::inherent::{GenericArgs as _, Ty as _};
use stdx::never;
use triomphe::Arc;
@@ -18,7 +18,7 @@ use crate::{
display::DisplayTarget,
mir::OperandKind,
next_solver::{
- DbInterner, GenericArgs, ParamEnv, StoredTy, Ty, TypingMode,
+ DbInterner, ErrorGuaranteed, GenericArgs, ParamEnv, StoredTy, Ty, TypingMode,
infer::{DbInternerInferExt, InferCtxt},
},
};
@@ -121,11 +121,14 @@ fn make_fetch_closure_field<'db>(
db: &'db dyn HirDatabase,
) -> impl FnOnce(InternedClosureId, GenericArgs<'db>, usize) -> Ty<'db> + use<'db> {
|c: InternedClosureId, subst: GenericArgs<'db>, f: usize| {
- let InternedClosure(def, _) = db.lookup_intern_closure(c);
+ let InternedClosure(owner, _) = db.lookup_intern_closure(c);
+ let interner = DbInterner::new_no_crate(db);
+ let Some(def) = owner.as_def_with_body() else {
+ return Ty::new_error(interner, ErrorGuaranteed);
+ };
let infer = InferenceResult::for_body(db, def);
let (captures, _) = infer.closure_info(c);
let parent_subst = subst.as_closure().parent_args();
- let interner = DbInterner::new_no_crate(db);
captures.get(f).expect("broken closure field").ty.get().instantiate(interner, parent_subst)
}
}
diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs
index ec0723c3f8..a85b3ef50a 100644
--- a/crates/hir-ty/src/mir/eval.rs
+++ b/crates/hir-ty/src/mir/eval.rs
@@ -730,7 +730,10 @@ impl<'db> Evaluator<'db> {
self.param_env.param_env,
ty,
|c, subst, f| {
- let InternedClosure(def, _) = self.db.lookup_intern_closure(c);
+ let InternedClosure(owner, _) = self.db.lookup_intern_closure(c);
+ let Some(def) = owner.as_def_with_body() else {
+ return Ty::new_error(self.interner(), ErrorGuaranteed);
+ };
let infer = InferenceResult::for_body(self.db, def);
let (captures, _) = infer.closure_info(c);
let parent_subst = subst.as_closure().parent_args();
@@ -1954,6 +1957,9 @@ impl<'db> Evaluator<'db> {
MirEvalError::ConstEvalError(name, Box::new(e))
})?
}
+ GeneralConstId::AnonConstId(_) => {
+ not_supported!("anonymous const evaluation")
+ }
};
if let ConstKind::Value(value) = result_owner.kind() {
break 'b value;
diff --git a/crates/hir-ty/src/mir/eval/shim.rs b/crates/hir-ty/src/mir/eval/shim.rs
index 76c8701ea2..a0dd3b5846 100644
--- a/crates/hir-ty/src/mir/eval/shim.rs
+++ b/crates/hir-ty/src/mir/eval/shim.rs
@@ -152,7 +152,10 @@ impl<'db> Evaluator<'db> {
not_supported!("wrong arg count for clone");
};
let addr = Address::from_bytes(arg.get(self)?)?;
- let InternedClosure(closure_owner, _) = self.db.lookup_intern_closure(id.0);
+ let InternedClosure(owner, _) = self.db.lookup_intern_closure(id.0);
+ let Some(closure_owner) = owner.as_def_with_body() else {
+ not_supported!("closure in non-body context");
+ };
let infer = InferenceResult::for_body(self.db, closure_owner);
let (captures, _) = infer.closure_info(id.0);
let layout = self.layout(self_ty)?;
diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs
index 2e849bcf3a..269d8729ba 100644
--- a/crates/hir-ty/src/mir/lower.rs
+++ b/crates/hir-ty/src/mir/lower.rs
@@ -1546,6 +1546,9 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> {
MirLowerError::ConstEvalError(name.into(), Box::new(e))
})?
}
+ GeneralConstId::AnonConstId(_) => {
+ return Err(MirLowerError::IncompleteExpr);
+ }
}
};
let ty = self
@@ -1553,6 +1556,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> {
.value_ty(match const_id {
GeneralConstId::ConstId(id) => id.into(),
GeneralConstId::StaticId(id) => id.into(),
+ GeneralConstId::AnonConstId(_) => unreachable!("handled above"),
})
.unwrap()
.instantiate(self.interner(), subst);
@@ -2106,8 +2110,10 @@ pub fn mir_body_for_closure_query<'db>(
closure: InternedClosureId,
) -> Result<'db, Arc<MirBody>> {
let InternedClosure(owner, expr) = db.lookup_intern_closure(closure);
- let body = db.body(owner);
- let infer = InferenceResult::for_body(db, owner);
+ let body_owner =
+ owner.as_def_with_body().expect("MIR lowering should only happen for body-owned closures");
+ let body = db.body(body_owner);
+ let infer = InferenceResult::for_body(db, body_owner);
let Expr::Closure { args, body: root, .. } = &body[expr] else {
implementation_error!("closure expression is not closure");
};
@@ -2115,7 +2121,7 @@ pub fn mir_body_for_closure_query<'db>(
implementation_error!("closure expression is not closure");
};
let (captures, kind) = infer.closure_info(closure);
- let mut ctx = MirLowerCtx::new(db, owner, &body.store, infer);
+ let mut ctx = MirLowerCtx::new(db, body_owner, &body.store, infer);
// 0 is return local
ctx.result.locals.alloc(Local { ty: infer.expr_ty(*root).store() });
let closure_local = ctx.result.locals.alloc(Local {
@@ -2138,7 +2144,7 @@ pub fn mir_body_for_closure_query<'db>(
});
ctx.result.param_locals.push(closure_local);
let sig = ctx.interner().signature_unclosure(substs.as_closure().sig(), Safety::Safe);
- let resolver_guard = ctx.resolver.update_to_inner_scope(db, owner, expr);
+ let resolver_guard = ctx.resolver.update_to_inner_scope(db, body_owner, expr);
let current = ctx.lower_params_and_bindings(
args.iter().zip(sig.skip_binder().inputs().iter()).map(|(it, y)| (*it, *y)),
None,
diff --git a/crates/hir-ty/src/next_solver/def_id.rs b/crates/hir-ty/src/next_solver/def_id.rs
index aa6caefc4a..e76ab16fc2 100644
--- a/crates/hir-ty/src/next_solver/def_id.rs
+++ b/crates/hir-ty/src/next_solver/def_id.rs
@@ -1,9 +1,9 @@
//! Definition of `SolverDefId`
use hir_def::{
- AdtId, AttrDefId, BuiltinDeriveImplId, CallableDefId, ConstId, DefWithBodyId, EnumId,
- EnumVariantId, FunctionId, GeneralConstId, GenericDefId, ImplId, StaticId, StructId, TraitId,
- TypeAliasId, UnionId,
+ AdtId, AnonConstId, AttrDefId, BuiltinDeriveImplId, CallableDefId, ConstId, DefWithBodyId,
+ EnumId, EnumVariantId, FunctionId, GeneralConstId, GenericDefId, ImplId, StaticId, StructId,
+ TraitId, TypeAliasId, UnionId,
};
use rustc_type_ir::inherent;
use stdx::impl_from;
@@ -26,6 +26,7 @@ pub enum SolverDefId {
ImplId(ImplId),
BuiltinDeriveImplId(BuiltinDeriveImplId),
StaticId(StaticId),
+ AnonConstId(AnonConstId),
TraitId(TraitId),
TypeAliasId(TypeAliasId),
InternedClosureId(InternedClosureId),
@@ -88,6 +89,7 @@ impl std::fmt::Debug for SolverDefId {
))
.finish()
}
+ SolverDefId::AnonConstId(id) => f.debug_tuple("AnonConstId").field(&id).finish(),
SolverDefId::Ctor(Ctor::Struct(id)) => {
f.debug_tuple("Ctor").field(&db.struct_signature(id).name.as_str()).finish()
}
@@ -112,6 +114,7 @@ impl_from!(
ImplId,
BuiltinDeriveImplId,
StaticId,
+ AnonConstId,
TraitId,
TypeAliasId,
InternedClosureId,
@@ -142,6 +145,7 @@ impl From<GeneralConstId> for SolverDefId {
match value {
GeneralConstId::ConstId(const_id) => SolverDefId::ConstId(const_id),
GeneralConstId::StaticId(static_id) => SolverDefId::StaticId(static_id),
+ GeneralConstId::AnonConstId(anon_const_id) => SolverDefId::AnonConstId(anon_const_id),
}
}
}
@@ -176,7 +180,8 @@ impl TryFrom<SolverDefId> for AttrDefId {
SolverDefId::BuiltinDeriveImplId(_)
| SolverDefId::InternedClosureId(_)
| SolverDefId::InternedCoroutineId(_)
- | SolverDefId::InternedOpaqueTyId(_) => Err(()),
+ | SolverDefId::InternedOpaqueTyId(_)
+ | SolverDefId::AnonConstId(_) => Err(()),
}
}
}
@@ -199,6 +204,7 @@ impl TryFrom<SolverDefId> for DefWithBodyId {
| SolverDefId::InternedClosureId(_)
| SolverDefId::InternedCoroutineId(_)
| SolverDefId::Ctor(Ctor::Struct(_))
+ | SolverDefId::AnonConstId(_)
| SolverDefId::AdtId(_) => return Err(()),
};
Ok(id)
@@ -222,6 +228,7 @@ impl TryFrom<SolverDefId> for GenericDefId {
| SolverDefId::InternedOpaqueTyId(_)
| SolverDefId::EnumVariantId(_)
| SolverDefId::BuiltinDeriveImplId(_)
+ | SolverDefId::AnonConstId(_)
| SolverDefId::Ctor(_) => return Err(()),
})
}
@@ -343,6 +350,7 @@ impl From<GeneralConstIdWrapper> for SolverDefId {
match value.0 {
GeneralConstId::ConstId(id) => SolverDefId::ConstId(id),
GeneralConstId::StaticId(id) => SolverDefId::StaticId(id),
+ GeneralConstId::AnonConstId(id) => SolverDefId::AnonConstId(id),
}
}
}
@@ -353,6 +361,7 @@ impl TryFrom<SolverDefId> for GeneralConstIdWrapper {
match value {
SolverDefId::ConstId(it) => Ok(Self(it.into())),
SolverDefId::StaticId(it) => Ok(Self(it.into())),
+ SolverDefId::AnonConstId(it) => Ok(Self(it.into())),
_ => Err(()),
}
}
diff --git a/crates/hir-ty/src/next_solver/interner.rs b/crates/hir-ty/src/next_solver/interner.rs
index e17bdac68c..dba4e74730 100644
--- a/crates/hir-ty/src/next_solver/interner.rs
+++ b/crates/hir-ty/src/next_solver/interner.rs
@@ -10,8 +10,8 @@ pub use tls_db::{attach_db, attach_db_allow_change, with_attached_db};
use base_db::Crate;
use hir_def::{
- AdtId, CallableDefId, DefWithBodyId, EnumVariantId, HasModule, ItemContainerId, StructId,
- UnionId, VariantId,
+ AdtId, CallableDefId, DefWithBodyId, EnumVariantId, ExpressionStoreOwner, HasModule,
+ ItemContainerId, StructId, UnionId, VariantId,
attrs::AttrFlags,
lang_item::LangItems,
signatures::{FieldData, FnFlags, ImplFlags, StructFlags, TraitFlags},
@@ -1193,7 +1193,8 @@ impl<'db> Interner for DbInterner<'db> {
| SolverDefId::ImplId(_)
| SolverDefId::BuiltinDeriveImplId(_)
| SolverDefId::InternedClosureId(_)
- | SolverDefId::InternedCoroutineId(_) => {
+ | SolverDefId::InternedCoroutineId(_)
+ | SolverDefId::AnonConstId(_) => {
return VariancesOf::empty(self);
}
};
@@ -1260,7 +1261,9 @@ impl<'db> Interner for DbInterner<'db> {
},
// rustc creates an `AnonConst` for consts, and evaluates them with CTFE (normalizing projections
// via selection, similar to ours `find_matching_impl()`, and not with the trait solver), so mimic it.
- SolverDefId::ConstId(_) => AliasTermKind::UnevaluatedConst,
+ SolverDefId::ConstId(_) | SolverDefId::AnonConstId(_) => {
+ AliasTermKind::UnevaluatedConst
+ }
_ => unimplemented!("Unexpected alias: {:?}", alias.def_id),
}
}
@@ -1308,22 +1311,10 @@ impl<'db> Interner for DbInterner<'db> {
SolverDefId::TypeAliasId(it) => it.lookup(self.db()).container,
SolverDefId::ConstId(it) => it.lookup(self.db()).container,
SolverDefId::InternedClosureId(it) => {
- return self
- .db()
- .lookup_intern_closure(it)
- .0
- .as_generic_def_id(self.db())
- .unwrap()
- .into();
+ return self.db().lookup_intern_closure(it).0.generic_def(self.db()).into();
}
SolverDefId::InternedCoroutineId(it) => {
- return self
- .db()
- .lookup_intern_coroutine(it)
- .0
- .as_generic_def_id(self.db())
- .unwrap()
- .into();
+ return self.db().lookup_intern_coroutine(it).0.generic_def(self.db()).into();
}
SolverDefId::StaticId(_)
| SolverDefId::AdtId(_)
@@ -1332,7 +1323,8 @@ impl<'db> Interner for DbInterner<'db> {
| SolverDefId::BuiltinDeriveImplId(_)
| SolverDefId::EnumVariantId(..)
| SolverDefId::Ctor(..)
- | SolverDefId::InternedOpaqueTyId(..) => panic!(),
+ | SolverDefId::InternedOpaqueTyId(..)
+ | SolverDefId::AnonConstId(_) => panic!(),
};
match container {
@@ -1361,7 +1353,10 @@ impl<'db> Interner for DbInterner<'db> {
// FIXME: Make this a query? I don't believe this can be accessed from bodies other than
// the current infer query, except with revealed opaques - is it rare enough to not matter?
let InternedCoroutine(owner, expr_id) = def_id.0.loc(self.db);
- let body = self.db.body(owner);
+ let Some(body_owner) = owner.as_def_with_body() else {
+ return rustc_ast_ir::Movability::Static;
+ };
+ let body = self.db.body(body_owner);
let expr = &body[expr_id];
match *expr {
hir_def::hir::Expr::Closure { closure_kind, .. } => match closure_kind {
@@ -1795,6 +1790,7 @@ impl<'db> Interner for DbInterner<'db> {
| SolverDefId::InternedCoroutineId(_)
| SolverDefId::InternedOpaqueTyId(_)
| SolverDefId::EnumVariantId(_)
+ | SolverDefId::AnonConstId(_)
| SolverDefId::Ctor(_) => return None,
};
module.block(self.db)
@@ -2006,7 +2002,10 @@ impl<'db> Interner for DbInterner<'db> {
// FIXME: Make this a query? I don't believe this can be accessed from bodies other than
// the current infer query, except with revealed opaques - is it rare enough to not matter?
let InternedCoroutine(owner, expr_id) = def_id.0.loc(self.db);
- let body = self.db.body(owner);
+ let Some(body_owner) = owner.as_def_with_body() else {
+ return false;
+ };
+ let body = self.db.body(body_owner);
matches!(
body[expr_id],
hir_def::hir::Expr::Closure {
@@ -2020,7 +2019,10 @@ impl<'db> Interner for DbInterner<'db> {
// FIXME: Make this a query? I don't believe this can be accessed from bodies other than
// the current infer query, except with revealed opaques - is it rare enough to not matter?
let InternedCoroutine(owner, expr_id) = def_id.0.loc(self.db);
- let body = self.db.body(owner);
+ let Some(body_owner) = owner.as_def_with_body() else {
+ return false;
+ };
+ let body = self.db.body(body_owner);
matches!(
body[expr_id],
hir_def::hir::Expr::Closure { closure_kind: hir_def::hir::ClosureKind::Async, .. }
@@ -2154,8 +2156,10 @@ impl<'db> Interner for DbInterner<'db> {
..
}
) {
- let coroutine =
- InternedCoroutineId::new(self.db, InternedCoroutine(def_id, expr_id));
+ let coroutine = InternedCoroutineId::new(
+ self.db,
+ InternedCoroutine(ExpressionStoreOwner::Body(def_id), expr_id),
+ );
result.push(coroutine.into());
}
});
diff --git a/crates/hir-ty/src/next_solver/solver.rs b/crates/hir-ty/src/next_solver/solver.rs
index 15d6e2e451..54baa8ac41 100644
--- a/crates/hir-ty/src/next_solver/solver.rs
+++ b/crates/hir-ty/src/next_solver/solver.rs
@@ -18,7 +18,7 @@ use crate::next_solver::{
};
use super::{
- DbInterner, ErrorGuaranteed, GenericArg, SolverDefId, Span,
+ Const, DbInterner, ErrorGuaranteed, GenericArg, SolverDefId, Span,
infer::{DbInternerInferExt, InferCtxt, canonical::instantiate::CanonicalExt},
};
@@ -256,6 +256,11 @@ impl<'db> SolverDelegate for SolverContext<'db> {
let ec = self.cx().db.const_eval_static(c).ok()?;
Some(ec)
}
+ // TODO: Wire up const_eval_anon query in Phase 5.
+ // For now, return an error const so normalization resolves the
+ // unevaluated const to Error (matching the old behavior where
+ // complex expressions produced ConstKind::Error directly).
+ GeneralConstId::AnonConstId(_) => Some(Const::error(self.cx())),
}
}
diff --git a/crates/hir-ty/src/next_solver/ty.rs b/crates/hir-ty/src/next_solver/ty.rs
index 1173028a10..09b1585866 100644
--- a/crates/hir-ty/src/next_solver/ty.rs
+++ b/crates/hir-ty/src/next_solver/ty.rs
@@ -714,7 +714,7 @@ impl<'db> Ty<'db> {
}
TyKind::Coroutine(coroutine_id, _args) => {
let InternedCoroutine(owner, _) = coroutine_id.0.loc(db);
- let krate = owner.module(db).krate(db);
+ let krate = owner.krate(db);
if let Some(future_trait) = hir_def::lang_item::lang_items(db, krate).Future {
// This is only used by type walking.
// Parameters will be walked outside, and projection predicate is not used.
diff --git a/crates/hir-ty/src/tests/closure_captures.rs b/crates/hir-ty/src/tests/closure_captures.rs
index f089120cd7..6e55641e56 100644
--- a/crates/hir-ty/src/tests/closure_captures.rs
+++ b/crates/hir-ty/src/tests/closure_captures.rs
@@ -40,7 +40,8 @@ fn check_closure_captures(#[rust_analyzer::rust_fixture] ra_fixture: &str, expec
captures_info.extend(infer.closure_info.iter().flat_map(
|(closure_id, (captures, _))| {
let closure = db.lookup_intern_closure(*closure_id);
- let source_map = db.body_with_source_map(closure.0).1;
+ let body_owner = closure.0.as_def_with_body().unwrap();
+ let source_map = db.body_with_source_map(body_owner).1;
let closure_text_range = source_map
.expr_syntax(closure.1)
.expect("failed to map closure to SyntaxNode")
@@ -56,7 +57,7 @@ fn check_closure_captures(#[rust_analyzer::rust_fixture] ra_fixture: &str, expec
}
// FIXME: Deduplicate this with hir::Local::sources().
- let (body, source_map) = db.body_with_source_map(closure.0);
+ let (body, source_map) = db.body_with_source_map(body_owner);
let local_text_range =
match body.self_param.zip(source_map.self_param_syntax()) {
Some((param, source)) if param == capture.local() => {
@@ -71,7 +72,7 @@ fn check_closure_captures(#[rust_analyzer::rust_fixture] ra_fixture: &str, expec
.map(|it| format!("{it:?}"))
.join(", "),
};
- let place = capture.display_place(closure.0, db);
+ let place = capture.display_place(body_owner, db);
let capture_ty = capture
.ty
.get()
diff --git a/crates/hir-ty/src/tests/incremental.rs b/crates/hir-ty/src/tests/incremental.rs
index faa7b80a89..0fbf8acf53 100644
--- a/crates/hir-ty/src/tests/incremental.rs
+++ b/crates/hir-ty/src/tests/incremental.rs
@@ -48,7 +48,7 @@ fn foo() -> i32 {
"crate_lang_items",
"GenericPredicates::query_with_diagnostics_",
"ImplTraits::return_type_impl_traits_",
- "expr_scopes_shim",
+ "body_expr_scopes_shim",
]
"#]],
);
@@ -136,7 +136,7 @@ fn baz() -> i32 {
"crate_lang_items",
"GenericPredicates::query_with_diagnostics_",
"ImplTraits::return_type_impl_traits_",
- "expr_scopes_shim",
+ "body_expr_scopes_shim",
"InferenceResult::for_body_",
"function_signature_shim",
"function_signature_with_source_map_shim",
@@ -146,7 +146,7 @@ fn baz() -> i32 {
"trait_environment_query",
"GenericPredicates::query_with_diagnostics_",
"ImplTraits::return_type_impl_traits_",
- "expr_scopes_shim",
+ "body_expr_scopes_shim",
"InferenceResult::for_body_",
"function_signature_shim",
"function_signature_with_source_map_shim",
@@ -156,7 +156,7 @@ fn baz() -> i32 {
"trait_environment_query",
"GenericPredicates::query_with_diagnostics_",
"ImplTraits::return_type_impl_traits_",
- "expr_scopes_shim",
+ "body_expr_scopes_shim",
]
"#]],
);
@@ -204,7 +204,7 @@ fn baz() -> i32 {
"body_with_source_map_shim",
"body_shim",
"InferenceResult::for_body_",
- "expr_scopes_shim",
+ "body_expr_scopes_shim",
"AttrFlags::query_",
"function_signature_with_source_map_shim",
"function_signature_shim",
@@ -600,7 +600,7 @@ fn main() {
"trait_environment_query",
"GenericPredicates::query_with_diagnostics_",
"ImplTraits::return_type_impl_traits_",
- "expr_scopes_shim",
+ "body_expr_scopes_shim",
"struct_signature_shim",
"struct_signature_with_source_map_shim",
"AttrFlags::query_",
@@ -690,7 +690,7 @@ fn main() {
"function_signature_with_source_map_shim",
"GenericPredicates::query_with_diagnostics_",
"ImplTraits::return_type_impl_traits_",
- "expr_scopes_shim",
+ "body_expr_scopes_shim",
"struct_signature_with_source_map_shim",
"AttrFlags::query_",
"GenericPredicates::query_with_diagnostics_",
diff --git a/crates/hir/src/has_source.rs b/crates/hir/src/has_source.rs
index e032a16989..66bb357066 100644
--- a/crates/hir/src/has_source.rs
+++ b/crates/hir/src/has_source.rs
@@ -293,7 +293,10 @@ impl HasSource for Param<'_> {
}
Callee::Closure(closure, _) => {
let InternedClosure(owner, expr_id) = db.lookup_intern_closure(closure);
- let (_, source_map) = db.body_with_source_map(owner);
+ let Some(body_owner) = owner.as_def_with_body() else {
+ return None;
+ };
+ let (_, source_map) = db.body_with_source_map(body_owner);
let ast @ InFile { file_id, value } = source_map.expr_syntax(expr_id).ok()?;
let root = db.parse_or_expand(file_id);
match value.to_node(&root) {
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 0b3515fd04..6dfb94cbf3 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -1737,7 +1737,7 @@ impl Variant {
}
pub fn value(self, db: &dyn HirDatabase) -> Option<ast::Expr> {
- self.source(db)?.value.expr()
+ self.source(db)?.value.const_arg()?.expr()
}
pub fn eval(self, db: &dyn HirDatabase) -> Result<i128, ConstEvalError> {
@@ -2891,11 +2891,12 @@ impl<'db> Param<'db> {
}
Callee::Closure(closure, _) => {
let c = db.lookup_intern_closure(closure);
- let body = db.body(c.0);
+ let body_owner = c.0.as_def_with_body()?;
+ let body = db.body(body_owner);
if let Expr::Closure { args, .. } = &body[c.1]
&& let Pat::Bind { id, .. } = &body[args[self.idx]]
{
- return Some(Local { parent: c.0, binding_id: *id });
+ return Some(Local { parent: body_owner, binding_id: *id });
}
None
}
@@ -5012,13 +5013,16 @@ impl<'db> Closure<'db> {
return Vec::new();
};
let owner = db.lookup_intern_closure(id).0;
- let infer = InferenceResult::for_body(db, owner);
+ let Some(body_owner) = owner.as_def_with_body() else {
+ return Vec::new();
+ };
+ let infer = InferenceResult::for_body(db, body_owner);
let info = infer.closure_info(id);
info.0
.iter()
.cloned()
.map(|capture| ClosureCapture {
- owner,
+ owner: body_owner,
closure: id,
capture,
_marker: PhantomCovariantLifetime::new(),
@@ -5032,9 +5036,12 @@ impl<'db> Closure<'db> {
return Vec::new();
};
let owner = db.lookup_intern_closure(id).0;
- let infer = InferenceResult::for_body(db, owner);
+ let Some(body_owner) = owner.as_def_with_body() else {
+ return Vec::new();
+ };
+ let infer = InferenceResult::for_body(db, body_owner);
let (captures, _) = infer.closure_info(id);
- let env = body_param_env_from_has_crate(db, owner);
+ let env = body_param_env_from_has_crate(db, body_owner);
captures.iter().map(|capture| Type { env, ty: capture.ty(db, self.subst) }).collect()
}
@@ -5042,7 +5049,10 @@ impl<'db> Closure<'db> {
match self.id {
AnyClosureId::ClosureId(id) => {
let owner = db.lookup_intern_closure(id).0;
- let infer = InferenceResult::for_body(db, owner);
+ let Some(body_owner) = owner.as_def_with_body() else {
+ return FnTrait::FnOnce;
+ };
+ let infer = InferenceResult::for_body(db, body_owner);
let info = infer.closure_info(id);
info.1.into()
}
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs
index c6f2d151f5..18929f8209 100644
--- a/crates/hir/src/source_analyzer.rs
+++ b/crates/hir/src/source_analyzer.rs
@@ -123,7 +123,7 @@ impl<'db> SourceAnalyzer<'db> {
infer: Option<&'db InferenceResult>,
) -> SourceAnalyzer<'db> {
let (body, source_map) = db.body_with_source_map(def);
- let scopes = db.expr_scopes(def);
+ let scopes = db.expr_scopes(def.into());
let scope = match offset {
None => scope_for(db, &scopes, &source_map, node),
Some(offset) => {
@@ -1045,7 +1045,7 @@ impl<'db> SourceAnalyzer<'db> {
}
// FIXME: collectiong here shouldnt be necessary?
- let mut collector = ExprCollector::new(db, self.resolver.module(), self.file_id);
+ let mut collector = ExprCollector::body(db, self.resolver.module(), self.file_id);
let hir_path =
collector.lower_path(path.clone(), &mut ExprCollector::impl_trait_error_allocator)?;
let parent_hir_path = path
@@ -1253,7 +1253,7 @@ impl<'db> SourceAnalyzer<'db> {
db: &dyn HirDatabase,
path: &ast::Path,
) -> Option<PathResolutionPerNs> {
- let mut collector = ExprCollector::new(db, self.resolver.module(), self.file_id);
+ let mut collector = ExprCollector::body(db, self.resolver.module(), self.file_id);
let hir_path =
collector.lower_path(path.clone(), &mut ExprCollector::impl_trait_error_allocator)?;
let (store, _) = collector.store.finish();
diff --git a/crates/ide-assists/src/handlers/add_explicit_enum_discriminant.rs b/crates/ide-assists/src/handlers/add_explicit_enum_discriminant.rs
index 7960373e61..75c5f84b85 100644
--- a/crates/ide-assists/src/handlers/add_explicit_enum_discriminant.rs
+++ b/crates/ide-assists/src/handlers/add_explicit_enum_discriminant.rs
@@ -47,7 +47,7 @@ pub(crate) fn add_explicit_enum_discriminant(
// Don't offer the assist if the enum has no variants or if all variants already have an
// explicit discriminant.
- if variant_list.variants().all(|variant_node| variant_node.expr().is_some()) {
+ if variant_list.variants().all(|variant_node| variant_node.const_arg().is_some()) {
return None;
}
@@ -72,7 +72,9 @@ fn add_variant_discriminant(
variant_node: &ast::Variant,
radix: &mut Radix,
) {
- if let Some(expr) = variant_node.expr() {
+ if let Some(expr) = variant_node.const_arg()
+ && let Some(expr) = expr.expr()
+ {
*radix = expr_radix(&expr).unwrap_or(*radix);
return;
}
diff --git a/crates/ide/src/inlay_hints/discriminant.rs b/crates/ide/src/inlay_hints/discriminant.rs
index 5b9267126f..e845faec56 100644
--- a/crates/ide/src/inlay_hints/discriminant.rs
+++ b/crates/ide/src/inlay_hints/discriminant.rs
@@ -46,7 +46,7 @@ fn variant_hints(
enum_: &ast::Enum,
variant: &ast::Variant,
) -> Option<()> {
- if variant.expr().is_some() {
+ if variant.const_arg().is_some() {
return None;
}
diff --git a/crates/parser/src/grammar/items/adt.rs b/crates/parser/src/grammar/items/adt.rs
index a375696140..cfba4c3a77 100644
--- a/crates/parser/src/grammar/items/adt.rs
+++ b/crates/parser/src/grammar/items/adt.rs
@@ -96,7 +96,9 @@ pub(crate) fn variant_list(p: &mut Parser<'_>) {
// test variant_discriminant
// enum E { X(i32) = 10 }
if p.eat(T![=]) {
+ let m = p.start();
expressions::expr(p);
+ m.complete(p, CONST_ARG);
}
m.complete(p, VARIANT);
} else {
@@ -139,7 +141,9 @@ pub(crate) fn record_field_list(p: &mut Parser<'_>) {
// test record_field_default_values
// struct S { f: f32 = 0.0 }
if p.eat(T![=]) {
+ let m = p.start();
expressions::expr(p);
+ m.complete(p, CONST_ARG);
}
m.complete(p, RECORD_FIELD);
} else {
diff --git a/crates/parser/test_data/parser/inline/ok/record_field_default_values.rast b/crates/parser/test_data/parser/inline/ok/record_field_default_values.rast
index 33088f2cab..e53b886bbf 100644
--- a/crates/parser/test_data/parser/inline/ok/record_field_default_values.rast
+++ b/crates/parser/test_data/parser/inline/ok/record_field_default_values.rast
@@ -21,8 +21,9 @@ SOURCE_FILE
WHITESPACE " "
EQ "="
WHITESPACE " "
- LITERAL
- FLOAT_NUMBER "0.0"
+ CONST_ARG
+ LITERAL
+ FLOAT_NUMBER "0.0"
WHITESPACE " "
R_CURLY "}"
WHITESPACE "\n"
diff --git a/crates/parser/test_data/parser/inline/ok/variant_discriminant.rast b/crates/parser/test_data/parser/inline/ok/variant_discriminant.rast
index 9f0c5a7610..3494085e88 100644
--- a/crates/parser/test_data/parser/inline/ok/variant_discriminant.rast
+++ b/crates/parser/test_data/parser/inline/ok/variant_discriminant.rast
@@ -23,8 +23,9 @@ SOURCE_FILE
WHITESPACE " "
EQ "="
WHITESPACE " "
- LITERAL
- INT_NUMBER "10"
+ CONST_ARG
+ LITERAL
+ INT_NUMBER "10"
WHITESPACE " "
R_CURLY "}"
WHITESPACE "\n"
diff --git a/crates/parser/test_data/parser/ok/0019_enums.rast b/crates/parser/test_data/parser/ok/0019_enums.rast
index dd47e3aa47..51837e5372 100644
--- a/crates/parser/test_data/parser/ok/0019_enums.rast
+++ b/crates/parser/test_data/parser/ok/0019_enums.rast
@@ -78,8 +78,9 @@ SOURCE_FILE
WHITESPACE " "
EQ "="
WHITESPACE " "
- LITERAL
- INT_NUMBER "92"
+ CONST_ARG
+ LITERAL
+ INT_NUMBER "92"
COMMA ","
WHITESPACE "\n "
VARIANT
diff --git a/crates/syntax/rust.ungram b/crates/syntax/rust.ungram
index 544053408f..3113fc7430 100644
--- a/crates/syntax/rust.ungram
+++ b/crates/syntax/rust.ungram
@@ -245,7 +245,7 @@ RecordFieldList =
RecordField =
Attr* Visibility? 'unsafe'?
- Name ':' Type ('=' Expr)?
+ Name ':' Type ('=' default_val:ConstArg)?
TupleFieldList =
'(' fields:(TupleField (',' TupleField)* ','?)? ')'
@@ -268,7 +268,7 @@ VariantList =
Variant =
Attr* Visibility?
- Name FieldList? ('=' Expr)?
+ Name FieldList? ('=' ConstArg)?
Union =
Attr* Visibility?
diff --git a/crates/syntax/src/ast/generated/nodes.rs b/crates/syntax/src/ast/generated/nodes.rs
index c4e72eafa7..7334de0fd9 100644
--- a/crates/syntax/src/ast/generated/nodes.rs
+++ b/crates/syntax/src/ast/generated/nodes.rs
@@ -1337,7 +1337,7 @@ impl ast::HasName for RecordField {}
impl ast::HasVisibility for RecordField {}
impl RecordField {
#[inline]
- pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
+ pub fn default_val(&self) -> Option<ConstArg> { support::child(&self.syntax) }
#[inline]
pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
#[inline]
@@ -1896,7 +1896,7 @@ impl ast::HasName for Variant {}
impl ast::HasVisibility for Variant {}
impl Variant {
#[inline]
- pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
+ pub fn const_arg(&self) -> Option<ConstArg> { support::child(&self.syntax) }
#[inline]
pub fn field_list(&self) -> Option<FieldList> { support::child(&self.syntax) }
#[inline]
diff --git a/crates/syntax/src/ast/syntax_factory/constructors.rs b/crates/syntax/src/ast/syntax_factory/constructors.rs
index d0f14dafe3..90a326ff9e 100644
--- a/crates/syntax/src/ast/syntax_factory/constructors.rs
+++ b/crates/syntax/src/ast/syntax_factory/constructors.rs
@@ -1503,8 +1503,10 @@ impl SyntaxFactory {
}
if let Some(discriminant) = discriminant {
- builder
- .map_node(discriminant.syntax().clone(), ast.expr().unwrap().syntax().clone());
+ builder.map_node(
+ discriminant.syntax().clone(),
+ ast.const_arg().unwrap().syntax().clone(),
+ );
}
builder.finish(&mut mapping);