Fix an Erg standard library loading bug

This commit is contained in:
Shunsuke Shibayama 2022-12-09 11:48:13 +09:00
parent a460b431a3
commit a395938413
7 changed files with 68 additions and 47 deletions

View file

@ -64,8 +64,8 @@ impl From<Str> for String {
impl<'a> From<Str> for Cow<'a, str> {
fn from(s: Str) -> Self {
match s {
Str::Static(s) => Cow::Owned(s.to_owned()),
_ => unreachable!(),
Str::Static(s) => Cow::Borrowed(s),
Str::Rc(s) => Cow::Owned(s.to_string()),
}
}
}

View file

@ -2,8 +2,8 @@
use std::option::Option; // conflicting to Type::Option
use std::path::{Path, PathBuf};
use erg_common::config::Input;
use erg_common::env::erg_pystd_path;
use erg_common::config::{ErgConfig, Input};
use erg_common::env::{erg_pystd_path, erg_std_path};
use erg_common::error::{ErrorCore, ErrorKind, Location, SubMessage};
use erg_common::levenshtein::get_similar_name;
use erg_common::set::Set;
@ -1736,7 +1736,7 @@ impl Context {
}
let type_name = namespaces.pop().unwrap(); // Response
let path = Path::new(namespaces.remove(0));
let mut path = self.resolve_path(path);
let mut path = Self::resolve_path(&self.cfg, path)?;
for p in namespaces.into_iter() {
path = self.push_path(path, Path::new(p));
}
@ -1766,7 +1766,7 @@ impl Context {
}
let type_name = namespaces.pop().unwrap(); // Response
let path = Path::new(namespaces.remove(0));
let mut path = self.resolve_path(path);
let mut path = Self::resolve_path(&self.cfg, path)?;
for p in namespaces.into_iter() {
path = self.push_path(path, Path::new(p));
}
@ -1925,23 +1925,45 @@ impl Context {
}
}
// TODO: erg std
pub(crate) fn resolve_path(&self, path: &Path) -> PathBuf {
if let Ok(path) = self.cfg.input.local_resolve(path) {
path
pub(crate) fn resolve_path(cfg: &ErgConfig, path: &Path) -> Option<PathBuf> {
Self::resolve_real_path(cfg, path).or_else(|| Self::resolve_d_path(cfg, path))
}
pub(crate) fn resolve_real_path(cfg: &ErgConfig, path: &Path) -> Option<PathBuf> {
if let Ok(path) = cfg.input.local_resolve(path) {
Some(path)
} else if let Ok(path) = erg_std_path()
.join(format!("{}.er", path.display()))
.canonicalize()
{
Some(path)
} else if let Ok(path) = erg_std_path()
.join(format!("{}", path.display()))
.join("__init__.er")
.canonicalize()
{
Some(path)
} else {
None
}
}
pub(crate) fn resolve_d_path(cfg: &ErgConfig, path: &Path) -> Option<PathBuf> {
if let Ok(path) = cfg.input.local_resolve(path) {
Some(path)
} else if let Ok(path) = erg_pystd_path()
.join(format!("{}.d.er", path.display()))
.canonicalize()
{
path
Some(path)
} else if let Ok(path) = erg_pystd_path()
.join(format!("{}.d", path.display()))
.join("__init__.d.er")
.canonicalize()
{
path
Some(path)
} else {
PathBuf::from(format!("<builtins>.{}", path.display()))
None
}
}
@ -1968,7 +1990,7 @@ impl Context {
if t.is_module() {
let path =
option_enum_unwrap!(t.typarams().remove(0), TyParam::Value:(ValueObj::Str:(_)))?;
let path = self.resolve_path(Path::new(&path[..]));
let path = Self::resolve_path(&self.cfg, Path::new(&path[..]))?;
self.mod_cache
.as_ref()
.and_then(|cache| cache.ref_ctx(&path))

View file

@ -1008,6 +1008,12 @@ impl Context {
self.params.retain(|(_, v)| v.t != Failure);
}
pub(crate) fn clear_all_vars(&mut self) {
self.locals.clear();
self.decls.clear();
self.params.retain(|(_, v)| v.t != Failure);
}
pub fn pop(&mut self) -> Context {
if let Some(parent) = self.outer.as_mut() {
let parent = mem::take(parent);

View file

@ -1168,22 +1168,18 @@ impl Context {
let __name__ = enum_unwrap!(mod_name.value.clone(), ValueObj::Str);
let mod_cache = self.mod_cache.as_ref().unwrap();
let py_mod_cache = self.py_mod_cache.as_ref().unwrap();
let path = match self.cfg.input.local_resolve(Path::new(&__name__[..])) {
Ok(path) => path,
Err(err) => {
let path = match Self::resolve_real_path(&self.cfg, Path::new(&__name__[..])) {
Some(path) => path,
None => {
let err = TyCheckErrors::from(TyCheckError::import_error(
self.cfg.input.clone(),
line!() as usize,
err.to_string(),
format!("module {__name__} not found"),
mod_name.loc(),
self.caused_by(),
self.mod_cache.as_ref().unwrap().get_similar_name(&__name__),
self.similar_builtin_py_mod_name(&__name__).or_else(|| {
self.py_mod_cache
.as_ref()
.unwrap()
.get_similar_name(&__name__)
}),
self.similar_builtin_py_mod_name(&__name__)
.or_else(|| py_mod_cache.get_similar_name(&__name__)),
));
return Err(err);
}
@ -1250,9 +1246,8 @@ impl Context {
let __name__ = enum_unwrap!(mod_name.value.clone(), ValueObj::Str);
let mod_cache = self.mod_cache.as_ref().unwrap();
let py_mod_cache = self.py_mod_cache.as_ref().unwrap();
let path = self.resolve_path(Path::new(&__name__[..]));
let path = match path.canonicalize() {
Ok(path) => {
let path = match Self::resolve_d_path(&self.cfg, Path::new(&__name__[..])) {
Some(path) => {
if self.is_pystd_main_module(path.as_path())
&& !BUILTIN_PYTHON_MODS.contains(&&__name__[..])
{
@ -1267,11 +1262,11 @@ impl Context {
}
path
}
Err(err) => {
None => {
let err = TyCheckError::import_error(
self.cfg.input.clone(),
line!() as usize,
err.to_string(),
format!("module {__name__} not found"),
mod_name.loc(),
self.caused_by(),
self.mod_cache.as_ref().unwrap().get_similar_name(&__name__),

View file

@ -8,14 +8,14 @@
.Version.
new major, minor, patch, pre := None =
.Version::__new__ { .major = major; .minor = minor; .patch = patch; .pre = pre }
#[
#[
greater self, other: .Version =
match [self.major > other.major, self.major >= other.major, self.minor > other.minor, self.minor >= other.minor, self.patch > other.patch]:
[True, _, _, _, _] -> True
[_, True, True, _, _] -> True
[_, True, _, True, True] -> True
_ -> False
]#
]#
.Version|.Version <: Eq|.
__eq__ self, other: .Version =
self.major == other.major and self.minor == other.minor and self.patch == other.patch and self.pre == other.pre

View file

@ -10,6 +10,7 @@ use erg_common::{enum_unwrap, log};
use erg_parser::ast::{DefId, OperationKind};
use erg_parser::token::{Token, TokenKind, DOT, EQUAL};
use crate::context::Context;
use crate::ty::typaram::TyParam;
use crate::ty::value::ValueObj;
use crate::ty::HasType;
@ -297,7 +298,7 @@ impl<'a> Linker<'a> {
let path =
enum_unwrap!(expr.ref_t().typarams().remove(0), TyParam::Value:(ValueObj::Str:(_)));
let path = Path::new(&path[..]);
let path = self.cfg.input.local_resolve(path).unwrap();
let path = Context::resolve_real_path(self.cfg, path).unwrap();
// In the case of REPL, entries cannot be used up
let hir = if self.cfg.input.is_repl() {
self.mod_cache

View file

@ -2051,6 +2051,15 @@ impl ASTLowerer {
HIR::new(ast.name, module)
}
fn return_incomplete_artifact(&mut self, hir: HIR) -> IncompleteArtifact {
self.ctx.clear_all_vars();
IncompleteArtifact::new(
Some(hir),
LowerErrors::from(self.errs.take_all()),
LowerWarnings::from(self.warns.take_all()),
)
}
pub fn lower(&mut self, ast: AST, mode: &str) -> Result<CompleteArtifact, IncompleteArtifact> {
log!(info "the AST lowering process has started.");
log!(info "the type-checking process has started.");
@ -2070,11 +2079,7 @@ impl ASTLowerer {
));
} else {
log!(err "the declaring process has failed.");
return Err(IncompleteArtifact::new(
Some(hir),
LowerErrors::from(self.errs.take_all()),
LowerWarnings::from(self.warns.take_all()),
));
return Err(self.return_incomplete_artifact(hir));
}
}
let mut module = hir::Module::with_capacity(ast.module.len());
@ -2105,11 +2110,7 @@ impl ASTLowerer {
Err((hir, errs)) => {
self.errs.extend(errs);
log!(err "the resolving process has failed. errs: {}", self.errs.len());
return Err(IncompleteArtifact::new(
Some(hir),
LowerErrors::from(self.errs.take_all()),
LowerWarnings::from(self.warns.take_all()),
));
return Err(self.return_incomplete_artifact(hir));
}
};
// TODO: recursive check
@ -2126,11 +2127,7 @@ impl ASTLowerer {
))
} else {
log!(err "the AST lowering process has failed. errs: {}", self.errs.len());
Err(IncompleteArtifact::new(
Some(hir),
LowerErrors::from(self.errs.take_all()),
LowerWarnings::from(self.warns.take_all()),
))
Err(self.return_incomplete_artifact(hir))
}
}
}