1
ļ»æ// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team
3
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
4
// software and associated documentation files (the "Software"), to deal in the Software
5
// without restriction, including without limitation the rights to use, copy, modify, merge,
6
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
7
// to whom the Software is furnished to do so, subject to the following conditions:
9
// The above copyright notice and this permission notice shall be included in all copies or
10
// substantial portions of the Software.
12
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
13
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
15
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
16
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
17
// DEALINGS IN THE SOFTWARE.
20
using ICSharpCode.NRefactory.TypeSystem;
22
namespace ICSharpCode.NRefactory.Semantics
25
/// Holds information about a conversion between two types.
27
public abstract class Conversion : IEquatable<Conversion>
29
#region Conversion factory methods
31
/// Not a valid conversion.
33
public static readonly Conversion None = new InvalidConversion();
36
/// Identity conversion.
38
public static readonly Conversion IdentityConversion = new BuiltinConversion(true, 0);
40
public static readonly Conversion ImplicitNumericConversion = new NumericOrEnumerationConversion(true, false);
41
public static readonly Conversion ExplicitNumericConversion = new NumericOrEnumerationConversion(false, false);
42
public static readonly Conversion ImplicitLiftedNumericConversion = new NumericOrEnumerationConversion(true, true);
43
public static readonly Conversion ExplicitLiftedNumericConversion = new NumericOrEnumerationConversion(false, true);
45
public static Conversion EnumerationConversion(bool isImplicit, bool isLifted)
47
return new NumericOrEnumerationConversion(isImplicit, isLifted, true);
50
public static readonly Conversion NullLiteralConversion = new BuiltinConversion(true, 1);
53
/// The numeric conversion of a constant expression.
55
public static readonly Conversion ImplicitConstantExpressionConversion = new BuiltinConversion(true, 2);
57
public static readonly Conversion ImplicitReferenceConversion = new BuiltinConversion(true, 3);
58
public static readonly Conversion ExplicitReferenceConversion = new BuiltinConversion(false, 3);
60
public static readonly Conversion ImplicitDynamicConversion = new BuiltinConversion(true, 4);
61
public static readonly Conversion ExplicitDynamicConversion = new BuiltinConversion(false, 4);
63
public static readonly Conversion ImplicitNullableConversion = new BuiltinConversion(true, 5);
64
public static readonly Conversion ExplicitNullableConversion = new BuiltinConversion(false, 5);
66
public static readonly Conversion ImplicitPointerConversion = new BuiltinConversion(true, 6);
67
public static readonly Conversion ExplicitPointerConversion = new BuiltinConversion(false, 6);
69
public static readonly Conversion BoxingConversion = new BuiltinConversion(true, 7);
70
public static readonly Conversion UnboxingConversion = new BuiltinConversion(false, 8);
75
public static readonly Conversion TryCast = new BuiltinConversion(false, 9);
77
[Obsolete("Use UserDefinedConversion() instead")]
78
public static Conversion UserDefinedImplicitConversion(IMethod operatorMethod, Conversion conversionBeforeUserDefinedOperator, Conversion conversionAfterUserDefinedOperator, bool isLifted)
80
if (operatorMethod == null)
81
throw new ArgumentNullException("operatorMethod");
82
return new UserDefinedConv(true, operatorMethod, conversionBeforeUserDefinedOperator, conversionAfterUserDefinedOperator, isLifted, false);
85
[Obsolete("Use UserDefinedConversion() instead")]
86
public static Conversion UserDefinedExplicitConversion(IMethod operatorMethod, Conversion conversionBeforeUserDefinedOperator, Conversion conversionAfterUserDefinedOperator, bool isLifted)
88
if (operatorMethod == null)
89
throw new ArgumentNullException("operatorMethod");
90
return new UserDefinedConv(false, operatorMethod, conversionBeforeUserDefinedOperator, conversionAfterUserDefinedOperator, isLifted, false);
93
public static Conversion UserDefinedConversion(IMethod operatorMethod, bool isImplicit, Conversion conversionBeforeUserDefinedOperator, Conversion conversionAfterUserDefinedOperator, bool isLifted = false, bool isAmbiguous = false)
95
if (operatorMethod == null)
96
throw new ArgumentNullException("operatorMethod");
97
return new UserDefinedConv(isImplicit, operatorMethod, conversionBeforeUserDefinedOperator, conversionAfterUserDefinedOperator, isLifted, isAmbiguous);
100
public static Conversion MethodGroupConversion(IMethod chosenMethod, bool isVirtualMethodLookup)
102
if (chosenMethod == null)
103
throw new ArgumentNullException("chosenMethod");
104
return new MethodGroupConv(chosenMethod, isVirtualMethodLookup, isValid: true);
107
public static Conversion InvalidMethodGroupConversion(IMethod chosenMethod, bool isVirtualMethodLookup)
109
if (chosenMethod == null)
110
throw new ArgumentNullException("chosenMethod");
111
return new MethodGroupConv(chosenMethod, isVirtualMethodLookup, isValid: false);
115
#region Inner classes
116
sealed class InvalidConversion : Conversion
118
public override bool IsValid {
119
get { return false; }
122
public override string ToString()
128
sealed class NumericOrEnumerationConversion : Conversion
130
readonly bool isImplicit;
131
readonly bool isLifted;
132
readonly bool isEnumeration;
134
public NumericOrEnumerationConversion(bool isImplicit, bool isLifted, bool isEnumeration = false)
136
this.isImplicit = isImplicit;
137
this.isLifted = isLifted;
138
this.isEnumeration = isEnumeration;
141
public override bool IsImplicit {
142
get { return isImplicit; }
145
public override bool IsExplicit {
146
get { return !isImplicit; }
149
public override bool IsNumericConversion {
150
get { return !isEnumeration; }
153
public override bool IsEnumerationConversion {
154
get { return isEnumeration; }
157
public override bool IsLifted {
158
get { return isLifted; }
161
public override string ToString()
163
return (isImplicit ? "implicit" : "explicit")
164
+ (isLifted ? " lifted" : "")
165
+ (isEnumeration ? " enumeration" : " numeric")
169
public override bool Equals(Conversion other)
171
NumericOrEnumerationConversion o = other as NumericOrEnumerationConversion;
172
return o != null && isImplicit == o.isImplicit && isLifted == o.isLifted && isEnumeration == o.isEnumeration;
175
public override int GetHashCode()
177
return (isImplicit ? 1 : 0) + (isLifted ? 2 : 0) + (isEnumeration ? 4 : 0);
181
sealed class BuiltinConversion : Conversion
183
readonly bool isImplicit;
186
public BuiltinConversion(bool isImplicit, byte type)
188
this.isImplicit = isImplicit;
192
public override bool IsImplicit {
193
get { return isImplicit; }
196
public override bool IsExplicit {
197
get { return !isImplicit; }
200
public override bool IsIdentityConversion {
201
get { return type == 0; }
204
public override bool IsNullLiteralConversion {
205
get { return type == 1; }
208
public override bool IsConstantExpressionConversion {
209
get { return type == 2; }
212
public override bool IsReferenceConversion {
213
get { return type == 3; }
216
public override bool IsDynamicConversion {
217
get { return type == 4; }
220
public override bool IsNullableConversion {
221
get { return type == 5; }
224
public override bool IsPointerConversion {
225
get { return type == 6; }
228
public override bool IsBoxingConversion {
229
get { return type == 7; }
232
public override bool IsUnboxingConversion {
233
get { return type == 8; }
236
public override bool IsTryCast {
237
get { return type == 9; }
240
public override string ToString()
245
return "identity conversion";
247
return "null-literal conversion";
249
name = "constant-expression";
264
return "boxing conversion";
266
return "unboxing conversion";
270
return (isImplicit ? "implicit " : "explicit ") + name + " conversion";
274
sealed class UserDefinedConv : Conversion
276
readonly IMethod method;
277
readonly bool isLifted;
278
readonly Conversion conversionBeforeUserDefinedOperator;
279
readonly Conversion conversionAfterUserDefinedOperator;
280
readonly bool isImplicit;
281
readonly bool isValid;
283
public UserDefinedConv(bool isImplicit, IMethod method, Conversion conversionBeforeUserDefinedOperator, Conversion conversionAfterUserDefinedOperator, bool isLifted, bool isAmbiguous)
285
this.method = method;
286
this.isLifted = isLifted;
287
this.conversionBeforeUserDefinedOperator = conversionBeforeUserDefinedOperator;
288
this.conversionAfterUserDefinedOperator = conversionAfterUserDefinedOperator;
289
this.isImplicit = isImplicit;
290
this.isValid = !isAmbiguous;
293
public override bool IsValid {
294
get { return isValid; }
297
public override bool IsImplicit {
298
get { return isImplicit; }
301
public override bool IsExplicit {
302
get { return !isImplicit; }
305
public override bool IsLifted {
306
get { return isLifted; }
309
public override bool IsUserDefined {
313
public override Conversion ConversionBeforeUserDefinedOperator {
314
get { return conversionBeforeUserDefinedOperator; }
317
public override Conversion ConversionAfterUserDefinedOperator {
318
get { return conversionAfterUserDefinedOperator; }
321
public override IMethod Method {
322
get { return method; }
325
public override bool Equals(Conversion other)
327
UserDefinedConv o = other as UserDefinedConv;
328
return o != null && isLifted == o.isLifted && isImplicit == o.isImplicit && isValid == o.isValid && method.Equals(o.method);
331
public override int GetHashCode()
333
return unchecked(method.GetHashCode() + (isLifted ? 31 : 27) + (isImplicit ? 71 : 61) + (isValid ? 107 : 109));
336
public override string ToString()
338
return (isImplicit ? "implicit" : "explicit")
339
+ (isLifted ? " lifted" : "")
340
+ (isValid ? "" : " ambiguous")
341
+ "user-defined conversion (" + method + ")";
345
sealed class MethodGroupConv : Conversion
347
readonly IMethod method;
348
readonly bool isVirtualMethodLookup;
349
readonly bool isValid;
351
public MethodGroupConv(IMethod method, bool isVirtualMethodLookup, bool isValid)
353
this.method = method;
354
this.isVirtualMethodLookup = isVirtualMethodLookup;
355
this.isValid = isValid;
358
public override bool IsValid {
359
get { return isValid; }
362
public override bool IsImplicit {
366
public override bool IsMethodGroupConversion {
370
public override bool IsVirtualMethodLookup {
371
get { return isVirtualMethodLookup; }
374
public override IMethod Method {
375
get { return method; }
378
public override bool Equals(Conversion other)
380
MethodGroupConv o = other as MethodGroupConv;
381
return o != null && method.Equals(o.method);
384
public override int GetHashCode()
386
return method.GetHashCode();
392
/// Gets whether the conversion is valid.
394
public virtual bool IsValid {
398
public virtual bool IsImplicit {
399
get { return false; }
402
public virtual bool IsExplicit {
403
get { return false; }
407
/// Gets whether the conversion is an '<c>as</c>' cast.
409
public virtual bool IsTryCast {
410
get { return false; }
413
public virtual bool IsIdentityConversion {
414
get { return false; }
417
public virtual bool IsNullLiteralConversion {
418
get { return false; }
421
public virtual bool IsConstantExpressionConversion {
422
get { return false; }
425
public virtual bool IsNumericConversion {
426
get { return false; }
430
/// Gets whether this conversion is a lifted version of another conversion.
432
public virtual bool IsLifted {
433
get { return false; }
437
/// Gets whether the conversion is dynamic.
439
public virtual bool IsDynamicConversion {
440
get { return false; }
444
/// Gets whether the conversion is a reference conversion.
446
public virtual bool IsReferenceConversion {
447
get { return false; }
451
/// Gets whether the conversion is an enumeration conversion.
453
public virtual bool IsEnumerationConversion {
454
get { return false; }
458
/// Gets whether the conversion is a nullable conversion
459
/// (conversion between a nullable type and the regular type).
461
public virtual bool IsNullableConversion {
462
get { return false; }
466
/// Gets whether this conversion is user-defined (op_Implicit or op_Explicit).
468
public virtual bool IsUserDefined {
469
get { return false; }
473
/// The conversion that is applied to the input before the user-defined conversion operator is invoked.
475
public virtual Conversion ConversionBeforeUserDefinedOperator {
480
/// The conversion that is applied to the result of the user-defined conversion operator.
482
public virtual Conversion ConversionAfterUserDefinedOperator {
487
/// Gets whether this conversion is a boxing conversion.
489
public virtual bool IsBoxingConversion {
490
get { return false; }
494
/// Gets whether this conversion is an unboxing conversion.
496
public virtual bool IsUnboxingConversion {
497
get { return false; }
501
/// Gets whether this conversion is a pointer conversion.
503
public virtual bool IsPointerConversion {
504
get { return false; }
508
/// Gets whether this conversion is a method group conversion.
510
public virtual bool IsMethodGroupConversion {
511
get { return false; }
515
/// For method-group conversions, gets whether to perform a virtual method lookup at runtime.
517
public virtual bool IsVirtualMethodLookup {
518
get { return false; }
522
/// Gets whether this conversion is an anonymous function conversion.
524
public virtual bool IsAnonymousFunctionConversion {
525
get { return false; }
529
/// Gets the method associated with this conversion.
530
/// For user-defined conversions, this is the method being called.
531
/// For method-group conversions, this is the method that was chosen from the group.
533
public virtual IMethod Method {
537
public override sealed bool Equals(object obj)
539
return Equals(obj as Conversion);
542
public override int GetHashCode()
544
return base.GetHashCode();
547
public virtual bool Equals(Conversion other)
549
return this == other;