From ae3373100914b71235fc87cb2d893e3b8e8d97e0 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Mon, 26 May 2025 14:45:31 +0200 Subject: [PATCH 1/5] Rust: Add `async` type inference tests --- .../test/library-tests/type-inference/main.rs | 41 +++++++++++++++++++ .../type-inference/type-inference.expected | 27 ++++++++++-- 2 files changed, 64 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 36d3f5a82ea8..2a0c28d43291 100644 --- a/rust/ql/test/library-tests/type-inference/main.rs +++ b/rust/ql/test/library-tests/type-inference/main.rs @@ -1630,6 +1630,46 @@ mod overloadable_operators { } } +mod async_ { + use std::future::Future; + + struct S1; + + impl S1 { + pub fn f(self) {} // S1f + } + + async fn f1() -> S1 { + S1 + } + + fn f2() -> impl Future { + async { + S1 + } + } + + struct S2; + + impl Future for S2 { + type Output = S1; + + fn poll(self: std::pin::Pin<&mut Self>, _cx: &mut std::task::Context<'_>) -> std::task::Poll { + std::task::Poll::Ready(S1) + } + } + + fn f3() -> impl Future { + S2 + } + + pub async fn f() { + f1().await.f(); // $ MISSING: method=S1f + f2().await.f(); // $ MISSING: method=S1f + f3().await.f(); // $ MISSING: method=S1f + } +} + fn main() { field_access::f(); method_impl::f(); @@ -1649,4 +1689,5 @@ fn main() { try_expressions::f(); builtins::f(); operators::f(); + async_::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 ff33ad89cb82..71bb5f85aeca 100644 --- a/rust/ql/test/library-tests/type-inference/type-inference.expected +++ b/rust/ql/test/library-tests/type-inference/type-inference.expected @@ -2374,8 +2374,27 @@ inferType | main.rs:1629:13:1629:20 | vec2_not | | main.rs:1278:5:1283:5 | Vec2 | | main.rs:1629:24:1629:26 | ! ... | | main.rs:1278:5:1283:5 | Vec2 | | main.rs:1629:25:1629:26 | v1 | | main.rs:1278:5:1283:5 | Vec2 | -| main.rs:1635:5:1635:20 | ...::f(...) | | main.rs:67:5:67:21 | Foo | -| main.rs:1636:5:1636:60 | ...::g(...) | | main.rs:67:5:67:21 | Foo | -| main.rs:1636:20:1636:38 | ...::Foo {...} | | main.rs:67:5:67:21 | Foo | -| main.rs:1636:41:1636:59 | ...::Foo {...} | | main.rs:67:5:67:21 | Foo | +| main.rs:1639:18:1639:21 | SelfParam | | main.rs:1636:5:1636:14 | S1 | +| main.rs:1642:25:1644:5 | { ... } | | main.rs:1636:5:1636:14 | S1 | +| main.rs:1643:9:1643:10 | S1 | | main.rs:1636:5:1636:14 | S1 | +| main.rs:1646:41:1650:5 | { ... } | | main.rs:1636:5:1636:14 | S1 | +| main.rs:1647:9:1649:9 | { ... } | | main.rs:1636:5:1636:14 | S1 | +| main.rs:1648:13:1648:14 | S1 | | main.rs:1636:5:1636:14 | S1 | +| main.rs:1657:17:1657:46 | SelfParam | | {EXTERNAL LOCATION} | Pin | +| main.rs:1657:17:1657:46 | SelfParam | Ptr | file://:0:0:0:0 | & | +| main.rs:1657:17:1657:46 | SelfParam | Ptr.&T | main.rs:1652:5:1652:14 | S2 | +| main.rs:1657:49:1657:51 | _cx | | file://:0:0:0:0 | & | +| main.rs:1657:49:1657:51 | _cx | &T | {EXTERNAL LOCATION} | Context | +| main.rs:1657:116:1659:9 | { ... } | | {EXTERNAL LOCATION} | Poll | +| main.rs:1657:116:1659:9 | { ... } | T | main.rs:1636:5:1636:14 | S1 | +| main.rs:1658:13:1658:38 | ...::Ready(...) | | {EXTERNAL LOCATION} | Poll | +| main.rs:1658:13:1658:38 | ...::Ready(...) | T | main.rs:1636:5:1636:14 | S1 | +| main.rs:1658:36:1658:37 | S1 | | main.rs:1636:5:1636:14 | S1 | +| main.rs:1662:41:1664:5 | { ... } | | main.rs:1652:5:1652:14 | S2 | +| main.rs:1663:9:1663:10 | S2 | | main.rs:1652:5:1652:14 | S2 | +| main.rs:1667:9:1667:12 | f1(...) | | main.rs:1636:5:1636:14 | S1 | +| main.rs:1675:5:1675:20 | ...::f(...) | | main.rs:67:5:67:21 | Foo | +| main.rs:1676:5:1676:60 | ...::g(...) | | main.rs:67:5:67:21 | Foo | +| main.rs:1676:20:1676:38 | ...::Foo {...} | | main.rs:67:5:67:21 | Foo | +| main.rs:1676:41:1676:59 | ...::Foo {...} | | main.rs:67:5:67:21 | Foo | testFailures From 767500f739c9f6d4509a05d2a21c5d7a024c956c Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Tue, 27 May 2025 11:34:30 +0200 Subject: [PATCH 2/5] Rust: Add type inference tests for `impl Trait` --- .../test/library-tests/type-inference/main.rs | 32 +++++++++++++++++++ .../type-inference/type-inference.expected | 18 ++++++++--- 2 files changed, 46 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 2a0c28d43291..e11af1a50e9e 100644 --- a/rust/ql/test/library-tests/type-inference/main.rs +++ b/rust/ql/test/library-tests/type-inference/main.rs @@ -1670,6 +1670,37 @@ mod async_ { } } + +mod impl_trait { + struct S1; + + trait Trait1 { + fn f1(&self) {} // Trait1f1 + } + + trait Trait2 { + fn f2(&self) {} // Trait2f2 + } + + impl Trait1 for S1 { + fn f1(&self) {} // S1f1 + } + + impl Trait2 for S1 { + fn f2(&self) {} // S1f2 + } + + fn f1() -> impl Trait1 + Trait2 { + S1 + } + + pub fn f() { + let x = f1(); + x.f1(); // $ MISSING: method=Trait1f1 + x.f2(); // $ MISSING: method=Trait2f2 + } +} + fn main() { field_access::f(); method_impl::f(); @@ -1690,4 +1721,5 @@ fn main() { builtins::f(); operators::f(); async_::f(); + impl_trait::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 71bb5f85aeca..d38a8c393735 100644 --- a/rust/ql/test/library-tests/type-inference/type-inference.expected +++ b/rust/ql/test/library-tests/type-inference/type-inference.expected @@ -2393,8 +2393,18 @@ inferType | main.rs:1662:41:1664:5 | { ... } | | main.rs:1652:5:1652:14 | S2 | | main.rs:1663:9:1663:10 | S2 | | main.rs:1652:5:1652:14 | S2 | | main.rs:1667:9:1667:12 | f1(...) | | main.rs:1636:5:1636:14 | S1 | -| main.rs:1675:5:1675:20 | ...::f(...) | | main.rs:67:5:67:21 | Foo | -| main.rs:1676:5:1676:60 | ...::g(...) | | main.rs:67:5:67:21 | Foo | -| main.rs:1676:20:1676:38 | ...::Foo {...} | | main.rs:67:5:67:21 | Foo | -| main.rs:1676:41:1676:59 | ...::Foo {...} | | main.rs:67:5:67:21 | Foo | +| main.rs:1678:15:1678:19 | SelfParam | | file://:0:0:0:0 | & | +| main.rs:1678:15:1678:19 | SelfParam | &T | main.rs:1677:5:1679:5 | Self [trait Trait1] | +| main.rs:1682:15:1682:19 | SelfParam | | file://:0:0:0:0 | & | +| main.rs:1682:15:1682:19 | SelfParam | &T | main.rs:1681:5:1683:5 | Self [trait Trait2] | +| main.rs:1686:15:1686:19 | SelfParam | | file://:0:0:0:0 | & | +| main.rs:1686:15:1686:19 | SelfParam | &T | main.rs:1675:5:1675:14 | S1 | +| main.rs:1690:15:1690:19 | SelfParam | | file://:0:0:0:0 | & | +| main.rs:1690:15:1690:19 | SelfParam | &T | main.rs:1675:5:1675:14 | S1 | +| main.rs:1693:37:1695:5 | { ... } | | main.rs:1675:5:1675:14 | S1 | +| main.rs:1694:9:1694:10 | S1 | | main.rs:1675:5:1675:14 | S1 | +| main.rs:1706:5:1706:20 | ...::f(...) | | main.rs:67:5:67:21 | Foo | +| main.rs:1707:5:1707:60 | ...::g(...) | | main.rs:67:5:67:21 | Foo | +| main.rs:1707:20:1707:38 | ...::Foo {...} | | main.rs:67:5:67:21 | Foo | +| main.rs:1707:41:1707:59 | ...::Foo {...} | | main.rs:67:5:67:21 | Foo | testFailures From d8c4cf30baf7ae60779680c0ce04ab3f44529382 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Mon, 26 May 2025 21:25:07 +0200 Subject: [PATCH 3/5] Rust: Type inference for `.await` expressions --- .../codeql/rust/frameworks/stdlib/Stdlib.qll | 16 +++++ rust/ql/lib/codeql/rust/internal/Type.qll | 56 ++++++++++++++- .../codeql/rust/internal/TypeInference.qll | 68 +++++++++++++++++-- .../lib/codeql/rust/internal/TypeMention.qll | 50 +++++++++++++- .../test/library-tests/type-inference/main.rs | 10 +-- .../type-inference/type-inference.expected | 43 +++++++++++- 6 files changed, 229 insertions(+), 14 deletions(-) diff --git a/rust/ql/lib/codeql/rust/frameworks/stdlib/Stdlib.qll b/rust/ql/lib/codeql/rust/frameworks/stdlib/Stdlib.qll index e7d9cac24e92..f8a65d9dcb9a 100644 --- a/rust/ql/lib/codeql/rust/frameworks/stdlib/Stdlib.qll +++ b/rust/ql/lib/codeql/rust/frameworks/stdlib/Stdlib.qll @@ -49,3 +49,19 @@ class ResultEnum extends Enum { /** Gets the `Err` variant. */ Variant getErr() { result = this.getVariant("Err") } } + +/** + * The [`Future` trait][1]. + * + * [1]: https://doc.rust-lang.org/std/future/trait.Future.html + */ +class FutureTrait extends Trait { + FutureTrait() { this.getCanonicalPath() = "core::future::future::Future" } + + /** Gets the `Output` associated type. */ + pragma[nomagic] + TypeAlias getOutputType() { + result = this.getAssocItemList().getAnAssocItem() and + result.getName().getText() = "Output" + } +} diff --git a/rust/ql/lib/codeql/rust/internal/Type.qll b/rust/ql/lib/codeql/rust/internal/Type.qll index db7938b3cf1b..7661b3ea279b 100644 --- a/rust/ql/lib/codeql/rust/internal/Type.qll +++ b/rust/ql/lib/codeql/rust/internal/Type.qll @@ -15,10 +15,14 @@ newtype TType = TTrait(Trait t) or TArrayType() or // todo: add size? TRefType() or // todo: add mut? + TImplTraitType(int bounds) { + bounds = any(ImplTraitTypeRepr impl).getTypeBoundList().getNumberOfBounds() + } or TTypeParamTypeParameter(TypeParam t) or TAssociatedTypeTypeParameter(TypeAlias t) { any(TraitItemNode trait).getAnAssocItem() = t } or TRefTypeParameter() or - TSelfTypeParameter(Trait t) + TSelfTypeParameter(Trait t) or + TImplTraitTypeParameter(ImplTraitType t, int i) { i in [0 .. t.getNumberOfBounds() - 1] } /** * A type without type arguments. @@ -115,6 +119,9 @@ class TraitType extends Type, TTrait { TraitType() { this = TTrait(trait) } + /** Gets the underlying trait. */ + Trait getTrait() { result = trait } + override StructField getStructField(string name) { none() } override TupleField getTupleField(int i) { none() } @@ -176,6 +183,33 @@ class RefType extends Type, TRefType { override Location getLocation() { result instanceof EmptyLocation } } +/** + * An [`impl Trait`][1] type. + * + * We represent `impl Trait` types as generic types with as many type parameters + * as there are bounds. + * + * [1] https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters + */ +class ImplTraitType extends Type, TImplTraitType { + private int bounds; + + ImplTraitType() { this = TImplTraitType(bounds) } + + /** Gets the number of bounds of this `impl Trait` type. */ + int getNumberOfBounds() { result = bounds } + + override StructField getStructField(string name) { none() } + + override TupleField getTupleField(int i) { none() } + + override TypeParameter getTypeParameter(int i) { result = TImplTraitTypeParameter(this, i) } + + override string toString() { result = "impl Trait ..." } + + override Location getLocation() { result instanceof EmptyLocation } +} + /** A type parameter. */ abstract class TypeParameter extends Type { override StructField getStructField(string name) { none() } @@ -281,6 +315,26 @@ class SelfTypeParameter extends TypeParameter, TSelfTypeParameter { override Location getLocation() { result = trait.getLocation() } } +/** + * An `impl Trait` type parameter. + */ +class ImplTraitTypeParameter extends TypeParameter, TImplTraitTypeParameter { + private ImplTraitType implTraitType; + private int i; + + ImplTraitTypeParameter() { this = TImplTraitTypeParameter(implTraitType, i) } + + /** Gets the `impl Trait` type that this parameter belongs to. */ + ImplTraitType getImplTraitType() { result = implTraitType } + + /** Gets the index of this type parameter. */ + int getIndex() { result = i } + + override string toString() { result = "impl Trait<" + i.toString() + ">" } + + override Location getLocation() { result instanceof EmptyLocation } +} + /** * A type abstraction. I.e., a place in the program where type variables are * introduced. diff --git a/rust/ql/lib/codeql/rust/internal/TypeInference.qll b/rust/ql/lib/codeql/rust/internal/TypeInference.qll index 8399bde8aa80..c030cca4433c 100644 --- a/rust/ql/lib/codeql/rust/internal/TypeInference.qll +++ b/rust/ql/lib/codeql/rust/internal/TypeInference.qll @@ -77,6 +77,16 @@ private module Input1 implements InputSig1 { apos.asMethodTypeArgumentPosition() = ppos.asTypeParam().getPosition() } + private int getImplTraitTypeParameterId(ImplTraitTypeParameter tp) { + tp = + rank[result](ImplTraitTypeParameter tp0, int bounds, int i | + bounds = tp0.getImplTraitType().getNumberOfBounds() and + i = tp0.getIndex() + | + tp0 order by bounds, i + ) + } + int getTypeParameterId(TypeParameter tp) { tp = rank[result](TypeParameter tp0, int kind, int id | @@ -90,6 +100,9 @@ private module Input1 implements InputSig1 { node = tp0.(AssociatedTypeTypeParameter).getTypeAlias() or node = tp0.(SelfTypeParameter).getTrait() ) + or + kind = 2 and + id = getImplTraitTypeParameterId(tp0) | tp0 order by kind, id ) @@ -228,7 +241,11 @@ private predicate typeEquality(AstNode n1, TypePath prefix1, AstNode n2, TypePat or n1 = n2.(ParenExpr).getExpr() or - n1 = n2.(BlockExpr).getStmtList().getTailExpr() + n2 = + any(BlockExpr be | + not be.isAsync() and + n1 = be.getStmtList().getTailExpr() + ) or n1 = n2.(IfExpr).getABranch() or @@ -1010,6 +1027,29 @@ private StructType inferLiteralType(LiteralExpr le) { ) } +pragma[nomagic] +private AssociatedTypeTypeParameter getFutureOutputTypeParameter() { + result.getTypeAlias() = any(FutureTrait ft).getOutputType() +} + +pragma[nomagic] +private Type inferAwaitExprType(AwaitExpr ae, TypePath path) { + exists(TypePath exprPath | result = inferType(ae.getExpr(), exprPath) | + exprPath + .isCons(TImplTraitTypeParameter(_, _), + any(TypePath path0 | path0.isCons(getFutureOutputTypeParameter(), path))) + or + path = exprPath and + not ( + exprPath = TypePath::singleton(TImplTraitTypeParameter(_, _)) and + result.(TraitType).getTrait() instanceof FutureTrait + ) and + not exprPath + .isCons(TImplTraitTypeParameter(_, _), + any(TypePath path0 | path0.isCons(getFutureOutputTypeParameter(), _))) + ) +} + private module MethodCall { /** An expression that calls a method. */ abstract private class MethodCallImpl extends Expr { @@ -1119,12 +1159,17 @@ private predicate methodCandidateTrait(Type type, Trait trait, string name, int } private module IsInstantiationOfInput implements IsInstantiationOfInputSig { + pragma[nomagic] + private predicate isMethodCall(MethodCall mc, Type rootType, string name, int arity) { + rootType = mc.getTypeAt(TypePath::nil()) and + name = mc.getMethodName() and + arity = mc.getArity() + } + pragma[nomagic] predicate potentialInstantiationOf(MethodCall mc, TypeAbstraction impl, TypeMention constraint) { exists(Type rootType, string name, int arity | - rootType = mc.getTypeAt(TypePath::nil()) and - name = mc.getMethodName() and - arity = mc.getArity() and + isMethodCall(mc, rootType, name, arity) and constraint = impl.(ImplTypeAbstraction).getSelfTy() | methodCandidateTrait(rootType, mc.getTrait(), name, arity, impl) @@ -1161,6 +1206,12 @@ private Function getMethodFromImpl(MethodCall mc) { ) } +bindingset[trait, name] +pragma[inline_late] +private Function getTraitMethod(TraitType trait, string name) { + result = getMethodSuccessor(trait.getTrait(), name) +} + /** * Gets a method that the method call `mc` resolves to based on type inference, * if any. @@ -1172,6 +1223,11 @@ private Function inferMethodCallTarget(MethodCall mc) { // The type of the receiver is a type parameter and the method comes from a // trait bound on the type parameter. result = getTypeParameterMethod(mc.getTypeAt(TypePath::nil()), mc.getMethodName()) + or + // The type of the receiver is an `impl Trait` type. + result = + getTraitMethod(mc.getTypeAt(TypePath::singleton(TImplTraitTypeParameter(_, _))), + mc.getMethodName()) } cached @@ -1347,6 +1403,8 @@ private module Cached { or result = inferLiteralType(n) and path.isEmpty() + or + result = inferAwaitExprType(n, path) } } @@ -1363,7 +1421,7 @@ private module Debug { exists(string filepath, int startline, int startcolumn, int endline, int endcolumn | result.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) and filepath.matches("%/main.rs") and - startline = 948 + startline = 1334 ) } diff --git a/rust/ql/lib/codeql/rust/internal/TypeMention.qll b/rust/ql/lib/codeql/rust/internal/TypeMention.qll index 7e947a35bc48..fab4c088b28c 100644 --- a/rust/ql/lib/codeql/rust/internal/TypeMention.qll +++ b/rust/ql/lib/codeql/rust/internal/TypeMention.qll @@ -15,7 +15,7 @@ abstract class TypeMention extends AstNode { /** Gets the sub mention at `path`. */ pragma[nomagic] - private TypeMention getMentionAt(TypePath path) { + TypeMention getMentionAt(TypePath path) { path.isEmpty() and result = this or @@ -150,6 +150,54 @@ class PathTypeReprMention extends TypeMention instanceof PathTypeRepr { not exists(resolved.(TypeAlias).getTypeRepr()) and result = super.resolveTypeAt(typePath) } + + pragma[nomagic] + private TypeAlias getResolvedTraitAlias(string name) { + exists(TraitItemNode trait | + trait = resolvePath(path) and + result = trait.getAnAssocItem() and + name = result.getName().getText() + ) + } + + pragma[nomagic] + private TypeRepr getAssocTypeArg(string name) { + exists(AssocTypeArg arg | + arg = path.getSegment().getGenericArgList().getAGenericArg() and + result = arg.getTypeRepr() and + name = arg.getIdentifier().getText() + ) + } + + /** Gets the type argument for the associated type `alias`, if any. */ + pragma[nomagic] + private TypeRepr getAnAssocTypeArgument(TypeAlias alias) { + exists(string name | + alias = this.getResolvedTraitAlias(name) and + result = this.getAssocTypeArg(name) + ) + } + + override TypeMention getMentionAt(TypePath tp) { + result = super.getMentionAt(tp) + or + exists(TypeAlias alias, AssociatedTypeTypeParameter attp, TypeMention arg, TypePath suffix | + arg = this.getAnAssocTypeArgument(alias) and + result = arg.getMentionAt(suffix) and + tp = TypePath::cons(attp, suffix) and + attp.getTypeAlias() = alias + ) + } +} + +class ImplTraitTypeReprMention extends TypeMention instanceof ImplTraitTypeRepr { + override TypeMention getTypeArgument(int i) { + result = super.getTypeBoundList().getBound(i).getTypeRepr() + } + + override ImplTraitType resolveType() { + result.getNumberOfBounds() = super.getTypeBoundList().getNumberOfBounds() + } } private TypeParameter pathGetTypeParameter(TypeAlias alias, int i) { diff --git a/rust/ql/test/library-tests/type-inference/main.rs b/rust/ql/test/library-tests/type-inference/main.rs index e11af1a50e9e..0508caf70927 100644 --- a/rust/ql/test/library-tests/type-inference/main.rs +++ b/rust/ql/test/library-tests/type-inference/main.rs @@ -1664,9 +1664,9 @@ mod async_ { } pub async fn f() { - f1().await.f(); // $ MISSING: method=S1f - f2().await.f(); // $ MISSING: method=S1f - f3().await.f(); // $ MISSING: method=S1f + f1().await.f(); // $ method=S1f + f2().await.f(); // $ method=S1f + f3().await.f(); // $ method=S1f } } @@ -1696,8 +1696,8 @@ mod impl_trait { pub fn f() { let x = f1(); - x.f1(); // $ MISSING: method=Trait1f1 - x.f2(); // $ MISSING: method=Trait2f2 + x.f1(); // $ method=Trait1f1 + x.f2(); // $ method=Trait2f2 } } 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 d38a8c393735..6cdfdea4975c 100644 --- a/rust/ql/test/library-tests/type-inference/type-inference.expected +++ b/rust/ql/test/library-tests/type-inference/type-inference.expected @@ -2377,8 +2377,12 @@ inferType | main.rs:1639:18:1639:21 | SelfParam | | main.rs:1636:5:1636:14 | S1 | | main.rs:1642:25:1644:5 | { ... } | | main.rs:1636:5:1636:14 | S1 | | main.rs:1643:9:1643:10 | S1 | | main.rs:1636:5:1636:14 | S1 | -| main.rs:1646:41:1650:5 | { ... } | | main.rs:1636:5:1636:14 | S1 | -| main.rs:1647:9:1649:9 | { ... } | | main.rs:1636:5:1636:14 | S1 | +| main.rs:1646:41:1650:5 | { ... } | | file://:0:0:0:0 | impl Trait ... | +| main.rs:1646:41:1650:5 | { ... } | impl Trait<0> | file:///RUSTUP_HOME/toolchain/lib/rustlib/src/rust/library/core/src/future/future.rs:7:1:105:1 | trait Future | +| main.rs:1646:41:1650:5 | { ... } | impl Trait<0>.Output | main.rs:1636:5:1636:14 | S1 | +| main.rs:1647:9:1649:9 | { ... } | | file://:0:0:0:0 | impl Trait ... | +| main.rs:1647:9:1649:9 | { ... } | impl Trait<0> | file:///RUSTUP_HOME/toolchain/lib/rustlib/src/rust/library/core/src/future/future.rs:7:1:105:1 | trait Future | +| main.rs:1647:9:1649:9 | { ... } | impl Trait<0>.Output | main.rs:1636:5:1636:14 | S1 | | main.rs:1648:13:1648:14 | S1 | | main.rs:1636:5:1636:14 | S1 | | main.rs:1657:17:1657:46 | SelfParam | | {EXTERNAL LOCATION} | Pin | | main.rs:1657:17:1657:46 | SelfParam | Ptr | file://:0:0:0:0 | & | @@ -2390,9 +2394,26 @@ inferType | main.rs:1658:13:1658:38 | ...::Ready(...) | | {EXTERNAL LOCATION} | Poll | | main.rs:1658:13:1658:38 | ...::Ready(...) | T | main.rs:1636:5:1636:14 | S1 | | main.rs:1658:36:1658:37 | S1 | | main.rs:1636:5:1636:14 | S1 | +| main.rs:1662:41:1664:5 | { ... } | | file://:0:0:0:0 | impl Trait ... | | main.rs:1662:41:1664:5 | { ... } | | main.rs:1652:5:1652:14 | S2 | +| main.rs:1662:41:1664:5 | { ... } | impl Trait<0> | file:///RUSTUP_HOME/toolchain/lib/rustlib/src/rust/library/core/src/future/future.rs:7:1:105:1 | trait Future | +| main.rs:1662:41:1664:5 | { ... } | impl Trait<0>.Output | main.rs:1636:5:1636:14 | S1 | +| main.rs:1663:9:1663:10 | S2 | | file://:0:0:0:0 | impl Trait ... | | main.rs:1663:9:1663:10 | S2 | | main.rs:1652:5:1652:14 | S2 | +| main.rs:1663:9:1663:10 | S2 | impl Trait<0> | file:///RUSTUP_HOME/toolchain/lib/rustlib/src/rust/library/core/src/future/future.rs:7:1:105:1 | trait Future | +| main.rs:1663:9:1663:10 | S2 | impl Trait<0>.Output | main.rs:1636:5:1636:14 | S1 | | main.rs:1667:9:1667:12 | f1(...) | | main.rs:1636:5:1636:14 | S1 | +| main.rs:1667:9:1667:18 | await ... | | main.rs:1636:5:1636:14 | S1 | +| main.rs:1668:9:1668:12 | f2(...) | | file://:0:0:0:0 | impl Trait ... | +| main.rs:1668:9:1668:12 | f2(...) | impl Trait<0> | file:///RUSTUP_HOME/toolchain/lib/rustlib/src/rust/library/core/src/future/future.rs:7:1:105:1 | trait Future | +| main.rs:1668:9:1668:12 | f2(...) | impl Trait<0>.Output | main.rs:1636:5:1636:14 | S1 | +| main.rs:1668:9:1668:18 | await ... | | file://:0:0:0:0 | impl Trait ... | +| main.rs:1668:9:1668:18 | await ... | | main.rs:1636:5:1636:14 | S1 | +| main.rs:1669:9:1669:12 | f3(...) | | file://:0:0:0:0 | impl Trait ... | +| main.rs:1669:9:1669:12 | f3(...) | impl Trait<0> | file:///RUSTUP_HOME/toolchain/lib/rustlib/src/rust/library/core/src/future/future.rs:7:1:105:1 | trait Future | +| main.rs:1669:9:1669:12 | f3(...) | impl Trait<0>.Output | main.rs:1636:5:1636:14 | S1 | +| main.rs:1669:9:1669:18 | await ... | | file://:0:0:0:0 | impl Trait ... | +| main.rs:1669:9:1669:18 | await ... | | main.rs:1636:5:1636:14 | S1 | | main.rs:1678:15:1678:19 | SelfParam | | file://:0:0:0:0 | & | | main.rs:1678:15:1678:19 | SelfParam | &T | main.rs:1677:5:1679:5 | Self [trait Trait1] | | main.rs:1682:15:1682:19 | SelfParam | | file://:0:0:0:0 | & | @@ -2401,8 +2422,26 @@ inferType | main.rs:1686:15:1686:19 | SelfParam | &T | main.rs:1675:5:1675:14 | S1 | | main.rs:1690:15:1690:19 | SelfParam | | file://:0:0:0:0 | & | | main.rs:1690:15:1690:19 | SelfParam | &T | main.rs:1675:5:1675:14 | S1 | +| main.rs:1693:37:1695:5 | { ... } | | file://:0:0:0:0 | impl Trait ... | | main.rs:1693:37:1695:5 | { ... } | | main.rs:1675:5:1675:14 | S1 | +| main.rs:1693:37:1695:5 | { ... } | impl Trait<0> | main.rs:1677:5:1679:5 | trait Trait1 | +| main.rs:1693:37:1695:5 | { ... } | impl Trait<1> | main.rs:1681:5:1683:5 | trait Trait2 | +| main.rs:1694:9:1694:10 | S1 | | file://:0:0:0:0 | impl Trait ... | | main.rs:1694:9:1694:10 | S1 | | main.rs:1675:5:1675:14 | S1 | +| main.rs:1694:9:1694:10 | S1 | impl Trait<0> | main.rs:1677:5:1679:5 | trait Trait1 | +| main.rs:1694:9:1694:10 | S1 | impl Trait<1> | main.rs:1681:5:1683:5 | trait Trait2 | +| main.rs:1698:13:1698:13 | x | | file://:0:0:0:0 | impl Trait ... | +| main.rs:1698:13:1698:13 | x | impl Trait<0> | main.rs:1677:5:1679:5 | trait Trait1 | +| main.rs:1698:13:1698:13 | x | impl Trait<1> | main.rs:1681:5:1683:5 | trait Trait2 | +| main.rs:1698:17:1698:20 | f1(...) | | file://:0:0:0:0 | impl Trait ... | +| main.rs:1698:17:1698:20 | f1(...) | impl Trait<0> | main.rs:1677:5:1679:5 | trait Trait1 | +| main.rs:1698:17:1698:20 | f1(...) | impl Trait<1> | main.rs:1681:5:1683:5 | trait Trait2 | +| main.rs:1699:9:1699:9 | x | | file://:0:0:0:0 | impl Trait ... | +| main.rs:1699:9:1699:9 | x | impl Trait<0> | main.rs:1677:5:1679:5 | trait Trait1 | +| main.rs:1699:9:1699:9 | x | impl Trait<1> | main.rs:1681:5:1683:5 | trait Trait2 | +| main.rs:1700:9:1700:9 | x | | file://:0:0:0:0 | impl Trait ... | +| main.rs:1700:9:1700:9 | x | impl Trait<0> | main.rs:1677:5:1679:5 | trait Trait1 | +| main.rs:1700:9:1700:9 | x | impl Trait<1> | main.rs:1681:5:1683:5 | trait Trait2 | | main.rs:1706:5:1706:20 | ...::f(...) | | main.rs:67:5:67:21 | Foo | | main.rs:1707:5:1707:60 | ...::g(...) | | main.rs:67:5:67:21 | Foo | | main.rs:1707:20:1707:38 | ...::Foo {...} | | main.rs:67:5:67:21 | Foo | From ad4aae2cf8a9c0c2641dc60cc430529712cf42a7 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Mon, 2 Jun 2025 10:14:50 +0200 Subject: [PATCH 4/5] Rust: Add more type inference tests --- .../test/library-tests/type-inference/main.rs | 33 +++++ .../type-inference/type-inference.expected | 128 ++++++++++++------ 2 files changed, 123 insertions(+), 38 deletions(-) diff --git a/rust/ql/test/library-tests/type-inference/main.rs b/rust/ql/test/library-tests/type-inference/main.rs index 0508caf70927..3ea87394cf29 100644 --- a/rust/ql/test/library-tests/type-inference/main.rs +++ b/rust/ql/test/library-tests/type-inference/main.rs @@ -1667,12 +1667,18 @@ mod async_ { f1().await.f(); // $ method=S1f f2().await.f(); // $ method=S1f f3().await.f(); // $ method=S1f + S2.await.f(); // $ MISSING: method=S1f + let b = async { + S1 + }; + b.await.f(); // $ MISSING: method=S1f } } mod impl_trait { struct S1; + struct S2; trait Trait1 { fn f1(&self) {} // Trait1f1 @@ -1694,10 +1700,37 @@ mod impl_trait { S1 } + trait MyTrait { + fn get_a(&self) -> A; // MyTrait::get_a + } + + impl MyTrait for S1 { + fn get_a(&self) -> S2 { + S2 + } + } + + fn get_a_my_trait() -> impl MyTrait { + S1 + } + + fn uses_my_trait1>(t: B) -> A { + t.get_a() // $ method=MyTrait::get_a + } + + fn uses_my_trait2(t: impl MyTrait) -> A { + t.get_a() // $ method=MyTrait::get_a + } + pub fn f() { let x = f1(); x.f1(); // $ method=Trait1f1 x.f2(); // $ method=Trait2f2 + let a = get_a_my_trait(); + let b = uses_my_trait1(a); // $ MISSING: type=b:S2 + let a = get_a_my_trait(); + let c = uses_my_trait2(a); // $ type=c:S2 + let d = uses_my_trait2(S1); // $ MISSING: type=d:S2 } } 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 6cdfdea4975c..e561f8579d05 100644 --- a/rust/ql/test/library-tests/type-inference/type-inference.expected +++ b/rust/ql/test/library-tests/type-inference/type-inference.expected @@ -2378,10 +2378,10 @@ inferType | main.rs:1642:25:1644:5 | { ... } | | main.rs:1636:5:1636:14 | S1 | | main.rs:1643:9:1643:10 | S1 | | main.rs:1636:5:1636:14 | S1 | | main.rs:1646:41:1650:5 | { ... } | | file://:0:0:0:0 | impl Trait ... | -| main.rs:1646:41:1650:5 | { ... } | impl Trait<0> | file:///RUSTUP_HOME/toolchain/lib/rustlib/src/rust/library/core/src/future/future.rs:7:1:105:1 | trait Future | +| main.rs:1646:41:1650:5 | { ... } | impl Trait<0> | {EXTERNAL LOCATION} | trait Future | | main.rs:1646:41:1650:5 | { ... } | impl Trait<0>.Output | main.rs:1636:5:1636:14 | S1 | | main.rs:1647:9:1649:9 | { ... } | | file://:0:0:0:0 | impl Trait ... | -| main.rs:1647:9:1649:9 | { ... } | impl Trait<0> | file:///RUSTUP_HOME/toolchain/lib/rustlib/src/rust/library/core/src/future/future.rs:7:1:105:1 | trait Future | +| main.rs:1647:9:1649:9 | { ... } | impl Trait<0> | {EXTERNAL LOCATION} | trait Future | | main.rs:1647:9:1649:9 | { ... } | impl Trait<0>.Output | main.rs:1636:5:1636:14 | S1 | | main.rs:1648:13:1648:14 | S1 | | main.rs:1636:5:1636:14 | S1 | | main.rs:1657:17:1657:46 | SelfParam | | {EXTERNAL LOCATION} | Pin | @@ -2396,54 +2396,106 @@ inferType | main.rs:1658:36:1658:37 | S1 | | main.rs:1636:5:1636:14 | S1 | | main.rs:1662:41:1664:5 | { ... } | | file://:0:0:0:0 | impl Trait ... | | main.rs:1662:41:1664:5 | { ... } | | main.rs:1652:5:1652:14 | S2 | -| main.rs:1662:41:1664:5 | { ... } | impl Trait<0> | file:///RUSTUP_HOME/toolchain/lib/rustlib/src/rust/library/core/src/future/future.rs:7:1:105:1 | trait Future | +| main.rs:1662:41:1664:5 | { ... } | impl Trait<0> | {EXTERNAL LOCATION} | trait Future | | main.rs:1662:41:1664:5 | { ... } | impl Trait<0>.Output | main.rs:1636:5:1636:14 | S1 | | main.rs:1663:9:1663:10 | S2 | | file://:0:0:0:0 | impl Trait ... | | main.rs:1663:9:1663:10 | S2 | | main.rs:1652:5:1652:14 | S2 | -| main.rs:1663:9:1663:10 | S2 | impl Trait<0> | file:///RUSTUP_HOME/toolchain/lib/rustlib/src/rust/library/core/src/future/future.rs:7:1:105:1 | trait Future | +| main.rs:1663:9:1663:10 | S2 | impl Trait<0> | {EXTERNAL LOCATION} | trait Future | | main.rs:1663:9:1663:10 | S2 | impl Trait<0>.Output | main.rs:1636:5:1636:14 | S1 | | main.rs:1667:9:1667:12 | f1(...) | | main.rs:1636:5:1636:14 | S1 | | main.rs:1667:9:1667:18 | await ... | | main.rs:1636:5:1636:14 | S1 | | main.rs:1668:9:1668:12 | f2(...) | | file://:0:0:0:0 | impl Trait ... | -| main.rs:1668:9:1668:12 | f2(...) | impl Trait<0> | file:///RUSTUP_HOME/toolchain/lib/rustlib/src/rust/library/core/src/future/future.rs:7:1:105:1 | trait Future | +| main.rs:1668:9:1668:12 | f2(...) | impl Trait<0> | {EXTERNAL LOCATION} | trait Future | | main.rs:1668:9:1668:12 | f2(...) | impl Trait<0>.Output | main.rs:1636:5:1636:14 | S1 | | main.rs:1668:9:1668:18 | await ... | | file://:0:0:0:0 | impl Trait ... | | main.rs:1668:9:1668:18 | await ... | | main.rs:1636:5:1636:14 | S1 | | main.rs:1669:9:1669:12 | f3(...) | | file://:0:0:0:0 | impl Trait ... | -| main.rs:1669:9:1669:12 | f3(...) | impl Trait<0> | file:///RUSTUP_HOME/toolchain/lib/rustlib/src/rust/library/core/src/future/future.rs:7:1:105:1 | trait Future | +| main.rs:1669:9:1669:12 | f3(...) | impl Trait<0> | {EXTERNAL LOCATION} | trait Future | | main.rs:1669:9:1669:12 | f3(...) | impl Trait<0>.Output | main.rs:1636:5:1636:14 | S1 | | main.rs:1669:9:1669:18 | await ... | | file://:0:0:0:0 | impl Trait ... | | main.rs:1669:9:1669:18 | await ... | | main.rs:1636:5:1636:14 | S1 | -| main.rs:1678:15:1678:19 | SelfParam | | file://:0:0:0:0 | & | -| main.rs:1678:15:1678:19 | SelfParam | &T | main.rs:1677:5:1679:5 | Self [trait Trait1] | -| main.rs:1682:15:1682:19 | SelfParam | | file://:0:0:0:0 | & | -| main.rs:1682:15:1682:19 | SelfParam | &T | main.rs:1681:5:1683:5 | Self [trait Trait2] | -| main.rs:1686:15:1686:19 | SelfParam | | file://:0:0:0:0 | & | -| main.rs:1686:15:1686:19 | SelfParam | &T | main.rs:1675:5:1675:14 | S1 | -| main.rs:1690:15:1690:19 | SelfParam | | file://:0:0:0:0 | & | -| main.rs:1690:15:1690:19 | SelfParam | &T | main.rs:1675:5:1675:14 | S1 | -| main.rs:1693:37:1695:5 | { ... } | | file://:0:0:0:0 | impl Trait ... | -| main.rs:1693:37:1695:5 | { ... } | | main.rs:1675:5:1675:14 | S1 | -| main.rs:1693:37:1695:5 | { ... } | impl Trait<0> | main.rs:1677:5:1679:5 | trait Trait1 | -| main.rs:1693:37:1695:5 | { ... } | impl Trait<1> | main.rs:1681:5:1683:5 | trait Trait2 | -| main.rs:1694:9:1694:10 | S1 | | file://:0:0:0:0 | impl Trait ... | -| main.rs:1694:9:1694:10 | S1 | | main.rs:1675:5:1675:14 | S1 | -| main.rs:1694:9:1694:10 | S1 | impl Trait<0> | main.rs:1677:5:1679:5 | trait Trait1 | -| main.rs:1694:9:1694:10 | S1 | impl Trait<1> | main.rs:1681:5:1683:5 | trait Trait2 | -| main.rs:1698:13:1698:13 | x | | file://:0:0:0:0 | impl Trait ... | -| main.rs:1698:13:1698:13 | x | impl Trait<0> | main.rs:1677:5:1679:5 | trait Trait1 | -| main.rs:1698:13:1698:13 | x | impl Trait<1> | main.rs:1681:5:1683:5 | trait Trait2 | -| main.rs:1698:17:1698:20 | f1(...) | | file://:0:0:0:0 | impl Trait ... | -| main.rs:1698:17:1698:20 | f1(...) | impl Trait<0> | main.rs:1677:5:1679:5 | trait Trait1 | -| main.rs:1698:17:1698:20 | f1(...) | impl Trait<1> | main.rs:1681:5:1683:5 | trait Trait2 | -| main.rs:1699:9:1699:9 | x | | file://:0:0:0:0 | impl Trait ... | -| main.rs:1699:9:1699:9 | x | impl Trait<0> | main.rs:1677:5:1679:5 | trait Trait1 | -| main.rs:1699:9:1699:9 | x | impl Trait<1> | main.rs:1681:5:1683:5 | trait Trait2 | -| main.rs:1700:9:1700:9 | x | | file://:0:0:0:0 | impl Trait ... | -| main.rs:1700:9:1700:9 | x | impl Trait<0> | main.rs:1677:5:1679:5 | trait Trait1 | -| main.rs:1700:9:1700:9 | x | impl Trait<1> | main.rs:1681:5:1683:5 | trait Trait2 | -| main.rs:1706:5:1706:20 | ...::f(...) | | main.rs:67:5:67:21 | Foo | -| main.rs:1707:5:1707:60 | ...::g(...) | | main.rs:67:5:67:21 | Foo | -| main.rs:1707:20:1707:38 | ...::Foo {...} | | main.rs:67:5:67:21 | Foo | -| main.rs:1707:41:1707:59 | ...::Foo {...} | | main.rs:67:5:67:21 | Foo | +| main.rs:1670:9:1670:10 | S2 | | main.rs:1652:5:1652:14 | S2 | +| main.rs:1670:9:1670:16 | await S2 | | main.rs:1652:5:1652:14 | S2 | +| main.rs:1672:13:1672:14 | S1 | | main.rs:1636:5:1636:14 | S1 | +| main.rs:1684:15:1684:19 | SelfParam | | file://:0:0:0:0 | & | +| main.rs:1684:15:1684:19 | SelfParam | &T | main.rs:1683:5:1685:5 | Self [trait Trait1] | +| main.rs:1688:15:1688:19 | SelfParam | | file://:0:0:0:0 | & | +| main.rs:1688:15:1688:19 | SelfParam | &T | main.rs:1687:5:1689:5 | Self [trait Trait2] | +| main.rs:1692:15:1692:19 | SelfParam | | file://:0:0:0:0 | & | +| main.rs:1692:15:1692:19 | SelfParam | &T | main.rs:1680:5:1680:14 | S1 | +| main.rs:1696:15:1696:19 | SelfParam | | file://:0:0:0:0 | & | +| main.rs:1696:15:1696:19 | SelfParam | &T | main.rs:1680:5:1680:14 | S1 | +| main.rs:1699:37:1701:5 | { ... } | | file://:0:0:0:0 | impl Trait ... | +| main.rs:1699:37:1701:5 | { ... } | | main.rs:1680:5:1680:14 | S1 | +| main.rs:1699:37:1701:5 | { ... } | impl Trait<0> | main.rs:1683:5:1685:5 | trait Trait1 | +| main.rs:1699:37:1701:5 | { ... } | impl Trait<1> | main.rs:1687:5:1689:5 | trait Trait2 | +| main.rs:1700:9:1700:10 | S1 | | file://:0:0:0:0 | impl Trait ... | +| main.rs:1700:9:1700:10 | S1 | | main.rs:1680:5:1680:14 | S1 | +| main.rs:1700:9:1700:10 | S1 | impl Trait<0> | main.rs:1683:5:1685:5 | trait Trait1 | +| main.rs:1700:9:1700:10 | S1 | impl Trait<1> | main.rs:1687:5:1689:5 | trait Trait2 | +| main.rs:1704:18:1704:22 | SelfParam | | file://:0:0:0:0 | & | +| main.rs:1704:18:1704:22 | SelfParam | &T | main.rs:1703:5:1705:5 | Self [trait MyTrait] | +| main.rs:1708:18:1708:22 | SelfParam | | file://:0:0:0:0 | & | +| main.rs:1708:18:1708:22 | SelfParam | &T | main.rs:1680:5:1680:14 | S1 | +| main.rs:1708:31:1710:9 | { ... } | | main.rs:1681:5:1681:14 | S2 | +| main.rs:1709:13:1709:14 | S2 | | main.rs:1681:5:1681:14 | S2 | +| main.rs:1713:45:1715:5 | { ... } | | file://:0:0:0:0 | impl Trait ... | +| main.rs:1713:45:1715:5 | { ... } | | main.rs:1680:5:1680:14 | S1 | +| main.rs:1713:45:1715:5 | { ... } | impl Trait<0> | main.rs:1703:5:1705:5 | trait MyTrait | +| main.rs:1713:45:1715:5 | { ... } | impl Trait<0>.A | main.rs:1681:5:1681:14 | S2 | +| main.rs:1714:9:1714:10 | S1 | | file://:0:0:0:0 | impl Trait ... | +| main.rs:1714:9:1714:10 | S1 | | main.rs:1680:5:1680:14 | S1 | +| main.rs:1714:9:1714:10 | S1 | impl Trait<0> | main.rs:1703:5:1705:5 | trait MyTrait | +| main.rs:1714:9:1714:10 | S1 | impl Trait<0>.A | main.rs:1681:5:1681:14 | S2 | +| main.rs:1717:41:1717:41 | t | | main.rs:1717:26:1717:38 | B | +| main.rs:1717:52:1719:5 | { ... } | | main.rs:1717:23:1717:23 | A | +| main.rs:1718:9:1718:9 | t | | main.rs:1717:26:1717:38 | B | +| main.rs:1718:9:1718:17 | t.get_a() | | main.rs:1717:23:1717:23 | A | +| main.rs:1721:26:1721:26 | t | | file://:0:0:0:0 | impl Trait ... | +| main.rs:1721:26:1721:26 | t | impl Trait<0> | main.rs:1703:5:1705:5 | trait MyTrait | +| main.rs:1721:26:1721:26 | t | impl Trait<0>.A | main.rs:1721:23:1721:23 | A | +| main.rs:1721:51:1723:5 | { ... } | | main.rs:1721:23:1721:23 | A | +| main.rs:1722:9:1722:9 | t | | file://:0:0:0:0 | impl Trait ... | +| main.rs:1722:9:1722:9 | t | impl Trait<0> | main.rs:1703:5:1705:5 | trait MyTrait | +| main.rs:1722:9:1722:9 | t | impl Trait<0>.A | main.rs:1721:23:1721:23 | A | +| main.rs:1722:9:1722:17 | t.get_a() | | main.rs:1721:23:1721:23 | A | +| main.rs:1726:13:1726:13 | x | | file://:0:0:0:0 | impl Trait ... | +| main.rs:1726:13:1726:13 | x | impl Trait<0> | main.rs:1683:5:1685:5 | trait Trait1 | +| main.rs:1726:13:1726:13 | x | impl Trait<1> | main.rs:1687:5:1689:5 | trait Trait2 | +| main.rs:1726:17:1726:20 | f1(...) | | file://:0:0:0:0 | impl Trait ... | +| main.rs:1726:17:1726:20 | f1(...) | impl Trait<0> | main.rs:1683:5:1685:5 | trait Trait1 | +| main.rs:1726:17:1726:20 | f1(...) | impl Trait<1> | main.rs:1687:5:1689:5 | trait Trait2 | +| main.rs:1727:9:1727:9 | x | | file://:0:0:0:0 | impl Trait ... | +| main.rs:1727:9:1727:9 | x | impl Trait<0> | main.rs:1683:5:1685:5 | trait Trait1 | +| main.rs:1727:9:1727:9 | x | impl Trait<1> | main.rs:1687:5:1689:5 | trait Trait2 | +| main.rs:1728:9:1728:9 | x | | file://:0:0:0:0 | impl Trait ... | +| main.rs:1728:9:1728:9 | x | impl Trait<0> | main.rs:1683:5:1685:5 | trait Trait1 | +| main.rs:1728:9:1728:9 | x | impl Trait<1> | main.rs:1687:5:1689:5 | trait Trait2 | +| main.rs:1729:13:1729:13 | a | | file://:0:0:0:0 | impl Trait ... | +| main.rs:1729:13:1729:13 | a | impl Trait<0> | main.rs:1703:5:1705:5 | trait MyTrait | +| main.rs:1729:13:1729:13 | a | impl Trait<0>.A | main.rs:1681:5:1681:14 | S2 | +| main.rs:1729:17:1729:32 | get_a_my_trait(...) | | file://:0:0:0:0 | impl Trait ... | +| main.rs:1729:17:1729:32 | get_a_my_trait(...) | impl Trait<0> | main.rs:1703:5:1705:5 | trait MyTrait | +| main.rs:1729:17:1729:32 | get_a_my_trait(...) | impl Trait<0>.A | main.rs:1681:5:1681:14 | S2 | +| main.rs:1730:32:1730:32 | a | | file://:0:0:0:0 | impl Trait ... | +| main.rs:1730:32:1730:32 | a | impl Trait<0> | main.rs:1703:5:1705:5 | trait MyTrait | +| main.rs:1730:32:1730:32 | a | impl Trait<0>.A | main.rs:1681:5:1681:14 | S2 | +| main.rs:1731:13:1731:13 | a | | file://:0:0:0:0 | impl Trait ... | +| main.rs:1731:13:1731:13 | a | impl Trait<0> | main.rs:1703:5:1705:5 | trait MyTrait | +| main.rs:1731:13:1731:13 | a | impl Trait<0>.A | main.rs:1681:5:1681:14 | S2 | +| main.rs:1731:17:1731:32 | get_a_my_trait(...) | | file://:0:0:0:0 | impl Trait ... | +| main.rs:1731:17:1731:32 | get_a_my_trait(...) | impl Trait<0> | main.rs:1703:5:1705:5 | trait MyTrait | +| main.rs:1731:17:1731:32 | get_a_my_trait(...) | impl Trait<0>.A | main.rs:1681:5:1681:14 | S2 | +| main.rs:1732:13:1732:13 | c | | main.rs:1681:5:1681:14 | S2 | +| main.rs:1732:17:1732:33 | uses_my_trait2(...) | | main.rs:1681:5:1681:14 | S2 | +| main.rs:1732:32:1732:32 | a | | file://:0:0:0:0 | impl Trait ... | +| main.rs:1732:32:1732:32 | a | impl Trait<0> | main.rs:1703:5:1705:5 | trait MyTrait | +| main.rs:1732:32:1732:32 | a | impl Trait<0>.A | main.rs:1681:5:1681:14 | S2 | +| main.rs:1733:32:1733:33 | S1 | | file://:0:0:0:0 | impl Trait ... | +| main.rs:1733:32:1733:33 | S1 | | main.rs:1680:5:1680:14 | S1 | +| main.rs:1733:32:1733:33 | S1 | impl Trait<0> | main.rs:1703:5:1705:5 | trait MyTrait | +| main.rs:1739:5:1739:20 | ...::f(...) | | main.rs:67:5:67:21 | Foo | +| main.rs:1740:5:1740:60 | ...::g(...) | | main.rs:67:5:67:21 | Foo | +| main.rs:1740:20:1740:38 | ...::Foo {...} | | main.rs:67:5:67:21 | Foo | +| main.rs:1740:41:1740:59 | ...::Foo {...} | | main.rs:67:5:67:21 | Foo | testFailures From 2ebb619a9982c6488cbec0a9eaa23021337890c4 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Mon, 2 Jun 2025 12:58:51 +0200 Subject: [PATCH 5/5] Rust: Reimplement type inference for impl Traits and await expressions --- .../codeql/rust/internal/PathResolution.qll | 53 ++++- rust/ql/lib/codeql/rust/internal/Type.qll | 88 +++++--- .../codeql/rust/internal/TypeInference.qll | 198 ++++++++++++++---- .../lib/codeql/rust/internal/TypeMention.qll | 8 +- .../test/library-tests/type-inference/main.rs | 8 +- .../type-inference/type-inference.expected | 113 ++++------ .../PathResolutionConsistency.expected | 8 + rust/tools/builtins/await.rs | 7 + .../typeinference/internal/TypeInference.qll | 6 +- 9 files changed, 327 insertions(+), 162 deletions(-) create mode 100644 rust/tools/builtins/await.rs diff --git a/rust/ql/lib/codeql/rust/internal/PathResolution.qll b/rust/ql/lib/codeql/rust/internal/PathResolution.qll index d23679ee81be..3bb33669f056 100644 --- a/rust/ql/lib/codeql/rust/internal/PathResolution.qll +++ b/rust/ql/lib/codeql/rust/internal/PathResolution.qll @@ -5,6 +5,7 @@ private import rust private import codeql.rust.elements.internal.generated.ParentChild private import codeql.rust.internal.CachedStages +private import codeql.rust.frameworks.stdlib.Bultins as Builtins private newtype TNamespace = TTypeNamespace() or @@ -165,6 +166,8 @@ abstract class ItemNode extends Locatable { or // type parameters have access to the associated items of its bounds result = this.(TypeParamItemNode).resolveABound().getASuccessorRec(name).(AssocItemNode) + or + result = this.(ImplTraitTypeReprItemNode).resolveABound().getASuccessorRec(name).(AssocItemNode) } /** @@ -618,6 +621,28 @@ class ImplItemNode extends ImplOrTraitItemNode instanceof Impl { } } +private class ImplTraitTypeReprItemNode extends ItemNode instanceof ImplTraitTypeRepr { + pragma[nomagic] + Path getABoundPath() { + result = super.getTypeBoundList().getABound().getTypeRepr().(PathTypeRepr).getPath() + } + + pragma[nomagic] + ItemNode resolveABound() { result = resolvePathFull(this.getABoundPath()) } + + override string getName() { result = "(impl trait)" } + + override Namespace getNamespace() { result.isType() } + + override Visibility getVisibility() { none() } + + override TypeParam getTypeParam(int i) { none() } + + override predicate hasCanonicalPath(Crate c) { none() } + + override string getCanonicalPath(Crate c) { none() } +} + private class MacroCallItemNode extends AssocItemNode instanceof MacroCall { override string getName() { result = "(macro call)" } @@ -1062,14 +1087,21 @@ private predicate crateDefEdge(CrateItemNode c, string name, ItemNode i) { not i instanceof Crate } +private class BuiltinSourceFile extends SourceFileItemNode { + BuiltinSourceFile() { this.getFile().getParentContainer() instanceof Builtins::BuiltinsFolder } +} + /** * Holds if `m` depends on crate `dep` named `name`. */ +pragma[nomagic] private predicate crateDependencyEdge(ModuleLikeNode m, string name, CrateItemNode dep) { - exists(CrateItemNode c | - dep = c.(Crate).getDependency(name) and - m = c.getASourceFile() - ) + exists(CrateItemNode c | dep = c.(Crate).getDependency(name) | m = c.getASourceFile()) + or + // Give builtin files, such as `await.rs`, access to `std` + m instanceof BuiltinSourceFile and + dep.getName() = name and + name = "std" } private predicate useTreeDeclares(UseTree tree, string name) { @@ -1414,9 +1446,14 @@ private predicate useImportEdge(Use use, string name, ItemNode item) { * [1]: https://doc.rust-lang.org/core/prelude/index.html * [2]: https://doc.rust-lang.org/std/prelude/index.html */ +pragma[nomagic] private predicate preludeEdge(SourceFile f, string name, ItemNode i) { exists(Crate stdOrCore, ModuleLikeNode mod, ModuleItemNode prelude, ModuleItemNode rust | - f = any(Crate c0 | stdOrCore = c0.getDependency(_) or stdOrCore = c0).getASourceFile() and + f = any(Crate c0 | stdOrCore = c0.getDependency(_) or stdOrCore = c0).getASourceFile() + or + // Give builtin files, such as `await.rs`, access to the prelude + f instanceof BuiltinSourceFile + | stdOrCore.getName() = ["std", "core"] and mod = stdOrCore.getSourceFile() and prelude = mod.getASuccessorRec("prelude") and @@ -1426,12 +1463,10 @@ private predicate preludeEdge(SourceFile f, string name, ItemNode i) { ) } -private import codeql.rust.frameworks.stdlib.Bultins as Builtins - pragma[nomagic] private predicate builtin(string name, ItemNode i) { - exists(SourceFileItemNode builtins | - builtins.getFile().getParentContainer() instanceof Builtins::BuiltinsFolder and + exists(BuiltinSourceFile builtins | + builtins.getFile().getBaseName() = "types.rs" and i = builtins.getASuccessorRec(name) ) } diff --git a/rust/ql/lib/codeql/rust/internal/Type.qll b/rust/ql/lib/codeql/rust/internal/Type.qll index 7661b3ea279b..a751fd0d1a0e 100644 --- a/rust/ql/lib/codeql/rust/internal/Type.qll +++ b/rust/ql/lib/codeql/rust/internal/Type.qll @@ -15,14 +15,11 @@ newtype TType = TTrait(Trait t) or TArrayType() or // todo: add size? TRefType() or // todo: add mut? - TImplTraitType(int bounds) { - bounds = any(ImplTraitTypeRepr impl).getTypeBoundList().getNumberOfBounds() - } or + TImplTraitType(ImplTraitTypeRepr impl) or TTypeParamTypeParameter(TypeParam t) or TAssociatedTypeTypeParameter(TypeAlias t) { any(TraitItemNode trait).getAnAssocItem() = t } or TRefTypeParameter() or - TSelfTypeParameter(Trait t) or - TImplTraitTypeParameter(ImplTraitType t, int i) { i in [0 .. t.getNumberOfBounds() - 1] } + TSelfTypeParameter(Trait t) /** * A type without type arguments. @@ -184,30 +181,50 @@ class RefType extends Type, TRefType { } /** - * An [`impl Trait`][1] type. + * An [impl Trait][1] type. * - * We represent `impl Trait` types as generic types with as many type parameters - * as there are bounds. + * Each syntactic `impl Trait` type gives rise to its own type, even if + * two `impl Trait` types have the same bounds. * - * [1] https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters + * [1]: https://doc.rust-lang.org/reference/types/impl-trait.html */ class ImplTraitType extends Type, TImplTraitType { - private int bounds; + ImplTraitTypeRepr impl; - ImplTraitType() { this = TImplTraitType(bounds) } + ImplTraitType() { this = TImplTraitType(impl) } - /** Gets the number of bounds of this `impl Trait` type. */ - int getNumberOfBounds() { result = bounds } + /** Gets the underlying AST node. */ + ImplTraitTypeRepr getImplTraitTypeRepr() { result = impl } + + /** Gets the function that this `impl Trait` belongs to. */ + abstract Function getFunction(); override StructField getStructField(string name) { none() } override TupleField getTupleField(int i) { none() } - override TypeParameter getTypeParameter(int i) { result = TImplTraitTypeParameter(this, i) } + override TypeParameter getTypeParameter(int i) { none() } - override string toString() { result = "impl Trait ..." } + override string toString() { result = impl.toString() } - override Location getLocation() { result instanceof EmptyLocation } + override Location getLocation() { result = impl.getLocation() } +} + +/** + * An [impl Trait in return position][1] type, for example: + * + * ```rust + * fn foo() -> impl Trait + * ``` + * + * [1]: https://doc.rust-lang.org/reference/types/impl-trait.html#r-type.impl-trait.return + */ +class ImplTraitReturnType extends ImplTraitType { + private Function function; + + ImplTraitReturnType() { impl = function.getRetType().getTypeRepr() } + + override Function getFunction() { result = function } } /** A type parameter. */ @@ -219,7 +236,7 @@ abstract class TypeParameter extends Type { override TypeParameter getTypeParameter(int i) { none() } } -private class RawTypeParameter = @type_param or @trait or @type_alias; +private class RawTypeParameter = @type_param or @trait or @type_alias or @impl_trait_type_repr; private predicate id(RawTypeParameter x, RawTypeParameter y) { x = y } @@ -316,23 +333,34 @@ class SelfTypeParameter extends TypeParameter, TSelfTypeParameter { } /** - * An `impl Trait` type parameter. + * An [impl Trait in argument position][1] type, for example: + * + * ```rust + * fn foo(arg: impl Trait) + * ``` + * + * Such types are syntactic sugar for type parameters, that is + * + * ```rust + * fn foo(arg: T) + * ``` + * + * so we model them as type parameters. + * + * [1]: https://doc.rust-lang.org/reference/types/impl-trait.html#r-type.impl-trait.param */ -class ImplTraitTypeParameter extends TypeParameter, TImplTraitTypeParameter { - private ImplTraitType implTraitType; - private int i; +class ImplTraitTypeTypeParameter extends ImplTraitType, TypeParameter { + private Function function; - ImplTraitTypeParameter() { this = TImplTraitTypeParameter(implTraitType, i) } + ImplTraitTypeTypeParameter() { impl = function.getParamList().getAParam().getTypeRepr() } - /** Gets the `impl Trait` type that this parameter belongs to. */ - ImplTraitType getImplTraitType() { result = implTraitType } + override Function getFunction() { result = function } - /** Gets the index of this type parameter. */ - int getIndex() { result = i } + override StructField getStructField(string name) { none() } - override string toString() { result = "impl Trait<" + i.toString() + ">" } + override TupleField getTupleField(int i) { none() } - override Location getLocation() { result instanceof EmptyLocation } + override TypeParameter getTypeParameter(int i) { none() } } /** @@ -370,3 +398,7 @@ final class SelfTypeBoundTypeAbstraction extends TypeAbstraction, Name { override TypeParamTypeParameter getATypeParameter() { none() } } + +final class ImplTraitTypeReprAbstraction extends TypeAbstraction, ImplTraitTypeRepr { + override TypeParamTypeParameter getATypeParameter() { none() } +} diff --git a/rust/ql/lib/codeql/rust/internal/TypeInference.qll b/rust/ql/lib/codeql/rust/internal/TypeInference.qll index c030cca4433c..ad9f7785e013 100644 --- a/rust/ql/lib/codeql/rust/internal/TypeInference.qll +++ b/rust/ql/lib/codeql/rust/internal/TypeInference.qll @@ -77,16 +77,6 @@ private module Input1 implements InputSig1 { apos.asMethodTypeArgumentPosition() = ppos.asTypeParam().getPosition() } - private int getImplTraitTypeParameterId(ImplTraitTypeParameter tp) { - tp = - rank[result](ImplTraitTypeParameter tp0, int bounds, int i | - bounds = tp0.getImplTraitType().getNumberOfBounds() and - i = tp0.getIndex() - | - tp0 order by bounds, i - ) - } - int getTypeParameterId(TypeParameter tp) { tp = rank[result](TypeParameter tp0, int kind, int id | @@ -98,11 +88,9 @@ private module Input1 implements InputSig1 { exists(AstNode node | id = idOfTypeParameterAstNode(node) | node = tp0.(TypeParamTypeParameter).getTypeParam() or node = tp0.(AssociatedTypeTypeParameter).getTypeAlias() or - node = tp0.(SelfTypeParameter).getTrait() + node = tp0.(SelfTypeParameter).getTrait() or + node = tp0.(ImplTraitTypeTypeParameter).getImplTraitTypeRepr() ) - or - kind = 2 and - id = getImplTraitTypeParameterId(tp0) | tp0 order by kind, id ) @@ -124,12 +112,22 @@ private module Input2 implements InputSig2 { class TypeMention = TM::TypeMention; - TypeMention getABaseTypeMention(Type t) { none() } + TypeMention getABaseTypeMention(Type t) { + result = + t.(ImplTraitReturnType).getImplTraitTypeRepr().getTypeBoundList().getABound().getTypeRepr() + } TypeMention getATypeParameterConstraint(TypeParameter tp) { result = tp.(TypeParamTypeParameter).getTypeParam().getTypeBoundList().getABound().getTypeRepr() or result = tp.(SelfTypeParameter).getTrait() + or + result = + tp.(ImplTraitTypeTypeParameter) + .getImplTraitTypeRepr() + .getTypeBoundList() + .getABound() + .getTypeRepr() } /** @@ -169,6 +167,12 @@ private module Input2 implements InputSig2 { condition = self and constraint = self.getTrait() ) + or + exists(ImplTraitTypeRepr impl | + abs = impl and + condition = impl and + constraint = impl.getTypeBoundList().getABound().getTypeRepr() + ) } } @@ -241,12 +245,6 @@ private predicate typeEquality(AstNode n1, TypePath prefix1, AstNode n2, TypePat or n1 = n2.(ParenExpr).getExpr() or - n2 = - any(BlockExpr be | - not be.isAsync() and - n1 = be.getStmtList().getTailExpr() - ) - or n1 = n2.(IfExpr).getABranch() or n1 = n2.(MatchExpr).getAnArm().getExpr() @@ -265,6 +263,19 @@ private predicate typeEquality(AstNode n1, TypePath prefix1, AstNode n2, TypePat n1 = n2.(DerefExpr).getExpr() and prefix1 = TypePath::singleton(TRefTypeParameter()) and prefix2.isEmpty() + or + exists(BlockExpr be | + n1 = be and + n2 = be.getStmtList().getTailExpr() and + if be.isAsync() + then + prefix1 = TypePath::singleton(getFutureOutputTypeParameter()) and + prefix2.isEmpty() + else ( + prefix1.isEmpty() and + prefix2.isEmpty() + ) + ) } pragma[nomagic] @@ -580,6 +591,9 @@ private module CallExprBaseMatchingInput implements MatchingInputSig { ppos.isImplicit() and result.(AssociatedTypeTypeParameter).getTrait() = trait ) + or + ppos.isImplicit() and + this = result.(ImplTraitTypeTypeParameter).getFunction() } override Type getParameterType(DeclarationPosition dpos, TypePath path) { @@ -599,9 +613,22 @@ private module CallExprBaseMatchingInput implements MatchingInputSig { ) } - override Type getReturnType(TypePath path) { + private Type resolveRetType(TypePath path) { result = this.getRetType().getTypeRepr().(TypeMention).resolveTypeAt(path) } + + override Type getReturnType(TypePath path) { + if this.isAsync() + then + path.isEmpty() and + result = getFutureTraitType() + or + exists(TypePath suffix | + result = this.resolveRetType(suffix) and + path = TypePath::cons(getFutureOutputTypeParameter(), suffix) + ) + else result = this.resolveRetType(path) + } } private predicate argPos(CallExprBase call, Expr e, int pos, boolean isMethodCall) { @@ -1027,26 +1054,110 @@ private StructType inferLiteralType(LiteralExpr le) { ) } +pragma[nomagic] +private TraitType getFutureTraitType() { result.getTrait() instanceof FutureTrait } + pragma[nomagic] private AssociatedTypeTypeParameter getFutureOutputTypeParameter() { result.getTypeAlias() = any(FutureTrait ft).getOutputType() } +/** + * A matching configuration for resolving types of `.await` expressions. + */ +private module AwaitExprMatchingInput implements MatchingInputSig { + private newtype TDeclarationPosition = + TSelfDeclarationPosition() or + TOutputPos() + + class DeclarationPosition extends TDeclarationPosition { + predicate isSelf() { this = TSelfDeclarationPosition() } + + predicate isOutput() { this = TOutputPos() } + + string toString() { + this.isSelf() and + result = "self" + or + this.isOutput() and + result = "(output)" + } + } + + private class BuiltinsAwaitFile extends File { + BuiltinsAwaitFile() { + this.getBaseName() = "await.rs" and + this.getParentContainer() instanceof Builtins::BuiltinsFolder + } + } + + class Declaration extends Function { + Declaration() { + this.getFile() instanceof BuiltinsAwaitFile and + this.getName().getText() = "await_type_matching" + } + + TypeParameter getTypeParameter(TypeParameterPosition ppos) { + typeParamMatchPosition(this.getGenericParamList().getATypeParam(), result, ppos) + } + + Type getDeclaredType(DeclarationPosition dpos, TypePath path) { + dpos.isSelf() and + result = this.getParamList().getParam(0).getTypeRepr().(TypeMention).resolveTypeAt(path) + or + dpos.isOutput() and + result = this.getRetType().getTypeRepr().(TypeMention).resolveTypeAt(path) + } + } + + class AccessPosition = DeclarationPosition; + + class Access extends AwaitExpr { + Type getTypeArgument(TypeArgumentPosition apos, TypePath path) { none() } + + AstNode getNodeAt(AccessPosition apos) { + result = this.getExpr() and + apos.isSelf() + or + result = this and + apos.isOutput() + } + + Type getInferredType(AccessPosition apos, TypePath path) { + result = inferType(this.getNodeAt(apos), path) + } + + Declaration getTarget() { exists(this) and exists(result) } + } + + predicate accessDeclarationPositionMatch(AccessPosition apos, DeclarationPosition dpos) { + apos = dpos + } +} + pragma[nomagic] -private Type inferAwaitExprType(AwaitExpr ae, TypePath path) { - exists(TypePath exprPath | result = inferType(ae.getExpr(), exprPath) | - exprPath - .isCons(TImplTraitTypeParameter(_, _), - any(TypePath path0 | path0.isCons(getFutureOutputTypeParameter(), path))) - or - path = exprPath and - not ( - exprPath = TypePath::singleton(TImplTraitTypeParameter(_, _)) and - result.(TraitType).getTrait() instanceof FutureTrait - ) and - not exprPath - .isCons(TImplTraitTypeParameter(_, _), - any(TypePath path0 | path0.isCons(getFutureOutputTypeParameter(), _))) +private TraitType inferAsyncBlockExprRootType(AsyncBlockExpr abe) { + // `typeEquality` handles the non-root case + exists(abe) and + result = getFutureTraitType() +} + +private module AwaitExprMatching = Matching; + +pragma[nomagic] +private Type inferAwaitExprType(AstNode n, TypePath path) { + exists(AwaitExprMatchingInput::Access a, AwaitExprMatchingInput::AccessPosition apos | + n = a.getNodeAt(apos) and + result = AwaitExprMatching::inferAccessType(a, apos, path) + ) + or + // This case is needed for `async` functions and blocks, where we assign + // the type `Future` directly instead of `impl Future` + // + // TODO: It would be better if we could handle this in the shared library + exists(TypePath exprPath | + result = inferType(n.(AwaitExpr).getExpr(), exprPath) and + exprPath.isCons(getFutureOutputTypeParameter(), path) ) } @@ -1196,6 +1307,8 @@ private Function getTypeParameterMethod(TypeParameter tp, string name) { result = getMethodSuccessor(tp.(TypeParamTypeParameter).getTypeParam(), name) or result = getMethodSuccessor(tp.(SelfTypeParameter).getTrait(), name) + or + result = getMethodSuccessor(tp.(ImplTraitTypeTypeParameter).getImplTraitTypeRepr(), name) } /** Gets a method from an `impl` block that matches the method call `mc`. */ @@ -1208,8 +1321,8 @@ private Function getMethodFromImpl(MethodCall mc) { bindingset[trait, name] pragma[inline_late] -private Function getTraitMethod(TraitType trait, string name) { - result = getMethodSuccessor(trait.getTrait(), name) +private Function getTraitMethod(ImplTraitReturnType trait, string name) { + result = getMethodSuccessor(trait.getImplTraitTypeRepr(), name) } /** @@ -1225,9 +1338,7 @@ private Function inferMethodCallTarget(MethodCall mc) { result = getTypeParameterMethod(mc.getTypeAt(TypePath::nil()), mc.getMethodName()) or // The type of the receiver is an `impl Trait` type. - result = - getTraitMethod(mc.getTypeAt(TypePath::singleton(TImplTraitTypeParameter(_, _))), - mc.getMethodName()) + result = getTraitMethod(mc.getTypeAt(TypePath::nil()), mc.getMethodName()) } cached @@ -1404,6 +1515,9 @@ private module Cached { result = inferLiteralType(n) and path.isEmpty() or + result = inferAsyncBlockExprRootType(n) and + path.isEmpty() + or result = inferAwaitExprType(n, path) } } @@ -1421,7 +1535,7 @@ private module Debug { exists(string filepath, int startline, int startcolumn, int endline, int endcolumn | result.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) and filepath.matches("%/main.rs") and - startline = 1334 + startline = 1718 ) } diff --git a/rust/ql/lib/codeql/rust/internal/TypeMention.qll b/rust/ql/lib/codeql/rust/internal/TypeMention.qll index fab4c088b28c..2773d76f955c 100644 --- a/rust/ql/lib/codeql/rust/internal/TypeMention.qll +++ b/rust/ql/lib/codeql/rust/internal/TypeMention.qll @@ -191,13 +191,9 @@ class PathTypeReprMention extends TypeMention instanceof PathTypeRepr { } class ImplTraitTypeReprMention extends TypeMention instanceof ImplTraitTypeRepr { - override TypeMention getTypeArgument(int i) { - result = super.getTypeBoundList().getBound(i).getTypeRepr() - } + override TypeMention getTypeArgument(int i) { none() } - override ImplTraitType resolveType() { - result.getNumberOfBounds() = super.getTypeBoundList().getNumberOfBounds() - } + override ImplTraitType resolveType() { result.getImplTraitTypeRepr() = this } } private TypeParameter pathGetTypeParameter(TypeAlias alias, int i) { diff --git a/rust/ql/test/library-tests/type-inference/main.rs b/rust/ql/test/library-tests/type-inference/main.rs index 3ea87394cf29..ba1dcefe3729 100644 --- a/rust/ql/test/library-tests/type-inference/main.rs +++ b/rust/ql/test/library-tests/type-inference/main.rs @@ -1667,11 +1667,11 @@ mod async_ { f1().await.f(); // $ method=S1f f2().await.f(); // $ method=S1f f3().await.f(); // $ method=S1f - S2.await.f(); // $ MISSING: method=S1f + S2.await.f(); // $ method=S1f let b = async { S1 }; - b.await.f(); // $ MISSING: method=S1f + b.await.f(); // $ method=S1f } } @@ -1727,10 +1727,10 @@ mod impl_trait { x.f1(); // $ method=Trait1f1 x.f2(); // $ method=Trait2f2 let a = get_a_my_trait(); - let b = uses_my_trait1(a); // $ MISSING: type=b:S2 + let b = uses_my_trait1(a); // $ type=b:S2 let a = get_a_my_trait(); let c = uses_my_trait2(a); // $ type=c:S2 - let d = uses_my_trait2(S1); // $ MISSING: type=d:S2 + let d = uses_my_trait2(S1); // $ type=d:S2 } } 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 e561f8579d05..b70af3bcbebc 100644 --- a/rust/ql/test/library-tests/type-inference/type-inference.expected +++ b/rust/ql/test/library-tests/type-inference/type-inference.expected @@ -2377,12 +2377,12 @@ inferType | main.rs:1639:18:1639:21 | SelfParam | | main.rs:1636:5:1636:14 | S1 | | main.rs:1642:25:1644:5 | { ... } | | main.rs:1636:5:1636:14 | S1 | | main.rs:1643:9:1643:10 | S1 | | main.rs:1636:5:1636:14 | S1 | -| main.rs:1646:41:1650:5 | { ... } | | file://:0:0:0:0 | impl Trait ... | -| main.rs:1646:41:1650:5 | { ... } | impl Trait<0> | {EXTERNAL LOCATION} | trait Future | -| main.rs:1646:41:1650:5 | { ... } | impl Trait<0>.Output | main.rs:1636:5:1636:14 | S1 | -| main.rs:1647:9:1649:9 | { ... } | | file://:0:0:0:0 | impl Trait ... | -| main.rs:1647:9:1649:9 | { ... } | impl Trait<0> | {EXTERNAL LOCATION} | trait Future | -| main.rs:1647:9:1649:9 | { ... } | impl Trait<0>.Output | main.rs:1636:5:1636:14 | S1 | +| main.rs:1646:41:1650:5 | { ... } | | {EXTERNAL LOCATION} | trait Future | +| main.rs:1646:41:1650:5 | { ... } | | main.rs:1646:16:1646:39 | ImplTraitTypeRepr | +| main.rs:1646:41:1650:5 | { ... } | Output | main.rs:1636:5:1636:14 | S1 | +| main.rs:1647:9:1649:9 | { ... } | | {EXTERNAL LOCATION} | trait Future | +| main.rs:1647:9:1649:9 | { ... } | | main.rs:1646:16:1646:39 | ImplTraitTypeRepr | +| main.rs:1647:9:1649:9 | { ... } | Output | main.rs:1636:5:1636:14 | S1 | | main.rs:1648:13:1648:14 | S1 | | main.rs:1636:5:1636:14 | S1 | | main.rs:1657:17:1657:46 | SelfParam | | {EXTERNAL LOCATION} | Pin | | main.rs:1657:17:1657:46 | SelfParam | Ptr | file://:0:0:0:0 | & | @@ -2394,29 +2394,27 @@ inferType | main.rs:1658:13:1658:38 | ...::Ready(...) | | {EXTERNAL LOCATION} | Poll | | main.rs:1658:13:1658:38 | ...::Ready(...) | T | main.rs:1636:5:1636:14 | S1 | | main.rs:1658:36:1658:37 | S1 | | main.rs:1636:5:1636:14 | S1 | -| main.rs:1662:41:1664:5 | { ... } | | file://:0:0:0:0 | impl Trait ... | | main.rs:1662:41:1664:5 | { ... } | | main.rs:1652:5:1652:14 | S2 | -| main.rs:1662:41:1664:5 | { ... } | impl Trait<0> | {EXTERNAL LOCATION} | trait Future | -| main.rs:1662:41:1664:5 | { ... } | impl Trait<0>.Output | main.rs:1636:5:1636:14 | S1 | -| main.rs:1663:9:1663:10 | S2 | | file://:0:0:0:0 | impl Trait ... | +| main.rs:1662:41:1664:5 | { ... } | | main.rs:1662:16:1662:39 | ImplTraitTypeRepr | | main.rs:1663:9:1663:10 | S2 | | main.rs:1652:5:1652:14 | S2 | -| main.rs:1663:9:1663:10 | S2 | impl Trait<0> | {EXTERNAL LOCATION} | trait Future | -| main.rs:1663:9:1663:10 | S2 | impl Trait<0>.Output | main.rs:1636:5:1636:14 | S1 | -| main.rs:1667:9:1667:12 | f1(...) | | main.rs:1636:5:1636:14 | S1 | +| main.rs:1663:9:1663:10 | S2 | | main.rs:1662:16:1662:39 | ImplTraitTypeRepr | +| main.rs:1667:9:1667:12 | f1(...) | | {EXTERNAL LOCATION} | trait Future | +| main.rs:1667:9:1667:12 | f1(...) | Output | main.rs:1636:5:1636:14 | S1 | | main.rs:1667:9:1667:18 | await ... | | main.rs:1636:5:1636:14 | S1 | -| main.rs:1668:9:1668:12 | f2(...) | | file://:0:0:0:0 | impl Trait ... | -| main.rs:1668:9:1668:12 | f2(...) | impl Trait<0> | {EXTERNAL LOCATION} | trait Future | -| main.rs:1668:9:1668:12 | f2(...) | impl Trait<0>.Output | main.rs:1636:5:1636:14 | S1 | -| main.rs:1668:9:1668:18 | await ... | | file://:0:0:0:0 | impl Trait ... | +| main.rs:1668:9:1668:12 | f2(...) | | main.rs:1646:16:1646:39 | ImplTraitTypeRepr | | main.rs:1668:9:1668:18 | await ... | | main.rs:1636:5:1636:14 | S1 | -| main.rs:1669:9:1669:12 | f3(...) | | file://:0:0:0:0 | impl Trait ... | -| main.rs:1669:9:1669:12 | f3(...) | impl Trait<0> | {EXTERNAL LOCATION} | trait Future | -| main.rs:1669:9:1669:12 | f3(...) | impl Trait<0>.Output | main.rs:1636:5:1636:14 | S1 | -| main.rs:1669:9:1669:18 | await ... | | file://:0:0:0:0 | impl Trait ... | +| main.rs:1669:9:1669:12 | f3(...) | | main.rs:1662:16:1662:39 | ImplTraitTypeRepr | | main.rs:1669:9:1669:18 | await ... | | main.rs:1636:5:1636:14 | S1 | | main.rs:1670:9:1670:10 | S2 | | main.rs:1652:5:1652:14 | S2 | -| main.rs:1670:9:1670:16 | await S2 | | main.rs:1652:5:1652:14 | S2 | +| main.rs:1670:9:1670:16 | await S2 | | main.rs:1636:5:1636:14 | S1 | +| main.rs:1671:13:1671:13 | b | | {EXTERNAL LOCATION} | trait Future | +| main.rs:1671:13:1671:13 | b | Output | main.rs:1636:5:1636:14 | S1 | +| main.rs:1671:17:1673:9 | { ... } | | {EXTERNAL LOCATION} | trait Future | +| main.rs:1671:17:1673:9 | { ... } | Output | main.rs:1636:5:1636:14 | S1 | | main.rs:1672:13:1672:14 | S1 | | main.rs:1636:5:1636:14 | S1 | +| main.rs:1674:9:1674:9 | b | | {EXTERNAL LOCATION} | trait Future | +| main.rs:1674:9:1674:9 | b | Output | main.rs:1636:5:1636:14 | S1 | +| main.rs:1674:9:1674:15 | await b | | main.rs:1636:5:1636:14 | S1 | | main.rs:1684:15:1684:19 | SelfParam | | file://:0:0:0:0 | & | | main.rs:1684:15:1684:19 | SelfParam | &T | main.rs:1683:5:1685:5 | Self [trait Trait1] | | main.rs:1688:15:1688:19 | SelfParam | | file://:0:0:0:0 | & | @@ -2425,77 +2423,48 @@ inferType | main.rs:1692:15:1692:19 | SelfParam | &T | main.rs:1680:5:1680:14 | S1 | | main.rs:1696:15:1696:19 | SelfParam | | file://:0:0:0:0 | & | | main.rs:1696:15:1696:19 | SelfParam | &T | main.rs:1680:5:1680:14 | S1 | -| main.rs:1699:37:1701:5 | { ... } | | file://:0:0:0:0 | impl Trait ... | | main.rs:1699:37:1701:5 | { ... } | | main.rs:1680:5:1680:14 | S1 | -| main.rs:1699:37:1701:5 | { ... } | impl Trait<0> | main.rs:1683:5:1685:5 | trait Trait1 | -| main.rs:1699:37:1701:5 | { ... } | impl Trait<1> | main.rs:1687:5:1689:5 | trait Trait2 | -| main.rs:1700:9:1700:10 | S1 | | file://:0:0:0:0 | impl Trait ... | +| main.rs:1699:37:1701:5 | { ... } | | main.rs:1699:16:1699:35 | ImplTraitTypeRepr | | main.rs:1700:9:1700:10 | S1 | | main.rs:1680:5:1680:14 | S1 | -| main.rs:1700:9:1700:10 | S1 | impl Trait<0> | main.rs:1683:5:1685:5 | trait Trait1 | -| main.rs:1700:9:1700:10 | S1 | impl Trait<1> | main.rs:1687:5:1689:5 | trait Trait2 | +| main.rs:1700:9:1700:10 | S1 | | main.rs:1699:16:1699:35 | ImplTraitTypeRepr | | main.rs:1704:18:1704:22 | SelfParam | | file://:0:0:0:0 | & | | main.rs:1704:18:1704:22 | SelfParam | &T | main.rs:1703:5:1705:5 | Self [trait MyTrait] | | main.rs:1708:18:1708:22 | SelfParam | | file://:0:0:0:0 | & | | main.rs:1708:18:1708:22 | SelfParam | &T | main.rs:1680:5:1680:14 | S1 | | main.rs:1708:31:1710:9 | { ... } | | main.rs:1681:5:1681:14 | S2 | | main.rs:1709:13:1709:14 | S2 | | main.rs:1681:5:1681:14 | S2 | -| main.rs:1713:45:1715:5 | { ... } | | file://:0:0:0:0 | impl Trait ... | | main.rs:1713:45:1715:5 | { ... } | | main.rs:1680:5:1680:14 | S1 | -| main.rs:1713:45:1715:5 | { ... } | impl Trait<0> | main.rs:1703:5:1705:5 | trait MyTrait | -| main.rs:1713:45:1715:5 | { ... } | impl Trait<0>.A | main.rs:1681:5:1681:14 | S2 | -| main.rs:1714:9:1714:10 | S1 | | file://:0:0:0:0 | impl Trait ... | +| main.rs:1713:45:1715:5 | { ... } | | main.rs:1713:28:1713:43 | ImplTraitTypeRepr | | main.rs:1714:9:1714:10 | S1 | | main.rs:1680:5:1680:14 | S1 | -| main.rs:1714:9:1714:10 | S1 | impl Trait<0> | main.rs:1703:5:1705:5 | trait MyTrait | -| main.rs:1714:9:1714:10 | S1 | impl Trait<0>.A | main.rs:1681:5:1681:14 | S2 | +| main.rs:1714:9:1714:10 | S1 | | main.rs:1713:28:1713:43 | ImplTraitTypeRepr | | main.rs:1717:41:1717:41 | t | | main.rs:1717:26:1717:38 | B | | main.rs:1717:52:1719:5 | { ... } | | main.rs:1717:23:1717:23 | A | | main.rs:1718:9:1718:9 | t | | main.rs:1717:26:1717:38 | B | | main.rs:1718:9:1718:17 | t.get_a() | | main.rs:1717:23:1717:23 | A | -| main.rs:1721:26:1721:26 | t | | file://:0:0:0:0 | impl Trait ... | -| main.rs:1721:26:1721:26 | t | impl Trait<0> | main.rs:1703:5:1705:5 | trait MyTrait | -| main.rs:1721:26:1721:26 | t | impl Trait<0>.A | main.rs:1721:23:1721:23 | A | +| main.rs:1721:26:1721:26 | t | | main.rs:1721:29:1721:43 | ImplTraitTypeRepr | | main.rs:1721:51:1723:5 | { ... } | | main.rs:1721:23:1721:23 | A | -| main.rs:1722:9:1722:9 | t | | file://:0:0:0:0 | impl Trait ... | -| main.rs:1722:9:1722:9 | t | impl Trait<0> | main.rs:1703:5:1705:5 | trait MyTrait | -| main.rs:1722:9:1722:9 | t | impl Trait<0>.A | main.rs:1721:23:1721:23 | A | +| main.rs:1722:9:1722:9 | t | | main.rs:1721:29:1721:43 | ImplTraitTypeRepr | | main.rs:1722:9:1722:17 | t.get_a() | | main.rs:1721:23:1721:23 | A | -| main.rs:1726:13:1726:13 | x | | file://:0:0:0:0 | impl Trait ... | -| main.rs:1726:13:1726:13 | x | impl Trait<0> | main.rs:1683:5:1685:5 | trait Trait1 | -| main.rs:1726:13:1726:13 | x | impl Trait<1> | main.rs:1687:5:1689:5 | trait Trait2 | -| main.rs:1726:17:1726:20 | f1(...) | | file://:0:0:0:0 | impl Trait ... | -| main.rs:1726:17:1726:20 | f1(...) | impl Trait<0> | main.rs:1683:5:1685:5 | trait Trait1 | -| main.rs:1726:17:1726:20 | f1(...) | impl Trait<1> | main.rs:1687:5:1689:5 | trait Trait2 | -| main.rs:1727:9:1727:9 | x | | file://:0:0:0:0 | impl Trait ... | -| main.rs:1727:9:1727:9 | x | impl Trait<0> | main.rs:1683:5:1685:5 | trait Trait1 | -| main.rs:1727:9:1727:9 | x | impl Trait<1> | main.rs:1687:5:1689:5 | trait Trait2 | -| main.rs:1728:9:1728:9 | x | | file://:0:0:0:0 | impl Trait ... | -| main.rs:1728:9:1728:9 | x | impl Trait<0> | main.rs:1683:5:1685:5 | trait Trait1 | -| main.rs:1728:9:1728:9 | x | impl Trait<1> | main.rs:1687:5:1689:5 | trait Trait2 | -| main.rs:1729:13:1729:13 | a | | file://:0:0:0:0 | impl Trait ... | -| main.rs:1729:13:1729:13 | a | impl Trait<0> | main.rs:1703:5:1705:5 | trait MyTrait | -| main.rs:1729:13:1729:13 | a | impl Trait<0>.A | main.rs:1681:5:1681:14 | S2 | -| main.rs:1729:17:1729:32 | get_a_my_trait(...) | | file://:0:0:0:0 | impl Trait ... | -| main.rs:1729:17:1729:32 | get_a_my_trait(...) | impl Trait<0> | main.rs:1703:5:1705:5 | trait MyTrait | -| main.rs:1729:17:1729:32 | get_a_my_trait(...) | impl Trait<0>.A | main.rs:1681:5:1681:14 | S2 | -| main.rs:1730:32:1730:32 | a | | file://:0:0:0:0 | impl Trait ... | -| main.rs:1730:32:1730:32 | a | impl Trait<0> | main.rs:1703:5:1705:5 | trait MyTrait | -| main.rs:1730:32:1730:32 | a | impl Trait<0>.A | main.rs:1681:5:1681:14 | S2 | -| main.rs:1731:13:1731:13 | a | | file://:0:0:0:0 | impl Trait ... | -| main.rs:1731:13:1731:13 | a | impl Trait<0> | main.rs:1703:5:1705:5 | trait MyTrait | -| main.rs:1731:13:1731:13 | a | impl Trait<0>.A | main.rs:1681:5:1681:14 | S2 | -| main.rs:1731:17:1731:32 | get_a_my_trait(...) | | file://:0:0:0:0 | impl Trait ... | -| main.rs:1731:17:1731:32 | get_a_my_trait(...) | impl Trait<0> | main.rs:1703:5:1705:5 | trait MyTrait | -| main.rs:1731:17:1731:32 | get_a_my_trait(...) | impl Trait<0>.A | main.rs:1681:5:1681:14 | S2 | +| main.rs:1726:13:1726:13 | x | | main.rs:1699:16:1699:35 | ImplTraitTypeRepr | +| main.rs:1726:17:1726:20 | f1(...) | | main.rs:1699:16:1699:35 | ImplTraitTypeRepr | +| main.rs:1727:9:1727:9 | x | | main.rs:1699:16:1699:35 | ImplTraitTypeRepr | +| main.rs:1728:9:1728:9 | x | | main.rs:1699:16:1699:35 | ImplTraitTypeRepr | +| main.rs:1729:13:1729:13 | a | | main.rs:1713:28:1713:43 | ImplTraitTypeRepr | +| main.rs:1729:17:1729:32 | get_a_my_trait(...) | | main.rs:1713:28:1713:43 | ImplTraitTypeRepr | +| main.rs:1730:13:1730:13 | b | | main.rs:1681:5:1681:14 | S2 | +| main.rs:1730:17:1730:33 | uses_my_trait1(...) | | main.rs:1681:5:1681:14 | S2 | +| main.rs:1730:32:1730:32 | a | | main.rs:1713:28:1713:43 | ImplTraitTypeRepr | +| main.rs:1731:13:1731:13 | a | | main.rs:1713:28:1713:43 | ImplTraitTypeRepr | +| main.rs:1731:17:1731:32 | get_a_my_trait(...) | | main.rs:1713:28:1713:43 | ImplTraitTypeRepr | | main.rs:1732:13:1732:13 | c | | main.rs:1681:5:1681:14 | S2 | | main.rs:1732:17:1732:33 | uses_my_trait2(...) | | main.rs:1681:5:1681:14 | S2 | -| main.rs:1732:32:1732:32 | a | | file://:0:0:0:0 | impl Trait ... | -| main.rs:1732:32:1732:32 | a | impl Trait<0> | main.rs:1703:5:1705:5 | trait MyTrait | -| main.rs:1732:32:1732:32 | a | impl Trait<0>.A | main.rs:1681:5:1681:14 | S2 | -| main.rs:1733:32:1733:33 | S1 | | file://:0:0:0:0 | impl Trait ... | +| main.rs:1732:32:1732:32 | a | | main.rs:1713:28:1713:43 | ImplTraitTypeRepr | +| main.rs:1733:13:1733:13 | d | | main.rs:1681:5:1681:14 | S2 | +| main.rs:1733:17:1733:34 | uses_my_trait2(...) | | main.rs:1681:5:1681:14 | S2 | | main.rs:1733:32:1733:33 | S1 | | main.rs:1680:5:1680:14 | S1 | -| main.rs:1733:32:1733:33 | S1 | impl Trait<0> | main.rs:1703:5:1705:5 | trait MyTrait | | main.rs:1739:5:1739:20 | ...::f(...) | | main.rs:67:5:67:21 | Foo | | main.rs:1740:5:1740:60 | ...::g(...) | | main.rs:67:5:67:21 | Foo | | main.rs:1740:20:1740:38 | ...::Foo {...} | | main.rs:67:5:67:21 | Foo | | main.rs:1740:41:1740:59 | ...::Foo {...} | | main.rs:67:5:67:21 | Foo | +| main.rs:1756:5:1756:15 | ...::f(...) | | {EXTERNAL LOCATION} | trait Future | testFailures diff --git a/rust/ql/test/query-tests/security/CWE-022/CONSISTENCY/PathResolutionConsistency.expected b/rust/ql/test/query-tests/security/CWE-022/CONSISTENCY/PathResolutionConsistency.expected index 88e64c648bcf..abeca72b3514 100644 --- a/rust/ql/test/query-tests/security/CWE-022/CONSISTENCY/PathResolutionConsistency.expected +++ b/rust/ql/test/query-tests/security/CWE-022/CONSISTENCY/PathResolutionConsistency.expected @@ -4,6 +4,8 @@ multiplePathResolutions | src/main.rs:8:21:8:33 | ...::from | file://:0:0:0:0 | fn from | | src/main.rs:8:21:8:33 | ...::from | file://:0:0:0:0 | fn from | | src/main.rs:8:21:8:33 | ...::from | file://:0:0:0:0 | fn from | +| src/main.rs:8:21:8:33 | ...::from | file://:0:0:0:0 | fn from | +| src/main.rs:19:21:19:33 | ...::from | file://:0:0:0:0 | fn from | | src/main.rs:19:21:19:33 | ...::from | file://:0:0:0:0 | fn from | | src/main.rs:19:21:19:33 | ...::from | file://:0:0:0:0 | fn from | | src/main.rs:19:21:19:33 | ...::from | file://:0:0:0:0 | fn from | @@ -14,6 +16,8 @@ multiplePathResolutions | src/main.rs:25:23:25:35 | ...::from | file://:0:0:0:0 | fn from | | src/main.rs:25:23:25:35 | ...::from | file://:0:0:0:0 | fn from | | src/main.rs:25:23:25:35 | ...::from | file://:0:0:0:0 | fn from | +| src/main.rs:25:23:25:35 | ...::from | file://:0:0:0:0 | fn from | +| src/main.rs:26:38:26:50 | ...::from | file://:0:0:0:0 | fn from | | src/main.rs:26:38:26:50 | ...::from | file://:0:0:0:0 | fn from | | src/main.rs:26:38:26:50 | ...::from | file://:0:0:0:0 | fn from | | src/main.rs:26:38:26:50 | ...::from | file://:0:0:0:0 | fn from | @@ -24,6 +28,8 @@ multiplePathResolutions | src/main.rs:39:23:39:35 | ...::from | file://:0:0:0:0 | fn from | | src/main.rs:39:23:39:35 | ...::from | file://:0:0:0:0 | fn from | | src/main.rs:39:23:39:35 | ...::from | file://:0:0:0:0 | fn from | +| src/main.rs:39:23:39:35 | ...::from | file://:0:0:0:0 | fn from | +| src/main.rs:40:38:40:50 | ...::from | file://:0:0:0:0 | fn from | | src/main.rs:40:38:40:50 | ...::from | file://:0:0:0:0 | fn from | | src/main.rs:40:38:40:50 | ...::from | file://:0:0:0:0 | fn from | | src/main.rs:40:38:40:50 | ...::from | file://:0:0:0:0 | fn from | @@ -34,6 +40,8 @@ multiplePathResolutions | src/main.rs:52:23:52:35 | ...::from | file://:0:0:0:0 | fn from | | src/main.rs:52:23:52:35 | ...::from | file://:0:0:0:0 | fn from | | src/main.rs:52:23:52:35 | ...::from | file://:0:0:0:0 | fn from | +| src/main.rs:52:23:52:35 | ...::from | file://:0:0:0:0 | fn from | +| src/main.rs:53:38:53:50 | ...::from | file://:0:0:0:0 | fn from | | src/main.rs:53:38:53:50 | ...::from | file://:0:0:0:0 | fn from | | src/main.rs:53:38:53:50 | ...::from | file://:0:0:0:0 | fn from | | src/main.rs:53:38:53:50 | ...::from | file://:0:0:0:0 | fn from | diff --git a/rust/tools/builtins/await.rs b/rust/tools/builtins/await.rs new file mode 100644 index 000000000000..c15af9dc529a --- /dev/null +++ b/rust/tools/builtins/await.rs @@ -0,0 +1,7 @@ +use std::future::Future; + +fn await_type_matching>(x: T2) -> T1 { + panic!( + "This function exists only in order to implement type inference for `.await` expressions." + ); +} diff --git a/shared/typeinference/codeql/typeinference/internal/TypeInference.qll b/shared/typeinference/codeql/typeinference/internal/TypeInference.qll index b0f5fc673009..ca79740a2ceb 100644 --- a/shared/typeinference/codeql/typeinference/internal/TypeInference.qll +++ b/shared/typeinference/codeql/typeinference/internal/TypeInference.qll @@ -220,6 +220,10 @@ module Make1 Input1> { predicate isCons(TypeParameter tp, TypePath suffix) { suffix = this.stripPrefix(TypePath::singleton(tp)) } + + /** Gets the head of this path, if any. */ + bindingset[this] + TypeParameter getHead() { result = this.getTypeParameter(0) } } /** Provides predicates for constructing `TypePath`s. */ @@ -1110,7 +1114,7 @@ module Make1 Input1> { Declaration decl, DeclarationPosition dpos, Type base, TypePath path, TypeParameter tp ) { tp = decl.getDeclaredType(dpos, path) and - path.isCons(base.getATypeParameter(), _) + base.getATypeParameter() = path.getHead() } /**