mirror of
https://github.com/erg-lang/erg.git
synced 2025-10-03 05:54:33 +00:00
Merge pull request #534 from erg-lang/perf-tyvar
Fix type-variable related bug
This commit is contained in:
commit
fdbfaec19a
9 changed files with 286 additions and 288 deletions
|
@ -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();
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue