Browse Source

Move ConversionResoleResult to ICSharpCode.NRefactory.Semantics.

Boxing conversion for attribute arguments is now used consistently in C# type system and Cecil-loaded type system.
newNRvisualizers
Daniel Grunwald 14 years ago
parent
commit
942b4f70ef
  1. 1
      ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj
  2. 19
      ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs
  3. 277
      ICSharpCode.NRefactory.CSharp/Resolver/Conversions.cs
  4. 2
      ICSharpCode.NRefactory.CSharp/Resolver/OverloadResolution.cs
  5. 67
      ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs
  6. 6
      ICSharpCode.NRefactory.CSharp/Resolver/TypeInference.cs
  7. 2
      ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/PrimitiveExpressionTests.cs
  8. 4
      ICSharpCode.NRefactory.Tests/CSharp/Resolver/CastTests.cs
  9. 50
      ICSharpCode.NRefactory.Tests/CSharp/Resolver/ConversionsTest.cs
  10. 10
      ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.cs
  11. 2
      ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj
  12. 450
      ICSharpCode.NRefactory/Semantics/Conversion.cs
  13. 3
      ICSharpCode.NRefactory/Semantics/ConversionResolveResult.cs
  14. 6
      ICSharpCode.NRefactory/TypeSystem/CecilLoader.cs
  15. 2
      NRefactory.sln

1
ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj

@ -271,7 +271,6 @@ @@ -271,7 +271,6 @@
<Compile Include="Refactoring\TextReplaceAction.cs" />
<Compile Include="Refactoring\TypeSystemAstBuilder.cs" />
<Compile Include="Resolver\CompositeResolveVisitorNavigator.cs" />
<Compile Include="Resolver\ConversionResolveResult.cs" />
<Compile Include="Resolver\Conversions.cs" />
<Compile Include="Resolver\CSharpAstResolver.cs" />
<Compile Include="Resolver\CSharpInvocationResolveResult.cs" />

19
ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs

@ -1157,7 +1157,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1157,7 +1157,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
bool TryConvert(ref ResolveResult rr, IType targetType)
{
Conversion c = conversions.ImplicitConversion(rr, targetType);
if (c) {
if (c.IsValid) {
rr = Convert(rr, targetType, c);
return true;
} else {
@ -1208,11 +1208,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1208,11 +1208,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
}
}
Conversion c = conversions.ExplicitConversion(expression, targetType);
if (c) {
return new ConversionResolveResult(targetType, expression, c);
} else {
return new ErrorResolveResult(targetType);
}
return new ConversionResolveResult(targetType, expression, c);
}
internal object CSharpPrimitiveCast(TypeCode targetType, object input)
@ -1348,10 +1344,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1348,10 +1344,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
// look in current type definitions
for (ITypeDefinition t = this.CurrentTypeDefinition; t != null; t = t.DeclaringTypeDefinition) {
if (k == 0) {
// look for type parameter with that name
// Look for type parameter with that name
var typeParameters = t.TypeParameters;
// only look at type parameters defined directly on this type, not at those copied from outer classes
for (int i = (t.DeclaringTypeDefinition != null ? t.DeclaringTypeDefinition.TypeParameterCount : 0); i < typeParameters.Count; i++) {
// Look at all type parameters, including those copied from outer classes,
// so that we can fetch the version with the correct owner.
for (int i = 0; i < typeParameters.Count; i++) {
if (typeParameters[i].Name == identifier)
return new TypeResolveResult(typeParameters[i]);
}
@ -1981,11 +1978,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1981,11 +1978,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
// The operator is valid:
// a) if there's a conversion in one direction but not the other
// b) if there are conversions in both directions, and the types are equivalent
if (t2f && !f2t) {
if (t2f.IsValid && !f2t.IsValid) {
resultType = falseExpression.Type;
isValid = true;
trueExpression = Convert(trueExpression, resultType, t2f);
} else if (f2t && !t2f) {
} else if (f2t.IsValid && !t2f.IsValid) {
resultType = trueExpression.Type;
isValid = true;
falseExpression = Convert(falseExpression, resultType, f2t);

277
ICSharpCode.NRefactory.CSharp/Resolver/Conversions.cs

@ -27,217 +27,6 @@ using ICSharpCode.NRefactory.Utils; @@ -27,217 +27,6 @@ using ICSharpCode.NRefactory.Utils;
namespace ICSharpCode.NRefactory.CSharp.Resolver
{
/// <summary>
/// Holds information about a conversion between two types.
/// </summary>
public struct Conversion : IEquatable<Conversion>
{
public static readonly Conversion None = default(Conversion);
public static readonly Conversion IdentityConversion = new Conversion(1);
public static readonly Conversion ImplicitNumericConversion = new Conversion(2);
public static readonly Conversion ImplicitEnumerationConversion = new Conversion(3);
public static readonly Conversion ImplicitNullableConversion = new Conversion(4);
public static readonly Conversion NullLiteralConversion = new Conversion(5);
public static readonly Conversion ImplicitReferenceConversion = new Conversion(6);
public static readonly Conversion BoxingConversion = new Conversion(7);
public static readonly Conversion ImplicitDynamicConversion = new Conversion(8);
public static readonly Conversion ImplicitConstantExpressionConversion = new Conversion(9);
const int userDefinedImplicitConversionKind = 10;
const int liftedUserDefinedImplicitConversionKind = 11;
public static readonly Conversion ImplicitPointerConversion = new Conversion(12);
const int anonymousFunctionConversionKind = 13;
const int methodGroupConversionKind = 14;
public static readonly Conversion ExplicitNumericConversion = new Conversion(15);
public static readonly Conversion ExplicitEnumerationConversion = new Conversion(16);
public static readonly Conversion ExplicitNullableConversion = new Conversion(17);
public static readonly Conversion ExplicitReferenceConversion = new Conversion(18);
public static readonly Conversion UnboxingConversion = new Conversion(19);
public static readonly Conversion ExplicitDynamicConversion = new Conversion(20);
public static readonly Conversion ExplicitPointerConversion = new Conversion(21);
const int userDefinedExplicitConversionKind = 22;
const int liftedUserDefinedExplicitConversionKind = 23;
const int lastImplicitConversion = methodGroupConversionKind;
static readonly string[] conversionNames = {
"None",
"Identity conversion",
"Implicit numeric conversion",
"Implicit enumeration conversion",
"Implicit nullable conversion",
"Null literal conversion",
"Implicit reference conversion",
"Boxing conversion",
"Implicit dynamic conversion",
"Implicit constant expression conversion",
"User-defined implicit conversion",
"Lifted user-defined implicit conversion",
"Implicit pointer conversion",
"Anonymous function conversion",
"Method group conversion",
"Explicit numeric conversion",
"Explicit enumeration conversion",
"Explicit nullable conversion",
"Explicit reference conversion",
"Unboxing conversion",
"Explicit dynamic conversion",
"Explicit pointer conversion",
"User-defined explicit conversion",
"Lifted user-defined explicit conversion"
};
public static Conversion UserDefinedImplicitConversion(IMethod operatorMethod, bool isLifted)
{
if (operatorMethod == null)
throw new ArgumentNullException("operatorMethod");
return new Conversion(isLifted ? liftedUserDefinedImplicitConversionKind : userDefinedImplicitConversionKind, operatorMethod);
}
public static Conversion UserDefinedExplicitConversion(IMethod operatorMethod, bool isLifted)
{
if (operatorMethod == null)
throw new ArgumentNullException("operatorMethod");
return new Conversion(isLifted ? liftedUserDefinedExplicitConversionKind : userDefinedExplicitConversionKind, operatorMethod);
}
public static Conversion MethodGroupConversion(IMethod chosenMethod)
{
if (chosenMethod == null)
throw new ArgumentNullException("chosenMethod");
return new Conversion(methodGroupConversionKind, chosenMethod);
}
/// <summary>
/// Creates a new anonymous function conversion.
/// </summary>
/// <param name="data">Used by ResolveVisitor to pass the LambdaTypeHypothesis.</param>
public static Conversion AnonymousFunctionConversion(object data)
{
return new Conversion(anonymousFunctionConversionKind, data);
}
readonly int kind;
internal readonly object data;
public Conversion(int kind, object data = null)
{
this.kind = kind;
this.data = data;
}
/// <summary>
/// Gets whether this conversion is an implicit conversion.
/// </summary>
public bool IsImplicitConversion {
get { return kind > 0 && kind <= lastImplicitConversion; }
}
/// <summary>
/// Gets whether this conversion is an explicit conversion.
/// </summary>
public bool IsExplicitConversion {
get { return kind > lastImplicitConversion; }
}
/// <summary>
/// Gets whether this conversion is user-defined.
/// </summary>
public bool IsUserDefined {
get {
switch (kind) {
case userDefinedImplicitConversionKind:
case liftedUserDefinedImplicitConversionKind:
case userDefinedExplicitConversionKind:
case liftedUserDefinedExplicitConversionKind:
return true;
default:
return false;
}
}
}
/// <summary>
/// Gets whether this conversion is a lifted version of a user-defined conversion operator.
/// </summary>
/// <remarks>Lifted versions of builtin conversion operators are classified as nullable-conversion</remarks>
public bool IsLifted {
get {
return kind == liftedUserDefinedImplicitConversionKind || kind == liftedUserDefinedExplicitConversionKind;
}
}
/// <summary>
/// Gets whether this conversion is a method group conversion.
/// </summary>
public bool IsMethodGroupConversion {
get { return kind == methodGroupConversionKind; }
}
/// <summary>
/// Gets whether this conversion is an anonymous function conversion.
/// </summary>
public bool IsAnonymousFunctionConversion {
get { return kind == anonymousFunctionConversionKind; }
}
/// <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 IMethod Method {
get { return data as IMethod; }
}
public override string ToString()
{
string name = conversionNames[kind];
if (data != null)
return name + " (" + data + ")";
else
return name;
}
public bool IsValid {
get { return kind > 0; }
}
public static implicit operator bool(Conversion conversion)
{
return conversion.kind > 0;
}
#region Equals and GetHashCode implementation
public override int GetHashCode()
{
if (data != null)
return kind ^ data.GetHashCode();
else
return kind;
}
public override bool Equals(object obj)
{
return (obj is Conversion) && Equals((Conversion)obj);
}
public bool Equals(Conversion other)
{
return this.kind == other.kind && object.Equals(this.data, other.data);
}
public static bool operator ==(Conversion lhs, Conversion rhs)
{
return lhs.Equals(rhs);
}
public static bool operator !=(Conversion lhs, Conversion rhs)
{
return !lhs.Equals(rhs);
}
#endregion
}
/// <summary>
/// Contains logic that determines whether an implicit conversion exists between two types.
/// </summary>
@ -311,17 +100,17 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -311,17 +100,17 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
{
if (resolveResult == null)
throw new ArgumentNullException("resolveResult");
Conversion c;
if (resolveResult.IsCompileTimeConstant) {
if (ImplicitEnumerationConversion(resolveResult, toType))
return Conversion.ImplicitEnumerationConversion;
c = ImplicitEnumerationConversion(resolveResult, toType);
if (c.IsValid) return c;
if (ImplicitConstantExpressionConversion(resolveResult, toType))
return Conversion.ImplicitConstantExpressionConversion;
}
Conversion c;
c = ImplicitConversion(resolveResult.Type, toType);
if (c) return c;
if (c.IsValid) return c;
c = AnonymousFunctionConversion(resolveResult, toType);
if (c) return c;
if (c.IsValid) return c;
c = MethodGroupConversion(resolveResult, toType);
return c;
}
@ -340,7 +129,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -340,7 +129,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
// C# 4.0 spec: §6.1
c = StandardImplicitConversion(fromType, toType);
if (!c) {
if (!c.IsValid) {
c = UserDefinedImplicitConversion(fromType, toType);
}
implicitConversionCache[pair] = c;
@ -358,8 +147,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -358,8 +147,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return Conversion.IdentityConversion;
if (ImplicitNumericConversion(fromType, toType))
return Conversion.ImplicitNumericConversion;
if (ImplicitNullableConversion(fromType, toType))
return Conversion.ImplicitNullableConversion;
Conversion c = ImplicitNullableConversion(fromType, toType);
if (c.IsValid)
return c;
if (NullLiteralConversion(fromType, toType))
return Conversion.NullLiteralConversion;
if (ImplicitReferenceConversion(fromType, toType))
@ -412,7 +202,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -412,7 +202,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
if (resolveResult.Type.Kind == TypeKind.Dynamic)
return Conversion.ExplicitDynamicConversion;
Conversion c = ImplicitConversion(resolveResult, toType);
if (c)
if (c.IsValid)
return c;
else
return ExplicitConversionImpl(resolveResult.Type, toType);
@ -428,7 +218,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -428,7 +218,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
if (fromType.Kind == TypeKind.Dynamic)
return Conversion.ExplicitDynamicConversion;
Conversion c = ImplicitConversion(fromType, toType);
if (c)
if (c.IsValid)
return c;
else
return ExplicitConversionImpl(fromType, toType);
@ -441,9 +231,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -441,9 +231,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
if (AnyNumericConversion(fromType, toType))
return Conversion.ExplicitNumericConversion;
if (ExplicitEnumerationConversion(fromType, toType))
return Conversion.ExplicitEnumerationConversion;
if (ExplicitNullableConversion(fromType, toType))
return Conversion.ExplicitNullableConversion;
return Conversion.EnumerationConversion(false, false);
Conversion c = ExplicitNullableConversion(fromType, toType);
if (c.IsValid)
return c;
if (ExplicitReferenceConversion(fromType, toType))
return Conversion.ExplicitReferenceConversion;
if (UnboxingConversion(fromType, toType))
@ -536,15 +327,17 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -536,15 +327,17 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
#endregion
#region Enumeration Conversions
bool ImplicitEnumerationConversion(ResolveResult rr, IType toType)
Conversion ImplicitEnumerationConversion(ResolveResult rr, IType toType)
{
// C# 4.0 spec: §6.1.3
Debug.Assert(rr.IsCompileTimeConstant);
TypeCode constantType = ReflectionHelper.GetTypeCode(rr.Type);
if (constantType >= TypeCode.SByte && constantType <= TypeCode.Decimal && Convert.ToDouble(rr.ConstantValue) == 0) {
return NullableType.GetUnderlyingType(toType).Kind == TypeKind.Enum;
if (NullableType.GetUnderlyingType(toType).Kind == TypeKind.Enum) {
return Conversion.EnumerationConversion(true, NullableType.IsNullable(toType));
}
}
return false;
return Conversion.None;
}
bool ExplicitEnumerationConversion(IType fromType, IType toType)
@ -560,28 +353,34 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -560,28 +353,34 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
#endregion
#region Nullable Conversions
bool ImplicitNullableConversion(IType fromType, IType toType)
Conversion ImplicitNullableConversion(IType fromType, IType toType)
{
// C# 4.0 spec: §6.1.4
if (NullableType.IsNullable(toType)) {
IType t = NullableType.GetUnderlyingType(toType);
IType s = NullableType.GetUnderlyingType(fromType); // might or might not be nullable
return IdentityConversion(s, t) || ImplicitNumericConversion(s, t);
} else {
return false;
if (IdentityConversion(s, t))
return Conversion.ImplicitNullableConversion;
if (ImplicitNumericConversion(s, t))
return Conversion.ImplicitLiftedNumericConversion;
}
return Conversion.None;
}
bool ExplicitNullableConversion(IType fromType, IType toType)
Conversion ExplicitNullableConversion(IType fromType, IType toType)
{
// C# 4.0 spec: §6.1.4
if (NullableType.IsNullable(toType) || NullableType.IsNullable(fromType)) {
IType t = NullableType.GetUnderlyingType(toType);
IType s = NullableType.GetUnderlyingType(fromType);
return IdentityConversion(s, t) || AnyNumericConversion(s, t) || ExplicitEnumerationConversion(s, t);
} else {
return false;
if (IdentityConversion(s, t))
return Conversion.ExplicitNullableConversion;
if (AnyNumericConversion(s, t))
return Conversion.ExplicitLiftedNumericConversion;
if (ExplicitEnumerationConversion(s, t))
return Conversion.EnumerationConversion(false, true);
}
return Conversion.None;
}
#endregion
@ -823,13 +622,13 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -823,13 +622,13 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
/// </summary>
bool IsEncompassedBy(IType a, IType b)
{
return a.Kind != TypeKind.Interface && b.Kind != TypeKind.Interface && StandardImplicitConversion(a, b);
return a.Kind != TypeKind.Interface && b.Kind != TypeKind.Interface && StandardImplicitConversion(a, b).IsValid;
}
bool IsEncompassingOrEncompassedBy(IType a, IType b)
{
return a.Kind != TypeKind.Interface && b.Kind != TypeKind.Interface
&& (StandardImplicitConversion(a, b) || StandardImplicitConversion(b, a));
&& (StandardImplicitConversion(a, b).IsValid || StandardImplicitConversion(b, a).IsValid);
}
Conversion UserDefinedImplicitConversion(IType fromType, IType toType)
@ -1102,8 +901,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1102,8 +901,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
/// <returns>0 = neither is better; 1 = t1 is better; 2 = t2 is better</returns>
int BetterConversionTarget(IType t1, IType t2)
{
bool t1To2 = ImplicitConversion(t1, t2);
bool t2To1 = ImplicitConversion(t2, t1);
bool t1To2 = ImplicitConversion(t1, t2).IsValid;
bool t2To1 = ImplicitConversion(t2, t1).IsValid;
if (t1To2 && !t2To1)
return 1;
if (t2To1 && !t1To2)

2
ICSharpCode.NRefactory.CSharp/Resolver/OverloadResolution.cs

@ -503,7 +503,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -503,7 +503,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
if (!(c == Conversion.IdentityConversion || c == Conversion.ImplicitReferenceConversion || c == Conversion.BoxingConversion))
candidate.AddError(OverloadResolutionErrors.ArgumentTypeMismatch);
} else {
if (!c)
if (!c.IsValid)
candidate.AddError(OverloadResolutionErrors.ArgumentTypeMismatch);
}
}

67
ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs

@ -245,13 +245,13 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -245,13 +245,13 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
#endregion
#region Process Conversions
sealed class AnonymousFunctionConversionData
sealed class AnonymousFunctionConversion : Conversion
{
public readonly IType ReturnType;
public readonly ExplicitlyTypedLambda ExplicitlyTypedLambda;
public readonly LambdaTypeHypothesis Hypothesis;
public AnonymousFunctionConversionData(IType returnType, LambdaTypeHypothesis hypothesis)
public AnonymousFunctionConversion(IType returnType, LambdaTypeHypothesis hypothesis)
{
if (returnType == null)
throw new ArgumentNullException("returnType");
@ -259,13 +259,21 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -259,13 +259,21 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
this.Hypothesis = hypothesis;
}
public AnonymousFunctionConversionData(IType returnType, ExplicitlyTypedLambda explicitlyTypedLambda)
public AnonymousFunctionConversion(IType returnType, ExplicitlyTypedLambda explicitlyTypedLambda)
{
if (returnType == null)
throw new ArgumentNullException("returnType");
this.ReturnType = returnType;
this.ExplicitlyTypedLambda = explicitlyTypedLambda;
}
public override bool IsImplicit {
get { return true; }
}
public override bool IsAnonymousFunctionConversion {
get { return true; }
}
}
/// <summary>
@ -275,19 +283,16 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -275,19 +283,16 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
{
if (expr == null || expr.IsNull)
return;
if (conversion.IsAnonymousFunctionConversion) {
AnonymousFunctionConversion afc = conversion as AnonymousFunctionConversion;
if (afc != null) {
Log.WriteLine("Processing conversion of anonymous function to " + targetType + "...");
AnonymousFunctionConversionData data = conversion.data as AnonymousFunctionConversionData;
if (data != null) {
Log.Indent();
if (data.Hypothesis != null)
data.Hypothesis.MergeInto(this, data.ReturnType);
if (data.ExplicitlyTypedLambda != null)
data.ExplicitlyTypedLambda.ApplyReturnType(this, data.ReturnType);
Log.Unindent();
} else {
Log.WriteLine(" Data not found.");
}
Log.Indent();
if (afc.Hypothesis != null)
afc.Hypothesis.MergeInto(this, afc.ReturnType);
if (afc.ExplicitlyTypedLambda != null)
afc.ExplicitlyTypedLambda.ApplyReturnType(this, afc.ReturnType);
Log.Unindent();
}
if (conversion != Conversion.IdentityConversion)
navigator.ProcessConversion(expr, rr, conversion, targetType);
@ -1819,7 +1824,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1819,7 +1824,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
Log.Unindent();
Log.WriteLine("{0} is {1} for return-type {2}", this, valid ? "valid" : "invalid", returnType);
if (valid) {
return Conversion.AnonymousFunctionConversion(new AnonymousFunctionConversionData(returnType, this));
return new AnonymousFunctionConversion(returnType, this);
} else {
return Conversion.None;
}
@ -1971,7 +1976,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1971,7 +1976,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
var hypothesis = GetHypothesis(parameterTypes);
Conversion c = hypothesis.IsValid(returnType, conversions);
Log.Unindent();
Log.WriteLine("{0} is {1} for return-type {2}", hypothesis, c ? "valid" : "invalid", returnType);
Log.WriteLine("{0} is {1} for return-type {2}", hypothesis, c.IsValid ? "valid" : "invalid", returnType);
return c;
}
@ -2131,7 +2136,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -2131,7 +2136,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
public Conversion IsValid(IType returnType, Conversions conversions)
{
if (success && IsValidLambda(isValidAsVoidMethod, lambda.IsAsync, returnValues, returnType, conversions)) {
return Conversion.AnonymousFunctionConversion(new AnonymousFunctionConversionData(returnType, this));
return new AnonymousFunctionConversion(returnType, this);
} else {
return Conversion.None;
}
@ -2341,7 +2346,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -2341,7 +2346,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
returnType = ((ParameterizedType)returnType).GetTypeArgument(0);
}
foreach (ResolveResult returnRR in returnValues) {
if (!conversions.ImplicitConversion(returnRR, returnType))
if (!conversions.ImplicitConversion(returnRR, returnType).IsValid)
return false;
}
return true;
@ -3182,6 +3187,24 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -3182,6 +3187,24 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return GetElementTypeFromIEnumerable(type, resolver.Compilation, false);
}
sealed class QueryExpressionLambdaConversion : Conversion
{
internal readonly IType[] ParameterTypes;
public QueryExpressionLambdaConversion(IType[] parameterTypes)
{
this.ParameterTypes = parameterTypes;
}
public override bool IsImplicit {
get { return true; }
}
public override bool IsAnonymousFunctionConversion {
get { return true; }
}
}
sealed class QueryExpressionLambda : LambdaResolveResult
{
readonly IParameter[] parameters;
@ -3206,7 +3229,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -3206,7 +3229,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
{
if (parameterTypes.Length == parameters.Length) {
this.inferredParameterTypes = parameterTypes;
return Conversion.AnonymousFunctionConversion(parameterTypes);
return new QueryExpressionLambdaConversion(parameterTypes);
} else {
return Conversion.None;
}
@ -3456,8 +3479,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -3456,8 +3479,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
IType[] inferredParameterTypes = null;
if (invocationRR != null && invocationRR.Arguments.Count > 0) {
ConversionResolveResult crr = invocationRR.Arguments[invocationRR.Arguments.Count - 1] as ConversionResolveResult;
if (crr != null && crr.Conversion.IsAnonymousFunctionConversion) {
inferredParameterTypes = crr.Conversion.data as IType[];
if (crr != null && crr.Conversion is QueryExpressionLambdaConversion) {
inferredParameterTypes = ((QueryExpressionLambdaConversion)crr.Conversion).ParameterTypes;
}
}
if (inferredParameterTypes == null)

6
ICSharpCode.NRefactory.CSharp/Resolver/TypeInference.cs

@ -854,12 +854,12 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -854,12 +854,12 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
// First try the Fixing algorithm from the C# spec (§7.5.2.11)
List<IType> candidateTypes = lowerBounds.Union(upperBounds)
.Where(c => lowerBounds.All(b => conversions.ImplicitConversion(b, c)))
.Where(c => upperBounds.All(b => conversions.ImplicitConversion(c, b)))
.Where(c => lowerBounds.All(b => conversions.ImplicitConversion(b, c).IsValid))
.Where(c => upperBounds.All(b => conversions.ImplicitConversion(c, b).IsValid))
.ToList(); // evaluate the query only once
candidateTypes = candidateTypes.Where(
c => candidateTypes.All(o => conversions.ImplicitConversion(c, o))
c => candidateTypes.All(o => conversions.ImplicitConversion(c, o).IsValid)
).ToList();
// If the specified algorithm produces a single candidate, we return
// that candidate.

2
ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/PrimitiveExpressionTests.cs

@ -72,7 +72,7 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.Expression @@ -72,7 +72,7 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.Expression
{
ParseUtilCSharp.AssertExpression(
"-2147483648",
new UnaryOperatorExpression(UnaryOperatorType.Minus, new PrimitiveExpression(-2147483648)));
new UnaryOperatorExpression(UnaryOperatorType.Minus, new PrimitiveExpression(2147483648)));
}
[Test]

4
ICSharpCode.NRefactory.Tests/CSharp/Resolver/CastTests.cs

@ -63,8 +63,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -63,8 +63,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
TestCast(typeof(int), MakeResult(typeof(int?)), Conversion.ExplicitNullableConversion);
TestCast(typeof(int?), MakeResult(typeof(int)), Conversion.ImplicitNullableConversion);
TestCast(typeof(int?), MakeResult(typeof(long?)), Conversion.ExplicitNullableConversion);
TestCast(typeof(long?), MakeResult(typeof(int?)), Conversion.ImplicitNullableConversion);
TestCast(typeof(int?), MakeResult(typeof(long?)), Conversion.ExplicitLiftedNumericConversion);
TestCast(typeof(long?), MakeResult(typeof(int?)), Conversion.ImplicitLiftedNumericConversion);
}
[Test]

50
ICSharpCode.NRefactory.Tests/CSharp/Resolver/ConversionsTest.cs

@ -110,27 +110,27 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -110,27 +110,27 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
[Test]
public void NullableConversions()
{
Assert.AreEqual(C.ImplicitNullableConversion, ImplicitConversion(typeof(char), typeof(ushort?)));
Assert.AreEqual(C.None, ImplicitConversion(typeof(byte), typeof(char?)));
Assert.AreEqual(C.ImplicitNullableConversion, ImplicitConversion(typeof(int), typeof(long?)));
Assert.AreEqual(C.None, ImplicitConversion(typeof(long), typeof(int?)));
Assert.AreEqual(C.ImplicitNullableConversion, ImplicitConversion(typeof(int), typeof(float?)));
Assert.AreEqual(C.None , ImplicitConversion(typeof(bool), typeof(float?)));
Assert.AreEqual(C.ImplicitNullableConversion, ImplicitConversion(typeof(float), typeof(double?)));
Assert.AreEqual(C.None, ImplicitConversion(typeof(float), typeof(decimal?)));
Assert.AreEqual(C.ImplicitLiftedNumericConversion, ImplicitConversion(typeof(char), typeof(ushort?)));
Assert.AreEqual(C.None, ImplicitConversion(typeof(byte), typeof(char?)));
Assert.AreEqual(C.ImplicitLiftedNumericConversion, ImplicitConversion(typeof(int), typeof(long?)));
Assert.AreEqual(C.None, ImplicitConversion(typeof(long), typeof(int?)));
Assert.AreEqual(C.ImplicitLiftedNumericConversion, ImplicitConversion(typeof(int), typeof(float?)));
Assert.AreEqual(C.None , ImplicitConversion(typeof(bool), typeof(float?)));
Assert.AreEqual(C.ImplicitLiftedNumericConversion, ImplicitConversion(typeof(float), typeof(double?)));
Assert.AreEqual(C.None, ImplicitConversion(typeof(float), typeof(decimal?)));
}
[Test]
public void NullableConversions2()
{
Assert.AreEqual(C.ImplicitNullableConversion, ImplicitConversion(typeof(char?), typeof(ushort?)));
Assert.AreEqual(C.None, ImplicitConversion(typeof(byte?), typeof(char?)));
Assert.AreEqual(C.ImplicitNullableConversion, ImplicitConversion(typeof(int?), typeof(long?)));
Assert.AreEqual(C.None, ImplicitConversion(typeof(long?), typeof(int?)));
Assert.AreEqual(C.ImplicitNullableConversion, ImplicitConversion(typeof(int?), typeof(float?)));
Assert.AreEqual(C.None, ImplicitConversion(typeof(bool?), typeof(float?)));
Assert.AreEqual(C.ImplicitNullableConversion, ImplicitConversion(typeof(float?), typeof(double?)));
Assert.AreEqual(C.None, ImplicitConversion(typeof(float?), typeof(decimal?)));
Assert.AreEqual(C.ImplicitLiftedNumericConversion, ImplicitConversion(typeof(char?), typeof(ushort?)));
Assert.AreEqual(C.None, ImplicitConversion(typeof(byte?), typeof(char?)));
Assert.AreEqual(C.ImplicitLiftedNumericConversion, ImplicitConversion(typeof(int?), typeof(long?)));
Assert.AreEqual(C.None, ImplicitConversion(typeof(long?), typeof(int?)));
Assert.AreEqual(C.ImplicitLiftedNumericConversion, ImplicitConversion(typeof(int?), typeof(float?)));
Assert.AreEqual(C.None, ImplicitConversion(typeof(bool?), typeof(float?)));
Assert.AreEqual(C.ImplicitLiftedNumericConversion, ImplicitConversion(typeof(float?), typeof(double?)));
Assert.AreEqual(C.None, ImplicitConversion(typeof(float?), typeof(decimal?)));
}
[Test]
@ -335,7 +335,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -335,7 +335,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
public void UserDefinedImplicitConversion()
{
Conversion c = ImplicitConversion(typeof(DateTime), typeof(DateTimeOffset));
Assert.IsTrue(c.IsImplicitConversion && c.IsUserDefined);
Assert.IsTrue(c.IsImplicit && c.IsUserDefined);
Assert.AreEqual("System.DateTimeOffset.op_Implicit", c.Method.FullName);
Assert.AreEqual(C.None, ImplicitConversion(typeof(DateTimeOffset), typeof(DateTime)));
@ -345,19 +345,23 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -345,19 +345,23 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
public void UserDefinedImplicitNullableConversion()
{
// User-defined conversion followed by nullable conversion
Assert.IsTrue(ImplicitConversion(typeof(DateTime), typeof(DateTimeOffset?)));
Conversion c = ImplicitConversion(typeof(DateTime), typeof(DateTimeOffset?));
Assert.IsTrue(c.IsValid && c.IsUserDefined);
Assert.IsFalse(c.IsLifted);
// Lifted user-defined conversion
Assert.IsTrue(ImplicitConversion(typeof(DateTime?), typeof(DateTimeOffset?)));
c = ImplicitConversion(typeof(DateTime?), typeof(DateTimeOffset?));
Assert.IsTrue(c.IsValid && c.IsUserDefined && c.IsLifted);
// User-defined conversion doesn't drop the nullability
Assert.IsFalse(ImplicitConversion(typeof(DateTime?), typeof(DateTimeOffset)));
c = ImplicitConversion(typeof(DateTime?), typeof(DateTimeOffset));
Assert.IsFalse(c.IsValid);
}
Conversion IntegerLiteralConversion(object value, Type to)
bool IntegerLiteralConversion(object value, Type to)
{
IType fromType = compilation.FindType(value.GetType());
ConstantResolveResult crr = new ConstantResolveResult(fromType, value);
IType to2 = compilation.FindType(to);
return conversions.ImplicitConversion(crr, to2);
return conversions.ImplicitConversion(crr, to2).IsValid;
}
[Test]
@ -506,7 +510,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -506,7 +510,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
IType type1 = new ParameterizedType(resolvedB, new[] { compilation.FindType(KnownTypeCode.Double) });
IType type2 = new ParameterizedType(resolvedA, new [] { new ParameterizedType(resolvedB, new[] { compilation.FindType(KnownTypeCode.String) }) });
Assert.IsFalse(conversions.ImplicitConversion(type1, type2));
Assert.IsFalse(conversions.ImplicitConversion(type1, type2).IsValid);
}
}
}

10
ICSharpCode.NRefactory.Tests/TypeSystem/TypeSystemTests.cs

@ -571,7 +571,7 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -571,7 +571,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
return crr.Input;
}
[Test, Ignore("CecilLoader does not create ConversionResolveResult")]
[Test]
public void ParamsAttribute_Integer()
{
ResolveResult rr = Unbox(GetParamsAttributeArgument(0));
@ -579,7 +579,7 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -579,7 +579,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
Assert.AreEqual(1, rr.ConstantValue);
}
[Test, Ignore("CecilLoader does not create ConversionResolveResult")]
[Test]
public void ParamsAttribute_Enum()
{
ResolveResult rr = Unbox(GetParamsAttributeArgument(1));
@ -587,7 +587,7 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -587,7 +587,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
Assert.AreEqual((int)StringComparison.CurrentCulture, rr.ConstantValue);
}
[Test, Ignore("CecilLoader does not create ConversionResolveResult")]
[Test]
public void ParamsAttribute_NullReference()
{
ResolveResult rr = GetParamsAttributeArgument(2);
@ -596,7 +596,7 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -596,7 +596,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
Assert.IsNull(rr.ConstantValue);
}
[Test, Ignore("CecilLoader does not create ConversionResolveResult")]
[Test]
public void ParamsAttribute_Double()
{
ResolveResult rr = Unbox(GetParamsAttributeArgument(3));
@ -604,7 +604,7 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -604,7 +604,7 @@ namespace ICSharpCode.NRefactory.TypeSystem
Assert.AreEqual(4.0, rr.ConstantValue);
}
[Test, Ignore("CecilLoader does not create ConversionResolveResult")]
[Test]
public void ParamsAttribute_String()
{
ConversionResolveResult rr = (ConversionResolveResult)GetParamsAttributeArgument(4);

2
ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj

@ -87,7 +87,9 @@ @@ -87,7 +87,9 @@
<Compile Include="Semantics\ArrayCreateResolveResult.cs" />
<Compile Include="Semantics\ByReferenceResolveResult.cs" />
<Compile Include="Semantics\ConstantResolveResult.cs" />
<Compile Include="Semantics\ConversionResolveResult.cs" />
<Compile Include="Semantics\ErrorResolveResult.cs" />
<Compile Include="Semantics\Conversion.cs" />
<Compile Include="Semantics\InvocationResolveResult.cs" />
<Compile Include="Semantics\LocalResolveResult.cs" />
<Compile Include="Semantics\MemberResolveResult.cs" />

450
ICSharpCode.NRefactory/Semantics/Conversion.cs

@ -0,0 +1,450 @@ @@ -0,0 +1,450 @@
// Copyright (c) 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 ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.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);
public static Conversion UserDefinedImplicitConversion(IMethod operatorMethod, bool isLifted)
{
if (operatorMethod == null)
throw new ArgumentNullException("operatorMethod");
return new UserDefinedConversion(true, operatorMethod, isLifted);
}
public static Conversion UserDefinedExplicitConversion(IMethod operatorMethod, bool isLifted)
{
if (operatorMethod == null)
throw new ArgumentNullException("operatorMethod");
return new UserDefinedConversion(false, operatorMethod, isLifted);
}
public static Conversion MethodGroupConversion(IMethod chosenMethod)
{
if (chosenMethod == null)
throw new ArgumentNullException("chosenMethod");
return new MethodGroupConv(chosenMethod);
}
#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 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 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";
}
return (isImplicit ? "implicit " : "explicit ") + name + " conversion";
}
}
sealed class UserDefinedConversion : Conversion
{
readonly IMethod method;
readonly bool isLifted;
readonly bool isImplicit;
public UserDefinedConversion(bool isImplicit, IMethod method, bool isLifted)
{
this.method = method;
this.isLifted = isLifted;
this.isImplicit = isImplicit;
}
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 IMethod Method {
get { return method; }
}
public override bool Equals(Conversion other)
{
UserDefinedConversion o = other as UserDefinedConversion;
return o != null && isLifted == o.isLifted && isImplicit == o.isImplicit && method.Equals(o.method);
}
public override int GetHashCode()
{
return unchecked(method.GetHashCode() * (isLifted ? 31 : 27) * (isImplicit ? 71 : 61));
}
public override string ToString()
{
return (isImplicit ? "implicit" : "explicit")
+ (isLifted ? " lifted" : "")
+ "user-defined conversion (" + method + ")";
}
}
sealed class MethodGroupConv : Conversion
{
readonly IMethod method;
public MethodGroupConv(IMethod method)
{
this.method = method;
}
public override bool IsImplicit {
get { return true; }
}
public override bool IsMethodGroupConversion {
get { return true; }
}
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();
}
}
#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; }
}
public virtual bool IsIdentityConversion {
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>
/// 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 an unboxing 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>
/// 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; }
}
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;
}
}
}

3
ICSharpCode.NRefactory.CSharp/Resolver/ConversionResolveResult.cs → ICSharpCode.NRefactory/Semantics/ConversionResolveResult.cs

@ -18,10 +18,9 @@ @@ -18,10 +18,9 @@
using System;
using System.Collections.Generic;
using ICSharpCode.NRefactory.Semantics;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.CSharp.Resolver
namespace ICSharpCode.NRefactory.Semantics
{
public class ConversionResolveResult : ResolveResult
{

6
ICSharpCode.NRefactory/TypeSystem/CecilLoader.cs

@ -1109,7 +1109,11 @@ namespace ICSharpCode.NRefactory.TypeSystem @@ -1109,7 +1109,11 @@ namespace ICSharpCode.NRefactory.TypeSystem
if (typeCode == KnownTypeCode.Object) {
// boxed value type
IType boxedTyped = ReadCustomAttributeFieldOrPropType();
return ReadElem(boxedTyped);
ResolveResult elem = ReadElem(boxedTyped);
if (elem.IsCompileTimeConstant && elem.ConstantValue == null)
return new ConstantResolveResult(elementType, null);
else
return new ConversionResolveResult(elementType, elem, Conversion.BoxingConversion);
} else if (typeCode == KnownTypeCode.Type) {
return new TypeOfResolveResult(underlyingType, ReadType());
} else {

2
NRefactory.sln

@ -1,7 +1,7 @@ @@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010
# SharpDevelop 4.2.0.8278-alpha
# SharpDevelop 4.2.0.8158-alpha
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{DC98210E-1646-483B-819A-2BB8272461E4}"
ProjectSection(SolutionItems) = preProject
README = README

Loading…
Cancel
Save