feat: let Shared: Send + Sync

This commit is contained in:
Shunsuke Shibayama 2023-05-27 20:41:28 +09:00
parent 4d9800716b
commit 0e42ab03ca
18 changed files with 197 additions and 174 deletions

9
Cargo.lock generated
View file

@ -117,10 +117,13 @@ dependencies = [
name = "erg_common" name = "erg_common"
version = "0.6.13" version = "0.6.13"
dependencies = [ dependencies = [
"backtrace",
"backtrace-on-stack-overflow", "backtrace-on-stack-overflow",
"crossterm", "crossterm",
"hermit-abi", "hermit-abi",
"libc", "libc",
"once_cell",
"parking_lot",
"winapi", "winapi",
] ]
@ -276,6 +279,12 @@ dependencies = [
"memchr", "memchr",
] ]
[[package]]
name = "once_cell"
version = "1.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
[[package]] [[package]]
name = "parking_lot" name = "parking_lot"
version = "0.12.1" version = "0.12.1"

View file

@ -4,11 +4,11 @@ use serde_json::Value;
use erg_common::config::{ErgConfig, Input}; use erg_common::config::{ErgConfig, Input};
use erg_common::dict::Dict; use erg_common::dict::Dict;
use erg_common::env::erg_pystd_path; use erg_common::env::ERG_PYSTD_PATH;
use erg_common::impl_u8_enum; use erg_common::impl_u8_enum;
use erg_common::python_util::BUILTIN_PYTHON_MODS; use erg_common::python_util::BUILTIN_PYTHON_MODS;
use erg_common::set::Set; use erg_common::set::Set;
use erg_common::shared::AtomicShared; use erg_common::shared::Shared;
use erg_common::traits::Locational; use erg_common::traits::Locational;
use erg_compiler::artifact::{BuildRunnable, Buildable}; use erg_compiler::artifact::{BuildRunnable, Buildable};
@ -174,7 +174,7 @@ impl<'b> CompletionOrderSetter<'b> {
} }
} }
type Cache = AtomicShared<Dict<String, Vec<CompletionItem>>>; type Cache = Shared<Dict<String, Vec<CompletionItem>>>;
#[derive(Debug)] #[derive(Debug)]
pub struct CompletionCache { pub struct CompletionCache {
@ -296,7 +296,7 @@ fn load_modules(cfg: ErgConfig, cache: Cache) {
if cache.get("<module>").is_none() { if cache.get("<module>").is_none() {
cache.insert("<module>".into(), module_completions()); cache.insert("<module>".into(), module_completions());
} }
let std_path = erg_pystd_path().display().to_string().replace('\\', "/"); let std_path = ERG_PYSTD_PATH.display().to_string().replace('\\', "/");
for (path, entry) in shared.py_mod_cache.iter() { for (path, entry) in shared.py_mod_cache.iter() {
let dir = entry.module.context.local_dir(); let dir = entry.module.context.local_dir();
let mod_name = path.display().to_string().replace('\\', "/"); let mod_name = path.display().to_string().replace('\\', "/");
@ -316,7 +316,7 @@ fn load_modules(cfg: ErgConfig, cache: Cache) {
impl CompletionCache { impl CompletionCache {
pub fn new(cfg: ErgConfig) -> Self { pub fn new(cfg: ErgConfig) -> Self {
let cache = AtomicShared::new(Dict::default()); let cache = Shared::new(Dict::default());
let clone = cache.clone(); let clone = cache.clone();
std::thread::spawn(move || { std::thread::spawn(move || {
crate::_log!("load_modules"); crate::_log!("load_modules");

View file

@ -12,7 +12,7 @@ use lsp_types::{
}; };
use erg_common::dict::Dict; use erg_common::dict::Dict;
use erg_common::shared::AtomicShared; use erg_common::shared::Shared;
use erg_common::traits::DequeStream; use erg_common::traits::DequeStream;
use erg_compiler::erg_parser::lex::Lexer; use erg_compiler::erg_parser::lex::Lexer;
use erg_compiler::erg_parser::token::{Token, TokenStream}; use erg_compiler::erg_parser::token::{Token, TokenStream};
@ -50,13 +50,13 @@ impl FileCacheEntry {
/// This struct can save changes in real-time & incrementally. /// This struct can save changes in real-time & incrementally.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct FileCache { pub struct FileCache {
pub files: AtomicShared<Dict<NormalizedUrl, FileCacheEntry>>, pub files: Shared<Dict<NormalizedUrl, FileCacheEntry>>,
} }
impl FileCache { impl FileCache {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
files: AtomicShared::new(Dict::new()), files: Shared::new(Dict::new()),
} }
} }

View file

@ -14,7 +14,7 @@ use serde_json::Value;
use erg_common::config::ErgConfig; use erg_common::config::ErgConfig;
use erg_common::dict::Dict; use erg_common::dict::Dict;
use erg_common::env::erg_path; use erg_common::env::ERG_PATH;
use erg_common::normalize_path; use erg_common::normalize_path;
use erg_compiler::artifact::{BuildRunnable, IncompleteArtifact}; use erg_compiler::artifact::{BuildRunnable, IncompleteArtifact};
@ -224,7 +224,7 @@ impl<Checker: BuildRunnable> Server<Checker> {
comp_cache: CompletionCache::new(cfg.copy()), comp_cache: CompletionCache::new(cfg.copy()),
cfg, cfg,
home: normalize_path(std::env::current_dir().unwrap_or_default()), home: normalize_path(std::env::current_dir().unwrap_or_default()),
erg_path: erg_path(), // already normalized erg_path: ERG_PATH.clone(), // already normalized
client_capas: ClientCapabilities::default(), client_capas: ClientCapabilities::default(),
disabled_features: vec![], disabled_features: vec![],
opt_features: vec![], opt_features: vec![],

View file

@ -33,7 +33,10 @@ version = "0.3"
features = ["consoleapi"] features = ["consoleapi"]
[dependencies] [dependencies]
backtrace = "0.3"
once_cell = "1.17"
crossterm = { optional = true, version = "0.25.0" } crossterm = { optional = true, version = "0.25.0" }
parking_lot = "0.12"
[lib] [lib]
path = "lib.rs" path = "lib.rs"

View file

@ -1,15 +1,15 @@
use std::borrow::{Borrow, ToOwned}; use std::borrow::{Borrow, ToOwned};
use std::cell::RefCell;
use std::hash::Hash; use std::hash::Hash;
use std::sync::Arc; use std::sync::Arc;
use std::thread::LocalKey; use std::thread::LocalKey;
use crate::dict::Dict; use crate::dict::Dict;
use crate::set::Set; use crate::set::Set;
use crate::shared::Shared;
use crate::{ArcArray, Str}; use crate::{ArcArray, Str};
#[derive(Debug)] #[derive(Debug)]
pub struct CacheSet<T: ?Sized>(RefCell<Set<Arc<T>>>); pub struct CacheSet<T: ?Sized>(Shared<Set<Arc<T>>>);
impl<T: ?Sized> Default for CacheSet<T> { impl<T: ?Sized> Default for CacheSet<T> {
fn default() -> Self { fn default() -> Self {
@ -19,7 +19,7 @@ impl<T: ?Sized> Default for CacheSet<T> {
impl<T: ?Sized> CacheSet<T> { impl<T: ?Sized> CacheSet<T> {
pub fn new() -> Self { pub fn new() -> Self {
Self(RefCell::new(Set::new())) Self(Shared::new(Set::new()))
} }
} }
@ -72,6 +72,6 @@ impl<T: Hash + Eq> CacheSet<T> {
} }
} }
pub struct CacheDict<K, V: ?Sized>(RefCell<Dict<K, Arc<V>>>); pub struct CacheDict<K, V: ?Sized>(Shared<Dict<K, Arc<V>>>);
pub struct GlobalCacheDict<K: 'static, V: ?Sized + 'static>(LocalKey<RefCell<CacheDict<K, V>>>); pub struct GlobalCacheDict<K: 'static, V: ?Sized + 'static>(LocalKey<Shared<CacheDict<K, V>>>);

View file

@ -11,7 +11,7 @@ use std::process;
use std::str::FromStr; use std::str::FromStr;
use crate::consts::ERG_MODE; use crate::consts::ERG_MODE;
use crate::env::{erg_py_external_lib_path, erg_pystd_path, erg_std_path, python_site_packages}; use crate::env::{ERG_EXTERNAL_LIB_PATH, ERG_PYSTD_PATH, ERG_STD_PATH, PYTHON_SITE_PACKAGES};
use crate::help_messages::{command_message, mode_message, OPTIONS}; use crate::help_messages::{command_message, mode_message, OPTIONS};
use crate::levenshtein::get_similar_name; use crate::levenshtein::get_similar_name;
use crate::pathutil::add_postfix_foreach; use crate::pathutil::add_postfix_foreach;
@ -581,12 +581,12 @@ impl Input {
pub fn resolve_real_path(&self, path: &Path) -> Option<PathBuf> { pub fn resolve_real_path(&self, path: &Path) -> Option<PathBuf> {
if let Ok(path) = self.resolve_local(path) { if let Ok(path) = self.resolve_local(path) {
Some(path) Some(path)
} else if let Ok(path) = erg_std_path() } else if let Ok(path) = ERG_STD_PATH
.join(format!("{}.er", path.display())) .join(format!("{}.er", path.display()))
.canonicalize() .canonicalize()
{ {
Some(normalize_path(path)) Some(normalize_path(path))
} else if let Ok(path) = erg_std_path() } else if let Ok(path) = ERG_STD_PATH
.join(format!("{}", path.display())) .join(format!("{}", path.display()))
.join("__init__.er") .join("__init__.er")
.canonicalize() .canonicalize()
@ -612,13 +612,12 @@ impl Input {
if let Ok(path) = self.resolve_local_decl(path) { if let Ok(path) = self.resolve_local_decl(path) {
Some(path) Some(path)
} else { } else {
let py_roots = [erg_pystd_path, erg_py_external_lib_path]; for root in [ERG_PYSTD_PATH.clone(), ERG_EXTERNAL_LIB_PATH.clone()] {
for root in py_roots { if let Some(path) = Self::resolve_std_decl_path(root, path) {
if let Some(path) = Self::resolve_std_decl_path(root(), path) {
return Some(path); return Some(path);
} }
} }
for site_packages in python_site_packages() { for site_packages in PYTHON_SITE_PACKAGES.clone() {
if let Some(path) = Self::resolve_site_pkgs_decl_path(site_packages, path) { if let Some(path) = Self::resolve_site_pkgs_decl_path(site_packages, path) {
return Some(path); return Some(path);
} }

View file

@ -1,6 +1,8 @@
use std::env::var; use std::env::var;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use once_cell::sync::Lazy;
use crate::normalize_path; use crate::normalize_path;
use crate::python_util::get_sys_path; use crate::python_util::get_sys_path;
use crate::style::colors::*; use crate::style::colors::*;
@ -66,43 +68,19 @@ fn _python_site_packages() -> impl Iterator<Item = PathBuf> {
}) })
} }
thread_local! { pub static ERG_PATH: Lazy<PathBuf> = Lazy::new(|| normalize_path(_erg_path()));
pub static ERG_PATH: PathBuf = normalize_path(_erg_path()); pub static ERG_STD_PATH: Lazy<PathBuf> = Lazy::new(|| normalize_path(_erg_std_path()));
pub static ERG_STD_PATH: PathBuf = normalize_path(_erg_std_path()); pub static ERG_STD_DECL_PATH: Lazy<PathBuf> = Lazy::new(|| normalize_path(_erg_std_decl_path()));
pub static ERG_STD_DECL_PATH: PathBuf = normalize_path(_erg_std_decl_path()); pub static ERG_PYSTD_PATH: Lazy<PathBuf> = Lazy::new(|| normalize_path(_erg_pystd_path()));
pub static ERG_PYSTD_PATH: PathBuf = normalize_path(_erg_pystd_path()); pub static ERG_EXTERNAL_LIB_PATH: Lazy<PathBuf> =
pub static ERG_EXTERNAL_LIB_PATH: PathBuf = normalize_path(_erg_external_lib_path()); Lazy::new(|| normalize_path(_erg_external_lib_path()));
pub static PYTHON_SITE_PACKAGES: Vec<PathBuf> = _python_site_packages().collect(); pub static PYTHON_SITE_PACKAGES: Lazy<Vec<PathBuf>> =
} Lazy::new(|| _python_site_packages().collect());
pub fn erg_path() -> PathBuf {
ERG_PATH.with(|s| s.clone())
}
pub fn erg_std_path() -> PathBuf {
ERG_STD_PATH.with(|s| s.clone())
}
pub fn erg_std_decl_path() -> PathBuf {
ERG_STD_DECL_PATH.with(|s| s.clone())
}
pub fn erg_pystd_path() -> PathBuf {
ERG_PYSTD_PATH.with(|s| s.clone())
}
pub fn erg_py_external_lib_path() -> PathBuf {
ERG_EXTERNAL_LIB_PATH.with(|s| s.clone())
}
pub fn python_site_packages() -> Vec<PathBuf> {
PYTHON_SITE_PACKAGES.with(|s| s.clone())
}
pub fn is_std_decl_path(path: &Path) -> bool { pub fn is_std_decl_path(path: &Path) -> bool {
path.starts_with(erg_pystd_path()) path.starts_with(ERG_PYSTD_PATH.as_path())
|| path.starts_with(erg_std_decl_path()) || path.starts_with(ERG_STD_DECL_PATH.as_path())
|| path.starts_with(erg_py_external_lib_path()) || path.starts_with(ERG_EXTERNAL_LIB_PATH.as_path())
} }
pub fn is_pystd_main_module(path: &Path) -> bool { pub fn is_pystd_main_module(path: &Path) -> bool {
@ -113,6 +91,6 @@ pub fn is_pystd_main_module(path: &Path) -> bool {
} else { } else {
path.pop(); path.pop();
} }
let pystd_path = erg_pystd_path(); // let pystd_path = erg_pystd_path();
path == pystd_path path == ERG_PYSTD_PATH.as_path()
} }

View file

@ -1,21 +1,17 @@
use crate::shared::Shared; use crate::shared::Shared;
thread_local! { use once_cell::sync::Lazy;
static VAR_ID: Shared<usize> = Shared::new(0);
} pub static VAR_ID: Lazy<Shared<usize>> = Lazy::new(|| Shared::new(0));
pub fn fresh_varname() -> String { pub fn fresh_varname() -> String {
VAR_ID.with(|id| { *VAR_ID.borrow_mut() += 1;
*id.borrow_mut() += 1; let i = *VAR_ID.borrow();
let i = *id.borrow(); format!("%v{i}")
format!("%v{i}")
})
} }
pub fn fresh_param_name() -> String { pub fn fresh_param_name() -> String {
VAR_ID.with(|id| { *VAR_ID.borrow_mut() += 1;
*id.borrow_mut() += 1; let i = *VAR_ID.borrow();
let i = *id.borrow(); format!("%p{i}")
format!("%p{i}")
})
} }

View file

@ -1,10 +1,13 @@
use std::cell::{Ref, RefCell, RefMut}; // use std::cell::{Ref, RefCell, RefMut};
use std::fmt; use std::fmt;
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use std::rc::Rc; // use std::rc::Rc;
use std::sync::{Arc, Mutex, MutexGuard}; pub use parking_lot::{
MappedRwLockReadGuard, MappedRwLockWriteGuard, RwLock, RwLockReadGuard, RwLockWriteGuard,
};
use std::sync::Arc;
#[derive(Debug)] /*#[derive(Debug)]
pub struct Shared<T: ?Sized>(Rc<RefCell<T>>); pub struct Shared<T: ?Sized>(Rc<RefCell<T>>);
impl<T: PartialEq> PartialEq for Shared<T> { impl<T: PartialEq> PartialEq for Shared<T> {
@ -108,14 +111,14 @@ impl<T: Clone> Shared<T> {
pub fn clone_inner(&self) -> T { pub fn clone_inner(&self) -> T {
self.borrow().clone() self.borrow().clone()
} }
} }*/
#[derive(Debug)] #[derive(Debug)]
pub struct AtomicShared<T: ?Sized>(Arc<Mutex<T>>); pub struct Shared<T: ?Sized>(Arc<RwLock<T>>);
impl<T: PartialEq> PartialEq for AtomicShared<T> impl<T: PartialEq> PartialEq for Shared<T>
where where
Mutex<T>: PartialEq, RwLock<T>: PartialEq,
{ {
#[inline] #[inline]
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
@ -123,35 +126,35 @@ where
} }
} }
impl<T: ?Sized> Clone for AtomicShared<T> { impl<T: ?Sized> Clone for Shared<T> {
fn clone(&self) -> AtomicShared<T> { fn clone(&self) -> Shared<T> {
Self(Arc::clone(&self.0)) Self(Arc::clone(&self.0))
} }
} }
impl<T: Eq> Eq for AtomicShared<T> where Mutex<T>: Eq {} impl<T: Eq> Eq for Shared<T> where RwLock<T>: Eq {}
impl<T: Hash> Hash for AtomicShared<T> { impl<T: Hash> Hash for Shared<T> {
fn hash<H: Hasher>(&self, state: &mut H) { fn hash<H: Hasher>(&self, state: &mut H) {
self.borrow_mut().hash(state); self.borrow_mut().hash(state);
} }
} }
impl<T: Default> Default for AtomicShared<T> { impl<T: Default> Default for Shared<T> {
fn default() -> Self { fn default() -> Self {
Self::new(Default::default()) Self::new(Default::default())
} }
} }
impl<T: fmt::Display> fmt::Display for AtomicShared<T> { impl<T: fmt::Display> fmt::Display for Shared<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.borrow_mut()) write!(f, "{}", self.borrow_mut())
} }
} }
impl<T> AtomicShared<T> { impl<T> Shared<T> {
pub fn new(t: T) -> Self { pub fn new(t: T) -> Self {
Self(Arc::new(Mutex::new(t))) Self(Arc::new(RwLock::new(t)))
} }
#[inline] #[inline]
@ -160,27 +163,56 @@ impl<T> AtomicShared<T> {
Ok(mutex) => mutex, Ok(mutex) => mutex,
Err(_rc) => panic!("unwrapping failed"), Err(_rc) => panic!("unwrapping failed"),
}; };
Mutex::into_inner(mutex).unwrap() RwLock::into_inner(mutex)
} }
} }
impl<T: ?Sized> AtomicShared<T> { impl<T: ?Sized> Shared<T> {
#[inline] #[inline]
pub fn copy(&self) -> Self { pub fn copy(&self) -> Self {
Self(self.0.clone()) Self(self.0.clone())
} }
#[inline] #[inline]
pub fn borrow_mut(&self) -> MutexGuard<'_, T> { pub fn borrow(&self) -> RwLockReadGuard<'_, T> {
self.0.lock().unwrap() println!("borrowing {}", std::any::type_name::<T>());
let res = self.0.read();
println!("borrowed successfully");
res
}
#[inline]
pub fn borrow_mut(&self) -> RwLockWriteGuard<'_, T> {
println!("borrowing mut {}", std::any::type_name::<T>());
let res = self.0.write();
println!("borrowed mut successfully");
res
} }
pub fn get_mut(&mut self) -> Option<&mut T> { pub fn get_mut(&mut self) -> Option<&mut T> {
Arc::get_mut(&mut self.0).map(|mutex| mutex.get_mut().unwrap()) Arc::get_mut(&mut self.0).map(|mutex| mutex.get_mut())
}
pub fn as_ptr(&self) -> *mut T {
Arc::as_ptr(&self.0) as *mut T
}
pub fn can_borrow(&self) -> bool {
self.0.try_read().is_some()
}
pub fn can_borrow_mut(&self) -> bool {
self.0.try_write().is_some()
}
/// # Safety
/// don't call this except you need to handle cyclic references.
pub unsafe fn force_unlock_write(&self) {
self.0.force_unlock_write();
} }
} }
impl<T: Clone> AtomicShared<T> { impl<T: Clone> Shared<T> {
#[inline] #[inline]
pub fn clone_inner(&self) -> T { pub fn clone_inner(&self) -> T {
self.borrow_mut().clone() self.borrow_mut().clone()

View file

@ -1,5 +1,5 @@
use std::cell::RefCell; // use std::cell::RefCell;
use std::thread::LocalKey; // use std::thread::LocalKey;
#[cfg(not(feature = "full-repl"))] #[cfg(not(feature = "full-repl"))]
use std::io::{stdin, BufRead, BufReader}; use std::io::{stdin, BufRead, BufReader};
@ -261,57 +261,52 @@ impl StdinReader {
} }
} }
thread_local! { static READER: crate::shared::RwLock<StdinReader> = crate::shared::RwLock::new(StdinReader {
static READER: RefCell<StdinReader> = RefCell::new(StdinReader{ block_begin: 1,
block_begin: 1, lineno: 1,
lineno: 1, buf: vec![],
buf: vec![], #[cfg(feature = "full-repl")]
#[cfg(feature = "full-repl")] history_input_position: 1,
history_input_position: 1, indent: 1,
indent: 1 });
});
}
#[derive(Debug)] #[derive(Debug)]
pub struct GlobalStdin(LocalKey<RefCell<StdinReader>>); pub struct GlobalStdin(&'static crate::shared::RwLock<StdinReader>);
pub static GLOBAL_STDIN: GlobalStdin = GlobalStdin(READER); pub static GLOBAL_STDIN: GlobalStdin = GlobalStdin(&READER);
impl GlobalStdin { impl GlobalStdin {
pub fn read(&'static self) -> String { pub fn read(&'static self) -> String {
self.0.with(|s| s.borrow_mut().read()) self.0.write().read()
} }
pub fn reread(&'static self) -> String { pub fn reread(&'static self) -> String {
self.0.with(|s| s.borrow().reread()) self.0.read().reread()
} }
pub fn reread_lines(&'static self, ln_begin: usize, ln_end: usize) -> Vec<String> { pub fn reread_lines(&'static self, ln_begin: usize, ln_end: usize) -> Vec<String> {
self.0 self.0.read().reread_lines(ln_begin, ln_end)
.with(|s| s.borrow_mut().reread_lines(ln_begin, ln_end))
} }
pub fn lineno(&'static self) -> usize { pub fn lineno(&'static self) -> usize {
self.0.with(|s| s.borrow().lineno) self.0.read().lineno
} }
pub fn block_begin(&'static self) -> usize { pub fn block_begin(&'static self) -> usize {
self.0.with(|s| s.borrow().block_begin) self.0.read().block_begin
} }
pub fn set_block_begin(&'static self, n: usize) { pub fn set_block_begin(&'static self, n: usize) {
self.0.with(|s| s.borrow_mut().block_begin = n); self.0.write().block_begin = n;
} }
pub fn set_indent(&'static self, n: usize) { pub fn set_indent(&'static self, n: usize) {
self.0.with(|s| s.borrow_mut().indent = n as u16); self.0.write().indent = n as u16;
} }
pub fn insert_whitespace(&'static self, whitespace: &str) { pub fn insert_whitespace(&'static self, whitespace: &str) {
self.0.with(|s| { if let Some(line) = self.0.write().last_line() {
if let Some(line) = s.borrow_mut().last_line() { line.insert_str(0, whitespace);
line.insert_str(0, whitespace); }
}
})
} }
} }

