Browse Source

Updated mcs.

newNRvisualizers
Mike Krüger 15 years ago
parent
commit
50f95d31ab
  1. 109
      ICSharpCode.NRefactory.CSharp/Parser/mcs/anonymous.cs
  2. 125
      ICSharpCode.NRefactory.CSharp/Parser/mcs/argument.cs
  3. 51
      ICSharpCode.NRefactory.CSharp/Parser/mcs/assign.cs
  4. 304
      ICSharpCode.NRefactory.CSharp/Parser/mcs/async.cs
  5. 39
      ICSharpCode.NRefactory.CSharp/Parser/mcs/attribute.cs
  6. 22
      ICSharpCode.NRefactory.CSharp/Parser/mcs/class.cs
  7. 486
      ICSharpCode.NRefactory.CSharp/Parser/mcs/codegen.cs
  8. 15
      ICSharpCode.NRefactory.CSharp/Parser/mcs/complete.cs
  9. 32
      ICSharpCode.NRefactory.CSharp/Parser/mcs/constant.cs
  10. 72
      ICSharpCode.NRefactory.CSharp/Parser/mcs/context.cs
  11. 3
      ICSharpCode.NRefactory.CSharp/Parser/mcs/convert.cs
  12. 9891
      ICSharpCode.NRefactory.CSharp/Parser/mcs/cs-parser.cs
  13. 117
      ICSharpCode.NRefactory.CSharp/Parser/mcs/cs-parser.jay
  14. 47
      ICSharpCode.NRefactory.CSharp/Parser/mcs/cs-tokenizer.cs
  15. 4
      ICSharpCode.NRefactory.CSharp/Parser/mcs/decl.cs
  16. 16
      ICSharpCode.NRefactory.CSharp/Parser/mcs/delegate.cs
  17. 19
      ICSharpCode.NRefactory.CSharp/Parser/mcs/dynamic.cs
  18. 499
      ICSharpCode.NRefactory.CSharp/Parser/mcs/ecore.cs
  19. 5
      ICSharpCode.NRefactory.CSharp/Parser/mcs/enum.cs
  20. 7
      ICSharpCode.NRefactory.CSharp/Parser/mcs/eval.cs
  21. 1059
      ICSharpCode.NRefactory.CSharp/Parser/mcs/expression.cs
  22. 108
      ICSharpCode.NRefactory.CSharp/Parser/mcs/flowanalysis.cs
  23. 34
      ICSharpCode.NRefactory.CSharp/Parser/mcs/generic.cs
  24. 27
      ICSharpCode.NRefactory.CSharp/Parser/mcs/import.cs
  25. 253
      ICSharpCode.NRefactory.CSharp/Parser/mcs/iterators.cs
  26. 6
      ICSharpCode.NRefactory.CSharp/Parser/mcs/lambda.cs
  27. 20
      ICSharpCode.NRefactory.CSharp/Parser/mcs/method.cs
  28. 50
      ICSharpCode.NRefactory.CSharp/Parser/mcs/namespace.cs
  29. 194
      ICSharpCode.NRefactory.CSharp/Parser/mcs/nullable.cs
  30. 32
      ICSharpCode.NRefactory.CSharp/Parser/mcs/parameter.cs
  31. 79
      ICSharpCode.NRefactory.CSharp/Parser/mcs/pending.cs
  32. 8
      ICSharpCode.NRefactory.CSharp/Parser/mcs/report.cs
  33. 2
      ICSharpCode.NRefactory.CSharp/Parser/mcs/roottypes.cs
  34. 297
      ICSharpCode.NRefactory.CSharp/Parser/mcs/statement.cs
  35. 2
      ICSharpCode.NRefactory.CSharp/Parser/mcs/support.cs
  36. 10
      ICSharpCode.NRefactory.CSharp/Parser/mcs/typemanager.cs
  37. 16
      ICSharpCode.NRefactory.CSharp/Parser/mcs/typespec.cs

109
ICSharpCode.NRefactory.CSharp/Parser/mcs/anonymous.cs

