Rust: Use verbose type paths in inline expectation comments

This commit is contained in:
Tom Hvitved
2026-04-30 13:33:32 +02:00
parent 68be006a29
commit e1cd708c75
8 changed files with 153 additions and 129 deletions

View File

@@ -131,9 +131,9 @@ mod default_method_using_associated_type {
println!("{:?}", y);
let x5 = S2;
println!("{:?}", x5.m1()); // $ target=m1 type=x5.m1():A.S2
println!("{:?}", x5.m1()); // $ target=m1 type=x5.m1()@Wrapper<A>:S2
let x6 = S2;
println!("{:?}", x6.m2()); // $ target=m2 type=x6.m2():A.S2
println!("{:?}", x6.m2()); // $ target=m2 type=x6.m2()@Wrapper<A>:S2
}
}
@@ -400,10 +400,10 @@ mod generic_associated_type {
pub fn test() {
let s = S;
// Call to the method in `impl` block
let _g1 = s.put(1i32); // $ target=S::put type=_g1:A.i32
let _g1 = s.put(1i32); // $ target=S::put type=_g1@Wrapper<A>:i32
// Call to default implementation in `trait` block
let _g2 = s.put_two(true, false); // $ target=MyTraitAssoc2::put_two MISSING: type=_g2:A.bool
let _g2 = s.put_two(true, false); // $ target=MyTraitAssoc2::put_two MISSING: type=_g2@Wrapper<A>:bool
}
}
@@ -534,12 +534,12 @@ mod generic_associated_type_name_clash {
type Output = Result<Output, Output>;
fn get(&self) -> Self::Output {
Ok(self.0) // $ fieldof=ST type=Ok(...):Result type=Ok(...):T.Output type=Ok(...):E.Output
Ok(self.0) // $ fieldof=ST type=Ok(...)@Result<T>:Output type=Ok(...)@Result<E>:Output
}
}
pub fn test() {
let _y = ST(true).get(); // $ type=_y:Result type=_y:T.bool type=_y:E.bool target=get
let _y = ST(true).get(); // $ type=_y@Result<T>:bool type=_y@Result<E>:bool target=get
}
}

View File

