Skip to content

Commit 320ea5b

Browse files
committed
wip
1 parent 4e5a80b commit 320ea5b

File tree

5 files changed

+158
-78
lines changed

5 files changed

+158
-78
lines changed

rust/ql/lib/codeql/rust/internal/typeinference/FunctionType.qll

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,7 @@ module ArgsAreInstantiationsOf<ArgsAreInstantiationsOfInputSig Input> {
355355
string toString() { result = call.toString() + " [arg " + pos + "]" }
356356
}
357357

358-
private module ArgIsInstantiationOfInput implements
358+
private module ArgIsInstantiationOfToIndexInput implements
359359
IsInstantiationOfInputSig<CallAndPos, AssocFunctionType>
360360
{
361361
pragma[nomagic]
@@ -388,7 +388,7 @@ module ArgsAreInstantiationsOf<ArgsAreInstantiationsOfInputSig Input> {
388388
}
389389

390390
private module ArgIsInstantiationOfToIndex =
391-
ArgIsInstantiationOf<CallAndPos, ArgIsInstantiationOfInput>;
391+
ArgIsInstantiationOf<CallAndPos, ArgIsInstantiationOfToIndexInput>;
392392

393393
pragma[nomagic]
394394
private predicate argsAreInstantiationsOfToIndex(
@@ -412,4 +412,24 @@ module ArgsAreInstantiationsOf<ArgsAreInstantiationsOfInputSig Input> {
412412
rnk = max(int r | toCheckRanked(i, f, _, r))
413413
)
414414
}
415+
416+
pragma[nomagic]
417+
private predicate argsAreNotInstantiationsOf0(
418+
Input::Call call, FunctionPosition pos, ImplOrTraitItemNode i
419+
) {
420+
ArgIsInstantiationOfToIndex::argIsNotInstantiationOf(MkCallAndPos(call, pos), i, _, _)
421+
}
422+
423+
/**
424+
* Holds if _some_ argument of `call` has a type that is not an instantiation of the
425+
* type of the corresponding parameter of `f` inside `i`.
426+
*/
427+
pragma[nomagic]
428+
predicate argsAreNotInstantiationsOf(Input::Call call, ImplOrTraitItemNode i, Function f) {
429+
exists(FunctionPosition pos |
430+
argsAreNotInstantiationsOf0(call, pos, i) and
431+
call.hasTargetCand(i, f) and
432+
Input::toCheck(i, f, pos, _)
433+
)
434+
}
415435
}

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

