}
} else {
am = body.Compatible (ec);
+
+ if (body.DirectMethodGroupConversion != null) {
+ var errors_printer = new SessionReportPrinter ();
+ var old = ec.Report.SetPrinter (errors_printer);
+ var expr = new ImplicitDelegateCreation (delegate_type, body.DirectMethodGroupConversion, loc) {
+ AllowSpecialMethodsInvocation = true
+ }.Resolve (ec);
+ ec.Report.SetPrinter (old);
+ if (expr != null && errors_printer.ErrorsCount == 0)
+ am = expr;
+ }
}
} catch (CompletionResult) {
throw;
get { return "anonymous method"; }
}
+ //
+ // Method-group instance for lambdas which can be replaced with
+ // simple method group call
+ //
+ public MethodGroupExpr DirectMethodGroupConversion {
+ get; set;
+ }
+
public override bool IsIterator {
get {
return false;
}
public override AnonymousMethodStorey Storey {
- get { return storey; }
+ get {
+ return storey;
+ }
}
#endregion
if (ec.Module.Compiler.Settings.Version != LanguageVersion.ISO_1){
MethodGroupExpr mg = expr as MethodGroupExpr;
if (mg != null)
- return ImplicitDelegateCreation.Create (
- ec, mg, target_type, loc);
+ return new ImplicitDelegateCreation (target_type, mg, loc).Resolve (ec);
}
}
protected MethodSpec constructor_method;
protected MethodGroupExpr method_group;
+ public bool AllowSpecialMethodsInvocation { get; set; }
+
public override bool ContainsEmitWithAwait ()
{
return false;
return null;
}
- Invocation.IsSpecialMethodInvocation (ec, delegate_method, loc);
+ if (!AllowSpecialMethodsInvocation)
+ Invocation.IsSpecialMethodInvocation (ec, delegate_method, loc);
ExtensionMethodGroupExpr emg = method_group as ExtensionMethodGroupExpr;
if (emg != null) {
//
public class ImplicitDelegateCreation : DelegateCreation
{
- ImplicitDelegateCreation (TypeSpec t, MethodGroupExpr mg, Location l)
+ public ImplicitDelegateCreation (TypeSpec delegateType, MethodGroupExpr mg, Location loc)
{
- type = t;
+ type = delegateType;
this.method_group = mg;
- loc = l;
- }
-
- static public Expression Create (ResolveContext ec, MethodGroupExpr mge,
- TypeSpec target_type, Location loc)
- {
- ImplicitDelegateCreation d = new ImplicitDelegateCreation (target_type, mge, loc);
- return d.DoResolve (ec);
+ this.loc = loc;
}
}
}
}
+ public virtual MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
+ {
+ //
+ // Return method-group expression when the expression can be used as
+ // lambda replacement. A good example is array sorting where instead of
+ // code like
+ //
+ // Array.Sort (s, (a, b) => String.Compare (a, b));
+ //
+ // we can use method group directly
+ //
+ // Array.Sort (s, String.Compare);
+ //
+ // Correct overload will be used because we do the reduction after
+ // best candidate was found.
+ //
+ return null;
+ }
+
//
// Returns true when the expression during Emit phase breaks stack
// by using await expression
#endregion
+ public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
+ {
+ if (best_candidate == null || !(best_candidate.IsStatic || InstanceExpression is This))
+ return null;
+
+ var args_count = arguments == null ? 0 : arguments.Count;
+ if (args_count != body.Parameters.Count && args_count == 0)
+ return null;
+
+ var mg = MethodGroupExpr.CreatePredefined (best_candidate.Get, DeclaringType, loc);
+ mg.InstanceExpression = InstanceExpression;
+
+ return mg;
+ }
+
public static PropertyExpr CreatePredefined (PropertySpec spec, Location loc)
{
return new PropertyExpr (spec, loc) {
#endregion
+ public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
+ {
+ if (MethodGroup == null)
+ return null;
+
+ var candidate = MethodGroup.BestCandidate;
+ if (candidate == null || !(candidate.IsStatic || Exp is This))
+ return null;
+
+ var args_count = arguments == null ? 0 : arguments.Count;
+ if (args_count != body.Parameters.Count)
+ return null;
+
+ var lambda_parameters = body.Block.Parameters.FixedParameters;
+ for (int i = 0; i < args_count; ++i) {
+ var pr = arguments[i].Expr as ParameterReference;
+ if (pr == null)
+ return null;
+
+ if (lambda_parameters[i] != pr.Parameter)
+ return null;
+
+ if ((lambda_parameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (pr.Parameter.ModFlags & Parameter.Modifier.RefOutMask))
+ return null;
+ }
+
+ var emg = MethodGroup as ExtensionMethodGroupExpr;
+ if (emg != null) {
+ return MethodGroupExpr.CreatePredefined (candidate, candidate.DeclaringType, MethodGroup.Location);
+ }
+
+ return MethodGroup;
+ }
+
protected override void CloneTo (CloneContext clonectx, Expression t)
{
Invocation target = (Invocation) t;
}
var l = am as AnonymousMethodBody;
- if (l != null && l.ReturnTypeInference != null && expr != null) {
- l.ReturnTypeInference.AddCommonTypeBound (expr.Type);
- return true;
+ if (l != null && expr != null) {
+ if (l.ReturnTypeInference != null) {
+ l.ReturnTypeInference.AddCommonTypeBound (expr.Type);
+ return true;
+ }
+
+ //
+ // Try to optimize simple lambda. Only when optimizations are enabled not to cause
+ // unexpected debugging experience
+ //
+ if (this is ContextualReturn && !ec.IsInProbingMode && ec.Module.Compiler.Settings.Optimize) {
+ l.DirectMethodGroupConversion = expr.CanReduceLambda (l);
+ }
}
}
}
if (Report.Errors > 0)
return;
-#if PRODUCTION
try {
-#endif
if (IsCompilerGenerated) {
using (ec.With (BuilderContext.Options.OmitDebugInfo, true)) {
base.Emit (ec);
ec.Emit (OpCodes.Ret);
}
-#if PRODUCTION
- } catch (Exception e){
- Console.WriteLine ("Exception caught by the compiler while emitting:");
- Console.WriteLine (" Block that caused the problem begin at: " + block.loc);
-
- Console.WriteLine (e.GetType ().FullName + ": " + e.Message);
- throw;
+ } catch (Exception e) {
+ throw new InternalErrorException (e, StartLocation);
}
-#endif
}
}
--- /dev/null
+// Compiler options: -optimize
+
+// Check lambdas to method group optimization, no lambdas should be created for any code int this test
+
+using System;
+using System.Collections;
+using System.Linq;
+
+class Test
+{
+ static int Prop {
+ get {
+ return 4;
+ }
+ }
+
+ public static int Main ()
+ {
+ var parsed = from t in new[] { "2" } select int.Parse (t);
+ if (parsed.First () != 2)
+ return 1;
+
+ var s = new string[] { "x", "a" };
+ Array.Sort (s, (a, b) => String.Compare (a, b));
+ if (s[0] != "a")
+ return 10;
+
+ if (s[1] != "x")
+ return 11;
+
+ Func<int> i = () => Prop;
+ if (i () != 4)
+ return 20;
+
+ var em = new IEnumerable[] { new int[] { 1 } }.Select (l => l.Cast<int> ()).First ().First ();
+ if (em != 1)
+ return 30;
+
+ Console.WriteLine ("ok");
+ return 0;
+ }
+}
\ No newline at end of file