Browse Source

Update resolver spec references to current C# standard numbering

The resolver comments cited section numbers from the C# 4.0 spec (and a
few from C# 9.0 drafts), which no longer match the published ECMA-334
standard. Renumber them against dotnet/csharpstandard draft-v11; every
reference was checked against the actual section headings. The old
'better conversion from type' subclause (7.5.3.4) no longer exists as
such and its rules live in 12.6.4.5-12.6.4.7, so that comment now says
so instead of pointing at a dead number.

Assisted-by: Claude:claude-fable-5:Claude Code
pull/3948/head
Siegfried Pammer 2 months ago committed by Siegfried Pammer
parent
commit
997b50d26b
  1. 39
      ICSharpCode.Decompiler/CSharp/Resolver/CSharpConversions.cs
  2. 2
      ICSharpCode.Decompiler/CSharp/Resolver/CSharpOperators.cs
  3. 14
      ICSharpCode.Decompiler/CSharp/Resolver/CSharpResolver.cs
  4. 6
      ICSharpCode.Decompiler/CSharp/Resolver/OverloadResolution.cs
  5. 47
      ICSharpCode.Decompiler/CSharp/Resolver/TypeInference.cs

39
ICSharpCode.Decompiler/CSharp/Resolver/CSharpConversions.cs

@ -165,7 +165,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -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 @@ -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 @@ -256,7 +256,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
/// <summary>
/// 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)
/// </summary>
public bool IsConstraintConvertible(IType fromType, IType toType)
{
@ -366,7 +366,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -366,7 +366,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
/// </summary>
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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -1414,7 +1414,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
/// <summary>
/// Gets whether a <paramref name="method"/> is compatible with a delegate type.
/// §15.2 Delegate compatibility
/// C# spec (draft-v11): §21.4 Delegate compatibility
/// </summary>
/// <param name="method">The method to test for compatibility</param>
/// <param name="delegateType">The delegate type</param>
@ -1439,7 +1439,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -1439,7 +1439,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
/// If this parameter is true, the first parameter of <paramref name="m"/> will be ignored.</param>
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 @@ -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 @@ -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 @@ -1659,7 +1659,8 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
}
/// <summary>
/// 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)
/// </summary>
/// <returns>0 = neither is better; 1 = t1 is better; 2 = t2 is better</returns>
public int BetterConversion(IType s, IType t1, IType t2)

2
ICSharpCode.Decompiler/CSharp/Resolver/CSharpOperators.cs

@ -366,7 +366,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -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 {

14
ICSharpCode.Decompiler/CSharp/Resolver/CSharpResolver.cs

@ -337,7 +337,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -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 @@ -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 @@ -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 @@ -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 @@ -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<IMethod>.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 @@ -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)
{

6
ICSharpCode.Decompiler/CSharp/Resolver/OverloadResolution.cs

@ -29,7 +29,7 @@ using ICSharpCode.Decompiler.Util; @@ -29,7 +29,7 @@ using ICSharpCode.Decompiler.Util;
namespace ICSharpCode.Decompiler.CSharp.Resolver
{
/// <summary>
/// C# overload resolution (C# 4.0 spec: §7.5).
/// C# overload resolution (C# spec draft-v11: §12.6.4).
/// </summary>
public class OverloadResolution
{
@ -390,8 +390,8 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -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

47
ICSharpCode.Decompiler/CSharp/Resolver/TypeInference.cs

@ -46,7 +46,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -46,7 +46,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
}
/// <summary>
/// Implements C# 4.0 Type Inference (§7.5.2).
/// Implements C# type inference (C# spec draft-v11: §12.6.3).
/// </summary>
public sealed class TypeInference
{
@ -318,7 +318,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -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<TP> typeParametersToFix = new List<TP>();
@ -373,30 +373,30 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -728,10 +728,10 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
}
#endregion
#region MakeLowerBoundInference (§7.5.2.9)
#region MakeLowerBoundInference (§12.6.3.11)
/// <summary>
/// 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
/// </summary>
void MakeLowerBoundInference(IType U, IType V)
{
@ -961,7 +961,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -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 @@ -996,7 +996,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
#region Finding the best common type of a set of expresssions
/// <summary>
/// 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.
/// </summary>
public IType GetBestCommonType(IList<ResolveResult> expressions, out bool success)
{
@ -1071,7 +1071,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -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<IType> 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 @@ -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();

Loading…
Cancel
Save