mirror of
https://github.com/icsharpcode/ILSpy.git
synced 2026-10-12 02:15:58 +00:00
Shortening default(T) is the same problem as removing the redundant cast around a lambda whose delegate type the context already fixes, so it uses the same mechanism: ConvertTo makes the explicit type implicit when the conversion is an identity conversion and the caller allows an implicit one. The literal keeps the type it was shortened from, so any later conversion to a different type - or any context that requires an explicit type, such as an overload resolution recheck falling back to CastArguments - can spell default(T) out again. That keeps the value intact where the bare literal would change it, e.g. "object o = default(SomeStruct)", which boxes a non-null struct while "default" would be null. Because the shortened literal resolves to DefaultLiteralResolveResult, CallBuilder's existing overload resolution recheck sees a real default literal and rejects ambiguous calls on its own; no separate bookkeeping about which arguments may stay untyped is needed. Only the contexts that supply no target type at all restore the explicit form: an awaited expression, and arguments of operator methods, which later become operator or cast syntax rather than calls. Assisted-by: Claude:claude-opus-5[1m]:Claude Code
696 lines
21 KiB
C#
696 lines
21 KiB
C#
// 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);
|
|
|
|
/// <summary>
|
|
/// C# 12 inline array implicitly being converted to <see cref="System.Span{T}"/> or <see cref="System.ReadOnlySpan{T}"/>.
|
|
/// </summary>
|
|
public static readonly Conversion InlineArrayConversion = new BuiltinConversion(true, 12);
|
|
|
|
/// <summary>
|
|
/// C# 14 implicit span conversion from an array type to <see cref="System.Span{T}"/> or <see cref="System.ReadOnlySpan{T}"/>.
|
|
/// </summary>
|
|
public static readonly Conversion ImplicitSpanConversion = new BuiltinConversion(true, 13);
|
|
|
|
/// <summary>
|
|
/// C# 14 explicit span conversion: from an array type to <see cref="System.Span{T}"/> or
|
|
/// <see cref="System.ReadOnlySpan{T}"/> where the element types are related by an
|
|
/// explicit reference conversion.
|
|
/// </summary>
|
|
public static readonly Conversion ExplicitSpanConversion = new BuiltinConversion(false, 14);
|
|
|
|
/// <summary>
|
|
/// C# 7.1 default literal being converted to an arbitrary type.
|
|
/// </summary>
|
|
public static readonly Conversion DefaultLiteralConversion = new BuiltinConversion(true, 15);
|
|
|
|
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 bool IsInlineArrayConversion => type == 12;
|
|
public override bool IsImplicitSpanConversion => type == 13;
|
|
public override bool IsExplicitSpanConversion => type == 14;
|
|
public override bool IsDefaultLiteralConversion => type == 15;
|
|
|
|
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";
|
|
case 12:
|
|
return "inline array conversion";
|
|
case 13:
|
|
return "implicit span conversion";
|
|
case 14:
|
|
return "explicit span conversion";
|
|
case 15:
|
|
return "default-literal 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 IsDefaultLiteralConversion {
|
|
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>
|
|
/// Gets whether this is an inline array conversion to <see cref="System.Span{T}"/> or <see cref="System.ReadOnlySpan{T}"/>.
|
|
/// </summary>
|
|
public virtual bool IsInlineArrayConversion => false;
|
|
|
|
/// <summary>
|
|
/// Gets whether this is an implicit span conversion from an array type to <see cref="System.Span{T}"/> or <see cref="System.ReadOnlySpan{T}"/>.
|
|
/// </summary>
|
|
public virtual bool IsImplicitSpanConversion => false;
|
|
|
|
/// <summary>
|
|
/// Gets whether this is an explicit span conversion from an array type to <see cref="System.Span{T}"/>
|
|
/// or <see cref="System.ReadOnlySpan{T}"/> whose element types are related by an explicit
|
|
/// reference conversion.
|
|
/// </summary>
|
|
public virtual bool IsExplicitSpanConversion => 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;
|
|
}
|
|
}
|
|
}
|