fix: path resolution bug

This commit is contained in:
Shunsuke Shibayama 2023-05-21 23:26:50 +09:00
parent 829b0d11b6
commit ac7a57a094
5 changed files with 62 additions and 49 deletions

View file

@ -441,16 +441,16 @@ impl Input {
} }
/// resolution order: /// resolution order:
/// 1. `{path}.er` /// 1. `{path/to}.er`
/// 2. `{path}/__init__.er` /// 2. `{path/to}/__init__.er`
fn resolve_local(&self, path: &Path) -> Result<PathBuf, std::io::Error> { fn resolve_local(&self, path: &Path) -> Result<PathBuf, std::io::Error> {
let mut dir = self.dir(); let mut dir = self.dir();
dir.push(path); dir.push(path);
dir.set_extension("er"); // {path}.er dir.set_extension("er"); // {path/to}.er
let path = dir.canonicalize().or_else(|_| { let path = dir.canonicalize().or_else(|_| {
dir.pop(); dir.pop(); // {path}
dir.push(path); dir.push(path.iter().last().unwrap_or_default()); // {path/to}
dir.push("__init__.er"); // -> {path}/__init__.er dir.push("__init__.er"); // -> {path/to}/__init__.er
dir.canonicalize() dir.canonicalize()
})?; })?;
Ok(normalize_path(path)) Ok(normalize_path(path))
@ -464,10 +464,10 @@ impl Input {
} }
/// resolution order: /// resolution order:
/// 1. `{path}.d.er` /// 1. `{path/to}.d.er`
/// 2. `{path}/__init__.d.er` /// 2. `{path/to}/__init__.d.er`
/// 3. `__pycache__/{path}.d.er` /// 3. `{path}/__pycache__/{to}.d.er`
/// 4. `{path}/__pycache__/__init__.d.er` /// 4. `{path/to}/__pycache__/__init__.d.er`
fn _resolve_local_decl(&self, path: &Path) -> Result<PathBuf, std::io::Error> { fn _resolve_local_decl(&self, path: &Path) -> Result<PathBuf, std::io::Error> {
let mut dir = self.dir(); let mut dir = self.dir();
let mut comps = path.components(); let mut comps = path.components();
@ -477,29 +477,29 @@ impl Input {
let last_path = Path::new(&last); let last_path = Path::new(&last);
dir.push(comps); dir.push(comps);
dir.push(last_path); dir.push(last_path);
dir.set_extension("d.er"); // {path}.d.er dir.set_extension("d.er"); // {path/to}.d.er
let path = dir let path = dir
.canonicalize() .canonicalize()
.or_else(|_| { .or_else(|_| {
dir.pop(); // {path}.d.er -> ./ dir.pop(); // {path/to}.d.er -> {path}
dir.push(last_path); // -> {path} dir.push(last_path); // -> {path/to}
dir.push("__init__.d.er"); // -> {path}/__init__.d.er dir.push("__init__.d.er"); // -> {path/to}/__init__.d.er
dir.canonicalize() dir.canonicalize()
}) })
.or_else(|_| { .or_else(|_| {
dir.pop(); // -> {path/to}
dir.pop(); // -> {path} dir.pop(); // -> {path}
dir.pop(); // -> ./ dir.push("__pycache__"); // -> {path}/__pycache__
dir.push("__pycache__"); dir.push(last_path); // -> {path}/__pycache__/{to}
dir.push(last_path); dir.set_extension("d.er"); // -> {path}/__pycache__/{to}.d.er
dir.set_extension("d.er"); // -> __pycache__/{path}.d.er
dir.canonicalize() dir.canonicalize()
}) })
.or_else(|_| { .or_else(|_| {
dir.pop(); // -> __pycache__ dir.pop(); // -> {path}/__pycache__
dir.pop(); // -> ./ dir.pop(); // -> {path}
dir.push(last_path); // -> {path} dir.push(last_path); // -> {path/to}
dir.push("__pycache__"); // -> {path}/__pycache__ dir.push("__pycache__"); // -> {path/to}/__pycache__
dir.push("__init__.d.er"); // -> {path}/__pycache__/__init__.d.er dir.push("__init__.d.er"); // -> {path/to}/__pycache__/__init__.d.er
dir.canonicalize() dir.canonicalize()
})?; })?;
Ok(normalize_path(path)) Ok(normalize_path(path))
@ -551,10 +551,10 @@ impl Input {
} }
/// resolution order: /// resolution order:
/// 1. `./{path}.er` /// 1. `./{path/to}.er`
/// 2. `./{path}/__init__.er` /// 2. `./{path/to}/__init__.er`
/// 3. `std/{path}.er` /// 3. `std/{path/to}.er`
/// 4. `std/{path}/__init__.er` /// 4. `std/{path/to}/__init__.er`
pub fn resolve_real_path(&self, path: &Path) -> Option<PathBuf> { pub fn resolve_real_path(&self, path: &Path) -> Option<PathBuf> {
if let Ok(path) = self.resolve_local(path) { if let Ok(path) = self.resolve_local(path) {
Some(path) Some(path)
@ -575,16 +575,16 @@ impl Input {
} }
/// resolution order: /// resolution order:
/// 1. `{path}.d.er` /// 1. `{path/to}.d.er`
/// 2. `{path}/__init__.d.er` /// 2. `{path/to}/__init__.d.er`
/// 3. `__pycache__/{path}.d.er` /// 3. `{path}/__pycache__/{to}.d.er`
/// 4. `{path}/__pycache__/__init__.d.er` /// 4. `{path/to}/__pycache__/__init__.d.er`
/// 5. `{path}.d/__init__.d.er` /// 5. `{path.d/to.d}/__init__.d.er`
/// 6. `{path}.d/__pycache__/__init__.d.er` /// 6. `{path.d/to.d}/__pycache__/__init__.d.er`
/// 7. `std/{path}.d.er` /// 7. `std/{path/to}.d.er`
/// 8. `std/{path}/__init__.d.er` /// 8. `std/{path/to}/__init__.d.er`
/// 9. `site-packages/__pycache__/{path}.d.er` /// 9. `site-packages/{path}/__pycache__/{to}.d.er`
/// 10. `site-packages/{path}/__pycache__/__init__.d.er` /// 10. `site-packages/{path/to}/__pycache__/__init__.d.er`
pub fn resolve_decl_path(&self, path: &Path) -> Option<PathBuf> { pub fn resolve_decl_path(&self, path: &Path) -> Option<PathBuf> {
if let Ok(path) = self.resolve_local_decl(path) { if let Ok(path) = self.resolve_local_decl(path) {
Some(path) Some(path)

View file

@ -1793,12 +1793,12 @@ impl Context {
} }
} }
fn import_err(&self, __name__: &Str, loc: &impl Locational) -> TyCheckErrors { fn import_err(&self, line: u32, __name__: &Str, loc: &impl Locational) -> TyCheckErrors {
let mod_cache = self.mod_cache(); let mod_cache = self.mod_cache();
let py_mod_cache = self.py_mod_cache(); let py_mod_cache = self.py_mod_cache();
TyCheckErrors::from(TyCheckError::import_error( TyCheckErrors::from(TyCheckError::import_error(
self.cfg.input.clone(), self.cfg.input.clone(),
line!() as usize, line as usize,
format!("module {__name__} not found"), format!("module {__name__} not found"),
loc.loc(), loc.loc(),
self.caused_by(), self.caused_by(),
@ -1813,7 +1813,7 @@ impl Context {
let path = match self.cfg.input.resolve_real_path(Path::new(&__name__[..])) { let path = match self.cfg.input.resolve_real_path(Path::new(&__name__[..])) {
Some(path) => path, Some(path) => path,
None => { None => {
return Err(self.import_err(__name__, loc)); return Err(self.import_err(line!(), __name__, loc));
} }
}; };
self.check_mod_vis(path.as_path(), __name__, loc)?; self.check_mod_vis(path.as_path(), __name__, loc)?;
@ -1834,8 +1834,14 @@ impl Context {
__name__: &Str, __name__: &Str,
loc: &impl Locational, loc: &impl Locational,
) -> CompileResult<()> { ) -> CompileResult<()> {
if let Some(parent) = path.parent() { let file_kind = FileKind::from(path);
if FileKind::from(path).is_simple_erg_file() && DirKind::from(parent).is_erg_module() { let parent = if file_kind.is_init_er() {
path.parent().and_then(|p| p.parent())
} else {
path.parent()
};
if let Some(parent) = parent {
if DirKind::from(parent).is_erg_module() {
let parent = parent.join("__init__.er"); let parent = parent.join("__init__.er");
let parent_module = if let Some(parent) = self.get_mod_with_path(&parent) { let parent_module = if let Some(parent) = self.get_mod_with_path(&parent) {
Some(parent) Some(parent)
@ -1845,10 +1851,10 @@ impl Context {
self.get_mod_with_path(&parent) self.get_mod_with_path(&parent)
}; };
if let Some(parent_module) = parent_module { if let Some(parent_module) = parent_module {
let import_err = || { let import_err = |line| {
TyCheckErrors::from(TyCheckError::import_error( TyCheckErrors::from(TyCheckError::import_error(
self.cfg.input.clone(), self.cfg.input.clone(),
line!() as usize, line as usize,
format!("module `{__name__}` is not public"), format!("module `{__name__}` is not public"),
loc.loc(), loc.loc(),
self.caused_by(), self.caused_by(),
@ -1856,13 +1862,18 @@ impl Context {
None, None,
)) ))
}; };
let mod_name = path.file_stem().unwrap_or_default().to_string_lossy(); let file_stem = if file_kind.is_init_er() {
path.parent().unwrap().file_stem()
} else {
path.file_stem()
};
let mod_name = file_stem.unwrap_or_default().to_string_lossy();
if let Some((_, vi)) = parent_module.get_var_info(&mod_name) { if let Some((_, vi)) = parent_module.get_var_info(&mod_name) {
if !vi.vis.compatible(&ast::AccessModifier::Public, self) { if !vi.vis.compatible(&ast::AccessModifier::Public, self) {
return Err(import_err()); return Err(import_err(line!()));
} }
} else { } else {
return Err(import_err()); return Err(import_err(line!()));
} }
} }
} }
@ -1881,7 +1892,7 @@ impl Context {
let src = cfg let src = cfg
.input .input
.try_read() .try_read()
.map_err(|_| self.import_err(__name__, loc))?; .map_err(|_| self.import_err(line!(), __name__, loc))?;
let mut builder = let mut builder =
HIRBuilder::new_with_cache(cfg, __name__, self.shared.as_ref().unwrap().clone()); HIRBuilder::new_with_cache(cfg, __name__, self.shared.as_ref().unwrap().clone());
match builder.build(src, "exec") { match builder.build(src, "exec") {
@ -2040,7 +2051,7 @@ impl Context {
let src = cfg let src = cfg
.input .input
.try_read() .try_read()
.map_err(|_| self.import_err(__name__, loc))?; .map_err(|_| self.import_err(line!(), __name__, loc))?;
let mut builder = HIRBuilder::new_with_cache( let mut builder = HIRBuilder::new_with_cache(
cfg, cfg,
self.mod_name(&path), self.mod_name(&path),

View file

@ -1 +1,2 @@
.bar = import "./bar" .bar = import "./bar"
.quux = import "./quux"

View file

View file

@ -2,3 +2,4 @@ _ = import "foo" # OK
_ = import "foo/bar" # OK _ = import "foo/bar" # OK
_ = import "foo/baz" # ERR _ = import "foo/baz" # ERR
_ = import "foo/qux" # ERR _ = import "foo/qux" # ERR
_ = import "foo/quux" # OK