mirror of
https://github.com/erg-lang/erg.git
synced 2025-09-30 04:44:44 +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())
|
.map(|c| c.is_uppercase())
|
||||||
.unwrap_or(false)
|
.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()) {
|
if let Some((_, ctx)) = self.rec_get_mono_type(&typ.local_name()) {
|
||||||
return Some(ctx);
|
return Some(ctx);
|
||||||
}
|
}
|
||||||
let path = name.split("::").next().unwrap_or(name);
|
// e.g. http.client.Response -> http.client
|
||||||
let path = path.split('.').next().unwrap_or(path);
|
let mut namespaces = name.split_with(&[".", "::"]);
|
||||||
let path = self.resolve_path(Path::new(path));
|
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
|
if let Some(ctx) = self
|
||||||
.mod_cache
|
.mod_cache
|
||||||
.as_ref()
|
.as_ref()
|
||||||
|
@ -1560,7 +1566,7 @@ impl Context {
|
||||||
.and_then(|cache| cache.ref_ctx(path.as_path()))
|
.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);
|
return Some(ctx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1570,9 +1576,13 @@ impl Context {
|
||||||
return Some(ctx);
|
return Some(ctx);
|
||||||
}
|
}
|
||||||
// NOTE: This needs to be changed if we want to be able to define classes/traits outside of the top level
|
// 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 mut namespaces = name.split_with(&[".", "::"]);
|
||||||
let path = path.split('.').next().unwrap_or(path);
|
let type_name = namespaces.pop().unwrap(); // Response
|
||||||
let path = self.resolve_path(Path::new(path));
|
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
|
if let Some(ctx) = self
|
||||||
.mod_cache
|
.mod_cache
|
||||||
.as_ref()
|
.as_ref()
|
||||||
|
@ -1583,7 +1593,7 @@ impl Context {
|
||||||
.and_then(|cache| cache.ref_ctx(path.as_path()))
|
.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);
|
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したモジュールはどこからでも見れる
|
// FIXME: 現在の実装だとimportしたモジュールはどこからでも見れる
|
||||||
pub(crate) fn get_mod(&self, name: &str) -> Option<&Context> {
|
pub(crate) fn get_mod(&self, name: &str) -> Option<&Context> {
|
||||||
let t = self.get_var_info(name).map(|(_, vi)| vi.t.clone()).ok()?;
|
let t = self.get_var_info(name).map(|(_, vi)| vi.t.clone()).ok()?;
|
||||||
|
|
|
@ -824,7 +824,20 @@ impl Context {
|
||||||
expr: &ast::ConstExpr,
|
expr: &ast::ConstExpr,
|
||||||
) -> SingleTyCheckResult<Type> {
|
) -> SingleTyCheckResult<Type> {
|
||||||
match expr {
|
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!(),
|
_ => todo!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,6 @@ use crate::error::{
|
||||||
};
|
};
|
||||||
use crate::hir;
|
use crate::hir;
|
||||||
use crate::hir::Literal;
|
use crate::hir::Literal;
|
||||||
use crate::mod_cache::SharedModuleCache;
|
|
||||||
use crate::varinfo::{Mutability, ParamIdx, VarInfo, VarKind};
|
use crate::varinfo::{Mutability, ParamIdx, VarInfo, VarKind};
|
||||||
use Mutability::*;
|
use Mutability::*;
|
||||||
use RegistrationMode::*;
|
use RegistrationMode::*;
|
||||||
|
@ -1016,30 +1015,16 @@ impl Context {
|
||||||
mod_name: &Literal,
|
mod_name: &Literal,
|
||||||
) -> CompileResult<PathBuf> {
|
) -> CompileResult<PathBuf> {
|
||||||
if kind.is_erg_import() {
|
if kind.is_erg_import() {
|
||||||
self.import_erg_mod_using_cache(mod_name)
|
self.import_erg_mod(mod_name)
|
||||||
} else {
|
} else {
|
||||||
self.import_py_mod(mod_name)
|
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 __name__ = enum_unwrap!(mod_name.value.clone(), ValueObj::Str);
|
||||||
let mod_cache = self.mod_cache.as_ref().unwrap();
|
let mod_cache = self.mod_cache.as_ref().unwrap();
|
||||||
let py_mod_cache = self.py_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__[..])) {
|
let path = match self.cfg.input.local_resolve(Path::new(&__name__[..])) {
|
||||||
Ok(path) => path,
|
Ok(path) => path,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
@ -1097,6 +1082,27 @@ impl Context {
|
||||||
path == pystd_path
|
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> {
|
fn import_py_mod(&self, mod_name: &Literal) -> CompileResult<PathBuf> {
|
||||||
let __name__ = enum_unwrap!(mod_name.value.clone(), ValueObj::Str);
|
let __name__ = enum_unwrap!(mod_name.value.clone(), ValueObj::Str);
|
||||||
let mod_cache = self.mod_cache.as_ref().unwrap();
|
let mod_cache = self.mod_cache.as_ref().unwrap();
|
||||||
|
@ -1137,8 +1143,12 @@ impl Context {
|
||||||
}
|
}
|
||||||
let cfg = ErgConfig::with_module_path(path.clone());
|
let cfg = ErgConfig::with_module_path(path.clone());
|
||||||
let src = cfg.input.read();
|
let src = cfg.input.read();
|
||||||
let mut builder =
|
let mut builder = HIRBuilder::new_with_cache(
|
||||||
HIRBuilder::new_with_cache(cfg, __name__, mod_cache.clone(), py_mod_cache.clone());
|
cfg,
|
||||||
|
self.mod_name(&path),
|
||||||
|
mod_cache.clone(),
|
||||||
|
py_mod_cache.clone(),
|
||||||
|
);
|
||||||
match builder.build(src, "declare") {
|
match builder.build(src, "declare") {
|
||||||
Ok(hir) => {
|
Ok(hir) => {
|
||||||
let ctx = builder.pop_mod_ctx();
|
let ctx = builder.pop_mod_ctx();
|
||||||
|
|
|
@ -795,8 +795,8 @@ impl Context {
|
||||||
for attr in record.attrs.iter_mut() {
|
for attr in record.attrs.iter_mut() {
|
||||||
match &mut attr.sig {
|
match &mut attr.sig {
|
||||||
hir::Signature::Var(var) => {
|
hir::Signature::Var(var) => {
|
||||||
var.t =
|
*var.ref_mut_t() =
|
||||||
self.deref_tyvar(mem::take(&mut var.t), Covariant, var.loc())?;
|
self.deref_tyvar(mem::take(var.ref_mut_t()), Covariant, var.loc())?;
|
||||||
}
|
}
|
||||||
hir::Signature::Subr(subr) => {
|
hir::Signature::Subr(subr) => {
|
||||||
subr.t =
|
subr.t =
|
||||||
|
@ -851,8 +851,8 @@ impl Context {
|
||||||
if !def.sig.ref_t().is_quantified() {
|
if !def.sig.ref_t().is_quantified() {
|
||||||
match &mut def.sig {
|
match &mut def.sig {
|
||||||
hir::Signature::Var(var) => {
|
hir::Signature::Var(var) => {
|
||||||
var.t =
|
*var.ref_mut_t() =
|
||||||
self.deref_tyvar(mem::take(&mut var.t), Covariant, var.loc())?;
|
self.deref_tyvar(mem::take(var.ref_mut_t()), Covariant, var.loc())?;
|
||||||
}
|
}
|
||||||
hir::Signature::Subr(subr) => {
|
hir::Signature::Subr(subr) => {
|
||||||
subr.t =
|
subr.t =
|
||||||
|
|
|
@ -548,8 +548,8 @@ impl Accessor {
|
||||||
pub fn local_name(&self) -> Option<&str> {
|
pub fn local_name(&self) -> Option<&str> {
|
||||||
match self {
|
match self {
|
||||||
Self::Ident(ident) => ident.qual_name.as_ref().map(|s| {
|
Self::Ident(ident) => ident.qual_name.as_ref().map(|s| {
|
||||||
let name = s.split("::").last().unwrap_or(&s[..]);
|
let mut seps = s.split_with(&[".", "::"]);
|
||||||
name.split('.').last().unwrap_or(name)
|
seps.remove(seps.len() - 1)
|
||||||
}),
|
}),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
|
@ -1200,22 +1200,39 @@ impl Locational for Block {
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct VarSignature {
|
pub struct VarSignature {
|
||||||
pub ident: Identifier,
|
pub ident: Identifier,
|
||||||
pub t: Type,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NestedDisplay for VarSignature {
|
impl NestedDisplay for VarSignature {
|
||||||
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result {
|
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_display_from_nested!(VarSignature);
|
||||||
impl_locational!(VarSignature, ident);
|
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 {
|
impl VarSignature {
|
||||||
pub const fn new(ident: Identifier, t: Type) -> Self {
|
pub const fn new(ident: Identifier) -> Self {
|
||||||
Self { ident, t }
|
Self { ident }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn inspect(&self) -> &Str {
|
pub fn inspect(&self) -> &Str {
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
.client = pyimport "./client"
|
.client = pyimport "client"
|
||||||
|
|
|
@ -1 +1,3 @@
|
||||||
.HTTPResponse: ClassType
|
.HTTPResponse: ClassType
|
||||||
|
.HTTPResponse <: FileLike
|
||||||
|
.HTTPResponse <: FileLike!
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
.parse = pyimport "./parse"
|
.parse = pyimport "parse"
|
||||||
.request = pyimport "./request"
|
.request = pyimport "request"
|
||||||
|
|
|
@ -13,7 +13,7 @@ use erg_parser::token::{Token, TokenKind};
|
||||||
use crate::ty::free::fresh_varname;
|
use crate::ty::free::fresh_varname;
|
||||||
use crate::ty::typaram::TyParam;
|
use crate::ty::typaram::TyParam;
|
||||||
use crate::ty::value::ValueObj;
|
use crate::ty::value::ValueObj;
|
||||||
use crate::ty::{HasType, Type};
|
use crate::ty::HasType;
|
||||||
|
|
||||||
use crate::hir::*;
|
use crate::hir::*;
|
||||||
use crate::mod_cache::SharedModuleCache;
|
use crate::mod_cache::SharedModuleCache;
|
||||||
|
@ -312,7 +312,7 @@ impl<'a> Linker<'a> {
|
||||||
let tmp =
|
let tmp =
|
||||||
Identifier::private_with_line(Str::from(fresh_varname()), expr.ln_begin().unwrap());
|
Identifier::private_with_line(Str::from(fresh_varname()), expr.ln_begin().unwrap());
|
||||||
let mod_def = Expr::Def(Def::new(
|
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)),
|
DefBody::new(Token::dummy(), block, DefId(0)),
|
||||||
));
|
));
|
||||||
let module = Expr::Accessor(Accessor::Ident(tmp));
|
let module = Expr::Accessor(Accessor::Ident(tmp));
|
||||||
|
|
|
@ -932,8 +932,9 @@ impl ASTLowerer {
|
||||||
body.id,
|
body.id,
|
||||||
None,
|
None,
|
||||||
)?;
|
)?;
|
||||||
let ident = hir::Identifier::bare(ident.dot.clone(), ident.name.clone());
|
let mut ident = hir::Identifier::bare(ident.dot.clone(), ident.name.clone());
|
||||||
let sig = hir::VarSignature::new(ident, found_body_t.clone());
|
ident.vi.t = found_body_t.clone();
|
||||||
|
let sig = hir::VarSignature::new(ident);
|
||||||
let body = hir::DefBody::new(body.op, block, body.id);
|
let body = hir::DefBody::new(body.op, block, body.id);
|
||||||
Ok(hir::Def::new(hir::Signature::Var(sig), body))
|
Ok(hir::Def::new(hir::Signature::Var(sig), body))
|
||||||
}
|
}
|
||||||
|
@ -1515,8 +1516,9 @@ impl ASTLowerer {
|
||||||
};
|
};
|
||||||
let id = body.id;
|
let id = body.id;
|
||||||
self.ctx.assign_var_sig(&sig, found_body_t, id, py_name)?;
|
self.ctx.assign_var_sig(&sig, found_body_t, id, py_name)?;
|
||||||
let ident = hir::Identifier::bare(ident.dot.clone(), ident.name.clone());
|
let mut ident = hir::Identifier::bare(ident.dot.clone(), ident.name.clone());
|
||||||
let sig = hir::VarSignature::new(ident, found_body_t.clone());
|
ident.vi.t = found_body_t.clone();
|
||||||
|
let sig = hir::VarSignature::new(ident);
|
||||||
let body = hir::DefBody::new(body.op, block, body.id);
|
let body = hir::DefBody::new(body.op, block, body.id);
|
||||||
Ok(hir::Def::new(hir::Signature::Var(sig), body))
|
Ok(hir::Def::new(hir::Signature::Var(sig), body))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1955,9 +1955,8 @@ impl Type {
|
||||||
pub fn local_name(&self) -> Str {
|
pub fn local_name(&self) -> Str {
|
||||||
match self {
|
match self {
|
||||||
Self::Mono(name) | Self::Poly { name, .. } => {
|
Self::Mono(name) | Self::Poly { name, .. } => {
|
||||||
let name = name.split("::").last().unwrap_or(name);
|
let namespaces = name.split_with(&[".", "::"]);
|
||||||
let name = name.split('.').last().unwrap_or(name);
|
Str::rc(namespaces.last().unwrap())
|
||||||
Str::rc(name)
|
|
||||||
}
|
}
|
||||||
_ => self.qual_name(),
|
_ => self.qual_name(),
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue