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

« back to all changes in this revision

Viewing changes to external/nrefactory/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ConversionsTest.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.Linq;
 
23
using ICSharpCode.NRefactory.CSharp.TypeSystem;
 
24
using ICSharpCode.NRefactory.Semantics;
 
25
using ICSharpCode.NRefactory.TypeSystem;
 
26
using ICSharpCode.NRefactory.TypeSystem.Implementation;
 
27
using NUnit.Framework;
 
28
 
 
29
namespace ICSharpCode.NRefactory.CSharp.Resolver
 
30
{
 
31
        // assign short names to the fake reflection types
 
32
        using Null = ICSharpCode.NRefactory.TypeSystem.ReflectionHelper.Null;
 
33
        using dynamic = ICSharpCode.NRefactory.TypeSystem.ReflectionHelper.Dynamic;
 
34
        using C = Conversion;
 
35
        
 
36
        [TestFixture]
 
37
        public unsafe class ConversionsTest : ResolverTestBase
 
38
        {
 
39
                CSharpConversions conversions;
 
40
                
 
41
                public override void SetUp()
 
42
                {
 
43
                        base.SetUp();
 
44
                        conversions = new CSharpConversions(compilation);
 
45
                }
 
46
                
 
47
                Conversion ImplicitConversion(Type from, Type to)
 
48
                {
 
49
                        IType from2 = compilation.FindType(from);
 
50
                        IType to2 = compilation.FindType(to);
 
51
                        return conversions.ImplicitConversion(from2, to2);
 
52
                }
 
53
                
 
54
                [Test]
 
55
                public void IdentityConversions()
 
56
                {
 
57
                        Assert.AreEqual(C.IdentityConversion, ImplicitConversion(typeof(char), typeof(char)));
 
58
                        Assert.AreEqual(C.IdentityConversion, ImplicitConversion(typeof(string), typeof(string)));
 
59
                        Assert.AreEqual(C.IdentityConversion, ImplicitConversion(typeof(object), typeof(object)));
 
60
                        Assert.AreEqual(C.None,               ImplicitConversion(typeof(bool), typeof(char)));
 
61
                        
 
62
                        Assert.AreEqual(C.IdentityConversion, conversions.ImplicitConversion(SpecialType.Dynamic, SpecialType.Dynamic));
 
63
                        Assert.AreEqual(C.IdentityConversion, conversions.ImplicitConversion(SpecialType.UnknownType, SpecialType.UnknownType));
 
64
                        Assert.AreEqual(C.IdentityConversion, conversions.ImplicitConversion(SpecialType.NullType, SpecialType.NullType));
 
65
                }
 
66
                
 
67
                [Test]
 
68
                public void DynamicIdentityConversions()
 
69
                {
 
70
                        Assert.AreEqual(C.IdentityConversion, ImplicitConversion(typeof(object), typeof(dynamic)));
 
71
                        Assert.AreEqual(C.IdentityConversion, ImplicitConversion(typeof(dynamic), typeof(object)));
 
72
                }
 
73
                
 
74
                [Test]
 
75
                public void ComplexDynamicIdentityConversions()
 
76
                {
 
77
                        Assert.AreEqual(C.IdentityConversion, ImplicitConversion(typeof(List<object>), typeof(List<dynamic>)));
 
78
                        Assert.AreEqual(C.IdentityConversion, ImplicitConversion(typeof(List<dynamic>), typeof(List<object>)));
 
79
                        Assert.AreEqual(C.None,               ImplicitConversion(typeof(List<string>), typeof(List<dynamic>)));
 
80
                        Assert.AreEqual(C.None,               ImplicitConversion(typeof(List<dynamic>), typeof(List<string>)));
 
81
                        
 
82
                        Assert.AreEqual(C.IdentityConversion, ImplicitConversion(typeof(List<List<dynamic>[]>), typeof(List<List<object>[]>)));
 
83
                        Assert.AreEqual(C.IdentityConversion, ImplicitConversion(typeof(List<List<object>[]>), typeof(List<List<dynamic>[]>)));
 
84
                        Assert.AreEqual(C.None,               ImplicitConversion(typeof(List<List<object>[,]>), typeof(List<List<dynamic>[]>)));
 
85
                }
 
86
                
 
87
                [Test]
 
88
                public void PrimitiveConversions()
 
89
                {
 
90
                        Assert.AreEqual(C.ImplicitNumericConversion, ImplicitConversion(typeof(char), typeof(ushort)));
 
91
                        Assert.AreEqual(C.None,                      ImplicitConversion(typeof(byte), typeof(char)));
 
92
                        Assert.AreEqual(C.ImplicitNumericConversion, ImplicitConversion(typeof(int), typeof(long)));
 
93
                        Assert.AreEqual(C.None,                      ImplicitConversion(typeof(long), typeof(int)));
 
94
                        Assert.AreEqual(C.ImplicitNumericConversion, ImplicitConversion(typeof(int), typeof(float)));
 
95
                        Assert.AreEqual(C.None,                      ImplicitConversion(typeof(bool), typeof(float)));
 
96
                        Assert.AreEqual(C.ImplicitNumericConversion, ImplicitConversion(typeof(float), typeof(double)));
 
97
                        Assert.AreEqual(C.None,                      ImplicitConversion(typeof(float), typeof(decimal)));
 
98
                        Assert.AreEqual(C.ImplicitNumericConversion, ImplicitConversion(typeof(char), typeof(long)));
 
99
                        Assert.AreEqual(C.ImplicitNumericConversion, ImplicitConversion(typeof(uint), typeof(long)));
 
100
                }
 
101
                
 
102
                [Test]
 
103
                public void EnumerationConversion()
 
104
                {
 
105
                        ResolveResult zero = new ConstantResolveResult(compilation.FindType(KnownTypeCode.Int32), 0);
 
106
                        ResolveResult one = new ConstantResolveResult(compilation.FindType(KnownTypeCode.Int32), 1);
 
107
                        C implicitEnumerationConversion = C.EnumerationConversion(true, false);
 
108
                        Assert.AreEqual(implicitEnumerationConversion, conversions.ImplicitConversion(zero, compilation.FindType(typeof(StringComparison))));
 
109
                        Assert.AreEqual(C.None, conversions.ImplicitConversion(one, compilation.FindType(typeof(StringComparison))));
 
110
                }
 
111
                
 
112
                [Test]
 
113
                public void NullableConversions()
 
114
                {
 
115
                        Assert.AreEqual(C.ImplicitLiftedNumericConversion, ImplicitConversion(typeof(char), typeof(ushort?)));
 
116
                        Assert.AreEqual(C.None,                            ImplicitConversion(typeof(byte), typeof(char?)));
 
117
                        Assert.AreEqual(C.ImplicitLiftedNumericConversion, ImplicitConversion(typeof(int), typeof(long?)));
 
118
                        Assert.AreEqual(C.None,                            ImplicitConversion(typeof(long), typeof(int?)));
 
119
                        Assert.AreEqual(C.ImplicitLiftedNumericConversion, ImplicitConversion(typeof(int), typeof(float?)));
 
120
                        Assert.AreEqual(C.None                           , ImplicitConversion(typeof(bool), typeof(float?)));
 
121
                        Assert.AreEqual(C.ImplicitLiftedNumericConversion, ImplicitConversion(typeof(float), typeof(double?)));
 
122
                        Assert.AreEqual(C.None,                            ImplicitConversion(typeof(float), typeof(decimal?)));
 
123
                }
 
124
                
 
125
                [Test]
 
126
                public void NullableConversions2()
 
127
                {
 
128
                        Assert.AreEqual(C.ImplicitLiftedNumericConversion, ImplicitConversion(typeof(char?), typeof(ushort?)));
 
129
                        Assert.AreEqual(C.None,                            ImplicitConversion(typeof(byte?), typeof(char?)));
 
130
                        Assert.AreEqual(C.ImplicitLiftedNumericConversion, ImplicitConversion(typeof(int?), typeof(long?)));
 
131
                        Assert.AreEqual(C.None,                            ImplicitConversion(typeof(long?), typeof(int?)));
 
132
                        Assert.AreEqual(C.ImplicitLiftedNumericConversion, ImplicitConversion(typeof(int?), typeof(float?)));
 
133
                        Assert.AreEqual(C.None,                            ImplicitConversion(typeof(bool?), typeof(float?)));
 
134
                        Assert.AreEqual(C.ImplicitLiftedNumericConversion, ImplicitConversion(typeof(float?), typeof(double?)));
 
135
                        Assert.AreEqual(C.None,                            ImplicitConversion(typeof(float?), typeof(decimal?)));
 
136
                }
 
137
                
 
138
                [Test]
 
139
                public void NullLiteralConversions()
 
140
                {
 
141
                        Assert.AreEqual(C.NullLiteralConversion, ImplicitConversion(typeof(Null), typeof(int?)));
 
142
                        Assert.AreEqual(C.NullLiteralConversion, ImplicitConversion(typeof(Null), typeof(char?)));
 
143
                        Assert.AreEqual(C.None,                  ImplicitConversion(typeof(Null), typeof(int)));
 
144
                        Assert.AreEqual(C.NullLiteralConversion, ImplicitConversion(typeof(Null), typeof(object)));
 
145
                        Assert.AreEqual(C.NullLiteralConversion, ImplicitConversion(typeof(Null), typeof(dynamic)));
 
146
                        Assert.AreEqual(C.NullLiteralConversion, ImplicitConversion(typeof(Null), typeof(string)));
 
147
                        Assert.AreEqual(C.NullLiteralConversion, ImplicitConversion(typeof(Null), typeof(int[])));
 
148
                }
 
149
                
 
150
                [Test]
 
151
                public void SimpleReferenceConversions()
 
152
                {
 
153
                        Assert.AreEqual(C.ImplicitReferenceConversion, ImplicitConversion(typeof(string), typeof(object)));
 
154
                        Assert.AreEqual(C.ImplicitReferenceConversion, ImplicitConversion(typeof(BitArray), typeof(ICollection)));
 
155
                        Assert.AreEqual(C.ImplicitReferenceConversion, ImplicitConversion(typeof(IList), typeof(IEnumerable)));
 
156
                        Assert.AreEqual(C.None, ImplicitConversion(typeof(object), typeof(string)));
 
157
                        Assert.AreEqual(C.None, ImplicitConversion(typeof(ICollection), typeof(BitArray)));
 
158
                        Assert.AreEqual(C.None, ImplicitConversion(typeof(IEnumerable), typeof(IList)));
 
159
                }
 
160
                
 
161
                [Test]
 
162
                public void ConversionToDynamic()
 
163
                {
 
164
                        Assert.AreEqual(C.ImplicitReferenceConversion, ImplicitConversion(typeof(string),  typeof(dynamic)));
 
165
                        Assert.AreEqual(C.BoxingConversion,            ImplicitConversion(typeof(int),     typeof(dynamic)));
 
166
                }
 
167
                
 
168
                [Test]
 
169
                public void ConversionFromDynamic()
 
170
                {
 
171
                        // There is no conversion from the type 'dynamic' to other types (except the identity conversion to object).
 
172
                        // Such conversions only exists from dynamic expression.
 
173
                        // This is an important distinction for type inference (see TypeInferenceTests.IEnumerableCovarianceWithDynamic)
 
174
                        Assert.AreEqual(C.None, ImplicitConversion(typeof(dynamic), typeof(string)));
 
175
                        Assert.AreEqual(C.None, ImplicitConversion(typeof(dynamic), typeof(int)));
 
176
                        
 
177
                        var dynamicRR = new ResolveResult(SpecialType.Dynamic);
 
178
                        Assert.AreEqual(C.ImplicitDynamicConversion, conversions.ImplicitConversion(dynamicRR, compilation.FindType(typeof(string))));
 
179
                        Assert.AreEqual(C.ImplicitDynamicConversion, conversions.ImplicitConversion(dynamicRR, compilation.FindType(typeof(int))));
 
180
                }
 
181
                
 
182
                [Test]
 
183
                public void ParameterizedTypeConversions()
 
184
                {
 
185
                        Assert.AreEqual(C.ImplicitReferenceConversion, ImplicitConversion(typeof(List<string>), typeof(ICollection<string>)));
 
186
                        Assert.AreEqual(C.ImplicitReferenceConversion, ImplicitConversion(typeof(IList<string>), typeof(ICollection<string>)));
 
187
                        Assert.AreEqual(C.None, ImplicitConversion(typeof(List<string>), typeof(ICollection<object>)));
 
188
                        Assert.AreEqual(C.None, ImplicitConversion(typeof(IList<string>), typeof(ICollection<object>)));
 
189
                }
 
190
                
 
191
                [Test]
 
192
                public void ArrayConversions()
 
193
                {
 
194
                        Assert.AreEqual(C.ImplicitReferenceConversion, ImplicitConversion(typeof(string[]), typeof(object[])));
 
195
                        Assert.AreEqual(C.ImplicitReferenceConversion, ImplicitConversion(typeof(string[,]), typeof(object[,])));
 
196
                        Assert.AreEqual(C.None, ImplicitConversion(typeof(string[]), typeof(object[,])));
 
197
                        Assert.AreEqual(C.None, ImplicitConversion(typeof(object[]), typeof(string[])));
 
198
                        
 
199
                        Assert.AreEqual(C.ImplicitReferenceConversion, ImplicitConversion(typeof(string[]), typeof(IList<string>)));
 
200
                        Assert.AreEqual(C.None, ImplicitConversion(typeof(string[,]), typeof(IList<string>)));
 
201
                        Assert.AreEqual(C.ImplicitReferenceConversion, ImplicitConversion(typeof(string[]), typeof(IList<object>)));
 
202
                        
 
203
                        Assert.AreEqual(C.ImplicitReferenceConversion, ImplicitConversion(typeof(string[]), typeof(Array)));
 
204
                        Assert.AreEqual(C.ImplicitReferenceConversion, ImplicitConversion(typeof(string[]), typeof(ICloneable)));
 
205
                        Assert.AreEqual(C.None, ImplicitConversion(typeof(Array), typeof(string[])));
 
206
                        Assert.AreEqual(C.None, ImplicitConversion(typeof(object), typeof(object[])));
 
207
                }
 
208
                
 
209
                [Test]
 
210
                public void VarianceConversions()
 
211
                {
 
212
                        Assert.AreEqual(C.ImplicitReferenceConversion,
 
213
                                        ImplicitConversion(typeof(List<string>), typeof(IEnumerable<object>)));
 
214
                        Assert.AreEqual(C.None,
 
215
                                        ImplicitConversion(typeof(List<object>), typeof(IEnumerable<string>)));
 
216
                        Assert.AreEqual(C.ImplicitReferenceConversion,
 
217
                                        ImplicitConversion(typeof(IEnumerable<string>), typeof(IEnumerable<object>)));
 
218
                        Assert.AreEqual(C.None,
 
219
                                        ImplicitConversion(typeof(ICollection<string>), typeof(ICollection<object>)));
 
220
                        
 
221
                        Assert.AreEqual(C.ImplicitReferenceConversion,
 
222
                                        ImplicitConversion(typeof(Comparer<object>), typeof(IComparer<string>)));
 
223
                        Assert.AreEqual(C.ImplicitReferenceConversion,
 
224
                                        ImplicitConversion(typeof(Comparer<object>), typeof(IComparer<Array>)));
 
225
                        Assert.AreEqual(C.None,
 
226
                                        ImplicitConversion(typeof(Comparer<object>), typeof(Comparer<string>)));
 
227
                        
 
228
                        Assert.AreEqual(C.None,
 
229
                                        ImplicitConversion(typeof(List<object>), typeof(IEnumerable<string>)));
 
230
                        Assert.AreEqual(C.ImplicitReferenceConversion,
 
231
                                        ImplicitConversion(typeof(IEnumerable<string>), typeof(IEnumerable<object>)));
 
232
                        
 
233
                        Assert.AreEqual(C.ImplicitReferenceConversion,
 
234
                                        ImplicitConversion(typeof(Func<ICollection, ICollection>), typeof(Func<IList, IEnumerable>)));
 
235
                        Assert.AreEqual(C.ImplicitReferenceConversion,
 
236
                                        ImplicitConversion(typeof(Func<IEnumerable, IList>), typeof(Func<ICollection, ICollection>)));
 
237
                        Assert.AreEqual(C.None,
 
238
                                        ImplicitConversion(typeof(Func<ICollection, ICollection>), typeof(Func<IEnumerable, IList>)));
 
239
                        Assert.AreEqual(C.None,
 
240
                                        ImplicitConversion(typeof(Func<IList, IEnumerable>), typeof(Func<ICollection, ICollection>)));
 
241
                }
 
242
                
 
243
                [Test]
 
244
                public void ImplicitPointerConversion()
 
245
                {
 
246
                        Assert.AreEqual(C.ImplicitPointerConversion, ImplicitConversion(typeof(Null), typeof(int*)));
 
247
                        Assert.AreEqual(C.ImplicitPointerConversion, ImplicitConversion(typeof(int*), typeof(void*)));
 
248
                }
 
249
                
 
250
                [Test]
 
251
                public void NoConversionFromPointerTypeToObject()
 
252
                {
 
253
                        Assert.AreEqual(C.None, ImplicitConversion(typeof(int*), typeof(object)));
 
254
                        Assert.AreEqual(C.None, ImplicitConversion(typeof(int*), typeof(dynamic)));
 
255
                }
 
256
                
 
257
                [Test]
 
258
                public void UnconstrainedTypeParameter()
 
259
                {
 
260
                        ITypeParameter t = new DefaultTypeParameter(compilation, EntityType.TypeDefinition, 0, "T");
 
261
                        ITypeParameter t2 = new DefaultTypeParameter(compilation, EntityType.TypeDefinition, 1, "T2");
 
262
                        ITypeParameter tm = new DefaultTypeParameter(compilation, EntityType.Method, 0, "TM");
 
263
                        
 
264
                        Assert.AreEqual(C.None, conversions.ImplicitConversion(SpecialType.NullType, t));
 
265
                        Assert.AreEqual(C.BoxingConversion, conversions.ImplicitConversion(t, compilation.FindType(KnownTypeCode.Object)));
 
266
                        Assert.AreEqual(C.BoxingConversion, conversions.ImplicitConversion(t, SpecialType.Dynamic));
 
267
                        Assert.AreEqual(C.None, conversions.ImplicitConversion(t, compilation.FindType(typeof(ValueType))));
 
268
                        
 
269
                        Assert.AreEqual(C.IdentityConversion, conversions.ImplicitConversion(t, t));
 
270
                        Assert.AreEqual(C.None, conversions.ImplicitConversion(t2, t));
 
271
                        Assert.AreEqual(C.None, conversions.ImplicitConversion(t, t2));
 
272
                        Assert.AreEqual(C.None, conversions.ImplicitConversion(t, tm));
 
273
                        Assert.AreEqual(C.None, conversions.ImplicitConversion(tm, t));
 
274
                }
 
275
                
 
276
                [Test]
 
277
                public void TypeParameterWithReferenceTypeConstraint()
 
278
                {
 
279
                        ITypeParameter t = new DefaultTypeParameter(compilation, EntityType.TypeDefinition, 0, "T", hasReferenceTypeConstraint: true);
 
280
                        
 
281
                        Assert.AreEqual(C.NullLiteralConversion, conversions.ImplicitConversion(SpecialType.NullType, t));
 
282
                        Assert.AreEqual(C.ImplicitReferenceConversion, conversions.ImplicitConversion(t, compilation.FindType(KnownTypeCode.Object)));
 
283
                        Assert.AreEqual(C.ImplicitReferenceConversion, conversions.ImplicitConversion(t, SpecialType.Dynamic));
 
284
                        Assert.AreEqual(C.None, conversions.ImplicitConversion(t, compilation.FindType(typeof(ValueType))));
 
285
                }
 
286
                
 
287
                [Test]
 
288
                public void TypeParameterWithValueTypeConstraint()
 
289
                {
 
290
                        ITypeParameter t = new DefaultTypeParameter(compilation, EntityType.TypeDefinition, 0, "T", hasValueTypeConstraint: true);
 
291
                        
 
292
                        Assert.AreEqual(C.None, conversions.ImplicitConversion(SpecialType.NullType, t));
 
293
                        Assert.AreEqual(C.BoxingConversion, conversions.ImplicitConversion(t, compilation.FindType(KnownTypeCode.Object)));
 
294
                        Assert.AreEqual(C.BoxingConversion, conversions.ImplicitConversion(t, SpecialType.Dynamic));
 
295
                        Assert.AreEqual(C.BoxingConversion, conversions.ImplicitConversion(t, compilation.FindType(typeof(ValueType))));
 
296
                }
 
297
                
 
298
                [Test]
 
299
                public void TypeParameterWithClassConstraint()
 
300
                {
 
301
                        ITypeParameter t = new DefaultTypeParameter(compilation, EntityType.TypeDefinition, 0, "T",
 
302
                                                                    constraints: new[] { compilation.FindType(typeof(StringComparer)) });
 
303
                        
 
304
                        Assert.AreEqual(C.NullLiteralConversion,
 
305
                                        conversions.ImplicitConversion(SpecialType.NullType, t));
 
306
                        Assert.AreEqual(C.ImplicitReferenceConversion,
 
307
                                        conversions.ImplicitConversion(t, compilation.FindType(KnownTypeCode.Object)));
 
308
                        Assert.AreEqual(C.ImplicitReferenceConversion,
 
309
                                        conversions.ImplicitConversion(t, SpecialType.Dynamic));
 
310
                        Assert.AreEqual(C.None, conversions.ImplicitConversion(t, compilation.FindType(typeof(ValueType))));
 
311
                        Assert.AreEqual(C.ImplicitReferenceConversion,
 
312
                                        conversions.ImplicitConversion(t, compilation.FindType(typeof(StringComparer))));
 
313
                        Assert.AreEqual(C.ImplicitReferenceConversion,
 
314
                                        conversions.ImplicitConversion(t, compilation.FindType(typeof(IComparer))));
 
315
                        Assert.AreEqual(C.None, conversions.ImplicitConversion(t, compilation.FindType(typeof(IComparer<int>))));
 
316
                        Assert.AreEqual(C.ImplicitReferenceConversion,
 
317
                                        conversions.ImplicitConversion(t, compilation.FindType(typeof(IComparer<string>))));
 
318
                }
 
319
                
 
320
                [Test]
 
321
                public void TypeParameterWithInterfaceConstraint()
 
322
                {
 
323
                        ITypeParameter t = new DefaultTypeParameter(compilation, EntityType.TypeDefinition, 0, "T",
 
324
                                                                    constraints: new [] { compilation.FindType(typeof(IList)) });
 
325
                        
 
326
                        Assert.AreEqual(C.None, conversions.ImplicitConversion(SpecialType.NullType, t));
 
327
                        Assert.AreEqual(C.BoxingConversion,
 
328
                                        conversions.ImplicitConversion(t, compilation.FindType(KnownTypeCode.Object)));
 
329
                        Assert.AreEqual(C.BoxingConversion,
 
330
                                        conversions.ImplicitConversion(t, SpecialType.Dynamic));
 
331
                        Assert.AreEqual(C.None, conversions.ImplicitConversion(t, compilation.FindType(typeof(ValueType))));
 
332
                        Assert.AreEqual(C.BoxingConversion,
 
333
                                        conversions.ImplicitConversion(t, compilation.FindType(typeof(IList))));
 
334
                        Assert.AreEqual(C.BoxingConversion,
 
335
                                        conversions.ImplicitConversion(t, compilation.FindType(typeof(IEnumerable))));
 
336
                }
 
337
                
 
338
                [Test]
 
339
                public void UserDefinedImplicitConversion()
 
340
                {
 
341
                        Conversion c = ImplicitConversion(typeof(DateTime), typeof(DateTimeOffset));
 
342
                        Assert.IsTrue(c.IsImplicit && c.IsUserDefined);
 
343
                        Assert.AreEqual("System.DateTimeOffset.op_Implicit", c.Method.FullName);
 
344
                        
 
345
                        Assert.AreEqual(C.None, ImplicitConversion(typeof(DateTimeOffset), typeof(DateTime)));
 
346
                }
 
347
                
 
348
                [Test]
 
349
                public void UserDefinedImplicitNullableConversion()
 
350
                {
 
351
                        // User-defined conversion followed by nullable conversion
 
352
                        Conversion c = ImplicitConversion(typeof(DateTime), typeof(DateTimeOffset?));
 
353
                        Assert.IsTrue(c.IsValid && c.IsUserDefined);
 
354
                        Assert.IsFalse(c.IsLifted);
 
355
                        // Lifted user-defined conversion
 
356
                        c = ImplicitConversion(typeof(DateTime?), typeof(DateTimeOffset?));
 
357
                        Assert.IsTrue(c.IsValid && c.IsUserDefined && c.IsLifted);
 
358
                        // User-defined conversion doesn't drop the nullability
 
359
                        c = ImplicitConversion(typeof(DateTime?), typeof(DateTimeOffset));
 
360
                        Assert.IsFalse(c.IsValid);
 
361
                }
 
362
                
 
363
                bool IntegerLiteralConversion(object value, Type to)
 
364
                {
 
365
                        IType fromType = compilation.FindType(value.GetType());
 
366
                        ConstantResolveResult crr = new ConstantResolveResult(fromType, value);
 
367
                        IType to2 = compilation.FindType(to);
 
368
                        return conversions.ImplicitConversion(crr, to2).IsValid;
 
369
                }
 
370
                
 
371
                [Test]
 
372
                public void IntegerLiteralToEnumConversions()
 
373
                {
 
374
                        Assert.IsTrue(IntegerLiteralConversion(0, typeof(LoaderOptimization)));
 
375
                        Assert.IsTrue(IntegerLiteralConversion(0L, typeof(LoaderOptimization)));
 
376
                        Assert.IsTrue(IntegerLiteralConversion(0, typeof(LoaderOptimization?)));
 
377
                        Assert.IsFalse(IntegerLiteralConversion(0, typeof(string)));
 
378
                        Assert.IsFalse(IntegerLiteralConversion(1, typeof(LoaderOptimization)));
 
379
                }
 
380
                
 
381
                [Test]
 
382
                public void ImplicitConstantExpressionConversion()
 
383
                {
 
384
                        Assert.IsTrue(IntegerLiteralConversion(0, typeof(int)));
 
385
                        Assert.IsTrue(IntegerLiteralConversion(0, typeof(ushort)));
 
386
                        Assert.IsTrue(IntegerLiteralConversion(0, typeof(sbyte)));
 
387
                        
 
388
                        Assert.IsTrue (IntegerLiteralConversion(-1, typeof(int)));
 
389
                        Assert.IsFalse(IntegerLiteralConversion(-1, typeof(ushort)));
 
390
                        Assert.IsTrue (IntegerLiteralConversion(-1, typeof(sbyte)));
 
391
                        
 
392
                        Assert.IsTrue (IntegerLiteralConversion(200, typeof(int)));
 
393
                        Assert.IsTrue (IntegerLiteralConversion(200, typeof(ushort)));
 
394
                        Assert.IsFalse(IntegerLiteralConversion(200, typeof(sbyte)));
 
395
                }
 
396
                
 
397
                [Test]
 
398
                public void ImplicitLongConstantExpressionConversion()
 
399
                {
 
400
                        Assert.IsFalse(IntegerLiteralConversion(0L, typeof(int)));
 
401
                        Assert.IsFalse(IntegerLiteralConversion(0L, typeof(short)));
 
402
                        Assert.IsTrue(IntegerLiteralConversion(0L, typeof(long)));
 
403
                        Assert.IsTrue(IntegerLiteralConversion(0L, typeof(ulong)));
 
404
                        
 
405
                        Assert.IsTrue(IntegerLiteralConversion(-1L, typeof(long)));
 
406
                        Assert.IsFalse(IntegerLiteralConversion(-1L, typeof(ulong)));
 
407
                }
 
408
                
 
409
                [Test]
 
410
                public void ImplicitConstantExpressionConversionToNullable()
 
411
                {
 
412
                        Assert.IsTrue(IntegerLiteralConversion(0, typeof(uint?)));
 
413
                        Assert.IsTrue(IntegerLiteralConversion(0, typeof(short?)));
 
414
                        Assert.IsTrue(IntegerLiteralConversion(0, typeof(byte?)));
 
415
                        
 
416
                        Assert.IsFalse(IntegerLiteralConversion(-1, typeof(uint?)));
 
417
                        Assert.IsTrue (IntegerLiteralConversion(-1, typeof(short?)));
 
418
                        Assert.IsFalse(IntegerLiteralConversion(-1, typeof(byte?)));
 
419
                        
 
420
                        Assert.IsTrue(IntegerLiteralConversion(200, typeof(uint?)));
 
421
                        Assert.IsTrue(IntegerLiteralConversion(200, typeof(short?)));
 
422
                        Assert.IsTrue(IntegerLiteralConversion(200, typeof(byte?)));
 
423
                        
 
424
                        Assert.IsFalse(IntegerLiteralConversion(0L, typeof(uint?)));
 
425
                        Assert.IsTrue (IntegerLiteralConversion(0L, typeof(long?)));
 
426
                        Assert.IsTrue (IntegerLiteralConversion(0L, typeof(ulong?)));
 
427
                        
 
428
                        Assert.IsTrue(IntegerLiteralConversion(-1L, typeof(long?)));
 
429
                        Assert.IsFalse(IntegerLiteralConversion(-1L, typeof(ulong?)));
 
430
                }
 
431
                
 
432
                [Test]
 
433
                public void ImplicitConstantExpressionConversionNumberInterfaces()
 
434
                {
 
435
                        Assert.IsTrue(IntegerLiteralConversion(0, typeof(IFormattable)));
 
436
                        Assert.IsTrue(IntegerLiteralConversion(0, typeof(IComparable<int>)));
 
437
                        Assert.IsFalse(IntegerLiteralConversion(0, typeof(IComparable<short>)));
 
438
                        Assert.IsFalse(IntegerLiteralConversion(0, typeof(IComparable<long>)));
 
439
                }
 
440
                
 
441
                int BetterConversion(Type s, Type t1, Type t2)
 
442
                {
 
443
                        IType sType = compilation.FindType(s);
 
444
                        IType t1Type = compilation.FindType(t1);
 
445
                        IType t2Type = compilation.FindType(t2);
 
446
                        return conversions.BetterConversion(sType, t1Type, t2Type);
 
447
                }
 
448
                
 
449
                int BetterConversion(object value, Type t1, Type t2)
 
450
                {
 
451
                        IType fromType = compilation.FindType(value.GetType());
 
452
                        ConstantResolveResult crr = new ConstantResolveResult(fromType, value);
 
453
                        IType t1Type = compilation.FindType(t1);
 
454
                        IType t2Type = compilation.FindType(t2);
 
455
                        return conversions.BetterConversion(crr, t1Type, t2Type);
 
456
                }
 
457
                
 
458
                [Test]
 
459
                public void BetterConversion()
 
460
                {
 
461
                        Assert.AreEqual(1, BetterConversion(typeof(string), typeof(string), typeof(object)));
 
462
                        Assert.AreEqual(2, BetterConversion(typeof(string), typeof(object), typeof(IComparable<string>)));
 
463
                        Assert.AreEqual(0, BetterConversion(typeof(string), typeof(IEnumerable<char>), typeof(IComparable<string>)));
 
464
                }
 
465
                
 
466
                [Test]
 
467
                public void BetterPrimitiveConversion()
 
468
                {
 
469
                        Assert.AreEqual(1, BetterConversion(typeof(short), typeof(int), typeof(long)));
 
470
                        Assert.AreEqual(1, BetterConversion(typeof(short), typeof(int), typeof(uint)));
 
471
                        Assert.AreEqual(2, BetterConversion(typeof(ushort), typeof(uint), typeof(int)));
 
472
                        Assert.AreEqual(1, BetterConversion(typeof(char), typeof(short), typeof(int)));
 
473
                        Assert.AreEqual(1, BetterConversion(typeof(char), typeof(ushort), typeof(int)));
 
474
                        Assert.AreEqual(1, BetterConversion(typeof(sbyte), typeof(long), typeof(ulong)));
 
475
                        Assert.AreEqual(2, BetterConversion(typeof(byte), typeof(ushort), typeof(short)));
 
476
                        
 
477
                        Assert.AreEqual(1, BetterConversion(1, typeof(sbyte), typeof(byte)));
 
478
                        Assert.AreEqual(2, BetterConversion(1, typeof(ushort), typeof(sbyte)));
 
479
                }
 
480
                
 
481
                [Test]
 
482
                public void BetterNullableConversion()
 
483
                {
 
484
                        Assert.AreEqual(0, BetterConversion(typeof(byte), typeof(int), typeof(uint?)));
 
485
                        Assert.AreEqual(0, BetterConversion(typeof(byte?), typeof(int?), typeof(uint?)));
 
486
                        Assert.AreEqual(1, BetterConversion(typeof(byte), typeof(ushort?), typeof(uint?)));
 
487
                        Assert.AreEqual(2, BetterConversion(typeof(byte?), typeof(ulong?), typeof(uint?)));
 
488
                        Assert.AreEqual(0, BetterConversion(typeof(byte), typeof(ushort?), typeof(uint)));
 
489
                        Assert.AreEqual(0, BetterConversion(typeof(byte), typeof(ushort?), typeof(int)));
 
490
                        Assert.AreEqual(2, BetterConversion(typeof(byte), typeof(ulong?), typeof(uint)));
 
491
                        Assert.AreEqual(0, BetterConversion(typeof(byte), typeof(ulong?), typeof(int)));
 
492
                        Assert.AreEqual(2, BetterConversion(typeof(ushort?), typeof(long?), typeof(int?)));
 
493
                        Assert.AreEqual(0, BetterConversion(typeof(sbyte), typeof(int?), typeof(uint?)));
 
494
                }
 
495
                
 
496
                [Test]
 
497
                public void ExpansiveInheritance()
 
498
                {
 
499
                        var a = new DefaultUnresolvedTypeDefinition(string.Empty, "A");
 
500
                        var b = new DefaultUnresolvedTypeDefinition(string.Empty, "B");
 
501
                        // interface A<in U>
 
502
                        a.Kind = TypeKind.Interface;
 
503
                        a.TypeParameters.Add(new DefaultUnresolvedTypeParameter(EntityType.TypeDefinition, 0, "U") { Variance = VarianceModifier.Contravariant });
 
504
                        // interface B<X> : A<A<B<X>>> { }
 
505
                        b.TypeParameters.Add(new DefaultUnresolvedTypeParameter(EntityType.TypeDefinition, 0, "X"));
 
506
                        b.BaseTypes.Add(new ParameterizedTypeReference(
 
507
                                a, new[] { new ParameterizedTypeReference(
 
508
                                        a, new [] { new ParameterizedTypeReference(
 
509
                                                b, new [] { new TypeParameterReference(EntityType.TypeDefinition, 0) }
 
510
                                        ) } ) }));
 
511
                        
 
512
                        ICompilation compilation = TypeSystemHelper.CreateCompilation(a, b);
 
513
                        ITypeDefinition resolvedA = compilation.MainAssembly.GetTypeDefinition(a.FullTypeName);
 
514
                        ITypeDefinition resolvedB = compilation.MainAssembly.GetTypeDefinition(b.FullTypeName);
 
515
                        
 
516
                        IType type1 = new ParameterizedType(resolvedB, new [] { compilation.FindType(KnownTypeCode.Double) });
 
517
                        IType type2 = new ParameterizedType(resolvedA, new [] { new ParameterizedType(resolvedB, new[] { compilation.FindType(KnownTypeCode.String) }) });
 
518
                        Assert.IsFalse(conversions.ImplicitConversion(type1, type2).IsValid);
 
519
                }
 
520
 
 
521
                [Test]
 
522
                public void ImplicitTypeParameterConversion()
 
523
                {
 
524
                        string program = @"using System;
 
525
class Test {
 
526
        public void M<T, U>(T t) where T : U {
 
527
                U u = $t$;
 
528
        }
 
529
}";
 
530
                        Assert.AreEqual(C.BoxingConversion, GetConversion(program));
 
531
                }
 
532
                
 
533
                [Test]
 
534
                public void InvalidImplicitTypeParameterConversion()
 
535
                {
 
536
                        string program = @"using System;
 
537
class Test {
 
538
        public void M<T, U>(T t) where U : T {
 
539
                U u = $t$;
 
540
        }
 
541
}";
 
542
                        Assert.AreEqual(C.None, GetConversion(program));
 
543
                }
 
544
                
 
545
                [Test]
 
546
                public void ImplicitTypeParameterArrayConversion()
 
547
                {
 
548
                        string program = @"using System;
 
549
class Test {
 
550
        public void M<T, U>(T[] t) where T : U {
 
551
                U[] u = $t$;
 
552
        }
 
553
}";
 
554
                        // invalid, e.g. T=int[], U=object[]
 
555
                        Assert.AreEqual(C.None, GetConversion(program));
 
556
                }
 
557
                
 
558
                [Test]
 
559
                public void ImplicitTypeParameterConversionWithClassConstraint()
 
560
                {
 
561
                        string program = @"using System;
 
562
class Test {
 
563
        public void M<T, U>(T t) where T : class, U where U : class {
 
564
                U u = $t$;
 
565
        }
 
566
}";
 
567
                        Assert.AreEqual(C.ImplicitReferenceConversion, GetConversion(program));
 
568
                }
 
569
                
 
570
                [Test]
 
571
                public void ImplicitTypeParameterArrayConversionWithClassConstraint()
 
572
                {
 
573
                        string program = @"using System;
 
574
class Test {
 
575
        public void M<T, U>(T[] t) where T : class, U where U : class {
 
576
                U[] u = $t$;
 
577
        }
 
578
}";
 
579
                        Assert.AreEqual(C.ImplicitReferenceConversion, GetConversion(program));
 
580
                }
 
581
                
 
582
                [Test]
 
583
                public void ImplicitTypeParameterConversionWithClassConstraintOnlyOnT()
 
584
                {
 
585
                        string program = @"using System;
 
586
class Test {
 
587
        public void M<T, U>(T t) where T : class, U {
 
588
                U u = $t$;
 
589
        }
 
590
}";
 
591
                        Assert.AreEqual(C.ImplicitReferenceConversion, GetConversion(program));
 
592
                }
 
593
                
 
594
                [Test]
 
595
                public void ImplicitTypeParameterArrayConversionWithClassConstraintOnlyOnT()
 
596
                {
 
597
                        string program = @"using System;
 
598
class Test {
 
599
        public void M<T, U>(T[] t) where T : class, U {
 
600
                U[] u = $t$;
 
601
        }
 
602
}";
 
603
                        Assert.AreEqual(C.ImplicitReferenceConversion, GetConversion(program));
 
604
                }
 
605
                
 
606
                [Test]
 
607
                public void MethodGroupConversion_Void()
 
608
                {
 
609
                        string program = @"using System;
 
610
delegate void D();
 
611
class Test {
 
612
        D d = $M$;
 
613
        public static void M() {}
 
614
}";
 
615
                        var c = GetConversion(program);
 
616
                        Assert.IsTrue(c.IsValid);
 
617
                        Assert.IsTrue(c.IsMethodGroupConversion);
 
618
                        Assert.IsNotNull(c.Method);
 
619
                }
 
620
                
 
621
                [Test]
 
622
                public void MethodGroupConversion_MatchingSignature()
 
623
                {
 
624
                        string program = @"using System;
 
625
delegate object D(int argument);
 
626
class Test {
 
627
        D d = $M$;
 
628
        public static object M(int argument) {}
 
629
}";
 
630
                        var c = GetConversion(program);
 
631
                        Assert.IsTrue(c.IsValid);
 
632
                        Assert.IsTrue(c.IsMethodGroupConversion);
 
633
                }
 
634
                
 
635
                [Test]
 
636
                public void MethodGroupConversion_InvalidReturnType()
 
637
                {
 
638
                        string program = @"using System;
 
639
delegate object D(int argument);
 
640
class Test {
 
641
        D d = $M$;
 
642
        public static int M(int argument) {}
 
643
}";
 
644
                        var c = GetConversion(program);
 
645
                        Assert.IsFalse(c.IsValid);
 
646
                        Assert.IsTrue(c.IsMethodGroupConversion);
 
647
                }
 
648
                
 
649
                [Test]
 
650
                public void MethodGroupConversion_CovariantReturnType()
 
651
                {
 
652
                        string program = @"using System;
 
653
delegate object D(int argument);
 
654
class Test {
 
655
        D d = $M$;
 
656
        public static string M(int argument) {}
 
657
}";
 
658
                        var c = GetConversion(program);
 
659
                        Assert.IsTrue(c.IsValid);
 
660
                        Assert.IsTrue(c.IsMethodGroupConversion);
 
661
                }
 
662
                
 
663
                [Test]
 
664
                public void MethodGroupConversion_RefArgumentTypesEqual()
 
665
                {
 
666
                        string program = @"using System;
 
667
delegate void D(ref object o);
 
668
class Test {
 
669
        D d = $M$;
 
670
        public static void M(ref object o) {}
 
671
}";
 
672
                        var c = GetConversion(program);
 
673
                        Assert.IsTrue(c.IsValid);
 
674
                        Assert.IsTrue(c.IsMethodGroupConversion);
 
675
                }
 
676
                
 
677
                [Test]
 
678
                public void MethodGroupConversion_RefArgumentObjectVsDynamic()
 
679
                {
 
680
                        string program = @"using System;
 
681
delegate void D(ref object o);
 
682
class Test {
 
683
        D d = $M$;
 
684
        public static void M(ref dynamic o) {}
 
685
}";
 
686
                        var c = GetConversion(program);
 
687
                        Assert.IsFalse(c.IsValid);
 
688
                        Assert.IsTrue(c.IsMethodGroupConversion);
 
689
                }
 
690
                
 
691
                [Test]
 
692
                public void MethodGroupConversion_RefVsOut()
 
693
                {
 
694
                        string program = @"using System;
 
695
delegate void D(ref object o);
 
696
class Test {
 
697
        D d = $M$;
 
698
        public static void M(out object o) {}
 
699
}";
 
700
                        var c = GetConversion(program);
 
701
                        Assert.IsFalse(c.IsValid);
 
702
                }
 
703
                
 
704
                [Test]
 
705
                public void MethodGroupConversion_RefVsNormal()
 
706
                {
 
707
                        string program = @"using System;
 
708
delegate void D(ref object o);
 
709
class Test {
 
710
        D d = $M$;
 
711
        public static void M(object o) {}
 
712
}";
 
713
                        var c = GetConversion(program);
 
714
                        Assert.IsFalse(c.IsValid);
 
715
                }
 
716
                
 
717
                [Test]
 
718
                public void MethodGroupConversion_NormalVsOut()
 
719
                {
 
720
                        string program = @"using System;
 
721
delegate void D(object o);
 
722
class Test {
 
723
        D d = $M$;
 
724
        public static void M(out object o) {}
 
725
}";
 
726
                        var c = GetConversion(program);
 
727
                        Assert.IsFalse(c.IsValid);
 
728
                }
 
729
                
 
730
                [Test]
 
731
                public void MethodGroupConversion_MatchingNormalParameter()
 
732
                {
 
733
                        string program = @"using System;
 
734
delegate void D(object o);
 
735
class Test {
 
736
        D d = $M$;
 
737
        public static void M(object o) {}
 
738
}";
 
739
                        var c = GetConversion(program);
 
740
                        Assert.IsTrue(c.IsValid);
 
741
                        Assert.IsTrue(c.IsMethodGroupConversion);
 
742
                }
 
743
                
 
744
                [Test]
 
745
                public void MethodGroupConversion_IdentityConversion()
 
746
                {
 
747
                        string program = @"using System;
 
748
delegate void D(object o);
 
749
class Test {
 
750
        D d = $M$;
 
751
        public static void M(dynamic o) {}
 
752
}";
 
753
                        var c = GetConversion(program);
 
754
                        Assert.IsTrue(c.IsValid);
 
755
                        Assert.IsTrue(c.IsMethodGroupConversion);
 
756
                }
 
757
                
 
758
                [Test]
 
759
                public void MethodGroupConversion_Contravariance()
 
760
                {
 
761
                        string program = @"using System;
 
762
delegate void D(string o);
 
763
class Test {
 
764
        D d = $M$;
 
765
        public static void M(object o) {}
 
766
}";
 
767
                        var c = GetConversion(program);
 
768
                        Assert.IsTrue(c.IsValid);
 
769
                        Assert.IsTrue(c.IsMethodGroupConversion);
 
770
                        
 
771
                }
 
772
                
 
773
                [Test, Ignore("Not sure if this conversion should be valid or not... NR and mcs both accept it as valid, csc treats it as invalid")]
 
774
                public void MethodGroupConversion_NoContravarianceDynamic()
 
775
                {
 
776
                        string program = @"using System;
 
777
delegate void D(string o);
 
778
class Test {
 
779
        D d = $M$;
 
780
        public static void M(dynamic o) {}
 
781
}";
 
782
                        var c = GetConversion(program);
 
783
                        //Assert.IsFrue(c.IsValid);
 
784
                        Assert.IsTrue(c.IsMethodGroupConversion);
 
785
                }
 
786
                
 
787
                [Test]
 
788
                public void MethodGroupConversion_ExactMatchIsBetter()
 
789
                {
 
790
                        string program = @"using System;
 
791
class Test {
 
792
        delegate void D(string a);
 
793
        D d = $M$;
 
794
        static void M(object x) {}
 
795
        static void M(string x = null) {}
 
796
}";
 
797
                        var c = GetConversion(program);
 
798
                        Assert.IsTrue(c.IsValid);
 
799
                        Assert.IsTrue(c.IsMethodGroupConversion);
 
800
                        Assert.AreEqual("System.String", c.Method.Parameters.Single().Type.FullName);
 
801
                }
 
802
                
 
803
                [Test]
 
804
                public void MethodGroupConversion_CannotLeaveOutOptionalParameters()
 
805
                {
 
806
                        string program = @"using System;
 
807
class Test {
 
808
        delegate void D(string a);
 
809
        D d = $M$;
 
810
        static void M(object x) {}
 
811
        static void M(string x, string y = null) {}
 
812
}";
 
813
                        var c = GetConversion(program);
 
814
                        Assert.IsTrue(c.IsValid);
 
815
                        Assert.IsTrue(c.IsMethodGroupConversion);
 
816
                        Assert.AreEqual("System.Object", c.Method.Parameters.Single().Type.FullName);
 
817
                }
 
818
                
 
819
                [Test]
 
820
                public void MethodGroupConversion_CannotUseExpandedParams()
 
821
                {
 
822
                        string program = @"using System;
 
823
class Test {
 
824
        delegate void D(string a);
 
825
        D d = $M$;
 
826
        static void M(object x) {}
 
827
        static void M(params string[] x) {}
 
828
}";
 
829
                        var c = GetConversion(program);
 
830
                        Assert.IsTrue(c.IsValid);
 
831
                        Assert.IsTrue(c.IsMethodGroupConversion);
 
832
                        Assert.AreEqual("System.Object", c.Method.Parameters.Single().Type.FullName);
 
833
                }
 
834
 
 
835
                [Test]
 
836
                public void UserDefined_IntLiteral_ViaUInt_ToCustomStruct()
 
837
                {
 
838
                        string program = @"using System;
 
839
struct T {
 
840
        public static implicit operator T(uint a) { return new T(); }
 
841
}
 
842
class Test {
 
843
        static void M() {
 
844
                T t = $1$;
 
845
        }
 
846
}";
 
847
                        var c = GetConversion(program);
 
848
                        Assert.IsTrue(c.IsValid);
 
849
                        Assert.IsTrue(c.IsUserDefined);
 
850
                }
 
851
                
 
852
                [Test]
 
853
                public void UserDefined_NullLiteral_ViaString_ToCustomStruct()
 
854
                {
 
855
                        string program = @"using System;
 
856
struct T {
 
857
        public static implicit operator T(string a) { return new T(); }
 
858
 
 
859
}
 
860
class Test {
 
861
        static void M() {
 
862
                T t = $null$;
 
863
        }
 
864
}";
 
865
                        var c = GetConversion(program);
 
866
                        Assert.IsTrue(c.IsValid);
 
867
                        Assert.IsTrue(c.IsUserDefined);
 
868
                }
 
869
 
 
870
                
 
871
                [Test]
 
872
                public void UserDefined_CanUseLiftedEvenIfReturnTypeAlreadyNullable()
 
873
                {
 
874
                        string program = @"using System;
 
875
struct S {
 
876
        public static implicit operator short?(S s) { return 0; }
 
877
}
 
878
 
 
879
class Test {
 
880
        static void M(S? s) {
 
881
                int? i = $s$;
 
882
        }
 
883
}";
 
884
                        var c = GetConversion(program);
 
885
                        Assert.IsTrue(c.IsValid);
 
886
                        Assert.IsTrue(c.IsUserDefined);
 
887
                        Assert.IsTrue(c.IsLifted);
 
888
                }
 
889
 
 
890
                [Test]
 
891
                public void UserDefinedImplicitConversion_PicksExactSourceTypeIfPossible() {
 
892
                        string program = @"using System;
 
893
class Convertible {
 
894
        public static implicit operator Convertible(int i) {return new Convertible(); }
 
895
        public static implicit operator Convertible(short s) {return new Convertible(); }
 
896
}
 
897
class Test {
 
898
        public void M() {
 
899
                Convertible a = $33$;
 
900
        }
 
901
}";
 
902
                        var c = GetConversion(program);
 
903
                        Assert.IsTrue(c.IsValid);
 
904
                        Assert.IsTrue(c.IsUserDefined);
 
905
                        Assert.AreEqual("i", c.Method.Parameters[0].Name);
 
906
                }
 
907
 
 
908
                [Test]
 
909
                public void UserDefinedImplicitConversion_PicksMostEncompassedSourceType() {
 
910
                        string program = @"using System;
 
911
class Convertible {
 
912
        public static implicit operator Convertible(long l) {return new Convertible(); }
 
913
        public static implicit operator Convertible(uint ui) {return new Convertible(); }
 
914
}
 
915
class Test {
 
916
        public void M() {
 
917
                Convertible a = $(ushort)33$;
 
918
        }
 
919
}";
 
920
                        var c = GetConversion(program);
 
921
                        Assert.IsTrue(c.IsValid);
 
922
                        Assert.IsTrue(c.IsUserDefined);
 
923
                        Assert.AreEqual("ui", c.Method.Parameters[0].Name);
 
924
                }
 
925
 
 
926
                [Test]
 
927
                public void UserDefinedImplicitConversion_NoMostEncompassedSourceTypeIsInvalid() {
 
928
                        string program = @"using System;
 
929
class Convertible {
 
930
        public static implicit operator Convertible(ulong l) {return new Convertible(); }
 
931
        public static implicit operator Convertible(int ui) {return new Convertible(); }
 
932
}
 
933
class Test {
 
934
        public void M() {
 
935
                Convertible a = $(ushort)33$;
 
936
        }
 
937
}";
 
938
                        var c = GetConversion(program);
 
939
                        Assert.IsFalse(c.IsValid);
 
940
                }
 
941
 
 
942
                [Test]
 
943
                public void UserDefinedImplicitConversion_PicksExactTargetTypeIfPossible() {
 
944
                        string program = @"using System;
 
945
class Convertible {
 
946
        public static implicit operator int(Convertible i) {return 0; }
 
947
        public static implicit operator short(Convertible s) {return 0; }
 
948
}
 
949
class Test {
 
950
        public void M() {
 
951
                int a = $new Convertible()$;
 
952
        }
 
953
}";
 
954
                        var c = GetConversion(program);
 
955
                        Assert.IsTrue(c.IsValid);
 
956
                        Assert.IsTrue(c.IsUserDefined);
 
957
                        Assert.AreEqual("i", c.Method.Parameters[0].Name);
 
958
                }
 
959
 
 
960
                [Test]
 
961
                public void UserDefinedImplicitConversion_PicksMostEncompassingTargetType() {
 
962
                        string program = @"using System;
 
963
class Convertible {
 
964
        public static implicit operator int(Convertible i) {return 0; }
 
965
        public static implicit operator ushort(Convertible us) {return 0; }
 
966
}
 
967
class Test {
 
968
        public void M() {
 
969
                ulong a = $new Convertible()$;
 
970
        }
 
971
}";
 
972
                        var c = GetConversion(program);
 
973
                        Assert.IsTrue(c.IsValid);
 
974
                        Assert.IsTrue(c.IsUserDefined);
 
975
                        Assert.AreEqual("us", c.Method.Parameters[0].Name);
 
976
                }
 
977
 
 
978
                [Test]
 
979
                public void UserDefinedImplicitConversion_NoMostEncompassingTargetTypeIsInvalid() {
 
980
                        string program = @"using System;
 
981
class Convertible {
 
982
        public static implicit operator uint(Convertible i) {return 0; }
 
983
        public static implicit operator short(Convertible us) {return 0; }
 
984
}
 
985
class Test {
 
986
        public void M() {
 
987
                long a = $new Convertible()$;
 
988
        }
 
989
}";
 
990
                        var c = GetConversion(program);
 
991
                        Assert.IsFalse(c.IsValid);
 
992
                }
 
993
 
 
994
                [Test]
 
995
                public void UserDefinedImplicitConversion_AmbiguousIsInvalid() {
 
996
                        string program = @"using System;
 
997
class Convertible1 {
 
998
        public static implicit operator Convertible2(Convertible1 c) {return 0; }
 
999
}
 
1000
class Convertible2 {
 
1001
        public static implicit operator Convertible2(Convertible1 c) {return 0; }
 
1002
}
 
1003
class Test {
 
1004
        public void M() {
 
1005
                Convertible2 a = $new Convertible1()$;
 
1006
        }
 
1007
}";
 
1008
                        var c = GetConversion(program);
 
1009
                        Assert.IsFalse(c.IsValid);
 
1010
                }
 
1011
 
 
1012
                [Test]
 
1013
                public void UserDefinedImplicitConversion_DefinedNullableTakesPrecedenceOverLifted() {
 
1014
                        string program = @"using System;
 
1015
struct Convertible {
 
1016
        public static implicit operator Convertible(int i) {return new Convertible(); }
 
1017
        public static implicit operator Convertible?(int? ni) {return new Convertible(); }
 
1018
}
 
1019
class Test {
 
1020
        public void M() {
 
1021
                Convertible? a = $(int?)33$;
 
1022
        }
 
1023
}";
 
1024
                        var c = GetConversion(program);
 
1025
                        Assert.IsTrue(c.IsValid);
 
1026
                        Assert.IsTrue(c.IsUserDefined);
 
1027
                        Assert.IsFalse(c.IsLifted);
 
1028
                        Assert.AreEqual("ni", c.Method.Parameters[0].Name);
 
1029
                }
 
1030
 
 
1031
                [Test]
 
1032
                public void UserDefinedImplicitConversion_UIntConstant() {
 
1033
                        string program = @"using System;
 
1034
class Convertible {
 
1035
        public static implicit operator Convertible(long l) {return new Convertible(); }
 
1036
        public static implicit operator Convertible(uint ui) {return new Convertible(); }
 
1037
}
 
1038
class Test {
 
1039
        public void M() {
 
1040
                Convertible a = $33$;
 
1041
        }
 
1042
}";
 
1043
                        var c = GetConversion(program);
 
1044
                        Assert.IsTrue(c.IsValid);
 
1045
                        Assert.IsTrue(c.IsUserDefined);
 
1046
                        Assert.AreEqual("ui", c.Method.Parameters[0].Name);
 
1047
                }
 
1048
 
 
1049
                [Test]
 
1050
                public void UserDefinedImplicitConversion_NullableUIntConstant() {
 
1051
                        string program = @"using System;
 
1052
class Convertible {
 
1053
        public static implicit operator Convertible(long? l) {return new Convertible(); }
 
1054
        public static implicit operator Convertible(uint? ui) {return new Convertible(); }
 
1055
}
 
1056
class Test {
 
1057
        public void M() {
 
1058
                Convertible a = $33$;
 
1059
        }
 
1060
}";
 
1061
                        var c = GetConversion(program);
 
1062
                        Assert.IsTrue(c.IsValid);
 
1063
                        Assert.IsTrue(c.IsUserDefined);
 
1064
                        Assert.AreEqual("ui", c.Method.Parameters[0].Name);
 
1065
                }
 
1066
 
 
1067
                [Test]
 
1068
                public void UserDefinedImplicitConversion_UseShortResult_BecauseNullableCannotBeUnpacked()
 
1069
                {
 
1070
                        string program = @"using System;
 
1071
class Test {
 
1072
        public static implicit operator int?(Test i) { return 0; }
 
1073
        public static implicit operator short(Test s) { return 0; }
 
1074
}
 
1075
class Program {
 
1076
        public static void Main(string[] args)
 
1077
        {
 
1078
                int x = $new Test()$;
 
1079
        }
 
1080
}";
 
1081
                        var c = GetConversion(program);
 
1082
                        Assert.IsTrue(c.IsValid);
 
1083
                        Assert.IsTrue(c.IsUserDefined);
 
1084
                        Assert.AreEqual("System.Int16", c.Method.ReturnType.FullName);
 
1085
                }
 
1086
                
 
1087
                [Test]
 
1088
                public void UserDefinedImplicitConversion_Short_Or_NullableByte_Target()
 
1089
                {
 
1090
                        string program = @"using System;
 
1091
class Test {
 
1092
        public static implicit operator short(Test s) { return 0; }
 
1093
        public static implicit operator byte?(Test b) { return 0; }
 
1094
}
 
1095
class Program {
 
1096
        public static void Main(string[] args)
 
1097
        {
 
1098
                int? x = $new Test()$;
 
1099
        }
 
1100
}";
 
1101
                        var c = GetConversion(program);
 
1102
                        Assert.IsTrue(c.IsValid);
 
1103
                        Assert.IsTrue(c.IsUserDefined);
 
1104
                        Assert.AreEqual("System.Int16", c.Method.ReturnType.FullName);
 
1105
                }
 
1106
                
 
1107
                [Test]
 
1108
                public void UserDefinedImplicitConversion_Byte_Or_NullableShort_Target()
 
1109
                {
 
1110
                        string program = @"using System;
 
1111
class Test {
 
1112
        public static implicit operator byte(Test b) { return 0; }
 
1113
        public static implicit operator short?(Test s) { return 0; }
 
1114
}
 
1115
class Program {
 
1116
        public static void Main(string[] args)
 
1117
        {
 
1118
                int? x = $new Test()$;
 
1119
        }
 
1120
}";
 
1121
                        var c = GetConversion(program);
 
1122
                        Assert.IsTrue(c.IsValid);
 
1123
                        Assert.IsTrue(c.IsUserDefined);
 
1124
                        Assert.AreEqual("s", c.Method.Parameters[0].Name);
 
1125
                }
 
1126
                
 
1127
                [Test]
 
1128
                public void UserDefinedImplicitConversion_Int_Or_NullableLong_Source()
 
1129
                {
 
1130
                        string program = @"using System;
 
1131
class Test {
 
1132
        public static implicit operator Test(int i) { return new Test(); }
 
1133
        public static implicit operator Test(long? l) { return new Test(); }
 
1134
}
 
1135
class Program {
 
1136
        static void Main() {
 
1137
                short s = 0;
 
1138
                Test t = $s$;
 
1139
        }
 
1140
}";
 
1141
                        var c = GetConversion(program);
 
1142
                        Assert.IsTrue(c.IsValid);
 
1143
                        Assert.IsTrue(c.IsUserDefined);
 
1144
                        Assert.AreEqual("i", c.Method.Parameters[0].Name);
 
1145
                }
 
1146
                
 
1147
                [Test]
 
1148
                public void UserDefinedImplicitConversion_NullableInt_Or_Long_Source()
 
1149
                {
 
1150
                        string program = @"using System;
 
1151
class Test {
 
1152
        public static implicit operator Test(int? i) { return new Test(); }
 
1153
        public static implicit operator Test(long l) { return new Test(); }
 
1154
}
 
1155
class Program {
 
1156
        static void Main() {
 
1157
                short s = 0;
 
1158
                Test t = $s$;
 
1159
        }
 
1160
}";
 
1161
                        var c = GetConversion(program);
 
1162
                        Assert.IsFalse(c.IsValid);
 
1163
                        Assert.IsTrue(c.IsUserDefined);
 
1164
                }
 
1165
                
 
1166
                [Test]
 
1167
                public void UserDefinedImplicitConversion_NullableInt_Or_Long_Constant_Source() {
 
1168
                        string program = @"using System;
 
1169
class Test {
 
1170
        public static implicit operator Test(int? i) { return new Test(); }
 
1171
        public static implicit operator Test(long l) { return new Test(); }
 
1172
}
 
1173
class Program {
 
1174
        static void Main() {
 
1175
                Test t = $1$;
 
1176
        }
 
1177
}";
 
1178
                        var c = GetConversion(program);
 
1179
                        Assert.IsFalse(c.IsValid);
 
1180
                        Assert.IsTrue(c.IsUserDefined);
 
1181
                }
 
1182
 
 
1183
                [Test]
 
1184
                public void UserDefinedImplicitConversion_NullableInt_Or_NullableLong_Source()
 
1185
                {
 
1186
                        string program = @"using System;
 
1187
class Test {
 
1188
        public static implicit operator Test(int? i) { return new Test(); }
 
1189
        public static implicit operator Test(long? l) { return new Test(); }
 
1190
}
 
1191
class Program {
 
1192
        static void Main() {
 
1193
                short s = 0;
 
1194
                Test t = $s$;
 
1195
        }
 
1196
}";
 
1197
                        var c = GetConversion(program);
 
1198
                        Assert.IsTrue(c.IsValid);
 
1199
                        Assert.IsTrue(c.IsUserDefined);
 
1200
                        Assert.AreEqual("i", c.Method.Parameters[0].Name);
 
1201
                }
 
1202
                
 
1203
                [Test]
 
1204
                public void PreferUserDefinedConversionOverReferenceConversion()
 
1205
                {
 
1206
                        // actually this is not because user-defined conversions are better;
 
1207
                        // but because string is a better conversion target
 
1208
                        string program = @"
 
1209
class AA {
 
1210
        public static implicit operator string(AA a) { return null; }
 
1211
}
 
1212
class Test {
 
1213
        static void M(object obj) {}
 
1214
        static void M(string str) {}
 
1215
        
 
1216
        static void Main() {
 
1217
                $M(new AA())$;
 
1218
        }
 
1219
}";
 
1220
 
 
1221
                        var rr = Resolve<CSharpInvocationResolveResult>(program);
 
1222
                        Assert.IsFalse(rr.IsError);
 
1223
                        Assert.AreEqual("str", rr.Member.Parameters[0].Name);
 
1224
                }
 
1225
                
 
1226
                [Test]
 
1227
                public void PreferAmbiguousConversionOverReferenceConversion()
 
1228
                {
 
1229
                        // Ambiguous conversions are a compiler error; but they are not
 
1230
                        // preventing the overload from being chosen.
 
1231
                        
 
1232
                        // The user-defined conversion wins because BB is a better conversion target than object.
 
1233
                        string program = @"
 
1234
class AA {
 
1235
        public static implicit operator BB(AA a) { return null; }
 
1236
}
 
1237
class BB {
 
1238
        public static implicit operator BB(AA a) { return null; }
 
1239
}
 
1240
 
 
1241
class Test {
 
1242
        static void M(BB b) {}
 
1243
        static void M(object o) {}
 
1244
        
 
1245
        static void Main() {
 
1246
                M($new AA()$);
 
1247
        }
 
1248
}";
 
1249
 
 
1250
                        var c = GetConversion(program);
 
1251
                        Assert.IsTrue(c.IsUserDefined);
 
1252
                        Assert.IsFalse(c.IsValid);
 
1253
                }
 
1254
 
 
1255
                [Test]
 
1256
                public void UserDefinedImplicitConversion_ConversionBeforeUserDefinedOperatorIsCorrect() {
 
1257
                        string program = @"using System;
 
1258
class Convertible {
 
1259
        public static implicit operator Convertible(long l) {return new Convertible(); }
 
1260
}
 
1261
class Test {
 
1262
        public void M() {
 
1263
                int i = 33;
 
1264
                Convertible a = $i$;
 
1265
        }
 
1266
}";
 
1267
                        var c = GetConversion(program);
 
1268
                        Assert.IsTrue(c.IsValid);
 
1269
                        Assert.IsTrue(c.ConversionBeforeUserDefinedOperator.IsImplicit);
 
1270
                        Assert.IsTrue(c.ConversionBeforeUserDefinedOperator.IsNumericConversion);
 
1271
                        Assert.IsTrue(c.ConversionBeforeUserDefinedOperator.IsValid);
 
1272
                        Assert.IsTrue(c.ConversionAfterUserDefinedOperator.IsIdentityConversion);
 
1273
                }
 
1274
 
 
1275
                [Test]
 
1276
                public void UserDefinedImplicitConversion_ConversionAfterUserDefinedOperatorIsCorrect() {
 
1277
                        string program = @"using System;
 
1278
class Convertible {
 
1279
        public static implicit operator int(Convertible i) {return 0; }
 
1280
}
 
1281
class Test {
 
1282
        public void M() {
 
1283
                long a = $new Convertible()$;
 
1284
        }
 
1285
}";
 
1286
                        var c = GetConversion(program);
 
1287
                        Assert.IsTrue(c.IsValid);
 
1288
                        Assert.IsTrue(c.ConversionBeforeUserDefinedOperator.IsIdentityConversion);
 
1289
                        Assert.IsTrue(c.ConversionAfterUserDefinedOperator.IsImplicit);
 
1290
                        Assert.IsTrue(c.ConversionAfterUserDefinedOperator.IsNumericConversion);
 
1291
                        Assert.IsTrue(c.ConversionAfterUserDefinedOperator.IsValid);
 
1292
                }
 
1293
        }
 
1294
}