From b2fc4f80fbb01663489223fcf0c1478b2da555a2 Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Thu, 20 Mar 2025 16:25:13 +0100 Subject: [PATCH 1/3] Rust: Adjustments to type inference --- .../rust/elements/internal/FieldExprImpl.qll | 2 +- .../rust/elements/internal/StructImpl.qll | 2 +- .../rust/elements/internal/VariantImpl.qll | 6 +- rust/ql/lib/codeql/rust/internal/Type.qll | 2 +- .../codeql/rust/internal/TypeInference.qll | 38 ++--- .../test/library-tests/type-inference/main.rs | 16 +- .../type-inference/type-inference.expected | 126 ++++++++-------- .../type-inference/type-inference.ql | 2 +- .../typeinference/internal/TypeInference.qll | 139 ++++++++++-------- 9 files changed, 172 insertions(+), 161 deletions(-) diff --git a/rust/ql/lib/codeql/rust/elements/internal/FieldExprImpl.qll b/rust/ql/lib/codeql/rust/elements/internal/FieldExprImpl.qll index 0970c73a1584..d7e2380cb77c 100644 --- a/rust/ql/lib/codeql/rust/elements/internal/FieldExprImpl.qll +++ b/rust/ql/lib/codeql/rust/elements/internal/FieldExprImpl.qll @@ -23,7 +23,7 @@ module Impl { */ class FieldExpr extends Generated::FieldExpr { /** Gets the record field that this access references, if any. */ - StructField getStructField() { result = TypeInference::resolveRecordFieldExpr(this) } + StructField getStructField() { result = TypeInference::resolveStructFieldExpr(this) } /** Gets the tuple field that this access references, if any. */ TupleField getTupleField() { result = TypeInference::resolveTupleFieldExpr(this) } diff --git a/rust/ql/lib/codeql/rust/elements/internal/StructImpl.qll b/rust/ql/lib/codeql/rust/elements/internal/StructImpl.qll index 1128da23ea5b..1693f1b989b6 100644 --- a/rust/ql/lib/codeql/rust/elements/internal/StructImpl.qll +++ b/rust/ql/lib/codeql/rust/elements/internal/StructImpl.qll @@ -43,6 +43,6 @@ module Impl { * Empty structs are considered to use record fields. */ pragma[nomagic] - predicate isRecord() { not this.isTuple() } + predicate isStruct() { not this.isTuple() } } } diff --git a/rust/ql/lib/codeql/rust/elements/internal/VariantImpl.qll b/rust/ql/lib/codeql/rust/elements/internal/VariantImpl.qll index 80d857fdc01c..ad46ee688485 100644 --- a/rust/ql/lib/codeql/rust/elements/internal/VariantImpl.qll +++ b/rust/ql/lib/codeql/rust/elements/internal/VariantImpl.qll @@ -38,12 +38,12 @@ module Impl { predicate isTuple() { this.getFieldList() instanceof TupleFieldList } /** - * Holds if this variant uses record fields. + * Holds if this variant uses struct fields. * - * Empty variants are considered to use record fields. + * Empty variants are considered to use struct fields. */ pragma[nomagic] - predicate isRecord() { not this.isTuple() } + predicate isStruct() { not this.isTuple() } /** Gets the enum that this variant belongs to. */ Enum getEnum() { this = result.getVariantList().getAVariant() } diff --git a/rust/ql/lib/codeql/rust/internal/Type.qll b/rust/ql/lib/codeql/rust/internal/Type.qll index 7871191ea518..8bf9f4a1c11f 100644 --- a/rust/ql/lib/codeql/rust/internal/Type.qll +++ b/rust/ql/lib/codeql/rust/internal/Type.qll @@ -29,7 +29,7 @@ abstract class Type extends TType { pragma[nomagic] abstract Function getMethod(string name); - /** Gets the record field `name` belonging to this type, if any. */ + /** Gets the struct field `name` belonging to this type, if any. */ pragma[nomagic] abstract StructField getStructField(string name); diff --git a/rust/ql/lib/codeql/rust/internal/TypeInference.qll b/rust/ql/lib/codeql/rust/internal/TypeInference.qll index 17a7e95b5a30..6e74be7dc823 100644 --- a/rust/ql/lib/codeql/rust/internal/TypeInference.qll +++ b/rust/ql/lib/codeql/rust/internal/TypeInference.qll @@ -248,24 +248,24 @@ private TypeMention getExplicitTypeArgMention(Path path, TypeParam tp) { } /** - * A matching configuration for resolving types of record expressions + * A matching configuration for resolving types of struct expressions * like `Foo { bar = baz }`. */ private module StructExprMatchingInput implements MatchingInputSig { private newtype TPos = TFieldPos(string name) { exists(any(Declaration decl).getField(name)) } or - TRecordPos() + TStructPos() class DeclarationPosition extends TPos { string asFieldPos() { this = TFieldPos(result) } - predicate isRecordPos() { this = TRecordPos() } + predicate isStructPos() { this = TStructPos() } string toString() { result = this.asFieldPos() or - this.isRecordPos() and - result = "(record)" + this.isStructPos() and + result = "(struct)" } } @@ -286,15 +286,15 @@ private module StructExprMatchingInput implements MatchingInputSig { result = tp.resolveTypeAt(path) ) or - // type parameter of the record itself - dpos.isRecordPos() and + // type parameter of the struct itself + dpos.isStructPos() and result = this.getTypeParameter(_) and path = TypePath::singleton(result) } } - private class RecordStructDecl extends Declaration, Struct { - RecordStructDecl() { this.isRecord() } + private class StructDecl extends Declaration, Struct { + StructDecl() { this.isStruct() } override TypeParam getATypeParam() { result = this.getGenericParamList().getATypeParam() } @@ -304,14 +304,14 @@ private module StructExprMatchingInput implements MatchingInputSig { result = super.getDeclaredType(dpos, path) or // type of the struct itself - dpos.isRecordPos() and + dpos.isStructPos() and path.isEmpty() and result = TStruct(this) } } - private class RecordVariantDecl extends Declaration, Variant { - RecordVariantDecl() { this.isRecord() } + private class StructVariantDecl extends Declaration, Variant { + StructVariantDecl() { this.isStruct() } Enum getEnum() { result.getVariantList().getAVariant() = this } @@ -325,7 +325,7 @@ private module StructExprMatchingInput implements MatchingInputSig { result = super.getDeclaredType(dpos, path) or // type of the enum itself - dpos.isRecordPos() and + dpos.isStructPos() and path.isEmpty() and result = TEnum(this.getEnum()) } @@ -342,7 +342,7 @@ private module StructExprMatchingInput implements MatchingInputSig { result = this.getFieldExpr(apos.asFieldPos()).getExpr() or result = this and - apos.isRecordPos() + apos.isStructPos() } Type getInferredType(AccessPosition apos, TypePath path) { @@ -360,8 +360,8 @@ private module StructExprMatchingInput implements MatchingInputSig { private module StructExprMatching = Matching; /** - * Gets the type of `n` at `path`, where `n` is either a record expression or - * a field expression of a record expression. + * Gets the type of `n` at `path`, where `n` is either a struct expression or + * a field expression of a struct expression. */ pragma[nomagic] private Type inferStructExprType(AstNode n, TypePath path) { @@ -777,7 +777,7 @@ private module FieldExprMatchingInput implements MatchingInputSig { Declaration getTarget() { // mutual recursion; resolving fields requires resolving types and vice versa - result = [resolveRecordFieldExpr(this).(AstNode), resolveTupleFieldExpr(this)] + result = [resolveStructFieldExpr(this).(AstNode), resolveTupleFieldExpr(this)] } } @@ -921,10 +921,10 @@ private module Cached { } /** - * Gets the record field that the field expression `fe` resolves to, if any. + * Gets the struct field that the field expression `fe` resolves to, if any. */ cached - StructField resolveRecordFieldExpr(FieldExpr fe) { + StructField resolveStructFieldExpr(FieldExpr fe) { exists(string name | result = getFieldExprLookupType(fe, name).getStructField(name)) } diff --git a/rust/ql/test/library-tests/type-inference/main.rs b/rust/ql/test/library-tests/type-inference/main.rs index 91aa4ffb7d78..b4aecc9e1a28 100644 --- a/rust/ql/test/library-tests/type-inference/main.rs +++ b/rust/ql/test/library-tests/type-inference/main.rs @@ -255,8 +255,8 @@ mod type_parameter_bounds { mod function_trait_bounds { #[derive(Debug)] - struct MyThing { - a: A, + struct MyThing { + a: T, } #[derive(Debug)] @@ -387,12 +387,12 @@ mod method_supertraits { #[derive(Debug)] struct S2; - trait MyTrait1 { - fn m1(self) -> A; + trait MyTrait1 { + fn m1(self) -> Tr1; } - trait MyTrait2: MyTrait1 { - fn m2(self) -> A + trait MyTrait2: MyTrait1 { + fn m2(self) -> Tr2 where Self: Sized, { @@ -404,8 +404,8 @@ mod method_supertraits { } } - trait MyTrait3: MyTrait2> { - fn m3(self) -> A + trait MyTrait3: MyTrait2> { + fn m3(self) -> Tr3 where Self: Sized, { 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 55e213a22cb6..b43a0ca8f8ed 100644 --- a/rust/ql/test/library-tests/type-inference/type-inference.expected +++ b/rust/ql/test/library-tests/type-inference/type-inference.expected @@ -337,69 +337,69 @@ inferType | main.rs:279:9:279:9 | x | A | main.rs:278:22:278:23 | T1 | | main.rs:279:9:279:14 | x.m1(...) | | main.rs:278:22:278:23 | T1 | | main.rs:283:15:283:18 | SelfParam | | main.rs:257:5:260:5 | struct MyThing | -| main.rs:283:15:283:18 | SelfParam | A | main.rs:282:10:282:10 | T | +| main.rs:283:15:283:18 | SelfParam | T | main.rs:282:10:282:10 | T | | main.rs:283:26:285:9 | { ... } | | main.rs:282:10:282:10 | T | | main.rs:284:13:284:16 | self | | main.rs:257:5:260:5 | struct MyThing | -| main.rs:284:13:284:16 | self | A | main.rs:282:10:282:10 | T | +| main.rs:284:13:284:16 | self | T | main.rs:282:10:282:10 | T | | main.rs:284:13:284:18 | self.a | | main.rs:282:10:282:10 | T | | main.rs:289:13:289:13 | x | | main.rs:257:5:260:5 | struct MyThing | -| main.rs:289:13:289:13 | x | A | main.rs:262:5:263:14 | struct S1 | +| main.rs:289:13:289:13 | x | T | main.rs:262:5:263:14 | struct S1 | | main.rs:289:17:289:33 | MyThing {...} | | main.rs:257:5:260:5 | struct MyThing | -| main.rs:289:17:289:33 | MyThing {...} | A | main.rs:262:5:263:14 | struct S1 | +| main.rs:289:17:289:33 | MyThing {...} | T | main.rs:262:5:263:14 | struct S1 | | main.rs:289:30:289:31 | S1 | | main.rs:262:5:263:14 | struct S1 | | main.rs:290:13:290:13 | y | | main.rs:257:5:260:5 | struct MyThing | -| main.rs:290:13:290:13 | y | A | main.rs:264:5:265:14 | struct S2 | +| main.rs:290:13:290:13 | y | T | main.rs:264:5:265:14 | struct S2 | | main.rs:290:17:290:33 | MyThing {...} | | main.rs:257:5:260:5 | struct MyThing | -| main.rs:290:17:290:33 | MyThing {...} | A | main.rs:264:5:265:14 | struct S2 | +| main.rs:290:17:290:33 | MyThing {...} | T | main.rs:264:5:265:14 | struct S2 | | main.rs:290:30:290:31 | S2 | | main.rs:264:5:265:14 | struct S2 | | main.rs:292:26:292:26 | x | | main.rs:257:5:260:5 | struct MyThing | -| main.rs:292:26:292:26 | x | A | main.rs:262:5:263:14 | struct S1 | +| main.rs:292:26:292:26 | x | T | main.rs:262:5:263:14 | struct S1 | | main.rs:292:26:292:31 | x.m1(...) | | main.rs:262:5:263:14 | struct S1 | | main.rs:293:26:293:26 | y | | main.rs:257:5:260:5 | struct MyThing | -| main.rs:293:26:293:26 | y | A | main.rs:264:5:265:14 | struct S2 | +| main.rs:293:26:293:26 | y | T | main.rs:264:5:265:14 | struct S2 | | main.rs:293:26:293:31 | y.m1(...) | | main.rs:264:5:265:14 | struct S2 | | main.rs:295:13:295:13 | x | | main.rs:257:5:260:5 | struct MyThing | | main.rs:295:13:295:13 | x | | main.rs:267:5:276:5 | trait MyTrait | | main.rs:295:13:295:13 | x | A | main.rs:262:5:263:14 | struct S1 | -| main.rs:295:13:295:13 | x | A | main.rs:262:5:263:14 | struct S1 | +| main.rs:295:13:295:13 | x | T | main.rs:262:5:263:14 | struct S1 | | main.rs:295:17:295:33 | MyThing {...} | | main.rs:257:5:260:5 | struct MyThing | | main.rs:295:17:295:33 | MyThing {...} | | main.rs:267:5:276:5 | trait MyTrait | | main.rs:295:17:295:33 | MyThing {...} | A | main.rs:262:5:263:14 | struct S1 | -| main.rs:295:17:295:33 | MyThing {...} | A | main.rs:262:5:263:14 | struct S1 | +| main.rs:295:17:295:33 | MyThing {...} | T | main.rs:262:5:263:14 | struct S1 | | main.rs:295:30:295:31 | S1 | | main.rs:262:5:263:14 | struct S1 | | main.rs:296:13:296:13 | y | | main.rs:257:5:260:5 | struct MyThing | | main.rs:296:13:296:13 | y | | main.rs:267:5:276:5 | trait MyTrait | | main.rs:296:13:296:13 | y | A | main.rs:264:5:265:14 | struct S2 | -| main.rs:296:13:296:13 | y | A | main.rs:264:5:265:14 | struct S2 | +| main.rs:296:13:296:13 | y | T | main.rs:264:5:265:14 | struct S2 | | main.rs:296:17:296:33 | MyThing {...} | | main.rs:257:5:260:5 | struct MyThing | | main.rs:296:17:296:33 | MyThing {...} | | main.rs:267:5:276:5 | trait MyTrait | | main.rs:296:17:296:33 | MyThing {...} | A | main.rs:264:5:265:14 | struct S2 | -| main.rs:296:17:296:33 | MyThing {...} | A | main.rs:264:5:265:14 | struct S2 | +| main.rs:296:17:296:33 | MyThing {...} | T | main.rs:264:5:265:14 | struct S2 | | main.rs:296:30:296:31 | S2 | | main.rs:264:5:265:14 | struct S2 | | main.rs:298:26:298:26 | x | | main.rs:257:5:260:5 | struct MyThing | | main.rs:298:26:298:26 | x | | main.rs:267:5:276:5 | trait MyTrait | | main.rs:298:26:298:26 | x | A | main.rs:262:5:263:14 | struct S1 | -| main.rs:298:26:298:26 | x | A | main.rs:262:5:263:14 | struct S1 | +| main.rs:298:26:298:26 | x | T | main.rs:262:5:263:14 | struct S1 | | main.rs:298:26:298:31 | x.m2(...) | | main.rs:262:5:263:14 | struct S1 | | main.rs:299:26:299:26 | y | | main.rs:257:5:260:5 | struct MyThing | | main.rs:299:26:299:26 | y | | main.rs:267:5:276:5 | trait MyTrait | | main.rs:299:26:299:26 | y | A | main.rs:264:5:265:14 | struct S2 | -| main.rs:299:26:299:26 | y | A | main.rs:264:5:265:14 | struct S2 | +| main.rs:299:26:299:26 | y | T | main.rs:264:5:265:14 | struct S2 | | main.rs:299:26:299:31 | y.m2(...) | | main.rs:264:5:265:14 | struct S2 | | main.rs:301:13:301:13 | x | | main.rs:257:5:260:5 | struct MyThing | -| main.rs:301:13:301:13 | x | A | main.rs:262:5:263:14 | struct S1 | +| main.rs:301:13:301:13 | x | T | main.rs:262:5:263:14 | struct S1 | | main.rs:301:17:301:33 | MyThing {...} | | main.rs:257:5:260:5 | struct MyThing | -| main.rs:301:17:301:33 | MyThing {...} | A | main.rs:262:5:263:14 | struct S1 | +| main.rs:301:17:301:33 | MyThing {...} | T | main.rs:262:5:263:14 | struct S1 | | main.rs:301:30:301:31 | S1 | | main.rs:262:5:263:14 | struct S1 | | main.rs:302:13:302:13 | y | | main.rs:257:5:260:5 | struct MyThing | -| main.rs:302:13:302:13 | y | A | main.rs:264:5:265:14 | struct S2 | +| main.rs:302:13:302:13 | y | T | main.rs:264:5:265:14 | struct S2 | | main.rs:302:17:302:33 | MyThing {...} | | main.rs:257:5:260:5 | struct MyThing | -| main.rs:302:17:302:33 | MyThing {...} | A | main.rs:264:5:265:14 | struct S2 | +| main.rs:302:17:302:33 | MyThing {...} | T | main.rs:264:5:265:14 | struct S2 | | main.rs:302:30:302:31 | S2 | | main.rs:264:5:265:14 | struct S2 | | main.rs:304:40:304:40 | x | | main.rs:257:5:260:5 | struct MyThing | -| main.rs:304:40:304:40 | x | A | main.rs:262:5:263:14 | struct S1 | +| main.rs:304:40:304:40 | x | T | main.rs:262:5:263:14 | struct S1 | | main.rs:305:40:305:40 | y | | main.rs:257:5:260:5 | struct MyThing | -| main.rs:305:40:305:40 | y | A | main.rs:264:5:265:14 | struct S2 | +| main.rs:305:40:305:40 | y | T | main.rs:264:5:265:14 | struct S2 | | main.rs:313:15:313:18 | SelfParam | | main.rs:310:5:322:5 | trait MyTrait | | main.rs:315:15:315:18 | SelfParam | | main.rs:310:5:322:5 | trait MyTrait | | main.rs:330:15:330:18 | SelfParam | | main.rs:324:5:325:13 | struct S | @@ -442,50 +442,50 @@ inferType | main.rs:370:26:370:26 | y | A | main.rs:353:5:354:14 | struct S2 | | main.rs:370:26:370:31 | y.m1(...) | | main.rs:353:5:354:14 | struct S2 | | main.rs:391:15:391:18 | SelfParam | | main.rs:390:5:392:5 | trait MyTrait1 | -| main.rs:391:15:391:18 | SelfParam | A | main.rs:390:20:390:20 | A | +| main.rs:391:15:391:18 | SelfParam | Tr1 | main.rs:390:20:390:22 | Tr1 | | main.rs:395:15:395:18 | SelfParam | | main.rs:390:5:392:5 | trait MyTrait1 | | main.rs:395:15:395:18 | SelfParam | | main.rs:394:5:405:5 | trait MyTrait2 | -| main.rs:395:15:395:18 | SelfParam | A | main.rs:394:20:394:20 | A | -| main.rs:395:15:395:18 | SelfParam | A | main.rs:394:20:394:20 | A | -| main.rs:398:9:404:9 | { ... } | | main.rs:394:20:394:20 | A | -| main.rs:399:13:403:13 | if ... {...} else {...} | | main.rs:394:20:394:20 | A | -| main.rs:399:26:401:13 | { ... } | | main.rs:394:20:394:20 | A | +| main.rs:395:15:395:18 | SelfParam | Tr1 | main.rs:394:20:394:22 | Tr2 | +| main.rs:395:15:395:18 | SelfParam | Tr2 | main.rs:394:20:394:22 | Tr2 | +| main.rs:398:9:404:9 | { ... } | | main.rs:394:20:394:22 | Tr2 | +| main.rs:399:13:403:13 | if ... {...} else {...} | | main.rs:394:20:394:22 | Tr2 | +| main.rs:399:26:401:13 | { ... } | | main.rs:394:20:394:22 | Tr2 | | main.rs:400:17:400:20 | self | | main.rs:390:5:392:5 | trait MyTrait1 | | main.rs:400:17:400:20 | self | | main.rs:394:5:405:5 | trait MyTrait2 | -| main.rs:400:17:400:20 | self | A | main.rs:394:20:394:20 | A | -| main.rs:400:17:400:20 | self | A | main.rs:394:20:394:20 | A | -| main.rs:400:17:400:25 | self.m1(...) | | main.rs:394:20:394:20 | A | -| main.rs:401:20:403:13 | { ... } | | main.rs:394:20:394:20 | A | -| main.rs:402:17:402:30 | ...::m1(...) | | main.rs:394:20:394:20 | A | +| main.rs:400:17:400:20 | self | Tr1 | main.rs:394:20:394:22 | Tr2 | +| main.rs:400:17:400:20 | self | Tr2 | main.rs:394:20:394:22 | Tr2 | +| main.rs:400:17:400:25 | self.m1(...) | | main.rs:394:20:394:22 | Tr2 | +| main.rs:401:20:403:13 | { ... } | | main.rs:394:20:394:22 | Tr2 | +| main.rs:402:17:402:30 | ...::m1(...) | | main.rs:394:20:394:22 | Tr2 | | main.rs:402:26:402:29 | self | | main.rs:390:5:392:5 | trait MyTrait1 | | main.rs:402:26:402:29 | self | | main.rs:394:5:405:5 | trait MyTrait2 | -| main.rs:402:26:402:29 | self | A | main.rs:394:20:394:20 | A | -| main.rs:402:26:402:29 | self | A | main.rs:394:20:394:20 | A | +| main.rs:402:26:402:29 | self | Tr1 | main.rs:394:20:394:22 | Tr2 | +| main.rs:402:26:402:29 | self | Tr2 | main.rs:394:20:394:22 | Tr2 | | main.rs:408:15:408:18 | SelfParam | | main.rs:394:5:405:5 | trait MyTrait2 | | main.rs:408:15:408:18 | SelfParam | | main.rs:407:5:418:5 | trait MyTrait3 | -| main.rs:408:15:408:18 | SelfParam | A | main.rs:375:5:378:5 | struct MyThing | -| main.rs:408:15:408:18 | SelfParam | A | main.rs:407:20:407:20 | A | -| main.rs:408:15:408:18 | SelfParam | A.A | main.rs:407:20:407:20 | A | -| main.rs:411:9:417:9 | { ... } | | main.rs:407:20:407:20 | A | -| main.rs:412:13:416:13 | if ... {...} else {...} | | main.rs:407:20:407:20 | A | -| main.rs:412:26:414:13 | { ... } | | main.rs:407:20:407:20 | A | +| main.rs:408:15:408:18 | SelfParam | Tr2 | main.rs:375:5:378:5 | struct MyThing | +| main.rs:408:15:408:18 | SelfParam | Tr2.A | main.rs:407:20:407:22 | Tr3 | +| main.rs:408:15:408:18 | SelfParam | Tr3 | main.rs:407:20:407:22 | Tr3 | +| main.rs:411:9:417:9 | { ... } | | main.rs:407:20:407:22 | Tr3 | +| main.rs:412:13:416:13 | if ... {...} else {...} | | main.rs:407:20:407:22 | Tr3 | +| main.rs:412:26:414:13 | { ... } | | main.rs:407:20:407:22 | Tr3 | | main.rs:413:17:413:20 | self | | main.rs:394:5:405:5 | trait MyTrait2 | | main.rs:413:17:413:20 | self | | main.rs:407:5:418:5 | trait MyTrait3 | -| main.rs:413:17:413:20 | self | A | main.rs:375:5:378:5 | struct MyThing | -| main.rs:413:17:413:20 | self | A | main.rs:407:20:407:20 | A | -| main.rs:413:17:413:20 | self | A.A | main.rs:407:20:407:20 | A | +| main.rs:413:17:413:20 | self | Tr2 | main.rs:375:5:378:5 | struct MyThing | +| main.rs:413:17:413:20 | self | Tr2.A | main.rs:407:20:407:22 | Tr3 | +| main.rs:413:17:413:20 | self | Tr3 | main.rs:407:20:407:22 | Tr3 | | main.rs:413:17:413:25 | self.m2(...) | | main.rs:375:5:378:5 | struct MyThing | -| main.rs:413:17:413:25 | self.m2(...) | A | main.rs:407:20:407:20 | A | -| main.rs:413:17:413:27 | ... .a | | main.rs:407:20:407:20 | A | -| main.rs:414:20:416:13 | { ... } | | main.rs:407:20:407:20 | A | +| main.rs:413:17:413:25 | self.m2(...) | A | main.rs:407:20:407:22 | Tr3 | +| main.rs:413:17:413:27 | ... .a | | main.rs:407:20:407:22 | Tr3 | +| main.rs:414:20:416:13 | { ... } | | main.rs:407:20:407:22 | Tr3 | | main.rs:415:17:415:30 | ...::m2(...) | | main.rs:375:5:378:5 | struct MyThing | -| main.rs:415:17:415:30 | ...::m2(...) | A | main.rs:407:20:407:20 | A | -| main.rs:415:17:415:32 | ... .a | | main.rs:407:20:407:20 | A | +| main.rs:415:17:415:30 | ...::m2(...) | A | main.rs:407:20:407:22 | Tr3 | +| main.rs:415:17:415:32 | ... .a | | main.rs:407:20:407:22 | Tr3 | | main.rs:415:26:415:29 | self | | main.rs:394:5:405:5 | trait MyTrait2 | | main.rs:415:26:415:29 | self | | main.rs:407:5:418:5 | trait MyTrait3 | -| main.rs:415:26:415:29 | self | A | main.rs:375:5:378:5 | struct MyThing | -| main.rs:415:26:415:29 | self | A | main.rs:407:20:407:20 | A | -| main.rs:415:26:415:29 | self | A.A | main.rs:407:20:407:20 | A | +| main.rs:415:26:415:29 | self | Tr2 | main.rs:375:5:378:5 | struct MyThing | +| main.rs:415:26:415:29 | self | Tr2.A | main.rs:407:20:407:22 | Tr3 | +| main.rs:415:26:415:29 | self | Tr3 | main.rs:407:20:407:22 | Tr3 | | main.rs:421:15:421:18 | SelfParam | | main.rs:375:5:378:5 | struct MyThing | | main.rs:421:15:421:18 | SelfParam | A | main.rs:420:10:420:10 | T | | main.rs:421:26:423:9 | { ... } | | main.rs:420:10:420:10 | T | @@ -520,58 +520,58 @@ inferType | main.rs:445:13:445:13 | x | | main.rs:375:5:378:5 | struct MyThing | | main.rs:445:13:445:13 | x | | main.rs:394:5:405:5 | trait MyTrait2 | | main.rs:445:13:445:13 | x | A | main.rs:385:5:386:14 | struct S1 | -| main.rs:445:13:445:13 | x | A | main.rs:385:5:386:14 | struct S1 | +| main.rs:445:13:445:13 | x | Tr2 | main.rs:385:5:386:14 | struct S1 | | main.rs:445:17:445:33 | MyThing {...} | | main.rs:375:5:378:5 | struct MyThing | | main.rs:445:17:445:33 | MyThing {...} | | main.rs:394:5:405:5 | trait MyTrait2 | | main.rs:445:17:445:33 | MyThing {...} | A | main.rs:385:5:386:14 | struct S1 | -| main.rs:445:17:445:33 | MyThing {...} | A | main.rs:385:5:386:14 | struct S1 | +| main.rs:445:17:445:33 | MyThing {...} | Tr2 | main.rs:385:5:386:14 | struct S1 | | main.rs:445:30:445:31 | S1 | | main.rs:385:5:386:14 | struct S1 | | main.rs:446:13:446:13 | y | | main.rs:375:5:378:5 | struct MyThing | | main.rs:446:13:446:13 | y | | main.rs:394:5:405:5 | trait MyTrait2 | | main.rs:446:13:446:13 | y | A | main.rs:387:5:388:14 | struct S2 | -| main.rs:446:13:446:13 | y | A | main.rs:387:5:388:14 | struct S2 | +| main.rs:446:13:446:13 | y | Tr2 | main.rs:387:5:388:14 | struct S2 | | main.rs:446:17:446:33 | MyThing {...} | | main.rs:375:5:378:5 | struct MyThing | | main.rs:446:17:446:33 | MyThing {...} | | main.rs:394:5:405:5 | trait MyTrait2 | | main.rs:446:17:446:33 | MyThing {...} | A | main.rs:387:5:388:14 | struct S2 | -| main.rs:446:17:446:33 | MyThing {...} | A | main.rs:387:5:388:14 | struct S2 | +| main.rs:446:17:446:33 | MyThing {...} | Tr2 | main.rs:387:5:388:14 | struct S2 | | main.rs:446:30:446:31 | S2 | | main.rs:387:5:388:14 | struct S2 | | main.rs:448:26:448:26 | x | | main.rs:375:5:378:5 | struct MyThing | | main.rs:448:26:448:26 | x | | main.rs:394:5:405:5 | trait MyTrait2 | | main.rs:448:26:448:26 | x | A | main.rs:385:5:386:14 | struct S1 | -| main.rs:448:26:448:26 | x | A | main.rs:385:5:386:14 | struct S1 | +| main.rs:448:26:448:26 | x | Tr2 | main.rs:385:5:386:14 | struct S1 | | main.rs:448:26:448:31 | x.m2(...) | | main.rs:385:5:386:14 | struct S1 | | main.rs:449:26:449:26 | y | | main.rs:375:5:378:5 | struct MyThing | | main.rs:449:26:449:26 | y | | main.rs:394:5:405:5 | trait MyTrait2 | | main.rs:449:26:449:26 | y | A | main.rs:387:5:388:14 | struct S2 | -| main.rs:449:26:449:26 | y | A | main.rs:387:5:388:14 | struct S2 | +| main.rs:449:26:449:26 | y | Tr2 | main.rs:387:5:388:14 | struct S2 | | main.rs:449:26:449:31 | y.m2(...) | | main.rs:387:5:388:14 | struct S2 | | main.rs:451:13:451:13 | x | | main.rs:380:5:383:5 | struct MyThing2 | | main.rs:451:13:451:13 | x | | main.rs:407:5:418:5 | trait MyTrait3 | | main.rs:451:13:451:13 | x | A | main.rs:385:5:386:14 | struct S1 | -| main.rs:451:13:451:13 | x | A | main.rs:385:5:386:14 | struct S1 | +| main.rs:451:13:451:13 | x | Tr3 | main.rs:385:5:386:14 | struct S1 | | main.rs:451:17:451:34 | MyThing2 {...} | | main.rs:380:5:383:5 | struct MyThing2 | | main.rs:451:17:451:34 | MyThing2 {...} | | main.rs:407:5:418:5 | trait MyTrait3 | | main.rs:451:17:451:34 | MyThing2 {...} | A | main.rs:385:5:386:14 | struct S1 | -| main.rs:451:17:451:34 | MyThing2 {...} | A | main.rs:385:5:386:14 | struct S1 | +| main.rs:451:17:451:34 | MyThing2 {...} | Tr3 | main.rs:385:5:386:14 | struct S1 | | main.rs:451:31:451:32 | S1 | | main.rs:385:5:386:14 | struct S1 | | main.rs:452:13:452:13 | y | | main.rs:380:5:383:5 | struct MyThing2 | | main.rs:452:13:452:13 | y | | main.rs:407:5:418:5 | trait MyTrait3 | | main.rs:452:13:452:13 | y | A | main.rs:387:5:388:14 | struct S2 | -| main.rs:452:13:452:13 | y | A | main.rs:387:5:388:14 | struct S2 | +| main.rs:452:13:452:13 | y | Tr3 | main.rs:387:5:388:14 | struct S2 | | main.rs:452:17:452:34 | MyThing2 {...} | | main.rs:380:5:383:5 | struct MyThing2 | | main.rs:452:17:452:34 | MyThing2 {...} | | main.rs:407:5:418:5 | trait MyTrait3 | | main.rs:452:17:452:34 | MyThing2 {...} | A | main.rs:387:5:388:14 | struct S2 | -| main.rs:452:17:452:34 | MyThing2 {...} | A | main.rs:387:5:388:14 | struct S2 | +| main.rs:452:17:452:34 | MyThing2 {...} | Tr3 | main.rs:387:5:388:14 | struct S2 | | main.rs:452:31:452:32 | S2 | | main.rs:387:5:388:14 | struct S2 | | main.rs:454:26:454:26 | x | | main.rs:380:5:383:5 | struct MyThing2 | | main.rs:454:26:454:26 | x | | main.rs:407:5:418:5 | trait MyTrait3 | | main.rs:454:26:454:26 | x | A | main.rs:385:5:386:14 | struct S1 | -| main.rs:454:26:454:26 | x | A | main.rs:385:5:386:14 | struct S1 | +| main.rs:454:26:454:26 | x | Tr3 | main.rs:385:5:386:14 | struct S1 | | main.rs:454:26:454:31 | x.m3(...) | | main.rs:385:5:386:14 | struct S1 | | main.rs:455:26:455:26 | y | | main.rs:380:5:383:5 | struct MyThing2 | | main.rs:455:26:455:26 | y | | main.rs:407:5:418:5 | trait MyTrait3 | | main.rs:455:26:455:26 | y | A | main.rs:387:5:388:14 | struct S2 | -| main.rs:455:26:455:26 | y | A | main.rs:387:5:388:14 | struct S2 | +| main.rs:455:26:455:26 | y | Tr3 | main.rs:387:5:388:14 | struct S2 | | main.rs:455:26:455:31 | y.m3(...) | | main.rs:387:5:388:14 | struct S2 | | main.rs:473:22:473:22 | x | | file://:0:0:0:0 | & | | main.rs:473:22:473:22 | x | &T | main.rs:473:11:473:19 | T | @@ -1026,7 +1026,7 @@ resolveMethodCallExpr | main.rs:340:26:340:31 | x.m2(...) | main.rs:315:9:321:9 | fn m2 | | main.rs:369:26:369:31 | x.m1(...) | main.rs:357:9:362:9 | fn m1 | | main.rs:370:26:370:31 | y.m1(...) | main.rs:357:9:362:9 | fn m1 | -| main.rs:400:17:400:25 | self.m1(...) | main.rs:391:9:391:25 | fn m1 | +| main.rs:400:17:400:25 | self.m1(...) | main.rs:391:9:391:27 | fn m1 | | main.rs:413:17:413:25 | self.m2(...) | main.rs:395:9:404:9 | fn m2 | | main.rs:442:26:442:31 | x.m1(...) | main.rs:421:9:423:9 | fn m1 | | main.rs:443:26:443:31 | y.m1(...) | main.rs:421:9:423:9 | fn m1 | diff --git a/rust/ql/test/library-tests/type-inference/type-inference.ql b/rust/ql/test/library-tests/type-inference/type-inference.ql index dfd13125796b..67f02c96cfa8 100644 --- a/rust/ql/test/library-tests/type-inference/type-inference.ql +++ b/rust/ql/test/library-tests/type-inference/type-inference.ql @@ -12,7 +12,7 @@ query predicate resolveMethodCallExpr(MethodCallExpr mce, Function f) { } query predicate resolveFieldExpr(FieldExpr fe, AstNode target) { - target = resolveRecordFieldExpr(fe) + target = resolveStructFieldExpr(fe) or target = resolveTupleFieldExpr(fe) } diff --git a/shared/typeinference/codeql/typeinference/internal/TypeInference.qll b/shared/typeinference/codeql/typeinference/internal/TypeInference.qll index 3c03530629fa..ee3c2adda017 100644 --- a/shared/typeinference/codeql/typeinference/internal/TypeInference.qll +++ b/shared/typeinference/codeql/typeinference/internal/TypeInference.qll @@ -106,28 +106,32 @@ module Make1 Input1> { /** * A path into a type. * - * Paths are represented in left-to-right order, for example, a path `"0.1"` into the - * type `C1,C3>` points at the type `B`. + * Paths are represented in left-to-right order, for example, a path `"A0.B1"` + * into the type `A,C>` points at the type `T`, assuming that the + * first type parameter of `A` is named `A0` and the second type parameter of + * `B` is named `B1`. * * Type paths are used to represent constructed types without using a `newtype`, which * makes it practically feasible to do type inference in mutual recursion with call * resolution. * - * As an example, the type above can be represented by the following set of tuples + * As an example, the type above can be represented by the following set of + * tuples, if assuming the same naming convention for type parameters as + * above: * - * `TypePath` | `Type` - * ---------- | -------- - * `""` | ``C1`2`` - * `"0"` | ``C2`2`` - * `"0.0"` | `A` - * `"0.1"` | `B` - * `"1"` | ``C3`2`` - * `"1.0"` | `C` - * `"1.1"` | `D` + * `TypePath` | `Type` + * ----------- | -------- + * `""` | ``A`2`` + * `"A0"` | ``B`2`` + * `"A0.B0"` | `S` + * `"A0.B1"` | `T` + * `"A1"` | ``C`2`` + * `"A1.C0"` | `U` + * `"A1.C1"` | `V` * - * Note that while we write type paths using type parameter positions (e.g. `"0.1"`), - * the actual implementation uses unique type parameter identifiers, in order to not - * mix up type parameters from different types. + * Note that while we write type paths using type parameter names, the actual + * implementation uses unique type parameter identifiers, in order to not mix + * up type parameters from different types. */ class TypePath extends String { bindingset[this] @@ -439,7 +443,8 @@ module Make1 Input1> { * Gets the declared type of this declaration at `path` for position `dpos`. * * For example, if this declaration is the method `int M(bool b)`, - * then the declared type at parameter position `0` is `bool` and the + * then the declared type at parameter position `0` is `bool`, the + * declared type at the `this` position is the class type, and the * declared return type is `int`. */ Type getDeclaredType(DeclarationPosition dpos, TypePath path); @@ -540,7 +545,11 @@ module Make1 Input1> { /** * Gets the type of the type argument at `path` in `a` that corresponds to - * the type parameter `tp` in `target`. + * the type parameter `tp` in `target`, if any. + * + * Note, that this predicate crucially does not depend on type inference, + * and hence can appear in negated position, e.g., as in + * `directTypeMatch`. */ bindingset[a, target] pragma[inline_late] @@ -605,19 +614,21 @@ module Make1 Input1> { * * class Sub : Mid> { } * - * new Sub().ToString(); + * new Sub().ToString(); + * // ^^^^^^^^^^^^^^ `apos` + * // ^^^^^^^^^^^^^^^^^^^^^^^^^ `a` * ``` * - * for the node `new Sub()`, which is the receiver of a method call, we - * have: + * where the method call is an access and `new Sub()` is an access + * position , which is the receiver of a method call, we have: * - * `baseMention` | `path` | `t` - * ------------- | --------- | --- - * `Mid>` | `"0"` | ``C`1`` - * `Mid>` | `"0.1"` | `int` - * `Base>` | `"0"` | ``C`1`` - * `Base>` | `"0.0"` | ``C`1`` - * `Base>` | `"0.0.1"` | `int` + * `baseMention` | `path` | `t` + * ------------- | ------------ | --- + * `Mid>` | `"T3"` | ``C`1`` + * `Mid>` | `"T3.T1"` | `int` + * `Base>` | `"T2"` | ``C`1`` + * `Base>` | `"T2.T1"` | ``C`1`` + * `Base>` | `"T2.T1.T1"` | `int` */ pragma[nomagic] predicate hasBaseTypeMention( @@ -635,28 +646,36 @@ module Make1 Input1> { } } + /** + * Holds if the type of `a` at `apos` has the base type `base`, and when + * viewed as an element of that type has at `path` the type `t`. + */ pragma[nomagic] private predicate accessBaseType( - Access a, AccessPosition apos, Declaration target, Type base, TypePath path, Type t + Access a, AccessPosition apos, Type base, TypePath path, Type t ) { exists(TypeMention tm | - target = a.getTarget() and AccessBaseType::hasBaseTypeMention(a, apos, tm, path, t) and base = resolveTypeMentionRoot(tm) ) } + /** + * Holds if the declared type at `decl` for `dpos` at the `path` is `tp` + * and `path` starts with a type parameter of `base`. + */ pragma[nomagic] private predicate declarationBaseType( - Declaration decl, DeclarationPosition dpos, Type base, TypePath path, Type t + Declaration decl, DeclarationPosition dpos, Type base, TypePath path, TypeParameter tp ) { - t = decl.getDeclaredType(dpos, path) and + tp = decl.getDeclaredType(dpos, path) and path.isCons(base.getATypeParameter(), _) } /** - * Holds if the (transitive) base type `t` at `path` of `a` matches the type - * parameter `tp`, which is used in the declared types of `target`. + * Holds if the (transitive) base type `t` at `path` of `a` for some + * `AccessPosition` matches the type parameter `tp`, which is used in the + * declared types of `target`. * * For example, in * @@ -681,17 +700,18 @@ module Make1 Input1> { * * `path` | `t` * --------- | ------- - * `"0"` | ``C`1`` - * `"0.0"` | ``C`1`` - * `"0.0.1"` | `int` + * `""` | ``C`1`` + * `"T1"` | ``C`1`` + * `"T1.T1"` | `int` */ pragma[nomagic] private predicate baseTypeMatch( Access a, Declaration target, TypePath path, Type t, TypeParameter tp ) { not exists(getTypeArgument(a, target, tp, _)) and + target = a.getTarget() and exists(AccessPosition apos, DeclarationPosition dpos, Type base, TypePath pathToTypeParam | - accessBaseType(a, apos, target, base, pathToTypeParam.append(path), t) and + accessBaseType(a, apos, base, pathToTypeParam.append(path), t) and declarationBaseType(target, dpos, base, pathToTypeParam, tp) and accessDeclarationPositionMatch(apos, dpos) ) @@ -710,17 +730,6 @@ module Make1 Input1> { t = getTypeArgument(a, target, tp, path) } - pragma[nomagic] - private predicate implicitTypeMatch( - Access a, Declaration target, TypePath path, Type t, TypeParameter tp - ) { - // We can get the type of `tp` from one of the access positions - directTypeMatch(a, target, path, t, tp) - or - // We can get the type of `tp` by going up the type hiearchy - baseTypeMatch(a, target, path, t, tp) - } - pragma[inline] private predicate typeMatch( Access a, Declaration target, TypePath path, Type t, TypeParameter tp @@ -729,9 +738,11 @@ module Make1 Input1> { // at the target. explicitTypeMatch(a, target, path, t, tp) or - // No explicit type argument, so we deduce the parameter from other - // information - implicitTypeMatch(a, target, path, t, tp) + // We can infer the type of `tp` from one of the access positions + directTypeMatch(a, target, path, t, tp) + or + // We can infer the type of `tp` by going up the type hiearchy + baseTypeMatch(a, target, path, t, tp) } /** @@ -750,27 +761,27 @@ module Make1 Input1> { * * class Sub : Mid> { } * - * new Sub().Method(); + * new Sub().Method(); // Note: Sub is a subtype of Base>> * // ^^^^^^^^^^^^^^^^^^^^^^^ `a` * ``` * * we infer the following types for the return position: * - * `path` | `t` - * ----------- | ------- - * `"0"` | ``C`1`` - * `"0.0"` | ``C`1`` - * `"0.0.0"` | ``C`1`` - * `"0.0.0.1"` | `int` + * `path` | `t` + * ------------ | ------- + * `""` | ``C`1`` + * `"T1"` | ``C`1`` + * `"T1.T1"` | ``C`1`` + * `"T1.T1.T1"` | `int` * * We also infer the following types for the receiver position: * - * `path` | `t` - * ----------- | ------- - * `"0"` | ``Base`1`` - * `"0.0"` | ``C`1`` - * `"0.0.0"` | ``C`1`` - * `"0.0.0.1"` | `int` + * `path` | `t` + * ------------ | ------- + * `""` | ``Base`1`` + * `"T2"` | ``C`1`` + * `"T2.T1"` | ``C`1`` + * `"T2.T2.T2"` | `int` */ pragma[nomagic] Type inferAccessType(Access a, AccessPosition apos, TypePath path) { From e0ef24154ad70b8d8c73313355924735893226ba Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Fri, 21 Mar 2025 08:30:14 +0100 Subject: [PATCH 2/3] Rust: Small tweaks to doc comments based on PR feedback --- .../codeql/typeinference/internal/TypeInference.qll | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/shared/typeinference/codeql/typeinference/internal/TypeInference.qll b/shared/typeinference/codeql/typeinference/internal/TypeInference.qll index ee3c2adda017..8c4b789f014b 100644 --- a/shared/typeinference/codeql/typeinference/internal/TypeInference.qll +++ b/shared/typeinference/codeql/typeinference/internal/TypeInference.qll @@ -547,7 +547,7 @@ module Make1 Input1> { * Gets the type of the type argument at `path` in `a` that corresponds to * the type parameter `tp` in `target`, if any. * - * Note, that this predicate crucially does not depend on type inference, + * Note that this predicate crucially does not depend on type inference, * and hence can appear in negated position, e.g., as in * `directTypeMatch`. */ @@ -615,12 +615,12 @@ module Make1 Input1> { * class Sub : Mid> { } * * new Sub().ToString(); - * // ^^^^^^^^^^^^^^ `apos` + * // ^^^^^^^^^^^^^^ node at `apos` * // ^^^^^^^^^^^^^^^^^^^^^^^^^ `a` * ``` * - * where the method call is an access and `new Sub()` is an access - * position , which is the receiver of a method call, we have: + * where the method call is an access and `new Sub()` is at an + * access position, which is the receiver of a method call, we have: * * `baseMention` | `path` | `t` * ------------- | ------------ | --- @@ -648,7 +648,7 @@ module Make1 Input1> { /** * Holds if the type of `a` at `apos` has the base type `base`, and when - * viewed as an element of that type has at `path` the type `t`. + * viewed as an element of that type has the type `t` at `path`. */ pragma[nomagic] private predicate accessBaseType( From 7dc49da6b0370fea6b8c1a5b5b1887027543f98f Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Mon, 24 Mar 2025 11:38:15 +0100 Subject: [PATCH 3/3] Shared: Fix path in qldoc Co-authored-by: Anders Schack-Mulligen --- .../codeql/typeinference/internal/TypeInference.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared/typeinference/codeql/typeinference/internal/TypeInference.qll b/shared/typeinference/codeql/typeinference/internal/TypeInference.qll index 8c4b789f014b..dac4aee7324d 100644 --- a/shared/typeinference/codeql/typeinference/internal/TypeInference.qll +++ b/shared/typeinference/codeql/typeinference/internal/TypeInference.qll @@ -781,7 +781,7 @@ module Make1 Input1> { * `""` | ``Base`1`` * `"T2"` | ``C`1`` * `"T2.T1"` | ``C`1`` - * `"T2.T2.T2"` | `int` + * `"T2.T1.T1"` | `int` */ pragma[nomagic] Type inferAccessType(Access a, AccessPosition apos, TypePath path) {