VariableInfo vi = vr.VariableInfo;
if (vi != null) {
if (vi.LocalInfo != null)
- vi.LocalInfo.Used = true;
+ vi.LocalInfo.SetIsUsed ();
//
// A variable is considered definitely assigned if you take its address.
Arguments args = new Arguments (1);
args.Add (new Argument (expr));
- var res = new OverloadResolver (methods, OverloadResolver.Restrictions.NoBaseMembers, loc);
+ var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
var oper = res.ResolveOperator (ec, ref args);
if (oper == null)
}
if (expr.Type == TypeManager.void_ptr_type) {
- ec.Report.Error (242, loc, "The operation in question is undefined on void pointers");
+ Error_VoidPointerOperation (ec);
return null;
}
// Holds the real operation
Expression operation;
+ static TypeSpec[] predefined;
+
public UnaryMutator (Mode m, Expression e, Location loc)
{
mode = m;
return new SimpleAssign (this, this).CreateExpressionTree (ec);
}
+ void CreatePredefinedOperators ()
+ {
+ //
+ // Predefined ++ and -- operators exist for the following types:
+ // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
+ //
+ predefined = new TypeSpec[] {
+ TypeManager.int32_type,
+
+ TypeManager.sbyte_type,
+ TypeManager.byte_type,
+ TypeManager.short_type,
+ TypeManager.ushort_type,
+ TypeManager.uint32_type,
+ TypeManager.int64_type,
+ TypeManager.uint64_type,
+ TypeManager.char_type,
+ TypeManager.float_type,
+ TypeManager.double_type,
+ TypeManager.decimal_type
+ };
+ }
+
protected override Expression DoResolve (ResolveContext ec)
{
expr = expr.Resolve (ec);
eclass = ExprClass.Value;
type = expr.Type;
- return ResolveOperator (ec);
+
+ if (expr is RuntimeValueExpression) {
+ operation = expr;
+ } else {
+ // Use itself at the top of the stack
+ operation = new EmptyExpression (type);
+ }
+
+ //
+ // The operand of the prefix/postfix increment decrement operators
+ // should be an expression that is classified as a variable,
+ // a property access or an indexer access
+ //
+ // TODO: Move to parser, expr is ATypeNameExpression
+ if (expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess) {
+ expr = expr.ResolveLValue (ec, expr);
+ } else {
+ ec.Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
+ }
+
+ //
+ // Step 1: Try to find a user operator, it has priority over predefined ones
+ //
+ var user_op = IsDecrement ? Operator.OpType.Decrement : Operator.OpType.Increment;
+ var methods = MemberCache.GetUserOperator (type, user_op, false);
+
+ if (methods != null) {
+ Arguments args = new Arguments (1);
+ args.Add (new Argument (expr));
+
+ var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
+ var method = res.ResolveOperator (ec, ref args);
+ if (method == null)
+ return null;
+
+ args[0].Expr = operation;
+ operation = new UserOperatorCall (method, args, null, loc);
+ operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
+ return this;
+ }
+
+ //
+ // Step 2: Try predefined types
+ //
+ if (predefined == null)
+ CreatePredefinedOperators ();
+
+ // Predefined without user conversion first for speed-up
+ Expression source = null;
+ bool primitive_type = false;
+ foreach (var t in predefined) {
+ if (t == type) {
+ source = operation;
+ primitive_type = true;
+ break;
+ }
+ }
+
+ // ++/-- on pointer variables of all types except void*
+ if (source == null && type.IsPointer) {
+ if (type == TypeManager.void_ptr_type) {
+ Error_VoidPointerOperation (ec);
+ return null;
+ }
+
+ source = operation;
+ }
+
+ if (source == null) {
+ // LAMESPEC: It should error on ambiguous operators but that would make us incompatible
+ foreach (var t in predefined) {
+ source = Convert.ImplicitUserConversion (ec, operation, t, loc);
+ if (source != null) {
+ break;
+ }
+ }
+ }
+
+ // ++/-- on enum types
+ if (source == null && type.IsEnum)
+ source = operation;
+
+ if (source == null) {
+ Unary.Error_OperatorCannotBeApplied (ec, loc, Operator.GetName (user_op), type);
+ return null;
+ }
+
+ var one = new IntConstant (1, loc);
+ var op = IsDecrement ? Binary.Operator.Subtraction : Binary.Operator.Addition;
+ operation = new Binary (op, source, one, loc);
+ operation = operation.Resolve (ec);
+ if (operation == null)
+ throw new NotImplementedException ("should not be reached");
+
+ if (operation.Type != type) {
+ if (primitive_type)
+ operation = Convert.ExplicitNumericConversion (operation, type);
+ else
+ operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
+ }
+
+ return this;
}
void EmitCode (EmitContext ec, bool is_expr)
get { return (mode & Mode.IsDecrement) != 0; }
}
- //
- // Returns whether an object of type `t' can be incremented
- // or decremented with add/sub (ie, basically whether we can
- // use pre-post incr-decr operations on it, but it is not a
- // System.Decimal, which we require operator overloading to catch)
- //
- static bool IsPredefinedOperator (TypeSpec t)
- {
- return (TypeManager.IsPrimitiveType (t) && t != TypeManager.bool_type) ||
- TypeManager.IsEnumType (t) ||
- t.IsPointer && t != TypeManager.void_ptr_type;
- }
#if NET_4_0
public override SLE.Expression MakeExpression (BuilderContext ctx)
}
#endif
- protected override void CloneTo (CloneContext clonectx, Expression t)
+ public static void Reset ()
{
- UnaryMutator target = (UnaryMutator) t;
-
- target.expr = expr.Clone (clonectx);
+ predefined = null;
}
- Expression ResolveOperator (ResolveContext ec)
+ protected override void CloneTo (CloneContext clonectx, Expression t)
{
- if (expr is RuntimeValueExpression) {
- operation = expr;
- } else {
- // Use itself at the top of the stack
- operation = new EmptyExpression (type);
- }
-
- //
- // The operand of the prefix/postfix increment decrement operators
- // should be an expression that is classified as a variable,
- // a property access or an indexer access
- //
- if (expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess) {
- expr = expr.ResolveLValue (ec, expr);
- } else {
- ec.Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
- }
-
- //
- // 1. Check predefined types
- //
- if (IsPredefinedOperator (type)) {
- // TODO: Move to IntConstant once I get rid of int32_type
- var one = new IntConstant (1, loc);
-
- // TODO: Cache this based on type when using EmptyExpression in
- // context cache
- Binary.Operator op = IsDecrement ? Binary.Operator.Subtraction : Binary.Operator.Addition;
- operation = new Binary (op, operation, one, loc);
- operation = operation.Resolve (ec);
- if (operation != null && operation.Type != type)
- operation = Convert.ExplicitNumericConversion (operation, type);
-
- return this;
- }
-
- //
- // Step 2: Perform Operator Overload location
- //
- var user_op = IsDecrement ? Operator.OpType.Decrement : Operator.OpType.Increment;
- var methods = MemberCache.GetUserOperator (type, user_op, false);
-
- if (methods != null) {
- Arguments args = new Arguments (1);
- args.Add (new Argument (expr));
-
- var res = new OverloadResolver (methods, OverloadResolver.Restrictions.NoBaseMembers, loc);
- var op = res.ResolveOperator (ec, ref args);
- if (op == null)
- return null;
-
- args[0].Expr = operation;
- operation = new UserOperatorCall (op, args, null, loc);
- operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
- return this;
- }
-
- string name = IsDecrement ?
- Operator.GetName (Operator.OpType.Decrement) :
- Operator.GetName (Operator.OpType.Increment);
+ UnaryMutator target = (UnaryMutator) t;
- Unary.Error_OperatorCannotBeApplied (ec, loc, name, type);
- return null;
+ target.expr = expr.Clone (clonectx);
}
}
if (TypeManager.IsGenericParameter (t))
return ResolveGenericParameter (ec, d, (TypeParameterSpec) t);
+ if (t == InternalType.Dynamic) {
+ ec.Report.Warning (1981, 3, loc,
+ "Using `{0}' to test compatibility with `{1}' is identical to testing compatibility with `object'",
+ OperatorName, t.GetSignatureForError ());
+ }
+
if (TypeManager.IsStruct (d)) {
if (Convert.ImplicitBoxingConversion (null, d, t) != null)
return CreateConstantResult (ec, true);
if (type.IsPointer && !ec.IsUnsafe) {
UnsafeError (ec, loc);
- } else if (expr.Type == InternalType.Dynamic) {
- if (type != InternalType.Dynamic) {
- Arguments arg = new Arguments (1);
- arg.Add (new Argument (expr));
- return new DynamicConversion (type, CSharpBinderFlags.ConvertExplicit, arg, loc).Resolve (ec);
- }
-
- return expr;
}
var res = Convert.ExplicitConversion (ec, expr, type, loc);
if (TypeManager.IsReferenceType (type))
return new NullConstant (type, loc);
- Constant c = New.Constantify (type);
+ Constant c = New.Constantify (type, expr.Location);
if (c != null)
return c.Resolve (ec);
var c = b.right as Constant;
if (c != null) {
- if (c.IsDefaultValue && (b.oper == Operator.Addition || b.oper == Operator.BitwiseOr || b.oper == Operator.Subtraction))
+ if (c.IsDefaultValue && (b.oper == Operator.Addition || b.oper == Operator.Subtraction || (b.oper == Operator.BitwiseOr && !(b is Nullable.LiftedBinaryOperator))))
return ReducedExpression.Create (b.left, b).Resolve (ec);
if ((b.oper == Operator.Multiply || b.oper == Operator.Division) && c.IsOneInteger)
return ReducedExpression.Create (b.left, b).Resolve (ec);
c = b.left as Constant;
if (c != null) {
- if (c.IsDefaultValue && (b.oper == Operator.Addition || b.oper == Operator.BitwiseOr))
+ if (c.IsDefaultValue && (b.oper == Operator.Addition || b.oper == Operator.Subtraction || (b.oper == Operator.BitwiseOr && !(b is Nullable.LiftedBinaryOperator))))
return ReducedExpression.Create (b.right, b).Resolve (ec);
if (b.oper == Operator.Multiply && c.IsOneInteger)
return ReducedExpression.Create (b.right, b).Resolve (ec);
RelationalMask = 1 << 13
}
+ protected enum State
+ {
+ None = 0,
+ Compound = 1 << 1,
+ LeftNullLifted = 1 << 2,
+ RightNullLifted = 1 << 3
+ }
+
readonly Operator oper;
protected Expression left, right;
- readonly bool is_compound;
+ protected State state;
Expression enum_conversion;
static PredefinedOperator[] standard_operators;
public Binary (Operator oper, Expression left, Expression right, bool isCompound, Location loc)
: this (oper, left, right, loc)
{
- this.is_compound = isCompound;
+ if (isCompound)
+ state |= State.Compound;
}
public Binary (Operator oper, Expression left, Expression right, Location loc)
this.loc = loc;
}
+ #region Properties
+
+ public bool IsCompound {
+ get {
+ return (state & State.Compound) != 0;
+ }
+ }
+
public Operator Oper {
get {
return oper;
}
}
-
+
+ #endregion
+
/// <summary>
/// Returns a stringified representation of the Operator
/// </summary>
break;
}
- if (is_compound)
+ if (IsCompound)
return s + "=";
return s;
{
switch (oper) {
case Operator.Addition:
- return is_compound ? "AddAssign" : "Add";
+ return IsCompound ? "AddAssign" : "Add";
case Operator.BitwiseAnd:
- return is_compound ? "AndAssign" : "And";
+ return IsCompound ? "AndAssign" : "And";
case Operator.BitwiseOr:
- return is_compound ? "OrAssign" : "Or";
+ return IsCompound ? "OrAssign" : "Or";
case Operator.Division:
- return is_compound ? "DivideAssign" : "Divide";
+ return IsCompound ? "DivideAssign" : "Divide";
case Operator.ExclusiveOr:
- return is_compound ? "ExclusiveOrAssign" : "ExclusiveOr";
+ return IsCompound ? "ExclusiveOrAssign" : "ExclusiveOr";
case Operator.Equality:
return "Equal";
case Operator.GreaterThan:
case Operator.Inequality:
return "NotEqual";
case Operator.LeftShift:
- return is_compound ? "LeftShiftAssign" : "LeftShift";
+ return IsCompound ? "LeftShiftAssign" : "LeftShift";
case Operator.LessThan:
return "LessThan";
case Operator.LessThanOrEqual:
case Operator.LogicalOr:
return "Or";
case Operator.Modulus:
- return is_compound ? "ModuloAssign" : "Modulo";
+ return IsCompound ? "ModuloAssign" : "Modulo";
case Operator.Multiply:
- return is_compound ? "MultiplyAssign" : "Multiply";
+ return IsCompound ? "MultiplyAssign" : "Multiply";
case Operator.RightShift:
- return is_compound ? "RightShiftAssign" : "RightShift";
+ return IsCompound ? "RightShiftAssign" : "RightShift";
case Operator.Subtraction:
- return is_compound ? "SubtractAssign" : "Subtract";
+ return IsCompound ? "SubtractAssign" : "Subtract";
default:
throw new NotImplementedException ("Unknown expression type operator " + oper.ToString ());
}
return ResolveOperatorPointer (ec, l, r);
// Enums
- bool lenum = TypeManager.IsEnumType (l);
- bool renum = TypeManager.IsEnumType (r);
+ bool lenum = l.IsEnum;
+ bool renum = r.IsEnum;
if (lenum || renum) {
expr = ResolveOperatorEnum (ec, lenum, renum, l, r);
- // TODO: Can this be ambiguous
if (expr != null)
return expr;
}
//
// U operator - (E e, E f)
// E operator - (E e, U x)
+ // E operator - (U x, E e) // LAMESPEC: Not covered by the specification
//
- // E operator + (U x, E e)
// E operator + (E e, U x)
+ // E operator + (U x, E e)
//
- if (!((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0 ||
- (oper == Operator.Subtraction && lenum) ||
- (oper == Operator.Addition && (lenum != renum || type != null)))) // type != null for lifted null
- return null;
-
Expression ltemp = left;
Expression rtemp = right;
TypeSpec underlying_type;
+ TypeSpec underlying_type_result;
+ TypeSpec res_type;
Expression expr;
+ //
+ // LAMESPEC: There is never ambiguous conversion between enum operators
+ // the one which contains more enum parameters always wins even if there
+ // is an implicit conversion involved
+ //
if ((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0) {
if (renum) {
+ underlying_type = EnumSpec.GetUnderlyingType (rtype);
expr = Convert.ImplicitConversion (ec, left, rtype, loc);
- if (expr != null) {
- left = expr;
- ltype = expr.Type;
- }
+ if (expr == null)
+ return null;
+
+ left = expr;
+ ltype = expr.Type;
} else if (lenum) {
+ underlying_type = EnumSpec.GetUnderlyingType (ltype);
expr = Convert.ImplicitConversion (ec, right, ltype, loc);
- if (expr != null) {
- right = expr;
- rtype = expr.Type;
- }
+ if (expr == null)
+ return null;
+
+ right = expr;
+ rtype = expr.Type;
+ } else {
+ return null;
}
- }
- if (ltype == rtype) {
- underlying_type = EnumSpec.GetUnderlyingType (ltype);
+ if ((oper & Operator.BitwiseMask) != 0) {
+ res_type = ltype;
+ underlying_type_result = underlying_type;
+ } else {
+ res_type = null;
+ underlying_type_result = null;
+ }
+ } else if (oper == Operator.Subtraction) {
+ if (renum) {
+ underlying_type = EnumSpec.GetUnderlyingType (rtype);
+ if (ltype != rtype) {
+ expr = Convert.ImplicitConversion (ec, left, rtype, left.Location);
+ if (expr == null) {
+ expr = Convert.ImplicitConversion (ec, left, underlying_type, left.Location);
+ if (expr == null)
+ return null;
+
+ res_type = rtype;
+ } else {
+ res_type = underlying_type;
+ }
- if (left is Constant)
- left = ((Constant) left).ConvertExplicitly (false, underlying_type).Resolve (ec);
- else
- left = EmptyCast.Create (left, underlying_type);
+ left = expr;
+ } else {
+ res_type = underlying_type;
+ }
- if (right is Constant)
- right = ((Constant) right).ConvertExplicitly (false, underlying_type).Resolve (ec);
- else
- right = EmptyCast.Create (right, underlying_type);
- } else if (lenum) {
- underlying_type = EnumSpec.GetUnderlyingType (ltype);
+ underlying_type_result = underlying_type;
+ } else if (lenum) {
+ underlying_type = EnumSpec.GetUnderlyingType (ltype);
+ expr = Convert.ImplicitConversion (ec, right, ltype, right.Location);
+ if (expr == null) {
+ expr = Convert.ImplicitConversion (ec, right, underlying_type, right.Location);
+ if (expr == null)
+ return null;
- if (oper != Operator.Subtraction && oper != Operator.Addition) {
- Constant c = right as Constant;
- if (c == null || !c.IsDefaultValue)
- return null;
+ res_type = ltype;
+ } else {
+ res_type = underlying_type;
+ }
+
+ right = expr;
+ underlying_type_result = underlying_type;
} else {
- if (!Convert.ImplicitStandardConversionExists (right, underlying_type))
- return null;
+ return null;
+ }
+ } else if (oper == Operator.Addition) {
+ if (lenum) {
+ underlying_type = EnumSpec.GetUnderlyingType (ltype);
+ res_type = ltype;
+
+ if (rtype != underlying_type && (state & (State.RightNullLifted | State.LeftNullLifted)) == 0) {
+ expr = Convert.ImplicitConversion (ec, right, underlying_type, right.Location);
+ if (expr == null)
+ return null;
- right = Convert.ImplicitConversionStandard (ec, right, underlying_type, right.Location);
+ right = expr;
+ }
+ } else {
+ underlying_type = EnumSpec.GetUnderlyingType (rtype);
+ res_type = rtype;
+ if (ltype != underlying_type) {
+ expr = Convert.ImplicitConversion (ec, left, underlying_type, left.Location);
+ if (expr == null)
+ return null;
+
+ left = expr;
+ }
}
+ underlying_type_result = underlying_type;
+ } else {
+ return null;
+ }
+
+ // Unwrap the constant correctly, so DoBinaryOperatorPromotion can do the magic
+ // with constants and expressions
+ if (left.Type != underlying_type) {
if (left is Constant)
left = ((Constant) left).ConvertExplicitly (false, underlying_type).Resolve (ec);
else
left = EmptyCast.Create (left, underlying_type);
+ }
- } else if (renum) {
- underlying_type = EnumSpec.GetUnderlyingType (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 = Convert.ImplicitConversionStandard (ec, left, underlying_type, left.Location);
- }
-
+ if (right.Type != underlying_type) {
if (right is Constant)
right = ((Constant) right).ConvertExplicitly (false, underlying_type).Resolve (ec);
else
right = EmptyCast.Create (right, underlying_type);
-
- } else {
- return null;
}
//
return null;
}
- TypeSpec res_type = null;
- if ((oper & Operator.BitwiseMask) != 0 || oper == Operator.Subtraction || oper == Operator.Addition) {
- TypeSpec 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;
+ if (underlying_type_result != null && left.Type != underlying_type_result) {
+ enum_conversion = Convert.ExplicitNumericConversion (new EmptyExpression (left.Type), underlying_type_result);
}
-
+
expr = ResolveOperatorPredefined (ec, standard_operators, true, res_type);
- if (!is_compound || expr == null)
+ if (expr == null)
+ return null;
+
+ if (!IsCompound)
return expr;
//
if (oper == Operator.BitwiseAnd || oper == Operator.LogicalAnd) {
Constant rc = right as Constant;
Constant lc = left as Constant;
- if ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue)) {
+ if (((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue)) && !(this is Nullable.LiftedBinaryOperator)) {
//
// The result is a constant with side-effect
//
left_operators = right_operators;
}
- var res = new OverloadResolver (left_operators, OverloadResolver.Restrictions.ProbingOnly, loc);
+ var res = new OverloadResolver (left_operators, OverloadResolver.Restrictions.ProbingOnly |
+ OverloadResolver.Restrictions.NoBaseMembers | OverloadResolver.Restrictions.BaseMembersIncluded, loc);
var oper_method = res.ResolveOperator (ec, ref args);
if (oper_method == null)
eclass = ExprClass.Variable;
if (left.Type == TypeManager.void_ptr_type) {
- ec.Report.Error (242, loc, "The operation in question is undefined on void pointers");
+ Error_VoidPointerOperation (ec);
return null;
}
}
}
- /// <summary>
- /// Local variables
- /// </summary>
- public class LocalVariableReference : VariableReference {
- readonly string name;
- public Block Block;
- public LocalInfo local_info;
- bool is_readonly;
+ //
+ // Resolved reference to a local variable
+ //
+ public class LocalVariableReference : VariableReference
+ {
+ public LocalVariable local_info;
- public LocalVariableReference (Block block, string name, Location l)
+ public LocalVariableReference (LocalVariable li, Location l)
{
- Block = block;
- this.name = name;
+ this.local_info = li;
loc = l;
}
- //
- // Setting `is_readonly' to false will allow you to create a writable
- // reference to a read-only variable. This is used by foreach and using.
- //
- public LocalVariableReference (Block block, string name, Location l,
- LocalInfo local_info, bool is_readonly)
- : this (block, name, l)
- {
- this.local_info = local_info;
- this.is_readonly = is_readonly;
- }
-
public override VariableInfo VariableInfo {
get { return local_info.VariableInfo; }
}
get { return false; }
}
- public bool IsReadOnly {
- get { return is_readonly; }
- }
-
public override string Name {
- get { return name; }
+ get { return local_info.Name; }
}
public bool VerifyAssigned (ResolveContext ec)
return variable_info == null || variable_info.IsAssigned (ec, loc);
}
- void ResolveLocalInfo ()
- {
- if (local_info == null) {
- local_info = Block.GetLocalInfo (Name);
- type = local_info.VariableType;
- is_readonly = local_info.ReadOnly;
- }
- }
-
public override void SetHasAddressTaken ()
{
local_info.AddressTaken = true;
Expression DoResolveBase (ResolveContext ec)
{
- Expression e = Block.GetConstantExpression (Name);
- if (e != null)
- return e.Resolve (ec);
-
VerifyAssigned (ec);
//
}
eclass = ExprClass.Variable;
- type = local_info.VariableType;
+ type = local_info.Type;
return this;
}
protected override Expression DoResolve (ResolveContext ec)
{
- ResolveLocalInfo ();
- local_info.Used = true;
+ local_info.SetIsUsed ();
- if (type == null && local_info.Type is VarExpr) {
- local_info.VariableType = TypeManager.object_type;
- Error_VariableIsUsedBeforeItIsDeclared (ec.Report, Name);
- return null;
- }
-
return DoResolveBase (ec);
}
public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
{
- ResolveLocalInfo ();
-
// is out param
if (right_side == EmptyExpression.OutAccess.Instance)
- local_info.Used = true;
+ local_info.SetIsUsed ();
- // Infer implicitly typed local variable
- if (type == null) {
- VarExpr ve = local_info.Type as VarExpr;
- if (ve != null) {
- if (!ve.InferType (ec, right_side))
- return null;
- type = local_info.VariableType = ve.Type;
- }
- }
-
- if (is_readonly) {
+ if (local_info.IsReadonly && !ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.UsingInitializerScope)) {
int code;
string msg;
if (right_side == EmptyExpression.OutAccess.Instance) {
public override int GetHashCode ()
{
- return Name.GetHashCode ();
+ return local_info.GetHashCode ();
}
public override bool Equals (object obj)
if (lvr == null)
return false;
- return Name == lvr.Name && Block == lvr.Block;
+ return local_info == lvr.local_info;
}
protected override ILocalVariable Variable {
protected override void CloneTo (CloneContext clonectx, Expression t)
{
- LocalVariableReference target = (LocalVariableReference) t;
-
- target.Block = clonectx.LookupBlock (Block);
- if (local_info != null)
- target.local_info = clonectx.LookupVariable (local_info);
+ // Nothing
}
}
/// This represents a reference to a parameter in the intermediate
/// representation.
/// </summary>
- public class ParameterReference : VariableReference {
- readonly ToplevelParameterInfo pi;
+ public class ParameterReference : VariableReference
+ {
+ protected ParametersBlock.ParameterInfo pi;
- public ParameterReference (ToplevelParameterInfo pi, Location loc)
+ public ParameterReference (ParametersBlock.ParameterInfo pi, Location loc)
{
this.pi = pi;
this.loc = loc;
}
+ #region Properties
+
public override bool IsRef {
get { return (pi.Parameter.ModFlags & Parameter.Modifier.ISBYREF) != 0; }
}
get { return Parameter; }
}
+ #endregion
+
public bool IsAssigned (ResolveContext ec, Location loc)
{
// HACK: Variables are not captured in probing mode
type = pi.ParameterType;
eclass = ExprClass.Variable;
- AnonymousExpression am = ec.CurrentAnonymousMethod;
- if (am == null)
- return true;
-
- Block b = ec.CurrentBlock;
- while (b != null) {
- b = b.Toplevel;
- IParameterData[] p = b.Toplevel.Parameters.FixedParameters;
- for (int i = 0; i < p.Length; ++i) {
- if (p [i] != Parameter)
- continue;
-
- //
- // Don't capture local parameters
- //
- if (b == ec.CurrentBlock.Toplevel && !am.IsIterator)
- return true;
-
- if (IsRef) {
- ec.Report.Error (1628, loc,
- "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
- Name, am.ContainerType);
- }
-
- if (pi.Parameter.HasAddressTaken)
- AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
-
- if (ec.IsVariableCapturingRequired && !b.Toplevel.IsExpressionTree) {
- AnonymousMethodStorey storey = pi.Block.CreateAnonymousMethodStorey (ec);
- storey.CaptureParameter (ec, this);
- }
+ //
+ // If we are referencing a parameter from the external block
+ // flag it for capturing
+ //
+ if (ec.MustCaptureVariable (pi)) {
+ if (Parameter.HasAddressTaken)
+ AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
- return true;
+ if (IsRef) {
+ ec.Report.Error (1628, loc,
+ "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
+ Name, ec.CurrentAnonymousMethod.ContainerType);
}
- b = b.Parent;
+ if (ec.IsVariableCapturingRequired && !pi.Block.ParametersBlock.IsExpressionTree) {
+ AnonymousMethodStorey storey = pi.Block.Explicit.CreateAnonymousMethodStorey (ec);
+ storey.CaptureParameter (ec, this);
+ }
}
return true;
protected override void CloneTo (CloneContext clonectx, Expression target)
{
// Nothing to clone
+ return;
}
public override Expression CreateExpressionTree (ResolveContext ec)
Expression member_expr;
var atn = expr as ATypeNameExpression;
if (atn != null) {
- member_expr = atn.LookupNameExpression (ec, true, true);
+ member_expr = atn.LookupNameExpression (ec, MemberLookupRestrictions.InvocableOnly | MemberLookupRestrictions.ReadAccess);
if (member_expr != null)
member_expr = member_expr.Resolve (ec);
} else {
}
}
- /// <summary>
- /// Implements the new expression
- /// </summary>
- public class New : ExpressionStatement, IMemoryLocation {
- protected Arguments Arguments;
+ //
+ // Implements simple new expression
+ //
+ public class New : ExpressionStatement, IMemoryLocation
+ {
+ protected Arguments arguments;
//
// During bootstrap, it contains the RequestedType,
public New (Expression requested_type, Arguments arguments, Location l)
{
RequestedType = requested_type;
- Arguments = arguments;
+ this.arguments = arguments;
loc = l;
}
+ #region Properties
+ public Arguments Arguments {
+ get {
+ return arguments;
+ }
+ }
+
+ //
+ // Returns true for resolved `new S()'
+ //
+ public bool IsDefaultStruct {
+ get {
+ return arguments == null && type.IsStruct && GetType () == typeof (New);
+ }
+ }
+
+ #endregion
+
/// <summary>
/// Converts complex core type syntax like 'new int ()' to simple constant
/// </summary>
- public static Constant Constantify (TypeSpec t)
+ public static Constant Constantify (TypeSpec t, Location loc)
{
if (t == TypeManager.int32_type)
- return new IntConstant (0, Location.Null);
+ return new IntConstant (0, loc);
if (t == TypeManager.uint32_type)
- return new UIntConstant (0, Location.Null);
+ return new UIntConstant (0, loc);
if (t == TypeManager.int64_type)
- return new LongConstant (0, Location.Null);
+ return new LongConstant (0, loc);
if (t == TypeManager.uint64_type)
- return new ULongConstant (0, Location.Null);
+ return new ULongConstant (0, loc);
if (t == TypeManager.float_type)
- return new FloatConstant (0, Location.Null);
+ return new FloatConstant (0, loc);
if (t == TypeManager.double_type)
- return new DoubleConstant (0, Location.Null);
+ return new DoubleConstant (0, loc);
if (t == TypeManager.short_type)
- return new ShortConstant (0, Location.Null);
+ return new ShortConstant (0, loc);
if (t == TypeManager.ushort_type)
- return new UShortConstant (0, Location.Null);
+ return new UShortConstant (0, loc);
if (t == TypeManager.sbyte_type)
- return new SByteConstant (0, Location.Null);
+ return new SByteConstant (0, loc);
if (t == TypeManager.byte_type)
- return new ByteConstant (0, Location.Null);
+ return new ByteConstant (0, loc);
if (t == TypeManager.char_type)
- return new CharConstant ('\0', Location.Null);
+ return new CharConstant ('\0', loc);
if (t == TypeManager.bool_type)
- return new BoolConstant (false, Location.Null);
+ return new BoolConstant (false, loc);
if (t == TypeManager.decimal_type)
- return new DecimalConstant (0, Location.Null);
+ return new DecimalConstant (0, loc);
if (TypeManager.IsEnumType (t))
- return new EnumConstant (Constantify (EnumSpec.GetUnderlyingType (t)), t);
+ return new EnumConstant (Constantify (EnumSpec.GetUnderlyingType (t), loc), t);
if (TypeManager.IsNullableType (t))
- return Nullable.LiftedNull.Create (t, Location.Null);
+ return Nullable.LiftedNull.Create (t, loc);
return null;
}
if (real_class == null)
return null;
- New proxy = new New (new TypeExpression (real_class, loc), Arguments, loc);
+ New proxy = new New (new TypeExpression (real_class, loc), arguments, loc);
Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
return cast.Resolve (ec);
}
args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
} else {
args = Arguments.CreateForExpressionTree (ec,
- Arguments, new TypeOfMethod (method, loc));
+ arguments, new TypeOfMethod (method, loc));
}
return CreateExpressionFactoryCall (ec, "New", args);
return null;
}
- if (Arguments == null) {
- Constant c = Constantify (type);
+ if (arguments == null) {
+ Constant c = Constantify (type, RequestedType.Location);
if (c != null)
return ReducedExpression.Create (c.Resolve (ec), this);
}
if (TypeManager.IsDelegateType (type)) {
- return (new NewDelegate (type, Arguments, loc)).Resolve (ec);
+ return (new NewDelegate (type, arguments, loc)).Resolve (ec);
}
var tparam = type as TypeParameterSpec;
TypeManager.CSharpName (type));
}
- if ((Arguments != null) && (Arguments.Count != 0)) {
+ if ((arguments != null) && (arguments.Count != 0)) {
ec.Report.Error (417, loc,
"`{0}': cannot provide arguments when creating an instance of a variable type",
TypeManager.CSharpName (type));
//
// Any struct always defines parameterless constructor
//
- if (type.IsStruct && Arguments == null)
+ if (type.IsStruct && arguments == null)
return this;
bool dynamic;
- if (Arguments != null) {
- Arguments.Resolve (ec, out dynamic);
+ if (arguments != null) {
+ arguments.Resolve (ec, out dynamic);
} else {
dynamic = false;
}
- method = ConstructorLookup (ec, type, ref Arguments, loc);
+ method = ConstructorLookup (ec, type, ref arguments, loc);
if (dynamic) {
- Arguments.Insert (0, new Argument (new TypeOf (texpr, loc).Resolve (ec), Argument.AType.DynamicTypeName));
- return new DynamicConstructorBinder (type, Arguments, loc).Resolve (ec);
+ arguments.Insert (0, new Argument (new TypeOf (texpr, loc).Resolve (ec), Argument.AType.DynamicTypeName));
+ return new DynamicConstructorBinder (type, arguments, loc).Resolve (ec);
}
return this;
vr.EmitLoad (ec);
}
- if (Arguments != null)
- Arguments.Emit (ec);
+ if (arguments != null)
+ arguments.Emit (ec);
if (is_value_type) {
if (method == null) {
ec.Emit (OpCodes.Pop);
}
- public virtual bool HasInitializer {
- get {
- return false;
- }
- }
-
public void AddressOf (EmitContext ec, AddressOp mode)
{
EmitAddressOf (ec, mode);
if (method == null) {
ec.Emit (OpCodes.Initobj, type);
} else {
- if (Arguments != null)
- Arguments.Emit (ec);
+ if (arguments != null)
+ arguments.Emit (ec);
ec.Emit (OpCodes.Call, method);
}
New target = (New) t;
target.RequestedType = RequestedType.Clone (clonectx);
- if (Arguments != null){
- target.Arguments = Arguments.Clone (clonectx);
+ if (arguments != null){
+ target.arguments = arguments.Clone (clonectx);
}
}
public override SLE.Expression MakeExpression (BuilderContext ctx)
{
- return SLE.Expression.New ((ConstructorInfo) method.GetMetaInfo (), Arguments.MakeExpression (Arguments, ctx));
+ return SLE.Expression.New ((ConstructorInfo) method.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
}
}
+ //
+ // Array initializer expression, the expression is allowed in
+ // variable or field initialization only which makes it tricky as
+ // the type has to be infered based on the context either from field
+ // type or variable type (think of multiple declarators)
+ //
public class ArrayInitializer : Expression
{
List<Expression> elements;
+ BlockVariableDeclaration variable;
public ArrayInitializer (List<Expression> init, Location loc)
{
}
public ArrayInitializer (int count, Location loc)
+ : this (new List<Expression> (count), loc)
{
- elements = new List<Expression> (count);
- this.loc = loc;
}
public ArrayInitializer (Location loc)
{
}
+ #region Properties
+
+ public int Count {
+ get { return elements.Count; }
+ }
+
+ public Expression this [int index] {
+ get {
+ return elements [index];
+ }
+ }
+
+ public BlockVariableDeclaration VariableDeclaration {
+ get {
+ return variable;
+ }
+ set {
+ variable = value;
+ }
+ }
+
+ #endregion
+
public void Add (Expression expr)
{
elements.Add (expr);
target.elements.Add (element.Clone (clonectx));
}
- public int Count {
- get { return elements.Count; }
- }
-
protected override Expression DoResolve (ResolveContext rc)
{
var current_field = rc.CurrentMemberDefinition as FieldBase;
- return new ArrayCreation (new TypeExpression (current_field.MemberType, current_field.Location), this).Resolve (rc);
+ TypeExpression type;
+ if (current_field != null) {
+ type = new TypeExpression (current_field.MemberType, current_field.Location);
+ } else if (variable != null) {
+ if (variable.TypeExpression is VarExpr) {
+ rc.Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
+ return EmptyExpression.Null;
+ }
+
+ type = new TypeExpression (variable.Variable.Type, variable.Variable.Location);
+ } else {
+ throw new NotImplementedException ("Unexpected array initializer context");
+ }
+
+ return new ArrayCreation (type, this).Resolve (rc);
}
public override void Emit (EmitContext ec)
{
throw new InternalErrorException ("Missing Resolve call");
}
-
- public Expression this [int index] {
- get { return elements [index]; }
- }
}
/// <summary>
//
bool ResolveArrayType (ResolveContext ec)
{
- if (requested_base_type is VarExpr) {
- ec.Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
- return false;
- }
-
//
// Lookup the type
//
return;
// Emit static initializer for arrays which have contain more than 2 items and
- // the static initializer will initialize at least 25% of array values.
+ // the static initializer will initialize at least 25% of array values or there
+ // is more than 10 items to be initialized
// NOTE: const_initializers_count does not contain default constant values.
- if (const_initializers_count > 2 && const_initializers_count * 4 > (array_data.Count) &&
+ if (const_initializers_count > 2 && (array_data.Count > 10 || const_initializers_count * 4 > (array_data.Count)) &&
(TypeManager.IsPrimitiveType (array_element_type) || TypeManager.IsEnumType (array_element_type))) {
EmitStaticInitializers (ec);
var block = ec.CurrentBlock;
if (block != null) {
- if (block.Toplevel.ThisVariable != null)
- variable_info = block.Toplevel.ThisVariable.VariableInfo;
+ if (block.ParametersBlock.TopBlock.ThisVariable != null)
+ variable_info = block.ParametersBlock.TopBlock.ThisVariable.VariableInfo;
AnonymousExpression am = ec.CurrentAnonymousMethod;
if (am != null && ec.IsVariableCapturingRequired) {
eclass = ExprClass.Variable;
type = TypeManager.runtime_argument_handle_type;
- if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.Toplevel.Parameters.HasArglist) {
+ if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.ParametersBlock.Parameters.HasArglist) {
ec.Report.Error (190, loc,
"The __arglist construct is valid only within a variable argument method");
}
public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
{
if (alias == GlobalAlias) {
- expr = GlobalRootNamespace.Instance;
+ expr = ec.Compiler.GlobalRootNamespace;
return base.ResolveAsTypeStep (ec, silent);
}
return alias + "::" + name;
}
- public override Expression LookupNameExpression (ResolveContext rc, bool readMode, bool invocableOnly)
+ public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
{
return DoResolve (rc);
}
Expression DoResolveName (ResolveContext rc, Expression right_side)
{
- Expression e = LookupNameExpression (rc, right_side == null, false);
+ Expression e = LookupNameExpression (rc, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
if (e == null)
return null;
- if (right_side != null)
+ if (right_side != null) {
+ if (e is TypeExpr) {
+ e.Error_UnexpectedKind (rc, ResolveFlags.VariableOrValue, loc);
+ return null;
+ }
+
e = e.ResolveLValue (rc, right_side);
- else
+ } else {
e = e.Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.Type);
+ }
return e;
}
- public override Expression LookupNameExpression (ResolveContext rc, bool readMode, bool invocableOnly)
+ public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
{
var sn = expr as SimpleName;
const ResolveFlags flags = ResolveFlags.VariableOrValue | ResolveFlags.Type;
//
using (rc.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
if (sn != null) {
- expr = sn.LookupNameExpression (rc, true, false);
+ expr = sn.LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.ExactArity);
// Call resolve on expression which does have type set as we need expression type
// TODO: I should probably ensure that the type is always set and leave resolve for the final
MemberKind.Interface | MemberKind.TypeParameter | MemberKind.ArrayType;
if ((expr_type.Kind & dot_kinds) == 0 || expr_type == TypeManager.void_type) {
- Unary.Error_OperatorCannotBeApplied (rc, loc, ".", expr_type);
+ if (expr_type == InternalType.Null && rc.Compiler.IsRuntimeBinder)
+ rc.Report.Error (Report.RuntimeErrorId, loc, "Cannot perform member binding on `null' value");
+ else
+ Unary.Error_OperatorCannotBeApplied (rc, loc, ".", expr_type);
return null;
}
bool errorMode = false;
Expression member_lookup;
while (true) {
- member_lookup = MemberLookup (errorMode ? null : rc, current_type, expr_type, Name, lookup_arity, invocableOnly, loc);
+ member_lookup = MemberLookup (errorMode ? null : rc, current_type, expr_type, Name, lookup_arity, restrictions, loc);
if (member_lookup == null) {
//
// Try to look for extension method when member lookup failed
current_type = null;
lookup_arity = 0;
- invocableOnly = false;
+ restrictions &= ~MemberLookupRestrictions.InvocableOnly;
errorMode = true;
}
return;
}
- var any_other_member = MemberLookup (null, rc.CurrentType, expr_type, Name, 0, false, loc);
+ var any_other_member = MemberLookup (null, rc.CurrentType, expr_type, Name, 0, MemberLookupRestrictions.None, loc);
if (any_other_member != null) {
any_other_member.Error_UnexpectedKind (rc.Compiler.Report, null, "type", loc);
return;
UnsafeError (ec.Compiler.Report, loc);
}
- type = PointerContainer.MakeType (type);
- single_spec = single_spec.Next;
+ do {
+ type = PointerContainer.MakeType (type);
+ single_spec = single_spec.Next;
+ } while (single_spec != null && single_spec.IsPointer);
}
if (single_spec != null && single_spec.Dimension > 0) {
target = new DynamicMemberBinder (Name, args, loc);
} else {
- var member = MemberLookup (ec, ec.CurrentType, t, Name, 0, false, loc);
+ var member = MemberLookup (ec, ec.CurrentType, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
if (member == null) {
- member = Expression.MemberLookup (null, ec.CurrentType, t, Name, 0, false, loc);
+ member = Expression.MemberLookup (null, ec.CurrentType, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
if (member != null) {
// TODO: ec.Report.SymbolRelatedToPreviousError (member);
initializer.Resolve (ec);
throw new InternalErrorException ("This line should never be reached");
} else {
- if (!ec.CurrentInitializerVariable.Type.ImplementsInterface (TypeManager.ienumerable_type)) {
+ var t = ec.CurrentInitializerVariable.Type;
+ // LAMESPEC: The collection must implement IEnumerable only, no dynamic support
+ if (!t.ImplementsInterface (TypeManager.ienumerable_type, false) && t != InternalType.Dynamic) {
ec.Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
"object initializer because type `{1}' does not implement `{2}' interface",
ec.CurrentInitializerVariable.GetSignatureForError (),
return left_on_stack;
}
-
- public override bool HasInitializer {
- get {
- return !initializers.IsEmpty;
- }
- }
}
public class NewAnonymousType : New
foreach (Property p in anonymous_type.Properties)
init.Add (new TypeOfMethod (MemberCache.GetMember (type, p.Get.Spec), loc));
- var ctor_args = new ArrayInitializer (Arguments.Count, loc);
- foreach (Argument a in Arguments)
+ var ctor_args = new ArrayInitializer (arguments.Count, loc);
+ foreach (Argument a in arguments)
ctor_args.Add (a.CreateExpressionTree (ec));
Arguments args = new Arguments (3);
}
bool error = false;
- Arguments = new Arguments (parameters.Count);
+ arguments = new Arguments (parameters.Count);
TypeExpression [] t_args = new TypeExpression [parameters.Count];
for (int i = 0; i < parameters.Count; ++i) {
Expression e = ((AnonymousTypeParameter) parameters [i]).Resolve (ec);
continue;
}
- Arguments.Add (new Argument (e));
+ arguments.Add (new Argument (e));
t_args [i] = new TypeExpression (e.Type, e.Location);
}