def test_error_on_no_max_argument(self): ir = self._make_ir("struct Foo:\n" " $max() [+1] UInt:8[] x\n") expression = ir.module[0].type[0].structure.field[0].location.start self.assertEqual([[ error.error("m.emb", expression.source_location, "Function '$max' requires at least 1 argument.") ]], error.filter_errors(type_check.annotate_types(ir)))
def test_return_value_requires_different_signedness_from_arguments(self): ir = _make_ir_from_emb( '[$default byte_order: "LittleEndian"]\n' "struct Foo:\n" " 0 [+1] UInt x\n" # Both arguments require uint64; result fits in int64. " if (x + 0x7fff_ffff_ffff_ffff) - 0x8000_0000_0000_0000 < 10:\n" " 1 [+1] UInt y\n") condition = ir.module[0].type[0].structure.field[1].existence_condition error_expression = condition.function.args[0] error_location = error_expression.source_location arg0_location = error_expression.function.args[0].source_location arg1_location = error_expression.function.args[1].source_location self.assertEqual([ [error.error( "m.emb", error_location, "Either all arguments to '-' and its result must fit in a 64-bit " "unsigned integer, or all must fit in a 64-bit signed integer."), error.note("m.emb", arg0_location, "Requires unsigned 64-bit integer."), error.note("m.emb", arg1_location, "Requires unsigned 64-bit integer."), error.note("m.emb", error_location, "Requires signed 64-bit integer.")] ], error.filter_errors(constraints.check_constraints(ir)))
def test_choice_of_bools(self): ir = self._make_ir("struct Foo:\n" " 0 [+1] UInt:8[] x\n" " 1 [+true ? true : false] UInt:8[] y\n") expression = ir.module[0].type[0].structure.field[1].location.size self.assertEqual([], error.filter_errors(type_check.annotate_types(ir))) self.assertEqual("boolean", expression.type.WhichOneof("type"))
def test_adds_opaque_field_type_for_array(self): ir = self._make_ir("struct Foo:\n" " 0 [+1] UInt:8[] x\n" " 1 [+x] UInt:8[] y\n") self.assertEqual([], error.filter_errors(type_check.annotate_types(ir))) expression = ir.module[0].type[0].structure.field[1].location.size self.assertEqual(expression.type.WhichOneof("type"), "opaque")
def test_checks_that_parameters_are_atomic_types(self): ir = self._make_ir("struct Foo(y: UInt:8[1]):\n" " 0 [+1] UInt x\n") error_parameter = ir.module[0].type[0].runtime_parameter[0] error_location = error_parameter.physical_type_alias.source_location self.assertEqual([[ error.error("m.emb", error_location, "Parameters cannot be arrays.") ]], error.filter_errors(type_check.annotate_types(ir)))
def test_error_on_bad_boolean_operand_type(self): ir = self._make_ir("struct Foo:\n" " 0 [+1] UInt x\n" " 1 [+1&&true] UInt:8[] y\n") expression = ir.module[0].type[0].structure.field[1].location.size self.assertEqual([[ error.error("m.emb", expression.function.args[0].source_location, "Left argument of operator '&&' must be a boolean.") ]], error.filter_errors(type_check.annotate_types(ir)))
def test_bits_must_be_fixed_size(self): ir = _make_ir_from_emb("bits Dynamic:\n" " 0 [+3] UInt x\n" " 3 [+3 * x] UInt:3[x] a\n") error_type = ir.module[0].type[0] self.assertEqual([ [error.error("m.emb", error_type.source_location, "`bits` types must be fixed size.")] ], error.filter_errors(constraints.check_constraints(ir)))
def test_bits_must_be_small(self): ir = _make_ir_from_emb("bits Big:\n" " 0 [+64] UInt x\n" " 64 [+1] UInt y\n") error_type = ir.module[0].type[0] self.assertEqual([ [error.error("m.emb", error_type.source_location, "`bits` types must be 64 bits or smaller.")] ], error.filter_errors(constraints.check_constraints(ir)))
def test_reserved_enum_name(self): ir = _make_ir_from_emb("enum Foo:\n" " NULL = 1\n") error_name = ir.module[0].type[0].enumeration.value[0].name.name self.assertEqual([[ error.error( "m.emb", error_name.source_location, "C reserved word may not be used as an enum name.") ]], error.filter_errors(constraints.check_constraints(ir)))
def test_reserved_type_name(self): ir = _make_ir_from_emb("struct False:\n" " 0 [+1] UInt foo\n") error_name = ir.module[0].type[0].name.name self.assertEqual([[ error.error( "m.emb", error_name.source_location, "Python 3 reserved word may not be used as a type name.") ]], error.filter_errors(constraints.check_constraints(ir)))
def test_explicit_size_too_small_for_field(self): ir = _make_ir_from_emb("bits Foo:\n" " 0 [+64] UInt:32 thirty_two_bit\n") error_type = ir.module[0].type[0].structure.field[0].type self.assertEqual([[ error.error("m.emb", error_type.source_location, "Fixed-size type 'UInt:32' cannot be placed in field of " "size 64 bits; requires 32 bits.") ]], error.filter_errors(constraints.check_constraints(ir)))
def test_lower_bound_too_many_arguments(self): ir = self._make_ir("struct Foo:\n" " $lower_bound(1, 2) [+1] UInt:8[] x\n") expression = ir.module[0].type[0].structure.field[0].location.start self.assertEqual([[ error.error( "m.emb", expression.source_location, "Function '$lower_bound' requires exactly 1 argument.") ]], error.filter_errors(type_check.annotate_types(ir)))
def test_adds_boolean_constant_type(self): ir = self._make_ir("struct Foo:\n" " 0 [+1] UInt x\n" " 1 [+true] UInt:8[] y\n") self.assertEqual([], error.filter_errors(type_check.annotate_types(ir)), ir.to_json(indent=2)) expression = ir.module[0].type[0].structure.field[1].location.size self.assertEqual(expression.type.WhichOneof("type"), "boolean")
def test_error_on_bad_max_argument(self): ir = self._make_ir("struct Foo:\n" " $max(Bar.XX) [+1] UInt:8[] x\n" "enum Bar:\n" " XX = 0\n") expression = ir.module[0].type[0].structure.field[0].location.start self.assertEqual([[ error.error("m.emb", expression.function.args[0].source_location, "Argument 0 of function '$max' must be an integer.") ]], error.filter_errors(type_check.annotate_types(ir)))
def test_reserved_field_name(self): ir = _make_ir_from_emb('[$default byte_order: "LittleEndian"]\n' "struct Foo:\n" " 0 [+8] UInt restrict\n") error_name = ir.module[0].type[0].structure.field[0].name.name self.assertEqual([[ error.error( "m.emb", error_name.source_location, "C reserved word may not be used as a field name.") ]], error.filter_errors(constraints.check_constraints(ir)))
def test_error_on_no_argument_has(self): ir = self._make_ir("struct Foo:\n" " if $present():\n" " 0 [+1] UInt x\n") expression = ir.module[0].type[0].structure.field[ 0].existence_condition self.assertEqual([[ error.error("m.emb", expression.source_location, "Function '$present' requires exactly 1 argument.") ]], error.filter_errors(type_check.annotate_types(ir)))
def test_error_on_non_field_argument_to_has(self): ir = self._make_ir("struct Foo:\n" " if $present(0):\n" " 0 [+1] UInt x\n") expression = ir.module[0].type[0].structure.field[ 0].existence_condition self.assertEqual([[ error.error("m.emb", expression.function.args[0].source_location, "Argument 0 of function '$present' must be a field.") ]], error.filter_errors(type_check.annotate_types(ir)))
def test_error_on_bad_choice_condition_operand(self): ir = self._make_ir("struct Foo:\n" " 0 [+1] UInt:8[] x\n" " 1 [+5 ? 0 : 1] UInt:8[] y\n") expression = ir.module[0].type[0].structure.field[1].location.size condition_arg = expression.function.args[0] self.assertEqual([[ error.error("m.emb", condition_arg.source_location, "Condition of operator '?:' must be a boolean.") ]], error.filter_errors(type_check.annotate_types(ir)))
def test_rejects_too_large_max_bits(self): ir = _make_ir_from_emb("enum Foo:\n" " [maximum_bits: 65]\n" " ZERO = 0\n") attribute_ir = ir.module[0].type[0].attribute[0] self.assertEqual([[ error.error( "m.emb", attribute_ir.value.source_location, "'maximum_bits' on an 'enum' must be between 1 and 64.") ]], error.filter_errors(attribute_checker.normalize_and_verify(ir)))
def test_checks_for_explicit_size_on_parameters(self): ir = _make_ir_from_emb("struct Foo(y: UInt):\n" " 0 [+1] UInt x\n") error_parameter = ir.module[0].type[0].runtime_parameter[0] error_location = error_parameter.physical_type_alias.source_location self.assertEqual( [[error.error("m.emb", error_location, "Integer range of parameter must not be unbounded; it " "must fit in a 64-bit signed or unsigned integer.")]], error.filter_errors(constraints.check_constraints(ir)))
def test_error_on_missing_inner_array_size(self): ir = _make_ir_from_emb("struct Foo:\n" " 0 [+1] UInt:8[][1] one_byte\n") error_array = ir.module[0].type[0].structure.field[0].type.array_type self.assertEqual([[ error.error( "m.emb", error_array.base_type.array_type.element_count.source_location, "Array dimensions can only be omitted for the outermost dimension.") ]], error.filter_errors(constraints.check_constraints(ir)))
def test_error_non_fixed_size_inner_array_dimension(self): ir = _make_ir_from_emb("struct Foo:\n" " 0 [+1] UInt size\n" " 1 [+size] UInt:8[size-1][1] one_byte\n") error_array = ir.module[0].type[0].structure.field[1].type.array_type self.assertEqual([[ error.error( "m.emb", error_array.base_type.array_type.element_count.source_location, "Inner array dimensions must be constant.") ]], error.filter_errors(constraints.check_constraints(ir)))
def test_checks_for_correct_explicit_size_on_parameters(self): ir = _make_ir_from_emb("struct Foo(y: UInt:300):\n" " 0 [+1] UInt x\n") error_parameter = ir.module[0].type[0].runtime_parameter[0] error_location = error_parameter.physical_type_alias.source_location self.assertEqual( [[error.error("m.emb", error_location, "Potential range of parameter is 0 to {}, which cannot " "fit in a 64-bit signed or unsigned integer.".format( 2**300-1))]], error.filter_errors(constraints.check_constraints(ir)))
def test_error_on_bad_equality_left_operand(self): ir = self._make_ir("struct Foo:\n" " 0 [+1] UInt:8[] x\n" " 1 [+x==x] UInt:8[] y\n") expression = ir.module[0].type[0].structure.field[1].location.size self.assertEqual([[ error.error( "m.emb", expression.function.args[0].source_location, "Left argument of operator '==' must be an integer, " "boolean, or enum.") ]], error.filter_errors(type_check.annotate_types(ir)))
def test_error_on_equality_mismatched_operands_bool_int(self): ir = self._make_ir("struct Foo:\n" " 0 [+1] UInt x\n" " 1 [+true==1] UInt:8[] y\n") expression = ir.module[0].type[0].structure.field[1].location.size self.assertEqual([[ error.error( "m.emb", expression.source_location, "Both arguments of operator '==' must have the same " "type.") ]], error.filter_errors(type_check.annotate_types(ir)))
def test_error_on_bad_choice_mismatched_operands(self): ir = self._make_ir("struct Foo:\n" " 0 [+1] UInt:8[] x\n" " 1 [+true ? 0 : true] UInt:8[] y\n") expression = ir.module[0].type[0].structure.field[1].location.size self.assertEqual([[ error.error( "m.emb", expression.source_location, "The if-true and if-false clauses of operator '?:' must " "have the same type.") ]], error.filter_errors(type_check.annotate_types(ir)))
def test_explicit_non_byte_size_array_element(self): ir = _make_ir_from_emb('[$default byte_order: "LittleEndian"]\n' "struct Foo:\n" " 0 [+2] UInt:4[4] nibbles\n") error_type = ir.module[0].type[0].structure.field[0].type.array_type self.assertEqual([ [error.error( "m.emb", error_type.base_type.source_location, "Array elements in structs must have sizes which are a multiple of " "8 bits.")] ], error.filter_errors(constraints.check_constraints(ir)))
def test_enum_value_too_wide(self): ir = _make_ir_from_emb('[$default byte_order: "LittleEndian"]\n' "enum Foo:\n" " LOW = -1\n" " HIGH = 0x8000_0000_0000_0000\n") error_value = ir.module[0].type[0].enumeration.value[0].value self.assertEqual([[ error.error( "m.emb", error_value.source_location, "Value -1 is out of range for unsigned enumeration.") ]], error.filter_errors(constraints.check_constraints(ir)))
def test_enum_value_too_wide_small_size_error_message(self): ir = _make_ir_from_emb('[$default byte_order: "LittleEndian"]\n' "enum Foo:\n" " [maximum_bits: 8]\n" " HIGH = 0x100\n") error_value = ir.module[0].type[0].enumeration.value[0].value self.assertEqual([[ error.error( "m.emb", error_value.source_location, "Value 256 is out of range for 8-bit unsigned enumeration.") ]], error.filter_errors(constraints.check_constraints(ir)))
def test_rejects_requires_on_float(self): ir = _make_ir_from_emb('[$default byte_order: "LittleEndian"]\n' "struct Foo:\n" " 0 [+4] Float float\n" " [requires: false]\n") field_ir = ir.module[0].type[0].structure.field[0] self.assertEqual([[ error.error( "m.emb", field_ir.attribute[0].value.source_location, "Attribute 'requires' is only allowed on integer, " "enumeration, or boolean fields.") ]], error.filter_errors(attribute_checker.normalize_and_verify(ir)))