mirror of https://github.com/icsharpcode/ILSpy.git
				
				
			
			You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							639 lines
						
					
					
						
							18 KiB
						
					
					
				
			
		
		
	
	
							639 lines
						
					
					
						
							18 KiB
						
					
					
				// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team | 
						|
//  | 
						|
// Permission is hereby granted, free of charge, to any person obtaining a copy of this | 
						|
// software and associated documentation files (the "Software"), to deal in the Software | 
						|
// without restriction, including without limitation the rights to use, copy, modify, merge, | 
						|
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons | 
						|
// to whom the Software is furnished to do so, subject to the following conditions: | 
						|
//  | 
						|
// The above copyright notice and this permission notice shall be included in all copies or | 
						|
// substantial portions of the Software. | 
						|
//  | 
						|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, | 
						|
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR | 
						|
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE | 
						|
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR | 
						|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | 
						|
// DEALINGS IN THE SOFTWARE. | 
						|
 | 
						|
using System; | 
						|
using System.Collections.Immutable; | 
						|
using System.Linq; | 
						|
 | 
						|
using ICSharpCode.Decompiler.TypeSystem; | 
						|
 | 
						|
namespace ICSharpCode.Decompiler.Semantics | 
						|
{ | 
						|
	/// <summary> | 
						|
	/// Holds information about a conversion between two types. | 
						|
	/// </summary> | 
						|
	public abstract class Conversion : IEquatable<Conversion> | 
						|
	{ | 
						|
		#region Conversion factory methods | 
						|
		/// <summary> | 
						|
		/// Not a valid conversion. | 
						|
		/// </summary> | 
						|
		public static readonly Conversion None = new InvalidConversion(); | 
						|
 | 
						|
		/// <summary> | 
						|
		/// Identity conversion. | 
						|
		/// </summary> | 
						|
		public static readonly Conversion IdentityConversion = new BuiltinConversion(true, 0); | 
						|
 | 
						|
		public static readonly Conversion ImplicitNumericConversion = new NumericOrEnumerationConversion(true, false); | 
						|
		public static readonly Conversion ExplicitNumericConversion = new NumericOrEnumerationConversion(false, false); | 
						|
		public static readonly Conversion ImplicitLiftedNumericConversion = new NumericOrEnumerationConversion(true, true); | 
						|
		public static readonly Conversion ExplicitLiftedNumericConversion = new NumericOrEnumerationConversion(false, true); | 
						|
 | 
						|
		public static Conversion EnumerationConversion(bool isImplicit, bool isLifted) | 
						|
		{ | 
						|
			return new NumericOrEnumerationConversion(isImplicit, isLifted, true); | 
						|
		} | 
						|
 | 
						|
		public static readonly Conversion NullLiteralConversion = new BuiltinConversion(true, 1); | 
						|
 | 
						|
		/// <summary> | 
						|
		/// The numeric conversion of a constant expression. | 
						|
		/// </summary> | 
						|
		public static readonly Conversion ImplicitConstantExpressionConversion = new BuiltinConversion(true, 2); | 
						|
 | 
						|
		public static readonly Conversion ImplicitReferenceConversion = new BuiltinConversion(true, 3); | 
						|
		public static readonly Conversion ExplicitReferenceConversion = new BuiltinConversion(false, 3); | 
						|
 | 
						|
		public static readonly Conversion ImplicitDynamicConversion = new BuiltinConversion(true, 4); | 
						|
		public static readonly Conversion ExplicitDynamicConversion = new BuiltinConversion(false, 4); | 
						|
 | 
						|
		public static readonly Conversion ImplicitNullableConversion = new BuiltinConversion(true, 5); | 
						|
		public static readonly Conversion ExplicitNullableConversion = new BuiltinConversion(false, 5); | 
						|
 | 
						|
		public static readonly Conversion ImplicitPointerConversion = new BuiltinConversion(true, 6); | 
						|
		public static readonly Conversion ExplicitPointerConversion = new BuiltinConversion(false, 6); | 
						|
 | 
						|
		public static readonly Conversion BoxingConversion = new BuiltinConversion(true, 7); | 
						|
		public static readonly Conversion UnboxingConversion = new BuiltinConversion(false, 8); | 
						|
 | 
						|
		/// <summary> | 
						|
		/// C# 'as' cast. | 
						|
		/// </summary> | 
						|
		public static readonly Conversion TryCast = new BuiltinConversion(false, 9); | 
						|
 | 
						|
		/// <summary> | 
						|
		/// C# 6 string interpolation expression implicitly being converted to <see cref="System.IFormattable"/> or <see cref="System.FormattableString"/>. | 
						|
		/// </summary> | 
						|
		public static readonly Conversion ImplicitInterpolatedStringConversion = new BuiltinConversion(true, 10); | 
						|
 | 
						|
		/// <summary> | 
						|
		/// C# 7 throw expression being converted to an arbitrary type. | 
						|
		/// </summary> | 
						|
		public static readonly Conversion ThrowExpressionConversion = new BuiltinConversion(true, 11); | 
						|
 | 
						|
		public static Conversion UserDefinedConversion(IMethod operatorMethod, bool isImplicit, Conversion conversionBeforeUserDefinedOperator, Conversion conversionAfterUserDefinedOperator, bool isLifted = false, bool isAmbiguous = false) | 
						|
		{ | 
						|
			if (operatorMethod == null) | 
						|
				throw new ArgumentNullException(nameof(operatorMethod)); | 
						|
			return new UserDefinedConv(isImplicit, operatorMethod, conversionBeforeUserDefinedOperator, conversionAfterUserDefinedOperator, isLifted, isAmbiguous); | 
						|
		} | 
						|
 | 
						|
		public static Conversion MethodGroupConversion(IMethod chosenMethod, bool isVirtualMethodLookup, bool delegateCapturesFirstArgument) | 
						|
		{ | 
						|
			if (chosenMethod == null) | 
						|
				throw new ArgumentNullException(nameof(chosenMethod)); | 
						|
			return new MethodGroupConv(chosenMethod, isVirtualMethodLookup, delegateCapturesFirstArgument, isValid: true); | 
						|
		} | 
						|
 | 
						|
		public static Conversion InvalidMethodGroupConversion(IMethod chosenMethod, bool isVirtualMethodLookup, bool delegateCapturesFirstArgument) | 
						|
		{ | 
						|
			if (chosenMethod == null) | 
						|
				throw new ArgumentNullException(nameof(chosenMethod)); | 
						|
			return new MethodGroupConv(chosenMethod, isVirtualMethodLookup, delegateCapturesFirstArgument, isValid: false); | 
						|
		} | 
						|
 | 
						|
		public static Conversion TupleConversion(ImmutableArray<Conversion> conversions) | 
						|
		{ | 
						|
			return new TupleConv(conversions); | 
						|
		} | 
						|
		#endregion | 
						|
 | 
						|
		#region Inner classes | 
						|
		sealed class InvalidConversion : Conversion | 
						|
		{ | 
						|
			public override bool IsValid { | 
						|
				get { return false; } | 
						|
			} | 
						|
 | 
						|
			public override string ToString() | 
						|
			{ | 
						|
				return "None"; | 
						|
			} | 
						|
		} | 
						|
 | 
						|
		sealed class NumericOrEnumerationConversion : Conversion | 
						|
		{ | 
						|
			readonly bool isImplicit; | 
						|
			readonly bool isLifted; | 
						|
			readonly bool isEnumeration; | 
						|
 | 
						|
			public NumericOrEnumerationConversion(bool isImplicit, bool isLifted, bool isEnumeration = false) | 
						|
			{ | 
						|
				this.isImplicit = isImplicit; | 
						|
				this.isLifted = isLifted; | 
						|
				this.isEnumeration = isEnumeration; | 
						|
			} | 
						|
 | 
						|
			public override bool IsImplicit { | 
						|
				get { return isImplicit; } | 
						|
			} | 
						|
 | 
						|
			public override bool IsExplicit { | 
						|
				get { return !isImplicit; } | 
						|
			} | 
						|
 | 
						|
			public override bool IsNumericConversion { | 
						|
				get { return !isEnumeration; } | 
						|
			} | 
						|
 | 
						|
			public override bool IsEnumerationConversion { | 
						|
				get { return isEnumeration; } | 
						|
			} | 
						|
 | 
						|
			public override bool IsLifted { | 
						|
				get { return isLifted; } | 
						|
			} | 
						|
 | 
						|
			public override string ToString() | 
						|
			{ | 
						|
				return (isImplicit ? "implicit" : "explicit") | 
						|
					+ (isLifted ? " lifted" : "") | 
						|
					+ (isEnumeration ? " enumeration" : " numeric") | 
						|
					+ " conversion"; | 
						|
			} | 
						|
 | 
						|
			public override bool Equals(Conversion other) | 
						|
			{ | 
						|
				NumericOrEnumerationConversion o = other as NumericOrEnumerationConversion; | 
						|
				return o != null && isImplicit == o.isImplicit && isLifted == o.isLifted && isEnumeration == o.isEnumeration; | 
						|
			} | 
						|
 | 
						|
			public override int GetHashCode() | 
						|
			{ | 
						|
				return (isImplicit ? 1 : 0) + (isLifted ? 2 : 0) + (isEnumeration ? 4 : 0); | 
						|
			} | 
						|
		} | 
						|
 | 
						|
		sealed class BuiltinConversion : Conversion | 
						|
		{ | 
						|
			readonly bool isImplicit; | 
						|
			readonly byte type; | 
						|
 | 
						|
			public BuiltinConversion(bool isImplicit, byte type) | 
						|
			{ | 
						|
				this.isImplicit = isImplicit; | 
						|
				this.type = type; | 
						|
			} | 
						|
 | 
						|
			public override bool IsImplicit { | 
						|
				get { return isImplicit; } | 
						|
			} | 
						|
 | 
						|
			public override bool IsExplicit { | 
						|
				get { return !isImplicit; } | 
						|
			} | 
						|
 | 
						|
			public override bool IsIdentityConversion { | 
						|
				get { return type == 0; } | 
						|
			} | 
						|
 | 
						|
			public override bool IsNullLiteralConversion { | 
						|
				get { return type == 1; } | 
						|
			} | 
						|
 | 
						|
			public override bool IsConstantExpressionConversion { | 
						|
				get { return type == 2; } | 
						|
			} | 
						|
 | 
						|
			public override bool IsReferenceConversion { | 
						|
				get { return type == 3; } | 
						|
			} | 
						|
 | 
						|
			public override bool IsDynamicConversion { | 
						|
				get { return type == 4; } | 
						|
			} | 
						|
 | 
						|
			public override bool IsNullableConversion { | 
						|
				get { return type == 5; } | 
						|
			} | 
						|
 | 
						|
			public override bool IsPointerConversion { | 
						|
				get { return type == 6; } | 
						|
			} | 
						|
 | 
						|
			public override bool IsBoxingConversion { | 
						|
				get { return type == 7; } | 
						|
			} | 
						|
 | 
						|
			public override bool IsUnboxingConversion { | 
						|
				get { return type == 8; } | 
						|
			} | 
						|
 | 
						|
			public override bool IsTryCast { | 
						|
				get { return type == 9; } | 
						|
			} | 
						|
 | 
						|
			public override bool IsInterpolatedStringConversion => type == 10; | 
						|
 | 
						|
			public override bool IsThrowExpressionConversion { | 
						|
				get { return type == 11; } | 
						|
			} | 
						|
 | 
						|
			public override string ToString() | 
						|
			{ | 
						|
				string name = null; | 
						|
				switch (type) | 
						|
				{ | 
						|
					case 0: | 
						|
						return "identity conversion"; | 
						|
					case 1: | 
						|
						return "null-literal conversion"; | 
						|
					case 2: | 
						|
						name = "constant-expression"; | 
						|
						break; | 
						|
					case 3: | 
						|
						name = "reference"; | 
						|
						break; | 
						|
					case 4: | 
						|
						name = "dynamic"; | 
						|
						break; | 
						|
					case 5: | 
						|
						name = "nullable"; | 
						|
						break; | 
						|
					case 6: | 
						|
						name = "pointer"; | 
						|
						break; | 
						|
					case 7: | 
						|
						return "boxing conversion"; | 
						|
					case 8: | 
						|
						return "unboxing conversion"; | 
						|
					case 9: | 
						|
						return "try cast"; | 
						|
					case 10: | 
						|
						return "interpolated string"; | 
						|
					case 11: | 
						|
						return "throw-expression conversion"; | 
						|
				} | 
						|
				return (isImplicit ? "implicit " : "explicit ") + name + " conversion"; | 
						|
			} | 
						|
		} | 
						|
 | 
						|
		sealed class UserDefinedConv : Conversion | 
						|
		{ | 
						|
			readonly IMethod method; | 
						|
			readonly bool isLifted; | 
						|
			readonly Conversion conversionBeforeUserDefinedOperator; | 
						|
			readonly Conversion conversionAfterUserDefinedOperator; | 
						|
			readonly bool isImplicit; | 
						|
			readonly bool isValid; | 
						|
 | 
						|
			public UserDefinedConv(bool isImplicit, IMethod method, Conversion conversionBeforeUserDefinedOperator, Conversion conversionAfterUserDefinedOperator, bool isLifted, bool isAmbiguous) | 
						|
			{ | 
						|
				this.method = method; | 
						|
				this.isLifted = isLifted; | 
						|
				this.conversionBeforeUserDefinedOperator = conversionBeforeUserDefinedOperator; | 
						|
				this.conversionAfterUserDefinedOperator = conversionAfterUserDefinedOperator; | 
						|
				this.isImplicit = isImplicit; | 
						|
				this.isValid = !isAmbiguous; | 
						|
			} | 
						|
 | 
						|
			public override bool IsValid { | 
						|
				get { return isValid; } | 
						|
			} | 
						|
 | 
						|
			public override bool IsImplicit { | 
						|
				get { return isImplicit; } | 
						|
			} | 
						|
 | 
						|
			public override bool IsExplicit { | 
						|
				get { return !isImplicit; } | 
						|
			} | 
						|
 | 
						|
			public override bool IsLifted { | 
						|
				get { return isLifted; } | 
						|
			} | 
						|
 | 
						|
			public override bool IsUserDefined { | 
						|
				get { return true; } | 
						|
			} | 
						|
 | 
						|
			public override Conversion ConversionBeforeUserDefinedOperator { | 
						|
				get { return conversionBeforeUserDefinedOperator; } | 
						|
			} | 
						|
 | 
						|
			public override Conversion ConversionAfterUserDefinedOperator { | 
						|
				get { return conversionAfterUserDefinedOperator; } | 
						|
			} | 
						|
 | 
						|
			public override IMethod Method { | 
						|
				get { return method; } | 
						|
			} | 
						|
 | 
						|
			public override bool Equals(Conversion other) | 
						|
			{ | 
						|
				UserDefinedConv o = other as UserDefinedConv; | 
						|
				return o != null && isLifted == o.isLifted && isImplicit == o.isImplicit && isValid == o.isValid && method.Equals(o.method); | 
						|
			} | 
						|
 | 
						|
			public override int GetHashCode() | 
						|
			{ | 
						|
				return unchecked(method.GetHashCode() + (isLifted ? 31 : 27) + (isImplicit ? 71 : 61) + (isValid ? 107 : 109)); | 
						|
			} | 
						|
 | 
						|
			public override string ToString() | 
						|
			{ | 
						|
				return (isImplicit ? "implicit" : "explicit") | 
						|
					+ (isLifted ? " lifted" : "") | 
						|
					+ (isValid ? "" : " ambiguous") | 
						|
					+ "user-defined conversion (" + method + ")"; | 
						|
			} | 
						|
		} | 
						|
 | 
						|
		sealed class MethodGroupConv : Conversion | 
						|
		{ | 
						|
			readonly IMethod method; | 
						|
			readonly bool isVirtualMethodLookup; | 
						|
			readonly bool delegateCapturesFirstArgument; | 
						|
			readonly bool isValid; | 
						|
 | 
						|
			public MethodGroupConv(IMethod method, bool isVirtualMethodLookup, bool delegateCapturesFirstArgument, bool isValid) | 
						|
			{ | 
						|
				this.method = method; | 
						|
				this.isVirtualMethodLookup = isVirtualMethodLookup; | 
						|
				this.delegateCapturesFirstArgument = delegateCapturesFirstArgument; | 
						|
				this.isValid = isValid; | 
						|
			} | 
						|
 | 
						|
			public override bool IsValid { | 
						|
				get { return isValid; } | 
						|
			} | 
						|
 | 
						|
			public override bool IsImplicit { | 
						|
				get { return true; } | 
						|
			} | 
						|
 | 
						|
			public override bool IsMethodGroupConversion { | 
						|
				get { return true; } | 
						|
			} | 
						|
 | 
						|
			public override bool IsVirtualMethodLookup { | 
						|
				get { return isVirtualMethodLookup; } | 
						|
			} | 
						|
 | 
						|
			public override bool DelegateCapturesFirstArgument { | 
						|
				get { return delegateCapturesFirstArgument; } | 
						|
			} | 
						|
 | 
						|
			public override IMethod Method { | 
						|
				get { return method; } | 
						|
			} | 
						|
 | 
						|
			public override bool Equals(Conversion other) | 
						|
			{ | 
						|
				MethodGroupConv o = other as MethodGroupConv; | 
						|
				return o != null && method.Equals(o.method); | 
						|
			} | 
						|
 | 
						|
			public override int GetHashCode() | 
						|
			{ | 
						|
				return method.GetHashCode(); | 
						|
			} | 
						|
		} | 
						|
 | 
						|
		sealed class TupleConv : Conversion | 
						|
		{ | 
						|
			public override bool IsImplicit { get; } | 
						|
			public override bool IsExplicit => !IsImplicit; | 
						|
			public override ImmutableArray<Conversion> ElementConversions { get; } | 
						|
			public override bool IsTupleConversion => true; | 
						|
 | 
						|
			public TupleConv(ImmutableArray<Conversion> elementConversions) | 
						|
			{ | 
						|
				this.ElementConversions = elementConversions; | 
						|
				this.IsImplicit = elementConversions.All(c => c.IsImplicit); | 
						|
			} | 
						|
 | 
						|
			public override bool Equals(Conversion other) | 
						|
			{ | 
						|
				return other is TupleConv o | 
						|
					&& ElementConversions.SequenceEqual(o.ElementConversions); | 
						|
			} | 
						|
 | 
						|
			public override int GetHashCode() | 
						|
			{ | 
						|
				unchecked | 
						|
				{ | 
						|
					int hash = 0; | 
						|
					foreach (var conv in ElementConversions) | 
						|
					{ | 
						|
						hash *= 31; | 
						|
						hash += conv.GetHashCode(); | 
						|
					} | 
						|
					return hash; | 
						|
				} | 
						|
			} | 
						|
 | 
						|
			public override string ToString() | 
						|
			{ | 
						|
				return (IsImplicit ? "implicit " : "explicit ") + " tuple conversion"; | 
						|
			} | 
						|
		} | 
						|
		#endregion | 
						|
 | 
						|
		/// <summary> | 
						|
		/// Gets whether the conversion is valid. | 
						|
		/// </summary> | 
						|
		public virtual bool IsValid { | 
						|
			get { return true; } | 
						|
		} | 
						|
 | 
						|
		public virtual bool IsImplicit { | 
						|
			get { return false; } | 
						|
		} | 
						|
 | 
						|
		public virtual bool IsExplicit { | 
						|
			get { return false; } | 
						|
		} | 
						|
 | 
						|
		/// <summary> | 
						|
		/// Gets whether the conversion is an '<c>as</c>' cast. | 
						|
		/// </summary> | 
						|
		public virtual bool IsTryCast { | 
						|
			get { return false; } | 
						|
		} | 
						|
 | 
						|
		public virtual bool IsThrowExpressionConversion { | 
						|
			get { return false; } | 
						|
		} | 
						|
 | 
						|
		public virtual bool IsIdentityConversion { | 
						|
			get { return false; } | 
						|
		} | 
						|
 | 
						|
		public virtual bool IsNullLiteralConversion { | 
						|
			get { return false; } | 
						|
		} | 
						|
 | 
						|
		public virtual bool IsConstantExpressionConversion { | 
						|
			get { return false; } | 
						|
		} | 
						|
 | 
						|
		public virtual bool IsNumericConversion { | 
						|
			get { return false; } | 
						|
		} | 
						|
 | 
						|
		/// <summary> | 
						|
		/// Gets whether this conversion is a lifted version of another conversion. | 
						|
		/// </summary> | 
						|
		public virtual bool IsLifted { | 
						|
			get { return false; } | 
						|
		} | 
						|
 | 
						|
		/// <summary> | 
						|
		/// Gets whether the conversion is dynamic. | 
						|
		/// </summary> | 
						|
		public virtual bool IsDynamicConversion { | 
						|
			get { return false; } | 
						|
		} | 
						|
 | 
						|
		/// <summary> | 
						|
		/// Gets whether the conversion is a reference conversion. | 
						|
		/// </summary> | 
						|
		public virtual bool IsReferenceConversion { | 
						|
			get { return false; } | 
						|
		} | 
						|
 | 
						|
		/// <summary> | 
						|
		/// Gets whether the conversion is an enumeration conversion. | 
						|
		/// </summary> | 
						|
		public virtual bool IsEnumerationConversion { | 
						|
			get { return false; } | 
						|
		} | 
						|
 | 
						|
		/// <summary> | 
						|
		/// Gets whether the conversion is a nullable conversion | 
						|
		/// (conversion between a nullable type and the regular type). | 
						|
		/// </summary> | 
						|
		public virtual bool IsNullableConversion { | 
						|
			get { return false; } | 
						|
		} | 
						|
 | 
						|
		/// <summary> | 
						|
		/// Gets whether this conversion is user-defined (op_Implicit or op_Explicit). | 
						|
		/// </summary> | 
						|
		public virtual bool IsUserDefined { | 
						|
			get { return false; } | 
						|
		} | 
						|
 | 
						|
		/// <summary> | 
						|
		/// The conversion that is applied to the input before the user-defined conversion operator is invoked. | 
						|
		/// </summary> | 
						|
		public virtual Conversion ConversionBeforeUserDefinedOperator { | 
						|
			get { return null; } | 
						|
		} | 
						|
 | 
						|
		/// <summary> | 
						|
		/// The conversion that is applied to the result of the user-defined conversion operator. | 
						|
		/// </summary> | 
						|
		public virtual Conversion ConversionAfterUserDefinedOperator { | 
						|
			get { return null; } | 
						|
		} | 
						|
 | 
						|
		/// <summary> | 
						|
		/// Gets whether this conversion is a boxing conversion. | 
						|
		/// </summary> | 
						|
		public virtual bool IsBoxingConversion { | 
						|
			get { return false; } | 
						|
		} | 
						|
 | 
						|
		/// <summary> | 
						|
		/// Gets whether this conversion is an unboxing conversion. | 
						|
		/// </summary> | 
						|
		public virtual bool IsUnboxingConversion { | 
						|
			get { return false; } | 
						|
		} | 
						|
 | 
						|
		/// <summary> | 
						|
		/// Gets whether this conversion is a pointer conversion. | 
						|
		/// </summary> | 
						|
		public virtual bool IsPointerConversion { | 
						|
			get { return false; } | 
						|
		} | 
						|
 | 
						|
		/// <summary> | 
						|
		/// Gets whether this conversion is a method group conversion. | 
						|
		/// </summary> | 
						|
		public virtual bool IsMethodGroupConversion { | 
						|
			get { return false; } | 
						|
		} | 
						|
 | 
						|
		/// <summary> | 
						|
		/// For method-group conversions, gets whether to perform a virtual method lookup at runtime. | 
						|
		/// </summary> | 
						|
		public virtual bool IsVirtualMethodLookup { | 
						|
			get { return false; } | 
						|
		} | 
						|
 | 
						|
		/// <summary> | 
						|
		/// For method-group conversions, gets whether the conversion captures the first argument. | 
						|
		///  | 
						|
		/// For instance methods, this property always returns true for C# method-group conversions. | 
						|
		/// For static methods, this property returns true for method-group conversions of an extension method performed on an instance (eg. <c>Func<int> f = myEnumerable.Single</c>). | 
						|
		/// </summary> | 
						|
		public virtual bool DelegateCapturesFirstArgument { | 
						|
			get { return false; } | 
						|
		} | 
						|
 | 
						|
		/// <summary> | 
						|
		/// Gets whether this conversion is an anonymous function conversion. | 
						|
		/// </summary> | 
						|
		public virtual bool IsAnonymousFunctionConversion { | 
						|
			get { return false; } | 
						|
		} | 
						|
 | 
						|
		/// <summary> | 
						|
		/// Gets the method associated with this conversion. | 
						|
		/// For user-defined conversions, this is the method being called. | 
						|
		/// For method-group conversions, this is the method that was chosen from the group. | 
						|
		/// </summary> | 
						|
		public virtual IMethod Method { | 
						|
			get { return null; } | 
						|
		} | 
						|
 | 
						|
		/// <summary> | 
						|
		/// Gets whether this conversion is a tuple conversion. | 
						|
		/// </summary> | 
						|
		public virtual bool IsTupleConversion => false; | 
						|
 | 
						|
		/// <summary> | 
						|
		/// Gets whether this is an interpolated string conversion to <see cref="IFormattable" /> or <see cref="FormattableString"/>. | 
						|
		/// </summary> | 
						|
		public virtual bool IsInterpolatedStringConversion => false; | 
						|
 | 
						|
		/// <summary> | 
						|
		/// For a tuple conversion, gets the individual tuple element conversions. | 
						|
		/// </summary> | 
						|
		public virtual ImmutableArray<Conversion> ElementConversions => default(ImmutableArray<Conversion>); | 
						|
 | 
						|
		public override sealed bool Equals(object obj) | 
						|
		{ | 
						|
			return Equals(obj as Conversion); | 
						|
		} | 
						|
 | 
						|
		public override int GetHashCode() | 
						|
		{ | 
						|
			return base.GetHashCode(); | 
						|
		} | 
						|
 | 
						|
		public virtual bool Equals(Conversion other) | 
						|
		{ | 
						|
			return this == other; | 
						|
		} | 
						|
	} | 
						|
}
 | 
						|
 |