Skip to content

Commit b1917d3

Browse files
committed
wip
1 parent 66b0939 commit b1917d3

File tree

6 files changed

+97
-62
lines changed

6 files changed

+97
-62
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ predicate traitTypeParameterOccurrence(
8686
TypeParameter traitTp
8787
) {
8888
f = trait.getAssocItem(functionName) and
89-
traitTp = getAssocFunctionTypeAt(f, trait, pos, path) and
89+
traitTp = getAssocFunctionTypeAtInclNonMethodSelf(f, trait, pos, path) and
9090
traitTp = trait.(TraitTypeAbstraction).getATypeParameter()
9191
}
9292

@@ -141,7 +141,7 @@ pragma[nomagic]
141141
private Type getAssocFunctionNonTypeParameterTypeAt(
142142
ImplItemNode impl, Function f, FunctionPosition pos, TypePath path
143143
) {
144-
result = getAssocFunctionTypeAt(f, impl, pos, path) and
144+
result = getAssocFunctionTypeAtInclNonMethodSelf(f, impl, pos, path) and
145145
not result instanceof TypeParameter
146146
}
147147

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

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,9 @@ private newtype TAssocFunctionType =
8282
// through `i`. This ensures that `parent` is either a supertrait of `i` or
8383
// `i` in an `impl` block implementing `parent`.
8484
(parent = i or BaseTypes::rootTypesSatisfaction(_, TTrait(parent), i, _, _)) and
85-
exists(pos.getTypeMention(f))
85+
// We always include the `self` position, even for non-methods, where it is used
86+
// to match type qualifiers against the `impl` or trait type, such as in `Vec::new`.
87+
(exists(pos.getTypeMention(f)) or pos.isSelf())
8688
}
8789

8890
bindingset[abs, constraint, tp]
@@ -116,6 +118,23 @@ Type getAssocFunctionTypeAt(Function f, ImplOrTraitItemNode i, FunctionPosition
116118
)
117119
}
118120

