Skip to content

Commit e2eac55

Browse files
committed
wip
1 parent be58e9b commit e2eac55

File tree

1 file changed

+77
-44
lines changed

1 file changed

+77
-44
lines changed

rust/ql/lib/codeql/rust/internal/TypeInference.qll

Lines changed: 77 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -882,7 +882,7 @@ private module ArgIsInstantiationOf<
882882
}
883883

884884
/**
885-
* Provides logic for resolving method calls.
885+
* Provides logic for resolving calls to methods.
886886
*
887887
* When resolving a method call, a list of [candidate receiver types][1] is constructed
888888
*
@@ -915,7 +915,7 @@ private module ArgIsInstantiationOf<
915915
*
916916
* [1]: https://doc.rust-lang.org/reference/expressions/method-call-expr.html#r-expr.method.candidate-receivers
917917
*/
918-
private module MethodCallResolution {
918+
private module MethodResolution {
919919
/**
920920
* Holds if `root` is a valid complex [`self` root type][1], with type
921921
* parameter `tp`.
@@ -1169,7 +1169,7 @@ private module MethodCallResolution {
11691169
derefChain = ""
11701170
or
11711171
exists(TypePath path0, Type t0, string derefChain0 |
1172-
this.hasNoCompatibleTarget(derefChain0) and
1172+
this.hasNoCompatibleTarget(derefChain0, _) and
11731173
t0 = this.getACandidateReceiverTypeAtNoBorrow(path0, derefChain0)
11741174
|
11751175
path0.isCons(TRefTypeParameter(), path) and
@@ -1212,13 +1212,13 @@ private module MethodCallResolution {
12121212
}
12131213

12141214
/**
1215-
* Holds if the candidate receiver type represented by `derefChain` does not
1216-
* have a matching method target.
1215+
* Holds if the candidate receiver type represented by
1216+
* `derefChainBorrow = derefChain;` does not have a matching method target.
12171217
*/
12181218
pragma[nomagic]
1219-
private predicate hasNoCompatibleTargetNoBorrow(string derefChain) {
1220-
this.supportsAutoDerefAndBorrow() and
1221-
exists(TypePath strippedTypePath, Type strippedType, string derefChainBorrow |
1219+
predicate hasNoCompatibleTargetNoBorrow(string derefChain, string derefChainBorrow) {
1220+
(this.supportsAutoDerefAndBorrow() or derefChain = "") and
1221+
exists(TypePath strippedTypePath, Type strippedType |
12221222
derefChainBorrow = derefChain + ";" and
12231223
not derefChain.matches("%.ref") and // no need to try a borrow if the last thing we did was a deref
12241224
strippedType = this.getComplexStrippedType(strippedTypePath, derefChainBorrow)
@@ -1233,14 +1233,15 @@ private module MethodCallResolution {
12331233
}
12341234

12351235
/**
1236-
* Holds if the candidate receiver type represented by `derefChain;borrow` does not
1237-
* have a matching method target.
1236+
* Holds if the candidate receiver type represented by
1237+
* `derefChainBorrow = derefChain;borrow` does not have a matching method
1238+
* target.
12381239
*/
12391240
pragma[nomagic]
1240-
private predicate hasNoCompatibleTarget(string derefChain) {
1241-
exists(TypePath strippedTypePath, Type strippedType, string derefChainBorrow |
1241+
predicate hasNoCompatibleTarget(string derefChain, string derefChainBorrow) {
1242+
exists(TypePath strippedTypePath, Type strippedType |
12421243
derefChainBorrow = derefChain + ";borrow" and
1243-
this.hasNoCompatibleTargetNoBorrow(derefChain) and
1244+
this.hasNoCompatibleTargetNoBorrow(derefChain, _) and
12441245
strippedType = this.getComplexStrippedType(strippedTypePath, derefChainBorrow)
12451246
|
12461247
// todo: also check that all blanket implementation candidates are incompatible
@@ -1270,7 +1271,7 @@ private module MethodCallResolution {
12701271
result = this.getACandidateReceiverTypeAtNoBorrow(path, derefChain) and
12711272
derefChainBorrow = derefChain + ";"
12721273
or
1273-
this.hasNoCompatibleTargetNoBorrow(derefChain) and
1274+
this.hasNoCompatibleTargetNoBorrow(derefChain, _) and
12741275
derefChainBorrow = derefChain + ";borrow" and
12751276
(
12761277
path.isEmpty() and
@@ -1429,6 +1430,13 @@ private module MethodCallResolution {
14291430
result = mc_.getACandidateReceiverTypeAtSubstituteLookupTraits(path, derefChainBorrow)
14301431
}
14311432

1433+
pragma[nomagic]
1434+
predicate hasNoCompatibleTarget() {
1435+
mc_.hasNoCompatibleTarget(_, derefChainBorrow)
1436+
or
1437+
mc_.hasNoCompatibleTargetNoBorrow(_, derefChainBorrow)
1438+
}
1439+
14321440
pragma[nomagic]
14331441
predicate hasSignature(
14341442
MethodCall mc, TypePath strippedTypePath, Type strippedType, string name, int arity
@@ -1476,13 +1484,7 @@ private module MethodCallResolution {
14761484
i, _)
14771485
|
14781486
mc_.hasNameAndArity(name, _) and
1479-
result = getMethodSuccessor(i, name, _) and
1480-
if i.(Impl).hasTrait()
1481-
then
1482-
// inherent methods take precedence over trait methods, so only allow
1483-
// trait methods when there are no matching inherent methods
1484-
this.hasNoInherentTarget()
1485-
else any()
1487+
result = getMethodSuccessor(i, name, _)
14861488
)
14871489
}
14881490

@@ -1531,7 +1533,11 @@ private module MethodCallResolution {
15311533
) {
15321534
exists(MethodCall mc, string name, int arity |
15331535
mcc.hasSignature(mc, _, _, name, arity) and
1534-
methodCallBlanketCandidate(mc, m, _, _, blanketPath, blanketTypeParam)
1536+
methodCallBlanketCandidate(mc, m, _, _, blanketPath, blanketTypeParam) and
1537+
// Only apply blanket implementations when no other implementations are possible;
1538+
// this is to account for codebases that use the (unstable) specialization feature
1539+
// (https://rust-lang.github.io/rfcs/1210-impl-specialization.html)
1540+
mcc.hasNoCompatibleTarget()
15351541
)
15361542
}
15371543
}
@@ -1544,23 +1550,36 @@ private module MethodCallResolution {
15441550
IsInstantiationOfInputSig<MethodCallCand, FunctionType>
15451551
{
15461552
pragma[nomagic]
1547-
predicate potentialInstantiationOf(
1548-
MethodCallCand mcc, TypeAbstraction abs, FunctionType constraint
1553+
additional predicate potentialInstantiationOf0(
1554+
MethodCallCand mcc, ImplOrTraitItemNode i, FunctionType selfType
15491555
) {
15501556
exists(
15511557
MethodCall mc, Method m, string name, int arity, TypePath strippedTypePath,
15521558
Type strippedType
15531559
|
15541560
mcc.hasSignature(mc, strippedTypePath, strippedType, name, arity)
15551561
|
1556-
methodCallNonBlanketCandidate(mc, m, abs, constraint, strippedTypePath, strippedType)
1562+
methodCallNonBlanketCandidate(mc, m, i, selfType, strippedTypePath, strippedType)
15571563
or
1558-
methodCallBlanketCandidate(mc, m, abs, constraint, _, _) and
1564+
methodCallBlanketCandidate(mc, m, i, selfType, _, _) and
15591565
BlanketImplementation::SatisfiesBlanketConstraint<MethodCallCand, SatisfiesBlanketConstraintInput>::satisfiesBlanketConstraint(mcc,
15601566
m)
15611567
)
15621568
}
15631569

1570+
pragma[nomagic]
1571+
predicate potentialInstantiationOf(
1572+
MethodCallCand mcc, TypeAbstraction abs, FunctionType constraint
1573+
) {
1574+
potentialInstantiationOf0(mcc, abs, constraint) and
1575+
if abs.(Impl).hasTrait()
1576+
then
1577+
// inherent methods take precedence over trait methods, so only allow
1578+
// trait methods when there are no matching inherent methods
1579+
mcc.hasNoInherentTarget()
1580+
else any()
1581+
}
1582+
15641583
predicate relevantTypeMention(FunctionType constraint) {
15651584
methodInfo(_, _, _, _, constraint, _, _)
15661585
}
@@ -1573,16 +1592,30 @@ private module MethodCallResolution {
15731592
private module MethodCallCallExprIsInstantiationOfInput implements
15741593
IsInstantiationOfInputSig<MethodCallCallExpr, TypeMentionTypeTree>
15751594
{
1595+
pragma[nomagic]
1596+
private predicate potentialInstantiationOf0(
1597+
MethodCallCallExpr ce, ImplItemNode impl, TypeMentionTypeTree constraint
1598+
) {
1599+
exists(getCallExprTypeQualifier(ce, _)) and
1600+
CallExprImpl::getResolvedFunction(ce) = impl.getASuccessor(_) and
1601+
constraint = impl.getSelfPath()
1602+
}
1603+
15761604
pragma[nomagic]
15771605
predicate potentialInstantiationOf(
15781606
MethodCallCallExpr ce, TypeAbstraction abs, TypeMentionTypeTree constraint
15791607
) {
1580-
exists(getCallExprTypeQualifier(ce, _)) and
1581-
abs =
1582-
any(ImplItemNode impl |
1583-
CallExprImpl::getResolvedFunction(ce) = impl.getASuccessor(_) and
1584-
constraint = impl.getSelfPath()
1585-
)
1608+
potentialInstantiationOf0(ce, abs, constraint) and
1609+
if abs.(Impl).hasTrait()
1610+
then
1611+
// inherent methods take precedence over trait methods, so only allow
1612+
// trait methods when there are no matching inherent methods
1613+
MkMethodCallCand(ce, "").(MethodCallCand).hasNoInherentTarget()
1614+
else any()
1615+
}
1616+
1617+
predicate relevantTypeMention(TypeMentionTypeTree constraint) {
1618+
potentialInstantiationOf0(_, _, constraint)
15861619
}
15871620
}
15881621

@@ -1597,7 +1630,7 @@ private module MethodCallResolution {
15971630
predicate potentialInstantiationOf(
15981631
MethodCallCand mcc, TypeAbstraction abs, FunctionType constraint
15991632
) {
1600-
MethodCallReceiverIsInstantiationOfInput::potentialInstantiationOf(mcc, abs, constraint) and
1633+
MethodCallReceiverIsInstantiationOfInput::potentialInstantiationOf0(mcc, abs, constraint) and
16011634
abs = any(Impl i | not i.hasTrait())
16021635
}
16031636

@@ -1674,7 +1707,7 @@ private module MethodCallMatchingInput implements MatchingWithEnvironmentInputSi
16741707

16751708
class AccessEnvironment = string;
16761709

1677-
final private class MethodCallFinal = MethodCallResolution::MethodCall;
1710+
final private class MethodCallFinal = MethodResolution::MethodCall;
16781711

16791712
class Access extends MethodCallFinal {
16801713
Access() {
@@ -1764,7 +1797,7 @@ private Type inferMethodCallExprType(AstNode n, TypePath path) {
17641797
MethodCallMatchingInput::Access a, MethodCallMatchingInput::AccessPosition apos,
17651798
string derefChainBorrow, TypePath path0
17661799
|
1767-
result = inferMethodCallExprType0(a, apos, n, derefChainBorrow, path0)
1800+
result = inferMethodCallExprType0(a, apos, n, derefChainBorrow, path0) //and
17681801
|
17691802
(
17701803
not apos.asArgumentPosition().isSelf()
@@ -1786,10 +1819,10 @@ private Type inferMethodCallExprType(AstNode n, TypePath path) {
17861819
}
17871820

17881821
/**
1789-
* Provides logic for resolving associated function calls. This includes
1822+
* Provides logic for resolving calls to associated functions. This includes
17901823
* "calls" to tuple variants and tuple structs.
17911824
*/
1792-
private module AssocFunctionCallResolution {
1825+
private module AssocFunctionResolution {
17931826
private import FunctionOverloading
17941827

17951828
/**
@@ -2131,7 +2164,7 @@ private module AssocFunctionCallMatchingInput implements MatchingInputSig {
21312164
}
21322165
}
21332166

2134-
class Access extends AssocFunctionCallResolution::AssocFunctionCall {
2167+
class Access extends AssocFunctionResolution::AssocFunctionCall {
21352168
pragma[nomagic]
21362169
Type getTypeArgument(TypeArgumentPosition apos, TypePath path) {
21372170
result = getCallExprTypeArgument(this, apos).resolveTypeAt(path)
@@ -2218,7 +2251,7 @@ private module OperationMatchingInput implements MatchingInputSig {
22182251
}
22192252
}
22202253

2221-
class Access extends MethodCallResolution::MethodCallOperation {
2254+
class Access extends MethodResolution::MethodCallOperation {
22222255
Type getTypeArgument(TypeArgumentPosition apos, TypePath path) { none() }
22232256

22242257
pragma[nomagic]
@@ -2247,7 +2280,7 @@ private Type getFieldExprLookupType(FieldExpr fe, string name) {
22472280
exists(TypePath path |
22482281
result = inferType(fe.getContainer(), path) and
22492282
name = fe.getIdentifier().getText() and
2250-
MethodCallResolution::isComplexRootStripped(path, result)
2283+
MethodResolution::isComplexRootStripped(path, result)
22512284
)
22522285
}
22532286

@@ -2885,21 +2918,21 @@ private module Cached {
28852918
/** Holds if `receiver` is the receiver of a method call with an implicit dereference. */
28862919
cached
28872920
predicate receiverHasImplicitDeref(AstNode receiver) {
2888-
any(MethodCallResolution::MethodCall mc).receiverHasImplicitDeref(receiver)
2921+
any(MethodResolution::MethodCall mc).receiverHasImplicitDeref(receiver)
28892922
}
28902923

28912924
/** Holds if `receiver` is the receiver of a method call with an implicit borrow. */
28922925
cached
28932926
predicate receiverHasImplicitBorrow(AstNode receiver) {
2894-
any(MethodCallResolution::MethodCall mc).receiverHasImplicitBorrow(receiver)
2927+
any(MethodResolution::MethodCall mc).receiverHasImplicitBorrow(receiver)
28952928
}
28962929

28972930
/** Gets a function that `call` resolves to, if any. */
28982931
cached
28992932
Function resolveCallTarget(Call call) {
2900-
result = call.(MethodCallResolution::MethodCall).resolveCallTarget(_)
2933+
result = call.(MethodResolution::MethodCall).resolveCallTarget(_)
29012934
or
2902-
result = call.(AssocFunctionCallResolution::AssocFunctionCall).resolveCallTarget()
2935+
result = call.(AssocFunctionResolution::AssocFunctionCall).resolveCallTarget()
29032936
}
29042937

29052938
/**

0 commit comments

Comments
 (0)