Lines changed: 71 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2741,7 +2741,7 @@ private module NonMethodResolution {
27412741
* Gets the blanket function that this call may resolve to, if any.
27422742
*/
27432743
pragma[nomagic]
2744-
private NonMethodFunction resolveCallTargetBlanketCand(ImplItemNode impl) {
2744+
NonMethodFunction resolveCallTargetBlanketCand(ImplItemNode impl) {
27452745
exists(string name |
27462746
this.hasNameAndArity(pragma[only_bind_into](name), _) and
27472747
ArgIsInstantiationOfBlanketParam::argIsInstantiationOf(MkCallAndBlanketPos(this, _), impl, _) and
@@ -2756,12 +2756,11 @@ private module NonMethodResolution {
27562756
predicate hasTrait() { exists(this.getTrait()) }
27572757

27582758
pragma[nomagic]
2759-
NonMethodFunction resolveAssocCallTargetCand(ImplItemNode i) {
2759+
NonMethodFunction resolveCallTargetNonBlanketCand(ImplItemNode i) {
27602760
not this.hasTrait() and
27612761
result = this.getPathResolutionResolved() and
2762-
result = i.getASuccessor(_)
2763-
or
2764-
result = this.resolveCallTargetBlanketCand(i)
2762+
result = i.getASuccessor(_) and
2763+
FunctionOverloading::functionResolutionDependsOnArgument(_, result, _, _, _)
27652764
}
27662765

27672766
AstNode getNodeAt(FunctionPosition pos) {
@@ -2793,6 +2792,16 @@ private module NonMethodResolution {
27932792
trait = this.getTrait()
27942793
}
27952794

2795+
pragma[nomagic]
2796+
predicate hasNoCompatibleNonBlanketTarget() {
2797+
not exists(this.resolveCallTargetViaPathResolution()) and
2798+
forall(ImplOrTraitItemNode i, Function f |
2799+
this.(NonMethodArgsAreInstantiationsOfNonBlanketInput::Call).hasTargetCand(i, f)
2800+
|
2801+
NonMethodArgsAreInstantiationsOfNonBlanket::argsAreNotInstantiationsOf(this, i, f)
2802+
)
2803+
}
2804+
27962805
/**
27972806
* Gets the target of this call, which can be resolved using only path resolution.
27982807
*/
@@ -2811,7 +2820,9 @@ private module NonMethodResolution {
28112820
result = this.resolveCallTargetBlanketCand(i) and
28122821
not FunctionOverloading::functionResolutionDependsOnArgument(_, result, _, _, _)
28132822
or
2814-
NonMethodArgsAreInstantiationsOf::argsAreInstantiationsOf(this, i, result)
2823+
NonMethodArgsAreInstantiationsOfBlanket::argsAreInstantiationsOf(this, i, result)
2824+
or
2825+
NonMethodArgsAreInstantiationsOfNonBlanket::argsAreInstantiationsOf(this, i, result)
28152826
}
28162827

28172828
pragma[nomagic]
@@ -2850,7 +2861,11 @@ private module NonMethodResolution {
28502861
) {
28512862
exists(NonMethodCall fc, FunctionPosition pos |
28522863
fcp = MkCallAndBlanketPos(fc, pos) and
2853-
fc.resolveCallTargetBlanketLikeCandidate(impl, pos, blanketPath, blanketTypeParam)
2864+
fc.resolveCallTargetBlanketLikeCandidate(impl, pos, blanketPath, blanketTypeParam) and
2865+
// Only apply blanket implementations when no other implementations are possible;
2866+
// this is to account for codebases that use the (unstable) specialization feature
2867+
// (https://rust-lang.github.io/rfcs/1210-impl-specialization.html)
2868+
(fc.hasNoCompatibleNonBlanketTarget() or not impl.isBlanketImplementation())
28542869
)
28552870
}
28562871
}
@@ -2885,37 +2900,29 @@ private module NonMethodResolution {
28852900
private module ArgIsInstantiationOfBlanketParam =
28862901
ArgIsInstantiationOf<CallAndBlanketPos, ArgIsInstantiationOfBlanketParamInput>;
28872902

2888-
private module NonMethodArgsAreInstantiationsOfInput implements ArgsAreInstantiationsOfInputSig {
2903+
private module NonMethodArgsAreInstantiationsOfBlanketInput implements
2904+
ArgsAreInstantiationsOfInputSig
2905+
{
28892906
predicate toCheck(ImplOrTraitItemNode i, Function f, FunctionPosition pos, AssocFunctionType t) {
28902907
t.appliesTo(f, i, pos) and
2891-
(
2892-
exists(Type t0 |
2893-
// for now, we do not handle ambiguous targets when one of the types it iself
2894-
// a type parameter; we should be checking the constraints on that type parameter
2895-
// in this case
2896-
not t0 instanceof TypeParameter
2897-
|
2898-
FunctionOverloading::functionResolutionDependsOnArgument(i, f, pos, _, t0)
2899-
or
2900-
traitFunctionDependsOnPos(_, _, pos, t0, i, f)
2901-
)
2908+
exists(Type t0 |
2909+
// for now, we do not handle ambiguous targets when one of the types it iself
2910+
// a type parameter; we should be checking the constraints on that type parameter
2911+
// in this case
2912+
not t0 instanceof TypeParameter
2913+
|
2914+
FunctionOverloading::functionResolutionDependsOnArgument(i, f, pos, _, t0)
29022915
or
2903-
// match against the trait function itself
2904-
exists(Trait trait |
2905-
FunctionOverloading::traitTypeParameterOccurrence(trait, f, _, pos, _,
2906-
TSelfTypeParameter(trait))
2907-
)
2916+
traitFunctionDependsOnPos(_, _, pos, t0, i, f)
29082917
)
29092918
}
29102919

2911-
class Call extends NonMethodCall {
2920+
final class Call extends NonMethodCall {
29122921
Type getArgType(FunctionPosition pos, TypePath path) {
29132922
result = inferType(this.getNodeAt(pos), path)
29142923
}
29152924

2916-
predicate hasTargetCand(ImplOrTraitItemNode i, Function f) {
2917-
f = this.resolveAssocCallTargetCand(i)
2918-
or
2925+
predicate hasTraitResolvedCand(ImplOrTraitItemNode i, Function f) {
29192926
exists(TraitItemNode trait, NonMethodFunction resolved, ImplItemNode i1, Function f1 |
29202927
this.hasTraitResolved(trait, resolved) and
29212928
traitFunctionDependsOnPos(trait, resolved, _, _, i1, f1)
@@ -2927,11 +2934,45 @@ private module NonMethodResolution {
29272934
i = trait
29282935
)
29292936
}
2937+
2938+
predicate hasTargetCand(ImplOrTraitItemNode i, Function f) {
2939+
f = this.resolveCallTargetBlanketCand(i)
2940+
or
2941+
this.hasTraitResolvedCand(i, f) and
2942+
BlanketImplementation::isBlanketLike(i, _, _)
2943+
}
2944+
}
2945+
}
2946+
2947+
private module NonMethodArgsAreInstantiationsOfBlanket =
2948+
ArgsAreInstantiationsOf<NonMethodArgsAreInstantiationsOfBlanketInput>;
2949+
2950+
private module NonMethodArgsAreInstantiationsOfNonBlanketInput implements
2951+
ArgsAreInstantiationsOfInputSig
2952+
{
2953+
predicate toCheck(ImplOrTraitItemNode i, Function f, FunctionPosition pos, AssocFunctionType t) {
2954+
NonMethodArgsAreInstantiationsOfBlanketInput::toCheck(i, f, pos, t)
2955+
or
2956+
// match against the trait function itself
2957+
t.appliesTo(f, i, pos) and
2958+
exists(Trait trait |
2959+
FunctionOverloading::traitTypeParameterOccurrence(trait, f, _, pos, _,
2960+
TSelfTypeParameter(trait))
2961+
)
2962+
}
2963+
2964+
class Call extends NonMethodArgsAreInstantiationsOfBlanketInput::Call {
2965+
predicate hasTargetCand(ImplOrTraitItemNode i, Function f) {
2966+
f = this.resolveCallTargetNonBlanketCand(i)
2967+
or
2968+
this.hasTraitResolvedCand(i, f) and
2969+
not BlanketImplementation::isBlanketLike(i, _, _)
2970+
}
29302971
}
29312972
}
29322973

2933-
private module NonMethodArgsAreInstantiationsOf =
2934-
ArgsAreInstantiationsOf<NonMethodArgsAreInstantiationsOfInput>;
2974+
private module NonMethodArgsAreInstantiationsOfNonBlanket =
2975+
ArgsAreInstantiationsOf<NonMethodArgsAreInstantiationsOfNonBlanketInput>;
29352976
}
29362977

29372978
abstract private class TupleLikeConstructor extends Addressable {

0 commit comments

Comments
 (0)