summaryrefslogtreecommitdiff
path: root/mcs/mcs/anonymous.cs
diff options
context:
space:
mode:
Diffstat (limited to 'mcs/mcs/anonymous.cs')
-rw-r--r--mcs/mcs/anonymous.cs122
1 files changed, 97 insertions, 25 deletions
diff --git a/mcs/mcs/anonymous.cs b/mcs/mcs/anonymous.cs
index f8a8d55f81..e5cb73dd94 100644
--- a/mcs/mcs/anonymous.cs
+++ b/mcs/mcs/anonymous.cs
@@ -191,15 +191,32 @@ namespace Mono.CSharp {
sealed class ThisInitializer : Statement
{
readonly HoistedThis hoisted_this;
+ readonly AnonymousMethodStorey parent;
- public ThisInitializer (HoistedThis hoisted_this)
+ public ThisInitializer (HoistedThis hoisted_this, AnonymousMethodStorey parent)
{
this.hoisted_this = hoisted_this;
+ this.parent = parent;
}
protected override void DoEmit (EmitContext ec)
{
- hoisted_this.EmitAssign (ec, new CompilerGeneratedThis (ec.CurrentType, loc), false, false);
+ Expression source;
+
+ if (parent == null)
+ source = new CompilerGeneratedThis (ec.CurrentType, loc);
+ else {
+ source = new FieldExpr (parent.HoistedThis.Field, Location.Null) {
+ InstanceExpression = new CompilerGeneratedThis (ec.CurrentType, Location.Null)
+ };
+ }
+
+ hoisted_this.EmitAssign (ec, source, false, false);
+ }
+
+ protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
+ {
+ return false;
}
protected override void CloneTo (CloneContext clonectx, Statement target)
@@ -229,22 +246,24 @@ namespace Mono.CSharp {
public Expression Instance;
bool initialize_hoisted_this;
+ AnonymousMethodStorey hoisted_this_parent;
public AnonymousMethodStorey (ExplicitBlock block, TypeDefinition parent, MemberBase host, TypeParameters tparams, string name, MemberKind kind)
- : base (parent, MakeMemberName (host, name, parent.Module.CounterAnonymousContainers, tparams, block.StartLocation),
+ : base (parent, MakeMemberName (host, name, parent.PartialContainer.CounterAnonymousContainers, tparams, block.StartLocation),
tparams, 0, kind)
{
OriginalSourceBlock = block;
- ID = parent.Module.CounterAnonymousContainers++;
+ ID = parent.PartialContainer.CounterAnonymousContainers++;
}
- public void AddCapturedThisField (EmitContext ec)
+ public void AddCapturedThisField (EmitContext ec, AnonymousMethodStorey parent)
{
TypeExpr type_expr = new TypeExpression (ec.CurrentType, Location);
Field f = AddCompilerGeneratedField ("$this", type_expr);
hoisted_this = new HoistedThis (this, f);
initialize_hoisted_this = true;
+ hoisted_this_parent = parent;
}
public Field AddCapturedVariable (string name, TypeSpec type)
@@ -553,7 +572,7 @@ namespace Mono.CSharp {
// referenced indirectly
//
if (initialize_hoisted_this) {
- rc.CurrentBlock.AddScopeStatement (new ThisInitializer (hoisted_this));
+ rc.CurrentBlock.AddScopeStatement (new ThisInitializer (hoisted_this, hoisted_this_parent));
}
//
@@ -1325,13 +1344,6 @@ namespace Mono.CSharp {
if (!DoResolveParameters (ec))
return null;
-#if !STATIC
- // FIXME: The emitted code isn't very careful about reachability
- // so, ensure we have a 'ret' at the end
- BlockContext bc = ec as BlockContext;
- if (bc != null && bc.CurrentBranching != null && bc.CurrentBranching.CurrentUsageVector.IsUnreachable)
- bc.NeedReturnLabel ();
-#endif
return this;
}
@@ -1507,12 +1519,28 @@ namespace Mono.CSharp {
}
var bc = ec as BlockContext;
- if (bc != null)
- aec.FlowOffset = bc.FlowOffset;
+
+ if (bc != null) {
+ aec.AssignmentInfoOffset = bc.AssignmentInfoOffset;
+ aec.EnclosingLoop = bc.EnclosingLoop;
+ aec.EnclosingLoopOrSwitch = bc.EnclosingLoopOrSwitch;
+ aec.Switch = bc.Switch;
+ }
var errors = ec.Report.Errors;
- bool res = Block.Resolve (ec.CurrentBranching, aec, null);
+ bool res = Block.Resolve (aec);
+
+ if (res && errors == ec.Report.Errors) {
+ MarkReachable (new Reachability ());
+
+ if (!CheckReachableExit (ec.Report)) {
+ return null;
+ }
+
+ if (bc != null)
+ bc.AssignmentInfoOffset = aec.AssignmentInfoOffset;
+ }
if (am != null && am.ReturnTypeInference != null) {
am.ReturnTypeInference.FixAllTypes (ec);
@@ -1521,10 +1549,14 @@ namespace Mono.CSharp {
//
// If e is synchronous the inferred return type is T
- // If e is asynchronous the inferred return type is Task<T>
+ // If e is asynchronous and the body of F is either an expression classified as nothing
+ // or a statement block where no return statements have expressions, the inferred return type is Task
+ // If e is async and has an inferred result type T, the inferred return type is Task<T>
//
if (block.IsAsync && ReturnType != null) {
- ReturnType = ec.Module.PredefinedTypes.TaskGeneric.TypeSpec.MakeGenericType (ec, new [] { ReturnType });
+ ReturnType = ReturnType.Kind == MemberKind.Void ?
+ ec.Module.PredefinedTypes.Task.TypeSpec :
+ ec.Module.PredefinedTypes.TaskGeneric.TypeSpec.MakeGenericType (ec, new [] { ReturnType });
}
}
@@ -1539,6 +1571,47 @@ namespace Mono.CSharp {
return false;
}
+ bool CheckReachableExit (Report report)
+ {
+ if (block.HasReachableClosingBrace && ReturnType.Kind != MemberKind.Void) {
+ // FIXME: Flow-analysis on MoveNext generated code
+ if (!IsIterator) {
+ report.Error (1643, StartLocation,
+ "Not all code paths return a value in anonymous method of type `{0}'", GetSignatureForError ());
+
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public override void FlowAnalysis (FlowAnalysisContext fc)
+ {
+ // We are reachable, mark block body reachable too
+ MarkReachable (new Reachability ());
+
+ CheckReachableExit (fc.Report);
+
+ var das = fc.BranchDefiniteAssignment ();
+ var prev_pb = fc.ParametersBlock;
+ fc.ParametersBlock = Block;
+ var da_ontrue = fc.DefiniteAssignmentOnTrue;
+ var da_onfalse = fc.DefiniteAssignmentOnFalse;
+
+ block.FlowAnalysis (fc);
+
+ fc.ParametersBlock = prev_pb;
+ fc.DefiniteAssignment = das;
+ fc.DefiniteAssignmentOnTrue = da_ontrue;
+ fc.DefiniteAssignmentOnFalse = da_onfalse;
+ }
+
+ public override void MarkReachable (Reachability rc)
+ {
+ block.MarkReachable (rc);
+ }
+
public void SetHasThisAccess ()
{
ExplicitBlock b = block;
@@ -1679,14 +1752,13 @@ namespace Mono.CSharp {
// use ldftn on non-boxed instances either to share mutated state
//
parent = sm_parent.Parent.PartialContainer;
+ } else if (sm is IteratorStorey) {
+ //
+ // For iterators we can host everything in one class
+ //
+ parent = storey = sm;
}
}
-
- //
- // For iterators we can host everything in one class
- //
- if (sm is IteratorStorey)
- parent = storey = sm;
}
modifiers = storey != null ? Modifiers.INTERNAL : Modifiers.PRIVATE;
@@ -1701,7 +1773,7 @@ namespace Mono.CSharp {
parent = ec.CurrentTypeDefinition.Parent.PartialContainer;
string name = CompilerGeneratedContainer.MakeName (parent != storey ? block_name : null,
- "m", null, ec.Module.CounterAnonymousMethods++);
+ "m", null, parent.PartialContainer.CounterAnonymousMethods++);
MemberName member_name;
if (storey == null && ec.CurrentTypeParameters != null) {