diff --git a/ICSharpCode.Decompiler/CSharp/Resolver/CSharpConversions.cs b/ICSharpCode.Decompiler/CSharp/Resolver/CSharpConversions.cs
index 044c61487..832e4ab3c 100644
--- a/ICSharpCode.Decompiler/CSharp/Resolver/CSharpConversions.cs
+++ b/ICSharpCode.Decompiler/CSharp/Resolver/CSharpConversions.cs
@@ -165,7 +165,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
private Conversion ImplicitConversion(IType fromType, IType toType, bool allowUserDefined, bool allowTuple)
{
- // C# 4.0 spec: §6.1
+ // C# spec (draft-v11): §10.2 Implicit conversions
var c = StandardImplicitConversion(fromType, toType, allowTuple);
if (c == Conversion.None && allowUserDefined)
{
@@ -234,7 +234,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
if (allowTupleConversion)
{
// TODO are tuple conversions really standard implicit conversions?
- // the C# 9.0 spec doesn't list them as standard implicit conversions.
+ // The C# spec (draft-v11, §10.4.2) doesn't list them as standard implicit conversions.
c = TupleConversion(fromType, toType, isExplicit: false);
if (c != Conversion.None)
return c;
@@ -256,7 +256,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
///
/// Gets whether the type 'fromType' is convertible to 'toType'
- /// using one of the conversions allowed when satisfying constraints (§4.4.4)
+ /// using one of the conversions allowed when satisfying constraints (§8.4.5)
///
public bool IsConstraintConvertible(IType fromType, IType toType)
{
@@ -366,7 +366,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
///
public bool IdentityConversion(IType fromType, IType toType)
{
- // C# 4.0 spec: §6.1.1
+ // C# spec (draft-v11): §10.2.2 Identity conversion
fromType = fromType.AcceptVisitor(NormalizeTypeVisitor.TypeErasure);
toType = toType.AcceptVisitor(NormalizeTypeVisitor.TypeErasure);
return fromType.Equals(toType);
@@ -450,7 +450,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
bool AnyNumericConversion(IType fromType, IType toType)
{
- // C# 4.0 spec: §6.1.2 + §6.2.1
+ // C# spec (draft-v11): §10.2.3 + §10.3.2 (numeric conversions)
return IsNumericType(fromType) && IsNumericType(toType);
}
#endregion
@@ -473,7 +473,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
bool ExplicitEnumerationConversion(IType fromType, IType toType)
{
- // C# 4.0 spec: §6.2.2
+ // C# spec (draft-v11): §10.3.3 Explicit enumeration conversions
if (fromType.Kind == TypeKind.Enum)
{
return toType.Kind == TypeKind.Enum || IsNumericType(toType);
@@ -504,7 +504,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
Conversion ExplicitNullableConversion(IType fromType, IType toType)
{
- // C# 4.0 spec: §6.1.4
+ // C# spec (draft-v11): §10.3.4 Explicit nullable conversions
if (NullableType.IsNullable(toType) || NullableType.IsNullable(fromType))
{
IType t = NullableType.GetUnderlyingType(toType);
@@ -638,7 +638,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
ParameterizedType pt = t as ParameterizedType;
if (ps != null && pt != null)
{
- // C# 4.0 spec: §13.1.3.2 Variance Conversion
+ // C# spec (draft-v11): §19.2.3.3 Variance conversion
for (int i = 0; i < def.TypeParameters.Count; i++)
{
IType si = ps.GetTypeArgument(i);
@@ -678,7 +678,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
#region Explicit Reference Conversion
bool ExplicitReferenceConversion(IType fromType, IType toType)
{
- // C# 4.0 spec: §6.2.4
+ // C# spec (draft-v11): §10.3.5 Explicit reference conversions
// test that the types are reference types:
if (toType.IsReferenceType != true)
@@ -811,7 +811,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
bool UnboxingConversion(IType fromType, IType toType)
{
- // C# 4.0 spec: §6.2.5
+ // C# spec (draft-v11): §10.3.7 Unboxing conversions
toType = NullableType.GetUnderlyingType(toType);
if (fromType.IsReferenceType == true && toType.IsReferenceType == false)
return IsSubtypeOf(toType, fromType, 0);
@@ -898,7 +898,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
#region Pointer Conversions
bool ImplicitPointerConversion(IType fromType, IType toType)
{
- // C# 4.0 spec: §18.4 Pointer conversions
+ // C# spec (draft-v11): §24.5 Pointer conversions
if (fromType.Kind.IsAnyPointer() && toType is PointerType && toType.ReflectionName == "System.Void*")
return true;
if (fromType.Kind == TypeKind.Null && toType.Kind.IsAnyPointer())
@@ -929,7 +929,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
bool ExplicitPointerConversion(IType fromType, IType toType)
{
- // C# 4.0 spec: §18.4 Pointer conversions
+ // C# spec (draft-v11): §24.5 Pointer conversions
if (fromType.Kind.IsAnyPointer())
{
return toType.Kind.IsAnyPointer() || IsIntegerType(toType);
@@ -1029,7 +1029,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
Conversion UserDefinedImplicitConversion(ResolveResult fromResult, IType fromType, IType toType)
{
- // C# 4.0 spec §6.4.4 User-defined implicit conversions
+ // C# spec (draft-v11): §10.5.4 User-defined implicit conversions
// user-defined conversions are not supported with interfaces
if (fromType.Kind == TypeKind.Interface || toType.Kind == TypeKind.Interface)
@@ -1078,7 +1078,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
Conversion UserDefinedExplicitConversion(ResolveResult fromResult, IType fromType, IType toType)
{
- // C# 4.0 spec §6.4.5 User-defined explicit conversions
+ // C# spec (draft-v11): §10.5.5 User-defined explicit conversions
// user-defined conversions are not supported with interfaces
if (fromType.Kind == TypeKind.Interface || toType.Kind == TypeKind.Interface)
@@ -1414,7 +1414,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
///
/// Gets whether a is compatible with a delegate type.
- /// §15.2 Delegate compatibility
+ /// C# spec (draft-v11): §21.4 Delegate compatibility
///
/// The method to test for compatibility
/// The delegate type
@@ -1439,7 +1439,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
/// If this parameter is true, the first parameter of will be ignored.
bool IsDelegateCompatible(IMethod m, IMethod d, bool isExtensionMethodInvocation)
{
- // C# 9.0 §20.4 Delegate compatibility
+ // C# spec (draft-v11): §21.4 Delegate compatibility
if (m == null)
throw new ArgumentNullException(nameof(m));
if (d == null)
@@ -1479,7 +1479,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
#region Tuple Conversion
Conversion TupleConversion(TupleResolveResult fromRR, IType toType, bool isExplicit)
{
- // C# 9.0 spec: §10.2.13 (implicit tuple conversions) + $10.3.6 (explicit tuple conversions)
+ // C# 9.0 spec: §10.2.13 (implicit tuple conversions) + §10.3.6 (explicit tuple conversions)
var fromElements = fromRR.Elements;
var toElements = TupleType.GetTupleElementTypes(toType);
if (toElements.IsDefault || fromElements.Length != toElements.Length)
@@ -1505,7 +1505,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
Conversion TupleConversion(IType fromType, IType toType, bool isExplicit)
{
- // C# 9.0 spec: §10.2.13 (implicit tuple conversions) + $10.3.6 (explicit tuple conversions)
+ // C# 9.0 spec: §10.2.13 (implicit tuple conversions) + §10.3.6 (explicit tuple conversions)
var fromElements = TupleType.GetTupleElementTypes(fromType);
if (fromElements.IsDefaultOrEmpty)
return Conversion.None;
@@ -1659,7 +1659,8 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
}
///
- /// Gets the better conversion (from type) (C# 4.0 spec, §7.5.3.4)
+ /// Gets the better conversion (from type) (C# 4.0 spec, §7.5.3.4; the current standard
+ /// no longer has this subclause, it was folded into §12.6.4.5-§12.6.4.7)
///
/// 0 = neither is better; 1 = t1 is better; 2 = t2 is better
public int BetterConversion(IType s, IType t1, IType t2)
diff --git a/ICSharpCode.Decompiler/CSharp/Resolver/CSharpOperators.cs b/ICSharpCode.Decompiler/CSharp/Resolver/CSharpOperators.cs
index 9db00cbe9..34f11b7db 100644
--- a/ICSharpCode.Decompiler/CSharp/Resolver/CSharpOperators.cs
+++ b/ICSharpCode.Decompiler/CSharp/Resolver/CSharpOperators.cs
@@ -366,7 +366,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
}
}
- // C# 4.0 spec: §7.7.3 Logical negation operator
+ // C# spec (draft-v11): §12.9.4 Logical negation operator
OperatorMethod[]? logicalNegationOperators;
public OperatorMethod[] LogicalNegationOperators {
diff --git a/ICSharpCode.Decompiler/CSharp/Resolver/CSharpResolver.cs b/ICSharpCode.Decompiler/CSharp/Resolver/CSharpResolver.cs
index d3a49fbc9..b54f309d6 100644
--- a/ICSharpCode.Decompiler/CSharp/Resolver/CSharpResolver.cs
+++ b/ICSharpCode.Decompiler/CSharp/Resolver/CSharpResolver.cs
@@ -337,7 +337,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
}
}
- // C# 4.0 spec: §7.3.3 Unary operator overload resolution
+ // C# spec (draft-v11): §12.4.4 Unary operator overload resolution
string overloadableOperatorName = GetOverloadableOperatorName(op);
if (overloadableOperatorName == null)
{
@@ -426,8 +426,8 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
case UnaryOperatorType.Decrement:
case UnaryOperatorType.PostIncrement:
case UnaryOperatorType.PostDecrement:
- // C# 4.0 spec: §7.6.9 Postfix increment and decrement operators
- // C# 4.0 spec: §7.7.5 Prefix increment and decrement operators
+ // C# spec (draft-v11): §12.8.16 Postfix increment and decrement operators
+ // C# spec (draft-v11): §12.9.7 Prefix increment and decrement operators
TypeCode code = ReflectionHelper.GetTypeCode(type);
if ((code >= TypeCode.Char && code <= TypeCode.Decimal) || type.Kind == TypeKind.Enum || type.Kind == TypeKind.Pointer || type.IsCSharpNativeIntegerType())
return UnaryOperatorResolveResult(expression.Type, op, expression, isNullable);
@@ -535,7 +535,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
#region UnaryNumericPromotion
ResolveResult UnaryNumericPromotion(UnaryOperatorType op, ref IType type, bool isNullable, ResolveResult expression)
{
- // C# 4.0 spec: §7.3.6.1
+ // C# spec (draft-v11): §12.4.7.2 Unary numeric promotions
TypeCode code = ReflectionHelper.GetTypeCode(type);
if (isNullable && type.Kind == TypeKind.Null)
code = TypeCode.SByte; // cause promotion of null to int32
@@ -1064,7 +1064,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
#region BinaryNumericPromotion
bool BinaryNumericPromotion(bool isNullable, ref ResolveResult lhs, ref ResolveResult rhs, bool allowNullableConstants)
{
- // C# 4.0 spec: §7.3.6.2
+ // C# spec (draft-v11): §12.4.7.3 Binary numeric promotions
var lhsUType = NullableType.GetUnderlyingType(lhs.Type);
var rhsUType = NullableType.GetUnderlyingType(rhs.Type);
TypeCode lhsCode = ReflectionHelper.GetTypeCode(lhsUType);
@@ -1288,7 +1288,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
// However, we must not use those as user-defined operators (we would skip numeric promotion).
return EmptyList.Instance;
}
- // C# 4.0 spec: §7.3.5 Candidate user-defined operators
+ // C# spec (draft-v11): §12.4.6 Candidate user-defined operators
var operators = type.GetMethods(m => m.IsOperator && m.Name == operatorName).ToList();
LiftUserDefinedOperators(operators);
return operators;
@@ -1396,7 +1396,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
public ResolveResult ResolveCast(IType targetType, ResolveResult expression)
{
- // C# 4.0 spec: §7.7.6 Cast expressions
+ // C# spec (draft-v11): §12.9.8 Cast expressions
Conversion c = conversions.ExplicitConversion(expression, targetType);
if (expression.IsCompileTimeConstant && !c.IsUserDefined)
{
diff --git a/ICSharpCode.Decompiler/CSharp/Resolver/OverloadResolution.cs b/ICSharpCode.Decompiler/CSharp/Resolver/OverloadResolution.cs
index 8e77d3133..53d972467 100644
--- a/ICSharpCode.Decompiler/CSharp/Resolver/OverloadResolution.cs
+++ b/ICSharpCode.Decompiler/CSharp/Resolver/OverloadResolution.cs
@@ -29,7 +29,7 @@ using ICSharpCode.Decompiler.Util;
namespace ICSharpCode.Decompiler.CSharp.Resolver
{
///
- /// C# overload resolution (C# 4.0 spec: §7.5).
+ /// C# overload resolution (C# spec draft-v11: §12.6.4).
///
public class OverloadResolution
{
@@ -390,8 +390,8 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
#region MapCorrespondingParameters
void MapCorrespondingParameters(Candidate candidate)
{
- // C# 4.0 spec: §7.5.1.1 Corresponding parameters
- // Updated for C# 7.2 non-trailing named arguments
+ // C# spec (draft-v11): §12.6.2.2 Corresponding parameters
+ // (includes the non-trailing named arguments rule from C# 7.2)
candidate.ArgumentToParameterMap = new int[arguments.Length];
bool hasPositionalArgument = false;
// go backwards, so that hasPositionalArgument tells us whether there
diff --git a/ICSharpCode.Decompiler/CSharp/Resolver/TypeInference.cs b/ICSharpCode.Decompiler/CSharp/Resolver/TypeInference.cs
index f90d45200..a46a0478e 100644
--- a/ICSharpCode.Decompiler/CSharp/Resolver/TypeInference.cs
+++ b/ICSharpCode.Decompiler/CSharp/Resolver/TypeInference.cs
@@ -46,7 +46,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
}
///
- /// Implements C# 4.0 Type Inference (§7.5.2).
+ /// Implements C# type inference (C# spec draft-v11: §12.6.3).
///
public sealed class TypeInference
{
@@ -318,7 +318,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
bool PhaseTwo()
{
- // C# 4.0 spec: §7.5.2.2 The second phase
+ // C# spec (draft-v11): §12.6.3.3 The second phase
Log.WriteLine("Phase Two");
// All unfixed type variables Xi which do not depend on any Xj are fixed.
List typeParametersToFix = new List();
@@ -373,30 +373,30 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
}
else
{
- // Otherwise, for all arguments ei with corresponding parameter type Ti
+ // Otherwise, for all arguments ei with corresponding parameter type Ti
for (int i = 0; i < arguments.Length; i++)
{
ResolveResult Ei = arguments[i];
IType Ti = parameterTypes[i];
- // where the output types (§7.4.2.4) contain unfixed type variables Xj
- // but the input types (§7.4.2.3) do not
+ // where the output types (§12.6.3.5) contain unfixed type variables Xj
+ // but the input types (§12.6.3.4) do not
if (OutputTypeContainsUnfixed(Ei, Ti) && !InputTypesContainsUnfixed(Ei, Ti))
{
- // an output type inference (§7.4.2.6) is made for ei with type Ti.
+ // an output type inference (§12.6.3.8) is made for ei with type Ti.
Log.WriteLine("MakeOutputTypeInference for argument #" + i);
MakeOutputTypeInference(Ei, Ti);
}
}
- // Then the second phase is repeated.
+ // Then the second phase is repeated.
return PhaseTwo();
}
}
#endregion
- #region Input Types / Output Types (§7.5.2.3 + §7.5.2.4)
+ #region Input Types / Output Types (§12.6.3.4 + §12.6.3.5)
IType[] InputTypes(ResolveResult e, IType t)
{
- // C# 4.0 spec: §7.5.2.3 Input types
+ // C# spec (draft-v11): §12.6.3.4 Input types
LambdaResolveResult lrr = e as LambdaResolveResult;
if (lrr != null && lrr.IsImplicitlyTyped || e is MethodGroupResolveResult)
{
@@ -416,7 +416,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
IType[] OutputTypes(ResolveResult e, IType t)
{
- // C# 4.0 spec: §7.5.2.4 Output types
+ // C# spec (draft-v11): §12.6.3.5 Output types
LambdaResolveResult lrr = e as LambdaResolveResult;
if (lrr != null || e is MethodGroupResolveResult)
{
@@ -465,8 +465,8 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
}
#endregion
- #region DependsOn (§7.5.2.5)
- // C# 4.0 spec: §7.5.2.5 Dependance
+ #region DependsOn (§12.6.3.6)
+ // C# spec (draft-v11): §12.6.3.6 Dependence
void CalculateDependencyMatrix()
{
@@ -522,8 +522,8 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
void MakeOutputTypeInference(ResolveResult e, IType t)
{
Log.WriteLine(" MakeOutputTypeInference from " + e + " to " + t);
- // If E is an anonymous function with inferred return type U (§7.5.2.12) and T is a delegate type or expression
- // tree type with return type Tb, then a lower-bound inference (§7.5.2.9) is made from U to Tb.
+ // If E is an anonymous function with inferred return type U (§12.6.3.14) and T is a delegate type or expression
+ // tree type with return type Tb, then a lower-bound inference (§12.6.3.11) is made from U to Tb.
LambdaResolveResult lrr = e as LambdaResolveResult;
if (lrr != null)
{
@@ -610,10 +610,10 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
}
#endregion
- #region MakeExplicitParameterTypeInference (§7.5.2.7)
+ #region MakeExplicitParameterTypeInference (§12.6.3.9)
void MakeExplicitParameterTypeInference(LambdaResolveResult e, IType t)
{
- // C# 4.0 spec: §7.5.2.7 Explicit parameter type inferences
+ // C# spec (draft-v11): §12.6.3.9 Explicit parameter type inferences
if (e.IsImplicitlyTyped || !e.HasParameterList)
return;
Log.WriteLine(" MakeExplicitParameterTypeInference from " + e + " to " + t);
@@ -728,10 +728,10 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
}
#endregion
- #region MakeLowerBoundInference (§7.5.2.9)
+ #region MakeLowerBoundInference (§12.6.3.11)
///
/// Make lower bound inference from U to V.
- /// C# 4.0 spec: §7.5.2.9 Lower-bound inferences
+ /// C# spec (draft-v11): §12.6.3.11 Lower-bound inferences
///
void MakeLowerBoundInference(IType U, IType V)
{
@@ -961,7 +961,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
}
#endregion
- #region Fixing (§7.5.2.11)
+ #region Fixing (§12.6.3.13)
bool Fix(TP tp)
{
Log.WriteLine(" Trying to fix " + tp);
@@ -996,7 +996,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
#region Finding the best common type of a set of expresssions
///
- /// Gets the best common type (C# 4.0 spec: §7.5.2.14) of a set of expressions.
+ /// Gets the best common type (C# spec draft-v11: §12.6.3.17) of a set of expressions.
///
public IType GetBestCommonType(IList expressions, out bool success)
{
@@ -1071,7 +1071,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
Log.WriteCollection("FindTypesInBound, LowerBounds=", lowerBounds);
Log.WriteCollection("FindTypesInBound, UpperBounds=", upperBounds);
- // First try the Fixing algorithm from the C# spec (§7.5.2.11)
+ // First try the Fixing algorithm from the C# spec (§12.6.3.13)
List candidateTypes = lowerBounds.Union(upperBounds)
.Where(c => lowerBounds.All(b => conversions.ImplicitConversion(b, c).IsValid))
.Where(c => upperBounds.All(b => conversions.ImplicitConversion(c, b).IsValid))
@@ -1079,9 +1079,8 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
Log.WriteCollection("FindTypesInBound, Candidates=", candidateTypes);
- // According to the C# specification, we need to pick the most specific
- // of the candidate types. (the type which has conversions to all others)
- // However, csc actually seems to choose the least specific.
+ // C# spec (draft-v11) §12.6.3.13: the result is the unique candidate type
+ // to which there is an implicit conversion from all the other candidate types.
candidateTypes = candidateTypes.Where(
c => candidateTypes.All(o => conversions.ImplicitConversion(o, c).IsValid)
).ToList();