fix: failure of the type inference of another module

This commit is contained in:
Shunsuke Shibayama 2023-02-22 11:55:02 +09:00
parent aa2cea60dd
commit 5c4c43ab2f
8 changed files with 119 additions and 59 deletions

View file

@ -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

View file

@ -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());

View file

@ -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
}

View file

@ -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(

View file

@ -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)

View file

@ -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, .. } => {

View file

@ -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

View file

@ -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)