diff --git a/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs b/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs
index bb951edf8d055..8ded8764ef004 100644
--- a/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs
@@ -22,17 +22,20 @@ internal partial class Binder
///
/// For the purpose of escape verification we operate with the depth of local scopes.
/// The depth is a uint, with smaller number representing shallower/wider scopes.
- /// The 0 and 1 are special scopes -
- /// 0 is the "external" or "return" scope that is outside of the containing method/lambda.
- /// If something can escape to scope 0, it can escape to any scope in a given method or can be returned.
- /// 1 is the "parameter" or "top" scope that is just inside the containing method/lambda.
+ /// 0, 1 and 2 are special scopes -
+ /// 0 is the "calling method" scope that is outside of the containing method/lambda.
+ /// If something can escape to scope 0, it can escape to any scope in a given method through a ref parameter or return.
+ /// 1 is the "return-only" scope that is outside of the containing method/lambda.
+ /// If something can escape to scope 1, it can escape to any scope in a given method or can be returned, but it can't escape through a ref parameter.
+ /// 2 is the "current method" scope that is just inside the containing method/lambda.
/// If something can escape to scope 1, it can escape to any scope in a given method, but cannot be returned.
/// n + 1 corresponds to scopes immediately inside a scope of depth n.
/// Since sibling scopes do not intersect and a value cannot escape from one to another without
/// escaping to a wider scope, we can use simple depth numbering without ambiguity.
///
internal const uint ExternalScope = 0;
- internal const uint TopLevelScope = 1;
+ internal const uint ReturnOnlyScope = 1;
+ internal const uint TopLevelScope = 2;
// Some value kinds are semantically the same and the only distinction is how errors are reported
// for those purposes we reserve lowest 2 bits
@@ -719,7 +722,7 @@ private static bool CheckLocalRefEscape(SyntaxNode node, BoundLocal local, uint
return true;
}
- if (escapeTo == Binder.ExternalScope)
+ if (escapeTo is Binder.ExternalScope or Binder.ReturnOnlyScope)
{
if (localSymbol.RefKind == RefKind.None)
{
@@ -794,21 +797,17 @@ private uint GetParameterValEscape(ParameterSymbol parameter)
private uint GetParameterRefEscape(ParameterSymbol parameter)
{
- if (UseUpdatedEscapeRules)
- {
- return parameter.RefKind is RefKind.None || parameter.EffectiveScope != DeclarationScope.Unscoped ? Binder.TopLevelScope : Binder.ExternalScope;
- }
- else
+ return parameter switch
{
- // byval parameters can escape to method's top level. Others can escape further.
- // NOTE: "method" here means nearest containing method, lambda or local function.
- return parameter.RefKind == RefKind.None ? Binder.TopLevelScope : Binder.ExternalScope;
- }
+ { RefKind: RefKind.None } or { EffectiveScope: not DeclarationScope.Unscoped } => Binder.TopLevelScope,
+ { Type.IsRefLikeType: true } => Binder.ReturnOnlyScope,
+ _ => Binder.ExternalScope
+ };
}
private bool CheckParameterValEscape(SyntaxNode node, BoundParameter parameter, uint escapeTo, BindingDiagnosticBag diagnostics)
{
- Debug.Assert(escapeTo == Binder.ExternalScope);
+ Debug.Assert(escapeTo is Binder.ExternalScope or Binder.ReturnOnlyScope);
if (UseUpdatedEscapeRules)
{
var parameterSymbol = parameter.ParameterSymbol;
@@ -826,22 +825,32 @@ private bool CheckParameterValEscape(SyntaxNode node, BoundParameter parameter,
}
}
- private bool CheckParameterRefEscape(SyntaxNode node, BoundParameter parameter, uint escapeTo, bool checkingReceiver, BindingDiagnosticBag diagnostics)
+ private bool CheckParameterRefEscape(SyntaxNode node, BoundExpression parameter, ParameterSymbol parameterSymbol, uint escapeTo, bool checkingReceiver, BindingDiagnosticBag diagnostics)
{
- var parameterSymbol = parameter.ParameterSymbol;
-
- if (GetParameterRefEscape(parameterSymbol) > escapeTo)
+ var refSafeToEscape = GetParameterRefEscape(parameterSymbol);
+ if (refSafeToEscape > escapeTo)
{
var isRefScoped = parameterSymbol.EffectiveScope == DeclarationScope.RefScoped;
- Debug.Assert(parameterSymbol.RefKind == RefKind.None || isRefScoped);
- if (checkingReceiver)
+ Debug.Assert(parameterSymbol.RefKind == RefKind.None || isRefScoped || refSafeToEscape == Binder.ReturnOnlyScope);
+
+ if (parameter is BoundThisReference)
{
- Error(diagnostics, isRefScoped ? ErrorCode.ERR_RefReturnScopedParameter2 : ErrorCode.ERR_RefReturnParameter2, parameter.Syntax, parameterSymbol.Name);
+ Error(diagnostics, ErrorCode.ERR_RefReturnStructThis, node);
+ return false;
}
- else
+
+#pragma warning disable format
+ var (errorCode, syntax) = (checkingReceiver, isRefScoped, refSafeToEscape) switch
{
- Error(diagnostics, isRefScoped ? ErrorCode.ERR_RefReturnScopedParameter : ErrorCode.ERR_RefReturnParameter, node, parameterSymbol.Name);
- }
+ (checkingReceiver: true, isRefScoped: true, _) => (ErrorCode.ERR_RefReturnScopedParameter2, parameter.Syntax),
+ (checkingReceiver: true, isRefScoped: false, Binder.ReturnOnlyScope) => (ErrorCode.ERR_RefReturnOnlyParameter, parameter.Syntax),
+ (checkingReceiver: true, isRefScoped: false, _) => (ErrorCode.ERR_RefReturnParameter2, parameter.Syntax),
+ (checkingReceiver: false, isRefScoped: true, _) => (ErrorCode.ERR_RefReturnScopedParameter, node),
+ (checkingReceiver: false, isRefScoped: false, Binder.ReturnOnlyScope) => (ErrorCode.ERR_RefReturnOnlyParameter, node),
+ (checkingReceiver: false, isRefScoped: false, _) => (ErrorCode.ERR_RefReturnParameter, node)
+ };
+#pragma warning restore format
+ Error(diagnostics, errorCode, syntax, parameterSymbol.Name);
return false;
}
@@ -2362,7 +2371,7 @@ private static ErrorCode GetStandardLvalueError(BindValueKind kind)
private static ErrorCode GetStandardRValueRefEscapeError(uint escapeTo)
{
- if (escapeTo == Binder.ExternalScope)
+ if (escapeTo is Binder.ExternalScope or Binder.ReturnOnlyScope)
{
return ErrorCode.ERR_RefReturnLvalueExpected;
}
@@ -2524,28 +2533,9 @@ internal uint GetRefEscape(BoundExpression expr, uint scopeOfTheContainingExpres
return ((BoundLocal)expr).LocalSymbol.RefEscapeScope;
case BoundKind.ThisReference:
- Debug.Assert(this.ContainingMember() is MethodSymbol { ThisParameter: not null });
-
- var thisref = (BoundThisReference)expr;
-
- // "this" is an RValue, unless in a struct.
- if (!thisref.Type.IsValueType)
- {
- break;
- }
-
- if (UseUpdatedEscapeRules)
- {
- if (this.ContainingMember() is MethodSymbol { ThisParameter: var thisParameter } &&
- thisParameter.EffectiveScope == DeclarationScope.Unscoped)
- {
- return Binder.ExternalScope;
- }
- }
-
- //"this" is not returnable by reference in a struct.
- // can ref escape to any other level
- return Binder.TopLevelScope;
+ var thisParam = ((MethodSymbol)this.ContainingMember()).ThisParameter;
+ Debug.Assert(thisParam.Type.Equals(((BoundThisReference)expr).Type, TypeCompareKind.ConsiderEverything));
+ return GetParameterRefEscape(thisParam);
case BoundKind.ConditionalOperator:
var conditional = (BoundConditionalOperator)expr;
@@ -2761,7 +2751,7 @@ internal bool CheckRefEscape(SyntaxNode node, BoundExpression expr, uint escapeF
case BoundKind.RefValueOperator:
// The undocumented __refvalue(tr, T) expression results in an lvalue of type T.
// for compat reasons it is not ref-returnable (since TypedReference is not val-returnable)
- if (escapeTo == Binder.ExternalScope)
+ if (escapeTo is Binder.ExternalScope or Binder.ReturnOnlyScope)
{
break;
}
@@ -2782,41 +2772,16 @@ internal bool CheckRefEscape(SyntaxNode node, BoundExpression expr, uint escapeF
case BoundKind.Parameter:
var parameter = (BoundParameter)expr;
- return CheckParameterRefEscape(node, parameter, escapeTo, checkingReceiver, diagnostics);
+ return CheckParameterRefEscape(node, parameter, parameter.ParameterSymbol, escapeTo, checkingReceiver, diagnostics);
case BoundKind.Local:
var local = (BoundLocal)expr;
return CheckLocalRefEscape(node, local, escapeTo, checkingReceiver, diagnostics);
case BoundKind.ThisReference:
- Debug.Assert(this.ContainingMember() is MethodSymbol { ThisParameter: not null });
-
- var thisref = (BoundThisReference)expr;
-
- // "this" is an RValue, unless in a struct.
- if (!thisref.Type.IsValueType)
- {
- break;
- }
-
- //"this" is not returnable by reference in a struct.
- if (escapeTo == Binder.ExternalScope)
- {
- if (UseUpdatedEscapeRules)
- {
- if (this.ContainingMember() is MethodSymbol { ThisParameter: var thisParameter } &&
- thisParameter.EffectiveScope == DeclarationScope.Unscoped)
- {
- // can ref escape to any other level
- return true;
- }
- }
- Error(diagnostics, ErrorCode.ERR_RefReturnStructThis, node);
- return false;
- }
-
- // can ref escape to any other level
- return true;
+ var thisParam = ((MethodSymbol)this.ContainingMember()).ThisParameter;
+ Debug.Assert(thisParam.Type.Equals(((BoundThisReference)expr).Type, TypeCompareKind.ConsiderEverything));
+ return CheckParameterRefEscape(node, expr, thisParam, escapeTo, checkingReceiver, diagnostics);
case BoundKind.ConditionalOperator:
var conditional = (BoundConditionalOperator)expr;
diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs
index 15e8ca841f1b2..566008ea46a62 100644
--- a/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs
@@ -237,7 +237,7 @@ private BoundStatement BindYieldReturnStatement(YieldStatementSyntax node, Bindi
BoundExpression argument = (node.Expression == null)
? BadExpression(node).MakeCompilerGenerated()
: BindValue(node.Expression, diagnostics, BindValueKind.RValue);
- argument = ValidateEscape(argument, ExternalScope, isByRef: false, diagnostics: diagnostics);
+ argument = ValidateEscape(argument, ReturnOnlyScope, isByRef: false, diagnostics: diagnostics);
if (!argument.HasAnyErrors)
{
@@ -1546,7 +1546,7 @@ private BoundAssignmentOperator BindAssignment(
var rightEscape = GetRefEscape(op2, LocalScopeDepth);
if (leftEscape < rightEscape)
{
- Error(diagnostics, ErrorCode.ERR_RefAssignNarrower, node, getName(op1), op2.Syntax);
+ Error(diagnostics, rightEscape == Binder.ReturnOnlyScope ? ErrorCode.ERR_RefAssignReturnOnly : ErrorCode.ERR_RefAssignNarrower, node, getName(op1), op2.Syntax);
op2 = ToBadExpression(op2);
}
}
@@ -2979,7 +2979,7 @@ private BoundStatement BindReturn(ReturnStatementSyntax syntax, BindingDiagnosti
else
{
arg = CreateReturnConversion(syntax, diagnostics, arg, sigRefKind, retType);
- arg = ValidateEscape(arg, Binder.ExternalScope, refKind != RefKind.None, diagnostics);
+ arg = ValidateEscape(arg, Binder.ReturnOnlyScope, refKind != RefKind.None, diagnostics);
}
}
}
@@ -3421,7 +3421,7 @@ static BoundBlock bindExpressionBodyAsBlockInternal(ArrowExpressionClauseSyntax
ExpressionSyntax expressionSyntax = expressionBody.Expression.CheckAndUnwrapRefExpression(diagnostics, out refKind);
BindValueKind requiredValueKind = bodyBinder.GetRequiredReturnValueKind(refKind);
BoundExpression expression = bodyBinder.BindValue(expressionSyntax, diagnostics, requiredValueKind);
- expression = bodyBinder.ValidateEscape(expression, Binder.ExternalScope, refKind != RefKind.None, diagnostics);
+ expression = bodyBinder.ValidateEscape(expression, Binder.ReturnOnlyScope, refKind != RefKind.None, diagnostics);
return bodyBinder.CreateBlockFromExpression(expressionBody, bodyBinder.GetDeclaredLocalsForScope(expressionBody), refKind, expression, expressionSyntax, diagnostics);
}
@@ -3439,7 +3439,7 @@ public BoundBlock BindLambdaExpressionAsBlock(ExpressionSyntax body, BindingDiag
var expressionSyntax = body.CheckAndUnwrapRefExpression(diagnostics, out refKind);
BindValueKind requiredValueKind = GetRequiredReturnValueKind(refKind);
BoundExpression expression = bodyBinder.BindValue(expressionSyntax, diagnostics, requiredValueKind);
- expression = ValidateEscape(expression, Binder.ExternalScope, refKind != RefKind.None, diagnostics);
+ expression = ValidateEscape(expression, Binder.ReturnOnlyScope, refKind != RefKind.None, diagnostics);
return bodyBinder.CreateBlockFromExpression(body, bodyBinder.GetDeclaredLocalsForScope(body), refKind, expression, expressionSyntax, diagnostics);
}
diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx
index 9a0f54618eb72..04bff9bc269d8 100644
--- a/src/Compilers/CSharp/Portable/CSharpResources.resx
+++ b/src/Compilers/CSharp/Portable/CSharpResources.resx
@@ -5077,6 +5077,12 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
Cannot return by reference a member of parameter '{0}' because it is scoped to the current method
+
+ Cannot return a parameter by reference '{0}' through a ref parameter; it can only be returned in a return statement
+
+
+ Cannot return by reference a member of parameter '{0}' through a ref parameter; it can only be returned in a return statement
+
Cannot return local '{0}' by reference because it is not a ref local
@@ -5791,6 +5797,9 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
Cannot ref-assign '{1}' to '{0}' because '{1}' has a narrower escape scope than '{0}'.
+
+ Cannot ref-assign '{1}' to '{0}' because '{1}' can only escape the current method through a return statement.
+
enum generic type constraints
diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
index 5929fe5682ba6..d49449df1f81b 100644
--- a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
+++ b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
@@ -2124,7 +2124,10 @@ internal enum ErrorCode
WRN_ScopedMismatchInParameterOfTarget = 9073,
WRN_ScopedMismatchInParameterOfOverrideOrImplementation = 9074,
ERR_RefReturnScopedParameter = 9075,
- ERR_RefReturnScopedParameter2 = 9076
+ ERR_RefReturnScopedParameter2 = 9076,
+ ERR_RefReturnOnlyParameter = 9077,
+ ERR_RefReturnOnlyParameter2 = 9078,
+ ERR_RefAssignReturnOnly = 9079,
#endregion
diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs b/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs
index c8ef49488ffe4..f9d9b37730345 100644
--- a/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs
+++ b/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs
@@ -2226,6 +2226,9 @@ internal static bool IsBuildOnlyDiagnostic(ErrorCode code)
case ErrorCode.WRN_ScopedMismatchInParameterOfOverrideOrImplementation:
case ErrorCode.ERR_RefReturnScopedParameter:
case ErrorCode.ERR_RefReturnScopedParameter2:
+ case ErrorCode.ERR_RefReturnOnlyParameter:
+ case ErrorCode.ERR_RefReturnOnlyParameter2:
+ case ErrorCode.ERR_RefAssignReturnOnly:
return false;
default:
// NOTE: All error codes must be explicitly handled in this switch statement
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf
index 8de91af2e61fa..c68eb4d8c7cbf 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf
@@ -1287,6 +1287,11 @@
Přiřazení odkazu {1} k {0} nelze provést, protože {1} má užší řídicí obor než {0}.
+
+ Cannot ref-assign '{1}' to '{0}' because '{1}' can only escape the current method through a return statement.
+ Cannot ref-assign '{1}' to '{0}' because '{1}' can only escape the current method through a return statement.
+
+ A ref field cannot refer to a ref struct.Pole ref nemůže odkazovat na hodnotu ref struct.
@@ -1302,6 +1307,16 @@
Levá strana přiřazení odkazu musí být parametr Ref.
+
+ Cannot return a parameter by reference '{0}' through a ref parameter; it can only be returned in a return statement
+ Cannot return a parameter by reference '{0}' through a ref parameter; it can only be returned in a return statement
+
+
+
+ Cannot return by reference a member of parameter '{0}' through a ref parameter; it can only be returned in a return statement
+ Cannot return by reference a member of parameter '{0}' through a ref parameter; it can only be returned in a return statement
+
+ Cannot return a parameter by reference '{0}' because it is scoped to the current methodCannot return a parameter by reference '{0}' because it is scoped to the current method
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf
index 2a9b54ddc616d..8692d8632c0c5 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf
@@ -1287,6 +1287,11 @@
ref-assign von "{1}" zu "{0}" ist nicht möglich, weil "{1}" einen geringeren Escapebereich als "{0}" aufweist.
+
+ Cannot ref-assign '{1}' to '{0}' because '{1}' can only escape the current method through a return statement.
+ Cannot ref-assign '{1}' to '{0}' because '{1}' can only escape the current method through a return statement.
+
+ A ref field cannot refer to a ref struct.Ein Ref-Feld kann nicht auf eine Ref-Struktur verweisen.
@@ -1302,6 +1307,16 @@
Die linke Seite einer Ref-Zuweisung muss eine Ref-Variable sein.
+
+ Cannot return a parameter by reference '{0}' through a ref parameter; it can only be returned in a return statement
+ Cannot return a parameter by reference '{0}' through a ref parameter; it can only be returned in a return statement
+
+
+
+ Cannot return by reference a member of parameter '{0}' through a ref parameter; it can only be returned in a return statement
+ Cannot return by reference a member of parameter '{0}' through a ref parameter; it can only be returned in a return statement
+
+ Cannot return a parameter by reference '{0}' because it is scoped to the current methodCannot return a parameter by reference '{0}' because it is scoped to the current method
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf
index ed600f1473222..b02a146c93efb 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf
@@ -1287,6 +1287,11 @@
No se puede asignar referencia "{1}" a "{0}" porque "{1}" tiene un ámbito de escape más limitado que "{0}".
+
+ Cannot ref-assign '{1}' to '{0}' because '{1}' can only escape the current method through a return statement.
+ Cannot ref-assign '{1}' to '{0}' because '{1}' can only escape the current method through a return statement.
+
+ A ref field cannot refer to a ref struct.Un campo de referencia no puede hacer referencia a una estructura de referencia.
@@ -1302,6 +1307,16 @@
La parte izquierda de una asignación de referencias debe ser una variable local.
+
+ Cannot return a parameter by reference '{0}' through a ref parameter; it can only be returned in a return statement
+ Cannot return a parameter by reference '{0}' through a ref parameter; it can only be returned in a return statement
+
+
+
+ Cannot return by reference a member of parameter '{0}' through a ref parameter; it can only be returned in a return statement
+ Cannot return by reference a member of parameter '{0}' through a ref parameter; it can only be returned in a return statement
+
+ Cannot return a parameter by reference '{0}' because it is scoped to the current methodCannot return a parameter by reference '{0}' because it is scoped to the current method
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf
index 4b6836cfc672f..aba5fc45e761f 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf
@@ -1287,6 +1287,11 @@
Impossible d'effectuer une assignation par référence de '{1}' vers '{0}', car '{1}' a une portée de sortie plus limitée que '{0}'.
+
+ Cannot ref-assign '{1}' to '{0}' because '{1}' can only escape the current method through a return statement.
+ Cannot ref-assign '{1}' to '{0}' because '{1}' can only escape the current method through a return statement.
+
+ A ref field cannot refer to a ref struct.Un champ ref ne peut pas faire référence à un struct ref.
@@ -1302,6 +1307,16 @@
Le côté gauche d’une affectation ref doit être une variable ref.
+
+ Cannot return a parameter by reference '{0}' through a ref parameter; it can only be returned in a return statement
+ Cannot return a parameter by reference '{0}' through a ref parameter; it can only be returned in a return statement
+
+
+
+ Cannot return by reference a member of parameter '{0}' through a ref parameter; it can only be returned in a return statement
+ Cannot return by reference a member of parameter '{0}' through a ref parameter; it can only be returned in a return statement
+
+ Cannot return a parameter by reference '{0}' because it is scoped to the current methodCannot return a parameter by reference '{0}' because it is scoped to the current method
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf
index ac12d777d5134..c75a8e92291a4 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf
@@ -1287,6 +1287,11 @@
Non è possibile assegnare '{1}' a '{0}' come ref perché l'ambito di escape di '{1}' è ridotto rispetto a quello di '{0}'.
+
+ Cannot ref-assign '{1}' to '{0}' because '{1}' can only escape the current method through a return statement.
+ Cannot ref-assign '{1}' to '{0}' because '{1}' can only escape the current method through a return statement.
+
+ A ref field cannot refer to a ref struct.Un campo ref non può fare riferimento a un ref struct.
@@ -1302,6 +1307,16 @@
La parte sinistra di un'assegnazione ref deve essere una variabile ref.
+
+ Cannot return a parameter by reference '{0}' through a ref parameter; it can only be returned in a return statement
+ Cannot return a parameter by reference '{0}' through a ref parameter; it can only be returned in a return statement
+
+
+
+ Cannot return by reference a member of parameter '{0}' through a ref parameter; it can only be returned in a return statement
+ Cannot return by reference a member of parameter '{0}' through a ref parameter; it can only be returned in a return statement
+
+ Cannot return a parameter by reference '{0}' because it is scoped to the current methodCannot return a parameter by reference '{0}' because it is scoped to the current method
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf
index ec7eee3d8caf2..65e1f9e213d31 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf
@@ -1287,6 +1287,11 @@
'{1}' を '{0}' に ref 割り当てすることはできません。'{1}' のエスケープ スコープが '{0}' より狭いためです。
+
+ Cannot ref-assign '{1}' to '{0}' because '{1}' can only escape the current method through a return statement.
+ Cannot ref-assign '{1}' to '{0}' because '{1}' can only escape the current method through a return statement.
+
+ A ref field cannot refer to a ref struct.ref フィールドは ref 構造体を参照できません。
@@ -1302,6 +1307,16 @@
ref 代入の左辺は ref 変数である必要があります。
+
+ Cannot return a parameter by reference '{0}' through a ref parameter; it can only be returned in a return statement
+ Cannot return a parameter by reference '{0}' through a ref parameter; it can only be returned in a return statement
+
+
+
+ Cannot return by reference a member of parameter '{0}' through a ref parameter; it can only be returned in a return statement
+ Cannot return by reference a member of parameter '{0}' through a ref parameter; it can only be returned in a return statement
+
+ Cannot return a parameter by reference '{0}' because it is scoped to the current methodCannot return a parameter by reference '{0}' because it is scoped to the current method
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf
index 8f768e0cba094..ff234ed42ab32 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf
@@ -1287,6 +1287,11 @@
'{1}'을(를) '{0}'에 참조 할당할 수 없습니다. '{1}'이(가) '{0}'보다 이스케이프 범위가 좁기 때문입니다.
+
+ Cannot ref-assign '{1}' to '{0}' because '{1}' can only escape the current method through a return statement.
+ Cannot ref-assign '{1}' to '{0}' because '{1}' can only escape the current method through a return statement.
+
+ A ref field cannot refer to a ref struct.ref 필드는 ref 구조체를 참조할 수 없습니다.
@@ -1302,6 +1307,16 @@
ref 할당의 왼쪽은 ref 변수여야 합니다.
+
+ Cannot return a parameter by reference '{0}' through a ref parameter; it can only be returned in a return statement
+ Cannot return a parameter by reference '{0}' through a ref parameter; it can only be returned in a return statement
+
+
+
+ Cannot return by reference a member of parameter '{0}' through a ref parameter; it can only be returned in a return statement
+ Cannot return by reference a member of parameter '{0}' through a ref parameter; it can only be returned in a return statement
+
+ Cannot return a parameter by reference '{0}' because it is scoped to the current methodCannot return a parameter by reference '{0}' because it is scoped to the current method
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf
index 03d6290263f95..3c9b7611cbe47 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf
@@ -1287,6 +1287,11 @@
Nie można przypisać odwołania elementu „{1}” do elementu „{0}”, ponieważ element „{1}” ma węższy zakres wyjścia niż element „{0}”.
+
+ Cannot ref-assign '{1}' to '{0}' because '{1}' can only escape the current method through a return statement.
+ Cannot ref-assign '{1}' to '{0}' because '{1}' can only escape the current method through a return statement.
+
+ A ref field cannot refer to a ref struct.Pole referencyjne nie może odwoływać się do struktury referencyjnej.
@@ -1302,6 +1307,16 @@
Lewa strona przypisania referencyjnego musi być zmienną referencyjną.
+
+ Cannot return a parameter by reference '{0}' through a ref parameter; it can only be returned in a return statement
+ Cannot return a parameter by reference '{0}' through a ref parameter; it can only be returned in a return statement
+
+
+
+ Cannot return by reference a member of parameter '{0}' through a ref parameter; it can only be returned in a return statement
+ Cannot return by reference a member of parameter '{0}' through a ref parameter; it can only be returned in a return statement
+
+ Cannot return a parameter by reference '{0}' because it is scoped to the current methodCannot return a parameter by reference '{0}' because it is scoped to the current method
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf
index 100bc9f3b1f83..63c6224abaa39 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf
@@ -1287,6 +1287,11 @@
Não é possível atribuir ref '{1}' a '{0}' porque '{1}' tem um escopo de escape mais limitado que '{0}'.
+
+ Cannot ref-assign '{1}' to '{0}' because '{1}' can only escape the current method through a return statement.
+ Cannot ref-assign '{1}' to '{0}' because '{1}' can only escape the current method through a return statement.
+
+ A ref field cannot refer to a ref struct.Um campo ref não pode se referir a um struct ref.
@@ -1302,6 +1307,16 @@
O lado esquerdo de uma atribuição ref deve ser uma variável ref.
+
+ Cannot return a parameter by reference '{0}' through a ref parameter; it can only be returned in a return statement
+ Cannot return a parameter by reference '{0}' through a ref parameter; it can only be returned in a return statement
+
+
+
+ Cannot return by reference a member of parameter '{0}' through a ref parameter; it can only be returned in a return statement
+ Cannot return by reference a member of parameter '{0}' through a ref parameter; it can only be returned in a return statement
+
+ Cannot return a parameter by reference '{0}' because it is scoped to the current methodCannot return a parameter by reference '{0}' because it is scoped to the current method
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf
index 250791c2a3fd6..de1fb4d926785 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf
@@ -1287,6 +1287,11 @@
Не удается присвоить по ссылке "{1}" для "{0}", так как escape-область у "{1}" уже, чем у "{0}".
+
+ Cannot ref-assign '{1}' to '{0}' because '{1}' can only escape the current method through a return statement.
+ Cannot ref-assign '{1}' to '{0}' because '{1}' can only escape the current method through a return statement.
+
+ A ref field cannot refer to a ref struct.Поле ref не должно ссылаться на ref struct.
@@ -1302,6 +1307,16 @@
Левая сторона назначения ref должна быть переменной ref.
+
+ Cannot return a parameter by reference '{0}' through a ref parameter; it can only be returned in a return statement
+ Cannot return a parameter by reference '{0}' through a ref parameter; it can only be returned in a return statement
+
+
+
+ Cannot return by reference a member of parameter '{0}' through a ref parameter; it can only be returned in a return statement
+ Cannot return by reference a member of parameter '{0}' through a ref parameter; it can only be returned in a return statement
+
+ Cannot return a parameter by reference '{0}' because it is scoped to the current methodCannot return a parameter by reference '{0}' because it is scoped to the current method
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf
index d7cc5e3b64575..bd7101a513967 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf
@@ -1287,6 +1287,11 @@
'{1}', '{0}' öğesinden daha dar bir kaçış kapsamı içerdiğinden '{0}' öğesine '{1}' ref ataması yapılamıyor.
+
+ Cannot ref-assign '{1}' to '{0}' because '{1}' can only escape the current method through a return statement.
+ Cannot ref-assign '{1}' to '{0}' because '{1}' can only escape the current method through a return statement.
+
+ A ref field cannot refer to a ref struct.Başvuru alanı bir başvuru yapısına başvuramaz.
@@ -1302,6 +1307,16 @@
ref atamasının sol tarafı, ref değişkeni olmalıdır.
+
+ Cannot return a parameter by reference '{0}' through a ref parameter; it can only be returned in a return statement
+ Cannot return a parameter by reference '{0}' through a ref parameter; it can only be returned in a return statement
+
+
+
+ Cannot return by reference a member of parameter '{0}' through a ref parameter; it can only be returned in a return statement
+ Cannot return by reference a member of parameter '{0}' through a ref parameter; it can only be returned in a return statement
+
+ Cannot return a parameter by reference '{0}' because it is scoped to the current methodCannot return a parameter by reference '{0}' because it is scoped to the current method
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf
index 0e9a1a4ded4c8..4fff2340c997b 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf
@@ -1287,6 +1287,11 @@
无法将“{1}”重新赋值为“{0}”,因为“{1}”具有比“{0}”更窄的转义范围。
+
+ Cannot ref-assign '{1}' to '{0}' because '{1}' can only escape the current method through a return statement.
+ Cannot ref-assign '{1}' to '{0}' because '{1}' can only escape the current method through a return statement.
+
+ A ref field cannot refer to a ref struct.ref 字段不能引用 ref 结构。
@@ -1302,6 +1307,16 @@
ref 赋值的左侧必须为 ref 变量。
+
+ Cannot return a parameter by reference '{0}' through a ref parameter; it can only be returned in a return statement
+ Cannot return a parameter by reference '{0}' through a ref parameter; it can only be returned in a return statement
+
+
+
+ Cannot return by reference a member of parameter '{0}' through a ref parameter; it can only be returned in a return statement
+ Cannot return by reference a member of parameter '{0}' through a ref parameter; it can only be returned in a return statement
+
+ Cannot return a parameter by reference '{0}' because it is scoped to the current methodCannot return a parameter by reference '{0}' because it is scoped to the current method
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf
index fa11c82ad73b3..23e75df9fe506 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf
@@ -1287,6 +1287,11 @@
不能將 '{1}' 參考指派至 '{0}',因為 '{1}' 的逸出範圍比 '{0}' 還要窄。
+
+ Cannot ref-assign '{1}' to '{0}' because '{1}' can only escape the current method through a return statement.
+ Cannot ref-assign '{1}' to '{0}' because '{1}' can only escape the current method through a return statement.
+
+ A ref field cannot refer to a ref struct.ref 欄位不能參考 ref 結構。
@@ -1302,6 +1307,16 @@
參考指派的左側必須為 ref 變數。
+
+ Cannot return a parameter by reference '{0}' through a ref parameter; it can only be returned in a return statement
+ Cannot return a parameter by reference '{0}' through a ref parameter; it can only be returned in a return statement
+
+
+
+ Cannot return by reference a member of parameter '{0}' through a ref parameter; it can only be returned in a return statement
+ Cannot return by reference a member of parameter '{0}' through a ref parameter; it can only be returned in a return statement
+
+ Cannot return a parameter by reference '{0}' because it is scoped to the current methodCannot return a parameter by reference '{0}' because it is scoped to the current method
diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs
index 0acb2966d3742..a7a24718b7a73 100644
--- a/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs
+++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs
@@ -1124,7 +1124,10 @@ static void F([UnscopedRef] ref R1 r1)
comp.VerifyEmitDiagnostics(
// (8,12): error CS9050: A ref field cannot refer to a ref struct.
// public ref R1 F;
- Diagnostic(ErrorCode.ERR_RefFieldCannotReferToRefStruct, "ref R1").WithLocation(8, 12));
+ Diagnostic(ErrorCode.ERR_RefFieldCannotReferToRefStruct, "ref R1").WithLocation(8, 12),
+ // (15,9): error CS9079: Cannot ref-assign 'r1' to 'F' because 'r1' can only escape the current method through a return statement.
+ // r2.F = ref r1;
+ Diagnostic(ErrorCode.ERR_RefAssignReturnOnly, "r2.F = ref r1").WithArguments("F", "r1").WithLocation(15, 9));
}
///
@@ -2980,7 +2983,7 @@ static void F1(ref R a, __arglist) { }
}
[Fact]
- public void MethodArgumentsMustMatch_07()
+ public void MethodArgumentsMustMatch_07_1()
{
var source =
@"using System.Diagnostics.CodeAnalysis;
@@ -2993,30 +2996,143 @@ static void F1(ref R a, __arglist) { }
static void F00(ref R x, ref R y) { F0(__arglist(ref x, ref y)); } // 1
static void F01(ref R x, ref R y) { F1(ref x, __arglist(ref y)); } // 2
static void F20(ref R x, [UnscopedRef] ref R y) { F0(__arglist(ref x, ref y)); } // 3
- static void F21(ref R x, [UnscopedRef] ref R y) { F1(ref x, __arglist(ref y)); }
- static void F50([UnscopedRef] ref R x, [UnscopedRef] ref R y) { F0(__arglist(ref x, ref y)); }
- static void F51([UnscopedRef] ref R x, [UnscopedRef] ref R y) { F1(ref x, __arglist(ref y)); }
+ static void F21(ref R x, [UnscopedRef] ref R y) { F1(ref x, __arglist(ref y)); } // 4
+ static void F50([UnscopedRef] ref R x, [UnscopedRef] ref R y) { F0(__arglist(ref x, ref y)); } // 5
+ static void F51([UnscopedRef] ref R x, [UnscopedRef] ref R y) { F1(ref x, __arglist(ref y)); } // 6
}";
var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition });
comp.VerifyEmitDiagnostics(
- // (8,41): error CS8350: This combination of arguments to 'Program.F0(__arglist)' is disallowed because it may expose variables referenced by parameter '__arglist' outside of their declaration scope
- // static void F00(ref R x, ref R y) { F0(__arglist(ref x, ref y)); } // 1
- Diagnostic(ErrorCode.ERR_CallArgMixing, "F0(__arglist(ref x, ref y))").WithArguments("Program.F0(__arglist)", "__arglist").WithLocation(8, 41),
// (8,58): error CS9075: Cannot return a parameter by reference 'x' because it is scoped to the current method
// static void F00(ref R x, ref R y) { F0(__arglist(ref x, ref y)); } // 1
Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "x").WithArguments("x").WithLocation(8, 58),
- // (9,41): error CS8350: This combination of arguments to 'Program.F1(ref R, __arglist)' is disallowed because it may expose variables referenced by parameter '__arglist' outside of their declaration scope
- // static void F01(ref R x, ref R y) { F1(ref x, __arglist(ref y)); } // 2
- Diagnostic(ErrorCode.ERR_CallArgMixing, "F1(ref x, __arglist(ref y))").WithArguments("Program.F1(ref R, __arglist)", "__arglist").WithLocation(9, 41),
+ // (8,41): error CS8350: This combination of arguments to 'Program.F0(__arglist)' is disallowed because it may expose variables referenced by parameter '__arglist' outside of their declaration scope
+ // static void F00(ref R x, ref R y) { F0(__arglist(ref x, ref y)); } // 1
+ Diagnostic(ErrorCode.ERR_CallArgMixing, "F0(__arglist(ref x, ref y))").WithArguments("Program.F0(__arglist)", "__arglist").WithLocation(8, 41),
// (9,65): error CS9075: Cannot return a parameter by reference 'y' because it is scoped to the current method
// static void F01(ref R x, ref R y) { F1(ref x, __arglist(ref y)); } // 2
Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "y").WithArguments("y").WithLocation(9, 65),
+ // (9,41): error CS8350: This combination of arguments to 'Program.F1(ref R, __arglist)' is disallowed because it may expose variables referenced by parameter '__arglist' outside of their declaration scope
+ // static void F01(ref R x, ref R y) { F1(ref x, __arglist(ref y)); } // 2
+ Diagnostic(ErrorCode.ERR_CallArgMixing, "F1(ref x, __arglist(ref y))").WithArguments("Program.F1(ref R, __arglist)", "__arglist").WithLocation(9, 41),
+ // (10,72): error CS9075: Cannot return a parameter by reference 'x' because it is scoped to the current method
+ // static void F20(ref R x, [UnscopedRef] ref R y) { F0(__arglist(ref x, ref y)); } // 3
+ Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "x").WithArguments("x").WithLocation(10, 72),
// (10,55): error CS8350: This combination of arguments to 'Program.F0(__arglist)' is disallowed because it may expose variables referenced by parameter '__arglist' outside of their declaration scope
// static void F20(ref R x, [UnscopedRef] ref R y) { F0(__arglist(ref x, ref y)); } // 3
Diagnostic(ErrorCode.ERR_CallArgMixing, "F0(__arglist(ref x, ref y))").WithArguments("Program.F0(__arglist)", "__arglist").WithLocation(10, 55),
- // (10,72): error CS9075: Cannot return a parameter by reference 'x' because it is scoped to the current method
- // static void F20(ref R x, [UnscopedRef] ref R y) { F0(__arglist(ref x, ref y)); } // 3
- Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "x").WithArguments("x").WithLocation(10, 72));
+ // (11,79): error CS9077: Cannot return a parameter by reference 'y' through a ref parameter; it can only be returned in a return statement
+ // static void F21(ref R x, [UnscopedRef] ref R y) { F1(ref x, __arglist(ref y)); } // 4
+ Diagnostic(ErrorCode.ERR_RefReturnOnlyParameter, "y").WithArguments("y").WithLocation(11, 79),
+ // (11,55): error CS8350: This combination of arguments to 'Program.F1(ref R, __arglist)' is disallowed because it may expose variables referenced by parameter '__arglist' outside of their declaration scope
+ // static void F21(ref R x, [UnscopedRef] ref R y) { F1(ref x, __arglist(ref y)); } // 4
+ Diagnostic(ErrorCode.ERR_CallArgMixing, "F1(ref x, __arglist(ref y))").WithArguments("Program.F1(ref R, __arglist)", "__arglist").WithLocation(11, 55),
+ // (12,86): error CS9077: Cannot return a parameter by reference 'x' through a ref parameter; it can only be returned in a return statement
+ // static void F50([UnscopedRef] ref R x, [UnscopedRef] ref R y) { F0(__arglist(ref x, ref y)); } // 5
+ Diagnostic(ErrorCode.ERR_RefReturnOnlyParameter, "x").WithArguments("x").WithLocation(12, 86),
+ // (12,69): error CS8350: This combination of arguments to 'Program.F0(__arglist)' is disallowed because it may expose variables referenced by parameter '__arglist' outside of their declaration scope
+ // static void F50([UnscopedRef] ref R x, [UnscopedRef] ref R y) { F0(__arglist(ref x, ref y)); } // 5
+ Diagnostic(ErrorCode.ERR_CallArgMixing, "F0(__arglist(ref x, ref y))").WithArguments("Program.F0(__arglist)", "__arglist").WithLocation(12, 69),
+ // (13,93): error CS9077: Cannot return a parameter by reference 'y' through a ref parameter; it can only be returned in a return statement
+ // static void F51([UnscopedRef] ref R x, [UnscopedRef] ref R y) { F1(ref x, __arglist(ref y)); } // 6
+ Diagnostic(ErrorCode.ERR_RefReturnOnlyParameter, "y").WithArguments("y").WithLocation(13, 93),
+ // (13,69): error CS8350: This combination of arguments to 'Program.F1(ref R, __arglist)' is disallowed because it may expose variables referenced by parameter '__arglist' outside of their declaration scope
+ // static void F51([UnscopedRef] ref R x, [UnscopedRef] ref R y) { F1(ref x, __arglist(ref y)); } // 6
+ Diagnostic(ErrorCode.ERR_CallArgMixing, "F1(ref x, __arglist(ref y))").WithArguments("Program.F1(ref R, __arglist)", "__arglist").WithLocation(13, 69));
+ }
+
+ [Fact]
+ public void MethodArgumentsMustMatch_07_2()
+ {
+ var source =
+@"
+using System.Diagnostics.CodeAnalysis;
+using System;
+
+ref struct R
+{
+ public byte B;
+ public ref byte RB;
+}
+
+class Program
+{
+ static R F0(__arglist)
+ {
+ var args = new ArgIterator(__arglist);
+ ref R r = ref __refvalue(args.GetNextArg(), R);
+ r.RB = ref r.B; // 1
+ return r;
+ }
+
+ static void F1(ref R y) { F0(__arglist(ref y)); } // 2
+ static void F2([UnscopedRef] ref R y) { F0(__arglist(ref y)); } // 3
+
+ static R F3(ref R y) { return F0(__arglist(ref y)); } // 4
+ static R F4([UnscopedRef] ref R y) { return F0(__arglist(ref y)); } // 5
+}";
+ // __refvalue operators can only ref-escape to current method.
+ // The __arglist operator here assumes that `F0` could do `y.RB = ref y`.
+ // These assumptions are contradictory, but it just ends up being more strict in both directions.
+ // Tracking in https://github.com/dotnet/roslyn/issues/64130
+ var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }, runtimeFeature: RuntimeFlag.ByRefFields);
+ comp.VerifyEmitDiagnostics(
+ // (17,9): error CS8374: Cannot ref-assign 'r.B' to 'RB' because 'r.B' has a narrower escape scope than 'RB'.
+ // r.RB = ref r.B; // 1
+ Diagnostic(ErrorCode.ERR_RefAssignNarrower, "r.RB = ref r.B").WithArguments("RB", "r.B").WithLocation(17, 9),
+ // (21,48): error CS9075: Cannot return a parameter by reference 'y' because it is scoped to the current method
+ // static void F1(ref R y) { F0(__arglist(ref y)); } // 2
+ Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "y").WithArguments("y").WithLocation(21, 48),
+ // (21,31): error CS8350: This combination of arguments to 'Program.F0(__arglist)' is disallowed because it may expose variables referenced by parameter '__arglist' outside of their declaration scope
+ // static void F1(ref R y) { F0(__arglist(ref y)); } // 2
+ Diagnostic(ErrorCode.ERR_CallArgMixing, "F0(__arglist(ref y))").WithArguments("Program.F0(__arglist)", "__arglist").WithLocation(21, 31),
+ // (22,62): error CS9077: Cannot return a parameter by reference 'y' through a ref parameter; it can only be returned in a return statement
+ // static void F2([UnscopedRef] ref R y) { F0(__arglist(ref y)); } // 3
+ Diagnostic(ErrorCode.ERR_RefReturnOnlyParameter, "y").WithArguments("y").WithLocation(22, 62),
+ // (22,45): error CS8350: This combination of arguments to 'Program.F0(__arglist)' is disallowed because it may expose variables referenced by parameter '__arglist' outside of their declaration scope
+ // static void F2([UnscopedRef] ref R y) { F0(__arglist(ref y)); } // 3
+ Diagnostic(ErrorCode.ERR_CallArgMixing, "F0(__arglist(ref y))").WithArguments("Program.F0(__arglist)", "__arglist").WithLocation(22, 45),
+ // (24,52): error CS9075: Cannot return a parameter by reference 'y' because it is scoped to the current method
+ // static R F3(ref R y) { return F0(__arglist(ref y)); } // 4
+ Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "y").WithArguments("y").WithLocation(24, 52),
+ // (24,35): error CS8350: This combination of arguments to 'Program.F0(__arglist)' is disallowed because it may expose variables referenced by parameter '__arglist' outside of their declaration scope
+ // static R F3(ref R y) { return F0(__arglist(ref y)); } // 4
+ Diagnostic(ErrorCode.ERR_CallArgMixing, "F0(__arglist(ref y))").WithArguments("Program.F0(__arglist)", "__arglist").WithLocation(24, 35),
+ // (25,66): error CS9077: Cannot return a parameter by reference 'y' through a ref parameter; it can only be returned in a return statement
+ // static R F4([UnscopedRef] ref R y) { return F0(__arglist(ref y)); } // 5
+ Diagnostic(ErrorCode.ERR_RefReturnOnlyParameter, "y").WithArguments("y").WithLocation(25, 66),
+ // (25,49): error CS8350: This combination of arguments to 'Program.F0(__arglist)' is disallowed because it may expose variables referenced by parameter '__arglist' outside of their declaration scope
+ // static R F4([UnscopedRef] ref R y) { return F0(__arglist(ref y)); } // 5
+ Diagnostic(ErrorCode.ERR_CallArgMixing, "F0(__arglist(ref y))").WithArguments("Program.F0(__arglist)", "__arglist").WithLocation(25, 49));
+ }
+
+ [Fact]
+ public void MethodArgumentsMustMatch_07_3()
+ {
+ // demonstrate the non-ref-fields behavior.
+ var source =
+@"
+using System;
+
+class Program
+{
+ static ref int F0(__arglist)
+ {
+ var args = new ArgIterator(__arglist);
+ ref int r = ref __refvalue(args.GetNextArg(), int);
+ return ref r; // 1
+ }
+
+ static void F1(scoped ref int y) { F0(__arglist(ref y)); }
+ static void F2(ref int y) { F0(__arglist(ref y)); }
+
+ static ref int F3(scoped ref int y) { return ref F0(__arglist(ref y)); }
+ static ref int F4(ref int y) { return ref F0(__arglist(ref y)); }
+}";
+ var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }, runtimeFeature: RuntimeFlag.ByRefFields);
+ comp.VerifyEmitDiagnostics(
+ // (10,20): error CS8157: Cannot return 'r' by reference because it was initialized to a value that cannot be returned by reference
+ // return ref r; // 1
+ Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "r").WithArguments("r").WithLocation(10, 20));
}
///
@@ -6349,8 +6465,11 @@ static T ReadIn(in R2 r2In)
var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }, runtimeFeature: RuntimeFlag.ByRefFields);
comp.VerifyEmitDiagnostics(
// (10,12): error CS9050: A ref field cannot refer to a ref struct.
- // public ref R1 R1
- Diagnostic(ErrorCode.ERR_RefFieldCannotReferToRefStruct, "ref R1").WithLocation(10, 12));
+ // public ref R1 R1;
+ Diagnostic(ErrorCode.ERR_RefFieldCannotReferToRefStruct, "ref R1").WithLocation(10, 12),
+ // (11,45): error CS9079: Cannot ref-assign 'r1' to 'R1' because 'r1' can only escape the current method through a return statement.
+ // public R2([UnscopedRef] ref R1 r1) { R1 = ref r1; }
+ Diagnostic(ErrorCode.ERR_RefAssignReturnOnly, "R1 = ref r1").WithArguments("R1", "r1").WithLocation(11, 45));
}
[Fact]
@@ -7118,7 +7237,10 @@ static void F([UnscopedRef] ref R r)
Diagnostic(ErrorCode.ERR_RefFieldCannotReferToRefStruct, "ref R").WithLocation(5, 12),
// (5,21): error CS0523: Struct member 'R.Next' of type 'R' causes a cycle in the struct layout
// public ref R Next;
- Diagnostic(ErrorCode.ERR_StructLayoutCycle, "Next").WithArguments("R.Next", "R").WithLocation(5, 21));
+ Diagnostic(ErrorCode.ERR_StructLayoutCycle, "Next").WithArguments("R.Next", "R").WithLocation(5, 21),
+ // (11,9): error CS9079: Cannot ref-assign 'r' to 'Next' because 'r' can only escape the current method through a return statement.
+ // r.Next = ref r;
+ Diagnostic(ErrorCode.ERR_RefAssignReturnOnly, "r.Next = ref r").WithArguments("Next", "r").WithLocation(11, 9));
}
///
@@ -13120,6 +13242,57 @@ public void ReturnThis_02(LanguageVersion languageVersion)
Diagnostic(ErrorCode.ERR_RefReturnStructThis, "this").WithLocation(5, 32));
}
+ [Fact, WorkItem(63526, "https://github.com/dotnet/roslyn/issues/63526")]
+ public void ReturnThis_03()
+ {
+ var source = """
+ using System.Diagnostics.CodeAnalysis;
+
+ ref struct S2 {
+ public S S;
+ }
+
+ ref struct S {
+ public int field;
+ public ref int refField;
+
+ ref int Prop1 => ref field; // 1
+
+ [UnscopedRef] ref int Prop2 => ref field; // okay
+
+ S2 Prop3 => new S2 { S = this }; // Okay
+
+ S Prop4 => new S { refField = ref this.field }; // 2
+
+ [UnscopedRef] S Prop5 => new S { refField = ref this.field }; // okay
+
+ S M1() => new S { refField = ref this.field }; // 3
+
+ [UnscopedRef]
+ S M2() => new S { refField = ref this.field }; // okay
+
+ static S M3(ref S s) => new S { refField = ref s.field }; // 4
+
+ static S M4([UnscopedRef] ref S s) => new S { refField = ref s.field }; // okay
+ }
+ """;
+
+ var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }, runtimeFeature: RuntimeFlag.ByRefFields);
+ comp.VerifyDiagnostics(
+ // (11,26): error CS8170: Struct members cannot return 'this' or other instance members by reference
+ // ref int Prop1 => ref field; // 1
+ Diagnostic(ErrorCode.ERR_RefReturnStructThis, "field").WithLocation(11, 26),
+ // (17,24): error CS8170: Struct members cannot return 'this' or other instance members by reference
+ // S Prop4 => new S { refField = ref this.field }; // 2
+ Diagnostic(ErrorCode.ERR_RefReturnStructThis, "refField = ref this.field").WithLocation(17, 24),
+ // (21,23): error CS8170: Struct members cannot return 'this' or other instance members by reference
+ // S M1() => new S { refField = ref this.field }; // 3
+ Diagnostic(ErrorCode.ERR_RefReturnStructThis, "refField = ref this.field").WithLocation(21, 23),
+ // (26,52): error CS9076: Cannot return by reference a member of parameter 's' because it is scoped to the current method
+ // static S M3(ref S s) => new S { refField = ref s.field }; // 4
+ Diagnostic(ErrorCode.ERR_RefReturnScopedParameter2, "s").WithArguments("s").WithLocation(26, 52));
+ }
+
[Fact]
public void RefInitializer_LangVer()
{
@@ -17882,16 +18055,12 @@ static void M12(ref ByteContainer bc)
static void M21([UnscopedRef] ref ByteContainer bc, ref RefByteContainer rbc)
{
// error. ref-safe-to-escape of 'bc' is 'ReturnOnly', therefore 'bc.ByteRef' can't be assigned to a ref parameter.
- // this error will be enabled in a future PR before RTM.
- // https://github.com/dotnet/csharplang/pull/6450
- rbc = bc.ByteRef;
+ rbc = bc.ByteRef; // 1
}
static void M22([UnscopedRef] ref ByteContainer bc, ref RefByteContainer rbc)
{
// error. ref-safe-to-escape of 'bc' is 'ReturnOnly', therefore 'bc.ByteRef' can't be assigned to a ref parameter.
- // this error will be enabled in a future PR before RTM.
- // https://github.com/dotnet/csharplang/pull/6450
- rbc = bc.GetByteRef();
+ rbc = bc.GetByteRef(); // 2
}
static RefByteContainer M31([UnscopedRef] ref ByteContainer bc)
@@ -17904,22 +18073,311 @@ static RefByteContainer M32([UnscopedRef] ref ByteContainer bc)
static RefByteContainer M41(ref ByteContainer bc)
// error: `bc.ByteRef` may contain a reference to `bc`, whose ref-safe-to-escape is CurrentMethod.
- => bc.ByteRef;
+ => bc.ByteRef; // 3
static RefByteContainer M42(ref ByteContainer bc)
// error: `bc.GetByteRef()` may contain a reference to `bc`, whose ref-safe-to-escape is CurrentMethod.
- => bc.GetByteRef();
+ => bc.GetByteRef(); // 4
}
""";
var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }, runtimeFeature: RuntimeFlag.ByRefFields);
comp.VerifyDiagnostics(
+ // (42,15): error CS9077: Cannot return a parameter by reference 'bc' through a ref parameter; it can only be returned in a return statement
+ // rbc = bc.ByteRef; // 1
+ Diagnostic(ErrorCode.ERR_RefReturnOnlyParameter, "bc").WithArguments("bc").WithLocation(42, 15),
+ // (47,15): error CS9077: Cannot return a parameter by reference 'bc' through a ref parameter; it can only be returned in a return statement
+ // rbc = bc.GetByteRef(); // 2
+ Diagnostic(ErrorCode.ERR_RefReturnOnlyParameter, "bc").WithArguments("bc").WithLocation(47, 15),
+ // (60,12): error CS9075: Cannot return a parameter by reference 'bc' because it is scoped to the current method
+ // => bc.ByteRef; // 3
+ Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "bc").WithArguments("bc").WithLocation(60, 12),
// (64,12): error CS9075: Cannot return a parameter by reference 'bc' because it is scoped to the current method
- // => bc.ByteRef;
- Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "bc").WithArguments("bc").WithLocation(64, 12),
- // (68,12): error CS9075: Cannot return a parameter by reference 'bc' because it is scoped to the current method
- // => bc.GetByteRef();
- Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "bc").WithArguments("bc").WithLocation(68, 12));
+ // => bc.GetByteRef(); // 4
+ Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "bc").WithArguments("bc").WithLocation(64, 12));
+ }
+
+ [Fact, WorkItem(63526, "https://github.com/dotnet/roslyn/issues/63526")]
+ public void ReturnOnlyScope_01()
+ {
+ // test that return scope is used in all return-ey locations.
+ var source = """
+ using System.Diagnostics.CodeAnalysis;
+
+ ref struct RS
+ {
+ public byte B;
+
+ [UnscopedRef]
+ public RSOut ToRSOut()
+ {
+ return new RSOut { RB = ref this.B };
+ }
+ }
+
+ ref struct RSOut
+ {
+ public ref byte RB;
+ }
+
+ class Program
+ {
+ RS M1([UnscopedRef] ref RS rs) => rs;
+ void M2([UnscopedRef] ref RS rs, out RSOut rs1) => rs1 = rs.ToRSOut(); // 1
+
+ RS M3([UnscopedRef] ref RS rs)
+ {
+ return rs;
+ }
+ void M4([UnscopedRef] ref RS rs, out RSOut rs1)
+ {
+ rs1 = rs.ToRSOut(); // 2
+ }
+
+ void localContainer()
+ {
+ #pragma warning disable 8321
+ RS M1([UnscopedRef] ref RS rs) => rs;
+ void M2([UnscopedRef] ref RS rs, out RSOut rs1) => rs1 = rs.ToRSOut(); // 3
+
+ RS M3([UnscopedRef] ref RS rs)
+ {
+ return rs;
+ }
+ void M4([UnscopedRef] ref RS rs, out RSOut rs1)
+ {
+ rs1 = rs.ToRSOut(); // 4
+ }
+ }
+
+ delegate RS ReturnsRefStruct([UnscopedRef] ref RS rs);
+ delegate void RefStructOut([UnscopedRef] ref RS rs, out RSOut rs1);
+
+ void lambdaContainer()
+ {
+ ReturnsRefStruct d1 = ([UnscopedRef] ref RS rs) => rs;
+ RefStructOut d2 = ([UnscopedRef] ref RS rs, out RSOut rs1) => rs1 = rs.ToRSOut(); // 5
+
+ ReturnsRefStruct d3 = ([UnscopedRef] ref RS rs) =>
+ {
+ return rs;
+ };
+ RefStructOut d4 = ([UnscopedRef] ref RS rs, out RSOut rs1) =>
+ {
+ rs1 = rs.ToRSOut(); // 6
+ };
+ }
+ }
+ """;
+
+ var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }, runtimeFeature: RuntimeFlag.ByRefFields);
+ comp.VerifyDiagnostics(
+ // (22,62): error CS9077: Cannot return a parameter by reference 'rs' through a ref parameter; it can only be returned in a return statement
+ // void M2([UnscopedRef] ref RS rs, out RSOut rs1) => rs1 = rs.ToRSOut(); // 1
+ Diagnostic(ErrorCode.ERR_RefReturnOnlyParameter, "rs").WithArguments("rs").WithLocation(22, 62),
+ // (30,15): error CS9077: Cannot return a parameter by reference 'rs' through a ref parameter; it can only be returned in a return statement
+ // rs1 = rs.ToRSOut(); // 2
+ Diagnostic(ErrorCode.ERR_RefReturnOnlyParameter, "rs").WithArguments("rs").WithLocation(30, 15),
+ // (37,66): error CS9077: Cannot return a parameter by reference 'rs' through a ref parameter; it can only be returned in a return statement
+ // void M2([UnscopedRef] ref RS rs, out RSOut rs1) => rs1 = rs.ToRSOut(); // 3
+ Diagnostic(ErrorCode.ERR_RefReturnOnlyParameter, "rs").WithArguments("rs").WithLocation(37, 66),
+ // (45,19): error CS9077: Cannot return a parameter by reference 'rs' through a ref parameter; it can only be returned in a return statement
+ // rs1 = rs.ToRSOut(); // 4
+ Diagnostic(ErrorCode.ERR_RefReturnOnlyParameter, "rs").WithArguments("rs").WithLocation(45, 19),
+ // (55,77): error CS9077: Cannot return a parameter by reference 'rs' through a ref parameter; it can only be returned in a return statement
+ // RefStructOut d2 = ([UnscopedRef] ref RS rs, out RSOut rs1) => rs1 = rs.ToRSOut(); // 5
+ Diagnostic(ErrorCode.ERR_RefReturnOnlyParameter, "rs").WithArguments("rs").WithLocation(55, 77),
+ // (63,19): error CS9077: Cannot return a parameter by reference 'rs' through a ref parameter; it can only be returned in a return statement
+ // rs1 = rs.ToRSOut(); // 6
+ Diagnostic(ErrorCode.ERR_RefReturnOnlyParameter, "rs").WithArguments("rs").WithLocation(63, 19));
+ }
+
+ [Fact, WorkItem(63526, "https://github.com/dotnet/roslyn/issues/63526")]
+ public void ReturnOnlyScope_02()
+ {
+ var source = """
+ using System.Diagnostics.CodeAnalysis;
+
+ #pragma warning disable 8321 // unused local function
+ static bool condition() => false;
+
+ static void M1(ref S p1, ref S p2) {
+ p2.refField = ref p1.field; // 1
+ p2.refField = ref p1.refField; // Okay
+ }
+
+ static void M2(ref S p1, out S p2) {
+ p2 = default;
+ p2.refField = ref p1.field; // 2
+ p2.refField = ref p1.refField; // Okay
+ }
+
+ static void M3(out S p1, ref S p2) {
+ p1 = default;
+ p2.refField = ref p1.field; // 3
+ p2.refField = ref p1.refField; // Okay
+ }
+
+ // The [UnscopedRef] moves `out` to default RSTE which is *return only*
+ static void M4([UnscopedRef] out S p1, ref S p2) {
+ p1 = default;
+ p2.refField = ref p1.field; // 4
+ p2.refField = ref p1.refField; // Okay
+ }
+
+ static void M5([UnscopedRef] ref S p1, ref S2 p2) {
+ p2 = Inner1(ref p1); // 5
+ p2 = Inner2(ref p1); // Okay
+ }
+
+ static void M6([UnscopedRef] ref S p1, out S2 p2) {
+ p2 = Inner1(ref p1); // 6
+ p2 = Inner2(ref p1); // Okay
+ }
+
+ static void M7(scoped ref S p1, ref S2 p2) {
+ p2 = Inner1(ref p1); // 7
+ p2 = Inner2(ref p1); // Okay
+ }
+
+ static S2 M8(scoped ref S p) {
+ if (condition()) return Inner1(ref p); // 8
+ if (condition()) return Inner2(ref p); // Okay
+
+ throw null!;
+ }
+
+ static S2 M9([UnscopedRef] ref S p) {
+ if (condition()) return Inner1(ref p); // Okay
+ if (condition()) return Inner2(ref p); // Okay
+
+ throw null!;
+ }
+
+ static S2 Inner1([UnscopedRef] ref S s) => new S2 { S = s };
+ static S2 Inner2(scoped ref S s) => new S2 { S = s };
+
+ ref struct S {
+ public int field;
+ public ref int refField;
+ }
+
+ ref struct S2 {
+ public S S;
+ }
+ """;
+
+ var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }, runtimeFeature: RuntimeFlag.ByRefFields);
+ comp.VerifyDiagnostics(
+ // (7,5): error CS8374: Cannot ref-assign 'p1.field' to 'refField' because 'p1.field' has a narrower escape scope than 'refField'.
+ // p2.refField = ref p1.field; // 1
+ Diagnostic(ErrorCode.ERR_RefAssignNarrower, "p2.refField = ref p1.field").WithArguments("refField", "p1.field").WithLocation(7, 5),
+ // (13,5): error CS8374: Cannot ref-assign 'p1.field' to 'refField' because 'p1.field' has a narrower escape scope than 'refField'.
+ // p2.refField = ref p1.field; // 2
+ Diagnostic(ErrorCode.ERR_RefAssignNarrower, "p2.refField = ref p1.field").WithArguments("refField", "p1.field").WithLocation(13, 5),
+ // (19,5): error CS8374: Cannot ref-assign 'p1.field' to 'refField' because 'p1.field' has a narrower escape scope than 'refField'.
+ // p2.refField = ref p1.field; // 3
+ Diagnostic(ErrorCode.ERR_RefAssignNarrower, "p2.refField = ref p1.field").WithArguments("refField", "p1.field").WithLocation(19, 5),
+ // (26,5): error CS9079: Cannot ref-assign 'p1.field' to 'refField' because 'p1.field' can only escape the current method through a return statement.
+ // p2.refField = ref p1.field; // 4
+ Diagnostic(ErrorCode.ERR_RefAssignReturnOnly, "p2.refField = ref p1.field").WithArguments("refField", "p1.field").WithLocation(26, 5),
+ // (31,10): error CS8347: Cannot use a result of 'Inner1(ref S)' in this context because it may expose variables referenced by parameter 's' outside of their declaration scope
+ // p2 = Inner1(ref p1); // 5
+ Diagnostic(ErrorCode.ERR_EscapeCall, "Inner1(ref p1)").WithArguments("Inner1(ref S)", "s").WithLocation(31, 10),
+ // (31,21): error CS9077: Cannot return a parameter by reference 'p1' through a ref parameter; it can only be returned in a return statement
+ // p2 = Inner1(ref p1); // 5
+ Diagnostic(ErrorCode.ERR_RefReturnOnlyParameter, "p1").WithArguments("p1").WithLocation(31, 21),
+ // (36,10): error CS8347: Cannot use a result of 'Inner1(ref S)' in this context because it may expose variables referenced by parameter 's' outside of their declaration scope
+ // p2 = Inner1(ref p1); // 6
+ Diagnostic(ErrorCode.ERR_EscapeCall, "Inner1(ref p1)").WithArguments("Inner1(ref S)", "s").WithLocation(36, 10),
+ // (36,21): error CS9077: Cannot return a parameter by reference 'p1' through a ref parameter; it can only be returned in a return statement
+ // p2 = Inner1(ref p1); // 6
+ Diagnostic(ErrorCode.ERR_RefReturnOnlyParameter, "p1").WithArguments("p1").WithLocation(36, 21),
+ // (41,10): error CS8347: Cannot use a result of 'Inner1(ref S)' in this context because it may expose variables referenced by parameter 's' outside of their declaration scope
+ // p2 = Inner1(ref p1); // 7
+ Diagnostic(ErrorCode.ERR_EscapeCall, "Inner1(ref p1)").WithArguments("Inner1(ref S)", "s").WithLocation(41, 10),
+ // (41,21): error CS9075: Cannot return a parameter by reference 'p1' because it is scoped to the current method
+ // p2 = Inner1(ref p1); // 7
+ Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "p1").WithArguments("p1").WithLocation(41, 21),
+ // (46,29): error CS8347: Cannot use a result of 'Inner1(ref S)' in this context because it may expose variables referenced by parameter 's' outside of their declaration scope
+ // if (condition()) return Inner1(ref p); // 8
+ Diagnostic(ErrorCode.ERR_EscapeCall, "Inner1(ref p)").WithArguments("Inner1(ref S)", "s").WithLocation(46, 29),
+ // (46,40): error CS9075: Cannot return a parameter by reference 'p' because it is scoped to the current method
+ // if (condition()) return Inner1(ref p); // 8
+ Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "p").WithArguments("p").WithLocation(46, 40));
+ }
+
+ [Fact, WorkItem(63526, "https://github.com/dotnet/roslyn/issues/63526")]
+ public void ReturnOnlyScope_03()
+ {
+ var source = """
+ using System.Diagnostics.CodeAnalysis;
+
+ #pragma warning disable 8321 // unused local function
+ ref struct S2 {
+ public S S;
+ }
+
+ ref struct S {
+ public int field;
+ public ref int refField;
+
+ void M1(ref S p) {
+ p.refField = ref this.field; // 1
+ p.refField = ref this.refField; // Okay
+ }
+
+ [UnscopedRef]
+ void M2(ref S p) {
+ p.refField = ref this.field; // 2
+ p.refField = ref this.refField; // Okay
+ }
+
+ [UnscopedRef]
+ void M3(out S p) {
+ p = default;
+ p.refField = ref this.field; // 3
+ p.refField = ref this.refField; // Okay
+ }
+
+ void M4(ref S2 p) {
+ p = Inner1(ref this); // 4
+ p = Inner2(ref this); // Okay
+ }
+
+ void M5(out S2 p) {
+ p = Inner1(ref this); // 5
+ p = Inner2(ref this); // Okay
+ }
+
+ static S2 Inner1([UnscopedRef] ref S s) => new S2 { S = s };
+ static S2 Inner2(scoped ref S s) => new S2 { S = s };
+ }
+ """;
+
+ var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }, runtimeFeature: RuntimeFlag.ByRefFields);
+ comp.VerifyDiagnostics(
+ // (13,9): error CS8374: Cannot ref-assign 'this.field' to 'refField' because 'this.field' has a narrower escape scope than 'refField'.
+ // p.refField = ref this.field; // 1
+ Diagnostic(ErrorCode.ERR_RefAssignNarrower, "p.refField = ref this.field").WithArguments("refField", "this.field").WithLocation(13, 9),
+ // (19,9): error CS9079: Cannot ref-assign 'this.field' to 'refField' because 'this.field' can only escape the current method through a return statement.
+ // p.refField = ref this.field; // 2
+ Diagnostic(ErrorCode.ERR_RefAssignReturnOnly, "p.refField = ref this.field").WithArguments("refField", "this.field").WithLocation(19, 9),
+ // (26,9): error CS9079: Cannot ref-assign 'this.field' to 'refField' because 'this.field' can only escape the current method through a return statement.
+ // p.refField = ref this.field; // 3
+ Diagnostic(ErrorCode.ERR_RefAssignReturnOnly, "p.refField = ref this.field").WithArguments("refField", "this.field").WithLocation(26, 9),
+ // (31,13): error CS8347: Cannot use a result of 'S.Inner1(ref S)' in this context because it may expose variables referenced by parameter 's' outside of their declaration scope
+ // p = Inner1(ref this); // 4
+ Diagnostic(ErrorCode.ERR_EscapeCall, "Inner1(ref this)").WithArguments("S.Inner1(ref S)", "s").WithLocation(31, 13),
+ // (31,24): error CS8170: Struct members cannot return 'this' or other instance members by reference
+ // p = Inner1(ref this); // 4
+ Diagnostic(ErrorCode.ERR_RefReturnStructThis, "this").WithLocation(31, 24),
+ // (36,13): error CS8347: Cannot use a result of 'S.Inner1(ref S)' in this context because it may expose variables referenced by parameter 's' outside of their declaration scope
+ // p = Inner1(ref this); // 5
+ Diagnostic(ErrorCode.ERR_EscapeCall, "Inner1(ref this)").WithArguments("S.Inner1(ref S)", "s").WithLocation(36, 13),
+ // (36,24): error CS8170: Struct members cannot return 'this' or other instance members by reference
+ // p = Inner1(ref this); // 5
+ Diagnostic(ErrorCode.ERR_RefReturnStructThis, "this").WithLocation(36, 24));
}
}
}