@ -193,7 +193,7 @@ namespace Mono.CSharp { @@ -193,7 +193,7 @@ namespace Mono.CSharp {
protected HoistedThis hoisted_this;
// Local variable which holds this storey instance
public LocalTemporary Instance;
public Expression Instance;
public AnonymousMethodStorey (Block block, TypeContainer parent, MemberBase host, TypeParameter[] tparams, string name)
: base (parent, MakeMemberName (host, name, unique_id, tparams, block.StartLocation),
@ -236,7 +236,12 @@ namespace Mono.CSharp { @@ -236,7 +236,12 @@ namespace Mono.CSharp {
protected Field AddCompilerGeneratedField (string name, FullNamedExpression type)
{
const Modifiers mod = Modifiers.INTERNAL | Modifiers.COMPILER_GENERATED;
return AddCompilerGeneratedField (name, type, false);
}
protected Field AddCompilerGeneratedField (string name, FullNamedExpression type, bool privateAccess)
{
Modifiers mod = Modifiers.COMPILER_GENERATED | (privateAccess ? Modifiers.PRIVATE : Modifiers.INTERNAL);
Field f = new Field (this, type, mod, new MemberName (name, Location), null);
AddField (f);
return f;
@ -391,21 +396,47 @@ namespace Mono.CSharp { @@ -391,21 +396,47 @@ namespace Mono.CSharp {
SymbolWriter.OpenCompilerGeneratedBlock (ec);
//
// Create an instance of a storey
// Create an instance of this storey
//
var storey_type_expr = CreateStoreyTypeExpression (ec);
ResolveContext rc = new ResolveContext (ec.MemberContext);
rc.CurrentBlock = block;
Expression e = new New (storey_type_expr, null, Location).Resolve (rc);
e.Emit (ec);
Instance = new LocalTemporary (storey_type_expr.Type);
Instance.Store (ec);
var storey_type_expr = CreateStoreyTypeExpression (ec);
var source = new New (storey_type_expr, null, Location).Resolve (rc);
//
// When the current context is async (or iterator) lift local storey
// instantiation to the currect storey
//
if (ec.CurrentAnonymousMethod is StateMachineInitializer) {
//
// Unfortunately, normal capture mechanism could not be used because we are
// too late in the pipeline and standart assign cannot be used either due to
// recursive nature of GetStoreyInstanceExpression
//
var field = ec.CurrentAnonymousMethod.Storey.AddCompilerGeneratedField (
LocalVariable.GetCompilerGeneratedName (block), storey_type_expr, true);
field.Define ();
field.Emit ();
var fexpr = new FieldExpr (field, Location);
fexpr.InstanceExpression = new CompilerGeneratedThis (ec.CurrentType, Location);
fexpr.EmitAssign (ec, source, false, false);
Instance = fexpr;
} else {
var local = TemporaryVariableReference.Create (source.Type, block, Location);
local.EmitAssign (ec, source);
Instance = local;
}
EmitHoistedFieldsInitialization (rc, ec);
SymbolWriter.DefineScopeVariable (ID, Instance.Builder);
// TODO: Implement properly
//SymbolWriter.DefineScopeVariable (ID, Instance.Builder);
SymbolWriter.CloseCompilerGeneratedBlock (ec);
}
@ -526,10 +557,11 @@ namespace Mono.CSharp { @@ -526,10 +557,11 @@ namespace Mono.CSharp {
if (f == null) {
if (am.Storey == this) {
//
// Access inside of same storey (S -> S)
// Access from inside of same storey (S -> S)
//
return new CompilerGeneratedThis (CurrentType, Location);
}
//
// External field access
//
@ -583,6 +615,11 @@ namespace Mono.CSharp { @@ -583,6 +615,11 @@ namespace Mono.CSharp {
this.hv = hv;
}
public override bool ContainsEmitWithAwait ()
{
return false;
}
public override Expression CreateExpressionTree (ResolveContext ec)
{
return hv.CreateExpressionTree ();
@ -637,6 +674,11 @@ namespace Mono.CSharp { @@ -637,6 +674,11 @@ namespace Mono.CSharp {
GetFieldExpression (ec).Emit (ec);
}
public Expression EmitToField (EmitContext ec)
{
return GetFieldExpression (ec);
}
//
// Creates field access expression for hoisted variable
//
@ -692,7 +734,7 @@ namespace Mono.CSharp { @@ -692,7 +734,7 @@ namespace Mono.CSharp {
GetFieldExpression (ec).Emit (ec, leave_copy);
}
public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
{
GetFieldExpression (ec).EmitAssign (ec, source, leave_copy, false);
}
@ -760,12 +802,20 @@ namespace Mono.CSharp { @@ -760,12 +802,20 @@ namespace Mono.CSharp {
{
readonly string name;
public HoistedLocalVariable (AnonymousMethodStorey scope, LocalVariable local, string name)
: base (scope, name, local.Type)
public HoistedLocalVariable (AnonymousMethodStorey storey, LocalVariable local, string name)
: base (storey, name, local.Type)
{
this.name = local.Name;
}
//
// For compiler generated local variables
//
public HoistedLocalVariable (AnonymousMethodStorey storey, Field field)
: base (storey, field)
{
}
public override void EmitSymbolInfo ()
{
SymbolWriter.DefineCapturedLocal (storey.ID, name, field.Name);
@ -1021,7 +1071,7 @@ namespace Mono.CSharp { @@ -1021,7 +1071,7 @@ namespace Mono.CSharp {
var body = CompatibleMethodBody (ec, tic, InternalType.Arglist, delegate_type);
if (body != null) {
if (is_async) {
AsyncInitializer.Create (body.Block, body.Parameters, ec.CurrentMemberDefinition.Parent, null, loc);
AsyncInitializer.Create (ec, body.Block, body.Parameters, ec.CurrentMemberDefinition.Parent, null, loc);
}
am = body.Compatible (ec, body, is_async);
@ -1037,6 +1087,11 @@ namespace Mono.CSharp { @@ -1037,6 +1087,11 @@ namespace Mono.CSharp {
return am.ReturnType;
}
public override bool ContainsEmitWithAwait ()
{
return false;
}
//
// Returns AnonymousMethod container if this anonymous method
// expression can be implicitly converted to the delegate type `delegate_type'
@ -1102,7 +1157,7 @@ namespace Mono.CSharp { @@ -1102,7 +1157,7 @@ namespace Mono.CSharp {
}
} else {
if (is_async) {
AsyncInitializer.Create (body.Block, body.Parameters, ec.CurrentMemberDefinition.Parent, body.ReturnType, loc);
AsyncInitializer.Create (ec, body.Block, body.Parameters, ec.CurrentMemberDefinition.Parent, body.ReturnType, loc);
}
am = body.Compatible (ec);
@ -1190,12 +1245,13 @@ namespace Mono.CSharp { @@ -1190,12 +1245,13 @@ namespace Mono.CSharp {
if (!DoResolveParameters (ec))
return null;
#if !STATIC
// FIXME: The emitted code isn't very careful about reachability
// so, ensure we have a 'ret' at the end
BlockContext bc = ec as BlockContext;
if (bc != null && bc.CurrentBranching != null && bc.CurrentBranching.CurrentUsageVector.IsUnreachable)
bc.NeedReturnLabel ();
#endif
return this;
}
@ -1280,11 +1336,6 @@ namespace Mono.CSharp { @@ -1280,11 +1336,6 @@ namespace Mono.CSharp {
{
EmitContext ec = new EmitContext (this, ig, ReturnType);
ec.CurrentAnonymousMethod = AnonymousMethod;
if (AnonymousMethod.return_label != null) {
ec.HasReturnLabel = true;
ec.ReturnLabel = (Label) AnonymousMethod.return_label;
}
return ec;
}
@ -1330,8 +1381,6 @@ namespace Mono.CSharp { @@ -1330,8 +1381,6 @@ namespace Mono.CSharp {
public TypeSpec ReturnType;
object return_label;
protected AnonymousExpression (ParametersBlock block, TypeSpec return_type, Location loc)
{
this.ReturnType = return_type;
@ -1380,9 +1429,6 @@ namespace Mono.CSharp { @@ -1380,9 +1429,6 @@ namespace Mono.CSharp {
bool res = Block.Resolve (ec.CurrentBranching, aec, null);
if (aec.HasReturnLabel)
return_label = aec.ReturnLabel;
if (am != null && am.ReturnTypeInference != null) {
am.ReturnTypeInference.FixAllTypes (ec);
ReturnType = am.ReturnTypeInference.InferredTypeArguments [0];
@ -1403,6 +1449,11 @@ namespace Mono.CSharp { @@ -1403,6 +1449,11 @@ namespace Mono.CSharp {
return res ? this : null;
}
public override bool ContainsEmitWithAwait ()
{
return false;
}
public void SetHasThisAccess ()
{
ExplicitBlock b = block;
@ -1629,13 +1680,13 @@ namespace Mono.CSharp { @@ -1629,13 +1680,13 @@ namespace Mono.CSharp {
//
if (is_static) {
ec.Emit (OpCodes.Ldnull);
ec.EmitNull ();
} else if (storey != null) {
Expression e = storey.GetStoreyInstanceExpression (ec).Resolve (new ResolveContext (ec.MemberContext));
if (e != null)
e.Emit (ec);
} else {
ec.Emit (OpCodes.Ldarg_0);
ec.EmitThis ();
}
var delegate_method = method.Spec;

125
ICSharpCode.NRefactory.CSharp/Parser/mcs/argument.cs

@ -103,6 +103,28 @@ namespace Mono.CSharp @@ -103,6 +103,28 @@ namespace Mono.CSharp
return Expr.CreateExpressionTree (ec);
}
public virtual void Emit (EmitContext ec)
{
if (!IsByRef) {
Expr.Emit (ec);
return;
}
AddressOp mode = AddressOp.Store;
if (ArgType == AType.Ref)
mode |= AddressOp.Load;
IMemoryLocation ml = (IMemoryLocation) Expr;
ml.AddressOf (ec, mode);
}
public Argument EmitToField (EmitContext ec)
{
var res = Expr.EmitToField (ec);
return res == Expr ? this : new Argument (res, ArgType);
}
public string GetSignatureForError ()
{
if (Expr.eclass == ExprClass.MethodGroup)
@ -141,21 +163,6 @@ namespace Mono.CSharp @@ -141,21 +163,6 @@ namespace Mono.CSharp
Expr = ErrorExpression.Instance;
// }
}
public virtual void Emit (EmitContext ec)
{
if (!IsByRef) {
Expr.Emit (ec);
return;
}
AddressOp mode = AddressOp.Store;
if (ArgType == AType.Ref)
mode |= AddressOp.Load;
IMemoryLocation ml = (IMemoryLocation) Expr;
ml.AddressOf (ec, mode);
}
}
public class MovableArgument : Argument
@ -182,12 +189,12 @@ namespace Mono.CSharp @@ -182,12 +189,12 @@ namespace Mono.CSharp
variable.Release (ec);
}
public void EmitAssign (EmitContext ec)
public void EmitToVariable (EmitContext ec)
{
var type = Expr.Type;
if (IsByRef) {
var ml = (IMemoryLocation) Expr;
ml.AddressOf (ec, AddressOp.Load);
ml.AddressOf (ec, AddressOp.LoadStore);
type = ReferenceContainer.MakeType (ec.Module, type);
} else {
Expr.Emit (ec);
@ -246,13 +253,16 @@ namespace Mono.CSharp @@ -246,13 +253,16 @@ namespace Mono.CSharp
ordered.Add (arg);
}
public override Expression[] Emit (EmitContext ec, bool dup_args)
public override Arguments Emit (EmitContext ec, bool dup_args, bool prepareAwait)
{
foreach (var a in ordered) {
a.EmitAssign (ec);
if (prepareAwait)
a.EmitToField (ec);
else
a.EmitToVariable (ec);
}
return base.Emit (ec, dup_args);
return base.Emit (ec, dup_args, prepareAwait);
}
}
@ -264,6 +274,11 @@ namespace Mono.CSharp @@ -264,6 +274,11 @@ namespace Mono.CSharp
args = new List<Argument> (capacity);
}
private Arguments (List<Argument> args)
{
this.args = args;
}
public void Add (Argument arg)
{
args.Add (arg);
@ -274,6 +289,16 @@ namespace Mono.CSharp @@ -274,6 +289,16 @@ namespace Mono.CSharp
this.args.AddRange (args.args);
}
public bool ContainsEmitWithAwait ()
{
foreach (var arg in args) {
if (arg.Expr.ContainsEmitWithAwait ())
return true;
}
return false;
}
public ArrayInitializer CreateDynamicBinderArguments (ResolveContext rc)
{
Location loc = Location.Null;
@ -395,46 +420,58 @@ namespace Mono.CSharp @@ -395,46 +420,58 @@ namespace Mono.CSharp
//
public void Emit (EmitContext ec)
{
Emit (ec, false);
Emit (ec, false, false);
}
//
// if `dup_args' is true, a copy of the arguments will be left
// on the stack and return value will contain an array of access
// expressions
// NOTE: It's caller responsibility is to release temporary variables
// if `dup_args' is true or any of arguments contains await.
// A copy of all arguments will be returned to the caller
//
public virtual Expression[] Emit (EmitContext ec, bool dup_args)
public virtual Arguments Emit (EmitContext ec, bool dup_args, bool prepareAwait)
{
Expression[] temps;
List<Argument> dups;
if (dup_args && Count != 0)
temps = new Expression [Count];
if ((dup_args && Count != 0) || prepareAwait)
dups = new List<Argument> (Count);
else
temps = null;
dups = null;
int i = 0;
LocalTemporary lt;
foreach (Argument a in args) {
if (prepareAwait) {
dups.Add (a.EmitToField (ec));
continue;
}
a.Emit (ec);
if (!dup_args)
if (!dup_args) {
continue;
}
if (a.Expr is Constant || a.Expr is This) {
if (a.Expr.IsSideEffectFree) {
//
// No need to create a temporary variable for constants
// No need to create a temporary variable for side effect free expressions. I assume
// all side-effect free expressions are cheap, this has to be tweaked when we become
// more aggressive on detection
//
temps[i] = a.Expr;
dups.Add (a);
} else {
ec.Emit (OpCodes.Dup);
temps[i] = lt = new LocalTemporary (a.Type);
// TODO: Release local temporary on next Emit
// Need to add a flag to argument to indicate this
lt = new LocalTemporary (a.Type);
lt.Store (ec);
}
++i;
dups.Add (new Argument (lt, a.ArgType));
}
}
return temps;
if (dups != null)
return new Arguments (dups);
return null;
}
public List<Argument>.Enumerator GetEnumerator ()
@ -497,9 +534,9 @@ namespace Mono.CSharp @@ -497,9 +534,9 @@ namespace Mono.CSharp
public Arguments MarkOrderedArgument (NamedArgument a)
{
//
// Constant expression have no effect on left-to-right execution
// An expression has no effect on left-to-right execution
//
if (a.Expr is Constant)
if (a.Expr.IsSideEffectFree)
return this;
ArgumentsOrdered ra = this as ArgumentsOrdered;
@ -511,6 +548,12 @@ namespace Mono.CSharp @@ -511,6 +548,12 @@ namespace Mono.CSharp
if (la == a)
break;
//
// When the argument is filled later by default expression
//
if (la == null)
continue;
var ma = la as MovableArgument;
if (ma == null) {
ma = new MovableArgument (la);

51
ICSharpCode.NRefactory.CSharp/Parser/mcs/assign.cs

@ -51,7 +51,7 @@ namespace Mono.CSharp { @@ -51,7 +51,7 @@ namespace Mono.CSharp {
// be data on the stack that it can use to compuatate its value. This is
// for expressions like a [f ()] ++, where you can't call `f ()' twice.
//
void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load);
void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
/*
For simple assignments, this interface is very simple, EmitAssign is called with source
@ -201,6 +201,11 @@ namespace Mono.CSharp { @@ -201,6 +201,11 @@ namespace Mono.CSharp {
builder = null;
}
public override bool ContainsEmitWithAwait ()
{
return false;
}
public override Expression CreateExpressionTree (ResolveContext ec)
{
Arguments args = new Arguments (1);
@ -236,9 +241,9 @@ namespace Mono.CSharp { @@ -236,9 +241,9 @@ namespace Mono.CSharp {
Emit (ec);
}
public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
{
if (prepare_for_load)
if (isCompound)
throw new NotImplementedException ();
source.Emit (ec);
@ -294,12 +299,6 @@ namespace Mono.CSharp { @@ -294,12 +299,6 @@ namespace Mono.CSharp {
this.loc = loc;
}
public override Expression CreateExpressionTree (ResolveContext ec)
{
ec.Report.Error (832, loc, "An expression tree cannot contain an assignment operator");
return null;
}
public Expression Target {
get { return target; }
}
@ -310,6 +309,17 @@ namespace Mono.CSharp { @@ -310,6 +309,17 @@ namespace Mono.CSharp {
}
}
public override bool ContainsEmitWithAwait ()
{
return target.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ();
}
public override Expression CreateExpressionTree (ResolveContext ec)
{
ec.Report.Error (832, loc, "An expression tree cannot contain an assignment operator");
return null;
}
protected override Expression DoResolve (ResolveContext ec)
{
bool ok = true;
@ -546,10 +556,6 @@ namespace Mono.CSharp { @@ -546,10 +556,6 @@ namespace Mono.CSharp {
base.EmitStatement (ec);
}
public bool IsComplexInitializer {
get { return !(source is Constant); }
}
public bool IsDefaultInitializer {
get {
Constant c = source as Constant;
@ -560,6 +566,12 @@ namespace Mono.CSharp { @@ -560,6 +566,12 @@ namespace Mono.CSharp {
return c.IsDefaultInitializer (fe.Type);
}
}
public override bool IsSideEffectFree {
get {
return source.IsSideEffectFree;
}
}
}
//
@ -570,13 +582,19 @@ namespace Mono.CSharp { @@ -570,13 +582,19 @@ namespace Mono.CSharp {
// This is just a hack implemented for arrays only
public sealed class TargetExpression : Expression
{
Expression child;
readonly Expression child;
public TargetExpression (Expression child)
{
this.child = child;
this.loc = child.Location;
}
public override bool ContainsEmitWithAwait ()
{
return child.ContainsEmitWithAwait ();
}
public override Expression CreateExpressionTree (ResolveContext ec)
{
throw new NotSupportedException ("ET");
@ -593,6 +611,11 @@ namespace Mono.CSharp { @@ -593,6 +611,11 @@ namespace Mono.CSharp {
{
child.Emit (ec);
}
public override Expression EmitToField (EmitContext ec)
{
return child.EmitToField (ec);
}
}
// Used for underlying binary operator

304
ICSharpCode.NRefactory.CSharp/Parser/mcs/async.cs

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
//
//
// async.cs: Asynchronous functions
//
// Author:
@ -7,11 +7,14 @@ @@ -7,11 +7,14 @@
// Dual licensed under the terms of the MIT X11 or GNU GPL
//
// Copyright 2011 Novell, Inc.
// Copyright 2011 Xamarin Inc.
//
using System;
using System.Collections.Generic;
using System.Linq;
using System.Collections;
#if STATIC
using IKVM.Reflection.Emit;
#else
@ -43,18 +46,13 @@ namespace Mono.CSharp @@ -43,18 +46,13 @@ namespace Mono.CSharp
throw new NotImplementedException ("ET");
}
protected override Expression DoResolve (ResolveContext rc)
public override bool ContainsEmitWithAwait ()
{
if (rc.HasSet (ResolveContext.Options.FinallyScope)) {
rc.Report.Error (1984, loc,
"The `await' operator cannot be used in the body of a finally clause");
}
if (rc.HasSet (ResolveContext.Options.CatchScope)) {
rc.Report.Error (1985, loc,
"The `await' operator cannot be used in the body of a catch clause");
}
return true;
}
protected override Expression DoResolve (ResolveContext rc)
{
if (rc.HasSet (ResolveContext.Options.LockScope)) {
rc.Report.Error (1996, loc,
"The `await' operator cannot be used in the body of a lock statement");
@ -92,7 +90,13 @@ namespace Mono.CSharp @@ -92,7 +90,13 @@ namespace Mono.CSharp
stmt.EmitPrologue (ec);
stmt.Emit (ec);
}
public override Expression EmitToField (EmitContext ec)
{
stmt.EmitPrologue (ec);
return stmt.GetResultExpression (ec);
}
public void EmitAssign (EmitContext ec, FieldExpr field)
{
stmt.EmitPrologue (ec);
@ -126,11 +130,27 @@ namespace Mono.CSharp @@ -126,11 +130,27 @@ namespace Mono.CSharp
}
}
sealed class GetResultInvocation : Invocation
{
public GetResultInvocation (MethodGroupExpr mge, Arguments arguments)
: base (null, arguments)
{
mg = mge;
type = mg.BestCandidateReturnType;
}
public override Expression EmitToField (EmitContext ec)
{
return this;
}
}
Field awaiter;
PropertyExpr is_completed;
PropertySpec is_completed;
MethodSpec on_completed;
MethodSpec get_result;
TypeSpec type;
TypeSpec result_type;
public AwaitStatement (Expression expr, Location loc)
: base (expr, loc)
@ -139,6 +159,12 @@ namespace Mono.CSharp @@ -139,6 +159,12 @@ namespace Mono.CSharp
#region Properties
bool IsDynamic {
get {
return is_completed == null;
}
}
public TypeSpec Type {
get {
return type;
@ -147,13 +173,18 @@ namespace Mono.CSharp @@ -147,13 +173,18 @@ namespace Mono.CSharp
public TypeSpec ResultType {
get {
return get_result.ReturnType;
return result_type;
}
}
#endregion
protected override void DoEmit (EmitContext ec)
{
GetResultExpression (ec).Emit (ec);
}
public Expression GetResultExpression (EmitContext ec)
{
var fe_awaiter = new FieldExpr (awaiter, loc);
fe_awaiter.InstanceExpression = new CompilerGeneratedThis (ec.CurrentType, loc);
@ -161,10 +192,15 @@ namespace Mono.CSharp @@ -161,10 +192,15 @@ namespace Mono.CSharp
//
// result = awaiter.GetResult ();
//
var mg_result = MethodGroupExpr.CreatePredefined (get_result, fe_awaiter.Type, loc);
mg_result.InstanceExpression = fe_awaiter;
if (IsDynamic) {
var rc = new ResolveContext (ec.MemberContext);
return new Invocation (new MemberAccess (fe_awaiter, "GetResult"), new Arguments (0)).Resolve (rc);
} else {
var mg_result = MethodGroupExpr.CreatePredefined (get_result, fe_awaiter.Type, loc);
mg_result.InstanceExpression = fe_awaiter;
mg_result.EmitCall (ec, new Arguments (0));
return new GetResultInvocation (mg_result, new Arguments (0));
}
}
public void EmitPrologue (EmitContext ec)
@ -177,11 +213,35 @@ namespace Mono.CSharp @@ -177,11 +213,35 @@ namespace Mono.CSharp
//
fe_awaiter.EmitAssign (ec, expr, false, false);
is_completed.InstanceExpression = fe_awaiter;
is_completed.EmitBranchable (ec, resume_point, true);
Label skip_continuation = ec.DefineLabel ();
var mg_completed = MethodGroupExpr.CreatePredefined (on_completed, fe_awaiter.Type, loc);
mg_completed.InstanceExpression = fe_awaiter;
Expression completed_expr;
if (IsDynamic) {
var rc = new ResolveContext (ec.MemberContext);
Arguments dargs = new Arguments (1);
dargs.Add (new Argument (fe_awaiter));
completed_expr = new DynamicMemberBinder ("IsCompleted", dargs, loc).Resolve (rc);
} else {
var pe = PropertyExpr.CreatePredefined (is_completed, loc);
pe.InstanceExpression = fe_awaiter;
completed_expr = pe;
}
completed_expr.EmitBranchable (ec, skip_continuation, true);
base.DoEmit (ec);
//
// The stack has to be empty before calling await continuation. We handle this
// by lifting values which would be left on stack into class fields. The process
// is quite complicated and quite hard to test because any expression can possibly
// leave a value on the stack.
//
// Following assert fails when some of expression called before is missing EmitToField
// or parent expression fails to find await in children expressions
//
ec.AssertEmptyStack ();
var args = new Arguments (1);
var storey = (AsyncTaskStorey) machine_initializer.Storey;
@ -190,12 +250,27 @@ namespace Mono.CSharp @@ -190,12 +250,27 @@ namespace Mono.CSharp
args.Add (new Argument (fe_cont));
//
// awaiter.OnCompleted (continuation);
//
mg_completed.EmitCall (ec, args);
if (IsDynamic) {
var rc = new ResolveContext (ec.MemberContext);
var mg_expr = new Invocation (new MemberAccess (fe_awaiter, "OnCompleted"), args).Resolve (rc);
base.DoEmit (ec);
ExpressionStatement es = (ExpressionStatement) mg_expr;
es.EmitStatement (ec);
} else {
var mg_completed = MethodGroupExpr.CreatePredefined (on_completed, fe_awaiter.Type, loc);
mg_completed.InstanceExpression = fe_awaiter;
//
// awaiter.OnCompleted (continuation);
//
mg_completed.EmitCall (ec, args);
}
// Return ok
machine_initializer.EmitLeave (ec, unwind_protect);
ec.MarkLabel (resume_point);
ec.MarkLabel (skip_continuation);
}
public void EmitStatement (EmitContext ec)
@ -231,13 +306,21 @@ namespace Mono.CSharp @@ -231,13 +306,21 @@ namespace Mono.CSharp
if (!base.Resolve (bc))
return false;
Arguments args = new Arguments (0);
type = expr.Type;
//
// The task result is of dynamic type
// The await expression is of dynamic type
//
if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
throw new NotImplementedException ("dynamic await");
if (type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
result_type = type;
awaiter = ((AsyncTaskStorey) machine_initializer.Storey).AddAwaiter (type, loc);
expr = new Invocation (new MemberAccess (expr, "GetAwaiter"), args).Resolve (bc);
return true;
}
//
// Check whether the expression is awaitable
@ -246,40 +329,28 @@ namespace Mono.CSharp @@ -246,40 +329,28 @@ namespace Mono.CSharp
if (ama == null)
return false;
Arguments args = new Arguments (0);
var errors_printer = new SessionReportPrinter ();
var old = bc.Report.SetPrinter (errors_printer);
ama = new Invocation (ama, args).Resolve (bc);
bc.Report.SetPrinter (old);
if (errors_printer.ErrorsCount > 0 || !MemberAccess.IsValidDotExpression (ama.Type)) {
bc.Report.SetPrinter (old);
Error_WrongGetAwaiter (bc, loc, expr.Type);
Error_WrongGetAwaiter (bc, expr.Location, expr.Type);
return false;
}
var awaiter_type = ama.Type;
awaiter = ((AsyncTaskStorey) machine_initializer.Storey).AddAwaiter (awaiter_type, loc);
expr = ama;
//
// Predefined: bool IsCompleted { get; }
//
var is_completed_ma = new MemberAccess (expr, "IsCompleted").Resolve (bc);
if (is_completed_ma != null) {
is_completed = is_completed_ma as PropertyExpr;
if (is_completed != null && is_completed.Type.BuiltinType == BuiltinTypeSpec.Type.Bool && is_completed.IsInstance && is_completed.Getter != null) {
// valid
} else {
bc.Report.SetPrinter (old);
Error_WrongAwaiterPattern (bc, awaiter_type);
return false;
}
}
bc.Report.SetPrinter (old);
is_completed = MemberCache.FindMember (awaiter_type, MemberFilter.Property ("IsCompleted", bc.Module.Compiler.BuiltinTypes.Bool),
BindingRestriction.InstanceOnly) as PropertySpec;
if (errors_printer.ErrorsCount > 0) {
if (is_completed == null || !is_completed.HasGet) {
Error_WrongAwaiterPattern (bc, awaiter_type);
return false;
}
@ -312,6 +383,8 @@ namespace Mono.CSharp @@ -312,6 +383,8 @@ namespace Mono.CSharp
return false;
}
result_type = get_result.ReturnType;
return true;
}
}
@ -353,7 +426,7 @@ namespace Mono.CSharp @@ -353,7 +426,7 @@ namespace Mono.CSharp
#endregion
public static void Create (ParametersBlock block, ParametersCompiled parameters, TypeContainer host, TypeSpec returnType, Location loc)
public static void Create (IMemberContext context, ParametersBlock block, ParametersCompiled parameters, TypeContainer host, TypeSpec returnType, Location loc)
{
if (returnType != null && returnType.Kind != MemberKind.Void &&
returnType != host.Module.PredefinedTypes.Task.TypeSpec &&
@ -385,11 +458,12 @@ namespace Mono.CSharp @@ -385,11 +458,12 @@ namespace Mono.CSharp
}
}
// TODO: Warning
//if (!block.HasAwait) {
//}
if (!block.IsAsync) {
host.Compiler.Report.Warning (1998, 1, loc,
"Async block lacks `await' operator and will run synchronously");
}
block.WrapIntoAsyncTask (host, returnType);
block.WrapIntoAsyncTask (context, host, returnType);
}
protected override BlockContext CreateBlockContext (ResolveContext rc)
@ -399,6 +473,7 @@ namespace Mono.CSharp @@ -399,6 +473,7 @@ namespace Mono.CSharp
if (lambda != null)
return_inference = lambda.ReturnTypeInference;
ctx.StartFlowBranching (this, rc.CurrentBranching);
return ctx;
}
@ -422,17 +497,31 @@ namespace Mono.CSharp @@ -422,17 +497,31 @@ namespace Mono.CSharp
{
var storey = (AsyncTaskStorey) Storey;
storey.Instance.Emit (ec);
ec.Emit (OpCodes.Call, storey.StateMachineMethod.Spec);
var move_next_entry = storey.StateMachineMethod.Spec;
if (storey.MemberName.Arity > 0) {
move_next_entry = MemberCache.GetMember (storey.Instance.Type, move_next_entry);
}
ec.Emit (OpCodes.Call, move_next_entry);
//
// Emits return <async-storey-instance>.$builder.Task;
//
if (storey.Task != null) {
//
// async.$builder.Task;
//
var builder_field = storey.Builder.Spec;
var task_get = storey.Task.Get;
if (storey.MemberName.Arity > 0) {
builder_field = MemberCache.GetMember (storey.Instance.Type, builder_field);
task_get = MemberCache.GetMember (builder_field.MemberType, task_get);
}
var pe_task = new PropertyExpr (storey.Task, loc) {
InstanceExpression = new FieldExpr (storey.Builder, loc) {
InstanceExpression = new FieldExpr (builder_field, loc) {
InstanceExpression = storey.Instance
},
Getter = storey.Task.Get
Getter = task_get
};
pe_task.Emit (ec);
@ -440,33 +529,60 @@ namespace Mono.CSharp @@ -440,33 +529,60 @@ namespace Mono.CSharp
ec.Emit (OpCodes.Ret);
}
public override void InjectYield (EmitContext ec, Expression expr, int resume_pc, bool unwind_protect, Label resume_point)
{
base.InjectYield (ec, expr, resume_pc, unwind_protect, resume_point);
}
}
class AsyncTaskStorey : StateMachine
{
sealed class ParametersLoadStatement : Statement
{
readonly FieldSpec[] fields;
readonly TypeSpec[] parametersTypes;
readonly int thisParameterIndex;
public ParametersLoadStatement (FieldSpec[] fields, TypeSpec[] parametersTypes, int thisParameterIndex)
{
this.fields = fields;
this.parametersTypes = parametersTypes;
this.thisParameterIndex = thisParameterIndex;
}
protected override void CloneTo (CloneContext clonectx, Statement target)
{
throw new NotImplementedException ();
}
protected override void DoEmit (EmitContext ec)
{
for (int i = 0; i < fields.Length; ++i) {
var field = fields[i];
if (field == null)
continue;
ec.EmitArgumentLoad (thisParameterIndex);
ec.EmitArgumentLoad (i);
if (parametersTypes[i] is ReferenceContainer)
ec.EmitLoadFromPtr (field.MemberType);
ec.Emit (OpCodes.Stfld, field);
}
}
}
int awaiters;
Field builder, continuation;
readonly TypeSpec return_type;
MethodSpec set_result;
MethodSpec set_exception;
PropertySpec task;
LocalVariable hoisted_return;
int locals_captured;
public AsyncTaskStorey (AsyncInitializer initializer, TypeSpec type)
: base (initializer.OriginalBlock, initializer.Host, null, null, "async")
public AsyncTaskStorey (IMemberContext context, AsyncInitializer initializer, TypeSpec type)
: base (initializer.OriginalBlock, initializer.Host,context.CurrentMemberDefinition as MemberBase, context.CurrentTypeParameters, "async")
{
return_type = type;
}
public Field AddAwaiter (TypeSpec type, Location loc)
{
return AddCompilerGeneratedField ("$awaiter" + awaiters++.ToString ("X"), new TypeExpression (type, loc));
}
#region Properties
public Field Builder {
@ -501,17 +617,34 @@ namespace Mono.CSharp @@ -501,17 +617,34 @@ namespace Mono.CSharp
#endregion
public Field AddAwaiter (TypeSpec type, Location loc)
{
return AddCompilerGeneratedField ("$awaiter" + awaiters++.ToString ("X"), new TypeExpression (type, loc), true);
}
public Field AddCapturedLocalVariable (TypeSpec type)
{
if (mutator != null)
type = mutator.Mutate (type);
var field = AddCompilerGeneratedField ("<s>$" + locals_captured++.ToString ("X"), new TypeExpression (type, Location), true);
field.Define ();
return field;
}
protected override bool DoDefineMembers ()
{
var action = Module.PredefinedTypes.Action.Resolve ();
if (action != null) {
continuation = AddCompilerGeneratedField ("$continuation", new TypeExpression (action, Location));
continuation = AddCompilerGeneratedField ("$continuation", new TypeExpression (action, Location), true);
continuation.ModFlags |= Modifiers.READONLY;
}
PredefinedType builder_type;
PredefinedMember<MethodSpec> bf;
PredefinedMember<MethodSpec> sr;
PredefinedMember<MethodSpec> se;
bool has_task_return_type = false;
var pred_members = Module.PredefinedMembers;
@ -519,32 +652,41 @@ namespace Mono.CSharp @@ -519,32 +652,41 @@ namespace Mono.CSharp
builder_type = Module.PredefinedTypes.AsyncVoidMethodBuilder;
bf = pred_members.AsyncVoidMethodBuilderCreate;
sr = pred_members.AsyncVoidMethodBuilderSetResult;
se = pred_members.AsyncVoidMethodBuilderSetException;
} else if (return_type == Module.PredefinedTypes.Task.TypeSpec) {
builder_type = Module.PredefinedTypes.AsyncTaskMethodBuilder;
bf = pred_members.AsyncTaskMethodBuilderCreate;
sr = pred_members.AsyncTaskMethodBuilderSetResult;
se = pred_members.AsyncTaskMethodBuilderSetException;
task = pred_members.AsyncTaskMethodBuilderTask.Resolve (Location);
} else {
builder_type = Module.PredefinedTypes.AsyncTaskMethodBuilderGeneric;
bf = pred_members.AsyncTaskMethodBuilderGenericCreate;
sr = pred_members.AsyncTaskMethodBuilderGenericSetResult;
se = pred_members.AsyncTaskMethodBuilderGenericSetException;
task = pred_members.AsyncTaskMethodBuilderGenericTask.Resolve (Location);
has_task_return_type = true;
}
set_result = sr.Resolve (Location);
set_exception = se.Resolve (Location);
var builder_factory = bf.Resolve (Location);
var bt = builder_type.Resolve ();
if (bt == null || set_result == null || builder_factory == null)
if (bt == null || set_result == null || builder_factory == null || set_exception == null)
return false;
//
// Inflate generic Task types
//
if (has_task_return_type) {
bt = bt.MakeGenericType (Module, return_type.TypeArguments);
var task_return_type = return_type.TypeArguments;
if (mutator != null)
task_return_type = mutator.Mutate (task_return_type);
bt = bt.MakeGenericType (Module, task_return_type);
builder_factory = MemberCache.GetMember<MethodSpec> (bt, builder_factory);
set_result = MemberCache.GetMember<MethodSpec> (bt, set_result);
set_exception = MemberCache.GetMember<MethodSpec> (bt, set_exception);
if (task != null)
task = MemberCache.GetMember<PropertySpec> (bt, task);
@ -589,6 +731,22 @@ namespace Mono.CSharp @@ -589,6 +731,22 @@ namespace Mono.CSharp
return true;
}
public void EmitSetException (EmitContext ec, LocalVariableReference exceptionVariable)
{
//
// $builder.SetException (Exception)
//
var mg = MethodGroupExpr.CreatePredefined (set_exception, set_exception.DeclaringType, Location);
mg.InstanceExpression = new FieldExpr (Builder, Location) {
InstanceExpression = new CompilerGeneratedThis (ec.CurrentType, Location)
};
Arguments args = new Arguments (1);
args.Add (new Argument (exceptionVariable));
mg.EmitCall (ec, args);
}
public void EmitSetResult (EmitContext ec)
{
//

39
ICSharpCode.NRefactory.CSharp/Parser/mcs/attribute.cs

@ -82,7 +82,7 @@ namespace Mono.CSharp { @@ -82,7 +82,7 @@ namespace Mono.CSharp {
public abstract string[] ValidAttributeTargets { get; }
};
public class Attribute : Expression
public class Attribute
{
public readonly string ExplicitTarget;
public AttributeTargets Target;
@ -94,6 +94,8 @@ namespace Mono.CSharp { @@ -94,6 +94,8 @@ namespace Mono.CSharp {
bool resolve_error;
bool arg_resolved;
readonly bool nameEscaped;
readonly Location loc;
public TypeSpec Type;
//
// An attribute can be attached to multiple targets (e.g. multiple fields)
@ -123,6 +125,12 @@ namespace Mono.CSharp { @@ -123,6 +125,12 @@ namespace Mono.CSharp {
this.nameEscaped = nameEscaped;
}
public Location Location {
get {
return loc;
}
}
void AddModuleCharSet (ResolveContext rc)
{
const string dll_import_char_set = "CharSet";
@ -326,7 +334,7 @@ namespace Mono.CSharp { @@ -326,7 +334,7 @@ namespace Mono.CSharp {
return Type;
}
public override string GetSignatureForError ()
public string GetSignatureForError ()
{
if (Type != null)
return TypeManager.CSharpName (Type);
@ -337,7 +345,7 @@ namespace Mono.CSharp { @@ -337,7 +345,7 @@ namespace Mono.CSharp {
public bool HasSecurityAttribute {
get {
PredefinedAttribute pa = context.Module.PredefinedAttributes.Security;
return pa.IsDefined && TypeSpec.IsBaseClass (type, pa.TypeSpec, false);
return pa.IsDefined && TypeSpec.IsBaseClass (Type, pa.TypeSpec, false);
}
}
@ -468,7 +476,7 @@ namespace Mono.CSharp { @@ -468,7 +476,7 @@ namespace Mono.CSharp {
}
}
return ConstructorLookup (ec, Type, ref PosArguments, loc);
return Expression.ConstructorLookup (ec, Type, ref PosArguments, loc);
}
bool ResolveNamedArguments (ResolveContext ec)
@ -489,10 +497,10 @@ namespace Mono.CSharp { @@ -489,10 +497,10 @@ namespace Mono.CSharp {
a.Resolve (ec);
Expression member = Expression.MemberLookup (ec, false, Type, name, 0, MemberLookupRestrictions.ExactArity, loc);
Expression member = Expression.MemberLookup (ec, false, Type, name, 0, Expression.MemberLookupRestrictions.ExactArity, loc);
if (member == null) {
member = Expression.MemberLookup (ec, true, Type, name, 0, MemberLookupRestrictions.ExactArity, loc);
member = Expression.MemberLookup (ec, true, Type, name, 0, Expression.MemberLookupRestrictions.ExactArity, loc);
if (member != null) {
// TODO: ec.Report.SymbolRelatedToPreviousError (member);
@ -680,7 +688,7 @@ namespace Mono.CSharp { @@ -680,7 +688,7 @@ namespace Mono.CSharp {
{
if (!arg_resolved) {
// corlib only case when obsolete is used before is resolved
var c = type.MemberDefinition as Class;
var c = Type.MemberDefinition as Class;
if (c != null && !c.HasMembersDefined)
c.Define ();
@ -919,7 +927,7 @@ namespace Mono.CSharp { @@ -919,7 +927,7 @@ namespace Mono.CSharp {
public override int GetHashCode ()
{
return type.GetHashCode () ^ Target.GetHashCode ();
return Type.GetHashCode () ^ Target.GetHashCode ();
}
/// <summary>
@ -1087,21 +1095,6 @@ namespace Mono.CSharp { @@ -1087,21 +1095,6 @@ namespace Mono.CSharp {
return null;
return e.TypeArgument;
}
public override Expression CreateExpressionTree (ResolveContext ec)
{
throw new NotSupportedException ("ET");
}
protected override Expression DoResolve (ResolveContext ec)
{
throw new NotImplementedException ();
}
public override void Emit (EmitContext ec)
{
throw new NotImplementedException ();
}
}
public class Attributes

22
ICSharpCode.NRefactory.CSharp/Parser/mcs/class.cs

@ -99,7 +99,7 @@ namespace Mono.CSharp @@ -99,7 +99,7 @@ namespace Mono.CSharp
return tc.GetSignatureForError ();
}
public IList<MethodSpec> LookupExtensionMethod (TypeSpec extensionType, string name, int arity, ref NamespaceContainer scope)
public ExtensionMethodCandidates LookupExtensionMethod (TypeSpec extensionType, string name, int arity)
{
return null;
}
@ -756,7 +756,7 @@ namespace Mono.CSharp @@ -756,7 +756,7 @@ namespace Mono.CSharp
ExpressionStatement s = fi.ResolveStatement (ec);
if (s == null) {
s = EmptyExpressionStatement.Instance;
} else if (fi.IsComplexInitializer) {
} else if (!fi.IsSideEffectFree) {
has_complex_initializer |= true;
}
@ -2455,18 +2455,19 @@ namespace Mono.CSharp @@ -2455,18 +2455,19 @@ namespace Mono.CSharp
}
}
public override IList<MethodSpec> LookupExtensionMethod (TypeSpec extensionType, string name, int arity, ref NamespaceContainer scope)
public override ExtensionMethodCandidates LookupExtensionMethod (TypeSpec extensionType, string name, int arity)
{
DeclSpace top_level = Parent;
if (top_level != null) {
var candidates = NamespaceEntry.NS.LookupExtensionMethod (this, extensionType, name, arity);
if (candidates != null) {
scope = NamespaceEntry;
return candidates;
var methods = NamespaceEntry.NS.LookupExtensionMethod (this, extensionType, name, arity);
if (methods != null) {
return new ExtensionMethodCandidates (methods, NamespaceEntry, NamespaceEntry.NS) {
HasUninspectedMembers = true
};
}
}
return NamespaceEntry.LookupExtensionMethod (extensionType, name, arity, ref scope);
return NamespaceEntry.LookupExtensionMethod (extensionType, name, arity);
}
protected override TypeAttributes TypeAttr {
@ -2805,7 +2806,10 @@ namespace Mono.CSharp @@ -2805,7 +2806,10 @@ namespace Mono.CSharp
}
}
if ((field.IsStatic && (!ftype.IsGeneric || ftype == CurrentType)))
//
// Static fields of exactly same type are allowed
//
if (field.IsStatic && ftype == s.CurrentType)
continue;
if (!CheckFieldTypeCycle (ftype)) {

486
ICSharpCode.NRefactory.CSharp/Parser/mcs/codegen.cs

@ -51,16 +51,6 @@ namespace Mono.CSharp @@ -51,16 +51,6 @@ namespace Mono.CSharp
/// </summary>
public LocalBuilder return_value;
/// <summary>
/// The location where return has to jump to return the
/// value
/// </summary>
public Label ReturnLabel;
/// <summary>
/// If we already defined the ReturnLabel
/// </summary>
public bool HasReturnLabel;
/// <summary>
/// Current loop begin and end labels.
@ -87,13 +77,17 @@ namespace Mono.CSharp @@ -87,13 +77,17 @@ namespace Mono.CSharp
DynamicSiteClass dynamic_site_container;
Label? return_label;
public EmitContext (IMemberContext rc, ILGenerator ig, TypeSpec return_type)
{
this.member_context = rc;
this.ig = ig;
this.return_type = return_type;
if (rc.Module.Compiler.Settings.Checked)
flags |= Options.CheckedScope;
#if STATIC
ig.__CleverExceptionBlockAssistance ();
#endif
@ -101,6 +95,12 @@ namespace Mono.CSharp @@ -101,6 +95,12 @@ namespace Mono.CSharp
#region Properties
internal AsyncTaskStorey AsyncTaskStorey {
get {
return CurrentAnonymousMethod.Storey as AsyncTaskStorey;
}
}
public BuiltinTypes BuiltinTypes {
get {
return MemberContext.Module.Compiler.BuiltinTypes;
@ -119,6 +119,12 @@ namespace Mono.CSharp @@ -119,6 +119,12 @@ namespace Mono.CSharp
get { return member_context.CurrentMemberDefinition; }
}
public bool HasReturnLabel {
get {
return return_label.HasValue;
}
}
public bool IsStatic {
get { return member_context.IsStatic; }
}
@ -156,8 +162,27 @@ namespace Mono.CSharp @@ -156,8 +162,27 @@ namespace Mono.CSharp
return return_type;
}
}
//
// The label where we have to jump before leaving the context
//
public Label ReturnLabel {
get {
return return_label.Value;
}
}
#endregion
public void AssertEmptyStack ()
{
#if STATIC
if (ig.__StackHeight != 0)
throw new InternalErrorException ("Await yields with non-empty stack in `{0}",
member_context.GetSignatureForError ());
#endif
}
/// <summary>
/// This is called immediately before emitting an IL opcode to tell the symbol
/// writer to which source line this opcode belongs.
@ -228,6 +253,14 @@ namespace Mono.CSharp @@ -228,6 +253,14 @@ namespace Mono.CSharp
return dynamic_site_container;
}
public Label CreateReturnLabel ()
{
if (!return_label.HasValue)
return_label = DefineLabel ();
return return_label.Value;
}
public LocalBuilder DeclareLocal (TypeSpec type, bool pinned)
{
if (IsAnonymousStoreyMutateRequired)
@ -241,6 +274,17 @@ namespace Mono.CSharp @@ -241,6 +274,17 @@ namespace Mono.CSharp
return ig.DefineLabel ();
}
//
// Creates temporary field in current async storey
//
public FieldExpr GetTemporaryField (TypeSpec type)
{
var f = AsyncTaskStorey.AddCapturedLocalVariable (type);
var fexpr = new FieldExpr (f, Location.Null);
fexpr.InstanceExpression = new CompilerGeneratedThis (CurrentType, Location.Null);
return fexpr;
}
public void MarkLabel (Label label)
{
ig.MarkLabel (label);
@ -271,16 +315,6 @@ namespace Mono.CSharp @@ -271,16 +315,6 @@ namespace Mono.CSharp
ig.Emit (opcode, arg);
}
public void Emit (OpCode opcode, int arg)
{
ig.Emit (opcode, arg);
}
public void Emit (OpCode opcode, byte arg)
{
ig.Emit (opcode, arg);
}
public void Emit (OpCode opcode, Label label)
{
ig.Emit (opcode, label);
@ -333,7 +367,11 @@ namespace Mono.CSharp @@ -333,7 +367,11 @@ namespace Mono.CSharp
public void EmitArrayNew (ArrayContainer ac)
{
if (ac.Rank == 1) {
Emit (OpCodes.Newarr, ac.Element);
var type = IsAnonymousStoreyMutateRequired ?
CurrentAnonymousMethod.Storey.Mutator.Mutate (ac.Element) :
ac.Element;
ig.Emit (OpCodes.Newarr, type.GetMetaInfo ());
} else {
if (IsAnonymousStoreyMutateRequired)
ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
@ -350,7 +388,11 @@ namespace Mono.CSharp @@ -350,7 +388,11 @@ namespace Mono.CSharp
ig.Emit (OpCodes.Call, ac.GetAddressMethod ());
} else {
Emit (OpCodes.Ldelema, ac.Element);
var type = IsAnonymousStoreyMutateRequired ?
CurrentAnonymousMethod.Storey.Mutator.Mutate (ac.Element) :
ac.Element;
ig.Emit (OpCodes.Ldelema, type.GetMetaInfo ());
}
}
@ -367,6 +409,7 @@ namespace Mono.CSharp @@ -367,6 +409,7 @@ namespace Mono.CSharp
return;
}
var type = ac.Element;
if (type.Kind == MemberKind.Enum)
type = EnumSpec.GetUnderlyingType (type);
@ -374,52 +417,59 @@ namespace Mono.CSharp @@ -374,52 +417,59 @@ namespace Mono.CSharp
switch (type.BuiltinType) {
case BuiltinTypeSpec.Type.Byte:
case BuiltinTypeSpec.Type.Bool:
Emit (OpCodes.Ldelem_U1);
return;
ig.Emit (OpCodes.Ldelem_U1);
break;
case BuiltinTypeSpec.Type.SByte:
Emit (OpCodes.Ldelem_I1);
return;
ig.Emit (OpCodes.Ldelem_I1);
break;
case BuiltinTypeSpec.Type.Short:
Emit (OpCodes.Ldelem_I2);
return;
ig.Emit (OpCodes.Ldelem_I2);
break;
case BuiltinTypeSpec.Type.UShort:
case BuiltinTypeSpec.Type.Char:
Emit (OpCodes.Ldelem_U2);
return;
ig.Emit (OpCodes.Ldelem_U2);
break;
case BuiltinTypeSpec.Type.Int:
Emit (OpCodes.Ldelem_I4);
return;
ig.Emit (OpCodes.Ldelem_I4);
break;
case BuiltinTypeSpec.Type.UInt:
Emit (OpCodes.Ldelem_U4);
return;
ig.Emit (OpCodes.Ldelem_U4);
break;
case BuiltinTypeSpec.Type.ULong:
case BuiltinTypeSpec.Type.Long:
Emit (OpCodes.Ldelem_I8);
return;
ig.Emit (OpCodes.Ldelem_I8);
break;
case BuiltinTypeSpec.Type.Float:
Emit (OpCodes.Ldelem_R4);
return;
case BuiltinTypeSpec.Type.Double:
Emit (OpCodes.Ldelem_R8);
return;
case BuiltinTypeSpec.Type.IntPtr:
Emit (OpCodes.Ldelem_I);
return;
}
switch (type.Kind) {
case MemberKind.Struct:
Emit (OpCodes.Ldelema, type);
Emit (OpCodes.Ldobj, type);
ig.Emit (OpCodes.Ldelem_R4);
break;
case MemberKind.TypeParameter:
Emit (OpCodes.Ldelem, type);
case BuiltinTypeSpec.Type.Double:
ig.Emit (OpCodes.Ldelem_R8);
break;
case MemberKind.PointerType:
Emit (OpCodes.Ldelem_I);
case BuiltinTypeSpec.Type.IntPtr:
ig.Emit (OpCodes.Ldelem_I);
break;
default:
Emit (OpCodes.Ldelem_Ref);
switch (type.Kind) {
case MemberKind.Struct:
if (IsAnonymousStoreyMutateRequired)
type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
ig.Emit (OpCodes.Ldelema, type.GetMetaInfo ());
ig.Emit (OpCodes.Ldobj, type.GetMetaInfo ());
break;
case MemberKind.TypeParameter:
if (IsAnonymousStoreyMutateRequired)
type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
ig.Emit (OpCodes.Ldelem, type.GetMetaInfo ());
break;
case MemberKind.PointerType:
ig.Emit (OpCodes.Ldelem_I);
break;
default:
ig.Emit (OpCodes.Ldelem_Ref);
break;
}
break;
}
}
@ -486,6 +536,11 @@ namespace Mono.CSharp @@ -486,6 +536,11 @@ namespace Mono.CSharp
}
public void EmitInt (int i)
{
EmitIntConstant (i);
}
void EmitIntConstant (int i)
{
switch (i) {
case -1:
@ -540,18 +595,14 @@ namespace Mono.CSharp @@ -540,18 +595,14 @@ namespace Mono.CSharp
public void EmitLong (long l)
{
if (l >= int.MinValue && l <= int.MaxValue) {
EmitInt (unchecked ((int) l));
EmitIntConstant (unchecked ((int) l));
ig.Emit (OpCodes.Conv_I8);
return;
}
if (l >= 0 && l <= uint.MaxValue) {
EmitInt (unchecked ((int) l));
} else if (l >= 0 && l <= uint.MaxValue) {
EmitIntConstant (unchecked ((int) l));
ig.Emit (OpCodes.Conv_U8);
return;
} else {
ig.Emit (OpCodes.Ldc_I8, l);
}
ig.Emit (OpCodes.Ldc_I8, l);
}
//
@ -565,53 +616,103 @@ namespace Mono.CSharp @@ -565,53 +616,103 @@ namespace Mono.CSharp
switch (type.BuiltinType) {
case BuiltinTypeSpec.Type.Int:
ig.Emit (OpCodes.Ldind_I4);
return;
break;
case BuiltinTypeSpec.Type.UInt:
ig.Emit (OpCodes.Ldind_U4);
return;
break;
case BuiltinTypeSpec.Type.Short:
ig.Emit (OpCodes.Ldind_I2);
return;
break;
case BuiltinTypeSpec.Type.UShort:
case BuiltinTypeSpec.Type.Char:
ig.Emit (OpCodes.Ldind_U2);
return;
break;
case BuiltinTypeSpec.Type.Byte:
ig.Emit (OpCodes.Ldind_U1);
return;
break;
case BuiltinTypeSpec.Type.SByte:
case BuiltinTypeSpec.Type.Bool:
ig.Emit (OpCodes.Ldind_I1);
return;
break;
case BuiltinTypeSpec.Type.ULong:
case BuiltinTypeSpec.Type.Long:
ig.Emit (OpCodes.Ldind_I8);
return;
break;
case BuiltinTypeSpec.Type.Float:
ig.Emit (OpCodes.Ldind_R4);
return;
break;
case BuiltinTypeSpec.Type.Double:
ig.Emit (OpCodes.Ldind_R8);
return;
break;
case BuiltinTypeSpec.Type.IntPtr:
ig.Emit (OpCodes.Ldind_I);
return;
}
switch (type.Kind) {
case MemberKind.Struct:
case MemberKind.TypeParameter:
Emit (OpCodes.Ldobj, type);
break;
case MemberKind.PointerType:
ig.Emit (OpCodes.Ldind_I);
default:
switch (type.Kind) {
case MemberKind.Struct:
case MemberKind.TypeParameter:
if (IsAnonymousStoreyMutateRequired)
type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
ig.Emit (OpCodes.Ldobj, type.GetMetaInfo ());
break;
case MemberKind.PointerType:
ig.Emit (OpCodes.Ldind_I);
break;
default:
ig.Emit (OpCodes.Ldind_Ref);
break;
}
break;
}
}
public void EmitNull ()
{
ig.Emit (OpCodes.Ldnull);
}
public void EmitArgumentAddress (int pos)
{
if (!IsStatic)
++pos;
if (pos > byte.MaxValue)
ig.Emit (OpCodes.Ldarga, pos);
else
ig.Emit (OpCodes.Ldarga_S, (byte) pos);
}
public void EmitArgumentLoad (int pos)
{
if (!IsStatic)
++pos;
switch (pos) {
case 0: ig.Emit (OpCodes.Ldarg_0); break;
case 1: ig.Emit (OpCodes.Ldarg_1); break;
case 2: ig.Emit (OpCodes.Ldarg_2); break;
case 3: ig.Emit (OpCodes.Ldarg_3); break;
default:
ig.Emit (OpCodes.Ldind_Ref);
if (pos > byte.MaxValue)
ig.Emit (OpCodes.Ldarg, pos);
else
ig.Emit (OpCodes.Ldarg_S, (byte) pos);
break;
}
}
public void EmitArgumentStore (int pos)
{
if (!IsStatic)
++pos;
if (pos > byte.MaxValue)
ig.Emit (OpCodes.Starg, pos);
else
ig.Emit (OpCodes.Starg_S, (byte) pos);
}
//
// The stack contains the pointer and the value of type `type'
//
@ -650,10 +751,23 @@ namespace Mono.CSharp @@ -650,10 +751,23 @@ namespace Mono.CSharp
return;
}
if (type.IsStruct || TypeManager.IsGenericParameter (type))
Emit (OpCodes.Stobj, type);
else
switch (type.Kind) {
case MemberKind.Struct:
case MemberKind.TypeParameter:
if (IsAnonymousStoreyMutateRequired)
type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
ig.Emit (OpCodes.Stobj, type.GetMetaInfo ());
break;
default:
ig.Emit (OpCodes.Stind_Ref);
break;
}
}
public void EmitThis ()
{
ig.Emit (OpCodes.Ldarg_0);
}
/// <summary>
@ -716,13 +830,203 @@ namespace Mono.CSharp @@ -716,13 +830,203 @@ namespace Mono.CSharp
{
if (return_value == null){
return_value = DeclareLocal (return_type, false);
if (!HasReturnLabel){
ReturnLabel = DefineLabel ();
HasReturnLabel = true;
}
}
return return_value;
}
}
struct CallEmitter
{
public Expression InstanceExpression;
//
// When set leaves an extra copy of all arguments on the stack
//
public bool DuplicateArguments;
//
// Does not emit InstanceExpression load when InstanceExpressionOnStack
// is set. Used by compound assignments.
//
public bool InstanceExpressionOnStack;
//
// Any of arguments contains await expression
//
public bool HasAwaitArguments;
//
// When dealing with await arguments the original arguments are converted
// into a new set with hoisted stack results
//
public Arguments EmittedArguments;
public void Emit (EmitContext ec, MethodSpec method, Arguments Arguments, Location loc)
{
// Speed up the check by not doing it on not allowed targets
if (method.ReturnType.Kind == MemberKind.Void && method.IsConditionallyExcluded (ec.Module.Compiler, loc))
return;
EmitPredefined (ec, method, Arguments);
}
public void EmitPredefined (EmitContext ec, MethodSpec method, Arguments Arguments)
{
Expression instance_copy = null;
if (!HasAwaitArguments && ec.HasSet (BuilderContext.Options.AsyncBody)) {
HasAwaitArguments = Arguments != null && Arguments.ContainsEmitWithAwait ();
if (HasAwaitArguments && InstanceExpressionOnStack) {
throw new NotSupportedException ();
}
}
OpCode call_op;
LocalTemporary lt = null;
if (method.IsStatic) {
call_op = OpCodes.Call;
} else {
if (IsVirtualCallRequired (InstanceExpression, method)) {
call_op = OpCodes.Callvirt;
} else {
call_op = OpCodes.Call;
}
if (HasAwaitArguments) {
instance_copy = InstanceExpression.EmitToField (ec);
if (Arguments == null)
EmitCallInstance (ec, instance_copy, method.DeclaringType, call_op);
} else if (!InstanceExpressionOnStack) {
var instance_on_stack_type = EmitCallInstance (ec, InstanceExpression, method.DeclaringType, call_op);
if (DuplicateArguments) {
ec.Emit (OpCodes.Dup);
if (Arguments != null && Arguments.Count != 0) {
lt = new LocalTemporary (instance_on_stack_type);
lt.Store (ec);
instance_copy = lt;
}
}
}
}
if (Arguments != null && !InstanceExpressionOnStack) {
EmittedArguments = Arguments.Emit (ec, DuplicateArguments, HasAwaitArguments);
if (EmittedArguments != null) {
if (instance_copy != null) {
EmitCallInstance (ec, instance_copy, method.DeclaringType, call_op);
if (lt != null)
lt.Release (ec);
}
EmittedArguments.Emit (ec);
}
}
if (call_op == OpCodes.Callvirt && (InstanceExpression.Type.IsGenericParameter || InstanceExpression.Type.IsStruct)) {
ec.Emit (OpCodes.Constrained, InstanceExpression.Type);
}
//
// Set instance expression to actual result expression. When it contains await it can be
// picked up by caller
//
InstanceExpression = instance_copy;
if (method.Parameters.HasArglist) {
var varargs_types = GetVarargsTypes (method, Arguments);
ec.Emit (call_op, method, varargs_types);
return;
}
//
// If you have:
// this.DoFoo ();
// and DoFoo is not virtual, you can omit the callvirt,
// because you don't need the null checking behavior.
//
ec.Emit (call_op, method);
}
static TypeSpec EmitCallInstance (EmitContext ec, Expression instance, TypeSpec declaringType, OpCode callOpcode)
{
var instance_type = instance.Type;
//
// Push the instance expression
//
if ((instance_type.IsStruct && (callOpcode == OpCodes.Callvirt || (callOpcode == OpCodes.Call && declaringType == instance_type))) ||
instance_type.IsGenericParameter || declaringType.IsNullableType) {
//
// If the expression implements IMemoryLocation, then
// we can optimize and use AddressOf on the
// return.
//
// If not we have to use some temporary storage for
// it.
var iml = instance as IMemoryLocation;
if (iml != null) {
iml.AddressOf (ec, AddressOp.Load);
} else {
LocalTemporary temp = new LocalTemporary (instance_type);
instance.Emit (ec);
temp.Store (ec);
temp.AddressOf (ec, AddressOp.Load);
temp.Release (ec);
}
return ReferenceContainer.MakeType (ec.Module, instance_type);
}
if (instance_type.IsEnum || instance_type.IsStruct) {
instance.Emit (ec);
ec.Emit (OpCodes.Box, instance_type);
return ec.BuiltinTypes.Object;
}
instance.Emit (ec);
return instance_type;
}
static MetaType[] GetVarargsTypes (MethodSpec method, Arguments arguments)
{
AParametersCollection pd = method.Parameters;
Argument a = arguments[pd.Count - 1];
Arglist list = (Arglist) a.Expr;
return list.ArgumentTypes;
}
//
// Used to decide whether call or callvirt is needed
//
static bool IsVirtualCallRequired (Expression instance, MethodSpec method)
{
//
// 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;
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))
return false;
return true;
}
}
}

15
ICSharpCode.NRefactory.CSharp/Parser/mcs/complete.cs

@ -43,19 +43,24 @@ namespace Mono.CSharp { @@ -43,19 +43,24 @@ namespace Mono.CSharp {
}
}
public override void EmitStatement (EmitContext ec)
public override bool ContainsEmitWithAwait ()
{
// Do nothing
return false;
}
public override void Emit (EmitContext ec)
public override Expression CreateExpressionTree (ResolveContext ec)
{
return null;
}
public override void EmitStatement (EmitContext ec)
{
// Do nothing
}
public override Expression CreateExpressionTree (ResolveContext ec)
public override void Emit (EmitContext ec)
{
return null;
// Do nothing
}
}

32
ICSharpCode.NRefactory.CSharp/Parser/mcs/constant.cs

@ -78,6 +78,11 @@ namespace Mono.CSharp { @@ -78,6 +78,11 @@ namespace Mono.CSharp {
return c;
}
public override bool ContainsEmitWithAwait ()
{
return false;
}
public virtual Constant ConvertImplicitly (TypeSpec type)
{
if (this.type == type)
@ -309,7 +314,13 @@ namespace Mono.CSharp { @@ -309,7 +314,13 @@ namespace Mono.CSharp {
public virtual bool IsOneInteger {
get { return false; }
}
}
public override bool IsSideEffectFree {
get {
return true;
}
}
//
// Returns true iff 1) the stack type of this is one of Object,
@ -427,9 +438,9 @@ namespace Mono.CSharp { @@ -427,9 +438,9 @@ namespace Mono.CSharp {
public override void Emit (EmitContext ec)
{
if (Value)
ec.Emit (OpCodes.Ldc_I4_1);
ec.EmitInt (1);
else
ec.Emit (OpCodes.Ldc_I4_0);
ec.EmitInt (0);
}
public override bool IsDefaultValue {
@ -1945,7 +1956,7 @@ namespace Mono.CSharp { @@ -1945,7 +1956,7 @@ namespace Mono.CSharp {
public override void Emit (EmitContext ec)
{
if (Value == null) {
ec.Emit (OpCodes.Ldnull);
ec.EmitNull ();
return;
}
@ -2050,7 +2061,7 @@ namespace Mono.CSharp { @@ -2050,7 +2061,7 @@ namespace Mono.CSharp {
public override void Emit (EmitContext ec)
{
ec.Emit (OpCodes.Ldnull);
ec.EmitNull ();
// Only to make verifier happy
if (type.IsGenericParameter)
@ -2152,7 +2163,7 @@ namespace Mono.CSharp { @@ -2152,7 +2163,7 @@ namespace Mono.CSharp {
//
// Emits null pointer
//
ec.Emit (OpCodes.Ldc_I4_0);
ec.EmitInt (0);
ec.Emit (OpCodes.Conv_U);
}
}
@ -2162,7 +2173,8 @@ namespace Mono.CSharp { @@ -2162,7 +2173,8 @@ namespace Mono.CSharp {
/// used by BitwiseAnd to ensure that the second expression is invoked
/// regardless of the value of the left side.
/// </summary>
public class SideEffectConstant : Constant {
public class SideEffectConstant : Constant
{
public readonly Constant value;
Expression side_effect;
@ -2178,6 +2190,12 @@ namespace Mono.CSharp { @@ -2178,6 +2190,12 @@ namespace Mono.CSharp {
this.side_effect = side_effect;
}
public override bool IsSideEffectFree {
get {
return false;
}
}
public override object GetValue ()
{
return value.GetValue ();

72
ICSharpCode.NRefactory.CSharp/Parser/mcs/context.cs

@ -7,18 +7,13 @@ @@ -7,18 +7,13 @@
//
// Copyright 2001, 2002, 2003 Ximian, Inc.
// Copyright 2004-2009 Novell, Inc.
// Copyright 2011 Xamarin Inc.
//
using System;
using System.Collections.Generic;
using System.IO;
#if STATIC
using IKVM.Reflection.Emit;
#else
using System.Reflection.Emit;
#endif
namespace Mono.CSharp
{
public enum LookupMode
@ -58,7 +53,7 @@ namespace Mono.CSharp @@ -58,7 +53,7 @@ namespace Mono.CSharp
string GetSignatureForError ();
IList<MethodSpec> LookupExtensionMethod (TypeSpec extensionType, string name, int arity, ref NamespaceContainer scope);
ExtensionMethodCandidates LookupExtensionMethod (TypeSpec extensionType, string name, int arity);
FullNamedExpression LookupNamespaceOrType (string name, int arity, LookupMode mode, Location loc);
FullNamedExpression LookupNamespaceAlias (string name);
}
@ -75,18 +70,7 @@ namespace Mono.CSharp @@ -75,18 +70,7 @@ namespace Mono.CSharp
{
FlowBranching current_flow_branching;
TypeSpec return_type;
/// <summary>
/// The location where return has to jump to return the
/// value
/// </summary>
public Label ReturnLabel; // TODO: It's emit dependant
/// <summary>
/// If we already defined the ReturnLabel
/// </summary>
public bool HasReturnLabel;
readonly TypeSpec return_type;
public int FlowOffset;
@ -116,6 +100,10 @@ namespace Mono.CSharp @@ -116,6 +100,10 @@ namespace Mono.CSharp
get { return current_flow_branching; }
}
public TypeSpec ReturnType {
get { return return_type; }
}
// <summary>
// Starts a new code branching. This inherits the state of all local
// variables and parameters from the current branching.
@ -145,9 +133,9 @@ namespace Mono.CSharp @@ -145,9 +133,9 @@ namespace Mono.CSharp
return branching;
}
public FlowBranchingException StartFlowBranching (ExceptionStatement stmt)
public FlowBranchingTryFinally StartFlowBranching (TryFinallyBlock stmt)
{
FlowBranchingException branching = new FlowBranchingException (CurrentBranching, stmt);
FlowBranchingTryFinally branching = new FlowBranchingTryFinally (CurrentBranching, stmt);
current_flow_branching = branching;
return branching;
}
@ -159,13 +147,20 @@ namespace Mono.CSharp @@ -159,13 +147,20 @@ namespace Mono.CSharp
return branching;
}
public FlowBranchingIterator StartFlowBranching (StateMachineInitializer iterator, FlowBranching parent)
public FlowBranchingIterator StartFlowBranching (Iterator iterator, FlowBranching parent)
{
FlowBranchingIterator branching = new FlowBranchingIterator (parent, iterator);
current_flow_branching = branching;
return branching;
}
public FlowBranchingAsync StartFlowBranching (AsyncInitializer asyncBody, FlowBranching parent)
{
var branching = new FlowBranchingAsync (parent, asyncBody);
current_flow_branching = branching;
return branching;
}
public FlowBranchingToplevel StartFlowBranching (ParametersBlock stmt, FlowBranching parent)
{
FlowBranchingToplevel branching = new FlowBranchingToplevel (parent, stmt);
@ -196,19 +191,11 @@ namespace Mono.CSharp @@ -196,19 +191,11 @@ namespace Mono.CSharp
current_flow_branching = current_flow_branching.Parent;
}
//
// This method is used during the Resolution phase to flag the
// need to define the ReturnLabel
//
#if !STATIC
public void NeedReturnLabel ()
{
if (!HasReturnLabel)
HasReturnLabel = true;
}
public TypeSpec ReturnType {
get { return return_type; }
}
#endif
}
//
@ -484,7 +471,7 @@ namespace Mono.CSharp @@ -484,7 +471,7 @@ namespace Mono.CSharp
// FIXME: IsIterator is too aggressive, we should capture only if child
// block contains yield
if (CurrentAnonymousMethod.IsIterator)
if (CurrentAnonymousMethod.IsIterator || CurrentAnonymousMethod is AsyncInitializer)
return true;
return local.Block.ParametersBlock != CurrentBlock.ParametersBlock.Original;
@ -519,9 +506,9 @@ namespace Mono.CSharp @@ -519,9 +506,9 @@ namespace Mono.CSharp
return MemberContext.GetSignatureForError ();
}
public IList<MethodSpec> LookupExtensionMethod (TypeSpec extensionType, string name, int arity, ref NamespaceContainer scope)
public ExtensionMethodCandidates LookupExtensionMethod (TypeSpec extensionType, string name, int arity)
{
return MemberContext.LookupExtensionMethod (extensionType, name, arity, ref scope);
return MemberContext.LookupExtensionMethod (extensionType, name, arity);
}
public FullNamedExpression LookupNamespaceOrType (string name, int arity, LookupMode mode, Location loc)
@ -685,18 +672,11 @@ namespace Mono.CSharp @@ -685,18 +672,11 @@ namespace Mono.CSharp
/// </summary>
CheckedScope = 1 << 0,
/// <summary>
/// The constant check state is always set to `true' and cant be changed
/// from the command line. The source code can change this setting with
/// the `checked' and `unchecked' statements and expressions.
/// </summary>
ConstantCheckState = 1 << 1,
AllCheckStateFlags = CheckedScope | ConstantCheckState,
OmitDebugInfo = 1 << 2,
ConstructorScope = 1 << 3
ConstructorScope = 1 << 3,
AsyncBody = 1 << 4
}
// utility helper for CheckExpr, UnCheckExpr, Checked and Unchecked statements
@ -725,7 +705,7 @@ namespace Mono.CSharp @@ -725,7 +705,7 @@ namespace Mono.CSharp
}
}
Options flags;
protected Options flags;
public bool HasSet (Options options)
{

3
ICSharpCode.NRefactory.CSharp/Parser/mcs/convert.cs

@ -8,6 +8,7 @@ @@ -8,6 +8,7 @@
//
// Copyright 2001, 2002, 2003 Ximian, Inc.
// Copyright 2003-2008 Novell, Inc.
// Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
//
using System;
@ -198,7 +199,7 @@ namespace Mono.CSharp { @@ -198,7 +199,7 @@ namespace Mono.CSharp {
return ImplicitReferenceConversionExists (expr_type, target_type, true);
}
static bool ImplicitReferenceConversionExists (TypeSpec expr_type, TypeSpec target_type, bool refOnlyTypeParameter)
public static bool ImplicitReferenceConversionExists (TypeSpec expr_type, TypeSpec target_type, bool refOnlyTypeParameter)
{
// It's here only to speed things up
if (target_type.IsStruct)

9891
ICSharpCode.NRefactory.CSharp/Parser/mcs/cs-parser.cs

File diff suppressed because it is too large Load Diff

117
ICSharpCode.NRefactory.CSharp/Parser/mcs/cs-parser.jay

@ -2,14 +2,15 @@ @@ -2,14 +2,15 @@
//
// cs-parser.jay: The Parser for the C# compiler
//
// Authors: Miguel de Icaza (miguel@gnu.org)
// Authors: Miguel de Icaza (miguel@gnome.org)
// Ravi Pratap (ravi@ximian.com)
// Marek Safar (marek.safar@gmail.com)
// Marek Safar (marek.safar@gmail.com)
//
// Dual Licensed under the terms of the GNU GPL and the MIT X11 license
//
// (C) 2001 Ximian, Inc (http://www.ximian.com)
// (C) 2004 Novell, Inc
// (C) 2004-2011 Novell, Inc
// Copyright 2011 Xamarin Inc.
//
// TODO:
// (1) Figure out why error productions dont work. `type-declaration' is a
@ -898,8 +899,13 @@ opt_class_member_declarations @@ -898,8 +899,13 @@ opt_class_member_declarations
class_member_declarations
: class_member_declaration
| class_member_declarations
class_member_declaration
{
lexer.parsing_modifiers = true;
}
| class_member_declarations class_member_declaration
{
lexer.parsing_modifiers = true;
}
;
class_member_declaration
@ -946,10 +952,17 @@ struct_declaration @@ -946,10 +952,17 @@ struct_declaration
if (doc_support)
current_container.DocComment = Lexer.consume_doc_comment ();
lexer.parsing_modifiers = true;
}
struct_body
OPEN_BRACE
{
--lexer.parsing_declaration;
if (doc_support)
Lexer.doc_state = XmlCommentState.Allowed;
}
opt_class_member_declarations CLOSE_BRACE
{
--lexer.parsing_declaration;
if (doc_support)
Lexer.doc_state = XmlCommentState.Allowed;
}
@ -964,46 +977,6 @@ struct_declaration @@ -964,46 +977,6 @@ struct_declaration
Error_SyntaxError (yyToken);
}
;
struct_body
: OPEN_BRACE
{
if (doc_support)
Lexer.doc_state = XmlCommentState.Allowed;
}
opt_struct_member_declarations CLOSE_BRACE
{
lbag.AppendToMember (current_class, GetLocation ($1), GetLocation ($4));
}
;
opt_struct_member_declarations
: /* empty */
| struct_member_declarations
;
struct_member_declarations
: struct_member_declaration
| struct_member_declarations struct_member_declaration
;
struct_member_declaration
: constant_declaration
| field_declaration
| method_declaration
| property_declaration
| event_declaration
| indexer_declaration
| operator_declaration
| constructor_declaration
| type_declaration
/*
* This is only included so we can flag error 575:
* destructors only allowed on class types
*/
| destructor_declaration
;
constant_declaration
: opt_attributes
@ -1259,13 +1232,16 @@ method_declaration @@ -1259,13 +1232,16 @@ method_declaration
if (doc_support)
Lexer.doc_state = XmlCommentState.NotAllowed;
// Add it early in the case of body being eof for full aot
current_container.AddMethod ((Method) $1);
// Add it early in the case of body being eof for full ast
Method m = (Method) $1;
lexer.async_block = (m.ModFlags & Modifiers.ASYNC) != 0;
current_container.AddMethod (m);
}
method_body
{
Method method = (Method) $1;
method.Block = (ToplevelBlock) $3;
lexer.async_block = false;
if (method.Block == null) {
lbag.AppendToMember (method, savedLocation); // semicolon
@ -1967,6 +1943,8 @@ interface_declaration @@ -1967,6 +1943,8 @@ interface_declaration
current_container.DocComment = Lexer.consume_doc_comment ();
Lexer.doc_state = XmlCommentState.Allowed;
}
lexer.parsing_modifiers = true;
}
OPEN_BRACE opt_interface_member_declarations CLOSE_BRACE
{
@ -1994,7 +1972,13 @@ opt_interface_member_declarations @@ -1994,7 +1972,13 @@ opt_interface_member_declarations
interface_member_declarations
: interface_member_declaration
{
lexer.parsing_modifiers = true;
}
| interface_member_declarations interface_member_declaration
{
lexer.parsing_modifiers = true;
}
;
interface_member_declaration
@ -3887,10 +3871,10 @@ cast_expression @@ -3887,10 +3871,10 @@ cast_expression
await_expression
: AWAIT unary_expression
{
{
current_block.ParametersBlock.IsAsync = true;
$$ = new Await ((Expression) $2, GetLocation ($1));
}
}
;
//
@ -4352,6 +4336,8 @@ class_declaration @@ -4352,6 +4336,8 @@ class_declaration
current_container.DocComment = Lexer.consume_doc_comment ();
Lexer.doc_state = XmlCommentState.Allowed;
}
lexer.parsing_modifiers = true;
}
OPEN_BRACE opt_class_member_declarations CLOSE_BRACE
{
@ -4380,8 +4366,12 @@ opt_modifiers @@ -4380,8 +4366,12 @@ opt_modifiers
{
mod_locations = null;
$$ = ModifierNone;
lexer.parsing_modifiers = false;
}
| modifiers
{
lexer.parsing_modifiers = false;
}
;
modifiers
@ -4951,6 +4941,17 @@ opt_variable_declarators @@ -4951,6 +4941,17 @@ opt_variable_declarators
| variable_declarators
;
opt_using_or_fixed_variable_declarators
: /* empty */
| variable_declarators
{
foreach (var d in current_variable.Declarators) {
if (d.Initializer == null)
Error_MissingInitializer (d.Variable.Location);
}
}
;
variable_declarators
: variable_declarator
| variable_declarators variable_declarator
@ -5561,7 +5562,7 @@ fixed_statement @@ -5561,7 +5562,7 @@ fixed_statement
current_block.AddLocalName (li);
current_variable = new Fixed.VariableDeclaration ((FullNamedExpression) $3, li);
}
using_or_fixed_variable_initializer opt_variable_declarators CLOSE_PARENS
using_or_fixed_variable_initializer opt_using_or_fixed_variable_declarators CLOSE_PARENS
{
$$ = current_variable;
current_variable = null;
@ -5589,7 +5590,7 @@ using_statement @@ -5589,7 +5590,7 @@ using_statement
current_block.AddLocalName (li);
current_variable = new Using.VariableDeclaration ((FullNamedExpression) $3, li);
}
using_or_fixed_variable_initializer opt_variable_declarators CLOSE_PARENS
using_or_fixed_variable_initializer opt_using_or_fixed_variable_declarators CLOSE_PARENS
{
$$ = current_variable;
current_variable = null;
@ -5618,7 +5619,7 @@ using_statement @@ -5618,7 +5619,7 @@ using_statement
using_or_fixed_variable_initializer
: /* empty */
{
report.Error (210, lexer.Location, "You must provide an initializer in a fixed or using statement declaration");
Error_MissingInitializer (lexer.Location);
}
| ASSIGN variable_initializer
{
@ -6366,6 +6367,11 @@ void Error_NamedArgumentExpected (NamedArgument a) @@ -6366,6 +6367,11 @@ void Error_NamedArgumentExpected (NamedArgument a)
report.Error (1738, a.Location, "Named arguments must appear after the positional arguments");
}
void Error_MissingInitializer (Location loc)
{
report.Error (210, loc, "You must provide an initializer in a fixed or using statement declaration");
}
void push_current_class (TypeContainer tc, object partial_token)
{
if (module.Evaluator != null && current_container is ModuleContainer){
@ -6621,6 +6627,7 @@ void start_anonymous (bool isLambda, ParametersCompiled parameters, bool isAsync @@ -6621,6 +6627,7 @@ void start_anonymous (bool isLambda, ParametersCompiled parameters, bool isAsync
oob_stack.Push (current_anonymous_method);
oob_stack.Push (current_local_parameters);
oob_stack.Push (current_variable);
oob_stack.Push (lexer.async_block);
current_local_parameters = parameters;
if (isLambda) {
@ -6635,6 +6642,7 @@ void start_anonymous (bool isLambda, ParametersCompiled parameters, bool isAsync @@ -6635,6 +6642,7 @@ void start_anonymous (bool isLambda, ParametersCompiled parameters, bool isAsync
current_anonymous_method = new AnonymousMethodExpression (isAsync, loc);
}
lexer.async_block = isAsync;
// Force the next block to be created as a ToplevelBlock
parsing_anonymous_method = true;
}
@ -6650,6 +6658,7 @@ AnonymousMethodExpression end_anonymous (ParametersBlock anon_block) @@ -6650,6 +6658,7 @@ AnonymousMethodExpression end_anonymous (ParametersBlock anon_block)
current_anonymous_method.Block = anon_block;
retval = current_anonymous_method;
lexer.async_block = (bool) oob_stack.Pop ();
current_variable = (BlockVariableDeclaration) oob_stack.Pop ();
current_local_parameters = (ParametersCompiled) oob_stack.Pop ();
current_anonymous_method = (AnonymousMethodExpression) oob_stack.Pop ();

47
ICSharpCode.NRefactory.CSharp/Parser/mcs/cs-tokenizer.cs

@ -3,13 +3,13 @@ @@ -3,13 +3,13 @@
// This also implements the preprocessor
//
// Author: Miguel de Icaza (miguel@gnu.org)
// Marek Safar (marek.safar@seznam.cz)
// Marek Safar (marek.safar@gmail.com)
//
// Dual licensed under the terms of the MIT X11 or GNU GPL
//
// Copyright 2001, 2002 Ximian, Inc (http://www.ximian.com)
// Copyright 2004-2008 Novell, Inc
//
// Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
//
using System;
using System.Text;
@ -205,6 +205,10 @@ namespace Mono.CSharp @@ -205,6 +205,10 @@ namespace Mono.CSharp
public int parsing_declaration;
public bool parsing_attribute_section;
public bool parsing_modifiers;
public bool async_block;
//
// The special characters to inject on streams to run the unit parser
// in the special expression mode. Using private characters from
@ -787,18 +791,47 @@ namespace Mono.CSharp @@ -787,18 +791,47 @@ namespace Mono.CSharp
res = -1;
break;
// TODO: async, it's modifiers context only
case Token.ASYNC:
if (context.Settings.Version != LanguageVersion.Future) {
if (parsing_modifiers) {
//
// Skip attributes section or constructor called async
//
if (parsing_attribute_section || peek_token () == Token.OPEN_PARENS) {
res = -1;
} else {
// async is keyword
}
} else if (parsing_block > 0) {
switch (peek_token ()) {
case Token.DELEGATE:
case Token.OPEN_PARENS_LAMBDA:
// async is keyword
break;
case Token.IDENTIFIER:
PushPosition ();
xtoken ();
if (xtoken () != Token.ARROW)
res = -1;
PopPosition ();
break;
default:
res = -1;
break;
}
} else {
res = -1;
}
if (res == Token.ASYNC && context.Settings.Version <= LanguageVersion.V_4) {
Report.FeatureIsNotAvailable (context, Location, "asynchronous functions");
}
break;
// TODO: async, it's async block context only
case Token.AWAIT:
if (context.Settings.Version != LanguageVersion.Future) {
if (!async_block)
res = -1;
}
break;
}

4
ICSharpCode.NRefactory.CSharp/Parser/mcs/decl.cs

@ -697,9 +697,9 @@ namespace Mono.CSharp { @@ -697,9 +697,9 @@ namespace Mono.CSharp {
return true;
}
public virtual IList<MethodSpec> LookupExtensionMethod (TypeSpec extensionType, string name, int arity, ref NamespaceContainer scope)
public virtual ExtensionMethodCandidates LookupExtensionMethod (TypeSpec extensionType, string name, int arity)
{
return Parent.LookupExtensionMethod (extensionType, name, arity, ref scope);
return Parent.LookupExtensionMethod (extensionType, name, arity);
}
public virtual FullNamedExpression LookupNamespaceAlias (string name)

16
ICSharpCode.NRefactory.CSharp/Parser/mcs/delegate.cs

@ -434,6 +434,11 @@ namespace Mono.CSharp { @@ -434,6 +434,11 @@ namespace Mono.CSharp {
protected MethodSpec constructor_method;
protected MethodGroupExpr method_group;
public override bool ContainsEmitWithAwait ()
{
return false;
}
public static Arguments CreateDelegateMethodArguments (AParametersCollection pd, TypeSpec[] types, Location loc)
{
Arguments delegate_arguments = new Arguments (pd.Count);
@ -541,7 +546,7 @@ namespace Mono.CSharp { @@ -541,7 +546,7 @@ namespace Mono.CSharp {
public override void Emit (EmitContext ec)
{
if (method_group.InstanceExpression == null)
ec.Emit (OpCodes.Ldnull);
ec.EmitNull ();
else
method_group.InstanceExpression.Emit (ec);
@ -717,6 +722,11 @@ namespace Mono.CSharp { @@ -717,6 +722,11 @@ namespace Mono.CSharp {
this.arguments = args;
this.loc = loc;
}
public override bool ContainsEmitWithAwait ()
{
return InstanceExpr.ContainsEmitWithAwait () || (arguments != null && arguments.ContainsEmitWithAwait ());
}
public override Expression CreateExpressionTree (ResolveContext ec)
{
@ -753,7 +763,9 @@ namespace Mono.CSharp { @@ -753,7 +763,9 @@ namespace Mono.CSharp {
// Invocation on delegates call the virtual Invoke member
// so we are always `instance' calls
//
Invocation.EmitCall (ec, InstanceExpr, method, arguments, loc);
var call = new CallEmitter ();
call.InstanceExpression = InstanceExpr;
call.EmitPredefined (ec, method, arguments);
}
public override void EmitStatement (EmitContext ec)

19
ICSharpCode.NRefactory.CSharp/Parser/mcs/dynamic.cs

@ -6,6 +6,7 @@ @@ -6,6 +6,7 @@
// Dual licensed under the terms of the MIT X11 or GNU GPL
//
// Copyright 2009 Novell, Inc
// Copyright 2011 Xamarin Inc.
//
using System;
@ -95,9 +96,14 @@ namespace Mono.CSharp @@ -95,9 +96,14 @@ namespace Mono.CSharp
throw new NotImplementedException ();
}
public override bool ContainsEmitWithAwait ()
{
throw new NotSupportedException ();
}
public override Expression CreateExpressionTree (ResolveContext ec)
{
throw new NotImplementedException ();
throw new NotSupportedException ();
}
protected override Expression DoResolve (ResolveContext ec)
@ -122,7 +128,7 @@ namespace Mono.CSharp @@ -122,7 +128,7 @@ namespace Mono.CSharp
throw new NotImplementedException ();
}
public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
{
throw new NotImplementedException ();
}
@ -262,6 +268,11 @@ namespace Mono.CSharp @@ -262,6 +268,11 @@ namespace Mono.CSharp
}
}
public override bool ContainsEmitWithAwait ()
{
return arguments.ContainsEmitWithAwait ();
}
public override Expression CreateExpressionTree (ResolveContext ec)
{
ec.Report.Error (1963, loc, "An expression tree cannot contain a dynamic operation");
@ -714,7 +725,7 @@ namespace Mono.CSharp @@ -714,7 +725,7 @@ namespace Mono.CSharp
class DynamicInvocation : DynamicExpressionStatement, IDynamicBinder
{
ATypeNameExpression member;
readonly ATypeNameExpression member;
public DynamicInvocation (ATypeNameExpression member, Arguments args, Location loc)
: base (null, args, loc)
@ -897,7 +908,7 @@ namespace Mono.CSharp @@ -897,7 +908,7 @@ namespace Mono.CSharp
throw new NotImplementedException ();
}
public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
{
EmitCall (ec, setter, setter_args, !leave_copy);
}

499
ICSharpCode.NRefactory.CSharp/Parser/mcs/ecore.cs

@ -7,6 +7,7 @@ @@ -7,6 +7,7 @@
//
// Copyright 2001, 2002, 2003 Ximian, Inc.
// Copyright 2003-2008 Novell, Inc.
// Copyright 2011 Xamarin Inc.
//
//
@ -130,16 +131,14 @@ namespace Mono.CSharp { @@ -130,16 +131,14 @@ namespace Mono.CSharp {
set { type = value; }
}
public Location Location {
get { return loc; }
public virtual bool IsSideEffectFree {
get {
return false;
}
}
public virtual string GetSignatureForError ()
{
if (type == null)
return "<nullType>";
TypeSpec typeSpec = type.GetDefinition ();
return typeSpec != null ? typeSpec.GetSignatureForError () : "<nullTypeSpec>";
public Location Location {
get { return loc; }
}
public virtual bool IsNull {
@ -148,6 +147,15 @@ namespace Mono.CSharp { @@ -148,6 +147,15 @@ namespace Mono.CSharp {
}
}
//
// Returns true when the expression during Emit phase breaks stack
// by using await expression
//
public virtual bool ContainsEmitWithAwait ()
{
return false;
}
/// <summary>
/// Performs semantic analysis on the Expression
/// </summary>
@ -343,6 +351,11 @@ namespace Mono.CSharp { @@ -343,6 +351,11 @@ namespace Mono.CSharp {
}
}
}
public virtual string GetSignatureForError ()
{
return type.GetDefinition ().GetSignatureForError ();
}
/// <summary>
/// Resolves an expression and performs semantic analysis on it.
@ -469,6 +482,107 @@ namespace Mono.CSharp { @@ -469,6 +482,107 @@ namespace Mono.CSharp {
ec.Emit (OpCodes.Pop);
}
//
// Emits the expression into temporary field variable. The method
// should be used for await expressions only
//
public virtual Expression EmitToField (EmitContext ec)
{
//
// This is the await prepare Emit method. When emitting code like
// a + b we emit code like
//
// a.Emit ()
// b.Emit ()
// Opcodes.Add
//
// For await a + await b we have to interfere the flow to keep the
// stack clean because await yields from the expression. The emit
// then changes to
//
// a = a.EmitToField () // a is changed to temporary field access
// b = b.EmitToField ()
// a.Emit ()
// b.Emit ()
// Opcodes.Add
//
//
// The idea is to emit expression and leave the stack empty with
// result value still available.
//
// Expressions should override this default implementation when
// optimized version can be provided (e.g. FieldExpr)
//
//
// We can optimize for side-effect free expressions, they can be
// emitted out of order
//
if (IsSideEffectFree)
return this;
bool needs_temporary = ContainsEmitWithAwait ();
if (!needs_temporary)
ec.EmitThis ();
// Emit original code
EmitToFieldSource (ec);
//
// Store the result to temporary field when we
// cannot load this directly
//
var field = ec.GetTemporaryField (type);
if (needs_temporary) {
//
// Create temporary local (we cannot load this before Emit)
//
var temp = ec.GetTemporaryLocal (type);
ec.Emit (OpCodes.Stloc, temp);
ec.EmitThis ();
ec.Emit (OpCodes.Ldloc, temp);
field.EmitAssignFromStack (ec);
ec.FreeTemporaryLocal (temp, type);
} else {
field.EmitAssignFromStack (ec);
}
return field;
}
protected virtual void EmitToFieldSource (EmitContext ec)
{
//
// Default implementation calls Emit method
//
Emit (ec);
}
protected static void EmitExpressionsList (EmitContext ec, List<Expression> expressions)
{
if (ec.HasSet (BuilderContext.Options.AsyncBody)) {
bool contains_await = false;
for (int i = 1; i < expressions.Count; ++i) {
if (expressions[i].ContainsEmitWithAwait ()) {
contains_await = true;
break;
}
}
if (contains_await) {
for (int i = 0; i < expressions.Count; ++i) {
expressions[i] = expressions[i].EmitToField (ec);
}
}
}
for (int i = 0; i < expressions.Count; ++i) {
expressions[i].Emit (ec);
}
}
/// <summary>
/// Protected constructor. Only derivate types should
/// be able to be created
@ -498,7 +612,7 @@ namespace Mono.CSharp { @@ -498,7 +612,7 @@ namespace Mono.CSharp {
return null;
}
protected static MethodSpec ConstructorLookup (ResolveContext rc, TypeSpec type, ref Arguments args, Location loc)
public static MethodSpec ConstructorLookup (ResolveContext rc, TypeSpec type, ref Arguments args, Location loc)
{
var ctors = MemberCache.FindMembers (type, Constructor.ConstructorName, true);
if (ctors == null) {
@ -961,6 +1075,11 @@ namespace Mono.CSharp { @@ -961,6 +1075,11 @@ namespace Mono.CSharp {
}
}
public override bool ContainsEmitWithAwait ()
{
return child.ContainsEmitWithAwait ();
}
public override Expression CreateExpressionTree (ResolveContext ec)
{
Arguments args = new Arguments (2);
@ -1140,6 +1259,12 @@ namespace Mono.CSharp { @@ -1140,6 +1259,12 @@ namespace Mono.CSharp {
get { return child.IsOneInteger; }
}
public override bool IsSideEffectFree {
get {
return child.IsSideEffectFree;
}
}
public override bool IsZeroInteger {
get { return child.IsZeroInteger; }
}
@ -1277,6 +1402,12 @@ namespace Mono.CSharp { @@ -1277,6 +1402,12 @@ namespace Mono.CSharp {
}
}
public override bool IsSideEffectFree {
get {
return Child.IsSideEffectFree;
}
}
public override bool IsZeroInteger {
get { return Child.IsZeroInteger; }
}
@ -1748,6 +1879,11 @@ namespace Mono.CSharp { @@ -1748,6 +1879,11 @@ namespace Mono.CSharp {
this.loc = orig.Location;
}
public override bool ContainsEmitWithAwait ()
{
return stm.ContainsEmitWithAwait ();
}
public override Expression CreateExpressionTree (ResolveContext ec)
{
return orig_expr.CreateExpressionTree (ec);
@ -1790,6 +1926,11 @@ namespace Mono.CSharp { @@ -1790,6 +1926,11 @@ namespace Mono.CSharp {
#endregion
public override bool ContainsEmitWithAwait ()
{
return expr.ContainsEmitWithAwait ();
}
//
// Creates fully resolved expression switcher
//
@ -1873,6 +2014,11 @@ namespace Mono.CSharp { @@ -1873,6 +2014,11 @@ namespace Mono.CSharp {
this.loc = expr.Location;
}
public override bool ContainsEmitWithAwait ()
{
return expr.ContainsEmitWithAwait ();
}
public override Expression CreateExpressionTree (ResolveContext rc)
{
return expr.CreateExpressionTree (rc);
@ -1930,6 +2076,11 @@ namespace Mono.CSharp { @@ -1930,6 +2076,11 @@ namespace Mono.CSharp {
target.expr = expr.Clone (clonectx);
}
public override bool ContainsEmitWithAwait ()
{
return expr.ContainsEmitWithAwait ();
}
public override Expression CreateExpressionTree (ResolveContext ec)
{
throw new NotSupportedException ("ET");
@ -2090,7 +2241,6 @@ namespace Mono.CSharp { @@ -2090,7 +2241,6 @@ namespace Mono.CSharp {
}
}
// MSAF
var retval = ctx.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
if (retval != null) {
ctx.Module.Compiler.Report.SymbolRelatedToPreviousError (retval.Type);
@ -2379,6 +2529,11 @@ namespace Mono.CSharp { @@ -2379,6 +2529,11 @@ namespace Mono.CSharp {
// resolved to different type
}
public override bool ContainsEmitWithAwait ()
{
return false;
}
public override Expression CreateExpressionTree (ResolveContext ec)
{
throw new NotSupportedException ("ET");
@ -2626,6 +2781,11 @@ namespace Mono.CSharp { @@ -2626,6 +2781,11 @@ namespace Mono.CSharp {
}
}
public override bool ContainsEmitWithAwait ()
{
return InstanceExpression != null && InstanceExpression.ContainsEmitWithAwait ();
}
static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
{
do {
@ -2814,6 +2974,7 @@ namespace Mono.CSharp { @@ -2814,6 +2974,7 @@ namespace Mono.CSharp {
InstanceExpression.Emit (ec);
t.Store (ec);
t.AddressOf (ec, AddressOp.Store);
t.Release (ec);
}
} else {
InstanceExpression.Emit (ec);
@ -2830,18 +2991,57 @@ namespace Mono.CSharp { @@ -2830,18 +2991,57 @@ namespace Mono.CSharp {
public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
}
public class ExtensionMethodCandidates
{
NamespaceContainer container;
Namespace ns;
IList<MethodSpec> methods;
public ExtensionMethodCandidates (IList<MethodSpec> methods, NamespaceContainer nsContainer)
: this (methods, nsContainer, null)
{
}
public ExtensionMethodCandidates (IList<MethodSpec> methods, NamespaceContainer nsContainer, Namespace ns)
{
this.methods = methods;
this.container = nsContainer;
this.ns = ns;
}
public NamespaceContainer Container {
get {
return container;
}
}
public bool HasUninspectedMembers { get; set; }
public Namespace Namespace {
get {
return ns;
}
}
public IList<MethodSpec> Methods {
get {
return methods;
}
}
}
//
// Represents a group of extension method candidates for whole namespace
//
class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
{
NamespaceContainer namespace_entry;
ExtensionMethodCandidates candidates;
public readonly Expression ExtensionExpression;
public ExtensionMethodGroupExpr (IList<MethodSpec> list, NamespaceContainer n, Expression extensionExpr, Location l)
: base (list.Cast<MemberSpec>().ToList (), extensionExpr.Type, l)
public ExtensionMethodGroupExpr (ExtensionMethodCandidates candidates, Expression extensionExpr, Location loc)
: base (candidates.Methods.Cast<MemberSpec>().ToList (), extensionExpr.Type, loc)
{
this.namespace_entry = n;
this.candidates = candidates;
this.ExtensionExpression = extensionExpr;
}
@ -2849,21 +3049,55 @@ namespace Mono.CSharp { @@ -2849,21 +3049,55 @@ namespace Mono.CSharp {
get { return true; }
}
//
// For extension methodgroup we are not looking for base members but parent
// namespace extension methods
//
public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
{
if (namespace_entry == null)
// TODO: candidates are null only when doing error reporting, that's
// incorrect. We have to discover same extension methods in error mode
if (candidates == null)
return null;
int arity = type_arguments == null ? 0 : type_arguments.Count;
//
// For extension methodgroup we are not looking for base members but parent
// namespace extension methods
// Here we try to resume the search for extension method at the point
// where the last bunch of candidates was found. It's more tricky than
// it seems as we have to check both namespace containers and namespace
// in correct order.
//
int arity = type_arguments == null ? 0 : type_arguments.Count;
var found = namespace_entry.LookupExtensionMethod (DeclaringType, Name, arity, ref namespace_entry);
if (found == null)
// Consider:
//
// namespace A {
// using N1;
// namespace B.C.D {
// <our first search found candidates in A.B.C.D
// }
// }
//
// In the example above namespace A.B.C.D, A.B.C and A.B have to be
// checked before we hit A.N1 using
//
if (candidates.Namespace == null) {
Namespace scope;
var methods = candidates.Container.NS.LookupExtensionMethod (candidates.Container, ExtensionExpression.Type, Name, arity, out scope);
if (methods != null) {
candidates = new ExtensionMethodCandidates (null, candidates.Container, scope);
return methods.Cast<MemberSpec> ().ToList ();
}
}
var ns_container = candidates.HasUninspectedMembers ? candidates.Container : candidates.Container.Parent;
if (ns_container == null)
return null;
return found.Cast<MemberSpec> ().ToList ();
candidates = ns_container.LookupExtensionMethod (ExtensionExpression.Type, Name, arity);
if (candidates == null)
return null;
return candidates.Methods.Cast<MemberSpec> ().ToList ();
}
public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
@ -3072,7 +3306,9 @@ namespace Mono.CSharp { @@ -3072,7 +3306,9 @@ namespace Mono.CSharp {
public void EmitCall (EmitContext ec, Arguments arguments)
{
Invocation.EmitCall (ec, InstanceExpression, best_candidate, arguments, loc);
var call = new CallEmitter ();
call.InstanceExpression = InstanceExpression;
call.Emit (ec, best_candidate, arguments, loc);
}
public override void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, TypeSpec target, bool expl)
@ -3197,12 +3433,11 @@ namespace Mono.CSharp { @@ -3197,12 +3433,11 @@ namespace Mono.CSharp {
return null;
int arity = type_arguments == null ? 0 : type_arguments.Count;
NamespaceContainer methods_scope = null;
var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity, ref methods_scope);
var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity);
if (methods == null)
return null;
var emg = new ExtensionMethodGroupExpr (methods, methods_scope, InstanceExpression, loc);
var emg = new ExtensionMethodGroupExpr (methods, InstanceExpression, loc);
emg.SetTypeArguments (rc, type_arguments);
return emg;
}
@ -3969,9 +4204,11 @@ namespace Mono.CSharp { @@ -3969,9 +4204,11 @@ namespace Mono.CSharp {
//
// Indentity, implicit reference or boxing conversion must exist for the extension parameter
//
// LAMESPEC: or implicit type parameter conversion
//
var at = a.Type;
if (at == pt || TypeSpecComparer.IsEqual (at, pt) ||
Convert.ImplicitReferenceConversionExists (at, pt) ||
Convert.ImplicitReferenceConversionExists (at, pt, false) ||
Convert.ImplicitBoxingConversion (null, at, pt) != null) {
score = 0;
continue;
@ -4756,10 +4993,11 @@ namespace Mono.CSharp { @@ -4756,10 +4993,11 @@ namespace Mono.CSharp {
}
}
/// <summary>
/// Fully resolved expression that evaluates to a Field
/// </summary>
public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference {
//
// Fully resolved expression that references a Field
//
public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
{
protected FieldSpec spec;
VariableInfo variable_info;
@ -4929,7 +5167,7 @@ namespace Mono.CSharp { @@ -4929,7 +5167,7 @@ namespace Mono.CSharp {
} else if (var != null && var.IsHoisted) {
AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
}
return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
}
@ -5108,23 +5346,27 @@ namespace Mono.CSharp { @@ -5108,23 +5346,27 @@ namespace Mono.CSharp {
}
}
public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
{
var await_expr = source as Await;
if (await_expr != null) {
//
// Await is not ordinary expression (it contains jump), hence the usual flow cannot be used
// to emit instance load before expression
//
await_expr.EmitAssign (ec, this);
} else {
prepared = prepare_for_load && !(source is DynamicExpressionStatement);
if (IsInstance)
EmitInstance (ec, prepared);
bool has_await_source = ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ();
if (isCompound && !(source is DynamicExpressionStatement)) {
if (has_await_source) {
if (IsInstance)
InstanceExpression = InstanceExpression.EmitToField (ec);
} else {
prepared = true;
}
}
source.Emit (ec);
if (IsInstance) {
if (has_await_source)
source = source.EmitToField (ec);
EmitInstance (ec, prepared);
}
source.Emit (ec);
if (leave_copy) {
ec.Emit (OpCodes.Dup);
if (!IsStatic) {
@ -5150,6 +5392,18 @@ namespace Mono.CSharp { @@ -5150,6 +5392,18 @@ namespace Mono.CSharp {
}
}
//
// Emits store to field with prepared values on stack
//
public void EmitAssignFromStack (EmitContext ec)
{
if (IsStatic) {
ec.Emit (OpCodes.Stsfld, spec);
} else {
ec.Emit (OpCodes.Stfld, spec);
}
}
public override void Emit (EmitContext ec)
{
Emit (ec, false);
@ -5187,12 +5441,12 @@ namespace Mono.CSharp { @@ -5187,12 +5441,12 @@ namespace Mono.CSharp {
} else
need_copy = false;
if (need_copy){
LocalBuilder local;
if (need_copy) {
Emit (ec);
local = ec.DeclareLocal (type, false);
ec.Emit (OpCodes.Stloc, local);
ec.Emit (OpCodes.Ldloca, local);
var temp = ec.GetTemporaryLocal (type);
ec.Emit (OpCodes.Stloc, temp);
ec.Emit (OpCodes.Ldloca, temp);
ec.FreeTemporaryLocal (temp, type);
return;
}
@ -5229,14 +5483,13 @@ namespace Mono.CSharp { @@ -5229,14 +5483,13 @@ namespace Mono.CSharp {
}
/// <summary>
/// Expression that evaluates to a Property. The Assign class
/// might set the `Value' expression if we are in an assignment.
///
/// This is not an LValue because we need to re-write the expression, we
/// can not take data from the stack and store it.
/// </summary>
class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
//
// Expression that evaluates to a Property.
//
// This is not an LValue because we need to re-write the expression. We
// can not take data from the stack and store it.
//
sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
{
public PropertyExpr (PropertySpec spec, Location l)
: base (l)
@ -5247,6 +5500,14 @@ namespace Mono.CSharp { @@ -5247,6 +5500,14 @@ namespace Mono.CSharp {
#region Properties
protected override Arguments Arguments {
get {
return null;
}
set {
}
}
protected override TypeSpec DeclaringType {
get {
return best_candidate.DeclaringType;
@ -5279,6 +5540,14 @@ namespace Mono.CSharp { @@ -5279,6 +5540,14 @@ namespace Mono.CSharp {
#endregion
public static PropertyExpr CreatePredefined (PropertySpec spec, Location loc)
{
return new PropertyExpr (spec, loc) {
Getter = spec.Get,
Setter = spec.Set
};
}
public override Expression CreateExpressionTree (ResolveContext ec)
{
Arguments args;
@ -5347,36 +5616,41 @@ namespace Mono.CSharp { @@ -5347,36 +5616,41 @@ namespace Mono.CSharp {
// Special case: length of single dimension array property is turned into ldlen
//
if (IsSingleDimensionalArrayLength ()) {
if (!prepared)
EmitInstance (ec, false);
EmitInstance (ec, false);
ec.Emit (OpCodes.Ldlen);
ec.Emit (OpCodes.Conv_I4);
return;
}
Invocation.EmitCall (ec, InstanceExpression, Getter, null, loc, prepared, false);
if (leave_copy) {
ec.Emit (OpCodes.Dup);
if (!IsStatic) {
temp = new LocalTemporary (this.Type);
temp.Store (ec);
}
}
base.Emit (ec, leave_copy);
}
public override 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 isCompound)
{
Arguments args;
LocalTemporary await_source_arg = null;
if (prepare_for_load && !(source is DynamicExpressionStatement)) {
args = new Arguments (0);
prepared = true;
if (isCompound && !(source is DynamicExpressionStatement)) {
emitting_compound_assignment = true;
source.Emit (ec);
if (leave_copy) {
ec.Emit (OpCodes.Dup);
if (!IsStatic) {
if (has_await_arguments) {
await_source_arg = new LocalTemporary (Type);
await_source_arg.Store (ec);
args = new Arguments (1);
args.Add (new Argument (await_source_arg));
if (leave_copy) {
temp = await_source_arg;
}
has_await_arguments = false;
} else {
args = null;
if (leave_copy) {
ec.Emit (OpCodes.Dup);
temp = new LocalTemporary (this.Type);
temp.Store (ec);
}
@ -5394,12 +5668,23 @@ namespace Mono.CSharp { @@ -5394,12 +5668,23 @@ namespace Mono.CSharp {
}
}
Invocation.EmitCall (ec, InstanceExpression, Setter, args, loc, false, prepared);
emitting_compound_assignment = false;
var call = new CallEmitter ();
call.InstanceExpression = InstanceExpression;
if (args == null)
call.InstanceExpressionOnStack = true;
call.Emit (ec, Setter, args, loc);
if (temp != null) {
temp.Emit (ec);
temp.Release (ec);
}
if (await_source_arg != null) {
await_source_arg.Release (ec);
}
}
protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
@ -5437,7 +5722,8 @@ namespace Mono.CSharp { @@ -5437,7 +5722,8 @@ namespace Mono.CSharp {
protected T best_candidate;
protected LocalTemporary temp;
protected bool prepared;
protected bool emitting_compound_assignment;
protected bool has_await_arguments;
protected PropertyOrIndexerExpr (Location l)
{
@ -5446,6 +5732,8 @@ namespace Mono.CSharp { @@ -5446,6 +5732,8 @@ namespace Mono.CSharp {
#region Properties
protected abstract Arguments Arguments { get; set; }
public MethodSpec Getter {
get {
return getter;
@ -5520,14 +5808,43 @@ namespace Mono.CSharp { @@ -5520,14 +5808,43 @@ namespace Mono.CSharp {
//
// Implements the IAssignMethod interface for assignments
//
public abstract void Emit (EmitContext ec, bool leave_copy);
public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load);
public virtual void Emit (EmitContext ec, bool leave_copy)
{
var call = new CallEmitter ();
call.InstanceExpression = InstanceExpression;
if (has_await_arguments)
call.HasAwaitArguments = true;
else
call.DuplicateArguments = emitting_compound_assignment;
call.Emit (ec, Getter, Arguments, loc);
if (call.HasAwaitArguments) {
InstanceExpression = call.InstanceExpression;
Arguments = call.EmittedArguments;
has_await_arguments = true;
}
if (leave_copy) {
ec.Emit (OpCodes.Dup);
temp = new LocalTemporary (Type);
temp.Store (ec);
}
}
public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound);
public override void Emit (EmitContext ec)
{
Emit (ec, false);
}
protected override void EmitToFieldSource (EmitContext ec)
{
has_await_arguments = true;
Emit (ec, false);
}
public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
@ -5716,14 +6033,17 @@ namespace Mono.CSharp { @@ -5716,14 +6033,17 @@ namespace Mono.CSharp {
throw new NotImplementedException ();
}
public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load)
public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
{
if (leave_copy || !prepare_for_load)
if (leave_copy || !isCompound)
throw new NotImplementedException ("EventExpr::EmitAssign");
Arguments args = new Arguments (1);
args.Add (new Argument (source));
Invocation.EmitCall (ec, InstanceExpression, op, args, loc);
var call = new CallEmitter ();
call.InstanceExpression = InstanceExpression;
call.Emit (ec, op, args, loc);
}
#endregion
@ -5810,20 +6130,15 @@ namespace Mono.CSharp { @@ -5810,20 +6130,15 @@ namespace Mono.CSharp {
return new TemporaryVariableReference (li, loc);
}
public override Expression CreateExpressionTree (ResolveContext ec)
{
throw new NotSupportedException ("ET");
}
protected override Expression DoResolve (ResolveContext ec)
{
eclass = ExprClass.Variable;
//
// Don't capture temporary variables except when using
// iterator redirection
// state machine redirection
//
if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.IsIterator && ec.IsVariableCapturingRequired) {
if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod is StateMachineInitializer && ec.IsVariableCapturingRequired) {
AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
storey.CaptureLocalVariable (ec, li);
}
@ -5877,7 +6192,7 @@ namespace Mono.CSharp { @@ -5877,7 +6192,7 @@ namespace Mono.CSharp {
}
public override VariableInfo VariableInfo {
get { throw new NotImplementedException (); }
get { return null; }
}
}

5
ICSharpCode.NRefactory.CSharp/Parser/mcs/enum.cs

@ -117,6 +117,11 @@ namespace Mono.CSharp { @@ -117,6 +117,11 @@ namespace Mono.CSharp {
this.prev = prev;
}
public override bool ContainsEmitWithAwait ()
{
return false;
}
public override Expression CreateExpressionTree (ResolveContext ec)
{
throw new NotSupportedException ("Missing Resolve call");

7
ICSharpCode.NRefactory.CSharp/Parser/mcs/eval.cs

@ -988,6 +988,13 @@ namespace Mono.CSharp @@ -988,6 +988,13 @@ namespace Mono.CSharp
}
}
/// <summary>
/// Same as quit - useful in script scenerios
/// </summary>
static public void Quit () {
QuitRequested = true;
}
#if !NET_2_1
/// <summary>
/// Describes an object or a type.

1059
ICSharpCode.NRefactory.CSharp/Parser/mcs/expression.cs

File diff suppressed because it is too large Load Diff

108
ICSharpCode.NRefactory.CSharp/Parser/mcs/flowanalysis.cs

@ -7,6 +7,7 @@ @@ -7,6 +7,7 @@
//
// Copyright 2001, 2002, 2003 Ximian, Inc.
// Copyright 2003-2008 Novell, Inc.
// Copyright 2011 Xamarin, Inc.
//
using System;
@ -415,9 +416,9 @@ namespace Mono.CSharp @@ -415,9 +416,9 @@ namespace Mono.CSharp
return Parent.CheckRethrow (loc);
}
public virtual bool AddResumePoint (ResumableStatement stmt, Location loc, out int pc)
public virtual bool AddResumePoint (ResumableStatement stmt, out int pc)
{
return Parent.AddResumePoint (stmt, loc, out pc);
return Parent.AddResumePoint (stmt, out pc);
}
// returns true if we crossed an unwind-protected region (try/catch/finally, lock, using, ...)
@ -636,15 +637,15 @@ namespace Mono.CSharp @@ -636,15 +637,15 @@ namespace Mono.CSharp
public class FlowBranchingIterator : FlowBranchingBlock
{
readonly StateMachineInitializer iterator;
readonly Iterator iterator;
public FlowBranchingIterator (FlowBranching parent, StateMachineInitializer iterator)
public FlowBranchingIterator (FlowBranching parent, Iterator iterator)
: base (parent, BranchingType.Iterator, SiblingType.Block, iterator.Block, iterator.Location)
{
this.iterator = iterator;
}
public override bool AddResumePoint (ResumableStatement stmt, Location loc, out int pc)
public override bool AddResumePoint (ResumableStatement stmt, out int pc)
{
pc = iterator.AddResumePoint (stmt);
return false;
@ -666,7 +667,7 @@ namespace Mono.CSharp @@ -666,7 +667,7 @@ namespace Mono.CSharp
return false;
}
public override bool AddResumePoint (ResumableStatement stmt, Location loc, out int pc)
public override bool AddResumePoint (ResumableStatement stmt, out int pc)
{
throw new InternalErrorException ("A yield in a non-iterator block");
}
@ -730,11 +731,12 @@ namespace Mono.CSharp @@ -730,11 +731,12 @@ namespace Mono.CSharp
public class FlowBranchingTryCatch : FlowBranchingBlock
{
TryCatch stmt;
readonly TryCatch tc;
public FlowBranchingTryCatch (FlowBranching parent, TryCatch stmt)
: base (parent, BranchingType.Block, SiblingType.Try, null, stmt.loc)
{
this.stmt = stmt;
this.tc = stmt;
}
public override bool CheckRethrow (Location loc)
@ -742,37 +744,92 @@ namespace Mono.CSharp @@ -742,37 +744,92 @@ namespace Mono.CSharp
return CurrentUsageVector.Next != null || Parent.CheckRethrow (loc);
}
public override bool AddResumePoint (ResumableStatement stmt, Location loc, out int pc)
public override bool AddResumePoint (ResumableStatement stmt, out int pc)
{
int errors = Report.Errors;
Parent.AddResumePoint (stmt, loc, out pc);
Parent.AddResumePoint (tc.IsTryCatchFinally ? stmt : tc, out pc);
if (errors == Report.Errors) {
if (CurrentUsageVector.Next == null)
Report.Error (1626, loc, "Cannot yield a value in the body of a try block with a catch clause");
else
Report.Error (1631, loc, "Cannot yield a value in the body of a catch clause");
if (stmt is AwaitStatement) {
if (CurrentUsageVector.Next != null) {
Report.Error (1985, stmt.loc, "The `await' operator cannot be used in the body of a catch clause");
} else {
this.tc.AddResumePoint (stmt, pc);
}
} else {
if (CurrentUsageVector.Next == null)
Report.Error (1626, stmt.loc, "Cannot yield a value in the body of a try block with a catch clause");
else
Report.Error (1631, stmt.loc, "Cannot yield a value in the body of a catch clause");
}
}
return true;
}
public override bool AddBreakOrigin (UsageVector vector, Location loc)
{
Parent.AddBreakOrigin (vector, loc);
tc.SomeCodeFollows ();
return true;
}
public override bool AddContinueOrigin (UsageVector vector, Location loc)
{
Parent.AddContinueOrigin (vector, loc);
tc.SomeCodeFollows ();
return true;
}
public override bool AddReturnOrigin (UsageVector vector, ExitStatement exit_stmt)
{
Parent.AddReturnOrigin (vector, exit_stmt);
tc.SomeCodeFollows ();
return true;
}
public override bool AddGotoOrigin (UsageVector vector, Goto goto_stmt)
{
Parent.AddGotoOrigin (vector, goto_stmt);
return true;
}
}
public class FlowBranchingAsync : FlowBranchingBlock
{
readonly AsyncInitializer async_init;
public FlowBranchingAsync (FlowBranching parent, AsyncInitializer async_init)
: base (parent, BranchingType.Block, SiblingType.Try, null, async_init.Location)
{
this.async_init = async_init;
}
/*
public override bool CheckRethrow (Location loc)
{
return CurrentUsageVector.Next != null || Parent.CheckRethrow (loc);
}
*/
public override bool AddResumePoint (ResumableStatement stmt, out int pc)
{
pc = async_init.AddResumePoint (stmt);
return true;
}
public override bool AddBreakOrigin (UsageVector vector, Location loc)
{
Parent.AddBreakOrigin (vector, loc);
stmt.SomeCodeFollows ();
return true;
}
public override bool AddContinueOrigin (UsageVector vector, Location loc)
{
Parent.AddContinueOrigin (vector, loc);
stmt.SomeCodeFollows ();
return true;
}
public override bool AddReturnOrigin (UsageVector vector, ExitStatement exit_stmt)
{
Parent.AddReturnOrigin (vector, exit_stmt);
stmt.SomeCodeFollows ();
return true;
}
@ -783,7 +840,7 @@ namespace Mono.CSharp @@ -783,7 +840,7 @@ namespace Mono.CSharp
}
}
public class FlowBranchingException : FlowBranching
public class FlowBranchingTryFinally : FlowBranching
{
ExceptionStatement stmt;
UsageVector current_vector;
@ -869,7 +926,7 @@ namespace Mono.CSharp @@ -869,7 +926,7 @@ namespace Mono.CSharp
SavedOrigin saved_origins;
public FlowBranchingException (FlowBranching parent,
public FlowBranchingTryFinally (FlowBranching parent,
ExceptionStatement stmt)
: base (parent, BranchingType.Exception, SiblingType.Try,
null, stmt.loc)
@ -906,15 +963,20 @@ namespace Mono.CSharp @@ -906,15 +963,20 @@ namespace Mono.CSharp
return false;
}
public override bool AddResumePoint (ResumableStatement stmt, Location loc, out int pc)
public override bool AddResumePoint (ResumableStatement stmt, out int pc)
{
int errors = Report.Errors;
Parent.AddResumePoint (this.stmt, loc, out pc);
Parent.AddResumePoint (this.stmt, out pc);
if (errors == Report.Errors) {
if (finally_vector == null)
this.stmt.AddResumePoint (stmt, pc);
else
Report.Error (1625, loc, "Cannot yield in the body of a finally clause");
else {
if (stmt is AwaitStatement) {
Report.Error (1984, stmt.loc, "The `await' operator cannot be used in the body of a finally clause");
} else {
Report.Error (1625, stmt.loc, "Cannot yield in the body of a finally clause");
}
}
}
return true;
}

34
ICSharpCode.NRefactory.CSharp/Parser/mcs/generic.cs

@ -9,7 +9,9 @@ @@ -9,7 +9,9 @@
//
// Copyright 2001, 2002, 2003 Ximian, Inc (http://www.ximian.com)
// Copyright 2004-2008 Novell, Inc
// Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
//
using System;
using System.Collections.Generic;
using System.Text;
@ -723,8 +725,8 @@ namespace Mono.CSharp { @@ -723,8 +725,8 @@ namespace Mono.CSharp {
}
}
if (ifaces_defined == null && ifaces != null)
ifaces_defined = ifaces.ToArray ();
if (ifaces_defined == null)
ifaces_defined = ifaces == null ? TypeSpec.EmptyTypes : ifaces.ToArray ();
state |= StateFlags.InterfacesExpanded;
}
@ -738,13 +740,19 @@ namespace Mono.CSharp { @@ -738,13 +740,19 @@ namespace Mono.CSharp {
//
public TypeSpec[] InterfacesDefined {
get {
if (ifaces_defined == null && ifaces != null)
if (ifaces_defined == null) {
if (ifaces == null)
return null;
ifaces_defined = ifaces.ToArray ();
}
return ifaces_defined;
return ifaces_defined.Length == 0 ? null : ifaces_defined;
}
set {
ifaces = ifaces_defined = value;
ifaces_defined = value;
if (value != null && value.Length != 0)
ifaces = value;
}
}
@ -974,10 +982,13 @@ namespace Mono.CSharp { @@ -974,10 +982,13 @@ namespace Mono.CSharp {
// Check interfaces implementation -> definition
if (InterfacesDefined != null) {
foreach (var iface in InterfacesDefined) {
//
// Iterate over inflated interfaces
//
foreach (var iface in Interfaces) {
found = false;
if (other.InterfacesDefined != null) {
foreach (var oiface in other.InterfacesDefined) {
foreach (var oiface in other.Interfaces) {
if (TypeSpecComparer.Override.IsEqual (iface, oiface)) {
found = true;
break;
@ -1007,9 +1018,12 @@ namespace Mono.CSharp { @@ -1007,9 +1018,12 @@ namespace Mono.CSharp {
if (InterfacesDefined == null)
return false;
foreach (var oiface in other.InterfacesDefined) {
//
// Iterate over inflated interfaces
//
foreach (var oiface in other.Interfaces) {
found = false;
foreach (var iface in InterfacesDefined) {
foreach (var iface in Interfaces) {
if (TypeSpecComparer.Override.IsEqual (iface, oiface)) {
found = true;
break;
@ -2789,7 +2803,7 @@ namespace Mono.CSharp { @@ -2789,7 +2803,7 @@ namespace Mono.CSharp {
// Some types cannot be used as type arguments
//
if (bound.Type.Kind == MemberKind.Void || bound.Type.IsPointer || bound.Type.IsSpecialRuntimeType ||
bound.Type == InternalType.MethodGroup)
bound.Type == InternalType.MethodGroup || bound.Type == InternalType.AnonymousMethod)
return;
var a = bounds [index];

27
ICSharpCode.NRefactory.CSharp/Parser/mcs/import.cs

@ -5,7 +5,8 @@ @@ -5,7 +5,8 @@
//
// Dual licensed under the terms of the MIT X11 or GNU GPL
//
// Copyright 2009, 2010 Novell, Inc
// Copyright 2009-2011 Novell, Inc
// Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
//
using System;
@ -962,6 +963,15 @@ namespace Mono.CSharp @@ -962,6 +963,15 @@ namespace Mono.CSharp
if (spec.BaseType != null) {
var bifaces = spec.BaseType.Interfaces;
if (bifaces != null) {
//
// Before adding base class interfaces close defined interfaces
// on type parameter
//
var tp = spec as TypeParameterSpec;
if (tp != null && tp.InterfacesDefined == null) {
tp.InterfacesDefined = TypeSpec.EmptyTypes;
}
foreach (var iface in bifaces)
spec.AddInterface (iface);
}
@ -1894,6 +1904,15 @@ namespace Mono.CSharp @@ -1894,6 +1904,15 @@ namespace Mono.CSharp
}
}
//
// Load base interfaces first to minic behaviour of compiled members
//
if (declaringType.IsInterface && declaringType.Interfaces != null) {
foreach (var iface in declaringType.Interfaces) {
cache.AddInterface (iface);
}
}
if (!onlyTypes) {
//
// The logic here requires methods to be returned first which seems to work for both Mono and .NET
@ -2024,12 +2043,6 @@ namespace Mono.CSharp @@ -2024,12 +2043,6 @@ namespace Mono.CSharp
cache.AddMemberImported (imported);
}
}
if (declaringType.IsInterface && declaringType.Interfaces != null) {
foreach (var iface in declaringType.Interfaces) {
cache.AddInterface (iface);
}
}
}
}

253
ICSharpCode.NRefactory.CSharp/Parser/mcs/iterators.cs

@ -8,6 +8,7 @@ @@ -8,6 +8,7 @@
// Dual licensed under the terms of the MIT X11 or GNU GPL
// Copyright 2003 Ximian, Inc.
// Copyright 2003-2008 Novell, Inc.
// Copyright 2011 Xamarin Inc.
//
// TODO:
@ -28,7 +29,7 @@ namespace Mono.CSharp @@ -28,7 +29,7 @@ namespace Mono.CSharp
public abstract class YieldStatement<T> : ResumableStatement where T : StateMachineInitializer
{
protected Expression expr;
bool unwind_protect;
protected bool unwind_protect;
protected T machine_initializer;
int resume_pc;
@ -62,7 +63,7 @@ namespace Mono.CSharp @@ -62,7 +63,7 @@ namespace Mono.CSharp
machine_initializer = bc.CurrentAnonymousMethod as T;
if (!bc.CurrentBranching.CurrentUsageVector.IsUnreachable)
unwind_protect = bc.CurrentBranching.AddResumePoint (this, loc, out resume_pc);
unwind_protect = bc.CurrentBranching.AddResumePoint (this, out resume_pc);
return true;
}
@ -156,7 +157,6 @@ namespace Mono.CSharp @@ -156,7 +157,6 @@ namespace Mono.CSharp
Start = 0
}
Field disposing_field;
Field pc_field;
int local_name_idx;
StateMachineMethod method;
@ -168,12 +168,6 @@ namespace Mono.CSharp @@ -168,12 +168,6 @@ namespace Mono.CSharp
#region Properties
public Field DisposingField {
get {
return disposing_field;
}
}
public StateMachineMethod StateMachineMethod {
get {
return method;
@ -200,14 +194,13 @@ namespace Mono.CSharp @@ -200,14 +194,13 @@ namespace Mono.CSharp
protected override bool DoDefineMembers ()
{
pc_field = AddCompilerGeneratedField ("$PC", new TypeExpression (Compiler.BuiltinTypes.Int, Location));
disposing_field = AddCompilerGeneratedField ("$disposing", new TypeExpression (Compiler.BuiltinTypes.Bool, Location));
return base.DoDefineMembers ();
}
protected override string GetVariableMangledName (LocalVariable local_info)
{
return "<" + local_info.Name + ">__" + local_name_idx++.ToString ();
return "<" + local_info.Name + ">__" + local_name_idx++.ToString ("X");
}
}
@ -280,7 +273,7 @@ namespace Mono.CSharp @@ -280,7 +273,7 @@ namespace Mono.CSharp
{
Label label_init = ec.DefineLabel ();
ec.Emit (OpCodes.Ldarg_0);
ec.EmitThis ();
ec.Emit (OpCodes.Ldflda, host.PC.Spec);
ec.EmitInt ((int) State.Start);
ec.EmitInt ((int) State.Uninitialized);
@ -292,7 +285,7 @@ namespace Mono.CSharp @@ -292,7 +285,7 @@ namespace Mono.CSharp
ec.EmitInt ((int) State.Uninitialized);
ec.Emit (OpCodes.Bne_Un_S, label_init);
ec.Emit (OpCodes.Ldarg_0);
ec.EmitThis ();
ec.Emit (OpCodes.Ret);
ec.MarkLabel (label_init);
@ -396,6 +389,7 @@ namespace Mono.CSharp @@ -396,6 +389,7 @@ namespace Mono.CSharp
TypeExpr iterator_type_expr;
Field current_field;
Field disposing_field;
TypeExpr enumerator_type;
TypeExpr enumerable_type;
@ -411,7 +405,15 @@ namespace Mono.CSharp @@ -411,7 +405,15 @@ namespace Mono.CSharp
}
public Field CurrentField {
get { return current_field; }
get {
return current_field;
}
}
public Field DisposingField {
get {
return disposing_field;
}
}
public IList<HoistedParameter> HoistedParameters {
@ -457,6 +459,7 @@ namespace Mono.CSharp @@ -457,6 +459,7 @@ namespace Mono.CSharp
protected override bool DoDefineMembers ()
{
current_field = AddCompilerGeneratedField ("$current", iterator_type_expr);
disposing_field = AddCompilerGeneratedField ("$disposing", new TypeExpression (Compiler.BuiltinTypes.Bool, Location));
if (hoisted_params != null) {
//
@ -578,6 +581,10 @@ namespace Mono.CSharp @@ -578,6 +581,10 @@ namespace Mono.CSharp
{
EmitContext ec = new EmitContext (this, ig, MemberType);
ec.CurrentAnonymousMethod = expr;
if (expr is AsyncInitializer)
ec.With (BuilderContext.Options.AsyncBody, true);
return ec;
}
}
@ -617,9 +624,11 @@ namespace Mono.CSharp @@ -617,9 +624,11 @@ namespace Mono.CSharp
// The state as we generate the machine
//
Label move_next_ok;
Label iterator_body_end;
protected Label move_next_error;
protected LocalBuilder skip_finally, current_pc;
List<ResumableStatement> resume_points;
LocalBuilder skip_finally;
protected LocalBuilder current_pc;
protected List<ResumableStatement> resume_points;
protected StateMachineInitializer (ParametersBlock block, TypeContainer host, TypeSpec returnType)
: base (block, returnType, block.StartLocation)
@ -627,12 +636,35 @@ namespace Mono.CSharp @@ -627,12 +636,35 @@ namespace Mono.CSharp
this.Host = host;
}
#region Properties
public Label BodyEnd {
get {
return iterator_body_end;
}
}
public LocalBuilder CurrentPC
{
get {
return current_pc;
}
}
public LocalBuilder SkipFinally {
get {
return skip_finally;
}
}
public override AnonymousMethodStorey Storey {
get {
return storey;
}
}
#endregion
public int AddResumePoint (ResumableStatement stmt)
{
if (resume_points == null)
@ -660,7 +692,6 @@ namespace Mono.CSharp @@ -660,7 +692,6 @@ namespace Mono.CSharp
var ctx = CreateBlockContext (ec);
ctx.StartFlowBranching (this, ec.CurrentBranching);
Block.Resolve (ctx);
//
@ -690,70 +721,26 @@ namespace Mono.CSharp @@ -690,70 +721,26 @@ namespace Mono.CSharp
storey.Instance.Emit (ec);
}
public void EmitDispose (EmitContext ec)
{
Label end = ec.DefineLabel ();
Label[] labels = null;
int n_resume_points = resume_points == null ? 0 : resume_points.Count;
for (int i = 0; i < n_resume_points; ++i) {
ResumableStatement s = resume_points[i];
Label ret = s.PrepareForDispose (ec, end);
if (ret.Equals (end) && labels == null)
continue;
if (labels == null) {
labels = new Label[resume_points.Count + 1];
for (int j = 0; j <= i; ++j)
labels[j] = end;
}
labels[i + 1] = ret;
}
if (labels != null) {
current_pc = ec.GetTemporaryLocal (ec.BuiltinTypes.UInt);
ec.Emit (OpCodes.Ldarg_0);
ec.Emit (OpCodes.Ldfld, storey.PC.Spec);
ec.Emit (OpCodes.Stloc, current_pc);
}
ec.Emit (OpCodes.Ldarg_0);
ec.EmitInt (1);
ec.Emit (OpCodes.Stfld, storey.DisposingField.Spec);
ec.Emit (OpCodes.Ldarg_0);
ec.EmitInt ((int) IteratorStorey.State.After);
ec.Emit (OpCodes.Stfld, storey.PC.Spec);
if (labels != null) {
//SymbolWriter.StartIteratorDispatcher (ec.ig);
ec.Emit (OpCodes.Ldloc, current_pc);
ec.Emit (OpCodes.Switch, labels);
//SymbolWriter.EndIteratorDispatcher (ec.ig);
foreach (ResumableStatement s in resume_points)
s.EmitForDispose (ec, current_pc, end, true);
}
ec.MarkLabel (end);
}
void EmitMoveNext_NoResumePoints (EmitContext ec, Block original_block)
{
ec.Emit (OpCodes.Ldarg_0);
ec.EmitThis ();
ec.Emit (OpCodes.Ldfld, storey.PC.Spec);
ec.Emit (OpCodes.Ldarg_0);
ec.EmitThis ();
ec.EmitInt ((int) IteratorStorey.State.After);
ec.Emit (OpCodes.Stfld, storey.PC.Spec);
// We only care if the PC is zero (start executing) or non-zero (don't do anything)
ec.Emit (OpCodes.Brtrue, move_next_error);
iterator_body_end = ec.DefineLabel ();
SymbolWriter.StartIteratorBody (ec);
original_block.Emit (ec);
SymbolWriter.EndIteratorBody (ec);
ec.MarkLabel (iterator_body_end);
EmitMoveNextEpilogue (ec);
ec.MarkLabel (move_next_error);
@ -773,14 +760,14 @@ namespace Mono.CSharp @@ -773,14 +760,14 @@ namespace Mono.CSharp
EmitMoveNext_NoResumePoints (ec, block);
return;
}
current_pc = ec.GetTemporaryLocal (ec.BuiltinTypes.UInt);
ec.Emit (OpCodes.Ldarg_0);
ec.EmitThis ();
ec.Emit (OpCodes.Ldfld, storey.PC.Spec);
ec.Emit (OpCodes.Stloc, current_pc);
// We're actually in state 'running', but this is as good a PC value as any if there's an abnormal exit
ec.Emit (OpCodes.Ldarg_0);
ec.EmitThis ();
ec.EmitInt ((int) IteratorStorey.State.After);
ec.Emit (OpCodes.Stfld, storey.PC.Spec);
@ -796,33 +783,57 @@ namespace Mono.CSharp @@ -796,33 +783,57 @@ namespace Mono.CSharp
if (need_skip_finally) {
skip_finally = ec.GetTemporaryLocal (ec.BuiltinTypes.Bool);
ec.Emit (OpCodes.Ldc_I4_0);
ec.EmitInt (0);
ec.Emit (OpCodes.Stloc, skip_finally);
}
var async_init = this as AsyncInitializer;
if (async_init != null)
ec.BeginExceptionBlock ();
SymbolWriter.StartIteratorDispatcher (ec);
ec.Emit (OpCodes.Ldloc, current_pc);
ec.Emit (OpCodes.Switch, labels);
ec.Emit (OpCodes.Br, move_next_error);
ec.Emit (async_init != null ? OpCodes.Leave : OpCodes.Br, move_next_error);
SymbolWriter.EndIteratorDispatcher (ec);
ec.MarkLabel (labels[0]);
iterator_body_end = ec.DefineLabel ();
SymbolWriter.StartIteratorBody (ec);
block.Emit (ec);
SymbolWriter.EndIteratorBody (ec);
SymbolWriter.StartIteratorDispatcher (ec);
ec.Emit (OpCodes.Ldarg_0);
ec.MarkLabel (iterator_body_end);
if (async_init != null) {
var catch_value = LocalVariable.CreateCompilerGenerated (ec.Module.Compiler.BuiltinTypes.Exception, block, Location);
ec.BeginCatchBlock (catch_value.Type);
catch_value.EmitAssign (ec);
ec.EmitThis ();
ec.EmitInt ((int) IteratorStorey.State.After);
ec.Emit (OpCodes.Stfld, storey.PC.Spec);
((AsyncTaskStorey) async_init.Storey).EmitSetException (ec, new LocalVariableReference (catch_value, Location));
ec.Emit (OpCodes.Leave, move_next_ok);
ec.EndExceptionBlock ();
}
ec.EmitThis ();
ec.EmitInt ((int) IteratorStorey.State.After);
ec.Emit (OpCodes.Stfld, storey.PC.Spec);
EmitMoveNextEpilogue (ec);
ec.MarkLabel (move_next_error);
if (ReturnType.Kind != MemberKind.Void) {
ec.EmitInt (0);
ec.Emit (OpCodes.Ret);
@ -842,6 +853,12 @@ namespace Mono.CSharp @@ -842,6 +853,12 @@ namespace Mono.CSharp
{
}
public void EmitLeave (EmitContext ec, bool unwind_protect)
{
// Return ok
ec.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, move_next_ok);
}
//
// Called back from YieldStatement
//
@ -851,28 +868,29 @@ namespace Mono.CSharp @@ -851,28 +868,29 @@ namespace Mono.CSharp
// Guard against being disposed meantime
//
Label disposed = ec.DefineLabel ();
ec.Emit (OpCodes.Ldarg_0);
ec.Emit (OpCodes.Ldfld, storey.DisposingField.Spec);
ec.Emit (OpCodes.Brtrue_S, disposed);
var iterator = storey as IteratorStorey;
if (iterator != null) {
ec.EmitThis ();
ec.Emit (OpCodes.Ldfld, iterator.DisposingField.Spec);
ec.Emit (OpCodes.Brtrue_S, disposed);
}
//
// store resume program-counter
//
ec.Emit (OpCodes.Ldarg_0);
ec.EmitThis ();
ec.EmitInt (resume_pc);
ec.Emit (OpCodes.Stfld, storey.PC.Spec);
ec.MarkLabel (disposed);
if (iterator != null) {
ec.MarkLabel (disposed);
}
// mark finally blocks as disabled
if (unwind_protect && skip_finally != null) {
ec.EmitInt (1);
ec.Emit (OpCodes.Stloc, skip_finally);
}
// Return ok
ec.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, move_next_ok);
ec.MarkLabel (resume_point);
}
}
@ -894,14 +912,6 @@ namespace Mono.CSharp @@ -894,14 +912,6 @@ namespace Mono.CSharp
this.type = method.ReturnType;
}
public LocalBuilder SkipFinally {
get { return skip_finally; }
}
public LocalBuilder CurrentPC {
get { return current_pc; }
}
public Block Container {
get { return OriginalMethod.Block; }
}
@ -951,6 +961,54 @@ namespace Mono.CSharp @@ -951,6 +961,54 @@ namespace Mono.CSharp
}
}
public void EmitDispose (EmitContext ec)
{
Label end = ec.DefineLabel ();
Label[] labels = null;
int n_resume_points = resume_points == null ? 0 : resume_points.Count;
for (int i = 0; i < n_resume_points; ++i) {
ResumableStatement s = resume_points[i];
Label ret = s.PrepareForDispose (ec, end);
if (ret.Equals (end) && labels == null)
continue;
if (labels == null) {
labels = new Label[resume_points.Count + 1];
for (int j = 0; j <= i; ++j)
labels[j] = end;
}
labels[i + 1] = ret;
}
if (labels != null) {
current_pc = ec.GetTemporaryLocal (ec.BuiltinTypes.UInt);
ec.EmitThis ();
ec.Emit (OpCodes.Ldfld, storey.PC.Spec);
ec.Emit (OpCodes.Stloc, current_pc);
}
ec.EmitThis ();
ec.EmitInt (1);
ec.Emit (OpCodes.Stfld, ((IteratorStorey) storey).DisposingField.Spec);
ec.EmitThis ();
ec.EmitInt ((int) IteratorStorey.State.After);
ec.Emit (OpCodes.Stfld, storey.PC.Spec);
if (labels != null) {
//SymbolWriter.StartIteratorDispatcher (ec.ig);
ec.Emit (OpCodes.Ldloc, current_pc);
ec.Emit (OpCodes.Switch, labels);
//SymbolWriter.EndIteratorDispatcher (ec.ig);
foreach (ResumableStatement s in resume_points)
s.EmitForDispose (ec, current_pc, end, true);
}
ec.MarkLabel (end);
}
public override void EmitStatement (EmitContext ec)
{
throw new NotImplementedException ();
@ -964,6 +1022,17 @@ namespace Mono.CSharp @@ -964,6 +1022,17 @@ namespace Mono.CSharp
fe.EmitAssign (ec, expr, false, false);
base.InjectYield (ec, expr, resume_pc, unwind_protect, resume_point);
EmitLeave (ec, unwind_protect);
ec.MarkLabel (resume_point);
}
protected override BlockContext CreateBlockContext (ResolveContext rc)
{
var bc = base.CreateBlockContext (rc);
bc.StartFlowBranching (this, rc.CurrentBranching);
return bc;
}
public static void CreateIterator (IMethodData method, TypeContainer parent, Modifiers modifiers)

6
ICSharpCode.NRefactory.CSharp/Parser/mcs/lambda.cs

@ -199,7 +199,11 @@ namespace Mono.CSharp { @@ -199,7 +199,11 @@ namespace Mono.CSharp {
{
if (statement != null) {
statement.EmitStatement (ec);
ec.Emit (OpCodes.Ret);
if (unwind_protect)
ec.Emit (OpCodes.Leave, ec.CreateReturnLabel ());
else {
ec.Emit (OpCodes.Ret);
}
return;
}

20
ICSharpCode.NRefactory.CSharp/Parser/mcs/method.cs

@ -1151,7 +1151,7 @@ namespace Mono.CSharp { @@ -1151,7 +1151,7 @@ namespace Mono.CSharp {
}
if ((ModFlags & Modifiers.ASYNC) != 0) {
AsyncInitializer.Create (block, parameters, Parent.PartialContainer, ReturnType, Location);
AsyncInitializer.Create (this, block, parameters, Parent.PartialContainer, ReturnType, Location);
}
}
@ -1316,6 +1316,11 @@ namespace Mono.CSharp { @@ -1316,6 +1316,11 @@ namespace Mono.CSharp {
}
}
public override bool ContainsEmitWithAwait ()
{
throw new NotSupportedException ();
}
public override Expression CreateExpressionTree (ResolveContext ec)
{
throw new NotSupportedException ("ET");
@ -1386,7 +1391,9 @@ namespace Mono.CSharp { @@ -1386,7 +1391,9 @@ namespace Mono.CSharp {
ec.Mark (loc);
Invocation.EmitCall (ec, new CompilerGeneratedThis (type, loc), base_ctor, argument_list, loc);
var call = new CallEmitter ();
call.InstanceExpression = new CompilerGeneratedThis (type, loc);
call.EmitPredefined (ec, base_ctor, argument_list);
}
public override void EmitStatement (EmitContext ec)
@ -1633,11 +1640,6 @@ namespace Mono.CSharp { @@ -1633,11 +1640,6 @@ namespace Mono.CSharp {
EmitContext ec = new EmitContext (this, ConstructorBuilder.GetILGenerator (), bc.ReturnType);
ec.With (EmitContext.Options.ConstructorScope, true);
if (!ec.HasReturnLabel && bc.HasReturnLabel) {
ec.ReturnLabel = bc.ReturnLabel;
ec.HasReturnLabel = true;
}
block.Emit (ec);
}
}
@ -2036,10 +2038,6 @@ namespace Mono.CSharp { @@ -2036,10 +2038,6 @@ namespace Mono.CSharp {
BlockContext bc = new BlockContext (mc, block, method.ReturnType);
if (block.Resolve (null, bc, method)) {
EmitContext ec = method.CreateEmitContext (MethodBuilder.GetILGenerator ());
if (!ec.HasReturnLabel && bc.HasReturnLabel) {
ec.ReturnLabel = bc.ReturnLabel;
ec.HasReturnLabel = true;
}
block.Emit (ec);
}

50
ICSharpCode.NRefactory.CSharp/Parser/mcs/namespace.cs

@ -370,9 +370,9 @@ namespace Mono.CSharp { @@ -370,9 +370,9 @@ namespace Mono.CSharp {
return res;
}
///
/// Looks for extension method in this namespace
///
//
// Looks for extension method in this namespace
//
public List<MethodSpec> LookupExtensionMethod (IMemberContext invocationContext, TypeSpec extensionType, string name, int arity)
{
if (types == null)
@ -402,6 +402,26 @@ namespace Mono.CSharp { @@ -402,6 +402,26 @@ namespace Mono.CSharp {
return found;
}
//
// Extension methods look up for dotted namespace names
//
public IList<MethodSpec> LookupExtensionMethod (IMemberContext invocationContext, TypeSpec extensionType, string name, int arity, out Namespace scope)
{
//
// Inspect parent namespaces in namespace expression
//
scope = this;
do {
var candidates = scope.LookupExtensionMethod (invocationContext, extensionType, name, arity);
if (candidates != null)
return candidates;
scope = scope.Parent;
} while (scope != null);
return null;
}
public void AddType (ModuleContainer module, TypeSpec ts)
{
if (types == null) {
@ -797,7 +817,7 @@ namespace Mono.CSharp { @@ -797,7 +817,7 @@ namespace Mono.CSharp {
// Does extension methods look up to find a method which matches name and extensionType.
// Search starts from this namespace and continues hierarchically up to top level.
//
public IList<MethodSpec> LookupExtensionMethod (TypeSpec extensionType, string name, int arity, ref NamespaceContainer scope)
public ExtensionMethodCandidates LookupExtensionMethod (TypeSpec extensionType, string name, int arity)
{
List<MethodSpec> candidates = null;
foreach (Namespace n in GetUsingTable ()) {
@ -811,29 +831,21 @@ namespace Mono.CSharp { @@ -811,29 +831,21 @@ namespace Mono.CSharp {
candidates.AddRange (a);
}
scope = parent;
if (candidates != null)
return candidates;
return new ExtensionMethodCandidates (candidates, this);
if (parent == null)
return null;
//
// Inspect parent namespaces in namespace expression
//
Namespace parent_ns = ns.Parent;
do {
candidates = parent_ns.LookupExtensionMethod (this, extensionType, name, arity);
if (candidates != null)
return candidates;
parent_ns = parent_ns.Parent;
} while (parent_ns != null);
Namespace ns_scope;
var ns_candidates = ns.Parent.LookupExtensionMethod (this, extensionType, name, arity, out ns_scope);
if (ns_candidates != null)
return new ExtensionMethodCandidates (ns_candidates, this, ns_scope);
//
// Continue in parent scope
// Continue in parent container
//
return parent.LookupExtensionMethod (extensionType, name, arity, ref scope);
return parent.LookupExtensionMethod (extensionType, name, arity);
}
public FullNamedExpression LookupNamespaceOrType (string name, int arity, LookupMode mode, Location loc)

194
ICSharpCode.NRefactory.CSharp/Parser/mcs/nullable.cs

@ -79,7 +79,7 @@ namespace Mono.CSharp.Nullable @@ -79,7 +79,7 @@ namespace Mono.CSharp.Nullable
}
}
public class Unwrap : Expression, IMemoryLocation, IAssignMethod
public class Unwrap : Expression, IMemoryLocation
{
Expression expr;
@ -96,6 +96,11 @@ namespace Mono.CSharp.Nullable @@ -96,6 +96,11 @@ namespace Mono.CSharp.Nullable
eclass = expr.eclass;
}
public override bool ContainsEmitWithAwait ()
{
return expr.ContainsEmitWithAwait ();
}
public static Expression Create (Expression expr)
{
//
@ -132,16 +137,24 @@ namespace Mono.CSharp.Nullable @@ -132,16 +137,24 @@ namespace Mono.CSharp.Nullable
public override void Emit (EmitContext ec)
{
Store (ec);
var call = new CallEmitter ();
call.InstanceExpression = this;
if (useDefaultValue)
Invocation.EmitCall (ec, this, NullableInfo.GetGetValueOrDefault (expr.Type), null, loc);
call.EmitPredefined (ec, NullableInfo.GetGetValueOrDefault (expr.Type), null);
else
Invocation.EmitCall (ec, this, NullableInfo.GetValue (expr.Type), null, loc);
call.EmitPredefined (ec, NullableInfo.GetValue (expr.Type), null);
}
public void EmitCheck (EmitContext ec)
{
Store (ec);
Invocation.EmitCall (ec, this, NullableInfo.GetHasValue (expr.Type), null, loc);
var call = new CallEmitter ();
call.InstanceExpression = this;
call.EmitPredefined (ec, NullableInfo.GetHasValue (expr.Type), null);
}
public override bool Equals (object obj)
@ -169,10 +182,10 @@ namespace Mono.CSharp.Nullable @@ -169,10 +182,10 @@ namespace Mono.CSharp.Nullable
void Store (EmitContext ec)
{
if (expr is VariableReference)
if (temp != null)
return;
if (temp != null)
if (expr is VariableReference)
return;
expr.Emit (ec);
@ -211,51 +224,6 @@ namespace Mono.CSharp.Nullable @@ -211,51 +224,6 @@ namespace Mono.CSharp.Nullable
return temp;
}
}
public void Emit (EmitContext ec, bool leave_copy)
{
if (leave_copy)
Load (ec);
Emit (ec);
}
public void EmitAssign (EmitContext ec, Expression source,
bool leave_copy, bool prepare_for_load)
{
InternalWrap wrap = new InternalWrap (source, expr.Type, loc);
((IAssignMethod) expr).EmitAssign (ec, wrap, leave_copy, false);
}
class InternalWrap : Expression
{
public Expression expr;
public InternalWrap (Expression expr, TypeSpec type, Location loc)
{
this.expr = expr;
this.loc = loc;
this.type = type;
eclass = ExprClass.Value;
}
public override Expression CreateExpressionTree (ResolveContext ec)
{
throw new NotSupportedException ("ET");
}
protected override Expression DoResolve (ResolveContext ec)
{
return this;
}
public override void Emit (EmitContext ec)
{
expr.Emit (ec);
ec.Emit (OpCodes.Newobj, NullableInfo.GetConstructor (type));
}
}
}
//
@ -280,7 +248,9 @@ namespace Mono.CSharp.Nullable @@ -280,7 +248,9 @@ namespace Mono.CSharp.Nullable
public override void Emit (EmitContext ec)
{
Invocation.EmitCall (ec, Child, NullableInfo.GetValue (Child.Type), null, loc);
var call = new CallEmitter ();
call.InstanceExpression = Child;
call.EmitPredefined (ec, NullableInfo.GetValue (Child.Type), null);
}
}
@ -354,6 +324,7 @@ namespace Mono.CSharp.Nullable @@ -354,6 +324,7 @@ namespace Mono.CSharp.Nullable
value_target.AddressOf (ec, AddressOp.Store);
ec.Emit (OpCodes.Initobj, type);
value_target.Emit (ec);
value_target.Release (ec);
}
public void AddressOf (EmitContext ec, AddressOp Mode)
@ -386,6 +357,11 @@ namespace Mono.CSharp.Nullable @@ -386,6 +357,11 @@ namespace Mono.CSharp.Nullable
: this (expr, unwrap as Unwrap, type)
{
}
public override bool ContainsEmitWithAwait ()
{
return unwrap.ContainsEmitWithAwait ();
}
public override Expression CreateExpressionTree (ResolveContext ec)
{
@ -677,7 +653,7 @@ namespace Mono.CSharp.Nullable @@ -677,7 +653,7 @@ namespace Mono.CSharp.Nullable
}
left_unwrap.Emit (ec);
ec.Emit (OpCodes.Brtrue_S, load_right);
ec.Emit (OpCodes.Brtrue, load_right);
// value & null, value | null
if (right_unwrap != null) {
@ -733,7 +709,7 @@ namespace Mono.CSharp.Nullable @@ -733,7 +709,7 @@ namespace Mono.CSharp.Nullable
if (left_unwrap != null && (IsRightNullLifted || right.IsNull)) {
left_unwrap.EmitCheck (ec);
if (Oper == Binary.Operator.Equality) {
ec.Emit (OpCodes.Ldc_I4_0);
ec.EmitInt (0);
ec.Emit (OpCodes.Ceq);
}
return;
@ -742,7 +718,7 @@ namespace Mono.CSharp.Nullable @@ -742,7 +718,7 @@ namespace Mono.CSharp.Nullable
if (right_unwrap != null && (IsLeftNullLifted || left.IsNull)) {
right_unwrap.EmitCheck (ec);
if (Oper == Binary.Operator.Equality) {
ec.Emit (OpCodes.Ldc_I4_0);
ec.EmitInt (0);
ec.Emit (OpCodes.Ceq);
}
return;
@ -755,6 +731,11 @@ namespace Mono.CSharp.Nullable @@ -755,6 +731,11 @@ namespace Mono.CSharp.Nullable
user_operator.Emit (ec);
ec.Emit (Oper == Operator.Equality ? OpCodes.Brfalse_S : OpCodes.Brtrue_S, dissimilar_label);
} else {
if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
left = left.EmitToField (ec);
right = right.EmitToField (ec);
}
left.Emit (ec);
right.Emit (ec);
@ -774,7 +755,7 @@ namespace Mono.CSharp.Nullable @@ -774,7 +755,7 @@ namespace Mono.CSharp.Nullable
ec.Emit (OpCodes.Ceq);
} else {
if (Oper == Operator.Inequality) {
ec.Emit (OpCodes.Ldc_I4_0);
ec.EmitInt (0);
ec.Emit (OpCodes.Ceq);
}
}
@ -783,9 +764,9 @@ namespace Mono.CSharp.Nullable @@ -783,9 +764,9 @@ namespace Mono.CSharp.Nullable
ec.MarkLabel (dissimilar_label);
if (Oper == Operator.Inequality)
ec.Emit (OpCodes.Ldc_I4_1);
ec.EmitInt (1);
else
ec.Emit (OpCodes.Ldc_I4_0);
ec.EmitInt (0);
ec.MarkLabel (end_label);
}
@ -839,7 +820,7 @@ namespace Mono.CSharp.Nullable @@ -839,7 +820,7 @@ namespace Mono.CSharp.Nullable
ec.MarkLabel (is_null_label);
if ((Oper & Operator.ComparisonMask) != 0) {
ec.Emit (OpCodes.Ldc_I4_0);
ec.EmitInt (0);
} else {
LiftedNull.Create (type, loc).Emit (ec);
}
@ -854,8 +835,14 @@ namespace Mono.CSharp.Nullable @@ -854,8 +835,14 @@ namespace Mono.CSharp.Nullable
return;
}
if (l.IsNullableType)
l = TypeManager.GetTypeArguments (l) [0];
if (left.Type.IsNullableType) {
l = NullableInfo.GetUnderlyingType (left.Type);
left = EmptyCast.Create (left, l);
}
if (right.Type.IsNullableType) {
right = EmptyCast.Create (right, NullableInfo.GetUnderlyingType (right.Type));
}
base.EmitOperator (ec, l);
}
@ -1149,6 +1136,14 @@ namespace Mono.CSharp.Nullable @@ -1149,6 +1136,14 @@ namespace Mono.CSharp.Nullable
return this;
}
public override bool ContainsEmitWithAwait ()
{
if (unwrap != null)
return unwrap.ContainsEmitWithAwait () || right.ContainsEmitWithAwait ();
return left.ContainsEmitWithAwait () || right.ContainsEmitWithAwait ();
}
protected override Expression DoResolve (ResolveContext ec)
{
left = left.Resolve (ec);
@ -1217,75 +1212,58 @@ namespace Mono.CSharp.Nullable @@ -1217,75 +1212,58 @@ namespace Mono.CSharp.Nullable
}
}
public class LiftedUnaryMutator : ExpressionStatement
class LiftedUnaryMutator : UnaryMutator
{
public readonly UnaryMutator.Mode Mode;
Expression expr;
UnaryMutator underlying;
Unwrap unwrap;
public LiftedUnaryMutator (UnaryMutator.Mode mode, Expression expr, Location loc)
public LiftedUnaryMutator (Mode mode, Expression expr, Location loc)
: base (mode, expr, loc)
{
this.expr = expr;
this.Mode = mode;
this.loc = loc;
}
public override Expression CreateExpressionTree (ResolveContext ec)
{
return new SimpleAssign (this, this).CreateExpressionTree (ec);
}
protected override Expression DoResolve (ResolveContext ec)
{
expr = expr.Resolve (ec);
if (expr == null)
return null;
unwrap = Unwrap.Create (expr, false);
if (unwrap == null)
return null;
var orig_expr = expr;
underlying = (UnaryMutator) new UnaryMutator (Mode, unwrap, loc).Resolve (ec);
if (underlying == null)
return null;
expr = Unwrap.Create (expr);
var res = base.DoResolveOperation (ec);
eclass = ExprClass.Value;
expr = orig_expr;
type = expr.Type;
return this;
return res;
}
void DoEmit (EmitContext ec, bool is_expr)
protected override void EmitOperation (EmitContext ec)
{
Label is_null_label = ec.DefineLabel ();
Label end_label = ec.DefineLabel ();
unwrap.EmitCheck (ec);
LocalTemporary lt = new LocalTemporary (type);
// Value is on the stack
lt.Store (ec);
var call = new CallEmitter ();
call.InstanceExpression = lt;
call.EmitPredefined (ec, NullableInfo.GetHasValue (expr.Type), null);
ec.Emit (OpCodes.Brfalse, is_null_label);
if (is_expr) {
underlying.Emit (ec);
ec.Emit (OpCodes.Br_S, end_label);
} else {
underlying.EmitStatement (ec);
}
call = new CallEmitter ();
call.InstanceExpression = lt;
call.EmitPredefined (ec, NullableInfo.GetValue (expr.Type), null);
ec.MarkLabel (is_null_label);
if (is_expr)
LiftedNull.Create (type, loc).Emit (ec);
lt.Release (ec);
ec.MarkLabel (end_label);
}
base.EmitOperation (ec);
public override void Emit (EmitContext ec)
{
DoEmit (ec, true);
}
ec.Emit (OpCodes.Newobj, NullableInfo.GetConstructor (type));
ec.Emit (OpCodes.Br_S, end_label);
public override void EmitStatement (EmitContext ec)
{
DoEmit (ec, false);
ec.MarkLabel (is_null_label);
LiftedNull.Create (type, loc).Emit (ec);
ec.MarkLabel (end_label);
}
}
}

32
ICSharpCode.NRefactory.CSharp/Parser/mcs/parameter.cs

@ -616,40 +616,20 @@ namespace Mono.CSharp { @@ -616,40 +616,20 @@ namespace Mono.CSharp {
public void Emit (EmitContext ec)
{
int arg_idx = idx;
if (!ec.IsStatic)
arg_idx++;
ParameterReference.EmitLdArg (ec, arg_idx);
ec.EmitArgumentLoad (idx);
}
public void EmitAssign (EmitContext ec)
{
int arg_idx = idx;
if (!ec.IsStatic)
arg_idx++;
if (arg_idx <= 255)
ec.Emit (OpCodes.Starg_S, (byte) arg_idx);
else
ec.Emit (OpCodes.Starg, arg_idx);
ec.EmitArgumentStore (idx);
}
public void EmitAddressOf (EmitContext ec)
{
int arg_idx = idx;
if (!ec.IsStatic)
arg_idx++;
bool is_ref = (ModFlags & Modifier.ISBYREF) != 0;
if (is_ref) {
ParameterReference.EmitLdArg (ec, arg_idx);
if ((ModFlags & Modifier.ISBYREF) != 0) {
ec.EmitArgumentLoad (idx);
} else {
if (arg_idx <= 255)
ec.Emit (OpCodes.Ldarga_S, (byte) arg_idx);
else
ec.Emit (OpCodes.Ldarga, arg_idx);
ec.EmitArgumentAddress (idx);
}
}
@ -1298,7 +1278,7 @@ namespace Mono.CSharp { @@ -1298,7 +1278,7 @@ namespace Mono.CSharp {
type.GetSignatureForError (), parameter_type.GetSignatureForError ());
}
public virtual object Accept (StructuralVisitor visitor)
public override object Accept (StructuralVisitor visitor)
{
return visitor.Visit (this);
}

79
ICSharpCode.NRefactory.CSharp/Parser/mcs/pending.cs

@ -51,6 +51,78 @@ namespace Mono.CSharp { @@ -51,6 +51,78 @@ namespace Mono.CSharp {
public MethodSpec [] need_proxy;
}
struct ProxyMethodContext : IMemberContext
{
readonly TypeContainer container;
public ProxyMethodContext (TypeContainer container)
{
this.container = container;
}
public TypeSpec CurrentType {
get {
throw new NotImplementedException ();
}
}
public TypeParameter[] CurrentTypeParameters {
get {
throw new NotImplementedException ();
}
}
public MemberCore CurrentMemberDefinition {
get {
throw new NotImplementedException ();
}
}
public bool IsObsolete {
get {
return false;
}
}
public bool IsUnsafe {
get {
throw new NotImplementedException ();
}
}
public bool IsStatic {
get {
return false;
}
}
public ModuleContainer Module {
get {
return container.Module;
}
}
public string GetSignatureForError ()
{
throw new NotImplementedException ();
}
public ExtensionMethodCandidates LookupExtensionMethod (TypeSpec extensionType, string name, int arity)
{
throw new NotImplementedException ();
}
public FullNamedExpression LookupNamespaceOrType (string name, int arity, LookupMode mode, Location loc)
{
throw new NotImplementedException ();
}
public FullNamedExpression LookupNamespaceAlias (string name)
{
throw new NotImplementedException ();
}
}
public class PendingImplementation
{
/// <summary>
@ -434,10 +506,11 @@ namespace Mono.CSharp { @@ -434,10 +506,11 @@ namespace Mono.CSharp {
}
int top = param.Count;
var ec = new EmitContext (null, proxy.GetILGenerator (), null);
var ec = new EmitContext (new ProxyMethodContext (container), proxy.GetILGenerator (), null);
ec.EmitThis ();
// TODO: GetAllParametersArguments
for (int i = 0; i <= top; i++)
ParameterReference.EmitLdArg (ec, i);
for (int i = 0; i < top; i++)
ec.EmitArgumentLoad (i);
ec.Emit (OpCodes.Call, base_method);
ec.Emit (OpCodes.Ret);

8
ICSharpCode.NRefactory.CSharp/Parser/mcs/report.cs

@ -2,9 +2,10 @@ @@ -2,9 +2,10 @@
// report.cs: report errors and warnings.
//
// Author: Miguel de Icaza (miguel@ximian.com)
// Marek Safar (marek.safar@seznam.cz)
// Marek Safar (marek.safar@gmail.com)
//
// Copyright 2001 Ximian, Inc. (http://www.ximian.com)
// Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
//
using System;
@ -62,7 +63,7 @@ namespace Mono.CSharp { @@ -62,7 +63,7 @@ namespace Mono.CSharp {
1522, 1570, 1571, 1572, 1573, 1574, 1580, 1581, 1584, 1587, 1589, 1590, 1591, 1592,
1607, 1616, 1633, 1634, 1635, 1685, 1690, 1691, 1692, 1695, 1696, 1699,
1700, 1701, 1702, 1709, 1711, 1717, 1718, 1720, 1735,
1901, 1956, 1981,
1901, 1956, 1981, 1998,
2002, 2023, 2029,
3000, 3001, 3002, 3003, 3005, 3006, 3007, 3008, 3009,
3010, 3011, 3012, 3013, 3014, 3015, 3016, 3017, 3018, 3019,
@ -103,6 +104,9 @@ namespace Mono.CSharp { @@ -103,6 +104,9 @@ namespace Mono.CSharp {
case LanguageVersion.V_3:
version = "3.0";
break;
case LanguageVersion.V_4:
version = "4.0";
break;
default:
throw new InternalErrorException ("Invalid feature version", compiler.Settings.Version);
}

2
ICSharpCode.NRefactory.CSharp/Parser/mcs/roottypes.cs

@ -608,7 +608,7 @@ namespace Mono.CSharp @@ -608,7 +608,7 @@ namespace Mono.CSharp
return PartialContainer.IsClsComplianceRequired ();
}
public override IList<MethodSpec> LookupExtensionMethod (TypeSpec extensionType, string name, int arity, ref NamespaceContainer scope)
public override ExtensionMethodCandidates LookupExtensionMethod (TypeSpec extensionType, string name, int arity)
{
return null;
}

297
ICSharpCode.NRefactory.CSharp/Parser/mcs/statement.cs

@ -8,6 +8,7 @@ @@ -8,6 +8,7 @@
//
// Copyright 2001, 2002, 2003 Ximian, Inc.
// Copyright 2003, 2004 Novell, Inc.
// Copyright 2011 Xamarin Inc.
//
using System;
@ -732,8 +733,6 @@ namespace Mono.CSharp { @@ -732,8 +733,6 @@ namespace Mono.CSharp {
return false;
unwind_protect = ec.CurrentBranching.AddReturnOrigin (ec.CurrentBranching.CurrentUsageVector, this);
if (unwind_protect)
ec.NeedReturnLabel ();
ec.CurrentBranching.CurrentUsageVector.Goto ();
return true;
}
@ -872,9 +871,12 @@ namespace Mono.CSharp { @@ -872,9 +871,12 @@ namespace Mono.CSharp {
var async_return = ((AsyncTaskStorey) async_body.Storey).HoistedReturn;
// It's null for await without async
if (async_return != null)
if (async_return != null) {
async_return.EmitAssign (ec);
ec.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, async_body.BodyEnd);
}
return;
}
@ -883,7 +885,7 @@ namespace Mono.CSharp { @@ -883,7 +885,7 @@ namespace Mono.CSharp {
}
if (unwind_protect)
ec.Emit (OpCodes.Leave, ec.ReturnLabel);
ec.Emit (OpCodes.Leave, ec.CreateReturnLabel ());
else
ec.Emit (OpCodes.Ret);
}
@ -1413,6 +1415,11 @@ namespace Mono.CSharp { @@ -1413,6 +1415,11 @@ namespace Mono.CSharp {
}
public override bool Resolve (BlockContext bc)
{
return Resolve (bc, true);
}
public bool Resolve (BlockContext bc, bool resolveDeclaratorInitializers)
{
if (li.Type == null) {
TypeSpec type = null;
@ -1490,10 +1497,10 @@ namespace Mono.CSharp { @@ -1490,10 +1497,10 @@ namespace Mono.CSharp {
d.Variable.PrepareForFlowAnalysis (bc);
}
if (d.Initializer != null) {
if (d.Initializer != null && resolveDeclaratorInitializers) {
d.Initializer = ResolveInitializer (bc, d.Variable, d.Initializer);
// d.Variable.DefinitelyAssigned
}
}
}
}
@ -1773,7 +1780,7 @@ namespace Mono.CSharp { @@ -1773,7 +1780,7 @@ namespace Mono.CSharp {
public static LocalVariable CreateCompilerGenerated (TypeSpec type, Block block, Location loc)
{
LocalVariable li = new LocalVariable (block, "<$$>", Flags.CompilerGenerated | Flags.Used, loc);
LocalVariable li = new LocalVariable (block, GetCompilerGeneratedName (block), Flags.CompilerGenerated | Flags.Used, loc);
li.Type = type;
return li;
}
@ -1809,6 +1816,11 @@ namespace Mono.CSharp { @@ -1809,6 +1816,11 @@ namespace Mono.CSharp {
ec.Emit (OpCodes.Ldloca, builder);
}
public static string GetCompilerGeneratedName (Block block)
{
return "$locvar" + block.ParametersBlock.TemporaryLocalsCount++.ToString ("X");
}
public string GetReadOnlyContext ()
{
switch (flags & Flags.ReadonlyMask) {
@ -2304,8 +2316,8 @@ namespace Mono.CSharp { @@ -2304,8 +2316,8 @@ namespace Mono.CSharp {
//
// An iterator has only 1 storey block
//
if (ec.CurrentIterator != null)
return ec.CurrentIterator.Storey;
if (ec.CurrentAnonymousMethod.IsIterator)
return ec.CurrentAnonymousMethod.Storey;
//
// When referencing a variable in iterator storey from children anonymous method
@ -2487,6 +2499,11 @@ namespace Mono.CSharp { @@ -2487,6 +2499,11 @@ namespace Mono.CSharp {
this.block = block;
}
public override bool ContainsEmitWithAwait ()
{
return child.ContainsEmitWithAwait ();
}
public override Expression CreateExpressionTree (ResolveContext ec)
{
throw new NotSupportedException ();
@ -2607,6 +2624,8 @@ namespace Mono.CSharp { @@ -2607,6 +2624,8 @@ namespace Mono.CSharp {
}
}
public int TemporaryLocalsCount { get; set; }
#endregion
// <summary>
@ -2781,7 +2800,7 @@ namespace Mono.CSharp { @@ -2781,7 +2800,7 @@ namespace Mono.CSharp {
AddStatement (new Return (iterator, iterator.Location));
}
public void WrapIntoAsyncTask (TypeContainer host, TypeSpec returnType)
public void WrapIntoAsyncTask (IMemberContext context, TypeContainer host, TypeSpec returnType)
{
ParametersBlock pb = new ParametersBlock (this, ParametersCompiled.EmptyReadOnlyParameters, StartLocation);
pb.EndLocation = EndLocation;
@ -2791,7 +2810,7 @@ namespace Mono.CSharp { @@ -2791,7 +2810,7 @@ namespace Mono.CSharp {
var initializer = new AsyncInitializer (pb, host, block_type);
initializer.Type = block_type;
am_storey = new AsyncTaskStorey (initializer, returnType);
am_storey = new AsyncTaskStorey (context, initializer, returnType);
statements = new List<Statement> (1);
AddStatement (new StatementExpression (initializer));
@ -3119,8 +3138,6 @@ namespace Mono.CSharp { @@ -3119,8 +3138,6 @@ namespace Mono.CSharp {
#if PRODUCTION
try {
#endif
if (ec.HasReturnLabel)
ec.ReturnLabel = ec.DefineLabel ();
base.Emit (ec);
@ -4063,21 +4080,16 @@ namespace Mono.CSharp { @@ -4063,21 +4080,16 @@ namespace Mono.CSharp {
}
}
// Base class for statements that are implemented in terms of try...finally
public abstract class ExceptionStatement : ResumableStatement
public abstract class TryFinallyBlock : ExceptionStatement
{
bool code_follows;
Iterator iter;
List<ResumableStatement> resume_points;
int first_resume_pc;
protected Statement stmt;
Label dispose_try_block;
bool prepared_for_dispose, emitted_dispose;
protected ExceptionStatement (Statement stmt, Location loc)
protected TryFinallyBlock (Statement stmt, Location loc)
: base (loc)
{
this.stmt = stmt;
this.loc = loc;
}
#region Properties
@ -4090,43 +4102,30 @@ namespace Mono.CSharp { @@ -4090,43 +4102,30 @@ namespace Mono.CSharp {
#endregion
protected abstract void EmitPreTryBody (EmitContext ec);
protected abstract void EmitTryBody (EmitContext ec);
protected abstract void EmitFinallyBody (EmitContext ec);
protected sealed override void DoEmit (EmitContext ec)
public override Label PrepareForDispose (EmitContext ec, Label end)
{
EmitPreTryBody (ec);
if (resume_points != null) {
ec.EmitInt ((int) IteratorStorey.State.Running);
ec.Emit (OpCodes.Stloc, iter.CurrentPC);
}
ec.BeginExceptionBlock ();
if (resume_points != null) {
ec.MarkLabel (resume_point);
// For normal control flow, we want to fall-through the Switch
// So, we use CurrentPC rather than the $PC field, and initialize it to an outside value above
ec.Emit (OpCodes.Ldloc, iter.CurrentPC);
ec.EmitInt (first_resume_pc);
ec.Emit (OpCodes.Sub);
Label [] labels = new Label [resume_points.Count];
for (int i = 0; i < resume_points.Count; ++i)
labels [i] = resume_points [i].PrepareForEmit (ec);
ec.Emit (OpCodes.Switch, labels);
if (!prepared_for_dispose) {
prepared_for_dispose = true;
dispose_try_block = ec.DefineLabel ();
}
return dispose_try_block;
}
protected sealed override void DoEmit (EmitContext ec)
{
EmitTryBodyPrepare (ec);
EmitTryBody (ec);
ec.BeginFinallyBlock ();
Label start_finally = ec.DefineLabel ();
if (resume_points != null) {
ec.Emit (OpCodes.Ldloc, iter.SkipFinally);
var state_machine = (StateMachineInitializer) ec.CurrentAnonymousMethod;
ec.Emit (OpCodes.Ldloc, state_machine.SkipFinally);
ec.Emit (OpCodes.Brfalse_S, start_finally);
ec.Emit (OpCodes.Endfinally);
}
@ -4137,44 +4136,6 @@ namespace Mono.CSharp { @@ -4137,44 +4136,6 @@ namespace Mono.CSharp {
ec.EndExceptionBlock ();
}
public void SomeCodeFollows ()
{
code_follows = true;
}
public override bool Resolve (BlockContext ec)
{
// System.Reflection.Emit automatically emits a 'leave' at the end of a try clause
// So, ensure there's some IL code after this statement.
if (!code_follows && resume_points == null && ec.CurrentBranching.CurrentUsageVector.IsUnreachable)
ec.NeedReturnLabel ();
iter = ec.CurrentIterator;
return true;
}
public void AddResumePoint (ResumableStatement stmt, int pc)
{
if (resume_points == null) {
resume_points = new List<ResumableStatement> ();
first_resume_pc = pc;
}
if (pc != first_resume_pc + resume_points.Count)
throw new InternalErrorException ("missed an intervening AddResumePoint?");
resume_points.Add (stmt);
}
public override Label PrepareForDispose (EmitContext ec, Label end)
{
if (!prepared_for_dispose) {
prepared_for_dispose = true;
dispose_try_block = ec.DefineLabel ();
}
return dispose_try_block;
}
public override void EmitForDispose (EmitContext ec, LocalBuilder pc, Label end, bool have_dispatcher)
{
if (emitted_dispose)
@ -4192,24 +4153,24 @@ namespace Mono.CSharp { @@ -4192,24 +4153,24 @@ namespace Mono.CSharp {
ec.MarkLabel (dispose_try_block);
Label [] labels = null;
Label[] labels = null;
for (int i = 0; i < resume_points.Count; ++i) {
ResumableStatement s = resume_points [i];
ResumableStatement s = resume_points[i];
Label ret = s.PrepareForDispose (ec, end_of_try);
if (ret.Equals (end_of_try) && labels == null)
continue;
if (labels == null) {
labels = new Label [resume_points.Count];
labels = new Label[resume_points.Count];
for (int j = 0; j < i; ++j)
labels [j] = end_of_try;
labels[j] = end_of_try;
}
labels [i] = ret;
labels[i] = ret;
}
if (labels != null) {
int j;
for (j = 1; j < labels.Length; ++j)
if (!labels [0].Equals (labels [j]))
if (!labels[0].Equals (labels[j]))
break;
bool emit_dispatcher = j < labels.Length;
@ -4236,7 +4197,84 @@ namespace Mono.CSharp { @@ -4236,7 +4197,84 @@ namespace Mono.CSharp {
}
}
public class Lock : ExceptionStatement
//
// Base class for blocks using exception handling
//
public abstract class ExceptionStatement : ResumableStatement
{
#if !STATIC
bool code_follows;
#endif
protected List<ResumableStatement> resume_points;
protected int first_resume_pc;
protected ExceptionStatement (Location loc)
{
this.loc = loc;
}
protected virtual void EmitTryBodyPrepare (EmitContext ec)
{
StateMachineInitializer state_machine = null;
if (resume_points != null) {
state_machine = (StateMachineInitializer) ec.CurrentAnonymousMethod;
ec.EmitInt ((int) IteratorStorey.State.Running);
ec.Emit (OpCodes.Stloc, state_machine.CurrentPC);
}
ec.BeginExceptionBlock ();
if (resume_points != null) {
ec.MarkLabel (resume_point);
// For normal control flow, we want to fall-through the Switch
// So, we use CurrentPC rather than the $PC field, and initialize it to an outside value above
ec.Emit (OpCodes.Ldloc, state_machine.CurrentPC);
ec.EmitInt (first_resume_pc);
ec.Emit (OpCodes.Sub);
Label[] labels = new Label[resume_points.Count];
for (int i = 0; i < resume_points.Count; ++i)
labels[i] = resume_points[i].PrepareForEmit (ec);
ec.Emit (OpCodes.Switch, labels);
}
}
public void SomeCodeFollows ()
{
#if !STATIC
code_follows = true;
#endif
}
public override bool Resolve (BlockContext ec)
{
#if !STATIC
// System.Reflection.Emit automatically emits a 'leave' at the end of a try clause
// So, ensure there's some IL code after this statement.
if (!code_follows && resume_points == null && ec.CurrentBranching.CurrentUsageVector.IsUnreachable)
ec.NeedReturnLabel ();
#endif
return true;
}
public void AddResumePoint (ResumableStatement stmt, int pc)
{
if (resume_points == null) {
resume_points = new List<ResumableStatement> ();
first_resume_pc = pc;
}
if (pc != first_resume_pc + resume_points.Count)
throw new InternalErrorException ("missed an intervening AddResumePoint?");
resume_points.Add (stmt);
}
}
public class Lock : TryFinallyBlock
{
Expression expr;
TemporaryVariableReference expr_copy;
@ -4294,21 +4332,21 @@ namespace Mono.CSharp { @@ -4294,21 +4332,21 @@ namespace Mono.CSharp {
// Have to keep original lock value around to unlock same location
// in the case the original has changed or is null
//
expr_copy = TemporaryVariableReference.Create (ec.BuiltinTypes.Object, ec.CurrentBlock.Parent, loc);
expr_copy = TemporaryVariableReference.Create (ec.BuiltinTypes.Object, ec.CurrentBlock, loc);
expr_copy.Resolve (ec);
//
// Ensure Monitor methods are available
//
if (ResolvePredefinedMethods (ec) > 1) {
lock_taken = TemporaryVariableReference.Create (ec.BuiltinTypes.Bool, ec.CurrentBlock.Parent, loc);
lock_taken = TemporaryVariableReference.Create (ec.BuiltinTypes.Bool, ec.CurrentBlock, loc);
lock_taken.Resolve (ec);
}
return true;
}
protected override void EmitPreTryBody (EmitContext ec)
protected override void EmitTryBodyPrepare (EmitContext ec)
{
expr_copy.EmitAssign (ec, expr);
@ -4324,6 +4362,8 @@ namespace Mono.CSharp { @@ -4324,6 +4362,8 @@ namespace Mono.CSharp {
expr_copy.Emit (ec);
ec.Emit (OpCodes.Call, ec.Module.PredefinedMembers.MonitorEnter.Get ());
}
base.EmitTryBodyPrepare (ec);
}
protected override void EmitTryBody (EmitContext ec)
@ -4409,7 +4449,7 @@ namespace Mono.CSharp { @@ -4409,7 +4449,7 @@ namespace Mono.CSharp {
protected override void DoEmit (EmitContext ec)
{
using (ec.With (EmitContext.Options.AllCheckStateFlags, false))
using (ec.With (EmitContext.Options.CheckedScope, false))
Block.Emit (ec);
}
@ -4444,7 +4484,7 @@ namespace Mono.CSharp { @@ -4444,7 +4484,7 @@ namespace Mono.CSharp {
protected override void DoEmit (EmitContext ec)
{
using (ec.With (EmitContext.Options.AllCheckStateFlags, true))
using (ec.With (EmitContext.Options.CheckedScope, true))
Block.Emit (ec);
}
@ -4537,7 +4577,7 @@ namespace Mono.CSharp { @@ -4537,7 +4577,7 @@ namespace Mono.CSharp {
public override void EmitExit (EmitContext ec)
{
ec.Emit (OpCodes.Ldc_I4_0);
ec.EmitInt (0);
ec.Emit (OpCodes.Conv_U);
vi.EmitAssign (ec);
}
@ -4589,7 +4629,7 @@ namespace Mono.CSharp { @@ -4589,7 +4629,7 @@ namespace Mono.CSharp {
public override void EmitExit (EmitContext ec)
{
ec.Emit (OpCodes.Ldnull);
ec.EmitNull ();
pinned_string.EmitAssign (ec);
}
}
@ -4910,7 +4950,8 @@ namespace Mono.CSharp { @@ -4910,7 +4950,8 @@ namespace Mono.CSharp {
}
}
public class TryFinally : ExceptionStatement {
public class TryFinally : TryFinallyBlock
{
Block fini;
public Statement Stmt {
@ -4950,10 +4991,6 @@ namespace Mono.CSharp { @@ -4950,10 +4991,6 @@ namespace Mono.CSharp {
return ok;
}
protected override void EmitPreTryBody (EmitContext ec)
{
}
protected override void EmitTryBody (EmitContext ec)
{
stmt.Emit (ec);
@ -4979,13 +5016,15 @@ namespace Mono.CSharp { @@ -4979,13 +5016,15 @@ namespace Mono.CSharp {
}
}
public class TryCatch : Statement {
public class TryCatch : ExceptionStatement
{
public Block Block;
public List<Catch> Specific;
public Catch General;
bool inside_try_finally, code_follows;
readonly bool inside_try_finally;
public TryCatch (Block block, List<Catch> catch_clauses, Location l, bool inside_try_finally)
: base (l)
{
this.Block = block;
this.Specific = catch_clauses;
@ -4996,8 +5035,12 @@ namespace Mono.CSharp { @@ -4996,8 +5035,12 @@ namespace Mono.CSharp {
this.General = c;
catch_clauses.RemoveAt (0);
}
}
loc = l;
public bool IsTryCatchFinally {
get {
return inside_try_finally;
}
}
public override bool Resolve (BlockContext ec)
@ -5055,23 +5098,13 @@ namespace Mono.CSharp { @@ -5055,23 +5098,13 @@ namespace Mono.CSharp {
ec.EndFlowBranching ();
// System.Reflection.Emit automatically emits a 'leave' at the end of a try/catch clause
// So, ensure there's some IL code after this statement
if (!inside_try_finally && !code_follows && ec.CurrentBranching.CurrentUsageVector.IsUnreachable)
ec.NeedReturnLabel ();
return ok;
return base.Resolve (ec) && ok;
}
public void SomeCodeFollows ()
{
code_follows = true;
}
protected override void DoEmit (EmitContext ec)
protected sealed override void DoEmit (EmitContext ec)
{
if (!inside_try_finally)
ec.BeginExceptionBlock ();
EmitTryBodyPrepare (ec);
Block.Emit (ec);
@ -5104,7 +5137,7 @@ namespace Mono.CSharp { @@ -5104,7 +5137,7 @@ namespace Mono.CSharp {
}
}
public class Using : ExceptionStatement
public class Using : TryFinallyBlock
{
public class VariableDeclaration : BlockVariableDeclaration
{
@ -5144,7 +5177,7 @@ namespace Mono.CSharp { @@ -5144,7 +5177,7 @@ namespace Mono.CSharp {
if (IsNested)
return true;
return base.Resolve (bc);
return base.Resolve (bc, false);
}
public Expression ResolveExpression (BlockContext bc)
@ -5230,7 +5263,12 @@ namespace Mono.CSharp { @@ -5230,7 +5263,12 @@ namespace Mono.CSharp {
return dispose;
}
public Statement RewriteForDeclarators (BlockContext bc, Statement stmt)
public void ResolveDeclaratorInitializer (BlockContext bc)
{
Initializer = base.ResolveInitializer (bc, Variable, Initializer);
}
public Statement RewriteUsingDeclarators (BlockContext bc, Statement stmt)
{
for (int i = declarators.Count - 1; i >= 0; --i) {
var d = declarators [i];
@ -5283,9 +5321,10 @@ namespace Mono.CSharp { @@ -5283,9 +5321,10 @@ namespace Mono.CSharp {
#endregion
protected override void EmitPreTryBody (EmitContext ec)
protected override void EmitTryBodyPrepare (EmitContext ec)
{
decl.Emit (ec);
base.EmitTryBodyPrepare (ec);
}
protected override void EmitTryBody (EmitContext ec)
@ -5311,11 +5350,15 @@ namespace Mono.CSharp { @@ -5311,11 +5350,15 @@ namespace Mono.CSharp {
vr.IsLockedByStatement = true;
}
} else {
if (!decl.Resolve (ec))
return false;
if (decl.IsNested) {
decl.ResolveDeclaratorInitializer (ec);
} else {
if (!decl.Resolve (ec))
return false;
if (decl.Declarators != null) {
stmt = decl.RewriteForDeclarators (ec, stmt);
if (decl.Declarators != null) {
stmt = decl.RewriteUsingDeclarators (ec, stmt);
}
}
vr = null;

2
ICSharpCode.NRefactory.CSharp/Parser/mcs/support.cs

@ -240,7 +240,7 @@ namespace Mono.CSharp { @@ -240,7 +240,7 @@ namespace Mono.CSharp {
public char[] ReadChars (int fromPosition, int toPosition)
{
char[] chars = new char[toPosition - fromPosition];
if (buffer_start <= fromPosition && toPosition < buffer_start + buffer.Length) {
if (buffer_start <= fromPosition && toPosition <= buffer_start + buffer.Length) {
Array.Copy (buffer, fromPosition - buffer_start, chars, 0, chars.Length);
} else {
throw new NotImplementedException ();

10
ICSharpCode.NRefactory.CSharp/Parser/mcs/typemanager.cs

@ -310,9 +310,11 @@ namespace Mono.CSharp @@ -310,9 +310,11 @@ namespace Mono.CSharp
public readonly PredefinedMember<MethodSpec> ActivatorCreateInstance;
public readonly PredefinedMember<MethodSpec> AsyncTaskMethodBuilderCreate;
public readonly PredefinedMember<MethodSpec> AsyncTaskMethodBuilderSetResult;
public readonly PredefinedMember<MethodSpec> AsyncTaskMethodBuilderSetException;
public readonly PredefinedMember<PropertySpec> AsyncTaskMethodBuilderTask;
public readonly PredefinedMember<MethodSpec> AsyncTaskMethodBuilderGenericCreate;
public readonly PredefinedMember<MethodSpec> AsyncTaskMethodBuilderGenericSetResult;
public readonly PredefinedMember<MethodSpec> AsyncTaskMethodBuilderGenericSetException;
public readonly PredefinedMember<PropertySpec> AsyncTaskMethodBuilderGenericTask;
public readonly PredefinedMember<MethodSpec> AsyncVoidMethodBuilderCreate;
public readonly PredefinedMember<MethodSpec> AsyncVoidMethodBuilderSetException;
@ -366,6 +368,10 @@ namespace Mono.CSharp @@ -366,6 +368,10 @@ namespace Mono.CSharp
AsyncTaskMethodBuilderSetResult = new PredefinedMember<MethodSpec> (module, types.AsyncTaskMethodBuilder,
MemberFilter.Method ("SetResult", 0, ParametersCompiled.EmptyReadOnlyParameters, btypes.Void));
AsyncTaskMethodBuilderSetException = new PredefinedMember<MethodSpec> (module, types.AsyncTaskMethodBuilder,
MemberFilter.Method ("SetException", 0,
ParametersCompiled.CreateFullyResolved (btypes.Exception), btypes.Void));
AsyncTaskMethodBuilderTask = new PredefinedMember<PropertySpec> (module, types.AsyncTaskMethodBuilder,
MemberFilter.Property ("Task", null));
@ -382,6 +388,10 @@ namespace Mono.CSharp @@ -382,6 +388,10 @@ namespace Mono.CSharp
new TypeParameterSpec (0, null, SpecialConstraint.None, Variance.None, null)
}, false), btypes.Void));
AsyncTaskMethodBuilderGenericSetException = new PredefinedMember<MethodSpec> (module, types.AsyncTaskMethodBuilderGeneric,
MemberFilter.Method ("SetException", 0,
ParametersCompiled.CreateFullyResolved (btypes.Exception), btypes.Void));
AsyncTaskMethodBuilderGenericTask = new PredefinedMember<PropertySpec> (module, types.AsyncTaskMethodBuilderGeneric,
MemberFilter.Property ("Task", null));

16
ICSharpCode.NRefactory.CSharp/Parser/mcs/typespec.cs

@ -6,6 +6,7 @@ @@ -6,6 +6,7 @@
// Dual licensed under the terms of the MIT X11 or GNU GPL
//
// Copyright 2010 Novell, Inc
// Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
//
using System;
@ -464,12 +465,13 @@ namespace Mono.CSharp @@ -464,12 +465,13 @@ namespace Mono.CSharp
{
var t = this;
do {
if (t.Interfaces != null) {
foreach (TypeSpec i in t.Interfaces) {
if (i == iface || TypeSpecComparer.IsEqual (i, iface))
var ifaces = t.Interfaces;
if (ifaces != null) {
for (int i = 0; i < ifaces.Count; ++i) {
if (TypeSpecComparer.IsEqual (ifaces[i], iface))
return true;
if (variantly && TypeSpecComparer.Variant.IsEqual (i, iface))
if (variantly && TypeSpecComparer.Variant.IsEqual (ifaces[i], iface))
return true;
}
}
@ -535,6 +537,7 @@ namespace Mono.CSharp @@ -535,6 +537,7 @@ namespace Mono.CSharp
return ((TypeParameterSpec) t).IsReferenceType;
case MemberKind.Struct:
case MemberKind.Enum:
case MemberKind.Void:
return false;
case MemberKind.InternalCompilerType:
//
@ -1016,10 +1019,11 @@ namespace Mono.CSharp @@ -1016,10 +1019,11 @@ namespace Mono.CSharp
}
for (int i = 0; i < targs_definition.Length; ++i) {
if (TypeSpecComparer.IsEqual (t1_targs[i], t2_targs[i]))
continue;
Variance v = targs_definition[i].Variance;
if (v == Variance.None) {
if (t1_targs[i] == t2_targs[i])
continue;
return false;
}

Loading…
Cancel
Save