fix: bugs with enumeration of vars

This commit is contained in:
Shunsuke Shibayama 2023-03-06 19:44:49 +09:00
parent b1a9f7bf40
commit fa2919e824
15 changed files with 107 additions and 94 deletions

View file

@ -205,11 +205,20 @@ impl<K: Hash + Eq, V> Dict<K, V> {
self.dict.remove(k) self.dict.remove(k)
} }
/// NOTE: This method does not consider pairing with values and keys. That is, a value may be paired with a different key (can be considered equal).
/// If you need to consider the pairing of the keys and values, use `guaranteed_extend` instead.
#[inline] #[inline]
pub fn extend<I: IntoIterator<Item = (K, V)>>(&mut self, iter: I) { pub fn extend<I: IntoIterator<Item = (K, V)>>(&mut self, iter: I) {
self.dict.extend(iter); self.dict.extend(iter);
} }
#[inline]
pub fn guaranteed_extend<I: IntoIterator<Item = (K, V)>>(&mut self, other: I) {
for (k, v) in other {
self.dict.entry(k).or_insert(v);
}
}
#[inline] #[inline]
pub fn merge(&mut self, other: Self) { pub fn merge(&mut self, other: Self) {
self.dict.extend(other.dict); self.dict.extend(other.dict);
@ -222,9 +231,9 @@ impl<K: Hash + Eq, V> Dict<K, V> {
} }
#[inline] #[inline]
pub fn diff(mut self, other: Self) -> Self { pub fn diff(mut self, other: &Self) -> Self {
for (k, _) in other.dict { for k in other.dict.keys() {
self.dict.remove(&k); self.dict.remove(k);
} }
self self
} }

View file

@ -40,7 +40,7 @@ pub fn levenshtein(a: &str, b: &str, limit: usize) -> Option<usize> {
(dcol[m] <= limit).then_some(dcol[m]) (dcol[m] <= limit).then_some(dcol[m])
} }
pub fn get_similar_name<'a, S: ?Sized, I: Iterator<Item = &'a S> + Clone>( pub fn get_similar_name<'a, S: ?Sized, I: Iterator<Item = &'a S>>(
candidates: I, candidates: I,
name: &str, name: &str,
) -> Option<&'a S> ) -> Option<&'a S>
@ -58,7 +58,7 @@ where
} }
} }
pub fn get_similar_name_and_some<'a, S: ?Sized, T, I: Iterator<Item = (&'a T, &'a S)> + Clone>( pub fn get_similar_name_and_some<'a, S: ?Sized, T, I: Iterator<Item = (&'a T, &'a S)>>(
candidates: I, candidates: I,
name: &str, name: &str,
) -> Option<(&'a T, &'a S)> ) -> Option<(&'a T, &'a S)>

View file

