1 // Licensed to the .NET Foundation under one or more agreements. 2 // The .NET Foundation licenses this file to you under the MIT license. 3 // See the LICENSE file in the project root for more information. 4 5 using System; 6 using System.Collections; 7 using System.Collections.Generic; 8 using System.Linq; 9 using System.Runtime.CompilerServices; 10 using System.Runtime.Serialization; 11 using Xunit; 12 13 namespace Microsoft.CSharp.RuntimeBinder.Tests 14 { 15 public class ImplicitConversionTests 16 { AssertImplicitConvert(TSource argument, TTarget expected)17 private static void AssertImplicitConvert<TSource, TTarget>(TSource argument, TTarget expected) 18 { 19 CallSiteBinder binder = Binder.Convert(CSharpBinderFlags.None, typeof(TTarget), typeof(ImplicitConversionTests)); 20 CallSite<Func<CallSite, TSource, TTarget>> callSite = 21 CallSite<Func<CallSite, TSource, TTarget>>.Create(binder); 22 Func<CallSite, TSource, TTarget> func = callSite.Target; 23 TTarget result = func(callSite, argument); 24 Assert.Equal(expected, result); 25 26 if (typeof(TSource) != typeof(object)) 27 { 28 AssertImplicitConvert<object, TTarget>(argument, expected); 29 } 30 } 31 AssertBadImplicitConvert(TSource argument)32 private static void AssertBadImplicitConvert<TSource, TTarget>(TSource argument) 33 { 34 CallSiteBinder binder = Binder.Convert(CSharpBinderFlags.None, typeof(TTarget), typeof(ImplicitConversionTests)); 35 CallSite<Func<CallSite, TSource, TTarget>> callSite = 36 CallSite<Func<CallSite, TSource, TTarget>>.Create(binder); 37 Func<CallSite, TSource, TTarget> func = callSite.Target; 38 Assert.Throws<RuntimeBinderException>(() => func(callSite, argument)); 39 40 if (typeof(TSource) != typeof(object)) 41 { 42 AssertBadImplicitConvert<object, TTarget>(argument); 43 } 44 } 45 TestTypeAsArgument(TTarget argument)46 private static void TestTypeAsArgument<TTarget>(TTarget argument) 47 { 48 // Do nothing. Just test whether something can be accepted as an argument. 49 } 50 TestBadTypeAsArgument(dynamic argument)51 private static void TestBadTypeAsArgument<TTarget>(dynamic argument) 52 { 53 Assert.Throws<RuntimeBinderException>(() => TestTypeAsArgument<TTarget>(argument)); 54 } 55 56 [Fact] NullablesToValueTypeUp()57 public void NullablesToValueTypeUp() 58 { 59 AssertImplicitConvert<int?, ValueType>(2, 2); 60 AssertImplicitConvert<int?, ValueType>(null, null); 61 AssertImplicitConvert<int?, object>(2, 2); 62 } 63 64 65 [Fact] NullablesToBaseTypesInterfaces()66 public void NullablesToBaseTypesInterfaces() 67 { 68 AssertImplicitConvert<int?, IEquatable<int>>(2, 2); 69 AssertImplicitConvert<int?, IEquatable<int>>(null, null); 70 AssertImplicitConvert<int?, IComparable<int>>(2, 2); 71 AssertImplicitConvert<int?, IComparable>(2, 2); 72 AssertImplicitConvert<int?, IConvertible>(2, 2); 73 AssertImplicitConvert<int?, IFormattable>(2, 2); 74 } 75 76 [Fact] NumericConversions()77 public void NumericConversions() 78 { 79 AssertImplicitConvert<sbyte, short>(1, 1); 80 AssertImplicitConvert<sbyte, int>(1, 1); 81 AssertImplicitConvert<sbyte, long>(1, 1); 82 AssertImplicitConvert<sbyte, float>(1, 1); 83 AssertImplicitConvert<sbyte, double>(1, 1); 84 AssertImplicitConvert<sbyte, decimal>(1, 1); 85 86 AssertImplicitConvert<byte, short>(1, 1); 87 AssertImplicitConvert<byte, ushort>(1, 1); 88 AssertImplicitConvert<byte, int>(1, 1); 89 AssertImplicitConvert<byte, uint>(1, 1); 90 AssertImplicitConvert<byte, long>(1, 1); 91 AssertImplicitConvert<byte, ulong>(1, 1); 92 AssertImplicitConvert<byte, float>(1, 1); 93 AssertImplicitConvert<byte, double>(1, 1); 94 AssertImplicitConvert<byte, decimal>(1, 1); 95 96 AssertImplicitConvert<short, int>(1, 1); 97 AssertImplicitConvert<short, long>(1, 1); 98 AssertImplicitConvert<short, float>(1, 1); 99 AssertImplicitConvert<short, double>(1, 1); 100 AssertImplicitConvert<short, decimal>(1, 1); 101 102 AssertImplicitConvert<ushort, int>(1, 1); 103 AssertImplicitConvert<ushort, uint>(1, 1); 104 AssertImplicitConvert<ushort, long>(1, 1); 105 AssertImplicitConvert<ushort, ulong>(1, 1); 106 AssertImplicitConvert<ushort, float>(1, 1); 107 AssertImplicitConvert<ushort, double>(1, 1); 108 AssertImplicitConvert<ushort, decimal>(1, 1); 109 110 AssertImplicitConvert<int, long>(1, 1); 111 AssertImplicitConvert<int, float>(1, 1); 112 AssertImplicitConvert<int, double>(1, 1); 113 AssertImplicitConvert<int, decimal>(1, 1); 114 115 AssertImplicitConvert<uint, long>(1, 1); 116 AssertImplicitConvert<uint, ulong>(1, 1); 117 AssertImplicitConvert<uint, float>(1, 1); 118 AssertImplicitConvert<uint, double>(1, 1); 119 AssertImplicitConvert<uint, decimal>(1, 1); 120 121 AssertImplicitConvert<long, float>(1, 1); 122 AssertImplicitConvert<long, double>(1, 1); 123 AssertImplicitConvert<long, decimal>(1, 1); 124 125 AssertImplicitConvert<ulong, float>(1, 1); 126 AssertImplicitConvert<ulong, double>(1, 1); 127 AssertImplicitConvert<ulong, decimal>(1, 1); 128 129 AssertImplicitConvert<float, double>(1, 1); 130 131 AssertImplicitConvert<char, ushort>('a', 'a'); 132 AssertImplicitConvert<char, int>('a', 'a'); 133 AssertImplicitConvert<char, uint>('a', 'a'); 134 AssertImplicitConvert<char, long>('a', 'a'); 135 AssertImplicitConvert<char, ulong>('a', 'a'); 136 AssertImplicitConvert<char, float>('a', 'a'); 137 AssertImplicitConvert<char, double>('a', 'a'); 138 AssertImplicitConvert<char, decimal>('a', 'a'); 139 } 140 141 [Fact] NumericNullableConversions()142 public void NumericNullableConversions() 143 { 144 AssertImplicitConvert<sbyte, short?>(1, 1); 145 AssertImplicitConvert<sbyte, int?>(1, 1); 146 AssertImplicitConvert<sbyte, long?>(1, 1); 147 AssertImplicitConvert<sbyte, float?>(1, 1); 148 AssertImplicitConvert<sbyte, double?>(1, 1); 149 AssertImplicitConvert<sbyte, decimal?>(1, 1); 150 151 AssertImplicitConvert<byte, short?>(1, 1); 152 AssertImplicitConvert<byte, ushort?>(1, 1); 153 AssertImplicitConvert<byte, int?>(1, 1); 154 AssertImplicitConvert<byte, uint?>(1, 1); 155 AssertImplicitConvert<byte, long?>(1, 1); 156 AssertImplicitConvert<byte, ulong?>(1, 1); 157 AssertImplicitConvert<byte, float?>(1, 1); 158 AssertImplicitConvert<byte, double?>(1, 1); 159 AssertImplicitConvert<byte, decimal?>(1, 1); 160 161 AssertImplicitConvert<short, int?>(1, 1); 162 AssertImplicitConvert<short, long?>(1, 1); 163 AssertImplicitConvert<short, float?>(1, 1); 164 AssertImplicitConvert<short, double?>(1, 1); 165 AssertImplicitConvert<short, decimal?>(1, 1); 166 167 AssertImplicitConvert<ushort, int?>(1, 1); 168 AssertImplicitConvert<ushort, uint?>(1, 1); 169 AssertImplicitConvert<ushort, long?>(1, 1); 170 AssertImplicitConvert<ushort, ulong?>(1, 1); 171 AssertImplicitConvert<ushort, float?>(1, 1); 172 AssertImplicitConvert<ushort, double?>(1, 1); 173 AssertImplicitConvert<ushort, decimal?>(1, 1); 174 175 AssertImplicitConvert<int, long?>(1, 1); 176 AssertImplicitConvert<int, float?>(1, 1); 177 AssertImplicitConvert<int, double?>(1, 1); 178 AssertImplicitConvert<int, decimal?>(1, 1); 179 180 AssertImplicitConvert<uint, long?>(1, 1); 181 AssertImplicitConvert<uint, ulong?>(1, 1); 182 AssertImplicitConvert<uint, float?>(1, 1); 183 AssertImplicitConvert<uint, double?>(1, 1); 184 AssertImplicitConvert<uint, decimal?>(1, 1); 185 186 AssertImplicitConvert<long, float?>(1, 1); 187 AssertImplicitConvert<long, double?>(1, 1); 188 AssertImplicitConvert<long, decimal?>(1, 1); 189 190 AssertImplicitConvert<ulong, float?>(1, 1); 191 AssertImplicitConvert<ulong, double?>(1, 1); 192 AssertImplicitConvert<ulong, decimal?>(1, 1); 193 194 AssertImplicitConvert<float, double?>(1, 1); 195 196 AssertImplicitConvert<char, ushort?>('a', 'a'); 197 AssertImplicitConvert<char, int?>('a', 'a'); 198 AssertImplicitConvert<char, uint?>('a', 'a'); 199 AssertImplicitConvert<char, long?>('a', 'a'); 200 AssertImplicitConvert<char, ulong?>('a', 'a'); 201 AssertImplicitConvert<char, float?>('a', 'a'); 202 AssertImplicitConvert<char, double?>('a', 'a'); 203 AssertImplicitConvert<char, decimal?>('a', 'a'); 204 } 205 206 [Fact] NumericNullableToNullableConversions()207 public void NumericNullableToNullableConversions() 208 { 209 AssertImplicitConvert<sbyte?, short?>(1, 1); 210 AssertImplicitConvert<sbyte?, int?>(1, 1); 211 AssertImplicitConvert<sbyte?, long?>(1, 1); 212 AssertImplicitConvert<sbyte?, float?>(1, 1); 213 AssertImplicitConvert<sbyte?, double?>(1, 1); 214 AssertImplicitConvert<sbyte?, decimal?>(1, 1); 215 216 AssertImplicitConvert<byte?, short?>(1, 1); 217 AssertImplicitConvert<byte?, ushort?>(1, 1); 218 AssertImplicitConvert<byte?, int?>(1, 1); 219 AssertImplicitConvert<byte?, uint?>(1, 1); 220 AssertImplicitConvert<byte?, long?>(1, 1); 221 AssertImplicitConvert<byte?, ulong?>(1, 1); 222 AssertImplicitConvert<byte?, float?>(1, 1); 223 AssertImplicitConvert<byte?, double?>(1, 1); 224 AssertImplicitConvert<byte?, decimal?>(1, 1); 225 226 AssertImplicitConvert<short?, int?>(1, 1); 227 AssertImplicitConvert<short?, long?>(1, 1); 228 AssertImplicitConvert<short?, float?>(1, 1); 229 AssertImplicitConvert<short?, double?>(1, 1); 230 AssertImplicitConvert<short?, decimal?>(1, 1); 231 232 AssertImplicitConvert<ushort?, int?>(1, 1); 233 AssertImplicitConvert<ushort?, uint?>(1, 1); 234 AssertImplicitConvert<ushort?, long?>(1, 1); 235 AssertImplicitConvert<ushort?, ulong?>(1, 1); 236 AssertImplicitConvert<ushort?, float?>(1, 1); 237 AssertImplicitConvert<ushort?, double?>(1, 1); 238 AssertImplicitConvert<ushort?, decimal?>(1, 1); 239 240 AssertImplicitConvert<int?, long?>(1, 1); 241 AssertImplicitConvert<int?, float?>(1, 1); 242 AssertImplicitConvert<int?, double?>(1, 1); 243 AssertImplicitConvert<int?, decimal?>(1, 1); 244 245 AssertImplicitConvert<uint?, long?>(1, 1); 246 AssertImplicitConvert<uint?, ulong?>(1, 1); 247 AssertImplicitConvert<uint?, float?>(1, 1); 248 AssertImplicitConvert<uint?, double?>(1, 1); 249 AssertImplicitConvert<uint?, decimal?>(1, 1); 250 251 AssertImplicitConvert<long?, float?>(1, 1); 252 AssertImplicitConvert<long?, double?>(1, 1); 253 AssertImplicitConvert<long?, decimal?>(1, 1); 254 255 AssertImplicitConvert<ulong?, float?>(1, 1); 256 AssertImplicitConvert<ulong?, double?>(1, 1); 257 AssertImplicitConvert<ulong?, decimal?>(1, 1); 258 259 AssertImplicitConvert<float?, double?>(1, 1); 260 261 AssertImplicitConvert<char?, ushort?>('a', 'a'); 262 AssertImplicitConvert<char?, int?>('a', 'a'); 263 AssertImplicitConvert<char?, uint?>('a', 'a'); 264 AssertImplicitConvert<char?, long?>('a', 'a'); 265 AssertImplicitConvert<char?, ulong?>('a', 'a'); 266 AssertImplicitConvert<char?, float?>('a', 'a'); 267 AssertImplicitConvert<char?, double?>('a', 'a'); 268 AssertImplicitConvert<char?, decimal?>('a', 'a'); 269 270 AssertImplicitConvert<sbyte?, short?>(null, null); 271 AssertImplicitConvert<sbyte?, int?>(null, null); 272 AssertImplicitConvert<sbyte?, long?>(null, null); 273 AssertImplicitConvert<sbyte?, float?>(null, null); 274 AssertImplicitConvert<sbyte?, double?>(null, null); 275 AssertImplicitConvert<sbyte?, decimal?>(null, null); 276 277 AssertImplicitConvert<byte?, short?>(null, null); 278 AssertImplicitConvert<byte?, ushort?>(null, null); 279 AssertImplicitConvert<byte?, int?>(null, null); 280 AssertImplicitConvert<byte?, uint?>(null, null); 281 AssertImplicitConvert<byte?, long?>(null, null); 282 AssertImplicitConvert<byte?, ulong?>(null, null); 283 AssertImplicitConvert<byte?, float?>(null, null); 284 AssertImplicitConvert<byte?, double?>(null, null); 285 AssertImplicitConvert<byte?, decimal?>(null, null); 286 287 AssertImplicitConvert<short?, int?>(null, null); 288 AssertImplicitConvert<short?, long?>(null, null); 289 AssertImplicitConvert<short?, float?>(null, null); 290 AssertImplicitConvert<short?, double?>(null, null); 291 AssertImplicitConvert<short?, decimal?>(null, null); 292 293 AssertImplicitConvert<ushort?, int?>(null, null); 294 AssertImplicitConvert<ushort?, uint?>(null, null); 295 AssertImplicitConvert<ushort?, long?>(null, null); 296 AssertImplicitConvert<ushort?, ulong?>(null, null); 297 AssertImplicitConvert<ushort?, float?>(null, null); 298 AssertImplicitConvert<ushort?, double?>(null, null); 299 AssertImplicitConvert<ushort?, decimal?>(null, null); 300 301 AssertImplicitConvert<int?, long?>(null, null); 302 AssertImplicitConvert<int?, float?>(null, null); 303 AssertImplicitConvert<int?, double?>(null, null); 304 AssertImplicitConvert<int?, decimal?>(null, null); 305 306 AssertImplicitConvert<uint?, long?>(null, null); 307 AssertImplicitConvert<uint?, ulong?>(null, null); 308 AssertImplicitConvert<uint?, float?>(null, null); 309 AssertImplicitConvert<uint?, double?>(null, null); 310 AssertImplicitConvert<uint?, decimal?>(null, null); 311 312 AssertImplicitConvert<long?, float?>(null, null); 313 AssertImplicitConvert<long?, double?>(null, null); 314 AssertImplicitConvert<long?, decimal?>(null, null); 315 316 AssertImplicitConvert<ulong?, float?>(null, null); 317 AssertImplicitConvert<ulong?, double?>(null, null); 318 AssertImplicitConvert<ulong?, decimal?>(null, null); 319 320 AssertImplicitConvert<float?, double?>(null, null); 321 322 AssertImplicitConvert<char?, ushort?>(null, null); 323 AssertImplicitConvert<char?, int?>(null, null); 324 AssertImplicitConvert<char?, uint?>(null, null); 325 AssertImplicitConvert<char?, long?>(null, null); 326 AssertImplicitConvert<char?, ulong?>(null, null); 327 AssertImplicitConvert<char?, float?>(null, null); 328 AssertImplicitConvert<char?, double?>(null, null); 329 AssertImplicitConvert<char?, decimal?>(null, null); 330 } 331 332 [Fact] StructToInterfacesAndBase()333 public void StructToInterfacesAndBase() 334 { 335 DateTime now = DateTime.Now; 336 AssertImplicitConvert<DateTime, IEquatable<DateTime>>(now, now); 337 AssertImplicitConvert<DateTime, IComparable<DateTime>>(now, now); 338 AssertImplicitConvert<DateTime, ISerializable>(now, now); 339 AssertImplicitConvert<DateTime, IFormattable>(now, now); 340 } 341 342 [Fact] ArraysToInterfaces()343 public void ArraysToInterfaces() 344 { 345 int[] intArray = {1, 2, 3}; 346 AssertImplicitConvert<int[], IEnumerable>(intArray, intArray); 347 AssertImplicitConvert<int[], IEnumerable<int>>(intArray, intArray); 348 AssertImplicitConvert<int[], IList<int>>(intArray, intArray); 349 AssertImplicitConvert<int[], ICollection<int>>(intArray, intArray); 350 AssertImplicitConvert<int[], IReadOnlyList<int>>(intArray, intArray); 351 AssertImplicitConvert<int[], IReadOnlyCollection<int>>(intArray, intArray); 352 } 353 354 [Fact] ArraysToInterfacesAsArguments()355 public void ArraysToInterfacesAsArguments() 356 { 357 dynamic intArray = new[] {1, 2, 3}; 358 TestTypeAsArgument<IEnumerable>(intArray); 359 TestTypeAsArgument<IEnumerable<int>>(intArray); 360 TestTypeAsArgument<IList<int>>(intArray); 361 TestTypeAsArgument<ICollection<int>>(intArray); 362 TestTypeAsArgument<IReadOnlyList<int>>(intArray); 363 TestTypeAsArgument<IReadOnlyCollection<int>>(intArray); 364 } 365 366 [Fact] ArraysToIncompatibleInterfaces()367 public void ArraysToIncompatibleInterfaces() 368 { 369 int[] intArray = { 1, 2, 3 }; 370 AssertBadImplicitConvert<int[], IEnumerable<string>>(intArray); 371 AssertBadImplicitConvert<int[], IList<int?>>(intArray); 372 AssertBadImplicitConvert<int[], ICollection<Uri>>(intArray); 373 AssertBadImplicitConvert<int[], IReadOnlyList<DateTime>>(intArray); 374 AssertBadImplicitConvert<int[], IReadOnlyCollection<long>>(intArray); 375 AssertBadImplicitConvert<int[], IOrderedEnumerable<int>>(intArray); 376 } 377 378 [Fact] ArraysToIncompatibleInterfacesAsArgument()379 public void ArraysToIncompatibleInterfacesAsArgument() 380 { 381 int[] intArray = { 1, 2, 3 }; 382 TestBadTypeAsArgument<IEnumerable<string>>(intArray); 383 TestBadTypeAsArgument<IList<int?>>(intArray); 384 TestBadTypeAsArgument<ICollection<Uri>>(intArray); 385 TestBadTypeAsArgument<IReadOnlyList<DateTime>>(intArray); 386 TestBadTypeAsArgument<IReadOnlyCollection<long>>(intArray); 387 TestBadTypeAsArgument<IOrderedEnumerable<int>>(intArray); 388 } 389 } 390 } 391