xref: /aosp_15_r20/external/emboss/compiler/front_end/constraints_test.py (revision 99e0aae7469b87d12f0ad23e61142c2d74c1ef70)
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