Fix name resolving bug

This commit is contained in:
Shunsuke Shibayama 2022-10-20 07:43:21 +09:00
parent cb4c2c7bbf
commit 09b5f00305
12 changed files with 172 additions and 51 deletions

View file

@ -139,4 +139,55 @@ impl Str {
.map(|c| c.is_uppercase())
.unwrap_or(false)
}
pub fn split_with(&self, seps: &[&str]) -> Vec<&str> {
let mut ret = vec![];
let mut start = 0;
#[allow(unused_assignments)]
let mut end = 0;
let mut i = 0;
while i < self.len() {
let mut found = false;
for sep in seps {
if self[i..].starts_with(sep) {
end = i;
ret.push(&self[start..end]);
start = i + sep.len();
i = start;
found = true;
break;
}
}
if !found {
i += 1;
}
}
ret.push(&self[start..]);
ret
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_split_with() {
assert_eq!(
Str::ever("aa::bb.cc").split_with(&[".", "::"]),
vec!["aa", "bb", "cc"]
);
assert_eq!(
Str::ever("aa::bb.cc").split_with(&["::", "."]),
vec!["aa", "bb", "cc"]
);
assert_eq!(
Str::ever("aaxxbbyycc").split_with(&["xx", "yy"]),
vec!["aa", "bb", "cc"]
);
assert_ne!(
Str::ever("aaxxbbyycc").split_with(&["xx", "yy"]),
vec!["aa", "bb", "ff"]
);
}
}

View file

