From 9bbaca06da418fdabc18e17917495abc49854d9e Mon Sep 17 00:00:00 2001 From: Jake Bailey Date: Fri, 23 Sep 2022 17:01:01 -0700 Subject: [PATCH] Add rust_provider_backend_api Summary: Add a trait abstracting over the set of providers necessary to typecheck a file, and make use of it in rust_provider_backend_ffi. When using a backend other than HhServerProviderBackend, raise panics (which are converted to OCaml exceptions by `ocaml_ffi!`) when attempting to invoke one of the rust_provider_backend_ffi functions outside of the minimum set necessary to typecheck a file. This makes it easier to implement the RustProviderBackend trait for use cases which are only interested in typechecking files (e.g., hh_distc workers, potentially hh rearchitecture workers, potentially zoncolan workers). Reviewed By: edwinsmith Differential Revision: D39780735 fbshipit-source-id: 6d0152e831679f9d4fd5c98925cf5f59c44fd812 --- hphp/hack/src/providers/Cargo.toml | 16 + .../cargo/rust_provider_backend_ffi/Cargo.toml | 3 + .../providers/hackrs_provider_backend/Cargo.toml | 1 + .../hackrs_provider_backend.rs | 27 +- .../src/providers/rust_provider_backend_api.rs | 18 + .../src/providers/rust_provider_backend_ffi.rs | 512 ++++++++++++++++----- 6 files changed, 456 insertions(+), 121 deletions(-) create mode 100644 hphp/hack/src/providers/Cargo.toml create mode 100644 hphp/hack/src/providers/rust_provider_backend_api.rs diff --git a/hphp/hack/src/providers/Cargo.toml b/hphp/hack/src/providers/Cargo.toml new file mode 100644 index 00000000000..2f98706d11e --- /dev/null +++ b/hphp/hack/src/providers/Cargo.toml @@ -0,0 +1,16 @@ +# @generated by autocargo from //hphp/hack/src/providers:rust_provider_backend_api +[package] +name = "rust_provider_backend_api" +version = "0.0.0" +edition = "2021" + +[lib] +path = "rust_provider_backend_api.rs" +test = false +doctest = false + +[dependencies] +file_provider = { path = "../hackrs/file_provider/cargo/file_provider" } +folded_decl_provider = { path = "../hackrs/folded_decl_provider/cargo/folded_decl_provider" } +naming_provider = { path = "../hackrs/naming_provider/cargo/naming_provider" } +ty = { path = "../hackrs/ty/cargo/ty" } diff --git a/hphp/hack/src/providers/cargo/rust_provider_backend_ffi/Cargo.toml b/hphp/hack/src/providers/cargo/rust_provider_backend_ffi/Cargo.toml index 1d026e2a6cc..7c42b3ccce1 100644 --- a/hphp/hack/src/providers/cargo/rust_provider_backend_ffi/Cargo.toml +++ b/hphp/hack/src/providers/cargo/rust_provider_backend_ffi/Cargo.toml @@ -14,11 +14,14 @@ crate-type = ["lib", "staticlib"] bincode = "1.3.3" bstr = { version = "0.2", features = ["serde1"] } deps_rust = { path = "../../../deps/cargo/deps_rust" } +file_provider = { path = "../../../hackrs/file_provider/cargo/file_provider" } hackrs_provider_backend = { path = "../../hackrs_provider_backend" } +naming_provider = { path = "../../../hackrs/naming_provider/cargo/naming_provider" } ocamlrep = { path = "../../../ocamlrep" } ocamlrep_custom = { path = "../../../ocamlrep_custom" } ocamlrep_ocamlpool = { path = "../../../ocamlrep_ocamlpool" } oxidized = { path = "../../../oxidized" } oxidized_by_ref = { path = "../../../oxidized_by_ref" } pos = { path = "../../../hackrs/pos/cargo/pos" } +rust_provider_backend_api = { path = "../.." } ty = { path = "../../../hackrs/ty/cargo/ty" } diff --git a/hphp/hack/src/providers/hackrs_provider_backend/Cargo.toml b/hphp/hack/src/providers/hackrs_provider_backend/Cargo.toml index 57491735bff..f5999906ad7 100644 --- a/hphp/hack/src/providers/hackrs_provider_backend/Cargo.toml +++ b/hphp/hack/src/providers/hackrs_provider_backend/Cargo.toml @@ -26,6 +26,7 @@ oxidized = { path = "../../oxidized" } oxidized_by_ref = { path = "../../oxidized_by_ref" } parking_lot = { version = "0.11.2", features = ["send_guard"] } pos = { path = "../../hackrs/pos/cargo/pos" } +rust_provider_backend_api = { path = ".." } serde = { version = "1.0.136", features = ["derive", "rc"] } shallow_decl_provider = { path = "../../hackrs/shallow_decl_provider/cargo/shallow_decl_provider" } shm_store = { path = "../../shmffi/cargo/shm_store" } diff --git a/hphp/hack/src/providers/hackrs_provider_backend/hackrs_provider_backend.rs b/hphp/hack/src/providers/hackrs_provider_backend/hackrs_provider_backend.rs index e66b9685349..3efc9e82e2c 100644 --- a/hphp/hack/src/providers/hackrs_provider_backend/hackrs_provider_backend.rs +++ b/hphp/hack/src/providers/hackrs_provider_backend/hackrs_provider_backend.rs @@ -19,6 +19,7 @@ use file_provider::DiskProvider; use file_provider::FileProvider; use folded_decl_provider::FoldedDeclProvider; use folded_decl_provider::LazyFoldedDeclProvider; +use naming_provider::NamingProvider; use naming_table::NamingTable; use ocamlrep_derive::FromOcamlRep; use ocamlrep_derive::ToOcamlRep; @@ -132,18 +133,10 @@ impl HhServerProviderBackend { &*self.file_store } - pub fn file_provider(&self) -> &dyn FileProvider { - &*self.file_provider - } - pub fn shallow_decl_provider(&self) -> &dyn ShallowDeclProvider { &*self.lazy_shallow_decl_provider } - pub fn folded_decl_provider(&self) -> &dyn FoldedDeclProvider { - &*self.folded_decl_provider - } - /// Decl-parse the given file, dedup duplicate definitions of the same /// symbol (within the file, as well as removing losers of naming conflicts /// with other files), and add the parsed decls to the shallow decl store. @@ -185,6 +178,24 @@ impl HhServerProviderBackend { } } +impl rust_provider_backend_api::RustProviderBackend for HhServerProviderBackend { + fn file_provider(&self) -> &dyn FileProvider { + &*self.file_provider + } + + fn naming_provider(&self) -> &dyn NamingProvider { + &*self.naming_table + } + + fn folded_decl_provider(&self) -> &dyn FoldedDeclProvider { + &*self.folded_decl_provider + } + + fn as_any(&self) -> &dyn std::any::Any { + self + } +} + pub struct ShallowStoreWithChanges { classes: Arc>>>, typedefs: Arc>>>, diff --git a/hphp/hack/src/providers/rust_provider_backend_api.rs b/hphp/hack/src/providers/rust_provider_backend_api.rs new file mode 100644 index 00000000000..06fb7e83181 --- /dev/null +++ b/hphp/hack/src/providers/rust_provider_backend_api.rs @@ -0,0 +1,18 @@ +// Copyright (c) Meta Platforms, Inc. and affiliates. +// +// This source code is licensed under the MIT license found in the +// LICENSE file in the "hack" directory of this source tree. + +use ty::reason::Reason; + +/// A trait which includes only the ProviderBackend functionality necessary to +/// typecheck a file. +pub trait RustProviderBackend { + fn file_provider(&self) -> &dyn file_provider::FileProvider; + + fn naming_provider(&self) -> &dyn naming_provider::NamingProvider; + + fn folded_decl_provider(&self) -> &dyn folded_decl_provider::FoldedDeclProvider; + + fn as_any(&self) -> &dyn std::any::Any; +} diff --git a/hphp/hack/src/providers/rust_provider_backend_ffi.rs b/hphp/hack/src/providers/rust_provider_backend_ffi.rs index 7535f18229c..7895d49fcb8 100644 --- a/hphp/hack/src/providers/rust_provider_backend_ffi.rs +++ b/hphp/hack/src/providers/rust_provider_backend_ffi.rs @@ -11,7 +11,9 @@ use hackrs_provider_backend::Config; use hackrs_provider_backend::FileType; use hackrs_provider_backend::HhServerProviderBackend; use ocamlrep::ptr::UnsafeOcamlPtr; +use ocamlrep::rc::RcOc; use ocamlrep::FromOcamlRep; +use ocamlrep::ToOcamlRep; use ocamlrep_custom::Custom; use ocamlrep_ocamlpool::ocaml_ffi; use ocamlrep_ocamlpool::ocaml_ffi_with_arena; @@ -23,15 +25,44 @@ use oxidized_by_ref::direct_decl_parser; use oxidized_by_ref::shallow_decl_defs; use pos::RelativePath; use pos::RelativePathCtx; +use rust_provider_backend_api::RustProviderBackend; use ty::decl; use ty::reason::BReason; +use ty::reason::NReason; -struct BackendWrapper(HhServerProviderBackend); +pub enum BackendWrapper { + Positioned(Arc>), + PositionFree(Arc>), +} + +impl BackendWrapper { + pub fn positioned(backend: Arc>) -> Custom { + Custom::from(Self::Positioned(backend)) + } + + pub fn position_free(backend: Arc>) -> Custom { + Custom::from(Self::PositionFree(backend)) + } -impl std::ops::Deref for BackendWrapper { - type Target = HhServerProviderBackend; - fn deref(&self) -> &HhServerProviderBackend { - &self.0 + fn as_hh_server_backend(&self) -> Option<&HhServerProviderBackend> { + match self { + Self::Positioned(backend) => backend.as_any().downcast_ref(), + Self::PositionFree(..) => None, + } + } + + pub fn file_provider(&self) -> &dyn file_provider::FileProvider { + match self { + Self::Positioned(backend) => backend.file_provider(), + Self::PositionFree(backend) => backend.file_provider(), + } + } + + pub fn naming_provider(&self) -> &dyn naming_provider::NamingProvider { + match self { + Self::Positioned(backend) => backend.naming_provider(), + Self::PositionFree(backend) => backend.naming_provider(), + } } } @@ -39,13 +70,16 @@ impl ocamlrep_custom::CamlSerialize for BackendWrapper { ocamlrep_custom::caml_serialize_default_impls!(); fn serialize(&self) -> Vec { - let config: Config = self.0.config(); + let backend = self + .as_hh_server_backend() + .expect("only HhServerProviderBackend can be serialized"); + let config: Config = backend.config(); bincode::serialize(&config).unwrap() } fn deserialize(data: &[u8]) -> Self { let config: Config = bincode::deserialize(data).unwrap(); - Self(HhServerProviderBackend::new(config).unwrap()) + BackendWrapper::Positioned(Arc::new(HhServerProviderBackend::new(config).unwrap())) } } @@ -73,22 +107,34 @@ ocaml_ffi! { tmp, ..Default::default() }; - let backend = HhServerProviderBackend::new(Config { + let backend = Arc::new(HhServerProviderBackend::new(Config { path_ctx, parser_options: opts, db_path: None, - }).unwrap(); - Custom::from(BackendWrapper(backend)) + }).unwrap()); + BackendWrapper::positioned(backend) } } +const UNIMPLEMENTED_MESSAGE: &str = "RustProviderBackend impls other than HhServerProviderBackend \ + only support the minimum functionality necessary for typechecking a file. \ + This API is not supported."; + ocaml_ffi! { fn hh_rust_provider_backend_push_local_changes(backend: Backend) { - backend.push_local_changes(); + if let Some(backend) = backend.as_hh_server_backend() { + backend.push_local_changes(); + } else { + unimplemented!("push_local_changes: {UNIMPLEMENTED_MESSAGE}"); + } } fn hh_rust_provider_backend_pop_local_changes(backend: Backend) { - backend.pop_local_changes(); + if let Some(backend) = backend.as_hh_server_backend() { + backend.pop_local_changes(); + } else { + unimplemented!("pop_local_changes: {UNIMPLEMENTED_MESSAGE}"); + } } } @@ -102,6 +148,10 @@ ocaml_ffi_with_arena! { text: UnsafeOcamlPtr, ) -> direct_decl_parser::ParsedFileWithHashes<'a> { let backend = unsafe { get_backend(backend) }; + let backend = match backend.as_hh_server_backend() { + Some(backend) => backend, + None => unimplemented!("direct_decl_parse_and_cache: {UNIMPLEMENTED_MESSAGE}"), + }; // SAFETY: Borrow the contents of the source file from the value on the // OCaml heap rather than copying it over. This is safe as long as we // don't call into OCaml within this function scope. @@ -116,126 +166,252 @@ ocaml_ffi_with_arena! { decls: &[(&'a str, shallow_decl_defs::Decl<'a>)], ) { let backend = unsafe { get_backend(backend) }; + let backend = match backend.as_hh_server_backend() { + Some(backend) => backend, + None => unimplemented!("add_shallow_decls: {UNIMPLEMENTED_MESSAGE}"), + }; backend.add_decls(decls).unwrap(); } +} - fn hh_rust_provider_backend_get_fun<'a>( - arena: &'a Bump, - backend: UnsafeOcamlPtr, +// UnsafeOcamlPtr is used because ocamlrep_custom::Custom cannot be used with +// ocaml_ffi_with_arena (it does not implement FromOcamlRepIn, and shouldn't, +// since arena-allocating a Custom would result in failing to decrement the +// inner Rc and leaking memory). +unsafe fn get_backend(ptr: UnsafeOcamlPtr) -> Backend { + Backend::from_ocamlrep(ptr.as_value()).unwrap() +} + +// NB: this function interacts with the OCaml runtime (but won't trigger a GC). +fn to_ocaml(value: &T) -> UnsafeOcamlPtr { + // SAFETY: this module doesn't do any concurrent interaction with the OCaml + // runtime while invoking this function + unsafe { UnsafeOcamlPtr::new(ocamlrep_ocamlpool::to_ocaml(value)) } +} + +ocaml_ffi! { + fn hh_rust_provider_backend_get_fun( + backend: Backend, name: pos::FunName, - ) -> Option>> { - let backend = unsafe { get_backend(backend) }; - backend.folded_decl_provider().get_fun(name.into(), name).unwrap() + ) -> UnsafeOcamlPtr { + match &*backend { + BackendWrapper::Positioned(backend) => { + let res: Option>> = backend.folded_decl_provider() + .get_fun(name.into(), name) + .unwrap(); + to_ocaml(&res) + } + BackendWrapper::PositionFree(backend) => { + let res: Option>> = backend.folded_decl_provider() + .get_fun(name.into(), name) + .unwrap(); + to_ocaml(&res) + } + } } - fn hh_rust_provider_backend_get_shallow_class<'a>( - arena: &'a Bump, - backend: UnsafeOcamlPtr, + fn hh_rust_provider_backend_get_shallow_class( + backend: Backend, name: pos::TypeName, ) -> Option>> { - let backend = unsafe { get_backend(backend) }; - backend.shallow_decl_provider().get_class(name).unwrap() + if let Some(backend) = backend.as_hh_server_backend() { + backend.shallow_decl_provider().get_class(name).unwrap() + } else { + unimplemented!("get_shallow_class: {UNIMPLEMENTED_MESSAGE}") + } } - fn hh_rust_provider_backend_get_typedef<'a>( - arena: &'a Bump, - backend: UnsafeOcamlPtr, + fn hh_rust_provider_backend_get_typedef( + backend: Backend, name: pos::TypeName, - ) -> Option>> { - let backend = unsafe { get_backend(backend) }; - backend.folded_decl_provider().get_typedef(name.into(), name).unwrap() + ) -> UnsafeOcamlPtr { + match &*backend { + BackendWrapper::Positioned(backend) => { + let res: Option>> = backend.folded_decl_provider() + .get_typedef(name.into(), name) + .unwrap(); + to_ocaml(&res) + } + BackendWrapper::PositionFree(backend) => { + let res: Option>> = backend.folded_decl_provider() + .get_typedef(name.into(), name) + .unwrap(); + to_ocaml(&res) + } + } } - fn hh_rust_provider_backend_get_gconst<'a>( - arena: &'a Bump, - backend: UnsafeOcamlPtr, + fn hh_rust_provider_backend_get_gconst( + backend: Backend, name: pos::ConstName, - ) -> Option>> { - let backend = unsafe { get_backend(backend) }; - backend.folded_decl_provider().get_const(name.into(), name).unwrap() + ) -> UnsafeOcamlPtr { + match &*backend { + BackendWrapper::Positioned(backend) => { + let res: Option>> = backend.folded_decl_provider() + .get_const(name.into(), name) + .unwrap(); + to_ocaml(&res) + } + BackendWrapper::PositionFree(backend) => { + let res: Option>> = backend.folded_decl_provider() + .get_const(name.into(), name) + .unwrap(); + to_ocaml(&res) + } + } } - fn hh_rust_provider_backend_get_module<'a>( - arena: &'a Bump, - backend: UnsafeOcamlPtr, + fn hh_rust_provider_backend_get_module( + backend: Backend, name: pos::ModuleName, - ) -> Option>> { - let backend = unsafe { get_backend(backend) }; - backend.folded_decl_provider().get_module(name.into(), name).unwrap() + ) -> UnsafeOcamlPtr { + match &*backend { + BackendWrapper::Positioned(backend) => { + let res: Option>> = backend.folded_decl_provider() + .get_module(name.into(), name) + .unwrap(); + to_ocaml(&res) + } + BackendWrapper::PositionFree(backend) => { + let res: Option>> = backend.folded_decl_provider() + .get_module(name.into(), name) + .unwrap(); + to_ocaml(&res) + } + } } - fn hh_rust_provider_backend_get_prop<'a>( - arena: &'a Bump, - backend: UnsafeOcamlPtr, + fn hh_rust_provider_backend_get_prop( + backend: Backend, name: (pos::TypeName, pos::PropName), - ) -> Option> { - let backend = unsafe { get_backend(backend) }; - backend.shallow_decl_provider().get_property_type(name.0, name.1).unwrap() + ) -> UnsafeOcamlPtr { + match &*backend { + BackendWrapper::Positioned(backend) => { + let res: Option> = backend.folded_decl_provider() + .get_shallow_property_type(name.0.into(), name.0, name.1) + .unwrap(); + to_ocaml(&res) + } + BackendWrapper::PositionFree(backend) => { + let res: Option> = backend.folded_decl_provider() + .get_shallow_property_type(name.0.into(), name.0, name.1) + .unwrap(); + to_ocaml(&res) + } + } } - fn hh_rust_provider_backend_get_static_prop<'a>( - arena: &'a Bump, - backend: UnsafeOcamlPtr, + fn hh_rust_provider_backend_get_static_prop( + backend: Backend, name: (pos::TypeName, pos::PropName), - ) -> Option> { - let backend = unsafe { get_backend(backend) }; - backend.shallow_decl_provider().get_static_property_type(name.0, name.1).unwrap() + ) -> UnsafeOcamlPtr { + match &*backend { + BackendWrapper::Positioned(backend) => { + let res: Option> = backend.folded_decl_provider() + .get_shallow_static_property_type(name.0.into(), name.0, name.1) + .unwrap(); + to_ocaml(&res) + } + BackendWrapper::PositionFree(backend) => { + let res: Option> = backend.folded_decl_provider() + .get_shallow_static_property_type(name.0.into(), name.0, name.1) + .unwrap(); + to_ocaml(&res) + } + } } - fn hh_rust_provider_backend_get_method<'a>( - arena: &'a Bump, - backend: UnsafeOcamlPtr, + fn hh_rust_provider_backend_get_method( + backend: Backend, name: (pos::TypeName, pos::MethodName), - ) -> Option> { - let backend = unsafe { get_backend(backend) }; - backend.shallow_decl_provider().get_method_type(name.0, name.1).unwrap() + ) -> UnsafeOcamlPtr { + match &*backend { + BackendWrapper::Positioned(backend) => { + let res: Option> = backend.folded_decl_provider() + .get_shallow_method_type(name.0.into(), name.0, name.1) + .unwrap(); + to_ocaml(&res) + } + BackendWrapper::PositionFree(backend) => { + let res: Option> = backend.folded_decl_provider() + .get_shallow_method_type(name.0.into(), name.0, name.1) + .unwrap(); + to_ocaml(&res) + } + } } - fn hh_rust_provider_backend_get_static_method<'a>( - arena: &'a Bump, - backend: UnsafeOcamlPtr, + fn hh_rust_provider_backend_get_static_method( + backend: Backend, name: (pos::TypeName, pos::MethodName), - ) -> Option> { - let backend = unsafe { get_backend(backend) }; - backend.shallow_decl_provider().get_static_method_type(name.0, name.1).unwrap() + ) -> UnsafeOcamlPtr { + match &*backend { + BackendWrapper::Positioned(backend) => { + let res: Option> = backend.folded_decl_provider() + .get_shallow_static_method_type(name.0.into(), name.0, name.1) + .unwrap(); + to_ocaml(&res) + } + BackendWrapper::PositionFree(backend) => { + let res: Option> = backend.folded_decl_provider() + .get_shallow_static_method_type(name.0.into(), name.0, name.1) + .unwrap(); + to_ocaml(&res) + } + } } - fn hh_rust_provider_backend_get_constructor<'a>( - arena: &'a Bump, - backend: UnsafeOcamlPtr, + fn hh_rust_provider_backend_get_constructor( + backend: Backend, name: pos::TypeName, - ) -> Option> { - let backend = unsafe { get_backend(backend) }; - backend.shallow_decl_provider().get_constructor_type(name).unwrap() + ) -> UnsafeOcamlPtr { + match &*backend { + BackendWrapper::Positioned(backend) => { + let res: Option> = backend.folded_decl_provider() + .get_shallow_constructor_type(name.into(), name) + .unwrap(); + to_ocaml(&res) + } + BackendWrapper::PositionFree(backend) => { + let res: Option> = backend.folded_decl_provider() + .get_shallow_constructor_type(name.into(), name) + .unwrap(); + to_ocaml(&res) + } + } } - fn hh_rust_provider_backend_get_folded_class<'a>( - arena: &'a Bump, - backend: UnsafeOcamlPtr, + fn hh_rust_provider_backend_get_folded_class( + backend: Backend, name: pos::TypeName, - ) -> Option>> { - let backend = unsafe { get_backend(backend) }; - backend.folded_decl_provider().get_class(name.into(), name).unwrap() + ) -> UnsafeOcamlPtr { + match &*backend { + BackendWrapper::Positioned(backend) => { + let res: Option>> = backend.folded_decl_provider() + .get_class(name.into(), name) + .unwrap(); + to_ocaml(&res) + } + BackendWrapper::PositionFree(backend) => { + let res: Option>> = backend.folded_decl_provider() + .get_class(name.into(), name) + .unwrap(); + to_ocaml(&res) + } + } } - fn hh_rust_provider_backend_declare_folded_class<'a>( - arena: &'a Bump, - backend: UnsafeOcamlPtr, + fn hh_rust_provider_backend_declare_folded_class( + backend: Backend, name: pos::TypeName, ) { - let backend = unsafe { get_backend(backend) }; - backend.folded_decl_provider().get_class(name.into(), name).unwrap(); + match &*backend { + BackendWrapper::Positioned(backend) => { backend.folded_decl_provider().get_class(name.into(), name).unwrap(); } + BackendWrapper::PositionFree(backend) => { backend.folded_decl_provider().get_class(name.into(), name).unwrap(); } + } } } -// UnsafeOcamlPtr is used because ocamlrep_custom::Custom cannot be used with -// ocaml_ffi_with_arena (it does not implement FromOcamlRepIn, and shouldn't, -// since arena-allocating a Custom would result in failing to decrement the -// inner Rc and leaking memory). -unsafe fn get_backend(ptr: UnsafeOcamlPtr) -> Backend { - Backend::from_ocamlrep(ptr.as_value()).unwrap() -} - // File_provider //////////////////////////////////////////////////////////// ocaml_ffi! { @@ -243,7 +419,16 @@ ocaml_ffi! { backend: Backend, path: RelativePath, ) -> Option { - backend.file_store().get(path).unwrap() + if let Some(backend) = backend.as_hh_server_backend() { + backend.file_store().get(path).unwrap() + } else { + // NB: This is semantically different than the above. We'll read + // from disk instead of returning None for files that aren't already + // present in our file store (i.e., the in-memory cache). We'll + // return Some("") instead of None for files that aren't present on + // disk. + Some(FileType::Disk(backend.file_provider().get(path).unwrap())) + } } fn hh_rust_provider_backend_file_provider_get_contents( @@ -258,7 +443,11 @@ ocaml_ffi! { path: RelativePath, contents: bstr::BString, ) { - backend.file_store().insert(path, FileType::Disk(contents)).unwrap(); + if let Some(backend) = backend.as_hh_server_backend() { + backend.file_store().insert(path, FileType::Disk(contents)).unwrap(); + } else { + unimplemented!("provide_file_for_tests: {UNIMPLEMENTED_MESSAGE}") + } } fn hh_rust_provider_backend_file_provider_provide_file_for_ide( @@ -266,7 +455,11 @@ ocaml_ffi! { path: RelativePath, contents: bstr::BString, ) { - backend.file_store().insert(path, FileType::Ide(contents)).unwrap(); + if let Some(backend) = backend.as_hh_server_backend() { + backend.file_store().insert(path, FileType::Ide(contents)).unwrap(); + } else { + unimplemented!("provide_file_for_ide: {UNIMPLEMENTED_MESSAGE}") + } } fn hh_rust_provider_backend_file_provider_provide_file_hint( @@ -274,8 +467,12 @@ ocaml_ffi! { path: RelativePath, file: FileType, ) { - if let FileType::Ide(_) = file { - backend.file_store().insert(path, file).unwrap(); + if let Some(backend) = backend.as_hh_server_backend() { + if let FileType::Ide(_) = file { + backend.file_store().insert(path, file).unwrap(); + } + } else { + unimplemented!("provide_file_hint: {UNIMPLEMENTED_MESSAGE}") } } @@ -283,7 +480,11 @@ ocaml_ffi! { backend: Backend, paths: BTreeSet, ) { - backend.file_store().remove_batch(&mut paths.into_iter()).unwrap(); + if let Some(backend) = backend.as_hh_server_backend() { + backend.file_store().remove_batch(&mut paths.into_iter()).unwrap(); + } else { + unimplemented!("file_provider_remove_batch: {UNIMPLEMENTED_MESSAGE}") + } } } @@ -295,28 +496,53 @@ ocaml_ffi! { name: pos::TypeName, pos: (file_info::Pos, naming_types::KindOfType), ) { - backend.naming_table().add_type(name, &pos).unwrap(); + if let Some(backend) = backend.as_hh_server_backend() { + backend.naming_table().add_type(name, &pos).unwrap(); + } else { + unimplemented!("naming_types_add: {UNIMPLEMENTED_MESSAGE}") + } } fn hh_rust_provider_backend_naming_types_get_pos( backend: Backend, name: pos::TypeName, ) -> Option<(file_info::Pos, naming_types::KindOfType)> { - backend.naming_table().get_type_pos(name).unwrap() + if let Some(backend) = backend.as_hh_server_backend() { + backend.naming_table().get_type_pos(name).unwrap() + } else { + backend.naming_provider() + .get_type_path_and_kind(name).unwrap() + .map(|(path, kind)| { + ( + file_info::Pos::File(kind.into(), RcOc::new(path.into())), + kind, + ) + }) + } } fn hh_rust_provider_backend_naming_types_remove_batch( backend: Backend, names: Vec, ) { - backend.naming_table().remove_type_batch(&names).unwrap(); + if let Some(backend) = backend.as_hh_server_backend() { + backend.naming_table().remove_type_batch(&names).unwrap(); + } else { + unimplemented!("naming_types_remove_batch: {UNIMPLEMENTED_MESSAGE}") + } } fn hh_rust_provider_backend_naming_types_get_canon_name( backend: Backend, name: pos::TypeName, ) -> Option { - backend.naming_table().get_canon_type_name(name).unwrap() + if let Some(backend) = backend.as_hh_server_backend() { + backend.naming_table().get_canon_type_name(name).unwrap() + } else { + // TODO: raise an exception or change NamingProvider to include + // canon methods; this implementation is incorrect + Some(name) + } } fn hh_rust_provider_backend_naming_funs_add( @@ -324,28 +550,48 @@ ocaml_ffi! { name: pos::FunName, pos: file_info::Pos, ) { - backend.naming_table().add_fun(name, &pos).unwrap(); + if let Some(backend) = backend.as_hh_server_backend() { + backend.naming_table().add_fun(name, &pos).unwrap(); + } else { + unimplemented!("naming_funs_add: {UNIMPLEMENTED_MESSAGE}") + } } fn hh_rust_provider_backend_naming_funs_get_pos( backend: Backend, name: pos::FunName, ) -> Option { - backend.naming_table().get_fun_pos(name).unwrap() + if let Some(backend) = backend.as_hh_server_backend() { + backend.naming_table().get_fun_pos(name).unwrap() + } else { + backend.naming_provider() + .get_fun_path(name).unwrap() + .map(|path| file_info::Pos::File(file_info::NameType::Fun, RcOc::new(path.into()))) + } } fn hh_rust_provider_backend_naming_funs_remove_batch( backend: Backend, names: Vec, ) { - backend.naming_table().remove_fun_batch(&names).unwrap(); + if let Some(backend) = backend.as_hh_server_backend() { + backend.naming_table().remove_fun_batch(&names).unwrap(); + } else { + unimplemented!("naming_funs_remove_batch: {UNIMPLEMENTED_MESSAGE}") + } } fn hh_rust_provider_backend_naming_funs_get_canon_name( backend: Backend, name: pos::FunName, ) -> Option { - backend.naming_table().get_canon_fun_name(name).unwrap() + if let Some(backend) = backend.as_hh_server_backend() { + backend.naming_table().get_canon_fun_name(name).unwrap() + } else { + // TODO: raise an exception or change NamingProvider to include + // canon methods; this implementation is incorrect + Some(name) + } } fn hh_rust_provider_backend_naming_consts_add( @@ -353,21 +599,35 @@ ocaml_ffi! { name: pos::ConstName, pos: file_info::Pos, ) { - backend.naming_table().add_const(name, &pos).unwrap(); + if let Some(backend) = backend.as_hh_server_backend() { + backend.naming_table().add_const(name, &pos).unwrap(); + } else { + unimplemented!("naming_consts_add: {UNIMPLEMENTED_MESSAGE}") + } } fn hh_rust_provider_backend_naming_consts_get_pos( backend: Backend, name: pos::ConstName, ) -> Option { - backend.naming_table().get_const_pos(name).unwrap() + if let Some(backend) = backend.as_hh_server_backend() { + backend.naming_table().get_const_pos(name).unwrap() + } else { + backend.naming_provider() + .get_const_path(name).unwrap() + .map(|path| file_info::Pos::File(file_info::NameType::Const, RcOc::new(path.into()))) + } } fn hh_rust_provider_backend_naming_consts_remove_batch( backend: Backend, names: Vec, ) { - backend.naming_table().remove_const_batch(&names).unwrap(); + if let Some(backend) = backend.as_hh_server_backend() { + backend.naming_table().remove_const_batch(&names).unwrap(); + } else { + unimplemented!("naming_consts_remove_batch: {UNIMPLEMENTED_MESSAGE}") + } } fn hh_rust_provider_backend_naming_modules_add( @@ -375,40 +635,66 @@ ocaml_ffi! { name: pos::ModuleName, pos: file_info::Pos, ) { - backend.naming_table().add_module(name, &pos).unwrap(); + if let Some(backend) = backend.as_hh_server_backend() { + backend.naming_table().add_module(name, &pos).unwrap(); + } else { + unimplemented!("naming_modules_add: {UNIMPLEMENTED_MESSAGE}") + } } fn hh_rust_provider_backend_naming_modules_get_pos( backend: Backend, name: pos::ModuleName, ) -> Option { - backend.naming_table().get_module_pos(name).unwrap() + if let Some(backend) = backend.as_hh_server_backend() { + backend.naming_table().get_module_pos(name).unwrap() + } else { + backend.naming_provider() + .get_module_path(name).unwrap() + .map(|path| file_info::Pos::File(file_info::NameType::Module, RcOc::new(path.into()))) + } } fn hh_rust_provider_backend_naming_modules_remove_batch( backend: Backend, names: Vec, ) { - backend.naming_table().remove_module_batch(&names).unwrap(); + if let Some(backend) = backend.as_hh_server_backend() { + backend.naming_table().remove_module_batch(&names).unwrap(); + } else { + unimplemented!("naming_modules_remove_batch: {UNIMPLEMENTED_MESSAGE}") + } } fn hh_rust_provider_backend_naming_get_db_path( backend: Backend, ) -> Option { - backend.naming_table().db_path() + if let Some(backend) = backend.as_hh_server_backend() { + backend.naming_table().db_path() + } else { + unimplemented!("naming_get_db_path: {UNIMPLEMENTED_MESSAGE}") + } } fn hh_rust_provider_backend_naming_set_db_path( backend: Backend, db_path: PathBuf, ) { - backend.naming_table().set_db_path(db_path).unwrap() + if let Some(backend) = backend.as_hh_server_backend() { + backend.naming_table().set_db_path(db_path).unwrap() + } else { + unimplemented!("naming_set_db_path: {UNIMPLEMENTED_MESSAGE}") + } } fn hh_rust_provider_backend_naming_get_filenames_by_hash( backend: Backend, deps: Custom, ) -> std::collections::BTreeSet { - backend.naming_table().get_filenames_by_hash(&deps).unwrap() + if let Some(backend) = backend.as_hh_server_backend() { + backend.naming_table().get_filenames_by_hash(&deps).unwrap() + } else { + unimplemented!("naming_get_filenames_by_hash: {UNIMPLEMENTED_MESSAGE}") + } } } -- 2.11.4.GIT