diff --git a/docs/types.rst b/docs/types.rst index d669e6946d..0ad13967e9 100644 --- a/docs/types.rst +++ b/docs/types.rst @@ -376,22 +376,22 @@ On the ABI level the Fixed-size bytes array is annotated as ``string``. example_str: String[100] = "Test String" -Enums +Flags ----- -**Keyword:** ``enum`` +**Keyword:** ``flag`` -Enums are custom defined types. An enum must have at least one member, and can hold up to a maximum of 256 members. +Flags are custom defined types. A flag must have at least one member, and can hold up to a maximum of 256 members. The members are represented by ``uint256`` values in the form of 2\ :sup:`n` where ``n`` is the index of the member in the range ``0 <= n <= 255``. .. code-block:: python - # Defining an enum with two members - enum Roles: + # Defining a flag with two members + flag Roles: ADMIN USER - # Declaring an enum variable + # Declaring a flag variable role: Roles = Roles.ADMIN # Returning a member @@ -426,13 +426,13 @@ Operator Description ``~x`` Bitwise not ============= ====================== -Enum members can be combined using the above bitwise operators. While enum members have values that are power of two, enum member combinations may not. +Flag members can be combined using the above bitwise operators. While flag members have values that are power of two, flag member combinations may not. -The ``in`` and ``not in`` operators can be used in conjunction with enum member combinations to check for membership. +The ``in`` and ``not in`` operators can be used in conjunction with flag member combinations to check for membership. .. code-block:: python - enum Roles: + flag Roles: MANAGER ADMIN USER @@ -447,7 +447,7 @@ The ``in`` and ``not in`` operators can be used in conjunction with enum member def bar(a: Roles) -> bool: return a not in (Roles.MANAGER | Roles.USER) -Note that ``in`` is not the same as strict equality (``==``). ``in`` checks that *any* of the flags on two enum objects are simultaneously set, while ``==`` checks that two enum objects are bit-for-bit equal. +Note that ``in`` is not the same as strict equality (``==``). ``in`` checks that *any* of the flags on two flag objects are simultaneously set, while ``==`` checks that two flag objects are bit-for-bit equal. The following code uses bitwise operations to add and revoke permissions from a given ``Roles`` object. @@ -488,7 +488,7 @@ Fixed-size Lists Fixed-size lists hold a finite number of elements which belong to a specified type. -Lists can be declared with ``_name: _ValueType[_Integer]``, except ``Bytes[N]``, ``String[N]`` and enums. +Lists can be declared with ``_name: _ValueType[_Integer]``, except ``Bytes[N]``, ``String[N]`` and flags. .. code-block:: python diff --git a/tests/functional/builtins/codegen/test_convert.py b/tests/functional/builtins/codegen/test_convert.py index b5ce613235..99dae4a932 100644 --- a/tests/functional/builtins/codegen/test_convert.py +++ b/tests/functional/builtins/codegen/test_convert.py @@ -486,10 +486,10 @@ def test_memory_variable_convert(x: {i_typ}) -> {o_typ}: @pytest.mark.parametrize("typ", ["uint8", "int128", "int256", "uint256"]) @pytest.mark.parametrize("val", [1, 2, 2**128, 2**256 - 1, 2**256 - 2]) -def test_enum_conversion(get_contract_with_gas_estimation, assert_compile_failed, val, typ): +def test_flag_conversion(get_contract_with_gas_estimation, assert_compile_failed, val, typ): roles = "\n ".join([f"ROLE_{i}" for i in range(256)]) contract = f""" -enum Roles: +flag Roles: {roles} @external @@ -510,11 +510,11 @@ def bar(a: uint256) -> Roles: @pytest.mark.parametrize("typ", ["uint8", "int128", "int256", "uint256"]) @pytest.mark.parametrize("val", [1, 2, 3, 4, 2**128, 2**256 - 1, 2**256 - 2]) -def test_enum_conversion_2( +def test_flag_conversion_2( get_contract_with_gas_estimation, assert_compile_failed, assert_tx_failed, val, typ ): contract = f""" -enum Status: +flag Status: STARTED PAUSED STOPPED diff --git a/tests/functional/codegen/features/test_assignment.py b/tests/functional/codegen/features/test_assignment.py index cd26659a5c..9af7058250 100644 --- a/tests/functional/codegen/features/test_assignment.py +++ b/tests/functional/codegen/features/test_assignment.py @@ -66,7 +66,7 @@ def bar(x: {typ}) -> {typ}: def test_internal_assign_struct(get_contract_with_gas_estimation): code = """ -enum Bar: +flag Bar: BAD BAK BAZ @@ -92,7 +92,7 @@ def bar(x: Foo) -> Foo: def test_internal_assign_struct_member(get_contract_with_gas_estimation): code = """ -enum Bar: +flag Bar: BAD BAK BAZ diff --git a/tests/functional/codegen/features/test_clampers.py b/tests/functional/codegen/features/test_clampers.py index ad7ea32b1e..2f7e57a8da 100644 --- a/tests/functional/codegen/features/test_clampers.py +++ b/tests/functional/codegen/features/test_clampers.py @@ -184,9 +184,9 @@ def foo(s: bool) -> bool: @pytest.mark.parametrize("evm_version", list(EVM_VERSIONS)) @pytest.mark.parametrize("value", [0] + [2**i for i in range(5)]) -def test_enum_clamper_passing(w3, get_contract, value, evm_version): +def test_flag_clamper_passing(w3, get_contract, value, evm_version): code = """ -enum Roles: +flag Roles: USER STAFF ADMIN @@ -204,9 +204,9 @@ def foo(s: Roles) -> Roles: @pytest.mark.parametrize("evm_version", list(EVM_VERSIONS)) @pytest.mark.parametrize("value", [2**i for i in range(5, 256)]) -def test_enum_clamper_failing(w3, assert_tx_failed, get_contract, value, evm_version): +def test_flag_clamper_failing(w3, assert_tx_failed, get_contract, value, evm_version): code = """ -enum Roles: +flag Roles: USER STAFF ADMIN diff --git a/tests/functional/codegen/types/test_dynamic_array.py b/tests/functional/codegen/types/test_dynamic_array.py index 9231d1979f..d793a56d6e 100644 --- a/tests/functional/codegen/types/test_dynamic_array.py +++ b/tests/functional/codegen/types/test_dynamic_array.py @@ -102,7 +102,7 @@ def foo6() -> DynArray[DynArray[String[32], 2], 2]: def test_list_output_tester_code(get_contract_with_gas_estimation): list_output_tester_code = """ -enum Foobar: +flag Foobar: FOO BAR @@ -1247,13 +1247,13 @@ def test_append_pop_complex(get_contract, assert_tx_failed, code_template, check """ code = struct_def + "\n" + code elif subtype == "DynArray[Foobar, 3]": - enum_def = """ -enum Foobar: + flag_def = """ +flag Foobar: FOO BAR BAZ """ - code = enum_def + "\n" + code + code = flag_def + "\n" + code test_data = [2 ** (i - 1) for i in test_data] c = get_contract(code) @@ -1292,7 +1292,7 @@ def foo() -> (uint256, DynArray[uint256, 3], DynArray[uint256, 2]): def test_list_of_structs_arg(get_contract): code = """ -enum Foobar: +flag Foobar: FOO BAR diff --git a/tests/functional/codegen/types/test_enum.py b/tests/functional/codegen/types/test_flag.py similarity index 93% rename from tests/functional/codegen/types/test_enum.py rename to tests/functional/codegen/types/test_flag.py index c66efff566..03c22134ed 100644 --- a/tests/functional/codegen/types/test_enum.py +++ b/tests/functional/codegen/types/test_flag.py @@ -1,6 +1,6 @@ def test_values_should_be_increasing_ints(get_contract): code = """ -enum Action: +flag Action: BUY SELL CANCEL @@ -26,9 +26,9 @@ def cancel() -> Action: assert c.cancel() == 4 -def test_enum_storage(get_contract): +def test_flag_storage(get_contract): code = """ -enum Actions: +flag Actions: BUY SELL CANCEL @@ -49,7 +49,7 @@ def set_and_get(a: Actions) -> Actions: def test_eq_neq(get_contract): code = """ -enum Roles: +flag Roles: USER STAFF ADMIN @@ -76,7 +76,7 @@ def is_not_boss(a: Roles) -> bool: def test_bitwise(get_contract, assert_tx_failed): code = """ -enum Roles: +flag Roles: USER STAFF ADMIN @@ -147,7 +147,7 @@ def binv_arg(a: Roles) -> Roles: def test_augassign_storage(get_contract, w3, assert_tx_failed): code = """ -enum Roles: +flag Roles: ADMIN MINTER @@ -214,9 +214,9 @@ def checkMinter(minter: address): assert_tx_failed(lambda: c.checkMinter(admin_address)) -def test_in_enum(get_contract_with_gas_estimation): +def test_in_flag(get_contract_with_gas_estimation): code = """ -enum Roles: +flag Roles: USER STAFF ADMIN @@ -259,9 +259,9 @@ def baz(a: Roles) -> bool: assert c.baz(0b01000) is False # Roles.MANAGER should fail -def test_struct_with_enum(get_contract_with_gas_estimation): +def test_struct_with_flag(get_contract_with_gas_estimation): code = """ -enum Foobar: +flag Foobar: FOO BAR @@ -270,17 +270,17 @@ def test_struct_with_enum(get_contract_with_gas_estimation): b: Foobar @external -def get_enum_from_struct() -> Foobar: +def get_flag_from_struct() -> Foobar: f: Foo = Foo({a: 1, b: Foobar.BAR}) return f.b """ c = get_contract_with_gas_estimation(code) - assert c.get_enum_from_struct() == 2 + assert c.get_flag_from_struct() == 2 -def test_mapping_with_enum(get_contract_with_gas_estimation): +def test_mapping_with_flag(get_contract_with_gas_estimation): code = """ -enum Foobar: +flag Foobar: FOO BAR diff --git a/tests/functional/syntax/test_dynamic_array.py b/tests/functional/syntax/test_dynamic_array.py index 0c23bf67da..99a01a17c8 100644 --- a/tests/functional/syntax/test_dynamic_array.py +++ b/tests/functional/syntax/test_dynamic_array.py @@ -34,12 +34,12 @@ def test_block_fail(assert_compile_failed, get_contract, bad_code, exc): valid_list = [ """ -enum Foo: +flag Foo: FE FI bar: DynArray[Foo, 10] - """, # dynamic arrays of enums are allowed, but not static arrays + """, # dynamic arrays of flags are allowed, but not static arrays """ bar: DynArray[Bytes[30], 10] """, # dynamic arrays of bytestrings are allowed, but not static arrays diff --git a/tests/functional/syntax/test_enum.py b/tests/functional/syntax/test_flag.py similarity index 74% rename from tests/functional/syntax/test_enum.py rename to tests/functional/syntax/test_flag.py index 9bb74fb675..22309502b7 100644 --- a/tests/functional/syntax/test_enum.py +++ b/tests/functional/syntax/test_flag.py @@ -2,7 +2,7 @@ from vyper import compiler from vyper.exceptions import ( - EnumDeclarationException, + FlagDeclarationException, InvalidOperation, NamespaceCollision, StructureException, @@ -16,7 +16,7 @@ event Action: pass -enum Action: +flag Action: BUY SELL """, @@ -24,23 +24,23 @@ ), ( """ -enum Action: +flag Action: pass """, - EnumDeclarationException, + FlagDeclarationException, ), ( """ -enum Action: +flag Action: BUY BUY """, - EnumDeclarationException, + FlagDeclarationException, ), - ("enum Foo:\n" + "\n".join([f" member{i}" for i in range(257)]), EnumDeclarationException), + ("flag Foo:\n" + "\n".join([f" member{i}" for i in range(257)]), FlagDeclarationException), ( """ -enum Roles: +flag Roles: USER STAFF ADMIN @@ -53,20 +53,20 @@ def foo(x: Roles) -> bool: ), ( """ -enum Roles: +flag Roles: USER STAFF ADMIN @external def foo(x: Roles) -> Roles: - return x.USER # can't dereference on enum instance + return x.USER # can't dereference on flag instance """, StructureException, ), ( """ -enum Roles: +flag Roles: USER STAFF ADMIN @@ -79,28 +79,28 @@ def foo(x: Roles) -> bool: ), ( """ -enum Functions: +flag Functions: def foo():nonpayable """, - EnumDeclarationException, + FlagDeclarationException, ), ( """ -enum Numbers: +flag Numbers: a:constant(uint256) = a """, - EnumDeclarationException, + FlagDeclarationException, ), ( """ -enum Numbers: +flag Numbers: 12 """, - EnumDeclarationException, + FlagDeclarationException, ), ( """ -enum Roles: +flag Roles: ADMIN USER @@ -112,9 +112,9 @@ def foo() -> Roles: ), ( """ -enum A: +flag A: a -enum B: +flag B: a b @@ -135,12 +135,12 @@ def test_fail_cases(bad_code): valid_list = [ """ -enum Action: +flag Action: BUY SELL """, """ -enum Action: +flag Action: BUY SELL @external @@ -148,7 +148,7 @@ def run() -> Action: return Action.BUY """, """ -enum Action: +flag Action: BUY SELL @@ -163,16 +163,16 @@ def run() -> Order: amount: 10**18 }) """, - "enum Foo:\n" + "\n".join([f" member{i}" for i in range(256)]), + "flag Foo:\n" + "\n".join([f" member{i}" for i in range(256)]), """ a: constant(uint256) = 1 -enum A: +flag A: a """, ] @pytest.mark.parametrize("good_code", valid_list) -def test_enum_success(good_code): +def test_flag_success(good_code): assert compiler.compile_code(good_code) is not None diff --git a/tests/functional/syntax/test_public.py b/tests/functional/syntax/test_public.py index 68575ebd41..71bff753f4 100644 --- a/tests/functional/syntax/test_public.py +++ b/tests/functional/syntax/test_public.py @@ -30,9 +30,9 @@ def foo() -> int128: x: public(HashMap[uint256, Foo]) """, - # expansion of public user-defined enum + # expansion of public user-defined flag """ -enum Foo: +flag Foo: BAR x: public(HashMap[uint256, Foo]) diff --git a/vyper/ast/folding.py b/vyper/ast/folding.py index 38d58f6fd0..087708a356 100644 --- a/vyper/ast/folding.py +++ b/vyper/ast/folding.py @@ -246,7 +246,7 @@ def replace_constant( continue # do not replace enum members - if node.get_ancestor(vy_ast.EnumDef): + if node.get_ancestor(vy_ast.FlagDef): continue try: diff --git a/vyper/ast/grammar.lark b/vyper/ast/grammar.lark index 15367ce94a..7889473b19 100644 --- a/vyper/ast/grammar.lark +++ b/vyper/ast/grammar.lark @@ -10,7 +10,8 @@ module: ( DOCSTRING | interface_def | constant_def | variable_def - | enum_def + | enum_def // TODO deprecate at some point in favor of flag + | flag_def | event_def | function_def | immutable_def @@ -76,12 +77,19 @@ indexed_event_arg: NAME ":" "indexed" "(" type ")" event_body: _NEWLINE _INDENT (((event_member | indexed_event_arg ) _NEWLINE)+ | _PASS _NEWLINE) _DEDENT event_def: _EVENT_DECL NAME ":" ( event_body | _PASS ) +// TODO deprecate in favor of flag // Enums _ENUM_DECL: "enum" enum_member: NAME enum_body: _NEWLINE _INDENT (enum_member _NEWLINE)+ _DEDENT enum_def: _ENUM_DECL NAME ":" enum_body +// Flags +_FLAG_DECL: "flag" +flag_member: NAME +flag_body: _NEWLINE _INDENT (flag_member _NEWLINE)+ _DEDENT +flag_def: _FLAG_DECL NAME ":" flag_body + // Types array_def: (NAME | array_def | dyn_array_def) "[" _expr "]" dyn_array_def: "DynArray" "[" (NAME | array_def | dyn_array_def) "," _expr "]" diff --git a/vyper/ast/identifiers.py b/vyper/ast/identifiers.py index 985b04e5cd..7d42727066 100644 --- a/vyper/ast/identifiers.py +++ b/vyper/ast/identifiers.py @@ -69,6 +69,7 @@ def validate_identifier(attr, ast_node=None): "struct", "event", "enum", + "flag" # EVM operations "unreachable", # special functions (no name mangling) diff --git a/vyper/ast/nodes.py b/vyper/ast/nodes.py index 3bccc5f141..dba9f2a22d 100644 --- a/vyper/ast/nodes.py +++ b/vyper/ast/nodes.py @@ -4,6 +4,7 @@ import decimal import operator import sys +import warnings from typing import Any, Optional, Union from vyper.ast.metadata import NodeMetadata @@ -18,6 +19,7 @@ SyntaxException, TypeMismatch, UnfoldableNode, + VyperException, ZeroDivisionException, ) from vyper.utils import MAX_DECIMAL_PLACES, SizeLimits, annotate_source_code @@ -78,6 +80,11 @@ def get_node( else: ast_struct["ast_type"] = "VariableDecl" + enum_warn = False + if ast_struct["ast_type"] == "EnumDef": + enum_warn = True + ast_struct["ast_type"] = "FlagDef" + vy_class = getattr(sys.modules[__name__], ast_struct["ast_type"], None) if not vy_class: if ast_struct["ast_type"] == "Delete": @@ -92,7 +99,17 @@ def get_node( ast_struct, ) - return vy_class(parent=parent, **ast_struct) + node = vy_class(parent=parent, **ast_struct) + + # TODO: Putting this after node creation to pretty print, remove after enum deprecation + if enum_warn: + # TODO: hack to pretty print, logic should be factored out of exception + pretty_printed_node = str(VyperException("", node)) + warnings.warn( + f"enum will be deprecated in a future release, use flag instead. {pretty_printed_node}", + stacklevel=2, + ) + return node def compare_nodes(left_node: "VyperNode", right_node: "VyperNode") -> bool: @@ -725,7 +742,7 @@ class Log(Stmt): __slots__ = ("value",) -class EnumDef(TopLevel): +class FlagDef(TopLevel): __slots__ = ("name", "body") diff --git a/vyper/ast/nodes.pyi b/vyper/ast/nodes.pyi index 05784aed0f..47856b6021 100644 --- a/vyper/ast/nodes.pyi +++ b/vyper/ast/nodes.pyi @@ -81,7 +81,7 @@ class Return(VyperNode): ... class Log(VyperNode): value: VyperNode = ... -class EnumDef(VyperNode): +class FlagDef(VyperNode): body: list = ... name: str = ... diff --git a/vyper/ast/pre_parser.py b/vyper/ast/pre_parser.py index 9d96efea5e..b949a242bb 100644 --- a/vyper/ast/pre_parser.py +++ b/vyper/ast/pre_parser.py @@ -44,7 +44,8 @@ def validate_version_pragma(version_str: str, start: ParserPosition) -> None: # compound statements that are replaced with `class` -VYPER_CLASS_TYPES = {"enum", "event", "interface", "struct"} +# TODO remove enum in favor of flag +VYPER_CLASS_TYPES = {"flag", "enum", "event", "interface", "struct"} # simple statements or expressions that are replaced with `yield` VYPER_EXPRESSION_TYPES = {"log"} @@ -55,7 +56,7 @@ def pre_parse(code: str) -> tuple[Settings, ModificationOffsets, str]: Re-formats a vyper source string into a python source string and performs some validation. More specifically, - * Translates "interface", "struct", "enum, and "event" keywords into python "class" keyword + * Translates "interface", "struct", "flag", and "event" keywords into python "class" keyword * Validates "@version" pragma against current compiler version * Prevents direct use of python "class" keyword * Prevents use of python semi-colon statement separator diff --git a/vyper/builtins/_convert.py b/vyper/builtins/_convert.py index e09f5f3174..998cbbc9f6 100644 --- a/vyper/builtins/_convert.py +++ b/vyper/builtins/_convert.py @@ -14,7 +14,7 @@ int_clamp, is_bytes_m_type, is_decimal_type, - is_enum_type, + is_flag_type, is_integer_type, sar, shl, @@ -35,7 +35,7 @@ BytesM_T, BytesT, DecimalT, - EnumT, + FlagT, IntegerT, StringT, ) @@ -277,7 +277,7 @@ def to_bool(expr, arg, out_typ): return IRnode.from_list(["iszero", ["iszero", arg]], typ=out_typ) -@_input_types(IntegerT, DecimalT, BytesM_T, AddressT, BoolT, EnumT, BytesT) +@_input_types(IntegerT, DecimalT, BytesM_T, AddressT, BoolT, FlagT, BytesT) def to_int(expr, arg, out_typ): return _to_int(expr, arg, out_typ) @@ -305,7 +305,7 @@ def _to_int(expr, arg, out_typ): elif is_decimal_type(arg.typ): arg = _fixed_to_int(arg, out_typ) - elif is_enum_type(arg.typ): + elif is_flag_type(arg.typ): if out_typ != UINT256_T: _FAIL(arg.typ, out_typ, expr) # pretend enum is uint256 @@ -468,7 +468,7 @@ def convert(expr, context): ret = to_bool(arg_ast, arg, out_typ) elif out_typ == AddressT(): ret = to_address(arg_ast, arg, out_typ) - elif is_enum_type(out_typ): + elif is_flag_type(out_typ): ret = to_enum(arg_ast, arg, out_typ) elif is_integer_type(out_typ): ret = to_int(arg_ast, arg, out_typ) diff --git a/vyper/codegen/core.py b/vyper/codegen/core.py index e1d3ea12b4..046d587353 100644 --- a/vyper/codegen/core.py +++ b/vyper/codegen/core.py @@ -23,7 +23,7 @@ ) from vyper.semantics.types.shortcuts import BYTES32_T, INT256_T, UINT256_T from vyper.semantics.types.subscriptable import SArrayT -from vyper.semantics.types.user import EnumT +from vyper.semantics.types.user import FlagT from vyper.utils import GAS_COPY_WORD, GAS_IDENTITY, GAS_IDENTITYWORD, ceil32 DYNAMIC_ARRAY_OVERHEAD = 1 @@ -45,8 +45,8 @@ def is_decimal_type(typ): return isinstance(typ, DecimalT) -def is_enum_type(typ): - return isinstance(typ, EnumT) +def is_flag_type(typ): + return isinstance(typ, FlagT) def is_tuple_like(typ): @@ -829,7 +829,7 @@ def needs_clamp(t, encoding): raise CompilerPanic("unreachable") # pragma: notest if isinstance(t, (_BytestringT, DArrayT)): return True - if isinstance(t, EnumT): + if isinstance(t, FlagT): return len(t._enum_members) < 256 if isinstance(t, SArrayT): return needs_clamp(t.value_type, encoding) @@ -1136,7 +1136,7 @@ def clamp_basetype(ir_node): # copy of the input ir_node = unwrap_location(ir_node) - if isinstance(t, EnumT): + if isinstance(t, FlagT): bits = len(t._enum_members) # assert x >> bits == 0 ret = int_clamp(ir_node, bits, signed=False) diff --git a/vyper/codegen/expr.py b/vyper/codegen/expr.py index 5870e64e98..b9f7b8c3fa 100644 --- a/vyper/codegen/expr.py +++ b/vyper/codegen/expr.py @@ -12,7 +12,7 @@ getpos, is_array_like, is_bytes_m_type, - is_enum_type, + is_flag_type, is_numeric_type, is_tuple_like, pop_dyn_array, @@ -40,7 +40,7 @@ BytesT, DArrayT, DecimalT, - EnumT, + FlagT, HashMapT, InterfaceT, SArrayT, @@ -205,7 +205,7 @@ def parse_Attribute(self): # MyEnum.foo if ( - isinstance(typ, EnumT) + isinstance(typ, FlagT) and isinstance(self.expr.value, vy_ast.Name) and typ.name == self.expr.value.id ): @@ -380,7 +380,7 @@ def parse_BinOp(self): # This should be unreachable due to the type check pass if left.typ != right.typ: raise TypeCheckFailure(f"unreachable, {left.typ} != {right.typ}", self.expr) - assert is_numeric_type(left.typ) or is_enum_type(left.typ) + assert is_numeric_type(left.typ) or is_flag_type(left.typ) out_typ = left.typ @@ -512,7 +512,7 @@ def parse_Compare(self): if is_array_like(right.typ): return self.build_in_comparator() else: - assert isinstance(right.typ, EnumT), right.typ + assert isinstance(right.typ, FlagT), right.typ intersection = ["and", left, right] if isinstance(self.expr.op, vy_ast.In): return IRnode.from_list(["iszero", ["iszero", intersection]], typ=BoolT()) @@ -629,7 +629,7 @@ def parse_UnaryOp(self): return IRnode.from_list(["iszero", operand], typ=BoolT()) if isinstance(self.expr.op, vy_ast.Invert): - if isinstance(operand.typ, EnumT): + if isinstance(operand.typ, FlagT): n_members = len(operand.typ._enum_members) # use (xor 0b11..1 operand) to flip all the bits in # `operand`. `mask` could be a very large constant and diff --git a/vyper/exceptions.py b/vyper/exceptions.py index 993c0a85eb..ac666e70a6 100644 --- a/vyper/exceptions.py +++ b/vyper/exceptions.py @@ -175,8 +175,8 @@ class FunctionDeclarationException(VyperException): """Invalid function declaration.""" -class EnumDeclarationException(VyperException): - """Invalid enum declaration.""" +class FlagDeclarationException(VyperException): + """Invalid flag declaration.""" class EventDeclarationException(VyperException): diff --git a/vyper/semantics/analysis/local.py b/vyper/semantics/analysis/local.py index 974c14f261..2a84f69ad4 100644 --- a/vyper/semantics/analysis/local.py +++ b/vyper/semantics/analysis/local.py @@ -38,8 +38,8 @@ AddressT, BoolT, DArrayT, - EnumT, EventT, + FlagT, HashMapT, IntegerT, SArrayT, @@ -700,7 +700,7 @@ def visit_Compare(self, node: vy_ast.Compare, typ: VyperType) -> None: validate_expected_type(node.right, rtyp) else: rtyp = get_exact_type_from_node(node.right) - if isinstance(rtyp, EnumT): + if isinstance(rtyp, FlagT): # enum membership - `some_enum in other_enum` ltyp = rtyp else: diff --git a/vyper/semantics/analysis/module.py b/vyper/semantics/analysis/module.py index 7aa661aec3..fb536b7ab7 100644 --- a/vyper/semantics/analysis/module.py +++ b/vyper/semantics/analysis/module.py @@ -31,7 +31,7 @@ ) from vyper.semantics.data_locations import DataLocation from vyper.semantics.namespace import Namespace, get_namespace, override_global_namespace -from vyper.semantics.types import EnumT, EventT, InterfaceT, StructT +from vyper.semantics.types import EventT, FlagT, InterfaceT, StructT from vyper.semantics.types.function import ContractFunctionT from vyper.semantics.types.module import ModuleT from vyper.semantics.types.utils import type_from_annotation @@ -326,8 +326,8 @@ def _validate_self_namespace(): return _finalize() - def visit_EnumDef(self, node): - obj = EnumT.from_EnumDef(node) + def visit_FlagDef(self, node): + obj = FlagT.from_FlagDef(node) self.namespace[node.name] = obj def visit_EventDef(self, node): diff --git a/vyper/semantics/analysis/utils.py b/vyper/semantics/analysis/utils.py index 1785afd92d..20ebb0f093 100644 --- a/vyper/semantics/analysis/utils.py +++ b/vyper/semantics/analysis/utils.py @@ -248,13 +248,13 @@ def types_from_Compare(self, node): # comparisons, e.g. `x < y` # TODO fixme circular import - from vyper.semantics.types.user import EnumT + from vyper.semantics.types.user import FlagT if isinstance(node.op, (vy_ast.In, vy_ast.NotIn)): # x in y left = self.get_possible_types_from_node(node.left) right = self.get_possible_types_from_node(node.right) - if any(isinstance(t, EnumT) for t in left): + if any(isinstance(t, FlagT) for t in left): types_list = get_common_types(node.left, node.right) _validate_op(node, types_list, "validate_comparator") return [BoolT()] diff --git a/vyper/semantics/types/__init__.py b/vyper/semantics/types/__init__.py index 1fef6a706e..880857ccb8 100644 --- a/vyper/semantics/types/__init__.py +++ b/vyper/semantics/types/__init__.py @@ -5,7 +5,7 @@ from .module import InterfaceT from .primitives import AddressT, BoolT, BytesM_T, DecimalT, IntegerT from .subscriptable import DArrayT, HashMapT, SArrayT, TupleT -from .user import EnumT, EventT, StructT +from .user import EventT, FlagT, StructT def _get_primitive_types(): diff --git a/vyper/semantics/types/user.py b/vyper/semantics/types/user.py index ef7e1d0eb4..a4e782349d 100644 --- a/vyper/semantics/types/user.py +++ b/vyper/semantics/types/user.py @@ -5,8 +5,8 @@ from vyper.abi_types import ABI_GIntM, ABI_Tuple, ABIType from vyper.ast.validation import validate_call_args from vyper.exceptions import ( - EnumDeclarationException, EventDeclarationException, + FlagDeclarationException, InvalidAttribute, NamespaceCollision, StructureException, @@ -43,7 +43,7 @@ def __hash__(self): # note: enum behaves a lot like uint256, or uints in general. -class EnumT(_UserType): +class FlagT(_UserType): # this is a carveout because currently we allow dynamic arrays of # enums, but not static arrays of enums _as_darray = True @@ -52,7 +52,7 @@ class EnumT(_UserType): def __init__(self, name: str, members: dict) -> None: if len(members.keys()) > 256: - raise EnumDeclarationException("Enums are limited to 256 members!") + raise FlagDeclarationException("Enums are limited to 256 members!") super().__init__(members=None) @@ -103,7 +103,7 @@ def validate_comparator(self, node): # return f"{self.name}({','.join(v.canonical_abi_type for v in self.arguments)})" @classmethod - def from_EnumDef(cls, base_node: vy_ast.EnumDef) -> "EnumT": + def from_FlagDef(cls, base_node: vy_ast.FlagDef) -> "FlagT": """ Generate an `Enum` object from a Vyper ast node. @@ -118,15 +118,15 @@ def from_EnumDef(cls, base_node: vy_ast.EnumDef) -> "EnumT": members: dict = {} if len(base_node.body) == 1 and isinstance(base_node.body[0], vy_ast.Pass): - raise EnumDeclarationException("Enum must have members", base_node) + raise FlagDeclarationException("Enum must have members", base_node) for i, node in enumerate(base_node.body): if not isinstance(node, vy_ast.Expr) or not isinstance(node.value, vy_ast.Name): - raise EnumDeclarationException("Invalid syntax for enum member", node) + raise FlagDeclarationException("Invalid syntax for enum member", node) member_name = node.value.id if member_name in members: - raise EnumDeclarationException( + raise FlagDeclarationException( f"Enum member '{member_name}' has already been declared", node.value )