@ -1547,9 +1547,15 @@ impl Context {
if let Some((_, ctx)) = self.rec_get_mono_type(&typ.local_name()) {
return Some(ctx);
}
let path = name.split("::").next().unwrap_or(name);
let path = path.split('.').next().unwrap_or(path);
let path = self.resolve_path(Path::new(path));
// e.g. http.client.Response -> http.client
let mut namespaces = name.split_with(&[".", "::"]);
let type_name = namespaces.pop().unwrap(); // Response
let path = Path::new(namespaces.remove(0));
let mut path = self.resolve_path(path);
for p in namespaces.into_iter() {
path = self.push_path(path, Path::new(p));
}
log!("{}", path.display());
if let Some(ctx) = self
.mod_cache
.as_ref()
@ -1560,7 +1566,7 @@ impl Context {
.and_then(|cache| cache.ref_ctx(path.as_path()))
})
{
if let Some((_, ctx)) = ctx.rec_get_mono_type(&typ.local_name()) {
if let Some((_, ctx)) = ctx.rec_get_mono_type(type_name) {
return Some(ctx);
}
}
@ -1570,9 +1576,13 @@ impl Context {
return Some(ctx);
}
// NOTE: This needs to be changed if we want to be able to define classes/traits outside of the top level
let path = name.split("::").next().unwrap_or(name);
let path = path.split('.').next().unwrap_or(path);
let path = self.resolve_path(Path::new(path));
let mut namespaces = name.split_with(&[".", "::"]);
let type_name = namespaces.pop().unwrap(); // Response
let path = Path::new(namespaces.remove(0));
let mut path = self.resolve_path(path);
for p in namespaces.into_iter() {
path = self.push_path(path, Path::new(p));
}
if let Some(ctx) = self
.mod_cache
.as_ref()
@ -1583,7 +1593,7 @@ impl Context {
.and_then(|cache| cache.ref_ctx(path.as_path()))
})
{
if let Some((_, ctx)) = ctx.rec_get_poly_type(&typ.local_name()) {
if let Some((_, ctx)) = ctx.rec_get_poly_type(type_name) {
return Some(ctx);
}
}
@ -1752,6 +1762,23 @@ impl Context {
}
}
pub(crate) fn push_path(&self, mut path: PathBuf, add: &Path) -> PathBuf {
path.pop(); // __init__.d.er
if let Ok(path) = path.join(add).canonicalize() {
path
} else if let Ok(path) = path.join(format!("{}.d.er", add.display())).canonicalize() {
path
} else if let Ok(path) = path
.join(format!("{}.d", add.display()))
.join("__init__.d.er")
.canonicalize()
{
path
} else {
todo!("{} {}", path.display(), add.display())
}
}
// FIXME: 現在の実装だとimportしたモジュールはどこからでも見れる
pub(crate) fn get_mod(&self, name: &str) -> Option<&Context> {
let t = self.get_var_info(name).map(|(_, vi)| vi.t.clone()).ok()?;

View file

@ -824,7 +824,20 @@ impl Context {
expr: &ast::ConstExpr,
) -> SingleTyCheckResult<Type> {
match expr {
ast::ConstExpr::Accessor(ast::ConstAccessor::Local(name)) => Ok(mono(name.inspect())),
ast::ConstExpr::Accessor(ast::ConstAccessor::Local(name)) => {
if let Some((typ, _)) = self.rec_get_type(name.inspect()) {
Ok(typ.clone())
} else {
Err(TyCheckError::no_var_error(
self.cfg.input.clone(),
line!() as usize,
name.loc(),
self.caused_by(),
name.inspect(),
self.get_similar_name(name.inspect()),
))
}
}
_ => todo!(),
}
}

View file

@ -29,7 +29,6 @@ use crate::error::{
};
use crate::hir;
use crate::hir::Literal;
use crate::mod_cache::SharedModuleCache;
use crate::varinfo::{Mutability, ParamIdx, VarInfo, VarKind};
use Mutability::*;
use RegistrationMode::*;
@ -1016,30 +1015,16 @@ impl Context {
mod_name: &Literal,
) -> CompileResult<PathBuf> {
if kind.is_erg_import() {
self.import_erg_mod_using_cache(mod_name)
self.import_erg_mod(mod_name)
} else {
self.import_py_mod(mod_name)
}
}
fn import_erg_mod_using_cache(&mut self, mod_name: &Literal) -> CompileResult<PathBuf> {
fn import_erg_mod(&self, mod_name: &Literal) -> CompileResult<PathBuf> {
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();
#[allow(clippy::match_single_binding)]
match &__name__[..] {
// TODO: erg builtin modules
_ => self.import_erg_mod(__name__, mod_name, mod_cache, py_mod_cache),
}
}
fn import_erg_mod(
&self,
__name__: Str,
mod_name: &Literal,
mod_cache: &SharedModuleCache,
py_mod_cache: &SharedModuleCache,
) -> CompileResult<PathBuf> {
let path = match self.cfg.input.local_resolve(Path::new(&__name__[..])) {
Ok(path) => path,
Err(err) => {
@ -1097,6 +1082,27 @@ impl Context {
path == pystd_path
}
/// e.g. http.d/client.d.er -> http.client
/// math.d.er -> math
fn mod_name(&self, path: &Path) -> Str {
let mut name = path
.file_name()
.unwrap()
.to_str()
.unwrap()
.trim_end_matches(".d.er")
.to_string();
for parent in path.components().rev().skip(1) {
let parent = parent.as_os_str().to_str().unwrap();
if parent.ends_with(".d") {
name = parent.trim_end_matches(".d").to_string() + "." + &name;
} else {
break;
}
}
Str::from(name)
}
fn import_py_mod(&self, mod_name: &Literal) -> CompileResult<PathBuf> {
let __name__ = enum_unwrap!(mod_name.value.clone(), ValueObj::Str);
let mod_cache = self.mod_cache.as_ref().unwrap();
@ -1137,8 +1143,12 @@ impl Context {
}
let cfg = ErgConfig::with_module_path(path.clone());
let src = cfg.input.read();
let mut builder =
HIRBuilder::new_with_cache(cfg, __name__, mod_cache.clone(), py_mod_cache.clone());
let mut builder = HIRBuilder::new_with_cache(
cfg,
self.mod_name(&path),
mod_cache.clone(),
py_mod_cache.clone(),
);
match builder.build(src, "declare") {
Ok(hir) => {
let ctx = builder.pop_mod_ctx();

View file

@ -795,8 +795,8 @@ impl Context {
for attr in record.attrs.iter_mut() {
match &mut attr.sig {
hir::Signature::Var(var) => {
var.t =
self.deref_tyvar(mem::take(&mut var.t), Covariant, var.loc())?;
*var.ref_mut_t() =
self.deref_tyvar(mem::take(var.ref_mut_t()), Covariant, var.loc())?;
}
hir::Signature::Subr(subr) => {
subr.t =
@ -851,8 +851,8 @@ impl Context {
if !def.sig.ref_t().is_quantified() {
match &mut def.sig {
hir::Signature::Var(var) => {
var.t =
self.deref_tyvar(mem::take(&mut var.t), Covariant, var.loc())?;
*var.ref_mut_t() =
self.deref_tyvar(mem::take(var.ref_mut_t()), Covariant, var.loc())?;
}
hir::Signature::Subr(subr) => {
subr.t =

View file

@ -548,8 +548,8 @@ impl Accessor {
pub fn local_name(&self) -> Option<&str> {
match self {
Self::Ident(ident) => ident.qual_name.as_ref().map(|s| {
let name = s.split("::").last().unwrap_or(&s[..]);
name.split('.').last().unwrap_or(name)
let mut seps = s.split_with(&[".", "::"]);
seps.remove(seps.len() - 1)
}),
_ => None,
}
@ -1200,22 +1200,39 @@ impl Locational for Block {
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct VarSignature {
pub ident: Identifier,
pub t: Type,
}
impl NestedDisplay for VarSignature {
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result {
write!(f, "{}(: {})", self.ident, self.t)
write!(f, "{}", self.ident)
}
}
impl_display_from_nested!(VarSignature);
impl_locational!(VarSignature, ident);
impl_t!(VarSignature);
impl HasType for VarSignature {
#[inline]
fn ref_t(&self) -> &Type {
self.ident.ref_t()
}
#[inline]
fn ref_mut_t(&mut self) -> &mut Type {
self.ident.ref_mut_t()
}
#[inline]
fn signature_t(&self) -> Option<&Type> {
self.ident.signature_t()
}
#[inline]
fn signature_mut_t(&mut self) -> Option<&mut Type> {
self.ident.signature_mut_t()
}
}
impl VarSignature {
pub const fn new(ident: Identifier, t: Type) -> Self {
Self { ident, t }
pub const fn new(ident: Identifier) -> Self {
Self { ident }
}
pub fn inspect(&self) -> &Str {

View file

@ -1 +1 @@
.client = pyimport "./client"
.client = pyimport "client"

View file

@ -1 +1,3 @@
.HTTPResponse: ClassType
.HTTPResponse <: FileLike
.HTTPResponse <: FileLike!

View file

@ -1,2 +1,2 @@
.parse = pyimport "./parse"
.request = pyimport "./request"
.parse = pyimport "parse"
.request = pyimport "request"

View file

@ -13,7 +13,7 @@ use erg_parser::token::{Token, TokenKind};
use crate::ty::free::fresh_varname;
use crate::ty::typaram::TyParam;
use crate::ty::value::ValueObj;
use crate::ty::{HasType, Type};
use crate::ty::HasType;
use crate::hir::*;
use crate::mod_cache::SharedModuleCache;
@ -312,7 +312,7 @@ impl<'a> Linker<'a> {
let tmp =
Identifier::private_with_line(Str::from(fresh_varname()), expr.ln_begin().unwrap());
let mod_def = Expr::Def(Def::new(
Signature::Var(VarSignature::new(tmp.clone(), Type::Uninited)),
Signature::Var(VarSignature::new(tmp.clone())),
DefBody::new(Token::dummy(), block, DefId(0)),
));
let module = Expr::Accessor(Accessor::Ident(tmp));

View file

@ -932,8 +932,9 @@ impl ASTLowerer {
body.id,
None,
)?;
let ident = hir::Identifier::bare(ident.dot.clone(), ident.name.clone());
let sig = hir::VarSignature::new(ident, found_body_t.clone());
let mut ident = hir::Identifier::bare(ident.dot.clone(), ident.name.clone());
ident.vi.t = found_body_t.clone();
let sig = hir::VarSignature::new(ident);
let body = hir::DefBody::new(body.op, block, body.id);
Ok(hir::Def::new(hir::Signature::Var(sig), body))
}
@ -1515,8 +1516,9 @@ impl ASTLowerer {
};
let id = body.id;
self.ctx.assign_var_sig(&sig, found_body_t, id, py_name)?;
let ident = hir::Identifier::bare(ident.dot.clone(), ident.name.clone());
let sig = hir::VarSignature::new(ident, found_body_t.clone());
let mut ident = hir::Identifier::bare(ident.dot.clone(), ident.name.clone());
ident.vi.t = found_body_t.clone();
let sig = hir::VarSignature::new(ident);
let body = hir::DefBody::new(body.op, block, body.id);
Ok(hir::Def::new(hir::Signature::Var(sig), body))
}

View file

@ -1955,9 +1955,8 @@ impl Type {
pub fn local_name(&self) -> Str {
match self {
Self::Mono(name) | Self::Poly { name, .. } => {
let name = name.split("::").last().unwrap_or(name);
let name = name.split('.').last().unwrap_or(name);
Str::rc(name)
let namespaces = name.split_with(&[".", "::"]);
Str::rc(namespaces.last().unwrap())
}
_ => self.qual_name(),
}