View file

@ -8,7 +8,7 @@ use crate::ty::codeobj::{CodeObj, CodeObjFlags, MakeFunctionFlags};
use crate::ty::value::GenTypeObj; use crate::ty::value::GenTypeObj;
use erg_common::cache::CacheSet; use erg_common::cache::CacheSet;
use erg_common::config::{ErgConfig, Input}; use erg_common::config::{ErgConfig, Input};
use erg_common::env::erg_std_path; use erg_common::env::ERG_STD_PATH;
use erg_common::error::{ErrorDisplay, Location}; use erg_common::error::{ErrorDisplay, Location};
use erg_common::opcode::{CommonOpcode, CompareOp}; use erg_common::opcode::{CommonOpcode, CompareOp};
use erg_common::opcode308::Opcode308; use erg_common::opcode308::Opcode308;
@ -3120,7 +3120,7 @@ impl PyCodeGenerator {
); );
self.emit_load_name_instr(Identifier::private("#path")); self.emit_load_name_instr(Identifier::private("#path"));
self.emit_load_method_instr(Identifier::public("append")); self.emit_load_method_instr(Identifier::public("append"));
self.emit_load_const(erg_std_path().to_str().unwrap()); self.emit_load_const(ERG_STD_PATH.to_str().unwrap());
self.emit_call_instr(1, Method); self.emit_call_instr(1, Method);
self.stack_dec(); self.stack_dec();
self.emit_pop_top(); self.emit_pop_top();

