Unnamed repository; edit this file 'description' to name the repository.
Merge pull request #22198 from ChayimFriedman2/anon-consts
fix: Do not infer signatures, instead infer anon consts in them
Chayim Refael Friedman 9 days ago
parent f44df76 · parent 2bbdac0 · commit 5458851
-rw-r--r--crates/hir-def/src/db.rs14
-rw-r--r--crates/hir-def/src/expr_store.rs104
-rw-r--r--crates/hir-def/src/expr_store/body.rs4
-rw-r--r--crates/hir-def/src/expr_store/lower.rs128
-rw-r--r--crates/hir-def/src/expr_store/lower/generics.rs10
-rw-r--r--crates/hir-def/src/expr_store/lower/path/tests.rs2
-rw-r--r--crates/hir-def/src/expr_store/scope.rs87
-rw-r--r--crates/hir-def/src/hir/generics.rs5
-rw-r--r--crates/hir-def/src/lib.rs68
-rw-r--r--crates/hir-def/src/signatures.rs2
-rw-r--r--crates/hir-ty/src/consteval.rs304
-rw-r--r--crates/hir-ty/src/consteval/tests.rs2
-rw-r--r--crates/hir-ty/src/db.rs251
-rw-r--r--crates/hir-ty/src/display.rs26
-rw-r--r--crates/hir-ty/src/generics.rs12
-rw-r--r--crates/hir-ty/src/infer.rs431
-rw-r--r--crates/hir-ty/src/infer/closure.rs4
-rw-r--r--crates/hir-ty/src/infer/closure/analysis.rs5
-rw-r--r--crates/hir-ty/src/infer/closure/analysis/expr_use_visitor.rs4
-rw-r--r--crates/hir-ty/src/infer/coerce.rs2
-rw-r--r--crates/hir-ty/src/infer/diagnostics.rs26
-rw-r--r--crates/hir-ty/src/infer/expr.rs154
-rw-r--r--crates/hir-ty/src/infer/path.rs3
-rw-r--r--crates/hir-ty/src/infer/unify.rs1
-rw-r--r--crates/hir-ty/src/layout/tests.rs2
-rw-r--r--crates/hir-ty/src/lib.rs100
-rw-r--r--crates/hir-ty/src/lower.rs1028
-rw-r--r--crates/hir-ty/src/lower/path.rs22
-rw-r--r--crates/hir-ty/src/method_resolution/confirm.rs10
-rw-r--r--crates/hir-ty/src/mir.rs6
-rw-r--r--crates/hir-ty/src/mir/borrowck.rs15
-rw-r--r--crates/hir-ty/src/mir/eval.rs55
-rw-r--r--crates/hir-ty/src/mir/lower.rs153
-rw-r--r--crates/hir-ty/src/mir/lower/as_place.rs2
-rw-r--r--crates/hir-ty/src/mir/lower/tests.rs2
-rw-r--r--crates/hir-ty/src/mir/monomorphization.rs7
-rw-r--r--crates/hir-ty/src/mir/pretty.rs18
-rw-r--r--crates/hir-ty/src/next_solver/binder.rs26
-rw-r--r--crates/hir-ty/src/next_solver/def_id.rs50
-rw-r--r--crates/hir-ty/src/next_solver/fulfill.rs2
-rw-r--r--crates/hir-ty/src/next_solver/generics.rs17
-rw-r--r--crates/hir-ty/src/next_solver/infer/errors.rs16
-rw-r--r--crates/hir-ty/src/next_solver/interner.rs82
-rw-r--r--crates/hir-ty/src/next_solver/solver.rs12
-rw-r--r--crates/hir-ty/src/opaques.rs18
-rw-r--r--crates/hir-ty/src/tests.rs39
-rw-r--r--crates/hir-ty/src/tests/incremental.rs13
-rw-r--r--crates/hir-ty/src/tests/patterns.rs2
-rw-r--r--crates/hir-ty/src/tests/regression.rs1
-rw-r--r--crates/hir-ty/src/tests/regression/new_solver.rs32
-rw-r--r--crates/hir-ty/src/tests/simple.rs44
-rw-r--r--crates/hir-ty/src/tests/traits.rs6
-rw-r--r--crates/hir-ty/src/upvars.rs5
-rw-r--r--crates/hir-ty/src/variance.rs3
-rw-r--r--crates/hir/src/from_id.rs7
-rw-r--r--crates/hir/src/has_source.rs3
-rw-r--r--crates/hir/src/lib.rs182
-rw-r--r--crates/hir/src/semantics.rs201
-rw-r--r--crates/hir/src/semantics/source_to_def.rs11
-rw-r--r--crates/hir/src/source_analyzer.rs146
-rw-r--r--crates/hir/src/term_search/tactics.rs2
-rw-r--r--crates/ide-assists/src/handlers/add_explicit_type.rs2
-rw-r--r--crates/ide-db/src/path_transform.rs3
-rw-r--r--crates/ide/src/inlay_hints/implicit_drop.rs2
-rw-r--r--crates/ide/src/signature_help.rs3
-rw-r--r--crates/rust-analyzer/src/cli/analysis_stats.rs39
-rw-r--r--crates/test-utils/src/minicore.rs2
67 files changed, 2447 insertions, 1593 deletions
diff --git a/crates/hir-def/src/db.rs b/crates/hir-def/src/db.rs
index d644c1e9fe..d9be96174e 100644
--- a/crates/hir-def/src/db.rs
+++ b/crates/hir-def/src/db.rs
@@ -7,12 +7,11 @@ use hir_expand::{
use triomphe::Arc;
use crate::{
- AnonConstId, AnonConstLoc, AssocItemId, AttrDefId, BlockId, BlockLoc, ConstId, ConstLoc,
- EnumId, EnumLoc, EnumVariantId, EnumVariantLoc, ExternBlockId, ExternBlockLoc, ExternCrateId,
- ExternCrateLoc, FunctionId, FunctionLoc, ImplId, ImplLoc, Macro2Id, Macro2Loc, MacroExpander,
- MacroId, MacroRulesId, MacroRulesLoc, MacroRulesLocFlags, ProcMacroId, ProcMacroLoc, StaticId,
- StaticLoc, StructId, StructLoc, TraitId, TraitLoc, TypeAliasId, TypeAliasLoc, UnionId,
- UnionLoc, UseId, UseLoc,
+ AssocItemId, AttrDefId, BlockId, BlockLoc, ConstId, ConstLoc, EnumId, EnumLoc, EnumVariantId,
+ EnumVariantLoc, ExternBlockId, ExternBlockLoc, ExternCrateId, ExternCrateLoc, FunctionId,
+ FunctionLoc, ImplId, ImplLoc, Macro2Id, Macro2Loc, MacroExpander, MacroId, MacroRulesId,
+ MacroRulesLoc, MacroRulesLocFlags, ProcMacroId, ProcMacroLoc, StaticId, StaticLoc, StructId,
+ StructLoc, TraitId, TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, UnionLoc, UseId, UseLoc,
attrs::AttrFlags,
item_tree::{ItemTree, file_item_tree},
nameres::crate_def_map,
@@ -52,9 +51,6 @@ pub trait InternDatabase: SourceDatabase {
fn intern_static(&self, loc: StaticLoc) -> StaticId;
#[salsa::interned]
- fn intern_anon_const(&self, loc: AnonConstLoc) -> AnonConstId;
-
- #[salsa::interned]
fn intern_trait(&self, loc: TraitLoc) -> TraitId;
#[salsa::interned]
diff --git a/crates/hir-def/src/expr_store.rs b/crates/hir-def/src/expr_store.rs
index af3d28d174..c195106498 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 f4842700f7..7862cda69f 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 {
@@ -3110,6 +3093,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 7d254c58db..60b1f8cc7e 100644
--- a/crates/hir-def/src/lib.rs
+++ b/crates/hir-def/src/lib.rs
@@ -86,19 +86,14 @@ use crate::{
builtin_type::BuiltinType,
db::DefDatabase,
expr_store::ExpressionStoreSourceMap,
- hir::{
- ExprId,
- generics::{GenericParams, LocalLifetimeParamId, LocalTypeOrConstParamId},
- },
+ hir::generics::{GenericParams, LocalLifetimeParamId, LocalTypeOrConstParamId},
nameres::{
LocalDefMap,
assoc::{ImplItems, TraitItems},
block_def_map, crate_def_map, crate_local_def_map,
diagnostics::DefDiagnostics,
},
- signatures::{
- ConstSignature, EnumVariants, InactiveEnumVariantCode, StaticSignature, VariantFields,
- },
+ signatures::{EnumVariants, InactiveEnumVariantCode, VariantFields},
};
type FxIndexMap<K, V> = indexmap::IndexMap<K, V, rustc_hash::FxBuildHasher>;
@@ -313,19 +308,6 @@ impl_intern!(ConstId, ConstLoc, intern_const, lookup_intern_const);
pub type StaticLoc = AssocItemLoc<ast::Static>;
impl_intern!(StaticId, StaticLoc, intern_static, lookup_intern_static);
-/// An anonymous const expression that appears in a type position (e.g., array lengths,
-/// const generic arguments like `{ N + 1 }`). Unlike named constants, these don't have
-/// their own `Body` — their expressions live in the parent's signature `ExpressionStore`.
-#[derive(Debug, Hash, PartialEq, Eq, Clone)]
-pub struct AnonConstLoc {
- /// The owner store containing this expression.
- pub owner: ExpressionStoreOwnerId,
- /// The ExprId within the owner's ExpressionStore that is the root
- /// of this anonymous const expression.
- pub expr: ExprId,
-}
-impl_intern!(AnonConstId, AnonConstLoc, intern_anon_const, lookup_intern_anon_const);
-
pub type TraitLoc = ItemLoc<ast::Trait>;
impl_intern!(TraitId, TraitLoc, intern_trait, lookup_intern_trait);
@@ -721,42 +703,6 @@ impl From<DefWithBodyId> for ModuleDefId {
}
}
-/// 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.
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa_macros::Supertype)]
-pub enum GeneralConstId {
- ConstId(ConstId),
- StaticId(StaticId),
- AnonConstId(AnonConstId),
-}
-
-impl_from!(ConstId, StaticId, AnonConstId for GeneralConstId);
-
-impl GeneralConstId {
- pub fn generic_def(self, db: &dyn DefDatabase) -> Option<GenericDefId> {
- match self {
- GeneralConstId::ConstId(it) => Some(it.into()),
- GeneralConstId::StaticId(it) => Some(it.into()),
- GeneralConstId::AnonConstId(it) => Some(it.lookup(db).owner.generic_def(db)),
- }
- }
-
- pub fn name(self, db: &dyn DefDatabase) -> String {
- match self {
- GeneralConstId::StaticId(it) => {
- StaticSignature::of(db, it).name.display(db, Edition::CURRENT).to_string()
- }
- GeneralConstId::ConstId(const_id) => {
- ConstSignature::of(db, const_id).name.as_ref().map_or_else(
- || "_".to_owned(),
- |name| name.display(db, Edition::CURRENT).to_string(),
- )
- }
- GeneralConstId::AnonConstId(_) => "{anon const}".to_owned(),
- }
- }
-}
-
/// The defs which have a body.
#[derive(Debug, PartialOrd, Ord, Clone, Copy, PartialEq, Eq, Hash, salsa_macros::Supertype)]
pub enum DefWithBodyId {
@@ -778,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 0fdd3ff1d9..67e40fa811 100644
--- a/crates/hir-ty/src/consteval.rs
+++ b/crates/hir-ty/src/consteval.rs
@@ -5,32 +5,34 @@ mod tests;
use base_db::Crate;
use hir_def::{
- ConstId, EnumVariantId, ExpressionStoreOwnerId, GeneralConstId, GenericDefId, HasModule,
- StaticId,
+ 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::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))
@@ -81,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, _)) => {
@@ -137,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
@@ -184,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 {
@@ -202,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,
@@ -218,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 {
@@ -232,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,
@@ -257,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(),
@@ -267,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,
@@ -361,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 5dba53a761..352f717454 100644
--- a/crates/hir-ty/src/db.rs
+++ b/crates/hir-ty/src/db.rs
@@ -1,32 +1,39 @@
//! The home of `HirDatabase`, which is the Salsa database containing all the
//! type inference-related queries.
+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;
use salsa::plumbing::AsId;
+use span::Edition;
+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},
};
@@ -38,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())
}
@@ -50,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> {
@@ -72,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())
}
@@ -85,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>;
@@ -135,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.
@@ -146,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]
@@ -195,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) -> GenericDefaults;
+ 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 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]
@@ -248,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,
}
@@ -263,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!(
@@ -291,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!(
@@ -320,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!(
@@ -337,3 +409,112 @@ impl InternedCoroutineClosureId {
Self::new_impl(db, loc)
}
}
+
+/// An anonymous const expression that appears in a type position (e.g., array lengths,
+/// 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.
+ pub owner: ExpressionStoreOwnerId,
+ /// The ExprId within the owner's ExpressionStore that is the root
+ /// of this anonymous const expression.
+ pub expr: ExprId,
+ 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
+ }
+}
+
+/// 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.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa_macros::Supertype)]
+pub enum GeneralConstId {
+ ConstId(ConstId),
+ StaticId(StaticId),
+ AnonConstId(AnonConstId),
+}
+
+impl_from!(ConstId, StaticId, AnonConstId for GeneralConstId);
+
+impl GeneralConstId {
+ pub fn generic_def(self, db: &dyn HirDatabase) -> Option<GenericDefId> {
+ match self {
+ GeneralConstId::ConstId(it) => Some(it.into()),
+ GeneralConstId::StaticId(it) => Some(it.into()),
+ GeneralConstId::AnonConstId(it) => Some(it.loc(db).owner.generic_def(db)),
+ }
+ }
+
+ pub fn name(self, db: &dyn DefDatabase) -> String {
+ match self {
+ GeneralConstId::StaticId(it) => {
+ StaticSignature::of(db, it).name.display(db, Edition::CURRENT).to_string()
+ }
+ GeneralConstId::ConstId(const_id) => {
+ ConstSignature::of(db, const_id).name.as_ref().map_or_else(
+ || "_".to_owned(),
+ |name| name.display(db, Edition::CURRENT).to_string(),
+ )
+ }
+ 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 e7f3827d84..e338548626 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()
}
@@ -745,6 +710,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)]
@@ -976,30 +943,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(),
@@ -1022,6 +980,7 @@ impl InferenceResult {
expr_adjustments: Default::default(),
coercion_casts: Default::default(),
closures_data: Default::default(),
+ defined_anon_consts: Default::default(),
}
}
@@ -1216,17 +1175,20 @@ enum DerefPatBorrowMode {
}
/// 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,
@@ -1261,6 +1223,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)]
@@ -1310,22 +1274,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),
@@ -1341,7 +1298,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,
@@ -1352,6 +1312,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())));
}
}
@@ -1362,7 +1413,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)
}
@@ -1398,26 +1449,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
@@ -1458,7 +1505,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);
@@ -1557,6 +1609,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,
);
@@ -1564,11 +1617,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,
);
@@ -1581,6 +1635,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<_>>(),
);
@@ -1621,6 +1676,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);
@@ -1672,10 +1728,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),
@@ -1776,6 +1828,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 {
@@ -1785,8 +1838,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)
}
@@ -1798,6 +1854,7 @@ impl<'body, 'db> InferenceContext<'body, 'db> {
self.with_ty_lowering(
self.store,
InferenceTyDiagnosticSource::Body,
+ self.store_owner,
LifetimeElisionKind::Infer,
f,
)
@@ -1808,11 +1865,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.
@@ -1839,34 +1898,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> {
@@ -1877,6 +1956,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),
);
@@ -2100,8 +2180,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() {
@@ -2549,7 +2632,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)),
@@ -2560,7 +2643,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 b42127cce6..88edb3bf21 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
@@ -657,7 +657,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);
}
@@ -1348,7 +1348,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 34fbaf6980..8732ca6a9a 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},
@@ -648,7 +648,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;
@@ -758,106 +758,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(),
@@ -1317,7 +1256,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 => {
@@ -1381,19 +1320,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(),
@@ -1431,7 +1359,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)
@@ -1559,7 +1487,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 d3db2a9057..dbbe31971e 100644
--- a/crates/hir-ty/src/lower.rs
+++ b/crates/hir-ty/src/lower.rs
@@ -8,23 +8,23 @@
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::{
AdtId, AssocItemId, CallableDefId, ConstId, ConstParamId, EnumId, EnumVariantId,
- ExpressionStoreOwnerId, FunctionId, GeneralConstId, GenericDefId, GenericParamId, HasModule,
- ImplId, ItemContainerId, LifetimeParamId, LocalFieldId, Lookup, StaticId, StructId, TraitId,
+ ExpressionStoreOwnerId, FunctionId, GenericDefId, GenericParamId, HasModule, ImplId,
+ 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::{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 8701ad5be6..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, GeneralConstId,
- 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,9 +37,9 @@ 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::{HirDatabase, InternedClosureId},
+ db::{GeneralConstId, HirDatabase, InternedClosureId},
display::{ClosureStyle, DisplayTarget, HirDisplay},
infer::PointerCast,
layout::{Layout, LayoutError, RustcEnumVariantIdx},
@@ -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
@@ -2058,9 +2067,9 @@ impl<'a, 'db: 'a> Evaluator<'a, 'db> {
ConstKind::Unevaluated(UnevaluatedConst { def: const_id, args: subst }) => {
let mut id = const_id.0;
let mut subst = subst;
- if let hir_def::GeneralConstId::ConstId(c) = id {
+ if let GeneralConstId::ConstId(c) = id {
let (c, s) = lookup_impl_const(&self.infcx, self.param_env.param_env, c, subst);
- id = hir_def::GeneralConstId::ConstId(c);
+ id = GeneralConstId::ConstId(c);
subst = s;
}
let allocation = match id {
@@ -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 8f8f557716..96ddb69814 100644
--- a/crates/hir-ty/src/mir/lower.rs
+++ b/crates/hir-ty/src/mir/lower.rs
@@ -4,8 +4,8 @@ use std::{fmt::Write, iter, mem};
use base_db::Crate;
use hir_def::{
- AdtId, DefWithBodyId, EnumVariantId, ExpressionStoreOwnerId, GeneralConstId, GenericParamId,
- HasModule, ItemContainerId, LocalFieldId, Lookup, TraitId, TupleId,
+ AdtId, DefWithBodyId, EnumVariantId, ExpressionStoreOwnerId, GenericParamId, HasModule,
+ ItemContainerId, LocalFieldId, Lookup, TraitId, TupleId,
expr_store::{Body, ExpressionStore, HygieneId, path::Path},
hir::{
ArithOp, Array, BinaryOp, BindingAnnotation, BindingId, ClosureKind, ExprId, ExprOrPatId,
@@ -27,9 +27,9 @@ use span::{Edition, FileId};
use syntax::TextRange;
use crate::{
- Adjust, Adjustment, AutoBorrow, CallableDefId, ParamEnvAndCrate,
+ Adjust, Adjustment, AutoBorrow, CallableDefId, InferBodyId, ParamEnvAndCrate,
consteval::ConstEvalError,
- db::{HirDatabase, InternedClosure, InternedClosureId},
+ db::{GeneralConstId, HirDatabase, InternedClosure, InternedClosureId},
display::{DisplayTarget, HirDisplay, hir_display_with_store},
generics::generics,
infer::{
@@ -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 542eca3ded..41b00b67cd 100644
--- a/crates/hir-ty/src/next_solver/def_id.rs
+++ b/crates/hir-ty/src/next_solver/def_id.rs
@@ -1,9 +1,9 @@
//! Definition of `SolverDefId`
use hir_def::{
- AdtId, AnonConstId, AttrDefId, BuiltinDeriveImplId, CallableDefId, ConstId, DefWithBodyId,
- EnumId, EnumVariantId, ExpressionStoreOwnerId, FunctionId, GeneralConstId, GenericDefId,
- ImplId, StaticId, StructId, TraitId, TypeAliasId, UnionId, VariantId,
+ AdtId, AttrDefId, BuiltinDeriveImplId, CallableDefId, ConstId, DefWithBodyId, EnumId,
+ EnumVariantId, ExpressionStoreOwnerId, FunctionId, GenericDefId, ImplId, StaticId, StructId,
+ TraitId, TypeAliasId, UnionId, VariantId,
signatures::{
ConstSignature, EnumSignature, FunctionSignature, StaticSignature, StructSignature,
TraitSignature, TypeAliasSignature, UnionSignature,
@@ -12,8 +12,12 @@ use hir_def::{
use rustc_type_ir::inherent;
use stdx::impl_from;
-use crate::db::{
- InternedClosureId, InternedCoroutineClosureId, InternedCoroutineId, InternedOpaqueTyId,
+use crate::{
+ InferBodyId,
+ db::{
+ AnonConstId, GeneralConstId, InternedClosureId, InternedCoroutineClosureId,
+ InternedCoroutineId, InternedOpaqueTyId,
+ },
};
use super::DbInterner;
@@ -173,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 {
@@ -246,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 6abc87f088..ecfc1c21b7 100644
--- a/crates/hir-ty/src/next_solver/solver.rs
+++ b/crates/hir-ty/src/next_solver/solver.rs
@@ -1,7 +1,7 @@
//! Defining `SolverContext` for next-trait-solver.
use hir_def::{
- AssocItemId, GeneralConstId,
+ AssocItemId,
signatures::{ConstSignature, TypeAliasSignature},
};
use rustc_next_trait_solver::delegate::SolverDelegate;
@@ -16,6 +16,7 @@ use tracing::debug;
use crate::{
ParamEnvAndCrate, Span,
+ db::GeneralConstId,
next_solver::{
AliasTy, AnyImplId, CanonicalVarKind, Clause, ClauseKind, CoercePredicate, GenericArgs,
ParamEnv, Predicate, PredicateKind, SubtypePredicate, Ty, TyKind, UnevaluatedConst,
@@ -260,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 ea94725df8..e719f43e74 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 4fb449117d..889b0e05af 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 {
@@ -788,21 +800,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,
};
@@ -810,7 +817,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()
}
@@ -1960,15 +1971,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
}
@@ -2116,11 +2128,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(
@@ -2129,10 +2144,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,
},
)
}
@@ -2159,6 +2175,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);
@@ -2200,34 +2295,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),
@@ -2360,6 +2457,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()?;
@@ -2426,7 +2524,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,
+ });
}
});
}
@@ -2554,7 +2656,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),
@@ -2564,6 +2665,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()
}
@@ -2590,6 +2699,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>,
}
@@ -2641,9 +2751,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) => {
@@ -2697,6 +2809,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,
@@ -2755,9 +2868,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 a7f5c3f1cf..f0208ad01a 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
@@ -1244,6 +1289,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())),
@@ -1310,13 +1356,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())),
@@ -1456,6 +1503,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()),
@@ -1495,6 +1543,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()),
@@ -1567,12 +1616,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();
@@ -1583,7 +1634,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(
@@ -1592,14 +1643,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
@@ -1608,13 +1659,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))
})
}
@@ -1627,7 +1680,7 @@ fn adjust(
expr_range: TextRange,
from_file: HirFileId,
offset: TextSize,
-) -> Option<ScopeId> {
+) -> Option<(ScopeId, ExprId)> {
let child_scopes = scopes
.scope_by_expr()
.iter()
@@ -1639,14 +1692,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) {
@@ -1655,18 +1708,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]
@@ -1684,6 +1738,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,
@@ -1693,9 +1748,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 => {
@@ -1753,7 +1814,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
@@ -1799,13 +1860,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()),
@@ -1842,9 +1904,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 0d9b866cdf..8975fa56d7 100644
--- a/crates/test-utils/src/minicore.rs
+++ b/crates/test-utils/src/minicore.rs
@@ -2003,7 +2003,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 {