From 0dcf15bf7733ce7c37e45b0a0349f307f1168985 Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Wed, 21 May 2025 12:59:00 +0200 Subject: [PATCH 1/3] Rust: Add type inference tests for operators --- .../ql/test/library-tests/type-inference/main.rs | 16 ++++++++++++++++ .../type-inference/type-inference.expected | 16 ++++++++++++---- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/rust/ql/test/library-tests/type-inference/main.rs b/rust/ql/test/library-tests/type-inference/main.rs index 7ac5710b7a1a..0c938d516f09 100644 --- a/rust/ql/test/library-tests/type-inference/main.rs +++ b/rust/ql/test/library-tests/type-inference/main.rs @@ -1224,6 +1224,21 @@ mod builtins { } } +mod operators { + pub fn f() { + let x = true && false; // $ MISSING: type=x:bool + let y = true || false; // $ MISSING: type=y:bool + + let mut a; + if 34 == 33 { + let z = (a = 1); // $ MISSING: type=z:() MISSING: type=a:i32 + } else { + a = 2; // $ MISSING: type=a:i32 + } + a; // $ MISSING: type=a:i32 + } +} + fn main() { field_access::f(); method_impl::f(); @@ -1242,4 +1257,5 @@ fn main() { borrowed_typed::f(); try_expressions::f(); builtins::f(); + operators::f(); } 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 b91a839b5ab9..473957c03447 100644 --- a/rust/ql/test/library-tests/type-inference/type-inference.expected +++ b/rust/ql/test/library-tests/type-inference/type-inference.expected @@ -1581,7 +1581,15 @@ inferType | main.rs:1222:17:1222:20 | true | | file:///BUILTINS/types.rs:3:1:5:16 | bool | | main.rs:1223:13:1223:13 | f | | file:///BUILTINS/types.rs:3:1:5:16 | bool | | main.rs:1223:17:1223:21 | false | | file:///BUILTINS/types.rs:3:1:5:16 | bool | -| main.rs:1229:5:1229:20 | ...::f(...) | | main.rs:67:5:67:21 | Foo | -| main.rs:1230:5:1230:60 | ...::g(...) | | main.rs:67:5:67:21 | Foo | -| main.rs:1230:20:1230:38 | ...::Foo {...} | | main.rs:67:5:67:21 | Foo | -| main.rs:1230:41:1230:59 | ...::Foo {...} | | main.rs:67:5:67:21 | Foo | +| main.rs:1229:17:1229:20 | true | | file:///BUILTINS/types.rs:3:1:5:16 | bool | +| main.rs:1229:25:1229:29 | false | | file:///BUILTINS/types.rs:3:1:5:16 | bool | +| main.rs:1230:17:1230:20 | true | | file:///BUILTINS/types.rs:3:1:5:16 | bool | +| main.rs:1230:25:1230:29 | false | | file:///BUILTINS/types.rs:3:1:5:16 | bool | +| main.rs:1233:12:1233:13 | 34 | | file:///BUILTINS/types.rs:12:1:12:15 | i32 | +| main.rs:1233:18:1233:19 | 33 | | file:///BUILTINS/types.rs:12:1:12:15 | i32 | +| main.rs:1234:26:1234:26 | 1 | | file:///BUILTINS/types.rs:12:1:12:15 | i32 | +| main.rs:1236:17:1236:17 | 2 | | file:///BUILTINS/types.rs:12:1:12:15 | i32 | +| main.rs:1244:5:1244:20 | ...::f(...) | | main.rs:67:5:67:21 | Foo | +| main.rs:1245:5:1245:60 | ...::g(...) | | main.rs:67:5:67:21 | Foo | +| main.rs:1245:20:1245:38 | ...::Foo {...} | | main.rs:67:5:67:21 | Foo | +| main.rs:1245:41:1245:59 | ...::Foo {...} | | main.rs:67:5:67:21 | Foo | From fafae8950211501d337c7380716f487300c6e703 Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Wed, 21 May 2025 13:00:28 +0200 Subject: [PATCH 2/3] Rust: Add unit type --- rust/ql/lib/codeql/rust/internal/Type.qll | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/rust/ql/lib/codeql/rust/internal/Type.qll b/rust/ql/lib/codeql/rust/internal/Type.qll index 9ffbf0614635..bb698236debc 100644 --- a/rust/ql/lib/codeql/rust/internal/Type.qll +++ b/rust/ql/lib/codeql/rust/internal/Type.qll @@ -9,6 +9,7 @@ private import codeql.rust.elements.internal.generated.Synth cached newtype TType = + TUnit() or TStruct(Struct s) { Stages::TypeInferenceStage::ref() } or TEnum(Enum e) or TTrait(Trait t) or @@ -48,6 +49,21 @@ abstract class Type extends TType { abstract Location getLocation(); } +/** The unit type `()`. */ +class UnitType extends Type, TUnit { + UnitType() { this = TUnit() } + + override StructField getStructField(string name) { none() } + + override TupleField getTupleField(int i) { none() } + + override TypeParameter getTypeParameter(int i) { none() } + + override string toString() { result = "()" } + + override Location getLocation() { result instanceof EmptyLocation } +} + abstract private class StructOrEnumType extends Type { abstract ItemNode asItemNode(); } From 666726c9359b8e58246757762d054d4ba507ce99 Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Wed, 21 May 2025 13:02:55 +0200 Subject: [PATCH 3/3] Rust: Infer types for non-overloadable operators --- .../codeql/rust/internal/TypeInference.qll | 28 +++++++++++++++++-- .../test/library-tests/type-inference/main.rs | 10 +++---- .../type-inference/type-inference.expected | 12 ++++++++ 3 files changed, 43 insertions(+), 7 deletions(-) diff --git a/rust/ql/lib/codeql/rust/internal/TypeInference.qll b/rust/ql/lib/codeql/rust/internal/TypeInference.qll index 278d9ebc3176..c13d80c2d198 100644 --- a/rust/ql/lib/codeql/rust/internal/TypeInference.qll +++ b/rust/ql/lib/codeql/rust/internal/TypeInference.qll @@ -7,6 +7,7 @@ private import Type as T private import TypeMention private import codeql.typeinference.internal.TypeInference private import codeql.rust.frameworks.stdlib.Stdlib +private import codeql.rust.frameworks.stdlib.Bultins as Builtins class Type = T::Type; @@ -190,6 +191,21 @@ private Type inferAnnotatedType(AstNode n, TypePath path) { result = getTypeAnnotation(n).resolveTypeAt(path) } +private Type inferLogicalOperationType(AstNode n, TypePath path) { + exists(Builtins::BuiltinType t, BinaryLogicalOperation be | + n = [be, be.getLhs(), be.getRhs()] and + path.isEmpty() and + result = TStruct(t) and + t instanceof Builtins::Bool + ) +} + +private Type inferAssignmentOperationType(AstNode n, TypePath path) { + n instanceof AssignmentOperation and + path.isEmpty() and + result = TUnit() +} + /** * Holds if the type of `n1` at `path1` is the same as the type of `n2` at * `path2` and type information should propagate in both directions through the @@ -237,6 +253,12 @@ private predicate typeEquality(AstNode n1, TypePath path1, AstNode n2, TypePath break.getTarget() = n2.(LoopExpr) and path1 = path2 ) + or + exists(AssignmentExpr be | + n1 = be.getLhs() and + n2 = be.getRhs() and + path1 = path2 + ) } pragma[nomagic] @@ -932,8 +954,6 @@ private Type inferTryExprType(TryExpr te, TypePath path) { ) } -private import codeql.rust.frameworks.stdlib.Bultins as Builtins - pragma[nomagic] private StructType inferLiteralType(LiteralExpr le) { exists(Builtins::BuiltinType t | result = TStruct(t) | @@ -1156,6 +1176,10 @@ private module Cached { Stages::TypeInferenceStage::ref() and result = inferAnnotatedType(n, path) or + result = inferLogicalOperationType(n, path) + or + result = inferAssignmentOperationType(n, path) + or result = inferTypeEquality(n, path) or result = inferImplicitSelfType(n, path) diff --git a/rust/ql/test/library-tests/type-inference/main.rs b/rust/ql/test/library-tests/type-inference/main.rs index 0c938d516f09..b33010e7b83c 100644 --- a/rust/ql/test/library-tests/type-inference/main.rs +++ b/rust/ql/test/library-tests/type-inference/main.rs @@ -1226,16 +1226,16 @@ mod builtins { mod operators { pub fn f() { - let x = true && false; // $ MISSING: type=x:bool - let y = true || false; // $ MISSING: type=y:bool + let x = true && false; // $ type=x:bool + let y = true || false; // $ type=y:bool let mut a; if 34 == 33 { - let z = (a = 1); // $ MISSING: type=z:() MISSING: type=a:i32 + let z = (a = 1); // $ type=z:() type=a:i32 } else { - a = 2; // $ MISSING: type=a:i32 + a = 2; // $ type=a:i32 } - a; // $ MISSING: type=a:i32 + a; // $ type=a:i32 } } 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 473957c03447..b8b52cf4b50c 100644 --- a/rust/ql/test/library-tests/type-inference/type-inference.expected +++ b/rust/ql/test/library-tests/type-inference/type-inference.expected @@ -1581,14 +1581,26 @@ inferType | main.rs:1222:17:1222:20 | true | | file:///BUILTINS/types.rs:3:1:5:16 | bool | | main.rs:1223:13:1223:13 | f | | file:///BUILTINS/types.rs:3:1:5:16 | bool | | main.rs:1223:17:1223:21 | false | | file:///BUILTINS/types.rs:3:1:5:16 | bool | +| main.rs:1229:13:1229:13 | x | | file:///BUILTINS/types.rs:3:1:5:16 | bool | | main.rs:1229:17:1229:20 | true | | file:///BUILTINS/types.rs:3:1:5:16 | bool | +| main.rs:1229:17:1229:29 | ... && ... | | file:///BUILTINS/types.rs:3:1:5:16 | bool | | main.rs:1229:25:1229:29 | false | | file:///BUILTINS/types.rs:3:1:5:16 | bool | +| main.rs:1230:13:1230:13 | y | | file:///BUILTINS/types.rs:3:1:5:16 | bool | | main.rs:1230:17:1230:20 | true | | file:///BUILTINS/types.rs:3:1:5:16 | bool | +| main.rs:1230:17:1230:29 | ... \|\| ... | | file:///BUILTINS/types.rs:3:1:5:16 | bool | | main.rs:1230:25:1230:29 | false | | file:///BUILTINS/types.rs:3:1:5:16 | bool | +| main.rs:1232:13:1232:17 | mut a | | file:///BUILTINS/types.rs:12:1:12:15 | i32 | | main.rs:1233:12:1233:13 | 34 | | file:///BUILTINS/types.rs:12:1:12:15 | i32 | | main.rs:1233:18:1233:19 | 33 | | file:///BUILTINS/types.rs:12:1:12:15 | i32 | +| main.rs:1234:17:1234:17 | z | | file://:0:0:0:0 | () | +| main.rs:1234:21:1234:27 | (...) | | file://:0:0:0:0 | () | +| main.rs:1234:22:1234:22 | a | | file:///BUILTINS/types.rs:12:1:12:15 | i32 | +| main.rs:1234:22:1234:26 | ... = ... | | file://:0:0:0:0 | () | | main.rs:1234:26:1234:26 | 1 | | file:///BUILTINS/types.rs:12:1:12:15 | i32 | +| main.rs:1236:13:1236:13 | a | | file:///BUILTINS/types.rs:12:1:12:15 | i32 | +| main.rs:1236:13:1236:17 | ... = ... | | file://:0:0:0:0 | () | | main.rs:1236:17:1236:17 | 2 | | file:///BUILTINS/types.rs:12:1:12:15 | i32 | +| main.rs:1238:9:1238:9 | a | | file:///BUILTINS/types.rs:12:1:12:15 | i32 | | main.rs:1244:5:1244:20 | ...::f(...) | | main.rs:67:5:67:21 | Foo | | main.rs:1245:5:1245:60 | ...::g(...) | | main.rs:67:5:67:21 | Foo | | main.rs:1245:20:1245:38 | ...::Foo {...} | | main.rs:67:5:67:21 | Foo |