From f7201023deefcf927c9880004863dd9497e5119c Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Tue, 2 Sep 2025 16:17:11 +0200 Subject: [PATCH 1/5] Rust: Add annotations to type inference tests --- rust/ql/test/library-tests/type-inference/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rust/ql/test/library-tests/type-inference/main.rs b/rust/ql/test/library-tests/type-inference/main.rs index a6395c5af9ff..a1461dedca9b 100644 --- a/rust/ql/test/library-tests/type-inference/main.rs +++ b/rust/ql/test/library-tests/type-inference/main.rs @@ -73,7 +73,7 @@ mod method_impl { impl Foo { pub fn m1(self) -> Self { - self + self // $ type=self:Foo } pub fn m2(self) -> Foo { @@ -108,7 +108,7 @@ mod trait_impl { impl MyTrait for MyThing { // MyThing::trait_method fn trait_method(self) -> bool { - self.field // $ fieldof=MyThing + self.field // $ type=self:MyThing fieldof=MyThing } } From 1b683f635992b082e51948e4d1adda9909e8150e Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Tue, 2 Sep 2025 16:30:21 +0200 Subject: [PATCH 2/5] Rust: Infer certain type for self shorthand --- .../codeql/rust/internal/TypeInference.qll | 40 +++++++++---------- .../test/library-tests/type-inference/main.rs | 4 +- .../type-inference/type-inference.expected | 4 -- 3 files changed, 21 insertions(+), 27 deletions(-) diff --git a/rust/ql/lib/codeql/rust/internal/TypeInference.qll b/rust/ql/lib/codeql/rust/internal/TypeInference.qll index ade1a5514f61..348b9c9f7d12 100644 --- a/rust/ql/lib/codeql/rust/internal/TypeInference.qll +++ b/rust/ql/lib/codeql/rust/internal/TypeInference.qll @@ -254,6 +254,10 @@ private TypeMention getTypeAnnotation(AstNode n) { pragma[nomagic] private Type inferAnnotatedType(AstNode n, TypePath path) { result = getTypeAnnotation(n).resolveTypeAt(path) + or + // The shorthand self syntax (i.e., a self parameter without a type + // annotation) is sugar for a self parameter with an annotation. + result = inferShorthandSelfType(n, path) } /** Module for inferring certain type information. */ @@ -369,10 +373,7 @@ module CertainTypeInference { */ pragma[nomagic] Type inferCertainType(AstNode n, TypePath path) { - exists(TypeMention tm | - tm = getTypeAnnotation(n) and - result = tm.resolveTypeAt(path) - ) + result = inferAnnotatedType(n, path) or result = inferCertainCallExprType(n, path) or @@ -608,7 +609,7 @@ private Type inferTypeEquality(AstNode n, TypePath path) { */ bindingset[self, suffix, t] pragma[inline_late] -private Type getRefAdjustImplicitSelfType(SelfParam self, TypePath suffix, Type t, TypePath path) { +private Type getRefAdjustShorthandSelfType(SelfParam self, TypePath suffix, Type t, TypePath path) { not self.hasTypeRepr() and ( if self.isRef() @@ -632,13 +633,17 @@ private Type resolveImplSelfType(Impl i, TypePath path) { result = i.getSelfTy().(TypeMention).resolveTypeAt(path) } -/** Gets the type at `path` of the implicitly typed `self` parameter. */ +/** + * Gets the type at `path` of the parameter `self` which uses the [shorthand + * syntax][1] which is sugar for an explicit annotation. + * + * [1]: https://doc.rust-lang.org/stable/reference/items/associated-items.html#r-associated.fn.method.self-pat-shorthands + */ pragma[nomagic] -private Type inferImplicitSelfType(SelfParam self, TypePath path) { - exists(ImplOrTraitItemNode i, Function f, TypePath suffix, Type t | - f = i.getAnAssocItem() and - self = f.getParamList().getSelfParam() and - result = getRefAdjustImplicitSelfType(self, suffix, t, path) +private Type inferShorthandSelfType(SelfParam self, TypePath path) { + exists(ImplOrTraitItemNode i, TypePath suffix, Type t | + self = i.getAnAssocItem().(Function).getParamList().getSelfParam() and + result = getRefAdjustShorthandSelfType(self, suffix, t, path) | t = resolveImplSelfType(i, suffix) or @@ -926,11 +931,8 @@ private module CallExprBaseMatchingInput implements MatchingInputSig { or exists(SelfParam self | self = pragma[only_bind_into](this.getParamList().getSelfParam()) and - dpos.isSelf() - | + dpos.isSelf() and result = inferAnnotatedType(self, path) // `self` parameter with type annotation - or - result = inferImplicitSelfType(self, path) // `self` parameter without type annotation ) or // For associated functions, we may also need to match type arguments against @@ -2420,14 +2422,10 @@ private module Cached { else any() ) and ( - result = inferAnnotatedType(n, path) - or result = inferAssignmentOperationType(n, path) or result = inferTypeEquality(n, path) or - result = inferImplicitSelfType(n, path) - or result = inferStructExprType(n, path) or result = inferPathExprType(n, path) @@ -2491,9 +2489,9 @@ private module Debug { Input2::conditionSatisfiesConstraint(abs, condition, constraint) } - predicate debugInferImplicitSelfType(SelfParam self, TypePath path, Type t) { + predicate debugInferShorthandSelfType(SelfParam self, TypePath path, Type t) { self = getRelevantLocatable() and - t = inferImplicitSelfType(self, path) + t = inferShorthandSelfType(self, path) } predicate debugInferCallExprBaseType(AstNode n, TypePath path, Type t) { diff --git a/rust/ql/test/library-tests/type-inference/main.rs b/rust/ql/test/library-tests/type-inference/main.rs index a1461dedca9b..6ce7a32184cb 100644 --- a/rust/ql/test/library-tests/type-inference/main.rs +++ b/rust/ql/test/library-tests/type-inference/main.rs @@ -73,7 +73,7 @@ mod method_impl { impl Foo { pub fn m1(self) -> Self { - self // $ type=self:Foo + self // $ certainType=self:Foo } pub fn m2(self) -> Foo { @@ -108,7 +108,7 @@ mod trait_impl { impl MyTrait for MyThing { // MyThing::trait_method fn trait_method(self) -> bool { - self.field // $ type=self:MyThing fieldof=MyThing + self.field // $ certainType=self:MyThing fieldof=MyThing } } diff --git a/rust/ql/test/library-tests/type-inference/type-inference.expected b/rust/ql/test/library-tests/type-inference/type-inference.expected index 158af57728ff..d53f33402277 100644 --- a/rust/ql/test/library-tests/type-inference/type-inference.expected +++ b/rust/ql/test/library-tests/type-inference/type-inference.expected @@ -2467,7 +2467,6 @@ inferType | main.rs:1328:33:1328:36 | SelfParam | | main.rs:1326:5:1329:5 | Self [trait ATrait] | | main.rs:1334:29:1334:33 | SelfParam | | file://:0:0:0:0 | & | | main.rs:1334:29:1334:33 | SelfParam | &T | file://:0:0:0:0 | & | -| main.rs:1334:29:1334:33 | SelfParam | &T | main.rs:1307:5:1310:5 | MyInt | | main.rs:1334:29:1334:33 | SelfParam | &T.&T | main.rs:1307:5:1310:5 | MyInt | | main.rs:1334:43:1336:9 | { ... } | | {EXTERNAL LOCATION} | i64 | | main.rs:1335:13:1335:22 | (...) | | main.rs:1307:5:1310:5 | MyInt | @@ -2481,7 +2480,6 @@ inferType | main.rs:1335:16:1335:20 | * ... | &T | main.rs:1307:5:1310:5 | MyInt | | main.rs:1335:17:1335:20 | self | | file://:0:0:0:0 | & | | main.rs:1335:17:1335:20 | self | &T | file://:0:0:0:0 | & | -| main.rs:1335:17:1335:20 | self | &T | main.rs:1307:5:1310:5 | MyInt | | main.rs:1335:17:1335:20 | self | &T.&T | main.rs:1307:5:1310:5 | MyInt | | main.rs:1339:33:1339:36 | SelfParam | | file://:0:0:0:0 | & | | main.rs:1339:33:1339:36 | SelfParam | &T | main.rs:1307:5:1310:5 | MyInt | @@ -3798,7 +3796,6 @@ inferType | main.rs:2030:31:2032:9 | { ... } | | main.rs:2002:5:2002:14 | S2 | | main.rs:2031:13:2031:14 | S2 | | main.rs:2002:5:2002:14 | S2 | | main.rs:2036:18:2036:22 | SelfParam | | file://:0:0:0:0 | & | -| main.rs:2036:18:2036:22 | SelfParam | | main.rs:2003:5:2003:22 | S3 | | main.rs:2036:18:2036:22 | SelfParam | &T | main.rs:2003:5:2003:22 | S3 | | main.rs:2036:18:2036:22 | SelfParam | &T.T3 | main.rs:2035:10:2035:17 | T | | main.rs:2036:30:2039:9 | { ... } | | main.rs:2035:10:2035:17 | T | @@ -3807,7 +3804,6 @@ inferType | main.rs:2037:17:2037:21 | S3(...) | &T | main.rs:2003:5:2003:22 | S3 | | main.rs:2037:17:2037:21 | S3(...) | &T.T3 | main.rs:2035:10:2035:17 | T | | main.rs:2037:25:2037:28 | self | | file://:0:0:0:0 | & | -| main.rs:2037:25:2037:28 | self | | main.rs:2003:5:2003:22 | S3 | | main.rs:2037:25:2037:28 | self | &T | main.rs:2003:5:2003:22 | S3 | | main.rs:2037:25:2037:28 | self | &T.T3 | main.rs:2035:10:2035:17 | T | | main.rs:2038:13:2038:21 | t.clone() | | main.rs:2035:10:2035:17 | T | From de8e535c3a2ec28b3fda48f2ac828fb63ae198ab Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Tue, 2 Sep 2025 16:34:03 +0200 Subject: [PATCH 3/5] Rust: Move predicates up to right before first usage --- .../codeql/rust/internal/TypeInference.qll | 96 +++++++++---------- 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/rust/ql/lib/codeql/rust/internal/TypeInference.qll b/rust/ql/lib/codeql/rust/internal/TypeInference.qll index 348b9c9f7d12..7af738836231 100644 --- a/rust/ql/lib/codeql/rust/internal/TypeInference.qll +++ b/rust/ql/lib/codeql/rust/internal/TypeInference.qll @@ -250,6 +250,54 @@ private TypeMention getTypeAnnotation(AstNode n) { ) } +/** + * Gets the type of the implicitly typed `self` parameter, taking into account + * whether the parameter is passed by value or by reference. + */ +bindingset[self, suffix, t] +pragma[inline_late] +private Type getRefAdjustShorthandSelfType(SelfParam self, TypePath suffix, Type t, TypePath path) { + not self.hasTypeRepr() and + ( + if self.isRef() + then + // `fn f(&self, ...)` + path.isEmpty() and + result = TRefType() + or + path = TypePath::cons(TRefTypeParameter(), suffix) and + result = t + else ( + // `fn f(self, ...)` + path = suffix and + result = t + ) + ) +} + +pragma[nomagic] +private Type resolveImplSelfType(Impl i, TypePath path) { + result = i.getSelfTy().(TypeMention).resolveTypeAt(path) +} + +/** + * Gets the type at `path` of the parameter `self` which uses the [shorthand + * syntax][1] which is sugar for an explicit annotation. + * + * [1]: https://doc.rust-lang.org/stable/reference/items/associated-items.html#r-associated.fn.method.self-pat-shorthands + */ +pragma[nomagic] +private Type inferShorthandSelfType(SelfParam self, TypePath path) { + exists(ImplOrTraitItemNode i, TypePath suffix, Type t | + self = i.getAnAssocItem().(Function).getParamList().getSelfParam() and + result = getRefAdjustShorthandSelfType(self, suffix, t, path) + | + t = resolveImplSelfType(i, suffix) + or + t = TSelfTypeParameter(i) and suffix.isEmpty() + ) +} + /** Gets the type of `n`, which has an explicit type annotation. */ pragma[nomagic] private Type inferAnnotatedType(AstNode n, TypePath path) { @@ -603,54 +651,6 @@ private Type inferTypeEquality(AstNode n, TypePath path) { ) } -/** - * Gets the type of the implicitly typed `self` parameter, taking into account - * whether the parameter is passed by value or by reference. - */ -bindingset[self, suffix, t] -pragma[inline_late] -private Type getRefAdjustShorthandSelfType(SelfParam self, TypePath suffix, Type t, TypePath path) { - not self.hasTypeRepr() and - ( - if self.isRef() - then - // `fn f(&self, ...)` - path.isEmpty() and - result = TRefType() - or - path = TypePath::cons(TRefTypeParameter(), suffix) and - result = t - else ( - // `fn f(self, ...)` - path = suffix and - result = t - ) - ) -} - -pragma[nomagic] -private Type resolveImplSelfType(Impl i, TypePath path) { - result = i.getSelfTy().(TypeMention).resolveTypeAt(path) -} - -/** - * Gets the type at `path` of the parameter `self` which uses the [shorthand - * syntax][1] which is sugar for an explicit annotation. - * - * [1]: https://doc.rust-lang.org/stable/reference/items/associated-items.html#r-associated.fn.method.self-pat-shorthands - */ -pragma[nomagic] -private Type inferShorthandSelfType(SelfParam self, TypePath path) { - exists(ImplOrTraitItemNode i, TypePath suffix, Type t | - self = i.getAnAssocItem().(Function).getParamList().getSelfParam() and - result = getRefAdjustShorthandSelfType(self, suffix, t, path) - | - t = resolveImplSelfType(i, suffix) - or - t = TSelfTypeParameter(i) and suffix.isEmpty() - ) -} - /** * A matching configuration for resolving types of struct expressions * like `Foo { bar = baz }`. From e610465ee8830dfadfada4a9c8b03dc3df452397 Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Wed, 3 Sep 2025 12:53:30 +0200 Subject: [PATCH 4/5] Rust: Suppress type inference inconsistency that can be explained by path resolution --- rust/ql/lib/codeql/rust/internal/TypeInference.qll | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/rust/ql/lib/codeql/rust/internal/TypeInference.qll b/rust/ql/lib/codeql/rust/internal/TypeInference.qll index 7af738836231..355429c66a7a 100644 --- a/rust/ql/lib/codeql/rust/internal/TypeInference.qll +++ b/rust/ql/lib/codeql/rust/internal/TypeInference.qll @@ -226,7 +226,13 @@ module Consistency { predicate nonUniqueCertainType(AstNode n, TypePath path, Type t) { strictcount(CertainTypeInference::inferCertainType(n, path)) > 1 and - t = CertainTypeInference::inferCertainType(n, path) + t = CertainTypeInference::inferCertainType(n, path) and + // Suppress the inconsistency if `n` is a self parameter and the type + // mention for the self type has multiple types for a path. + not exists(ImplItemNode impl, TypePath path0 | + n = impl.getAnAssocItem().(Function).getParamList().getSelfParam() and + strictcount(impl.(Impl).getSelfTy().(TypeMention).resolveTypeAt(path0)) > 1 + ) } } From 26919a6c6ec4e9950efe53617f8bc75e581acc23 Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Thu, 4 Sep 2025 12:50:14 +0200 Subject: [PATCH 5/5] Rust: Rename variable as suggested in review --- rust/ql/lib/codeql/rust/internal/TypeInference.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rust/ql/lib/codeql/rust/internal/TypeInference.qll b/rust/ql/lib/codeql/rust/internal/TypeInference.qll index 355429c66a7a..bcb8e5e1ff6b 100644 --- a/rust/ql/lib/codeql/rust/internal/TypeInference.qll +++ b/rust/ql/lib/codeql/rust/internal/TypeInference.qll @@ -229,9 +229,9 @@ module Consistency { t = CertainTypeInference::inferCertainType(n, path) and // Suppress the inconsistency if `n` is a self parameter and the type // mention for the self type has multiple types for a path. - not exists(ImplItemNode impl, TypePath path0 | + not exists(ImplItemNode impl, TypePath selfTypePath | n = impl.getAnAssocItem().(Function).getParamList().getSelfParam() and - strictcount(impl.(Impl).getSelfTy().(TypeMention).resolveTypeAt(path0)) > 1 + strictcount(impl.(Impl).getSelfTy().(TypeMention).resolveTypeAt(selfTypePath)) > 1 ) } }