1 // 2 // conversion.cs: various routines for implementing conversions. 3 // 4 // Authors: 5 // Miguel de Icaza (miguel@ximian.com) 6 // Ravi Pratap (ravi@ximian.com) 7 // Marek Safar (marek.safar@gmail.com) 8 // 9 // Copyright 2001, 2002, 2003 Ximian, Inc. 10 // Copyright 2003-2008 Novell, Inc. 11 // Copyright 2011 Xamarin Inc (http://www.xamarin.com) 12 // 13 14 using System; 15 using System.Collections.Generic; 16 17 #if STATIC 18 using IKVM.Reflection.Emit; 19 #else 20 using System.Reflection.Emit; 21 #endif 22 23 namespace Mono.CSharp { 24 25 // 26 // A container class for all the conversion operations 27 // 28 static class Convert 29 { 30 [Flags] 31 public enum UserConversionRestriction 32 { 33 None = 0, 34 ImplicitOnly = 1, 35 ProbingOnly = 1 << 1, 36 NullableSourceOnly = 1 << 2 37 38 } 39 // 40 // From a one-dimensional array-type S[] to System.Collections.IList<T> and base 41 // interfaces of this interface, provided there is an implicit reference conversion 42 // from S to T. 43 // ArrayToIList(ArrayContainer array, TypeSpec list, bool isExplicit)44 static bool ArrayToIList (ArrayContainer array, TypeSpec list, bool isExplicit) 45 { 46 if (array.Rank != 1 || !list.IsArrayGenericInterface) 47 return false; 48 49 var arg_type = list.TypeArguments[0]; 50 if (array.Element == arg_type) 51 return true; 52 53 // 54 // Reject conversion from T[] to IList<U> even if T has U dependency 55 // 56 if (arg_type.IsGenericParameter) 57 return false; 58 59 if (isExplicit) 60 return ExplicitReferenceConversionExists (array.Element, arg_type); 61 62 return ImplicitReferenceConversionExists (array.Element, arg_type); 63 } 64 IList_To_Array(TypeSpec list, ArrayContainer array)65 static bool IList_To_Array(TypeSpec list, ArrayContainer array) 66 { 67 if (array.Rank != 1 || !list.IsArrayGenericInterface) 68 return false; 69 70 var arg_type = list.TypeArguments[0]; 71 if (array.Element == arg_type) 72 return true; 73 74 return ImplicitReferenceConversionExists (array.Element, arg_type) || ExplicitReferenceConversionExists (array.Element, arg_type); 75 } 76 ImplicitTypeParameterConversion(Expression expr, TypeParameterSpec expr_type, TypeSpec target_type)77 public static Expression ImplicitTypeParameterConversion (Expression expr, TypeParameterSpec expr_type, TypeSpec target_type) 78 { 79 // 80 // From T to a type parameter U, provided T depends on U 81 // 82 if (target_type.IsGenericParameter) { 83 if (expr_type.TypeArguments != null && expr_type.HasDependencyOn (target_type)) { 84 if (expr == null) 85 return EmptyExpression.Null; 86 87 if (expr_type.IsReferenceType && !((TypeParameterSpec) target_type).IsReferenceType) 88 return new BoxedCast (expr, target_type); 89 90 return new ClassCast (expr, target_type); 91 } 92 93 return null; 94 } 95 96 // 97 // LAMESPEC: From T to dynamic type because it's like T to object 98 // 99 if (target_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) { 100 if (expr == null) 101 return EmptyExpression.Null; 102 103 if (expr_type.IsReferenceType) 104 return new ClassCast (expr, target_type); 105 106 return new BoxedCast (expr, target_type); 107 } 108 109 // 110 // From T to its effective base class C 111 // From T to any base class of C (it cannot contain dynamic or be of dynamic type) 112 // From T to any interface implemented by C 113 // 114 var base_type = expr_type.GetEffectiveBase (); 115 if (base_type == target_type || TypeSpec.IsBaseClass (base_type, target_type, false) || base_type.ImplementsInterface (target_type, true)) { 116 if (expr == null) 117 return EmptyExpression.Null; 118 119 if (expr_type.IsReferenceType) 120 return new ClassCast (expr, target_type); 121 122 return new BoxedCast (expr, target_type); 123 } 124 125 if (target_type.IsInterface && expr_type.IsConvertibleToInterface (target_type)) { 126 if (expr == null) 127 return EmptyExpression.Null; 128 129 if (expr_type.IsReferenceType) 130 return new ClassCast (expr, target_type); 131 132 return new BoxedCast (expr, target_type); 133 } 134 135 return null; 136 } 137 ExplicitTypeParameterConversionFromT(Expression source, TypeSpec source_type, TypeSpec target_type)138 static Expression ExplicitTypeParameterConversionFromT (Expression source, TypeSpec source_type, TypeSpec target_type) 139 { 140 var target_tp = target_type as TypeParameterSpec; 141 if (target_tp != null) { 142 // 143 // From a type parameter U to T, provided T depends on U 144 // 145 if (target_tp.TypeArguments != null && target_tp.HasDependencyOn (source_type)) { 146 return source == null ? EmptyExpression.Null : new ClassCast (source, target_type); 147 } 148 } 149 150 // 151 // From T to any interface-type I provided there is not already an implicit conversion from T to I 152 // 153 if (target_type.IsInterface) 154 return source == null ? EmptyExpression.Null : new ClassCast (source, target_type, true); 155 156 return null; 157 } 158 ExplicitTypeParameterConversionToT(Expression source, TypeSpec source_type, TypeParameterSpec target_type)159 static Expression ExplicitTypeParameterConversionToT (Expression source, TypeSpec source_type, TypeParameterSpec target_type) 160 { 161 // 162 // From the effective base class C of T to T and from any base class of C to T 163 // 164 var effective = target_type.GetEffectiveBase (); 165 if (TypeSpecComparer.IsEqual (effective, source_type) || TypeSpec.IsBaseClass (effective, source_type, false)) 166 return source == null ? EmptyExpression.Null : new ClassCast (source, target_type); 167 168 return null; 169 } 170 ImplicitReferenceConversion(Expression expr, TypeSpec target_type, bool explicit_cast)171 public static Expression ImplicitReferenceConversion (Expression expr, TypeSpec target_type, bool explicit_cast) 172 { 173 TypeSpec expr_type = expr.Type; 174 175 if (expr_type.Kind == MemberKind.TypeParameter) 176 return ImplicitTypeParameterConversion (expr, (TypeParameterSpec) expr.Type, target_type); 177 178 // 179 // from the null type to any reference-type. 180 // 181 NullLiteral nl = expr as NullLiteral; 182 if (nl != null) { 183 return nl.ConvertImplicitly (target_type); 184 } 185 186 if (ImplicitReferenceConversionExists (expr_type, target_type)) { 187 // 188 // Avoid wrapping implicitly convertible reference type 189 // 190 if (!explicit_cast) 191 return expr; 192 193 return EmptyCast.Create (expr, target_type); 194 } 195 196 return null; 197 } 198 199 // 200 // Implicit reference conversions 201 // ImplicitReferenceConversionExists(TypeSpec expr_type, TypeSpec target_type)202 public static bool ImplicitReferenceConversionExists (TypeSpec expr_type, TypeSpec target_type) 203 { 204 return ImplicitReferenceConversionExists (expr_type, target_type, true); 205 } 206 ImplicitReferenceConversionExists(TypeSpec expr_type, TypeSpec target_type, bool refOnlyTypeParameter)207 public static bool ImplicitReferenceConversionExists (TypeSpec expr_type, TypeSpec target_type, bool refOnlyTypeParameter) 208 { 209 // It's here only to speed things up 210 if (target_type.IsStruct) 211 return false; 212 213 switch (expr_type.Kind) { 214 case MemberKind.TypeParameter: 215 return ImplicitTypeParameterConversion (null, (TypeParameterSpec) expr_type, target_type) != null && 216 (!refOnlyTypeParameter || TypeSpec.IsReferenceType (expr_type)); 217 218 case MemberKind.Class: 219 // 220 // From any class-type to dynamic (+object to speed up common path) 221 // 222 if (target_type.BuiltinType == BuiltinTypeSpec.Type.Object || target_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) 223 return true; 224 225 if (target_type.IsClass) { 226 // 227 // Identity conversion, including dynamic erasure 228 // 229 if (TypeSpecComparer.IsEqual (expr_type, target_type)) 230 return true; 231 232 // 233 // From any class-type S to any class-type T, provided S is derived from T 234 // 235 return TypeSpec.IsBaseClass (expr_type, target_type, true); 236 } 237 238 // 239 // From any class-type S to any interface-type T, provided S implements T 240 // 241 if (target_type.IsInterface) 242 return expr_type.ImplementsInterface (target_type, true); 243 244 return false; 245 246 case MemberKind.ArrayType: 247 // 248 // Identity array conversion 249 // 250 if (expr_type == target_type) 251 return true; 252 253 // 254 // From any array-type to System.Array 255 // 256 switch (target_type.BuiltinType) { 257 case BuiltinTypeSpec.Type.Array: 258 case BuiltinTypeSpec.Type.Object: 259 case BuiltinTypeSpec.Type.Dynamic: 260 return true; 261 } 262 263 var expr_type_array = (ArrayContainer) expr_type; 264 var target_type_array = target_type as ArrayContainer; 265 266 // 267 // From an array-type S to an array-type of type T 268 // 269 if (target_type_array != null && expr_type_array.Rank == target_type_array.Rank) { 270 271 // 272 // Both SE and TE are reference-types. TE check is defered 273 // to ImplicitReferenceConversionExists 274 // 275 TypeSpec expr_element_type = expr_type_array.Element; 276 if (!TypeSpec.IsReferenceType (expr_element_type)) 277 return false; 278 279 // 280 // An implicit reference conversion exists from SE to TE 281 // 282 return ImplicitReferenceConversionExists (expr_element_type, target_type_array.Element); 283 } 284 285 // 286 // From any array-type to the interfaces it implements 287 // 288 if (target_type.IsInterface) { 289 if (expr_type.ImplementsInterface (target_type, false)) 290 return true; 291 292 // from an array-type of type T to IList<T> 293 if (ArrayToIList (expr_type_array, target_type, false)) 294 return true; 295 } 296 297 return false; 298 299 case MemberKind.Delegate: 300 // 301 // From any delegate-type to System.Delegate (and its base types) 302 // 303 switch (target_type.BuiltinType) { 304 case BuiltinTypeSpec.Type.Delegate: 305 case BuiltinTypeSpec.Type.MulticastDelegate: 306 case BuiltinTypeSpec.Type.Object: 307 case BuiltinTypeSpec.Type.Dynamic: 308 return true; 309 } 310 311 // 312 // Identity conversion, including dynamic erasure 313 // 314 if (TypeSpecComparer.IsEqual (expr_type, target_type)) 315 return true; 316 317 // 318 // From any delegate-type to the interfaces it implements 319 // From any reference-type to an delegate type if is variance-convertible 320 // 321 return expr_type.ImplementsInterface (target_type, false) || TypeSpecComparer.Variant.IsEqual (expr_type, target_type); 322 323 case MemberKind.Interface: 324 // 325 // Identity conversion, including dynamic erasure 326 // 327 if (TypeSpecComparer.IsEqual (expr_type, target_type)) 328 return true; 329 330 // 331 // From any interface type S to interface-type T 332 // From any reference-type to an interface if is variance-convertible 333 // 334 if (target_type.IsInterface) 335 return TypeSpecComparer.Variant.IsEqual (expr_type, target_type) || expr_type.ImplementsInterface (target_type, true); 336 337 return target_type.BuiltinType == BuiltinTypeSpec.Type.Object || target_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic; 338 339 case MemberKind.InternalCompilerType: 340 // 341 // from the null literal to any reference-type. 342 // 343 if (expr_type == InternalType.NullLiteral) { 344 // Exlude internal compiler types 345 if (target_type.Kind == MemberKind.InternalCompilerType) 346 return target_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic; 347 348 return TypeSpec.IsReferenceType (target_type) || target_type.Kind == MemberKind.PointerType; 349 } 350 351 // 352 // Implicit dynamic conversion 353 // 354 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) { 355 switch (target_type.Kind) { 356 case MemberKind.ArrayType: 357 case MemberKind.Class: 358 case MemberKind.Delegate: 359 case MemberKind.Interface: 360 case MemberKind.TypeParameter: 361 return true; 362 } 363 364 // dynamic to __arglist 365 if (target_type == InternalType.Arglist) 366 return true; 367 368 return false; 369 } 370 371 break; 372 } 373 374 return false; 375 } 376 ImplicitBoxingConversion(Expression expr, TypeSpec expr_type, TypeSpec target_type)377 public static Expression ImplicitBoxingConversion (Expression expr, TypeSpec expr_type, TypeSpec target_type) 378 { 379 switch (target_type.BuiltinType) { 380 // 381 // From any non-nullable-value-type to the type object and dynamic 382 // 383 case BuiltinTypeSpec.Type.Object: 384 case BuiltinTypeSpec.Type.Dynamic: 385 // 386 // From any non-nullable-value-type to the type System.ValueType 387 // 388 case BuiltinTypeSpec.Type.ValueType: 389 // 390 // No ned to check for nullable type as underlying type is always convertible 391 // 392 if (!TypeSpec.IsValueType (expr_type)) 393 return null; 394 395 if (expr_type.IsByRefLike) 396 return null; 397 398 return expr == null ? EmptyExpression.Null : new BoxedCast (expr, target_type); 399 400 case BuiltinTypeSpec.Type.Enum: 401 // 402 // From any enum-type to the type System.Enum. 403 // 404 if (expr_type.IsEnum) 405 return expr == null ? EmptyExpression.Null : new BoxedCast (expr, target_type); 406 407 break; 408 } 409 410 // 411 // From a nullable-type to a reference type, if a boxing conversion exists from 412 // the underlying type to the reference type 413 // 414 if (expr_type.IsNullableType) { 415 if (!TypeSpec.IsReferenceType (target_type)) 416 return null; 417 418 var res = ImplicitBoxingConversion (expr, Nullable.NullableInfo.GetUnderlyingType (expr_type), target_type); 419 420 // "cast" underlying type to target type to emit correct InvalidCastException when 421 // underlying hierarchy changes without recompilation 422 if (res != null && expr != null) 423 res = new UnboxCast (res, target_type); 424 425 return res; 426 } 427 428 // 429 // A value type has a boxing conversion to an interface type I if it has a boxing conversion 430 // to an interface or delegate type I0 and I0 is variance-convertible to I 431 // 432 if (target_type.IsInterface && TypeSpec.IsValueType (expr_type) && expr_type.ImplementsInterface (target_type, true)) { 433 return expr == null ? EmptyExpression.Null : new BoxedCast (expr, target_type); 434 } 435 436 return null; 437 } 438 ImplicitNulableConversion(ResolveContext ec, Expression expr, TypeSpec target_type)439 public static Expression ImplicitNulableConversion (ResolveContext ec, Expression expr, TypeSpec target_type) 440 { 441 TypeSpec expr_type = expr.Type; 442 443 // 444 // From null to any nullable type 445 // 446 if (expr_type == InternalType.NullLiteral) 447 return ec == null ? EmptyExpression.Null : Nullable.LiftedNull.Create (target_type, expr.Location); 448 449 // S -> T? 450 TypeSpec t_el = Nullable.NullableInfo.GetUnderlyingType (target_type); 451 452 // S? -> T? 453 if (expr_type.IsNullableType) 454 expr_type = Nullable.NullableInfo.GetUnderlyingType (expr_type); 455 456 // 457 // Predefined implicit identity or implicit numeric conversion 458 // has to exist between underlying type S and underlying type T 459 // 460 461 // conversion exists only mode 462 if (ec == null) { 463 if (TypeSpecComparer.IsEqual (expr_type, t_el)) 464 return EmptyExpression.Null; 465 466 if (expr is Constant) 467 return ((Constant) expr).ConvertImplicitly (t_el); 468 469 return ImplicitNumericConversion (null, expr_type, t_el); 470 } 471 472 Expression unwrap; 473 if (expr_type != expr.Type) 474 unwrap = Nullable.Unwrap.Create (expr); 475 else 476 unwrap = expr; 477 478 Expression conv = unwrap; 479 if (!TypeSpecComparer.IsEqual (expr_type, t_el)) { 480 if (conv is Constant) 481 conv = ((Constant)conv).ConvertImplicitly (t_el); 482 else 483 conv = ImplicitNumericConversion (conv, expr_type, t_el); 484 485 if (conv == null) 486 return null; 487 } 488 489 if (expr_type != expr.Type) 490 return new Nullable.LiftedConversion (conv, unwrap, target_type).Resolve (ec); 491 492 return Nullable.Wrap.Create (conv, target_type); 493 } 494 495 /// <summary> 496 /// Implicit Numeric Conversions. 497 /// 498 /// expr is the expression to convert, returns a new expression of type 499 /// target_type or null if an implicit conversion is not possible. 500 /// </summary> ImplicitNumericConversion(Expression expr, TypeSpec target_type)501 public static Expression ImplicitNumericConversion (Expression expr, TypeSpec target_type) 502 { 503 return ImplicitNumericConversion (expr, expr.Type, target_type); 504 } 505 ImplicitNumericConversionExists(TypeSpec expr_type, TypeSpec target_type)506 public static bool ImplicitNumericConversionExists (TypeSpec expr_type, TypeSpec target_type) 507 { 508 return ImplicitNumericConversion (null, expr_type, target_type) != null; 509 } 510 ImplicitNumericConversion(Expression expr, TypeSpec expr_type, TypeSpec target_type)511 static Expression ImplicitNumericConversion (Expression expr, TypeSpec expr_type, TypeSpec target_type) 512 { 513 switch (expr_type.BuiltinType) { 514 case BuiltinTypeSpec.Type.SByte: 515 // 516 // From sbyte to short, int, long, float, double, decimal 517 // 518 switch (target_type.BuiltinType) { 519 case BuiltinTypeSpec.Type.Int: 520 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_I4); 521 case BuiltinTypeSpec.Type.Long: 522 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_I8); 523 case BuiltinTypeSpec.Type.Double: 524 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R8); 525 case BuiltinTypeSpec.Type.Float: 526 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R4); 527 case BuiltinTypeSpec.Type.Short: 528 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_I2); 529 case BuiltinTypeSpec.Type.Decimal: 530 return expr == null ? EmptyExpression.Null : new OperatorCast (expr, target_type); 531 532 } 533 534 break; 535 case BuiltinTypeSpec.Type.Byte: 536 // 537 // From byte to short, ushort, int, uint, long, ulong, float, double, decimal 538 // 539 switch (target_type.BuiltinType) { 540 case BuiltinTypeSpec.Type.Int: 541 case BuiltinTypeSpec.Type.UInt: 542 case BuiltinTypeSpec.Type.Short: 543 case BuiltinTypeSpec.Type.UShort: 544 return expr == null ? EmptyExpression.Null : EmptyCast.Create (expr, target_type); 545 case BuiltinTypeSpec.Type.ULong: 546 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_U8); 547 case BuiltinTypeSpec.Type.Long: 548 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_I8); 549 case BuiltinTypeSpec.Type.Float: 550 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R4); 551 case BuiltinTypeSpec.Type.Double: 552 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R8); 553 case BuiltinTypeSpec.Type.Decimal: 554 return expr == null ? EmptyExpression.Null : new OperatorCast (expr, target_type); 555 } 556 break; 557 case BuiltinTypeSpec.Type.Short: 558 // 559 // From short to int, long, float, double, decimal 560 // 561 switch (target_type.BuiltinType) { 562 case BuiltinTypeSpec.Type.Int: 563 return expr == null ? EmptyExpression.Null : EmptyCast.Create (expr, target_type); 564 case BuiltinTypeSpec.Type.Long: 565 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_I8); 566 case BuiltinTypeSpec.Type.Double: 567 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R8); 568 case BuiltinTypeSpec.Type.Float: 569 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R4); 570 case BuiltinTypeSpec.Type.Decimal: 571 return expr == null ? EmptyExpression.Null : new OperatorCast (expr, target_type); 572 } 573 break; 574 case BuiltinTypeSpec.Type.UShort: 575 // 576 // From ushort to int, uint, long, ulong, float, double, decimal 577 // 578 switch (target_type.BuiltinType) { 579 case BuiltinTypeSpec.Type.Int: 580 case BuiltinTypeSpec.Type.UInt: 581 return expr == null ? EmptyExpression.Null : EmptyCast.Create (expr, target_type); 582 case BuiltinTypeSpec.Type.ULong: 583 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_U8); 584 case BuiltinTypeSpec.Type.Long: 585 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_I8); 586 case BuiltinTypeSpec.Type.Double: 587 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R8); 588 case BuiltinTypeSpec.Type.Float: 589 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R4); 590 case BuiltinTypeSpec.Type.Decimal: 591 return expr == null ? EmptyExpression.Null : new OperatorCast (expr, target_type); 592 } 593 break; 594 case BuiltinTypeSpec.Type.Int: 595 // 596 // From int to long, float, double, decimal 597 // 598 switch (target_type.BuiltinType) { 599 case BuiltinTypeSpec.Type.Long: 600 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_I8); 601 case BuiltinTypeSpec.Type.Double: 602 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R8); 603 case BuiltinTypeSpec.Type.Float: 604 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R4); 605 case BuiltinTypeSpec.Type.Decimal: 606 return expr == null ? EmptyExpression.Null : new OperatorCast (expr, target_type); 607 } 608 break; 609 case BuiltinTypeSpec.Type.UInt: 610 // 611 // From uint to long, ulong, float, double, decimal 612 // 613 switch (target_type.BuiltinType) { 614 case BuiltinTypeSpec.Type.Long: 615 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_U8); 616 case BuiltinTypeSpec.Type.ULong: 617 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_U8); 618 case BuiltinTypeSpec.Type.Double: 619 return expr == null ? EmptyExpression.Null : new OpcodeCastDuplex (expr, target_type, OpCodes.Conv_R_Un, OpCodes.Conv_R8); 620 case BuiltinTypeSpec.Type.Float: 621 return expr == null ? EmptyExpression.Null : new OpcodeCastDuplex (expr, target_type, OpCodes.Conv_R_Un, OpCodes.Conv_R4); 622 case BuiltinTypeSpec.Type.Decimal: 623 return expr == null ? EmptyExpression.Null : new OperatorCast (expr, target_type); 624 } 625 break; 626 case BuiltinTypeSpec.Type.Long: 627 // 628 // From long to float, double, decimal 629 // 630 switch (target_type.BuiltinType) { 631 case BuiltinTypeSpec.Type.Double: 632 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R8); 633 case BuiltinTypeSpec.Type.Float: 634 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R4); 635 case BuiltinTypeSpec.Type.Decimal: 636 return expr == null ? EmptyExpression.Null : new OperatorCast (expr, target_type); 637 } 638 break; 639 case BuiltinTypeSpec.Type.ULong: 640 // 641 // From ulong to float, double, decimal 642 // 643 switch (target_type.BuiltinType) { 644 case BuiltinTypeSpec.Type.Double: 645 return expr == null ? EmptyExpression.Null : new OpcodeCastDuplex (expr, target_type, OpCodes.Conv_R_Un, OpCodes.Conv_R8); 646 case BuiltinTypeSpec.Type.Float: 647 return expr == null ? EmptyExpression.Null : new OpcodeCastDuplex (expr, target_type, OpCodes.Conv_R_Un, OpCodes.Conv_R4); 648 case BuiltinTypeSpec.Type.Decimal: 649 return expr == null ? EmptyExpression.Null : new OperatorCast (expr, target_type); 650 } 651 break; 652 case BuiltinTypeSpec.Type.Char: 653 // 654 // From char to ushort, int, uint, long, ulong, float, double, decimal 655 // 656 switch (target_type.BuiltinType) { 657 case BuiltinTypeSpec.Type.UShort: 658 case BuiltinTypeSpec.Type.Int: 659 case BuiltinTypeSpec.Type.UInt: 660 return expr == null ? EmptyExpression.Null : EmptyCast.Create (expr, target_type); 661 case BuiltinTypeSpec.Type.ULong: 662 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_U8); 663 case BuiltinTypeSpec.Type.Long: 664 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_I8); 665 case BuiltinTypeSpec.Type.Float: 666 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R4); 667 case BuiltinTypeSpec.Type.Double: 668 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R8); 669 case BuiltinTypeSpec.Type.Decimal: 670 return expr == null ? EmptyExpression.Null : new OperatorCast (expr, target_type); 671 } 672 break; 673 case BuiltinTypeSpec.Type.Float: 674 // 675 // float to double 676 // 677 if (target_type.BuiltinType == BuiltinTypeSpec.Type.Double) 678 return expr == null ? EmptyExpression.Null : new OpcodeCast (expr, target_type, OpCodes.Conv_R8); 679 break; 680 } 681 682 return null; 683 } 684 ImplicitTupleLiteralConversion(ResolveContext rc, Expression source, TypeSpec targetType, Location loc)685 static Expression ImplicitTupleLiteralConversion (ResolveContext rc, Expression source, TypeSpec targetType, Location loc) 686 { 687 var targetTypeArgument = targetType.TypeArguments; 688 if (source.Type.Arity != targetTypeArgument.Length) 689 return null; 690 691 var namedTarget = targetType as NamedTupleSpec; 692 var tupleLiteral = source as TupleLiteral; 693 Expression instance; 694 695 if (tupleLiteral == null && !ExpressionAnalyzer.IsInexpensiveLoad (source)) { 696 var expr_variable = LocalVariable.CreateCompilerGenerated (source.Type, rc.CurrentBlock, loc); 697 source = new CompilerAssign (expr_variable.CreateReferenceExpression (rc, loc), source, loc); 698 instance = expr_variable.CreateReferenceExpression (rc, loc); 699 } else { 700 instance = null; 701 } 702 703 var converted = new List<Expression> (targetType.Arity); 704 for (int i = 0; i < targetType.Arity; ++i) { 705 Expression elementSrc; 706 if (tupleLiteral != null) { 707 elementSrc = tupleLiteral.Elements [i].Expr; 708 709 if (namedTarget != null) { 710 var elementSrcName = tupleLiteral.Elements [i].Name; 711 if (elementSrcName != null && elementSrcName != namedTarget.Elements [i]) { 712 rc.Report.Warning (8123, 1, loc, 713 "The tuple element name `{0}' is ignored because a different name or no name is specified by the target type `{1}'", 714 elementSrcName, namedTarget.GetSignatureForErrorWithNames ()); 715 } 716 } 717 } else { 718 elementSrc = new MemberAccess (instance, NamedTupleSpec.GetElementPropertyName (i)).Resolve (rc); 719 } 720 721 var res = ImplicitConversionStandard (rc, elementSrc, targetTypeArgument [i], loc); 722 if (res == null) 723 return null; 724 725 converted.Add (res); 726 } 727 728 return new TupleLiteralConversion (source, targetType, converted, loc); 729 } 730 ImplicitTupleLiteralConversionExists(Expression source, TypeSpec targetType)731 static bool ImplicitTupleLiteralConversionExists (Expression source, TypeSpec targetType) 732 { 733 if (source.Type.Arity != targetType.Arity) 734 return false; 735 736 var srcTypeArgument = source.Type.TypeArguments; 737 var targetTypeArgument = targetType.TypeArguments; 738 739 var tupleLiteralElements = (source as TupleLiteral)?.Elements; 740 741 for (int i = 0; i < targetType.Arity; ++i) { 742 if (tupleLiteralElements != null) { 743 if (!ImplicitStandardConversionExists (tupleLiteralElements[i].Expr, targetTypeArgument [i])) { 744 return false; 745 } 746 } else { 747 if (!ImplicitStandardConversionExists (new EmptyExpression (srcTypeArgument [i]), targetTypeArgument [i])) { 748 return false; 749 } 750 } 751 } 752 753 return true; 754 } 755 756 757 // 758 // Full version of implicit conversion 759 // ImplicitConversionExists(ResolveContext ec, Expression expr, TypeSpec target_type)760 public static bool ImplicitConversionExists (ResolveContext ec, Expression expr, TypeSpec target_type) 761 { 762 if (ImplicitStandardConversionExists (ec, expr, target_type)) 763 return true; 764 765 if (expr.Type == InternalType.AnonymousMethod) { 766 if (!target_type.IsDelegate && !target_type.IsExpressionTreeType) 767 return false; 768 769 AnonymousMethodExpression ame = (AnonymousMethodExpression) expr; 770 return ame.ImplicitStandardConversionExists (ec, target_type); 771 } 772 773 // Conversion from __arglist to System.ArgIterator 774 if (expr.Type == InternalType.Arglist) 775 return target_type == ec.Module.PredefinedTypes.ArgIterator.TypeSpec; 776 777 return UserDefinedConversion (ec, expr, target_type, 778 UserConversionRestriction.ImplicitOnly | UserConversionRestriction.ProbingOnly, Location.Null) != null; 779 } 780 ImplicitStandardConversionExists(ResolveContext rc, Expression expr, TypeSpec target_type)781 public static bool ImplicitStandardConversionExists (ResolveContext rc, Expression expr, TypeSpec target_type) 782 { 783 if (expr.eclass == ExprClass.MethodGroup) { 784 if (target_type.IsDelegate && rc.Module.Compiler.Settings.Version != LanguageVersion.ISO_1) { 785 MethodGroupExpr mg = expr as MethodGroupExpr; 786 if (mg != null) 787 return DelegateCreation.ImplicitStandardConversionExists (rc, mg, target_type); 788 } 789 790 return false; 791 } 792 793 var interpolated_string = expr as InterpolatedString; 794 if (interpolated_string != null) { 795 if (target_type == rc.Module.PredefinedTypes.IFormattable.TypeSpec || target_type == rc.Module.PredefinedTypes.FormattableString.TypeSpec) 796 return true; 797 } 798 799 return ImplicitStandardConversionExists (expr, target_type); 800 } 801 802 // 803 // Implicit standard conversion (only core conversions are used here) 804 // ImplicitStandardConversionExists(Expression expr, TypeSpec target_type)805 public static bool ImplicitStandardConversionExists (Expression expr, TypeSpec target_type) 806 { 807 // 808 // Identity conversions 809 // Implicit numeric conversions 810 // Implicit nullable conversions 811 // Implicit reference conversions 812 // Boxing conversions 813 // Implicit constant expression conversions 814 // Implicit conversions involving type parameters 815 // 816 817 TypeSpec expr_type = expr.Type; 818 819 if (expr_type == target_type) 820 return true; 821 822 if (expr_type == InternalType.ThrowExpr || expr_type == InternalType.DefaultType) 823 return target_type.Kind != MemberKind.InternalCompilerType; 824 825 if (target_type.IsNullableType) 826 return ImplicitNulableConversion (null, expr, target_type) != null; 827 828 if (ImplicitNumericConversion (null, expr_type, target_type) != null) 829 return true; 830 831 if (ImplicitReferenceConversionExists (expr_type, target_type, false)) 832 return true; 833 834 if (ImplicitBoxingConversion (null, expr_type, target_type) != null) 835 return true; 836 837 if (expr_type.IsTupleType && target_type.IsTupleType) 838 return ImplicitTupleLiteralConversionExists (expr, target_type); 839 840 // 841 // Implicit Constant Expression Conversions 842 // 843 if (expr is IntConstant){ 844 int value = ((IntConstant) expr).Value; 845 switch (target_type.BuiltinType) { 846 case BuiltinTypeSpec.Type.SByte: 847 if (value >= SByte.MinValue && value <= SByte.MaxValue) 848 return true; 849 break; 850 case BuiltinTypeSpec.Type.Byte: 851 if (value >= 0 && value <= Byte.MaxValue) 852 return true; 853 break; 854 case BuiltinTypeSpec.Type.Short: 855 if (value >= Int16.MinValue && value <= Int16.MaxValue) 856 return true; 857 break; 858 case BuiltinTypeSpec.Type.UShort: 859 if (value >= UInt16.MinValue && value <= UInt16.MaxValue) 860 return true; 861 break; 862 case BuiltinTypeSpec.Type.UInt: 863 if (value >= 0) 864 return true; 865 break; 866 case BuiltinTypeSpec.Type.ULong: 867 // 868 // we can optimize this case: a positive int32 869 // always fits on a uint64. But we need an opcode 870 // to do it. 871 // 872 if (value >= 0) 873 return true; 874 875 break; 876 } 877 } 878 879 if (expr is LongConstant && target_type.BuiltinType == BuiltinTypeSpec.Type.ULong){ 880 // 881 // Try the implicit constant expression conversion 882 // from long to ulong, instead of a nice routine, 883 // we just inline it 884 // 885 long v = ((LongConstant) expr).Value; 886 if (v >= 0) 887 return true; 888 } 889 890 if (expr is IntegralConstant && target_type.IsEnum) { 891 var i = (IntegralConstant) expr; 892 // 893 // LAMESPEC: csc allows any constant like 0 values to be converted, including const float f = 0.0 894 // 895 // An implicit enumeration conversion permits the decimal-integer-literal 0 896 // to be converted to any enum-type and to any nullable-type whose underlying 897 // type is an enum-type 898 // 899 return i.IsZeroInteger; 900 } 901 902 // 903 // Implicit dynamic conversion for remaining value types. It should probably 904 // go somewhere else 905 // 906 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) { 907 switch (target_type.Kind) { 908 case MemberKind.Struct: 909 case MemberKind.Enum: 910 return true; 911 } 912 913 return false; 914 } 915 916 // 917 // In an unsafe context implicit conversions is extended to include 918 // 919 // From any pointer-type to the type void* 920 // From the null literal to any pointer-type. 921 // 922 // LAMESPEC: The specification claims this conversion is allowed in implicit conversion but 923 // in reality implicit standard conversion uses it 924 // 925 if (target_type.IsPointer && expr.Type.IsPointer && ((PointerContainer) target_type).Element.Kind == MemberKind.Void) 926 return true; 927 928 // 929 // Struct identity conversion, including dynamic erasure 930 // 931 if (expr_type.IsStruct && TypeSpecComparer.IsEqual (expr_type, target_type)) 932 return true; 933 934 return false; 935 } 936 937 /// <summary> 938 /// Finds "most encompassed type" according to the spec (13.4.2) 939 /// amongst the methods in the MethodGroupExpr 940 /// </summary> FindMostEncompassedType(IList<TypeSpec> types)941 public static TypeSpec FindMostEncompassedType (IList<TypeSpec> types) 942 { 943 TypeSpec best = null; 944 EmptyExpression expr; 945 946 foreach (TypeSpec t in types) { 947 if (best == null) { 948 best = t; 949 continue; 950 } 951 952 expr = new EmptyExpression (t); 953 if (ImplicitStandardConversionExists (expr, best)) 954 best = t; 955 } 956 957 expr = new EmptyExpression (best); 958 foreach (TypeSpec t in types) { 959 if (best == t) 960 continue; 961 if (!ImplicitStandardConversionExists (expr, t)) { 962 best = null; 963 break; 964 } 965 } 966 967 return best; 968 } 969 970 // 971 // Finds the most encompassing type (type into which all other 972 // types can convert to) amongst the types in the given set 973 // FindMostEncompassingType(IList<TypeSpec> types)974 static TypeSpec FindMostEncompassingType (IList<TypeSpec> types) 975 { 976 if (types.Count == 0) 977 return null; 978 979 if (types.Count == 1) 980 return types [0]; 981 982 TypeSpec best = null; 983 for (int i = 0; i < types.Count; ++i) { 984 int ii = 0; 985 for (; ii < types.Count; ++ii) { 986 if (ii == i) 987 continue; 988 989 var expr = new EmptyExpression (types[ii]); 990 if (!ImplicitStandardConversionExists (expr, types [i])) { 991 ii = 0; 992 break; 993 } 994 } 995 996 if (ii == 0) 997 continue; 998 999 if (best == null) { 1000 best = types[i]; 1001 continue; 1002 } 1003 1004 // Indicates multiple best types 1005 return InternalType.FakeInternalType; 1006 } 1007 1008 return best; 1009 } 1010 1011 // 1012 // Finds the most specific source Sx according to the rules of the spec (13.4.4) 1013 // by making use of FindMostEncomp* methods. Applies the correct rules separately 1014 // for explicit and implicit conversion operators. 1015 // FindMostSpecificSource(ResolveContext rc, List<MethodSpec> list, TypeSpec sourceType, Expression source, bool apply_explicit_conv_rules)1016 static TypeSpec FindMostSpecificSource (ResolveContext rc, List<MethodSpec> list, TypeSpec sourceType, Expression source, bool apply_explicit_conv_rules) 1017 { 1018 TypeSpec[] src_types_set = null; 1019 1020 // 1021 // Try exact match first, if any operator converts from S then Sx = S 1022 // 1023 for (int i = 0; i < list.Count; ++i) { 1024 TypeSpec param_type = list [i].Parameters.Types [0]; 1025 1026 if (param_type == sourceType) 1027 return param_type; 1028 1029 if (src_types_set == null) 1030 src_types_set = new TypeSpec [list.Count]; 1031 1032 src_types_set [i] = param_type; 1033 } 1034 1035 // 1036 // Explicit Conv rules 1037 // 1038 if (apply_explicit_conv_rules) { 1039 var candidate_set = new List<TypeSpec> (); 1040 1041 foreach (TypeSpec param_type in src_types_set){ 1042 if (ImplicitStandardConversionExists (rc, source, param_type)) 1043 candidate_set.Add (param_type); 1044 } 1045 1046 if (candidate_set.Count != 0) { 1047 if (source.eclass == ExprClass.MethodGroup) 1048 return InternalType.FakeInternalType; 1049 1050 return FindMostEncompassedType (candidate_set); 1051 } 1052 } 1053 1054 // 1055 // Final case 1056 // 1057 if (apply_explicit_conv_rules) 1058 return FindMostEncompassingType (src_types_set); 1059 else 1060 return FindMostEncompassedType (src_types_set); 1061 } 1062 1063 /// <summary> 1064 /// Finds the most specific target Tx according to section 13.4.4 1065 /// </summary> FindMostSpecificTarget(IList<MethodSpec> list, TypeSpec target, bool apply_explicit_conv_rules)1066 static public TypeSpec FindMostSpecificTarget (IList<MethodSpec> list, 1067 TypeSpec target, bool apply_explicit_conv_rules) 1068 { 1069 List<TypeSpec> tgt_types_set = null; 1070 1071 // 1072 // If any operator converts to T then Tx = T 1073 // 1074 foreach (var mi in list){ 1075 TypeSpec ret_type = mi.ReturnType; 1076 if (ret_type == target) 1077 return ret_type; 1078 1079 if (tgt_types_set == null) { 1080 tgt_types_set = new List<TypeSpec> (list.Count); 1081 } else if (tgt_types_set.Contains (ret_type)) { 1082 continue; 1083 } 1084 1085 tgt_types_set.Add (ret_type); 1086 } 1087 1088 // 1089 // Explicit conv rules 1090 // 1091 if (apply_explicit_conv_rules) { 1092 var candidate_set = new List<TypeSpec> (); 1093 1094 foreach (TypeSpec ret_type in tgt_types_set) { 1095 var expr = new EmptyExpression (ret_type); 1096 1097 if (ImplicitStandardConversionExists (expr, target)) 1098 candidate_set.Add (ret_type); 1099 } 1100 1101 if (candidate_set.Count != 0) 1102 return FindMostEncompassingType (candidate_set); 1103 } 1104 1105 // 1106 // Okay, final case ! 1107 // 1108 if (apply_explicit_conv_rules) 1109 return FindMostEncompassedType (tgt_types_set); 1110 else 1111 return FindMostEncompassingType (tgt_types_set); 1112 } 1113 1114 /// <summary> 1115 /// User-defined Implicit conversions 1116 /// </summary> ImplicitUserConversion(ResolveContext ec, Expression source, TypeSpec target, Location loc)1117 static public Expression ImplicitUserConversion (ResolveContext ec, Expression source, TypeSpec target, Location loc) 1118 { 1119 return UserDefinedConversion (ec, source, target, UserConversionRestriction.ImplicitOnly, loc); 1120 } 1121 1122 /// <summary> 1123 /// User-defined Explicit conversions 1124 /// </summary> ExplicitUserConversion(ResolveContext ec, Expression source, TypeSpec target, Location loc)1125 static Expression ExplicitUserConversion (ResolveContext ec, Expression source, TypeSpec target, Location loc) 1126 { 1127 return UserDefinedConversion (ec, source, target, 0, loc); 1128 } 1129 FindApplicableUserDefinedConversionOperators(ResolveContext rc, IList<MemberSpec> operators, Expression source, TypeSpec target, UserConversionRestriction restr, ref List<MethodSpec> candidates)1130 static void FindApplicableUserDefinedConversionOperators (ResolveContext rc, IList<MemberSpec> operators, Expression source, TypeSpec target, UserConversionRestriction restr, ref List<MethodSpec> candidates) 1131 { 1132 if (source.Type.IsInterface) { 1133 // Neither A nor B are interface-types 1134 return; 1135 } 1136 1137 // For a conversion operator to be applicable, it must be possible 1138 // to perform a standard conversion from the source type to 1139 // the operand type of the operator, and it must be possible 1140 // to perform a standard conversion from the result type of 1141 // the operator to the target type. 1142 1143 Expression texpr = null; 1144 1145 foreach (MethodSpec op in operators) { 1146 1147 // Can be null because MemberCache.GetUserOperator does not resize the array 1148 if (op == null) 1149 continue; 1150 1151 var t = op.Parameters.Types[0]; 1152 if (source.Type != t && !ImplicitStandardConversionExists (rc, source, t)) { 1153 if ((restr & UserConversionRestriction.ImplicitOnly) != 0) 1154 continue; 1155 1156 if (!ImplicitStandardConversionExists (new EmptyExpression (t), source.Type)) 1157 continue; 1158 } 1159 1160 if ((restr & UserConversionRestriction.NullableSourceOnly) != 0 && !t.IsNullableType) 1161 continue; 1162 1163 t = op.ReturnType; 1164 1165 if (t.IsInterface) 1166 continue; 1167 1168 if (target != t) { 1169 if (t.IsNullableType) 1170 t = Nullable.NullableInfo.GetUnderlyingType (t); 1171 1172 if (!ImplicitStandardConversionExists (new EmptyExpression (t), target)) { 1173 if ((restr & UserConversionRestriction.ImplicitOnly) != 0) 1174 continue; 1175 1176 if (texpr == null) 1177 texpr = new EmptyExpression (target); 1178 1179 if (!ImplicitStandardConversionExists (texpr, t)) 1180 continue; 1181 } 1182 } 1183 1184 if (candidates == null) 1185 candidates = new List<MethodSpec> (); 1186 1187 candidates.Add (op); 1188 } 1189 } 1190 1191 // 1192 // User-defined conversions 1193 // UserDefinedConversion(ResolveContext rc, Expression source, TypeSpec target, UserConversionRestriction restr, Location loc)1194 public static Expression UserDefinedConversion (ResolveContext rc, Expression source, TypeSpec target, UserConversionRestriction restr, Location loc) 1195 { 1196 List<MethodSpec> candidates = null; 1197 1198 // 1199 // If S or T are nullable types, source_type and target_type are their underlying types 1200 // otherwise source_type and target_type are equal to S and T respectively. 1201 // 1202 TypeSpec source_type = source.Type; 1203 TypeSpec target_type = target; 1204 Expression source_type_expr; 1205 bool nullable_source = false; 1206 var implicitOnly = (restr & UserConversionRestriction.ImplicitOnly) != 0; 1207 1208 if (source_type.IsNullableType) { 1209 // No unwrapping conversion S? -> T for non-reference types 1210 if (implicitOnly && !TypeSpec.IsReferenceType (target_type) && !target_type.IsNullableType) { 1211 source_type_expr = source; 1212 } else { 1213 source_type_expr = Nullable.Unwrap.CreateUnwrapped (source); 1214 source_type = source_type_expr.Type; 1215 nullable_source = true; 1216 } 1217 } else { 1218 source_type_expr = source; 1219 } 1220 1221 if (target_type.IsNullableType) 1222 target_type = Nullable.NullableInfo.GetUnderlyingType (target_type); 1223 1224 // Only these containers can contain a user defined implicit or explicit operators 1225 const MemberKind user_conversion_kinds = MemberKind.Class | MemberKind.Struct | MemberKind.TypeParameter; 1226 1227 if ((source_type.Kind & user_conversion_kinds) != 0 && source_type.BuiltinType != BuiltinTypeSpec.Type.Decimal) { 1228 bool declared_only = source_type.IsStruct; 1229 1230 var operators = MemberCache.GetUserOperator (source_type, Operator.OpType.Implicit, declared_only); 1231 if (operators != null) { 1232 FindApplicableUserDefinedConversionOperators (rc, operators, source_type_expr, target_type, restr, ref candidates); 1233 } 1234 1235 if (!implicitOnly) { 1236 operators = MemberCache.GetUserOperator (source_type, Operator.OpType.Explicit, declared_only); 1237 if (operators != null) { 1238 FindApplicableUserDefinedConversionOperators (rc, operators, source_type_expr, target_type, restr, ref candidates); 1239 } 1240 } 1241 } 1242 1243 if ((target.Kind & user_conversion_kinds) != 0 && target_type.BuiltinType != BuiltinTypeSpec.Type.Decimal) { 1244 bool declared_only = target.IsStruct || implicitOnly; 1245 1246 var operators = MemberCache.GetUserOperator (target_type, Operator.OpType.Implicit, declared_only); 1247 if (operators != null) { 1248 FindApplicableUserDefinedConversionOperators (rc, operators, source_type_expr, target_type, restr, ref candidates); 1249 } 1250 1251 if (!implicitOnly) { 1252 operators = MemberCache.GetUserOperator (target_type, Operator.OpType.Explicit, declared_only); 1253 if (operators != null) { 1254 FindApplicableUserDefinedConversionOperators (rc, operators, source_type_expr, target_type, restr, ref candidates); 1255 } 1256 } 1257 } 1258 1259 if (candidates == null) 1260 return null; 1261 1262 // 1263 // Find the most specific conversion operator 1264 // 1265 MethodSpec most_specific_operator; 1266 TypeSpec s_x, t_x; 1267 if (candidates.Count == 1) { 1268 most_specific_operator = candidates[0]; 1269 s_x = most_specific_operator.Parameters.Types[0]; 1270 t_x = most_specific_operator.ReturnType; 1271 } else { 1272 // 1273 // Pass original source type to find the best match against input type and 1274 // not the unwrapped expression 1275 // 1276 s_x = FindMostSpecificSource (rc, candidates, source.Type, source_type_expr, !implicitOnly); 1277 if (s_x == null) 1278 return null; 1279 1280 t_x = FindMostSpecificTarget (candidates, target, !implicitOnly); 1281 if (t_x == null) 1282 return null; 1283 1284 most_specific_operator = null; 1285 for (int i = 0; i < candidates.Count; ++i) { 1286 if (candidates[i].ReturnType == t_x && candidates[i].Parameters.Types[0] == s_x) { 1287 most_specific_operator = candidates[i]; 1288 break; 1289 } 1290 } 1291 1292 if (most_specific_operator == null) { 1293 // 1294 // Unless running in probing more 1295 // 1296 if ((restr & UserConversionRestriction.ProbingOnly) == 0) { 1297 MethodSpec ambig_arg = candidates [0]; 1298 most_specific_operator = candidates [1]; 1299 /* 1300 foreach (var candidate in candidates) { 1301 if (candidate.ReturnType == t_x) 1302 most_specific_operator = candidate; 1303 else if (candidate.Parameters.Types[0] == s_x) 1304 ambig_arg = candidate; 1305 } 1306 */ 1307 rc.Report.Error (457, loc, 1308 "Ambiguous user defined operators `{0}' and `{1}' when converting from `{2}' to `{3}'", 1309 ambig_arg.GetSignatureForError (), most_specific_operator.GetSignatureForError (), 1310 source.Type.GetSignatureForError (), target.GetSignatureForError ()); 1311 } 1312 1313 return ErrorExpression.Instance; 1314 } 1315 } 1316 1317 // 1318 // Convert input type when it's different to best operator argument 1319 // 1320 if (s_x != source_type) { 1321 var c = source as Constant; 1322 if (c != null) { 1323 source = c.Reduce (rc, s_x); 1324 if (source == null) 1325 c = null; 1326 } 1327 1328 if (c == null) { 1329 source = implicitOnly ? 1330 ImplicitConversionStandard (rc, source_type_expr, s_x, loc) : 1331 ExplicitConversionStandard (rc, source_type_expr, s_x, loc); 1332 } 1333 } else { 1334 source = source_type_expr; 1335 } 1336 1337 source = new UserCast (most_specific_operator, source, loc).Resolve (rc); 1338 1339 // 1340 // Convert result type when it's different to best operator return type 1341 // 1342 if (t_x != target_type) { 1343 // 1344 // User operator is of T? 1345 // 1346 if (t_x.IsNullableType && (target.IsNullableType || !implicitOnly)) { 1347 // 1348 // User operator return type does not match target type we need 1349 // yet another conversion. This should happen for promoted numeric 1350 // types only 1351 // 1352 if (t_x != target) { 1353 var unwrap = Nullable.Unwrap.CreateUnwrapped (source); 1354 1355 source = implicitOnly ? 1356 ImplicitConversionStandard (rc, unwrap, target_type, loc) : 1357 ExplicitConversionStandard (rc, unwrap, target_type, loc); 1358 1359 if (source == null) 1360 return null; 1361 1362 if (target.IsNullableType) 1363 source = new Nullable.LiftedConversion (source, unwrap, target).Resolve (rc); 1364 } 1365 } else { 1366 source = implicitOnly ? 1367 ImplicitConversionStandard (rc, source, target_type, loc) : 1368 ExplicitConversionStandard (rc, source, target_type, loc); 1369 1370 if (source == null) 1371 return null; 1372 } 1373 } 1374 1375 1376 // 1377 // Source expression is of nullable type and underlying conversion returns 1378 // only non-nullable type we need to lift it manually 1379 // 1380 if (nullable_source && !s_x.IsNullableType) 1381 return new Nullable.LiftedConversion (source, source_type_expr, target).Resolve (rc); 1382 1383 // 1384 // Target is of nullable type but source type is not, wrap the result expression 1385 // 1386 if (target.IsNullableType && !t_x.IsNullableType) 1387 source = Nullable.Wrap.Create (source, target); 1388 1389 return source; 1390 } 1391 1392 /// <summary> 1393 /// Converts implicitly the resolved expression `expr' into the 1394 /// `target_type'. It returns a new expression that can be used 1395 /// in a context that expects a `target_type'. 1396 /// </summary> ImplicitConversion(ResolveContext ec, Expression expr, TypeSpec target_type, Location loc)1397 static public Expression ImplicitConversion (ResolveContext ec, Expression expr, 1398 TypeSpec target_type, Location loc) 1399 { 1400 Expression e; 1401 1402 if (target_type == null) 1403 throw new Exception ("Target type is null"); 1404 1405 e = ImplicitConversionStandard (ec, expr, target_type, loc); 1406 if (e != null) 1407 return e; 1408 1409 e = ImplicitUserConversion (ec, expr, target_type, loc); 1410 if (e != null) 1411 return e; 1412 1413 return null; 1414 } 1415 1416 1417 /// <summary> 1418 /// Attempts to apply the `Standard Implicit 1419 /// Conversion' rules to the expression `expr' into 1420 /// the `target_type'. It returns a new expression 1421 /// that can be used in a context that expects a 1422 /// `target_type'. 1423 /// 1424 /// This is different from `ImplicitConversion' in that the 1425 /// user defined implicit conversions are excluded. 1426 /// </summary> ImplicitConversionStandard(ResolveContext ec, Expression expr, TypeSpec target_type, Location loc)1427 static public Expression ImplicitConversionStandard (ResolveContext ec, Expression expr, 1428 TypeSpec target_type, Location loc) 1429 { 1430 return ImplicitConversionStandard (ec, expr, target_type, loc, false); 1431 } 1432 ImplicitConversionStandard(ResolveContext ec, Expression expr, TypeSpec target_type, Location loc, bool explicit_cast)1433 static Expression ImplicitConversionStandard (ResolveContext ec, Expression expr, TypeSpec target_type, Location loc, bool explicit_cast) 1434 { 1435 if (expr.eclass == ExprClass.MethodGroup){ 1436 if (!target_type.IsDelegate){ 1437 return null; 1438 } 1439 1440 // 1441 // Only allow anonymous method conversions on post ISO_1 1442 // 1443 if (ec.Module.Compiler.Settings.Version != LanguageVersion.ISO_1){ 1444 MethodGroupExpr mg = expr as MethodGroupExpr; 1445 if (mg != null) 1446 return new ImplicitDelegateCreation (target_type, mg, loc).Resolve (ec); 1447 } 1448 } 1449 1450 TypeSpec expr_type = expr.Type; 1451 Expression e; 1452 1453 if (expr_type == target_type) { 1454 if (expr_type != InternalType.NullLiteral && expr_type != InternalType.AnonymousMethod && expr_type != InternalType.ThrowExpr) 1455 return expr; 1456 return null; 1457 } 1458 1459 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) { 1460 switch (target_type.Kind) { 1461 case MemberKind.ArrayType: 1462 case MemberKind.Class: 1463 if (target_type.BuiltinType == BuiltinTypeSpec.Type.Object) 1464 return EmptyCast.Create (expr, target_type); 1465 1466 goto case MemberKind.Struct; 1467 case MemberKind.Struct: 1468 case MemberKind.Delegate: 1469 case MemberKind.Enum: 1470 case MemberKind.Interface: 1471 case MemberKind.TypeParameter: 1472 Arguments args = new Arguments (1); 1473 args.Add (new Argument (expr)); 1474 return new DynamicConversion (target_type, explicit_cast ? CSharpBinderFlags.ConvertExplicit : 0, args, loc).Resolve (ec); 1475 } 1476 1477 return null; 1478 } 1479 1480 if (expr_type == InternalType.ThrowExpr) { 1481 return target_type.Kind == MemberKind.InternalCompilerType ? null : EmptyCast.Create (expr, target_type); 1482 } 1483 1484 if (expr_type == InternalType.DefaultType) { 1485 return new DefaultValueExpression (new TypeExpression (target_type, expr.Location), expr.Location).Resolve (ec); 1486 } 1487 1488 if (target_type.IsNullableType) 1489 return ImplicitNulableConversion (ec, expr, target_type); 1490 1491 // 1492 // Attempt to do the implicit constant expression conversions 1493 // 1494 Constant c = expr as Constant; 1495 if (c != null) { 1496 try { 1497 c = c.ConvertImplicitly (target_type); 1498 } catch { 1499 throw new InternalErrorException ("Conversion error", loc); 1500 } 1501 if (c != null) 1502 return c; 1503 } 1504 1505 if (expr_type.IsTupleType) { 1506 if (target_type.IsTupleType) 1507 return ImplicitTupleLiteralConversion (ec, expr, target_type, loc); 1508 1509 if (expr is TupleLiteral && TupleLiteral.ContainsNoTypeElement (expr_type)) 1510 return null; 1511 } 1512 1513 if (expr is ReferenceExpression) { 1514 // Only identify conversion is allowed 1515 return null; 1516 } 1517 1518 e = ImplicitNumericConversion (expr, expr_type, target_type); 1519 if (e != null) 1520 return e; 1521 1522 e = ImplicitReferenceConversion (expr, target_type, explicit_cast); 1523 if (e != null) 1524 return e; 1525 1526 e = ImplicitBoxingConversion (expr, expr_type, target_type); 1527 if (e != null) 1528 return e; 1529 1530 if (expr is IntegralConstant && target_type.IsEnum){ 1531 var i = (IntegralConstant) expr; 1532 // 1533 // LAMESPEC: csc allows any constant like 0 values to be converted, including const float f = 0.0 1534 // 1535 // An implicit enumeration conversion permits the decimal-integer-literal 0 1536 // to be converted to any enum-type and to any nullable-type whose underlying 1537 // type is an enum-type 1538 // 1539 if (i.IsZeroInteger) { 1540 // Recreate 0 literal to remove any collected conversions 1541 return new EnumConstant (new IntLiteral (ec.BuiltinTypes, 0, i.Location), target_type); 1542 } 1543 } 1544 1545 var target_pc = target_type as PointerContainer; 1546 if (target_pc != null) { 1547 if (expr_type.IsPointer) { 1548 // 1549 // Pointer types are same when they have same element types 1550 // 1551 if (expr_type == target_pc) 1552 return expr; 1553 1554 if (target_pc.Element.Kind == MemberKind.Void) 1555 return EmptyCast.Create (expr, target_type); 1556 1557 //return null; 1558 } 1559 1560 if (expr_type == InternalType.NullLiteral) 1561 return new NullPointer (target_type, loc); 1562 } 1563 1564 if (expr_type == InternalType.AnonymousMethod){ 1565 AnonymousMethodExpression ame = (AnonymousMethodExpression) expr; 1566 Expression am = ame.Compatible (ec, target_type); 1567 if (am != null) 1568 return am.Resolve (ec); 1569 1570 // Avoid CS1503 after CS1661 1571 return ErrorExpression.Instance; 1572 } 1573 1574 if (expr_type == InternalType.Arglist && target_type == ec.Module.PredefinedTypes.ArgIterator.TypeSpec) 1575 return expr; 1576 1577 // 1578 // dynamic erasure conversion on value types 1579 // 1580 if (expr_type.IsStruct && TypeSpecComparer.IsEqual (expr_type, target_type)) 1581 return expr_type == target_type ? expr : EmptyCast.Create (expr, target_type); 1582 1583 var interpolated_string = expr as InterpolatedString; 1584 if (interpolated_string != null) { 1585 if (target_type == ec.Module.PredefinedTypes.IFormattable.TypeSpec || target_type == ec.Module.PredefinedTypes.FormattableString.TypeSpec) 1586 return interpolated_string.ConvertTo (ec, target_type); 1587 } 1588 1589 return null; 1590 } 1591 1592 /// <summary> 1593 /// Attempts to implicitly convert `source' into `target_type', using 1594 /// ImplicitConversion. If there is no implicit conversion, then 1595 /// an error is signaled 1596 /// </summary> ImplicitConversionRequired(ResolveContext ec, Expression source, TypeSpec target_type, Location loc)1597 public static Expression ImplicitConversionRequired (ResolveContext ec, Expression source, 1598 TypeSpec target_type, Location loc) 1599 { 1600 Expression e = ImplicitConversion (ec, source, target_type, loc); 1601 if (e != null) 1602 return e; 1603 1604 if (target_type != InternalType.ErrorType) 1605 source.Error_ValueCannotBeConverted (ec, target_type, false); 1606 1607 return null; 1608 } 1609 1610 /// <summary> 1611 /// Performs the explicit numeric conversions 1612 /// 1613 /// There are a few conversions that are not part of the C# standard, 1614 /// they were interim hacks in the C# compiler that were supposed to 1615 /// become explicit operators in the UIntPtr class and IntPtr class, 1616 /// but for historical reasons it did not happen, so the C# compiler 1617 /// ended up with these special hacks. 1618 /// 1619 /// See bug 59800 for details. 1620 /// 1621 /// The conversion are: 1622 /// UIntPtr->SByte 1623 /// UIntPtr->Int16 1624 /// UIntPtr->Int32 1625 /// IntPtr->UInt64 1626 /// UInt64->IntPtr 1627 /// SByte->UIntPtr 1628 /// Int16->UIntPtr 1629 /// 1630 /// </summary> ExplicitNumericConversion(ResolveContext rc, Expression expr, TypeSpec target_type)1631 public static Expression ExplicitNumericConversion (ResolveContext rc, Expression expr, TypeSpec target_type) 1632 { 1633 // Not all predefined explicit numeric conversion are 1634 // defined here, for some of them (mostly IntPtr/UIntPtr) we 1635 // defer to user-operator handling which is now perfect but 1636 // works for now 1637 // 1638 // LAMESPEC: Undocumented IntPtr/UIntPtr conversions 1639 // IntPtr -> uint uses int 1640 // UIntPtr -> long uses ulong 1641 // 1642 1643 switch (expr.Type.BuiltinType) { 1644 case BuiltinTypeSpec.Type.SByte: 1645 // 1646 // From sbyte to byte, ushort, uint, ulong, char, uintptr 1647 // 1648 switch (target_type.BuiltinType) { 1649 case BuiltinTypeSpec.Type.Byte: 1650 return new ConvCast (expr, target_type, ConvCast.Mode.I1_U1); 1651 case BuiltinTypeSpec.Type.UShort: 1652 return new ConvCast (expr, target_type, ConvCast.Mode.I1_U2); 1653 case BuiltinTypeSpec.Type.UInt: 1654 return new ConvCast (expr, target_type, ConvCast.Mode.I1_U4); 1655 case BuiltinTypeSpec.Type.ULong: 1656 return new ConvCast (expr, target_type, ConvCast.Mode.I1_U8); 1657 case BuiltinTypeSpec.Type.Char: 1658 return new ConvCast (expr, target_type, ConvCast.Mode.I1_CH); 1659 1660 // One of the built-in conversions that belonged in the class library 1661 case BuiltinTypeSpec.Type.UIntPtr: 1662 return new OperatorCast (new ConvCast (expr, rc.BuiltinTypes.ULong, ConvCast.Mode.I1_U8), target_type, target_type, true); 1663 } 1664 break; 1665 case BuiltinTypeSpec.Type.Byte: 1666 // 1667 // From byte to sbyte and char 1668 // 1669 switch (target_type.BuiltinType) { 1670 case BuiltinTypeSpec.Type.SByte: 1671 return new ConvCast (expr, target_type, ConvCast.Mode.U1_I1); 1672 case BuiltinTypeSpec.Type.Char: 1673 return new ConvCast (expr, target_type, ConvCast.Mode.U1_CH); 1674 } 1675 break; 1676 case BuiltinTypeSpec.Type.Short: 1677 // 1678 // From short to sbyte, byte, ushort, uint, ulong, char, uintptr 1679 // 1680 switch (target_type.BuiltinType) { 1681 case BuiltinTypeSpec.Type.SByte: 1682 return new ConvCast (expr, target_type, ConvCast.Mode.I2_I1); 1683 case BuiltinTypeSpec.Type.Byte: 1684 return new ConvCast (expr, target_type, ConvCast.Mode.I2_U1); 1685 case BuiltinTypeSpec.Type.UShort: 1686 return new ConvCast (expr, target_type, ConvCast.Mode.I2_U2); 1687 case BuiltinTypeSpec.Type.UInt: 1688 return new ConvCast (expr, target_type, ConvCast.Mode.I2_U4); 1689 case BuiltinTypeSpec.Type.ULong: 1690 return new ConvCast (expr, target_type, ConvCast.Mode.I2_U8); 1691 case BuiltinTypeSpec.Type.Char: 1692 return new ConvCast (expr, target_type, ConvCast.Mode.I2_CH); 1693 1694 // One of the built-in conversions that belonged in the class library 1695 case BuiltinTypeSpec.Type.UIntPtr: 1696 return new OperatorCast (new ConvCast (expr, rc.BuiltinTypes.ULong, ConvCast.Mode.I2_U8), target_type, target_type, true); 1697 } 1698 break; 1699 case BuiltinTypeSpec.Type.UShort: 1700 // 1701 // From ushort to sbyte, byte, short, char 1702 // 1703 switch (target_type.BuiltinType) { 1704 case BuiltinTypeSpec.Type.SByte: 1705 return new ConvCast (expr, target_type, ConvCast.Mode.U2_I1); 1706 case BuiltinTypeSpec.Type.Byte: 1707 return new ConvCast (expr, target_type, ConvCast.Mode.U2_U1); 1708 case BuiltinTypeSpec.Type.Short: 1709 return new ConvCast (expr, target_type, ConvCast.Mode.U2_I2); 1710 case BuiltinTypeSpec.Type.Char: 1711 return new ConvCast (expr, target_type, ConvCast.Mode.U2_CH); 1712 } 1713 break; 1714 case BuiltinTypeSpec.Type.Int: 1715 // 1716 // From int to sbyte, byte, short, ushort, uint, ulong, char, uintptr 1717 // 1718 switch (target_type.BuiltinType) { 1719 case BuiltinTypeSpec.Type.SByte: 1720 return new ConvCast (expr, target_type, ConvCast.Mode.I4_I1); 1721 case BuiltinTypeSpec.Type.Byte: 1722 return new ConvCast (expr, target_type, ConvCast.Mode.I4_U1); 1723 case BuiltinTypeSpec.Type.Short: 1724 return new ConvCast (expr, target_type, ConvCast.Mode.I4_I2); 1725 case BuiltinTypeSpec.Type.UShort: 1726 return new ConvCast (expr, target_type, ConvCast.Mode.I4_U2); 1727 case BuiltinTypeSpec.Type.UInt: 1728 return new ConvCast (expr, target_type, ConvCast.Mode.I4_U4); 1729 case BuiltinTypeSpec.Type.ULong: 1730 return new ConvCast (expr, target_type, ConvCast.Mode.I4_U8); 1731 case BuiltinTypeSpec.Type.Char: 1732 return new ConvCast (expr, target_type, ConvCast.Mode.I4_CH); 1733 1734 // One of the built-in conversions that belonged in the class library 1735 case BuiltinTypeSpec.Type.UIntPtr: 1736 return new OperatorCast (new ConvCast (expr, rc.BuiltinTypes.ULong, ConvCast.Mode.I2_U8), target_type, target_type, true); 1737 } 1738 break; 1739 case BuiltinTypeSpec.Type.UInt: 1740 // 1741 // From uint to sbyte, byte, short, ushort, int, char 1742 // 1743 switch (target_type.BuiltinType) { 1744 case BuiltinTypeSpec.Type.SByte: 1745 return new ConvCast (expr, target_type, ConvCast.Mode.U4_I1); 1746 case BuiltinTypeSpec.Type.Byte: 1747 return new ConvCast (expr, target_type, ConvCast.Mode.U4_U1); 1748 case BuiltinTypeSpec.Type.Short: 1749 return new ConvCast (expr, target_type, ConvCast.Mode.U4_I2); 1750 case BuiltinTypeSpec.Type.UShort: 1751 return new ConvCast (expr, target_type, ConvCast.Mode.U4_U2); 1752 case BuiltinTypeSpec.Type.Int: 1753 return new ConvCast (expr, target_type, ConvCast.Mode.U4_I4); 1754 case BuiltinTypeSpec.Type.Char: 1755 return new ConvCast (expr, target_type, ConvCast.Mode.U4_CH); 1756 } 1757 break; 1758 case BuiltinTypeSpec.Type.Long: 1759 // 1760 // From long to sbyte, byte, short, ushort, int, uint, ulong, char 1761 // 1762 switch (target_type.BuiltinType) { 1763 case BuiltinTypeSpec.Type.SByte: 1764 return new ConvCast (expr, target_type, ConvCast.Mode.I8_I1); 1765 case BuiltinTypeSpec.Type.Byte: 1766 return new ConvCast (expr, target_type, ConvCast.Mode.I8_U1); 1767 case BuiltinTypeSpec.Type.Short: 1768 return new ConvCast (expr, target_type, ConvCast.Mode.I8_I2); 1769 case BuiltinTypeSpec.Type.UShort: 1770 return new ConvCast (expr, target_type, ConvCast.Mode.I8_U2); 1771 case BuiltinTypeSpec.Type.Int: 1772 return new ConvCast (expr, target_type, ConvCast.Mode.I8_I4); 1773 case BuiltinTypeSpec.Type.UInt: 1774 return new ConvCast (expr, target_type, ConvCast.Mode.I8_U4); 1775 case BuiltinTypeSpec.Type.ULong: 1776 return new ConvCast (expr, target_type, ConvCast.Mode.I8_U8); 1777 case BuiltinTypeSpec.Type.Char: 1778 return new ConvCast (expr, target_type, ConvCast.Mode.I8_CH); 1779 } 1780 break; 1781 case BuiltinTypeSpec.Type.ULong: 1782 // 1783 // From ulong to sbyte, byte, short, ushort, int, uint, long, char 1784 // 1785 switch (target_type.BuiltinType) { 1786 case BuiltinTypeSpec.Type.SByte: 1787 return new ConvCast (expr, target_type, ConvCast.Mode.U8_I1); 1788 case BuiltinTypeSpec.Type.Byte: 1789 return new ConvCast (expr, target_type, ConvCast.Mode.U8_U1); 1790 case BuiltinTypeSpec.Type.Short: 1791 return new ConvCast (expr, target_type, ConvCast.Mode.U8_I2); 1792 case BuiltinTypeSpec.Type.UShort: 1793 return new ConvCast (expr, target_type, ConvCast.Mode.U8_U2); 1794 case BuiltinTypeSpec.Type.Int: 1795 return new ConvCast (expr, target_type, ConvCast.Mode.U8_I4); 1796 case BuiltinTypeSpec.Type.UInt: 1797 return new ConvCast (expr, target_type, ConvCast.Mode.U8_U4); 1798 case BuiltinTypeSpec.Type.Long: 1799 return new ConvCast (expr, target_type, ConvCast.Mode.U8_I8); 1800 case BuiltinTypeSpec.Type.Char: 1801 return new ConvCast (expr, target_type, ConvCast.Mode.U8_CH); 1802 1803 // One of the built-in conversions that belonged in the class library 1804 case BuiltinTypeSpec.Type.IntPtr: 1805 return new OperatorCast (EmptyCast.Create (expr, rc.BuiltinTypes.Long), target_type, true); 1806 } 1807 break; 1808 case BuiltinTypeSpec.Type.Char: 1809 // 1810 // From char to sbyte, byte, short 1811 // 1812 switch (target_type.BuiltinType) { 1813 case BuiltinTypeSpec.Type.SByte: 1814 return new ConvCast (expr, target_type, ConvCast.Mode.CH_I1); 1815 case BuiltinTypeSpec.Type.Byte: 1816 return new ConvCast (expr, target_type, ConvCast.Mode.CH_U1); 1817 case BuiltinTypeSpec.Type.Short: 1818 return new ConvCast (expr, target_type, ConvCast.Mode.CH_I2); 1819 } 1820 break; 1821 case BuiltinTypeSpec.Type.Float: 1822 // 1823 // From float to sbyte, byte, short, 1824 // ushort, int, uint, long, ulong, char 1825 // or decimal 1826 // 1827 switch (target_type.BuiltinType) { 1828 case BuiltinTypeSpec.Type.SByte: 1829 return new ConvCast (expr, target_type, ConvCast.Mode.R4_I1); 1830 case BuiltinTypeSpec.Type.Byte: 1831 return new ConvCast (expr, target_type, ConvCast.Mode.R4_U1); 1832 case BuiltinTypeSpec.Type.Short: 1833 return new ConvCast (expr, target_type, ConvCast.Mode.R4_I2); 1834 case BuiltinTypeSpec.Type.UShort: 1835 return new ConvCast (expr, target_type, ConvCast.Mode.R4_U2); 1836 case BuiltinTypeSpec.Type.Int: 1837 return new ConvCast (expr, target_type, ConvCast.Mode.R4_I4); 1838 case BuiltinTypeSpec.Type.UInt: 1839 return new ConvCast (expr, target_type, ConvCast.Mode.R4_U4); 1840 case BuiltinTypeSpec.Type.Long: 1841 return new ConvCast (expr, target_type, ConvCast.Mode.R4_I8); 1842 case BuiltinTypeSpec.Type.ULong: 1843 return new ConvCast (expr, target_type, ConvCast.Mode.R4_U8); 1844 case BuiltinTypeSpec.Type.Char: 1845 return new ConvCast (expr, target_type, ConvCast.Mode.R4_CH); 1846 case BuiltinTypeSpec.Type.Decimal: 1847 return new OperatorCast (expr, target_type, true); 1848 } 1849 break; 1850 case BuiltinTypeSpec.Type.Double: 1851 // 1852 // From double to sbyte, byte, short, 1853 // ushort, int, uint, long, ulong, 1854 // char, float or decimal 1855 // 1856 switch (target_type.BuiltinType) { 1857 case BuiltinTypeSpec.Type.SByte: 1858 return new ConvCast (expr, target_type, ConvCast.Mode.R8_I1); 1859 case BuiltinTypeSpec.Type.Byte: 1860 return new ConvCast (expr, target_type, ConvCast.Mode.R8_U1); 1861 case BuiltinTypeSpec.Type.Short: 1862 return new ConvCast (expr, target_type, ConvCast.Mode.R8_I2); 1863 case BuiltinTypeSpec.Type.UShort: 1864 return new ConvCast (expr, target_type, ConvCast.Mode.R8_U2); 1865 case BuiltinTypeSpec.Type.Int: 1866 return new ConvCast (expr, target_type, ConvCast.Mode.R8_I4); 1867 case BuiltinTypeSpec.Type.UInt: 1868 return new ConvCast (expr, target_type, ConvCast.Mode.R8_U4); 1869 case BuiltinTypeSpec.Type.Long: 1870 return new ConvCast (expr, target_type, ConvCast.Mode.R8_I8); 1871 case BuiltinTypeSpec.Type.ULong: 1872 return new ConvCast (expr, target_type, ConvCast.Mode.R8_U8); 1873 case BuiltinTypeSpec.Type.Char: 1874 return new ConvCast (expr, target_type, ConvCast.Mode.R8_CH); 1875 case BuiltinTypeSpec.Type.Float: 1876 return new ConvCast (expr, target_type, ConvCast.Mode.R8_R4); 1877 case BuiltinTypeSpec.Type.Decimal: 1878 return new OperatorCast (expr, target_type, true); 1879 } 1880 break; 1881 case BuiltinTypeSpec.Type.UIntPtr: 1882 // 1883 // Various built-in conversions that belonged in the class library 1884 // 1885 // from uintptr to sbyte, short, int32 1886 // 1887 switch (target_type.BuiltinType) { 1888 case BuiltinTypeSpec.Type.SByte: 1889 return new ConvCast (new OperatorCast (expr, expr.Type, rc.BuiltinTypes.UInt, true), target_type, ConvCast.Mode.U4_I1); 1890 case BuiltinTypeSpec.Type.Short: 1891 return new ConvCast (new OperatorCast (expr, expr.Type, rc.BuiltinTypes.UInt, true), target_type, ConvCast.Mode.U4_I2); 1892 case BuiltinTypeSpec.Type.Int: 1893 return EmptyCast.Create (new OperatorCast (expr, expr.Type, rc.BuiltinTypes.UInt, true), target_type); 1894 case BuiltinTypeSpec.Type.UInt: 1895 return new OperatorCast (expr, expr.Type, target_type, true); 1896 case BuiltinTypeSpec.Type.Long: 1897 return EmptyCast.Create (new OperatorCast (expr, expr.Type, rc.BuiltinTypes.ULong, true), target_type); 1898 } 1899 break; 1900 case BuiltinTypeSpec.Type.IntPtr: 1901 if (target_type.BuiltinType == BuiltinTypeSpec.Type.UInt) 1902 return EmptyCast.Create (new OperatorCast (expr, expr.Type, rc.BuiltinTypes.Int, true), target_type); 1903 if (target_type.BuiltinType == BuiltinTypeSpec.Type.ULong) 1904 return EmptyCast.Create (new OperatorCast (expr, expr.Type, rc.BuiltinTypes.Long, true), target_type); 1905 1906 break; 1907 case BuiltinTypeSpec.Type.Decimal: 1908 // From decimal to sbyte, byte, short, 1909 // ushort, int, uint, long, ulong, char, 1910 // float, or double 1911 switch (target_type.BuiltinType) { 1912 case BuiltinTypeSpec.Type.SByte: 1913 case BuiltinTypeSpec.Type.Byte: 1914 case BuiltinTypeSpec.Type.Short: 1915 case BuiltinTypeSpec.Type.UShort: 1916 case BuiltinTypeSpec.Type.Int: 1917 case BuiltinTypeSpec.Type.UInt: 1918 case BuiltinTypeSpec.Type.Long: 1919 case BuiltinTypeSpec.Type.ULong: 1920 case BuiltinTypeSpec.Type.Char: 1921 case BuiltinTypeSpec.Type.Float: 1922 case BuiltinTypeSpec.Type.Double: 1923 return new OperatorCast (expr, expr.Type, target_type, true); 1924 } 1925 1926 break; 1927 } 1928 1929 return null; 1930 } 1931 1932 /// <summary> 1933 /// Returns whether an explicit reference conversion can be performed 1934 /// from source_type to target_type 1935 /// </summary> ExplicitReferenceConversionExists(TypeSpec source_type, TypeSpec target_type)1936 public static bool ExplicitReferenceConversionExists (TypeSpec source_type, TypeSpec target_type) 1937 { 1938 Expression e = ExplicitReferenceConversion (null, source_type, target_type); 1939 if (e == null) 1940 return false; 1941 1942 if (e == EmptyExpression.Null) 1943 return true; 1944 1945 throw new InternalErrorException ("Invalid probing conversion result"); 1946 } 1947 1948 /// <summary> 1949 /// Implements Explicit Reference conversions 1950 /// </summary> ExplicitReferenceConversion(Expression source, TypeSpec source_type, TypeSpec target_type)1951 static Expression ExplicitReferenceConversion (Expression source, TypeSpec source_type, TypeSpec target_type) 1952 { 1953 // 1954 // From object to a generic parameter 1955 // 1956 if (source_type.BuiltinType == BuiltinTypeSpec.Type.Object && TypeManager.IsGenericParameter (target_type)) 1957 return source == null ? EmptyExpression.Null : new UnboxCast (source, target_type); 1958 1959 // 1960 // Explicit type parameter conversion from T 1961 // 1962 if (source_type.Kind == MemberKind.TypeParameter) 1963 return ExplicitTypeParameterConversionFromT (source, source_type, target_type); 1964 1965 bool target_is_value_type = target_type.Kind == MemberKind.Struct || target_type.Kind == MemberKind.Enum; 1966 1967 // 1968 // Unboxing conversion from System.ValueType to any non-nullable-value-type 1969 // 1970 if (source_type.BuiltinType == BuiltinTypeSpec.Type.ValueType && target_is_value_type) 1971 return source == null ? EmptyExpression.Null : new UnboxCast (source, target_type); 1972 1973 // 1974 // From object or dynamic to any reference type or value type (unboxing) 1975 // 1976 if (source_type.BuiltinType == BuiltinTypeSpec.Type.Object || source_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) { 1977 if (target_type.IsPointer || target_type.IsByRefLike) 1978 return null; 1979 1980 return 1981 source == null ? EmptyExpression.Null : 1982 target_is_value_type ? new UnboxCast (source, target_type) : 1983 source is Constant ? (Expression) new EmptyConstantCast ((Constant) source, target_type) : 1984 new ClassCast (source, target_type); 1985 } 1986 1987 // 1988 // From any class S to any class-type T, provided S is a base class of T 1989 // 1990 if (source_type.Kind == MemberKind.Class && TypeSpec.IsBaseClass (target_type, source_type, true)) 1991 return source == null ? EmptyExpression.Null : new ClassCast (source, target_type); 1992 1993 // 1994 // From any interface-type S to to any class type T, provided T is not 1995 // sealed, or provided T implements S. 1996 // 1997 // This also covers Explicit conversions involving type parameters 1998 // section From any interface type to T 1999 // 2000 if (source_type.Kind == MemberKind.Interface) { 2001 if (!target_type.IsSealed || target_type.ImplementsInterface (source_type, true)) { 2002 if (source == null) 2003 return EmptyExpression.Null; 2004 2005 // 2006 // Unboxing conversion from any interface-type to any non-nullable-value-type that 2007 // implements the interface-type 2008 // 2009 return target_is_value_type ? new UnboxCast (source, target_type) : (Expression) new ClassCast (source, target_type); 2010 } 2011 2012 // 2013 // From System.Collections.Generic.IList<T> and its base interfaces to a one-dimensional 2014 // array type S[], provided there is an implicit or explicit reference conversion from S to T. 2015 // 2016 var target_array = target_type as ArrayContainer; 2017 if (target_array != null && IList_To_Array (source_type, target_array)) 2018 return source == null ? EmptyExpression.Null : new ClassCast (source, target_type); 2019 2020 return null; 2021 } 2022 2023 var source_array = source_type as ArrayContainer; 2024 if (source_array != null) { 2025 var target_array = target_type as ArrayContainer; 2026 if (target_array != null) { 2027 // 2028 // From System.Array to any array-type 2029 // 2030 if (source_type.BuiltinType == BuiltinTypeSpec.Type.Array) 2031 return source == null ? EmptyExpression.Null : new ClassCast (source, target_type); 2032 2033 // 2034 // From an array type S with an element type Se to an array type T with an 2035 // element type Te provided all the following are true: 2036 // * S and T differe only in element type, in other words, S and T 2037 // have the same number of dimensions. 2038 // * Both Se and Te are reference types 2039 // * An explicit reference conversions exist from Se to Te 2040 // 2041 if (source_array.Rank == target_array.Rank) { 2042 2043 source_type = source_array.Element; 2044 var target_element = target_array.Element; 2045 2046 // 2047 // LAMESPEC: Type parameters are special cased somehow but 2048 // only when both source and target elements are type parameters 2049 // 2050 if ((source_type.Kind & target_element.Kind & MemberKind.TypeParameter) == MemberKind.TypeParameter) { 2051 // 2052 // Conversion is allowed unless source element type has struct constrain 2053 // 2054 if (TypeSpec.IsValueType (source_type)) 2055 return null; 2056 } else { 2057 if (!TypeSpec.IsReferenceType (source_type)) 2058 return null; 2059 } 2060 2061 if (!TypeSpec.IsReferenceType (target_element)) 2062 return null; 2063 2064 if (ExplicitReferenceConversionExists (source_type, target_element)) 2065 return source == null ? EmptyExpression.Null : new ClassCast (source, target_type); 2066 2067 return null; 2068 } 2069 } 2070 2071 // 2072 // From a single-dimensional array type S[] to System.Collections.Generic.IList<T> and its base interfaces, 2073 // provided that there is an explicit reference conversion from S to T 2074 // 2075 if (ArrayToIList (source_array, target_type, true)) 2076 return source == null ? EmptyExpression.Null : new ClassCast (source, target_type); 2077 2078 return null; 2079 } 2080 2081 // 2082 // From any class type S to any interface T, provides S is not sealed 2083 // and provided S does not implement T. 2084 // 2085 if (target_type.IsInterface && !source_type.IsSealed && !source_type.ImplementsInterface (target_type, true)) { 2086 return source == null ? EmptyExpression.Null : new ClassCast (source, target_type); 2087 } 2088 2089 // 2090 // From System delegate to any delegate-type 2091 // 2092 if (source_type.BuiltinType == BuiltinTypeSpec.Type.Delegate && target_type.IsDelegate) 2093 return source == null ? EmptyExpression.Null : new ClassCast (source, target_type); 2094 2095 // 2096 // From variant generic delegate to same variant generic delegate type 2097 // 2098 if (source_type.IsDelegate && target_type.IsDelegate && source_type.MemberDefinition == target_type.MemberDefinition) { 2099 var tparams = source_type.MemberDefinition.TypeParameters; 2100 var targs_src = source_type.TypeArguments; 2101 var targs_dst = target_type.TypeArguments; 2102 int i; 2103 for (i = 0; i < tparams.Length; ++i) { 2104 // 2105 // If TP is invariant, types have to be identical 2106 // 2107 if (TypeSpecComparer.IsEqual (targs_src[i], targs_dst[i])) 2108 continue; 2109 2110 if (tparams[i].Variance == Variance.Covariant) { 2111 // 2112 //If TP is covariant, an implicit or explicit identity or reference conversion is required 2113 // 2114 if (ImplicitReferenceConversionExists (targs_src[i], targs_dst[i])) 2115 continue; 2116 2117 if (ExplicitReferenceConversionExists (targs_src[i], targs_dst[i])) 2118 continue; 2119 2120 } else if (tparams[i].Variance == Variance.Contravariant) { 2121 // 2122 //If TP is contravariant, both are either identical or reference types 2123 // 2124 if (TypeSpec.IsReferenceType (targs_src[i]) && TypeSpec.IsReferenceType (targs_dst[i])) 2125 continue; 2126 } 2127 2128 break; 2129 } 2130 2131 if (i == tparams.Length) 2132 return source == null ? EmptyExpression.Null : new ClassCast (source, target_type); 2133 } 2134 2135 var tps = target_type as TypeParameterSpec; 2136 if (tps != null) 2137 return ExplicitTypeParameterConversionToT (source, source_type, tps); 2138 2139 return null; 2140 } 2141 2142 /// <summary> 2143 /// Performs an explicit conversion of the expression `expr' whose 2144 /// type is expr.Type to `target_type'. 2145 /// </summary> ExplicitConversionCore(ResolveContext ec, Expression expr, TypeSpec target_type, Location loc)2146 static public Expression ExplicitConversionCore (ResolveContext ec, Expression expr, 2147 TypeSpec target_type, Location loc) 2148 { 2149 TypeSpec expr_type = expr.Type; 2150 2151 // Explicit conversion includes implicit conversion and it used for enum underlying types too 2152 Expression ne = ImplicitConversionStandard (ec, expr, target_type, loc, true); 2153 if (ne != null) 2154 return ne; 2155 2156 if (expr_type.IsEnum) { 2157 TypeSpec real_target = target_type.IsEnum ? EnumSpec.GetUnderlyingType (target_type) : target_type; 2158 Expression underlying = EmptyCast.Create (expr, EnumSpec.GetUnderlyingType (expr_type)); 2159 if (underlying.Type == real_target) 2160 ne = underlying; 2161 2162 if (ne == null) 2163 ne = ImplicitNumericConversion (underlying, real_target); 2164 2165 if (ne == null) 2166 ne = ExplicitNumericConversion (ec, underlying, real_target); 2167 2168 // 2169 // LAMESPEC: IntPtr and UIntPtr conversion to any Enum is allowed 2170 // 2171 if (ne == null && (real_target.BuiltinType == BuiltinTypeSpec.Type.IntPtr || real_target.BuiltinType == BuiltinTypeSpec.Type.UIntPtr)) 2172 ne = ExplicitUserConversion (ec, underlying, real_target, loc); 2173 2174 return ne != null ? EmptyCast.Create (ne, target_type) : null; 2175 } 2176 2177 if (target_type.IsEnum) { 2178 // 2179 // System.Enum can be unboxed to any enum-type 2180 // 2181 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Enum) 2182 return new UnboxCast (expr, target_type); 2183 2184 TypeSpec real_target = target_type.IsEnum ? EnumSpec.GetUnderlyingType (target_type) : target_type; 2185 2186 if (expr_type == real_target) 2187 return EmptyCast.Create (expr, target_type); 2188 2189 Constant c = expr as Constant; 2190 if (c != null) { 2191 c = c.TryReduce (ec, real_target); 2192 if (c != null) 2193 return c; 2194 } else { 2195 ne = ImplicitNumericConversion (expr, real_target); 2196 if (ne != null) 2197 return EmptyCast.Create (ne, target_type); 2198 2199 ne = ExplicitNumericConversion (ec, expr, real_target); 2200 if (ne != null) 2201 return EmptyCast.Create (ne, target_type); 2202 2203 // 2204 // LAMESPEC: IntPtr and UIntPtr conversion to any Enum is allowed 2205 // 2206 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.IntPtr || expr_type.BuiltinType == BuiltinTypeSpec.Type.UIntPtr) { 2207 ne = ExplicitUserConversion (ec, expr, real_target, loc); 2208 if (ne != null) 2209 return ExplicitConversionCore (ec, ne, target_type, loc); 2210 } 2211 } 2212 } else { 2213 ne = ExplicitNumericConversion (ec, expr, target_type); 2214 if (ne != null) 2215 return ne; 2216 } 2217 2218 // 2219 // Skip the ExplicitReferenceConversion because we can not convert 2220 // from Null to a ValueType, and ExplicitReference wont check against 2221 // null literal explicitly 2222 // 2223 if (expr_type != InternalType.NullLiteral) { 2224 ne = ExplicitReferenceConversion (expr, expr_type, target_type); 2225 if (ne != null) 2226 return ne; 2227 } 2228 2229 if (ec.IsUnsafe){ 2230 ne = ExplicitUnsafe (expr, target_type); 2231 if (ne != null) 2232 return ne; 2233 } 2234 2235 return null; 2236 } 2237 ExplicitUnsafe(Expression expr, TypeSpec target_type)2238 public static Expression ExplicitUnsafe (Expression expr, TypeSpec target_type) 2239 { 2240 TypeSpec expr_type = expr.Type; 2241 2242 if (target_type.IsPointer){ 2243 if (expr_type.IsPointer) 2244 return EmptyCast.Create (expr, target_type); 2245 2246 switch (expr_type.BuiltinType) { 2247 case BuiltinTypeSpec.Type.SByte: 2248 case BuiltinTypeSpec.Type.Short: 2249 case BuiltinTypeSpec.Type.Int: 2250 return new OpcodeCast (expr, target_type, OpCodes.Conv_I); 2251 2252 case BuiltinTypeSpec.Type.UShort: 2253 case BuiltinTypeSpec.Type.UInt: 2254 case BuiltinTypeSpec.Type.Byte: 2255 return new OpcodeCast (expr, target_type, OpCodes.Conv_U); 2256 2257 case BuiltinTypeSpec.Type.Long: 2258 return new ConvCast (expr, target_type, ConvCast.Mode.I8_I); 2259 2260 case BuiltinTypeSpec.Type.ULong: 2261 return new ConvCast (expr, target_type, ConvCast.Mode.U8_I); 2262 } 2263 } 2264 2265 if (expr_type.IsPointer){ 2266 switch (target_type.BuiltinType) { 2267 case BuiltinTypeSpec.Type.SByte: 2268 return new OpcodeCast (expr, target_type, OpCodes.Conv_I1); 2269 case BuiltinTypeSpec.Type.Byte: 2270 return new OpcodeCast (expr, target_type, OpCodes.Conv_U1); 2271 case BuiltinTypeSpec.Type.Short: 2272 return new OpcodeCast (expr, target_type, OpCodes.Conv_I2); 2273 case BuiltinTypeSpec.Type.UShort: 2274 return new OpcodeCast (expr, target_type, OpCodes.Conv_U2); 2275 case BuiltinTypeSpec.Type.Int: 2276 return new OpcodeCast (expr, target_type, OpCodes.Conv_I4); 2277 case BuiltinTypeSpec.Type.UInt: 2278 return new OpcodeCast (expr, target_type, OpCodes.Conv_U4); 2279 case BuiltinTypeSpec.Type.Long: 2280 return new ConvCast (expr, target_type, ConvCast.Mode.I_I8); 2281 case BuiltinTypeSpec.Type.ULong: 2282 return new OpcodeCast (expr, target_type, OpCodes.Conv_U8); 2283 } 2284 } 2285 return null; 2286 } 2287 2288 /// <summary> 2289 /// Same as ExplicitConversion, only it doesn't include user defined conversions 2290 /// </summary> ExplicitConversionStandard(ResolveContext ec, Expression expr, TypeSpec target_type, Location l)2291 static public Expression ExplicitConversionStandard (ResolveContext ec, Expression expr, 2292 TypeSpec target_type, Location l) 2293 { 2294 int errors = ec.Report.Errors; 2295 Expression ne = ImplicitConversionStandard (ec, expr, target_type, l); 2296 if (ec.Report.Errors > errors) 2297 return null; 2298 2299 if (ne != null) 2300 return ne; 2301 2302 ne = ExplicitNumericConversion (ec, expr, target_type); 2303 if (ne != null) 2304 return ne; 2305 2306 ne = ExplicitReferenceConversion (expr, expr.Type, target_type); 2307 if (ne != null) 2308 return ne; 2309 2310 if (ec.IsUnsafe && expr.Type.IsPointer && target_type.IsPointer && ((PointerContainer)expr.Type).Element.Kind == MemberKind.Void) 2311 return EmptyCast.Create (expr, target_type); 2312 2313 expr.Error_ValueCannotBeConverted (ec, target_type, true); 2314 return null; 2315 } 2316 2317 /// <summary> 2318 /// Performs an explicit conversion of the expression `expr' whose 2319 /// type is expr.Type to `target_type'. 2320 /// </summary> ExplicitConversion(ResolveContext ec, Expression expr, TypeSpec target_type, Location loc)2321 static public Expression ExplicitConversion (ResolveContext ec, Expression expr, 2322 TypeSpec target_type, Location loc) 2323 { 2324 Expression e = ExplicitConversionCore (ec, expr, target_type, loc); 2325 if (e != null) { 2326 // 2327 // Don't eliminate explicit precission casts 2328 // 2329 if (e == expr) { 2330 if (target_type.BuiltinType == BuiltinTypeSpec.Type.Float) 2331 return new OpcodeCast (expr, target_type, OpCodes.Conv_R4); 2332 2333 if (target_type.BuiltinType == BuiltinTypeSpec.Type.Double) 2334 return new OpcodeCast (expr, target_type, OpCodes.Conv_R8); 2335 } 2336 2337 return e; 2338 } 2339 2340 TypeSpec expr_type = expr.Type; 2341 if (target_type.IsNullableType) { 2342 TypeSpec target; 2343 2344 if (expr_type.IsNullableType) { 2345 target = Nullable.NullableInfo.GetUnderlyingType (target_type); 2346 Expression unwrap = Nullable.Unwrap.Create (expr); 2347 e = ExplicitConversion (ec, unwrap, target, expr.Location); 2348 if (e == null) 2349 return null; 2350 2351 return new Nullable.LiftedConversion (e, unwrap, target_type).Resolve (ec); 2352 } 2353 if (expr_type.BuiltinType == BuiltinTypeSpec.Type.Object) { 2354 return new UnboxCast (expr, target_type); 2355 } 2356 2357 target = TypeManager.GetTypeArguments (target_type) [0]; 2358 e = ExplicitConversionCore (ec, expr, target, loc); 2359 if (e != null) 2360 return TypeSpec.IsReferenceType (expr.Type) ? new UnboxCast (expr, target_type) : Nullable.Wrap.Create (e, target_type); 2361 } else if (expr_type.IsNullableType) { 2362 e = ImplicitBoxingConversion (expr, Nullable.NullableInfo.GetUnderlyingType (expr_type), target_type); 2363 if (e != null) 2364 return e; 2365 2366 e = Nullable.Unwrap.Create (expr, false); 2367 e = ExplicitConversionCore (ec, e, target_type, loc); 2368 if (e != null) 2369 return EmptyCast.Create (e, target_type); 2370 } 2371 2372 e = ExplicitUserConversion (ec, expr, target_type, loc); 2373 2374 if (e != null) 2375 return e; 2376 2377 expr.Error_ValueCannotBeConverted (ec, target_type, true); 2378 return null; 2379 } 2380 } 2381 } 2382