@@ -1262,30 +1262,58 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
12621262 module MatchingWithEnvironment< MatchingWithEnvironmentInputSig Input> {
12631263 private import Input
12641264
1265+ private Type getTypeArgumentNonPseudo ( Access a , int pos , TypePath path ) {
1266+ result = a .getTypeArgument ( pos , path ) and
1267+ not result instanceof PseudoType
1268+ }
1269+
12651270 /**
12661271 * Gets the type of the type argument at `path` in `a` that corresponds to
12671272 * the type parameter `tp` in `target`, if any.
12681273 *
12691274 * Note that this predicate crucially does not depend on type inference,
1270- * and hence can appear in negated position, e.g., as in
1271- * `directTypeMatch`.
1275+ * and hence can appear in negated position, e.g., as in `directTypeMatch`.
12721276 */
12731277 bindingset [ a, target]
12741278 pragma [ inline_late]
12751279 Type getTypeArgument ( Access a , Declaration target , TypeParameter tp , TypePath path ) {
12761280 exists ( int pos |
1277- result = a .getTypeArgument ( pos , path ) and
1278- tp = target .getTypeParameter ( pos ) and
1279- 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 , _) )
12801292 )
12811293 }
12821294
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+
12831311 pragma [ nomagic]
12841312 private predicate directTypeMatch0 (
12851313 Access a , DeclarationPosition dpos , AccessEnvironment e , Declaration target ,
12861314 TypePath pathToTypeParam , TypeParameter tp
12871315 ) {
1288- not exists ( getTypeArgument ( a , target , tp , _ ) ) and
1316+ hasNotTypeArgument ( a , target , tp ) and
12891317 tp = target .getDeclaredType ( dpos , pathToTypeParam ) and
12901318 target = a .getTarget ( e )
12911319 }
@@ -1360,12 +1388,18 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
13601388 t = a .getInferredType ( e , apos , TypePath:: nil ( ) )
13611389 }
13621390
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+
13631400 private newtype TRelevantAccess =
13641401 MkRelevantAccess ( Access a , AccessPosition apos , AccessEnvironment e ) {
1365- exists ( Declaration target , Type t |
1366- accessTargetsWithArgRootType ( a , e , target , apos , t ) and
1367- argRootTypeSatisfiesTargetTypeCand ( t , target , apos , _, _)
1368- )
1402+ relevantAccessTarget ( a , apos , e , _)
13691403 }
13701404
13711405 private class RelevantAccess extends MkRelevantAccess {
@@ -1375,7 +1409,12 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
13751409
13761410 RelevantAccess ( ) { this = MkRelevantAccess ( a , apos , e ) }
13771411
1378- 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+ }
13791418
13801419 pragma [ nomagic]
13811420 Type getTypeAt ( TypePath path ) { result = a .getInferredType ( e , apos , path ) }
@@ -1432,13 +1471,23 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
14321471 predicate baseTypeMatch (
14331472 Access a , AccessEnvironment e , Declaration target , TypePath path , Type t , TypeParameter tp
14341473 ) {
1435- exists ( AccessPosition apos , TypePath pathToTp |
1436- argRootTypeSatisfiesTargetTypeCand ( _, target , pragma [ only_bind_into ] ( apos ) , tp , pathToTp ) and
1474+ exists ( AccessPosition apos , TypePath pathToTp , TypePath pathFull , string regexp |
14371475 SatisfiesParameterConstraint:: satisfiesConstraint ( MkRelevantAccess ( a ,
14381476 pragma [ only_bind_into ] ( apos ) , e ) ,
1439- MkRelevantTarget ( target , pragma [ only_bind_into ] ( apos ) ) , pathToTp .appendInverse ( path ) ,
1440- t ) and
1441- 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+ pathToTp0 .replaceAll ( "." , "\\." ) , "|"
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 )
14421491 )
14431492 }
14441493 }
@@ -1596,11 +1645,25 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
15961645 private predicate typeConstraintBaseTypeMatch (
15971646 Access a , AccessEnvironment e , Declaration target , TypePath path , Type t , TypeParameter tp
15981647 ) {
1599- not exists ( getTypeArgument ( a , target , tp , _) ) and
1600- exists ( TypeMention constraint , TypeParameter constrainedTp , TypePath pathToTp |
1601- typeParameterConstraintHasTypeParameter ( target , constrainedTp , constraint , pathToTp , tp ) and
1602- AccessConstraint:: satisfiesConstraint ( a , e , target , constrainedTp , constraint ,
1603- 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+ pathToTp0 .replaceAll ( "." , "\\." ) , "|"
1663+ ) + ").*" and
1664+ pathToTp = pathFull .regexpCapture ( regexp , 1 ) and
1665+ pathFull = pathToTp .appendInverse ( path ) and
1666+ typeParameterConstraintHasTypeParameter ( target , constrainedTp , constraint , pathToTp , tp )
16041667 )
16051668 }
16061669
0 commit comments