if (expr == null)
return false;
+ if (expr is ReferenceExpression && block_return_type.Kind != MemberKind.ByRef) {
+ ec.Report.Error (8149, loc, "By-reference returns can only be used in methods that return by reference");
+ return false;
+ }
+
if (expr.Type != block_return_type && expr.Type != InternalType.ErrorType) {
- expr = Convert.ImplicitConversionRequired (ec, expr, block_return_type, loc);
+ if (block_return_type.Kind == MemberKind.ByRef) {
+ var ref_expr = Expr as ReferenceExpression;
+ if (ref_expr == null) {
+ ec.Report.Error (8150, loc, "By-reference return is required when method returns by reference");
+ return false;
+ }
- if (expr == null) {
- if (am != null && block_return_type == ec.ReturnType) {
- ec.Report.Error (1662, loc,
- "Cannot convert `{0}' to delegate type `{1}' because some of the return types in the block are not implicitly convertible to the delegate return type",
- am.ContainerType, am.GetSignatureForError ());
+ var byref_return = (ReferenceContainer)block_return_type;
+
+ if (expr.Type != byref_return.Element) {
+ ec.Report.Error (8151, loc, "The return by reference expression must be of type `{0}' because this method returns by reference",
+ byref_return.GetSignatureForError ());
+ return false;
+ }
+ } else {
+
+ expr = Convert.ImplicitConversionRequired (ec, expr, block_return_type, loc);
+
+ if (expr == null) {
+ if (am != null && block_return_type == ec.ReturnType) {
+ ec.Report.Error (1662, loc,
+ "Cannot convert `{0}' to delegate type `{1}' because some of the return types in the block are not implicitly convertible to the delegate return type",
+ am.ContainerType, am.GetSignatureForError ());
+ }
+ return false;
}
- return false;
}
}
}
if (type == null) {
- type = type_expr.ResolveAsType (bc);
+ type = ResolveTypeExpression (bc);
if (type == null)
return false;
}
if (initializer != null) {
+ if (li.IsByRef) {
+ if (!(initializer is ReferenceExpression)) {
+ bc.Report.Error (8172, loc, "Cannot initialize a by-reference variable `{0}' with a value", li.Name);
+ return false;
+ }
+
+ if (bc.CurrentAnonymousMethod is AsyncInitializer) {
+ bc.Report.Error (8177, loc, "Async methods cannot use by-reference variables");
+ } else if (bc.CurrentIterator != null) {
+ bc.Report.Error (8176, loc, "Iterators cannot use by-reference variables");
+ }
+
+ } else {
+ if (initializer is ReferenceExpression) {
+ bc.Report.Error (8171, loc, "Cannot initialize a by-value variable `{0}' with a reference expression", li.Name);
+ return false;
+ }
+ }
+
initializer = ResolveInitializer (bc, li, initializer);
// li.Variable.DefinitelyAssigned
}
return a.ResolveStatement (bc);
}
+ protected virtual TypeSpec ResolveTypeExpression (BlockContext bc)
+ {
+ return type_expr.ResolveAsType (bc);
+ }
+
protected override void DoEmit (EmitContext ec)
{
li.CreateBuilder (ec);
UsingVariable = 1 << 7,
IsLocked = 1 << 8,
SymbolFileHidden = 1 << 9,
+ ByRef = 1 << 10,
ReadonlyMask = ForeachVariable | FixedVariable | UsingVariable
}
}
}
+ public bool IsByRef => (flags & Flags.ByRef) != 0;
+
public bool IsCompilerGenerated {
get {
return (flags & Flags.CompilerGenerated) != 0;
throw new InternalErrorException ("Already created variable `{0}'", name);
}
- //
- // All fixed variabled are pinned, a slot has to be alocated
- //
- builder = ec.DeclareLocal (Type, IsFixed);
+ if (IsByRef) {
+ builder = ec.DeclareLocal (ReferenceContainer.MakeType (ec.Module, Type), IsFixed);
+ } else {
+ //
+ // All fixed variabled are pinned, a slot has to be alocated
+ //
+ builder = ec.DeclareLocal(Type, IsFixed);
+ }
+
if ((flags & Flags.SymbolFileHidden) == 0)
ec.DefineLocalVariable (name, builder);
}
if ((flags & Flags.CompilerGenerated) != 0)
CreateBuilder (ec);
- ec.Emit (OpCodes.Ldloca, builder);
+ if (IsByRef)
+ ec.Emit (OpCodes.Ldloc, builder);
+ else
+ ec.Emit (OpCodes.Ldloca, builder);
}
public static string GetCompilerGeneratedName (Block block)
AddLocalName (li.Name, li);
}
- public void AddLocalName (string name, INamedBlockVariable li)
+ public virtual void AddLocalName (string name, INamedBlockVariable li, bool canShadowChildrenBlockName = false)
{
- ParametersBlock.TopBlock.AddLocalName (name, li, false);
+ ParametersBlock.TopBlock.AddLocalName (name, li, canShadowChildrenBlockName);
}
public virtual void Error_AlreadyDeclared (string name, INamedBlockVariable variable, string reason)
}
}
- public void AddLocalName (string name, INamedBlockVariable li, bool ignoreChildrenBlocks)
+ public override void AddLocalName (string name, INamedBlockVariable li, bool ignoreChildrenBlocks)
{
if (names == null)
names = new Dictionary<string, object> ();