@@ -1261,30 +1261,58 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
12611261 module MatchingWithEnvironment< MatchingWithEnvironmentInputSig Input> {
12621262 private import Input
12631263
1264+ private Type getTypeArgumentNonPseudo ( Access a , int pos , TypePath path ) {
1265+ result = a .getTypeArgument ( pos , path ) and
1266+ not result instanceof PseudoType
1267+ }
1268+
12641269 /**
12651270 * Gets the type of the type argument at `path` in `a` that corresponds to
12661271 * the type parameter `tp` in `target`, if any.
12671272 *
12681273 * 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`.
1274+ * and hence can appear in negated position, e.g., as in `directTypeMatch`.
12711275 */
12721276 bindingset [ a, target]
12731277 pragma [ inline_late]
12741278 Type getTypeArgument ( Access a , Declaration target , TypeParameter tp , TypePath path ) {
12751279 exists ( int pos |
1276- result = a .getTypeArgument ( pos , path ) and
1277- tp = target .getTypeParameter ( pos ) and
1278- not result instanceof PseudoType
1280+ result = getTypeArgumentNonPseudo ( a , pos , path ) and
1281+ tp = target .getTypeParameter ( pos )
1282+ )
1283+ }
1284+
1285+ bindingset [ a, target]
1286+ pragma [ inline_late]
1287+ private predicate hasNotTypeArgument0 ( Access a , Declaration target , TypeParameter tp ) {
1288+ exists ( int pos |
1289+ tp = target .getTypeParameter ( pragma [ only_bind_into ] ( pos ) ) and
1290+ not exists ( getTypeArgumentNonPseudo ( a , pos , _) )
12791291 )
12801292 }
12811293
1294+ bindingset [ target, tp]
1295+ pragma [ inline_late]
1296+ private predicate hasNotTypeArgument1 ( Declaration target , TypeParameter tp ) {
1297+ not tp = target .getTypeParameter ( _)
1298+ }
1299+
1300+ /**
1301+ * A join-order optimized version of `not exists(getTypeArgument(a, target, tp, _)`.
1302+ */
1303+ pragma [ inline]
1304+ private predicate hasNotTypeArgument ( Access a , Declaration target , TypeParameter tp ) {
1305+ hasNotTypeArgument0 ( a , target , tp )
1306+ or
1307+ hasNotTypeArgument1 ( target , tp )
1308+ }
1309+
12821310 pragma [ nomagic]
12831311 private predicate directTypeMatch0 (
12841312 Access a , DeclarationPosition dpos , AccessEnvironment e , Declaration target ,
12851313 TypePath pathToTypeParam , TypeParameter tp
12861314 ) {
1287- not exists ( getTypeArgument ( a , target , tp , _ ) ) and
1315+ hasNotTypeArgument ( a , target , tp ) and
12881316 tp = target .getDeclaredType ( dpos , pathToTypeParam ) and
12891317 target = a .getTarget ( e )
12901318 }
@@ -1359,12 +1387,18 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
13591387 t = a .getInferredType ( e , apos , TypePath:: nil ( ) )
13601388 }
13611389
1390+ private predicate relevantAccessTarget (
1391+ Access a , AccessPosition apos , AccessEnvironment e , Declaration target
1392+ ) {
1393+ exists ( Type t |
1394+ accessTargetsWithArgRootType ( a , e , target , apos , t ) and
1395+ argRootTypeSatisfiesTargetTypeCand ( t , target , apos , _, _)
1396+ )
1397+ }
1398+
13621399 private newtype TRelevantAccess =
13631400 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- )
1401+ relevantAccessTarget ( a , apos , e , _)
13681402 }
13691403
13701404 private class RelevantAccess extends MkRelevantAccess {
@@ -1374,7 +1408,12 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
13741408
13751409 RelevantAccess ( ) { this = MkRelevantAccess ( a , apos , e ) }
13761410
1377- RelevantTarget getTarget ( ) { result = MkRelevantTarget ( a .getTarget ( e ) , apos ) }
1411+ RelevantTarget getTarget ( ) {
1412+ exists ( Declaration target |
1413+ relevantAccessTarget ( a , apos , e , target ) and
1414+ result = MkRelevantTarget ( target , apos )
1415+ )
1416+ }
13781417
13791418 pragma [ nomagic]
13801419 Type getTypeAt ( TypePath path ) { result = a .getInferredType ( e , apos , path ) }
@@ -1431,13 +1470,23 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
14311470 predicate baseTypeMatch (
14321471 Access a , AccessEnvironment e , Declaration target , TypePath path , Type t , TypeParameter tp
14331472 ) {
1434- exists ( AccessPosition apos , TypePath pathToTp |
1435- argRootTypeSatisfiesTargetTypeCand ( _, target , pragma [ only_bind_into ] ( apos ) , tp , pathToTp ) and
1473+ exists ( AccessPosition apos , TypePath pathToTp , TypePath pathFull , string regexp |
14361474 SatisfiesParameterConstraint:: satisfiesConstraint ( MkRelevantAccess ( a ,
14371475 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 , _) )
1476+ MkRelevantTarget ( target , pragma [ only_bind_into ] ( apos ) ) , pathFull , t ) and
1477+ // In order to prevent fan-out in the subsequent inverse append below, first
1478+ // pin down `pathToTp` using a single regex match
1479+ regexp =
1480+ "(" +
1481+ strictconcat ( TypePath pathToTp0 |
1482+ argRootTypeSatisfiesTargetTypeCand ( _, target , apos , _, pathToTp0 )
1483+ |
1484+ pathToTp0 .replaceAll ( "." , "\\." ) , "|"
1485+ ) + ").*" and
1486+ pathToTp = pathFull .regexpCapture ( regexp , 1 ) and
1487+ pathFull = pathToTp .appendInverse ( path ) and
1488+ argRootTypeSatisfiesTargetTypeCand ( _, target , pragma [ only_bind_into ] ( apos ) , tp , pathToTp ) and
1489+ hasNotTypeArgument ( a , target , tp )
14411490 )
14421491 }
14431492 }
@@ -1595,11 +1644,25 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
15951644 private predicate typeConstraintBaseTypeMatch (
15961645 Access a , AccessEnvironment e , Declaration target , TypePath path , Type t , TypeParameter tp
15971646 ) {
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 )
1647+ hasNotTypeArgument ( a , target , tp ) and
1648+ exists (
1649+ TypeParameter constrainedTp , TypeMention constraint , TypePath pathToTp , TypePath pathFull ,
1650+ string regexp
1651+ |
1652+ AccessConstraint:: satisfiesConstraint ( a , e , target , constrainedTp , constraint , pathFull , t ) and
1653+ // In order to prevent fan-out in the subsequent inverse append below, first
1654+ // pin down `pathToTp` using a single regex match
1655+ regexp =
1656+ "(" +
1657+ strictconcat ( TypePath pathToTp0 |
1658+ typeParameterConstraintHasTypeParameter ( target , constrainedTp , constraint ,
1659+ pathToTp0 , _)
1660+ |
1661+ pathToTp0 .replaceAll ( "." , "\\." ) , "|"
1662+ ) + ").*" and
1663+ pathToTp = pathFull .regexpCapture ( regexp , 1 ) and
1664+ pathFull = pathToTp .appendInverse ( path ) and
1665+ typeParameterConstraintHasTypeParameter ( target , constrainedTp , constraint , pathToTp , tp )
16031666 )
16041667 }
16051668
0 commit comments