View file

@ -15,6 +15,7 @@ use std::path::PathBuf;
use erg_common::config::ErgConfig; use erg_common::config::ErgConfig;
use erg_common::consts::{DEBUG_MODE, ERG_MODE, PYTHON_MODE}; use erg_common::consts::{DEBUG_MODE, ERG_MODE, PYTHON_MODE};
use erg_common::dict; use erg_common::dict;
use erg_common::env::{ERG_PYSTD_PATH, ERG_STD_DECL_PATH};
use erg_common::error::Location; use erg_common::error::Location;
use erg_common::fresh::fresh_varname; use erg_common::fresh::fresh_varname;
#[allow(unused_imports)] #[allow(unused_imports)]
@ -513,11 +514,11 @@ const KW_OFFSET: &str = "offset";
const KW_WHENCE: &str = "whence"; const KW_WHENCE: &str = "whence";
pub fn builtins_path() -> PathBuf { pub fn builtins_path() -> PathBuf {
erg_common::env::erg_pystd_path().join("builtins.d.er") ERG_PYSTD_PATH.join("builtins.d.er")
} }
pub fn std_decl_path() -> PathBuf { pub fn std_decl_path() -> PathBuf {
erg_common::env::erg_std_decl_path() ERG_STD_DECL_PATH.clone()
} }
impl Context { impl Context {
@ -772,7 +773,8 @@ impl Context {
); );
self.consts.insert(name.clone(), val); self.consts.insert(name.clone(), val);
for impl_trait in ctx.super_traits.iter() { for impl_trait in ctx.super_traits.iter() {
if let Some(impls) = self.trait_impls().get_mut(&impl_trait.qual_name()) { if self.trait_impls().get(&impl_trait.qual_name()).is_some() {
let mut impls = self.trait_impls().get_mut(&impl_trait.qual_name());
impls.insert(TraitImpl::new(t.clone(), impl_trait.clone())); impls.insert(TraitImpl::new(t.clone(), impl_trait.clone()));
} else { } else {
self.trait_impls().register( self.trait_impls().register(
@ -848,7 +850,8 @@ impl Context {
} }
self.consts.insert(name.clone(), val); self.consts.insert(name.clone(), val);
for impl_trait in ctx.super_traits.iter() { for impl_trait in ctx.super_traits.iter() {
if let Some(impls) = self.trait_impls().get_mut(&impl_trait.qual_name()) { if self.trait_impls().get(&impl_trait.qual_name()).is_some() {
let mut impls = self.trait_impls().get_mut(&impl_trait.qual_name());
impls.insert(TraitImpl::new(t.clone(), impl_trait.clone())); impls.insert(TraitImpl::new(t.clone(), impl_trait.clone()));
} else { } else {
self.trait_impls().register( self.trait_impls().register(
@ -912,7 +915,12 @@ impl Context {
} }
} }
if let ContextKind::GluePatch(tr_impl) = &ctx.kind { if let ContextKind::GluePatch(tr_impl) = &ctx.kind {
if let Some(impls) = self.trait_impls().get_mut(&tr_impl.sup_trait.qual_name()) { if self
.trait_impls()
.get(&tr_impl.sup_trait.qual_name())
.is_some()
{
let mut impls = self.trait_impls().get_mut(&tr_impl.sup_trait.qual_name());
impls.insert(tr_impl.clone()); impls.insert(tr_impl.clone());
} else { } else {
self.trait_impls() self.trait_impls()

View file

@ -1653,7 +1653,8 @@ impl Context {
self.decls.insert(name.clone(), vi); self.decls.insert(name.clone(), vi);
self.consts.insert(name.clone(), val); self.consts.insert(name.clone(), val);
for impl_trait in ctx.super_traits.iter() { for impl_trait in ctx.super_traits.iter() {
if let Some(impls) = self.trait_impls().get_mut(&impl_trait.qual_name()) { if self.trait_impls().get(&impl_trait.qual_name()).is_some() {
let mut impls = self.trait_impls().get_mut(&impl_trait.qual_name());
impls.insert(TraitImpl::new(t.clone(), impl_trait.clone())); impls.insert(TraitImpl::new(t.clone(), impl_trait.clone()));
} else { } else {
self.trait_impls().register( self.trait_impls().register(
@ -1733,7 +1734,8 @@ impl Context {
self.consts self.consts
.insert(name.clone(), ValueObj::Type(TypeObj::Generated(gen))); .insert(name.clone(), ValueObj::Type(TypeObj::Generated(gen)));
for impl_trait in ctx.super_traits.iter() { for impl_trait in ctx.super_traits.iter() {
if let Some(impls) = self.trait_impls().get_mut(&impl_trait.qual_name()) { if self.trait_impls().get(&impl_trait.qual_name()).is_some() {
let mut impls = self.trait_impls().get_mut(&impl_trait.qual_name());
impls.insert(TraitImpl::new(t.clone(), impl_trait.clone())); impls.insert(TraitImpl::new(t.clone(), impl_trait.clone()));
} else { } else {
self.trait_impls().register( self.trait_impls().register(

View file

@ -1892,12 +1892,18 @@ impl ASTLowerer {
trait_loc: &impl Locational, trait_loc: &impl Locational,
) -> LowerResult<()> { ) -> LowerResult<()> {
// TODO: polymorphic trait // TODO: polymorphic trait
if let Some(impls) = self if self
.module .module
.context .context
.trait_impls() .trait_impls()
.get_mut(&trait_.qual_name()) .get(&trait_.qual_name())
.is_some()
{ {
let mut impls = self
.module
.context
.trait_impls()
.get_mut(&trait_.qual_name());
impls.insert(TraitImpl::new(class.clone(), trait_.clone())); impls.insert(TraitImpl::new(class.clone(), trait_.clone()));
} else { } else {
self.module.context.trait_impls().register( self.module.context.trait_impls().register(

View file

@ -2,7 +2,7 @@ use std::borrow::Borrow;
use std::fmt; use std::fmt;
use std::hash::Hash; use std::hash::Hash;
use std::path::PathBuf; use std::path::PathBuf;
use std::rc::Rc; use std::sync::Arc;
use erg_common::config::ErgConfig; use erg_common::config::ErgConfig;
use erg_common::dict::Dict; use erg_common::dict::Dict;
@ -32,7 +32,7 @@ impl ModId {
pub struct ModuleEntry { pub struct ModuleEntry {
pub id: ModId, // builtin == 0, __main__ == 1 pub id: ModId, // builtin == 0, __main__ == 1
pub hir: Option<HIR>, pub hir: Option<HIR>,
pub module: Rc<ModuleContext>, pub module: Arc<ModuleContext>,
} }
impl fmt::Display for ModuleEntry { impl fmt::Display for ModuleEntry {
@ -50,7 +50,7 @@ impl ModuleEntry {
Self { Self {
id, id,
hir, hir,
module: Rc::new(ctx), module: Arc::new(ctx),
} }
} }
@ -58,7 +58,7 @@ impl ModuleEntry {
Self { Self {
id: ModId::builtin(), id: ModId::builtin(),
hir: None, hir: None,
module: Rc::new(ctx), module: Arc::new(ctx),
} }
} }
@ -189,7 +189,7 @@ impl SharedModuleCache {
ref_.get_mut(path) ref_.get_mut(path)
} }
pub fn get_ctx<Q: Eq + Hash + ?Sized>(&self, path: &Q) -> Option<Rc<ModuleContext>> pub fn get_ctx<Q: Eq + Hash + ?Sized>(&self, path: &Q) -> Option<Arc<ModuleContext>>
where where
PathBuf: Borrow<Q>, PathBuf: Borrow<Q>,
{ {
@ -236,7 +236,7 @@ impl SharedModuleCache {
for path in self.keys() { for path in self.keys() {
self.remove(&path); self.remove(&path);
} }
self.register(builtin_path, None, Rc::try_unwrap(builtin.module).unwrap()); self.register(builtin_path, None, Arc::try_unwrap(builtin.module).unwrap());
} }
pub fn rename_path(&self, path: &PathBuf, new: PathBuf) { pub fn rename_path(&self, path: &PathBuf, new: PathBuf) {

View file

@ -4,7 +4,7 @@ use std::hash::Hash;
use erg_common::dict::Dict; use erg_common::dict::Dict;
use erg_common::set::Set; use erg_common::set::Set;
use erg_common::shared::Shared; use erg_common::shared::{MappedRwLockWriteGuard, RwLockWriteGuard, Shared};
use erg_common::Str; use erg_common::Str;
use crate::context::TraitImpl; use crate::context::TraitImpl;
@ -84,12 +84,13 @@ impl SharedTraitImpls {
ref_.get(path) ref_.get(path)
} }
pub fn get_mut<Q: Eq + Hash + ?Sized>(&self, path: &Q) -> Option<&mut Set<TraitImpl>> pub fn get_mut<Q: Eq + Hash + ?Sized>(&self, path: &Q) -> MappedRwLockWriteGuard<Set<TraitImpl>>
where where
Str: Borrow<Q>, Str: Borrow<Q>,
{ {
let ref_ = unsafe { self.0.as_ptr().as_mut().unwrap() }; // let ref_ = unsafe { self.0.as_ptr().as_mut().unwrap() };
ref_.get_mut(path) // ref_.get_mut(path)
RwLockWriteGuard::map(self.0.borrow_mut(), |tis| tis.get_mut(path).unwrap())
} }
pub fn register(&self, name: Str, impls: Set<TraitImpl>) { pub fn register(&self, name: Str, impls: Set<TraitImpl>) {

View file

@ -1,8 +1,9 @@
use std::cell::{Ref, RefMut}; // use std::cell::{Ref, RefMut};
use std::fmt; use std::fmt;
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use std::mem; use std::mem;
use erg_common::fresh::VAR_ID;
use erg_common::shared::Shared; use erg_common::shared::Shared;
use erg_common::traits::{LimitedDisplay, StructuralEq}; use erg_common::traits::{LimitedDisplay, StructuralEq};
use erg_common::Str; use erg_common::Str;
@ -17,10 +18,6 @@ pub type Id = usize;
/// HACK: see doc/compiler/inference.md for details /// HACK: see doc/compiler/inference.md for details
pub const GENERIC_LEVEL: usize = usize::MAX; pub const GENERIC_LEVEL: usize = usize::MAX;
thread_local! {
static UNBOUND_ID: Shared<usize> = Shared::new(0);
}
pub trait HasLevel { pub trait HasLevel {
fn level(&self) -> Option<Level>; fn level(&self) -> Option<Level>;
fn set_level(&self, lev: Level); fn set_level(&self, lev: Level);
@ -429,14 +426,12 @@ impl<T> FreeKind<T> {
} }
pub fn new_unbound(lev: Level, constraint: Constraint) -> Self { pub fn new_unbound(lev: Level, constraint: Constraint) -> Self {
UNBOUND_ID.with(|id| { *VAR_ID.borrow_mut() += 1;
*id.borrow_mut() += 1; Self::Unbound {
Self::Unbound { id: *VAR_ID.borrow(),
id: *id.borrow(), lev,
lev, constraint,
constraint, }
}
})
} }
pub const fn named_unbound(name: Str, lev: Level, constraint: Constraint) -> Self { pub const fn named_unbound(name: Str, lev: Level, constraint: Constraint) -> Self {
@ -601,10 +596,10 @@ impl<T: LimitedDisplay> LimitedDisplay for Free<T> {
} }
impl<T> Free<T> { impl<T> Free<T> {
pub fn borrow(&self) -> Ref<'_, FreeKind<T>> { pub fn borrow(&self) -> erg_common::shared::RwLockReadGuard<'_, FreeKind<T>> {
self.0.borrow() self.0.borrow()
} }
pub fn borrow_mut(&self) -> RefMut<'_, FreeKind<T>> { pub fn borrow_mut(&self) -> erg_common::shared::RwLockWriteGuard<'_, FreeKind<T>> {
self.0.borrow_mut() self.0.borrow_mut()
} }
/// very unsafe, use `force_replace` instead whenever possible /// very unsafe, use `force_replace` instead whenever possible
@ -620,8 +615,9 @@ impl<T> Free<T> {
return; return;
} }
unsafe { unsafe {
*self.0.as_ptr() = new; self.0.force_unlock_write();
} }
*self.0.borrow_mut() = new;
} }
pub fn can_borrow(&self) -> bool { pub fn can_borrow(&self) -> bool {
self.0.can_borrow() self.0.can_borrow()
@ -650,7 +646,7 @@ impl Free<TyParam> {
} }
} }
impl<T: StructuralEq + CanbeFree + Clone + Default> StructuralEq for Free<T> { impl<T: StructuralEq + CanbeFree + Clone + Default + fmt::Debug> StructuralEq for Free<T> {
fn structural_eq(&self, other: &Self) -> bool { fn structural_eq(&self, other: &Self) -> bool {
if let (Some((l, r)), Some((l2, r2))) = (self.get_subsup(), other.get_subsup()) { if let (Some((l, r)), Some((l2, r2))) = (self.get_subsup(), other.get_subsup()) {
self.dummy_link(); self.dummy_link();
@ -736,14 +732,12 @@ impl<T> Free<T> {
} }
pub fn new_unbound(level: Level, constraint: Constraint) -> Self { pub fn new_unbound(level: Level, constraint: Constraint) -> Self {
UNBOUND_ID.with(|id| { *VAR_ID.borrow_mut() += 1;
*id.borrow_mut() += 1; Self(Shared::new(FreeKind::unbound(
Self(Shared::new(FreeKind::unbound( *VAR_ID.borrow(),
*id.borrow(), level,
level, constraint,
constraint, )))
)))
})
} }
pub fn new_named_unbound(name: Str, level: Level, constraint: Constraint) -> Self { pub fn new_named_unbound(name: Str, level: Level, constraint: Constraint) -> Self {
@ -766,8 +760,8 @@ impl<T> Free<T> {
/// returns linked type (panic if self is unbounded) /// returns linked type (panic if self is unbounded)
/// NOTE: check by `.is_linked` before call /// NOTE: check by `.is_linked` before call
pub fn crack(&self) -> Ref<'_, T> { pub fn crack(&self) -> erg_common::shared::MappedRwLockReadGuard<'_, T> {
Ref::map(self.borrow(), |f| match f { erg_common::shared::RwLockReadGuard::map(self.borrow(), |f| match f {
FreeKind::Linked(t) | FreeKind::UndoableLinked { t, .. } => t, FreeKind::Linked(t) | FreeKind::UndoableLinked { t, .. } => t,
FreeKind::Unbound { .. } | FreeKind::NamedUnbound { .. } => { FreeKind::Unbound { .. } | FreeKind::NamedUnbound { .. } => {
panic!("the value is unbounded") panic!("the value is unbounded")
@ -775,8 +769,8 @@ impl<T> Free<T> {
}) })
} }
pub fn crack_constraint(&self) -> Ref<'_, Constraint> { pub fn crack_constraint(&self) -> erg_common::shared::MappedRwLockReadGuard<'_, Constraint> {
Ref::map(self.borrow(), |f| match f { erg_common::shared::RwLockReadGuard::map(self.borrow(), |f| match f {
FreeKind::Linked(_) | FreeKind::UndoableLinked { .. } => panic!("the value is linked"), FreeKind::Linked(_) | FreeKind::UndoableLinked { .. } => panic!("the value is linked"),
FreeKind::Unbound { constraint, .. } | FreeKind::NamedUnbound { constraint, .. } => { FreeKind::Unbound { constraint, .. } | FreeKind::NamedUnbound { constraint, .. } => {
constraint constraint
@ -814,7 +808,7 @@ impl<T> Free<T> {
} }
} }
impl<T: Clone> Free<T> { impl<T: Clone + fmt::Debug> Free<T> {
/// SAFETY: use `Type/TyParam::link` instead of this. /// SAFETY: use `Type/TyParam::link` instead of this.
/// This method may cause circular references. /// This method may cause circular references.
pub(super) fn link(&self, to: &T) { pub(super) fn link(&self, to: &T) {
@ -871,7 +865,7 @@ impl<T: Clone> Free<T> {
let prev = *previous.clone(); let prev = *previous.clone();
self.force_replace(prev); self.force_replace(prev);
} }
_other => panic!("cannot undo"), _other => panic!("cannot undo: {_other:?}"),
} }
} }
@ -920,7 +914,7 @@ impl<T: Clone> Free<T> {
} }
} }
impl<T: Default + Clone> Free<T> { impl<T: Default + Clone + fmt::Debug> Free<T> {
pub fn dummy_link(&self) { pub fn dummy_link(&self) {
self.forced_undoable_link(&T::default()); self.forced_undoable_link(&T::default());
} }