hoisted_this.EmitAssign (ec, source, false, false);
}
+ protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
+ {
+ return false;
+ }
+
protected override void CloneTo (CloneContext clonectx, Statement target)
{
// Nothing to clone
throw new InternalErrorException (e, loc);
}
- if (!ec.IsInProbingMode) {
+ if (!ec.IsInProbingMode && !etree_conversion) {
compatibles.Add (type, am ?? EmptyExpression.Null);
}
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;
}
}
var bc = ec as BlockContext;
- if (bc != null)
+
+ 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);
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;
+
+ fc.DefiniteAssignmentOnTrue = fc.DefiniteAssignmentOnFalse = null;
+ 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;
Modifiers modifiers;
TypeDefinition parent = null;
+ TypeParameters hoisted_tparams = null;
var src_block = Block.Original.Explicit;
if (src_block.HasCapturedVariable || src_block.HasCapturedThis) {
// use ldftn on non-boxed instances either to share mutated state
//
parent = sm_parent.Parent.PartialContainer;
+ hoisted_tparams = sm_parent.OriginalTypeParameters;
} else if (sm is IteratorStorey) {
//
// For iterators we can host everything in one class
modifiers = Modifiers.STATIC | Modifiers.PRIVATE;
}
+ if (storey == null && hoisted_tparams == null)
+ hoisted_tparams = ec.CurrentTypeParameters;
+
if (parent == null)
parent = ec.CurrentTypeDefinition.Parent.PartialContainer;
"m", null, parent.PartialContainer.CounterAnonymousMethods++);
MemberName member_name;
- if (storey == null && ec.CurrentTypeParameters != null) {
-
- var hoisted_tparams = ec.CurrentTypeParameters;
+ if (hoisted_tparams != null) {
var type_params = new TypeParameters (hoisted_tparams.Count);
for (int i = 0; i < hoisted_tparams.Count; ++i) {
type_params.Add (hoisted_tparams[i].CreateHoistedCopy (null));
ec.Emit (OpCodes.Ldftn, TypeBuilder.GetMethod (t.GetMetaInfo (), (MethodInfo) delegate_method.GetMetaInfo ()));
} else {
- if (delegate_method.IsGeneric)
- delegate_method = delegate_method.MakeGenericMethod (ec.MemberContext, method.TypeParameters);
+ if (delegate_method.IsGeneric) {
+ TypeParameterSpec[] tparams;
+ var sm = ec.CurrentAnonymousMethod == null ? null : ec.CurrentAnonymousMethod.Storey as StateMachine;
+ if (sm != null && sm.OriginalTypeParameters != null) {
+ tparams = sm.CurrentTypeParameters.Types;
+ } else {
+ tparams = method.TypeParameters;
+ }
+
+ delegate_method = delegate_method.MakeGenericMethod (ec.MemberContext, tparams);
+ }
ec.Emit (OpCodes.Ldftn, delegate_method);
}
equals.Block = equals_block;
equals.Define ();
- equals.PrepareEmit ();
Members.Add (equals);
//
hashcode_block.AddStatement (new Return (hash_variable, loc));
hashcode.Block = hashcode_top;
hashcode.Define ();
- hashcode.PrepareEmit ();
Members.Add (hashcode);
//
tostring_block.AddStatement (new Return (string_concat, loc));
tostring.Block = tostring_block;
tostring.Define ();
- tostring.PrepareEmit ();
Members.Add (tostring);
return true;