From 72f0a9845dcae0b5e8543e69c6ea9565da1320d9 Mon Sep 17 00:00:00 2001 From: Devin Jeanpierre Date: Fri, 23 Jan 2026 18:40:49 -0800 Subject: [PATCH] Allow functions to memoize themselves without being added to the query group. This, in turn, lets us dismantle the God Object so that we don't need one giant struct with every function we ever dispatch to. This, in turn, makes it potentially cheap and easy to use memoized functions from tests (we only need to set up the _inputs_), and makes it very simple to memoize expensive functions without refactoring all callers. (By convention, the first argument is always the db already!) I'm not sold on the exact syntax -- in fact, I think it needs some work, and we should make it a proc macro wrapper thing so that we can apply it as an attribute and let rustfmt work, and even maybe to methods. PiperOrigin-RevId: 860334587 --- cc_bindings_from_rs/cc_bindings_from_rs.rs | 4 +- .../generate_bindings/database/db.rs | 3 +- .../database/fully_qualified_name.rs | 4 +- .../generate_bindings/database/lib.rs | 2 +- .../generate_bindings/format_type.rs | 53 ++-- .../generate_bindings/generate_function.rs | 14 +- .../generate_function_thunk.rs | 16 +- .../generate_struct_and_union.rs | 22 +- cc_bindings_from_rs/generate_bindings/lib.rs | 105 +++---- .../generate_bindings/test_helpers.rs | 6 +- common/error_report.rs | 2 +- common/memoized.rs | 270 ++++++++++-------- .../database/code_snippet.rs | 2 +- .../generate_bindings/database/db.rs | 53 ++-- .../generate_bindings/database/lib.rs | 2 +- .../generate_bindings/database/rs_snippet.rs | 81 +++--- .../generate_bindings_test.rs | 1 - .../generate_bindings/generate_comment.rs | 2 +- .../generate_comment_test.rs | 4 +- .../generate_dyn_callable.rs | 4 +- .../generate_bindings/generate_enum.rs | 2 +- .../generate_bindings/generate_function.rs | 62 ++-- .../generate_function_thunk.rs | 10 +- .../generate_struct_and_union.rs | 25 +- .../generate_bindings/has_bindings.rs | 20 +- rs_bindings_from_cc/generate_bindings/lib.rs | 40 ++- .../generate_bindings/rs_type_kind.rs | 2 +- .../generate_bindings/test_generators.rs | 4 +- 28 files changed, 403 insertions(+), 412 deletions(-) diff --git a/cc_bindings_from_rs/cc_bindings_from_rs.rs b/cc_bindings_from_rs/cc_bindings_from_rs.rs index 364b34a4e..74501953d 100644 --- a/cc_bindings_from_rs/cc_bindings_from_rs.rs +++ b/cc_bindings_from_rs/cc_bindings_from_rs.rs @@ -32,7 +32,7 @@ use std::rc::Rc; use cmdline::Cmdline; use code_gen_utils::CcInclude; use error_report::{ErrorReport, ErrorReporting, FatalErrors, ReportFatalError}; -use generate_bindings::{Database, IncludeGuard}; +use generate_bindings::{BindingsGenerator, IncludeGuard}; use kythe_metadata::cc_embed_provenance_map; use run_compiler::run_compiler; use token_stream_printer::{ @@ -58,7 +58,7 @@ fn new_db<'tcx>( tcx: TyCtxt<'tcx>, errors: Rc, fatal_errors: Rc, -) -> Database<'tcx> { +) -> BindingsGenerator<'tcx> { let mut crate_name_to_include_paths = , Vec>>::new(); for (crate_name, include_path) in &cmdline.crate_headers { let paths = crate_name_to_include_paths.entry(crate_name.as_str().into()).or_default(); diff --git a/cc_bindings_from_rs/generate_bindings/database/db.rs b/cc_bindings_from_rs/generate_bindings/database/db.rs index 3f94c8781..9d848c7dc 100644 --- a/cc_bindings_from_rs/generate_bindings/database/db.rs +++ b/cc_bindings_from_rs/generate_bindings/database/db.rs @@ -24,7 +24,7 @@ use std::collections::HashMap; use std::rc::Rc; memoized::query_group! { - pub trait BindingsGenerator<'tcx> { + pub struct BindingsGenerator<'tcx> { #[input] /// Compilation context for the crate that the bindings should be generated /// for. @@ -282,5 +282,4 @@ memoized::query_group! { /// Implementation: cc_bindings_from_rs/generate_bindings/generate_struct_and_union.rs?q=function:local_from_trait_impls_by_argument fn from_trait_impls_by_argument(&self, crate_num: CrateNum) -> Rc, Vec>>; } - pub struct Database; } diff --git a/cc_bindings_from_rs/generate_bindings/database/fully_qualified_name.rs b/cc_bindings_from_rs/generate_bindings/database/fully_qualified_name.rs index 3a0a9145e..3c3ac2a47 100644 --- a/cc_bindings_from_rs/generate_bindings/database/fully_qualified_name.rs +++ b/cc_bindings_from_rs/generate_bindings/database/fully_qualified_name.rs @@ -64,7 +64,7 @@ pub struct FullyQualifiedName { } fn format_ns_path_for_cc( - db: &dyn BindingsGenerator<'_>, + db: &BindingsGenerator<'_>, ns: &NamespaceQualifier, ) -> Result { let idents = @@ -73,7 +73,7 @@ fn format_ns_path_for_cc( } impl FullyQualifiedName { - pub fn format_for_cc(&self, db: &dyn BindingsGenerator<'_>) -> Result { + pub fn format_for_cc(&self, db: &BindingsGenerator<'_>) -> Result { if let Some(path) = self.unqualified.cpp_type { let path = format_cc_type_name(path.as_str())?; return Ok(path); diff --git a/cc_bindings_from_rs/generate_bindings/database/lib.rs b/cc_bindings_from_rs/generate_bindings/database/lib.rs index d2534dfe8..fba2ec6d9 100644 --- a/cc_bindings_from_rs/generate_bindings/database/lib.rs +++ b/cc_bindings_from_rs/generate_bindings/database/lib.rs @@ -12,7 +12,7 @@ mod adt_core_bindings; pub use adt_core_bindings::{AdtCoreBindings, NoMoveOrAssign}; pub mod cpp_type; mod db; -pub use db::{BindingsGenerator, Database}; +pub use db::BindingsGenerator; mod fine_grained_feature; pub use fine_grained_feature::FineGrainedFeature; mod fully_qualified_name; diff --git a/cc_bindings_from_rs/generate_bindings/format_type.rs b/cc_bindings_from_rs/generate_bindings/format_type.rs index 634639582..c39faa0b0 100644 --- a/cc_bindings_from_rs/generate_bindings/format_type.rs +++ b/cc_bindings_from_rs/generate_bindings/format_type.rs @@ -35,10 +35,7 @@ use rustc_span::symbol::Symbol; use std::rc::Rc; /// Implementation of `BindingsGenerator::format_top_level_ns_for_crate`. -pub fn format_top_level_ns_for_crate( - db: &dyn BindingsGenerator<'_>, - krate: CrateNum, -) -> Rc<[Symbol]> { +pub fn format_top_level_ns_for_crate(db: &BindingsGenerator<'_>, krate: CrateNum) -> Rc<[Symbol]> { let mut crate_name = if krate == db.source_crate_num() { "self".to_string() } else { @@ -55,12 +52,12 @@ pub fn format_top_level_ns_for_crate( } } -pub fn format_cc_ident_symbol(db: &dyn BindingsGenerator, ident: Symbol) -> Result { +pub fn format_cc_ident_symbol(db: &BindingsGenerator, ident: Symbol) -> Result { format_cc_ident(db, ident.as_str()) } /// Implementation of `BindingsGenerator::format_cc_ident`. -pub fn format_cc_ident(db: &dyn BindingsGenerator, ident: &str) -> Result { +pub fn format_cc_ident(db: &BindingsGenerator, ident: &str) -> Result { // TODO(b/254104998): Check whether the crate where the identifier is defined is // enabled for the feature. Right now if the dep enables the feature but the // current crate doesn't, we will escape the identifier in the dep but @@ -74,7 +71,7 @@ pub fn format_cc_ident(db: &dyn BindingsGenerator, ident: &str) -> Result } pub fn format_pointer_or_reference_ty_for_cc<'tcx>( - db: &dyn BindingsGenerator<'tcx>, + db: &BindingsGenerator<'tcx>, pointee: SugaredTy<'tcx>, mutability: Mutability, pointer_sigil: TokenStream, @@ -93,7 +90,7 @@ pub fn format_pointer_or_reference_ty_for_cc<'tcx>( } pub fn format_slice_pointer_for_cc<'tcx>( - db: &dyn BindingsGenerator<'tcx>, + db: &BindingsGenerator<'tcx>, slice_ty: SugaredTy<'tcx>, mutability: rustc_middle::mir::Mutability, ) -> Result { @@ -119,12 +116,12 @@ pub fn format_slice_pointer_for_cc<'tcx>( } /// Returns a CcSnippet referencing `rs_std::StrRef` and its include path. -pub fn format_str_ref_for_cc(db: &dyn BindingsGenerator<'_>) -> CcSnippet { +pub fn format_str_ref_for_cc(db: &BindingsGenerator<'_>) -> CcSnippet { CcSnippet::with_include(quote! { rs_std::StrRef }, db.support_header("rs_std/str_ref.h")) } pub fn format_transparent_pointee_or_reference_for_cc<'tcx>( - db: &dyn BindingsGenerator<'tcx>, + db: &BindingsGenerator<'tcx>, referent_ty: Ty<'tcx>, mutability: rustc_middle::mir::Mutability, pointer_sigil: TokenStream, @@ -146,7 +143,7 @@ pub fn format_transparent_pointee_or_reference_for_cc<'tcx>( /// Implementation of `BindingsGenerator::format_ty_for_cc`. pub fn format_ty_for_cc<'tcx>( - db: &dyn BindingsGenerator<'tcx>, + db: &BindingsGenerator<'tcx>, ty: SugaredTy<'tcx>, location: TypeLocation, ) -> Result { @@ -543,7 +540,7 @@ fn treat_ref_as_ptr<'tcx>( /// Returns the C++ return type. pub fn format_ret_ty_for_cc<'tcx>( - db: &dyn BindingsGenerator<'tcx>, + db: &BindingsGenerator<'tcx>, sig_mid: &ty::FnSig<'tcx>, ) -> Result { let output_ty = SugaredTy::fn_output(sig_mid); @@ -589,7 +586,7 @@ pub struct CcParamTy { /// Returns the C++ parameter types. pub fn format_param_types_for_cc<'tcx>( - db: &dyn BindingsGenerator<'tcx>, + db: &BindingsGenerator<'tcx>, sig_mid: &ty::FnSig<'tcx>, has_self_param: bool, ) -> Result> { @@ -614,7 +611,7 @@ pub fn format_param_types_for_cc<'tcx>( } fn try_ty_as_maybe_uninit<'tcx>( - db: &dyn BindingsGenerator<'_>, + db: &BindingsGenerator<'_>, ty: &Ty<'tcx>, ) -> Option> { if let ty::TyKind::Adt(adt, substs) = ty.kind() { @@ -627,7 +624,7 @@ fn try_ty_as_maybe_uninit<'tcx>( /// Format a supported `repr(transparent)` pointee type pub fn format_transparent_pointee<'tcx>( - db: &dyn BindingsGenerator<'tcx>, + db: &BindingsGenerator<'tcx>, ty: &Ty<'tcx>, ) -> Result { let Some(generic_arg) = try_ty_as_maybe_uninit(db, ty) else { @@ -642,7 +639,7 @@ fn has_non_lifetime_substs(substs: &[ty::GenericArg]) -> bool { } fn format_fn_ptr_for_rs<'tcx>( - db: &dyn BindingsGenerator<'tcx>, + db: &BindingsGenerator<'tcx>, binder_with_fn_sig_tys: ty::Binder>>, fn_header: ty::FnHeader>, ) -> Result { @@ -698,10 +695,7 @@ fn format_fn_ptr_for_rs<'tcx>( /// than just `SomeStruct`. // // TODO(b/259724276): This function's results should be memoized. -pub fn format_ty_for_rs<'tcx>( - db: &dyn BindingsGenerator<'tcx>, - ty: Ty<'tcx>, -) -> Result { +pub fn format_ty_for_rs<'tcx>(db: &BindingsGenerator<'tcx>, ty: Ty<'tcx>) -> Result { Ok(match ty.kind() { ty::TyKind::Bool | ty::TyKind::Float(_) @@ -806,7 +800,7 @@ pub fn format_ty_for_rs<'tcx>( } pub fn format_region_as_cc_lifetime<'tcx>( - db: &dyn BindingsGenerator<'tcx>, + db: &BindingsGenerator<'tcx>, region: &ty::Region<'tcx>, prereqs: &mut CcPrerequisites, ) -> TokenStream { @@ -885,10 +879,7 @@ fn layout_pointer_like(from: &Layout, data_layout: &TargetDataLayout) -> bool { } /// Returns an error if `ty` is not pointer-like. -pub fn ensure_ty_is_pointer_like<'tcx>( - db: &dyn BindingsGenerator<'tcx>, - ty: Ty<'tcx>, -) -> Result<()> { +pub fn ensure_ty_is_pointer_like<'tcx>(db: &BindingsGenerator<'tcx>, ty: Ty<'tcx>) -> Result<()> { if let ty::TyKind::Adt(adt, _) = ty.kind() { if !adt.repr().transparent() { bail!("Can't convert {ty} to a C++ pointer as it's not `repr(transparent)`"); @@ -908,7 +899,7 @@ pub fn ensure_ty_is_pointer_like<'tcx>( } pub fn crubit_abi_type_from_ty<'tcx>( - db: &dyn BindingsGenerator<'tcx>, + db: &BindingsGenerator<'tcx>, ty: Ty<'tcx>, ) -> Result { Ok(CrubitAbiTypeWithCcPrereqs::from(match ty.kind() { @@ -1027,7 +1018,7 @@ pub enum BridgedBuiltin { impl BridgedBuiltin { /// Determines if an AdtDef is for a Result or Option or neither. - pub fn new(db: &dyn BindingsGenerator<'_>, adt: AdtDef<'_>) -> Option { + pub fn new(db: &BindingsGenerator<'_>, adt: AdtDef<'_>) -> Option { let variant = adt.variants().iter().next()?; match db.tcx().lang_items().from_def_id(variant.def_id) { @@ -1042,7 +1033,7 @@ impl BridgedBuiltin { /// Returns an error is `crubit_abi_type_from_ty` fails for any of the generic args. pub fn crubit_abi_type<'tcx>( self, - db: &dyn BindingsGenerator<'tcx>, + db: &BindingsGenerator<'tcx>, substs: &[GenericArg<'tcx>], ) -> Result { match self { @@ -1081,7 +1072,7 @@ impl BridgedBuiltin { /// Returns a CrubitAbiType for a manually annotated composable bridged ADT. /// May return an error is `crubit_abi_type_from_ty` fails for any of the generic args. fn crubit_abi_type_from_bridged_adt<'tcx>( - db: &dyn BindingsGenerator<'tcx>, + db: &BindingsGenerator<'tcx>, abi_rust: Symbol, abi_cpp: Symbol, substs: &[GenericArg<'tcx>], @@ -1115,7 +1106,7 @@ fn crubit_abi_type_from_bridged_adt<'tcx>( /// Returns None if the type is not manually annotated as bridged. /// Returns an error if getting the bridging attributes fails. fn is_manually_annotated_bridged_adt<'tcx>( - db: &dyn BindingsGenerator<'tcx>, + db: &BindingsGenerator<'tcx>, ty: Ty<'tcx>, ) -> Result> { // We take a `Ty` instead of adt + substs directly so we can use `Ty` in error messages. @@ -1198,7 +1189,7 @@ fn is_manually_annotated_bridged_adt<'tcx>( /// is configured. An error is returned if the type is a pointer or reference or /// the attribute could not be parsed or is in an invalid state. pub fn is_bridged_type<'tcx>( - db: &dyn BindingsGenerator<'tcx>, + db: &BindingsGenerator<'tcx>, ty: Ty<'tcx>, ) -> Result> { match ty.kind() { diff --git a/cc_bindings_from_rs/generate_bindings/generate_function.rs b/cc_bindings_from_rs/generate_bindings/generate_function.rs index b6d239602..f4e37ad2b 100644 --- a/cc_bindings_from_rs/generate_bindings/generate_function.rs +++ b/cc_bindings_from_rs/generate_bindings/generate_function.rs @@ -61,7 +61,7 @@ impl FunctionKind { } fn thunk_name( - db: &dyn BindingsGenerator, + db: &BindingsGenerator, def_id: DefId, export_name: Option, needs_thunk: bool, @@ -129,7 +129,7 @@ fn ident_for_each(prefix: &str, n: usize) -> Vec { /// Returns a `TokenStream` containing an expression that evaluates to the /// C-ABI-compatible version of the type. fn cc_param_to_c_abi<'tcx>( - db: &dyn BindingsGenerator<'tcx>, + db: &BindingsGenerator<'tcx>, cc_ident: Ident, ty: SugaredTy<'tcx>, post_analysis_typing_env: ty::TypingEnv<'tcx>, @@ -243,7 +243,7 @@ struct ReturnConversion { } fn format_ty_for_cc_amending_prereqs<'tcx>( - db: &dyn BindingsGenerator<'tcx>, + db: &BindingsGenerator<'tcx>, ty: SugaredTy<'tcx>, prereqs: &mut CcPrerequisites, ) -> Result { @@ -254,7 +254,7 @@ fn format_ty_for_cc_amending_prereqs<'tcx>( } fn cc_return_value_from_c_abi<'tcx>( - db: &dyn BindingsGenerator<'tcx>, + db: &BindingsGenerator<'tcx>, ident: Ident, ty: SugaredTy<'tcx>, prereqs: &mut CcPrerequisites, @@ -477,7 +477,7 @@ struct RefsToCheckForAliasing<'a, 'tcx> { /// C++ does not have this requirement, so we insert checks in the generated bindings to ensure that /// this requirement is not violated. fn refs_to_check_for_aliasing<'tcx, 'a>( - db: &dyn BindingsGenerator<'tcx>, + db: &BindingsGenerator<'tcx>, params: &'a [Param<'tcx>], ) -> Option> { let tcx = db.tcx(); @@ -543,7 +543,7 @@ impl ThunkSelfParameter { /// Generates the wrapping code to call a thunk and return its result. /// This can be checking parameter invariants or creating a slot to pass as an output pointer. pub(crate) fn generate_thunk_call<'tcx>( - db: &dyn BindingsGenerator<'tcx>, + db: &BindingsGenerator<'tcx>, def_id: DefId, thunk_name: Ident, rs_return_type: SugaredTy<'tcx>, @@ -656,7 +656,7 @@ pub(crate) fn generate_thunk_call<'tcx>( } /// Implementation of `BindingsGenerator::generate_function`. -pub fn generate_function(db: &dyn BindingsGenerator<'_>, def_id: DefId) -> Result { +pub fn generate_function(db: &BindingsGenerator<'_>, def_id: DefId) -> Result { let tcx = db.tcx(); ensure!( !tcx.generics_of(def_id).requires_monomorphization(tcx), diff --git a/cc_bindings_from_rs/generate_bindings/generate_function_thunk.rs b/cc_bindings_from_rs/generate_bindings/generate_function_thunk.rs index e19a49047..12f42713f 100644 --- a/cc_bindings_from_rs/generate_bindings/generate_function_thunk.rs +++ b/cc_bindings_from_rs/generate_bindings/generate_function_thunk.rs @@ -80,7 +80,7 @@ fn array_c_abi_c_type<'tcx>(tcx: ty::TyCtxt<'tcx>, inner_ty: ty::Ty<'tcx>) -> Re /// Formats a C++ declaration of a C-ABI-compatible-function wrapper around a Rust function. pub fn generate_thunk_decl<'tcx>( - db: &dyn BindingsGenerator<'tcx>, + db: &BindingsGenerator<'tcx>, sig_mid: &ty::FnSig<'tcx>, thunk_name: &Ident, has_self_param: bool, @@ -180,7 +180,7 @@ pub fn generate_thunk_decl<'tcx>( /// Expects an exising local of type `cpp_type` named `local_name` and shadows it /// with a local of type `ty` named `local_name`. fn convert_bridged_type_from_c_abi_to_rust<'tcx>( - db: &dyn BindingsGenerator<'tcx>, + db: &BindingsGenerator<'tcx>, ty: ty::Ty<'tcx>, bridged_type: &BridgedType, local_name: &Ident, @@ -234,7 +234,7 @@ fn convert_bridged_type_from_c_abi_to_rust<'tcx>( /// Converts a local named `local_name` from its C ABI-compatible type /// `*const [*const core::ffi::c_void; ]` to a tuple of Rust types. fn convert_tuple_from_c_abi_to_rust<'tcx>( - db: &dyn BindingsGenerator<'tcx>, + db: &BindingsGenerator<'tcx>, tuple_tys: &[ty::Ty<'tcx>], local_name: &Ident, extern_c_decls: &mut BTreeSet, @@ -263,7 +263,7 @@ fn convert_tuple_from_c_abi_to_rust<'tcx>( /// Returns code to convert a local named `local_name` from its C ABI-compatible type to its Rust /// type. fn convert_value_from_c_abi_to_rust<'tcx>( - db: &dyn BindingsGenerator<'tcx>, + db: &BindingsGenerator<'tcx>, ty: ty::Ty<'tcx>, local_name: &Ident, extern_c_decls: &mut BTreeSet, @@ -290,7 +290,7 @@ fn convert_value_from_c_abi_to_rust<'tcx>( } fn c_abi_for_param_type<'tcx>( - db: &dyn BindingsGenerator<'tcx>, + db: &BindingsGenerator<'tcx>, ty: ty::Ty<'tcx>, ) -> Result { let tcx = db.tcx(); @@ -378,7 +378,7 @@ fn add_extern_c_decl( /// Writes a Rust value out into the memory pointed to a `*mut c_void` pointed to by `c_ptr`. fn write_rs_value_to_c_abi_ptr<'tcx>( - db: &dyn BindingsGenerator<'tcx>, + db: &BindingsGenerator<'tcx>, rs_value: &Ident, c_ptr: &Ident, rs_type: ty::Ty<'tcx>, @@ -496,7 +496,7 @@ where /// - `<::crate_name::some_module::SomeStruct as /// ::core::default::Default>::default` pub fn generate_thunk_impl<'tcx>( - db: &dyn BindingsGenerator<'tcx>, + db: &BindingsGenerator<'tcx>, fn_def_id: DefId, sig: &ty::FnSig<'tcx>, thunk_name: &str, @@ -628,7 +628,7 @@ pub struct TraitThunks { } pub fn generate_trait_thunks<'tcx>( - db: &dyn BindingsGenerator<'tcx>, + db: &BindingsGenerator<'tcx>, trait_id: DefId, // We do not support other generic args, yet. type_args: &[Ty<'tcx>], diff --git a/cc_bindings_from_rs/generate_bindings/generate_struct_and_union.rs b/cc_bindings_from_rs/generate_bindings/generate_struct_and_union.rs index d6e35bfe6..55085afeb 100644 --- a/cc_bindings_from_rs/generate_bindings/generate_struct_and_union.rs +++ b/cc_bindings_from_rs/generate_bindings/generate_struct_and_union.rs @@ -74,7 +74,7 @@ pub fn cpp_enum_rust_underlying_type(tcx: TyCtxt, def_id: DefId) -> Result { /// Returns the C++ underlying type of the `cpp_enum` struct specified by the given def id. pub(crate) fn cpp_enum_cpp_underlying_type( - db: &dyn BindingsGenerator, + db: &BindingsGenerator, def_id: DefId, ) -> Result { let tcx = db.tcx(); @@ -183,7 +183,7 @@ pub fn scalar_value_to_string(tcx: TyCtxt, scalar: Scalar, kind: TyKind) -> Resu /// }; /// ``` fn generate_cpp_enum<'tcx>( - db: &dyn BindingsGenerator<'tcx>, + db: &BindingsGenerator<'tcx>, core: Rc>, ) -> ApiSnippets { let tcx = db.tcx(); @@ -286,7 +286,7 @@ fn is_supported_associated_item<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool } pub(crate) fn generate_associated_item<'tcx>( - db: &dyn BindingsGenerator<'tcx>, + db: &BindingsGenerator<'tcx>, assoc_item: &ty::AssocItem, member_function_names: &mut HashSet, ) -> Option { @@ -352,7 +352,7 @@ fn erase_regions<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { } pub fn from_trait_impls_by_argument<'tcx>( - db: &dyn BindingsGenerator<'tcx>, + db: &BindingsGenerator<'tcx>, crate_num: CrateNum, ) -> Rc, Vec>> { let tcx = db.tcx(); @@ -391,7 +391,7 @@ pub fn from_trait_impls_by_argument<'tcx>( } fn generate_into_impls<'tcx>( - db: &dyn BindingsGenerator<'tcx>, + db: &BindingsGenerator<'tcx>, core: &AdtCoreBindings<'tcx>, ) -> ApiSnippets { let tcx = db.tcx(); @@ -527,7 +527,7 @@ fn generate_into_impls<'tcx>( /// `generate_adt_core` returns success we have committed to emitting C++ /// bindings for the ADT. pub fn generate_adt<'tcx>( - db: &dyn BindingsGenerator<'tcx>, + db: &BindingsGenerator<'tcx>, core: Rc>, ) -> ApiSnippets { let tcx = db.tcx(); @@ -727,7 +727,7 @@ pub fn generate_adt<'tcx>( /// Implementation of `BindingsGenerator::adt_needs_bindings`. pub fn adt_needs_bindings<'tcx>( - db: &dyn BindingsGenerator<'tcx>, + db: &BindingsGenerator<'tcx>, def_id: DefId, ) -> Result>> { let tcx = db.tcx(); @@ -761,7 +761,7 @@ pub fn adt_needs_bindings<'tcx>( /// Implementation of `BindingsGenerator::generate_adt_core`. pub fn generate_adt_core<'tcx>( - db: &dyn BindingsGenerator<'tcx>, + db: &BindingsGenerator<'tcx>, def_id: DefId, ) -> Result>> { let tcx = db.tcx(); @@ -873,7 +873,7 @@ fn anonymous_field_ident(index: usize) -> Ident { } fn generate_tuple_struct_ctor<'tcx>( - db: &dyn BindingsGenerator<'tcx>, + db: &BindingsGenerator<'tcx>, core: Rc>, ) -> Option { let tcx = db.tcx(); @@ -970,7 +970,7 @@ fn generate_tuple_struct_ctor<'tcx>( /// Returns the body of the C++ struct that represents the given ADT. fn generate_fields<'tcx>( - db: &dyn BindingsGenerator<'tcx>, + db: &BindingsGenerator<'tcx>, core: &AdtCoreBindings<'tcx>, member_function_names: &HashSet, ) -> ApiSnippets { @@ -1693,7 +1693,7 @@ fn generate_fields<'tcx>( /// Generates the `(UnsafeRelocateTag, T&&)` constructor for the given ADT. fn generate_relocating_ctor<'tcx>( - db: &dyn BindingsGenerator<'tcx>, + db: &BindingsGenerator<'tcx>, core: Rc>, ) -> ApiSnippets { let adt_cc_name = &core.cc_short_name; diff --git a/cc_bindings_from_rs/generate_bindings/lib.rs b/cc_bindings_from_rs/generate_bindings/lib.rs index 6e498434c..88cd8cffc 100644 --- a/cc_bindings_from_rs/generate_bindings/lib.rs +++ b/cc_bindings_from_rs/generate_bindings/lib.rs @@ -39,10 +39,10 @@ use arc_anyhow::{Context, Error, Result}; use code_gen_utils::{format_cc_includes, CcConstQualifier, CcInclude, NamespaceQualifier}; use database::code_snippet::{ApiSnippets, CcPrerequisites, CcSnippet, ExternCDecl, RsSnippet}; use database::{ - AdtCoreBindings, BindingsGenerator, ExportedPath, FineGrainedFeature, FullyQualifiedName, - NoMoveOrAssign, PublicPaths, SugaredTy, TypeLocation, UnqualifiedName, + AdtCoreBindings, ExportedPath, FineGrainedFeature, FullyQualifiedName, NoMoveOrAssign, + PublicPaths, SugaredTy, TypeLocation, UnqualifiedName, }; -pub use database::{Database, IncludeGuard}; +pub use database::{BindingsGenerator, IncludeGuard}; use error_report::{anyhow, bail, ErrorReporting, ReportFatalError}; use itertools::Itertools; use proc_macro2::TokenStream; @@ -66,7 +66,7 @@ use std::iter::once; use std::rc::Rc; /// Implementation of `BindingsGenerator::support_header`. -fn support_header<'tcx>(db: &dyn BindingsGenerator<'tcx>, suffix: &'tcx str) -> CcInclude { +fn support_header<'tcx>(db: &BindingsGenerator<'tcx>, suffix: &'tcx str) -> CcInclude { CcInclude::support_lib_header(db.crubit_support_path_format(), suffix.into()) } @@ -75,7 +75,7 @@ pub struct BindingsTokens { pub cc_api_impl: TokenStream, } -fn add_include_guard(db: &dyn BindingsGenerator<'_>, cc_api: TokenStream) -> Result { +fn add_include_guard(db: &BindingsGenerator<'_>, cc_api: TokenStream) -> Result { let metadata_block = if db.kythe_annotations() { quote! { __HASH_TOKEN__ ifdef KYTHE_IS_RUNNING __NEWLINE__ @@ -112,13 +112,13 @@ fn add_include_guard(db: &dyn BindingsGenerator<'_>, cc_api: TokenStream) -> Res /// Wrap `repr_attrs` for use as a database function. fn repr_attrs_from_db( - db: &dyn BindingsGenerator<'_>, + db: &BindingsGenerator<'_>, def_id: DefId, ) -> Rc<[rustc_hir::attrs::ReprAttr]> { repr_attrs(db.tcx(), def_id) } -fn source_crate_num(db: &dyn BindingsGenerator<'_>) -> CrateNum { +fn source_crate_num(db: &BindingsGenerator<'_>) -> CrateNum { // This is a temporary workaround while migrating to the rmeta interface. Our old implementation // breaks with some rmeta files, notably proto files, due to crate renaming behavior. But our // new implementation relies on assuming our source is the placeholder file provided by @@ -188,8 +188,8 @@ pub fn new_database<'db>( fatal_errors: Rc, no_thunk_name_mangling: bool, h_out_include_guard: IncludeGuard, -) -> Database<'db> { - Database::new( +) -> BindingsGenerator<'db> { + BindingsGenerator::new( tcx, source_crate_name, crubit_support_path_format, @@ -229,7 +229,7 @@ pub fn new_database<'db>( ) } -pub fn generate_bindings(db: &Database) -> Result { +pub fn generate_bindings(db: &BindingsGenerator) -> Result { let tcx = db.tcx(); let top_comment = { @@ -301,7 +301,7 @@ pub fn generate_bindings(db: &Database) -> Result { } fn crate_features( - db: &dyn BindingsGenerator, + db: &BindingsGenerator, krate: CrateNum, ) -> flagset::FlagSet { let crate_features = db.crate_name_to_features(); @@ -314,7 +314,7 @@ fn crate_features( } fn check_feature_enabled_on_self_and_all_deps( - db: &dyn BindingsGenerator, + db: &BindingsGenerator, feature: FineGrainedFeature, ) -> bool { for (_, crate_features) in db.crate_name_to_features().iter() { @@ -326,7 +326,7 @@ fn check_feature_enabled_on_self_and_all_deps( } fn format_with_cc_body( - db: &dyn BindingsGenerator, + db: &BindingsGenerator, ns: &NamespaceQualifier, mut tokens: TokenStream, attributes: Vec, @@ -362,7 +362,7 @@ fn format_with_cc_body( /// Implementation of `BindingsGenerator::public_paths_by_def_id`. fn public_paths_by_def_id( - db: &dyn BindingsGenerator<'_>, + db: &BindingsGenerator<'_>, crate_num: CrateNum, ) -> HashMap { /// This is retooled logic from rustc's `visible_parent_map` function. Except where that only @@ -489,7 +489,7 @@ fn module_children(tcx: TyCtxt<'_>, parent: DefId) -> &[ModChild] { } } -fn resolve_if_use(db: &dyn BindingsGenerator<'_>, def_id: DefId) -> Option { +fn resolve_if_use(db: &BindingsGenerator<'_>, def_id: DefId) -> Option { let tcx = db.tcx(); let DefKind::Use = tcx.def_kind(def_id) else { return None; @@ -505,10 +505,7 @@ fn resolve_if_use(db: &dyn BindingsGenerator<'_>, def_id: DefId) -> Option, - def_id: DefId, -) -> Option { +fn symbol_unqualified_name(db: &BindingsGenerator<'_>, def_id: DefId) -> Option { let tcx = db.tcx(); let item_name = db .public_paths_by_def_id(def_id.krate) @@ -533,10 +530,7 @@ fn symbol_unqualified_name( } /// Implementation of `BindingsGenerator::symbol_canonical_name`. -fn symbol_canonical_name( - db: &dyn BindingsGenerator<'_>, - def_id: DefId, -) -> Option { +fn symbol_canonical_name(db: &BindingsGenerator<'_>, def_id: DefId) -> Option { let tcx = db.tcx(); // TODO: b/433286909 - We shouldn't pass DefKind::Use to this method and instead should keep what our use @@ -615,7 +609,7 @@ fn symbol_canonical_name( /// Checks whether a definition matches a specific qualified name by matching it's definition path /// against `name`. Name must include the crate in it's path. -fn matches_qualified_name(db: &dyn BindingsGenerator<'_>, item_did: DefId, name: &[&str]) -> bool { +fn matches_qualified_name(db: &BindingsGenerator<'_>, item_did: DefId, name: &[&str]) -> bool { let tcx = db.tcx(); let path = tcx.def_path(item_did); if path.data.len() + 1 != name.len() { @@ -717,7 +711,7 @@ fn generate_deprecated_tag(tcx: TyCtxt, def_id: DefId) -> Option { } fn generate_using( - db: &dyn BindingsGenerator<'_>, + db: &BindingsGenerator<'_>, using_name: &Symbol, def_id: DefId, ) -> Result { @@ -761,7 +755,7 @@ fn generate_using( } } -fn generate_const(db: &dyn BindingsGenerator<'_>, def_id: DefId) -> Result { +fn generate_const(db: &BindingsGenerator<'_>, def_id: DefId) -> Result { let tcx = db.tcx(); // TODO: b/457843120 - Remove this workaround once we can properly support float constants. let unsupported_consts = [ @@ -827,7 +821,7 @@ fn generate_const(db: &dyn BindingsGenerator<'_>, def_id: DefId) -> Result) -> Rc<[DefId]> { +fn supported_traits(db: &BindingsGenerator<'_>) -> Rc<[DefId]> { let tcx = db.tcx(); let traits = tcx .visible_traits() @@ -857,10 +851,7 @@ fn supported_traits(db: &dyn BindingsGenerator<'_>) -> Rc<[DefId]> { Rc::from(traits) } -fn generate_trait( - db: &dyn BindingsGenerator<'_>, - trait_id: DefId, -) -> arc_anyhow::Result { +fn generate_trait(db: &BindingsGenerator<'_>, trait_id: DefId) -> arc_anyhow::Result { if !db.supported_traits().contains(&trait_id) { bail!("Trait is not yet supported") } @@ -886,7 +877,7 @@ fn generate_trait( } fn generate_type_alias( - db: &dyn BindingsGenerator<'_>, + db: &BindingsGenerator<'_>, def_id: DefId, using_name: &str, ) -> Result { @@ -897,7 +888,7 @@ fn generate_type_alias( } fn create_type_alias<'tcx>( - db: &dyn BindingsGenerator<'tcx>, + db: &BindingsGenerator<'tcx>, def_id: DefId, alias_name: &str, alias_type: SugaredTy<'tcx>, @@ -926,11 +917,11 @@ fn create_type_alias<'tcx>( /// Implementation of `BindingsGenerator::generate_default_ctor`. fn generate_default_ctor<'tcx>( - db: &dyn BindingsGenerator<'tcx>, + db: &BindingsGenerator<'tcx>, core: Rc>, ) -> Result { fn fallible_format_default_ctor<'tcx>( - db: &dyn BindingsGenerator<'tcx>, + db: &BindingsGenerator<'tcx>, core: Rc>, ) -> Result { let tcx = db.tcx(); @@ -996,11 +987,11 @@ fn generate_default_ctor<'tcx>( /// Implementation of `BindingsGenerator::generate_copy_ctor_and_assignment_operator`. fn generate_copy_ctor_and_assignment_operator<'tcx>( - db: &dyn BindingsGenerator<'tcx>, + db: &BindingsGenerator<'tcx>, core: Rc>, ) -> Result { fn fallible_format_copy_ctor_and_assignment_operator<'tcx>( - db: &dyn BindingsGenerator<'tcx>, + db: &BindingsGenerator<'tcx>, core: Rc>, ) -> Result { let tcx = db.tcx(); @@ -1081,11 +1072,11 @@ fn generate_copy_ctor_and_assignment_operator<'tcx>( /// Implementation of `BindingsGenerator::generate_move_ctor_and_assignment_operator`. #[allow(clippy::result_large_err)] fn generate_move_ctor_and_assignment_operator<'tcx>( - db: &dyn BindingsGenerator<'tcx>, + db: &BindingsGenerator<'tcx>, core: Rc>, ) -> Result { fn fallible_format_move_ctor_and_assignment_operator<'tcx>( - db: &dyn BindingsGenerator<'tcx>, + db: &BindingsGenerator<'tcx>, core: Rc>, ) -> Result { let tcx = db.tcx(); @@ -1199,7 +1190,7 @@ fn generate_move_ctor_and_assignment_operator<'tcx>( /// /// Will panic if `def_id` doesn't identify an ADT that can be successfully /// handled by `generate_adt_core`. -fn generate_fwd_decl(db: &Database<'_>, def_id: DefId) -> TokenStream { +fn generate_fwd_decl(db: &BindingsGenerator<'_>, def_id: DefId) -> TokenStream { // `generate_fwd_decl` should only be called for items from // `CcPrerequisites::fwd_decls` and `fwd_decls` should only contain ADTs // that `generate_adt_core` succeeds for. @@ -1223,7 +1214,7 @@ fn generate_fwd_decl(db: &Database<'_>, def_id: DefId) -> TokenStream { } fn generate_kythe_doc_comment( - db: &dyn BindingsGenerator, + db: &BindingsGenerator, def_id: DefId, doc_comment: String, ) -> TokenStream { @@ -1246,7 +1237,7 @@ fn generate_kythe_doc_comment( quote! { __CAPTURE_TAG__ #file_name #start #end __COMMENT__ #doc_comment} } -fn generate_source_location(db: &dyn BindingsGenerator, def_id: DefId) -> String { +fn generate_source_location(db: &BindingsGenerator, def_id: DefId) -> String { let tcx = db.tcx(); let def_span = tcx.def_span(def_id); let rustc_span::FileLines { file, lines } = @@ -1274,7 +1265,7 @@ fn generate_source_location(db: &dyn BindingsGenerator, def_id: DefId) -> String /// Formats the doc comment (if any) associated with the item identified by /// `local_def_id`, and appends the source location at which the item is /// defined. -fn generate_doc_comment(db: &dyn BindingsGenerator, def_id: DefId) -> TokenStream { +fn generate_doc_comment(db: &BindingsGenerator, def_id: DefId) -> TokenStream { let mut docs = db .tcx() .get_all_attrs(def_id) @@ -1299,14 +1290,11 @@ fn generate_doc_comment(db: &dyn BindingsGenerator, def_id: DefId) -> TokenStrea /// Returns the name of the item identified by `def_id`, or "" if /// the item can't be identified. -fn item_name(db: &dyn BindingsGenerator<'_>, def_id: DefId) -> Symbol { +fn item_name(db: &BindingsGenerator<'_>, def_id: DefId) -> Symbol { db.tcx().opt_item_name(def_id).unwrap_or_else(|| Symbol::intern("")) } -fn item_name_for_error_report( - db: &dyn BindingsGenerator<'_>, - def_id: DefId, -) -> error_report::ItemName { +fn item_name_for_error_report(db: &BindingsGenerator<'_>, def_id: DefId) -> error_report::ItemName { let name = format!( "{}::{}", db.tcx().crate_name(db.source_crate_num()), @@ -1318,7 +1306,7 @@ fn item_name_for_error_report( } /// Implementation of `BindingsGenerator::generate_item`. -fn generate_item(db: &dyn BindingsGenerator<'_>, def_id: DefId) -> Result> { +fn generate_item(db: &BindingsGenerator<'_>, def_id: DefId) -> Result> { let tcx = db.tcx(); let generated = generate_item_impl(db, def_id); let attributes = crubit_attr::get_attrs(tcx, def_id).unwrap(); @@ -1349,10 +1337,7 @@ macro_rules! error_scope { // A helper for `generate_item`. // The wrapper is used to ensure that the `must_bind` annotation is enforced. -fn generate_item_impl( - db: &dyn BindingsGenerator<'_>, - def_id: DefId, -) -> Result> { +fn generate_item_impl(db: &BindingsGenerator<'_>, def_id: DefId) -> Result> { let tcx = db.tcx(); if db.symbol_canonical_name(def_id).is_none() { return Ok(None); @@ -1380,11 +1365,7 @@ fn generate_item_impl( /// Formats a C++ comment explaining why no bindings have been generated for /// `local_def_id`. -fn generate_unsupported_def( - db: &dyn BindingsGenerator<'_>, - def_id: DefId, - err: Error, -) -> CcSnippet { +fn generate_unsupported_def(db: &BindingsGenerator<'_>, def_id: DefId, err: Error) -> CcSnippet { let tcx = db.tcx(); db.errors().assert_in_item(item_name_for_error_report(db, def_id)); db.errors().report(&err); @@ -1431,7 +1412,7 @@ fn generate_unsupported_def( /// #tokens /// ``` pub fn format_namespace_bound_cc_tokens( - db: &dyn BindingsGenerator<'_>, + db: &BindingsGenerator<'_>, iter: impl IntoIterator, NamespaceQualifier, TokenStream)>, tcx: TyCtxt, ) -> TokenStream { @@ -1511,7 +1492,7 @@ struct FormattedItem { /// Generate bindings to supported trait implementations. An implementation is supported if both /// its trait and implementing type receive bindings. fn generate_trait_impls<'a, 'b>( - db: &'a dyn BindingsGenerator<'b>, + db: &'a BindingsGenerator<'b>, ) -> impl Iterator + use<'a, 'b> { let tcx = db.tcx(); let supported_traits: Vec = db.supported_traits().iter().copied().collect(); @@ -1627,7 +1608,7 @@ fn generate_trait_impls<'a, 'b>( }) } -fn formatted_items_in_crate(db: &dyn BindingsGenerator<'_>) -> impl Iterator { +fn formatted_items_in_crate(db: &BindingsGenerator<'_>) -> impl Iterator { let tcx = db.tcx(); let defs_in_crate = db.public_paths_by_def_id(db.source_crate_num()); defs_in_crate @@ -1659,7 +1640,7 @@ fn formatted_items_in_crate(db: &dyn BindingsGenerator<'_>) -> impl Iterator Result { +fn generate_crate(db: &BindingsGenerator) -> Result { struct CcDetails { def_id: DefId, namespace: NamespaceQualifier, diff --git a/cc_bindings_from_rs/generate_bindings/test_helpers.rs b/cc_bindings_from_rs/generate_bindings/test_helpers.rs index 4e37722b5..571c246bb 100644 --- a/cc_bindings_from_rs/generate_bindings/test_helpers.rs +++ b/cc_bindings_from_rs/generate_bindings/test_helpers.rs @@ -9,7 +9,7 @@ extern crate rustc_middle; use arc_anyhow::Result; use database::code_snippet::ApiSnippets; -use database::{BindingsGenerator as _, Database, IncludeGuard}; +use database::{BindingsGenerator, IncludeGuard}; use error_report::{FatalErrors, IgnoreErrors}; use generate_bindings::{generate_bindings, new_database, BindingsTokens}; use run_compiler_test_support::{find_def_id_by_name, run_compiler_for_testing}; @@ -72,7 +72,7 @@ fn bindings_db_for_tests_with_features( tcx: TyCtxt, features: flagset::FlagSet, with_kythe_annotations: bool, -) -> Database { +) -> BindingsGenerator { new_database( tcx, /* source_crate_name= */ None, @@ -96,7 +96,7 @@ fn bindings_db_for_tests_with_features( ) } -pub fn bindings_db_for_tests(tcx: TyCtxt) -> Database { +pub fn bindings_db_for_tests(tcx: TyCtxt) -> BindingsGenerator { bindings_db_for_tests_with_features( tcx, crubit_feature::CrubitFeature::Experimental | crubit_feature::CrubitFeature::Supported, diff --git a/common/error_report.rs b/common/error_report.rs index cb135e147..6ee71e4cd 100644 --- a/common/error_report.rs +++ b/common/error_report.rs @@ -224,7 +224,7 @@ pub struct ErrorReport { // a method call, and the methods do not call each other. map: RefCell>, // TODO(jeanpierreda): This should really be passed around rather than mutated in the - // BindingsGenerator. For example, if we used a totally separate `dyn BindingsGenerator` + // BindingsGenerator. For example, if we used a totally separate `BindingsGenerator` // which is the same as the old one except that it has a different input. current_item: RefCell>, } diff --git a/common/memoized.rs b/common/memoized.rs index 203a0891c..a7f73cb59 100644 --- a/common/memoized.rs +++ b/common/memoized.rs @@ -24,6 +24,8 @@ //! `Hash`. //! * Supports `#[break_cycles_with = ]`, which generates a //! function that returns if a cycle is detected. +//! * Uses function pointers in the interior of a concrete type, instead of +//! `dyn Trait`. //! //! There are more substantial differences with Salsa 2022 - this was written //! based on Salsa 0.16. We don't need to match exactly the API, but the @@ -41,7 +43,9 @@ /// /// ``` /// query_group! { -/// trait QueryGroupName { +/// // QueryGroup name is the name of the memoized query object, including +/// // all relevant state. +/// struct QueryGroup { /// // First, all shared inputs are specified, in order. /// // /// // These are available to all of the memoized functions, by calling `db.some_input()`, etc., @@ -66,17 +70,17 @@ /// // parameters, and return a `Clone` return type. /// // /// // Each of these must be implemented in the _same module_ as a top-level function, with -/// // the same function signature except taking `&dyn QueryGroupName` instead of `&self`. +/// // the same function signature. /// // -/// // The functions can call methods on the `&dyn QueryGroupName` to access both the shared -/// // inputs, as well to call other memoized functions. +/// // The functions can call methods on the `&QueryGroup` self argument to access both +/// // the shared inputs, as well to call other memoized functions. /// // /// // Inputs to the computation which change from call to call should be specified as function /// // parameters. Inputs which never change can be either `#[input]` functions, or actual /// // program globals. /// // -/// // When called on the `&dyn QueryGroupName` or directly on the concrete type, the functions -/// // will be memoized, and the return value will be cached, automatically. +/// // When called on the `&QueryGroup`, the functions will be memoized, and the return +/// // value will be cached, automatically. /// // /// // Some functions may need to gracefully handle cycles, in which case they should be /// // annotated with `#[break_cycles_with = ]`. This will generate a function @@ -91,33 +95,30 @@ /// /// Doc comment goes here. /// fn some_function(&self, arg: ArgType) -> ReturnType; /// } -/// // The concrete type for the storage of inputs and memoized values. -/// // `query_group!` will add the required fields to this struct. -/// struct Database; /// } /// /// // The non-memoized implementation of the memoized functions -/// fn may_by_cyclic(db: &dyn QueryGroupName, arg: ArgType) -> ReturnType { +/// fn may_by_cyclic(db: &QueryGroup, arg: ArgType) -> ReturnType { /// // ... /// } /// -/// fn some_function(db: &dyn QueryGroupName, arg: ArgType) -> ReturnType { +/// fn some_function(db: &QueryGroup, arg: ArgType) -> ReturnType { /// // ... /// } /// ``` /// -/// A new instance of `Database` can be created by using `Database::new(input, +/// A new instance of `QueryGroup` can be created by using `QueryGroup::new(input, /// values, here)`. It will implement the trait defined above: the `#[input]` -/// functions will return the corresponding values passed in to `Database::new`, +/// functions will return the corresponding values passed in to `QueryGroup::new`, /// and the memoized functions will call the corresponding top-level functions. /// /// For example, above, one could run `let db = -/// Database::new(InputType::default())`. +/// QueryGroup::new(InputType::default())`. /// /// Now, if you call `db.some_function(...)`, it will either return a cached -/// value (if one is present), or else execute `some_function(&db as &dyn -/// QueryGroupName, ...)`, and cache and return the result. A direct call to -/// `some_function` (instead of `db.some_function`) is not directly memoized. +/// value (if one is present), or else execute `some_function(&db)`, and cache +/// and return the result. A direct call to `some_function` (instead of +/// `db.some_function`) is not directly memoized. /// /// Because the results are saved, it's very important that the functions are /// pure and have no side-effects. In particular, internal mutability on the @@ -128,8 +129,8 @@ /// * In the trait definition, all `#[input]` functions must be declared before /// all (non-`#[input]`) memoized functions. The order of the input functions /// is the order of their parameters in `new()`. -/// * Every (non-`#[input]`) trait method _must_ have a matching top-level -/// function, with `&self` replaced by `&dyn QueryGroupName`. +/// * Every (non-`#[input]`) trait method _must_ have a matching function passed +/// to `new()`. /// * Since all trait methods are memoized, their arguments must be `Clone`, /// `Eq`, and `Hash`. /// @@ -140,31 +141,30 @@ /// /// ``` /// query_group! { -/// trait QueryGroupName<'a> { +/// struct QueryGroup<'a> { /// #[input] /// fn some_input(&self) -> &'a InputType; /// fn some_function(&self, arg: &'a ArgType) -> &'a ReturnType; /// } -/// struct Database; /// } /// -/// fn<'a> some_function(db: &dyn QueryGroupName<'a>, arg: &'a ArgType) -> &'a ReturnType { +/// fn<'a> some_function(db: &QueryGroup<'a>, arg: &'a ArgType) -> &'a ReturnType { /// // ... /// } /// ``` /// -/// Note that under the hood, `struct Database` will be replaced by something +/// Note that under the hood, `QueryGroup` will bedefined as something /// like: /// /// ``` -/// struct Database<'a> {...} +/// struct QueryGroup<'a> {...} /// ``` /// /// And so you may need to specify the lifetime in some uses. #[macro_export] macro_rules! query_group { ( - $trait_vis:vis trait $trait:ident $(<$($type_param:tt),*>)?{ + $vis:vis struct $database_struct:ident $(<$($type_param:tt),*>)?{ $( // TODO(jeanpierreda): Ideally would allow putting the doc-comment first, // but this causes parsing ambiguity. @@ -201,73 +201,35 @@ macro_rules! query_group { fn $provided_function:ident(&$provided_self:ident $(, $provided_arg:ident : $provided_arg_type:ty)* $(,)?) -> $provided_type:ty { $($provided_body:tt)* } )* } - - $struct_vis:vis struct $database_struct:ident; ) => { - // First, yes, generate the trait. - $trait_vis trait $trait $(<$($type_param),*>)?{ - $( - $(#[doc = $input_doc])* - fn $input_function(&self) -> $input_type { unimplemented!(concat!("input function '", stringify!($input_function), "'")) } - )* - $( - $(#[doc = $break_cycles_doc])* - fn $break_cycles_function( - &self, - $( - $break_cycles_arg : $break_cycles_arg_type - ),* - ) -> $break_cycles_return_type { _ = ($($break_cycles_arg),*); unimplemented!(concat!("break cycles function '", stringify!($break_cycles_function), "'")) } - )* - $( - $(#[doc = $function_doc])* - fn $function( - &self, - $( - $arg : $arg_type - ),* - ) -> $return_type { _ = ($($arg),*); unimplemented!(concat!("function '", stringify!($function), "'")) } - )* - $( - $(#[doc = $provided_doc])* - fn $provided_function(&$provided_self $(, $provided_arg: $provided_arg_type)*) -> $provided_type { _ = ($($provided_arg),*); unimplemented!(concat!("provided function '", stringify!($provided_function), "'")) } - )* - } - - // Avoid having to repeat the `$type_param` metavariable below, since its repetition - // should not be zipped with other metavariable repetitions. - // This also avoids having to repeat out `&dyn $trait $(<$($type_param),*>)?` all over the - // place. - macro_rules! dyn_trait { - () => { &dyn $trait $(<$($type_param),*>)? }; - } - - // Now we can generate a database struct that contains the lookup tables. - $struct_vis struct $database_struct $(<$($type_param),*>)? { - __unwinding_cycles: ::core::cell::Cell, + // The database struct, which contains the lookup tables. + $vis struct $database_struct $(<$($type_param),*>)? { + pub __unwinding_cycles: ::core::cell::Cell, + pub __db_index: u8, $( $input_function: $input_type, )* $( $break_cycles_function: $crate::internal::FnAndTable< - fn(dyn_trait!(), $($break_cycles_arg_type),*) -> $break_cycles_return_type, + fn(&Self, $($break_cycles_arg_type),*) -> $break_cycles_return_type, ($($break_cycles_arg_type,)*), $break_cycles_return_type >, )* $( $function: $crate::internal::FnAndTable< - fn(dyn_trait!(), $($arg_type),*) -> $return_type, + fn(&Self, $($arg_type),*) -> $return_type, ($($arg_type,)*), $return_type >, )* } - // ...and an implementation of the trait. - impl $(<$($type_param),*>)? $trait $(<$($type_param),*>)? for $database_struct $(<$($type_param),*>)? { + // ...and the methods. + impl $(<$($type_param),*>)? $database_struct $(<$($type_param),*>)? { $( - fn $input_function(&self) -> $input_type { + $(#[doc = $input_doc])* + $vis fn $input_function(&self) -> $input_type { // Have to be very careful to clone whatever the top level value is. // In particular, if it's a reference `&T`, clone the _reference_ to get another `&T`, // not the referent to get a `T`, like if we just cloned `self.$input_function`. @@ -275,7 +237,8 @@ macro_rules! query_group { } )* $( - fn $break_cycles_function( + $(#[doc = $break_cycles_doc])* + $vis fn $break_cycles_function( &self, $( $break_cycles_arg : $break_cycles_arg_type @@ -286,15 +249,15 @@ macro_rules! query_group { $break_cycles_arg, )*), |($($break_cycles_arg,)*)| { - // Force the use of &dyn $trait, so that we don't rule out separate compilation later. - (self.$break_cycles_function.fn_ptr)(self as &dyn $trait, $($break_cycles_arg),*) + (self.$break_cycles_function.fn_ptr)(self, $($break_cycles_arg),*) }, &self.__unwinding_cycles, ).unwrap_or($break_cycles_default_value) } )* $( - fn $function( + $(#[doc = $function_doc])* + $vis fn $function( &self, $( $arg : $arg_type @@ -305,8 +268,7 @@ macro_rules! query_group { $arg, )*), |($($arg,)*)| { - // Force the use of &dyn $trait, so that we don't rule out separate compilation later. - (self.$function.fn_ptr)(self as &dyn $trait, $($arg),*) + (self.$function.fn_ptr)(self, $($arg),*) }, &self.__unwinding_cycles, ).unwrap_or_else( @@ -315,7 +277,8 @@ macro_rules! query_group { } )* $( - fn $provided_function( + $(#[doc = $provided_doc])* + $vis fn $provided_function( &$provided_self, $( $provided_arg : $provided_arg_type @@ -325,15 +288,16 @@ macro_rules! query_group { } )* } - // and the new() function for initialization. + // And the new() functions for initialization. impl $(<$($type_param),*>)? $database_struct $(<$($type_param),*>)? { - $struct_vis fn new( + $vis fn new( $($input_function: $input_type,)* - $($break_cycles_function: fn(dyn_trait!(), $($break_cycles_arg_type),*) -> $break_cycles_return_type,)* - $($function: fn(dyn_trait!(), $($arg_type),*) -> $return_type,)* + $($break_cycles_function: fn(&Self, $($break_cycles_arg_type),*) -> $break_cycles_return_type,)* + $($function: fn(&Self, $($arg_type),*) -> $return_type,)* ) -> Self { Self { __unwinding_cycles: ::core::cell::Cell::new(0), + __db_index: $crate::internal::db_index(), $( $input_function, )* @@ -355,6 +319,45 @@ macro_rules! query_group { } } +#[macro_export] +macro_rules! memoized { + ( + $vis:vis fn $memoized_ident:ident( + db: $db_type:ty + $(, $arg:ident : $arg_type:ty)* + $(,)? + ) -> $return_type:ty = $original_fn:ident + ) => { + mod $memoized_ident { + std::thread_local! { + /// A table off to the side -- one per db instance. + /// + /// This acts the same as if the db had a table field (or one per thread, anyway), + /// but doesn't require centrally registering with the db. + pub static TABLES: ::std::cell::RefCell<::std::vec::Vec<$crate::internal::MemoizationTable<($($arg_type,)*), $return_type>>> = ::std::cell::RefCell::new(vec![Default::default()]); + } + } + $vis fn $memoized_ident(db: $db_type, $($arg: $arg_type),*) -> $return_type { + $memoized_ident::TABLES.with(|tables| { + let db_index = db.__db_index as usize; + if tables.borrow().len() <= db_index { + tables.borrow_mut().resize_with(db_index + 1, Default::default); + } + let table = &tables.borrow()[db_index]; + table.internal_memoized_call( + ($($arg,)*), + |($($arg,)*)| { + $original_fn(db, $($arg),*) + }, + &db.__unwinding_cycles, + ).unwrap_or_else( + || panic!("Cycle detected: '{}' depends on its own return value", stringify!($memoized_ident)), + ) + }) + } + } +} + #[doc(hidden)] pub mod internal { use std::cell::{Cell, RefCell}; @@ -444,6 +447,11 @@ pub mod internal { Some(return_value) } } + + pub fn db_index() -> u8 { + static DB_INDEX: std::sync::atomic::AtomicU8 = std::sync::atomic::AtomicU8::new(0); + DB_INDEX.fetch_add(1, std::sync::atomic::Ordering::AcqRel) + } } #[cfg(test)] @@ -455,7 +463,7 @@ pub mod tests { #[gtest] fn test_basic_memoization() { crate::query_group! { - pub trait Add10 { + pub struct Add10 { #[input] /// Tracker for how many times this function is called so we can check /// that memoization is indeed happening. This is just for testing; @@ -464,13 +472,12 @@ pub mod tests { fn call_counter(&self) -> Rc>; fn add10(&self, arg: i32) -> i32; } - pub struct Database; } - fn add10(db: &dyn Add10, arg: i32) -> i32 { + fn add10(db: &Add10, arg: i32) -> i32 { db.call_counter().set(db.call_counter().get() + 1); arg + 10 } - let db = Database::new(Rc::new(Cell::new(0)), add10); + let db = Add10::new(Rc::new(Cell::new(0)), add10); assert_eq!(db.add10(100), 110); assert_eq!(db.call_counter().get(), 1); @@ -489,25 +496,24 @@ pub mod tests { #[gtest] fn test_nonstatic_memoization() { crate::query_group! { - pub trait Add10<'a> { + pub struct Add10<'a> { #[input] fn call_counter(&self) -> &'a Cell; fn add10(&self, arg: &'a i32) -> i32; // non-input function with 'a in return type fn identity(&self, arg: &'a i32) -> &'a i32; } - pub struct Database; } - fn add10<'a>(db: &dyn Add10<'a>, arg: &'a i32) -> i32 { + fn add10<'a>(db: &Add10<'a>, arg: &'a i32) -> i32 { db.call_counter().set(db.call_counter().get() + 1); *arg + 10 } - fn identity<'a>(db: &dyn Add10<'a>, arg: &'a i32) -> &'a i32 { + fn identity<'a>(db: &Add10<'a>, arg: &'a i32) -> &'a i32 { db.call_counter().set(db.call_counter().get() + 1); arg } let count = Cell::new(0); - let db = Database::new(&count, add10, identity); + let db = Add10::new(&count, add10, identity); assert_eq!(db.add10(&100), 110); assert_eq!(count.get(), 1); @@ -529,54 +535,51 @@ pub mod tests { #[should_panic(expected = "Cycle detected: 'add10' depends on its own return value")] fn test_cycle() { crate::query_group! { - pub trait Add10 { + pub struct Add10 { fn add10(&self, arg: i32) -> i32; } - pub struct Database; } - fn add10(db: &dyn Add10, arg: i32) -> i32 { + fn add10(db: &Add10, arg: i32) -> i32 { db.add10(arg) // infinite recursion! } - let db = Database::new(add10); + let db = Add10::new(add10); db.add10(1); } #[gtest] fn test_break_cycles_with_option() { crate::query_group! { - pub trait Add10 { + pub struct Add10 { #[break_cycles_with = None] fn add10(&self, arg: i32) -> Option; } - pub struct Database; } - fn add10(db: &dyn Add10, arg: i32) -> Option { + fn add10(db: &Add10, arg: i32) -> Option { db.add10(arg) } - let db = Database::new(add10); + let db = Add10::new(add10); assert_eq!(db.add10(1), None); } #[gtest] fn test_break_cycles_with_sentinel() { crate::query_group! { - pub trait Add10 { + pub struct Add10 { #[break_cycles_with = -1] fn add10(&self, arg: i32) -> i32; } - pub struct Database; } - fn add10(db: &dyn Add10, arg: i32) -> i32 { + fn add10(db: &Add10, arg: i32) -> i32 { db.add10(arg) } - let db = Database::new(add10); + let db = Add10::new(add10); assert_eq!(db.add10(1), -1); } #[gtest] fn test_calls_in_cycle_are_not_memoized() { crate::query_group! { - pub trait Table { + pub struct Table { #[input] fn logging(&self) -> Rc>>; @@ -588,7 +591,6 @@ pub mod tests { fn record(&self, name: &'static str) -> Record; } - pub struct Database; } #[derive(Clone)] @@ -599,7 +601,7 @@ pub mod tests { } // Returns whether or not a record is unsafe, checking recursively. - fn is_unsafe(db: &dyn Table, name: &'static str) -> bool { + fn is_unsafe(db: &Table, name: &'static str) -> bool { let record = db.record(name); let outcome = record.is_unsafe || record.fields.iter().any(|&field| db.is_unsafe(field)); @@ -608,7 +610,7 @@ pub mod tests { } // Helper function so we can refer to records by name instead of by index. - fn record(db: &dyn Table, name: &'static str) -> Record { + fn record(db: &Table, name: &'static str) -> Record { db.records() .iter() .find(|record| record.name == name) @@ -618,7 +620,7 @@ pub mod tests { let logging = Rc::default(); - let db = Database::new( + let db = Table::new( Rc::clone(&logging), &[ Record { name: "A", is_unsafe: false, fields: &["B", "Unsafe"] }, @@ -651,14 +653,13 @@ pub mod tests { #[gtest] fn test_finite_recursion() { crate::query_group! { - pub trait Add10 { + pub struct Add10 { #[input] fn call_counter(&self) -> Rc>; fn add10(&self, arg: i32) -> i32; } - pub struct Database; } - fn add10(db: &dyn Add10, arg: i32) -> i32 { + fn add10(db: &Add10, arg: i32) -> i32 { db.call_counter().set(db.call_counter().get() + 1); if (arg % 10) != 0 { db.add10(arg - 1) + 1 // Some recursion, but not infinite! @@ -666,7 +667,7 @@ pub mod tests { arg + 10 } } - let db = Database::new(Rc::new(Cell::new(0)), add10); + let db = Add10::new(Rc::new(Cell::new(0)), add10); assert_eq!(db.add10(100), 110); assert_eq!(db.call_counter().get(), 1); @@ -690,18 +691,17 @@ pub mod tests { #[gtest] fn test_argless() { crate::query_group! { - pub trait Argless { + pub struct Argless { #[input] fn call_counter(&self) -> Rc>; fn argless_function(&self) -> Rc; } - pub struct Database; } - fn argless_function(db: &dyn Argless) -> Rc { + fn argless_function(db: &Argless) -> Rc { db.call_counter().set(db.call_counter().get() + 1); Rc::new(0) } - let db = Database::new(Rc::new(Cell::new(0)), argless_function); + let db = Argless::new(Rc::new(Cell::new(0)), argless_function); assert_eq!(db.call_counter().get(), 0); let argless_return = db.argless_function(); @@ -714,16 +714,44 @@ pub mod tests { #[gtest] fn test_provided_fn() { crate::query_group! { - pub trait Db { + pub struct Db { #[input] fn input_fn(&self) -> i32; #[provided] fn provided_fn(&self, x: i32) -> i32 { self.input_fn() + x } } - pub struct Database; } - let db = Database::new(42); + let db = Db::new(42); let result = db.provided_fn(10); expect_eq!(result, 52); } + + #[gtest] + fn test_separate_memoization() { + crate::query_group! { + pub struct Add10 { + #[input] + /// Tracker for how many times this function is called so we can check + /// that memoization is indeed happening. This is just for testing; + /// memoized functions in non-test code shouldn't have side effects, + /// and inputs in non-test code shouldn't have internal mutability. + fn call_counter(&self) -> Rc>; + } + } + fn add10_impl(db: &Add10, arg: i32) -> i32 { + db.call_counter().set(db.call_counter().get() + 1); + arg + 10 + } + crate::memoized!(pub fn add10(db: &Add10, arg: i32) -> i32 = add10_impl); + let db = Add10::new(Rc::new(Cell::new(0))); + + assert_eq!(add10(&db, 100), 110); + assert_eq!(db.call_counter().get(), 1); + + assert_eq!(add10(&db, 100), 110); + assert_eq!(db.call_counter().get(), 1); + + assert_eq!(add10(&db, 200), 210); + assert_eq!(db.call_counter().get(), 2); + } } diff --git a/rs_bindings_from_cc/generate_bindings/database/code_snippet.rs b/rs_bindings_from_cc/generate_bindings/database/code_snippet.rs index e21842bc2..5115258b2 100644 --- a/rs_bindings_from_cc/generate_bindings/database/code_snippet.rs +++ b/rs_bindings_from_cc/generate_bindings/database/code_snippet.rs @@ -140,7 +140,7 @@ impl Display for RequiredCrubitFeature { /// If the item does have a defining target, and it doesn't enable the specified /// features, then bindings are suppressed for this item. pub fn required_crubit_features( - db: &dyn BindingsGenerator, + db: &BindingsGenerator, item: &Item, ) -> Result> { let mut missing_features = vec![]; diff --git a/rs_bindings_from_cc/generate_bindings/database/db.rs b/rs_bindings_from_cc/generate_bindings/database/db.rs index 3ba44fb70..face53d94 100644 --- a/rs_bindings_from_cc/generate_bindings/database/db.rs +++ b/rs_bindings_from_cc/generate_bindings/database/db.rs @@ -21,13 +21,13 @@ pub fn test_again() {} #[derive(Clone)] pub struct CodegenFunctions { - pub generate_enum: fn(&dyn BindingsGenerator, Rc) -> Result, - pub generate_item: fn(&dyn BindingsGenerator, ir::Item) -> Result, - pub generate_record: fn(&dyn BindingsGenerator, Rc) -> Result, + pub generate_enum: fn(&BindingsGenerator, Rc) -> Result, + pub generate_item: fn(&BindingsGenerator, ir::Item) -> Result, + pub generate_record: fn(&BindingsGenerator, Rc) -> Result, } memoized::query_group! { - pub trait BindingsGenerator<'db> { + pub struct BindingsGenerator<'db> { #[input] fn ir(&self) -> &'db IR; @@ -62,7 +62,7 @@ memoized::query_group! { /// reference lifetimes with the elided lifetime (`'_`). /// /// An `Ok()` return value does not necessarily imply that the resulting `RsTypeKind` is - /// usable in APIs: callers must also check the result of `db::type_visibility()` for + /// usable in APIs: callers must also check the result of `type_visibility()` for /// the type, to see if it is usable within a specific crate. Eventually, all types will /// have a successful non-error return value, even if the type is not generally usable. /// Instead, restrictions will always be done via `type_visibility`. @@ -132,7 +132,7 @@ memoized::query_group! { /// Implementation: rs_bindings_from_cc/generate_bindings/lib.rs?q=function:crubit_abi_type fn crubit_abi_type(&self, rs_type_kind: RsTypeKind) -> Result; - // You should probably use db::type_visibility instead of this function. + // You should probably use `type_visibility()` instead of this function. fn type_target_restriction(&self, rs_type_kind: RsTypeKind) -> Result>; /// Resolves type names to a map from name to ResolvedTypeName. @@ -190,34 +190,25 @@ memoized::query_group! { Some(id) => *id != Some(item_id), } } - } - pub struct Database; -} -/// Returns the `Visibility` of the `rs_type_kind` in the given `library`. -// TODO(jeanpierreda): it would be nice if this was a `#[provided]` function, -// but because it calls `display`, it would need to convert to a -// `dyn BindingsGenerator`, which is not reasonably possible. -// -// See e.g. https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=10f937bb0f13d2ea05f20f676c37439a -pub fn type_visibility( - db: &dyn BindingsGenerator, - library: &BazelLabel, - rs_type_kind: RsTypeKind, -) -> Result { - match db.type_target_restriction(rs_type_kind.clone())? { - Some(label) if &label != library => { - let rs_type_kind = rs_type_kind.display(db); - Err(anyhow!("{rs_type_kind} is `pub(crate)` in {label}")) - } - Some(_) => Ok(Visibility::PubCrate), - None => { - for subtype in rs_type_kind.dfs_iter() { - if let RsTypeKind::Error { visibility_override, .. } = subtype { - return Ok(visibility_override.unwrap_or(Visibility::PubCrate)); + #[provided] + /// Returns the `Visibility` of the `rs_type_kind` in the given `library`. + fn type_visibility(&self, library: &BazelLabel, rs_type_kind: RsTypeKind) -> Result { + match self.type_target_restriction(rs_type_kind.clone())? { + Some(label) if &label != library => { + let rs_type_kind = rs_type_kind.display(self); + Err(anyhow!("{rs_type_kind} is `pub(crate)` in {label}")) + } + Some(_) => Ok(Visibility::PubCrate), + None => { + for subtype in rs_type_kind.dfs_iter() { + if let RsTypeKind::Error { visibility_override, .. } = subtype { + return Ok(visibility_override.unwrap_or(Visibility::PubCrate)); + } + } + Ok(Visibility::Public) } } - Ok(Visibility::Public) } } } diff --git a/rs_bindings_from_cc/generate_bindings/database/lib.rs b/rs_bindings_from_cc/generate_bindings/database/lib.rs index e098f1b51..182cc1a62 100644 --- a/rs_bindings_from_cc/generate_bindings/database/lib.rs +++ b/rs_bindings_from_cc/generate_bindings/database/lib.rs @@ -8,4 +8,4 @@ pub mod code_snippet; pub mod db; pub mod function_types; pub mod rs_snippet; -pub use db::{BindingsGenerator, Database}; +pub use db::BindingsGenerator; diff --git a/rs_bindings_from_cc/generate_bindings/database/rs_snippet.rs b/rs_bindings_from_cc/generate_bindings/database/rs_snippet.rs index 32addddcb..3221b2386 100644 --- a/rs_bindings_from_cc/generate_bindings/database/rs_snippet.rs +++ b/rs_bindings_from_cc/generate_bindings/database/rs_snippet.rs @@ -23,6 +23,8 @@ use token_stream_printer::write_unformatted_tokens; pub use ir::BackingType; +use std::ops::Deref; + const SLICE_REF_NAME_RS: &str = "&[]"; /// A struct with information associated with the formatted Rust code snippet. @@ -201,8 +203,8 @@ pub fn format_generic_params<'a, T: ToTokens>( } } -pub fn format_generic_params_replacing_by_self<'a>( - db: &dyn BindingsGenerator, +pub fn format_generic_params_replacing_by_self<'db, 'a>( + db: impl Deref> + Copy, types: impl IntoIterator, trait_record: Option<&Record>, ) -> TokenStream { @@ -282,7 +284,7 @@ impl UniformReprTemplateType { /// Returns none if the template specialization is not for a known type corresponding with /// one of `UniformReprTemplateType`s variants. fn new( - db: &dyn BindingsGenerator, + db: &BindingsGenerator, template_specialization_kind: Option<&TemplateSpecializationKind>, is_return_type: bool, ) -> Result>> { @@ -356,7 +358,7 @@ impl UniformReprTemplateType { } } - fn to_token_stream(&self, db: &dyn BindingsGenerator) -> TokenStream { + fn to_token_stream(&self, db: &BindingsGenerator) -> TokenStream { match self { Self::StdVector { element_type } => { let element_type_tokens = element_type.to_token_stream(db); @@ -468,7 +470,7 @@ pub enum RsTypeKind { fn new_c9_co_record( have_reference_param: bool, record: Rc, - db: &dyn BindingsGenerator, + db: &BindingsGenerator, ) -> Result> { let Some(TemplateSpecialization { kind: TemplateSpecializationKind::C9Co { element_type }, @@ -531,7 +533,7 @@ pub struct Callable { impl Callable { /// Returns a `TokenStream` in the shape of `-> Output`, or None if the return type is void. - pub fn rust_return_type_fragment(&self, db: &dyn BindingsGenerator) -> Option { + pub fn rust_return_type_fragment(&self, db: &BindingsGenerator) -> Option { if self.return_type.is_void() { None } else { @@ -541,7 +543,7 @@ impl Callable { } /// Returns a `TokenStream` in the shape of `dyn Trait(Inputs) -> Output`. - pub fn dyn_fn_spelling(&self, db: &dyn BindingsGenerator) -> TokenStream { + pub fn dyn_fn_spelling(&self, db: &BindingsGenerator) -> TokenStream { let rust_return_type_fragment = self.rust_return_type_fragment(db); let param_type_tokens = self.param_types.iter().map(|param_ty| param_ty.to_token_stream(db)); @@ -589,7 +591,7 @@ impl BridgeRsTypeKind { /// If the record is a bridge type, returns the corresponding BridgeRsTypeKind. /// Otherwise, returns None. This may also return an error if db.rs_type_kind fails, or if the /// record has template parameters that cannot be translated. - pub fn new(record: &Record, db: &dyn BindingsGenerator) -> Result> { + pub fn new(record: &Record, db: &BindingsGenerator) -> Result> { let Some(bridge_type) = &record.bridge_type else { return Ok(None); }; @@ -677,7 +679,7 @@ impl RsTypeKind { /// or if the `RsTypeKind` cannot be created (e.g. a type alias which points to a type that /// cannot receive an `RsTypeKind`). pub fn from_item_raw( - db: &dyn BindingsGenerator, + db: &BindingsGenerator, item: Item, have_reference_param: bool, is_return_type: bool, @@ -698,7 +700,7 @@ impl RsTypeKind { } } - fn new_type_alias(db: &dyn BindingsGenerator, type_alias: Rc) -> Result { + fn new_type_alias(db: &BindingsGenerator, type_alias: Rc) -> Result { let ir = db.ir(); let underlying_type = db.rs_type_kind(type_alias.underlying_type.clone())?; // Note: we don't need to call `.unalias()` for these checks, because we already checked @@ -733,7 +735,7 @@ impl RsTypeKind { } fn new_record( - db: &dyn BindingsGenerator, + db: &BindingsGenerator, record: Rc, have_reference_param: bool, is_return_type: bool, @@ -765,7 +767,7 @@ impl RsTypeKind { } fn new_incomplete_record( - db: &dyn BindingsGenerator, + db: &BindingsGenerator, incomplete_record: Rc, ) -> Result { let ir = db.ir(); @@ -777,7 +779,7 @@ impl RsTypeKind { Ok(RsTypeKind::IncompleteRecord { incomplete_record, crate_path }) } - fn new_enum(db: &dyn BindingsGenerator, enum_: Rc) -> Result { + fn new_enum(db: &BindingsGenerator, enum_: Rc) -> Result { let ir = db.ir(); let crate_path = Rc::new(CratePath::new( ir, @@ -788,7 +790,7 @@ impl RsTypeKind { } fn new_existing_rust_type( - db: &dyn BindingsGenerator, + db: &BindingsGenerator, existing_rust_type: Rc, ) -> Result { if existing_rust_type.rs_name.as_ref() == SLICE_REF_NAME_RS { @@ -891,9 +893,9 @@ impl RsTypeKind { /// for both the template definition and its instantiation, and so both /// would need to be passed in to rs_type_kind() in order to be able to /// merge these two functions. - pub fn required_crubit_features( + pub fn required_crubit_features<'a>( &self, - db: &dyn BindingsGenerator, + db: impl Deref>, enabled_features: flagset::FlagSet, ) -> (flagset::FlagSet, String) { let mut missing_features = >::default(); @@ -943,7 +945,7 @@ impl RsTypeKind { RsTypeKind::IncompleteRecord { .. } => require_feature( CrubitFeature::Wrapper, Some(&|| { - format!("{} is not a complete type)", rs_type_kind.display(db)).into() + format!("{} is not a complete type)", rs_type_kind.display(&db)).into() }), ), // Here, we can very carefully be non-recursive into the _structure_ of the type. @@ -967,7 +969,7 @@ impl RsTypeKind { require_feature( CrubitFeature::Wrapper, Some(&|| { - format!("{} is a template instantiation", rs_type_kind.display(db),) + format!("{} is a template instantiation", rs_type_kind.display(&db),) .into() }), ) @@ -988,7 +990,7 @@ impl RsTypeKind { Some(&|| { format!( "{} is a bridged template instantiation", - rs_type_kind.display(db), + rs_type_kind.display(&db), ) .into() }), @@ -1129,9 +1131,9 @@ impl RsTypeKind { } } - pub fn format_as_return_type_fragment( + pub fn format_as_return_type_fragment<'a>( &self, - db: &dyn BindingsGenerator, + db: impl Deref> + Copy, self_record: Option<&Record>, ) -> Option { match self.unalias() { @@ -1330,7 +1332,7 @@ impl RsTypeKind { /// `RsTypeKind::Pointer` with kind /// `RustPtrKind::CcPtr(PointerTypeKind::Owned)` will emit the corresponding /// owning Rust type rather than a raw pointer. - pub fn to_token_stream_with_owned_ptr_type(&self, db: &dyn BindingsGenerator) -> TokenStream { + pub fn to_token_stream_with_owned_ptr_type(&self, db: &BindingsGenerator) -> TokenStream { // If it's not an owned pointer, just use the default implementation. let Some(pointee) = self.as_owned_ptr() else { return self.to_token_stream(db); @@ -1352,9 +1354,9 @@ impl RsTypeKind { /// Similar to to_token_stream, but replacing RsTypeKind:Record with Self /// when the underlying Record matches the given one. - pub fn to_token_stream_replacing_by_self( + pub fn to_token_stream_replacing_by_self<'a>( &self, - db: &dyn BindingsGenerator, + db: impl Deref> + Copy, self_record: Option<&Record>, ) -> TokenStream { match self { @@ -1425,7 +1427,7 @@ impl RsTypeKind { /// Returns a `Display`able type for this `RsTypeKind`. pub fn display<'a, 'db>( &'a self, - db: &'a dyn BindingsGenerator<'db>, + db: &'a BindingsGenerator<'db>, ) -> impl std::fmt::Display + use<'a, 'db> { DisplayRsTypeKind { rs_type_kind: self, db } } @@ -1446,7 +1448,7 @@ impl RsTypeKind { /// requires a [`BindingsGenerator`] to be able to format the type. pub struct DisplayRsTypeKind<'a, 'db> { rs_type_kind: &'a RsTypeKind, - db: &'a dyn BindingsGenerator<'db>, + db: &'a BindingsGenerator<'db>, } impl std::fmt::Display for DisplayRsTypeKind<'_, '_> { @@ -1465,7 +1467,10 @@ impl std::fmt::Display for DisplayRsTypeKind<'_, '_> { } impl RsTypeKind { - pub fn to_token_stream(&self, db: &dyn BindingsGenerator) -> TokenStream { + pub fn to_token_stream<'a>( + &self, + db: impl Deref> + Copy, + ) -> TokenStream { match self { // errors become opaque blobs RsTypeKind::Error { symbol, .. } => { @@ -1531,7 +1536,7 @@ impl RsTypeKind { owned_ptr_type: _, } => { if let Some(generic_monomorphization) = uniform_repr_template_type { - return generic_monomorphization.to_token_stream(db); + return generic_monomorphization.to_token_stream(&db); } let ident = make_rs_ident(record.rs_name.identifier.as_ref()); quote! { #crate_path #ident } @@ -1697,7 +1702,7 @@ impl RsTypeKind { } } BridgeRsTypeKind::DynCallable(dyn_callable) => { - let dyn_callable_spelling = dyn_callable.dyn_fn_spelling(db); + let dyn_callable_spelling = dyn_callable.dyn_fn_spelling(&db); quote! { ::alloc::boxed::Box<#dyn_callable_spelling> } } } @@ -1731,8 +1736,8 @@ impl RsTypeKind { /// /// This has _very_ limited support for other type expressions, like `&T`, /// and special-cases well known builtin types like `char`. -fn fully_qualify_type( - db: &dyn BindingsGenerator, +fn fully_qualify_type<'a>( + db: impl Deref> + Copy, item: ir::Item, type_expression: &str, ) -> TokenStream { @@ -1917,8 +1922,14 @@ mod tests { assert_eq!(vec!["fn", "::A", "::B", "::C"], dfs_names); } + #[derive(Copy, Clone)] struct EmptyDatabase; - impl<'db> BindingsGenerator<'db> for EmptyDatabase {} + impl Deref for EmptyDatabase { + type Target = BindingsGenerator<'static>; + fn deref(&self) -> &Self::Target { + panic!("Tried to use the empty bindings generator query group.") + } + } #[gtest] fn test_lifetime_elision_for_references() { @@ -1928,7 +1939,7 @@ mod tests { mutability: Mutability::Const, lifetime: Lifetime::new("_"), }; - assert_rs_matches!(reference.to_token_stream(&EmptyDatabase), quote! {&::T}); + assert_rs_matches!(reference.to_token_stream(EmptyDatabase), quote! {&::T}); } #[gtest] @@ -1940,7 +1951,7 @@ mod tests { lifetime: Lifetime::new("_"), }; assert_rs_matches!( - reference.to_token_stream(&EmptyDatabase), + reference.to_token_stream(EmptyDatabase), quote! {RvalueReference<'_, ::T>} ); } @@ -2001,7 +2012,7 @@ mod tests { }, ] { let (all_required_features, reason) = func_ptr.required_crubit_features( - &EmptyDatabase, + EmptyDatabase, >::default(), ); assert_eq!( diff --git a/rs_bindings_from_cc/generate_bindings/generate_bindings_test.rs b/rs_bindings_from_cc/generate_bindings/generate_bindings_test.rs index 0bed032bb..fbcc96d15 100644 --- a/rs_bindings_from_cc/generate_bindings/generate_bindings_test.rs +++ b/rs_bindings_from_cc/generate_bindings/generate_bindings_test.rs @@ -5,7 +5,6 @@ use arc_anyhow::{anyhow, Result}; use database::code_snippet::BindingsTokens; use database::rs_snippet::{Mutability, RsTypeKind}; -use database::BindingsGenerator; use googletest::{expect_eq, gtest}; use ir_testing::{retrieve_func, with_lifetime_macros}; use multiplatform_ir_testing::{ir_from_cc, ir_from_cc_dependency}; diff --git a/rs_bindings_from_cc/generate_bindings/generate_comment.rs b/rs_bindings_from_cc/generate_bindings/generate_comment.rs index 5792efc5c..6bba18fb5 100644 --- a/rs_bindings_from_cc/generate_bindings/generate_comment.rs +++ b/rs_bindings_from_cc/generate_bindings/generate_comment.rs @@ -84,7 +84,7 @@ pub fn generate_doc_comment( } /// Generates Rust source code for a given `UnsupportedItem`. -pub fn generate_unsupported(db: &dyn BindingsGenerator, item: Rc) -> ApiSnippets { +pub fn generate_unsupported(db: &BindingsGenerator, item: Rc) -> ApiSnippets { Item::UnsupportedItem(item.clone()).assert_in_error_scope(db.ir(), db.errors()); for error in item.errors() { db.errors().report(error); diff --git a/rs_bindings_from_cc/generate_bindings/generate_comment_test.rs b/rs_bindings_from_cc/generate_bindings/generate_comment_test.rs index 887a20085..d79864917 100644 --- a/rs_bindings_from_cc/generate_bindings/generate_comment_test.rs +++ b/rs_bindings_from_cc/generate_bindings/generate_comment_test.rs @@ -6,7 +6,7 @@ use arc_anyhow::Result; use database::code_snippet; -use database::{BindingsGenerator, Database}; +use database::BindingsGenerator; use error_report::{ErrorReport, FatalErrors}; use ffi_types::Environment; use generate_bindings::new_database; @@ -120,7 +120,7 @@ impl TestDbFactory { fatal_errors: FatalErrors::new(), } } - fn make_db(&self, environment: Environment) -> Database { + fn make_db(&self, environment: Environment) -> BindingsGenerator { new_database(&self.ir, &self.errors, &self.fatal_errors, environment) } } diff --git a/rs_bindings_from_cc/generate_bindings/generate_dyn_callable.rs b/rs_bindings_from_cc/generate_bindings/generate_dyn_callable.rs index b281c2239..72350a096 100644 --- a/rs_bindings_from_cc/generate_bindings/generate_dyn_callable.rs +++ b/rs_bindings_from_cc/generate_bindings/generate_dyn_callable.rs @@ -11,7 +11,7 @@ use quote::{format_ident, quote}; /// Generates the `CrubitAbiType` for callables. pub fn dyn_callable_crubit_abi_type( - db: &dyn BindingsGenerator, + db: &BindingsGenerator, callable: &Callable, ) -> Result { let dyn_fn_spelling = callable.dyn_fn_spelling(db); @@ -125,7 +125,7 @@ pub fn dyn_callable_crubit_abi_type( /// value. In the case that all inputs and outputs are C-compatible by value, this lambda is simply /// a pointer to the thunk. fn generate_invoker_function_pointer( - db: &dyn BindingsGenerator, + db: &BindingsGenerator, callable: &Callable, cpp_param_types: &[TokenStream], cpp_return_type: &TokenStream, diff --git a/rs_bindings_from_cc/generate_bindings/generate_enum.rs b/rs_bindings_from_cc/generate_bindings/generate_enum.rs index 7e6000b84..59521860a 100644 --- a/rs_bindings_from_cc/generate_bindings/generate_enum.rs +++ b/rs_bindings_from_cc/generate_bindings/generate_enum.rs @@ -16,7 +16,7 @@ use std::collections::HashMap; use std::rc::Rc; /// Implementation of `BindingsGenerator::generate_enum`. -pub fn generate_enum(db: &dyn BindingsGenerator, enum_: Rc) -> Result { +pub fn generate_enum(db: &BindingsGenerator, enum_: Rc) -> Result { let ident = expect_format_cc_ident(&enum_.cc_name.identifier); let namespace_qualifier = db.ir().namespace_qualifier(&enum_).format_for_cc()?; let fully_qualified_cc_name = quote! { #namespace_qualifier #ident }.to_string(); diff --git a/rs_bindings_from_cc/generate_bindings/generate_function.rs b/rs_bindings_from_cc/generate_bindings/generate_function.rs index bb2957948..de8c400f3 100644 --- a/rs_bindings_from_cc/generate_bindings/generate_function.rs +++ b/rs_bindings_from_cc/generate_bindings/generate_function.rs @@ -36,7 +36,7 @@ use std::sync::LazyLock; /// This is used to remove the record whose trait implementation is being /// generated. fn trait_name_to_token_stream_removing_trait_record( - db: &dyn BindingsGenerator, + db: &BindingsGenerator, trait_name: &TraitName, trait_record: Option<&Record>, ) -> TokenStream { @@ -83,7 +83,7 @@ fn trait_name_to_token_stream_removing_trait_record( } } -fn trait_name_to_token_stream(db: &dyn BindingsGenerator, trait_name: &TraitName) -> TokenStream { +fn trait_name_to_token_stream(db: &BindingsGenerator, trait_name: &TraitName) -> TokenStream { trait_name_to_token_stream_removing_trait_record(db, trait_name, None) } @@ -191,7 +191,7 @@ static OPERATOR_METADATA: LazyLock = LazyLock::new(|| { /// /// This is necessary because ADL is needed in order to find friend functions. fn is_friend_of_record_not_visible_by_adl( - db: &dyn BindingsGenerator, + db: &BindingsGenerator, func: &Func, param_types: &[RsTypeKind], ) -> bool { @@ -208,7 +208,7 @@ fn is_friend_of_record_not_visible_by_adl( /// /// Returns the `RsTypeKind` and `Record` of the underlying record type. fn type_by_value_or_under_const_ref<'a>( - db: &dyn BindingsGenerator, + db: &BindingsGenerator, kind: &'a mut RsTypeKind, value_desc: &str, errors: &Errors, @@ -239,7 +239,7 @@ fn type_by_value_or_under_const_ref<'a>( } fn api_func_shape_for_operator_ne( - db: &dyn BindingsGenerator, + db: &BindingsGenerator, func: &Func, param_types: &mut [RsTypeKind], errors: &Errors, @@ -272,7 +272,7 @@ fn api_func_shape_for_operator_ne( } fn api_func_shape_for_operator_eq( - db: &dyn BindingsGenerator, + db: &BindingsGenerator, func: &Func, param_types: &mut [RsTypeKind], errors: &Errors, @@ -297,7 +297,7 @@ fn api_func_shape_for_operator_eq( } fn api_func_shape_for_operator_lt( - db: &dyn BindingsGenerator, + db: &BindingsGenerator, func: &Func, param_types: &mut [RsTypeKind], errors: &Errors, @@ -399,7 +399,7 @@ fn api_func_shape_for_operator_assign( } fn api_func_shape_for_operator_unary_plus( - db: &dyn BindingsGenerator, + db: &BindingsGenerator, param_type: &RsTypeKind, errors: &Errors, ) -> ErrorsOr<(Ident, ImplKind)> { @@ -416,7 +416,7 @@ fn api_func_shape_for_operator_unary_plus( } fn extract_first_operator_parameter( - db: &dyn BindingsGenerator, + db: &BindingsGenerator, param_types: &RsTypeKind, errors: &Errors, ) -> ErrorsOr<(Rc, ImplFor)> { @@ -448,7 +448,7 @@ fn extract_first_operator_parameter( } fn expect_possibly_incomplete_record<'a>( - db: &dyn BindingsGenerator, + db: &BindingsGenerator, type_kind: &'a RsTypeKind, value_desc: &str, errors: &Errors, @@ -469,7 +469,7 @@ fn expect_possibly_incomplete_record<'a>( } fn record_type_of_compound_assignment<'a>( - db: &dyn BindingsGenerator, + db: &BindingsGenerator, lhs_type: &'a mut RsTypeKind, errors: &Errors, ) -> ErrorsOr<&'a Rc> { @@ -520,12 +520,12 @@ fn record_type_of_compound_assignment<'a>( /// Reports a fatal error generating bindings for a function. /// Fatal errors should only be reported -fn report_fatal_func_error(db: &dyn BindingsGenerator, func: &Func, msg: &str) { +fn report_fatal_func_error(db: &BindingsGenerator, func: &Func, msg: &str) { db.fatal_errors().report(&format!("{}: {}", func.source_loc, msg)); } fn api_func_shape_for_operator( - db: &dyn BindingsGenerator, + db: &BindingsGenerator, func: &Func, maybe_record: Option<&Rc>, param_types: &mut [RsTypeKind], @@ -606,7 +606,7 @@ fn api_func_shape_for_operator( } fn api_func_shape_for_identifier( - db: &dyn BindingsGenerator, + db: &BindingsGenerator, func: &Func, maybe_record: Option<&Rc>, param_types: &mut [RsTypeKind], @@ -652,7 +652,7 @@ fn api_func_shape_for_identifier( } fn api_func_shape_for_destructor( - db: &dyn BindingsGenerator, + db: &BindingsGenerator, func: &Func, maybe_record: Option<&Rc>, param_types: &mut [RsTypeKind], @@ -712,7 +712,7 @@ fn api_func_shape_for_destructor( /// Issue any errors related to unsafe constructors being unsupported. fn issue_unsafe_constructor_errors( - db: &dyn BindingsGenerator, + db: &BindingsGenerator, func: &Func, record: &Record, param_types: &[RsTypeKind], @@ -755,7 +755,7 @@ fn issue_unsafe_constructor_errors( } fn api_func_shape_for_constructor( - db: &dyn BindingsGenerator, + db: &BindingsGenerator, func: &Func, maybe_record: Option<&Rc>, param_types: &mut [RsTypeKind], @@ -869,7 +869,7 @@ fn api_func_shape_for_constructor( /// destructor might be mapped to no `Drop` impl at all.) /// * `(func_name, impl_kind)`: The function name and ImplKind. fn api_func_shape( - db: &dyn BindingsGenerator, + db: &BindingsGenerator, func: &Func, param_types: &mut [RsTypeKind], errors: &Errors, @@ -910,7 +910,7 @@ fn api_func_shape( /// Returns the shape of the generated Rust API for a given function definition /// or `None` if no function will be generated. fn api_func_shape_if_some( - db: &dyn BindingsGenerator, + db: &BindingsGenerator, func: &Func, param_types: &mut [RsTypeKind], ) -> Option<(Ident, ImplKind)> { @@ -925,7 +925,7 @@ fn api_func_shape_if_some( /// Implementation of `BindingsGenerator::get_binding`. pub fn get_binding( - db: &dyn BindingsGenerator, + db: &BindingsGenerator, expected_function_name: UnqualifiedIdentifier, expected_param_types: Vec, ) -> Option<(Ident, ImplKind)> { @@ -946,7 +946,7 @@ pub fn get_binding( } /// Implementation of `BindingsGenerator::is_record_clonable`. -pub fn is_record_clonable(db: &dyn BindingsGenerator, record: Rc) -> bool { +pub fn is_record_clonable(db: &BindingsGenerator, record: Rc) -> bool { if !record.is_unpin() { return false; } @@ -1022,7 +1022,7 @@ struct ParamValueAdjustments { /// `param_types`-length list containing any necessary adjustments to the /// parameter values. fn adjust_param_types_for_trait_impl( - db: &dyn BindingsGenerator, + db: &BindingsGenerator, impl_kind: &ImplKind, param_types: &mut [RsTypeKind], errors: &Errors, @@ -1060,7 +1060,7 @@ fn adjust_param_types_for_trait_impl( #[allow(clippy::too_many_arguments)] fn generate_func_body( - db: &dyn BindingsGenerator, + db: &BindingsGenerator, impl_kind: &ImplKind, crate_root_path: TokenStream, return_type: &RsTypeKind, @@ -1326,7 +1326,7 @@ fn func_should_infer_lifetimes_of_references(func: &Func) -> bool { } fn rs_type_kinds_for_func( - db: &dyn BindingsGenerator, + db: &BindingsGenerator, func: &Func, ) -> Result<(Vec, RsTypeKind)> { @@ -1399,7 +1399,7 @@ fn rs_type_kinds_for_func( /// Implementation of `BindingsGenerator::generate_function`. pub fn generate_function( - db: &dyn BindingsGenerator, + db: &BindingsGenerator, func: Rc, derived_record: Option>, ) -> Result> { @@ -1869,7 +1869,7 @@ struct BindingsSignature { /// * serialize a `()` as the empty string. #[allow(clippy::too_many_arguments)] fn function_signature( - db: &dyn BindingsGenerator, + db: &BindingsGenerator, features: &mut FlagSet, func: &Func, impl_kind: &ImplKind, @@ -2148,7 +2148,7 @@ fn function_signature( } fn move_self_from_out_param_to_return_value( - db: &dyn BindingsGenerator, + db: &BindingsGenerator, func: &Func, return_type: &mut RsTypeKind, api_params: &mut Vec, @@ -2225,7 +2225,7 @@ fn format_tuple_except_singleton(iter: impl IntoIterator) -> } fn format_tuple_except_singleton_replacing_by_self( - db: &dyn BindingsGenerator, + db: &BindingsGenerator, items: &[RsTypeKind], trait_record: Option<&Record>, ) -> TokenStream { @@ -2252,7 +2252,7 @@ fn format_tuple_except_singleton_replacing_by_self( /// /// where `SameType` is the same type as the class this function is declared in. fn has_copy_assignment_operator_from_const_reference( - db: &dyn BindingsGenerator, + db: &BindingsGenerator, copy_constructor: &Func, ) -> bool { let [_self, first_param] = ©_constructor.params[..] else { @@ -2282,9 +2282,7 @@ fn has_copy_assignment_operator_from_const_reference( } /// Implementation of `BindingsGenerator::overload_sets`. -pub fn overload_sets( - db: &dyn BindingsGenerator, -) -> Rc, Option>> { +pub fn overload_sets(db: &BindingsGenerator) -> Rc, Option>> { #[derive(Copy, Clone)] struct CandidateFunction { item_id: ir::ItemId, diff --git a/rs_bindings_from_cc/generate_bindings/generate_function_thunk.rs b/rs_bindings_from_cc/generate_bindings/generate_function_thunk.rs index da9c83864..a567c8044 100644 --- a/rs_bindings_from_cc/generate_bindings/generate_function_thunk.rs +++ b/rs_bindings_from_cc/generate_bindings/generate_function_thunk.rs @@ -23,7 +23,7 @@ use unicode_ident::is_xid_continue; /// If we know the original C++ function is codegenned and already compatible /// with `extern "C"` calling convention we skip creating/calling the C++ thunk /// since we can call the original C++ directly. -pub fn can_skip_cc_thunk(db: &dyn BindingsGenerator, func: &Func) -> bool { +pub fn can_skip_cc_thunk(db: &BindingsGenerator, func: &Func) -> bool { // ## Inline functions // // Inline functions may not be codegenned in the C++ library since Clang doesn't @@ -117,7 +117,7 @@ pub fn can_skip_cc_thunk(db: &dyn BindingsGenerator, func: &Func) -> bool { } pub fn generate_function_thunk( - db: &dyn BindingsGenerator, + db: &BindingsGenerator, func: &Func, param_idents: &[Ident], param_types: &[RsTypeKind], @@ -251,7 +251,7 @@ pub fn thunk_ident(func: &Func) -> Ident { } fn generate_function_assertation_for_identifier( - db: &dyn BindingsGenerator, + db: &BindingsGenerator, func: &Func, id: &Identifier, ) -> Result { @@ -325,7 +325,7 @@ fn generate_function_assertation_for_identifier( } pub fn generate_function_assertation( - db: &dyn BindingsGenerator, + db: &BindingsGenerator, func: &Func, ) -> Result> { if func.adl_enclosing_record.is_some() { @@ -365,7 +365,7 @@ fn is_copy_constructor(func: &Func, record_id: ItemId) -> bool { } pub fn generate_function_thunk_impl( - db: &dyn BindingsGenerator, + db: &BindingsGenerator, func: &Func, ) -> Result> { if can_skip_cc_thunk(db, func) { diff --git a/rs_bindings_from_cc/generate_bindings/generate_struct_and_union.rs b/rs_bindings_from_cc/generate_bindings/generate_struct_and_union.rs index 941f4a550..fcde7dbe6 100644 --- a/rs_bindings_from_cc/generate_bindings/generate_struct_and_union.rs +++ b/rs_bindings_from_cc/generate_bindings/generate_struct_and_union.rs @@ -12,7 +12,6 @@ use database::code_snippet::{ NoUniqueAddressAccessor, RecursivelyPinnedAttr, SizeofImpl, StructOrUnion, Thunk, ThunkImpl, UpcastImpl, UpcastImplBody, Visibility, }; -use database::db; use database::rs_snippet::{should_derive_clone, RsTypeKind}; use database::BindingsGenerator; use error_report::{bail, ensure}; @@ -54,7 +53,7 @@ fn needs_manually_drop(ty: &RsTypeKind) -> bool { /// Generates Rust source code for a given incomplete record declaration. pub fn generate_incomplete_record( - db: &dyn BindingsGenerator, + db: &BindingsGenerator, incomplete_record: Rc, ) -> Result { // If the record won't have bindings, we default to `public` to keep going anyway. @@ -99,7 +98,7 @@ fn make_rs_field_ident(field: &Field, field_index: usize) -> Ident { /// /// See docs/struct_layout fn get_field_rs_type_kind_for_layout( - db: &dyn BindingsGenerator, + db: &BindingsGenerator, record: &Record, field: &Field, ) -> Result { @@ -164,7 +163,7 @@ fn get_field_rs_type_kind_for_layout( } fn collect_unqualified_member_functions_from_all_bases( - db: &dyn BindingsGenerator, + db: &BindingsGenerator, record: &Record, ) -> Rc<[Rc]> { let ir = db.ir(); @@ -188,7 +187,7 @@ fn collect_unqualified_member_functions_from_all_bases( /// Implementation of `BindingsGenerator::collect_unqualified_member_functions`. pub fn collect_unqualified_member_functions( - db: &dyn BindingsGenerator, + db: &BindingsGenerator, record: Rc, ) -> Rc<[Rc]> { let ir = db.ir(); @@ -216,7 +215,7 @@ pub fn collect_unqualified_member_functions( /// Ambiguous functions are functions that have the same name as a function in /// the base class. fn filter_out_ambiguous_member_functions( - db: &dyn BindingsGenerator, + db: &BindingsGenerator, derived_record: Rc, inherited_functions: Rc<[Rc]>, ) -> Rc<[Rc]> { @@ -249,7 +248,7 @@ fn filter_out_ambiguous_member_functions( #[allow(clippy::too_many_arguments)] fn field_definition( - db: &dyn BindingsGenerator, + db: &BindingsGenerator, record: &Record, field: Option<&ir::Field>, field_index: usize, @@ -315,7 +314,7 @@ fn field_definition( } }; let visibility = if field.access == AccessSpecifier::Public && field_rs_type_kind.is_ok() { - db::type_visibility(db, &record.owning_target, field_rs_type_kind.clone().unwrap()) + db.type_visibility(&record.owning_target, field_rs_type_kind.clone().unwrap()) .unwrap_or_default() } else { Visibility::PubCrate @@ -350,7 +349,7 @@ fn field_definition( } /// Implementation of `BindingsGenerator::generate_record`. -pub fn generate_record(db: &dyn BindingsGenerator, record: Rc) -> Result { +pub fn generate_record(db: &BindingsGenerator, record: Rc) -> Result { let record_rs_type_kind = db.rs_type_kind(record.as_ref().into())?; if matches!( &record_rs_type_kind, @@ -710,7 +709,7 @@ pub fn generate_record(db: &dyn BindingsGenerator, record: Rc) -> Result /// whether each child item should be nested in a module. pub fn child_items<'a, 'db>( record: &'a Record, - db: &'a dyn BindingsGenerator<'db>, + db: &'a BindingsGenerator<'db>, ) -> impl Iterator> + use<'a, 'db> { record.child_item_ids.iter().map(|&child_item_id| { let item = db.ir().find_untyped_decl(child_item_id); @@ -751,7 +750,7 @@ pub fn generate_derives(record: &Record) -> DeriveAttr { DeriveAttr(derives) } -fn cc_struct_layout_assertion(db: &dyn BindingsGenerator, record: &Record) -> Result { +fn cc_struct_layout_assertion(db: &BindingsGenerator, record: &Record) -> Result { let namespace_qualifier = db.ir().namespace_qualifier(record).format_for_cc()?; let fields_and_expected_offsets: Vec<(TokenStream, usize)> = record .fields @@ -801,7 +800,7 @@ fn cc_struct_layout_assertion(db: &dyn BindingsGenerator, record: &Record) -> Re /// Returns the accessor functions for no_unique_address member variables. fn cc_struct_no_unique_address_impl( - db: &dyn BindingsGenerator, + db: &BindingsGenerator, record: &Record, ) -> Result> { let mut no_unique_address_accessors = vec![]; @@ -851,7 +850,7 @@ type UpcastImplResult = Result; /// Returns the implementation of base class conversions, for converting a type /// to its unambiguous public base classes. fn cc_struct_upcast_impl( - db: &dyn BindingsGenerator, + db: &BindingsGenerator, record: &Rc, ir: &IR, ) -> Result<(Vec, Vec, Vec)> { diff --git a/rs_bindings_from_cc/generate_bindings/has_bindings.rs b/rs_bindings_from_cc/generate_bindings/has_bindings.rs index e3ea95d8f..4f81dfb6c 100644 --- a/rs_bindings_from_cc/generate_bindings/has_bindings.rs +++ b/rs_bindings_from_cc/generate_bindings/has_bindings.rs @@ -7,7 +7,6 @@ use database::code_snippet::{ required_crubit_features, BindingsInfo, NoBindingsReason, RequiredCrubitFeature, ResolvedTypeName, Visibility, }; -use database::db; use database::rs_snippet::RsTypeKind; use database::BindingsGenerator; use error_report::{anyhow, bail}; @@ -17,10 +16,7 @@ use std::collections::HashMap; use std::rc::Rc; /// Implementation of `BindingsGenerator::has_bindings`. -pub fn has_bindings( - db: &dyn BindingsGenerator, - item: Item, -) -> Result { +pub fn has_bindings(db: &BindingsGenerator, item: Item) -> Result { let ir = db.ir(); if let Some(name) = item.cc_name_as_str() { @@ -176,7 +172,7 @@ pub fn has_bindings( /// Returns function-specific `has_bindings` information. fn func_has_bindings( - db: &dyn BindingsGenerator, + db: &BindingsGenerator, func: Rc, ) -> Result { if func.is_consteval { @@ -258,7 +254,7 @@ fn func_has_bindings( // // YMMV: feel free to unify the two functions later. pub fn type_target_restriction( - db: &dyn BindingsGenerator, + db: &BindingsGenerator, rs_type_kind: RsTypeKind, ) -> Result> { // We visit `self` twice, but it doesn't matter, we just need a starting value. @@ -292,7 +288,7 @@ struct TargetRestriction { /// Returns an error if both are `pub(crate)`, and the two types are owned by different crates. /// The error contains just a list of the types it found that are incompatible. fn intersect_target_restrictions( - db: &dyn BindingsGenerator, + db: &BindingsGenerator, old_restriction: &mut TargetRestriction, new_restriction: TargetRestriction, ) -> Result<()> { @@ -320,7 +316,7 @@ fn intersect_target_restrictions( /// For example, the top level visibility restriction of `*mut T` is `None` for all `T`, because /// pointers are never `pub(crate)`, only their pointees can be. fn type_target_restriction_shallow( - db: &dyn BindingsGenerator, + db: &BindingsGenerator, rs_type_kind: RsTypeKind, ) -> TargetRestriction { let mut target = match rs_type_kind.unalias() { @@ -351,14 +347,14 @@ fn type_target_restriction_shallow( } fn type_visibility( - db: &dyn BindingsGenerator, + db: &BindingsGenerator, item: &dyn GenericItem, rs_type_kind: RsTypeKind, ) -> Result { let Some(target) = item.owning_target() else { return Ok(Visibility::Public); }; - match db::type_visibility(db, &target, rs_type_kind.clone()) { + match db.type_visibility(&target, rs_type_kind.clone()) { Ok(vis) => Ok(vis), Err(error) => { let missing_features = vec![RequiredCrubitFeature { @@ -387,7 +383,7 @@ fn type_visibility( /// In the future, we may want to extend this to check the value namespace for functions and /// global variables as well. pub fn resolve_type_names( - db: &dyn BindingsGenerator, + db: &BindingsGenerator, parent: Rc, ) -> Result, ResolvedTypeName>>> { let child_item_ids: &[ItemId] = diff --git a/rs_bindings_from_cc/generate_bindings/lib.rs b/rs_bindings_from_cc/generate_bindings/lib.rs index 5a38a83b9..82e7346ff 100644 --- a/rs_bindings_from_cc/generate_bindings/lib.rs +++ b/rs_bindings_from_cc/generate_bindings/lib.rs @@ -10,7 +10,7 @@ use crubit_abi_type::{CrubitAbiType, CrubitAbiTypeToRustExprTokens, FullyQualifi use database::code_snippet::{ self, ApiSnippets, Bindings, BindingsTokens, CppDetails, CppIncludes, Feature, GeneratedItem, }; -use database::db::{self, BindingsGenerator, CodegenFunctions, Database}; +use database::db::{BindingsGenerator, CodegenFunctions}; use database::rs_snippet::{ BridgeRsTypeKind, Callable, FnTrait, Mutability, RsTypeKind, RustPtrKind, }; @@ -101,10 +101,7 @@ pub fn generate_bindings( Ok(Bindings { rs_api, rs_api_impl }) } -fn generate_type_alias( - db: &dyn BindingsGenerator, - type_alias: Rc, -) -> Result { +fn generate_type_alias(db: &BindingsGenerator, type_alias: Rc) -> Result { // Skip the type alias if it maps to a bridge type. let rs_type_kind = db.rs_type_kind((&*type_alias).into())?; let generated_item = if rs_type_kind.unalias().is_bridge_type() { @@ -138,7 +135,8 @@ fn generate_type_alias( Some(&type_alias.source_loc), db.environment(), ), - visibility: db::type_visibility(db, &type_alias.owning_target, rs_type_kind) + visibility: db + .type_visibility(&type_alias.owning_target, rs_type_kind) .unwrap_or_default(), ident: make_rs_ident(&type_alias.rs_name.identifier), underlying_type: underlying_type.to_token_stream(db), @@ -151,7 +149,7 @@ fn generate_type_alias( }) } -fn generate_global_var(db: &dyn BindingsGenerator, var: Rc) -> Result { +fn generate_global_var(db: &BindingsGenerator, var: Rc) -> Result { let type_ = db.rs_type_kind(var.type_.clone())?; Ok(ApiSnippets { @@ -162,14 +160,14 @@ fn generate_global_var(db: &dyn BindingsGenerator, var: Rc) -> Result is_mut: !var.type_.is_const, ident: make_rs_ident(&var.rs_name.identifier), type_tokens: type_.to_token_stream(db), - visibility: db::type_visibility(db, &var.owning_target, type_).unwrap_or_default(), + visibility: db.type_visibility(&var.owning_target, type_).unwrap_or_default(), }, )]), ..Default::default() }) } -fn generate_namespace(db: &dyn BindingsGenerator, namespace: Rc) -> Result { +fn generate_namespace(db: &BindingsGenerator, namespace: Rc) -> Result { let ir = db.ir(); let mut api_snippets = ApiSnippets::default(); @@ -187,7 +185,7 @@ fn generate_namespace(db: &dyn BindingsGenerator, namespace: Rc) -> R } /// Implementation of `BindingsGenerator::generate_item`. -fn generate_item(db: &dyn BindingsGenerator, item: Item) -> Result { +fn generate_item(db: &BindingsGenerator, item: Item) -> Result { let _scope = item.error_scope(db.ir(), db.errors()); let err = match generate_item_impl(db, &item) { Ok(generated) => return Ok(generated), @@ -211,7 +209,7 @@ fn generate_item(db: &dyn BindingsGenerator, item: Item) -> Result /// The implementation of generate_item, without the error recovery logic. /// /// Returns Err if bindings could not be generated for this item. -fn generate_item_impl(db: &dyn BindingsGenerator, item: &Item) -> Result { +fn generate_item_impl(db: &BindingsGenerator, item: &Item) -> Result { let ir = db.ir(); if let Some(owning_target) = item.owning_target() { if !ir.is_current_target(&owning_target) { @@ -301,8 +299,8 @@ pub fn new_database<'db>( errors: &'db dyn ErrorReporting, fatal_errors: &'db dyn ReportFatalError, environment: Environment, -) -> Database<'db> { - Database::new( +) -> BindingsGenerator<'db> { + BindingsGenerator::new( ir, errors, fatal_errors, @@ -494,7 +492,7 @@ pub fn generate_bindings_tokens( } /// Implementation of `BindingsGenerator::is_rs_type_kind_unsafe`. -fn is_rs_type_kind_unsafe(db: &dyn BindingsGenerator, rs_type_kind: RsTypeKind) -> bool { +fn is_rs_type_kind_unsafe(db: &BindingsGenerator, rs_type_kind: RsTypeKind) -> bool { match rs_type_kind { RsTypeKind::Error { .. } => true, RsTypeKind::Pointer { .. } => true, @@ -549,7 +547,7 @@ fn is_rs_type_kind_unsafe(db: &dyn BindingsGenerator, rs_type_kind: RsTypeKind) /// Helper function for `is_rs_type_kind_unsafe`. /// Returns true if the record is unsafe, or if it transitively contains a public field of /// an unsafe type. -fn is_record_unsafe(db: &dyn BindingsGenerator, record: &Record) -> bool { +fn is_record_unsafe(db: &BindingsGenerator, record: &Record) -> bool { if record.is_unsafe_type { return true; } @@ -577,7 +575,7 @@ fn is_record_unsafe(db: &dyn BindingsGenerator, record: &Record) -> bool { } fn generate_rs_api_impl_includes( - db: &Database, + db: &BindingsGenerator, crubit_support_path_format: Format<1>, has_callables: bool, ) -> CppIncludes { @@ -684,7 +682,7 @@ fn make_transmute_abi_type_from_item( item: &impl GenericItem, rs_name: &str, cc_name: &str, - db: &dyn BindingsGenerator, + db: &BindingsGenerator, ) -> Result { // Rust names are of the form ":: tuples_golden :: NontrivialDrop" let mut rust_path = rs_name; @@ -716,7 +714,7 @@ fn make_transmute_abi_type_from_item( } /// Implementation of `BindingsGenerator::crubit_abi_type`. -fn crubit_abi_type(db: &dyn BindingsGenerator, rs_type_kind: RsTypeKind) -> Result { +fn crubit_abi_type(db: &BindingsGenerator, rs_type_kind: RsTypeKind) -> Result { match rs_type_kind { RsTypeKind::Error { error, .. } => { bail!("Type has an error and cannot be bridged: {error}") @@ -889,7 +887,7 @@ fn crubit_abi_type(db: &dyn BindingsGenerator, rs_type_kind: RsTypeKind) -> Resu /// `None` is returned if there is issue generating the thunk. The specific error is not reported /// because it will be reported elsewhere. fn generate_dyn_callable_cpp_thunk( - db: &dyn BindingsGenerator, + db: &BindingsGenerator, dyn_callable: &Callable, param_idents: &[Ident], ) -> Option { @@ -976,7 +974,7 @@ fn generate_dyn_callable_cpp_thunk( /// `None` is returned if there is issue generating the definition. The specific error is not /// reported because it will be reported elsewhere. fn generate_dyn_callable_rust_thunk_impl( - db: &dyn BindingsGenerator, + db: &BindingsGenerator, dyn_callable: Rc, param_idents: &[Ident], ) -> Option { @@ -1166,7 +1164,7 @@ fn strip_leading_colon2(path: &mut &str) -> bool { fn make_cpp_type_from_item( item: &impl GenericItem, cc_name_parts: &[&str], - db: &dyn BindingsGenerator, + db: &BindingsGenerator, ) -> Result { let namespace_qualifier = db.ir().namespace_qualifier(item); let parts = namespace_qualifier diff --git a/rs_bindings_from_cc/generate_bindings/rs_type_kind.rs b/rs_bindings_from_cc/generate_bindings/rs_type_kind.rs index ee0aef7d3..698ad19d6 100644 --- a/rs_bindings_from_cc/generate_bindings/rs_type_kind.rs +++ b/rs_bindings_from_cc/generate_bindings/rs_type_kind.rs @@ -11,7 +11,7 @@ use std::rc::Rc; /// Implementation of `BindingsGenerator::rs_type_kind`. pub fn rs_type_kind_with_lifetime_elision( - db: &dyn BindingsGenerator, + db: &BindingsGenerator, ty: CcType, lifetime_options: LifetimeOptions, ) -> Result { diff --git a/rs_bindings_from_cc/generate_bindings/test_generators.rs b/rs_bindings_from_cc/generate_bindings/test_generators.rs index bb9b4e211..1aec48c8b 100644 --- a/rs_bindings_from_cc/generate_bindings/test_generators.rs +++ b/rs_bindings_from_cc/generate_bindings/test_generators.rs @@ -6,7 +6,7 @@ use arc_anyhow::Result; use database::code_snippet::BindingsTokens; -use database::db::Database; +use database::db::BindingsGenerator; use error_report::{bail, ErrorReport, FatalErrors}; use ffi_types::Environment; use generate_bindings::{generate_bindings_tokens, new_database}; @@ -43,7 +43,7 @@ impl TestDbFactory { fatal_errors: FatalErrors::new(), }) } - pub fn make_db(&self) -> Database { + pub fn make_db(&self) -> BindingsGenerator { new_database(&self.ir, &self.errors, &self.fatal_errors, Environment::Production) } }