diff --git a/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs b/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs
index 216abf14dd7bea825f76ff936a5a7ae0e3bb9084..2d2e1e5c0ae0caeb696a90d69ec2afa0a629ad3d 100644
--- a/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs
+++ b/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs
@@ -8999,6 +8999,15 @@ internal class CSharpResources {
}
}
+ ///
+ /// Looks up a localized string similar to local functions.
+ ///
+ internal static string IDS_FeatureLocalFunctions {
+ get {
+ return ResourceManager.GetString("IDS_FeatureLocalFunctions", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to module as an attribute target specifier.
///
diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx
index aeabf8e8fc05d3c3bf6d5047049b621a7aff6de0..f7f823629115cbb4711ccf70d22f0fdc4de2489a 100644
--- a/src/Compilers/CSharp/Portable/CSharpResources.resx
+++ b/src/Compilers/CSharp/Portable/CSharpResources.resx
@@ -4599,6 +4599,9 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
await in catch blocks and finally blocks
+
+ local functions
+
A '{0}' character must be escaped (by doubling) in an interpolated string.
diff --git a/src/Compilers/CSharp/Portable/Errors/MessageID.cs b/src/Compilers/CSharp/Portable/Errors/MessageID.cs
index 04a7f1774a07ce370ea94ebc9426467e6642334f..b78459d9b60292d7b8b6dbd374a80f3dd73ae8f8 100644
--- a/src/Compilers/CSharp/Portable/Errors/MessageID.cs
+++ b/src/Compilers/CSharp/Portable/Errors/MessageID.cs
@@ -112,6 +112,7 @@ internal enum MessageID
IDS_OperationCausedStackOverflow = MessageBase + 12703,
IDS_AwaitInCatchAndFinally = MessageBase + 12704,
+ IDS_FeatureLocalFunctions = MessageBase + 12705,
}
// Message IDs may refer to strings that need to be localized.
@@ -149,6 +150,9 @@ internal static string RequiredFeature(this MessageID feature)
{
switch (feature)
{
+ case MessageID.IDS_FeatureLocalFunctions:
+ return "localFunctions";
+
default:
return null;
}
diff --git a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs
index 35857bea46a12f23cb9cf2694a2720e626b26b6c..1a43ac4ca8e62d77cca664a7bd5c94b4eff1d547 100644
--- a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs
+++ b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs
@@ -7938,8 +7938,9 @@ private StatementSyntax ParseLocalDeclarationStatement()
try
{
this.ParseDeclarationModifiers(mods);
+ var allowLocalFunctions = IsFeatureEnabled(MessageID.IDS_FeatureLocalFunctions);
LocalFunctionStatementSyntax localFunction;
- this.ParseDeclaration(out type, variables, true, mods.ToTokenList(), out localFunction);
+ this.ParseDeclaration(out type, variables, allowLocalFunctions, mods.ToTokenList(), out localFunction);
if (localFunction != null)
{
Debug.Assert(variables.Count == 0);
diff --git a/src/Compilers/CSharp/Test/Semantic/Diagnostics/DiagnosticAnalyzerTests.AllInOne.cs b/src/Compilers/CSharp/Test/Semantic/Diagnostics/DiagnosticAnalyzerTests.AllInOne.cs
index fe8bc0056aee53e1714d9a22b56a9fdcaac2dd9b..e8cc8c259e332c9b3f743d990c8a60394f94becf 100644
--- a/src/Compilers/CSharp/Test/Semantic/Diagnostics/DiagnosticAnalyzerTests.AllInOne.cs
+++ b/src/Compilers/CSharp/Test/Semantic/Diagnostics/DiagnosticAnalyzerTests.AllInOne.cs
@@ -26,7 +26,7 @@ public void DiagnosticAnalyzerAllInOne()
symbolKindsWithNoCodeBlocks.Add(SymbolKind.NamedType);
var analyzer = new CSharpTrackingDiagnosticAnalyzer();
- CreateCompilationWithMscorlib45(source, parseOptions: TestOptions.Regular).VerifyAnalyzerDiagnostics(new[] { analyzer });
+ CreateExperimentalCompilationWithMscorlib45(source).VerifyAnalyzerDiagnostics(new[] { analyzer });
analyzer.VerifyAllAnalyzerMembersWereCalled();
analyzer.VerifyAnalyzeSymbolCalledForAllSymbolKinds();
analyzer.VerifyAnalyzeNodeCalledForAllSyntaxKinds();
@@ -85,7 +85,7 @@ public class C
[WorkItem(759)]
public void AnalyzerDriverIsSafeAgainstAnalyzerExceptions()
{
- var compilation = CreateCompilationWithMscorlib45(TestResource.AllInOneCSharpCode, parseOptions: TestOptions.Regular);
+ var compilation = CreateExperimentalCompilationWithMscorlib45(TestResource.AllInOneCSharpCode);
ThrowingDiagnosticAnalyzer.VerifyAnalyzerEngineIsSafeAgainstExceptions(analyzer =>
compilation.GetAnalyzerDiagnostics(new[] { analyzer }, null, logAnalyzerExceptionAsDiagnostics: true));
}
@@ -99,7 +99,7 @@ public void AnalyzerOptionsArePassedToAllAnalyzers()
new[] { new TestAdditionalText("myfilepath", text) }.ToImmutableArray()
);
- var compilation = CreateCompilationWithMscorlib45(TestResource.AllInOneCSharpCode, parseOptions: TestOptions.Regular);
+ var compilation = CreateExperimentalCompilationWithMscorlib45(TestResource.AllInOneCSharpCode);
var analyzer = new OptionsDiagnosticAnalyzer(options);
compilation.GetAnalyzerDiagnostics(new[] { analyzer }, options);
analyzer.VerifyAnalyzerOptions();
diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/LocalFunctionTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/LocalFunctionTests.cs
index 516a761dc01bf10ba654be4ef709692acd54bd73..757317e786865566145f0d5ae192f06b5edd0bdb 100644
--- a/src/Compilers/CSharp/Test/Semantic/Semantics/LocalFunctionTests.cs
+++ b/src/Compilers/CSharp/Test/Semantic/Semantics/LocalFunctionTests.cs
@@ -7,6 +7,8 @@ namespace Microsoft.CodeAnalysis.CSharp.UnitTests
{
public class LocalFunctionTests : CSharpTestBase
{
+ private readonly CSharpParseOptions _parseOptions = TestOptions.Regular.WithFeatures(new SmallDictionary { { "localFunctions", "true" } });
+
[Fact]
public void EndToEnd()
{
@@ -25,7 +27,8 @@ void Local()
}
}
";
- var comp = CompileAndVerify(source, expectedOutput: @"
+ var comp = CreateCompilationWithMscorlib(source, options: TestOptions.ReleaseExe, parseOptions: _parseOptions);
+ var verify = CompileAndVerify(comp, expectedOutput: @"
Hello, world!
");
}
@@ -45,7 +48,8 @@ static void Main(string[] args)
}
}
";
- var comp = CompileAndVerify(source, expectedOutput: @"
+ var comp = CreateCompilationWithMscorlib(source, options: TestOptions.ReleaseExe, parseOptions: _parseOptions);
+ var verify = CompileAndVerify(comp, expectedOutput: @"
2
");
}
@@ -83,7 +87,8 @@ void NamedOptional(int x = 2)
}
}
";
- var comp = CompileAndVerify(source, expectedOutput: @"
+ var comp = CreateCompilationWithMscorlib(source, options: TestOptions.ReleaseExe, parseOptions: _parseOptions);
+ var verify = CompileAndVerify(comp, expectedOutput: @"
2
2
2
@@ -137,7 +142,8 @@ static void Main(string[] args)
}
}
";
- var comp = CompileAndVerify(source, expectedOutput: @"
+ var comp = CreateCompilationWithMscorlib(source, options: TestOptions.ReleaseExe, parseOptions: _parseOptions);
+ var verify = CompileAndVerify(comp, expectedOutput: @"
2
2
");
@@ -165,7 +171,8 @@ void Local2()
}
}
";
- var comp = CompileAndVerify(source, expectedOutput: @"
+ var comp = CreateCompilationWithMscorlib(source, options: TestOptions.ReleaseExe, parseOptions: _parseOptions);
+ var verify = CompileAndVerify(comp, expectedOutput: @"
2
2
");
@@ -196,7 +203,8 @@ static void Main(string[] args)
}
}
";
- var comp = CompileAndVerify(source, expectedOutput: @"
+ var comp = CreateCompilationWithMscorlib(source, options: TestOptions.ReleaseExe, parseOptions: _parseOptions);
+ var verify = CompileAndVerify(comp, expectedOutput: @"
1
2
");
@@ -234,7 +242,8 @@ static void Main(string[] args)
}
}
";
- var comp = CompileAndVerify(source, expectedOutput: @"
+ var comp = CreateCompilationWithMscorlib(source, options: TestOptions.ReleaseExe, parseOptions: _parseOptions);
+ var verify = CompileAndVerify(comp, expectedOutput: @"
6
");
}
@@ -267,7 +276,8 @@ static void Main(string[] args)
}
}
";
- var comp = CompileAndVerify(source, expectedOutput: @"
+ var comp = CreateCompilationWithMscorlib(source, options: TestOptions.ReleaseExe, parseOptions: _parseOptions);
+ var verify = CompileAndVerify(comp, expectedOutput: @"
2
");
}
@@ -296,7 +306,8 @@ void Foo(int depth)
}
}
";
- var comp = CompileAndVerify(source, expectedOutput: @"
+ var comp = CreateCompilationWithMscorlib(source, options: TestOptions.ReleaseExe, parseOptions: _parseOptions);
+ var verify = CompileAndVerify(comp, expectedOutput: @"
2
");
}
@@ -328,7 +339,8 @@ void Bar(int depth2)
}
}
";
- var comp = CompileAndVerify(source, expectedOutput: @"
+ var comp = CreateCompilationWithMscorlib(source, options: TestOptions.ReleaseExe, parseOptions: _parseOptions);
+ var verify = CompileAndVerify(comp, expectedOutput: @"
2
");
}
@@ -368,7 +380,8 @@ IEnumerator LocalEnumerator()
}
}
";
- var comp = CompileAndVerify(source, expectedOutput: @"
+ var comp = CreateCompilationWithMscorlib(source, options: TestOptions.ReleaseExe, parseOptions: _parseOptions);
+ var verify = CompileAndVerify(comp, expectedOutput: @"
2
2
2
@@ -395,7 +408,9 @@ async Task Local()
}
}
";
- var compilation = CreateCompilationWithMscorlib45(source, options: new CSharpCompilationOptions(OutputKind.ConsoleApplication));
+ var compilation = CreateCompilationWithMscorlib45(source,
+ options: new CSharpCompilationOptions(OutputKind.ConsoleApplication),
+ parseOptions: _parseOptions);
var comp = CompileAndVerify(compilation, expectedOutput: @"
2
");
@@ -421,7 +436,9 @@ async Task Local(int x)
}
}
";
- var compilation = CreateCompilationWithMscorlib45(source, options: new CSharpCompilationOptions(OutputKind.ConsoleApplication));
+ var compilation = CreateCompilationWithMscorlib45(source,
+ options: new CSharpCompilationOptions(OutputKind.ConsoleApplication),
+ parseOptions: _parseOptions);
var comp = CompileAndVerify(compilation, expectedOutput: @"
2
");
@@ -480,7 +497,8 @@ static void Main(string[] args)
}
}
";
- var comp = CompileAndVerify(source, expectedOutput: @"
+ var comp = CreateCompilationWithMscorlib(source, options: TestOptions.ReleaseExe, parseOptions: _parseOptions);
+ var verify = CompileAndVerify(comp, expectedOutput: @"
2
");
}
@@ -509,7 +527,8 @@ void Local()
}
}
";
- var comp = CompileAndVerify(source, expectedOutput: @"
+ var comp = CreateCompilationWithMscorlib(source, options: TestOptions.ReleaseExe, parseOptions: _parseOptions);
+ var verify = CompileAndVerify(comp, expectedOutput: @"
2
");
}
@@ -531,7 +550,7 @@ void Local1()
}
";
var option = TestOptions.ReleaseExe.WithWarningLevel(0);
- CreateCompilationWithMscorlibAndSystemCore(source, options: option).VerifyDiagnostics(
+ CreateCompilationWithMscorlibAndSystemCore(source, options: option, parseOptions: _parseOptions).VerifyDiagnostics(
// (9,22): error CS1002: ; expected
// void Local1()
Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(9, 22),
@@ -565,7 +584,7 @@ IEnumerable Local(ref int x)
}
";
var option = TestOptions.ReleaseExe.WithWarningLevel(0);
- CreateCompilationWithMscorlibAndSystemCore(source, options: option).VerifyDiagnostics(
+ CreateCompilationWithMscorlibAndSystemCore(source, options: option, parseOptions: _parseOptions).VerifyDiagnostics(
// (9,40): error CS1623: Iterators cannot have ref or out parameters
// IEnumerable Local(ref int x)
Diagnostic(ErrorCode.ERR_BadIteratorArgType, "x").WithLocation(9, 40)
@@ -592,7 +611,7 @@ IEnumerable Local(__arglist)
}
";
var option = TestOptions.ReleaseExe.WithWarningLevel(0);
- CreateCompilationWithMscorlibAndSystemCore(source, options: option).VerifyDiagnostics(
+ CreateCompilationWithMscorlibAndSystemCore(source, options: option, parseOptions: _parseOptions).VerifyDiagnostics(
// (9,26): error CS1636: __arglist is not allowed in the parameter list of iterators
// IEnumerable Local(__arglist)
Diagnostic(ErrorCode.ERR_VarargsIterator, "Local").WithLocation(9, 26)
@@ -616,7 +635,7 @@ static void Main(string[] args)
}
";
var option = TestOptions.ReleaseExe.WithWarningLevel(0);
- CreateCompilationWithMscorlibAndSystemCore(source, options: option).VerifyDiagnostics(
+ CreateCompilationWithMscorlibAndSystemCore(source, options: option, parseOptions: _parseOptions).VerifyDiagnostics(
// (9,27): error CS0841: Cannot use local variable 'Local' before it is declared
// Console.WriteLine(Local());
Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "Local").WithArguments("Local").WithLocation(9, 27)
diff --git a/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxAnnotationTests.cs b/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxAnnotationTests.cs
index 4e07d6fb4b63ed2131303421ea92f586799a9a6a..342a3de8918ac8ca364696327fcdb4447e8e16ed 100644
--- a/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxAnnotationTests.cs
+++ b/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxAnnotationTests.cs
@@ -125,7 +125,7 @@ public void TestCopyAnnotationOfZeroLengthToSyntaxTrivia()
public void TestMissingAnnotationsOnNodesOrTokens()
{
SyntaxAnnotation annotation = new SyntaxAnnotation();
- var tree = SyntaxFactory.ParseSyntaxTree(_allInOneCSharpCode, options: Test.Utilities.TestOptions.Regular);
+ var tree = SyntaxFactory.ParseSyntaxTree(_allInOneCSharpCode, options: Test.Utilities.TestOptions.ExperimentalParseOptions);
var matchingNodesOrTokens = tree.GetCompilationUnitRoot().GetAnnotatedNodesAndTokens(annotation);
Assert.Empty(matchingNodesOrTokens);
@@ -135,7 +135,7 @@ public void TestMissingAnnotationsOnNodesOrTokens()
public void TestMissingAnnotationsOnTrivia()
{
SyntaxAnnotation annotation = new SyntaxAnnotation();
- var tree = SyntaxFactory.ParseSyntaxTree(_allInOneCSharpCode, options: Test.Utilities.TestOptions.Regular);
+ var tree = SyntaxFactory.ParseSyntaxTree(_allInOneCSharpCode, options: Test.Utilities.TestOptions.ExperimentalParseOptions);
var matchingTrivia = tree.GetCompilationUnitRoot().GetAnnotatedTrivia(annotation);
Assert.Empty(matchingTrivia);
@@ -298,7 +298,7 @@ public void TestIfNodeHasAnnotations()
[Fact]
public void TestCSharpAllInOne()
{
- var tree = SyntaxFactory.ParseSyntaxTree(_allInOneCSharpCode, options: Test.Utilities.TestOptions.Regular);
+ var tree = SyntaxFactory.ParseSyntaxTree(_allInOneCSharpCode, options: Test.Utilities.TestOptions.ExperimentalParseOptions);
TestAnnotation(tree);
}
@@ -306,7 +306,7 @@ public void TestCSharpAllInOne()
[Fact]
public void TestCSharpAllInOneRandom()
{
- var tree = SyntaxFactory.ParseSyntaxTree(_allInOneCSharpCode, options: Test.Utilities.TestOptions.Regular);
+ var tree = SyntaxFactory.ParseSyntaxTree(_allInOneCSharpCode, options: Test.Utilities.TestOptions.ExperimentalParseOptions);
TestRandomAnnotations(tree);
}
@@ -314,7 +314,7 @@ public void TestCSharpAllInOneRandom()
[Fact]
public void TestCSharpAllInOneManyRandom()
{
- var tree = SyntaxFactory.ParseSyntaxTree(_allInOneCSharpCode, options: Test.Utilities.TestOptions.Regular);
+ var tree = SyntaxFactory.ParseSyntaxTree(_allInOneCSharpCode, options: Test.Utilities.TestOptions.ExperimentalParseOptions);
TestManyRandomAnnotations(tree);
}
@@ -322,7 +322,7 @@ public void TestCSharpAllInOneManyRandom()
[Fact]
public void TestCSharpAllInOneTrivia()
{
- var tree = SyntaxFactory.ParseSyntaxTree(_allInOneCSharpCode, options: Test.Utilities.TestOptions.Regular);
+ var tree = SyntaxFactory.ParseSyntaxTree(_allInOneCSharpCode, options: Test.Utilities.TestOptions.ExperimentalParseOptions);
TestTriviaAnnotation(tree);
}
@@ -330,8 +330,8 @@ public void TestCSharpAllInOneTrivia()
[Fact]
public void TestCopyAnnotations1()
{
- var tree1 = SyntaxFactory.ParseSyntaxTree(_allInOneCSharpCode, options: Test.Utilities.TestOptions.Regular);
- var tree2 = SyntaxFactory.ParseSyntaxTree(_allInOneCSharpCode, options: Test.Utilities.TestOptions.Regular);
+ var tree1 = SyntaxFactory.ParseSyntaxTree(_allInOneCSharpCode, options: Test.Utilities.TestOptions.ExperimentalParseOptions);
+ var tree2 = SyntaxFactory.ParseSyntaxTree(_allInOneCSharpCode, options: Test.Utilities.TestOptions.ExperimentalParseOptions);
TestCopyAnnotations(tree1, tree2);
}
diff --git a/src/Compilers/Test/Utilities/CSharp/TestOptions.cs b/src/Compilers/Test/Utilities/CSharp/TestOptions.cs
index c5e5ddefdbcade5af5fa6f6339889ff57d9b5d74..e80722fef6f5874352859839d68751fafdeb5cb4 100644
--- a/src/Compilers/Test/Utilities/CSharp/TestOptions.cs
+++ b/src/Compilers/Test/Utilities/CSharp/TestOptions.cs
@@ -15,7 +15,7 @@ public static class TestOptions
public static readonly CSharpParseOptions Regular = new CSharpParseOptions(kind: SourceCodeKind.Regular, documentationMode: DocumentationMode.None);
public static readonly CSharpParseOptions RegularWithDocumentationComments = new CSharpParseOptions(kind: SourceCodeKind.Regular, documentationMode: DocumentationMode.Diagnose);
- private static readonly SmallDictionary s_experimentalFeatures = new SmallDictionary(); // no experimental features to enable
+ private static readonly SmallDictionary s_experimentalFeatures = new SmallDictionary { { "localFunctions", "true" } };
public static readonly CSharpParseOptions ExperimentalParseOptions =
new CSharpParseOptions(kind: SourceCodeKind.Regular, documentationMode: DocumentationMode.None, languageVersion: LanguageVersion.CSharp6).WithFeatures(s_experimentalFeatures);
diff --git a/src/Test/Utilities/TestResource.Designer.cs b/src/Test/Utilities/TestResource.Designer.cs
index 821bf5815bc4caa2784d09560c223e4c09fd4a32..4fa573a8b42bf6becf047c41d0aaa321ff6a6d2c 100644
--- a/src/Test/Utilities/TestResource.Designer.cs
+++ b/src/Test/Utilities/TestResource.Designer.cs
@@ -1,7 +1,7 @@
//------------------------------------------------------------------------------
//
// This code was generated by a tool.
-// Runtime Version:4.0.30319.0
+// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
diff --git a/src/Test/Utilities/TestResource.resx b/src/Test/Utilities/TestResource.resx
index 92b03dc304162fbc3d12c70105a5641d2db7d3fa..2f9550e2e8f1de0c3b7e017c2f1fc451e3f70777 100644
--- a/src/Test/Utilities/TestResource.resx
+++ b/src/Test/Utilities/TestResource.resx
@@ -196,6 +196,10 @@ namespace My
var s2 = $@"x {1 , -2 :d}";
}
+ int LocalFunction()
+ {
+ }
+
#if DEBUG
Console.WriteLine(export.iefSupplied.command);
#endif