~ubuntu-branches/ubuntu/trusty/monodevelop/trusty-proposed

« back to all changes in this revision

Viewing changes to external/nrefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/TypeInferenceTests.cs

  • Committer: Package Import Robot
  • Author(s): Jo Shields
  • Date: 2013-05-12 09:46:03 UTC
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20130512094603-mad323bzcxvmcam0
Tags: upstream-4.0.5+dfsg
ImportĀ upstreamĀ versionĀ 4.0.5+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
ļ»æ// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team
 
2
// 
 
3
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
 
4
// software and associated documentation files (the "Software"), to deal in the Software
 
5
// without restriction, including without limitation the rights to use, copy, modify, merge,
 
6
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
 
7
// to whom the Software is furnished to do so, subject to the following conditions:
 
8
// 
 
9
// The above copyright notice and this permission notice shall be included in all copies or
 
10
// substantial portions of the Software.
 
11
// 
 
12
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 
13
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
 
14
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
 
15
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
 
16
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 
17
// DEALINGS IN THE SOFTWARE.
 
18
 
 
19
using System;
 
20
using System.Collections;
 
21
using System.Collections.Generic;
 
22
using System.Collections.ObjectModel;
 
23
using System.Linq;
 
24
using System.Runtime.CompilerServices;
 
25
using ICSharpCode.NRefactory.Semantics;
 
26
using ICSharpCode.NRefactory.TypeSystem;
 
27
using ICSharpCode.NRefactory.TypeSystem.Implementation;
 
28
using NUnit.Framework;
 
29
 
 
30
namespace ICSharpCode.NRefactory.CSharp.Resolver
 
