2008-01-14 Marek Safar <marek.safar@gmail.com>
authorMarek Safar <marek.safar@gmail.com>
Mon, 14 Jan 2008 18:06:47 +0000 (18:06 -0000)
committerMarek Safar <marek.safar@gmail.com>
Mon, 14 Jan 2008 18:06:47 +0000 (18:06 -0000)
  * typemanager.cs, lambda.cs, parameter.cs, ecore.cs, class.cs, delegate.cs,
  iterators.cs, convert.cs, assign.cs, anonymous.cs, expression.cs,
  statement.cs: The first expression tree implementation drop, mostly
  infrastructure work.

svn path=/trunk/mcs/; revision=92889

13 files changed:
mcs/mcs/ChangeLog
mcs/mcs/anonymous.cs
mcs/mcs/assign.cs
mcs/mcs/class.cs
mcs/mcs/convert.cs
mcs/mcs/delegate.cs
mcs/mcs/ecore.cs
mcs/mcs/expression.cs
mcs/mcs/iterators.cs
mcs/mcs/lambda.cs
mcs/mcs/parameter.cs
mcs/mcs/statement.cs
mcs/mcs/typemanager.cs

index db7264dbfb8cdc64d81404d8ad1fc5df4574efdc..874053301d2590ba4642a1b420d1bf10124a6612 100644 (file)
@@ -1,3 +1,10 @@
+2008-01-14  Marek Safar  <marek.safar@gmail.com>
+
+       * typemanager.cs, lambda.cs, parameter.cs, ecore.cs, class.cs, delegate.cs,
+       iterators.cs, convert.cs, assign.cs, anonymous.cs, expression.cs,
+       statement.cs: The first expression tree implementation drop, mostly
+       infrastructure work.
+
 2008-01-14  Marek Safar  <marek.safar@gmail.com>
 
        * ecore.cs (IsNestedChild): Refactored.
