Skip to content

Commit 22407ca

Browse files
committed
Rust: Add type inference test for non-universal impl blocks
1 parent 1770f56 commit 22407ca

File tree

1 file changed

+191
-22
lines changed
  • rust/ql/test/library-tests/type-inference

1 file changed

+191
-22
lines changed

rust/ql/test/library-tests/type-inference/main.rs

Lines changed: 191 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ mod method_non_parametric_impl {
130130
println!("{:?}", y.a); // $ fieldof=MyThing
131131

132132
println!("{:?}", x.m1()); // $ MISSING: method=MyThing<S1>::m1
133-
println!("{:?}", y.m1().a); // $ MISSING: method=MyThing<S2>::m1, field=MyThing
133+
println!("{:?}", y.m1().a); // $ MISSING: method=MyThing<S2>::m1 fieldof=MyThing
134134

135135
let x = MyThing { a: S1 };
136136
let y = MyThing { a: S2 };
@@ -141,15 +141,23 @@ mod method_non_parametric_impl {
141141
}
142142

143143
mod method_non_parametric_trait_impl {
144-
#[derive(Debug)]
144+
#[derive(Debug, Clone, Copy)]
145145
struct MyThing<A> {
146146
a: A,
147147
}
148148

149-
#[derive(Debug)]
149+
#[derive(Debug, Clone, Copy)]
150+
struct MyPair<P1, P2> {
151+
p1: P1,
152+
p2: P2,
153+
}
154+
155+
#[derive(Debug, Clone, Copy)]
150156
struct S1;
151-
#[derive(Debug)]
157+
#[derive(Debug, Clone, Copy)]
152158
struct S2;
159+
#[derive(Debug, Clone, Copy, Default)]
160+
struct S3;
153161

154162
trait MyTrait<A> {
155163
fn m1(self) -> A;
@@ -162,6 +170,13 @@ mod method_non_parametric_trait_impl {
162170
}
163171
}
164172

173+
trait MyProduct<A, B> {
174+
// MyProduct::fst
175+
fn fst(self) -> A;
176+
// MyProduct::snd
177+
fn snd(self) -> B;
178+
}
179+
165180
fn call_trait_m1<T1, T2: MyTrait<T1>>(x: T2) -> T1 {
166181
x.m1() // $ method=m1
167182
}
@@ -180,18 +195,170 @@ mod method_non_parametric_trait_impl {
180195
}
181196
}
182197

198+
// Implementation where the type parameter `TD` only occurs in the
199+
// implemented trait and not the implementing type.
200+
impl<TD> MyTrait<TD> for MyThing<S3>
201+
where
202+
TD: Default,
203+
{
204+
// MyThing<S3>::m1
205+
fn m1(self) -> TD {
206+
TD::default()
207+
}
208+
}
209+
210+
impl<I> MyTrait<I> for MyPair<I, S1> {
211+
// MyTrait<I>::m1
212+
fn m1(self) -> I {
213+
self.p1 // $ fieldof=MyPair
214+
}
215+
}
216+
217+
impl MyTrait<S3> for MyPair<S1, S2> {
218+
// MyTrait<S3>::m1
219+
fn m1(self) -> S3 {
220+
S3
221+
}
222+
}
223+
224+
impl<TT> MyTrait<TT> for MyPair<MyThing<TT>, S3> {
225+
// MyTrait<TT>::m1
226+
fn m1(self) -> TT {
227+
let alpha = self.p1; // $ fieldof=MyPair
228+
alpha.a // $ fieldof=MyThing
229+
}
230+
}
231+
232+
// This implementation only applies if the two type parameters are equal.
233+
impl<A> MyProduct<A, A> for MyPair<A, A> {
234+
// MyPair<A,A>::fst
235+
fn fst(self) -> A {
236+
self.p1 // $ fieldof=MyPair
237+
}
238+
239+
// MyPair<A,A>::snd
240+
fn snd(self) -> A {
241+
self.p2 // $ fieldof=MyPair
242+
}
243+
}
244+
245+
// This implementation swaps the type parameters.
246+
impl MyProduct<S1, S2> for MyPair<S2, S1> {
247+
// MyPair<S2,S1>::fst
248+
fn fst(self) -> S1 {
249+
self.p2 // $ fieldof=MyPair
250+
}
251+
252+
// MyPair<S2,S1>::snd
253+
fn snd(self) -> S2 {
254+
self.p1 // $ fieldof=MyPair
255+
}
256+
}
257+
258+
fn get_fst<V1, V2, P: MyProduct<V1, V2>>(p: P) -> V1 {
259+
p.fst() // $ method=MyProduct::fst
260+
}
261+
262+
fn get_snd<V1, V2, P: MyProduct<V1, V2>>(p: P) -> V2 {
263+
p.snd() // $ method=MyProduct::snd
264+
}
265+
266+
fn get_snd_fst<V0, V1, V2, P: MyProduct<V1, V2>>(p: MyPair<V0, P>) -> V1 {
267+
p.p2.fst() // $ fieldof=MyPair method=MyProduct::fst
268+
}
269+
270+
trait ConvertTo<T> {
271+
// ConvertTo::convert_to
272+
fn convert_to(self) -> T;
273+
}
274+
275+
impl<T: MyTrait<S1>> ConvertTo<S1> for T {
276+
// T::convert_to
277+
fn convert_to(self) -> S1 {
278+
self.m1() // $ method=m1
279+
}
280+
}
281+
282+
fn convert_to<TS, T: ConvertTo<TS>>(thing: T) -> TS {
283+
thing.convert_to() // $ method=ConvertTo::convert_to
284+
}
285+
286+
fn type_bound_type_parameter_impl<TP: MyTrait<S1>>(thing: TP) -> S1 {
287+
// The trait bound on `TP` makes the implementation of `ConvertTo` valid
288+
thing.convert_to() // $ MISSING: method=T::convert_to
289+
}
290+
183291
pub fn f() {
184-
let x = MyThing { a: S1 };
185-
let y = MyThing { a: S2 };
292+
let thing_s1 = MyThing { a: S1 };
293+
let thing_s2 = MyThing { a: S2 };
294+
let thing_s3 = MyThing { a: S3 };
186295

187-
println!("{:?}", x.m1()); // $ MISSING: method=MyThing<S1>::m1
188-
println!("{:?}", y.m1().a); // $ MISSING: method=MyThing<S2>::m1, field=MyThing
296+
// Tests for method resolution
189297

190-
let x = MyThing { a: S1 };
191-
let y = MyThing { a: S2 };
298+
println!("{:?}", thing_s1.m1()); // $ MISSING: method=MyThing<S1>::m1
299+
println!("{:?}", thing_s2.m1().a); // $ MISSING: method=MyThing<S2>::m1 fieldof=MyThing
300+
let s3: S3 = thing_s3.m1(); // $ MISSING: method=MyThing<S3>::m1
301+
println!("{:?}", s3);
302+
303+
let p1 = MyPair { p1: S1, p2: S1 };
304+
println!("{:?}", p1.m1()); // $ MISSING: method=MyTrait<I>::m1
192305

193-
println!("{:?}", call_trait_m1(x)); // MISSING: type=call_trait_m1(...):S1
194-
println!("{:?}", call_trait_m1(y).a); // MISSING: field=MyThing
306+
let p2 = MyPair { p1: S1, p2: S2 };
307+
println!("{:?}", p2.m1()); // $ MISSING: method=MyTrait<S3>::m1
308+
309+
let p3 = MyPair {
310+
p1: MyThing { a: S1 },
311+
p2: S3,
312+
};
313+
println!("{:?}", p3.m1()); // $ MISSING: method=MyTrait<TT>::m1
314+
315+
// These calls go to the first implementation of `MyProduct` for `MyPair`
316+
let a = MyPair { p1: S1, p2: S1 };
317+
let x = a.fst(); // $ method=MyPair<A,A>::fst
318+
println!("{:?}", x);
319+
let y = a.snd(); // $ method=MyPair<A,A>::snd
320+
println!("{:?}", y);
321+
322+
// These calls go to the last implementation of `MyProduct` for
323+
// `MyPair`. The first implementation does not apply as the type
324+
// parameters of the implementation enforce that the two generics must
325+
// be equal.
326+
let b = MyPair { p1: S2, p2: S1 };
327+
let x = b.fst(); // $ MISSING: method=MyPair<S2,S1>::fst SPURIOUS: method=MyPair<A,A>::fst
328+
println!("{:?}", x);
329+
let y = b.snd(); // $ MISSING: method=MyPair<S2,S1>::snd SPURIOUS: method=MyPair<A,A>::snd
330+
println!("{:?}", y);
331+
332+
// Tests for inference of type parameters based on trait implementations.
333+
334+
let x = call_trait_m1(thing_s1); // $ MISSING: type=x:S1
335+
println!("{:?}", x);
336+
let y = call_trait_m1(thing_s2); // $ MISSING: type=y:MyThing type=y.A:S2
337+
println!("{:?}", y.a); // $ MISSING: fieldof=MyThing
338+
339+
// First implementation
340+
let a = MyPair { p1: S1, p2: S1 };
341+
let x = get_fst(a); // $ type=x:S1
342+
println!("{:?}", x);
343+
let y = get_snd(a); // $ type=y:S1
344+
println!("{:?}", y);
345+
346+
// Second implementation
347+
let b = MyPair { p1: S2, p2: S1 };
348+
let x = get_fst(b); // $ type=x:S1 SPURIOUS: type=x:S2
349+
println!("{:?}", x);
350+
let y = get_snd(b); // $ type=y:S2 SPURIOUS: type=y:S1
351+
println!("{:?}", y);
352+
353+
let c = MyPair {
354+
p1: S3,
355+
p2: MyPair { p1: S2, p2: S1 },
356+
};
357+
let x = get_snd_fst(c); // $ type=x:S1 SPURIOUS: type=x:S2
358+
359+
let thing = MyThing { a: S1 };
360+
let i = thing.convert_to(); // $ MISSING: type=i:S1 MISSING: method=T::convert_to
361+
let j = convert_to(thing); // $ MISSING: type=j:S1
195362
}
196363
}
197364

