From 7a16e06009d1d6e9576ab7b78427827142f5bbf6 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Fri, 21 Jun 2024 18:38:37 +0200 Subject: [PATCH] Lazy generics --- crates/hir-ty/src/consteval.rs | 6 +++--- crates/hir-ty/src/infer.rs | 13 +++++++++++-- crates/hir-ty/src/infer/closure.rs | 4 ++-- crates/hir-ty/src/lower.rs | 14 ++++++++++---- 4 files changed, 26 insertions(+), 11 deletions(-) diff --git a/crates/hir-ty/src/consteval.rs b/crates/hir-ty/src/consteval.rs index aa7fc598b4..8b6cde975f 100644 --- a/crates/hir-ty/src/consteval.rs +++ b/crates/hir-ty/src/consteval.rs @@ -71,12 +71,12 @@ impl From for ConstEvalError { } } -pub(crate) fn path_to_const( +pub(crate) fn path_to_const<'g>( db: &dyn HirDatabase, resolver: &Resolver, path: &Path, mode: ParamLoweringMode, - args: impl FnOnce() -> Option, + args: impl FnOnce() -> Option<&'g Generics>, debruijn: DebruijnIndex, expected_ty: Ty, ) -> Option { @@ -89,7 +89,7 @@ pub(crate) fn path_to_const( } ParamLoweringMode::Variable => { let args = args(); - match args.as_ref().and_then(|args| args.type_or_const_param_idx(p.into())) { + match args.and_then(|args| args.type_or_const_param_idx(p.into())) { Some(it) => ConstValue::BoundVar(BoundVar::new(debruijn, it)), None => { never!( diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs index c82bac0c5c..aeb6e69ce7 100644 --- a/crates/hir-ty/src/infer.rs +++ b/crates/hir-ty/src/infer.rs @@ -49,6 +49,7 @@ use hir_def::{ use hir_expand::name::{name, Name}; use indexmap::IndexSet; use la_arena::{ArenaMap, Entry}; +use once_cell::unsync::OnceCell; use rustc_hash::{FxHashMap, FxHashSet}; use stdx::{always, never}; use triomphe::Arc; @@ -527,6 +528,7 @@ pub(crate) struct InferenceContext<'a> { pub(crate) owner: DefWithBodyId, pub(crate) body: &'a Body, pub(crate) resolver: Resolver, + generics: OnceCell>, table: unify::InferenceTable<'a>, /// The traits in scope, disregarding block modules. This is used for caching purposes. traits_in_scope: FxHashSet, @@ -612,6 +614,7 @@ impl<'a> InferenceContext<'a> { ) -> Self { let trait_env = db.trait_environment_for_body(owner); InferenceContext { + generics: OnceCell::new(), result: InferenceResult::default(), table: unify::InferenceTable::new(db, trait_env), tuple_field_accesses_rev: Default::default(), @@ -633,8 +636,14 @@ impl<'a> InferenceContext<'a> { } } - pub(crate) fn generics(&self) -> Option { - Some(crate::generics::generics(self.db.upcast(), self.resolver.generic_def()?)) + pub(crate) fn generics(&self) -> Option<&Generics> { + self.generics + .get_or_init(|| { + self.resolver + .generic_def() + .map(|def| crate::generics::generics(self.db.upcast(), def)) + }) + .as_ref() } // FIXME: This function should be private in module. It is currently only used in the consteval, since we need diff --git a/crates/hir-ty/src/infer/closure.rs b/crates/hir-ty/src/infer/closure.rs index 9f95e6edff..b7c7b66545 100644 --- a/crates/hir-ty/src/infer/closure.rs +++ b/crates/hir-ty/src/infer/closure.rs @@ -339,7 +339,7 @@ impl CapturedItemWithoutTy { fn replace_placeholder_with_binder(ctx: &mut InferenceContext<'_>, ty: Ty) -> Binders { struct Filler<'a> { db: &'a dyn HirDatabase, - generics: Generics, + generics: &'a Generics, } impl FallibleTypeFolder for Filler<'_> { type Error = (); @@ -382,7 +382,7 @@ impl CapturedItemWithoutTy { }; let filler = &mut Filler { db: ctx.db, generics }; let result = ty.clone().try_fold_with(filler, DebruijnIndex::INNERMOST).unwrap_or(ty); - make_binders(ctx.db, &filler.generics, result) + make_binders(ctx.db, filler.generics, result) } } } diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs index 00b1f53857..30d6b2f664 100644 --- a/crates/hir-ty/src/lower.rs +++ b/crates/hir-ty/src/lower.rs @@ -45,6 +45,7 @@ use hir_def::{ use hir_expand::{name::Name, ExpandResult}; use intern::Interned; use la_arena::{Arena, ArenaMap}; +use once_cell::unsync::OnceCell; use rustc_hash::FxHashSet; use smallvec::SmallVec; use stdx::{impl_from, never}; @@ -122,6 +123,7 @@ impl ImplTraitLoweringState { pub struct TyLoweringContext<'a> { pub db: &'a dyn HirDatabase, resolver: &'a Resolver, + generics: OnceCell>, in_binders: DebruijnIndex, // FIXME: Should not be an `Option` but `Resolver` currently does not return owners in all cases // where expected @@ -153,6 +155,7 @@ impl<'a> TyLoweringContext<'a> { Self { db, resolver, + generics: OnceCell::new(), owner, in_binders, impl_trait_mode, @@ -175,6 +178,7 @@ impl<'a> TyLoweringContext<'a> { impl_trait_mode, expander: RefCell::new(expander), unsized_types: RefCell::new(unsized_types), + generics: self.generics.clone(), ..*self }; let result = f(&new_ctx); @@ -246,8 +250,10 @@ impl<'a> TyLoweringContext<'a> { ) } - fn generics(&self) -> Option { - Some(generics(self.db.upcast(), self.resolver.generic_def()?)) + fn generics(&self) -> Option<&Generics> { + self.generics + .get_or_init(|| self.resolver.generic_def().map(|def| generics(self.db.upcast(), def))) + .as_ref() } pub fn lower_ty_ext(&self, type_ref: &TypeRef) -> (Ty, Option) { @@ -2207,14 +2213,14 @@ pub(crate) fn generic_arg_to_chalk<'a, T>( } } -pub(crate) fn const_or_path_to_chalk( +pub(crate) fn const_or_path_to_chalk<'g>( db: &dyn HirDatabase, resolver: &Resolver, owner: TypeOwnerId, expected_ty: Ty, value: &ConstRef, mode: ParamLoweringMode, - args: impl FnOnce() -> Option, + args: impl FnOnce() -> Option<&'g Generics>, debruijn: DebruijnIndex, ) -> Const { match value {