Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 6 additions & 11 deletions rust/ql/lib/codeql/rust/internal/TypeInference.qll
Original file line number Diff line number Diff line change
Expand Up @@ -578,14 +578,9 @@ private module CallExprBaseMatchingInput implements MatchingInputSig {
}

Declaration getTarget() {
result =
[
CallExprImpl::getResolvedFunction(this).(AstNode),
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note, this line calls getResolvedFunction and casts to AstNode. The next line calls getResolvedFunction and calls to Struct. Seems like the later will always be included in the former.

this.(CallExpr).getStruct(),
this.(CallExpr).getVariant(),
// mutual recursion; resolving method calls requires resolving types and vice versa
resolveMethodCallExpr(this)
]
result = CallExprImpl::getResolvedFunction(this)
or
result = resolveMethodCallExpr(this) // mutual recursion; resolving method calls requires resolving types and vice versa
}
}

Expand Down Expand Up @@ -908,7 +903,7 @@ private module Cached {
}

/**
* Gets a method that the method call `mce` infers to, if any.
* Gets a method that the method call `mce` resolves to, if any.
*/
cached
Function resolveMethodCallExpr(MethodCallExpr mce) {
Expand All @@ -922,7 +917,7 @@ private module Cached {
}

/**
* Gets the record field that the field expression `fe` infers to, if any.
* Gets the record field that the field expression `fe` resolves to, if any.
*/
cached
RecordField resolveRecordFieldExpr(FieldExpr fe) {
Expand All @@ -938,7 +933,7 @@ private module Cached {
}

/**
* Gets the tuple field that the field expression `fe` infers to, if any.
* Gets the tuple field that the field expression `fe` resolves to, if any.
*/
cached
TupleField resolveTupleFieldExpr(FieldExpr fe) {
Expand Down
124 changes: 97 additions & 27 deletions rust/ql/test/library-tests/type-inference/main.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,69 @@
mod m1 {
mod field_access {
#[derive(Debug)]
struct S;

#[derive(Debug)]
struct MyThing {
a: S,
}

#[derive(Debug)]
enum MyOption<T> {
MyNone(),
MySome(T),
}

#[derive(Debug)]
struct GenericThing<A> {
a: A,
}

struct OptionS {
a: MyOption<S>,
}

fn simple_field_access() {
let x = MyThing { a: S };
println!("{:?}", x.a);
}

fn generic_field_access() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do all the expressions in this test have correctly inferred types (I didn't bother to check the .expected file)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe so, yes :)

// Explicit type argument
let x = GenericThing::<S> { a: S };
println!("{:?}", x.a);

// Implicit type argument
let y = GenericThing { a: S };
println!("{:?}", x.a);

// The type of the field `a` can only be infered from the concrete type
// in the struct declaration.
let x = OptionS {
a: MyOption::MyNone(),
};
println!("{:?}", x.a);

// The type of the field `a` can only be infered from the type argument
let x = GenericThing::<MyOption<S>> {
a: MyOption::MyNone(),
};
println!("{:?}", x.a);

let mut x = GenericThing {
a: MyOption::MyNone(),
};
// Only after this access can we infer the type parameter of `x`
let a: MyOption<S> = x.a;
println!("{:?}", a);
}

pub fn f() {
simple_field_access();
generic_field_access();
}
}

mod method_impl {
pub struct Foo {}

impl Foo {
Expand All @@ -25,7 +90,7 @@ mod m1 {
}
}

mod m2 {
mod method_non_parametric_impl {
#[derive(Debug)]
struct MyThing<A> {
a: A,
Expand Down Expand Up @@ -58,6 +123,10 @@ mod m2 {
let x = MyThing { a: S1 };
let y = MyThing { a: S2 };

// simple field access
println!("{:?}", x.a);
println!("{:?}", y.a);

println!("{:?}", x.m1()); // missing call target
println!("{:?}", y.m1().a); // missing call target

Expand All @@ -69,7 +138,7 @@ mod m2 {
}
}

mod m3 {
mod method_non_parametric_trait_impl {
#[derive(Debug)]
struct MyThing<A> {
a: A,
Expand Down Expand Up @@ -122,7 +191,7 @@ mod m3 {
}
}

mod m4 {
mod function_trait_bounds {
#[derive(Debug)]
struct MyThing<A> {
a: A,
Expand Down Expand Up @@ -175,7 +244,7 @@ mod m4 {
}
}

mod m5 {
mod trait_associated_type {
trait MyTrait {
type AssociatedType;

Expand Down Expand Up @@ -210,7 +279,7 @@ mod m5 {
}
}

mod m6 {
mod generic_enum {
#[derive(Debug)]
enum MyEnum<A> {
C1(A),
Expand Down Expand Up @@ -240,7 +309,7 @@ mod m6 {
}
}

mod m7 {
mod method_supertraits {
#[derive(Debug)]
struct MyThing<A> {
a: A,
Expand Down Expand Up @@ -325,7 +394,7 @@ mod m7 {
}
}

mod m8 {
mod function_trait_bounds_2 {
use std::convert::From;
use std::fmt::Debug;

Expand Down Expand Up @@ -374,7 +443,7 @@ mod m8 {
}
}

mod m9 {
mod option_methods {
#[derive(Debug)]
enum MyOption<T> {
MyNone(),
Expand Down Expand Up @@ -456,7 +525,7 @@ mod m9 {
}
}

mod m10 {
mod method_call_type_conversion {

#[derive(Debug, Copy, Clone)]
struct S<T>(T);
Expand Down Expand Up @@ -508,7 +577,7 @@ mod m10 {
}
}

mod m11 {
mod trait_implicit_self_borrow {
trait MyTrait {
fn foo(&self) -> &Self;

Expand All @@ -531,7 +600,7 @@ mod m11 {
}
}

mod m12 {
mod implicit_self_borrow {
struct S;

struct MyStruct<T>(T);
Expand All @@ -548,7 +617,7 @@ mod m12 {
}
}

mod m13 {
mod borrowed_typed {
struct S;

impl S {
Expand Down Expand Up @@ -578,18 +647,19 @@ mod m13 {
}

fn main() {
m1::f();
m1::g(m1::Foo {}, m1::Foo {});
m2::f();
m3::f();
m4::f();
m5::f();
m6::f();
m7::f();
m8::f();
m9::f();
m10::f();
m11::f();
m12::f();
m13::f();
field_access::f();
method_impl::f();
method_impl::g(method_impl::Foo {}, method_impl::Foo {});
method_non_parametric_impl::f();
method_non_parametric_trait_impl::f();
function_trait_bounds::f();
trait_associated_type::f();
generic_enum::f();
method_supertraits::f();
function_trait_bounds_2::f();
option_methods::f();
method_call_type_conversion::f();
trait_implicit_self_borrow::f();
implicit_self_borrow::f();
borrowed_typed::f();
}
Loading