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

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

@ -103,6 +103,28 @@ namespace Mono.CSharp
return Expr.CreateExpressionTree (ec); 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 () public string GetSignatureForError ()
{ {
if (Expr.eclass == ExprClass.MethodGroup) if (Expr.eclass == ExprClass.MethodGroup)
@ -141,21 +163,6 @@ namespace Mono.CSharp
Expr = ErrorExpression.Instance; 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 public class MovableArgument : Argument
@ -182,12 +189,12 @@ namespace Mono.CSharp
variable.Release (ec); variable.Release (ec);
} }
public void EmitAssign (EmitContext ec) public void EmitToVariable (EmitContext ec)
{ {
var type = Expr.Type; var type = Expr.Type;
if (IsByRef) { if (IsByRef) {
var ml = (IMemoryLocation) Expr; var ml = (IMemoryLocation) Expr;
ml.AddressOf (ec, AddressOp.Load); ml.AddressOf (ec, AddressOp.LoadStore);
type = ReferenceContainer.MakeType (ec.Module, type); type = ReferenceContainer.MakeType (ec.Module, type);
} else { } else {
Expr.Emit (ec); Expr.Emit (ec);
@ -246,13 +253,16 @@ namespace Mono.CSharp
ordered.Add (arg); 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) { 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
args = new List<Argument> (capacity); args = new List<Argument> (capacity);
} }
private Arguments (List<Argument> args)
{
this.args = args;
}
public void Add (Argument arg) public void Add (Argument arg)
{ {
args.Add (arg); args.Add (arg);
@ -274,6 +289,16 @@ namespace Mono.CSharp
this.args.AddRange (args.args); 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) public ArrayInitializer CreateDynamicBinderArguments (ResolveContext rc)
{ {
Location loc = Location.Null; Location loc = Location.Null;
@ -395,46 +420,58 @@ namespace Mono.CSharp
// //
public void Emit (EmitContext ec) 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 // if `dup_args' is true or any of arguments contains await.
// on the stack and return value will contain an array of access // A copy of all arguments will be returned to the caller
// expressions
// NOTE: It's caller responsibility is to release temporary variables
// //
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) if ((dup_args && Count != 0) || prepareAwait)
temps = new Expression [Count]; dups = new List<Argument> (Count);
else else
temps = null; dups = null;
int i = 0;
LocalTemporary lt; LocalTemporary lt;
foreach (Argument a in args) { foreach (Argument a in args) {
if (prepareAwait) {
dups.Add (a.EmitToField (ec));
continue;
}
a.Emit (ec); a.Emit (ec);
if (!dup_args)
if (!dup_args) {
continue; 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 { } else {
ec.Emit (OpCodes.Dup); 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); 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 () public List<Argument>.Enumerator GetEnumerator ()
@ -497,9 +534,9 @@ namespace Mono.CSharp
public Arguments MarkOrderedArgument (NamedArgument a) 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; return this;
ArgumentsOrdered ra = this as ArgumentsOrdered; ArgumentsOrdered ra = this as ArgumentsOrdered;
@ -511,6 +548,12 @@ namespace Mono.CSharp
if (la == a) if (la == a)
break; break;
//
// When the argument is filled later by default expression
//
if (la == null)
continue;
var ma = la as MovableArgument; var ma = la as MovableArgument;
if (ma == null) { if (ma == null) {
ma = new MovableArgument (la); ma = new MovableArgument (la);

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

@ -51,7 +51,7 @@ namespace Mono.CSharp {
// be data on the stack that it can use to compuatate its value. This is // 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. // 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 For simple assignments, this interface is very simple, EmitAssign is called with source
@ -201,6 +201,11 @@ namespace Mono.CSharp {
builder = null; builder = null;
} }
public override bool ContainsEmitWithAwait ()
{
return false;
}
public override Expression CreateExpressionTree (ResolveContext ec) public override Expression CreateExpressionTree (ResolveContext ec)
{ {
Arguments args = new Arguments (1); Arguments args = new Arguments (1);
@ -236,9 +241,9 @@ namespace Mono.CSharp {
Emit (ec); 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 (); throw new NotImplementedException ();
source.Emit (ec); source.Emit (ec);
@ -294,12 +299,6 @@ namespace Mono.CSharp {
this.loc = loc; 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 { public Expression Target {
get { return target; } get { return target; }
} }
@ -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) protected override Expression DoResolve (ResolveContext ec)
{ {
bool ok = true; bool ok = true;
@ -546,10 +556,6 @@ namespace Mono.CSharp {
base.EmitStatement (ec); base.EmitStatement (ec);
} }
public bool IsComplexInitializer {
get { return !(source is Constant); }
}
public bool IsDefaultInitializer { public bool IsDefaultInitializer {
get { get {
Constant c = source as Constant; Constant c = source as Constant;
@ -560,6 +566,12 @@ namespace Mono.CSharp {
return c.IsDefaultInitializer (fe.Type); return c.IsDefaultInitializer (fe.Type);
} }
} }
public override bool IsSideEffectFree {
get {
return source.IsSideEffectFree;
}
}
} }
// //
@ -570,13 +582,19 @@ namespace Mono.CSharp {
// This is just a hack implemented for arrays only // This is just a hack implemented for arrays only
public sealed class TargetExpression : Expression public sealed class TargetExpression : Expression
{ {
Expression child; readonly Expression child;
public TargetExpression (Expression child) public TargetExpression (Expression child)
{ {
this.child = child; this.child = child;
this.loc = child.Location; this.loc = child.Location;
} }
public override bool ContainsEmitWithAwait ()
{
return child.ContainsEmitWithAwait ();
}
public override Expression CreateExpressionTree (ResolveContext ec) public override Expression CreateExpressionTree (ResolveContext ec)
{ {
throw new NotSupportedException ("ET"); throw new NotSupportedException ("ET");
@ -593,6 +611,11 @@ namespace Mono.CSharp {
{ {
child.Emit (ec); child.Emit (ec);
} }
public override Expression EmitToField (EmitContext ec)
{
return child.EmitToField (ec);
}
} }
// Used for underlying binary operator // Used for underlying binary operator

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

@ -1,4 +1,4 @@
// //
// async.cs: Asynchronous functions // async.cs: Asynchronous functions
// //
// Author: // Author:
@ -7,11 +7,14 @@
// Dual licensed under the terms of the MIT X11 or GNU GPL // Dual licensed under the terms of the MIT X11 or GNU GPL
// //
// Copyright 2011 Novell, Inc. // Copyright 2011 Novell, Inc.
// Copyright 2011 Xamarin Inc.
// //
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Collections;
#if STATIC #if STATIC
using IKVM.Reflection.Emit; using IKVM.Reflection.Emit;
#else #else
@ -43,18 +46,13 @@ namespace Mono.CSharp
throw new NotImplementedException ("ET"); throw new NotImplementedException ("ET");
} }
protected override Expression DoResolve (ResolveContext rc) public override bool ContainsEmitWithAwait ()
{ {
if (rc.HasSet (ResolveContext.Options.FinallyScope)) { return true;
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");
}
protected override Expression DoResolve (ResolveContext rc)
{
if (rc.HasSet (ResolveContext.Options.LockScope)) { if (rc.HasSet (ResolveContext.Options.LockScope)) {
rc.Report.Error (1996, loc, rc.Report.Error (1996, loc,
"The `await' operator cannot be used in the body of a lock statement"); "The `await' operator cannot be used in the body of a lock statement");
@ -92,7 +90,13 @@ namespace Mono.CSharp
stmt.EmitPrologue (ec); stmt.EmitPrologue (ec);
stmt.Emit (ec); stmt.Emit (ec);
} }
public override Expression EmitToField (EmitContext ec)
{
stmt.EmitPrologue (ec);
return stmt.GetResultExpression (ec);
}
public void EmitAssign (EmitContext ec, FieldExpr field) public void EmitAssign (EmitContext ec, FieldExpr field)
{ {
stmt.EmitPrologue (ec); stmt.EmitPrologue (ec);
@ -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; Field awaiter;
PropertyExpr is_completed; PropertySpec is_completed;
MethodSpec on_completed; MethodSpec on_completed;
MethodSpec get_result; MethodSpec get_result;
TypeSpec type; TypeSpec type;
TypeSpec result_type;
public AwaitStatement (Expression expr, Location loc) public AwaitStatement (Expression expr, Location loc)
: base (expr, loc) : base (expr, loc)
@ -139,6 +159,12 @@ namespace Mono.CSharp
#region Properties #region Properties
bool IsDynamic {
get {
return is_completed == null;
}
}
public TypeSpec Type { public TypeSpec Type {
get { get {
return type; return type;
@ -147,13 +173,18 @@ namespace Mono.CSharp
public TypeSpec ResultType { public TypeSpec ResultType {
get { get {
return get_result.ReturnType; return result_type;
} }
} }
#endregion #endregion
protected override void DoEmit (EmitContext ec) protected override void DoEmit (EmitContext ec)
{
GetResultExpression (ec).Emit (ec);
}
public Expression GetResultExpression (EmitContext ec)
{ {
var fe_awaiter = new FieldExpr (awaiter, loc); var fe_awaiter = new FieldExpr (awaiter, loc);
fe_awaiter.InstanceExpression = new CompilerGeneratedThis (ec.CurrentType, loc); fe_awaiter.InstanceExpression = new CompilerGeneratedThis (ec.CurrentType, loc);
@ -161,10 +192,15 @@ namespace Mono.CSharp
// //
// result = awaiter.GetResult (); // result = awaiter.GetResult ();
// //
var mg_result = MethodGroupExpr.CreatePredefined (get_result, fe_awaiter.Type, loc); if (IsDynamic) {
mg_result.InstanceExpression = fe_awaiter; 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) public void EmitPrologue (EmitContext ec)
@ -177,11 +213,35 @@ namespace Mono.CSharp
// //
fe_awaiter.EmitAssign (ec, expr, false, false); fe_awaiter.EmitAssign (ec, expr, false, false);
is_completed.InstanceExpression = fe_awaiter; Label skip_continuation = ec.DefineLabel ();
is_completed.EmitBranchable (ec, resume_point, true);
var mg_completed = MethodGroupExpr.CreatePredefined (on_completed, fe_awaiter.Type, loc); Expression completed_expr;
mg_completed.InstanceExpression = fe_awaiter; 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 args = new Arguments (1);
var storey = (AsyncTaskStorey) machine_initializer.Storey; var storey = (AsyncTaskStorey) machine_initializer.Storey;
@ -190,12 +250,27 @@ namespace Mono.CSharp
args.Add (new Argument (fe_cont)); args.Add (new Argument (fe_cont));
// if (IsDynamic) {
// awaiter.OnCompleted (continuation); var rc = new ResolveContext (ec.MemberContext);
// var mg_expr = new Invocation (new MemberAccess (fe_awaiter, "OnCompleted"), args).Resolve (rc);
mg_completed.EmitCall (ec, args);
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) public void EmitStatement (EmitContext ec)
@ -231,13 +306,21 @@ namespace Mono.CSharp
if (!base.Resolve (bc)) if (!base.Resolve (bc))
return false; return false;
Arguments args = new Arguments (0);
type = expr.Type; type = expr.Type;
// //
// The task result is of dynamic type // The await expression is of dynamic type
// //
if (expr.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) if (type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
throw new NotImplementedException ("dynamic await"); 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 // Check whether the expression is awaitable
@ -246,40 +329,28 @@ namespace Mono.CSharp
if (ama == null) if (ama == null)
return false; return false;
Arguments args = new Arguments (0);
var errors_printer = new SessionReportPrinter (); var errors_printer = new SessionReportPrinter ();
var old = bc.Report.SetPrinter (errors_printer); var old = bc.Report.SetPrinter (errors_printer);
ama = new Invocation (ama, args).Resolve (bc); ama = new Invocation (ama, args).Resolve (bc);
bc.Report.SetPrinter (old);
if (errors_printer.ErrorsCount > 0 || !MemberAccess.IsValidDotExpression (ama.Type)) { if (errors_printer.ErrorsCount > 0 || !MemberAccess.IsValidDotExpression (ama.Type)) {
bc.Report.SetPrinter (old); Error_WrongGetAwaiter (bc, expr.Location, expr.Type);
Error_WrongGetAwaiter (bc, loc, expr.Type);
return false; return false;
} }
var awaiter_type = ama.Type; var awaiter_type = ama.Type;
awaiter = ((AsyncTaskStorey) machine_initializer.Storey).AddAwaiter (awaiter_type, loc); awaiter = ((AsyncTaskStorey) machine_initializer.Storey).AddAwaiter (awaiter_type, loc);
expr = ama; expr = ama;
// //
// Predefined: bool IsCompleted { get; } // Predefined: bool IsCompleted { get; }
// //
var is_completed_ma = new MemberAccess (expr, "IsCompleted").Resolve (bc); is_completed = MemberCache.FindMember (awaiter_type, MemberFilter.Property ("IsCompleted", bc.Module.Compiler.BuiltinTypes.Bool),
if (is_completed_ma != null) { BindingRestriction.InstanceOnly) as PropertySpec;
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);
if (errors_printer.ErrorsCount > 0) { if (is_completed == null || !is_completed.HasGet) {
Error_WrongAwaiterPattern (bc, awaiter_type); Error_WrongAwaiterPattern (bc, awaiter_type);
return false; return false;
} }
@ -312,6 +383,8 @@ namespace Mono.CSharp
return false; return false;
} }
result_type = get_result.ReturnType;
return true; return true;
} }
} }
@ -353,7 +426,7 @@ namespace Mono.CSharp
#endregion #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 && if (returnType != null && returnType.Kind != MemberKind.Void &&
returnType != host.Module.PredefinedTypes.Task.TypeSpec && returnType != host.Module.PredefinedTypes.Task.TypeSpec &&
@ -385,11 +458,12 @@ namespace Mono.CSharp
} }
} }
// TODO: Warning if (!block.IsAsync) {
//if (!block.HasAwait) { 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) protected override BlockContext CreateBlockContext (ResolveContext rc)
@ -399,6 +473,7 @@ namespace Mono.CSharp
if (lambda != null) if (lambda != null)
return_inference = lambda.ReturnTypeInference; return_inference = lambda.ReturnTypeInference;
ctx.StartFlowBranching (this, rc.CurrentBranching);
return ctx; return ctx;
} }
@ -422,17 +497,31 @@ namespace Mono.CSharp
{ {
var storey = (AsyncTaskStorey) Storey; var storey = (AsyncTaskStorey) Storey;
storey.Instance.Emit (ec); 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) { if (storey.Task != null) {
// var builder_field = storey.Builder.Spec;
// async.$builder.Task; 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) { var pe_task = new PropertyExpr (storey.Task, loc) {
InstanceExpression = new FieldExpr (storey.Builder, loc) { InstanceExpression = new FieldExpr (builder_field, loc) {
InstanceExpression = storey.Instance InstanceExpression = storey.Instance
}, },
Getter = storey.Task.Get Getter = task_get
}; };
pe_task.Emit (ec); pe_task.Emit (ec);
@ -440,33 +529,60 @@ namespace Mono.CSharp
ec.Emit (OpCodes.Ret); 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 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; int awaiters;
Field builder, continuation; Field builder, continuation;
readonly TypeSpec return_type; readonly TypeSpec return_type;
MethodSpec set_result; MethodSpec set_result;
MethodSpec set_exception;
PropertySpec task; PropertySpec task;
LocalVariable hoisted_return; LocalVariable hoisted_return;
int locals_captured;
public AsyncTaskStorey (AsyncInitializer initializer, TypeSpec type) public AsyncTaskStorey (IMemberContext context, AsyncInitializer initializer, TypeSpec type)
: base (initializer.OriginalBlock, initializer.Host, null, null, "async") : base (initializer.OriginalBlock, initializer.Host,context.CurrentMemberDefinition as MemberBase, context.CurrentTypeParameters, "async")
{ {
return_type = type; return_type = type;
} }
public Field AddAwaiter (TypeSpec type, Location loc)
{
return AddCompilerGeneratedField ("$awaiter" + awaiters++.ToString ("X"), new TypeExpression (type, loc));
}
#region Properties #region Properties
public Field Builder { public Field Builder {
@ -501,17 +617,34 @@ namespace Mono.CSharp
#endregion #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 () protected override bool DoDefineMembers ()
{ {
var action = Module.PredefinedTypes.Action.Resolve (); var action = Module.PredefinedTypes.Action.Resolve ();
if (action != null) { if (action != null) {
continuation = AddCompilerGeneratedField ("$continuation", new TypeExpression (action, Location)); continuation = AddCompilerGeneratedField ("$continuation", new TypeExpression (action, Location), true);
continuation.ModFlags |= Modifiers.READONLY; continuation.ModFlags |= Modifiers.READONLY;
} }
PredefinedType builder_type; PredefinedType builder_type;
PredefinedMember<MethodSpec> bf; PredefinedMember<MethodSpec> bf;
PredefinedMember<MethodSpec> sr; PredefinedMember<MethodSpec> sr;
PredefinedMember<MethodSpec> se;
bool has_task_return_type = false; bool has_task_return_type = false;
var pred_members = Module.PredefinedMembers; var pred_members = Module.PredefinedMembers;
@ -519,32 +652,41 @@ namespace Mono.CSharp
builder_type = Module.PredefinedTypes.AsyncVoidMethodBuilder; builder_type = Module.PredefinedTypes.AsyncVoidMethodBuilder;
bf = pred_members.AsyncVoidMethodBuilderCreate; bf = pred_members.AsyncVoidMethodBuilderCreate;
sr = pred_members.AsyncVoidMethodBuilderSetResult; sr = pred_members.AsyncVoidMethodBuilderSetResult;
se = pred_members.AsyncVoidMethodBuilderSetException;
} else if (return_type == Module.PredefinedTypes.Task.TypeSpec) { } else if (return_type == Module.PredefinedTypes.Task.TypeSpec) {
builder_type = Module.PredefinedTypes.AsyncTaskMethodBuilder; builder_type = Module.PredefinedTypes.AsyncTaskMethodBuilder;
bf = pred_members.AsyncTaskMethodBuilderCreate; bf = pred_members.AsyncTaskMethodBuilderCreate;
sr = pred_members.AsyncTaskMethodBuilderSetResult; sr = pred_members.AsyncTaskMethodBuilderSetResult;
se = pred_members.AsyncTaskMethodBuilderSetException;
task = pred_members.AsyncTaskMethodBuilderTask.Resolve (Location); task = pred_members.AsyncTaskMethodBuilderTask.Resolve (Location);
} else { } else {
builder_type = Module.PredefinedTypes.AsyncTaskMethodBuilderGeneric; builder_type = Module.PredefinedTypes.AsyncTaskMethodBuilderGeneric;
bf = pred_members.AsyncTaskMethodBuilderGenericCreate; bf = pred_members.AsyncTaskMethodBuilderGenericCreate;
sr = pred_members.AsyncTaskMethodBuilderGenericSetResult; sr = pred_members.AsyncTaskMethodBuilderGenericSetResult;
se = pred_members.AsyncTaskMethodBuilderGenericSetException;
task = pred_members.AsyncTaskMethodBuilderGenericTask.Resolve (Location); task = pred_members.AsyncTaskMethodBuilderGenericTask.Resolve (Location);
has_task_return_type = true; has_task_return_type = true;
} }
set_result = sr.Resolve (Location); set_result = sr.Resolve (Location);
set_exception = se.Resolve (Location);
var builder_factory = bf.Resolve (Location); var builder_factory = bf.Resolve (Location);
var bt = builder_type.Resolve (); 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; return false;
// //
// Inflate generic Task types // Inflate generic Task types
// //
if (has_task_return_type) { 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); builder_factory = MemberCache.GetMember<MethodSpec> (bt, builder_factory);
set_result = MemberCache.GetMember<MethodSpec> (bt, set_result); set_result = MemberCache.GetMember<MethodSpec> (bt, set_result);
set_exception = MemberCache.GetMember<MethodSpec> (bt, set_exception);
if (task != null) if (task != null)
task = MemberCache.GetMember<PropertySpec> (bt, task); task = MemberCache.GetMember<PropertySpec> (bt, task);
@ -589,6 +731,22 @@ namespace Mono.CSharp
return true; 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) public void EmitSetResult (EmitContext ec)
{ {
// //

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

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

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

@ -99,7 +99,7 @@ namespace Mono.CSharp
return tc.GetSignatureForError (); 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; return null;
} }
@ -756,7 +756,7 @@ namespace Mono.CSharp
ExpressionStatement s = fi.ResolveStatement (ec); ExpressionStatement s = fi.ResolveStatement (ec);
if (s == null) { if (s == null) {
s = EmptyExpressionStatement.Instance; s = EmptyExpressionStatement.Instance;
} else if (fi.IsComplexInitializer) { } else if (!fi.IsSideEffectFree) {
has_complex_initializer |= true; has_complex_initializer |= true;
} }
@ -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; DeclSpace top_level = Parent;
if (top_level != null) { if (top_level != null) {
var candidates = NamespaceEntry.NS.LookupExtensionMethod (this, extensionType, name, arity); var methods = NamespaceEntry.NS.LookupExtensionMethod (this, extensionType, name, arity);
if (candidates != null) { if (methods != null) {
scope = NamespaceEntry; return new ExtensionMethodCandidates (methods, NamespaceEntry, NamespaceEntry.NS) {
return candidates; HasUninspectedMembers = true
};
} }
} }
return NamespaceEntry.LookupExtensionMethod (extensionType, name, arity, ref scope); return NamespaceEntry.LookupExtensionMethod (extensionType, name, arity);
} }
protected override TypeAttributes TypeAttr { protected override TypeAttributes TypeAttr {
@ -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; continue;
if (!CheckFieldTypeCycle (ftype)) { if (!CheckFieldTypeCycle (ftype)) {

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

@ -51,16 +51,6 @@ namespace Mono.CSharp
/// </summary> /// </summary>
public LocalBuilder return_value; 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> /// <summary>
/// Current loop begin and end labels. /// Current loop begin and end labels.
@ -87,13 +77,17 @@ namespace Mono.CSharp
DynamicSiteClass dynamic_site_container; DynamicSiteClass dynamic_site_container;
Label? return_label;
public EmitContext (IMemberContext rc, ILGenerator ig, TypeSpec return_type) public EmitContext (IMemberContext rc, ILGenerator ig, TypeSpec return_type)
{ {
this.member_context = rc; this.member_context = rc;
this.ig = ig; this.ig = ig;
this.return_type = return_type; this.return_type = return_type;
if (rc.Module.Compiler.Settings.Checked)
flags |= Options.CheckedScope;
#if STATIC #if STATIC
ig.__CleverExceptionBlockAssistance (); ig.__CleverExceptionBlockAssistance ();
#endif #endif
@ -101,6 +95,12 @@ namespace Mono.CSharp
#region Properties #region Properties
internal AsyncTaskStorey AsyncTaskStorey {
get {
return CurrentAnonymousMethod.Storey as AsyncTaskStorey;
}
}
public BuiltinTypes BuiltinTypes { public BuiltinTypes BuiltinTypes {
get { get {
return MemberContext.Module.Compiler.BuiltinTypes; return MemberContext.Module.Compiler.BuiltinTypes;
@ -119,6 +119,12 @@ namespace Mono.CSharp
get { return member_context.CurrentMemberDefinition; } get { return member_context.CurrentMemberDefinition; }
} }
public bool HasReturnLabel {
get {
return return_label.HasValue;
}
}
public bool IsStatic { public bool IsStatic {
get { return member_context.IsStatic; } get { return member_context.IsStatic; }
} }
@ -156,8 +162,27 @@ namespace Mono.CSharp
return return_type; return return_type;
} }
} }
//
// The label where we have to jump before leaving the context
//
public Label ReturnLabel {
get {
return return_label.Value;
}
}
#endregion #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> /// <summary>
/// This is called immediately before emitting an IL opcode to tell the symbol /// This is called immediately before emitting an IL opcode to tell the symbol
/// writer to which source line this opcode belongs. /// writer to which source line this opcode belongs.
@ -228,6 +253,14 @@ namespace Mono.CSharp
return dynamic_site_container; 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) public LocalBuilder DeclareLocal (TypeSpec type, bool pinned)
{ {
if (IsAnonymousStoreyMutateRequired) if (IsAnonymousStoreyMutateRequired)
@ -241,6 +274,17 @@ namespace Mono.CSharp
return ig.DefineLabel (); 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) public void MarkLabel (Label label)
{ {
ig.MarkLabel (label); ig.MarkLabel (label);
@ -271,16 +315,6 @@ namespace Mono.CSharp
ig.Emit (opcode, arg); 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) public void Emit (OpCode opcode, Label label)
{ {
ig.Emit (opcode, label); ig.Emit (opcode, label);
@ -333,7 +367,11 @@ namespace Mono.CSharp
public void EmitArrayNew (ArrayContainer ac) public void EmitArrayNew (ArrayContainer ac)
{ {
if (ac.Rank == 1) { 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 { } else {
if (IsAnonymousStoreyMutateRequired) if (IsAnonymousStoreyMutateRequired)
ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator); ac = (ArrayContainer) ac.Mutate (CurrentAnonymousMethod.Storey.Mutator);
@ -350,7 +388,11 @@ namespace Mono.CSharp
ig.Emit (OpCodes.Call, ac.GetAddressMethod ()); ig.Emit (OpCodes.Call, ac.GetAddressMethod ());
} else { } 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
return; return;
} }
var type = ac.Element; var type = ac.Element;
if (type.Kind == MemberKind.Enum) if (type.Kind == MemberKind.Enum)
type = EnumSpec.GetUnderlyingType (type); type = EnumSpec.GetUnderlyingType (type);
@ -374,52 +417,59 @@ namespace Mono.CSharp
switch (type.BuiltinType) { switch (type.BuiltinType) {
case BuiltinTypeSpec.Type.Byte: case BuiltinTypeSpec.Type.Byte:
case BuiltinTypeSpec.Type.Bool: case BuiltinTypeSpec.Type.Bool:
Emit (OpCodes.Ldelem_U1); ig.Emit (OpCodes.Ldelem_U1);
return; break;
case BuiltinTypeSpec.Type.SByte: case BuiltinTypeSpec.Type.SByte:
Emit (OpCodes.Ldelem_I1); ig.Emit (OpCodes.Ldelem_I1);
return; break;
case BuiltinTypeSpec.Type.Short: case BuiltinTypeSpec.Type.Short:
Emit (OpCodes.Ldelem_I2); ig.Emit (OpCodes.Ldelem_I2);
return; break;
case BuiltinTypeSpec.Type.UShort: case BuiltinTypeSpec.Type.UShort:
case BuiltinTypeSpec.Type.Char: case BuiltinTypeSpec.Type.Char:
Emit (OpCodes.Ldelem_U2); ig.Emit (OpCodes.Ldelem_U2);
return; break;
case BuiltinTypeSpec.Type.Int: case BuiltinTypeSpec.Type.Int:
Emit (OpCodes.Ldelem_I4); ig.Emit (OpCodes.Ldelem_I4);
return; break;
case BuiltinTypeSpec.Type.UInt: case BuiltinTypeSpec.Type.UInt:
Emit (OpCodes.Ldelem_U4); ig.Emit (OpCodes.Ldelem_U4);
return; break;
case BuiltinTypeSpec.Type.ULong: case BuiltinTypeSpec.Type.ULong:
case BuiltinTypeSpec.Type.Long: case BuiltinTypeSpec.Type.Long:
Emit (OpCodes.Ldelem_I8); ig.Emit (OpCodes.Ldelem_I8);
return; break;
case BuiltinTypeSpec.Type.Float: case BuiltinTypeSpec.Type.Float:
Emit (OpCodes.Ldelem_R4); ig.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);
break; break;
case MemberKind.TypeParameter: case BuiltinTypeSpec.Type.Double:
Emit (OpCodes.Ldelem, type); ig.Emit (OpCodes.Ldelem_R8);
break; break;
case MemberKind.PointerType: case BuiltinTypeSpec.Type.IntPtr:
Emit (OpCodes.Ldelem_I); ig.Emit (OpCodes.Ldelem_I);
break; break;
default: 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; break;
} }
} }
@ -486,6 +536,11 @@ namespace Mono.CSharp
} }
public void EmitInt (int i) public void EmitInt (int i)
{
EmitIntConstant (i);
}
void EmitIntConstant (int i)
{ {
switch (i) { switch (i) {
case -1: case -1:
@ -540,18 +595,14 @@ namespace Mono.CSharp
public void EmitLong (long l) public void EmitLong (long l)
{ {
if (l >= int.MinValue && l <= int.MaxValue) { if (l >= int.MinValue && l <= int.MaxValue) {
EmitInt (unchecked ((int) l)); EmitIntConstant (unchecked ((int) l));
ig.Emit (OpCodes.Conv_I8); ig.Emit (OpCodes.Conv_I8);
return; } else if (l >= 0 && l <= uint.MaxValue) {
} EmitIntConstant (unchecked ((int) l));
if (l >= 0 && l <= uint.MaxValue) {
EmitInt (unchecked ((int) l));
ig.Emit (OpCodes.Conv_U8); 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
switch (type.BuiltinType) { switch (type.BuiltinType) {
case BuiltinTypeSpec.Type.Int: case BuiltinTypeSpec.Type.Int:
ig.Emit (OpCodes.Ldind_I4); ig.Emit (OpCodes.Ldind_I4);
return; break;
case BuiltinTypeSpec.Type.UInt: case BuiltinTypeSpec.Type.UInt:
ig.Emit (OpCodes.Ldind_U4); ig.Emit (OpCodes.Ldind_U4);
return; break;
case BuiltinTypeSpec.Type.Short: case BuiltinTypeSpec.Type.Short:
ig.Emit (OpCodes.Ldind_I2); ig.Emit (OpCodes.Ldind_I2);
return; break;
case BuiltinTypeSpec.Type.UShort: case BuiltinTypeSpec.Type.UShort:
case BuiltinTypeSpec.Type.Char: case BuiltinTypeSpec.Type.Char:
ig.Emit (OpCodes.Ldind_U2); ig.Emit (OpCodes.Ldind_U2);
return; break;
case BuiltinTypeSpec.Type.Byte: case BuiltinTypeSpec.Type.Byte:
ig.Emit (OpCodes.Ldind_U1); ig.Emit (OpCodes.Ldind_U1);
return; break;
case BuiltinTypeSpec.Type.SByte: case BuiltinTypeSpec.Type.SByte:
case BuiltinTypeSpec.Type.Bool: case BuiltinTypeSpec.Type.Bool:
ig.Emit (OpCodes.Ldind_I1); ig.Emit (OpCodes.Ldind_I1);
return; break;
case BuiltinTypeSpec.Type.ULong: case BuiltinTypeSpec.Type.ULong:
case BuiltinTypeSpec.Type.Long: case BuiltinTypeSpec.Type.Long:
ig.Emit (OpCodes.Ldind_I8); ig.Emit (OpCodes.Ldind_I8);
return; break;
case BuiltinTypeSpec.Type.Float: case BuiltinTypeSpec.Type.Float:
ig.Emit (OpCodes.Ldind_R4); ig.Emit (OpCodes.Ldind_R4);
return; break;
case BuiltinTypeSpec.Type.Double: case BuiltinTypeSpec.Type.Double:
ig.Emit (OpCodes.Ldind_R8); ig.Emit (OpCodes.Ldind_R8);
return; break;
case BuiltinTypeSpec.Type.IntPtr: case BuiltinTypeSpec.Type.IntPtr:
ig.Emit (OpCodes.Ldind_I); ig.Emit (OpCodes.Ldind_I);
return;
}
switch (type.Kind) {
case MemberKind.Struct:
case MemberKind.TypeParameter:
Emit (OpCodes.Ldobj, type);
break; break;
case MemberKind.PointerType: default:
ig.Emit (OpCodes.Ldind_I); 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; 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: default:
ig.Emit (OpCodes.Ldind_Ref); if (pos > byte.MaxValue)
ig.Emit (OpCodes.Ldarg, pos);
else
ig.Emit (OpCodes.Ldarg_S, (byte) pos);
break; 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' // The stack contains the pointer and the value of type `type'
// //
@ -650,10 +751,23 @@ namespace Mono.CSharp
return; return;
} }
if (type.IsStruct || TypeManager.IsGenericParameter (type)) switch (type.Kind) {
Emit (OpCodes.Stobj, type); case MemberKind.Struct:
else case MemberKind.TypeParameter:
if (IsAnonymousStoreyMutateRequired)
type = CurrentAnonymousMethod.Storey.Mutator.Mutate (type);
ig.Emit (OpCodes.Stobj, type.GetMetaInfo ());
break;
default:
ig.Emit (OpCodes.Stind_Ref); ig.Emit (OpCodes.Stind_Ref);
break;
}
}
public void EmitThis ()
{
ig.Emit (OpCodes.Ldarg_0);
} }
/// <summary> /// <summary>
@ -716,13 +830,203 @@ namespace Mono.CSharp
{ {
if (return_value == null){ if (return_value == null){
return_value = DeclareLocal (return_type, false); return_value = DeclareLocal (return_type, false);
if (!HasReturnLabel){
ReturnLabel = DefineLabel ();
HasReturnLabel = true;
}
} }
return return_value; 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 {
} }
} }
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 // 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 {
return c; return c;
} }
public override bool ContainsEmitWithAwait ()
{
return false;
}
public virtual Constant ConvertImplicitly (TypeSpec type) public virtual Constant ConvertImplicitly (TypeSpec type)
{ {
if (this.type == type) if (this.type == type)
@ -309,7 +314,13 @@ namespace Mono.CSharp {
public virtual bool IsOneInteger { public virtual bool IsOneInteger {
get { return false; } get { return false; }
} }
public override bool IsSideEffectFree {
get {
return true;
}
}
// //
// Returns true iff 1) the stack type of this is one of Object, // Returns true iff 1) the stack type of this is one of Object,
@ -427,9 +438,9 @@ namespace Mono.CSharp {
public override void Emit (EmitContext ec) public override void Emit (EmitContext ec)
{ {
if (Value) if (Value)
ec.Emit (OpCodes.Ldc_I4_1); ec.EmitInt (1);
else else
ec.Emit (OpCodes.Ldc_I4_0); ec.EmitInt (0);
} }
public override bool IsDefaultValue { public override bool IsDefaultValue {
@ -1945,7 +1956,7 @@ namespace Mono.CSharp {
public override void Emit (EmitContext ec) public override void Emit (EmitContext ec)
{ {
if (Value == null) { if (Value == null) {
ec.Emit (OpCodes.Ldnull); ec.EmitNull ();
return; return;
} }
@ -2050,7 +2061,7 @@ namespace Mono.CSharp {
public override void Emit (EmitContext ec) public override void Emit (EmitContext ec)
{ {
ec.Emit (OpCodes.Ldnull); ec.EmitNull ();
// Only to make verifier happy // Only to make verifier happy
if (type.IsGenericParameter) if (type.IsGenericParameter)
@ -2152,7 +2163,7 @@ namespace Mono.CSharp {
// //
// Emits null pointer // Emits null pointer
// //
ec.Emit (OpCodes.Ldc_I4_0); ec.EmitInt (0);
ec.Emit (OpCodes.Conv_U); ec.Emit (OpCodes.Conv_U);
} }
} }
@ -2162,7 +2173,8 @@ namespace Mono.CSharp {
/// used by BitwiseAnd to ensure that the second expression is invoked /// used by BitwiseAnd to ensure that the second expression is invoked
/// regardless of the value of the left side. /// regardless of the value of the left side.
/// </summary> /// </summary>
public class SideEffectConstant : Constant { public class SideEffectConstant : Constant
{
public readonly Constant value; public readonly Constant value;
Expression side_effect; Expression side_effect;
@ -2178,6 +2190,12 @@ namespace Mono.CSharp {
this.side_effect = side_effect; this.side_effect = side_effect;
} }
public override bool IsSideEffectFree {
get {
return false;
}
}
public override object GetValue () public override object GetValue ()
{ {
return value.GetValue (); return value.GetValue ();

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

@ -7,18 +7,13 @@
// //
// Copyright 2001, 2002, 2003 Ximian, Inc. // Copyright 2001, 2002, 2003 Ximian, Inc.
// Copyright 2004-2009 Novell, Inc. // Copyright 2004-2009 Novell, Inc.
// Copyright 2011 Xamarin Inc.
// //
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
#if STATIC
using IKVM.Reflection.Emit;
#else
using System.Reflection.Emit;
#endif
namespace Mono.CSharp namespace Mono.CSharp
{ {
public enum LookupMode public enum LookupMode
@ -58,7 +53,7 @@ namespace Mono.CSharp
string GetSignatureForError (); 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 LookupNamespaceOrType (string name, int arity, LookupMode mode, Location loc);
FullNamedExpression LookupNamespaceAlias (string name); FullNamedExpression LookupNamespaceAlias (string name);
} }
@ -75,18 +70,7 @@ namespace Mono.CSharp
{ {
FlowBranching current_flow_branching; FlowBranching current_flow_branching;
TypeSpec return_type; readonly 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;
public int FlowOffset; public int FlowOffset;
@ -116,6 +100,10 @@ namespace Mono.CSharp
get { return current_flow_branching; } get { return current_flow_branching; }
} }
public TypeSpec ReturnType {
get { return return_type; }
}
// <summary> // <summary>
// Starts a new code branching. This inherits the state of all local // Starts a new code branching. This inherits the state of all local
// variables and parameters from the current branching. // variables and parameters from the current branching.
@ -145,9 +133,9 @@ namespace Mono.CSharp
return branching; 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; current_flow_branching = branching;
return branching; return branching;
} }
@ -159,13 +147,20 @@ namespace Mono.CSharp
return branching; return branching;
} }
public FlowBranchingIterator StartFlowBranching (StateMachineInitializer iterator, FlowBranching parent) public FlowBranchingIterator StartFlowBranching (Iterator iterator, FlowBranching parent)
{ {
FlowBranchingIterator branching = new FlowBranchingIterator (parent, iterator); FlowBranchingIterator branching = new FlowBranchingIterator (parent, iterator);
current_flow_branching = branching; current_flow_branching = branching;
return 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) public FlowBranchingToplevel StartFlowBranching (ParametersBlock stmt, FlowBranching parent)
{ {
FlowBranchingToplevel branching = new FlowBranchingToplevel (parent, stmt); FlowBranchingToplevel branching = new FlowBranchingToplevel (parent, stmt);
@ -196,19 +191,11 @@ namespace Mono.CSharp
current_flow_branching = current_flow_branching.Parent; current_flow_branching = current_flow_branching.Parent;
} }
// #if !STATIC
// This method is used during the Resolution phase to flag the
// need to define the ReturnLabel
//
public void NeedReturnLabel () public void NeedReturnLabel ()
{ {
if (!HasReturnLabel)
HasReturnLabel = true;
}
public TypeSpec ReturnType {
get { return return_type; }
} }
#endif
} }
// //
@ -484,7 +471,7 @@ namespace Mono.CSharp
// FIXME: IsIterator is too aggressive, we should capture only if child // FIXME: IsIterator is too aggressive, we should capture only if child
// block contains yield // block contains yield
if (CurrentAnonymousMethod.IsIterator) if (CurrentAnonymousMethod.IsIterator || CurrentAnonymousMethod is AsyncInitializer)
return true; return true;
return local.Block.ParametersBlock != CurrentBlock.ParametersBlock.Original; return local.Block.ParametersBlock != CurrentBlock.ParametersBlock.Original;
@ -519,9 +506,9 @@ namespace Mono.CSharp
return MemberContext.GetSignatureForError (); 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) public FullNamedExpression LookupNamespaceOrType (string name, int arity, LookupMode mode, Location loc)
@ -685,18 +672,11 @@ namespace Mono.CSharp
/// </summary> /// </summary>
CheckedScope = 1 << 0, 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, OmitDebugInfo = 1 << 2,
ConstructorScope = 1 << 3 ConstructorScope = 1 << 3,
AsyncBody = 1 << 4
} }
// utility helper for CheckExpr, UnCheckExpr, Checked and Unchecked statements // utility helper for CheckExpr, UnCheckExpr, Checked and Unchecked statements
@ -725,7 +705,7 @@ namespace Mono.CSharp
} }
} }
Options flags; protected Options flags;
public bool HasSet (Options options) public bool HasSet (Options options)
{ {

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

@ -8,6 +8,7 @@
// //
// Copyright 2001, 2002, 2003 Ximian, Inc. // Copyright 2001, 2002, 2003 Ximian, Inc.
// Copyright 2003-2008 Novell, Inc. // Copyright 2003-2008 Novell, Inc.
// Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
// //
using System; using System;
@ -198,7 +199,7 @@ namespace Mono.CSharp {
return ImplicitReferenceConversionExists (expr_type, target_type, true); 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 // It's here only to speed things up
if (target_type.IsStruct) 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 @@
// //
// cs-parser.jay: The Parser for the C# compiler // 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) // 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 // Dual Licensed under the terms of the GNU GPL and the MIT X11 license
// //
// (C) 2001 Ximian, Inc (http://www.ximian.com) // (C) 2001 Ximian, Inc (http://www.ximian.com)
// (C) 2004 Novell, Inc // (C) 2004-2011 Novell, Inc
// Copyright 2011 Xamarin Inc.
// //
// TODO: // TODO:
// (1) Figure out why error productions dont work. `type-declaration' is a // (1) Figure out why error productions dont work. `type-declaration' is a
@ -898,8 +899,13 @@ opt_class_member_declarations
class_member_declarations class_member_declarations
: class_member_declaration : 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 class_member_declaration
@ -946,10 +952,17 @@ struct_declaration
if (doc_support) if (doc_support)
current_container.DocComment = Lexer.consume_doc_comment (); 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) if (doc_support)
Lexer.doc_state = XmlCommentState.Allowed; Lexer.doc_state = XmlCommentState.Allowed;
} }
@ -964,46 +977,6 @@ struct_declaration
Error_SyntaxError (yyToken); 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 constant_declaration
: opt_attributes : opt_attributes
@ -1259,13 +1232,16 @@ method_declaration
if (doc_support) if (doc_support)
Lexer.doc_state = XmlCommentState.NotAllowed; Lexer.doc_state = XmlCommentState.NotAllowed;
// Add it early in the case of body being eof for full aot // Add it early in the case of body being eof for full ast
current_container.AddMethod ((Method) $1); Method m = (Method) $1;
lexer.async_block = (m.ModFlags & Modifiers.ASYNC) != 0;
current_container.AddMethod (m);
} }
method_body method_body
{ {
Method method = (Method) $1; Method method = (Method) $1;
method.Block = (ToplevelBlock) $3; method.Block = (ToplevelBlock) $3;
lexer.async_block = false;
if (method.Block == null) { if (method.Block == null) {
lbag.AppendToMember (method, savedLocation); // semicolon lbag.AppendToMember (method, savedLocation); // semicolon
@ -1967,6 +1943,8 @@ interface_declaration
current_container.DocComment = Lexer.consume_doc_comment (); current_container.DocComment = Lexer.consume_doc_comment ();
Lexer.doc_state = XmlCommentState.Allowed; Lexer.doc_state = XmlCommentState.Allowed;
} }
lexer.parsing_modifiers = true;
} }
OPEN_BRACE opt_interface_member_declarations CLOSE_BRACE OPEN_BRACE opt_interface_member_declarations CLOSE_BRACE
{ {
@ -1994,7 +1972,13 @@ opt_interface_member_declarations
interface_member_declarations interface_member_declarations
: interface_member_declaration : interface_member_declaration
{
lexer.parsing_modifiers = true;
}
| interface_member_declarations interface_member_declaration | interface_member_declarations interface_member_declaration
{
lexer.parsing_modifiers = true;
}
; ;
interface_member_declaration interface_member_declaration
@ -3887,10 +3871,10 @@ cast_expression
await_expression await_expression
: AWAIT unary_expression : AWAIT unary_expression
{ {
current_block.ParametersBlock.IsAsync = true; current_block.ParametersBlock.IsAsync = true;
$$ = new Await ((Expression) $2, GetLocation ($1)); $$ = new Await ((Expression) $2, GetLocation ($1));
} }
; ;
// //
@ -4352,6 +4336,8 @@ class_declaration
current_container.DocComment = Lexer.consume_doc_comment (); current_container.DocComment = Lexer.consume_doc_comment ();
Lexer.doc_state = XmlCommentState.Allowed; Lexer.doc_state = XmlCommentState.Allowed;
} }
lexer.parsing_modifiers = true;
} }
OPEN_BRACE opt_class_member_declarations CLOSE_BRACE OPEN_BRACE opt_class_member_declarations CLOSE_BRACE
{ {
@ -4380,8 +4366,12 @@ opt_modifiers
{ {
mod_locations = null; mod_locations = null;
$$ = ModifierNone; $$ = ModifierNone;
lexer.parsing_modifiers = false;
} }
| modifiers | modifiers
{
lexer.parsing_modifiers = false;
}
; ;
modifiers modifiers
@ -4951,6 +4941,17 @@ opt_variable_declarators
| 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_declarators
: variable_declarator : variable_declarator
| variable_declarators variable_declarator | variable_declarators variable_declarator
@ -5561,7 +5562,7 @@ fixed_statement
current_block.AddLocalName (li); current_block.AddLocalName (li);
current_variable = new Fixed.VariableDeclaration ((FullNamedExpression) $3, 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;
current_variable = null; current_variable = null;
@ -5589,7 +5590,7 @@ using_statement
current_block.AddLocalName (li); current_block.AddLocalName (li);
current_variable = new Using.VariableDeclaration ((FullNamedExpression) $3, 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;
current_variable = null; current_variable = null;
@ -5618,7 +5619,7 @@ using_statement
using_or_fixed_variable_initializer using_or_fixed_variable_initializer
: /* empty */ : /* 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 | ASSIGN variable_initializer
{ {
@ -6366,6 +6367,11 @@ void Error_NamedArgumentExpected (NamedArgument a)
report.Error (1738, a.Location, "Named arguments must appear after the positional arguments"); 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) void push_current_class (TypeContainer tc, object partial_token)
{ {
if (module.Evaluator != null && current_container is ModuleContainer){ if (module.Evaluator != null && current_container is ModuleContainer){
@ -6621,6 +6627,7 @@ void start_anonymous (bool isLambda, ParametersCompiled parameters, bool isAsync
oob_stack.Push (current_anonymous_method); oob_stack.Push (current_anonymous_method);
oob_stack.Push (current_local_parameters); oob_stack.Push (current_local_parameters);
oob_stack.Push (current_variable); oob_stack.Push (current_variable);
oob_stack.Push (lexer.async_block);
current_local_parameters = parameters; current_local_parameters = parameters;
if (isLambda) { if (isLambda) {
@ -6635,6 +6642,7 @@ void start_anonymous (bool isLambda, ParametersCompiled parameters, bool isAsync
current_anonymous_method = new AnonymousMethodExpression (isAsync, loc); current_anonymous_method = new AnonymousMethodExpression (isAsync, loc);
} }
lexer.async_block = isAsync;
// Force the next block to be created as a ToplevelBlock // Force the next block to be created as a ToplevelBlock
parsing_anonymous_method = true; parsing_anonymous_method = true;
} }
@ -6650,6 +6658,7 @@ AnonymousMethodExpression end_anonymous (ParametersBlock anon_block)
current_anonymous_method.Block = anon_block; current_anonymous_method.Block = anon_block;
retval = current_anonymous_method; retval = current_anonymous_method;
lexer.async_block = (bool) oob_stack.Pop ();
current_variable = (BlockVariableDeclaration) oob_stack.Pop (); current_variable = (BlockVariableDeclaration) oob_stack.Pop ();
current_local_parameters = (ParametersCompiled) oob_stack.Pop (); current_local_parameters = (ParametersCompiled) oob_stack.Pop ();
current_anonymous_method = (AnonymousMethodExpression) oob_stack.Pop (); current_anonymous_method = (AnonymousMethodExpression) oob_stack.Pop ();

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

@ -3,13 +3,13 @@
// This also implements the preprocessor // This also implements the preprocessor
// //
// Author: Miguel de Icaza (miguel@gnu.org) // 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 // Dual licensed under the terms of the MIT X11 or GNU GPL
// //
// Copyright 2001, 2002 Ximian, Inc (http://www.ximian.com) // Copyright 2001, 2002 Ximian, Inc (http://www.ximian.com)
// Copyright 2004-2008 Novell, Inc // Copyright 2004-2008 Novell, Inc
// // Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
// //
using System; using System;
using System.Text; using System.Text;
@ -205,6 +205,10 @@ namespace Mono.CSharp
public int parsing_declaration; public int parsing_declaration;
public bool parsing_attribute_section; 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 // The special characters to inject on streams to run the unit parser
// in the special expression mode. Using private characters from // in the special expression mode. Using private characters from
@ -787,18 +791,47 @@ namespace Mono.CSharp
res = -1; res = -1;
break; break;
// TODO: async, it's modifiers context only
case Token.ASYNC: 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; res = -1;
} }
if (res == Token.ASYNC && context.Settings.Version <= LanguageVersion.V_4) {
Report.FeatureIsNotAvailable (context, Location, "asynchronous functions");
}
break; break;
// TODO: async, it's async block context only
case Token.AWAIT: case Token.AWAIT:
if (context.Settings.Version != LanguageVersion.Future) { if (!async_block)
res = -1; res = -1;
}
break; break;
} }

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

@ -697,9 +697,9 @@ namespace Mono.CSharp {
return true; 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) public virtual FullNamedExpression LookupNamespaceAlias (string name)

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

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

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

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

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

@ -7,6 +7,7 @@
// //
// Copyright 2001, 2002, 2003 Ximian, Inc. // Copyright 2001, 2002, 2003 Ximian, Inc.
// Copyright 2003-2008 Novell, Inc. // Copyright 2003-2008 Novell, Inc.
// Copyright 2011 Xamarin Inc.
// //
// //
@ -130,16 +131,14 @@ namespace Mono.CSharp {
set { type = value; } set { type = value; }
} }
public Location Location { public virtual bool IsSideEffectFree {
get { return loc; } get {
return false;
}
} }
public virtual string GetSignatureForError () public Location Location {
{ get { return loc; }
if (type == null)
return "<nullType>";
TypeSpec typeSpec = type.GetDefinition ();
return typeSpec != null ? typeSpec.GetSignatureForError () : "<nullTypeSpec>";
} }
public virtual bool IsNull { public virtual bool IsNull {
@ -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> /// <summary>
/// Performs semantic analysis on the Expression /// Performs semantic analysis on the Expression
/// </summary> /// </summary>
@ -343,6 +351,11 @@ namespace Mono.CSharp {
} }
} }
} }
public virtual string GetSignatureForError ()
{
return type.GetDefinition ().GetSignatureForError ();
}
/// <summary> /// <summary>
/// Resolves an expression and performs semantic analysis on it. /// Resolves an expression and performs semantic analysis on it.
@ -469,6 +482,107 @@ namespace Mono.CSharp {
ec.Emit (OpCodes.Pop); 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> /// <summary>
/// Protected constructor. Only derivate types should /// Protected constructor. Only derivate types should
/// be able to be created /// be able to be created
@ -498,7 +612,7 @@ namespace Mono.CSharp {
return null; 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); var ctors = MemberCache.FindMembers (type, Constructor.ConstructorName, true);
if (ctors == null) { if (ctors == null) {
@ -961,6 +1075,11 @@ namespace Mono.CSharp {
} }
} }
public override bool ContainsEmitWithAwait ()
{
return child.ContainsEmitWithAwait ();
}
public override Expression CreateExpressionTree (ResolveContext ec) public override Expression CreateExpressionTree (ResolveContext ec)
{ {
Arguments args = new Arguments (2); Arguments args = new Arguments (2);
@ -1140,6 +1259,12 @@ namespace Mono.CSharp {
get { return child.IsOneInteger; } get { return child.IsOneInteger; }
} }
public override bool IsSideEffectFree {
get {
return child.IsSideEffectFree;
}
}
public override bool IsZeroInteger { public override bool IsZeroInteger {
get { return child.IsZeroInteger; } get { return child.IsZeroInteger; }
} }
@ -1277,6 +1402,12 @@ namespace Mono.CSharp {
} }
} }
public override bool IsSideEffectFree {
get {
return Child.IsSideEffectFree;
}
}
public override bool IsZeroInteger { public override bool IsZeroInteger {
get { return Child.IsZeroInteger; } get { return Child.IsZeroInteger; }
} }
@ -1748,6 +1879,11 @@ namespace Mono.CSharp {
this.loc = orig.Location; this.loc = orig.Location;
} }
public override bool ContainsEmitWithAwait ()
{
return stm.ContainsEmitWithAwait ();
}
public override Expression CreateExpressionTree (ResolveContext ec) public override Expression CreateExpressionTree (ResolveContext ec)
{ {
return orig_expr.CreateExpressionTree (ec); return orig_expr.CreateExpressionTree (ec);
@ -1790,6 +1926,11 @@ namespace Mono.CSharp {
#endregion #endregion
public override bool ContainsEmitWithAwait ()
{
return expr.ContainsEmitWithAwait ();
}
// //
// Creates fully resolved expression switcher // Creates fully resolved expression switcher
// //
@ -1873,6 +2014,11 @@ namespace Mono.CSharp {
this.loc = expr.Location; this.loc = expr.Location;
} }
public override bool ContainsEmitWithAwait ()
{
return expr.ContainsEmitWithAwait ();
}
public override Expression CreateExpressionTree (ResolveContext rc) public override Expression CreateExpressionTree (ResolveContext rc)
{ {
return expr.CreateExpressionTree (rc); return expr.CreateExpressionTree (rc);
@ -1930,6 +2076,11 @@ namespace Mono.CSharp {
target.expr = expr.Clone (clonectx); target.expr = expr.Clone (clonectx);
} }
public override bool ContainsEmitWithAwait ()
{
return expr.ContainsEmitWithAwait ();
}
public override Expression CreateExpressionTree (ResolveContext ec) public override Expression CreateExpressionTree (ResolveContext ec)
{ {
throw new NotSupportedException ("ET"); throw new NotSupportedException ("ET");
@ -2090,7 +2241,6 @@ namespace Mono.CSharp {
} }
} }
// MSAF
var retval = ctx.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc); var retval = ctx.LookupNamespaceOrType (Name, Arity, LookupMode.IgnoreAccessibility, loc);
if (retval != null) { if (retval != null) {
ctx.Module.Compiler.Report.SymbolRelatedToPreviousError (retval.Type); ctx.Module.Compiler.Report.SymbolRelatedToPreviousError (retval.Type);
@ -2379,6 +2529,11 @@ namespace Mono.CSharp {
// resolved to different type // resolved to different type
} }
public override bool ContainsEmitWithAwait ()
{
return false;
}
public override Expression CreateExpressionTree (ResolveContext ec) public override Expression CreateExpressionTree (ResolveContext ec)
{ {
throw new NotSupportedException ("ET"); throw new NotSupportedException ("ET");
@ -2626,6 +2781,11 @@ namespace Mono.CSharp {
} }
} }
public override bool ContainsEmitWithAwait ()
{
return InstanceExpression != null && InstanceExpression.ContainsEmitWithAwait ();
}
static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype) static bool IsSameOrBaseQualifier (TypeSpec type, TypeSpec qtype)
{ {
do { do {
@ -2814,6 +2974,7 @@ namespace Mono.CSharp {
InstanceExpression.Emit (ec); InstanceExpression.Emit (ec);
t.Store (ec); t.Store (ec);
t.AddressOf (ec, AddressOp.Store); t.AddressOf (ec, AddressOp.Store);
t.Release (ec);
} }
} else { } else {
InstanceExpression.Emit (ec); InstanceExpression.Emit (ec);
@ -2830,18 +2991,57 @@ namespace Mono.CSharp {
public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta); 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 // Represents a group of extension method candidates for whole namespace
// //
class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
{ {
NamespaceContainer namespace_entry; ExtensionMethodCandidates candidates;
public readonly Expression ExtensionExpression; public readonly Expression ExtensionExpression;
public ExtensionMethodGroupExpr (IList<MethodSpec> list, NamespaceContainer n, Expression extensionExpr, Location l) public ExtensionMethodGroupExpr (ExtensionMethodCandidates candidates, Expression extensionExpr, Location loc)
: base (list.Cast<MemberSpec>().ToList (), extensionExpr.Type, l) : base (candidates.Methods.Cast<MemberSpec>().ToList (), extensionExpr.Type, loc)
{ {
this.namespace_entry = n; this.candidates = candidates;
this.ExtensionExpression = extensionExpr; this.ExtensionExpression = extensionExpr;
} }
@ -2849,21 +3049,55 @@ namespace Mono.CSharp {
get { return true; } 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) 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; return null;
int arity = type_arguments == null ? 0 : type_arguments.Count;
// //
// For extension methodgroup we are not looking for base members but parent // Here we try to resume the search for extension method at the point
// namespace extension methods // 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; // Consider:
var found = namespace_entry.LookupExtensionMethod (DeclaringType, Name, arity, ref namespace_entry); //
if (found == null) // 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 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) public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
@ -3072,7 +3306,9 @@ namespace Mono.CSharp {
public void EmitCall (EmitContext ec, Arguments arguments) 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) public override void Error_ValueCannotBeConverted (ResolveContext ec, Location loc, TypeSpec target, bool expl)
@ -3197,12 +3433,11 @@ namespace Mono.CSharp {
return null; return null;
int arity = type_arguments == null ? 0 : type_arguments.Count; int arity = type_arguments == null ? 0 : type_arguments.Count;
NamespaceContainer methods_scope = null; var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity);
var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity, ref methods_scope);
if (methods == null) if (methods == null)
return null; return null;
var emg = new ExtensionMethodGroupExpr (methods, methods_scope, InstanceExpression, loc); var emg = new ExtensionMethodGroupExpr (methods, InstanceExpression, loc);
emg.SetTypeArguments (rc, type_arguments); emg.SetTypeArguments (rc, type_arguments);
return emg; return emg;
} }
@ -3969,9 +4204,11 @@ namespace Mono.CSharp {
// //
// Indentity, implicit reference or boxing conversion must exist for the extension parameter // Indentity, implicit reference or boxing conversion must exist for the extension parameter
// //
// LAMESPEC: or implicit type parameter conversion
//
var at = a.Type; var at = a.Type;
if (at == pt || TypeSpecComparer.IsEqual (at, pt) || if (at == pt || TypeSpecComparer.IsEqual (at, pt) ||
Convert.ImplicitReferenceConversionExists (at, pt) || Convert.ImplicitReferenceConversionExists (at, pt, false) ||
Convert.ImplicitBoxingConversion (null, at, pt) != null) { Convert.ImplicitBoxingConversion (null, at, pt) != null) {
score = 0; score = 0;
continue; continue;
@ -4756,10 +4993,11 @@ namespace Mono.CSharp {
} }
} }
/// <summary> //
/// Fully resolved expression that evaluates to a Field // Fully resolved expression that references a Field
/// </summary> //
public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference { public class FieldExpr : MemberExpr, IDynamicAssign, IMemoryLocation, IVariableReference
{
protected FieldSpec spec; protected FieldSpec spec;
VariableInfo variable_info; VariableInfo variable_info;
@ -4929,7 +5167,7 @@ namespace Mono.CSharp {
} else if (var != null && var.IsHoisted) { } else if (var != null && var.IsHoisted) {
AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc); AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
} }
return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec); return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
} }
@ -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; bool has_await_source = ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ();
if (await_expr != null) { if (isCompound && !(source is DynamicExpressionStatement)) {
// if (has_await_source) {
// Await is not ordinary expression (it contains jump), hence the usual flow cannot be used if (IsInstance)
// to emit instance load before expression InstanceExpression = InstanceExpression.EmitToField (ec);
// } else {
await_expr.EmitAssign (ec, this); prepared = true;
} else { }
prepared = prepare_for_load && !(source is DynamicExpressionStatement); }
if (IsInstance)
EmitInstance (ec, prepared);
source.Emit (ec); if (IsInstance) {
if (has_await_source)
source = source.EmitToField (ec);
EmitInstance (ec, prepared);
} }
source.Emit (ec);
if (leave_copy) { if (leave_copy) {
ec.Emit (OpCodes.Dup); ec.Emit (OpCodes.Dup);
if (!IsStatic) { if (!IsStatic) {
@ -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) public override void Emit (EmitContext ec)
{ {
Emit (ec, false); Emit (ec, false);
@ -5187,12 +5441,12 @@ namespace Mono.CSharp {
} else } else
need_copy = false; need_copy = false;
if (need_copy){ if (need_copy) {
LocalBuilder local;
Emit (ec); Emit (ec);
local = ec.DeclareLocal (type, false); var temp = ec.GetTemporaryLocal (type);
ec.Emit (OpCodes.Stloc, local); ec.Emit (OpCodes.Stloc, temp);
ec.Emit (OpCodes.Ldloca, local); ec.Emit (OpCodes.Ldloca, temp);
ec.FreeTemporaryLocal (temp, type);
return; return;
} }
@ -5229,14 +5483,13 @@ namespace Mono.CSharp {
} }
/// <summary> //
/// Expression that evaluates to a Property. The Assign class // Expression that evaluates to a Property.
/// 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
/// This is not an LValue because we need to re-write the expression, we // can not take data from the stack and store it.
/// can not take data from the stack and store it. //
/// </summary> sealed class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
class PropertyExpr : PropertyOrIndexerExpr<PropertySpec>
{ {
public PropertyExpr (PropertySpec spec, Location l) public PropertyExpr (PropertySpec spec, Location l)
: base (l) : base (l)
@ -5247,6 +5500,14 @@ namespace Mono.CSharp {
#region Properties #region Properties
protected override Arguments Arguments {
get {
return null;
}
set {
}
}
protected override TypeSpec DeclaringType { protected override TypeSpec DeclaringType {
get { get {
return best_candidate.DeclaringType; return best_candidate.DeclaringType;
@ -5279,6 +5540,14 @@ namespace Mono.CSharp {
#endregion #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) public override Expression CreateExpressionTree (ResolveContext ec)
{ {
Arguments args; Arguments args;
@ -5347,36 +5616,41 @@ namespace Mono.CSharp {
// Special case: length of single dimension array property is turned into ldlen // Special case: length of single dimension array property is turned into ldlen
// //
if (IsSingleDimensionalArrayLength ()) { if (IsSingleDimensionalArrayLength ()) {
if (!prepared) EmitInstance (ec, false);
EmitInstance (ec, false);
ec.Emit (OpCodes.Ldlen); ec.Emit (OpCodes.Ldlen);
ec.Emit (OpCodes.Conv_I4); ec.Emit (OpCodes.Conv_I4);
return; return;
} }
Invocation.EmitCall (ec, InstanceExpression, Getter, null, loc, prepared, false); base.Emit (ec, leave_copy);
if (leave_copy) {
ec.Emit (OpCodes.Dup);
if (!IsStatic) {
temp = new LocalTemporary (this.Type);
temp.Store (ec);
}
}
} }
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; Arguments args;
LocalTemporary await_source_arg = null;
if (prepare_for_load && !(source is DynamicExpressionStatement)) { if (isCompound && !(source is DynamicExpressionStatement)) {
args = new Arguments (0); emitting_compound_assignment = true;
prepared = true;
source.Emit (ec); source.Emit (ec);
if (leave_copy) { if (has_await_arguments) {
ec.Emit (OpCodes.Dup); await_source_arg = new LocalTemporary (Type);
if (!IsStatic) { 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 = new LocalTemporary (this.Type);
temp.Store (ec); temp.Store (ec);
} }
@ -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) { if (temp != null) {
temp.Emit (ec); temp.Emit (ec);
temp.Release (ec); temp.Release (ec);
} }
if (await_source_arg != null) {
await_source_arg.Release (ec);
}
} }
protected override Expression OverloadResolve (ResolveContext rc, Expression right_side) protected override Expression OverloadResolve (ResolveContext rc, Expression right_side)
@ -5437,7 +5722,8 @@ namespace Mono.CSharp {
protected T best_candidate; protected T best_candidate;
protected LocalTemporary temp; protected LocalTemporary temp;
protected bool prepared; protected bool emitting_compound_assignment;
protected bool has_await_arguments;
protected PropertyOrIndexerExpr (Location l) protected PropertyOrIndexerExpr (Location l)
{ {
@ -5446,6 +5732,8 @@ namespace Mono.CSharp {
#region Properties #region Properties
protected abstract Arguments Arguments { get; set; }
public MethodSpec Getter { public MethodSpec Getter {
get { get {
return getter; return getter;
@ -5520,14 +5808,43 @@ namespace Mono.CSharp {
// //
// Implements the IAssignMethod interface for assignments // Implements the IAssignMethod interface for assignments
// //
public abstract void Emit (EmitContext ec, bool leave_copy); public virtual void Emit (EmitContext ec, bool leave_copy)
public abstract void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load); {
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) public override void Emit (EmitContext ec)
{ {
Emit (ec, false); 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); public abstract SLE.Expression MakeAssignExpression (BuilderContext ctx, Expression source);
protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side); protected abstract Expression OverloadResolve (ResolveContext rc, Expression right_side);
@ -5716,14 +6033,17 @@ namespace Mono.CSharp {
throw new NotImplementedException (); 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"); throw new NotImplementedException ("EventExpr::EmitAssign");
Arguments args = new Arguments (1); Arguments args = new Arguments (1);
args.Add (new Argument (source)); 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 #endregion
@ -5810,20 +6130,15 @@ namespace Mono.CSharp {
return new TemporaryVariableReference (li, loc); return new TemporaryVariableReference (li, loc);
} }
public override Expression CreateExpressionTree (ResolveContext ec)
{
throw new NotSupportedException ("ET");
}
protected override Expression DoResolve (ResolveContext ec) protected override Expression DoResolve (ResolveContext ec)
{ {
eclass = ExprClass.Variable; eclass = ExprClass.Variable;
// //
// Don't capture temporary variables except when using // 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); AnonymousMethodStorey storey = li.Block.Explicit.CreateAnonymousMethodStorey (ec);
storey.CaptureLocalVariable (ec, li); storey.CaptureLocalVariable (ec, li);
} }
@ -5877,7 +6192,7 @@ namespace Mono.CSharp {
} }
public override VariableInfo VariableInfo { 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 {
this.prev = prev; this.prev = prev;
} }
public override bool ContainsEmitWithAwait ()
{
return false;
}
public override Expression CreateExpressionTree (ResolveContext ec) public override Expression CreateExpressionTree (ResolveContext ec)
{ {
throw new NotSupportedException ("Missing Resolve call"); throw new NotSupportedException ("Missing Resolve call");

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

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

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

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

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

@ -5,7 +5,8 @@
// //
// Dual licensed under the terms of the MIT X11 or GNU GPL // 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; using System;
@ -962,6 +963,15 @@ namespace Mono.CSharp
if (spec.BaseType != null) { if (spec.BaseType != null) {
var bifaces = spec.BaseType.Interfaces; var bifaces = spec.BaseType.Interfaces;
if (bifaces != null) { 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) foreach (var iface in bifaces)
spec.AddInterface (iface); spec.AddInterface (iface);
} }
@ -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) { if (!onlyTypes) {
// //
// The logic here requires methods to be returned first which seems to work for both Mono and .NET // 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
cache.AddMemberImported (imported); 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 @@
// Dual licensed under the terms of the MIT X11 or GNU GPL // Dual licensed under the terms of the MIT X11 or GNU GPL
// Copyright 2003 Ximian, Inc. // Copyright 2003 Ximian, Inc.
// Copyright 2003-2008 Novell, Inc. // Copyright 2003-2008 Novell, Inc.
// Copyright 2011 Xamarin Inc.
// //
// TODO: // TODO:
@ -28,7 +29,7 @@ namespace Mono.CSharp
public abstract class YieldStatement<T> : ResumableStatement where T : StateMachineInitializer public abstract class YieldStatement<T> : ResumableStatement where T : StateMachineInitializer
{ {
protected Expression expr; protected Expression expr;
bool unwind_protect; protected bool unwind_protect;
protected T machine_initializer; protected T machine_initializer;
int resume_pc; int resume_pc;
@ -62,7 +63,7 @@ namespace Mono.CSharp
machine_initializer = bc.CurrentAnonymousMethod as T; machine_initializer = bc.CurrentAnonymousMethod as T;
if (!bc.CurrentBranching.CurrentUsageVector.IsUnreachable) 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; return true;
} }
@ -156,7 +157,6 @@ namespace Mono.CSharp
Start = 0 Start = 0
} }
Field disposing_field;
Field pc_field; Field pc_field;
int local_name_idx; int local_name_idx;
StateMachineMethod method; StateMachineMethod method;
@ -168,12 +168,6 @@ namespace Mono.CSharp
#region Properties #region Properties
public Field DisposingField {
get {
return disposing_field;
}
}
public StateMachineMethod StateMachineMethod { public StateMachineMethod StateMachineMethod {
get { get {
return method; return method;
@ -200,14 +194,13 @@ namespace Mono.CSharp
protected override bool DoDefineMembers () protected override bool DoDefineMembers ()
{ {
pc_field = AddCompilerGeneratedField ("$PC", new TypeExpression (Compiler.BuiltinTypes.Int, Location)); pc_field = AddCompilerGeneratedField ("$PC", new TypeExpression (Compiler.BuiltinTypes.Int, Location));
disposing_field = AddCompilerGeneratedField ("$disposing", new TypeExpression (Compiler.BuiltinTypes.Bool, Location));
return base.DoDefineMembers (); return base.DoDefineMembers ();
} }
protected override string GetVariableMangledName (LocalVariable local_info) 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
{ {
Label label_init = ec.DefineLabel (); Label label_init = ec.DefineLabel ();
ec.Emit (OpCodes.Ldarg_0); ec.EmitThis ();
ec.Emit (OpCodes.Ldflda, host.PC.Spec); ec.Emit (OpCodes.Ldflda, host.PC.Spec);
ec.EmitInt ((int) State.Start); ec.EmitInt ((int) State.Start);
ec.EmitInt ((int) State.Uninitialized); ec.EmitInt ((int) State.Uninitialized);
@ -292,7 +285,7 @@ namespace Mono.CSharp
ec.EmitInt ((int) State.Uninitialized); ec.EmitInt ((int) State.Uninitialized);
ec.Emit (OpCodes.Bne_Un_S, label_init); ec.Emit (OpCodes.Bne_Un_S, label_init);
ec.Emit (OpCodes.Ldarg_0); ec.EmitThis ();
ec.Emit (OpCodes.Ret); ec.Emit (OpCodes.Ret);
ec.MarkLabel (label_init); ec.MarkLabel (label_init);
@ -396,6 +389,7 @@ namespace Mono.CSharp
TypeExpr iterator_type_expr; TypeExpr iterator_type_expr;
Field current_field; Field current_field;
Field disposing_field;
TypeExpr enumerator_type; TypeExpr enumerator_type;
TypeExpr enumerable_type; TypeExpr enumerable_type;
@ -411,7 +405,15 @@ namespace Mono.CSharp
} }
public Field CurrentField { public Field CurrentField {
get { return current_field; } get {
return current_field;
}
}
public Field DisposingField {
get {
return disposing_field;
}
} }
public IList<HoistedParameter> HoistedParameters { public IList<HoistedParameter> HoistedParameters {
@ -457,6 +459,7 @@ namespace Mono.CSharp
protected override bool DoDefineMembers () protected override bool DoDefineMembers ()
{ {
current_field = AddCompilerGeneratedField ("$current", iterator_type_expr); current_field = AddCompilerGeneratedField ("$current", iterator_type_expr);
disposing_field = AddCompilerGeneratedField ("$disposing", new TypeExpression (Compiler.BuiltinTypes.Bool, Location));
if (hoisted_params != null) { if (hoisted_params != null) {
// //
@ -578,6 +581,10 @@ namespace Mono.CSharp
{ {
EmitContext ec = new EmitContext (this, ig, MemberType); EmitContext ec = new EmitContext (this, ig, MemberType);
ec.CurrentAnonymousMethod = expr; ec.CurrentAnonymousMethod = expr;
if (expr is AsyncInitializer)
ec.With (BuilderContext.Options.AsyncBody, true);
return ec; return ec;
} }
} }
@ -617,9 +624,11 @@ namespace Mono.CSharp
// The state as we generate the machine // The state as we generate the machine
// //
Label move_next_ok; Label move_next_ok;
Label iterator_body_end;
protected Label move_next_error; protected Label move_next_error;
protected LocalBuilder skip_finally, current_pc; LocalBuilder skip_finally;
List<ResumableStatement> resume_points; protected LocalBuilder current_pc;
protected List<ResumableStatement> resume_points;
protected StateMachineInitializer (ParametersBlock block, TypeContainer host, TypeSpec returnType) protected StateMachineInitializer (ParametersBlock block, TypeContainer host, TypeSpec returnType)
: base (block, returnType, block.StartLocation) : base (block, returnType, block.StartLocation)
@ -627,12 +636,35 @@ namespace Mono.CSharp
this.Host = host; 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 { public override AnonymousMethodStorey Storey {
get { get {
return storey; return storey;
} }
} }
#endregion
public int AddResumePoint (ResumableStatement stmt) public int AddResumePoint (ResumableStatement stmt)
{ {
if (resume_points == null) if (resume_points == null)
@ -660,7 +692,6 @@ namespace Mono.CSharp
var ctx = CreateBlockContext (ec); var ctx = CreateBlockContext (ec);
ctx.StartFlowBranching (this, ec.CurrentBranching);
Block.Resolve (ctx); Block.Resolve (ctx);
// //
@ -690,70 +721,26 @@ namespace Mono.CSharp
storey.Instance.Emit (ec); 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) 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.Ldfld, storey.PC.Spec);
ec.Emit (OpCodes.Ldarg_0); ec.EmitThis ();
ec.EmitInt ((int) IteratorStorey.State.After); ec.EmitInt ((int) IteratorStorey.State.After);
ec.Emit (OpCodes.Stfld, storey.PC.Spec); ec.Emit (OpCodes.Stfld, storey.PC.Spec);
// We only care if the PC is zero (start executing) or non-zero (don't do anything) // We only care if the PC is zero (start executing) or non-zero (don't do anything)
ec.Emit (OpCodes.Brtrue, move_next_error); ec.Emit (OpCodes.Brtrue, move_next_error);
iterator_body_end = ec.DefineLabel ();
SymbolWriter.StartIteratorBody (ec); SymbolWriter.StartIteratorBody (ec);
original_block.Emit (ec); original_block.Emit (ec);
SymbolWriter.EndIteratorBody (ec); SymbolWriter.EndIteratorBody (ec);
ec.MarkLabel (iterator_body_end);
EmitMoveNextEpilogue (ec); EmitMoveNextEpilogue (ec);
ec.MarkLabel (move_next_error); ec.MarkLabel (move_next_error);
@ -773,14 +760,14 @@ namespace Mono.CSharp
EmitMoveNext_NoResumePoints (ec, block); EmitMoveNext_NoResumePoints (ec, block);
return; return;
} }
current_pc = ec.GetTemporaryLocal (ec.BuiltinTypes.UInt); current_pc = ec.GetTemporaryLocal (ec.BuiltinTypes.UInt);
ec.Emit (OpCodes.Ldarg_0); ec.EmitThis ();
ec.Emit (OpCodes.Ldfld, storey.PC.Spec); ec.Emit (OpCodes.Ldfld, storey.PC.Spec);
ec.Emit (OpCodes.Stloc, current_pc); 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 // 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.EmitInt ((int) IteratorStorey.State.After);
ec.Emit (OpCodes.Stfld, storey.PC.Spec); ec.Emit (OpCodes.Stfld, storey.PC.Spec);
@ -796,33 +783,57 @@ namespace Mono.CSharp
if (need_skip_finally) { if (need_skip_finally) {
skip_finally = ec.GetTemporaryLocal (ec.BuiltinTypes.Bool); skip_finally = ec.GetTemporaryLocal (ec.BuiltinTypes.Bool);
ec.Emit (OpCodes.Ldc_I4_0); ec.EmitInt (0);
ec.Emit (OpCodes.Stloc, skip_finally); ec.Emit (OpCodes.Stloc, skip_finally);
} }
var async_init = this as AsyncInitializer;
if (async_init != null)
ec.BeginExceptionBlock ();
SymbolWriter.StartIteratorDispatcher (ec); SymbolWriter.StartIteratorDispatcher (ec);
ec.Emit (OpCodes.Ldloc, current_pc); ec.Emit (OpCodes.Ldloc, current_pc);
ec.Emit (OpCodes.Switch, labels); 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); SymbolWriter.EndIteratorDispatcher (ec);
ec.MarkLabel (labels[0]); ec.MarkLabel (labels[0]);
iterator_body_end = ec.DefineLabel ();
SymbolWriter.StartIteratorBody (ec); SymbolWriter.StartIteratorBody (ec);
block.Emit (ec); block.Emit (ec);
SymbolWriter.EndIteratorBody (ec); SymbolWriter.EndIteratorBody (ec);
SymbolWriter.StartIteratorDispatcher (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.EmitInt ((int) IteratorStorey.State.After);
ec.Emit (OpCodes.Stfld, storey.PC.Spec); ec.Emit (OpCodes.Stfld, storey.PC.Spec);
EmitMoveNextEpilogue (ec); EmitMoveNextEpilogue (ec);
ec.MarkLabel (move_next_error); ec.MarkLabel (move_next_error);
if (ReturnType.Kind != MemberKind.Void) { if (ReturnType.Kind != MemberKind.Void) {
ec.EmitInt (0); ec.EmitInt (0);
ec.Emit (OpCodes.Ret); ec.Emit (OpCodes.Ret);
@ -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 // Called back from YieldStatement
// //
@ -851,28 +868,29 @@ namespace Mono.CSharp
// Guard against being disposed meantime // Guard against being disposed meantime
// //
Label disposed = ec.DefineLabel (); Label disposed = ec.DefineLabel ();
ec.Emit (OpCodes.Ldarg_0); var iterator = storey as IteratorStorey;
ec.Emit (OpCodes.Ldfld, storey.DisposingField.Spec); if (iterator != null) {
ec.Emit (OpCodes.Brtrue_S, disposed); ec.EmitThis ();
ec.Emit (OpCodes.Ldfld, iterator.DisposingField.Spec);
ec.Emit (OpCodes.Brtrue_S, disposed);
}
// //
// store resume program-counter // store resume program-counter
// //
ec.Emit (OpCodes.Ldarg_0); ec.EmitThis ();
ec.EmitInt (resume_pc); ec.EmitInt (resume_pc);
ec.Emit (OpCodes.Stfld, storey.PC.Spec); ec.Emit (OpCodes.Stfld, storey.PC.Spec);
ec.MarkLabel (disposed);
if (iterator != null) {
ec.MarkLabel (disposed);
}
// mark finally blocks as disabled // mark finally blocks as disabled
if (unwind_protect && skip_finally != null) { if (unwind_protect && skip_finally != null) {
ec.EmitInt (1); ec.EmitInt (1);
ec.Emit (OpCodes.Stloc, skip_finally); 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
this.type = method.ReturnType; this.type = method.ReturnType;
} }
public LocalBuilder SkipFinally {
get { return skip_finally; }
}
public LocalBuilder CurrentPC {
get { return current_pc; }
}
public Block Container { public Block Container {
get { return OriginalMethod.Block; } get { return OriginalMethod.Block; }
} }
@ -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) public override void EmitStatement (EmitContext ec)
{ {
throw new NotImplementedException (); throw new NotImplementedException ();
@ -964,6 +1022,17 @@ namespace Mono.CSharp
fe.EmitAssign (ec, expr, false, false); fe.EmitAssign (ec, expr, false, false);
base.InjectYield (ec, expr, resume_pc, unwind_protect, resume_point); 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) 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 {
{ {
if (statement != null) { if (statement != null) {
statement.EmitStatement (ec); statement.EmitStatement (ec);
ec.Emit (OpCodes.Ret); if (unwind_protect)
ec.Emit (OpCodes.Leave, ec.CreateReturnLabel ());
else {
ec.Emit (OpCodes.Ret);
}
return; return;
} }

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

@ -1151,7 +1151,7 @@ namespace Mono.CSharp {
} }
if ((ModFlags & Modifiers.ASYNC) != 0) { 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 {
} }
} }
public override bool ContainsEmitWithAwait ()
{
throw new NotSupportedException ();
}
public override Expression CreateExpressionTree (ResolveContext ec) public override Expression CreateExpressionTree (ResolveContext ec)
{ {
throw new NotSupportedException ("ET"); throw new NotSupportedException ("ET");
@ -1386,7 +1391,9 @@ namespace Mono.CSharp {
ec.Mark (loc); 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) public override void EmitStatement (EmitContext ec)
@ -1633,11 +1640,6 @@ namespace Mono.CSharp {
EmitContext ec = new EmitContext (this, ConstructorBuilder.GetILGenerator (), bc.ReturnType); EmitContext ec = new EmitContext (this, ConstructorBuilder.GetILGenerator (), bc.ReturnType);
ec.With (EmitContext.Options.ConstructorScope, true); ec.With (EmitContext.Options.ConstructorScope, true);
if (!ec.HasReturnLabel && bc.HasReturnLabel) {
ec.ReturnLabel = bc.ReturnLabel;
ec.HasReturnLabel = true;
}
block.Emit (ec); block.Emit (ec);
} }
} }
@ -2036,10 +2038,6 @@ namespace Mono.CSharp {
BlockContext bc = new BlockContext (mc, block, method.ReturnType); BlockContext bc = new BlockContext (mc, block, method.ReturnType);
if (block.Resolve (null, bc, method)) { if (block.Resolve (null, bc, method)) {
EmitContext ec = method.CreateEmitContext (MethodBuilder.GetILGenerator ()); EmitContext ec = method.CreateEmitContext (MethodBuilder.GetILGenerator ());
if (!ec.HasReturnLabel && bc.HasReturnLabel) {
ec.ReturnLabel = bc.ReturnLabel;
ec.HasReturnLabel = true;
}
block.Emit (ec); block.Emit (ec);
} }

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

@ -370,9 +370,9 @@ namespace Mono.CSharp {
return res; 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) public List<MethodSpec> LookupExtensionMethod (IMemberContext invocationContext, TypeSpec extensionType, string name, int arity)
{ {
if (types == null) if (types == null)
@ -402,6 +402,26 @@ namespace Mono.CSharp {
return found; 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) public void AddType (ModuleContainer module, TypeSpec ts)
{ {
if (types == null) { if (types == null) {
@ -797,7 +817,7 @@ namespace Mono.CSharp {
// Does extension methods look up to find a method which matches name and extensionType. // 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. // 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; List<MethodSpec> candidates = null;
foreach (Namespace n in GetUsingTable ()) { foreach (Namespace n in GetUsingTable ()) {
@ -811,29 +831,21 @@ namespace Mono.CSharp {
candidates.AddRange (a); candidates.AddRange (a);
} }
scope = parent;
if (candidates != null) if (candidates != null)
return candidates; return new ExtensionMethodCandidates (candidates, this);
if (parent == null) if (parent == null)
return null; return null;
// Namespace ns_scope;
// Inspect parent namespaces in namespace expression var ns_candidates = ns.Parent.LookupExtensionMethod (this, extensionType, name, arity, out ns_scope);
// if (ns_candidates != null)
Namespace parent_ns = ns.Parent; return new ExtensionMethodCandidates (ns_candidates, this, ns_scope);
do {
candidates = parent_ns.LookupExtensionMethod (this, extensionType, name, arity);
if (candidates != null)
return candidates;
parent_ns = parent_ns.Parent;
} while (parent_ns != null);
// //
// 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) 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
} }
} }
public class Unwrap : Expression, IMemoryLocation, IAssignMethod public class Unwrap : Expression, IMemoryLocation
{ {
Expression expr; Expression expr;
@ -96,6 +96,11 @@ namespace Mono.CSharp.Nullable
eclass = expr.eclass; eclass = expr.eclass;
} }
public override bool ContainsEmitWithAwait ()
{
return expr.ContainsEmitWithAwait ();
}
public static Expression Create (Expression expr) public static Expression Create (Expression expr)
{ {
// //
@ -132,16 +137,24 @@ namespace Mono.CSharp.Nullable
public override void Emit (EmitContext ec) public override void Emit (EmitContext ec)
{ {
Store (ec); Store (ec);
var call = new CallEmitter ();
call.InstanceExpression = this;
if (useDefaultValue) if (useDefaultValue)
Invocation.EmitCall (ec, this, NullableInfo.GetGetValueOrDefault (expr.Type), null, loc); call.EmitPredefined (ec, NullableInfo.GetGetValueOrDefault (expr.Type), null);
else else
Invocation.EmitCall (ec, this, NullableInfo.GetValue (expr.Type), null, loc); call.EmitPredefined (ec, NullableInfo.GetValue (expr.Type), null);
} }
public void EmitCheck (EmitContext ec) public void EmitCheck (EmitContext ec)
{ {
Store (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) public override bool Equals (object obj)
@ -169,10 +182,10 @@ namespace Mono.CSharp.Nullable
void Store (EmitContext ec) void Store (EmitContext ec)
{ {
if (expr is VariableReference) if (temp != null)
return; return;
if (temp != null) if (expr is VariableReference)
return; return;
expr.Emit (ec); expr.Emit (ec);
@ -211,51 +224,6 @@ namespace Mono.CSharp.Nullable
return temp; 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
public override void Emit (EmitContext ec) 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
value_target.AddressOf (ec, AddressOp.Store); value_target.AddressOf (ec, AddressOp.Store);
ec.Emit (OpCodes.Initobj, type); ec.Emit (OpCodes.Initobj, type);
value_target.Emit (ec); value_target.Emit (ec);
value_target.Release (ec);
} }
public void AddressOf (EmitContext ec, AddressOp Mode) public void AddressOf (EmitContext ec, AddressOp Mode)
@ -386,6 +357,11 @@ namespace Mono.CSharp.Nullable
: this (expr, unwrap as Unwrap, type) : this (expr, unwrap as Unwrap, type)
{ {
} }
public override bool ContainsEmitWithAwait ()
{
return unwrap.ContainsEmitWithAwait ();
}
public override Expression CreateExpressionTree (ResolveContext ec) public override Expression CreateExpressionTree (ResolveContext ec)
{ {
@ -677,7 +653,7 @@ namespace Mono.CSharp.Nullable
} }
left_unwrap.Emit (ec); left_unwrap.Emit (ec);
ec.Emit (OpCodes.Brtrue_S, load_right); ec.Emit (OpCodes.Brtrue, load_right);
// value & null, value | null // value & null, value | null
if (right_unwrap != null) { if (right_unwrap != null) {
@ -733,7 +709,7 @@ namespace Mono.CSharp.Nullable
if (left_unwrap != null && (IsRightNullLifted || right.IsNull)) { if (left_unwrap != null && (IsRightNullLifted || right.IsNull)) {
left_unwrap.EmitCheck (ec); left_unwrap.EmitCheck (ec);
if (Oper == Binary.Operator.Equality) { if (Oper == Binary.Operator.Equality) {
ec.Emit (OpCodes.Ldc_I4_0); ec.EmitInt (0);
ec.Emit (OpCodes.Ceq); ec.Emit (OpCodes.Ceq);
} }
return; return;
@ -742,7 +718,7 @@ namespace Mono.CSharp.Nullable
if (right_unwrap != null && (IsLeftNullLifted || left.IsNull)) { if (right_unwrap != null && (IsLeftNullLifted || left.IsNull)) {
right_unwrap.EmitCheck (ec); right_unwrap.EmitCheck (ec);
if (Oper == Binary.Operator.Equality) { if (Oper == Binary.Operator.Equality) {
ec.Emit (OpCodes.Ldc_I4_0); ec.EmitInt (0);
ec.Emit (OpCodes.Ceq); ec.Emit (OpCodes.Ceq);
} }
return; return;
@ -755,6 +731,11 @@ namespace Mono.CSharp.Nullable
user_operator.Emit (ec); user_operator.Emit (ec);
ec.Emit (Oper == Operator.Equality ? OpCodes.Brfalse_S : OpCodes.Brtrue_S, dissimilar_label); ec.Emit (Oper == Operator.Equality ? OpCodes.Brfalse_S : OpCodes.Brtrue_S, dissimilar_label);
} else { } else {
if (ec.HasSet (BuilderContext.Options.AsyncBody) && right.ContainsEmitWithAwait ()) {
left = left.EmitToField (ec);
right = right.EmitToField (ec);
}
left.Emit (ec); left.Emit (ec);
right.Emit (ec); right.Emit (ec);
@ -774,7 +755,7 @@ namespace Mono.CSharp.Nullable
ec.Emit (OpCodes.Ceq); ec.Emit (OpCodes.Ceq);
} else { } else {
if (Oper == Operator.Inequality) { if (Oper == Operator.Inequality) {
ec.Emit (OpCodes.Ldc_I4_0); ec.EmitInt (0);
ec.Emit (OpCodes.Ceq); ec.Emit (OpCodes.Ceq);
} }
} }
@ -783,9 +764,9 @@ namespace Mono.CSharp.Nullable
ec.MarkLabel (dissimilar_label); ec.MarkLabel (dissimilar_label);
if (Oper == Operator.Inequality) if (Oper == Operator.Inequality)
ec.Emit (OpCodes.Ldc_I4_1); ec.EmitInt (1);
else else
ec.Emit (OpCodes.Ldc_I4_0); ec.EmitInt (0);
ec.MarkLabel (end_label); ec.MarkLabel (end_label);
} }
@ -839,7 +820,7 @@ namespace Mono.CSharp.Nullable
ec.MarkLabel (is_null_label); ec.MarkLabel (is_null_label);
if ((Oper & Operator.ComparisonMask) != 0) { if ((Oper & Operator.ComparisonMask) != 0) {
ec.Emit (OpCodes.Ldc_I4_0); ec.EmitInt (0);
} else { } else {
LiftedNull.Create (type, loc).Emit (ec); LiftedNull.Create (type, loc).Emit (ec);
} }
@ -854,8 +835,14 @@ namespace Mono.CSharp.Nullable
return; return;
} }
if (l.IsNullableType) if (left.Type.IsNullableType) {
l = TypeManager.GetTypeArguments (l) [0]; 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); base.EmitOperator (ec, l);
} }
@ -1149,6 +1136,14 @@ namespace Mono.CSharp.Nullable
return this; 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) protected override Expression DoResolve (ResolveContext ec)
{ {
left = left.Resolve (ec); left = left.Resolve (ec);
@ -1217,75 +1212,58 @@ namespace Mono.CSharp.Nullable
} }
} }
public class LiftedUnaryMutator : ExpressionStatement class LiftedUnaryMutator : UnaryMutator
{ {
public readonly UnaryMutator.Mode Mode; public LiftedUnaryMutator (Mode mode, Expression expr, Location loc)
Expression expr; : base (mode, expr, loc)
UnaryMutator underlying;
Unwrap unwrap;
public LiftedUnaryMutator (UnaryMutator.Mode mode, Expression expr, Location 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) protected override Expression DoResolve (ResolveContext ec)
{ {
expr = expr.Resolve (ec); var orig_expr = expr;
if (expr == null)
return null;
unwrap = Unwrap.Create (expr, false);
if (unwrap == null)
return null;
underlying = (UnaryMutator) new UnaryMutator (Mode, unwrap, loc).Resolve (ec); expr = Unwrap.Create (expr);
if (underlying == null)
return null;
var res = base.DoResolveOperation (ec);
eclass = ExprClass.Value; expr = orig_expr;
type = expr.Type; 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 is_null_label = ec.DefineLabel ();
Label end_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); ec.Emit (OpCodes.Brfalse, is_null_label);
if (is_expr) { call = new CallEmitter ();
underlying.Emit (ec); call.InstanceExpression = lt;
ec.Emit (OpCodes.Br_S, end_label); call.EmitPredefined (ec, NullableInfo.GetValue (expr.Type), null);
} else {
underlying.EmitStatement (ec);
}
ec.MarkLabel (is_null_label); lt.Release (ec);
if (is_expr)
LiftedNull.Create (type, loc).Emit (ec);
ec.MarkLabel (end_label); base.EmitOperation (ec);
}
public override void Emit (EmitContext ec) ec.Emit (OpCodes.Newobj, NullableInfo.GetConstructor (type));
{ ec.Emit (OpCodes.Br_S, end_label);
DoEmit (ec, true);
}
public override void EmitStatement (EmitContext ec) ec.MarkLabel (is_null_label);
{ LiftedNull.Create (type, loc).Emit (ec);
DoEmit (ec, false);
ec.MarkLabel (end_label);
} }
} }
} }

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

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

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

@ -51,6 +51,78 @@ namespace Mono.CSharp {
public MethodSpec [] need_proxy; 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 public class PendingImplementation
{ {
/// <summary> /// <summary>
@ -434,10 +506,11 @@ namespace Mono.CSharp {
} }
int top = param.Count; 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 // TODO: GetAllParametersArguments
for (int i = 0; i <= top; i++) for (int i = 0; i < top; i++)
ParameterReference.EmitLdArg (ec, i); ec.EmitArgumentLoad (i);
ec.Emit (OpCodes.Call, base_method); ec.Emit (OpCodes.Call, base_method);
ec.Emit (OpCodes.Ret); ec.Emit (OpCodes.Ret);

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

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

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

@ -608,7 +608,7 @@ namespace Mono.CSharp
return PartialContainer.IsClsComplianceRequired (); 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; return null;
} }

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

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

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

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

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

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

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

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

Loading…
Cancel
Save