7 use hhbc::HhasAttribute;
10 use hhbc::HhasConstant;
11 use hhbc::HhasFunction;
16 use hhbc::HhasSymbolRefs;
17 use hhbc::HhasTypedef;
19 use crate::code_path::CodePath;
20 use crate::helpers::*;
22 /// Compare two HackCUnits semantically.
24 /// For a semantic comparison we don't care about any bytecode differences as
27 /// 1. Instructs with side-effects exist and are in the same order.
29 /// 2. Instructs that can mutate COW datatypes (dict, vec, keyset, string)
30 /// have the same COW behavior (if a datatype would have been mutated in-place
31 /// in a_unit it should be mutated in-place in b_unit).
33 /// 3. An exception thrown from an instruction will be handled the same way
35 /// In general most of the HackCUnit is compared using Eq - although structs are
36 /// destructured so an error can report where the difference occurred.
38 /// The "interesting" bit happens in `body::compare_bodies()`.
40 pub fn sem_diff_unit<'arena>(a_unit: &HackCUnit<'arena>, b_unit: &HackCUnit<'arena>) -> Result<()> {
43 functions: a_functions,
47 file_attributes: a_file_attributes,
48 module_use: a_module_use,
49 symbol_refs: a_symbol_refs,
50 constants: a_constants,
55 functions: b_functions,
59 file_attributes: b_file_attributes,
60 module_use: b_module_use,
61 symbol_refs: b_symbol_refs,
62 constants: b_constants,
66 let path = CodePath::name("HackCUnit");
68 sem_diff_map_t(&path.qualified("adata"), a_adata, b_adata, sem_diff_eq)?;
71 &path.qualified("typedefs"),
78 &path.qualified("file_attributes"),
84 &path.qualified("fatal"),
85 a_fatal.as_ref().into_option(),
86 b_fatal.as_ref().into_option(),
91 &path.qualified("constants"),
97 sem_diff_symbol_refs(&path.qualified("symbol_refs"), a_symbol_refs, b_symbol_refs)?;
100 &path.qualified("modules"),
107 &path.qualified("module_use"),
108 a_module_use.as_ref().into_option(),
109 b_module_use.as_ref().into_option(),
114 &path.qualified("functions"),
115 a_functions.as_arena_ref(),
116 b_functions.as_arena_ref(),
121 &path.qualified("classes"),
122 a_classes.as_arena_ref(),
123 b_classes.as_arena_ref(),
130 fn sem_diff_attribute(
132 a: &HhasAttribute<'_>,
133 b: &HhasAttribute<'_>,
137 arguments: a_arguments,
141 arguments: b_arguments,
143 sem_diff_eq(&path.qualified("name"), a_name, b_name)?;
145 &path.qualified("arguments"),
153 fn sem_diff_attributes(
155 a: &[HhasAttribute<'_>],
156 b: &[HhasAttribute<'_>],
158 sem_diff_slice(path, a, b, sem_diff_attribute)
161 fn sem_diff_body<'arena>(
163 a: &'arena HhasBody<'arena>,
164 b: &'arena HhasBody<'arena>,
169 num_iters: a_num_iters,
170 is_memoize_wrapper: a_is_memoize_wrapper,
171 is_memoize_wrapper_lsb: a_is_memoize_wrapper_lsb,
172 upper_bounds: a_upper_bounds,
173 shadowed_tparams: a_shadowed_tparams,
175 return_type_info: a_return_type_info,
176 doc_comment: a_doc_comment,
181 num_iters: b_num_iters,
182 is_memoize_wrapper: b_is_memoize_wrapper,
183 is_memoize_wrapper_lsb: b_is_memoize_wrapper_lsb,
184 upper_bounds: b_upper_bounds,
185 shadowed_tparams: b_shadowed_tparams,
187 return_type_info: b_return_type_info,
188 doc_comment: b_doc_comment,
191 sem_diff_eq(&path.qualified("num_iters"), a_num_iters, b_num_iters)?;
193 &path.qualified("params"),
199 &path.qualified("is_memoize_wrapper"),
200 a_is_memoize_wrapper,
201 b_is_memoize_wrapper,
204 &path.qualified("is_memoize_wrapper_lsb"),
205 a_is_memoize_wrapper_lsb,
206 b_is_memoize_wrapper_lsb,
208 sem_diff_eq(&path.qualified("doc_comment"), a_doc_comment, b_doc_comment)?;
210 &path.qualified("return_type_info"),
215 &path.qualified("upper_bounds"),
220 &path.qualified("shadowed_tparams"),
225 // Don't bother comparing decl_vars - when we use named vars later we'll
226 // compare the names to ensure we're using the same ones.
227 // sem_diff_set_t(&path.qualified("decl_vars"), a_decl_vars, b_decl_vars)?;
229 // This compares the instrs themselves.
230 crate::body::compare_bodies(path, a, b)
233 fn sem_diff_param<'arena>(
235 a: &'arena HhasParam<'arena>,
236 b: &'arena HhasParam<'arena>,
240 is_variadic: a_is_variadic,
241 is_inout: a_is_inout,
242 is_readonly: a_is_readonly,
243 user_attributes: a_user_attributes,
244 type_info: a_type_info,
245 default_value: a_default_value,
249 is_variadic: b_is_variadic,
250 is_inout: b_is_inout,
251 is_readonly: b_is_readonly,
252 user_attributes: b_user_attributes,
253 type_info: b_type_info,
254 default_value: b_default_value,
257 sem_diff_eq(&path.qualified("name"), a_name, b_name)?;
258 sem_diff_eq(&path.qualified("is_variadic"), a_is_variadic, b_is_variadic)?;
259 sem_diff_eq(&path.qualified("is_inout"), a_is_inout, b_is_inout)?;
260 sem_diff_eq(&path.qualified("is_readonly"), a_is_readonly, b_is_readonly)?;
262 &path.qualified("user_attributes"),
266 sem_diff_eq(&path.qualified("type_info"), a_type_info, b_type_info)?;
268 &path.qualified("default_value"),
269 a_default_value.as_ref().into_option(),
270 b_default_value.as_ref().into_option(),
271 |path, Pair(_, a_text), Pair(_, b_text)| sem_diff_eq(path, a_text, b_text),
277 fn sem_diff_class<'arena>(
279 a: &'arena HhasClass<'arena>,
280 b: &'arena HhasClass<'arena>,
283 attributes: a_attributes,
285 implements: a_implements,
286 enum_includes: a_enum_includes,
290 enum_type: a_enum_type,
292 properties: a_properties,
293 constants: a_constants,
294 type_constants: a_type_constants,
295 ctx_constants: a_ctx_constants,
296 requirements: a_requirements,
297 upper_bounds: a_upper_bounds,
298 doc_comment: a_doc_comment,
302 attributes: b_attributes,
304 implements: b_implements,
305 enum_includes: b_enum_includes,
309 enum_type: b_enum_type,
311 properties: b_properties,
312 constants: b_constants,
313 type_constants: b_type_constants,
314 ctx_constants: b_ctx_constants,
315 requirements: b_requirements,
316 upper_bounds: b_upper_bounds,
317 doc_comment: b_doc_comment,
321 sem_diff_eq(&path.qualified("name"), a_name, b_name)?;
322 sem_diff_attributes(&path.qualified("attributes"), a_attributes, b_attributes)?;
323 sem_diff_eq(&path.qualified("base"), a_base, b_base)?;
325 sem_diff_eq(&path.qualified("implements"), a_implements, b_implements)?;
327 &path.qualified("enum_includes"),
331 sem_diff_eq(&path.qualified("span"), a_span, b_span)?;
332 sem_diff_eq(&path.qualified("uses"), a_uses, b_uses)?;
334 &path.qualified("enum_type"),
335 a_enum_type.as_ref().into_option(),
336 b_enum_type.as_ref().into_option(),
340 &path.qualified("properties"),
346 &path.qualified("constants"),
352 &path.qualified("type_constants"),
358 &path.qualified("ctx_constants"),
364 &path.qualified("requirements"),
367 |path, a, b| sem_diff_eq(path, &a.1, &b.1),
370 &path.qualified("upper_bounds"),
373 |path, a, b| sem_diff_slice(path, &a.1, &b.1, sem_diff_eq),
375 sem_diff_eq(&path.qualified("doc_comment"), a_doc_comment, b_doc_comment)?;
376 sem_diff_eq(&path.qualified("flags"), a_flags, b_flags)?;
379 &path.qualified("methods"),
388 fn sem_diff_constant(
390 a: &HhasConstant<'_>,
391 b: &HhasConstant<'_>,
396 is_abstract: a_is_abstract,
401 is_abstract: b_is_abstract,
403 sem_diff_eq(&path.qualified("name"), a_name, b_name)?;
405 &path.qualified("value"),
406 a_value.as_ref().into_option(),
407 b_value.as_ref().into_option(),
410 sem_diff_eq(&path.qualified("is_abstract"), a_is_abstract, b_is_abstract)?;
416 a: &Triple<FatalOp, HhasPos, Str<'_>>,
417 b: &Triple<FatalOp, HhasPos, Str<'_>>,
419 sem_diff_eq(&path.index(0), &a.0, &b.0)?;
420 sem_diff_eq(&path.index(1), &a.1, &b.1)?;
421 sem_diff_eq(&path.index(2), &a.2, &b.2)?;
425 fn sem_diff_function<'arena>(
427 a: &'arena HhasFunction<'arena>,
428 b: &'arena HhasFunction<'arena>,
431 attributes: a_attributes,
435 coeffects: a_coeffects,
440 attributes: b_attributes,
444 coeffects: b_coeffects,
449 sem_diff_eq(&path.qualified("name"), a_name, b_name)?;
450 sem_diff_attributes(&path.qualified("attributes"), a_attributes, b_attributes)?;
451 sem_diff_body(&path.qualified("body"), a_body, b_body)?;
452 sem_diff_eq(&path.qualified("span"), a_span, b_span)?;
453 sem_diff_eq(&path.qualified("coeffects"), a_coeffects, b_coeffects)?;
454 sem_diff_eq(&path.qualified("flags"), a_flags, b_flags)?;
455 sem_diff_eq(&path.qualified("attrs"), a_attrs, b_attrs)?;
460 fn sem_diff_method<'arena>(
462 a: &'arena HhasMethod<'arena>,
463 b: &'arena HhasMethod<'arena>,
466 attributes: a_attributes,
467 visibility: a_visibility,
471 coeffects: a_coeffects,
476 attributes: b_attributes,
477 visibility: b_visibility,
481 coeffects: b_coeffects,
485 sem_diff_attributes(&path.qualified("attributes"), a_attributes, b_attributes)?;
486 sem_diff_eq(&path.qualified("visibility"), a_visibility, b_visibility)?;
487 sem_diff_eq(&path.qualified("name"), a_name, b_name)?;
488 sem_diff_body(&path.qualified("body"), a_body, b_body)?;
489 sem_diff_eq(&path.qualified("span"), a_span, b_span)?;
490 sem_diff_eq(&path.qualified("coeffects"), a_coeffects, b_coeffects)?;
491 sem_diff_eq(&path.qualified("flags"), a_flags, b_flags)?;
492 sem_diff_eq(&path.qualified("attrs"), a_attrs, b_attrs)?;
496 fn sem_diff_module<'arena>(
498 a: &HhasModule<'arena>,
499 b: &HhasModule<'arena>,
502 attributes: a_attributes,
507 attributes: b_attributes,
512 sem_diff_eq(&path.qualified("name"), a_name, b_name)?;
513 sem_diff_attributes(&path.qualified("attributes"), a_attributes, b_attributes)?;
514 sem_diff_eq(&path.qualified("span"), a_span, b_span)?;
518 fn sem_diff_symbol_refs<'arena>(
520 a: &HhasSymbolRefs<'arena>,
521 b: &HhasSymbolRefs<'arena>,
524 includes: a_includes,
525 constants: a_constants,
526 functions: a_functions,
530 includes: b_includes,
531 constants: b_constants,
532 functions: b_functions,
537 &path.qualified("includes"),
543 &path.qualified("constants"),
549 &path.qualified("functions"),
555 &path.qualified("classes"),
563 fn sem_diff_typedef<'arena>(
565 a: &HhasTypedef<'arena>,
566 b: &HhasTypedef<'arena>,
570 attributes: a_attributes,
571 type_info: a_type_info,
572 type_structure: a_type_structure,
578 attributes: b_attributes,
579 type_info: b_type_info,
580 type_structure: b_type_structure,
585 sem_diff_eq(&path.qualified("name"), a_name, b_name)?;
586 sem_diff_attributes(&path.qualified("attributes"), a_attributes, b_attributes)?;
587 sem_diff_eq(&path.qualified("type_info"), a_type_info, b_type_info)?;
589 &path.qualified("type_structure"),
593 sem_diff_eq(&path.qualified("span"), a_span, b_span)?;
594 sem_diff_eq(&path.qualified("attrs"), a_attrs, b_attrs)?;