Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow ref-like locals in iterators and async methods #72664

Merged
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
c245c53
Allow ref-like locals in iterators and async methods
jjonescz Mar 22, 2024
770f206
Return check of ref-like locals in async methods
jjonescz Mar 27, 2024
0e2a287
Move declaration to block where it's used
jjonescz Mar 27, 2024
31cf0fe
Add todo for improving error message of ERR_SpecialByRefInLambda
jjonescz Mar 27, 2024
8e0373f
Test `ref` in `await foreach` and iterator
jjonescz Mar 27, 2024
62d8600
Extend tests
jjonescz Apr 2, 2024
6175750
Skip incompatible desktop tests
jjonescz Apr 2, 2024
e81c580
Test `yield break` in the new `lock`
jjonescz Apr 2, 2024
1e28e31
Extend tests
jjonescz Apr 2, 2024
cc51f66
Mark removed unreleased error code as available
jjonescz Apr 3, 2024
23b9781
Improve check for ref locals that can be hoisted
jjonescz Apr 3, 2024
d6dbc5f
Return error `ERR_BadSpecialByRefIterator`
jjonescz Apr 3, 2024
41e5297
Extend tests
jjonescz Apr 4, 2024
3ba63bb
Uncapitalize feature name to be like others
jjonescz Apr 4, 2024
ee213d0
Use better errors for refs across awaits
jjonescz Apr 4, 2024
9d4dedf
Improve errors for spilled ref locals across awaits
jjonescz Apr 4, 2024
419473e
Replace remaining old error messages
jjonescz Apr 4, 2024
3ded80b
Return wrongly removed fact condition
jjonescz Apr 4, 2024
7e6334b
Extend tests
jjonescz Apr 5, 2024
6cbbccf
Report errors close to problematic usage where possible
jjonescz Apr 5, 2024
755030c
Add more tests
jjonescz Apr 5, 2024
1804c58
Test foreach on ref local with iterator inside
jjonescz Apr 8, 2024
b4cc4b5
Report spill local await boundary errors at their declaration
jjonescz Apr 8, 2024
17677b7
Revert accidentally changed test name
jjonescz Apr 16, 2024
19c3482
Merge branch 'features/RefInAsync' into RefInAsync-01-RefLikeLocals
jjonescz Apr 16, 2024
e45df8a
Test ref struct Current of async enumerator
jjonescz Apr 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 6 additions & 14 deletions src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1327,8 +1327,8 @@ private BoundExpression BindArgList(CSharpSyntaxNode node, BindingDiagnosticBag
// would be hoisted into a closure for an anonymous function, iterator or async method.
// We do that during the actual rewrites.

// CS4013: Instance of type '{0}' cannot be used inside an anonymous function, query expression, iterator block or async method
Error(diagnostics, ErrorCode.ERR_SpecialByRefInLambda, node, runtimeArgumentHandleType);
// CS4013: Instance of type '{0}{1}' cannot be used inside an anonymous function, query expression, iterator block or async method
Error(diagnostics, ErrorCode.ERR_SpecialByRefInLambda, node, string.Empty, runtimeArgumentHandleType);

hasError = true;
}
Expand Down Expand Up @@ -1998,7 +1998,7 @@ private BoundExpression BindNonMethod(SimpleNameSyntax node, Symbol symbol, Bind

if (localSymbol.RefKind == RefKind.None && type.IsRestrictedType(ignoreSpanLikeTypes: true))
{
Error(diagnostics, ErrorCode.ERR_SpecialByRefInLambda, node, type);
Error(diagnostics, ErrorCode.ERR_SpecialByRefInLambda, node, string.Empty, type);
}
else
{
Expand Down Expand Up @@ -2042,7 +2042,7 @@ private BoundExpression BindNonMethod(SimpleNameSyntax node, Symbol symbol, Bind
}
else if (parameter.Type.IsRestrictedType(ignoreSpanLikeTypes: true))
{
Error(diagnostics, ErrorCode.ERR_SpecialByRefInLambda, node, parameter.Type);
Error(diagnostics, ErrorCode.ERR_SpecialByRefInLambda, node, string.Empty, parameter.Type);
}
else
{
Expand Down Expand Up @@ -3182,21 +3182,13 @@ private BoundExpression BindOutVariableDeclarationArgument(
/// <summary>
/// Reports an error when a bad special by-ref local was found.
/// </summary>
internal static void CheckRestrictedTypeInAsyncMethod(Symbol containingSymbol, TypeSymbol type, BindingDiagnosticBag diagnostics, SyntaxNode syntax, ErrorCode errorCode = ErrorCode.ERR_BadSpecialByRefLocal)
internal static void CheckRestrictedTypeInAsyncMethod(Symbol containingSymbol, TypeSymbol type, BindingDiagnosticBag diagnostics, SyntaxNode syntax)
{
Debug.Assert(errorCode is ErrorCode.ERR_BadSpecialByRefLocal or ErrorCode.ERR_BadSpecialByRefUsing or ErrorCode.ERR_BadSpecialByRefLock);
if (containingSymbol.Kind == SymbolKind.Method
&& ((MethodSymbol)containingSymbol).IsAsync
&& type.IsRestrictedType())
{
if (errorCode == ErrorCode.ERR_BadSpecialByRefLock)
{
Error(diagnostics, errorCode, syntax);
}
else
{
Error(diagnostics, errorCode, syntax, type);
}
CheckFeatureAvailability(syntax, MessageID.IDS_FeatureRefUnsafeInIteratorAsync, diagnostics);
}
}

Expand Down
10 changes: 2 additions & 8 deletions src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1165,15 +1165,9 @@ protected BoundLocalDeclaration BindVariableDeclaration(

protected bool CheckRefLocalInAsyncOrIteratorMethod(SyntaxToken identifierToken, BindingDiagnosticBag diagnostics)
{
if (IsInAsyncMethod())
{
Error(diagnostics, ErrorCode.ERR_BadAsyncLocalType, identifierToken);
return true;
}
else if (IsDirectlyInIterator)
if (IsDirectlyInIterator || IsInAsyncMethod())
{
Error(diagnostics, ErrorCode.ERR_BadIteratorLocalType, identifierToken);
return true;
return !CheckFeatureAvailability(identifierToken, MessageID.IDS_FeatureRefUnsafeInIteratorAsync, diagnostics);
}

return false;
Expand Down
2 changes: 1 addition & 1 deletion src/Compilers/CSharp/Portable/Binder/ForEachLoopBinder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -527,7 +527,7 @@ private BoundForEachStatement BindForEachPartsWorker(BindingDiagnosticBag diagno

if (builder.InlineArraySpanType == WellKnownType.Unknown && getEnumeratorType.IsRestrictedType() && (IsDirectlyInIterator || IsInAsyncMethod()))
{
diagnostics.Add(ErrorCode.ERR_BadSpecialByRefIterator, foreachKeyword.GetLocation(), getEnumeratorType);
CheckFeatureAvailability(foreachKeyword, MessageID.IDS_FeatureRefUnsafeInIteratorAsync, diagnostics);
jjonescz marked this conversation as resolved.
Show resolved Hide resolved
}

diagnostics.Add(_syntax.ForEachKeyword, useSiteInfo);
Expand Down
7 changes: 0 additions & 7 deletions src/Compilers/CSharp/Portable/Binder/LockBinder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,6 @@ internal override BoundStatement BindLockStatementParts(BindingDiagnosticBag dia
_ = diagnostics.ReportUseSite(lockTypeInfo.EnterScopeMethod, exprSyntax) ||
diagnostics.ReportUseSite(lockTypeInfo.ScopeType, exprSyntax) ||
diagnostics.ReportUseSite(lockTypeInfo.ScopeDisposeMethod, exprSyntax);

CheckRestrictedTypeInAsyncMethod(
jjonescz marked this conversation as resolved.
Show resolved Hide resolved
originalBinder.ContainingMemberOrLambda,
lockTypeInfo.ScopeType,
diagnostics,
exprSyntax,
errorCode: ErrorCode.ERR_BadSpecialByRefLock);
}

BoundStatement stmt = originalBinder.BindPossibleEmbeddedStatement(_syntax.Statement, diagnostics);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ internal static BoundStatement BindUsingStatementOrDeclarationFromParts(SyntaxNo
Debug.Assert(expressionOpt is not null);
if (expressionOpt.Type is not null)
{
CheckRestrictedTypeInAsyncMethod(originalBinder.ContainingMemberOrLambda, expressionOpt.Type, diagnostics, expressionOpt.Syntax, errorCode: ErrorCode.ERR_BadSpecialByRefUsing);
CheckRestrictedTypeInAsyncMethod(originalBinder.ContainingMemberOrLambda, expressionOpt.Type, diagnostics, expressionOpt.Syntax);
}
}
else
Expand Down
24 changes: 6 additions & 18 deletions src/Compilers/CSharp/Portable/CSharpResources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -3851,14 +3851,8 @@ Give the compiler some way to differentiate the methods. For example, you can gi
<data name="ERR_BadAsyncLacksBody" xml:space="preserve">
<value>The 'async' modifier can only be used in methods that have a body.</value>
</data>
<data name="ERR_BadSpecialByRefLocal" xml:space="preserve">
<value>Parameters or locals of type '{0}' cannot be declared in async methods or async lambda expressions.</value>
</data>
<data name="ERR_BadSpecialByRefUsing" xml:space="preserve">
<value>A using statement resource of type '{0}' cannot be used in async methods or async lambda expressions.</value>
</data>
<data name="ERR_BadSpecialByRefIterator" xml:space="preserve">
<value>foreach statement cannot operate on enumerators of type '{0}' in async or iterator methods because '{0}' is a ref struct.</value>
<data name="ERR_BadSpecialByRefParameter" xml:space="preserve">
<value>Parameters of type '{0}' cannot be declared in async methods or async lambda expressions.</value>
</data>
<data name="ERR_SecurityCriticalOrSecuritySafeCriticalOnAsync" xml:space="preserve">
<value>Security attribute '{0}' cannot be applied to an Async method.</value>
Expand Down Expand Up @@ -4191,7 +4185,7 @@ You should consider suppressing the warning only if you're sure that you don't w
<value>Indexed property '{0}' must have all arguments optional</value>
</data>
<data name="ERR_SpecialByRefInLambda" xml:space="preserve">
<value>Instance of type '{0}' cannot be used inside a nested function, query expression, iterator block or async method</value>
<value>Instance of type '{0}{1}' cannot be used inside a nested function, query expression, iterator block or async method</value>
</data>
<data name="ERR_SecurityAttributeMissingAction" xml:space="preserve">
<value>First argument to a security attribute must be a valid SecurityAction</value>
Expand Down Expand Up @@ -5290,12 +5284,6 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<data name="ERR_AnonDelegateCantUseLocal" xml:space="preserve">
<value>Cannot use ref local '{0}' inside an anonymous method, lambda expression, or query expression</value>
</data>
<data name="ERR_BadIteratorLocalType" xml:space="preserve">
<value>Iterators cannot have by-reference locals</value>
</data>
<data name="ERR_BadAsyncLocalType" xml:space="preserve">
<value>Async methods cannot have by-reference locals</value>
</data>
<data name="ERR_RefReturningCallAndAwait" xml:space="preserve">
<value>A reference returned by a call to '{0}' cannot be preserved across 'await' or 'yield' boundary.</value>
</data>
Expand Down Expand Up @@ -7851,9 +7839,6 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<data name="WRN_ConvertingLock_Title" xml:space="preserve">
<value>A value of type 'System.Threading.Lock' converted to a different type will use likely unintended monitor-based locking in 'lock' statement.</value>
</data>
<data name="ERR_BadSpecialByRefLock" xml:space="preserve">
<value>A lock statement on a value of type 'System.Threading.Lock' cannot be used in async methods or async lambda expressions.</value>
</data>
<data name="IDS_FeatureLockObject" xml:space="preserve">
<value>Lock object</value>
</data>
Expand Down Expand Up @@ -7905,4 +7890,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<data name="ERR_NoModifiersOnUsing" xml:space="preserve">
<value>Modifiers cannot be placed on using declarations</value>
</data>
<data name="IDS_FeatureRefUnsafeInIteratorAsync" xml:space="preserve">
<value>Ref and unsafe in async and iterator methods</value>
jjonescz marked this conversation as resolved.
Show resolved Hide resolved
</data>
</root>
12 changes: 6 additions & 6 deletions src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1111,7 +1111,7 @@ internal enum ErrorCode
ERR_NonTaskMainCantBeAsync = 4009,
ERR_CantConvAsyncAnonFuncReturns = 4010,
ERR_BadAwaiterPattern = 4011,
ERR_BadSpecialByRefLocal = 4012,
ERR_BadSpecialByRefParameter = 4012,
ERR_SpecialByRefInLambda = 4013,
WRN_UnobservedAwaitableExpression = 4014,
ERR_SynchronizedAsyncMethod = 4015,
Expand Down Expand Up @@ -1429,8 +1429,8 @@ internal enum ErrorCode
ERR_RefAssignmentMustHaveIdentityConversion = 8173,
ERR_ByReferenceVariableMustBeInitialized = 8174,
ERR_AnonDelegateCantUseLocal = 8175,
ERR_BadIteratorLocalType = 8176,
ERR_BadAsyncLocalType = 8177,
// ERR_BadIteratorLocalType = 8176,
// ERR_BadAsyncLocalType = 8177,
ERR_RefReturningCallAndAwait = 8178,
#endregion diagnostics for ref locals and ref returns introduced in C# 7

Expand Down Expand Up @@ -1529,7 +1529,7 @@ internal enum ErrorCode
ERR_AutoPropsInRoStruct = 8341,
ERR_FieldlikeEventsInRoStruct = 8342,
ERR_RefStructInterfaceImpl = 8343,
ERR_BadSpecialByRefIterator = 8344,
// ERR_BadSpecialByRefIterator = 8344,
ERR_FieldAutoPropCantBeByRefLike = 8345,
ERR_StackAllocConversionNotPossible = 8346,

Expand Down Expand Up @@ -2161,7 +2161,7 @@ internal enum ErrorCode
ERR_UnscopedRefAttributeUnsupportedMemberTarget = 9101,
ERR_UnscopedRefAttributeInterfaceImplementation = 9102,
ERR_UnrecognizedRefSafetyRulesAttributeVersion = 9103,
ERR_BadSpecialByRefUsing = 9104,
// ERR_BadSpecialByRefUsing = 9104,

ERR_InvalidPrimaryConstructorParameterReference = 9105,
ERR_AmbiguousPrimaryConstructorParameterAsColorColorReceiver = 9106,
Expand Down Expand Up @@ -2286,7 +2286,7 @@ internal enum ErrorCode
ERR_CollectionExpressionMissingAdd = 9215,

WRN_ConvertingLock = 9216,
ERR_BadSpecialByRefLock = 9217,
// ERR_BadSpecialByRefLock = 9217,
jjonescz marked this conversation as resolved.
Show resolved Hide resolved

ERR_CantInferMethTypeArgs_DynamicArgumentWithParamsCollections = 9218,
ERR_ParamsCollectionAmbiguousDynamicArgument = 9219,
Expand Down
7 changes: 1 addition & 6 deletions src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1533,7 +1533,7 @@ internal static bool IsBuildOnlyDiagnostic(ErrorCode code)
case ErrorCode.ERR_NonTaskMainCantBeAsync:
case ErrorCode.ERR_CantConvAsyncAnonFuncReturns:
case ErrorCode.ERR_BadAwaiterPattern:
case ErrorCode.ERR_BadSpecialByRefLocal:
case ErrorCode.ERR_BadSpecialByRefParameter:
case ErrorCode.WRN_UnobservedAwaitableExpression:
case ErrorCode.ERR_SynchronizedAsyncMethod:
case ErrorCode.ERR_BadAsyncReturnExpression:
Expand Down Expand Up @@ -1776,8 +1776,6 @@ internal static bool IsBuildOnlyDiagnostic(ErrorCode code)
case ErrorCode.ERR_RefAssignmentMustHaveIdentityConversion:
case ErrorCode.ERR_ByReferenceVariableMustBeInitialized:
case ErrorCode.ERR_AnonDelegateCantUseLocal:
case ErrorCode.ERR_BadIteratorLocalType:
case ErrorCode.ERR_BadAsyncLocalType:
case ErrorCode.ERR_PredefinedValueTupleTypeNotFound:
case ErrorCode.ERR_SemiOrLBraceOrArrowExpected:
case ErrorCode.ERR_NewWithTupleTypeSyntax:
Expand Down Expand Up @@ -1840,7 +1838,6 @@ internal static bool IsBuildOnlyDiagnostic(ErrorCode code)
case ErrorCode.ERR_AutoPropsInRoStruct:
case ErrorCode.ERR_FieldlikeEventsInRoStruct:
case ErrorCode.ERR_RefStructInterfaceImpl:
case ErrorCode.ERR_BadSpecialByRefIterator:
case ErrorCode.ERR_FieldAutoPropCantBeByRefLike:
case ErrorCode.ERR_StackAllocConversionNotPossible:
case ErrorCode.ERR_EscapeCall:
Expand Down Expand Up @@ -2329,7 +2326,6 @@ internal static bool IsBuildOnlyDiagnostic(ErrorCode code)
case ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget:
case ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation:
case ErrorCode.ERR_UnrecognizedRefSafetyRulesAttributeVersion:
case ErrorCode.ERR_BadSpecialByRefUsing:
case ErrorCode.ERR_InvalidPrimaryConstructorParameterReference:
case ErrorCode.ERR_AmbiguousPrimaryConstructorParameterAsColorColorReceiver:
case ErrorCode.WRN_CapturedPrimaryConstructorParameterPassedToBase:
Expand Down Expand Up @@ -2418,7 +2414,6 @@ internal static bool IsBuildOnlyDiagnostic(ErrorCode code)
case ErrorCode.ERR_CollectionExpressionMissingConstructor:
case ErrorCode.ERR_CollectionExpressionMissingAdd:
case ErrorCode.WRN_ConvertingLock:
case ErrorCode.ERR_BadSpecialByRefLock:
case ErrorCode.ERR_CantInferMethTypeArgs_DynamicArgumentWithParamsCollections:
case ErrorCode.ERR_ParamsCollectionAmbiguousDynamicArgument:
case ErrorCode.WRN_DynamicDispatchToParamsCollectionMethod:
Expand Down
3 changes: 3 additions & 0 deletions src/Compilers/CSharp/Portable/Errors/MessageID.cs
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,8 @@ internal enum MessageID
IDS_FeatureLockObject = MessageBase + 12841,

IDS_FeatureParamsCollections = MessageBase + 12842,

IDS_FeatureRefUnsafeInIteratorAsync = MessageBase + 12843,
}

// Message IDs may refer to strings that need to be localized.
Expand Down Expand Up @@ -466,6 +468,7 @@ internal static LanguageVersion RequiredVersion(this MessageID feature)
case MessageID.IDS_FeatureImplicitIndexerInitializer:
case MessageID.IDS_FeatureLockObject:
case MessageID.IDS_FeatureParamsCollections:
case MessageID.IDS_FeatureRefUnsafeInIteratorAsync:
return LanguageVersion.Preview;

// C# 12.0 features.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -697,7 +697,7 @@ private void AddDiagnosticIfRestrictedType(Symbol capturedVariable, SyntaxNode s

if (type.IsRestrictedType() == true)
{
_diagnostics.Add(ErrorCode.ERR_SpecialByRefInLambda, syntax.Location, type);
_diagnostics.Add(ErrorCode.ERR_SpecialByRefInLambda, syntax.Location, string.Empty, type);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ namespace Microsoft.CodeAnalysis.CSharp
/// </summary>
/// <remarks>
/// Data flow analysis is used to calculate the locals. At yield/await we mark all variables as "unassigned".
/// When a read from an unassigned variables is reported we add the variable to the captured set.
/// When a read from an unassigned variable is reported we add the variable to the captured set.
/// "this" parameter is captured if a reference to "this", "base" or an instance field is encountered.
/// Variables used in finally also need to be captured if there is a yield in the corresponding try block.
/// </remarks>
Expand Down Expand Up @@ -76,7 +76,6 @@ public static OrderedSet<Symbol> Analyze(CSharpCompilation compilation, MethodSy
foreach (var kvp in lazyDisallowedCaptures)
{
var variable = kvp.Key;
var type = (variable.Kind == SymbolKind.Local) ? ((LocalSymbol)variable).Type : ((ParameterSymbol)variable).Type;

if (variable is SynthesizedLocal local && local.SynthesizedKind == SynthesizedLocalKind.Spill)
{
Expand All @@ -85,10 +84,18 @@ public static OrderedSet<Symbol> Analyze(CSharpCompilation compilation, MethodSy
}
else
{
var (type, refKindPrefix) = variable switch
{
LocalSymbol l => (l.Type, l.RefKind.ToLocalPrefix()),
ParameterSymbol p => (p.Type, p.RefKind.ToParameterPrefix()),
_ => throw ExceptionUtilities.UnexpectedValue(variable),
};

foreach (CSharpSyntaxNode syntax in kvp.Value)
{
// CS4013: Instance of type '{0}' cannot be used inside an anonymous function, query expression, iterator block or async method
diagnostics.Add(ErrorCode.ERR_SpecialByRefInLambda, syntax.Location, type);
// PROTOTYPE: Improve error message (the instance might be usable in iterator/async just not across yield/await)
// CS4013: Instance of type '{0}{1}' cannot be used inside an anonymous function, query expression, iterator block or async method
jjonescz marked this conversation as resolved.
Show resolved Hide resolved
diagnostics.Add(ErrorCode.ERR_SpecialByRefInLambda, syntax.Location, refKindPrefix, type);
jjonescz marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
Expand Down Expand Up @@ -195,7 +202,7 @@ protected override ImmutableArray<PendingBranch> Scan(ref bool badRegion)
private void CaptureVariable(Symbol variable, SyntaxNode syntax)
{
var type = (variable.Kind == SymbolKind.Local) ? ((LocalSymbol)variable).Type : ((ParameterSymbol)variable).Type;
if (type.IsRestrictedType())
if (type.IsRestrictedType() || variable is LocalSymbol { RefKind: not RefKind.None, IsCompilerGenerated: false })
jjonescz marked this conversation as resolved.
Show resolved Hide resolved
jjonescz marked this conversation as resolved.
Show resolved Hide resolved
{
(_lazyDisallowedCaptures ??= new MultiDictionary<Symbol, SyntaxNode>()).Add(variable, syntax);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ internal void ReportAsyncParameterErrors(BindingDiagnosticBag diagnostics, Locat
}
else if (parameter.Type.IsRestrictedType())
{
diagnostics.Add(ErrorCode.ERR_BadSpecialByRefLocal, getLocation(parameter, location), parameter.Type);
diagnostics.Add(ErrorCode.ERR_BadSpecialByRefParameter, getLocation(parameter, location), parameter.Type);
}
}

Expand Down
Loading