@@ -46,7 +46,7 @@ impl<T> S<T> {
fn explicit_monomorphic_dereference() {
// Dereference with method call
let a1 = MyIntPointer { value: 34i64 };
let _b1 = a1.deref(); // $ target=MyIntPointer::deref type=_b1:TRef.i64
let _b1 = a1.deref(); // $ target=MyIntPointer::deref type=_b1@&<TRef>:i64
// Dereference with overloaded dereference operator
let a2 = MyIntPointer { value: 34i64 };
@@ -60,7 +60,7 @@ fn explicit_monomorphic_dereference() {
fn explicit_polymorphic_dereference() {
// Explicit dereference with type parameter
let c1 = MySmartPointer { value: 'a' };
let _d1 = c1.deref(); // $ target=MySmartPointer::deref type=_d1:TRef.char
let _d1 = c1.deref(); // $ target=MySmartPointer::deref type=_d1@&<TRef>:char
// Explicit dereference with type parameter
let c2 = MySmartPointer { value: 'a' };
@@ -74,7 +74,7 @@ fn explicit_polymorphic_dereference() {
fn explicit_ref_dereference() {
// Explicit dereference with type parameter
let e1 = &'a';
let _f1 = e1.deref(); // $ target=deref type=_f1:TRef.char
let _f1 = e1.deref(); // $ target=deref type=_f1@&<TRef>:char
// Explicit dereference with type parameter
let e2 = &'a';
@@ -88,7 +88,7 @@ fn explicit_ref_dereference() {
fn explicit_box_dereference() {
// Explicit dereference with type parameter
let g1: Box<char> = Box::new('a'); // $ target=new
let _h1 = g1.deref(); // $ target=deref type=_h1:TRef.char
let _h1 = g1.deref(); // $ target=deref type=_h1@&<TRef>:char
// Explicit dereference with type parameter
let g2: Box<char> = Box::new('a'); // $ target=new
@@ -109,9 +109,9 @@ fn implicit_dereference() {
let _y = x.is_positive(); // $ target=is_positive type=_y:bool
let z = MySmartPointer { value: S(0i64) };
let z_ = z.foo(); // $ target=foo type=z_:TRef.i64
let z_ = z.foo(); // $ target=foo type=z_@&<TRef>:i64
let v = Vec::new(); // $ target=new type=v:T.i32
let v = Vec::new(); // $ target=new type=v@Vec<T>:i32
let mut x = MySmartPointer { value: v };
x.push(0); // $ target=push
}

View File

@@ -34,7 +34,7 @@ mod field_access {
fn generic_field_access() {
// Explicit type argument
let x = GenericThing::<S> { a: S }; // $ certainType=x:A.S
let x = GenericThing::<S> { a: S }; // $ certainType=x@GenericThing<A>:S
println!("{:?}", x.a); // $ fieldof=GenericThing
// Implicit type argument
@@ -427,7 +427,7 @@ mod method_non_parametric_trait_impl {
let x = call_trait_m1(thing_s1); // $ type=x:S1 target=call_trait_m1
println!("{:?}", x);
let y = call_trait_m1(thing_s2); // $ type=y:MyThing type=y:A.S2 target=call_trait_m1
let y = call_trait_m1(thing_s2); // $ type=y:MyThing type=y@MyThing<A>:S2 target=call_trait_m1
println!("{:?}", y.a); // $ fieldof=MyThing
// First implementation
@@ -566,7 +566,7 @@ mod trait_default_self_type_parameter {
// The trait bound on `T` uses the default for `A` which contains `Self`
fn tp_uses_default<S: TraitWithSelfTp>(thing: S) -> i64 {
let _ms = thing.get_a(); // $ target=TraitWithSelfTp::get_a type=_ms:T.S
let _ms = thing.get_a(); // $ target=TraitWithSelfTp::get_a type=_ms@Option<T>:S
0
}
@@ -575,7 +575,7 @@ mod trait_default_self_type_parameter {
fn get_a_through_tp<S: SubTraitOfTraitWithSelfTp>(thing: &S) {
// `thing` is a `TraitWithSelfTp` through the trait hierarchy
let _ms = get_a(thing); // $ target=get_a type=_ms:T.S
let _ms = get_a(thing); // $ target=get_a type=_ms@Option<T>:S
}
struct MyStruct {
@@ -593,7 +593,7 @@ mod trait_default_self_type_parameter {
pub fn test() {
let s = MyStruct { value: 0 };
let _ms = get_a(&s); // $ target=get_a type=_ms:T.MyStruct
let _ms = get_a(&s); // $ target=get_a type=_ms@Option<T>:MyStruct
}
}
@@ -871,7 +871,7 @@ mod method_supertraits {
fn type_param_trait_to_supertrait<T: MyTrait3<S1>>(x: T) {
// Test that `MyTrait3` is a subtrait of `MyTrait1<MyThing<S1>>`
let a = x.m1(); // $ target=MyTrait1::m1 type=a:MyThing type=a:A.S1
let a = x.m1(); // $ target=MyTrait1::m1 type=a@MyThing<A>:S1
println!("{:?}", a);
}
@@ -898,7 +898,7 @@ mod method_supertraits {
let s = call_trait_m1(x); // $ type=s:S1 target=call_trait_m1
let x = MyThing2 { a: S2 };
let s = call_trait_m1(x); // $ type=s:MyThing type=s:A.S2 target=call_trait_m1
let s = call_trait_m1(x); // $ type=s@MyThing<A>:S2 target=call_trait_m1
}
}
@@ -1011,20 +1011,20 @@ mod type_aliases {
println!("{:?}", p1);
// Type can be only inferred from the type alias
let p2: MyPair = PairOption::PairNone(); // $ certainType=p2:Fst.S1 certainType=p2:Snd.S2
let p2: MyPair = PairOption::PairNone(); // $ certainType=p2@PairOption<Fst>:S1 certainType=p2@PairOption<Snd>:S2
println!("{:?}", p2);
// First type from alias, second from constructor
let p3: AnotherPair<_> = PairOption::PairSnd(S3); // $ certainType=p3:Fst.S2
let p3: AnotherPair<_> = PairOption::PairSnd(S3); // $ certainType=p3@PairOption<Fst>:S2
println!("{:?}", p3);
// First type from alias definition, second from argument to alias
let p3: AnotherPair<S3> = PairOption::PairNone(); // $ certainType=p3:Fst.S2 certainType=p3:Snd.S3
let p3: AnotherPair<S3> = PairOption::PairNone(); // $ certainType=p3@PairOption<Fst>:S2 certainType=p3@PairOption<Snd>:S3
println!("{:?}", p3);
g(PairOption::PairSnd(PairOption::PairSnd(S3))); // $ target=g
let x: S7<S2>; // $ certainType=x:Result $ certainType=x:E.S1 $ certainType=x:T.S4 $ certainType=x:T.T41.S2 $ certainType=x:T.T42.S5 $ certainType=x:T.T42.T5.S2
let x: S7<S2>; // $ certainType=x@Result<E>:S1 $ certainType=x@Result<T>:S4 $ certainType=x@Result<T>.S4<T41>:S2 $ certainType=x@Result<T>.S4<T42>:S5 $ certainType=x@Result<T>.S4<T42>.S5<T5>:S2
}
}
@@ -1068,7 +1068,7 @@ mod option_methods {
struct S;
pub fn f() {
let x1 = MyOption::<S>::new(); // $ certainType=x1:T.S target=new
let x1 = MyOption::<S>::new(); // $ certainType=x1@MyOption<T>:S target=new
println!("{:?}", x1);
let mut x2 = MyOption::new(); // $ target=new
@@ -1192,14 +1192,14 @@ mod method_call_type_conversion {
let x7 = S(&S2);
// Non-implicit dereference with nested borrow in order to test that the
// implicit dereference handling doesn't affect nested borrows.
let t = x7.m1(); // $ target=m1 type=t:& type=t:TRef.S2
let t = x7.m1(); // $ target=m1 type=t:& type=t@&<TRef>:S2
println!("{:?}", x7);
let x9: String = "Hello".to_string(); // $ certainType=x9:String target=to_string
// Implicit `String` -> `str` conversion happens via the `Deref` trait:
// https://doc.rust-lang.org/std/string/struct.String.html#deref.
let u = x9.parse::<u32>(); // $ target=parse type=u:T.u32
let u = x9.parse::<u32>(); // $ target=parse type=u@Result<T>:u32
let my_thing = &MyInt { a: 37 };
// implicit borrow of a `&`
@@ -1382,7 +1382,7 @@ mod builtins {
let z = x + y; // $ type=z:i32 target=add
let z = x.abs(); // $ target=abs $ type=z:i32
let c = 'c'; // $ certainType=c:char
let hello = "Hello"; // $ certainType=hello:TRef.str
let hello = "Hello"; // $ certainType=hello@&<TRef>:str
let f = 123.0f64; // $ certainType=f:f64
let t = true; // $ certainType=t:bool
let f = false; // $ certainType=f:bool
@@ -1403,8 +1403,8 @@ mod builtins {
}
}
let x = [1, 2, 3].my_method(); // $ target=my_method type=x:TRef.i32
let x = <[_; 3]>::my_method(&[1, 2, 3]); // $ target=my_method type=x:TRef.i32
let x = [1, 2, 3].my_method(); // $ target=my_method type=x@&<TRef>:i32
let x = <[_; 3]>::my_method(&[1, 2, 3]); // $ target=my_method type=x@&<TRef>:i32
let x = <[i32; 3]>::my_func(); // $ target=my_func type=x:i32
impl<T: Default> MyTrait<T> for [T] {
@@ -1418,8 +1418,8 @@ mod builtins {
}
let s: &[i32] = &[1, 2, 3];
let x = s.my_method(); // $ target=my_method type=x:TRef.i32
let x = <[_]>::my_method(s); // $ target=my_method type=x:TRef.i32
let x = s.my_method(); // $ target=my_method type=x@&<TRef>:i32
let x = <[_]>::my_method(s); // $ target=my_method type=x@&<TRef>:i32
let x = <[i32]>::my_func(); // $ target=my_func type=x:i32
impl<T: Default> MyTrait<T> for (T, i32) {
@@ -1433,8 +1433,8 @@ mod builtins {
}
let p = (42, 7);
let x = p.my_method(); // $ target=my_method type=x:TRef.i32
let x = <(_, _)>::my_method(&p); // $ target=my_method type=x:TRef.i32
let x = p.my_method(); // $ target=my_method type=x@&<TRef>:i32
let x = <(_, _)>::my_method(&p); // $ target=my_method type=x@&<TRef>:i32
let x = <(i32, i32)>::my_func(); // $ target=my_func type=x:i32
impl<T: Default> MyTrait<T> for &T {
@@ -1448,8 +1448,8 @@ mod builtins {
}
let r = &42;
let x = r.my_method(); // $ target=my_method type=x:TRef.i32
let x = <&_>::my_method(&r); // $ target=my_method type=x:TRef.i32
let x = r.my_method(); // $ target=my_method type=x@&<TRef>:i32
let x = <&_>::my_method(&r); // $ target=my_method type=x@&<TRef>:i32
let x = <&i32>::my_func(); // $ target=my_func type=x:i32
impl<T: Default> MyTrait<T> for *mut T {
@@ -1464,8 +1464,8 @@ mod builtins {
let mut v = 42;
let p: *mut i32 = &mut v;
let x = unsafe { p.my_method() }; // $ target=my_method type=x:TRef.i32
let x = unsafe { <*mut _>::my_method(&p) }; // $ target=my_method type=x:TRef.i32
let x = unsafe { p.my_method() }; // $ target=my_method type=x@&<TRef>:i32
let x = unsafe { <*mut _>::my_method(&p) }; // $ target=my_method type=x@&<TRef>:i32
let x = <*mut i32>::my_func(); // $ target=my_func type=x:i32
}
}
@@ -2046,7 +2046,7 @@ mod indexers {
}
pub fn f() {
let mut vec = MyVec::new(); // $ type=vec:T.S target=new
let mut vec = MyVec::new(); // $ type=vec@MyVec<T>:S target=new
vec.push(S); // $ target=push
vec[0].foo(); // $ target=MyVec::index target=foo
@@ -2262,24 +2262,24 @@ mod loops {
for i in [1, 2, 3].map(|x| x + 1) {} // $ target=map target=add type=i:i32
for i in [1, 2, 3].into_iter() {} // $ target=into_iter type=i:i32
let vals1 = [1u8, 2, 3]; // $ type=vals1:TArray.u8
let vals1 = [1u8, 2, 3]; // $ type=vals1@[;]<TArray>:u8
for u in vals1 {} // $ type=u:u8
let vals2 = [1u16; 3]; // $ type=vals2:TArray.u16
let vals2 = [1u16; 3]; // $ type=vals2@[;]<TArray>:u16
for u in vals2 {} // $ type=u:u16
let vals3: [u32; 3] = [1, 2, 3]; // $ certainType=vals3:TArray.u32
let vals3: [u32; 3] = [1, 2, 3]; // $ certainType=vals3@[;]<TArray>:u32
for u in vals3 {} // $ type=u:u32
let vals4: [u64; 3] = [1; 3]; // $ certainType=vals4:TArray.u64
let vals4: [u64; 3] = [1; 3]; // $ certainType=vals4@[;]<TArray>:u64
for u in vals4 {} // $ type=u:u64
let mut strings1 = ["foo", "bar", "baz"]; // $ type=strings1:TArray.TRef.str
for s in &strings1 {} // $ type=s:TRef.TRef.str
for s in &mut strings1 {} // $ type=s:TRefMut.TRef.str
for s in strings1 {} // $ type=s:TRef.str
let mut strings1 = ["foo", "bar", "baz"]; // $ type=strings1@[;]<TArray>.&<TRef>:str
for s in &strings1 {} // $ type=s@&<TRef>.&<TRef>:str
for s in &mut strings1 {} // $ type=s@&mut<TRefMut>.&<TRef>:str
for s in strings1 {} // $ type=s@&<TRef>:str
let strings2 = // $ type=strings2:TArray.String
let strings2 = // $ type=strings2@[;]<TArray>:String
[
String::from("foo"), // $ target=from
String::from("bar"), // $ target=from
@@ -2287,15 +2287,15 @@ mod loops {
];
for s in strings2 {} // $ type=s:String
let strings3 = // $ type=strings3:TRef.TArray.String
let strings3 = // $ type=strings3@&<TRef>.[;]<TArray>:String
&[
String::from("foo"), // $ target=from
String::from("bar"), // $ target=from
String::from("baz"), // $ target=from
];
for s in strings3 {} // $ type=s:TRef.String
for s in strings3 {} // $ type=s@&<TRef>:String
let callables = [MyCallable::new(), MyCallable::new(), MyCallable::new()]; // $ target=new $ type=callables:TArray.MyCallable
let callables = [MyCallable::new(), MyCallable::new(), MyCallable::new()]; // $ target=new $ type=callables@[;]<TArray>:MyCallable
for c // $ type=c:MyCallable
in callables
{
@@ -2305,13 +2305,13 @@ mod loops {
// for loops with ranges
for i in 0..10 {} // $ type=i:i32
for u in [0u8..10] {} // $ type=u:Range type=u:Idx.u8
let range = 0..10; // $ certainType=range:Range type=range:Idx.i32
for u in [0u8..10] {} // $ type=u:Range type=u@Range<Idx>:u8
let range = 0..10; // $ certainType=range:Range type=range@Range<Idx>:i32
for i in range {} // $ type=i:i32
let range_full = ..; // $ certainType=range_full:RangeFull
for i in &[1i64, 2i64, 3i64][range_full] {} // $ target=index MISSING: type=i:TRef.i64
for i in &[1i64, 2i64, 3i64][range_full] {} // $ target=index MISSING: type=i@&<TRef>:i64
let range1 = // $ certainType=range1:Range type=range1:Idx.u16
let range1 = // $ certainType=range1:Range type=range1@Range<Idx>:u16
std::ops::Range {
start: 0u16,
end: 10u16,
@@ -2320,39 +2320,39 @@ mod loops {
// for loops with containers
let vals3 = vec![1, 2, 3]; // $ type=vals3:Vec $ MISSING: type=vals3:T.i32
let vals3 = vec![1, 2, 3]; // $ type=vals3:Vec $ MISSING: type=vals3@Vec<T>:i32
for i in vals3 {} // $ MISSING: type=i:i32
let vals4a: Vec<u16> = [1u16, 2, 3].to_vec(); // $ certainType=vals4a:Vec certainType=vals4a:T.u16
let vals4a: Vec<u16> = [1u16, 2, 3].to_vec(); // $ certainType=vals4a@Vec<T>:u16
for u in vals4a {} // $ type=u:u16
let vals4b = [1u16, 2, 3].to_vec(); // $ MISSING: type=vals4b:Vec type=vals4b:T.u16
let vals4b = [1u16, 2, 3].to_vec(); // $ MISSING: type=vals4b:Vec type=vals4b@Vec<T>:u16
for u in vals4b {} // $ MISSING: type=u:u16
let vals5 = Vec::from([1u32, 2, 3]); // $ certainType=vals5:Vec target=from type=vals5:T.u32
let vals5 = Vec::from([1u32, 2, 3]); // $ target=from type=vals5@Vec<T>:u32
for u in vals5 {} // $ type=u:u32
let vals6: Vec<&u64> = [1u64, 2, 3].iter().collect(); // $ certainType=vals6:Vec certainType=vals6:T.TRef.u64
for u in vals6 {} // $ type=u:TRef.u64
let vals6: Vec<&u64> = [1u64, 2, 3].iter().collect(); // $ certainType=vals6@Vec<T>.&<TRef>:u64
for u in vals6 {} // $ type=u@&<TRef>:u64
let mut vals7 = Vec::new(); // $ target=new certainType=vals7:Vec type=vals7:T.u8
let mut vals7 = Vec::new(); // $ target=new type=vals7@Vec<T>:u8
vals7.push(1u8); // $ target=push
for u in vals7 {} // $ type=u:u8
let matrix1 = vec![vec![1, 2], vec![3, 4]]; // $ type=matrix1:Vec $ MISSING: type=matrix1:T.Vec type=matrix1:T.T.i32
let matrix1 = vec![vec![1, 2], vec![3, 4]]; // $ type=matrix1:Vec $ MISSING: type=matrix1@T:Vec type=matrix1@Vec<T>.Vec<T>:i32
#[rustfmt::skip]
let _ = for row in matrix1 { // $ MISSING: type=row:Vec type=row:T.i32
let _ = for row in matrix1 { // $ MISSING: type=row:Vec type=row@Vec<T>:i32
for cell in row { // $ MISSING: type=cell:i32
}
};
let mut map1 = std::collections::HashMap::new(); // $ target=new type=map1:K.i32 type=map1:V.Box $ MISSING: type=map1:Hashmap type1=map1:V.T.TRef.str
let mut map1 = std::collections::HashMap::new(); // $ target=new type=map1@HashMap<K>:i32 type=map1@HashMap<V>.Box<T>.&<TRef>:str
map1.insert(1, Box::new("one")); // $ target=insert target=new
map1.insert(2, Box::new("two")); // $ target=insert target=new
for key in map1.keys() {} // $ target=keys type=key:TRef.i32
for value in map1.values() {} // $ target=values type=value:TRef.Box type=value:TRef.T.TRef.str
for (key, value) in map1.iter() {} // $ target=iter type=key:TRef.i32 type=value:TRef.Box type=value:TRef.T.TRef.str
for (key, value) in &map1 {} // $ type=key:TRef.i32 type=value:TRef.Box type=value:TRef.T.TRef.str
for key in map1.keys() {} // $ target=keys type=key@&<TRef>:i32
for value in map1.values() {} // $ target=values type=value@&<TRef>.Box<T>.&<TRef>:str
for (key, value) in map1.iter() {} // $ target=iter type=key@&<TRef>:i32 type=value@&<TRef>.Box<T>.&<TRef>:str
for (key, value) in &map1 {} // $ type=key@&<TRef>:i32 type=value@&<TRef>.Box<T>.&<TRef>:str
// while loops
@@ -2398,27 +2398,27 @@ mod explicit_type_args {
}
pub fn f() {
let x1: Option<S1<S2>> = S1::assoc_fun(); // $ certainType=x1:T.T.S2 target=assoc_fun
let x2 = S1::<S2>::assoc_fun(); // $ certainType=x2:T.T.S2 target=assoc_fun
let x3 = S3::assoc_fun(); // $ certainType=x3:T.T.S2 target=assoc_fun
let x4 = S1::<S2>::method(S1::default()); // $ target=method target=default certainType=x4:T.S2
let x5 = S3::method(S1::default()); // $ target=method target=default certainType=x5:T.S2
let x6 = S4::<S2>(Default::default()); // $ type=x6:T4.S2 target=default
let x7 = S4(S2); // $ type=x7:T4.S2
let x8 = S4(0); // $ type=x8:T4.i32
let x9 = S4(S2::default()); // $ type=x9:T4.S2 target=default
let x10 = S5::<S2> // $ certainType=x10:T5.S2
let x1: Option<S1<S2>> = S1::assoc_fun(); // $ certainType=x1@Option<T>.S1<T>:S2 target=assoc_fun
let x2 = S1::<S2>::assoc_fun(); // $ certainType=x2@Option<T>.S1<T>:S2 target=assoc_fun
let x3 = S3::assoc_fun(); // $ certainType=x3@Option<T>.S1<T>:S2 target=assoc_fun
let x4 = S1::<S2>::method(S1::default()); // $ target=method target=default certainType=x4@S1<T>:S2
let x5 = S3::method(S1::default()); // $ target=method target=default certainType=x5@S1<T>:S2
let x6 = S4::<S2>(Default::default()); // $ type=x6@S4<T4>:S2 target=default
let x7 = S4(S2); // $ type=x7@S4<T4>:S2
let x8 = S4(0); // $ type=x8@S4<T4>:i32
let x9 = S4(S2::default()); // $ type=x9@S4<T4>:S2 target=default
let x10 = S5::<S2> // $ certainType=x10@S5<T5>:S2
{
field: Default::default(), // $ target=default
};
let x11 = S5 { field: S2 }; // $ type=x11:T5.S2
let x12 = S5 { field: 0 }; // $ type=x12:T5.i32
let x13 = S5 // $ type=x13:T5.S2
let x11 = S5 { field: S2 }; // $ type=x11@S5<T5>:S2
let x12 = S5 { field: 0 }; // $ type=x12@S5<T5>:i32
let x13 = S5 // $ type=x13@S5<T5>:S2
{
field: S2::default(), // $ target=default
};
let x14 = foo::<i32>(Default::default()); // $ certainType=x14:i32 target=default target=foo
let x15 = S1::<S2>::default(); // $ certainType=x15:T.S2 target=default
let x15 = S1::<S2>::default(); // $ certainType=x15@S1<T>:S2 target=default
}
}
@@ -2454,11 +2454,11 @@ mod tuples {
// `a` and `b` to be inferred.
let a = Default::default(); // $ target=default type=a:i64
let b = Default::default(); // $ target=default type=b:bool
let pair = (a, b); // $ type=pair:T0.i64 type=pair:T1.bool
let pair = (a, b); // $ type=pair@(T_2)<T0>:i64 type=pair@(T_2)<T1>:bool
let i: i64 = pair.0; // $ fieldof=Tuple2
let j: bool = pair.1; // $ fieldof=Tuple2
let pair = [1, 1].into(); // $ type=pair:(T_2) type=pair:T0.i32 type=pair:T1.i32 target=into
let pair = [1, 1].into(); // $ type=pair@(T_2)<T0>:i32 type=pair@(T_2)<T1>:i32 target=into
match pair {
(0, 0) => print!("unexpected"),
_ => print!("expected"),
@@ -2572,7 +2572,7 @@ mod if_expr {
pub fn f(b: bool) -> Box<dyn MyTrait<i32>> {
let x = if b {
let y = Default::default(); // $ target=default
y // $ type=y:T.i32
y // $ type=y@S<T>:i32
} else {
S(2)
};
@@ -2648,14 +2648,14 @@ mod context_typed {
}
pub fn f() {
let x = None; // $ type=x:T.i32
let x = None; // $ type=x@Option<T>:i32
let x: Option<i32> = x;
let x = Option::<i32>::None; // $ type=x:T.i32
let x = Option::None::<i32>; // $ type=x:T.i32
let x = Option::<i32>::None; // $ type=x@Option<T>:i32
let x = Option::None::<i32>; // $ type=x@Option<T>:i32
fn pin_option<T>(opt: Option<T>, x: T) {}
let x = None; // $ type=x:T.i32
let x = None; // $ type=x@Option<T>:i32
pin_option(x, 0); // $ target=pin_option
enum MyEither<T1, T2> {
@@ -2663,33 +2663,33 @@ mod context_typed {
B { right: T2 },
}
let x = MyEither::A { left: 0 }; // $ type=x:T1.i32 type=x:T2.String
let x = MyEither::A { left: 0 }; // $ type=x@MyEither<T1>:i32 type=x@MyEither<T2>:String
let x: MyEither<i32, String> = x;
let x = MyEither::<_, String>::A { left: 0 }; // $ type=x:T1.i32 certainType=x:T2.String
let x = MyEither::<_, String>::A { left: 0 }; // $ type=x@MyEither<T1>:i32 certainType=x@MyEither<T2>:String
#[rustfmt::skip]
let x = MyEither::B::<i32, _> { // $ certainType=x:T1.i32 type=x:T2.String
let x = MyEither::B::<i32, _> { // $ certainType=x@MyEither<T1>:i32 type=x@MyEither<T2>:String
right: String::new(), // $ target=new
};
fn pin_my_either<T>(e: MyEither<T, String>, x: T) {}
#[rustfmt::skip]
let x = MyEither::B { // $ type=x:T1.i32 type=x:T2.String
let x = MyEither::B { // $ type=x@MyEither<T1>:i32 type=x@MyEither<T2>:String
right: String::new(), // $ target=new
};
pin_my_either(x, 0); // $ target=pin_my_either
let x = Result::Ok(0); // $ type=x:E.String
let x = Result::Ok(0); // $ type=x@Result<E>:String
let x: Result<i32, String> = x;
let x = Result::<i32, String>::Ok(0); // $ type=x:E.String
let x = Result::Ok::<i32, String>(0); // $ type=x:E.String
let x = Result::<i32, String>::Ok(0); // $ type=x@Result<E>:String
let x = Result::Ok::<i32, String>(0); // $ type=x@Result<E>:String
fn pin_result<T, E>(res: Result<T, E>, x: E) {}
let x = Result::Ok(0); // $ type=x:T.i32 type=x:E.bool
let x = Result::Ok(0); // $ type=x@Result<T>:i32 type=x@Result<E>:bool
pin_result(x, false); // $ target=pin_result
let mut x = Vec::new(); // $ type=x:T.i32 target=new
let mut x = Vec::new(); // $ type=x@Vec<T>:i32 target=new
x.push(0); // $ target=push
let y = Default::default(); // $ type=y:i32 target=default

View File

@@ -37,18 +37,18 @@ pub fn f() -> Option<()> {
let value3 = 42;
if let ref mesg = value3 {
let mesg = mesg; // $ type=mesg:TRef.i32
let mesg = mesg; // $ type=mesg@&<TRef>:i32
println!("{mesg}");
}
let value4 = Some(42);
if let Some(ref mesg) = value4 {
let mesg = mesg; // $ type=mesg:TRef.i32
let mesg = mesg; // $ type=mesg@&<TRef>:i32
println!("{mesg}");
}
let ref value5 = 42;
let x = value5; // $ type=x:TRef.i32
let x = value5; // $ type=x@&<TRef>:i32
let my_record_struct = MyRecordStruct {
value1: 42,
@@ -102,27 +102,27 @@ pub fn f() -> Option<()> {
) => {
let a = value1; // $ type=a:bool
let b = x; // $ type=b:i32
let c = y; // $ type=c:TRef.str
let c = y; // $ type=c@&<TRef>:str
();
}
_ => (),
}
let opt1 = Some(Default::default()); // $ type=opt1:T.i32 target=default
let opt1 = Some(Default::default()); // $ type=opt1@Option<T>:i32 target=default
#[rustfmt::skip]
let _ = if let Some::<i32>(x) = opt1
{
x; // $ type=x:i32
};
let opt2 = Some(Default::default()); // $ type=opt2:T.i32 target=default
let opt2 = Some(Default::default()); // $ type=opt2@Option<T>:i32 target=default
#[rustfmt::skip]
let _ = if let Option::Some::<i32>(x) = opt2
{
x; // $ type=x:i32
};
let opt3 = Some(Default::default()); // $ type=opt3:T.i32 target=default
let opt3 = Some(Default::default()); // $ type=opt3@Option<T>:i32 target=default
#[rustfmt::skip]
let _ = if let Option::<i32>::Some(x) = opt3
{
@@ -197,7 +197,7 @@ pub fn literal_patterns() {
let string_val = "hello";
match string_val {
"hello" => {
let hello_match = string_val; // $ certainType=hello_match:TRef.str
let hello_match = string_val; // $ certainType=hello_match@&<TRef>:str
println!("String literal: {}", hello_match);
}
_ => {}
@@ -230,7 +230,7 @@ pub fn identifier_patterns() {
// IdentPat with ref
match &value {
ref x => {
let ref_bound = x; // $ type=ref_bound:TRef.TRef.i32
let ref_bound = x; // $ type=ref_bound@&<TRef>.&<TRef>:i32
println!("Reference identifier: {:?}", ref_bound);
}
}
@@ -269,7 +269,7 @@ pub fn identifier_patterns() {
let mut ref_mut_val = 5i32;
match &mut ref_mut_val {
ref mut x => {
let ref_mut_bound = x; // $ type=ref_mut_bound:TRefMut.TRefMut.i32
let ref_mut_bound = x; // $ type=ref_mut_bound@&mut<TRefMut>.&mut<TRefMut>:i32
**ref_mut_bound += 1; // $ target=deref target=add_assign
println!("Ref mut pattern");
}
@@ -341,14 +341,14 @@ pub fn reference_patterns() {
match &mut mutable_value {
&mut ref x => {
let mut_ref_bound = x; // $ type=mut_ref_bound:TRef.i32
let mut_ref_bound = x; // $ type=mut_ref_bound@&<TRef>:i32
println!("Mutable ref pattern: {}", mut_ref_bound);
}
}
match &value {
ref x => {
let ref_pattern = x; // $ type=ref_pattern:TRef.TRef.i32
let ref_pattern = x; // $ type=ref_pattern@&<TRef>.&<TRef>:i32
println!("Reference pattern: {}", ref_pattern);
}
}
@@ -525,7 +525,7 @@ pub fn slice_patterns() {
// SlicePat - Slice patterns
match slice {
[] => {
let empty_slice = slice; // $ certainType=empty_slice:TRef.TSlice.i32
let empty_slice = slice; // $ certainType=empty_slice@&<TRef>.[]<TSlice>:i32
println!("Empty slice: {:?}", empty_slice);
}
[x] => {
@@ -540,7 +540,7 @@ pub fn slice_patterns() {
[first, middle @ .., last] => {
let slice_start = *first; // $ MISSING: type=slice_start:i32
let slice_end = *last; // $ MISSING: type=slice_end:i32
let slice_middle = middle; // $ MISSING: type=slice_middle:TRef.TSlice.i32
let slice_middle = middle; // $ MISSING: type=slice_middle@&<TRef>.[]<TSlice>:i32
println!(
"First: {}, last: {}, middle len: {}",
slice_start,
@@ -717,7 +717,7 @@ pub fn complex_nested_patterns() {
}
// Catch-all with identifier pattern
other => {
let other_complex = other; // $ type=other_complex:T0.Point type=other_complex:T1.MyOption
let other_complex = other; // $ type=other_complex@(T_2)<T0>:Point type=other_complex@(T_2)<T1>:MyOption
println!("Other complex data: {:?}", other_complex);
}
}
@@ -750,7 +750,7 @@ pub fn patterns_in_let_statements() {
// Let with reference pattern
let value = 42i32;
let ref ref_val = value;
let let_ref = ref_val; // $ certainType=let_ref:TRef.i32
let let_ref = ref_val; // $ certainType=let_ref@&<TRef>:i32
// Let with mutable pattern
let mut mut_val = 10i32;
@@ -779,13 +779,13 @@ pub fn patterns_in_function_parameters() {
// Call the functions to use them
let point = Point { x: 5, y: 10 };
let extracted = extract_point(point); // $ target=extract_point certainType=extracted:T0.i32 certainType=extracted:T1.i32
let extracted = extract_point(point); // $ target=extract_point certainType=extracted@(T_2)<T0>:i32 certainType=extracted@(T_2)<T1>:i32
let color = Color(200, 100, 50);
let red = extract_color(color); // $ target=extract_color certainType=red:u8
let tuple = (42i32, 3.14f64, true);
let tuple_extracted = extract_tuple(tuple); // $ target=extract_tuple certainType=tuple_extracted:T0.i32 certainType=tuple_extracted:T1.bool
let tuple_extracted = extract_tuple(tuple); // $ target=extract_tuple certainType=tuple_extracted@(T_2)<T0>:i32 certainType=tuple_extracted@(T_2)<T1>:bool
}
#[rustfmt::skip]

View File

@@ -12,7 +12,7 @@ fn raw_pointer_mut_deref(x: *mut bool) -> i32 {
fn raw_const_borrow() {
let a: i64 = 10;
let x = &raw const a; // $ type=x:TPtrConst.i64
let x = &raw const a; // $ type=x@*const<TPtrConst>:i64
unsafe {
let _y = *x; // $ type=_y:i64
}
@@ -20,7 +20,7 @@ fn raw_const_borrow() {
fn raw_mut_borrow() {
let mut a = 10i32;
let x = &raw mut a; // $ type=x:TPtrMut.i32
let x = &raw mut a; // $ type=x@*mut<TPtrMut>:i32
unsafe {
let _y = *x; // $ type=_y:i32
}
@@ -29,7 +29,7 @@ fn raw_mut_borrow() {
fn raw_mut_write(cond: bool) {
let a = 10i32;
// The type of `ptr_written` must be inferred from the write below.
let ptr_written = null_mut(); // $ target=null_mut type=ptr_written:TPtrMut.i32
let ptr_written = null_mut(); // $ target=null_mut type=ptr_written@*mut<TPtrMut>:i32
if cond {
unsafe {
// NOTE: This write is undefined behavior because `ptr_written` is a null pointer.
@@ -41,7 +41,7 @@ fn raw_mut_write(cond: bool) {
fn raw_type_from_deref(cond: bool) {
// The type of `ptr_read` must be inferred from the read below.
let ptr_read = null_mut(); // $ target=null_mut type=ptr_read:TPtrMut.i64
let ptr_read = null_mut(); // $ target=null_mut type=ptr_read@*mut<TPtrMut>:i64
if cond {
unsafe {
// NOTE: This read is undefined behavior because `ptr_read` is a null pointer.

View File

@@ -149,7 +149,7 @@ mod regression5 {
fn foo() -> S2<S1> {
let x = S1.into(); // $ target=into
x // $ type=x:T2.S1
x // $ type=x@S2<T2>:S1
}
}
@@ -176,6 +176,6 @@ mod regression6 {
}
fn foo() {
let x = S(0) + S(1); // $ target=add1 $ SPURIOUS: target=add2 type=x:T.T.i32
let x = S(0) + S(1); // $ target=add1 $ SPURIOUS: target=add2 type=x@S<T>.S<T>:i32
}
}

View File

@@ -67,7 +67,7 @@ module TypeTest implements TestSig {
predicate hasActualResult(Location location, string element, string tag, string value) { none() }
predicate hasOptionalResult(Location location, string element, string tag, string value) {
exists(AstNode n, TypePath path, Type t |
exists(AstNode n, TypePath path, Type t, string at |
t = TypeInference::inferType(n, path) and
(
tag = "type"
@@ -76,11 +76,8 @@ module TypeTest implements TestSig {
tag = "certainType"
) and
location = n.getLocation() and
(
if path.isEmpty()
then value = element + ":" + t
else value = element + ":" + path.toString() + "." + t.toString()
) and
(if path.isEmpty() then at = "" else at = "@" + TypePath::printTypePathVerbose(path)) and
value = element + at + ":" + t.toString() and
element = [n.toString(), n.(IdentPat).getName().getText()]
)
}

View File

@@ -275,7 +275,34 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
class TypePath = UnboundList;
/** Provides predicates for constructing `TypePath`s. */
module TypePath = UnboundList;
module TypePath {
import UnboundList
private string printTypeParameterVerbose(TypeParameter tp) {
exists(Type t |
t.getATypeParameter() = tp and
result = t.toString() + "<" + tp.toString() + ">"
)
}
/**
* Gets a verbose textual representation of `path`, which includes the names
* of the types that the type parameters belong to.
*
* For example, the verbose textual representation of the path `"T1.T2"` is
* `"S1<T1>.S2<T2>"`, provided that `T1` is a type parameter of `S1` and `T2`
* is a type parameter of `S2`.
*/
bindingset[path]
string printTypePathVerbose(TypePath path) {
result =
concat(int i, TypeParameter e |
e = path.getElement(i)
|
printTypeParameterVerbose(e), "." order by i
)
}
}
/**
* A class that has a type tree associated with it.