Browse Source

Add support for user-defined conversions starting with a constant expression conversion.

newNRvisualizers
Daniel Grunwald 13 years ago
parent
commit
902f00ee7a
  1. 56
      ICSharpCode.NRefactory.CSharp/Resolver/CSharpConversions.cs
  2. 9
      ICSharpCode.NRefactory.Tests/CSharp/Resolver/ConversionsTest.cs
  3. 2
      ICSharpCode.NRefactory.Tests/CSharp/Resolver/ExplicitConversionsTest.cs

56
ICSharpCode.NRefactory.CSharp/Resolver/CSharpConversions.cs

@ -109,9 +109,14 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -109,9 +109,14 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
if (c.IsValid) return c;
if (ImplicitConstantExpressionConversion(resolveResult, toType))
return Conversion.ImplicitConstantExpressionConversion;
c = StandardImplicitConversion(resolveResult.Type, toType);
if (c.IsValid) return c;
c = UserDefinedImplicitConversion(resolveResult, resolveResult.Type, toType);
if (c.IsValid) return c;
} else {
c = ImplicitConversion(resolveResult.Type, toType);
if (c.IsValid) return c;
}
c = ImplicitConversion(resolveResult.Type, toType);
if (c.IsValid) return c;
if (resolveResult.Type.Kind == TypeKind.Dynamic)
return Conversion.ImplicitDynamicConversion;
c = AnonymousFunctionConversion(resolveResult, toType);
@ -135,7 +140,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -135,7 +140,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
// C# 4.0 spec: §6.1
c = StandardImplicitConversion(fromType, toType);
if (!c.IsValid) {
c = UserDefinedImplicitConversion(fromType, toType);
c = UserDefinedImplicitConversion(null, fromType, toType);
}
implicitConversionCache[pair] = c;
return c;
@ -214,8 +219,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -214,8 +219,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
Conversion c = ImplicitConversion(resolveResult, toType);
if (c.IsValid)
return c;
else
return ExplicitConversionImpl(resolveResult.Type, toType);
c = ExplicitConversionImpl(resolveResult.Type, toType);
if (c.IsValid)
return c;
return UserDefinedExplicitConversion(resolveResult, resolveResult.Type, toType);
}
public Conversion ExplicitConversion(IType fromType, IType toType)
@ -228,8 +235,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -228,8 +235,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
Conversion c = ImplicitConversion(fromType, toType);
if (c.IsValid)
return c;
else
return ExplicitConversionImpl(fromType, toType);
c = ExplicitConversionImpl(fromType, toType);
if (c.IsValid)
return c;
return UserDefinedExplicitConversion(null, fromType, toType);
}
Conversion ExplicitConversionImpl(IType fromType, IType toType)
@ -252,7 +261,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -252,7 +261,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
return c;
if (ExplicitPointerConversion(fromType, toType))
return Conversion.ExplicitPointerConversion;
return UserDefinedExplicitConversion(fromType, toType);
return Conversion.None;
}
#endregion
@ -643,8 +652,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -643,8 +652,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
#region Implicit Constant-Expression Conversion
bool ImplicitConstantExpressionConversion(ResolveResult rr, IType toType)
{
if (rr == null || !rr.IsCompileTimeConstant)
return false;
// C# 4.0 spec: §6.1.9
Debug.Assert(rr.IsCompileTimeConstant);
TypeCode fromTypeCode = ReflectionHelper.GetTypeCode(rr.Type);
TypeCode toTypeCode = ReflectionHelper.GetTypeCode(NullableType.GetUnderlyingType(toType));
if (fromTypeCode == TypeCode.Int64) {
@ -784,10 +794,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -784,10 +794,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
// "selected.Count == 1" check above should have found the unique lifted operator.
}
Conversion UserDefinedImplicitConversion(IType fromType, IType toType)
Conversion UserDefinedImplicitConversion(ResolveResult fromResult, IType fromType, IType toType)
{
// C# 4.0 spec §6.4.4 User-defined implicit conversions
var operators = GetApplicableConversionOperators(fromType, toType, false);
var operators = GetApplicableConversionOperators(fromResult, fromType, toType, false);
if (operators.Count > 0) {
IType S0 = NullableType.GetUnderlyingType(fromType);
@ -808,21 +818,24 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -808,21 +818,24 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
}
}
Conversion UserDefinedExplicitConversion(IType fromType, IType toType)
Conversion UserDefinedExplicitConversion(ResolveResult fromResult, IType fromType, IType toType)
{
// C# 4.0 spec §6.4.5 User-defined implicit conversions
var operators = GetApplicableConversionOperators(fromType, toType, true);
var operators = GetApplicableConversionOperators(fromResult, fromType, toType, true);
if (operators.Count > 0) {
IType S0 = NullableType.GetUnderlyingType(fromType);
IType T0 = NullableType.GetUnderlyingType(toType);
IType mostSpecificSource;
if (operators.Any(op => op.SourceType.Equals(S0)))
if (operators.Any(op => op.SourceType.Equals(S0))) {
mostSpecificSource = S0;
else if (operators.Any(op => IsEncompassedBy(S0, op.SourceType)))
mostSpecificSource = FindMostEncompassedType(operators.Where(op => IsEncompassedBy(S0, op.SourceType)).Select(op => op.SourceType));
else
mostSpecificSource = FindMostEncompassingType(operators.Select(op => op.SourceType));
} else {
var operatorsWithSourceEncompassingFromType = operators.Where(op => IsEncompassedBy(S0, op.SourceType) || ImplicitConstantExpressionConversion(fromResult, op.SourceType));
if (operatorsWithSourceEncompassingFromType.Any())
mostSpecificSource = FindMostEncompassedType(operatorsWithSourceEncompassingFromType.Select(op => op.SourceType));
else
mostSpecificSource = FindMostEncompassingType(operators.Select(op => op.SourceType));
}
if (mostSpecificSource == null)
return Conversion.None;
@ -860,7 +873,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -860,7 +873,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
}
}
List<OperatorInfo> GetApplicableConversionOperators(IType fromType, IType toType, bool isExplicit)
List<OperatorInfo> GetApplicableConversionOperators(ResolveResult fromResult, IType fromType, IType toType, bool isExplicit)
{
// Find the candidate operators:
Predicate<IUnresolvedMethod> opFilter;
@ -879,10 +892,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -879,10 +892,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
// Try if the operator is applicable:
bool isApplicable;
if (isExplicit) {
isApplicable = IsEncompassingOrEncompassedBy(fromType, sourceType)
isApplicable = (IsEncompassingOrEncompassedBy(fromType, sourceType) || ImplicitConstantExpressionConversion(fromResult, sourceType))
&& IsEncompassingOrEncompassedBy(targetType, toType);
} else {
isApplicable = IsEncompassedBy(fromType, sourceType) && IsEncompassedBy(targetType, toType);
isApplicable = (IsEncompassedBy(fromType, sourceType) || ImplicitConstantExpressionConversion(fromResult, sourceType))
&& IsEncompassedBy(targetType, toType);
}
// Try if the operator is applicable in lifted form:
bool isApplicableInLiftedForm = false;

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

@ -832,7 +832,7 @@ class Test { @@ -832,7 +832,7 @@ class Test {
Assert.AreEqual("System.Object", c.Method.Parameters.Single().Type.FullName);
}
[Test, Ignore("expression-based user-defined conversions not implemented")]
[Test]
public void UserDefined_IntLiteral_ViaUInt_ToCustomStruct()
{
string program = @"using System;
@ -843,10 +843,6 @@ class Test { @@ -843,10 +843,6 @@ class Test {
static void M() {
T t = $1$;
}
}";
var c = GetConversion(program);
Assert.IsTrue(c.IsValid);
@ -861,7 +857,6 @@ struct T { @@ -861,7 +857,6 @@ struct T {
public static implicit operator T(string a) { return new T(); }
}
class Test {
static void M() {
T t = $null$;
@ -1033,7 +1028,7 @@ class Test { @@ -1033,7 +1028,7 @@ class Test {
Assert.AreEqual("ni", c.Method.Parameters[0].Name);
}
[Test, Ignore("TODO: The 'most encompassing' algorithm should pick the long overload, but csc picks the uint one.")]
[Test]
public void UserDefinedImplicitConversion_UIntConstant() {
string program = @"using System;
class Convertible {

2
ICSharpCode.NRefactory.Tests/CSharp/Resolver/ExplicitConversionsTest.cs

@ -711,7 +711,7 @@ class Test { @@ -711,7 +711,7 @@ class Test {
Assert.AreEqual("ni", rr.Conversion.Method.Parameters[0].Name);
}
[Test, Ignore("TODO: The 'most encompassing' algorithm should pick the long overload, but csc picks the uint one.")]
[Test]
public void UserDefinedExplicitConversion_UIntConstant() {
string program = @"using System;
class Convertible {

Loading…
Cancel
Save