diff --git a/ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs b/ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs
index b524045a11..788ea2445a 100644
--- a/ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs
+++ b/ICSharpCode.NRefactory.CSharp/Resolver/CSharpResolver.cs
@@ -2095,6 +2095,25 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
#endregion
#region ResolveConditional
+ ///
+ /// Converts the input to bool using the rules for boolean expressions.
+ /// That is, operator true is used if a regular conversion to bool is not possible.
+ ///
+ public ResolveResult ResolveCondition(ResolveResult input)
+ {
+ if (input == null)
+ throw new ArgumentNullException("input");
+ IType boolean = compilation.FindType(KnownTypeCode.Boolean);
+ Conversion c = conversions.ImplicitConversion(input, boolean);
+ if (!c.IsValid) {
+ var opTrue = input.Type.GetMethods(m => m.IsOperator && m.Name == "op_True").FirstOrDefault();
+ if (opTrue != null) {
+ c = Conversion.UserDefinedImplicitConversion(opTrue, false);
+ }
+ }
+ return Convert(input, boolean, c);
+ }
+
public ResolveResult ResolveConditional(ResolveResult condition, ResolveResult trueExpression, ResolveResult falseExpression)
{
// C# 4.0 spec ยง7.14: Conditional operator
@@ -2131,7 +2150,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
} else {
return ErrorResult;
}
- isValid &= TryConvert(ref condition, compilation.FindType(KnownTypeCode.Boolean));
+ condition = ResolveCondition(condition);
if (isValid) {
if (condition.IsCompileTimeConstant && trueExpression.IsCompileTimeConstant && falseExpression.IsCompileTimeConstant) {
bool? val = condition.ConstantValue as bool?;
diff --git a/ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs b/ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs
index a8802127bc..464b5afd46 100644
--- a/ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs
+++ b/ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs
@@ -2604,7 +2604,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
if (resolverEnabled) {
for (AstNode child = conditionStatement.FirstChild; child != null; child = child.NextSibling) {
if (child.Role == AstNode.Roles.Condition) {
- ResolveAndProcessConversion((Expression)child, resolver.Compilation.FindType(KnownTypeCode.Boolean));
+ Expression condition = (Expression)child;
+ ResolveResult conditionRR = Resolve(condition);
+ ResolveResult convertedRR = resolver.ResolveCondition(conditionRR);
+ if (convertedRR != conditionRR)
+ ProcessConversionResult(condition, convertedRR as ConversionResolveResult);
} else {
Scan(child);
}
diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/OperatorDeclarationTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/OperatorDeclarationTests.cs
index 034b525490..cf8afda519 100644
--- a/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/OperatorDeclarationTests.cs
+++ b/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/OperatorDeclarationTests.cs
@@ -64,5 +64,11 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.TypeMembers
Assert.AreEqual("MyObject", ((SimpleType)od.ReturnType).Identifier);
Assert.AreEqual("op_UnaryPlus", od.Name);
}
+
+ [Test, Ignore("Parser crash")]
+ public void InvalidOperatorTrueDeclaration()
+ {
+ ParseUtilCSharp.ParseTypeMember("public static implicit operator true(MyBool b) {}", expectErrors: true);
+ }
}
}
diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ConditionalOperatorTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ConditionalOperatorTests.cs
index 9c8fe4cd97..e04499e30b 100644
--- a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ConditionalOperatorTests.cs
+++ b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/ConditionalOperatorTests.cs
@@ -165,5 +165,37 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
AssertType(typeof(StringComparison), resolver.ResolveConditional(
MakeResult(typeof(bool)), MakeResult(typeof(StringComparison)), MakeConstant(0)));
}
+
+ [Test]
+ public void TypeWithImplicitConversionToBool()
+ {
+ string program = @"struct MyBool {
+ public static implicit operator bool(MyBool b) {}
+ void Test() {
+ var x = $this$ ? 1 : 0;
+ }
+}";
+ Assert.AreEqual("System.Boolean", GetExpectedType(program).ReflectionName);
+ Conversion c = GetConversion(program);
+ Assert.IsTrue(c.IsValid);
+ Assert.IsTrue(c.IsUserDefined);
+ Assert.AreEqual("op_Implicit", c.Method.Name);
+ }
+
+ [Test]
+ public void TypeWithOperatorTrue()
+ {
+ string program = @"struct MyBool {
+ public static bool operator true(MyBool b) {}
+ void Test() {
+ var x = $this$ ? 1 : 0;
+ }
+}";
+ Assert.AreEqual("System.Boolean", GetExpectedType(program).ReflectionName);
+ Conversion c = GetConversion(program);
+ Assert.IsTrue(c.IsValid);
+ Assert.IsTrue(c.IsUserDefined);
+ Assert.AreEqual("op_True", c.Method.Name);
+ }
}
}