31
{
 
32
        [TestFixture]
 
33
        public class TypeInferenceTests : ResolverTestBase
 
34
        {
 
35
                TypeInference ti;
 
36
                
 
37
                [SetUp]
 
38
                public void Setup()
 
39
                {
 
40
                        ti = new TypeInference(compilation);
 
41
                }
 
42
                
 
43
                #region Type Inference
 
44
                IType[] Resolve(params Type[] types)
 
45
                {
 
46
                        IType[] r = new IType[types.Length];
 
47
                        for (int i = 0; i < types.Length; i++) {
 
48
                                r[i] = compilation.FindType(types[i]);
 
49
                                Assert.AreNotSame(r[i], SpecialType.UnknownType);
 
50
                        }
 
51
                        Array.Sort(r, (a,b)=>a.ReflectionName.CompareTo(b.ReflectionName));
 
52
                        return r;
 
53
                }
 
54
                
 
55
                [Test]
 
56
                public void ArrayToEnumerable()
 
57
                {
 
58
                        ITypeParameter tp = new DefaultTypeParameter(compilation, EntityType.Method, 0, "T");
 
59
                        IType stringType = compilation.FindType(KnownTypeCode.String);
 
60
                        ITypeDefinition enumerableType = compilation.FindType(KnownTypeCode.IEnumerableOfT).GetDefinition();
 
61
                        
 
62
                        bool success;
 
63
                        Assert.AreEqual(
 
64
                                new [] { stringType },
 
65
                                ti.InferTypeArguments(new [] { tp },
 
66
                                                      new [] { new ResolveResult(new ArrayType(compilation, stringType)) },
 
67
                                                      new [] { new ParameterizedType(enumerableType, new [] { tp }) },
 
68
                                                      out success));
 
69
                        Assert.IsTrue(success);
 
70
                }
 
71
                
 
72
                [Test]
 
73
                public void ArrayToReadOnlyList()
 
74
                {
 
75
                        ITypeParameter tp = new DefaultTypeParameter(compilation, EntityType.Method, 0, "T");
 
76
                        IType stringType = compilation.FindType(KnownTypeCode.String);
 
77
                        ITypeDefinition readOnlyListType = compilation.FindType(KnownTypeCode.IReadOnlyListOfT).GetDefinition();
 
78
                        if (readOnlyListType == null)
 
79
                                Assert.Ignore(".NET 4.5 IReadOnlyList not available");
 
80
                        
 
81
                        bool success;
 
82
                        Assert.AreEqual(
 
83
                                new [] { stringType },
 
84
                                ti.InferTypeArguments(new [] { tp },
 
85
                                                      new [] { new ResolveResult(new ArrayType(compilation, stringType)) },
 
86
                                                      new [] { new ParameterizedType(readOnlyListType, new [] { tp }) },
 
87
                                                      out success));
 
88
                        Assert.IsTrue(success);
 
89
                }
 
90
                
 
91
                [Test]
 
92
                public void EnumerableToArrayInContravariantType()
 
93
                {
 
94
                        ITypeParameter tp = new DefaultTypeParameter(compilation, EntityType.Method, 0, "T");
 
95
                        IType stringType = compilation.FindType(KnownTypeCode.String);
 
96
                        ITypeDefinition enumerableType = compilation.FindType(typeof(IEnumerable<>)).GetDefinition();
 
97
                        ITypeDefinition comparerType = compilation.FindType(typeof(IComparer<>)).GetDefinition();
 
98
                        
 
99
                        var comparerOfIEnumerableOfString = new ParameterizedType(comparerType, new [] { new ParameterizedType(enumerableType, new [] { stringType } ) });
 
100
                        var comparerOfTpArray = new ParameterizedType(comparerType, new [] { new ArrayType(compilation, tp) });
 
101
                        
 
102
                        bool success;
 
103
                        Assert.AreEqual(
 
104
                                new [] { stringType },
 
105
                                ti.InferTypeArguments(new [] { tp },
 
106
                                                      new [] { new ResolveResult(comparerOfIEnumerableOfString) },
 
107
                                                      new [] { comparerOfTpArray },
 
108
                                                      out success));
 
109
                        Assert.IsTrue(success);
 
110
                }
 
111
                
 
112
                [Test]
 
113
                public void InferFromObjectAndFromNullLiteral()
 
114
                {
 
115
                        // M<T>(T a, T b);
 
116
                        ITypeParameter tp = new DefaultTypeParameter(compilation, EntityType.Method, 0, "T");
 
117
                        
 
118
                        // M(new object(), null);
 
119
                        bool success;
 
120
                        Assert.AreEqual(
 
121
                                new [] { compilation.FindType(KnownTypeCode.Object) },
 
122
                                ti.InferTypeArguments(new [] { tp },
 
123
                                                      new [] { new ResolveResult(compilation.FindType(KnownTypeCode.Object)), new ResolveResult(SpecialType.NullType) },
 
124
                                                      new [] { tp, tp },
 
125
                                                      out success));
 
126
                        Assert.IsTrue(success);
 
127
                }
 
128
                
 
129
                [Test]
 
130
                public void ArrayToListWithArrayCovariance()
 
131
                {
 
132
                        ITypeParameter tp = new DefaultTypeParameter(compilation, EntityType.Method, 0, "T");
 
133
                        IType objectType = compilation.FindType(KnownTypeCode.Object);
 
134
                        IType stringType = compilation.FindType(KnownTypeCode.String);
 
135
                        ITypeDefinition listType = compilation.FindType(KnownTypeCode.IListOfT).GetDefinition();
 
136
                        
 
137
                        // void M<T>(IList<T> a, T b);
 
138
                        // M(new string[0], new object());
 
139
                        
 
140
                        bool success;
 
141
                        Assert.AreEqual(
 
142
                                new [] { objectType },
 
143
                                ti.InferTypeArguments(
 
144
                                        new [] { tp },
 
145
                                        new [] { new ResolveResult(new ArrayType(compilation, stringType)), new ResolveResult(objectType) },
 
146
                                        new [] { new ParameterizedType(listType, new [] { tp }), (IType)tp },
 
147
                                        out success));
 
148
                        Assert.IsTrue(success);
 
149
                }
 
150
                
 
151
                [Test]
 
152
                public void IEnumerableCovarianceWithDynamic()
 
153
                {
 
154
                        ITypeParameter tp = new DefaultTypeParameter(compilation, EntityType.Method, 0, "T");
 
155
                        var ienumerableOfT = new ParameterizedType(compilation.FindType(typeof(IEnumerable<>)).GetDefinition(), new[] { tp });
 
156
                        var ienumerableOfString = compilation.FindType(typeof(IEnumerable<string>));
 
157
                        var ienumerableOfDynamic = compilation.FindType(typeof(IEnumerable<ReflectionHelper.Dynamic>));
 
158
                        
 
159
                        // static T M<T>(IEnumerable<T> x, IEnumerable<T> y) {}
 
160
                        // M(IEnumerable<dynamic>, IEnumerable<string>); -> should infer T=dynamic, no ambiguity
 
161
                        // See http://blogs.msdn.com/b/cburrows/archive/2010/04/01/errata-dynamic-conversions-and-overload-resolution.aspx
 
162
                        // for details.
 
163
                        
 
164
                        bool success;
 
165
                        Assert.AreEqual(
 
166
                                new [] { SpecialType.Dynamic },
 
167
                                ti.InferTypeArguments(
 
168
                                        new [] { tp },
 
169
                                        new [] { new ResolveResult(ienumerableOfDynamic), new ResolveResult(ienumerableOfString) },
 
170
                                        new [] { ienumerableOfT, ienumerableOfT },
 
171
                                        out success));
 
172
                        Assert.IsTrue(success);
 
173
                }
 
174
                #endregion
 
175
                
 
176
                #region Inference with Method Groups
 
177
                [Test]
 
178
                public void CannotInferFromMethodParameterTypes()
 
179
                {
 
180
                        // static void M<A, B>(Func<A, B> f) {}
 
181
                        // M(int.Parse); // type inference fails
 
182
                        var A = new DefaultTypeParameter(compilation, EntityType.Method, 0, "A");
 
183
                        var B = new DefaultTypeParameter(compilation, EntityType.Method, 1, "B");
 
184
                        
 
185
                        IType declType = compilation.FindType(typeof(int));
 
186
                        var methods = new MethodListWithDeclaringType(declType, declType.GetMethods(m => m.Name == "Parse"));
 
187
                        var argument = new MethodGroupResolveResult(new TypeResolveResult(declType), "Parse", new[] { methods }, new IType[0]);
 
188
                        
 
189
                        bool success;
 
190
                        ti.InferTypeArguments(new [] { A, B }, new [] { argument },
 
191
                                              new [] { new ParameterizedType(compilation.FindType(typeof(Func<,>)).GetDefinition(), new[] { A, B }) },
 
192
                                              out success);
 
193
                        Assert.IsFalse(success);
 
194
                }
 
195
                
 
196
                [Test]
 
197
                public void InferFromMethodReturnType()
 
198
                {
 
199
                        // static void M<T>(Func<T> f) {}
 
200
                        // M(Console.ReadKey); // type inference produces ConsoleKeyInfo
 
201
                        
 
202
                        var T = new DefaultTypeParameter(compilation, EntityType.Method, 0, "T");
 
203
                        
 
204
                        IType declType = compilation.FindType(typeof(Console));
 
205
                        var methods = new MethodListWithDeclaringType(declType, declType.GetMethods(m => m.Name == "ReadKey"));
 
206
                        var argument = new MethodGroupResolveResult(new TypeResolveResult(declType), "ReadKey", new[] { methods }, new IType[0]);
 
207
                        
 
208
                        bool success;
 
209
                        Assert.AreEqual(
 
210
                                new [] { compilation.FindType(typeof(ConsoleKeyInfo)) },
 
211
                                ti.InferTypeArguments(new [] { T }, new [] { argument },
 
212
                                                      new [] { new ParameterizedType(compilation.FindType(typeof(Func<>)).GetDefinition(), new[] { T }) },
 
213
                                                      out success));
 
214
                        Assert.IsTrue(success);
 
215
                }
 
216
                #endregion
 
217
                
 
218
                #region Inference with Lambda
 
219
                #region MockImplicitLambda
 
220
                sealed class MockImplicitLambda : LambdaResolveResult
 
221
                {
 
222
                        IType[] expectedParameterTypes;
 
223
                        IType inferredReturnType;
 
224
                        IParameter[] parameters;
 
225
                        
 
226
                        public MockImplicitLambda(IType[] expectedParameterTypes, IType inferredReturnType)
 
227
                        {
 
228
                                this.expectedParameterTypes = expectedParameterTypes;
 
229
                                this.inferredReturnType = inferredReturnType;
 
230
                                this.parameters = new IParameter[expectedParameterTypes.Length];
 
231
                                for (int i = 0; i < parameters.Length; i++) {
 
232
                                        // UnknownType because this lambda is implicitly typed
 
233
                                        parameters[i] = new DefaultParameter(SpecialType.UnknownType, "X" + i);
 
234
                                }
 
235
                        }
 
236
                        
 
237
                        public override IList<IParameter> Parameters {
 
238
                                get { return parameters; }
 
239
                        }
 
240
                        
 
241
                        public override Conversion IsValid(IType[] parameterTypes, IType returnType, CSharpConversions conversions)
 
242
                        {
 
243
                                Assert.AreEqual(expectedParameterTypes, parameterTypes);
 
244
                                return conversions.ImplicitConversion(inferredReturnType, returnType);
 
245
                        }
 
246
                        
 
247
                        public override bool IsImplicitlyTyped {
 
248
                                get { return true; }
 
249
                        }
 
250
                        
 
251
                        public override bool IsAnonymousMethod {
 
252
                                get { return false; }
 
253
                        }
 
254
                        
 
255
                        public override bool HasParameterList {
 
256
                                get { return true; }
 
257
                        }
 
258
                        
 
259
                        public override bool IsAsync {
 
260
                                get { return false; }
 
261
                        }
 
262
                        
 
263
                        public override ResolveResult Body {
 
264
                                get { throw new NotImplementedException(); }
 
265
                        }
 
266
                        
 
267
                        public override IType GetInferredReturnType(IType[] parameterTypes)
 
268
                        {
 
269
                                Assert.AreEqual(expectedParameterTypes, parameterTypes, "Parameters types passed to " + this);
 
270
                                return inferredReturnType;
 
271
                        }
 
272
                        
 
273
                        public override string ToString()
 
274
                        {
 
275
                                return "[MockImplicitLambda (" + string.Join<IType>(", ", expectedParameterTypes) + ") => " + inferredReturnType + "]";
 
276
                        }
 
277
                }
 
278
                #endregion
 
279
                
 
280
                [Test]
 
281
                public void TestLambdaInference()
 
282
                {
 
283
                        ITypeParameter[] typeParameters = {
 
284
                                new DefaultTypeParameter(compilation, EntityType.Method, 0, "X"),
 
285
                                new DefaultTypeParameter(compilation, EntityType.Method, 1, "Y"),
 
286
                                new DefaultTypeParameter(compilation, EntityType.Method, 2, "Z")
 
287
                        };
 
288
                        IType[] parameterTypes = {
 
289
                                typeParameters[0],
 
290
                                new ParameterizedType(compilation.FindType(typeof(Func<,>)).GetDefinition(), new[] { typeParameters[0], typeParameters[1] }),
 
291
                                new ParameterizedType(compilation.FindType(typeof(Func<,>)).GetDefinition(), new[] { typeParameters[1], typeParameters[2] })
 
292
                        };
 
293
                        // Signature:  M<X,Y,Z>(X x, Func<X,Y> y, Func<Y,Z> z) {}
 
294
                        // Invocation: M(default(string), s => default(int), t => default(float));
 
295
                        ResolveResult[] arguments = {
 
296
                                new ResolveResult(compilation.FindType(KnownTypeCode.String)),
 
297
                                new MockImplicitLambda(new[] { compilation.FindType(KnownTypeCode.String) }, compilation.FindType(KnownTypeCode.Int32)),
 
298
                                new MockImplicitLambda(new[] { compilation.FindType(KnownTypeCode.Int32) }, compilation.FindType(KnownTypeCode.Single))
 
299
                        };
 
300
                        bool success;
 
301
                        Assert.AreEqual(
 
302
                                new [] {
 
303
                                        compilation.FindType(KnownTypeCode.String),
 
304
                                        compilation.FindType(KnownTypeCode.Int32),
 
305
                                        compilation.FindType(KnownTypeCode.Single)
 
306
                                },
 
307
                                ti.InferTypeArguments(typeParameters, arguments, parameterTypes, out success));
 
308
                        Assert.IsTrue(success);
 
309
                }
 
310
                
 
311
                [Test]
 
312
                public void ConvertAllLambdaInference()
 
313
                {
 
314
                        ITypeParameter[] classTypeParameters  = { new DefaultTypeParameter(compilation, EntityType.TypeDefinition, 0, "T") };
 
315
                        ITypeParameter[] methodTypeParameters = { new DefaultTypeParameter(compilation, EntityType.Method, 0, "R") };
 
316
                        
 
317
                        IType[] parameterTypes = {
 
318
                                new ParameterizedType(compilation.FindType(typeof(Converter<,>)).GetDefinition(),
 
319
                                                      new[] { classTypeParameters[0], methodTypeParameters[0] })
 
320
                        };
 
321
                        
 
322
                        // Signature:  List<T>.ConvertAll<R>(Converter<T, R> converter);
 
323
                        // Invocation: listOfString.ConvertAll(s => default(int));
 
324
                        ResolveResult[] arguments = {
 
325
                                new MockImplicitLambda(new[] { compilation.FindType(KnownTypeCode.String) }, compilation.FindType(KnownTypeCode.Int32))
 
326
                        };
 
327
                        IType[] classTypeArguments = {
 
328
                                compilation.FindType(KnownTypeCode.String)
 
329
                        };
 
330
                        
 
331
                        bool success;
 
332
                        Assert.AreEqual(
 
333
                                new [] { compilation.FindType(KnownTypeCode.Int32) },
 
334
                                ti.InferTypeArguments(methodTypeParameters, arguments, parameterTypes, out success, classTypeArguments));
 
335
                }
 
336
                
 
337
                [Test]
 
338
                public void InferFromImplicitAsyncLambda()
 
339
                {
 
340
                        string program = @"using System;
 
341
using System.Threading.Tasks;
 
342
 
 
343
class Test
 
344
{
 
345
        static T M<T>(Func<int, Task<T>> f)
 
346
        {
 
347
                return f(0);
 
348
        }
 
349
        public static void Test()
 
350
        {
 
351
                $M(async x => x + 1)$;
 
352
        }
 
353
}
 
354
";
 
355
                        var rr = Resolve<CSharpInvocationResolveResult>(program);
 
356
                        Assert.IsFalse(rr.IsError);
 
357
                        Assert.AreEqual("System.Int32", ((IMethod)rr.Member).TypeArguments[0].FullName);
 
358
                }
 
359
                
 
360
                [Test]
 
361
                public void InferFromExplicitAsyncLambda()
 
362
                {
 
363
                        string program = @"using System;
 
364
using System.Threading.Tasks;
 
365
 
 
366
class Test
 
367
{
 
368
        static T M<T>(Func<int, Task<T>> f)
 
369
        {
 
370
                return f(0);
 
371
        }
 
372
        public static void Test()
 
373
        {
 
374
                $M(async (int x) => x + 1)$;
 
375
        }
 
376
}
 
377
";
 
378
                        var rr = Resolve<CSharpInvocationResolveResult>(program);
 
379
                        Assert.IsFalse(rr.IsError);
 
380
                        Assert.AreEqual("System.Int32", ((IMethod)rr.Member).TypeArguments[0].FullName);
 
381
                }
 
382
                #endregion
 
383
                
 
384
                #region FindTypeInBounds
 
385
                IType[] FindAllTypesInBounds(IList<IType> lowerBounds, IList<IType> upperBounds = null)
 
386
                {
 
387
                        ti.Algorithm = TypeInferenceAlgorithm.ImprovedReturnAllResults;
 
388
                        IType type = ti.FindTypeInBounds(lowerBounds, upperBounds ?? new IType[0]);
 
389
                        return ExpandIntersections(type).OrderBy(t => t.ReflectionName).ToArray();
 
390
                }
 
391
                
 
392
                static IEnumerable<IType> ExpandIntersections(IType type)
 
393
                {
 
394
                        IntersectionType it = type as IntersectionType;
 
395
                        if (it != null) {
 
396
                                return it.Types.SelectMany(t => ExpandIntersections(t));
 
397
                        }
 
398
                        ParameterizedType pt = type as ParameterizedType;
 
399
                        if (pt != null) {
 
400
                                IType[][] typeArguments = new IType[pt.TypeArguments.Count][];
 
401
                                for (int i = 0; i < typeArguments.Length; i++) {
 
402
                                        typeArguments[i] = ExpandIntersections(pt.TypeArguments[i]).ToArray();
 
403
                                }
 
404
                                return AllCombinations(typeArguments).Select(ta => new ParameterizedType(pt.GetDefinition(), ta));
 
405
                        }
 
406
                        return new [] { type };
 
407
                }
 
408
                
 
409
                /// <summary>
 
410
                /// Performs the combinatorial explosion.
 
411
                /// </summary>
 
412
                static IEnumerable<IType[]> AllCombinations(IType[][] typeArguments)
 
413
                {
 
414
                        int[] index = new int[typeArguments.Length];
 
415
                        index[typeArguments.Length - 1] = -1;
 
416
                        while (true) {
 
417
                                int i;
 
418
                                for (i = index.Length - 1; i >= 0; i--) {
 
419
                                        if (++index[i] == typeArguments[i].Length)
 
420
                                                index[i] = 0;
 
421
                                        else
 
422
                                                break;
 
423
                                }
 
424
                                if (i < 0)
 
425
                                        break;
 
426
                                IType[] r = new IType[typeArguments.Length];
 
427
                                for (i = 0; i < r.Length; i++) {
 
428
                                        r[i] = typeArguments[i][index[i]];
 
429
                                }
 
430
                                yield return r;
 
431
                        }
 
432
                }
 
433
                
 
434
                [Test]
 
435
                public void ListOfShortAndInt()
 
436
                {
 
437
                        Assert.AreEqual(
 
438
                                Resolve(typeof(IList)),
 
439
                                FindAllTypesInBounds(Resolve(typeof(List<short>), typeof(List<int>))));
 
440
                }
 
441
                
 
442
                [Test]
 
443
                [Ignore("Produces different results in .NET 4.5 due to new read-only interfaces")]
 
444
                public void ListOfStringAndObject()
 
445
                {
 
446
                        Assert.AreEqual(
 
447
                                Resolve(typeof(IList), typeof(IEnumerable<object>)),
 
448
                                FindAllTypesInBounds(Resolve(typeof(List<string>), typeof(List<object>))));
 
449
                }
 
450
                
 
451
                [Test]
 
452
                [Ignore("Produces different results in .NET 4.5 due to new read-only interfaces")]
 
453
                public void ListOfListOfStringAndObject()
 
454
                {
 
455
                        Assert.AreEqual(
 
456
                                Resolve(typeof(IList), typeof(IEnumerable<IList>), typeof(IEnumerable<IEnumerable<object>>)),
 
457
                                FindAllTypesInBounds(Resolve(typeof(List<List<string>>), typeof(List<List<object>>))));
 
458
                }
 
459
                
 
460
                [Test]
 
461
                public void ShortAndInt()
 
462
                {
 
463
                        Assert.AreEqual(
 
464
                                Resolve(typeof(int)),
 
465
                                FindAllTypesInBounds(Resolve(typeof(short), typeof(int))));
 
466
                }
 
467
                
 
468
                [Test]
 
469
                public void StringAndVersion()
 
470
                {
 
471
                        Assert.AreEqual(
 
472
                                Resolve(typeof(ICloneable), typeof(IComparable)),
 
473
                                FindAllTypesInBounds(Resolve(typeof(string), typeof(Version))));
 
474
                }
 
475
                
 
476
                [Test]
 
477
                public void CommonSubTypeClonableComparable()
 
478
                {
 
479
                        Assert.AreEqual(
 
480
                                Resolve(typeof(string), typeof(Version)),
 
481
                                FindAllTypesInBounds(Resolve(), Resolve(typeof(ICloneable), typeof(IComparable))));
 
482
                }
 
483
                
 
484
                [Test]
 
485
                public void EnumerableOfStringAndVersion()
 
486
                {
 
487
                        Assert.AreEqual(
 
488
                                Resolve(typeof(IEnumerable<ICloneable>), typeof(IEnumerable<IComparable>)),
 
489
                                FindAllTypesInBounds(Resolve(typeof(IList<string>), typeof(IList<Version>))));
 
490
                }
 
491
                
 
492
                [Test]
 
493
                public void CommonSubTypeIEnumerableClonableIEnumerableComparable()
 
494
                {
 
495
                        Assert.AreEqual(
 
496
                                Resolve(typeof(IEnumerable<string>), typeof(IEnumerable<Version>)),
 
497
                                FindAllTypesInBounds(Resolve(), Resolve(typeof(IEnumerable<ICloneable>), typeof(IEnumerable<IComparable>))));
 
498
                }
 
499
                
 
500
                [Test]
 
501
                public void CommonSubTypeIEnumerableClonableIEnumerableComparableList()
 
502
                {
 
503
                        Assert.AreEqual(
 
504
                                Resolve(typeof(List<string>), typeof(List<Version>), typeof(Collection<string>), typeof(Collection<Version>),
 
505
                                        typeof(ReadOnlyCollectionBuilder<string>), typeof(ReadOnlyCollectionBuilder<Version>),
 
506
                                        typeof(ReadOnlyCollection<string>), typeof(ReadOnlyCollection<Version>)),
 
507
                                FindAllTypesInBounds(Resolve(), Resolve(typeof(IEnumerable<ICloneable>), typeof(IEnumerable<IComparable>), typeof(IList))));
 
508
                }
 
509
                #endregion
 
510
 
 
511
                [Test]
 
512
                public void NullablePick()
 
513
                {
 
514
                                string program = @"
 
515
interface ICo<out T> {}
 
516
interface IContra<in T> {}
 
517
class Test
 
518
{
 
519
        static T Pick<T> (T? a, T? b)
 
520
        {
 
521
                return a;
 
522
        }
 
523
        public static void Test(int? i, long? l)
 
524
        {
 
525
                $Pick(i, l)$;
 
526
        }
 
527
}
 
528
";
 
529
                        var mrr = Resolve<CSharpInvocationResolveResult>(program);
 
530
                        Assert.AreEqual("System.Int64", mrr.Type.FullName);
 
531
                        Assert.IsFalse(mrr.IsError);
 
532
                }
 
533
                
 
534
                [Test]
 
535
                public void CoContraPick()
 
536
                {
 
537
                        string program = @"
 
538
interface ICo<out T> {}
 
539
interface IContra<in T> {}
 
540
class Test
 
541
{
 
542
        static T Pick<T> (ICo<T> a, IContra<T> b)
 
543
        {
 
544
                return a;
 
545
        }
 
546
        public static void Test(ICo<string> i, IContra<object> l)
 
547
        {
 
548
                $Pick(i, l)$;
 
549
        }
 
550
}
 
551
";
 
552
                        // String and Object are both valid choices; and csc ends up picking object,
 
553
                        // even though the C# specification says it should pick string:
 
554
                        // 7.5.2.11 Fixing - both string and object are in the candidate set;
 
555
                        // string has a conversion to object (the other candidate),
 
556
                        // object doesn't have that; so string should be chosen as the result.
 
557
                        
 
558
                        // We follow the csc behavior.
 
559
                        var mrr = Resolve<CSharpInvocationResolveResult>(program);
 
560
                        Assert.AreEqual("System.Object", mrr.Type.FullName);
 
561
                        Assert.IsFalse(mrr.IsError);
 
562
                }
 
563
                
 
564
                /// <summary>
 
565
                /// Bug 9300 - Unknown Resolve Error
 
566
                /// </summary>
 
567
                [Test]
 
568
                public void TestBug9300()
 
569
                {
 
570
                        string program = @"struct S
 
571
{
 
572
        public static implicit operator string (S s)
 
573
        {
 
574
                return ""a"";
 
575
        }
 
576
}
 
577
 
 
578
interface I<in T>
 
579
{
 
580
}
 
581
 
 
582
class C : I<string>
 
583
{
 
584
        static T Foo<T> (T a, I<T> b)
 
585
        {
 
586
                return a;
 
587
        }
 
588
        
 
589
        public static void Main ()
 
590
        {
 
591
                S s = new S ();
 
592
                I<string> i = new C ();
 
593
                var result = $Foo (s, i)$;
 
594
        }
 
595
}
 
596
";
 
597
                        var mrr = Resolve<CSharpInvocationResolveResult>(program);
 
598
                        Assert.AreEqual("System.String", mrr.Type.FullName);
 
599
                        Assert.IsFalse(mrr.IsError);
 
600
                }
 
601
        }
 
602
}