lr.local_info.Used = true;
}
+ ParameterReference pr = Expr as ParameterReference;
+ if ((pr != null) && pr.Parameter.IsCaptured) {
+ AnonymousMethod.Error_AddressOfCapturedVar (pr.Name, loc);
+ return null;
+ }
+
// According to the specs, a variable is considered definitely assigned if you take
// its address.
if ((variable != null) && (variable.VariableInfo != null)){
StoreFromPtr (ec.ig, type);
- if (temporary != null)
+ if (temporary != null) {
temporary.Emit (ec);
+ temporary.Release (ec);
+ }
}
public void AddressOf (EmitContext ec, AddressOp Mode)
#region IVariable Members
public VariableInfo VariableInfo {
- get {
- return null;
- }
+ get { return null; }
}
public bool VerifyFixed ()
PostIncrement = IsPost,
PostDecrement = IsPost | IsDecrement
}
-
+
Mode mode;
bool is_expr = false;
bool recurse = false;
-
+
Expression expr;
//
// This is expensive for the simplest case.
//
StaticCallExpr method;
-
+
public UnaryMutator (Mode m, Expression e, Location l)
{
mode = m;
return (mode == Mode.PreIncrement || mode == Mode.PostIncrement) ?
"++" : "--";
}
-
+
/// <summary>
/// Returns whether an object of type `t' can be incremented
/// or decremented with add/sub (ie, basically whether we can
}
}
-
+
void EmitCode (EmitContext ec, bool is_expr)
{
recurse = true;
// having to allocate another expression
//
if (recurse) {
- ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
+ ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
if (method == null)
LoadOneAndEmitOp (ec, expr.Type);
else
recurse = false;
return;
}
-
+
EmitCode (ec, true);
}
-
+
public override void EmitStatement (EmitContext ec)
{
EmitCode (ec, false);
this.loc = loc;
if (target_type == TypeManager.system_void_expr)
- Report.Error (1547, loc, "Keyword `void' cannot be used in this context");
+ Error_VoidInvalidInTheContext (loc);
}
public Expression TargetType {
+ "'");
}
- static bool IsOfType (EmitContext ec, Type l, Type r, Type t, bool check_user_conversions)
+ bool IsConvertible (EmitContext ec, Expression le, Expression re, Type t)
{
- if ((l == t) || (r == t))
- return true;
-
- if (!check_user_conversions)
- return false;
+ return Convert.ImplicitConversionExists (ec, le, t) && Convert.ImplicitConversionExists (ec, re, t);
+ }
- if (Convert.ImplicitUserConversionExists (ec, l, t))
- return true;
- else if (Convert.ImplicitUserConversionExists (ec, r, t))
- return true;
- else
+ bool VerifyApplicable_Predefined (EmitContext ec, Type t)
+ {
+ if (!IsConvertible (ec, left, right, t))
return false;
+ left = ForceConversion (ec, left, t);
+ right = ForceConversion (ec, right, t);
+ type = t;
+ return true;
}
- //
- // Note that handling the case l == Decimal || r == Decimal
- // is taken care of by the Step 1 Operator Overload resolution.
- //
- // If `check_user_conv' is true, we also check whether a user-defined conversion
- // exists. Note that we only need to do this if both arguments are of a user-defined
- // type, otherwise ConvertImplict() already finds the user-defined conversion for us,
- // so we don't explicitly check for performance reasons.
- //
- bool DoNumericPromotions (EmitContext ec, Type l, Type r, Expression lexpr, Expression rexpr, bool check_user_conv)
- {
- if (IsOfType (ec, l, r, TypeManager.double_type, check_user_conv)){
- //
- // If either operand is of type double, the other operand is
- // conveted to type double.
- //
- if (r != TypeManager.double_type)
- right = Convert.ImplicitConversion (ec, right, TypeManager.double_type, loc);
- if (l != TypeManager.double_type)
- left = Convert.ImplicitConversion (ec, left, TypeManager.double_type, loc);
-
- type = TypeManager.double_type;
- } else if (IsOfType (ec, l, r, TypeManager.float_type, check_user_conv)){
- //
- // if either operand is of type float, the other operand is
- // converted to type float.
- //
- if (r != TypeManager.double_type)
- right = Convert.ImplicitConversion (ec, right, TypeManager.float_type, loc);
- if (l != TypeManager.double_type)
- left = Convert.ImplicitConversion (ec, left, TypeManager.float_type, loc);
- type = TypeManager.float_type;
- } else if (IsOfType (ec, l, r, TypeManager.uint64_type, check_user_conv)){
- Expression e;
- Type other;
- //
- // If either operand is of type ulong, the other operand is
- // converted to type ulong. or an error ocurrs if the other
- // operand is of type sbyte, short, int or long
- //
- if (l == TypeManager.uint64_type){
- if (r != TypeManager.uint64_type){
- if (right is IntConstant){
- IntConstant ic = (IntConstant) right;
-
- e = Convert.TryImplicitIntConversion (l, ic);
- if (e != null)
- right = e;
- } else if (right is LongConstant){
- long ll = ((LongConstant) right).Value;
-
- if (ll >= 0)
- right = new ULongConstant ((ulong) ll, right.Location);
- } else {
- e = Convert.ImplicitNumericConversion (right, l);
- if (e != null)
- right = e;
- }
- }
- other = right.Type;
- } else {
- if (left is IntConstant){
- e = Convert.TryImplicitIntConversion (r, (IntConstant) left);
- if (e != null)
- left = e;
- } else if (left is LongConstant){
- long ll = ((LongConstant) left).Value;
-
- if (ll > 0)
- left = new ULongConstant ((ulong) ll, right.Location);
- } else {
- e = Convert.ImplicitNumericConversion (left, r);
- if (e != null)
- left = e;
- }
- other = left.Type;
- }
-
- if ((other == TypeManager.sbyte_type) ||
- (other == TypeManager.short_type) ||
- (other == TypeManager.int32_type) ||
- (other == TypeManager.int64_type))
- Error_OperatorAmbiguous (loc, oper, l, r);
- else {
- left = ForceConversion (ec, left, TypeManager.uint64_type);
- right = ForceConversion (ec, right, TypeManager.uint64_type);
- }
- type = TypeManager.uint64_type;
- } else if (IsOfType (ec, l, r, TypeManager.int64_type, check_user_conv)){
- //
- // If either operand is of type long, the other operand is converted
- // to type long.
- //
- if (l != TypeManager.int64_type)
- left = Convert.ImplicitConversion (ec, left, TypeManager.int64_type, loc);
- if (r != TypeManager.int64_type)
- right = Convert.ImplicitConversion (ec, right, TypeManager.int64_type, loc);
-
- type = TypeManager.int64_type;
- } else if (IsOfType (ec, l, r, TypeManager.uint32_type, check_user_conv)){
- //
- // If either operand is of type uint, and the other
- // operand is of type sbyte, short or int, othe operands are
- // converted to type long (unless we have an int constant).
- //
- Type other = null;
-
- if (l == TypeManager.uint32_type){
- if (right is IntConstant){
- IntConstant ic = (IntConstant) right;
- int val = ic.Value;
-
- if (val >= 0){
- right = new UIntConstant ((uint) val, ic.Location);
- type = l;
-
- return true;
- }
- }
- other = r;
- } else if (r == TypeManager.uint32_type){
- if (left is IntConstant){
- IntConstant ic = (IntConstant) left;
- int val = ic.Value;
-
- if (val >= 0){
- left = new UIntConstant ((uint) val, ic.Location);
- type = r;
- return true;
- }
- }
-
- other = l;
- }
-
- if ((other == TypeManager.sbyte_type) ||
- (other == TypeManager.short_type) ||
- (other == TypeManager.int32_type)){
- left = ForceConversion (ec, left, TypeManager.int64_type);
- right = ForceConversion (ec, right, TypeManager.int64_type);
- type = TypeManager.int64_type;
- } else {
- //
- // if either operand is of type uint, the other
- // operand is converd to type uint
- //
- left = ForceConversion (ec, left, TypeManager.uint32_type);
- right = ForceConversion (ec, right, TypeManager.uint32_type);
- type = TypeManager.uint32_type;
- }
- } else if (l == TypeManager.decimal_type || r == TypeManager.decimal_type){
- if (l != TypeManager.decimal_type)
- left = Convert.ImplicitConversion (ec, left, TypeManager.decimal_type, loc);
+ bool IsApplicable_String (EmitContext ec, Expression le, Expression re, Operator oper)
+ {
+ bool l = Convert.ImplicitConversionExists (ec, le, TypeManager.string_type);
+ bool r = Convert.ImplicitConversionExists (ec, re, TypeManager.string_type);
- if (r != TypeManager.decimal_type)
- right = Convert.ImplicitConversion (ec, right, TypeManager.decimal_type, loc);
- type = TypeManager.decimal_type;
- } else {
- left = ForceConversion (ec, left, TypeManager.int32_type);
- right = ForceConversion (ec, right, TypeManager.int32_type);
+ if (oper == Operator.Equality || oper == Operator.Inequality)
+ return l && r;
+ if (oper == Operator.Addition)
+ return l || r;
+ return false;
+ }
- bool strConv =
- Convert.ImplicitConversionExists (ec, lexpr, TypeManager.string_type) &&
- Convert.ImplicitConversionExists (ec, rexpr, TypeManager.string_type);
- if (strConv && left != null && right != null)
- Error_OperatorAmbiguous (loc, oper, l, r);
+ bool OverloadResolve_PredefinedString (EmitContext ec, Operator oper)
+ {
+ if (!IsApplicable_String (ec, left, right, oper))
+ return false;
+ Type t = TypeManager.string_type;
+ if (Convert.ImplicitConversionExists (ec, left, t))
+ left = ForceConversion (ec, left, t);
+ if (Convert.ImplicitConversionExists (ec, right, t))
+ right = ForceConversion (ec, right, t);
+ type = t;
+ return true;
+ }
- type = TypeManager.int32_type;
- }
+ bool OverloadResolve_PredefinedIntegral (EmitContext ec)
+ {
+ return VerifyApplicable_Predefined (ec, TypeManager.int32_type) ||
+ VerifyApplicable_Predefined (ec, TypeManager.uint32_type) ||
+ VerifyApplicable_Predefined (ec, TypeManager.int64_type) ||
+ VerifyApplicable_Predefined (ec, TypeManager.uint64_type) ||
+ false;
+ }
- return (left != null) && (right != null);
+ bool OverloadResolve_PredefinedFloating (EmitContext ec)
+ {
+ return VerifyApplicable_Predefined (ec, TypeManager.float_type) ||
+ VerifyApplicable_Predefined (ec, TypeManager.double_type) ||
+ false;
}
static public void Error_OperatorCannotBeApplied (Location loc, string name, Type l, Type r)
void Error_OperatorCannotBeApplied ()
{
- Error_OperatorCannotBeApplied (Location, OperName (oper), left.GetSignatureForError (), right.GetSignatureForError ());
+ Error_OperatorCannotBeApplied (Location, OperName (oper), TypeManager.CSharpName (left.Type),
+ TypeManager.CSharpName(right.Type));
}
static bool is_unsigned (Type t)
t == TypeManager.short_type || t == TypeManager.byte_type);
}
- static bool is_user_defined (Type t)
- {
- if (t.IsSubclassOf (TypeManager.value_type) &&
- (!TypeManager.IsBuiltinType (t) || t == TypeManager.decimal_type))
- return true;
- else
- return false;
- }
-
Expression Make32or64 (EmitContext ec, Expression e)
{
Type t= e.Type;
Expression CheckShiftArguments (EmitContext ec)
{
- Expression e;
-
- e = ForceConversion (ec, right, TypeManager.int32_type);
- if (e == null){
+ Expression new_left = Make32or64 (ec, left);
+ Expression new_right = ForceConversion (ec, right, TypeManager.int32_type);
+ if (new_left == null || new_right == null) {
Error_OperatorCannotBeApplied ();
return null;
}
- right = e;
-
- if (((e = Convert.ImplicitConversion (ec, left, TypeManager.int32_type, loc)) != null) ||
- ((e = Convert.ImplicitConversion (ec, left, TypeManager.uint32_type, loc)) != null) ||
- ((e = Convert.ImplicitConversion (ec, left, TypeManager.int64_type, loc)) != null) ||
- ((e = Convert.ImplicitConversion (ec, left, TypeManager.uint64_type, loc)) != null)){
- left = e;
- type = e.Type;
-
- if (type == TypeManager.int32_type || type == TypeManager.uint32_type){
- right = new Binary (Binary.Operator.BitwiseAnd, right, new IntConstant (31, loc));
- right = right.DoResolve (ec);
- } else {
- right = new Binary (Binary.Operator.BitwiseAnd, right, new IntConstant (63, loc));
- right = right.DoResolve (ec);
- }
-
- return this;
- }
- Error_OperatorCannotBeApplied ();
- return null;
+ type = new_left.Type;
+ int shiftmask = (type == TypeManager.int32_type || type == TypeManager.uint32_type) ? 31 : 63;
+ left = new_left;
+ right = new Binary (Binary.Operator.BitwiseAnd, new_right, new IntConstant (shiftmask, loc)).DoResolve (ec);
+ return this;
}
//
if ((l == TypeManager.null_type && EqualsNullIsReferenceEquals (r)) ||
(r == TypeManager.null_type && EqualsNullIsReferenceEquals (l))) {
Type = TypeManager.bool_type;
-
return this;
}
// built-in types
//
Expression left_operators = null, right_operators = null;
- if (!(TypeManager.IsPrimitiveType (l) && TypeManager.IsPrimitiveType (r))){
+ if (!(TypeManager.IsPrimitiveType (l) && TypeManager.IsPrimitiveType (r))) {
//
// Step 1: Perform Operator Overload location
//
string op = oper_names [(int) oper];
-
+
MethodGroupExpr union;
left_operators = MemberLookup (ec.ContainerType, l, op, MemberTypes.Method, AllBindingFlags, loc);
if (r != l){
union = Invocation.MakeUnionSet (left_operators, right_operators, loc);
} else
union = (MethodGroupExpr) left_operators;
-
+
if (union != null) {
ArrayList args = new ArrayList (2);
args.Add (new Argument (left, Argument.AType.Expression));
args.Add (new Argument (right, Argument.AType.Expression));
-
- MethodBase method = Invocation.OverloadResolve (
- ec, union, args, true, Location.Null);
+
+ MethodBase method = Invocation.OverloadResolve (ec, union, args, true, Location.Null);
if (method != null) {
MethodInfo mi = (MethodInfo) method;
-
return new BinaryMethod (mi.ReturnType, method, args);
}
}
}
-
+
//
// Step 0: String concatenation (because overloading will get this wrong)
//
Error_OperatorCannotBeApplied ();
return null;
}
-
+
// try to fold it in on the left
if (left is StringConcat) {
return left;
}
}
-
+
// Otherwise, start a new concat expression
return new StringConcat (ec, loc, left, right).Resolve (ec);
}
Error_OperatorCannotBeApplied ();
return null;
}
-
+
type = TypeManager.bool_type;
return this;
}
if (r != TypeManager.object_type)
right = new EmptyCast (right, TypeManager.object_type);
- //
- // FIXME: CSC here catches errors cs254 and cs252
- //
return this;
}
-
- //
- // One of them is a valuetype, but the other one is not.
- //
- if (!l.IsValueType || !r.IsValueType) {
- Error_OperatorCannotBeApplied ();
- return null;
- }
}
// Only perform numeric promotions on:
r = right.Type;
}
}
-
- if (TypeManager.IsDelegateType (r)){
+
+ if (TypeManager.IsDelegateType (r) || right is NullLiteral){
MethodInfo method;
ArrayList args = new ArrayList (2);
else
method = TypeManager.delegate_remove_delegate_delegate;
- if (!TypeManager.IsEqual (l, r)) {
+ if (!TypeManager.IsEqual (l, r) && !(right is NullLiteral)) {
Error_OperatorCannotBeApplied ();
return null;
}
return e.Resolve (ec);
}
+ Expression orig_left = left;
+ Expression orig_right = right;
+
//
// operator & (bool x, bool y)
// operator | (bool x, bool y)
// operator ^ (bool x, bool y)
//
- if (l == TypeManager.bool_type && r == TypeManager.bool_type){
- if (oper == Operator.BitwiseAnd ||
- oper == Operator.BitwiseOr ||
- oper == Operator.ExclusiveOr){
- type = l;
- return this;
+ if (oper == Operator.BitwiseAnd ||
+ oper == Operator.BitwiseOr ||
+ oper == Operator.ExclusiveOr) {
+ if (OverloadResolve_PredefinedIntegral (ec)) {
+ if (IsConvertible (ec, orig_left, orig_right, TypeManager.bool_type)) {
+ Error_OperatorAmbiguous (loc, oper, l, r);
+ return null;
+ }
+ } else if (!VerifyApplicable_Predefined (ec, TypeManager.bool_type)) {
+ Error_OperatorCannotBeApplied ();
+ return null;
}
+ return this;
}
//
return this;
}
}
-
- //
- // This will leave left or right set to null if there is an error
- //
- bool check_user_conv = is_user_defined (l) && is_user_defined (r);
- DoNumericPromotions (ec, l, r, left, right, check_user_conv);
- if (left == null || right == null){
- Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
- return null;
- }
- //
- // reload our cached types if required
- //
- l = left.Type;
- r = right.Type;
-
- if (oper == Operator.BitwiseAnd ||
- oper == Operator.BitwiseOr ||
- oper == Operator.ExclusiveOr){
- if (l == r){
- if (((l == TypeManager.int32_type) ||
- (l == TypeManager.uint32_type) ||
- (l == TypeManager.short_type) ||
- (l == TypeManager.ushort_type) ||
- (l == TypeManager.int64_type) ||
- (l == TypeManager.uint64_type))){
- type = l;
- } else {
- Error_OperatorCannotBeApplied ();
- return null;
- }
- } else {
- Error_OperatorCannotBeApplied ();
+ if (OverloadResolve_PredefinedIntegral (ec)) {
+ if (IsApplicable_String (ec, orig_left, orig_right, oper)) {
+ Error_OperatorAmbiguous (loc, oper, l, r);
+ return null;
+ }
+ } else if (OverloadResolve_PredefinedFloating (ec)) {
+ if (IsConvertible (ec, orig_left, orig_right, TypeManager.decimal_type) ||
+ IsApplicable_String (ec, orig_left, orig_right, oper)) {
+ Error_OperatorAmbiguous (loc, oper, l, r);
return null;
}
+ } else if (VerifyApplicable_Predefined (ec, TypeManager.decimal_type)) {
+ if (IsApplicable_String (ec, orig_left, orig_right, oper)) {
+ Error_OperatorAmbiguous (loc, oper, l, r);
+ return null;
+ }
+ } else if (!OverloadResolve_PredefinedString (ec, oper)) {
+ Error_OperatorCannotBeApplied ();
+ return null;
}
if (oper == Operator.Equality ||
oper == Operator.LessThanOrEqual ||
oper == Operator.LessThan ||
oper == Operator.GreaterThanOrEqual ||
- oper == Operator.GreaterThan){
+ oper == Operator.GreaterThan)
type = TypeManager.bool_type;
+
+ l = left.Type;
+ r = right.Type;
+
+ if (l == TypeManager.decimal_type || l == TypeManager.string_type || r == TypeManager.string_type) {
+ Type lookup = l;
+ if (r == TypeManager.string_type)
+ lookup = r;
+ MethodGroupExpr ops = (MethodGroupExpr) MemberLookup (
+ ec.ContainerType, lookup, oper_names [(int) oper],
+ MemberTypes.Method, AllBindingFlags, loc);
+ ArrayList args = new ArrayList (2);
+ args.Add (new Argument (left, Argument.AType.Expression));
+ args.Add (new Argument (right, Argument.AType.Expression));
+ MethodBase method = Invocation.OverloadResolve (ec, ops, args, true, Location.Null);
+ return new BinaryMethod (type, method, args);
}
return this;
}
Type ltype = left.Type, rtype = right.Type;
- if (ltype.IsValueType && rtype.IsValueType &&
+ if ((left is NullLiteral || ltype.IsValueType) &&
+ (right is NullLiteral || rtype.IsValueType) &&
+ !(left is NullLiteral && right is NullLiteral) &&
(TypeManager.IsNullableType (ltype) || TypeManager.IsNullableType (rtype)))
return new Nullable.LiftedBinaryOperator (oper, left, right, loc).Resolve (ec);
ig.MarkLabel (false_target);
op.Emit (ec);
ig.MarkLabel (end_target);
+
+ // We release 'left_temp' here since 'op' may refer to it too
+ left_temp.Release (ec);
}
}
}
+ public abstract class VariableReference : Expression, IAssignMethod, IMemoryLocation {
+ bool prepared;
+ LocalTemporary temp;
+
+ public abstract Variable Variable {
+ get;
+ }
+
+ public abstract bool IsRef {
+ get;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ Emit (ec, false);
+ }
+
+ //
+ // This method is used by parameters that are references, that are
+ // being passed as references: we only want to pass the pointer (that
+ // is already stored in the parameter, not the address of the pointer,
+ // and not the value of the variable).
+ //
+ 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);
+
+ EmitLoad (ec);
+
+ if (IsRef) {
+ if (prepared)
+ ec.ig.Emit (OpCodes.Dup);
+
+ //
+ // If we are a reference, we loaded on the stack a pointer
+ // Now lets load the real value
+ //
+ LoadFromPtr (ec.ig, type);
+ }
+
+ if (leave_copy) {
+ ec.ig.Emit (OpCodes.Dup);
+
+ if (IsRef || Variable.NeedsTemporary) {
+ temp = new LocalTemporary (Type);
+ temp.Store (ec);
+ }
+ }
+ }
+
+ public void EmitAssign (EmitContext ec, Expression source, bool leave_copy,
+ bool prepare_for_load)
+ {
+ 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 && Variable.HasInstance)
+ ig.Emit (OpCodes.Dup);
+ else if (IsRef && !prepared)
+ Variable.Emit (ec);
+
+ source.Emit (ec);
+
+ if (leave_copy) {
+ ig.Emit (OpCodes.Dup);
+ if (IsRef || Variable.NeedsTemporary) {
+ temp = new LocalTemporary (Type);
+ temp.Store (ec);
+ }
+ }
+
+ if (IsRef)
+ StoreFromPtr (ig, type);
+ else
+ Variable.EmitAssign (ec);
+
+ if (temp != null) {
+ temp.Emit (ec);
+ temp.Release (ec);
+ }
+ }
+
+ public void AddressOf (EmitContext ec, AddressOp mode)
+ {
+ Variable.EmitInstance (ec);
+ Variable.EmitAddressOf (ec);
+ }
+ }
+
/// <summary>
/// Local variables
/// </summary>
- public class LocalVariableReference : Expression, IAssignMethod, IMemoryLocation, IVariable {
+ public class LocalVariableReference : VariableReference, IVariable {
public readonly string Name;
public readonly Block Block;
public LocalInfo local_info;
bool is_readonly;
- bool prepared;
- LocalTemporary temp;
+ Variable variable;
public LocalVariableReference (Block block, string name, Location l)
{
get { return local_info.VariableInfo; }
}
+ public override bool IsRef {
+ get { return false; }
+ }
+
public bool IsReadOnly {
get { return is_readonly; }
}
if (!VerifyAssigned (ec))
return null;
- if (ec.CurrentAnonymousMethod != null){
- //
- // If we are referencing a variable from the external block
- // flag it for capturing
- //
- if ((local_info.Block.Toplevel != ec.CurrentBlock.Toplevel) ||
- ec.CurrentAnonymousMethod.IsIterator)
- {
- if (local_info.AddressTaken){
- AnonymousMethod.Error_AddressOfCapturedVar (local_info.Name, loc);
- return null;
- }
- ec.CaptureVariable (local_info);
+ //
+ // 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;
}
+
+ ScopeInfo scope = local_info.Block.CreateScopeInfo ();
+ variable = scope.AddLocal (local_info);
+ type = variable.Type;
}
return this;
public override int GetHashCode ()
{
return Name.GetHashCode ();
- }
-
- public override bool Equals (object obj)
- {
- LocalVariableReference lvr = obj as LocalVariableReference;
- if (lvr == null)
- return false;
-
- return Name == lvr.Name && Block == lvr.Block;
- }
-
- public override void Emit (EmitContext ec)
- {
- ILGenerator ig = ec.ig;
-
- if (local_info.FieldBuilder == null){
- //
- // A local variable on the local CLR stack
- //
- ig.Emit (OpCodes.Ldloc, local_info.LocalBuilder);
- } else {
- //
- // A local variable captured by anonymous methods.
- //
- if (!prepared)
- ec.EmitCapturedVariableInstance (local_info);
-
- ig.Emit (OpCodes.Ldfld, local_info.FieldBuilder);
- }
- }
-
- public void Emit (EmitContext ec, bool leave_copy)
- {
- Emit (ec);
- if (leave_copy){
- ec.ig.Emit (OpCodes.Dup);
- if (local_info.FieldBuilder != null){
- temp = new LocalTemporary (Type);
- temp.Store (ec);
- }
- }
- }
-
- public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
- {
- ILGenerator ig = ec.ig;
- prepared = prepare_for_load;
-
- if (local_info.FieldBuilder == null){
- //
- // A local variable on the local CLR stack
- //
- if (local_info.LocalBuilder == null)
- throw new Exception ("This should not happen: both Field and Local are null");
-
- source.Emit (ec);
- if (leave_copy)
- ec.ig.Emit (OpCodes.Dup);
- ig.Emit (OpCodes.Stloc, local_info.LocalBuilder);
- } else {
- //
- // A local variable captured by anonymous methods or itereators.
- //
- ec.EmitCapturedVariableInstance (local_info);
-
- if (prepare_for_load)
- ig.Emit (OpCodes.Dup);
- source.Emit (ec);
- if (leave_copy){
- ig.Emit (OpCodes.Dup);
- temp = new LocalTemporary (Type);
- temp.Store (ec);
- }
- ig.Emit (OpCodes.Stfld, local_info.FieldBuilder);
- if (temp != null)
- temp.Emit (ec);
- }
- }
-
- public void AddressOf (EmitContext ec, AddressOp mode)
+ }
+
+ public override bool Equals (object obj)
{
- ILGenerator ig = ec.ig;
+ LocalVariableReference lvr = obj as LocalVariableReference;
+ if (lvr == null)
+ return false;
- if (local_info.FieldBuilder == null){
- //
- // A local variable on the local CLR stack
- //
- ig.Emit (OpCodes.Ldloca, local_info.LocalBuilder);
- } else {
- //
- // A local variable captured by anonymous methods or iterators
- //
- ec.EmitCapturedVariableInstance (local_info);
- ig.Emit (OpCodes.Ldflda, local_info.FieldBuilder);
- }
+ return Name == lvr.Name && Block == lvr.Block;
+ }
+
+ public override Variable Variable {
+ get { return variable != null ? variable : local_info.Variable; }
}
public override string ToString ()
/// This represents a reference to a parameter in the intermediate
/// representation.
/// </summary>
- public class ParameterReference : Expression, IAssignMethod, IMemoryLocation, IVariable {
+ public class ParameterReference : VariableReference, IVariable {
Parameter par;
string name;
int idx;
Block block;
VariableInfo vi;
- public bool is_ref, is_out, prepared;
+ public bool is_ref, is_out;
public bool IsOut {
get {
}
}
- public bool IsRef {
+ public override bool IsRef {
get {
return is_ref;
}
}
- LocalTemporary temp;
+ public string Name {
+ get {
+ return name;
+ }
+ }
+
+ public Parameter Parameter {
+ get {
+ return par;
+ }
+ }
+
+ Variable variable;
public ParameterReference (Parameter par, Block block, int idx, Location loc)
{
get { return vi; }
}
+ public override Variable Variable {
+ get { return variable != null ? variable : par.Variable; }
+ }
+
public bool VerifyFixed ()
{
// A parameter is fixed if it's a value parameter (i.e., no modifier like out, ref, param).
if (is_out)
vi = block.ParameterMap [idx];
- if (ec.CurrentAnonymousMethod != null){
- if (is_ref && !block.Toplevel.IsLocalParameter (name)){
- Report.Error (1628, Location, "Cannot use ref or out parameter `{0}' inside an anonymous method block",
- par.Name);
- return false;
- }
+ AnonymousContainer am = ec.CurrentAnonymousMethod;
+ if (am == null)
+ return true;
- //
- // If we are referencing the parameter from the external block
- // flag it for capturing
- //
- //Console.WriteLine ("Is parameter `{0}' local? {1}", name, block.IsLocalParameter (name));
- if (!block.Toplevel.IsLocalParameter (name)){
- ec.CaptureParameter (name, type, idx);
+ if (is_ref && !block.Toplevel.IsLocalParameter (name)){
+ Report.Error (1628, Location,
+ "Cannot use ref or out parameter `{0}' inside an " +
+ "anonymous method block", par.Name);
+ return false;
+ }
+
+ if (!am.IsIterator && block.Toplevel.IsLocalParameter (name))
+ return true;
+
+ AnonymousMethodHost host = null;
+ ToplevelBlock toplevel = block.Toplevel;
+ while (toplevel != null) {
+ if (toplevel.IsLocalParameter (name)) {
+ host = toplevel.AnonymousMethodHost;
+ break;
}
+
+ toplevel = toplevel.Container;
}
+ variable = host.AddParameter (par, idx);
+ type = variable.Type;
return true;
}
if (!DoResolveBase (ec))
return null;
- if (is_out && ec.DoFlowAnalysis && (!ec.OmitStructFlowAnalysis || !vi.TypeInfo.IsStruct) && !IsAssigned (ec, loc))
+ if (is_out && ec.DoFlowAnalysis &&
+ (!ec.OmitStructFlowAnalysis || !vi.TypeInfo.IsStruct) && !IsAssigned (ec, loc))
return null;
return this;
ig.Emit (OpCodes.Ldarg, x);
}
- //
- // This method is used by parameters that are references, that are
- // being passed as references: we only want to pass the pointer (that
- // is already stored in the parameter, not the address of the pointer,
- // and not the value of the variable).
- //
- public void EmitLoad (EmitContext ec)
- {
- ILGenerator ig = ec.ig;
- int arg_idx = idx;
-
- if (!ec.MethodIsStatic)
- arg_idx++;
-
- EmitLdArg (ig, arg_idx);
-
- //
- // FIXME: Review for anonymous methods
- //
- }
-
- public override void Emit (EmitContext ec)
- {
- Emit (ec, false);
- }
-
- public void Emit (EmitContext ec, bool leave_copy)
- {
- ILGenerator ig = ec.ig;
- int arg_idx = idx;
-
- if (ec.HaveCaptureInfo && ec.IsParameterCaptured (name)){
- ec.EmitParameter (name, leave_copy, prepared, ref temp);
- return;
- }
-
- if (!ec.MethodIsStatic)
- arg_idx++;
-
- EmitLdArg (ig, arg_idx);
-
- if (is_ref) {
- if (prepared)
- ec.ig.Emit (OpCodes.Dup);
-
- //
- // If we are a reference, we loaded on the stack a pointer
- // Now lets load the real value
- //
- LoadFromPtr (ig, type);
- }
-
- if (leave_copy) {
- ec.ig.Emit (OpCodes.Dup);
-
- if (is_ref) {
- temp = new LocalTemporary (type);
- temp.Store (ec);
- }
- }
- }
-
- public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
- {
- prepared = prepare_for_load;
- if (ec.HaveCaptureInfo && ec.IsParameterCaptured (name)){
- ec.EmitAssignParameter (name, source, leave_copy, prepare_for_load, ref temp);
- return;
- }
-
- ILGenerator ig = ec.ig;
- int arg_idx = idx;
-
-
-
- if (!ec.MethodIsStatic)
- arg_idx++;
-
- if (is_ref && !prepared)
- EmitLdArg (ig, arg_idx);
-
- source.Emit (ec);
-
- if (leave_copy)
- ec.ig.Emit (OpCodes.Dup);
-
- if (is_ref) {
- if (leave_copy) {
- temp = new LocalTemporary (type);
- temp.Store (ec);
- }
-
- StoreFromPtr (ig, type);
-
- if (temp != null)
- temp.Emit (ec);
- } else {
- if (arg_idx <= 255)
- ig.Emit (OpCodes.Starg_S, (byte) arg_idx);
- else
- ig.Emit (OpCodes.Starg, arg_idx);
- }
- }
-
- public void AddressOf (EmitContext ec, AddressOp mode)
- {
- if (ec.HaveCaptureInfo && ec.IsParameterCaptured (name)){
- ec.EmitAddressOfParameter (name);
- return;
- }
-
- int arg_idx = idx;
-
- if (!ec.MethodIsStatic)
- arg_idx++;
-
- if (is_ref){
- if (arg_idx <= 255)
- ec.ig.Emit (OpCodes.Ldarg_S, (byte) arg_idx);
- else
- ec.ig.Emit (OpCodes.Ldarg, arg_idx);
- } else {
- if (arg_idx <= 255)
- ec.ig.Emit (OpCodes.Ldarga_S, (byte) arg_idx);
- else
- ec.ig.Emit (OpCodes.Ldarga, arg_idx);
- }
- }
-
public override string ToString ()
{
return "ParameterReference[" + name + "]";
public bool Resolve (EmitContext ec, Location loc)
{
- bool old_do_flow_analysis = ec.DoFlowAnalysis;
- ec.DoFlowAnalysis = true;
-
- // Verify that the argument is readable
- if (ArgType != AType.Out)
- Expr = Expr.Resolve (ec);
-
- // Verify that the argument is writeable
- if (Expr != null && (ArgType == AType.Out || ArgType == AType.Ref))
- Expr = Expr.ResolveLValue (ec, EmptyExpression.OutAccess, loc);
+ using (ec.With (EmitContext.Flags.DoFlowAnalysis, true)) {
+ // Verify that the argument is readable
+ if (ArgType != AType.Out)
+ Expr = Expr.Resolve (ec);
- ec.DoFlowAnalysis = old_do_flow_analysis;
+ // Verify that the argument is writeable
+ if (Expr != null && (ArgType == AType.Out || ArgType == AType.Ref))
+ Expr = Expr.ResolveLValue (ec, EmptyExpression.OutAccess, loc);
- return Expr != null;
+ return Expr != null;
+ }
}
public void Emit (EmitContext ec)
if (!p.IsGenericParameter && q.IsGenericParameter)
return p;
- if (p.IsGenericType) {
+ if (TypeManager.HasElementType (p)) {
+ Type pe = TypeManager.GetElementType (p);
+ Type qe = TypeManager.GetElementType (q);
+ Type specific = MoreSpecific (pe, qe);
+ if (specific == pe)
+ return p;
+ if (specific == qe)
+ return q;
+ } else if (p.IsGenericType) {
Type[] pargs = TypeManager.GetTypeArguments (p);
Type[] qargs = TypeManager.GetTypeArguments (q);
return p;
if (!p_specific_at_least_once && q_specific_at_least_once)
return q;
- } else if (TypeManager.HasElementType (p)) {
- Type pe = TypeManager.GetElementType (p);
- Type qe = TypeManager.GetElementType (q);
- Type specific = MoreSpecific (pe, qe);
- if (specific == pe)
- return p;
- if (specific == qe)
- return q;
}
return null;
if (this_arg != null)
this_arg.Emit (ec);
- for (int i = 0; i < top; i ++)
+ for (int i = 0; i < top; i ++) {
temps [i].Emit (ec);
+ temps [i].Release (ec);
+ }
}
if (pd != null && pd.Count > top &&
{
eclass = ExprClass.Variable;
type = ec.ContainerType;
+ variable = new SimpleThis (type);
return this;
}
}
/// <summary>
/// Represents the `this' construct
/// </summary>
- public class This : Expression, IAssignMethod, IMemoryLocation, IVariable {
+ public class This : VariableReference, IVariable
+ {
Block block;
VariableInfo variable_info;
-
+ protected Variable variable;
+ bool is_struct;
+
public This (Block block, Location loc)
{
this.loc = loc;
return !TypeManager.IsValueType (Type);
}
+ public override bool IsRef {
+ get { return is_struct; }
+ }
+
+ public override Variable Variable {
+ get { return variable; }
+ }
+
public bool ResolveBase (EmitContext ec)
{
eclass = ExprClass.Variable;
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");
+ Error (26, "Keyword `this' is not valid in a static property, " +
+ "static method, or static field initializer");
return false;
}
- if (block != null && block.Toplevel.ThisVariable != null)
- variable_info = block.Toplevel.ThisVariable.VariableInfo;
+ 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.");
+ return false;
+ }
+
+ AnonymousMethodHost host = block.Toplevel.AnonymousMethodHost;
+ if ((host != null) && (!is_struct || host.IsIterator)) {
+ variable = host.CaptureThis ();
+ type = variable.Type;
+ is_struct = false;
+ }
+ }
- if (ec.CurrentAnonymousMethod != null)
- ec.CaptureThis ();
+ if (variable == null)
+ variable = new SimpleThis (type);
return true;
}
if (!ResolveBase (ec))
return null;
- if ((variable_info != null) && !(type.IsValueType && ec.OmitStructFlowAnalysis) && !variable_info.IsAssigned (ec)) {
- Error (188, "The `this' object cannot be used before all of its fields are assigned to");
+ if ((variable_info != null) && !(type.IsValueType && ec.OmitStructFlowAnalysis) &&
+ !variable_info.IsAssigned (ec)) {
+ Error (188, "The `this' object cannot be used before all of its " +
+ "fields are assigned to");
variable_info.SetAssigned (ec);
return this;
}
return this;
}
-
- public void Emit (EmitContext ec, bool leave_copy)
- {
- Emit (ec);
- if (leave_copy)
- ec.ig.Emit (OpCodes.Dup);
- }
-
- public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
- {
- ILGenerator ig = ec.ig;
-
- if (ec.TypeContainer is Struct){
- ec.EmitThis (false);
- source.Emit (ec);
-
- LocalTemporary t = null;
- if (leave_copy) {
- t = new LocalTemporary (type);
- ec.ig.Emit (OpCodes.Dup);
- t.Store (ec);
- }
-
- ig.Emit (OpCodes.Stobj, type);
-
- if (leave_copy)
- t.Emit (ec);
- } else {
- throw new Exception ("how did you get here");
- }
- }
-
- public override void Emit (EmitContext ec)
- {
- ILGenerator ig = ec.ig;
-
- ec.EmitThis (false);
- if (ec.TypeContainer is Struct)
- ig.Emit (OpCodes.Ldobj, type);
- }
-
public override int GetHashCode()
{
return block.GetHashCode ();
return block == t.block;
}
- public void AddressOf (EmitContext ec, AddressOp mode)
+ protected class SimpleThis : Variable
{
- ec.EmitThis (true);
+ Type type;
- // FIMXE
- // FIGURE OUT WHY LDARG_S does not work
- //
- // consider: struct X { int val; int P { set { val = value; }}}
- //
- // Yes, this looks very bad. Look at `NOTAS' for
- // an explanation.
- // ec.ig.Emit (OpCodes.Ldarga_S, (byte) 0);
+ 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 ();
+ }
+
+ public override void EmitAddressOf (EmitContext ec)
+ {
+ ec.ig.Emit (OpCodes.Ldarg_0);
+ }
}
}
public override bool GetAttributableValue (Type valueType, out object value)
{
+ if (typearg.ContainsGenericParameters) {
+ Report.SymbolRelatedToPreviousError(typearg);
+ Report.Error(416, loc, "`{0}': an attribute argument cannot use type parameters",
+ TypeManager.CSharpName(typearg));
+ value = null;
+ return false;
+ }
+
if (valueType == TypeManager.object_type) {
value = (object)typearg;
return true;
value = typearg;
return true;
}
+
+ public Type TypeArgument
+ {
+ get
+ {
+ return typearg;
+ }
+ }
}
/// <summary>
}
type_queried = texpr.Type;
+ if (type_queried.IsEnum)
+ type_queried = TypeManager.EnumToUnderlying (type_queried);
+
+ if (type_queried == TypeManager.void_type) {
+ Expression.Error_VoidInvalidInTheContext (loc);
+ return null;
+ }
int size_of = GetTypeSize (type_queried);
if (size_of > 0) {
public override Expression DoResolve (EmitContext ec)
{
- bool last_check = ec.CheckState;
- bool last_const_check = ec.ConstantCheckState;
-
- ec.CheckState = true;
- ec.ConstantCheckState = true;
- Expr = Expr.Resolve (ec);
- ec.CheckState = last_check;
- ec.ConstantCheckState = last_const_check;
+ using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
+ Expr = Expr.Resolve (ec);
if (Expr == null)
return null;
public override void Emit (EmitContext ec)
{
- bool last_check = ec.CheckState;
- bool last_const_check = ec.ConstantCheckState;
-
- ec.CheckState = true;
- ec.ConstantCheckState = true;
- Expr.Emit (ec);
- ec.CheckState = last_check;
- ec.ConstantCheckState = last_const_check;
+ using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
+ Expr.Emit (ec);
+ }
+
+ public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
+ {
+ using (ec.With (EmitContext.Flags.AllCheckStateFlags, true))
+ Expr.EmitBranchable (ec, target, onTrue);
}
-
}
/// <summary>
public override Expression DoResolve (EmitContext ec)
{
- bool last_check = ec.CheckState;
- bool last_const_check = ec.ConstantCheckState;
-
- ec.CheckState = false;
- ec.ConstantCheckState = false;
- Expr = Expr.Resolve (ec);
- ec.CheckState = last_check;
- ec.ConstantCheckState = last_const_check;
+ using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
+ Expr = Expr.Resolve (ec);
if (Expr == null)
return null;
public override void Emit (EmitContext ec)
{
- bool last_check = ec.CheckState;
- bool last_const_check = ec.ConstantCheckState;
-
- ec.CheckState = false;
- ec.ConstantCheckState = false;
- Expr.Emit (ec);
- ec.CheckState = last_check;
- ec.ConstantCheckState = last_const_check;
+ using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
+ Expr.Emit (ec);
}
+ public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
+ {
+ using (ec.With (EmitContext.Flags.AllCheckStateFlags, false))
+ Expr.EmitBranchable (ec, target, onTrue);
+ }
}
/// <summary>
}
StoreFromPtr (ec.ig, t);
- if (temp != null)
+ if (temp != null) {
temp.Emit (ec);
+ temp.Release (ec);
+ }
return;
}
ig.Emit (OpCodes.Call, set);
}
- if (temp != null)
+ if (temp != null) {
temp.Emit (ec);
+ temp.Release (ec);
+ }
}
public void AddressOf (EmitContext ec, AddressOp mode)
public override Expression DoResolve (EmitContext ec)
{
- ArrayList AllGetters = new ArrayList();
if (!CommonResolve (ec))
return null;
//
// This is a group of properties, piles of them.
- bool found_any = false, found_any_getters = false;
- Type lookup_type = indexer_type;
+ ArrayList AllGetters = null;
- Indexers ilist = Indexers.GetIndexersForType (current_type, lookup_type);
+ Indexers ilist = Indexers.GetIndexersForType (current_type, indexer_type);
if (ilist.Properties != null) {
- found_any = true;
+ AllGetters = new ArrayList(ilist.Properties.Count);
foreach (Indexers.Indexer ix in ilist.Properties) {
if (ix.Getter != null)
AllGetters.Add (ix.Getter);
}
}
- if (AllGetters.Count > 0) {
- found_any_getters = true;
- get = (MethodInfo) Invocation.OverloadResolve (
- ec, new MethodGroupExpr (AllGetters, loc),
- arguments, false, loc);
- }
-
- if (!found_any) {
+ if (AllGetters == null) {
Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
- TypeManager.CSharpName (indexer_type));
+ TypeManager.CSharpName (indexer_type));
return null;
}
- if (!found_any_getters) {
+ if (AllGetters.Count == 0) {
+ // FIXME: we cannot simply select first one as the error message is missleading when
+ // multiple indexers exist
+ Indexers.Indexer first_indexer = (Indexers.Indexer)ilist.Properties[ilist.Properties.Count - 1];
Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks the `get' accessor",
- "XXXXXXXX");
+ TypeManager.GetFullNameSignature (first_indexer.PropertyInfo));
return null;
}
+ get = (MethodInfo)Invocation.OverloadResolve (ec, new MethodGroupExpr (AllGetters, loc),
+ arguments, false, loc);
+
if (get == null) {
Invocation.Error_WrongNumArguments (loc, "this", arguments.Count);
return null;
Invocation.EmitCall (ec, is_base_indexer, false, instance_expr, set, set_arguments, loc, false, prepared);
- if (temp != null)
+ if (temp != null) {
temp.Emit (ec);
+ temp.Release (ec);
+ }
}
Type ltype = lexpr.Type;
if ((ltype == TypeManager.void_type) && (dim != "*")) {
- Report.Error (1547, Location,
- "Keyword 'void' cannot be used in this context");
+ Error_VoidInvalidInTheContext (loc);
return null;
}