@@ -42,6 +42,37 @@ fun <Type> UState<Type, *, *, *, *, *>.objectTypeEquals(
4242 )
4343}
4444
45+ fun <Type > UState <Type , * , * , * , * , * >.objectTypeSubtype (
46+ lhs : UHeapRef ,
47+ rhs : UHeapRef
48+ ): UBoolExpr = with (lhs.uctx) {
49+ mapTypeStream(
50+ ref = lhs,
51+ onNull = { trueExpr },
52+ operation = { lhsRef, lhsTypes ->
53+ mapTypeStream(
54+ rhs,
55+ onNull = { falseExpr },
56+ operation = { rhsRef, rhsTypes ->
57+ mkSubtypeConstraint(lhsRef, lhsTypes, rhsRef, rhsTypes)
58+ }
59+ )
60+ }
61+ )
62+ }
63+
64+ fun <Type , R : USort > UState <Type , * , * , * , * , * >.mapTypeStreamNotNull (
65+ ref : UHeapRef ,
66+ operation : (UHeapRef , UTypeStream <Type >) -> UExpr <R >?
67+ ): UExpr <R >? = mapTypeStream(
68+ ref = ref,
69+ onNull = { error(" unexpected null" ) },
70+ operation = { expr, types ->
71+ operation(expr, types) ? : return null
72+ },
73+ ignoreNullRefs = true
74+ )
75+
4576fun <Type , R : USort > UState <Type , * , * , * , * , * >.mapTypeStream (
4677 ref : UHeapRef ,
4778 operation : (UHeapRef , UTypeStream <Type >) -> UExpr <R >?
@@ -53,6 +84,12 @@ fun <Type, R : USort> UState<Type, *, *, *, *, *>.mapTypeStream(
5384 }
5485)
5586
87+ /* *
88+ * Utility function to assert that type of lhs ref is equal to the type of the rhs ref.
89+ *
90+ * Note: if both refs have no concrete type stream, the result expression will be extremely complex.
91+ * So, we mock the result of this operation.
92+ * */
5693private fun <Type > UState <Type , * , * , * , * , * >.mkTypeEqualsConstraint (
5794 lhs : UHeapRef ,
5895 lhsTypes : UTypeStream <Type >,
@@ -78,12 +115,44 @@ private fun <Type> UState<Type, *, *, *, *, *>.mkTypeEqualsConstraint(
78115 makeSymbolicPrimitive(boolSort)
79116}
80117
118+ /* *
119+ * Utility function to assert that type of lhs ref is subtype of type of the rhs ref.
120+ *
121+ * Note: if both refs have no concrete type stream, the result expression will be extremely complex.
122+ * So, we mock the result of this operation.
123+ * */
124+ private fun <Type > UState <Type , * , * , * , * , * >.mkSubtypeConstraint (
125+ lhs : UHeapRef ,
126+ lhsTypes : UTypeStream <Type >,
127+ rhs : UHeapRef ,
128+ rhsTypes : UTypeStream <Type >,
129+ ): UBoolExpr = with (lhs.uctx) {
130+ val lhsType = lhsTypes.singleOrNull()
131+ val rhsType = rhsTypes.singleOrNull()
132+
133+ if (lhsType != null ) {
134+ return if (lhsType == rhsType) {
135+ trueExpr
136+ } else {
137+ memory.types.evalIsSupertype(rhs, lhsType)
138+ }
139+ }
140+
141+ if (rhsType != null ) {
142+ return memory.types.evalIsSubtype(lhs, rhsType)
143+ }
144+
145+ // TODO: don't mock type equals
146+ makeSymbolicPrimitive(boolSort)
147+ }
148+
81149private inline fun <Type , R : USort > UState <Type , * , * , * , * , * >.mapTypeStream (
82150 ref : UHeapRef ,
83151 onNull : () -> UExpr <R >,
84- operation : (UHeapRef , UTypeStream <Type >) -> UExpr <R >
152+ operation : (UHeapRef , UTypeStream <Type >) -> UExpr <R >,
153+ ignoreNullRefs : Boolean = false,
85154): UExpr <R > = ref.mapWithStaticAsConcrete(
86- ignoreNullRefs = false ,
155+ ignoreNullRefs = ignoreNullRefs ,
87156 concreteMapper = { concreteRef ->
88157 val types = memory.types.getTypeStream(concreteRef)
89158 operation(concreteRef, types)
0 commit comments