Browse Source

Updated mcs. Note: Switch ast changed in mcs. (does not affect the

nrefactory AST)
pull/32/merge
Mike Krüger 13 years ago
parent
commit
df1fa134c6
  1. 71
      ICSharpCode.NRefactory.CSharp/Parser/CSharpParser.cs
  2. 23
      ICSharpCode.NRefactory.CSharp/Parser/mcs/anonymous.cs
  3. 14
      ICSharpCode.NRefactory.CSharp/Parser/mcs/assign.cs
  4. 46
      ICSharpCode.NRefactory.CSharp/Parser/mcs/cfold.cs
  5. 1
      ICSharpCode.NRefactory.CSharp/Parser/mcs/class.cs
  6. 3
      ICSharpCode.NRefactory.CSharp/Parser/mcs/convert.cs
  7. 6884
      ICSharpCode.NRefactory.CSharp/Parser/mcs/cs-parser.cs
  8. 43
      ICSharpCode.NRefactory.CSharp/Parser/mcs/cs-parser.jay
  9. 93
      ICSharpCode.NRefactory.CSharp/Parser/mcs/delegate.cs
  10. 59
      ICSharpCode.NRefactory.CSharp/Parser/mcs/ecore.cs
  11. 4
      ICSharpCode.NRefactory.CSharp/Parser/mcs/eval.cs
  12. 90
      ICSharpCode.NRefactory.CSharp/Parser/mcs/expression.cs
  13. 10
      ICSharpCode.NRefactory.CSharp/Parser/mcs/field.cs
  14. 2
      ICSharpCode.NRefactory.CSharp/Parser/mcs/flowanalysis.cs
  15. 2
      ICSharpCode.NRefactory.CSharp/Parser/mcs/import.cs
  16. 2
      ICSharpCode.NRefactory.CSharp/Parser/mcs/lambda.cs
  17. 18
      ICSharpCode.NRefactory.CSharp/Parser/mcs/membercache.cs
  18. 595
      ICSharpCode.NRefactory.CSharp/Parser/mcs/statement.cs
  19. 5
      ICSharpCode.NRefactory.CSharp/Parser/mcs/visit.cs

71
ICSharpCode.NRefactory.CSharp/Parser/CSharpParser.cs

