mirror of
https://github.com/erg-lang/erg.git
synced 2025-09-30 12:51:10 +00:00
Fix name resolving bug
This commit is contained in:
parent
cb4c2c7bbf
commit
09b5f00305
12 changed files with 172 additions and 51 deletions
|
@ -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"]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()?;
|
||||
|
|
|
@ -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!(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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 =
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -1 +1 @@
|
|||
.client = pyimport "./client"
|
||||
.client = pyimport "client"
|
||||
|
|
|
@ -1 +1,3 @@
|
|||
.HTTPResponse: ClassType
|
||||
.HTTPResponse <: FileLike
|
||||
.HTTPResponse <: FileLike!
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
.parse = pyimport "./parse"
|
||||
.request = pyimport "./request"
|
||||
.parse = pyimport "parse"
|
||||
.request = pyimport "request"
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
|
|
|
@ -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(),
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue