123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777(******************************************************************************)(* ASLRef *)(******************************************************************************)(*
* SPDX-FileCopyrightText: Copyright 2022-2023 Arm Limited and/or its affiliates <open-source-office@arm.com>
* SPDX-License-Identifier: BSD-3-Clause
*)(******************************************************************************)(* Disclaimer: *)(* This material covers both ASLv0 (viz, the existing ASL pseudocode language *)(* which appears in the Arm Architecture Reference Manual) and ASLv1, a new, *)(* experimental, and as yet unreleased version of ASL. *)(* This material is work in progress, more precisely at pre-Alpha quality as *)(* per Arm’s quality standards. *)(* In particular, this means that it would be premature to base any *)(* production tool development on this material. *)(* However, any feedback, question, query and feature request would be most *)(* welcome; those can be sent to Arm’s Architecture Formal Team Lead *)(* Jade Alglave <jade.alglave@arm.com>, or by raising issues or PRs to the *)(* herdtools7 github repository. *)(******************************************************************************)openASTopenASTUtilsopenInfixmoduleSEnv=StaticEnvtypeenv=SEnv.envmoduleTypingRule=Instrumentation.TypingRulelet(|:)=Instrumentation.TypingNoInstr.use_withletundefined_identifierposx=Error.fatal_frompos(Error.UndefinedIdentifierx)letthing_equalastutil_equalenv=astutil_equal(StaticModel.equal_in_envenv)letexpr_equal=thing_equalexpr_equallettype_equal=thing_equaltype_equalletarray_length_equal=thing_equalarray_length_equalletbitwidth_equal=thing_equalbitwidth_equalletslices_equal=thing_equalslices_equalletbitfield_equal=thing_equalbitfield_equalletconstraints_equal=thing_equalconstraints_equalletassoc_mapmapli=List.map(fun(x,y)->(x,mapy))li(* --------------------------------------------------------------------------*)(* Begin Anonymize *)letrecmake_anonymous(env:env)(ty:ty):ty=matchty.descwith|T_Namedx->(matchIMap.find_optxenv.global.declared_typeswith|Some(t1,_)->make_anonymousenvt1|None->undefined_identifiertyx)|_->ty(* End *)(* TODO: rethink to have physical equality when structural equality? *)(* TODO: memoize? *)(* Begin Structure *)letrecget_structure(env:env)(ty:ty):ty=let()=iffalsethenFormat.eprintf"@[Getting structure of %a.@]@."PP.pp_tytyinletwith_pos=add_pos_fromtyin(matchty.descwith|T_Namedx->(matchIMap.find_optxenv.global.declared_typeswith|None->undefined_identifiertyx|Some(t1,_)->get_structureenvt1)|T_Int_|T_Real|T_String|T_Bool|T_Bits_|T_Enum_->ty|T_Tupletys->T_Tuple(List.map(get_structureenv)tys)|>with_pos|T_Array(e,t)->T_Array(e,(get_structureenv)t)|>with_pos|T_Recordfields->letfields'=assoc_map(get_structureenv)fields|>canonical_fieldsinT_Recordfields'|>with_pos|T_Exceptionfields->letfields'=assoc_map(get_structureenv)fields|>canonical_fieldsinT_Exceptionfields'|>with_pos)|:TypingRule.Structure(* End *)(* --------------------------------------------------------------------------*)(* Begin BuiltinSingular *)letis_builtin_singularty=(matchty.descwith|T_Real|T_String|T_Bool|T_Bits_|T_Enum_|T_Int_->true|T_Tuple_|T_Array(_,_)|T_Record_|T_Exception_|T_Named_->false)|:TypingRule.BuiltinSingularType(* End *)(* Begin BuiltinAggregate *)letis_builtin_aggregatety=(matchty.descwith|T_Tuple_|T_Array_|T_Record_|T_Exception_->true|T_Int_|T_Bits(_,_)|T_Real|T_String|T_Bool|T_Enum_|T_Named_->false)|:TypingRule.BuiltinAggregateType(* End *)(* Begin BuiltinSingularOrAggregate *)letis_builtinty=(is_builtin_singularty||is_builtin_aggregatety)|:TypingRule.BuiltinSingularOrAggregate(* End *)(* Begin Named *)letis_namedty=(matchty.descwithT_Named_->true|_->false)|:TypingRule.NamedType(* End *)(* Begin Anonymous *)letis_anonymousty=(not(is_namedty))|:TypingRule.AnonymousType(* End *)(* A named type is singular if its underlying (a.k.a. anonimized) type is a builtin-singular type,
otherwise it is aggregate. *)(* Begin Singular *)letis_singularenvty=make_anonymousenvty|>is_builtin_singular|:TypingRule.SingularType(* End *)(* A named type is singular if its underlying (a.k.a. anonimized) type is a builtin-aggregate type. *)(* Begin Aggregate *)letis_aggregateenvty=make_anonymousenvty|>is_builtin_aggregate|:TypingRule.AggregateType(* End *)(* Begin NonPrimitive *)letrecis_non_primitivety=(matchty.descwith|T_Real|T_String|T_Bool|T_Bits_|T_Enum_|T_Int_->false|T_Named_->true|T_Tupletys->List.existsis_non_primitivetys|T_Array(_,ty)->is_non_primitivety|T_Recordfields|T_Exceptionfields->List.exists(fun(_,ty)->is_non_primitivety)fields)|:TypingRule.NonPrimitiveType(* End *)(* Begin Primitive *)letis_primitivety=(not(is_non_primitivety))|:TypingRule.PrimitiveType(* End *)letparameterized_constraints=letnext_uid=ref0infunvar->letuid=!next_uidinincrnext_uid;Parameterized(uid,var)letparameterized_tyvar=T_Int(parameterized_constraintsvar)|>add_dummy_annotationletto_well_constrainedty=matchty.descwith|T_Int(Parameterized(_uid,var))->var_var|>integer_exact|_->tyletget_well_constrained_structureenvty=get_structureenvty|>to_well_constrained(* --------------------------------------------------------------------------*)moduleDomain=structmoduleIntSet=Diet.Ztypesyntax=AST.int_constraintlist(** Represents the domain of an integer expression. *)typet=FiniteofIntSet.t|Top|FromSyntaxofsyntaxletadd_interval_to_intsetaccbottop=ifbot>topthenaccelseletinterval=IntSet.Interval.makebottopinIntSet.addintervalaccletppf=letopenFormatinfunction|Top->pp_print_stringf"ℤ"|Finiteset->fprintff"@[{@,%a}@]"IntSet.ppset|FromSyntaxslices->PP.pp_int_constraintsfslicesexceptionStaticEvaluationTop(* Begin NormalizeToInt *)leteval(env:env)(e:expr)=matchStaticModel.reduce_to_z_optenvewith|None->raiseStaticEvaluationTop|Somei->i(* End *)(* Begin ConstraintToIntSet *)letadd_constraint_to_intsetenvacc=function|Constraint_Exacte->letv=evalenveinadd_interval_to_intsetaccvv|Constraint_Range(bot,top)->letbot=evalenvbotandtop=evalenvtopinadd_interval_to_intsetaccbottop(* End *)(* Begin IntSetOfIntConstraints *)letint_set_of_int_constraintsenvconstraints=matchconstraintswith|[]->Error.fatal_fromASTUtils.dummy_annotatedError.EmptyConstraints|_->(tryFinite(List.fold_left(add_constraint_to_intsetenv)IntSet.emptyconstraints)withStaticEvaluationTop->FromSyntaxconstraints)(* End *)(* Begin IntSetToIntConstraints *)letint_set_to_int_constraints=letinterval_to_constraintinterval=letx=IntSet.Interval.xintervalandy=IntSet.Interval.yintervalinletexpr_of_zz=L_Intz|>literalinConstraint_Range(expr_of_zx,expr_of_zy)infunis->IntSet.fold(funintervalacc->interval_to_constraintinterval::acc)is[](* End *)(* Begin IntSetOp *)letrecint_set_raise_interval_opfopopis1is2=match(is1,is2)with|Top,_|_,Top->Top|Finiteis1,Finiteis2->(tryFinite(IntSet.fold(funi1->IntSet.fold(funi2->IntSet.add(fopi1i2))is2)is1IntSet.empty)withStaticEvaluationTop->lets1=int_set_to_int_constraintsis1ands2=int_set_to_int_constraintsis2inint_set_raise_interval_opfopop(FromSyntaxs1)(FromSyntaxs2))|Finiteis1,FromSyntax_->lets1=int_set_to_int_constraintsis1inint_set_raise_interval_opfopop(FromSyntaxs1)is2|FromSyntax_,Finiteis2->lets2=int_set_to_int_constraintsis2inint_set_raise_interval_opfopopis1(FromSyntaxs2)|FromSyntaxs1,FromSyntaxs2->FromSyntax(StaticOperations.constraint_binopops1s2)(* End *)letmonotone_interval_opopi1i2=letopenIntSet.Intervalinletx=op(xi1)(xi2)andy=op(yi1)(yi2)inifx<ythenmakexyelseraiseStaticEvaluationTopletanti_monotone_interval_opopi1i2=letopenIntSet.Intervalinletx=op(xi1)(yi2)andy=op(yi1)(xi2)inifx<ythenmakexyelseraiseStaticEvaluationTopletof_literal=function|L_Intn->Finite(IntSet.singletonn)|_->raiseStaticEvaluationTop(* [of_expr env e] returns the symbolic integer domain for the integer-typed expression [e]. *)letrecof_exprenve=matche.descwith|E_Literalv->of_literalv|E_Varx->(trySEnv.lookup_constantsenvx|>of_literalwithNot_found->(trySEnv.type_ofenvx|>of_typeenvwithNot_found->Error.fatal_frome(Error.UndefinedIdentifierx)))|E_Unop(NEG,e1)->of_exprenv(E_Binop(MINUS,!$0,e1)|>add_pos_frome)|E_Binop(((PLUS|MINUS|MUL)asop),e1,e2)->letis1=of_exprenve1andis2=of_exprenve2andfop=matchopwith|PLUS->monotone_interval_opZ.add|MINUS->anti_monotone_interval_opZ.sub|MUL->monotone_interval_opZ.mul|_->assertfalseinint_set_raise_interval_opfopopis1is2|_->let()=iffalsethenFormat.eprintf"@[<2>Cannot interpret as int set:@ @[%a@]@]@."PP.pp_expreinFromSyntax[Constraint_Exacte]andof_width_exprenve=lete_domain=of_exprenveinletexact_domain=FromSyntax[Constraint_Exacte]inmatche_domainwith|Finiteint_set->ifZ.equal(IntSet.cardinalint_set)Z.onethene_domainelseexact_domain|FromSyntax[Constraint_Exact_]->e_domain|_->exact_domainandof_typeenvty=letty=make_anonymousenvtyinmatchty.descwith|T_IntUnConstrained->Top|T_Int(Parameterized(_uid,var))->FromSyntax[Constraint_Exact(var_var)]|T_Int(WellConstrainedconstraints)->int_set_of_int_constraintsenvconstraints|T_IntPendingConstrained->assertfalse|T_Bool|T_String|T_Real->failwith"Unimplemented: domain of primitive type"|T_Bits_|T_Enum_|T_Array_|T_Exception_|T_Record_|T_Tuple_->failwith"Unimplemented: domain of a non singular type."|T_Named_->assertfalse(* make anonymous *)letmemvd=match(v,d)with|L_Bool_,_|L_Real_,_|L_String_,_|L_BitVector_,_|L_Label_,_->false|L_Int_,Top->true|L_Inti,Finiteintset->IntSet.memiintset|L_Int_,_->falseletequald1d2=match(d1,d2)with|Top,Top->true|Finiteis1,Finiteis2->IntSet.equalis1is2|_->falseletcompare_d1_d2=assertfalse(** The [StaticApprox] module creates constant approximation of integer
constraints as sets of integers. *)moduleStaticApprox=struct(** The two possible types of approximations. *)typeapprox=Over|UnderexceptionCannotOverApproximate(** Raised if over approximation is not possible. *)(** Return bottom for Under approximation, top for over approximation. *)letbottom_topapprox=ifapprox=OverthenraiseCannotOverApproximateelseIntSet.emptyletmake_intervalapproxz1z2=ifZ.leqz1z2thenIntSet.(add(Interval.makez1z2)empty)elsebottom_topapproxletliteral_to_z=functionL_Intz->Somez|_->Noneletapply_unoplocopz=letopenErrorintryOperations.unop_valueslocError.Staticop(L_Intz)|>literal_to_zwithASLException{desc=UnsupportedUnop_}->Noneletapply_binoplocopz1z2=letopenErrorintryOperations.binop_valueslocStaticop(L_Intz1)(L_Intz2)|>literal_to_zwithASLException{desc=UnsupportedBinop_}->None(* Begin ApproxExpr *)letrecapprox_exprapproxenve=matche.descwith|E_Literal(L_Intz)->IntSet.singletonz|E_Literal_->bottom_topapprox|E_Varx->(matchapproxwith|Over->approx_typeOverenv(SEnv.type_ofenvx)|Under->IntSet.empty)|E_Unop(op,e')->IntSet.filter_map_individual(apply_unopeop)(approx_exprapproxenve')|E_Binop(op,e1,e2)->IntSet.cross_filter_map_individual(apply_binopeop)(approx_exprapproxenve1)(approx_exprapproxenve2)|E_Cond(_econd,e2,e3)->(lets2=approx_exprapproxenve2ands3=approx_exprapproxenve3inmatchapproxwith|Over->IntSet.unions2s3|Under->IntSet.inters2s3)|_->bottom_topapprox(* End *)(* Begin ApproxType *)andapprox_typeapproxenvt=matcht.descwith|T_Named_->make_anonymousenvt|>approx_typeapproxenv|T_Int(WellConstrainedcs)->approx_constraintsapproxenvcs|_->bottom_topapprox(* End *)(* Begin ApproxConstraints *)andapprox_constraintsapproxenvcs=letjoin=letempty=IntSet.empty(* will not be used *)inmatchapproxwith|Under->list_iterated_op~emptyIntSet.inter|Over->list_iterated_op~emptyIntSet.unioninList.map(approx_constraintapproxenv)cs|>join|:TypingRule.ApproxConstraints(* End *)(* Begin ApproxConstraint *)andapprox_constraintapproxenv=function|Constraint_Exacte->approx_exprapproxenve|:TypingRule.ApproxConstraint|Constraint_Range(e1,e2)->(tryletz1,z2=matchapproxwith|Over->(approx_expr_minenve1,approx_expr_maxenve2)|Under->(approx_expr_maxenve1,approx_expr_minenve2)inmake_intervalapproxz1z2withNot_found|CannotOverApproximate->bottom_topapprox)(* end *)(* Begin ApproxExprMin *)andapprox_expr_minenve=approx_exprOverenve|>IntSet.min_elt(* End *)(* Begin ApproxExprMax *)andapprox_expr_maxenve=approx_exprOverenve|>IntSet.max_elt(* End *)end(* Begin SymDomIsSubset *)letis_subsetenvis1is2=let()=iffalsethenFormat.eprintf"Is %a a subset of %a?@."ppis1ppis2inletopenStaticApproxin(match(is1,is2)with|_,Top->true|Top,_->false|Finiteints1,Finiteints2->IntSet.(is_empty(diffints1ints2))|FromSyntaxcs1,FromSyntaxcs2->(constraints_equalenvcs1cs2||trylets1=approx_constraintsOverenvcs1ands2=approx_constraintsUnderenvcs2inIntSet.subsets1s2withCannotOverApproximate->false)|Finites1,FromSyntaxcs2->lets2=approx_constraintsUnderenvcs2inIntSet.subsets1s2|FromSyntaxcs1,Finites2->(trylets1=approx_constraintsOverenvcs1inIntSet.subsets1s2withCannotOverApproximate->false))|:TypingRule.SymDomIsSubset(* End *)end(* --------------------------------------------------------------------------*)letis_bits_width_fixedenvty=matchty.descwith|T_Bits_->(letopenDomaininmatchof_typeenvtywith|Finiteint_set->IntSet.cardinalint_set=Z.one|Top->false|_->failwith"Wrong domain for a bitwidth.")|_->failwith"Wrong type for some bits."let_is_bits_width_constrainedenvty=not(is_bits_width_fixedenvty)(* --------------------------------------------------------------------------*)(* Begin Subtype *)letrecsubtypes_namesenvs1s2=ifString.equals1s2thentrueelsematchIMap.find_opts1env.SEnv.global.subtypeswith|None->false|Somes1'->subtypes_namesenvs1's2letsubtypesenvt1t2=(match(t1.desc,t2.desc)with|T_Nameds1,T_Nameds2->subtypes_namesenvs1s2|_->false)|:TypingRule.Subtype(* End Subtype *)letrecbitfields_includedenvbfs1bfs2=letrecmem_bfsbfs2bf1=matchfind_bitfield_opt(bitfield_get_namebf1)bfs2with|None->false|Some(BitField_Simple_asbf2)->bitfield_equalenvbf1bf2|Some(BitField_Nested(name2,slices2,bfs2')asbf2)->(matchbf1with|BitField_Simple_->bitfield_equalenvbf1bf2|BitField_Nested(name1,slices1,bfs1)->String.equalname1name2&&slices_equalenvslices1slices2&&incl_bfsbfs1bfs2'|BitField_Type_->false)|Some(BitField_Type(name2,slices2,ty2)asbf2)->(matchbf1with|BitField_Simple_->bitfield_equalenvbf1bf2|BitField_Nested_->false|BitField_Type(name1,slices1,ty1)->String.equalname1name2&&slices_equalenvslices1slices2&&subtype_satisfiesenvty1ty2)andincl_bfsbfs1bfs2=List.for_all(mem_bfsbfs2)bfs1inincl_bfsbfs1bfs2(* Begin TypingRule.SubtypeSatisfaction *)andsubtype_satisfiesenvts=(* A type T subtype-satisfies type S if and only if all of the following
conditions hold: *)(match((make_anonymousenvs).desc,(make_anonymousenvt).desc)with(* If S has the structure of an integer type then T must have the structure
of an integer type. *)|T_Int_,T_Int_->letd_s=Domain.of_typeenvsandd_t=Domain.of_typeenvtinlet()=iffalsethenFormat.eprintf"domain_subtype_satisfies: %a included in %a?@."Domain.ppd_tDomain.ppd_sinDomain.is_subsetenvd_td_s(* If S has the structure of a real/string/bool then T must have the
same structure. *)|(((T_Real|T_String|T_Bool)ass_anon),((T_Real|T_String|T_Bool)ast_anon))->s_anon=t_anon(* If S has the structure of an enumeration type then T must have
the structure of an enumeration type with exactly the same
enumeration literals. *)|T_Enumli_s,T_Enumli_t->list_equalString.equalli_sli_t(*
• If S has the structure of a bitvector type then T must have the
structure of a bitvector type of the same width.
• If S has the structure of a bitvector type which has bitfields then T
must have the structure of a bitvector type of the same width and for
every bitfield in S there must be a bitfield in T of the same name, width
and offset, whose type type-satisfies the bitfield in S.
*)|T_Bits(w_s,bf_s),T_Bits(w_t,bf_t)->letbitfields_subtype=bitfields_includedenvbf_sbf_tinletwidths_subtype=lett_width_domain=Domain.of_width_exprenvw_tands_width_domain=Domain.of_width_exprenvw_sinlet()=iffalsethenFormat.eprintf"Is %a included in %a?@."Domain.ppt_width_domainDomain.pps_width_domaininDomain.is_subsetenvt_width_domains_width_domaininbitfields_subtype&&widths_subtype(* If S has the structure of an array type with elements of type E then
T must have the structure of an array type with elements of type E,
and T must have the same element indices as S. *)|T_Array(length_s,ty_s),T_Array(length_t,ty_t)->(type_equalenvty_sty_t&&match(length_s,length_t)with|ArrayLength_Exprlength_expr_s,ArrayLength_Exprlength_expr_t->expr_equalenvlength_expr_slength_expr_t|ArrayLength_Enum(name_s,_),ArrayLength_Enum(name_t,_)->String.equalname_sname_t|ArrayLength_Enum(_,_),ArrayLength_Expr_|ArrayLength_Expr_,ArrayLength_Enum(_,_)->false)(* If S has the structure of a tuple type then T must have the
structure of a tuple type with same number of elements as S,
and each element in T must type-satisfy the corresponding
element in S.*)|T_Tupleli_s,T_Tupleli_t->List.compare_lengthsli_sli_t=0&&List.for_all2(type_satisfiesenv)li_tli_s(* If S has the structure of an exception type then T must have the
structure of an exception type with at least the same fields
(each with the same type) as S.
If S has the structure of a record type then T must have the
structure of a record type with at least the same fields
(each with the same type) as S. *)|T_Exceptionfields_s,T_Exceptionfields_t|T_Recordfields_s,T_Recordfields_t->List.for_all(fun(name_s,ty_s)->List.exists(fun(name_t,ty_t)->String.equalname_sname_t&&type_equalenvty_sty_t)fields_t)fields_s|T_Named_,_->assertfalse|_,_->false)|:TypingRule.SubtypeSatisfaction(* End *)(* Begin TypeSatisfaction *)andtype_satisfiesenvts=((* Type T type-satisfies type S if and only if at least one of the following
conditions holds: *)(* T is a subtype of S *)subtypesenvts(* T subtype-satisfies S and at least one of S or T is an anonymous type *)||((is_anonymoust||is_anonymouss)&&subtype_satisfiesenvts)||(* T is an anonymous bitvector with no bitfields and S has the
structure of a bitvector (with or without bitfields) of the
same width as T. *)(* Here we interpret "same width" as statically the same width *)match(t.desc,(get_structureenvs).desc)with|T_Bits(width_t,[]),T_Bits(width_s,_)->bitwidth_equalenvwidth_twidth_s|_->false)|:TypingRule.TypeSatisfaction(* End *)(* --------------------------------------------------------------------------*)(* Begin TypeClash *)letrectype_clashesenvts=(*
Definition VPZZ:
A type T type-clashes with S if any of the following hold:
• they both have the structure of integers
• they both have the structure of reals
• they both have the structure of strings
• they both have the structure of enumeration types with the same
enumeration literals
• they both have the structure of bitvectors
• they both have the structure of arrays whose element types
type-clash
• they both have the structure of tuples of the same length whose
corresponding element types type-clash
• S is either a subtype or a supertype of T *)(* We will add a rule for boolean and boolean. *)((subtypesenvst||subtypesenvts)||lets_struct=get_structureenvsandt_struct=get_structureenvtinmatch(s_struct.desc,t_struct.desc)with|T_Int_,T_Int_|T_Real,T_Real|T_String,T_String|T_Bits_,T_Bits_|T_Bool,T_Bool->true|T_Enumli_s,T_Enumli_t->list_equalString.equalli_sli_t|T_Array(_,ty_s),T_Array(_,ty_t)->type_clashesenvty_sty_t|T_Tupleli_s,T_Tupleli_t->List.compare_lengthsli_sli_t=0&&List.for_all2(type_clashesenv)li_sli_t|_->false)|:TypingRule.TypeClash(* End *)letsubprogram_clashesenv(f1:func)(f2:func)=(* Two subprograms clash if all of the following hold:
• they have the same name
• they are the same kind of subprogram
• they have the same number of formal arguments
• every formal argument in one type-clashes with the corresponding formal
argument in the other
TODO: they are the same kind of subprogram
*)String.equalf1.namef2.name&&List.compare_lengthsf1.argsf2.args=0&&List.for_all2(fun(_,t1)(_,t2)->type_clashesenvt1t2)f1.argsf2.args(* --------------------------------------------------------------------------*)letsupertypes_set(env:env)=letrecauxaccx=letacc=ISet.addxaccinmatchIMap.find_optxenv.global.subtypeswith|Somex'->auxaccx'|None->accinauxISet.emptyletfind_named_lowest_common_supertypeenvx1x2=(* TODO: Have a better algorithm? This is in O(h * log h) because set
insertions are in O (log h), where h is the max height of the subtype
tree. Wikipedia says it is in O(h) generally, and it can be precomputed,
in which case it becomes O(1). *)letset1=supertypes_setenvx1inletrecauxx=ifISet.memxset1thenSomexelsematchIMap.find_optxenv.global.subtypeswith|None->None|Somex'->auxx'inauxx2(* [unpack_options li] is [Some [x1; ... x_n]] if [li] is [[Some x1; ... Some x_n]], [None] otherwise *)letunpack_optionsli=letexceptionNoneFoundinletunpack_one=functionSomeelt->elt|None->raiseNoneFoundintrySome(List.mapunpack_oneli)withNoneFound->None(* Begin LowestCommonAncestor *)letreclowest_common_ancestorenvst=let(let+)of=Option.mapfoin(* The lowest common ancestor of types S and T is: *)(match(s.desc,t.desc)with|_,_whentype_equalenvst->(* • If S and T are the same type: S (or T). *)Somes|T_Namedname_s,T_Namedname_t->((* If S and T are both named types: the (unique) common supertype of S
and T that is a subtype of all other common supertypes of S and T. *)matchfind_named_lowest_common_supertypeenvname_sname_twith|Somename->Some(T_Namedname|>add_dummy_annotation)|None->letanon_s=make_anonymousenvsandanon_t=make_anonymousenvtinlowest_common_ancestorenvanon_sanon_t)|_,T_Named_|T_Named_,_->letanon_s=make_anonymousenvsandanon_t=make_anonymousenvtiniftype_equalenvanon_sanon_tthenSome(matchs.descwithT_Named_->s|_->t)elselowest_common_ancestorenvanon_sanon_t|T_Int_,T_IntUnConstrained|T_IntUnConstrained,T_Int_->(* If either S or T is an unconstrained integer type: the unconstrained
integer type. *)Someinteger|T_Int_,T_Int(Parameterized_)|T_Int(Parameterized_),T_Int_->lowest_common_ancestorenv(to_well_constraineds)(to_well_constrainedt)|T_Int(WellConstrainedcs_s),T_Int(WellConstrainedcs_t)->(* If S and T both are well-constrained integer types: the
well-constrained integer type with domain the union of the
domains of S and T. *)(* TODO: simplify domains ? If domains use a form of diets,
this could be more efficient. *)Some(add_dummy_annotation(T_Int(WellConstrained(cs_s@cs_t))))|T_Bits(e_s,_),T_Bits(e_t,_)whenexpr_equalenve_se_t->(* We forget the bitfields if they are not equal. *)Some(T_Bits(e_s,[])|>add_dummy_annotation)|T_Array(width_s,ty_s),T_Array(width_t,ty_t)whenarray_length_equalenvwidth_swidth_t->let+t=lowest_common_ancestorenvty_sty_tinT_Array(width_s,t)|>add_dummy_annotation|T_Tupleli_s,T_Tupleli_twhenList.compare_lengthsli_sli_t=0->(* If S and T both are tuple types with the same number of elements:
the tuple type with the type of each element the lowest common ancestor
of the types of the corresponding elements of S and T. *)let+li=List.map2(lowest_common_ancestorenv)li_sli_t|>unpack_optionsinadd_dummy_annotation(T_Tupleli)|_->None)|:TypingRule.LowestCommonAncestor(* End *)