Merge pull request #534 from erg-lang/perf-tyvar

Fix type-variable related bug
This commit is contained in:
Shunsuke Shibayama 2024-11-09 17:37:09 +09:00 committed by GitHub
commit fdbfaec19a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 286 additions and 288 deletions

View file

@ -792,7 +792,7 @@ impl SubMessage {
cxt.to_string() cxt.to_string()
} }
Location::Unknown => match &e.input().kind { Location::Unknown => match &e.input().kind {
InputKind::File(_) => "\n".to_string(), InputKind::File { .. } => "\n".to_string(),
_other => { _other => {
let (_, vbar) = chars.gutters(); let (_, vbar) = chars.gutters();
let mut cxt = StyledStrings::default(); let mut cxt = StyledStrings::default();

View file

@ -13,6 +13,7 @@ use crate::env::{
use crate::pathutil::{add_postfix_foreach, remove_postfix}; use crate::pathutil::{add_postfix_foreach, remove_postfix};
use crate::random::random; use crate::random::random;
use crate::stdin::GLOBAL_STDIN; use crate::stdin::GLOBAL_STDIN;
use crate::traits::Immutable;
use crate::vfs::VFS; use crate::vfs::VFS;
use crate::{normalize_path, power_assert}; use crate::{normalize_path, power_assert};
@ -59,7 +60,10 @@ impl DummyStdin {
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum InputKind { pub enum InputKind {
File(PathBuf), File {
path: PathBuf,
project_root: Option<PathBuf>,
},
REPL, REPL,
// use Box to reduce the size // use Box to reduce the size
DummyREPL(Box<DummyStdin>), DummyREPL(Box<DummyStdin>),
@ -77,7 +81,7 @@ impl InputKind {
pub fn path(&self) -> &Path { pub fn path(&self) -> &Path {
match self { match self {
Self::File(filename) => filename.as_path(), Self::File { path, .. } => path.as_path(),
Self::REPL | Self::Pipe(_) => Path::new("<stdin>"), Self::REPL | Self::Pipe(_) => Path::new("<stdin>"),
Self::DummyREPL(_stdin) => Path::new("<stdin>"), Self::DummyREPL(_stdin) => Path::new("<stdin>"),
Self::Str(_) => Path::new("<string>"), Self::Str(_) => Path::new("<string>"),
@ -87,7 +91,7 @@ impl InputKind {
pub fn as_str(&self) -> &str { pub fn as_str(&self) -> &str {
match self { match self {
Self::File(filename) => filename.to_str().unwrap_or("_"), Self::File { path, .. } => path.to_str().unwrap_or("_"),
Self::REPL | Self::DummyREPL(_) | Self::Pipe(_) => "<stdin>", Self::REPL | Self::DummyREPL(_) | Self::Pipe(_) => "<stdin>",
Self::Str(_) => "<string>", Self::Str(_) => "<string>",
Self::Dummy => "<dummy>", Self::Dummy => "<dummy>",
@ -95,7 +99,7 @@ impl InputKind {
} }
pub fn dir(&self) -> PathBuf { pub fn dir(&self) -> PathBuf {
if let Self::File(path) = self { if let Self::File { path, .. } = self {
let mut path = path.clone(); let mut path = path.clone();
path.pop(); path.pop();
if path.ends_with("__pycache__") { if path.ends_with("__pycache__") {
@ -111,17 +115,10 @@ impl InputKind {
} }
} }
pub fn project_root(&self) -> Option<PathBuf> { pub fn project_root(&self) -> Option<&PathBuf> {
if let Self::File(path) = self { match self {
let mut parent = path.clone(); Self::File { project_root, .. } => project_root.as_ref(),
while parent.pop() { _ => None,
if parent.join("package.er").exists() {
return Some(parent);
}
}
None
} else {
None
} }
} }
} }
@ -147,13 +144,25 @@ impl From<&Path> for Input {
} }
} }
impl Immutable for Input {}
impl Input { impl Input {
pub const fn new(kind: InputKind, id: u64) -> Self { pub const fn new(kind: InputKind, id: u64) -> Self {
Self { kind, id } Self { kind, id }
} }
pub fn file(path: PathBuf) -> Self { pub fn file(path: PathBuf) -> Self {
Self::new(InputKind::File(path), random()) fn project_root(path: &Path) -> Option<PathBuf> {
let mut parent = path.to_path_buf();
while parent.pop() {
if parent.join("package.er").exists() {
return Some(parent);
}
}
None
}
let project_root = project_root(&path);
Self::new(InputKind::File { path, project_root }, random())
} }
pub fn pipe(src: String) -> Self { pub fn pipe(src: String) -> Self {
@ -188,7 +197,7 @@ impl Input {
self.kind.dir() self.kind.dir()
} }
pub fn project_root(&self) -> Option<PathBuf> { pub fn project_root(&self) -> Option<&PathBuf> {
self.kind.project_root() self.kind.project_root()
} }
@ -218,7 +227,7 @@ impl Input {
pub fn file_stem(&self) -> String { pub fn file_stem(&self) -> String {
match &self.kind { match &self.kind {
InputKind::File(filename) => filename InputKind::File { path, .. } => path
.file_stem() .file_stem()
.and_then(|f| f.to_str()) .and_then(|f| f.to_str())
.unwrap_or("_") .unwrap_or("_")
@ -233,14 +242,14 @@ impl Input {
pub fn full_path(&self) -> PathBuf { pub fn full_path(&self) -> PathBuf {
match &self.kind { match &self.kind {
InputKind::File(filename) => filename.clone(), InputKind::File { path, .. } => path.clone(),
_ => PathBuf::from(self.file_stem()), _ => PathBuf::from(self.file_stem()),
} }
} }
pub fn filename(&self) -> String { pub fn filename(&self) -> String {
match &self.kind { match &self.kind {
InputKind::File(filename) => filename InputKind::File { path, .. } => path
.file_name() .file_name()
.and_then(|f| f.to_str()) .and_then(|f| f.to_str())
.unwrap_or("_") .unwrap_or("_")
@ -257,13 +266,13 @@ impl Input {
pub fn module_name(&self) -> String { pub fn module_name(&self) -> String {
match &self.kind { match &self.kind {
InputKind::File(filename) => { InputKind::File { path, .. } => {
let file_stem = if filename.file_stem() == Some(OsStr::new("__init__")) let file_stem = if path.file_stem() == Some(OsStr::new("__init__"))
|| filename.file_stem() == Some(OsStr::new("__init__.d")) || path.file_stem() == Some(OsStr::new("__init__.d"))
{ {
filename.parent().and_then(|p| p.file_stem()) path.parent().and_then(|p| p.file_stem())
} else { } else {
filename.file_stem() path.file_stem()
}; };
file_stem file_stem
.and_then(|f| f.to_str()) .and_then(|f| f.to_str())
@ -280,13 +289,13 @@ impl Input {
pub fn read(&mut self) -> String { pub fn read(&mut self) -> String {
match &mut self.kind { match &mut self.kind {
InputKind::File(filename) => match VFS.read(filename.as_path()) { InputKind::File { path, .. } => match VFS.read(path.as_path()) {
Ok(s) => s, Ok(s) => s,
Err(e) => { Err(e) => {
let code = e.raw_os_error().unwrap_or(1); let code = e.raw_os_error().unwrap_or(1);
println!( println!(
"cannot read '{}': [Errno {code}] {e}", "cannot read '{}': [Errno {code}] {e}",
filename.to_string_lossy() path.to_string_lossy()
); );
process::exit(code); process::exit(code);
} }
@ -300,7 +309,7 @@ impl Input {
pub fn source_exists(&self) -> bool { pub fn source_exists(&self) -> bool {
match &self.kind { match &self.kind {
InputKind::File(filename) => filename.exists(), InputKind::File { path, .. } => path.exists(),
InputKind::Dummy => false, InputKind::Dummy => false,
_ => true, _ => true,
} }
@ -308,7 +317,7 @@ impl Input {
pub fn try_read(&mut self) -> std::io::Result<String> { pub fn try_read(&mut self) -> std::io::Result<String> {
match &mut self.kind { match &mut self.kind {
InputKind::File(filename) => VFS.read(filename), InputKind::File { path, .. } => VFS.read(path),
InputKind::Pipe(s) | InputKind::Str(s) => Ok(s.clone()), InputKind::Pipe(s) | InputKind::Str(s) => Ok(s.clone()),
InputKind::REPL => Ok(GLOBAL_STDIN.read()), InputKind::REPL => Ok(GLOBAL_STDIN.read()),
InputKind::DummyREPL(dummy) => Ok(dummy.read_line()), InputKind::DummyREPL(dummy) => Ok(dummy.read_line()),
@ -318,13 +327,13 @@ impl Input {
pub fn read_non_dummy(&self) -> String { pub fn read_non_dummy(&self) -> String {
match &self.kind { match &self.kind {
InputKind::File(filename) => match VFS.read(filename) { InputKind::File { path, .. } => match VFS.read(path) {
Ok(s) => s, Ok(s) => s,
Err(e) => { Err(e) => {
let code = e.raw_os_error().unwrap_or(1); let code = e.raw_os_error().unwrap_or(1);
println!( println!(
"cannot read '{}': [Errno {code}] {e}", "cannot read '{}': [Errno {code}] {e}",
filename.to_string_lossy() path.to_string_lossy()
); );
process::exit(code); process::exit(code);
} }
@ -338,7 +347,7 @@ impl Input {
pub fn reread_lines(&self, ln_begin: usize, ln_end: usize) -> Vec<String> { pub fn reread_lines(&self, ln_begin: usize, ln_end: usize) -> Vec<String> {
power_assert!(ln_begin, >=, 1); power_assert!(ln_begin, >=, 1);
match &self.kind { match &self.kind {
InputKind::File(filename) => match VFS.read(filename) { InputKind::File { path, .. } => match VFS.read(path) {
Ok(code) => { Ok(code) => {
let mut codes = vec![]; let mut codes = vec![];
let mut lines = code.lines().map(ToString::to_string).skip(ln_begin - 1); let mut lines = code.lines().map(ToString::to_string).skip(ln_begin - 1);
@ -368,7 +377,7 @@ impl Input {
pub fn reread(&self) -> String { pub fn reread(&self) -> String {
match &self.kind { match &self.kind {
InputKind::File(path) => VFS.read(path).unwrap(), InputKind::File { path, .. } => VFS.read(path).unwrap(),
InputKind::Pipe(s) | InputKind::Str(s) => s.clone(), InputKind::Pipe(s) | InputKind::Str(s) => s.clone(),
InputKind::REPL => GLOBAL_STDIN.reread().trim_end().to_owned(), InputKind::REPL => GLOBAL_STDIN.reread().trim_end().to_owned(),
InputKind::DummyREPL(dummy) => dummy.reread().unwrap_or_default(), InputKind::DummyREPL(dummy) => dummy.reread().unwrap_or_default(),
@ -410,12 +419,13 @@ impl Input {
path: &Path, path: &Path,
) -> Result<PathBuf, std::io::Error> { ) -> Result<PathBuf, std::io::Error> {
if path == Path::new("") { if path == Path::new("") {
let path = dir let result = dir
.join("__init__.d.er") .join("__init__.d.er")
.canonicalize() .canonicalize()
.or_else(|_| dir.join("__pycache__").join("__init__.d.er").canonicalize()) .or_else(|_| dir.join("__pycache__").join("__init__.d.er").canonicalize())
.or_else(|_| dir.canonicalize())?; .or_else(|_| dir.canonicalize())?;
return Ok(path); VFS.cache_path(self.clone(), path.to_path_buf(), Some(result.clone()));
return Ok(result);
} }
let mut comps = path.components(); let mut comps = path.components();
let last = comps let last = comps
@ -425,7 +435,7 @@ impl Input {
dir.push(comps); dir.push(comps);
dir.push(last_path); dir.push(last_path);
dir.set_extension("d.er"); // {path/to}.d.er dir.set_extension("d.er"); // {path/to}.d.er
let path = dir let result = dir
.canonicalize() .canonicalize()
.or_else(|_| { .or_else(|_| {
dir.pop(); // {path/to}.d.er -> {path} dir.pop(); // {path/to}.d.er -> {path}
@ -449,7 +459,9 @@ impl Input {
dir.push("__init__.d.er"); // -> {path/to}/__pycache__/__init__.d.er dir.push("__init__.d.er"); // -> {path/to}/__pycache__/__init__.d.er
dir.canonicalize() dir.canonicalize()
})?; })?;
Ok(normalize_path(path)) let result = normalize_path(result);
VFS.cache_path(self.clone(), path.to_path_buf(), Some(result.clone()));
Ok(result)
} }
fn resolve_local_py(&self, path: &Path) -> Result<PathBuf, std::io::Error> { fn resolve_local_py(&self, path: &Path) -> Result<PathBuf, std::io::Error> {
@ -466,21 +478,34 @@ impl Input {
} }
pub fn resolve_py(&self, path: &Path) -> Result<PathBuf, std::io::Error> { pub fn resolve_py(&self, path: &Path) -> Result<PathBuf, std::io::Error> {
if let Ok(path) = self.resolve_local_py(path) { if let Some(opt_path) = VFS.get_cached_path(self.clone(), path.to_path_buf()) {
return Ok(path); return opt_path.ok_or_else(|| {
std::io::Error::new(
std::io::ErrorKind::NotFound,
format!("cannot find module `{}`", path.display()),
)
});
}
if let Ok(resolved) = self.resolve_local_py(path) {
VFS.cache_path(self.clone(), path.to_path_buf(), Some(resolved.clone()));
return Ok(resolved);
} }
for sys_path in python_sys_path() { for sys_path in python_sys_path() {
let mut dir = sys_path.clone(); let mut dir = sys_path.clone();
dir.push(path); dir.push(path);
dir.set_extension("py"); dir.set_extension("py");
if dir.exists() { if dir.exists() {
return Ok(normalize_path(dir)); let resolved = normalize_path(dir);
VFS.cache_path(self.clone(), path.to_path_buf(), Some(resolved.clone()));
return Ok(resolved);
} }
dir.pop(); dir.pop();
dir.push(path); dir.push(path);
dir.push("__init__.py"); dir.push("__init__.py");
if dir.exists() { if dir.exists() {
return Ok(normalize_path(dir)); let resolved = normalize_path(dir);
VFS.cache_path(self.clone(), path.to_path_buf(), Some(resolved.clone()));
return Ok(resolved);
} }
if !EXPERIMENTAL_MODE { if !EXPERIMENTAL_MODE {
break; break;
@ -491,13 +516,17 @@ impl Input {
dir.push(path); dir.push(path);
dir.set_extension("py"); dir.set_extension("py");
if dir.exists() { if dir.exists() {
return Ok(normalize_path(dir)); let resolved = normalize_path(dir);
VFS.cache_path(self.clone(), path.to_path_buf(), Some(resolved.clone()));
return Ok(resolved);
} }
dir.pop(); dir.pop();
dir.push(path); dir.push(path);
dir.push("__init__.py"); dir.push("__init__.py");
if dir.exists() { if dir.exists() {
return Ok(normalize_path(dir)); let resolved = normalize_path(dir);
VFS.cache_path(self.clone(), path.to_path_buf(), Some(resolved.clone()));
return Ok(resolved);
} }
} }
Err(std::io::Error::new( Err(std::io::Error::new(
@ -518,21 +547,31 @@ impl Input {
/// 4. `std/{path/to}/__init__.er` /// 4. `std/{path/to}/__init__.er`
/// 5. `pkgs/{path/to}/src/lib.er` /// 5. `pkgs/{path/to}/src/lib.er`
pub fn resolve_real_path(&self, path: &Path, cfg: &ErgConfig) -> Option<PathBuf> { pub fn resolve_real_path(&self, path: &Path, cfg: &ErgConfig) -> Option<PathBuf> {
if let Ok(path) = self.resolve_local(path) { if let Some(opt_path) = VFS.get_cached_path(self.clone(), path.to_path_buf()) {
Some(path) return opt_path;
} else if let Ok(path) = erg_std_path() }
if let Ok(resolved) = self.resolve_local(path) {
VFS.cache_path(self.clone(), path.to_path_buf(), Some(resolved.clone()));
Some(resolved)
} else if let Ok(resolved) = erg_std_path()
.join(format!("{}.er", path.display())) .join(format!("{}.er", path.display()))
.canonicalize() .canonicalize()
{ {
Some(normalize_path(path)) let resolved = normalize_path(resolved);
} else if let Ok(path) = erg_std_path() VFS.cache_path(self.clone(), path.to_path_buf(), Some(resolved.clone()));
Some(resolved)
} else if let Ok(resolved) = erg_std_path()
.join(format!("{}", path.display())) .join(format!("{}", path.display()))
.join("__init__.er") .join("__init__.er")
.canonicalize() .canonicalize()
{ {
Some(normalize_path(path)) let resolved = normalize_path(resolved);
VFS.cache_path(self.clone(), path.to_path_buf(), Some(resolved.clone()));
Some(resolved)
} else if let Some(pkg) = self.resolve_project_dep_path(path, cfg, false) { } else if let Some(pkg) = self.resolve_project_dep_path(path, cfg, false) {
Some(normalize_path(pkg)) let resolved = normalize_path(pkg);
VFS.cache_path(self.clone(), path.to_path_buf(), Some(resolved.clone()));
Some(resolved)
} else if path == Path::new("unsound") { } else if path == Path::new("unsound") {
Some(PathBuf::from("unsound")) Some(PathBuf::from("unsound"))
} else { } else {
@ -597,8 +636,12 @@ impl Input {
/// 10. `site-packages/{path}/__pycache__/{to}.d.er` /// 10. `site-packages/{path}/__pycache__/{to}.d.er`
/// 11. `site-packages/{path/to}/__pycache__/__init__.d.er` /// 11. `site-packages/{path/to}/__pycache__/__init__.d.er`
pub fn resolve_decl_path(&self, path: &Path, cfg: &ErgConfig) -> Option<PathBuf> { pub fn resolve_decl_path(&self, path: &Path, cfg: &ErgConfig) -> Option<PathBuf> {
if let Ok(path) = self.resolve_local_decl(self.dir(), path) { if let Some(opt_path) = VFS.get_cached_path(self.clone(), path.to_path_buf()) {
return Some(path); return opt_path;
}
if let Ok(resolved) = self.resolve_local_decl(self.dir(), path) {
VFS.cache_path(self.clone(), path.to_path_buf(), Some(resolved.clone()));
return Some(resolved);
} }
// e.g. // e.g.
// root: lib/external/pandas.d, path: pandas/core/frame // root: lib/external/pandas.d, path: pandas/core/frame
@ -609,28 +652,34 @@ impl Input {
// -> NO // -> NO
if let Some((root, first)) = self.project_root().zip(path.components().next()) { if let Some((root, first)) = self.project_root().zip(path.components().next()) {
if root.ends_with(first) || remove_postfix(root.clone(), ".d").ends_with(first) { if root.ends_with(first) || remove_postfix(root.clone(), ".d").ends_with(first) {
let path = path.iter().skip(1).collect::<PathBuf>(); let path_buf = path.iter().skip(1).collect::<PathBuf>();
if let Ok(path) = self.resolve_local_decl(root, &path) { if let Ok(resolved) = self.resolve_local_decl(root.clone(), &path_buf) {
return Some(path); VFS.cache_path(self.clone(), path.to_path_buf(), Some(resolved.clone()));
return Some(resolved);
} }
} }
} }
if let Some(path) = Self::resolve_std_decl_path(erg_pystd_path(), path) { if let Some(resolved) = Self::resolve_std_decl_path(erg_pystd_path(), path) {
return Some(path); VFS.cache_path(self.clone(), path.to_path_buf(), Some(resolved.clone()));
return Some(resolved);
} }
if let Some(pkg) = self.resolve_project_dep_path(path, cfg, true) { if let Some(pkg) = self.resolve_project_dep_path(path, cfg, true) {
return Some(normalize_path(pkg)); let resolved = normalize_path(pkg);
VFS.cache_path(self.clone(), path.to_path_buf(), Some(resolved.clone()));
return Some(resolved);
} }
for site_packages in python_site_packages() { for site_packages in python_site_packages() {
if let Some(path) = Self::resolve_site_pkgs_decl_path(site_packages, path) { if let Some(resolved) = Self::resolve_site_pkgs_decl_path(site_packages, path) {
return Some(path); VFS.cache_path(self.clone(), path.to_path_buf(), Some(resolved.clone()));
return Some(resolved);
} }
} }
if PYTHON_MODE { if PYTHON_MODE {
if let Ok(path) = self.resolve_py(path) { if let Ok(resolved) = self.resolve_py(path) {
return Some(path); return Some(resolved);
} }
} }
VFS.cache_path(self.clone(), path.to_path_buf(), None);
None None
} }

View file

@ -762,7 +762,7 @@ pub trait Runnable: Sized + Default + New {
let mut num_errors = 0; let mut num_errors = 0;
let mut instance = Self::new(cfg); let mut instance = Self::new(cfg);
let res = match &instance.input().kind { let res = match &instance.input().kind {
InputKind::File(_) | InputKind::Pipe(_) | InputKind::Str(_) => instance.exec(), InputKind::File { .. } | InputKind::Pipe(_) | InputKind::Str(_) => instance.exec(),
InputKind::REPL | InputKind::DummyREPL(_) => { InputKind::REPL | InputKind::DummyREPL(_) => {
let output = stdout(); let output = stdout();
let mut output = BufWriter::new(output.lock()); let mut output = BufWriter::new(output.lock());

View file

@ -1,7 +1,8 @@
use std::path::Path; use std::path::{Path, PathBuf};
use std::sync::OnceLock; use std::sync::OnceLock;
use crate::dict::Dict; use crate::dict::Dict;
use crate::io::Input;
use crate::pathutil::NormalizedPathBuf; use crate::pathutil::NormalizedPathBuf;
use crate::shared::Shared; use crate::shared::Shared;
@ -10,12 +11,14 @@ use crate::shared::Shared;
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct VirtualFileSystem { pub struct VirtualFileSystem {
cache: Shared<Dict<NormalizedPathBuf, String>>, cache: Shared<Dict<NormalizedPathBuf, String>>,
path_cache: Shared<Dict<(Input, PathBuf), Option<PathBuf>>>,
} }
impl VirtualFileSystem { impl VirtualFileSystem {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
cache: Shared::new(Dict::new()), cache: Shared::new(Dict::new()),
path_cache: Shared::new(Dict::new()),
} }
} }
@ -24,6 +27,14 @@ impl VirtualFileSystem {
self.cache.borrow_mut().insert(path, contents); self.cache.borrow_mut().insert(path, contents);
} }
pub fn cache_path(&self, input: Input, path: PathBuf, result: Option<PathBuf>) {
self.path_cache.borrow_mut().insert((input, path), result);
}
pub fn get_cached_path(&self, input: Input, path: PathBuf) -> Option<Option<PathBuf>> {
self.path_cache.borrow().get(&(input, path)).cloned()
}
pub fn remove(&self, path: impl AsRef<Path>) { pub fn remove(&self, path: impl AsRef<Path>) {
let path = NormalizedPathBuf::from(path.as_ref()); let path = NormalizedPathBuf::from(path.as_ref());
self.cache.borrow_mut().remove(&path); self.cache.borrow_mut().remove(&path);
@ -69,6 +80,18 @@ impl SharedVFS {
pub fn remove(&self, path: impl AsRef<Path>) { pub fn remove(&self, path: impl AsRef<Path>) {
self.0.get_or_init(VirtualFileSystem::new).remove(path) self.0.get_or_init(VirtualFileSystem::new).remove(path)
} }
pub fn cache_path(&self, input: Input, path: PathBuf, result: Option<PathBuf>) {
self.0
.get_or_init(VirtualFileSystem::new)
.cache_path(input, path, result)
}
pub fn get_cached_path(&self, input: Input, path: PathBuf) -> Option<Option<PathBuf>> {
self.0
.get_or_init(VirtualFileSystem::new)
.get_cached_path(input, path)
}
} }
pub static VFS: SharedVFS = SharedVFS(OnceLock::new()); pub static VFS: SharedVFS = SharedVFS(OnceLock::new());

View file

@ -177,6 +177,9 @@ impl<'c> Substituter<'c> {
qt: &Type, qt: &Type,
st: &Type, st: &Type,
) -> EvalResult<Option<Self>> { ) -> EvalResult<Option<Self>> {
if qt == st {
return Ok(None);
}
let mut qtps = qt.typarams(); let mut qtps = qt.typarams();
let mut stps = st.typarams(); let mut stps = st.typarams();
// Or, And are commutative, choose fitting order // Or, And are commutative, choose fitting order
@ -251,6 +254,9 @@ impl<'c> Substituter<'c> {
qt: &Type, qt: &Type,
st: &Type, st: &Type,
) -> EvalResult<Option<Self>> { ) -> EvalResult<Option<Self>> {
if qt == st {
return Ok(None);
}
let mut qtps = qt.typarams(); let mut qtps = qt.typarams();
let mut stps = st.typarams(); let mut stps = st.typarams();
if qt.qual_name() == st.qual_name() { if qt.qual_name() == st.qual_name() {

View file

@ -93,7 +93,7 @@ impl Context {
inst.lift(); inst.lift();
let quantified_again = self.generalize_t(inst); let quantified_again = self.generalize_t(inst);
println!("quantified_again: {quantified_again}"); println!("quantified_again: {quantified_again}");
assert_eq!(quantified, quantified_again); assert!(quantified.structural_eq(&quantified_again));
Ok(()) Ok(())
} }

View file

@ -269,6 +269,7 @@ impl Constraint {
pub trait CanbeFree { pub trait CanbeFree {
fn unbound_name(&self) -> Option<Str>; fn unbound_name(&self) -> Option<Str>;
fn unbound_id(&self) -> Option<usize>;
fn constraint(&self) -> Option<Constraint>; fn constraint(&self) -> Option<Constraint>;
fn destructive_update_constraint(&self, constraint: Constraint, in_instantiation: bool); fn destructive_update_constraint(&self, constraint: Constraint, in_instantiation: bool);
} }
@ -278,6 +279,10 @@ impl<T: CanbeFree + Send + Clone> Free<T> {
self.borrow().unbound_name() self.borrow().unbound_name()
} }
pub fn unbound_id(&self) -> Option<usize> {
self.borrow().unbound_id()
}
pub fn constraint(&self) -> Option<Constraint> { pub fn constraint(&self) -> Option<Constraint> {
self.borrow().constraint() self.borrow().constraint()
} }
@ -298,6 +303,7 @@ pub enum FreeKind<T> {
}, },
NamedUnbound { NamedUnbound {
name: Str, name: Str,
id: Id,
lev: Level, lev: Level,
constraint: Constraint, constraint: Constraint,
}, },
@ -307,23 +313,8 @@ impl<T: Hash> Hash for FreeKind<T> {
fn hash<H: Hasher>(&self, state: &mut H) { fn hash<H: Hasher>(&self, state: &mut H) {
match self { match self {
Self::Linked(t) | Self::UndoableLinked { t, .. } => t.hash(state), Self::Linked(t) | Self::UndoableLinked { t, .. } => t.hash(state),
Self::Unbound { Self::Unbound { id, .. } | Self::NamedUnbound { id, .. } => {
id,
lev,
constraint,
} => {
id.hash(state); id.hash(state);
lev.hash(state);
constraint.hash(state);
}
Self::NamedUnbound {
name,
lev,
constraint,
} => {
name.hash(state);
lev.hash(state);
constraint.hash(state);
} }
} }
} }
@ -336,30 +327,10 @@ impl<T: PartialEq> PartialEq for FreeKind<T> {
Self::Linked(t1) | Self::UndoableLinked { t: t1, .. }, Self::Linked(t1) | Self::UndoableLinked { t: t1, .. },
Self::Linked(t2) | Self::UndoableLinked { t: t2, .. }, Self::Linked(t2) | Self::UndoableLinked { t: t2, .. },
) => t1 == t2, ) => t1 == t2,
( (Self::Unbound { id: id1, .. }, Self::Unbound { id: id2, .. })
Self::Unbound { | (Self::NamedUnbound { id: id1, .. }, Self::NamedUnbound { id: id2, .. }) => {
id: id1, id1 == id2
lev: lev1, }
constraint: c1,
},
Self::Unbound {
id: id2,
lev: lev2,
constraint: c2,
},
) => id1 == id2 && lev1 == lev2 && c1 == c2,
(
Self::NamedUnbound {
name: n1,
lev: l1,
constraint: c1,
},
Self::NamedUnbound {
name: n2,
lev: l2,
constraint: c2,
},
) => n1 == n2 && l1 == l2 && c1 == c2,
_ => false, _ => false,
} }
} }
@ -374,6 +345,13 @@ impl<T: CanbeFree> FreeKind<T> {
} }
} }
pub fn unbound_id(&self) -> Option<usize> {
match self {
FreeKind::NamedUnbound { id, .. } | FreeKind::Unbound { id, .. } => Some(*id),
FreeKind::Linked(t) | FreeKind::UndoableLinked { t, .. } => t.unbound_id(),
}
}
pub fn constraint(&self) -> Option<Constraint> { pub fn constraint(&self) -> Option<Constraint> {
match self { match self {
FreeKind::Unbound { constraint, .. } | FreeKind::NamedUnbound { constraint, .. } => { FreeKind::Unbound { constraint, .. } | FreeKind::NamedUnbound { constraint, .. } => {
@ -407,6 +385,7 @@ impl<T: LimitedDisplay> LimitedDisplay for FreeKind<T> {
} }
Self::NamedUnbound { Self::NamedUnbound {
name, name,
id: _,
lev, lev,
constraint, constraint,
} => { } => {
@ -473,9 +452,10 @@ impl<T> FreeKind<T> {
} }
} }
pub const fn named_unbound(name: Str, lev: Level, constraint: Constraint) -> Self { pub const fn named_unbound(name: Str, id: usize, lev: Level, constraint: Constraint) -> Self {
Self::NamedUnbound { Self::NamedUnbound {
name, name,
id,
lev, lev,
constraint, constraint,
} }
@ -563,19 +543,8 @@ pub struct Free<T: Send + Clone>(Forkable<FreeKind<T>>);
impl Hash for Free<Type> { impl Hash for Free<Type> {
fn hash<H: Hasher>(&self, state: &mut H) { fn hash<H: Hasher>(&self, state: &mut H) {
if let Some(name) = self.unbound_name() { if let Some(id) = self.unbound_id() {
name.hash(state); id.hash(state);
}
if let Some(lev) = self.level() {
lev.hash(state);
}
if let Some((sub, sup)) = self.get_subsup() {
self.do_avoiding_recursion(|| {
sub.hash(state);
sup.hash(state);
});
} else if let Some(t) = self.get_type() {
t.hash(state);
} else if self.is_linked() { } else if self.is_linked() {
let cracked = self.crack(); let cracked = self.crack();
if !Type::FreeVar(self.clone()).addr_eq(&cracked) { if !Type::FreeVar(self.clone()).addr_eq(&cracked) {
@ -589,14 +558,8 @@ impl Hash for Free<Type> {
impl Hash for Free<TyParam> { impl Hash for Free<TyParam> {
fn hash<H: Hasher>(&self, state: &mut H) { fn hash<H: Hasher>(&self, state: &mut H) {
if let Some(name) = self.unbound_name() { if let Some(id) = self.unbound_id() {
name.hash(state); id.hash(state);
}
if let Some(lev) = self.level() {
lev.hash(state);
}
if let Some(t) = self.get_type() {
t.hash(state);
} else if self.is_linked() { } else if self.is_linked() {
self.crack().hash(state); self.crack().hash(state);
} }
@ -617,38 +580,9 @@ impl PartialEq for Free<Type> {
} else { } else {
other other
}; };
if let Some(self_name) = this.unbound_name() { if let Some(self_id) = this.unbound_id() {
if let Some(other_name) = other.unbound_name() { if let Some(other_id) = other.unbound_id() {
if self_name != other_name { self_id == other_id
return false;
}
} else {
return false;
}
}
if let Some(self_lev) = this.level() {
if let Some(other_lev) = other.level() {
if self_lev != other_lev {
return false;
}
} else {
return false;
}
}
if let Some((sub, sup)) = this.get_subsup() {
if let Some((other_sub, other_sup)) = other.get_subsup() {
this.dummy_link();
other.dummy_link();
let res = sub == other_sub && sup == other_sup;
this.undo();
other.undo();
res
} else {
false
}
} else if let Some(self_t) = this.get_type() {
if let Some(other_t) = other.get_type() {
self_t == other_t
} else { } else {
false false
} }
@ -659,8 +593,7 @@ impl PartialEq for Free<Type> {
false false
} }
} else { } else {
// name, level, constraint are equal false
true
} }
} }
} }
@ -679,27 +612,9 @@ impl PartialEq for Free<TyParam> {
} else { } else {
other other
}; };
if let Some(self_name) = this.unbound_name() { if let Some(self_id) = this.unbound_id() {
if let Some(other_name) = other.unbound_name() { if let Some(other_id) = other.unbound_id() {
if self_name != other_name { self_id == other_id
return false;
}
} else {
return false;
}
}
if let Some(self_lev) = this.level() {
if let Some(other_lev) = other.level() {
if self_lev != other_lev {
return false;
}
} else {
return false;
}
}
if let Some(self_t) = this.get_type() {
if let Some(other_t) = other.get_type() {
self_t == other_t
} else { } else {
false false
} }
@ -710,8 +625,7 @@ impl PartialEq for Free<TyParam> {
false false
} }
} else { } else {
// name, level, constraint are equal false
true
} }
} }
} }
@ -827,24 +741,26 @@ impl Free<Type> {
}) { }) {
return; return;
} }
match &mut *self.borrow_mut() { if let Some(linked) = self.get_linked() {
FreeKind::Unbound { linked.destructive_update_constraint(new_constraint, in_inst_or_gen);
lev, constraint, .. } else {
} match &mut *self.borrow_mut() {
| FreeKind::NamedUnbound { FreeKind::Unbound {
lev, constraint, .. lev, constraint, ..
} => {
if !in_inst_or_gen && *lev == GENERIC_LEVEL {
log!(err "cannot update the constraint of a generalized type variable");
return;
} }
if addr_eq!(*constraint, new_constraint) { | FreeKind::NamedUnbound {
return; lev, constraint, ..
} => {
if !in_inst_or_gen && *lev == GENERIC_LEVEL {
log!(err "cannot update the constraint of a generalized type variable");
return;
}
if addr_eq!(*constraint, new_constraint) {
return;
}
*constraint = new_constraint;
} }
*constraint = new_constraint; FreeKind::Linked(_) | FreeKind::UndoableLinked { .. } => unreachable!(),
}
FreeKind::Linked(t) | FreeKind::UndoableLinked { t, .. } => {
t.destructive_update_constraint(new_constraint, in_inst_or_gen);
} }
} }
} }
@ -1018,17 +934,17 @@ impl<T: Send + Clone> Free<T> {
} }
pub fn new_unbound(level: Level, constraint: Constraint) -> Self { pub fn new_unbound(level: Level, constraint: Constraint) -> Self {
UNBOUND_ID.fetch_add(1, std::sync::atomic::Ordering::SeqCst); let id = UNBOUND_ID.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
Self(Forkable::new(FreeKind::unbound( Self(Forkable::new(FreeKind::unbound(id + 1, level, constraint)))
UNBOUND_ID.load(std::sync::atomic::Ordering::SeqCst),
level,
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 {
let id = UNBOUND_ID.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
Self(Forkable::new(FreeKind::named_unbound( Self(Forkable::new(FreeKind::named_unbound(
name, level, constraint, name,
id + 1,
level,
constraint,
))) )))
} }
@ -1163,6 +1079,7 @@ impl<T: Clone + Send + Sync + 'static> Free<T> {
} => (None, lev, constraint), } => (None, lev, constraint),
FreeKind::NamedUnbound { FreeKind::NamedUnbound {
name, name,
id: _,
lev, lev,
constraint, constraint,
} => (Some(name), lev, constraint), } => (Some(name), lev, constraint),
@ -1310,24 +1227,26 @@ impl Free<TyParam> {
if new_constraint.get_type() == Some(&Type::Never) { if new_constraint.get_type() == Some(&Type::Never) {
panic!("{new_constraint}"); panic!("{new_constraint}");
} }
match &mut *self.borrow_mut() { if let Some(linked) = self.get_linked() {
FreeKind::Unbound { linked.destructive_update_constraint(new_constraint, in_inst_or_gen);
lev, constraint, .. } else {
} match &mut *self.borrow_mut() {
| FreeKind::NamedUnbound { FreeKind::Unbound {
lev, constraint, .. lev, constraint, ..
} => {
if !in_inst_or_gen && *lev == GENERIC_LEVEL {
log!(err "cannot update the constraint of a generalized type variable");
return;
} }
if addr_eq!(*constraint, new_constraint) { | FreeKind::NamedUnbound {
return; lev, constraint, ..
} => {
if !in_inst_or_gen && *lev == GENERIC_LEVEL {
log!(err "cannot update the constraint of a generalized type variable");
return;
}
if addr_eq!(*constraint, new_constraint) {
return;
}
*constraint = new_constraint;
} }
*constraint = new_constraint; FreeKind::Linked(_) | FreeKind::UndoableLinked { .. } => unreachable!(),
}
FreeKind::Linked(t) | FreeKind::UndoableLinked { t, .. } => {
t.destructive_update_constraint(new_constraint, in_inst_or_gen);
} }
} }
} }
@ -1362,6 +1281,7 @@ mod tests {
let u = named_free_var("T".into(), 1, constraint); let u = named_free_var("T".into(), 1, constraint);
println!("{t} {u}"); println!("{t} {u}");
assert_eq!(t, t); assert_eq!(t, t);
assert_eq!(t, u); assert_ne!(t, u);
assert!(t.structural_eq(&u));
} }
} }

View file

@ -212,8 +212,8 @@ macro_rules! impl_t_for_enum {
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct SharedFrees { pub struct SharedFrees {
tvs: Shared<Dict<Str, Type>>, tvs: Shared<Dict<usize, Type>>,
tps: Shared<Dict<Str, TyParam>>, tps: Shared<Dict<usize, TyParam>>,
} }
impl SharedFrees { impl SharedFrees {
@ -224,20 +224,20 @@ impl SharedFrees {
} }
} }
pub fn get_tv(&self, name: &str) -> Option<Type> { pub fn get_tv(&self, id: usize) -> Option<Type> {
self.tvs.borrow().get(name).cloned() self.tvs.borrow().get(&id).cloned()
} }
pub fn get_tp(&self, name: &str) -> Option<TyParam> { pub fn get_tp(&self, id: usize) -> Option<TyParam> {
self.tps.borrow().get(name).cloned() self.tps.borrow().get(&id).cloned()
} }
pub fn insert_tv(&self, name: Str, t: Type) { pub fn insert_tv(&self, id: usize, t: Type) {
self.tvs.borrow_mut().insert(name, t); self.tvs.borrow_mut().insert(id, t);
} }
pub fn insert_tp(&self, name: Str, tp: TyParam) { pub fn insert_tp(&self, id: usize, tp: TyParam) {
self.tps.borrow_mut().insert(name, tp); self.tps.borrow_mut().insert(id, tp);
} }
} }
@ -1783,6 +1783,14 @@ impl CanbeFree for Type {
} }
} }
fn unbound_id(&self) -> Option<usize> {
if let Some(fv) = self.as_free() {
fv.unbound_id()
} else {
None
}
}
fn constraint(&self) -> Option<Constraint> { fn constraint(&self) -> Option<Constraint> {
if let Some(fv) = self.as_free() { if let Some(fv) = self.as_free() {
fv.constraint() fv.constraint()
@ -4431,19 +4439,6 @@ impl Type {
} }
} }
pub(crate) fn eliminate_and_or_recursion(self, target: &Type) -> Self {
match self {
Self::And(tys, idx) => Self::checked_and(
tys.into_iter().filter(|t| !t.addr_eq(target)).collect(),
idx,
),
Self::Or(tys) => {
Self::checked_or(tys.into_iter().filter(|t| !t.addr_eq(target)).collect())
}
_ => self,
}
}
pub fn replace(self, target: &Type, to: &Type) -> Type { pub fn replace(self, target: &Type, to: &Type) -> Type {
let table = ReplaceTable::make(target, to); let table = ReplaceTable::make(target, to);
table.replace(self) table.replace(self)
@ -4525,8 +4520,8 @@ impl Type {
match self { match self {
Self::FreeVar(fv) if fv.is_linked() => fv.unwrap_linked().map(f, tvs), Self::FreeVar(fv) if fv.is_linked() => fv.unwrap_linked().map(f, tvs),
Self::FreeVar(fv) => { Self::FreeVar(fv) => {
if let Some(name) = fv.unbound_name() { if let Some(id) = fv.unbound_id() {
if let Some(tv) = tvs.get_tv(&name) { if let Some(tv) = tvs.get_tv(id) {
return tv; return tv;
} }
} }
@ -4539,8 +4534,8 @@ impl Type {
let fv_clone = fv.deep_clone(); let fv_clone = fv.deep_clone();
fv_clone fv_clone
.update_constraint(Constraint::new_sandwiched(new_sub, new_sup), true); .update_constraint(Constraint::new_sandwiched(new_sub, new_sup), true);
if let Some(name) = fv.unbound_name() { if let Some(id) = fv.unbound_id() {
tvs.insert_tv(name, Self::FreeVar(fv_clone.clone())); tvs.insert_tv(id, Self::FreeVar(fv_clone.clone()));
} }
Self::FreeVar(fv_clone) Self::FreeVar(fv_clone)
} else { } else {
@ -4551,8 +4546,8 @@ impl Type {
if new_ty != ty { if new_ty != ty {
let fv_clone = fv.deep_clone(); let fv_clone = fv.deep_clone();
fv_clone.update_constraint(Constraint::new_type_of(new_ty), true); fv_clone.update_constraint(Constraint::new_type_of(new_ty), true);
if let Some(name) = fv.unbound_name() { if let Some(id) = fv.unbound_id() {
tvs.insert_tv(name, Self::FreeVar(fv_clone.clone())); tvs.insert_tv(id, Self::FreeVar(fv_clone.clone()));
} }
Self::FreeVar(fv_clone) Self::FreeVar(fv_clone)
} else { } else {
@ -4638,8 +4633,8 @@ impl Type {
match self { match self {
Self::FreeVar(fv) if fv.is_linked() => fv.unwrap_linked()._replace_tp(target, to, tvs), Self::FreeVar(fv) if fv.is_linked() => fv.unwrap_linked()._replace_tp(target, to, tvs),
Self::FreeVar(fv) => { Self::FreeVar(fv) => {
if let Some(name) = fv.unbound_name() { if let Some(id) = fv.unbound_id() {
if let Some(tv) = tvs.get_tv(&name) { if let Some(tv) = tvs.get_tv(id) {
return tv; return tv;
} }
} }
@ -4652,8 +4647,8 @@ impl Type {
let fv_clone = fv.deep_clone(); let fv_clone = fv.deep_clone();
fv_clone fv_clone
.update_constraint(Constraint::new_sandwiched(new_sub, new_sup), true); .update_constraint(Constraint::new_sandwiched(new_sub, new_sup), true);
if let Some(name) = fv.unbound_name() { if let Some(id) = fv.unbound_id() {
tvs.insert_tv(name, Self::FreeVar(fv_clone.clone())); tvs.insert_tv(id, Self::FreeVar(fv_clone.clone()));
} }
Self::FreeVar(fv_clone) Self::FreeVar(fv_clone)
} else { } else {
@ -4664,8 +4659,8 @@ impl Type {
if new_ty != ty { if new_ty != ty {
let fv_clone = fv.deep_clone(); let fv_clone = fv.deep_clone();
fv_clone.update_constraint(Constraint::new_type_of(new_ty), true); fv_clone.update_constraint(Constraint::new_type_of(new_ty), true);
if let Some(name) = fv.unbound_name() { if let Some(id) = fv.unbound_id() {
tvs.insert_tv(name, Self::FreeVar(fv_clone.clone())); tvs.insert_tv(id, Self::FreeVar(fv_clone.clone()));
} }
Self::FreeVar(fv_clone) Self::FreeVar(fv_clone)
} else { } else {
@ -4756,8 +4751,8 @@ impl Type {
match self { match self {
Self::FreeVar(fv) if fv.is_linked() => fv.unwrap_linked().map_tp(f, tvs), Self::FreeVar(fv) if fv.is_linked() => fv.unwrap_linked().map_tp(f, tvs),
Self::FreeVar(fv) => { Self::FreeVar(fv) => {
if let Some(name) = fv.unbound_name() { if let Some(id) = fv.unbound_id() {
if let Some(tv) = tvs.get_tv(&name) { if let Some(tv) = tvs.get_tv(id) {
return tv; return tv;
} }
} }
@ -4770,8 +4765,8 @@ impl Type {
let fv_clone = fv.deep_clone(); let fv_clone = fv.deep_clone();
fv_clone fv_clone
.update_constraint(Constraint::new_sandwiched(new_sub, new_sup), true); .update_constraint(Constraint::new_sandwiched(new_sub, new_sup), true);
if let Some(name) = fv.unbound_name() { if let Some(id) = fv.unbound_id() {
tvs.insert_tv(name, Self::FreeVar(fv_clone.clone())); tvs.insert_tv(id, Self::FreeVar(fv_clone.clone()));
} }
Self::FreeVar(fv_clone) Self::FreeVar(fv_clone)
} else { } else {
@ -4782,8 +4777,8 @@ impl Type {
if new_ty != ty { if new_ty != ty {
let fv_clone = fv.deep_clone(); let fv_clone = fv.deep_clone();
fv_clone.update_constraint(Constraint::new_type_of(new_ty), true); fv_clone.update_constraint(Constraint::new_type_of(new_ty), true);
if let Some(name) = fv.unbound_name() { if let Some(id) = fv.unbound_id() {
tvs.insert_tv(name, Self::FreeVar(fv_clone.clone())); tvs.insert_tv(id, Self::FreeVar(fv_clone.clone()));
} }
Self::FreeVar(fv_clone) Self::FreeVar(fv_clone)
} else { } else {
@ -4862,8 +4857,8 @@ impl Type {
match self { match self {
Self::FreeVar(fv) if fv.is_linked() => fv.unwrap_linked().try_map_tp(f, tvs), Self::FreeVar(fv) if fv.is_linked() => fv.unwrap_linked().try_map_tp(f, tvs),
Self::FreeVar(fv) => { Self::FreeVar(fv) => {
if let Some(name) = fv.unbound_name() { if let Some(id) = fv.unbound_id() {
if let Some(tv) = tvs.get_tv(&name) { if let Some(tv) = tvs.get_tv(id) {
return Ok(tv); return Ok(tv);
} }
} }
@ -4876,8 +4871,8 @@ impl Type {
let fv_clone = fv.deep_clone(); let fv_clone = fv.deep_clone();
fv_clone fv_clone
.update_constraint(Constraint::new_sandwiched(new_sub, new_sup), true); .update_constraint(Constraint::new_sandwiched(new_sub, new_sup), true);
if let Some(name) = fv.unbound_name() { if let Some(id) = fv.unbound_id() {
tvs.insert_tv(name, Self::FreeVar(fv_clone.clone())); tvs.insert_tv(id, Self::FreeVar(fv_clone.clone()));
} }
Ok(Self::FreeVar(fv_clone)) Ok(Self::FreeVar(fv_clone))
} else { } else {
@ -4888,8 +4883,8 @@ impl Type {
if new_ty != ty { if new_ty != ty {
let fv_clone = fv.deep_clone(); let fv_clone = fv.deep_clone();
fv_clone.update_constraint(Constraint::new_type_of(new_ty), true); fv_clone.update_constraint(Constraint::new_type_of(new_ty), true);
if let Some(name) = fv.unbound_name() { if let Some(id) = fv.unbound_id() {
tvs.insert_tv(name, Self::FreeVar(fv_clone.clone())); tvs.insert_tv(id, Self::FreeVar(fv_clone.clone()));
} }
Ok(Self::FreeVar(fv_clone)) Ok(Self::FreeVar(fv_clone))
} else { } else {
@ -5215,11 +5210,7 @@ impl Type {
} }
match self { match self {
Self::FreeVar(fv) => { Self::FreeVar(fv) => {
// NOTE: we can't use `eliminate_recursion` let to_ = to.clone().eliminate_subsup(self).eliminate_recursion(self);
let to_ = to
.clone()
.eliminate_subsup(self)
.eliminate_and_or_recursion(self);
if self.addr_eq(&to_) { if self.addr_eq(&to_) {
self.inc_undo_count(); self.inc_undo_count();
} else { } else {

View file

@ -547,6 +547,15 @@ impl CanbeFree for TyParam {
} }
} }
fn unbound_id(&self) -> Option<usize> {
match self {
TyParam::FreeVar(fv) => fv.unbound_id(),
TyParam::Type(t) => t.unbound_id(),
TyParam::Value(ValueObj::Type(ty)) => ty.typ().unbound_id(),
_ => None,
}
}
fn constraint(&self) -> Option<Constraint> { fn constraint(&self) -> Option<Constraint> {
match self { match self {
TyParam::FreeVar(fv) => fv.constraint(), TyParam::FreeVar(fv) => fv.constraint(),
@ -1567,8 +1576,8 @@ impl TyParam {
match self { match self {
Self::FreeVar(fv) if fv.is_linked() => fv.unwrap_linked().replace_t(target, to, tvs), Self::FreeVar(fv) if fv.is_linked() => fv.unwrap_linked().replace_t(target, to, tvs),
Self::FreeVar(fv) if fv.get_type().is_some() => { Self::FreeVar(fv) if fv.get_type().is_some() => {
let name = fv.unbound_name().unwrap(); let id = fv.unbound_id().unwrap();
if let Some(tp) = tvs.get_tp(&name) { if let Some(tp) = tvs.get_tp(id) {
return tp; return tp;
} }
let typ = fv.get_type().unwrap(); let typ = fv.get_type().unwrap();
@ -1576,7 +1585,7 @@ impl TyParam {
if new_typ != typ { if new_typ != typ {
let fv_clone = fv.deep_clone(); let fv_clone = fv.deep_clone();
fv_clone.update_type(new_typ); fv_clone.update_type(new_typ);
tvs.insert_tp(name, Self::FreeVar(fv_clone.clone())); tvs.insert_tp(id, Self::FreeVar(fv_clone.clone()));
Self::FreeVar(fv_clone) Self::FreeVar(fv_clone)
} else { } else {
Self::FreeVar(fv) Self::FreeVar(fv)
@ -1926,8 +1935,8 @@ impl TyParam {
match self { match self {
TyParam::FreeVar(fv) if fv.is_linked() => f(fv.unwrap_linked()), TyParam::FreeVar(fv) if fv.is_linked() => f(fv.unwrap_linked()),
TyParam::FreeVar(fv) if fv.get_type().is_some() => { TyParam::FreeVar(fv) if fv.get_type().is_some() => {
if let Some(name) = fv.unbound_name() { if let Some(id) = fv.unbound_id() {
if let Some(tp) = tvs.get_tp(&name) { if let Some(tp) = tvs.get_tp(id) {
return tp; return tp;
} }
} }
@ -1936,8 +1945,8 @@ impl TyParam {
if typ != new_typ { if typ != new_typ {
let fv_clone = fv.deep_clone(); let fv_clone = fv.deep_clone();
fv_clone.update_type(new_typ); fv_clone.update_type(new_typ);
if let Some(name) = fv_clone.unbound_name() { if let Some(id) = fv_clone.unbound_id() {
tvs.insert_tp(name, TyParam::FreeVar(fv_clone.clone())); tvs.insert_tp(id, TyParam::FreeVar(fv_clone.clone()));
} }
TyParam::FreeVar(fv_clone) TyParam::FreeVar(fv_clone)
} else { } else {
@ -2001,8 +2010,8 @@ impl TyParam {
match self { match self {
TyParam::FreeVar(fv) if fv.is_linked() => fv.unwrap_linked().map_t(f, tvs), TyParam::FreeVar(fv) if fv.is_linked() => fv.unwrap_linked().map_t(f, tvs),
TyParam::FreeVar(fv) if fv.get_type().is_some() => { TyParam::FreeVar(fv) if fv.get_type().is_some() => {
if let Some(name) = fv.unbound_name() { if let Some(id) = fv.unbound_id() {
if let Some(tp) = tvs.get_tp(&name) { if let Some(tp) = tvs.get_tp(id) {
return tp; return tp;
} }
} }
@ -2011,8 +2020,8 @@ impl TyParam {
if typ != new_typ { if typ != new_typ {
let fv_clone = fv.deep_clone(); let fv_clone = fv.deep_clone();
fv_clone.update_type(new_typ); fv_clone.update_type(new_typ);
if let Some(name) = fv_clone.unbound_name() { if let Some(id) = fv_clone.unbound_id() {
tvs.insert_tp(name, TyParam::FreeVar(fv_clone.clone())); tvs.insert_tp(id, TyParam::FreeVar(fv_clone.clone()));
} }
TyParam::FreeVar(fv_clone) TyParam::FreeVar(fv_clone)
} else { } else {