Skip to content

Commit dfb9e08

Browse files
committed
Type inference: Performance tweaks
1 parent bd75795 commit dfb9e08

2 files changed

Lines changed: 93 additions & 21 deletions

File tree

shared/typeinference/codeql/typeinference/internal/TypeInference.qll

Lines changed: 85 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ overlay[local?]
7070
module;
7171

7272
private import codeql.util.Location
73+
private import codeql.util.Strings
7374

7475
/** Provides the input to `Make1`. */
7576
signature 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

shared/util/codeql/util/Strings.qll

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,3 +91,11 @@ int asciiPrintable(string char) {
9191
.charAt(_)
9292
)
9393
}
94+
95+
/**
96+
* Escapes all characters in `s` that have special meaning in regular expressions.
97+
*/
98+
bindingset[s]
99+
string regexpEscape(string s) {
100+
result = s.regexpReplaceAll("([\\\\.*+?\\[^\\]$(){}=!<>|:\\-])", "\\\\$1")
101+
}

0 commit comments

Comments
 (0)