(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)){
//
Type l = left.Type;
Type r = right.Type;
- bool overload_failed = false;
-
//
// Special cases: string comapred to null
//
if (oper == Operator.Equality || oper == Operator.Inequality){
- if ((l == TypeManager.string_type && (right is NullLiteral)) ||
- (r == TypeManager.string_type && (left is NullLiteral))){
+ if ((!TypeManager.IsValueType (l) && (right is NullLiteral)) ||
+ (!TypeManager.IsValueType (r) && (left is NullLiteral))) {
Type = TypeManager.bool_type;
return this;
MethodInfo mi = (MethodInfo) method;
return new BinaryMethod (mi.ReturnType, method, args);
- } else {
- overload_failed = true;
}
}
}
if (r == l)
return new PointerArithmetic (
false, left, right, TypeManager.int64_type,
- loc);
+ loc).Resolve (ec);
} else {
Expression t = Make32or64 (ec, right);
if (t != null)
- return new PointerArithmetic (oper == Operator.Addition, left, t, l, loc);
+ return new PointerArithmetic (oper == Operator.Addition, left, t, l, loc).Resolve (ec);
}
} else if (r.IsPointer && oper == Operator.Addition){
Expression t = Make32or64 (ec, left);
if (t != null)
- return new PointerArithmetic (true, right, t, r, loc);
+ return new PointerArithmetic (true, right, t, r, loc).Resolve (ec);
}
}
}
}
- //
- // We are dealing with numbers
- //
- if (overload_failed){
- Error_OperatorCannotBeApplied ();
- return null;
- }
-
//
// This will leave left or right set to null if there is an error
//
public class StringConcat : Expression {
ArrayList operands;
bool invalid = false;
-
+ bool emit_conv_done = false;
+ //
+ // Are we also concating objects?
+ //
+ bool is_strings_only = true;
public StringConcat (EmitContext ec, Location loc, Expression left, Expression right)
{
{
MethodInfo concat_method = null;
- //
- // Are we also concating objects?
- //
- bool is_strings_only = true;
-
//
// Do conversion to arguments; check for strings only
//
- for (int i = 0; i < operands.Count; i ++) {
- Expression e = (Expression) operands [i];
- is_strings_only &= e.Type == TypeManager.string_type;
- }
- for (int i = 0; i < operands.Count; i ++) {
- Expression e = (Expression) operands [i];
+ // This can get called multiple times, so we have to deal with that.
+ if (!emit_conv_done) {
+ emit_conv_done = true;
+ for (int i = 0; i < operands.Count; i ++) {
+ Expression e = (Expression) operands [i];
+ is_strings_only &= e.Type == TypeManager.string_type;
+ }
- if (! is_strings_only && e.Type == TypeManager.string_type) {
- // need to make sure this is an object, because the EmitParams
- // method might look at the type of this expression, see it is a
- // string and emit a string [] when we want an object [];
+ for (int i = 0; i < operands.Count; i ++) {
+ Expression e = (Expression) operands [i];
- e = Convert.ImplicitConversion (ec, e, TypeManager.object_type, loc);
+ if (! is_strings_only && e.Type == TypeManager.string_type) {
+ // need to make sure this is an object, because the EmitParams
+ // method might look at the type of this expression, see it is a
+ // string and emit a string [] when we want an object [];
+
+ e = new EmptyCast (e, TypeManager.object_type);
+ }
+ operands [i] = new Argument (e, Argument.AType.Expression);
}
- operands [i] = new Argument (e, Argument.AType.Expression);
}
//
public PointerArithmetic (bool is_addition, Expression l, Expression r, Type t, Location loc)
{
type = t;
- eclass = ExprClass.Variable;
this.loc = loc;
left = l;
right = r;
public override Expression DoResolve (EmitContext ec)
{
- //
- // We are born fully resolved
- //
+ eclass = ExprClass.Variable;
+
+ if (left.Type == TypeManager.void_ptr_type) {
+ Error (242, "The operation in question is undefined on void pointers");
+ return null;
+ }
+
return this;
}
{
Type op_type = left.Type;
ILGenerator ig = ec.ig;
- int size = GetTypeSize (TypeManager.GetElementType (op_type));
+ Type element = TypeManager.GetElementType (op_type);
+ int size = GetTypeSize (element);
Type rtype = right.Type;
if (rtype.IsPointer){
if (size != 1){
if (size == 0)
- ig.Emit (OpCodes.Sizeof, op_type);
+ ig.Emit (OpCodes.Sizeof, element);
else
IntLiteral.EmitInt (ig, size);
ig.Emit (OpCodes.Div);
right.Emit (ec);
if (size != 1){
if (size == 0)
- ig.Emit (OpCodes.Sizeof, op_type);
+ ig.Emit (OpCodes.Sizeof, element);
else
IntLiteral.EmitInt (ig, size);
if (rtype == TypeManager.int64_type)
else if (rtype == TypeManager.uint64_type)
ig.Emit (OpCodes.Conv_U8);
ig.Emit (OpCodes.Mul);
- ig.Emit (OpCodes.Conv_I);
}
+
+ if (rtype == TypeManager.int64_type || rtype == TypeManager.uint64_type)
+ ig.Emit (OpCodes.Conv_I);
+
if (is_add)
ig.Emit (OpCodes.Add);
else
if (e != null) {
local_info.Used = true;
eclass = ExprClass.Value;
- return e;
+ return e.Resolve (ec);
}
VariableInfo variable_info = local_info.VariableInfo;
public enum AType : byte {
Expression,
Ref,
- Out
+ Out,
+ ArgList
};
public readonly AType ArgType;
public static string FullDesc (Argument a)
{
+ if (a.ArgType == AType.ArgList)
+ return "__arglist";
+
return (a.ArgType == AType.Ref ? "ref " :
(a.ArgType == AType.Out ? "out " : "")) +
TypeManager.CSharpName (a.Expr.Type);
return (ParameterData) ip;
} else {
- ParameterInfo [] pi = mb.GetParameters ();
- ReflectionParameters rp = new ReflectionParameters (pi);
+ ReflectionParameters rp = new ReflectionParameters (mb);
method_parameter_cache [mb] = rp;
return (ParameterData) rp;
if (argument_type == q)
return 0;
- //
- // Now probe whether an implicit constant expression conversion
- // can be used.
- //
- // An implicit constant expression conversion permits the following
- // conversions:
- //
- // * A constant-expression of type `int' can be converted to type
- // sbyte, byute, short, ushort, uint, ulong provided the value of
- // of the expression is withing the range of the destination type.
- //
- // * A constant-expression of type long can be converted to type
- // ulong, provided the value of the constant expression is not negative
- //
- // FIXME: Note that this assumes that constant folding has
- // taken place. We dont do constant folding yet.
- //
-
- if (argument_expr is IntConstant){
- IntConstant ei = (IntConstant) argument_expr;
- int value = ei.Value;
-
- if (p == TypeManager.sbyte_type){
- if (value >= SByte.MinValue && value <= SByte.MaxValue)
- return 1;
- } else if (p == TypeManager.byte_type){
- if (q == TypeManager.sbyte_type &&
- value >= SByte.MinValue && value <= SByte.MaxValue)
- return 0;
- else if (Byte.MinValue >= 0 && value <= Byte.MaxValue)
- return 1;
- } else if (p == TypeManager.short_type){
- if (value >= Int16.MinValue && value <= Int16.MaxValue)
- return 1;
- } else if (p == TypeManager.ushort_type){
- if (q == TypeManager.short_type &&
- value >= Int16.MinValue && value <= Int16.MaxValue)
- return 0;
- else if (value >= UInt16.MinValue && value <= UInt16.MaxValue)
- return 1;
- } else if (p == TypeManager.int32_type){
- if (value >= Int32.MinValue && value <= Int32.MaxValue)
- return 1;
- } else if (p == TypeManager.uint32_type){
- //
- // we can optimize this case: a positive int32
- // always fits on a uint32
- //
- if (value >= 0)
- return 1;
- } else if (p == TypeManager.uint64_type){
- //
- // we can optimize this case: a positive int32
- // always fits on a uint64
- //
-
- //
- // This special case is needed because csc behaves like this.
- // int -> uint is better than int -> ulong!
- //
- if (q == TypeManager.uint32_type)
- return 0;
-
- if (q == TypeManager.int64_type)
- return 0;
- else if (value >= 0)
- return 1;
- } else if (p == TypeManager.int64_type){
- return 1;
- }
- } else if (argument_type == TypeManager.int64_type && argument_expr is LongConstant){
- LongConstant lc = (LongConstant) argument_expr;
-
- if (p == TypeManager.uint64_type){
- if (lc.Value > 0)
- return 1;
- }
- }
-
if (q == null) {
Expression tmp = Convert.ImplicitConversion (ec, argument_expr, p, loc);
if (cand_count == 0 && argument_count == 0)
return best == null || best_params ? 1 : 0;
- if (candidate_pd.ParameterModifier (cand_count - 1) != Parameter.Modifier.PARAMS)
+ if ((candidate_pd.ParameterModifier (cand_count - 1) != Parameter.Modifier.PARAMS) &&
+ (candidate_pd.ParameterModifier (cand_count - 1) != Parameter.Modifier.ARGLIST))
if (cand_count != argument_count)
return 0;
/// Determines if the candidate method, if a params method, is applicable
/// in its expanded form to the given set of arguments
/// </summary>
- static bool IsParamsMethodApplicable (EmitContext ec, ArrayList arguments, MethodBase candidate)
+ static bool IsParamsMethodApplicable (EmitContext ec, ArrayList arguments,
+ MethodBase candidate, bool do_varargs)
{
int arg_count;
arg_count = arguments.Count;
ParameterData pd = GetParameterData (candidate);
-
- int pd_count = pd.Count;
+ int pd_count = pd.Count;
if (pd_count == 0)
return false;
+
+ int count = pd_count - 1;
+ if (do_varargs) {
+ if (pd.ParameterModifier (count) != Parameter.Modifier.ARGLIST)
+ return false;
+ if (pd_count != arg_count)
+ return false;
+ } else {
+ if (pd.ParameterModifier (count) != Parameter.Modifier.PARAMS)
+ return false;
+ }
- if (pd.ParameterModifier (pd_count - 1) != Parameter.Modifier.PARAMS)
- return false;
-
- if (pd_count - 1 > arg_count)
+ if (count > arg_count)
return false;
if (pd_count == 1 && arg_count == 0)
// remains is when the number of parameters is
// less than or equal to the argument count.
//
- for (int i = 0; i < pd_count - 1; ++i) {
+ for (int i = 0; i < count; ++i) {
Argument a = (Argument) arguments [i];
}
+ if (do_varargs) {
+ Argument a = (Argument) arguments [count];
+ if (!(a.Expr is Arglist))
+ return false;
+
+ return true;
+ }
+
Type element_type = TypeManager.GetElementType (pd.ParameterType (pd_count - 1));
for (int i = pd_count - 1; i < arg_count; i++) {
Argument a = (Argument) arguments [i];
-
+
if (!Convert.ImplicitConversionExists (ec, a.Expr, element_type))
return false;
}
candidates.Add (candidate);
applicable_type = candidate.DeclaringType;
found_applicable = true;
- } else if (IsParamsMethodApplicable (ec, Arguments, candidate)) {
+ } else if (IsParamsMethodApplicable (ec, Arguments, candidate, false)) {
+ if (candidate_to_form == null)
+ candidate_to_form = new PtrHashtable ();
+
+ // Candidate is applicable in expanded form
+ candidates.Add (candidate);
+ applicable_type = candidate.DeclaringType;
+ found_applicable = true;
+ candidate_to_form [candidate] = candidate;
+ } else if (IsParamsMethodApplicable (ec, Arguments, candidate, true)) {
if (candidate_to_form == null)
candidate_to_form = new PtrHashtable ();
{
ParameterData pd = GetParameterData (method);
int pd_count = pd.Count;
-
+
for (int j = 0; j < argument_count; j++) {
Argument a = (Argument) Arguments [j];
Expression a_expr = a.Expr;
if (chose_params_expanded)
parameter_type = TypeManager.GetElementType (parameter_type);
+ } else if (pm == Parameter.Modifier.ARGLIST){
+ continue;
} else {
//
// Check modifiers
if (TypeManager.IsSpecialMethod (method))
Report.Error (571, loc, method.Name + ": can not call operator or accessor");
}
-
+
eclass = ExprClass.Value;
return this;
}
}
}
+ static Type[] GetVarargsTypes (EmitContext ec, MethodBase mb,
+ ArrayList arguments)
+ {
+ ParameterData pd = GetParameterData (mb);
+
+ if (arguments == null)
+ return new Type [0];
+
+ Argument a = (Argument) arguments [pd.Count - 1];
+ Arglist list = (Arglist) a.Expr;
+
+ return list.ArgumentTypes;
+ }
+
/// <summary>
/// This checks the ConditionalAttribute on the method
/// </summary>
}
EmitArguments (ec, method, Arguments);
+
+ OpCode call_op;
+ if (is_static || struct_call || is_base || (this_call && !method.IsVirtual))
+ call_op = OpCodes.Call;
+ else
+ call_op = OpCodes.Callvirt;
+
+ if ((method.CallingConvention & CallingConventions.VarArgs) != 0) {
+ Type[] varargs_types = GetVarargsTypes (ec, method, Arguments);
+ ig.EmitCall (call_op, (MethodInfo) method, varargs_types);
+ return;
+ }
+
//
// If you have:
// this.DoFoo ();
// and DoFoo is not virtual, you can omit the callvirt,
// because you don't need the null checking behavior.
//
- if (is_static || struct_call || is_base || (this_call && !method.IsVirtual)){
- if (method is MethodInfo) {
- ig.Emit (OpCodes.Call, (MethodInfo) method);
- } else
- ig.Emit (OpCodes.Call, (ConstructorInfo) method);
- } else {
- if (method is MethodInfo)
- ig.Emit (OpCodes.Callvirt, (MethodInfo) method);
- else
- ig.Emit (OpCodes.Callvirt, (ConstructorInfo) method);
- }
+ if (method is MethodInfo)
+ ig.Emit (call_op, (MethodInfo) method);
+ else
+ ig.Emit (call_op, (ConstructorInfo) method);
}
public override void Emit (EmitContext ec)
Expression tmp = (Expression) o;
tmp = tmp.Resolve (ec);
if (tmp == null)
- continue;
+ return false;
// Console.WriteLine ("I got: " + tmp);
// Handle initialization from vars, fields etc.
if (type == null)
return false;
-
- underlying_type = type;
- if (underlying_type.IsArray)
- underlying_type = TypeManager.GetElementType (underlying_type);
+
+ if (!type.IsArray) {
+ Error (622, "Can only use array initializer expressions to assign to array types. Try using a new expression instead.");
+ return false;
+ }
+ underlying_type = TypeManager.GetElementType (type);
dimensions = type.GetArrayRank ();
return true;
}
}
+ /// <summary>
+ /// Represents the `__arglist' construct
+ /// </summary>
+ public class ArglistAccess : Expression
+ {
+ public ArglistAccess (Location loc)
+ {
+ this.loc = loc;
+ }
+
+ public bool ResolveBase (EmitContext ec)
+ {
+ eclass = ExprClass.Variable;
+ type = TypeManager.runtime_argument_handle_type;
+ return true;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ if (!ResolveBase (ec))
+ return null;
+
+ if (ec.IsFieldInitializer || !ec.CurrentBlock.HasVarargs) {
+ Error (190, "The __arglist construct is valid only within " +
+ "a variable argument method.");
+ return null;
+ }
+
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ ec.ig.Emit (OpCodes.Arglist);
+ }
+ }
+
+ /// <summary>
+ /// Represents the `__arglist (....)' construct
+ /// </summary>
+ public class Arglist : Expression
+ {
+ public readonly Argument[] Arguments;
+
+ public Arglist (Argument[] args, Location l)
+ {
+ Arguments = args;
+ loc = l;
+ }
+
+ public Type[] ArgumentTypes {
+ get {
+ Type[] retval = new Type [Arguments.Length];
+ for (int i = 0; i < Arguments.Length; i++)
+ retval [i] = Arguments [i].Type;
+ return retval;
+ }
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ eclass = ExprClass.Variable;
+ type = TypeManager.runtime_argument_handle_type;
+
+ foreach (Argument arg in Arguments) {
+ if (!arg.Resolve (ec, loc))
+ return null;
+ }
+
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ foreach (Argument arg in Arguments)
+ arg.Emit (ec);
+ }
+ }
+
//
// This produces the value that renders an instance, used by the iterators code
//
return null;
}
+ if (typearg.IsPointer && !ec.InUnsafe){
+ UnsafeError (loc);
+ return null;
+ }
CheckObsoleteAttribute (typearg);
type = TypeManager.type_type;
"type name instead");
}
- static bool IdenticalNameAndTypeName (EmitContext ec, Expression left_original, Expression left, Location loc)
+ public static bool IdenticalNameAndTypeName (EmitContext ec, Expression left_original, Expression left, Location loc)
{
SimpleName sn = left_original as SimpleName;
if (sn == null || left == null || left.Type.Name != sn.Name)
//
Expression original = expr;
- expr = expr.Resolve (ec, flags | ResolveFlags.DisableFlowAnalysis);
+ expr = expr.Resolve (ec, flags | ResolveFlags.Intermediate | ResolveFlags.DisableFlowAnalysis);
if (expr == null)
return null;
return true;
}
- Expression MakePointerAccess ()
+ Expression MakePointerAccess (EmitContext ec)
{
Type t = Expr.Type;
}
Expression p;
- p = new PointerArithmetic (true, Expr, ((Argument)Arguments [0]).Expr, t, loc);
- return new Indirection (p, loc);
+ p = new PointerArithmetic (true, Expr, ((Argument)Arguments [0]).Expr, t, loc).Resolve (ec);
+ if (p == null)
+ return null;
+ return new Indirection (p, loc).Resolve (ec);
}
public override Expression DoResolve (EmitContext ec)
if (t.IsArray)
return (new ArrayAccess (this, loc)).Resolve (ec);
else if (t.IsPointer)
- return MakePointerAccess ();
+ return MakePointerAccess (ec);
else
return (new IndexerAccess (this, loc)).Resolve (ec);
}
if (t.IsArray)
return (new ArrayAccess (this, loc)).ResolveLValue (ec, right_side);
else if (t.IsPointer)
- return MakePointerAccess ();
+ return MakePointerAccess (ec);
else
return (new IndexerAccess (this, loc)).ResolveLValue (ec, right_side);
}
//Console.WriteLine (new System.Diagnostics.StackTrace ());
is_stobj = false;
t = TypeManager.TypeToCoreType (t);
- if (TypeManager.IsEnumType (t) && t != TypeManager.enum_type)
+ if (TypeManager.IsEnumType (t))
t = TypeManager.EnumToUnderlying (t);
if (t == TypeManager.byte_type || t == TypeManager.sbyte_type ||
t == TypeManager.bool_type)
pe.IsBase = true;
}
+
+ if (e is MethodGroupExpr)
+ ((MethodGroupExpr) e).IsBase = true;
return e;
}
return null;
}
+ Constant c = count as Constant;
+ // TODO: because we don't have property IsNegative
+ if (c != null && c.ConvertToUInt () == null) {
+ // "Cannot use a negative size with stackalloc"
+ Report.Error_T (247, loc);
+ return null;
+ }
+
if (ec.CurrentBranching.InCatch () ||
ec.CurrentBranching.InFinally (true)) {
Error (255,