@ -1,4 +1,5 @@
use erg_common::config::ErgConfig; use erg_common::config::ErgConfig;
use erg_common::dict::Dict;
use erg_common::error::MultiErrorDisplay; use erg_common::error::MultiErrorDisplay;
use erg_common::traits::{Runnable, Stream}; use erg_common::traits::{Runnable, Stream};
use erg_common::Str; use erg_common::Str;
@ -100,7 +101,7 @@ impl Buildable for HIRBuilder {
impl BuildRunnable for HIRBuilder {} impl BuildRunnable for HIRBuilder {}
impl ContextProvider for HIRBuilder { impl ContextProvider for HIRBuilder {
fn dir(&self) -> Vec<(&VarName, &VarInfo)> { fn dir(&self) -> Dict<&VarName, &VarInfo> {
self.lowerer.dir() self.lowerer.dir()
} }
@ -157,7 +158,7 @@ impl HIRBuilder {
self.lowerer.pop_mod_ctx() self.lowerer.pop_mod_ctx()
} }
pub fn dir(&mut self) -> Vec<(&VarName, &VarInfo)> { pub fn dir(&mut self) -> Dict<&VarName, &VarInfo> {
ContextProvider::dir(self) ContextProvider::dir(self)
} }

View file

@ -4,12 +4,14 @@
use std::path::Path; use std::path::Path;
use erg_common::config::ErgConfig; use erg_common::config::ErgConfig;
use erg_common::dict::Dict;
use erg_common::error::MultiErrorDisplay; use erg_common::error::MultiErrorDisplay;
use erg_common::log; use erg_common::log;
use erg_common::traits::{Runnable, Stream}; use erg_common::traits::{Runnable, Stream};
use erg_parser::ast::VarName;
use crate::artifact::{CompleteArtifact, ErrorArtifact}; use crate::artifact::{CompleteArtifact, ErrorArtifact};
use crate::context::ContextProvider; use crate::context::{Context, ContextProvider};
use crate::ty::codeobj::CodeObj; use crate::ty::codeobj::CodeObj;
use crate::build_hir::HIRBuilder; use crate::build_hir::HIRBuilder;
@ -19,6 +21,7 @@ use crate::error::{CompileError, CompileErrors, CompileWarnings};
use crate::hir::Expr; use crate::hir::Expr;
use crate::link::Linker; use crate::link::Linker;
use crate::module::{SharedCompilerResource, SharedModuleCache}; use crate::module::{SharedCompilerResource, SharedModuleCache};
use crate::varinfo::VarInfo;
/// * registered as global -> Global /// * registered as global -> Global
/// * defined in the toplevel scope (and called in the inner scope) -> Global /// * defined in the toplevel scope (and called in the inner scope) -> Global
@ -169,12 +172,8 @@ impl Runnable for Compiler {
} }
} }
use crate::context::Context;
use crate::varinfo::VarInfo;
use erg_parser::ast::VarName;
impl ContextProvider for Compiler { impl ContextProvider for Compiler {
fn dir(&self) -> Vec<(&VarName, &VarInfo)> { fn dir(&self) -> Dict<&VarName, &VarInfo> {
self.builder.dir() self.builder.dir()
} }

View file

@ -174,7 +174,6 @@ impl Context {
| (Float | Ratio | Int, Int) | (Float | Ratio | Int, Int)
| (Float | Ratio, Ratio) => (Absolutely, true), | (Float | Ratio, Ratio) => (Absolutely, true),
(Type, ClassType | TraitType) => (Absolutely, true), (Type, ClassType | TraitType) => (Absolutely, true),
(Uninited, _) | (_, Uninited) => panic!("used an uninited type variable"),
( (
Mono(n), Mono(n),
Subr(SubrType { Subr(SubrType {
@ -542,6 +541,7 @@ impl Context {
let nat = Type::Refinement(Nat.into_refinement()); let nat = Type::Refinement(Nat.into_refinement());
self.structural_supertype_of(re, &nat) self.structural_supertype_of(re, &nat)
} }
(Structural(_), Refinement(refine)) => self.supertype_of(lhs, &refine.t),
// Int :> {I: Int | ...} == true // Int :> {I: Int | ...} == true
// Int :> {I: Str| ...} == false // Int :> {I: Str| ...} == false
// Eq({1, 2}) :> {1, 2} (= {I: Int | I == 1 or I == 2}) // Eq({1, 2}) :> {1, 2} (= {I: Int | I == 1 or I == 2})
@ -694,7 +694,6 @@ impl Context {
} }
} }
// TODO: we need consider duplicating keys
pub fn fields(&self, t: &Type) -> Dict<Field, Type> { pub fn fields(&self, t: &Type) -> Dict<Field, Type> {
match t { match t {
Type::FreeVar(fv) if fv.is_linked() => self.fields(&fv.crack()), Type::FreeVar(fv) if fv.is_linked() => self.fields(&fv.crack()),
@ -702,10 +701,10 @@ impl Context {
Type::Refinement(refine) => self.fields(&refine.t), Type::Refinement(refine) => self.fields(&refine.t),
Type::Structural(t) => self.fields(t), Type::Structural(t) => self.fields(t),
other => { other => {
let (_, ctx) = self let Some((_, ctx)) = self.get_nominal_type_ctx(other) else {
.get_nominal_type_ctx(other) return Dict::new();
.unwrap_or_else(|| panic!("{other} is not found")); };
ctx.type_dir() ctx.type_dir(self)
.into_iter() .into_iter()
.map(|(name, vi)| { .map(|(name, vi)| {
( (
@ -993,7 +992,7 @@ impl Context {
// not {i = Int} and {i = Int; j = Int} == {j = Int} // not {i = Int} and {i = Int; j = Int} == {j = Int}
(other @ Record(rec), Not(t)) | (Not(t), other @ Record(rec)) => match t.as_ref() { (other @ Record(rec), Not(t)) | (Not(t), other @ Record(rec)) => match t.as_ref() {
Type::FreeVar(fv) => self.intersection(&fv.crack(), other), Type::FreeVar(fv) => self.intersection(&fv.crack(), other),
Type::Record(rec2) => Type::Record(rec.clone().diff(rec2.clone())), Type::Record(rec2) => Type::Record(rec.clone().diff(rec2)),
_ => Type::Never, _ => Type::Never,
}, },
(l, r) if self.is_trait(l) && self.is_trait(r) => and(l.clone(), r.clone()), (l, r) if self.is_trait(l) && self.is_trait(r) => and(l.clone(), r.clone()),

View file

@ -85,20 +85,8 @@ impl Context {
Visibility::BUILTIN_PUBLIC, Visibility::BUILTIN_PUBLIC,
ValueObj::Float(2.220446049250313e-16), ValueObj::Float(2.220446049250313e-16),
); );
float.register_builtin_py_impl( float.register_builtin_py_impl(REAL, Float, Const, Visibility::BUILTIN_PUBLIC, Some(REAL));
REAL, float.register_builtin_py_impl(IMAG, Float, Const, Visibility::BUILTIN_PUBLIC, Some(IMAG));
Float,
Const,
Visibility::BUILTIN_PUBLIC,
Some(FUNC_REAL),
);
float.register_builtin_py_impl(
IMAG,
Float,
Const,
Visibility::BUILTIN_PUBLIC,
Some(FUNC_IMAG),
);
float.register_py_builtin( float.register_py_builtin(
FUNC_AS_INTEGER_RATIO, FUNC_AS_INTEGER_RATIO,
fn0_met(Float, tuple_t(vec![Int, Int])), fn0_met(Float, tuple_t(vec![Int, Int])),
@ -124,6 +112,10 @@ impl Context {
Some(FUNC_FROMHEX), Some(FUNC_FROMHEX),
53, 53,
); );
float.register_py_builtin(OP_GT, fn1_met(Float, Float, Bool), Some(OP_GT), 0);
float.register_py_builtin(OP_GE, fn1_met(Float, Float, Bool), Some(OP_GE), 0);
float.register_py_builtin(OP_LT, fn1_met(Float, Float, Bool), Some(OP_LT), 0);
float.register_py_builtin(OP_LE, fn1_met(Float, Float, Bool), Some(OP_LE), 0);
float.register_marker_trait(mono(NUM)); float.register_marker_trait(mono(NUM));
float.register_marker_trait(mono(ORD)); float.register_marker_trait(mono(ORD));
let mut float_ord = Self::builtin_methods(Some(mono(ORD)), 2); let mut float_ord = Self::builtin_methods(Some(mono(ORD)), 2);
@ -250,20 +242,8 @@ impl Context {
// TODO: Int, Nat, Boolの継承元をRatioにする(今はFloat) // TODO: Int, Nat, Boolの継承元をRatioにする(今はFloat)
let mut ratio = Self::builtin_mono_class(RATIO, 2); let mut ratio = Self::builtin_mono_class(RATIO, 2);
ratio.register_superclass(Obj, &obj); ratio.register_superclass(Obj, &obj);
ratio.register_builtin_py_impl( ratio.register_builtin_py_impl(REAL, Ratio, Const, Visibility::BUILTIN_PUBLIC, Some(REAL));
REAL, ratio.register_builtin_py_impl(IMAG, Ratio, Const, Visibility::BUILTIN_PUBLIC, Some(IMAG));
Ratio,
Const,
Visibility::BUILTIN_PUBLIC,
Some(FUNC_REAL),
);
ratio.register_builtin_py_impl(
IMAG,
Ratio,
Const,
Visibility::BUILTIN_PUBLIC,
Some(FUNC_IMAG),
);
ratio.register_marker_trait(mono(NUM)); ratio.register_marker_trait(mono(NUM));
ratio.register_marker_trait(mono(ORD)); ratio.register_marker_trait(mono(ORD));
let mut ratio_ord = Self::builtin_methods(Some(mono(ORD)), 2); let mut ratio_ord = Self::builtin_methods(Some(mono(ORD)), 2);
@ -513,20 +493,8 @@ impl Context {
Some(FUNDAMENTAL_STR), Some(FUNDAMENTAL_STR),
); );
int.register_trait(Int, int_show); int.register_trait(Int, int_show);
int.register_builtin_py_impl( int.register_builtin_py_impl(REAL, Int, Const, Visibility::BUILTIN_PUBLIC, Some(REAL));
REAL, int.register_builtin_py_impl(IMAG, Int, Const, Visibility::BUILTIN_PUBLIC, Some(IMAG));
Int,
Const,
Visibility::BUILTIN_PUBLIC,
Some(FUNC_REAL),
);
int.register_builtin_py_impl(
IMAG,
Int,
Const,
Visibility::BUILTIN_PUBLIC,
Some(FUNC_IMAG),
);
/* Nat */ /* Nat */
let mut nat = Self::builtin_mono_class(NAT, 10); let mut nat = Self::builtin_mono_class(NAT, 10);

View file

@ -100,10 +100,8 @@ const BYTES: &str = "Bytes";
const FLOAT: &str = "Float"; const FLOAT: &str = "Float";
const MUT_FLOAT: &str = "Float!"; const MUT_FLOAT: &str = "Float!";
const EPSILON: &str = "EPSILON"; const EPSILON: &str = "EPSILON";
const REAL: &str = "Real"; const REAL: &str = "real";
const FUNC_REAL: &str = "real"; const IMAG: &str = "imag";
const IMAG: &str = "Imag";
const FUNC_IMAG: &str = "imag";
const FUNC_AS_INTEGER_RATIO: &str = "as_integer_ratio"; const FUNC_AS_INTEGER_RATIO: &str = "as_integer_ratio";
const FUNC_CONJUGATE: &str = "conjugate"; const FUNC_CONJUGATE: &str = "conjugate";
const FUNC_IS_INTEGER: &str = "is_integer"; const FUNC_IS_INTEGER: &str = "is_integer";

View file

@ -396,6 +396,25 @@ impl Context {
mode: RegistrationMode, mode: RegistrationMode,
kind: ParamKind, kind: ParamKind,
) -> TyCheckResult<ParamTy> { ) -> TyCheckResult<ParamTy> {
if let Some(value) = sig
.name()
.and_then(|name| self.get_const_local(name.token(), &self.name).ok())
{
return Ok(ParamTy::pos(None, v_enum(set! { value })));
} else if let Some(tp) = sig.name().and_then(|name| {
self.instantiate_local(name.inspect(), None, tmp_tv_cache, sig)
.ok()
}) {
match tp {
TyParam::Type(t) => return Ok(ParamTy::pos(None, *t)),
other => {
return Ok(ParamTy::pos(
None,
tp_enum(self.get_tp_t(&other)?, set! { other }),
))
}
}
}
let t = self.instantiate_param_sig_t(sig, opt_decl_t, tmp_tv_cache, mode, kind.clone())?; let t = self.instantiate_param_sig_t(sig, opt_decl_t, tmp_tv_cache, mode, kind.clone())?;
match (sig.inspect(), kind) { match (sig.inspect(), kind) {
(Some(name), ParamKind::Default(default_t)) => { (Some(name), ParamKind::Default(default_t)) => {

View file

@ -43,7 +43,7 @@ use Type::*;
/// For implementing LSP or other IDE features /// For implementing LSP or other IDE features
pub trait ContextProvider { pub trait ContextProvider {
fn dir(&self) -> Vec<(&VarName, &VarInfo)>; fn dir(&self) -> Dict<&VarName, &VarInfo>;
fn get_receiver_ctx(&self, receiver_name: &str) -> Option<&Context>; fn get_receiver_ctx(&self, receiver_name: &str) -> Option<&Context>;
fn get_var_info(&self, name: &str) -> Option<(&VarName, &VarInfo)>; fn get_var_info(&self, name: &str) -> Option<(&VarName, &VarInfo)>;
} }
@ -411,12 +411,12 @@ impl fmt::Display for Context {
} }
impl ContextProvider for Context { impl ContextProvider for Context {
fn dir(&self) -> Vec<(&VarName, &VarInfo)> { fn dir(&self) -> Dict<&VarName, &VarInfo> {
let mut vars = self.type_dir(); let mut vars = self.type_dir(self);
if let Some(outer) = self.get_outer() { if let Some(outer) = self.get_outer() {
vars.extend(outer.dir()); vars.guaranteed_extend(outer.dir());
} else if let Some(builtins) = self.get_builtins() { } else if let Some(builtins) = self.get_builtins() {
vars.extend(builtins.locals.iter()); vars.guaranteed_extend(builtins.locals.iter());
} }
vars vars
} }
@ -439,7 +439,7 @@ impl ContextProvider for Context {
} }
impl Context { impl Context {
pub fn dir(&self) -> Vec<(&VarName, &VarInfo)> { pub fn dir(&self) -> Dict<&VarName, &VarInfo> {
ContextProvider::dir(self) ContextProvider::dir(self)
} }
@ -1013,24 +1013,25 @@ impl Context {
} }
/// enumerates all the variables/methods in the current context & super contexts. /// enumerates all the variables/methods in the current context & super contexts.
fn type_dir(&self) -> Vec<(&VarName, &VarInfo)> { fn type_dir<'t>(&'t self, namespace: &'t Context) -> Dict<&VarName, &VarInfo> {
let mut vars: Vec<_> = self let mut attrs = self.locals.iter().collect::<Dict<_, _>>();
.locals attrs.guaranteed_extend(
.iter() self.params
.chain(self.decls.iter()) .iter()
.chain( .filter_map(|(k, v)| k.as_ref().map(|k| (k, v))),
self.params );
.iter() attrs.guaranteed_extend(self.decls.iter());
.filter_map(|(k, v)| k.as_ref().map(|k| (k, v))), attrs.guaranteed_extend(
) self.methods_list
.chain(self.methods_list.iter().flat_map(|(_, ctx)| ctx.type_dir())) .iter()
.collect(); .flat_map(|(_, ctx)| ctx.type_dir(namespace)),
);
for sup in self.super_classes.iter() { for sup in self.super_classes.iter() {
if let Some((_, sup_ctx)) = self.get_nominal_type_ctx(sup) { if let Some((_, sup_ctx)) = namespace.get_nominal_type_ctx(sup) {
vars.extend(sup_ctx.type_dir()); attrs.guaranteed_extend(sup_ctx.type_dir(namespace));
} }
} }
vars attrs
} }
pub(crate) fn mod_cache(&self) -> &SharedModuleCache { pub(crate) fn mod_cache(&self) -> &SharedModuleCache {

View file

@ -5,6 +5,7 @@ use std::mem;
use erg_common::config::{ErgConfig, ErgMode}; use erg_common::config::{ErgConfig, ErgMode};
use erg_common::dict; use erg_common::dict;
use erg_common::dict::Dict;
use erg_common::error::{Location, MultiErrorDisplay}; use erg_common::error::{Location, MultiErrorDisplay};
use erg_common::set; use erg_common::set;
use erg_common::set::Set; use erg_common::set::Set;
@ -124,7 +125,7 @@ impl Runnable for ASTLowerer {
} }
impl ContextProvider for ASTLowerer { impl ContextProvider for ASTLowerer {
fn dir(&self) -> Vec<(&VarName, &VarInfo)> { fn dir(&self) -> Dict<&VarName, &VarInfo> {
self.module.context.dir() self.module.context.dir()
} }
@ -176,7 +177,7 @@ impl ASTLowerer {
&self.module &self.module
} }
pub fn dir(&self) -> Vec<(&VarName, &VarInfo)> { pub fn dir(&self) -> Dict<&VarName, &VarInfo> {
ContextProvider::dir(self) ContextProvider::dir(self)
} }

View file

@ -2,6 +2,7 @@ use std::fs::File;
use std::io::Write; use std::io::Write;
use erg_common::config::ErgConfig; use erg_common::config::ErgConfig;
use erg_common::dict::Dict as HashMap;
use erg_common::error::MultiErrorDisplay; use erg_common::error::MultiErrorDisplay;
use erg_common::log; use erg_common::log;
use erg_common::traits::{Runnable, Stream}; use erg_common::traits::{Runnable, Stream};
@ -167,7 +168,7 @@ impl Runnable for Transpiler {
} }
impl ContextProvider for Transpiler { impl ContextProvider for Transpiler {
fn dir(&self) -> Vec<(&VarName, &VarInfo)> { fn dir(&self) -> HashMap<&VarName, &VarInfo> {
self.builder.dir() self.builder.dir()
} }
@ -238,7 +239,7 @@ impl Transpiler {
self.builder.pop_mod_ctx() self.builder.pop_mod_ctx()
} }
pub fn dir(&mut self) -> Vec<(&VarName, &VarInfo)> { pub fn dir(&mut self) -> HashMap<&VarName, &VarInfo> {
ContextProvider::dir(self) ContextProvider::dir(self)
} }

View file

@ -273,6 +273,13 @@ Option T: Type = T or NoneType
Option: Type -> Type Option: Type -> Type
``` ```
Compile-time function parameters must have different names from any constants already defined. If the names are the same, it will be interpreted as a constant pattern.
```python
# Int is not a parameter but a constant (type Int)
K Int = None
```
## Appendix: Function Comparison ## Appendix: Function Comparison
Erg does not define `==` for functions. This is because there is no structural equivalence algorithm for functions in general. Erg does not define `==` for functions. This is because there is no structural equivalence algorithm for functions in general.

View file

@ -277,6 +277,13 @@ Option T: Type = T or NoneType
Option: Type -> Type Option: Type -> Type
``` ```
コンパイル時関数の仮引数は、既に定義されている如何なる定数とも違う名前である必要があります。名前が被った場合、定数パターンとして解釈されます。
```python
# Intは仮引数ではない。型Intのみを引数にとる関数
K Int = None
```
## 付録1: 関数の比較 ## 付録1: 関数の比較
Ergでは、関数に`==`が定義されていません。それは関数の構造的な同値性判定アルゴリズムが一般には存在しないためです。 Ergでは、関数に`==`が定義されていません。それは関数の構造的な同値性判定アルゴリズムが一般には存在しないためです。

View file

@ -12,3 +12,6 @@ x = _add 1, 2
y = _add x, 2 y = _add x, 2
z = _add y, 2 z = _add y, 2
assert z == 7 assert z == 7
w = _add -1, 2
assert w == 1

View file

@ -157,13 +157,13 @@ fn exec_return() -> Result<(), ()> {
} }
#[test] #[test]
fn exec_structural() -> Result<(), ()> { fn exec_structural_example() -> Result<(), ()> {
expect_success("examples/structural.er") expect_success("examples/structural.er")
} }
#[test] #[test]
fn exec_structural_test() -> Result<(), ()> { fn exec_structural() -> Result<(), ()> {
expect_success("tests/should_ok/structural_test.er") expect_success("tests/should_ok/structural.er")
} }
#[test] #[test]