@ -1822,40 +1822,31 @@ namespace ICSharpCode.NRefactory.CSharp @@ -1822,40 +1822,31 @@ namespace ICSharpCode.NRefactory.CSharp
result.AddChild (new CSharpTokenNode (Convert (location [1]), Roles.RPar), Roles.RPar);
if (location != null && location.Count > 2)
result.AddChild (new CSharpTokenNode (Convert (location [2]), Roles.LBrace), Roles.LBrace);
if (switchStatement.Sections != null) {
foreach (var section in switchStatement.Sections) {
var newSection = new SwitchSection ();
if (section.Labels != null) {
foreach (var caseLabel in section.Labels) {
var newLabel = new CaseLabel ();
if (caseLabel.Label != null) {
newLabel.AddChild (new CSharpTokenNode (Convert (caseLabel.Location), CaseLabel.CaseKeywordRole), CaseLabel.CaseKeywordRole);
if (caseLabel.Label != null)
newLabel.AddChild ((Expression)caseLabel.Label.Accept (this), Roles.Expression);
var colonLocation = LocationsBag.GetLocations (caseLabel);
if (colonLocation != null)
newLabel.AddChild (new CSharpTokenNode (Convert (colonLocation [0]), Roles.Colon), Roles.Colon);
} else {
newLabel.AddChild (new CSharpTokenNode (Convert (caseLabel.Location), CaseLabel.DefaultKeywordRole), CaseLabel.DefaultKeywordRole);
newLabel.AddChild (new CSharpTokenNode (new TextLocation (caseLabel.Location.Row, caseLabel.Location.Column + "default".Length), Roles.Colon), Roles.Colon);
}
newSection.AddChild (newLabel, SwitchSection.CaseLabelRole);
}
SwitchSection newSection = null;
bool lastWasCase = false, added = true;
foreach (var child in switchStatement.Block.Statements) {
var statement = child.Accept(this);
var caseLabel = statement as CaseLabel;
if (caseLabel != null) {
if (!lastWasCase) {
newSection = new SwitchSection();
added = false;
}
var blockStatement = section.Block;
var bodyBlock = new BlockStatement ();
int curLocal = 0;
AddBlockChildren (bodyBlock, blockStatement, ref curLocal);
foreach (var statement in bodyBlock.Statements) {
statement.Remove ();
newSection.AddChild (statement, Roles.EmbeddedStatement);
newSection.AddChild (caseLabel, SwitchSection.CaseLabelRole);
lastWasCase = true;
} else {
if (lastWasCase) {
result.AddChild (newSection, SwitchStatement.SwitchSectionRole);
lastWasCase = false;
added = true;
}
result.AddChild (newSection, SwitchStatement.SwitchSectionRole);
newSection.AddChild((Statement)statement, Roles.EmbeddedStatement);
}
}
if (!added)
result.AddChild (newSection, SwitchStatement.SwitchSectionRole);
if (location != null && location.Count > 3) {
result.AddChild (new CSharpTokenNode (Convert (location [3]), Roles.RBrace), Roles.RBrace);
} else {
@ -1865,7 +1856,25 @@ namespace ICSharpCode.NRefactory.CSharp @@ -1865,7 +1856,25 @@ namespace ICSharpCode.NRefactory.CSharp
return result;
}
public override object Visit(SwitchLabel switchLabel)
{
var newLabel = new CaseLabel ();
if (!switchLabel.IsDefault) {
newLabel.AddChild (new CSharpTokenNode (Convert (switchLabel.Location), CaseLabel.CaseKeywordRole), CaseLabel.CaseKeywordRole);
if (switchLabel.Label != null)
newLabel.AddChild ((Expression)switchLabel.Label.Accept (this), Roles.Expression);
var colonLocation = LocationsBag.GetLocations (switchLabel);
if (colonLocation != null)
newLabel.AddChild (new CSharpTokenNode (Convert (colonLocation [0]), Roles.Colon), Roles.Colon);
} else {
newLabel.AddChild (new CSharpTokenNode (Convert (switchLabel.Location), CaseLabel.DefaultKeywordRole), CaseLabel.DefaultKeywordRole);
newLabel.AddChild (new CSharpTokenNode (new TextLocation (switchLabel.Location.Row, switchLabel.Location.Column + "default".Length), Roles.Colon), Roles.Colon);
}
return newLabel;
}
public override object Visit (Lock lockStatement)
{
var result = new LockStatement ();

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

@ -1230,6 +1230,17 @@ namespace Mono.CSharp { @@ -1230,6 +1230,17 @@ namespace Mono.CSharp {
}
} else {
am = body.Compatible (ec);
if (body.DirectMethodGroupConversion != null) {
var errors_printer = new SessionReportPrinter ();
var old = ec.Report.SetPrinter (errors_printer);
var expr = new ImplicitDelegateCreation (delegate_type, body.DirectMethodGroupConversion, loc) {
AllowSpecialMethodsInvocation = true
}.Resolve (ec);
ec.Report.SetPrinter (old);
if (expr != null && errors_printer.ErrorsCount == 0)
am = expr;
}
}
} catch (CompletionResult) {
throw;
@ -1568,6 +1579,14 @@ namespace Mono.CSharp { @@ -1568,6 +1579,14 @@ namespace Mono.CSharp {
get { return "anonymous method"; }
}
//
// Method-group instance for lambdas which can be replaced with
// simple method group call
//
public MethodGroupExpr DirectMethodGroupConversion {
get; set;
}
public override bool IsIterator {
get {
return false;
@ -1590,7 +1609,9 @@ namespace Mono.CSharp { @@ -1590,7 +1609,9 @@ namespace Mono.CSharp {
}
public override AnonymousMethodStorey Storey {
get { return storey; }
get {
return storey;
}
}
#endregion

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

@ -310,6 +310,12 @@ namespace Mono.CSharp { @@ -310,6 +310,12 @@ namespace Mono.CSharp {
}
}
public override Location StartLocation {
get {
return target.StartLocation;
}
}
public override bool ContainsEmitWithAwait ()
{
return target.ContainsEmitWithAwait () || source.ContainsEmitWithAwait ();
@ -541,7 +547,7 @@ namespace Mono.CSharp { @@ -541,7 +547,7 @@ namespace Mono.CSharp {
// Keep resolved value because field initializers have their own rules
//
ExpressionStatement resolved;
IMemberContext mc;
FieldBase mc;
public FieldInitializer (FieldBase mc, Expression expression, Location loc)
: base (new FieldExpr (mc.Spec, expression.Location), expression, loc)
@ -551,6 +557,12 @@ namespace Mono.CSharp { @@ -551,6 +557,12 @@ namespace Mono.CSharp {
((FieldExpr)target).InstanceExpression = new CompilerGeneratedThis (mc.CurrentType, expression.Location);
}
public override Location StartLocation {
get {
return loc;
}
}
protected override Expression DoResolve (ResolveContext ec)
{
// Field initializer can be resolved (fail) many times

46
ICSharpCode.NRefactory.CSharp/Parser/mcs/cfold.cs

@ -299,25 +299,51 @@ namespace Mono.CSharp { @@ -299,25 +299,51 @@ namespace Mono.CSharp {
break;
case Binary.Operator.Addition:
if (lt == InternalType.NullLiteral)
return right;
if (rt == InternalType.NullLiteral)
return left;
//
// If both sides are strings, then concatenate, if
// one is a string, and the other is not, then defer
// to runtime concatenation
// If both sides are strings, then concatenate
//
// string operator + (string x, string y)
//
if (lt.BuiltinType == BuiltinTypeSpec.Type.String || rt.BuiltinType == BuiltinTypeSpec.Type.String){
if (lt == rt)
return new StringConstant (ec.BuiltinTypes, (string)left.GetValue () + (string)right.GetValue (),
left.Location);
if (lt == InternalType.NullLiteral)
return new StringConstant (ec.BuiltinTypes, "" + right.GetValue (), left.Location);
if (rt == InternalType.NullLiteral)
return new StringConstant (ec.BuiltinTypes, left.GetValue () + "", left.Location);
return null;
}
//
// string operator + (string x, object y)
//
if (lt == InternalType.NullLiteral) {
if (rt.BuiltinType == BuiltinTypeSpec.Type.Object)
return new StringConstant (ec.BuiltinTypes, "" + right.GetValue (), left.Location);
if (lt == rt) {
ec.Report.Error (34, loc, "Operator `{0}' is ambiguous on operands of type `{1}' and `{2}'",
"+", lt.GetSignatureForError (), rt.GetSignatureForError ());
return null;
}
return right;
}
//
// string operator + (object x, string y)
//
if (rt == InternalType.NullLiteral) {
if (lt.BuiltinType == BuiltinTypeSpec.Type.Object)
return new StringConstant (ec.BuiltinTypes, right.GetValue () + "", left.Location);
return left;
}
//
// handle "E operator + (E x, U y)"
// handle "E operator + (Y y, E x)"

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

@ -544,6 +544,7 @@ namespace Mono.CSharp @@ -544,6 +544,7 @@ namespace Mono.CSharp
public int DynamicSitesCounter;
public int AnonymousMethodsCounter;
public int MethodGroupsCounter;
static readonly string[] attribute_targets = new string[] { "type" };

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

@ -1310,8 +1310,7 @@ namespace Mono.CSharp { @@ -1310,8 +1310,7 @@ namespace Mono.CSharp {
if (ec.Module.Compiler.Settings.Version != LanguageVersion.ISO_1){
MethodGroupExpr mg = expr as MethodGroupExpr;
if (mg != null)
return ImplicitDelegateCreation.Create (
ec, mg, target_type, loc);
return new ImplicitDelegateCreation (target_type, mg, loc).Resolve (ec);
}
}

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

File diff suppressed because it is too large Load Diff

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

@ -3209,12 +3209,12 @@ close_parens @@ -3209,12 +3209,12 @@ close_parens
parenthesized_expression
: OPEN_PARENS expression CLOSE_PARENS
{
$$ = new ParenthesizedExpression ((Expression) $2);
$$ = new ParenthesizedExpression ((Expression) $2, GetLocation ($1));
lbag.AddLocation ($$, GetLocation ($1), GetLocation ($3));
}
| OPEN_PARENS expression COMPLETE_COMPLETION
{
$$ = new ParenthesizedExpression ((Expression) $2);
$$ = new ParenthesizedExpression ((Expression) $2, GetLocation ($1));
}
;
@ -5591,7 +5591,7 @@ switch_statement @@ -5591,7 +5591,7 @@ switch_statement
}
opt_switch_sections CLOSE_BRACE
{
$$ = new Switch ((Expression) $3, (ExplicitBlock) current_block.Explicit, (List<SwitchSection>) $7, GetLocation ($1));
$$ = new Switch ((Expression) $3, (ExplicitBlock) current_block.Explicit, GetLocation ($1));
end_block (GetLocation ($8));
lbag.AddStatement ($$, GetLocation ($2), GetLocation ($4), GetLocation ($5), GetLocation ($8));
}
@ -5599,7 +5599,7 @@ switch_statement @@ -5599,7 +5599,7 @@ switch_statement
{
Error_SyntaxError (yyToken);
$$ = new Switch ((Expression) $3, null, null, GetLocation ($1));
$$ = new Switch ((Expression) $3, null, GetLocation ($1));
lbag.AddStatement ($$, GetLocation ($2));
}
;
@ -5608,58 +5608,33 @@ opt_switch_sections @@ -5608,58 +5608,33 @@ opt_switch_sections
: /* empty */
{
report.Warning (1522, 1, current_block.StartLocation, "Empty switch block");
$$ = new List<SwitchSection> ();
}
| switch_sections
;
switch_sections
: switch_section
{
var sections = new List<SwitchSection> (4);
sections.Add ((SwitchSection) $1);
$$ = sections;
}
| switch_sections switch_section
{
var sections = (List<SwitchSection>) $1;
sections.Add ((SwitchSection) $2);
$$ = sections;
}
| error
{
Error_SyntaxError (yyToken);
$$ = new List<SwitchSection> ();
}
;
switch_section
: switch_labels
{
current_block = current_block.CreateSwitchBlock (lexer.Location);
}
statement_list
{
$$ = new SwitchSection ((List<SwitchLabel>) $1, current_block);
}
: switch_labels statement_list
;
switch_labels
: switch_label
{
var labels = new List<SwitchLabel> (2);
labels.Add ((SwitchLabel) $1);
$$ = labels;
var label = (SwitchLabel) $1;
label.SectionStart = true;
current_block.AddStatement (label);
}
| switch_labels switch_label
{
var labels = (List<SwitchLabel>) ($1);
labels.Add ((SwitchLabel) $2);
$$ = labels;
current_block.AddStatement ((Statement) $2);
}
;

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

@ -436,6 +436,8 @@ namespace Mono.CSharp { @@ -436,6 +436,8 @@ namespace Mono.CSharp {
protected MethodSpec constructor_method;
protected MethodGroupExpr method_group;
public bool AllowSpecialMethodsInvocation { get; set; }
public override bool ContainsEmitWithAwait ()
{
return false;
@ -511,7 +513,8 @@ namespace Mono.CSharp { @@ -511,7 +513,8 @@ namespace Mono.CSharp {
return null;
}
Invocation.IsSpecialMethodInvocation (ec, delegate_method, loc);
if (!AllowSpecialMethodsInvocation)
Invocation.IsSpecialMethodInvocation (ec, delegate_method, loc);
ExtensionMethodGroupExpr emg = method_group as ExtensionMethodGroupExpr;
if (emg != null) {
@ -642,18 +645,92 @@ namespace Mono.CSharp { @@ -642,18 +645,92 @@ namespace Mono.CSharp {
//
public class ImplicitDelegateCreation : DelegateCreation
{
ImplicitDelegateCreation (TypeSpec t, MethodGroupExpr mg, Location l)
Field mg_cache;
public ImplicitDelegateCreation (TypeSpec delegateType, MethodGroupExpr mg, Location loc)
{
type = t;
type = delegateType;
this.method_group = mg;
loc = l;
this.loc = loc;
}
//
// Returns true when type is MVAR or has MVAR reference
//
static bool ContainsMethodTypeParameter (TypeSpec type)
{
var tps = type as TypeParameterSpec;
if (tps != null)
return tps.IsMethodOwned;
var ec = type as ElementTypeSpec;
if (ec != null)
return ContainsMethodTypeParameter (ec.Element);
foreach (var t in type.TypeArguments) {
if (ContainsMethodTypeParameter (t)) {
return true;
}
}
return false;
}
protected override Expression DoResolve (ResolveContext ec)
{
var expr = base.DoResolve (ec);
if (expr == null)
return null;
if (ec.IsInProbingMode)
return expr;
//
// Cache any static delegate creation
//
if (method_group.InstanceExpression != null)
return expr;
//
// Cannot easily cache types with MVAR
//
if (ContainsMethodTypeParameter (type))
return expr;
if (ContainsMethodTypeParameter (method_group.BestCandidate.DeclaringType))
return expr;
//
// Create type level cache for a delegate instance
//
var parent = ec.CurrentMemberDefinition.Parent.PartialContainer;
int id = parent.MethodGroupsCounter++;
mg_cache = new Field (parent, new TypeExpression (type, loc),
Modifiers.STATIC | Modifiers.PRIVATE | Modifiers.COMPILER_GENERATED,
new MemberName (CompilerGeneratedContainer.MakeName (null, "f", "mg$cache", id), loc), null);
mg_cache.Define ();
parent.AddField (mg_cache);
return expr;
}
static public Expression Create (ResolveContext ec, MethodGroupExpr mge,
TypeSpec target_type, Location loc)
public override void Emit (EmitContext ec)
{
ImplicitDelegateCreation d = new ImplicitDelegateCreation (target_type, mge, loc);
return d.DoResolve (ec);
Label l_initialized = ec.DefineLabel ();
if (mg_cache != null) {
ec.Emit (OpCodes.Ldsfld, mg_cache.Spec);
ec.Emit (OpCodes.Brtrue_S, l_initialized);
}
base.Emit (ec);
if (mg_cache != null) {
ec.Emit (OpCodes.Stsfld, mg_cache.Spec);
ec.MarkLabel (l_initialized);
ec.Emit (OpCodes.Ldsfld, mg_cache.Spec);
}
}
}

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

@ -152,6 +152,35 @@ namespace Mono.CSharp { @@ -152,6 +152,35 @@ namespace Mono.CSharp {
}
}
//
// Used to workaround parser limitation where we cannot get
// start of statement expression location
//
public virtual Location StartLocation {
get {
return loc;
}
}
public virtual MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
{
//
// Return method-group expression when the expression can be used as
// lambda replacement. A good example is array sorting where instead of
// code like
//
// Array.Sort (s, (a, b) => String.Compare (a, b));
//
// we can use method group directly
//
// Array.Sort (s, String.Compare);
//
// Correct overload will be used because we do the reduction after
// best candidate was found.
//
return null;
}
//
// Returns true when the expression during Emit phase breaks stack
// by using await expression
@ -1055,8 +1084,8 @@ namespace Mono.CSharp { @@ -1055,8 +1084,8 @@ namespace Mono.CSharp {
/// being that they would support an extra Emition interface that
/// does not leave a result on the stack.
/// </summary>
public abstract class ExpressionStatement : Expression {
public abstract class ExpressionStatement : Expression
{
public ExpressionStatement ResolveStatement (BlockContext ec)
{
Expression e = Resolve (ec);
@ -3220,7 +3249,7 @@ namespace Mono.CSharp { @@ -3220,7 +3249,7 @@ namespace Mono.CSharp {
class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
{
ExtensionMethodCandidates candidates;
public readonly Expression ExtensionExpression;
public Expression ExtensionExpression;
public ExtensionMethodGroupExpr (ExtensionMethodCandidates candidates, Expression extensionExpr, Location loc)
: base (candidates.Methods.Cast<MemberSpec>().ToList (), extensionExpr.Type, loc)
@ -3264,6 +3293,10 @@ namespace Mono.CSharp { @@ -3264,6 +3293,10 @@ namespace Mono.CSharp {
if (arguments == null)
arguments = new Arguments (1);
ExtensionExpression = ExtensionExpression.Resolve (ec);
if (ExtensionExpression == null)
return null;
arguments.Insert (0, new Argument (ExtensionExpression, Argument.AType.ExtensionType));
var res = base.OverloadResolve (ec, ref arguments, ehandler ?? this, restr);
@ -5616,6 +5649,11 @@ namespace Mono.CSharp { @@ -5616,6 +5649,11 @@ namespace Mono.CSharp {
override public Expression DoResolveLValue (ResolveContext ec, Expression right_side)
{
if (spec is FixedFieldSpec) {
// It could be much better error message but we want to be error compatible
Error_ValueAssignment (ec, right_side);
}
Expression e = DoResolve (ec, right_side);
if (e == null)
@ -5934,6 +5972,21 @@ namespace Mono.CSharp { @@ -5934,6 +5972,21 @@ namespace Mono.CSharp {
#endregion
public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
{
if (best_candidate == null || !(best_candidate.IsStatic || InstanceExpression is This))
return null;
var args_count = arguments == null ? 0 : arguments.Count;
if (args_count != body.Parameters.Count && args_count == 0)
return null;
var mg = MethodGroupExpr.CreatePredefined (best_candidate.Get, DeclaringType, loc);
mg.InstanceExpression = InstanceExpression;
return mg;
}
public static PropertyExpr CreatePredefined (PropertySpec spec, Location loc)
{
return new PropertyExpr (spec, loc) {

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

@ -452,6 +452,9 @@ namespace Mono.CSharp @@ -452,6 +452,9 @@ namespace Mono.CSharp
{
Tokenizer tokenizer = new Tokenizer (seekable, source_file, new ParserSession ());
// Prefer contextual block keywords over identifiers
tokenizer.parsing_block++;
int t = tokenizer.token ();
switch (t){
case Token.EOF:
@ -583,6 +586,7 @@ namespace Mono.CSharp @@ -583,6 +586,7 @@ namespace Mono.CSharp
if (kind == InputKind.StatementOrExpression){
parser.Lexer.putback_char = Tokenizer.EvalStatementParserCharacter;
parser.Lexer.parsing_block++;
ctx.Settings.StatementMode = true;
} else {
parser.Lexer.putback_char = Tokenizer.EvalCompilationUnitParserCharacter;

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

@ -95,10 +95,10 @@ namespace Mono.CSharp @@ -95,10 +95,10 @@ namespace Mono.CSharp
public class ParenthesizedExpression : ShimExpression
{
public ParenthesizedExpression (Expression expr)
public ParenthesizedExpression (Expression expr, Location loc)
: base (expr)
{
loc = expr.Location;
this.loc = loc;
}
protected override Expression DoResolve (ResolveContext ec)
@ -824,6 +824,12 @@ namespace Mono.CSharp @@ -824,6 +824,12 @@ namespace Mono.CSharp
get { return true; }
}
public override Location StartLocation {
get {
return expr.StartLocation;
}
}
protected override void CloneTo (CloneContext clonectx, Expression t)
{
Indirection target = (Indirection) t;
@ -1043,6 +1049,12 @@ namespace Mono.CSharp @@ -1043,6 +1049,12 @@ namespace Mono.CSharp
}
}
public override Location StartLocation {
get {
return (mode & Mode.IsPost) != 0 ? expr.Location : loc;
}
}
public override bool ContainsEmitWithAwait ()
{
return expr.ContainsEmitWithAwait ();
@ -4205,6 +4217,12 @@ namespace Mono.CSharp @@ -4205,6 +4217,12 @@ namespace Mono.CSharp
public override void Emit (EmitContext ec)
{
// Optimize by removing any extra null arguments, they are no-op
for (int i = 0; i < arguments.Count; ++i) {
if (arguments[i].Expr is NullConstant)
arguments.RemoveAt (i--);
}
var members = GetConcatMethodCandidates ();
var res = new OverloadResolver (members, OverloadResolver.Restrictions.NoBaseMembers, loc);
var method = res.ResolveMember<MethodSpec> (new ResolveContext (ec.MemberContext), ref arguments);
@ -5300,8 +5318,7 @@ namespace Mono.CSharp @@ -5300,8 +5318,7 @@ namespace Mono.CSharp
this.expr = expr;
this.arguments = arguments;
if (expr != null) {
var ma = expr as MemberAccess;
loc = ma != null ? ma.GetLeftExpressionLocation () : expr.Location;
loc = expr.Location;
}
}
@ -5323,8 +5340,49 @@ namespace Mono.CSharp @@ -5323,8 +5340,49 @@ namespace Mono.CSharp
return mg;
}
}
public override Location StartLocation {
get {
return expr.StartLocation;
}
}
#endregion
public override MethodGroupExpr CanReduceLambda (AnonymousMethodBody body)
{
if (MethodGroup == null)
return null;
var candidate = MethodGroup.BestCandidate;
if (candidate == null || !(candidate.IsStatic || Exp is This))
return null;
var args_count = arguments == null ? 0 : arguments.Count;
if (args_count != body.Parameters.Count)
return null;
var lambda_parameters = body.Block.Parameters.FixedParameters;
for (int i = 0; i < args_count; ++i) {
var pr = arguments[i].Expr as ParameterReference;
if (pr == null)
return null;
if (lambda_parameters[i] != pr.Parameter)
return null;
if ((lambda_parameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (pr.Parameter.ModFlags & Parameter.Modifier.RefOutMask))
return null;
}
var emg = MethodGroup as ExtensionMethodGroupExpr;
if (emg != null) {
return MethodGroupExpr.CreatePredefined (candidate, candidate.DeclaringType, MethodGroup.Location);
}
return MethodGroup;
}
protected override void CloneTo (CloneContext clonectx, Expression t)
{
Invocation target = (Invocation) t;
@ -7921,6 +7979,12 @@ namespace Mono.CSharp @@ -7921,6 +7979,12 @@ namespace Mono.CSharp
}
}
public override Location StartLocation {
get {
return expr == null ? loc : expr.StartLocation;
}
}
protected override Expression DoResolve (ResolveContext rc)
{
var e = DoResolveName (rc, null);
@ -7978,18 +8042,6 @@ namespace Mono.CSharp @@ -7978,18 +8042,6 @@ namespace Mono.CSharp
expr.Error_OperatorCannotBeApplied (rc, loc, ".", type);
}
public Location GetLeftExpressionLocation ()
{
Expression expr = LeftExpression;
MemberAccess ma = expr as MemberAccess;
while (ma != null && ma.LeftExpression != null) {
expr = ma.LeftExpression;
ma = expr as MemberAccess;
}
return expr == null ? Location : expr.Location;
}
public static bool IsValidDotExpression (TypeSpec type)
{
const MemberKind dot_kinds = MemberKind.Class | MemberKind.Struct | MemberKind.Delegate | MemberKind.Enum |
@ -8503,6 +8555,12 @@ namespace Mono.CSharp @@ -8503,6 +8555,12 @@ namespace Mono.CSharp
this.Arguments = args;
}
public override Location StartLocation {
get {
return Expr.StartLocation;
}
}
public override bool ContainsEmitWithAwait ()
{
return Expr.ContainsEmitWithAwait () || Arguments.ContainsEmitWithAwait ();

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

@ -428,7 +428,7 @@ namespace Mono.CSharp @@ -428,7 +428,7 @@ namespace Mono.CSharp
FieldBuilder = Parent.TypeBuilder.DefineField (Name, fixed_buffer_type, ModifiersExtensions.FieldAttr (ModFlags));
var element_spec = new FieldSpec (null, this, MemberType, ffield, ModFlags);
spec = new FixedFieldSpec (Parent.Definition, this, FieldBuilder, element_spec, ModFlags);
spec = new FixedFieldSpec (Module, Parent.Definition, this, FieldBuilder, element_spec, ModFlags);
Parent.MemberCache.AddMember (spec);
return true;
@ -538,8 +538,8 @@ namespace Mono.CSharp @@ -538,8 +538,8 @@ namespace Mono.CSharp
{
readonly FieldSpec element;
public FixedFieldSpec (TypeSpec declaringType, IMemberDefinition definition, FieldInfo info, FieldSpec element, Modifiers modifiers)
: base (declaringType, definition, element.MemberType, info, modifiers)
public FixedFieldSpec (ModuleContainer module, TypeSpec declaringType, IMemberDefinition definition, FieldInfo info, FieldSpec element, Modifiers modifiers)
: base (declaringType, definition, PointerContainer.MakeType (module, element.MemberType), info, modifiers)
{
this.element = element;
@ -552,10 +552,10 @@ namespace Mono.CSharp @@ -552,10 +552,10 @@ namespace Mono.CSharp
return element;
}
}
public TypeSpec ElementType {
get {
return MemberType;
return element.MemberType;
}
}
}

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

@ -394,7 +394,7 @@ namespace Mono.CSharp @@ -394,7 +394,7 @@ namespace Mono.CSharp
// <summary>
// Creates a sibling of the current usage vector.
// </summary>
public virtual void CreateSibling (Block block, SiblingType type)
public void CreateSibling (Block block, SiblingType type)
{
UsageVector vector = new UsageVector (
type, Parent.CurrentUsageVector, block, Location);

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

@ -220,7 +220,7 @@ namespace Mono.CSharp @@ -220,7 +220,7 @@ namespace Mono.CSharp
// TODO: Sanity check on field_type (only few types are allowed)
var element_field = CreateField (fi.FieldType.GetField (FixedField.FixedElementName), declaringType);
return new FixedFieldSpec (declaringType, definition, fi, element_field, mod);
return new FixedFieldSpec (module, declaringType, definition, fi, element_field, mod);
}
}

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

@ -182,7 +182,7 @@ namespace Mono.CSharp { @@ -182,7 +182,7 @@ namespace Mono.CSharp {
ExpressionStatement statement;
public ContextualReturn (Expression expr)
: base (expr, expr.Location)
: base (expr, expr.StartLocation)
{
}

18
ICSharpCode.NRefactory.CSharp/Parser/mcs/membercache.cs

@ -299,6 +299,7 @@ namespace Mono.CSharp { @@ -299,6 +299,7 @@ namespace Mono.CSharp {
if (member.Kind == MemberKind.Operator) {
var dt = member.DeclaringType;
//
// Some core types have user operators but they cannot be used like normal
// user operators as they are predefined and therefore having different
@ -908,7 +909,7 @@ namespace Mono.CSharp { @@ -908,7 +909,7 @@ namespace Mono.CSharp {
public static IList<MemberSpec> GetUserOperator (TypeSpec container, Operator.OpType op, bool declaredOnly)
{
IList<MemberSpec> found = null;
bool shared_list = true;
IList<MemberSpec> applicable;
do {
var mc = container.MemberCache;
@ -938,10 +939,13 @@ namespace Mono.CSharp { @@ -938,10 +939,13 @@ namespace Mono.CSharp {
found = new List<MemberSpec> ();
found.Add (applicable[i]);
} else {
var prev = found as List<MemberSpec>;
if (prev == null) {
List<MemberSpec> prev;
if (shared_list) {
shared_list = false;
prev = new List<MemberSpec> (found.Count + 1);
prev.AddRange (found);
} else {
prev = (List<MemberSpec>) found;
}
prev.Add (applicable[i]);
@ -950,12 +954,16 @@ namespace Mono.CSharp { @@ -950,12 +954,16 @@ namespace Mono.CSharp {
} else {
if (found == null) {
found = applicable;
shared_list = true;
} else {
var merged = found as List<MemberSpec>;
if (merged == null) {
List<MemberSpec> merged;
if (shared_list) {
shared_list = false;
merged = new List<MemberSpec> (found.Count + applicable.Count);
merged.AddRange (found);
found = merged;
} else {
merged = (List<MemberSpec>) found;
}
merged.AddRange (applicable);

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

@ -661,7 +661,7 @@ namespace Mono.CSharp { @@ -661,7 +661,7 @@ namespace Mono.CSharp {
public StatementExpression (ExpressionStatement expr)
{
this.expr = expr;
loc = expr.Location;
loc = expr.StartLocation;
}
public StatementExpression (ExpressionStatement expr, Location loc)
@ -931,9 +931,19 @@ namespace Mono.CSharp { @@ -931,9 +931,19 @@ namespace Mono.CSharp {
}
var l = am as AnonymousMethodBody;
if (l != null && l.ReturnTypeInference != null && expr != null) {
l.ReturnTypeInference.AddCommonTypeBound (expr.Type);
return true;
if (l != null && expr != null) {
if (l.ReturnTypeInference != null) {
l.ReturnTypeInference.AddCommonTypeBound (expr.Type);
return true;
}
//
// Try to optimize simple lambda. Only when optimizations are enabled not to cause
// unexpected debugging experience
//
if (this is ContextualReturn && !ec.IsInProbingMode && ec.Module.Compiler.Settings.Optimize) {
l.DirectMethodGroupConversion = expr.CanReduceLambda (l);
}
}
}
}
@ -1171,7 +1181,7 @@ namespace Mono.CSharp { @@ -1171,7 +1181,7 @@ namespace Mono.CSharp {
return false;
}
if (!ec.Switch.GotDefault) {
if (ec.Switch.DefaultLabel == null) {
FlowBranchingBlock.Error_UnknownLabel (loc, "default", ec.Report);
return false;
}
@ -1181,7 +1191,7 @@ namespace Mono.CSharp { @@ -1181,7 +1191,7 @@ namespace Mono.CSharp {
protected override void DoEmit (EmitContext ec)
{
ec.Emit (OpCodes.Br, ec.Switch.DefaultLabel);
ec.Emit (OpCodes.Br, ec.Switch.DefaultLabel.GetILLabel (ec));
}
public override object Accept (StructuralVisitor visitor)
@ -2146,14 +2156,6 @@ namespace Mono.CSharp { @@ -2146,14 +2156,6 @@ namespace Mono.CSharp {
#endregion
public Block CreateSwitchBlock (Location start)
{
// FIXME: Only explicit block should be created
var new_block = new Block (this, start, start);
new_block.IsCompilerGenerated = true;
return new_block;
}
public void SetEndLocation (Location loc)
{
EndLocation = loc;
@ -2287,7 +2289,7 @@ namespace Mono.CSharp { @@ -2287,7 +2289,7 @@ namespace Mono.CSharp {
if (s is EmptyStatement)
continue;
if (!ec.UnreachableReported && !(s is LabeledStatement)) {
if (!ec.UnreachableReported && !(s is LabeledStatement) && !(s is SwitchLabel)) {
ec.Report.Warning (162, 2, s.loc, "Unreachable code detected");
ec.UnreachableReported = true;
}
@ -2309,7 +2311,7 @@ namespace Mono.CSharp { @@ -2309,7 +2311,7 @@ namespace Mono.CSharp {
continue;
}
if (unreachable && !(s is LabeledStatement) && !(s is Block))
if (unreachable && !(s is LabeledStatement) && !(s is SwitchLabel) && !(s is Block))
statements [ix] = new EmptyStatement (s.loc);
unreachable = ec.CurrentBranching.CurrentUsageVector.IsUnreachable;
@ -3258,18 +3260,19 @@ namespace Mono.CSharp { @@ -3258,18 +3260,19 @@ namespace Mono.CSharp {
//
// A collision checking between local names
//
var variable_block = li.Block.Explicit;
for (int i = 0; i < existing_list.Count; ++i) {
existing = existing_list[i];
Block b = existing.Block.Explicit;
// Collision at same level
if (li.Block.Explicit == b) {
if (variable_block == b) {
li.Block.Error_AlreadyDeclared (name, li);
break;
}
// Collision with parent
Block parent = li.Block.Explicit;
Block parent = variable_block;
while ((parent = parent.Parent) != null) {
if (parent == b) {
li.Block.Error_AlreadyDeclared (name, li, "parent or current");
@ -3278,10 +3281,10 @@ namespace Mono.CSharp { @@ -3278,10 +3281,10 @@ namespace Mono.CSharp {
}
}
if (!ignoreChildrenBlocks) {
if (!ignoreChildrenBlocks && variable_block.Parent != b.Parent) {
// Collision with children
while ((b = b.Parent) != null) {
if (li.Block.Explicit == b) {
if (variable_block == b) {
li.Block.Error_AlreadyDeclared (name, li, "child");
i = existing_list.Count;
break;
@ -3458,20 +3461,12 @@ namespace Mono.CSharp { @@ -3458,20 +3461,12 @@ namespace Mono.CSharp {
if (label != null) {
if (label.Block == b.Original)
return label;
// TODO: Temporary workaround for the switch block implicit label block
if (label.Block.IsCompilerGenerated && (label.Block.Parent == b.Original || label.Block == b.Original.Parent))
return label;
} else {
List<LabeledStatement> list = (List<LabeledStatement>) value;
for (int i = 0; i < list.Count; ++i) {
label = list[i];
if (label.Block == b.Original)
return label;
// TODO: Temporary workaround for the switch block implicit label block
if (label.Block.IsCompilerGenerated && (label.Block.Parent == b.Original || label.Block == b.Original.Parent))
return label;
}
}
@ -3505,9 +3500,7 @@ namespace Mono.CSharp { @@ -3505,9 +3500,7 @@ namespace Mono.CSharp {
if (Report.Errors > 0)
return;
#if PRODUCTION
try {
#endif
if (IsCompilerGenerated) {
using (ec.With (BuilderContext.Options.OmitDebugInfo, true)) {
base.Emit (ec);
@ -3541,22 +3534,16 @@ namespace Mono.CSharp { @@ -3541,22 +3534,16 @@ namespace Mono.CSharp {
ec.Emit (OpCodes.Ret);
}
#if PRODUCTION
} catch (Exception e){
Console.WriteLine ("Exception caught by the compiler while emitting:");
Console.WriteLine (" Block that caused the problem begin at: " + block.loc);
Console.WriteLine (e.GetType ().FullName + ": " + e.Message);
throw;
} catch (Exception e) {
throw new InternalErrorException (e, StartLocation);
}
#endif
}
}
public class SwitchLabel {
public class SwitchLabel : Statement
{
Expression label;
Constant converted;
readonly Location loc;
Label? il_label;
@ -3596,6 +3583,8 @@ namespace Mono.CSharp { @@ -3596,6 +3583,8 @@ namespace Mono.CSharp {
}
}
public bool SectionStart { get; set; }
public Label GetILLabel (EmitContext ec)
{
if (il_label == null){
@ -3605,6 +3594,18 @@ namespace Mono.CSharp { @@ -3605,6 +3594,18 @@ namespace Mono.CSharp {
return il_label.Value;
}
protected override void DoEmit (EmitContext ec)
{
ec.MarkLabel (GetILLabel (ec));
}
public override bool Resolve (BlockContext bc)
{
bc.CurrentBranching.CurrentUsageVector.ResetBarrier ();
return base.Resolve (bc);
}
//
// Resolves the expression, reduces it to a literal if possible
// and then converts it to the requested type.
@ -3643,36 +3644,19 @@ namespace Mono.CSharp { @@ -3643,36 +3644,19 @@ namespace Mono.CSharp {
ec.Report.Error (152, loc, "The label `case {0}:' already occurs in this switch statement", label);
}
public SwitchLabel Clone (CloneContext clonectx)
{
if (label == null)
return this;
return new SwitchLabel (label.Clone (clonectx), loc);
}
}
public class SwitchSection {
public readonly List<SwitchLabel> Labels;
public readonly Block Block;
public SwitchSection (List<SwitchLabel> labels, Block block)
protected override void CloneTo (CloneContext clonectx, Statement target)
{
Labels = labels;
Block = block;
var t = (SwitchLabel) target;
if (label != null)
t.label = label.Clone (clonectx);
}
public SwitchSection Clone (CloneContext clonectx)
public override object Accept (StructuralVisitor visitor)
{
var cloned_labels = new List<SwitchLabel> ();
foreach (SwitchLabel sl in Labels)
cloned_labels.Add (sl.Clone (clonectx));
return new SwitchSection (cloned_labels, clonectx.LookupBlock (Block));
return visitor.Visit (this);
}
}
public class Switch : Statement
{
// structure used to hold blocks of keys while calculating table switch
@ -3725,33 +3709,26 @@ namespace Mono.CSharp { @@ -3725,33 +3709,26 @@ namespace Mono.CSharp {
}
}
sealed class LabelMarker : Statement
sealed class DispatchStatement : Statement
{
readonly Switch s;
readonly List<SwitchLabel> labels;
readonly Switch body;
public LabelMarker (Switch s, List<SwitchLabel> labels)
public DispatchStatement (Switch body)
{
this.s = s;
this.labels = labels;
this.body = body;
}
protected override void CloneTo (CloneContext clonectx, Statement target)
{
throw new NotImplementedException ();
}
protected override void DoEmit (EmitContext ec)
{
foreach (var l in labels) {
if (l.IsDefault)
ec.MarkLabel (s.DefaultLabel);
else
ec.MarkLabel (l.GetILLabel (ec));
}
body.EmitDispatch (ec);
}
}
public List<SwitchSection> Sections;
public Expression Expr;
//
@ -3759,25 +3736,19 @@ namespace Mono.CSharp { @@ -3759,25 +3736,19 @@ namespace Mono.CSharp {
//
Dictionary<long, SwitchLabel> labels;
Dictionary<string, SwitchLabel> string_labels;
List<SwitchLabel> case_labels;
/// <summary>
/// The governing switch type
/// </summary>
public TypeSpec SwitchType;
//
// Computed
//
Label default_target;
Label null_target;
Expression new_expr;
bool is_constant;
SwitchSection constant_section;
SwitchSection default_section;
SwitchLabel null_section;
SwitchLabel case_null;
SwitchLabel case_default;
Statement simple_stmt;
Label defaultLabel, nullLabel;
VariableReference value;
ExpressionStatement string_dictionary;
FieldExpr switch_cache_field;
@ -3788,11 +3759,10 @@ namespace Mono.CSharp { @@ -3788,11 +3759,10 @@ namespace Mono.CSharp {
//
Nullable.Unwrap unwrap;
public Switch (Expression e, ExplicitBlock block, List<SwitchSection> sects, Location l)
public Switch (Expression e, ExplicitBlock block, Location l)
{
Expr = e;
this.block = block;
Sections = sects;
loc = l;
}
@ -3802,15 +3772,9 @@ namespace Mono.CSharp { @@ -3802,15 +3772,9 @@ namespace Mono.CSharp {
}
}
public Label DefaultLabel {
public SwitchLabel DefaultLabel {
get {
return default_target;
}
}
public bool GotDefault {
get {
return default_section != null;
return case_default;
}
}
@ -3900,54 +3864,80 @@ namespace Mono.CSharp { @@ -3900,54 +3864,80 @@ namespace Mono.CSharp {
// It also returns a hashtable with the keys that we will later
// use to compute the switch tables
//
bool CheckSwitch (ResolveContext ec)
bool ResolveLabels (ResolveContext ec, Constant value)
{
bool error = false;
if (SwitchType.BuiltinType == BuiltinTypeSpec.Type.String)
string_labels = new Dictionary<string, SwitchLabel> (Sections.Count + 1);
else
labels = new Dictionary<long, SwitchLabel> (Sections.Count + 1);
foreach (SwitchSection ss in Sections){
foreach (SwitchLabel sl in ss.Labels){
if (sl.IsDefault){
if (default_section != null){
sl.Error_AlreadyOccurs (ec, SwitchType, default_section.Labels [0]);
error = true;
}
default_section = ss;
continue;
}
if (SwitchType.BuiltinType == BuiltinTypeSpec.Type.String) {
string_labels = new Dictionary<string, SwitchLabel> ();
} else {
labels = new Dictionary<long, SwitchLabel> ();
}
case_labels = new List<SwitchLabel> ();
int default_label_index = -1;
bool constant_label_found = false;
for (int i = 0; i < block.Statements.Count; ++i) {
var s = block.Statements[i];
if (!sl.ResolveAndReduce (ec, SwitchType, IsNullable)) {
var sl = s as SwitchLabel;
if (sl == null) {
continue;
}
case_labels.Add (sl);
if (sl.IsDefault) {
if (case_default != null) {
sl.Error_AlreadyOccurs (ec, SwitchType, case_default);
error = true;
continue;
}
try {
if (string_labels != null) {
string s = sl.Converted.GetValue () as string;
if (s == null)
null_section = sl;
else
string_labels.Add (s, sl);
default_label_index = i;
case_default = sl;
continue;
}
if (!sl.ResolveAndReduce (ec, SwitchType, IsNullable)) {
error = true;
continue;
}
try {
if (string_labels != null) {
string string_value = sl.Converted.GetValue () as string;
if (string_value == null)
case_null = sl;
else
string_labels.Add (string_value, sl);
} else {
if (sl.Converted is NullLiteral) {
case_null = sl;
} else {
if (sl.Converted is NullLiteral) {
null_section = sl;
} else {
labels.Add (sl.Converted.GetValueAsLong (), sl);
}
labels.Add (sl.Converted.GetValueAsLong (), sl);
}
} catch (ArgumentException) {
if (string_labels != null)
sl.Error_AlreadyOccurs (ec, SwitchType, string_labels[(string) sl.Converted.GetValue ()]);
else
sl.Error_AlreadyOccurs (ec, SwitchType, labels[sl.Converted.GetValueAsLong ()]);
error = true;
}
} catch (ArgumentException) {
if (string_labels != null)
sl.Error_AlreadyOccurs (ec, SwitchType, string_labels[(string) sl.Converted.GetValue ()]);
else
sl.Error_AlreadyOccurs (ec, SwitchType, labels[sl.Converted.GetValueAsLong ()]);
error = true;
}
if (value != null) {
var constant_label = constant_label_found ? null : FindLabel (value);
if (constant_label == null || constant_label != sl)
block.Statements[i] = new EmptyStatement (s.loc);
else
constant_label_found = true;
}
}
if (value != null && constant_label_found && default_label_index >= 0)
block.Statements[default_label_index] = new EmptyStatement (case_default.loc);
return !error;
}
@ -3960,8 +3950,6 @@ namespace Mono.CSharp { @@ -3960,8 +3950,6 @@ namespace Mono.CSharp {
//
void EmitTableSwitch (EmitContext ec, Expression val)
{
Label lbl_default = default_target;
if (labels != null && labels.Count > 0) {
List<LabelsRange> ranges;
if (string_labels != null) {
@ -3994,17 +3982,21 @@ namespace Mono.CSharp { @@ -3994,17 +3982,21 @@ namespace Mono.CSharp {
ranges.Sort ();
}
Label lbl_default = defaultLabel;
TypeSpec compare_type = SwitchType.IsEnum ? EnumSpec.GetUnderlyingType (SwitchType) : SwitchType;
for (int range_index = ranges.Count - 1; range_index >= 0; --range_index) {
LabelsRange kb = ranges[range_index];
lbl_default = (range_index == 0) ? default_target : ec.DefineLabel ();
lbl_default = (range_index == 0) ? defaultLabel : ec.DefineLabel ();
// Optimize small ranges using simple equality check
if (kb.Range <= 2) {
foreach (var key in kb.label_values) {
SwitchLabel sl = labels[key];
if (sl.Converted.IsDefaultValue) {
if (sl == case_default || sl == case_null)
continue;
if (sl.Converted.IsZeroInteger) {
val.EmitBranchable (ec, sl.GetILLabel (ec), false);
} else {
val.Emit (ec);
@ -4075,35 +4067,8 @@ namespace Mono.CSharp { @@ -4075,35 +4067,8 @@ namespace Mono.CSharp {
if (ranges.Count > 0)
ec.Emit (OpCodes.Br, lbl_default);
}
// now emit the code for the sections
bool found_default = false;
foreach (SwitchSection ss in Sections) {
foreach (SwitchLabel sl in ss.Labels) {
if (sl.IsDefault) {
ec.MarkLabel (lbl_default);
found_default = true;
if (null_section == null)
ec.MarkLabel (null_target);
} else if (sl.Converted.IsNull) {
ec.MarkLabel (null_target);
}
ec.MarkLabel (sl.GetILLabel (ec));
}
ss.Block.Emit (ec);
}
if (!found_default) {
ec.MarkLabel (lbl_default);
if (null_section == null) {
ec.MarkLabel (null_target);
}
}
}
SwitchLabel FindLabel (Constant value)
{
SwitchLabel sl = null;
@ -4111,16 +4076,16 @@ namespace Mono.CSharp { @@ -4111,16 +4076,16 @@ namespace Mono.CSharp {
if (string_labels != null) {
string s = value.GetValue () as string;
if (s == null) {
if (null_section != null)
sl = null_section;
else if (default_section != null)
sl = default_section.Labels[0];
if (case_null != null)
sl = case_null;
else if (case_default != null)
sl = case_default;
} else {
string_labels.TryGetValue (s, out sl);
}
} else {
if (value is NullLiteral) {
sl = null_section;
sl = case_null;
} else {
labels.TryGetValue (value.GetValueAsLong (), out sl);
}
@ -4129,18 +4094,6 @@ namespace Mono.CSharp { @@ -4129,18 +4094,6 @@ namespace Mono.CSharp {
return sl;
}
SwitchSection FindSection (SwitchLabel label)
{
foreach (SwitchSection ss in Sections){
foreach (SwitchLabel sl in ss.Labels){
if (label == sl)
return ss;
}
}
return null;
}
public override bool Resolve (BlockContext ec)
{
Expr = Expr.Resolve (ec);
@ -4172,64 +4125,45 @@ namespace Mono.CSharp { @@ -4172,64 +4125,45 @@ namespace Mono.CSharp {
return false;
}
if (!CheckSwitch (ec))
return false;
if (block.Statements.Count == 0)
return true;
Switch old_switch = ec.Switch;
ec.Switch = this;
ec.Switch.SwitchType = SwitchType;
var constant = new_expr as Constant;
ec.StartFlowBranching (FlowBranching.BranchingType.Switch, loc);
if (!ResolveLabels (ec, constant))
return false;
var constant = new_expr as Constant;
if (constant != null) {
is_constant = true;
SwitchLabel label = FindLabel (constant);
if (label != null)
constant_section = FindSection (label);
if (constant_section == null)
constant_section = default_section;
} else {
//
// Don't need extra variable for constant switch or switch with
// only default case
//
if (constant == null && (case_labels.Count - (case_default != null ? 1 : 0)) != 0) {
//
// Store switch expression for comparison purposes
//
value = new_expr as VariableReference;
if (value == null) {
// Create temporary variable inside switch scope
var block = ec.CurrentBlock;
var current_block = ec.CurrentBlock;
ec.CurrentBlock = Block;
value = TemporaryVariableReference.Create (SwitchType, ec.CurrentBlock, loc);
value.Resolve (ec);
ec.CurrentBlock = block;
ec.CurrentBlock = current_block;
}
}
bool first = true;
bool ok = true;
foreach (SwitchSection ss in Sections){
if (!first)
ec.CurrentBranching.CreateSibling (
null, FlowBranching.SiblingType.SwitchSection);
else
first = false;
Switch old_switch = ec.Switch;
ec.Switch = this;
ec.Switch.SwitchType = SwitchType;
if (is_constant && (ss != constant_section)) {
// If we're a constant switch, we're only emitting
// one single section - mark all the others as
// unreachable.
ec.CurrentBranching.CurrentUsageVector.Goto ();
if (!ss.Block.ResolveUnreachable (ec, true)) {
ok = false;
}
} else {
if (!ss.Block.Resolve (ec))
ok = false;
}
}
ec.StartFlowBranching (FlowBranching.BranchingType.Switch, loc);
ec.CurrentBranching.CurrentUsageVector.Goto ();
var ok = block.Resolve (ec);
if (default_section == null)
ec.CurrentBranching.CreateSibling (null, FlowBranching.SiblingType.SwitchSection);
if (case_default == null)
ec.CurrentBranching.CurrentUsageVector.ResetBarrier ();
ec.EndFlowBranching ();
ec.Switch = old_switch;
@ -4237,17 +4171,16 @@ namespace Mono.CSharp { @@ -4237,17 +4171,16 @@ namespace Mono.CSharp {
if (!ok)
return false;
if (!is_constant) {
if (SwitchType.BuiltinType == BuiltinTypeSpec.Type.String) {
if (string_labels.Count < 7)
ResolveSimpleSwitch (ec);
else
ResolveStringSwitchMap (ec);
} else if (labels.Count < 3 && !IsNullable) {
ResolveSimpleSwitch (ec);
}
if (constant == null && SwitchType.BuiltinType == BuiltinTypeSpec.Type.String && string_labels.Count > 6) {
ResolveStringSwitchMap (ec);
}
//
// Needed to emit anonymous storey initialization before
// any generated switch dispatch
//
block.AddScopeStatement (new DispatchStatement (this));
return true;
}
@ -4262,45 +4195,6 @@ namespace Mono.CSharp { @@ -4262,45 +4195,6 @@ namespace Mono.CSharp {
return sl;
}
//
// Prepares switch using simple if/else comparison for small label count (4 + optional default)
//
void ResolveSimpleSwitch (BlockContext bc)
{
simple_stmt = default_section != null ? default_section.Block : null;
for (int i = Sections.Count - 1; i >= 0; --i) {
var s = Sections[i];
if (s == default_section) {
s.Block.AddScopeStatement (new LabelMarker (this, s.Labels));
continue;
}
s.Block.AddScopeStatement (new LabelMarker (this, s.Labels));
Expression cond = null;
for (int ci = 0; ci < s.Labels.Count; ++ci) {
var e = new Binary (Binary.Operator.Equality, value, s.Labels[ci].Converted);
if (ci > 0) {
cond = new Binary (Binary.Operator.LogicalOr, cond, e);
} else {
cond = e;
}
}
//
// Compiler generated, hide from symbol file
//
simple_stmt = new If (cond, s.Block, simple_stmt, Location.Null);
}
// It's null for empty switch
if (simple_stmt != null)
simple_stmt.Resolve (bc);
}
//
// Converts string switch into string hashtable
//
@ -4328,37 +4222,28 @@ namespace Mono.CSharp { @@ -4328,37 +4222,28 @@ namespace Mono.CSharp {
ctype.AddField (field);
var init = new List<Expression> ();
int counter = 0;
int counter = -1;
labels = new Dictionary<long, SwitchLabel> (string_labels.Count);
string value = null;
foreach (SwitchSection section in Sections) {
bool contains_label = false;
foreach (SwitchLabel sl in section.Labels) {
if (sl.IsDefault || sl.Converted.IsNull)
continue;
if (!contains_label) {
labels.Add (counter, sl);
contains_label = true;
}
foreach (SwitchLabel sl in case_labels) {
if (sl.SectionStart)
labels.Add (++counter, sl);
value = (string) sl.Converted.GetValue ();
var init_args = new List<Expression> (2);
init_args.Add (new StringLiteral (ec.BuiltinTypes, value, sl.Location));
if (sl == case_default || sl == case_null)
continue;
sl.Converted = new IntConstant (ec.BuiltinTypes, counter, loc);
init_args.Add (sl.Converted);
value = (string) sl.Converted.GetValue ();
var init_args = new List<Expression> (2);
init_args.Add (new StringLiteral (ec.BuiltinTypes, value, sl.Location));
init.Add (new CollectionElementInitializer (init_args, loc));
}
sl.Converted = new IntConstant (ec.BuiltinTypes, counter, loc);
init_args.Add (sl.Converted);
//
// Don't add empty sections
//
if (contains_label)
++counter;
init.Add (new CollectionElementInitializer (init_args, loc));
}
Arguments args = new Arguments (1);
args.Add (new Argument (new IntConstant (ec.BuiltinTypes, init.Count, loc)));
Expression initializer = new NewInitialize (string_dictionary_type, args,
@ -4375,7 +4260,7 @@ namespace Mono.CSharp { @@ -4375,7 +4260,7 @@ namespace Mono.CSharp {
//
// Skip initialization when value is null
//
value.EmitBranchable (ec, null_target, false);
value.EmitBranchable (ec, nullLabel, false);
//
// Check if string dictionary is initialized and initialize
@ -4401,7 +4286,7 @@ namespace Mono.CSharp { @@ -4401,7 +4286,7 @@ namespace Mono.CSharp {
//
// A value was not found, go to default case
//
get_item.EmitBranchable (ec, default_target, false);
get_item.EmitBranchable (ec, defaultLabel, false);
} else {
Arguments get_value_args = new Arguments (1);
get_value_args.Add (new Argument (value));
@ -4412,7 +4297,7 @@ namespace Mono.CSharp { @@ -4412,7 +4297,7 @@ namespace Mono.CSharp {
LocalTemporary get_item_object = new LocalTemporary (ec.BuiltinTypes.Object);
get_item_object.EmitAssign (ec, get_item, true, false);
ec.Emit (OpCodes.Brfalse, default_target);
ec.Emit (OpCodes.Brfalse, defaultLabel);
ExpressionStatement get_item_int = (ExpressionStatement) new SimpleAssign (string_switch_variable,
new Cast (new TypeExpression (ec.BuiltinTypes.Int, loc), get_item_object, loc)).Resolve (rc);
@ -4425,49 +4310,104 @@ namespace Mono.CSharp { @@ -4425,49 +4310,104 @@ namespace Mono.CSharp {
string_switch_variable.Release (ec);
}
protected override void DoEmit (EmitContext ec)
//
// Emits switch using simple if/else comparison for small label count (4 + optional default)
//
void EmitShortSwitch (EmitContext ec)
{
// Workaround broken flow-analysis
block.HasUnreachableClosingBrace = true;
MethodSpec equal_method = null;
if (SwitchType.BuiltinType == BuiltinTypeSpec.Type.String) {
equal_method = ec.Module.PredefinedMembers.StringEqual.Resolve (loc);
}
if (equal_method != null) {
value.EmitBranchable (ec, nullLabel, false);
}
for (int i = 0; i < case_labels.Count; ++i) {
var label = case_labels [i];
if (label == case_default || label == case_null)
continue;
var constant = label.Converted;
if (equal_method != null) {
value.Emit (ec);
constant.Emit (ec);
var call = new CallEmitter ();
call.EmitPredefined (ec, equal_method, new Arguments (0));
ec.Emit (OpCodes.Brtrue, label.GetILLabel (ec));
continue;
}
if (constant.IsZeroInteger && constant.Type.BuiltinType != BuiltinTypeSpec.Type.Long && constant.Type.BuiltinType != BuiltinTypeSpec.Type.ULong) {
value.EmitBranchable (ec, label.GetILLabel (ec), false);
continue;
}
value.Emit (ec);
constant.Emit (ec);
ec.Emit (OpCodes.Beq, label.GetILLabel (ec));
}
ec.Emit (OpCodes.Br, defaultLabel);
}
void EmitDispatch (EmitContext ec)
{
if (value == null) {
//
// Constant switch, we already done the work
//
return;
}
//
// Needed to emit anonymous storey initialization
// Otherwise it does not contain any statements for now
// Mark sequence point explicitly to switch
//
block.Emit (ec);
ec.Mark (block.StartLocation);
block.IsCompilerGenerated = true;
default_target = ec.DefineLabel ();
null_target = ec.DefineLabel ();
if (IsNullable) {
unwrap.EmitCheck (ec);
ec.Emit (OpCodes.Brfalse, null_target);
value.EmitAssign (ec, new_expr, false, false);
} else if (new_expr != value && !is_constant) {
value.EmitAssign (ec, new_expr, false, false);
if (string_dictionary != null) {
DoEmitStringSwitch (ec);
} else if (case_labels.Count < 4 || string_labels != null) {
EmitShortSwitch (ec);
} else {
EmitTableSwitch (ec, value);
}
}
protected override void DoEmit (EmitContext ec)
{
// Workaround broken flow-analysis
block.HasUnreachableClosingBrace = true;
//
// Setup the codegen context
//
Label old_end = ec.LoopEnd;
Switch old_switch = ec.Switch;
ec.LoopEnd = ec.DefineLabel ();
ec.Switch = this;
// Emit Code.
if (is_constant) {
if (constant_section != null)
constant_section.Block.Emit (ec);
} else if (string_dictionary != null) {
DoEmitStringSwitch (ec);
} else if (simple_stmt != null) {
simple_stmt.Emit (ec);
} else {
EmitTableSwitch (ec, value);
defaultLabel = case_default == null ? ec.LoopEnd : case_default.GetILLabel (ec);
nullLabel = case_null == null ? defaultLabel : case_null.GetILLabel (ec);
if (value != null) {
ec.Mark (loc);
if (IsNullable) {
unwrap.EmitCheck (ec);
ec.Emit (OpCodes.Brfalse, nullLabel);
value.EmitAssign (ec, new_expr, false, false);
} else if (new_expr != value) {
value.EmitAssign (ec, new_expr, false, false);
}
}
block.Emit (ec);
// Restore context state.
ec.MarkLabel (ec.LoopEnd);
@ -4483,10 +4423,7 @@ namespace Mono.CSharp { @@ -4483,10 +4423,7 @@ namespace Mono.CSharp {
Switch target = (Switch) t;
target.Expr = Expr.Clone (clonectx);
target.Sections = new List<SwitchSection> ();
foreach (SwitchSection ss in Sections){
target.Sections.Add (ss.Clone (clonectx));
}
target.block = (ExplicitBlock) block.Clone (clonectx);
}
public override object Accept (StructuralVisitor visitor)

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

@ -206,6 +206,11 @@ namespace Mono.CSharp @@ -206,6 +206,11 @@ namespace Mono.CSharp
return null;
}
public virtual object Visit (SwitchLabel switchLabel)
{
return null;
}
public virtual object Visit (GotoDefault gotoDefault)
{
return null;

Loading…
Cancel
Save