//
// Author:
// Miguel de Icaza (miguel@ximian.com)
-// Marek Safar (marek.safar@seznam.cz)
+// Marek Safar (marek.safar@gmail.com)
//
// Copyright 2001, 2002, 2003 Ximian, Inc.
// Copyright 2003-2008 Novell, Inc.
return CreateExpressionFactoryCall ("Call", args);
}
+ protected override void CloneTo (CloneContext context, Expression target)
+ {
+ // Nothing to clone
+ }
+
public override Expression DoResolve (EmitContext ec)
{
//
mg.EmitCall (ec, arguments);
}
- [Obsolete ("It may not be compatible with expression trees")]
- static public UserOperatorCall MakeSimpleCall (EmitContext ec, MethodGroupExpr mg,
- Expression e, Location loc)
- {
- ArrayList args;
-
- args = new ArrayList (1);
- Argument a = new Argument (e, Argument.AType.Expression);
-
- // We need to resolve the arguments before sending them in !
- if (!a.Resolve (ec, loc))
- return null;
-
- args.Add (a);
- mg = mg.OverloadResolve (ec, ref args, false, loc);
-
- if (mg == null)
- return null;
-
- return new UserOperatorCall (mg, args, null, loc);
- }
-
public MethodGroupExpr Method {
get { return mg; }
}
+
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ foreach (Argument a in arguments)
+ a.Expr.MutateHoistedGenericType (storey);
+
+ mg.MutateHoistedGenericType (storey);
+ }
}
public class ParenthesizedExpression : Expression
public ParenthesizedExpression (Expression expr)
{
this.Expr = expr;
+ this.loc = expr.Location;
+ }
+
+ public override Expression CreateExpressionTree (EmitContext ec)
+ {
+ throw new NotSupportedException ("ET");
}
public override Expression DoResolve (EmitContext ec)
throw new Exception ("Should not happen");
}
- public override Location Location
- {
- get {
- return Expr.Location;
- }
- }
-
protected override void CloneTo (CloneContext clonectx, Expression t)
{
ParenthesizedExpression target = (ParenthesizedExpression) t;
AddressOf, TOP
}
- public static readonly string [] oper_names;
static Type [] [] predefined_operators;
public readonly Operator Oper;
public Expression Expr;
+ Expression enum_conversion;
public Unary (Operator op, Expression expr, Location loc)
{
this.loc = loc;
}
- static Unary ()
- {
- oper_names = new string [(int)Operator.TOP];
-
- oper_names [(int) Operator.UnaryPlus] = "op_UnaryPlus";
- oper_names [(int) Operator.UnaryNegation] = "op_UnaryNegation";
- oper_names [(int) Operator.LogicalNot] = "op_LogicalNot";
- oper_names [(int) Operator.OnesComplement] = "op_OnesComplement";
- oper_names [(int) Operator.AddressOf] = "op_AddressOf";
- }
-
// <summary>
// This routine will attempt to simplify the unary expression when the
// argument is a constant.
// </summary>
Constant TryReduceConstant (EmitContext ec, Constant e)
{
+ if (e is EmptyConstantCast)
+ return TryReduceConstant (ec, ((EmptyConstantCast) e).child);
+
if (e is SideEffectConstant) {
Constant r = TryReduceConstant (ec, ((SideEffectConstant) e).value);
return r == null ? null : new SideEffectConstant (r, e, r.Location);
protected Expression ResolveOperator (EmitContext ec, Expression expr)
{
+ eclass = ExprClass.Value;
+
if (predefined_operators == null)
CreatePredefinedOperatorsTable ();
//
// E operator ~(E x);
//
- if (Oper == Operator.OnesComplement && TypeManager.IsEnumType (expr_type)) {
- best_expr = ResolvePrimitivePredefinedType (EmptyCast.Create (expr, TypeManager.GetEnumUnderlyingType (expr_type)));
- if (best_expr == null)
- return null;
-
- Expr = EmptyCast.Create (best_expr, expr_type);
- type = Expr.Type;
- return this;
- }
+ if (Oper == Operator.OnesComplement && TypeManager.IsEnumType (expr_type))
+ return ResolveEnumOperator (ec, expr);
return ResolveUserType (ec, expr);
}
+ protected virtual Expression ResolveEnumOperator (EmitContext ec, Expression expr)
+ {
+ Type underlying_type = TypeManager.GetEnumUnderlyingType (expr.Type);
+ Expression best_expr = ResolvePrimitivePredefinedType (EmptyCast.Create (expr, underlying_type));
+ if (best_expr == null)
+ return null;
+
+ Expr = best_expr;
+ enum_conversion = Convert.ExplicitNumericConversion (new EmptyExpression (best_expr.Type), underlying_type);
+ type = expr.Type;
+ return EmptyCast.Create (this, type);
+ }
+
public override Expression CreateExpressionTree (EmitContext ec)
{
return CreateExpressionTree (ec, null);
{
string method_name;
switch (Oper) {
+ case Operator.AddressOf:
+ Error_PointerInsideExpressionTree ();
+ return null;
case Operator.UnaryNegation:
if (ec.CheckState && user_op == null && !IsFloat (type))
method_name = "NegateChecked";
public override Expression DoResolve (EmitContext ec)
{
- eclass = ExprClass.Value;
-
if (Oper == Operator.AddressOf) {
- Expr = Expr.DoResolveLValue (ec, new EmptyExpression ());
-
- if (Expr == null || Expr.eclass != ExprClass.Variable){
- Error (211, "Cannot take the address of the given expression");
- return null;
- }
-
return ResolveAddressOf (ec);
}
throw new Exception ("This should not happen: Operator = "
+ Oper.ToString ());
}
+
+ //
+ // Same trick as in Binary expression
+ //
+ if (enum_conversion != null)
+ enum_conversion.Emit (ec);
}
public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
throw new NotImplementedException (oper.ToString ());
}
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ type = storey.MutateType (type);
+ Expr.MutateHoistedGenericType (storey);
+ }
+
Expression ResolveAddressOf (EmitContext ec)
{
- if (!ec.InUnsafe) {
+ if (!ec.InUnsafe)
UnsafeError (loc);
+
+ Expr = Expr.DoResolveLValue (ec, EmptyExpression.UnaryAddress);
+ if (Expr == null || Expr.eclass != ExprClass.Variable) {
+ Error (211, "Cannot take the address of the given expression");
return null;
}
return null;
}
- IVariable variable = Expr as IVariable;
- bool is_fixed = variable != null && variable.VerifyFixed ();
+ IVariableReference vr = Expr as IVariableReference;
+ bool is_fixed;
+ if (vr != null) {
+ VariableInfo vi = vr.VariableInfo;
+ if (vi != null) {
+ if (vi.LocalInfo != null)
+ vi.LocalInfo.Used = true;
- if (!ec.InFixedInitializer && !is_fixed) {
- Error (212, "You can only take the address of unfixed expression inside " +
- "of a fixed statement initializer");
- return null;
- }
+ //
+ // A variable is considered definitely assigned if you take its address.
+ //
+ vi.SetAssigned (ec);
+ }
- if (ec.InFixedInitializer && is_fixed) {
- Error (213, "You cannot use the fixed statement to take the address of an already fixed expression");
- return null;
- }
+ is_fixed = vr.IsFixedVariable;
+ vr.SetHasAddressTaken ();
- LocalVariableReference lr = Expr as LocalVariableReference;
- if (lr != null) {
- if (lr.local_info.IsCaptured) {
- AnonymousMethod.Error_AddressOfCapturedVar (lr.Name, loc);
- return null;
+ if (vr.IsHoisted) {
+ AnonymousMethodExpression.Error_AddressOfCapturedVar (vr, loc);
}
- lr.local_info.AddressTaken = true;
- lr.local_info.Used = true;
- }
-
- ParameterReference pr = Expr as ParameterReference;
- if ((pr != null) && pr.Parameter.IsCaptured) {
- AnonymousMethod.Error_AddressOfCapturedVar (pr.Name, loc);
- return null;
+ } else {
+ //
+ // A pointer-indirection is always fixed
+ //
+ is_fixed = Expr is Indirection;
}
- // According to the specs, a variable is considered definitely assigned if you take
- // its address.
- if ((variable != null) && (variable.VariableInfo != null)) {
- variable.VariableInfo.SetAssigned (ec);
+ if (!is_fixed && !ec.InFixedInitializer) {
+ Error (212, "You can only take the address of unfixed expression inside of a fixed statement initializer");
}
type = TypeManager.GetPointerType (Expr.Type);
+ eclass = ExprClass.Value;
return this;
}
//
protected virtual Expression ResolveUserOperator (EmitContext ec, Expression expr)
{
- string op_name = oper_names [(int) Oper];
+ CSharp.Operator.OpType op_type;
+ switch (Oper) {
+ case Operator.LogicalNot:
+ op_type = CSharp.Operator.OpType.LogicalNot; break;
+ case Operator.OnesComplement:
+ op_type = CSharp.Operator.OpType.OnesComplement; break;
+ case Operator.UnaryNegation:
+ op_type = CSharp.Operator.OpType.UnaryNegation; break;
+ case Operator.UnaryPlus:
+ op_type = CSharp.Operator.OpType.UnaryPlus; break;
+ default:
+ throw new InternalErrorException (Oper.ToString ());
+ }
+
+ string op_name = CSharp.Operator.GetMetadataName (op_type);
MethodGroupExpr user_op = MemberLookup (ec.ContainerType, expr.Type, op_name, MemberTypes.Method, AllBindingFlags, expr.Location) as MethodGroupExpr;
if (user_op == null)
return null;
// after semantic analysis (this is so we can take the address
// of an indirection).
//
- public class Indirection : Expression, IMemoryLocation, IAssignMethod, IVariable {
+ public class Indirection : Expression, IMemoryLocation, IAssignMethod {
Expression expr;
LocalTemporary temporary;
bool prepared;
this.expr = expr;
loc = l;
}
+
+ public override Expression CreateExpressionTree (EmitContext ec)
+ {
+ Error_PointerInsideExpressionTree ();
+ return null;
+ }
+
+ protected override void CloneTo (CloneContext clonectx, Expression t)
+ {
+ Indirection target = (Indirection) t;
+ target.expr = expr.Clone (clonectx);
+ }
public override void Emit (EmitContext ec)
{
return null;
}
+ if (expr.Type == TypeManager.void_ptr_type) {
+ Error (242, "The operation in question is undefined on void pointers");
+ return null;
+ }
+
type = TypeManager.GetElementType (expr.Type);
eclass = ExprClass.Variable;
return this;
}
-
+
public override string ToString ()
{
return "*(" + expr + ")";
}
-
- #region IVariable Members
-
- public VariableInfo VariableInfo {
- get { return null; }
- }
-
- public bool VerifyFixed ()
- {
- // A pointer-indirection is always fixed.
- return true;
- }
-
- #endregion
}
/// <summary>
Expression ResolveOperator (EmitContext ec)
{
- Type expr_type = expr.Type;
+ type = expr.Type;
//
// Step 1: Perform Operator Overload location
//
- Expression mg;
+ MethodGroupExpr mg;
string op_name;
if (mode == Mode.PreIncrement || mode == Mode.PostIncrement)
- op_name = "op_Increment";
- else
- op_name = "op_Decrement";
+ op_name = Operator.GetMetadataName (Operator.OpType.Increment);
+ else
+ op_name = Operator.GetMetadataName (Operator.OpType.Decrement);
- mg = MemberLookup (ec.ContainerType, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc);
+ mg = MemberLookup (ec.ContainerType, type, op_name, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
if (mg != null) {
- method = UserOperatorCall.MakeSimpleCall (
- ec, (MethodGroupExpr) mg, expr, loc);
+ ArrayList args = new ArrayList (1);
+ args.Add (new Argument (expr, Argument.AType.Expression));
+ mg = mg.OverloadResolve (ec, ref args, false, loc);
+ if (mg == null)
+ return null;
+
+ method = new UserOperatorCall (mg, args, null, loc);
+ Convert.ImplicitConversionRequired (ec, method, type, loc);
+ return this;
+ }
- type = method.Type;
- } else if (!IsIncrementableNumber (expr_type)) {
+ if (!IsIncrementableNumber (type)) {
Error (187, "No such operator '" + OperName (mode) + "' defined for type '" +
- TypeManager.CSharpName (expr_type) + "'");
- return null;
+ TypeManager.CSharpName (type) + "'");
+ return null;
}
//
// should be an expression that is classified as a variable,
// a property access or an indexer access
//
- type = expr_type;
- if (expr.eclass == ExprClass.Variable){
- LocalVariableReference var = expr as LocalVariableReference;
- if ((var != null) && var.IsReadOnly) {
- Error (1604, "cannot assign to `" + var.Name + "' because it is readonly");
- return null;
- }
- } else if (expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess){
- expr = expr.ResolveLValue (ec, this, Location);
- if (expr == null)
- return null;
+ if (expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess) {
+ expr = expr.ResolveLValue (ec, expr, Location);
} else {
Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
- return null;
}
return this;
if (n == 0)
ig.Emit (OpCodes.Sizeof, et);
- else
+ else {
IntConstant.EmitInt (ig, n);
+ ig.Emit (OpCodes.Conv_I);
+ }
} else
ig.Emit (OpCodes.Ldc_I4_1);
//
// Now emit the operation
//
- if (ec.CheckState){
- if (t == TypeManager.int32_type ||
- t == TypeManager.int64_type){
- if ((mode & Mode.IsDecrement) != 0)
- ig.Emit (OpCodes.Sub_Ovf);
- else
- ig.Emit (OpCodes.Add_Ovf);
- } else if (t == TypeManager.uint32_type ||
- t == TypeManager.uint64_type){
- if ((mode & Mode.IsDecrement) != 0)
- ig.Emit (OpCodes.Sub_Ovf_Un);
- else
- ig.Emit (OpCodes.Add_Ovf_Un);
- } else {
- if ((mode & Mode.IsDecrement) != 0)
- ig.Emit (OpCodes.Sub_Ovf);
- else
- ig.Emit (OpCodes.Add_Ovf);
- }
- } else {
- if ((mode & Mode.IsDecrement) != 0)
- ig.Emit (OpCodes.Sub);
- else
- ig.Emit (OpCodes.Add);
- }
+
+ Binary.Operator op = (mode & Mode.IsDecrement) != 0 ? Binary.Operator.Subtraction : Binary.Operator.Addition;
+ Binary.EmitOperatorOpcode (ec, op, t);
if (t == TypeManager.sbyte_type){
if (ec.CheckState)
expr = expr.Resolve (ec);
if (expr == null)
return null;
+
+ if ((probe_type_expr.Type.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
+ Report.Error (-244, loc, "The `{0}' operator cannot be applied to an operand of a static type",
+ OperatorName);
+ }
if (expr.Type.IsPointer || probe_type_expr.Type.IsPointer) {
Report.Error (244, loc, "The `{0}' operator cannot be applied to an operand of pointer type",
return this;
}
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ expr.MutateHoistedGenericType (storey);
+ probe_type_expr.MutateHoistedGenericType (storey);
+ }
+
protected abstract string OperatorName { get; }
protected override void CloneTo (CloneContext clonectx, Expression t)
/// Implementation of the `is' operator.
/// </summary>
public class Is : Probe {
+ Nullable.Unwrap expr_unwrap;
+
public Is (Expression expr, Expression probe_type, Location l)
: base (expr, probe_type, l)
{
public override void Emit (EmitContext ec)
{
ILGenerator ig = ec.ig;
+ if (expr_unwrap != null) {
+ expr_unwrap.EmitCheck (ec);
+ return;
+ }
expr.Emit (ec);
ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
{
ILGenerator ig = ec.ig;
-
- expr.Emit (ec);
- ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
+ if (expr_unwrap != null) {
+ expr_unwrap.EmitCheck (ec);
+ } else {
+ expr.Emit (ec);
+ ig.Emit (OpCodes.Isinst, probe_type_expr.Type);
+ }
ig.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
}
Type d = expr.Type;
bool d_is_nullable = false;
- if (expr is Constant) {
- //
- // If E is a method group or the null literal, of if the type of E is a reference
- // type or a nullable type and the value of E is null, the result is false
- //
- if (expr.IsNull)
- return CreateConstantResult (false);
- } else if (TypeManager.IsNullableType (d) && !TypeManager.ContainsGenericParameters (d)) {
+ //
+ // If E is a method group or the null literal, or if the type of E is a reference
+ // type or a nullable type and the value of E is null, the result is false
+ //
+ if (expr.IsNull || expr.eclass == ExprClass.MethodGroup)
+ return CreateConstantResult (false);
+
+ if (TypeManager.IsNullableType (d) && !TypeManager.ContainsGenericParameters (d)) {
d = TypeManager.GetTypeArguments (d) [0];
d_is_nullable = true;
}
//
// D and T are the same value types but D can be null
//
- if (d_is_nullable && !t_is_nullable)
- return Nullable.HasValue.Create (expr, ec);
+ if (d_is_nullable && !t_is_nullable) {
+ expr_unwrap = Nullable.Unwrap.Create (expr, ec);
+ return this;
+ }
//
// The result is true if D and T are the same value types
return CreateConstantResult (false);
if (constraints.IsValueType && !d.IsValueType)
- return CreateConstantResult (false);
+ return CreateConstantResult (TypeManager.IsEqual (d, t));
}
- expr = new BoxedCast (expr, d);
+ if (!TypeManager.IsReferenceType (expr.Type))
+ expr = new BoxedCast (expr, d);
+
return this;
#else
return null;
#endif
}
- static void Error_CannotConvertType (Type source, Type target, Location loc)
- {
- Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
- TypeManager.CSharpName (source),
- TypeManager.CSharpName (target));
- }
-
public override Expression DoResolve (EmitContext ec)
{
if (resolved_type == null) {
eclass = ExprClass.Value;
Type etype = expr.Type;
- if (type.IsValueType && !TypeManager.IsNullableType (type)) {
- Report.Error (77, loc, "The `as' operator cannot be used with a non-nullable value type `{0}'",
- TypeManager.CSharpName (type));
- return null;
-
- }
-
-#if GMCS_SOURCE
- //
- // If the type is a type parameter, ensure
- // that it is constrained by a class
- //
- TypeParameterExpr tpe = probe_type_expr as TypeParameterExpr;
- if (tpe != null){
- GenericConstraints constraints = tpe.TypeParameter.GenericConstraints;
- bool error = false;
-
- if (constraints == null)
- error = true;
- else {
- if (!constraints.HasClassConstraint)
- if ((constraints.Attributes & GenericParameterAttributes.ReferenceTypeConstraint) == 0)
- error = true;
- }
- if (error){
+ if (!TypeManager.IsReferenceType (type) && !TypeManager.IsNullableType (type)) {
+ if (probe_type_expr is TypeParameterExpr) {
Report.Error (413, loc,
- "The as operator requires that the `{0}' type parameter be constrained by a class",
- probe_type_expr.GetSignatureForError ());
- return null;
+ "The `as' operator cannot be used with a non-reference type parameter `{0}'",
+ probe_type_expr.GetSignatureForError ());
+ } else {
+ Report.Error (77, loc,
+ "The `as' operator cannot be used with a non-nullable value type `{0}'",
+ TypeManager.CSharpName (type));
}
+ return null;
}
-#endif
+
if (expr.IsNull && TypeManager.IsNullableType (type)) {
return Nullable.LiftedNull.CreateFromExpression (this);
}
return this;
}
- Error_CannotConvertType (etype, type, loc);
+ Report.Error (39, loc, "Cannot convert type `{0}' to `{1}' via a built-in conversion",
+ TypeManager.CSharpName (etype), TypeManager.CSharpName (type));
+
return null;
}
get { return "as"; }
}
- public override bool GetAttributableValue (Type value_type, out object value)
+ public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
{
- return expr.GetAttributableValue (value_type, out value);
+ return expr.GetAttributableValue (ec, value_type, out value);
}
}
this.target_type = cast_type;
this.expr = expr;
this.loc = loc;
-
- if (target_type == TypeManager.system_void_expr)
- Error_VoidInvalidInTheContext (loc);
}
public Expression TargetType {
get { return expr; }
}
+ public override Expression CreateExpressionTree (EmitContext ec)
+ {
+ throw new NotSupportedException ("ET");
+ }
+
public override Expression DoResolve (EmitContext ec)
{
expr = expr.Resolve (ec);
type = texpr.Type;
- if (type == TypeManager.void_type) {
- Error_VoidInvalidInTheContext (loc);
- return null;
+ if ((type.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
+ Report.Error (-244, loc, "The `default value' operator cannot be applied to an operand of a static type");
}
- if (TypeManager.IsGenericParameter (type)) {
- GenericConstraints constraints = TypeManager.GetTypeParameterConstraints(type);
- if (constraints != null && constraints.IsReferenceType)
- return new EmptyConstantCast (new NullLiteral (Location), type);
- } else {
- Constant c = New.Constantify (type);
- if (c != null)
- return new EmptyConstantCast (c, type);
+ if (type.IsPointer)
+ return new NullLiteral (Location).ConvertImplicitly (type);
+
+ if (TypeManager.IsReferenceType (type)) {
+ return new EmptyConstantCast (new NullLiteral (Location), type);
- if (!TypeManager.IsValueType (type))
- return new EmptyConstantCast (new NullLiteral (Location), type);
+ // TODO: ET needs
+ // return ReducedExpression.Create (new NullLiteral (Location), this);
}
+
+ Constant c = New.Constantify (type);
+ if (c != null)
+ return c;
+
eclass = ExprClass.Variable;
return this;
}
ec.ig.Emit(OpCodes.Initobj, type);
temp_storage.Emit(ec);
}
+
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ type = storey.MutateType (type);
+ }
protected override void CloneTo (CloneContext clonectx, Expression t)
{
{
b.type = ReturnType;
- if (left != null)
- b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
+ b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
+ b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
- if (right != null)
- b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
+ //
+ // A user operators does not support multiple user conversions, but decimal type
+ // is considered to be predefined type therefore we apply predefined operators rules
+ // and then look for decimal user-operator implementation
+ //
+ if (left == TypeManager.decimal_type)
+ return b.ResolveUserOperator (ec, b.left.Type, b.right.Type);
return b;
}
- public bool IsPrimitiveApplicable (Type type)
+ public bool IsPrimitiveApplicable (Type ltype, Type rtype)
{
//
// We are dealing with primitive types only
//
- return left == type;
+ return left == ltype && ltype == rtype;
}
public virtual bool IsApplicable (EmitContext ec, Expression lexpr, Expression rexpr)
Convert.ImplicitConversionExists (ec, rexpr, right);
}
- public PredefinedOperator ResolveBetterOperator (EmitContext ec, Expression lexpr, Expression rexpr, PredefinedOperator best_operator)
+ public PredefinedOperator ResolveBetterOperator (EmitContext ec, PredefinedOperator best_operator)
{
int result = 0;
if (left != null && best_operator.left != null) {
//
// When second arguments are same as the first one, the result is same
//
- if (left != right || best_operator.left != best_operator.right) {
+ if (right != null && (left != right || best_operator.left != best_operator.right)) {
result |= MethodGroupExpr.BetterTypeConversion (ec, best_operator.right, right);
}
{
}
+ public PredefinedPointerOperator (Type ltype, Type rtype, Operator op_mask, Type retType)
+ : base (ltype, rtype, op_mask, retType)
+ {
+ }
+
public PredefinedPointerOperator (Type type, Operator op_mask, Type return_type)
: base (type, op_mask, return_type)
{
public override Expression ConvertResult (EmitContext ec, Binary b)
{
- base.ConvertResult (ec, b);
+ if (left != null) {
+ b.left = EmptyCast.Create (b.left, left);
+ } else if (right != null) {
+ b.right = EmptyCast.Create (b.right, right);
+ }
Type r_type = ReturnType;
if (r_type == null) {
- r_type = b.left.Type;
- if (r_type == null)
+ if (left == null)
+ r_type = b.left.Type;
+ else
r_type = b.right.Type;
}
- return new PointerArithmetic (b.oper == Operator.Addition,
- b.left, b.right, r_type, b.loc).Resolve (ec);
+ return new PointerArithmetic (b.oper, b.left, b.right, r_type, b.loc).Resolve (ec);
}
}
readonly bool is_compound;
Expression enum_conversion;
- // This must be kept in sync with Operator!!!
- public static readonly string [] oper_names;
-
static PredefinedOperator [] standard_operators;
static PredefinedOperator [] pointer_operators;
- static Binary ()
- {
- oper_names = new string [18];
-
- oper_names [(int) (Operator.Multiply & Operator.ValuesOnlyMask)] = "op_Multiply";
- oper_names [(int) (Operator.Division & Operator.ValuesOnlyMask)] = "op_Division";
- oper_names [(int) (Operator.Modulus & Operator.ValuesOnlyMask)] = "op_Modulus";
- oper_names [(int) (Operator.Addition & Operator.ValuesOnlyMask)] = "op_Addition";
- oper_names [(int) (Operator.Subtraction & Operator.ValuesOnlyMask)] = "op_Subtraction";
- oper_names [(int) (Operator.LeftShift & Operator.ValuesOnlyMask)] = "op_LeftShift";
- oper_names [(int) (Operator.RightShift & Operator.ValuesOnlyMask)] = "op_RightShift";
- oper_names [(int) (Operator.LessThan & Operator.ValuesOnlyMask)] = "op_LessThan";
- oper_names [(int) (Operator.GreaterThan & Operator.ValuesOnlyMask)] = "op_GreaterThan";
- oper_names [(int) (Operator.LessThanOrEqual & Operator.ValuesOnlyMask)] = "op_LessThanOrEqual";
- oper_names [(int) (Operator.GreaterThanOrEqual & Operator.ValuesOnlyMask)] = "op_GreaterThanOrEqual";
- oper_names [(int) (Operator.Equality & Operator.ValuesOnlyMask)] = "op_Equality";
- oper_names [(int) (Operator.Inequality & Operator.ValuesOnlyMask)] = "op_Inequality";
- oper_names [(int) (Operator.BitwiseAnd & Operator.ValuesOnlyMask)] = "op_BitwiseAnd";
- oper_names [(int) (Operator.BitwiseOr & Operator.ValuesOnlyMask)] = "op_BitwiseOr";
- oper_names [(int) (Operator.ExclusiveOr & Operator.ValuesOnlyMask)] = "op_ExclusiveOr";
- oper_names [(int) (Operator.LogicalOr & Operator.ValuesOnlyMask)] = "op_LogicalOr";
- oper_names [(int) (Operator.LogicalAnd & Operator.ValuesOnlyMask)] = "op_LogicalAnd";
- }
-
public Binary (Operator oper, Expression left, Expression right, bool isCompound)
: this (oper, left, right)
{
return s;
}
- static public void Error_OperatorCannotBeApplied (Location loc, string name, Type l, Type r)
+ public static void Error_OperatorCannotBeApplied (Expression left, Expression right, Operator oper, Location loc)
{
- Error_OperatorCannotBeApplied (loc, name, TypeManager.CSharpName (l), TypeManager.CSharpName (r));
+ new Binary (oper, left, right).Error_OperatorCannotBeApplied (left, right);
}
- public static void Error_OperatorCannotBeApplied (Location loc, string name, string left, string right)
- {
- Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
- name, left, right);
- }
-
- protected void Error_OperatorCannotBeApplied (Expression left, Expression right)
+ public static void Error_OperatorCannotBeApplied (Expression left, Expression right, string oper, Location loc)
{
string l, r;
// TODO: This should be handled as Type of method group in CSharpName
else
r = TypeManager.CSharpName (right.Type);
- Error_OperatorCannotBeApplied (Location, OperName (oper), l, r);
+ Report.Error (19, loc, "Operator `{0}' cannot be applied to operands of type `{1}' and `{2}'",
+ oper, l, r);
}
-
- public static string GetOperatorMetadataName (Operator op)
+
+ protected void Error_OperatorCannotBeApplied (Expression left, Expression right)
{
- return oper_names [(int)(op & Operator.ValuesOnlyMask)];
+ Error_OperatorCannotBeApplied (left, right, OperName (oper), loc);
}
- static bool IsUnsigned (Type t)
+ static string GetOperatorMetadataName (Operator op)
{
- while (t.IsPointer)
- t = TypeManager.GetElementType (t);
+ CSharp.Operator.OpType op_type;
+ switch (op) {
+ case Operator.Addition:
+ op_type = CSharp.Operator.OpType.Addition; break;
+ case Operator.BitwiseAnd:
+ op_type = CSharp.Operator.OpType.BitwiseAnd; break;
+ case Operator.BitwiseOr:
+ op_type = CSharp.Operator.OpType.BitwiseOr; break;
+ case Operator.Division:
+ op_type = CSharp.Operator.OpType.Division; break;
+ case Operator.Equality:
+ op_type = CSharp.Operator.OpType.Equality; break;
+ case Operator.ExclusiveOr:
+ op_type = CSharp.Operator.OpType.ExclusiveOr; break;
+ case Operator.GreaterThan:
+ op_type = CSharp.Operator.OpType.GreaterThan; break;
+ case Operator.GreaterThanOrEqual:
+ op_type = CSharp.Operator.OpType.GreaterThanOrEqual; break;
+ case Operator.Inequality:
+ op_type = CSharp.Operator.OpType.Inequality; break;
+ case Operator.LeftShift:
+ op_type = CSharp.Operator.OpType.LeftShift; break;
+ case Operator.LessThan:
+ op_type = CSharp.Operator.OpType.LessThan; break;
+ case Operator.LessThanOrEqual:
+ op_type = CSharp.Operator.OpType.LessThanOrEqual; break;
+ case Operator.Modulus:
+ op_type = CSharp.Operator.OpType.Modulus; break;
+ case Operator.Multiply:
+ op_type = CSharp.Operator.OpType.Multiply; break;
+ case Operator.RightShift:
+ op_type = CSharp.Operator.OpType.RightShift; break;
+ case Operator.Subtraction:
+ op_type = CSharp.Operator.OpType.Subtraction; break;
+ default:
+ throw new InternalErrorException (op.ToString ());
+ }
- return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||
- t == TypeManager.ushort_type || t == TypeManager.byte_type);
+ return CSharp.Operator.GetMetadataName (op_type);
}
- static bool IsFloat (Type t)
+ public static void EmitOperatorOpcode (EmitContext ec, Operator oper, Type l)
{
- return t == TypeManager.float_type || t == TypeManager.double_type;
- }
+ OpCode opcode;
+ ILGenerator ig = ec.ig;
- Expression ResolveOperator (EmitContext ec)
- {
+ switch (oper){
+ case Operator.Multiply:
+ if (ec.CheckState){
+ if (l == TypeManager.int32_type || l == TypeManager.int64_type)
+ opcode = OpCodes.Mul_Ovf;
+ else if (!IsFloat (l))
+ opcode = OpCodes.Mul_Ovf_Un;
+ else
+ opcode = OpCodes.Mul;
+ } else
+ opcode = OpCodes.Mul;
+
+ break;
+
+ case Operator.Division:
+ if (IsUnsigned (l))
+ opcode = OpCodes.Div_Un;
+ else
+ opcode = OpCodes.Div;
+ break;
+
+ case Operator.Modulus:
+ if (IsUnsigned (l))
+ opcode = OpCodes.Rem_Un;
+ else
+ opcode = OpCodes.Rem;
+ break;
+
+ case Operator.Addition:
+ if (ec.CheckState){
+ if (l == TypeManager.int32_type || l == TypeManager.int64_type)
+ opcode = OpCodes.Add_Ovf;
+ else if (!IsFloat (l))
+ opcode = OpCodes.Add_Ovf_Un;
+ else
+ opcode = OpCodes.Add;
+ } else
+ opcode = OpCodes.Add;
+ break;
+
+ case Operator.Subtraction:
+ if (ec.CheckState){
+ if (l == TypeManager.int32_type || l == TypeManager.int64_type)
+ opcode = OpCodes.Sub_Ovf;
+ else if (!IsFloat (l))
+ opcode = OpCodes.Sub_Ovf_Un;
+ else
+ opcode = OpCodes.Sub;
+ } else
+ opcode = OpCodes.Sub;
+ break;
+
+ case Operator.RightShift:
+ if (IsUnsigned (l))
+ opcode = OpCodes.Shr_Un;
+ else
+ opcode = OpCodes.Shr;
+ break;
+
+ case Operator.LeftShift:
+ opcode = OpCodes.Shl;
+ break;
+
+ case Operator.Equality:
+ opcode = OpCodes.Ceq;
+ break;
+
+ case Operator.Inequality:
+ ig.Emit (OpCodes.Ceq);
+ ig.Emit (OpCodes.Ldc_I4_0);
+
+ opcode = OpCodes.Ceq;
+ break;
+
+ case Operator.LessThan:
+ if (IsUnsigned (l))
+ opcode = OpCodes.Clt_Un;
+ else
+ opcode = OpCodes.Clt;
+ break;
+
+ case Operator.GreaterThan:
+ if (IsUnsigned (l))
+ opcode = OpCodes.Cgt_Un;
+ else
+ opcode = OpCodes.Cgt;
+ break;
+
+ case Operator.LessThanOrEqual:
+ if (IsUnsigned (l) || IsFloat (l))
+ ig.Emit (OpCodes.Cgt_Un);
+ else
+ ig.Emit (OpCodes.Cgt);
+ ig.Emit (OpCodes.Ldc_I4_0);
+
+ opcode = OpCodes.Ceq;
+ break;
+
+ case Operator.GreaterThanOrEqual:
+ if (IsUnsigned (l) || IsFloat (l))
+ ig.Emit (OpCodes.Clt_Un);
+ else
+ ig.Emit (OpCodes.Clt);
+
+ ig.Emit (OpCodes.Ldc_I4_0);
+
+ opcode = OpCodes.Ceq;
+ break;
+
+ case Operator.BitwiseOr:
+ opcode = OpCodes.Or;
+ break;
+
+ case Operator.BitwiseAnd:
+ opcode = OpCodes.And;
+ break;
+
+ case Operator.ExclusiveOr:
+ opcode = OpCodes.Xor;
+ break;
+
+ default:
+ throw new InternalErrorException (oper.ToString ());
+ }
+
+ ig.Emit (opcode);
+ }
+
+ static bool IsUnsigned (Type t)
+ {
+ if (t.IsPointer)
+ return true;
+
+ return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||
+ t == TypeManager.ushort_type || t == TypeManager.byte_type);
+ }
+
+ static bool IsFloat (Type t)
+ {
+ return t == TypeManager.float_type || t == TypeManager.double_type;
+ }
+
+ Expression ResolveOperator (EmitContext ec)
+ {
Type l = left.Type;
Type r = right.Type;
Expression expr;
}
// Delegates
- if (oper == Operator.Addition || oper == Operator.Subtraction) {
- if (TypeManager.IsDelegateType (l))
- return ResolveOperatorDelegateBinary (ec, l, r);
+ if ((oper == Operator.Addition || oper == Operator.Subtraction || (oper & Operator.EqualityMask) != 0) &&
+ (TypeManager.IsDelegateType (l) || TypeManager.IsDelegateType (r))) {
+
+ expr = ResolveOperatorDelegate (ec, l, r);
+
+ // TODO: Can this be ambiguous
+ if (expr != null)
+ return expr;
}
// User operators
// T* operator + (long y, T *x);
// T* operator + (ulong y, T *x);
//
- temp.Add (new PredefinedPointerOperator (TypeManager.int32_type, null, Operator.AdditionMask));
- temp.Add (new PredefinedPointerOperator (TypeManager.uint32_type, null, Operator.AdditionMask));
- temp.Add (new PredefinedPointerOperator (TypeManager.int64_type, null, Operator.AdditionMask));
- temp.Add (new PredefinedPointerOperator (TypeManager.uint64_type, null, Operator.AdditionMask));
+ temp.Add (new PredefinedPointerOperator (TypeManager.int32_type, null, Operator.AdditionMask, null));
+ temp.Add (new PredefinedPointerOperator (TypeManager.uint32_type, null, Operator.AdditionMask, null));
+ temp.Add (new PredefinedPointerOperator (TypeManager.int64_type, null, Operator.AdditionMask, null));
+ temp.Add (new PredefinedPointerOperator (TypeManager.uint64_type, null, Operator.AdditionMask, null));
//
// long operator - (T* x, T *y)
temp.Add (new PredefinedOperator (TypeManager.uint64_type, Operator.ArithmeticMask | Operator.BitwiseMask));
temp.Add (new PredefinedOperator (TypeManager.float_type, Operator.ArithmeticMask));
temp.Add (new PredefinedOperator (TypeManager.double_type, Operator.ArithmeticMask));
+ temp.Add (new PredefinedOperator (TypeManager.decimal_type, Operator.ArithmeticMask));
temp.Add (new PredefinedOperator (TypeManager.int32_type, Operator.ComparisonMask, bool_type));
temp.Add (new PredefinedOperator (TypeManager.uint32_type, Operator.ComparisonMask, bool_type));
temp.Add (new PredefinedOperator (TypeManager.uint64_type, Operator.ComparisonMask, bool_type));
temp.Add (new PredefinedOperator (TypeManager.float_type, Operator.ComparisonMask, bool_type));
temp.Add (new PredefinedOperator (TypeManager.double_type, Operator.ComparisonMask, bool_type));
+ temp.Add (new PredefinedOperator (TypeManager.decimal_type, Operator.ComparisonMask, bool_type));
temp.Add (new PredefinedOperator (TypeManager.string_type, Operator.EqualityMask, bool_type));
return null;
}
- if (rc != null) {
- right = left;
- lc = rc;
- }
-
+ //
// The result is a constant with side-effect
- return new SideEffectConstant (lc, right, loc);
+ //
+ Constant side_effect = rc == null ?
+ new SideEffectConstant (lc, right, loc) :
+ new SideEffectConstant (rc, left, loc);
+
+ return ReducedExpression.Create (side_effect, this);
}
}
return expr;
}
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ left.MutateHoistedGenericType (storey);
+ right.MutateHoistedGenericType (storey);
+ }
+
//
// D operator + (D x, D y)
// D operator - (D x, D y)
+ // bool operator == (D x, D y)
+ // bool operator != (D x, D y)
//
- Expression ResolveOperatorDelegateBinary (EmitContext ec, Type l, Type r)
+ Expression ResolveOperatorDelegate (EmitContext ec, Type l, Type r)
{
- if (((right.eclass == ExprClass.MethodGroup) || (r == TypeManager.anonymous_method_type))) {
- if ((RootContext.Version != LanguageVersion.ISO_1)) {
- Expression tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
+ bool is_equality = (oper & Operator.EqualityMask) != 0;
+ if (!TypeManager.IsEqual (l, r)) {
+ Expression tmp;
+ if (right.eclass == ExprClass.MethodGroup || (r == TypeManager.anonymous_method_type && !is_equality)) {
+ tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
if (tmp == null)
return null;
right = tmp;
r = right.Type;
- }
- } else {
- if (!TypeManager.IsEqual (l, r) && !(right is NullLiteral))
+ } else if (left.eclass == ExprClass.MethodGroup || (l == TypeManager.anonymous_method_type && !is_equality)) {
+ tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
+ if (tmp == null)
+ return null;
+ left = tmp;
+ l = left.Type;
+ } else {
return null;
+ }
}
+ //
+ // Resolve delegate equality as a user operator
+ //
+ if (is_equality)
+ return ResolveUserOperator (ec, l, r);
+
MethodInfo method;
ArrayList args = new ArrayList (2);
-
- args = new ArrayList (2);
args.Add (new Argument (left, Argument.AType.Expression));
args.Add (new Argument (right, Argument.AType.Expression));
method = TypeManager.delegate_remove_delegate_delegate;
}
- return new BinaryDelegate (l, method, args);
+ MethodGroupExpr mg = new MethodGroupExpr (new MemberInfo [] { method }, TypeManager.delegate_type, loc);
+ mg = mg.OverloadResolve (ec, ref args, false, loc);
+
+ return new ClassCast (new UserOperatorCall (mg, args, CreateExpressionTree, loc), l);
}
//
//
Expression ResolveOperatorEnum (EmitContext ec, bool lenum, bool renum, Type ltype, Type rtype)
{
- Expression temp;
+ //
+ // bool operator == (E x, E y);
+ // bool operator != (E x, E y);
+ // bool operator < (E x, E y);
+ // bool operator > (E x, E y);
+ // bool operator <= (E x, E y);
+ // bool operator >= (E x, E y);
+ //
+ // E operator & (E x, E y);
+ // E operator | (E x, E y);
+ // E operator ^ (E x, E y);
+ //
+ // U operator - (E e, E f)
+ // E operator - (E e, U x)
+ //
+ // E operator + (U x, E e)
+ // E operator + (E e, U x)
+ //
+ if (!((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0 ||
+ (oper == Operator.Subtraction && lenum) || (oper == Operator.Addition && lenum != renum)))
+ return null;
- if (lenum || renum) {
- //
- // bool operator == (E x, E y);
- // bool operator != (E x, E y);
- // bool operator < (E x, E y);
- // bool operator > (E x, E y);
- // bool operator <= (E x, E y);
- // bool operator >= (E x, E y);
- //
- if ((oper & Operator.ComparisonMask) != 0) {
- type = TypeManager.bool_type;
- } else if ((oper & Operator.BitwiseMask) != 0) {
- type = ltype;
+ Expression ltemp = left;
+ Expression rtemp = right;
+ Type underlying_type;
+ Expression expr;
+
+ if ((oper & Operator.ComparisonMask | Operator.BitwiseMask) != 0) {
+ if (renum) {
+ expr = Convert.ImplicitConversion (ec, left, rtype, loc);
+ if (expr != null) {
+ left = expr;
+ ltype = expr.Type;
+ }
+ } else if (lenum) {
+ expr = Convert.ImplicitConversion (ec, right, ltype, loc);
+ if (expr != null) {
+ right = expr;
+ rtype = expr.Type;
+ }
}
+ }
- if (type != null) {
- if (!TypeManager.IsEqual (ltype, rtype)) {
- if (!lenum) {
- temp = Convert.ImplicitConversion (ec, left, rtype, loc);
- if (temp == null)
- return null;
- left = temp;
- } else {
- temp = Convert.ImplicitConversion (ec, right, ltype, loc);
- if (temp == null)
- return null;
- right = temp;
- }
- }
+ if (TypeManager.IsEqual (ltype, rtype)) {
+ underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
- return this;
- }
- }
+ if (left is Constant)
+ left = ((Constant) left).ConvertExplicitly (false, underlying_type);
+ else
+ left = EmptyCast.Create (left, underlying_type);
- Type underlying_type;
- if (lenum && !renum) {
- //
- // E operator + (E e, U x)
- // E operator - (E e, U x)
- //
- if (oper == Operator.Addition || oper == Operator.Subtraction) {
- underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
- temp = left;
- left = EmptyCast.Create (left, underlying_type, true);
- if (!DoBinaryOperatorPromotion (ec)) {
- left = temp;
- return null;
- }
+ if (right is Constant)
+ right = ((Constant) right).ConvertExplicitly (false, underlying_type);
+ else
+ right = EmptyCast.Create (right, underlying_type);
+ } else if (lenum) {
+ underlying_type = TypeManager.GetEnumUnderlyingType (ltype);
- enum_conversion = Convert.ExplicitNumericConversion (
- new EmptyExpression (left.Type), underlying_type);
+ if (oper != Operator.Subtraction && oper != Operator.Addition) {
+ Constant c = right as Constant;
+ if (c == null || !c.IsDefaultValue)
+ return null;
+ } else {
+ if (!Convert.ImplicitStandardConversionExists (right, underlying_type))
+ return null;
- return ResolveOperatorPredefined (ec, standard_operators, true, ltype);
+ right = Convert.ImplicitConversionStandard (ec, right, underlying_type, right.Location);
}
- return null;
- }
+ if (left is Constant)
+ left = ((Constant) left).ConvertExplicitly (false, underlying_type);
+ else
+ left = EmptyCast.Create (left, underlying_type);
- if (renum) {
- //
- // E operator + (U x, E e)
- //
- if (oper == Operator.Addition) {
- underlying_type = TypeManager.GetEnumUnderlyingType (rtype);
- temp = Convert.ImplicitConversion (ec, left, underlying_type, loc);
- if (temp == null)
+ } else if (renum) {
+ underlying_type = TypeManager.GetEnumUnderlyingType (rtype);
+
+ if (oper != Operator.Addition) {
+ Constant c = left as Constant;
+ if (c == null || !c.IsDefaultValue)
+ return null;
+ } else {
+ if (!Convert.ImplicitStandardConversionExists (left, underlying_type))
return null;
- left = temp;
- type = rtype;
- return this;
+ left = Convert.ImplicitConversionStandard (ec, left, underlying_type, left.Location);
}
+
+ if (right is Constant)
+ right = ((Constant) right).ConvertExplicitly (false, underlying_type);
+ else
+ right = EmptyCast.Create (right, underlying_type);
+
+ } else {
+ return null;
}
//
- // U operator - (E e, E f)
+ // C# specification uses explicit cast syntax which means binary promotion
+ // should happen, however it seems that csc does not do that
//
- if (oper == Operator.Subtraction) {
- if (!TypeManager.IsEqual (ltype, rtype))
- return null;
+ if (!DoBinaryOperatorPromotion (ec)) {
+ left = ltemp;
+ right = rtemp;
+ return null;
+ }
- type = TypeManager.GetEnumUnderlyingType (ltype);
- return this;
+ Type res_type = null;
+ if ((oper & Operator.BitwiseMask) != 0 || oper == Operator.Subtraction || oper == Operator.Addition) {
+ Type promoted_type = lenum ? left.Type : right.Type;
+ enum_conversion = Convert.ExplicitNumericConversion (
+ new EmptyExpression (promoted_type), underlying_type);
+
+ if (oper == Operator.Subtraction && renum && lenum)
+ res_type = underlying_type;
+ else if (oper == Operator.Addition && renum)
+ res_type = rtype;
+ else
+ res_type = ltype;
}
+
+ expr = ResolveOperatorPredefined (ec, standard_operators, true, res_type);
+ if (!is_compound || expr == null)
+ return expr;
- return null;
+ //
+ // TODO: Need to corectly implemented Coumpound Assigment for all operators
+ // Section: 7.16.2
+ //
+ if (Convert.ImplicitConversionExists (ec, left, rtype))
+ return expr;
+
+ if (!Convert.ImplicitConversionExists (ec, ltemp, rtype))
+ return null;
+
+ expr = Convert.ExplicitConversion (ec, expr, rtype, loc);
+ return expr;
}
//
return null;
} else if (l.IsInterface) {
l = TypeManager.object_type;
+ } else if (l.IsValueType) {
+ return null;
}
if (rgen) {
return null;
} else if (r.IsInterface) {
r = TypeManager.object_type;
+ } else if (r.IsValueType) {
+ return null;
}
+
const string ref_comparison = "Possible unintended reference comparison. " +
"Consider casting the {0} side of the expression to `string' to compare the values";
{
PredefinedOperator best_operator = null;
Type l = left.Type;
+ Type r = right.Type;
Operator oper_mask = oper & ~Operator.ValuesOnlyMask;
foreach (PredefinedOperator po in operators) {
continue;
if (primitives_only) {
- if (!po.IsPrimitiveApplicable (l))
+ if (!po.IsPrimitiveApplicable (l, r))
continue;
} else {
if (!po.IsApplicable (ec, left, right))
continue;
}
- best_operator = po.ResolveBetterOperator (ec, left, right, best_operator);
+ best_operator = po.ResolveBetterOperator (ec, best_operator);
if (best_operator == null) {
Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
string op = GetOperatorMetadataName (user_oper);
- MethodGroupExpr union;
MethodGroupExpr left_operators = MemberLookup (ec.ContainerType, l, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
- if (!TypeManager.IsEqual (r, l)) {
- MethodGroupExpr right_operators = MemberLookup (
- ec.ContainerType, r, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
- union = MethodGroupExpr.MakeUnionSet (left_operators, right_operators, loc);
- } else
- union = left_operators;
+ MethodGroupExpr right_operators = null;
- if (union == null)
+ if (!TypeManager.IsEqual (r, l)) {
+ right_operators = MemberLookup (ec.ContainerType, r, op, MemberTypes.Method, AllBindingFlags, loc) as MethodGroupExpr;
+ if (right_operators == null && left_operators == null)
+ return null;
+ } else if (left_operators == null) {
return null;
+ }
ArrayList args = new ArrayList (2);
Argument larg = new Argument (left);
Argument rarg = new Argument (right);
args.Add (rarg);
- union = union.OverloadResolve (ec, ref args, true, loc);
- if (union == null)
- return null;
-
- Expression oper_expr;
+ MethodGroupExpr union;
- // TODO: CreateExpressionTree is allocated every time
- if (user_oper != oper) {
- oper_expr = new ConditionalLogicalOperator (union, args, CreateExpressionTree,
+ //
+ // User-defined operator implementations always take precedence
+ // over predefined operator implementations
+ //
+ if (left_operators != null && right_operators != null) {
+ if (IsPredefinedUserOperator (l, user_oper)) {
+ union = right_operators.OverloadResolve (ec, ref args, true, loc);
+ if (union == null)
+ union = left_operators;
+ } else if (IsPredefinedUserOperator (r, user_oper)) {
+ union = left_operators.OverloadResolve (ec, ref args, true, loc);
+ if (union == null)
+ union = right_operators;
+ } else {
+ union = MethodGroupExpr.MakeUnionSet (left_operators, right_operators, loc);
+ }
+ } else if (left_operators != null) {
+ union = left_operators;
+ } else {
+ union = right_operators;
+ }
+
+ union = union.OverloadResolve (ec, ref args, true, loc);
+ if (union == null)
+ return null;
+
+ Expression oper_expr;
+
+ // TODO: CreateExpressionTree is allocated every time
+ if (user_oper != oper) {
+ oper_expr = new ConditionalLogicalOperator (union, args, CreateExpressionTree,
oper == Operator.LogicalAnd, loc).Resolve (ec);
} else {
oper_expr = new UserOperatorCall (union, args, CreateExpressionTree, loc);
WarnUselessComparison (type);
}
- private bool IsValueOutOfRange (long value, Type type)
+ static bool IsValueOutOfRange (long value, Type type)
{
if (IsTypeUnsigned (type) && value < 0)
return true;
t == TypeManager.delegate_type || TypeManager.IsDelegateType (t);
}
+ static bool IsPredefinedUserOperator (Type t, Operator op)
+ {
+ //
+ // Some predefined types have user operators
+ //
+ return (op & Operator.EqualityMask) != 0 && (t == TypeManager.string_type || t == TypeManager.decimal_type);
+ }
+
private static bool IsTypeIntegral (Type type)
{
return type == TypeManager.uint64_type ||
right.Emit (ec);
Type t = left.Type;
- bool is_unsigned = IsUnsigned (t) || t == TypeManager.double_type || t == TypeManager.float_type;
+ bool is_float = IsFloat (t);
+ bool is_unsigned = is_float || IsUnsigned (t);
switch (oper){
case Operator.Equality:
case Operator.LessThan:
if (on_true)
- if (is_unsigned)
+ if (is_unsigned && !is_float)
ig.Emit (OpCodes.Blt_Un, target);
else
ig.Emit (OpCodes.Blt, target);
case Operator.GreaterThan:
if (on_true)
- if (is_unsigned)
+ if (is_unsigned && !is_float)
ig.Emit (OpCodes.Bgt_Un, target);
else
ig.Emit (OpCodes.Bgt, target);
case Operator.LessThanOrEqual:
if (on_true)
- if (is_unsigned)
+ if (is_unsigned && !is_float)
ig.Emit (OpCodes.Ble_Un, target);
else
ig.Emit (OpCodes.Ble, target);
case Operator.GreaterThanOrEqual:
if (on_true)
- if (is_unsigned)
+ if (is_unsigned && !is_float)
ig.Emit (OpCodes.Bge_Un, target);
else
ig.Emit (OpCodes.Bge, target);
}
right.Emit (ec);
-
- OpCode opcode;
-
- switch (oper){
- case Operator.Multiply:
- if (ec.CheckState){
- if (l == TypeManager.int32_type || l == TypeManager.int64_type)
- opcode = OpCodes.Mul_Ovf;
- else if (!IsFloat (l))
- opcode = OpCodes.Mul_Ovf_Un;
- else
- opcode = OpCodes.Mul;
- } else
- opcode = OpCodes.Mul;
-
- break;
-
- case Operator.Division:
- if (IsUnsigned (l))
- opcode = OpCodes.Div_Un;
- else
- opcode = OpCodes.Div;
- break;
-
- case Operator.Modulus:
- if (IsUnsigned (l))
- opcode = OpCodes.Rem_Un;
- else
- opcode = OpCodes.Rem;
- break;
-
- case Operator.Addition:
- if (ec.CheckState){
- if (l == TypeManager.int32_type || l == TypeManager.int64_type)
- opcode = OpCodes.Add_Ovf;
- else if (!IsFloat (l))
- opcode = OpCodes.Add_Ovf_Un;
- else
- opcode = OpCodes.Add;
- } else
- opcode = OpCodes.Add;
- break;
-
- case Operator.Subtraction:
- if (ec.CheckState){
- if (l == TypeManager.int32_type || l == TypeManager.int64_type)
- opcode = OpCodes.Sub_Ovf;
- else if (!IsFloat (l))
- opcode = OpCodes.Sub_Ovf_Un;
- else
- opcode = OpCodes.Sub;
- } else
- opcode = OpCodes.Sub;
- break;
-
- case Operator.RightShift:
- if (IsUnsigned (l))
- opcode = OpCodes.Shr_Un;
- else
- opcode = OpCodes.Shr;
- break;
-
- case Operator.LeftShift:
- opcode = OpCodes.Shl;
- break;
-
- case Operator.Equality:
- opcode = OpCodes.Ceq;
- break;
-
- case Operator.Inequality:
- ig.Emit (OpCodes.Ceq);
- ig.Emit (OpCodes.Ldc_I4_0);
-
- opcode = OpCodes.Ceq;
- break;
-
- case Operator.LessThan:
- if (IsUnsigned (l))
- opcode = OpCodes.Clt_Un;
- else
- opcode = OpCodes.Clt;
- break;
-
- case Operator.GreaterThan:
- if (IsUnsigned (l))
- opcode = OpCodes.Cgt_Un;
- else
- opcode = OpCodes.Cgt;
- break;
-
- case Operator.LessThanOrEqual:
- if (IsUnsigned (l) || IsFloat (l))
- ig.Emit (OpCodes.Cgt_Un);
- else
- ig.Emit (OpCodes.Cgt);
- ig.Emit (OpCodes.Ldc_I4_0);
-
- opcode = OpCodes.Ceq;
- break;
-
- case Operator.GreaterThanOrEqual:
- if (IsUnsigned (l) || IsFloat (l))
- ig.Emit (OpCodes.Clt_Un);
- else
- ig.Emit (OpCodes.Clt);
-
- ig.Emit (OpCodes.Ldc_I4_0);
-
- opcode = OpCodes.Ceq;
- break;
-
- case Operator.BitwiseOr:
- opcode = OpCodes.Or;
- break;
-
- case Operator.BitwiseAnd:
- opcode = OpCodes.And;
- break;
-
- case Operator.ExclusiveOr:
- opcode = OpCodes.Xor;
- break;
-
- default:
- throw new InternalErrorException (oper.ToString ());
- }
-
- ig.Emit (opcode);
+ EmitOperatorOpcode (ec, oper, l);
//
// Nullable enum could require underlying type cast and we cannot simply wrap binary
return CreateExpressionFactoryCall (method_name, args);
}
}
-
- //
- // Object created by Binary when the binary operator uses an method instead of being
- // a binary operation that maps to a CIL binary operation.
- //
- public class BinaryMethod : Expression {
- public MethodBase method;
- public ArrayList Arguments;
-
- public BinaryMethod (Type t, MethodBase m, ArrayList args)
- {
- method = m;
- Arguments = args;
- type = t;
- eclass = ExprClass.Value;
- }
-
- public override Expression DoResolve (EmitContext ec)
- {
- return this;
- }
-
- public override void Emit (EmitContext ec)
- {
- ILGenerator ig = ec.ig;
-
- Invocation.EmitArguments (ec, Arguments, false, null);
-
- if (method is MethodInfo)
- ig.Emit (OpCodes.Call, (MethodInfo) method);
- else
- ig.Emit (OpCodes.Call, (ConstructorInfo) method);
- }
- }
//
// Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
if (concat != null)
concat.Emit (ec);
}
- }
-
- //
- // Object created with +/= on delegates
- //
- public class BinaryDelegate : Expression {
- MethodInfo method;
- ArrayList args;
-
- public BinaryDelegate (Type t, MethodInfo mi, ArrayList args)
- {
- method = mi;
- this.args = args;
- type = t;
- eclass = ExprClass.Value;
- }
-
- public override Expression DoResolve (EmitContext ec)
- {
- return this;
- }
-
- public override void Emit (EmitContext ec)
+
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
{
- ILGenerator ig = ec.ig;
-
- Invocation.EmitArguments (ec, args, false, null);
-
- ig.Emit (OpCodes.Call, (MethodInfo) method);
- ig.Emit (OpCodes.Castclass, type);
- }
-
- public Expression Right {
- get {
- Argument arg = (Argument) args [1];
- return arg.Expr;
- }
- }
-
- public bool IsAddition {
- get {
- return method == TypeManager.delegate_combine_delegate_delegate;
- }
- }
+ foreach (Argument a in arguments)
+ a.Expr.MutateHoistedGenericType (storey);
+ }
}
-
+
//
// User-defined conditional logical operator
//
{
MethodInfo method = (MethodInfo)mg;
type = TypeManager.TypeToCoreType (method.ReturnType);
- ParameterData pd = TypeManager.GetParameterData (method);
+ AParametersCollection pd = TypeManager.GetParameterData (method);
if (!TypeManager.IsEqual (type, type) || !TypeManager.IsEqual (type, pd.Types [0]) || !TypeManager.IsEqual (type, pd.Types [1])) {
Report.Error (217, loc,
"A user-defined operator `{0}' must have parameters and return values of the same type in order to be applicable as a short circuit operator",
public class PointerArithmetic : Expression {
Expression left, right;
- bool is_add;
+ Binary.Operator op;
//
// We assume that `l' is always a pointer
//
- public PointerArithmetic (bool is_addition, Expression l, Expression r, Type t, Location loc)
+ public PointerArithmetic (Binary.Operator op, Expression l, Expression r, Type t, Location loc)
{
type = t;
this.loc = loc;
left = l;
right = r;
- is_add = is_addition;
+ this.op = op;
+ }
+
+ public override Expression CreateExpressionTree (EmitContext ec)
+ {
+ Error_PointerInsideExpressionTree ();
+ return null;
}
public override Expression DoResolve (EmitContext ec)
ILGenerator ig = ec.ig;
// It must be either array or fixed buffer
- Type element = TypeManager.HasElementType (op_type) ?
- element = TypeManager.GetElementType (op_type) :
- element = AttributeTester.GetFixedBuffer (((FieldExpr)left).FieldInfo).ElementType;
+ Type element;
+ if (TypeManager.HasElementType (op_type)) {
+ element = TypeManager.GetElementType (op_type);
+ } else {
+ FieldExpr fe = left as FieldExpr;
+ if (fe != null)
+ element = AttributeTester.GetFixedBuffer (fe.FieldInfo).ElementType;
+ else
+ element = op_type;
+ }
int size = GetTypeSize (element);
Type rtype = right.Type;
- if (rtype.IsPointer){
+ if ((op & Binary.Operator.SubtractionMask) != 0 && rtype.IsPointer){
//
// handle (pointer - pointer)
//
// handle + and - on (pointer op int)
//
left.Emit (ec);
- ig.Emit (OpCodes.Conv_I);
Constant right_const = right as Constant;
- if (right_const != null && size != 0) {
- Expression ex = ConstantFold.BinaryFold (ec, Binary.Operator.Multiply, new IntConstant (size, right.Location), right_const, loc);
- if (ex == null)
+ if (right_const != null) {
+ //
+ // Optimize 0-based arithmetic
+ //
+ if (right_const.IsDefaultValue)
return;
- ex.Emit (ec);
- } else {
- right.Emit (ec);
- if (size != 1){
- if (size == 0)
- ig.Emit (OpCodes.Sizeof, element);
- else
- IntLiteral.EmitInt (ig, size);
- if (rtype == TypeManager.int64_type)
- ig.Emit (OpCodes.Conv_I8);
- else if (rtype == TypeManager.uint64_type)
- ig.Emit (OpCodes.Conv_U8);
- ig.Emit (OpCodes.Mul);
+
+ if (size != 0) {
+ right = ConstantFold.BinaryFold (ec, Binary.Operator.Multiply, new IntConstant (size, right.Location), right_const, loc);
+ if (right == null)
+ return;
+ } else {
+ ig.Emit (OpCodes.Sizeof, element);
+ right = EmptyExpression.Null;
}
}
-
- if (rtype == TypeManager.int64_type || rtype == TypeManager.uint64_type)
+
+ right.Emit (ec);
+ if (rtype == TypeManager.sbyte_type || rtype == TypeManager.byte_type ||
+ rtype == TypeManager.short_type || rtype == TypeManager.ushort_type) {
ig.Emit (OpCodes.Conv_I);
-
- if (is_add)
- ig.Emit (OpCodes.Add);
- else
- ig.Emit (OpCodes.Sub);
+ } else if (rtype == TypeManager.uint32_type) {
+ ig.Emit (OpCodes.Conv_U);
+ }
+
+ if (right_const == null && size != 1){
+ if (size == 0)
+ ig.Emit (OpCodes.Sizeof, element);
+ else
+ IntLiteral.EmitInt (ig, size);
+ if (rtype == TypeManager.int64_type || rtype == TypeManager.uint64_type)
+ ig.Emit (OpCodes.Conv_I8);
+
+ Binary.EmitOperatorOpcode (ec, Binary.Operator.Multiply, rtype);
+ }
+
+ if (rtype == TypeManager.int64_type)
+ ig.Emit (OpCodes.Conv_I);
+ else if (rtype == TypeManager.uint64_type)
+ ig.Emit (OpCodes.Conv_U);
+
+ Binary.EmitOperatorOpcode (ec, op, op_type);
}
}
}
return null;
eclass = ExprClass.Value;
- if (true_expr.Type == false_expr.Type) {
- type = true_expr.Type;
- if (type == TypeManager.null_type) {
- // TODO: probably will have to implement ConditionalConstant
- // to call method without return constant as well
- Report.Warning (-101, 1, loc, "Conditional expression will always return same value");
- return true_expr;
- }
- } else {
- Expression conv;
- Type true_type = true_expr.Type;
- Type false_type = false_expr.Type;
+ Type true_type = true_expr.Type;
+ Type false_type = false_expr.Type;
+ type = true_type;
- //
- // First, if an implicit conversion exists from true_expr
- // to false_expr, then the result type is of type false_expr.Type
- //
- conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
- if (conv != null){
+ //
+ // First, if an implicit conversion exists from true_expr
+ // to false_expr, then the result type is of type false_expr.Type
+ //
+ if (!TypeManager.IsEqual (true_type, false_type)) {
+ Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
+ if (conv != null) {
//
// Check if both can convert implicitl to each other's type
//
- if (Convert.ImplicitConversion (ec, false_expr, true_type, loc) != null){
+ if (Convert.ImplicitConversion (ec, false_expr, true_type, loc) != null) {
Error (172,
- "Can not compute type of conditional expression " +
- "as `" + TypeManager.CSharpName (true_expr.Type) +
- "' and `" + TypeManager.CSharpName (false_expr.Type) +
- "' convert implicitly to each other");
+ "Can not compute type of conditional expression " +
+ "as `" + TypeManager.CSharpName (true_expr.Type) +
+ "' and `" + TypeManager.CSharpName (false_expr.Type) +
+ "' convert implicitly to each other");
return null;
}
type = false_type;
true_expr = conv;
- } else if ((conv = Convert.ImplicitConversion(ec, false_expr, true_type,loc))!= null){
- type = true_type;
+ } else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
false_expr = conv;
} else {
- Report.Error (173, loc, "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
+ Report.Error (173, loc,
+ "Type of conditional expression cannot be determined because there is no implicit conversion between `{0}' and `{1}'",
true_expr.GetSignatureForError (), false_expr.GetSignatureForError ());
return null;
}
- }
+ }
// Dead code optimalization
- if (expr is BoolConstant){
- BoolConstant bc = (BoolConstant) expr;
-
- Report.Warning (429, 4, bc.Value ? false_expr.Location : true_expr.Location, "Unreachable expression code detected");
- return bc.Value ? true_expr : false_expr;
+ Constant c = expr as Constant;
+ if (c != null){
+ bool is_false = c.IsDefaultValue;
+ Report.Warning (429, 4, is_false ? true_expr.Location : false_expr.Location, "Unreachable expression code detected");
+ return ReducedExpression.Create (is_false ? false_expr : true_expr, this).Resolve (ec);
}
return this;
}
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ expr.MutateHoistedGenericType (storey);
+ true_expr.MutateHoistedGenericType (storey);
+ false_expr.MutateHoistedGenericType (storey);
+ type = storey.MutateType (type);
+ }
+
public override TypeExpr ResolveAsTypeTerminal (IResolveContext ec, bool silent)
{
return null;
}
}
- public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation {
- bool prepared;
+ public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation, IVariableReference {
LocalTemporary temp;
- public abstract Variable Variable {
- get;
- }
+ #region Abstract
+ public abstract HoistedVariable HoistedVariable { get; }
+ public abstract bool IsFixedVariable { get; }
+ public abstract bool IsRef { get; }
+ public abstract string Name { get; }
+ public abstract void SetHasAddressTaken ();
+
+ //
+ // Variable IL data, it has to be protected to encapsulate hoisted variables
+ //
+ protected abstract ILocalVariable Variable { get; }
+
+ //
+ // Variable flow-analysis data
+ //
+ public abstract VariableInfo VariableInfo { get; }
+ #endregion
+
+ public void AddressOf (EmitContext ec, AddressOp mode)
+ {
+ if (IsHoistedEmitRequired (ec)) {
+ HoistedVariable.AddressOf (ec, mode);
+ return;
+ }
- public abstract bool IsRef {
- get;
+ Variable.EmitAddressOf (ec);
}
public override void Emit (EmitContext ec)
//
public void EmitLoad (EmitContext ec)
{
- Report.Debug (64, "VARIABLE EMIT LOAD", this, Variable, type, loc);
- if (!prepared)
- Variable.EmitInstance (ec);
Variable.Emit (ec);
}
-
+
public void Emit (EmitContext ec, bool leave_copy)
{
Report.Debug (64, "VARIABLE EMIT", this, Variable, type, IsRef, loc);
+ if (IsHoistedEmitRequired (ec)) {
+ HoistedVariable.Emit (ec, leave_copy);
+ return;
+ }
+
EmitLoad (ec);
if (IsRef) {
if (leave_copy) {
ec.ig.Emit (OpCodes.Dup);
- if (IsRef || Variable.NeedsTemporary) {
+ if (IsRef) {
temp = new LocalTemporary (Type);
temp.Store (ec);
}
Report.Debug (64, "VARIABLE EMIT ASSIGN", this, Variable, type, IsRef,
source, loc);
- ILGenerator ig = ec.ig;
- prepared = prepare_for_load;
-
- Variable.EmitInstance (ec);
- if (prepare_for_load) {
- if (Variable.HasInstance)
- ig.Emit (OpCodes.Dup);
+ if (IsHoistedEmitRequired (ec)) {
+ HoistedVariable.EmitAssign (ec, source, leave_copy, prepare_for_load);
+ return;
}
if (IsRef)
// HACK: variable is already emitted when source is an initializer
if (source is NewInitialize) {
if (leave_copy) {
- Variable.EmitInstance (ec);
Variable.Emit (ec);
}
return;
}
if (leave_copy) {
- ig.Emit (OpCodes.Dup);
- if (IsRef || Variable.NeedsTemporary) {
+ ec.ig.Emit (OpCodes.Dup);
+ if (IsRef) {
temp = new LocalTemporary (Type);
temp.Store (ec);
}
}
if (IsRef)
- StoreFromPtr (ig, type);
+ StoreFromPtr (ec.ig, type);
else
Variable.EmitAssign (ec);
temp.Release (ec);
}
}
-
- public void AddressOf (EmitContext ec, AddressOp mode)
+
+ public bool IsHoisted {
+ get { return HoistedVariable != null; }
+ }
+
+ protected virtual bool IsHoistedEmitRequired (EmitContext ec)
+ {
+ //
+ // Default implementation return true when there is a hosted variable
+ //
+ return HoistedVariable != null;
+ }
+
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
{
- Variable.EmitInstance (ec);
- Variable.EmitAddressOf (ec);
+ type = storey.MutateType (type);
}
}
/// <summary>
/// Local variables
/// </summary>
- public class LocalVariableReference : VariableReference, IVariable {
- public readonly string Name;
+ public class LocalVariableReference : VariableReference {
+ readonly string name;
public Block Block;
public LocalInfo local_info;
bool is_readonly;
- Variable variable;
public LocalVariableReference (Block block, string name, Location l)
{
Block = block;
- Name = name;
+ this.name = name;
loc = l;
eclass = ExprClass.Variable;
}
this.is_readonly = is_readonly;
}
- public VariableInfo VariableInfo {
+ public override VariableInfo VariableInfo {
get { return local_info.VariableInfo; }
}
+ public override HoistedVariable HoistedVariable {
+ get { return local_info.HoistedVariableReference; }
+ }
+
+ //
+ // A local variable is always fixed
+ //
+ public override bool IsFixedVariable {
+ get { return true; }
+ }
+
public override bool IsRef {
get { return false; }
}
get { return is_readonly; }
}
+ public override string Name {
+ get { return name; }
+ }
+
public bool VerifyAssigned (EmitContext ec)
{
VariableInfo variable_info = local_info.VariableInfo;
}
}
+ public override void SetHasAddressTaken ()
+ {
+ local_info.AddressTaken = true;
+ }
+
public override Expression CreateExpressionTree (EmitContext ec)
{
ArrayList arg = new ArrayList (1);
return CreateExpressionFactoryCall ("Constant", arg);
}
- protected Expression DoResolveBase (EmitContext ec)
+ Expression DoResolveBase (EmitContext ec)
{
type = local_info.VariableType;
if (e != null)
return e.Resolve (ec);
- if (!VerifyAssigned (ec))
- return null;
+ VerifyAssigned (ec);
//
// If we are referencing a variable from the external block
// flag it for capturing
//
if (ec.MustCaptureVariable (local_info)) {
- if (local_info.AddressTaken){
- AnonymousMethod.Error_AddressOfCapturedVar (local_info.Name, loc);
- return null;
- }
+ if (local_info.AddressTaken)
+ AnonymousMethodExpression.Error_AddressOfCapturedVar (this, loc);
- if (!ec.IsInProbingMode)
- {
- ScopeInfo scope = local_info.Block.CreateScopeInfo ();
- variable = scope.AddLocal (local_info);
- type = variable.Type;
+ if (ec.IsVariableCapturingRequired) {
+ AnonymousMethodStorey storey = local_info.Block.Explicit.CreateAnonymousMethodStorey (ec);
+ storey.CaptureLocalVariable (ec, local_info);
}
}
code = 1654; msg = "Cannot assign to members of `{0}' because it is a `{1}'";
} else if (right_side == EmptyExpression.LValueMemberOutAccess) {
code = 1655; msg = "Cannot pass members of `{0}' as ref or out arguments because it is a `{1}'";
+ } else if (right_side == EmptyExpression.UnaryAddress) {
+ code = 459; msg = "Cannot take the address of {1} `{0}'";
} else {
code = 1656; msg = "Cannot assign to `{0}' because it is a `{1}'";
}
Report.Error (code, loc, msg, Name, local_info.GetReadOnlyContext ());
- return null;
- }
-
- if (VariableInfo != null)
+ } else if (VariableInfo != null) {
VariableInfo.SetAssigned (ec);
+ }
return DoResolveBase (ec);
}
- public bool VerifyFixed ()
- {
- // A local Variable is always fixed.
- return true;
- }
-
public override int GetHashCode ()
{
return Name.GetHashCode ();
return Name == lvr.Name && Block == lvr.Block;
}
- public override Variable Variable {
- get { return variable != null ? variable : local_info.Variable; }
+ protected override ILocalVariable Variable {
+ get { return local_info; }
}
public override string ToString ()
/// This represents a reference to a parameter in the intermediate
/// representation.
/// </summary>
- public class ParameterReference : VariableReference, IVariable {
+ public class ParameterReference : VariableReference {
readonly ToplevelParameterInfo pi;
readonly ToplevelBlock referenced;
- Variable variable;
-
- public bool is_ref, is_out;
- public bool IsOut {
- get { return is_out; }
+ public ParameterReference (ToplevelBlock referenced, ToplevelParameterInfo pi, Location loc)
+ {
+ this.pi = pi;
+ this.referenced = referenced;
+ this.loc = loc;
}
public override bool IsRef {
- get { return is_ref; }
+ get { return (pi.Parameter.ModFlags & Parameter.Modifier.ISBYREF) != 0; }
}
- public string Name {
- get { return Parameter.Name; }
+ bool HasOutModifier {
+ get { return pi.Parameter.ModFlags == Parameter.Modifier.OUT; }
}
- public Parameter Parameter {
- get { return pi.Parameter; }
+ public override HoistedVariable HoistedVariable {
+ get { return pi.Parameter.HoistedVariableReference; }
}
- public ParameterReference (ToplevelBlock referenced, ToplevelParameterInfo pi, Location loc)
- {
- this.pi = pi;
- this.referenced = referenced;
- this.loc = loc;
- eclass = ExprClass.Variable;
+ //
+ // A ref or out parameter is classified as a moveable variable, even
+ // if the argument given for the parameter is a fixed variable
+ //
+ public override bool IsFixedVariable {
+ get { return !IsRef; }
}
- public VariableInfo VariableInfo {
- get { return pi.VariableInfo; }
+ public override string Name {
+ get { return Parameter.Name; }
}
- public override Variable Variable {
- get { return variable != null ? variable : Parameter.Variable; }
+ public Parameter Parameter {
+ get { return pi.Parameter; }
}
- public bool VerifyFixed ()
- {
- // A parameter is fixed if it's a value parameter (i.e., no modifier like out, ref, param).
- return Parameter.ModFlags == Parameter.Modifier.NONE;
+ public override VariableInfo VariableInfo {
+ get { return pi.VariableInfo; }
+ }
+
+ protected override ILocalVariable Variable {
+ get { return Parameter; }
}
public bool IsAssigned (EmitContext ec, Location loc)
if (ec.IsInProbingMode)
return true;
- if (!ec.DoFlowAnalysis || !is_out || ec.CurrentBranching.IsAssigned (VariableInfo))
+ if (!ec.DoFlowAnalysis || !HasOutModifier || ec.CurrentBranching.IsAssigned (VariableInfo))
return true;
Report.Error (269, loc, "Use of unassigned out parameter `{0}'", Name);
return false;
}
- public bool IsFieldAssigned (EmitContext ec, string field_name, Location loc)
+ public override void SetHasAddressTaken ()
{
- if (!ec.DoFlowAnalysis || !is_out || ec.CurrentBranching.IsFieldAssigned (VariableInfo, field_name))
- return true;
-
- Report.Error (170, loc, "Use of possibly unassigned field `{0}'", field_name);
- return false;
+ Parameter.HasAddressTaken = true;
}
- public void SetAssigned (EmitContext ec)
+ void SetAssigned (EmitContext ec)
{
- if (is_out && ec.DoFlowAnalysis)
+ if (HasOutModifier && ec.DoFlowAnalysis)
ec.CurrentBranching.SetAssigned (VariableInfo);
}
- public void SetFieldAssigned (EmitContext ec, string field_name)
+ bool DoResolveBase (EmitContext ec)
{
- if (is_out && ec.DoFlowAnalysis)
- ec.CurrentBranching.SetFieldAssigned (VariableInfo, field_name);
- }
-
- protected bool DoResolveBase (EmitContext ec)
- {
- Parameter par = Parameter;
- if (!par.Resolve (ec)) {
- //TODO:
- }
-
- type = par.ParameterType;
- Parameter.Modifier mod = par.ModFlags;
- is_ref = (mod & Parameter.Modifier.ISBYREF) != 0;
- is_out = (mod & Parameter.Modifier.OUT) == Parameter.Modifier.OUT;
+ type = pi.ParameterType;
eclass = ExprClass.Variable;
- AnonymousContainer am = ec.CurrentAnonymousMethod;
+ AnonymousExpression am = ec.CurrentAnonymousMethod;
if (am == null)
return true;
ToplevelBlock declared = pi.Block;
- if (is_ref && declared != referenced) {
- Report.Error (1628, Location,
- "Cannot use ref or out parameter `{0}' inside an " +
- "anonymous method block", par.Name);
- return false;
+ if (declared != referenced) {
+ if (IsRef) {
+ Report.Error (1628, loc,
+ "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
+ Name, am.ContainerType);
+ return false;
+ }
+ } else {
+ if (!am.IsIterator)
+ return true;
}
- if (!am.IsIterator && declared == referenced)
- return true;
+ if (ec.IsVariableCapturingRequired) {
+ if (pi.Parameter.HasAddressTaken)
+ AnonymousMethodExpression.Error_AddressOfCapturedVar (this, loc);
- // Don't capture aruments when the probing is on
- if (!ec.IsInProbingMode) {
- ScopeInfo scope = declared.CreateScopeInfo ();
- variable = scope.AddParameter (par, pi.Index);
- type = variable.Type;
+ AnonymousMethodStorey storey = declared.CreateAnonymousMethodStorey (ec);
+ storey.CaptureParameter (ec, this);
}
+
return true;
}
return Name == pr.Name && referenced == pr.referenced;
}
+
+ protected override void CloneTo (CloneContext clonectx, Expression target)
+ {
+ // Nothing to clone
+ }
public override Expression CreateExpressionTree (EmitContext ec)
{
+ if (IsHoistedEmitRequired (ec))
+ return HoistedVariable.CreateExpressionTree (ec);
+
return Parameter.ExpressionTreeVariableReference ();
}
if (!DoResolveBase (ec))
return null;
- if (is_out && ec.DoFlowAnalysis &&
+ if (HasOutModifier && ec.DoFlowAnalysis &&
(!ec.OmitStructFlowAnalysis || !VariableInfo.TypeInfo.IsStruct) && !IsAssigned (ec, loc))
return null;
} else
ig.Emit (OpCodes.Ldarg, x);
}
-
- public override string ToString ()
- {
- return "ParameterReference[" + Name + "]";
- }
}
/// <summary>
}
public Type Type {
- get {
- if (ArgType == AType.Ref || ArgType == AType.Out)
- return TypeManager.GetReferenceType (Expr.Type);
- else
- return Expr.Type;
- }
+ get { return Expr.Type; }
}
public Parameter.Modifier Modifier
if (Expr.eclass == ExprClass.MethodGroup)
return Expr.ExprClassName;
- return Expr.GetSignatureForError ();
+ return TypeManager.CSharpName (Expr.Type);
}
public bool ResolveMethodGroup (EmitContext ec)
public bool Resolve (EmitContext ec, Location loc)
{
+ if (Expr == null)
+ return false;
+
using (ec.With (EmitContext.Flags.DoFlowAnalysis, true)) {
// Verify that the argument is readable
if (ArgType != AType.Out)
return CreateExpressionFactoryCall ("Quote", args);
}
- args = new ArrayList (Arguments == null ? 2 : Arguments.Count + 2);
+ ExtensionMethodGroupExpr emg = mg as ExtensionMethodGroupExpr;
+
+ int arg_count = Arguments == null ? 2 : Arguments.Count + 2;
+ if (emg != null)
+ ++arg_count;
+ args = new ArrayList (arg_count);
+
if (mg.IsInstance)
args.Add (new Argument (mg.InstanceExpression.CreateExpressionTree (ec)));
else
args.Add (new Argument (new NullLiteral (loc)));
args.Add (new Argument (mg.CreateExpressionTree (ec)));
+
+ //
+ // Use extension argument when exists
+ //
+ if (emg != null) {
+ Expression e = emg.ExtensionExpression.CreateExpressionTree (ec);
+ if (e != null)
+ args.Add (new Argument (e));
+ }
+
if (Arguments != null) {
foreach (Argument a in Arguments) {
Expression e = a.Expr.CreateExpressionTree (ec);
}
}
+ if (mg.IsBase)
+ MemberExpr.Error_BaseAccessInExpressionTree (loc);
+
return CreateExpressionFactoryCall ("Call", args);
}
return null;
}
- if (IsSpecialMethodInvocation (method)) {
- return null;
- }
+ IsSpecialMethodInvocation (method, loc);
if (mg.InstanceExpression != null)
mg.InstanceExpression.CheckMarshalByRefAccess (ec);
return mg.OverloadResolve (ec, ref Arguments, false, loc);
}
- bool IsSpecialMethodInvocation (MethodBase method)
+ public static bool IsSpecialMethodInvocation (MethodBase method, Location loc)
{
if (!TypeManager.IsSpecialMethod (method))
return false;
static Type[] GetVarargsTypes (MethodBase mb, ArrayList arguments)
{
- ParameterData pd = TypeManager.GetParameterData (mb);
-
- if (arguments == null)
- return new Type [0];
-
+ AParametersCollection pd = TypeManager.GetParameterData (mb);
+
Argument a = (Argument) arguments [pd.Count - 1];
Arglist list = (Arglist) a.Expr;
/// <summary>
/// This checks the ConditionalAttribute on the method
/// </summary>
- public static bool IsMethodExcluded (MethodBase method)
+ public static bool IsMethodExcluded (MethodBase method, Location loc)
{
if (method.IsConstructor)
return false;
return false;
}
- return AttributeTester.IsConditionalMethodExcluded (method);
+ return AttributeTester.IsConditionalMethodExcluded (method, loc);
}
/// <remarks>
}
}
- if (IsMethodExcluded (method))
+ if (IsMethodExcluded (method, loc))
return;
bool is_static = method.IsStatic;
else
ig.Emit (call_op, (ConstructorInfo) method);
}
-
+
public override void Emit (EmitContext ec)
{
mg.EmitCall (ec, Arguments);
target.expr = expr.Clone (clonectx);
}
+
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ mg.MutateHoistedGenericType (storey);
+ if (Arguments != null) {
+ foreach (Argument a in Arguments)
+ a.Expr.MutateHoistedGenericType (storey);
+ }
+ }
}
+ //
+ // It's either a cast or delegate invocation
+ //
public class InvocationOrCast : ExpressionStatement
{
Expression expr;
this.loc = expr.Location;
}
+ public override Expression CreateExpressionTree (EmitContext ec)
+ {
+ throw new NotSupportedException ("ET");
+ }
+
public override Expression DoResolve (EmitContext ec)
+ {
+ Expression e = ResolveCore (ec);
+ if (e == null)
+ return null;
+
+ return e.Resolve (ec);
+ }
+
+ Expression ResolveCore (EmitContext ec)
{
//
// First try to resolve it as a cast.
//
- TypeExpr te = expr.ResolveAsTypeTerminal (ec, true);
- if ((te != null) && (te.eclass == ExprClass.Type)) {
- Cast cast = new Cast (te, argument, loc);
- return cast.Resolve (ec);
+ TypeExpr te = expr.ResolveAsBaseTerminal (ec, true);
+ if (te != null) {
+ return new Cast (te, argument, loc);
}
//
//
// Ok, so it's a Cast.
//
- if (expr.eclass == ExprClass.Type) {
- Cast cast = new Cast (new TypeExpression (expr.Type, loc), argument, loc);
- return cast.Resolve (ec);
+ if (expr.eclass == ExprClass.Type || expr.eclass == ExprClass.TypeParameter) {
+ return new Cast (expr, argument, loc);
}
+ if (expr.eclass == ExprClass.Namespace) {
+ expr.Error_UnexpectedKind (null, "type", loc);
+ return null;
+ }
+
//
// It's a delegate invocation.
//
return null;
}
- ArrayList args = new ArrayList ();
+ ArrayList args = new ArrayList (1);
args.Add (new Argument (argument, Argument.AType.Expression));
- DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
- return invocation.Resolve (ec);
+ return new DelegateInvocation (expr, args, loc);
}
public override ExpressionStatement ResolveStatement (EmitContext ec)
{
- //
- // First try to resolve it as a cast.
- //
- TypeExpr te = expr.ResolveAsTypeTerminal (ec, true);
- if ((te != null) && (te.eclass == ExprClass.Type)) {
- Error_InvalidExpressionStatement ();
+ Expression e = ResolveCore (ec);
+ if (e == null)
return null;
- }
- //
- // This can either be a type or a delegate invocation.
- // Let's just resolve it and see what we'll get.
- //
- expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
- if ((expr == null) || (expr.eclass == ExprClass.Type)) {
+ ExpressionStatement s = e as ExpressionStatement;
+ if (s == null) {
Error_InvalidExpressionStatement ();
return null;
}
- //
- // It's a delegate invocation.
- //
- if (!TypeManager.IsDelegateType (expr.Type)) {
- Error (149, "Method name expected");
- return null;
- }
-
- ArrayList args = new ArrayList ();
- args.Add (new Argument (argument, Argument.AType.Expression));
- DelegateInvocation invocation = new DelegateInvocation (expr, args, loc);
- return invocation.ResolveStatement (ec);
+ return s.ResolveStatement (ec);
}
public override void Emit (EmitContext ec)
// This class is used to "disable" the code generation for the
// temporary variable when initializing value types.
//
- class EmptyAddressOf : EmptyExpression, IMemoryLocation {
+ sealed class EmptyAddressOf : EmptyExpression, IMemoryLocation {
public void AddressOf (EmitContext ec, AddressOp Mode)
{
// nothing
type = texpr.Type;
- if (type == TypeManager.void_type) {
- Error_VoidInvalidInTheContext (loc);
- return null;
- }
-
if (type.IsPointer) {
Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
TypeManager.CSharpName (type));
}
if (TypeManager.IsDelegateType (type)) {
- RequestedType = (new NewDelegate (type, Arguments, loc)).Resolve (ec);
- if (RequestedType != null)
- if (!(RequestedType is DelegateCreation))
- throw new Exception ("NewDelegate.Resolve returned a non NewDelegate: " + RequestedType.GetType ());
- return RequestedType;
+ return (new NewDelegate (type, Arguments, loc)).Resolve (ec);
}
#if GMCS_SOURCE
}
return false;
} else {
- ig.Emit (OpCodes.Newobj, (ConstructorInfo) method);
+ ConstructorInfo ci = (ConstructorInfo) method;
+#if MS_COMPATIBLE
+ if (TypeManager.IsGenericType (type))
+ ci = TypeBuilder.GetConstructor (type, ci);
+#endif
+ ig.Emit (OpCodes.Newobj, ci);
return true;
}
}
}
}
}
+
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ if (method != null) {
+ method.MutateHoistedGenericType (storey);
+ if (Arguments != null) {
+ foreach (Argument a in Arguments)
+ a.Expr.MutateHoistedGenericType (storey);
+ }
+ }
+
+ type = storey.MutateType (type);
+ }
}
/// <summary>
this.rank = rank;
loc = l;
- arguments = new ArrayList ();
+ arguments = new ArrayList (exprs.Count);
foreach (Expression e in exprs) {
arguments.Add (new Argument (e, Argument.AType.Expression));
Constant c = a.Expr as Constant;
if (c != null) {
- c = c.ImplicitConversionRequired (TypeManager.int32_type, a.Expr.Location);
+ c = c.ImplicitConversionRequired (ec, TypeManager.int32_type, a.Expr.Location);
}
if (c == null) {
{
ArrayList args;
- if (dimensions != 1) {
- if (initializers != null) {
- Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
- return null;
- }
-
+ if (array_data == null) {
args = new ArrayList (arguments.Count + 1);
args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
- foreach (Argument a in arguments)
+ foreach (Argument a in arguments) {
+ if (arguments.Count == 1) {
+ Constant c = a.Expr as Constant;
+ if (c.IsDefaultValue)
+ return CreateExpressionFactoryCall ("NewArrayInit", args);
+ }
args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
+ }
return CreateExpressionFactoryCall ("NewArrayBounds", args);
}
+ if (dimensions > 1) {
+ Report.Error (838, loc, "An expression tree cannot contain a multidimensional array initializer");
+ return null;
+ }
+
args = new ArrayList (array_data == null ? 1 : array_data.Count + 1);
args.Add (new Argument (new TypeOf (new TypeExpression (array_element_type, loc), loc)));
if (array_data != null) {
- foreach (Expression e in array_data)
+ for (int i = 0; i < array_data.Count; ++i) {
+ Expression e = (Expression) array_data [i];
+ if (e == null)
+ e = Convert.ImplicitConversion (ec, (Expression) initializers [i], array_element_type, loc);
+
args.Add (new Argument (e.CreateExpressionTree (ec)));
+ }
}
return CreateExpressionFactoryCall ("NewArrayInit", args);
}
+ Expression first_emit;
+ LocalTemporary first_emit_temp;
+
protected virtual Expression ResolveArrayElement (EmitContext ec, Expression element)
{
element = element.Resolve (ec);
if (element == null)
return null;
+ if (element is CompoundAssign.Helper) {
+ if (first_emit != null)
+ throw new InternalErrorException ("Can only handle one mutator at a time");
+ first_emit = element;
+ element = first_emit_temp = new LocalTemporary (element.Type);
+ }
+
return Convert.ImplicitConversionRequired (
ec, element, array_element_type, loc);
}
Report.Error (622, loc, "Can only use array initializer expressions to assign to array types. Try using a new expression instead");
return false;
}
+
+ if (requested_base_type is VarExpr) {
+ Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
+ return false;
+ }
StringBuilder array_qualifier = new StringBuilder (rank);
if (!ResolveArrayType (ec))
return null;
-
- if ((array_element_type.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
- Report.Error (719, loc, "`{0}': array elements cannot be of static type",
- TypeManager.CSharpName (array_element_type));
- }
//
// First step is to validate the initializers and fill
return data;
}
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ array_element_type = storey.MutateType (array_element_type);
+ type = storey.MutateType (type);
+ if (arguments != null) {
+ foreach (Argument a in arguments)
+ a.Expr.MutateHoistedGenericType (storey);
+ }
+
+ if (array_data != null) {
+ foreach (Expression e in array_data)
+ e.MutateHoistedGenericType (storey);
+ }
+ }
+
//
// Emits the initializers for the array
//
{
ILGenerator ig = ec.ig;
+ if (first_emit != null) {
+ first_emit.Emit (ec);
+ first_emit_temp.Store (ec);
+ }
+
foreach (Argument a in arguments)
a.Emit (ec);
EmitDynamicInitializers (ec, false);
} else {
EmitDynamicInitializers (ec, true);
- }
+ }
+
+ if (first_emit_temp != null)
+ first_emit_temp.Release (ec);
}
- public override bool GetAttributableValue (Type value_type, out object value)
+ public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
{
if (arguments.Count != 1) {
// Report.Error (-211, Location, "attribute can not encode multi-dimensional arrays");
- return base.GetAttributableValue (null, out value);
+ return base.GetAttributableValue (ec, null, out value);
}
if (array_data == null) {
return true;
}
// Report.Error (-212, Location, "array should be initialized when passing it to an attribute");
- return base.GetAttributableValue (null, out value);
+ return base.GetAttributableValue (ec, null, out value);
}
Array ret = Array.CreateInstance (array_element_type, array_data.Count);
if (e == null)
continue;
- if (!e.GetAttributableValue (array_element_type, out element_value)) {
+ if (!e.GetAttributableValue (ec, array_element_type, out element_value)) {
value = null;
return false;
}
if (array_element_type == null || array_element_type == TypeManager.null_type ||
array_element_type == TypeManager.void_type || array_element_type == TypeManager.anonymous_method_type ||
arguments.Count != dimensions) {
- Report.Error (826, loc, "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
+ Error_NoBestType ();
return null;
}
return this;
}
+ void Error_NoBestType ()
+ {
+ Report.Error (826, loc,
+ "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
+ }
+
//
// Converts static initializer only
//
return element;
}
- element.Error_ValueCannotBeConverted (ec, element.Location, array_element_type, false);
- return element;
+ Error_NoBestType ();
+ return null;
}
}
{
}
+ public CompilerGeneratedThis (Type type, Location loc)
+ : base (loc)
+ {
+ this.type = type;
+ }
+
public override Expression DoResolve (EmitContext ec)
{
eclass = ExprClass.Variable;
- type = ec.ContainerType;
- variable = new SimpleThis (type);
+ if (type == null)
+ type = ec.ContainerType;
return this;
}
+
+ public override HoistedVariable HoistedVariable {
+ get { return null; }
+ }
}
/// <summary>
/// Represents the `this' construct
/// </summary>
- public class This : VariableReference, IVariable
+ public class This : VariableReference
{
+ sealed class ThisVariable : ILocalVariable
+ {
+ public static readonly ILocalVariable Instance = new ThisVariable ();
+
+ public void Emit (EmitContext ec)
+ {
+ ec.ig.Emit (OpCodes.Ldarg_0);
+ }
+
+ public void EmitAssign (EmitContext ec)
+ {
+ throw new InvalidOperationException ();
+ }
+
+ public void EmitAddressOf (EmitContext ec)
+ {
+ ec.ig.Emit (OpCodes.Ldarg_0);
+ }
+ }
+
Block block;
VariableInfo variable_info;
- protected Variable variable;
bool is_struct;
public This (Block block, Location loc)
this.loc = loc;
}
- public VariableInfo VariableInfo {
+ public override VariableInfo VariableInfo {
get { return variable_info; }
}
- public bool VerifyFixed ()
+ public override bool IsFixedVariable {
+ get { return !TypeManager.IsValueType (type); }
+ }
+
+ protected override bool IsHoistedEmitRequired (EmitContext ec)
{
- return !TypeManager.IsValueType (Type);
+ //
+ // Handle 'this' differently, it cannot be assigned hence
+ // when we are not inside anonymous method we can emit direct access
+ //
+ return ec.CurrentAnonymousMethod != null && base.IsHoistedEmitRequired (ec);
+ }
+
+ public override HoistedVariable HoistedVariable {
+ get { return TopToplevelBlock.HoistedThisVariable; }
}
public override bool IsRef {
get { return is_struct; }
}
- public override Variable Variable {
- get { return variable; }
+ protected override ILocalVariable Variable {
+ get { return ThisVariable.Instance; }
+ }
+
+ // TODO: Move to ToplevelBlock
+ ToplevelBlock TopToplevelBlock {
+ get {
+ ToplevelBlock tl = block.Toplevel;
+ while (tl.Parent != null) tl = tl.Parent.Toplevel;
+ return tl;
+ }
+ }
+
+ public static bool IsThisAvailable (EmitContext ec)
+ {
+ if (ec.IsStatic || ec.IsInFieldInitializer)
+ return false;
+
+ if (ec.CurrentAnonymousMethod == null)
+ return true;
+
+ if (ec.TypeContainer is Struct && ec.CurrentIterator == null)
+ return false;
+
+ return true;
}
public bool ResolveBase (EmitContext ec)
{
+ if (eclass != ExprClass.Invalid)
+ return true;
+
eclass = ExprClass.Variable;
if (ec.TypeContainer.CurrentType != null)
else
type = ec.ContainerType;
- is_struct = ec.TypeContainer is Struct;
-
- if (ec.IsStatic) {
- Error (26, "Keyword `this' is not valid in a static property, " +
- "static method, or static field initializer");
- return false;
+ if (!IsThisAvailable (ec)) {
+ if (ec.IsStatic) {
+ Error (26, "Keyword `this' is not valid in a static property, static method, or static field initializer");
+ } else {
+ Report.Error (1673, loc,
+ "Anonymous methods inside structs cannot access instance members of `this'. " +
+ "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
+ }
}
+ is_struct = ec.TypeContainer is Struct;
+
if (block != null) {
if (block.Toplevel.ThisVariable != null)
variable_info = block.Toplevel.ThisVariable.VariableInfo;
- AnonymousContainer am = ec.CurrentAnonymousMethod;
- if (is_struct && (am != null) && !am.IsIterator) {
- Report.Error (1673, loc, "Anonymous methods inside structs " +
- "cannot access instance members of `this'. " +
- "Consider copying `this' to a local variable " +
- "outside the anonymous method and using the " +
- "local instead.");
- }
-
- RootScopeInfo host = block.Toplevel.RootScope;
- if ((host != null) && !ec.IsConstructor &&
- (!is_struct || host.IsIterator)) {
- variable = host.CaptureThis ();
- type = variable.Type;
- is_struct = false;
+ AnonymousExpression am = ec.CurrentAnonymousMethod;
+ if (am != null) {
+ //
+ // this is hoisted to very top level block
+ //
+ if (ec.IsVariableCapturingRequired) {
+ // TODO: it could be optimized
+ AnonymousMethodStorey scope = TopToplevelBlock.Explicit.CreateAnonymousMethodStorey (ec);
+ if (HoistedVariable == null) {
+ TopToplevelBlock.HoistedThisVariable = scope.CaptureThis (ec, this);
+ }
+ }
}
}
-
- if (variable == null)
- variable = new SimpleThis (type);
return true;
}
if (variable_info != null)
variable_info.SetAssigned (ec);
-
+
if (ec.TypeContainer is Class){
- Error (1604, "Cannot assign to 'this' because it is read-only");
- return null;
+ if (right_side == EmptyExpression.UnaryAddress)
+ Report.Error (459, loc, "Cannot take the address of `this' because it is read-only");
+ else if (right_side == EmptyExpression.OutAccess)
+ Report.Error (1605, loc, "Cannot pass `this' as a ref or out argument because it is read-only");
+ else
+ Report.Error (1604, loc, "Cannot assign to `this' because it is read-only");
}
return this;
}
+
public override int GetHashCode()
{
return block.GetHashCode ();
}
+ public override string Name {
+ get { return "this"; }
+ }
+
public override bool Equals (object obj)
{
This t = obj as This;
return block == t.block;
}
- protected class SimpleThis : Variable
+ protected override void CloneTo (CloneContext clonectx, Expression t)
{
- Type type;
-
- public SimpleThis (Type type)
- {
- this.type = type;
- }
-
- public override Type Type {
- get { return type; }
- }
-
- public override bool HasInstance {
- get { return false; }
- }
-
- public override bool NeedsTemporary {
- get { return false; }
- }
-
- public override void EmitInstance (EmitContext ec)
- {
- // Do nothing.
- }
-
- public override void Emit (EmitContext ec)
- {
- ec.ig.Emit (OpCodes.Ldarg_0);
- }
-
- public override void EmitAssign (EmitContext ec)
- {
- throw new InvalidOperationException ();
- }
+ This target = (This) t;
- public override void EmitAddressOf (EmitContext ec)
- {
- ec.ig.Emit (OpCodes.Ldarg_0);
- }
+ target.block = clonectx.LookupBlock (block);
}
- protected override void CloneTo (CloneContext clonectx, Expression t)
+ public void RemoveHoisting ()
{
- This target = (This) t;
+ TopToplevelBlock.HoistedThisVariable = null;
+ }
- target.block = clonectx.LookupBlock (block);
+ public override void SetHasAddressTaken ()
+ {
+ // Nothing
}
}
this.loc = loc;
}
+ public override Expression CreateExpressionTree (EmitContext ec)
+ {
+ throw new NotSupportedException ("ET");
+ }
+
public override Expression DoResolve (EmitContext ec)
{
eclass = ExprClass.Variable;
type = TypeManager.runtime_argument_handle_type;
- if (ec.IsInFieldInitializer || !ec.CurrentBlock.Toplevel.HasVarargs)
+ if (ec.IsInFieldInitializer || !ec.CurrentBlock.Toplevel.Parameters.HasArglist)
{
Error (190, "The __arglist construct is valid only within " +
"a variable argument method");
arg.Emit (ec);
}
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ foreach (Argument arg in Arguments)
+ arg.Expr.MutateHoistedGenericType (storey);
+ }
+
protected override void CloneTo (CloneContext clonectx, Expression t)
{
Arglist target = (Arglist) t;
}
}
- //
- // This produces the value that renders an instance, used by the iterators code
- //
- public class ProxyInstance : Expression, IMemoryLocation {
- public override Expression DoResolve (EmitContext ec)
- {
- eclass = ExprClass.Variable;
- type = ec.ContainerType;
- return this;
- }
-
- public override void Emit (EmitContext ec)
- {
- ec.ig.Emit (OpCodes.Ldarg_0);
-
- }
-
- public void AddressOf (EmitContext ec, AddressOp mode)
- {
- ec.ig.Emit (OpCodes.Ldarg_0);
- }
- }
-
/// <summary>
/// Implements the typeof operator
/// </summary>
ec.ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
}
- public override bool GetAttributableValue (Type value_type, out object value)
+ public override bool GetAttributableValue (EmitContext ec, Type value_type, out object value)
{
if (TypeManager.ContainsGenericParameters (typearg) &&
!TypeManager.IsGenericTypeDefinition (typearg)) {
return true;
}
- public Type TypeArgument
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
{
- get
- {
+ typearg = storey.MutateType (typearg);
+ }
+
+ public Type TypeArgument {
+ get {
return typearg;
}
}
protected override void CloneTo (CloneContext clonectx, Expression t)
{
TypeOf target = (TypeOf) t;
-
- target.QueriedType = QueriedType.Clone (clonectx);
+ if (QueriedType != null)
+ target.QueriedType = QueriedType.Clone (clonectx);
}
}
this.loc = loc;
}
+ public override Expression CreateExpressionTree (EmitContext ec)
+ {
+ throw new NotSupportedException ("ET");
+ }
+
public override Expression DoResolve (EmitContext ec)
{
if (TypeManager.fieldinfo_get_field_from_handle == null) {
loc = l;
}
+ public override Expression CreateExpressionTree (EmitContext ec)
+ {
+ Error_PointerInsideExpressionTree ();
+ return null;
+ }
+
public override Expression DoResolve (EmitContext ec)
{
TypeExpr texpr = QueriedType.ResolveAsTypeTerminal (ec, false);
if (TypeManager.IsEnumType (type_queried))
type_queried = TypeManager.GetEnumUnderlyingType (type_queried);
- if (type_queried == TypeManager.void_type) {
- Expression.Error_VoidInvalidInTheContext (loc);
- return null;
- }
-
int size_of = GetTypeSize (type_queried);
if (size_of > 0) {
return new IntConstant (size_of, loc);
public class QualifiedAliasMember : MemberAccess
{
readonly string alias;
+ public static readonly string GlobalAlias = "global";
public QualifiedAliasMember (string alias, string identifier, TypeArguments targs, Location l)
: base (null, identifier, targs, l)
public override FullNamedExpression ResolveAsTypeStep (IResolveContext ec, bool silent)
{
- if (alias == "global") {
+ if (alias == GlobalAlias) {
expr = RootNamespace.Global;
return base.ResolveAsTypeStep (ec, silent);
}
if (Expr == null)
return null;
- if (Expr is Constant)
+ if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression)
return Expr;
eclass = Expr.eclass;
Expr.EmitBranchable (ec, target, on_true);
}
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ Expr.MutateHoistedGenericType (storey);
+ }
+
protected override void CloneTo (CloneContext clonectx, Expression t)
{
CheckedExpr target = (CheckedExpr) t;
if (Expr == null)
return null;
- if (Expr is Constant)
+ if (Expr is Constant || Expr is MethodGroupExpr || Expr is AnonymousMethodExpression)
return Expr;
eclass = Expr.eclass;
Expr.EmitBranchable (ec, target, on_true);
}
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ Expr.MutateHoistedGenericType (storey);
+ }
+
protected override void CloneTo (CloneContext clonectx, Expression t)
{
UnCheckedExpr target = (UnCheckedExpr) t;
public ElementAccess (Expression e, ArrayList e_list)
{
Expr = e;
-
loc = e.Location;
if (e_list == null)
return;
- Arguments = new ArrayList ();
+ Arguments = new ArrayList (e_list.Count);
foreach (Expression tmp in e_list)
Arguments.Add (new Argument (tmp, Argument.AType.Expression));
-
}
bool CommonResolve (EmitContext ec)
Expression MakePointerAccess (EmitContext ec, Type t)
{
- if (t == TypeManager.void_ptr_type){
- Error (242, "The array index operation is not valid on void pointers");
- return null;
- }
if (Arguments.Count != 1){
Error (196, "A pointer must be indexed by only one value");
return null;
}
- Expression p;
- p = new PointerArithmetic (true, Expr, ((Argument)Arguments [0]).Expr, t, loc).Resolve (ec);
+ Expression p = new PointerArithmetic (Binary.Operator.Addition, Expr, ((Argument) Arguments [0]).Expr, t, loc).Resolve (ec);
if (p == null)
return null;
return new Indirection (p, loc).Resolve (ec);
ElementAccess ea;
LocalTemporary temp;
- LocalTemporary prepared_value;
bool prepared;
public ArrayAccess (ElementAccess ea_data, Location l)
{
ea = ea_data;
- eclass = ExprClass.Variable;
loc = l;
}
}
#endif
+ if (eclass != ExprClass.Invalid)
+ return this;
+
Type t = ea.Expr.Type;
int rank = ea.Arguments.Count;
if (t.GetArrayRank () != rank) {
return null;
}
- if (rank != 1 && TypeManager.int_getlength_int == null) {
- TypeManager.int_getlength_int = TypeManager.GetPredefinedMethod (
- TypeManager.array_type, "GetLength", loc, TypeManager.int32_type);
- }
-
type = TypeManager.GetElementType (t);
if (type.IsPointer && !ec.InUnsafe) {
UnsafeError (ea.Location);
//
// Load the array arguments into the stack.
//
- // If we have been requested to cache the values (cached_locations array
- // initialized), then load the arguments the first time and store them
- // in locals. otherwise load from local variables.
- //
- // prepare_for_load is used in compound assignments to cache original index
- // values ( label[idx++] += s )
- //
- LocalTemporary [] LoadArrayAndArguments (EmitContext ec, bool prepare_for_load)
+ void LoadArrayAndArguments (EmitContext ec)
{
ea.Expr.Emit (ec);
- LocalTemporary[] indexes = null;
- if (prepare_for_load) {
- ec.ig.Emit (OpCodes.Dup);
- indexes = new LocalTemporary [ea.Arguments.Count];
- }
-
for (int i = 0; i < ea.Arguments.Count; ++i) {
((Argument)ea.Arguments [i]).Emit (ec);
- if (!prepare_for_load)
- continue;
-
- // Keep original array index value on the stack
- ec.ig.Emit (OpCodes.Dup);
-
- indexes [i] = new LocalTemporary (TypeManager.intptr_type);
- indexes [i].Store (ec);
}
-
- return indexes;
}
public void Emit (EmitContext ec, bool leave_copy)
int rank = ea.Expr.Type.GetArrayRank ();
ILGenerator ig = ec.ig;
- if (prepared_value != null) {
- prepared_value.Emit (ec);
- } else if (prepared) {
+ if (prepared) {
LoadFromPtr (ig, this.type);
} else {
- LoadArrayAndArguments (ec, false);
+ LoadArrayAndArguments (ec);
EmitLoadOpcode (ig, type, rank);
}
int rank = ea.Expr.Type.GetArrayRank ();
ILGenerator ig = ec.ig;
Type t = source.Type;
- prepared = prepare_for_load && !(source is StringConcat);
+ prepared = prepare_for_load;
if (prepared) {
AddressOf (ec, AddressOp.LoadStore);
ec.ig.Emit (OpCodes.Dup);
} else {
- LocalTemporary[] original_indexes_values = LoadArrayAndArguments (ec,
- prepare_for_load && (source is StringConcat));
-
- if (original_indexes_values != null) {
- prepared_value = new LocalTemporary (type);
- EmitLoadOpcode (ig, type, rank);
- prepared_value.Store (ec);
- foreach (LocalTemporary lt in original_indexes_values) {
- lt.Emit (ec);
- lt.Release (ec);
- }
- }
+ LoadArrayAndArguments (ec);
}
if (rank == 1) {
int rank = ea.Expr.Type.GetArrayRank ();
ILGenerator ig = ec.ig;
- LoadArrayAndArguments (ec, false);
+ LoadArrayAndArguments (ec);
if (rank == 1){
ig.Emit (OpCodes.Ldelema, type);
}
}
- public void EmitGetLength (EmitContext ec, int dim)
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
{
- int rank = ea.Expr.Type.GetArrayRank ();
- ILGenerator ig = ec.ig;
-
- ea.Expr.Emit (ec);
- if (rank == 1) {
- ig.Emit (OpCodes.Ldlen);
- ig.Emit (OpCodes.Conv_I4);
- } else {
- IntLiteral.EmitInt (ig, dim);
- ig.Emit (OpCodes.Callvirt, TypeManager.int_getlength_int);
- }
+ type = storey.MutateType (type);
}
}
}
}
- protected override int GetApplicableParametersCount (MethodBase method, ParameterData parameters)
+ protected override int GetApplicableParametersCount (MethodBase method, AParametersCollection parameters)
{
//
// Here is the trick, decrease number of arguments by 1 when only
throw new NotImplementedException (at.ToString ());
}
+ public override Expression CreateExpressionTree (EmitContext ec)
+ {
+ ArrayList args = new ArrayList (arguments.Count + 2);
+ args.Add (new Argument (instance_expr.CreateExpressionTree (ec)));
+ args.Add (new Argument (new TypeOfMethodInfo (get, loc)));
+ foreach (Argument a in arguments)
+ args.Add (new Argument (a.Expr.CreateExpressionTree (ec)));
+
+ return CreateExpressionFactoryCall ("Call", args);
+ }
+
protected virtual bool CommonResolve (EmitContext ec)
{
indexer_type = instance_expr.Type;
return TypeManager.CSharpSignature (get != null ? get : set, false);
}
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ if (get != null)
+ get = storey.MutateGenericMethod (get);
+ if (set != null)
+ set = storey.MutateGenericMethod (set);
+
+ instance_expr.MutateHoistedGenericType (storey);
+ foreach (Argument a in arguments)
+ a.Expr.MutateHoistedGenericType (storey);
+
+ type = storey.MutateType (type);
+ }
+
protected override void CloneTo (CloneContext clonectx, Expression t)
{
IndexerAccess target = (IndexerAccess) t;
this.args = args;
}
+ public override Expression CreateExpressionTree (EmitContext ec)
+ {
+ throw new NotSupportedException ("ET");
+ }
+
public override Expression DoResolve (EmitContext ec)
{
Expression c = CommonResolve (ec);
Type current_type = ec.ContainerType;
Type base_type = current_type.BaseType;
- if (ec.IsStatic){
- Error (1511, "Keyword `base' is not available in a static method");
- return null;
- }
-
- if (ec.IsInFieldInitializer){
- Error (1512, "Keyword `base' is not available in the current context");
+ if (!This.IsThisAvailable (ec)) {
+ if (ec.IsStatic) {
+ Error (1511, "Keyword `base' is not available in a static method");
+ } else {
+ Error (1512, "Keyword `base' is not available in the current context");
+ }
return null;
}
return true;
}
+
+ public override Expression CreateExpressionTree (EmitContext ec)
+ {
+ MemberExpr.Error_BaseAccessInExpressionTree (loc);
+ return base.CreateExpressionTree (ec);
+ }
}
/// <summary>
/// is needed (the `New' class).
/// </summary>
public class EmptyExpression : Expression {
- public static readonly EmptyExpression Null = new EmptyExpression ();
+ public static readonly Expression Null = new EmptyExpression ();
public static readonly EmptyExpression OutAccess = new EmptyExpression ();
public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression ();
public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression ();
+ public static readonly EmptyExpression UnaryAddress = new EmptyExpression ();
static EmptyExpression temp = new EmptyExpression ();
public static EmptyExpression Grab ()
eclass = ExprClass.Value;
loc = Location.Null;
}
+
+ public override Expression CreateExpressionTree (EmitContext ec)
+ {
+ throw new NotSupportedException ("ET");
+ }
public override Expression DoResolve (EmitContext ec)
{
loc = Location.Null;
}
+ public override Expression CreateExpressionTree (EmitContext ec)
+ {
+ return null;
+ }
+
public override void EmitStatement (EmitContext ec)
{
// Do nothing
public override Expression CreateExpressionTree (EmitContext ec)
{
- ArrayList args = new ArrayList (2);
+ ArrayList args = new ArrayList (3);
args.Add (new Argument (source.CreateExpressionTree (ec)));
args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
args.Add (new Argument (new TypeOfMethodInfo (method, loc)));
source.Emit (ec);
ec.ig.Emit (OpCodes.Call, method);
}
+
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ source.MutateHoistedGenericType (storey);
+ method = storey.MutateGenericMethod (method);
+ }
}
// <summary>
loc = l;
}
- public Expression RemoveNullable ()
- {
- if (dim.EndsWith ("?")) {
- dim = dim.Substring (0, dim.Length - 1);
- if (dim.Length == 0)
- return left;
- }
-
- return this;
- }
-
protected override TypeExpr DoResolveAsTypeStep (IResolveContext ec)
{
TypeExpr lexpr = left.ResolveAsTypeTerminal (ec, false);
return null;
Type ltype = lexpr.Type;
- if ((ltype == TypeManager.void_type) && (dim != "*")) {
- Error_VoidInvalidInTheContext (loc);
- return null;
- }
-
#if GMCS_SOURCE
if ((dim.Length > 0) && (dim [0] == '?')) {
TypeExpr nullable = new Nullable.NullableType (left, loc);
if (dim == "*" && !TypeManager.VerifyUnManaged (ltype, loc))
return null;
- if (dim != "" && dim [0] == '[' &&
- (ltype == TypeManager.arg_iterator_type || ltype == TypeManager.typed_reference_type)) {
- Report.Error (611, loc, "Array elements cannot be of type `{0}'", TypeManager.CSharpName (ltype));
- return null;
+ if (dim.Length != 0 && dim [0] == '[') {
+ if (TypeManager.IsSpecialType (ltype)) {
+ Report.Error (611, loc, "Array elements cannot be of type `{0}'", TypeManager.CSharpName (ltype));
+ return null;
+ }
+
+ if ((ltype.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
+ Report.SymbolRelatedToPreviousError (ltype);
+ Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
+ TypeManager.CSharpName (ltype));
+ }
}
if (dim != "")
if (type.IsPointer && !ec.IsInUnsafeScope){
UnsafeError (loc);
- return null;
}
eclass = ExprClass.Type;
eclass = ExprClass.Value;
}
+ public override Expression CreateExpressionTree (EmitContext ec)
+ {
+ Error_PointerInsideExpressionTree ();
+ return null;
+ }
+
public override void Emit(EmitContext ec)
{
array.Emit (ec);
//
// Encapsulates a conversion rules required for array indexes
//
- public class ArrayIndexCast : Expression
+ public class ArrayIndexCast : TypeCast
{
- Expression expr;
-
public ArrayIndexCast (Expression expr)
+ : base (expr, expr.Type)
{
- this.expr = expr;
- this.loc = expr.Location;
}
public override Expression CreateExpressionTree (EmitContext ec)
{
ArrayList args = new ArrayList (2);
- args.Add (new Argument (expr.CreateExpressionTree (ec)));
+ args.Add (new Argument (child.CreateExpressionTree (ec)));
args.Add (new Argument (new TypeOf (new TypeExpression (TypeManager.int32_type, loc), loc)));
return CreateExpressionFactoryCall ("ConvertChecked", args);
}
- public override Expression DoResolve (EmitContext ec)
- {
- type = expr.Type;
- eclass = expr.eclass;
- return this;
- }
-
public override void Emit (EmitContext ec)
{
- expr.Emit (ec);
+ child.Emit (ec);
if (type == TypeManager.int32_type)
return;
}
}
- //
- // Used by the fixed statement
- //
- public class StringPtr : Expression {
- LocalBuilder b;
-
- public StringPtr (LocalBuilder b, Location l)
- {
- this.b = b;
- eclass = ExprClass.Value;
- type = TypeManager.char_ptr_type;
- loc = l;
- }
-
- public override Expression DoResolve (EmitContext ec)
- {
- // This should never be invoked, we are born in fully
- // initialized state.
-
- return this;
- }
-
- public override void Emit (EmitContext ec)
- {
- if (TypeManager.int_get_offset_to_string_data == null) {
- // TODO: Move to resolve !!
- TypeManager.int_get_offset_to_string_data = TypeManager.GetPredefinedMethod (
- TypeManager.runtime_helpers_type, "get_OffsetToStringData", loc, Type.EmptyTypes);
- }
-
- ILGenerator ig = ec.ig;
-
- ig.Emit (OpCodes.Ldloc, b);
- ig.Emit (OpCodes.Conv_I);
- ig.Emit (OpCodes.Call, TypeManager.int_get_offset_to_string_data);
- ig.Emit (OpCodes.Add);
- }
- }
-
//
// Implements the `stackalloc' keyword
//
loc = l;
}
+ public override Expression CreateExpressionTree (EmitContext ec)
+ {
+ throw new NotSupportedException ("ET");
+ }
+
public override Expression DoResolve (EmitContext ec)
{
count = count.Resolve (ec);
if (count == null)
return null;
- if (count.Type != TypeManager.int32_type){
+ if (count.Type != TypeManager.uint32_type){
count = Convert.ImplicitConversionRequired (ec, count, TypeManager.int32_type, loc);
if (count == null)
return null;
{
int size = GetTypeSize (otype);
ILGenerator ig = ec.ig;
-
+
+ count.Emit (ec);
+
if (size == 0)
ig.Emit (OpCodes.Sizeof, otype);
else
IntConstant.EmitInt (ig, size);
- count.Emit (ec);
- ig.Emit (OpCodes.Mul);
+
+ ig.Emit (OpCodes.Mul_Ovf_Un);
ig.Emit (OpCodes.Localloc);
}
{
this.Name = name;
}
+
+ protected override void CloneTo (CloneContext clonectx, Expression t)
+ {
+ ElementInitializer target = (ElementInitializer) t;
+ target.source = source.Clone (clonectx);
+ }
public override Expression CreateExpressionTree (EmitContext ec)
{
return CreateExpressionFactoryCall ("ElementInit", args);
}
+ protected override void CloneTo (CloneContext clonectx, Expression t)
+ {
+ CollectionElementInitializer target = (CollectionElementInitializer) t;
+
+ target.Arguments = new ArrayList (Arguments.Count);
+ foreach (Expression e in Arguments)
+ target.Arguments.Add (e.Clone (clonectx));
+ }
+
public override Expression DoResolve (EmitContext ec)
{
if (eclass != ExprClass.Invalid)
// for known types like List<T>, Dictionary<T, U>
for (int i = 0; i < Arguments.Count; ++i) {
- Expression expr = ((Expression) Arguments [i]).Resolve (ec);
+ Expression expr = Arguments [i] as Expression;
+ if (expr == null)
+ return null;
+
+ expr = expr.Resolve (ec);
if (expr == null)
return null;
foreach (ExpressionStatement e in initializers)
e.EmitStatement (ec);
}
+
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ foreach (Expression e in initializers)
+ e.MutateHoistedGenericType (storey);
+ }
}
//
public override Expression CreateExpressionTree (EmitContext ec)
{
// Should not be reached
- throw new NotSupportedException ();
+ throw new NotSupportedException ("ET");
}
public override Expression DoResolve (EmitContext ec)
ec.CurrentInitializerVariable = new InitializerTargetExpression (this);
initializers.Resolve (ec);
ec.CurrentInitializerVariable = previous;
- return this;
+ return e;
}
public override void Emit (EmitContext ec)
base.Emit (ec);
//
- // If target is a value, let's use it
+ // If target is non-hoisted variable, let's use it
//
VariableReference variable = value_target as VariableReference;
- if (variable != null) {
+ if (variable != null && variable.HoistedVariable == null) {
if (variable.IsRef)
StoreFromPtr (ec.ig, type);
else
- variable.Variable.EmitAssign (ec);
+ variable.EmitAssign (ec, EmptyExpression.Null, false, false);
} else {
+ variable = null;
if (value_target == null || value_target_set)
value_target = new LocalTemporary (type);
initializers.Emit (ec);
- if (variable == null)
+ if (variable == null) {
value_target.Emit (ec);
+ value_target = null;
+ }
}
public override void EmitStatement (EmitContext ec)
return !initializers.IsEmpty;
}
}
+
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ base.MutateHoistedGenericType (storey);
+ initializers.MutateHoistedGenericType (storey);
+ }
}
public class AnonymousTypeDeclaration : Expression
type.DefineMembers ();
type.Define ();
type.EmitType ();
+ type.CloseType ();
RootContext.ToplevelTypes.AddAnonymousType (type);
return type;
}
+ public override Expression CreateExpressionTree (EmitContext ec)
+ {
+ throw new NotSupportedException ("ET");
+ }
+
public override Expression DoResolve (EmitContext ec)
{
AnonymousTypeClass anonymous_type;
t.initializer = initializer.Clone (clonectx);
}
+ public override Expression CreateExpressionTree (EmitContext ec)
+ {
+ throw new NotSupportedException ("ET");
+ }
+
public override bool Equals (object o)
{
AnonymousTypeParameter other = o as AnonymousTypeParameter;
if (e == null)
return null;
+ if (e.eclass == ExprClass.MethodGroup) {
+ Error_InvalidInitializer (e.ExprClassName);
+ return null;
+ }
+
type = e.Type;
if (type == TypeManager.void_type || type == TypeManager.null_type ||
type == TypeManager.anonymous_method_type || type.IsPointer) {
- Error_InvalidInitializer (e);
+ Error_InvalidInitializer (e.GetSignatureForError ());
return null;
}
return e;
}
- protected virtual void Error_InvalidInitializer (Expression initializer)
+ protected virtual void Error_InvalidInitializer (string initializer)
{
Report.Error (828, loc, "An anonymous type property `{0}' cannot be initialized with `{1}'",
- Name, initializer.GetSignatureForError ());
+ Name, initializer);
}
public override void Emit (EmitContext ec)