index 40ee7ae75c3ef0405bed7e58e32b722289af5881..19d73e1c6a7b2da7cf86d3da311ed1ddb6ec5476 100644 (file)
@@ -1124,6 +1124,8 @@ namespace Mono.CSharp {
 
                public bool CreateAnonymousHelpers ()
                {
+                       // FIXME: this polutes expression trees implementation
+
                        Report.Debug (64, "ANONYMOUS METHOD EXPRESSION CREATE ROOT SCOPE",
                                      this, Host, container, loc);
 
@@ -1164,21 +1166,31 @@ namespace Mono.CSharp {
                        }
                }
 
-               protected Expression CompatibleChecks (EmitContext ec, Type delegate_type)
+               protected Type CompatibleChecks (EmitContext ec, Type delegate_type)
                {
                        if (!ec.IsAnonymousMethodAllowed) {
                                Report.Error (1706, loc, "Anonymous methods and lambda expressions cannot be used in the current context");
                                return null;
                        }
                        
-                       if (!TypeManager.IsDelegateType (delegate_type)){
-                               Report.Error (1660, loc,
-                                             "Cannot convert `{0}' to type " +
-                                             "`{1}' because it is not a delegate type",
-                                             GetSignatureForError (), TypeManager.CSharpName (delegate_type));
+                       if (TypeManager.IsDelegateType (delegate_type))
+                               return delegate_type;
+
+#if GMCS_SOURCE
+                       if (TypeManager.DropGenericTypeArguments (delegate_type) == TypeManager.expression_type) {
+                               delegate_type = TypeManager.GetTypeArguments (delegate_type) [0];
+                               if (TypeManager.IsDelegateType (delegate_type))
+                                       return delegate_type;
+
+                               Report.Error (835, loc, "Cannot convert `{0}' to an expression tree of non-delegate type `{1}'",
+                                       GetSignatureForError (), TypeManager.CSharpName (delegate_type));
                                return null;
                        }
-                       return this;
+#endif
+
+                       Report.Error (1660, loc, "Cannot convert `{0}' to non-delegate type `{1}'",
+                                     GetSignatureForError (), TypeManager.CSharpName (delegate_type));
+                       return null;
                }
 
                protected bool VerifyExplicitParameters (Type delegate_type, ParameterData parameters, bool ignore_error)
@@ -1298,9 +1310,10 @@ namespace Mono.CSharp {
                // Returns AnonymousMethod container if this anonymous method
                // expression can be implicitly converted to the delegate type `delegate_type'
                //
-               public AnonymousMethod Compatible (EmitContext ec, Type delegate_type)
+               public Expression Compatible (EmitContext ec, Type type)
                {
-                       if (CompatibleChecks (ec, delegate_type) == null)
+                       Type delegate_type = CompatibleChecks (ec, type);
+                       if (delegate_type == null)
                                return null;
 
                        //
@@ -1330,12 +1343,22 @@ namespace Mono.CSharp {
                                      TypeManager.IsGenericType (delegate_type), loc);
 
                        try {
-                               return CompatibleMethod (ec, null, return_type, delegate_type);
+                               AnonymousMethod am = CompatibleMethod (ec, null, return_type, delegate_type);
+                               if (am != null && delegate_type != type)
+                                       return CreateExpressionTree (ec, delegate_type);
+
+                               return am;
                        } catch (Exception e) {
                                throw new InternalErrorException (e, loc);
                        }
                }
 
+               protected virtual Expression CreateExpressionTree (EmitContext ec, Type delegate_type)
+               {
+                       Report.Error (1946, loc, "An anonymous method cannot be converted to an expression tree");
+                       return null;
+               }
+
                protected virtual Parameters ResolveParameters (EmitContext ec, TypeInferenceContext tic, Type delegate_type)
                {
                        ParameterData delegate_parameters = TypeManager.GetDelegateParameters (delegate_type);
@@ -1437,10 +1460,8 @@ namespace Mono.CSharp {
                }
        }
 
-       public abstract class AnonymousContainer : IAnonymousContainer
+       public abstract class AnonymousContainer : Expression, IAnonymousContainer
        {
-               public readonly Location Location;
-
                public Parameters Parameters;
 
                //
@@ -1476,7 +1497,7 @@ namespace Mono.CSharp {
                        this.generic = generic;
                        this.Parameters = parameters;
                        this.Block = block;
-                       this.Location = loc;
+                       this.loc = loc;
 
                        block.AnonymousContainer = this;
                }
@@ -1497,8 +1518,6 @@ namespace Mono.CSharp {
                        get;
                }
 
-               public abstract string GetSignatureForError ();
-
                public bool Compatible (EmitContext ec)
                {
                        // REFACTOR: The method should be refactor, many of the
@@ -1570,8 +1589,6 @@ namespace Mono.CSharp {
                        return res;
                }
 
-               public abstract Expression Resolve (EmitContext ec);
-
                public virtual bool Define (EmitContext ec)
                {
                        Report.Debug (64, "DEFINE ANONYMOUS METHOD #3", this, ec, aec, Block);
@@ -1595,6 +1612,11 @@ namespace Mono.CSharp {
 
                protected abstract Method DoCreateMethodHost (EmitContext ec);
 
+               public override void Emit (EmitContext ec)
+               {
+                       throw new NotSupportedException ();
+               }
+
                public Block Container {
                        get { return container; }
                }
@@ -1762,7 +1784,7 @@ namespace Mono.CSharp {
                                scope == null ? Modifiers.PRIVATE : Modifiers.INTERNAL, member_name, Parameters);
                }
 
-               public override Expression Resolve (EmitContext ec)
+               public override Expression DoResolve (EmitContext ec)
                {
                        if (!Define (ec))
                                return null;
index 693683e5383436291fa0a399e3bde260a5f9ffcf..6a5c34d2872608c9e0fd04f861a618fff99ed553 100644 (file)
@@ -282,6 +282,12 @@ namespace Mono.CSharp {
                {
                        this.is_embedded = true;
                }
+               
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       Report.Error (832, loc, "An expression tree cannot contain an assignment operator");
+                       return null;
+               }
 
                protected virtual Assign GetEmbeddedAssign (Location loc)
                {
index 8ad3c3b4b39740f0fc7c3012c59d2c983738abc0..6bb8a5d8635922a54c37ecdd1b1bc9e935cedbbb 100644 (file)
@@ -3081,8 +3081,10 @@ namespace Mono.CSharp {
                {
                        base.Emit ();
 
+#if GMCS_SOURCE
                        if ((ModFlags & Modifiers.METHOD_EXTENSION) != 0)
                                TypeBuilder.SetCustomAttribute (TypeManager.extension_attribute_attr);
+#endif                 
                }
 
                public override TypeExpr[] GetClassBases (out TypeExpr base_class)
@@ -4565,9 +4567,11 @@ namespace Mono.CSharp {
                                MethodData.Emit (Parent);
                                base.Emit ();
                                
+#if GMCS_SOURCE                                
                                if ((ModFlags & Modifiers.METHOD_EXTENSION) != 0)
                                        MethodBuilder.SetCustomAttribute (TypeManager.extension_attribute_attr);
-                               
+#endif
+
                                Block = null;
                                MethodData = null;
                        } catch {
index a2820a1442416f48ba62920f87b1e11b13cbbb2f..e0495b570560e724dee362ed92679870430b8136 100644 (file)
@@ -1405,10 +1405,9 @@ namespace Mono.CSharp {
 
                        if (expr_type == TypeManager.anonymous_method_type){
                                AnonymousMethodExpression ame = (AnonymousMethodExpression) expr;
-
-                               AnonymousMethod am = ame.Compatible (ec, target_type);
+                               Expression am = ame.Compatible (ec, target_type);
                                if (am != null)
-                                       return am.Resolve (ec);
+                                       return am.DoResolve (ec);
                        }
 
                        return null;
index ad001171ff5c8bcbe9a0b6bde767e074bcddf4cd..6997ff98f65c6e73e1121b67c9f2dba5fa72428b 100644 (file)
@@ -848,10 +848,10 @@ namespace Mono.CSharp {
                        
                        Expression e = a.Expr;
                        if (e is AnonymousMethodExpression && RootContext.Version != LanguageVersion.ISO_1) {
-                               AnonymousMethod am = ((AnonymousMethodExpression) e).Compatible (ec, type);
-                               if (am == null)
+                               e = ((AnonymousMethodExpression) e).Compatible (ec, type);
+                               if (e == null)
                                        return null;
-                               return am.Resolve (ec);
+                               return e.Resolve (ec);
                        }
 
                        method_group = e as MethodGroupExpr;
index 4d99f415c86fa30ce9ef16bb5a166016538865bb..d5f2000b2bd682083468758fef16a795f485b86d 100644 (file)
@@ -1244,6 +1244,12 @@ namespace Mono.CSharp {
 
                        return cloned;
                }
+
+               public virtual Expression CreateExpressionTree (EmitContext ec)
+               {
+                       throw new NotImplementedException (
+                               "Expression tree conversion not implemented for " + GetType ());
+               }
        }
 
        /// <summary>
index 21417d492d1a7699cd6eaf5b272b08670c88792e..84df47ce8e51a757727b925b41113b0f3d6c29eb 100644 (file)
@@ -4027,6 +4027,11 @@ namespace Mono.CSharp {
                        return Name == pr.Name && referenced == pr.referenced;
                }
 
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       return Parameter.ExpressionTreeVariableReference ();
+               }
+
                //
                // Notice that for ref/out parameters, the type exposed is not the
                // same type exposed externally.
index 678ca672fbbe781db1f3c822e1cba454006801b9..d8b0facd72d15ac4e0044b65f8a48972fa798277 100644 (file)
@@ -938,7 +938,7 @@ namespace Mono.CSharp {
                                Parameters.EmptyReadOnlyParameters);
                }
 
-               public override Expression Resolve (EmitContext ec)
+               public override Expression DoResolve (EmitContext ec)
                {
                        throw new NotSupportedException ();
                }
index 57109d797958d6aa2ecbf47c05ab8f67f1607ba1..86a14d0f3a2cbb128068c00a50a99daecb49d737 100644 (file)
@@ -34,6 +34,33 @@ namespace Mono.CSharp {
                                explicit_parameters = !(parameters.FixedParameters [0] is ImplicitLambdaParameter);
                }
 
+               public static Expression System_Linq_Expressions;
+               public static Expression System_Linq_Expressions_Expression;
+
+               protected override Expression CreateExpressionTree (EmitContext ec, Type delegate_type)
+               {
+                       System_Linq_Expressions = new MemberAccess (
+                                       new MemberAccess (new SimpleName ("System", loc), "Linq", loc), "Expressions", loc);
+
+                       System_Linq_Expressions_Expression = new MemberAccess (
+                               System_Linq_Expressions, "Expression", loc);
+
+                       MemberAccess lambda = new MemberAccess (System_Linq_Expressions_Expression, "Lambda",
+                               new TypeArguments (loc, new TypeExpression (delegate_type, loc)), loc);
+
+                       Expression args = Parameters.CreateExpressionTree (ec, loc);
+                       Expression expr = Block.CreateExpressionTree (ec);
+                       if (expr == null)
+                               return null;
+
+                       ArrayList arguments = new ArrayList (2);
+                       arguments.Add (new Argument (expr));
+                       arguments.Add (new Argument (args));
+                       Expression invocation = new Invocation (lambda, arguments);
+
+                       return invocation;
+               }
+
                public override bool HasExplicitParameters {
                        get {
                                return explicit_parameters;
@@ -147,6 +174,11 @@ namespace Mono.CSharp {
                {
                }
 
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       return Expr.CreateExpressionTree (ec);
+               }
+
                public override void Emit (EmitContext ec)
                {
                        if (statement_return) {
index c7b805597679e5bd817cdcc3f1293bab49d24d1c..bbf41601552eaef1db5eb830b3a622becb7e1c87 100644 (file)
@@ -236,6 +236,8 @@ namespace Mono.CSharp {
                public readonly Location Location;
 
                IResolveContext resolve_context;
+               LocalVariableReference expr_tree_variable;
+               static TypeExpr parameter_expr_tree_type;
 
                Variable var;
                public Variable Variable {
@@ -606,6 +608,47 @@ namespace Mono.CSharp {
 
                        return p;
                }
+
+               public ExpressionStatement CreateExpressionTreeVariable (EmitContext ec)
+               {
+                       if ((modFlags & Modifier.ISBYREF) != 0)
+                               Report.Error (1951, Location, "An expression tree parameter cannot use `ref' or `out' modifier");
+
+                       LocalInfo variable = ec.CurrentBlock.AddTemporaryVariable (
+                               ResolveParameterExpressionType (ec, Location), Location);
+                       variable.Resolve (ec);
+
+                       expr_tree_variable = new LocalVariableReference (
+                               ec.CurrentBlock, variable.Name, Location, variable, false);
+
+                       ArrayList arguments = new ArrayList (2);
+                       arguments.Add (new Argument (new TypeOf (
+                               new TypeExpression (parameter_type, Location), Location)));
+                       arguments.Add (new Argument (new StringConstant (Name, Location)));
+                       return new Assign (ExpressionTreeVariableReference (),
+                               new Invocation (
+                                       new MemberAccess (LambdaExpression.System_Linq_Expressions_Expression, "Parameter", Location),
+                                       arguments));
+               }
+
+               public Expression ExpressionTreeVariableReference ()
+               {
+                       return expr_tree_variable;
+               }
+
+               //
+               // System.Linq.Expressions.ParameterExpression type
+               //
+               public static TypeExpr ResolveParameterExpressionType (EmitContext ec, Location location)
+               {
+                       if (parameter_expr_tree_type != null)
+                               return parameter_expr_tree_type;
+
+                       MemberAccess ma = new MemberAccess (
+                               LambdaExpression.System_Linq_Expressions, "ParameterExpression", location);
+                       parameter_expr_tree_type = ma.ResolveAsTypeTerminal (ec, false);
+                       return parameter_expr_tree_type;
+               }
        }
 
        /// <summary>
@@ -949,6 +992,26 @@ namespace Mono.CSharp {
                        return this [pos].ModFlags;
                }
 
+               public Expression CreateExpressionTree (EmitContext ec, Location loc)
+               {
+                       ArrayList initializers = new ArrayList (count);
+                       foreach (Parameter p in FixedParameters) {
+                               //
+                               // Each parameter expression is stored to local variable
+                               // to save some memory when referenced later.
+                               //
+                               StatementExpression se = new StatementExpression (p.CreateExpressionTreeVariable (ec));
+                               if (se.Resolve (ec))
+                                       ec.CurrentBlock.AddScopeStatement (se);
+                               
+                               initializers.Add (p.ExpressionTreeVariableReference ());
+                       }
+
+                       return new ArrayCreation (
+                               Parameter.ResolveParameterExpressionType (ec, loc),
+                               "[]", initializers, loc);
+               }
+
                public Parameters Clone ()
                {
                        Parameter [] parameters_copy = new Parameter [FixedParameters.Length];
index 41e66800529e39cca467dab82ab7ace9dea41803..a3a77722a0310cd6c6c478648aaf40c4897784d6 100644 (file)
@@ -103,6 +103,12 @@ namespace Mono.CSharp {
                        return s;
                }
 
+               public virtual Expression CreateExpressionTree (EmitContext ec)
+               {
+                       Report.Error (834, loc, "A lambda expression with statement body cannot be converted to an expresion tree");
+                       return null;
+               }
+
                public Statement PerformClone ()
                {
                        CloneContext clonectx = new CloneContext ();
@@ -1531,7 +1537,9 @@ namespace Mono.CSharp {
                //
                Block switch_block;
 
+               // TODO: merge with scope_initializers
                ExpressionStatement scope_init;
+               ArrayList scope_initializers;
 
                ArrayList anonymous_children;
 
@@ -1900,6 +1908,18 @@ namespace Mono.CSharp {
                        }
                        return null;
                }
+
+               //
+               // It should be used by expressions which require to
+               // register a statement during resolve process.
+               //
+               public void AddScopeStatement (StatementExpression s)
+               {
+                       if (scope_initializers == null)
+                               scope_initializers = new ArrayList ();
+
+                       scope_initializers.Add (s);
+               }
                
                public void AddStatement (Statement s)
                {
@@ -2275,6 +2295,11 @@ namespace Mono.CSharp {
                        ec.Mark (StartLocation, true);
                        if (scope_init != null)
                                scope_init.EmitStatement (ec);
+                       if (scope_initializers != null) {
+                               foreach (StatementExpression s in scope_initializers)
+                                       s.Emit (ec);
+                       }
+
                        DoEmit (ec);
                        ec.Mark (EndLocation, true); 
 
@@ -2607,6 +2632,11 @@ namespace Mono.CSharp {
                        return root_scope;
                }
 
+               public override Expression CreateExpressionTree (EmitContext ec)
+               {
+                       return ((Statement) statements [0]).CreateExpressionTree (ec);
+               }
+
                public void CreateIteratorHost (RootScopeInfo root)
                {
                        Report.Debug (64, "CREATE ITERATOR HOST", this, root, Parent, root_scope);
index 1d3921cbf36f61d9b406174110952a31e7aafd73..da719a467e66b082ef7a457d3a71cf8c9993967f 100644 (file)
@@ -112,16 +112,21 @@ namespace Mono.CSharp {
        static public Type coclass_attr_type;
        static public Type comimport_attr_type;
 
-       /// 
-       /// .NET 2.0
-       ///
-#if NET_2_0
+#if GMCS_SOURCE
+       // 
+       // C# 2.0
+       //
        static internal Type runtime_compatibility_attr_type;
        static internal Type compiler_generated_attr_type;
        static internal Type fixed_buffer_attr_type;
        static internal Type default_charset_type;
        static internal Type internals_visible_attr_type;
        static internal Type type_forwarder_attr_type;
+
+       //
+       // C# 3.0
+       //
+       static internal Type expression_type;
 #endif
 
        // 
@@ -208,14 +213,14 @@ namespace Mono.CSharp {
        static internal ConstructorInfo struct_layout_attribute_ctor;
        static public ConstructorInfo field_offset_attribute_ctor;
        
-#if NET_2_0
-       /// C# 2.0
+#if GMCS_SOURCE
+       // C# 2.0
        static internal CustomAttributeBuilder compiler_generated_attr;
        static internal ConstructorInfo fixed_buffer_attr_ctor;
-#endif
 
-       /// C# 3.0
+       // C# 3.0
        static internal CustomAttributeBuilder extension_attribute_attr;
+#endif
 
        static PtrHashtable builder_to_declspace;
 
@@ -1125,6 +1130,7 @@ namespace Mono.CSharp {
                // C# 3.0
                //
                extension_attribute_type = CoreLookupType("System.Runtime.CompilerServices", "ExtensionAttribute", true);
+               expression_type = CoreLookupType ("System.Linq.Expressions", "Expression`1", true);
 #endif
 
                //