@@ -77,7 +77,6 @@ private Virtualizable getAnImplementedInterfaceMemberForSubType(Virtualizable m,
7777 )
7878}
7979
80- // predicate folding for proper join order
8180pragma [ noinline]
8281private predicate hasMemberCompatibleWithInterfaceMember ( ValueOrRefType t , Virtualizable m ) {
8382 m = getACompatibleInterfaceMember ( t .getAMember ( ) )
@@ -128,7 +127,6 @@ private DeclarationWithAccessors getACompatibleInterfaceAccessorCandidate(Declar
128127 d .isPublic ( )
129128}
130129
131- // predicate folding for proper join-order
132130pragma [ noinline]
133131private predicate getACompatibleInterfaceAccessorAux (
134132 DeclarationWithAccessors d , ValueOrRefType t , string name
@@ -162,47 +160,51 @@ ValueOrRefType getAPossibleImplementor(Interface i) {
162160 not result instanceof Interface
163161}
164162
163+ private Indexer getACompatibleInterfaceIndexer0 ( Indexer i , int j ) {
164+ result = getACompatibleInterfaceIndexerCandidate ( i ) and
165+ convIdentity ( i .getType ( ) , result .getType ( ) ) and
166+ j = - 1
167+ or
168+ result = getACompatibleInterfaceIndexer0 ( i , j - 1 ) and
169+ convIdentity ( i .getParameter ( j ) .getType ( ) , result .getParameter ( j ) .getType ( ) )
170+ }
171+
165172/**
166173 * Gets an interface indexer whose signature matches `i`'s
167174 * signature, and where `i` can potentially be accessed when
168175 * the interface indexer is accessed.
169176 */
170177private Indexer getACompatibleInterfaceIndexer ( Indexer i ) {
171- result = getACompatibleInterfaceIndexerCandidate ( i ) and
172- convIdentity ( i .getType ( ) , result .getType ( ) ) and
173- forex ( int j | j in [ 0 .. i .getNumberOfParameters ( ) - 1 ] |
174- convIdentity ( i .getParameter ( j ) .getType ( ) , result .getParameter ( j ) .getType ( ) )
175- )
178+ result = getACompatibleInterfaceIndexer0 ( i , i .getNumberOfParameters ( ) - 1 )
176179}
177180
178181private Indexer getACompatibleInterfaceIndexerCandidate ( Indexer i ) {
179182 getACompatibleInterfaceIndexerAux ( result , i .getDeclaringType ( ) ) and
180183 i .isPublic ( )
181184}
182185
183- // predicate folding for proper join-order
184186pragma [ noinline]
185187private predicate getACompatibleInterfaceIndexerAux ( Indexer i , ValueOrRefType t ) {
186188 t = getAPossibleImplementor ( i .getDeclaringType ( ) )
187189}
188190
189- private Method getACompatibleInterfaceMethod ( Method m ) {
191+ private Method getACompatibleInterfaceMethod0 ( Method m , int i ) {
190192 result = getAnInterfaceMethodCandidate ( m ) and
191- forex ( int i | i in [ 0 .. m .getNumberOfParameters ( ) ] |
192- exists ( Type t1 , Type t2 |
193- t1 = getArgumentOrReturnType ( m , i ) and
194- t2 = getArgumentOrReturnType ( result , i )
195- |
196- convIdentity ( t1 , t2 )
197- or
198- // In the case where both `m` and `result` are unbound generic methods,
199- // we need to do check for structural equality modulo the method type
200- // parameters
201- structurallyCompatible ( m , result , t1 , t2 )
202- )
193+ i = - 1
194+ or
195+ result = getACompatibleInterfaceMethod0 ( m , i - 1 ) and
196+ exists ( Type t1 , Type t2 |
197+ t1 = getArgumentOrReturnType ( m , i ) and
198+ t2 = getArgumentOrReturnType ( result , i )
199+ |
200+ Gvn:: getGlobalValueNumber ( t1 ) = Gvn:: getGlobalValueNumber ( t2 )
203201 )
204202}
205203
204+ private Method getACompatibleInterfaceMethod ( Method m ) {
205+ result = getACompatibleInterfaceMethod0 ( m , m .getNumberOfParameters ( ) )
206+ }
207+
206208/**
207209 * Gets an interface method that may potentially be implemented by `m`.
208210 *
@@ -215,7 +217,6 @@ private Method getAnInterfaceMethodCandidate(Method m) {
215217 m .isPublic ( )
216218}
217219
218- // predicate folding for proper join-order
219220pragma [ nomagic]
220221private predicate getAPotentialInterfaceMethodAux (
221222 Method m , ValueOrRefType t , string name , int params
@@ -232,90 +233,158 @@ private Type getArgumentOrReturnType(Method m, int i) {
232233}
233234
234235/**
235- * Holds if `m2` is an interface method candidate for `m1`
236- * (`m2 = getAnInterfaceMethodCandidate(m1)`), both `m1` and `m2` are
237- * unbound generic methods, `t1` is a structural sub term of a
238- * parameter type of `m1`, `t2` is a structural sub term of a parameter
239- * (at the same index) type of `m2`, and `t1` and `t2` are compatible.
236+ * INTERNAL: Do not use.
240237 *
241- * Here, compatibility means that the two types are structurally equal
242- * modulo identity conversions and method type parameters.
238+ * Provides an implementation of Global Value Numbering for types
239+ * (see https://en.wikipedia.org/wiki/Global_value_numbering), where
240+ * types are considered equal modulo identity conversions and method
241+ * type parameters (at the same index).
243242 */
244- private predicate structurallyCompatible (
245- UnboundGenericMethod m1 , UnboundGenericMethod m2 , Type t1 , Type t2
246- ) {
247- candidateTypes ( m1 , m2 , t1 , t2 ) and
248- (
249- // Base case: identity convertible
250- convIdentity ( t1 , t2 )
251- or
252- // Base case: method type parameter (at same index)
253- exists ( int i | structurallyCompatibleTypeParameter ( m1 , m2 , i , t1 , m2 .getTypeParameter ( i ) ) )
254- or
255- // Recursive case
256- (
257- t1 instanceof PointerType and t2 instanceof PointerType
243+ module Gvn {
244+ private newtype TCompoundTypeKind =
245+ TPointerTypeKind ( ) or
246+ TNullableTypeKind ( ) or
247+ TArrayTypeKind ( int dim , int rnk ) {
248+ exists ( ArrayType at | dim = at .getDimension ( ) and rnk = at .getRank ( ) )
249+ } or
250+ TConstructedType ( UnboundGenericType ugt )
251+
252+ /** A type kind for a compound type. */
253+ class CompoundTypeKind extends TCompoundTypeKind {
254+ int getNumberOfTypeParameters ( ) {
255+ this = TPointerTypeKind ( ) and result = 1
258256 or
259- t1 instanceof NullableType and t2 instanceof NullableType
257+ this = TNullableTypeKind ( ) and result = 1
260258 or
261- t1 . ( ArrayType ) . hasSameShapeAs ( t2 . ( ArrayType ) )
259+ this = TArrayTypeKind ( _ , _ ) and result = 1
262260 or
263- t1 .( ConstructedType ) .getUnboundGeneric ( ) = t2 .( ConstructedType ) .getUnboundGeneric ( )
264- ) and
265- structurallyCompatibleChildren ( m1 , m2 , t1 , t2 , t1 .getNumberOfChildren ( ) - 1 )
266- )
267- }
261+ exists ( UnboundGenericType ugt | this = TConstructedType ( ugt ) |
262+ result = ugt .getNumberOfTypeParameters ( )
263+ )
264+ }
268265
269- // Predicate folding to force joining on `candidateTypes` first
270- // to prevent `private#structurallyCompatibleTypeParameter#fbbfb`
271- pragma [ nomagic]
272- private predicate structurallyCompatibleTypeParameter (
273- UnboundGenericMethod m1 , UnboundGenericMethod m2 , int i , Type t1 , Type t2
274- ) {
275- candidateTypes ( m1 , m2 , t1 , t2 ) and
276- t1 = m1 .getTypeParameter ( i )
277- }
266+ string toString ( ) {
267+ this = TPointerTypeKind ( ) and result = "*"
268+ or
269+ this = TNullableTypeKind ( ) and result = "?"
270+ or
271+ exists ( int dim , int rnk | this = TArrayTypeKind ( dim , rnk ) |
272+ result = "[" + dim + ", " + rnk + "]"
273+ )
274+ or
275+ exists ( UnboundGenericType ugt | this = TConstructedType ( ugt ) |
276+ result = ugt .getNameWithoutBrackets ( )
277+ )
278+ }
278279
279- /**
280- * Holds if the `i+1` first children of types `x` and `y` are compatible.
281- */
282- private predicate structurallyCompatibleChildren (
283- UnboundGenericMethod m1 , UnboundGenericMethod m2 , Type t1 , Type t2 , int i
284- ) {
285- exists ( Type t3 , Type t4 |
286- i = 0 and
287- candidateChildren ( t1 , t2 , i , t3 , t4 ) and
288- structurallyCompatible ( m1 , m2 , t3 , t4 )
289- )
290- or
291- exists ( Type t3 , Type t4 |
292- structurallyCompatibleChildren ( m1 , m2 , t1 , t2 , i - 1 ) and
293- candidateChildren ( t1 , t2 , i , t3 , t4 ) and
294- structurallyCompatible ( m1 , m2 , t3 , t4 )
295- )
296- }
280+ Location getLocation ( ) { result instanceof EmptyLocation }
281+ }
297282
298- // manual magic predicate used to enumerate types relevant for structural comparison
299- private predicate candidateTypes ( UnboundGenericMethod m1 , UnboundGenericMethod m2 , Type t1 , Type t2 ) {
300- m2 = getAnInterfaceMethodCandidate ( m1 ) and
301- (
302- exists ( int i |
303- t1 = getArgumentOrReturnType ( m1 , i ) and
304- t2 = getArgumentOrReturnType ( m2 , i )
305- )
283+ /** Gets the type kind for type `t`, if any. */
284+ CompoundTypeKind getTypeKind ( Type t ) {
285+ result = TPointerTypeKind ( ) and t instanceof PointerType
286+ or
287+ result = TNullableTypeKind ( ) and t instanceof NullableType
288+ or
289+ t = any ( ArrayType at | result = TArrayTypeKind ( at .getDimension ( ) , at .getRank ( ) ) )
306290 or
307- exists ( Type t3 , Type t4 , int j |
308- candidateTypes ( m1 , m2 , t3 , t4 ) and
309- t1 = t3 .getChild ( j ) and
310- t2 = t4 .getChild ( j )
291+ result = TConstructedType ( t .( ConstructedType ) .getUnboundGeneric ( ) )
292+ }
293+
294+ private class MethodTypeParameter extends TypeParameter {
295+ MethodTypeParameter ( ) { this = any ( UnboundGenericMethod ugm ) .getATypeParameter ( ) }
296+ }
297+
298+ private class LeafType extends Type {
299+ LeafType ( ) {
300+ not exists ( this .getAChild ( ) ) and
301+ not this instanceof MethodTypeParameter
302+ }
303+ }
304+
305+ private predicate id ( LeafType t , int i ) = equivalenceRelation( convIdentity / 2 ) ( t , i )
306+
307+ private newtype TGvnType =
308+ TLeafGvnType ( int i ) { id ( _, i ) } or
309+ TMethodTypeParameterGvnType ( int i ) { i = any ( MethodTypeParameter p ) .getIndex ( ) } or
310+ TConstructedGvnType ( TConstructedGvnType0 t )
311+
312+ private newtype TConstructedGvnType0 =
313+ TConstructedGvnTypeNil ( CompoundTypeKind k ) or
314+ TConstructedGvnTypeCons ( TGvnType head , TConstructedGvnType0 tail ) {
315+ gvnConstructedCons ( _, _, head , tail )
316+ }
317+
318+ private TConstructedGvnType0 gvnConstructed ( Type t , int i ) {
319+ result = TConstructedGvnTypeNil ( getTypeKind ( t ) ) and i = - 1
320+ or
321+ exists ( TGvnType head , TConstructedGvnType0 tail | gvnConstructedCons ( t , i , head , tail ) |
322+ result = TConstructedGvnTypeCons ( head , tail )
311323 )
312- )
313- }
324+ }
314325
315- // predicate folding for proper join-order
316- pragma [ noinline]
317- private predicate candidateChildren ( Type t1 , Type t2 , int i , Type t3 , Type t4 ) {
318- candidateTypes ( _, _, t1 , t2 ) and
319- t3 = t1 .getChild ( i ) and
320- t4 = t2 .getChild ( i )
326+ pragma [ noinline]
327+ private TGvnType gvnTypeChild ( Type t , int i ) { result = getGlobalValueNumber ( t .getChild ( i ) ) }
328+
329+ pragma [ noinline]
330+ private predicate gvnConstructedCons ( Type t , int i , TGvnType head , TConstructedGvnType0 tail ) {
331+ tail = gvnConstructed ( t , i - 1 ) and
332+ head = gvnTypeChild ( t , i )
333+ }
334+
335+ /** Gets the global value number for a given type. */
336+ GvnType getGlobalValueNumber ( Type t ) {
337+ result = TLeafGvnType ( any ( int i | id ( t , i ) ) )
338+ or
339+ result = TMethodTypeParameterGvnType ( t .( MethodTypeParameter ) .getIndex ( ) )
340+ or
341+ result = TConstructedGvnType ( gvnConstructed ( t , getTypeKind ( t ) .getNumberOfTypeParameters ( ) - 1 ) )
342+ }
343+
344+ /** A global value number for a type. */
345+ class GvnType extends TGvnType {
346+ string toString ( ) {
347+ exists ( int i | this = TLeafGvnType ( i ) | result = i .toString ( ) )
348+ or
349+ exists ( int i | this = TMethodTypeParameterGvnType ( i ) | result = "M!" + i )
350+ or
351+ exists ( GvnConstructedType t | this = TConstructedGvnType ( t ) | result = t .toString ( ) )
352+ }
353+
354+ Location getLocation ( ) { result instanceof EmptyLocation }
355+ }
356+
357+ /** A global value number for a constructed type. */
358+ class GvnConstructedType extends TConstructedGvnType0 {
359+ private CompoundTypeKind getKind ( ) {
360+ this = TConstructedGvnTypeNil ( result )
361+ or
362+ exists ( GvnConstructedType tail | this = TConstructedGvnTypeCons ( _, tail ) |
363+ result = tail .getKind ( )
364+ )
365+ }
366+
367+ private GvnType getArg ( int i ) {
368+ this = TConstructedGvnTypeCons ( result , TConstructedGvnTypeNil ( _) ) and
369+ i = 0
370+ or
371+ exists ( GvnConstructedType tail | this = TConstructedGvnTypeCons ( result , tail ) |
372+ exists ( tail .getArg ( i - 1 ) )
373+ )
374+ }
375+
376+ language [ monotonicAggregates]
377+ string toString ( ) {
378+ exists ( CompoundTypeKind k | k = this .getKind ( ) |
379+ result = k + "<" +
380+ concat ( int i |
381+ i in [ 0 .. k .getNumberOfTypeParameters ( ) - 1 ]
382+ |
383+ this .getArg ( i ) .toString ( ) , ", "
384+ ) + ">"
385+ )
386+ }
387+
388+ Location getLocation ( ) { result instanceof EmptyLocation }
389+ }
321390}
0 commit comments