121+
/**
122+
* Same as `getAssocFunctionTypeAt`, but also includes types at the `self` position
123+
* for non-methods.
124+
*/
125+
pragma[nomagic]
126+
Type getAssocFunctionTypeAtInclNonMethodSelf(
127+
Function f, ImplOrTraitItemNode i, FunctionPosition pos, TypePath path
128+
) {
129+
result = getAssocFunctionTypeAt(f, i, pos, path)
130+
or
131+
exists(ImplOrTraitItemNode parent | exists(MkAssocFunctionType(parent, f, i, pos)) |
132+
not f.hasSelfParam() and
133+
pos.isSelf() and
134+
result = resolveImplOrTraitType(i, path)
135+
)
136+
}
137+
119138
/**
120139
* The type of an associated function at a given position, when its implicit
121140
* `Self` type parameter is specialized to a given trait or `impl` block.
@@ -174,7 +193,7 @@ class AssocFunctionType extends MkAssocFunctionType {
174193
Type getTypeAt(TypePath path) {
175194
exists(Function f, FunctionPosition pos, ImplOrTraitItemNode i, Type t |
176195
this.appliesTo(f, i, pos) and
177-
t = getAssocFunctionTypeAt(f, i, pos, path)
196+
t = getAssocFunctionTypeAtInclNonMethodSelf(f, i, pos, path)
178197
|
179198
not t instanceof SelfTypeParameter and
180199
result = t
@@ -184,9 +203,12 @@ class AssocFunctionType extends MkAssocFunctionType {
184203
}
185204

186205
private TypeMention getTypeMention() {
187-
exists(Function f, FunctionPosition pos |
188-
this.appliesTo(f, _, pos) and
206+
exists(Function f, ImplOrTraitItemNode i, FunctionPosition pos | this.appliesTo(f, i, pos) |
189207
result = pos.getTypeMention(f)
208+
or
209+
pos.isSelf() and
210+
not f.hasSelfParam() and
211+
result = [i.(Impl).getSelfTy().(TypeMention), i.(TypeMention)]
190212
)
191213
}
192214

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

Lines changed: 43 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1059,13 +1059,24 @@ private Path getCallExprPathQualifier(CallExpr ce) {
10591059
*
10601060
* For example, the type qualifier of `Foo::<i32>::default()` is `Foo::<i32>`,
10611061
* but only when `Foo` is not a trait.
1062+
*
1063+
* `isDefaultTypeArg` indicates whether the returned type is a default type
1064+
* argument, for example in `Vec::new()` the default type for the type parameter
1065+
* `A` of `Vec` is `Global`.
10621066
*/
10631067
pragma[nomagic]
1064-
private Type getCallExprTypeQualifier(CallExpr ce, TypePath path) {
1065-
exists(TypeMention tm |
1066-
tm = getCallExprPathQualifier(ce) and
1068+
private Type getCallExprTypeQualifier(CallExpr ce, TypePath path, boolean isDefaultTypeArg) {
1069+
exists(TypeMention tm | tm = getCallExprPathQualifier(ce) |
10671070
result = tm.getTypeAt(path) and
1068-
not resolvePath(tm) instanceof Trait
1071+
not resolvePath(tm) instanceof Trait and
1072+
isDefaultTypeArg = false
1073+
or
1074+
exists(TypeParameter tp, TypePath suffix |
1075+
result =
1076+
tm.(NonAliasPathTypeMention).getDefaultTypeForTypeParameterInNonAnnotationAt(tp, suffix) and
1077+
path = TypePath::cons(tp, suffix) and
1078+
isDefaultTypeArg = true
1079+
)
10691080
)
10701081
}
10711082

@@ -1148,7 +1159,7 @@ private module ContextTyping {
11481159
) and
11491160
not (
11501161
tp instanceof TSelfTypeParameter and
1151-
exists(getCallExprTypeQualifier(this, _))
1162+
exists(getCallExprTypeQualifier(this, _, _))
11521163
)
11531164
)
11541165
}
@@ -1947,7 +1958,7 @@ private module MethodResolution {
19471958
*/
19481959
pragma[nomagic]
19491960
predicate hasTypeQualifiedCandidate(ImplItemNode impl) {
1950-
exists(getCallExprTypeQualifier(this, _)) and
1961+
exists(getCallExprTypeQualifier(this, _, _)) and
19511962
CallExprImpl::getResolvedFunction(this) = impl.getADescendant()
19521963
}
19531964

@@ -1966,7 +1977,7 @@ private module MethodResolution {
19661977

19671978
// needed for `TypeQualifierIsInstantiationOfImplSelfInput`
19681979
Type getTypeAt(TypePath path) {
1969-
result = substituteLookupTraits(getCallExprTypeQualifier(this, path))
1980+
result = substituteLookupTraits(getCallExprTypeQualifier(this, path, _))
19701981
}
19711982

19721983
override predicate supportsAutoDerefAndBorrow() { none() }
@@ -2743,7 +2754,7 @@ private module NonMethodResolution {
27432754
result = this.getPathResolutionResolved() and
27442755
result = i.getASuccessor(_) and
27452756
not exists(this.resolveCallTargetViaPathResolution()) and
2746-
FunctionOverloading::functionResolutionDependsOnArgument(i, result, _, _)
2757+
implTraitTypeParameterOccurrence(_, _, _, i, result, _, _)
27472758
}
27482759

27492760
pragma[nomagic]
@@ -2778,14 +2789,9 @@ private module NonMethodResolution {
27782789
this.resolveCallTargetBlanketLikeCand(_, _, _, _) and
27792790
not exists(this.resolveCallTargetViaPathResolution()) and
27802791
forall(ImplOrTraitItemNode i, Function f |
2781-
this.(NonMethodNonTraitArgsAreInstantiationsOfNonBlanketInput::Call).hasTargetCand(i, f)
2792+
this.(NonMethodArgsAreInstantiationsOfNonBlanketInput::Call).hasTargetCand(i, f)
27822793
|
2783-
NonMethodNonTraitArgsAreInstantiationsOfNonBlanket::argsAreNotInstantiationsOf(this, i, f)
2784-
) and
2785-
forall(ImplOrTraitItemNode i, Function f |
2786-
this.(NonMethodTraitArgsAreInstantiationsOfNonBlanketInput::Call).hasTargetCand(i, f)
2787-
|
2788-
NonMethodTraitArgsAreInstantiationsOfNonBlanket::argsAreNotInstantiationsOf(this, i, f)
2794+
NonMethodArgsAreInstantiationsOfNonBlanket::argsAreNotInstantiationsOf(this, i, f)
27892795
)
27902796
}
27912797

@@ -2796,7 +2802,7 @@ private module NonMethodResolution {
27962802
ItemNode resolveCallTargetViaPathResolution() {
27972803
not this.hasTrait() and
27982804
result = this.getPathResolutionResolved() and
2799-
not FunctionOverloading::functionResolutionDependsOnArgument(_, result, _, _)
2805+
not implTraitTypeParameterOccurrence(_, _, _, _, result, _, _)
28002806
}
28012807

28022808
/**
@@ -2809,9 +2815,7 @@ private module NonMethodResolution {
28092815
or
28102816
NonMethodArgsAreInstantiationsOfBlanket::argsAreInstantiationsOf(this, i, result)
28112817
or
2812-
NonMethodNonTraitArgsAreInstantiationsOfNonBlanket::argsAreInstantiationsOf(this, i, result)
2813-
or
2814-
NonMethodTraitArgsAreInstantiationsOfNonBlanket::argsAreInstantiationsOf(this, i, result)
2818+
NonMethodArgsAreInstantiationsOfNonBlanket::argsAreInstantiationsOf(this, i, result)
28152819
}
28162820

28172821
pragma[nomagic]
@@ -2890,21 +2894,27 @@ private module NonMethodResolution {
28902894
private module ArgIsInstantiationOfBlanketParam =
28912895
ArgIsInstantiationOf<CallAndBlanketPos, ArgIsInstantiationOfBlanketParamInput>;
28922896

2893-
private Type getArgType(NonMethodCall call, FunctionPosition pos, TypePath path) {
2894-
result = inferType(call.getNodeAt(pos), path)
2897+
private Type getArgType(
2898+
NonMethodCall call, FunctionPosition pos, TypePath path, boolean isDefaultTypeArg
2899+
) {
2900+
result = inferType(call.getNodeAt(pos), path) and
2901+
isDefaultTypeArg = false
2902+
or
2903+
result = getCallExprTypeQualifier(call, path, isDefaultTypeArg) and
2904+
pos.isSelf()
28952905
}
28962906

28972907
private module NonMethodArgsAreInstantiationsOfBlanketInput implements
28982908
ArgsAreInstantiationsOfInputSig
28992909
{
29002910
predicate toCheck(ImplOrTraitItemNode i, Function f, TypeParameter traitTp, FunctionPosition pos) {
2901-
// For calls to blanket functions, we check all the positions in which a
2902-
// type parameter occurs.
29032911
implTraitTypeParameterOccurrence(_, _, pos, i, f, _, traitTp)
29042912
}
29052913

29062914
final class Call extends NonMethodCall {
2907-
Type getArgType(FunctionPosition pos, TypePath path) { result = getArgType(this, pos, path) }
2915+
Type getArgType(FunctionPosition pos, TypePath path) {
2916+
result = getArgType(this, pos, path, false)
2917+
}
29082918

29092919
predicate hasTargetCand(ImplOrTraitItemNode i, Function f) {
29102920
f = this.resolveCallTargetBlanketCand(i)
@@ -2915,31 +2925,10 @@ private module NonMethodResolution {
29152925
private module NonMethodArgsAreInstantiationsOfBlanket =
29162926
ArgsAreInstantiationsOf<NonMethodArgsAreInstantiationsOfBlanketInput>;
29172927

2918-
private module NonMethodNonTraitArgsAreInstantiationsOfNonBlanketInput implements
2919-
ArgsAreInstantiationsOfInputSig
2920-
{
2921-
predicate toCheck(ImplOrTraitItemNode i, Function f, TypeParameter traitTp, FunctionPosition pos) {
2922-
// For calls to non-blanket functions, where no trait qualifier is supplied, e.g.
2923-
// `Vec::from(...)` we only check the positions needed for disambiguating sibling
2924-
// implementations.
2925-
FunctionOverloading::functionResolutionDependsOnArgument(i, f, traitTp, pos)
2926-
}
2927-
2928-
class Call extends NonMethodCall {
2929-
Type getArgType(FunctionPosition pos, TypePath path) { result = getArgType(this, pos, path) }
2930-
2931-
predicate hasTargetCand(ImplOrTraitItemNode i, Function f) {
2932-
f = this.resolveCallTargetNonBlanketCand(i)
2933-
}
2934-
}
2935-
}
2936-
2937-
private module NonMethodTraitArgsAreInstantiationsOfNonBlanketInput implements
2928+
private module NonMethodArgsAreInstantiationsOfNonBlanketInput implements
29382929
ArgsAreInstantiationsOfInputSig
29392930
{
29402931
predicate toCheck(ImplOrTraitItemNode i, Function f, TypeParameter traitTp, FunctionPosition pos) {
2941-
// For calls to non-blanket functions, where a trait qualifier is supplied, e.g.
2942-
// `From::from(...)`, we check all the positions in which a type parameter occurs.
29432932
implTraitTypeParameterOccurrence(_, _, pos, i, f, _, traitTp)
29442933
or
29452934
// Also match against the trait function itself
@@ -2948,9 +2937,13 @@ private module NonMethodResolution {
29482937
}
29492938

29502939
class Call extends NonMethodCall {
2951-
Type getArgType(FunctionPosition pos, TypePath path) { result = getArgType(this, pos, path) }
2940+
Type getArgType(FunctionPosition pos, TypePath path) {
2941+
result = getArgType(this, pos, path, _)
2942+
}
29522943

29532944
predicate hasTargetCand(ImplOrTraitItemNode i, Function f) {
2945+
f = this.resolveCallTargetNonBlanketCand(i)
2946+
or
29542947
exists(TraitItemNode trait, NonMethodFunction resolved, ImplItemNode i1, Function f1 |
29552948
this.hasTraitResolved(trait, resolved) and
29562949
implTraitTypeParameterOccurrence(trait, resolved, _, i1, f1, _, _) and
@@ -2975,11 +2968,8 @@ private module NonMethodResolution {
29752968
}
29762969
}
29772970

2978-
private module NonMethodNonTraitArgsAreInstantiationsOfNonBlanket =
2979-
ArgsAreInstantiationsOf<NonMethodNonTraitArgsAreInstantiationsOfNonBlanketInput>;
2980-
2981-
private module NonMethodTraitArgsAreInstantiationsOfNonBlanket =
2982-
ArgsAreInstantiationsOf<NonMethodTraitArgsAreInstantiationsOfNonBlanketInput>;
2971+
private module NonMethodArgsAreInstantiationsOfNonBlanket =
2972+
ArgsAreInstantiationsOf<NonMethodArgsAreInstantiationsOfNonBlanketInput>;
29832973
}
29842974

29852975
abstract private class TupleLikeConstructor extends Addressable {
@@ -3143,7 +3133,7 @@ private module NonMethodCallMatchingInput implements MatchingInputSig {
31433133
pragma[nomagic]
31443134
Type getInferredType(AccessPosition apos, TypePath path) {
31453135
apos.isSelf() and
3146-
result = getCallExprTypeQualifier(this, path)
3136+
result = getCallExprTypeQualifier(this, path, false)
31473137
or
31483138
result = inferType(this.getNodeAt(apos), path)
31493139
}

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

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -210,8 +210,6 @@ private module MkTypeMention<getAdditionalPathTypeAtSig/2 getAdditionalPathTypeA
210210
// If a type argument is not given in the path, then we use the default for
211211
// the type parameter if one exists for the type.
212212
not exists(getPathTypeArgument(this, i)) and
213-
// Defaults only apply to type mentions in type annotations
214-
this = any(PathTypeRepr ptp).getPath().getQualifier*() and
215213
exists(Type ty, TypePath prefix |
216214
ty = this.resolveRootType().getTypeParameterDefault(i).(TypeMention).getTypeAt(prefix) and
217215
if not ty = TSelfTypeParameter(resolved)
@@ -226,9 +224,32 @@ private module MkTypeMention<getAdditionalPathTypeAtSig/2 getAdditionalPathTypeA
226224
)
227225
}
228226

227+
private predicate isInTypeAnnotation() {
228+
this = any(PathTypeRepr ptp).getPath().getQualifier*()
229+
}
230+
231+
/**
232+
* Gets the default type for the type parameter `tp` at `path`, if any.
233+
*
234+
* This predicate is restricted to mentions that are _not_ part of a type
235+
* annotation, such as a qualifier in a call, `Vec::new()`. In these cases,
236+
* whether or not the default type applies may depend on the types of
237+
* arguments.
238+
*/
239+
pragma[nomagic]
240+
Type getDefaultTypeForTypeParameterInNonAnnotationAt(TypeParameter tp, TypePath path) {
241+
not this.isInTypeAnnotation() and
242+
exists(int i |
243+
result = this.getDefaultPositionalTypeArgument(pragma[only_bind_into](i), path) and
244+
tp = this.resolveRootType().getPositionalTypeParameter(pragma[only_bind_into](i))
245+
)
246+
}
247+
229248
private Type getPositionalTypeArgument(int i, TypePath path) {
230249
result = getPathTypeArgument(this, i).getTypeAt(path)
231250
or
251+
// Defaults only apply to type mentions in type annotations
252+
this.isInTypeAnnotation() and
232253
result = this.getDefaultPositionalTypeArgument(i, path)
233254
}
234255

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ mod default_type_args {
227227
type AssocType = S;
228228

229229
fn g(self) -> S {
230-
let x = S::f(S(Default::default())); // $ type=x:i64 $ MISSING: target=f target=default
230+
let x = S::f(S(Default::default())); // $ target=f target=default type=x:i64
231231
let x = Self::AssocType::f(S(Default::default())); // $ target=f target=default type=x:i64
232232
let x = S::<bool>::g(S(Default::default())); // $ target=g target=default type=x:bool
233233
let x = S::<i64>::g(S(Default::default())); // $ target=g target=default type=x:i64

rust/ql/test/library-tests/type-inference/type-inference.expected

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12256,6 +12256,8 @@ inferType
1225612256
| overloading.rs:230:17:230:17 | x | | {EXTERNAL LOCATION} | i64 |
1225712257
| overloading.rs:230:21:230:47 | ...::f(...) | | {EXTERNAL LOCATION} | i64 |
1225812258
| overloading.rs:230:26:230:46 | S(...) | | overloading.rs:202:5:202:25 | S |
12259+
| overloading.rs:230:26:230:46 | S(...) | T | {EXTERNAL LOCATION} | i64 |
12260+
| overloading.rs:230:28:230:45 | ...::default(...) | | {EXTERNAL LOCATION} | i64 |
1225912261
| overloading.rs:231:17:231:17 | x | | {EXTERNAL LOCATION} | i64 |
1226012262
| overloading.rs:231:21:231:61 | ...::f(...) | | {EXTERNAL LOCATION} | i64 |
1226112263
| overloading.rs:231:40:231:60 | S(...) | | overloading.rs:202:5:202:25 | S |

0 commit comments

Comments
 (0)