diff --git a/ICSharpCode.NRefactory/CSharp/Ast/AstNode.cs b/ICSharpCode.NRefactory/CSharp/Ast/AstNode.cs index 9e27348b33..3c089a63c0 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/AstNode.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/AstNode.cs @@ -27,6 +27,7 @@ using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; +using System.IO; using System.Linq; using System.Threading; @@ -663,6 +664,19 @@ namespace ICSharpCode.NRefactory.CSharp base.AddAnnotation (annotation); } + internal string DebugToString() + { + if (IsNull) + return "Null"; + StringWriter w = new StringWriter(); + AcceptVisitor(new OutputVisitor(w, new CSharpFormattingOptions()), null); + string text = w.ToString().TrimEnd().Replace("\t", "").Replace(w.NewLine, " "); + if (text.Length > 100) + return text.Substring(0, 97) + "..."; + else + return text; + } + // the Root role must be available when creating the null nodes, so we can't put it in the Roles class static readonly Role RootRole = new Role ("Root"); diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/Expression.cs b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/Expression.cs index 00d9b10d88..23f3342585 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/Expression.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/Expression.cs @@ -18,8 +18,6 @@ using System; using System.Collections.Generic; -using System.IO; -using System.Linq; namespace ICSharpCode.NRefactory.CSharp { @@ -105,11 +103,7 @@ namespace ICSharpCode.NRefactory.CSharp // Make debugging easier by giving Expressions a ToString() implementation public override string ToString() { - if (IsNull) - return "Null"; - StringWriter w = new StringWriter(); - AcceptVisitor(new OutputVisitor(w, new CSharpFormattingOptions()), null); - return w.ToString(); + return DebugToString(); } public Expression ReplaceWith(Func replaceFunction) diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Statements/Statement.cs b/ICSharpCode.NRefactory/CSharp/Ast/Statements/Statement.cs index e2d607571d..73100a64cd 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Statements/Statement.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Statements/Statement.cs @@ -2,7 +2,6 @@ // This code is distributed under MIT X11 license (for details please see \doc\license.txt) using System; -using System.IO; namespace ICSharpCode.NRefactory.CSharp { @@ -93,15 +92,7 @@ namespace ICSharpCode.NRefactory.CSharp // Make debugging easier by giving Statements a ToString() implementation public override string ToString() { - if (IsNull) - return "Null"; - StringWriter w = new StringWriter(); - AcceptVisitor(new OutputVisitor(w, new CSharpFormattingOptions()), null); - string text = w.ToString().TrimEnd().Replace("\t", "").Replace(w.NewLine, " "); - if (text.Length > 100) - return text.Substring(0, 97) + "..."; - else - return text; + return DebugToString(); } } } diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs b/ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs index 1bf13424bd..7ae440d281 100644 --- a/ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs +++ b/ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs @@ -159,8 +159,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver } break; case ResolveVisitorNavigationMode.Scan: - if (node is LambdaExpression) { - // lambdas must be resolved so that they get stored in the resolver cache + if (node is LambdaExpression || node is AnonymousMethodExpression) { + // lambdas must be resolved so that they get stored in the 'undecided' list only once goto case ResolveVisitorNavigationMode.Resolve; } resolverBeforeDict[node] = resolver.Clone(); @@ -265,13 +265,17 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver void ProcessConversion(ResolveResult rr, Conversion conversion, IType targetType) { if (conversion.IsAnonymousFunctionConversion) { - Debug.WriteLine("Processing conversion of anonymous function to " + targetType); + Debug.WriteLine("Processing conversion of anonymous function to " + targetType + "..."); AnonymousFunctionConversionData data = conversion.data as AnonymousFunctionConversionData; if (data != null) { + Debug.Indent(); if (data.Hypothesis != null) data.Hypothesis.MergeInto(this, data.ReturnType); if (data.ExplicitlyTypedLambda != null) data.ExplicitlyTypedLambda.ApplyReturnType(this, data.ReturnType); + Debug.Unindent(); + } else { + Debug.WriteLine(" Data not found."); } } } @@ -1329,7 +1333,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver if (visitor.undecidedLambdas == null) visitor.undecidedLambdas = new List(); - visitor.undecidedLambdas.Add(lambda); + visitor.undecidedLambdas.Add(this); Debug.WriteLine("Added undecided explicitly-typed lambda: " + this.LambdaExpression); } @@ -1343,7 +1347,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver { // If it's not already analyzed if (inferredReturnType == null) { - Debug.WriteLine("Analyzing " + this.LambdaExpression); + Debug.WriteLine("Analyzing " + this.LambdaExpression + "..."); Debug.Indent(); visitor.ResetContext( @@ -1362,10 +1366,16 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver public override Conversion IsValid(IType[] parameterTypes, IType returnType, Conversions conversions) { - if (Analyze() && IsValidLambda(isValidAsVoidMethod, returnValues, returnType, conversions)) + Debug.WriteLine("Testing validity of {0} for return-type {1}...", this, returnType); + Debug.Indent(); + bool valid = Analyze() && IsValidLambda(isValidAsVoidMethod, returnValues, returnType, conversions); + Debug.Unindent(); + Debug.WriteLine("{0} is {1} for return-type {2}", this, valid ? "valid" : "invalid", returnType); + if (valid) { return Conversion.AnonymousFunctionConversion(new AnonymousFunctionConversionData(returnType, this)); - else + } else { return Conversion.None; + } } public override IType GetInferredReturnType(IType[] parameterTypes) @@ -1463,7 +1473,14 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver public override Conversion IsValid(IType[] parameterTypes, IType returnType, Conversions conversions) { - return GetHypothesis(parameterTypes).IsValid(returnType, conversions); + Debug.WriteLine("Testing validity of {0} for parameters ({1}) and return-type {2}...", + this, string.Join(", ", parameterTypes), returnType); + Debug.Indent(); + var hypothesis = GetHypothesis(parameterTypes); + Conversion c = hypothesis.IsValid(returnType, conversions); + Debug.Unindent(); + Debug.WriteLine("{0} is {1} for return-type {2}", hypothesis, c ? "valid" : "invalid", returnType); + return c; } public override IType GetInferredReturnType(IType[] parameterTypes) @@ -1572,7 +1589,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver this.parameterTypes = parameterTypes; this.visitor = visitor; - Debug.WriteLine("Analyzing " + ToString()); + Debug.WriteLine("Analyzing " + ToString() + "..."); Debug.Indent(); visitor.resolver.PushLambdaBlock(); int i = 0; @@ -1585,7 +1602,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver visitor.AnalyzeLambda(lambda.lambda.Body, out success, out isValidAsVoidMethod, out inferredReturnType, out returnValues); visitor.resolver.PopBlock(); Debug.Unindent(); - Debug.WriteLine("Finished analyzing " + ToString() + "."); + Debug.WriteLine("Finished analyzing " + ToString()); } internal int CountUnknownParameters() @@ -1600,10 +1617,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver public Conversion IsValid(IType returnType, Conversions conversions) { - if (success && IsValidLambda(isValidAsVoidMethod, returnValues, returnType, conversions)) + if (success && IsValidLambda(isValidAsVoidMethod, returnValues, returnType, conversions)) { return Conversion.AnonymousFunctionConversion(new AnonymousFunctionConversionData(returnType, this)); - else + } else { return Conversion.None; + } } public void MergeInto(ResolveVisitor parentVisitor, IType returnType) @@ -1637,9 +1655,19 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver public override string ToString() { - return "[LambdaTypeHypothesis for '" + lambda.lambda + "': " + string.Join(", ", parameterTypes) + "]"; + StringBuilder b = new StringBuilder(); + b.Append("[LambdaTypeHypothesis ("); + for (int i = 0; i < parameterTypes.Length; i++) { + if (i > 0) b.Append(", "); + b.Append(parameterTypes[i]); + b.Append(' '); + b.Append(lambda.Parameters[i].Name); + } + b.Append(") => "); + b.Append(lambda.lambda.Body.ToString()); + b.Append(']'); + return b.ToString(); } - } #endregion @@ -1656,7 +1684,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver { if (undecidedLambdas == null) return; - Debug.WriteLine("MergeUndecidedLambdas()"); + Debug.WriteLine("MergeUndecidedLambdas()..."); Debug.Indent(); while (undecidedLambdas.Count > 0) { LambdaBase lambda = undecidedLambdas[0]; @@ -1665,7 +1693,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver parent = parent.Parent; CSharpResolver storedResolver; if (parent != null && resolverBeforeDict.TryGetValue(parent, out storedResolver)) { - Debug.WriteLine("Trying to resolve '" + parent + "' in order to merge the lambda"); + Debug.WriteLine("Trying to resolve '" + parent + "' in order to merge the lambda..."); Debug.Indent(); ResetContext(storedResolver, delegate { Resolve(parent); }); Debug.Unindent(); @@ -1701,7 +1729,6 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver isValidAsVoidMethod = ExpressionPermittedAsStatement(expr); returnValues = new[] { Resolve(expr) }; inferredReturnType = returnValues[0].Type; - success = true; } else { Scan(body); @@ -1711,19 +1738,21 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver if (alv.HasVoidReturnStatements) { returnValues = EmptyList.Instance; inferredReturnType = KnownTypeReference.Void.Resolve(resolver.Context); - success = true; } else { returnValues = new ResolveResult[alv.ReturnExpressions.Count]; for (int i = 0; i < returnValues.Count; i++) { returnValues[i] = resolveResultCache[alv.ReturnExpressions[i]]; } TypeInference ti = new TypeInference(resolver.Context); - inferredReturnType = ti.GetBestCommonType(returnValues, out success); + bool tiSuccess; + inferredReturnType = ti.GetBestCommonType(returnValues, out tiSuccess); + // Failure to infer a return type does not make the lambda invalid, + // so we can ignore the 'tiSuccess' value } } Debug.WriteLine("Lambda return type was inferred to: " + inferredReturnType); // TODO: check for compiler errors within the lambda body - // success &= ..; + success = true; } static bool ExpressionPermittedAsStatement(Expression expr)