Skip to content

Commit

Permalink
Permit selecting an instance from a type in a sub-expression in nameo…
Browse files Browse the repository at this point in the history
…f(...)

Fixes dotnet#20600
  • Loading branch information
gafter committed Feb 10, 2018
1 parent 5c9cd2a commit c3fd390
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 11 deletions.
2 changes: 2 additions & 0 deletions src/Compilers/CSharp/Portable/Binder/Binder.cs
Expand Up @@ -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;

/// <summary>
/// Get the next binder in which to look up a name, if not found by this binder.
/// </summary>
Expand Down
19 changes: 8 additions & 11 deletions src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs
Expand Up @@ -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())
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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;

Expand All @@ -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;
Expand All @@ -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)
Expand Down Expand Up @@ -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;
Expand Down
46 changes: 46 additions & 0 deletions src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs
Expand Up @@ -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<T>
{
public string Instance1 = null;
public static string Static1 = null;
public string Instance2 => string.Empty;
public static string Static2 => string.Empty;
void M()
{
_ = nameof(C<string>.Instance1);
_ = nameof(C<string>.Instance1.Length);
_ = nameof(C<string>.Static1);
_ = nameof(C<string>.Static1.Length);
_ = nameof(C<string>.Instance2);
_ = nameof(C<string>.Instance2.Length);
_ = nameof(C<string>.Static2);
_ = nameof(C<string>.Static2.Length);
}
}
").VerifyDiagnostics();
}
}
}

0 comments on commit c3fd390

Please sign in to comment.