diff --git a/src/Compilers/CSharp/Portable/Binder/Binder.cs b/src/Compilers/CSharp/Portable/Binder/Binder.cs index 46c6af1a94164..732107a73a321 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder.cs @@ -73,6 +73,8 @@ internal bool IsEarlyAttributeBinder // Return the nearest enclosing node being bound as a nameof(...) argument, if any, or null if none. protected virtual SyntaxNode EnclosingNameofArgument => null; + private bool IsInsideNameof => this.EnclosingNameofArgument != null; + /// /// Get the next binder in which to look up a name, if not found by this binder. /// diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs index b66cb01e0c6e9..b5e1aa262b05d 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs @@ -343,8 +343,7 @@ protected BoundExpression BindExpressionAllowArgList(ExpressionSyntax node, Diag private void VerifyUnchecked(ExpressionSyntax node, DiagnosticBag diagnostics, BoundExpression expr) { - var isInsideNameof = this.EnclosingNameofArgument != null; - if (!expr.HasAnyErrors && !isInsideNameof) + if (!expr.HasAnyErrors && !IsInsideNameof) { TypeSymbol exprType = expr.Type; if ((object)exprType != null && exprType.IsUnsafe()) @@ -1191,7 +1190,7 @@ private BoundExpression BindDefaultExpression(DefaultExpressionSyntax node, Diag options |= LookupOptions.MustBeInvocableIfMember; } - if (!IsInMethodBody && this.EnclosingNameofArgument == null) + if (!IsInMethodBody && !IsInsideNameof) { Debug.Assert((options & LookupOptions.NamespacesOrTypesOnly) == 0); options |= LookupOptions.MustNotBeMethodTypeParameter; @@ -1418,9 +1417,8 @@ private bool IsBadLocalOrParameterCapture(Symbol symbol, TypeSymbol type, RefKin // Not expecting symbol from constructed method. Debug.Assert(!symbol.ContainingSymbol.Equals(containingMethod)); - var isInsideNameof = this.EnclosingNameofArgument != null; // Captured in a lambda. - return (containingMethod.MethodKind == MethodKind.AnonymousFunction || containingMethod.MethodKind == MethodKind.LocalFunction) && !isInsideNameof; // false in EE evaluation method + return (containingMethod.MethodKind == MethodKind.AnonymousFunction || containingMethod.MethodKind == MethodKind.LocalFunction) && !IsInsideNameof; // false in EE evaluation method } } return false; @@ -1530,7 +1528,7 @@ private BoundExpression BindNonMethod(SimpleNameSyntax node, Symbol symbol, Diag } } - var constantValueOpt = localSymbol.IsConst && this.EnclosingNameofArgument == null && !type.IsErrorType() + var constantValueOpt = localSymbol.IsConst && !IsInsideNameof && !type.IsErrorType() ? localSymbol.GetConstantValue(node, this.LocalInProgress, diagnostics) : null; return new BoundLocal(node, localSymbol, constantValueOpt, type, hasErrors: isError); } @@ -5979,7 +5977,7 @@ private static void CombineExtensionMethodArguments(BoundExpression receiver, An hasError = this.CheckInstanceOrStatic(node, receiver, fieldSymbol, ref resultKind, diagnostics); } - if (!hasError && fieldSymbol.IsFixed && EnclosingNameofArgument == null) + if (!hasError && fieldSymbol.IsFixed && !IsInsideNameof) { TypeSymbol receiverType = receiver.Type; @@ -5989,9 +5987,8 @@ private static void CombineExtensionMethodArguments(BoundExpression receiver, An if (!hasError) { var isFixedStatementExpression = SyntaxFacts.IsFixedStatementExpression(node); - var isInsideNameof = this.EnclosingNameofArgument != null; Symbol accessedLocalOrParameterOpt; - if (IsNonMoveableVariable(receiver, out accessedLocalOrParameterOpt) == isFixedStatementExpression && !isInsideNameof) + if (IsNonMoveableVariable(receiver, out accessedLocalOrParameterOpt) == isFixedStatementExpression && !IsInsideNameof) { Error(diagnostics, isFixedStatementExpression ? ErrorCode.ERR_FixedNotNeeded : ErrorCode.ERR_FixedBufferNotFixed, node); hasErrors = hasError = true; @@ -6006,7 +6003,7 @@ private static void CombineExtensionMethodArguments(BoundExpression receiver, An ConstantValue constantValueOpt = null; - if (fieldSymbol.IsConst && this.EnclosingNameofArgument == null) + if (fieldSymbol.IsConst && !IsInsideNameof) { constantValueOpt = fieldSymbol.GetConstantValue(this.ConstantFieldsInProgress, this.IsEarlyAttributeBinder); if (constantValueOpt == ConstantValue.Unset) @@ -6163,7 +6160,7 @@ private bool InEnumMemberInitializer() } else { - if (instanceReceiver == false && EnclosingNameofArgument != node) + if (instanceReceiver == false && !IsInsideNameof) { Error(diagnostics, ErrorCode.ERR_ObjectRequired, node, symbol); resultKind = LookupResultKind.StaticInstanceMismatch; diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs index 7dc665458f55e..83753f350cf71 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs @@ -1343,5 +1343,51 @@ private static void M(in string value) } }", expectedOutput: "Main"); } + + [Fact, WorkItem(20600, "https://github.com/dotnet/roslyn/issues/20600")] + public void PermitInstanceQualifiedFromType() + { + CreateStandardCompilation(@" +class C +{ + public string Instance1 = null; + public static string Static1 = null; + public string Instance2 => string.Empty; + public static string Static2 => string.Empty; + + void M() + { + _ = nameof(C.Instance1); + _ = nameof(C.Instance1.Length); + _ = nameof(C.Static1); + _ = nameof(C.Static1.Length); + _ = nameof(C.Instance2); + _ = nameof(C.Instance2.Length); + _ = nameof(C.Static2); + _ = nameof(C.Static2.Length); + } +} + +class C +{ + public string Instance1 = null; + public static string Static1 = null; + public string Instance2 => string.Empty; + public static string Static2 => string.Empty; + + void M() + { + _ = nameof(C.Instance1); + _ = nameof(C.Instance1.Length); + _ = nameof(C.Static1); + _ = nameof(C.Static1.Length); + _ = nameof(C.Instance2); + _ = nameof(C.Instance2.Length); + _ = nameof(C.Static2); + _ = nameof(C.Static2.Length); + } +} +").VerifyDiagnostics(); + } } }