if (IsSideEffectFree)
return this;
+ bool needs_temporary = ContainsEmitWithAwait ();
+ if (!needs_temporary)
+ ec.EmitThis ();
+
// Emit original code
EmitToFieldSource (ec);
- // Create temporary local (we cannot load this before Emit)
- var temp = ec.GetTemporaryLocal (type);
- ec.Emit (OpCodes.Stloc, temp, type);
-
//
- // Store the result to temporary field
+ // Store the result to temporary field when we
+ // cannot load this directly
//
var field = ec.GetTemporaryField (type);
- ec.EmitThis ();
- ec.Emit (OpCodes.Ldloc, temp, type);
- field.EmitAssignFromStack (ec);
+ if (needs_temporary) {
+ //
+ // Create temporary local (we cannot load this before Emit)
+ //
+ var temp = ec.GetTemporaryLocal (type);
+ ec.Emit (OpCodes.Stloc, temp);
- ec.FreeTemporaryLocal (temp, type);
+ ec.EmitThis ();
+ ec.Emit (OpCodes.Ldloc, temp);
+ field.EmitAssignFromStack (ec);
+
+ ec.FreeTemporaryLocal (temp, type);
+ } else {
+ field.EmitAssignFromStack (ec);
+ }
return field;
}
return null;
}
- protected static MethodSpec ConstructorLookup (ResolveContext rc, TypeSpec type, ref Arguments args, Location loc)
+ public static MethodSpec ConstructorLookup (ResolveContext rc, TypeSpec type, ref Arguments args, Location loc)
{
var ctors = MemberCache.FindMembers (type, Constructor.ConstructorName, true);
if (ctors == null) {
InstanceExpression.Emit (ec);
t.Store (ec);
t.AddressOf (ec, AddressOp.Store);
+ t.Release (ec);
}
} else {
InstanceExpression.Emit (ec);
public abstract void SetTypeArguments (ResolveContext ec, TypeArguments ta);
}
+ public class ExtensionMethodCandidates
+ {
+ NamespaceContainer container;
+ Namespace ns;
+ IList<MethodSpec> methods;
+
+ public ExtensionMethodCandidates (IList<MethodSpec> methods, NamespaceContainer nsContainer)
+ : this (methods, nsContainer, null)
+ {
+ }
+
+ public ExtensionMethodCandidates (IList<MethodSpec> methods, NamespaceContainer nsContainer, Namespace ns)
+ {
+ this.methods = methods;
+ this.container = nsContainer;
+ this.ns = ns;
+ }
+
+ public NamespaceContainer Container {
+ get {
+ return container;
+ }
+ }
+
+ public bool HasUninspectedMembers { get; set; }
+
+ public Namespace Namespace {
+ get {
+ return ns;
+ }
+ }
+
+ public IList<MethodSpec> Methods {
+ get {
+ return methods;
+ }
+ }
+ }
+
//
// Represents a group of extension method candidates for whole namespace
//
class ExtensionMethodGroupExpr : MethodGroupExpr, OverloadResolver.IErrorHandler
{
- NamespaceContainer namespace_entry;
+ ExtensionMethodCandidates candidates;
public readonly Expression ExtensionExpression;
- public ExtensionMethodGroupExpr (IList<MethodSpec> list, NamespaceContainer n, Expression extensionExpr, Location l)
- : base (list.Cast<MemberSpec>().ToList (), extensionExpr.Type, l)
+ public ExtensionMethodGroupExpr (ExtensionMethodCandidates candidates, Expression extensionExpr, Location loc)
+ : base (candidates.Methods.Cast<MemberSpec>().ToList (), extensionExpr.Type, loc)
{
- this.namespace_entry = n;
+ this.candidates = candidates;
this.ExtensionExpression = extensionExpr;
}
get { return true; }
}
+ //
+ // For extension methodgroup we are not looking for base members but parent
+ // namespace extension methods
+ //
public override IList<MemberSpec> GetBaseMembers (TypeSpec baseType)
{
- if (namespace_entry == null)
+ // TODO: candidates are null only when doing error reporting, that's
+ // incorrect. We have to discover same extension methods in error mode
+ if (candidates == null)
return null;
+ int arity = type_arguments == null ? 0 : type_arguments.Count;
+
//
- // For extension methodgroup we are not looking for base members but parent
- // namespace extension methods
+ // Here we try to resume the search for extension method at the point
+ // where the last bunch of candidates was found. It's more tricky than
+ // it seems as we have to check both namespace containers and namespace
+ // in correct order.
//
- int arity = type_arguments == null ? 0 : type_arguments.Count;
- var found = namespace_entry.LookupExtensionMethod (DeclaringType, Name, arity, ref namespace_entry);
- if (found == null)
+ // Consider:
+ //
+ // namespace A {
+ // using N1;
+ // namespace B.C.D {
+ // <our first search found candidates in A.B.C.D
+ // }
+ // }
+ //
+ // In the example above namespace A.B.C.D, A.B.C and A.B have to be
+ // checked before we hit A.N1 using
+ //
+ if (candidates.Namespace == null) {
+ Namespace scope;
+ var methods = candidates.Container.NS.LookupExtensionMethod (candidates.Container, ExtensionExpression.Type, Name, arity, out scope);
+ if (methods != null) {
+ candidates = new ExtensionMethodCandidates (null, candidates.Container, scope);
+ return methods.Cast<MemberSpec> ().ToList ();
+ }
+ }
+
+ var ns_container = candidates.HasUninspectedMembers ? candidates.Container : candidates.Container.Parent;
+ if (ns_container == null)
return null;
- return found.Cast<MemberSpec> ().ToList ();
+ candidates = ns_container.LookupExtensionMethod (ExtensionExpression.Type, Name, arity);
+ if (candidates == null)
+ return null;
+
+ return candidates.Methods.Cast<MemberSpec> ().ToList ();
}
public override MethodGroupExpr LookupExtensionMethod (ResolveContext rc)
return null;
int arity = type_arguments == null ? 0 : type_arguments.Count;
- NamespaceContainer methods_scope = null;
- var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity, ref methods_scope);
+ var methods = rc.LookupExtensionMethod (InstanceExpression.Type, Methods[0].Name, arity);
if (methods == null)
return null;
- var emg = new ExtensionMethodGroupExpr (methods, methods_scope, InstanceExpression, loc);
+ var emg = new ExtensionMethodGroupExpr (methods, InstanceExpression, loc);
emg.SetTypeArguments (rc, type_arguments);
return emg;
}
} else if (var != null && var.IsHoisted) {
AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, var, loc);
}
-
+
return new FixedBufferPtr (this, fb.ElementType, loc).Resolve (ec);
}
public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
{
- if (ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ()) {
- source = source.EmitToField (ec);
+ bool has_await_source = ec.HasSet (BuilderContext.Options.AsyncBody) && source.ContainsEmitWithAwait ();
+ if (isCompound && !(source is DynamicExpressionStatement)) {
+ if (has_await_source) {
+ if (IsInstance)
+ InstanceExpression = InstanceExpression.EmitToField (ec);
+ } else {
+ prepared = true;
+ }
}
- prepared = isCompound && !(source is DynamicExpressionStatement);
- if (IsInstance)
+ if (IsInstance) {
+ if (has_await_source)
+ source = source.EmitToField (ec);
+
EmitInstance (ec, prepared);
+ }
source.Emit (ec);
if (need_copy) {
Emit (ec);
var temp = ec.GetTemporaryLocal (type);
- ec.Emit (OpCodes.Stloc, temp, type);
- ec.Emit (OpCodes.Ldloca, temp, type);
+ ec.Emit (OpCodes.Stloc, temp);
+ ec.Emit (OpCodes.Ldloca, temp);
ec.FreeTemporaryLocal (temp, type);
return;
}