/NRefactory/ICSharpCode.NRefactory.CSharp/Parser/mcs/expression.cs
http://github.com/icsharpcode/ILSpy · C# · 11921 lines · 8883 code · 2037 blank · 1001 comment · 2460 complexity · 24d900a0fd8e2b864aaeb0244c899382 MD5 · raw file
Large files are truncated click here to view the full file
- //
- // expression.cs: Expression representation for the IL tree.
- //
- // Author:
- // Miguel de Icaza (miguel@ximian.com)
- // Marek Safar (marek.safar@gmail.com)
- //
- // Copyright 2001, 2002, 2003 Ximian, Inc.
- // Copyright 2003-2008 Novell, Inc.
- // Copyright 2011 Xamarin Inc.
- //
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using SLE = System.Linq.Expressions;
- #if STATIC
- using MetaType = IKVM.Reflection.Type;
- using IKVM.Reflection;
- using IKVM.Reflection.Emit;
- #else
- using MetaType = System.Type;
- using System.Reflection;
- using System.Reflection.Emit;
- #endif
- namespace Mono.CSharp
- {
- //
- // This is an user operator expression, automatically created during
- // resolve phase
- //
- public class UserOperatorCall : Expression {
- protected readonly Arguments arguments;
- protected readonly MethodSpec oper;
- readonly Func<ResolveContext, Expression, Expression> expr_tree;
- public UserOperatorCall (MethodSpec oper, Arguments args, Func<ResolveContext, Expression, Expression> expr_tree, Location loc)
- {
- this.oper = oper;
- this.arguments = args;
- this.expr_tree = expr_tree;
- type = oper.ReturnType;
- eclass = ExprClass.Value;
- this.loc = loc;
- }
- public override bool ContainsEmitWithAwait ()
- {
- return arguments.ContainsEmitWithAwait ();
- }
- public override Expression CreateExpressionTree (ResolveContext ec)
- {
- if (expr_tree != null)
- return expr_tree (ec, new TypeOfMethod (oper, loc));
- Arguments args = Arguments.CreateForExpressionTree (ec, arguments,
- new NullLiteral (loc),
- new TypeOfMethod (oper, loc));
- return CreateExpressionFactoryCall (ec, "Call", args);
- }
- protected override void CloneTo (CloneContext context, Expression target)
- {
- // Nothing to clone
- }
-
- protected override Expression DoResolve (ResolveContext ec)
- {
- //
- // We are born fully resolved
- //
- return this;
- }
- public override void Emit (EmitContext ec)
- {
- var call = new CallEmitter ();
- call.Emit (ec, oper, arguments, loc);
- }
- public override void FlowAnalysis (FlowAnalysisContext fc)
- {
- arguments.FlowAnalysis (fc);
- }
- public override SLE.Expression MakeExpression (BuilderContext ctx)
- {
- #if STATIC
- return base.MakeExpression (ctx);
- #else
- return SLE.Expression.Call ((MethodInfo) oper.GetMetaInfo (), Arguments.MakeExpression (arguments, ctx));
- #endif
- }
- }
- public class ParenthesizedExpression : ShimExpression
- {
- public ParenthesizedExpression (Expression expr, Location loc)
- : base (expr)
- {
- this.loc = loc;
- }
- protected override Expression DoResolve (ResolveContext ec)
- {
- var res = expr.Resolve (ec);
- var constant = res as Constant;
- if (constant != null && constant.IsLiteral)
- return Constant.CreateConstantFromValue (res.Type, constant.GetValue (), expr.Location);
- return res;
- }
- public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
- {
- return expr.DoResolveLValue (ec, right_side);
- }
-
- public override object Accept (StructuralVisitor visitor)
- {
- return visitor.Visit (this);
- }
- }
-
- //
- // Unary implements unary expressions.
- //
- public class Unary : Expression
- {
- public enum Operator : byte {
- UnaryPlus, UnaryNegation, LogicalNot, OnesComplement,
- AddressOf, TOP
- }
- public readonly Operator Oper;
- public Expression Expr;
- ConvCast.Mode enum_conversion;
- public Unary (Operator op, Expression expr, Location loc)
- {
- Oper = op;
- Expr = expr;
- this.loc = loc;
- }
- // <summary>
- // This routine will attempt to simplify the unary expression when the
- // argument is a constant.
- // </summary>
- Constant TryReduceConstant (ResolveContext ec, Constant constant)
- {
- var e = constant;
- while (e is EmptyConstantCast)
- e = ((EmptyConstantCast) e).child;
-
- if (e is SideEffectConstant) {
- Constant r = TryReduceConstant (ec, ((SideEffectConstant) e).value);
- return r == null ? null : new SideEffectConstant (r, e, r.Location);
- }
- TypeSpec expr_type = e.Type;
-
- switch (Oper){
- case Operator.UnaryPlus:
- // Unary numeric promotions
- switch (expr_type.BuiltinType) {
- case BuiltinTypeSpec.Type.Byte:
- return new IntConstant (ec.BuiltinTypes, ((ByteConstant) e).Value, e.Location);
- case BuiltinTypeSpec.Type.SByte:
- return new IntConstant (ec.BuiltinTypes, ((SByteConstant) e).Value, e.Location);
- case BuiltinTypeSpec.Type.Short:
- return new IntConstant (ec.BuiltinTypes, ((ShortConstant) e).Value, e.Location);
- case BuiltinTypeSpec.Type.UShort:
- return new IntConstant (ec.BuiltinTypes, ((UShortConstant) e).Value, e.Location);
- case BuiltinTypeSpec.Type.Char:
- return new IntConstant (ec.BuiltinTypes, ((CharConstant) e).Value, e.Location);
-
- // Predefined operators
- case BuiltinTypeSpec.Type.Int:
- case BuiltinTypeSpec.Type.UInt:
- case BuiltinTypeSpec.Type.Long:
- case BuiltinTypeSpec.Type.ULong:
- case BuiltinTypeSpec.Type.Float:
- case BuiltinTypeSpec.Type.Double:
- case BuiltinTypeSpec.Type.Decimal:
- return e;
- }
-
- return null;
-
- case Operator.UnaryNegation:
- // Unary numeric promotions
- switch (expr_type.BuiltinType) {
- case BuiltinTypeSpec.Type.Byte:
- return new IntConstant (ec.BuiltinTypes, -((ByteConstant) e).Value, e.Location);
- case BuiltinTypeSpec.Type.SByte:
- return new IntConstant (ec.BuiltinTypes, -((SByteConstant) e).Value, e.Location);
- case BuiltinTypeSpec.Type.Short:
- return new IntConstant (ec.BuiltinTypes, -((ShortConstant) e).Value, e.Location);
- case BuiltinTypeSpec.Type.UShort:
- return new IntConstant (ec.BuiltinTypes, -((UShortConstant) e).Value, e.Location);
- case BuiltinTypeSpec.Type.Char:
- return new IntConstant (ec.BuiltinTypes, -((CharConstant) e).Value, e.Location);
- // Predefined operators
- case BuiltinTypeSpec.Type.Int:
- int ivalue = ((IntConstant) e).Value;
- if (ivalue == int.MinValue) {
- if (ec.ConstantCheckState) {
- ConstantFold.Error_CompileTimeOverflow (ec, loc);
- return null;
- }
- return e;
- }
- return new IntConstant (ec.BuiltinTypes, -ivalue, e.Location);
- case BuiltinTypeSpec.Type.Long:
- long lvalue = ((LongConstant) e).Value;
- if (lvalue == long.MinValue) {
- if (ec.ConstantCheckState) {
- ConstantFold.Error_CompileTimeOverflow (ec, loc);
- return null;
- }
- return e;
- }
- return new LongConstant (ec.BuiltinTypes, -lvalue, e.Location);
- case BuiltinTypeSpec.Type.UInt:
- UIntLiteral uil = constant as UIntLiteral;
- if (uil != null) {
- if (uil.Value == int.MaxValue + (uint) 1)
- return new IntLiteral (ec.BuiltinTypes, int.MinValue, e.Location);
- return new LongLiteral (ec.BuiltinTypes, -uil.Value, e.Location);
- }
- return new LongConstant (ec.BuiltinTypes, -((UIntConstant) e).Value, e.Location);
- case BuiltinTypeSpec.Type.ULong:
- ULongLiteral ull = constant as ULongLiteral;
- if (ull != null && ull.Value == 9223372036854775808)
- return new LongLiteral (ec.BuiltinTypes, long.MinValue, e.Location);
- return null;
- case BuiltinTypeSpec.Type.Float:
- FloatLiteral fl = constant as FloatLiteral;
- // For better error reporting
- if (fl != null)
- return new FloatLiteral (ec.BuiltinTypes, -fl.Value, e.Location);
- return new FloatConstant (ec.BuiltinTypes, -((FloatConstant) e).Value, e.Location);
- case BuiltinTypeSpec.Type.Double:
- DoubleLiteral dl = constant as DoubleLiteral;
- // For better error reporting
- if (dl != null)
- return new DoubleLiteral (ec.BuiltinTypes, -dl.Value, e.Location);
- return new DoubleConstant (ec.BuiltinTypes, -((DoubleConstant) e).Value, e.Location);
- case BuiltinTypeSpec.Type.Decimal:
- return new DecimalConstant (ec.BuiltinTypes, -((DecimalConstant) e).Value, e.Location);
- }
- return null;
-
- case Operator.LogicalNot:
- if (expr_type.BuiltinType != BuiltinTypeSpec.Type.Bool)
- return null;
-
- bool b = (bool)e.GetValue ();
- return new BoolConstant (ec.BuiltinTypes, !b, e.Location);
-
- case Operator.OnesComplement:
- // Unary numeric promotions
- switch (expr_type.BuiltinType) {
- case BuiltinTypeSpec.Type.Byte:
- return new IntConstant (ec.BuiltinTypes, ~((ByteConstant) e).Value, e.Location);
- case BuiltinTypeSpec.Type.SByte:
- return new IntConstant (ec.BuiltinTypes, ~((SByteConstant) e).Value, e.Location);
- case BuiltinTypeSpec.Type.Short:
- return new IntConstant (ec.BuiltinTypes, ~((ShortConstant) e).Value, e.Location);
- case BuiltinTypeSpec.Type.UShort:
- return new IntConstant (ec.BuiltinTypes, ~((UShortConstant) e).Value, e.Location);
- case BuiltinTypeSpec.Type.Char:
- return new IntConstant (ec.BuiltinTypes, ~((CharConstant) e).Value, e.Location);
-
- // Predefined operators
- case BuiltinTypeSpec.Type.Int:
- return new IntConstant (ec.BuiltinTypes, ~((IntConstant)e).Value, e.Location);
- case BuiltinTypeSpec.Type.UInt:
- return new UIntConstant (ec.BuiltinTypes, ~((UIntConstant) e).Value, e.Location);
- case BuiltinTypeSpec.Type.Long:
- return new LongConstant (ec.BuiltinTypes, ~((LongConstant) e).Value, e.Location);
- case BuiltinTypeSpec.Type.ULong:
- return new ULongConstant (ec.BuiltinTypes, ~((ULongConstant) e).Value, e.Location);
- }
- if (e is EnumConstant) {
- var res = TryReduceConstant (ec, ((EnumConstant)e).Child);
- if (res != null) {
- //
- // Numeric promotion upgraded types to int but for enum constant
- // original underlying constant type is needed
- //
- if (res.Type.BuiltinType == BuiltinTypeSpec.Type.Int) {
- int v = ((IntConstant) res).Value;
- switch (((EnumConstant) e).Child.Type.BuiltinType) {
- case BuiltinTypeSpec.Type.UShort:
- res = new UShortConstant (ec.BuiltinTypes, (ushort) v, e.Location);
- break;
- case BuiltinTypeSpec.Type.Short:
- res = new ShortConstant (ec.BuiltinTypes, (short) v, e.Location);
- break;
- case BuiltinTypeSpec.Type.Byte:
- res = new ByteConstant (ec.BuiltinTypes, (byte) v, e.Location);
- break;
- case BuiltinTypeSpec.Type.SByte:
- res = new SByteConstant (ec.BuiltinTypes, (sbyte) v, e.Location);
- break;
- }
- }
- res = new EnumConstant (res, expr_type);
- }
- return res;
- }
- return null;
- }
- throw new Exception ("Can not constant fold: " + Oper.ToString());
- }
-
- protected virtual Expression ResolveOperator (ResolveContext ec, Expression expr)
- {
- eclass = ExprClass.Value;
- TypeSpec expr_type = expr.Type;
- Expression best_expr;
- TypeSpec[] predefined = ec.BuiltinTypes.OperatorsUnary [(int) Oper];
- //
- // Primitive types first
- //
- if (BuiltinTypeSpec.IsPrimitiveType (expr_type)) {
- best_expr = ResolvePrimitivePredefinedType (ec, expr, predefined);
- if (best_expr == null)
- return null;
- type = best_expr.Type;
- Expr = best_expr;
- return this;
- }
- //
- // E operator ~(E x);
- //
- if (Oper == Operator.OnesComplement && expr_type.IsEnum)
- return ResolveEnumOperator (ec, expr, predefined);
- return ResolveUserType (ec, expr, predefined);
- }
- protected virtual Expression ResolveEnumOperator (ResolveContext ec, Expression expr, TypeSpec[] predefined)
- {
- TypeSpec underlying_type = EnumSpec.GetUnderlyingType (expr.Type);
- Expression best_expr = ResolvePrimitivePredefinedType (ec, EmptyCast.Create (expr, underlying_type), predefined);
- if (best_expr == null)
- return null;
- Expr = best_expr;
- enum_conversion = Binary.GetEnumResultCast (underlying_type);
- type = expr.Type;
- return EmptyCast.Create (this, type);
- }
- public override bool ContainsEmitWithAwait ()
- {
- return Expr.ContainsEmitWithAwait ();
- }
- public override Expression CreateExpressionTree (ResolveContext ec)
- {
- return CreateExpressionTree (ec, null);
- }
- Expression CreateExpressionTree (ResolveContext ec, Expression user_op)
- {
- string method_name;
- switch (Oper) {
- case Operator.AddressOf:
- Error_PointerInsideExpressionTree (ec);
- return null;
- case Operator.UnaryNegation:
- if (ec.HasSet (ResolveContext.Options.CheckedScope) && user_op == null && !IsFloat (type))
- method_name = "NegateChecked";
- else
- method_name = "Negate";
- break;
- case Operator.OnesComplement:
- case Operator.LogicalNot:
- method_name = "Not";
- break;
- case Operator.UnaryPlus:
- method_name = "UnaryPlus";
- break;
- default:
- throw new InternalErrorException ("Unknown unary operator " + Oper.ToString ());
- }
- Arguments args = new Arguments (2);
- args.Add (new Argument (Expr.CreateExpressionTree (ec)));
- if (user_op != null)
- args.Add (new Argument (user_op));
- return CreateExpressionFactoryCall (ec, method_name, args);
- }
- public static TypeSpec[][] CreatePredefinedOperatorsTable (BuiltinTypes types)
- {
- var predefined_operators = new TypeSpec[(int) Operator.TOP][];
- //
- // 7.6.1 Unary plus operator
- //
- predefined_operators [(int) Operator.UnaryPlus] = new TypeSpec [] {
- types.Int, types.UInt,
- types.Long, types.ULong,
- types.Float, types.Double,
- types.Decimal
- };
- //
- // 7.6.2 Unary minus operator
- //
- predefined_operators [(int) Operator.UnaryNegation] = new TypeSpec [] {
- types.Int, types.Long,
- types.Float, types.Double,
- types.Decimal
- };
- //
- // 7.6.3 Logical negation operator
- //
- predefined_operators [(int) Operator.LogicalNot] = new TypeSpec [] {
- types.Bool
- };
- //
- // 7.6.4 Bitwise complement operator
- //
- predefined_operators [(int) Operator.OnesComplement] = new TypeSpec [] {
- types.Int, types.UInt,
- types.Long, types.ULong
- };
- return predefined_operators;
- }
- //
- // Unary numeric promotions
- //
- static Expression DoNumericPromotion (ResolveContext rc, Operator op, Expression expr)
- {
- TypeSpec expr_type = expr.Type;
- if (op == Operator.UnaryPlus || op == Operator.UnaryNegation || op == Operator.OnesComplement) {
- switch (expr_type.BuiltinType) {
- case BuiltinTypeSpec.Type.Byte:
- case BuiltinTypeSpec.Type.SByte:
- case BuiltinTypeSpec.Type.Short:
- case BuiltinTypeSpec.Type.UShort:
- case BuiltinTypeSpec.Type.Char:
- return Convert.ImplicitNumericConversion (expr, rc.BuiltinTypes.Int);
- }
- }
- if (op == Operator.UnaryNegation && expr_type.BuiltinType == BuiltinTypeSpec.Type.UInt)
- return Convert.ImplicitNumericConversion (expr, rc.BuiltinTypes.Long);
- return expr;
- }
- protected override Expression DoResolve (ResolveContext ec)
- {
- if (Oper == Operator.AddressOf) {
- return ResolveAddressOf (ec);
- }
- Expr = Expr.Resolve (ec);
- if (Expr == null)
- return null;
- if (Expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
- Arguments args = new Arguments (1);
- args.Add (new Argument (Expr));
- return new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc).Resolve (ec);
- }
- if (Expr.Type.IsNullableType)
- return new Nullable.LiftedUnaryOperator (Oper, Expr, loc).Resolve (ec);
- //
- // Attempt to use a constant folding operation.
- //
- Constant cexpr = Expr as Constant;
- if (cexpr != null) {
- cexpr = TryReduceConstant (ec, cexpr);
- if (cexpr != null)
- return cexpr;
- }
- Expression expr = ResolveOperator (ec, Expr);
- if (expr == null)
- Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), Expr.Type);
-
- //
- // Reduce unary operator on predefined types
- //
- if (expr == this && Oper == Operator.UnaryPlus)
- return Expr;
- return expr;
- }
- public override Expression DoResolveLValue (ResolveContext ec, Expression right)
- {
- return null;
- }
- public override void Emit (EmitContext ec)
- {
- EmitOperator (ec, type);
- }
- protected void EmitOperator (EmitContext ec, TypeSpec type)
- {
- switch (Oper) {
- case Operator.UnaryPlus:
- Expr.Emit (ec);
- break;
-
- case Operator.UnaryNegation:
- if (ec.HasSet (EmitContext.Options.CheckedScope) && !IsFloat (type)) {
- if (ec.HasSet (BuilderContext.Options.AsyncBody) && Expr.ContainsEmitWithAwait ())
- Expr = Expr.EmitToField (ec);
- ec.EmitInt (0);
- if (type.BuiltinType == BuiltinTypeSpec.Type.Long)
- ec.Emit (OpCodes.Conv_U8);
- Expr.Emit (ec);
- ec.Emit (OpCodes.Sub_Ovf);
- } else {
- Expr.Emit (ec);
- ec.Emit (OpCodes.Neg);
- }
-
- break;
-
- case Operator.LogicalNot:
- Expr.Emit (ec);
- ec.EmitInt (0);
- ec.Emit (OpCodes.Ceq);
- break;
-
- case Operator.OnesComplement:
- Expr.Emit (ec);
- ec.Emit (OpCodes.Not);
- break;
-
- case Operator.AddressOf:
- ((IMemoryLocation)Expr).AddressOf (ec, AddressOp.LoadStore);
- break;
-
- default:
- throw new Exception ("This should not happen: Operator = "
- + Oper.ToString ());
- }
- //
- // Same trick as in Binary expression
- //
- if (enum_conversion != 0) {
- using (ec.With (BuilderContext.Options.CheckedScope, false)) {
- ConvCast.Emit (ec, enum_conversion);
- }
- }
- }
- public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
- {
- if (Oper == Operator.LogicalNot)
- Expr.EmitBranchable (ec, target, !on_true);
- else
- base.EmitBranchable (ec, target, on_true);
- }
- public override void EmitSideEffect (EmitContext ec)
- {
- Expr.EmitSideEffect (ec);
- }
- public static void Error_Ambiguous (ResolveContext rc, string oper, TypeSpec type, Location loc)
- {
- rc.Report.Error (35, loc, "Operator `{0}' is ambiguous on an operand of type `{1}'",
- oper, type.GetSignatureForError ());
- }
- public override void FlowAnalysis (FlowAnalysisContext fc)
- {
- FlowAnalysis (fc, false);
- }
- public override void FlowAnalysisConditional (FlowAnalysisContext fc)
- {
- FlowAnalysis (fc, true);
- }
- void FlowAnalysis (FlowAnalysisContext fc, bool conditional)
- {
- if (Oper == Operator.AddressOf) {
- var vr = Expr as VariableReference;
- if (vr != null && vr.VariableInfo != null)
- fc.SetVariableAssigned (vr.VariableInfo);
- return;
- }
- if (Oper == Operator.LogicalNot && conditional) {
- Expr.FlowAnalysisConditional (fc);
- var temp = fc.DefiniteAssignmentOnTrue;
- fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse;
- fc.DefiniteAssignmentOnFalse = temp;
- } else {
- Expr.FlowAnalysis (fc);
- }
- }
- //
- // Converts operator to System.Linq.Expressions.ExpressionType enum name
- //
- string GetOperatorExpressionTypeName ()
- {
- switch (Oper) {
- case Operator.OnesComplement:
- return "OnesComplement";
- case Operator.LogicalNot:
- return "Not";
- case Operator.UnaryNegation:
- return "Negate";
- case Operator.UnaryPlus:
- return "UnaryPlus";
- default:
- throw new NotImplementedException ("Unknown express type operator " + Oper.ToString ());
- }
- }
- static bool IsFloat (TypeSpec t)
- {
- return t.BuiltinType == BuiltinTypeSpec.Type.Double || t.BuiltinType == BuiltinTypeSpec.Type.Float;
- }
- //
- // Returns a stringified representation of the Operator
- //
- public static string OperName (Operator oper)
- {
- switch (oper) {
- case Operator.UnaryPlus:
- return "+";
- case Operator.UnaryNegation:
- return "-";
- case Operator.LogicalNot:
- return "!";
- case Operator.OnesComplement:
- return "~";
- case Operator.AddressOf:
- return "&";
- }
- throw new NotImplementedException (oper.ToString ());
- }
- public override SLE.Expression MakeExpression (BuilderContext ctx)
- {
- var expr = Expr.MakeExpression (ctx);
- bool is_checked = ctx.HasSet (BuilderContext.Options.CheckedScope);
- switch (Oper) {
- case Operator.UnaryNegation:
- return is_checked ? SLE.Expression.NegateChecked (expr) : SLE.Expression.Negate (expr);
- case Operator.LogicalNot:
- return SLE.Expression.Not (expr);
- #if NET_4_0 || MOBILE_DYNAMIC
- case Operator.OnesComplement:
- return SLE.Expression.OnesComplement (expr);
- #endif
- default:
- throw new NotImplementedException (Oper.ToString ());
- }
- }
- Expression ResolveAddressOf (ResolveContext ec)
- {
- if (!ec.IsUnsafe)
- UnsafeError (ec, loc);
- Expr = Expr.DoResolveLValue (ec, EmptyExpression.UnaryAddress);
- if (Expr == null || Expr.eclass != ExprClass.Variable) {
- ec.Report.Error (211, loc, "Cannot take the address of the given expression");
- return null;
- }
- if (!TypeManager.VerifyUnmanaged (ec.Module, Expr.Type, loc)) {
- return null;
- }
- IVariableReference vr = Expr as IVariableReference;
- bool is_fixed;
- if (vr != null) {
- is_fixed = vr.IsFixed;
- vr.SetHasAddressTaken ();
- if (vr.IsHoisted) {
- AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, vr, loc);
- }
- } else {
- IFixedExpression fe = Expr as IFixedExpression;
- is_fixed = fe != null && fe.IsFixed;
- }
- if (!is_fixed && !ec.HasSet (ResolveContext.Options.FixedInitializerScope)) {
- ec.Report.Error (212, loc, "You can only take the address of unfixed expression inside of a fixed statement initializer");
- }
- type = PointerContainer.MakeType (ec.Module, Expr.Type);
- eclass = ExprClass.Value;
- return this;
- }
- Expression ResolvePrimitivePredefinedType (ResolveContext rc, Expression expr, TypeSpec[] predefined)
- {
- expr = DoNumericPromotion (rc, Oper, expr);
- TypeSpec expr_type = expr.Type;
- foreach (TypeSpec t in predefined) {
- if (t == expr_type)
- return expr;
- }
- return null;
- }
- //
- // Perform user-operator overload resolution
- //
- protected virtual Expression ResolveUserOperator (ResolveContext ec, Expression expr)
- {
- CSharp.Operator.OpType op_type;
- switch (Oper) {
- case Operator.LogicalNot:
- op_type = CSharp.Operator.OpType.LogicalNot; break;
- case Operator.OnesComplement:
- op_type = CSharp.Operator.OpType.OnesComplement; break;
- case Operator.UnaryNegation:
- op_type = CSharp.Operator.OpType.UnaryNegation; break;
- case Operator.UnaryPlus:
- op_type = CSharp.Operator.OpType.UnaryPlus; break;
- default:
- throw new InternalErrorException (Oper.ToString ());
- }
- var methods = MemberCache.GetUserOperator (expr.Type, op_type, false);
- if (methods == null)
- return null;
- Arguments args = new Arguments (1);
- args.Add (new Argument (expr));
- 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 (oper, args, CreateExpressionTree, expr.Location);
- }
- //
- // Unary user type overload resolution
- //
- Expression ResolveUserType (ResolveContext ec, Expression expr, TypeSpec[] predefined)
- {
- Expression best_expr = ResolveUserOperator (ec, expr);
- if (best_expr != null)
- return best_expr;
- foreach (TypeSpec t in predefined) {
- Expression oper_expr = Convert.ImplicitUserConversion (ec, expr, t, expr.Location);
- if (oper_expr == null)
- continue;
- if (oper_expr == ErrorExpression.Instance)
- return oper_expr;
- //
- // decimal type is predefined but has user-operators
- //
- if (oper_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal)
- oper_expr = ResolveUserType (ec, oper_expr, predefined);
- else
- oper_expr = ResolvePrimitivePredefinedType (ec, oper_expr, predefined);
- if (oper_expr == null)
- continue;
- if (best_expr == null) {
- best_expr = oper_expr;
- continue;
- }
- int result = OverloadResolver.BetterTypeConversion (ec, best_expr.Type, t);
- if (result == 0) {
- if ((oper_expr is UserOperatorCall || oper_expr is UserCast) && (best_expr is UserOperatorCall || best_expr is UserCast)) {
- Error_Ambiguous (ec, OperName (Oper), expr.Type, loc);
- } else {
- Error_OperatorCannotBeApplied (ec, loc, OperName (Oper), expr.Type);
- }
- break;
- }
- if (result == 2)
- best_expr = oper_expr;
- }
-
- if (best_expr == null)
- return null;
-
- //
- // HACK: Decimal user-operator is included in standard operators
- //
- if (best_expr.Type.BuiltinType == BuiltinTypeSpec.Type.Decimal)
- return best_expr;
- Expr = best_expr;
- type = best_expr.Type;
- return this;
- }
- protected override void CloneTo (CloneContext clonectx, Expression t)
- {
- Unary target = (Unary) t;
- target.Expr = Expr.Clone (clonectx);
- }
-
- public override object Accept (StructuralVisitor visitor)
- {
- return visitor.Visit (this);
- }
- }
- //
- // Unary operators are turned into Indirection expressions
- // after semantic analysis (this is so we can take the address
- // of an indirection).
- //
- public class Indirection : Expression, IMemoryLocation, IAssignMethod, IFixedExpression {
- Expression expr;
- LocalTemporary temporary;
- bool prepared;
-
- public Indirection (Expression expr, Location l)
- {
- this.expr = expr;
- loc = l;
- }
- public Expression Expr {
- get {
- return expr;
- }
- }
- public bool IsFixed {
- get { return true; }
- }
- public override Location StartLocation {
- get {
- return expr.StartLocation;
- }
- }
- protected override void CloneTo (CloneContext clonectx, Expression t)
- {
- Indirection target = (Indirection) t;
- target.expr = expr.Clone (clonectx);
- }
- public override bool ContainsEmitWithAwait ()
- {
- throw new NotImplementedException ();
- }
- public override Expression CreateExpressionTree (ResolveContext ec)
- {
- Error_PointerInsideExpressionTree (ec);
- return null;
- }
-
- public override void Emit (EmitContext ec)
- {
- if (!prepared)
- expr.Emit (ec);
-
- ec.EmitLoadFromPtr (Type);
- }
- public void Emit (EmitContext ec, bool leave_copy)
- {
- Emit (ec);
- if (leave_copy) {
- ec.Emit (OpCodes.Dup);
- temporary = new LocalTemporary (expr.Type);
- temporary.Store (ec);
- }
- }
-
- public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
- {
- prepared = isCompound;
-
- expr.Emit (ec);
- if (isCompound)
- ec.Emit (OpCodes.Dup);
-
- source.Emit (ec);
- if (leave_copy) {
- ec.Emit (OpCodes.Dup);
- temporary = new LocalTemporary (source.Type);
- temporary.Store (ec);
- }
-
- ec.EmitStoreFromPtr (type);
-
- if (temporary != null) {
- temporary.Emit (ec);
- temporary.Release (ec);
- }
- }
-
- public void AddressOf (EmitContext ec, AddressOp Mode)
- {
- expr.Emit (ec);
- }
- public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
- {
- return DoResolve (ec);
- }
- protected override Expression DoResolve (ResolveContext ec)
- {
- expr = expr.Resolve (ec);
- if (expr == null)
- return null;
- if (!ec.IsUnsafe)
- UnsafeError (ec, loc);
- var pc = expr.Type as PointerContainer;
- if (pc == null) {
- ec.Report.Error (193, loc, "The * or -> operator must be applied to a pointer");
- return null;
- }
- type = pc.Element;
- if (type.Kind == MemberKind.Void) {
- Error_VoidPointerOperation (ec);
- return null;
- }
- eclass = ExprClass.Variable;
- return this;
- }
- public override object Accept (StructuralVisitor visitor)
- {
- return visitor.Visit (this);
- }
- }
-
- /// <summary>
- /// Unary Mutator expressions (pre and post ++ and --)
- /// </summary>
- ///
- /// <remarks>
- /// UnaryMutator implements ++ and -- expressions. It derives from
- /// ExpressionStatement becuase the pre/post increment/decrement
- /// operators can be used in a statement context.
- ///
- /// FIXME: Idea, we could split this up in two classes, one simpler
- /// for the common case, and one with the extra fields for more complex
- /// classes (indexers require temporary access; overloaded require method)
- ///
- /// </remarks>
- public class UnaryMutator : ExpressionStatement
- {
- class DynamicPostMutator : Expression, IAssignMethod
- {
- LocalTemporary temp;
- Expression expr;
- public DynamicPostMutator (Expression expr)
- {
- this.expr = expr;
- this.type = expr.Type;
- this.loc = expr.Location;
- }
- public override Expression CreateExpressionTree (ResolveContext ec)
- {
- throw new NotImplementedException ("ET");
- }
- protected override Expression DoResolve (ResolveContext rc)
- {
- eclass = expr.eclass;
- return this;
- }
- public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
- {
- expr.DoResolveLValue (ec, right_side);
- return DoResolve (ec);
- }
- public override void Emit (EmitContext ec)
- {
- temp.Emit (ec);
- }
- public void Emit (EmitContext ec, bool leave_copy)
- {
- throw new NotImplementedException ();
- }
- //
- // Emits target assignment using unmodified source value
- //
- public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
- {
- //
- // Allocate temporary variable to keep original value before it's modified
- //
- temp = new LocalTemporary (type);
- expr.Emit (ec);
- temp.Store (ec);
- ((IAssignMethod) expr).EmitAssign (ec, source, false, isCompound);
- if (leave_copy)
- Emit (ec);
- temp.Release (ec);
- temp = null;
- }
- }
- [Flags]
- public enum Mode : byte {
- IsIncrement = 0,
- IsDecrement = 1,
- IsPre = 0,
- IsPost = 2,
-
- PreIncrement = 0,
- PreDecrement = IsDecrement,
- PostIncrement = IsPost,
- PostDecrement = IsPost | IsDecrement
- }
- Mode mode;
- bool is_expr, recurse;
- protected Expression expr;
- // Holds the real operation
- Expression operation;
-
- public UnaryMutator (Mode m, Expression e, Location loc)
- {
- mode = m;
- this.loc = loc;
- expr = e;
- }
- public Mode UnaryMutatorMode {
- get {
- return mode;
- }
- }
-
- public Expression Expr {
- get {
- return expr;
- }
- }
- public override Location StartLocation {
- get {
- return (mode & Mode.IsPost) != 0 ? expr.Location : loc;
- }
- }
- public override bool ContainsEmitWithAwait ()
- {
- return expr.ContainsEmitWithAwait ();
- }
- public override Expression CreateExpressionTree (ResolveContext ec)
- {
- return new SimpleAssign (this, this).CreateExpressionTree (ec);
- }
- public static TypeSpec[] CreatePredefinedOperatorsTable (BuiltinTypes types)
- {
- //
- // Predefined ++ and -- operators exist for the following types:
- // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
- //
- return new TypeSpec[] {
- types.Int,
- types.Long,
- types.SByte,
- types.Byte,
- types.Short,
- types.UInt,
- types.ULong,
- types.Char,
- types.Float,
- types.Double,
- types.Decimal
- };
- }
- protected override Expression DoResolve (ResolveContext ec)
- {
- expr = expr.Resolve (ec);
-
- if (expr == null || expr.Type == InternalType.ErrorType)
- return null;
- if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
- //
- // Handle postfix unary operators using local
- // temporary variable
- //
- if ((mode & Mode.IsPost) != 0)
- expr = new DynamicPostMutator (expr);
- Arguments args = new Arguments (1);
- args.Add (new Argument (expr));
- return new SimpleAssign (expr, new DynamicUnaryConversion (GetOperatorExpressionTypeName (), args, loc)).Resolve (ec);
- }
- if (expr.Type.IsNullableType)
- return new Nullable.LiftedUnaryMutator (mode, expr, loc).Resolve (ec);
- return DoResolveOperation (ec);
- }
- protected Expression DoResolveOperation (ResolveContext ec)
- {
- eclass = ExprClass.Value;
- type = expr.Type;
- 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
- //
- Expression source = null;
- bool primitive_type;
- //
- // Predefined without user conversion first for speed-up
- //
- // Predefined ++ and -- operators exist for the following types:
- // sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal
- //
- switch (type.BuiltinType) {
- case BuiltinTypeSpec.Type.Byte:
- case BuiltinTypeSpec.Type.SByte:
- case BuiltinTypeSpec.Type.Short:
- case BuiltinTypeSpec.Type.UShort:
- case BuiltinTypeSpec.Type.Int:
- case BuiltinTypeSpec.Type.UInt:
- case BuiltinTypeSpec.Type.Long:
- case BuiltinTypeSpec.Type.ULong:
- case BuiltinTypeSpec.Type.Char:
- case BuiltinTypeSpec.Type.Float:
- case BuiltinTypeSpec.Type.Double:
- case BuiltinTypeSpec.Type.Decimal:
- source = operation;
- primitive_type = true;
- break;
- default:
- primitive_type = false;
- // ++/-- on pointer variables of all types except void*
- if (type.IsPointer) {
- if (((PointerContainer) type).Element.Kind == MemberKind.Void) {
- Error_VoidPointerOperation (ec);
- return null;
- }
- source = operation;
- } else {
- Expression best_source = null;
- foreach (var t in ec.BuiltinTypes.OperatorsUnaryMutator) {
- source = Convert.ImplicitUserConversion (ec, operation, t, loc);
- // LAMESPEC: It should error on ambiguous operators but that would make us incompatible
- if (source == null)
- continue;
- if (best_source == null) {
- best_source = source;
- continue;
- }
- var better = OverloadResolver.BetterTypeConversion (ec, best_source.Type, source.Type);
- if (better == 1)
- continue;
- if (better == 2) {
- best_source = source;
- continue;
- }
- Unary.Error_Ambiguous (ec, OperName (mode), type, loc);
- break;
- }
- source = best_source;
- }
- // ++/-- on enum types
- if (source == null && type.IsEnum)
- source = operation;
- if (source == null) {
- expr.Error_OperatorCannotBeApplied (ec, loc, Operator.GetName (user_op), type);
- return null;
- }
- break;
- }
- var one = new IntConstant (ec.BuiltinTypes, 1, loc);
- var op = IsDecrement ? Binary.Operator.Subtraction : Binary.Operator.Addition;
- operation = new Binary (op, source, one);
- operation = operation.Resolve (ec);
- if (operation == null)
- throw new NotImplementedException ("should not be reached");
- if (operation.Type != type) {
- if (primitive_type)
- operation = Convert.ExplicitNumericConversion (ec, operation, type);
- else
- operation = Convert.ImplicitConversionRequired (ec, operation, type, loc);
- }
- return this;
- }
- void EmitCode (EmitContext ec, bool is_expr)
- {
- recurse = true;
- this.is_expr = is_expr;
- ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true);
- }
- public override void Emit (EmitContext ec)
- {
- //
- // We use recurse to allow ourselfs to be the source
- // of an assignment. This little hack prevents us from
- // having to allocate another expression
- //
- if (recurse) {
- ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement));
- EmitOperation (ec);
- recurse = false;
- return;
- }
- EmitCode (ec, true);
- }
- protected virtual void EmitOperation (EmitContext ec)
- {
- operation.Emit (ec);
- }
- public override void EmitStatement (EmitContext ec)
- {
- EmitCode (ec, false);
- }
- public override void FlowAnalysis (FlowAnalysisContext fc)
- {
- expr.FlowAnalysis (fc);
- }
- //
- // Converts operator to System.Linq.Expressions.ExpressionType enum name
- //
- string GetOperatorExpressionTypeName ()
- {
- return IsDecrement ? "Decrement" : "Increment";
- }
- bool IsDecrement {
- get { return (mode & Mode.IsDecrement) != 0; }
- }
- #if NET_4_0 || MOBILE_DYNAMIC
- public override SLE.Expression MakeExpression (BuilderContext ctx)
- {
- var target = ((RuntimeValueExpression) expr).MetaObject.Expression;
- var source = SLE.Expression.Convert (operation.MakeExpression (ctx), target.Type);
- return SLE.Expression.Assign (target, source);
- }
- #endif
- public static string OperName (Mode oper)
- {
- return (oper & Mode.IsDecrement) != 0 ? "--" : "++";
- }
- protected override void CloneTo (CloneContext clonectx, Expression t)
- {
- UnaryMutator target = (UnaryMutator) t;
- target.expr = expr.Clone (clonectx);
- }
- public override object Accept (StructuralVisitor visitor)
- {
- return visitor.Visit (this);
- }
- }
- //
- // Base class for the `is' and `as' operators
- //
- public abstract class Probe : Expression
- {
- public Expression ProbeType;
- protected Expression expr;
- protected TypeSpec probe_type_expr;
-
- protected Probe (Expression expr, Expression probe_type, Location l)
- {
- ProbeType = probe_type;
- loc = l;
- this.expr = expr;
- }
- public Expression Expr {
- get {
- return expr;
- }
- }
- public override bool ContainsEmitWithAwait ()
- {
- return expr.ContainsEmitWithAwait ();
- }
- protected Expression ResolveCommon (ResolveContext rc)
- {
- expr = expr.Resolve (rc);
- if (expr == null)
- return null;
- ResolveProbeType (rc);
- if (probe_type_expr == null)
- return this;
- if (probe_type_expr.IsStatic) {
- rc.Report.Error (7023, loc, "The second operand of `is' or `as' operator cannot be static type `{0}'",
- probe_type_expr.GetSignatureForError ());
- return null;
- }
-
- if (expr.Type.IsPointer || probe_type_expr.IsPointer) {
- rc.Report.Error (244, loc, "The `{0}' operator cannot be applied to an operand of pointer type",
- OperatorName);
- return null;
- }
- if (expr.Type == InternalType.AnonymousMethod || expr.Type == InternalType.MethodGroup) {
- rc.Report.Error (837, loc, "The `{0}' operator cannot be applied to a lambda expression, anonymous method, or method group",
- OperatorName);
- return null;
- }
- return this;
- }
- protected virtual void ResolveProbeType (ResolveContext rc)
- {
- probe_type_expr = ProbeType.ResolveAsType (rc);
- }
- public override void EmitSideEffect (EmitContext ec)
- {
- expr.EmitSideEffect (ec);
- }
- public override void FlowAnalysis (FlowAnalysisContext fc)
- {
- expr.FlowAnalysis (fc);
- }
- protected abstract string OperatorName { get; }
- protected override void CloneTo (CloneContext clonectx, Expression t)
- {
- Probe target = (Probe) t;
- target.expr = expr.Clone (clonectx);
- target.ProbeType = ProbeType.Clone (clonectx);
- }
- }
- /// <summary>
- /// Implementation of the `is' operator.
- /// </summary>
- public class Is : Probe
- {
- Nullable.Unwrap expr_unwrap;
- MethodSpec number_mg;
- Arguments number_args;
- public Is (Expression expr, Expression probe_type, Location l)
- : base (expr, probe_type, l)
- {
- }
- protected override string OperatorName {
- get { return "is"; }
- }
- public LocalVariable Variable { get; set; }
- public override Expression CreateExpressionTree (ResolveContext ec)
- {
- if (Variable != null)
- throw new NotSupportedException ();
- Arguments args = Arguments.CreateForExpressionTree (ec, null,
- expr.CreateExpressionTree (ec),
- new TypeOf (probe_type_expr, loc));
- return CreateExpressionFactoryCall (ec, "TypeIs", args);
- }
- Expression CreateConstantResult (ResolveContext rc, bool result)
- {
- if (result)
- rc.Report.Warning (183, 1, loc, "The given expression is always of the provided (`{0}') type",
- probe_type_expr.GetSignatureForError ());
- else
- rc.Report.Warning (184, 1, loc, "The given expression is never of the provided (`{0}') type",
- probe_type_expr.GetSignatureForError ());
- var c = new BoolConstant (rc.BuiltinTypes, result, loc);
- return expr.IsSideEffectFree ?
- ReducedExpression.Create (c, this) :
- new SideEffectConstant (c, this, loc);
- }
- public override void Emit (EmitContext ec)
- {
- if (probe_type_expr == null) {
- EmitConstantMatch (ec);
- return;
- }
- EmitLoad (ec);
- if (expr_unwrap == null) {
- ec.EmitNull ();
- ec.Emit (OpCodes.Cgt_Un);
- }
- }
- public override void EmitBranchable (EmitContext ec, Label target, bool on_true)
- {
- if (probe_type_expr == null) {
- EmitConstantMatch (ec);
- } else {
- EmitLoad (ec);
- }
- ec.Emit (on_true ? OpCodes.Brtrue : OpCodes.Brfalse, target);
- }
- void EmitConstantMatch (EmitContext ec)
- {
- var no_match = ec.DefineLabel ();
- var end = ec.DefineLabel ();
- if (expr_unwrap != null) {
- expr_unwrap.EmitCheck (ec);
- if (ProbeType.IsNull) {
- ec.EmitInt (0);
- ec.Emit (OpCodes.Ceq);
- return;
- }
- ec.Emit (OpCodes.Brfalse_S, no_match);
- expr_unwrap.Emit (ec);
- ProbeType.Emit (ec);
- ec.Emit (OpCodes.Ceq);
- ec.Emit (OpCodes.Br_S, end);
- ec.MarkLabel (no_match);
- ec.EmitInt (0);
- ec.MarkLabel (end);
- return;
- }
- if (number_args != null && number_args.Count == 3) {
- var ce = new CallEmitter ();
- ce.Emit (ec, number_mg, number_args, loc);
- return;
- }
- Expr.Emit (ec);
- ec.Emit (OpCodes.Isinst, ProbeType.Type);
- ec.Emit (OpCodes.Dup);
- ec.Emit (OpCodes.Brfalse, no_match);
- if (number_mg != null) {
- var ce = new CallEmitter ();
- ce.Emit (ec, number_mg, number_args, loc);
- } else {
- ProbeType.Emit (ec);
- ec.Emit (OpCodes.Ceq);
- }
- ec.Emit (OpCodes.Br_S, end);
- ec.MarkLabel (no_match);
- ec.Emit (OpCodes.Pop);
- ec.EmitInt (0);
- ec.MarkLabel (end);
- }
- void EmitLoad (EmitContext ec)
- {
- Label no_value_label = new Label ();
- if (expr_unwrap != null) {
- expr_unwrap.EmitCheck (ec);
- if (Variable == null)
- return;
- ec.Emit (OpCodes.Dup);
- no_value_label = ec.DefineLabel ();
- ec.Emit (OpCodes.Brfalse_S, no_value_label);
- expr_unwrap.Emit (ec);
- } else {
- expr.Emit (ec);
- // Only to make verifier happy
- if (probe_type_expr.IsGenericParameter && TypeSpec.IsValueType (expr.Type))
- ec.Emit (OpCodes.Box, expr.Type);
- ec.Emit (OpCodes.Isinst, probe_type_expr);
- }
- if (Variable != null) {
- bool value_on_stack;
- if (probe_type_expr.IsGenericParameter || probe_type_expr.IsNullableType) {
- ec.Emit (OpCodes.Dup);
- ec.Emit (OpCodes.Unbox_Any, probe_type_expr);
- value_on_stack = true;
- } else {
- value_on_stack = false;
- }
- Variable.CreateBuilder (ec);
- Variable.EmitAssign (ec);
- if (expr_unwrap != null) {
- ec.MarkLabel (no_value_label);
- } else if (!value_on_stack) {
- Variable.Emit (ec);
- }
- }
- }
- protected override Expression DoResolve (ResolveContext rc)
- {
- if (ResolveCommon (rc) == null)
- return null;
- type = rc.BuiltinTypes.Bool;
- eclass = ExprClass.Value;
- if (probe_type_expr == null)
- return ResolveMatchingExpression (rc);
- var res = ResolveResultExpression (rc);
- if (Variable != null) {
- if (res is Constant)
- throw new NotImplementedException ("constant in type pattern matching");
- Variable.Type = probe_type_expr;
- var bc = rc as BlockContext;
- if (bc != null)
- Variable.PrepareAssignmentAnalysis (bc);
- }
- return res;
- }
- public override void FlowAnalysis (FlowAnalysisContext fc)
- {
- base.FlowAnalysis (fc);
- if (Variable != null)
- fc.SetVariableAssigned (Variable.VariableInfo, true);
- }
- protected override void ResolveProbeType (ResolveContext rc)
- {
- if (!(ProbeType is TypeExpr) && rc.Module.Compiler.Settings.Version == LanguageVersion.Experimental) {
- ProbeType = ProbeType.Resolve (rc, ResolveFlags.VariableOrValue | ResolveFlags.MethodGroup | ResolveFlags.Type);
- if (ProbeType == null)
- return;
- if (ProbeType.eclass == ExprClass.Type) {
- probe_type_expr = ProbeType.Type;
- }
- return;
- }
- base.ResolveProbeType (rc);
- }
- Expression ResolveMatchingExpression (ResolveContext rc)
- {
- var mc = ProbeType as Constant;
- if (mc != null) {
- if (!Convert.ImplicitConversionExists (rc, ProbeType, Expr.Type)) {
- ProbeType.Error_ValueCannotBeConverted (rc, Expr.Type, false);
- return null;
- }
- if (mc.IsNull)
- return new Binary (Binary.Operator.Equality, Expr, mc).Resolve (rc);
- var c = Expr as Constant;
- if (c != null) {
- c = ConstantFold.BinaryFold (rc, Binary.Operator.Equality, c, mc, loc);
- if (c != null)
- return c;
- }
- if (Expr.Type.IsNullableType) {
- expr_unwrap = new Nullable.Unwrap (Expr);
- expr_unwrap.Resolve (rc);
- } else if (ProbeType.Type.IsEnum || (ProbeType.Type.BuiltinType >= BuiltinTypeSpec.Type.Byte && ProbeType.Type.BuiltinType <= BuiltinTypeSpec.Type.Decimal)) {
- var helper = rc.Module.CreatePatterMatchingHelper ();
- number_mg = helper.NumberMatcher.Spec;
- //
- // There are actually 3 arguments but the first one is already on the stack
- //
- number_args = new Arguments (3);
- if (!ProbeType.Type.IsEnum)
- number_args.Add (new Argument (Expr));
- number_args.Add (new Argument (Convert.ImplicitConversion (rc, ProbeType, rc.BuiltinTypes.Object, loc)));
- number_args.Add (new Argument (new BoolLiteral (rc.BuiltinTypes, ProbeType.Type.IsEnum, loc)));
- }
- return this;
- }
- throw new NotImplementedException ();
- }
- Expression ResolveResultExpression (ResolveContext ec)
- {
- TypeSpec d = expr.Type;
- bool d_is_nullable = false;
- //
- // If E is a method group or the null literal, or if the type of E is a reference
- // type or a nullable type and the value of E is null, the result is false
- //
- if (expr.IsNull || expr.eclass == ExprClass.MethodGroup)
- return CreateConstantResult (ec, false);
- if (d.IsNullableType) {
- var ut = Nullable.NullableInfo.GetUnderlyingType (d);
- if (!ut.IsGenericParameter) {
- d = ut;
- d_is_nullable = true;
- }
- }
-
- TypeSpec t = probe_type_expr;
- bool t_is_nullable = false;
- if (t.IsNullableType) {
- var ut = Nullable.NullableInfo.GetUnderlyingType (t);
- if (!ut.IsGenericParameter) {
- t = ut;
- t_is_nullable = true;
- }
- }
- if (t.IsStruct) {
- if (d == t) {
- //
- // D and T are the same value types but D can be null
- //
- if (d_is_nullable && !t_is_nullable) {
- expr_unwrap = Nullable.Unwrap.Create (expr, true);
- return this;
- }
-
- //
- // The result is true if D and T are the same value types
- //
- return CreateConstantResult (ec, true);
- }
- var tp = d as TypeParameterSpec;
- if (tp != null)
- return ResolveGenericParameter (ec, t, tp);
- //
- // An unboxing conversion exists
- //
- if (Convert.ExplicitReferenceConversionExists (d, t))
- return this;
- //
- // open generic type
- //
- if (d is InflatedTypeSpec && InflatedTypeSpec.ContainsTypeParameter (d))
- return this;
- } else {
- var tps = t as TypeParameterSpec;
- if (tps != null)
- return ResolveGenericParameter (ec, d, tps);
- if (t.BuiltinType == BuiltinTypeSpec.Type.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.IsGenericParameter (d))
- return ResolveGenericParameter (ec, t, (TypeParameterSpec) d);
- if (TypeSpec.IsValueType (d)) {
- if (Convert.ImplicitBoxingConversion (null, d, t) != null) {
- if (d_is_nullable && !t_is_nullable) {
- expr_unwrap = Nullable.Unwrap.Create (expr, false);
- return this;
- }
- return CreateConstantResult (ec, true);
- }
- } else {
- if (Convert.ImplicitReferenceConversionExists (d, t)) {
- var c = expr as Constant;
- if (c != null)
- return CreateConstantResult (ec, !c.IsNull);
- //
- // Do not optimize for imported type or dynamic type
- //
- if (d.MemberDefinition.IsImported && d.BuiltinType != BuiltinTypeSpec.Type.None &&
- d.MemberDefinition.DeclaringAssembly != t.MemberDefinition.DeclaringAssembly) {
- return this;
- }
- if (d.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
- return this;
-
- //
- // Turn is check into simple null check for implicitly convertible reference types
- //
- return ReducedExpression.Create (
- new Binary (Binary.Operator.Inequality, expr, new NullLiteral (loc)).Resolve (ec),
- this).Resolve (ec);
- }
- if (Convert.ExplicitReferenceConversionExists (d, t))
- return this;
- //
- // open generic type
- //
- if ((d is InflatedTypeSpec || d.IsArray) && InflatedTypeSpec.ContainsTypeParameter (d))
- return this;
- }
- }
- return CreateConstantResult (ec, false);
- }
- Expression ResolveGenericParameter (ResolveContext ec, TypeSpec d, TypeParameterSpec t)
- {
- if (t.IsReferenceType) {
- if (d.IsStruct)
- return CreateConstantR…