fix: unintended behavior for collections

This commit is contained in:
Shunsuke Shibayama 2023-04-19 18:49:27 +09:00
parent daf01f3cf2
commit 7d7849b493
9 changed files with 66 additions and 17 deletions

View file

@ -2661,13 +2661,27 @@ impl PyCodeGenerator {
self.emit_push_null();
self.emit_load_name_instr(Identifier::public("Str"));
}
other if other.is_array() => {
self.emit_push_null();
self.emit_load_name_instr(Identifier::public("Array"));
}
_ => {
wrapped = false;
}
other => match &other.qual_name()[..] {
"Array" => {
self.emit_push_null();
self.emit_load_name_instr(Identifier::public("Array"));
}
"Dict" => {
self.emit_push_null();
self.emit_load_name_instr(Identifier::public("Dict"));
}
"Set" => {
self.emit_push_null();
self.emit_load_name_instr(Identifier::public("Set"));
}
"Tuple" => {
self.emit_push_null();
self.emit_load_name_instr(Identifier::public("tuple"));
}
_ => {
wrapped = false;
}
},
}
}
match expr {

View file

@ -2160,19 +2160,19 @@ impl Context {
generic_array,
vis.clone(),
Const,
Some(FUNC_LIST),
Some(ARRAY),
);
self.register_builtin_type(arr_t, array_, vis.clone(), Const, Some(FUNC_LIST));
self.register_builtin_type(arr_t, array_, vis.clone(), Const, Some(ARRAY));
self.register_builtin_type(
mono(GENERIC_SET),
generic_set,
vis.clone(),
Const,
Some(FUNC_SET),
Some(SET),
);
self.register_builtin_type(set_t, set_, vis.clone(), Const, Some(FUNC_SET));
self.register_builtin_type(g_dict_t, generic_dict, vis.clone(), Const, Some(FUNC_DICT));
self.register_builtin_type(dict_t, dict_, vis.clone(), Const, Some(FUNC_DICT));
self.register_builtin_type(set_t, set_, vis.clone(), Const, Some(SET));
self.register_builtin_type(g_dict_t, generic_dict, vis.clone(), Const, Some(DICT));
self.register_builtin_type(dict_t, dict_, vis.clone(), Const, Some(DICT));
self.register_builtin_type(mono(BYTES), bytes, vis.clone(), Const, Some(BYTES));
self.register_builtin_type(
mono(GENERIC_TUPLE),

View file

@ -0,0 +1,10 @@
.Set: ClassType
.Set.
copy: |T|(self: .Set(T)) -> .Set(T)
differece: |T|(self: .Set(T), other: .Set(T)) -> .Set(T)
intersection: |T|(self: .Set(T), other: .Set(T)) -> .Set(T)
isdisjoint: |T|(self: .Set(T), other: .Set(T)) -> Bool
issubset: |T|(self: .Set(T), other: .Set(T)) -> Bool
issuperset: |T|(self: .Set(T), other: .Set(T)) -> Bool
symmetric_difference: |T|(self: .Set(T), other: .Set(T)) -> .Set(T)
union: |T|(self: .Set(T), other: .Set(T)) -> .Set(T)

View file

@ -0,0 +1,2 @@
class Dict(dict):
pass

View file

@ -0,0 +1,2 @@
class Set(set):
pass

View file

@ -14,6 +14,8 @@ from _erg_bool import Bool
from _erg_bytes import Bytes
from _erg_str import Str, StrMut
from _erg_array import Array
from _erg_dict import Dict
from _erg_set import Set
from _erg_in_operator import in_operator
from _erg_mutate_operator import mutate_operator

View file

@ -80,15 +80,21 @@ You cannot cast to unrelated types or subtypes with ``as``.
## Forced casting
You can use `typing.cast` to force casting. This can convert the target to any type.
In Python, `typing.cast` does nothing at runtime, but in Erg the conversion will be performed by the constructor. This is to protect type safety.
In Python, `typing.cast` does nothing at runtime, but in Erg the conversion will be performed by the constructor if object's type is built-in[<sup id="f1">1</sup>](#1).
For non-built-in types, the safety is not guaranteed at all.
```python
typing = pyimport "typing"
C = Class { .x = Int }
s = typing.cast Str, 1
assert s == "1"
print! s + "a" # 1a
c = typing.cast C, 1
print! c.x # AttributeError: 'int' object has no attribute 'x'
```
## Downcasting
@ -104,6 +110,10 @@ IntTryFromFloat.
else: Error "conversion failed".
```
---
<span id="1" style="font-size:x-small"><sup>1</sup> This conversion is a byproduct of the current implementation and will be removed in the future. [](#f1) </span>
<p align='center'>
<a href='./16_subtyping.md'>Previous</a> | <a href='./18_mut.md'>Next</a>
</p>

View file

@ -75,8 +75,8 @@ i: Int
i as (Int or Str)
i as (1..10)
i as {I: Int | I >= 0}
```
<p align='center'>
<a href='./15_quantified.md'>Previous</a> | <a href='./17_type_casting.md'>Next</a>
</p>

View file

@ -83,16 +83,21 @@ s = n as Str # ERR
`typing.cast`を使って、型を強制的にキャストすることができます。
これは対象をどんな型にでも変換出来ます。
Pythonの`typing.cast`はランタイムに何も行わない関数ですが、Ergではコンストラクタによる変換が入ります。
これは型安全性を保護するためです
Pythonの`typing.cast`はランタイムに何も行わない関数ですが、Ergでは組み込み型の場合コンストラクタによる変換が入ります[<sup id="f1">1</sup>](#1)
組み込み型でない場合、変換は入らず、安全性の保証は全くありません
```python
typing = pyimport "typing"
C = Class { .x = Int }
s = typing.cast Str, 1
assert s == "1"
print! s + "a" # 1a
c = typing.cast C, 1
print! c.x # AttributeError: 'int' object has no attribute 'x'
```
## ダウンキャスト
@ -108,6 +113,10 @@ IntTryFromFloat.
else: Error "conversion failed"
```
---
<span id="1" style="font-size:x-small"><sup>1</sup> この変換は現状の実装による副産物であり、将来的には除去される。[](#f1) </span>
<p align='center'>
<a href='./16_subtyping.md'>Previous</a> | <a href='./18_mut.md'>Next</a>
</p>