@@ -219,13 +386,13 @@ mod type_parameter_bounds {
219386
fn call_first_trait_per_bound<I: Debug, T: SecondTrait<I>>(x: T) {
220387
// The type parameter bound determines which method this call is resolved to.
221388
let s1 = x.method(); // $ method=SecondTrait::method
222-
println!("{:?}", s1);
389+
println!("{:?}", s1); // $ type=s1:I
223390
}
224391

225392
fn call_second_trait_per_bound<I: Debug, T: SecondTrait<I>>(x: T) {
226393
// The type parameter bound determines which method this call is resolved to.
227394
let s2 = x.method(); // $ method=SecondTrait::method
228-
println!("{:?}", s2);
395+
println!("{:?}", s2); // $ type=s2:I
229396
}
230397

231398
fn trait_bound_with_type<T: FirstTrait<S1>>(x: T) {
@@ -235,7 +402,7 @@ mod type_parameter_bounds {
235402

236403
fn trait_per_bound_with_type<T: FirstTrait<S1>>(x: T) {
237404
let s = x.method(); // $ method=FirstTrait::method
238-
println!("{:?}", s);
405+
println!("{:?}", s); // $ type=s:S1
239406
}
240407

241408
trait Pair<P1, P2> {
@@ -323,8 +490,10 @@ mod function_trait_bounds {
323490
a: MyThing { a: S2 },
324491
};
325492

326-
println!("{:?}", call_trait_thing_m1(x3));
327-
println!("{:?}", call_trait_thing_m1(y3));
493+
let a = call_trait_thing_m1(x3); // $ type=a:S1
494+
println!("{:?}", a);
495+
let b = call_trait_thing_m1(y3); // $ type=b:S2
496+
println!("{:?}", b);
328497
}
329498
}
330499

@@ -584,14 +753,14 @@ mod method_supertraits {
584753
let x = MyThing { a: S1 };
585754
let y = MyThing { a: S2 };
586755

587-
println!("{:?}", x.m2()); // $ method=m2
588-
println!("{:?}", y.m2()); // $ method=m2
756+
println!("{:?}", x.m2()); // $ method=m2 type=x.m2():S1
757+
println!("{:?}", y.m2()); // $ method=m2 type=y.m2():S2
589758

590759
let x = MyThing2 { a: S1 };
591760
let y = MyThing2 { a: S2 };
592761

593-
println!("{:?}", x.m3()); // $ method=m3
594-
println!("{:?}", y.m3()); // $ method=m3
762+
println!("{:?}", x.m3()); // $ method=m3 type=x.m3():S1
763+
println!("{:?}", y.m3()); // $ method=m3 type=y.m3():S2
595764
}
596765
}
597766

@@ -767,7 +936,7 @@ mod option_methods {
767936
println!("{:?}", x4);
768937

769938
let x5 = MyOption::MySome(MyOption::<S>::MyNone());
770-
println!("{:?}", x5.flatten()); // MISSING: method=flatten
939+
println!("{:?}", x5.flatten()); // $ MISSING: method=flatten
771940

772941
let x6 = MyOption::MySome(MyOption::<S>::MyNone());
773942
println!("{:?}", MyOption::<MyOption<S>>::flatten(x6));

0 commit comments

Comments
 (0)