Browse Source

Fixed lambda type inference in delegate creation expressions. ("new Func<int, int>(a => a)")

newNRvisualizers
Daniel Grunwald 14 years ago
parent
commit
0f2b0c380e
  1. 23
      ICSharpCode.NRefactory.CSharp/Ast/Expressions/ParenthesizedExpression.cs
  2. 2
      ICSharpCode.NRefactory.CSharp/Resolver/FindReferencedEntities.cs
  3. 2
      ICSharpCode.NRefactory.CSharp/Resolver/FindReferences.cs
  4. 25
      ICSharpCode.NRefactory.CSharp/Resolver/ResolveVisitor.cs
  5. 25
      ICSharpCode.NRefactory.Tests/CSharp/Resolver/LambdaTests.cs
  6. 2
      ICSharpCode.NRefactory/TypeSystem/Implementation/SimpleCompilation.cs

23
ICSharpCode.NRefactory.CSharp/Ast/Expressions/ParenthesizedExpression.cs

@ -1,6 +1,6 @@ @@ -1,6 +1,6 @@
//
// ParenthesizedExpression.cs
//
//
// Author:
// Mike Krüger <mkrueger@novell.com>
//
@ -63,5 +63,26 @@ namespace ICSharpCode.NRefactory.CSharp @@ -63,5 +63,26 @@ namespace ICSharpCode.NRefactory.CSharp
ParenthesizedExpression o = other as ParenthesizedExpression;
return o != null && this.Expression.DoMatch(o.Expression, match);
}
/// <summary>
/// Gets whether the expression acts like a parenthesized expression,
/// i.e. whether information about the expected type (for lambda type inference) flows
/// into the inner expression.
/// </summary>
/// <returns>Returns true for ParenthesizedExpression, CheckedExpression or UncheckedExpression; false otherwise.</returns>
public static bool ActsAsParenthesizedExpression(AstNode expression)
{
return expression is ParenthesizedExpression || expression is CheckedExpression || expression is UncheckedExpression;
}
/// <summary>
/// Unpacks the given expression if it is a ParenthesizedExpression, CheckedExpression or UncheckedExpression.
/// </summary>
public static Expression UnpackParenthesizedExpression(Expression expr)
{
while (ActsAsParenthesizedExpression(expr))
expr = expr.GetChildByRole(ParenthesizedExpression.Roles.Expression);
return expr;
}
}
}

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

@ -43,7 +43,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -43,7 +43,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
public void Resolved(AstNode node, ResolveResult result)
{
if (ResolveVisitor.ActsAsParenthesizedExpression(node))
if (ParenthesizedExpression.ActsAsParenthesizedExpression(node))
return;
MemberResolveResult mrr = result as MemberResolveResult;

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

@ -617,7 +617,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -617,7 +617,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
InvocationExpression ie = node as InvocationExpression;
if (ie != null) {
Expression target = ResolveVisitor.UnpackParenthesizedExpression(ie.Target);
Expression target = ParenthesizedExpression.UnpackParenthesizedExpression(ie.Target);
IdentifierExpression ident = target as IdentifierExpression;
if (ident != null)

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

@ -517,7 +517,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -517,7 +517,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
public ConversionWithTargetType GetConversionWithTargetType(Expression expr)
{
MergeUndecidedLambdas();
GetResolverStateBefore(expr);
ResolveParentForConversion(expr);
ConversionWithTargetType result;
if (conversionDict.TryGetValue(expr, out result)) {
@ -1305,6 +1305,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -1305,6 +1305,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
ResolveResult[] arguments = GetArguments(objectCreateExpression.Arguments, out argumentNames);
ResolveResult rr = resolver.ResolveObjectCreation(type, arguments, argumentNames);
if (arguments.Length == 1) {
// process conversion in case it's a delegate creation
ProcessConversionResult(objectCreateExpression.Arguments.Single(), rr as ConversionResolveResult);
}
// process conversions in all other cases
ProcessConversionsInInvocation(null, objectCreateExpression.Arguments, rr as CSharpInvocationResolveResult);
return rr;
} else {
@ -2233,7 +2238,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -2233,7 +2238,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
AstNode parent = expression.Parent;
// Continue going upwards until we find a node that can be resolved and provides
// an expected type.
while (ActsAsParenthesizedExpression(parent) || parent is NamedArgumentExpression || parent is ArrayInitializerExpression) {
while (ParenthesizedExpression.ActsAsParenthesizedExpression(parent) || CSharpAstResolver.IsUnresolvableNode(parent)) {
parent = parent.Parent;
}
CSharpResolver storedResolver;
@ -2243,21 +2248,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -2243,21 +2248,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
ResetContext(storedResolver, delegate { Resolve(parent); });
Log.Unindent();
} else {
Log.WriteLine("Could not find a suitable parent for '" + expression);
Log.WriteLine("Could not find a suitable parent for '" + expression + "'");
}
}
internal static bool ActsAsParenthesizedExpression(AstNode expression)
{
return expression is ParenthesizedExpression || expression is CheckedExpression || expression is UncheckedExpression;
}
internal static Expression UnpackParenthesizedExpression(Expression expr)
{
while (ActsAsParenthesizedExpression(expr))
expr = expr.GetChildByRole(ParenthesizedExpression.Roles.Expression);
return expr;
}
#endregion
#region AnalyzeLambda
@ -3340,7 +3333,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver @@ -3340,7 +3333,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver
QueryExpression query = querySelectClause.Parent as QueryExpression;
string rangeVariable = GetSingleRangeVariable(query);
if (rangeVariable != null) {
IdentifierExpression ident = UnpackParenthesizedExpression(querySelectClause.Expression) as IdentifierExpression;
IdentifierExpression ident = ParenthesizedExpression.UnpackParenthesizedExpression(querySelectClause.Expression) as IdentifierExpression;
if (ident != null && ident.Identifier == rangeVariable && !ident.TypeArguments.Any()) {
// selecting the single identifier that is the range variable
if (query.Clauses.Count > 2) {

25
ICSharpCode.NRefactory.Tests/CSharp/Resolver/LambdaTests.cs

@ -19,6 +19,7 @@ @@ -19,6 +19,7 @@
using System;
using System.Linq;
using ICSharpCode.NRefactory.Semantics;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem.Implementation;
using NUnit.Framework;
@ -421,6 +422,30 @@ class TestClass { @@ -421,6 +422,30 @@ class TestClass {
Assert.IsTrue(c.IsValid);
}
[Test]
public void ImplicitLambdaInNewFunc()
{
string program = @"using System;
class Test {
static bool b;
object x = new Func<int, string>(a => $a$.ToString());
}";
var r = Resolve(program);
Assert.AreEqual("System.Int32", r.Type.ReflectionName);
}
[Test]
public void LambdaInNewAction()
{
string program = @"using System;
class Test {
static bool b;
object x = new Action(() => $b = true$);
}";
var c = GetConversion(program);
Assert.IsTrue(c.IsValid);
}
[Test]
public void RaisePropertyChanged_WithExpressionLambda()
{

2
ICSharpCode.NRefactory/TypeSystem/Implementation/SimpleCompilation.cs

@ -66,7 +66,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation @@ -66,7 +66,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation
List<IAssembly> referencedAssemblies = new List<IAssembly>();
foreach (var asmRef in assemblyReferences) {
IAssembly asm = asmRef.Resolve(context);
if (asm != null)
if (asm != null && !referencedAssemblies.Contains(asm))
referencedAssemblies.Add(asm);
}
this.referencedAssemblies = referencedAssemblies.AsReadOnly();

Loading…
Cancel
Save