Merge pull request #19549 from paldepind/rust/type-inference-operators

Rust: Type inference for non-overloadable operators
This commit is contained in:
Simon Friis Vindum
2025-05-21 17:25:44 +02:00
committed by GitHub
4 changed files with 82 additions and 6 deletions

View File

@@ -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();
}

View File

@@ -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)

View File

@@ -1224,6 +1224,21 @@ mod builtins {
}
}
mod operators {
pub fn f() {
let x = true && false; // $ type=x:bool
let y = true || false; // $ type=y:bool
let mut a;
if 34 == 33 {
let z = (a = 1); // $ type=z:() type=a:i32
} else {
a = 2; // $ type=a:i32
}
a; // $ 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();
}

View File

@@ -1581,7 +1581,27 @@ 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: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 |
| main.rs:1245:41:1245:59 | ...::Foo {...} | | main.rs:67:5:67:21 | Foo |