// Copyright 2001, 2002, 2003 Ximian, Inc.
// Copyright 2003-2008 Novell, Inc.
//
-#define USE_OLD
namespace Mono.CSharp {
using System;
// resolve phase
//
public class UserOperatorCall : Expression {
- public delegate Expression ExpressionTreeExpression (ResolveContext ec, MethodGroupExpr mg);
-
protected readonly Arguments arguments;
- protected readonly MethodGroupExpr mg;
- readonly ExpressionTreeExpression expr_tree;
+ protected readonly MethodSpec oper;
+ readonly Func<ResolveContext, Expression, Expression> expr_tree;
- public UserOperatorCall (MethodGroupExpr mg, Arguments args, ExpressionTreeExpression expr_tree, Location loc)
+ public UserOperatorCall (MethodSpec oper, Arguments args, Func<ResolveContext, Expression, Expression> expr_tree, Location loc)
{
- this.mg = mg;
+ this.oper = oper;
this.arguments = args;
this.expr_tree = expr_tree;
- type = mg.BestCandidate.ReturnType;
+ type = oper.ReturnType;
eclass = ExprClass.Value;
this.loc = loc;
}
public override Expression CreateExpressionTree (ResolveContext ec)
{
if (expr_tree != null)
- return expr_tree (ec, mg);
+ return expr_tree (ec, new TypeOfMethod (oper, loc));
Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
new NullLiteral (loc),
- mg.CreateExpressionTree (ec));
+ new TypeOfMethod (oper, loc));
return CreateExpressionFactoryCall (ec, "Call", args);
}
public override void Emit (EmitContext ec)
{
- mg.EmitCall (ec, arguments);
+ Invocation.EmitCall (ec, null, oper, arguments, loc);
}
public override SLE.Expression MakeExpression (BuilderContext ctx)
{
- var method = mg.BestCandidate.GetMetaInfo () as MethodInfo;
+ var method = oper.GetMetaInfo () as MethodInfo;
return SLE.Expression.Call (method, Arguments.MakeExpression (arguments, ctx));
}
-
- public MethodGroupExpr Method {
- get { return mg; }
- }
}
public class ParenthesizedExpression : ShimExpression
return CreateExpressionTree (ec, null);
}
- Expression CreateExpressionTree (ResolveContext ec, MethodGroupExpr user_op)
+ Expression CreateExpressionTree (ResolveContext ec, Expression user_op)
{
string method_name;
switch (Oper) {
Arguments args = new Arguments (2);
args.Add (new Argument (Expr.CreateExpressionTree (ec)));
if (user_op != null)
- args.Add (new Argument (user_op.CreateExpressionTree (ec)));
+ args.Add (new Argument (user_op));
+
return CreateExpressionFactoryCall (ec, method_name, args);
}
VariableInfo vi = vr.VariableInfo;
if (vi != null) {
if (vi.LocalInfo != null)
- vi.LocalInfo.Used = true;
+ vi.LocalInfo.SetIsUsed ();
//
// A variable is considered definitely assigned if you take its address.
throw new InternalErrorException (Oper.ToString ());
}
- string op_name = CSharp.Operator.GetMetadataName (op_type);
- MethodGroupExpr user_op = MethodLookup (ec.Compiler, ec.CurrentType, expr.Type, MemberKind.Operator, op_name, 0, expr.Location);
- if (user_op == null)
+ var methods = MemberCache.GetUserOperator (expr.Type, op_type, false);
+ if (methods == null)
return null;
Arguments args = new Arguments (1);
args.Add (new Argument (expr));
- user_op = user_op.OverloadResolve (ec, ref args, false, expr.Location);
- if (user_op == null)
+ var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
+ var oper = res.ResolveOperator (ec, ref args);
+
+ if (oper == null)
return null;
Expr = args [0].Expr;
- return new UserOperatorCall (user_op, args, CreateExpressionTree, expr.Location);
+ return new UserOperatorCall (oper, args, CreateExpressionTree, expr.Location);
}
//
TypeSpec[] predefined = predefined_operators [(int) Oper];
foreach (TypeSpec t in predefined) {
- Expression oper_expr = Convert.UserDefinedConversion (ec, expr, t, expr.Location, false, false);
+ Expression oper_expr = Convert.ImplicitUserConversion (ec, expr, t, expr.Location);
if (oper_expr == null)
continue;
continue;
}
- int result = MethodGroupExpr.BetterTypeConversion (ec, best_expr.Type, t);
+ int result = OverloadResolver.BetterTypeConversion (ec, best_expr.Type, t);
if (result == 0) {
ec.Report.Error (35, loc, "Operator `{0}' is ambiguous on an operand of type `{1}'",
OperName (Oper), TypeManager.CSharpName (expr.Type));
}
if (expr.Type == TypeManager.void_ptr_type) {
- ec.Report.Error (242, loc, "The operation in question is undefined on void pointers");
+ Error_VoidPointerOperation (ec);
return null;
}
// Holds the real operation
Expression operation;
+ static TypeSpec[] predefined;
+
public UnaryMutator (Mode m, Expression e, Location loc)
{
mode = m;
return new SimpleAssign (this, this).CreateExpressionTree (ec);
}
+ void CreatePredefinedOperators ()
+ {
+ //
+ // Predefined ++ and -- operators exist for the following types:
+ // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
+ //
+ predefined = new TypeSpec[] {
+ TypeManager.int32_type,
+
+ TypeManager.sbyte_type,
+ TypeManager.byte_type,
+ TypeManager.short_type,
+ TypeManager.ushort_type,
+ TypeManager.uint32_type,
+ TypeManager.int64_type,
+ TypeManager.uint64_type,
+ TypeManager.char_type,
+ TypeManager.float_type,
+ TypeManager.double_type,
+ TypeManager.decimal_type
+ };
+ }
+
protected override Expression DoResolve (ResolveContext ec)
{
expr = expr.Resolve (ec);
eclass = ExprClass.Value;
type = expr.Type;
- return ResolveOperator (ec);
+
+ if (expr is RuntimeValueExpression) {
+ operation = expr;
+ } else {
+ // Use itself at the top of the stack
+ operation = new EmptyExpression (type);
+ }
+
+ //
+ // The operand of the prefix/postfix increment decrement operators
+ // should be an expression that is classified as a variable,
+ // a property access or an indexer access
+ //
+ // TODO: Move to parser, expr is ATypeNameExpression
+ if (expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess) {
+ expr = expr.ResolveLValue (ec, expr);
+ } else {
+ ec.Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
+ }
+
+ //
+ // Step 1: Try to find a user operator, it has priority over predefined ones
+ //
+ var user_op = IsDecrement ? Operator.OpType.Decrement : Operator.OpType.Increment;
+ var methods = MemberCache.GetUserOperator (type, user_op, false);
+
+ if (methods != null) {
+ Arguments args = new Arguments (1);
+ args.Add (new Argument (expr));
+
+ var res = new OverloadResolver (methods, OverloadResolver.Restrictions.BaseMembersIncluded | OverloadResolver.Restrictions.NoBaseMembers, loc);
+ var method = res.ResolveOperator (ec, ref args);
+ if (method == null)
+ return null;
+
+ args[0].Expr = operation;
+ operation = new UserOperatorCall (method, args, null, loc);
+ operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
+ return this;
+ }
+
+ //
+ // Step 2: Try predefined types
+ //
+ if (predefined == null)
+ CreatePredefinedOperators ();
+
+ // Predefined without user conversion first for speed-up
+ Expression source = null;
+ bool primitive_type = false;
+ foreach (var t in predefined) {
+ if (t == type) {
+ source = operation;
+ primitive_type = true;
+ break;
+ }
+ }
+
+ // ++/-- on pointer variables of all types except void*
+ if (source == null && type.IsPointer) {
+ if (type == TypeManager.void_ptr_type) {
+ Error_VoidPointerOperation (ec);
+ return null;
+ }
+
+ source = operation;
+ }
+
+ if (source == null) {
+ // LAMESPEC: It should error on ambiguous operators but that would make us incompatible
+ foreach (var t in predefined) {
+ source = Convert.ImplicitUserConversion (ec, operation, t, loc);
+ if (source != null) {
+ break;
+ }
+ }
+ }
+
+ // ++/-- on enum types
+ if (source == null && type.IsEnum)
+ source = operation;
+
+ if (source == null) {
+ Unary.Error_OperatorCannotBeApplied (ec, loc, Operator.GetName (user_op), type);
+ return null;
+ }
+
+ var one = new IntConstant (1, loc);
+ var op = IsDecrement ? Binary.Operator.Subtraction : Binary.Operator.Addition;
+ operation = new Binary (op, source, one, loc);
+ operation = operation.Resolve (ec);
+ if (operation == null)
+ throw new NotImplementedException ("should not be reached");
+
+ if (operation.Type != type) {
+ if (primitive_type)
+ operation = Convert.ExplicitNumericConversion (operation, type);
+ else
+ operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
+ }
+
+ return this;
}
void EmitCode (EmitContext ec, bool is_expr)
get { return (mode & Mode.IsDecrement) != 0; }
}
- //
- // Returns whether an object of type `t' can be incremented
- // or decremented with add/sub (ie, basically whether we can
- // use pre-post incr-decr operations on it, but it is not a
- // System.Decimal, which we require operator overloading to catch)
- //
- static bool IsPredefinedOperator (TypeSpec t)
- {
- return (TypeManager.IsPrimitiveType (t) && t != TypeManager.bool_type) ||
- TypeManager.IsEnumType (t) ||
- t.IsPointer && t != TypeManager.void_ptr_type;
- }
#if NET_4_0
public override SLE.Expression MakeExpression (BuilderContext ctx)
}
#endif
- protected override void CloneTo (CloneContext clonectx, Expression t)
+ public static void Reset ()
{
- UnaryMutator target = (UnaryMutator) t;
-
- target.expr = expr.Clone (clonectx);
+ predefined = null;
}
- Expression ResolveOperator (ResolveContext ec)
+ protected override void CloneTo (CloneContext clonectx, Expression t)
{
- if (expr is RuntimeValueExpression) {
- operation = expr;
- } else {
- // Use itself at the top of the stack
- operation = new EmptyExpression (type);
- }
-
- //
- // The operand of the prefix/postfix increment decrement operators
- // should be an expression that is classified as a variable,
- // a property access or an indexer access
- //
- if (expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.IndexerAccess || expr.eclass == ExprClass.PropertyAccess) {
- expr = expr.ResolveLValue (ec, expr);
- } else {
- ec.Report.Error (1059, loc, "The operand of an increment or decrement operator must be a variable, property or indexer");
- }
-
- //
- // 1. Check predefined types
- //
- if (IsPredefinedOperator (type)) {
- // TODO: Move to IntConstant once I get rid of int32_type
- var one = new IntConstant (1, loc);
-
- // TODO: Cache this based on type when using EmptyExpression in
- // context cache
- Binary.Operator op = IsDecrement ? Binary.Operator.Subtraction : Binary.Operator.Addition;
- operation = new Binary (op, operation, one, loc);
- operation = operation.Resolve (ec);
- if (operation != null && operation.Type != type)
- operation = Convert.ExplicitNumericConversion (operation, type);
-
- return this;
- }
-
- //
- // Step 2: Perform Operator Overload location
- //
- string op_name;
-
- if (IsDecrement)
- op_name = Operator.GetMetadataName (Operator.OpType.Decrement);
- else
- op_name = Operator.GetMetadataName (Operator.OpType.Increment);
-
- var mg = MethodLookup (ec.Compiler, ec.CurrentType, type, MemberKind.Operator, op_name, 0, loc);
-
- if (mg != null) {
- Arguments args = new Arguments (1);
- args.Add (new Argument (expr));
- mg = mg.OverloadResolve (ec, ref args, false, loc);
- if (mg == null)
- return null;
-
- args[0].Expr = operation;
- operation = new UserOperatorCall (mg, args, null, loc);
- operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
- return this;
- }
-
- string name = IsDecrement ?
- Operator.GetName (Operator.OpType.Decrement) :
- Operator.GetName (Operator.OpType.Increment);
+ UnaryMutator target = (UnaryMutator) t;
- Unary.Error_OperatorCannotBeApplied (ec, loc, name, type);
- return null;
+ target.expr = expr.Clone (clonectx);
}
}
if (TypeManager.IsGenericParameter (t))
return ResolveGenericParameter (ec, d, (TypeParameterSpec) t);
+ if (t == InternalType.Dynamic) {
+ ec.Report.Warning (1981, 3, loc,
+ "Using `{0}' to test compatibility with `{1}' is identical to testing compatibility with `object'",
+ OperatorName, t.GetSignatureForError ());
+ }
+
if (TypeManager.IsStruct (d)) {
- bool temp;
- if (Convert.ImplicitBoxingConversionExists (d, t, out temp))
+ if (Convert.ImplicitBoxingConversion (null, d, t) != null)
return CreateConstantResult (ec, true);
} else {
if (TypeManager.IsGenericParameter (d))
if (expr.IsNull && TypeManager.IsNullableType (type)) {
return Nullable.LiftedNull.CreateFromExpression (ec, this);
}
+
+ // If the compile-time type of E is dynamic, unlike the cast operator the as operator is not dynamically bound
+ if (etype == InternalType.Dynamic) {
+ do_isinst = true;
+ return this;
+ }
Expression e = Convert.ImplicitConversion (ec, expr, type, loc);
if (e != null){
expr = e;
- do_isinst = false;
return this;
}
}
}
- /// <summary>
- /// This represents a typecast in the source language.
- ///
- /// FIXME: Cast expressions have an unusual set of parsing
- /// rules, we need to figure those out.
- /// </summary>
+ //
+ // This represents a typecast in the source language.
+ //
public class Cast : ShimExpression {
Expression target_type;
-
- public Cast (Expression cast_type, Expression expr)
- : this (cast_type, expr, cast_type.Location)
- {
- }
public Cast (Expression cast_type, Expression expr, Location loc)
: base (expr)
if (type.IsPointer && !ec.IsUnsafe) {
UnsafeError (ec, loc);
- } else if (expr.Type == InternalType.Dynamic) {
- Arguments arg = new Arguments (1);
- arg.Add (new Argument (expr));
- return new DynamicConversion (type, CSharpBinderFlags.ConvertExplicit, arg, loc).Resolve (ec);
}
- expr = Convert.ExplicitConversion (ec, expr, type, loc);
- return expr;
+ var res = Convert.ExplicitConversion (ec, expr, type, loc);
+ if (res == expr)
+ return EmptyCast.Create (res, type);
+
+ return res;
}
protected override void CloneTo (CloneContext clonectx, Expression t)
if (TypeManager.IsReferenceType (type))
return new NullConstant (type, loc);
- Constant c = New.Constantify (type);
+ Constant c = New.Constantify (type, expr.Location);
if (c != null)
return c.Resolve (ec);
var c = b.right as Constant;
if (c != null) {
- if (c.IsDefaultValue && (b.oper == Operator.Addition || b.oper == Operator.BitwiseOr || b.oper == Operator.Subtraction))
+ if (c.IsDefaultValue && (b.oper == Operator.Addition || b.oper == Operator.Subtraction || (b.oper == Operator.BitwiseOr && !(b is Nullable.LiftedBinaryOperator))))
return ReducedExpression.Create (b.left, b).Resolve (ec);
if ((b.oper == Operator.Multiply || b.oper == Operator.Division) && c.IsOneInteger)
return ReducedExpression.Create (b.left, b).Resolve (ec);
c = b.left as Constant;
if (c != null) {
- if (c.IsDefaultValue && (b.oper == Operator.Addition || b.oper == Operator.BitwiseOr))
+ if (c.IsDefaultValue && (b.oper == Operator.Addition || b.oper == Operator.Subtraction || (b.oper == Operator.BitwiseOr && !(b is Nullable.LiftedBinaryOperator))))
return ReducedExpression.Create (b.right, b).Resolve (ec);
if (b.oper == Operator.Multiply && c.IsOneInteger)
return ReducedExpression.Create (b.right, b).Resolve (ec);
public virtual bool IsApplicable (ResolveContext ec, Expression lexpr, Expression rexpr)
{
- if (TypeManager.IsEqual (left, lexpr.Type) &&
- TypeManager.IsEqual (right, rexpr.Type))
+ // Quick path
+ if (left == lexpr.Type && right == rexpr.Type)
return true;
return Convert.ImplicitConversionExists (ec, lexpr, left) &&
{
int result = 0;
if (left != null && best_operator.left != null) {
- result = MethodGroupExpr.BetterTypeConversion (ec, best_operator.left, left);
+ result = OverloadResolver.BetterTypeConversion (ec, best_operator.left, left);
}
//
- // When second arguments are same as the first one, the result is same
+ // When second argument is same as the first one, the result is same
//
if (right != null && (left != right || best_operator.left != best_operator.right)) {
- result |= MethodGroupExpr.BetterTypeConversion (ec, best_operator.right, right);
+ result |= OverloadResolver.BetterTypeConversion (ec, best_operator.right, right);
}
if (result == 0 || result > 2)
}
}
- class PredefinedPointerOperator : PredefinedOperator {
+ class PredefinedEqualityOperator : PredefinedOperator
+ {
+ MethodSpec equal_method, inequal_method;
+
+ public PredefinedEqualityOperator (TypeSpec arg, TypeSpec retType)
+ : base (arg, arg, Operator.EqualityMask, retType)
+ {
+ }
+
+ public override Expression ConvertResult (ResolveContext ec, Binary b)
+ {
+ b.type = ReturnType;
+
+ b.left = Convert.ImplicitConversion (ec, b.left, left, b.left.Location);
+ b.right = Convert.ImplicitConversion (ec, b.right, right, b.right.Location);
+
+ Arguments args = new Arguments (2);
+ args.Add (new Argument (b.left));
+ args.Add (new Argument (b.right));
+
+ MethodSpec method;
+ if (b.oper == Operator.Equality) {
+ if (equal_method == null) {
+ equal_method = TypeManager.GetPredefinedMethod (left,
+ new MemberFilter (CSharp.Operator.GetMetadataName (CSharp.Operator.OpType.Equality), 0, MemberKind.Operator, null, ReturnType), b.loc);
+ }
+
+ method = equal_method;
+ } else {
+ if (inequal_method == null) {
+ inequal_method = TypeManager.GetPredefinedMethod (left,
+ new MemberFilter (CSharp.Operator.GetMetadataName (CSharp.Operator.OpType.Inequality), 0, MemberKind.Operator, null, ReturnType), b.loc);
+ }
+
+ method = inequal_method;
+ }
+
+ return new UserOperatorCall (method, args, b.CreateExpressionTree, b.loc);
+ }
+ }
+
+ class PredefinedPointerOperator : PredefinedOperator
+ {
public PredefinedPointerOperator (TypeSpec ltype, TypeSpec rtype, Operator op_mask)
: base (ltype, rtype, op_mask)
{
RelationalMask = 1 << 13
}
+ protected enum State
+ {
+ None = 0,
+ Compound = 1 << 1,
+ LeftNullLifted = 1 << 2,
+ RightNullLifted = 1 << 3
+ }
+
readonly Operator oper;
protected Expression left, right;
- readonly bool is_compound;
+ protected State state;
Expression enum_conversion;
static PredefinedOperator[] standard_operators;
+ static PredefinedOperator[] equality_operators;
static PredefinedOperator[] pointer_operators;
public Binary (Operator oper, Expression left, Expression right, bool isCompound, Location loc)
: this (oper, left, right, loc)
{
- this.is_compound = isCompound;
+ if (isCompound)
+ state |= State.Compound;
}
public Binary (Operator oper, Expression left, Expression right, Location loc)
this.loc = loc;
}
+ #region Properties
+
+ public bool IsCompound {
+ get {
+ return (state & State.Compound) != 0;
+ }
+ }
+
public Operator Oper {
get {
return oper;
}
}
-
+
+ #endregion
+
/// <summary>
/// Returns a stringified representation of the Operator
/// </summary>
break;
}
- if (is_compound)
+ if (IsCompound)
return s + "=";
return s;
{
switch (oper) {
case Operator.Addition:
- return is_compound ? "AddAssign" : "Add";
+ return IsCompound ? "AddAssign" : "Add";
case Operator.BitwiseAnd:
- return is_compound ? "AndAssign" : "And";
+ return IsCompound ? "AndAssign" : "And";
case Operator.BitwiseOr:
- return is_compound ? "OrAssign" : "Or";
+ return IsCompound ? "OrAssign" : "Or";
case Operator.Division:
- return is_compound ? "DivideAssign" : "Divide";
+ return IsCompound ? "DivideAssign" : "Divide";
case Operator.ExclusiveOr:
- return is_compound ? "ExclusiveOrAssign" : "ExclusiveOr";
+ return IsCompound ? "ExclusiveOrAssign" : "ExclusiveOr";
case Operator.Equality:
return "Equal";
case Operator.GreaterThan:
case Operator.Inequality:
return "NotEqual";
case Operator.LeftShift:
- return is_compound ? "LeftShiftAssign" : "LeftShift";
+ return IsCompound ? "LeftShiftAssign" : "LeftShift";
case Operator.LessThan:
return "LessThan";
case Operator.LessThanOrEqual:
case Operator.LogicalOr:
return "Or";
case Operator.Modulus:
- return is_compound ? "ModuloAssign" : "Modulo";
+ return IsCompound ? "ModuloAssign" : "Modulo";
case Operator.Multiply:
- return is_compound ? "MultiplyAssign" : "Multiply";
+ return IsCompound ? "MultiplyAssign" : "Multiply";
case Operator.RightShift:
- return is_compound ? "RightShiftAssign" : "RightShift";
+ return IsCompound ? "RightShiftAssign" : "RightShift";
case Operator.Subtraction:
- return is_compound ? "SubtractAssign" : "Subtract";
+ return IsCompound ? "SubtractAssign" : "Subtract";
default:
throw new NotImplementedException ("Unknown expression type operator " + oper.ToString ());
}
}
- static string GetOperatorMetadataName (Operator op)
+ static CSharp.Operator.OpType ConvertBinaryToUserOperator (Operator op)
{
- CSharp.Operator.OpType op_type;
switch (op) {
case Operator.Addition:
- op_type = CSharp.Operator.OpType.Addition; break;
+ return CSharp.Operator.OpType.Addition;
case Operator.BitwiseAnd:
- op_type = CSharp.Operator.OpType.BitwiseAnd; break;
+ case Operator.LogicalAnd:
+ return CSharp.Operator.OpType.BitwiseAnd;
case Operator.BitwiseOr:
- op_type = CSharp.Operator.OpType.BitwiseOr; break;
+ case Operator.LogicalOr:
+ return CSharp.Operator.OpType.BitwiseOr;
case Operator.Division:
- op_type = CSharp.Operator.OpType.Division; break;
+ return CSharp.Operator.OpType.Division;
case Operator.Equality:
- op_type = CSharp.Operator.OpType.Equality; break;
+ return CSharp.Operator.OpType.Equality;
case Operator.ExclusiveOr:
- op_type = CSharp.Operator.OpType.ExclusiveOr; break;
+ return CSharp.Operator.OpType.ExclusiveOr;
case Operator.GreaterThan:
- op_type = CSharp.Operator.OpType.GreaterThan; break;
+ return CSharp.Operator.OpType.GreaterThan;
case Operator.GreaterThanOrEqual:
- op_type = CSharp.Operator.OpType.GreaterThanOrEqual; break;
+ return CSharp.Operator.OpType.GreaterThanOrEqual;
case Operator.Inequality:
- op_type = CSharp.Operator.OpType.Inequality; break;
+ return CSharp.Operator.OpType.Inequality;
case Operator.LeftShift:
- op_type = CSharp.Operator.OpType.LeftShift; break;
+ return CSharp.Operator.OpType.LeftShift;
case Operator.LessThan:
- op_type = CSharp.Operator.OpType.LessThan; break;
+ return CSharp.Operator.OpType.LessThan;
case Operator.LessThanOrEqual:
- op_type = CSharp.Operator.OpType.LessThanOrEqual; break;
+ return CSharp.Operator.OpType.LessThanOrEqual;
case Operator.Modulus:
- op_type = CSharp.Operator.OpType.Modulus; break;
+ return CSharp.Operator.OpType.Modulus;
case Operator.Multiply:
- op_type = CSharp.Operator.OpType.Multiply; break;
+ return CSharp.Operator.OpType.Multiply;
case Operator.RightShift:
- op_type = CSharp.Operator.OpType.RightShift; break;
+ return CSharp.Operator.OpType.RightShift;
case Operator.Subtraction:
- op_type = CSharp.Operator.OpType.Subtraction; break;
+ return CSharp.Operator.OpType.Subtraction;
default:
throw new InternalErrorException (op.ToString ());
}
-
- return CSharp.Operator.GetMetadataName (op_type);
}
public static void EmitOperatorOpcode (EmitContext ec, Operator oper, TypeSpec l)
public static void Reset ()
{
- pointer_operators = standard_operators = null;
+ equality_operators = pointer_operators = standard_operators = null;
}
Expression ResolveOperator (ResolveContext ec)
return ResolveOperatorPointer (ec, l, r);
// Enums
- bool lenum = TypeManager.IsEnumType (l);
- bool renum = TypeManager.IsEnumType (r);
+ bool lenum = l.IsEnum;
+ bool renum = r.IsEnum;
if (lenum || renum) {
expr = ResolveOperatorEnum (ec, lenum, renum, l, r);
- // TODO: Can this be ambiguous
if (expr != null)
return expr;
}
// Delegates
- if ((oper == Operator.Addition || oper == Operator.Subtraction || (oper & Operator.EqualityMask) != 0) &&
- (TypeManager.IsDelegateType (l) || TypeManager.IsDelegateType (r))) {
+ if ((oper == Operator.Addition || oper == Operator.Subtraction) && (l.IsDelegate || r.IsDelegate)) {
expr = ResolveOperatorDelegate (ec, l, r);
// Predefined reference types equality
if ((oper & Operator.EqualityMask) != 0) {
- expr = ResolveOperatorEqualityRerefence (ec, l, r);
+ expr = ResolveOperatorEquality (ec, l, r);
if (expr != null)
return expr;
}
temp.Add (new PredefinedOperator (TypeManager.double_type, Operator.ComparisonMask, bool_type));
temp.Add (new PredefinedOperator (TypeManager.decimal_type, Operator.ComparisonMask, bool_type));
- temp.Add (new PredefinedOperator (TypeManager.string_type, Operator.EqualityMask, bool_type));
-
temp.Add (new PredefinedStringOperator (TypeManager.string_type, Operator.AdditionMask));
temp.Add (new PredefinedStringOperator (TypeManager.string_type, TypeManager.object_type, Operator.AdditionMask));
temp.Add (new PredefinedStringOperator (TypeManager.object_type, TypeManager.string_type, Operator.AdditionMask));
temp.Add (new PredefinedShiftOperator (TypeManager.uint64_type, Operator.ShiftMask));
standard_operators = temp.ToArray ();
+
+ var equality = new List<PredefinedOperator> () {
+ new PredefinedEqualityOperator (TypeManager.string_type, bool_type),
+ new PredefinedEqualityOperator (TypeManager.delegate_type, bool_type),
+ new PredefinedOperator (bool_type, Operator.EqualityMask, bool_type)
+ };
+
+ equality_operators = equality.ToArray ();
}
//
//
// D operator + (D x, D y)
// D operator - (D x, D y)
- // bool operator == (D x, D y)
- // bool operator != (D x, D y)
//
Expression ResolveOperatorDelegate (ResolveContext ec, TypeSpec l, TypeSpec r)
{
- bool is_equality = (oper & Operator.EqualityMask) != 0;
- if (!TypeManager.IsEqual (l, r) && !TypeSpecComparer.Variant.IsEqual (r, l)) {
+ if (l != r && !TypeSpecComparer.Variant.IsEqual (r, l)) {
Expression tmp;
- if (right.eclass == ExprClass.MethodGroup || (r == InternalType.AnonymousMethod && !is_equality)) {
+ if (right.eclass == ExprClass.MethodGroup || r == InternalType.AnonymousMethod || r == InternalType.Null) {
tmp = Convert.ImplicitConversionRequired (ec, right, l, loc);
if (tmp == null)
return null;
right = tmp;
r = right.Type;
- } else if (left.eclass == ExprClass.MethodGroup || (l == InternalType.AnonymousMethod && !is_equality)) {
+ } else if (left.eclass == ExprClass.MethodGroup || (l == InternalType.AnonymousMethod)) {
tmp = Convert.ImplicitConversionRequired (ec, left, r, loc);
if (tmp == null)
return null;
}
}
- //
- // Resolve delegate equality as a user operator
- //
- if (is_equality)
- return ResolveUserOperator (ec, l, r);
-
MethodSpec method;
Arguments args = new Arguments (2);
args.Add (new Argument (left));
}
method = TypeManager.delegate_combine_delegate_delegate;
- } else {
+ } else if (oper == Operator.Subtraction) {
if (TypeManager.delegate_remove_delegate_delegate == null) {
TypeManager.delegate_remove_delegate_delegate = TypeManager.GetPredefinedMethod (
TypeManager.delegate_type, "Remove", loc, TypeManager.delegate_type, TypeManager.delegate_type);
}
method = TypeManager.delegate_remove_delegate_delegate;
- }
-
- if (method == null)
+ } else {
return new EmptyExpression (TypeManager.decimal_type);
+ }
- MethodGroupExpr mg = new MethodGroupExpr (method, TypeManager.delegate_type, loc);
- mg = mg.OverloadResolve (ec, ref args, false, loc);
-
- return new ClassCast (new UserOperatorCall (mg, args, CreateExpressionTree, loc), l);
+ MethodGroupExpr mg = MethodGroupExpr.CreatePredefined (method, TypeManager.delegate_type, loc);
+ Expression expr = new UserOperatorCall (mg.BestCandidate, args, CreateExpressionTree, loc);
+ return new ClassCast (expr, l);
}
//
//
// U operator - (E e, E f)
// E operator - (E e, U x)
+ // E operator - (U x, E e) // LAMESPEC: Not covered by the specification
//
- // E operator + (U x, E e)
// E operator + (E e, U x)
+ // E operator + (U x, E e)
//
- if (!((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0 ||
- (oper == Operator.Subtraction && lenum) ||
- (oper == Operator.Addition && (lenum != renum || type != null)))) // type != null for lifted null
- return null;
-
Expression ltemp = left;
Expression rtemp = right;
TypeSpec underlying_type;
+ TypeSpec underlying_type_result;
+ TypeSpec res_type;
Expression expr;
+ //
+ // LAMESPEC: There is never ambiguous conversion between enum operators
+ // the one which contains more enum parameters always wins even if there
+ // is an implicit conversion involved
+ //
if ((oper & (Operator.ComparisonMask | Operator.BitwiseMask)) != 0) {
if (renum) {
+ underlying_type = EnumSpec.GetUnderlyingType (rtype);
expr = Convert.ImplicitConversion (ec, left, rtype, loc);
- if (expr != null) {
+ if (expr == null)
+ return null;
+
+ left = expr;
+ ltype = expr.Type;
+ } else if (lenum) {
+ underlying_type = EnumSpec.GetUnderlyingType (ltype);
+ expr = Convert.ImplicitConversion (ec, right, ltype, loc);
+ if (expr == null)
+ return null;
+
+ right = expr;
+ rtype = expr.Type;
+ } else {
+ return null;
+ }
+
+ if ((oper & Operator.BitwiseMask) != 0) {
+ res_type = ltype;
+ underlying_type_result = underlying_type;
+ } else {
+ res_type = null;
+ underlying_type_result = null;
+ }
+ } else if (oper == Operator.Subtraction) {
+ if (renum) {
+ underlying_type = EnumSpec.GetUnderlyingType (rtype);
+ if (ltype != rtype) {
+ expr = Convert.ImplicitConversion (ec, left, rtype, left.Location);
+ if (expr == null) {
+ expr = Convert.ImplicitConversion (ec, left, underlying_type, left.Location);
+ if (expr == null)
+ return null;
+
+ res_type = rtype;
+ } else {
+ res_type = underlying_type;
+ }
+
left = expr;
- ltype = expr.Type;
+ } else {
+ res_type = underlying_type;
}
+
+ underlying_type_result = underlying_type;
} else if (lenum) {
- expr = Convert.ImplicitConversion (ec, right, ltype, loc);
- if (expr != null) {
+ underlying_type = EnumSpec.GetUnderlyingType (ltype);
+ expr = Convert.ImplicitConversion (ec, right, ltype, right.Location);
+ if (expr == null) {
+ expr = Convert.ImplicitConversion (ec, right, underlying_type, right.Location);
+ if (expr == null)
+ return null;
+
+ res_type = ltype;
+ } else {
+ res_type = underlying_type;
+ }
+
+ right = expr;
+ underlying_type_result = underlying_type;
+ } else {
+ return null;
+ }
+ } else if (oper == Operator.Addition) {
+ if (lenum) {
+ underlying_type = EnumSpec.GetUnderlyingType (ltype);
+ res_type = ltype;
+
+ if (rtype != underlying_type && (state & (State.RightNullLifted | State.LeftNullLifted)) == 0) {
+ expr = Convert.ImplicitConversion (ec, right, underlying_type, right.Location);
+ if (expr == null)
+ return null;
+
right = expr;
- rtype = expr.Type;
+ }
+ } else {
+ underlying_type = EnumSpec.GetUnderlyingType (rtype);
+ res_type = rtype;
+ if (ltype != underlying_type) {
+ expr = Convert.ImplicitConversion (ec, left, underlying_type, left.Location);
+ if (expr == null)
+ return null;
+
+ left = expr;
}
}
- }
- if (TypeManager.IsEqual (ltype, rtype)) {
- underlying_type = EnumSpec.GetUnderlyingType (ltype);
+ underlying_type_result = underlying_type;
+ } else {
+ return null;
+ }
+ // Unwrap the constant correctly, so DoBinaryOperatorPromotion can do the magic
+ // with constants and expressions
+ if (left.Type != underlying_type) {
if (left is Constant)
left = ((Constant) left).ConvertExplicitly (false, underlying_type).Resolve (ec);
else
left = EmptyCast.Create (left, underlying_type);
+ }
+ if (right.Type != underlying_type) {
if (right is Constant)
right = ((Constant) right).ConvertExplicitly (false, underlying_type).Resolve (ec);
else
right = EmptyCast.Create (right, underlying_type);
- } else if (lenum) {
- underlying_type = EnumSpec.GetUnderlyingType (ltype);
-
- if (oper != Operator.Subtraction && oper != Operator.Addition) {
- Constant c = right as Constant;
- if (c == null || !c.IsDefaultValue)
- return null;
- } else {
- if (!Convert.ImplicitStandardConversionExists (right, underlying_type))
- return null;
-
- right = Convert.ImplicitConversionStandard (ec, right, underlying_type, right.Location);
- }
-
- if (left is Constant)
- left = ((Constant) left).ConvertExplicitly (false, underlying_type).Resolve (ec);
- else
- left = EmptyCast.Create (left, underlying_type);
-
- } else if (renum) {
- underlying_type = EnumSpec.GetUnderlyingType (rtype);
-
- if (oper != Operator.Addition) {
- Constant c = left as Constant;
- if (c == null || !c.IsDefaultValue)
- return null;
- } else {
- if (!Convert.ImplicitStandardConversionExists (left, underlying_type))
- return null;
-
- left = Convert.ImplicitConversionStandard (ec, left, underlying_type, left.Location);
- }
-
- if (right is Constant)
- right = ((Constant) right).ConvertExplicitly (false, underlying_type).Resolve (ec);
- else
- right = EmptyCast.Create (right, underlying_type);
-
- } else {
- return null;
- }
+ }
//
// C# specification uses explicit cast syntax which means binary promotion
return null;
}
- TypeSpec res_type = null;
- if ((oper & Operator.BitwiseMask) != 0 || oper == Operator.Subtraction || oper == Operator.Addition) {
- TypeSpec promoted_type = lenum ? left.Type : right.Type;
- enum_conversion = Convert.ExplicitNumericConversion (
- new EmptyExpression (promoted_type), underlying_type);
-
- if (oper == Operator.Subtraction && renum && lenum)
- res_type = underlying_type;
- else if (oper == Operator.Addition && renum)
- res_type = rtype;
- else
- res_type = ltype;
+ if (underlying_type_result != null && left.Type != underlying_type_result) {
+ enum_conversion = Convert.ExplicitNumericConversion (new EmptyExpression (left.Type), underlying_type_result);
}
-
+
expr = ResolveOperatorPredefined (ec, standard_operators, true, res_type);
- if (!is_compound || expr == null)
+ if (expr == null)
+ return null;
+
+ if (!IsCompound)
return expr;
//
//
// 7.9.6 Reference type equality operators
//
- Binary ResolveOperatorEqualityRerefence (ResolveContext ec, TypeSpec l, TypeSpec r)
+ Expression ResolveOperatorEquality (ResolveContext ec, TypeSpec l, TypeSpec r)
{
+ Expression result;
+ type = TypeManager.bool_type;
+
+ //
+ // a, Both operands are reference-type values or the value null
+ // b, One operand is a value of type T where T is a type-parameter and
+ // the other operand is the value null. Furthermore T does not have the
+ // value type constraint
//
- // operator != (object a, object b)
- // operator == (object a, object b)
+ // LAMESPEC: Very confusing details in the specification, basically any
+ // reference like type-parameter is allowed
//
+ var tparam_l = l as TypeParameterSpec;
+ var tparam_r = r as TypeParameterSpec;
+ if (tparam_l != null) {
+ if (right is NullLiteral && !tparam_l.HasSpecialStruct) {
+ left = new BoxedCast (left, TypeManager.object_type);
+ return this;
+ }
- // TODO: this method is almost equivalent to Convert.ImplicitReferenceConversion
-
- if (left.eclass == ExprClass.MethodGroup || right.eclass == ExprClass.MethodGroup)
- return null;
-
- type = TypeManager.bool_type;
-
- var lgen = l as TypeParameterSpec;
+ if (!tparam_l.IsReferenceType)
+ return null;
- if (l == r) {
- if (l is InternalType)
+ l = tparam_l.GetEffectiveBase ();
+ left = new BoxedCast (left, l);
+ } else if (left is NullLiteral && tparam_r == null) {
+ if (!TypeManager.IsReferenceType (r) || r.Kind == MemberKind.InternalCompilerType)
return null;
- if (lgen != null) {
- //
- // Only allow to compare same reference type parameter
- //
- if (TypeManager.IsReferenceType (l)) {
- left = new BoxedCast (left, TypeManager.object_type);
- right = new BoxedCast (right, TypeManager.object_type);
- return this;
- }
+ return this;
+ }
- return null;
+ if (tparam_r != null) {
+ if (left is NullLiteral && !tparam_r.HasSpecialStruct) {
+ right = new BoxedCast (right, TypeManager.object_type);
+ return this;
}
- if (TypeManager.IsValueType (l))
+ if (!tparam_r.IsReferenceType)
+ return null;
+
+ r = tparam_r.GetEffectiveBase ();
+ right = new BoxedCast (right, r);
+ } else if (right is NullLiteral) {
+ if (!TypeManager.IsReferenceType (l) || l.Kind == MemberKind.InternalCompilerType)
return null;
return this;
}
- var rgen = r as TypeParameterSpec;
-
//
- // a, Both operands are reference-type values or the value null
- // b, One operand is a value of type T where T is a type-parameter and
- // the other operand is the value null. Furthermore T does not have the
- // value type constrain
+ // LAMESPEC: method groups can be compared when they convert to other side delegate
//
- if (left is NullLiteral || right is NullLiteral) {
- if (lgen != null) {
- if (lgen.HasSpecialStruct)
+ if (l.IsDelegate) {
+ if (right.eclass == ExprClass.MethodGroup) {
+ result = Convert.ImplicitConversion (ec, right, l, loc);
+ if (result == null)
return null;
- left = new BoxedCast (left, TypeManager.object_type);
- return this;
+ right = result;
+ r = l;
+ } else if (r.IsDelegate && l != r) {
+ return null;
}
+ } else if (left.eclass == ExprClass.MethodGroup && r.IsDelegate) {
+ result = Convert.ImplicitConversionRequired (ec, left, r, loc);
+ if (result == null)
+ return null;
- if (rgen != null) {
- if (rgen.HasSpecialStruct)
- return null;
-
- right = new BoxedCast (right, TypeManager.object_type);
- return this;
- }
+ left = result;
+ l = r;
}
//
- // An interface is converted to the object before the
- // standard conversion is applied. It's not clear from the
- // standard but it looks like it works like that.
+ // bool operator != (string a, string b)
+ // bool operator == (string a, string b)
//
- if (lgen != null) {
- if (!TypeManager.IsReferenceType (l))
- return null;
-
- l = TypeManager.object_type;
- left = new BoxedCast (left, l);
- } else if (l.IsInterface) {
- l = TypeManager.object_type;
- } else if (TypeManager.IsStruct (l)) {
- return null;
- }
-
- if (rgen != null) {
- if (!TypeManager.IsReferenceType (r))
- return null;
-
- r = TypeManager.object_type;
- right = new BoxedCast (right, r);
- } else if (r.IsInterface) {
- r = TypeManager.object_type;
- } else if (TypeManager.IsStruct (r)) {
- return null;
+ // bool operator != (Delegate a, Delegate b)
+ // bool operator == (Delegate a, Delegate b)
+ //
+ // bool operator != (bool a, bool b)
+ // bool operator == (bool a, bool b)
+ //
+ // LAMESPEC: Reference equality comparison can apply to value types when
+ // they implement an implicit conversion to any of types above.
+ //
+ if (r != TypeManager.object_type && l != TypeManager.object_type) {
+ result = ResolveOperatorPredefined (ec, equality_operators, false, null);
+ if (result != null)
+ return result;
}
-
- const string ref_comparison = "Possible unintended reference comparison. " +
- "Consider casting the {0} side of the expression to `string' to compare the values";
-
//
- // A standard implicit conversion exists from the type of either
- // operand to the type of the other operand
+ // bool operator != (object a, object b)
+ // bool operator == (object a, object b)
+ //
+ // An explicit reference conversion exists from the
+ // type of either operand to the type of the other operand.
//
- if (Convert.ImplicitReferenceConversionExists (left, r)) {
- if (l == TypeManager.string_type)
- ec.Report.Warning (253, 2, loc, ref_comparison, "right");
- return this;
+ // Optimize common path
+ if (l == r) {
+ return l.Kind == MemberKind.InternalCompilerType || l.Kind == MemberKind.Struct ? null : this;
}
- if (Convert.ImplicitReferenceConversionExists (right, l)) {
- if (r == TypeManager.string_type)
- ec.Report.Warning (252, 2, loc, ref_comparison, "left");
+ if (!Convert.ExplicitReferenceConversionExists (l, r) &&
+ !Convert.ExplicitReferenceConversionExists (r, l))
+ return null;
+
+ // Reject allowed explicit conversions like int->object
+ if (!TypeManager.IsReferenceType (l) || !TypeManager.IsReferenceType (r))
+ return null;
- return this;
- }
+ if (l == TypeManager.string_type || l == TypeManager.delegate_type || MemberCache.GetUserOperator (l, CSharp.Operator.OpType.Equality, false) != null)
+ ec.Report.Warning (253, 2, loc,
+ "Possible unintended reference comparison. Consider casting the right side expression to type `{0}' to get value comparison",
+ l.GetSignatureForError ());
- return null;
+ if (r == TypeManager.string_type || r == TypeManager.delegate_type || MemberCache.GetUserOperator (r, CSharp.Operator.OpType.Equality, false) != null)
+ ec.Report.Warning (252, 2, loc,
+ "Possible unintended reference comparison. Consider casting the left side expression to type `{0}' to get value comparison",
+ r.GetSignatureForError ());
+
+ return this;
}
if (oper == Operator.BitwiseAnd || oper == Operator.LogicalAnd) {
Constant rc = right as Constant;
Constant lc = left as Constant;
- if ((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue)) {
+ if (((lc != null && lc.IsDefaultValue) || (rc != null && rc.IsDefaultValue)) && !(this is Nullable.LiftedBinaryOperator)) {
//
// The result is a constant with side-effect
//
//
protected virtual Expression ResolveUserOperator (ResolveContext ec, TypeSpec l, TypeSpec r)
{
- Operator user_oper;
- if (oper == Operator.LogicalAnd)
- user_oper = Operator.BitwiseAnd;
- else if (oper == Operator.LogicalOr)
- user_oper = Operator.BitwiseOr;
- else
- user_oper = oper;
+ var op = ConvertBinaryToUserOperator (oper);
+ IList<MemberSpec> left_operators = MemberCache.GetUserOperator (l, op, false);
+ IList<MemberSpec> right_operators = null;
- string op = GetOperatorMetadataName (user_oper);
-
- MethodGroupExpr left_operators = MethodLookup (ec.Compiler, ec.CurrentType, l, MemberKind.Operator, op, 0, loc);
- MethodGroupExpr right_operators = null;
-
- if (!TypeManager.IsEqual (r, l)) {
- right_operators = MethodLookup (ec.Compiler, ec.CurrentType, r, MemberKind.Operator, op, 0, loc);
+ if (l != r) {
+ right_operators = MemberCache.GetUserOperator (r, op, false);
if (right_operators == null && left_operators == null)
return null;
} else if (left_operators == null) {
Argument rarg = new Argument (right);
args.Add (rarg);
- MethodGroupExpr union;
-
//
// User-defined operator implementations always take precedence
// over predefined operator implementations
//
if (left_operators != null && right_operators != null) {
- if (IsPredefinedUserOperator (l, user_oper)) {
- union = right_operators.OverloadResolve (ec, ref args, true, loc);
- if (union == null)
- union = left_operators;
- } else if (IsPredefinedUserOperator (r, user_oper)) {
- union = left_operators.OverloadResolve (ec, ref args, true, loc);
- if (union == null)
- union = right_operators;
- } else {
- union = MethodGroupExpr.MakeUnionSet (left_operators, right_operators, loc);
- }
- } else if (left_operators != null) {
- union = left_operators;
- } else {
- union = right_operators;
+ left_operators = CombineUserOperators (left_operators, right_operators);
+ } else if (right_operators != null) {
+ left_operators = right_operators;
}
- union = union.OverloadResolve (ec, ref args, true, loc);
- if (union == null)
+ var res = new OverloadResolver (left_operators, OverloadResolver.Restrictions.ProbingOnly |
+ OverloadResolver.Restrictions.NoBaseMembers | OverloadResolver.Restrictions.BaseMembersIncluded, loc);
+
+ var oper_method = res.ResolveOperator (ec, ref args);
+ if (oper_method == null)
return null;
Expression oper_expr;
// TODO: CreateExpressionTree is allocated every time
- if (user_oper != oper) {
- oper_expr = new ConditionalLogicalOperator (union, args, CreateExpressionTree,
+ if ((oper & Operator.LogicalMask) != 0) {
+ oper_expr = new ConditionalLogicalOperator (oper_method, args, CreateExpressionTree,
oper == Operator.LogicalAnd, loc).Resolve (ec);
} else {
- oper_expr = new UserOperatorCall (union, args, CreateExpressionTree, loc);
-
- //
- // This is used to check if a test 'x == null' can be optimized to a reference equals,
- // and not invoke user operator
- //
- if ((oper & Operator.EqualityMask) != 0) {
- if ((left is NullLiteral && IsBuildInEqualityOperator (r)) ||
- (right is NullLiteral && IsBuildInEqualityOperator (l))) {
- type = TypeManager.bool_type;
- if (left is NullLiteral || right is NullLiteral)
- oper_expr = ReducedExpression.Create (this, oper_expr);
- } else if (l != r) {
- var mi = union.BestCandidate;
-
- //
- // Two System.Delegate(s) are never equal
- //
- if (mi.DeclaringType == TypeManager.multicast_delegate_type)
- return null;
- }
- }
+ oper_expr = new UserOperatorCall (oper_method, args, CreateExpressionTree, loc);
}
left = larg.Expr;
return oper_expr;
}
+ //
+ // Merge two sets of user operators into one, they are mostly distinguish
+ // expect when they share base type and it contains an operator
+ //
+ static IList<MemberSpec> CombineUserOperators (IList<MemberSpec> left, IList<MemberSpec> right)
+ {
+ var combined = new List<MemberSpec> (left.Count + right.Count);
+ combined.AddRange (left);
+ foreach (var r in right) {
+ bool same = false;
+ foreach (var l in left) {
+ if (l.DeclaringType == r.DeclaringType) {
+ same = true;
+ break;
+ }
+ }
+
+ if (!same)
+ combined.Add (r);
+ }
+
+ return combined;
+ }
+
public override TypeExpr ResolveAsTypeTerminal (IMemberContext ec, bool silent)
{
return null;
type == TypeManager.uint32_type && value >= 0x100000000;
}
- static bool IsBuildInEqualityOperator (TypeSpec t)
- {
- return t == TypeManager.object_type || t == TypeManager.string_type ||
- t == TypeManager.delegate_type || TypeManager.IsDelegateType (t);
- }
-
- static bool IsPredefinedUserOperator (TypeSpec t, Operator op)
- {
- //
- // Some predefined types have user operators
- //
- return (op & Operator.EqualityMask) != 0 && (t == TypeManager.string_type || t == TypeManager.decimal_type);
- }
-
private static bool IsTypeIntegral (TypeSpec type)
{
return type == TypeManager.uint64_type ||
binder_args.Add (new Argument (new EnumConstant (new IntLiteral ((int) flags, loc), TypeManager.binder_flags)));
binder_args.Add (new Argument (new MemberAccess (new MemberAccess (sle, "ExpressionType", loc), GetOperatorExpressionTypeName (), loc)));
binder_args.Add (new Argument (new TypeOf (new TypeExpression (ec.CurrentType, loc), loc)));
- binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation ("[]", args.CreateDynamicBinderArguments (ec), loc)));
+ binder_args.Add (new Argument (new ImplicitlyTypedArrayCreation (args.CreateDynamicBinderArguments (ec), loc)));
return new Invocation (DynamicExpressionStatement.GetBinder ("BinaryOperation", loc), binder_args);
}
return CreateExpressionTree (ec, null);
}
- Expression CreateExpressionTree (ResolveContext ec, MethodGroupExpr method)
+ Expression CreateExpressionTree (ResolveContext ec, Expression method)
{
string method_name;
bool lift_arg = false;
if (method != null) {
if (lift_arg)
args.Add (new Argument (new BoolConstant (false, loc)));
-
- args.Add (new Argument (method.CreateExpressionTree (ec)));
+
+ args.Add (new Argument (method));
}
return CreateExpressionFactoryCall (ec, method_name, args);
//
public class StringConcat : Expression {
Arguments arguments;
+ static IList<MemberSpec> concat_members;
public StringConcat (Expression left, Expression right, Location loc)
{
concat_args.Add (arguments [pos]);
add_args.Add (new Argument (arguments [pos].CreateExpressionTree (ec)));
- MethodGroupExpr method = CreateConcatMemberExpression ().Resolve (ec) as MethodGroupExpr;
- if (method == null)
+ var methods = CreateConcatMethodCandidates ();
+ if (methods == null)
return null;
- method = method.OverloadResolve (ec, ref concat_args, false, loc);
+ var res = new OverloadResolver (methods, OverloadResolver.Restrictions.NoBaseMembers, loc);
+ var method = res.ResolveMember<MethodSpec> (ec, ref concat_args);
if (method == null)
return null;
- add_args.Add (new Argument (method.CreateExpressionTree (ec)));
+ add_args.Add (new Argument (new TypeOfMethod (method, loc)));
Expression expr = CreateExpressionFactoryCall (ec, "Add", add_args);
if (++pos == arguments.Count)
return expr;
- left = new Argument (new EmptyExpression (method.BestCandidate.ReturnType));
+ left = new Argument (new EmptyExpression (method.ReturnType));
return CreateExpressionAddCall (ec, left, expr, pos);
}
arguments.Add (new Argument (operand));
}
- Expression CreateConcatMemberExpression ()
+ IList<MemberSpec> CreateConcatMethodCandidates ()
{
- return new MemberAccess (new MemberAccess (new QualifiedAliasMember ("global", "System", loc), "String", loc), "Concat", loc);
+ if (concat_members == null) {
+ concat_members = MemberCache.FindMembers (type, "Concat", true);
+ }
+
+ return concat_members;
}
public override void Emit (EmitContext ec)
{
- Expression concat = new Invocation (CreateConcatMemberExpression (), arguments, true);
- concat = concat.Resolve (new ResolveContext (ec.MemberContext));
- if (concat != null)
- concat.Emit (ec);
+ var members = CreateConcatMethodCandidates ();
+ var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
+ var method = res.ResolveMember<MethodSpec> (new ResolveContext (ec.MemberContext), ref arguments);
+ if (method != null)
+ Invocation.EmitCall (ec, null, method, arguments, loc);
}
public override SLE.Expression MakeExpression (BuilderContext ctx)
var concat = typeof (string).GetMethod ("Concat", new[] { typeof (object), typeof (object) });
return SLE.Expression.Add (arguments[0].Expr.MakeExpression (ctx), arguments[1].Expr.MakeExpression (ctx), concat);
}
+
+ public static void Reset ()
+ {
+ concat_members = null;
+ }
}
//
//
public class ConditionalLogicalOperator : UserOperatorCall {
readonly bool is_and;
- Expression oper;
+ Expression oper_expr;
- public ConditionalLogicalOperator (MethodGroupExpr oper_method, Arguments arguments,
- ExpressionTreeExpression expr_tree, bool is_and, Location loc)
- : base (oper_method, arguments, expr_tree, loc)
+ public ConditionalLogicalOperator (MethodSpec oper, Arguments arguments, Func<ResolveContext, Expression, Expression> expr_tree, bool is_and, Location loc)
+ : base (oper, arguments, expr_tree, loc)
{
this.is_and = is_and;
eclass = ExprClass.Unresolved;
protected override Expression DoResolve (ResolveContext ec)
{
- var method = mg.BestCandidate;
- type = method.ReturnType;
- AParametersCollection pd = method.Parameters;
- if (!TypeManager.IsEqual (type, type) || !TypeManager.IsEqual (type, pd.Types [0]) || !TypeManager.IsEqual (type, pd.Types [1])) {
+ AParametersCollection pd = oper.Parameters;
+ if (!TypeSpecComparer.IsEqual (type, pd.Types[0]) || !TypeSpecComparer.IsEqual (type, pd.Types[1])) {
ec.Report.Error (217, loc,
"A user-defined operator `{0}' must have parameters and return values of the same type in order to be applicable as a short circuit operator",
- TypeManager.CSharpSignature (method));
+ oper.GetSignatureForError ());
return null;
}
if (op_true == null || op_false == null) {
ec.Report.Error (218, loc,
"The type `{0}' must have operator `true' and operator `false' defined when `{1}' is used as a short circuit operator",
- TypeManager.CSharpName (type), TypeManager.CSharpSignature (method));
+ TypeManager.CSharpName (type), oper.GetSignatureForError ());
return null;
}
- oper = is_and ? op_false : op_true;
+ oper_expr = is_and ? op_false : op_true;
eclass = ExprClass.Value;
return this;
}
ec.Emit (OpCodes.Dup);
arguments.RemoveAt (0);
- oper.EmitBranchable (ec, end_target, true);
+ oper_expr.EmitBranchable (ec, end_target, true);
base.Emit (ec);
ec.MarkLabel (end_target);
}
eclass = ExprClass.Variable;
if (left.Type == TypeManager.void_ptr_type) {
- ec.Report.Error (242, loc, "The operation in question is undefined on void pointers");
+ Error_VoidPointerOperation (ec);
return null;
}
public class Conditional : Expression {
Expression expr, true_expr, false_expr;
- public Conditional (BooleanExpression expr, Expression true_expr, Expression false_expr)
+ public Conditional (BooleanExpression expr, Expression true_expr, Expression false_expr, Location loc)
{
this.expr = expr;
this.true_expr = true_expr;
this.false_expr = false_expr;
- this.loc = expr.Location;
+ this.loc = loc;
}
public Expression Expr {
// First, if an implicit conversion exists from true_expr
// to false_expr, then the result type is of type false_expr.Type
//
- if (!TypeManager.IsEqual (true_type, false_type)) {
+ if (!TypeSpecComparer.IsEqual (true_type, false_type)) {
Expression conv = Convert.ImplicitConversion (ec, true_expr, false_type, loc);
if (conv != null) {
//
// Check if both can convert implicitly to each other's type
//
- if (Convert.ImplicitConversion (ec, false_expr, true_type, loc) != null) {
- ec.Report.Error (172, true_expr.Location,
- "Type of conditional expression cannot be determined as `{0}' and `{1}' convert implicitly to each other",
- TypeManager.CSharpName (true_type), TypeManager.CSharpName (false_type));
- return null;
+ if (true_type != InternalType.Dynamic) {
+ type = false_type;
+
+ if (false_type != InternalType.Dynamic && Convert.ImplicitConversion (ec, false_expr, true_type, loc) != null) {
+ ec.Report.Error (172, true_expr.Location,
+ "Type of conditional expression cannot be determined as `{0}' and `{1}' convert implicitly to each other",
+ TypeManager.CSharpName (true_type), TypeManager.CSharpName (false_type));
+ return null;
+ }
}
- type = false_type;
+
true_expr = conv;
} else if ((conv = Convert.ImplicitConversion (ec, false_expr, true_type, loc)) != null) {
false_expr = conv;
New n_source = source as New;
if (n_source != null) {
if (!n_source.Emit (ec, this)) {
- if (leave_copy)
+ if (leave_copy) {
EmitLoad (ec);
+ if (IsRef)
+ ec.EmitLoadFromPtr (type);
+ }
return;
}
} else {
}
}
- /// <summary>
- /// Local variables
- /// </summary>
- public class LocalVariableReference : VariableReference {
- readonly string name;
- public Block Block;
- public LocalInfo local_info;
- bool is_readonly;
+ //
+ // Resolved reference to a local variable
+ //
+ public class LocalVariableReference : VariableReference
+ {
+ public LocalVariable local_info;
- public LocalVariableReference (Block block, string name, Location l)
+ public LocalVariableReference (LocalVariable li, Location l)
{
- Block = block;
- this.name = name;
+ this.local_info = li;
loc = l;
}
- //
- // Setting `is_readonly' to false will allow you to create a writable
- // reference to a read-only variable. This is used by foreach and using.
- //
- public LocalVariableReference (Block block, string name, Location l,
- LocalInfo local_info, bool is_readonly)
- : this (block, name, l)
- {
- this.local_info = local_info;
- this.is_readonly = is_readonly;
- }
-
public override VariableInfo VariableInfo {
get { return local_info.VariableInfo; }
}
get { return false; }
}
- public bool IsReadOnly {
- get { return is_readonly; }
- }
-
public override string Name {
- get { return name; }
+ get { return local_info.Name; }
}
public bool VerifyAssigned (ResolveContext ec)
return variable_info == null || variable_info.IsAssigned (ec, loc);
}
- void ResolveLocalInfo ()
- {
- if (local_info == null) {
- local_info = Block.GetLocalInfo (Name);
- type = local_info.VariableType;
- is_readonly = local_info.ReadOnly;
- }
- }
-
public override void SetHasAddressTaken ()
{
local_info.AddressTaken = true;
Expression DoResolveBase (ResolveContext ec)
{
- Expression e = Block.GetConstantExpression (Name);
- if (e != null)
- return e.Resolve (ec);
-
VerifyAssigned (ec);
//
}
eclass = ExprClass.Variable;
- type = local_info.VariableType;
+ type = local_info.Type;
return this;
}
protected override Expression DoResolve (ResolveContext ec)
{
- ResolveLocalInfo ();
- local_info.Used = true;
+ local_info.SetIsUsed ();
- if (type == null && local_info.Type is VarExpr) {
- local_info.VariableType = TypeManager.object_type;
- Error_VariableIsUsedBeforeItIsDeclared (ec.Report, Name);
- return null;
- }
-
return DoResolveBase (ec);
}
public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
{
- ResolveLocalInfo ();
-
// is out param
if (right_side == EmptyExpression.OutAccess.Instance)
- local_info.Used = true;
+ local_info.SetIsUsed ();
- // Infer implicitly typed local variable
- if (type == null) {
- VarExpr ve = local_info.Type as VarExpr;
- if (ve != null) {
- if (!ve.InferType (ec, right_side))
- return null;
- type = local_info.VariableType = ve.Type;
- }
- }
-
- if (is_readonly) {
+ if (local_info.IsReadonly && !ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.UsingInitializerScope)) {
int code;
string msg;
if (right_side == EmptyExpression.OutAccess.Instance) {
public override int GetHashCode ()
{
- return Name.GetHashCode ();
+ return local_info.GetHashCode ();
}
public override bool Equals (object obj)
if (lvr == null)
return false;
- return Name == lvr.Name && Block == lvr.Block;
+ return local_info == lvr.local_info;
}
protected override ILocalVariable Variable {
protected override void CloneTo (CloneContext clonectx, Expression t)
{
- LocalVariableReference target = (LocalVariableReference) t;
-
- target.Block = clonectx.LookupBlock (Block);
- if (local_info != null)
- target.local_info = clonectx.LookupVariable (local_info);
+ // Nothing
}
}
/// This represents a reference to a parameter in the intermediate
/// representation.
/// </summary>
- public class ParameterReference : VariableReference {
- readonly ToplevelParameterInfo pi;
+ public class ParameterReference : VariableReference
+ {
+ protected ParametersBlock.ParameterInfo pi;
- public ParameterReference (ToplevelParameterInfo pi, Location loc)
+ public ParameterReference (ParametersBlock.ParameterInfo pi, Location loc)
{
this.pi = pi;
this.loc = loc;
}
+ #region Properties
+
public override bool IsRef {
get { return (pi.Parameter.ModFlags & Parameter.Modifier.ISBYREF) != 0; }
}
get { return Parameter; }
}
+ #endregion
+
public bool IsAssigned (ResolveContext ec, Location loc)
{
// HACK: Variables are not captured in probing mode
type = pi.ParameterType;
eclass = ExprClass.Variable;
- AnonymousExpression am = ec.CurrentAnonymousMethod;
- if (am == null)
- return true;
-
- Block b = ec.CurrentBlock;
- while (b != null) {
- b = b.Toplevel;
- IParameterData[] p = b.Toplevel.Parameters.FixedParameters;
- for (int i = 0; i < p.Length; ++i) {
- if (p [i] != Parameter)
- continue;
-
- //
- // Don't capture local parameters
- //
- if (b == ec.CurrentBlock.Toplevel && !am.IsIterator)
- return true;
-
- if (IsRef) {
- ec.Report.Error (1628, loc,
- "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
- Name, am.ContainerType);
- }
-
- if (pi.Parameter.HasAddressTaken)
- AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
-
- if (ec.IsVariableCapturingRequired && !b.Toplevel.IsExpressionTree) {
- AnonymousMethodStorey storey = pi.Block.CreateAnonymousMethodStorey (ec);
- storey.CaptureParameter (ec, this);
- }
+ //
+ // If we are referencing a parameter from the external block
+ // flag it for capturing
+ //
+ if (ec.MustCaptureVariable (pi)) {
+ if (Parameter.HasAddressTaken)
+ AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
- return true;
+ if (IsRef) {
+ ec.Report.Error (1628, loc,
+ "Parameter `{0}' cannot be used inside `{1}' when using `ref' or `out' modifier",
+ Name, ec.CurrentAnonymousMethod.ContainerType);
}
- b = b.Parent;
+ if (ec.IsVariableCapturingRequired && !pi.Block.ParametersBlock.IsExpressionTree) {
+ AnonymousMethodStorey storey = pi.Block.Explicit.CreateAnonymousMethodStorey (ec);
+ storey.CaptureParameter (ec, this);
+ }
}
return true;
protected override void CloneTo (CloneContext clonectx, Expression target)
{
// Nothing to clone
+ return;
}
public override Expression CreateExpressionTree (ResolveContext ec)
protected Arguments arguments;
protected Expression expr;
protected MethodGroupExpr mg;
- bool arguments_resolved;
- //
- // arguments is an ArrayList, but we do not want to typecast,
- // as it might be null.
- //
public Invocation (Expression expr, Arguments arguments)
{
- SimpleName sn = expr as SimpleName;
- if (sn != null)
- this.expr = sn.GetMethodGroup ();
- else
- this.expr = expr;
-
+ this.expr = expr;
this.arguments = arguments;
if (expr != null)
loc = expr.Location;
}
- public Invocation (Expression expr, Arguments arguments, bool arguments_resolved)
- : this (expr, arguments)
+ #region Properties
+ public Arguments Arguments {
+ get {
+ return arguments;
+ }
+ }
+
+ public Expression Expression {
+ get {
+ return expr;
+ }
+ }
+ #endregion
+
+ protected override void CloneTo (CloneContext clonectx, Expression t)
{
- this.arguments_resolved = arguments_resolved;
+ Invocation target = (Invocation) t;
+
+ if (arguments != null)
+ target.arguments = arguments.Clone (clonectx);
+
+ target.expr = expr.Clone (clonectx);
}
+
public override Expression CreateExpressionTree (ResolveContext ec)
{
Expression instance = mg.IsInstance ?
instance,
mg.CreateExpressionTree (ec));
- if (mg.IsBase)
- MemberExpr.Error_BaseAccessInExpressionTree (ec, loc);
-
return CreateExpressionFactoryCall (ec, "Call", args);
}
protected override Expression DoResolve (ResolveContext ec)
{
- Expression member_expr = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
+ Expression member_expr;
+ var atn = expr as ATypeNameExpression;
+ if (atn != null) {
+ member_expr = atn.LookupNameExpression (ec, MemberLookupRestrictions.InvocableOnly | MemberLookupRestrictions.ReadAccess);
+ if (member_expr != null)
+ member_expr = member_expr.Resolve (ec);
+ } else {
+ member_expr = expr.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup);
+ }
+
if (member_expr == null)
return null;
// Next, evaluate all the expressions in the argument list
//
bool dynamic_arg = false;
- if (arguments != null && !arguments_resolved)
+ if (arguments != null)
arguments.Resolve (ec, out dynamic_arg);
TypeSpec expr_type = member_expr.Type;
return null;
}
- mg = ec.LookupExtensionMethod (me.Type, me.Name, -1, loc);
- if (mg == null) {
- ec.Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
+ ec.Report.Error (1955, loc, "The member `{0}' cannot be used as method or delegate",
member_expr.GetSignatureForError ());
- return null;
- }
-
- ((ExtensionMethodGroupExpr) mg).ExtensionExpression = me.InstanceExpression;
+ return null;
}
}
type = method.ReturnType;
}
- //
- // Only base will allow this invocation to happen.
- //
- if (mg.IsBase && method.IsAbstract){
- Error_CannotCallAbstractBase (ec, TypeManager.CSharpSignature (method));
- return null;
- }
-
if (arguments == null && method.DeclaringType == TypeManager.object_type && method.Name == Destructor.MetadataName) {
if (mg.IsBase)
ec.Report.Error (250, loc, "Do not directly call your base class Finalize method. It is called automatically from your destructor");
return null;
}
- args = arguments;
-
- if (mg.IsStatic != mg.IsInstance) {
- if (args == null)
- args = new Arguments (1);
+ if (arguments == null)
+ args = new Arguments (1);
+ else
+ args = arguments;
- if (mg.IsStatic) {
- args.Insert (0, new Argument (new TypeOf (new TypeExpression (mg.DeclaringType, loc), loc).Resolve (ec), Argument.AType.DynamicTypeName));
+ MemberAccess ma = expr as MemberAccess;
+ if (ma != null) {
+ var left_type = ma.LeftExpression as TypeExpr;
+ if (left_type != null) {
+ args.Insert (0, new Argument (new TypeOf (left_type, loc).Resolve (ec), Argument.AType.DynamicTypeName));
} else {
- MemberAccess ma = expr as MemberAccess;
- if (ma != null)
- args.Insert (0, new Argument (ma.Left.Resolve (ec)));
- else
- args.Insert (0, new Argument (new This (loc).Resolve (ec)));
+ args.Insert (0, new Argument (ma.LeftExpression.Resolve (ec)));
+ }
+ } else { // is SimpleName
+ if (ec.IsStatic) {
+ args.Insert (0, new Argument (new TypeOf (new TypeExpression (ec.CurrentType, loc), loc).Resolve (ec), Argument.AType.DynamicTypeName));
+ } else {
+ args.Insert (0, new Argument (new This (loc).Resolve (ec)));
}
}
}
protected virtual MethodGroupExpr DoResolveOverload (ResolveContext ec)
{
- return mg.OverloadResolve (ec, ref arguments, false, loc);
+ return mg.OverloadResolve (ec, ref arguments, null, OverloadResolver.Restrictions.None);
}
- public static bool IsSpecialMethodInvocation (ResolveContext ec, MethodSpec method, Location loc)
+ static Type[] GetVarargsTypes (MethodSpec mb, Arguments arguments)
{
- if (!method.IsReservedMethod)
+ AParametersCollection pd = mb.Parameters;
+
+ Argument a = arguments[pd.Count - 1];
+ Arglist list = (Arglist) a.Expr;
+
+ return list.ArgumentTypes;
+ }
+
+ //
+ // If a member is a method or event, or if it is a constant, field or property of either a delegate type
+ // or the type dynamic, then the member is invocable
+ //
+ public static bool IsMemberInvocable (MemberSpec member)
+ {
+ switch (member.Kind) {
+ case MemberKind.Event:
+ return true;
+ case MemberKind.Field:
+ case MemberKind.Property:
+ var m = member as IInterfaceMemberSpec;
+ return m.MemberType.IsDelegate || m.MemberType == InternalType.Dynamic;
+ default:
+ return false;
+ }
+ }
+
+ public static bool IsSpecialMethodInvocation (ResolveContext ec, MethodSpec method, Location loc)
+ {
+ if (!method.IsReservedMethod)
return false;
- if (ec.HasSet (ResolveContext.Options.InvokeSpecialName))
+ if (ec.HasSet (ResolveContext.Options.InvokeSpecialName) || ec.CurrentMemberDefinition.IsCompilerGenerated)
return false;
ec.Report.SymbolRelatedToPreviousError (method);
return true;
}
- static Type[] GetVarargsTypes (MethodSpec mb, Arguments arguments)
+ //
+ // Used to decide whether call or callvirt is needed
+ //
+ static bool IsVirtualCallRequired (Expression instance, MethodSpec method)
{
- AParametersCollection pd = mb.Parameters;
-
- Argument a = arguments [pd.Count - 1];
- Arglist list = (Arglist) a.Expr;
+ //
+ // There are 2 scenarious where we emit callvirt
+ //
+ // Case 1: A method is virtual and it's not used to call base
+ // Case 2: A method instance expression can be null. In this casen callvirt ensures
+ // correct NRE exception when the method is called
+ //
+ var decl_type = method.DeclaringType;
+ if (decl_type.IsStruct || decl_type.IsEnum)
+ return false;
- return list.ArgumentTypes;
+ if (instance is BaseThis)
+ return false;
+
+ //
+ // It's non-virtual and will never be null
+ //
+ if (!method.IsVirtual && (instance is This || instance is New || instance is ArrayCreation || instance is DelegateCreation || instance is TypeOf))
+ return false;
+
+ return true;
}
/// <remarks>
///
/// Arguments is the list of arguments to pass to the method or constructor.
/// </remarks>
- public static void EmitCall (EmitContext ec, bool is_base,
- Expression instance_expr,
+ public static void EmitCall (EmitContext ec, Expression instance_expr,
MethodSpec method, Arguments Arguments, Location loc)
{
- EmitCall (ec, is_base, instance_expr, method, Arguments, loc, false, false);
+ EmitCall (ec, instance_expr, method, Arguments, loc, false, false);
}
// `dup_args' leaves an extra copy of the arguments on the stack
// and then another with `omit_args' set to true, and the two calls
// would have the same set of arguments. However, each argument would
// only have been evaluated once.
- public static void EmitCall (EmitContext ec, bool is_base,
- Expression instance_expr,
+ public static void EmitCall (EmitContext ec, Expression instance_expr,
MethodSpec method, Arguments Arguments, Location loc,
bool dup_args, bool omit_args)
{
LocalTemporary this_arg = null;
- TypeSpec decl_type = method.DeclaringType;
-
// Speed up the check by not doing it on not allowed targets
if (method.ReturnType == TypeManager.void_type && method.IsConditionallyExcluded (loc))
return;
} else {
iexpr_type = instance_expr.Type;
- if (is_base || decl_type.IsStruct || decl_type.IsEnum || (instance_expr is This && !method.IsVirtual)) {
- call_op = OpCodes.Call;
- } else {
+ if (IsVirtualCallRequired (instance_expr, method)) {
call_op = OpCodes.Callvirt;
+ } else {
+ call_op = OpCodes.Call;
}
//
//
// Push the instance expression
//
- if ((iexpr_type.IsStruct && (call_op == OpCodes.Callvirt || (call_op == OpCodes.Call && decl_type == iexpr_type))) ||
- iexpr_type.IsGenericParameter || TypeManager.IsNullableType (decl_type)) {
+ if ((iexpr_type.IsStruct && (call_op == OpCodes.Callvirt || (call_op == OpCodes.Call && method.DeclaringType == iexpr_type))) ||
+ iexpr_type.IsGenericParameter || TypeManager.IsNullableType (method.DeclaringType)) {
//
// If the expression implements IMemoryLocation, then
// we can optimize and use AddressOf on the
ec.Emit (OpCodes.Pop);
}
- protected override void CloneTo (CloneContext clonectx, Expression t)
- {
- Invocation target = (Invocation) t;
-
- if (arguments != null)
- target.arguments = arguments.Clone (clonectx);
-
- target.expr = expr.Clone (clonectx);
- }
-
public override SLE.Expression MakeExpression (BuilderContext ctx)
{
- return MakeExpression (ctx, mg.InstanceExpression, (MethodSpec) mg, arguments);
+ return MakeExpression (ctx, mg.InstanceExpression, mg.BestCandidate, arguments);
}
public static SLE.Expression MakeExpression (BuilderContext ctx, Expression instance, MethodSpec mi, Arguments args)
}
}
- /// <summary>
- /// Implements the new expression
- /// </summary>
- public class New : ExpressionStatement, IMemoryLocation {
- protected Arguments Arguments;
+ //
+ // Implements simple new expression
+ //
+ public class New : ExpressionStatement, IMemoryLocation
+ {
+ protected Arguments arguments;
//
// During bootstrap, it contains the RequestedType,
//
protected Expression RequestedType;
- protected MethodGroupExpr method;
+ protected MethodSpec method;
public New (Expression requested_type, Arguments arguments, Location l)
{
RequestedType = requested_type;
- Arguments = arguments;
+ this.arguments = arguments;
loc = l;
}
+ #region Properties
+ public Arguments Arguments {
+ get {
+ return arguments;
+ }
+ }
+
+ //
+ // Returns true for resolved `new S()'
+ //
+ public bool IsDefaultStruct {
+ get {
+ return arguments == null && type.IsStruct && GetType () == typeof (New);
+ }
+ }
+
+ #endregion
+
/// <summary>
/// Converts complex core type syntax like 'new int ()' to simple constant
/// </summary>
- public static Constant Constantify (TypeSpec t)
+ public static Constant Constantify (TypeSpec t, Location loc)
{
if (t == TypeManager.int32_type)
- return new IntConstant (0, Location.Null);
+ return new IntConstant (0, loc);
if (t == TypeManager.uint32_type)
- return new UIntConstant (0, Location.Null);
+ return new UIntConstant (0, loc);
if (t == TypeManager.int64_type)
- return new LongConstant (0, Location.Null);
+ return new LongConstant (0, loc);
if (t == TypeManager.uint64_type)
- return new ULongConstant (0, Location.Null);
+ return new ULongConstant (0, loc);
if (t == TypeManager.float_type)
- return new FloatConstant (0, Location.Null);
+ return new FloatConstant (0, loc);
if (t == TypeManager.double_type)
- return new DoubleConstant (0, Location.Null);
+ return new DoubleConstant (0, loc);
if (t == TypeManager.short_type)
- return new ShortConstant (0, Location.Null);
+ return new ShortConstant (0, loc);
if (t == TypeManager.ushort_type)
- return new UShortConstant (0, Location.Null);
+ return new UShortConstant (0, loc);
if (t == TypeManager.sbyte_type)
- return new SByteConstant (0, Location.Null);
+ return new SByteConstant (0, loc);
if (t == TypeManager.byte_type)
- return new ByteConstant (0, Location.Null);
+ return new ByteConstant (0, loc);
if (t == TypeManager.char_type)
- return new CharConstant ('\0', Location.Null);
+ return new CharConstant ('\0', loc);
if (t == TypeManager.bool_type)
- return new BoolConstant (false, Location.Null);
+ return new BoolConstant (false, loc);
if (t == TypeManager.decimal_type)
- return new DecimalConstant (0, Location.Null);
+ return new DecimalConstant (0, loc);
if (TypeManager.IsEnumType (t))
- return new EnumConstant (Constantify (EnumSpec.GetUnderlyingType (t)), t);
+ return new EnumConstant (Constantify (EnumSpec.GetUnderlyingType (t), loc), t);
if (TypeManager.IsNullableType (t))
- return Nullable.LiftedNull.Create (t, Location.Null);
+ return Nullable.LiftedNull.Create (t, loc);
return null;
}
if (real_class == null)
return null;
- New proxy = new New (new TypeExpression (real_class, loc), Arguments, loc);
+ New proxy = new New (new TypeExpression (real_class, loc), arguments, loc);
Cast cast = new Cast (new TypeExpression (type, loc), proxy, loc);
return cast.Resolve (ec);
}
args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
} else {
args = Arguments.CreateForExpressionTree (ec,
- Arguments,
- method.CreateExpressionTree (ec));
+ arguments, new TypeOfMethod (method, loc));
}
return CreateExpressionFactoryCall (ec, "New", args);
protected override Expression DoResolve (ResolveContext ec)
{
- //
- // The New DoResolve might be called twice when initializing field
- // expressions (see EmitFieldInitializers, the call to
- // GetInitializerExpression will perform a resolve on the expression,
- // and later the assign will trigger another resolution
- //
- // This leads to bugs (#37014)
- //
- if (type != null){
- if (RequestedType is NewDelegate)
- return RequestedType;
- return this;
- }
-
TypeExpr texpr = RequestedType.ResolveAsTypeTerminal (ec, false);
if (texpr == null)
return null;
type = texpr.Type;
+ eclass = ExprClass.Value;
if (type.IsPointer) {
ec.Report.Error (1919, loc, "Unsafe type `{0}' cannot be used in an object creation expression",
return null;
}
- if (Arguments == null) {
- Constant c = Constantify (type);
+ if (arguments == null) {
+ Constant c = Constantify (type, RequestedType.Location);
if (c != null)
return ReducedExpression.Create (c.Resolve (ec), this);
}
if (TypeManager.IsDelegateType (type)) {
- return (new NewDelegate (type, Arguments, loc)).Resolve (ec);
+ return (new NewDelegate (type, arguments, loc)).Resolve (ec);
}
var tparam = type as TypeParameterSpec;
TypeManager.CSharpName (type));
}
- if ((Arguments != null) && (Arguments.Count != 0)) {
+ if ((arguments != null) && (arguments.Count != 0)) {
ec.Report.Error (417, loc,
"`{0}': cannot provide arguments when creating an instance of a variable type",
TypeManager.CSharpName (type));
}
}
- eclass = ExprClass.Value;
return this;
}
return null;
}
- bool is_struct = TypeManager.IsStruct (type);
- eclass = ExprClass.Value;
-
//
- // SRE returns a match for .ctor () on structs (the object constructor),
- // so we have to manually ignore it.
+ // Any struct always defines parameterless constructor
//
- if (is_struct && Arguments == null)
+ if (type.IsStruct && arguments == null)
return this;
- // For member-lookup, treat 'new Foo (bar)' as call to 'foo.ctor (bar)', where 'foo' is of type 'Foo'.
- Expression ml = MemberLookupFinal (ec, type, type, ConstructorInfo.ConstructorName, 0,
- MemberKind.Constructor, BindingRestriction.AccessibleOnly | BindingRestriction.DeclaredOnly, loc);
-
bool dynamic;
- if (Arguments != null) {
- Arguments.Resolve (ec, out dynamic);
+ if (arguments != null) {
+ arguments.Resolve (ec, out dynamic);
} else {
dynamic = false;
}
- if (ml == null)
- return null;
-
- method = ml as MethodGroupExpr;
- if (method == null) {
- ml.Error_UnexpectedKind (ec, ResolveFlags.MethodGroup, loc);
- return null;
- }
-
- method = method.OverloadResolve (ec, ref Arguments, false, loc);
- if (method == null)
- return null;
+ method = ConstructorLookup (ec, type, ref arguments, loc);
if (dynamic) {
- Arguments.Insert (0, new Argument (new TypeOf (texpr, loc).Resolve (ec), Argument.AType.DynamicTypeName));
- return new DynamicConstructorBinder (type, Arguments, loc).Resolve (ec);
+ arguments.Insert (0, new Argument (new TypeOf (texpr, loc).Resolve (ec), Argument.AType.DynamicTypeName));
+ return new DynamicConstructorBinder (type, arguments, loc).Resolve (ec);
}
return this;
vr.EmitLoad (ec);
}
- if (Arguments != null)
- Arguments.Emit (ec);
+ if (arguments != null)
+ arguments.Emit (ec);
if (is_value_type) {
if (method == null) {
}
if (vr != null) {
- ec.Emit (OpCodes.Call, method.BestCandidate);
+ ec.Emit (OpCodes.Call, method);
return false;
}
}
if (type is TypeParameterSpec)
return DoEmitTypeParameter (ec);
- ec.Emit (OpCodes.Newobj, method.BestCandidate);
+ ec.Emit (OpCodes.Newobj, method);
return true;
}
ec.Emit (OpCodes.Pop);
}
- public virtual bool HasInitializer {
- get {
- return false;
- }
- }
-
public void AddressOf (EmitContext ec, AddressOp mode)
{
EmitAddressOf (ec, mode);
if (method == null) {
ec.Emit (OpCodes.Initobj, type);
} else {
- if (Arguments != null)
- Arguments.Emit (ec);
+ if (arguments != null)
+ arguments.Emit (ec);
- ec.Emit (OpCodes.Call, method.BestCandidate);
+ ec.Emit (OpCodes.Call, method);
}
value_target.AddressOf (ec, mode);
New target = (New) t;
target.RequestedType = RequestedType.Clone (clonectx);
- if (Arguments != null){
- target.Arguments = Arguments.Clone (clonectx);
+ if (arguments != null){
+ target.arguments = arguments.Clone (clonectx);
}
}
public override SLE.Expression MakeExpression (BuilderContext ctx)
{
- return SLE.Expression.New ((ConstructorInfo) method.BestCandidate.GetMetaInfo (), Arguments.MakeExpression (Arguments, ctx));
+ return SLE.Expression.New ((ConstructorInfo) method.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
}
}
- public class ArrayInitializer : ShimExpression
+ //
+ // Array initializer expression, the expression is allowed in
+ // variable or field initialization only which makes it tricky as
+ // the type has to be infered based on the context either from field
+ // type or variable type (think of multiple declarators)
+ //
+ public class ArrayInitializer : Expression
{
List<Expression> elements;
+ BlockVariableDeclaration variable;
public ArrayInitializer (List<Expression> init, Location loc)
- : base (null)
{
elements = init;
+ this.loc = loc;
}
public ArrayInitializer (int count, Location loc)
- : base (null)
+ : this (new List<Expression> (count), loc)
{
- elements = new List<Expression> (count);
}
public ArrayInitializer (Location loc)
{
}
+ #region Properties
+
+ public int Count {
+ get { return elements.Count; }
+ }
+
+ public Expression this [int index] {
+ get {
+ return elements [index];
+ }
+ }
+
+ public BlockVariableDeclaration VariableDeclaration {
+ get {
+ return variable;
+ }
+ set {
+ variable = value;
+ }
+ }
+
+ #endregion
+
public void Add (Expression expr)
{
elements.Add (expr);
}
+ public override Expression CreateExpressionTree (ResolveContext ec)
+ {
+ throw new NotSupportedException ("ET");
+ }
+
protected override void CloneTo (CloneContext clonectx, Expression t)
{
var target = (ArrayInitializer) t;
target.elements = new List<Expression> (elements.Count);
foreach (var element in elements)
target.elements.Add (element.Clone (clonectx));
-
- base.CloneTo (clonectx, t);
- }
-
- public int Count {
- get { return elements.Count; }
}
protected override Expression DoResolve (ResolveContext rc)
{
- throw new NotImplementedException ();
+ var current_field = rc.CurrentMemberDefinition as FieldBase;
+ TypeExpression type;
+ if (current_field != null) {
+ type = new TypeExpression (current_field.MemberType, current_field.Location);
+ } else if (variable != null) {
+ if (variable.TypeExpression is VarExpr) {
+ rc.Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
+ return EmptyExpression.Null;
+ }
+
+ type = new TypeExpression (variable.Variable.Type, variable.Variable.Location);
+ } else {
+ throw new NotImplementedException ("Unexpected array initializer context");
+ }
+
+ return new ArrayCreation (type, this).Resolve (rc);
}
- public Expression this [int index] {
- get { return elements [index]; }
+ public override void Emit (EmitContext ec)
+ {
+ throw new InternalErrorException ("Missing Resolve call");
}
}
protected TypeSpec array_element_type;
int num_arguments = 0;
protected int dimensions;
- protected readonly string rank;
+ protected readonly ComposedTypeSpecifier rank;
Expression first_emit;
LocalTemporary first_emit_temp;
int const_initializers_count;
bool only_constant_initializers;
- public ArrayCreation (FullNamedExpression requested_base_type, List<Expression> exprs, string rank, ArrayInitializer initializers, Location l)
+ public ArrayCreation (FullNamedExpression requested_base_type, List<Expression> exprs, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location l)
+ : this (requested_base_type, rank, initializers, l)
{
- this.requested_base_type = requested_base_type;
- this.initializers = initializers;
- this.rank = rank;
- loc = l;
-
arguments = new List<Expression> (exprs);
num_arguments = arguments.Count;
}
- public ArrayCreation (FullNamedExpression requested_base_type, string rank, ArrayInitializer initializers, Location l)
+ //
+ // For expressions like int[] foo = new int[] { 1, 2, 3 };
+ //
+ public ArrayCreation (FullNamedExpression requested_base_type, ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
{
this.requested_base_type = requested_base_type;
- this.initializers = initializers;
this.rank = rank;
- loc = l;
+ this.initializers = initializers;
+ this.loc = loc;
+
+ if (rank != null)
+ num_arguments = rank.Dimension;
+ }
+
+ //
+ // For compiler generated single dimensional arrays only
+ //
+ public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers, Location loc)
+ : this (requested_base_type, ComposedTypeSpecifier.SingleDimension, initializers, loc)
+ {
+ }
+
+ //
+ // For expressions like int[] foo = { 1, 2, 3 };
+ //
+ public ArrayCreation (FullNamedExpression requested_base_type, ArrayInitializer initializers)
+ : this (requested_base_type, null, initializers, initializers.Location)
+ {
}
protected override void Error_NegativeArrayIndex (ResolveContext ec, Location loc)
//
bool ResolveArrayType (ResolveContext ec)
{
- if (requested_base_type is VarExpr) {
- ec.Report.Error (820, loc, "An implicitly typed local variable declarator cannot use an array initializer");
- return false;
- }
-
- StringBuilder array_qualifier = new StringBuilder ();
-
//
- // `In the first form allocates an array instace of the type that results
- // from deleting each of the individual expression from the expression list'
+ // Lookup the type
//
+ FullNamedExpression array_type_expr;
if (num_arguments > 0) {
- array_qualifier.Append ("[");
- for (int i = num_arguments-1; i > 0; i--)
- array_qualifier.Append (",");
- array_qualifier.Append ("]");
+ array_type_expr = new ComposedCast (requested_base_type, rank);
+ } else {
+ array_type_expr = requested_base_type;
}
- array_qualifier.Append (rank);
-
- //
- // Lookup the type
- //
- TypeExpr array_type_expr;
- array_type_expr = new ComposedCast (requested_base_type, array_qualifier.ToString (), loc);
array_type_expr = array_type_expr.ResolveAsTypeTerminal (ec, false);
if (array_type_expr == null)
return false;
return;
// Emit static initializer for arrays which have contain more than 2 items and
- // the static initializer will initialize at least 25% of array values.
+ // the static initializer will initialize at least 25% of array values or there
+ // is more than 10 items to be initialized
// NOTE: const_initializers_count does not contain default constant values.
- if (const_initializers_count > 2 && const_initializers_count * 4 > (array_data.Count) &&
+ if (const_initializers_count > 2 && (array_data.Count > 10 || const_initializers_count * 4 > (array_data.Count)) &&
(TypeManager.IsPrimitiveType (array_element_type) || TypeManager.IsEnumType (array_element_type))) {
EmitStaticInitializers (ec);
return;
}
- enc.Encode (type);
+ if (enc.Encode (type) == AttributeEncoder.EncodedTypeProperties.DynamicType) {
+ Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
+ return;
+ }
}
// Single dimensional array of 0 size
//
class ImplicitlyTypedArrayCreation : ArrayCreation
{
- public ImplicitlyTypedArrayCreation (string rank, ArrayInitializer initializers, Location loc)
+ TypeInferenceContext best_type_inference;
+
+ public ImplicitlyTypedArrayCreation (ComposedTypeSpecifier rank, ArrayInitializer initializers, Location loc)
: base (null, rank, initializers, loc)
{
- if (rank.Length > 2) {
- while (rank [++dimensions] == ',');
- } else {
- dimensions = 1;
- }
+ }
+
+ public ImplicitlyTypedArrayCreation (ArrayInitializer initializers, Location loc)
+ : base (null, initializers, loc)
+ {
}
protected override Expression DoResolve (ResolveContext ec)
if (type != null)
return this;
+ dimensions = rank.Dimension;
+
+ best_type_inference = new TypeInferenceContext ();
+
if (!ResolveInitializers (ec))
return null;
- if (array_element_type == null || array_element_type == TypeManager.null_type ||
- array_element_type == TypeManager.void_type || array_element_type == InternalType.AnonymousMethod ||
- array_element_type == InternalType.MethodGroup ||
- arguments.Count != dimensions) {
- Error_NoBestType (ec);
+ best_type_inference.FixAllTypes (ec);
+ array_element_type = best_type_inference.InferredTypeArguments[0];
+ best_type_inference = null;
+
+ if (array_element_type == null || array_element_type == InternalType.MethodGroup || array_element_type == InternalType.AnonymousMethod ||
+ arguments.Count != rank.Dimension) {
+ ec.Report.Error (826, loc,
+ "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
return null;
}
//
UnifyInitializerElement (ec);
- type = TypeManager.GetConstructedType (array_element_type, rank);
+ type = ArrayContainer.MakeType (array_element_type, dimensions);
eclass = ExprClass.Value;
return this;
}
- void Error_NoBestType (ResolveContext ec)
- {
- ec.Report.Error (826, loc,
- "The type of an implicitly typed array cannot be inferred from the initializer. Try specifying array type explicitly");
- }
-
//
// Converts static initializer only
//
void UnifyInitializerElement (ResolveContext ec)
{
for (int i = 0; i < array_data.Count; ++i) {
- Expression e = (Expression)array_data[i];
+ Expression e = array_data[i];
if (e != null)
array_data [i] = Convert.ImplicitConversion (ec, e, array_element_type, Location.Null);
}
protected override Expression ResolveArrayElement (ResolveContext ec, Expression element)
{
element = element.Resolve (ec);
- if (element == null)
- return null;
-
- if (array_element_type == null) {
- if (element.Type != TypeManager.null_type)
- array_element_type = element.Type;
-
- return element;
- }
-
- if (Convert.ImplicitConversionExists (ec, element, array_element_type)) {
- return element;
- }
-
- if (Convert.ImplicitConversionExists (ec, new TypeExpression (array_element_type, loc), element.Type)) {
- array_element_type = element.Type;
- return element;
- }
+ if (element != null)
+ best_type_inference.AddCommonTypeBound (element.Type);
- Error_NoBestType (ec);
- return null;
+ return element;
}
}
this.loc = loc;
}
+ #region Properties
+
+ public override string Name {
+ get { return "this"; }
+ }
+
+ public override bool IsRef {
+ get { return type.IsStruct; }
+ }
+
+ protected override ILocalVariable Variable {
+ get { return ThisVariable.Instance; }
+ }
+
public override VariableInfo VariableInfo {
get { return variable_info; }
}
get { return false; }
}
+ #endregion
+
+ protected virtual void Error_ThisNotAvailable (ResolveContext ec)
+ {
+ if (ec.IsStatic && !ec.HasSet (ResolveContext.Options.ConstantScope)) {
+ ec.Report.Error (26, loc, "Keyword `this' is not valid in a static property, static method, or static field initializer");
+ } else if (ec.CurrentAnonymousMethod != null) {
+ ec.Report.Error (1673, loc,
+ "Anonymous methods inside structs cannot access instance members of `this'. " +
+ "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
+ } else {
+ ec.Report.Error (27, loc, "Keyword `this' is not available in the current context");
+ }
+ }
+
public override HoistedVariable GetHoistedVariable (AnonymousExpression ae)
{
if (ae == null)
return null;
}
- public override bool IsRef {
- get { return type.IsStruct; }
- }
-
- protected override ILocalVariable Variable {
- get { return ThisVariable.Instance; }
- }
-
public static bool IsThisAvailable (ResolveContext ec, bool ignoreAnonymous)
{
if (ec.IsStatic || ec.HasAny (ResolveContext.Options.FieldInitializerScope | ResolveContext.Options.BaseInitializer | ResolveContext.Options.ConstantScope))
return true;
}
- public bool ResolveBase (ResolveContext ec)
+ public virtual void ResolveBase (ResolveContext ec)
{
- eclass = ExprClass.Variable;
- type = ec.CurrentType;
-
if (!IsThisAvailable (ec, false)) {
- if (ec.IsStatic && !ec.HasSet (ResolveContext.Options.ConstantScope)) {
- ec.Report.Error (26, loc, "Keyword `this' is not valid in a static property, static method, or static field initializer");
- } else if (ec.CurrentAnonymousMethod != null) {
- ec.Report.Error (1673, loc,
- "Anonymous methods inside structs cannot access instance members of `this'. " +
- "Consider copying `this' to a local variable outside the anonymous method and using the local instead");
- } else {
- ec.Report.Error (27, loc, "Keyword `this' is not available in the current context");
- }
+ Error_ThisNotAvailable (ec);
}
var block = ec.CurrentBlock;
if (block != null) {
- if (block.Toplevel.ThisVariable != null)
- variable_info = block.Toplevel.ThisVariable.VariableInfo;
+ if (block.ParametersBlock.TopBlock.ThisVariable != null)
+ variable_info = block.ParametersBlock.TopBlock.ThisVariable.VariableInfo;
AnonymousExpression am = ec.CurrentAnonymousMethod;
if (am != null && ec.IsVariableCapturingRequired) {
am.SetHasThisAccess ();
}
}
-
- return true;
+
+ eclass = ExprClass.Variable;
+ type = ec.CurrentType;
}
//
override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
{
- if (!ResolveBase (ec))
- return null;
+ ResolveBase (ec);
if (variable_info != null)
variable_info.SetAssigned (ec);
throw new NotImplementedException ();
}
- public override string Name {
- get { return "this"; }
- }
-
public override bool Equals (object obj)
{
This t = obj as This;
eclass = ExprClass.Variable;
type = TypeManager.runtime_argument_handle_type;
- if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.Toplevel.Parameters.HasArglist) {
+ if (ec.HasSet (ResolveContext.Options.FieldInitializerScope) || !ec.CurrentBlock.ParametersBlock.Parameters.HasArglist) {
ec.Report.Error (190, loc,
"The __arglist construct is valid only within a variable argument method");
}
/// Implements the typeof operator
/// </summary>
public class TypeOf : Expression {
- Expression QueriedType;
- protected TypeSpec typearg;
+ FullNamedExpression QueriedType;
+ TypeSpec typearg;
- public TypeOf (Expression queried_type, Location l)
+ public TypeOf (FullNamedExpression queried_type, Location l)
{
QueriedType = queried_type;
loc = l;
}
- public override Expression CreateExpressionTree (ResolveContext ec)
- {
- Arguments args = new Arguments (2);
- args.Add (new Argument (this));
- args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
- return CreateExpressionFactoryCall (ec, "Constant", args);
+ #region Properties
+ public TypeSpec TypeArgument {
+ get {
+ return typearg;
+ }
+ }
+
+ public FullNamedExpression TypeExpression {
+ get {
+ return QueriedType;
+ }
+ }
+
+ #endregion
+
+ public override Expression CreateExpressionTree (ResolveContext ec)
+ {
+ Arguments args = new Arguments (2);
+ args.Add (new Argument (this));
+ args.Add (new Argument (new TypeOf (new TypeExpression (type, loc), loc)));
+ return CreateExpressionFactoryCall (ec, "Constant", args);
}
protected override Expression DoResolve (ResolveContext ec)
typearg = texpr.Type;
- //
- // Get generic type definition for unbounded type arguments
- //
- var tne = QueriedType as ATypeNameExpression;
- if (tne != null && typearg.IsGeneric && !tne.HasTypeArguments)
- typearg = typearg.GetDefinition ();
-
- if (typearg == TypeManager.void_type) {
+ if (typearg == TypeManager.void_type && !(QueriedType is TypeExpression)) {
ec.Report.Error (673, loc, "System.Void cannot be used from C#. Use typeof (void) to get the void type object");
} else if (typearg.IsPointer && !ec.IsUnsafe){
UnsafeError (ec, loc);
}
type = TypeManager.type_type;
+ QueriedType = texpr;
return DoResolveBase ();
}
return this;
}
+ static bool ContainsDynamicType (TypeSpec type)
+ {
+ if (type == InternalType.Dynamic)
+ return true;
+
+ var element_container = type as ElementTypeSpec;
+ if (element_container != null)
+ return ContainsDynamicType (element_container.Element);
+
+ foreach (var t in type.TypeArguments) {
+ if (ContainsDynamicType (t)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ static bool ContainsTypeParameter (TypeSpec type)
+ {
+ if (type.Kind == MemberKind.TypeParameter)
+ return true;
+
+ var element_container = type as ElementTypeSpec;
+ if (element_container != null)
+ return ContainsTypeParameter (element_container.Element);
+
+ foreach (var t in type.TypeArguments) {
+ if (ContainsTypeParameter (t)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
public override void EncodeAttributeValue (IMemberContext rc, AttributeEncoder enc, TypeSpec targetType)
{
// Target type is not System.Type therefore must be object
if (targetType != type)
enc.Encode (type);
-/*
- var gi = typearg as InflatedTypeSpec;
- if (gi != null) {
- // TODO: This has to be recursive, handle arrays, etc.
- // I could probably do it after CustomAttribute encoder rewrite
- foreach (var ta in gi.TypeArguments) {
- if (ta.IsGenericParameter) {
- ec.Report.SymbolRelatedToPreviousError (typearg);
- ec.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
- TypeManager.CSharpName (typearg));
- value = null;
- return false;
+ if (!(QueriedType is GenericOpenTypeExpr)) {
+ var gt = typearg;
+ while (gt != null) {
+ if (ContainsTypeParameter (gt)) {
+ rc.Compiler.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
+ typearg.GetSignatureForError ());
+ return;
}
+
+ gt = gt.DeclaringType;
}
- }
- */
- if (!enc.EncodeTypeName (typearg)) {
- rc.Compiler.Report.SymbolRelatedToPreviousError (typearg);
- rc.Compiler.Report.Error (416, loc, "`{0}': an attribute argument cannot use type parameters",
- TypeManager.CSharpName (typearg));
+ if (ContainsDynamicType (typearg)) {
+ Attribute.Error_AttributeArgumentIsDynamic (rc, loc);
+ return;
+ }
}
+
+ enc.EncodeTypeName (typearg);
}
public override void Emit (EmitContext ec)
ec.Emit (OpCodes.Call, TypeManager.system_type_get_type_from_handle);
}
- public TypeSpec TypeArgument {
- get {
- return typearg;
- }
- }
-
protected override void CloneTo (CloneContext clonectx, Expression t)
{
TypeOf target = (TypeOf) t;
if (QueriedType != null)
- target.QueriedType = QueriedType.Clone (clonectx);
- }
- }
-
- /// <summary>
- /// Implements the `typeof (void)' operator
- /// </summary>
- public class TypeOfVoid : TypeOf {
- public TypeOfVoid (Location l) : base (null, l)
- {
- loc = l;
- }
-
- protected override Expression DoResolve (ResolveContext ec)
- {
- type = TypeManager.type_type;
- typearg = TypeManager.void_type;
-
- return DoResolveBase ();
+ target.QueriedType = (FullNamedExpression) QueriedType.Clone (clonectx);
}
}
public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
{
if (alias == GlobalAlias) {
- expr = GlobalRootNamespace.Instance;
+ expr = ec.Compiler.GlobalRootNamespace;
return base.ResolveAsTypeStep (ec, silent);
}
return alias + "::" + name;
}
+ public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
+ {
+ return DoResolve (rc);
+ }
+
protected override void CloneTo (CloneContext clonectx, Expression t)
{
// Nothing
/// <summary>
/// Implements the member access expression
/// </summary>
- public class MemberAccess : ATypeNameExpression {
+ public class MemberAccess : ATypeNameExpression
+ {
protected Expression expr;
public MemberAccess (Expression expr, string id)
this.expr = expr;
}
- Expression DoResolve (ResolveContext ec, Expression right_side)
+ public Expression LeftExpression {
+ get {
+ return expr;
+ }
+ }
+
+ protected override Expression DoResolve (ResolveContext ec)
{
- if (type != null)
- throw new Exception ();
+ return DoResolveName (ec, null);
+ }
+
+ public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
+ {
+ return DoResolveName (ec, right_side);
+ }
+
+ Expression DoResolveName (ResolveContext rc, Expression right_side)
+ {
+ Expression e = LookupNameExpression (rc, right_side == null ? MemberLookupRestrictions.ReadAccess : MemberLookupRestrictions.None);
+ if (e == null)
+ return null;
+
+ if (right_side != null) {
+ if (e is TypeExpr) {
+ e.Error_UnexpectedKind (rc, ResolveFlags.VariableOrValue, loc);
+ return null;
+ }
+
+ e = e.ResolveLValue (rc, right_side);
+ } else {
+ e = e.Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.Type);
+ }
+
+ return e;
+ }
+
+ public override Expression LookupNameExpression (ResolveContext rc, MemberLookupRestrictions restrictions)
+ {
+ var sn = expr as SimpleName;
+ const ResolveFlags flags = ResolveFlags.VariableOrValue | ResolveFlags.Type;
//
// Resolve the expression with flow analysis turned off, we'll do the definite
// will resolve to - it may resolve to a FieldExpr and in this case we must do the
// definite assignment check on the actual field and not on the whole struct.
//
+ using (rc.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
+ if (sn != null) {
+ expr = sn.LookupNameExpression (rc, MemberLookupRestrictions.ReadAccess | MemberLookupRestrictions.ExactArity);
- SimpleName original = expr as SimpleName;
- Expression expr_resolved;
- const ResolveFlags flags = ResolveFlags.VariableOrValue | ResolveFlags.Type;
-
- using (ec.Set (ResolveContext.Options.OmitStructFlowAnalysis)) {
- if (original != null) {
- expr_resolved = original.DoResolve (ec, true);
- if (expr_resolved != null) {
- // Ugly, simulate skipped Resolve
- if (expr_resolved is ConstantExpr) {
- expr_resolved = expr_resolved.Resolve (ec);
- } else if (expr_resolved is FieldExpr || expr_resolved is PropertyExpr) {
- // nothing yet
- } else if ((flags & expr_resolved.ExprClassToResolveFlags) == 0) {
- expr_resolved.Error_UnexpectedKind (ec, flags, expr.Location);
- expr_resolved = null;
+ // Call resolve on expression which does have type set as we need expression type
+ // TODO: I should probably ensure that the type is always set and leave resolve for the final
+ if (expr is VariableReference || expr is ConstantExpr || expr is Linq.TransparentMemberAccess) {
+ using (rc.With (ResolveContext.Options.DoFlowAnalysis, false)) {
+ expr = expr.Resolve (rc);
}
+ } else if (expr is TypeParameterExpr) {
+ expr.Error_UnexpectedKind (rc, flags, expr.Location);
+ expr = null;
}
} else {
- expr_resolved = expr.Resolve (ec, flags);
+ expr = expr.Resolve (rc, flags);
}
}
- if (expr_resolved == null)
+ if (expr == null)
return null;
- Namespace ns = expr_resolved as Namespace;
+ Namespace ns = expr as Namespace;
if (ns != null) {
- FullNamedExpression retval = ns.Lookup (ec.Compiler, Name, Arity, loc);
+ FullNamedExpression retval = ns.Lookup (rc.Compiler, Name, Arity, loc);
- if (retval == null)
- ns.Error_NamespaceDoesNotExist (loc, Name, Arity, ec);
- else if (HasTypeArguments)
- retval = new GenericTypeExpr (retval.Type, targs, loc).ResolveAsTypeStep (ec, false);
+ if (retval == null) {
+ ns.Error_NamespaceDoesNotExist (loc, Name, Arity, rc);
+ return null;
+ }
+
+ if (HasTypeArguments)
+ return new GenericTypeExpr (retval.Type, targs, loc);
return retval;
}
- TypeSpec expr_type = expr_resolved.Type;
+ MemberExpr me;
+ TypeSpec expr_type = expr.Type;
if (expr_type == InternalType.Dynamic) {
- Arguments args = new Arguments (1);
- args.Add (new Argument (expr_resolved.Resolve (ec)));
- expr = new DynamicMemberBinder (Name, args, loc);
- if (right_side != null)
- return expr.DoResolveLValue (ec, right_side);
+ me = expr as MemberExpr;
+ if (me != null)
+ me.ResolveInstanceExpression (rc);
- return expr.Resolve (ec);
+ Arguments args = new Arguments (1);
+ args.Add (new Argument (expr));
+ return new DynamicMemberBinder (Name, args, loc);
}
- const MemberKind dot_kinds = MemberKind.Class | MemberKind.Struct | MemberKind.Delegate | MemberKind.Enum | MemberKind.Interface | MemberKind.TypeParameter;
+ const MemberKind dot_kinds = MemberKind.Class | MemberKind.Struct | MemberKind.Delegate | MemberKind.Enum |
+ MemberKind.Interface | MemberKind.TypeParameter | MemberKind.ArrayType;
+
if ((expr_type.Kind & dot_kinds) == 0 || expr_type == TypeManager.void_type) {
- Unary.Error_OperatorCannotBeApplied (ec, loc, ".", expr_type);
+ if (expr_type == InternalType.Null && rc.Compiler.IsRuntimeBinder)
+ rc.Report.Error (Report.RuntimeErrorId, loc, "Cannot perform member binding on `null' value");
+ else
+ Unary.Error_OperatorCannotBeApplied (rc, loc, ".", expr_type);
return null;
}
- var arity = HasTypeArguments ? targs.Count : -1;
-
- var member_lookup = MemberLookup (ec.Compiler,
- ec.CurrentType, expr_type, expr_type, Name, arity, BindingRestriction.NoOverrides, loc);
-
- if (member_lookup == null) {
- expr = expr_resolved.Resolve (ec);
-
- ExprClass expr_eclass = expr.eclass;
+ var current_type = rc.CurrentType;
+ var lookup_arity = Arity;
+ bool errorMode = false;
+ Expression member_lookup;
+ while (true) {
+ member_lookup = MemberLookup (errorMode ? null : rc, current_type, expr_type, Name, lookup_arity, restrictions, loc);
+ if (member_lookup == null) {
+ //
+ // Try to look for extension method when member lookup failed
+ //
+ if (MethodGroupExpr.IsExtensionMethodArgument (expr)) {
+ NamespaceEntry scope = null;
+ var methods = rc.LookupExtensionMethod (expr_type, Name, lookup_arity, ref scope);
+ if (methods != null) {
+ var emg = new ExtensionMethodGroupExpr (methods, scope, expr, loc);
+ if (HasTypeArguments) {
+ if (!targs.Resolve (rc))
+ return null;
+
+ emg.SetTypeArguments (rc, targs);
+ }
+
+ // TODO: Should it really skip the checks bellow
+ return emg.Resolve (rc);
+ }
+ }
+ }
- //
- // Extension methods are not allowed on all expression types
- //
- if (expr_eclass == ExprClass.Value || expr_eclass == ExprClass.Variable ||
- expr_eclass == ExprClass.IndexerAccess || expr_eclass == ExprClass.PropertyAccess ||
- expr_eclass == ExprClass.EventAccess) {
- ExtensionMethodGroupExpr ex_method_lookup = ec.LookupExtensionMethod (expr_type, Name, arity, loc);
- if (ex_method_lookup != null) {
- ex_method_lookup.ExtensionExpression = expr;
-
- if (HasTypeArguments) {
- if (!targs.Resolve (ec))
- return null;
+ if (errorMode) {
+ if (member_lookup == null) {
+ if (expr is TypeExpr)
+ base.Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
+ else
+ Error_TypeDoesNotContainDefinition (rc, expr_type, Name);
- ex_method_lookup.SetTypeArguments (ec, targs);
- }
+ return null;
+ }
- return ex_method_lookup.Resolve (ec);
+ if (member_lookup is MethodGroupExpr) {
+ // Leave it to overload resolution to report correct error
+ } else {
+ // TODO: rc.SymbolRelatedToPreviousError
+ ErrorIsInaccesible (rc, member_lookup.GetSignatureForError (), loc);
}
+ break;
}
- member_lookup = Error_MemberLookupFailed (ec,
- ec.CurrentType, expr_type, expr_type, Name, arity, null,
- MemberKind.All, BindingRestriction.AccessibleOnly);
- if (member_lookup == null)
- return null;
+ if (member_lookup != null)
+ break;
+
+ current_type = null;
+ lookup_arity = 0;
+ restrictions &= ~MemberLookupRestrictions.InvocableOnly;
+ errorMode = true;
}
- MemberExpr me;
TypeExpr texpr = member_lookup as TypeExpr;
if (texpr != null) {
- if (!(expr_resolved is TypeExpr)) {
- me = expr_resolved as MemberExpr;
- if (me == null || me.ProbeIdenticalTypeName (ec, expr_resolved, original) == expr_resolved) {
- ec.Report.Error (572, loc, "`{0}': cannot reference a type through an expression; try `{1}' instead",
+ if (!(expr is TypeExpr)) {
+ me = expr as MemberExpr;
+ if (me == null || me.ProbeIdenticalTypeName (rc, expr, sn) == expr) {
+ rc.Report.Error (572, loc, "`{0}': cannot reference a type through an expression; try `{1}' instead",
Name, member_lookup.GetSignatureForError ());
return null;
}
}
- if (!texpr.CheckAccessLevel (ec.MemberContext)) {
- ec.Report.SymbolRelatedToPreviousError (member_lookup.Type);
- ErrorIsInaccesible (loc, TypeManager.CSharpName (member_lookup.Type), ec.Report);
+ if (!texpr.Type.IsAccessible (rc.CurrentType)) {
+ rc.Report.SymbolRelatedToPreviousError (member_lookup.Type);
+ ErrorIsInaccesible (rc, member_lookup.Type.GetSignatureForError (), loc);
return null;
}
if (HasTypeArguments) {
- var ct = new GenericTypeExpr (member_lookup.Type, targs, loc);
- return ct.ResolveAsTypeStep (ec, false);
+ return new GenericTypeExpr (member_lookup.Type, targs, loc);
}
return member_lookup;
}
- me = (MemberExpr) member_lookup;
+ me = member_lookup as MemberExpr;
- if (original != null && me.IsStatic)
- expr_resolved = me.ProbeIdenticalTypeName (ec, expr_resolved, original);
+ if (sn != null && me.IsStatic)
+ expr = me.ProbeIdenticalTypeName (rc, expr, sn);
- me = me.ResolveMemberAccess (ec, expr_resolved, original);
+ me = me.ResolveMemberAccess (rc, expr, sn);
- if (HasTypeArguments) {
- if (!targs.Resolve (ec))
+ if (Arity > 0) {
+ if (!targs.Resolve (rc))
return null;
- me.SetTypeArguments (ec, targs);
+ me.SetTypeArguments (rc, targs);
}
- if (original != null && (!TypeManager.IsValueType (expr_type) || me is PropertyExpr)) {
+ if (sn != null && (!TypeManager.IsValueType (expr_type) || me is PropertyExpr)) {
if (me.IsInstance) {
- LocalVariableReference var = expr_resolved as LocalVariableReference;
- if (var != null && !var.VerifyAssigned (ec))
+ LocalVariableReference var = expr as LocalVariableReference;
+ if (var != null && !var.VerifyAssigned (rc))
return null;
}
}
- // The following DoResolve/DoResolveLValue will do the definite assignment
- // check.
-
- if (right_side != null)
- return me.DoResolveLValue (ec, right_side);
- else
- return me.Resolve (ec);
- }
-
- protected override Expression DoResolve (ResolveContext ec)
- {
- return DoResolve (ec, null);
- }
-
- public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
- {
- return DoResolve (ec, right_side);
+ return me;
}
public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
return null;
}
- bool extra_check;
- if (!IsMemberAccessible (rc.CurrentType ?? InternalType.FakeInternalType, nested, out extra_check)) {
- ErrorIsInaccesible (loc, nested.GetSignatureForError (), rc.Compiler.Report);
+ if (!nested.IsAccessible (rc.CurrentType ?? InternalType.FakeInternalType)) {
+ ErrorIsInaccesible (rc, nested.GetSignatureForError (), loc);
}
TypeExpr texpr;
- if (HasTypeArguments) {
- texpr = new GenericTypeExpr (nested, targs, loc);
+ if (Arity > 0) {
+ if (HasTypeArguments) {
+ texpr = new GenericTypeExpr (nested, targs, loc);
+ } else {
+ texpr = new GenericOpenTypeExpr (nested, loc);
+ }
} else {
texpr = new TypeExpression (nested, loc);
}
return;
}
- var member_lookup = MemberLookup (rc.Compiler,
- rc.CurrentType, expr_type, expr_type, identifier, -1,
- MemberKind.All, BindingRestriction.None, loc);
-
- if (member_lookup == null) {
- rc.Compiler.Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
- Name, expr_type.GetSignatureForError ());
- } else {
- // TODO: Report.SymbolRelatedToPreviousError
- member_lookup.Error_UnexpectedKind (rc.Compiler.Report, null, "type", loc);
+ var any_other_member = MemberLookup (null, rc.CurrentType, expr_type, Name, 0, MemberLookupRestrictions.None, loc);
+ if (any_other_member != null) {
+ any_other_member.Error_UnexpectedKind (rc.Compiler.Report, null, "type", loc);
+ return;
}
+
+ rc.Compiler.Report.Error (426, loc, "The nested type `{0}' does not exist in the type `{1}'",
+ Name, expr_type.GetSignatureForError ());
}
protected override void Error_TypeDoesNotContainDefinition (ResolveContext ec, TypeSpec type, string name)
{
- if (RootContext.Version > LanguageVersion.ISO_2 && !ec.Compiler.IsRuntimeBinder &&
- ((expr.eclass & (ExprClass.Value | ExprClass.Variable)) != 0)) {
- ec.Report.Error (1061, loc, "Type `{0}' does not contain a definition for `{1}' and no " +
- "extension method `{1}' of type `{0}' could be found " +
- "(are you missing a using directive or an assembly reference?)",
- TypeManager.CSharpName (type), name);
+ if (RootContext.Version > LanguageVersion.ISO_2 && !ec.Compiler.IsRuntimeBinder && MethodGroupExpr.IsExtensionMethodArgument (expr)) {
+ ec.Report.Error (1061, loc,
+ "Type `{0}' does not contain a definition for `{1}' and no extension method `{1}' of type `{0}' could be found (are you missing a using directive or an assembly reference?)",
+ type.GetSignatureForError (), name);
return;
}
return expr.GetSignatureForError () + "." + base.GetSignatureForError ();
}
- public Expression Left {
- get {
- return expr;
- }
- }
-
protected override void CloneTo (CloneContext clonectx, Expression t)
{
MemberAccess target = (MemberAccess) t;
public Arguments Arguments;
public Expression Expr;
- public ElementAccess (Expression e, Arguments args)
+ public ElementAccess (Expression e, Arguments args, Location loc)
{
Expr = e;
- loc = e.Location;
+ this.loc = loc;
this.Arguments = args;
}
+ //
+ // We perform some simple tests, and then to "split" the emit and store
+ // code we create an instance of a different class, and return that.
+ //
+ Expression CreateAccessExpression (ResolveContext ec)
+ {
+ if (type.IsArray)
+ return (new ArrayAccess (this, loc));
+
+ if (type.IsPointer)
+ return MakePointerAccess (ec, type);
+
+ FieldExpr fe = Expr as FieldExpr;
+ if (fe != null) {
+ var ff = fe.Spec as FixedFieldSpec;
+ if (ff != null) {
+ return MakePointerAccess (ec, ff.ElementType);
+ }
+ }
+
+ var indexers = MemberCache.FindMembers (type, MemberCache.IndexerNameAlias, false);
+ if (indexers != null || type == InternalType.Dynamic) {
+ return new IndexerExpr (indexers, this);
+ }
+
+ ec.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
+ type.GetSignatureForError ());
+ return null;
+ }
+
public override Expression CreateExpressionTree (ResolveContext ec)
{
Arguments args = Arguments.CreateForExpressionTree (ec, Arguments,
return CreateExpressionFactoryCall (ec, "ArrayIndex", args);
}
- Expression MakePointerAccess (ResolveContext ec, TypeSpec t)
+ Expression MakePointerAccess (ResolveContext ec, TypeSpec type)
{
if (Arguments.Count != 1){
ec.Report.Error (196, loc, "A pointer must be indexed by only one value");
if (Arguments [0] is NamedArgument)
Error_NamedArgument ((NamedArgument) Arguments[0], ec.Report);
- Expression p = new PointerArithmetic (Binary.Operator.Addition, Expr, Arguments [0].Expr.Resolve (ec), t, loc);
- return new Indirection (p, loc).Resolve (ec);
+ Expression p = new PointerArithmetic (Binary.Operator.Addition, Expr, Arguments [0].Expr.Resolve (ec), type, loc);
+ return new Indirection (p, loc);
}
protected override Expression DoResolve (ResolveContext ec)
if (Expr == null)
return null;
- //
- // We perform some simple tests, and then to "split" the emit and store
- // code we create an instance of a different class, and return that.
- //
- // I am experimenting with this pattern.
- //
- TypeSpec t = Expr.Type;
+ type = Expr.Type;
- if (t == TypeManager.array_type){
- ec.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `System.Array'");
+ // TODO: Create 1 result for Resolve and ResolveLValue ?
+ var res = CreateAccessExpression (ec);
+ if (res == null)
return null;
- }
-
- if (t.IsArray)
- return (new ArrayAccess (this, loc)).Resolve (ec);
- if (t.IsPointer)
- return MakePointerAccess (ec, t);
- FieldExpr fe = Expr as FieldExpr;
- if (fe != null) {
- var ff = fe.Spec as FixedFieldSpec;
- if (ff != null) {
- return MakePointerAccess (ec, ff.ElementType);
- }
- }
- return (new IndexerAccess (this, loc)).Resolve (ec);
+ return res.Resolve (ec);
}
public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
return null;
type = Expr.Type;
- if (type.IsArray)
- return (new ArrayAccess (this, loc)).DoResolveLValue (ec, right_side);
-
- if (type.IsPointer)
- return MakePointerAccess (ec, type);
- if (Expr.eclass != ExprClass.Variable && TypeManager.IsStruct (type))
- Error_CannotModifyIntermediateExpressionValue (ec);
+ var res = CreateAccessExpression (ec);
+ if (res == null)
+ return null;
- return (new IndexerAccess (this, loc)).DoResolveLValue (ec, right_side);
+ return res.ResolveLValue (ec, right_side);
}
public override void Emit (EmitContext ec)
bool dynamic;
ea.Arguments.Resolve (ec, out dynamic);
- TypeSpec t = ea.Expr.Type;
+ var ac = ea.Expr.Type as ArrayContainer;
int rank = ea.Arguments.Count;
- if (t.GetMetaInfo ().GetArrayRank () != rank) {
+ if (ac.Rank != rank) {
ec.Report.Error (22, ea.Location, "Wrong number of indexes `{0}' inside [], expected `{1}'",
- ea.Arguments.Count.ToString (), t.GetMetaInfo ().GetArrayRank ().ToString ());
+ rank.ToString (), ac.Rank.ToString ());
return null;
}
- type = TypeManager.GetElementType (t);
+ type = ac.Element;
if (type.IsPointer && !ec.IsUnsafe) {
UnsafeError (ec, ea.Location);
}
ec.EmitArrayAddress (ac);
}
-#if NET_4_0
- public SLE.Expression MakeAssignExpression (BuilderContext ctx)
+ public SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
{
+#if NET_4_0
return SLE.Expression.ArrayAccess (
ea.Expr.MakeExpression (ctx),
Arguments.MakeExpression (ea.Arguments, ctx));
- }
+#else
+ throw new NotImplementedException ();
#endif
+ }
public override SLE.Expression MakeExpression (BuilderContext ctx)
{
}
}
- /// <summary>
- /// Expressions that represent an indexer call.
- /// </summary>
- public class IndexerAccess : Expression, IDynamicAssign
+ //
+ // Indexer access expression
+ //
+ class IndexerExpr : PropertyOrIndexerExpr<IndexerSpec>, OverloadResolver.IBaseMembersProvider
{
- class IndexerMethodGroupExpr : MethodGroupExpr
+ LocalTemporary prepared_value;
+ IList<MemberSpec> indexers;
+ Arguments arguments;
+
+ public IndexerExpr (IList<MemberSpec> indexers, ElementAccess ea)
+ : base (ea.Location)
{
- IEnumerable<IndexerSpec> candidates;
+ this.indexers = indexers;
+ this.InstanceExpression = ea.Expr;
+ this.arguments = ea.Arguments;
+ }
- public IndexerMethodGroupExpr (IEnumerable<IndexerSpec> indexers, Location loc)
- : base (FilterAccessors (indexers).ToList (), null, loc)
- {
- candidates = indexers;
+ #region Properties
+ protected override TypeSpec DeclaringType {
+ get {
+ return best_candidate.DeclaringType;
}
+ }
- public IndexerSpec BestIndexer ()
- {
- return candidates.Where (l => l.Get == BestCandidate || l.Set == BestCandidate).First ();
+ public override bool IsInstance {
+ get {
+ return true;
}
+ }
- static IEnumerable<MemberSpec> FilterAccessors (IEnumerable<IndexerSpec> indexers)
- {
- foreach (IndexerSpec i in indexers) {
- if (i.HasGet)
- yield return i.Get;
- else
- yield return i.Set;
- }
+ public override bool IsStatic {
+ get {
+ return false;
}
+ }
- protected override IList<MemberSpec> GetBaseTypeMethods (ResolveContext rc, TypeSpec type)
- {
- candidates = GetIndexersForType (type, false);
- if (candidates == null)
- return null;
-
- return FilterAccessors (candidates).ToList ();
+ public override string Name {
+ get {
+ return "this";
}
+ }
- public override string Name {
- get {
- return "this";
- }
- }
+ #endregion
- protected override int GetApplicableParametersCount (MethodSpec method, AParametersCollection parameters)
- {
- //
- // Here is the trick, decrease number of arguments by 1 when only
- // available property method is setter. This makes overload resolution
- // work correctly for indexers.
- //
-
- if (method.Name [0] == 'g')
- return parameters.Count;
+ public override Expression CreateExpressionTree (ResolveContext ec)
+ {
+ Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
+ InstanceExpression.CreateExpressionTree (ec),
+ new TypeOfMethod (Getter, loc));
- return parameters.Count - 1;
- }
+ return CreateExpressionFactoryCall (ec, "Call", args);
}
- //
- // Points to our "data" repository
- //
- IndexerSpec spec;
- bool is_base_indexer;
- bool prepared;
- LocalTemporary temp;
- LocalTemporary prepared_value;
- Expression set_expr;
-
- protected TypeSpec indexer_type;
- protected TypeSpec current_type;
- protected Expression instance_expr;
- protected Arguments arguments;
-
- public IndexerAccess (ElementAccess ea, Location loc)
- : this (ea.Expr, false, loc)
- {
- this.arguments = ea.Arguments;
- }
-
- protected IndexerAccess (Expression instance_expr, bool is_base_indexer,
- Location loc)
- {
- this.instance_expr = instance_expr;
- this.is_base_indexer = is_base_indexer;
- this.loc = loc;
- }
-
- static string GetAccessorName (bool isSet)
- {
- return isSet ? "set" : "get";
- }
-
- public override Expression CreateExpressionTree (ResolveContext ec)
- {
- Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
- instance_expr.CreateExpressionTree (ec),
- new TypeOfMethod (spec.Get, loc));
-
- return CreateExpressionFactoryCall (ec, "Call", args);
- }
-
- static IEnumerable<IndexerSpec> GetIndexersForType (TypeSpec lookup_type, bool baseAccess)
- {
- BindingRestriction restrictions = BindingRestriction.AccessibleOnly;
- if (!baseAccess)
- restrictions |= BindingRestriction.NoOverrides;
-
- return MemberCache.FindIndexers (lookup_type, restrictions);
- }
-
- protected virtual void CommonResolve (ResolveContext ec)
- {
- indexer_type = instance_expr.Type;
- current_type = ec.CurrentType;
- }
-
- protected override Expression DoResolve (ResolveContext ec)
- {
- return ResolveAccessor (ec, null);
- }
-
- public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
- {
- if (right_side == EmptyExpression.OutAccess.Instance) {
- right_side.DoResolveLValue (ec, this);
- return null;
- }
-
- // if the indexer returns a value type, and we try to set a field in it
- if (right_side == EmptyExpression.LValueMemberAccess || right_side == EmptyExpression.LValueMemberOutAccess) {
- Error_CannotModifyIntermediateExpressionValue (ec);
- }
-
- return ResolveAccessor (ec, right_side);
- }
-
- Expression ResolveAccessor (ResolveContext ec, Expression right_side)
- {
- CommonResolve (ec);
-
- bool dynamic;
-
- arguments.Resolve (ec, out dynamic);
-
- if (indexer_type == InternalType.Dynamic) {
- dynamic = true;
- } else {
- var ilist = GetIndexersForType (indexer_type, this is BaseIndexerAccess);
- if (ilist == null) {
- ec.Report.Error (21, loc, "Cannot apply indexing with [] to an expression of type `{0}'",
- TypeManager.CSharpName (indexer_type));
- return null;
- }
-
- var mg = new IndexerMethodGroupExpr (ilist, loc);
- mg.InstanceExpression = instance_expr;
- mg = mg.OverloadResolve (ec, ref arguments, false, loc) as IndexerMethodGroupExpr;
- if (mg == null)
- return null;
-
- if (!dynamic)
- spec = mg.BestIndexer ();
- }
-
- if (dynamic) {
- Arguments args = new Arguments (arguments.Count + 1);
- if (is_base_indexer) {
- ec.Report.Error (1972, loc, "The indexer base access cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access");
- } else {
- args.Add (new Argument (instance_expr));
- }
- args.AddRange (arguments);
-
- var expr = new DynamicIndexBinder (args, loc);
- if (right_side != null)
- return expr.ResolveLValue (ec, right_side);
-
- return expr.Resolve (ec);
- }
-
- type = spec.MemberType;
- if (type.IsPointer && !ec.IsUnsafe)
- UnsafeError (ec, loc);
-
- MethodSpec accessor;
- if (right_side == null) {
- accessor = spec.Get;
- } else {
- accessor = spec.Set;
- if (!spec.HasSet && spec.HasGet) {
- ec.Report.SymbolRelatedToPreviousError (spec);
- ec.Report.Error (200, loc, "The read only property or indexer `{0}' cannot be assigned to",
- spec.GetSignatureForError ());
- return null;
- }
-
- set_expr = Convert.ImplicitConversion (ec, right_side, type, loc);
- }
-
- if (accessor == null || accessor.Kind == MemberKind.FakeMethod) {
- ec.Report.SymbolRelatedToPreviousError (spec);
- ec.Report.Error (154, loc, "The property or indexer `{0}' cannot be used in this context because it lacks a `{1}' accessor",
- spec.GetSignatureForError (), GetAccessorName (right_side != null));
- return null;
- }
-
- //
- // Only base will allow this invocation to happen.
- //
- if (spec.IsAbstract && this is BaseIndexerAccess) {
- Error_CannotCallAbstractBase (ec, spec.GetSignatureForError ());
- }
-
- bool must_do_cs1540_check;
- if (!IsMemberAccessible (ec.CurrentType, accessor, out must_do_cs1540_check)) {
- if (spec.HasDifferentAccessibility) {
- ec.Report.SymbolRelatedToPreviousError (accessor);
- ec.Report.Error (271, loc, "The property or indexer `{0}' cannot be used in this context because a `{1}' accessor is inaccessible",
- TypeManager.GetFullNameSignature (spec), GetAccessorName (right_side != null));
- } else {
- ec.Report.SymbolRelatedToPreviousError (spec);
- ErrorIsInaccesible (loc, TypeManager.GetFullNameSignature (spec), ec.Report);
- }
- }
-
- instance_expr.CheckMarshalByRefAccess (ec);
-
- if (must_do_cs1540_check && (instance_expr != EmptyExpression.Null) &&
- !TypeManager.IsInstantiationOfSameGenericType (instance_expr.Type, ec.CurrentType) &&
- !TypeManager.IsNestedChildOf (ec.CurrentType, instance_expr.Type) &&
- !TypeManager.IsSubclassOf (instance_expr.Type, ec.CurrentType)) {
- ec.Report.SymbolRelatedToPreviousError (accessor);
- Error_CannotAccessProtected (ec, loc, spec, instance_expr.Type, ec.CurrentType);
- return null;
- }
-
- eclass = ExprClass.IndexerAccess;
- return this;
- }
-
- public override void Emit (EmitContext ec)
- {
- Emit (ec, false);
- }
-
- public void Emit (EmitContext ec, bool leave_copy)
+ public override void Emit (EmitContext ec, bool leave_copy)
{
if (prepared) {
prepared_value.Emit (ec);
} else {
- Invocation.EmitCall (ec, is_base_indexer, instance_expr, spec.Get,
- arguments, loc, false, false);
+ Invocation.EmitCall (ec, InstanceExpression, Getter, arguments, loc, false, false);
}
if (leave_copy) {
}
}
- //
- // source is ignored, because we already have a copy of it from the
- // LValue resolution and we have already constructed a pre-cached
- // version of the arguments (ea.set_arguments);
- //
- public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
+ public override void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
{
prepared = prepare_for_load;
- Expression value = set_expr;
+ Expression value = source;
if (prepared) {
- Invocation.EmitCall (ec, is_base_indexer, instance_expr, spec.Get,
+ Invocation.EmitCall (ec, InstanceExpression, Getter,
arguments, loc, true, false);
prepared_value = new LocalTemporary (type);
if (!prepared)
arguments.Add (new Argument (value));
- Invocation.EmitCall (ec, is_base_indexer, instance_expr, spec.Set, arguments, loc, false, prepared);
+ Invocation.EmitCall (ec, InstanceExpression, Setter, arguments, loc, false, prepared);
if (temp != null) {
temp.Emit (ec);
temp.Release (ec);
}
}
-
+
public override string GetSignatureForError ()
{
- return spec.GetSignatureForError ();
+ return best_candidate.GetSignatureForError ();
}
-
-#if NET_4_0
- public SLE.Expression MakeAssignExpression (BuilderContext ctx)
+
+ public override SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source)
{
- var value = new[] { set_expr.MakeExpression (ctx) };
+ var value = new[] { source.MakeExpression (ctx) };
var args = Arguments.MakeExpression (arguments, ctx).Concat (value);
-
+#if NET_4_0
return SLE.Expression.Block (
- SLE.Expression.Call (instance_expr.MakeExpression (ctx), (MethodInfo) spec.Set.GetMetaInfo (), args),
+ SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Setter.GetMetaInfo (), args),
value [0]);
- }
+#else
+ return args.First ();
#endif
+ }
public override SLE.Expression MakeExpression (BuilderContext ctx)
{
var args = Arguments.MakeExpression (arguments, ctx);
- return SLE.Expression.Call (instance_expr.MakeExpression (ctx), (MethodInfo) spec.Get.GetMetaInfo (), args);
+ return SLE.Expression.Call (InstanceExpression.MakeExpression (ctx), (MethodInfo) Getter.GetMetaInfo (), args);
}
- protected override void CloneTo (CloneContext clonectx, Expression t)
+ protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
{
- IndexerAccess target = (IndexerAccess) t;
+ if (best_candidate != null)
+ return this;
- if (arguments != null)
- target.arguments = arguments.Clone (clonectx);
+ eclass = ExprClass.IndexerAccess;
- if (instance_expr != null)
- target.instance_expr = instance_expr.Clone (clonectx);
- }
- }
+ bool dynamic;
+ arguments.Resolve (rc, out dynamic);
- /// <summary>
- /// The base operator for method names
- /// </summary>
- public class BaseAccess : Expression {
- public readonly string Identifier;
- TypeArguments args;
+ if (indexers == null && InstanceExpression.Type == InternalType.Dynamic) {
+ dynamic = true;
+ } else {
+ var res = new OverloadResolver (indexers, OverloadResolver.Restrictions.None, loc);
+ res.BaseMembersProvider = this;
+
+ // TODO: Do I need 2 argument sets?
+ best_candidate = res.ResolveMember<IndexerSpec> (rc, ref arguments);
+ if (best_candidate != null)
+ type = best_candidate.MemberType;
+ else if (!res.BestCandidateIsDynamic)
+ return null;
+ }
- public BaseAccess (string member, Location l)
- {
- this.Identifier = member;
- loc = l;
- }
+ //
+ // It has dynamic arguments
+ //
+ if (dynamic) {
+ Arguments args = new Arguments (arguments.Count + 1);
+ if (IsBase) {
+ rc.Report.Error (1972, loc,
+ "The indexer base access cannot be dynamically dispatched. Consider casting the dynamic arguments or eliminating the base access");
+ } else {
+ args.Add (new Argument (InstanceExpression));
+ }
+ args.AddRange (arguments);
- public BaseAccess (string member, TypeArguments args, Location l)
- : this (member, l)
- {
- this.args = args;
- }
+ best_candidate = null;
+ return new DynamicIndexBinder (args, loc);
+ }
- public override Expression CreateExpressionTree (ResolveContext ec)
- {
- throw new NotSupportedException ("ET");
+ ResolveInstanceExpression (rc);
+ CheckProtectedMemberAccess (rc, best_candidate);
+ return this;
}
- protected override Expression DoResolve (ResolveContext ec)
+ protected override void CloneTo (CloneContext clonectx, Expression t)
{
- Expression c = CommonResolve (ec);
-
- if (c == null)
- return null;
+ IndexerExpr target = (IndexerExpr) t;
- //
- // MethodGroups use this opportunity to flag an error on lacking ()
- //
- if (!(c is MethodGroupExpr))
- return c.Resolve (ec);
- return c;
+ if (arguments != null)
+ target.arguments = arguments.Clone (clonectx);
}
- public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
+ public override void SetTypeArguments (ResolveContext ec, TypeArguments ta)
{
- Expression c = CommonResolve (ec);
-
- if (c == null)
- return null;
+ Error_TypeArgumentsCannotBeUsed (ec.Report, "indexer", GetSignatureForError (), loc);
+ }
- //
- // MethodGroups use this opportunity to flag an error on lacking ()
- //
- if (! (c is MethodGroupExpr))
- return c.DoResolveLValue (ec, right_side);
+ #region IBaseMembersProvider Members
- return c;
+ IList<MemberSpec> OverloadResolver.IBaseMembersProvider.GetBaseMembers (TypeSpec baseType)
+ {
+ return baseType == null ? null : MemberCache.FindMembers (baseType, MemberCache.IndexerNameAlias, false);
}
- Expression CommonResolve (ResolveContext ec)
+ MethodGroupExpr OverloadResolver.IBaseMembersProvider.LookupExtensionMethod (ResolveContext rc)
{
- Expression member_lookup;
- TypeSpec current_type = ec.CurrentType;
- TypeSpec base_type = current_type.BaseType;
+ return null;
+ }
- if (!This.IsThisAvailable (ec, false)) {
- if (ec.IsStatic) {
- ec.Report.Error (1511, loc, "Keyword `base' is not available in a static method");
- } else {
- ec.Report.Error (1512, loc, "Keyword `base' is not available in the current context");
- }
- return null;
- }
+ #endregion
+ }
- var arity = args == null ? -1 : args.Count;
- member_lookup = MemberLookup (ec.Compiler, ec.CurrentType, null, base_type, Identifier, arity,
- MemberKind.All, BindingRestriction.AccessibleOnly, loc);
- if (member_lookup == null) {
- Error_MemberLookupFailed (ec, ec.CurrentType, base_type, base_type, Identifier, arity,
- null, MemberKind.All, BindingRestriction.AccessibleOnly);
- return null;
- }
+ //
+ // A base access expression
+ //
+ public class BaseThis : This
+ {
+ public BaseThis (Location loc)
+ : base (loc)
+ {
+ }
- Expression left;
-
- if (ec.IsStatic)
- left = new TypeExpression (base_type, loc);
- else
- left = ec.GetThis (loc);
+ public BaseThis (TypeSpec type, Location loc)
+ : base (loc)
+ {
+ this.type = type;
+ eclass = ExprClass.Variable;
+ }
- MemberExpr me = member_lookup as MemberExpr;
- if (me == null){
- if (member_lookup is TypeExpression){
- ec.Report.Error (582, loc, "{0}: Can not reference a type through an expression, try `{1}' instead",
- Identifier, member_lookup.GetSignatureForError ());
- } else {
- ec.Report.Error (582, loc, "{0}: Can not reference a {1} through an expression",
- Identifier, member_lookup.ExprClassName);
- }
-
- return null;
- }
-
- me = me.ResolveMemberAccess (ec, left, null);
- me.IsBase = true;
+ #region Properties
- if (args != null) {
- args.Resolve (ec);
- me.SetTypeArguments (ec, args);
+ public override string Name {
+ get {
+ return "base";
}
-
- return me;
}
- public override void Emit (EmitContext ec)
- {
- throw new Exception ("Should never be called");
- }
+ #endregion
- protected override void CloneTo (CloneContext clonectx, Expression t)
+ public override Expression CreateExpressionTree (ResolveContext ec)
{
- BaseAccess target = (BaseAccess) t;
-
- if (args != null)
- target.args = args.Clone ();
+ ec.Report.Error (831, loc, "An expression tree may not contain a base access");
+ return base.CreateExpressionTree (ec);
}
- }
- /// <summary>
- /// The base indexer operator
- /// </summary>
- public class BaseIndexerAccess : IndexerAccess {
- public BaseIndexerAccess (Arguments args, Location loc)
- : base (null, true, loc)
+ public override void Emit (EmitContext ec)
{
- this.arguments = args;
+ base.Emit (ec);
+
+ if (ec.CurrentType.IsStruct) {
+ ec.Emit (OpCodes.Ldobj, ec.CurrentType);
+ ec.Emit (OpCodes.Box, ec.CurrentType);
+ }
}
- protected override void CommonResolve (ResolveContext ec)
+ protected override void Error_ThisNotAvailable (ResolveContext ec)
{
- instance_expr = ec.GetThis (loc);
-
- current_type = ec.CurrentType.BaseType;
- indexer_type = current_type;
+ if (ec.IsStatic) {
+ ec.Report.Error (1511, loc, "Keyword `base' is not available in a static method");
+ } else {
+ ec.Report.Error (1512, loc, "Keyword `base' is not available in the current context");
+ }
}
- public override Expression CreateExpressionTree (ResolveContext ec)
+ public override void ResolveBase (ResolveContext ec)
{
- MemberExpr.Error_BaseAccessInExpressionTree (ec, loc);
- return base.CreateExpressionTree (ec);
+ base.ResolveBase (ec);
+ type = ec.CurrentType.BaseType;
}
}
-
+
/// <summary>
/// This class exists solely to pass the Type around and to be a dummy
/// that can be passed to the conversion functions (this is used by
public static readonly EmptyExpression LValueMemberAccess = new EmptyExpression ();
public static readonly EmptyExpression LValueMemberOutAccess = new EmptyExpression ();
public static readonly EmptyExpression UnaryAddress = new EmptyExpression ();
+ public static readonly EmptyExpression EventAddition = new EmptyExpression ();
+ public static readonly EmptyExpression EventSubtraction = new EmptyExpression ();
+ public static readonly EmptyExpression MissingValue = new EmptyExpression (InternalType.FakeInternalType);
static EmptyExpression temp = new EmptyExpression ();
public static EmptyExpression Grab ()
}
}
+ //
+ // Holds additional type specifiers like ?, *, []
+ //
+ public class ComposedTypeSpecifier
+ {
+ public static readonly ComposedTypeSpecifier SingleDimension = new ComposedTypeSpecifier (1, Location.Null);
+
+ public readonly int Dimension;
+ public readonly Location Location;
+
+ public ComposedTypeSpecifier (int specifier, Location loc)
+ {
+ this.Dimension = specifier;
+ this.Location = loc;
+ }
+
+ #region Properties
+ public bool IsNullable {
+ get {
+ return Dimension == -1;
+ }
+ }
+
+ public bool IsPointer {
+ get {
+ return Dimension == -2;
+ }
+ }
+
+ public ComposedTypeSpecifier Next { get; set; }
+
+ #endregion
+
+ public static ComposedTypeSpecifier CreateArrayDimension (int dimension, Location loc)
+ {
+ return new ComposedTypeSpecifier (dimension, loc);
+ }
+
+ public static ComposedTypeSpecifier CreateNullable (Location loc)
+ {
+ return new ComposedTypeSpecifier (-1, loc);
+ }
+
+ public static ComposedTypeSpecifier CreatePointer (Location loc)
+ {
+ return new ComposedTypeSpecifier (-2, loc);
+ }
+
+ public string GetSignatureForError ()
+ {
+ string s =
+ IsPointer ? "*" :
+ IsNullable ? "?" :
+ ArrayContainer.GetPostfixSignature (Dimension);
+
+ return Next != null ? s + Next.GetSignatureForError () : s;
+ }
+ }
+
// <summary>
// This class is used to "construct" the type during a typecast
// operation. Since the Type.GetType class in .NET can parse
// </summary>
public class ComposedCast : TypeExpr {
FullNamedExpression left;
- string dim;
+ ComposedTypeSpecifier spec;
- public ComposedCast (FullNamedExpression left, string dim)
- : this (left, dim, left.Location)
+ public ComposedCast (FullNamedExpression left, ComposedTypeSpecifier spec)
{
- }
+ if (spec == null)
+ throw new ArgumentNullException ("spec");
- public ComposedCast (FullNamedExpression left, string dim, Location l)
- {
this.left = left;
- this.dim = dim;
- loc = l;
+ this.spec = spec;
+ this.loc = spec.Location;
}
protected override TypeExpr DoResolveAsTypeStep (IMemberContext ec)
if (lexpr == null)
return null;
- TypeSpec ltype = lexpr.Type;
- if ((dim.Length > 0) && (dim [0] == '?')) {
- TypeExpr nullable = new Nullable.NullableType (lexpr, loc);
- if (dim.Length > 1)
- nullable = new ComposedCast (nullable, dim.Substring (1), loc);
- return nullable.ResolveAsTypeTerminal (ec, false);
- }
+ type = lexpr.Type;
+ eclass = ExprClass.Type;
- if (dim == "*" && !TypeManager.VerifyUnmanaged (ec.Compiler, ltype, loc))
- return null;
+ var single_spec = spec;
+
+ if (single_spec.IsNullable) {
+ lexpr = new Nullable.NullableType (lexpr, loc);
+ lexpr = lexpr.ResolveAsTypeTerminal (ec, false);
+ if (lexpr != null)
+ type = lexpr.Type;
- if (dim.Length != 0 && dim [0] == '[') {
- if (TypeManager.IsSpecialType (ltype)) {
- ec.Compiler.Report.Error (611, loc, "Array elements cannot be of type `{0}'", TypeManager.CSharpName (ltype));
+ single_spec = single_spec.Next;
+ } else if (single_spec.IsPointer) {
+ if (!TypeManager.VerifyUnmanaged (ec.Compiler, type, loc))
return null;
- }
- if (ltype.IsStatic) {
- ec.Compiler.Report.SymbolRelatedToPreviousError (ltype);
- ec.Compiler.Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
- TypeManager.CSharpName (ltype));
+ if (!ec.IsUnsafe) {
+ UnsafeError (ec.Compiler.Report, loc);
}
- }
- if (dim != "")
- type = TypeManager.GetConstructedType (ltype, dim);
- else
- type = ltype;
-
- if (type == null)
- throw new InternalErrorException ("Couldn't create computed type " + ltype + dim);
+ do {
+ type = PointerContainer.MakeType (type);
+ single_spec = single_spec.Next;
+ } while (single_spec != null && single_spec.IsPointer);
+ }
- if (type.IsPointer && !ec.IsUnsafe){
- UnsafeError (ec.Compiler.Report, loc);
+ if (single_spec != null && single_spec.Dimension > 0) {
+ if (TypeManager.IsSpecialType (type)) {
+ ec.Compiler.Report.Error (611, loc, "Array elements cannot be of type `{0}'", type.GetSignatureForError ());
+ } else if (type.IsStatic) {
+ ec.Compiler.Report.SymbolRelatedToPreviousError (type);
+ ec.Compiler.Report.Error (719, loc, "Array elements cannot be of static type `{0}'",
+ type.GetSignatureForError ());
+ } else {
+ MakeArray (single_spec);
+ }
}
- eclass = ExprClass.Type;
return this;
}
+ void MakeArray (ComposedTypeSpecifier spec)
+ {
+ if (spec.Next != null)
+ MakeArray (spec.Next);
+
+ type = ArrayContainer.MakeType (type, spec.Dimension);
+ }
+
public override string GetSignatureForError ()
{
- return left.GetSignatureForError () + dim;
+ return left.GetSignatureForError () + spec.GetSignatureForError ();
}
}
{
if (source == null)
return EmptyExpressionStatement.Instance;
-
- MemberExpr me = MemberLookupFinal (ec, ec.CurrentInitializerVariable.Type, ec.CurrentInitializerVariable.Type,
- Name, 0, MemberKind.Field | MemberKind.Property, BindingRestriction.AccessibleOnly | BindingRestriction.InstanceOnly, loc) as MemberExpr;
- if (me == null)
- return null;
+ var t = ec.CurrentInitializerVariable.Type;
+ if (t == InternalType.Dynamic) {
+ Arguments args = new Arguments (1);
+ args.Add (new Argument (ec.CurrentInitializerVariable));
+ target = new DynamicMemberBinder (Name, args, loc);
+ } else {
+
+ var member = MemberLookup (ec, ec.CurrentType, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
+ if (member == null) {
+ member = Expression.MemberLookup (null, ec.CurrentType, t, Name, 0, MemberLookupRestrictions.ExactArity, loc);
+
+ if (member != null) {
+ // TODO: ec.Report.SymbolRelatedToPreviousError (member);
+ ErrorIsInaccesible (ec, member.GetSignatureForError (), loc);
+ return null;
+ }
+ }
- target = me;
- me.InstanceExpression = ec.CurrentInitializerVariable;
+ if (member == null) {
+ Error_TypeDoesNotContainDefinition (ec, loc, t, Name);
+ return null;
+ }
+
+ if (!(member is PropertyExpr || member is FieldExpr)) {
+ ec.Report.Error (1913, loc,
+ "Member `{0}' cannot be initialized. An object initializer may only be used for fields, or properties",
+ member.GetSignatureForError ());
+
+ return null;
+ }
+
+ var me = member as MemberExpr;
+ if (me.IsStatic) {
+ ec.Report.Error (1914, loc,
+ "Static field or property `{0}' cannot be assigned in an object initializer",
+ me.GetSignatureForError ());
+ }
+
+ target = me;
+ me.InstanceExpression = ec.CurrentInitializerVariable;
+ }
if (source is CollectionOrObjectInitializers) {
Expression previous = ec.CurrentInitializerVariable;
return this;
}
- Expression expr = base.DoResolve (ec);
- if (expr == null)
- return null;
-
- //
- // Ignore field initializers with default value
- //
- Constant c = source as Constant;
- if (c != null && c.IsDefaultInitializer (type) && target.eclass == ExprClass.Variable)
- return EmptyExpressionStatement.Instance.Resolve (ec);
-
- return expr;
- }
-
- protected override MemberExpr Error_MemberLookupFailed (ResolveContext ec, TypeSpec type, IList<MemberSpec> members)
- {
- var member = members.First ();
- if (member.Kind != MemberKind.Property && member.Kind != MemberKind.Field)
- ec.Report.Error (1913, loc, "Member `{0}' cannot be initialized. An object " +
- "initializer may only be used for fields, or properties", TypeManager.GetFullNameSignature (member));
- else
- ec.Report.Error (1914, loc, " Static field or property `{0}' cannot be assigned in an object initializer",
- TypeManager.GetFullNameSignature (member));
-
- return null;
+ return base.DoResolve (ec);
}
-
+
public override void EmitStatement (EmitContext ec)
{
if (source is CollectionOrObjectInitializers)
expr_initializers.Add (a.CreateExpressionTree (ec));
args.Add (new Argument (new ArrayCreation (
- CreateExpressionTypeExpression (ec, loc), "[]", expr_initializers, loc)));
+ CreateExpressionTypeExpression (ec, loc), expr_initializers, loc)));
return CreateExpressionFactoryCall (ec, "ElementInit", args);
}
expr_initializers.Add (expr);
}
- return new ImplicitlyTypedArrayCreation ("[]", expr_initializers, loc);
+ return new ImplicitlyTypedArrayCreation (expr_initializers, loc);
}
protected override Expression DoResolve (ResolveContext ec)
{
List<string> element_names = null;
for (int i = 0; i < initializers.Count; ++i) {
- Expression initializer = (Expression) initializers [i];
+ Expression initializer = initializers [i];
ElementInitializer element_initializer = initializer as ElementInitializer;
if (i == 0) {
initializer.Resolve (ec);
throw new InternalErrorException ("This line should never be reached");
} else {
- if (!ec.CurrentInitializerVariable.Type.ImplementsInterface (TypeManager.ienumerable_type)) {
+ var t = ec.CurrentInitializerVariable.Type;
+ // LAMESPEC: The collection must implement IEnumerable only, no dynamic support
+ if (!t.ImplementsInterface (TypeManager.ienumerable_type, false) && t != InternalType.Dynamic) {
ec.Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
"object initializer because type `{1}' does not implement `{2}' interface",
ec.CurrentInitializerVariable.GetSignatureForError (),
CollectionOrObjectInitializers initializers;
IMemoryLocation instance;
- public NewInitialize (Expression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)
+ public NewInitialize (FullNamedExpression requested_type, Arguments arguments, CollectionOrObjectInitializers initializers, Location l)
: base (requested_type, arguments, l)
{
this.initializers = initializers;
return left_on_stack;
}
-
- public override bool HasInitializer {
- get {
- return !initializers.IsEmpty;
- }
- }
}
public class NewAnonymousType : New
foreach (Property p in anonymous_type.Properties)
init.Add (new TypeOfMethod (MemberCache.GetMember (type, p.Get.Spec), loc));
- var ctor_args = new ArrayInitializer (Arguments.Count, loc);
- foreach (Argument a in Arguments)
+ var ctor_args = new ArrayInitializer (arguments.Count, loc);
+ foreach (Argument a in arguments)
ctor_args.Add (a.CreateExpressionTree (ec));
Arguments args = new Arguments (3);
- args.Add (new Argument (method.CreateExpressionTree (ec)));
- args.Add (new Argument (new ArrayCreation (TypeManager.expression_type_expr, "[]", ctor_args, loc)));
- args.Add (new Argument (new ImplicitlyTypedArrayCreation ("[]", init, loc)));
+ args.Add (new Argument (new TypeOfMethod (method, loc)));
+ args.Add (new Argument (new ArrayCreation (TypeManager.expression_type_expr, ctor_args, loc)));
+ args.Add (new Argument (new ImplicitlyTypedArrayCreation (init, loc)));
return CreateExpressionFactoryCall (ec, "New", args);
}
}
bool error = false;
- Arguments = new Arguments (parameters.Count);
+ arguments = new Arguments (parameters.Count);
TypeExpression [] t_args = new TypeExpression [parameters.Count];
for (int i = 0; i < parameters.Count; ++i) {
Expression e = ((AnonymousTypeParameter) parameters [i]).Resolve (ec);
continue;
}
- Arguments.Add (new Argument (e));
+ arguments.Add (new Argument (e));
t_args [i] = new TypeExpression (e.Type, e.Location);
}
}
type = e.Type;
- if (type == TypeManager.void_type || type == TypeManager.null_type ||
+ if (type == TypeManager.void_type || type == InternalType.Null ||
type == InternalType.AnonymousMethod || type.IsPointer) {
Error_InvalidInitializer (ec, e.GetSignatureForError ());
return null;