Skip to content
67 changes: 50 additions & 17 deletions src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2075,19 +2075,18 @@ private BoundExpression SynthesizeReceiver(SyntaxNode node, Symbol member, Bindi
(currentType.IsInterface && (declaringType.IsObjectType() || currentType.AllInterfacesNoUseSiteDiagnostics.Contains(declaringType))))
{
bool hasErrors = false;
if (EnclosingNameofArgument != node)
if (!IsInsideNameof || (EnclosingNameofArgument != node && !IsFeatureAvailable(node, MessageID.IDS_FeatureInstanceMemberInNameof)))
{
DiagnosticInfo diagnosticInfoOpt = null;
if (InFieldInitializer && !currentType.IsScriptClass)
{
//can't access "this" in field initializers
Error(diagnostics, ErrorCode.ERR_FieldInitRefNonstatic, node, member);
hasErrors = true;
diagnosticInfoOpt = new CSDiagnosticInfo(ErrorCode.ERR_FieldInitRefNonstatic, member);
}
else if (InConstructorInitializer || InAttributeArgument)
{
//can't access "this" in constructor initializers or attribute arguments
Error(diagnostics, ErrorCode.ERR_ObjectRequired, node, member);
hasErrors = true;
diagnosticInfoOpt = new CSDiagnosticInfo(ErrorCode.ERR_ObjectRequired, member);
}
else
{
Expand All @@ -2099,12 +2098,24 @@ private BoundExpression SynthesizeReceiver(SyntaxNode node, Symbol member, Bindi
if (!locationIsInstanceMember)
{
// error CS0120: An object reference is required for the non-static field, method, or property '{0}'
Error(diagnostics, ErrorCode.ERR_ObjectRequired, node, member);
hasErrors = true;
diagnosticInfoOpt = new CSDiagnosticInfo(ErrorCode.ERR_ObjectRequired, member);
}
}

hasErrors = hasErrors || IsRefOrOutThisParameterCaptured(node, diagnostics);
diagnosticInfoOpt ??= GetDiagnosticIfRefOrOutThisParameterCaptured();
hasErrors = diagnosticInfoOpt is not null;

if (hasErrors)
{
if (IsInsideNameof)
{
CheckFeatureAvailability(node, MessageID.IDS_FeatureInstanceMemberInNameof, diagnostics);
}
else
{
Error(diagnostics, diagnosticInfoOpt, node);
}
}
}

return ThisReference(node, currentType, hasErrors, wasCompilerGenerated: true);
Expand Down Expand Up @@ -2276,20 +2287,35 @@ private BoundThisReference ThisReference(SyntaxNode node, NamedTypeSymbol thisTy
return new BoundThisReference(node, thisTypeOpt ?? CreateErrorType(), hasErrors) { WasCompilerGenerated = wasCompilerGenerated };
}

#nullable enable
private bool IsRefOrOutThisParameterCaptured(SyntaxNodeOrToken thisOrBaseToken, BindingDiagnosticBag diagnostics)
{
ParameterSymbol thisSymbol = this.ContainingMemberOrLambda.EnclosingThisSymbol();
// If there is no this parameter, then it is definitely not captured and
// any diagnostic would be cascading.
if ((object)thisSymbol != null && thisSymbol.ContainingSymbol != ContainingMemberOrLambda && thisSymbol.RefKind != RefKind.None)
if (GetDiagnosticIfRefOrOutThisParameterCaptured() is { } diagnosticInfo)
{
Error(diagnostics, ErrorCode.ERR_ThisStructNotInAnonMeth, thisOrBaseToken);
var location = thisOrBaseToken.GetLocation();
Debug.Assert(location is not null);
Error(diagnostics, diagnosticInfo, location);
return true;
}

return false;
}

private DiagnosticInfo? GetDiagnosticIfRefOrOutThisParameterCaptured()
{
Debug.Assert(this.ContainingMemberOrLambda is not null);
ParameterSymbol? thisSymbol = this.ContainingMemberOrLambda.EnclosingThisSymbol();
// If there is no this parameter, then it is definitely not captured and
// any diagnostic would be cascading.
if (thisSymbol is not null && thisSymbol.ContainingSymbol != ContainingMemberOrLambda && thisSymbol.RefKind != RefKind.None)
{
return new CSDiagnosticInfo(ErrorCode.ERR_ThisStructNotInAnonMeth);
}

return null;
}
#nullable disable

private BoundBaseReference BindBase(BaseExpressionSyntax node, BindingDiagnosticBag diagnostics)
{
bool hasErrors = false;
Expand Down Expand Up @@ -7714,10 +7740,17 @@ private bool CheckInstanceOrStatic(
{
if (instanceReceiver == true)
{
ErrorCode errorCode = this.Flags.Includes(BinderFlags.ObjectInitializerMember) ?
ErrorCode.ERR_StaticMemberInObjectInitializer :
ErrorCode.ERR_ObjectProhibited;
Error(diagnostics, errorCode, node, symbol);
if (!IsInsideNameof)
{
ErrorCode errorCode = this.Flags.Includes(BinderFlags.ObjectInitializerMember) ?
ErrorCode.ERR_StaticMemberInObjectInitializer :
ErrorCode.ERR_ObjectProhibited;
Error(diagnostics, errorCode, node, symbol);
}
else if (CheckFeatureAvailability(node, MessageID.IDS_FeatureInstanceMemberInNameof, diagnostics))
{
return false;
}
resultKind = LookupResultKind.StaticInstanceMismatch;
return true;
}
Expand Down
5 changes: 5 additions & 0 deletions src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2686,6 +2686,11 @@ protected AssemblySymbol GetForwardedToAssembly(string name, int arity, ref Name
}

#nullable enable
internal static bool IsFeatureAvailable(SyntaxNode syntax, MessageID feature)

@jcouv jcouv Mar 30, 2023

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we use the existing CSharpCompilationExtensions.IsFeatureEnabled(this CSharpCompilation, MessageID) instead of introducing a new helper? #Closed

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, thanks.

{
return ((CSharpParseOptions)syntax.SyntaxTree.Options).IsFeatureEnabled(feature);
}

internal static bool CheckFeatureAvailability(SyntaxNode syntax, MessageID feature, BindingDiagnosticBag diagnostics, Location? location = null)
{
return CheckFeatureAvailability(syntax, feature, diagnostics.DiagnosticBag, location);
Expand Down
3 changes: 3 additions & 0 deletions src/Compilers/CSharp/Portable/CSharpResources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -6817,6 +6817,9 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<data name="WRN_UnreadRecordParameter_Title" xml:space="preserve">
<value>Parameter is unread. Did you forget to use it to initialize the property with that name?</value>
</data>
<data name="IDS_FeatureInstanceMemberInNameof" xml:space="preserve">
<value>instance member in 'nameof'</value>
</data>
<data name="ERR_RecordAmbigCtor" xml:space="preserve">
<value>The primary constructor conflicts with the synthesized copy constructor.</value>
</data>
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 @@ -265,6 +265,8 @@ internal enum MessageID

IDS_FeaturePrimaryConstructors = MessageBase + 12833,
IDS_FeatureUsingTypeAlias = MessageBase + 12834,

IDS_FeatureInstanceMemberInNameof = MessageBase + 12835,
}

// Message IDs may refer to strings that need to be localized.
Expand Down Expand Up @@ -393,6 +395,7 @@ internal static LanguageVersion RequiredVersion(this MessageID feature)
case MessageID.IDS_FeatureLambdaParamsArray: // semantic check
case MessageID.IDS_FeaturePrimaryConstructors: // declaration table check
case MessageID.IDS_FeatureUsingTypeAlias: // semantic check
case MessageID.IDS_FeatureInstanceMemberInNameof: // semantic check
return LanguageVersion.Preview;

// C# 11.0 features.
Expand Down
5 changes: 5 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading