Skip to content
This repository has been archived by the owner on Oct 16, 2020. It is now read-only.

Commit

Permalink
Add support for user-defined conversions starting with a constant exp…
Browse files Browse the repository at this point in the history
…ression conversion.
  • Loading branch information
dgrunwald committed Jan 9, 2013
1 parent 7eeb034 commit 902f00e
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 29 deletions.
56 changes: 35 additions & 21 deletions ICSharpCode.NRefactory.CSharp/Resolver/CSharpConversions.cs
Expand Up @@ -109,9 +109,14 @@ public Conversion ImplicitConversion(ResolveResult resolveResult, IType toType)
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);
Expand All @@ -135,7 +140,7 @@ public Conversion ImplicitConversion(IType fromType, IType toType)
// 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;
Expand Down Expand Up @@ -214,8 +219,10 @@ public Conversion ExplicitConversion(ResolveResult resolveResult, IType toType)
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)
Expand All @@ -228,8 +235,10 @@ public Conversion ExplicitConversion(IType fromType, IType toType)
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)
Expand All @@ -252,7 +261,7 @@ Conversion ExplicitConversionImpl(IType fromType, IType toType)
return c;
if (ExplicitPointerConversion(fromType, toType))
return Conversion.ExplicitPointerConversion;
return UserDefinedExplicitConversion(fromType, toType);
return Conversion.None;
}
#endregion

Expand Down Expand Up @@ -643,8 +652,9 @@ bool UnboxingConversion(IType fromType, IType toType)
#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) {
Expand Down Expand Up @@ -784,10 +794,10 @@ OperatorInfo SelectOperator(IType mostSpecificSource, IType mostSpecificTarget,
// "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);
Expand All @@ -808,21 +818,24 @@ Conversion UserDefinedImplicitConversion(IType fromType, IType toType)
}
}

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;

Expand Down Expand Up @@ -860,7 +873,7 @@ public OperatorInfo(IMethod method, IType sourceType, IType targetType, bool isL
}
}

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;
Expand All @@ -879,10 +892,11 @@ List<OperatorInfo> GetApplicableConversionOperators(IType fromType, IType toType
// 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;
Expand Down
Expand Up @@ -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;
Expand All @@ -843,10 +843,6 @@ class Test {
static void M() {
T t = $1$;
}
}";
var c = GetConversion(program);
Assert.IsTrue(c.IsValid);
Expand All @@ -861,7 +857,6 @@ struct T {
public static implicit operator T(string a) { return new T(); }
}
class Test {
static void M() {
T t = $null$;
Expand Down Expand Up @@ -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 {
Expand Down
Expand Up @@ -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 {
Expand Down

0 comments on commit 902f00e

Please sign in to comment.