Skip to content

Commit a36613d

Browse files
committed
wip
1 parent 0ef372f commit a36613d

File tree

6 files changed

+138
-80
lines changed

6 files changed

+138
-80
lines changed

rust/ql/lib/codeql/rust/elements/internal/CallImpl.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ module Impl {
125125
// trait method's default implementation. This is not a dispatch whose
126126
// target is inferred from the type of the receiver, but should always
127127
// resolve to the function in the trait block as path resolution does.
128-
qualifier.toString() != "Self"
128+
not qualifier.(RelevantPath).isUnqualified("Self")
129129
}
130130

131131
override predicate implicitBorrowAt(ArgumentPosition pos, boolean certain) { none() }

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,8 @@ final class TraitTypeAbstraction extends TypeAbstraction, Trait {
425425
result.(TypeParamTypeParameter).getTypeParam() = this.getGenericParamList().getATypeParam()
426426
or
427427
result.(AssociatedTypeTypeParameter).getTrait() = this
428+
or
429+
result.(SelfTypeParameter).getTrait() = this
428430
}
429431
}
430432

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

Lines changed: 131 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1277,10 +1277,6 @@ final class MethodCall extends Call {
12771277
}
12781278
}
12791279

1280-
final private class FunctionCallExpr extends CallExpr {
1281-
FunctionCallExpr() { not this instanceof MethodCall }
1282-
}
1283-
12841280
/**
12851281
* Holds if a method for `type` with the name `name` and the arity `arity`
12861282
* exists in `impl`.
@@ -1406,42 +1402,48 @@ private predicate implSiblings(TraitItemNode trait, Impl impl1, Impl impl2) {
14061402
pragma[nomagic]
14071403
private predicate implHasSibling(Impl impl, Trait trait) { implSiblings(trait, impl, _) }
14081404

1405+
pragma[nomagic]
1406+
private predicate functionTypeAtPath(Function f, int pos, TypePath path, Type type) {
1407+
exists(TypeMention tm | type = tm.resolveTypeAt(path) |
1408+
tm = f.getParam(pos).getTypeRepr()
1409+
or
1410+
pos = -1 and
1411+
tm = f.getRetType().getTypeRepr()
1412+
)
1413+
}
1414+
14091415
/**
1410-
* Holds if a type parameter of `trait` occurs in the method with the name
1411-
* `methodName` at the `pos`th parameter at `path`.
1416+
* Holds if a type parameter of `trait` occurs in the function with the name
1417+
* `functionName` at the `pos`th parameter at `path`.
1418+
*
1419+
* The special position `-1` refers to the return type of the function, which
1420+
* is sometimes needed to disambiguate associated function calls like
1421+
* `Default::default()`.
14121422
*/
14131423
bindingset[trait]
14141424
pragma[inline_late]
14151425
private predicate traitTypeParameterOccurrence(
1416-
TraitItemNode trait, string methodName, int pos, TypePath path
1426+
TraitItemNode trait, Function f, string functionName, int pos, TypePath path
14171427
) {
1418-
exists(Function f | f = trait.getAssocItem(methodName) |
1419-
f.getParam(pos).getTypeRepr().(TypeMention).resolveTypeAt(path) =
1420-
trait.(TraitTypeAbstraction).getATypeParameter()
1421-
)
1422-
}
1423-
1424-
bindingset[f, pos, path]
1425-
pragma[inline_late]
1426-
private predicate methodTypeAtPath(Function f, int pos, TypePath path, Type type) {
1427-
f.getParam(pos).getTypeRepr().(TypeMention).resolveTypeAt(path) = type
1428+
f = trait.getAssocItem(functionName) and
1429+
functionTypeAtPath(f, pos, path, trait.(TraitTypeAbstraction).getATypeParameter())
14281430
}
14291431

