Skip to content

Commit

Permalink
Misc.
Browse files Browse the repository at this point in the history
  • Loading branch information
cston committed May 19, 2022
1 parent 0055014 commit 405ce6a
Show file tree
Hide file tree
Showing 10 changed files with 265 additions and 34 deletions.
6 changes: 6 additions & 0 deletions src/Compilers/CSharp/Portable/CodeGen/Optimizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2267,5 +2267,11 @@ public override RefKind RefKind
/// Checking escape scopes is not valid here.
/// </summary>
internal override uint RefEscapeScope => throw ExceptionUtilities.Unreachable;

/// <summary>
/// Compiler should always be synthesizing locals with correct escape semantics.
/// Checking escape scopes is not valid here.
/// </summary>
internal override DeclarationScope Scope => throw ExceptionUtilities.Unreachable;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ public override bool Equals(Symbol obj, TypeCompareKind compareKind)
internal override LocalSymbol WithSynthesizedLocalKindAndSyntax(SynthesizedLocalKind kind, SyntaxNode syntax) => throw ExceptionUtilities.Unreachable;
internal override uint ValEscapeScope => throw ExceptionUtilities.Unreachable;
internal override uint RefEscapeScope => throw ExceptionUtilities.Unreachable;
internal override DeclarationScope Scope => throw ExceptionUtilities.Unreachable;
}
}
}
2 changes: 2 additions & 0 deletions src/Compilers/CSharp/Portable/Symbols/LocalSymbol.cs
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,8 @@ public sealed override SymbolKind Kind
}
}

internal abstract DeclarationScope Scope { get; }

