Unnamed repository; edit this file 'description' to name the repository.
Implement signature type inference
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); |