14301432
/**
1431-
* Holds if resolving the method `f` in `impl` with the name `methodName`
1433+
* Holds if resolving the function `f` in `impl` with the name `functionName`
14321434
* requires inspecting the types of applied _arguments_ in order to determine
14331435
* whether it is the correct resolution.
14341436
*/
14351437
pragma[nomagic]
1436-
private predicate methodResolutionDependsOnArgument(
1437-
ImplItemNode impl, string methodName, Function f, int pos, TypePath path, Type type
1438+
private predicate functionResolutionDependsOnArgument(
1439+
ImplItemNode impl, string functionName, Function f, int pos, TypePath path, Type type
14381440
) {
14391441
/*
14401442
* As seen in the example below, when an implementation has a sibling for a
1441-
* trait we find occurrences of a type parameter of the trait in a method
1443+
* trait we find occurrences of a type parameter of the trait in a function
14421444
* signature in the trait. We then find the type given in the implementation
14431445
* at the same position, which is a position that might disambiguate the
1444-
* method from its siblings.
1446+
* function from its siblings.
14451447
*
14461448
* ```rust
14471449
* trait MyTrait<T> {
@@ -1463,9 +1465,10 @@ private predicate methodResolutionDependsOnArgument(
14631465

14641466
exists(TraitItemNode trait |
14651467
implHasSibling(impl, trait) and
1466-
traitTypeParameterOccurrence(trait, methodName, pos, path) and
1467-
methodTypeAtPath(f, pos, path, type) and
1468-
f = impl.getAssocItem(methodName)
1468+
traitTypeParameterOccurrence(trait, _, functionName, pos, path) and
1469+
functionTypeAtPath(f, pos, path, type) and
1470+
f = impl.getAssocItem(functionName) and
1471+
pos >= 0
14691472
)
14701473
}
14711474

@@ -1505,11 +1508,12 @@ private Function getMethodFromImpl(MethodCall mc) {
15051508
name = mc.getMethodName() and
15061509
result = getMethodSuccessor(impl, name)
15071510
|
1508-
not methodResolutionDependsOnArgument(impl, _, _, _, _, _)
1511+
not functionResolutionDependsOnArgument(impl, name, _, _, _, _)
15091512
or
15101513
exists(int pos, TypePath path, Type type |
1511-
methodResolutionDependsOnArgument(impl, name, result, pos, path, type) and
1512-
inferType(mc.getPositionalArgument(pos), path) = type
1514+
functionResolutionDependsOnArgument(impl, name, result, pos, pragma[only_bind_into](path),
1515+
type) and
1516+
inferType(mc.getPositionalArgument(pos), pragma[only_bind_into](path)) = type
15131517
)
15141518
)
15151519
}
@@ -1535,37 +1539,96 @@ private Function resolveMethodCallTarget(MethodCall mc) {
15351539

15361540
pragma[nomagic]
15371541
private predicate assocFuncResolutionDependsOnArgument(Function f, Impl impl, int pos) {
1538-
methodResolutionDependsOnArgument(impl, _, f, pos, _, _)
1542+
functionResolutionDependsOnArgument(impl, _, f, pos, _, _) and
1543+
not f.getParamList().hasSelfParam()
15391544
}
15401545

1541-
private class AssocFunctionCallExpr extends FunctionCallExpr {
1542-
private int pos;
1546+
private class FunctionCallExpr extends CallExpr {
1547+
FunctionCallExpr() { not this instanceof MethodCall }
1548+
1549+
ItemNode getResolvedFunction() { result = CallExprImpl::getResolvedFunction(this) }
15431550

1544-
AssocFunctionCallExpr() {
1545-
assocFuncResolutionDependsOnArgument(CallExprImpl::getResolvedFunction(this), _, pos)
1551+
pragma[nomagic]
1552+
Trait getTrait() {
1553+
exists(Path qualifier |
1554+
qualifier = this.getFunction().(PathExpr).getPath().getQualifier() and
1555+
result = resolvePath(qualifier) and
1556+
// When the qualifier is `Self` and resolves to a trait, it's inside a
1557+
// trait method's default implementation. This is not a dispatch whose
1558+
// target is inferred from the type of the receiver, but should always
1559+
// resolve to the function in the trait block as path resolution does.
1560+
not qualifier.(RelevantPath).isUnqualified("Self")
1561+
)
15461562
}
15471563

1548-
Function getACandidate(Impl impl) {
1549-
result = CallExprImpl::getResolvedFunction(this) and
1564+
predicate hasTrait() { exists(this.getTrait()) }
1565+
1566+
predicate isAmbigous() {
1567+
this.hasTrait()
1568+
or
1569+
assocFuncResolutionDependsOnArgument(this.getResolvedFunction(), _, _)
1570+
}
1571+
1572+
pragma[nomagic]
1573+
Function getAnAmbigousCandiate(ImplItemNode impl, int pos) {
1574+
exists(TraitItemNode trait, Function traitFunction |
1575+
trait = this.getTrait() and
1576+
traitFunction = this.getResolvedFunction() and
1577+
result.implements(traitFunction) and
1578+
result = impl.getAnAssocItem()
1579+
|
1580+
assocFuncResolutionDependsOnArgument(result, impl, pos)
1581+
or
1582+
not assocFuncResolutionDependsOnArgument(result, _, _) and
1583+
traitTypeParameterOccurrence(trait, traitFunction, _, pos, _)
1584+
)
1585+
or
1586+
result = this.getResolvedFunction() and
15501587
assocFuncResolutionDependsOnArgument(result, impl, pos)
15511588
}
15521589

1553-
int getPosition() { result = pos }
1590+
Function getAnAmbigousCandiate(ImplItemNode impl, int pos, int rnk) {
1591+
pos = rank[rnk + 1](int pos0 | result = this.getAnAmbigousCandiate(impl, pos0) | pos0)
1592+
}
1593+
}
1594+
1595+
private newtype TAmbigousAssocFunctionCallExpr =
1596+
MkAmbigousAssocFunctionCallExpr(FunctionCallExpr call, Function f, ImplItemNode impl, int pos) {
1597+
f = call.getAnAmbigousCandiate(impl, pos)
1598+
}
1599+
1600+
private class AmbigousAssocFunctionCallExpr extends MkAmbigousAssocFunctionCallExpr {
1601+
FunctionCallExpr call;
1602+
Function f;
1603+
ImplItemNode impl_;
1604+
int pos;
1605+
1606+
AmbigousAssocFunctionCallExpr() { this = MkAmbigousAssocFunctionCallExpr(call, f, impl_, pos) }
1607+
1608+
Type getTypeAt(TypePath path) {
1609+
result = inferType(call.getArg(pos), path)
1610+
or
1611+
pos = -1 and
1612+
result = inferType(call, path)
1613+
}
1614+
1615+
string toString() { result = call.toString() }
15541616

1555-
/** Gets the type of the receiver of the associated function call at `path`. */
1556-
Type getTypeAt(TypePath path) { result = inferType(this.getArg(pos), path) }
1617+
Location getLocation() { result = call.getLocation() }
15571618
}
15581619

1559-
private module AssocFuncIsInstantiationOfInput implements
1560-
IsInstantiationOfInputSig<AssocFunctionCallExpr>
1620+
private module AmbigousAssocFuncIsInstantiationOfInput implements
1621+
IsInstantiationOfInputSig<AmbigousAssocFunctionCallExpr>
15611622
{
15621623
pragma[nomagic]
15631624
predicate potentialInstantiationOf(
1564-
AssocFunctionCallExpr ce, TypeAbstraction impl, TypeMention constraint
1625+
AmbigousAssocFunctionCallExpr ce, TypeAbstraction impl, TypeMention constraint
15651626
) {
1566-
exists(Function cand |
1567-
cand = ce.getACandidate(impl) and
1568-
constraint = cand.getParam(ce.getPosition()).getTypeRepr()
1627+
exists(Function cand, int pos | ce = MkAmbigousAssocFunctionCallExpr(_, cand, impl, pos) |
1628+
constraint = cand.getParam(pos).getTypeRepr()
1629+
or
1630+
pos = -1 and
1631+
constraint = cand.getRetType().getTypeRepr()
15691632
)
15701633
}
15711634
}
@@ -1574,28 +1637,39 @@ private module AssocFuncIsInstantiationOfInput implements
15741637
* Gets the target of `call`, where resolution does not rely on type inference.
15751638
*/
15761639
pragma[nomagic]
1577-
private ItemNode resolveFunctionCallTargetSimple(FunctionCallExpr call) {
1578-
result = CallExprImpl::getResolvedFunction(call) and
1579-
not assocFuncResolutionDependsOnArgument(result, _, _)
1640+
private ItemNode resolveUnambigousFunctionCallTarget(FunctionCallExpr call) {
1641+
result = call.getResolvedFunction() and
1642+
not call.isAmbigous()
1643+
}
1644+
1645+
pragma[nomagic]
1646+
private Function resolveAmbigousFunctionCallTargetFromIndex(FunctionCallExpr call, int index) {
1647+
exists(Impl impl, int pos |
1648+
IsInstantiationOf<AmbigousAssocFunctionCallExpr, AmbigousAssocFuncIsInstantiationOfInput>::isInstantiationOf(MkAmbigousAssocFunctionCallExpr(call,
1649+
result, _, pos), impl, _) and
1650+
result = call.getAnAmbigousCandiate(impl, pos, index)
1651+
|
1652+
index = 0
1653+
or
1654+
result = resolveAmbigousFunctionCallTargetFromIndex(call, index - 1)
1655+
)
15801656
}
15811657

15821658
/**
15831659
* Gets the target of `call`, where resolution relies on type inference.
15841660
*/
15851661
pragma[nomagic]
1586-
private Function resolveFunctionCallTargetComplex(AssocFunctionCallExpr call) {
1587-
exists(Impl impl |
1588-
IsInstantiationOf<AssocFunctionCallExpr, AssocFuncIsInstantiationOfInput>::isInstantiationOf(call,
1589-
impl, _) and
1590-
result = getMethodSuccessor(impl, call.getACandidate(_).getName().getText())
1591-
)
1662+
private Function resolveAmbigousFunctionCallTarget(FunctionCallExpr call) {
1663+
result =
1664+
resolveAmbigousFunctionCallTargetFromIndex(call,
1665+
max(int index | result = call.getAnAmbigousCandiate(_, _, index)))
15921666
}
15931667

15941668
pragma[inline]
15951669
private ItemNode resolveFunctionCallTarget(FunctionCallExpr call) {
1596-
result = resolveFunctionCallTargetSimple(call)
1670+
result = resolveUnambigousFunctionCallTarget(call)
15971671
or
1598-
result = resolveFunctionCallTargetComplex(call)
1672+
result = resolveAmbigousFunctionCallTarget(call)
15991673
}
16001674

16011675
cached
@@ -1770,8 +1844,8 @@ private module Debug {
17701844
private Locatable getRelevantLocatable() {
17711845
exists(string filepath, int startline, int startcolumn, int endline, int endcolumn |
17721846
result.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) and
1773-
filepath.matches("%/sqlx.rs") and
1774-
startline = [56 .. 60]
1847+
filepath.matches("%/test_futures.rs") and
1848+
startline = 45
17751849
)
17761850
}
17771851

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
multipleCallTargets
2+
| main.rs:272:14:272:29 | ...::deref(...) |

rust/ql/test/library-tests/type-inference/main.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2096,10 +2096,10 @@ mod method_determined_by_argument_type {
20962096

20972097
let x = i64::my_from(73i64); // $ method=MyFrom<i64>::my_from
20982098
let y = i64::my_from(true); // $ method=MyFrom<bool>::my_from
2099-
let z: i64 = MyFrom::my_from(73i64); // $ MISSING: method=MyFrom<i64>::my_from $ SPURIOUS: method=MyFrom::my_from
2099+
let z: i64 = MyFrom::my_from(73i64); // $ method=MyFrom<i64>::my_from
21002100
i64::my_from2(73i64, 0i64); // $ method=MyFrom2<i64>::my_from2
21012101
i64::my_from2(true, 0i64); // $ method=MyFrom2<bool>::my_from2
2102-
MyFrom2::my_from2(73i64, 0i64); // $ MISSING: method=MyFrom2<i64>::my_from2 $ SPURIOUS: method=MyFrom2::my_from2
2102+
MyFrom2::my_from2(73i64, 0i64); // $ method=MyFrom2<i64>::my_from2
21032103
}
21042104
}
21052105

0 commit comments

Comments
 (0)