mirror of
https://github.com/erg-lang/erg.git
synced 2025-08-04 18:58:30 +00:00
fix: failure of the type inference of another module
This commit is contained in:
parent
aa2cea60dd
commit
5c4c43ab2f
8 changed files with 119 additions and 59 deletions
|
@ -1145,7 +1145,7 @@ impl Context {
|
|||
// obj: [T; N]|<: Add([T; M])|.Output == ValueObj::Type(<type [T; M+N]>)
|
||||
if let ValueObj::Type(quant_projected_t) = obj {
|
||||
let projected_t = quant_projected_t.into_typ();
|
||||
let (quant_sub, _) = self.rec_get_type(&sub.local_name()).unwrap();
|
||||
let (quant_sub, _) = self.get_type(&sub.qual_name()).unwrap();
|
||||
if let Some(sup) = opt_sup {
|
||||
if let Some(quant_sup) = methods.impl_of() {
|
||||
// T -> Int, M -> 2
|
||||
|
|
|
@ -676,7 +676,7 @@ impl Context {
|
|||
muty: Mutability,
|
||||
py_name: Option<&'static str>,
|
||||
) {
|
||||
if self.rec_get_mono_type(&t.local_name()).is_some() {
|
||||
if self.rec_local_get_mono_type(&t.local_name()).is_some() {
|
||||
panic!("{} has already been registered", t.local_name());
|
||||
} else if self.rec_get_const_obj(&t.local_name()).is_some() {
|
||||
panic!("{} has already been registered as const", t.local_name());
|
||||
|
|
|
@ -134,7 +134,7 @@ impl Context {
|
|||
namespace: &Str,
|
||||
) -> SingleTyCheckResult<&Context> {
|
||||
self.get_mod(ident.inspect())
|
||||
.or_else(|| self.rec_get_type(ident.inspect()).map(|(_, ctx)| ctx))
|
||||
.or_else(|| self.rec_local_get_type(ident.inspect()).map(|(_, ctx)| ctx))
|
||||
.or_else(|| self.rec_get_patch(ident.inspect()))
|
||||
.ok_or_else(|| {
|
||||
TyCheckError::no_var_error(
|
||||
|
@ -1894,7 +1894,7 @@ impl Context {
|
|||
if let Some((t, ctx)) = self
|
||||
.get_builtins()
|
||||
.unwrap_or(self)
|
||||
.rec_get_mono_type("QuantifiedFunc")
|
||||
.rec_local_get_mono_type("QuantifiedFunc")
|
||||
{
|
||||
return Some((t, ctx));
|
||||
}
|
||||
|
@ -1904,7 +1904,7 @@ impl Context {
|
|||
if let Some((t, ctx)) = self
|
||||
.get_builtins()
|
||||
.unwrap_or(self)
|
||||
.rec_get_mono_type("Func")
|
||||
.rec_local_get_mono_type("Func")
|
||||
{
|
||||
return Some((t, ctx));
|
||||
}
|
||||
|
@ -1913,53 +1913,17 @@ impl Context {
|
|||
if let Some((t, ctx)) = self
|
||||
.get_builtins()
|
||||
.unwrap_or(self)
|
||||
.rec_get_mono_type("Proc")
|
||||
.rec_local_get_mono_type("Proc")
|
||||
{
|
||||
return Some((t, ctx));
|
||||
}
|
||||
}
|
||||
},
|
||||
Type::Mono(name) => {
|
||||
if let Some((t, ctx)) = self.rec_get_mono_type(&typ.local_name()) {
|
||||
return Some((t, ctx));
|
||||
}
|
||||
// e.g. http.client.Response -> http.client
|
||||
let mut namespaces = name.split_with(&[".", "::"]);
|
||||
if namespaces.len() < 2 {
|
||||
return None;
|
||||
}
|
||||
let type_name = namespaces.pop().unwrap(); // Response
|
||||
let path = Path::new(namespaces.remove(0));
|
||||
let mut path = Self::resolve_path(&self.cfg, path)?;
|
||||
for p in namespaces.into_iter() {
|
||||
path = self.push_path(path, Path::new(p));
|
||||
}
|
||||
if let Some(ctx) = self.get_ctx_from_path(path.as_path()) {
|
||||
if let Some((t, ctx)) = ctx.rec_get_mono_type(type_name) {
|
||||
return Some((t, ctx));
|
||||
}
|
||||
}
|
||||
return self.get_mono_type(name);
|
||||
}
|
||||
Type::Poly { name, .. } => {
|
||||
if let Some((t, ctx)) = self.rec_get_poly_type(&typ.local_name()) {
|
||||
return Some((t, ctx));
|
||||
}
|
||||
// NOTE: This needs to be changed if we want to be able to define classes/traits outside of the top level
|
||||
let mut namespaces = name.split_with(&[".", "::"]);
|
||||
if namespaces.len() < 2 {
|
||||
return None;
|
||||
}
|
||||
let type_name = namespaces.pop().unwrap(); // Response
|
||||
let path = Path::new(namespaces.remove(0));
|
||||
let mut path = Self::resolve_path(&self.cfg, path)?;
|
||||
for p in namespaces.into_iter() {
|
||||
path = self.push_path(path, Path::new(p));
|
||||
}
|
||||
if let Some(ctx) = self.get_ctx_from_path(path.as_path()) {
|
||||
if let Some((t, ctx)) = ctx.rec_get_poly_type(type_name) {
|
||||
return Some((t, ctx));
|
||||
}
|
||||
}
|
||||
return self.get_type(name);
|
||||
}
|
||||
Type::Record(rec)
|
||||
if rec
|
||||
|
@ -1969,13 +1933,13 @@ impl Context {
|
|||
return self
|
||||
.get_builtins()
|
||||
.unwrap_or(self)
|
||||
.rec_get_mono_type("RecordType");
|
||||
.rec_local_get_mono_type("RecordType");
|
||||
}
|
||||
Type::Record(_) => {
|
||||
return self
|
||||
.get_builtins()
|
||||
.unwrap_or(self)
|
||||
.rec_get_mono_type("Record");
|
||||
.rec_local_get_mono_type("Record");
|
||||
}
|
||||
Type::Or(_l, _r) => {
|
||||
if let Some(ctx) = self.get_nominal_type_ctx(&poly("Or", vec![])) {
|
||||
|
@ -1984,7 +1948,7 @@ impl Context {
|
|||
}
|
||||
// FIXME: `F()`などの場合、実際は引数が省略されていてもmonomorphicになる
|
||||
other if other.is_monomorphic() => {
|
||||
if let Some((t, ctx)) = self.rec_get_mono_type(&other.local_name()) {
|
||||
if let Some((t, ctx)) = self.rec_local_get_mono_type(&other.local_name()) {
|
||||
return Some((t, ctx));
|
||||
}
|
||||
}
|
||||
|
@ -2000,6 +1964,7 @@ impl Context {
|
|||
None
|
||||
}
|
||||
|
||||
/// It is currently not possible to get the type defined in another module
|
||||
// TODO: Never
|
||||
pub(crate) fn get_mut_nominal_type_ctx<'a>(
|
||||
&'a mut self,
|
||||
|
@ -2217,21 +2182,55 @@ impl Context {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn rec_get_mono_type(&self, name: &str) -> Option<(&Type, &Context)> {
|
||||
pub(crate) fn get_mono_type(&self, name: &Str) -> Option<(&Type, &Context)> {
|
||||
if let Some((t, ctx)) = self.rec_local_get_mono_type(name) {
|
||||
return Some((t, ctx));
|
||||
}
|
||||
// e.g.
|
||||
// http.client.Response -> http.client
|
||||
// ../http/client.Response -> ../http.client
|
||||
let mut namespaces = name.split_with(&[".", "::"]);
|
||||
if namespaces.len() < 2 {
|
||||
return None;
|
||||
}
|
||||
let type_name = namespaces.pop().unwrap(); // "Response"
|
||||
if let Some((t, ctx)) = self.rec_local_get_mono_type(type_name) {
|
||||
return Some((t, ctx));
|
||||
}
|
||||
let mut namespace = namespaces.remove(0).to_string(); // "http" or ""
|
||||
while namespace.is_empty() || namespace.ends_with('.') {
|
||||
namespace.push('.');
|
||||
namespace.push_str(namespaces.remove(0));
|
||||
}
|
||||
let path = Path::new(&namespace);
|
||||
let mut path = Self::resolve_path(&self.cfg, path)?;
|
||||
for p in namespaces.into_iter() {
|
||||
path = self.push_path(path, Path::new(p));
|
||||
}
|
||||
if let Some(ctx) = self.get_ctx_from_path(path.as_path()) {
|
||||
if let Some((t, ctx)) = ctx.rec_local_get_mono_type(type_name) {
|
||||
return Some((t, ctx));
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// you should use `get_mono_type` instead of this
|
||||
pub(crate) fn rec_local_get_mono_type(&self, name: &str) -> Option<(&Type, &Context)> {
|
||||
if let Some((t, ctx)) = self.mono_types.get(name) {
|
||||
Some((t, ctx))
|
||||
} else if let Some(outer) = self.get_outer().or_else(|| self.get_builtins()) {
|
||||
outer.rec_get_mono_type(name)
|
||||
outer.rec_local_get_mono_type(name)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn rec_get_poly_type(&self, name: &str) -> Option<(&Type, &Context)> {
|
||||
pub(crate) fn _rec_local_get_poly_type(&self, name: &str) -> Option<(&Type, &Context)> {
|
||||
if let Some((t, ctx)) = self.poly_types.get(name) {
|
||||
Some((t, ctx))
|
||||
} else if let Some(outer) = self.get_outer().or_else(|| self.get_builtins()) {
|
||||
outer.rec_get_poly_type(name)
|
||||
outer._rec_local_get_poly_type(name)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
@ -2258,13 +2257,47 @@ impl Context {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn rec_get_type(&self, name: &str) -> Option<(&Type, &Context)> {
|
||||
pub(crate) fn get_type(&self, name: &Str) -> Option<(&Type, &Context)> {
|
||||
if let Some((t, ctx)) = self.rec_local_get_type(name) {
|
||||
return Some((t, ctx));
|
||||
}
|
||||
// e.g.
|
||||
// http.client.Response -> http.client
|
||||
// ../http/client.Response -> ../http.client
|
||||
let mut namespaces = name.split_with(&[".", "::"]);
|
||||
if namespaces.len() < 2 {
|
||||
return None;
|
||||
}
|
||||
let type_name = namespaces.pop().unwrap(); // "Response"
|
||||
if let Some((t, ctx)) = self.rec_local_get_type(type_name) {
|
||||
return Some((t, ctx));
|
||||
}
|
||||
let mut namespace = namespaces.remove(0).to_string(); // "http" or ""
|
||||
while namespace.is_empty() || namespace.ends_with('.') {
|
||||
namespace.push('.');
|
||||
namespace.push_str(namespaces.remove(0));
|
||||
}
|
||||
let path = Path::new(&namespace);
|
||||
let mut path = Self::resolve_path(&self.cfg, path)?;
|
||||
for p in namespaces.into_iter() {
|
||||
path = self.push_path(path, Path::new(p));
|
||||
}
|
||||
if let Some(ctx) = self.get_ctx_from_path(path.as_path()) {
|
||||
if let Some((t, ctx)) = ctx.rec_local_get_type(type_name) {
|
||||
return Some((t, ctx));
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// you should use `get_type` instead of this
|
||||
pub(crate) fn rec_local_get_type(&self, name: &str) -> Option<(&Type, &Context)> {
|
||||
if let Some((t, ctx)) = self.mono_types.get(name) {
|
||||
Some((t, ctx))
|
||||
} else if let Some((t, ctx)) = self.poly_types.get(name) {
|
||||
Some((t, ctx))
|
||||
} else if let Some(outer) = self.get_outer().or_else(|| self.get_builtins()) {
|
||||
outer.rec_get_type(name)
|
||||
outer.rec_local_get_type(name)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
|
|
@ -500,7 +500,7 @@ impl Context {
|
|||
}
|
||||
}
|
||||
let ctx = self.get_singular_ctx(namespace.as_ref(), &self.name)?;
|
||||
if let Some((typ, _)) = ctx.rec_get_type(t.ident.inspect()) {
|
||||
if let Some((typ, _)) = ctx.rec_local_get_type(t.ident.inspect()) {
|
||||
// TODO: visibility check
|
||||
Ok(typ.clone())
|
||||
} else {
|
||||
|
@ -624,7 +624,7 @@ impl Context {
|
|||
if let Some(decl_t) = opt_decl_t {
|
||||
return Ok(decl_t.typ().clone());
|
||||
}
|
||||
if let Some((typ, _)) = self.rec_get_type(other) {
|
||||
if let Some((typ, _)) = self.get_type(&Str::rc(other)) {
|
||||
Ok(typ.clone())
|
||||
} else if not_found_is_qvar {
|
||||
let tyvar = named_free_var(Str::rc(other), self.level, Constraint::Uninited);
|
||||
|
@ -642,7 +642,7 @@ impl Context {
|
|||
}
|
||||
}
|
||||
other => {
|
||||
let ctx = if let Some((_, ctx)) = self.rec_get_type(other) {
|
||||
let ctx = if let Some((_, ctx)) = self.get_type(&Str::rc(other)) {
|
||||
ctx
|
||||
} else {
|
||||
return Err(TyCheckErrors::from(TyCheckError::no_type_error(
|
||||
|
|
|
@ -416,7 +416,7 @@ impl ContextProvider for Context {
|
|||
|
||||
fn get_receiver_ctx(&self, receiver_name: &str) -> Option<&Context> {
|
||||
self.get_mod(receiver_name)
|
||||
.or_else(|| self.rec_get_type(receiver_name).map(|(_, ctx)| ctx))
|
||||
.or_else(|| self.rec_local_get_type(receiver_name).map(|(_, ctx)| ctx))
|
||||
.or_else(|| {
|
||||
let (_, vi) = self.get_var_info(receiver_name)?;
|
||||
self.get_nominal_type_ctx(&vi.t).map(|(_, ctx)| ctx)
|
||||
|
|
|
@ -1555,6 +1555,16 @@ impl Type {
|
|||
}
|
||||
}
|
||||
|
||||
/// full name of the type, if the type is a normal nominal type, then returns the inner `name`
|
||||
/// ```
|
||||
/// # use erg_compiler::ty::constructors::*;
|
||||
/// let i = mono("Int!");
|
||||
/// assert_eq!(&i.qual_name()[..], "Int!");
|
||||
/// assert_eq!(&i.local_name()[..], "Int!");
|
||||
/// let t = mono("http.client.Response");
|
||||
/// assert_eq!(&t.qual_name()[..], "http.client.Response");
|
||||
/// assert_eq!(&t.local_name()[..], "Response");
|
||||
/// ```
|
||||
pub fn qual_name(&self) -> Str {
|
||||
match self {
|
||||
Self::Obj => Str::ever("Obj"),
|
||||
|
@ -1609,6 +1619,16 @@ impl Type {
|
|||
}
|
||||
}
|
||||
|
||||
/// local name of the type
|
||||
/// ```
|
||||
/// # use erg_compiler::ty::constructors::*;
|
||||
/// let i = mono("Int!");
|
||||
/// assert_eq!(&i.qual_name()[..], "Int!");
|
||||
/// assert_eq!(&i.local_name()[..], "Int!");
|
||||
/// let t = mono("http.client.Response");
|
||||
/// assert_eq!(&t.qual_name()[..], "http.client.Response");
|
||||
/// assert_eq!(&t.local_name()[..], "Response");
|
||||
/// ```
|
||||
pub fn local_name(&self) -> Str {
|
||||
match self {
|
||||
Self::Mono(name) | Self::Poly { name, .. } => {
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
impl = import "../should_ok/impl"
|
||||
|
||||
c = impl.C.new()
|
||||
print! c + 1
|
||||
|
||||
assert c + 1 == 1
|
||||
assert c + 1 == c # ERR
|
||||
assert c + -1 == c
|
||||
assert c + -1 == -1 # ERR
|
||||
|
|
|
@ -202,6 +202,11 @@ fn exec_tests_impl() -> Result<(), ()> {
|
|||
expect_end_with("tests/should_ok/impl.er", 1)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn exec_impl_err() -> Result<(), ()> {
|
||||
expect_failure("tests/should_err/impl.er", 2)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn exec_infer_union_array() -> Result<(), ()> {
|
||||
expect_failure("tests/should_err/infer_union_array.er", 1)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue