1*99e0aae7SDavid Rees# Copyright 2019 Google LLC 2*99e0aae7SDavid Rees# 3*99e0aae7SDavid Rees# Licensed under the Apache License, Version 2.0 (the "License"); 4*99e0aae7SDavid Rees# you may not use this file except in compliance with the License. 5*99e0aae7SDavid Rees# You may obtain a copy of the License at 6*99e0aae7SDavid Rees# 7*99e0aae7SDavid Rees# https://www.apache.org/licenses/LICENSE-2.0 8*99e0aae7SDavid Rees# 9*99e0aae7SDavid Rees# Unless required by applicable law or agreed to in writing, software 10*99e0aae7SDavid Rees# distributed under the License is distributed on an "AS IS" BASIS, 11*99e0aae7SDavid Rees# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*99e0aae7SDavid Rees# See the License for the specific language governing permissions and 13*99e0aae7SDavid Rees# limitations under the License. 14*99e0aae7SDavid Rees 15*99e0aae7SDavid Rees"""Tests for constraints.py.""" 16*99e0aae7SDavid Rees 17*99e0aae7SDavid Reesimport unittest 18*99e0aae7SDavid Reesfrom compiler.front_end import attributes 19*99e0aae7SDavid Reesfrom compiler.front_end import constraints 20*99e0aae7SDavid Reesfrom compiler.front_end import glue 21*99e0aae7SDavid Reesfrom compiler.util import error 22*99e0aae7SDavid Reesfrom compiler.util import ir_data_utils 23*99e0aae7SDavid Reesfrom compiler.util import ir_util 24*99e0aae7SDavid Reesfrom compiler.util import test_util 25*99e0aae7SDavid Rees 26*99e0aae7SDavid Rees 27*99e0aae7SDavid Reesdef _make_ir_from_emb(emb_text, name="m.emb"): 28*99e0aae7SDavid Rees ir, unused_debug_info, errors = glue.parse_emboss_file( 29*99e0aae7SDavid Rees name, 30*99e0aae7SDavid Rees test_util.dict_file_reader({name: emb_text}), 31*99e0aae7SDavid Rees stop_before_step="check_constraints") 32*99e0aae7SDavid Rees assert not errors, repr(errors) 33*99e0aae7SDavid Rees return ir 34*99e0aae7SDavid Rees 35*99e0aae7SDavid Rees 36*99e0aae7SDavid Reesclass ConstraintsTest(unittest.TestCase): 37*99e0aae7SDavid Rees """Tests constraints.check_constraints and helpers.""" 38*99e0aae7SDavid Rees 39*99e0aae7SDavid Rees def test_error_on_missing_inner_array_size(self): 40*99e0aae7SDavid Rees ir = _make_ir_from_emb("struct Foo:\n" 41*99e0aae7SDavid Rees " 0 [+1] UInt:8[][1] one_byte\n") 42*99e0aae7SDavid Rees # There is a latent issue here where the source location reported in this 43*99e0aae7SDavid Rees # error is using a default value of 0:0. An issue is filed at 44*99e0aae7SDavid Rees # https://github.com/google/emboss/issues/153 for further investigation. 45*99e0aae7SDavid Rees # In the meantime we use `ir_data_utils.reader` to mimic this legacy 46*99e0aae7SDavid Rees # behavior. 47*99e0aae7SDavid Rees error_array = ir_data_utils.reader( 48*99e0aae7SDavid Rees ir.module[0].type[0].structure.field[0].type.array_type) 49*99e0aae7SDavid Rees self.assertEqual([[ 50*99e0aae7SDavid Rees error.error( 51*99e0aae7SDavid Rees "m.emb", 52*99e0aae7SDavid Rees error_array.base_type.array_type.element_count.source_location, 53*99e0aae7SDavid Rees "Array dimensions can only be omitted for the outermost dimension.") 54*99e0aae7SDavid Rees ]], error.filter_errors(constraints.check_constraints(ir))) 55*99e0aae7SDavid Rees 56*99e0aae7SDavid Rees def test_no_error_on_ok_array_size(self): 57*99e0aae7SDavid Rees ir = _make_ir_from_emb("struct Foo:\n" 58*99e0aae7SDavid Rees " 0 [+1] UInt:8[1][1] one_byte\n") 59*99e0aae7SDavid Rees self.assertEqual([], constraints.check_constraints(ir)) 60*99e0aae7SDavid Rees 61*99e0aae7SDavid Rees def test_no_error_on_ok_missing_outer_array_size(self): 62*99e0aae7SDavid Rees ir = _make_ir_from_emb("struct Foo:\n" 63*99e0aae7SDavid Rees " 0 [+1] UInt:8[1][] one_byte\n") 64*99e0aae7SDavid Rees self.assertEqual([], constraints.check_constraints(ir)) 65*99e0aae7SDavid Rees 66*99e0aae7SDavid Rees def test_no_error_on_dynamically_sized_struct_in_dynamically_sized_field( 67*99e0aae7SDavid Rees self): 68*99e0aae7SDavid Rees ir = _make_ir_from_emb("struct Foo:\n" 69*99e0aae7SDavid Rees " 0 [+1] UInt size\n" 70*99e0aae7SDavid Rees " 1 [+size] Bar bar\n" 71*99e0aae7SDavid Rees "struct Bar:\n" 72*99e0aae7SDavid Rees " 0 [+1] UInt size\n" 73*99e0aae7SDavid Rees " 1 [+size] UInt:8[] payload\n") 74*99e0aae7SDavid Rees self.assertEqual([], constraints.check_constraints(ir)) 75*99e0aae7SDavid Rees 76*99e0aae7SDavid Rees def test_no_error_on_dynamically_sized_struct_in_statically_sized_field(self): 77*99e0aae7SDavid Rees ir = _make_ir_from_emb("struct Foo:\n" 78*99e0aae7SDavid Rees " 0 [+10] Bar bar\n" 79*99e0aae7SDavid Rees "struct Bar:\n" 80*99e0aae7SDavid Rees " 0 [+1] UInt size\n" 81*99e0aae7SDavid Rees " 1 [+size] UInt:8[] payload\n") 82*99e0aae7SDavid Rees self.assertEqual([], constraints.check_constraints(ir)) 83*99e0aae7SDavid Rees 84*99e0aae7SDavid Rees def test_no_error_non_fixed_size_outer_array_dimension(self): 85*99e0aae7SDavid Rees ir = _make_ir_from_emb("struct Foo:\n" 86*99e0aae7SDavid Rees " 0 [+1] UInt size\n" 87*99e0aae7SDavid Rees " 1 [+size] UInt:8[1][size-1] one_byte\n") 88*99e0aae7SDavid Rees self.assertEqual([], constraints.check_constraints(ir)) 89*99e0aae7SDavid Rees 90*99e0aae7SDavid Rees def test_error_non_fixed_size_inner_array_dimension(self): 91*99e0aae7SDavid Rees ir = _make_ir_from_emb("struct Foo:\n" 92*99e0aae7SDavid Rees " 0 [+1] UInt size\n" 93*99e0aae7SDavid Rees " 1 [+size] UInt:8[size-1][1] one_byte\n") 94*99e0aae7SDavid Rees error_array = ir.module[0].type[0].structure.field[1].type.array_type 95*99e0aae7SDavid Rees self.assertEqual([[ 96*99e0aae7SDavid Rees error.error( 97*99e0aae7SDavid Rees "m.emb", 98*99e0aae7SDavid Rees error_array.base_type.array_type.element_count.source_location, 99*99e0aae7SDavid Rees "Inner array dimensions must be constant.") 100*99e0aae7SDavid Rees ]], error.filter_errors(constraints.check_constraints(ir))) 101*99e0aae7SDavid Rees 102*99e0aae7SDavid Rees def test_error_non_constant_inner_array_dimensions(self): 103*99e0aae7SDavid Rees ir = _make_ir_from_emb("struct Foo:\n" 104*99e0aae7SDavid Rees " 0 [+1] Bar[1] one_byte\n" 105*99e0aae7SDavid Rees # There is no dynamically-sized byte-oriented type in 106*99e0aae7SDavid Rees # the Prelude, so this test has to make its own. 107*99e0aae7SDavid Rees "external Bar:\n" 108*99e0aae7SDavid Rees " [is_integer: true]\n" 109*99e0aae7SDavid Rees " [addressable_unit_size: 8]\n") 110*99e0aae7SDavid Rees error_array = ir.module[0].type[0].structure.field[0].type.array_type 111*99e0aae7SDavid Rees self.assertEqual([[ 112*99e0aae7SDavid Rees error.error( 113*99e0aae7SDavid Rees "m.emb", error_array.base_type.atomic_type.source_location, 114*99e0aae7SDavid Rees "Array elements must be fixed size.") 115*99e0aae7SDavid Rees ]], error.filter_errors(constraints.check_constraints(ir))) 116*99e0aae7SDavid Rees 117*99e0aae7SDavid Rees def test_error_dynamically_sized_array_elements(self): 118*99e0aae7SDavid Rees ir = _make_ir_from_emb('[$default byte_order: "LittleEndian"]\n' 119*99e0aae7SDavid Rees "struct Foo:\n" 120*99e0aae7SDavid Rees " 0 [+1] Bar[1] bar\n" 121*99e0aae7SDavid Rees "struct Bar:\n" 122*99e0aae7SDavid Rees " 0 [+1] UInt size\n" 123*99e0aae7SDavid Rees " 1 [+size] UInt:8[] payload\n") 124*99e0aae7SDavid Rees error_array = ir.module[0].type[0].structure.field[0].type.array_type 125*99e0aae7SDavid Rees self.assertEqual([[ 126*99e0aae7SDavid Rees error.error( 127*99e0aae7SDavid Rees "m.emb", error_array.base_type.atomic_type.source_location, 128*99e0aae7SDavid Rees "Array elements must be fixed size.") 129*99e0aae7SDavid Rees ]], error.filter_errors(constraints.check_constraints(ir))) 130*99e0aae7SDavid Rees 131*99e0aae7SDavid Rees def test_field_too_small_for_type(self): 132*99e0aae7SDavid Rees ir = _make_ir_from_emb('[$default byte_order: "LittleEndian"]\n' 133*99e0aae7SDavid Rees "struct Foo:\n" 134*99e0aae7SDavid Rees " 0 [+1] Bar bar\n" 135*99e0aae7SDavid Rees "struct Bar:\n" 136*99e0aae7SDavid Rees " 0 [+2] UInt value\n") 137*99e0aae7SDavid Rees error_type = ir.module[0].type[0].structure.field[0].type 138*99e0aae7SDavid Rees self.assertEqual([[ 139*99e0aae7SDavid Rees error.error( 140*99e0aae7SDavid Rees "m.emb", error_type.source_location, 141*99e0aae7SDavid Rees "Fixed-size type 'Bar' cannot be placed in field of size 8 bits; " 142*99e0aae7SDavid Rees "requires 16 bits.") 143*99e0aae7SDavid Rees ]], error.filter_errors(constraints.check_constraints(ir))) 144*99e0aae7SDavid Rees 145*99e0aae7SDavid Rees def test_dynamically_sized_field_always_too_small_for_type(self): 146*99e0aae7SDavid Rees ir = _make_ir_from_emb('[$default byte_order: "LittleEndian"]\n' 147*99e0aae7SDavid Rees "struct Foo:\n" 148*99e0aae7SDavid Rees " 0 [+1] bits:\n" 149*99e0aae7SDavid Rees " 0 [+1] UInt x\n" 150*99e0aae7SDavid Rees " 0 [+x] Bar bar\n" 151*99e0aae7SDavid Rees "struct Bar:\n" 152*99e0aae7SDavid Rees " 0 [+2] UInt value\n") 153*99e0aae7SDavid Rees error_type = ir.module[0].type[0].structure.field[2].type 154*99e0aae7SDavid Rees self.assertEqual([[ 155*99e0aae7SDavid Rees error.error( 156*99e0aae7SDavid Rees "m.emb", error_type.source_location, 157*99e0aae7SDavid Rees "Field of maximum size 8 bits cannot hold fixed-size type 'Bar', " 158*99e0aae7SDavid Rees "which requires 16 bits.") 159*99e0aae7SDavid Rees ]], error.filter_errors(constraints.check_constraints(ir))) 160*99e0aae7SDavid Rees 161*99e0aae7SDavid Rees def test_struct_field_too_big_for_type(self): 162*99e0aae7SDavid Rees ir = _make_ir_from_emb("struct Foo:\n" 163*99e0aae7SDavid Rees " 0 [+2] Byte double_byte\n" 164*99e0aae7SDavid Rees "struct Byte:\n" 165*99e0aae7SDavid Rees " 0 [+1] UInt b\n") 166*99e0aae7SDavid Rees error_type = ir.module[0].type[0].structure.field[0].type 167*99e0aae7SDavid Rees self.assertEqual([[ 168*99e0aae7SDavid Rees error.error( 169*99e0aae7SDavid Rees "m.emb", error_type.source_location, 170*99e0aae7SDavid Rees "Fixed-size type 'Byte' cannot be placed in field of size 16 bits; " 171*99e0aae7SDavid Rees "requires 8 bits.") 172*99e0aae7SDavid Rees ]], error.filter_errors(constraints.check_constraints(ir))) 173*99e0aae7SDavid Rees 174*99e0aae7SDavid Rees def test_bits_field_too_big_for_type(self): 175*99e0aae7SDavid Rees ir = _make_ir_from_emb("struct Foo:\n" 176*99e0aae7SDavid Rees " 0 [+9] UInt uint72\n" 177*99e0aae7SDavid Rees ' [byte_order: "LittleEndian"]\n') 178*99e0aae7SDavid Rees error_field = ir.module[0].type[0].structure.field[0] 179*99e0aae7SDavid Rees uint_type = ir_util.find_object(error_field.type.atomic_type.reference, ir) 180*99e0aae7SDavid Rees uint_requirements = ir_util.get_attribute(uint_type.attribute, 181*99e0aae7SDavid Rees attributes.STATIC_REQUIREMENTS) 182*99e0aae7SDavid Rees self.assertEqual([[ 183*99e0aae7SDavid Rees error.error("m.emb", error_field.source_location, 184*99e0aae7SDavid Rees "Requirements of UInt not met."), 185*99e0aae7SDavid Rees error.note("", uint_requirements.source_location, 186*99e0aae7SDavid Rees "Requirements specified here."), 187*99e0aae7SDavid Rees ]], error.filter_errors(constraints.check_constraints(ir))) 188*99e0aae7SDavid Rees 189*99e0aae7SDavid Rees def test_field_type_not_allowed_in_bits(self): 190*99e0aae7SDavid Rees ir = _make_ir_from_emb('[$default byte_order: "LittleEndian"]\n' 191*99e0aae7SDavid Rees "bits Foo:\n" 192*99e0aae7SDavid Rees " 0 [+16] Bar bar\n" 193*99e0aae7SDavid Rees "external Bar:\n" 194*99e0aae7SDavid Rees " [addressable_unit_size: 8]\n") 195*99e0aae7SDavid Rees error_type = ir.module[0].type[0].structure.field[0].type 196*99e0aae7SDavid Rees self.assertEqual([[ 197*99e0aae7SDavid Rees error.error( 198*99e0aae7SDavid Rees "m.emb", error_type.source_location, 199*99e0aae7SDavid Rees "Byte-oriented type 'Bar' cannot be used in a bits field.") 200*99e0aae7SDavid Rees ]], error.filter_errors(constraints.check_constraints(ir))) 201*99e0aae7SDavid Rees 202*99e0aae7SDavid Rees def test_arrays_allowed_in_bits(self): 203*99e0aae7SDavid Rees ir = _make_ir_from_emb("bits Foo:\n" 204*99e0aae7SDavid Rees " 0 [+16] Flag[16] bar\n") 205*99e0aae7SDavid Rees self.assertEqual([], constraints.check_constraints(ir)) 206*99e0aae7SDavid Rees 207*99e0aae7SDavid Rees def test_oversized_anonymous_bit_field(self): 208*99e0aae7SDavid Rees ir = _make_ir_from_emb('[$default byte_order: "LittleEndian"]\n' 209*99e0aae7SDavid Rees "struct Foo:\n" 210*99e0aae7SDavid Rees " 0 [+4] bits:\n" 211*99e0aae7SDavid Rees " 0 [+8] UInt field\n") 212*99e0aae7SDavid Rees self.assertEqual([], constraints.check_constraints(ir)) 213*99e0aae7SDavid Rees 214*99e0aae7SDavid Rees def test_undersized_anonymous_bit_field(self): 215*99e0aae7SDavid Rees ir = _make_ir_from_emb('[$default byte_order: "LittleEndian"]\n' 216*99e0aae7SDavid Rees "struct Foo:\n" 217*99e0aae7SDavid Rees " 0 [+1] bits:\n" 218*99e0aae7SDavid Rees " 0 [+32] UInt field\n") 219*99e0aae7SDavid Rees error_type = ir.module[0].type[0].structure.field[0].type 220*99e0aae7SDavid Rees self.assertEqual([[ 221*99e0aae7SDavid Rees error.error( 222*99e0aae7SDavid Rees "m.emb", error_type.source_location, 223*99e0aae7SDavid Rees "Fixed-size anonymous type cannot be placed in field of size 8 " 224*99e0aae7SDavid Rees "bits; requires 32 bits.") 225*99e0aae7SDavid Rees ]], error.filter_errors(constraints.check_constraints(ir))) 226*99e0aae7SDavid Rees 227*99e0aae7SDavid Rees def test_reserved_field_name(self): 228*99e0aae7SDavid Rees ir = _make_ir_from_emb('[$default byte_order: "LittleEndian"]\n' 229*99e0aae7SDavid Rees "struct Foo:\n" 230*99e0aae7SDavid Rees " 0 [+8] UInt restrict\n") 231*99e0aae7SDavid Rees error_name = ir.module[0].type[0].structure.field[0].name.name 232*99e0aae7SDavid Rees self.assertEqual([[ 233*99e0aae7SDavid Rees error.error( 234*99e0aae7SDavid Rees "m.emb", error_name.source_location, 235*99e0aae7SDavid Rees "C reserved word may not be used as a field name.") 236*99e0aae7SDavid Rees ]], error.filter_errors(constraints.check_constraints(ir))) 237*99e0aae7SDavid Rees 238*99e0aae7SDavid Rees def test_reserved_type_name(self): 239*99e0aae7SDavid Rees ir = _make_ir_from_emb("struct False:\n" 240*99e0aae7SDavid Rees " 0 [+1] UInt foo\n") 241*99e0aae7SDavid Rees error_name = ir.module[0].type[0].name.name 242*99e0aae7SDavid Rees self.assertEqual([[ 243*99e0aae7SDavid Rees error.error( 244*99e0aae7SDavid Rees "m.emb", error_name.source_location, 245*99e0aae7SDavid Rees "Python 3 reserved word may not be used as a type name.") 246*99e0aae7SDavid Rees ]], error.filter_errors(constraints.check_constraints(ir))) 247*99e0aae7SDavid Rees 248*99e0aae7SDavid Rees def test_reserved_enum_name(self): 249*99e0aae7SDavid Rees ir = _make_ir_from_emb("enum Foo:\n" 250*99e0aae7SDavid Rees " NULL = 1\n") 251*99e0aae7SDavid Rees error_name = ir.module[0].type[0].enumeration.value[0].name.name 252*99e0aae7SDavid Rees self.assertEqual([[ 253*99e0aae7SDavid Rees error.error( 254*99e0aae7SDavid Rees "m.emb", error_name.source_location, 255*99e0aae7SDavid Rees "C reserved word may not be used as an enum name.") 256*99e0aae7SDavid Rees ]], error.filter_errors(constraints.check_constraints(ir))) 257*99e0aae7SDavid Rees 258*99e0aae7SDavid Rees def test_bits_type_in_struct_array(self): 259*99e0aae7SDavid Rees ir = _make_ir_from_emb('[$default byte_order: "LittleEndian"]\n' 260*99e0aae7SDavid Rees "struct Foo:\n" 261*99e0aae7SDavid Rees " 0 [+10] UInt:8[10] array\n") 262*99e0aae7SDavid Rees self.assertEqual([], constraints.check_constraints(ir)) 263*99e0aae7SDavid Rees 264*99e0aae7SDavid Rees def test_bits_type_in_bits_array(self): 265*99e0aae7SDavid Rees ir = _make_ir_from_emb("bits Foo:\n" 266*99e0aae7SDavid Rees " 0 [+10] UInt:8[10] array\n") 267*99e0aae7SDavid Rees self.assertEqual([], constraints.check_constraints(ir)) 268*99e0aae7SDavid Rees 269*99e0aae7SDavid Rees def test_explicit_size_too_small(self): 270*99e0aae7SDavid Rees ir = _make_ir_from_emb("bits Foo:\n" 271*99e0aae7SDavid Rees " 0 [+0] UInt:0 zero_bit\n") 272*99e0aae7SDavid Rees error_field = ir.module[0].type[0].structure.field[0] 273*99e0aae7SDavid Rees uint_type = ir_util.find_object(error_field.type.atomic_type.reference, ir) 274*99e0aae7SDavid Rees uint_requirements = ir_util.get_attribute(uint_type.attribute, 275*99e0aae7SDavid Rees attributes.STATIC_REQUIREMENTS) 276*99e0aae7SDavid Rees self.assertEqual([[ 277*99e0aae7SDavid Rees error.error("m.emb", error_field.source_location, 278*99e0aae7SDavid Rees "Requirements of UInt not met."), 279*99e0aae7SDavid Rees error.note("", uint_requirements.source_location, 280*99e0aae7SDavid Rees "Requirements specified here."), 281*99e0aae7SDavid Rees ]], error.filter_errors(constraints.check_constraints(ir))) 282*99e0aae7SDavid Rees 283*99e0aae7SDavid Rees def test_explicit_enumeration_size_too_small(self): 284*99e0aae7SDavid Rees ir = _make_ir_from_emb('[$default byte_order: "BigEndian"]\n' 285*99e0aae7SDavid Rees "bits Foo:\n" 286*99e0aae7SDavid Rees " 0 [+0] Bar:0 zero_bit\n" 287*99e0aae7SDavid Rees "enum Bar:\n" 288*99e0aae7SDavid Rees " BAZ = 0\n") 289*99e0aae7SDavid Rees error_type = ir.module[0].type[0].structure.field[0].type 290*99e0aae7SDavid Rees self.assertEqual([[ 291*99e0aae7SDavid Rees error.error("m.emb", error_type.source_location, 292*99e0aae7SDavid Rees "Enumeration type 'Bar' cannot be 0 bits; type 'Bar' " 293*99e0aae7SDavid Rees "must be between 1 and 64 bits, inclusive."), 294*99e0aae7SDavid Rees ]], error.filter_errors(constraints.check_constraints(ir))) 295*99e0aae7SDavid Rees 296*99e0aae7SDavid Rees def test_explicit_size_too_big_for_field(self): 297*99e0aae7SDavid Rees ir = _make_ir_from_emb("bits Foo:\n" 298*99e0aae7SDavid Rees " 0 [+8] UInt:32 thirty_two_bit\n") 299*99e0aae7SDavid Rees error_type = ir.module[0].type[0].structure.field[0].type 300*99e0aae7SDavid Rees self.assertEqual([[ 301*99e0aae7SDavid Rees error.error( 302*99e0aae7SDavid Rees "m.emb", error_type.source_location, 303*99e0aae7SDavid Rees "Fixed-size type 'UInt:32' cannot be placed in field of size 8 " 304*99e0aae7SDavid Rees "bits; requires 32 bits.") 305*99e0aae7SDavid Rees ]], error.filter_errors(constraints.check_constraints(ir))) 306*99e0aae7SDavid Rees 307*99e0aae7SDavid Rees def test_explicit_size_too_small_for_field(self): 308*99e0aae7SDavid Rees ir = _make_ir_from_emb("bits Foo:\n" 309*99e0aae7SDavid Rees " 0 [+64] UInt:32 thirty_two_bit\n") 310*99e0aae7SDavid Rees error_type = ir.module[0].type[0].structure.field[0].type 311*99e0aae7SDavid Rees self.assertEqual([[ 312*99e0aae7SDavid Rees error.error("m.emb", error_type.source_location, 313*99e0aae7SDavid Rees "Fixed-size type 'UInt:32' cannot be placed in field of " 314*99e0aae7SDavid Rees "size 64 bits; requires 32 bits.") 315*99e0aae7SDavid Rees ]], error.filter_errors(constraints.check_constraints(ir))) 316*99e0aae7SDavid Rees 317*99e0aae7SDavid Rees def test_explicit_size_too_big(self): 318*99e0aae7SDavid Rees ir = _make_ir_from_emb("struct Foo:\n" 319*99e0aae7SDavid Rees " 0 [+16] UInt:128 one_twenty_eight_bit\n" 320*99e0aae7SDavid Rees ' [byte_order: "LittleEndian"]\n') 321*99e0aae7SDavid Rees error_field = ir.module[0].type[0].structure.field[0] 322*99e0aae7SDavid Rees uint_type = ir_util.find_object(error_field.type.atomic_type.reference, ir) 323*99e0aae7SDavid Rees uint_requirements = ir_util.get_attribute(uint_type.attribute, 324*99e0aae7SDavid Rees attributes.STATIC_REQUIREMENTS) 325*99e0aae7SDavid Rees self.assertEqual([[ 326*99e0aae7SDavid Rees error.error("m.emb", error_field.source_location, 327*99e0aae7SDavid Rees "Requirements of UInt not met."), 328*99e0aae7SDavid Rees error.note("", uint_requirements.source_location, 329*99e0aae7SDavid Rees "Requirements specified here."), 330*99e0aae7SDavid Rees ]], error.filter_errors(constraints.check_constraints(ir))) 331*99e0aae7SDavid Rees 332*99e0aae7SDavid Rees def test_explicit_enumeration_size_too_big(self): 333*99e0aae7SDavid Rees ir = _make_ir_from_emb('[$default byte_order: "BigEndian"]\n' 334*99e0aae7SDavid Rees "struct Foo:\n" 335*99e0aae7SDavid Rees " 0 [+9] Bar seventy_two_bit\n" 336*99e0aae7SDavid Rees "enum Bar:\n" 337*99e0aae7SDavid Rees " BAZ = 0\n") 338*99e0aae7SDavid Rees error_type = ir.module[0].type[0].structure.field[0].type 339*99e0aae7SDavid Rees self.assertEqual([[ 340*99e0aae7SDavid Rees error.error("m.emb", error_type.source_location, 341*99e0aae7SDavid Rees "Enumeration type 'Bar' cannot be 72 bits; type 'Bar' " + 342*99e0aae7SDavid Rees "must be between 1 and 64 bits, inclusive."), 343*99e0aae7SDavid Rees ]], error.filter_errors(constraints.check_constraints(ir))) 344*99e0aae7SDavid Rees 345*99e0aae7SDavid Rees def test_explicit_enumeration_size_too_big_for_small_enum(self): 346*99e0aae7SDavid Rees ir = _make_ir_from_emb('[$default byte_order: "BigEndian"]\n' 347*99e0aae7SDavid Rees "struct Foo:\n" 348*99e0aae7SDavid Rees " 0 [+8] Bar sixty_four_bit\n" 349*99e0aae7SDavid Rees "enum Bar:\n" 350*99e0aae7SDavid Rees " [maximum_bits: 63]\n" 351*99e0aae7SDavid Rees " BAZ = 0\n") 352*99e0aae7SDavid Rees error_type = ir.module[0].type[0].structure.field[0].type 353*99e0aae7SDavid Rees self.assertEqual([[ 354*99e0aae7SDavid Rees error.error("m.emb", error_type.source_location, 355*99e0aae7SDavid Rees "Enumeration type 'Bar' cannot be 64 bits; type 'Bar' " + 356*99e0aae7SDavid Rees "must be between 1 and 63 bits, inclusive."), 357*99e0aae7SDavid Rees ]], error.filter_errors(constraints.check_constraints(ir))) 358*99e0aae7SDavid Rees 359*99e0aae7SDavid Rees def test_explicit_size_on_fixed_size_type(self): 360*99e0aae7SDavid Rees ir = _make_ir_from_emb("struct Foo:\n" 361*99e0aae7SDavid Rees " 0 [+1] Byte:8 one_byte\n" 362*99e0aae7SDavid Rees "struct Byte:\n" 363*99e0aae7SDavid Rees " 0 [+1] UInt b\n") 364*99e0aae7SDavid Rees self.assertEqual([], constraints.check_constraints(ir)) 365*99e0aae7SDavid Rees 366*99e0aae7SDavid Rees def test_explicit_size_too_small_on_fixed_size_type(self): 367*99e0aae7SDavid Rees ir = _make_ir_from_emb("struct Foo:\n" 368*99e0aae7SDavid Rees " 0 [+0] Byte:0 null_byte\n" 369*99e0aae7SDavid Rees "struct Byte:\n" 370*99e0aae7SDavid Rees " 0 [+1] UInt b\n") 371*99e0aae7SDavid Rees error_type = ir.module[0].type[0].structure.field[0].type 372*99e0aae7SDavid Rees self.assertEqual([[ 373*99e0aae7SDavid Rees error.error( 374*99e0aae7SDavid Rees "m.emb", error_type.size_in_bits.source_location, 375*99e0aae7SDavid Rees "Explicit size of 0 bits does not match fixed size (8 bits) of " 376*99e0aae7SDavid Rees "type 'Byte'."), 377*99e0aae7SDavid Rees error.note("m.emb", ir.module[0].type[1].source_location, 378*99e0aae7SDavid Rees "Size specified here."), 379*99e0aae7SDavid Rees ]], error.filter_errors(constraints.check_constraints(ir))) 380*99e0aae7SDavid Rees 381*99e0aae7SDavid Rees def test_explicit_size_too_big_on_fixed_size_type(self): 382*99e0aae7SDavid Rees ir = _make_ir_from_emb("struct Foo:\n" 383*99e0aae7SDavid Rees " 0 [+2] Byte:16 double_byte\n" 384*99e0aae7SDavid Rees "struct Byte:\n" 385*99e0aae7SDavid Rees " 0 [+1] UInt b\n") 386*99e0aae7SDavid Rees error_type = ir.module[0].type[0].structure.field[0].type 387*99e0aae7SDavid Rees self.assertEqual([[ 388*99e0aae7SDavid Rees error.error( 389*99e0aae7SDavid Rees "m.emb", error_type.size_in_bits.source_location, 390*99e0aae7SDavid Rees "Explicit size of 16 bits does not match fixed size (8 bits) of " 391*99e0aae7SDavid Rees "type 'Byte'."), 392*99e0aae7SDavid Rees error.note( 393*99e0aae7SDavid Rees "m.emb", ir.module[0].type[1].source_location, 394*99e0aae7SDavid Rees "Size specified here."), 395*99e0aae7SDavid Rees ]], error.filter_errors(constraints.check_constraints(ir))) 396*99e0aae7SDavid Rees 397*99e0aae7SDavid Rees def test_explicit_size_ignored_on_variable_size_type(self): 398*99e0aae7SDavid Rees ir = _make_ir_from_emb('[$default byte_order: "LittleEndian"]\n' 399*99e0aae7SDavid Rees "struct Foo:\n" 400*99e0aae7SDavid Rees " 0 [+1] UInt n\n" 401*99e0aae7SDavid Rees " 1 [+n] UInt:8[] d\n" 402*99e0aae7SDavid Rees "struct Bar:\n" 403*99e0aae7SDavid Rees " 0 [+10] Foo:80 foo\n") 404*99e0aae7SDavid Rees self.assertEqual([], constraints.check_constraints(ir)) 405*99e0aae7SDavid Rees 406*99e0aae7SDavid Rees def test_fixed_size_type_in_dynamically_sized_field(self): 407*99e0aae7SDavid Rees ir = _make_ir_from_emb("struct Foo:\n" 408*99e0aae7SDavid Rees " 0 [+1] UInt bar\n" 409*99e0aae7SDavid Rees " 0 [+bar] Byte one_byte\n" 410*99e0aae7SDavid Rees "struct Byte:\n" 411*99e0aae7SDavid Rees " 0 [+1] UInt b\n") 412*99e0aae7SDavid Rees self.assertEqual([], constraints.check_constraints(ir)) 413*99e0aae7SDavid Rees 414*99e0aae7SDavid Rees def test_enum_in_dynamically_sized_field(self): 415*99e0aae7SDavid Rees ir = _make_ir_from_emb('[$default byte_order: "BigEndian"]\n' 416*99e0aae7SDavid Rees "struct Foo:\n" 417*99e0aae7SDavid Rees " 0 [+1] UInt bar\n" 418*99e0aae7SDavid Rees " 0 [+bar] Baz baz\n" 419*99e0aae7SDavid Rees "enum Baz:\n" 420*99e0aae7SDavid Rees " QUX = 0\n") 421*99e0aae7SDavid Rees error_type = ir.module[0].type[0].structure.field[1].type 422*99e0aae7SDavid Rees self.assertEqual( 423*99e0aae7SDavid Rees [[ 424*99e0aae7SDavid Rees error.error("m.emb", error_type.source_location, 425*99e0aae7SDavid Rees "Enumeration type 'Baz' cannot be placed in a " 426*99e0aae7SDavid Rees "dynamically-sized field.") 427*99e0aae7SDavid Rees ]], 428*99e0aae7SDavid Rees error.filter_errors(constraints.check_constraints(ir))) 429*99e0aae7SDavid Rees 430*99e0aae7SDavid Rees def test_enum_value_too_high(self): 431*99e0aae7SDavid Rees ir = _make_ir_from_emb('[$default byte_order: "LittleEndian"]\n' 432*99e0aae7SDavid Rees "enum Foo:\n" 433*99e0aae7SDavid Rees " HIGH = 0x1_0000_0000_0000_0000\n") 434*99e0aae7SDavid Rees error_value = ir.module[0].type[0].enumeration.value[0].value 435*99e0aae7SDavid Rees self.assertEqual([ 436*99e0aae7SDavid Rees [error.error( 437*99e0aae7SDavid Rees "m.emb", error_value.source_location, 438*99e0aae7SDavid Rees # TODO(bolms): Try to print numbers like 2**64 in hex? (I.e., if a 439*99e0aae7SDavid Rees # number is a round number in hex, but not in decimal, print in 440*99e0aae7SDavid Rees # hex?) 441*99e0aae7SDavid Rees "Value 18446744073709551616 is out of range for 64-bit unsigned " + 442*99e0aae7SDavid Rees "enumeration.")] 443*99e0aae7SDavid Rees ], constraints.check_constraints(ir)) 444*99e0aae7SDavid Rees 445*99e0aae7SDavid Rees def test_enum_value_too_low(self): 446*99e0aae7SDavid Rees ir = _make_ir_from_emb('[$default byte_order: "LittleEndian"]\n' 447*99e0aae7SDavid Rees "enum Foo:\n" 448*99e0aae7SDavid Rees " LOW = -0x8000_0000_0000_0001\n") 449*99e0aae7SDavid Rees error_value = ir.module[0].type[0].enumeration.value[0].value 450*99e0aae7SDavid Rees self.assertEqual([ 451*99e0aae7SDavid Rees [error.error( 452*99e0aae7SDavid Rees "m.emb", error_value.source_location, 453*99e0aae7SDavid Rees "Value -9223372036854775809 is out of range for 64-bit signed " + 454*99e0aae7SDavid Rees "enumeration.")] 455*99e0aae7SDavid Rees ], constraints.check_constraints(ir)) 456*99e0aae7SDavid Rees 457*99e0aae7SDavid Rees def test_enum_value_too_wide(self): 458*99e0aae7SDavid Rees ir = _make_ir_from_emb('[$default byte_order: "LittleEndian"]\n' 459*99e0aae7SDavid Rees "enum Foo:\n" 460*99e0aae7SDavid Rees " LOW = -1\n" 461*99e0aae7SDavid Rees " HIGH = 0x8000_0000_0000_0000\n") 462*99e0aae7SDavid Rees error_value = ir.module[0].type[0].enumeration.value[1].value 463*99e0aae7SDavid Rees self.assertEqual([[ 464*99e0aae7SDavid Rees error.error( 465*99e0aae7SDavid Rees "m.emb", error_value.source_location, 466*99e0aae7SDavid Rees "Value 9223372036854775808 is out of range for 64-bit signed " + 467*99e0aae7SDavid Rees "enumeration.") 468*99e0aae7SDavid Rees ]], error.filter_errors(constraints.check_constraints(ir))) 469*99e0aae7SDavid Rees 470*99e0aae7SDavid Rees def test_enum_value_too_wide_unsigned_error_message(self): 471*99e0aae7SDavid Rees ir = _make_ir_from_emb('[$default byte_order: "LittleEndian"]\n' 472*99e0aae7SDavid Rees "enum Foo:\n" 473*99e0aae7SDavid Rees " LOW = -2\n" 474*99e0aae7SDavid Rees " LOW2 = -1\n" 475*99e0aae7SDavid Rees " HIGH = 0x8000_0000_0000_0000\n") 476*99e0aae7SDavid Rees error_value = ir.module[0].type[0].enumeration.value[2].value 477*99e0aae7SDavid Rees self.assertEqual([[ 478*99e0aae7SDavid Rees error.error( 479*99e0aae7SDavid Rees "m.emb", error_value.source_location, 480*99e0aae7SDavid Rees "Value 9223372036854775808 is out of range for 64-bit signed " + 481*99e0aae7SDavid Rees "enumeration.") 482*99e0aae7SDavid Rees ]], error.filter_errors(constraints.check_constraints(ir))) 483*99e0aae7SDavid Rees 484*99e0aae7SDavid Rees def test_enum_value_too_wide_small_size_error_message(self): 485*99e0aae7SDavid Rees ir = _make_ir_from_emb('[$default byte_order: "LittleEndian"]\n' 486*99e0aae7SDavid Rees "enum Foo:\n" 487*99e0aae7SDavid Rees " [maximum_bits: 8]\n" 488*99e0aae7SDavid Rees " HIGH = 0x100\n") 489*99e0aae7SDavid Rees error_value = ir.module[0].type[0].enumeration.value[0].value 490*99e0aae7SDavid Rees self.assertEqual([[ 491*99e0aae7SDavid Rees error.error( 492*99e0aae7SDavid Rees "m.emb", error_value.source_location, 493*99e0aae7SDavid Rees "Value 256 is out of range for 8-bit unsigned enumeration.") 494*99e0aae7SDavid Rees ]], error.filter_errors(constraints.check_constraints(ir))) 495*99e0aae7SDavid Rees 496*99e0aae7SDavid Rees def test_enum_value_too_wide_small_size_signed_error_message(self): 497*99e0aae7SDavid Rees ir = _make_ir_from_emb('[$default byte_order: "LittleEndian"]\n' 498*99e0aae7SDavid Rees "enum Foo:\n" 499*99e0aae7SDavid Rees " [maximum_bits: 8]\n" 500*99e0aae7SDavid Rees " [is_signed: true]\n" 501*99e0aae7SDavid Rees " HIGH = 0x80\n") 502*99e0aae7SDavid Rees error_value = ir.module[0].type[0].enumeration.value[0].value 503*99e0aae7SDavid Rees self.assertEqual([[ 504*99e0aae7SDavid Rees error.error( 505*99e0aae7SDavid Rees "m.emb", error_value.source_location, 506*99e0aae7SDavid Rees "Value 128 is out of range for 8-bit signed enumeration.") 507*99e0aae7SDavid Rees ]], error.filter_errors(constraints.check_constraints(ir))) 508*99e0aae7SDavid Rees 509*99e0aae7SDavid Rees def test_enum_value_too_wide_multiple(self): 510*99e0aae7SDavid Rees ir = _make_ir_from_emb('[$default byte_order: "LittleEndian"]\n' 511*99e0aae7SDavid Rees "enum Foo:\n" 512*99e0aae7SDavid Rees " LOW = -2\n" 513*99e0aae7SDavid Rees " LOW2 = -1\n" 514*99e0aae7SDavid Rees " HIGH = 0x8000_0000_0000_0000\n" 515*99e0aae7SDavid Rees " HIGH2 = 0x8000_0000_0000_0001\n") 516*99e0aae7SDavid Rees error_value = ir.module[0].type[0].enumeration.value[2].value 517*99e0aae7SDavid Rees error_value2 = ir.module[0].type[0].enumeration.value[3].value 518*99e0aae7SDavid Rees self.assertEqual([ 519*99e0aae7SDavid Rees [error.error( 520*99e0aae7SDavid Rees "m.emb", error_value.source_location, 521*99e0aae7SDavid Rees "Value 9223372036854775808 is out of range for 64-bit signed " + 522*99e0aae7SDavid Rees "enumeration.")], 523*99e0aae7SDavid Rees [error.error( 524*99e0aae7SDavid Rees "m.emb", error_value2.source_location, 525*99e0aae7SDavid Rees "Value 9223372036854775809 is out of range for 64-bit signed " + 526*99e0aae7SDavid Rees "enumeration.")] 527*99e0aae7SDavid Rees ], error.filter_errors(constraints.check_constraints(ir))) 528*99e0aae7SDavid Rees 529*99e0aae7SDavid Rees def test_enum_value_too_wide_multiple_signed_error_message(self): 530*99e0aae7SDavid Rees ir = _make_ir_from_emb('[$default byte_order: "LittleEndian"]\n' 531*99e0aae7SDavid Rees "enum Foo:\n" 532*99e0aae7SDavid Rees " LOW = -3\n" 533*99e0aae7SDavid Rees " LOW2 = -2\n" 534*99e0aae7SDavid Rees " LOW3 = -1\n" 535*99e0aae7SDavid Rees " HIGH = 0x8000_0000_0000_0000\n" 536*99e0aae7SDavid Rees " HIGH2 = 0x8000_0000_0000_0001\n") 537*99e0aae7SDavid Rees error_value = ir.module[0].type[0].enumeration.value[3].value 538*99e0aae7SDavid Rees error_value2 = ir.module[0].type[0].enumeration.value[4].value 539*99e0aae7SDavid Rees self.assertEqual([ 540*99e0aae7SDavid Rees [error.error( 541*99e0aae7SDavid Rees "m.emb", error_value.source_location, 542*99e0aae7SDavid Rees "Value 9223372036854775808 is out of range for 64-bit signed " 543*99e0aae7SDavid Rees "enumeration.")], 544*99e0aae7SDavid Rees [error.error( 545*99e0aae7SDavid Rees "m.emb", error_value2.source_location, 546*99e0aae7SDavid Rees "Value 9223372036854775809 is out of range for 64-bit signed " 547*99e0aae7SDavid Rees "enumeration.")] 548*99e0aae7SDavid Rees ], error.filter_errors(constraints.check_constraints(ir))) 549*99e0aae7SDavid Rees 550*99e0aae7SDavid Rees def test_enum_value_mixed_error_message(self): 551*99e0aae7SDavid Rees ir = _make_ir_from_emb('[$default byte_order: "LittleEndian"]\n' 552*99e0aae7SDavid Rees "enum Foo:\n" 553*99e0aae7SDavid Rees " LOW = -1\n" 554*99e0aae7SDavid Rees " HIGH = 0x8000_0000_0000_0000\n" 555*99e0aae7SDavid Rees " HIGH2 = 0x1_0000_0000_0000_0000\n") 556*99e0aae7SDavid Rees error_value1 = ir.module[0].type[0].enumeration.value[1].value 557*99e0aae7SDavid Rees error_value2 = ir.module[0].type[0].enumeration.value[2].value 558*99e0aae7SDavid Rees self.assertEqual([ 559*99e0aae7SDavid Rees [error.error( 560*99e0aae7SDavid Rees "m.emb", error_value1.source_location, 561*99e0aae7SDavid Rees "Value 9223372036854775808 is out of range for 64-bit signed " + 562*99e0aae7SDavid Rees "enumeration.")], 563*99e0aae7SDavid Rees [error.error( 564*99e0aae7SDavid Rees "m.emb", error_value2.source_location, 565*99e0aae7SDavid Rees "Value 18446744073709551616 is out of range for 64-bit signed " + 566*99e0aae7SDavid Rees "enumeration.")] 567*99e0aae7SDavid Rees ], error.filter_errors(constraints.check_constraints(ir))) 568*99e0aae7SDavid Rees 569*99e0aae7SDavid Rees def test_enum_value_explicitly_signed_error_message(self): 570*99e0aae7SDavid Rees ir = _make_ir_from_emb('[$default byte_order: "LittleEndian"]\n' 571*99e0aae7SDavid Rees "enum Foo:\n" 572*99e0aae7SDavid Rees " [is_signed: true]\n" 573*99e0aae7SDavid Rees " HIGH = 0x8000_0000_0000_0000\n" 574*99e0aae7SDavid Rees " HIGH2 = 0x1_0000_0000_0000_0000\n") 575*99e0aae7SDavid Rees error_value0 = ir.module[0].type[0].enumeration.value[0].value 576*99e0aae7SDavid Rees error_value1 = ir.module[0].type[0].enumeration.value[1].value 577*99e0aae7SDavid Rees self.assertEqual([ 578*99e0aae7SDavid Rees [error.error( 579*99e0aae7SDavid Rees "m.emb", error_value0.source_location, 580*99e0aae7SDavid Rees "Value 9223372036854775808 is out of range for 64-bit signed " + 581*99e0aae7SDavid Rees "enumeration.")], 582*99e0aae7SDavid Rees [error.error( 583*99e0aae7SDavid Rees "m.emb", error_value1.source_location, 584*99e0aae7SDavid Rees "Value 18446744073709551616 is out of range for 64-bit signed " + 585*99e0aae7SDavid Rees "enumeration.")] 586*99e0aae7SDavid Rees ], error.filter_errors(constraints.check_constraints(ir))) 587*99e0aae7SDavid Rees 588*99e0aae7SDavid Rees def test_enum_value_explicitly_unsigned_error_message(self): 589*99e0aae7SDavid Rees ir = _make_ir_from_emb('[$default byte_order: "LittleEndian"]\n' 590*99e0aae7SDavid Rees "enum Foo:\n" 591*99e0aae7SDavid Rees " [is_signed: false]\n" 592*99e0aae7SDavid Rees " LOW = -1\n" 593*99e0aae7SDavid Rees " HIGH = 0x8000_0000_0000_0000\n" 594*99e0aae7SDavid Rees " HIGH2 = 0x1_0000_0000_0000_0000\n") 595*99e0aae7SDavid Rees error_value0 = ir.module[0].type[0].enumeration.value[0].value 596*99e0aae7SDavid Rees error_value2 = ir.module[0].type[0].enumeration.value[2].value 597*99e0aae7SDavid Rees self.assertEqual([ 598*99e0aae7SDavid Rees [error.error( 599*99e0aae7SDavid Rees "m.emb", error_value0.source_location, 600*99e0aae7SDavid Rees "Value -1 is out of range for 64-bit unsigned enumeration.")], 601*99e0aae7SDavid Rees [error.error( 602*99e0aae7SDavid Rees "m.emb", error_value2.source_location, 603*99e0aae7SDavid Rees "Value 18446744073709551616 is out of range for 64-bit unsigned " + 604*99e0aae7SDavid Rees "enumeration.")] 605*99e0aae7SDavid Rees ], error.filter_errors(constraints.check_constraints(ir))) 606*99e0aae7SDavid Rees 607*99e0aae7SDavid Rees def test_explicit_non_byte_size_array_element(self): 608*99e0aae7SDavid Rees ir = _make_ir_from_emb('[$default byte_order: "LittleEndian"]\n' 609*99e0aae7SDavid Rees "struct Foo:\n" 610*99e0aae7SDavid Rees " 0 [+2] UInt:4[4] nibbles\n") 611*99e0aae7SDavid Rees error_type = ir.module[0].type[0].structure.field[0].type.array_type 612*99e0aae7SDavid Rees self.assertEqual([ 613*99e0aae7SDavid Rees [error.error( 614*99e0aae7SDavid Rees "m.emb", error_type.base_type.source_location, 615*99e0aae7SDavid Rees "Array elements in structs must have sizes which are a multiple of " 616*99e0aae7SDavid Rees "8 bits.")] 617*99e0aae7SDavid Rees ], error.filter_errors(constraints.check_constraints(ir))) 618*99e0aae7SDavid Rees 619*99e0aae7SDavid Rees def test_implicit_non_byte_size_array_element(self): 620*99e0aae7SDavid Rees ir = _make_ir_from_emb('[$default byte_order: "LittleEndian"]\n' 621*99e0aae7SDavid Rees "bits Nibble:\n" 622*99e0aae7SDavid Rees " 0 [+4] UInt nibble\n" 623*99e0aae7SDavid Rees "struct Foo:\n" 624*99e0aae7SDavid Rees " 0 [+2] Nibble[4] nibbles\n") 625*99e0aae7SDavid Rees error_type = ir.module[0].type[1].structure.field[0].type.array_type 626*99e0aae7SDavid Rees self.assertEqual([ 627*99e0aae7SDavid Rees [error.error( 628*99e0aae7SDavid Rees "m.emb", error_type.base_type.source_location, 629*99e0aae7SDavid Rees "Array elements in structs must have sizes which are a multiple of " 630*99e0aae7SDavid Rees "8 bits.")] 631*99e0aae7SDavid Rees ], error.filter_errors(constraints.check_constraints(ir))) 632*99e0aae7SDavid Rees 633*99e0aae7SDavid Rees def test_bits_must_be_fixed_size(self): 634*99e0aae7SDavid Rees ir = _make_ir_from_emb("bits Dynamic:\n" 635*99e0aae7SDavid Rees " 0 [+3] UInt x\n" 636*99e0aae7SDavid Rees " 3 [+3 * x] UInt:3[x] a\n") 637*99e0aae7SDavid Rees error_type = ir.module[0].type[0] 638*99e0aae7SDavid Rees self.assertEqual([ 639*99e0aae7SDavid Rees [error.error("m.emb", error_type.source_location, 640*99e0aae7SDavid Rees "`bits` types must be fixed size.")] 641*99e0aae7SDavid Rees ], error.filter_errors(constraints.check_constraints(ir))) 642*99e0aae7SDavid Rees 643*99e0aae7SDavid Rees def test_bits_must_be_small(self): 644*99e0aae7SDavid Rees ir = _make_ir_from_emb("bits Big:\n" 645*99e0aae7SDavid Rees " 0 [+64] UInt x\n" 646*99e0aae7SDavid Rees " 64 [+1] UInt y\n") 647*99e0aae7SDavid Rees error_type = ir.module[0].type[0] 648*99e0aae7SDavid Rees self.assertEqual([ 649*99e0aae7SDavid Rees [error.error("m.emb", error_type.source_location, 650*99e0aae7SDavid Rees "`bits` types must be 64 bits or smaller.")] 651*99e0aae7SDavid Rees ], error.filter_errors(constraints.check_constraints(ir))) 652*99e0aae7SDavid Rees 653*99e0aae7SDavid Rees def test_constant_expressions_must_be_small(self): 654*99e0aae7SDavid Rees ir = _make_ir_from_emb('[$default byte_order: "LittleEndian"]\n' 655*99e0aae7SDavid Rees "struct Foo:\n" 656*99e0aae7SDavid Rees " 0 [+8] UInt x\n" 657*99e0aae7SDavid Rees " if x < 0x1_0000_0000_0000_0000:\n" 658*99e0aae7SDavid Rees " 8 [+1] UInt y\n") 659*99e0aae7SDavid Rees condition = ir.module[0].type[0].structure.field[1].existence_condition 660*99e0aae7SDavid Rees error_location = condition.function.args[1].source_location 661*99e0aae7SDavid Rees self.assertEqual([ 662*99e0aae7SDavid Rees [error.error( 663*99e0aae7SDavid Rees "m.emb", error_location, 664*99e0aae7SDavid Rees "Constant value {} of expression cannot fit in a 64-bit signed or " 665*99e0aae7SDavid Rees "unsigned integer.".format(2**64))] 666*99e0aae7SDavid Rees ], error.filter_errors(constraints.check_constraints(ir))) 667*99e0aae7SDavid Rees 668*99e0aae7SDavid Rees def test_variable_expression_out_of_range_for_uint64(self): 669*99e0aae7SDavid Rees ir = _make_ir_from_emb('[$default byte_order: "LittleEndian"]\n' 670*99e0aae7SDavid Rees "struct Foo:\n" 671*99e0aae7SDavid Rees " 0 [+8] UInt x\n" 672*99e0aae7SDavid Rees " if x + 1 < 0xffff_ffff_ffff_ffff:\n" 673*99e0aae7SDavid Rees " 8 [+1] UInt y\n") 674*99e0aae7SDavid Rees condition = ir.module[0].type[0].structure.field[1].existence_condition 675*99e0aae7SDavid Rees error_location = condition.function.args[0].source_location 676*99e0aae7SDavid Rees self.assertEqual([ 677*99e0aae7SDavid Rees [error.error( 678*99e0aae7SDavid Rees "m.emb", error_location, 679*99e0aae7SDavid Rees "Potential range of expression is {} to {}, which cannot fit in a " 680*99e0aae7SDavid Rees "64-bit signed or unsigned integer.".format(1, 2**64))] 681*99e0aae7SDavid Rees ], error.filter_errors(constraints.check_constraints(ir))) 682*99e0aae7SDavid Rees 683*99e0aae7SDavid Rees def test_variable_expression_out_of_range_for_int64(self): 684*99e0aae7SDavid Rees ir = _make_ir_from_emb('[$default byte_order: "LittleEndian"]\n' 685*99e0aae7SDavid Rees "struct Foo:\n" 686*99e0aae7SDavid Rees " 0 [+8] UInt x\n" 687*99e0aae7SDavid Rees " if x - 0x8000_0000_0000_0001 < 0:\n" 688*99e0aae7SDavid Rees " 8 [+1] UInt y\n") 689*99e0aae7SDavid Rees condition = ir.module[0].type[0].structure.field[1].existence_condition 690*99e0aae7SDavid Rees error_location = condition.function.args[0].source_location 691*99e0aae7SDavid Rees self.assertEqual([ 692*99e0aae7SDavid Rees [error.error( 693*99e0aae7SDavid Rees "m.emb", error_location, 694*99e0aae7SDavid Rees "Potential range of expression is {} to {}, which cannot fit in a " 695*99e0aae7SDavid Rees "64-bit signed or unsigned integer.".format(-(2**63) - 1, 696*99e0aae7SDavid Rees 2**63 - 2))] 697*99e0aae7SDavid Rees ], error.filter_errors(constraints.check_constraints(ir))) 698*99e0aae7SDavid Rees 699*99e0aae7SDavid Rees def test_requires_expression_out_of_range_for_uint64(self): 700*99e0aae7SDavid Rees ir = _make_ir_from_emb('[$default byte_order: "LittleEndian"]\n' 701*99e0aae7SDavid Rees "struct Foo:\n" 702*99e0aae7SDavid Rees " 0 [+8] UInt x\n" 703*99e0aae7SDavid Rees " [requires: this * 2 < 0x1_0000]\n") 704*99e0aae7SDavid Rees attribute_list = ir.module[0].type[0].structure.field[0].attribute 705*99e0aae7SDavid Rees error_arg = attribute_list[0].value.expression.function.args[0] 706*99e0aae7SDavid Rees error_location = error_arg.source_location 707*99e0aae7SDavid Rees self.assertEqual( 708*99e0aae7SDavid Rees [[ 709*99e0aae7SDavid Rees error.error( 710*99e0aae7SDavid Rees "m.emb", error_location, 711*99e0aae7SDavid Rees "Potential range of expression is {} to {}, which cannot fit " 712*99e0aae7SDavid Rees "in a 64-bit signed or unsigned integer.".format(0, 2**65-2)) 713*99e0aae7SDavid Rees ]], 714*99e0aae7SDavid Rees error.filter_errors(constraints.check_constraints(ir))) 715*99e0aae7SDavid Rees 716*99e0aae7SDavid Rees def test_arguments_require_different_signedness_64_bits(self): 717*99e0aae7SDavid Rees ir = _make_ir_from_emb( 718*99e0aae7SDavid Rees '[$default byte_order: "LittleEndian"]\n' 719*99e0aae7SDavid Rees "struct Foo:\n" 720*99e0aae7SDavid Rees " 0 [+1] UInt x\n" 721*99e0aae7SDavid Rees # Left side requires uint64, right side requires int64. 722*99e0aae7SDavid Rees " if (x + 0x8000_0000_0000_0000) + (x - 0x7fff_ffff_ffff_ffff) < 10:\n" 723*99e0aae7SDavid Rees " 1 [+1] UInt y\n") 724*99e0aae7SDavid Rees condition = ir.module[0].type[0].structure.field[1].existence_condition 725*99e0aae7SDavid Rees error_expression = condition.function.args[0] 726*99e0aae7SDavid Rees error_location = error_expression.source_location 727*99e0aae7SDavid Rees arg0_location = error_expression.function.args[0].source_location 728*99e0aae7SDavid Rees arg1_location = error_expression.function.args[1].source_location 729*99e0aae7SDavid Rees self.assertEqual([ 730*99e0aae7SDavid Rees [error.error( 731*99e0aae7SDavid Rees "m.emb", error_location, 732*99e0aae7SDavid Rees "Either all arguments to '+' and its result must fit in a 64-bit " 733*99e0aae7SDavid Rees "unsigned integer, or all must fit in a 64-bit signed integer."), 734*99e0aae7SDavid Rees error.note("m.emb", arg0_location, 735*99e0aae7SDavid Rees "Requires unsigned 64-bit integer."), 736*99e0aae7SDavid Rees error.note("m.emb", arg1_location, 737*99e0aae7SDavid Rees "Requires signed 64-bit integer.")] 738*99e0aae7SDavid Rees ], error.filter_errors(constraints.check_constraints(ir))) 739*99e0aae7SDavid Rees 740*99e0aae7SDavid Rees def test_return_value_requires_different_signedness_from_arguments(self): 741*99e0aae7SDavid Rees ir = _make_ir_from_emb( 742*99e0aae7SDavid Rees '[$default byte_order: "LittleEndian"]\n' 743*99e0aae7SDavid Rees "struct Foo:\n" 744*99e0aae7SDavid Rees " 0 [+1] UInt x\n" 745*99e0aae7SDavid Rees # Both arguments require uint64; result fits in int64. 746*99e0aae7SDavid Rees " if (x + 0x7fff_ffff_ffff_ffff) - 0x8000_0000_0000_0000 < 10:\n" 747*99e0aae7SDavid Rees " 1 [+1] UInt y\n") 748*99e0aae7SDavid Rees condition = ir.module[0].type[0].structure.field[1].existence_condition 749*99e0aae7SDavid Rees error_expression = condition.function.args[0] 750*99e0aae7SDavid Rees error_location = error_expression.source_location 751*99e0aae7SDavid Rees arg0_location = error_expression.function.args[0].source_location 752*99e0aae7SDavid Rees arg1_location = error_expression.function.args[1].source_location 753*99e0aae7SDavid Rees self.assertEqual([ 754*99e0aae7SDavid Rees [error.error( 755*99e0aae7SDavid Rees "m.emb", error_location, 756*99e0aae7SDavid Rees "Either all arguments to '-' and its result must fit in a 64-bit " 757*99e0aae7SDavid Rees "unsigned integer, or all must fit in a 64-bit signed integer."), 758*99e0aae7SDavid Rees error.note("m.emb", arg0_location, 759*99e0aae7SDavid Rees "Requires unsigned 64-bit integer."), 760*99e0aae7SDavid Rees error.note("m.emb", arg1_location, 761*99e0aae7SDavid Rees "Requires unsigned 64-bit integer."), 762*99e0aae7SDavid Rees error.note("m.emb", error_location, 763*99e0aae7SDavid Rees "Requires signed 64-bit integer.")] 764*99e0aae7SDavid Rees ], error.filter_errors(constraints.check_constraints(ir))) 765*99e0aae7SDavid Rees 766*99e0aae7SDavid Rees def test_return_value_requires_different_signedness_from_one_argument(self): 767*99e0aae7SDavid Rees ir = _make_ir_from_emb( 768*99e0aae7SDavid Rees '[$default byte_order: "LittleEndian"]\n' 769*99e0aae7SDavid Rees "struct Foo:\n" 770*99e0aae7SDavid Rees " 0 [+1] UInt x\n" 771*99e0aae7SDavid Rees # One argument requires uint64; result fits in int64. 772*99e0aae7SDavid Rees " if (x + 0x7fff_ffff_ffff_fff0) - 0x7fff_ffff_ffff_ffff < 10:\n" 773*99e0aae7SDavid Rees " 1 [+1] UInt y\n") 774*99e0aae7SDavid Rees condition = ir.module[0].type[0].structure.field[1].existence_condition 775*99e0aae7SDavid Rees error_expression = condition.function.args[0] 776*99e0aae7SDavid Rees error_location = error_expression.source_location 777*99e0aae7SDavid Rees arg0_location = error_expression.function.args[0].source_location 778*99e0aae7SDavid Rees self.assertEqual([ 779*99e0aae7SDavid Rees [error.error( 780*99e0aae7SDavid Rees "m.emb", error_location, 781*99e0aae7SDavid Rees "Either all arguments to '-' and its result must fit in a 64-bit " 782*99e0aae7SDavid Rees "unsigned integer, or all must fit in a 64-bit signed integer."), 783*99e0aae7SDavid Rees error.note("m.emb", arg0_location, 784*99e0aae7SDavid Rees "Requires unsigned 64-bit integer."), 785*99e0aae7SDavid Rees error.note("m.emb", error_location, 786*99e0aae7SDavid Rees "Requires signed 64-bit integer.")] 787*99e0aae7SDavid Rees ], error.filter_errors(constraints.check_constraints(ir))) 788*99e0aae7SDavid Rees 789*99e0aae7SDavid Rees def test_checks_constancy_of_constant_references(self): 790*99e0aae7SDavid Rees ir = _make_ir_from_emb("struct Foo:\n" 791*99e0aae7SDavid Rees " 0 [+1] UInt x\n" 792*99e0aae7SDavid Rees " let y = x\n" 793*99e0aae7SDavid Rees " let z = Foo.y\n") 794*99e0aae7SDavid Rees error_expression = ir.module[0].type[0].structure.field[2].read_transform 795*99e0aae7SDavid Rees error_location = error_expression.source_location 796*99e0aae7SDavid Rees note_field = ir.module[0].type[0].structure.field[1] 797*99e0aae7SDavid Rees note_location = note_field.source_location 798*99e0aae7SDavid Rees self.assertEqual([ 799*99e0aae7SDavid Rees [error.error("m.emb", error_location, 800*99e0aae7SDavid Rees "Static references must refer to constants."), 801*99e0aae7SDavid Rees error.note("m.emb", note_location, "y is not constant.")] 802*99e0aae7SDavid Rees ], error.filter_errors(constraints.check_constraints(ir))) 803*99e0aae7SDavid Rees 804*99e0aae7SDavid Rees def test_checks_for_explicit_size_on_parameters(self): 805*99e0aae7SDavid Rees ir = _make_ir_from_emb("struct Foo(y: UInt):\n" 806*99e0aae7SDavid Rees " 0 [+1] UInt x\n") 807*99e0aae7SDavid Rees error_parameter = ir.module[0].type[0].runtime_parameter[0] 808*99e0aae7SDavid Rees error_location = error_parameter.physical_type_alias.source_location 809*99e0aae7SDavid Rees self.assertEqual( 810*99e0aae7SDavid Rees [[error.error("m.emb", error_location, 811*99e0aae7SDavid Rees "Integer range of parameter must not be unbounded; it " 812*99e0aae7SDavid Rees "must fit in a 64-bit signed or unsigned integer.")]], 813*99e0aae7SDavid Rees error.filter_errors(constraints.check_constraints(ir))) 814*99e0aae7SDavid Rees 815*99e0aae7SDavid Rees def test_checks_for_correct_explicit_size_on_parameters(self): 816*99e0aae7SDavid Rees ir = _make_ir_from_emb("struct Foo(y: UInt:300):\n" 817*99e0aae7SDavid Rees " 0 [+1] UInt x\n") 818*99e0aae7SDavid Rees error_parameter = ir.module[0].type[0].runtime_parameter[0] 819*99e0aae7SDavid Rees error_location = error_parameter.physical_type_alias.source_location 820*99e0aae7SDavid Rees self.assertEqual( 821*99e0aae7SDavid Rees [[error.error("m.emb", error_location, 822*99e0aae7SDavid Rees "Potential range of parameter is 0 to {}, which cannot " 823*99e0aae7SDavid Rees "fit in a 64-bit signed or unsigned integer.".format( 824*99e0aae7SDavid Rees 2**300-1))]], 825*99e0aae7SDavid Rees error.filter_errors(constraints.check_constraints(ir))) 826*99e0aae7SDavid Rees 827*99e0aae7SDavid Rees def test_checks_for_explicit_enum_size_on_parameters(self): 828*99e0aae7SDavid Rees ir = _make_ir_from_emb("struct Foo(y: Bar:8):\n" 829*99e0aae7SDavid Rees " 0 [+1] UInt x\n" 830*99e0aae7SDavid Rees "enum Bar:\n" 831*99e0aae7SDavid Rees " QUX = 1\n") 832*99e0aae7SDavid Rees error_parameter = ir.module[0].type[0].runtime_parameter[0] 833*99e0aae7SDavid Rees error_size = error_parameter.physical_type_alias.size_in_bits 834*99e0aae7SDavid Rees error_location = error_size.source_location 835*99e0aae7SDavid Rees self.assertEqual( 836*99e0aae7SDavid Rees [[error.error( 837*99e0aae7SDavid Rees "m.emb", error_location, 838*99e0aae7SDavid Rees "Parameters with enum type may not have explicit size.")]], 839*99e0aae7SDavid Rees error.filter_errors(constraints.check_constraints(ir))) 840*99e0aae7SDavid Rees 841*99e0aae7SDavid Rees 842*99e0aae7SDavid Reesif __name__ == "__main__": 843*99e0aae7SDavid Rees unittest.main() 844