diff --git a/tests/parser/features/test_string_map_keys.py b/tests/parser/features/test_string_map_keys.py new file mode 100644 index 0000000000..c52bd72821 --- /dev/null +++ b/tests/parser/features/test_string_map_keys.py @@ -0,0 +1,25 @@ +def test_string_map_keys(get_contract): + code = """ +f:HashMap[String[1], bool] +@external +def test() -> bool: + a:String[1] = "a" + b:String[1] = "b" + self.f[a] = True + return self.f[b] # should return False + """ + c = get_contract(code) + c.test() + assert c.test() is False + + +def test_string_map_keys_literals(get_contract): + code = """ +f:HashMap[String[1], bool] +@external +def test() -> bool: + self.f["a"] = True + return self.f["b"] # should return False + """ + c = get_contract(code) + assert c.test() is False diff --git a/vyper/builtins/functions.py b/vyper/builtins/functions.py index 93dce54756..7733b3331f 100644 --- a/vyper/builtins/functions.py +++ b/vyper/builtins/functions.py @@ -611,7 +611,7 @@ def infer_arg_types(self, node): @process_inputs def build_IR(self, expr, args, kwargs, context): assert len(args) == 1 - return keccak256_helper(expr, args[0], context) + return keccak256_helper(args[0], context) def _make_sha256_call(inp_start, inp_len, out_start, out_len): diff --git a/vyper/codegen/events.py b/vyper/codegen/events.py index 9508a869ea..30a1b1e591 100644 --- a/vyper/codegen/events.py +++ b/vyper/codegen/events.py @@ -15,7 +15,7 @@ def _encode_log_topics(expr, event_id, arg_nodes, context): value = unwrap_location(arg) elif isinstance(arg.typ, _BytestringT): - value = keccak256_helper(expr, arg, context=context) + value = keccak256_helper(arg, context=context) else: # TODO block at higher level raise TypeMismatch("Event indexes may only be value types", expr) diff --git a/vyper/codegen/expr.py b/vyper/codegen/expr.py index dfba469084..5f45f66f71 100644 --- a/vyper/codegen/expr.py +++ b/vyper/codegen/expr.py @@ -338,11 +338,10 @@ def parse_Subscript(self): if isinstance(sub.typ, HashMapT): # TODO sanity check we are in a self.my_map[i] situation - index = Expr.parse_value_expr(self.expr.slice.value, self.context) - if isinstance(index.typ, BytesT): + index = Expr(self.expr.slice.value, self.context).ir_node + if isinstance(index.typ, _BytestringT): # we have to hash the key to get a storage location - assert len(index.args) == 1 - index = keccak256_helper(self.expr.slice.value, index.args[0], self.context) + index = keccak256_helper(index, self.context) elif is_array_like(sub.typ): index = Expr.parse_value_expr(self.expr.slice.value, self.context) @@ -528,8 +527,8 @@ def parse_Compare(self): left = Expr(self.expr.left, self.context).ir_node right = Expr(self.expr.right, self.context).ir_node - left_keccak = keccak256_helper(self.expr, left, self.context) - right_keccak = keccak256_helper(self.expr, right, self.context) + left_keccak = keccak256_helper(left, self.context) + right_keccak = keccak256_helper(right, self.context) if op not in ("eq", "ne"): return # raises diff --git a/vyper/codegen/keccak256_helper.py b/vyper/codegen/keccak256_helper.py index b22453761b..9c5f5eb1d0 100644 --- a/vyper/codegen/keccak256_helper.py +++ b/vyper/codegen/keccak256_helper.py @@ -8,7 +8,7 @@ from vyper.utils import SHA3_BASE, SHA3_PER_WORD, MemoryPositions, bytes_to_int, keccak256 -def _check_byteslike(typ, _expr): +def _check_byteslike(typ): if not isinstance(typ, _BytestringT) and typ != BYTES32_T: # NOTE this may be checked at a higher level, but just be safe raise CompilerPanic("keccak256 only accepts bytes-like objects") @@ -18,8 +18,8 @@ def _gas_bound(num_words): return SHA3_BASE + num_words * SHA3_PER_WORD -def keccak256_helper(expr, to_hash, context): - _check_byteslike(to_hash.typ, expr) +def keccak256_helper(to_hash, context): + _check_byteslike(to_hash.typ) # Can hash literals # TODO this is dead code.