Unnamed repository; edit this file 'description' to name the repository.
Do not infer signatures, instead infer anon consts in them
See [the Zulip discussion](https://rust-lang.zulipchat.com/#narrow/channel/185405-t-compiler.2Frust-analyzer/topic/Anon.20consts.20for.20everything/with/587684630) for details, but in short:
- This allows us to easily set the expected type.
- They can have proper MIR an eval, preventing the need for hacks like `fixme_resolve_all_clone()`.
This also fixes a bunch of old inference failures caused by us unable to evaluate constants.
In order to make them visible to the IDE layer, each query that can create anon consts now keeps a list of the anon consts it created. The expression store also gains an ability to find the root expression of something. Then, in `Semantics`, when wanting to find inference info for something, we find its root expr, then search it in the list of anon consts defined by the body.
66 files changed, 2379 insertions, 1521 deletions
diff --git a/crates/hir-def/src/expr_store.rs b/crates/hir-def/src/expr_store.rs index 2c2b477115..152dd6f798 100644 --- a/crates/hir-def/src/expr_store.rs +++ b/crates/hir-def/src/expr_store.rs @@ -94,21 +94,15 @@ 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 RootExprOrigin { - /// 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, - /// The root expression of a body. - BodyRoot, +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +struct ExprRoot { + root: ExprId, + // We store, for each root, the range of exprs (and pats and bindings) it holds. + // We store only the end (exclusive), since the start can be inferred from the previous + // roots or is zero. + exprs_end: ExprId, + pats_end: PatId, + bindings_end: BindingId, } // We split the store into types-only and expressions, because most stores (e.g. generics) @@ -132,7 +126,34 @@ struct ExpressionOnlyStore { ident_hygiene: FxHashMap<ExprOrPatId, HygieneId>, /// Maps expression roots to their origin. - expr_roots: SmallVec<[(ExprId, RootExprOrigin); 1]>, + /// + /// Note: while every root expr is an inference root (aka. an `AnonConst`), there could be other roots that do not appear here. + /// This can happen when anon consts are nested, for example: + /// + /// ``` + /// [ + /// (); + /// { + /// // this repeat expr is anon const #1, and *only it* appears in this list. + /// [ + /// (); + /// { + /// // this repeat expr is anon const #2. + /// 0 + /// } + /// ]; + /// 0 + /// } + /// ] + /// ``` + /// We do this because this allows us to search this list using a binary search, + /// and it does not bother us because we use this list for two things: constructing `ExprScopes`, which + /// works fine with nested exprs, and retrieving inference results, and we copy the inner const's inference + /// into the outer const. + // FIXME: Array repeat is not problematic indeed, but this could still break with exprs in types, + // which we do not visit for `ExprScopes` (they're fine for inference though). We either need to visit them, + // or use a more complicated search. + expr_roots: SmallVec<[ExprRoot; 1]>, } #[derive(Debug, Clone, PartialEq, Eq)] @@ -246,7 +267,7 @@ pub struct ExpressionStoreBuilder { pub types: Arena<TypeRef>, block_scopes: Vec<BlockId>, ident_hygiene: FxHashMap<ExprOrPatId, HygieneId>, - pub inference_roots: Option<SmallVec<[(ExprId, RootExprOrigin); 1]>>, + inference_roots: Option<SmallVec<[ExprRoot; 1]>>, // 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). @@ -379,8 +400,8 @@ impl ExpressionStoreBuilder { let store = { let expr_only = if has_exprs { - if let Some(const_expr_origins) = &mut expr_roots { - const_expr_origins.shrink_to_fit(); + if let Some(expr_roots) = &mut expr_roots { + expr_roots.shrink_to_fit(); } Some(Box::new(ExpressionOnlyStore { exprs, @@ -390,7 +411,8 @@ impl ExpressionStoreBuilder { binding_owners, block_scopes: block_scopes.into_boxed_slice(), ident_hygiene, - expr_roots: expr_roots.unwrap_or_default(), + expr_roots: expr_roots + .expect("should always finish with a `Some(_)` expr_roots"), })) } else { None @@ -431,6 +453,14 @@ impl ExpressionStoreBuilder { } impl ExpressionStore { + const EMPTY: &ExpressionStore = + &ExpressionStore { expr_only: None, types: Arena::new(), lifetimes: Arena::new() }; + + #[inline] + pub fn empty() -> &'static ExpressionStore { + ExpressionStore::EMPTY + } + pub fn of(db: &dyn DefDatabase, def: ExpressionStoreOwnerId) -> &ExpressionStore { match def { ExpressionStoreOwnerId::Signature(def) => { @@ -520,19 +550,35 @@ impl ExpressionStore { } /// Returns all expression root `ExprId`s found in this store. - pub fn expr_roots(&self) -> impl Iterator<Item = ExprId> { - self.const_expr_origins().iter().map(|&(id, _)| id) + pub fn expr_roots(&self) -> impl DoubleEndedIterator<Item = ExprId> { + self.expr_only + .as_ref() + .map_or(&[][..], |expr_only| &expr_only.expr_roots) + .iter() + .map(|root| root.root) + } + + fn find_root_for( + &self, + mut get: impl FnMut(&ExprRoot) -> la_arena::RawIdx, + find: la_arena::RawIdx, + ) -> ExprId { + let expr_only = self.assert_expr_only(); + let find = find.into_u32(); + let entry = expr_only.expr_roots.partition_point(|root| get(root).into_u32() <= find); + expr_only.expr_roots[entry].root + } + + pub fn find_root_for_expr(&self, expr: ExprId) -> ExprId { + self.find_root_for(|root| root.exprs_end.into_raw(), expr.into_raw()) } - /// Like [`Self::expr_roots`], but also returns the origin - /// of each expression. - pub fn expr_roots_with_origins(&self) -> impl Iterator<Item = (ExprId, RootExprOrigin)> { - self.const_expr_origins().iter().map(|&(id, origin)| (id, origin)) + pub fn find_root_for_pat(&self, pat: PatId) -> ExprId { + self.find_root_for(|root| root.pats_end.into_raw(), pat.into_raw()) } - /// Returns the map of const expression roots to their origins. - pub fn const_expr_origins(&self) -> &[(ExprId, RootExprOrigin)] { - self.expr_only.as_ref().map_or(&[], |it| &it.expr_roots) + pub fn find_root_for_binding(&self, binding: BindingId) -> ExprId { + self.find_root_for(|root| root.bindings_end.into_raw(), binding.into_raw()) } /// Returns an iterator over all block expressions in this store that define inner items. diff --git a/crates/hir-def/src/expr_store/body.rs b/crates/hir-def/src/expr_store/body.rs index 2764677226..3c7452507e 100644 --- a/crates/hir-def/src/expr_store/body.rs +++ b/crates/hir-def/src/expr_store/body.rs @@ -117,7 +117,9 @@ impl Body { impl Body { pub fn root_expr(&self) -> ExprId { - self.store.expr_roots().next().unwrap() + // A `Body` can also contain root expressions that aren't the body (in the param patterns), + // but the body always come last. + self.store.expr_roots().next_back().unwrap() } pub fn pretty_print( diff --git a/crates/hir-def/src/expr_store/lower.rs b/crates/hir-def/src/expr_store/lower.rs index 93f8304230..096dc9c9b9 100644 --- a/crates/hir-def/src/expr_store/lower.rs +++ b/crates/hir-def/src/expr_store/lower.rs @@ -19,7 +19,7 @@ use hir_expand::{ }; use intern::{Symbol, sym}; use rustc_hash::FxHashMap; -use smallvec::smallvec; +use smallvec::SmallVec; use stdx::never; use syntax::{ AstNode, AstPtr, SyntaxNodePtr, @@ -38,9 +38,9 @@ use crate::{ attrs::AttrFlags, db::DefDatabase, expr_store::{ - Body, BodySourceMap, ExprPtr, ExpressionStore, ExpressionStoreBuilder, + Body, BodySourceMap, ExprPtr, ExprRoot, ExpressionStore, ExpressionStoreBuilder, ExpressionStoreDiagnostics, ExpressionStoreSourceMap, HygieneId, LabelPtr, LifetimePtr, - PatPtr, RootExprOrigin, TypePtr, + PatPtr, TypePtr, expander::Expander, lower::generics::ImplTraitLowerFn, path::{AssociatedTypeBinding, GenericArg, GenericArgs, GenericArgsParentheses, Path}, @@ -83,7 +83,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::body(db, module, current_file_id); + let mut collector = ExprCollector::new(db, module, current_file_id); let skip_body = AttrFlags::query( db, @@ -120,8 +120,7 @@ pub(super) fn lower_body( let count = param_list.params().filter(|it| collector.check_cfg(it)).count(); params = (0..count).map(|_| collector.missing_pat()).collect(); }; - let body_expr = collector.missing_expr(); - collector.store.inference_roots = Some(smallvec![(body_expr, RootExprOrigin::BodyRoot)]); + collector.with_expr_root(|collector| collector.missing_expr()); let (store, source_map) = collector.store.finish(); return ( Body { store, params: params.into_boxed_slice(), self_param }, @@ -164,24 +163,25 @@ pub(super) fn lower_body( } }; - let body_expr = collector.collect( - self_param, - &mut params, - body, - if is_async_fn { - Awaitable::Yes - } else { - match owner { - DefWithBodyId::FunctionId(..) => Awaitable::No("non-async function"), - DefWithBodyId::StaticId(..) => Awaitable::No("static"), - DefWithBodyId::ConstId(..) => Awaitable::No("constant"), - DefWithBodyId::VariantId(..) => Awaitable::No("enum variant"), - } - }, - is_async_fn, - is_gen_fn, - ); - collector.store.inference_roots = Some(smallvec![(body_expr, RootExprOrigin::BodyRoot)]); + collector.with_expr_root(|collector| { + collector.collect( + self_param, + &mut params, + body, + if is_async_fn { + Awaitable::Yes + } else { + match owner { + DefWithBodyId::FunctionId(..) => Awaitable::No("non-async function"), + DefWithBodyId::StaticId(..) => Awaitable::No("static"), + DefWithBodyId::ConstId(..) => Awaitable::No("constant"), + DefWithBodyId::VariantId(..) => Awaitable::No("enum variant"), + } + }, + is_async_fn, + is_gen_fn, + ) + }); let (store, source_map) = collector.store.finish(); ( @@ -195,7 +195,7 @@ pub(crate) fn lower_type_ref( module: ModuleId, type_ref: InFile<Option<ast::Type>>, ) -> (ExpressionStore, ExpressionStoreSourceMap, TypeRefId) { - let mut expr_collector = ExprCollector::signature(db, module, type_ref.file_id); + let mut expr_collector = ExprCollector::new(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(); @@ -210,7 +210,7 @@ pub(crate) fn lower_generic_params( param_list: Option<ast::GenericParamList>, where_clause: Option<ast::WhereClause>, ) -> (ExpressionStore, GenericParams, ExpressionStoreSourceMap) { - let mut expr_collector = ExprCollector::signature(db, module, file_id); + let mut expr_collector = ExprCollector::new(db, module, file_id); let mut collector = generics::GenericParamsCollector::new(def); collector.lower(&mut expr_collector, param_list, where_clause); let params = collector.finish(); @@ -224,7 +224,7 @@ pub(crate) fn lower_impl( impl_syntax: InFile<ast::Impl>, impl_id: ImplId, ) -> (ExpressionStore, ExpressionStoreSourceMap, TypeRefId, Option<TraitRef>, GenericParams) { - let mut expr_collector = ExprCollector::signature(db, module, impl_syntax.file_id); + let mut expr_collector = ExprCollector::new(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 { @@ -252,7 +252,7 @@ pub(crate) fn lower_trait( trait_syntax: InFile<ast::Trait>, trait_id: TraitId, ) -> (ExpressionStore, ExpressionStoreSourceMap, GenericParams) { - let mut expr_collector = ExprCollector::signature(db, module, trait_syntax.file_id); + let mut expr_collector = ExprCollector::new(db, module, trait_syntax.file_id); let mut collector = generics::GenericParamsCollector::with_self_param( &mut expr_collector, trait_id.into(), @@ -275,7 +275,7 @@ pub(crate) fn lower_type_alias( type_alias_id: TypeAliasId, ) -> (ExpressionStore, ExpressionStoreSourceMap, GenericParams, Box<[TypeBound]>, Option<TypeRefId>) { - let mut expr_collector = ExprCollector::signature(db, module, alias.file_id); + let mut expr_collector = ExprCollector::new(db, module, alias.file_id); let bounds = alias .value .type_bound_list() @@ -317,7 +317,7 @@ pub(crate) fn lower_function( bool, bool, ) { - let mut expr_collector = ExprCollector::signature(db, module, fn_.file_id); + let mut expr_collector = ExprCollector::new(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![]; @@ -544,20 +544,7 @@ impl BindingList { } impl<'db> ExprCollector<'db> { - /// 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.inference_roots = Some(Default::default()); - this - } - - /// Creates a collector for a bidy store. - pub fn body( + pub fn new( db: &dyn DefDatabase, module: ModuleId, current_file_id: HirFileId, @@ -565,7 +552,7 @@ impl<'db> ExprCollector<'db> { let (def_map, local_def_map) = module.local_def_map(db); let expander = Expander::new(db, current_file_id, def_map); let krate = module.krate(db); - ExprCollector { + let mut result = ExprCollector { db, cfg_options: krate.cfg_options(db), module, @@ -583,7 +570,9 @@ impl<'db> ExprCollector<'db> { outer_impl_trait: false, krate, name_generator_index: 0, - } + }; + result.store.inference_roots = Some(SmallVec::new()); + result } fn generate_new_name(&mut self) -> Name { @@ -652,9 +641,6 @@ 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.inference_roots { - const_expr_origins.push((len.expr, RootExprOrigin::ArrayLength)); - } TypeRef::Array(ArrayType { ty: self.lower_type_ref_opt(inner.ty(), impl_trait_lower_fn), len, @@ -939,9 +925,6 @@ impl<'db> ExprCollector<'db> { } ast::GenericArg::ConstArg(arg) => { let arg = self.lower_const_arg(arg); - if let Some(const_expr_origins) = &mut self.store.inference_roots { - const_expr_origins.push((arg.expr, RootExprOrigin::GenericArgsPath)); - } args.push(GenericArg::Const(arg)) } } @@ -1216,17 +1199,17 @@ impl<'db> ExprCollector<'db> { } fn lower_const_arg_opt(&mut self, arg: Option<ast::ConstArg>) -> ConstRef { - let const_expr_origins = self.store.inference_roots.take(); - let r = ConstRef { expr: self.collect_expr_opt(arg.and_then(|it| it.expr())) }; - self.store.inference_roots = const_expr_origins; - r + ConstRef { + expr: self.with_fresh_binding_expr_root(|this| { + this.collect_expr_opt(arg.and_then(|arg| arg.expr())) + }), + } } pub fn lower_const_arg(&mut self, arg: ast::ConstArg) -> ConstRef { - let const_expr_origins = self.store.inference_roots.take(); - let r = ConstRef { expr: self.collect_expr_opt(arg.expr()) }; - self.store.inference_roots = const_expr_origins; - r + ConstRef { + expr: self.with_fresh_binding_expr_root(|this| this.collect_expr_opt(arg.expr())), + } } fn collect_expr(&mut self, expr: ast::Expr) -> ExprId { @@ -3106,6 +3089,31 @@ fn pat_literal_to_hir(lit: &ast::LiteralPat) -> Option<(Literal, ast::Literal)> } impl ExprCollector<'_> { + fn with_fresh_binding_expr_root(&mut self, f: impl FnOnce(&mut Self) -> ExprId) -> ExprId { + self.with_expr_root(|this| this.with_binding_owner(f)) + } + + fn with_expr_root(&mut self, f: impl FnOnce(&mut Self) -> ExprId) -> ExprId { + let inference_roots = self.store.inference_roots.take(); + let root = f(self); + self.store.inference_roots = inference_roots; + + if let Some(inference_roots) = &mut self.store.inference_roots { + inference_roots.push(ExprRoot { + root, + exprs_end: end(&self.store.exprs), + pats_end: end(&self.store.pats), + bindings_end: end(&self.store.bindings), + }); + } + + return root; + + fn end<T>(arena: &la_arena::Arena<T>) -> la_arena::Idx<T> { + la_arena::Idx::from_raw(la_arena::RawIdx::from_u32(arena.len() as u32)) + } + } + fn alloc_expr(&mut self, expr: Expr, ptr: ExprPtr) -> ExprId { let src = self.expander.in_file(ptr); let id = self.store.exprs.alloc(expr); diff --git a/crates/hir-def/src/expr_store/lower/generics.rs b/crates/hir-def/src/expr_store/lower/generics.rs index 5ffc4f5851..7ef9c80de1 100644 --- a/crates/hir-def/src/expr_store/lower/generics.rs +++ b/crates/hir-def/src/expr_store/lower/generics.rs @@ -128,15 +128,7 @@ impl GenericParamsCollector { ); 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.inference_roots - { - const_expr_origins.push(( - default.expr, - crate::expr_store::RootExprOrigin::ConstParam(idx), - )); - } + self.type_or_consts.alloc(param.into()); } 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 6819eb3deb..f507841a91 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::signature(&db, crate_def_map(&db, krate).root_module_id(), file_id.into()); + ExprCollector::new(&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 c6ba0241b7..5663b8155c 100644 --- a/crates/hir-def/src/expr_store/scope.rs +++ b/crates/hir-def/src/expr_store/scope.rs @@ -7,7 +7,7 @@ use crate::{ db::DefDatabase, expr_store::{Body, ExpressionStore, HygieneId}, hir::{ - Binding, BindingId, Expr, ExprId, Item, LabelId, Pat, PatId, Statement, + Array, Binding, BindingId, Expr, ExprId, Item, LabelId, Pat, PatId, Statement, generics::GenericParams, }, signatures::VariantFields, @@ -151,7 +151,7 @@ impl ExprScopes { scopes.add_bindings(body, root, self_param, body.binding_hygiene(self_param)); } scopes.add_params_bindings(body, root, &body.params); - compute_expr_scopes(body.root_expr(), body, &mut scopes, &mut root); + compute_expr_scopes(body.root_expr(), body, &mut scopes, &mut { root }, &mut root); scopes } @@ -166,7 +166,7 @@ impl ExprScopes { 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); + compute_expr_scopes(root_expr, store, &mut scopes, &mut { scope }, &mut scope); } scopes } @@ -270,31 +270,33 @@ fn compute_block_scopes( store: &ExpressionStore, scopes: &mut ExprScopes, scope: &mut ScopeId, + const_scope: &mut ScopeId, ) { for stmt in statements { match stmt { Statement::Let { pat, initializer, else_branch, .. } => { if let Some(expr) = initializer { - compute_expr_scopes(*expr, store, scopes, scope); + compute_expr_scopes(*expr, store, scopes, scope, const_scope); } if let Some(expr) = else_branch { - compute_expr_scopes(*expr, store, scopes, scope); + compute_expr_scopes(*expr, store, scopes, scope, const_scope); } *scope = scopes.new_scope(*scope); scopes.add_pat_bindings(store, *scope, *pat); } Statement::Expr { expr, .. } => { - compute_expr_scopes(*expr, store, scopes, scope); + compute_expr_scopes(*expr, store, scopes, scope, const_scope); } Statement::Item(Item::MacroDef(macro_id)) => { *scope = scopes.new_macro_def_scope(*scope, macro_id.clone()); + *const_scope = scopes.new_macro_def_scope(*const_scope, macro_id.clone()); } Statement::Item(Item::Other) => (), } } if let Some(expr) = tail { - compute_expr_scopes(expr, store, scopes, scope); + compute_expr_scopes(expr, store, scopes, scope, const_scope); } } @@ -303,69 +305,86 @@ fn compute_expr_scopes( store: &ExpressionStore, scopes: &mut ExprScopes, scope: &mut ScopeId, + const_scope: &mut ScopeId, ) { - let make_label = - |label: &Option<LabelId>| label.map(|label| (label, store[label].name.clone())); + let make_label = |label: Option<LabelId>| label.map(|label| (label, store[label].name.clone())); - let compute_expr_scopes = |scopes: &mut ExprScopes, expr: ExprId, scope: &mut ScopeId| { - compute_expr_scopes(expr, store, scopes, scope) + let compute_expr_scopes = + |scopes: &mut ExprScopes, expr: ExprId, scope: &mut ScopeId, const_scope: &mut ScopeId| { + compute_expr_scopes(expr, store, scopes, scope, const_scope) + }; + let handle_block = |id, + statements, + tail, + label, + scopes: &mut ExprScopes, + scope: &mut ScopeId, + const_scope: &mut ScopeId| { + let mut scope = scopes.new_block_scope(*scope, id, make_label(label)); + let mut const_scope = if id.is_some() { + scopes.new_block_scope(*const_scope, id, None) + } else { + // We don't need to allocate a new scope, since only items matter to us. + *const_scope + }; + // Overwrite the old scope for the block expr, so that every block scope can be found + // via the block itself (important for blocks that only contain items, no expressions). + scopes.set_scope(expr, scope); + compute_block_scopes(statements, tail, store, scopes, &mut scope, &mut const_scope); }; scopes.set_scope(expr, *scope); match &store[expr] { Expr::Block { statements, tail, id, label } => { - let mut scope = scopes.new_block_scope(*scope, *id, make_label(label)); - // Overwrite the old scope for the block expr, so that every block scope can be found - // via the block itself (important for blocks that only contain items, no expressions). - scopes.set_scope(expr, scope); - compute_block_scopes(statements, *tail, store, scopes, &mut scope); + handle_block(*id, statements, *tail, *label, scopes, scope, const_scope); } Expr::Const(id) => { - let mut scope = scopes.root_scope(); - compute_expr_scopes(scopes, *id, &mut scope); + let mut scope = *const_scope; + compute_expr_scopes(scopes, *id, &mut scope, const_scope); + } + Expr::Array(Array::Repeat { initializer, repeat }) => { + compute_expr_scopes(scopes, *initializer, scope, const_scope); + let mut repeat_scope = *const_scope; + compute_expr_scopes(scopes, *repeat, &mut repeat_scope, const_scope); } Expr::Unsafe { id, statements, tail } => { - let mut scope = scopes.new_block_scope(*scope, *id, None); - // Overwrite the old scope for the block expr, so that every block scope can be found - // via the block itself (important for blocks that only contain items, no expressions). - scopes.set_scope(expr, scope); - compute_block_scopes(statements, *tail, store, scopes, &mut scope); + handle_block(*id, statements, *tail, None, scopes, scope, const_scope); } Expr::Loop { body: body_expr, label } => { - let mut scope = scopes.new_labeled_scope(*scope, make_label(label)); - compute_expr_scopes(scopes, *body_expr, &mut scope); + let mut scope = scopes.new_labeled_scope(*scope, make_label(*label)); + compute_expr_scopes(scopes, *body_expr, &mut scope, const_scope); } Expr::Closure { args, body: body_expr, .. } => { let mut scope = scopes.new_scope(*scope); scopes.add_params_bindings(store, scope, args); - compute_expr_scopes(scopes, *body_expr, &mut scope); + compute_expr_scopes(scopes, *body_expr, &mut scope, const_scope); } Expr::Match { expr, arms } => { - compute_expr_scopes(scopes, *expr, scope); + compute_expr_scopes(scopes, *expr, scope, const_scope); for arm in arms.iter() { let mut scope = scopes.new_scope(*scope); scopes.add_pat_bindings(store, scope, arm.pat); if let Some(guard) = arm.guard { scope = scopes.new_scope(scope); - compute_expr_scopes(scopes, guard, &mut scope); + compute_expr_scopes(scopes, guard, &mut scope, const_scope); } - compute_expr_scopes(scopes, arm.expr, &mut scope); + compute_expr_scopes(scopes, arm.expr, &mut scope, const_scope); } } &Expr::If { condition, then_branch, else_branch } => { let mut then_branch_scope = scopes.new_scope(*scope); - compute_expr_scopes(scopes, condition, &mut then_branch_scope); - compute_expr_scopes(scopes, then_branch, &mut then_branch_scope); + compute_expr_scopes(scopes, condition, &mut then_branch_scope, const_scope); + compute_expr_scopes(scopes, then_branch, &mut then_branch_scope, const_scope); if let Some(else_branch) = else_branch { - compute_expr_scopes(scopes, else_branch, scope); + compute_expr_scopes(scopes, else_branch, scope, const_scope); } } &Expr::Let { pat, expr } => { - compute_expr_scopes(scopes, expr, scope); + compute_expr_scopes(scopes, expr, scope, const_scope); *scope = scopes.new_scope(*scope); scopes.add_pat_bindings(store, *scope, pat); } - _ => store.walk_child_exprs(expr, |e| compute_expr_scopes(scopes, e, scope)), + _ => store.walk_child_exprs(expr, |e| compute_expr_scopes(scopes, e, scope, const_scope)), }; } diff --git a/crates/hir-def/src/hir/generics.rs b/crates/hir-def/src/hir/generics.rs index 43dd7d1c54..04ccc7bf90 100644 --- a/crates/hir-def/src/hir/generics.rs +++ b/crates/hir-def/src/hir/generics.rs @@ -188,6 +188,11 @@ impl GenericParams { pub const SELF_PARAM_ID_IN_SELF: la_arena::Idx<TypeOrConstParamData> = LocalTypeOrConstParamId::from_raw(RawIdx::from_u32(0)); + #[inline] + pub fn empty() -> &'static GenericParams { + LazyLock::force(&EMPTY) + } + pub fn of(db: &dyn DefDatabase, def: GenericDefId) -> &GenericParams { Self::with_store(db, def).0 } diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs index 36afd8f8a5..ba6f67fcbb 100644 --- a/crates/hir-def/src/lib.rs +++ b/crates/hir-def/src/lib.rs @@ -724,12 +724,12 @@ impl From<EnumVariantId> for DefWithBodyId { } impl DefWithBodyId { - pub fn as_generic_def_id(self, db: &dyn DefDatabase) -> Option<GenericDefId> { + pub fn generic_def(self, db: &dyn DefDatabase) -> GenericDefId { match self { - DefWithBodyId::FunctionId(f) => Some(f.into()), - DefWithBodyId::StaticId(s) => Some(s.into()), - DefWithBodyId::ConstId(c) => Some(c.into()), - DefWithBodyId::VariantId(c) => Some(c.lookup(db).parent.into()), + DefWithBodyId::FunctionId(f) => f.into(), + DefWithBodyId::StaticId(s) => s.into(), + DefWithBodyId::ConstId(c) => c.into(), + DefWithBodyId::VariantId(c) => c.lookup(db).parent.into(), } } } diff --git a/crates/hir-def/src/signatures.rs b/crates/hir-def/src/signatures.rs index 8136e11412..aedfaaa6aa 100644 --- a/crates/hir-def/src/signatures.rs +++ b/crates/hir-def/src/signatures.rs @@ -984,7 +984,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::signature(db, module, fields.file_id); + let mut col = ExprCollector::new(db, module, fields.file_id); let override_visibility = override_visibility.map(|vis| { LazyCell::new(|| { let span_map = db.span_map(fields.file_id); diff --git a/crates/hir-ty/src/consteval.rs b/crates/hir-ty/src/consteval.rs index 9e2040ce37..67e40fa811 100644 --- a/crates/hir-ty/src/consteval.rs +++ b/crates/hir-ty/src/consteval.rs @@ -7,29 +7,32 @@ use base_db::Crate; use hir_def::{ ConstId, EnumVariantId, ExpressionStoreOwnerId, GenericDefId, HasModule, StaticId, attrs::AttrFlags, - expr_store::{Body, ExpressionStore}, + expr_store::{Body, ExpressionStore, HygieneId, path::Path}, hir::{Expr, ExprId, Literal}, + resolver::{Resolver, ValueNs}, }; use hir_expand::Lookup; use rustc_abi::Size; use rustc_apfloat::Float; -use rustc_type_ir::inherent::IntoKind; +use rustc_ast_ir::Mutability; +use rustc_type_ir::inherent::{Const as _, GenericArgs as _, IntoKind, Ty as _}; use stdx::never; use crate::{ - LifetimeElisionKind, ParamEnvAndCrate, TyLoweringContext, - db::{GeneralConstId, HirDatabase}, + ParamEnvAndCrate, + db::{AnonConstId, AnonConstLoc, GeneralConstId, HirDatabase}, display::DisplayTarget, - infer::InferenceContext, + generics::Generics, mir::{MirEvalError, MirLowerError, pad16}, next_solver::{ - Allocation, Const, ConstKind, Consts, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs, - ScalarInt, StoredAllocation, StoredGenericArgs, Ty, TyKind, ValTreeKind, default_types, + Allocation, Const, ConstKind, Consts, DbInterner, DefaultAny, ErrorGuaranteed, GenericArg, + GenericArgs, ParamConst, ScalarInt, StoredAllocation, StoredEarlyBinder, StoredGenericArgs, + Ty, TyKind, UnevaluatedConst, ValTreeKind, default_types, infer::InferCtxt, }, traits::StoredParamEnvAndCrate, }; -use super::mir::{interpret_mir, lower_body_to_mir}; +use super::mir::interpret_mir; pub fn unknown_const<'db>(_ty: Ty<'db>) -> Const<'db> { Const::new(DbInterner::conjure(), rustc_type_ir::ConstKind::Error(ErrorGuaranteed)) @@ -80,15 +83,13 @@ impl From<MirEvalError> for ConstEvalError { } /// Interns a constant scalar with the given type -pub fn intern_const_ref<'a>( - db: &'a dyn HirDatabase, +fn intern_const_ref<'db>( + interner: DbInterner<'db>, value: &Literal, - ty: Ty<'a>, - krate: Crate, -) -> Const<'a> { - let interner = DbInterner::new_no_crate(db); - let Ok(data_layout) = db.target_data_layout(krate) else { - return Const::error(interner); + ty: Ty<'db>, +) -> Result<Const<'db>, CreateConstError<'db>> { + let Ok(data_layout) = interner.db.target_data_layout(interner.expect_crate()) else { + return Ok(Const::error(interner)); }; let valtree = match (ty.kind(), value) { (TyKind::Uint(uint), Literal::Uint(value, _)) => { @@ -136,14 +137,80 @@ pub fn intern_const_ref<'a>( } (_, Literal::CString(_)) => { // FIXME: - return Const::error(interner); + return Ok(Const::error(interner)); } _ => { never!("mismatching type for literal"); - return Const::error(interner); + let actual = literal_ty( + interner, + value, + |types| types.types.i32, + |types| types.types.u32, + |types| types.types.f64, + ); + return Err(CreateConstError::TypeMismatch { actual }); } }; - Const::new_valtree(interner, ty, valtree) + Ok(Const::new_valtree(interner, ty, valtree)) +} + +pub(crate) fn literal_ty<'db>( + interner: DbInterner<'db>, + value: &Literal, + default_int: impl FnOnce(&DefaultAny<'db>) -> Ty<'db>, + default_uint: impl FnOnce(&DefaultAny<'db>) -> Ty<'db>, + default_float: impl FnOnce(&DefaultAny<'db>) -> Ty<'db>, +) -> Ty<'db> { + let types = interner.default_types(); + match value { + Literal::Bool(..) => types.types.bool, + Literal::String(..) => types.types.static_str_ref, + Literal::ByteString(bs) => { + let byte_type = types.types.u8; + let array_type = Ty::new_array(interner, byte_type, bs.len() as u128); + Ty::new_ref(interner, types.regions.statik, array_type, Mutability::Not) + } + Literal::CString(..) => Ty::new_ref( + interner, + types.regions.statik, + interner.lang_items().CStr.map_or(types.types.error, |strukt| { + Ty::new_adt(interner, strukt.into(), types.empty.generic_args) + }), + Mutability::Not, + ), + Literal::Char(..) => types.types.char, + Literal::Int(_v, ty) => match ty { + Some(int_ty) => match int_ty { + hir_def::builtin_type::BuiltinInt::Isize => types.types.isize, + hir_def::builtin_type::BuiltinInt::I8 => types.types.i8, + hir_def::builtin_type::BuiltinInt::I16 => types.types.i16, + hir_def::builtin_type::BuiltinInt::I32 => types.types.i32, + hir_def::builtin_type::BuiltinInt::I64 => types.types.i64, + hir_def::builtin_type::BuiltinInt::I128 => types.types.i128, + }, + None => default_int(types), + }, + Literal::Uint(_v, ty) => match ty { + Some(int_ty) => match int_ty { + hir_def::builtin_type::BuiltinUint::Usize => types.types.usize, + hir_def::builtin_type::BuiltinUint::U8 => types.types.u8, + hir_def::builtin_type::BuiltinUint::U16 => types.types.u16, + hir_def::builtin_type::BuiltinUint::U32 => types.types.u32, + hir_def::builtin_type::BuiltinUint::U64 => types.types.u64, + hir_def::builtin_type::BuiltinUint::U128 => types.types.u128, + }, + None => default_uint(types), + }, + Literal::Float(_v, ty) => match ty { + Some(float_ty) => match float_ty { + hir_def::builtin_type::BuiltinFloat::F16 => types.types.f16, + hir_def::builtin_type::BuiltinFloat::F32 => types.types.f32, + hir_def::builtin_type::BuiltinFloat::F64 => types.types.f64, + hir_def::builtin_type::BuiltinFloat::F128 => types.types.f128, + }, + None => default_float(types), + }, + } } /// Interns a possibly-unknown target usize @@ -183,7 +250,11 @@ pub fn try_const_usize<'db>(db: &'db dyn HirDatabase, c: Const<'db>) -> Option<u let ec = db.const_eval_static(id).ok()?; Some(allocation_as_usize(ec)) } - GeneralConstId::AnonConstId(_) => None, + GeneralConstId::AnonConstId(id) => { + let subst = unevaluated_const.args; + let ec = db.anon_const_eval(id, subst, None).ok()?; + Some(allocation_as_usize(ec)) + } }, ConstKind::Value(val) => { if val.ty == default_types(db).types.usize { @@ -201,8 +272,8 @@ pub fn allocation_as_isize(ec: Allocation<'_>) -> i128 { i128::from_le_bytes(pad16(&ec.memory, true)) } -pub fn try_const_isize<'db>(db: &'db dyn HirDatabase, c: &Const<'db>) -> Option<i128> { - match (*c).kind() { +pub fn try_const_isize<'db>(db: &'db dyn HirDatabase, c: Const<'db>) -> Option<i128> { + match c.kind() { ConstKind::Param(_) => None, ConstKind::Infer(_) => None, ConstKind::Bound(_, _) => None, @@ -217,7 +288,11 @@ pub fn try_const_isize<'db>(db: &'db dyn HirDatabase, c: &Const<'db>) -> Option< let ec = db.const_eval_static(id).ok()?; Some(allocation_as_isize(ec)) } - GeneralConstId::AnonConstId(_) => None, + GeneralConstId::AnonConstId(id) => { + let subst = unevaluated_const.args; + let ec = db.anon_const_eval(id, subst, None).ok()?; + Some(allocation_as_isize(ec)) + } }, ConstKind::Value(val) => { if val.ty == default_types(db).types.isize { @@ -231,6 +306,99 @@ pub fn try_const_isize<'db>(db: &'db dyn HirDatabase, c: &Const<'db>) -> Option< } } +#[derive(Debug)] +pub(crate) enum CreateConstError<'db> { + UsedForbiddenParam, + ResolveToNonConst, + DoesNotResolve, + UnderscoreExpr, + TypeMismatch { + #[expect(unused, reason = "will need this for diagnostics")] + actual: Ty<'db>, + }, +} + +pub(crate) fn path_to_const<'a, 'db>( + db: &'db dyn HirDatabase, + resolver: &Resolver<'db>, + generics: &dyn Fn() -> &'a Generics<'db>, + forbid_params_after: Option<u32>, + path: &Path, +) -> Result<Const<'db>, CreateConstError<'db>> { + let interner = DbInterner::new_no_crate(db); + let resolution = resolver + .resolve_path_in_value_ns_fully(db, path, HygieneId::ROOT) + .ok_or(CreateConstError::DoesNotResolve)?; + let konst = match resolution { + ValueNs::ConstId(id) => GeneralConstId::ConstId(id), + ValueNs::StaticId(id) => GeneralConstId::StaticId(id), + ValueNs::GenericParam(param) => { + let index = generics().type_or_const_param_idx(param.into()); + if forbid_params_after.is_some_and(|forbid_after| index >= forbid_after) { + return Err(CreateConstError::UsedForbiddenParam); + } + return Ok(Const::new_param(interner, ParamConst { id: param, index })); + } + // These are not valid as consts. + // FIXME: Report an error? + ValueNs::ImplSelf(_) + | ValueNs::LocalBinding(_) + | ValueNs::FunctionId(_) + | ValueNs::StructId(_) + | ValueNs::EnumVariantId(_) => return Err(CreateConstError::ResolveToNonConst), + }; + let args = GenericArgs::empty(interner); + Ok(Const::new_unevaluated(interner, UnevaluatedConst { def: konst.into(), args })) +} + +pub(crate) fn create_anon_const<'a, 'db>( + interner: DbInterner<'db>, + owner: ExpressionStoreOwnerId, + store: &ExpressionStore, + expr: ExprId, + resolver: &Resolver<'db>, + expected_ty: Ty<'db>, + generics: &dyn Fn() -> &'a Generics<'db>, + infcx: Option<&InferCtxt<'db>>, + forbid_params_after: Option<u32>, +) -> Result<Const<'db>, CreateConstError<'db>> { + match &store[expr] { + Expr::Literal(literal) => intern_const_ref(interner, literal, expected_ty), + Expr::Underscore => match infcx { + Some(infcx) => Ok(infcx.next_const_var(expr.into())), + None => Err(CreateConstError::UnderscoreExpr), + }, + Expr::Path(path) + if let konst = + path_to_const(interner.db, resolver, generics, forbid_params_after, path) + && !matches!(konst, Err(CreateConstError::DoesNotResolve)) => + { + konst + } + _ => { + let allow_using_generic_params = forbid_params_after.is_none(); + let konst = AnonConstId::new( + interner.db, + AnonConstLoc { + owner, + expr, + ty: StoredEarlyBinder::bind(expected_ty.store()), + allow_using_generic_params, + }, + ); + let args = if allow_using_generic_params { + GenericArgs::identity_for_item(interner, owner.generic_def(interner.db).into()) + } else { + GenericArgs::empty(interner) + }; + Ok(Const::new_unevaluated( + interner, + UnevaluatedConst { def: GeneralConstId::AnonConstId(konst).into(), args }, + )) + } + } +} + pub(crate) fn const_eval_discriminant_variant( db: &dyn HirDatabase, variant_id: EnumVariantId, @@ -256,7 +424,7 @@ pub(crate) fn const_eval_discriminant_variant( let is_signed = repr.and_then(|repr| repr.int).is_none_or(|int| int.is_signed()); let mir_body = db.monomorphized_mir_body( - def, + def.into(), GenericArgs::empty(interner).store(), ParamEnvAndCrate { param_env: db.trait_environment(def.into()), krate: def.krate(db) } .store(), @@ -266,49 +434,6 @@ pub(crate) fn const_eval_discriminant_variant( Ok(c) } -// FIXME: Ideally constants in const eval should have separate body (issue #7434), and this function should -// get an `InferenceResult` instead of an `InferenceContext`. And we should remove `ctx.clone().resolve_all()` here -// and make this function private. See the fixme comment on `InferenceContext::resolve_all`. -pub(crate) fn eval_to_const<'db>(expr: ExprId, ctx: &mut InferenceContext<'_, 'db>) -> Const<'db> { - let infer = ctx.fixme_resolve_all_clone(); - fn has_closure(store: &ExpressionStore, expr: ExprId) -> bool { - if matches!(store[expr], Expr::Closure { .. }) { - return true; - } - let mut r = false; - store.walk_child_exprs(expr, |idx| r |= has_closure(store, idx)); - r - } - if has_closure(ctx.store, expr) { - // Type checking clousres need an isolated body (See the above FIXME). Bail out early to prevent panic. - return Const::error(ctx.interner()); - } - if let Expr::Path(p) = &ctx.store[expr] { - let mut ctx = TyLoweringContext::new( - ctx.db, - &ctx.resolver, - ctx.store, - ctx.generic_def, - LifetimeElisionKind::Infer, - ); - if let Some(c) = ctx.path_to_const(p) { - return c; - } - } - if let Some(body_owner) = ctx.owner.as_def_with_body() - && let Ok(mir_body) = - lower_body_to_mir(ctx.db, body_owner, Body::of(ctx.db, body_owner), &infer, expr) - && let Ok((Ok(result), _)) = interpret_mir(ctx.db, &mir_body, true, None) - { - return Const::new_from_allocation( - ctx.interner(), - &result, - ParamEnvAndCrate { param_env: ctx.table.param_env, krate: ctx.resolver.krate() }, - ); - } - Const::error(ctx.interner()) -} - pub(crate) fn const_eval_discriminant_cycle_result( _: &dyn HirDatabase, _: salsa::Id, @@ -360,6 +485,48 @@ pub(crate) fn const_eval<'db>( } } +pub(crate) fn anon_const_eval<'db>( + db: &'db dyn HirDatabase, + def: AnonConstId, + subst: GenericArgs<'db>, + trait_env: Option<ParamEnvAndCrate<'db>>, +) -> Result<Allocation<'db>, ConstEvalError> { + return match anon_const_eval_query(db, def, subst.store(), trait_env.map(|env| env.store())) { + Ok(konst) => Ok(konst.as_ref()), + Err(err) => Err(err.clone()), + }; + + #[salsa::tracked(returns(ref), cycle_result = anon_const_eval_cycle_result)] + pub(crate) fn anon_const_eval_query( + db: &dyn HirDatabase, + def: AnonConstId, + subst: StoredGenericArgs, + trait_env: Option<StoredParamEnvAndCrate>, + ) -> Result<StoredAllocation, ConstEvalError> { + let body = db.monomorphized_mir_body( + def.into(), + subst, + ParamEnvAndCrate { + param_env: db.trait_environment(def.loc(db).owner), + krate: def.krate(db), + } + .store(), + )?; + let c = interpret_mir(db, body, false, trait_env.as_ref().map(|env| env.as_ref()))?.0?; + Ok(c.store()) + } + + pub(crate) fn anon_const_eval_cycle_result( + _: &dyn HirDatabase, + _: salsa::Id, + _: AnonConstId, + _: StoredGenericArgs, + _: Option<StoredParamEnvAndCrate>, + ) -> Result<StoredAllocation, ConstEvalError> { + Err(ConstEvalError::MirLowerError(MirLowerError::Loop)) + } +} + pub(crate) fn const_eval_static<'db>( db: &'db dyn HirDatabase, def: StaticId, diff --git a/crates/hir-ty/src/consteval/tests.rs b/crates/hir-ty/src/consteval/tests.rs index 723fa0fc68..90d9a2ab62 100644 --- a/crates/hir-ty/src/consteval/tests.rs +++ b/crates/hir-ty/src/consteval/tests.rs @@ -2474,8 +2474,6 @@ fn extern_weak_statics() { } #[test] -// FIXME -#[should_panic] fn from_ne_bytes() { check_number( r#" diff --git a/crates/hir-ty/src/db.rs b/crates/hir-ty/src/db.rs index bf209392f0..352f717454 100644 --- a/crates/hir-ty/src/db.rs +++ b/crates/hir-ty/src/db.rs @@ -1,17 +1,19 @@ //! The home of `HirDatabase`, which is the Salsa database containing all the //! type inference-related queries. -use base_db::{Crate, impl_intern_key, target::TargetLoadError}; +use arrayvec::ArrayVec; +use base_db::{Crate, target::TargetLoadError}; use either::Either; use hir_def::{ - AdtId, BuiltinDeriveImplId, CallableDefId, ConstId, ConstParamId, DefWithBodyId, EnumVariantId, - ExpressionStoreOwnerId, FunctionId, GenericDefId, ImplId, LifetimeParamId, LocalFieldId, - StaticId, TraitId, TypeAliasId, VariantId, + AdtId, BuiltinDeriveImplId, CallableDefId, ConstId, ConstParamId, EnumVariantId, + ExpressionStoreOwnerId, FunctionId, GenericDefId, HasModule, ImplId, LifetimeParamId, + LocalFieldId, ModuleId, StaticId, TraitId, TypeAliasId, VariantId, builtin_derive::BuiltinDeriveImplMethod, db::DefDatabase, expr_store::ExpressionStore, - hir::{ClosureKind, ExprId}, + hir::{ClosureKind, ExprId, generics::LocalTypeOrConstParamId}, layout::TargetDataLayout, + resolver::{HasResolver, Resolver}, signatures::{ConstSignature, StaticSignature}, }; use la_arena::ArenaMap; @@ -21,15 +23,17 @@ use stdx::impl_from; use triomphe::Arc; use crate::{ - ImplTraitId, TyDefId, ValueTyDefId, + GenericDefaultsRef, GenericPredicates, ImplTraitId, InferBodyId, TyDefId, TyLoweringResult, + ValueTyDefId, consteval::ConstEvalError, dyn_compatibility::DynCompatibilityViolation, layout::{Layout, LayoutError}, - lower::{Diagnostics, GenericDefaults}, + lower::{GenericDefaults, TypeAliasBounds}, mir::{BorrowckResult, MirBody, MirLowerError}, next_solver::{ - Allocation, EarlyBinder, GenericArgs, ParamEnv, PolyFnSig, StoredEarlyBinder, - StoredGenericArgs, StoredTy, TraitRef, Ty, VariancesOf, + Allocation, Clause, EarlyBinder, GenericArgs, ParamEnv, PolyFnSig, StoredClauses, + StoredEarlyBinder, StoredGenericArgs, StoredPolyFnSig, StoredTraitRef, StoredTy, TraitRef, + Ty, VariancesOf, }, traits::{ParamEnvAndCrate, StoredParamEnvAndCrate}, }; @@ -41,7 +45,7 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { // FXME: Collapse `mir_body_for_closure` into `mir_body` // and `monomorphized_mir_body_for_closure` into `monomorphized_mir_body` #[salsa::transparent] - fn mir_body(&self, def: DefWithBodyId) -> Result<&MirBody, MirLowerError> { + fn mir_body(&self, def: InferBodyId) -> Result<&MirBody, MirLowerError> { crate::mir::mir_body_query(self, def).as_ref().map_err(|err| err.clone()) } @@ -53,7 +57,7 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { #[salsa::transparent] fn monomorphized_mir_body( &self, - def: DefWithBodyId, + def: InferBodyId, subst: StoredGenericArgs, env: StoredParamEnvAndCrate, ) -> Result<&MirBody, MirLowerError> { @@ -75,7 +79,7 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { } #[salsa::transparent] - fn borrowck(&self, def: DefWithBodyId) -> Result<&[BorrowckResult], MirLowerError> { + fn borrowck(&self, def: InferBodyId) -> Result<&[BorrowckResult], MirLowerError> { crate::mir::borrowck_query(self, def).as_ref().map(|it| &**it).map_err(|err| err.clone()) } @@ -88,6 +92,15 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { trait_env: Option<ParamEnvAndCrate<'db>>, ) -> Result<Allocation<'db>, ConstEvalError>; + #[salsa::invoke(crate::consteval::anon_const_eval)] + #[salsa::transparent] + fn anon_const_eval<'db>( + &'db self, + def: AnonConstId, + subst: GenericArgs<'db>, + trait_env: Option<ParamEnvAndCrate<'db>>, + ) -> Result<Allocation<'db>, ConstEvalError>; + #[salsa::invoke(crate::consteval::const_eval_static)] #[salsa::transparent] fn const_eval_static<'db>(&'db self, def: StaticId) -> Result<Allocation<'db>, ConstEvalError>; @@ -138,10 +151,10 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { #[salsa::invoke(crate::lower::type_for_type_alias_with_diagnostics)] #[salsa::transparent] - fn type_for_type_alias_with_diagnostics<'db>( - &'db self, + fn type_for_type_alias_with_diagnostics( + &self, def: TypeAliasId, - ) -> (EarlyBinder<'db, Ty<'db>>, Diagnostics); + ) -> &TyLoweringResult<StoredEarlyBinder<StoredTy>>; /// Returns the type of the value of the given constant, or `None` if the `ValueTyDefId` is /// a `StructId` or `EnumVariantId` with a record constructor. @@ -149,43 +162,71 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { #[salsa::transparent] fn value_ty<'db>(&'db self, def: ValueTyDefId) -> Option<EarlyBinder<'db, Ty<'db>>>; + #[salsa::invoke(crate::lower::type_for_const)] + #[salsa::transparent] + fn type_for_const<'db>(&'db self, def: ConstId) -> EarlyBinder<'db, Ty<'db>>; + + #[salsa::invoke(crate::lower::type_for_const_with_diagnostics)] + #[salsa::transparent] + fn type_for_const_with_diagnostics( + &self, + def: ConstId, + ) -> &TyLoweringResult<StoredEarlyBinder<StoredTy>>; + + #[salsa::invoke(crate::lower::type_for_static)] + #[salsa::transparent] + fn type_for_static<'db>(&'db self, def: StaticId) -> EarlyBinder<'db, Ty<'db>>; + + #[salsa::invoke(crate::lower::type_for_static_with_diagnostics)] + #[salsa::transparent] + fn type_for_static_with_diagnostics( + &self, + def: StaticId, + ) -> &TyLoweringResult<StoredEarlyBinder<StoredTy>>; + #[salsa::invoke(crate::lower::impl_self_ty_with_diagnostics)] #[salsa::transparent] - fn impl_self_ty_with_diagnostics<'db>( - &'db self, + fn impl_self_ty_with_diagnostics( + &self, def: ImplId, - ) -> (EarlyBinder<'db, Ty<'db>>, Diagnostics); + ) -> &TyLoweringResult<StoredEarlyBinder<StoredTy>>; #[salsa::invoke(crate::lower::impl_self_ty_query)] #[salsa::transparent] fn impl_self_ty<'db>(&'db self, def: ImplId) -> EarlyBinder<'db, Ty<'db>>; - #[salsa::invoke(crate::lower::const_param_ty_with_diagnostics)] + #[salsa::invoke(crate::lower::const_param_types_with_diagnostics)] #[salsa::transparent] - fn const_param_ty_with_diagnostics<'db>(&'db self, def: ConstParamId) - -> (Ty<'db>, Diagnostics); + fn const_param_types_with_diagnostics( + &self, + def: GenericDefId, + ) -> &TyLoweringResult<ArenaMap<LocalTypeOrConstParamId, StoredTy>>; - #[salsa::invoke(crate::lower::const_param_ty_query)] + #[salsa::invoke(crate::lower::const_param_types)] + #[salsa::transparent] + fn const_param_types(&self, def: GenericDefId) -> &ArenaMap<LocalTypeOrConstParamId, StoredTy>; + + #[salsa::invoke(crate::lower::const_param_ty)] #[salsa::transparent] fn const_param_ty<'db>(&'db self, def: ConstParamId) -> Ty<'db>; #[salsa::invoke(crate::lower::impl_trait_with_diagnostics)] #[salsa::transparent] - fn impl_trait_with_diagnostics<'db>( - &'db self, + fn impl_trait_with_diagnostics( + &self, def: ImplId, - ) -> Option<(EarlyBinder<'db, TraitRef<'db>>, Diagnostics)>; + ) -> &Option<TyLoweringResult<StoredEarlyBinder<StoredTraitRef>>>; #[salsa::invoke(crate::lower::impl_trait_query)] #[salsa::transparent] fn impl_trait<'db>(&'db self, def: ImplId) -> Option<EarlyBinder<'db, TraitRef<'db>>>; - #[salsa::invoke(crate::lower::field_types_with_diagnostics_query)] + #[salsa::invoke(crate::lower::field_types_with_diagnostics)] #[salsa::transparent] fn field_types_with_diagnostics( &self, var: VariantId, - ) -> &(ArenaMap<LocalFieldId, StoredEarlyBinder<StoredTy>>, Diagnostics); + ) -> &TyLoweringResult<ArenaMap<LocalFieldId, StoredEarlyBinder<StoredTy>>>; #[salsa::invoke(crate::lower::field_types_query)] #[salsa::transparent] @@ -198,23 +239,51 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug { def: CallableDefId, ) -> EarlyBinder<'db, PolyFnSig<'db>>; + #[salsa::invoke(crate::lower::callable_item_signature_with_diagnostics)] + #[salsa::transparent] + fn callable_item_signature_with_diagnostics( + &self, + def: CallableDefId, + ) -> &TyLoweringResult<StoredEarlyBinder<StoredPolyFnSig>>; + #[salsa::invoke(crate::lower::trait_environment)] #[salsa::transparent] fn trait_environment<'db>(&'db self, def: ExpressionStoreOwnerId) -> ParamEnv<'db>; - #[salsa::invoke(crate::lower::generic_defaults_with_diagnostics_query)] - #[salsa::cycle(cycle_result = crate::lower::generic_defaults_with_diagnostics_cycle_result)] + #[salsa::invoke(crate::lower::generic_defaults_with_diagnostics)] + #[salsa::transparent] fn generic_defaults_with_diagnostics( &self, def: GenericDefId, - ) -> (GenericDefaults, Diagnostics); + ) -> &TyLoweringResult<GenericDefaults>; /// This returns an empty list if no parameter has default. /// /// The binders of the returned defaults are only up to (not including) this parameter. - #[salsa::invoke(crate::lower::generic_defaults_query)] + #[salsa::invoke(crate::lower::generic_defaults)] + #[salsa::transparent] + fn generic_defaults(&self, def: GenericDefId) -> GenericDefaultsRef<'_>; + + #[salsa::invoke(crate::lower::type_alias_bounds_with_diagnostics)] + #[salsa::transparent] + fn type_alias_bounds_with_diagnostics( + &self, + type_alias: TypeAliasId, + ) -> &TyLoweringResult<TypeAliasBounds<StoredEarlyBinder<StoredClauses>>>; + + #[salsa::invoke(crate::lower::type_alias_bounds)] #[salsa::transparent] - fn generic_defaults(&self, def: GenericDefId) -> GenericDefaults; + fn type_alias_bounds<'db>( + &'db self, + type_alias: TypeAliasId, + ) -> EarlyBinder<'db, &'db [Clause<'db>]>; + + #[salsa::invoke(crate::lower::type_alias_self_bounds)] + #[salsa::transparent] + fn type_alias_self_bounds<'db>( + &'db self, + type_alias: TypeAliasId, + ) -> EarlyBinder<'db, &'db [Clause<'db>]>; // Interned IDs for solver integration #[salsa::interned] @@ -251,7 +320,7 @@ pub struct InternedOpaqueTyId { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct InternedClosure { - pub owner: ExpressionStoreOwnerId, + pub owner: InferBodyId, pub expr: ExprId, pub kind: ClosureKind, } @@ -266,7 +335,7 @@ impl InternedClosureId { #[inline] pub fn new(db: &dyn HirDatabase, loc: InternedClosure) -> Self { if cfg!(debug_assertions) { - let store = ExpressionStore::of(db, loc.owner); + let store = ExpressionStore::of(db, loc.owner.expression_store_owner(db)); let expr = &store[loc.expr]; assert!( matches!( @@ -294,7 +363,7 @@ impl InternedCoroutineId { #[inline] pub fn new(db: &dyn HirDatabase, loc: InternedClosure) -> Self { if cfg!(debug_assertions) { - let store = ExpressionStore::of(db, loc.owner); + let store = ExpressionStore::of(db, loc.owner.expression_store_owner(db)); let expr = &store[loc.expr]; assert!( matches!( @@ -323,7 +392,7 @@ impl InternedCoroutineClosureId { #[inline] pub fn new(db: &dyn HirDatabase, loc: InternedClosure) -> Self { if cfg!(debug_assertions) { - let store = ExpressionStore::of(db, loc.owner); + let store = ExpressionStore::of(db, loc.owner.expression_store_owner(db)); let expr = &store[loc.expr]; assert!( matches!( @@ -342,8 +411,8 @@ impl InternedCoroutineClosureId { } /// 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`. +/// const generic arguments like `{ N + 1 }`, or const param defaults). 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. @@ -351,9 +420,68 @@ pub struct AnonConstLoc { /// The ExprId within the owner's ExpressionStore that is the root /// of this anonymous const expression. pub expr: ExprId, - pub ty: StoredTy, + pub ty: StoredEarlyBinder<StoredTy>, + /// Whether to allow using generic params from the owner. + /// true for array repeats, false for everything else. + pub(crate) allow_using_generic_params: bool, +} + +#[salsa_macros::interned(debug, no_lifetime, revisions = usize::MAX)] +#[derive(PartialOrd, Ord)] +pub struct AnonConstId { + #[returns(ref)] + pub loc: AnonConstLoc, +} + +impl HasModule for AnonConstId { + fn module(&self, db: &dyn DefDatabase) -> ModuleId { + self.loc(db).owner.module(db) + } +} + +impl HasResolver for AnonConstId { + fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> { + self.loc(db).owner.resolver(db) + } +} + +impl AnonConstId { + pub fn all_from_signature( + db: &dyn HirDatabase, + def: GenericDefId, + ) -> ArrayVec<&[AnonConstId], 5> { + let mut result = ArrayVec::new(); + + // Queries common to all generic defs: + result.push(db.generic_defaults_with_diagnostics(def).defined_anon_consts()); + result.push(GenericPredicates::query_with_diagnostics(db, def).defined_anon_consts()); + result.push(db.const_param_types_with_diagnostics(def).defined_anon_consts()); + + match def { + GenericDefId::ImplId(id) => { + result.push(db.impl_self_ty_with_diagnostics(id).defined_anon_consts()); + if let Some(trait_ref) = db.impl_trait_with_diagnostics(id) { + result.push(trait_ref.defined_anon_consts()); + } + } + GenericDefId::TypeAliasId(id) => { + result.push(db.type_for_type_alias_with_diagnostics(id).defined_anon_consts()); + result.push(db.type_alias_bounds_with_diagnostics(id).defined_anon_consts()); + } + GenericDefId::FunctionId(id) => result + .push(db.callable_item_signature_with_diagnostics(id.into()).defined_anon_consts()), + GenericDefId::ConstId(def) => { + result.push(db.type_for_const_with_diagnostics(def).defined_anon_consts()) + } + GenericDefId::StaticId(def) => { + result.push(db.type_for_static_with_diagnostics(def).defined_anon_consts()) + } + GenericDefId::TraitId(_) | GenericDefId::AdtId(_) => {} + } + + result + } } -impl_intern_key!(AnonConstId, AnonConstLoc); /// A constant, which might appears as a const item, an anonymous const block in expressions /// or patterns, or as a constant in types with const generics. @@ -386,7 +514,7 @@ impl GeneralConstId { |name| name.display(db, Edition::CURRENT).to_string(), ) } - GeneralConstId::AnonConstId(_) => "{anon const}".to_owned(), + GeneralConstId::AnonConstId(_) => "{const}".to_owned(), } } } diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs index 7c80066b49..df8ea98dd0 100644 --- a/crates/hir-ty/src/display.rs +++ b/crates/hir-ty/src/display.rs @@ -22,8 +22,8 @@ use hir_def::{ item_tree::FieldsShape, lang_item::LangItems, signatures::{ - EnumSignature, FunctionSignature, StructSignature, TraitSignature, TypeAliasSignature, - UnionSignature, VariantFields, + ConstSignature, EnumSignature, FunctionSignature, StaticSignature, StructSignature, + TraitSignature, TypeAliasSignature, UnionSignature, VariantFields, }, type_ref::{ ConstRef, LifetimeRef, LifetimeRefId, TraitBoundModifier, TypeBound, TypeRef, TypeRefId, @@ -51,7 +51,7 @@ use stdx::never; use crate::{ CallableDefId, FnAbi, ImplTraitId, MemoryMap, ParamEnvAndCrate, consteval, - db::HirDatabase, + db::{GeneralConstId, HirDatabase}, generics::{ProvenanceSplit, generics}, layout::Layout, lower::GenericPredicates, @@ -749,7 +749,25 @@ impl<'db> HirDisplay<'db> for Const<'db> { ConstKind::Value(value) => render_const_scalar_from_valtree(f, value.ty, value.value), ConstKind::Unevaluated(unev) => { let c = unev.def.0; - write!(f, "{}", c.name(f.db))?; + match c { + GeneralConstId::ConstId(id) => match &ConstSignature::of(f.db, id).name { + Some(name) => { + f.start_location_link(id.into()); + write!(f, "{}", name.display(f.db, f.edition()))?; + f.end_location_link(); + } + None => f.write_str("_")?, + }, + GeneralConstId::StaticId(id) => { + let name = &StaticSignature::of(f.db, id).name; + f.start_location_link(id.into()); + write!(f, "{}", name.display(f.db, f.edition()))?; + f.end_location_link(); + } + GeneralConstId::AnonConstId(_) => { + f.write_str(if f.display_kind.is_source_code() { "_" } else { "{const}" })? + } + }; hir_fmt_generics(f, unev.args.as_slice(), c.generic_def(f.db), None)?; Ok(()) } diff --git a/crates/hir-ty/src/generics.rs b/crates/hir-ty/src/generics.rs index 32482ca94b..25a31e2f58 100644 --- a/crates/hir-ty/src/generics.rs +++ b/crates/hir-ty/src/generics.rs @@ -282,6 +282,18 @@ impl<'db> Generics<'db> { + u32::from(has_trait_self) + param.local_id.into_raw().into_u32() } + + #[deprecated = "don't use this; it's easy to expose an erroneous `Generics` with this"] + pub(crate) fn empty(def: GenericDefId) -> Self { + let mut chain = ArrayVec::new(); + chain.push(SingleGenerics { + def, + preceding_params_len: 0, + params: GenericParams::empty(), + store: ExpressionStore::empty(), + }); + Generics { chain } + } } pub(crate) struct ProvenanceSplit { diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs index d28ee4ab44..601aface61 100644 --- a/crates/hir-ty/src/infer.rs +++ b/crates/hir-ty/src/infer.rs @@ -29,22 +29,28 @@ mod path; mod place_op; pub(crate) mod unify; -use std::{cell::OnceCell, convert::identity, fmt, ops::Deref}; +use std::{ + cell::{OnceCell, RefCell}, + convert::identity, + fmt, + hash::Hash, + ops::Deref, +}; use base_db::{Crate, FxIndexMap}; use either::Either; use hir_def::{ - AdtId, AssocItemId, AttrDefId, ConstId, ConstParamId, DefWithBodyId, ExpressionStoreOwnerId, - FieldId, FunctionId, GenericDefId, GenericParamId, HasModule, LocalFieldId, Lookup, TraitId, - TupleFieldId, TupleId, TypeOrConstParamId, VariantId, + AdtId, AssocItemId, AttrDefId, ConstId, DefWithBodyId, ExpressionStoreOwnerId, FieldId, + FunctionId, GenericDefId, GenericParamId, HasModule, LocalFieldId, Lookup, StaticId, TraitId, + TupleFieldId, TupleId, VariantId, attrs::AttrFlags, - expr_store::{Body, ExpressionStore, HygieneId, RootExprOrigin, path::Path}, + expr_store::{Body, ExpressionStore, HygieneId, path::Path}, hir::{BindingId, ExprId, ExprOrPatId, LabelId, PatId}, lang_item::LangItems, layout::Integer, resolver::{HasResolver, ResolveValueResult, Resolver, TypeNs, ValueNs}, signatures::{ConstSignature, EnumSignature, FunctionSignature, StaticSignature}, - type_ref::{ConstRef, LifetimeRefId, TypeRef, TypeRefId}, + type_ref::{LifetimeRefId, TypeRef, TypeRefId}, unstable_features::UnstableFeatures, }; use hir_expand::{mod_path::ModPath, name::Name}; @@ -54,8 +60,8 @@ use macros::{TypeFoldable, TypeVisitable}; use rustc_ast_ir::Mutability; use rustc_hash::{FxHashMap, FxHashSet}; use rustc_type_ir::{ - AliasTyKind, TypeFoldable, - inherent::{Const as _, IntoKind, Ty as _}, + AliasTyKind, TypeFoldable, TypeVisitableExt, + inherent::{IntoKind, Ty as _}, }; use smallvec::SmallVec; use span::Edition; @@ -63,10 +69,13 @@ use stdx::never; use thin_vec::ThinVec; use crate::{ - ImplTraitId, IncorrectGenericsLenKind, PathLoweringDiagnostic, Span, TargetFeatures, + ImplTraitId, IncorrectGenericsLenKind, InferBodyId, PathLoweringDiagnostic, Span, + TargetFeatures, closure_analysis::PlaceBase, collect_type_inference_vars, - db::{HirDatabase, InternedOpaqueTyId}, + consteval::{create_anon_const, path_to_const}, + db::{AnonConstId, GeneralConstId, HirDatabase, InternedOpaqueTyId}, + generics::Generics, infer::{ callee::DeferredCallResolution, closure::analysis::{ @@ -84,8 +93,8 @@ use crate::{ }, method_resolution::CandidateId, next_solver::{ - AliasTy, Const, DbInterner, ErrorGuaranteed, GenericArgs, Region, StoredGenericArg, - StoredGenericArgs, StoredTy, StoredTys, Term, Ty, TyKind, Tys, + AliasTy, Const, ConstKind, DbInterner, ErrorGuaranteed, GenericArgs, Region, + StoredGenericArg, StoredGenericArgs, StoredTy, StoredTys, Term, Ty, TyKind, Tys, abi::Safety, infer::{InferCtxt, ObligationInspector, traits::ObligationCause}, }, @@ -116,8 +125,15 @@ pub fn infer_query_with_inspect<'db>( let _p = tracing::info_span!("infer_query").entered(); let resolver = def.resolver(db); let body = Body::of(db, def); - let mut ctx = - InferenceContext::new(db, ExpressionStoreOwnerId::Body(def), &body.store, resolver); + let mut ctx = InferenceContext::new( + db, + InferBodyId::DefWithBodyId(def), + ExpressionStoreOwnerId::Body(def), + def.generic_def(db), + &body.store, + resolver, + true, + ); if let Some(inspect) = inspect { ctx.table.infer_ctxt.attach_obligation_inspector(inspect); @@ -126,7 +142,7 @@ pub fn infer_query_with_inspect<'db>( match def { DefWithBodyId::FunctionId(f) => ctx.collect_fn(f, body.self_param, &body.params), DefWithBodyId::ConstId(c) => ctx.collect_const(c, ConstSignature::of(db, c)), - DefWithBodyId::StaticId(s) => ctx.collect_static(StaticSignature::of(db, s)), + DefWithBodyId::StaticId(s) => ctx.collect_static(s, StaticSignature::of(db, s)), DefWithBodyId::VariantId(v) => { ctx.return_ty = match EnumSignature::variant_body_type(db, v.lookup(db).parent) { hir_def::layout::IntegerType::Pointer(signed) => match signed { @@ -167,91 +183,38 @@ 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 = ExpressionStore::of(db, def.into()); - let mut roots = store.expr_roots_with_origins().peekable(); - let Some(_) = roots.peek() else { - return InferenceResult::new(crate::next_solver::default_types(db).types.error); - }; - - let resolver = def.resolver(db); - let owner = ExpressionStoreOwnerId::Signature(def); - - let mut ctx = InferenceContext::new(db, owner, store, resolver); - - for (root_expr, origin) in roots { - let expected = match origin { - // Array lengths are always `usize`. - RootExprOrigin::ArrayLength => Expectation::has_type(ctx.types.types.usize), - // Const parameter default: look up the param's declared type. - RootExprOrigin::ConstParam(local_id) => Expectation::has_type(db.const_param_ty( - ConstParamId::from_unchecked(TypeOrConstParamId { parent: def, local_id }), - )), - // Path const generic args: determining the expected type requires - // path resolution. - // FIXME - RootExprOrigin::GenericArgsPath => Expectation::None, - RootExprOrigin::BodyRoot => Expectation::None, - }; - ctx.infer_expr(root_expr, &expected, ExprIsRead::Yes); - } +/// Infer types for an anonymous const expression. +fn infer_anon_const_query(db: &dyn HirDatabase, def: AnonConstId) -> InferenceResult { + let _p = tracing::info_span!("infer_anon_const_query").entered(); + let loc = def.loc(db); + let store_owner = loc.owner; + let store = ExpressionStore::of(db, store_owner); + + let resolver = store_owner.resolver(db); + + let mut ctx = InferenceContext::new( + db, + InferBodyId::AnonConstId(def), + store_owner, + loc.owner.generic_def(db), + store, + resolver, + loc.allow_using_generic_params, + ); + + ctx.infer_expr( + loc.expr, + &Expectation::has_type(loc.ty.get().instantiate_identity()), + ExprIsRead::Yes, + ); infer_finalize(ctx) } -fn infer_variant_fields_query(db: &dyn HirDatabase, def: VariantId) -> InferenceResult { - let _p = tracing::info_span!("infer_variant_fields_query").entered(); - let store = ExpressionStore::of(db, def.into()); - let mut roots = store.expr_roots_with_origins().peekable(); - let Some(_) = roots.peek() else { - return InferenceResult::new(crate::next_solver::default_types(db).types.error); - }; - - let resolver = def.resolver(db); - let owner = ExpressionStoreOwnerId::VariantFields(def); - - let mut ctx = InferenceContext::new(db, owner, store, resolver); - - for (root_expr, origin) in roots { - let expected = match origin { - // Array lengths are always `usize`. - RootExprOrigin::ArrayLength => Expectation::has_type(ctx.types.types.usize), - // unreachable - RootExprOrigin::ConstParam(_) => Expectation::None, - // Path const generic args: determining the expected type requires - // path resolution. - // FIXME - RootExprOrigin::GenericArgsPath => Expectation::None, - RootExprOrigin::BodyRoot => Expectation::None, - }; - ctx.infer_expr(root_expr, &expected, ExprIsRead::Yes); - } - - infer_finalize(ctx) -} - -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)) - } -} - -fn infer_variant_fields_cycle_result( +fn infer_anon_const_cycle_result( db: &dyn HirDatabase, _: salsa::Id, - _: VariantId, + _: AnonConstId, ) -> InferenceResult { InferenceResult { has_errors: true, @@ -285,6 +248,8 @@ fn infer_finalize(mut ctx: InferenceContext<'_, '_>) -> InferenceResult { ctx.handle_opaque_type_uses(); + ctx.merge_anon_consts(); + ctx.resolve_all() } @@ -741,6 +706,8 @@ pub struct InferenceResult { pub(crate) coercion_casts: FxHashSet<ExprId>, pub closures_data: FxHashMap<ExprId, ClosureData>, + + defined_anon_consts: ThinVec<AnonConstId>, } #[derive(Clone, PartialEq, Eq, Debug, Default)] @@ -972,30 +939,21 @@ impl InferenceResult { /// 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)] - fn for_signature(db: &dyn HirDatabase, def: GenericDefId) -> InferenceResult { - infer_signature_query(db, def) + #[salsa::tracked(returns(ref), cycle_result = infer_anon_const_cycle_result)] + fn for_anon_const(db: &dyn HirDatabase, def: AnonConstId) -> InferenceResult { + infer_anon_const_query(db, def) } - #[salsa::tracked(returns(ref), cycle_result = infer_variant_fields_cycle_result)] - fn for_variant_fields(db: &dyn HirDatabase, def: VariantId) -> InferenceResult { - infer_variant_fields_query(db, def) - } -} - -impl InferenceResult { - pub fn of(db: &dyn HirDatabase, def: impl Into<ExpressionStoreOwnerId>) -> &InferenceResult { + #[inline] + pub fn of(db: &dyn HirDatabase, def: impl Into<InferBodyId>) -> &InferenceResult { match def.into() { - ExpressionStoreOwnerId::Signature(generic_def_id) => { - Self::for_signature(db, generic_def_id) - } - ExpressionStoreOwnerId::Body(def_with_body_id) => Self::for_body(db, def_with_body_id), - ExpressionStoreOwnerId::VariantFields(variant_id) => { - Self::for_variant_fields(db, variant_id) - } + InferBodyId::DefWithBodyId(it) => InferenceResult::for_body(db, it), + InferBodyId::AnonConstId(it) => InferenceResult::for_anon_const(db, it), } } +} +impl InferenceResult { fn new(error_ty: Ty<'_>) -> Self { Self { method_resolutions: Default::default(), @@ -1018,6 +976,7 @@ impl InferenceResult { expr_adjustments: Default::default(), coercion_casts: Default::default(), closures_data: Default::default(), + defined_anon_consts: Default::default(), } } @@ -1206,17 +1165,20 @@ impl InferenceResult { } /// The inference context contains all information needed during type inference. -#[derive(Clone, Debug)] +#[derive(Debug)] pub(crate) struct InferenceContext<'body, 'db> { pub(crate) db: &'db dyn HirDatabase, - pub(crate) owner: ExpressionStoreOwnerId, + pub(crate) owner: InferBodyId, + pub(crate) store_owner: ExpressionStoreOwnerId, + pub(crate) generic_def: GenericDefId, pub(crate) store: &'body ExpressionStore, /// 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. pub(crate) resolver: Resolver<'db>, target_features: OnceCell<(TargetFeatures<'db>, TargetFeatureIsSafeInTarget)>, pub(crate) edition: Edition, - pub(crate) generic_def: GenericDefId, + allow_using_generic_params: bool, + generics: OnceCell<Generics<'db>>, pub(crate) table: unify::InferenceTable<'db>, pub(crate) lang_items: &'db LangItems, pub(crate) features: &'db UnstableFeatures, @@ -1251,6 +1213,8 @@ pub(crate) struct InferenceContext<'body, 'db> { diagnostics: Diagnostics, vars_emitted_type_must_be_known_for: FxHashSet<Term<'db>>, + + defined_anon_consts: RefCell<ThinVec<AnonConstId>>, } #[derive(Clone, Debug)] @@ -1300,22 +1264,15 @@ fn find_continuable<'a, 'db>( impl<'body, 'db> InferenceContext<'body, 'db> { fn new( db: &'db dyn HirDatabase, - owner: ExpressionStoreOwnerId, + owner: InferBodyId, + store_owner: ExpressionStoreOwnerId, + generic_def: GenericDefId, store: &'body ExpressionStore, resolver: Resolver<'db>, + allow_using_generic_params: bool, ) -> Self { - let trait_env = match owner { - ExpressionStoreOwnerId::Signature(generic_def_id) => { - db.trait_environment(ExpressionStoreOwnerId::from(generic_def_id)) - } - ExpressionStoreOwnerId::Body(def_with_body_id) => { - db.trait_environment(ExpressionStoreOwnerId::Body(def_with_body_id)) - } - ExpressionStoreOwnerId::VariantFields(variant_id) => { - db.trait_environment(ExpressionStoreOwnerId::VariantFields(variant_id)) - } - }; - let table = unify::InferenceTable::new(db, trait_env, resolver.krate(), owner); + let trait_env = db.trait_environment(store_owner); + let table = unify::InferenceTable::new(db, trait_env, resolver.krate(), store_owner); let types = crate::next_solver::default_types(db); InferenceContext { result: InferenceResult::new(types.types.error), @@ -1331,7 +1288,10 @@ impl<'body, 'db> InferenceContext<'body, 'db> { return_coercion: None, db, owner, - generic_def: owner.generic_def(db), + store_owner, + generic_def, + allow_using_generic_params, + generics: OnceCell::new(), store, traits_in_scope: resolver.traits_in_scope(db), resolver, @@ -1342,6 +1302,97 @@ impl<'body, 'db> InferenceContext<'body, 'db> { diagnostics: Diagnostics::default(), vars_emitted_type_must_be_known_for: FxHashSet::default(), deferred_call_resolutions: FxHashMap::default(), + defined_anon_consts: RefCell::new(ThinVec::new()), + } + } + + fn merge(&mut self, other: &InferenceResult) { + let InferenceResult { + method_resolutions, + field_resolutions, + variant_resolutions, + assoc_resolutions, + tuple_field_access_types: _, + type_of_expr, + type_of_pat, + type_of_binding, + type_of_type_placeholder, + type_of_opaque, + has_errors: _, + diagnostics: _, + error_ty: _, + expr_adjustments, + pat_adjustments, + binding_modes, + skipped_ref_pats, + coercion_casts, + closures_data, + nodes_with_type_mismatches, + defined_anon_consts: _, + } = &mut self.result; + merge_hash_maps(method_resolutions, &other.method_resolutions); + merge_hash_maps(variant_resolutions, &other.variant_resolutions); + merge_hash_maps(assoc_resolutions, &other.assoc_resolutions); + field_resolutions.extend(other.field_resolutions.iter().map( + |(&field_expr, &field_resolution)| { + let mut field_resolution = field_resolution; + if let Either::Right(tuple_field) = &mut field_resolution { + let tys = other.tuple_field_access_type(tuple_field.tuple); + tuple_field.tuple = + TupleId(self.tuple_field_accesses_rev.insert_full(tys).0 as u32); + }; + (field_expr, field_resolution) + }, + )); + merge_arena_maps(type_of_expr, &other.type_of_expr); + merge_arena_maps(type_of_pat, &other.type_of_pat); + merge_arena_maps(type_of_binding, &other.type_of_binding); + merge_hash_maps(type_of_type_placeholder, &other.type_of_type_placeholder); + merge_hash_maps(type_of_opaque, &other.type_of_opaque); + merge_hash_maps(expr_adjustments, &other.expr_adjustments); + merge_hash_maps(pat_adjustments, &other.pat_adjustments); + merge_arena_maps(binding_modes, &other.binding_modes); + merge_hash_set(skipped_ref_pats, &other.skipped_ref_pats); + merge_hash_set(coercion_casts, &other.coercion_casts); + merge_hash_maps(closures_data, &other.closures_data); + if let Some(other_nodes_with_type_mismatches) = &other.nodes_with_type_mismatches { + merge_hash_set( + nodes_with_type_mismatches.get_or_insert_default(), + other_nodes_with_type_mismatches, + ); + } + self.defined_anon_consts.borrow_mut().extend(other.defined_anon_consts.iter().copied()); + + fn merge_hash_set<T: Hash + Eq + Clone>(dest: &mut FxHashSet<T>, source: &FxHashSet<T>) { + dest.extend(source.iter().cloned()); + } + + #[cfg_attr(debug_assertions, track_caller)] + fn merge_hash_maps<K: Hash + Eq + Clone, V: Clone + PartialEq>( + dest: &mut FxHashMap<K, V>, + source: &FxHashMap<K, V>, + ) { + if cfg!(debug_assertions) { + for (key, src) in source { + assert!(dest.get(key).is_none_or(|dst| dst == src)); + } + } + + dest.extend(source.iter().map(|(k, v)| (k.clone(), v.clone()))); + } + + #[cfg_attr(debug_assertions, track_caller)] + fn merge_arena_maps<K, V: Clone + PartialEq>( + dest: &mut ArenaMap<la_arena::Idx<K>, V>, + source: &ArenaMap<la_arena::Idx<K>, V>, + ) { + if cfg!(debug_assertions) { + for (key, src) in source.iter() { + assert!(dest.get(key).is_none_or(|dst| dst == src)); + } + } + + dest.extend(source.iter().map(|(k, v)| (k, v.clone()))); } } @@ -1352,7 +1403,7 @@ 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 { + let target_features = match self.store_owner { ExpressionStoreOwnerId::Body(DefWithBodyId::FunctionId(id)) => { TargetFeatures::from_fn(self.db, id) } @@ -1372,26 +1423,22 @@ impl<'body, 'db> InferenceContext<'body, 'db> { self.result.has_errors = true; } - /// Clones `self` and calls `resolve_all()` on it. - // FIXME: Remove this. - pub(crate) fn fixme_resolve_all_clone(&self) -> InferenceResult { - let mut ctx = self.clone(); - - ctx.type_inference_fallback(); - - // Comment from rustc: - // Even though coercion casts provide type hints, we check casts after fallback for - // backwards compatibility. This makes fallback a stronger type hint than a cast coercion. - let cast_checks = std::mem::take(&mut ctx.deferred_cast_checks); - for mut cast in cast_checks.into_iter() { - if let Err(diag) = cast.check(&mut ctx) { - ctx.diagnostics.push(diag); + /// Copy the inference of defined anon consts to ourselves, so that we don't need to lookup the defining + /// anon const when looking the type of something. + fn merge_anon_consts(&mut self) { + let mut defined_anon_consts = std::mem::take(&mut *self.defined_anon_consts.borrow_mut()); + defined_anon_consts.retain(|&konst| { + if konst.loc(self.db).owner != self.store_owner { + // This comes from the signature, we don't define it. + return false; } - } - ctx.table.select_obligations_where_possible(); - - ctx.resolve_all() + let const_infer = InferenceResult::of(self.db, konst); + self.merge(const_infer); + true + }); + // Caution, other defined anon consts might have been added by `merge()`! + self.defined_anon_consts.borrow_mut().append(&mut defined_anon_consts); } // FIXME: This function should be private in module. It is currently only used in the consteval, since we need @@ -1432,7 +1479,12 @@ impl<'body, 'db> InferenceContext<'body, 'db> { coercion_casts: _, diagnostics: result_diagnostics, nodes_with_type_mismatches, + defined_anon_consts: result_defined_anon_consts, } = &mut result; + + *result_defined_anon_consts = self.defined_anon_consts.into_inner(); + result_defined_anon_consts.shrink_to_fit(); + let mut resolver = WriteBackCtxt::new(table, diagnostics, vars_emitted_type_must_be_known_for); @@ -1531,6 +1583,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { data.type_ref, &data.store, InferenceTyDiagnosticSource::Signature, + ExpressionStoreOwnerId::Signature(id.into()), LifetimeElisionKind::for_const(self.interner(), id.loc(self.db).container), Span::Dummy, ); @@ -1538,11 +1591,12 @@ impl<'body, 'db> InferenceContext<'body, 'db> { self.return_ty = return_ty; } - fn collect_static(&mut self, data: &StaticSignature) { + fn collect_static(&mut self, id: StaticId, data: &StaticSignature) { let return_ty = self.make_ty( data.type_ref, &data.store, InferenceTyDiagnosticSource::Signature, + ExpressionStoreOwnerId::Signature(id.into()), LifetimeElisionKind::Elided(self.types.regions.statik), Span::Dummy, ); @@ -1555,6 +1609,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { let mut param_tys = self.with_ty_lowering( &data.store, InferenceTyDiagnosticSource::Signature, + ExpressionStoreOwnerId::Signature(func.into()), LifetimeElisionKind::for_fn_params(data), |ctx| data.params.iter().map(|&type_ref| ctx.lower_ty(type_ref)).collect::<Vec<_>>(), ); @@ -1595,6 +1650,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { let return_ty = self.with_ty_lowering( &data.store, InferenceTyDiagnosticSource::Signature, + ExpressionStoreOwnerId::Signature(func.into()), LifetimeElisionKind::for_fn_ret(self.interner()), |ctx| { ctx.impl_trait_mode(ImplTraitLoweringMode::Opaque); @@ -1646,10 +1702,6 @@ impl<'body, 'db> InferenceContext<'body, 'db> { } } - pub(super) fn insert_const_vars_shallow(&mut self, c: Const<'db>) -> Const<'db> { - if c.is_ct_error() { self.table.next_const_var(Span::Dummy) } else { c } - } - fn infer_body(&mut self, body_expr: ExprId) { match self.return_coercion { Some(_) => self.infer_return(body_expr), @@ -1750,6 +1802,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { &mut self, store: &ExpressionStore, types_source: InferenceTyDiagnosticSource, + store_owner: ExpressionStoreOwnerId, lifetime_elision: LifetimeElisionKind<'db>, f: impl FnOnce(&mut TyLoweringContext<'db, '_>) -> R, ) -> R { @@ -1759,8 +1812,11 @@ impl<'body, 'db> InferenceContext<'body, 'db> { store, &self.diagnostics, types_source, + store_owner, self.generic_def, lifetime_elision, + self.allow_using_generic_params, + &self.defined_anon_consts, ); f(&mut ctx) } @@ -1772,6 +1828,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { self.with_ty_lowering( self.store, InferenceTyDiagnosticSource::Body, + self.store_owner, LifetimeElisionKind::Infer, f, ) @@ -1782,11 +1839,13 @@ impl<'body, 'db> InferenceContext<'body, 'db> { type_ref: TypeRefId, store: &ExpressionStore, type_source: InferenceTyDiagnosticSource, + store_owner: ExpressionStoreOwnerId, lifetime_elision: LifetimeElisionKind<'db>, span: Span, ) -> Ty<'db> { - let ty = self - .with_ty_lowering(store, type_source, lifetime_elision, |ctx| ctx.lower_ty(type_ref)); + let ty = self.with_ty_lowering(store, type_source, store_owner, lifetime_elision, |ctx| { + ctx.lower_ty(type_ref) + }); let ty = self.process_user_written_ty(span, ty); // Record the association from placeholders' TypeRefId to type variables. @@ -1813,34 +1872,54 @@ impl<'body, 'db> InferenceContext<'body, 'db> { type_ref, self.store, InferenceTyDiagnosticSource::Body, + self.store_owner, LifetimeElisionKind::Infer, type_ref.into(), ) } - pub(crate) fn make_body_const(&mut self, const_ref: ConstRef, ty: Ty<'db>) -> Const<'db> { - let const_ = self.with_ty_lowering( - self.store, - InferenceTyDiagnosticSource::Body, - LifetimeElisionKind::Infer, - |ctx| ctx.lower_const(const_ref, ty), - ); - self.insert_type_vars(const_, const_ref.expr.into()) + fn generics(&self) -> &Generics<'db> { + self.generics.get_or_init(|| { + crate::generics::generics(self.db, self.store_owner.generic_def(self.db)) + }) } - pub(crate) fn make_path_as_body_const( + pub(crate) fn create_body_anon_const( &mut self, - type_ref: TypeRefId, - path: &Path, - ty: Ty<'db>, + expr: ExprId, + expected_ty: Ty<'db>, + allow_using_generic_params: bool, ) -> Const<'db> { - let const_ = self.with_ty_lowering( + never!(expected_ty.has_infer(), "cannot have infer vars in an anon const's ty"); + let konst = create_anon_const( + self.interner(), + self.store_owner, self.store, - InferenceTyDiagnosticSource::Body, - LifetimeElisionKind::Infer, - |ctx| ctx.lower_path_as_const(path, ty), + expr, + &self.resolver, + expected_ty, + &|| self.generics(), + Some(self.infcx()), + (!(allow_using_generic_params && self.allow_using_generic_params)).then_some(0), ); - self.insert_type_vars(const_, type_ref.into()) + + if let Ok(konst) = konst + && let ConstKind::Unevaluated(konst) = konst.kind() + && let GeneralConstId::AnonConstId(konst) = konst.def.0 + { + self.defined_anon_consts.borrow_mut().push(konst); + } + + self.write_expr_ty(expr, expected_ty); + // FIXME: Report an error if needed. + konst.unwrap_or_else(|_| self.table.next_const_var(Span::Dummy)) + } + + pub(crate) fn make_path_as_body_const(&mut self, path: &Path) -> Const<'db> { + let forbid_params_after = if self.allow_using_generic_params { None } else { Some(0) }; + // FIXME: Report errors. + path_to_const(self.db, &self.resolver, &|| self.generics(), forbid_params_after, path) + .unwrap_or_else(|_| self.table.next_const_var(Span::Dummy)) } fn err_ty(&self) -> Ty<'db> { @@ -1851,6 +1930,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> { let lt = self.with_ty_lowering( self.store, InferenceTyDiagnosticSource::Body, + self.store_owner, LifetimeElisionKind::Infer, |ctx| ctx.lower_lifetime(lifetime_ref), ); @@ -2074,8 +2154,11 @@ impl<'body, 'db> InferenceContext<'body, 'db> { self.store, &self.diagnostics, InferenceTyDiagnosticSource::Body, + self.store_owner, self.generic_def, LifetimeElisionKind::Infer, + self.allow_using_generic_params, + &self.defined_anon_consts, ); if let Some(type_anchor) = path.type_anchor() { @@ -2523,7 +2606,7 @@ impl<'db> Expectation<'db> { Expectation::None } - fn resolve(&self, table: &mut unify::InferenceTable<'db>) -> Expectation<'db> { + fn resolve(&self, table: &unify::InferenceTable<'db>) -> Expectation<'db> { match self { Expectation::None => Expectation::None, Expectation::HasType(t) => Expectation::HasType(table.shallow_resolve(*t)), @@ -2534,7 +2617,7 @@ impl<'db> Expectation<'db> { } } - fn to_option(&self, table: &mut unify::InferenceTable<'db>) -> Option<Ty<'db>> { + fn to_option(&self, table: &unify::InferenceTable<'db>) -> Option<Ty<'db>> { match self.resolve(table) { Expectation::None => None, Expectation::HasType(t) diff --git a/crates/hir-ty/src/infer/closure.rs b/crates/hir-ty/src/infer/closure.rs index 2679efca7d..0e55bb8e26 100644 --- a/crates/hir-ty/src/infer/closure.rs +++ b/crates/hir-ty/src/infer/closure.rs @@ -78,7 +78,7 @@ impl<'db> InferenceContext<'_, 'db> { // It's always helpful for inference if we know the kind of // closure sooner rather than later, so first examine the expected // type, and see if can glean a closure kind from there. - let (expected_sig, expected_kind) = match expected.to_option(&mut self.table) { + let (expected_sig, expected_kind) = match expected.to_option(&self.table) { Some(ty) => { let ty = self.table.try_structurally_resolve_type(closure_expr.into(), ty); self.deduce_closure_signature(closure_expr, ty, closure_kind) @@ -97,7 +97,7 @@ impl<'db> InferenceContext<'_, 'db> { debug!(?bound_sig, ?liberated_sig); - let parent_args = GenericArgs::identity_for_item(interner, self.generic_def.into()); + let parent_args = GenericArgs::identity_for_item(interner, self.store_owner.into()); let tupled_upvars_ty = self.table.next_ty_var(closure_expr.into()); diff --git a/crates/hir-ty/src/infer/closure/analysis.rs b/crates/hir-ty/src/infer/closure/analysis.rs index 979551f316..bd88644a3c 100644 --- a/crates/hir-ty/src/infer/closure/analysis.rs +++ b/crates/hir-ty/src/infer/closure/analysis.rs @@ -195,7 +195,7 @@ type InferredCaptureInformation = Vec<(Place, CaptureInfo)>; impl<'a, 'db> InferenceContext<'a, 'db> { pub(crate) fn closure_analyze(&mut self) { - let upvars = crate::upvars::upvars_mentioned(self.db, self.owner) + let upvars = crate::upvars::upvars_mentioned(self.db, self.store_owner) .unwrap_or(const { &FxHashMap::with_hasher(FxBuildHasher) }); for root_expr in self.store.expr_roots() { self.analyze_closures_in_expr(root_expr, upvars); @@ -329,7 +329,8 @@ impl<'a, 'db> InferenceContext<'a, 'db> { let Expr::Path(path) = &self.store[init] else { panic!(); }; - let update_guard = self.resolver.update_to_inner_scope(self.db, self.owner, init); + let update_guard = + self.resolver.update_to_inner_scope(self.db, self.store_owner, init); let Some(ValueNs::LocalBinding(local_id)) = self.resolver.resolve_path_in_value_ns_fully( self.db, diff --git a/crates/hir-ty/src/infer/closure/analysis/expr_use_visitor.rs b/crates/hir-ty/src/infer/closure/analysis/expr_use_visitor.rs index 44dc1a63d1..be0fb30f40 100644 --- a/crates/hir-ty/src/infer/closure/analysis/expr_use_visitor.rs +++ b/crates/hir-ty/src/infer/closure/analysis/expr_use_visitor.rs @@ -655,7 +655,7 @@ impl<'a, 'b, 'db, D: Delegate<'db>> ExprUseVisitor<'a, 'b, 'db, D> { self.walk_expr(value)?; let expr_place = self.cat_expr(value)?; let update_guard = - self.cx.resolver.update_to_inner_scope(self.cx.db, self.cx.owner, expr); + self.cx.resolver.update_to_inner_scope(self.cx.db, self.cx.store_owner, expr); self.walk_pat(expr_place, target, false)?; self.cx.resolver.reset_to_guard(update_guard); } @@ -1308,7 +1308,7 @@ impl<'db, D: Delegate<'db>> ExprUseVisitor<'_, '_, 'db, D> { Expr::Path(ref path) => { let resolver_guard = - self.cx.resolver.update_to_inner_scope(self.cx.db, self.cx.owner, expr); + self.cx.resolver.update_to_inner_scope(self.cx.db, self.cx.store_owner, expr); let resolution = self.cx.resolver.resolve_path_in_value_ns_fully( self.cx.db, path, diff --git a/crates/hir-ty/src/infer/coerce.rs b/crates/hir-ty/src/infer/coerce.rs index e5767c2d46..a2b584e1d6 100644 --- a/crates/hir-ty/src/infer/coerce.rs +++ b/crates/hir-ty/src/infer/coerce.rs @@ -1598,7 +1598,7 @@ fn coerce<'db>( fn is_capturing_closure(db: &dyn HirDatabase, closure: InternedClosureId) -> bool { let InternedClosure { owner, expr, .. } = closure.loc(db); - upvars_mentioned(db, owner) + upvars_mentioned(db, owner.expression_store_owner(db)) .is_some_and(|upvars| upvars.get(&expr).is_some_and(|upvars| !upvars.is_empty())) } diff --git a/crates/hir-ty/src/infer/diagnostics.rs b/crates/hir-ty/src/infer/diagnostics.rs index 2bdc6f9491..71aa35e634 100644 --- a/crates/hir-ty/src/infer/diagnostics.rs +++ b/crates/hir-ty/src/infer/diagnostics.rs @@ -6,18 +6,20 @@ use std::cell::RefCell; use std::ops::{Deref, DerefMut}; use either::Either; -use hir_def::GenericDefId; use hir_def::expr_store::ExpressionStore; use hir_def::expr_store::path::Path; +use hir_def::{ExpressionStoreOwnerId, GenericDefId}; use hir_def::{hir::ExprOrPatId, resolver::Resolver}; use la_arena::{Idx, RawIdx}; use thin_vec::ThinVec; use crate::{ InferenceDiagnostic, InferenceTyDiagnosticSource, TyLoweringDiagnostic, - db::HirDatabase, - lower::path::{PathDiagnosticCallback, PathLoweringContext}, - lower::{LifetimeElisionKind, TyLoweringContext}, + db::{AnonConstId, HirDatabase}, + lower::{ + ForbidParamsAfterReason, LifetimeElisionKind, TyLoweringContext, + path::{PathDiagnosticCallback, PathLoweringContext}, + }, }; // Unfortunately, this struct needs to use interior mutability (but we encapsulate it) @@ -35,7 +37,7 @@ impl Diagnostics { fn push_ty_diagnostics( &self, source: InferenceTyDiagnosticSource, - diagnostics: Vec<TyLoweringDiagnostic>, + diagnostics: ThinVec<TyLoweringDiagnostic>, ) { self.0.borrow_mut().extend( diagnostics.into_iter().map(|diag| InferenceDiagnostic::TyDiagnostic { source, diag }), @@ -56,6 +58,7 @@ pub(super) struct InferenceTyLoweringContext<'db, 'a> { ctx: TyLoweringContext<'db, 'a>, diagnostics: &'a Diagnostics, source: InferenceTyDiagnosticSource, + defined_anon_consts: &'a RefCell<ThinVec<AnonConstId>>, } impl<'db, 'a> InferenceTyLoweringContext<'db, 'a> { @@ -66,14 +69,18 @@ impl<'db, 'a> InferenceTyLoweringContext<'db, 'a> { store: &'a ExpressionStore, diagnostics: &'a Diagnostics, source: InferenceTyDiagnosticSource, + def: ExpressionStoreOwnerId, generic_def: GenericDefId, lifetime_elision: LifetimeElisionKind<'db>, + allow_using_generic_params: bool, + defined_anon_consts: &'a RefCell<ThinVec<AnonConstId>>, ) -> Self { - Self { - ctx: TyLoweringContext::new(db, resolver, store, generic_def, lifetime_elision), - diagnostics, - source, + let mut ctx = + TyLoweringContext::new(db, resolver, store, def, generic_def, lifetime_elision); + if !allow_using_generic_params { + ctx.forbid_params_after(0, ForbidParamsAfterReason::AnonConst); } + Self { ctx, diagnostics, source, defined_anon_consts } } #[inline] @@ -135,5 +142,6 @@ impl Drop for InferenceTyLoweringContext<'_, '_> { fn drop(&mut self) { self.diagnostics .push_ty_diagnostics(self.source, std::mem::take(&mut self.ctx.diagnostics)); + self.defined_anon_consts.borrow_mut().extend(self.ctx.defined_anon_consts.iter().copied()); } } diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs index b1e983f274..3613cf7cea 100644 --- a/crates/hir-ty/src/infer/expr.rs +++ b/crates/hir-ty/src/infer/expr.rs @@ -8,8 +8,7 @@ use hir_def::{ expr_store::path::{GenericArgs as HirGenericArgs, Path}, hir::{ Array, AsmOperand, AsmOptions, BinaryOp, BindingAnnotation, Expr, ExprId, ExprOrPatId, - InlineAsmKind, LabelId, Literal, Pat, PatId, RecordLitField, RecordSpread, Statement, - UnaryOp, + InlineAsmKind, LabelId, Pat, PatId, RecordLitField, RecordSpread, Statement, UnaryOp, }, resolver::ValueNs, signatures::VariantFields, @@ -27,7 +26,8 @@ use syntax::ast::RangeOp; use tracing::debug; use crate::{ - Adjust, Adjustment, CallableDefId, Rawness, Span, consteval, + Adjust, Adjustment, CallableDefId, Rawness, Span, + consteval::literal_ty, infer::{AllowTwoPhase, BreakableKind, coerce::CoerceMany, find_continuable, pat::PatOrigin}, lower::lower_mutability, method_resolution::{self, CandidateId, MethodCallee, MethodError}, @@ -647,7 +647,7 @@ impl<'db> InferenceContext<'_, 'db> { } else { let rhs_ty = self.infer_expr(value, &Expectation::none(), ExprIsRead::Yes); let resolver_guard = - self.resolver.update_to_inner_scope(self.db, self.owner, tgt_expr); + self.resolver.update_to_inner_scope(self.db, self.store_owner, tgt_expr); self.inside_assignment = true; self.infer_top_pat(target, rhs_ty, PatOrigin::DestructuringAssignment); self.inside_assignment = false; @@ -757,106 +757,45 @@ impl<'db> InferenceContext<'_, 'db> { Expr::Array(Array::Repeat { initializer, repeat }) => { self.infer_array_repeat_expr(*initializer, *repeat, expected, tgt_expr) } - Expr::Literal(lit) => match lit { - Literal::Bool(..) => self.types.types.bool, - Literal::String(..) => self.types.types.static_str_ref, - Literal::ByteString(bs) => { - let byte_type = self.types.types.u8; - - let len = consteval::usize_const( - self.db, - Some(bs.len() as u128), - self.resolver.krate(), - ); - - let array_type = Ty::new_array_with_const_len(self.interner(), byte_type, len); - Ty::new_ref( - self.interner(), - self.types.regions.statik, - array_type, - Mutability::Not, - ) - } - Literal::CString(..) => Ty::new_ref( - self.interner(), - self.types.regions.statik, - self.lang_items.CStr.map_or_else( - || self.err_ty(), - |strukt| { - Ty::new_adt( - self.interner(), - strukt.into(), - self.types.empty.generic_args, - ) - }, - ), - Mutability::Not, - ), - Literal::Char(..) => self.types.types.char, - Literal::Int(_v, ty) => match ty { - Some(int_ty) => match int_ty { - hir_def::builtin_type::BuiltinInt::Isize => self.types.types.isize, - hir_def::builtin_type::BuiltinInt::I8 => self.types.types.i8, - hir_def::builtin_type::BuiltinInt::I16 => self.types.types.i16, - hir_def::builtin_type::BuiltinInt::I32 => self.types.types.i32, - hir_def::builtin_type::BuiltinInt::I64 => self.types.types.i64, - hir_def::builtin_type::BuiltinInt::I128 => self.types.types.i128, - }, - None => { - let expected_ty = expected.to_option(&mut self.table); - tracing::debug!(?expected_ty); - let opt_ty = match expected_ty.as_ref().map(|it| it.kind()) { - Some(TyKind::Int(_) | TyKind::Uint(_)) => expected_ty, - Some(TyKind::Char) => Some(self.types.types.u8), - Some(TyKind::RawPtr(..) | TyKind::FnDef(..) | TyKind::FnPtr(..)) => { - Some(self.types.types.usize) - } - _ => None, - }; - opt_ty.unwrap_or_else(|| self.table.next_int_var()) - } + Expr::Literal(lit) => literal_ty( + self.interner(), + lit, + |_| { + let expected_ty = expected.to_option(&self.table); + tracing::debug!(?expected_ty); + let opt_ty = match expected_ty.as_ref().map(|it| it.kind()) { + Some(TyKind::Int(_) | TyKind::Uint(_)) => expected_ty, + Some(TyKind::Char) => Some(self.types.types.u8), + Some(TyKind::RawPtr(..) | TyKind::FnDef(..) | TyKind::FnPtr(..)) => { + Some(self.types.types.usize) + } + _ => None, + }; + opt_ty.unwrap_or_else(|| self.table.next_int_var()) }, - Literal::Uint(_v, ty) => match ty { - Some(int_ty) => match int_ty { - hir_def::builtin_type::BuiltinUint::Usize => self.types.types.usize, - hir_def::builtin_type::BuiltinUint::U8 => self.types.types.u8, - hir_def::builtin_type::BuiltinUint::U16 => self.types.types.u16, - hir_def::builtin_type::BuiltinUint::U32 => self.types.types.u32, - hir_def::builtin_type::BuiltinUint::U64 => self.types.types.u64, - hir_def::builtin_type::BuiltinUint::U128 => self.types.types.u128, - }, - None => { - let expected_ty = expected.to_option(&mut self.table); - let opt_ty = match expected_ty.as_ref().map(|it| it.kind()) { - Some(TyKind::Int(_) | TyKind::Uint(_)) => expected_ty, - Some(TyKind::Char) => Some(self.types.types.u8), - Some(TyKind::RawPtr(..) | TyKind::FnDef(..) | TyKind::FnPtr(..)) => { - Some(self.types.types.usize) - } - _ => None, - }; - opt_ty.unwrap_or_else(|| self.table.next_int_var()) - } + |_| { + let expected_ty = expected.to_option(&self.table); + let opt_ty = match expected_ty.as_ref().map(|it| it.kind()) { + Some(TyKind::Int(_) | TyKind::Uint(_)) => expected_ty, + Some(TyKind::Char) => Some(self.types.types.u8), + Some(TyKind::RawPtr(..) | TyKind::FnDef(..) | TyKind::FnPtr(..)) => { + Some(self.types.types.usize) + } + _ => None, + }; + opt_ty.unwrap_or_else(|| self.table.next_int_var()) }, - Literal::Float(_v, ty) => match ty { - Some(float_ty) => match float_ty { - hir_def::builtin_type::BuiltinFloat::F16 => self.types.types.f16, - hir_def::builtin_type::BuiltinFloat::F32 => self.types.types.f32, - hir_def::builtin_type::BuiltinFloat::F64 => self.types.types.f64, - hir_def::builtin_type::BuiltinFloat::F128 => self.types.types.f128, - }, - None => { - let opt_ty = expected - .to_option(&mut self.table) - .filter(|ty| matches!(ty.kind(), TyKind::Float(_))); - opt_ty.unwrap_or_else(|| self.table.next_float_var()) - } + |_| { + let opt_ty = expected + .to_option(&self.table) + .filter(|ty| matches!(ty.kind(), TyKind::Float(_))); + opt_ty.unwrap_or_else(|| self.table.next_float_var()) }, - }, + ), Expr::Underscore => { // Underscore expression is an error, we render a specialized diagnostic // to let the user know what type is expected though. - let expected = expected.to_option(&mut self.table).unwrap_or_else(|| self.err_ty()); + let expected = expected.to_option(&self.table).unwrap_or_else(|| self.err_ty()); self.push_diagnostic(InferenceDiagnostic::TypedHole { expr: tgt_expr, expected: expected.store(), @@ -1312,7 +1251,7 @@ impl<'db> InferenceContext<'_, 'db> { } fn infer_expr_path(&mut self, path: &Path, id: ExprOrPatId, scope_id: ExprId) -> Ty<'db> { - let g = self.resolver.update_to_inner_scope(self.db, self.owner, scope_id); + let g = self.resolver.update_to_inner_scope(self.db, self.store_owner, scope_id); let ty = match self.infer_path(path, id) { Some((_, ty)) => ty, None => { @@ -1376,19 +1315,8 @@ impl<'db> InferenceContext<'_, 'db> { expr: ExprId, ) -> Ty<'db> { let interner = self.interner(); - let usize = self.types.types.usize; - let count_ct = match self.store[count] { - Expr::Underscore => { - self.write_expr_ty(count, usize); - self.table.next_const_var(count.into()) - } - _ => { - self.infer_expr(count, &Expectation::HasType(usize), ExprIsRead::Yes); - consteval::eval_to_const(count, self) - } - }; + let count_ct = self.create_body_anon_const(count, self.types.types.usize, true); let count = self.table.try_structurally_resolve_const(count.into(), count_ct); - let count = self.insert_const_vars_shallow(count); let uty = match expected { Expectation::HasType(uty) => uty.builtin_index(), @@ -1426,7 +1354,7 @@ impl<'db> InferenceContext<'_, 'db> { ) -> Ty<'db> { let element_ty = if !args.is_empty() { let coerce_to = expected - .to_option(&mut self.table) + .to_option(&self.table) .and_then(|uty| { self.table .resolve_vars_with_obligations(uty) @@ -1554,7 +1482,7 @@ impl<'db> InferenceContext<'_, 'db> { expected: &Expectation<'db>, ) -> Ty<'db> { let coerce_ty = expected.coercion_target_type(&mut self.table, expr.into()); - let g = self.resolver.update_to_inner_scope(self.db, self.owner, expr); + let g = self.resolver.update_to_inner_scope(self.db, self.store_owner, expr); let (break_ty, ty) = self.with_breakable_ctx(BreakableKind::Block, Some(coerce_ty), label, |this| { diff --git a/crates/hir-ty/src/infer/path.rs b/crates/hir-ty/src/infer/path.rs index 4df38e96ee..c9262ce12e 100644 --- a/crates/hir-ty/src/infer/path.rs +++ b/crates/hir-ty/src/infer/path.rs @@ -145,8 +145,11 @@ impl<'db> InferenceContext<'_, 'db> { self.store, &self.diagnostics, InferenceTyDiagnosticSource::Body, + self.store_owner, self.generic_def, LifetimeElisionKind::Infer, + self.allow_using_generic_params, + &self.defined_anon_consts, ); let mut path_ctx = if no_diagnostics { ctx.at_path_forget_diagnostics(path) diff --git a/crates/hir-ty/src/infer/unify.rs b/crates/hir-ty/src/infer/unify.rs index bb6e383e7d..33311412bf 100644 --- a/crates/hir-ty/src/infer/unify.rs +++ b/crates/hir-ty/src/infer/unify.rs @@ -128,7 +128,6 @@ fn could_unify_impl<'db>( can_unify && select(&mut ctxt).is_empty() } -#[derive(Clone)] pub(crate) struct InferenceTable<'db> { pub(crate) db: &'db dyn HirDatabase, pub(crate) param_env: ParamEnv<'db>, diff --git a/crates/hir-ty/src/layout/tests.rs b/crates/hir-ty/src/layout/tests.rs index 484ecebba5..97c572c4e6 100644 --- a/crates/hir-ty/src/layout/tests.rs +++ b/crates/hir-ty/src/layout/tests.rs @@ -565,8 +565,6 @@ fn const_eval_simple() { } #[test] -// FIXME -#[should_panic] fn const_eval_complex() { size_and_align! { struct Goal([i32; 2 + 2]); diff --git a/crates/hir-ty/src/lib.rs b/crates/hir-ty/src/lib.rs index 0c107460fa..094e5b623c 100644 --- a/crates/hir-ty/src/lib.rs +++ b/crates/hir-ty/src/lib.rs @@ -62,10 +62,13 @@ mod tests; use std::{hash::Hash, ops::ControlFlow}; use hir_def::{ - CallableDefId, ExpressionStoreOwnerId, GenericDefId, LifetimeParamId, TypeAliasId, - TypeOrConstParamId, TypeParamId, + CallableDefId, ConstId, DefWithBodyId, EnumVariantId, ExpressionStoreOwnerId, FunctionId, + GenericDefId, HasModule, LifetimeParamId, ModuleId, StaticId, TypeAliasId, TypeOrConstParamId, + TypeParamId, + db::DefDatabase, + expr_store::{Body, ExpressionStore}, hir::{BindingId, ExprId, ExprOrPatId, PatId}, - resolver::TypeNs, + resolver::{HasResolver, Resolver, TypeNs}, type_ref::{Rawness, TypeRefId}, }; use hir_expand::name::Name; @@ -83,8 +86,8 @@ use syntax::ast::{ConstArg, make}; use traits::FnTrait; use crate::{ - db::HirDatabase, - display::{DisplayTarget, HirDisplay}, + db::{AnonConstId, HirDatabase}, + display::HirDisplay, lower::SupertraitsInfo, next_solver::{ AliasTy, Binder, BoundConst, BoundRegion, BoundRegionKind, BoundTy, BoundTyKind, Canonical, @@ -106,8 +109,8 @@ pub use infer::{ could_unify, could_unify_deeply, infer_query_with_inspect, }; pub use lower::{ - GenericPredicates, ImplTraits, LifetimeElisionKind, TyDefId, TyLoweringContext, ValueTyDefId, - diagnostics::*, + GenericDefaults, GenericDefaultsRef, GenericPredicates, ImplTraits, LifetimeElisionKind, + TyDefId, TyLoweringContext, TyLoweringResult, ValueTyDefId, diagnostics::*, }; pub use next_solver::interner::{attach_db, attach_db_allow_change, with_attached_db}; pub use target_feature::TargetFeatures; @@ -662,9 +665,11 @@ where pub fn known_const_to_ast<'db>( konst: Const<'db>, db: &'db dyn HirDatabase, - display_target: DisplayTarget, + target_module: ModuleId, ) -> Option<ConstArg> { - Some(make::expr_const_value(konst.display(db, display_target).to_string().as_str())) + Some(make::expr_const_value( + &konst.display_source_code(db, target_module, true).unwrap_or_else(|_| "_".to_owned()), + )) } /// A `Span` represents some location in lowered code - a type, expression or pattern. @@ -704,6 +709,83 @@ impl Span { } } +/// A [`DefWithBodyId`], or an anon const. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, salsa::Supertype)] +pub enum InferBodyId { + DefWithBodyId(DefWithBodyId), + AnonConstId(AnonConstId), +} +impl_from!(DefWithBodyId(FunctionId, ConstId, StaticId), AnonConstId for InferBodyId); +impl From<EnumVariantId> for InferBodyId { + fn from(id: EnumVariantId) -> Self { + InferBodyId::DefWithBodyId(DefWithBodyId::VariantId(id)) + } +} + +impl HasModule for InferBodyId { + fn module(&self, db: &dyn DefDatabase) -> ModuleId { + match self { + InferBodyId::DefWithBodyId(id) => id.module(db), + InferBodyId::AnonConstId(id) => id.module(db), + } + } +} + +impl HasResolver for InferBodyId { + fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> { + match self { + InferBodyId::DefWithBodyId(id) => id.resolver(db), + InferBodyId::AnonConstId(id) => id.resolver(db), + } + } +} + +impl InferBodyId { + pub fn expression_store_owner(self, db: &dyn HirDatabase) -> ExpressionStoreOwnerId { + match self { + InferBodyId::DefWithBodyId(id) => id.into(), + InferBodyId::AnonConstId(id) => id.loc(db).owner, + } + } + + pub fn generic_def(self, db: &dyn HirDatabase) -> GenericDefId { + match self { + InferBodyId::DefWithBodyId(id) => id.generic_def(db), + InferBodyId::AnonConstId(id) => id.loc(db).owner.generic_def(db), + } + } + + #[inline] + pub fn as_function(self) -> Option<FunctionId> { + match self { + InferBodyId::DefWithBodyId(DefWithBodyId::FunctionId(it)) => Some(it), + _ => None, + } + } + + #[inline] + pub fn as_variant(self) -> Option<EnumVariantId> { + match self { + InferBodyId::DefWithBodyId(DefWithBodyId::VariantId(it)) => Some(it), + _ => None, + } + } + + pub fn store_and_root_expr(self, db: &dyn HirDatabase) -> (&ExpressionStore, ExprId) { + match self { + InferBodyId::DefWithBodyId(id) => { + let body = Body::of(db, id); + (body, body.root_expr()) + } + InferBodyId::AnonConstId(id) => { + let loc = id.loc(db); + let store = ExpressionStore::of(db, loc.owner); + (store, loc.expr) + } + } + } +} + pub fn setup_tracing() -> Option<tracing::subscriber::DefaultGuard> { use std::env; use std::sync::LazyLock; diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs index 49807cc6c0..dbbe31971e 100644 --- a/crates/hir-ty/src/lower.rs +++ b/crates/hir-ty/src/lower.rs @@ -8,7 +8,7 @@ pub(crate) mod diagnostics; pub(crate) mod path; -use std::{cell::OnceCell, iter, mem}; +use std::{cell::OnceCell, iter, mem, sync::OnceLock}; use either::Either; use hir_def::{ @@ -17,14 +17,14 @@ use hir_def::{ ItemContainerId, LifetimeParamId, LocalFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId, VariantId, builtin_type::BuiltinType, - expr_store::{ExpressionStore, HygieneId, path::Path}, + expr_store::{ExpressionStore, path::Path}, hir::generics::{ - GenericParamDataRef, GenericParams, TypeOrConstParamData, TypeParamProvenance, - WherePredicate, + GenericParamDataRef, GenericParams, LocalTypeOrConstParamId, TypeOrConstParamData, + TypeParamProvenance, WherePredicate, }, item_tree::FieldsShape, lang_item::LangItems, - resolver::{HasResolver, LifetimeNs, Resolver, TypeNs, ValueNs}, + resolver::{HasResolver, LifetimeNs, Resolver, TypeNs}, signatures::{ ConstSignature, FunctionSignature, ImplSignature, StaticSignature, StructSignature, TraitFlags, TraitSignature, TypeAliasFlags, TypeAliasSignature, @@ -40,27 +40,27 @@ use path::{PathDiagnosticCallback, PathLoweringContext}; use rustc_ast_ir::Mutability; use rustc_hash::FxHashSet; use rustc_type_ir::{ - AliasTyKind, BoundVarIndexKind, ConstKind, DebruijnIndex, ExistentialPredicate, - ExistentialProjection, ExistentialTraitRef, FnSig, Interner, OutlivesPredicate, TermKind, - TyKind, TypeFoldable, TypeVisitableExt, Upcast, UpcastFrom, elaborate, + AliasTyKind, BoundVarIndexKind, DebruijnIndex, ExistentialPredicate, ExistentialProjection, + ExistentialTraitRef, FnSig, Interner, OutlivesPredicate, TermKind, TyKind, TypeFoldable, + TypeVisitableExt, Upcast, UpcastFrom, elaborate, inherent::{Clause as _, GenericArgs as _, IntoKind as _, Region as _, Ty as _}, }; use smallvec::SmallVec; use stdx::{impl_from, never}; +use thin_vec::ThinVec; use tracing::debug; -use triomphe::{Arc, ThinArc}; use crate::{ FnAbi, ImplTraitId, TyLoweringDiagnostic, TyLoweringDiagnosticKind, - consteval::intern_const_ref, - db::{GeneralConstId, HirDatabase, InternedOpaqueTyId}, + consteval::{create_anon_const, path_to_const}, + db::{AnonConstId, GeneralConstId, HirDatabase, InternedOpaqueTyId}, generics::{Generics, SingleGenerics, generics}, next_solver::{ - AliasTy, Binder, BoundExistentialPredicates, Clause, ClauseKind, Clauses, Const, + AliasTy, Binder, BoundExistentialPredicates, Clause, ClauseKind, Clauses, Const, ConstKind, DbInterner, EarlyBinder, EarlyParamRegion, ErrorGuaranteed, FxIndexMap, GenericArg, GenericArgs, ParamConst, ParamEnv, PolyFnSig, Predicate, Region, SolverDefId, StoredClauses, StoredEarlyBinder, StoredGenericArg, StoredGenericArgs, StoredPolyFnSig, - StoredTy, TraitPredicate, TraitRef, Ty, Tys, UnevaluatedConst, abi::Safety, + StoredTraitRef, StoredTy, TraitPredicate, TraitRef, Ty, Tys, abi::Safety, util::BottomUpFolder, }, }; @@ -171,6 +171,18 @@ pub(crate) enum GenericPredicateSource { AssocTyBound, } +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub(crate) enum ForbidParamsAfterReason { + /// When lowering generic param defaults, you cannot refer to any param after + /// the currently lowered param, including the current param. + LoweringParamDefault, + /// Most anon const (except array repeat expressions) cannot refer to any generic + /// param. + AnonConst, + /// The type of a const param cannot refer to a type param. + ConstParamTy, +} + #[derive(Debug)] pub struct TyLoweringContext<'db, 'a> { pub db: &'db dyn HirDatabase, @@ -179,17 +191,18 @@ pub struct TyLoweringContext<'db, 'a> { lang_items: &'db LangItems, resolver: &'a Resolver<'db>, store: &'a ExpressionStore, - def: GenericDefId, + def: ExpressionStoreOwnerId, + generic_def: GenericDefId, generics: OnceCell<Generics<'db>>, in_binders: DebruijnIndex, impl_trait_mode: ImplTraitLoweringState, /// Tracks types with explicit `?Sized` bounds. pub(crate) unsized_types: FxHashSet<Ty<'db>>, - pub(crate) diagnostics: Vec<TyLoweringDiagnostic>, + pub(crate) diagnostics: ThinVec<TyLoweringDiagnostic>, lifetime_elision: LifetimeElisionKind<'db>, - /// When lowering the defaults for generic params, this contains the index of the currently lowered param. - /// We disallow referring to later params, or to ADT's `Self`. - lowering_param_default: Option<u32>, + forbid_params_after: Option<u32>, + forbid_params_after_reason: ForbidParamsAfterReason, + pub(crate) defined_anon_consts: ThinVec<AnonConstId>, } impl<'db, 'a> TyLoweringContext<'db, 'a> { @@ -197,7 +210,8 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { db: &'db dyn HirDatabase, resolver: &'a Resolver<'db>, store: &'a ExpressionStore, - def: GenericDefId, + def: ExpressionStoreOwnerId, + generic_def: GenericDefId, lifetime_elision: LifetimeElisionKind<'db>, ) -> Self { let impl_trait_mode = ImplTraitLoweringState::new(ImplTraitLoweringMode::Disallowed); @@ -211,14 +225,17 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { lang_items: interner.lang_items(), resolver, def, + generic_def, generics: Default::default(), store, in_binders, impl_trait_mode, unsized_types: FxHashSet::default(), - diagnostics: Vec::new(), + diagnostics: ThinVec::new(), lifetime_elision, - lowering_param_default: None, + forbid_params_after: None, + forbid_params_after_reason: ForbidParamsAfterReason::AnonConst, + defined_anon_consts: ThinVec::new(), } } @@ -254,8 +271,9 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { self } - pub(crate) fn lowering_param_default(&mut self, index: u32) { - self.lowering_param_default = Some(index); + pub(crate) fn forbid_params_after(&mut self, index: u32, reason: ForbidParamsAfterReason) { + self.forbid_params_after = Some(index); + self.forbid_params_after_reason = reason; } pub(crate) fn push_diagnostic(&mut self, type_ref: TypeRefId, kind: TyLoweringDiagnosticKind) { @@ -281,128 +299,45 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { } pub(crate) fn lower_const(&mut self, const_ref: ConstRef, const_type: Ty<'db>) -> Const<'db> { - 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()) - } - hir_def::hir::Expr::UnaryOp { expr: inner_expr, op: hir_def::hir::UnaryOp::Neg } => { - if let hir_def::hir::Expr::Literal(literal) = &self.store[*inner_expr] { - // Only handle negation for signed integers and floats - match literal { - hir_def::hir::Literal::Int(_, _) | hir_def::hir::Literal::Float(_, _) => { - if let Some(negated_literal) = literal.clone().negate() { - intern_const_ref( - self.db, - &negated_literal, - const_type, - self.resolver.krate(), - ) - } else { - Const::new(self.interner, ConstKind::Error(ErrorGuaranteed)) - } - } - // For unsigned integers, chars, bools, etc., negation is not meaningful - _ => Const::new(self.interner, ConstKind::Error(ErrorGuaranteed)), - } - } else { - // Complex negation expression (e.g. `-N` where N is a const param) - self.lower_const_as_unevaluated(expr_id, 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), - } - } + let konst = create_anon_const( + self.interner, + self.def, + self.store, + const_ref.expr, + self.resolver, + const_type, + &|| self.generics(), + None, + self.forbid_params_after, + ); - /// 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)) => { - let args = self.generics(); - let idx = args.type_or_const_param_idx(p.into()); - Some(self.const_param(p, idx)) - } - Some(ValueNs::ConstId(c)) => { - let args = GenericArgs::empty(self.interner); - Some(Const::new( - self.interner, - rustc_type_ir::ConstKind::Unevaluated(UnevaluatedConst::new( - GeneralConstId::ConstId(c).into(), - args, - )), - )) - } - _ => None, + if let Ok(konst) = konst + && let ConstKind::Unevaluated(konst) = konst.kind() + && let GeneralConstId::AnonConstId(konst) = konst.def.0 + { + self.defined_anon_consts.push(konst); } + + konst.unwrap_or({ + // FIXME: Report an error. + self.types.consts.error + }) } - pub(crate) fn lower_path_as_const(&mut self, path: &Path, const_type: Ty<'db>) -> Const<'db> { - self.path_to_const(path).unwrap_or_else(|| unknown_const(const_type)) + pub(crate) fn lower_path_as_const(&mut self, path: &Path, _const_type: Ty<'db>) -> Const<'db> { + path_to_const(self.db, self.resolver, &|| self.generics(), self.forbid_params_after, path) + .unwrap_or({ + // FIXME: Report an error. + self.types.consts.error + }) } fn generics(&self) -> &Generics<'db> { - self.generics.get_or_init(|| generics(self.db, self.def)) + self.generics.get_or_init(|| generics(self.db, self.generic_def)) } fn param_index_is_disallowed(&self, index: u32) -> bool { - self.lowering_param_default - .is_some_and(|disallow_params_after| index >= disallow_params_after) + self.forbid_params_after.is_some_and(|disallow_params_after| index >= disallow_params_after) } fn type_param(&mut self, id: TypeParamId, index: u32) -> Ty<'db> { @@ -414,15 +349,6 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { } } - fn const_param(&mut self, id: ConstParamId, index: u32) -> Const<'db> { - if self.param_index_is_disallowed(index) { - // FIXME: Report an error. - Const::error(self.interner) - } else { - Const::new_param(self.interner, ParamConst { id, index }) - } - } - fn region_param(&mut self, id: LifetimeParamId, index: u32) -> Region<'db> { if self.param_index_is_disallowed(index) { // FIXME: Report an error. @@ -1091,6 +1017,69 @@ impl<'db, 'a> TyLoweringContext<'db, 'a> { } } +#[derive(Clone, PartialEq, Eq)] +pub struct TyLoweringResult<T> { + pub value: T, + info: Option<Box<(ThinVec<TyLoweringDiagnostic>, ThinVec<AnonConstId>)>>, +} + +impl<T: std::fmt::Debug> std::fmt::Debug for TyLoweringResult<T> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let mut debug = f.debug_struct("TyLoweringResult"); + debug.field("value", &self.value); + let diagnostics = self.diagnostics(); + if !diagnostics.is_empty() { + debug.field("diagnostics", &diagnostics); + } + let defined_anon_consts = self.defined_anon_consts(); + if !defined_anon_consts.is_empty() { + debug.field("defined_anon_consts", &defined_anon_consts); + } + debug.finish() + } +} + +impl<T> TyLoweringResult<T> { + fn new( + value: T, + mut diagnostics: ThinVec<TyLoweringDiagnostic>, + mut defined_anon_consts: ThinVec<AnonConstId>, + ) -> Self { + let info = if diagnostics.is_empty() && defined_anon_consts.is_empty() { + None + } else { + diagnostics.shrink_to_fit(); + defined_anon_consts.shrink_to_fit(); + Some(Box::new((diagnostics, defined_anon_consts))) + }; + Self { value, info } + } + + fn from_ctx(value: T, ctx: TyLoweringContext<'_, '_>) -> Self { + Self::new(value, ctx.diagnostics, ctx.defined_anon_consts) + } + + fn empty(value: T) -> Self { + Self { value, info: None } + } + + #[inline] + pub fn diagnostics(&self) -> &[TyLoweringDiagnostic] { + match &self.info { + Some(info) => &info.0, + None => &[], + } + } + + #[inline] + pub fn defined_anon_consts(&self) -> &[AnonConstId] { + match &self.info { + Some(info) => &info.1, + None => &[], + } + } +} + fn dyn_trait_dummy_self(interner: DbInterner<'_>) -> Ty<'_> { // This type must not appear anywhere except here. Ty::new_fresh(interner, 0) @@ -1118,62 +1107,34 @@ pub(crate) fn lower_mutability(m: hir_def::type_ref::Mutability) -> Mutability { } } -fn unknown_const(_ty: Ty<'_>) -> Const<'_> { - Const::new(DbInterner::conjure(), ConstKind::Error(ErrorGuaranteed)) -} - -pub(crate) type Diagnostics = Option<ThinArc<(), TyLoweringDiagnostic>>; - -pub(crate) fn create_diagnostics(diagnostics: Vec<TyLoweringDiagnostic>) -> Diagnostics { - (!diagnostics.is_empty()).then(|| ThinArc::from_header_and_iter((), diagnostics.into_iter())) -} - pub(crate) fn impl_trait_query<'db>( db: &'db dyn HirDatabase, impl_id: ImplId, ) -> Option<EarlyBinder<'db, TraitRef<'db>>> { - db.impl_trait_with_diagnostics(impl_id).map(|it| it.0) + impl_trait_with_diagnostics(db, impl_id) + .as_ref() + .map(|it| it.value.get(DbInterner::new_no_crate(db))) } -pub(crate) fn impl_trait_with_diagnostics<'db>( - db: &'db dyn HirDatabase, +#[salsa::tracked(returns(ref))] +pub(crate) fn impl_trait_with_diagnostics( + db: &dyn HirDatabase, impl_id: ImplId, -) -> Option<(EarlyBinder<'db, TraitRef<'db>>, Diagnostics)> { - return impl_trait_with_diagnostics_query(db, impl_id).as_ref().map(|(binder, diags)| { - ( - binder.get_with(|(trait_id, args)| { - TraitRef::new_from_args( - DbInterner::new_no_crate(db), - (*trait_id).into(), - args.as_ref(), - ) - }), - diags.clone(), - ) - }); - - #[salsa::tracked(returns(ref))] - pub(crate) fn impl_trait_with_diagnostics_query( - db: &dyn HirDatabase, - impl_id: ImplId, - ) -> Option<(StoredEarlyBinder<(TraitId, StoredGenericArgs)>, Diagnostics)> { - let impl_data = ImplSignature::of(db, impl_id); - let resolver = impl_id.resolver(db); - let mut ctx = TyLoweringContext::new( - db, - &resolver, - &impl_data.store, - impl_id.into(), - LifetimeElisionKind::AnonymousCreateParameter { report_in_path: true }, - ); - let self_ty = db.impl_self_ty(impl_id).skip_binder(); - let target_trait = impl_data.target_trait.as_ref()?; - let trait_ref = ctx.lower_trait_ref(target_trait, self_ty)?; - Some(( - StoredEarlyBinder::bind((trait_ref.def_id.0, trait_ref.args.store())), - create_diagnostics(ctx.diagnostics), - )) - } +) -> Option<TyLoweringResult<StoredEarlyBinder<StoredTraitRef>>> { + let impl_data = ImplSignature::of(db, impl_id); + let resolver = impl_id.resolver(db); + let mut ctx = TyLoweringContext::new( + db, + &resolver, + &impl_data.store, + ExpressionStoreOwnerId::Signature(impl_id.into()), + impl_id.into(), + LifetimeElisionKind::AnonymousCreateParameter { report_in_path: true }, + ); + let self_ty = db.impl_self_ty(impl_id).skip_binder(); + let target_trait = impl_data.target_trait.as_ref()?; + let trait_ref = ctx.lower_trait_ref(target_trait, self_ty)?; + Some(TyLoweringResult::from_ctx(StoredEarlyBinder::bind(StoredTraitRef::new(trait_ref)), ctx)) } impl ImplTraitId { @@ -1248,6 +1209,7 @@ impl ImplTraits { db, &resolver, &data.store, + ExpressionStoreOwnerId::Signature(def.into()), def.into(), LifetimeElisionKind::Infer, ) @@ -1276,6 +1238,7 @@ impl ImplTraits { db, &resolver, &data.store, + ExpressionStoreOwnerId::Signature(def.into()), def.into(), LifetimeElisionKind::AnonymousReportError, ) @@ -1339,26 +1302,34 @@ pub(crate) fn ty_query<'db>(db: &'db dyn HirDatabase, def: TyDefId) -> EarlyBind it, GenericArgs::identity_for_item(interner, it.into()), )), - TyDefId::TypeAliasId(it) => db.type_for_type_alias_with_diagnostics(it).0, + TyDefId::TypeAliasId(it) => db.type_for_type_alias_with_diagnostics(it).value.get(), } } /// Build the declared type of a function. This should not need to look at the /// function body. -fn type_for_fn(db: &dyn HirDatabase, def: FunctionId) -> StoredEarlyBinder<StoredTy> { +fn type_for_fn<'db>(db: &'db dyn HirDatabase, def: FunctionId) -> EarlyBinder<'db, Ty<'db>> { let interner = DbInterner::new_no_crate(db); - StoredEarlyBinder::bind( - Ty::new_fn_def( - interner, - CallableDefId::FunctionId(def).into(), - GenericArgs::identity_for_item(interner, def.into()), - ) - .store(), - ) + EarlyBinder::bind(Ty::new_fn_def( + interner, + CallableDefId::FunctionId(def).into(), + GenericArgs::identity_for_item(interner, def.into()), + )) +} + +pub(crate) fn type_for_const<'db>( + db: &'db dyn HirDatabase, + def: ConstId, +) -> EarlyBinder<'db, Ty<'db>> { + type_for_const_with_diagnostics(db, def).value.get() } /// Build the declared type of a const. -fn type_for_const(db: &dyn HirDatabase, def: ConstId) -> StoredEarlyBinder<StoredTy> { +#[salsa_macros::tracked(returns(ref))] +pub(crate) fn type_for_const_with_diagnostics( + db: &dyn HirDatabase, + def: ConstId, +) -> TyLoweringResult<StoredEarlyBinder<StoredTy>> { let resolver = def.resolver(db); let data = ConstSignature::of(db, def); let parent = def.loc(db).container; @@ -1366,70 +1337,79 @@ fn type_for_const(db: &dyn HirDatabase, def: ConstId) -> StoredEarlyBinder<Store db, &resolver, &data.store, + ExpressionStoreOwnerId::Signature(def.into()), def.into(), LifetimeElisionKind::AnonymousReportError, ); ctx.set_lifetime_elision(LifetimeElisionKind::for_const(ctx.interner, parent)); - StoredEarlyBinder::bind(ctx.lower_ty(data.type_ref).store()) + let result = StoredEarlyBinder::bind(ctx.lower_ty(data.type_ref).store()); + TyLoweringResult::from_ctx(result, ctx) +} + +pub(crate) fn type_for_static<'db>( + db: &'db dyn HirDatabase, + def: StaticId, +) -> EarlyBinder<'db, Ty<'db>> { + type_for_static_with_diagnostics(db, def).value.get() } /// Build the declared type of a static. -fn type_for_static(db: &dyn HirDatabase, def: StaticId) -> StoredEarlyBinder<StoredTy> { +#[salsa_macros::tracked(returns(ref))] +pub(crate) fn type_for_static_with_diagnostics( + db: &dyn HirDatabase, + def: StaticId, +) -> TyLoweringResult<StoredEarlyBinder<StoredTy>> { let resolver = def.resolver(db); let data = StaticSignature::of(db, def); let mut ctx = TyLoweringContext::new( db, &resolver, &data.store, + ExpressionStoreOwnerId::Signature(def.into()), def.into(), LifetimeElisionKind::AnonymousReportError, ); ctx.set_lifetime_elision(LifetimeElisionKind::Elided(Region::new_static(ctx.interner))); - StoredEarlyBinder::bind(ctx.lower_ty(data.type_ref).store()) + let result = StoredEarlyBinder::bind(ctx.lower_ty(data.type_ref).store()); + TyLoweringResult::from_ctx(result, ctx) } /// Build the type of a tuple struct constructor. -fn type_for_struct_constructor( - db: &dyn HirDatabase, +fn type_for_struct_constructor<'db>( + db: &'db dyn HirDatabase, def: StructId, -) -> Option<StoredEarlyBinder<StoredTy>> { +) -> Option<EarlyBinder<'db, Ty<'db>>> { let struct_data = StructSignature::of(db, def); match struct_data.shape { FieldsShape::Record => None, FieldsShape::Unit => Some(type_for_adt(db, def.into())), FieldsShape::Tuple => { let interner = DbInterner::new_no_crate(db); - Some(StoredEarlyBinder::bind( - Ty::new_fn_def( - interner, - CallableDefId::StructId(def).into(), - GenericArgs::identity_for_item(interner, def.into()), - ) - .store(), - )) + Some(EarlyBinder::bind(Ty::new_fn_def( + interner, + CallableDefId::StructId(def).into(), + GenericArgs::identity_for_item(interner, def.into()), + ))) } } } /// Build the type of a tuple enum variant constructor. -fn type_for_enum_variant_constructor( - db: &dyn HirDatabase, +fn type_for_enum_variant_constructor<'db>( + db: &'db dyn HirDatabase, def: EnumVariantId, -) -> Option<StoredEarlyBinder<StoredTy>> { +) -> Option<EarlyBinder<'db, Ty<'db>>> { let struct_data = def.fields(db); match struct_data.shape { FieldsShape::Record => None, FieldsShape::Unit => Some(type_for_adt(db, def.loc(db).parent.into())), FieldsShape::Tuple => { let interner = DbInterner::new_no_crate(db); - Some(StoredEarlyBinder::bind( - Ty::new_fn_def( - interner, - CallableDefId::EnumVariantId(def).into(), - GenericArgs::identity_for_item(interner, def.loc(db).parent.into()), - ) - .store(), - )) + Some(EarlyBinder::bind(Ty::new_fn_def( + interner, + CallableDefId::EnumVariantId(def).into(), + GenericArgs::identity_for_item(interner, def.loc(db).parent.into()), + ))) } } } @@ -1438,197 +1418,166 @@ pub(crate) fn value_ty<'db>( db: &'db dyn HirDatabase, def: ValueTyDefId, ) -> Option<EarlyBinder<'db, Ty<'db>>> { - return value_ty_query(db, def).as_ref().map(|it| it.get()); - - #[salsa::tracked(returns(ref))] - pub(crate) fn value_ty_query( - db: &dyn HirDatabase, - def: ValueTyDefId, - ) -> Option<StoredEarlyBinder<StoredTy>> { - match def { - ValueTyDefId::FunctionId(it) => Some(type_for_fn(db, it)), - ValueTyDefId::StructId(it) => type_for_struct_constructor(db, it), - ValueTyDefId::UnionId(it) => Some(type_for_adt(db, it.into())), - ValueTyDefId::EnumVariantId(it) => type_for_enum_variant_constructor(db, it), - ValueTyDefId::ConstId(it) => Some(type_for_const(db, it)), - ValueTyDefId::StaticId(it) => Some(type_for_static(db, it)), - } + match def { + ValueTyDefId::FunctionId(it) => Some(type_for_fn(db, it)), + ValueTyDefId::StructId(it) => type_for_struct_constructor(db, it), + ValueTyDefId::UnionId(it) => Some(type_for_adt(db, it.into())), + ValueTyDefId::EnumVariantId(it) => type_for_enum_variant_constructor(db, it), + ValueTyDefId::ConstId(it) => Some(type_for_const(db, it)), + ValueTyDefId::StaticId(it) => Some(type_for_static(db, it)), } } -pub(crate) fn type_for_type_alias_with_diagnostics<'db>( - db: &'db dyn HirDatabase, +#[salsa::tracked(returns(ref), cycle_result = type_for_type_alias_with_diagnostics_cycle_result)] +pub(crate) fn type_for_type_alias_with_diagnostics( + db: &dyn HirDatabase, t: TypeAliasId, -) -> (EarlyBinder<'db, Ty<'db>>, Diagnostics) { - let (ty, diags) = type_for_type_alias_with_diagnostics_query(db, t); - return (ty.get(), diags.clone()); - - #[salsa::tracked(returns(ref), cycle_result = type_for_type_alias_with_diagnostics_cycle_result)] - pub(crate) fn type_for_type_alias_with_diagnostics_query( - db: &dyn HirDatabase, - t: TypeAliasId, - ) -> (StoredEarlyBinder<StoredTy>, Diagnostics) { - let type_alias_data = TypeAliasSignature::of(db, t); - let mut diags = None; - let resolver = t.resolver(db); - let interner = DbInterner::new_no_crate(db); - let inner = if type_alias_data.flags.contains(TypeAliasFlags::IS_EXTERN) { - StoredEarlyBinder::bind(Ty::new_foreign(interner, t.into()).store()) - } else { - let mut ctx = TyLoweringContext::new( - db, - &resolver, - &type_alias_data.store, - t.into(), - LifetimeElisionKind::AnonymousReportError, - ) - .with_impl_trait_mode(ImplTraitLoweringMode::Opaque); - let res = StoredEarlyBinder::bind( - type_alias_data - .ty - .map(|type_ref| ctx.lower_ty(type_ref)) - .unwrap_or_else(|| Ty::new_error(interner, ErrorGuaranteed)) - .store(), - ); - diags = create_diagnostics(ctx.diagnostics); - res - }; - (inner, diags) - } - - pub(crate) fn type_for_type_alias_with_diagnostics_cycle_result( - db: &dyn HirDatabase, - _: salsa::Id, - _adt: TypeAliasId, - ) -> (StoredEarlyBinder<StoredTy>, Diagnostics) { - ( - StoredEarlyBinder::bind( - Ty::new_error(DbInterner::new_no_crate(db), ErrorGuaranteed).store(), - ), - None, +) -> TyLoweringResult<StoredEarlyBinder<StoredTy>> { + let type_alias_data = TypeAliasSignature::of(db, t); + let resolver = t.resolver(db); + let interner = DbInterner::new_no_crate(db); + if type_alias_data.flags.contains(TypeAliasFlags::IS_EXTERN) { + TyLoweringResult::empty(StoredEarlyBinder::bind( + Ty::new_foreign(interner, t.into()).store(), + )) + } else { + let mut ctx = TyLoweringContext::new( + db, + &resolver, + &type_alias_data.store, + ExpressionStoreOwnerId::Signature(t.into()), + t.into(), + LifetimeElisionKind::AnonymousReportError, ) + .with_impl_trait_mode(ImplTraitLoweringMode::Opaque); + let res = StoredEarlyBinder::bind( + type_alias_data + .ty + .map(|type_ref| ctx.lower_ty(type_ref)) + .unwrap_or_else(|| Ty::new_error(interner, ErrorGuaranteed)) + .store(), + ); + TyLoweringResult::from_ctx(res, ctx) } } +pub(crate) fn type_for_type_alias_with_diagnostics_cycle_result( + db: &dyn HirDatabase, + _: salsa::Id, + _adt: TypeAliasId, +) -> TyLoweringResult<StoredEarlyBinder<StoredTy>> { + TyLoweringResult::empty(StoredEarlyBinder::bind( + Ty::new_error(DbInterner::new_no_crate(db), ErrorGuaranteed).store(), + )) +} + pub(crate) fn impl_self_ty_query<'db>( db: &'db dyn HirDatabase, impl_id: ImplId, ) -> EarlyBinder<'db, Ty<'db>> { - db.impl_self_ty_with_diagnostics(impl_id).0 + impl_self_ty_with_diagnostics(db, impl_id).value.get() } -pub(crate) fn impl_self_ty_with_diagnostics<'db>( - db: &'db dyn HirDatabase, +#[salsa::tracked(returns(ref), cycle_result = impl_self_ty_with_diagnostics_cycle_result)] +pub(crate) fn impl_self_ty_with_diagnostics( + db: &dyn HirDatabase, impl_id: ImplId, -) -> (EarlyBinder<'db, Ty<'db>>, Diagnostics) { - let (ty, diags) = impl_self_ty_with_diagnostics_query(db, impl_id); - return (ty.get(), diags.clone()); +) -> TyLoweringResult<StoredEarlyBinder<StoredTy>> { + let resolver = impl_id.resolver(db); - #[salsa::tracked(returns(ref), cycle_result = impl_self_ty_with_diagnostics_cycle_result)] - pub(crate) fn impl_self_ty_with_diagnostics_query( - db: &dyn HirDatabase, - impl_id: ImplId, - ) -> (StoredEarlyBinder<StoredTy>, Diagnostics) { - let resolver = impl_id.resolver(db); + let impl_data = ImplSignature::of(db, impl_id); + let mut ctx = TyLoweringContext::new( + db, + &resolver, + &impl_data.store, + ExpressionStoreOwnerId::Signature(impl_id.into()), + impl_id.into(), + LifetimeElisionKind::AnonymousCreateParameter { report_in_path: true }, + ); + let ty = ctx.lower_ty(impl_data.self_ty); + assert!(!ty.has_escaping_bound_vars()); + TyLoweringResult::from_ctx(StoredEarlyBinder::bind(ty.store()), ctx) +} - let impl_data = ImplSignature::of(db, impl_id); - let mut ctx = TyLoweringContext::new( - db, - &resolver, - &impl_data.store, - impl_id.into(), - LifetimeElisionKind::AnonymousCreateParameter { report_in_path: true }, - ); - let ty = ctx.lower_ty(impl_data.self_ty); - assert!(!ty.has_escaping_bound_vars()); - (StoredEarlyBinder::bind(ty.store()), create_diagnostics(ctx.diagnostics)) - } +pub(crate) fn impl_self_ty_with_diagnostics_cycle_result( + db: &dyn HirDatabase, + _: salsa::Id, + _impl_id: ImplId, +) -> TyLoweringResult<StoredEarlyBinder<StoredTy>> { + TyLoweringResult::empty(StoredEarlyBinder::bind( + Ty::new_error(DbInterner::new_no_crate(db), ErrorGuaranteed).store(), + )) +} - pub(crate) fn impl_self_ty_with_diagnostics_cycle_result( - db: &dyn HirDatabase, - _: salsa::Id, - _impl_id: ImplId, - ) -> (StoredEarlyBinder<StoredTy>, Diagnostics) { - ( - StoredEarlyBinder::bind( - Ty::new_error(DbInterner::new_no_crate(db), ErrorGuaranteed).store(), - ), - None, - ) +pub(crate) fn const_param_ty<'db>(db: &'db dyn HirDatabase, def: ConstParamId) -> Ty<'db> { + let param_types = const_param_types(db, def.parent()); + match param_types.get(def.local_id()) { + Some(ty) => ty.as_ref(), + None => Ty::new_error(DbInterner::new_no_crate(db), ErrorGuaranteed), } } -pub(crate) fn const_param_ty_query<'db>(db: &'db dyn HirDatabase, def: ConstParamId) -> Ty<'db> { - db.const_param_ty_with_diagnostics(def).0 +pub(crate) fn const_param_types( + db: &dyn HirDatabase, + def: GenericDefId, +) -> &ArenaMap<LocalTypeOrConstParamId, StoredTy> { + &const_param_types_with_diagnostics(db, def).value } -// returns None if def is a type arg -pub(crate) fn const_param_ty_with_diagnostics<'db>( - db: &'db dyn HirDatabase, - def: ConstParamId, -) -> (Ty<'db>, Diagnostics) { - let (ty, diags) = const_param_ty_with_diagnostics_query(db, (), def); - return (ty.as_ref(), diags.clone()); - - // FIXME: Make this query non-interned. - #[salsa::tracked(returns(ref), cycle_result = const_param_ty_with_diagnostics_cycle_result)] - pub(crate) fn const_param_ty_with_diagnostics_query( - db: &dyn HirDatabase, - _: (), - def: ConstParamId, - ) -> (StoredTy, Diagnostics) { - let (parent_data, store) = GenericParams::with_store(db, def.parent()); - let data = &parent_data[def.local_id()]; - let resolver = def.parent().resolver(db); - let interner = DbInterner::new_no_crate(db); - let mut ctx = TyLoweringContext::new( - db, - &resolver, - store, - def.parent(), - LifetimeElisionKind::AnonymousReportError, - ); - let ty = match data { - TypeOrConstParamData::TypeParamData(_) => { - never!(); - Ty::new_error(interner, ErrorGuaranteed) - } - TypeOrConstParamData::ConstParamData(d) => ctx.lower_ty(d.ty), - }; - (ty.store(), create_diagnostics(ctx.diagnostics)) +#[salsa::tracked(returns(ref), cycle_result = const_param_types_with_diagnostics_cycle_result)] +pub(crate) fn const_param_types_with_diagnostics( + db: &dyn HirDatabase, + def: GenericDefId, +) -> TyLoweringResult<ArenaMap<LocalTypeOrConstParamId, StoredTy>> { + let mut result = ArenaMap::new(); + let (data, store) = GenericParams::with_store(db, def); + let resolver = def.resolver(db); + let mut ctx = TyLoweringContext::new( + db, + &resolver, + store, + ExpressionStoreOwnerId::Signature(def), + def, + LifetimeElisionKind::AnonymousReportError, + ); + ctx.forbid_params_after(0, ForbidParamsAfterReason::ConstParamTy); + for (local_id, param_data) in data.iter_type_or_consts() { + if let TypeOrConstParamData::ConstParamData(param_data) = param_data { + result.insert(local_id, ctx.lower_ty(param_data.ty).store()); + } } + result.shrink_to_fit(); + TyLoweringResult::from_ctx(result, ctx) +} - pub(crate) fn const_param_ty_with_diagnostics_cycle_result( - db: &dyn HirDatabase, - _: salsa::Id, - _: (), - _def: ConstParamId, - ) -> (StoredTy, Diagnostics) { - let interner = DbInterner::new_no_crate(db); - (Ty::new_error(interner, ErrorGuaranteed).store(), None) - } +fn const_param_types_with_diagnostics_cycle_result( + _db: &dyn HirDatabase, + _: salsa::Id, + _def: GenericDefId, +) -> TyLoweringResult<ArenaMap<LocalTypeOrConstParamId, StoredTy>> { + TyLoweringResult::empty(ArenaMap::default()) } pub(crate) fn field_types_query( db: &dyn HirDatabase, variant_id: VariantId, ) -> &ArenaMap<LocalFieldId, StoredEarlyBinder<StoredTy>> { - &db.field_types_with_diagnostics(variant_id).0 + &field_types_with_diagnostics(db, variant_id).value } /// Build the type of all specific fields of a struct or enum variant. #[salsa::tracked(returns(ref))] -pub(crate) fn field_types_with_diagnostics_query( +pub(crate) fn field_types_with_diagnostics( db: &dyn HirDatabase, variant_id: VariantId, -) -> (ArenaMap<LocalFieldId, StoredEarlyBinder<StoredTy>>, Diagnostics) { +) -> TyLoweringResult<ArenaMap<LocalFieldId, StoredEarlyBinder<StoredTy>>> { let var_data = variant_id.fields(db); let fields = var_data.fields(); if fields.is_empty() { - return (ArenaMap::default(), None); + return TyLoweringResult::empty(ArenaMap::default()); } - let (resolver, def): (_, GenericDefId) = match variant_id { + let (resolver, generic_def): (_, GenericDefId) = match variant_id { VariantId::StructId(it) => (it.resolver(db), it.into()), VariantId::UnionId(it) => (it.resolver(db), it.into()), VariantId::EnumVariantId(it) => (it.resolver(db), it.lookup(db).parent.into()), @@ -1638,13 +1587,14 @@ pub(crate) fn field_types_with_diagnostics_query( db, &resolver, &var_data.store, - def, + ExpressionStoreOwnerId::VariantFields(variant_id), + generic_def, LifetimeElisionKind::AnonymousReportError, ); for (field_id, field_data) in var_data.fields().iter() { res.insert(field_id, StoredEarlyBinder::bind(ctx.lower_ty(field_data.type_ref).store())); } - (res, create_diagnostics(ctx.diagnostics)) + TyLoweringResult::from_ctx(res, ctx) } #[derive(Debug, PartialEq, Eq, Default)] @@ -1766,6 +1716,7 @@ fn resolve_type_param_assoc_type_shorthand( db, &resolver, generics.store(), + ExpressionStoreOwnerId::Signature(def), def, LifetimeElisionKind::AnonymousReportError, ); @@ -1906,7 +1857,11 @@ pub(crate) fn type_alias_bounds<'db>( db: &'db dyn HirDatabase, type_alias: TypeAliasId, ) -> EarlyBinder<'db, &'db [Clause<'db>]> { - type_alias_bounds_with_diagnostics(db, type_alias).0.predicates.map_bound(|it| it.as_slice()) + type_alias_bounds_with_diagnostics(db, type_alias) + .value + .predicates + .get() + .map_bound(|it| it.as_slice()) } #[inline] @@ -1914,89 +1869,73 @@ pub(crate) fn type_alias_self_bounds<'db>( db: &'db dyn HirDatabase, type_alias: TypeAliasId, ) -> EarlyBinder<'db, &'db [Clause<'db>]> { - let (TypeAliasBounds { predicates, assoc_ty_bounds_start }, _) = - type_alias_bounds_with_diagnostics(db, type_alias); - predicates.map_bound(|it| &it.as_slice()[..assoc_ty_bounds_start as usize]) + let TypeAliasBounds { predicates, assoc_ty_bounds_start } = + &type_alias_bounds_with_diagnostics(db, type_alias).value; + predicates.get().map_bound(|it| &it.as_slice()[..*assoc_ty_bounds_start as usize]) } #[derive(PartialEq, Eq, Debug, Hash)] -struct TypeAliasBounds<T> { +pub struct TypeAliasBounds<T> { predicates: T, assoc_ty_bounds_start: u32, } -fn type_alias_bounds_with_diagnostics<'db>( - db: &'db dyn HirDatabase, +#[salsa::tracked(returns(ref))] +pub(crate) fn type_alias_bounds_with_diagnostics( + db: &dyn HirDatabase, type_alias: TypeAliasId, -) -> (TypeAliasBounds<EarlyBinder<'db, Clauses<'db>>>, Diagnostics) { - let (TypeAliasBounds { predicates, assoc_ty_bounds_start }, diags) = - type_alias_bounds_with_diagnostics_query(db, type_alias); - return ( - TypeAliasBounds { - predicates: predicates.get(), - assoc_ty_bounds_start: *assoc_ty_bounds_start, - }, - diags.clone(), +) -> TyLoweringResult<TypeAliasBounds<StoredEarlyBinder<StoredClauses>>> { + let type_alias_data = TypeAliasSignature::of(db, type_alias); + let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db); + let mut ctx = TyLoweringContext::new( + db, + &resolver, + &type_alias_data.store, + ExpressionStoreOwnerId::Signature(type_alias.into()), + type_alias.into(), + LifetimeElisionKind::AnonymousReportError, ); + let interner = ctx.interner; + let def_id = type_alias.into(); - #[salsa::tracked(returns(ref))] - pub fn type_alias_bounds_with_diagnostics_query( - db: &dyn HirDatabase, - type_alias: TypeAliasId, - ) -> (TypeAliasBounds<StoredEarlyBinder<StoredClauses>>, Diagnostics) { - let type_alias_data = TypeAliasSignature::of(db, type_alias); - let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db); - let mut ctx = TyLoweringContext::new( - db, - &resolver, - &type_alias_data.store, - type_alias.into(), - LifetimeElisionKind::AnonymousReportError, - ); - let interner = ctx.interner; - let def_id = type_alias.into(); + let item_args = GenericArgs::identity_for_item(interner, def_id); + let interner_ty = Ty::new_projection_from_args(interner, def_id, item_args); - let item_args = GenericArgs::identity_for_item(interner, def_id); - let interner_ty = Ty::new_projection_from_args(interner, def_id, item_args); + let mut bounds = Vec::new(); + let mut assoc_ty_bounds = Vec::new(); + for bound in &type_alias_data.bounds { + ctx.lower_type_bound(bound, interner_ty, false).for_each(|(pred, source)| match source { + GenericPredicateSource::SelfOnly => { + bounds.push(pred); + } + GenericPredicateSource::AssocTyBound => { + assoc_ty_bounds.push(pred); + } + }); + } - let mut bounds = Vec::new(); - let mut assoc_ty_bounds = Vec::new(); - for bound in &type_alias_data.bounds { - ctx.lower_type_bound(bound, interner_ty, false).for_each( - |(pred, source)| match source { - GenericPredicateSource::SelfOnly => { - bounds.push(pred); - } - GenericPredicateSource::AssocTyBound => { - assoc_ty_bounds.push(pred); - } - }, + if !ctx.unsized_types.contains(&interner_ty) { + let sized_trait = ctx.lang_items.Sized; + if let Some(sized_trait) = sized_trait { + let trait_ref = TraitRef::new_from_args( + interner, + sized_trait.into(), + GenericArgs::new_from_slice(&[interner_ty.into()]), ); - } - - if !ctx.unsized_types.contains(&interner_ty) { - let sized_trait = ctx.lang_items.Sized; - if let Some(sized_trait) = sized_trait { - let trait_ref = TraitRef::new_from_args( - interner, - sized_trait.into(), - GenericArgs::new_from_slice(&[interner_ty.into()]), - ); - bounds.push(trait_ref.upcast(interner)); - }; - } + bounds.push(trait_ref.upcast(interner)); + }; + } - let assoc_ty_bounds_start = bounds.len() as u32; - bounds.extend(assoc_ty_bounds); + let assoc_ty_bounds_start = bounds.len() as u32; + bounds.extend(assoc_ty_bounds); - ( - TypeAliasBounds { - predicates: StoredEarlyBinder::bind(Clauses::new_from_slice(&bounds).store()), - assoc_ty_bounds_start, - }, - create_diagnostics(ctx.diagnostics), - ) - } + TyLoweringResult::from_ctx( + TypeAliasBounds { + predicates: StoredEarlyBinder::bind(Clauses::new_from_slice(&bounds).store()), + assoc_ty_bounds_start, + }, + ctx, + ) } #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -2027,7 +1966,7 @@ impl<'db> GenericPredicates { pub fn query_with_diagnostics( db: &'db dyn HirDatabase, def: GenericDefId, - ) -> (GenericPredicates, Diagnostics) { + ) -> TyLoweringResult<GenericPredicates> { generic_predicates(db, def) } } @@ -2037,17 +1976,26 @@ fn generic_predicates_cycle_result( _db: &dyn HirDatabase, _: salsa::Id, _def: GenericDefId, -) -> (GenericPredicates, Diagnostics) { - ( - GenericPredicates::from_explicit_own_predicates(StoredEarlyBinder::bind( - Clauses::default().store(), - )), - None, - ) +) -> TyLoweringResult<GenericPredicates> { + TyLoweringResult::empty(GenericPredicates::from_explicit_own_predicates( + StoredEarlyBinder::bind(Clauses::default().store()), + )) } impl GenericPredicates { #[inline] + pub fn empty() -> &'static GenericPredicates { + static EMPTY: OnceLock<GenericPredicates> = OnceLock::new(); + EMPTY.get_or_init(|| GenericPredicates { + predicates: StoredEarlyBinder::bind(Clauses::default().store()), + has_trait_implied_predicate: false, + parent_explicit_self_predicates_start: 0, + own_predicates_start: 0, + own_assoc_ty_bounds_start: 0, + }) + } + + #[inline] pub(crate) fn from_explicit_own_predicates( predicates: StoredEarlyBinder<StoredClauses>, ) -> Self { @@ -2063,7 +2011,7 @@ impl GenericPredicates { #[inline] pub fn query(db: &dyn HirDatabase, def: GenericDefId) -> &GenericPredicates { - &Self::query_with_diagnostics(db, def).0 + &Self::query_with_diagnostics(db, def).value } #[inline] @@ -2171,7 +2119,10 @@ pub(crate) fn trait_environment<'db>( /// Resolve the where clause(s) of an item with generics, /// with a given filter #[tracing::instrument(skip(db), ret)] -fn generic_predicates(db: &dyn HirDatabase, def: GenericDefId) -> (GenericPredicates, Diagnostics) { +fn generic_predicates( + db: &dyn HirDatabase, + def: GenericDefId, +) -> TyLoweringResult<GenericPredicates> { let generics = generics(db, def); let resolver = def.resolver(db); let interner = DbInterner::new_no_crate(db); @@ -2179,6 +2130,7 @@ fn generic_predicates(db: &dyn HirDatabase, def: GenericDefId) -> (GenericPredic db, &resolver, generics.store(), + ExpressionStoreOwnerId::Signature(def), def, LifetimeElisionKind::AnonymousReportError, ); @@ -2278,7 +2230,8 @@ fn generic_predicates(db: &dyn HirDatabase, def: GenericDefId) -> (GenericPredic // But we do have to lower the parent first. } - let diagnostics = create_diagnostics(ctx.diagnostics); + let diagnostics = mem::take(&mut ctx.diagnostics); + let defined_anon_consts = mem::take(&mut ctx.defined_anon_consts); let predicates = parent_implicit_trait_predicate .iter() @@ -2304,7 +2257,7 @@ fn generic_predicates(db: &dyn HirDatabase, def: GenericDefId) -> (GenericPredic own_assoc_ty_bounds_start, predicates: StoredEarlyBinder::bind(Clauses::new_from_slice(&predicates).store()), }; - return (predicates, diagnostics); + return TyLoweringResult::new(predicates, diagnostics, defined_anon_consts); fn implicit_trait_predicate<'db>( interner: DbInterner<'db>, @@ -2349,29 +2302,40 @@ fn push_const_arg_has_type_predicates<'db>( } #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct GenericDefaults(Option<Arc<[Option<StoredEarlyBinder<StoredGenericArg>>]>>); +pub struct GenericDefaults(ThinVec<Option<StoredEarlyBinder<StoredGenericArg>>>); impl GenericDefaults { #[inline] - pub fn get<'db>(&self, idx: usize) -> Option<EarlyBinder<'db, GenericArg<'db>>> { - Some(self.0.as_ref()?[idx].as_ref()?.get_with(|it| it.as_ref())) + pub fn as_ref(&self) -> GenericDefaultsRef<'_> { + GenericDefaultsRef(&self.0) + } +} + +#[derive(Debug, Clone, Copy)] +pub struct GenericDefaultsRef<'db>(&'db [Option<StoredEarlyBinder<StoredGenericArg>>]); + +impl<'db> GenericDefaultsRef<'db> { + #[inline] + pub fn get(self, idx: usize) -> Option<EarlyBinder<'db, GenericArg<'db>>> { + Some(self.0.get(idx)?.as_ref()?.get()) } } -pub(crate) fn generic_defaults_query(db: &dyn HirDatabase, def: GenericDefId) -> GenericDefaults { - db.generic_defaults_with_diagnostics(def).0 +pub(crate) fn generic_defaults(db: &dyn HirDatabase, def: GenericDefId) -> GenericDefaultsRef<'_> { + generic_defaults_with_diagnostics(db, def).value.as_ref() } /// Resolve the default type params from generics. /// /// Diagnostics are only returned for this `GenericDefId` (returned defaults include parents). -pub(crate) fn generic_defaults_with_diagnostics_query( +#[salsa_macros::tracked(returns(ref), cycle_result = generic_defaults_with_diagnostics_cycle_result)] +pub(crate) fn generic_defaults_with_diagnostics( db: &dyn HirDatabase, def: GenericDefId, -) -> (GenericDefaults, Diagnostics) { +) -> TyLoweringResult<GenericDefaults> { let generic_params = generics(db, def); if generic_params.has_no_params() { - return (GenericDefaults(None), None); + return TyLoweringResult::empty(GenericDefaults(ThinVec::new())); } let resolver = def.resolver(db); @@ -2380,48 +2344,39 @@ pub(crate) fn generic_defaults_with_diagnostics_query( db, &resolver, store_for_self, + ExpressionStoreOwnerId::Signature(def), def, LifetimeElisionKind::AnonymousReportError, ) .with_impl_trait_mode(ImplTraitLoweringMode::Disallowed); - let mut has_any_default = false; - let mut defaults = Vec::new(); + let mut defaults = ThinVec::new(); if let Some(parent) = generic_params.parent() { ctx.store = parent.store(); - defaults.extend(parent.iter_with_idx().map(|(idx, _id, p)| { - let (result, has_default) = handle_generic_param(&mut ctx, idx, p); - has_any_default |= has_default; - result - })); + defaults.extend( + parent.iter_with_idx().map(|(idx, _id, p)| handle_generic_param(&mut ctx, idx, p)), + ); } ctx.diagnostics.clear(); // Don't include diagnostics from the parent. + ctx.defined_anon_consts.clear(); ctx.store = store_for_self; - defaults.extend(generic_params.iter_self_with_idx().map(|(idx, _id, p)| { - let (result, has_default) = handle_generic_param(&mut ctx, idx, p); - has_any_default |= has_default; - result - })); - let diagnostics = create_diagnostics(mem::take(&mut ctx.diagnostics)); - let defaults = if has_any_default { - GenericDefaults(Some(Arc::from_iter(defaults))) - } else { - GenericDefaults(None) - }; - return (defaults, diagnostics); + defaults.extend( + generic_params + .iter_self_with_idx() + .map(|(idx, _id, p)| handle_generic_param(&mut ctx, idx, p)), + ); + defaults.shrink_to_fit(); + return TyLoweringResult::from_ctx(GenericDefaults(defaults), ctx); fn handle_generic_param<'db>( ctx: &mut TyLoweringContext<'db, '_>, idx: u32, p: GenericParamDataRef<'_>, - ) -> (Option<StoredEarlyBinder<StoredGenericArg>>, bool) { - ctx.lowering_param_default(idx); + ) -> Option<StoredEarlyBinder<StoredGenericArg>> { + ctx.forbid_params_after(idx, ForbidParamsAfterReason::LoweringParamDefault); match p { GenericParamDataRef::TypeParamData(p) => { let ty = p.default.map(|ty| ctx.lower_ty(ty)); - ( - ty.map(|ty| StoredEarlyBinder::bind(GenericArg::from(ty).store())), - p.default.is_some(), - ) + ty.map(|ty| StoredEarlyBinder::bind(GenericArg::from(ty).store())) } GenericParamDataRef::ConstParamData(p) => { let val = p.default.map(|c| { @@ -2429,19 +2384,19 @@ pub(crate) fn generic_defaults_with_diagnostics_query( let c = ctx.lower_const(c, param_ty); GenericArg::from(c).store() }); - (val.map(StoredEarlyBinder::bind), p.default.is_some()) + val.map(StoredEarlyBinder::bind) } - GenericParamDataRef::LifetimeParamData(_) => (None, false), + GenericParamDataRef::LifetimeParamData(_) => None, } } } -pub(crate) fn generic_defaults_with_diagnostics_cycle_result( +fn generic_defaults_with_diagnostics_cycle_result( _db: &dyn HirDatabase, _: salsa::Id, _def: GenericDefId, -) -> (GenericDefaults, Diagnostics) { - (GenericDefaults(None), None) +) -> TyLoweringResult<GenericDefaults> { + TyLoweringResult::empty(GenericDefaults(ThinVec::new())) } /// Build the signature of a callable item (function, struct or enum variant). @@ -2449,22 +2404,27 @@ pub(crate) fn callable_item_signature<'db>( db: &'db dyn HirDatabase, def: CallableDefId, ) -> EarlyBinder<'db, PolyFnSig<'db>> { - return callable_item_signature_query(db, def).get_with(|sig| sig.get()); + callable_item_signature_with_diagnostics(db, def).value.get() +} - #[salsa::tracked(returns(ref))] - pub(crate) fn callable_item_signature_query( - db: &dyn HirDatabase, - def: CallableDefId, - ) -> StoredEarlyBinder<StoredPolyFnSig> { - match def { - CallableDefId::FunctionId(f) => fn_sig_for_fn(db, f), - CallableDefId::StructId(s) => fn_sig_for_struct_constructor(db, s), - CallableDefId::EnumVariantId(e) => fn_sig_for_enum_variant_constructor(db, e), +#[salsa::tracked(returns(ref))] +pub(crate) fn callable_item_signature_with_diagnostics( + db: &dyn HirDatabase, + def: CallableDefId, +) -> TyLoweringResult<StoredEarlyBinder<StoredPolyFnSig>> { + match def { + CallableDefId::FunctionId(f) => fn_sig_for_fn(db, f), + CallableDefId::StructId(s) => TyLoweringResult::empty(fn_sig_for_struct_constructor(db, s)), + CallableDefId::EnumVariantId(e) => { + TyLoweringResult::empty(fn_sig_for_enum_variant_constructor(db, e)) } } } -fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> StoredEarlyBinder<StoredPolyFnSig> { +fn fn_sig_for_fn( + db: &dyn HirDatabase, + def: FunctionId, +) -> TyLoweringResult<StoredEarlyBinder<StoredPolyFnSig>> { let data = FunctionSignature::of(db, def); let resolver = def.resolver(db); let interner = DbInterner::new_no_crate(db); @@ -2472,41 +2432,46 @@ fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> StoredEarlyBinder<Sto db, &resolver, &data.store, + ExpressionStoreOwnerId::Signature(def.into()), def.into(), LifetimeElisionKind::for_fn_params(data), ); let params = data.params.iter().map(|&tr| ctx_params.lower_ty(tr)); + let mut ctx_ret = TyLoweringContext::new( + db, + &resolver, + &data.store, + ExpressionStoreOwnerId::Signature(def.into()), + def.into(), + LifetimeElisionKind::for_fn_ret(interner), + ) + .with_impl_trait_mode(ImplTraitLoweringMode::Opaque); let ret = match data.ret_type { - Some(ret_type) => { - let mut ctx_ret = TyLoweringContext::new( - db, - &resolver, - &data.store, - def.into(), - LifetimeElisionKind::for_fn_ret(interner), - ) - .with_impl_trait_mode(ImplTraitLoweringMode::Opaque); - ctx_ret.lower_ty(ret_type) - } - None => Ty::new_tup(interner, &[]), + Some(ret_type) => ctx_ret.lower_ty(ret_type), + None => Ty::new_unit(interner), }; let inputs_and_output = Tys::new_from_iter(interner, params.chain(Some(ret))); + + ctx_params.diagnostics.extend(ctx_ret.diagnostics); + ctx_params.defined_anon_consts.extend(ctx_ret.defined_anon_consts); + // If/when we track late bound vars, we need to switch this to not be `dummy` - StoredEarlyBinder::bind(StoredPolyFnSig::new(Binder::dummy(FnSig { + let result = StoredEarlyBinder::bind(StoredPolyFnSig::new(Binder::dummy(FnSig { abi: data.abi.as_ref().map_or(FnAbi::Rust, FnAbi::from_symbol), c_variadic: data.is_varargs(), safety: if data.is_unsafe() { Safety::Unsafe } else { Safety::Safe }, inputs_and_output, - }))) + }))); + TyLoweringResult::from_ctx(result, ctx_params) } -fn type_for_adt(db: &dyn HirDatabase, adt: AdtId) -> StoredEarlyBinder<StoredTy> { +fn type_for_adt<'db>(db: &'db dyn HirDatabase, adt: AdtId) -> EarlyBinder<'db, Ty<'db>> { let interner = DbInterner::new_no_crate(db); let args = GenericArgs::identity_for_item(interner, adt.into()); let ty = Ty::new_adt(interner, adt, args); - StoredEarlyBinder::bind(ty.store()) + EarlyBinder::bind(ty) } fn fn_sig_for_struct_constructor( @@ -2518,7 +2483,7 @@ fn fn_sig_for_struct_constructor( let ret = type_for_adt(db, def.into()).skip_binder(); let inputs_and_output = - Tys::new_from_iter(DbInterner::new_no_crate(db), params.chain(Some(ret.as_ref()))); + Tys::new_from_iter(DbInterner::new_no_crate(db), params.chain(Some(ret))); StoredEarlyBinder::bind(StoredPolyFnSig::new(Binder::dummy(FnSig { abi: FnAbi::Rust, c_variadic: false, @@ -2537,7 +2502,7 @@ fn fn_sig_for_enum_variant_constructor( let ret = type_for_adt(db, parent.into()).skip_binder(); let inputs_and_output = - Tys::new_from_iter(DbInterner::new_no_crate(db), params.chain(Some(ret.as_ref()))); + Tys::new_from_iter(DbInterner::new_no_crate(db), params.chain(Some(ret))); StoredEarlyBinder::bind(StoredPolyFnSig::new(Binder::dummy(FnSig { abi: FnAbi::Rust, c_variadic: false, @@ -2546,7 +2511,7 @@ fn fn_sig_for_enum_variant_constructor( }))) } -// FIXME(next-solver): should merge this with `explicit_item_bounds` in some way +// FIXME: Remove this. pub(crate) fn associated_ty_item_bounds<'db>( db: &'db dyn HirDatabase, type_alias: TypeAliasId, @@ -2558,6 +2523,7 @@ pub(crate) fn associated_ty_item_bounds<'db>( db, &resolver, &type_alias_data.store, + ExpressionStoreOwnerId::Signature(type_alias.into()), type_alias.into(), LifetimeElisionKind::AnonymousReportError, ); diff --git a/crates/hir-ty/src/lower/path.rs b/crates/hir-ty/src/lower/path.rs index 2a23e07a03..bf37e1faa8 100644 --- a/crates/hir-ty/src/lower/path.rs +++ b/crates/hir-ty/src/lower/path.rs @@ -30,8 +30,8 @@ use crate::{ db::HirDatabase, generics::{Generics, generics}, lower::{ - AssocTypeShorthandResolution, GenericPredicateSource, LifetimeElisionKind, - PathDiagnosticCallbackData, + AssocTypeShorthandResolution, ForbidParamsAfterReason, GenericPredicateSource, + LifetimeElisionKind, PathDiagnosticCallbackData, const_param_ty, }, next_solver::{ Binder, Clause, Const, DbInterner, EarlyBinder, ErrorGuaranteed, GenericArg, GenericArgs, @@ -41,7 +41,7 @@ use crate::{ use super::{ ImplTraitLoweringMode, TyLoweringContext, - associated_type_by_name_including_super_traits_allow_ambiguity, const_param_ty_query, ty_query, + associated_type_by_name_including_super_traits_allow_ambiguity, ty_query, }; type CallbackData<'a> = @@ -288,7 +288,11 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> { TypeNs::AdtSelfType(_) => { prohibit_generics_on_resolved(GenericArgsProhibitedReason::SelfTy); - if self.ctx.lowering_param_default.is_some() { + if self.ctx.forbid_params_after.is_some() + && self.ctx.forbid_params_after_reason + == ForbidParamsAfterReason::LoweringParamDefault + { + // FIXME: Handle other reasons. let segment = self.current_segment_u32(); self.on_diagnostic(PathLoweringDiagnostic::GenericDefaultRefersToSelf { segment, @@ -469,7 +473,7 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> { fn select_associated_type(&mut self, res: Option<TypeNs>, infer_args: bool) -> Ty<'db> { let interner = self.ctx.interner; let db = self.ctx.db; - let def = self.ctx.def; + let def = self.ctx.generic_def; let segment = self.current_or_prev_segment; let assoc_name = segment.name; let error_ty = || Ty::new_error(self.ctx.interner, ErrorGuaranteed); @@ -718,7 +722,7 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> { }; self.ctx .ctx - .lower_const(konst, const_param_ty_query(self.ctx.ctx.db, const_id)) + .lower_const(konst, const_param_ty(self.ctx.ctx.db, const_id)) .into() } _ => unreachable!("unmatching param kinds were passed to `provided_kind()`"), @@ -775,7 +779,7 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> { let GenericParamId::ConstParamId(const_id) = param_id else { unreachable!("non-const param ID for const param"); }; - unknown_const_as_generic(const_param_ty_query(self.ctx.ctx.db, const_id)) + unknown_const_as_generic(const_param_ty(self.ctx.ctx.db, const_id)) } } } @@ -786,7 +790,7 @@ impl<'a, 'b, 'db> PathLoweringContext<'a, 'b, 'db> { Ty::new_error(self.ctx.ctx.interner, ErrorGuaranteed).into() } GenericParamId::ConstParamId(const_id) => { - unknown_const_as_generic(const_param_ty_query(self.ctx.ctx.db, const_id)) + unknown_const_as_generic(const_param_ty(self.ctx.ctx.db, const_id)) } GenericParamId::LifetimeParamId(_) => { Region::new(self.ctx.ctx.interner, rustc_type_ir::ReError(ErrorGuaranteed)) @@ -1220,7 +1224,7 @@ pub(crate) fn substs_from_args_and_bindings<'db>( let GenericParamId::ConstParamId(param_id) = param_id else { panic!("unmatching param kinds"); }; - let const_ty = const_param_ty_query(db, param_id); + let const_ty = const_param_ty(db, param_id); substs .push(ctx.provided_type_like_const(*type_ref, const_ty, konst).into()); args.next(); diff --git a/crates/hir-ty/src/method_resolution/confirm.rs b/crates/hir-ty/src/method_resolution/confirm.rs index ffd65a58d8..013b107b30 100644 --- a/crates/hir-ty/src/method_resolution/confirm.rs +++ b/crates/hir-ty/src/method_resolution/confirm.rs @@ -403,7 +403,7 @@ impl<'a, 'b, 'db> ConfirmContext<'a, 'b, 'db> { unreachable!("non-const param ID for const param"); }; let const_ty = self.ctx.db.const_param_ty(const_id); - self.ctx.make_body_const(*konst, const_ty).into() + self.ctx.create_body_anon_const(konst.expr, const_ty, false).into() } _ => unreachable!("unmatching param kinds were passed to `provided_kind()`"), } @@ -411,14 +411,12 @@ impl<'a, 'b, 'db> ConfirmContext<'a, 'b, 'db> { fn provided_type_like_const( &mut self, - type_ref: TypeRefId, - const_ty: Ty<'db>, + _type_ref: TypeRefId, + _const_ty: Ty<'db>, arg: TypeLikeConst<'_>, ) -> Const<'db> { match arg { - TypeLikeConst::Path(path) => { - self.ctx.make_path_as_body_const(type_ref, path, const_ty) - } + TypeLikeConst::Path(path) => self.ctx.make_path_as_body_const(path), TypeLikeConst::Infer => self.ctx.table.next_const_var(Span::Dummy), } } diff --git a/crates/hir-ty/src/mir.rs b/crates/hir-ty/src/mir.rs index 67cc67fd39..05f3f00103 100644 --- a/crates/hir-ty/src/mir.rs +++ b/crates/hir-ty/src/mir.rs @@ -5,7 +5,7 @@ use std::{collections::hash_map::Entry, fmt::Display, iter}; use base_db::Crate; use either::Either; use hir_def::{ - DefWithBodyId, FieldId, StaticId, TupleFieldId, UnionId, VariantId, + FieldId, StaticId, TupleFieldId, UnionId, VariantId, hir::{BindingId, Expr, ExprId, Ordering, PatId}, }; use la_arena::{Arena, ArenaMap, Idx, RawIdx}; @@ -16,7 +16,7 @@ use smallvec::{SmallVec, smallvec}; use stdx::{impl_from, never}; use crate::{ - CallableDefId, InferenceResult, MemoryMap, + CallableDefId, InferBodyId, InferenceResult, MemoryMap, consteval::usize_const, db::{HirDatabase, InternedClosureId}, display::{DisplayTarget, HirDisplay}, @@ -1084,7 +1084,7 @@ pub struct MirBody { pub basic_blocks: Arena<BasicBlock>, pub locals: Arena<Local>, pub start_block: BasicBlockId, - pub owner: DefWithBodyId, + pub owner: InferBodyId, pub binding_locals: ArenaMap<BindingId, LocalId>, pub upvar_locals: FxHashMap<BindingId, Vec<(LocalId, crate::closure_analysis::Place)>>, pub param_locals: Vec<LocalId>, diff --git a/crates/hir-ty/src/mir/borrowck.rs b/crates/hir-ty/src/mir/borrowck.rs index dcd06ae25f..940bc57259 100644 --- a/crates/hir-ty/src/mir/borrowck.rs +++ b/crates/hir-ty/src/mir/borrowck.rs @@ -6,12 +6,13 @@ use std::iter; use either::Either; -use hir_def::{DefWithBodyId, ExpressionStoreOwnerId, HasModule}; +use hir_def::HasModule; use la_arena::ArenaMap; use rustc_hash::FxHashMap; use stdx::never; use crate::{ + InferBodyId, closure_analysis::ProjectionKind as HirProjectionKind, db::{HirDatabase, InternedClosureId}, display::DisplayTarget, @@ -57,7 +58,7 @@ pub struct BorrowRegion { #[derive(Debug, Clone, PartialEq, Eq)] pub struct BorrowckResult { - owner: Either<DefWithBodyId, InternedClosureId>, + owner: Either<InferBodyId, InternedClosureId>, pub mutability_of_locals: ArenaMap<LocalId, MutabilityReason>, pub moved_out_of_ref: Vec<MovedOutOfRef>, pub partially_moved: Vec<PartiallyMoved>, @@ -75,8 +76,8 @@ impl BorrowckResult { fn all_mir_bodies<'db>( db: &'db dyn HirDatabase, - def: DefWithBodyId, - mut cb: impl FnMut(&'db MirBody, Either<DefWithBodyId, InternedClosureId>) -> BorrowckResult, + def: InferBodyId, + mut cb: impl FnMut(&'db MirBody, Either<InferBodyId, InternedClosureId>) -> BorrowckResult, mut merge_from_closures: impl FnMut( (&mut BorrowckResult, &'db MirBody), (&BorrowckResult, &'db MirBody), @@ -86,7 +87,7 @@ fn all_mir_bodies<'db>( db: &'db dyn HirDatabase, c: InternedClosureId, results: &mut Vec<(BorrowckResult, &'db MirBody)>, - cb: &mut impl FnMut(&'db MirBody, Either<DefWithBodyId, InternedClosureId>) -> BorrowckResult, + cb: &mut impl FnMut(&'db MirBody, Either<InferBodyId, InternedClosureId>) -> BorrowckResult, merge_from_closures: &mut impl FnMut( (&mut BorrowckResult, &'db MirBody), (&BorrowckResult, &'db MirBody), @@ -135,12 +136,12 @@ fn all_mir_bodies<'db>( #[salsa_macros::tracked(returns(ref), lru = 2024)] pub fn borrowck_query( db: &dyn HirDatabase, - def: DefWithBodyId, + def: InferBodyId, ) -> Result<Box<[BorrowckResult]>, MirLowerError> { let _p = tracing::info_span!("borrowck_query").entered(); let module = def.module(db); let interner = DbInterner::new_with(db, module.krate(db)); - let env = db.trait_environment(ExpressionStoreOwnerId::from(def)); + let env = db.trait_environment(def.expression_store_owner(db)); // This calculates opaques defining scope which is a bit costly therefore is put outside `all_mir_bodies()`. let typing_mode = TypingMode::borrowck(interner, def.into()); let res = all_mir_bodies( diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs index af2912b185..9e2861fa2b 100644 --- a/crates/hir-ty/src/mir/eval.rs +++ b/crates/hir-ty/src/mir/eval.rs @@ -5,9 +5,9 @@ use std::{borrow::Cow, cell::RefCell, fmt::Write, iter, mem, ops::Range}; use base_db::{Crate, target::TargetLoadError}; use either::Either; use hir_def::{ - AdtId, DefWithBodyId, EnumVariantId, ExpressionStoreOwnerId, FunctionId, HasModule, - ItemContainerId, Lookup, StaticId, VariantId, - expr_store::{Body, HygieneId}, + AdtId, DefWithBodyId, EnumVariantId, FunctionId, HasModule, ItemContainerId, Lookup, StaticId, + VariantId, + expr_store::{Body, ExpressionStore, HygieneId}, item_tree::FieldsShape, lang_item::LangItems, layout::{TagEncoding, Variants}, @@ -37,7 +37,7 @@ use syntax::{SyntaxNodePtr, TextRange}; use triomphe::Arc; use crate::{ - CallableDefId, ComplexMemoryMap, InferenceResult, MemoryMap, ParamEnvAndCrate, + CallableDefId, ComplexMemoryMap, InferBodyId, InferenceResult, MemoryMap, ParamEnvAndCrate, consteval::{self, ConstEvalError, try_const_usize}, db::{GeneralConstId, HirDatabase, InternedClosureId}, display::{ClosureStyle, DisplayTarget, HirDisplay}, @@ -159,7 +159,7 @@ struct StackFrame<'a> { locals: Locals<'a>, destination: Option<BasicBlockId>, prev_stack_ptr: usize, - span: (MirSpan, DefWithBodyId), + span: (MirSpan, InferBodyId), } #[derive(Clone)] @@ -193,7 +193,7 @@ pub struct Evaluator<'a, 'db> { /// Constantly dropping and creating `Locals` is very costly. We store /// old locals that we normally want to drop here, to reuse their allocations /// later. - unused_locals_store: RefCell<FxHashMap<DefWithBodyId, Vec<Locals<'a>>>>, + unused_locals_store: RefCell<FxHashMap<InferBodyId, Vec<Locals<'a>>>>, cached_ptr_size: usize, cached_fn_trait_func: Option<FunctionId>, cached_fn_mut_trait_func: Option<FunctionId>, @@ -371,7 +371,7 @@ pub enum MirEvalError { InvalidConst, InFunction( Box<MirEvalError>, - Vec<(Either<FunctionId, InternedClosureId>, MirSpan, DefWithBodyId)>, + Vec<(Either<FunctionId, InternedClosureId>, MirSpan, InferBodyId)>, ), ExecutionLimitExceeded, StackOverflow, @@ -410,7 +410,16 @@ impl MirEvalError { writeln!(f, "In {closure:?}")?; } } - let source_map = &Body::with_source_map(db, *def).1; + let (source_map, self_param_syntax) = match *def { + InferBodyId::DefWithBodyId(def) => { + let body = &Body::with_source_map(db, def).1; + (&**body, body.self_param_syntax()) + } + InferBodyId::AnonConstId(def) => { + let store = ExpressionStore::with_source_map(db, def.loc(db).owner).1; + (store, None) + } + }; let span: InFile<SyntaxNodePtr> = match span { MirSpan::ExprId(e) => match source_map.expr_syntax(*e) { Ok(s) => s.map(|it| it.into()), @@ -430,7 +439,7 @@ impl MirEvalError { None => continue, } } - MirSpan::SelfParam => match source_map.self_param_syntax() { + MirSpan::SelfParam => match self_param_syntax { Some(s) => s.map(|it| it.syntax_node_ptr()), None => continue, }, @@ -650,7 +659,7 @@ const EXECUTION_LIMIT: usize = 10_000_000; impl<'a, 'db: 'a> Evaluator<'a, 'db> { pub fn new( db: &'db dyn HirDatabase, - owner: DefWithBodyId, + owner: InferBodyId, assert_placeholder_ty_is_unused: bool, trait_env: Option<ParamEnvAndCrate<'db>>, ) -> Result<'db, Evaluator<'a, 'db>> { @@ -675,7 +684,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { db, random_state: oorandom::Rand64::new(0), param_env: trait_env.unwrap_or_else(|| ParamEnvAndCrate { - param_env: db.trait_environment(ExpressionStoreOwnerId::from(owner)), + param_env: db.trait_environment(owner.expression_store_owner(db)), krate: crate_id, }), crate_id, @@ -1044,7 +1053,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { let my_code_stack = mem::replace(&mut self.code_stack, prev_code_stack); let mut error_stack = vec![]; for frame in my_code_stack.into_iter().rev() { - if let DefWithBodyId::FunctionId(f) = frame.locals.body.owner { + if let Some(f) = frame.locals.body.owner.as_function() { error_stack.push((Either::Left(f), frame.span.0, frame.span.1)); } } @@ -1806,7 +1815,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { locals: &Locals<'a>, ) -> Result<'db, (usize, Arc<Layout>, Option<(usize, usize, i128)>)> { let adt = it.adt_id(self.db); - if let DefWithBodyId::VariantId(f) = locals.body.owner + if let Some(f) = locals.body.owner.as_variant() && let VariantId::EnumVariantId(it) = it && let AdtId::EnumId(e) = adt && f.lookup(self.db).parent == e @@ -2076,9 +2085,13 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { MirEvalError::ConstEvalError(name, Box::new(e)) })? } - GeneralConstId::AnonConstId(_) => { - not_supported!("anonymous const evaluation") - } + GeneralConstId::AnonConstId(anon_const_id) => self + .db + .anon_const_eval(anon_const_id, subst, Some(self.param_env)) + .map_err(|e| { + let name = id.name(self.db); + MirEvalError::ConstEvalError(name, Box::new(e)) + })?, }; self.allocate_allocation_in_heap(locals, allocation) } @@ -2237,7 +2250,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { .is_sized() .then(|| (layout.size.bytes_usize(), layout.align.bytes() as usize))); } - if let DefWithBodyId::VariantId(f) = locals.body.owner + if let Some(f) = locals.body.owner.as_variant() && let Some((AdtId::EnumId(e), _)) = ty.as_adt() && f.lookup(self.db).parent == e { @@ -3127,7 +3140,7 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> { pub fn render_const_using_debug_impl<'db>( db: &'db dyn HirDatabase, - owner: DefWithBodyId, + owner: InferBodyId, c: Allocation<'db>, ty: Ty<'db>, ) -> Result<'db, String> { diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs index 974bc40965..96ddb69814 100644 --- a/crates/hir-ty/src/mir/lower.rs +++ b/crates/hir-ty/src/mir/lower.rs @@ -27,7 +27,7 @@ use span::{Edition, FileId}; use syntax::TextRange; use crate::{ - Adjust, Adjustment, AutoBorrow, CallableDefId, ParamEnvAndCrate, + Adjust, Adjustment, AutoBorrow, CallableDefId, InferBodyId, ParamEnvAndCrate, consteval::ConstEvalError, db::{GeneralConstId, HirDatabase, InternedClosure, InternedClosureId}, display::{DisplayTarget, HirDisplay, hir_display_with_store}, @@ -81,7 +81,8 @@ struct DropScope { struct MirLowerCtx<'a, 'db> { result: MirBody, - owner: DefWithBodyId, + owner: InferBodyId, + store_owner: ExpressionStoreOwnerId, current_loop_blocks: Option<LoopBlocks>, labeled_loop_blocks: FxHashMap<LabelId, LoopBlocks>, discr_temp: Option<Place>, @@ -109,7 +110,7 @@ pub enum MirLowerError { UnresolvedMethod(String), UnresolvedField, UnsizedTemporary(StoredTy), - MissingFunctionDefinition(DefWithBodyId, ExprId), + MissingFunctionDefinition(InferBodyId, ExprId), HasErrors, /// This should never happen. Type mismatch should catch everything. TypeError(&'static str), @@ -188,11 +189,18 @@ impl MirLowerError { } } MirLowerError::MissingFunctionDefinition(owner, it) => { - let body = Body::of(db, *owner); + let owner = owner.expression_store_owner(db); + let store = ExpressionStore::of(db, owner); writeln!( f, "Missing function definition for {}", - body.pretty_print_expr(db, *owner, *it, display_target.edition) + hir_def::expr_store::pretty::print_expr_hir( + db, + store, + owner, + *it, + display_target.edition + ) )?; } MirLowerError::HasErrors => writeln!(f, "Type inference result contains errors")?, @@ -281,7 +289,7 @@ type Result<'db, T> = std::result::Result<T, MirLowerError>; impl<'a, 'db> MirLowerCtx<'a, 'db> { fn new( db: &'db dyn HirDatabase, - owner: DefWithBodyId, + owner: InferBodyId, store: &'a ExpressionStore, infer: &'a InferenceResult, ) -> Self { @@ -304,8 +312,9 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { owner, closures: vec![], }; - let resolver = owner.resolver(db); - let env = db.trait_environment(ExpressionStoreOwnerId::from(owner)); + let store_owner = owner.expression_store_owner(db); + let resolver = store_owner.resolver(db); + let env = db.trait_environment(store_owner); let interner = DbInterner::new_with(db, resolver.krate()); // FIXME(next-solver): Is `non_body_analysis()` correct here? Don't we want to reveal opaque types defined by this body? let infcx = interner.infer_ctxt().build(TypingMode::non_body_analysis()); @@ -317,6 +326,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { store, types: crate::next_solver::default_types(db), owner, + store_owner, resolver, current_loop_blocks: None, labeled_loop_blocks: Default::default(), @@ -467,7 +477,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { not_supported!("builtin#asm") } Expr::Missing => { - if let DefWithBodyId::FunctionId(f) = self.owner { + if let Some(f) = self.owner.as_function() { let assoc = f.lookup(self.db); if let ItemContainerId::TraitId(t) = assoc.container { let name = &FunctionSignature::of(self.db, f).name; @@ -497,7 +507,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { } } else { let resolver_guard = - self.resolver.update_to_inner_scope(self.db, self.owner, expr_id); + self.resolver.update_to_inner_scope(self.db, self.store_owner, expr_id); let hygiene = self.store.expr_path_hygiene(expr_id); let result = self .resolver @@ -555,9 +565,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { Ok(Some(current)) } ValueNs::GenericParam(p) => { - let Some(def) = self.owner.as_generic_def_id(self.db) else { - not_supported!("owner without generic def id"); - }; + let def = self.owner.generic_def(self.db); let generics = generics(self.db, def); let index = generics.type_or_const_param_idx(p.into()); self.push_assignment( @@ -615,7 +623,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { }; self.push_fake_read(current, cond_place, expr_id.into()); let resolver_guard = - self.resolver.update_to_inner_scope(self.db, self.owner, expr_id); + self.resolver.update_to_inner_scope(self.db, self.store_owner, expr_id); let (then_target, else_target) = self.pattern_match(current, None, cond_place, *pat)?; self.resolver.reset_to_guard(resolver_guard); @@ -753,7 +761,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { self.push_fake_read(current, cond_place, expr_id.into()); let mut end = None; let resolver_guard = - self.resolver.update_to_inner_scope(self.db, self.owner, expr_id); + self.resolver.update_to_inner_scope(self.db, self.store_owner, expr_id); for MatchArm { pat, guard, expr } in arms.iter() { let (then, mut otherwise) = self.pattern_match(current, None, cond_place, *pat)?; @@ -1182,7 +1190,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { }; self.push_fake_read(current, value, expr_id.into()); let resolver_guard = - self.resolver.update_to_inner_scope(self.db, self.owner, expr_id); + self.resolver.update_to_inner_scope(self.db, self.store_owner, expr_id); current = self.pattern_match_assignment(current, value, target)?; self.resolver.reset_to_guard(resolver_guard); Ok(Some(current)) @@ -1529,23 +1537,16 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { subst: GenericArgs<'db>, const_id: GeneralConstId, ) -> Result<'db, Operand> { - if matches!(const_id, GeneralConstId::AnonConstId(_)) { - // FIXME: - not_supported!("anon consts are not supported yet in const eval"); - } let konst = Const::new_unevaluated( self.interner(), UnevaluatedConst { def: const_id.into(), args: subst }, ); - let ty = self - .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); + let ty = match const_id { + GeneralConstId::ConstId(id) => self.db.value_ty(id.into()).unwrap(), + GeneralConstId::StaticId(id) => self.db.value_ty(id.into()).unwrap(), + GeneralConstId::AnonConstId(id) => id.loc(self.db).ty.get(), + }; + let ty = ty.instantiate(self.interner(), subst); Ok(Operand { kind: OperandKind::Constant { konst: konst.store(), ty: ty.store() }, span: None, @@ -1829,8 +1830,11 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { self.push_fake_read(current, init_place, span); // Using the initializer for the resolver scope is good enough for us, as it cannot create new declarations // and has all declarations of the `let`. - let resolver_guard = - self.resolver.update_to_inner_scope(self.db, self.owner, *expr_id); + let resolver_guard = self.resolver.update_to_inner_scope( + self.db, + self.store_owner, + *expr_id, + ); (current, else_block) = self.pattern_match(current, None, init_place, *pat)?; self.resolver.reset_to_guard(resolver_guard); @@ -1961,8 +1965,7 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> { match self.result.binding_locals.get(b) { Some(it) => Ok(*it), None => { - // FIXME: It should never happens, but currently it will happen in `const_dependent_on_local` test, which - // is a hir lowering problem IMO. + // FIXME: It should never happens, but currently it will happen in some cases, not sure when exactly. // never!("Using inaccessible local for binding is always a bug"); Err(MirLowerError::InaccessibleLocal) } @@ -2134,12 +2137,10 @@ pub fn mir_body_for_closure_query<'db>( db: &'db dyn HirDatabase, closure: InternedClosureId, ) -> Result<'db, MirBody> { - let InternedClosure { owner, expr, .. } = closure.loc(db); - let body_owner = - owner.as_def_with_body().expect("MIR lowering should only happen for body-owned closures"); - let body = Body::of(db, body_owner); + let InternedClosure { owner: body_owner, expr, .. } = closure.loc(db); + let store = ExpressionStore::of(db, body_owner.expression_store_owner(db)); let infer = InferenceResult::of(db, body_owner); - let Expr::Closure { args, body: root, .. } = &body[expr] else { + let Expr::Closure { args, body: root, .. } = &store[expr] else { implementation_error!("closure expression is not closure"); }; let crate::next_solver::TyKind::Closure(_, substs) = infer.expr_ty(expr).kind() else { @@ -2147,7 +2148,7 @@ pub fn mir_body_for_closure_query<'db>( }; let kind = substs.as_closure().kind(); let captures = infer.closures_data[&expr].min_captures.values().flatten(); - let mut ctx = MirLowerCtx::new(db, body_owner, &body.store, infer); + let mut ctx = MirLowerCtx::new(db, body_owner, store, infer); // 0 is return local ctx.result.locals.alloc(Local { ty: infer.expr_ty(*root).store() }); @@ -2172,7 +2173,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, body_owner, expr); + let resolver_guard = ctx.resolver.update_to_inner_scope(db, ctx.store_owner, expr); let current = ctx.lower_params_and_bindings( args.iter().zip(sig.skip_binder().inputs().iter()).map(|(it, y)| (*it, *y)), None, @@ -2290,34 +2291,45 @@ pub fn mir_body_for_closure_query<'db>( } #[salsa_macros::tracked(returns(ref), cycle_result = mir_body_cycle_result)] -pub fn mir_body_query<'db>(db: &'db dyn HirDatabase, def: DefWithBodyId) -> Result<'db, MirBody> { +pub fn mir_body_query<'db>(db: &'db dyn HirDatabase, def: InferBodyId) -> Result<'db, MirBody> { let krate = def.krate(db); let edition = krate.data(db).edition; let detail = match def { - DefWithBodyId::FunctionId(it) => { + InferBodyId::DefWithBodyId(DefWithBodyId::FunctionId(it)) => { FunctionSignature::of(db, it).name.display(db, edition).to_string() } - DefWithBodyId::StaticId(it) => { + InferBodyId::DefWithBodyId(DefWithBodyId::StaticId(it)) => { StaticSignature::of(db, it).name.display(db, edition).to_string() } - DefWithBodyId::ConstId(it) => ConstSignature::of(db, it) + InferBodyId::DefWithBodyId(DefWithBodyId::ConstId(it)) => ConstSignature::of(db, it) .name .clone() .unwrap_or_else(Name::missing) .display(db, edition) .to_string(), - DefWithBodyId::VariantId(it) => { + InferBodyId::DefWithBodyId(DefWithBodyId::VariantId(it)) => { let loc = it.lookup(db); loc.parent.enum_variants(db).variants[loc.index as usize] .1 .display(db, edition) .to_string() } + InferBodyId::AnonConstId(_) => "{const}".to_owned(), }; let _p = tracing::info_span!("mir_body_query", ?detail).entered(); - let body = Body::of(db, def); + let (store, root_expr, self_param, params) = match def { + InferBodyId::DefWithBodyId(def) => { + let body = Body::of(db, def); + (&**body, body.root_expr(), body.self_param, &*body.params) + } + InferBodyId::AnonConstId(def) => { + let loc = def.loc(db); + let store = ExpressionStore::of(db, loc.owner); + (store, loc.expr, None, &[][..]) + } + }; let infer = InferenceResult::of(db, def); - let mut result = lower_body_to_mir(db, def, body, infer, body.root_expr())?; + let mut result = lower_body_to_mir(db, def, store, infer, root_expr, self_param, params)?; result.shrink_to_fit(); Ok(result) } @@ -2325,7 +2337,7 @@ pub fn mir_body_query<'db>(db: &'db dyn HirDatabase, def: DefWithBodyId) -> Resu fn mir_body_cycle_result<'db>( _db: &'db dyn HirDatabase, _: salsa::Id, - _def: DefWithBodyId, + _def: InferBodyId, ) -> Result<'db, MirBody> { Err(MirLowerError::Loop) } @@ -2342,42 +2354,31 @@ fn mir_body_for_closure_cycle_result<'db>( /// then delegates to [`lower_to_mir_with_store`]. pub fn lower_body_to_mir<'db>( db: &'db dyn HirDatabase, - owner: DefWithBodyId, - body: &Body, + owner: InferBodyId, + store: &ExpressionStore, infer: &InferenceResult, - // FIXME: root_expr should always be the body.body_expr, - // but this is currently also used for `X` in `[(); X]` which live in the same expression store root_expr: ExprId, + self_param: Option<BindingId>, + params: &[PatId], ) -> Result<'db, MirBody> { - let is_root = root_expr == body.root_expr(); // Extract params and self_param only when lowering the body's root expression for a function. - if is_root && let DefWithBodyId::FunctionId(fid) = owner { + if let Some(fid) = owner.as_function() { let callable_sig = db.callable_item_signature(fid.into()).instantiate_identity().skip_binder(); let mut param_tys = callable_sig.inputs().iter().copied(); - let self_param = body.self_param.and_then(|id| Some((id, param_tys.next()?))); + let self_param = self_param.and_then(|id| Some((id, param_tys.next()?))); lower_to_mir_with_store( db, owner, - &body.store, + store, infer, root_expr, - body.params.iter().copied().zip(param_tys), + params.iter().copied().zip(param_tys), self_param, - is_root, ) } else { - lower_to_mir_with_store( - db, - owner, - &body.store, - infer, - root_expr, - iter::empty(), - None, - is_root, - ) + lower_to_mir_with_store(db, owner, store, infer, root_expr, iter::empty(), None) } } @@ -2387,13 +2388,12 @@ pub fn lower_body_to_mir<'db>( /// const (picks bindings owned by `root_expr`). pub fn lower_to_mir_with_store<'db>( db: &'db dyn HirDatabase, - owner: DefWithBodyId, + owner: InferBodyId, store: &ExpressionStore, infer: &InferenceResult, root_expr: ExprId, params: impl Iterator<Item = (PatId, Ty<'db>)> + Clone, self_param: Option<(BindingId, Ty<'db>)>, - is_root: bool, ) -> Result<'db, MirBody> { if infer.has_type_mismatches() || infer.is_erroneous() { return Err(MirLowerError::HasErrors); @@ -2401,10 +2401,9 @@ pub fn lower_to_mir_with_store<'db>( let mut ctx = MirLowerCtx::new(db, owner, store, infer); // 0 is return local ctx.result.locals.alloc(Local { ty: ctx.expr_ty_after_adjustments(root_expr).store() }); - let binding_picker = |b: BindingId| { - let owner = ctx.store.binding_owner(b); - if is_root { owner.is_none() } else { owner == Some(root_expr) } - }; + let expected_binding_owner = + if matches!(owner, InferBodyId::DefWithBodyId(_)) { None } else { Some(root_expr) }; + let binding_picker = |b: BindingId| ctx.store.binding_owner(b) == expected_binding_owner; let current = ctx.lower_params_and_bindings(params, self_param, binding_picker)?; if let Some(current) = ctx.lower_expr_to_place(root_expr, return_slot().into(), current)? { let current = ctx.pop_drop_scope_assert_finished(current, root_expr.into())?; diff --git a/crates/hir-ty/src/mir/lower/as_place.rs b/crates/hir-ty/src/mir/lower/as_place.rs index 0f7fc9a18e..2ed7aedecf 100644 --- a/crates/hir-ty/src/mir/lower/as_place.rs +++ b/crates/hir-ty/src/mir/lower/as_place.rs @@ -130,7 +130,7 @@ impl<'db> MirLowerCtx<'_, 'db> { match &self.store[expr_id] { Expr::Path(p) => { let resolver_guard = - self.resolver.update_to_inner_scope(self.db, self.owner, expr_id); + self.resolver.update_to_inner_scope(self.db, self.store_owner, expr_id); let hygiene = self.store.expr_path_hygiene(expr_id); let resolved = self.resolver.resolve_path_in_value_ns_fully(self.db, p, hygiene); self.resolver.reset_to_guard(resolver_guard); diff --git a/crates/hir-ty/src/mir/lower/tests.rs b/crates/hir-ty/src/mir/lower/tests.rs index 73399dab7f..8e10284cc1 100644 --- a/crates/hir-ty/src/mir/lower/tests.rs +++ b/crates/hir-ty/src/mir/lower/tests.rs @@ -78,7 +78,7 @@ fn check_borrowck(#[rust_analyzer::rust_fixture] ra_fixture: &str) { } for body in bodies { - let _ = db.borrowck(body); + let _ = db.borrowck(body.into()); } }) } diff --git a/crates/hir-ty/src/mir/monomorphization.rs b/crates/hir-ty/src/mir/monomorphization.rs index b3529437c0..06871a3f18 100644 --- a/crates/hir-ty/src/mir/monomorphization.rs +++ b/crates/hir-ty/src/mir/monomorphization.rs @@ -7,14 +7,13 @@ //! //! So the monomorphization should be called even if the substitution is empty. -use hir_def::DefWithBodyId; use rustc_type_ir::inherent::IntoKind; use rustc_type_ir::{ FallibleTypeFolder, TypeFlags, TypeFoldable, TypeSuperFoldable, TypeVisitableExt, }; use crate::{ - ParamEnvAndCrate, + InferBodyId, ParamEnvAndCrate, next_solver::{ Allocation, AllocationData, Const, ConstKind, Region, RegionKind, StoredConst, StoredGenericArgs, StoredTy, @@ -242,7 +241,7 @@ impl<'db> Filler<'db> { #[salsa_macros::tracked(returns(ref), cycle_result = monomorphized_mir_body_cycle_result)] pub fn monomorphized_mir_body_query( db: &dyn HirDatabase, - owner: DefWithBodyId, + owner: InferBodyId, subst: StoredGenericArgs, trait_env: StoredParamEnvAndCrate, ) -> Result<MirBody, MirLowerError> { @@ -256,7 +255,7 @@ pub fn monomorphized_mir_body_query( fn monomorphized_mir_body_cycle_result( _db: &dyn HirDatabase, _: salsa::Id, - _: DefWithBodyId, + _: InferBodyId, _: StoredGenericArgs, _: StoredParamEnvAndCrate, ) -> Result<MirBody, MirLowerError> { diff --git a/crates/hir-ty/src/mir/pretty.rs b/crates/hir-ty/src/mir/pretty.rs index c224f2054f..777cf170bc 100644 --- a/crates/hir-ty/src/mir/pretty.rs +++ b/crates/hir-ty/src/mir/pretty.rs @@ -7,7 +7,7 @@ use std::{ use either::Either; use hir_def::{ - expr_store::Body, + expr_store::ExpressionStore, hir::BindingId, signatures::{ConstSignature, EnumSignature, FunctionSignature, StaticSignature}, }; @@ -15,6 +15,7 @@ use hir_expand::{Lookup, name::Name}; use la_arena::ArenaMap; use crate::{ + InferBodyId, db::{HirDatabase, InternedClosureId}, display::{ClosureStyle, DisplayTarget, HirDisplay}, mir::{PlaceElem, ProjectionElem, StatementKind, TerminatorKind}, @@ -42,18 +43,18 @@ macro_rules! wln { impl MirBody { pub fn pretty_print(&self, db: &dyn HirDatabase, display_target: DisplayTarget) -> String { - let hir_body = Body::of(db, self.owner); + let hir_body = ExpressionStore::of(db, self.owner.expression_store_owner(db)); let mut ctx = MirPrettyCtx::new(self, hir_body, db, display_target); ctx.for_body(|this| match ctx.body.owner { - hir_def::DefWithBodyId::FunctionId(id) => { + InferBodyId::DefWithBodyId(hir_def::DefWithBodyId::FunctionId(id)) => { let data = FunctionSignature::of(db, id); w!(this, "fn {}() ", data.name.display(db, this.display_target.edition)); } - hir_def::DefWithBodyId::StaticId(id) => { + InferBodyId::DefWithBodyId(hir_def::DefWithBodyId::StaticId(id)) => { let data = StaticSignature::of(db, id); w!(this, "static {}: _ = ", data.name.display(db, this.display_target.edition)); } - hir_def::DefWithBodyId::ConstId(id) => { + InferBodyId::DefWithBodyId(hir_def::DefWithBodyId::ConstId(id)) => { let data = ConstSignature::of(db, id); w!( this, @@ -64,7 +65,7 @@ impl MirBody { .display(db, this.display_target.edition) ); } - hir_def::DefWithBodyId::VariantId(id) => { + InferBodyId::DefWithBodyId(hir_def::DefWithBodyId::VariantId(id)) => { let loc = id.lookup(db); let edition = this.display_target.edition; w!( @@ -78,6 +79,7 @@ impl MirBody { .display(db, edition), ) } + InferBodyId::AnonConstId(_) => w!(this, "{{const}}"), }); ctx.result } @@ -97,7 +99,7 @@ impl MirBody { struct MirPrettyCtx<'a, 'db> { body: &'a MirBody, - hir_body: &'a Body, + hir_body: &'a ExpressionStore, db: &'db dyn HirDatabase, result: String, indent: String, @@ -184,7 +186,7 @@ impl<'a, 'db> MirPrettyCtx<'a, 'db> { fn new( body: &'a MirBody, - hir_body: &'a Body, + hir_body: &'a ExpressionStore, db: &'db dyn HirDatabase, display_target: DisplayTarget, ) -> Self { diff --git a/crates/hir-ty/src/next_solver/binder.rs b/crates/hir-ty/src/next_solver/binder.rs index 84cfbf2767..22019f1ff9 100644 --- a/crates/hir-ty/src/next_solver/binder.rs +++ b/crates/hir-ty/src/next_solver/binder.rs @@ -4,8 +4,9 @@ use macros::{TypeFoldable, TypeVisitable}; use crate::{ FnAbi, next_solver::{ - Binder, Clauses, DbInterner, EarlyBinder, FnSig, PolyFnSig, StoredBoundVarKinds, - StoredClauses, StoredGenericArgs, StoredTy, StoredTys, TraitRef, Ty, abi::Safety, + Binder, Clauses, DbInterner, EarlyBinder, FnSig, GenericArg, PolyFnSig, + StoredBoundVarKinds, StoredClauses, StoredGenericArg, StoredGenericArgs, StoredTy, + StoredTys, TraitRef, Ty, abi::Safety, }, }; @@ -41,6 +42,13 @@ impl StoredEarlyBinder<StoredTy> { } } +impl StoredEarlyBinder<StoredGenericArg> { + #[inline] + pub fn get<'db>(&self) -> EarlyBinder<'db, GenericArg<'db>> { + self.get_with(|it| it.as_ref()) + } +} + impl StoredEarlyBinder<StoredClauses> { #[inline] pub fn get<'db>(&self) -> EarlyBinder<'db, Clauses<'db>> { @@ -48,6 +56,20 @@ impl StoredEarlyBinder<StoredClauses> { } } +impl StoredEarlyBinder<StoredPolyFnSig> { + #[inline] + pub fn get<'db>(&'db self) -> EarlyBinder<'db, PolyFnSig<'db>> { + self.get_with(|it| it.get()) + } +} + +impl StoredEarlyBinder<StoredTraitRef> { + #[inline] + pub fn get<'db>(&'db self, interner: DbInterner<'db>) -> EarlyBinder<'db, TraitRef<'db>> { + self.get_with(|it| it.get(interner)) + } +} + #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct StoredPolyFnSig { bound_vars: StoredBoundVarKinds, diff --git a/crates/hir-ty/src/next_solver/def_id.rs b/crates/hir-ty/src/next_solver/def_id.rs index 7c67e65876..41b00b67cd 100644 --- a/crates/hir-ty/src/next_solver/def_id.rs +++ b/crates/hir-ty/src/next_solver/def_id.rs @@ -12,9 +12,12 @@ use hir_def::{ use rustc_type_ir::inherent; use stdx::impl_from; -use crate::db::{ - AnonConstId, GeneralConstId, InternedClosureId, InternedCoroutineClosureId, - InternedCoroutineId, InternedOpaqueTyId, +use crate::{ + InferBodyId, + db::{ + AnonConstId, GeneralConstId, InternedClosureId, InternedCoroutineClosureId, + InternedCoroutineId, InternedOpaqueTyId, + }, }; use super::DbInterner; @@ -174,6 +177,16 @@ impl From<DefWithBodyId> for SolverDefId { } } +impl From<InferBodyId> for SolverDefId { + #[inline] + fn from(value: InferBodyId) -> Self { + match value { + InferBodyId::DefWithBodyId(id) => id.into(), + InferBodyId::AnonConstId(id) => id.into(), + } + } +} + impl From<VariantId> for SolverDefId { #[inline] fn from(value: VariantId) -> Self { @@ -247,6 +260,32 @@ impl TryFrom<SolverDefId> for DefWithBodyId { } } +impl TryFrom<SolverDefId> for InferBodyId { + type Error = (); + + #[inline] + fn try_from(value: SolverDefId) -> Result<Self, Self::Error> { + let id = match value { + SolverDefId::ConstId(id) => id.into(), + SolverDefId::FunctionId(id) => id.into(), + SolverDefId::StaticId(id) => id.into(), + SolverDefId::EnumVariantId(id) | SolverDefId::Ctor(Ctor::Enum(id)) => id.into(), + SolverDefId::AnonConstId(id) => id.into(), + SolverDefId::InternedOpaqueTyId(_) + | SolverDefId::TraitId(_) + | SolverDefId::TypeAliasId(_) + | SolverDefId::ImplId(_) + | SolverDefId::BuiltinDeriveImplId(_) + | SolverDefId::InternedClosureId(_) + | SolverDefId::InternedCoroutineId(_) + | SolverDefId::InternedCoroutineClosureId(_) + | SolverDefId::Ctor(Ctor::Struct(_)) + | SolverDefId::AdtId(_) => return Err(()), + }; + Ok(id) + } +} + impl TryFrom<SolverDefId> for GenericDefId { type Error = (); diff --git a/crates/hir-ty/src/next_solver/fulfill.rs b/crates/hir-ty/src/next_solver/fulfill.rs index 1fb4cb2b43..066d67f965 100644 --- a/crates/hir-ty/src/next_solver/fulfill.rs +++ b/crates/hir-ty/src/next_solver/fulfill.rs @@ -39,7 +39,7 @@ type PendingObligations<'db> = /// /// It is also likely that we want to use slightly different datastructures /// here as this will have to deal with far more root goals than `evaluate_all`. -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct FulfillmentCtxt<'db> { obligations: ObligationStorage<'db>, diff --git a/crates/hir-ty/src/next_solver/generics.rs b/crates/hir-ty/src/next_solver/generics.rs index 570e245922..2f8c7dc160 100644 --- a/crates/hir-ty/src/next_solver/generics.rs +++ b/crates/hir-ty/src/next_solver/generics.rs @@ -19,6 +19,23 @@ pub(crate) fn generics(interner: DbInterner<'_>, def: SolverDefId) -> Generics<' (_, SolverDefId::BuiltinDeriveImplId(id)) => { return crate::builtin_derive::generics_of(interner, id); } + (_, SolverDefId::AnonConstId(id)) => { + let loc = id.loc(db); + let generic_def = loc.owner.generic_def(db); + return if loc.allow_using_generic_params { + Generics::from_generic_def(db, generic_def) + } else { + #[expect( + deprecated, + reason = "`Generics` only exposes an iterator over `GenericParamId`, \ + so you cannot exploit the erroneous `crate::generics::Generics`" + )] + Generics { + generics: crate::generics::Generics::empty(generic_def), + additional_param: None, + } + }; + } _ => panic!("No generics for {def:?}"), }; diff --git a/crates/hir-ty/src/next_solver/infer/errors.rs b/crates/hir-ty/src/next_solver/infer/errors.rs index d10f70274c..3c2119b6fa 100644 --- a/crates/hir-ty/src/next_solver/infer/errors.rs +++ b/crates/hir-ty/src/next_solver/infer/errors.rs @@ -1,21 +1,22 @@ use std::{fmt, ops::ControlFlow}; -use hir_def::{GeneralConstId, attrs::AttrFlags}; +use hir_def::attrs::AttrFlags; use rustc_next_trait_solver::solve::{GoalEvaluation, SolverDelegateEvalExt}; use rustc_type_ir::{ AliasRelationDirection, AliasTermKind, PredicatePolarity, error::ExpectedFound, - inherent::{IntoKind as _, Ty as _}, + inherent::IntoKind as _, solve::{CandidateSource, Certainty, GoalSource, MaybeCause, NoSolution}, }; use tracing::{instrument, trace}; use crate::{ Span, + db::GeneralConstId, next_solver::{ - AliasTerm, AnyImplId, Binder, ClauseKind, Const, ConstKind, DbInterner, EarlyBinder, - ErrorGuaranteed, HostEffectPredicate, PolyTraitPredicate, PredicateKind, SolverContext, - Term, TraitPredicate, Ty, TyKind, TypeError, + AliasTerm, AnyImplId, Binder, ClauseKind, Const, ConstKind, DbInterner, + HostEffectPredicate, PolyTraitPredicate, PredicateKind, SolverContext, Term, + TraitPredicate, Ty, TyKind, TypeError, fulfill::NextSolverError, infer::{ InferCtxt, @@ -144,10 +145,7 @@ fn fulfillment_error_for_no_solution<'db>( let ct_ty = match uv.def.0 { GeneralConstId::ConstId(konst) => db.value_ty(konst.into()).unwrap(), GeneralConstId::StaticId(statik) => db.value_ty(statik.into()).unwrap(), - // FIXME: Return the type of the const here. - GeneralConstId::AnonConstId(_) => { - EarlyBinder::bind(Ty::new_error(interner, ErrorGuaranteed)) - } + GeneralConstId::AnonConstId(konst) => konst.loc(db).ty.get(), }; ct_ty.instantiate(interner, uv.args) } diff --git a/crates/hir-ty/src/next_solver/interner.rs b/crates/hir-ty/src/next_solver/interner.rs index fb70734872..fb9b608d31 100644 --- a/crates/hir-ty/src/next_solver/interner.rs +++ b/crates/hir-ty/src/next_solver/interner.rs @@ -11,11 +11,10 @@ pub use tls_db::{attach_db, attach_db_allow_change, with_attached_db}; use base_db::Crate; use hir_def::{ - AdtId, CallableDefId, DefWithBodyId, EnumId, ExpressionStoreOwnerId, HasModule, - ItemContainerId, StructId, UnionId, VariantId, + AdtId, CallableDefId, EnumId, HasModule, ItemContainerId, StructId, UnionId, VariantId, attrs::AttrFlags, - expr_store::{Body, ExpressionStore}, - hir::{ClosureKind as HirClosureKind, CoroutineKind as HirCoroutineKind}, + expr_store::ExpressionStore, + hir::{ClosureKind as HirClosureKind, CoroutineKind as HirCoroutineKind, ExprId}, lang_item::LangItems, signatures::{ EnumFlags, EnumSignature, FnFlags, FunctionSignature, ImplFlags, ImplSignature, @@ -37,7 +36,7 @@ use rustc_type_ir::{ }; use crate::{ - FnAbi, Span, + FnAbi, InferBodyId, Span, db::{HirDatabase, InternedClosure, InternedCoroutineId}, lower::GenericPredicates, method_resolution::TraitImpls, @@ -1164,14 +1163,15 @@ 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 it.loc(self.db).owner.generic_def(self.db()).into(); + return it.loc(self.db).owner.into(); } SolverDefId::InternedCoroutineId(it) => { - return it.loc(self.db).owner.generic_def(self.db()).into(); + return it.loc(self.db).owner.into(); } SolverDefId::InternedCoroutineClosureId(it) => { - return it.loc(self.db).owner.generic_def(self.db()).into(); + return it.loc(self.db).owner.into(); } + SolverDefId::AnonConstId(it) => return it.loc(self.db).owner.into(), SolverDefId::StaticId(_) | SolverDefId::AdtId(_) | SolverDefId::TraitId(_) @@ -1179,8 +1179,7 @@ impl<'db> Interner for DbInterner<'db> { | SolverDefId::BuiltinDeriveImplId(_) | SolverDefId::EnumVariantId(..) | SolverDefId::Ctor(..) - | SolverDefId::InternedOpaqueTyId(..) - | SolverDefId::AnonConstId(_) => panic!(), + | SolverDefId::InternedOpaqueTyId(..) => panic!(), }; match container { @@ -1956,7 +1955,7 @@ impl<'db> Interner for DbInterner<'db> { } fn opaque_types_defined_by(self, def_id: Self::LocalDefId) -> Self::LocalDefIds { - let Ok(def_id) = DefWithBodyId::try_from(def_id) else { + let Ok(def_id) = InferBodyId::try_from(def_id) else { return SolverDefIds::default(); }; let mut result = Vec::new(); @@ -1965,16 +1964,31 @@ impl<'db> Interner for DbInterner<'db> { } fn opaque_types_and_coroutines_defined_by(self, def_id: Self::LocalDefId) -> Self::LocalDefIds { - let Ok(def_id) = DefWithBodyId::try_from(def_id) else { + let db = self.db; + + let Ok(def_id) = InferBodyId::try_from(def_id) else { return SolverDefIds::default(); }; let mut result = Vec::new(); - crate::opaques::opaque_types_defined_by(self.db, def_id, &mut result); + crate::opaques::opaque_types_defined_by(db, def_id, &mut result); // Collect coroutines. - let body = Body::of(self.db, def_id); - body.exprs().for_each(|(expr_id, expr)| { + let (store, root_expr) = def_id.store_and_root_expr(db); + // We can't just visit all exprs, since this may end up in unrelated anon consts. + append_coroutines_in_expr(db, def_id, store, root_expr, &mut result); + + return SolverDefIds::new_from_slice(&result); + + fn append_coroutines_in_expr( + db: &dyn HirDatabase, + owner: InferBodyId, + store: &ExpressionStore, + expr_id: ExprId, + result: &mut Vec<SolverDefId>, + ) { + let expr = &store[expr_id]; + if let hir_def::hir::Expr::Closure { closure_kind: kind @ (hir_def::hir::ClosureKind::Coroutine { .. } @@ -1982,19 +1996,22 @@ impl<'db> Interner for DbInterner<'db> { .. } = *expr { - let coroutine = InternedCoroutineId::new( - self.db, - InternedClosure { - owner: ExpressionStoreOwnerId::Body(def_id), - expr: expr_id, - kind, - }, - ); + let coroutine = + InternedCoroutineId::new(db, InternedClosure { owner, expr: expr_id, kind }); result.push(coroutine.into()); } - }); - SolverDefIds::new_from_slice(&result) + match expr { + // The repeat is an anon const. + &hir_def::hir::Expr::Array(hir_def::hir::Array::Repeat { + initializer, + repeat: _, + }) => append_coroutines_in_expr(db, owner, store, initializer, result), + _ => store.walk_child_exprs(expr_id, |expr_id| { + append_coroutines_in_expr(db, owner, store, expr_id, result) + }), + } + } } fn alias_has_const_conditions(self, _def_id: Self::DefId) -> bool { @@ -2266,10 +2283,17 @@ impl<'db> DbInterner<'db> { } fn predicates_of(db: &dyn HirDatabase, def_id: SolverDefId) -> &GenericPredicates { - if let SolverDefId::BuiltinDeriveImplId(impl_) = def_id { - crate::builtin_derive::predicates(db, impl_) - } else { - GenericPredicates::query(db, def_id.try_into().unwrap()) + match def_id { + SolverDefId::BuiltinDeriveImplId(impl_) => crate::builtin_derive::predicates(db, impl_), + SolverDefId::AnonConstId(anon_const) => { + let loc = anon_const.loc(db); + if loc.allow_using_generic_params { + GenericPredicates::query(db, loc.owner.generic_def(db)) + } else { + GenericPredicates::empty() + } + } + _ => GenericPredicates::query(db, def_id.try_into().unwrap()), } } diff --git a/crates/hir-ty/src/next_solver/solver.rs b/crates/hir-ty/src/next_solver/solver.rs index 5e7e03e0b2..ecfc1c21b7 100644 --- a/crates/hir-ty/src/next_solver/solver.rs +++ b/crates/hir-ty/src/next_solver/solver.rs @@ -261,11 +261,10 @@ impl<'db> SolverDelegate for SolverContext<'db> { self.cx().db.const_eval(c, subst, None).ok()? } GeneralConstId::StaticId(c) => self.cx().db.const_eval_static(c).ok()?, - // 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(_) => return Some(Const::error(self.cx())), + GeneralConstId::AnonConstId(c) => { + let subst = uv.args; + self.cx().db.anon_const_eval(c, subst, None).ok()? + } }; Some(Const::new_from_allocation( self.interner, diff --git a/crates/hir-ty/src/opaques.rs b/crates/hir-ty/src/opaques.rs index 699b6307dc..86baa64895 100644 --- a/crates/hir-ty/src/opaques.rs +++ b/crates/hir-ty/src/opaques.rs @@ -10,7 +10,7 @@ use rustc_type_ir::inherent::Ty as _; use syntax::ast; use crate::{ - ImplTraitId, InferenceResult, Span, + ImplTraitId, InferBodyId, InferenceResult, Span, db::{HirDatabase, InternedOpaqueTyId}, lower::{ImplTraitIdx, ImplTraits}, next_solver::{ @@ -22,10 +22,10 @@ use crate::{ pub(crate) fn opaque_types_defined_by( db: &dyn HirDatabase, - def_id: DefWithBodyId, + def_id: InferBodyId, result: &mut Vec<SolverDefId>, ) { - if let DefWithBodyId::FunctionId(func) = def_id { + if let Some(func) = def_id.as_function() { // A function may define its own RPITs. extend_with_opaques( db, @@ -66,9 +66,15 @@ pub(crate) fn opaque_types_defined_by( _ => {} }; match def_id { - DefWithBodyId::ConstId(id) => extend_with_atpit_from_container(id.loc(db).container), - DefWithBodyId::FunctionId(id) => extend_with_atpit_from_container(id.loc(db).container), - DefWithBodyId::StaticId(_) | DefWithBodyId::VariantId(_) => {} + InferBodyId::DefWithBodyId(DefWithBodyId::ConstId(id)) => { + extend_with_atpit_from_container(id.loc(db).container) + } + InferBodyId::DefWithBodyId(DefWithBodyId::FunctionId(id)) => { + extend_with_atpit_from_container(id.loc(db).container) + } + InferBodyId::DefWithBodyId(DefWithBodyId::StaticId(_)) + | InferBodyId::DefWithBodyId(DefWithBodyId::VariantId(_)) + | InferBodyId::AnonConstId(_) => {} } // FIXME: Collect opaques from `#[define_opaque]`. diff --git a/crates/hir-ty/src/tests.rs b/crates/hir-ty/src/tests.rs index 2fa70cd3a8..9e70f69bad 100644 --- a/crates/hir-ty/src/tests.rs +++ b/crates/hir-ty/src/tests.rs @@ -16,8 +16,8 @@ mod traits; use base_db::{Crate, SourceDatabase}; use expect_test::Expect; use hir_def::{ - AssocItemId, DefWithBodyId, GenericDefId, HasModule, Lookup, ModuleDefId, ModuleId, - SyntheticSyntax, + AdtId, AssocItemId, DefWithBodyId, GenericDefId, HasModule, Lookup, ModuleDefId, ModuleId, + SyntheticSyntax, VariantId, expr_store::{Body, BodySourceMap, ExpressionStore, ExpressionStoreSourceMap}, hir::{ExprId, Pat, PatId}, item_scope::ItemScope, @@ -37,6 +37,7 @@ use test_fixture::WithFixture; use crate::{ InferenceDiagnostic, InferenceResult, + db::{AnonConstId, HirDatabase}, display::{DisplayTarget, HirDisplay}, infer::Adjustment, next_solver::Ty, @@ -432,6 +433,7 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { let mut defs: Vec<(DefWithBodyId, Crate)> = Vec::new(); let mut generic_defs: Vec<(GenericDefId, Crate)> = Vec::new(); + let mut variants: Vec<(VariantId, Crate)> = Vec::new(); visit_module(&db, def_map, module, &mut |it| { let krate = module.krate(&db); match it { @@ -452,6 +454,16 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { } ModuleDefId::AdtId(it) => { generic_defs.push((it.into(), krate)); + match it { + AdtId::StructId(id) => variants.push((id.into(), krate)), + AdtId::UnionId(id) => variants.push((id.into(), krate)), + AdtId::EnumId(id) => variants.extend( + id.enum_variants(&db) + .variants + .iter() + .map(|&(variant, ..)| (variant.into(), krate)), + ), + } } ModuleDefId::TraitId(it) => { generic_defs.push((it.into(), krate)); @@ -511,11 +523,26 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String { for (def, krate) in generic_defs { let (store, source_map) = ExpressionStore::with_source_map(&db, def.into()); // Skip if there are no const expressions in the signature - if store.const_expr_origins().is_empty() { + if store.expr_roots().next().is_none() { continue; } - let infer = InferenceResult::of(&db, def); - infer_def(infer, store, source_map, None, krate); + for &anon_const in AnonConstId::all_from_signature(&db, def).into_iter().flatten() { + let infer = InferenceResult::of(&db, anon_const); + infer_def(infer, store, source_map, None, krate); + } + } + variants.dedup(); + for (def, krate) in variants { + let (store, source_map) = ExpressionStore::with_source_map(&db, def.into()); + // Skip if there are no const expressions in the signature + if store.expr_roots().next().is_none() { + continue; + } + let anon_consts = db.field_types_with_diagnostics(def).defined_anon_consts(); + for &anon_const in anon_consts { + let infer = InferenceResult::of(&db, anon_const); + infer_def(infer, store, source_map, None, krate); + } } buf.truncate(buf.trim_end().len()); @@ -572,7 +599,7 @@ pub(crate) fn visit_module( let body = Body::of(db, it.into()); visit_body(db, body, cb); } - ModuleDefId::AdtId(hir_def::AdtId::EnumId(it)) => { + ModuleDefId::AdtId(AdtId::EnumId(it)) => { it.enum_variants(db).variants.iter().for_each(|&(it, _, _)| { let body = Body::of(db, it.into()); cb(it.into()); diff --git a/crates/hir-ty/src/tests/incremental.rs b/crates/hir-ty/src/tests/incremental.rs index 02d8f6597d..4c26b19120 100644 --- a/crates/hir-ty/src/tests/incremental.rs +++ b/crates/hir-ty/src/tests/incremental.rs @@ -611,15 +611,14 @@ fn main() { "StructSignature::with_source_map_", "AttrFlags::query_", "GenericPredicates::query_with_diagnostics_", - "value_ty_query", "InherentImpls::for_crate_", - "callable_item_signature_query", + "callable_item_signature_with_diagnostics", "TraitImpls::for_crate_and_deps_", "TraitImpls::for_crate_", - "impl_trait_with_diagnostics_query", + "impl_trait_with_diagnostics", "ImplSignature::of_", "ImplSignature::with_source_map_", - "impl_self_ty_with_diagnostics_query", + "impl_self_ty_with_diagnostics", "AttrFlags::query_", "GenericPredicates::query_with_diagnostics_", "body_upvars_mentioned", @@ -703,12 +702,12 @@ fn main() { "AttrFlags::query_", "GenericPredicates::query_with_diagnostics_", "InherentImpls::for_crate_", - "callable_item_signature_query", + "callable_item_signature_with_diagnostics", "TraitImpls::for_crate_", "ImplSignature::with_source_map_", "ImplSignature::of_", - "impl_trait_with_diagnostics_query", - "impl_self_ty_with_diagnostics_query", + "impl_trait_with_diagnostics", + "impl_self_ty_with_diagnostics", "AttrFlags::query_", "GenericPredicates::query_with_diagnostics_", "body_upvars_mentioned", diff --git a/crates/hir-ty/src/tests/patterns.rs b/crates/hir-ty/src/tests/patterns.rs index 9449f531a6..021b71b9cf 100644 --- a/crates/hir-ty/src/tests/patterns.rs +++ b/crates/hir-ty/src/tests/patterns.rs @@ -417,8 +417,6 @@ fn infer_pattern_match_byte_string_literal() { 254..256 '&v': &'? [u8; 3] 255..256 'v': [u8; 3] 257..259 '{}': () - 199..200 '3': usize - 62..63 'N': usize "#]], ); } diff --git a/crates/hir-ty/src/tests/regression.rs b/crates/hir-ty/src/tests/regression.rs index 87e6521e63..5a90e700ac 100644 --- a/crates/hir-ty/src/tests/regression.rs +++ b/crates/hir-ty/src/tests/regression.rs @@ -2758,7 +2758,6 @@ where 664..680 'filter...ter_fn': dyn Fn(&'? T) -> bool + 'static 691..698 'loop {}': ! 696..698 '{}': () - 512..513 'N': usize "#]], ); } diff --git a/crates/hir-ty/src/tests/regression/new_solver.rs b/crates/hir-ty/src/tests/regression/new_solver.rs index 565360dc25..33a12fcd1e 100644 --- a/crates/hir-ty/src/tests/regression/new_solver.rs +++ b/crates/hir-ty/src/tests/regression/new_solver.rs @@ -34,7 +34,6 @@ impl Space for [u8; 1] { 223..227 'iter': IntoIter<u8> 230..231 'a': Vec<u8> 230..243 'a.into_iter()': IntoIter<u8> - 322..323 '1': usize "#]], ); } @@ -473,8 +472,6 @@ fn foo() { 249..257 'to_bytes': fn to_bytes() -> [u8; _] 249..259 'to_bytes()': [u8; _] 249..268 'to_byt..._vec()': Vec<<[u8; _] as Foo>::Item> - 205..206 '_': usize - 156..157 'N': usize "#]], ); } @@ -516,15 +513,15 @@ fn test_at_most() { "#, expect![[r#" 48..49 '0': usize - 182..186 'self': Between<M, _, T> + 182..186 'self': Between<M, 0, T> 188..192 '_sep': &'? str - 200..206 '_other': Between<M, _, T> - 222..242 '{ ... }': Between<M, _, T> - 232..236 'self': Between<M, _, T> + 200..206 '_other': Between<M, 0, T> + 222..242 '{ ... }': Between<M, 0, T> + 232..236 'self': Between<M, 0, T> 300..304 'self': Self - 343..372 '{ ... }': Between<M, _, Self> - 353..360 'Between': fn Between<M, _, Self>(Self) -> Between<M, _, Self> - 353..366 'Between(self)': Between<M, _, Self> + 343..372 '{ ... }': Between<M, 0, Self> + 353..360 'Between': fn Between<M, 0, Self>(Self) -> Between<M, 0, Self> + 353..366 'Between(self)': Between<M, 0, Self> 361..365 'self': Self 404..408 'self': Self 433..462 '{ ... }': Between<0, N, Self> @@ -532,21 +529,22 @@ fn test_at_most() { 443..456 'Between(self)': Between<0, N, Self> 451..455 'self': Self 510..587 '{ ...um); }': () - 520..523 'num': Between<1, _, char> + 520..523 'num': Between<1, 0, char> 526..529 ''9'': char - 526..545 ''9'.at...:<1>()': Between<1, _, char> - 555..559 '_ver': Between<1, _, char> - 562..565 'num': Between<1, _, char> - 562..584 'num.se..., num)': Between<1, _, char> + 526..545 ''9'.at...:<1>()': Between<1, 0, char> + 541..542 '1': usize + 555..559 '_ver': Between<1, 0, char> + 562..565 'num': Between<1, 0, char> + 562..584 'num.se..., num)': Between<1, 0, char> 575..578 '"."': &'static str - 580..583 'num': Between<1, _, char> + 580..583 'num': Between<1, 0, char> 607..644 '{ ...>(); }': () 617..620 'num': Between<0, 1, char> 623..626 ''9'': char 623..641 ''9'.at...:<1>()': Between<0, 1, char> + 637..638 '1': usize 320..335 '{ Consts::MAX }': usize 322..333 'Consts::MAX': usize - 421..422 '0': i32 144..159 '{ Consts::MAX }': usize 146..157 'Consts::MAX': usize "#]], diff --git a/crates/hir-ty/src/tests/simple.rs b/crates/hir-ty/src/tests/simple.rs index fbe7c3bd37..76da816055 100644 --- a/crates/hir-ty/src/tests/simple.rs +++ b/crates/hir-ty/src/tests/simple.rs @@ -1240,6 +1240,9 @@ fn infer_array() { 274..275 'x': [u8; 0] 287..289 '[]': [u8; 0] 299..300 'y': [u8; 4] + 307..308 '2': usize + 307..310 '2+2': usize + 309..310 '2': usize 314..323 '[1,2,3,4]': [u8; 4] 315..316 '1': u8 317..318 '2': u8 @@ -1811,8 +1814,6 @@ impl Foo for u8 { } #[test] -// FIXME -#[should_panic] fn const_eval_in_function_signature() { check_types( r#" @@ -3999,8 +4000,6 @@ fn main() { 208..209 'c': u8 213..214 'a': A 213..221 'a.into()': [u8; 2] - 33..34 '2': usize - 111..112 '3': usize "#]], ); } @@ -4187,14 +4186,14 @@ fn foo() { 130..153 '{ ... }': &'? T 140..147 'loop {}': ! 145..147 '{}': () - 207..220 'LazyLock::new': fn new<[u32; _]>() -> LazyLock<[u32; _]> - 207..222 'LazyLock::new()': LazyLock<[u32; _]> + 207..220 'LazyLock::new': fn new<[u32; 0]>() -> LazyLock<[u32; 0]> + 207..222 'LazyLock::new()': LazyLock<[u32; 0]> 234..285 '{ ...CK); }': () - 244..245 '_': &'? [u32; _] - 248..263 'LazyLock::force': fn force<[u32; _]>(&'? LazyLock<[u32; _]>) -> &'? [u32; _] - 248..282 'LazyLo..._LOCK)': &'? [u32; _] - 264..281 '&VALUE...Y_LOCK': &'? LazyLock<[u32; _]> - 265..281 'VALUES...Y_LOCK': LazyLock<[u32; _]> + 244..245 '_': &'? [u32; 0] + 248..263 'LazyLock::force': fn force<[u32; 0]>(&'? LazyLock<[u32; 0]>) -> &'? [u32; 0] + 248..282 'LazyLo..._LOCK)': &'? [u32; 0] + 264..281 '&VALUE...Y_LOCK': &'? LazyLock<[u32; 0]> + 265..281 'VALUES...Y_LOCK': LazyLock<[u32; 0]> 197..202 '{ 0 }': usize 199..200 '0': usize "#]], @@ -4272,11 +4271,9 @@ union U { "#, expect![[r#" 242..243 '0': isize - 46..47 '2': i32 - 65..68 '0.0': f32 - 90..91 '2': i32 - 200..201 '0': i32 - 212..213 '0': i32 + 111..125 '{ C as usize }': usize + 113..114 'C': f32 + 113..123 'C as usize': usize "#]], ); } @@ -4294,3 +4291,18 @@ fn foo() { "#, ); } + +#[test] +fn enum_variant_anon_const() { + check_infer( + r#" +enum Enum { + Variant([(); { 2 }]), +} + "#, + expect![[r#" + 29..34 '{ 2 }': usize + 31..32 '2': usize + "#]], + ); +} diff --git a/crates/hir-ty/src/tests/traits.rs b/crates/hir-ty/src/tests/traits.rs index 18e4a5b41d..ea978cde58 100644 --- a/crates/hir-ty/src/tests/traits.rs +++ b/crates/hir-ty/src/tests/traits.rs @@ -1290,7 +1290,6 @@ fn bar() { 241..245 'R::B': fn B<(), i32>(i32) -> R<(), i32> 241..248 'R::B(7)': R<(), i32> 246..247 '7': i32 - 46..47 '2': usize "#]], ); } @@ -3802,8 +3801,6 @@ fn main() { 371..373 'v4': usize 376..378 'v3': [u8; 4] 376..389 'v3.do_thing()': usize - 86..87 '4': usize - 192..193 '2': usize "#]], ) } @@ -3843,9 +3840,6 @@ fn main() { 240..242 'v2': [u8; 2] 245..246 'v': [u8; 2] 245..257 'v.do_thing()': [u8; 2] - 130..131 'L': usize - 102..103 'L': usize - 130..131 'L': usize "#]], ) } diff --git a/crates/hir-ty/src/upvars.rs b/crates/hir-ty/src/upvars.rs index 026e6ab183..6dcd8b59a5 100644 --- a/crates/hir-ty/src/upvars.rs +++ b/crates/hir-ty/src/upvars.rs @@ -110,10 +110,7 @@ pub fn upvars_mentioned_impl( owner: ExpressionStoreOwnerId, ) -> Option<Box<FxHashMap<ExprId, Upvars>>> { let store = ExpressionStore::of(db, owner); - if store.const_expr_origins().is_empty() { - // Save constructing a Resolver. - return None; - } + store.expr_roots().next()?; let mut resolver = owner.resolver(db); let mut result = FxHashMap::default(); for root_expr in store.expr_roots() { diff --git a/crates/hir-ty/src/variance.rs b/crates/hir-ty/src/variance.rs index a89a938639..77a6af13d2 100644 --- a/crates/hir-ty/src/variance.rs +++ b/crates/hir-ty/src/variance.rs @@ -476,7 +476,6 @@ struct Other<'a> { #[test] fn rustc_test_variance_associated_consts() { - // FIXME: Should be invariant check( r#" trait Trait { @@ -488,7 +487,7 @@ struct Foo<T: Trait> { //~ ERROR [T: o] } "#, expect![[r#" - Foo[T: bivariant] + Foo[T: invariant] "#]], ); } diff --git a/crates/hir/src/from_id.rs b/crates/hir/src/from_id.rs index 0a48be5473..219eb9c3b9 100644 --- a/crates/hir/src/from_id.rs +++ b/crates/hir/src/from_id.rs @@ -254,14 +254,9 @@ impl TryFrom<AssocItem> for GenericDefId { } } -impl From<(ExpressionStoreOwnerId, BindingId)> for Local { - fn from((parent, binding_id): (ExpressionStoreOwnerId, BindingId)) -> Self { - Local { parent, binding_id } - } -} impl From<(DefWithBodyId, BindingId)> for Local { fn from((parent, binding_id): (DefWithBodyId, BindingId)) -> Self { - Local { parent: parent.into(), binding_id } + Local { parent: parent.into(), parent_infer: parent.into(), binding_id } } } diff --git a/crates/hir/src/has_source.rs b/crates/hir/src/has_source.rs index 3e7745c090..9bff8bda3a 100644 --- a/crates/hir/src/has_source.rs +++ b/crates/hir/src/has_source.rs @@ -294,7 +294,8 @@ impl HasSource for Param<'_> { } Callee::Closure(closure, _) => { let InternedClosure { owner, expr: expr_id, .. } = closure.loc(db); - let (_, source_map) = ExpressionStore::with_source_map(db, owner); + let (_, source_map) = + ExpressionStore::with_source_map(db, owner.expression_store_owner(db)); 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 753ff246c2..14a285d5bd 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -83,10 +83,10 @@ use hir_expand::{ proc_macro::ProcMacroKind, }; use hir_ty::{ - GenericPredicates, InferenceResult, ParamEnvAndCrate, TyDefId, TyLoweringDiagnostic, - ValueTyDefId, all_super_traits, autoderef, check_orphan_rules, + GenericPredicates, InferBodyId, InferenceResult, ParamEnvAndCrate, TyDefId, + TyLoweringDiagnostic, ValueTyDefId, all_super_traits, autoderef, check_orphan_rules, consteval::try_const_usize, - db::{InternedClosure, InternedClosureId, InternedCoroutineClosureId}, + db::{AnonConstId, InternedClosure, InternedClosureId, InternedCoroutineClosureId}, diagnostics::BodyValidationDiagnostic, direct_super_traits, known_const_to_ast, layout::{Layout as TyLayout, RustcEnumVariantIdx, RustcFieldIdx, TagEncoding}, @@ -114,7 +114,7 @@ use syntax::{ ast::{self, HasName as _, HasVisibility as _}, format_smolstr, }; -use triomphe::{Arc, ThinArc}; +use triomphe::Arc; use crate::db::{DefDatabase, HirDatabase}; @@ -759,7 +759,7 @@ impl Module { push_ty_diagnostics( db, acc, - db.field_types_with_diagnostics(s.id.into()).1.clone(), + db.field_types_with_diagnostics(s.id.into()).diagnostics(), source_map, ); } @@ -771,7 +771,7 @@ impl Module { push_ty_diagnostics( db, acc, - db.field_types_with_diagnostics(u.id.into()).1.clone(), + db.field_types_with_diagnostics(u.id.into()).diagnostics(), source_map, ); } @@ -801,7 +801,7 @@ impl Module { push_ty_diagnostics( db, acc, - db.field_types_with_diagnostics(v.into()).1.clone(), + db.field_types_with_diagnostics(v.into()).diagnostics(), source_map, ); expr_store_diagnostics(db, acc, source_map); @@ -817,7 +817,7 @@ impl Module { push_ty_diagnostics( db, acc, - db.type_for_type_alias_with_diagnostics(type_alias.id).1, + db.type_for_type_alias_with_diagnostics(type_alias.id).diagnostics(), source_map, ); acc.extend(def.diagnostics(db, style_lints)); @@ -1027,11 +1027,19 @@ impl Module { impl_assoc_items_scratch.clear(); } - push_ty_diagnostics(db, acc, db.impl_self_ty_with_diagnostics(impl_id).1, source_map); push_ty_diagnostics( db, acc, - db.impl_trait_with_diagnostics(impl_id).and_then(|it| it.1), + db.impl_self_ty_with_diagnostics(impl_id).diagnostics(), + source_map, + ); + push_ty_diagnostics( + db, + acc, + db.impl_trait_with_diagnostics(impl_id) + .as_ref() + .map(|it| it.diagnostics()) + .unwrap_or_default(), source_map, ); @@ -1344,7 +1352,7 @@ impl<'db> InstantiatedField<'db> { #[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)] pub struct TupleField { - pub owner: ExpressionStoreOwnerId, + pub owner: InferBodyId, pub tuple: TupleId, pub index: u32, } @@ -1362,7 +1370,7 @@ impl TupleField { .get(self.index as usize) .copied() .unwrap_or_else(|| Ty::new_error(interner, ErrorGuaranteed)); - Type { env: body_param_env_from_has_crate(db, self.owner), ty } + Type { env: body_param_env_from_has_crate(db, self.owner.expression_store_owner(db)), ty } } } @@ -1997,6 +2005,39 @@ impl Variant { } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct AnonConst { + id: AnonConstId, +} + +impl AnonConst { + pub fn owner(self, db: &dyn HirDatabase) -> ExpressionStoreOwner { + self.id.loc(db).owner.into() + } + + pub fn ty<'db>(self, db: &'db dyn HirDatabase) -> Type<'db> { + let loc = self.id.loc(db); + let env = body_param_env_from_has_crate(db, loc.owner); + Type { env, ty: loc.ty.get().instantiate_identity() } + } + + pub fn eval(self, db: &dyn HirDatabase) -> Result<EvaluatedConst<'_>, ConstEvalError> { + let interner = DbInterner::new_no_crate(db); + let ty = self.id.loc(db).ty.get().instantiate_identity(); + db.anon_const_eval(self.id, GenericArgs::empty(interner), None).map(|it| EvaluatedConst { + allocation: it, + def: self.id.into(), + ty, + }) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub enum InferBody { + Body(DefWithBody), + AnonConst(AnonConst), +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum ExpressionStoreOwner { Body(DefWithBody), Signature(GenericDef), @@ -2090,6 +2131,12 @@ impl DefWithBody { }) } + #[deprecated = "you should really not use this, this is exported for analysis-stats only"] + pub fn run_mir_body(self, db: &dyn HirDatabase) -> Result<(), MirLowerError> { + let Some(id) = self.id() else { return Ok(()) }; + db.mir_body(id.into()).map(drop) + } + /// A textual representation of the HIR of this def's body for debugging purposes. pub fn debug_hir(self, db: &dyn HirDatabase) -> String { let Some(id) = self.id() else { @@ -2104,7 +2151,7 @@ impl DefWithBody { let Some(id) = self.id() else { return String::new(); }; - let body = db.mir_body(id); + let body = db.mir_body(id.into()); match body { Ok(body) => body.pretty_print(db, self.module(db).krate(db).to_display_target(db)), Err(e) => format!("error:\n{e:?}"), @@ -2190,7 +2237,7 @@ impl DefWithBody { } } - if let Ok(borrowck_results) = db.borrowck(id) { + if let Ok(borrowck_results) = db.borrowck(id.into()) { for borrowck_result in borrowck_results.iter() { let mir_body = borrowck_result.mir_body(db); for moof in &borrowck_result.moved_out_of_ref { @@ -2247,7 +2294,8 @@ impl DefWithBody { { need_mut = &mir::MutabilityReason::Not; } - let local = Local { parent: id.into(), binding_id }; + let local = + Local { parent: id.into(), parent_infer: mir_body.owner, binding_id }; let is_mut = body[binding_id].mode == BindingAnnotation::Mutable; match (need_mut, is_mut) { @@ -2948,24 +2996,37 @@ impl<'db> Param<'db> { let parent = DefWithBodyId::FunctionId(it); let body = Body::of(db, parent); if let Some(self_param) = body.self_param.filter(|_| self.idx == 0) { - Some(Local { parent: parent.into(), binding_id: self_param }) + Some(Local { + parent: parent.into(), + parent_infer: parent.into(), + binding_id: self_param, + }) } else if let Pat::Bind { id, .. } = &body[body.params[self.idx - body.self_param.is_some() as usize]] { - Some(Local { parent: parent.into(), binding_id: *id }) + Some(Local { + parent: parent.into(), + parent_infer: parent.into(), + binding_id: *id, + }) } else { None } } Callee::Closure(closure, _) => { let c = closure.loc(db); - let body_owner = c.owner; - let store = ExpressionStore::of(db, c.owner); + let body_infer_owner = c.owner; + let body_owner = c.owner.expression_store_owner(db); + let store = ExpressionStore::of(db, body_owner); if let Expr::Closure { args, .. } = &store[c.expr] && let Pat::Bind { id, .. } = &store[args[self.idx]] { - return Some(Local { parent: body_owner, binding_id: *id }); + return Some(Local { + parent: body_owner, + parent_infer: body_infer_owner, + binding_id: *id, + }); } None } @@ -3146,7 +3207,7 @@ impl HasVisibility for Const { } pub struct EvaluatedConst<'db> { - def: DefWithBodyId, + def: InferBodyId, allocation: hir_ty::next_solver::Allocation<'db>, ty: Ty<'db>, } @@ -4008,7 +4069,7 @@ impl AssocItem { push_ty_diagnostics( db, acc, - db.type_for_type_alias_with_diagnostics(type_alias.id).1, + db.type_for_type_alias_with_diagnostics(type_alias.id).diagnostics(), &TypeAliasSignature::with_source_map(db, type_alias.id).1, ); for diag in hir_ty::diagnostics::incorrect_case(db, type_alias.id.into()) { @@ -4172,26 +4233,24 @@ impl GenericDef { }; expr_store_diagnostics(db, acc, source_map); - push_ty_diagnostics(db, acc, db.generic_defaults_with_diagnostics(def).1, source_map); push_ty_diagnostics( db, acc, - GenericPredicates::query_with_diagnostics(db, def).1.clone(), + db.generic_defaults_with_diagnostics(def).diagnostics(), + source_map, + ); + push_ty_diagnostics( + db, + acc, + GenericPredicates::query_with_diagnostics(db, def).diagnostics(), + source_map, + ); + push_ty_diagnostics( + db, + acc, + db.const_param_types_with_diagnostics(def).diagnostics(), source_map, ); - for (param_id, param) in generics.iter_type_or_consts() { - if let TypeOrConstParamData::ConstParamData(_) = param { - push_ty_diagnostics( - db, - acc, - db.const_param_ty_with_diagnostics(ConstParamId::from_unchecked( - TypeOrConstParamId { parent: def, local_id: param_id }, - )) - .1, - source_map, - ); - } - } } /// Returns a string describing the kind of this type. @@ -4286,6 +4345,7 @@ impl<'db> GenericSubstitution<'db> { #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub struct Local { pub(crate) parent: ExpressionStoreOwnerId, + pub(crate) parent_infer: InferBodyId, pub(crate) binding_id: BindingId, } @@ -4387,7 +4447,7 @@ impl Local { pub fn ty(self, db: &dyn HirDatabase) -> Type<'_> { let def = self.parent; - let infer = InferenceResult::of(db, def); + let infer = InferenceResult::of(db, self.parent_infer); let ty = infer.binding_ty(self.binding_id); Type::new(db, def, ty) } @@ -4781,13 +4841,18 @@ impl ConstParam { Type::new(db, self.id.parent(), db.const_param_ty(self.id)) } - pub fn default( + pub fn default(self, db: &dyn HirDatabase, display_target: DisplayTarget) -> Option<String> { + let arg = generic_arg_from_param(db, self.id.into())?; + Some(arg.display(db, display_target).to_string()) + } + + pub fn default_source_code( self, db: &dyn HirDatabase, - display_target: DisplayTarget, + target_module: Module, ) -> Option<ast::ConstArg> { let arg = generic_arg_from_param(db, self.id.into())?; - known_const_to_ast(arg.konst()?, db, display_target) + known_const_to_ast(arg.konst()?, db, target_module.id) } } @@ -5148,14 +5213,15 @@ impl<'db> Closure<'db> { AnyClosureId::ClosureId(it) => it.loc(db), AnyClosureId::CoroutineClosureId(it) => it.loc(db), }; - let InternedClosure { owner, expr: closure, .. } = closure; - let infer = InferenceResult::of(db, owner); + let InternedClosure { owner: infer_owner, expr: closure, .. } = closure; + let infer = InferenceResult::of(db, infer_owner); + let owner = infer_owner.expression_store_owner(db); let param_env = body_param_env_from_has_crate(db, owner); infer.closures_data[&closure] .min_captures .values() .flatten() - .map(|capture| ClosureCapture { owner, closure, capture, param_env }) + .map(|capture| ClosureCapture { owner, infer_owner, closure, capture, param_env }) .collect() } @@ -5243,6 +5309,7 @@ impl FnTrait { #[derive(Clone, Debug, PartialEq, Eq)] pub struct ClosureCapture<'db> { owner: ExpressionStoreOwnerId, + infer_owner: InferBodyId, closure: ExprId, capture: &'db hir_ty::closure_analysis::CapturedPlace, param_env: ParamEnvAndCrate<'db>, @@ -5250,7 +5317,11 @@ pub struct ClosureCapture<'db> { impl<'db> ClosureCapture<'db> { pub fn local(&self) -> Local { - Local { parent: self.owner, binding_id: self.capture.captured_local() } + Local { + parent: self.owner, + parent_infer: self.infer_owner, + binding_id: self.capture.captured_local(), + } } /// Returns whether this place has any field (aka. non-deref) projections. @@ -7035,6 +7106,12 @@ impl HasCrate for Module { } } +impl HasCrate for AnonConst { + fn krate(&self, db: &dyn HirDatabase) -> Crate { + hir_def::HasModule::krate(&self.id.loc(db).owner, db).into() + } +} + pub trait HasContainer { fn container(&self, db: &dyn HirDatabase) -> ItemContainer; } @@ -7211,17 +7288,14 @@ pub enum DocLinkDef { fn push_ty_diagnostics<'db>( db: &'db dyn HirDatabase, acc: &mut Vec<AnyDiagnostic<'db>>, - diagnostics: Option<ThinArc<(), TyLoweringDiagnostic>>, + diagnostics: &[TyLoweringDiagnostic], source_map: &ExpressionStoreSourceMap, ) { - if let Some(diagnostics) = diagnostics { - acc.extend( - diagnostics - .slice - .iter() - .filter_map(|diagnostic| AnyDiagnostic::ty_diagnostic(diagnostic, source_map, db)), - ); - } + acc.extend( + diagnostics + .iter() + .filter_map(|diagnostic| AnyDiagnostic::ty_diagnostic(diagnostic, source_map, db)), + ); } pub trait MethodCandidateCallback { diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index d2056b1e7c..6265e228bd 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs @@ -13,8 +13,8 @@ use std::{ use base_db::{FxIndexSet, all_crates, toolchain_channel}; use either::Either; use hir_def::{ - BuiltinDeriveImplId, DefWithBodyId, ExpressionStoreOwnerId, HasModule, MacroId, StructId, - TraitId, VariantId, + BuiltinDeriveImplId, DefWithBodyId, ExpressionStoreOwnerId, GenericDefId, HasModule, MacroId, + StructId, TraitId, VariantId, attrs::parse_extra_crate_attrs, expr_store::{Body, ExprOrPatSource, ExpressionStore, HygieneId, path::Path}, hir::{BindingId, Expr, ExprId, ExprOrPatId}, @@ -32,7 +32,8 @@ use hir_expand::{ name::AsName, }; use hir_ty::{ - InferenceResult, + InferBodyId, InferenceResult, + db::AnonConstId, diagnostics::unsafe_operations, infer_query_with_inspect, next_solver::{ @@ -164,11 +165,17 @@ pub struct Semantics<'db, DB: ?Sized> { imp: SemanticsImpl<'db>, } +type DefWithoutBodyWithAnonConsts = Either<GenericDefId, VariantId>; +type ExprToAnonConst = FxHashMap<ExprId, AnonConstId>; +type DefAnonConstsMap = FxHashMap<DefWithoutBodyWithAnonConsts, ExprToAnonConst>; + pub struct SemanticsImpl<'db> { pub db: &'db dyn HirDatabase, s2d_cache: RefCell<SourceToDefCache<'db>>, /// MacroCall to its expansion's MacroCallId cache macro_call_cache: RefCell<FxHashMap<InFile<ast::MacroCall>, MacroCallId>>, + /// All anon consts defined by a *signature* (not a body). + signature_anon_consts_cache: RefCell<DefAnonConstsMap>, } impl<DB: ?Sized> fmt::Debug for Semantics<'_, DB> { @@ -454,7 +461,12 @@ impl<DB: HirDatabase + ?Sized> Semantics<'_, DB> { impl<'db> SemanticsImpl<'db> { fn new(db: &'db dyn HirDatabase) -> Self { - SemanticsImpl { db, s2d_cache: Default::default(), macro_call_cache: Default::default() } + SemanticsImpl { + db, + s2d_cache: Default::default(), + macro_call_cache: Default::default(), + signature_anon_consts_cache: Default::default(), + } } pub fn parse(&self, file_id: EditionedFileId) -> ast::SourceFile { @@ -784,21 +796,16 @@ impl<'db> SemanticsImpl<'db> { /// Checks if renaming `renamed` to `new_name` may introduce conflicts with other locals, /// and returns the conflicting locals. pub fn rename_conflicts(&self, to_be_renamed: &Local, new_name: &Name) -> Vec<Local> { - // FIXME: signatures - let Some(def) = to_be_renamed.parent.as_def_with_body() else { - return Vec::new(); - }; - let body = Body::of(self.db, def); + let (store, root_expr) = to_be_renamed.parent_infer.store_and_root_expr(self.db); let resolver = to_be_renamed.parent.resolver(self.db); - let starting_expr = - body.binding_owner(to_be_renamed.binding_id).unwrap_or(body.root_expr()); + let starting_expr = store.binding_owner(to_be_renamed.binding_id).unwrap_or(root_expr); let mut visitor = RenameConflictsVisitor { - body, + body: store, conflicts: FxHashSet::default(), db: self.db, new_name: new_name.symbol().clone(), old_name: to_be_renamed.name(self.db).symbol().clone(), - owner: def, + owner: to_be_renamed.parent, to_be_renamed: to_be_renamed.binding_id, resolver, }; @@ -806,7 +813,11 @@ impl<'db> SemanticsImpl<'db> { visitor .conflicts .into_iter() - .map(|binding_id| Local { parent: to_be_renamed.parent, binding_id }) + .map(|binding_id| Local { + parent: to_be_renamed.parent, + parent_infer: to_be_renamed.parent_infer, + binding_id, + }) .collect() } @@ -1956,15 +1967,16 @@ impl<'db> SemanticsImpl<'db> { pub fn get_unsafe_ops(&self, def: ExpressionStoreOwner) -> FxHashSet<ExprOrPatSource> { let Ok(def) = ExpressionStoreOwnerId::try_from(def) else { return Default::default() }; let (body, source_map) = ExpressionStore::with_source_map(self.db, def); - let infer = InferenceResult::of(self.db, def); let mut res = FxHashSet::default(); - for root in body.expr_roots() { - unsafe_operations(self.db, infer, def, body, root, &mut |node, _| { - if let Ok(node) = source_map.expr_or_pat_syntax(node) { - res.insert(node); - } - }); - } + self.with_all_infers_for_store(def, &mut |infer| { + for root in body.expr_roots() { + unsafe_operations(self.db, infer, def, body, root, &mut |node, _| { + if let Ok(node) = source_map.expr_or_pat_syntax(node) { + res.insert(node); + } + }); + } + }); res } @@ -2112,11 +2124,14 @@ impl<'db> SemanticsImpl<'db> { } pub fn scope(&self, node: &SyntaxNode) -> Option<SemanticsScope<'db>> { - self.analyze_no_infer(node).map(|SourceAnalyzer { file_id, resolver, .. }| SemanticsScope { - db: self.db, - file_id, - resolver, - }) + self.analyze_no_infer(node).map( + |SourceAnalyzer { file_id, resolver, infer_body, .. }| SemanticsScope { + db: self.db, + file_id, + resolver, + infer_body, + }, + ) } pub fn scope_at_offset( @@ -2125,10 +2140,11 @@ impl<'db> SemanticsImpl<'db> { offset: TextSize, ) -> Option<SemanticsScope<'db>> { self.analyze_with_offset_no_infer(node, offset).map( - |SourceAnalyzer { file_id, resolver, .. }| SemanticsScope { + |SourceAnalyzer { file_id, resolver, infer_body, .. }| SemanticsScope { db: self.db, file_id, resolver, + infer_body, }, ) } @@ -2155,6 +2171,85 @@ impl<'db> SemanticsImpl<'db> { container.as_expression_store_owner().map(|id| id.into()) } + fn populate_anon_const_cache_for<'a>( + &self, + cache: &'a mut DefAnonConstsMap, + def: DefWithoutBodyWithAnonConsts, + ) -> &'a ExprToAnonConst { + cache.entry(def).or_insert_with(|| match def { + Either::Left(def) => { + let all_anon_consts = + AnonConstId::all_from_signature(self.db, def).into_iter().flatten().copied(); + all_anon_consts + .map(|anon_const| (anon_const.loc(self.db).expr, anon_const)) + .collect() + } + Either::Right(def) => { + let all_anon_consts = + self.db.field_types_with_diagnostics(def).defined_anon_consts().iter().copied(); + all_anon_consts + .map(|anon_const| (anon_const.loc(self.db).expr, anon_const)) + .collect() + } + }) + } + + fn find_anon_const_for_root_expr_in_signature( + &self, + def: DefWithoutBodyWithAnonConsts, + root_expr: ExprId, + ) -> Option<AnonConstId> { + let mut cache = self.signature_anon_consts_cache.borrow_mut(); + let anon_consts_map = self.populate_anon_const_cache_for(&mut cache, def); + anon_consts_map.get(&root_expr).copied() + } + + pub(crate) fn infer_body_for_expr_or_pat( + &self, + def: ExpressionStoreOwnerId, + store: &ExpressionStore, + node: ExprOrPatId, + ) -> Option<InferBodyId> { + let handle_def_without_body = |def| { + let root_expr = match node { + ExprOrPatId::ExprId(expr) => store.find_root_for_expr(expr), + ExprOrPatId::PatId(pat) => store.find_root_for_pat(pat), + }; + let anon_const = self.find_anon_const_for_root_expr_in_signature(def, root_expr)?; + Some(anon_const.into()) + }; + match def { + ExpressionStoreOwnerId::Signature(def) => handle_def_without_body(Either::Left(def)), + ExpressionStoreOwnerId::Body(def) => Some(def.into()), + ExpressionStoreOwnerId::VariantFields(def) => { + handle_def_without_body(Either::Right(def)) + } + } + } + + fn with_all_infers_for_store( + &self, + owner: ExpressionStoreOwnerId, + callback: &mut dyn FnMut(&'db InferenceResult), + ) { + let mut handle_def_without_body = |def| { + let mut cache = self.signature_anon_consts_cache.borrow_mut(); + let map = self.populate_anon_const_cache_for(&mut cache, def); + for &anon_const in map.values() { + callback(InferenceResult::of(self.db, anon_const)); + } + }; + match owner { + ExpressionStoreOwnerId::Signature(def) => handle_def_without_body(Either::Left(def)), + ExpressionStoreOwnerId::Body(def) => { + callback(InferenceResult::of(self.db, def)); + } + ExpressionStoreOwnerId::VariantFields(def) => { + handle_def_without_body(Either::Right(def)) + } + } + } + /// Returns none if the file of the node is not part of a crate. fn analyze(&self, node: &SyntaxNode) -> Option<SourceAnalyzer<'db>> { let node = self.find_file(node); @@ -2196,34 +2291,36 @@ impl<'db> SemanticsImpl<'db> { }); } ChildContainer::VariantId(def) => { - return Some(SourceAnalyzer::new_variant_body(self.db, def, node, offset, infer)); + return Some(SourceAnalyzer::new_variant_body( + self.db, self, def, node, offset, infer, + )); } ChildContainer::TraitId(it) => { return Some(if infer { - SourceAnalyzer::new_generic_def(self.db, it.into(), node, offset) + SourceAnalyzer::new_generic_def(self.db, self, it.into(), node, offset) } else { - SourceAnalyzer::new_generic_def_no_infer(self.db, it.into(), node, offset) + SourceAnalyzer::new_generic_def_no_infer(self.db, self, it.into(), node, offset) }); } ChildContainer::ImplId(it) => { return Some(if infer { - SourceAnalyzer::new_generic_def(self.db, it.into(), node, offset) + SourceAnalyzer::new_generic_def(self.db, self, it.into(), node, offset) } else { - SourceAnalyzer::new_generic_def_no_infer(self.db, it.into(), node, offset) + SourceAnalyzer::new_generic_def_no_infer(self.db, self, it.into(), node, offset) }); } ChildContainer::EnumId(it) => { return Some(if infer { - SourceAnalyzer::new_generic_def(self.db, it.into(), node, offset) + SourceAnalyzer::new_generic_def(self.db, self, it.into(), node, offset) } else { - SourceAnalyzer::new_generic_def_no_infer(self.db, it.into(), node, offset) + SourceAnalyzer::new_generic_def_no_infer(self.db, self, it.into(), node, offset) }); } ChildContainer::GenericDefId(it) => { return Some(if infer { - SourceAnalyzer::new_generic_def(self.db, it, node, offset) + SourceAnalyzer::new_generic_def(self.db, self, it, node, offset) } else { - SourceAnalyzer::new_generic_def_no_infer(self.db, it, node, offset) + SourceAnalyzer::new_generic_def_no_infer(self.db, self, it, node, offset) }); } ChildContainer::ModuleId(it) => it.resolver(self.db), @@ -2356,6 +2453,7 @@ impl<'db> SemanticsImpl<'db> { text_range: TextRange, ) -> Option<FxIndexSet<Local>> { let sa = self.analyze(element.either(|e| e.syntax(), |s| s.syntax()))?; + let infer_body = sa.infer_body?; let store = sa.store()?; let mut resolver = sa.resolver.clone(); let def = resolver.expression_store_owner()?; @@ -2422,7 +2520,11 @@ impl<'db> SemanticsImpl<'db> { let hygiene = store.expr_or_pat_path_hygiene(id); resolver.resolve_path_in_value_ns_fully(self.db, path, hygiene).inspect(|value| { if let ValueNs::LocalBinding(id) = value { - locals.insert((def, *id).into()); + locals.insert(Local { + parent: def, + parent_infer: infer_body, + binding_id: *id, + }); } }); } @@ -2550,7 +2652,6 @@ to_def_impls![ (crate::ConstParam, ast::ConstParam, const_param_to_def), (crate::GenericParam, ast::GenericParam, generic_param_to_def), (crate::Macro, ast::Macro, macro_to_def), - (crate::Local, ast::IdentPat, bind_pat_to_def), (crate::Local, ast::SelfParam, self_param_to_def), (crate::Label, ast::Label, label_to_def), (crate::Adt, ast::Adt, adt_to_def), @@ -2560,6 +2661,14 @@ to_def_impls![ (MacroCallId, ast::MacroCall, macro_call_to_macro_call), ]; +impl ToDef for ast::IdentPat { + type Def = crate::Local; + + fn to_def(sema: &SemanticsImpl<'_>, src: InFile<&Self>) -> Option<Self::Def> { + sema.with_ctx(|ctx| ctx.bind_pat_to_def(src, sema)) + } +} + fn find_root(node: &SyntaxNode) -> SyntaxNode { node.ancestors().last().unwrap() } @@ -2586,6 +2695,7 @@ fn find_root(node: &SyntaxNode) -> SyntaxNode { #[derive(Debug)] pub struct SemanticsScope<'db> { pub db: &'db dyn HirDatabase, + infer_body: Option<InferBodyId>, file_id: HirFileId, resolver: Resolver<'db>, } @@ -2637,9 +2747,11 @@ impl<'db> SemanticsScope<'db> { resolver::ScopeDef::AdtSelfType(it) => ScopeDef::AdtSelfType(it.into()), resolver::ScopeDef::GenericParam(id) => ScopeDef::GenericParam(id.into()), resolver::ScopeDef::Local(binding_id) => { - match self.resolver.expression_store_owner() { - Some(parent) => ScopeDef::Local(Local { parent, binding_id }), - None => continue, + match (self.resolver.expression_store_owner(), self.infer_body) { + (Some(parent), Some(parent_infer)) => { + ScopeDef::Local(Local { parent, parent_infer, binding_id }) + } + _ => continue, } } resolver::ScopeDef::Label(label_id) => { @@ -2693,6 +2805,7 @@ impl<'db> SemanticsScope<'db> { resolve_hir_path( self.db, &self.resolver, + self.infer_body, &Path::BarePath(Interned::new(ModPath::from_segments(kind, segments))), HygieneId::ROOT, None, @@ -2751,9 +2864,9 @@ impl ops::Deref for VisibleTraits { struct RenameConflictsVisitor<'a> { db: &'a dyn HirDatabase, - owner: DefWithBodyId, + owner: ExpressionStoreOwnerId, resolver: Resolver<'a>, - body: &'a Body, + body: &'a ExpressionStore, to_be_renamed: BindingId, new_name: Symbol, old_name: Symbol, diff --git a/crates/hir/src/semantics/source_to_def.rs b/crates/hir/src/semantics/source_to_def.rs index a9c3395381..1d1acd7f8e 100644 --- a/crates/hir/src/semantics/source_to_def.rs +++ b/crates/hir/src/semantics/source_to_def.rs @@ -114,7 +114,10 @@ use syntax::{ }; use tt::TextRange; -use crate::{InFile, InlineAsmOperand, db::HirDatabase, semantics::child_by_source::ChildBySource}; +use crate::{ + InFile, InlineAsmOperand, SemanticsImpl, db::HirDatabase, + semantics::child_by_source::ChildBySource, +}; #[derive(Default)] pub(super) struct SourceToDefCache<'db> { @@ -345,14 +348,16 @@ impl SourceToDefCtx<'_, '_> { pub(super) fn bind_pat_to_def( &mut self, src: InFile<&ast::IdentPat>, - ) -> Option<(ExpressionStoreOwnerId, BindingId)> { + semantics: &SemanticsImpl<'_>, + ) -> Option<crate::Local> { let container = self.find_container(src.syntax_ref())?.as_expression_store_owner()?; let (store, source_map) = ExpressionStore::with_source_map(self.db, container); let src = src.cloned().map(ast::Pat::from); let pat_id = source_map.node_pat(src.as_ref())?; // the pattern could resolve to a constant, verify that this is not the case if let crate::Pat::Bind { id, .. } = store[pat_id.as_pat()?] { - Some((container, id)) + let parent_infer = semantics.infer_body_for_expr_or_pat(container, store, pat_id)?; + Some(crate::Local { parent: container, parent_infer, binding_id: id }) } else { None } diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs index f8f8152219..74db8303b6 100644 --- a/crates/hir/src/source_analyzer.rs +++ b/crates/hir/src/source_analyzer.rs @@ -29,7 +29,8 @@ use hir_expand::{ name::{AsName, Name}, }; use hir_ty::{ - Adjustment, InferenceResult, LifetimeElisionKind, ParamEnvAndCrate, TyLoweringContext, + Adjustment, InferBodyId, InferenceResult, LifetimeElisionKind, ParamEnvAndCrate, + TyLoweringContext, diagnostics::{ InsideUnsafeBlock, record_literal_missing_fields, record_pattern_missing_fields, unsafe_operations, @@ -59,7 +60,7 @@ use syntax::{ use crate::{ Adt, AnyFunctionId, AssocItem, BindingMode, BuiltinAttr, BuiltinType, Callable, Const, DeriveHelper, EnumVariant, Field, Function, GenericSubstitution, Local, Macro, ModuleDef, - Static, Struct, ToolModule, Trait, TupleField, Type, TypeAlias, + SemanticsImpl, Static, Struct, ToolModule, Trait, TupleField, Type, TypeAlias, db::HirDatabase, semantics::{PathResolution, PathResolutionPerNs}, }; @@ -71,6 +72,7 @@ pub(crate) struct SourceAnalyzer<'db> { pub(crate) file_id: HirFileId, pub(crate) resolver: Resolver<'db>, pub(crate) body_or_sig: Option<BodyOrSig<'db>>, + pub(crate) infer_body: Option<InferBodyId>, } #[derive(Debug)] @@ -137,34 +139,39 @@ impl<'db> SourceAnalyzer<'db> { scope_for_offset(db, scopes, source_map, node.file_id, offset) } }; + let (scope, _expr) = scope.unzip(); let resolver = resolver_for_scope(db, def, scope); SourceAnalyzer { resolver, body_or_sig: Some(BodyOrSig::Body { def, body, source_map, infer }), file_id, + infer_body: Some(def.into()), } } pub(crate) fn new_generic_def( db: &'db dyn HirDatabase, + sema: &SemanticsImpl<'db>, def: GenericDefId, node: InFile<&SyntaxNode>, offset: Option<TextSize>, ) -> SourceAnalyzer<'db> { - Self::new_generic_def_(db, def, node, offset, true) + Self::new_generic_def_(db, sema, def, node, offset, true) } pub(crate) fn new_generic_def_no_infer( db: &'db dyn HirDatabase, + sema: &SemanticsImpl<'db>, def: GenericDefId, node: InFile<&SyntaxNode>, offset: Option<TextSize>, ) -> SourceAnalyzer<'db> { - Self::new_generic_def_(db, def, node, offset, false) + Self::new_generic_def_(db, sema, def, node, offset, false) } pub(crate) fn new_generic_def_( db: &'db dyn HirDatabase, + sema: &SemanticsImpl<'db>, def: GenericDefId, node @ InFile { file_id, .. }: InFile<&SyntaxNode>, offset: Option<TextSize>, @@ -184,17 +191,31 @@ impl<'db> SourceAnalyzer<'db> { scope_for_offset(db, scopes, source_map, node.file_id, offset) } }; + let (scope, expr) = scope.unzip(); let resolver = resolver_for_scope(db, def, scope); - let infer = if infer { Some(InferenceResult::of(db, def)) } else { None }; + let infer_body = expr.and_then(|expr| { + sema.infer_body_for_expr_or_pat( + ExpressionStoreOwnerId::Signature(def), + store, + expr.into(), + ) + }); + let infer = if infer && let Some(infer_body) = infer_body { + Some(InferenceResult::of(db, infer_body)) + } else { + None + }; SourceAnalyzer { resolver, body_or_sig: Some(BodyOrSig::Sig { def, store, source_map, generics, infer }), file_id, + infer_body, } } pub(crate) fn new_variant_body( db: &'db dyn HirDatabase, + sema: &SemanticsImpl<'db>, def: VariantId, node @ InFile { file_id, .. }: InFile<&SyntaxNode>, offset: Option<TextSize>, @@ -214,8 +235,20 @@ impl<'db> SourceAnalyzer<'db> { scope_for_offset(db, scopes, source_map, node.file_id, offset) } }; + let (scope, expr) = scope.unzip(); let resolver = resolver_for_scope(db, def, scope); - let infer = if infer { Some(InferenceResult::of(db, def)) } else { None }; + let infer_body = expr.and_then(|expr| { + sema.infer_body_for_expr_or_pat( + ExpressionStoreOwnerId::VariantFields(def), + &fields.store, + expr.into(), + ) + }); + let infer = if infer && let Some(infer_body) = infer_body { + Some(InferenceResult::of(db, infer_body)) + } else { + None + }; SourceAnalyzer { resolver, body_or_sig: Some(BodyOrSig::VariantFields { @@ -225,6 +258,7 @@ impl<'db> SourceAnalyzer<'db> { infer, }), file_id, + infer_body, } } @@ -232,7 +266,7 @@ impl<'db> SourceAnalyzer<'db> { resolver: Resolver<'db>, node: InFile<&SyntaxNode>, ) -> SourceAnalyzer<'db> { - SourceAnalyzer { resolver, body_or_sig: None, file_id: node.file_id } + SourceAnalyzer { resolver, body_or_sig: None, file_id: node.file_id, infer_body: None } } fn owner(&self) -> Option<ExpressionStoreOwnerId> { @@ -339,11 +373,13 @@ impl<'db> SourceAnalyzer<'db> { let type_ref = self.type_id(ty)?; + let generic_def = self.resolver.generic_def()?; let mut ty = TyLoweringContext::new( db, &self.resolver, self.store()?, - self.resolver.generic_def()?, + generic_def.into(), + generic_def, // FIXME: Is this correct here? Anyway that should impact mostly diagnostics, which we don't emit here // (this can impact the lifetimes generated, e.g. in `const` they won't be `'static`, but this seems like a // small problem). @@ -538,7 +574,7 @@ impl<'db> SourceAnalyzer<'db> { &self, field: &ast::FieldExpr, ) -> Option<Either<Field, TupleField>> { - let def = self.owner()?; + let def = self.infer_body?; let expr_id = self.expr_id(field.clone().into())?.as_expr()?; self.infer()?.field_resolution(expr_id).map(|it| { it.map_either(Into::into, |f| TupleField { owner: def, tuple: f.tuple, index: f.index }) @@ -565,7 +601,7 @@ impl<'db> SourceAnalyzer<'db> { field: &ast::FieldExpr, ) -> Option<(Either<Either<Field, TupleField>, Function>, Option<GenericSubstitution<'db>>)> { - let def = self.owner()?; + let def = self.infer_body?; let expr_id = self.expr_id(field.clone().into())?.as_expr()?; let inference_result = self.infer()?; match inference_result.field_resolution(expr_id) { @@ -820,9 +856,11 @@ impl<'db> SourceAnalyzer<'db> { &path, name_hygiene(db, InFile::new(self.file_id, ast_name.syntax())), ) { - Some(ValueNs::LocalBinding(binding_id)) => { - Some(Local { binding_id, parent: self.resolver.expression_store_owner()? }) - } + Some(ValueNs::LocalBinding(binding_id)) => Some(Local { + binding_id, + parent: self.owner()?, + parent_infer: self.infer_body?, + }), _ => None, } }; @@ -882,7 +920,14 @@ impl<'db> SourceAnalyzer<'db> { }; let store_owner = self.resolver.expression_store_owner(); - let res = resolve_hir_value_path(db, &self.resolver, store_owner, path, HygieneId::ROOT)?; + let res = resolve_hir_value_path( + db, + &self.resolver, + store_owner, + self.infer_body, + path, + HygieneId::ROOT, + )?; match res { PathResolution::Def(def) => Some(def), _ => None, @@ -1104,7 +1149,7 @@ impl<'db> SourceAnalyzer<'db> { } // FIXME: collectiong here shouldnt be necessary? - let mut collector = ExprCollector::body(db, self.resolver.module(), self.file_id); + let mut collector = ExprCollector::new(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 @@ -1250,6 +1295,7 @@ impl<'db> SourceAnalyzer<'db> { let res = resolve_hir_path_( db, &self.resolver, + self.infer_body, &hir_path, prefer_value_ns, name_hygiene(db, InFile::new(self.file_id, path.syntax())), @@ -1316,13 +1362,14 @@ impl<'db> SourceAnalyzer<'db> { db: &dyn HirDatabase, path: &ast::Path, ) -> Option<PathResolutionPerNs> { - let mut collector = ExprCollector::body(db, self.resolver.module(), self.file_id); + let mut collector = ExprCollector::new(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(); Some(resolve_hir_path_( db, &self.resolver, + self.infer_body, &hir_path, false, name_hygiene(db, InFile::new(self.file_id, path.syntax())), @@ -1462,6 +1509,7 @@ impl<'db> SourceAnalyzer<'db> { db, &self.resolver, self.resolver.expression_store_owner(), + self.infer_body, &Path::from_known_path_with_no_generic(ModPath::from_segments( PathKind::Plain, Some(name.clone()), @@ -1501,6 +1549,7 @@ impl<'db> SourceAnalyzer<'db> { db, &self.resolver, self.resolver.expression_store_owner(), + self.infer_body, &Path::from_known_path_with_no_generic(ModPath::from_segments( PathKind::Plain, Some(name.clone()), @@ -1573,12 +1622,14 @@ impl<'db> SourceAnalyzer<'db> { } } +// Note: the `ExprId` here does not need to be accurate, what's important is that it points at the same +// inference root. fn scope_for( db: &dyn HirDatabase, scopes: &ExprScopes, source_map: &ExpressionStoreSourceMap, node: InFile<&SyntaxNode>, -) -> Option<ScopeId> { +) -> Option<(ScopeId, ExprId)> { node.ancestors_with_macros(db) .take_while(|it| { let kind = it.kind(); @@ -1589,7 +1640,7 @@ fn scope_for( }) .filter_map(|it| it.map(ast::Expr::cast).transpose()) .filter_map(|it| source_map.node_expr(it.as_ref())?.as_expr()) - .find_map(|it| scopes.scope_for(it)) + .find_map(|expr| scopes.scope_for(expr).map(|scope| (scope, expr))) } fn scope_for_offset( @@ -1598,14 +1649,14 @@ fn scope_for_offset( source_map: &ExpressionStoreSourceMap, from_file: HirFileId, offset: TextSize, -) -> Option<ScopeId> { +) -> Option<(ScopeId, ExprId)> { scopes .scope_by_expr() .iter() .filter_map(|(id, scope)| { let InFile { file_id, value } = source_map.expr_syntax(id).ok()?; if from_file == file_id { - return Some((value.text_range(), scope)); + return Some((value.text_range(), scope, id)); } // FIXME handle attribute expansion @@ -1614,13 +1665,15 @@ fn scope_for_offset( }) .find(|it| it.file_id == from_file) .filter(|it| it.kind() == SyntaxKind::MACRO_CALL)?; - Some((source.text_range(), scope)) + Some((source.text_range(), scope, id)) + }) + .filter(|(expr_range, _scope, _expr)| { + expr_range.start() <= offset && offset <= expr_range.end() }) - .filter(|(expr_range, _scope)| expr_range.start() <= offset && offset <= expr_range.end()) // find containing scope - .min_by_key(|(expr_range, _scope)| expr_range.len()) - .map(|(expr_range, scope)| { - adjust(db, scopes, source_map, expr_range, from_file, offset).unwrap_or(*scope) + .min_by_key(|(expr_range, _scope, _expr)| expr_range.len()) + .map(|(expr_range, scope, expr)| { + adjust(db, scopes, source_map, expr_range, from_file, offset).unwrap_or((*scope, expr)) }) } @@ -1633,7 +1686,7 @@ fn adjust( expr_range: TextRange, from_file: HirFileId, offset: TextSize, -) -> Option<ScopeId> { +) -> Option<(ScopeId, ExprId)> { let child_scopes = scopes .scope_by_expr() .iter() @@ -1645,14 +1698,14 @@ fn adjust( } let root = source.file_syntax(db); let node = source.value.to_node(&root); - Some((node.syntax().text_range(), scope)) + Some((node.syntax().text_range(), scope, id)) }) - .filter(|&(range, _)| { + .filter(|&(range, _, _)| { range.start() <= offset && expr_range.contains_range(range) && range != expr_range }); child_scopes - .max_by(|&(r1, _), &(r2, _)| { + .max_by(|&(r1, _, _), &(r2, _, _)| { if r1.contains_range(r2) { std::cmp::Ordering::Greater } else if r2.contains_range(r1) { @@ -1661,18 +1714,19 @@ fn adjust( r1.start().cmp(&r2.start()) } }) - .map(|(_ptr, scope)| *scope) + .map(|(_ptr, scope, expr)| (*scope, expr)) } #[inline] pub(crate) fn resolve_hir_path( db: &dyn HirDatabase, resolver: &Resolver<'_>, + infer_body: Option<InferBodyId>, path: &Path, hygiene: HygieneId, store: Option<&ExpressionStore>, ) -> Option<PathResolution> { - resolve_hir_path_(db, resolver, path, false, hygiene, store, false).any() + resolve_hir_path_(db, resolver, infer_body, path, false, hygiene, store, false).any() } #[inline] @@ -1690,6 +1744,7 @@ pub(crate) fn resolve_hir_path_as_attr_macro( fn resolve_hir_path_( db: &dyn HirDatabase, resolver: &Resolver<'_>, + infer_body: Option<InferBodyId>, path: &Path, prefer_value_ns: bool, hygiene: HygieneId, @@ -1699,9 +1754,15 @@ fn resolve_hir_path_( let types = || { let (ty, unresolved) = match path.type_anchor() { Some(type_ref) => resolver.generic_def().and_then(|def| { - let (_, res) = - TyLoweringContext::new(db, resolver, store?, def, LifetimeElisionKind::Infer) - .lower_ty_ext(type_ref); + let (_, res) = TyLoweringContext::new( + db, + resolver, + store?, + def.into(), + def, + LifetimeElisionKind::Infer, + ) + .lower_ty_ext(type_ref); res.map(|ty_ns| (ty_ns, path.segments().first())) }), None => { @@ -1759,7 +1820,7 @@ fn resolve_hir_path_( }; let body_owner = resolver.expression_store_owner(); - let values = || resolve_hir_value_path(db, resolver, body_owner, path, hygiene); + let values = || resolve_hir_value_path(db, resolver, body_owner, infer_body, path, hygiene); let items = || { resolver @@ -1805,13 +1866,14 @@ fn resolve_hir_value_path( db: &dyn HirDatabase, resolver: &Resolver<'_>, store_owner: Option<ExpressionStoreOwnerId>, + infer_body: Option<InferBodyId>, path: &Path, hygiene: HygieneId, ) -> Option<PathResolution> { resolver.resolve_path_in_value_ns_fully(db, path, hygiene).and_then(|val| { let res = match val { ValueNs::LocalBinding(binding_id) => { - let var = Local { parent: store_owner?, binding_id }; + let var = Local { parent: store_owner?, parent_infer: infer_body?, binding_id }; PathResolution::Local(var) } ValueNs::FunctionId(it) => PathResolution::Def(Function::from(it).into()), @@ -1848,9 +1910,15 @@ fn resolve_hir_path_qualifier( (|| { let (ty, unresolved) = match path.type_anchor() { Some(type_ref) => resolver.generic_def().and_then(|def| { - let (_, res) = - TyLoweringContext::new(db, resolver, store, def, LifetimeElisionKind::Infer) - .lower_ty_ext(type_ref); + let (_, res) = TyLoweringContext::new( + db, + resolver, + store, + def.into(), + def, + LifetimeElisionKind::Infer, + ) + .lower_ty_ext(type_ref); res.map(|ty_ns| (ty_ns, path.segments().first())) }), None => { diff --git a/crates/hir/src/term_search/tactics.rs b/crates/hir/src/term_search/tactics.rs index 99ad1e0739..8700326e17 100644 --- a/crates/hir/src/term_search/tactics.rs +++ b/crates/hir/src/term_search/tactics.rs @@ -53,7 +53,7 @@ pub(super) fn trivial<'a, 'lt, 'db, DB: HirDatabase>( ScopeDef::GenericParam(GenericParam::ConstParam(it)) => Some(Expr::ConstParam(*it)), ScopeDef::Local(it) => { if ctx.config.enable_borrowcheck { - let borrowck = db.borrowck(it.parent.as_def_with_body()?).ok()?; + let borrowck = db.borrowck(it.parent_infer).ok()?; let invalid = borrowck.iter().any(|b| { let mir_body = b.mir_body(ctx.sema.db); diff --git a/crates/ide-assists/src/handlers/add_explicit_type.rs b/crates/ide-assists/src/handlers/add_explicit_type.rs index 53de25c454..e543005e67 100644 --- a/crates/ide-assists/src/handlers/add_explicit_type.rs +++ b/crates/ide-assists/src/handlers/add_explicit_type.rs @@ -208,8 +208,6 @@ fn main() { } "#, ); - // note: this may break later if we add more consteval. it just needs to be something that our - // consteval engine doesn't understand check_assist_not_applicable( add_explicit_type, r#" diff --git a/crates/ide-db/src/path_transform.rs b/crates/ide-db/src/path_transform.rs index 83991a85e0..661f0cff8e 100644 --- a/crates/ide-db/src/path_transform.rs +++ b/crates/ide-db/src/path_transform.rs @@ -218,8 +218,7 @@ impl<'a> PathTransform<'a> { } } (Either::Left(k), None) => { - if let Some(default) = - k.default(db, target_module.krate(db).to_display_target(db)) + if let Some(default) = k.default_source_code(db, target_module) && let Some(default) = default.expr() { const_substs.insert(k, default.syntax().clone()); diff --git a/crates/ide/src/inlay_hints/implicit_drop.rs b/crates/ide/src/inlay_hints/implicit_drop.rs index 3af529e8c5..57aba51b4e 100644 --- a/crates/ide/src/inlay_hints/implicit_drop.rs +++ b/crates/ide/src/inlay_hints/implicit_drop.rs @@ -37,7 +37,7 @@ pub(super) fn hints( let def = def.try_into().ok()?; let (hir, source_map) = hir::Body::with_source_map(sema.db, def); - let mir = sema.db.mir_body(def).ok()?; + let mir = sema.db.mir_body(def.into()).ok()?; let local_to_binding = mir.local_to_binding_map(); diff --git a/crates/ide/src/signature_help.rs b/crates/ide/src/signature_help.rs index cf796b2715..edcf0dc22b 100644 --- a/crates/ide/src/signature_help.rs +++ b/crates/ide/src/signature_help.rs @@ -381,8 +381,7 @@ fn signature_help_for_generics( } } GenericParam::ConstParam(param) => { - if let Some(expr) = param.default(db, display_target).and_then(|konst| konst.expr()) - { + if let Some(expr) = param.default(db, display_target) { format_to!(buf, " = {}", expr); } } diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs index d06690f203..61e0b1e611 100644 --- a/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/crates/rust-analyzer/src/cli/analysis_stats.rs @@ -12,7 +12,7 @@ use std::{ use cfg::{CfgAtom, CfgDiff}; use hir::{ Adt, AssocItem, Crate, DefWithBody, FindPathConfig, GenericDef, HasCrate, HasSource, - HirDisplay, ModuleDef, Name, Variant, VariantId, crate_lang_items, + HirDisplay, ModuleDef, Name, Variant, crate_lang_items, db::{DefDatabase, ExpandDatabase, HirDatabase}, next_solver::{DbInterner, GenericArgs}, }; @@ -746,10 +746,8 @@ impl flags::AnalysisStats { } all += 1; - let Ok(body_id) = body.try_into() else { - continue; - }; - let Err(e) = db.mir_body(body_id) else { + #[expect(deprecated)] + let Err(e) = body.run_mir_body(db) else { continue; }; if verbosity.is_spammy() { @@ -780,7 +778,7 @@ impl flags::AnalysisStats { vfs: &Vfs, bodies: &[DefWithBody], signatures: &[GenericDef], - variants: &[Variant], + _variants: &[Variant], verbosity: Verbosity, ) { let mut bar = match verbosity { @@ -801,23 +799,24 @@ impl flags::AnalysisStats { InferenceResult::of(snap, body); }) .count(); - let signatures = signatures + let _signatures = signatures .iter() .filter_map(|&signatures| signatures.try_into().ok()) .collect::<Vec<GenericDefId>>(); - signatures - .par_iter() - .map_with(db.clone(), |snap, &signatures| { - InferenceResult::of(snap, signatures); - }) - .count(); - let variants = variants.iter().copied().map(Into::into).collect::<Vec<VariantId>>(); - variants - .par_iter() - .map_with(db.clone(), |snap, &variants| { - InferenceResult::of(snap, variants); - }) - .count(); + // FIXME: We don't have access to the necessary types here (nor we should have). + // signatures + // .par_iter() + // .map_with(db.clone(), |snap, &signatures| { + // InferenceResult::of(snap, signatures); + // }) + // .count(); + // let variants = variants.iter().copied().map(Into::into).collect::<Vec<VariantId>>(); + // variants + // .par_iter() + // .map_with(db.clone(), |snap, &variants| { + // InferenceResult::of(snap, variants); + // }) + // .count(); eprintln!("{:<20} {}", "Parallel Inference:", inference_sw.elapsed()); } diff --git a/crates/test-utils/src/minicore.rs b/crates/test-utils/src/minicore.rs index 802e6ab8ce..ce28808803 100644 --- a/crates/test-utils/src/minicore.rs +++ b/crates/test-utils/src/minicore.rs @@ -1992,7 +1992,7 @@ pub mod iter { pub struct Iter<'a, T> { slice: &'a [T], } - impl<'a, T> IntoIterator for &'a [T; N] { + impl<'a, T, const N: usize> IntoIterator for &'a [T; N] { type Item = &'a T; type IntoIter = Iter<'a, T>; fn into_iter(self) -> Self::IntoIter { |