Index: tests/ChangeLog =================================================================== --- tests/ChangeLog (revision 138597) +++ tests/ChangeLog (working copy) @@ -1,3 +1,14 @@ +2008-07-23 Scott Thomas + + This patch is contributed under the MIT/X11 license. + + * gtest-plus-arrow.cs + * gtest-initialize-arrow-assign.cs + * gtest-arrow-assign.cs + * gtest-initialize-plus-arrow.cs + * gtest-initialize-event-handler.cs: Added test for new lambda and + object initialization sugar available in -langversion:future. + 2009-07-13 Marcus Griep * test-723.cs, test-724.cs: Added test for resolution of interface Index: tests/gtest-plus-arrow.cs =================================================================== --- tests/gtest-plus-arrow.cs (revision 0) +++ tests/gtest-plus-arrow.cs (revision 0) @@ -0,0 +1,34 @@ +// Compiler options: -langversion:future + +delegate void Del (string s); + +class Foo +{ + public event Del Bar; + + public void OnBar () + { + Bar ("blarg!"); + } +} + +public class Test +{ + static int Main () + { + Foo foo = new Foo (); + bool bared = false; + foo.Bar +=> bared = !bared; + foo.OnBar (); + if (!bared) + return 1; + + bool bared2 = true; + foo.Bar +=> { bared2 = !bared2; }; + foo.OnBar (); + if (bared || bared2) + return 2; + + return 0; + } +} Index: tests/gtest-initialize-arrow-assign.cs =================================================================== --- tests/gtest-initialize-arrow-assign.cs (revision 0) +++ tests/gtest-initialize-arrow-assign.cs (revision 0) @@ -0,0 +1,22 @@ +// Compiler options: -langversion:future + +delegate int Del (string s); + +class Foo +{ + public Del Del { get; set; } +} + +public class Test +{ + static int Main () + { + if (new Foo { Del => 42 }.Del (null) != 42) + return 1; + + if (new Foo { Del => { return 13; } }.Del (null) != 13) + return 2; + + return 0; + } +} Index: tests/gtest-arrow-assign.cs =================================================================== --- tests/gtest-arrow-assign.cs (revision 0) +++ tests/gtest-arrow-assign.cs (revision 0) @@ -0,0 +1,25 @@ +// Compiler options: -langversion:future + +delegate int Del (string s); + +class Foo +{ + public Del Del { get; set; } +} + +public class Test +{ + static int Main () + { + Foo foo = new Foo (); + foo.Del => 42; + if (foo.Del (null) != 42) + return 1; + + foo.Del => { return 13; }; + if (foo.Del (null) != 13) + return 2; + + return 0; + } +} Index: tests/gtest-initialize-plus-arrow.cs =================================================================== --- tests/gtest-initialize-plus-arrow.cs (revision 0) +++ tests/gtest-initialize-plus-arrow.cs (revision 0) @@ -0,0 +1,31 @@ +// Compiler options: -langversion:future + +delegate void Del (string s); + +class Foo +{ + public event Del Bar; + + public void OnBar () + { + Bar ("blarg!"); + } +} + +public class Test +{ + static int Main () + { + bool handled = false; + new Foo { Bar +=> handled = true }.OnBar (); + if (!handled) + return 1; + + handled = false; + new Foo { Bar +=> { handled = true; } }.OnBar (); + if (!handled) + return 2; + + return 0; + } +} Index: tests/gtest-initialize-event-handler.cs =================================================================== --- tests/gtest-initialize-event-handler.cs (revision 0) +++ tests/gtest-initialize-event-handler.cs (revision 0) @@ -0,0 +1,77 @@ +// Compiler options: -langversion:future + +delegate void Del (string s); + +class Foo +{ + public event Del Bar; + + public void OnBar () + { + Bar ("blarg!"); + } +} + +public class Test +{ + static bool handled; + + static int Main () + { + new Foo { Bar += OnFooBar }.OnBar (); + if (!handled) + return 1; + + handled = false; + new Foo { Bar += new Del (OnFooBar) }.OnBar (); + if (!handled) + return 2; + + handled = false; + new Foo { Bar += delegate (string s) { handled = true; } }.OnBar (); + if (!handled) + return 3; + + handled = false; + new Foo { Bar += delegate { handled = true; } }.OnBar (); + if (!handled) + return 4; + + handled = false; + new Foo { Bar += (s) => handled = true }.OnBar (); + if (!handled) + return 5; + + handled = false; + new Foo { Bar += (s) => { handled = true; } }.OnBar (); + if (!handled) + return 6; + + handled = false; + new Foo { Bar += (string s) => handled = true }.OnBar (); + if (!handled) + return 7; + + handled = false; + new Foo { Bar += (string s) => { handled = true; } }.OnBar (); + if (!handled) + return 8; + + handled = false; + new Foo { Bar += s => handled = true }.OnBar (); + if (!handled) + return 9; + + handled = false; + new Foo { Bar += s => { handled = true; } }.OnBar (); + if (!handled) + return 10; + + return 0; + } + + static void OnFooBar (string s) + { + handled = true; + } +} Index: mcs/cs-tokenizer.cs =================================================================== --- mcs/cs-tokenizer.cs (revision 138597) +++ mcs/cs-tokenizer.cs (working copy) @@ -2617,7 +2617,15 @@ if (d == '+') { d = Token.OP_INC; } else if (d == '=') { - d = Token.OP_ADD_ASSIGN; + if (reader.Peek () == '>') { + if (RootContext.Version != LanguageVersion.Future) + Report.FeatureIsNotAvailable (Location, "add arrow"); + + get_char (); + d = Token.OP_ADD_ARROW; + } else { + d = Token.OP_ADD_ASSIGN; + } } else { return Token.PLUS; } Index: mcs/lambda.cs =================================================================== --- mcs/lambda.cs (revision 138597) +++ mcs/lambda.cs (working copy) @@ -57,6 +57,10 @@ return null; AParametersCollection d_params = TypeManager.GetDelegateParameters (delegateType); + + if (Parameters == ParametersCompiled.Undefined) { + return CreateDefaultParameters (ec, tic, delegateType, d_params); + } if (HasExplicitParameters) { if (!VerifyExplicitParameters (delegateType, d_params, ec.IsInProbingMode)) Index: mcs/ChangeLog =================================================================== --- mcs/ChangeLog (revision 138597) +++ mcs/ChangeLog (working copy) @@ -1,3 +1,44 @@ +2009-07-23 Scott Thomas + + This patch is contributed under the MIT/X11 license. + + All of the features in this patch are enabled by passing + -langversion:future. + + * cs-tokenizer.cs: Added support for the new add arrow operator (+=>) + which is used to added lambdas as event handlers without specifying the + parameters (a la anonymous methods via the delegate keyword). + + * lambda.cs: Added support to lambdas for undefined parameters. + + * anonymous.cs: Refactored the parameter generation for anonymous + methods with undefined parameters to a protected method so that the + lambda expressions can re-use that code to auto-generate parameters. + + * expression.cs: Added MulticastDelegateInitializer which represents + an event handler registration inside of an object initializer. + + * cs-parser.jay: Added support for the following: you can register event + handlers in object initializers, you can omit the parameter list of a + lambda from handler registration with the new add arrow operator (+=>), + and from simple assignment with just the arrow. For example: + + Func myDel => 42; + + is the same as: + + Func myDel = s => 42; + + And: + + myThing.OnChanged +=> Console.WriteLine ("foo"); + + is the same as: + + myThing.OnChanged += (sender, args) => Console.WriteLine ("foo"); + + These syntaxes can be used in object initializers as well. + 2009-07-23 Marek Safar * expression.cs, delegate.cs: Moved arguments resolve into their Index: mcs/anonymous.cs =================================================================== --- mcs/anonymous.cs (revision 138597) +++ mcs/anonymous.cs (working copy) @@ -1075,33 +1075,38 @@ Report.Error (1946, loc, "An anonymous method cannot be converted to an expression tree"); return null; } + + protected ParametersCompiled CreateDefaultParameters (EmitContext ec, TypeInferenceContext tic, Type delegate_type, AParametersCollection delegate_parameters) + { + // + // We provide a set of inaccessible parameters + // + Parameter[] fixedpars = new Parameter[delegate_parameters.Count]; + for (int i = 0; i < delegate_parameters.Count; i++) { + Parameter.Modifier i_mod = delegate_parameters.FixedParameters [i].ModFlags; + if (i_mod == Parameter.Modifier.OUT) { + Report.Error (1688, loc, "Cannot convert anonymous " + + "method block without a parameter list " + + "to delegate type `{0}' because it has " + + "one or more `out' parameters.", + TypeManager.CSharpName (delegate_type)); + return null; + } + fixedpars[i] = new Parameter ( + null, null, + delegate_parameters.FixedParameters [i].ModFlags, null, loc); + } + + return ParametersCompiled.CreateFullyResolved (fixedpars, delegate_parameters.Types); + } + protected virtual ParametersCompiled ResolveParameters (EmitContext ec, TypeInferenceContext tic, Type delegate_type) { AParametersCollection delegate_parameters = TypeManager.GetDelegateParameters (delegate_type); if (Parameters == ParametersCompiled.Undefined) { - // - // We provide a set of inaccessible parameters - // - Parameter[] fixedpars = new Parameter[delegate_parameters.Count]; - - for (int i = 0; i < delegate_parameters.Count; i++) { - Parameter.Modifier i_mod = delegate_parameters.FixedParameters [i].ModFlags; - if (i_mod == Parameter.Modifier.OUT) { - Report.Error (1688, loc, "Cannot convert anonymous " + - "method block without a parameter list " + - "to delegate type `{0}' because it has " + - "one or more `out' parameters.", - TypeManager.CSharpName (delegate_type)); - return null; - } - fixedpars[i] = new Parameter ( - null, null, - delegate_parameters.FixedParameters [i].ModFlags, null, loc); - } - - return ParametersCompiled.CreateFullyResolved (fixedpars, delegate_parameters.Types); + return CreateDefaultParameters (ec, tic, delegate_type, delegate_parameters); } if (!VerifyExplicitParameters (delegate_type, delegate_parameters, ec.IsInProbingMode)) { Index: mcs/expression.cs =================================================================== --- mcs/expression.cs (revision 138597) +++ mcs/expression.cs (working copy) @@ -9114,6 +9114,48 @@ } } + public class MulticastDelegateInitializer : ElementInitializer + { + public MulticastDelegateInitializer (string name, Expression initializer, Location loc) + : base (name, initializer, loc) + { + } + + public override Expression CreateExpressionTree (EmitContext ec) + { + throw new NotSupportedException ("ET"); + } + + public override Expression DoResolve (EmitContext ec) + { + if (source == null) + return EmptyExpressionStatement.Instance; + + MemberExpr me = MemberLookupFinal (ec, ec.CurrentInitializerVariable.Type, ec.CurrentInitializerVariable.Type, + Name, MemberTypes.Event, BindingFlags.Public | BindingFlags.Instance, loc) as MemberExpr; + + if (me == null) + return null; + + me.InstanceExpression = ec.CurrentInitializerVariable; + + return new EventAddOrRemove (me, Binary.Operator.Addition, source, loc).DoResolve (ec); + } + + protected override Expression Error_MemberLookupFailed (Type type, MemberInfo[] members) + { + MemberInfo member = members [0]; + if (member.MemberType != MemberTypes.Event) + Report.Error (-39, loc, "Member `{0}' cannot be initialized. An object " + + "event initializer may only be used for events", TypeManager.GetFullNameSignature (member)); + else + Report.Error (-40, loc, " Static event `{0}' cannot be assigned in an object initializer", + TypeManager.GetFullNameSignature (member)); + + return null; + } + } + // // A collection initializer expression // Index: mcs/cs-parser.jay =================================================================== --- mcs/cs-parser.jay (revision 138597) +++ mcs/cs-parser.jay (working copy) @@ -324,6 +324,7 @@ %token OP_OR_ASSIGN %token OP_PTR %token OP_COALESCING +%token OP_ADD_ARROW /* Numbers */ %token LITERAL_INTEGER @@ -3170,6 +3171,34 @@ LocatedToken lt = $1 as LocatedToken; $$ = new ElementInitializer (lt.Value, (Expression)$3, lt.Location); } + | IDENTIFIER OP_ADD_ASSIGN expression + { + LocatedToken lt = (LocatedToken)$1; + $$ = new MulticastDelegateInitializer (lt.Value, (Expression)$3, lt.Location); + } + | IDENTIFIER OP_ADD_ARROW + { + start_anonymous (true, ParametersCompiled.Undefined, GetLocation ($1)); + } + lambda_expression_body + { + LocatedToken lt = (LocatedToken)$1; + AnonymousMethodExpression e = end_anonymous ((ToplevelBlock) $4); + $$ = new MulticastDelegateInitializer (lt.Value, e, lt.Location); + } + | IDENTIFIER ARROW + { + if (RootContext.Version != LanguageVersion.Future) + Report.FeatureIsNotAvailable (lexer.Location, "parameterless lambda assignment"); + + start_anonymous (true, ParametersCompiled.Undefined, GetLocation ($1)); + } + lambda_expression_body + { + LocatedToken lt = (LocatedToken)$1; + AnonymousMethodExpression e = end_anonymous ((ToplevelBlock) $4); + $$ = new ElementInitializer (lt.Value, e, lt.Location); + } | GENERATE_COMPLETION { $$ = new CompletionElementInitializer (null, GetLocation ($1)); @@ -3188,7 +3217,7 @@ | OPEN_BRACE CLOSE_BRACE { Report.Error (1920, GetLocation ($1), "An element initializer cannot be empty"); - } + } ; initializer_value @@ -4057,6 +4086,28 @@ $$ = new CompoundAssign ( Binary.Operator.ExclusiveOr, (Expression) $1, (Expression) $3); } + | prefixed_unary_expression OP_ADD_ARROW + { + start_anonymous (true, ParametersCompiled.Undefined, GetLocation ($1)); + } + lambda_expression_body + { + AnonymousMethodExpression e = end_anonymous ((ToplevelBlock) $4); + $$ = new CompoundAssign ( + Binary.Operator.Addition, (Expression) $1, e); + } + | prefixed_unary_expression ARROW + { + if (RootContext.Version != LanguageVersion.Future) + Report.FeatureIsNotAvailable (lexer.Location, "parameterless lambda assignment"); + + start_anonymous (true, ParametersCompiled.Undefined, GetLocation ($1)); + } + lambda_expression_body + { + AnonymousMethodExpression e = end_anonymous ((ToplevelBlock) $4); + $$ = new SimpleAssign ((Expression) $1, e); + } ; lambda_parameter_list @@ -6611,6 +6662,8 @@ return "partial"; case Token.ARROW: return "=>"; + case Token.OP_ADD_ARROW: + return "+=>"; case Token.FROM: case Token.FROM_FIRST: return "from"; Index: errors/errors.txt =================================================================== --- errors/errors.txt (revision 138597) +++ errors/errors.txt (working copy) @@ -108,6 +108,10 @@ -38 Covariant type parameters cannot be used as method parameters. +-39 Handlers can only be registered to events in object initializers. + +-40 Handlers cannot be registered to static events in object initializers. + ---------- Errors that we have allocated that will have corresponding errors in Index: errors/ChangeLog =================================================================== --- errors/ChangeLog (revision 138597) +++ errors/ChangeLog (working copy) @@ -1,3 +1,13 @@ +2009-07-23 Scott Thomas + + This patch is contributed under the MIT/X11 license. + + * errors.txt + * gcs8039.cs + * gcs8040.cs: Added errors and tests for new lambda and object + initializer sugar available in -langversion:future. + + 2009-06-18 Raja R Harinath * Makefile (run-test-local): Make parallel-make safe.