// Author:
// Miguel de Icaza (miguel@ximian.com)
//
-// (C) 2001 Ximian, Inc.
-//
+// (C) 2001, 2002, 2003 Ximian, Inc.
+// (C) 2003, 2004 Novell, Inc.
//
#define USE_OLD
return null;
args.Add (a);
- method = Invocation.OverloadResolve (ec, (MethodGroupExpr) mg, args, loc);
+ method = Invocation.OverloadResolve (
+ ec, (MethodGroupExpr) mg, args, false, loc);
if (method == null)
return null;
return null;
}
+ if (ec.InFixedInitializer && ((variable != null) && variable.VerifyFixed (false))) {
+ Error (213, "You can not fix an already fixed expression");
+ return null;
+ }
+
// According to the specs, a variable is considered definitely assigned if you take
// its address.
if ((variable != null) && (variable.VariableInfo != null))
}
}
- /// <summary>
- /// This will emit the child expression for `ec' avoiding the logical
- /// not. The parent will take care of changing brfalse/brtrue
- /// </summary>
- public void EmitLogicalNot (EmitContext ec)
+ public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
{
- if (Oper != Operator.LogicalNot)
- throw new Exception ("EmitLogicalNot can only be called with !expr");
-
- Expr.Emit (ec);
+ if (Oper == Operator.LogicalNot)
+ Expr.EmitBranchable (ec, target, !onTrue);
+ else
+ base.EmitBranchable (ec, target, onTrue);
}
public override string ToString ()
ILGenerator ig = ec.ig;
if (temporary != null){
- if (have_temporary){
+ if (have_temporary) {
temporary.Emit (ec);
- return;
- }
+ } else {
expr.Emit (ec);
ec.ig.Emit (OpCodes.Dup);
temporary.Store (ec);
have_temporary = true;
+ }
} else
expr.Emit (ec);
ia.CacheTemporaries (ec);
+ //
+ // NOTE: We should probably handle three cases:
+ //
+ // * method invocation required.
+ // * direct stack manipulation possible
+ // * the object requires an "instance" field
+ //
if (temp_storage == null){
//
// Temporary improvement: if we are dealing with something that does
ia.EmitAssign (ec, temp_storage);
break;
}
+
+ temp_storage.Release (ec);
}
public override void Emit (EmitContext ec)
throw new Exception ("never reached");
}
+ public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
+ {
+ ILGenerator ig = ec.ig;
+
+ switch (action){
+ case Action.AlwaysFalse:
+ if (! onTrue)
+ ig.Emit (OpCodes.Br, target);
+
+ return;
+ case Action.AlwaysTrue:
+ if (onTrue)
+ ig.Emit (OpCodes.Br, target);
+
+ return;
+ case Action.LeaveOnStack:
+ // the `e != null' rule.
+ expr.Emit (ec);
+ ig.Emit (onTrue ? OpCodes.Brtrue : OpCodes.Brfalse, target);
+ return;
+ case Action.Probe:
+ expr.Emit (ec);
+ ig.Emit (OpCodes.Isinst, probe_type);
+ ig.Emit (onTrue ? OpCodes.Brtrue : OpCodes.Brfalse, target);
+ return;
+ }
+ throw new Exception ("never reached");
+ }
+
public override Expression DoResolve (EmitContext ec)
{
Expression e = base.DoResolve (ec);
Error_OperatorCannotBeApplied (loc, OperName (oper), left.Type, right.Type);
}
- static bool is_32_or_64 (Type t)
- {
- return (t == TypeManager.int32_type || t == TypeManager.uint32_type ||
- t == TypeManager.int64_type || t == TypeManager.uint64_type);
- }
-
static bool is_unsigned (Type t)
{
return (t == TypeManager.uint32_type || t == TypeManager.uint64_type ||
else
return false;
}
+
+ Expression Make32or64 (EmitContext ec, Expression e)
+ {
+ Type t= e.Type;
+
+ if (t == TypeManager.int32_type || t == TypeManager.uint32_type ||
+ t == TypeManager.int64_type || t == TypeManager.uint64_type)
+ return e;
+ Expression ee = Convert.ImplicitConversion (ec, e, TypeManager.int32_type, loc);
+ if (ee != null)
+ return ee;
+ ee = Convert.ImplicitConversion (ec, e, TypeManager.uint32_type, loc);
+ if (ee != null)
+ return ee;
+ ee = Convert.ImplicitConversion (ec, e, TypeManager.int64_type, loc);
+ if (ee != null)
+ return ee;
+ ee = Convert.ImplicitConversion (ec, e, TypeManager.uint64_type, loc);
+ if (ee != null)
+ return ee;
+ return null;
+ }
Expression CheckShiftArguments (EmitContext ec)
{
bool overload_failed = false;
//
- // Special cases: string comapred to null
+ // Special cases: string or type parameter comapred to null
//
if (oper == Operator.Equality || oper == Operator.Inequality){
if ((l == TypeManager.string_type && (right is NullLiteral)) ||
return this;
}
+
+ if (l.IsGenericParameter && (right is NullLiteral)) {
+ if (l.BaseType == TypeManager.value_type) {
+ Error_OperatorCannotBeApplied ();
+ return null;
+ }
+
+ left = new BoxedCast (left);
+ Type = TypeManager.bool_type;
+ return this;
+ }
+
+ if (r.IsGenericParameter && (left is NullLiteral)) {
+ if (r.BaseType == TypeManager.value_type) {
+ Error_OperatorCannotBeApplied ();
+ return null;
+ }
+
+ right = new BoxedCast (right);
+ Type = TypeManager.bool_type;
+ return this;
+ }
}
//
args.Add (new Argument (left, Argument.AType.Expression));
args.Add (new Argument (right, Argument.AType.Expression));
- MethodBase method = Invocation.OverloadResolve (ec, union, args, Location.Null);
+ MethodBase method = Invocation.OverloadResolve (
+ ec, union, args, true, Location.Null);
+
if (method != null) {
MethodInfo mi = (MethodInfo) method;
}
}
- //
- // Step 2: Default operations on CLI native types.
- //
-
//
// Step 0: String concatenation (because overloading will get this wrong)
//
// If any of the arguments is a string, cast to string
//
- if (l == TypeManager.string_type){
- MethodBase method;
-
- if (r == TypeManager.void_type) {
- Error_OperatorCannotBeApplied ();
- return null;
- }
-
- if (r == TypeManager.string_type){
- if (left is Constant && right is Constant){
- StringConstant ls = (StringConstant) left;
- StringConstant rs = (StringConstant) right;
-
- return new StringConstant (
- ls.Value + rs.Value);
- }
-
- if (left is BinaryMethod){
- BinaryMethod b = (BinaryMethod) left;
-
- //
- // Call String.Concat (string, string, string) or
- // String.Concat (string, string, string, string)
- // if possible.
- //
- if (b.method == TypeManager.string_concat_string_string ||
- b.method == TypeManager.string_concat_string_string_string){
- int count = b.Arguments.Count;
-
- if (count == 2){
- ArrayList bargs = new ArrayList (3);
- bargs.AddRange (b.Arguments);
- bargs.Add (new Argument (right, Argument.AType.Expression));
- return new BinaryMethod (
- TypeManager.string_type,
- TypeManager.string_concat_string_string_string, bargs);
- } else if (count == 3){
- ArrayList bargs = new ArrayList (4);
- bargs.AddRange (b.Arguments);
- bargs.Add (new Argument (right, Argument.AType.Expression));
- return new BinaryMethod (
- TypeManager.string_type,
- TypeManager.string_concat_string_string_string_string, bargs);
- }
- }
- }
-
- // string + string
- method = TypeManager.string_concat_string_string;
- } else {
- // string + object
- method = TypeManager.string_concat_object_object;
- right = Convert.ImplicitConversion (
- ec, right, TypeManager.object_type, loc);
- if (right == null){
- Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
- return null;
- }
- }
-
- //
- // Cascading concats will hold up to 2 arguments, any extras will be
- // reallocated above.
- //
- ArrayList args = new ArrayList (2);
- args.Add (new Argument (left, Argument.AType.Expression));
- args.Add (new Argument (right, Argument.AType.Expression));
+ // Simple constant folding
+ if (left is StringConstant && right is StringConstant)
+ return new StringConstant (((StringConstant) left).Value + ((StringConstant) right).Value);
- return new BinaryMethod (TypeManager.string_type, method, args);
- } else if (r == TypeManager.string_type){
- // object + string
+ if (l == TypeManager.string_type || r == TypeManager.string_type) {
- if (l == TypeManager.void_type) {
+ if (r == TypeManager.void_type || l == TypeManager.void_type) {
Error_OperatorCannotBeApplied ();
return null;
}
- left = Convert.ImplicitConversion (ec, left, TypeManager.object_type, loc);
- if (left == null){
- Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
- return null;
+ // try to fold it in on the left
+ if (left is StringConcat) {
+
+ //
+ // We have to test here for not-null, since we can be doubly-resolved
+ // take care of not appending twice
+ //
+ if (type == null){
+ type = TypeManager.string_type;
+ ((StringConcat) left).Append (ec, right);
+ return left.Resolve (ec);
+ } else {
+ return left;
+ }
}
- ArrayList args = new ArrayList (2);
- args.Add (new Argument (left, Argument.AType.Expression));
- args.Add (new Argument (right, Argument.AType.Expression));
- return new BinaryMethod (TypeManager.string_type, TypeManager.string_concat_object_object, args);
+ // Otherwise, start a new concat expression
+ return new StringConcat (ec, loc, left, right).Resolve (ec);
}
//
// +, -, *, /, %, &, |, ^, ==, !=, <, >, <=, >=
//
if (oper == Operator.Addition || oper == Operator.Subtraction) {
- if (l.IsSubclassOf (TypeManager.delegate_type) &&
- r.IsSubclassOf (TypeManager.delegate_type)) {
+ if (TypeManager.IsDelegateType (l)){
+ if (right.eclass == ExprClass.MethodGroup && RootContext.V2){
+ Expression tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
+ if (tmp == null)
+ return null;
+ right = tmp;
+ r = right.Type;
+ }
+
+ if (TypeManager.IsDelegateType (r)){
MethodInfo method;
ArrayList args = new ArrayList (2);
return new BinaryDelegate (l, method, args);
}
+ }
//
// Pointer arithmetic:
return new PointerArithmetic (
false, left, right, TypeManager.int64_type,
loc);
- } else if (is_32_or_64 (r))
- return new PointerArithmetic (
- oper == Operator.Addition, left, right, l, loc);
- } else if (r.IsPointer && is_32_or_64 (l) && oper == Operator.Addition)
- return new PointerArithmetic (
- true, right, left, r, loc);
+ } else {
+ Expression t = Make32or64 (ec, right);
+ if (t != null)
+ return new PointerArithmetic (oper == Operator.Addition, left, t, l, loc);
+ }
+ } else if (r.IsPointer && oper == Operator.Addition){
+ Expression t = Make32or64 (ec, left);
+ if (t != null)
+ return new PointerArithmetic (true, right, t, r, loc);
+ }
}
//
Expression temp;
// U operator - (E e, E f)
- if (lie && rie && oper == Operator.Subtraction){
+ if (lie && rie){
+ if (oper == Operator.Subtraction){
if (l == r){
type = TypeManager.EnumToUnderlying (l);
return this;
Error_OperatorCannotBeApplied ();
return null;
}
+ }
//
// operator + (E e, U x)
Type enum_type = lie ? l : r;
Type other_type = lie ? r : l;
Type underlying_type = TypeManager.EnumToUnderlying (enum_type);
-;
if (underlying_type != other_type){
+ temp = Convert.ImplicitConversion (ec, lie ? right : left, underlying_type, loc);
+ if (temp != null){
+ if (lie)
+ right = temp;
+ else
+ left = temp;
+ type = enum_type;
+ return this;
+ }
+
Error_OperatorCannotBeApplied ();
return null;
}
/// The expression's code is generated, and we will generate a branch to `target'
/// if the resulting expression value is equal to isTrue
/// </remarks>
- public bool EmitBranchable (EmitContext ec, Label target, bool onTrue)
+ public override void EmitBranchable (EmitContext ec, Label target, bool onTrue)
{
ILGenerator ig = ec.ig;
// but on top of that we want for == and != to use a special path
// if we are comparing against null
//
- if (oper == Operator.Equality || oper == Operator.Inequality){
+ if ((oper == Operator.Equality || oper == Operator.Inequality) && (left is Constant || right is Constant)) {
bool my_on_true = oper == Operator.Inequality ? onTrue : !onTrue;
- if (left is NullLiteral){
- right.Emit (ec);
- if (my_on_true)
- ig.Emit (OpCodes.Brtrue, target);
- else
- ig.Emit (OpCodes.Brfalse, target);
- return true;
- } else if (right is NullLiteral){
+ //
+ // put the constant on the rhs, for simplicity
+ //
+ if (left is Constant) {
+ Expression swap = right;
+ right = left;
+ left = swap;
+ }
+
+ if (((Constant) right).IsZeroInteger) {
left.Emit (ec);
if (my_on_true)
ig.Emit (OpCodes.Brtrue, target);
else
ig.Emit (OpCodes.Brfalse, target);
- return true;
- } else if (left is BoolConstant){
- right.Emit (ec);
- if (my_on_true != ((BoolConstant) left).Value)
- ig.Emit (OpCodes.Brtrue, target);
- else
- ig.Emit (OpCodes.Brfalse, target);
- return true;
+
+ return;
} else if (right is BoolConstant){
left.Emit (ec);
if (my_on_true != ((BoolConstant) right).Value)
ig.Emit (OpCodes.Brtrue, target);
else
ig.Emit (OpCodes.Brfalse, target);
- return true;
+
+ return;
}
- } else if (oper == Operator.LogicalAnd){
- if (left is Binary){
- Binary left_binary = (Binary) left;
+ } else if (oper == Operator.LogicalAnd) {
- if (onTrue){
+ if (onTrue) {
Label tests_end = ig.DefineLabel ();
- if (left_binary.EmitBranchable (ec, tests_end, false)){
- if (right is Binary){
- Binary right_binary = (Binary) right;
-
- if (right_binary.EmitBranchable (ec, target, true)){
- ig.MarkLabel (tests_end);
- return true;
- }
- }
- right.Emit (ec);
- ig.Emit (OpCodes.Brtrue, target);
+ left.EmitBranchable (ec, tests_end, false);
+ right.EmitBranchable (ec, target, true);
ig.MarkLabel (tests_end);
- return true;
- }
} else {
- if (left_binary.EmitBranchable (ec, target, false)){
- if (right is Binary){
- Binary right_binary = (Binary) right;
-
- if (right_binary.EmitBranchable (ec, target, false))
- return true;
- }
- right.Emit (ec);
- if (onTrue)
- ig.Emit (OpCodes.Brtrue, target);
- else
- ig.Emit (OpCodes.Brfalse, target);
- return true;
- }
+ left.EmitBranchable (ec, target, false);
+ right.EmitBranchable (ec, target, false);
}
- //
- // Give up, and let the regular Emit work, but we could
- // also optimize the left-non-Branchable, but-right-Branchable
- //
- }
- return false;
- } else if (oper == Operator.LogicalOr){
- if (left is Binary){
- Binary left_binary = (Binary) left;
- if (onTrue){
- if (left_binary.EmitBranchable (ec, target, true)){
- if (right is Binary){
- Binary right_binary = (Binary) right;
+ return;
- if (right_binary.EmitBranchable (ec, target, true))
- return true;
- }
- right.Emit (ec);
- ig.Emit (OpCodes.Brtrue, target);
- return true;
- }
+ } else if (oper == Operator.LogicalOr){
+ if (onTrue) {
+ left.EmitBranchable (ec, target, true);
+ right.EmitBranchable (ec, target, true);
- //
- // Give up, and let the regular Emit work, but we could
- // also optimize the left-non-Branchable, but-right-Branchable
- //
} else {
Label tests_end = ig.DefineLabel ();
+ left.EmitBranchable (ec, tests_end, true);
+ right.EmitBranchable (ec, target, false);
+ ig.MarkLabel (tests_end);
+ }
- if (left_binary.EmitBranchable (ec, tests_end, true)){
- if (right is Binary){
- Binary right_binary = (Binary) right;
-
- if (right_binary.EmitBranchable (ec, target, false)){
- ig.MarkLabel (tests_end);
- return true;
- }
- }
- right.Emit (ec);
- ig.Emit (OpCodes.Brfalse, target);
- ig.MarkLabel (tests_end);
- return true;
- }
- }
+ return;
+
+ } else if (!(oper == Operator.LessThan || oper == Operator.GreaterThan ||
+ oper == Operator.LessThanOrEqual || oper == Operator.GreaterThanOrEqual ||
+ oper == Operator.Equality || oper == Operator.Inequality)) {
+ base.EmitBranchable (ec, target, onTrue);
+ return;
}
- return false;
- } else if (!(oper == Operator.LessThan ||
- oper == Operator.GreaterThan ||
- oper == Operator.LessThanOrEqual ||
- oper == Operator.GreaterThanOrEqual))
- return false;
-
left.Emit (ec);
right.Emit (ec);
Type t = left.Type;
- bool isUnsigned = is_unsigned (t);
+ bool isUnsigned = is_unsigned (t) || t == TypeManager.double_type || t == TypeManager.float_type;
switch (oper){
case Operator.Equality:
break;
case Operator.LessThanOrEqual:
- if (t == TypeManager.double_type || t == TypeManager.float_type)
- isUnsigned = true;
-
if (onTrue)
if (isUnsigned)
ig.Emit (OpCodes.Ble_Un, target);
case Operator.GreaterThanOrEqual:
- if (t == TypeManager.double_type || t == TypeManager.float_type)
- isUnsigned = true;
if (onTrue)
if (isUnsigned)
ig.Emit (OpCodes.Bge_Un, target);
else
ig.Emit (OpCodes.Blt, target);
break;
-
default:
- return false;
+ Console.WriteLine (oper);
+ throw new Exception ("what is THAT");
}
-
- return true;
}
public override void Emit (EmitContext ec)
// Handle short-circuit operators differently
// than the rest
//
- if (oper == Operator.LogicalAnd){
+ if (oper == Operator.LogicalAnd) {
Label load_zero = ig.DefineLabel ();
Label end = ig.DefineLabel ();
- bool process = true;
- if (left is Binary){
- Binary left_binary = (Binary) left;
-
- if (left_binary.EmitBranchable (ec, load_zero, false)){
+ left.EmitBranchable (ec, load_zero, false);
right.Emit (ec);
ig.Emit (OpCodes.Br, end);
- process = false;
- }
- }
- if (process){
- left.Emit (ec);
- ig.Emit (OpCodes.Brfalse, load_zero);
- right.Emit (ec);
- ig.Emit (OpCodes.Br, end);
- }
ig.MarkLabel (load_zero);
ig.Emit (OpCodes.Ldc_I4_0);
ig.MarkLabel (end);
return;
- } else if (oper == Operator.LogicalOr){
+ } else if (oper == Operator.LogicalOr) {
Label load_one = ig.DefineLabel ();
Label end = ig.DefineLabel ();
- bool process = true;
- if (left is Binary){
- Binary left_binary = (Binary) left;
-
- if (left_binary.EmitBranchable (ec, load_one, true)){
+ left.EmitBranchable (ec, load_one, true);
right.Emit (ec);
ig.Emit (OpCodes.Br, end);
- process = false;
- }
- }
- if (process){
- left.Emit (ec);
- ig.Emit (OpCodes.Brtrue, load_one);
- right.Emit (ec);
- ig.Emit (OpCodes.Br, end);
- }
ig.MarkLabel (load_one);
ig.Emit (OpCodes.Ldc_I4_1);
ig.MarkLabel (end);
}
}
+ //
+ // Represents the operation a + b [+ c [+ d [+ ...]]], where a is a string
+ // b, c, d... may be strings or objects.
+ //
+ public class StringConcat : Expression {
+ ArrayList operands;
+ bool invalid = false;
+
+
+ public StringConcat (EmitContext ec, Location loc, Expression left, Expression right)
+ {
+ this.loc = loc;
+ type = TypeManager.string_type;
+ eclass = ExprClass.Value;
+
+ operands = new ArrayList (2);
+ Append (ec, left);
+ Append (ec, right);
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ if (invalid)
+ return null;
+
+ return this;
+ }
+
+ public void Append (EmitContext ec, Expression operand)
+ {
+ //
+ // Constant folding
+ //
+ if (operand is StringConstant && operands.Count != 0) {
+ StringConstant last_operand = operands [operands.Count - 1] as StringConstant;
+ if (last_operand != null) {
+ operands [operands.Count - 1] = new StringConstant (last_operand.Value + ((StringConstant) operand).Value);
+ return;
+ }
+ }
+
+ //
+ // Conversion to object
+ //
+ if (operand.Type != TypeManager.string_type) {
+ Expression no = Convert.ImplicitConversion (ec, operand, TypeManager.object_type, loc);
+
+ if (no == null) {
+ Binary.Error_OperatorCannotBeApplied (loc, "+", TypeManager.string_type, operand.Type);
+ invalid = true;
+ }
+ operand = no;
+ }
+
+ operands.Add (operand);
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ 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];
+
+ 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 = Convert.ImplicitConversion (ec, e, TypeManager.object_type, loc);
+ }
+ operands [i] = new Argument (e, Argument.AType.Expression);
+ }
+
+ //
+ // Find the right method
+ //
+ switch (operands.Count) {
+ case 1:
+ //
+ // This should not be possible, because simple constant folding
+ // is taken care of in the Binary code.
+ //
+ throw new Exception ("how did you get here?");
+
+ case 2:
+ concat_method = is_strings_only ?
+ TypeManager.string_concat_string_string :
+ TypeManager.string_concat_object_object ;
+ break;
+ case 3:
+ concat_method = is_strings_only ?
+ TypeManager.string_concat_string_string_string :
+ TypeManager.string_concat_object_object_object ;
+ break;
+ case 4:
+ //
+ // There is not a 4 param overlaod for object (the one that there is
+ // is actually a varargs methods, and is only in corlib because it was
+ // introduced there before.).
+ //
+ if (!is_strings_only)
+ goto default;
+
+ concat_method = TypeManager.string_concat_string_string_string_string;
+ break;
+ default:
+ concat_method = is_strings_only ?
+ TypeManager.string_concat_string_dot_dot_dot :
+ TypeManager.string_concat_object_dot_dot_dot ;
+ break;
+ }
+
+ Invocation.EmitArguments (ec, concat_method, operands);
+ ec.ig.Emit (OpCodes.Call, concat_method);
+ }
+ }
+
//
// Object created with +/= on delegates
//
ArrayList arguments = new ArrayList ();
arguments.Add (new Argument (left, Argument.AType.Expression));
arguments.Add (new Argument (right, Argument.AType.Expression));
- method = Invocation.OverloadResolve (ec, (MethodGroupExpr) operator_group, arguments, loc) as MethodInfo;
+ method = Invocation.OverloadResolve (
+ ec, (MethodGroupExpr) operator_group, arguments, false, loc)
+ as MethodInfo;
if ((method == null) || (method.ReturnType != type)) {
Error19 ();
return null;
ig.Emit (OpCodes.Nop);
- Statement.EmitBoolExpression (ec, is_and ? op_false : op_true, false_target, false);
+ (is_and ? op_false : op_true).EmitBranchable (ec, false_target, false);
left.Emit (ec);
ig.Emit (OpCodes.Br, end_target);
ig.MarkLabel (false_target);
Label false_target = ig.DefineLabel ();
Label end_target = ig.DefineLabel ();
- Statement.EmitBoolExpression (ec, expr, false_target, false);
+ expr.EmitBranchable (ec, false_target, false);
trueExpr.Emit (ec);
ig.Emit (OpCodes.Br, end_target);
ig.MarkLabel (false_target);
public bool ResolveMethodGroup (EmitContext ec, Location loc)
{
+ ConstructedType ctype = Expr as ConstructedType;
+ if (ctype != null)
+ Expr = ctype.GetMemberAccess (ec);
+
// FIXME: csc doesn't report any error if you try to use `ref' or
// `out' in a delegate creation expression.
Expr = Expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
if (ArgType == AType.Expression)
return true;
-
- if (Expr.eclass != ExprClass.Variable){
+ else {
//
- // We just probe to match the CSC output
+ // Catch errors where fields of a MarshalByRefObject are passed as ref or out
+ // This is only allowed for `this'
//
- if (Expr.eclass == ExprClass.PropertyAccess ||
+ FieldExpr fe = Expr as FieldExpr;
+ if (fe != null && !fe.IsStatic){
+ Expression instance = fe.InstanceExpression;
+
+ if (instance.GetType () != typeof (This)){
+ if (fe.InstanceExpression.Type.IsSubclassOf (TypeManager.mbr_type)){
+ Report.Error (197, loc,
+ "Can not pass a type that derives from MarshalByRefObject with out or ref");
+ return false;
+ }
+ }
+ }
+ }
+
+ if (Expr.eclass != ExprClass.Variable){
+ //
+ // We just probe to match the CSC output
+ //
+ if (Expr.eclass == ExprClass.PropertyAccess ||
Expr.eclass == ExprClass.IndexerAccess){
Report.Error (
206, loc,
pr.AddressOf (ec, mode);
}
- } else
+ } else {
((IMemoryLocation)Expr).AddressOf (ec, mode);
+ }
} else
Expr.Emit (ec);
}
if (pd != null)
return (ParameterData) pd;
-
ip = TypeManager.LookupParametersByBuilder (mb);
if (ip != null){
method_parameter_cache [mb] = ip;
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;
" does not resolve its type");
//
- // This is a special case since csc behaves this way. I can't find
- // it anywhere in the spec but oh well ...
+ // This is a special case since csc behaves this way.
//
if (argument_expr is NullLiteral &&
p == TypeManager.string_type &&
q == TypeManager.string_type)
return 0;
+ //
+ // csc behaves this way so we emulate it. Basically, if the argument
+ // is null and one of the types to compare is 'object' and the other
+ // is a reference type, we prefer the other.
+ //
+ // I can't find this anywhere in the spec but we can interpret this
+ // to mean that null can be of any type you wish in such a context
+ //
+ if (p != null && q != null) {
+ if (argument_expr is NullLiteral &&
+ !p.IsValueType &&
+ q == TypeManager.object_type)
+ return 1;
+ else if (argument_expr is NullLiteral &&
+ !q.IsValueType &&
+ p == TypeManager.object_type)
+ return 0;
+ }
+
if (p == q)
return 0;
// 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)
// best method, we cant tell. This happens
// if we have:
//
- //
// interface IFoo {
// void DoIt ();
// }
//
// However, we have to consider that
// Trim (); is better than Trim (params char[] chars);
+ //
if (cand_count == 0 && argument_count == 0)
return best == null || best_params ? 1 : 0;
{
string ret_type = "";
+ if (mb == null)
+ return "";
+
if (mb is MethodInfo)
ret_type = TypeManager.CSharpName (((MethodInfo) mb).ReturnType);
return union;
}
+ static bool IsParamsMethodApplicable (EmitContext ec, MethodGroupExpr me,
+ ArrayList arguments, ref MethodBase candidate)
+ {
+ if (!me.HasTypeArguments &&
+ !InferParamsTypeArguments (ec, arguments, ref candidate))
+ return false;
+
+ return IsParamsMethodApplicable (ec, arguments, candidate);
+ }
+
/// <summary>
/// Determines if the candidate method, if a params method, is applicable
/// in its expanded form to the given set of arguments
return true;
}
+ static bool IsApplicable (EmitContext ec, MethodGroupExpr me,
+ ArrayList arguments, ref MethodBase candidate)
+ {
+ if (!me.HasTypeArguments &&
+ !InferTypeArguments (ec, arguments, ref candidate))
+ return false;
+
+ return IsApplicable (ec, arguments, candidate);
+ }
+
/// <summary>
/// Determines if the candidate method is applicable (section 14.4.2.1)
/// to the given set of arguments
return true;
}
-
-
/// <summary>
/// Find the Applicable Function Members (7.4.2.1)
///
///
/// </summary>
public static MethodBase OverloadResolve (EmitContext ec, MethodGroupExpr me,
- ArrayList Arguments, Location loc)
+ ArrayList Arguments, bool may_fail,
+ Location loc)
{
MethodBase method = null;
Type applicable_type = null;
// and whether it is being considered in its
// normal or expanded form
//
+ // false is normal form, true is expanded form
+ //
Hashtable candidate_to_form = new PtrHashtable ();
bool found_applicable = false;
- foreach (MethodBase candidate in me.Methods){
- Type decl_type = candidate.DeclaringType;
+ MethodBase[] methods = me.Methods;
+
+ for (int i = 0; i < methods.Length; i++) {
+ Type decl_type = methods [i].DeclaringType;
//
// If we have already found an applicable method
found_applicable)
continue;
-
// Check if candidate is applicable (section 14.4.2.1)
- if (IsApplicable (ec, Arguments, candidate)) {
+ if (IsApplicable (ec, me, Arguments, ref methods [i])) {
// Candidate is applicable in normal form
+ MethodBase candidate = methods [i];
candidates.Add (candidate);
applicable_type = candidate.DeclaringType;
found_applicable = true;
candidate_to_form [candidate] = false;
- } else {
- if (IsParamsMethodApplicable (ec, Arguments, candidate)) {
- // Candidate is applicable in expanded form
- candidates.Add (candidate);
- applicable_type = candidate.DeclaringType;
- found_applicable = true;
- candidate_to_form [candidate] = true;
- }
+ } else if (IsParamsMethodApplicable (ec, me, Arguments, ref methods [i])) {
+ // Candidate is applicable in expanded form
+ MethodBase candidate = methods [i];
+ candidates.Add (candidate);
+ applicable_type = candidate.DeclaringType;
+ found_applicable = true;
+ candidate_to_form [candidate] = true;
}
}
+ if (Arguments == null)
+ argument_count = 0;
+ else
+ argument_count = Arguments.Count;
+
//
// Now we actually find the best method
//
method = candidate;
}
- if (Arguments == null)
- argument_count = 0;
- else
- argument_count = Arguments.Count;
-
-
if (method == null) {
+ int errors = Report.Errors;
+
//
// Okay so we have failed to find anything so we
// return by providing info about the closest match
//
- for (int i = 0; i < me.Methods.Length; ++i) {
+ for (int i = 0; i < methods.Length; ++i) {
- MethodBase c = (MethodBase) me.Methods [i];
- ParameterData pd = GetParameterData (c);
+ MethodBase c = methods [i];
+ if (c == null)
+ continue;
+ ParameterData pd = GetParameterData (c);
if (pd.Count != argument_count)
continue;
- VerifyArgumentsCompat (ec, Arguments, argument_count, c, false,
- null, loc);
+ if (!InferTypeArguments (ec, Arguments, ref c))
+ continue;
+
+ VerifyArgumentsCompat (ec, Arguments, argument_count,
+ c, false, null, loc);
break;
}
- if (!Location.IsNull (loc)) {
- string report_name = me.Name;
- if (report_name == ".ctor")
- report_name = me.DeclaringType.ToString ();
+ if (Report.Errors > errors)
+ return null;
+
+ string report_name = me.Name;
+ if (report_name == ".ctor")
+ report_name = me.DeclaringType.ToString ();
- Error_WrongNumArguments (loc, report_name, argument_count);
- }
+ for (int i = 0; i < methods.Length; ++i) {
+
+ MethodBase c = methods [i];
+ if (c == null)
+ continue;
+
+ ParameterData pd = GetParameterData (c);
+ if (pd.Count != argument_count)
+ continue;
+
+ if (InferTypeArguments (ec, Arguments, ref c))
+ continue;
+
+ Report.Error (411, loc, "The type arguments for " +
+ "method `{0}' cannot be infered from " +
+ "the usage. Try specifying the type " +
+ "arguments explicitly.", report_name);
+ break;
+ }
+
+ if (!may_fail && (errors == Report.Errors))
+ Error_WrongNumArguments (loc, report_name,
+ argument_count);
return null;
}
// applicable so we debar the params
// method.
//
- if ((IsParamsMethodApplicable (ec, Arguments, candidate) &&
- IsApplicable (ec, Arguments, method)))
- continue;
+ // if ((IsParamsMethodApplicable (ec, Arguments, candidate) &&
+// IsApplicable (ec, Arguments, method)))
+// continue;
bool cand_params = (bool) candidate_to_form [candidate];
int x = BetterFunction (ec, Arguments,
return true;
}
+ static bool InferType (Type pt, Type at, ref Type[] infered)
+ {
+ if (pt.IsGenericParameter) {
+ int pos = pt.GenericParameterPosition;
+
+ if (infered [pos] == null) {
+ Type check = at;
+ while (check.IsArray)
+ check = check.GetElementType ();
+
+ if (pt.Equals (check))
+ return false;
+
+ infered [pos] = at;
+ return true;
+ }
+
+ if (infered [pos] != at)
+ return false;
+
+ return true;
+ }
+
+ if (!pt.ContainsGenericParameters)
+ return true;
+
+ if (at.IsArray) {
+ if (!pt.IsArray ||
+ (at.GetArrayRank () != pt.GetArrayRank ()))
+ return false;
+
+ return InferType (pt.GetElementType (), at.GetElementType (),
+ ref infered);
+ }
+
+ if (pt.IsArray) {
+ if (!at.IsArray ||
+ (pt.GetArrayRank () != at.GetArrayRank ()))
+ return false;
+
+ return InferType (pt.GetElementType (), at.GetElementType (),
+ ref infered);
+ }
+
+ if (!at.IsGenericInstance)
+ return false;
+
+ Type[] at_args = at.GetGenericArguments ();
+ Type[] pt_args = pt.GetGenericArguments ();
+
+ if (at_args.Length != pt_args.Length)
+ return false;
+
+ Type[] infered_types = new Type [at_args.Length];
+
+ for (int i = 0; i < at_args.Length; i++)
+ if (!InferType (pt_args [i], at_args [i], ref infered_types))
+ return false;
+
+ for (int i = 0; i < infered_types.Length; i++)
+ if (infered_types [i] == null)
+ return false;
+
+ for (int i = 0; i < infered_types.Length; i++) {
+ if (infered [i] == null) {
+ infered [i] = infered_types [i];
+ continue;
+ }
+
+ if (infered [i] != infered_types [i])
+ return false;
+ }
+
+ return true;
+ }
+
+ static bool InferParamsTypeArguments (EmitContext ec, ArrayList arguments,
+ ref MethodBase method)
+ {
+ if ((arguments == null) || !TypeManager.IsGenericMethod (method))
+ return true;
+
+ int arg_count;
+
+ if (arguments == null)
+ arg_count = 0;
+ else
+ arg_count = arguments.Count;
+
+ ParameterData pd = GetParameterData (method);
+
+ int pd_count = pd.Count;
+
+ if (pd_count == 0)
+ return false;
+
+ if (pd.ParameterModifier (pd_count - 1) != Parameter.Modifier.PARAMS)
+ return false;
+
+ if (pd_count - 1 > arg_count)
+ return false;
+
+ if (pd_count == 1 && arg_count == 0)
+ return true;
+
+ Type[] method_args = method.GetGenericArguments ();
+ Type[] infered_types = new Type [method_args.Length];
+
+ //
+ // If we have come this far, the case which
+ // 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) {
+ Argument a = (Argument) arguments [i];
+
+ if ((a.Expr is NullLiteral) || (a.Expr is MethodGroupExpr))
+ continue;
+
+ Type pt = pd.ParameterType (i);
+ Type at = a.Type;
+
+ if (!InferType (pt, at, ref infered_types))
+ return false;
+ }
+
+ 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 ((a.Expr is NullLiteral) || (a.Expr is MethodGroupExpr))
+ continue;
+
+ if (!InferType (element_type, a.Type, ref infered_types))
+ return false;
+ }
+
+ for (int i = 0; i < infered_types.Length; i++)
+ if (infered_types [i] == null)
+ return false;
+
+ method = method.BindGenericParameters (infered_types);
+ return true;
+ }
+
+ public static bool InferTypeArguments (Type[] param_types, Type[] arg_types,
+ ref Type[] infered_types)
+ {
+ for (int i = 0; i < arg_types.Length; i++) {
+ if (arg_types [i] == null)
+ continue;
+
+ if (!InferType (param_types [i], arg_types [i],
+ ref infered_types))
+ return false;
+ }
+
+ for (int i = 0; i < infered_types.Length; i++)
+ if (infered_types [i] == null)
+ return false;
+
+ return true;
+ }
+
+ static bool InferTypeArguments (EmitContext ec, ArrayList arguments,
+ ref MethodBase method)
+ {
+ if (!TypeManager.IsGenericMethod (method))
+ return true;
+
+ int arg_count;
+ if (arguments != null)
+ arg_count = arguments.Count;
+ else
+ arg_count = 0;
+
+ ParameterData pd = GetParameterData (method);
+ if (arg_count != pd.Count)
+ return false;
+
+ Type[] method_args = method.GetGenericArguments ();
+ Type[] infered_types = new Type [method_args.Length];
+
+ Type[] param_types = new Type [pd.Count];
+ Type[] arg_types = new Type [pd.Count];
+
+ for (int i = 0; i < arg_count; i++) {
+ param_types [i] = pd.ParameterType (i);
+
+ Argument a = (Argument) arguments [i];
+ if ((a.Expr is NullLiteral) || (a.Expr is MethodGroupExpr))
+ continue;
+
+ arg_types [i] = a.Type;
+ }
+
+ if (!InferTypeArguments (param_types, arg_types, ref infered_types))
+ return false;
+
+ method = method.BindGenericParameters (infered_types);
+ return true;
+ }
+
+ public static bool InferTypeArguments (EmitContext ec, ParameterData apd,
+ ref MethodBase method)
+ {
+ if (!TypeManager.IsGenericMethod (method))
+ return true;
+
+ ParameterData pd = GetParameterData (method);
+ if (apd.Count != pd.Count)
+ return false;
+
+ Type[] method_args = method.GetGenericArguments ();
+ Type[] infered_types = new Type [method_args.Length];
+
+ Type[] param_types = new Type [pd.Count];
+ Type[] arg_types = new Type [pd.Count];
+
+ for (int i = 0; i < apd.Count; i++) {
+ param_types [i] = pd.ParameterType (i);
+ arg_types [i] = apd.ParameterType (i);
+ }
+
+ if (!InferTypeArguments (param_types, arg_types, ref infered_types))
+ return false;
+
+ method = method.BindGenericParameters (infered_types);
+ return true;
+ }
+
public override Expression DoResolve (EmitContext ec)
{
//
if (expr is BaseAccess)
is_base = true;
+ if (expr is ConstructedType)
+ expr = ((ConstructedType) expr).GetMemberAccess (ec);
+
expr = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
if (expr == null)
return null;
}
MethodGroupExpr mg = (MethodGroupExpr) expr;
- method = OverloadResolve (ec, mg, Arguments, loc);
+ method = OverloadResolve (ec, mg, Arguments, false, loc);
- if (method == null){
- Error (-6,
- "Could not find any applicable function for this argument list");
+ if (method == null)
return null;
- }
MethodInfo mi = method as MethodInfo;
if (mi != null) {
int count = arguments.Count - idx;
Argument a = (Argument) arguments [idx];
Type t = a.Expr.Type;
- string array_type = t.FullName + "[]";
- LocalBuilder array;
- array = ig.DeclareLocal (TypeManager.LookupType (array_type));
IntConstant.EmitInt (ig, count);
ig.Emit (OpCodes.Newarr, TypeManager.TypeToCoreType (t));
- ig.Emit (OpCodes.Stloc, array);
int top = arguments.Count;
for (int j = idx; j < top; j++){
a = (Argument) arguments [j];
- ig.Emit (OpCodes.Ldloc, array);
+ ig.Emit (OpCodes.Dup);
IntConstant.EmitInt (ig, j - idx);
bool is_stobj, has_type_arg;
else
ig.Emit (op);
}
- ig.Emit (OpCodes.Ldloc, array);
}
/// <summary>
{
ILGenerator ig = ec.ig;
bool struct_call = false;
+ bool this_call = false;
Type decl_type = method.DeclaringType;
// If this is ourselves, push "this"
//
if (instance_expr == null){
+ this_call = true;
ig.Emit (OpCodes.Ldarg_0);
} else {
+ Type itype = instance_expr.Type;
+
//
// Push the instance expression
//
- if (TypeManager.IsValueType (instance_expr.Type)){
+ if (TypeManager.IsValueType (itype)){
//
// Special case: calls to a function declared in a
// reference-type with a value-type argument need
// to have their value boxed.
-
- if (!instance_expr.Type.IsGenericParameter)
- struct_call = true;
- if (TypeManager.IsValueType (decl_type)){
+ if (decl_type.IsValueType || itype.IsGenericParameter){
//
// If the expression implements IMemoryLocation, then
// we can optimize and use AddressOf on the
AddressOf (ec, AddressOp.LoadStore);
}
else {
- Type t = instance_expr.Type;
-
instance_expr.Emit (ec);
- LocalBuilder temp = ig.DeclareLocal (t);
+ LocalBuilder temp = ig.DeclareLocal (itype);
ig.Emit (OpCodes.Stloc, temp);
ig.Emit (OpCodes.Ldloca, temp);
}
+ if (itype.IsGenericParameter)
+ ig.Emit (OpCodes.Constrained, itype);
+ else
+ struct_call = true;
} else {
instance_expr.Emit (ec);
- ig.Emit (OpCodes.Box, instance_expr.Type);
+ ig.Emit (OpCodes.Box, itype);
}
} else
instance_expr.Emit (ec);
}
EmitArguments (ec, method, Arguments);
-
- if (is_static || struct_call || is_base){
+ //
+ // 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
//
Expression value_target;
bool value_target_set = false;
+ bool is_type_parameter = false;
public New (Expression requested_type, ArrayList arguments, Location l)
{
return RequestedType;
}
- if (type.IsInterface || type.IsAbstract){
+ if (type.IsGenericParameter) {
+ if (!TypeManager.HasConstructorConstraint (type)) {
+ Error (304, String.Format (
+ "Cannot create an instance of the " +
+ "variable type '{0}' because it " +
+ "doesn't have the new() constraint",
+ type));
+ return null;
+ }
+
+ if ((Arguments != null) && (Arguments.Count != 0)) {
+ Error (417, String.Format (
+ "`{0}': cannot provide arguments " +
+ "when creating an instance of a " +
+ "variable type.", type));
+ return null;
+ }
+
+ is_type_parameter = true;
+ eclass = ExprClass.Value;
+ return this;
+ } else if (type.IsInterface || type.IsAbstract){
Error (144, "It is not possible to create instances of interfaces or abstract classes");
return null;
}
}
}
- method = Invocation.OverloadResolve (ec, (MethodGroupExpr) ml, Arguments, loc);
+ method = Invocation.OverloadResolve (
+ ec, (MethodGroupExpr) ml, Arguments, false, loc);
}
return this;
}
+ bool DoEmitTypeParameter (EmitContext ec)
+ {
+ ILGenerator ig = ec.ig;
+
+ ig.Emit (OpCodes.Ldtoken, type);
+ ig.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
+ ig.Emit (OpCodes.Call, TypeManager.activator_create_instance);
+ ig.Emit (OpCodes.Unbox_Any, type);
+
+ return true;
+ }
+
//
// This DoEmit can be invoked in two contexts:
// * As a mechanism that will leave a value on the stack (new object)
public override void Emit (EmitContext ec)
{
- DoEmit (ec, true);
+ if (is_type_parameter)
+ DoEmitTypeParameter (ec);
+ else
+ DoEmit (ec, true);
}
public override void EmitStatement (EmitContext ec)
{
+ if (is_type_parameter)
+ throw new InvalidOperationException ();
+
if (DoEmit (ec, false))
ec.ig.Emit (OpCodes.Pop);
}
public void AddressOf (EmitContext ec, AddressOp Mode)
{
+ if (is_type_parameter)
+ throw new InvalidOperationException ();
+
if (!type.IsValueType){
//
// We throw an exception. So far, I believe we only need to support
if (conv == null)
return false;
- if (conv is StringConstant)
+ if (conv is StringConstant || conv is DecimalConstant || conv is NullCast) {
+ // These are subclasses of Constant that can appear as elements of an
+ // array that cannot be statically initialized (with num_automatic_initializers
+ // > max_automatic_initializers), so num_automatic_initializers should be left as zero.
array_data.Add (conv);
- else if (conv is Constant) {
+ } else if (conv is Constant) {
+ // These are the types of Constant that can appear in arrays that can be
+ // statically allocated.
array_data.Add (conv);
num_automatic_initializers++;
} else
return null;
}
- new_method = Invocation.OverloadResolve (ec, (MethodGroupExpr) ml, arguments, loc);
+ new_method = Invocation.OverloadResolve (
+ ec, (MethodGroupExpr) ml, arguments, false, loc);
if (new_method == null) {
Error (-6, "New invocation: Can not find a constructor for " +
eclass = ExprClass.Value;
return this;
} else {
- ModuleBuilder mb = CodeGen.ModuleBuilder;
+ ModuleBuilder mb = CodeGen.Module.Builder;
ArrayList args = new ArrayList ();
if (arguments != null) {
int dims = bounds.Count;
int [] current_pos = new int [dims];
int top = array_data.Count;
- LocalBuilder temp = ig.DeclareLocal (type);
-
- ig.Emit (OpCodes.Stloc, temp);
MethodInfo set = null;
if (dims != 1){
Type [] args;
ModuleBuilder mb = null;
- mb = CodeGen.ModuleBuilder;
+ mb = CodeGen.Module.Builder;
args = new Type [dims + 1];
int j;
num_automatic_initializers <= max_automatic_initializers) {
Type etype = e.Type;
- ig.Emit (OpCodes.Ldloc, temp);
+ if (is_expression || i != top - 1)
+ ig.Emit (OpCodes.Dup);
for (int idx = 0; idx < dims; idx++)
IntConstant.EmitInt (ig, current_pos [idx]);
ig.Emit (OpCodes.Ldelema, etype);
}
- ig.Emit (OpCodes.Nop);
e.Emit (ec);
- ig.Emit (OpCodes.Nop);
- ig.Emit (OpCodes.Nop);
if (dims == 1)
ArrayAccess.EmitStoreOpcode (ig, array_element_type);
current_pos [j] = 0;
}
}
-
- if (is_expression)
- ig.Emit (OpCodes.Ldloc, temp);
}
void EmitArrayArguments (EmitContext ec)
//
bool dynamic_initializers = true;
- if (underlying_type != TypeManager.string_type &&
- underlying_type != TypeManager.decimal_type &&
- underlying_type != TypeManager.object_type) {
+ // This will never be true for array types that cannot be statically
+ // initialized. num_automatic_initializers will always be zero. See
+ // CheckIndices.
if (num_automatic_initializers > max_automatic_initializers)
EmitStaticInitializers (ec, dynamic_initializers || !is_statement);
- }
if (dynamic_initializers)
EmitDynamicInitializers (ec, !is_statement);
}
return ret;
}
+
+ public Expression TurnIntoConstant ()
+ {
+ //
+ // Should use something like the above attribute thing.
+ // It should return a subclass of Constant that just returns
+ // the computed value of the array
+ //
+ throw new Exception ("Does not support yet Turning array into a Constant");
+ }
}
/// <summary>
public bool ResolveBase (EmitContext ec)
{
eclass = ExprClass.Variable;
- type = ec.ContainerType;
+
+ if (ec.TypeContainer.CurrentType != null)
+ type = ec.TypeContainer.CurrentType.ResolveType (ec);
+ else
+ type = ec.ContainerType;
if (ec.IsStatic) {
Error (26, "Keyword this not valid in static code");
public override void Emit (EmitContext ec)
{
ILGenerator ig = ec.ig;
-
- ig.Emit (OpCodes.Ldarg_0);
+
+ ec.EmitThis ();
if (ec.TypeContainer is Struct)
ig.Emit (OpCodes.Ldobj, type);
}
ILGenerator ig = ec.ig;
if (ec.TypeContainer is Struct){
- ig.Emit (OpCodes.Ldarg_0);
+ ec.EmitThis ();
source.Emit (ec);
ig.Emit (OpCodes.Stobj, type);
} else {
public void AddressOf (EmitContext ec, AddressOp mode)
{
- ec.ig.Emit (OpCodes.Ldarg_0);
+ ec.EmitThis ();
// FIMXE
// FIGURE OUT WHY LDARG_S does not work
/// Implements the member access expression
/// </summary>
public class MemberAccess : Expression {
- public readonly string Identifier;
- Expression expr;
+ public string Identifier;
+ protected Expression expr;
+ protected TypeArguments args;
public MemberAccess (Expression expr, string id, Location l)
{
loc = l;
}
+ public MemberAccess (Expression expr, string id, TypeArguments args,
+ Location l)
+ : this (expr, id, l)
+ {
+ this.args = args;
+ }
+
public Expression Expr {
get {
return expr;
SimpleName sn = (SimpleName) left_original;
- Type t = RootContext.LookupType (ec.DeclSpace, sn.Name, true, loc);
+ TypeExpr t = RootContext.LookupType (ec.DeclSpace, sn.Name, true, loc);
if (t != null)
return true;
Const c = TypeManager.LookupConstant ((FieldBuilder) fi);
if (c != null) {
- object o = c.LookupConstantValue ();
- if (o == null)
+ object o;
+ if (!c.LookupConstantValue (out o))
return null;
-
+
object real_value = ((Constant) c.Expr).GetValue ();
return Constantify (real_value, fi.FieldType);
// it will fail to find any members at all
//
- Type expr_type = expr.Type;
+ Type expr_type;
if (expr is TypeExpr){
+ expr_type = ((TypeExpr) expr).ResolveType (ec);
+
if (!ec.DeclSpace.CheckAccessLevel (expr_type)){
Error (122, "`" + expr_type + "' " +
"is inaccessible because of its protection level");
}
}
}
- }
+ } else
+ expr_type = expr.Type;
if (expr_type.IsPointer){
Error (23, "The `.' operator can not be applied to pointer operands (" +
return null;
}
+ int errors = Report.Errors;
+
Expression member_lookup;
- member_lookup = MemberLookupFinal (ec, expr_type, expr_type, Identifier, loc);
- if (member_lookup == null)
+ member_lookup = MemberLookup (
+ ec, expr_type, expr_type, Identifier, loc);
+ if ((member_lookup == null) && (args != null)) {
+ string lookup_id = Identifier + "!" + args.Count;
+ member_lookup = MemberLookup (
+ ec, expr_type, expr_type, lookup_id, loc);
+ }
+ if (member_lookup == null) {
+ MemberLookupFailed (
+ ec, expr_type, expr_type, Identifier, null, loc);
return null;
+ }
if (member_lookup is TypeExpr) {
if (!(expr is TypeExpr) && !(expr is SimpleName)) {
return member_lookup;
}
+
+ if (args != null) {
+ string full_name = expr_type + "." + Identifier;
+
+ if (member_lookup is FieldExpr) {
+ Report.Error (307, loc, "The field `{0}' cannot " +
+ "be used with type arguments", full_name);
+ return null;
+ } else if (member_lookup is EventExpr) {
+ Report.Error (307, loc, "The event `{0}' cannot " +
+ "be used with type arguments", full_name);
+ return null;
+ } else if (member_lookup is PropertyExpr) {
+ Report.Error (307, loc, "The property `{0}' cannot " +
+ "be used with type arguments", full_name);
+ return null;
+ }
+ }
member_lookup = ResolveMemberAccess (ec, member_lookup, expr, loc, original);
if (member_lookup == null)
return null;
+ if (args != null) {
+ MethodGroupExpr mg = member_lookup as MethodGroupExpr;
+ if (mg == null)
+ throw new InternalErrorException ();
+
+ if (args.Resolve (ec) == false)
+ return null;
+
+ Type[] atypes = args.Arguments;
+
+ int first_count = 0;
+ MethodInfo first = null;
+
+ ArrayList list = new ArrayList ();
+ foreach (MethodBase mb in mg.Methods) {
+ MethodInfo mi = mb as MethodInfo;
+ if ((mi == null) || !mi.HasGenericParameters)
+ continue;
+
+ Type[] gen_params = mi.GetGenericArguments ();
+
+ if (first == null) {
+ first = mi;
+ first_count = gen_params.Length;
+ }
+
+ if (gen_params.Length != atypes.Length)
+ continue;
+
+ list.Add (mi.BindGenericParameters (atypes));
+ }
+
+ if (list.Count > 0) {
+ MethodGroupExpr new_mg = new MethodGroupExpr (
+ list, mg.Location);
+ new_mg.InstanceExpression = mg.InstanceExpression;
+ new_mg.HasTypeArguments = true;
+ return new_mg;
+ }
+
+ string name = expr_type + "." + Identifier;
+
+ if (first != null)
+ Report.Error (
+ 305, loc, "Using the generic method `{0}' " +
+ "requires {1} type arguments", name,
+ first_count);
+ else
+ Report.Error (
+ 308, loc, "The non-generic method `{0}' " +
+ "cannot be used with type arguments", name);
+
+ return null;
+ }
+
// The following DoResolve/DoResolveLValue will do the definite assignment
// check.
return new_expr.ResolveAsTypeStep (ec);
}
- Type expr_type = new_expr.Type;
-
+ Type expr_type = ((TypeExpr) new_expr).ResolveType (ec);
+
if (expr_type.IsPointer){
Error (23, "The `.' operator can not be applied to pointer operands (" +
TypeManager.CSharpName (expr_type) + ")");
return null;
}
-
+
Expression member_lookup;
- member_lookup = MemberLookupFinal (ec, expr_type, expr_type, Identifier, loc);
+ string lookup_id;
+ if (args != null)
+ lookup_id = Identifier + "!" + args.Count;
+ else
+ lookup_id = Identifier;
+ member_lookup = MemberLookupFinal (
+ ec, expr_type, expr_type, lookup_id, loc);
if (member_lookup == null)
return null;
- if (member_lookup is TypeExpr){
- member_lookup.Resolve (ec, ResolveFlags.Type);
- return member_lookup;
- }
+ TypeExpr texpr = member_lookup as TypeExpr;
+ if (texpr == null)
+ return null;
+
+ Type t = texpr.ResolveType (ec);
+ if (t == null)
+ return null;
+
+ if (TypeManager.HasGenericArguments (expr_type)) {
+ Type[] decl_args = TypeManager.GetTypeArguments (expr_type);
+
+ TypeArguments new_args = new TypeArguments (loc);
+ foreach (Type decl in decl_args)
+ new_args.Add (new TypeExpression (decl, loc));
+
+ if (args != null)
+ new_args.Add (args);
+
+ args = new_args;
+ }
- return null;
+ if (args != null) {
+ ConstructedType ctype = new ConstructedType (t, args, loc);
+ return ctype.ResolveAsTypeStep (ec);
+ }
+
+ return texpr;
}
public override void Emit (EmitContext ec)
public override string ToString ()
{
- return expr + "." + Identifier;
+ if (args != null)
+ return expr + "." + Identifier + "!" + args.Count;
+ else
+ return expr + "." + Identifier;
}
}
ig.Emit (OpCodes.Ldelem_R8);
else if (type == TypeManager.intptr_type)
ig.Emit (OpCodes.Ldelem_I);
- else if (type.IsValueType){
+ else if (TypeManager.IsEnumType (type)){
+ EmitLoadOpcode (ig, TypeManager.EnumToUnderlying (type));
+ } else if (type.IsValueType){
ig.Emit (OpCodes.Ldelema, type);
ig.Emit (OpCodes.Ldobj, type);
} else if (type.IsGenericParameter)
MethodInfo FetchGetMethod ()
{
- ModuleBuilder mb = CodeGen.ModuleBuilder;
+ ModuleBuilder mb = CodeGen.Module.Builder;
int arg_count = ea.Arguments.Count;
Type [] args = new Type [arg_count];
MethodInfo get;
MethodInfo FetchAddressMethod ()
{
- ModuleBuilder mb = CodeGen.ModuleBuilder;
+ ModuleBuilder mb = CodeGen.Module.Builder;
int arg_count = ea.Arguments.Count;
Type [] args = new Type [arg_count];
MethodInfo address;
if (rank == 1)
EmitStoreOpcode (ig, t);
else {
- ModuleBuilder mb = CodeGen.ModuleBuilder;
+ ModuleBuilder mb = CodeGen.Module.Builder;
int arg_count = ea.Arguments.Count;
Type [] args = new Type [arg_count + 1];
MethodInfo set;
if (AllGetters.Count > 0) {
found_any_getters = true;
get = (MethodInfo) Invocation.OverloadResolve (
- ec, new MethodGroupExpr (AllGetters, loc), arguments, loc);
+ ec, new MethodGroupExpr (AllGetters, loc),
+ arguments, false, loc);
}
if (!found_any) {
set_arguments.Add (new Argument (right_side, Argument.AType.Expression));
set = (MethodInfo) Invocation.OverloadResolve (
ec, new MethodGroupExpr (AllSetters, loc),
- set_arguments, loc);
+ set_arguments, false, loc);
}
if (!found_any) {
Error (1511, "Keyword base is not allowed in static method");
return null;
}
+
+ if (ec.IsFieldInitializer){
+ Error (1512, "Keyword base is not available in the current context");
+ return null;
+ }
- member_lookup = MemberLookup (ec, ec.ContainerType, null, base_type, member,
- AllMemberTypes, AllBindingFlags, loc);
+ member_lookup = MemberLookup (ec, ec.ContainerType, null, base_type,
+ member, AllMemberTypes, AllBindingFlags,
+ loc);
if (member_lookup == null) {
- MemberLookupFailed (ec, base_type, base_type, member, null, loc);
+ MemberLookupFailed (
+ ec, base_type, base_type, member, null, loc);
return null;
}
int pos = 0;
while ((pos < dim.Length) && (dim [pos] == '[')) {
pos++;
+
if (dim [pos] == ']') {
ltype = ltype.MakeArrayType ();
pos++;
}
int rank = 0;
- while (dim [pos++] == ',')
- rank++;
+ while (dim [pos] == ',') {
+ pos++; rank++;
+ }
if ((dim [pos] != ']') || (pos != dim.Length-1))
return null;
// ltype.Fullname is already fully qualified, so we can skip
// a lot of probes, and go directly to TypeManager.LookupType
//
- string cname = ltype.FullName + dim;
+ string fname = ltype.FullName != null ? ltype.FullName : ltype.Name;
+ string cname = fname + dim;
type = TypeManager.LookupTypeDirect (cname);
if (type == null){
//
//
// For now, fall back to the full lookup in that case.
//
- type = RootContext.LookupType (
+ TypeExpr texpr = RootContext.LookupType (
ec.DeclSpace, cname, false, loc);
+ if (texpr == null)
+ return null;
+
+ type = texpr.ResolveType (ec);
if (type == null)
return null;
}
return null;
}
- if (ec.InCatch || ec.InFinally){
+ if (ec.CurrentBranching.InCatch () ||
+ ec.CurrentBranching.InFinally (true)) {
Error (255,
"stackalloc can not be used in a catch or finally block");
return null;