Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarek Safar <marek.safar@gmail.com>2012-06-08 11:36:55 +0400
committerMarek Safar <marek.safar@gmail.com>2012-06-08 11:36:55 +0400
commit3f0aa3e3c8d150490b804d2c248ae9f427da33a0 (patch)
treeb5a24339303f8b8c7d538dfe70d87c6bda1bd932 /mcs/class/dlr
parent93e56b120a61a9cfb98310c143002a358842dea4 (diff)
Convert crlf to lf
Diffstat (limited to 'mcs/class/dlr')
-rw-r--r--mcs/class/dlr/Runtime/Microsoft.Scripting.Core/Actions/.gitattributes2
-rw-r--r--mcs/class/dlr/Runtime/Microsoft.Scripting.Core/Actions/BindingRestrictions.cs736
-rw-r--r--mcs/class/dlr/Runtime/Microsoft.Scripting.Core/Actions/ExpandoObject.cs2200
-rw-r--r--mcs/class/dlr/Runtime/Microsoft.Scripting.Core/Ast/.gitattributes2
-rw-r--r--mcs/class/dlr/Runtime/Microsoft.Scripting.Core/Ast/Expression.cs838
-rw-r--r--mcs/class/dlr/Runtime/Microsoft.Scripting.Core/Ast/ListInitExpression.cs474
-rw-r--r--mcs/class/dlr/Runtime/Microsoft.Scripting.Core/Compiler/.gitattributes1
-rw-r--r--mcs/class/dlr/Runtime/Microsoft.Scripting.Core/Compiler/LambdaCompiler.Lambda.cs386
-rw-r--r--mcs/class/dlr/Runtime/Microsoft.Scripting.Core/Properties/.gitattributes1
-rw-r--r--mcs/class/dlr/Runtime/Microsoft.Scripting.Core/Properties/ExtensionAssemblyInfo.cs124
10 files changed, 2379 insertions, 2385 deletions
diff --git a/mcs/class/dlr/Runtime/Microsoft.Scripting.Core/Actions/.gitattributes b/mcs/class/dlr/Runtime/Microsoft.Scripting.Core/Actions/.gitattributes
deleted file mode 100644
index 9e416188c5d..00000000000
--- a/mcs/class/dlr/Runtime/Microsoft.Scripting.Core/Actions/.gitattributes
+++ /dev/null
@@ -1,2 +0,0 @@
-/BindingRestrictions.cs -crlf
-/ExpandoObject.cs -crlf
diff --git a/mcs/class/dlr/Runtime/Microsoft.Scripting.Core/Actions/BindingRestrictions.cs b/mcs/class/dlr/Runtime/Microsoft.Scripting.Core/Actions/BindingRestrictions.cs
index 2b1115cb49c..f4fd62fa89a 100644
--- a/mcs/class/dlr/Runtime/Microsoft.Scripting.Core/Actions/BindingRestrictions.cs
+++ b/mcs/class/dlr/Runtime/Microsoft.Scripting.Core/Actions/BindingRestrictions.cs
@@ -1,368 +1,368 @@
-/* ****************************************************************************
- *
- * Copyright (c) Microsoft Corporation.
- *
- * This source code is subject to terms and conditions of the Apache License, Version 2.0. A
- * copy of the license can be found in the License.html file at the root of this distribution. If
- * you cannot locate the Apache License, Version 2.0, please send an email to
- * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
- * by the terms of the Apache License, Version 2.0.
- *
- * You must not remove this notice, or any other, from this software.
- *
- *
- * ***************************************************************************/
-
-#if CLR2
-using Microsoft.Scripting.Ast;
-#else
-using System.Linq.Expressions;
-#endif
-
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Dynamic.Utils;
-using System.Runtime.CompilerServices;
-
-namespace System.Dynamic {
-
- /// <summary>
- /// Represents a set of binding restrictions on the <see cref="DynamicMetaObject"/>under which the dynamic binding is valid.
- /// </summary>
-#if !SILVERLIGHT
- [DebuggerTypeProxy(typeof(BindingRestrictionsProxy)), DebuggerDisplay("{DebugView}")]
-#endif
- public abstract class BindingRestrictions {
- /// <summary>
- /// Represents an empty set of binding restrictions. This field is read only.
- /// </summary>
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")]
- public static readonly BindingRestrictions Empty = new CustomRestriction(Expression.Constant(true));
-
- private const int TypeRestrictionHash = 0x10000000;
- private const int InstanceRestrictionHash = 0x20000000;
- private const int CustomRestrictionHash = 0x40000000;
-
- private BindingRestrictions() {
- }
-
- // Overridden by specialized subclasses
- internal abstract Expression GetExpression();
-
- /// <summary>
- /// Merges the set of binding restrictions with the current binding restrictions.
- /// </summary>
- /// <param name="restrictions">The set of restrictions with which to merge the current binding restrictions.</param>
- /// <returns>The new set of binding restrictions.</returns>
- public BindingRestrictions Merge(BindingRestrictions restrictions) {
- ContractUtils.RequiresNotNull(restrictions, "restrictions");
- if (this == Empty) {
- return restrictions;
- }
- if (restrictions == Empty) {
- return this;
- }
- return new MergedRestriction(this, restrictions);
- }
-
- /// <summary>
- /// Creates the binding restriction that check the expression for runtime type identity.
- /// </summary>
- /// <param name="expression">The expression to test.</param>
- /// <param name="type">The exact type to test.</param>
- /// <returns>The new binding restrictions.</returns>
- public static BindingRestrictions GetTypeRestriction(Expression expression, Type type) {
- ContractUtils.RequiresNotNull(expression, "expression");
- ContractUtils.RequiresNotNull(type, "type");
-
- return new TypeRestriction(expression, type);
- }
-
- /// <summary>
- /// The method takes a DynamicMetaObject, and returns an instance restriction for testing null if the object
- /// holds a null value, otherwise returns a type restriction.
- /// </summary>
- internal static BindingRestrictions GetTypeRestriction(DynamicMetaObject obj) {
- if (obj.Value == null && obj.HasValue) {
- return BindingRestrictions.GetInstanceRestriction(obj.Expression, null);
- } else {
- return BindingRestrictions.GetTypeRestriction(obj.Expression, obj.LimitType);
- }
- }
-
- /// <summary>
- /// Creates the binding restriction that checks the expression for object instance identity.
- /// </summary>
- /// <param name="expression">The expression to test.</param>
- /// <param name="instance">The exact object instance to test.</param>
- /// <returns>The new binding restrictions.</returns>
- public static BindingRestrictions GetInstanceRestriction(Expression expression, object instance) {
- ContractUtils.RequiresNotNull(expression, "expression");
-
- return new InstanceRestriction(expression, instance);
- }
-
- /// <summary>
- /// Creates the binding restriction that checks the expression for arbitrary immutable properties.
- /// </summary>
- /// <param name="expression">The expression expression the restrictions.</param>
- /// <returns>The new binding restrictions.</returns>
- /// <remarks>
- /// By convention, the general restrictions created by this method must only test
- /// immutable object properties.
- /// </remarks>
- public static BindingRestrictions GetExpressionRestriction(Expression expression) {
- ContractUtils.RequiresNotNull(expression, "expression");
- ContractUtils.Requires(expression.Type == typeof(bool), "expression");
- return new CustomRestriction(expression);
- }
-
- /// <summary>
- /// Combines binding restrictions from the list of <see cref="DynamicMetaObject"/> instances into one set of restrictions.
- /// </summary>
- /// <param name="contributingObjects">The list of <see cref="DynamicMetaObject"/> instances from which to combine restrictions.</param>
- /// <returns>The new set of binding restrictions.</returns>
- public static BindingRestrictions Combine(IList<DynamicMetaObject> contributingObjects) {
- BindingRestrictions res = BindingRestrictions.Empty;
- if (contributingObjects != null) {
- foreach (DynamicMetaObject mo in contributingObjects) {
- if (mo != null) {
- res = res.Merge(mo.Restrictions);
- }
- }
- }
- return res;
- }
-
- /// <summary>
- /// Builds a balanced tree of AndAlso nodes.
- /// We do this so the compiler won't stack overflow if we have many
- /// restrictions.
- /// </summary>
- private sealed class TestBuilder {
- private readonly Set<BindingRestrictions> _unique = new Set<BindingRestrictions>();
- private readonly Stack<AndNode> _tests = new Stack<AndNode>();
-
- private struct AndNode {
- internal int Depth;
- internal Expression Node;
- }
-
- internal void Append(BindingRestrictions restrictions) {
- if (_unique.Contains(restrictions)) {
- return;
- }
- _unique.Add(restrictions);
-
- Push(restrictions.GetExpression(), 0);
- }
-
- internal Expression ToExpression() {
- Expression result = _tests.Pop().Node;
- while (_tests.Count > 0) {
- result = Expression.AndAlso(_tests.Pop().Node, result);
- }
- return result;
- }
-
- private void Push(Expression node, int depth) {
- while (_tests.Count > 0 && _tests.Peek().Depth == depth) {
- node = Expression.AndAlso(_tests.Pop().Node, node);
- depth++;
- }
- _tests.Push(new AndNode { Node = node, Depth = depth });
- }
- }
-
- /// <summary>
- /// Creates the <see cref="Expression"/> representing the binding restrictions.
- /// </summary>
- /// <returns>The expression tree representing the restrictions.</returns>
- public Expression ToExpression() {
- // We could optimize this better, e.g. common subexpression elimination
- // But for now, it's good enough.
-
- if (this == Empty) {
- return Expression.Constant(true);
- }
-
- var testBuilder = new TestBuilder();
-
- // Visit the tree, left to right.
- // Use an explicit stack so we don't stack overflow.
- //
- // Left-most node is on top of the stack, so we always expand the
- // left most node each iteration.
- var stack = new Stack<BindingRestrictions>();
- stack.Push(this);
- do {
- var top = stack.Pop();
- var m = top as MergedRestriction;
- if (m != null) {
- stack.Push(m.Right);
- stack.Push(m.Left);
- } else {
- testBuilder.Append(top);
- }
- } while (stack.Count > 0);
-
- return testBuilder.ToExpression();
- }
-
- private sealed class MergedRestriction : BindingRestrictions {
- internal readonly BindingRestrictions Left;
- internal readonly BindingRestrictions Right;
-
- internal MergedRestriction(BindingRestrictions left, BindingRestrictions right) {
- Left = left;
- Right = right;
- }
- internal override Expression GetExpression() {
- throw ContractUtils.Unreachable;
- }
- }
-
- private sealed class CustomRestriction : BindingRestrictions {
- private readonly Expression _expression;
-
- internal CustomRestriction(Expression expression) {
- _expression = expression;
- }
-
- public override bool Equals(object obj) {
- var other = obj as CustomRestriction;
- return other != null && other._expression == _expression;
- }
-
- public override int GetHashCode() {
- return CustomRestrictionHash ^ _expression.GetHashCode();
- }
-
- internal override Expression GetExpression() {
- return _expression;
- }
- }
-
- private sealed class TypeRestriction : BindingRestrictions {
- private readonly Expression _expression;
- private readonly Type _type;
-
- internal TypeRestriction(Expression parameter, Type type) {
- _expression = parameter;
- _type = type;
- }
-
- public override bool Equals(object obj) {
- var other = obj as TypeRestriction;
- return other != null && TypeUtils.AreEquivalent(other._type, _type) && other._expression == _expression;
- }
-
- public override int GetHashCode() {
- return TypeRestrictionHash ^ _expression.GetHashCode() ^ _type.GetHashCode();
- }
-
- internal override Expression GetExpression() {
- return Expression.TypeEqual(_expression, _type);
- }
- }
-
- private sealed class InstanceRestriction : BindingRestrictions {
- private readonly Expression _expression;
- private readonly object _instance;
-
- internal InstanceRestriction(Expression parameter, object instance) {
- _expression = parameter;
- _instance = instance;
- }
-
- public override bool Equals(object obj) {
- var other = obj as InstanceRestriction;
- return other != null && other._instance == _instance && other._expression == _expression;
- }
-
- public override int GetHashCode() {
- return InstanceRestrictionHash ^ RuntimeHelpers.GetHashCode(_instance) ^ _expression.GetHashCode();
- }
-
- internal override Expression GetExpression() {
- if (_instance == null) {
- return Expression.Equal(
- Expression.Convert(_expression, typeof(object)),
- Expression.Constant(null)
- );
- }
-
- ParameterExpression temp = Expression.Parameter(typeof(object), null);
- return Expression.Block(
- new[] { temp },
- Expression.Assign(
- temp,
- Expression.Property(
- Expression.Constant(new WeakReference(_instance)),
- typeof(WeakReference).GetProperty("Target")
- )
- ),
- Expression.AndAlso(
- //check that WeekReference was not collected.
- Expression.NotEqual(temp, Expression.Constant(null)),
- Expression.Equal(
- Expression.Convert(_expression, typeof(object)),
- temp
- )
- )
- );
- }
- }
-
- private string DebugView {
- get { return ToExpression().ToString(); }
- }
-
- private sealed class BindingRestrictionsProxy {
- private readonly BindingRestrictions _node;
-
- public BindingRestrictionsProxy(BindingRestrictions node) {
- _node = node;
- }
-
- public bool IsEmpty {
- get { return _node == Empty; }
- }
-
- public Expression Test {
- get { return _node.ToExpression(); }
- }
-
- public BindingRestrictions[] Restrictions {
- get {
- var restrictions = new List<BindingRestrictions>();
-
- // Visit the tree, left to right
- //
- // Left-most node is on top of the stack, so we always expand the
- // left most node each iteration.
- var stack = new Stack<BindingRestrictions>();
- stack.Push(_node);
- do {
- var top = stack.Pop();
- var m = top as MergedRestriction;
- if (m != null) {
- stack.Push(m.Right);
- stack.Push(m.Left);
- } else {
- restrictions.Add(top);
- }
- } while (stack.Count > 0);
-
- return restrictions.ToArray();
- }
- }
-
- public override string ToString() {
- // To prevent fxcop warning about this field
- return _node.DebugView;
- }
- }
- }
-}
+/* ****************************************************************************
+ *
+ * Copyright (c) Microsoft Corporation.
+ *
+ * This source code is subject to terms and conditions of the Apache License, Version 2.0. A
+ * copy of the license can be found in the License.html file at the root of this distribution. If
+ * you cannot locate the Apache License, Version 2.0, please send an email to
+ * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
+ * by the terms of the Apache License, Version 2.0.
+ *
+ * You must not remove this notice, or any other, from this software.
+ *
+ *
+ * ***************************************************************************/
+
+#if CLR2
+using Microsoft.Scripting.Ast;
+#else
+using System.Linq.Expressions;
+#endif
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Dynamic.Utils;
+using System.Runtime.CompilerServices;
+
+namespace System.Dynamic {
+
+ /// <summary>
+ /// Represents a set of binding restrictions on the <see cref="DynamicMetaObject"/>under which the dynamic binding is valid.
+ /// </summary>
+#if !SILVERLIGHT
+ [DebuggerTypeProxy(typeof(BindingRestrictionsProxy)), DebuggerDisplay("{DebugView}")]
+#endif
+ public abstract class BindingRestrictions {
+ /// <summary>
+ /// Represents an empty set of binding restrictions. This field is read only.
+ /// </summary>
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes")]
+ public static readonly BindingRestrictions Empty = new CustomRestriction(Expression.Constant(true));
+
+ private const int TypeRestrictionHash = 0x10000000;
+ private const int InstanceRestrictionHash = 0x20000000;
+ private const int CustomRestrictionHash = 0x40000000;
+
+ private BindingRestrictions() {
+ }
+
+ // Overridden by specialized subclasses
+ internal abstract Expression GetExpression();
+
+ /// <summary>
+ /// Merges the set of binding restrictions with the current binding restrictions.
+ /// </summary>
+ /// <param name="restrictions">The set of restrictions with which to merge the current binding restrictions.</param>
+ /// <returns>The new set of binding restrictions.</returns>
+ public BindingRestrictions Merge(BindingRestrictions restrictions) {
+ ContractUtils.RequiresNotNull(restrictions, "restrictions");
+ if (this == Empty) {
+ return restrictions;
+ }
+ if (restrictions == Empty) {
+ return this;
+ }
+ return new MergedRestriction(this, restrictions);
+ }
+
+ /// <summary>
+ /// Creates the binding restriction that check the expression for runtime type identity.
+ /// </summary>
+ /// <param name="expression">The expression to test.</param>
+ /// <param name="type">The exact type to test.</param>
+ /// <returns>The new binding restrictions.</returns>
+ public static BindingRestrictions GetTypeRestriction(Expression expression, Type type) {
+ ContractUtils.RequiresNotNull(expression, "expression");
+ ContractUtils.RequiresNotNull(type, "type");
+
+ return new TypeRestriction(expression, type);
+ }
+
+ /// <summary>
+ /// The method takes a DynamicMetaObject, and returns an instance restriction for testing null if the object
+ /// holds a null value, otherwise returns a type restriction.
+ /// </summary>
+ internal static BindingRestrictions GetTypeRestriction(DynamicMetaObject obj) {
+ if (obj.Value == null && obj.HasValue) {
+ return BindingRestrictions.GetInstanceRestriction(obj.Expression, null);
+ } else {
+ return BindingRestrictions.GetTypeRestriction(obj.Expression, obj.LimitType);
+ }
+ }
+
+ /// <summary>
+ /// Creates the binding restriction that checks the expression for object instance identity.
+ /// </summary>
+ /// <param name="expression">The expression to test.</param>
+ /// <param name="instance">The exact object instance to test.</param>
+ /// <returns>The new binding restrictions.</returns>
+ public static BindingRestrictions GetInstanceRestriction(Expression expression, object instance) {
+ ContractUtils.RequiresNotNull(expression, "expression");
+
+ return new InstanceRestriction(expression, instance);
+ }
+
+ /// <summary>
+ /// Creates the binding restriction that checks the expression for arbitrary immutable properties.
+ /// </summary>
+ /// <param name="expression">The expression expression the restrictions.</param>
+ /// <returns>The new binding restrictions.</returns>
+ /// <remarks>
+ /// By convention, the general restrictions created by this method must only test
+ /// immutable object properties.
+ /// </remarks>
+ public static BindingRestrictions GetExpressionRestriction(Expression expression) {
+ ContractUtils.RequiresNotNull(expression, "expression");
+ ContractUtils.Requires(expression.Type == typeof(bool), "expression");
+ return new CustomRestriction(expression);
+ }
+
+ /// <summary>
+ /// Combines binding restrictions from the list of <see cref="DynamicMetaObject"/> instances into one set of restrictions.
+ /// </summary>
+ /// <param name="contributingObjects">The list of <see cref="DynamicMetaObject"/> instances from which to combine restrictions.</param>
+ /// <returns>The new set of binding restrictions.</returns>
+ public static BindingRestrictions Combine(IList<DynamicMetaObject> contributingObjects) {
+ BindingRestrictions res = BindingRestrictions.Empty;
+ if (contributingObjects != null) {
+ foreach (DynamicMetaObject mo in contributingObjects) {
+ if (mo != null) {
+ res = res.Merge(mo.Restrictions);
+ }
+ }
+ }
+ return res;
+ }
+
+ /// <summary>
+ /// Builds a balanced tree of AndAlso nodes.
+ /// We do this so the compiler won't stack overflow if we have many
+ /// restrictions.
+ /// </summary>
+ private sealed class TestBuilder {
+ private readonly Set<BindingRestrictions> _unique = new Set<BindingRestrictions>();
+ private readonly Stack<AndNode> _tests = new Stack<AndNode>();
+
+ private struct AndNode {
+ internal int Depth;
+ internal Expression Node;
+ }
+
+ internal void Append(BindingRestrictions restrictions) {
+ if (_unique.Contains(restrictions)) {
+ return;
+ }
+ _unique.Add(restrictions);
+
+ Push(restrictions.GetExpression(), 0);
+ }
+
+ internal Expression ToExpression() {
+ Expression result = _tests.Pop().Node;
+ while (_tests.Count > 0) {
+ result = Expression.AndAlso(_tests.Pop().Node, result);
+ }
+ return result;
+ }
+
+ private void Push(Expression node, int depth) {
+ while (_tests.Count > 0 && _tests.Peek().Depth == depth) {
+ node = Expression.AndAlso(_tests.Pop().Node, node);
+ depth++;
+ }
+ _tests.Push(new AndNode { Node = node, Depth = depth });
+ }
+ }
+
+ /// <summary>
+ /// Creates the <see cref="Expression"/> representing the binding restrictions.
+ /// </summary>
+ /// <returns>The expression tree representing the restrictions.</returns>
+ public Expression ToExpression() {
+ // We could optimize this better, e.g. common subexpression elimination
+ // But for now, it's good enough.
+
+ if (this == Empty) {
+ return Expression.Constant(true);
+ }
+
+ var testBuilder = new TestBuilder();
+
+ // Visit the tree, left to right.
+ // Use an explicit stack so we don't stack overflow.
+ //
+ // Left-most node is on top of the stack, so we always expand the
+ // left most node each iteration.
+ var stack = new Stack<BindingRestrictions>();
+ stack.Push(this);
+ do {
+ var top = stack.Pop();
+ var m = top as MergedRestriction;
+ if (m != null) {
+ stack.Push(m.Right);
+ stack.Push(m.Left);
+ } else {
+ testBuilder.Append(top);
+ }
+ } while (stack.Count > 0);
+
+ return testBuilder.ToExpression();
+ }
+
+ private sealed class MergedRestriction : BindingRestrictions {
+ internal readonly BindingRestrictions Left;
+ internal readonly BindingRestrictions Right;
+
+ internal MergedRestriction(BindingRestrictions left, BindingRestrictions right) {
+ Left = left;
+ Right = right;
+ }
+ internal override Expression GetExpression() {
+ throw ContractUtils.Unreachable;
+ }
+ }
+
+ private sealed class CustomRestriction : BindingRestrictions {
+ private readonly Expression _expression;
+
+ internal CustomRestriction(Expression expression) {
+ _expression = expression;
+ }
+
+ public override bool Equals(object obj) {
+ var other = obj as CustomRestriction;
+ return other != null && other._expression == _expression;
+ }
+
+ public override int GetHashCode() {
+ return CustomRestrictionHash ^ _expression.GetHashCode();
+ }
+
+ internal override Expression GetExpression() {
+ return _expression;
+ }
+ }
+
+ private sealed class TypeRestriction : BindingRestrictions {
+ private readonly Expression _expression;
+ private readonly Type _type;
+
+ internal TypeRestriction(Expression parameter, Type type) {
+ _expression = parameter;
+ _type = type;
+ }
+
+ public override bool Equals(object obj) {
+ var other = obj as TypeRestriction;
+ return other != null && TypeUtils.AreEquivalent(other._type, _type) && other._expression == _expression;
+ }
+
+ public override int GetHashCode() {
+ return TypeRestrictionHash ^ _expression.GetHashCode() ^ _type.GetHashCode();
+ }
+
+ internal override Expression GetExpression() {
+ return Expression.TypeEqual(_expression, _type);
+ }
+ }
+
+ private sealed class InstanceRestriction : BindingRestrictions {
+ private readonly Expression _expression;
+ private readonly object _instance;
+
+ internal InstanceRestriction(Expression parameter, object instance) {
+ _expression = parameter;
+ _instance = instance;
+ }
+
+ public override bool Equals(object obj) {
+ var other = obj as InstanceRestriction;
+ return other != null && other._instance == _instance && other._expression == _expression;
+ }
+
+ public override int GetHashCode() {
+ return InstanceRestrictionHash ^ RuntimeHelpers.GetHashCode(_instance) ^ _expression.GetHashCode();
+ }
+
+ internal override Expression GetExpression() {
+ if (_instance == null) {
+ return Expression.Equal(
+ Expression.Convert(_expression, typeof(object)),
+ Expression.Constant(null)
+ );
+ }
+
+ ParameterExpression temp = Expression.Parameter(typeof(object), null);
+ return Expression.Block(
+ new[] { temp },
+ Expression.Assign(
+ temp,
+ Expression.Property(
+ Expression.Constant(new WeakReference(_instance)),
+ typeof(WeakReference).GetProperty("Target")
+ )
+ ),
+ Expression.AndAlso(
+ //check that WeekReference was not collected.
+ Expression.NotEqual(temp, Expression.Constant(null)),
+ Expression.Equal(
+ Expression.Convert(_expression, typeof(object)),
+ temp
+ )
+ )
+ );
+ }
+ }
+
+ private string DebugView {
+ get { return ToExpression().ToString(); }
+ }
+
+ private sealed class BindingRestrictionsProxy {
+ private readonly BindingRestrictions _node;
+
+ public BindingRestrictionsProxy(BindingRestrictions node) {
+ _node = node;
+ }
+
+ public bool IsEmpty {
+ get { return _node == Empty; }
+ }
+
+ public Expression Test {
+ get { return _node.ToExpression(); }
+ }
+
+ public BindingRestrictions[] Restrictions {
+ get {
+ var restrictions = new List<BindingRestrictions>();
+
+ // Visit the tree, left to right
+ //
+ // Left-most node is on top of the stack, so we always expand the
+ // left most node each iteration.
+ var stack = new Stack<BindingRestrictions>();
+ stack.Push(_node);
+ do {
+ var top = stack.Pop();
+ var m = top as MergedRestriction;
+ if (m != null) {
+ stack.Push(m.Right);
+ stack.Push(m.Left);
+ } else {
+ restrictions.Add(top);
+ }
+ } while (stack.Count > 0);
+
+ return restrictions.ToArray();
+ }
+ }
+
+ public override string ToString() {
+ // To prevent fxcop warning about this field
+ return _node.DebugView;
+ }
+ }
+ }
+}
diff --git a/mcs/class/dlr/Runtime/Microsoft.Scripting.Core/Actions/ExpandoObject.cs b/mcs/class/dlr/Runtime/Microsoft.Scripting.Core/Actions/ExpandoObject.cs
index 6ba7c7d510b..0eb1fcbc28f 100644
--- a/mcs/class/dlr/Runtime/Microsoft.Scripting.Core/Actions/ExpandoObject.cs
+++ b/mcs/class/dlr/Runtime/Microsoft.Scripting.Core/Actions/ExpandoObject.cs
@@ -1,1100 +1,1100 @@
-/* ****************************************************************************
- *
- * Copyright (c) Microsoft Corporation.
- *
- * This source code is subject to terms and conditions of the Apache License, Version 2.0. A
- * copy of the license can be found in the License.html file at the root of this distribution. If
- * you cannot locate the Apache License, Version 2.0, please send an email to
- * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
- * by the terms of the Apache License, Version 2.0.
- *
- * You must not remove this notice, or any other, from this software.
- *
- *
- * ***************************************************************************/
-
-#if CLR2
-using Microsoft.Scripting.Ast;
-using Microsoft.Scripting.Utils;
-#else
-using System.Linq.Expressions;
-#endif
-#if SILVERLIGHT
-using System.Core;
-#endif
-
-using System.Collections.Generic;
-using System.ComponentModel;
-using System.Diagnostics;
-using System.Dynamic;
-using System.Dynamic.Utils;
-using System.Runtime.CompilerServices;
-
-namespace System.Dynamic {
- /// <summary>
- /// Represents an object with members that can be dynamically added and removed at runtime.
- /// </summary>
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")]
- public sealed class ExpandoObject : IDynamicMetaObjectProvider, IDictionary<string, object>, INotifyPropertyChanged {
- internal readonly object LockObject; // the readonly field is used for locking the Expando object
- private ExpandoData _data; // the data currently being held by the Expando object
- private int _count; // the count of available members
-
- internal readonly static object Uninitialized = new object(); // A marker object used to identify that a value is uninitialized.
-
- internal const int AmbiguousMatchFound = -2; // The value is used to indicate there exists ambiguous match in the Expando object
- internal const int NoMatch = -1; // The value is used to indicate there is no matching member
-
- private PropertyChangedEventHandler _propertyChanged;
-
- /// <summary>
- /// Creates a new ExpandoObject with no members.
- /// </summary>
- public ExpandoObject() {
- _data = ExpandoData.Empty;
- LockObject = new object();
- }
-
- #region Get/Set/Delete Helpers
-
- /// <summary>
- /// Try to get the data stored for the specified class at the specified index. If the
- /// class has changed a full lookup for the slot will be performed and the correct
- /// value will be retrieved.
- /// </summary>
- internal bool TryGetValue(object indexClass, int index, string name, bool ignoreCase, out object value) {
- // read the data now. The data is immutable so we get a consistent view.
- // If there's a concurrent writer they will replace data and it just appears
- // that we won the race
- ExpandoData data = _data;
- if (data.Class != indexClass || ignoreCase) {
- /* Re-search for the index matching the name here if
- * 1) the class has changed, we need to get the correct index and return
- * the value there.
- * 2) the search is case insensitive:
- * a. the member specified by index may be deleted, but there might be other
- * members matching the name if the binder is case insensitive.
- * b. the member that exactly matches the name didn't exist before and exists now,
- * need to find the exact match.
- */
- index = data.Class.GetValueIndex(name, ignoreCase, this);
- if (index == ExpandoObject.AmbiguousMatchFound) {
- throw Error.AmbiguousMatchInExpandoObject(name);
- }
- }
-
- if (index == ExpandoObject.NoMatch) {
- value = null;
- return false;
- }
-
- // Capture the value into a temp, so it doesn't get mutated after we check
- // for Uninitialized.
- object temp = data[index];
- if (temp == Uninitialized) {
- value = null;
- return false;
- }
-
- // index is now known to be correct
- value = temp;
- return true;
- }
-
- /// <summary>
- /// Sets the data for the specified class at the specified index. If the class has
- /// changed then a full look for the slot will be performed. If the new class does
- /// not have the provided slot then the Expando's class will change. Only case sensitive
- /// setter is supported in ExpandoObject.
- /// </summary>
- internal void TrySetValue(object indexClass, int index, object value, string name, bool ignoreCase, bool add) {
- ExpandoData data;
- object oldValue;
-
- lock (LockObject) {
- data = _data;
-
- if (data.Class != indexClass || ignoreCase) {
- // The class has changed or we are doing a case-insensitive search,
- // we need to get the correct index and set the value there. If we
- // don't have the value then we need to promote the class - that
- // should only happen when we have multiple concurrent writers.
- index = data.Class.GetValueIndex(name, ignoreCase, this);
- if (index == ExpandoObject.AmbiguousMatchFound) {
- throw Error.AmbiguousMatchInExpandoObject(name);
- }
- if (index == ExpandoObject.NoMatch) {
- // Before creating a new class with the new member, need to check
- // if there is the exact same member but is deleted. We should reuse
- // the class if there is such a member.
- int exactMatch = ignoreCase ?
- data.Class.GetValueIndexCaseSensitive(name) :
- index;
- if (exactMatch != ExpandoObject.NoMatch) {
- Debug.Assert(data[exactMatch] == Uninitialized);
- index = exactMatch;
- } else {
- ExpandoClass newClass = data.Class.FindNewClass(name);
- data = PromoteClassCore(data.Class, newClass);
- // After the class promotion, there must be an exact match,
- // so we can do case-sensitive search here.
- index = data.Class.GetValueIndexCaseSensitive(name);
- Debug.Assert(index != ExpandoObject.NoMatch);
- }
- }
- }
-
- // Setting an uninitialized member increases the count of available members
- oldValue = data[index];
- if (oldValue == Uninitialized) {
- _count++;
- } else if (add) {
- throw Error.SameKeyExistsInExpando(name);
- }
-
- data[index] = value;
- }
-
- // Notify property changed, outside of the lock.
- var propertyChanged = _propertyChanged;
- if (propertyChanged != null && value != oldValue) {
- // Use the canonical case for the key.
- propertyChanged(this, new PropertyChangedEventArgs(data.Class.Keys[index]));
- }
- }
-
- /// <summary>
- /// Deletes the data stored for the specified class at the specified index.
- /// </summary>
- internal bool TryDeleteValue(object indexClass, int index, string name, bool ignoreCase, object deleteValue) {
- ExpandoData data;
- lock (LockObject) {
- data = _data;
-
- if (data.Class != indexClass || ignoreCase) {
- // the class has changed or we are doing a case-insensitive search,
- // we need to get the correct index. If there is no associated index
- // we simply can't have the value and we return false.
- index = data.Class.GetValueIndex(name, ignoreCase, this);
- if (index == ExpandoObject.AmbiguousMatchFound) {
- throw Error.AmbiguousMatchInExpandoObject(name);
- }
- }
- if (index == ExpandoObject.NoMatch) {
- return false;
- }
-
- object oldValue = data[index];
- if (oldValue == Uninitialized) {
- return false;
- }
-
- // Make sure the value matches, if requested.
- //
- // It's a shame we have to call Equals with the lock held but
- // there doesn't seem to be a good way around that, and
- // ConcurrentDictionary in mscorlib does the same thing.
- if (deleteValue != Uninitialized && !object.Equals(oldValue, deleteValue)) {
- return false;
- }
-
- data[index] = Uninitialized;
-
- // Deleting an available member decreases the count of available members
- _count--;
- }
-
- // Notify property changed, outside of the lock.
- var propertyChanged = _propertyChanged;
- if (propertyChanged != null) {
- // Use the canonical case for the key.
- propertyChanged(this, new PropertyChangedEventArgs(data.Class.Keys[index]));
- }
-
- return true;
- }
-
- /// <summary>
- /// Returns true if the member at the specified index has been deleted,
- /// otherwise false. Call this function holding the lock.
- /// </summary>
- internal bool IsDeletedMember(int index) {
- Debug.Assert(index >= 0 && index <= _data.Length);
-
- if (index == _data.Length) {
- // The member is a newly added by SetMemberBinder and not in data yet
- return false;
- }
-
- return _data[index] == ExpandoObject.Uninitialized;
- }
-
- /// <summary>
- /// Exposes the ExpandoClass which we've associated with this
- /// Expando object. Used for type checks in rules.
- /// </summary>
- internal ExpandoClass Class {
- get {
- return _data.Class;
- }
- }
-
- /// <summary>
- /// Promotes the class from the old type to the new type and returns the new
- /// ExpandoData object.
- /// </summary>
- private ExpandoData PromoteClassCore(ExpandoClass oldClass, ExpandoClass newClass) {
- Debug.Assert(oldClass != newClass);
-
- lock (LockObject) {
- if (_data.Class == oldClass) {
- _data = _data.UpdateClass(newClass);
- }
- return _data;
- }
- }
-
- /// <summary>
- /// Internal helper to promote a class. Called from our RuntimeOps helper. This
- /// version simply doesn't expose the ExpandoData object which is a private
- /// data structure.
- /// </summary>
- internal void PromoteClass(object oldClass, object newClass) {
- PromoteClassCore((ExpandoClass)oldClass, (ExpandoClass)newClass);
- }
-
- #endregion
-
- #region IDynamicMetaObjectProvider Members
-
- DynamicMetaObject IDynamicMetaObjectProvider.GetMetaObject(Expression parameter) {
- return new MetaExpando(parameter, this);
- }
- #endregion
-
- #region Helper methods
- private void TryAddMember(string key, object value) {
- ContractUtils.RequiresNotNull(key, "key");
- // Pass null to the class, which forces lookup.
- TrySetValue(null, -1, value, key, false, true);
- }
-
- private bool TryGetValueForKey(string key, out object value) {
- // Pass null to the class, which forces lookup.
- return TryGetValue(null, -1, key, false, out value);
- }
-
- private bool ExpandoContainsKey(string key) {
- return _data.Class.GetValueIndexCaseSensitive(key) >= 0;
- }
-
- // We create a non-generic type for the debug view for each different collection type
- // that uses DebuggerTypeProxy, instead of defining a generic debug view type and
- // using different instantiations. The reason for this is that support for generics
- // with using DebuggerTypeProxy is limited. For C#, DebuggerTypeProxy supports only
- // open types (from MSDN http://msdn.microsoft.com/en-us/library/d8eyd8zc.aspx).
- private sealed class KeyCollectionDebugView {
- private ICollection<string> collection;
- public KeyCollectionDebugView(ICollection<string> collection) {
- Debug.Assert(collection != null);
- this.collection = collection;
- }
-
- [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
- public string[] Items {
- get {
- string[] items = new string[collection.Count];
- collection.CopyTo(items, 0);
- return items;
- }
- }
- }
-
- [DebuggerTypeProxy(typeof(KeyCollectionDebugView))]
- [DebuggerDisplay("Count = {Count}")]
- private class KeyCollection : ICollection<string> {
- private readonly ExpandoObject _expando;
- private readonly int _expandoVersion;
- private readonly int _expandoCount;
- private readonly ExpandoData _expandoData;
-
- internal KeyCollection(ExpandoObject expando) {
- lock (expando.LockObject) {
- _expando = expando;
- _expandoVersion = expando._data.Version;
- _expandoCount = expando._count;
- _expandoData = expando._data;
- }
- }
-
- private void CheckVersion() {
- if (_expando._data.Version != _expandoVersion || _expandoData != _expando._data) {
- //the underlying expando object has changed
- throw Error.CollectionModifiedWhileEnumerating();
- }
- }
-
- #region ICollection<string> Members
-
- public void Add(string item) {
- throw Error.CollectionReadOnly();
- }
-
- public void Clear() {
- throw Error.CollectionReadOnly();
- }
-
- public bool Contains(string item) {
- lock (_expando.LockObject) {
- CheckVersion();
- return _expando.ExpandoContainsKey(item);
- }
- }
-
- public void CopyTo(string[] array, int arrayIndex) {
- ContractUtils.RequiresNotNull(array, "array");
- ContractUtils.RequiresArrayRange(array, arrayIndex, _expandoCount, "arrayIndex", "Count");
- lock (_expando.LockObject) {
- CheckVersion();
- ExpandoData data = _expando._data;
- for (int i = 0; i < data.Class.Keys.Length; i++) {
- if (data[i] != Uninitialized) {
- array[arrayIndex++] = data.Class.Keys[i];
- }
- }
- }
- }
-
- public int Count {
- get {
- CheckVersion();
- return _expandoCount;
- }
- }
-
- public bool IsReadOnly {
- get { return true; }
- }
-
- public bool Remove(string item) {
- throw Error.CollectionReadOnly();
- }
-
- #endregion
-
- #region IEnumerable<string> Members
-
- public IEnumerator<string> GetEnumerator() {
- for (int i = 0, n = _expandoData.Class.Keys.Length; i < n; i++) {
- CheckVersion();
- if (_expandoData[i] != Uninitialized) {
- yield return _expandoData.Class.Keys[i];
- }
- }
- }
-
- #endregion
-
- #region IEnumerable Members
-
- System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
- return GetEnumerator();
- }
-
- #endregion
- }
-
- // We create a non-generic type for the debug view for each different collection type
- // that uses DebuggerTypeProxy, instead of defining a generic debug view type and
- // using different instantiations. The reason for this is that support for generics
- // with using DebuggerTypeProxy is limited. For C#, DebuggerTypeProxy supports only
- // open types (from MSDN http://msdn.microsoft.com/en-us/library/d8eyd8zc.aspx).
- private sealed class ValueCollectionDebugView {
- private ICollection<object> collection;
- public ValueCollectionDebugView(ICollection<object> collection) {
- Debug.Assert(collection != null);
- this.collection = collection;
- }
-
- [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
- public object[] Items {
- get {
- object[] items = new object[collection.Count];
- collection.CopyTo(items, 0);
- return items;
- }
- }
- }
-
- [DebuggerTypeProxy(typeof(ValueCollectionDebugView))]
- [DebuggerDisplay("Count = {Count}")]
- private class ValueCollection : ICollection<object> {
- private readonly ExpandoObject _expando;
- private readonly int _expandoVersion;
- private readonly int _expandoCount;
- private readonly ExpandoData _expandoData;
-
- internal ValueCollection(ExpandoObject expando) {
- lock (expando.LockObject) {
- _expando = expando;
- _expandoVersion = expando._data.Version;
- _expandoCount = expando._count;
- _expandoData = expando._data;
- }
- }
-
- private void CheckVersion() {
- if (_expando._data.Version != _expandoVersion || _expandoData != _expando._data) {
- //the underlying expando object has changed
- throw Error.CollectionModifiedWhileEnumerating();
- }
- }
-
- #region ICollection<string> Members
-
- public void Add(object item) {
- throw Error.CollectionReadOnly();
- }
-
- public void Clear() {
- throw Error.CollectionReadOnly();
- }
-
- public bool Contains(object item) {
- lock (_expando.LockObject) {
- CheckVersion();
-
- ExpandoData data = _expando._data;
- for (int i = 0; i < data.Class.Keys.Length; i++) {
-
- // See comment in TryDeleteValue; it's okay to call
- // object.Equals with the lock held.
- if (object.Equals(data[i], item)) {
- return true;
- }
- }
- return false;
- }
- }
-
- public void CopyTo(object[] array, int arrayIndex) {
- ContractUtils.RequiresNotNull(array, "array");
- ContractUtils.RequiresArrayRange(array, arrayIndex, _expandoCount, "arrayIndex", "Count");
- lock (_expando.LockObject) {
- CheckVersion();
- ExpandoData data = _expando._data;
- for (int i = 0; i < data.Class.Keys.Length; i++) {
- if (data[i] != Uninitialized) {
- array[arrayIndex++] = data[i];
- }
- }
- }
- }
-
- public int Count {
- get {
- CheckVersion();
- return _expandoCount;
- }
- }
-
- public bool IsReadOnly {
- get { return true; }
- }
-
- public bool Remove(object item) {
- throw Error.CollectionReadOnly();
- }
-
- #endregion
-
- #region IEnumerable<string> Members
-
- public IEnumerator<object> GetEnumerator() {
- ExpandoData data = _expando._data;
- for (int i = 0; i < data.Class.Keys.Length; i++) {
- CheckVersion();
- // Capture the value into a temp so we don't inadvertently
- // return Uninitialized.
- object temp = data[i];
- if (temp != Uninitialized) {
- yield return temp;
- }
- }
- }
-
- #endregion
-
- #region IEnumerable Members
-
- System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
- return GetEnumerator();
- }
-
- #endregion
- }
-
- #endregion
-
- #region IDictionary<string, object> Members
- ICollection<string> IDictionary<string, object>.Keys {
- get {
- return new KeyCollection(this);
- }
- }
-
- ICollection<object> IDictionary<string, object>.Values {
- get {
- return new ValueCollection(this);
- }
- }
-
- object IDictionary<string, object>.this[string key] {
- get {
- object value;
- if (!TryGetValueForKey(key, out value)) {
- throw Error.KeyDoesNotExistInExpando(key);
- }
- return value;
- }
- set {
- ContractUtils.RequiresNotNull(key, "key");
- // Pass null to the class, which forces lookup.
- TrySetValue(null, -1, value, key, false, false);
- }
- }
-
- void IDictionary<string, object>.Add(string key, object value) {
- this.TryAddMember(key, value);
- }
-
- bool IDictionary<string, object>.ContainsKey(string key) {
- ContractUtils.RequiresNotNull(key, "key");
-
- ExpandoData data = _data;
- int index = data.Class.GetValueIndexCaseSensitive(key);
- return index >= 0 && data[index] != Uninitialized;
- }
-
- bool IDictionary<string, object>.Remove(string key) {
- ContractUtils.RequiresNotNull(key, "key");
- // Pass null to the class, which forces lookup.
- return TryDeleteValue(null, -1, key, false, Uninitialized);
- }
-
- bool IDictionary<string, object>.TryGetValue(string key, out object value) {
- return TryGetValueForKey(key, out value);
- }
-
- #endregion
-
- #region ICollection<KeyValuePair<string, object>> Members
- int ICollection<KeyValuePair<string, object>>.Count {
- get {
- return _count;
- }
- }
-
- bool ICollection<KeyValuePair<string, object>>.IsReadOnly {
- get { return false; }
- }
-
- void ICollection<KeyValuePair<string, object>>.Add(KeyValuePair<string, object> item) {
- TryAddMember(item.Key, item.Value);
- }
-
- void ICollection<KeyValuePair<string, object>>.Clear() {
- // We remove both class and data!
- ExpandoData data;
- lock (LockObject) {
- data = _data;
- _data = ExpandoData.Empty;
- _count = 0;
- }
-
- // Notify property changed for all properties.
- var propertyChanged = _propertyChanged;
- if (propertyChanged != null) {
- for (int i = 0, n = data.Class.Keys.Length; i < n; i++) {
- if (data[i] != Uninitialized) {
- propertyChanged(this, new PropertyChangedEventArgs(data.Class.Keys[i]));
- }
- }
- }
- }
-
- bool ICollection<KeyValuePair<string, object>>.Contains(KeyValuePair<string, object> item) {
- object value;
- if (!TryGetValueForKey(item.Key, out value)) {
- return false;
- }
-
- return object.Equals(value, item.Value);
- }
-
- void ICollection<KeyValuePair<string, object>>.CopyTo(KeyValuePair<string, object>[] array, int arrayIndex) {
- ContractUtils.RequiresNotNull(array, "array");
- ContractUtils.RequiresArrayRange(array, arrayIndex, _count, "arrayIndex", "Count");
-
- // We want this to be atomic and not throw
- lock (LockObject) {
- foreach (KeyValuePair<string, object> item in this) {
- array[arrayIndex++] = item;
- }
- }
- }
-
- bool ICollection<KeyValuePair<string, object>>.Remove(KeyValuePair<string, object> item) {
- return TryDeleteValue(null, -1, item.Key, false, item.Value);
- }
- #endregion
-
- #region IEnumerable<KeyValuePair<string, object>> Member
-
- IEnumerator<KeyValuePair<string, object>> IEnumerable<KeyValuePair<string, object>>.GetEnumerator() {
- ExpandoData data = _data;
- return GetExpandoEnumerator(data, data.Version);
- }
-
- System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
- ExpandoData data = _data;
- return GetExpandoEnumerator(data, data.Version);
- }
-
- // Note: takes the data and version as parameters so they will be
- // captured before the first call to MoveNext().
- private IEnumerator<KeyValuePair<string, object>> GetExpandoEnumerator(ExpandoData data, int version) {
- for (int i = 0; i < data.Class.Keys.Length; i++) {
- if (_data.Version != version || data != _data) {
- // The underlying expando object has changed:
- // 1) the version of the expando data changed
- // 2) the data object is changed
- throw Error.CollectionModifiedWhileEnumerating();
- }
- // Capture the value into a temp so we don't inadvertently
- // return Uninitialized.
- object temp = data[i];
- if (temp != Uninitialized) {
- yield return new KeyValuePair<string,object>(data.Class.Keys[i], temp);
- }
- }
- }
- #endregion
-
- #region MetaExpando
-
- private class MetaExpando : DynamicMetaObject {
- public MetaExpando(Expression expression, ExpandoObject value)
- : base(expression, BindingRestrictions.Empty, value) {
- }
-
- private DynamicMetaObject BindGetOrInvokeMember(DynamicMetaObjectBinder binder, string name, bool ignoreCase, DynamicMetaObject fallback, Func<DynamicMetaObject, DynamicMetaObject> fallbackInvoke) {
- ExpandoClass klass = Value.Class;
-
- //try to find the member, including the deleted members
- int index = klass.GetValueIndex(name, ignoreCase, Value);
-
- ParameterExpression value = Expression.Parameter(typeof(object), "value");
-
- Expression tryGetValue = Expression.Call(
- typeof(RuntimeOps).GetMethod("ExpandoTryGetValue"),
- GetLimitedSelf(),
- Expression.Constant(klass, typeof(object)),
- Expression.Constant(index),
- Expression.Constant(name),
- Expression.Constant(ignoreCase),
- value
- );
-
- var result = new DynamicMetaObject(value, BindingRestrictions.Empty);
- if (fallbackInvoke != null) {
- result = fallbackInvoke(result);
- }
-
- result = new DynamicMetaObject(
- Expression.Block(
- new[] { value },
- Expression.Condition(
- tryGetValue,
- result.Expression,
- fallback.Expression,
- typeof(object)
- )
- ),
- result.Restrictions.Merge(fallback.Restrictions)
- );
-
- return AddDynamicTestAndDefer(binder, Value.Class, null, result);
- }
-
- public override DynamicMetaObject BindGetMember(GetMemberBinder binder) {
- ContractUtils.RequiresNotNull(binder, "binder");
- return BindGetOrInvokeMember(
- binder,
- binder.Name,
- binder.IgnoreCase,
- binder.FallbackGetMember(this),
- null
- );
- }
-
- public override DynamicMetaObject BindInvokeMember(InvokeMemberBinder binder, DynamicMetaObject[] args) {
- ContractUtils.RequiresNotNull(binder, "binder");
- return BindGetOrInvokeMember(
- binder,
- binder.Name,
- binder.IgnoreCase,
- binder.FallbackInvokeMember(this, args),
- value => binder.FallbackInvoke(value, args, null)
- );
- }
-
- public override DynamicMetaObject BindSetMember(SetMemberBinder binder, DynamicMetaObject value) {
- ContractUtils.RequiresNotNull(binder, "binder");
- ContractUtils.RequiresNotNull(value, "value");
-
- ExpandoClass klass;
- int index;
-
- ExpandoClass originalClass = GetClassEnsureIndex(binder.Name, binder.IgnoreCase, Value, out klass, out index);
-
- return AddDynamicTestAndDefer(
- binder,
- klass,
- originalClass,
- new DynamicMetaObject(
- Expression.Call(
- typeof(RuntimeOps).GetMethod("ExpandoTrySetValue"),
- GetLimitedSelf(),
- Expression.Constant(klass, typeof(object)),
- Expression.Constant(index),
- Expression.Convert(value.Expression, typeof(object)),
- Expression.Constant(binder.Name),
- Expression.Constant(binder.IgnoreCase)
- ),
- BindingRestrictions.Empty
- )
- );
- }
-
- public override DynamicMetaObject BindDeleteMember(DeleteMemberBinder binder) {
- ContractUtils.RequiresNotNull(binder, "binder");
-
- int index = Value.Class.GetValueIndex(binder.Name, binder.IgnoreCase, Value);
-
- Expression tryDelete = Expression.Call(
- typeof(RuntimeOps).GetMethod("ExpandoTryDeleteValue"),
- GetLimitedSelf(),
- Expression.Constant(Value.Class, typeof(object)),
- Expression.Constant(index),
- Expression.Constant(binder.Name),
- Expression.Constant(binder.IgnoreCase)
- );
- DynamicMetaObject fallback = binder.FallbackDeleteMember(this);
-
- DynamicMetaObject target = new DynamicMetaObject(
- Expression.IfThen(Expression.Not(tryDelete), fallback.Expression),
- fallback.Restrictions
- );
-
- return AddDynamicTestAndDefer(binder, Value.Class, null, target);
- }
-
- public override IEnumerable<string> GetDynamicMemberNames() {
- var expandoData = Value._data;
- var klass = expandoData.Class;
- for (int i = 0; i < klass.Keys.Length; i++) {
- object val = expandoData[i];
- if (val != ExpandoObject.Uninitialized) {
- yield return klass.Keys[i];
- }
- }
- }
-
- /// <summary>
- /// Adds a dynamic test which checks if the version has changed. The test is only necessary for
- /// performance as the methods will do the correct thing if called with an incorrect version.
- /// </summary>
- private DynamicMetaObject AddDynamicTestAndDefer(DynamicMetaObjectBinder binder, ExpandoClass klass, ExpandoClass originalClass, DynamicMetaObject succeeds) {
-
- Expression ifTestSucceeds = succeeds.Expression;
- if (originalClass != null) {
- // we are accessing a member which has not yet been defined on this class.
- // We force a class promotion after the type check. If the class changes the
- // promotion will fail and the set/delete will do a full lookup using the new
- // class to discover the name.
- Debug.Assert(originalClass != klass);
-
- ifTestSucceeds = Expression.Block(
- Expression.Call(
- null,
- typeof(RuntimeOps).GetMethod("ExpandoPromoteClass"),
- GetLimitedSelf(),
- Expression.Constant(originalClass, typeof(object)),
- Expression.Constant(klass, typeof(object))
- ),
- succeeds.Expression
- );
- }
-
- return new DynamicMetaObject(
- Expression.Condition(
- Expression.Call(
- null,
- typeof(RuntimeOps).GetMethod("ExpandoCheckVersion"),
- GetLimitedSelf(),
- Expression.Constant(originalClass ?? klass, typeof(object))
- ),
- ifTestSucceeds,
- binder.GetUpdateExpression(ifTestSucceeds.Type)
- ),
- GetRestrictions().Merge(succeeds.Restrictions)
- );
- }
-
- /// <summary>
- /// Gets the class and the index associated with the given name. Does not update the expando object. Instead
- /// this returns both the original and desired new class. A rule is created which includes the test for the
- /// original class, the promotion to the new class, and the set/delete based on the class post-promotion.
- /// </summary>
- private ExpandoClass GetClassEnsureIndex(string name, bool caseInsensitive, ExpandoObject obj, out ExpandoClass klass, out int index) {
- ExpandoClass originalClass = Value.Class;
-
- index = originalClass.GetValueIndex(name, caseInsensitive, obj) ;
- if (index == ExpandoObject.AmbiguousMatchFound) {
- klass = originalClass;
- return null;
- }
- if (index == ExpandoObject.NoMatch) {
- // go ahead and find a new class now...
- ExpandoClass newClass = originalClass.FindNewClass(name);
-
- klass = newClass;
- index = newClass.GetValueIndexCaseSensitive(name);
-
- Debug.Assert(index != ExpandoObject.NoMatch);
- return originalClass;
- } else {
- klass = originalClass;
- return null;
- }
- }
-
- /// <summary>
- /// Returns our Expression converted to our known LimitType
- /// </summary>
- private Expression GetLimitedSelf() {
- if (TypeUtils.AreEquivalent(Expression.Type, LimitType)) {
- return Expression;
- }
- return Expression.Convert(Expression, LimitType);
- }
-
- /// <summary>
- /// Returns a Restrictions object which includes our current restrictions merged
- /// with a restriction limiting our type
- /// </summary>
- private BindingRestrictions GetRestrictions() {
- Debug.Assert(Restrictions == BindingRestrictions.Empty, "We don't merge, restrictions are always empty");
-
- return BindingRestrictions.GetTypeRestriction(this);
- }
-
- public new ExpandoObject Value {
- get {
- return (ExpandoObject)base.Value;
- }
- }
- }
-
- #endregion
-
- #region ExpandoData
-
- /// <summary>
- /// Stores the class and the data associated with the class as one atomic
- /// pair. This enables us to do a class check in a thread safe manner w/o
- /// requiring locks.
- /// </summary>
- private class ExpandoData {
- internal static ExpandoData Empty = new ExpandoData();
-
- /// <summary>
- /// the dynamically assigned class associated with the Expando object
- /// </summary>
- internal readonly ExpandoClass Class;
-
- /// <summary>
- /// data stored in the expando object, key names are stored in the class.
- ///
- /// Expando._data must be locked when mutating the value. Otherwise a copy of it
- /// could be made and lose values.
- /// </summary>
- private readonly object[] _dataArray;
-
- /// <summary>
- /// Indexer for getting/setting the data
- /// </summary>
- internal object this[int index] {
- get {
- return _dataArray[index];
- }
- set {
- //when the array is updated, version increases, even the new value is the same
- //as previous. Dictionary type has the same behavior.
- _version++;
- _dataArray[index] = value;
- }
- }
-
- internal int Version {
- get { return _version; }
- }
-
- internal int Length {
- get { return _dataArray.Length; }
- }
-
- /// <summary>
- /// Constructs an empty ExpandoData object with the empty class and no data.
- /// </summary>
- private ExpandoData() {
- Class = ExpandoClass.Empty;
- _dataArray = new object[0];
- }
-
- /// <summary>
- /// the version of the ExpandoObject that tracks set and delete operations
- /// </summary>
- private int _version;
-
- /// <summary>
- /// Constructs a new ExpandoData object with the specified class and data.
- /// </summary>
- internal ExpandoData(ExpandoClass klass, object[] data, int version) {
- Class = klass;
- _dataArray = data;
- _version = version;
- }
-
- /// <summary>
- /// Update the associated class and increases the storage for the data array if needed.
- /// </summary>
- /// <returns></returns>
- internal ExpandoData UpdateClass(ExpandoClass newClass) {
- if (_dataArray.Length >= newClass.Keys.Length) {
- // we have extra space in our buffer, just initialize it to Uninitialized.
- this[newClass.Keys.Length - 1] = ExpandoObject.Uninitialized;
- return new ExpandoData(newClass, this._dataArray, this._version);
- } else {
- // we've grown too much - we need a new object array
- int oldLength = _dataArray.Length;
- object[] arr = new object[GetAlignedSize(newClass.Keys.Length)];
- Array.Copy(_dataArray, arr, _dataArray.Length);
- ExpandoData newData = new ExpandoData(newClass, arr, this._version);
- newData[oldLength] = ExpandoObject.Uninitialized;
- return newData;
- }
- }
-
- private static int GetAlignedSize(int len) {
- // the alignment of the array for storage of values (must be a power of two)
- const int DataArrayAlignment = 8;
-
- // round up and then mask off lower bits
- return (len + (DataArrayAlignment - 1)) & (~(DataArrayAlignment - 1));
- }
- }
-
- #endregion
-
- #region INotifyPropertyChanged Members
-
- event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged {
- add { _propertyChanged += value; }
- remove { _propertyChanged -= value; }
- }
-
- #endregion
- }
-}
-
-namespace System.Runtime.CompilerServices {
-
- //
- // Note: these helpers are kept as simple wrappers so they have a better
- // chance of being inlined.
- //
- public static partial class RuntimeOps {
-
- /// <summary>
- /// Gets the value of an item in an expando object.
- /// </summary>
- /// <param name="expando">The expando object.</param>
- /// <param name="indexClass">The class of the expando object.</param>
- /// <param name="index">The index of the member.</param>
- /// <param name="name">The name of the member.</param>
- /// <param name="ignoreCase">true if the name should be matched ignoring case; false otherwise.</param>
- /// <param name="value">The out parameter containing the value of the member.</param>
- /// <returns>True if the member exists in the expando object, otherwise false.</returns>
- [Obsolete("do not use this method", true), EditorBrowsable(EditorBrowsableState.Never)]
- public static bool ExpandoTryGetValue(ExpandoObject expando, object indexClass, int index, string name, bool ignoreCase, out object value) {
- return expando.TryGetValue(indexClass, index, name, ignoreCase, out value);
- }
-
- /// <summary>
- /// Sets the value of an item in an expando object.
- /// </summary>
- /// <param name="expando">The expando object.</param>
- /// <param name="indexClass">The class of the expando object.</param>
- /// <param name="index">The index of the member.</param>
- /// <param name="value">The value of the member.</param>
- /// <param name="name">The name of the member.</param>
- /// <param name="ignoreCase">true if the name should be matched ignoring case; false otherwise.</param>
- /// <returns>
- /// Returns the index for the set member.
- /// </returns>
- [Obsolete("do not use this method", true), EditorBrowsable(EditorBrowsableState.Never)]
- public static object ExpandoTrySetValue(ExpandoObject expando, object indexClass, int index, object value, string name, bool ignoreCase) {
- expando.TrySetValue(indexClass, index, value, name, ignoreCase, false);
- return value;
- }
-
- /// <summary>
- /// Deletes the value of an item in an expando object.
- /// </summary>
- /// <param name="expando">The expando object.</param>
- /// <param name="indexClass">The class of the expando object.</param>
- /// <param name="index">The index of the member.</param>
- /// <param name="name">The name of the member.</param>
- /// <param name="ignoreCase">true if the name should be matched ignoring case; false otherwise.</param>
- /// <returns>true if the item was successfully removed; otherwise, false.</returns>
- [Obsolete("do not use this method", true), EditorBrowsable(EditorBrowsableState.Never)]
- public static bool ExpandoTryDeleteValue(ExpandoObject expando, object indexClass, int index, string name, bool ignoreCase) {
- return expando.TryDeleteValue(indexClass, index, name, ignoreCase, ExpandoObject.Uninitialized);
- }
-
- /// <summary>
- /// Checks the version of the expando object.
- /// </summary>
- /// <param name="expando">The expando object.</param>
- /// <param name="version">The version to check.</param>
- /// <returns>true if the version is equal; otherwise, false.</returns>
- [Obsolete("do not use this method", true), EditorBrowsable(EditorBrowsableState.Never)]
- public static bool ExpandoCheckVersion(ExpandoObject expando, object version) {
- return expando.Class == version;
- }
-
- /// <summary>
- /// Promotes an expando object from one class to a new class.
- /// </summary>
- /// <param name="expando">The expando object.</param>
- /// <param name="oldClass">The old class of the expando object.</param>
- /// <param name="newClass">The new class of the expando object.</param>
- [Obsolete("do not use this method", true), EditorBrowsable(EditorBrowsableState.Never)]
- public static void ExpandoPromoteClass(ExpandoObject expando, object oldClass, object newClass) {
- expando.PromoteClass(oldClass, newClass);
- }
- }
-}
-
+/* ****************************************************************************
+ *
+ * Copyright (c) Microsoft Corporation.
+ *
+ * This source code is subject to terms and conditions of the Apache License, Version 2.0. A
+ * copy of the license can be found in the License.html file at the root of this distribution. If
+ * you cannot locate the Apache License, Version 2.0, please send an email to
+ * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
+ * by the terms of the Apache License, Version 2.0.
+ *
+ * You must not remove this notice, or any other, from this software.
+ *
+ *
+ * ***************************************************************************/
+
+#if CLR2
+using Microsoft.Scripting.Ast;
+using Microsoft.Scripting.Utils;
+#else
+using System.Linq.Expressions;
+#endif
+#if SILVERLIGHT
+using System.Core;
+#endif
+
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Diagnostics;
+using System.Dynamic;
+using System.Dynamic.Utils;
+using System.Runtime.CompilerServices;
+
+namespace System.Dynamic {
+ /// <summary>
+ /// Represents an object with members that can be dynamically added and removed at runtime.
+ /// </summary>
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")]
+ public sealed class ExpandoObject : IDynamicMetaObjectProvider, IDictionary<string, object>, INotifyPropertyChanged {
+ internal readonly object LockObject; // the readonly field is used for locking the Expando object
+ private ExpandoData _data; // the data currently being held by the Expando object
+ private int _count; // the count of available members
+
+ internal readonly static object Uninitialized = new object(); // A marker object used to identify that a value is uninitialized.
+
+ internal const int AmbiguousMatchFound = -2; // The value is used to indicate there exists ambiguous match in the Expando object
+ internal const int NoMatch = -1; // The value is used to indicate there is no matching member
+
+ private PropertyChangedEventHandler _propertyChanged;
+
+ /// <summary>
+ /// Creates a new ExpandoObject with no members.
+ /// </summary>
+ public ExpandoObject() {
+ _data = ExpandoData.Empty;
+ LockObject = new object();
+ }
+
+ #region Get/Set/Delete Helpers
+
+ /// <summary>
+ /// Try to get the data stored for the specified class at the specified index. If the
+ /// class has changed a full lookup for the slot will be performed and the correct
+ /// value will be retrieved.
+ /// </summary>
+ internal bool TryGetValue(object indexClass, int index, string name, bool ignoreCase, out object value) {
+ // read the data now. The data is immutable so we get a consistent view.
+ // If there's a concurrent writer they will replace data and it just appears
+ // that we won the race
+ ExpandoData data = _data;
+ if (data.Class != indexClass || ignoreCase) {
+ /* Re-search for the index matching the name here if
+ * 1) the class has changed, we need to get the correct index and return
+ * the value there.
+ * 2) the search is case insensitive:
+ * a. the member specified by index may be deleted, but there might be other
+ * members matching the name if the binder is case insensitive.
+ * b. the member that exactly matches the name didn't exist before and exists now,
+ * need to find the exact match.
+ */
+ index = data.Class.GetValueIndex(name, ignoreCase, this);
+ if (index == ExpandoObject.AmbiguousMatchFound) {
+ throw Error.AmbiguousMatchInExpandoObject(name);
+ }
+ }
+
+ if (index == ExpandoObject.NoMatch) {
+ value = null;
+ return false;
+ }
+
+ // Capture the value into a temp, so it doesn't get mutated after we check
+ // for Uninitialized.
+ object temp = data[index];
+ if (temp == Uninitialized) {
+ value = null;
+ return false;
+ }
+
+ // index is now known to be correct
+ value = temp;
+ return true;
+ }
+
+ /// <summary>
+ /// Sets the data for the specified class at the specified index. If the class has
+ /// changed then a full look for the slot will be performed. If the new class does
+ /// not have the provided slot then the Expando's class will change. Only case sensitive
+ /// setter is supported in ExpandoObject.
+ /// </summary>
+ internal void TrySetValue(object indexClass, int index, object value, string name, bool ignoreCase, bool add) {
+ ExpandoData data;
+ object oldValue;
+
+ lock (LockObject) {
+ data = _data;
+
+ if (data.Class != indexClass || ignoreCase) {
+ // The class has changed or we are doing a case-insensitive search,
+ // we need to get the correct index and set the value there. If we
+ // don't have the value then we need to promote the class - that
+ // should only happen when we have multiple concurrent writers.
+ index = data.Class.GetValueIndex(name, ignoreCase, this);
+ if (index == ExpandoObject.AmbiguousMatchFound) {
+ throw Error.AmbiguousMatchInExpandoObject(name);
+ }
+ if (index == ExpandoObject.NoMatch) {
+ // Before creating a new class with the new member, need to check
+ // if there is the exact same member but is deleted. We should reuse
+ // the class if there is such a member.
+ int exactMatch = ignoreCase ?
+ data.Class.GetValueIndexCaseSensitive(name) :
+ index;
+ if (exactMatch != ExpandoObject.NoMatch) {
+ Debug.Assert(data[exactMatch] == Uninitialized);
+ index = exactMatch;
+ } else {
+ ExpandoClass newClass = data.Class.FindNewClass(name);
+ data = PromoteClassCore(data.Class, newClass);
+ // After the class promotion, there must be an exact match,
+ // so we can do case-sensitive search here.
+ index = data.Class.GetValueIndexCaseSensitive(name);
+ Debug.Assert(index != ExpandoObject.NoMatch);
+ }
+ }
+ }
+
+ // Setting an uninitialized member increases the count of available members
+ oldValue = data[index];
+ if (oldValue == Uninitialized) {
+ _count++;
+ } else if (add) {
+ throw Error.SameKeyExistsInExpando(name);
+ }
+
+ data[index] = value;
+ }
+
+ // Notify property changed, outside of the lock.
+ var propertyChanged = _propertyChanged;
+ if (propertyChanged != null && value != oldValue) {
+ // Use the canonical case for the key.
+ propertyChanged(this, new PropertyChangedEventArgs(data.Class.Keys[index]));
+ }
+ }
+
+ /// <summary>
+ /// Deletes the data stored for the specified class at the specified index.
+ /// </summary>
+ internal bool TryDeleteValue(object indexClass, int index, string name, bool ignoreCase, object deleteValue) {
+ ExpandoData data;
+ lock (LockObject) {
+ data = _data;
+
+ if (data.Class != indexClass || ignoreCase) {
+ // the class has changed or we are doing a case-insensitive search,
+ // we need to get the correct index. If there is no associated index
+ // we simply can't have the value and we return false.
+ index = data.Class.GetValueIndex(name, ignoreCase, this);
+ if (index == ExpandoObject.AmbiguousMatchFound) {
+ throw Error.AmbiguousMatchInExpandoObject(name);
+ }
+ }
+ if (index == ExpandoObject.NoMatch) {
+ return false;
+ }
+
+ object oldValue = data[index];
+ if (oldValue == Uninitialized) {
+ return false;
+ }
+
+ // Make sure the value matches, if requested.
+ //
+ // It's a shame we have to call Equals with the lock held but
+ // there doesn't seem to be a good way around that, and
+ // ConcurrentDictionary in mscorlib does the same thing.
+ if (deleteValue != Uninitialized && !object.Equals(oldValue, deleteValue)) {
+ return false;
+ }
+
+ data[index] = Uninitialized;
+
+ // Deleting an available member decreases the count of available members
+ _count--;
+ }
+
+ // Notify property changed, outside of the lock.
+ var propertyChanged = _propertyChanged;
+ if (propertyChanged != null) {
+ // Use the canonical case for the key.
+ propertyChanged(this, new PropertyChangedEventArgs(data.Class.Keys[index]));
+ }
+
+ return true;
+ }
+
+ /// <summary>
+ /// Returns true if the member at the specified index has been deleted,
+ /// otherwise false. Call this function holding the lock.
+ /// </summary>
+ internal bool IsDeletedMember(int index) {
+ Debug.Assert(index >= 0 && index <= _data.Length);
+
+ if (index == _data.Length) {
+ // The member is a newly added by SetMemberBinder and not in data yet
+ return false;
+ }
+
+ return _data[index] == ExpandoObject.Uninitialized;
+ }
+
+ /// <summary>
+ /// Exposes the ExpandoClass which we've associated with this
+ /// Expando object. Used for type checks in rules.
+ /// </summary>
+ internal ExpandoClass Class {
+ get {
+ return _data.Class;
+ }
+ }
+
+ /// <summary>
+ /// Promotes the class from the old type to the new type and returns the new
+ /// ExpandoData object.
+ /// </summary>
+ private ExpandoData PromoteClassCore(ExpandoClass oldClass, ExpandoClass newClass) {
+ Debug.Assert(oldClass != newClass);
+
+ lock (LockObject) {
+ if (_data.Class == oldClass) {
+ _data = _data.UpdateClass(newClass);
+ }
+ return _data;
+ }
+ }
+
+ /// <summary>
+ /// Internal helper to promote a class. Called from our RuntimeOps helper. This
+ /// version simply doesn't expose the ExpandoData object which is a private
+ /// data structure.
+ /// </summary>
+ internal void PromoteClass(object oldClass, object newClass) {
+ PromoteClassCore((ExpandoClass)oldClass, (ExpandoClass)newClass);
+ }
+
+ #endregion
+
+ #region IDynamicMetaObjectProvider Members
+
+ DynamicMetaObject IDynamicMetaObjectProvider.GetMetaObject(Expression parameter) {
+ return new MetaExpando(parameter, this);
+ }
+ #endregion
+
+ #region Helper methods
+ private void TryAddMember(string key, object value) {
+ ContractUtils.RequiresNotNull(key, "key");
+ // Pass null to the class, which forces lookup.
+ TrySetValue(null, -1, value, key, false, true);
+ }
+
+ private bool TryGetValueForKey(string key, out object value) {
+ // Pass null to the class, which forces lookup.
+ return TryGetValue(null, -1, key, false, out value);
+ }
+
+ private bool ExpandoContainsKey(string key) {
+ return _data.Class.GetValueIndexCaseSensitive(key) >= 0;
+ }
+
+ // We create a non-generic type for the debug view for each different collection type
+ // that uses DebuggerTypeProxy, instead of defining a generic debug view type and
+ // using different instantiations. The reason for this is that support for generics
+ // with using DebuggerTypeProxy is limited. For C#, DebuggerTypeProxy supports only
+ // open types (from MSDN http://msdn.microsoft.com/en-us/library/d8eyd8zc.aspx).
+ private sealed class KeyCollectionDebugView {
+ private ICollection<string> collection;
+ public KeyCollectionDebugView(ICollection<string> collection) {
+ Debug.Assert(collection != null);
+ this.collection = collection;
+ }
+
+ [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
+ public string[] Items {
+ get {
+ string[] items = new string[collection.Count];
+ collection.CopyTo(items, 0);
+ return items;
+ }
+ }
+ }
+
+ [DebuggerTypeProxy(typeof(KeyCollectionDebugView))]
+ [DebuggerDisplay("Count = {Count}")]
+ private class KeyCollection : ICollection<string> {
+ private readonly ExpandoObject _expando;
+ private readonly int _expandoVersion;
+ private readonly int _expandoCount;
+ private readonly ExpandoData _expandoData;
+
+ internal KeyCollection(ExpandoObject expando) {
+ lock (expando.LockObject) {
+ _expando = expando;
+ _expandoVersion = expando._data.Version;
+ _expandoCount = expando._count;
+ _expandoData = expando._data;
+ }
+ }
+
+ private void CheckVersion() {
+ if (_expando._data.Version != _expandoVersion || _expandoData != _expando._data) {
+ //the underlying expando object has changed
+ throw Error.CollectionModifiedWhileEnumerating();
+ }
+ }
+
+ #region ICollection<string> Members
+
+ public void Add(string item) {
+ throw Error.CollectionReadOnly();
+ }
+
+ public void Clear() {
+ throw Error.CollectionReadOnly();
+ }
+
+ public bool Contains(string item) {
+ lock (_expando.LockObject) {
+ CheckVersion();
+ return _expando.ExpandoContainsKey(item);
+ }
+ }
+
+ public void CopyTo(string[] array, int arrayIndex) {
+ ContractUtils.RequiresNotNull(array, "array");
+ ContractUtils.RequiresArrayRange(array, arrayIndex, _expandoCount, "arrayIndex", "Count");
+ lock (_expando.LockObject) {
+ CheckVersion();
+ ExpandoData data = _expando._data;
+ for (int i = 0; i < data.Class.Keys.Length; i++) {
+ if (data[i] != Uninitialized) {
+ array[arrayIndex++] = data.Class.Keys[i];
+ }
+ }
+ }
+ }
+
+ public int Count {
+ get {
+ CheckVersion();
+ return _expandoCount;
+ }
+ }
+
+ public bool IsReadOnly {
+ get { return true; }
+ }
+
+ public bool Remove(string item) {
+ throw Error.CollectionReadOnly();
+ }
+
+ #endregion
+
+ #region IEnumerable<string> Members
+
+ public IEnumerator<string> GetEnumerator() {
+ for (int i = 0, n = _expandoData.Class.Keys.Length; i < n; i++) {
+ CheckVersion();
+ if (_expandoData[i] != Uninitialized) {
+ yield return _expandoData.Class.Keys[i];
+ }
+ }
+ }
+
+ #endregion
+
+ #region IEnumerable Members
+
+ System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
+ return GetEnumerator();
+ }
+
+ #endregion
+ }
+
+ // We create a non-generic type for the debug view for each different collection type
+ // that uses DebuggerTypeProxy, instead of defining a generic debug view type and
+ // using different instantiations. The reason for this is that support for generics
+ // with using DebuggerTypeProxy is limited. For C#, DebuggerTypeProxy supports only
+ // open types (from MSDN http://msdn.microsoft.com/en-us/library/d8eyd8zc.aspx).
+ private sealed class ValueCollectionDebugView {
+ private ICollection<object> collection;
+ public ValueCollectionDebugView(ICollection<object> collection) {
+ Debug.Assert(collection != null);
+ this.collection = collection;
+ }
+
+ [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
+ public object[] Items {
+ get {
+ object[] items = new object[collection.Count];
+ collection.CopyTo(items, 0);
+ return items;
+ }
+ }
+ }
+
+ [DebuggerTypeProxy(typeof(ValueCollectionDebugView))]
+ [DebuggerDisplay("Count = {Count}")]
+ private class ValueCollection : ICollection<object> {
+ private readonly ExpandoObject _expando;
+ private readonly int _expandoVersion;
+ private readonly int _expandoCount;
+ private readonly ExpandoData _expandoData;
+
+ internal ValueCollection(ExpandoObject expando) {
+ lock (expando.LockObject) {
+ _expando = expando;
+ _expandoVersion = expando._data.Version;
+ _expandoCount = expando._count;
+ _expandoData = expando._data;
+ }
+ }
+
+ private void CheckVersion() {
+ if (_expando._data.Version != _expandoVersion || _expandoData != _expando._data) {
+ //the underlying expando object has changed
+ throw Error.CollectionModifiedWhileEnumerating();
+ }
+ }
+
+ #region ICollection<string> Members
+
+ public void Add(object item) {
+ throw Error.CollectionReadOnly();
+ }
+
+ public void Clear() {
+ throw Error.CollectionReadOnly();
+ }
+
+ public bool Contains(object item) {
+ lock (_expando.LockObject) {
+ CheckVersion();
+
+ ExpandoData data = _expando._data;
+ for (int i = 0; i < data.Class.Keys.Length; i++) {
+
+ // See comment in TryDeleteValue; it's okay to call
+ // object.Equals with the lock held.
+ if (object.Equals(data[i], item)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ public void CopyTo(object[] array, int arrayIndex) {
+ ContractUtils.RequiresNotNull(array, "array");
+ ContractUtils.RequiresArrayRange(array, arrayIndex, _expandoCount, "arrayIndex", "Count");
+ lock (_expando.LockObject) {
+ CheckVersion();
+ ExpandoData data = _expando._data;
+ for (int i = 0; i < data.Class.Keys.Length; i++) {
+ if (data[i] != Uninitialized) {
+ array[arrayIndex++] = data[i];
+ }
+ }
+ }
+ }
+
+ public int Count {
+ get {
+ CheckVersion();
+ return _expandoCount;
+ }
+ }
+
+ public bool IsReadOnly {
+ get { return true; }
+ }
+
+ public bool Remove(object item) {
+ throw Error.CollectionReadOnly();
+ }
+
+ #endregion
+
+ #region IEnumerable<string> Members
+
+ public IEnumerator<object> GetEnumerator() {
+ ExpandoData data = _expando._data;
+ for (int i = 0; i < data.Class.Keys.Length; i++) {
+ CheckVersion();
+ // Capture the value into a temp so we don't inadvertently
+ // return Uninitialized.
+ object temp = data[i];
+ if (temp != Uninitialized) {
+ yield return temp;
+ }
+ }
+ }
+
+ #endregion
+
+ #region IEnumerable Members
+
+ System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
+ return GetEnumerator();
+ }
+
+ #endregion
+ }
+
+ #endregion
+
+ #region IDictionary<string, object> Members
+ ICollection<string> IDictionary<string, object>.Keys {
+ get {
+ return new KeyCollection(this);
+ }
+ }
+
+ ICollection<object> IDictionary<string, object>.Values {
+ get {
+ return new ValueCollection(this);
+ }
+ }
+
+ object IDictionary<string, object>.this[string key] {
+ get {
+ object value;
+ if (!TryGetValueForKey(key, out value)) {
+ throw Error.KeyDoesNotExistInExpando(key);
+ }
+ return value;
+ }
+ set {
+ ContractUtils.RequiresNotNull(key, "key");
+ // Pass null to the class, which forces lookup.
+ TrySetValue(null, -1, value, key, false, false);
+ }
+ }
+
+ void IDictionary<string, object>.Add(string key, object value) {
+ this.TryAddMember(key, value);
+ }
+
+ bool IDictionary<string, object>.ContainsKey(string key) {
+ ContractUtils.RequiresNotNull(key, "key");
+
+ ExpandoData data = _data;
+ int index = data.Class.GetValueIndexCaseSensitive(key);
+ return index >= 0 && data[index] != Uninitialized;
+ }
+
+ bool IDictionary<string, object>.Remove(string key) {
+ ContractUtils.RequiresNotNull(key, "key");
+ // Pass null to the class, which forces lookup.
+ return TryDeleteValue(null, -1, key, false, Uninitialized);
+ }
+
+ bool IDictionary<string, object>.TryGetValue(string key, out object value) {
+ return TryGetValueForKey(key, out value);
+ }
+
+ #endregion
+
+ #region ICollection<KeyValuePair<string, object>> Members
+ int ICollection<KeyValuePair<string, object>>.Count {
+ get {
+ return _count;
+ }
+ }
+
+ bool ICollection<KeyValuePair<string, object>>.IsReadOnly {
+ get { return false; }
+ }
+
+ void ICollection<KeyValuePair<string, object>>.Add(KeyValuePair<string, object> item) {
+ TryAddMember(item.Key, item.Value);
+ }
+
+ void ICollection<KeyValuePair<string, object>>.Clear() {
+ // We remove both class and data!
+ ExpandoData data;
+ lock (LockObject) {
+ data = _data;
+ _data = ExpandoData.Empty;
+ _count = 0;
+ }
+
+ // Notify property changed for all properties.
+ var propertyChanged = _propertyChanged;
+ if (propertyChanged != null) {
+ for (int i = 0, n = data.Class.Keys.Length; i < n; i++) {
+ if (data[i] != Uninitialized) {
+ propertyChanged(this, new PropertyChangedEventArgs(data.Class.Keys[i]));
+ }
+ }
+ }
+ }
+
+ bool ICollection<KeyValuePair<string, object>>.Contains(KeyValuePair<string, object> item) {
+ object value;
+ if (!TryGetValueForKey(item.Key, out value)) {
+ return false;
+ }
+
+ return object.Equals(value, item.Value);
+ }
+
+ void ICollection<KeyValuePair<string, object>>.CopyTo(KeyValuePair<string, object>[] array, int arrayIndex) {
+ ContractUtils.RequiresNotNull(array, "array");
+ ContractUtils.RequiresArrayRange(array, arrayIndex, _count, "arrayIndex", "Count");
+
+ // We want this to be atomic and not throw
+ lock (LockObject) {
+ foreach (KeyValuePair<string, object> item in this) {
+ array[arrayIndex++] = item;
+ }
+ }
+ }
+
+ bool ICollection<KeyValuePair<string, object>>.Remove(KeyValuePair<string, object> item) {
+ return TryDeleteValue(null, -1, item.Key, false, item.Value);
+ }
+ #endregion
+
+ #region IEnumerable<KeyValuePair<string, object>> Member
+
+ IEnumerator<KeyValuePair<string, object>> IEnumerable<KeyValuePair<string, object>>.GetEnumerator() {
+ ExpandoData data = _data;
+ return GetExpandoEnumerator(data, data.Version);
+ }
+
+ System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
+ ExpandoData data = _data;
+ return GetExpandoEnumerator(data, data.Version);
+ }
+
+ // Note: takes the data and version as parameters so they will be
+ // captured before the first call to MoveNext().
+ private IEnumerator<KeyValuePair<string, object>> GetExpandoEnumerator(ExpandoData data, int version) {
+ for (int i = 0; i < data.Class.Keys.Length; i++) {
+ if (_data.Version != version || data != _data) {
+ // The underlying expando object has changed:
+ // 1) the version of the expando data changed
+ // 2) the data object is changed
+ throw Error.CollectionModifiedWhileEnumerating();
+ }
+ // Capture the value into a temp so we don't inadvertently
+ // return Uninitialized.
+ object temp = data[i];
+ if (temp != Uninitialized) {
+ yield return new KeyValuePair<string,object>(data.Class.Keys[i], temp);
+ }
+ }
+ }
+ #endregion
+
+ #region MetaExpando
+
+ private class MetaExpando : DynamicMetaObject {
+ public MetaExpando(Expression expression, ExpandoObject value)
+ : base(expression, BindingRestrictions.Empty, value) {
+ }
+
+ private DynamicMetaObject BindGetOrInvokeMember(DynamicMetaObjectBinder binder, string name, bool ignoreCase, DynamicMetaObject fallback, Func<DynamicMetaObject, DynamicMetaObject> fallbackInvoke) {
+ ExpandoClass klass = Value.Class;
+
+ //try to find the member, including the deleted members
+ int index = klass.GetValueIndex(name, ignoreCase, Value);
+
+ ParameterExpression value = Expression.Parameter(typeof(object), "value");
+
+ Expression tryGetValue = Expression.Call(
+ typeof(RuntimeOps).GetMethod("ExpandoTryGetValue"),
+ GetLimitedSelf(),
+ Expression.Constant(klass, typeof(object)),
+ Expression.Constant(index),
+ Expression.Constant(name),
+ Expression.Constant(ignoreCase),
+ value
+ );
+
+ var result = new DynamicMetaObject(value, BindingRestrictions.Empty);
+ if (fallbackInvoke != null) {
+ result = fallbackInvoke(result);
+ }
+
+ result = new DynamicMetaObject(
+ Expression.Block(
+ new[] { value },
+ Expression.Condition(
+ tryGetValue,
+ result.Expression,
+ fallback.Expression,
+ typeof(object)
+ )
+ ),
+ result.Restrictions.Merge(fallback.Restrictions)
+ );
+
+ return AddDynamicTestAndDefer(binder, Value.Class, null, result);
+ }
+
+ public override DynamicMetaObject BindGetMember(GetMemberBinder binder) {
+ ContractUtils.RequiresNotNull(binder, "binder");
+ return BindGetOrInvokeMember(
+ binder,
+ binder.Name,
+ binder.IgnoreCase,
+ binder.FallbackGetMember(this),
+ null
+ );
+ }
+
+ public override DynamicMetaObject BindInvokeMember(InvokeMemberBinder binder, DynamicMetaObject[] args) {
+ ContractUtils.RequiresNotNull(binder, "binder");
+ return BindGetOrInvokeMember(
+ binder,
+ binder.Name,
+ binder.IgnoreCase,
+ binder.FallbackInvokeMember(this, args),
+ value => binder.FallbackInvoke(value, args, null)
+ );
+ }
+
+ public override DynamicMetaObject BindSetMember(SetMemberBinder binder, DynamicMetaObject value) {
+ ContractUtils.RequiresNotNull(binder, "binder");
+ ContractUtils.RequiresNotNull(value, "value");
+
+ ExpandoClass klass;
+ int index;
+
+ ExpandoClass originalClass = GetClassEnsureIndex(binder.Name, binder.IgnoreCase, Value, out klass, out index);
+
+ return AddDynamicTestAndDefer(
+ binder,
+ klass,
+ originalClass,
+ new DynamicMetaObject(
+ Expression.Call(
+ typeof(RuntimeOps).GetMethod("ExpandoTrySetValue"),
+ GetLimitedSelf(),
+ Expression.Constant(klass, typeof(object)),
+ Expression.Constant(index),
+ Expression.Convert(value.Expression, typeof(object)),
+ Expression.Constant(binder.Name),
+ Expression.Constant(binder.IgnoreCase)
+ ),
+ BindingRestrictions.Empty
+ )
+ );
+ }
+
+ public override DynamicMetaObject BindDeleteMember(DeleteMemberBinder binder) {
+ ContractUtils.RequiresNotNull(binder, "binder");
+
+ int index = Value.Class.GetValueIndex(binder.Name, binder.IgnoreCase, Value);
+
+ Expression tryDelete = Expression.Call(
+ typeof(RuntimeOps).GetMethod("ExpandoTryDeleteValue"),
+ GetLimitedSelf(),
+ Expression.Constant(Value.Class, typeof(object)),
+ Expression.Constant(index),
+ Expression.Constant(binder.Name),
+ Expression.Constant(binder.IgnoreCase)
+ );
+ DynamicMetaObject fallback = binder.FallbackDeleteMember(this);
+
+ DynamicMetaObject target = new DynamicMetaObject(
+ Expression.IfThen(Expression.Not(tryDelete), fallback.Expression),
+ fallback.Restrictions
+ );
+
+ return AddDynamicTestAndDefer(binder, Value.Class, null, target);
+ }
+
+ public override IEnumerable<string> GetDynamicMemberNames() {
+ var expandoData = Value._data;
+ var klass = expandoData.Class;
+ for (int i = 0; i < klass.Keys.Length; i++) {
+ object val = expandoData[i];
+ if (val != ExpandoObject.Uninitialized) {
+ yield return klass.Keys[i];
+ }
+ }
+ }
+
+ /// <summary>
+ /// Adds a dynamic test which checks if the version has changed. The test is only necessary for
+ /// performance as the methods will do the correct thing if called with an incorrect version.
+ /// </summary>
+ private DynamicMetaObject AddDynamicTestAndDefer(DynamicMetaObjectBinder binder, ExpandoClass klass, ExpandoClass originalClass, DynamicMetaObject succeeds) {
+
+ Expression ifTestSucceeds = succeeds.Expression;
+ if (originalClass != null) {
+ // we are accessing a member which has not yet been defined on this class.
+ // We force a class promotion after the type check. If the class changes the
+ // promotion will fail and the set/delete will do a full lookup using the new
+ // class to discover the name.
+ Debug.Assert(originalClass != klass);
+
+ ifTestSucceeds = Expression.Block(
+ Expression.Call(
+ null,
+ typeof(RuntimeOps).GetMethod("ExpandoPromoteClass"),
+ GetLimitedSelf(),
+ Expression.Constant(originalClass, typeof(object)),
+ Expression.Constant(klass, typeof(object))
+ ),
+ succeeds.Expression
+ );
+ }
+
+ return new DynamicMetaObject(
+ Expression.Condition(
+ Expression.Call(
+ null,
+ typeof(RuntimeOps).GetMethod("ExpandoCheckVersion"),
+ GetLimitedSelf(),
+ Expression.Constant(originalClass ?? klass, typeof(object))
+ ),
+ ifTestSucceeds,
+ binder.GetUpdateExpression(ifTestSucceeds.Type)
+ ),
+ GetRestrictions().Merge(succeeds.Restrictions)
+ );
+ }
+
+ /// <summary>
+ /// Gets the class and the index associated with the given name. Does not update the expando object. Instead
+ /// this returns both the original and desired new class. A rule is created which includes the test for the
+ /// original class, the promotion to the new class, and the set/delete based on the class post-promotion.
+ /// </summary>
+ private ExpandoClass GetClassEnsureIndex(string name, bool caseInsensitive, ExpandoObject obj, out ExpandoClass klass, out int index) {
+ ExpandoClass originalClass = Value.Class;
+
+ index = originalClass.GetValueIndex(name, caseInsensitive, obj) ;
+ if (index == ExpandoObject.AmbiguousMatchFound) {
+ klass = originalClass;
+ return null;
+ }
+ if (index == ExpandoObject.NoMatch) {
+ // go ahead and find a new class now...
+ ExpandoClass newClass = originalClass.FindNewClass(name);
+
+ klass = newClass;
+ index = newClass.GetValueIndexCaseSensitive(name);
+
+ Debug.Assert(index != ExpandoObject.NoMatch);
+ return originalClass;
+ } else {
+ klass = originalClass;
+ return null;
+ }
+ }
+
+ /// <summary>
+ /// Returns our Expression converted to our known LimitType
+ /// </summary>
+ private Expression GetLimitedSelf() {
+ if (TypeUtils.AreEquivalent(Expression.Type, LimitType)) {
+ return Expression;
+ }
+ return Expression.Convert(Expression, LimitType);
+ }
+
+ /// <summary>
+ /// Returns a Restrictions object which includes our current restrictions merged
+ /// with a restriction limiting our type
+ /// </summary>
+ private BindingRestrictions GetRestrictions() {
+ Debug.Assert(Restrictions == BindingRestrictions.Empty, "We don't merge, restrictions are always empty");
+
+ return BindingRestrictions.GetTypeRestriction(this);
+ }
+
+ public new ExpandoObject Value {
+ get {
+ return (ExpandoObject)base.Value;
+ }
+ }
+ }
+
+ #endregion
+
+ #region ExpandoData
+
+ /// <summary>
+ /// Stores the class and the data associated with the class as one atomic
+ /// pair. This enables us to do a class check in a thread safe manner w/o
+ /// requiring locks.
+ /// </summary>
+ private class ExpandoData {
+ internal static ExpandoData Empty = new ExpandoData();
+
+ /// <summary>
+ /// the dynamically assigned class associated with the Expando object
+ /// </summary>
+ internal readonly ExpandoClass Class;
+
+ /// <summary>
+ /// data stored in the expando object, key names are stored in the class.
+ ///
+ /// Expando._data must be locked when mutating the value. Otherwise a copy of it
+ /// could be made and lose values.
+ /// </summary>
+ private readonly object[] _dataArray;
+
+ /// <summary>
+ /// Indexer for getting/setting the data
+ /// </summary>
+ internal object this[int index] {
+ get {
+ return _dataArray[index];
+ }
+ set {
+ //when the array is updated, version increases, even the new value is the same
+ //as previous. Dictionary type has the same behavior.
+ _version++;
+ _dataArray[index] = value;
+ }
+ }
+
+ internal int Version {
+ get { return _version; }
+ }
+
+ internal int Length {
+ get { return _dataArray.Length; }
+ }
+
+ /// <summary>
+ /// Constructs an empty ExpandoData object with the empty class and no data.
+ /// </summary>
+ private ExpandoData() {
+ Class = ExpandoClass.Empty;
+ _dataArray = new object[0];
+ }
+
+ /// <summary>
+ /// the version of the ExpandoObject that tracks set and delete operations
+ /// </summary>
+ private int _version;
+
+ /// <summary>
+ /// Constructs a new ExpandoData object with the specified class and data.
+ /// </summary>
+ internal ExpandoData(ExpandoClass klass, object[] data, int version) {
+ Class = klass;
+ _dataArray = data;
+ _version = version;
+ }
+
+ /// <summary>
+ /// Update the associated class and increases the storage for the data array if needed.
+ /// </summary>
+ /// <returns></returns>
+ internal ExpandoData UpdateClass(ExpandoClass newClass) {
+ if (_dataArray.Length >= newClass.Keys.Length) {
+ // we have extra space in our buffer, just initialize it to Uninitialized.
+ this[newClass.Keys.Length - 1] = ExpandoObject.Uninitialized;
+ return new ExpandoData(newClass, this._dataArray, this._version);
+ } else {
+ // we've grown too much - we need a new object array
+ int oldLength = _dataArray.Length;
+ object[] arr = new object[GetAlignedSize(newClass.Keys.Length)];
+ Array.Copy(_dataArray, arr, _dataArray.Length);
+ ExpandoData newData = new ExpandoData(newClass, arr, this._version);
+ newData[oldLength] = ExpandoObject.Uninitialized;
+ return newData;
+ }
+ }
+
+ private static int GetAlignedSize(int len) {
+ // the alignment of the array for storage of values (must be a power of two)
+ const int DataArrayAlignment = 8;
+
+ // round up and then mask off lower bits
+ return (len + (DataArrayAlignment - 1)) & (~(DataArrayAlignment - 1));
+ }
+ }
+
+ #endregion
+
+ #region INotifyPropertyChanged Members
+
+ event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged {
+ add { _propertyChanged += value; }
+ remove { _propertyChanged -= value; }
+ }
+
+ #endregion
+ }
+}
+
+namespace System.Runtime.CompilerServices {
+
+ //
+ // Note: these helpers are kept as simple wrappers so they have a better
+ // chance of being inlined.
+ //
+ public static partial class RuntimeOps {
+
+ /// <summary>
+ /// Gets the value of an item in an expando object.
+ /// </summary>
+ /// <param name="expando">The expando object.</param>
+ /// <param name="indexClass">The class of the expando object.</param>
+ /// <param name="index">The index of the member.</param>
+ /// <param name="name">The name of the member.</param>
+ /// <param name="ignoreCase">true if the name should be matched ignoring case; false otherwise.</param>
+ /// <param name="value">The out parameter containing the value of the member.</param>
+ /// <returns>True if the member exists in the expando object, otherwise false.</returns>
+ [Obsolete("do not use this method", true), EditorBrowsable(EditorBrowsableState.Never)]
+ public static bool ExpandoTryGetValue(ExpandoObject expando, object indexClass, int index, string name, bool ignoreCase, out object value) {
+ return expando.TryGetValue(indexClass, index, name, ignoreCase, out value);
+ }
+
+ /// <summary>
+ /// Sets the value of an item in an expando object.
+ /// </summary>
+ /// <param name="expando">The expando object.</param>
+ /// <param name="indexClass">The class of the expando object.</param>
+ /// <param name="index">The index of the member.</param>
+ /// <param name="value">The value of the member.</param>
+ /// <param name="name">The name of the member.</param>
+ /// <param name="ignoreCase">true if the name should be matched ignoring case; false otherwise.</param>
+ /// <returns>
+ /// Returns the index for the set member.
+ /// </returns>
+ [Obsolete("do not use this method", true), EditorBrowsable(EditorBrowsableState.Never)]
+ public static object ExpandoTrySetValue(ExpandoObject expando, object indexClass, int index, object value, string name, bool ignoreCase) {
+ expando.TrySetValue(indexClass, index, value, name, ignoreCase, false);
+ return value;
+ }
+
+ /// <summary>
+ /// Deletes the value of an item in an expando object.
+ /// </summary>
+ /// <param name="expando">The expando object.</param>
+ /// <param name="indexClass">The class of the expando object.</param>
+ /// <param name="index">The index of the member.</param>
+ /// <param name="name">The name of the member.</param>
+ /// <param name="ignoreCase">true if the name should be matched ignoring case; false otherwise.</param>
+ /// <returns>true if the item was successfully removed; otherwise, false.</returns>
+ [Obsolete("do not use this method", true), EditorBrowsable(EditorBrowsableState.Never)]
+ public static bool ExpandoTryDeleteValue(ExpandoObject expando, object indexClass, int index, string name, bool ignoreCase) {
+ return expando.TryDeleteValue(indexClass, index, name, ignoreCase, ExpandoObject.Uninitialized);
+ }
+
+ /// <summary>
+ /// Checks the version of the expando object.
+ /// </summary>
+ /// <param name="expando">The expando object.</param>
+ /// <param name="version">The version to check.</param>
+ /// <returns>true if the version is equal; otherwise, false.</returns>
+ [Obsolete("do not use this method", true), EditorBrowsable(EditorBrowsableState.Never)]
+ public static bool ExpandoCheckVersion(ExpandoObject expando, object version) {
+ return expando.Class == version;
+ }
+
+ /// <summary>
+ /// Promotes an expando object from one class to a new class.
+ /// </summary>
+ /// <param name="expando">The expando object.</param>
+ /// <param name="oldClass">The old class of the expando object.</param>
+ /// <param name="newClass">The new class of the expando object.</param>
+ [Obsolete("do not use this method", true), EditorBrowsable(EditorBrowsableState.Never)]
+ public static void ExpandoPromoteClass(ExpandoObject expando, object oldClass, object newClass) {
+ expando.PromoteClass(oldClass, newClass);
+ }
+ }
+}
+
diff --git a/mcs/class/dlr/Runtime/Microsoft.Scripting.Core/Ast/.gitattributes b/mcs/class/dlr/Runtime/Microsoft.Scripting.Core/Ast/.gitattributes
deleted file mode 100644
index 1dede25a279..00000000000
--- a/mcs/class/dlr/Runtime/Microsoft.Scripting.Core/Ast/.gitattributes
+++ /dev/null
@@ -1,2 +0,0 @@
-/Expression.cs -crlf
-/ListInitExpression.cs -crlf
diff --git a/mcs/class/dlr/Runtime/Microsoft.Scripting.Core/Ast/Expression.cs b/mcs/class/dlr/Runtime/Microsoft.Scripting.Core/Ast/Expression.cs
index b2ef4fc3917..045844fac73 100644
--- a/mcs/class/dlr/Runtime/Microsoft.Scripting.Core/Ast/Expression.cs
+++ b/mcs/class/dlr/Runtime/Microsoft.Scripting.Core/Ast/Expression.cs
@@ -1,419 +1,419 @@
-/* ****************************************************************************
- *
- * Copyright (c) Microsoft Corporation.
- *
- * This source code is subject to terms and conditions of the Apache License, Version 2.0. A
- * copy of the license can be found in the License.html file at the root of this distribution. If
- * you cannot locate the Apache License, Version 2.0, please send an email to
- * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
- * by the terms of the Apache License, Version 2.0.
- *
- * You must not remove this notice, or any other, from this software.
- *
- *
- * ***************************************************************************/
-
-using System;
-using System.Collections.Generic;
-using System.Collections.ObjectModel;
-using System.Dynamic.Utils;
-using System.Globalization;
-using System.IO;
-using System.Reflection;
-using System.Runtime.CompilerServices;
-using System.Threading;
-
-#if SILVERLIGHT
-using System.Core;
-#endif
-
-#if CLR2
-namespace Microsoft.Scripting.Ast {
- using Microsoft.Scripting.Utils;
-#else
-namespace System.Linq.Expressions {
-#endif
- /// <summary>
- /// The base type for all nodes in Expression Trees.
- /// </summary>
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling")]
- public abstract partial class Expression {
- private delegate LambdaExpression LambdaFactory(Expression body, string name, bool tailCall, ReadOnlyCollection<ParameterExpression> parameters);
-
- private static readonly CacheDict<Type, MethodInfo> _LambdaDelegateCache = new CacheDict<Type, MethodInfo>(40);
- private static CacheDict<Type, LambdaFactory> _LambdaFactories;
-
- // LINQ protected ctor from 3.5
-
-#if !CLR2 // needs ConditionWeakTable in 4.0
-
- // For 4.0, many frequently used Expression nodes have had their memory
- // footprint reduced by removing the Type and NodeType fields. This has
- // large performance benefits to all users of Expression Trees.
- //
- // To support the 3.5 protected constructor, we store the fields that
- // used to be here in a ConditionalWeakTable.
-
- private class ExtensionInfo {
- public ExtensionInfo(ExpressionType nodeType, Type type) {
- NodeType = nodeType;
- Type = type;
- }
-
- internal readonly ExpressionType NodeType;
- internal readonly Type Type;
- }
-
- private static ConditionalWeakTable<Expression, ExtensionInfo> _legacyCtorSupportTable;
-
- /// <summary>
- /// Constructs a new instance of <see cref="Expression"/>.
- /// </summary>
- /// <param name="nodeType">The <see ctype="ExpressionType"/> of the <see cref="Expression"/>.</param>
- /// <param name="type">The <see cref="Type"/> of the <see cref="Expression"/>.</param>
- [Obsolete("use a different constructor that does not take ExpressionType. Then override NodeType and Type properties to provide the values that would be specified to this constructor.")]
- protected Expression(ExpressionType nodeType, Type type) {
- // Can't enforce anything that V1 didn't
- if (_legacyCtorSupportTable == null) {
- Interlocked.CompareExchange(
- ref _legacyCtorSupportTable,
- new ConditionalWeakTable<Expression, ExtensionInfo>(),
- null
- );
- }
-
- _legacyCtorSupportTable.Add(this, new ExtensionInfo(nodeType, type));
- }
-#endif
-
- /// <summary>
- /// Constructs a new instance of <see cref="Expression"/>.
- /// </summary>
- protected Expression() {
- }
-
- /// <summary>
- /// The <see cref="ExpressionType"/> of the <see cref="Expression"/>.
- /// </summary>
- public virtual ExpressionType NodeType {
- get {
-#if !CLR2
- ExtensionInfo extInfo;
- if (_legacyCtorSupportTable != null && _legacyCtorSupportTable.TryGetValue(this, out extInfo)) {
- return extInfo.NodeType;
- }
-#endif
- // the extension expression failed to override NodeType
- throw Error.ExtensionNodeMustOverrideProperty("Expression.NodeType");
- }
- }
-
-
- /// <summary>
- /// The <see cref="Type"/> of the value represented by this <see cref="Expression"/>.
- /// </summary>
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods")]
- public virtual Type Type {
- get {
-#if !CLR2
- ExtensionInfo extInfo;
- if (_legacyCtorSupportTable != null && _legacyCtorSupportTable.TryGetValue(this, out extInfo)) {
- return extInfo.Type;
- }
-#endif
- // the extension expression failed to override Type
- throw Error.ExtensionNodeMustOverrideProperty("Expression.Type");
- }
- }
-
- /// <summary>
- /// Indicates that the node can be reduced to a simpler node. If this
- /// returns true, Reduce() can be called to produce the reduced form.
- /// </summary>
- public virtual bool CanReduce {
- get { return false; }
- }
-
- /// <summary>
- /// Reduces this node to a simpler expression. If CanReduce returns
- /// true, this should return a valid expression. This method is
- /// allowed to return another node which itself must be reduced.
- /// </summary>
- /// <returns>The reduced expression.</returns>
- public virtual Expression Reduce() {
- if (CanReduce) throw Error.ReducibleMustOverrideReduce();
- return this;
- }
-
- /// <summary>
- /// Reduces the node and then calls the visitor delegate on the reduced expression.
- /// Throws an exception if the node isn't reducible.
- /// </summary>
- /// <param name="visitor">An instance of <see cref="Func{Expression, Expression}"/>.</param>
- /// <returns>The expression being visited, or an expression which should replace it in the tree.</returns>
- /// <remarks>
- /// Override this method to provide logic to walk the node's children.
- /// A typical implementation will call visitor.Visit on each of its
- /// children, and if any of them change, should return a new copy of
- /// itself with the modified children.
- /// </remarks>
- protected internal virtual Expression VisitChildren(ExpressionVisitor visitor) {
- if (!CanReduce) throw Error.MustBeReducible();
- return visitor.Visit(ReduceAndCheck());
- }
-
- /// <summary>
- /// Dispatches to the specific visit method for this node type. For
- /// example, <see cref="MethodCallExpression" /> will call into
- /// <see cref="ExpressionVisitor.VisitMethodCall" />.
- /// </summary>
- /// <param name="visitor">The visitor to visit this node with.</param>
- /// <returns>The result of visiting this node.</returns>
- /// <remarks>
- /// This default implementation for <see cref="ExpressionType.Extension" />
- /// nodes will call <see cref="ExpressionVisitor.VisitExtension" />.
- /// Override this method to call into a more specific method on a derived
- /// visitor class of ExprressionVisitor. However, it should still
- /// support unknown visitors by calling VisitExtension.
- /// </remarks>
- protected internal virtual Expression Accept(ExpressionVisitor visitor) {
- return visitor.VisitExtension(this);
- }
-
- /// <summary>
- /// Reduces this node to a simpler expression. If CanReduce returns
- /// true, this should return a valid expression. This method is
- /// allowed to return another node which itself must be reduced.
- /// </summary>
- /// <returns>The reduced expression.</returns>
- /// <remarks >
- /// Unlike Reduce, this method checks that the reduced node satisfies
- /// certain invariants.
- /// </remarks>
- public Expression ReduceAndCheck() {
- if (!CanReduce) throw Error.MustBeReducible();
-
- var newNode = Reduce();
-
- // 1. Reduction must return a new, non-null node
- // 2. Reduction must return a new node whose result type can be assigned to the type of the original node
- if (newNode == null || newNode == this) throw Error.MustReduceToDifferent();
- if (!TypeUtils.AreReferenceAssignable(Type, newNode.Type)) throw Error.ReducedNotCompatible();
- return newNode;
- }
-
- /// <summary>
- /// Reduces the expression to a known node type (i.e. not an Extension node)
- /// or simply returns the expression if it is already a known type.
- /// </summary>
- /// <returns>The reduced expression.</returns>
- public Expression ReduceExtensions() {
- var node = this;
- while (node.NodeType == ExpressionType.Extension) {
- node = node.ReduceAndCheck();
- }
- return node;
- }
-
-
- /// <summary>
- /// Creates a <see cref="String"/> representation of the Expression.
- /// </summary>
- /// <returns>A <see cref="String"/> representation of the Expression.</returns>
- public override string ToString() {
- return ExpressionStringBuilder.ExpressionToString(this);
- }
-
-#if CLR2
- /// <summary>
- /// Writes a <see cref="String"/> representation of the <see cref="Expression"/> to a <see cref="TextWriter"/>.
- /// </summary>
- /// <param name="writer">A <see cref="TextWriter"/> that will be used to build the string representation.</param>
- public void DumpExpression(TextWriter writer) {
- DebugViewWriter.WriteTo(this, writer);
- }
-
- /// <summary>
- /// Creates a <see cref="String"/> representation of the Expression.
- /// </summary>
- /// <returns>A <see cref="String"/> representation of the Expression.</returns>
- public string DebugView {
-#else
- private string DebugView {
-#endif
- get {
- using (System.IO.StringWriter writer = new System.IO.StringWriter(CultureInfo.CurrentCulture)) {
- DebugViewWriter.WriteTo(this, writer);
- return writer.ToString();
- }
- }
- }
-
- /// <summary>
- /// Helper used for ensuring we only return 1 instance of a ReadOnlyCollection of T.
- ///
- /// This is called from various methods where we internally hold onto an IList of T
- /// or a readonly collection of T. We check to see if we've already returned a
- /// readonly collection of T and if so simply return the other one. Otherwise we do
- /// a thread-safe replacement of the list w/ a readonly collection which wraps it.
- ///
- /// Ultimately this saves us from having to allocate a ReadOnlyCollection for our
- /// data types because the compiler is capable of going directly to the IList of T.
- /// </summary>
- internal static ReadOnlyCollection<T> ReturnReadOnly<T>(ref IList<T> collection) {
- IList<T> value = collection;
-
- // if it's already read-only just return it.
- ReadOnlyCollection<T> res = value as ReadOnlyCollection<T>;
- if (res != null) {
- return res;
- }
-
- // otherwise make sure only readonly collection every gets exposed
- Interlocked.CompareExchange<IList<T>>(
- ref collection,
- value.ToReadOnly(),
- value
- );
-
- // and return it
- return (ReadOnlyCollection<T>)collection;
- }
-
- /// <summary>
- /// Helper used for ensuring we only return 1 instance of a ReadOnlyCollection of T.
- ///
- /// This is similar to the ReturnReadOnly of T. This version supports nodes which hold
- /// onto multiple Expressions where one is typed to object. That object field holds either
- /// an expression or a ReadOnlyCollection of Expressions. When it holds a ReadOnlyCollection
- /// the IList which backs it is a ListArgumentProvider which uses the Expression which
- /// implements IArgumentProvider to get 2nd and additional values. The ListArgumentProvider
- /// continues to hold onto the 1st expression.
- ///
- /// This enables users to get the ReadOnlyCollection w/o it consuming more memory than if
- /// it was just an array. Meanwhile The DLR internally avoids accessing which would force
- /// the readonly collection to be created resulting in a typical memory savings.
- /// </summary>
- internal static ReadOnlyCollection<Expression> ReturnReadOnly(IArgumentProvider provider, ref object collection) {
- Expression tObj = collection as Expression;
- if (tObj != null) {
- // otherwise make sure only one readonly collection ever gets exposed
- Interlocked.CompareExchange(
- ref collection,
- new ReadOnlyCollection<Expression>(new ListArgumentProvider(provider, tObj)),
- tObj
- );
- }
-
- // and return what is not guaranteed to be a readonly collection
- return (ReadOnlyCollection<Expression>)collection;
- }
-
- /// <summary>
- /// Helper which is used for specialized subtypes which use ReturnReadOnly(ref object, ...).
- /// This is the reverse version of ReturnReadOnly which takes an IArgumentProvider.
- ///
- /// This is used to return the 1st argument. The 1st argument is typed as object and either
- /// contains a ReadOnlyCollection or the Expression. We check for the Expression and if it's
- /// present we return that, otherwise we return the 1st element of the ReadOnlyCollection.
- /// </summary>
- internal static T ReturnObject<T>(object collectionOrT) where T : class {
- T t = collectionOrT as T;
- if (t != null) {
- return t;
- }
-
- return ((ReadOnlyCollection<T>)collectionOrT)[0];
- }
-
-#if SILVERLIGHT
-#if !CLR2
- // Quirks mode for Expression Trees as they existed in Silverlight 2 and 3
- internal readonly static bool SilverlightQuirks =
- AppDomain.CurrentDomain.IsCompatibilitySwitchSet("APP_EARLIER_THAN_SL4.0").GetValueOrDefault();
-#else
- internal readonly static bool SilverlightQuirks = true;
-#endif
-#endif
-
- private static void RequiresCanRead(Expression expression, string paramName) {
- if (expression == null) {
- throw new ArgumentNullException(paramName);
- }
-
- // validate that we can read the node
- switch (expression.NodeType) {
- case ExpressionType.Index:
- IndexExpression index = (IndexExpression)expression;
- if (index.Indexer != null && !index.Indexer.CanRead) {
- throw new ArgumentException(Strings.ExpressionMustBeReadable, paramName);
- }
- break;
- case ExpressionType.MemberAccess:
- MemberExpression member = (MemberExpression)expression;
- MemberInfo memberInfo = member.Member;
- if (memberInfo.MemberType == MemberTypes.Property) {
- PropertyInfo prop = (PropertyInfo)memberInfo;
- if (!prop.CanRead) {
- throw new ArgumentException(Strings.ExpressionMustBeReadable, paramName);
- }
- }
- break;
- }
- }
-
- private static void RequiresCanRead(IEnumerable<Expression> items, string paramName) {
- if (items != null) {
- // this is called a lot, avoid allocating an enumerator if we can...
- IList<Expression> listItems = items as IList<Expression>;
- if (listItems != null) {
- for (int i = 0; i < listItems.Count; i++) {
- RequiresCanRead(listItems[i], paramName);
- }
- return;
- }
-
- foreach (var i in items) {
- RequiresCanRead(i, paramName);
- }
- }
- }
- private static void RequiresCanWrite(Expression expression, string paramName) {
- if (expression == null) {
- throw new ArgumentNullException(paramName);
- }
-
- bool canWrite = false;
- switch (expression.NodeType) {
- case ExpressionType.Index:
- IndexExpression index = (IndexExpression)expression;
- if (index.Indexer != null) {
- canWrite = index.Indexer.CanWrite;
- } else {
- canWrite = true;
- }
- break;
- case ExpressionType.MemberAccess:
- MemberExpression member = (MemberExpression)expression;
- switch (member.Member.MemberType) {
- case MemberTypes.Property:
- PropertyInfo prop = (PropertyInfo)member.Member;
- canWrite = prop.CanWrite;
- break;
- case MemberTypes.Field:
- FieldInfo field = (FieldInfo)member.Member;
- canWrite = !(field.IsInitOnly || field.IsLiteral);
- break;
- }
- break;
- case ExpressionType.Parameter:
- canWrite = true;
- break;
- }
-
- if (!canWrite) {
- throw new ArgumentException(Strings.ExpressionMustBeWriteable, paramName);
- }
- }
- }
-}
+/* ****************************************************************************
+ *
+ * Copyright (c) Microsoft Corporation.
+ *
+ * This source code is subject to terms and conditions of the Apache License, Version 2.0. A
+ * copy of the license can be found in the License.html file at the root of this distribution. If
+ * you cannot locate the Apache License, Version 2.0, please send an email to
+ * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
+ * by the terms of the Apache License, Version 2.0.
+ *
+ * You must not remove this notice, or any other, from this software.
+ *
+ *
+ * ***************************************************************************/
+
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Dynamic.Utils;
+using System.Globalization;
+using System.IO;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Threading;
+
+#if SILVERLIGHT
+using System.Core;
+#endif
+
+#if CLR2
+namespace Microsoft.Scripting.Ast {
+ using Microsoft.Scripting.Utils;
+#else
+namespace System.Linq.Expressions {
+#endif
+ /// <summary>
+ /// The base type for all nodes in Expression Trees.
+ /// </summary>
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling")]
+ public abstract partial class Expression {
+ private delegate LambdaExpression LambdaFactory(Expression body, string name, bool tailCall, ReadOnlyCollection<ParameterExpression> parameters);
+
+ private static readonly CacheDict<Type, MethodInfo> _LambdaDelegateCache = new CacheDict<Type, MethodInfo>(40);
+ private static CacheDict<Type, LambdaFactory> _LambdaFactories;
+
+ // LINQ protected ctor from 3.5
+
+#if !CLR2 // needs ConditionWeakTable in 4.0
+
+ // For 4.0, many frequently used Expression nodes have had their memory
+ // footprint reduced by removing the Type and NodeType fields. This has
+ // large performance benefits to all users of Expression Trees.
+ //
+ // To support the 3.5 protected constructor, we store the fields that
+ // used to be here in a ConditionalWeakTable.
+
+ private class ExtensionInfo {
+ public ExtensionInfo(ExpressionType nodeType, Type type) {
+ NodeType = nodeType;
+ Type = type;
+ }
+
+ internal readonly ExpressionType NodeType;
+ internal readonly Type Type;
+ }
+
+ private static ConditionalWeakTable<Expression, ExtensionInfo> _legacyCtorSupportTable;
+
+ /// <summary>
+ /// Constructs a new instance of <see cref="Expression"/>.
+ /// </summary>
+ /// <param name="nodeType">The <see ctype="ExpressionType"/> of the <see cref="Expression"/>.</param>
+ /// <param name="type">The <see cref="Type"/> of the <see cref="Expression"/>.</param>
+ [Obsolete("use a different constructor that does not take ExpressionType. Then override NodeType and Type properties to provide the values that would be specified to this constructor.")]
+ protected Expression(ExpressionType nodeType, Type type) {
+ // Can't enforce anything that V1 didn't
+ if (_legacyCtorSupportTable == null) {
+ Interlocked.CompareExchange(
+ ref _legacyCtorSupportTable,
+ new ConditionalWeakTable<Expression, ExtensionInfo>(),
+ null
+ );
+ }
+
+ _legacyCtorSupportTable.Add(this, new ExtensionInfo(nodeType, type));
+ }
+#endif
+
+ /// <summary>
+ /// Constructs a new instance of <see cref="Expression"/>.
+ /// </summary>
+ protected Expression() {
+ }
+
+ /// <summary>
+ /// The <see cref="ExpressionType"/> of the <see cref="Expression"/>.
+ /// </summary>
+ public virtual ExpressionType NodeType {
+ get {
+#if !CLR2
+ ExtensionInfo extInfo;
+ if (_legacyCtorSupportTable != null && _legacyCtorSupportTable.TryGetValue(this, out extInfo)) {
+ return extInfo.NodeType;
+ }
+#endif
+ // the extension expression failed to override NodeType
+ throw Error.ExtensionNodeMustOverrideProperty("Expression.NodeType");
+ }
+ }
+
+
+ /// <summary>
+ /// The <see cref="Type"/> of the value represented by this <see cref="Expression"/>.
+ /// </summary>
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods")]
+ public virtual Type Type {
+ get {
+#if !CLR2
+ ExtensionInfo extInfo;
+ if (_legacyCtorSupportTable != null && _legacyCtorSupportTable.TryGetValue(this, out extInfo)) {
+ return extInfo.Type;
+ }
+#endif
+ // the extension expression failed to override Type
+ throw Error.ExtensionNodeMustOverrideProperty("Expression.Type");
+ }
+ }
+
+ /// <summary>
+ /// Indicates that the node can be reduced to a simpler node. If this
+ /// returns true, Reduce() can be called to produce the reduced form.
+ /// </summary>
+ public virtual bool CanReduce {
+ get { return false; }
+ }
+
+ /// <summary>
+ /// Reduces this node to a simpler expression. If CanReduce returns
+ /// true, this should return a valid expression. This method is
+ /// allowed to return another node which itself must be reduced.
+ /// </summary>
+ /// <returns>The reduced expression.</returns>
+ public virtual Expression Reduce() {
+ if (CanReduce) throw Error.ReducibleMustOverrideReduce();
+ return this;
+ }
+
+ /// <summary>
+ /// Reduces the node and then calls the visitor delegate on the reduced expression.
+ /// Throws an exception if the node isn't reducible.
+ /// </summary>
+ /// <param name="visitor">An instance of <see cref="Func{Expression, Expression}"/>.</param>
+ /// <returns>The expression being visited, or an expression which should replace it in the tree.</returns>
+ /// <remarks>
+ /// Override this method to provide logic to walk the node's children.
+ /// A typical implementation will call visitor.Visit on each of its
+ /// children, and if any of them change, should return a new copy of
+ /// itself with the modified children.
+ /// </remarks>
+ protected internal virtual Expression VisitChildren(ExpressionVisitor visitor) {
+ if (!CanReduce) throw Error.MustBeReducible();
+ return visitor.Visit(ReduceAndCheck());
+ }
+
+ /// <summary>
+ /// Dispatches to the specific visit method for this node type. For
+ /// example, <see cref="MethodCallExpression" /> will call into
+ /// <see cref="ExpressionVisitor.VisitMethodCall" />.
+ /// </summary>
+ /// <param name="visitor">The visitor to visit this node with.</param>
+ /// <returns>The result of visiting this node.</returns>
+ /// <remarks>
+ /// This default implementation for <see cref="ExpressionType.Extension" />
+ /// nodes will call <see cref="ExpressionVisitor.VisitExtension" />.
+ /// Override this method to call into a more specific method on a derived
+ /// visitor class of ExprressionVisitor. However, it should still
+ /// support unknown visitors by calling VisitExtension.
+ /// </remarks>
+ protected internal virtual Expression Accept(ExpressionVisitor visitor) {
+ return visitor.VisitExtension(this);
+ }
+
+ /// <summary>
+ /// Reduces this node to a simpler expression. If CanReduce returns
+ /// true, this should return a valid expression. This method is
+ /// allowed to return another node which itself must be reduced.
+ /// </summary>
+ /// <returns>The reduced expression.</returns>
+ /// <remarks >
+ /// Unlike Reduce, this method checks that the reduced node satisfies
+ /// certain invariants.
+ /// </remarks>
+ public Expression ReduceAndCheck() {
+ if (!CanReduce) throw Error.MustBeReducible();
+
+ var newNode = Reduce();
+
+ // 1. Reduction must return a new, non-null node
+ // 2. Reduction must return a new node whose result type can be assigned to the type of the original node
+ if (newNode == null || newNode == this) throw Error.MustReduceToDifferent();
+ if (!TypeUtils.AreReferenceAssignable(Type, newNode.Type)) throw Error.ReducedNotCompatible();
+ return newNode;
+ }
+
+ /// <summary>
+ /// Reduces the expression to a known node type (i.e. not an Extension node)
+ /// or simply returns the expression if it is already a known type.
+ /// </summary>
+ /// <returns>The reduced expression.</returns>
+ public Expression ReduceExtensions() {
+ var node = this;
+ while (node.NodeType == ExpressionType.Extension) {
+ node = node.ReduceAndCheck();
+ }
+ return node;
+ }
+
+
+ /// <summary>
+ /// Creates a <see cref="String"/> representation of the Expression.
+ /// </summary>
+ /// <returns>A <see cref="String"/> representation of the Expression.</returns>
+ public override string ToString() {
+ return ExpressionStringBuilder.ExpressionToString(this);
+ }
+
+#if CLR2
+ /// <summary>
+ /// Writes a <see cref="String"/> representation of the <see cref="Expression"/> to a <see cref="TextWriter"/>.
+ /// </summary>
+ /// <param name="writer">A <see cref="TextWriter"/> that will be used to build the string representation.</param>
+ public void DumpExpression(TextWriter writer) {
+ DebugViewWriter.WriteTo(this, writer);
+ }
+
+ /// <summary>
+ /// Creates a <see cref="String"/> representation of the Expression.
+ /// </summary>
+ /// <returns>A <see cref="String"/> representation of the Expression.</returns>
+ public string DebugView {
+#else
+ private string DebugView {
+#endif
+ get {
+ using (System.IO.StringWriter writer = new System.IO.StringWriter(CultureInfo.CurrentCulture)) {
+ DebugViewWriter.WriteTo(this, writer);
+ return writer.ToString();
+ }
+ }
+ }
+
+ /// <summary>
+ /// Helper used for ensuring we only return 1 instance of a ReadOnlyCollection of T.
+ ///
+ /// This is called from various methods where we internally hold onto an IList of T
+ /// or a readonly collection of T. We check to see if we've already returned a
+ /// readonly collection of T and if so simply return the other one. Otherwise we do
+ /// a thread-safe replacement of the list w/ a readonly collection which wraps it.
+ ///
+ /// Ultimately this saves us from having to allocate a ReadOnlyCollection for our
+ /// data types because the compiler is capable of going directly to the IList of T.
+ /// </summary>
+ internal static ReadOnlyCollection<T> ReturnReadOnly<T>(ref IList<T> collection) {
+ IList<T> value = collection;
+
+ // if it's already read-only just return it.
+ ReadOnlyCollection<T> res = value as ReadOnlyCollection<T>;
+ if (res != null) {
+ return res;
+ }
+
+ // otherwise make sure only readonly collection every gets exposed
+ Interlocked.CompareExchange<IList<T>>(
+ ref collection,
+ value.ToReadOnly(),
+ value
+ );
+
+ // and return it
+ return (ReadOnlyCollection<T>)collection;
+ }
+
+ /// <summary>
+ /// Helper used for ensuring we only return 1 instance of a ReadOnlyCollection of T.
+ ///
+ /// This is similar to the ReturnReadOnly of T. This version supports nodes which hold
+ /// onto multiple Expressions where one is typed to object. That object field holds either
+ /// an expression or a ReadOnlyCollection of Expressions. When it holds a ReadOnlyCollection
+ /// the IList which backs it is a ListArgumentProvider which uses the Expression which
+ /// implements IArgumentProvider to get 2nd and additional values. The ListArgumentProvider
+ /// continues to hold onto the 1st expression.
+ ///
+ /// This enables users to get the ReadOnlyCollection w/o it consuming more memory than if
+ /// it was just an array. Meanwhile The DLR internally avoids accessing which would force
+ /// the readonly collection to be created resulting in a typical memory savings.
+ /// </summary>
+ internal static ReadOnlyCollection<Expression> ReturnReadOnly(IArgumentProvider provider, ref object collection) {
+ Expression tObj = collection as Expression;
+ if (tObj != null) {
+ // otherwise make sure only one readonly collection ever gets exposed
+ Interlocked.CompareExchange(
+ ref collection,
+ new ReadOnlyCollection<Expression>(new ListArgumentProvider(provider, tObj)),
+ tObj
+ );
+ }
+
+ // and return what is not guaranteed to be a readonly collection
+ return (ReadOnlyCollection<Expression>)collection;
+ }
+
+ /// <summary>
+ /// Helper which is used for specialized subtypes which use ReturnReadOnly(ref object, ...).
+ /// This is the reverse version of ReturnReadOnly which takes an IArgumentProvider.
+ ///
+ /// This is used to return the 1st argument. The 1st argument is typed as object and either
+ /// contains a ReadOnlyCollection or the Expression. We check for the Expression and if it's
+ /// present we return that, otherwise we return the 1st element of the ReadOnlyCollection.
+ /// </summary>
+ internal static T ReturnObject<T>(object collectionOrT) where T : class {
+ T t = collectionOrT as T;
+ if (t != null) {
+ return t;
+ }
+
+ return ((ReadOnlyCollection<T>)collectionOrT)[0];
+ }
+
+#if SILVERLIGHT
+#if !CLR2
+ // Quirks mode for Expression Trees as they existed in Silverlight 2 and 3
+ internal readonly static bool SilverlightQuirks =
+ AppDomain.CurrentDomain.IsCompatibilitySwitchSet("APP_EARLIER_THAN_SL4.0").GetValueOrDefault();
+#else
+ internal readonly static bool SilverlightQuirks = true;
+#endif
+#endif
+
+ private static void RequiresCanRead(Expression expression, string paramName) {
+ if (expression == null) {
+ throw new ArgumentNullException(paramName);
+ }
+
+ // validate that we can read the node
+ switch (expression.NodeType) {
+ case ExpressionType.Index:
+ IndexExpression index = (IndexExpression)expression;
+ if (index.Indexer != null && !index.Indexer.CanRead) {
+ throw new ArgumentException(Strings.ExpressionMustBeReadable, paramName);
+ }
+ break;
+ case ExpressionType.MemberAccess:
+ MemberExpression member = (MemberExpression)expression;
+ MemberInfo memberInfo = member.Member;
+ if (memberInfo.MemberType == MemberTypes.Property) {
+ PropertyInfo prop = (PropertyInfo)memberInfo;
+ if (!prop.CanRead) {
+ throw new ArgumentException(Strings.ExpressionMustBeReadable, paramName);
+ }
+ }
+ break;
+ }
+ }
+
+ private static void RequiresCanRead(IEnumerable<Expression> items, string paramName) {
+ if (items != null) {
+ // this is called a lot, avoid allocating an enumerator if we can...
+ IList<Expression> listItems = items as IList<Expression>;
+ if (listItems != null) {
+ for (int i = 0; i < listItems.Count; i++) {
+ RequiresCanRead(listItems[i], paramName);
+ }
+ return;
+ }
+
+ foreach (var i in items) {
+ RequiresCanRead(i, paramName);
+ }
+ }
+ }
+ private static void RequiresCanWrite(Expression expression, string paramName) {
+ if (expression == null) {
+ throw new ArgumentNullException(paramName);
+ }
+
+ bool canWrite = false;
+ switch (expression.NodeType) {
+ case ExpressionType.Index:
+ IndexExpression index = (IndexExpression)expression;
+ if (index.Indexer != null) {
+ canWrite = index.Indexer.CanWrite;
+ } else {
+ canWrite = true;
+ }
+ break;
+ case ExpressionType.MemberAccess:
+ MemberExpression member = (MemberExpression)expression;
+ switch (member.Member.MemberType) {
+ case MemberTypes.Property:
+ PropertyInfo prop = (PropertyInfo)member.Member;
+ canWrite = prop.CanWrite;
+ break;
+ case MemberTypes.Field:
+ FieldInfo field = (FieldInfo)member.Member;
+ canWrite = !(field.IsInitOnly || field.IsLiteral);
+ break;
+ }
+ break;
+ case ExpressionType.Parameter:
+ canWrite = true;
+ break;
+ }
+
+ if (!canWrite) {
+ throw new ArgumentException(Strings.ExpressionMustBeWriteable, paramName);
+ }
+ }
+ }
+}
diff --git a/mcs/class/dlr/Runtime/Microsoft.Scripting.Core/Ast/ListInitExpression.cs b/mcs/class/dlr/Runtime/Microsoft.Scripting.Core/Ast/ListInitExpression.cs
index 71bd0f6c1c4..0b8125a7086 100644
--- a/mcs/class/dlr/Runtime/Microsoft.Scripting.Core/Ast/ListInitExpression.cs
+++ b/mcs/class/dlr/Runtime/Microsoft.Scripting.Core/Ast/ListInitExpression.cs
@@ -1,237 +1,237 @@
-/* ****************************************************************************
- *
- * Copyright (c) Microsoft Corporation.
- *
- * This source code is subject to terms and conditions of the Apache License, Version 2.0. A
- * copy of the license can be found in the License.html file at the root of this distribution. If
- * you cannot locate the Apache License, Version 2.0, please send an email to
- * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
- * by the terms of the Apache License, Version 2.0.
- *
- * You must not remove this notice, or any other, from this software.
- *
- *
- * ***************************************************************************/
-
-using System;
-using System.Collections.Generic;
-using System.Collections.ObjectModel;
-using System.Diagnostics;
-using System.Dynamic.Utils;
-using System.Reflection;
-using System.Runtime.CompilerServices;
-
-#if SILVERLIGHT
-using System.Core;
-#endif
-
-#if CLR2
-namespace Microsoft.Scripting.Ast {
-#else
-namespace System.Linq.Expressions {
-#endif
- /// <summary>
- /// Represents a constructor call that has a collection initializer.
- /// </summary>
- /// <remarks>
- /// Use the <see cref="M:ListInit"/> factory methods to create a ListInitExpression.
- /// The value of the NodeType property of a ListInitExpression is ListInit.
- /// </remarks>
-#if !SILVERLIGHT
- [DebuggerTypeProxy(typeof(Expression.ListInitExpressionProxy))]
-#endif
- public sealed class ListInitExpression : Expression {
- private readonly NewExpression _newExpression;
- private readonly ReadOnlyCollection<ElementInit> _initializers;
-
- internal ListInitExpression(NewExpression newExpression, ReadOnlyCollection<ElementInit> initializers) {
- _newExpression = newExpression;
- _initializers = initializers;
- }
-
- /// <summary>
- /// Returns the node type of this <see cref="Expression"/>. (Inherited from <see cref="Expression" />.)
- /// </summary>
- /// <returns>The <see cref="ExpressionType"/> that represents this expression.</returns>
- public sealed override ExpressionType NodeType {
- get { return ExpressionType.ListInit; }
- }
-
- /// <summary>
- /// Gets the static type of the expression that this <see cref="Expression" /> represents. (Inherited from <see cref="Expression"/>.)
- /// </summary>
- /// <returns>The <see cref="Type"/> that represents the static type of the expression.</returns>
- public sealed override Type Type {
- get { return _newExpression.Type; }
- }
-
- /// <summary>
- /// Gets a value that indicates whether the expression tree node can be reduced.
- /// </summary>
- public override bool CanReduce {
- get {
- return true;
- }
- }
-
- /// <summary>
- /// Gets the expression that contains a call to the constructor of a collection type.
- /// </summary>
- public NewExpression NewExpression {
- get { return _newExpression; }
- }
-
- /// <summary>
- /// Gets the element initializers that are used to initialize a collection.
- /// </summary>
- public ReadOnlyCollection<ElementInit> Initializers {
- get { return _initializers; }
- }
-
- /// <summary>
- /// Dispatches to the specific visit method for this node type.
- /// </summary>
- protected internal override Expression Accept(ExpressionVisitor visitor) {
- return visitor.VisitListInit(this);
- }
-
- /// <summary>
- /// Reduces the binary expression node to a simpler expression.
- /// If CanReduce returns true, this should return a valid expression.
- /// This method is allowed to return another node which itself
- /// must be reduced.
- /// </summary>
- /// <returns>The reduced expression.</returns>
- public override Expression Reduce() {
- return MemberInitExpression.ReduceListInit(_newExpression, _initializers, true);
- }
-
- /// <summary>
- /// Creates a new expression that is like this one, but using the
- /// supplied children. If all of the children are the same, it will
- /// return this expression.
- /// </summary>
- /// <param name="newExpression">The <see cref="NewExpression" /> property of the result.</param>
- /// <param name="initializers">The <see cref="Initializers" /> property of the result.</param>
- /// <returns>This expression if no children changed, or an expression with the updated children.</returns>
- public ListInitExpression Update(NewExpression newExpression, IEnumerable<ElementInit> initializers) {
- if (newExpression == NewExpression && initializers == Initializers) {
- return this;
- }
- return Expression.ListInit(newExpression, initializers);
- }
- }
-
-
- public partial class Expression {
- /// <summary>
- /// Creates a <see cref="ListInitExpression"/> that uses a method named "Add" to add elements to a collection.
- /// </summary>
- /// <param name="newExpression">A <see cref="NewExpression"/> to set the <see cref="P:ListInitExpression.NewExpression"/> property equal to.</param>
- /// <param name="initializers">An array of <see cref="Expression"/> objects to use to populate the <see cref="ListInitExpression.Initializers"/> collection.</param>
- /// <returns>A <see cref="ListInitExpression"/> that has the <see cref="P:ListInitExpression.NodeType"/> property equal to ListInit and the <see cref="P:ListInitExpression.NewExpression"/> property set to the specified value.</returns>
- public static ListInitExpression ListInit(NewExpression newExpression, params Expression[] initializers) {
- ContractUtils.RequiresNotNull(newExpression, "newExpression");
- ContractUtils.RequiresNotNull(initializers, "initializers");
- return ListInit(newExpression, initializers as IEnumerable<Expression>);
- }
-
- /// <summary>
- /// Creates a <see cref="ListInitExpression"/> that uses a method named "Add" to add elements to a collection.
- /// </summary>
- /// <param name="newExpression">A <see cref="NewExpression"/> to set the <see cref="P:ListInitExpression.NewExpression"/> property equal to.</param>
- /// <param name="initializers">An <see cref="IEnumerable{T}"/> that contains <see cref="M:ElementInit"/> objects to use to populate the <see cref="ListInitExpression.Initializers"/> collection.</param>
- /// <returns>A <see cref="ListInitExpression"/> that has the <see cref="P:ListInitExpression.NodeType"/> property equal to ListInit and the <see cref="P:ListInitExpression.NewExpression"/> property set to the specified value.</returns>
- public static ListInitExpression ListInit(NewExpression newExpression, IEnumerable<Expression> initializers) {
- ContractUtils.RequiresNotNull(newExpression, "newExpression");
- ContractUtils.RequiresNotNull(initializers, "initializers");
-
- var initializerlist = initializers.ToReadOnly();
- if (initializerlist.Count == 0) {
- throw Error.ListInitializerWithZeroMembers();
- }
-
- MethodInfo addMethod = FindMethod(newExpression.Type, "Add", null, new Expression[] { initializerlist[0] }, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
- return ListInit(newExpression, addMethod, initializers);
- }
-
- /// <summary>
- /// Creates a <see cref="ListInitExpression"/> that uses a specified method to add elements to a collection.
- /// </summary>
- /// <param name="newExpression">A <see cref="NewExpression"/> to set the <see cref="P:ListInitExpression.NewExpression"/> property equal to.</param>
- /// <param name="addMethod">A <see cref="MethodInfo"/> that represents an instance method named "Add" (case insensitive), that adds an element to a collection. </param>
- /// <param name="initializers">An array of <see cref="Expression"/> objects to use to populate the <see cref="ListInitExpression.Initializers"/> collection.</param>
- /// <returns>A <see cref="ListInitExpression"/> that has the <see cref="P:ListInitExpression.NodeType"/> property equal to ListInit and the <see cref="P:ListInitExpression.NewExpression"/> property set to the specified value.</returns>
- public static ListInitExpression ListInit(NewExpression newExpression, MethodInfo addMethod, params Expression[] initializers) {
- if (addMethod == null) {
- return ListInit(newExpression, initializers as IEnumerable<Expression>);
- }
- ContractUtils.RequiresNotNull(newExpression, "newExpression");
- ContractUtils.RequiresNotNull(initializers, "initializers");
- return ListInit(newExpression, addMethod, initializers as IEnumerable<Expression>);
- }
-
- /// <summary>
- /// Creates a <see cref="ListInitExpression"/> that uses a specified method to add elements to a collection.
- /// </summary>
- /// <param name="newExpression">A <see cref="NewExpression"/> to set the <see cref="P:ListInitExpression.NewExpression"/> property equal to.</param>
- /// <param name="addMethod">A <see cref="MethodInfo"/> that represents an instance method named "Add" (case insensitive), that adds an element to a collection. </param>
- /// <param name="initializers">An <see cref="IEnumerable{T}"/> that contains <see cref="Expression"/> objects to use to populate the Initializers collection.</param>
- /// <returns>A <see cref="ListInitExpression"/> that has the <see cref="P:ListInitExpression.NodeType"/> property equal to ListInit and the <see cref="P:ListInitExpression.NewExpression"/> property set to the specified value.</returns>
- public static ListInitExpression ListInit(NewExpression newExpression, MethodInfo addMethod, IEnumerable<Expression> initializers) {
- if (addMethod == null) {
- return ListInit(newExpression, initializers);
- }
- ContractUtils.RequiresNotNull(newExpression, "newExpression");
- ContractUtils.RequiresNotNull(initializers, "initializers");
-
- var initializerlist = initializers.ToReadOnly();
- if (initializerlist.Count == 0) {
- throw Error.ListInitializerWithZeroMembers();
- }
- ElementInit[] initList = new ElementInit[initializerlist.Count];
- for (int i = 0; i < initializerlist.Count; i++) {
- initList[i] = ElementInit(addMethod, initializerlist[i]);
- }
- return ListInit(newExpression, new TrueReadOnlyCollection<ElementInit>(initList));
- }
-
- /// <summary>
- /// Creates a <see cref="ListInitExpression"/> that uses specified <see cref="M:ElementInit"/> objects to initialize a collection.
- /// </summary>
- /// <param name="newExpression">A <see cref="NewExpression"/> to set the <see cref="P:ListInitExpression.NewExpression"/> property equal to.</param>
- /// <param name="initializers">An array that contains <see cref="M:ElementInit"/> objects to use to populate the <see cref="ListInitExpression.Initializers"/> collection.</param>
- /// <returns>
- /// A <see cref="ListInitExpression"/> that has the <see cref="P:Expressions.NodeType"/> property equal to ListInit
- /// and the <see cref="P:ListInitExpression.NewExpression"/> and <see cref="P:ListInitExpression.Initializers"/> properties set to the specified values.
- /// </returns>
- /// <remarks>
- /// The <see cref="P:Expressions.Type"/> property of <paramref name="newExpression"/> must represent a type that implements <see cref="System.Collections.IEnumerable"/>.
- /// The <see cref="P:Expressions.Type"/> property of the resulting <see cref="ListInitExpression"/> is equal to newExpression.Type.
- /// </remarks>
- public static ListInitExpression ListInit(NewExpression newExpression, params ElementInit[] initializers) {
- return ListInit(newExpression, (IEnumerable<ElementInit>)initializers);
- }
-
- /// <summary>
- /// Creates a <see cref="ListInitExpression"/> that uses specified <see cref="M:ElementInit"/> objects to initialize a collection.
- /// </summary>
- /// <param name="newExpression">A <see cref="NewExpression"/> to set the <see cref="P:ListInitExpression.NewExpression"/> property equal to.</param>
- /// <param name="initializers">An <see cref="IEnumerable{T}"/> that contains <see cref="M:ElementInit"/> objects to use to populate the <see cref="ListInitExpression.Initializers"/> collection.</param>
- /// <returns>An <see cref="IEnumerable{T}"/> that contains <see cref="M:ElementInit"/> objects to use to populate the <see cref="ListInitExpression.Initializers"/> collection.</returns>
- /// <remarks>
- /// The <see cref="P:Expressions.Type"/> property of <paramref name="newExpression"/> must represent a type that implements <see cref="System.Collections.IEnumerable"/>.
- /// The <see cref="P:Expressions.Type"/> property of the resulting <see cref="ListInitExpression"/> is equal to newExpression.Type.
- /// </remarks>
- public static ListInitExpression ListInit(NewExpression newExpression, IEnumerable<ElementInit> initializers) {
- ContractUtils.RequiresNotNull(newExpression, "newExpression");
- ContractUtils.RequiresNotNull(initializers, "initializers");
- var initializerlist = initializers.ToReadOnly();
- if (initializerlist.Count == 0) {
- throw Error.ListInitializerWithZeroMembers();
- }
- ValidateListInitArgs(newExpression.Type, initializerlist);
- return new ListInitExpression(newExpression, initializerlist);
- }
- }
-}
+/* ****************************************************************************
+ *
+ * Copyright (c) Microsoft Corporation.
+ *
+ * This source code is subject to terms and conditions of the Apache License, Version 2.0. A
+ * copy of the license can be found in the License.html file at the root of this distribution. If
+ * you cannot locate the Apache License, Version 2.0, please send an email to
+ * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
+ * by the terms of the Apache License, Version 2.0.
+ *
+ * You must not remove this notice, or any other, from this software.
+ *
+ *
+ * ***************************************************************************/
+
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Diagnostics;
+using System.Dynamic.Utils;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+#if SILVERLIGHT
+using System.Core;
+#endif
+
+#if CLR2
+namespace Microsoft.Scripting.Ast {
+#else
+namespace System.Linq.Expressions {
+#endif
+ /// <summary>
+ /// Represents a constructor call that has a collection initializer.
+ /// </summary>
+ /// <remarks>
+ /// Use the <see cref="M:ListInit"/> factory methods to create a ListInitExpression.
+ /// The value of the NodeType property of a ListInitExpression is ListInit.
+ /// </remarks>
+#if !SILVERLIGHT
+ [DebuggerTypeProxy(typeof(Expression.ListInitExpressionProxy))]
+#endif
+ public sealed class ListInitExpression : Expression {
+ private readonly NewExpression _newExpression;
+ private readonly ReadOnlyCollection<ElementInit> _initializers;
+
+ internal ListInitExpression(NewExpression newExpression, ReadOnlyCollection<ElementInit> initializers) {
+ _newExpression = newExpression;
+ _initializers = initializers;
+ }
+
+ /// <summary>
+ /// Returns the node type of this <see cref="Expression"/>. (Inherited from <see cref="Expression" />.)
+ /// </summary>
+ /// <returns>The <see cref="ExpressionType"/> that represents this expression.</returns>
+ public sealed override ExpressionType NodeType {
+ get { return ExpressionType.ListInit; }
+ }
+
+ /// <summary>
+ /// Gets the static type of the expression that this <see cref="Expression" /> represents. (Inherited from <see cref="Expression"/>.)
+ /// </summary>
+ /// <returns>The <see cref="Type"/> that represents the static type of the expression.</returns>
+ public sealed override Type Type {
+ get { return _newExpression.Type; }
+ }
+
+ /// <summary>
+ /// Gets a value that indicates whether the expression tree node can be reduced.
+ /// </summary>
+ public override bool CanReduce {
+ get {
+ return true;
+ }
+ }
+
+ /// <summary>
+ /// Gets the expression that contains a call to the constructor of a collection type.
+ /// </summary>
+ public NewExpression NewExpression {
+ get { return _newExpression; }
+ }
+
+ /// <summary>
+ /// Gets the element initializers that are used to initialize a collection.
+ /// </summary>
+ public ReadOnlyCollection<ElementInit> Initializers {
+ get { return _initializers; }
+ }
+
+ /// <summary>
+ /// Dispatches to the specific visit method for this node type.
+ /// </summary>
+ protected internal override Expression Accept(ExpressionVisitor visitor) {
+ return visitor.VisitListInit(this);
+ }
+
+ /// <summary>
+ /// Reduces the binary expression node to a simpler expression.
+ /// If CanReduce returns true, this should return a valid expression.
+ /// This method is allowed to return another node which itself
+ /// must be reduced.
+ /// </summary>
+ /// <returns>The reduced expression.</returns>
+ public override Expression Reduce() {
+ return MemberInitExpression.ReduceListInit(_newExpression, _initializers, true);
+ }
+
+ /// <summary>
+ /// Creates a new expression that is like this one, but using the
+ /// supplied children. If all of the children are the same, it will
+ /// return this expression.
+ /// </summary>
+ /// <param name="newExpression">The <see cref="NewExpression" /> property of the result.</param>
+ /// <param name="initializers">The <see cref="Initializers" /> property of the result.</param>
+ /// <returns>This expression if no children changed, or an expression with the updated children.</returns>
+ public ListInitExpression Update(NewExpression newExpression, IEnumerable<ElementInit> initializers) {
+ if (newExpression == NewExpression && initializers == Initializers) {
+ return this;
+ }
+ return Expression.ListInit(newExpression, initializers);
+ }
+ }
+
+
+ public partial class Expression {
+ /// <summary>
+ /// Creates a <see cref="ListInitExpression"/> that uses a method named "Add" to add elements to a collection.
+ /// </summary>
+ /// <param name="newExpression">A <see cref="NewExpression"/> to set the <see cref="P:ListInitExpression.NewExpression"/> property equal to.</param>
+ /// <param name="initializers">An array of <see cref="Expression"/> objects to use to populate the <see cref="ListInitExpression.Initializers"/> collection.</param>
+ /// <returns>A <see cref="ListInitExpression"/> that has the <see cref="P:ListInitExpression.NodeType"/> property equal to ListInit and the <see cref="P:ListInitExpression.NewExpression"/> property set to the specified value.</returns>
+ public static ListInitExpression ListInit(NewExpression newExpression, params Expression[] initializers) {
+ ContractUtils.RequiresNotNull(newExpression, "newExpression");
+ ContractUtils.RequiresNotNull(initializers, "initializers");
+ return ListInit(newExpression, initializers as IEnumerable<Expression>);
+ }
+
+ /// <summary>
+ /// Creates a <see cref="ListInitExpression"/> that uses a method named "Add" to add elements to a collection.
+ /// </summary>
+ /// <param name="newExpression">A <see cref="NewExpression"/> to set the <see cref="P:ListInitExpression.NewExpression"/> property equal to.</param>
+ /// <param name="initializers">An <see cref="IEnumerable{T}"/> that contains <see cref="M:ElementInit"/> objects to use to populate the <see cref="ListInitExpression.Initializers"/> collection.</param>
+ /// <returns>A <see cref="ListInitExpression"/> that has the <see cref="P:ListInitExpression.NodeType"/> property equal to ListInit and the <see cref="P:ListInitExpression.NewExpression"/> property set to the specified value.</returns>
+ public static ListInitExpression ListInit(NewExpression newExpression, IEnumerable<Expression> initializers) {
+ ContractUtils.RequiresNotNull(newExpression, "newExpression");
+ ContractUtils.RequiresNotNull(initializers, "initializers");
+
+ var initializerlist = initializers.ToReadOnly();
+ if (initializerlist.Count == 0) {
+ throw Error.ListInitializerWithZeroMembers();
+ }
+
+ MethodInfo addMethod = FindMethod(newExpression.Type, "Add", null, new Expression[] { initializerlist[0] }, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
+ return ListInit(newExpression, addMethod, initializers);
+ }
+
+ /// <summary>
+ /// Creates a <see cref="ListInitExpression"/> that uses a specified method to add elements to a collection.
+ /// </summary>
+ /// <param name="newExpression">A <see cref="NewExpression"/> to set the <see cref="P:ListInitExpression.NewExpression"/> property equal to.</param>
+ /// <param name="addMethod">A <see cref="MethodInfo"/> that represents an instance method named "Add" (case insensitive), that adds an element to a collection. </param>
+ /// <param name="initializers">An array of <see cref="Expression"/> objects to use to populate the <see cref="ListInitExpression.Initializers"/> collection.</param>
+ /// <returns>A <see cref="ListInitExpression"/> that has the <see cref="P:ListInitExpression.NodeType"/> property equal to ListInit and the <see cref="P:ListInitExpression.NewExpression"/> property set to the specified value.</returns>
+ public static ListInitExpression ListInit(NewExpression newExpression, MethodInfo addMethod, params Expression[] initializers) {
+ if (addMethod == null) {
+ return ListInit(newExpression, initializers as IEnumerable<Expression>);
+ }
+ ContractUtils.RequiresNotNull(newExpression, "newExpression");
+ ContractUtils.RequiresNotNull(initializers, "initializers");
+ return ListInit(newExpression, addMethod, initializers as IEnumerable<Expression>);
+ }
+
+ /// <summary>
+ /// Creates a <see cref="ListInitExpression"/> that uses a specified method to add elements to a collection.
+ /// </summary>
+ /// <param name="newExpression">A <see cref="NewExpression"/> to set the <see cref="P:ListInitExpression.NewExpression"/> property equal to.</param>
+ /// <param name="addMethod">A <see cref="MethodInfo"/> that represents an instance method named "Add" (case insensitive), that adds an element to a collection. </param>
+ /// <param name="initializers">An <see cref="IEnumerable{T}"/> that contains <see cref="Expression"/> objects to use to populate the Initializers collection.</param>
+ /// <returns>A <see cref="ListInitExpression"/> that has the <see cref="P:ListInitExpression.NodeType"/> property equal to ListInit and the <see cref="P:ListInitExpression.NewExpression"/> property set to the specified value.</returns>
+ public static ListInitExpression ListInit(NewExpression newExpression, MethodInfo addMethod, IEnumerable<Expression> initializers) {
+ if (addMethod == null) {
+ return ListInit(newExpression, initializers);
+ }
+ ContractUtils.RequiresNotNull(newExpression, "newExpression");
+ ContractUtils.RequiresNotNull(initializers, "initializers");
+
+ var initializerlist = initializers.ToReadOnly();
+ if (initializerlist.Count == 0) {
+ throw Error.ListInitializerWithZeroMembers();
+ }
+ ElementInit[] initList = new ElementInit[initializerlist.Count];
+ for (int i = 0; i < initializerlist.Count; i++) {
+ initList[i] = ElementInit(addMethod, initializerlist[i]);
+ }
+ return ListInit(newExpression, new TrueReadOnlyCollection<ElementInit>(initList));
+ }
+
+ /// <summary>
+ /// Creates a <see cref="ListInitExpression"/> that uses specified <see cref="M:ElementInit"/> objects to initialize a collection.
+ /// </summary>
+ /// <param name="newExpression">A <see cref="NewExpression"/> to set the <see cref="P:ListInitExpression.NewExpression"/> property equal to.</param>
+ /// <param name="initializers">An array that contains <see cref="M:ElementInit"/> objects to use to populate the <see cref="ListInitExpression.Initializers"/> collection.</param>
+ /// <returns>
+ /// A <see cref="ListInitExpression"/> that has the <see cref="P:Expressions.NodeType"/> property equal to ListInit
+ /// and the <see cref="P:ListInitExpression.NewExpression"/> and <see cref="P:ListInitExpression.Initializers"/> properties set to the specified values.
+ /// </returns>
+ /// <remarks>
+ /// The <see cref="P:Expressions.Type"/> property of <paramref name="newExpression"/> must represent a type that implements <see cref="System.Collections.IEnumerable"/>.
+ /// The <see cref="P:Expressions.Type"/> property of the resulting <see cref="ListInitExpression"/> is equal to newExpression.Type.
+ /// </remarks>
+ public static ListInitExpression ListInit(NewExpression newExpression, params ElementInit[] initializers) {
+ return ListInit(newExpression, (IEnumerable<ElementInit>)initializers);
+ }
+
+ /// <summary>
+ /// Creates a <see cref="ListInitExpression"/> that uses specified <see cref="M:ElementInit"/> objects to initialize a collection.
+ /// </summary>
+ /// <param name="newExpression">A <see cref="NewExpression"/> to set the <see cref="P:ListInitExpression.NewExpression"/> property equal to.</param>
+ /// <param name="initializers">An <see cref="IEnumerable{T}"/> that contains <see cref="M:ElementInit"/> objects to use to populate the <see cref="ListInitExpression.Initializers"/> collection.</param>
+ /// <returns>An <see cref="IEnumerable{T}"/> that contains <see cref="M:ElementInit"/> objects to use to populate the <see cref="ListInitExpression.Initializers"/> collection.</returns>
+ /// <remarks>
+ /// The <see cref="P:Expressions.Type"/> property of <paramref name="newExpression"/> must represent a type that implements <see cref="System.Collections.IEnumerable"/>.
+ /// The <see cref="P:Expressions.Type"/> property of the resulting <see cref="ListInitExpression"/> is equal to newExpression.Type.
+ /// </remarks>
+ public static ListInitExpression ListInit(NewExpression newExpression, IEnumerable<ElementInit> initializers) {
+ ContractUtils.RequiresNotNull(newExpression, "newExpression");
+ ContractUtils.RequiresNotNull(initializers, "initializers");
+ var initializerlist = initializers.ToReadOnly();
+ if (initializerlist.Count == 0) {
+ throw Error.ListInitializerWithZeroMembers();
+ }
+ ValidateListInitArgs(newExpression.Type, initializerlist);
+ return new ListInitExpression(newExpression, initializerlist);
+ }
+ }
+}
diff --git a/mcs/class/dlr/Runtime/Microsoft.Scripting.Core/Compiler/.gitattributes b/mcs/class/dlr/Runtime/Microsoft.Scripting.Core/Compiler/.gitattributes
deleted file mode 100644
index 9b2b3f88b17..00000000000
--- a/mcs/class/dlr/Runtime/Microsoft.Scripting.Core/Compiler/.gitattributes
+++ /dev/null
@@ -1 +0,0 @@
-/LambdaCompiler.Lambda.cs -crlf
diff --git a/mcs/class/dlr/Runtime/Microsoft.Scripting.Core/Compiler/LambdaCompiler.Lambda.cs b/mcs/class/dlr/Runtime/Microsoft.Scripting.Core/Compiler/LambdaCompiler.Lambda.cs
index a2e58076f08..ed668bceca2 100644
--- a/mcs/class/dlr/Runtime/Microsoft.Scripting.Core/Compiler/LambdaCompiler.Lambda.cs
+++ b/mcs/class/dlr/Runtime/Microsoft.Scripting.Core/Compiler/LambdaCompiler.Lambda.cs
@@ -1,193 +1,193 @@
-/* ****************************************************************************
- *
- * Copyright (c) Microsoft Corporation.
- *
- * This source code is subject to terms and conditions of the Apache License, Version 2.0. A
- * copy of the license can be found in the License.html file at the root of this distribution. If
- * you cannot locate the Apache License, Version 2.0, please send an email to
- * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
- * by the terms of the Apache License, Version 2.0.
- *
- * You must not remove this notice, or any other, from this software.
- *
- *
- * ***************************************************************************/
-
-using System;
-using System.Diagnostics;
-using System.Dynamic.Utils;
-using System.Reflection;
-using System.Reflection.Emit;
-using System.Runtime.CompilerServices;
-using System.Threading;
-
-#if CLR2
-namespace Microsoft.Scripting.Ast.Compiler {
-#else
-namespace System.Linq.Expressions.Compiler {
-#endif
-
- /// <summary>
- /// Dynamic Language Runtime Compiler.
- /// This part compiles lambdas.
- /// </summary>
- partial class LambdaCompiler {
- private static int _Counter;
-
- internal void EmitConstantArray<T>(T[] array) {
- // Emit as runtime constant if possible
- // if not, emit into IL
- if (_method is DynamicMethod) {
- EmitConstant(array, typeof(T[]));
- } else if(_typeBuilder != null) {
- // store into field in our type builder, we will initialize
- // the value only once.
- FieldBuilder fb = CreateStaticField("ConstantArray", typeof(T[]));
- Label l = _ilg.DefineLabel();
- _ilg.Emit(OpCodes.Ldsfld, fb);
- _ilg.Emit(OpCodes.Ldnull);
- _ilg.Emit(OpCodes.Bne_Un, l);
- _ilg.EmitArray(array);
- _ilg.Emit(OpCodes.Stsfld, fb);
- _ilg.MarkLabel(l);
- _ilg.Emit(OpCodes.Ldsfld, fb);
- } else {
- _ilg.EmitArray(array);
- }
- }
-
- private void EmitClosureCreation(LambdaCompiler inner) {
- bool closure = inner._scope.NeedsClosure;
- bool boundConstants = inner._boundConstants.Count > 0;
-
- if (!closure && !boundConstants) {
- _ilg.EmitNull();
- return;
- }
-
- // new Closure(constantPool, currentHoistedLocals)
- if (boundConstants) {
- _boundConstants.EmitConstant(this, inner._boundConstants.ToArray(), typeof(object[]));
- } else {
- _ilg.EmitNull();
- }
- if (closure) {
- _scope.EmitGet(_scope.NearestHoistedLocals.SelfVariable);
- } else {
- _ilg.EmitNull();
- }
- _ilg.EmitNew(typeof(Closure).GetConstructor(new Type[] { typeof(object[]), typeof(object[]) }));
- }
-
- /// <summary>
- /// Emits code which creates new instance of the delegateType delegate.
- ///
- /// Since the delegate is getting closed over the "Closure" argument, this
- /// cannot be used with virtual/instance methods (inner must be static method)
- /// </summary>
- private void EmitDelegateConstruction(LambdaCompiler inner) {
- Type delegateType = inner._lambda.Type;
- DynamicMethod dynamicMethod = inner._method as DynamicMethod;
- if (dynamicMethod != null) {
- // dynamicMethod.CreateDelegate(delegateType, closure)
- _boundConstants.EmitConstant(this, dynamicMethod, typeof(DynamicMethod));
- _ilg.EmitType(delegateType);
- EmitClosureCreation(inner);
- _ilg.Emit(OpCodes.Callvirt, typeof(DynamicMethod).GetMethod("CreateDelegate", new Type[] { typeof(Type), typeof(object) }));
- _ilg.Emit(OpCodes.Castclass, delegateType);
- } else {
- // new DelegateType(closure)
- EmitClosureCreation(inner);
- _ilg.Emit(OpCodes.Ldftn, (MethodInfo)inner._method);
- _ilg.Emit(OpCodes.Newobj, (ConstructorInfo)(delegateType.GetMember(".ctor")[0]));
- }
- }
-
- /// <summary>
- /// Emits a delegate to the method generated for the LambdaExpression.
- /// May end up creating a wrapper to match the requested delegate type.
- /// </summary>
- /// <param name="lambda">Lambda for which to generate a delegate</param>
- ///
- private void EmitDelegateConstruction(LambdaExpression lambda) {
- // 1. Create the new compiler
- LambdaCompiler impl;
- if (_method is DynamicMethod) {
- impl = new LambdaCompiler(_tree, lambda);
- } else {
- // When the lambda does not have a name or the name is empty, generate a unique name for it.
- string name = String.IsNullOrEmpty(lambda.Name) ? GetUniqueMethodName() : lambda.Name;
- MethodBuilder mb = _typeBuilder.DefineMethod(name, MethodAttributes.Private | MethodAttributes.Static);
- impl = new LambdaCompiler(_tree, lambda, mb);
- }
-
- // 2. emit the lambda
- // Since additional ILs are always emitted after the lambda's body, should not emit with tail call optimization.
- impl.EmitLambdaBody(_scope, false, CompilationFlags.EmitAsNoTail);
-
- // 3. emit the delegate creation in the outer lambda
- EmitDelegateConstruction(impl);
- }
-
- private static Type[] GetParameterTypes(LambdaExpression lambda) {
- return lambda.Parameters.Map(p => p.IsByRef ? p.Type.MakeByRefType() : p.Type);
- }
-
- private static string GetUniqueMethodName() {
- return "<ExpressionCompilerImplementationDetails>{" + Interlocked.Increment(ref _Counter) + "}lambda_method";
- }
-
- private void EmitLambdaBody() {
- // The lambda body is the "last" expression of the lambda
- CompilationFlags tailCallFlag = _lambda.TailCall ? CompilationFlags.EmitAsTail : CompilationFlags.EmitAsNoTail;
- EmitLambdaBody(null, false, tailCallFlag);
- }
-
- /// <summary>
- /// Emits the lambda body. If inlined, the parameters should already be
- /// pushed onto the IL stack.
- /// </summary>
- /// <param name="parent">The parent scope.</param>
- /// <param name="inlined">true if the lambda is inlined; false otherwise.</param>
- /// <param name="flags">
- /// The emum to specify if the lambda is compiled with the tail call optimization.
- /// </param>
- private void EmitLambdaBody(CompilerScope parent, bool inlined, CompilationFlags flags) {
- _scope.Enter(this, parent);
-
- if (inlined) {
- // The arguments were already pushed onto the IL stack.
- // Store them into locals, popping in reverse order.
- //
- // If any arguments were ByRef, the address is on the stack and
- // we'll be storing it into the variable, which has a ref type.
- for (int i = _lambda.Parameters.Count - 1; i >= 0; i--) {
- _scope.EmitSet(_lambda.Parameters[i]);
- }
- }
-
- // Need to emit the expression start for the lambda body
- flags = UpdateEmitExpressionStartFlag(flags, CompilationFlags.EmitExpressionStart);
- if (_lambda.ReturnType == typeof(void)) {
- EmitExpressionAsVoid(_lambda.Body, flags);
- } else {
- EmitExpression(_lambda.Body, flags);
- }
-
- // Return must be the last instruction in a CLI method.
- // But if we're inlining the lambda, we want to leave the return
- // value on the IL stack.
- if (!inlined) {
- _ilg.Emit(OpCodes.Ret);
- }
-
- _scope.Exit();
-
- // Validate labels
- Debug.Assert(_labelBlock.Parent == null && _labelBlock.Kind == LabelScopeKind.Lambda);
- foreach (LabelInfo label in _labelInfo.Values) {
- label.ValidateFinish();
- }
- }
- }
-}
+/* ****************************************************************************
+ *
+ * Copyright (c) Microsoft Corporation.
+ *
+ * This source code is subject to terms and conditions of the Apache License, Version 2.0. A
+ * copy of the license can be found in the License.html file at the root of this distribution. If
+ * you cannot locate the Apache License, Version 2.0, please send an email to
+ * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
+ * by the terms of the Apache License, Version 2.0.
+ *
+ * You must not remove this notice, or any other, from this software.
+ *
+ *
+ * ***************************************************************************/
+
+using System;
+using System.Diagnostics;
+using System.Dynamic.Utils;
+using System.Reflection;
+using System.Reflection.Emit;
+using System.Runtime.CompilerServices;
+using System.Threading;
+
+#if CLR2
+namespace Microsoft.Scripting.Ast.Compiler {
+#else
+namespace System.Linq.Expressions.Compiler {
+#endif
+
+ /// <summary>
+ /// Dynamic Language Runtime Compiler.
+ /// This part compiles lambdas.
+ /// </summary>
+ partial class LambdaCompiler {
+ private static int _Counter;
+
+ internal void EmitConstantArray<T>(T[] array) {
+ // Emit as runtime constant if possible
+ // if not, emit into IL
+ if (_method is DynamicMethod) {
+ EmitConstant(array, typeof(T[]));
+ } else if(_typeBuilder != null) {
+ // store into field in our type builder, we will initialize
+ // the value only once.
+ FieldBuilder fb = CreateStaticField("ConstantArray", typeof(T[]));
+ Label l = _ilg.DefineLabel();
+ _ilg.Emit(OpCodes.Ldsfld, fb);
+ _ilg.Emit(OpCodes.Ldnull);
+ _ilg.Emit(OpCodes.Bne_Un, l);
+ _ilg.EmitArray(array);
+ _ilg.Emit(OpCodes.Stsfld, fb);
+ _ilg.MarkLabel(l);
+ _ilg.Emit(OpCodes.Ldsfld, fb);
+ } else {
+ _ilg.EmitArray(array);
+ }
+ }
+
+ private void EmitClosureCreation(LambdaCompiler inner) {
+ bool closure = inner._scope.NeedsClosure;
+ bool boundConstants = inner._boundConstants.Count > 0;
+
+ if (!closure && !boundConstants) {
+ _ilg.EmitNull();
+ return;
+ }
+
+ // new Closure(constantPool, currentHoistedLocals)
+ if (boundConstants) {
+ _boundConstants.EmitConstant(this, inner._boundConstants.ToArray(), typeof(object[]));
+ } else {
+ _ilg.EmitNull();
+ }
+ if (closure) {
+ _scope.EmitGet(_scope.NearestHoistedLocals.SelfVariable);
+ } else {
+ _ilg.EmitNull();
+ }
+ _ilg.EmitNew(typeof(Closure).GetConstructor(new Type[] { typeof(object[]), typeof(object[]) }));
+ }
+
+ /// <summary>
+ /// Emits code which creates new instance of the delegateType delegate.
+ ///
+ /// Since the delegate is getting closed over the "Closure" argument, this
+ /// cannot be used with virtual/instance methods (inner must be static method)
+ /// </summary>
+ private void EmitDelegateConstruction(LambdaCompiler inner) {
+ Type delegateType = inner._lambda.Type;
+ DynamicMethod dynamicMethod = inner._method as DynamicMethod;
+ if (dynamicMethod != null) {
+ // dynamicMethod.CreateDelegate(delegateType, closure)
+ _boundConstants.EmitConstant(this, dynamicMethod, typeof(DynamicMethod));
+ _ilg.EmitType(delegateType);
+ EmitClosureCreation(inner);
+ _ilg.Emit(OpCodes.Callvirt, typeof(DynamicMethod).GetMethod("CreateDelegate", new Type[] { typeof(Type), typeof(object) }));
+ _ilg.Emit(OpCodes.Castclass, delegateType);
+ } else {
+ // new DelegateType(closure)
+ EmitClosureCreation(inner);
+ _ilg.Emit(OpCodes.Ldftn, (MethodInfo)inner._method);
+ _ilg.Emit(OpCodes.Newobj, (ConstructorInfo)(delegateType.GetMember(".ctor")[0]));
+ }
+ }
+
+ /// <summary>
+ /// Emits a delegate to the method generated for the LambdaExpression.
+ /// May end up creating a wrapper to match the requested delegate type.
+ /// </summary>
+ /// <param name="lambda">Lambda for which to generate a delegate</param>
+ ///
+ private void EmitDelegateConstruction(LambdaExpression lambda) {
+ // 1. Create the new compiler
+ LambdaCompiler impl;
+ if (_method is DynamicMethod) {
+ impl = new LambdaCompiler(_tree, lambda);
+ } else {
+ // When the lambda does not have a name or the name is empty, generate a unique name for it.
+ string name = String.IsNullOrEmpty(lambda.Name) ? GetUniqueMethodName() : lambda.Name;
+ MethodBuilder mb = _typeBuilder.DefineMethod(name, MethodAttributes.Private | MethodAttributes.Static);
+ impl = new LambdaCompiler(_tree, lambda, mb);
+ }
+
+ // 2. emit the lambda
+ // Since additional ILs are always emitted after the lambda's body, should not emit with tail call optimization.
+ impl.EmitLambdaBody(_scope, false, CompilationFlags.EmitAsNoTail);
+
+ // 3. emit the delegate creation in the outer lambda
+ EmitDelegateConstruction(impl);
+ }
+
+ private static Type[] GetParameterTypes(LambdaExpression lambda) {
+ return lambda.Parameters.Map(p => p.IsByRef ? p.Type.MakeByRefType() : p.Type);
+ }
+
+ private static string GetUniqueMethodName() {
+ return "<ExpressionCompilerImplementationDetails>{" + Interlocked.Increment(ref _Counter) + "}lambda_method";
+ }
+
+ private void EmitLambdaBody() {
+ // The lambda body is the "last" expression of the lambda
+ CompilationFlags tailCallFlag = _lambda.TailCall ? CompilationFlags.EmitAsTail : CompilationFlags.EmitAsNoTail;
+ EmitLambdaBody(null, false, tailCallFlag);
+ }
+
+ /// <summary>
+ /// Emits the lambda body. If inlined, the parameters should already be
+ /// pushed onto the IL stack.
+ /// </summary>
+ /// <param name="parent">The parent scope.</param>
+ /// <param name="inlined">true if the lambda is inlined; false otherwise.</param>
+ /// <param name="flags">
+ /// The emum to specify if the lambda is compiled with the tail call optimization.
+ /// </param>
+ private void EmitLambdaBody(CompilerScope parent, bool inlined, CompilationFlags flags) {
+ _scope.Enter(this, parent);
+
+ if (inlined) {
+ // The arguments were already pushed onto the IL stack.
+ // Store them into locals, popping in reverse order.
+ //
+ // If any arguments were ByRef, the address is on the stack and
+ // we'll be storing it into the variable, which has a ref type.
+ for (int i = _lambda.Parameters.Count - 1; i >= 0; i--) {
+ _scope.EmitSet(_lambda.Parameters[i]);
+ }
+ }
+
+ // Need to emit the expression start for the lambda body
+ flags = UpdateEmitExpressionStartFlag(flags, CompilationFlags.EmitExpressionStart);
+ if (_lambda.ReturnType == typeof(void)) {
+ EmitExpressionAsVoid(_lambda.Body, flags);
+ } else {
+ EmitExpression(_lambda.Body, flags);
+ }
+
+ // Return must be the last instruction in a CLI method.
+ // But if we're inlining the lambda, we want to leave the return
+ // value on the IL stack.
+ if (!inlined) {
+ _ilg.Emit(OpCodes.Ret);
+ }
+
+ _scope.Exit();
+
+ // Validate labels
+ Debug.Assert(_labelBlock.Parent == null && _labelBlock.Kind == LabelScopeKind.Lambda);
+ foreach (LabelInfo label in _labelInfo.Values) {
+ label.ValidateFinish();
+ }
+ }
+ }
+}
diff --git a/mcs/class/dlr/Runtime/Microsoft.Scripting.Core/Properties/.gitattributes b/mcs/class/dlr/Runtime/Microsoft.Scripting.Core/Properties/.gitattributes
deleted file mode 100644
index 31e93e4e9e3..00000000000
--- a/mcs/class/dlr/Runtime/Microsoft.Scripting.Core/Properties/.gitattributes
+++ /dev/null
@@ -1 +0,0 @@
-/ExtensionAssemblyInfo.cs -crlf
diff --git a/mcs/class/dlr/Runtime/Microsoft.Scripting.Core/Properties/ExtensionAssemblyInfo.cs b/mcs/class/dlr/Runtime/Microsoft.Scripting.Core/Properties/ExtensionAssemblyInfo.cs
index bc47e001f31..2a2c1c0f76c 100644
--- a/mcs/class/dlr/Runtime/Microsoft.Scripting.Core/Properties/ExtensionAssemblyInfo.cs
+++ b/mcs/class/dlr/Runtime/Microsoft.Scripting.Core/Properties/ExtensionAssemblyInfo.cs
@@ -1,62 +1,62 @@
-/* ****************************************************************************
- *
- * Copyright (c) Microsoft Corporation.
- *
- * This source code is subject to terms and conditions of the Microsoft Public License. A
- * copy of the license can be found in the License.html file at the root of this distribution. If
- * you cannot locate the Microsoft Public License, please send an email to
- * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
- * by the terms of the Microsoft Public License.
- *
- * You must not remove this notice, or any other, from this software.
- *
- *
- * ***************************************************************************/
-
-using System;
-using System.Reflection;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-using System.Security;
-
-// General Information about an assembly is controlled through the following
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("Microsoft.Scripting.ExtensionAttribute")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("Microsoft")]
-[assembly: AssemblyProduct("Microsoft.Scripting.ExtensionAttribute")]
-[assembly: AssemblyCopyright("� Microsoft Corporation. All rights reserved.")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM components. If you need to access a type in this assembly from
-// COM, set the ComVisible attribute to true on that type.
-[assembly: ComVisible(false)]
-
-[assembly: CLSCompliant(true)]
-
-// The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("b828a36d-f568-48a7-9bdd-412b0a1bfa32")]
-
-// Version information for an assembly consists of the following four values:
-//
-// Major Version
-// Minor Version
-// Build Number
-// Revision
-//
-// You can specify all the values or you can default the Revision and Build Numbers
-// by using the '*' as shown below:
-[assembly: SecurityTransparent]
-
-[assembly: System.Resources.NeutralResourcesLanguage("en-US")]
-
-#if !SILVERLIGHT
-[assembly: AssemblyVersion("2.0.0.0")] // shouldn't change, this assembly is unchanged. This is the version it originally shipped as.
-[assembly: AssemblyFileVersion("1.0.1.00")]
-[assembly: AssemblyInformationalVersion("1.0.1")]
-[assembly: AllowPartiallyTrustedCallers]
-#endif
+/* ****************************************************************************
+ *
+ * Copyright (c) Microsoft Corporation.
+ *
+ * This source code is subject to terms and conditions of the Microsoft Public License. A
+ * copy of the license can be found in the License.html file at the root of this distribution. If
+ * you cannot locate the Microsoft Public License, please send an email to
+ * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
+ * by the terms of the Microsoft Public License.
+ *
+ * You must not remove this notice, or any other, from this software.
+ *
+ *
+ * ***************************************************************************/
+
+using System;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Security;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Microsoft.Scripting.ExtensionAttribute")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Microsoft")]
+[assembly: AssemblyProduct("Microsoft.Scripting.ExtensionAttribute")]
+[assembly: AssemblyCopyright("� Microsoft Corporation. All rights reserved.")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+[assembly: CLSCompliant(true)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("b828a36d-f568-48a7-9bdd-412b0a1bfa32")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Revision and Build Numbers
+// by using the '*' as shown below:
+[assembly: SecurityTransparent]
+
+[assembly: System.Resources.NeutralResourcesLanguage("en-US")]
+
+#if !SILVERLIGHT
+[assembly: AssemblyVersion("2.0.0.0")] // shouldn't change, this assembly is unchanged. This is the version it originally shipped as.
+[assembly: AssemblyFileVersion("1.0.1.00")]
+[assembly: AssemblyInformationalVersion("1.0.1")]
+[assembly: AllowPartiallyTrustedCallers]
+#endif