Skip to content

Commit

Permalink
Static lambdas testing (dotnet#45715)
Browse files Browse the repository at this point in the history
  • Loading branch information
RikkiGibson authored Jul 9, 2020
1 parent b64dacf commit 621e320
Show file tree
Hide file tree
Showing 4 changed files with 1,402 additions and 82 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,71 @@ static void F()
Assert.Same(lambdaOperation, lambdaOperationSecondRequest);
}

[CompilerTrait(CompilerFeature.IOperation)]
[Fact]
public void IAnonymousFunctionExpression_StaticLambda()
{
string source = @"
using System;
class Program
{
static void Main(string[] args)
{
/*<bind>*/Action x = static () => F();/*</bind>*/
}
static void F()
{
}
}
";
string expectedOperationTree = @"
IVariableDeclarationGroupOperation (1 declarations) (OperationKind.VariableDeclarationGroup, Type: null, IsInvalid) (Syntax: 'Action x = ... () => F();')
IVariableDeclarationOperation (1 declarators) (OperationKind.VariableDeclaration, Type: null, IsInvalid) (Syntax: 'Action x = ... c () => F()')
Declarators:
IVariableDeclaratorOperation (Symbol: System.Action x) (OperationKind.VariableDeclarator, Type: null, IsInvalid) (Syntax: 'x = static () => F()')
Initializer:
IVariableInitializerOperation (OperationKind.VariableInitializer, Type: null, IsInvalid) (Syntax: '= static () => F()')
IDelegateCreationOperation (OperationKind.DelegateCreation, Type: System.Action, IsInvalid, IsImplicit) (Syntax: 'static () => F()')
Target:
IAnonymousFunctionOperation (Symbol: lambda expression) (OperationKind.AnonymousFunction, Type: null, IsInvalid) (Syntax: 'static () => F()')
IBlockOperation (2 statements) (OperationKind.Block, Type: null, IsImplicit) (Syntax: 'F()')
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null, IsImplicit) (Syntax: 'F()')
Expression:
IInvocationOperation (void Program.F()) (OperationKind.Invocation, Type: System.Void) (Syntax: 'F()')
Instance Receiver:
null
Arguments(0)
IReturnOperation (OperationKind.Return, Type: null, IsImplicit) (Syntax: 'F()')
ReturnedValue:
null
Initializer:
null
";
var expectedDiagnostics = new DiagnosticDescription[] {
// file.cs(8,30): error CS8652: The feature 'static anonymous function' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// /*<bind>*/Action x = static () => F();/*</bind>*/
Diagnostic(ErrorCode.ERR_FeatureInPreview, "static").WithArguments("static anonymous function").WithLocation(8, 30)
};

VerifyOperationTreeAndDiagnosticsForTest<LocalDeclarationStatementSyntax>(
source,
expectedOperationTree,
expectedDiagnostics
);

var compilation = CreateCompilationWithMscorlib40AndSystemCore(source);
var syntaxTree = compilation.SyntaxTrees[0];
var semanticModel = compilation.GetSemanticModel(syntaxTree);

var variableDeclaration = syntaxTree.GetRoot().DescendantNodes().OfType<LocalDeclarationStatementSyntax>().Single();
var lambdaSyntax = (LambdaExpressionSyntax)variableDeclaration.Declaration.Variables.Single().Initializer.Value;
var lambdaOperation = (IAnonymousFunctionOperation)semanticModel.GetOperation(lambdaSyntax);

Assert.True(lambdaOperation.Symbol.IsStatic);
}

[CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)]
[Fact]
public void LambdaFlow_01()
Expand Down
125 changes: 125 additions & 0 deletions src/Compilers/CSharp/Test/Semantic/FlowAnalysis/RegionAnalysisTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System;
using System.Linq;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Test.Extensions;
using Roslyn.Test.Utilities;
using Xunit;
Expand Down Expand Up @@ -5119,6 +5120,130 @@ void M()
Assert.Equal(1, flowAnalysis.VariablesDeclared.Count());
}

[Fact]
public void StaticLambda_01()
{
var source = @"
using System;
class C
{
static void Main()
{
int x = 42;
Action fn = static () => Console.Write(x);
fn();
}
}
";
var comp = CreateCompilation(source, parseOptions: TestOptions.RegularPreview);
comp.VerifyDiagnostics(
// (9,48): error CS8820: A static anonymous function cannot contain a reference to 'x'.
// Action fn = static () => Console.Write(x);
Diagnostic(ErrorCode.ERR_StaticAnonymousFunctionCannotCaptureVariable, "x").WithArguments("x").WithLocation(9, 48)
);

var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);

var root = tree.GetRoot();
var node = root.DescendantNodes().OfType<LambdaExpressionSyntax>().Single();

var flowAnalysis = model.AnalyzeDataFlow(node);

Assert.Equal("x", GetSymbolNamesJoined(flowAnalysis.ReadInside));
Assert.Null(GetSymbolNamesJoined(flowAnalysis.WrittenInside));
Assert.Null(GetSymbolNamesJoined(flowAnalysis.VariablesDeclared));
}

[Fact]
public void StaticLambda_02()
{
var source = @"
using System;
class C
{
static void Main()
{
int x = 42;
Action fn = static () =>
{
int y = x;
x = 43;
Console.Write(y);
};
fn();
}
}
";
var comp = CreateCompilation(source, parseOptions: TestOptions.RegularPreview);
comp.VerifyDiagnostics(
// (11,21): error CS8820: A static anonymous function cannot contain a reference to 'x'.
// int y = x;
Diagnostic(ErrorCode.ERR_StaticAnonymousFunctionCannotCaptureVariable, "x").WithArguments("x").WithLocation(11, 21),
// (12,13): error CS8820: A static anonymous function cannot contain a reference to 'x'.
// x = 43;
Diagnostic(ErrorCode.ERR_StaticAnonymousFunctionCannotCaptureVariable, "x").WithArguments("x").WithLocation(12, 13)
);

var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);

var root = tree.GetRoot();
var node = root.DescendantNodes().OfType<LambdaExpressionSyntax>().Single();

var flowAnalysis = model.AnalyzeDataFlow(node);

Assert.Equal("x, y", GetSymbolNamesJoined(flowAnalysis.ReadInside));
Assert.Equal("x, y", GetSymbolNamesJoined(flowAnalysis.WrittenInside));
Assert.Equal("y", GetSymbolNamesJoined(flowAnalysis.VariablesDeclared));
}

[Fact]
public void StaticLambda_03()
{
var source = @"
using System;
class C
{
public static int x = 42;
static void Main()
{
Action fn = static () =>
{
int y = x;
x = 43;
Console.Write(y);
};
fn();
}
}
";
verify(source);
verify(source.Replace("static (", "("));

void verify(string source)
{
var verifier = CompileAndVerify(source, parseOptions: TestOptions.RegularPreview, expectedOutput: "42");
verifier.VerifyDiagnostics();

var comp = verifier.Compilation;
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree);

var root = tree.GetRoot();
var node = root.DescendantNodes().OfType<LambdaExpressionSyntax>().Single();

var flowAnalysis = model.AnalyzeDataFlow(node);

Assert.Equal("y", GetSymbolNamesJoined(flowAnalysis.ReadInside));
Assert.Equal("y", GetSymbolNamesJoined(flowAnalysis.WrittenInside));
Assert.Equal("y", GetSymbolNamesJoined(flowAnalysis.VariablesDeclared));
}
}

#endregion

#region "query expressions"
Expand Down
Loading

0 comments on commit 621e320

Please sign in to comment.