//
// Author:
// Miguel de Icaza (miguel@ximian.com)
+// Manjula GHM (mmanjula@novell.com)
+// Satya Sudha K (ksathyasudha@novell.com)
//
// (C) 2001 Ximian, Inc.
//
case Operator.UnaryNegation:
return "-";
case Operator.LogicalNot:
- return "!";
+ return "Not";
case Operator.OnesComplement:
return "~";
case Operator.AddressOf:
- return "&";
+ return "AddressOf";
case Operator.Indirection:
return "*";
}
void Error23 (Type t)
{
Error (
- 23, "Operator " + OperName (Oper) +
+ 30311, "Operator " + OperName (Oper) +
" cannot be applied to operand of type '" +
TypeManager.MonoBASIC_Name (t) + "'");
}
{
Type expr_type = Expr.Type;
+ Expression mg;
+ string op_name;
+ if (Oper == Operator.LogicalNot && expr_type != TypeManager.bool_type)
+ Oper = Operator.OnesComplement;
+
+
+ if ((expr_type == TypeManager.string_type) &&
+ (Oper == Operator.UnaryPlus ||
+ Oper == Operator.UnaryNegation)) {
+
+ Expr = ConvertImplicit (ec, Expr, TypeManager.double_type, loc);
+ if (Expr == null) {
+ Error23 (expr_type);
+ return null;
+ }
+ expr_type = Expr.Type;
+ }
+
//
// Step 1: Perform Operator Overload location
//
- Expression mg;
- string op_name;
-
op_name = oper_names [(int) Oper];
mg = MemberLookup (ec, expr_type, op_name, MemberTypes.Method, AllBindingFlags, loc);
return this;
case Operator.OnesComplement:
- if (!((expr_type == TypeManager.int32_type) ||
- (expr_type == TypeManager.uint32_type) ||
- (expr_type == TypeManager.int64_type) ||
- (expr_type == TypeManager.uint64_type) ||
- (expr_type.IsSubclassOf (TypeManager.enum_type)))){
- Expression e;
-
- e = ConvertImplicit (ec, Expr, TypeManager.int32_type, loc);
- if (e != null){
- type = TypeManager.int32_type;
- return this;
- }
- e = ConvertImplicit (ec, Expr, TypeManager.uint32_type, loc);
- if (e != null){
- type = TypeManager.uint32_type;
- return this;
- }
- e = ConvertImplicit (ec, Expr, TypeManager.int64_type, loc);
- if (e != null){
- type = TypeManager.int64_type;
- return this;
- }
- e = ConvertImplicit (ec, Expr, TypeManager.uint64_type, loc);
- if (e != null){
- type = TypeManager.uint64_type;
- return this;
+ if (expr_type == TypeManager.string_type ||
+ expr_type == TypeManager.decimal_type ||
+ expr_type == TypeManager.double_type ||
+ expr_type == TypeManager.float_type) {
+ if ((Expr = ConvertImplicit (ec, Expr, TypeManager.int64_type, loc)) == null) {
+ Error23 (Expr.Type);
+ return null;
}
- Error23 (expr_type);
- return null;
+ expr_type = Expr.Type;
+ }
+
+ if (expr_type == TypeManager.int64_type) {
+ type = expr_type;
+ return this;
+ }
+ if (expr_type == TypeManager.byte_type ||
+ expr_type == TypeManager.short_type ||
+ expr_type == TypeManager.int32_type) {
+ type = TypeManager.int32_type;
+ return this;
+ }
+
+ if (expr_type == TypeManager.object_type) {
+ Expression etmp = Parser.DecomposeQI ("Microsoft.VisualBasic.CompilerServices.ObjectType.NotObj", Location.Null);
+ ArrayList arguments = new ArrayList ();
+ arguments.Add (new Argument (Expr, Argument.AType.Expression));
+ Expression e = new Invocation (etmp, arguments, loc);
+ return e.Resolve (ec);
}
- type = expr_type;
- return this;
+ break;
case Operator.AddressOf:
+ // Not required in VB ??
if (Expr.eclass != ExprClass.Variable){
Error (211, "Cannot take the address of non-variables");
return null;
//
// A plus in front of something is just a no-op, so return the child.
//
+ if (expr_type == TypeManager.string_type) {
+ Expression e = ConvertImplicit (ec, Expr, TypeManager.double_type, loc);
+ if (e != null){
+ type = TypeManager.double_type;
+ return e;
+ }
+ }
+
+ if (expr_type == TypeManager.bool_type) {
+ Expression e = ConvertImplicit (ec, Expr, TypeManager.short_type, loc);
+ if (e != null){
+ type = TypeManager.int32_type;
+ return e;
+ }
+ }
+
return Expr;
case Operator.UnaryNegation:
// double operator- (double d)
// decimal operator- (decimal d)
//
- Expression expr = null;
//
// transform - - expr into expr
// It is also not clear if we should convert to Float
// or Double initially.
//
- if (expr_type == TypeManager.uint32_type){
- //
- // FIXME: handle exception to this rule that
- // permits the int value -2147483648 (-2^31) to
- // bt wrote as a decimal interger literal
- //
- type = TypeManager.int64_type;
- Expr = ConvertImplicit (ec, Expr, type, loc);
- return this;
+ if (expr_type == TypeManager.string_type) {
+ Expression e = ConvertImplicit (ec, Expr, TypeManager.double_type, loc);
+ if (e != null){
+ Expr = e;
+ type = TypeManager.double_type;
+ return this;
+ }
}
- if (expr_type == TypeManager.uint64_type){
- //
- // FIXME: Handle exception of 'long value'
- // -92233720368547758087 (-2^63) to be wrote as
- // decimal integer literal.
- //
- Error23 (expr_type);
- return null;
+ if (expr_type == TypeManager.bool_type) {
+ Expression e = ConvertImplicit (ec, Expr, TypeManager.short_type, loc);
+ if (e != null){
+ Expr = e;
+ type = TypeManager.int32_type;
+ return this;
+ }
}
- if (expr_type == TypeManager.float_type){
+ if (expr_type == TypeManager.float_type ||
+ expr_type == TypeManager.double_type) {
type = expr_type;
return this;
}
-
- expr = ConvertImplicit (ec, Expr, TypeManager.int32_type, loc);
- if (expr != null){
- Expr = expr;
- type = expr.Type;
- return this;
- }
- expr = ConvertImplicit (ec, Expr, TypeManager.int64_type, loc);
- if (expr != null){
- Expr = expr;
- type = expr.Type;
+ if (expr_type == TypeManager.short_type ||
+ expr_type == TypeManager.byte_type) {
+ type = TypeManager.int32_type;
return this;
}
- expr = ConvertImplicit (ec, Expr, TypeManager.double_type, loc);
- if (expr != null){
- Expr = expr;
- type = expr.Type;
- return this;
+ if (expr_type == TypeManager.int32_type ||
+ expr_type == TypeManager.int64_type) {
+ Expression e = new Binary (Binary.Operator.Subtraction, new IntLiteral (0), Expr, loc);
+ return e.Resolve (ec);
}
Error23 (expr_type);
if (Expr == null)
return null;
+ Type init_type = Expr.Type;
+
eclass = ExprClass.Value;
- return ResolveOperator (ec);
+ Expression etmp = ResolveOperator (ec);
+ // Convert the result to byte/short if operands are of type byte/short/boolean
+ if (etmp.Type != init_type &&
+ (init_type == TypeManager.byte_type ||
+ init_type == TypeManager.short_type ||
+ init_type == TypeManager.bool_type)) {
+ Expression conv_exp = null;
+ if (init_type == TypeManager.byte_type && Oper != Operator.UnaryNegation) {
+ return new OpcodeCast (etmp, TypeManager.byte_type, OpCodes.Conv_U1);
+ }
+ else
+ conv_exp = ConvertImplicit (ec, etmp, TypeManager.short_type, loc);
+
+ if (conv_exp != null)
+ return conv_exp;
+ }
+ return etmp;
}
public override void Emit (EmitContext ec)
{
ILGenerator ig = ec.ig;
- Type expr_type = Expr.Type;
switch (Oper) {
case Operator.UnaryPlus:
loc = l;
}
+/*
void LoadExprValue (EmitContext ec)
{
}
+*/
public override void Emit (EmitContext ec)
{
"++" : "--";
}
- void Error23 (Type t)
- {
- Error (
- 23, "Operator " + OperName (mode) +
- " cannot be applied to operand of type '" +
- TypeManager.MonoBASIC_Name (t) + "'");
- }
-
/// <summary>
/// Returns whether an object of type 't' can be incremented
/// or decremented with add/sub (ie, basically whether we can
public override Expression DoResolve (EmitContext ec)
{
- probe_type = ec.DeclSpace.ResolveType (ProbeType, false, loc);
+ probe_type = ec.DeclSpace.ResolveType (ProbeType, false, loc);
if (probe_type == null)
return null;
}
}
- public bool IsRuntimeCast\r
+ public bool IsRuntimeCast
{
get {
return runtime_cast;
if (expr == null)
return null;
- int errors = Report.Errors;
-
type = ec.DeclSpace.ResolveType (target_type, false, Location);
if (type == null)
}
}
+ public class StringConcat : Expression {
+
+ Expression left, right;
+ ArrayList Arguments;
+ protected MethodBase method;
+
+ public StringConcat(Location loc, Expression left, Expression right) {
+ this.left = left;
+ this.right = right;
+ this.loc = loc;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ left = left.Resolve (ec);
+ right = right.Resolve (ec);
+
+ if (left == null || right == null)
+ return null;
+
+ if (left.Type == null)
+ throw new Exception (
+ "Resolve returned non null, but did not set the type! (" +
+ left + ") at Line: " + loc.Row);
+ if (right.Type == null)
+ throw new Exception (
+ "Resolve returned non null, but did not set the type! (" +
+ right + ") at Line: "+ loc.Row);
+
+ eclass = ExprClass.Value;
+ if (left is StringConstant && right is StringConstant){
+ return new StringConstant (
+ ((StringConstant) left).Value +
+ ((StringConstant) right).Value);
+ }
+
+ Type l = left.Type;
+ Type r = right.Type;
+
+ if (l == TypeManager.string_type && r == TypeManager.string_type) {
+ type = TypeManager.string_type;
+ method = TypeManager.string_concat_string_string;
+ Arguments = new ArrayList ();
+ Arguments.Add (new Argument (left, Argument.AType.Expression));
+ Arguments.Add (new Argument (right, Argument.AType.Expression));
+ return this;
+ }
+
+ if (l != TypeManager.string_type) {
+ method = TypeManager.string_concat_object_object;
+ left = ConvertImplicit (ec, left, TypeManager.string_type, loc);
+ if (left == null){
+ Error_OperatorCannotBeApplied (loc, "&", l, r);
+ return null;
+ }
+
+ type = TypeManager.string_type;
+ Arguments = new ArrayList ();
+ Arguments.Add (new Argument (left, Argument.AType.Expression));
+ Arguments.Add (new Argument (right, Argument.AType.Expression));
+ return this;
+ }
+
+ if (r != TypeManager.string_type) {
+ method = TypeManager.string_concat_object_object;
+ right = ConvertImplicit (ec, right, TypeManager.string_type, loc);
+ if (right == null){
+ Error_OperatorCannotBeApplied (loc, "&", l, r);
+ return null;
+ }
+
+ type = TypeManager.string_type;
+ Arguments = new ArrayList ();
+ Arguments.Add (new Argument (left, Argument.AType.Expression));
+ Arguments.Add (new Argument (right, Argument.AType.Expression));
+ return this;
+ }
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ ILGenerator ig = ec.ig;
+ if (method != null) {
+ // Note that operators are static anyway
+ if (Arguments != null)
+ Invocation.EmitArguments (ec, method, Arguments);
+ if (method is MethodInfo)
+ ig.Emit (OpCodes.Call, (MethodInfo) method);
+ else
+ ig.Emit (OpCodes.Call, (ConstructorInfo) method);
+
+ return;
+ }
+ }
+
+ static public void Error_OperatorCannotBeApplied (Location loc, string name, Type l, Type r)
+ {
+ Report.Error (19, loc,
+ "Operator " + name + " cannot be applied to operands of type '" +
+ TypeManager.MonoBASIC_Name (l) + "' and '" +
+ TypeManager.MonoBASIC_Name (r) + "'");
+ }
+
+ }
+
+
/// <summary>
/// Binary operators
/// </summary>
public class Binary : Expression {
public enum Operator : byte {
- Multiply, Division, Modulus,
- Addition, Subtraction,
+ Exponentiation,
+ Multiply, Division, IntDivision, Modulus,
+ Addition, Subtraction, Concat,
LeftShift, RightShift,
LessThan, GreaterThan, LessThanOrEqual, GreaterThanOrEqual,
Equality, Inequality,
+ Like,
BitwiseAnd,
ExclusiveOr,
BitwiseOr,
LogicalAnd,
LogicalOr,
+ Is,
TOP
}
oper_names [(int) Operator.Multiply] = "op_Multiply";
oper_names [(int) Operator.Division] = "op_Division";
+ oper_names [(int) Operator.IntDivision] = "op_Division";
oper_names [(int) Operator.Modulus] = "op_Modulus";
oper_names [(int) Operator.Addition] = "op_Addition";
oper_names [(int) Operator.Subtraction] = "op_Subtraction";
oper_names [(int) Operator.ExclusiveOr] = "op_ExclusiveOr";
oper_names [(int) Operator.LogicalOr] = "op_LogicalOr";
oper_names [(int) Operator.LogicalAnd] = "op_LogicalAnd";
+ oper_names [(int) Operator.Is] = "op_Is";
}
public Binary (Operator oper, Expression left, Expression right, Location loc)
{
+ left = Parser.SetValueRequiredFlag (left);
+ right = Parser.SetValueRequiredFlag (right);
this.oper = oper;
this.left = left;
this.right = right;
static string OperName (Operator oper)
{
switch (oper){
+ case Operator.Exponentiation:
+ return "^";
case Operator.Multiply:
return "*";
case Operator.Division:
return "/";
+ case Operator.IntDivision:
+ return "\\";
case Operator.Modulus:
- return "%";
+ return "Mod";
case Operator.Addition:
return "+";
case Operator.Subtraction:
case Operator.GreaterThanOrEqual:
return ">=";
case Operator.Equality:
- return "==";
+ return "=";
case Operator.Inequality:
- return "!=";
+ return "<>";
case Operator.BitwiseAnd:
- return "&";
+ return "And";
case Operator.BitwiseOr:
- return "|";
+ return "Or";
case Operator.ExclusiveOr:
return "^";
case Operator.LogicalOr:
- return "||";
+ return "Or";
case Operator.LogicalAnd:
- return "&&";
+ return "And";
+ case Operator.Is:
+ return "Is";
}
return oper.ToString ();
}
//
- // Note that handling the case l == Decimal || r == Decimal
- // is taken care of by the Step 1 Operator Overload resolution.
+ // Handles boolean types also
//
- bool DoNumericPromotions (EmitContext ec, Type l, Type r)
+ bool DoNumericPromotions (EmitContext ec, Type l, Type r, Operator oper)
{
- if (l == TypeManager.double_type || r == TypeManager.double_type){
+
+ Type conv_left_as = null;
+ Type conv_right_as = null;
+ if (left is NullLiteral)
+ conv_left_as = r;
+ if (right is NullLiteral)
+ conv_right_as = l;
+
+ // Need not do anything for shift operators, as this will be handled by the
+ // 'CheckShiftArguments' method
+ if (oper == Operator.LeftShift || oper == Operator.RightShift)
+ return true;
+ if (l == TypeManager.bool_type && r == TypeManager.bool_type) {
+ if (IsArithmaticOperator (oper) && oper != Operator.Division) {
+ type = TypeManager.int32_type;
+ conv_left_as = conv_right_as = TypeManager.short_type;
+ }
+ }
+
+ if (IsBitwiseOperator (oper)) {
+
+ if (l == TypeManager.decimal_type ||
+ l == TypeManager.double_type ||
+ l == TypeManager.float_type) {
+ conv_left_as = type = TypeManager.int64_type;
+ l = conv_left_as;
+ }
+ if (r == TypeManager.decimal_type ||
+ r == TypeManager.double_type ||
+ r == TypeManager.float_type) {
+ conv_right_as = type = TypeManager.int64_type;
+ r = conv_right_as;
+ }
+ }
+
+ if (oper == Operator.IntDivision) {
+ if (l == TypeManager.decimal_type || r == TypeManager.decimal_type ||
+ l == TypeManager.float_type || r == TypeManager.float_type ||
+ l == TypeManager.double_type || r == TypeManager.double_type)
+ conv_left_as = conv_right_as = TypeManager.int64_type;
+ l = r = TypeManager.int64_type;
+ }
+
+ if (IsLogicalOperator (oper)) {
+ if (l == TypeManager.decimal_type)
+ conv_left_as = TypeManager.bool_type;
+ else if (r == TypeManager.decimal_type)
+ conv_right_as = TypeManager.bool_type;
+ } else if ((l == TypeManager.double_type || r == TypeManager.double_type) ||
+ (oper == Operator.Exponentiation) ||
+ (oper == Operator.Division &&
+ !(l == TypeManager.decimal_type || r == TypeManager.decimal_type))) {
//
// If either operand is of type double, the other operand is
// conveted to type double.
//
- if (r != TypeManager.double_type)
- right = ConvertImplicit (ec, right, TypeManager.double_type, loc);
- if (l != TypeManager.double_type)
- left = ConvertImplicit (ec, left, TypeManager.double_type, loc);
+ type = conv_left_as = conv_right_as = TypeManager.double_type;
- type = TypeManager.double_type;
} else if (l == TypeManager.float_type || r == TypeManager.float_type){
//
// if either operand is of type float, the other operand is
// converted to type float.
//
- if (r != TypeManager.double_type)
- right = ConvertImplicit (ec, right, TypeManager.float_type, loc);
- if (l != TypeManager.double_type)
- left = ConvertImplicit (ec, left, TypeManager.float_type, loc);
- type = TypeManager.float_type;
- } else if (l == TypeManager.uint64_type || r == TypeManager.uint64_type){
- 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 = 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);
- } else {
- e = ImplicitNumericConversion (ec, right, l, loc);
- if (e != null)
- right = e;
- }
- }
- other = right.Type;
- } else {
- if (left is IntConstant){
- e = 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);
- } else {
- e = ImplicitNumericConversion (ec, left, r, loc);
- 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);
- type = TypeManager.uint64_type;
+ type = conv_left_as = conv_right_as = TypeManager.float_type;
+ } else if (l == TypeManager.decimal_type || r == TypeManager.decimal_type){
+ type = conv_left_as = conv_right_as = TypeManager.decimal_type;
} else if (l == TypeManager.int64_type || r == TypeManager.int64_type){
//
// If either operand is of type long, the other operand is converted
// to type long.
//
- if (l != TypeManager.int64_type)
- left = ConvertImplicit (ec, left, TypeManager.int64_type, loc);
- if (r != TypeManager.int64_type)
- right = ConvertImplicit (ec, right, TypeManager.int64_type, loc);
-
- type = TypeManager.int64_type;
- } else if (l == TypeManager.uint32_type || r == TypeManager.uint32_type){
- //
- // 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.
- //
- 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);
-
- 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);
-
- 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 = ConvertImplicit (ec, left, TypeManager.decimal_type, loc);
-
- if (r != TypeManager.decimal_type)
- right = ConvertImplicit (ec, right, TypeManager.decimal_type, loc);
- type = TypeManager.decimal_type;
+ type = conv_left_as = conv_right_as = TypeManager.int64_type;
+ } else if (l == TypeManager.int32_type || r == TypeManager.int32_type){
+ type = conv_left_as = conv_right_as = TypeManager.int32_type;
+ } else if (l == TypeManager.short_type || r == TypeManager.short_type){
+ conv_left_as = conv_right_as = TypeManager.short_type;
+ type = TypeManager.int32_type;
} else {
- left = ForceConversion (ec, left, TypeManager.int32_type);
- right = ForceConversion (ec, right, TypeManager.int32_type);
-
type = TypeManager.int32_type;
}
+ if (conv_left_as != null)
+ left = ConvertImplicit (ec, left, conv_left_as, loc);
+ if (conv_right_as != null)
+ right = ConvertImplicit (ec, right, conv_right_as, loc);
+
return (left != null) && (right != null);
}
static public void Error_OperatorCannotBeApplied (Location loc, string name, Type l, Type r)
{
Report.Error (19, loc,
- "Operator " + name + " cannot be applied to operands of type '" +
+ "Operator '" + name + "' cannot be applied to operands of type '" +
TypeManager.MonoBASIC_Name (l) + "' and '" +
TypeManager.MonoBASIC_Name (r) + "'");
}
Expression CheckShiftArguments (EmitContext ec)
{
Expression e;
- Type l = left.Type;
- Type r = right.Type;
e = ForceConversion (ec, right, TypeManager.int32_type);
if (e == null){
Error_OperatorCannotBeApplied ();
return null;
}
+
+ type = left.Type;
+ if (left is NullLiteral) {
+ type = right.Type;
+ if (right.Type != TypeManager.bool_type) {
+ left = ConvertImplicit (ec, left, right.Type, loc);
+ if (left == null) {
+ Error_OperatorCannotBeApplied (loc, OperName (oper), left.Type, right.Type);
+ return null;
+ }
+ }
+ }
right = e;
- if (((e = ConvertImplicit (ec, left, TypeManager.int32_type, loc)) != null) ||
- ((e = ConvertImplicit (ec, left, TypeManager.uint32_type, loc)) != null) ||
- ((e = ConvertImplicit (ec, left, TypeManager.int64_type, loc)) != null) ||
- ((e = ConvertImplicit (ec, left, TypeManager.uint64_type, loc)) != null)){
- left = e;
- type = e.Type;
+ if (type == TypeManager.bool_type) {
+ left = ConvertImplicit (ec, left, TypeManager.short_type, loc);
+ if (left == null) {
+ Error_OperatorCannotBeApplied (loc, OperName (oper), left.Type, right.Type);
+ return null;
+ }
+ type = left.Type;
+ }
+
+ int mask = 0;
+ if ( type == TypeManager.byte_type)
+ mask = 7;
+ else if (type == TypeManager.short_type || type == TypeManager.bool_type)
+ mask = 15;
+ else if (type == TypeManager.int32_type || type == TypeManager.uint32_type)
+ mask = 31;
+ else
+ mask = 63;
+ if (mask != 0) {
+ right = new Binary (Binary.Operator.BitwiseAnd, right, new IntLiteral (mask), loc);
+ right = right.DoResolve (ec);
+ }
+
+ if (type == TypeManager.byte_type ||
+ type == TypeManager.short_type ||
+ type == TypeManager.int32_type) {
+ type = TypeManager.int32_type;
+ return this;
+ }
+ if (type == TypeManager.int64_type)
+ return this;
+ if ((e = ConvertImplicit (ec, left, TypeManager.int64_type, loc)) != null) {
+ left = e;
+ type = TypeManager.int64_type;
return this;
}
+
Error_OperatorCannotBeApplied ();
return null;
}
+ bool IsRelationalOperator (Binary.Operator oper) {
+ return (oper == Operator.Equality ||
+ oper == Operator.Inequality ||
+ oper == Operator.LessThan ||
+ oper == Operator.LessThanOrEqual ||
+ oper == Operator.GreaterThan ||
+ oper == Operator.GreaterThanOrEqual);
+ }
+
+ bool IsArithmaticOperator (Binary.Operator oper) {
+ return (oper == Operator.Addition ||
+ oper == Operator.Subtraction ||
+ oper == Operator.Multiply ||
+ oper == Operator.Division ||
+ oper == Operator.IntDivision ||
+ oper == Operator.Exponentiation ||
+ oper == Operator.Modulus);
+ }
+
+ bool IsShiftOperator (Binary.Operator oper) {
+ return (oper == Operator.LeftShift ||
+ oper == Operator.RightShift);
+ }
+
+ bool IsLogicalOperator (Binary.Operator oper) {
+ return (oper == Operator.LogicalOr ||
+ oper == Operator.LogicalAnd);
+ }
+
+ bool IsBitwiseOperator (Binary.Operator oper) {
+ return (oper == Operator.BitwiseOr ||
+ oper == Operator.BitwiseAnd ||
+ oper == Operator.ExclusiveOr);
+ }
+
Expression ResolveOperator (EmitContext ec)
{
Type l = left.Type;
Type r = right.Type;
- bool overload_failed = false;
-
- //
- // Step 1: Perform Operator Overload location
- //
Expression left_expr, right_expr;
-
- string op = oper_names [(int) oper];
-
- MethodGroupExpr union;
- left_expr = MemberLookup (ec, l, op, MemberTypes.Method, AllBindingFlags, loc);
- if (r != l){
- right_expr = MemberLookup (
- ec, r, op, MemberTypes.Method, AllBindingFlags, loc);
- union = Invocation.MakeUnionSet (left_expr, right_expr, loc);
- } else
- union = (MethodGroupExpr) left_expr;
-
- if (union != null) {
- Arguments = new ArrayList ();
- Arguments.Add (new Argument (left, Argument.AType.Expression));
- Arguments.Add (new Argument (right, Argument.AType.Expression));
-
- method = Invocation.OverloadResolve (ec, union, Arguments, Location.Null);
- if (method != null) {
- MethodInfo mi = (MethodInfo) method;
-
- type = mi.ReturnType;
- return this;
- } else {
- overload_failed = true;
+ left_expr = right_expr = null;
+
+ if (oper == Operator.Addition && right is Unary) {
+ Unary unary_right = (Unary) right;
+ if (unary_right.Oper == Unary.Operator.UnaryNegation) {
+ oper = Operator.Subtraction;
+ right = unary_right.Expr;
+ r = right.Type;
}
- }
-
- //
- // Step 2: Default operations on CLI native types.
- //
+ }
- //
- // Step 0: String concatenation (because overloading will get this wrong)
- //
- if (oper == Operator.Addition){
- //
- // If any of the arguments is a string, cast to string
- //
-
- if (l == TypeManager.string_type){
-
- if (r == TypeManager.void_type) {
- Error_OperatorCannotBeApplied ();
+ if (TypeManager.IsEnumType (l))
+ l = TypeManager.EnumToUnderlying (l);
+ if (TypeManager.IsEnumType (r))
+ r = TypeManager.EnumToUnderlying (r);
+
+ Type conv_left_as = null;
+ Type conv_right_as = null;
+
+ if ((left is NullLiteral ||(Type.GetTypeCode(l)==TypeCode.DBNull)) && (r.IsValueType || r == TypeManager.string_type)) {
+ // Just treat nothing as the other type, implicit conversion
+ // will return the default value
+ conv_left_as = r;
+ l = r;
+ //incase of DBNull set to NullLiteral
+ left = NullLiteral.Null;
+ }
+
+ if ((right is NullLiteral ||(Type.GetTypeCode(r)==TypeCode.DBNull)) && (l.IsValueType || l == TypeManager.string_type)) {
+ // Just treat nothing as the other type, implicit conversion
+ // will return the default value
+ conv_right_as = l;
+ r = l;
+ right = NullLiteral.Null;
+ }
+
+ // deal with objects and reference types first
+ if (l == TypeManager.object_type || r == TypeManager.object_type) {
+
+ //
+ // operator != (object a, object b)
+ // operator == (object a, object b)
+ //
+ // For this to be used, both arguments have to be reference-types.
+ // Read the rationale on the spec (14.9.6)
+ //
+ // Also, if at compile time we know that the classes do not inherit
+ // one from the other, then we catch the error there.
+
+ // If other type is a value type, convert it to object
+ if (r == TypeManager.object_type &&
+ (l.IsValueType || l == TypeManager.string_type))
+ left = ConvertImplicit (ec, left, TypeManager.object_type, loc);
+ if (l == TypeManager.object_type &&
+ (r.IsValueType || r == TypeManager.string_type))
+ right = ConvertImplicit (ec, right, TypeManager.object_type, loc);
+ if (left == null || right == null) {
+ Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
+ return null;
+ }
+
+ l = left.Type;
+ r = right.Type;
+
+ if (l == TypeManager.object_type && r == TypeManager.object_type) {
+ string fqn = null;
+ switch (oper) {
+ case Operator.Addition :
+ fqn = "ObjectType.AddObj";
+ break;
+ case Operator.Subtraction :
+ fqn = "ObjectType.SubObj";
+ break;
+ case Operator.Multiply :
+ fqn = "ObjectType.MulObj";
+ break;
+ case Operator.Division :
+ fqn = "ObjectType.DivObj";
+ break;
+ case Operator.IntDivision :
+ fqn = "ObjectType.IDivObj";
+ break;
+ case Operator.Modulus :
+ fqn = "ObjectType.ModObj";
+ break;
+ case Operator.Exponentiation :
+ fqn = "ObjectType.PowObj";
+ break;
+ case Operator.Like :
+ fqn = "ObjectType.LikeObj";
+ break;
+ case Operator.Equality :
+ case Operator.Inequality :
+ case Operator.LessThan :
+ case Operator.LessThanOrEqual :
+ case Operator.GreaterThan :
+ case Operator.GreaterThanOrEqual :
+ fqn = "ObjectType.ObjTst";
+ break;
+ case Operator.BitwiseAnd:
+ fqn = "ObjectType.BitAndObj";
+ break;
+ case Operator.BitwiseOr:
+ fqn = "ObjectType.BitOrObj";
+ break;
+ case Operator.ExclusiveOr:
+ fqn = "ObjectType.BitXorObj";
+ break;
+ case Operator.LeftShift:
+ fqn = "ObjectType.ShiftLeftObj";
+ break;
+ case Operator.RightShift:
+ fqn = "ObjectType.ShiftRightObj";
+ break;
+ case Operator.Is:
+ eclass = ExprClass.Value;
+ type = TypeManager.bool_type;
+ return this;
+ }
+
+ if (fqn == null) {
+ Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
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);
- }
-
- // string + string
- method = TypeManager.string_concat_string_string;
- } else {
- // string + object
- method = TypeManager.string_concat_object_object;
- right = ConvertImplicit (ec, right,
- TypeManager.object_type, loc);
- if (right == null){
+
+ if (oper == Operator.LeftShift || oper == Operator.RightShift) {
+ right = ConvertImplicit (ec, right, TypeManager.object_type, loc);
+ if (right == null) {
Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
return null;
}
}
- type = TypeManager.string_type;
-
- Arguments = new ArrayList ();
- Arguments.Add (new Argument (left, Argument.AType.Expression));
- Arguments.Add (new Argument (right, Argument.AType.Expression));
- return this;
-
- } else if (r == TypeManager.string_type){
- // object + string
+ Expression etmp = Mono.MonoBASIC.Parser.DecomposeQI (
+ "Microsoft.VisualBasic.CompilerServices." + fqn,
+ Location.Null);
+
+ ArrayList args = new ArrayList ();
+ args.Add (new Argument (left, Argument.AType.Expression));
+ args.Add (new Argument (right, Argument.AType.Expression));
+ if (IsRelationalOperator (oper))
+ args.Add (new Argument (new BoolConstant (false), Argument.AType.Expression));
+ if (oper == Operator.Like)
+ args.Add (new Argument(new IntLiteral (0), Argument.AType.Expression));
+ Expression e = new Invocation (etmp, args, loc);
+ if (IsRelationalOperator (oper)) {
+ e = new Binary (oper, e.Resolve(ec), new IntConstant (0), loc);
+ }
+ return e.Resolve (ec);
+ } else if (!l.IsValueType || !r.IsValueType) {
+
+ // If one of the operands are reference types and other is object, support for 'Is' operator
+ if (oper == Operator.Is) {
+ eclass = ExprClass.Value;
+ type = TypeManager.bool_type;
+ return this;
+ }
+ }
- if (l == TypeManager.void_type) {
- Error_OperatorCannotBeApplied ();
- return null;
+
+ } else if (!l.IsValueType || !r.IsValueType) {
+
+ if (!l.IsValueType && !r.IsValueType) {
+ // If both the operands are reference types, support for 'Is' operator
+ if (oper == Operator.Is) {
+ eclass = ExprClass.Value;
+ type = TypeManager.bool_type;
+ return this;
+ }
+ }
+ // Either of the operands are reference types
+ if (l.IsSubclassOf (TypeManager.delegate_type) &&
+ r.IsSubclassOf (TypeManager.delegate_type)) {
+ if (oper == Operator.Addition || oper == Operator.Subtraction) {
+ Arguments = new ArrayList ();
+ Arguments.Add (new Argument (left, Argument.AType.Expression));
+ Arguments.Add (new Argument (right, Argument.AType.Expression));
+
+ if (oper == Operator.Addition)
+ method = TypeManager.delegate_combine_delegate_delegate;
+ else
+ method = TypeManager.delegate_remove_delegate_delegate;
+
+ if (l != r) {
+ Error_OperatorCannotBeApplied ();
+ return null;
+ }
+
+ DelegateOperation = true;
+ type = l;
+ return this;
}
-
- method = TypeManager.string_concat_object_object;
- left = ConvertImplicit (ec, left, TypeManager.object_type, loc);
- if (left == null){
+
+ if (oper != Operator.Equality) {
Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
return null;
}
- Arguments = new ArrayList ();
- Arguments.Add (new Argument (left, Argument.AType.Expression));
- Arguments.Add (new Argument (right, Argument.AType.Expression));
-
- type = TypeManager.string_type;
-
- return this;
}
- //
- // Transform a + ( - b) into a - b
- //
- if (right is Unary){
- Unary right_unary = (Unary) right;
+ bool left_is_string = (left.Type == TypeManager.string_type);
+ bool right_is_string = (right.Type == TypeManager.string_type);
- if (right_unary.Oper == Unary.Operator.UnaryNegation){
- oper = Operator.Subtraction;
- right = right_unary.Expr;
- r = right.Type;
+ if (left_is_string || right_is_string) {
+
+ if (left is NullLiteral) {
+ left_is_string = true;
+ l = r;
}
- }
- }
-
- if (oper == Operator.Equality || oper == Operator.Inequality){
- if (l == TypeManager.bool_type || r == TypeManager.bool_type){
- if (r != TypeManager.bool_type || l != TypeManager.bool_type){
- Error_OperatorCannotBeApplied ();
- return null;
+ if (right is NullLiteral) {
+ right_is_string = true;
+ r = l;
}
-
- type = TypeManager.bool_type;
- return this;
- }
+ if (left_is_string && right_is_string) {
+ if (oper == Operator.Addition) {
+ // Both operands are string
+ Expression e = new StringConcat (loc, left, right);
+ return e.Resolve(ec);
+ }
- //
- // operator != (object a, object b)
- // operator == (object a, object b)
- //
- // For this to be used, both arguments have to be reference-types.
- // Read the rationale on the spec (14.9.6)
- //
- // Also, if at compile time we know that the classes do not inherit
- // one from the other, then we catch the error there.
- //
- if (!(l.IsValueType || r.IsValueType)){
- type = TypeManager.bool_type;
+ if (IsRelationalOperator (oper)) {
+
+ Expression etmp = Mono.MonoBASIC.Parser.DecomposeQI ("Microsoft.VisualBasic.CompilerServices.StringType.StrCmp", Location.Null);
+ eclass = ExprClass.Value;
+ type = TypeManager.bool_type;
+ ArrayList args = new ArrayList ();
+ args.Add (new Argument(left, Argument.AType.Expression));
+ args.Add (new Argument(right, Argument.AType.Expression));
+ args.Add (new Argument(new BoolConstant(false), Argument.AType.Expression));
+ Expression e = (Expression) new Invocation (etmp, args, loc);
+ e = new Binary (oper, e.Resolve(ec), new IntConstant(0), loc);
+ return e.Resolve(ec);
+ }
- if (l == r)
- return this;
-
- if (l.IsSubclassOf (r) || r.IsSubclassOf (l))
- return this;
+ if (oper == Operator.Like) {
+ Expression etmp = Mono.MonoBASIC.Parser.DecomposeQI ("Microsoft.VisualBasic.CompilerServices.StringType.StrLike", Location.Null);
+ type = TypeManager.bool_type;
+ ArrayList args = new ArrayList ();
+ args.Add (new Argument(left, Argument.AType.Expression));
+ args.Add (new Argument(right, Argument.AType.Expression));
+ args.Add (new Argument(new IntLiteral (0), Argument.AType.Expression));
+ Expression e = (Expression) new Invocation (etmp, args, loc);
+ return e.Resolve (ec);
+ }
+ }
+ Expression other = right_is_string ? left: right;
+ Type other_type = other.Type;
+
//
- // Also, a standard conversion must exist from either one
+ // Disallow arithmatic / shift / logical operators on dates and characters
//
- if (!(StandardConversionExists (left, r) ||
- StandardConversionExists (right, l))){
- Error_OperatorCannotBeApplied ();
+ if (other_type == TypeManager.date_type || other_type == TypeManager.char_type) {
+ if (!(oper == Operator.Addition || IsRelationalOperator (oper) || oper == Operator.Like)) {
+ Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
+ return null;
+ }
+ }
+
+ if (oper == Operator.Addition) {
+ if (other_type == TypeManager.void_type) {
+ Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
+ return null;
+ }
+ if (other_type == TypeManager.date_type ||
+ other_type == TypeManager.char_type ||
+ other_type == typeof (System.Char[])) {
+ conv_left_as = conv_right_as = TypeManager.string_type;
+ type = TypeManager.string_type;
+ } else {
+ // numeric operand
+ conv_right_as = conv_left_as = TypeManager.double_type;
+ type = TypeManager.double_type;
+ }
+ } else if (IsRelationalOperator (oper)) {
+ if (other_type == TypeManager.char_type || other_type == typeof (System.Char[])) {
+ conv_left_as = conv_right_as = TypeManager.string_type;
+ } else if (other_type == TypeManager.date_type) {
+ conv_right_as = conv_left_as = other_type;
+ } else if (other_type == TypeManager.bool_type) {
+ conv_right_as = conv_left_as = other_type;
+ } else if (! other_type.IsValueType) {
+ // Do Nothing, just return
+ type = TypeManager.bool_type;
+ return this;
+ } else {
+ conv_right_as = conv_left_as = TypeManager.double_type;
+ }
+ type = TypeManager.bool_type;
+
+ } else if (oper == Operator.Like) {
+ conv_left_as = conv_right_as = TypeManager.string_type;
+ } else if (oper == Operator.LeftShift || oper == Operator.RightShift) {
+
+ conv_left_as = TypeManager.int64_type;
+ conv_right_as = TypeManager.int32_type;
+ type = TypeManager.int64_type;
+
+ } else if ( IsLogicalOperator (oper)) {
+ type = conv_right_as = conv_left_as = TypeManager.bool_type;
+ } else if ( IsBitwiseOperator (oper)) {
+
+ if (other_type == TypeManager.bool_type) {
+ conv_right_as = conv_left_as = TypeManager.bool_type;
+ type = TypeManager.bool_type;
+ } else {
+ conv_left_as = conv_right_as = TypeManager.int64_type;
+ type = TypeManager.int64_type;
+ }
+ } else if (oper == Operator.Exponentiation) {
+ conv_left_as = conv_right_as = TypeManager.double_type;
+ } else if (oper == Operator.IntDivision) {
+ conv_left_as = conv_right_as = TypeManager.int64_type;
+ } else {
+ // Arithmatic operators
+ conv_right_as = conv_left_as = TypeManager.double_type;
+ type = TypeManager.double_type;
+ }
+ } else {
+ // Both are not of type string
+ if (oper == Operator.Equality || oper == Operator.Inequality || oper == Operator.Is) {
+ if (l.IsValueType || r.IsValueType) {
+ Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
+ return null;
+ }
+ type = TypeManager.bool_type;
+ return this;
+ } else {
+ Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
return null;
}
- //
- // We are going to have to convert to an object to compare
- //
- if (l != TypeManager.object_type)
- left = new EmptyCast (left, TypeManager.object_type);
- 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 ();
+ } else if (l == TypeManager.date_type || r == TypeManager.date_type) {
+ // Date with string operations handled above
+ // Only other possiblity is date with date
+ if (oper == Operator.Like) {
+ conv_right_as = conv_left_as = TypeManager.string_type;
+ type = TypeManager.bool_type;
+ } else if (l == TypeManager.date_type && r == TypeManager.date_type) {
+ if (oper == Operator.Addition) {
+ conv_left_as = conv_right_as = TypeManager.string_type;
+ } else if (IsRelationalOperator (oper)) {
+ Expression etmp = Mono.MonoBASIC.Parser.DecomposeQI ("System.DateTime.Compare", Location.Null);
+ eclass = ExprClass.Value;
+ type = TypeManager.bool_type;
+ ArrayList args = new ArrayList ();
+ args.Add (new Argument(left, Argument.AType.Expression));
+ args.Add (new Argument(right, Argument.AType.Expression));
+ Expression e = (Expression) new Invocation (etmp, args, loc);
+ e = new Binary (oper, e.Resolve(ec), new IntConstant(0), loc);
+ return e.Resolve(ec);
+ } else {
+ Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
+ return null;
+ }
+ } else {
+ Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
return null;
}
- }
-
- // Only perform numeric promotions on:
- // +, -, *, /, %, &, |, ^, ==, !=, <, >, <=, >=
- //
- if (oper == Operator.Addition || oper == Operator.Subtraction) {
- if (l.IsSubclassOf (TypeManager.delegate_type) &&
- r.IsSubclassOf (TypeManager.delegate_type)) {
-
- Arguments = new ArrayList ();
- Arguments.Add (new Argument (left, Argument.AType.Expression));
- Arguments.Add (new Argument (right, Argument.AType.Expression));
-
+ } else if (l == TypeManager.char_type || r == TypeManager.char_type) {
+ // char op string handled above
+ if (oper == Operator.Like) {
+ conv_right_as = conv_left_as = TypeManager.string_type;
+ type = TypeManager.bool_type;
+ } else if (l == TypeManager.char_type && r == TypeManager.char_type) {
if (oper == Operator.Addition)
- method = TypeManager.delegate_combine_delegate_delegate;
- else
- method = TypeManager.delegate_remove_delegate_delegate;
-
- if (l != r) {
- Error_OperatorCannotBeApplied ();
+ conv_left_as = conv_right_as = TypeManager.string_type;
+ else if (IsRelationalOperator (oper)) {
+ type = TypeManager.bool_type;
+ } else {
+ Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
return null;
}
-
- DelegateOperation = true;
- type = l;
- return this;
+ } else {
+ Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
+ return null;
}
-
- //
- // Pointer arithmetic:
- //
- // T* operator + (T* x, int y);
- // T* operator + (T* x, uint y);
- // T* operator + (T* x, long y);
- // T* operator + (T* x, ulong y);
- //
- // T* operator + (int y, T* x);
- // T* operator + (uint y, T *x);
- // T* operator + (long y, T *x);
- // T* operator + (ulong y, T *x);
- //
- // T* operator - (T* x, int y);
- // T* operator - (T* x, uint y);
- // T* operator - (T* x, long y);
- // T* operator - (T* x, ulong y);
- //
- // long operator - (T* x, T *y)
- //
- if (l.IsPointer){
- if (r.IsPointer && oper == Operator.Subtraction){
- if (r == l)
- return new PointerArithmetic (
- false, left, right, TypeManager.int64_type,
- loc);
+ } else if (l.IsPointer || r.IsPointer) {
+ if (oper == Operator.Addition || oper == Operator.Subtraction) {
+ if (l.IsPointer){
+ if (r.IsPointer && oper == Operator.Subtraction){
+ if (r == l)
+ 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);
- }
-
- //
- // Enumeration operators
- //
- bool lie = TypeManager.IsEnumType (l);
- bool rie = TypeManager.IsEnumType (r);
- if (lie || rie){
- Expression temp;
-
- // U operator - (E e, E f)
- if (lie && rie && oper == Operator.Subtraction){
- if (l == r){
- type = TypeManager.EnumToUnderlying (l);
- return this;
- }
- Error_OperatorCannotBeApplied ();
- return null;
+ } else if (r.IsPointer && is_32_or_64 (l) && oper == Operator.Addition)
+ return new PointerArithmetic (
+ true, right, left, r, loc);
}
-
+
//
- // operator + (E e, U x)
- // operator - (E e, U x)
+ // Pointer comparison
//
- if (oper == Operator.Addition || oper == Operator.Subtraction){
- Type enum_type = lie ? l : r;
- Type other_type = lie ? r : l;
- Type underlying_type = TypeManager.EnumToUnderlying (enum_type);
-;
-
- if (underlying_type != other_type){
- Error_OperatorCannotBeApplied ();
- return null;
+ if (l.IsPointer && r.IsPointer){
+ if (oper == Operator.Equality || oper == Operator.Inequality ||
+ oper == Operator.LessThan || oper == Operator.LessThanOrEqual ||
+ oper == Operator.GreaterThan || oper == Operator.GreaterThanOrEqual){
+ type = TypeManager.bool_type;
+ return this;
}
-
- type = enum_type;
- return this;
}
-
- if (!rie){
- temp = ConvertImplicit (ec, right, l, loc);
- if (temp != null)
- right = temp;
- else {
- Error_OperatorCannotBeApplied ();
- return null;
- }
- } if (!lie){
- temp = ConvertImplicit (ec, left, r, loc);
- if (temp != null){
- left = temp;
- l = r;
- } else {
- Error_OperatorCannotBeApplied ();
- return null;
- }
+ Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
+ return null;
+
+ } else if (oper == Operator.Like) {
+ conv_left_as = conv_right_as = TypeManager.string_type;
+ } else {
+
+ // Numeric Types
+ DoNumericPromotions (ec, l, r, oper);
+ if (left == null || right == null) {
+ Error_OperatorCannotBeApplied (loc, OperName(oper), l, r);
+ return null;
}
- if (oper == Operator.Equality || oper == Operator.Inequality ||
- oper == Operator.LessThanOrEqual || oper == Operator.LessThan ||
- oper == Operator.GreaterThanOrEqual || oper == Operator.GreaterThan){
- type = TypeManager.bool_type;
- return this;
+ l = left.Type;
+ r = right.Type;
+ // Required conversions done by 'DoNumericPromotions' method
+ // So Reset 'conv_left_as', 'conv_right_as'
+ conv_left_as = conv_right_as = null;
+
+ if (l == TypeManager.decimal_type && r == TypeManager.decimal_type) {
+ if (IsRelationalOperator (oper)) {
+ Expression etmp = Mono.MonoBASIC.Parser.DecomposeQI ("System.Decimal.Compare", Location.Null);
+ eclass = ExprClass.Value;
+ type = TypeManager.bool_type;
+ ArrayList args = new ArrayList ();
+ args.Add (new Argument(left, Argument.AType.Expression));
+ args.Add (new Argument(right, Argument.AType.Expression));
+ Expression e = (Expression) new Invocation (etmp, args, loc);
+ e = new Binary (oper, e.Resolve(ec), new IntConstant(0), loc);
+ return e.Resolve(ec);
+ } else if (IsArithmaticOperator (oper)) {
+ string fqn = null;
+ if (oper == Operator.Addition)
+ fqn = "System.Decimal.Add";
+ else if (oper == Operator.Subtraction)
+ fqn = "System.Decimal.Subtract";
+ else if (oper == Operator.Multiply)
+ fqn = "System.Decimal.Multiply";
+ else if (oper == Operator.Division)
+ fqn = "System.Decimal.Divide";
+ else if (oper == Operator.Modulus)
+ fqn = "System.Decimal.Remainder";
+ if (fqn != null) {
+
+ Expression etmp = Mono.MonoBASIC.Parser.DecomposeQI (fqn, Location.Null);
+ eclass = ExprClass.Value;
+ type = TypeManager.decimal_type;
+ ArrayList args = new ArrayList ();
+ args.Add (new Argument(left, Argument.AType.Expression));
+ args.Add (new Argument(right, Argument.AType.Expression));
+ Expression e = (Expression) new Invocation (etmp, args, loc);
+ return e.Resolve (ec);
+ }
+ }
}
+ }
- if (oper == Operator.BitwiseAnd ||
- oper == Operator.BitwiseOr ||
- oper == Operator.ExclusiveOr){
- type = l;
- return this;
+ bool conv_done = false;
+ if (conv_left_as != null && conv_left_as != l) {
+ conv_done = true;
+ left = ConvertImplicit (ec, left, conv_left_as, loc);
+ if (left == null) {
+ Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
+ return null;
}
- Error_OperatorCannotBeApplied ();
- return null;
+ l = left.Type;
}
-
- if (oper == Operator.LeftShift || oper == Operator.RightShift)
- return CheckShiftArguments (ec);
- if (oper == Operator.LogicalOr || oper == Operator.LogicalAnd){
- if (l != TypeManager.bool_type || r != TypeManager.bool_type){
- Error_OperatorCannotBeApplied ();
+ if (conv_right_as != null && conv_right_as != r) {
+ conv_done = true;
+ right = ConvertImplicit (ec, right, conv_right_as, loc);
+ if (right == null) {
+ Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
return null;
}
+ r = right.Type;
+ }
- type = TypeManager.bool_type;
- return this;
- }
+ if (conv_done)
+ return ResolveOperator (ec);
- //
- // 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.Exponentiation) {
+ Expression etmp = Mono.MonoBASIC.Parser.DecomposeQI("System.Math.Pow", loc);
+ ArrayList args = new ArrayList();
+ args.Add (new Argument (left, Argument.AType.Expression));
+ args.Add (new Argument (right, Argument.AType.Expression));
+ Expression e = (Expression) new Invocation (etmp, args, loc);
+ return e.Resolve(ec);
}
-
- //
- // Pointer comparison
- //
- if (l.IsPointer && r.IsPointer){
- if (oper == Operator.Equality || oper == Operator.Inequality ||
- oper == Operator.LessThan || oper == Operator.LessThanOrEqual ||
- oper == Operator.GreaterThan || oper == Operator.GreaterThanOrEqual){
- type = TypeManager.bool_type;
+
+ bool overload_failed = false;
+ string op = oper_names [(int) oper];
+ MethodGroupExpr union = null;
+ left_expr = MemberLookup (ec, l, op, MemberTypes.Method, AllBindingFlags, loc);
+ if (r != l) {
+ right_expr = MemberLookup (
+ ec, r, op, MemberTypes.Method, AllBindingFlags, loc);
+ union = Invocation.MakeUnionSet (left_expr, right_expr, loc);
+ } else
+ union = (MethodGroupExpr) left_expr;
+
+ if (union != null) {
+ Arguments = new ArrayList ();
+ Arguments.Add (new Argument (left, Argument.AType.Expression));
+ Arguments.Add (new Argument (right, Argument.AType.Expression));
+
+ method = Invocation.OverloadResolve (ec, union, Arguments, Location.Null);
+ if (method != null) {
+ MethodInfo mi = (MethodInfo) method;
+
+ type = mi.ReturnType;
return this;
+ } else {
+ overload_failed = true;
}
}
-
- //
- // We are dealing with numbers
- //
- if (overload_failed){
+
+ if (overload_failed) {
Error_OperatorCannotBeApplied ();
return null;
}
- //
- // This will leave left or right set to null if there is an error
- //
- DoNumericPromotions (ec, l, r);
- if (left == null || right == null){
- Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
- return null;
+ if (IsRelationalOperator (oper)) {
+ type = TypeManager.bool_type;
+ if (l == TypeManager.bool_type && r == TypeManager.bool_type) {
+ // Reverse the operator - to make it consistent with vbc
+ if (oper == Operator.LessThan)
+ oper = Operator.GreaterThan;
+ else if (oper == Operator.GreaterThan)
+ oper = Operator.LessThan;
+ else if (oper == Operator.LessThanOrEqual)
+ oper = Operator.GreaterThanOrEqual;
+ else if (oper == Operator.GreaterThanOrEqual)
+ oper = Operator.LessThanOrEqual;
+ }
}
- //
- // 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.int64_type) ||
- (l == TypeManager.uint64_type)))
+ if (IsLogicalOperator (oper))
+ type = TypeManager.bool_type;
+ if (IsBitwiseOperator (oper)) {
+ if (l == r) {
+ if (l == TypeManager.byte_type ||
+ l == TypeManager.short_type ||
+ l == TypeManager.bool_type ||
+ l == TypeManager.int32_type ||
+ l == TypeManager.int64_type)
type = l;
+ else {
+ Error_OperatorCannotBeApplied();
+ return null;
+ }
} else {
- Error_OperatorCannotBeApplied ();
+ Error_OperatorCannotBeApplied();
return null;
}
}
- if (oper == Operator.Equality ||
- oper == Operator.Inequality ||
- oper == Operator.LessThanOrEqual ||
- oper == Operator.LessThan ||
- oper == Operator.GreaterThanOrEqual ||
- oper == Operator.GreaterThan){
- type = TypeManager.bool_type;
+ if (oper == Operator.LeftShift || oper == Operator.RightShift) {
+ return CheckShiftArguments (ec);
}
return this;
}
+
public override Expression DoResolve (EmitContext ec)
{
+ if (oper == Operator.Concat) {
+ Expression e = new StringConcat (loc, left, right);
+ return e.Resolve (ec);
+ }
left = left.Resolve (ec);
right = right.Resolve (ec);
right + ") at Line: "+ loc.Row);
eclass = ExprClass.Value;
+
+ // To support 'Or' argument of AttributeTargets in AttributeUsage
+
+ if (left is EnumConstant && oper != Operator.BitwiseOr) {
+ left = ((EnumConstant) left).WidenToCompilerConstant();
+ }
+
+ if (right is EnumConstant && oper != Operator.BitwiseOr) {
+ right = ((EnumConstant) right).WidenToCompilerConstant();
+ }
if (left is Constant && right is Constant){
Expression e = ConstantFold.BinaryFold (
return e;
}
- return ResolveOperator (ec);
+ Expression etmp = ResolveOperator (ec);
+ Type l = left.Type;
+
+ // if the operands are of type byte/short, convert the result back to short/byte
+ if (l == TypeManager.bool_type || l == TypeManager.short_type || l == TypeManager.byte_type) {
+ if (l == TypeManager.bool_type)
+ l = TypeManager.short_type;
+ if (IsArithmaticOperator (oper) && oper != Operator.Division) {
+ Expression conv_exp = ConvertImplicit (ec, etmp, l, loc);
+ if (conv_exp != null)
+ return conv_exp;
+ }
+ if (IsShiftOperator (oper)) {
+ // No overflow checks are needed
+ if (l == TypeManager.byte_type)
+ return new OpcodeCast (etmp, l, OpCodes.Conv_U1);
+ else
+ return new OpcodeCast (etmp, l, OpCodes.Conv_I2);
+ }
+ }
+
+ return etmp;
}
/// <remarks>
// 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 || oper == Operator.Is){
bool my_on_true = oper == Operator.Inequality ? onTrue : !onTrue;
if (left is NullLiteral){
} else if (!(oper == Operator.LessThan ||
oper == Operator.GreaterThan ||
oper == Operator.LessThanOrEqual ||
- oper == Operator.GreaterThanOrEqual))
+ oper == Operator.GreaterThanOrEqual ||
+ oper == Operator.Is))
return false;
ig.Emit (OpCodes.Blt, target);
break;
+ case Operator.Is:
+ if (onTrue)
+ ig.Emit (OpCodes.Beq, target); //Check this
+ else
+ ig.Emit (OpCodes.Bne_Un_S, target);
+ break;
+
default:
return false;
}
ILGenerator ig = ec.ig;
Type l = left.Type;
Type r = right.Type;
+ //Type r = right.Type;
OpCode opcode;
if (method != null) {
// Handle short-circuit operators differently
// than the rest
//
- if (oper == Operator.LogicalAnd){
+ if (IsLogicalOperator (oper)) {
Label load_zero = ig.DefineLabel ();
+ Label load_one = ig.DefineLabel ();
Label end = ig.DefineLabel ();
left.Emit (ec);
- ig.Emit (OpCodes.Brfalse, load_zero);
+ if (l != TypeManager.bool_type) {
+ if (l == TypeManager.int64_type) {
+ ec.ig.Emit (OpCodes.Ldc_I8, 0L);
+ ec.ig.Emit (OpCodes.Cgt_Un);
+ } else if (l == TypeManager.float_type) {
+ ec.ig.Emit (OpCodes.Ldc_R4, 0.0F);
+ ec.ig.Emit (OpCodes.Ceq);
+ ec.ig.Emit (OpCodes.Ldc_I4_0);
+ ec.ig.Emit (OpCodes.Ceq);
+ } else if (l == TypeManager.double_type) {
+ ec.ig.Emit (OpCodes.Ldc_R8, 0.0);
+ ec.ig.Emit (OpCodes.Ceq);
+ ec.ig.Emit (OpCodes.Ldc_I4_0);
+ ec.ig.Emit (OpCodes.Ceq);
+ } else {
+ ec.ig.Emit (OpCodes.Ldc_I4_0);
+ ec.ig.Emit (OpCodes.Cgt_Un);
+ }
+ }
+ if (oper == Operator.LogicalAnd)
+ ig.Emit (OpCodes.Brfalse, load_zero);
+ else
+ ig.Emit (OpCodes.Brtrue, load_one);
+
right.Emit (ec);
- ig.Emit (OpCodes.Br, end);
+ if (r != TypeManager.bool_type) {
+ if (r == TypeManager.int64_type) {
+ ec.ig.Emit (OpCodes.Ldc_I8, 0L);
+ ec.ig.Emit (OpCodes.Cgt_Un);
+ } else if (r == TypeManager.float_type) {
+ ec.ig.Emit (OpCodes.Ldc_R4, 0.0F);
+ ec.ig.Emit (OpCodes.Ceq);
+ ec.ig.Emit (OpCodes.Ldc_I4_0);
+ ec.ig.Emit (OpCodes.Ceq);
+ } else if (r == TypeManager.double_type) {
+ ec.ig.Emit (OpCodes.Ldc_R8, 0.0);
+ ec.ig.Emit (OpCodes.Ceq);
+ ec.ig.Emit (OpCodes.Ldc_I4_0);
+ ec.ig.Emit (OpCodes.Ceq);
+ } else {
+ ec.ig.Emit (OpCodes.Ldc_I4_0);
+ ec.ig.Emit (OpCodes.Cgt_Un);
+ }
+ }
+ ig.Emit (OpCodes.Brtrue, load_one);
ig.MarkLabel (load_zero);
ig.Emit (OpCodes.Ldc_I4_0);
- ig.MarkLabel (end);
- return;
- } else if (oper == Operator.LogicalOr){
- Label load_one = ig.DefineLabel ();
- Label end = ig.DefineLabel ();
-
- 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);
break;
case Operator.Division:
+ case Operator.IntDivision:
if (l == TypeManager.uint32_type || l == TypeManager.uint64_type)
opcode = OpCodes.Div_Un;
else
break;
case Operator.Equality:
+ case Operator.Is:
opcode = OpCodes.Ceq;
break;
{
VariableInfo vi = VariableInfo;
- if (ec.DoFlowAnalysis)
+ if (ec.DoFlowAnalysis) {
ec.SetVariableAssigned (vi);
+ }
Expression e = DoResolve (ec);
VariableInfo vi = VariableInfo;
ILGenerator ig = ec.ig;
- ig.Emit (OpCodes.Ldloc, vi.LocalBuilder);
+ if (vi.Alias != null && vi.Static) {
+ ArrayList fields = ec.TypeContainer.Fields;
+ FieldBase fb = null;
+ for (int i = 0; i < fields.Count; i++) {
+ if (((Field) fields[i]).Name == vi.Alias) {
+ fb = (Field) fields[i];
+ break;
+ }
+ }
+ if ((fb.ModFlags & Modifiers.STATIC) != 0)
+ ig.Emit (OpCodes.Ldsfld, fb.FieldBuilder);
+ else {
+ ig.Emit (OpCodes.Ldarg_0);
+ ig.Emit (OpCodes.Ldfld, fb.FieldBuilder);
+ }
+ } else
+ ig.Emit (OpCodes.Ldloc, vi.LocalBuilder);
+
vi.Used = true;
}
vi.Assigned = true;
- source.Emit (ec);
-
- ig.Emit (OpCodes.Stloc, vi.LocalBuilder);
+ if (vi.Alias != null && vi.Static) {
+ ArrayList fields = ec.TypeContainer.Fields;
+ FieldBase fb = null;
+ for (int i = 0; i < fields.Count; i++) {
+ if (((Field) fields[i]).Name == vi.Alias) {
+ fb = (Field) fields[i];
+ break;
+ }
+ }
+ if ((fb.ModFlags & Modifiers.STATIC) != 0) {
+ source.Emit (ec);
+ ig.Emit (OpCodes.Stsfld, fb.FieldBuilder);
+ }
+ else {
+ ig.Emit (OpCodes.Ldarg_0);
+ source.Emit (ec);
+ ig.Emit (OpCodes.Stfld, fb.FieldBuilder);
+ }
+ }
+ else {
+ source.Emit (ec);
+ ig.Emit (OpCodes.Stloc, vi.LocalBuilder);
+ }
}
public void AddressOf (EmitContext ec, AddressOp mode)
{
VariableInfo vi = VariableInfo;
- ec.ig.Emit (OpCodes.Ldloca, vi.LocalBuilder);
+ if (vi.Alias != null && vi.Static) {
+ ArrayList fields = ec.TypeContainer.Fields;
+ FieldBase fb = null;
+ for (int i = 0; i < fields.Count; i++) {
+ if (((Field) fields[i]).Name == vi.Alias) {
+ fb = (Field) fields[i];
+ break;
+ }
+ }
+ if ((fb.ModFlags & Modifiers.STATIC) != 0)
+ ec.ig.Emit (OpCodes.Ldsflda, fb.FieldBuilder);
+ else {
+ ec.ig.Emit (OpCodes.Ldarg_0);
+ ec.ig.Emit (OpCodes.Ldflda, fb.FieldBuilder);
+ }
+ } else
+ ec.ig.Emit (OpCodes.Ldloca, vi.LocalBuilder);
}
}
{
type = pars.GetParameterInfo (ec.DeclSpace, idx, out mod);
is_ref = (mod & Parameter.Modifier.ISBYREF) != 0;
- is_out = (mod & Parameter.Modifier.OUT) != 0;
+ // is_out = (mod & Parameter.Modifier.OUT) != 0;
eclass = ExprClass.Variable;
- if (is_out && ec.DoFlowAnalysis && !IsAssigned (ec, loc))
+ /* if (is_out && ec.DoFlowAnalysis && !IsAssigned (ec, loc))
return null;
-
+ */
return this;
}
{
type = pars.GetParameterInfo (ec.DeclSpace, idx, out mod);
is_ref = (mod & Parameter.Modifier.ISBYREF) != 0;
- is_out = (mod & Parameter.Modifier.OUT) != 0;
+ // is_out = (mod & Parameter.Modifier.OUT) != 0;
eclass = ExprClass.Variable;
-
+ /*
if (is_out && ec.DoFlowAnalysis)
ec.SetParameterAssigned (idx);
-
+ */
return this;
}
public Expression expr;
MethodBase method = null;
bool is_base;
+ bool is_latebinding;
bool is_left_hand; // Needed for late bound calls
+ bool is_retval_required; // Needed for late bound calls
static Hashtable method_parameter_cache;
- static MemberFilter CompareName;
+ //static MemberFilter CompareName;
+
+ static ArrayList tempvars; // For ByRef - different parameter and argument type
+ static bool is_byref_conversion = false; //For ByRef when it is converted
+ static string errorMsg = "";
static Invocation ()
{
public Invocation (Expression expr, ArrayList arguments, Location l)
{
this.expr = expr;
+ if (this.expr is MemberAccess)
+ ((MemberAccess) this.expr).IsInvocation = true;
+ if (this.expr is SimpleName)
+ ((SimpleName) this.expr).IsInvocation = true;
+ this.is_retval_required = false;
+ this.is_left_hand = false;
Arguments = arguments;
loc = l;
- CompareName = new MemberFilter (compare_name_filter);
+ //CompareName = new MemberFilter (compare_name_filter);
}
public Expression Expr {
}
}
+ public bool IsLeftHand {
+ get {
+ return is_left_hand;
+ }
+ set {
+ is_left_hand = value;
+ }
+ }
+
+ public bool IsRetvalRequired {
+ get {
+ return is_retval_required;
+ }
+ set {
+ is_retval_required = value;
+ }
+ }
+
+ public bool IsLateBinding {
+ get {
+ return is_latebinding;
+ }
+ set {
+ is_latebinding = value;
+ }
+ }
+
/// <summary>
/// Returns the Parameters (a ParameterData interface) for the
/// Method 'mb'
return (ParameterData) ip;
} else {
ParameterInfo [] pi = mb.GetParameters ();
+
ReflectionParameters rp = new ReflectionParameters (pi);
method_parameter_cache [mb] = rp;
}
}
- /// <summary>
- /// Determines "better conversion" as specified in 7.4.2.3
- /// Returns : 1 if a->p is better
- /// 0 if a->q or neither is better
- /// </summary>
- static int BetterConversion (EmitContext ec, Argument a, Type p, Type q, Location loc)
- {
- Type argument_type = a.Type;
- Expression argument_expr = a.Expr;
-
- if (argument_type == null)
- throw new Exception ("Expression of type " + a.Expr + " does not resolve its type");
+ enum Applicability { Same, Better, Worse };
- //
- // This is a special case since csc behaves this way. I can't find
- // it anywhere in the spec but oh well ...
- //
- if (argument_expr is NullLiteral && p == TypeManager.string_type && q == TypeManager.object_type)
- return 1;
- else if (argument_expr is NullLiteral && p == TypeManager.object_type && q == TypeManager.string_type)
- return 0;
-
- if (p == q)
- return 0;
-
- if (argument_type == p)
- return 1;
-
- 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 (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 (value >= UInt16.MinValue && value <= UInt16.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
- //
- if (value >= 0)
- 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 = ConvertImplicit (ec, argument_expr, p, loc);
-
- if (tmp != null)
- return 1;
- else
- return 0;
- }
-
- Expression p_tmp = new EmptyExpression (p);
- Expression q_tmp = new EmptyExpression (q);
-
- if (StandardConversionExists (p_tmp, q) == true &&
- StandardConversionExists (q_tmp, p) == false)
- return 1;
-
- if (p == TypeManager.sbyte_type)
- if (q == TypeManager.byte_type || q == TypeManager.ushort_type ||
- q == TypeManager.uint32_type || q == TypeManager.uint64_type)
- return 1;
-
- if (p == TypeManager.short_type)
- if (q == TypeManager.ushort_type || q == TypeManager.uint32_type ||
- q == TypeManager.uint64_type)
- return 1;
-
- if (p == TypeManager.int32_type)
- if (q == TypeManager.uint32_type || q == TypeManager.uint64_type)
- return 1;
-
- if (p == TypeManager.int64_type)
- if (q == TypeManager.uint64_type)
- return 1;
-
- return 0;
- }
-
/// <summary>
/// Determines "Better function"
/// </summary>
/// 0 if candidate ain't better
/// 1 if candidate is better than the current best match
/// </remarks>
- static int BetterFunction (EmitContext ec, ArrayList args,
- MethodBase candidate, MethodBase best,
- bool expanded_form, Location loc)
+ static Applicability BetterFunction (EmitContext ec, ArrayList args,
+ MethodBase candidate, MethodBase best,
+ bool expanded_form, Location loc)
{
ParameterData candidate_pd = GetParameterData (candidate);
ParameterData best_pd;
int argument_count;
-
+
if (args == null)
argument_count = 0;
else
- argument_count = args.Count;
-
- int cand_count = candidate_pd.Count;
-
- if (cand_count == 0 && argument_count == 0)
- return 1;
-
- if (candidate_pd.ParameterModifier (cand_count - 1) != Parameter.Modifier.PARAMS)
- if (cand_count != argument_count)
- return 0;
-
- if (best == null) {
- int x = 0;
-
- if (argument_count == 0 && cand_count == 1 &&
- candidate_pd.ParameterModifier (cand_count - 1) == Parameter.Modifier.PARAMS)
- return 1;
-
- for (int j = argument_count; j > 0;) {
- j--;
-
- Argument a = (Argument) args [j];
- Type t = candidate_pd.ParameterType (j);
-
- if (candidate_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
- if (expanded_form)
- t = t.GetElementType ();
-
- x = BetterConversion (ec, a, t, null, loc);
-
- if (x <= 0)
- break;
- }
+ argument_count = args.Count;
- if (x > 0)
- return 1;
- else
- return 0;
- }
+ int cand_count = candidate_pd.Count;
- best_pd = GetParameterData (best);
+ if (cand_count == 0 && argument_count == 0)
+ return Applicability.Same;
- int rating1 = 0, rating2 = 0;
+ if (candidate_pd.ParameterModifier (cand_count - 1) != Parameter.Modifier.PARAMS)
+ if (cand_count != argument_count)
+ return Applicability.Worse;
+ best_pd = GetParameterData (best);
+
+ Applicability res = Applicability.Same;
+
for (int j = 0; j < argument_count; ++j) {
- int x, y;
- Argument a = (Argument) args [j];
+ //Argument a = (Argument) args [j];
Type ct = candidate_pd.ParameterType (j);
Type bt = best_pd.ParameterType (j);
if (expanded_form)
bt = bt.GetElementType ();
- x = BetterConversion (ec, a, ct, bt, loc);
- y = BetterConversion (ec, a, bt, ct, loc);
-
- if (x < y)
- return 0;
-
- rating1 += x;
- rating2 += y;
+ if (ct != bt) {
+ if (!WideningConversionExists (ct, bt))
+ return Applicability.Worse;
+ res = Applicability.Better;
+ }
}
- if (rating1 > rating2)
- return 1;
- else
- return 0;
+ if (res == Applicability.Same)
+ if (candidate_pd.Count < best_pd.Count)
+ res = Applicability.Better;
+ else if (candidate_pd.Count > best_pd.Count)
+ res = Applicability.Worse;
+
+ return res;
}
public static string FullMethodDesc (MethodBase mb)
return union;
}
- /// <summary>
- /// Determines is 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)
- {
- int arg_count;
-
- if (arguments == null)
- arg_count = 0;
- else
- arg_count = arguments.Count;
-
- ParameterData pd = GetParameterData (candidate);
-
- 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;
-
- //
- // 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];
-
- Parameter.Modifier a_mod = a.GetParameterModifier () &
- ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);
- Parameter.Modifier p_mod = pd.ParameterModifier (i) &
- ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);
-
- if (a_mod == p_mod) {
-
- if (a_mod == Parameter.Modifier.NONE)
- if (!ImplicitConversionExists (ec, a.Expr, pd.ParameterType (i)))
- return false;
-
- if ((a_mod & Parameter.Modifier.ISBYREF) != 0) {
- Type pt = pd.ParameterType (i);
-
- if (!pt.IsByRef)
- pt = TypeManager.LookupType (pt.FullName + "&");
-
- if (pt != a.Type)
- return false;
- }
- } else
- return false;
-
- }
- Type element_type = pd.ParameterType (pd_count - 1).GetElementType ();
+ protected enum ConversionType { None, Widening, Narrowing };
- for (int i = pd_count - 1; i < arg_count; i++) {
- Argument a = (Argument) arguments [i];
-
- if (!StandardConversionExists (a.Expr, element_type))
- return false;
+ static ConversionType CheckParameterAgainstArgument (EmitContext ec, ParameterData pd, int i, Argument a, Type ptype)
+ {
+ if (a.ArgType == Argument.AType.NoArg) {
+ return ConversionType.Widening;
}
-
- return true;
- }
- static bool CheckParameterAgainstArgument (EmitContext ec, ParameterData pd, int i, Argument a, Type ptype)
- {
Parameter.Modifier a_mod = a.GetParameterModifier () &
- ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);
+ ~(Parameter.Modifier.REF);
Parameter.Modifier p_mod = pd.ParameterModifier (i) &
- ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);
+ ~(Parameter.Modifier.REF | Parameter.Modifier.OPTIONAL);
- if (a_mod == p_mod || (a_mod == Parameter.Modifier.NONE && p_mod == Parameter.Modifier.PARAMS)) {
- if (a_mod == Parameter.Modifier.NONE)
- if (! (ImplicitConversionExists (ec, a.Expr, ptype) || RuntimeConversionExists (ec, a.Expr, ptype)) )
- return false;
+ if (a_mod == p_mod ||
+ (a_mod == Parameter.Modifier.NONE && p_mod == Parameter.Modifier.PARAMS)) {
+ // if (a_mod == Parameter.Modifier.NONE) {
+ if (! WideningConversionExists (a.Expr, ptype) ) {
+
+ if (! NarrowingConversionExists (ec, a.Expr, ptype) )
+ return ConversionType.None;
+ else
+ return ConversionType.Narrowing;
+ } else
+ return ConversionType.Widening;
+ // }
+/*
if ((a_mod & Parameter.Modifier.ISBYREF) != 0) {
Type pt = pd.ParameterType (i);
pt = TypeManager.LookupType (pt.FullName + "&");
if (pt != a.Type)
- return false;
+ return ConversionType.None;
}
+ return ConversionType.Widening;
+*/
} else
- return false;
- return true;
+ return ConversionType.None;
}
-
+
+ static bool HasArrayParameter (ParameterData pd)
+ {
+ int c = pd.Count;
+ return c > 0 && (pd.ParameterModifier (c - 1) & Parameter.Modifier.PARAMS) != 0;
+ }
+
+ static int CountStandardParams (ParameterData pd)
+ {
+ int count = pd.Count;
+ for (int i = 0; i < count; i++) {
+ Parameter.Modifier pm = pd.ParameterModifier (i);
+ if ((pm & (Parameter.Modifier.OPTIONAL | Parameter.Modifier.PARAMS)) != 0)
+ return i;
+ }
+ return count;
+ }
+
+ static ConversionType IsApplicable (EmitContext ec, ArrayList arguments, MethodBase candidate,
+ out bool expanded)
+ {
+ bool objectArgsPresent;
+ return IsApplicable (ec, arguments, candidate, out expanded, out objectArgsPresent);
+ }
+
/// <summary>
/// Determines if the candidate method is applicable (section 14.4.2.1)
/// to the given set of arguments
/// </summary>
- static bool IsApplicable (EmitContext ec, ref ArrayList arguments, MethodBase candidate)
+ static ConversionType IsApplicable (EmitContext ec, ArrayList arguments, MethodBase candidate,
+ out bool expanded, out bool objectArgsPresent)
{
- int arg_count, ps_count, po_count;
+ int arg_count;
Type param_type;
+
+ expanded = objectArgsPresent = false;
+ int num_narr_conv = 0; // Count the narrowing conversion not involving object
+ // arguments
if (arguments == null)
arg_count = 0;
arg_count = arguments.Count;
ParameterData pd = GetParameterData (candidate);
- Parameters ps = GetFullParameters (candidate);
-
- if (ps == null) {
- ps_count = 0;
- po_count = 0;
- }
- else {
- ps_count = ps.CountStandardParams();
- po_count = ps.CountOptionalParams();
- }
+ int ps_count = CountStandardParams (pd);
int pd_count = pd.Count;
// Validate argument count
- if (po_count == 0) {
- if (arg_count != pd.Count)
- return false;
+ if (ps_count == pd_count) {
+ if (arg_count != pd_count)
+ return ConversionType.None;
}
else {
- if ((arg_count < ps_count) || (arg_count > pd_count))
- return false;
+ if (arg_count < ps_count)
+ return ConversionType.None;
+ if (!HasArrayParameter (pd) && arg_count > pd_count)
+ return ConversionType.None;
}
-
- if (arg_count > 0) {
- for (int i = arg_count; i > 0 ; ) {
- i--;
+ ConversionType result = ConversionType.Widening;
+ if (arg_count > 0) {
+ result = ConversionType.None;
+ int array_param_index = -1;
+ for (int i = 0; i < arg_count; ++i) {
Argument a = (Argument) arguments [i];
- if (a.ArgType == Argument.AType.NoArg) {
- Parameter p = (Parameter) ps.FixedParameters[i];
- a = new Argument (p.ParameterInitializer, Argument.AType.Expression);
- param_type = p.ParameterInitializer.Type;
- }
- else {
- param_type = pd.ParameterType (i);
- if (ps != null) {
- Parameter p = (Parameter) ps.FixedParameters[i];
- bool IsDelegate = TypeManager.IsDelegateType (param_type);
-
- if (IsDelegate) {
- if (a.ArgType == Argument.AType.AddressOf) {
- a = new Argument ((Expression) a.Expr, Argument.AType.Expression);
- ArrayList args = new ArrayList();
- args.Add (a);
- string param_name = param_type.Name;
- Expression pname = MonoBASIC.Parser.DecomposeQI (param_name, Location.Null);
-
- New temp_new = new New ((Expression)pname, args, Location.Null);
- Expression del_temp = temp_new.DoResolve(ec);
-
- if (del_temp == null)
- return false;
-
- a = new Argument (del_temp, Argument.AType.Expression);
- if (!a.Resolve(ec, Location.Null))\r
- return false;
- }
- }
- else {
- if (a.ArgType == Argument.AType.AddressOf)
- return false;
- }
+ param_type = pd.ParameterType (i);
+ Parameter.Modifier mod = pd.ParameterModifier (i);
+ if (array_param_index < 0 && (mod & Parameter.Modifier.PARAMS) != 0)
+ array_param_index = i;
- if ((p.ModFlags & Parameter.Modifier.REF) != 0) {
- a = new Argument (a.Expr, Argument.AType.Ref);
- if (!a.Resolve(ec,Location.Null))
- return false;
- }
+ bool IsDelegate = TypeManager.IsDelegateType (param_type);
+
+ if (IsDelegate) {
+ if (a.ArgType == Argument.AType.AddressOf) {
+ a = new Argument ((Expression) a.Expr, Argument.AType.Expression);
+ ArrayList args = new ArrayList();
+ args.Add (a);
+ string param_name = pd.ParameterDesc(i).Replace('+', '.');
+ Expression pname = MonoBASIC.Parser.DecomposeQI (param_name, Location.Null);
+
+ New temp_new = new New ((Expression)pname, args, Location.Null);
+ Expression del_temp = temp_new.DoResolve(ec);
+
+ if (del_temp == null)
+ return ConversionType.None;
+
+ a = new Argument (del_temp, Argument.AType.Expression);
+ if (!a.Resolve(ec, Location.Null))
+ return ConversionType.None;
}
- }
-\r
- if (!CheckParameterAgainstArgument (ec, pd, i, a, param_type))
- return (false);
- }
- }
- else {
- // If we have no arguments AND the first parameter is optional
- // we must check for a candidate (the loop above wouldn't)
- if (po_count > 0) {
- ArrayList arglist = new ArrayList();
-
- // Since we got so far, there's no need to check if
- // arguments are optional; we simply retrieve
- // parameter default values and build a brand-new
- // argument list.
-
- for (int i = 0; i < ps.FixedParameters.Length; i++) {
- Parameter p = ps.FixedParameters[i];
- Argument a = new Argument (p.ParameterInitializer, Argument.AType.Expression);
- a.Resolve(ec, Location.Null);
- arglist.Add (a);
}
- arguments = arglist;
- return true;
- }
- }
- // We've found a candidate, so we exchange the dummy NoArg arguments
- // with new arguments containing the default value for that parameter
-
- ArrayList newarglist = new ArrayList();
- for (int i = 0; i < arg_count; i++) {
- Argument a = (Argument) arguments [i];
- Parameter p = null;
+ else {
+ if (a.ArgType == Argument.AType.AddressOf)
+ return ConversionType.None;
+ }
- if (ps != null)
- p = (Parameter) ps.FixedParameters[i];
+ if (a.ArgType != Argument.AType.NoArg && (mod & Parameter.Modifier.REF) != 0) {
+ a = new Argument (a.Expr, Argument.AType.Ref);
+ if (!a.Resolve(ec,Location.Null))
+ return ConversionType.None;
+ }
- if (a.ArgType == Argument.AType.NoArg){
- a = new Argument (p.ParameterInitializer, Argument.AType.Expression);
- a.Resolve(ec, Location.Null);
+ ConversionType match = ConversionType.None;
+ if (i == array_param_index)
+ match = CheckParameterAgainstArgument (ec, pd, i, a, param_type);
+ if (match == ConversionType.None && array_param_index >= 0 && i >= array_param_index) {
+ expanded = true;
+ param_type = param_type.GetElementType ();
+ }
+ if (match == ConversionType.None)
+ match = CheckParameterAgainstArgument (ec, pd, i, a, param_type);
+ if (match == ConversionType.None)
+ return ConversionType.None;
+
+ if (match == ConversionType.Narrowing) {
+ result = match;
+ if (a.Expr.Type == TypeManager.object_type)
+ objectArgsPresent = true;
+ else {
+ objectArgsPresent = false;
+ num_narr_conv ++;
+ }
+ } else if (result == ConversionType.None)
+ result = match;
}
+ }
- // ToDo - This part is getting resolved second time within this function
- // This is a costly operation
- // The earlier resoved result should be used here.
- // Has to be done during compiler optimization.
- if (a.ArgType == Argument.AType.AddressOf) {
- param_type = pd.ParameterType (i);
- bool IsDelegate = TypeManager.IsDelegateType (param_type);
-
- a = new Argument ((Expression) a.Expr, Argument.AType.Expression);
- ArrayList args = new ArrayList();
- args.Add (a);
- string param_name = param_type.Name;
- Expression pname = MonoBASIC.Parser.DecomposeQI (param_name, Location.Null);
-
- New temp_new = new New ((Expression)pname, args, Location.Null);
- Expression del_temp = temp_new.DoResolve(ec);
+ if (num_narr_conv > 0) // There were narrowing conversions other than those for object arguments
+ objectArgsPresent = false;
- if (del_temp == null)
- return false;
+ return result;
+ }
- a = new Argument (del_temp, Argument.AType.Expression);
- if (!a.Resolve(ec, Location.Null))\r
- return false;
+ internal static ArrayList ReorderArguments (MethodBase mb,
+ ArrayList Arguments,
+ CaseInsensitiveHashtable namedArgs,
+ ref string ErrMsg,
+ Location loc)
+ {
+ ArrayList orderedArgs = new ArrayList ();
+ ParameterData pd = GetParameterData (mb);
+ bool error = false;
+ for (int index = 0; index < pd.Count; index ++) {
+ string paramName = pd.ParameterName (index);
+ if (namedArgs.Contains (paramName)) {
+ if ((pd.ParameterModifier (index) & Parameter.Modifier.PARAMS) == Parameter.Modifier.PARAMS) {
+ error = true;
+ ErrMsg += "\n\t'" + FullMethodDesc (mb) + "': Named argument cannot match a ParamArray parameter";
+ continue;
+ }
+ int argIndex = (int) namedArgs [paramName];
+ orderedArgs.Add (Arguments [argIndex]);
+ } else {
+ Parameter.Modifier p_mod = pd.ParameterModifier (index) & Parameter.Modifier.OPTIONAL;
+ if (p_mod == Parameter.Modifier.OPTIONAL)
+ orderedArgs.Add (new Argument (pd.ParameterName (index), new EmptyExpression (), Argument.AType.NoArg));
+ else {
+ error = true;
+ ErrMsg += "\n\t'" + FullMethodDesc (mb) + "': Argument not specified for parameter '" + paramName + "'";
+ }
}
+ }
- if ((p != null) && ((p.ModFlags & Parameter.Modifier.REF) != 0)) {
- a.ArgType = Argument.AType.Ref;
- a.Resolve(ec, Location.Null);
- }
- newarglist.Add(a);
- int n = pd_count - arg_count;
- if (n > 0) {
- for (int x = 0; x < n; x++) {
- Parameter op = (Parameter) ps.FixedParameters[x + arg_count];
- Argument b = new Argument (op.ParameterInitializer, Argument.AType.Expression);
- b.Resolve(ec, Location.Null);
- newarglist.Add (b);
+ if (Arguments.Count > orderedArgs.Count) {
+ for (int argIndex = 0; argIndex < Arguments.Count; argIndex ++) {
+ string argName = ((Argument) Arguments [argIndex]).ParamName;
+ bool found = false;
+ for (int paramIndex = 0; paramIndex < pd.Count; paramIndex ++) {
+ string paramName = pd.ParameterName (paramIndex);
+ if (String.Compare (argName, paramName, true) == 0) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ error = true;
+ ErrMsg += "\n\t'" + FullMethodDesc (mb) + "': '" + argName + "' is not a parameter";
}
}
}
- arguments = newarglist;
- return true;
+ if (error)
+ return null;
+ return orderedArgs;
}
+/*
static bool compare_name_filter (MemberInfo m, object filterCriteria)
{
return (m.Name == ((string) filterCriteria));
}
+*/
- static Parameters GetFullParameters (MethodBase mb)
+ public static MethodBase OverloadResolve (EmitContext ec, MethodGroupExpr me,
+ ref ArrayList Arguments, Location loc)
{
- TypeContainer tc = TypeManager.LookupTypeContainer (mb.DeclaringType);
- InternalParameters ip = TypeManager.LookupParametersByBuilder(mb);
-
- return (ip != null) ? ip.Parameters : null;
+ bool isLateBindingRequired;
+ return OverloadResolve (ec, me, ref Arguments, loc, out isLateBindingRequired);
}
-
+
// We need an overload for OverloadResolve because Invocation.DoResolve
// must pass Arguments by reference, since a later call to IsApplicable
// can change the argument list if optional parameters are defined
ArrayList a = Arguments;
return OverloadResolve (ec, me, ref a, loc);
}
+
+/*
+ static string ToString(MethodBase mbase)
+ {
+ if (mbase == null)
+ return "NULL";
+
+ if (mbase is MethodBuilder)
+ {
+ MethodBuilder mb = (MethodBuilder) mbase;
+ String res = mb.ReturnType + " (";
+ ParameterInfo [] parms = mb.GetParameters();
+ for (int i = 0; i < parms.Length; i++) {
+ if (i != 0)
+ res += " ";
+ res += parms[i].ParameterType;
+ }
+ res += ")";
+ return res;
+ }
+
+ return mbase.ToString();
+ }
+*/
/// <summary>
/// Find the Applicable Function Members (7.4.2.1)
/// loc: The location if we want an error to be reported, or a Null
/// location for "probing" purposes.
///
+ /// isLateBindingRequired : Flag to indicate that this method call is
+ /// is a candidate for late binding. Set to true if
+ /// there is atleast one object argument and we get
+ /// * Two or more candidates that require widening conv
+ /// * Two or more candidates require narrowing conversions
+ /// (for object arguments **only**)
/// Returns: The MethodBase (either a ConstructorInfo or a MethodInfo)
/// that is the best match of me on Arguments.
///
/// </summary>
public static MethodBase OverloadResolve (EmitContext ec, MethodGroupExpr me,
- ref ArrayList Arguments, Location loc)
+ ref ArrayList Arguments, Location loc,
+ out bool isLateBindingRequired)
{
- ArrayList afm = new ArrayList ();
MethodBase method = null;
- Type current_type = null;
int argument_count;
ArrayList candidates = new ArrayList ();
-
- foreach (MethodBase candidate in me.Methods){
- int x;
-
- // If we're going one level higher in the class hierarchy, abort if
- // we already found an applicable method.
- if (candidate.DeclaringType != current_type) {
- current_type = candidate.DeclaringType;
- if (method != null)
- break;
- }
-
- // Check if candidate is applicable (section 14.4.2.1)
- if (!IsApplicable (ec, ref Arguments, candidate))
- continue;
-
- candidates.Add (candidate);
- x = BetterFunction (ec, Arguments, candidate, method, false, loc);
-
- if (x == 0)
- continue;
-
- method = candidate;
- }
+ ArrayList lateBindingCandidates = new ArrayList ();
+ Hashtable expanded_candidates = new Hashtable();
+ int narrow_count = 0;
+ bool narrowing_candidate = false;
+ errorMsg = "";
+ isLateBindingRequired = false;
+ CaseInsensitiveHashtable namedArgs = new CaseInsensitiveHashtable ();
if (Arguments == null)
argument_count = 0;
else
argument_count = Arguments.Count;
-
-
- //
- // Now we see if we can find params functions, applicable in their expanded form
- // since if they were applicable in their normal form, they would have been selected
- // above anyways
- //
- bool chose_params_expanded = false;
-
- if (method == null) {
- candidates = new ArrayList ();
- foreach (MethodBase candidate in me.Methods){
- if (!IsParamsMethodApplicable (ec, Arguments, candidate))
- continue;
- candidates.Add (candidate);
+ if (!CheckNamedArguments (Arguments, loc))
+ return null;
- int x = BetterFunction (ec, Arguments, candidate, method, true, loc);
- if (x == 0)
+ if (!GetNamedArgPos (Arguments, ref namedArgs, loc))
+ return null;
+
+ ArrayList newarglist = Arguments;
+ foreach (MethodBase candidate in me.Methods){
+ bool candidate_expanded, object_args_present;
+ newarglist = Arguments;
+ if (argument_count > 0 && namedArgs.Count != 0) {
+ newarglist = ReorderArguments (candidate, Arguments, namedArgs, ref errorMsg, loc);
+ if (newarglist == null)
continue;
+ }
- method = candidate;
- chose_params_expanded = true;
+ ConversionType m = IsApplicable (ec, newarglist, candidate, out candidate_expanded, out object_args_present);
+ if (candidate_expanded)
+ expanded_candidates [candidate] = candidate;
+ if (m == ConversionType.None)
+ continue;
+ else if (m == ConversionType.Narrowing) {
+ if (object_args_present) // if the narrowing conversion was due
+ // to the argument being an object
+ lateBindingCandidates.Add (candidate);
+ if (method == null) {
+ method = candidate;
+ narrowing_candidate = true;
+ }
+ narrow_count++;
+ } else if (m == ConversionType.Widening) {
+ if (method == null || narrowing_candidate) {
+ method = candidate;
+ narrowing_candidate = false;
+ } else {
+ Applicability res = BetterFunction (ec, Arguments, candidate, method, true, loc);
+ if (res == Applicability.Same)
+ continue; // should check it overrides?
+ if (res == Applicability.Better)
+ method = candidate;
+ }
+ candidates.Add (candidate);
}
}
+ if (candidates.Count == 0) {
+ if (lateBindingCandidates.Count > 1) {
+ isLateBindingRequired = true;
+ return null;
+ }
+
+ if (narrow_count > 1) {
+ if (lateBindingCandidates.Count == 1)
+ method = (MethodBase) lateBindingCandidates [0];
+ else
+ method = null;
+ } else if (narrow_count == 1)
+ candidates = null;
+ } else if (candidates.Count == 1) {
+ method = (MethodBase)candidates [0];
+ candidates = null;
+ } else
+ narrow_count = 0;
+
if (method == null) {
//
// Okay so we have failed to find anything so we
if (pd.Count != argument_count)
continue;
+ bool dummy;
+ if (narrow_count != 0) {
+ if (IsApplicable (ec, Arguments, c, out dummy) == ConversionType.None)
+ continue;
+ Report.Error (1502, loc,
+ "Overloaded match for method '" +
+ FullMethodDesc (c) +
+ "' requires narrowing conversionss");
+ }
+
VerifyArgumentsCompat (ec, Arguments, argument_count, c, false,
null, loc);
}
// should be better than all the others
//
- foreach (MethodBase candidate in candidates){
- if (candidate == method)
- continue;
+ if (candidates != null) {
+ foreach (MethodBase candidate in candidates){
+ if (candidate == method)
+ continue;
- //
- // If a normal method is applicable in the sense that it has the same
- // number of arguments, then the expanded params method is never applicable
- // so we debar the params method.
- //
- if (IsParamsMethodApplicable (ec, Arguments, candidate) &&
- IsApplicable (ec, ref Arguments, method))
- continue;
-
- int x = BetterFunction (ec, Arguments, method, candidate,
- chose_params_expanded, loc);
- if (x != 1) {
- Report.Error (
- 121, loc,
- "Ambiguous call when selecting function due to implicit casts");
- return null;
- }
+ if (BetterFunction (ec, Arguments, candidate, method,
+ false, loc) == Applicability.Better) {
+ Report.Error (
+ 121, loc,
+ "Ambiguous call of '" + me.Name + "' when selecting function due to implicit casts");
+ return null;
+ }
+ }
}
//
// And now check if the arguments are all compatible, perform conversions
// if necessary etc. and return if everything is all right
//
+ if (method == null)
+ return null;
+
+ bool chose_params_expanded = expanded_candidates.Contains (method);
+
+ newarglist = Arguments;
+ if (argument_count > 0 && namedArgs.Count != 0) {
+ string err = "";
+ newarglist = ReorderArguments (method, Arguments, namedArgs, ref err, loc);
+ if (newarglist == null)
+ return null;
+ }
+ Arguments = ConstructArgumentList(ec, newarglist, namedArgs, method);
if (VerifyArgumentsCompat (ec, Arguments, argument_count, method,
chose_params_expanded, null, loc))
+ {
return method;
+ }
else
return null;
}
+ internal static bool CheckNamedArguments (ArrayList Arguments, Location loc)
+ {
+ if (Arguments == null || Arguments.Count == 0)
+ return true;
+
+ bool namedArgFound = false;
+ for (int index = 0; index < Arguments.Count; index ++) {
+ Argument a = (Argument) Arguments [index];
+ if (a.ParamName == null || a.ParamName == "") {
+ if (namedArgFound) {
+ Report.Error (30241, loc,
+ "Named argument expected");
+ return false;
+ }
+ } else
+ namedArgFound = true;
+ }
+
+ return true;
+ }
+
+ internal static bool GetNamedArgPos (ArrayList Arguments, ref CaseInsensitiveHashtable namedArgs, Location loc)
+ {
+ namedArgs.Clear ();
+ if (Arguments == null || Arguments.Count == 0)
+ return true;
+ for (int index = 0; index < Arguments.Count; index ++) {
+ Argument a = (Argument) Arguments [index];
+ if (a.ParamName == null || a.ParamName == "")
+ // none of the args are named
+ return true;
+ if (namedArgs.Contains (a.ParamName)) {
+ Report.Error (30274, loc, "Parameter '" + a.ParamName +"'already has a matching argument");
+ return false;
+ }
+ namedArgs.Add (a.ParamName, index);
+ }
+ return true;
+ }
+
+ public static ArrayList ConstructArgumentList (EmitContext ec, ArrayList Arguments, CaseInsensitiveHashtable namedArgs, MethodBase method)
+ {
+ ArrayList newarglist = new ArrayList();
+ int arg_count = Arguments == null ? 0 : Arguments.Count;
+
+ ParameterData pd = GetParameterData (method);
+ bool argNamesGiven = (namedArgs.Count > 0);
+ for (int i = 0; i < arg_count; i++) {
+ Argument a = (Argument) Arguments [i];
+ Type param_type = pd.ParameterType (i);
+
+ bool IsDelegate = TypeManager.IsDelegateType (param_type);
+ if (a.ArgType == Argument.AType.NoArg) {
+ Expression pdvalue = pd.DefaultValue (i);
+ pdvalue.Resolve (ec);
+ if (pdvalue != NullLiteral.Null)
+ pdvalue = ConvertImplicit (ec, pdvalue, param_type, Location.Null);;
+ if (argNamesGiven)
+ a = new Argument (pd.ParameterName (i), pdvalue, Argument.AType.Expression);
+ else
+ a = new Argument (pdvalue, Argument.AType.Expression);
+ a.Resolve (ec, Location.Null);
+ }
+
+ if (IsDelegate) {
+ if (a.ArgType == Argument.AType.AddressOf) {
+ a = new Argument ((Expression) a.Expr, Argument.AType.Expression);
+ ArrayList args = new ArrayList();
+ args.Add (a);
+ string param_name = pd.ParameterDesc(i).Replace('+', '.');
+ Expression pname = MonoBASIC.Parser.DecomposeQI (param_name, Location.Null);
+
+ New temp_new = new New ((Expression)pname, args, Location.Null);
+ Expression del_temp = temp_new.DoResolve(ec);
+ a = new Argument (del_temp, Argument.AType.Expression);
+ a.Resolve(ec, Location.Null);
+ }
+ }
+ if ((pd.ParameterModifier (i) & Parameter.Modifier.REF) != 0) {
+ a.ArgType = Argument.AType.Ref;
+ a.Resolve(ec, Location.Null);
+ }
+
+ newarglist.Add (a);
+ }
+
+ if (HasArrayParameter (pd) && arg_count == pd.Count - 1)
+ return newarglist;
+
+ for (int i = arg_count; i < pd.Count; i++) {
+ Type param_type = pd.ParameterType (i);
+ Expression e = pd.DefaultValue (i);
+ e.Resolve (ec);
+ if (e != NullLiteral.Null)
+ e = ConvertImplicit (ec, e, param_type, Location.Null);
+ Argument a = null;
+ if (argNamesGiven)
+ a = new Argument (e, Argument.AType.Expression);
+ else
+ a = new Argument (pd.ParameterName (i), e, Argument.AType.Expression);
+ if ((pd.ParameterModifier (i) & Parameter.Modifier.REF) != 0)
+ a.ArgType = Argument.AType.Ref;
+ a.Resolve (ec, Location.Null);
+ newarglist.Add (a);
+ }
+
+ return newarglist;
+ }
+
public static bool VerifyArgumentsCompat (EmitContext ec, ArrayList Arguments,
int argument_count,
MethodBase method,
return false;
}
if (pd.ParameterModifier (j) == Parameter.Modifier.PARAMS &&
- chose_params_expanded)
+ chose_params_expanded)
parameter_type = TypeManager.TypeToCoreType (parameter_type.GetElementType ());
+ // By pass conversion for foll. case and handle it in EmitArguments()
- if (a.Type != parameter_type){
+ if (a.ArgType != Argument.AType.Ref && a.Type != parameter_type){
Expression conv;
conv = ConvertImplicit (ec, a_expr, parameter_type, loc);
}
Parameter.Modifier a_mod = a.GetParameterModifier () &
- ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);
+ ~(Parameter.Modifier.REF);
Parameter.Modifier p_mod = pd.ParameterModifier (j) &
- ~(Parameter.Modifier.OUT | Parameter.Modifier.REF);
+ ~(Parameter.Modifier.REF | Parameter.Modifier.OPTIONAL);
-
if (a_mod != p_mod &&
pd.ParameterModifier (pd_count - 1) != Parameter.Modifier.PARAMS) {
if (!Location.IsNull (loc)) {
return true;
}
-
+
public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
{
this.is_left_hand = true;
- return DoResolve (ec);
+ Expression expr_to_return = DoResolve (ec);
+ if (expr_to_return is PropertyGroupExpr) {
+ PropertyGroupExpr pe = expr_to_return as PropertyGroupExpr;
+ pe = (PropertyGroupExpr) pe.ResolveLValue (ec, right_side);
+ if (pe == null)
+ return null;
+ if (pe.IndexerAccessRequired) {
+ if (pe.Type.IsArray) {
+ // If we are here, expr must be an ArrayAccess
+ ArrayList idxs = new ArrayList();
+ foreach (Argument a in Arguments)
+ {
+ idxs.Add (a.Expr);
+ }
+ ElementAccess ea = new ElementAccess (expr_to_return, idxs, expr.Location);
+ ArrayAccess aa = new ArrayAccess (ea, expr_to_return.Location);
+ expr_to_return = aa.DoResolve(ec);
+ expr_to_return.eclass = ExprClass.Variable;
+ } else {
+ //
+ // check whether this is a indexer
+ //
+ ArrayList idxs = new ArrayList();
+ foreach (Argument a in Arguments) {
+ idxs.Add (a.Expr);
+ }
+ ElementAccess ea = new ElementAccess (expr_to_return, idxs, expr.Location);
+ IndexerAccess ia = new IndexerAccess (ea, expr_to_return.Location);
+ if (is_left_hand)
+ expr_to_return = ia.DoResolveLValue (ec, right_side);
+ else
+ expr_to_return = ia.DoResolve(ec);
+ }
+ return expr_to_return;
+ }
+ }
+
+ if (expr_to_return is IndexerAccess && is_left_hand) {
+ IndexerAccess ia = expr_to_return as IndexerAccess;
+ expr_to_return = ia.DoResolveLValue (ec, right_side);
+ }
+
+ return expr_to_return;
}
public override Expression DoResolve (EmitContext ec)
// trigger the invocation
//
Expression expr_to_return = null;
+ Expression temp = null;
if (expr is BaseAccess)
is_base = true;
+ ResolveFlags flags;
if ((ec.ReturnType != null) && (expr.ToString() == ec.BlockName)) {
ec.InvokingOwnOverload = true;
- expr = expr.Resolve (ec, ResolveFlags.MethodGroup);
+ flags = ResolveFlags.MethodGroup;
+ temp = expr.Resolve (ec, flags);
ec.InvokingOwnOverload = false;
}
else
{
ec.InvokingOwnOverload = false;
- expr = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
- }
- if (expr == null)
+ flags = ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup;
+ temp = expr.Resolve (ec, flags);
+ }
+
+ if (temp == null) {
+ if (is_left_hand)
+ return null;
+
+ if (expr is MemberAccess) {
+ MemberAccess m = expr as MemberAccess;
+ if (m.Expr.Type == TypeManager.object_type) {
+ StatementSequence etmp = new StatementSequence (ec.CurrentBlock,
+ loc, expr, Arguments,
+ is_retval_required, is_left_hand);
+ if (!etmp.ResolveArguments (ec))
+ return null;
+ etmp.GenerateLateBindingStatements();
+ this.is_latebinding = true;
+ return etmp.Resolve (ec);
+ }
+ }
return null;
+ }
+
+ expr = temp;
if (expr is Invocation) {
// FIXME Calls which return an Array are not resolved (here or in the grammar)
expr = expr.Resolve(ec);
}
- if (!(expr is MethodGroupExpr))
+ if (!(expr is MethodGroupExpr || expr is PropertyGroupExpr))
{
Type expr_type = expr.Type;
if ((a.ArgType == Argument.AType.NoArg) && (!(expr is MethodGroupExpr)))
Report.Error (999, "This item cannot have empty arguments");
-
if (!a.Resolve (ec, loc))
return null;
}
if (expr is MethodGroupExpr)
{
MethodGroupExpr mg = (MethodGroupExpr) expr;
- method = OverloadResolve (ec, mg, ref Arguments, loc);
-
+ bool isLateBindingRequired = false;
+ method = OverloadResolve (ec, mg, ref Arguments, loc, out isLateBindingRequired);
if (method == null)
{
+ if (isLateBindingRequired) {
+ Expression type_expr = new TypeOf (Parser.DecomposeQI (mg.DeclaringType.Name, loc), loc);
+ StatementSequence etmp = new StatementSequence (ec.CurrentBlock,
+ loc, null, mg.Name, type_expr,
+ Arguments, is_retval_required, is_left_hand);
+ if (! etmp.ResolveArguments (ec))
+ return null;
+ etmp.GenerateLateBindingStatements ();
+ return etmp.Resolve (ec);
+ }
Error (30455,
- "Could not find any applicable function to invoke for this argument list");
+ "Could not find any applicable function to invoke for this argument list" + errorMsg);
return null;
}
}
eclass = ExprClass.Value;
expr_to_return = this;
+ return expr_to_return;
}
- if (expr is PropertyExpr)
+ if (expr is PropertyGroupExpr)
{
- PropertyExpr pe = ((PropertyExpr) expr);
- pe.PropertyArgs = (ArrayList) Arguments.Clone();
- Arguments.Clear();
- Arguments = new ArrayList();
- MethodBase mi = pe.PropertyInfo.GetGetMethod(true);
-
- if(VerifyArgumentsCompat (ec, pe.PropertyArgs,
- pe.PropertyArgs.Count, mi, false, null, loc, pe.Name))
- {
-
- expr_to_return = pe.DoResolve (ec);
- expr_to_return.eclass = ExprClass.PropertyAccess;
- }
- else
- {
- throw new Exception("Error resolving Property Access expression\n" + pe.ToString());
+ PropertyGroupExpr pe = ((PropertyGroupExpr) expr);
+ if (pe.Arguments != null)
+ goto skip_already_resolved_property;
+ if (Arguments != null)
+ pe.Arguments = (ArrayList) Arguments.Clone ();
+ if (is_left_hand)
+ return pe;
+ string name = pe.Name;
+ pe = (PropertyGroupExpr) pe.Resolve (ec);
+ if (pe == null) {
+ Error (30057, "Property '" + name + "' cannot be invoked with given arguments");
+ return null;
}
+
+ if (!pe.IndexerAccessRequired)
+ return pe;
+ expr = pe;
}
- if (expr is FieldExpr || expr is LocalVariableReference || expr is ParameterReference) {
- if (expr.Type.IsArray) {
- // If we are here, expr must be an ArrayAccess
- ArrayList idxs = new ArrayList();
- foreach (Argument a in Arguments)
- {
- idxs.Add (a.Expr);
- }
- ElementAccess ea = new ElementAccess (expr, idxs, expr.Location);
- ArrayAccess aa = new ArrayAccess (ea, expr.Location);
- expr_to_return = aa.DoResolve(ec);
- expr_to_return.eclass = ExprClass.Variable;
+ skip_already_resolved_property:
+ if (expr.Type.IsArray) {
+ // If we are here, expr must be an ArrayAccess
+ ArrayList idxs = new ArrayList();
+ foreach (Argument a in Arguments)
+ {
+ idxs.Add (a.Expr);
+ }
+ ElementAccess ea = new ElementAccess (expr, idxs, expr.Location);
+ ArrayAccess aa = new ArrayAccess (ea, expr.Location);
+ expr_to_return = aa.DoResolve(ec);
+ expr_to_return.eclass = ExprClass.Variable;
+ } else {
+ //
+ // check whether this is a indexer
+ //
+ ArrayList idxs = new ArrayList();
+ foreach (Argument a in Arguments) {
+ idxs.Add (a.Expr);
}
+ ElementAccess ea = new ElementAccess (expr, idxs, expr.Location);
+ IndexerAccess ia = new IndexerAccess (ea, expr.Location);
+ if (!is_left_hand)
+ expr_to_return = ia.DoResolve(ec);
else
- {
+ expr_to_return = ia.DoResolve(ec);
+ //
+ // Since all the above are failed we need to do
+ // late binding
+ //
+ if (expr_to_return == null) {
+
// We can't resolve now, but we
// have to try to access the array with a call
// to LateIndexGet/Set in the runtime
- Expression lig_call_expr;
-
- if (!is_left_hand)
- lig_call_expr = Mono.MonoBASIC.Parser.DecomposeQI("Microsoft.VisualBasic.CompilerServices.LateBinding.LateIndexGet", Location.Null);
- else
- lig_call_expr = Mono.MonoBASIC.Parser.DecomposeQI("Microsoft.VisualBasic.CompilerServices.LateBinding.LateIndexSet", Location.Null);
- Expression obj_type = Mono.MonoBASIC.Parser.DecomposeQI("System.Object", Location.Null);
- ArrayList adims = new ArrayList();
-
- ArrayList ainit = new ArrayList();
- foreach (Argument a in Arguments)
- ainit.Add ((Expression) a.Expr);
-
- adims.Add ((Expression) new IntLiteral (Arguments.Count));
-
- Expression oace = new ArrayCreation (obj_type, adims, "", ainit, Location.Null);
-
- ArrayList args = new ArrayList();
- args.Add (new Argument(expr, Argument.AType.Expression));
- args.Add (new Argument(oace, Argument.AType.Expression));
- args.Add (new Argument(NullLiteral.Null, Argument.AType.Expression));
-
- Expression lig_call = new Invocation (lig_call_expr, args, Location.Null);
- expr_to_return = lig_call.Resolve(ec);
- expr_to_return.eclass = ExprClass.Variable;
+ if (! is_left_hand) {
+ StatementSequence etmp = new StatementSequence (ec.CurrentBlock,
+ loc, ia, Arguments,
+ true, false);
+ if (!etmp.ResolveArguments (ec))
+ return null;
+ etmp.GenerateLateBindingStatements();
+ return etmp.Resolve (ec);
+ }
+ return null;
}
}
return expr_to_return;
}
- static void Error_WrongNumArguments (Location loc, String name, int arg_count)
- {
- Report.Error (1501, loc, "No overload for method `" + name + "' takes `" +
+ static void Error_WrongNumArguments (Location loc, String name, int arg_count)
+ {
+ Report.Error (1501, loc, "No overload for method `" + name + "' takes `" +
arg_count + "' arguments");
- }
+ }
// <summary>
// Emits the list of arguments as an array
/// <summary>
/// Emits a list of resolved Arguments that are in the arguments
/// ArrayList.
- ///
- /// The MethodBase argument might be null if the
- /// emission of the arguments is known not to contain
- /// a 'params' field (for example in constructors or other routines
- /// that keep their arguments in this structure)
/// </summary>
public static void EmitArguments (EmitContext ec, MethodBase mb, ArrayList arguments)
{
- ParameterData pd;
- if (mb != null)
- pd = GetParameterData (mb);
- else
- pd = null;
-
+ ParameterData pd = GetParameterData (mb);
//
// If we are calling a params method with no arguments, special case it
//
if (arguments == null){
- if (pd != null && pd.Count > 0 &&
+ if (pd.Count > 0 &&
pd.ParameterModifier (0) == Parameter.Modifier.PARAMS){
ILGenerator ig = ec.ig;
for (int i = 0; i < top; i++){
Argument a = (Argument) arguments [i];
+ Type parameter_type = pd.ParameterType(i);
+ Type argtype = a.Type;
+ Type arg_expr_type = a.Expr.Type;
- if (pd != null){
- if (pd.ParameterModifier (i) == Parameter.Modifier.PARAMS){
- //
- // Special case if we are passing the same data as the
- // params argument, do not put it in an array.
- //
- if (pd.ParameterType (i) == a.Type)
- a.Emit (ec);
- else
- EmitParams (ec, i, arguments);
- return;
+ if (pd.ParameterModifier (i) == Parameter.Modifier.PARAMS){
+ //
+ // Special case if we are passing the same data as the
+ // params argument, do not put it in an array.
+ //
+ if (pd.ParameterType (i) == a.Type)
+ a.Emit (ec);
+ else
+ EmitParams (ec, i, arguments);
+ return;
+ }
+ if ((a.ArgType == Argument.AType.Ref ) &&
+ (parameter_type != arg_expr_type ||
+ ! (a.Expr is IMemoryLocation))) {
+
+ LocalTemporary localtmp = new LocalTemporary (ec, parameter_type );
+
+ if((arg_expr_type != parameter_type) && (a.ArgType == Argument.AType.Ref)) {
+ Expression e = ConvertImplicit (ec, a.Expr, parameter_type, Location.Null);
+ is_byref_conversion = true;
+ e.Emit (ec);
+ } else
+ a.Expr.Emit (ec);
+
+
+
+ if (tempvars == null)
+ tempvars = new ArrayList ();
+ if (a.Expr is IMemoryLocation && is_byref_conversion ) {
+ Expression conv;
+ if(argtype.IsByRef)
+ argtype = argtype.GetElementType();
+ conv = ConvertImplicit (ec, localtmp, argtype, Location.Null);
+ tempvars.Add (new Assign (a.Expr, conv, Location.Null));
+
+ } else if (a.Expr is PropertyGroupExpr) {
+ // FIXME: We shouldnt be doing Resolve from inside 'Emit'.
+ // Have to find a way to push this up to 'Resolve'
+ Expression conv;
+ if(argtype.IsByRef)
+ argtype = argtype.GetElementType();
+ conv = ConvertImplicit (ec, localtmp, argtype, Location.Null);
+ Assign assgn = new Assign (a.Expr, conv, Location.Null);
+ Expression e = assgn.Resolve (ec);
+ tempvars.Add (e);
}
+ localtmp.Store (ec);
+ a = new Argument (localtmp, a.ArgType);
}
-
- a.Emit (ec);
- }
+ a.Emit (ec);
+ }
+
- if (pd != null && pd.Count > top &&
+
+ if (pd.Count > top &&
pd.ParameterModifier (top) == Parameter.Modifier.PARAMS){
ILGenerator ig = ec.ig;
{
ILGenerator ig = ec.ig;
bool struct_call = false;
+ bool is_myclass = false;
+
+ if (instance_expr is This && ((This) instance_expr).AccessType == This.TypeOfAccess.MyClass)
+ is_myclass = true;
Type decl_type = method.DeclaringType;
EmitArguments (ec, method, Arguments);
- if (is_static || struct_call || is_base)
+ if (is_static || struct_call || is_base || is_myclass)
{
if (method is MethodInfo)
{
}
}
+/*
static void EmitPropertyArgs (EmitContext ec, ArrayList prop_args)
{
int top = prop_args.Count;
a.Emit (ec);
}
}
+*/
public override void Emit (EmitContext ec)
{
MethodGroupExpr mg = (MethodGroupExpr) this.expr;
-
+
EmitCall (
ec, is_base, method.IsStatic, mg.InstanceExpression, method, Arguments, loc);
}
//
if (method is MethodInfo){
Type ret = ((MethodInfo)method).ReturnType;
- if (TypeManager.TypeToCoreType (ret) != TypeManager.void_type)
+ if ((TypeManager.TypeToCoreType (ret) != TypeManager.void_type) && !this.is_latebinding) {
ec.ig.Emit (OpCodes.Pop);
+
+ if (tempvars != null) {
+ foreach (Expression s in tempvars) {
+ if (s is ExpressionStatement)
+ ((ExpressionStatement) s).EmitStatement (ec);
+ else
+ s.Emit (ec);
+ }
+ tempvars.Clear ();
+ }
+ }
+
}
}
}
"or classes marked as MustInherit");
return null;
}
-
+
bool is_struct = false;
is_struct = type.IsValueType;
eclass = ExprClass.Value;
}
}
+/*
void Error_NegativeArrayIndex ()
{
Error (284, "Can not create array with a negative size");
return target;
}
+*/
//
// Creates the type of the array
//
Expression array_type_expr;
array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
- string sss = array_qualifier.ToString ();
type = ec.DeclSpace.ResolveType (array_type_expr, false, loc);
if (type == null)
/// </summary>
public class This : Expression, IAssignMethod, IMemoryLocation, IVariable {
+ public enum TypeOfAccess : byte {
+ Me, MyClass
+ }
+
Block block;
VariableInfo vi;
+ TypeOfAccess access_type;
+ public This (TypeOfAccess access_type, Block block, Location loc)
+ {
+ this.loc = loc;
+ this.block = block;
+ this.access_type = access_type;
+ }
+
public This (Block block, Location loc)
{
this.loc = loc;
this.block = block;
+ this.access_type = TypeOfAccess.Me;
}
public This (Location loc)
{
this.loc = loc;
+ this.access_type = TypeOfAccess.Me;
+ }
+
+ public TypeOfAccess AccessType {
+ get { return access_type; }
}
public bool IsAssigned (EmitContext ec, Location loc)
{
if (!ec.InUnsafe) {
Error (233, "Sizeof may only be used in an unsafe context " +
- "(consider using System.Runtime.InteropServices.Marshal.Sizeof");
+ "(consider using System.Runtime.InteropServices.Marshal.SizeOf");
return null;
}
public readonly string Identifier;
Expression expr;
Expression member_lookup;
+ bool is_invocation = false;
+ bool is_left_hand;
+ bool is_addressof = false;
public MemberAccess (Expression expr, string id, Location l)
{
loc = l;
}
+ public MemberAccess (Expression expr, string id, Location l, bool isInvocation)
+ {
+ this.expr = expr;
+ Identifier = id;
+ loc = l;
+ is_invocation = isInvocation;
+ }
+
+ public bool IsInvocation {
+ get {
+ return is_invocation;
+ }
+ set {
+ is_invocation = value;
+ }
+ }
+
+ public bool IsAddressOf {
+ set {
+ is_addressof = value;
+ }
+ }
+
+ public bool IsLeftHand {
+ get {
+ return is_left_hand;
+ }
+ set {
+ is_left_hand = value;
+ }
+ }
+
public Expression Expr {
get {
return expr;
Expression left, Location loc,
Expression left_original)
{
- bool left_is_type, left_is_explicit;
+ bool left_is_type, left_is_explicit;
+
// If 'left' is null, then we're called from SimpleNameResolve and this is
// a member in the currently defining class.
if (fi is FieldBuilder) {
Const c = TypeManager.LookupConstant ((FieldBuilder) fi);
-
if (c != null) {
- object o = c.LookupConstantValue (ec);
+ object o;
+ if (!c.LookupConstantValue (out o, ec))
+ return null;
+
object real_value = ((Constant) c.Expr).GetValue ();
+ Expression exp = Constantify (real_value, fi.FieldType);
- return Constantify (real_value, fi.FieldType);
- }
+ return exp;
+ }
}
+
+ // IsInitOnly is because of MS compatibility, I don't know why but they emit decimal constant as InitOnly
+
+ if (fi.IsInitOnly && !(fi is FieldBuilder) && fi.FieldType == TypeManager.decimal_type) {
+ object[] attrs = fi.GetCustomAttributes (TypeManager.decimal_constant_attribute_type, false);
+ if (attrs.Length == 1)
+ return new DecimalConstant (((System.Runtime.CompilerServices.DecimalConstantAttribute) attrs [0]).Value);
+ }
+
+
if (fi.IsLiteral) {
Type t = fi.FieldType;
Enum en = TypeManager.LookupEnum (decl_type);
Constant c;
- if (en != null) {
+ if (en != null)
c = Constantify (o, en.UnderlyingType);
- return new EnumConstant (c, en.UnderlyingType);
- }
- else {
+ else
c = Constantify (o, enum_member.Type);
- return new EnumConstant (c, enum_member.Type);
- }
-
-
+
+ return new EnumConstant (c, decl_type);
}
Expression exp = Constantify (o, t);
}
}
- if (member_lookup is EventExpr) {
-
- EventExpr ee = (EventExpr) member_lookup;
-
- //
- // If the event is local to this class, we transform ourselves into
- // a FieldExpr
- //
-
- if (ee.EventInfo.DeclaringType == ec.ContainerType) {
- MemberInfo mi = GetFieldFromEvent (ee);
-
- if (mi == null) {
- //
- // If this happens, then we have an event with its own
- // accessors and private field etc so there's no need
- // to transform ourselves : we should instead flag an error
- //
- Assign.error70 (ee.EventInfo, loc);
- return null;
- }
-
- Expression ml = ExprClassFromMemberInfo (ec, mi, loc);
-
- if (ml == null) {
- Report.Error (-200, loc, "Internal error!!");
- return null;
- }
-
- return ResolveMemberAccess (ec, ml, left, loc, left_original);
- }
- }
if (member_lookup is IMemberExpr) {
IMemberExpr me = (IMemberExpr) member_lookup;
- if (left_is_type){
- MethodGroupExpr mg = me as MethodGroupExpr;
- if ((mg != null) && left_is_explicit && left.Type.IsInterface)
- mg.IsExplicitImpl = left_is_explicit;
-
- if (!me.IsStatic){
- if (IdenticalNameAndTypeName (ec, left_original, loc))
- return member_lookup;
-
- SimpleName.Error_ObjectRefRequired (ec, loc, me.Name);
- return null;
+ if (left_is_type) {
+ if (me is PropertyGroupExpr) {
+ PropertyGroupExpr mg = me as PropertyGroupExpr;
+ if ((mg != null) && left_is_explicit && left.Type.IsInterface)
+ mg.IsExplicitImpl = left_is_explicit;
+
+ if (!me.IsStatic){
+ if (IdenticalNameAndTypeName (ec, left_original, loc))
+ return member_lookup;
+
+ SimpleName.Error_ObjectRefRequired (ec, loc, me.Name);
+ return null;
+ }
+ } else {
+ MethodGroupExpr mg = me as MethodGroupExpr;
+ if ((mg != null) && left_is_explicit && left.Type.IsInterface)
+ mg.IsExplicitImpl = left_is_explicit;
+
+ if (!me.IsStatic){
+ if (IdenticalNameAndTypeName (ec, left_original, loc))
+ return member_lookup;
+
+ SimpleName.Error_ObjectRefRequired (ec, loc, me.Name);
+ return null;
+ }
}
} else {
Expression original = expr;
expr = expr.Resolve (ec, flags | ResolveFlags.DisableFlowAnalysis);
-
+
if (expr == null)
return null;
if (expr is SimpleName){
SimpleName child_expr = (SimpleName) expr;
-
+
Expression new_expr = new SimpleName (child_expr.Name + "." + Identifier, loc);
+ ((SimpleName) new_expr).IsInvocation = is_invocation;
- return new_expr.Resolve (ec, flags | ResolveFlags.MethodGroup);
+ if ((flags & ResolveFlags.MaskExprClass) == ResolveFlags.Type)
+ return new_expr.Resolve (ec, flags);
+ else
+ return new_expr.Resolve (ec, flags | ResolveFlags.MethodGroup | ResolveFlags.VariableOrValue);
}
int errors = Report.Errors;
Type expr_type = expr.Type;
+ if (expr is TypeExpr){
+ //FIXME: add access level check
+ //if (!ec.DeclSpace.CheckAccessLevel (expr_type)) {
+ // Error (30390, "'" + TypeManager.MonoBASIC_Name (expr_type) + "' " +
+ // "is inaccessible because of its protection level");
+ // return null;
+ //}
+
+ if (expr_type == TypeManager.enum_type || expr_type.IsSubclassOf (TypeManager.enum_type)){
+ Enum en = TypeManager.LookupEnum (expr_type);
+
+ if (en != null) {
+ object value = en.LookupEnumValue (Identifier);
+
+ if (value != null){
+ Constant c = Constantify (value, en.UnderlyingType);
+ return new EnumConstant (c, expr_type);
+ } else {
+ Report.Error (30456, loc,
+ Identifier + " is not found in member list of enum " + en.Name);
+ }
+ }
+ }
+ }
+
if (expr_type.IsPointer){
- Error (23, "The '.' operator can not be applied to pointer operands (" +
+ Error (30311, "The '.' operator can not be applied to pointer operands (" +
TypeManager.MonoBASIC_Name (expr_type) + ")");
return null;
}
member_lookup = MemberLookup (ec, expr_type, Identifier, loc);
-
if (member_lookup == null)
{
// Error has already been reported.
expr_type, expr_type, AllMemberTypes, AllBindingFlags |
BindingFlags.NonPublic, Identifier);
- if (lookup == null)
- Error (30456, "'" + expr_type + "' does not contain a definition for '" + Identifier + "'");
+ if (lookup == null) {
+ if (expr_type != TypeManager.object_type)
+ Error (30456, "'" + expr_type + "' does not contain a definition for '" + Identifier + "'");
+ // If this came as a part of Invocation,
+ // Since argumets are not known, return null,
+ // let Invocation's Resolve take care
+ if (is_invocation)
+ return null;
+
+ else if (! is_left_hand) {
+ StatementSequence etmp = new StatementSequence (ec.CurrentBlock,
+ loc, this, null,
+ true, is_left_hand);
+ etmp.GenerateLateBindingStatements();
+ return etmp.Resolve (ec);
+ }
+
+ // if the expression is a left hand side of an assignment,
+ // return null, as we dont know the RHS
+ // Let assign take care of Late Binding
+ return null;
+ }
else
{
if ((expr_type != ec.ContainerType) &&
Enum en = TypeManager.LookupEnum (expr_type);
if (en != null) {
- object value = en.LookupEnumValue (ec, Identifier, loc);
+ object value = en.LookupEnumValue (Identifier);
expr_type = TypeManager.int32_type;
if (value != null) {
Constant c = Constantify (value, en.UnderlyingType);
return new EnumConstant (c, en.UnderlyingType);
+ } else {
+ Report.Error (30456, loc,
+ Identifier + " is not found in member list of enum " + en.Name);
}
}
}
if (member_lookup == null)
return null;
+ if ((member_lookup is MethodGroupExpr) && ! is_invocation && !is_addressof) {
+ Expression inv = new Invocation (this, new ArrayList (), loc);
+ return inv.Resolve (ec);
+ }
+
+ if (member_lookup is PropertyGroupExpr && is_invocation) // As we dont know the arguments yet
+ return member_lookup;
+
// The following DoResolve/DoResolveLValue will do the definite assignment
// check.
if (right_side != null)
else
member_lookup = member_lookup.DoResolve (ec);
+
return member_lookup;
}
public override Expression DoResolve (EmitContext ec)
{
- ExprClass eclass = ea.Expr.eclass;
+ //ExprClass eclass = ea.Expr.eclass;
#if false
// As long as the type is valid
return ix;
}
}
-
- Report.Error (21, loc,
- "Type '" + TypeManager.MonoBASIC_Name (lookup_type) +
- "' does not have any indexers defined");
return null;
}
}
MethodInfo get, set;
Indexers ilist;
ArrayList set_arguments;
- bool is_base_indexer;
+ //bool is_base_indexer;
protected Type indexer_type;
protected Type current_type;
Location loc)
{
this.instance_expr = instance_expr;
- this.is_base_indexer = is_base_indexer;
+ //this.is_base_indexer = is_base_indexer;
this.eclass = ExprClass.Value;
this.loc = loc;
}
+ public Expression Instance {
+ get {
+ return instance_expr;
+ }
+ }
+
+ public ArrayList Arguments {
+ get {
+ return arguments;
+ }
+ }
+
protected virtual bool CommonResolve (EmitContext ec)
{
indexer_type = instance_expr.Type;
//
// This is a group of properties, piles of them.
- if (ilist == null)
+ if (ilist == null) {
ilist = Indexers.GetIndexersForType (
current_type, indexer_type, loc);
+ if (ilist == null && indexer_type != TypeManager.object_type) {
+ Report.Error (21, loc,
+ "Type '" + TypeManager.MonoBASIC_Name (indexer_type) +
+ "' does not have any indexers defined");
+ return null;
+ }
+ }
+
//
// Step 2: find the proper match
//
ec, new MethodGroupExpr (ilist.getters, loc), arguments, loc);
if (get == null){
- Error (154, "indexer can not be used in this context, because " +
- "it lacks a 'get' accessor");
+ if (instance_expr.Type != TypeManager.object_type)
+ Error (30524, "indexer can not be used in this context, because " +
+ "it lacks a 'get' accessor");
return null;
}
Type right_type = right_side.Type;
- if (ilist == null)
+ if (ilist == null) {
ilist = Indexers.GetIndexersForType (
current_type, indexer_type, loc);
+ if (ilist == null && indexer_type != TypeManager.object_type) {
+ Report.Error (21, loc,
+ "Type '" + TypeManager.MonoBASIC_Name (indexer_type) +
+ "' does not have any indexers defined");
+ return null;
+ }
+ }
if (ilist != null && ilist.setters != null && ilist.setters.Count > 0){
set_arguments = (ArrayList) arguments.Clone ();
}
if (set == null){
- Error (200, "indexer X.this [" + TypeManager.MonoBASIC_Name (right_type) +
+ Error (30526, "indexer X.this [" + TypeManager.MonoBASIC_Name (right_type) +
"] lacks a 'set' accessor");
return null;
}
if (member == "New")
member = ".ctor";
- member_lookup = MemberLookup (ec, base_type, base_type, member,
+ member_lookup = MemberLookup (ec, current_type, base_type, member,
AllMemberTypes, AllBindingFlags, loc);
if (member_lookup == null) {
e = MemberAccess.ResolveMemberAccess (ec, member_lookup, left, loc, null);
- if (e is PropertyExpr){
+ if (e is PropertyExpr) {
PropertyExpr pe = (PropertyExpr) e;
pe.IsBase = true;
ig.Emit (OpCodes.Localloc);
}
}
+ public class Preserve : ExpressionStatement {
+ ArrayList args = null;
+ MethodInfo mi = null;
+ Expression target = null;
+ ExpressionStatement source = null;
+
+
+ public Preserve (Expression RedimTarget, ExpressionStatement acExpr, Location l)
+ {
+ Type type = typeof(Microsoft.VisualBasic.CompilerServices.Utils);
+ mi = type.GetMethod("CopyArray");
+
+ target = RedimTarget;
+ source = acExpr;
+
+ eclass = ExprClass.Value;
+ loc = l;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ //
+ // We are born fully resolved
+ //
+ type = mi.ReturnType;
+
+ source.Resolve (ec);
+
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ args = new ArrayList (2);
+
+ args.Add (new Argument (target, Argument.AType.Expression));
+ args.Add (new Argument (source, Argument.AType.Expression));
+
+ Invocation.EmitArguments (ec, mi, args);
+
+ ec.ig.Emit (OpCodes.Call, mi);
+ return;
+ }
+
+ public override void EmitStatement (EmitContext ec)
+ {
+ Emit (ec);
+ }
+
+ }
}