1
ļ»æ// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team
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:
9
// The above copyright notice and this permission notice shall be included in all copies or
10
// substantial portions of the Software.
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.
20
using System.Collections;
21
using System.Collections.Generic;
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;
29
namespace ICSharpCode.NRefactory.CSharp.Resolver
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;
37
public unsafe class ConversionsTest : ResolverTestBase
39
CSharpConversions conversions;
41
public override void SetUp()
44
conversions = new CSharpConversions(compilation);
47
Conversion ImplicitConversion(Type from, Type to)
49
IType from2 = compilation.FindType(from);
50
IType to2 = compilation.FindType(to);
51
return conversions.ImplicitConversion(from2, to2);
55
public void IdentityConversions()
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)));
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));
68
public void DynamicIdentityConversions()
70
Assert.AreEqual(C.IdentityConversion, ImplicitConversion(typeof(object), typeof(dynamic)));
71
Assert.AreEqual(C.IdentityConversion, ImplicitConversion(typeof(dynamic), typeof(object)));
75
public void ComplexDynamicIdentityConversions()
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>)));
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>[]>)));
88
public void PrimitiveConversions()
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)));
103
public void EnumerationConversion()
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))));
113
public void NullableConversions()
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?)));
126
public void NullableConversions2()
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?)));
139
public void NullLiteralConversions()
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[])));
151
public void SimpleReferenceConversions()
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)));
162
public void ConversionToDynamic()
164
Assert.AreEqual(C.ImplicitReferenceConversion, ImplicitConversion(typeof(string), typeof(dynamic)));
165
Assert.AreEqual(C.BoxingConversion, ImplicitConversion(typeof(int), typeof(dynamic)));
169
public void ConversionFromDynamic()
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)));
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))));
183
public void ParameterizedTypeConversions()
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>)));
192
public void ArrayConversions()
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[])));
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>)));
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[])));
210
public void VarianceConversions()
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>)));
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>)));
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>)));
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>)));
244
public void ImplicitPointerConversion()
246
Assert.AreEqual(C.ImplicitPointerConversion, ImplicitConversion(typeof(Null), typeof(int*)));
247
Assert.AreEqual(C.ImplicitPointerConversion, ImplicitConversion(typeof(int*), typeof(void*)));
251
public void NoConversionFromPointerTypeToObject()
253
Assert.AreEqual(C.None, ImplicitConversion(typeof(int*), typeof(object)));
254
Assert.AreEqual(C.None, ImplicitConversion(typeof(int*), typeof(dynamic)));
258
public void UnconstrainedTypeParameter()
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");
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))));
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));
277
public void TypeParameterWithReferenceTypeConstraint()
279
ITypeParameter t = new DefaultTypeParameter(compilation, EntityType.TypeDefinition, 0, "T", hasReferenceTypeConstraint: true);
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))));
288
public void TypeParameterWithValueTypeConstraint()
290
ITypeParameter t = new DefaultTypeParameter(compilation, EntityType.TypeDefinition, 0, "T", hasValueTypeConstraint: true);
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))));
299
public void TypeParameterWithClassConstraint()
301
ITypeParameter t = new DefaultTypeParameter(compilation, EntityType.TypeDefinition, 0, "T",
302
constraints: new[] { compilation.FindType(typeof(StringComparer)) });
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>))));
321
public void TypeParameterWithInterfaceConstraint()
323
ITypeParameter t = new DefaultTypeParameter(compilation, EntityType.TypeDefinition, 0, "T",
324
constraints: new [] { compilation.FindType(typeof(IList)) });
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))));
339
public void UserDefinedImplicitConversion()
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);
345
Assert.AreEqual(C.None, ImplicitConversion(typeof(DateTimeOffset), typeof(DateTime)));
349
public void UserDefinedImplicitNullableConversion()
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);
363
bool IntegerLiteralConversion(object value, Type to)
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;
372
public void IntegerLiteralToEnumConversions()
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)));
382
public void ImplicitConstantExpressionConversion()
384
Assert.IsTrue(IntegerLiteralConversion(0, typeof(int)));
385
Assert.IsTrue(IntegerLiteralConversion(0, typeof(ushort)));
386
Assert.IsTrue(IntegerLiteralConversion(0, typeof(sbyte)));
388
Assert.IsTrue (IntegerLiteralConversion(-1, typeof(int)));
389
Assert.IsFalse(IntegerLiteralConversion(-1, typeof(ushort)));
390
Assert.IsTrue (IntegerLiteralConversion(-1, typeof(sbyte)));
392
Assert.IsTrue (IntegerLiteralConversion(200, typeof(int)));
393
Assert.IsTrue (IntegerLiteralConversion(200, typeof(ushort)));
394
Assert.IsFalse(IntegerLiteralConversion(200, typeof(sbyte)));
398
public void ImplicitLongConstantExpressionConversion()
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)));
405
Assert.IsTrue(IntegerLiteralConversion(-1L, typeof(long)));
406
Assert.IsFalse(IntegerLiteralConversion(-1L, typeof(ulong)));
410
public void ImplicitConstantExpressionConversionToNullable()
412
Assert.IsTrue(IntegerLiteralConversion(0, typeof(uint?)));
413
Assert.IsTrue(IntegerLiteralConversion(0, typeof(short?)));
414
Assert.IsTrue(IntegerLiteralConversion(0, typeof(byte?)));
416
Assert.IsFalse(IntegerLiteralConversion(-1, typeof(uint?)));
417
Assert.IsTrue (IntegerLiteralConversion(-1, typeof(short?)));
418
Assert.IsFalse(IntegerLiteralConversion(-1, typeof(byte?)));
420
Assert.IsTrue(IntegerLiteralConversion(200, typeof(uint?)));
421
Assert.IsTrue(IntegerLiteralConversion(200, typeof(short?)));
422
Assert.IsTrue(IntegerLiteralConversion(200, typeof(byte?)));
424
Assert.IsFalse(IntegerLiteralConversion(0L, typeof(uint?)));
425
Assert.IsTrue (IntegerLiteralConversion(0L, typeof(long?)));
426
Assert.IsTrue (IntegerLiteralConversion(0L, typeof(ulong?)));
428
Assert.IsTrue(IntegerLiteralConversion(-1L, typeof(long?)));
429
Assert.IsFalse(IntegerLiteralConversion(-1L, typeof(ulong?)));
433
public void ImplicitConstantExpressionConversionNumberInterfaces()
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>)));
441
int BetterConversion(Type s, Type t1, Type t2)
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);
449
int BetterConversion(object value, Type t1, Type t2)
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);
459
public void BetterConversion()
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>)));
467
public void BetterPrimitiveConversion()
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)));
477
Assert.AreEqual(1, BetterConversion(1, typeof(sbyte), typeof(byte)));
478
Assert.AreEqual(2, BetterConversion(1, typeof(ushort), typeof(sbyte)));
482
public void BetterNullableConversion()
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?)));
497
public void ExpansiveInheritance()
499
var a = new DefaultUnresolvedTypeDefinition(string.Empty, "A");
500
var b = new DefaultUnresolvedTypeDefinition(string.Empty, "B");
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) }
512
ICompilation compilation = TypeSystemHelper.CreateCompilation(a, b);
513
ITypeDefinition resolvedA = compilation.MainAssembly.GetTypeDefinition(a.FullTypeName);
514
ITypeDefinition resolvedB = compilation.MainAssembly.GetTypeDefinition(b.FullTypeName);
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);
522
public void ImplicitTypeParameterConversion()
524
string program = @"using System;
526
public void M<T, U>(T t) where T : U {
530
Assert.AreEqual(C.BoxingConversion, GetConversion(program));
534
public void InvalidImplicitTypeParameterConversion()
536
string program = @"using System;
538
public void M<T, U>(T t) where U : T {
542
Assert.AreEqual(C.None, GetConversion(program));
546
public void ImplicitTypeParameterArrayConversion()
548
string program = @"using System;
550
public void M<T, U>(T[] t) where T : U {
554
// invalid, e.g. T=int[], U=object[]
555
Assert.AreEqual(C.None, GetConversion(program));
559
public void ImplicitTypeParameterConversionWithClassConstraint()
561
string program = @"using System;
563
public void M<T, U>(T t) where T : class, U where U : class {
567
Assert.AreEqual(C.ImplicitReferenceConversion, GetConversion(program));
571
public void ImplicitTypeParameterArrayConversionWithClassConstraint()
573
string program = @"using System;
575
public void M<T, U>(T[] t) where T : class, U where U : class {
579
Assert.AreEqual(C.ImplicitReferenceConversion, GetConversion(program));
583
public void ImplicitTypeParameterConversionWithClassConstraintOnlyOnT()
585
string program = @"using System;
587
public void M<T, U>(T t) where T : class, U {
591
Assert.AreEqual(C.ImplicitReferenceConversion, GetConversion(program));
595
public void ImplicitTypeParameterArrayConversionWithClassConstraintOnlyOnT()
597
string program = @"using System;
599
public void M<T, U>(T[] t) where T : class, U {
603
Assert.AreEqual(C.ImplicitReferenceConversion, GetConversion(program));
607
public void MethodGroupConversion_Void()
609
string program = @"using System;
613
public static void M() {}
615
var c = GetConversion(program);
616
Assert.IsTrue(c.IsValid);
617
Assert.IsTrue(c.IsMethodGroupConversion);
618
Assert.IsNotNull(c.Method);
622
public void MethodGroupConversion_MatchingSignature()
624
string program = @"using System;
625
delegate object D(int argument);
628
public static object M(int argument) {}
630
var c = GetConversion(program);
631
Assert.IsTrue(c.IsValid);
632
Assert.IsTrue(c.IsMethodGroupConversion);
636
public void MethodGroupConversion_InvalidReturnType()
638
string program = @"using System;
639
delegate object D(int argument);
642
public static int M(int argument) {}
644
var c = GetConversion(program);
645
Assert.IsFalse(c.IsValid);
646
Assert.IsTrue(c.IsMethodGroupConversion);
650
public void MethodGroupConversion_CovariantReturnType()
652
string program = @"using System;
653
delegate object D(int argument);
656
public static string M(int argument) {}
658
var c = GetConversion(program);
659
Assert.IsTrue(c.IsValid);
660
Assert.IsTrue(c.IsMethodGroupConversion);
664
public void MethodGroupConversion_RefArgumentTypesEqual()
666
string program = @"using System;
667
delegate void D(ref object o);
670
public static void M(ref object o) {}
672
var c = GetConversion(program);
673
Assert.IsTrue(c.IsValid);
674
Assert.IsTrue(c.IsMethodGroupConversion);
678
public void MethodGroupConversion_RefArgumentObjectVsDynamic()
680
string program = @"using System;
681
delegate void D(ref object o);
684
public static void M(ref dynamic o) {}
686
var c = GetConversion(program);
687
Assert.IsFalse(c.IsValid);
688
Assert.IsTrue(c.IsMethodGroupConversion);
692
public void MethodGroupConversion_RefVsOut()
694
string program = @"using System;
695
delegate void D(ref object o);
698
public static void M(out object o) {}
700
var c = GetConversion(program);
701
Assert.IsFalse(c.IsValid);
705
public void MethodGroupConversion_RefVsNormal()
707
string program = @"using System;
708
delegate void D(ref object o);
711
public static void M(object o) {}
713
var c = GetConversion(program);
714
Assert.IsFalse(c.IsValid);
718
public void MethodGroupConversion_NormalVsOut()
720
string program = @"using System;
721
delegate void D(object o);
724
public static void M(out object o) {}
726
var c = GetConversion(program);
727
Assert.IsFalse(c.IsValid);
731
public void MethodGroupConversion_MatchingNormalParameter()
733
string program = @"using System;
734
delegate void D(object o);
737
public static void M(object o) {}
739
var c = GetConversion(program);
740
Assert.IsTrue(c.IsValid);
741
Assert.IsTrue(c.IsMethodGroupConversion);
745
public void MethodGroupConversion_IdentityConversion()
747
string program = @"using System;
748
delegate void D(object o);
751
public static void M(dynamic o) {}
753
var c = GetConversion(program);
754
Assert.IsTrue(c.IsValid);
755
Assert.IsTrue(c.IsMethodGroupConversion);
759
public void MethodGroupConversion_Contravariance()
761
string program = @"using System;
762
delegate void D(string o);
765
public static void M(object o) {}
767
var c = GetConversion(program);
768
Assert.IsTrue(c.IsValid);
769
Assert.IsTrue(c.IsMethodGroupConversion);
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()
776
string program = @"using System;
777
delegate void D(string o);
780
public static void M(dynamic o) {}
782
var c = GetConversion(program);
783
//Assert.IsFrue(c.IsValid);
784
Assert.IsTrue(c.IsMethodGroupConversion);
788
public void MethodGroupConversion_ExactMatchIsBetter()
790
string program = @"using System;
792
delegate void D(string a);
794
static void M(object x) {}
795
static void M(string x = null) {}
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);
804
public void MethodGroupConversion_CannotLeaveOutOptionalParameters()
806
string program = @"using System;
808
delegate void D(string a);
810
static void M(object x) {}
811
static void M(string x, string y = null) {}
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);
820
public void MethodGroupConversion_CannotUseExpandedParams()
822
string program = @"using System;
824
delegate void D(string a);
826
static void M(object x) {}
827
static void M(params string[] x) {}
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);
836
public void UserDefined_IntLiteral_ViaUInt_ToCustomStruct()
838
string program = @"using System;
840
public static implicit operator T(uint a) { return new T(); }
847
var c = GetConversion(program);
848
Assert.IsTrue(c.IsValid);
849
Assert.IsTrue(c.IsUserDefined);
853
public void UserDefined_NullLiteral_ViaString_ToCustomStruct()
855
string program = @"using System;
857
public static implicit operator T(string a) { return new T(); }
865
var c = GetConversion(program);
866
Assert.IsTrue(c.IsValid);
867
Assert.IsTrue(c.IsUserDefined);
872
public void UserDefined_CanUseLiftedEvenIfReturnTypeAlreadyNullable()
874
string program = @"using System;
876
public static implicit operator short?(S s) { return 0; }
880
static void M(S? s) {
884
var c = GetConversion(program);
885
Assert.IsTrue(c.IsValid);
886
Assert.IsTrue(c.IsUserDefined);
887
Assert.IsTrue(c.IsLifted);
891
public void UserDefinedImplicitConversion_PicksExactSourceTypeIfPossible() {
892
string program = @"using System;
894
public static implicit operator Convertible(int i) {return new Convertible(); }
895
public static implicit operator Convertible(short s) {return new Convertible(); }
899
Convertible a = $33$;
902
var c = GetConversion(program);
903
Assert.IsTrue(c.IsValid);
904
Assert.IsTrue(c.IsUserDefined);
905
Assert.AreEqual("i", c.Method.Parameters[0].Name);
909
public void UserDefinedImplicitConversion_PicksMostEncompassedSourceType() {
910
string program = @"using System;
912
public static implicit operator Convertible(long l) {return new Convertible(); }
913
public static implicit operator Convertible(uint ui) {return new Convertible(); }
917
Convertible a = $(ushort)33$;
920
var c = GetConversion(program);
921
Assert.IsTrue(c.IsValid);
922
Assert.IsTrue(c.IsUserDefined);
923
Assert.AreEqual("ui", c.Method.Parameters[0].Name);
927
public void UserDefinedImplicitConversion_NoMostEncompassedSourceTypeIsInvalid() {
928
string program = @"using System;
930
public static implicit operator Convertible(ulong l) {return new Convertible(); }
931
public static implicit operator Convertible(int ui) {return new Convertible(); }
935
Convertible a = $(ushort)33$;
938
var c = GetConversion(program);
939
Assert.IsFalse(c.IsValid);
943
public void UserDefinedImplicitConversion_PicksExactTargetTypeIfPossible() {
944
string program = @"using System;
946
public static implicit operator int(Convertible i) {return 0; }
947
public static implicit operator short(Convertible s) {return 0; }
951
int a = $new Convertible()$;
954
var c = GetConversion(program);
955
Assert.IsTrue(c.IsValid);
956
Assert.IsTrue(c.IsUserDefined);
957
Assert.AreEqual("i", c.Method.Parameters[0].Name);
961
public void UserDefinedImplicitConversion_PicksMostEncompassingTargetType() {
962
string program = @"using System;
964
public static implicit operator int(Convertible i) {return 0; }
965
public static implicit operator ushort(Convertible us) {return 0; }
969
ulong a = $new Convertible()$;
972
var c = GetConversion(program);
973
Assert.IsTrue(c.IsValid);
974
Assert.IsTrue(c.IsUserDefined);
975
Assert.AreEqual("us", c.Method.Parameters[0].Name);
979
public void UserDefinedImplicitConversion_NoMostEncompassingTargetTypeIsInvalid() {
980
string program = @"using System;
982
public static implicit operator uint(Convertible i) {return 0; }
983
public static implicit operator short(Convertible us) {return 0; }
987
long a = $new Convertible()$;
990
var c = GetConversion(program);
991
Assert.IsFalse(c.IsValid);
995
public void UserDefinedImplicitConversion_AmbiguousIsInvalid() {
996
string program = @"using System;
998
public static implicit operator Convertible2(Convertible1 c) {return 0; }
1000
class Convertible2 {
1001
public static implicit operator Convertible2(Convertible1 c) {return 0; }
1005
Convertible2 a = $new Convertible1()$;
1008
var c = GetConversion(program);
1009
Assert.IsFalse(c.IsValid);
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(); }
1021
Convertible? a = $(int?)33$;
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);
1032
public void UserDefinedImplicitConversion_UIntConstant() {
1033
string program = @"using System;
1035
public static implicit operator Convertible(long l) {return new Convertible(); }
1036
public static implicit operator Convertible(uint ui) {return new Convertible(); }
1040
Convertible a = $33$;
1043
var c = GetConversion(program);
1044
Assert.IsTrue(c.IsValid);
1045
Assert.IsTrue(c.IsUserDefined);
1046
Assert.AreEqual("ui", c.Method.Parameters[0].Name);
1050
public void UserDefinedImplicitConversion_NullableUIntConstant() {
1051
string program = @"using System;
1053
public static implicit operator Convertible(long? l) {return new Convertible(); }
1054
public static implicit operator Convertible(uint? ui) {return new Convertible(); }
1058
Convertible a = $33$;
1061
var c = GetConversion(program);
1062
Assert.IsTrue(c.IsValid);
1063
Assert.IsTrue(c.IsUserDefined);
1064
Assert.AreEqual("ui", c.Method.Parameters[0].Name);
1068
public void UserDefinedImplicitConversion_UseShortResult_BecauseNullableCannotBeUnpacked()
1070
string program = @"using System;
1072
public static implicit operator int?(Test i) { return 0; }
1073
public static implicit operator short(Test s) { return 0; }
1076
public static void Main(string[] args)
1078
int x = $new Test()$;
1081
var c = GetConversion(program);
1082
Assert.IsTrue(c.IsValid);
1083
Assert.IsTrue(c.IsUserDefined);
1084
Assert.AreEqual("System.Int16", c.Method.ReturnType.FullName);
1088
public void UserDefinedImplicitConversion_Short_Or_NullableByte_Target()
1090
string program = @"using System;
1092
public static implicit operator short(Test s) { return 0; }
1093
public static implicit operator byte?(Test b) { return 0; }
1096
public static void Main(string[] args)
1098
int? x = $new Test()$;
1101
var c = GetConversion(program);
1102
Assert.IsTrue(c.IsValid);
1103
Assert.IsTrue(c.IsUserDefined);
1104
Assert.AreEqual("System.Int16", c.Method.ReturnType.FullName);
1108
public void UserDefinedImplicitConversion_Byte_Or_NullableShort_Target()
1110
string program = @"using System;
1112
public static implicit operator byte(Test b) { return 0; }
1113
public static implicit operator short?(Test s) { return 0; }
1116
public static void Main(string[] args)
1118
int? x = $new Test()$;
1121
var c = GetConversion(program);
1122
Assert.IsTrue(c.IsValid);
1123
Assert.IsTrue(c.IsUserDefined);
1124
Assert.AreEqual("s", c.Method.Parameters[0].Name);
1128
public void UserDefinedImplicitConversion_Int_Or_NullableLong_Source()
1130
string program = @"using System;
1132
public static implicit operator Test(int i) { return new Test(); }
1133
public static implicit operator Test(long? l) { return new Test(); }
1136
static void Main() {
1141
var c = GetConversion(program);
1142
Assert.IsTrue(c.IsValid);
1143
Assert.IsTrue(c.IsUserDefined);
1144
Assert.AreEqual("i", c.Method.Parameters[0].Name);
1148
public void UserDefinedImplicitConversion_NullableInt_Or_Long_Source()
1150
string program = @"using System;
1152
public static implicit operator Test(int? i) { return new Test(); }
1153
public static implicit operator Test(long l) { return new Test(); }
1156
static void Main() {
1161
var c = GetConversion(program);
1162
Assert.IsFalse(c.IsValid);
1163
Assert.IsTrue(c.IsUserDefined);
1167
public void UserDefinedImplicitConversion_NullableInt_Or_Long_Constant_Source() {
1168
string program = @"using System;
1170
public static implicit operator Test(int? i) { return new Test(); }
1171
public static implicit operator Test(long l) { return new Test(); }
1174
static void Main() {
1178
var c = GetConversion(program);
1179
Assert.IsFalse(c.IsValid);
1180
Assert.IsTrue(c.IsUserDefined);
1184
public void UserDefinedImplicitConversion_NullableInt_Or_NullableLong_Source()
1186
string program = @"using System;
1188
public static implicit operator Test(int? i) { return new Test(); }
1189
public static implicit operator Test(long? l) { return new Test(); }
1192
static void Main() {
1197
var c = GetConversion(program);
1198
Assert.IsTrue(c.IsValid);
1199
Assert.IsTrue(c.IsUserDefined);
1200
Assert.AreEqual("i", c.Method.Parameters[0].Name);
1204
public void PreferUserDefinedConversionOverReferenceConversion()
1206
// actually this is not because user-defined conversions are better;
1207
// but because string is a better conversion target
1210
public static implicit operator string(AA a) { return null; }
1213
static void M(object obj) {}
1214
static void M(string str) {}
1216
static void Main() {
1221
var rr = Resolve<CSharpInvocationResolveResult>(program);
1222
Assert.IsFalse(rr.IsError);
1223
Assert.AreEqual("str", rr.Member.Parameters[0].Name);
1227
public void PreferAmbiguousConversionOverReferenceConversion()
1229
// Ambiguous conversions are a compiler error; but they are not
1230
// preventing the overload from being chosen.
1232
// The user-defined conversion wins because BB is a better conversion target than object.
1235
public static implicit operator BB(AA a) { return null; }
1238
public static implicit operator BB(AA a) { return null; }
1242
static void M(BB b) {}
1243
static void M(object o) {}
1245
static void Main() {
1250
var c = GetConversion(program);
1251
Assert.IsTrue(c.IsUserDefined);
1252
Assert.IsFalse(c.IsValid);
1256
public void UserDefinedImplicitConversion_ConversionBeforeUserDefinedOperatorIsCorrect() {
1257
string program = @"using System;
1259
public static implicit operator Convertible(long l) {return new Convertible(); }
1264
Convertible a = $i$;
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);
1276
public void UserDefinedImplicitConversion_ConversionAfterUserDefinedOperatorIsCorrect() {
1277
string program = @"using System;
1279
public static implicit operator int(Convertible i) {return 0; }
1283
long a = $new Convertible()$;
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);