diff --git a/rust/ql/lib/codeql/rust/internal/TypeInference.qll b/rust/ql/lib/codeql/rust/internal/TypeInference.qll index ade1a5514f61..bcb8e5e1ff6b 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 selfTypePath | + n = impl.getAnAssocItem().(Function).getParamList().getSelfParam() and + strictcount(impl.(Impl).getSelfTy().(TypeMention).resolveTypeAt(selfTypePath)) > 1 + ) } } @@ -250,10 +256,62 @@ 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) { 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 +427,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 @@ -602,50 +657,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 getRefAdjustImplicitSelfType(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 implicitly typed `self` parameter. */ -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) - | - t = resolveImplSelfType(i, suffix) - or - t = TSelfTypeParameter(i) and suffix.isEmpty() - ) -} - /** * A matching configuration for resolving types of struct expressions * like `Foo { bar = baz }`. @@ -926,11 +937,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 +2428,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 +2495,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 a6395c5af9ff..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 + 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 // $ 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 |