mirror of
https://github.com/github/codeql.git
synced 2026-04-22 15:25:18 +02:00
Merge pull request #19657 from hvitved/rust/type-inference-index-expr-simple
Rust: Simple type inference for index expressions
This commit is contained in:
@@ -16,10 +16,13 @@ newtype TType =
|
||||
TArrayType() or // todo: add size?
|
||||
TRefType() or // todo: add mut?
|
||||
TImplTraitType(ImplTraitTypeRepr impl) or
|
||||
TSliceType() or
|
||||
TTypeParamTypeParameter(TypeParam t) or
|
||||
TAssociatedTypeTypeParameter(TypeAlias t) { any(TraitItemNode trait).getAnAssocItem() = t } or
|
||||
TArrayTypeParameter() or
|
||||
TRefTypeParameter() or
|
||||
TSelfTypeParameter(Trait t)
|
||||
TSelfTypeParameter(Trait t) or
|
||||
TSliceTypeParameter()
|
||||
|
||||
/**
|
||||
* A type without type arguments.
|
||||
@@ -149,7 +152,8 @@ class ArrayType extends Type, TArrayType {
|
||||
override TupleField getTupleField(int i) { none() }
|
||||
|
||||
override TypeParameter getTypeParameter(int i) {
|
||||
none() // todo
|
||||
result = TArrayTypeParameter() and
|
||||
i = 0
|
||||
}
|
||||
|
||||
override string toString() { result = "[]" }
|
||||
@@ -227,6 +231,29 @@ class ImplTraitReturnType extends ImplTraitType {
|
||||
override Function getFunction() { result = function }
|
||||
}
|
||||
|
||||
/**
|
||||
* A slice type.
|
||||
*
|
||||
* Slice types like `[i64]` are modeled as normal generic types
|
||||
* with a single type argument.
|
||||
*/
|
||||
class SliceType extends Type, TSliceType {
|
||||
SliceType() { this = TSliceType() }
|
||||
|
||||
override StructField getStructField(string name) { none() }
|
||||
|
||||
override TupleField getTupleField(int i) { none() }
|
||||
|
||||
override TypeParameter getTypeParameter(int i) {
|
||||
result = TSliceTypeParameter() and
|
||||
i = 0
|
||||
}
|
||||
|
||||
override string toString() { result = "[]" }
|
||||
|
||||
override Location getLocation() { result instanceof EmptyLocation }
|
||||
}
|
||||
|
||||
/** A type parameter. */
|
||||
abstract class TypeParameter extends Type {
|
||||
override StructField getStructField(string name) { none() }
|
||||
@@ -306,6 +333,13 @@ class AssociatedTypeTypeParameter extends TypeParameter, TAssociatedTypeTypePara
|
||||
override Location getLocation() { result = typeAlias.getLocation() }
|
||||
}
|
||||
|
||||
/** An implicit array type parameter. */
|
||||
class ArrayTypeParameter extends TypeParameter, TArrayTypeParameter {
|
||||
override string toString() { result = "[T;...]" }
|
||||
|
||||
override Location getLocation() { result instanceof EmptyLocation }
|
||||
}
|
||||
|
||||
/** An implicit reference type parameter. */
|
||||
class RefTypeParameter extends TypeParameter, TRefTypeParameter {
|
||||
override string toString() { result = "&T" }
|
||||
@@ -313,6 +347,13 @@ class RefTypeParameter extends TypeParameter, TRefTypeParameter {
|
||||
override Location getLocation() { result instanceof EmptyLocation }
|
||||
}
|
||||
|
||||
/** An implicit slice type parameter. */
|
||||
class SliceTypeParameter extends TypeParameter, TSliceTypeParameter {
|
||||
override string toString() { result = "[T]" }
|
||||
|
||||
override Location getLocation() { result instanceof EmptyLocation }
|
||||
}
|
||||
|
||||
/**
|
||||
* The implicit `Self` type parameter of a trait, that refers to the
|
||||
* implementing type of the trait.
|
||||
|
||||
@@ -80,10 +80,18 @@ private module Input1 implements InputSig1<Location> {
|
||||
int getTypeParameterId(TypeParameter tp) {
|
||||
tp =
|
||||
rank[result](TypeParameter tp0, int kind, int id |
|
||||
tp0 instanceof RefTypeParameter and
|
||||
tp0 instanceof ArrayTypeParameter and
|
||||
kind = 0 and
|
||||
id = 0
|
||||
or
|
||||
tp0 instanceof RefTypeParameter and
|
||||
kind = 0 and
|
||||
id = 1
|
||||
or
|
||||
tp0 instanceof SliceTypeParameter and
|
||||
kind = 0 and
|
||||
id = 2
|
||||
or
|
||||
kind = 1 and
|
||||
exists(AstNode node | id = idOfTypeParameterAstNode(node) |
|
||||
node = tp0.(TypeParamTypeParameter).getTypeParam() or
|
||||
@@ -1128,6 +1136,50 @@ private Type inferAwaitExprType(AstNode n, TypePath path) {
|
||||
)
|
||||
}
|
||||
|
||||
private class Vec extends Struct {
|
||||
Vec() { this.getCanonicalPath() = "alloc::vec::Vec" }
|
||||
|
||||
TypeParamTypeParameter getElementTypeParameter() {
|
||||
result.getTypeParam() = this.getGenericParamList().getTypeParam(0)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* According to [the Rust reference][1]: _"array and slice-typed expressions
|
||||
* can be indexed with a `usize` index ... For other types an index expression
|
||||
* `a[b]` is equivalent to *std::ops::Index::index(&a, b)"_.
|
||||
*
|
||||
* The logic below handles array and slice indexing, but for other types it is
|
||||
* currently limited to `Vec`.
|
||||
*
|
||||
* [1]: https://doc.rust-lang.org/reference/expressions/array-expr.html#r-expr.array.index
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private Type inferIndexExprType(IndexExpr ie, TypePath path) {
|
||||
// TODO: Should be implemented as method resolution, using the special
|
||||
// `std::ops::Index` trait.
|
||||
exists(TypePath exprPath, Builtins::BuiltinType t |
|
||||
TStruct(t) = inferType(ie.getIndex()) and
|
||||
(
|
||||
// also allow `i32`, since that is currently the type that we infer for
|
||||
// integer literals like `0`
|
||||
t instanceof Builtins::I32
|
||||
or
|
||||
t instanceof Builtins::Usize
|
||||
) and
|
||||
result = inferType(ie.getBase(), exprPath)
|
||||
|
|
||||
exprPath.isCons(any(Vec v).getElementTypeParameter(), path)
|
||||
or
|
||||
exprPath.isCons(any(ArrayTypeParameter tp), path)
|
||||
or
|
||||
exists(TypePath path0 |
|
||||
exprPath.isCons(any(RefTypeParameter tp), path0) and
|
||||
path0.isCons(any(SliceTypeParameter tp), path)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private module MethodCall {
|
||||
/** An expression that calls a method. */
|
||||
abstract private class MethodCallImpl extends Expr {
|
||||
@@ -1487,6 +1539,8 @@ private module Cached {
|
||||
path.isEmpty()
|
||||
or
|
||||
result = inferAwaitExprType(n, path)
|
||||
or
|
||||
result = inferIndexExprType(n, path)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -43,6 +43,12 @@ class RefTypeReprMention extends TypeMention instanceof RefTypeRepr {
|
||||
override Type resolveType() { result = TRefType() }
|
||||
}
|
||||
|
||||
class SliceTypeReprMention extends TypeMention instanceof SliceTypeRepr {
|
||||
override TypeMention getTypeArgument(int i) { result = super.getTypeRepr() and i = 0 }
|
||||
|
||||
override Type resolveType() { result = TSliceType() }
|
||||
}
|
||||
|
||||
class PathTypeReprMention extends TypeMention instanceof PathTypeRepr {
|
||||
Path path;
|
||||
ItemNode resolved;
|
||||
|
||||
@@ -1753,6 +1753,58 @@ mod impl_trait {
|
||||
}
|
||||
}
|
||||
|
||||
mod indexers {
|
||||
use std::ops::Index;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct S;
|
||||
|
||||
impl S {
|
||||
fn foo(&self) -> Self {
|
||||
S
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct MyVec<T> {
|
||||
data: Vec<T>,
|
||||
}
|
||||
|
||||
impl<T> MyVec<T> {
|
||||
fn new() -> Self {
|
||||
MyVec { data: Vec::new() }
|
||||
}
|
||||
|
||||
fn push(&mut self, value: T) {
|
||||
self.data.push(value); // $ fieldof=MyVec method=push
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Index<usize> for MyVec<T> {
|
||||
type Output = T;
|
||||
|
||||
// MyVec::index
|
||||
fn index(&self, index: usize) -> &Self::Output {
|
||||
&self.data[index] // $ fieldof=MyVec
|
||||
}
|
||||
}
|
||||
|
||||
fn analyze_slice(slice: &[S]) {
|
||||
let x = slice[0].foo(); // $ method=foo type=x:S
|
||||
}
|
||||
|
||||
pub fn f() {
|
||||
let mut vec = MyVec::new(); // $ type=vec:T.S
|
||||
vec.push(S); // $ method=push
|
||||
vec[0].foo(); // $ MISSING: method=foo -- type inference does not support the `Index` trait yet
|
||||
|
||||
let xs: [S; 1] = [S];
|
||||
let x = xs[0].foo(); // $ method=foo type=x:S
|
||||
|
||||
analyze_slice(&xs);
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
field_access::f();
|
||||
method_impl::f();
|
||||
@@ -1774,4 +1826,5 @@ fn main() {
|
||||
operators::f();
|
||||
async_::f();
|
||||
impl_trait::f();
|
||||
indexers::f();
|
||||
}
|
||||
|
||||
@@ -2525,9 +2525,91 @@ inferType
|
||||
| main.rs:1752:13:1752:13 | d | | main.rs:1700:5:1700:14 | S2 |
|
||||
| main.rs:1752:17:1752:34 | uses_my_trait2(...) | | main.rs:1700:5:1700:14 | S2 |
|
||||
| main.rs:1752:32:1752:33 | S1 | | main.rs:1699:5:1699:14 | S1 |
|
||||
| main.rs:1758:5:1758:20 | ...::f(...) | | main.rs:67:5:67:21 | Foo |
|
||||
| main.rs:1759:5:1759:60 | ...::g(...) | | main.rs:67:5:67:21 | Foo |
|
||||
| main.rs:1759:20:1759:38 | ...::Foo {...} | | main.rs:67:5:67:21 | Foo |
|
||||
| main.rs:1759:41:1759:59 | ...::Foo {...} | | main.rs:67:5:67:21 | Foo |
|
||||
| main.rs:1775:5:1775:15 | ...::f(...) | | {EXTERNAL LOCATION} | trait Future |
|
||||
| main.rs:1763:16:1763:20 | SelfParam | | file://:0:0:0:0 | & |
|
||||
| main.rs:1763:16:1763:20 | SelfParam | &T | main.rs:1759:5:1760:13 | S |
|
||||
| main.rs:1763:31:1765:9 | { ... } | | main.rs:1759:5:1760:13 | S |
|
||||
| main.rs:1764:13:1764:13 | S | | main.rs:1759:5:1760:13 | S |
|
||||
| main.rs:1774:26:1776:9 | { ... } | | main.rs:1768:5:1771:5 | MyVec |
|
||||
| main.rs:1774:26:1776:9 | { ... } | T | main.rs:1773:10:1773:10 | T |
|
||||
| main.rs:1775:13:1775:38 | MyVec {...} | | main.rs:1768:5:1771:5 | MyVec |
|
||||
| main.rs:1775:13:1775:38 | MyVec {...} | T | main.rs:1773:10:1773:10 | T |
|
||||
| main.rs:1775:27:1775:36 | ...::new(...) | | {EXTERNAL LOCATION} | Vec |
|
||||
| main.rs:1775:27:1775:36 | ...::new(...) | T | main.rs:1773:10:1773:10 | T |
|
||||
| main.rs:1778:17:1778:25 | SelfParam | | file://:0:0:0:0 | & |
|
||||
| main.rs:1778:17:1778:25 | SelfParam | &T | main.rs:1768:5:1771:5 | MyVec |
|
||||
| main.rs:1778:17:1778:25 | SelfParam | &T.T | main.rs:1773:10:1773:10 | T |
|
||||
| main.rs:1778:28:1778:32 | value | | main.rs:1773:10:1773:10 | T |
|
||||
| main.rs:1779:13:1779:16 | self | | file://:0:0:0:0 | & |
|
||||
| main.rs:1779:13:1779:16 | self | &T | main.rs:1768:5:1771:5 | MyVec |
|
||||
| main.rs:1779:13:1779:16 | self | &T.T | main.rs:1773:10:1773:10 | T |
|
||||
| main.rs:1779:13:1779:21 | self.data | | {EXTERNAL LOCATION} | Vec |
|
||||
| main.rs:1779:13:1779:21 | self.data | T | main.rs:1773:10:1773:10 | T |
|
||||
| main.rs:1779:28:1779:32 | value | | main.rs:1773:10:1773:10 | T |
|
||||
| main.rs:1787:18:1787:22 | SelfParam | | file://:0:0:0:0 | & |
|
||||
| main.rs:1787:18:1787:22 | SelfParam | &T | main.rs:1768:5:1771:5 | MyVec |
|
||||
| main.rs:1787:18:1787:22 | SelfParam | &T.T | main.rs:1783:10:1783:10 | T |
|
||||
| main.rs:1787:25:1787:29 | index | | {EXTERNAL LOCATION} | usize |
|
||||
| main.rs:1787:56:1789:9 | { ... } | | file://:0:0:0:0 | & |
|
||||
| main.rs:1787:56:1789:9 | { ... } | &T | main.rs:1783:10:1783:10 | T |
|
||||
| main.rs:1788:13:1788:29 | &... | | file://:0:0:0:0 | & |
|
||||
| main.rs:1788:13:1788:29 | &... | &T | main.rs:1783:10:1783:10 | T |
|
||||
| main.rs:1788:14:1788:17 | self | | file://:0:0:0:0 | & |
|
||||
| main.rs:1788:14:1788:17 | self | &T | main.rs:1768:5:1771:5 | MyVec |
|
||||
| main.rs:1788:14:1788:17 | self | &T.T | main.rs:1783:10:1783:10 | T |
|
||||
| main.rs:1788:14:1788:22 | self.data | | {EXTERNAL LOCATION} | Vec |
|
||||
| main.rs:1788:14:1788:22 | self.data | T | main.rs:1783:10:1783:10 | T |
|
||||
| main.rs:1788:14:1788:29 | ...[index] | | main.rs:1783:10:1783:10 | T |
|
||||
| main.rs:1788:24:1788:28 | index | | {EXTERNAL LOCATION} | usize |
|
||||
| main.rs:1792:22:1792:26 | slice | | file://:0:0:0:0 | & |
|
||||
| main.rs:1792:22:1792:26 | slice | &T | file://:0:0:0:0 | [] |
|
||||
| main.rs:1792:22:1792:26 | slice | &T.[T] | main.rs:1759:5:1760:13 | S |
|
||||
| main.rs:1793:13:1793:13 | x | | main.rs:1759:5:1760:13 | S |
|
||||
| main.rs:1793:17:1793:21 | slice | | file://:0:0:0:0 | & |
|
||||
| main.rs:1793:17:1793:21 | slice | &T | file://:0:0:0:0 | [] |
|
||||
| main.rs:1793:17:1793:21 | slice | &T.[T] | main.rs:1759:5:1760:13 | S |
|
||||
| main.rs:1793:17:1793:24 | slice[0] | | main.rs:1759:5:1760:13 | S |
|
||||
| main.rs:1793:17:1793:30 | ... .foo() | | main.rs:1759:5:1760:13 | S |
|
||||
| main.rs:1793:23:1793:23 | 0 | | {EXTERNAL LOCATION} | i32 |
|
||||
| main.rs:1797:13:1797:19 | mut vec | | main.rs:1768:5:1771:5 | MyVec |
|
||||
| main.rs:1797:13:1797:19 | mut vec | T | main.rs:1759:5:1760:13 | S |
|
||||
| main.rs:1797:23:1797:34 | ...::new(...) | | main.rs:1768:5:1771:5 | MyVec |
|
||||
| main.rs:1797:23:1797:34 | ...::new(...) | T | main.rs:1759:5:1760:13 | S |
|
||||
| main.rs:1798:9:1798:11 | vec | | main.rs:1768:5:1771:5 | MyVec |
|
||||
| main.rs:1798:9:1798:11 | vec | T | main.rs:1759:5:1760:13 | S |
|
||||
| main.rs:1798:18:1798:18 | S | | main.rs:1759:5:1760:13 | S |
|
||||
| main.rs:1799:9:1799:11 | vec | | main.rs:1768:5:1771:5 | MyVec |
|
||||
| main.rs:1799:9:1799:11 | vec | T | main.rs:1759:5:1760:13 | S |
|
||||
| main.rs:1799:13:1799:13 | 0 | | {EXTERNAL LOCATION} | i32 |
|
||||
| main.rs:1801:13:1801:14 | xs | | file://:0:0:0:0 | [] |
|
||||
| main.rs:1801:13:1801:14 | xs | | file://:0:0:0:0 | [] |
|
||||
| main.rs:1801:13:1801:14 | xs | [T;...] | main.rs:1759:5:1760:13 | S |
|
||||
| main.rs:1801:13:1801:14 | xs | [T] | main.rs:1759:5:1760:13 | S |
|
||||
| main.rs:1801:21:1801:21 | 1 | | {EXTERNAL LOCATION} | i32 |
|
||||
| main.rs:1801:26:1801:28 | [...] | | file://:0:0:0:0 | [] |
|
||||
| main.rs:1801:26:1801:28 | [...] | | file://:0:0:0:0 | [] |
|
||||
| main.rs:1801:26:1801:28 | [...] | [T;...] | main.rs:1759:5:1760:13 | S |
|
||||
| main.rs:1801:26:1801:28 | [...] | [T] | main.rs:1759:5:1760:13 | S |
|
||||
| main.rs:1801:27:1801:27 | S | | main.rs:1759:5:1760:13 | S |
|
||||
| main.rs:1802:13:1802:13 | x | | main.rs:1759:5:1760:13 | S |
|
||||
| main.rs:1802:17:1802:18 | xs | | file://:0:0:0:0 | [] |
|
||||
| main.rs:1802:17:1802:18 | xs | | file://:0:0:0:0 | [] |
|
||||
| main.rs:1802:17:1802:18 | xs | [T;...] | main.rs:1759:5:1760:13 | S |
|
||||
| main.rs:1802:17:1802:18 | xs | [T] | main.rs:1759:5:1760:13 | S |
|
||||
| main.rs:1802:17:1802:21 | xs[0] | | main.rs:1759:5:1760:13 | S |
|
||||
| main.rs:1802:17:1802:27 | ... .foo() | | main.rs:1759:5:1760:13 | S |
|
||||
| main.rs:1802:20:1802:20 | 0 | | {EXTERNAL LOCATION} | i32 |
|
||||
| main.rs:1804:23:1804:25 | &xs | | file://:0:0:0:0 | & |
|
||||
| main.rs:1804:23:1804:25 | &xs | &T | file://:0:0:0:0 | [] |
|
||||
| main.rs:1804:23:1804:25 | &xs | &T | file://:0:0:0:0 | [] |
|
||||
| main.rs:1804:23:1804:25 | &xs | &T.[T;...] | main.rs:1759:5:1760:13 | S |
|
||||
| main.rs:1804:23:1804:25 | &xs | &T.[T] | main.rs:1759:5:1760:13 | S |
|
||||
| main.rs:1804:24:1804:25 | xs | | file://:0:0:0:0 | [] |
|
||||
| main.rs:1804:24:1804:25 | xs | | file://:0:0:0:0 | [] |
|
||||
| main.rs:1804:24:1804:25 | xs | [T;...] | main.rs:1759:5:1760:13 | S |
|
||||
| main.rs:1804:24:1804:25 | xs | [T] | main.rs:1759:5:1760:13 | S |
|
||||
| main.rs:1810:5:1810:20 | ...::f(...) | | main.rs:67:5:67:21 | Foo |
|
||||
| main.rs:1811:5:1811:60 | ...::g(...) | | main.rs:67:5:67:21 | Foo |
|
||||
| main.rs:1811:20:1811:38 | ...::Foo {...} | | main.rs:67:5:67:21 | Foo |
|
||||
| main.rs:1811:41:1811:59 | ...::Foo {...} | | main.rs:67:5:67:21 | Foo |
|
||||
| main.rs:1827:5:1827:15 | ...::f(...) | | {EXTERNAL LOCATION} | trait Future |
|
||||
testFailures
|
||||
|
||||
@@ -55,10 +55,13 @@ module TypeTest implements TestSig {
|
||||
exists(AstNode n, TypePath path, Type t |
|
||||
t = TypeInference::inferType(n, path) and
|
||||
location = n.getLocation() and
|
||||
element = n.toString() and
|
||||
if path.isEmpty()
|
||||
then value = element + ":" + t
|
||||
else value = element + ":" + path.toString() + "." + t.toString()
|
||||
|
|
||||
element = n.toString()
|
||||
or
|
||||
element = n.(IdentPat).getName().getText()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user