internal sealed override TResult Accept<TArgument, TResult>(CSharpSymbolVisitor<TArgument, TResult> visitor, TArgument argument)
{
return visitor.VisitLocal(this, argument);
Expand Down
34 changes: 16 additions & 18 deletions src/Compilers/CSharp/Portable/Symbols/Source/SourceLocalSymbol.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ internal class SourceLocalSymbol : LocalSymbol
private readonly TypeSyntax _typeSyntax;
private readonly RefKind _refKind;
private readonly LocalDeclarationKind _declarationKind;
private readonly RefAndScope _refAndScope;
private readonly DeclarationScope _scope;

private TypeWithAnnotations.Boxed _type;

Expand Down Expand Up @@ -66,7 +66,7 @@ private SourceLocalSymbol(
this._identifierToken = identifierToken;
this._typeSyntax = allowRefKind ? typeSyntax?.SkipRef(out this._refKind) : typeSyntax;
this._declarationKind = declarationKind;
this._refAndScope = GetRefAndScope(scoped, _refKind, typeSyntax);
this._scope = GetScope(scoped, allowRefKind, _refKind, typeSyntax);

// create this eagerly as it will always be needed for the EnsureSingleDefinition
_locations = ImmutableArray.Create<Location>(identifierToken.GetLocation());
Expand All @@ -80,17 +80,22 @@ private SourceLocalSymbol(
_valEscapeScope = Binder.ExternalScope;
}

private static RefAndScope GetRefAndScope(bool scoped, RefKind refKind, TypeSyntax typeSyntax)
private static DeclarationScope GetScope(bool scoped, bool allowRefKind, RefKind refKind, TypeSyntax typeSyntax)
{
if (typeSyntax is RefTypeSyntax refTypeSyntax &&
refTypeSyntax.ScopedKeyword.Kind() == SyntaxKind.ScopedKeyword)
var result = DeclarationScope.None;
if (typeSyntax is RefTypeSyntax refTypeSyntax)
{
// Note that 'ref scoped' and 'scoped ref scoped' are equivalent.
return RefAndScope.RefScoped;
if (allowRefKind && scoped)
{
result |= DeclarationScope.RefScoped;
}
@scoped = (refTypeSyntax.ScopedKeyword.Kind() == SyntaxKind.ScopedKeyword);
}
if (scoped)
{
result |= DeclarationScope.ValueScoped;
}
return scoped ?
(refKind == RefKind.None ? RefAndScope.Scoped : RefAndScope.ScopedRef) :
(refKind == RefKind.None ? RefAndScope.None : RefAndScope.Ref);
return result;
}

/// <summary>
Expand All @@ -110,14 +115,7 @@ internal override SyntaxNode ScopeDesignatorOpt

internal override uint ValEscapeScope => _valEscapeScope;

private enum RefAndScope : byte
{
None,
Scoped,
Ref,
ScopedRef,
RefScoped,
}
internal sealed override DeclarationScope Scope => _scope;

/// <summary>
/// Binder that should be used to bind type syntax for the local.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,12 @@ internal sealed override bool IsCompilerGenerated
/// </summary>
internal sealed override uint RefEscapeScope => throw ExceptionUtilities.Unreachable;

/// <summary>
/// Compiler should always be synthesizing locals with correct escape semantics.
/// Checking escape scopes is not valid here.
/// </summary>
internal sealed override DeclarationScope Scope => throw ExceptionUtilities.Unreachable;

internal sealed override ConstantValue GetConstantValue(SyntaxNode node, LocalSymbol inProgress, BindingDiagnosticBag diagnostics)
{
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,12 @@ public override RefKind RefKind
/// </summary>
internal override uint RefEscapeScope => throw ExceptionUtilities.Unreachable;

/// <summary>
/// Compiler should always be synthesizing locals with correct escape semantics.
/// Checking escape scopes is not valid here.
/// </summary>
internal override DeclarationScope Scope => throw new System.NotImplementedException();

internal override ConstantValue GetConstantValue(SyntaxNode node, LocalSymbol inProgress, BindingDiagnosticBag diagnostics)
{
return _originalVariable.GetConstantValue(node, inProgress, diagnostics);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ public override bool Equals(Symbol other, TypeCompareKind compareKind)
internal override bool IsCompilerGenerated => _underlyingLocal.IsCompilerGenerated;
internal override uint RefEscapeScope => _underlyingLocal.RefEscapeScope;
internal override uint ValEscapeScope => _underlyingLocal.ValEscapeScope;
internal override DeclarationScope Scope => _underlyingLocal.Scope;
internal override ConstantValue GetConstantValue(SyntaxNode node, LocalSymbol inProgress, BindingDiagnosticBag? diagnostics = null) =>
_underlyingLocal.GetConstantValue(node, inProgress, diagnostics);
internal override ImmutableBindingDiagnostic<AssemblySymbol> GetConstantValueDiagnostics(BoundExpression boundInitValue) =>
Expand Down
71 changes: 70 additions & 1 deletion src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4308,6 +4308,75 @@ static unsafe void Main()
VerifyParameterSymbol(methods[1].Parameters[1], "scoped ref System.Int32", RefKind.Ref, DeclarationScope.RefScoped);
}

[Fact]
public void ParameterScope_07()
{
var source =
@"ref struct R { }
class Program
{
static void F1(scoped scoped R r) { }
static void F2(ref scoped scoped int i) { }
}";
var comp = CreateCompilation(source);
// PROTOTYPE: Should report duplicate modifiers.
comp.VerifyDiagnostics();
}

[Fact]
public void ParameterScope_08()
{
var source =
@"ref struct R { }
class Program
{
static void Main()
{
var f = (scoped scoped R r) => { };
}
}";
var comp = CreateCompilation(source);
// PROTOTYPE: Should report duplicate modifiers.
comp.VerifyDiagnostics();
}

[Fact]
public void ParameterScope_09()
{
var source =
@"class Program
{
static void Main()
{
var f = (ref scoped scoped int i) => { };
}
}";
var comp = CreateCompilation(source);
// The duplicated scoped modifier results in parse errors rather than a binding error.
comp.VerifyDiagnostics(
// (5,18): error CS1525: Invalid expression term 'ref'
// var f = (ref scoped scoped int i) => { };
Diagnostic(ErrorCode.ERR_InvalidExprTerm, "ref scoped").WithArguments("ref").WithLocation(5, 18),
// (5,18): error CS1073: Unexpected token 'ref'
// var f = (ref scoped scoped int i) => { };
Diagnostic(ErrorCode.ERR_UnexpectedToken, "ref").WithArguments("ref").WithLocation(5, 18),
// (5,29): error CS1026: ) expected
// var f = (ref scoped scoped int i) => { };
Diagnostic(ErrorCode.ERR_CloseParenExpected, "scoped").WithLocation(5, 29),
// (5,29): error CS1002: ; expected
// var f = (ref scoped scoped int i) => { };
Diagnostic(ErrorCode.ERR_SemicolonExpected, "scoped").WithLocation(5, 29),
// (5,40): warning CS0168: The variable 'i' is declared but never used
// var f = (ref scoped scoped int i) => { };
Diagnostic(ErrorCode.WRN_UnreferencedVar, "i").WithArguments("i").WithLocation(5, 40),
// (5,41): error CS1002: ; expected
// var f = (ref scoped scoped int i) => { };
Diagnostic(ErrorCode.ERR_SemicolonExpected, ")").WithLocation(5, 41),
// (5,41): error CS1513: } expected
// var f = (ref scoped scoped int i) => { };
Diagnostic(ErrorCode.ERR_RbraceExpected, ")").WithLocation(5, 41));
}

// PROTOTYPE: Report error for implicit conversion between delegate types that differ by 'scoped',
// and between function pointer types and methods that differ by 'scoped'.

Expand Down Expand Up @@ -4441,7 +4510,7 @@ static void Main()
private static void VerifyLocalSymbol(LocalSymbol local, RefKind expectedRefKind, DeclarationScope scope)
{
Assert.Equal(expectedRefKind, local.RefKind);
//Assert.Equal(scope, local.Scope); // PROTOTYPE: Enable
Assert.Equal(scope, local.Scope);
}

// PROTOTYPE: Test `const scoped int local = 0;`. Are there other invalid combinations of modifiers?
Expand Down
Loading

0 comments on commit 405ce6a

Please sign in to comment.