Skip to content

Commit ea17215

Browse files
committed
wip3
1 parent ef4255f commit ea17215

File tree

10 files changed

+180
-103
lines changed

10 files changed

+180
-103
lines changed

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

Lines changed: 113 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -825,23 +825,24 @@ private predicate functionInfo(
825825

826826
/**
827827
* Holds if function `f` with the name `name` and the arity `arity` exists in
828-
* [blanket implementation][1] `impl` of `trait`, and the type at position
828+
* blanket implementation `impl` of `trait`, and the type at position
829829
* `pos` is `t`.
830830
*
831831
* `blanketPath` points to the type `blanketTypeParam` inside `t`, which
832832
* is the type parameter used in the blanket implementation.
833-
*
834-
* [1]: https://doc.rust-lang.org/book/ch10-02-traits.html#using-trait-bounds-to-conditionally-implement-methods
835833
*/
836834
pragma[nomagic]
837835
private predicate functionInfoBlanket(
838836
Function f, string name, int arity, ImplItemNode impl, Trait trait, FunctionTypePosition pos,
839837
FunctionType t, TypePath blanketPath, TypeParam blanketTypeParam
840838
) {
841-
functionInfo(f, name, arity, impl, pos, t) and
842-
TTypeParamTypeParameter(blanketTypeParam) = t.getTypeAt(blanketPath) and
843-
MethodResolution::isBlanketLike(impl, blanketTypeParam) and
844-
trait = impl.resolveTraitTy()
839+
exists(TypePath path0 |
840+
functionInfo(f, name, arity, impl, pos, t) and
841+
TTypeParamTypeParameter(blanketTypeParam) = t.getTypeAt(blanketPath) and
842+
blanketPath = any(string s) + path0 and
843+
BlanketImplementation::isBlanket(impl, path0, blanketTypeParam) and
844+
trait = impl.resolveTraitTy()
845+
)
845846
}
846847

847848
/**
@@ -881,6 +882,30 @@ private module ArgIsInstantiationOf<
881882
}
882883
}
883884

885+
/**
886+
* Holds if `root` is a valid complex [`self` root type][1], with type
887+
* parameter `tp`.
888+
*
889+
* [1]: https://doc.rust-lang.org/stable/reference/items/associated-items.html?highlight=self#r-items.associated.fn.method.self-ty
890+
*/
891+
pragma[nomagic]
892+
predicate complexSelfRoot(Type root, TypeParameter tp) {
893+
tp = root.(RefType).getPositionalTypeParameter(_)
894+
or
895+
exists(Struct s |
896+
root = TStruct(s) and
897+
tp = root.getPositionalTypeParameter(0)
898+
|
899+
s instanceof BoxStruct
900+
or
901+
s instanceof RcStruct
902+
or
903+
s instanceof ArcStruct
904+
or
905+
s instanceof PinStruct
906+
)
907+
}
908+
884909
/**
885910
* Provides logic for resolving calls to methods.
886911
*
@@ -916,30 +941,6 @@ private module ArgIsInstantiationOf<
916941
* [1]: https://doc.rust-lang.org/reference/expressions/method-call-expr.html#r-expr.method.candidate-receivers
917942
*/
918943
private module MethodResolution {
919-
/**
920-
* Holds if `root` is a valid complex [`self` root type][1], with type
921-
* parameter `tp`.
922-
*
923-
* [1]: https://doc.rust-lang.org/stable/reference/items/associated-items.html?highlight=self#r-items.associated.fn.method.self-ty
924-
*/
925-
pragma[nomagic]
926-
private predicate complexSelfRoot(Type root, TypeParameter tp) {
927-
tp = root.(RefType).getPositionalTypeParameter(_)
928-
or
929-
exists(Struct s |
930-
root = TStruct(s) and
931-
tp = root.getPositionalTypeParameter(0)
932-
|
933-
s instanceof BoxStruct
934-
or
935-
s instanceof RcStruct
936-
or
937-
s instanceof ArcStruct
938-
or
939-
s instanceof PinStruct
940-
)
941-
}
942-
943944
/**
944945
* Holds if the type path `path` pointing to `type` is stripped of any leading
945946
* complex root type allowed for `self` parameters, such as `&`, `Box`, `Rc`,
@@ -991,17 +992,6 @@ private module MethodResolution {
991992
methodInfo(m, name, arity, i, selfType, strippedTypePath, TTypeParamTypeParameter(tp))
992993
}
993994

994-
predicate isBlanketLike(ImplItemNode i, TypeParam tp) {
995-
tp = i.getBlanketImplementationTypeParam()
996-
// or
997-
// exists(TypeMention tm, Type root, TypeParameter tp0 |
998-
// tm = i.(Impl).getSelfTy() and
999-
// complexSelfRoot(root, tp0) and
1000-
// tm.resolveType() = root and
1001-
// tm.resolveTypeAt(TypePath::singleton(tp0)) = TTypeParamTypeParameter(tp)
1002-
// )
1003-
}
1004-
1005995
/**
1006996
* Same as `methodInfo`, but restricted to non-blanket implementations, and
1007997
* allowing for any `strippedType` when the corresponding type inside `m` is
@@ -1016,18 +1006,16 @@ private module MethodResolution {
10161006
methodInfo(m, name, arity, i, selfType, strippedTypePath, strippedType) or
10171007
methodInfoTypeParam(m, name, arity, i, selfType, strippedTypePath, _)
10181008
) and
1019-
not isBlanketLike(i, _)
1009+
not BlanketImplementation::isBlanket(i, _, _)
10201010
}
10211011

10221012
/**
10231013
* Holds if method `m` with the name `name` and the arity `arity` exists in
1024-
* [blanket implementation][1] `impl` of `trait`, and the type of the `self`
1014+
* blanket implementation `impl` of `trait`, and the type of the `self`
10251015
* parameter is `selfType`.
10261016
*
10271017
* `blanketPath` points to the type `blanketTypeParam` inside `selfType`, which
10281018
* is the type parameter used in the blanket implementation.
1029-
*
1030-
* [1]: https://doc.rust-lang.org/book/ch10-02-traits.html#using-trait-bounds-to-conditionally-implement-methods
10311019
*/
10321020
pragma[nomagic]
10331021
private predicate methodInfoBlanket(
@@ -1179,6 +1167,7 @@ private module MethodResolution {
11791167
result = this.getReceiverTypeAt(path) and
11801168
derefChain = ""
11811169
or
1170+
this.supportsAutoDerefAndBorrow() and
11821171
exists(TypePath path0, Type t0, string derefChain0 |
11831172
this.hasNoCompatibleTarget(derefChain0, _) and
11841173
t0 = this.getACandidateReceiverTypeAtNoBorrow(path0, derefChain0)
@@ -1242,7 +1231,7 @@ private module MethodResolution {
12421231
forall(ImplOrTraitItemNode i |
12431232
methodCallNonBlanketCandidate(this, _, i, _, strippedTypePath, strippedType)
12441233
or
1245-
CallExprImpl::getResolvedFunction(this) = i.(ImplItemNode).getASuccessor(_)
1234+
this.(MethodCallCallExpr).hasTypeQualifiedCandidate(i)
12461235
|
12471236
this.hasIncompatibleTarget(i, derefChainBorrow)
12481237
)
@@ -1265,7 +1254,7 @@ private module MethodResolution {
12651254
forall(ImplOrTraitItemNode i |
12661255
methodCallNonBlanketCandidate(this, _, i, _, strippedTypePath, strippedType)
12671256
or
1268-
CallExprImpl::getResolvedFunction(this) = i.(ImplItemNode).getASuccessor(_)
1257+
this.(MethodCallCallExpr).hasTypeQualifiedCandidate(i)
12691258
|
12701259
this.hasIncompatibleTarget(i, derefChainBorrow)
12711260
)
@@ -1290,6 +1279,7 @@ private module MethodResolution {
12901279
result = this.getACandidateReceiverTypeAtNoBorrow(path, derefChain) and
12911280
derefChainBorrow = derefChain + ";"
12921281
or
1282+
this.supportsAutoDerefAndBorrow() and
12931283
this.hasNoCompatibleTargetNoBorrow(derefChain, _) and
12941284
derefChainBorrow = derefChain + ";borrow" and
12951285
(
@@ -1371,6 +1361,20 @@ private module MethodResolution {
13711361
forall(ItemNode i | i = CallExprImpl::getResolvedFunction(this) | i instanceof Method)
13721362
}
13731363

1364+
/**
1365+
* Holds if this call has a type qualifier, and we are able to resolve,
1366+
* using path resolution, the function to a member of `impl`.
1367+
*
1368+
* When this is the case, we still want to check that the type qualifier
1369+
* is an instance of the type being implemented, which is done in
1370+
* `MethodCallCallExprIsInstantiationOfInput`.
1371+
*/
1372+
pragma[nomagic]
1373+
predicate hasTypeQualifiedCandidate(ImplItemNode impl) {
1374+
exists(getCallExprTypeQualifier(this, _)) and
1375+
CallExprImpl::getResolvedFunction(this) = impl.getASuccessor(_)
1376+
}
1377+
13741378
pragma[nomagic]
13751379
override predicate hasNameAndArity(string name, int arity) {
13761380
name = CallExprImpl::getFunctionPath(this).getText() and
@@ -1492,18 +1496,30 @@ private module MethodResolution {
14921496
)
14931497
}
14941498

1499+
pragma[nomagic]
1500+
private predicate argIsInstanceOf(ImplOrTraitItemNode i) {
1501+
IsInstantiationOf<MethodCallCallExpr, TypeMentionTypeTree, MethodCallCallExprIsInstantiationOfInput>::isInstantiationOf(mc_,
1502+
i, _)
1503+
}
1504+
14951505
pragma[nomagic]
14961506
private predicate argIsInstanceOf(ImplOrTraitItemNode i, string name, int arity) {
14971507
(
14981508
ArgIsInstantiationOf<MethodCallCand, MethodCallReceiverIsInstantiationOfInput>::argIsInstanceOf(this,
14991509
i, _)
15001510
or
1501-
IsInstantiationOf<MethodCallCallExpr, TypeMentionTypeTree, MethodCallCallExprIsInstantiationOfInput>::isInstantiationOf(mc_,
1502-
i, _)
1511+
this.argIsInstanceOf(i)
15031512
) and
15041513
mc_.hasNameAndArity(name, arity)
15051514
}
15061515

1516+
pragma[nomagic]
1517+
private predicate foo(ImplOrTraitItemNode i) {
1518+
ArgIsInstantiationOf<MethodCallCand, MethodCallReceiverIsInstantiationOfInput>::argIsInstanceOf(this,
1519+
i, _) and
1520+
mc_ = Debug::getRelevantLocatable()
1521+
}
1522+
15071523
pragma[nomagic]
15081524
private Method resolveCallTargetCand(ImplOrTraitItemNode i) {
15091525
exists(string name, int arity |
@@ -1553,11 +1569,11 @@ private module MethodResolution {
15531569
{
15541570
pragma[nomagic]
15551571
predicate hasBlanketCandidate(
1556-
MethodCallCand mcc, Function m, TypePath blanketPath, TypeParam blanketTypeParam
1572+
MethodCallCand mcc, ImplItemNode impl, TypePath blanketPath, TypeParam blanketTypeParam
15571573
) {
15581574
exists(MethodCall mc, string name, int arity |
15591575
mcc.hasSignature(mc, _, _, name, arity) and
1560-
methodCallBlanketCandidate(mc, m, _, _, blanketPath, blanketTypeParam) and
1576+
methodCallBlanketCandidate(mc, _, impl, _, blanketPath, blanketTypeParam) and
15611577
// Only apply blanket implementations when no other implementations are possible;
15621578
// this is to account for codebases that use the (unstable) specialization feature
15631579
// (https://rust-lang.github.io/rfcs/1210-impl-specialization.html)
@@ -1587,10 +1603,20 @@ private module MethodResolution {
15871603
or
15881604
methodCallBlanketCandidate(mc, m, i, selfType, _, _) and
15891605
BlanketImplementation::SatisfiesBlanketConstraint<MethodCallCand, SatisfiesBlanketConstraintInput>::satisfiesBlanketConstraint(mcc,
1590-
m)
1606+
i)
15911607
)
15921608
}
15931609

1610+
private predicate potentialInstantiationOf1(
1611+
MethodCallCand mcc, ImplOrTraitItemNode i, FunctionType selfType, TypePath path, Type t,
1612+
TypePath path2, Type t2
1613+
) {
1614+
potentialInstantiationOf0(mcc, i, selfType) and
1615+
mcc.getLocation() = Debug::getRelevantLocatable().getLocation() and
1616+
t = selfType.getTypeAt(path) and
1617+
t2 = mcc.getTypeAt(path2)
1618+
}
1619+
15941620
pragma[nomagic]
15951621
predicate potentialInstantiationOf(
15961622
MethodCallCand mcc, TypeAbstraction abs, FunctionType constraint
@@ -1620,8 +1646,7 @@ private module MethodResolution {
16201646
private predicate potentialInstantiationOf0(
16211647
MethodCallCallExpr ce, ImplItemNode impl, TypeMentionTypeTree constraint
16221648
) {
1623-
exists(getCallExprTypeQualifier(ce, _)) and
1624-
CallExprImpl::getResolvedFunction(ce) = impl.getASuccessor(_) and
1649+
ce.hasTypeQualifiedCandidate(impl) and
16251650
constraint = impl.getSelfPath()
16261651
}
16271652

@@ -1634,7 +1659,7 @@ private module MethodResolution {
16341659
then
16351660
// inherent methods take precedence over trait methods, so only allow
16361661
// trait methods when there are no matching inherent methods
1637-
MkMethodCallCand(ce, "").(MethodCallCand).hasNoInherentTarget()
1662+
MkMethodCallCand(ce, _).(MethodCallCand).hasNoInherentTarget()
16381663
else any()
16391664
}
16401665

@@ -1914,10 +1939,10 @@ private module AssocFunctionResolution {
19141939

19151940
pragma[nomagic]
19161941
private predicate functionCallBlanketCandidate(
1917-
AssocFunctionCall fc, AssocFunction f, FunctionTypePosition pos, TypePath blanketPath,
1918-
TypeParam blanketTypeParam
1942+
AssocFunctionCall fc, AssocFunction f, ImplItemNode impl, FunctionTypePosition pos,
1943+
TypePath blanketPath, TypeParam blanketTypeParam
19191944
) {
1920-
exists(string name, int arity, ImplItemNode impl, Trait trait, FunctionType t |
1945+
exists(string name, int arity, Trait trait, FunctionType t |
19211946
fc.hasNameAndArity(name, arity) and
19221947
exists(getTypeAt(fc, pos, blanketPath)) and
19231948
functionInfoBlanketRelevantPos(f, name, arity, impl, trait, pos, t, blanketPath,
@@ -1928,7 +1953,7 @@ private module AssocFunctionResolution {
19281953

19291954
private newtype TAssocFunctionCallAndPos =
19301955
MkAssocFunctionCallAndPos(AssocFunctionCall fc, FunctionTypePosition pos) {
1931-
functionCallBlanketCandidate(fc, _, pos, _, _)
1956+
functionCallBlanketCandidate(fc, _, _, pos, _, _)
19321957
}
19331958

19341959
class AssocFunctionCallAndPos extends MkAssocFunctionCallAndPos {
@@ -1949,11 +1974,12 @@ private module AssocFunctionResolution {
19491974
{
19501975
pragma[nomagic]
19511976
predicate hasBlanketCandidate(
1952-
AssocFunctionCallAndPos fcp, Function f, TypePath blanketPath, TypeParam blanketTypeParam
1977+
AssocFunctionCallAndPos fcp, ImplItemNode impl, TypePath blanketPath,
1978+
TypeParam blanketTypeParam
19531979
) {
19541980
exists(AssocFunctionCall fc, FunctionTypePosition pos |
19551981
fcp = MkAssocFunctionCallAndPos(fc, pos) and
1956-
functionCallBlanketCandidate(fc, f, pos, blanketPath, blanketTypeParam)
1982+
functionCallBlanketCandidate(fc, _, impl, pos, blanketPath, blanketTypeParam)
19571983
)
19581984
}
19591985
}
@@ -1969,11 +1995,11 @@ private module AssocFunctionResolution {
19691995
predicate potentialInstantiationOf(
19701996
AssocFunctionCallAndPos fcp, TypeAbstraction abs, FunctionType constraint
19711997
) {
1972-
exists(Function f, FunctionTypePosition pos |
1998+
exists(FunctionTypePosition pos |
19731999
BlanketImplementation::SatisfiesBlanketConstraint<AssocFunctionCallAndPos, SatisfiesBlanketConstraintInput>::satisfiesBlanketConstraint(fcp,
1974-
f) and
2000+
abs) and
19752001
fcp = MkAssocFunctionCallAndPos(_, pos) and
1976-
functionInfoBlanketRelevantPos(f, _, _, abs, _, pos, constraint, _, _)
2002+
functionInfoBlanketRelevantPos(_, _, _, abs, _, pos, constraint, _, _)
19772003
)
19782004
}
19792005

@@ -2289,13 +2315,33 @@ private module OperationMatchingInput implements MatchingInputSig {
22892315
Declaration getTarget() {
22902316
result = this.resolveCallTarget(_) // mutual recursion
22912317
}
2318+
2319+
private Declaration getTarget(
2320+
int c, FunctionTypePosition pos, TypePath path, Type type, Type t1, Type t2
2321+
) {
2322+
c = strictcount(this.getTarget()) and
2323+
result = this.getTarget() and
2324+
FunctionOverloading::functionResolutionDependsOnArgument(_, result, pos, path, type) and
2325+
t1 = this.getInferredType(pos, path) and
2326+
t2 = result.getDeclaredType(pos, path) and
2327+
t1 != t2 and
2328+
not this.getInferredType(pos, path) = result.getDeclaredType(pos, path)
2329+
}
2330+
2331+
private Declaration getTarget(int c, FunctionTypePosition pos, TypePath path, Type type) {
2332+
c = strictcount(this.getTarget()) and
2333+
result = this.getTarget() and
2334+
this = Debug::getRelevantLocatable() and
2335+
type = result.getDeclaredType(pos, path)
2336+
}
22922337
}
22932338
}
22942339

22952340
private module OperationMatching = Matching<OperationMatchingInput>;
22962341

22972342
pragma[nomagic]
22982343
private Type inferOperationType(AstNode n, TypePath path) {
2344+
// none() and
22992345
exists(OperationMatchingInput::Access a, OperationMatchingInput::AccessPosition apos |
23002346
n = a.getNodeAt(apos) and
23012347
result = OperationMatching::inferAccessType(a, apos, path)
@@ -3079,8 +3125,8 @@ module Debug {
30793125
Locatable getRelevantLocatable() {
30803126
exists(string filepath, int startline, int startcolumn, int endline, int endcolumn |
30813127
result.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) and
3082-
filepath.matches("%/sqlx.rs") and
3083-
startline = 246
3128+
filepath.matches("%/day23.rs") and
3129+
startline = 161
30843130
)
30853131
}
30863132

0 commit comments

Comments
 (0)