@@ -70,6 +70,7 @@ overlay[local?]
7070module ;
7171
7272private import codeql.util.Location
73+ private import codeql.util.Strings
7374
7475/** Provides the input to `Make1`. */
7576signature module InputSig1< LocationSig Location> {
@@ -1261,30 +1262,58 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
12611262 module MatchingWithEnvironment< MatchingWithEnvironmentInputSig Input> {
12621263 private import Input
12631264
1265+ private Type getTypeArgumentNonPseudo ( Access a , int pos , TypePath path ) {
1266+ result = a .getTypeArgument ( pos , path ) and
1267+ not result instanceof PseudoType
1268+ }
1269+
12641270 /**
12651271 * Gets the type of the type argument at `path` in `a` that corresponds to
12661272 * the type parameter `tp` in `target`, if any.
12671273 *
12681274 * Note that this predicate crucially does not depend on type inference,
1269- * and hence can appear in negated position, e.g., as in
1270- * `directTypeMatch`.
1275+ * and hence can appear in negated position, e.g., as in `directTypeMatch`.
12711276 */
12721277 bindingset [ a, target]
12731278 pragma [ inline_late]
12741279 Type getTypeArgument ( Access a , Declaration target , TypeParameter tp , TypePath path ) {
12751280 exists ( int pos |
1276- result = a .getTypeArgument ( pos , path ) and
1277- tp = target .getTypeParameter ( pos ) and
1278- not result instanceof PseudoType
1281+ result = getTypeArgumentNonPseudo ( a , pos , path ) and
1282+ tp = target .getTypeParameter ( pos )
1283+ )
1284+ }
1285+
1286+ bindingset [ a, target]
1287+ pragma [ inline_late]
1288+ private predicate hasNotTypeArgument0 ( Access a , Declaration target , TypeParameter tp ) {
1289+ exists ( int pos |
1290+ tp = target .getTypeParameter ( pragma [ only_bind_into ] ( pos ) ) and
1291+ not exists ( getTypeArgumentNonPseudo ( a , pos , _) )
12791292 )
12801293 }
12811294
1295+ bindingset [ target, tp]
1296+ pragma [ inline_late]
1297+ private predicate hasNotTypeArgument1 ( Declaration target , TypeParameter tp ) {
1298+ not tp = target .getTypeParameter ( _)
1299+ }
1300+
1301+ /**
1302+ * A join-order optimized version of `not exists(getTypeArgument(a, target, tp, _)`.
1303+ */
1304+ pragma [ inline]
1305+ private predicate hasNotTypeArgument ( Access a , Declaration target , TypeParameter tp ) {
1306+ hasNotTypeArgument0 ( a , target , tp )
1307+ or
1308+ hasNotTypeArgument1 ( target , tp )
1309+ }
1310+
12821311 pragma [ nomagic]
12831312 private predicate directTypeMatch0 (
12841313 Access a , DeclarationPosition dpos , AccessEnvironment e , Declaration target ,
12851314 TypePath pathToTypeParam , TypeParameter tp
12861315 ) {
1287- not exists ( getTypeArgument ( a , target , tp , _ ) ) and
1316+ hasNotTypeArgument ( a , target , tp ) and
12881317 tp = target .getDeclaredType ( dpos , pathToTypeParam ) and
12891318 target = a .getTarget ( e )
12901319 }
@@ -1359,12 +1388,18 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
13591388 t = a .getInferredType ( e , apos , TypePath:: nil ( ) )
13601389 }
13611390
1391+ private predicate relevantAccessTarget (
1392+ Access a , AccessPosition apos , AccessEnvironment e , Declaration target
1393+ ) {
1394+ exists ( Type t |
1395+ accessTargetsWithArgRootType ( a , e , target , apos , t ) and
1396+ argRootTypeSatisfiesTargetTypeCand ( t , target , apos , _, _)
1397+ )
1398+ }
1399+
13621400 private newtype TRelevantAccess =
13631401 MkRelevantAccess ( Access a , AccessPosition apos , AccessEnvironment e ) {
1364- exists ( Declaration target , Type t |
1365- accessTargetsWithArgRootType ( a , e , target , apos , t ) and
1366- argRootTypeSatisfiesTargetTypeCand ( t , target , apos , _, _)
1367- )
1402+ relevantAccessTarget ( a , apos , e , _)
13681403 }
13691404
13701405 private class RelevantAccess extends MkRelevantAccess {
@@ -1374,7 +1409,12 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
13741409
13751410 RelevantAccess ( ) { this = MkRelevantAccess ( a , apos , e ) }
13761411
1377- RelevantTarget getTarget ( ) { result = MkRelevantTarget ( a .getTarget ( e ) , apos ) }
1412+ RelevantTarget getTarget ( ) {
1413+ exists ( Declaration target |
1414+ relevantAccessTarget ( a , apos , e , target ) and
1415+ result = MkRelevantTarget ( target , apos )
1416+ )
1417+ }
13781418
13791419 pragma [ nomagic]
13801420 Type getTypeAt ( TypePath path ) { result = a .getInferredType ( e , apos , path ) }
@@ -1431,13 +1471,23 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
14311471 predicate baseTypeMatch (
14321472 Access a , AccessEnvironment e , Declaration target , TypePath path , Type t , TypeParameter tp
14331473 ) {
1434- exists ( AccessPosition apos , TypePath pathToTp |
1435- argRootTypeSatisfiesTargetTypeCand ( _, target , pragma [ only_bind_into ] ( apos ) , tp , pathToTp ) and
1474+ exists ( AccessPosition apos , TypePath pathToTp , TypePath pathFull , string regexp |
14361475 SatisfiesParameterConstraint:: satisfiesConstraint ( MkRelevantAccess ( a ,
14371476 pragma [ only_bind_into ] ( apos ) , e ) ,
1438- MkRelevantTarget ( target , pragma [ only_bind_into ] ( apos ) ) , pathToTp .appendInverse ( path ) ,
1439- t ) and
1440- not exists ( getTypeArgument ( a , target , tp , _) )
1477+ MkRelevantTarget ( target , pragma [ only_bind_into ] ( apos ) ) , pathFull , t ) and
1478+ // In order to prevent fan-out in the subsequent inverse append below, first
1479+ // pin down `pathToTp` using a single regex match
1480+ regexp =
1481+ "(" +
1482+ strictconcat ( TypePath pathToTp0 |
1483+ argRootTypeSatisfiesTargetTypeCand ( _, target , apos , _, pathToTp0 )
1484+ |
1485+ regexpEscape ( pathToTp0 ) , "|"
1486+ ) + ").*" and
1487+ pathToTp = pathFull .regexpCapture ( regexp , 1 ) and
1488+ pathFull = pathToTp .appendInverse ( path ) and
1489+ argRootTypeSatisfiesTargetTypeCand ( _, target , pragma [ only_bind_into ] ( apos ) , tp , pathToTp ) and
1490+ hasNotTypeArgument ( a , target , tp )
14411491 )
14421492 }
14431493 }
@@ -1595,11 +1645,25 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
15951645 private predicate typeConstraintBaseTypeMatch (
15961646 Access a , AccessEnvironment e , Declaration target , TypePath path , Type t , TypeParameter tp
15971647 ) {
1598- not exists ( getTypeArgument ( a , target , tp , _) ) and
1599- exists ( TypeMention constraint , TypeParameter constrainedTp , TypePath pathToTp |
1600- typeParameterConstraintHasTypeParameter ( target , constrainedTp , constraint , pathToTp , tp ) and
1601- AccessConstraint:: satisfiesConstraint ( a , e , target , constrainedTp , constraint ,
1602- pathToTp .appendInverse ( path ) , t )
1648+ hasNotTypeArgument ( a , target , tp ) and
1649+ exists (
1650+ TypeParameter constrainedTp , TypeMention constraint , TypePath pathToTp , TypePath pathFull ,
1651+ string regexp
1652+ |
1653+ AccessConstraint:: satisfiesConstraint ( a , e , target , constrainedTp , constraint , pathFull , t ) and
1654+ // In order to prevent fan-out in the subsequent inverse append below, first
1655+ // pin down `pathToTp` using a single regex match
1656+ regexp =
1657+ "(" +
1658+ strictconcat ( TypePath pathToTp0 |
1659+ typeParameterConstraintHasTypeParameter ( target , constrainedTp , constraint ,
1660+ pathToTp0 , _)
1661+ |
1662+ regexpEscape ( pathToTp0 ) , "|"
1663+ ) + ").*" and
1664+ pathToTp = pathFull .regexpCapture ( regexp , 1 ) and
1665+ pathFull = pathToTp .appendInverse ( path ) and
1666+ typeParameterConstraintHasTypeParameter ( target , constrainedTp , constraint , pathToTp , tp )
16031667 )
16041668 }
16051669
0 commit comments