提交 1fad593c 编写于 作者: J Jared Parsons

Merge pull request #10887 from jaredpar/localfunc-test

Local function testing: var and async
# Interaction with other language features:
General concerns:
- [ ] Error handling/recovery
- [ ] Errors in parsing
- [ ] Error handling for semantic errors (e.g. ambiguous lookup, inaccessible lookup, wrong kind of thing found, instance vs static thing found, wrong type for the context, value vs variable)
- [ ] Public interface of compiler APIs, backcompat scenarios
- [ ] Determinism
- [ ] Atomicity
- [ ] Edit-and-continue
- [ ] Completeness of the specification as a guide for testing (e.g. is the spec complete enough to suggest what the compiler should do in each scenario?)
- [ ] Other external documentation
- [ ] Performance
Types and members:
- [ ] Access modifiers (public, protected, internal, protected internal, private), static modifier
- [ ] Parameter modifiers (ref, out, params)
- [ ] Attributes (including security attribute)
- [ ] Generics (type arguments, constraints, variance)
- [ ] default value
- [ ] partial classes
- [ ] literals
- [ ] enum (implicit vs. explicit underlying type)
- [ ] expression trees
- [ ] Iterators
- [ ] Initializers (object, collection, dictionary)
- [ ] array (single- or multi-dimensional, jagged, initilalizer)
- [ ] Expression-bodied methods/properties/...
- [ ] Extension methods
- [ ] Partial method
- [ ] Named and optional parameters
- [ ] String interpolation
- [ ] Properties (read-write, read-only, write-only, auto-property, expression-bodied)
- [ ] Interfaces (implicit vs. explicit interface member implementation)
- [ ] delegates
- [ ] Multi-declaration
Code:
- [ ] Operators (see Eric's list)
- [ ] Operator overloading
- [ ] Lvalues: the synthesized fields are mutable
- [ ] Ref / out parameters
- [ ] Compound operators (+=, /=, etc ..)
- [ ] Assignment exprs
- [ ] lambdas (capture of parameters or locals, target typing)
- [ ] execution order
- [ ] Target typing (var, lambdas, integrals)
- [ ] Type inference
- [ ] Conversions
- [ ] Implicit (identity, implicit numeric, implicit enumeration, implicit nullable, null litaral, implicit reference, boxing, implicit dynamic, implicit constant, user-defined implicit conversion, anonymous function, method group)
- [ ] Explicit (numeric, enumeration, nullable, reference, unboxing, dynamic, user-defined)
- [ ] Anonymous functions
- [ ] nullable (wrapping, unwrapping)
- [ ] OHI
- [ ] inheritance (virtual, override, abstract, new)
- [ ] overload resolution
- [ ] Anonymous types
- [ ] Unsafe code
- [ ] LINQ
- [ ] constructors, properties, indexers, events, operators, and destructors.
- [X] Async
- [X] Var
Misc:
- [ ] reserved keywords (sometimes contextual)
- [ ] pre-processing directives
- [ ] COM interop
......@@ -9,7 +9,7 @@
namespace Microsoft.CodeAnalysis.CSharp.UnitTests
{
public static class LocalFunctionTestsExt
public static class LocalFunctionTestsUtil
{
public static IMethodSymbol FindLocalFunction(this CommonTestBase.CompilationVerifier verifier, string localFunctionName)
{
......@@ -29,24 +29,23 @@ public static IMethodSymbol FindLocalFunction(this CommonTestBase.CompilationVer
}
}
[CompilerTrait(CompilerFeature.LocalFunctions)]
public class LocalFunctionTests : CSharpTestBase
public class LocalFunctionsTestBase : CSharpTestBase
{
private readonly CSharpParseOptions _parseOptions = TestOptions.Regular.WithLocalFunctionsFeature();
internal static readonly CSharpParseOptions DefaultParseOptions = TestOptions.Regular.WithLocalFunctionsFeature();
CompilationVerifier VerifyOutput(string source, string output, CSharpCompilationOptions options)
internal CompilationVerifier VerifyOutput(string source, string output, CSharpCompilationOptions options)
{
var comp = CreateCompilationWithMscorlib45AndCSruntime(source, options: options, parseOptions: _parseOptions);
var comp = CreateCompilationWithMscorlib45AndCSruntime(source, options: options, parseOptions: DefaultParseOptions);
return CompileAndVerify(comp, expectedOutput: output).VerifyDiagnostics(); // no diagnostics
}
CompilationVerifier VerifyOutput(string source, string output)
internal CompilationVerifier VerifyOutput(string source, string output)
{
var comp = CreateCompilationWithMscorlib45AndCSruntime(source, options: TestOptions.ReleaseExe, parseOptions: _parseOptions);
var comp = CreateCompilationWithMscorlib45AndCSruntime(source, options: TestOptions.ReleaseExe, parseOptions: DefaultParseOptions);
return CompileAndVerify(comp, expectedOutput: output).VerifyDiagnostics(); // no diagnostics
}
CompilationVerifier VerifyOutputInMain(string methodBody, string output, params string[] usings)
internal CompilationVerifier VerifyOutputInMain(string methodBody, string output, params string[] usings)
{
for (var i = 0; i < usings.Length; i++)
{
......@@ -64,18 +63,22 @@ static void Main()
return VerifyOutput(source, output);
}
private void VerifyDiagnostics(string source, params DiagnosticDescription[] expected)
internal void VerifyDiagnostics(string source, params DiagnosticDescription[] expected)
{
var comp = CreateCompilationWithMscorlib45AndCSruntime(source, options: TestOptions.ReleaseExe, parseOptions: _parseOptions);
var comp = CreateCompilationWithMscorlib45AndCSruntime(source, options: TestOptions.ReleaseExe, parseOptions: DefaultParseOptions);
comp.VerifyDiagnostics(expected);
}
private void VerifyDiagnostics(string source, CSharpCompilationOptions options, params DiagnosticDescription[] expected)
internal void VerifyDiagnostics(string source, CSharpCompilationOptions options, params DiagnosticDescription[] expected)
{
var comp = CreateCompilationWithMscorlib45AndCSruntime(source, options: options, parseOptions: _parseOptions);
var comp = CreateCompilationWithMscorlib45AndCSruntime(source, options: options, parseOptions: DefaultParseOptions);
comp.VerifyDiagnostics(expected);
}
}
[CompilerTrait(CompilerFeature.LocalFunctions)]
public class LocalFunctionTests : LocalFunctionsTestBase
{
[Fact]
public void EndToEnd()
{
......@@ -1325,193 +1328,6 @@ IEnumerator LocalEnumerator()
VerifyOutputInMain(source, "2", "System", "System.Collections");
}
[Fact]
[CompilerTrait(CompilerFeature.Async)]
public void AsyncBasic()
{
var source = @"
async Task<int> Local()
{
return await Task.FromResult(2);
}
Console.Write(Local().Result);
";
VerifyOutputInMain(source, "2", "System", "System.Threading.Tasks");
}
[Fact]
public void AsyncParam()
{
var source = @"
async Task<int> LocalParam(int x)
{
return await Task.FromResult(x);
}
Console.Write(LocalParam(2).Result);
";
VerifyOutputInMain(source, "2", "System", "System.Threading.Tasks");
}
[Fact]
[CompilerTrait(CompilerFeature.Async)]
public void AsyncGeneric()
{
var source = @"
async Task<T> LocalGeneric<T>(T x)
{
return await Task.FromResult(x);
}
Console.Write(LocalGeneric(2).Result);
";
VerifyOutputInMain(source, "2", "System", "System.Threading.Tasks");
}
[Fact]
[CompilerTrait(CompilerFeature.Async)]
public void AsyncVoid()
{
var source = @"
// had bug with parser where 'async [keyword]' didn't parse.
async void LocalVoid()
{
Console.Write(2);
await Task.Yield();
}
LocalVoid();
";
VerifyOutputInMain(source, "2", "System", "System.Threading.Tasks");
}
[Fact]
[CompilerTrait(CompilerFeature.Async)]
public void AsyncAwaitAwait()
{
var source = @"
Task<int> Fun(int x)
{
return Task.FromResult(x);
}
async Task<int> AwaitAwait()
{
var a = Fun(2);
await Fun(await a);
return await Fun(await a);
}
Console.WriteLine(AwaitAwait().Result);
";
VerifyOutputInMain(source, "2", "System", "System.Threading.Tasks");
}
[Fact]
[CompilerTrait(CompilerFeature.Async)]
public void AsyncKeyword()
{
var source = @"
using System;
struct async
{
public override string ToString() => ""2"";
}
struct await
{
public override string ToString() => ""2"";
}
class Program
{
static string A()
{
async async()
{
return new async();
}
return async().ToString();
}
static string B()
{
string async()
{
return ""2"";
}
return async();
}
static string C()
{
async Foo()
{
return new async();
}
return Foo().ToString();
}
static string D()
{
await Fun(await x)
{
return x;
}
return Fun(new await()).ToString();
}
static void Main(string[] args)
{
Console.WriteLine(A());
Console.WriteLine(B());
Console.WriteLine(C());
Console.WriteLine(D());
}
}
";
var output = @"
2
2
2
2
";
VerifyOutput(source, output);
}
[Fact]
[CompilerTrait(CompilerFeature.Async)]
public void AsyncUnsafeKeyword()
{
var source = @"
using System;
using System.Threading.Tasks;
class Program
{
static string A()
{
async unsafe Task<int> async()
{
return 2;
}
return async().Result.ToString();
}
static string B()
{
unsafe async Task<int> async()
{
return 2;
}
return async().Result.ToString();
}
static void Main(string[] args)
{
Console.WriteLine(A());
Console.WriteLine(B());
}
}
";
var output = @"
2
2
";
VerifyOutput(source, output, TestOptions.ReleaseExe.WithAllowUnsafe(true).WithWarningLevel(0));
}
[Fact]
public void Generic()
{
......@@ -3733,5 +3549,390 @@ static void Main(string[] args)
Diagnostic(ErrorCode.ERR_BadEmbeddedStmt, "int Add(int x, int y) => x + y;").WithLocation(7, 9)
);
}
[CompilerTrait(CompilerFeature.LocalFunctions, CompilerFeature.Var)]
public sealed class VarTests : LocalFunctionsTestBase
{
[Fact]
public void IllegalAsReturn()
{
var source = @"
using System;
class Program
{
static void Main()
{
var f() => 42;
Console.WriteLine(f());
}
}";
var comp = CreateCompilationWithMscorlib45(source, parseOptions: DefaultParseOptions);
comp.VerifyDiagnostics(
// (7,9): error CS0825: The contextual keyword 'var' may only appear within a local variable declaration or in script code
// var f() => 42;
Diagnostic(ErrorCode.ERR_TypeVarNotFound, "var").WithLocation(7, 9));
}
[Fact]
public void RealTypeAsReturn()
{
var source = @"
using System;
class var
{
public override string ToString() => ""dog"";
}
class Program
{
static void Main()
{
var f() => new var();
Console.WriteLine(f());
}
}";
CompileAndVerify(
source,
parseOptions: DefaultParseOptions,
expectedOutput: "dog");
}
[Fact]
public void RealTypeParameterAsReturn()
{
var source = @"
using System;
class test
{
public override string ToString() => ""dog"";
}
class Program
{
static void Test<var>(var x)
{
var f() => x;
Console.WriteLine(f());
}
static void Main()
{
Test(new test());
}
}";
CompileAndVerify(
source,
parseOptions: DefaultParseOptions,
expectedOutput: "dog");
}
[Fact]
public void IdentifierAndTypeNamedVar()
{
var source = @"
using System;
class var
{
public override string ToString() => ""dog"";
}
class Program
{
static void Main()
{
int var = 42;
var f() => new var();
Console.WriteLine($""{f()}-{var}"");
}
}";
CompileAndVerify(
source,
parseOptions: DefaultParseOptions,
expectedOutput: "dog-42");
}
}
[CompilerTrait(CompilerFeature.LocalFunctions, CompilerFeature.Async)]
public sealed class AsyncTests : LocalFunctionsTestBase
{
[Fact]
public void RealTypeAsReturn()
{
var source = @"
using System;
class async
{
public override string ToString() => ""dog"";
}
class Program
{
static void Main()
{
async f() => new async();
Console.WriteLine(f());
}
}";
CompileAndVerify(
source,
parseOptions: DefaultParseOptions,
expectedOutput: "dog");
}
[Fact]
public void RealTypeParameterAsReturn()
{
var source = @"
using System;
class test
{
public override string ToString() => ""dog"";
}
class Program
{
static void Test<async>(async x)
{
async f() => x;
Console.WriteLine(f());
}
static void Main()
{
Test(new test());
}
}";
CompileAndVerify(
source,
parseOptions: DefaultParseOptions,
expectedOutput: "dog");
}
[Fact]
public void ManyMeaningsType()
{
var source = @"
using System;
using System.Threading;
using System.Threading.Tasks;
class async
{
public override string ToString() => ""async"";
}
class Program
{
static void Main()
{
async Task<async> Test(Task<async> t)
{
async local = await t;
Console.WriteLine(local);
return local;
}
Test(Task.FromResult<async>(new async())).Wait();
}
}";
var comp = CreateCompilationWithMscorlib46(source, parseOptions: DefaultParseOptions, options: TestOptions.DebugExe);
CompileAndVerify(
comp,
expectedOutput: "async");
}
[Fact]
public void Basic()
{
var source = @"
async Task<int> Local()
{
return await Task.FromResult(2);
}
Console.Write(Local().Result);
";
VerifyOutputInMain(source, "2", "System", "System.Threading.Tasks");
}
[Fact]
public void Param()
{
var source = @"
async Task<int> LocalParam(int x)
{
return await Task.FromResult(x);
}
Console.Write(LocalParam(2).Result);
";
VerifyOutputInMain(source, "2", "System", "System.Threading.Tasks");
}
[Fact]
[CompilerTrait(CompilerFeature.Async)]
public void Generic()
{
var source = @"
async Task<T> LocalGeneric<T>(T x)
{
return await Task.FromResult(x);
}
Console.Write(LocalGeneric(2).Result);
";
VerifyOutputInMain(source, "2", "System", "System.Threading.Tasks");
}
[Fact]
[CompilerTrait(CompilerFeature.Async)]
public void Void()
{
var source = @"
// had bug with parser where 'async [keyword]' didn't parse.
async void LocalVoid()
{
Console.Write(2);
await Task.Yield();
}
LocalVoid();
";
VerifyOutputInMain(source, "2", "System", "System.Threading.Tasks");
}
[Fact]
[CompilerTrait(CompilerFeature.Async)]
public void AwaitAwait()
{
var source = @"
Task<int> Fun(int x)
{
return Task.FromResult(x);
}
async Task<int> AwaitAwait()
{
var a = Fun(2);
await Fun(await a);
return await Fun(await a);
}
Console.WriteLine(AwaitAwait().Result);
";
VerifyOutputInMain(source, "2", "System", "System.Threading.Tasks");
}
[Fact]
[CompilerTrait(CompilerFeature.Async)]
public void Keyword()
{
var source = @"
using System;
struct async
{
public override string ToString() => ""2"";
}
struct await
{
public override string ToString() => ""2"";
}
class Program
{
static string A()
{
async async()
{
return new async();
}
return async().ToString();
}
static string B()
{
string async()
{
return ""2"";
}
return async();
}
static string C()
{
async Foo()
{
return new async();
}
return Foo().ToString();
}
static string D()
{
await Fun(await x)
{
return x;
}
return Fun(new await()).ToString();
}
static void Main(string[] args)
{
Console.WriteLine(A());
Console.WriteLine(B());
Console.WriteLine(C());
Console.WriteLine(D());
}
}
";
var output = @"
2
2
2
2
";
VerifyOutput(source, output);
}
[Fact]
[CompilerTrait(CompilerFeature.Async)]
public void UnsafeKeyword()
{
var source = @"
using System;
using System.Threading.Tasks;
class Program
{
static string A()
{
async unsafe Task<int> async()
{
return 2;
}
return async().Result.ToString();
}
static string B()
{
unsafe async Task<int> async()
{
return 2;
}
return async().Result.ToString();
}
static void Main(string[] args)
{
Console.WriteLine(A());
Console.WriteLine(B());
}
}
";
var output = @"
2
2
";
VerifyOutput(source, output, TestOptions.ReleaseExe.WithAllowUnsafe(true).WithWarningLevel(0));
}
}
}
}
......@@ -328,6 +328,23 @@ public static SyntaxTree ParseWithRoundTripCheck(string text, CSharpParseOptions
return CreateCompilation(source, refs, options, assemblyName);
}
public static CSharpCompilation CreateCompilationWithMscorlib46(
string source,
IEnumerable<MetadataReference> references = null,
CSharpCompilationOptions options = null,
CSharpParseOptions parseOptions = null,
string sourceFileName = "",
string assemblyName = "")
{
return CreateCompilationWithMscorlib46(
new[] { source },
references,
options,
parseOptions,
sourceFileName,
assemblyName);
}
public static CSharpCompilation CreateCompilationWithMscorlib46(
string[] sources,
IEnumerable<MetadataReference> references = null,
......
......@@ -13,6 +13,7 @@ public enum CompilerFeature
ExpressionBody,
Iterator,
LocalFunctions,
Params
Params,
Var
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册