diff --git a/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs b/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs index c6f95c550547ab8e8e669b7220d3fa20708ecb27..28cdb85198cb4418301aad7f045066f5f2bfac12 100644 --- a/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs +++ b/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs @@ -607,17 +607,17 @@ private void CompileSynthesizedMethods(TypeCompilationState compilationState) var importChain = methodWithBody.ImportChainOpt; compilationState.CurrentImportChain = importChain; - var method = methodWithBody.Method; - var lambda = method as SynthesizedLambdaMethod; - var variableSlotAllocatorOpt = ((object)lambda != null) ? - _moduleBeingBuiltOpt.TryCreateVariableSlotAllocator(lambda, lambda.TopLevelMethod) : - _moduleBeingBuiltOpt.TryCreateVariableSlotAllocator(method, method); - // We make sure that an asynchronous mutation to the diagnostic bag does not // confuse the method body generator by making a fresh bag and then loading // any diagnostics emitted into it back into the main diagnostic bag. var diagnosticsThisMethod = DiagnosticBag.GetInstance(); + var method = methodWithBody.Method; + var lambda = method as SynthesizedLambdaMethod; + var variableSlotAllocatorOpt = ((object)lambda != null) ? + _moduleBeingBuiltOpt.TryCreateVariableSlotAllocator(lambda, lambda.TopLevelMethod, diagnosticsThisMethod) : + _moduleBeingBuiltOpt.TryCreateVariableSlotAllocator(method, method, diagnosticsThisMethod); + // Synthesized methods have no ordinal stored in custom debug information (only user-defined methods have ordinals). // In case of async lambdas, which synthesize a state machine type during the following rewrite, the containing method has already been uniquely named, // so there is no need to produce a unique method ordinal for the corresponding state machine type, whose name includes the (unique) containing method name. @@ -1234,7 +1234,7 @@ private BoundStatement ChainImplicitStructConstructor(MethodSymbol methodSymbol, if (lazyVariableSlotAllocator == null) { - lazyVariableSlotAllocator = compilationState.ModuleBuilderOpt.TryCreateVariableSlotAllocator(method, method); + lazyVariableSlotAllocator = compilationState.ModuleBuilderOpt.TryCreateVariableSlotAllocator(method, method, diagnostics); } BoundStatement bodyWithoutLambdas = loweredBody; diff --git a/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/PEDeltaAssemblyBuilder.cs b/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/PEDeltaAssemblyBuilder.cs index dae2c36ad454a8be5ec486b42b883dd0d5420ca1..a7a15eab443d0652dbd973312e5b29a9f9edd472 100644 --- a/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/PEDeltaAssemblyBuilder.cs +++ b/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/PEDeltaAssemblyBuilder.cs @@ -193,9 +193,9 @@ internal override bool SupportsPrivateImplClass return anonymousTypes; } - internal override VariableSlotAllocator TryCreateVariableSlotAllocator(MethodSymbol method, MethodSymbol topLevelMethod) + internal override VariableSlotAllocator TryCreateVariableSlotAllocator(MethodSymbol method, MethodSymbol topLevelMethod, DiagnosticBag diagnostics) { - return _previousDefinitions.TryCreateVariableSlotAllocator(_previousGeneration, method, topLevelMethod); + return _previousDefinitions.TryCreateVariableSlotAllocator(_previousGeneration, Compilation, method, topLevelMethod, diagnostics); } internal override ImmutableArray GetPreviousAnonymousTypes() diff --git a/src/Compilers/CSharp/Portable/Emitter/Model/PEModuleBuilder.cs b/src/Compilers/CSharp/Portable/Emitter/Model/PEModuleBuilder.cs index 7806865d0a5b1dba1df147b90b910d7cc67504ea..965cddb404ab27745aeec28989e920ed24629bf5 100644 --- a/src/Compilers/CSharp/Portable/Emitter/Model/PEModuleBuilder.cs +++ b/src/Compilers/CSharp/Portable/Emitter/Model/PEModuleBuilder.cs @@ -331,7 +331,7 @@ private Location GetSmallestSourceLocationOrNull(Symbol symbol) /// internal virtual NamedTypeSymbol DynamicOperationContextType => null; - internal virtual VariableSlotAllocator TryCreateVariableSlotAllocator(MethodSymbol method, MethodSymbol topLevelMethod) + internal virtual VariableSlotAllocator TryCreateVariableSlotAllocator(MethodSymbol method, MethodSymbol topLevelMethod, DiagnosticBag diagnostics) { return null; } diff --git a/src/Compilers/CSharp/Portable/Symbols/MethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/MethodSymbol.cs index d3fd648cfb1b7f48ac023edfd785d2aed8121ca6..5988ea271e70ee7d5064c783e7b7b314410d9d96 100644 --- a/src/Compilers/CSharp/Portable/Symbols/MethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/MethodSymbol.cs @@ -1218,10 +1218,9 @@ public virtual MethodSymbol TupleUnderlyingMethod #region IMethodSymbolInternal - int IMethodSymbolInternal.CalculateLocalSyntaxOffset(int localPosition, SyntaxTree localTree) - { - return CalculateLocalSyntaxOffset(localPosition, localTree); - } + bool IMethodSymbolInternal.IsIterator => IsIterator; + + int IMethodSymbolInternal.CalculateLocalSyntaxOffset(int localPosition, SyntaxTree localTree) => CalculateLocalSyntaxOffset(localPosition, localTree); #endregion diff --git a/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueStateMachineTests.cs b/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueStateMachineTests.cs index 4ae07c8d49447e1bd6316afc6115d1f7d5e46ea1..5f10f83a8cd1be514096ccd09debe769e1200a02 100644 --- a/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueStateMachineTests.cs +++ b/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/EditAndContinueStateMachineTests.cs @@ -4756,8 +4756,206 @@ public IEnumerable F() new SemanticEdit(SemanticEditKind.Update, f0, f1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables: true))); diff1.EmitResult.Diagnostics.Verify( - // error CS7043: Cannot update 'C.F()'; attribute 'System.Runtime.CompilerServices.IteratorStateMachineAttribute' is missing. - Diagnostic(ErrorCode.ERR_EncUpdateFailedMissingAttribute).WithArguments("C.F()", "System.Runtime.CompilerServices.IteratorStateMachineAttribute")); + // (7,29): error CS7043: Cannot update 'C.F()'; attribute 'System.Runtime.CompilerServices.IteratorStateMachineAttribute' is missing. + Diagnostic(ErrorCode.ERR_EncUpdateFailedMissingAttribute, "F").WithArguments("C.F()", "System.Runtime.CompilerServices.IteratorStateMachineAttribute").WithLocation(7, 29)); + } + + [Fact, WorkItem(9119, "https://github.com/dotnet/roslyn/issues/9119")] + public void BadIteratorStateMachineAttribute() + { + var source0 = MarkedSource(@" +using System; +using System.Collections.Generic; + +namespace System.Runtime.CompilerServices +{ + public class IteratorStateMachineAttribute : Attribute { } +} + +class C +{ + public IEnumerable F() + { + int a = 0; + yield return 0; + Console.WriteLine(a); + } +} +"); + var source1 = MarkedSource(@" +using System; +using System.Collections.Generic; + +namespace System.Runtime.CompilerServices +{ + public class IteratorStateMachineAttribute : Attribute { } +} + +class C +{ + public IEnumerable F() + { + int a = 1; + yield return 1; + Console.WriteLine(a); + } +} +"); + + var compilation0 = CreateCompilationWithMscorlib(new[] { source0.Tree }, options: ComSafeDebugDll); + var compilation1 = compilation0.WithSource(source1.Tree); + + // the ctor is missing a parameter + Assert.Null(compilation0.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_IteratorStateMachineAttribute__ctor)); + + var v0 = CompileAndVerify(compilation0); + v0.VerifyDiagnostics(); + var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); + + var f0 = compilation0.GetMember("C.F"); + var f1 = compilation1.GetMember("C.F"); + + var generation0 = EmitBaseline.CreateInitialBaseline(md0, v0.CreateSymReader().GetEncMethodDebugInfo); + + var diff1 = compilation1.EmitDifference( + generation0, + ImmutableArray.Create( + new SemanticEdit(SemanticEditKind.Update, f0, f1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables: true))); + + diff1.EmitResult.Diagnostics.Verify( + // (12,29): error CS7043: Cannot update 'C.F()'; attribute 'System.Runtime.CompilerServices.IteratorStateMachineAttribute' is missing. + // public IEnumerable F() + Diagnostic(ErrorCode.ERR_EncUpdateFailedMissingAttribute, "F").WithArguments("C.F()", "System.Runtime.CompilerServices.IteratorStateMachineAttribute").WithLocation(12, 29)); + } + + [Fact] + public void AddedIteratorStateMachineAttribute() + { + var source0 = MarkedSource(@" +using System; +using System.Collections.Generic; + + +class C +{ + public IEnumerable F() + { + int a = 0; + yield return 0; + Console.WriteLine(a); + } +} +"); + var source1 = MarkedSource(@" +using System; +using System.Collections.Generic; + +namespace System.Runtime.CompilerServices +{ + public class IteratorStateMachineAttribute : Attribute { public IteratorStateMachineAttribute(Type type) { } } +} + +class C +{ + public IEnumerable F() + { + int a = 1; + yield return 1; + Console.WriteLine(a); + } +} +"); + + var compilation0 = CreateCompilationWithMscorlib(new[] { source0.Tree }, options: ComSafeDebugDll); + var compilation1 = compilation0.WithSource(source1.Tree); + + // older versions of mscorlib don't contain IteratorStateMachineAttribute + Assert.Null(compilation0.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_IteratorStateMachineAttribute__ctor)); + + var v0 = CompileAndVerify(compilation0); + v0.VerifyDiagnostics(); + var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); + + var f0 = compilation0.GetMember("C.F"); + var f1 = compilation1.GetMember("C.F"); + var ism1 = compilation1.GetMember("System.Runtime.CompilerServices.IteratorStateMachineAttribute"); + + var generation0 = EmitBaseline.CreateInitialBaseline(md0, v0.CreateSymReader().GetEncMethodDebugInfo); + + var diff1 = compilation1.EmitDifference( + generation0, + ImmutableArray.Create( + new SemanticEdit(SemanticEditKind.Insert, null, ism1), + new SemanticEdit(SemanticEditKind.Update, f0, f1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables: true))); + + // We conclude the original method wasn't a state machine. + // The IDE however reports a Rude Edit in that case. + diff1.EmitResult.Diagnostics.Verify(); + } + + [Fact] + public void SourceIteratorStateMachineAttribute() + { + var source0 = MarkedSource(@" +using System; +using System.Collections.Generic; + +namespace System.Runtime.CompilerServices +{ + public class IteratorStateMachineAttribute : Attribute { public IteratorStateMachineAttribute(Type type) { } } +} + +class C +{ + public IEnumerable F() + { + int a = 0; + yield return 0; + Console.WriteLine(a); + } +} +"); + var source1 = MarkedSource(@" +using System; +using System.Collections.Generic; + +namespace System.Runtime.CompilerServices +{ + public class IteratorStateMachineAttribute : Attribute { public IteratorStateMachineAttribute(Type type) { } } +} + +class C +{ + public IEnumerable F() + { + int a = 1; + yield return 1; + Console.WriteLine(a); + } +} +"); + + var compilation0 = CreateCompilationWithMscorlib(new[] { source0.Tree }, options: ComSafeDebugDll); + var compilation1 = compilation0.WithSource(source1.Tree); + + // older versions of mscorlib don't contain IteratorStateMachineAttribute + Assert.NotNull(compilation0.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_IteratorStateMachineAttribute__ctor)); + + var v0 = CompileAndVerify(compilation0); + v0.VerifyDiagnostics(); + var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); + + var f0 = compilation0.GetMember("C.F"); + var f1 = compilation1.GetMember("C.F"); + + var generation0 = EmitBaseline.CreateInitialBaseline(md0, v0.CreateSymReader().GetEncMethodDebugInfo); + + var diff1 = compilation1.EmitDifference( + generation0, + ImmutableArray.Create( + new SemanticEdit(SemanticEditKind.Update, f0, f1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables: true))); + + diff1.EmitResult.Diagnostics.Verify(); } [Fact, WorkItem(9119, "https://github.com/dotnet/roslyn/issues/9119")] @@ -4811,10 +5009,402 @@ public async Task F() new SemanticEdit(SemanticEditKind.Update, f0, f1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables: true))); diff1.EmitResult.Diagnostics.Verify( - // error CS7043: Cannot update 'C.F()'; attribute 'System.Runtime.CompilerServices.AsyncStateMachineAttribute' is missing. - Diagnostic(ErrorCode.ERR_EncUpdateFailedMissingAttribute).WithArguments("C.F()", "System.Runtime.CompilerServices.AsyncStateMachineAttribute"), - // error CS7043: Cannot update 'C.F()'; attribute 'System.Runtime.CompilerServices.AsyncStateMachineAttribute' is missing. - Diagnostic(ErrorCode.ERR_EncUpdateFailedMissingAttribute).WithArguments("C.F()", "System.Runtime.CompilerServices.AsyncStateMachineAttribute")); + // (6,28): error CS7043: Cannot update 'C.F()'; attribute 'System.Runtime.CompilerServices.AsyncStateMachineAttribute' is missing. + Diagnostic(ErrorCode.ERR_EncUpdateFailedMissingAttribute, "F").WithArguments("C.F()", "System.Runtime.CompilerServices.AsyncStateMachineAttribute").WithLocation(6, 28)); + } + + [Fact] + public void AddedAsyncStateMachineAttribute() + { + var source0 = MarkedSource(@" +using System.Threading.Tasks; + +class C +{ + public async Task F() + { + int a = 0; + await new Task(); + return a; + } +} +"); + var source1 = MarkedSource(@" +using System.Threading.Tasks; + +namespace System.Runtime.CompilerServices +{ + public class AsyncStateMachineAttribute : Attribute { public AsyncStateMachineAttribute(Type type) { } } +} + +class C +{ + public async Task F() + { + int a = 1; + await new Task(); + return a; + } +} +"); + + var compilation0 = CreateCompilation(new[] { source0.Tree }, new[] { TestReferences.NetFx.Minimal.mincorlib, TestReferences.NetFx.Minimal.minasync }, options: ComSafeDebugDll); + var compilation1 = compilation0.WithSource(source1.Tree); + + // older versions of mscorlib don't contain IteratorStateMachineAttribute + Assert.Null(compilation0.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_AsyncStateMachineAttribute__ctor)); + + var v0 = CompileAndVerify(compilation0, verify: false); + v0.VerifyDiagnostics(); + var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); + + var f0 = compilation0.GetMember("C.F"); + var f1 = compilation1.GetMember("C.F"); + var asm1 = compilation1.GetMember("System.Runtime.CompilerServices.AsyncStateMachineAttribute"); + + var generation0 = EmitBaseline.CreateInitialBaseline(md0, v0.CreateSymReader().GetEncMethodDebugInfo); + + var diff1 = compilation1.EmitDifference( + generation0, + ImmutableArray.Create( + new SemanticEdit(SemanticEditKind.Insert, null, asm1), + new SemanticEdit(SemanticEditKind.Update, f0, f1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables: true))); + + diff1.EmitResult.Diagnostics.Verify(); + } + + [Fact] + public void SourceAsyncStateMachineAttribute() + { + var source0 = MarkedSource(@" +using System.Threading.Tasks; + +namespace System.Runtime.CompilerServices +{ + public class AsyncStateMachineAttribute : Attribute { public AsyncStateMachineAttribute(Type type) { } } +} + +class C +{ + public async Task F() + { + int a = 0; + await new Task(); + return a; + } +} +"); + var source1 = MarkedSource(@" +using System.Threading.Tasks; + +namespace System.Runtime.CompilerServices +{ + public class AsyncStateMachineAttribute : Attribute { public AsyncStateMachineAttribute(Type type) { } } +} + +class C +{ + public async Task F() + { + int a = 1; + await new Task(); + return a; + } +} +"); + + var compilation0 = CreateCompilation(new[] { source0.Tree }, new[] { TestReferences.NetFx.Minimal.mincorlib, TestReferences.NetFx.Minimal.minasync }, options: ComSafeDebugDll); + var compilation1 = compilation0.WithSource(source1.Tree); + + Assert.NotNull(compilation0.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_AsyncStateMachineAttribute__ctor)); + + var v0 = CompileAndVerify(compilation0, verify: false); + v0.VerifyDiagnostics(); + var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); + + var f0 = compilation0.GetMember("C.F"); + var f1 = compilation1.GetMember("C.F"); + + var generation0 = EmitBaseline.CreateInitialBaseline(md0, v0.CreateSymReader().GetEncMethodDebugInfo); + + var diff1 = compilation1.EmitDifference( + generation0, + ImmutableArray.Create( + new SemanticEdit(SemanticEditKind.Update, f0, f1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables: true))); + + diff1.EmitResult.Diagnostics.Verify(); + } + + [Fact, WorkItem(10190, "https://github.com/dotnet/roslyn/issues/10190")] + public void NonAsyncToAsync() + { + var source0 = MarkedSource(@" +using System.Threading.Tasks; + +class C +{ + public Task F() + { + int a = 0; + return Task.FromResult(a); + } +} +"); + var source1 = MarkedSource(@" +using System.Threading.Tasks; + +class C +{ + public async Task F() + { + int a = 1; + return await Task.FromResult(a); + } +} +"); + + var compilation0 = CreateCompilation(new[] { source0.Tree }, new[] { TestReferences.NetFx.v4_0_30316_17626.mscorlib }, options: ComSafeDebugDll); + var compilation1 = compilation0.WithSource(source1.Tree); + + Assert.NotNull(compilation0.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_AsyncStateMachineAttribute__ctor)); + + var v0 = CompileAndVerify(compilation0, verify: false); + var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); + + var f0 = compilation0.GetMember("C.F"); + var f1 = compilation1.GetMember("C.F"); + + var generation0 = EmitBaseline.CreateInitialBaseline(md0, v0.CreateSymReader().GetEncMethodDebugInfo); + + var diff1 = compilation1.EmitDifference( + generation0, + ImmutableArray.Create( + new SemanticEdit(SemanticEditKind.Update, f0, f1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables: true))); + + diff1.EmitResult.Diagnostics.Verify(); + } + + [Fact] + public void NonAsyncToAsync_MissingAttribute() + { + var source0 = MarkedSource(@" +using System.Threading.Tasks; + +class C +{ + public Task F() + { + int a = 0; + a++; + return new Task(); + } +} +"); + var source1 = MarkedSource(@" +using System.Threading.Tasks; + +class C +{ + public async Task F() + { + int a = 1; + a++; + return await new Task(); + } +} +"); + + var compilation0 = CreateCompilation(new[] { source0.Tree }, new[] { TestReferences.NetFx.Minimal.mincorlib, TestReferences.NetFx.Minimal.minasync }, options: ComSafeDebugDll); + var compilation1 = compilation0.WithSource(source1.Tree); + + Assert.Null(compilation0.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_AsyncStateMachineAttribute__ctor)); + + var v0 = CompileAndVerify(compilation0, verify: false); + var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); + + var f0 = compilation0.GetMember("C.F"); + var f1 = compilation1.GetMember("C.F"); + + var generation0 = EmitBaseline.CreateInitialBaseline(md0, v0.CreateSymReader().GetEncMethodDebugInfo); + + var diff1 = compilation1.EmitDifference( + generation0, + ImmutableArray.Create( + new SemanticEdit(SemanticEditKind.Update, f0, f1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables: true))); + + diff1.EmitResult.Diagnostics.Verify( + // (6,28): error CS7043: Cannot update 'C.F()'; attribute 'System.Runtime.CompilerServices.AsyncStateMachineAttribute' is missing. + Diagnostic(ErrorCode.ERR_EncUpdateFailedMissingAttribute, "F").WithArguments("C.F()", "System.Runtime.CompilerServices.AsyncStateMachineAttribute").WithLocation(6, 28)); + } + + [Fact] + public void NonIteratorToIterator_MissingAttribute() + { + var source0 = MarkedSource(@" +using System.Collections.Generic; + +class C +{ + public IEnumerable F() + { + int a = 0; + return new int[] { a }; + } +} +"); + var source1 = MarkedSource(@" +using System.Collections.Generic; + +class C +{ + public IEnumerable F() + { + int a = 1; + yield return a; + } +} +"); + + var compilation0 = CreateCompilation(new[] { source0.Tree }, new[] { TestReferences.NetFx.v2_0_50727.mscorlib }, options: ComSafeDebugDll); + var compilation1 = compilation0.WithSource(source1.Tree); + + Assert.Null(compilation0.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_IteratorStateMachineAttribute__ctor)); + + var v0 = CompileAndVerify(compilation0, verify: false); + var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); + + var f0 = compilation0.GetMember("C.F"); + var f1 = compilation1.GetMember("C.F"); + + var generation0 = EmitBaseline.CreateInitialBaseline(md0, v0.CreateSymReader().GetEncMethodDebugInfo); + + var diff1 = compilation1.EmitDifference( + generation0, + ImmutableArray.Create( + new SemanticEdit(SemanticEditKind.Update, f0, f1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables: true))); + + diff1.EmitResult.Diagnostics.Verify( + // (6,29): error CS7043: Cannot update 'C.F()'; attribute 'System.Runtime.CompilerServices.IteratorStateMachineAttribute' is missing. + Diagnostic(ErrorCode.ERR_EncUpdateFailedMissingAttribute, "F").WithArguments("C.F()", "System.Runtime.CompilerServices.IteratorStateMachineAttribute").WithLocation(6, 29)); + } + + [Fact] + public void NonIteratorToIterator_SourceAttribute() + { + var source0 = MarkedSource(@" +using System.Collections.Generic; + +namespace System.Runtime.CompilerServices +{ + public class IteratorStateMachineAttribute : Attribute { public IteratorStateMachineAttribute(Type type) { } } +} + +class C +{ + public IEnumerable F() + { + int a = 0; + return new int[] { a }; + } +} +"); + var source1 = MarkedSource(@" +using System.Collections.Generic; + +namespace System.Runtime.CompilerServices +{ + public class IteratorStateMachineAttribute : Attribute { public IteratorStateMachineAttribute(Type type) { } } +} + +class C +{ + public IEnumerable F() + { + int a = 1; + yield return a; + } +} +"); + + var compilation0 = CreateCompilation(new[] { source0.Tree }, new[] { TestReferences.NetFx.v2_0_50727.mscorlib }, options: ComSafeDebugDll); + var compilation1 = compilation0.WithSource(source1.Tree); + + Assert.NotNull(compilation0.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_IteratorStateMachineAttribute__ctor)); + + var v0 = CompileAndVerify(compilation0, verify: false); + var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); + + var f0 = compilation0.GetMember("C.F"); + var f1 = compilation1.GetMember("C.F"); + + var generation0 = EmitBaseline.CreateInitialBaseline(md0, v0.CreateSymReader().GetEncMethodDebugInfo); + + var diff1 = compilation1.EmitDifference( + generation0, + ImmutableArray.Create( + new SemanticEdit(SemanticEditKind.Update, f0, f1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables: true))); + + diff1.EmitResult.Diagnostics.Verify(); + } + + [Fact] + public void NonAsyncToAsyncLambda() + { + var source0 = MarkedSource(@" +using System.Threading.Tasks; + +class C +{ + public object F() + { + return new System.Func>(() => + { + int a = 0; + return Task.FromResult(a); + }); + } +} +"); + var source1 = MarkedSource(@" +using System.Threading.Tasks; + +class C +{ + public object F() + { + return new System.Func>(async () => + { + int a = 0; + return await Task.FromResult(a); + }); + } +} +"); + + var compilation0 = CreateCompilation(new[] { source0.Tree }, new[] { TestReferences.NetFx.v4_0_30316_17626.mscorlib }, options: ComSafeDebugDll.WithMetadataImportOptions(MetadataImportOptions.All)); + var compilation1 = compilation0.WithSource(source1.Tree); + + Assert.NotNull(compilation0.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_AsyncStateMachineAttribute__ctor)); + + var v0 = CompileAndVerify(compilation0, verify: false); + var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); + + var f0 = compilation0.GetMember("C.F"); + var f1 = compilation1.GetMember("C.F"); + + var generation0 = EmitBaseline.CreateInitialBaseline(md0, v0.CreateSymReader().GetEncMethodDebugInfo); + + var diff1 = compilation1.EmitDifference( + generation0, + ImmutableArray.Create( + new SemanticEdit(SemanticEditKind.Update, f0, f1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables: true))); + + diff1.EmitResult.Diagnostics.Verify(); + + diff1.VerifySynthesizedMembers( + "C: {<>c}", + "C.<>c: {<>9__0_0, b__0_0, <b__0_0>d}", + "C.<>c.<b__0_0>d: {<>1__state, <>t__builder, <>4__this, 5__1, <>s__2, <>u__1, MoveNext, SetStateMachine}"); } } } diff --git a/src/Compilers/Core/Portable/Emit/EditAndContinue/DefinitionMap.cs b/src/Compilers/Core/Portable/Emit/EditAndContinue/DefinitionMap.cs index 473c8a7ba069f0d7c01922bdb67c374b48b3f739..168b8cf61f4e3c8b08b2798ca7bee5bcbd67995a 100644 --- a/src/Compilers/Core/Portable/Emit/EditAndContinue/DefinitionMap.cs +++ b/src/Compilers/Core/Portable/Emit/EditAndContinue/DefinitionMap.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Linq; using Microsoft.CodeAnalysis.CodeGen; using Microsoft.CodeAnalysis.Symbols; using System.Reflection.Metadata.Ecma335; @@ -152,7 +153,7 @@ private bool TryGetMethodHandle(EmitBaseline baseline, Cci.IMethodDefinition def protected abstract ImmutableArray TryGetLocalSlotMapFromMetadata(MethodDefinitionHandle handle, EditAndContinueMethodDebugInformation debugInfo); protected abstract ITypeSymbol TryGetStateMachineType(EntityHandle methodHandle); - internal VariableSlotAllocator TryCreateVariableSlotAllocator(EmitBaseline baseline, IMethodSymbol method, IMethodSymbol topLevelMethod) + internal VariableSlotAllocator TryCreateVariableSlotAllocator(EmitBaseline baseline, Compilation compilation, IMethodSymbolInternal method, IMethodSymbol topLevelMethod, DiagnosticBag diagnostics) { // Top-level methods are always included in the semantic edit list. Lambda methods are not. MappedMethod mappedMethod; @@ -249,6 +250,31 @@ internal VariableSlotAllocator TryCreateVariableSlotAllocator(EmitBaseline basel } else { + // If the current method is async/iterator then either the previous method wasn't declared as async/iterator and it's updated to be one, + // or it was but is not marked by the corresponding state machine attribute because it was missing in the compilation. + // In the later case we need to report an error since we don't known how to map to the previous state machine. + + // The IDE already checked that the attribute type is present in the base compilation, but didn't validate that it is well-formed. + // We don't have the base compilation to directly query for the attribute, only the source compilation. + // But since constructor signatures can't be updated during EnC we can just check the current compilation. + + if (method.IsAsync) + { + if (compilation.CommonGetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_AsyncStateMachineAttribute__ctor) == null) + { + ReportMissingStateMachineAttribute(diagnostics, method, AttributeDescription.AsyncStateMachineAttribute.FullName); + return null; + } + } + else if (method.IsIterator) + { + if (compilation.CommonGetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_IteratorStateMachineAttribute__ctor) == null) + { + ReportMissingStateMachineAttribute(diagnostics, method, AttributeDescription.IteratorStateMachineAttribute.FullName); + return null; + } + } + previousLocals = TryGetLocalSlotMapFromMetadata(previousHandle, debugInfo); if (previousLocals.IsDefault) { @@ -276,6 +302,15 @@ internal VariableSlotAllocator TryCreateVariableSlotAllocator(EmitBaseline basel awaiterMap); } + private void ReportMissingStateMachineAttribute(DiagnosticBag diagnostics, IMethodSymbolInternal method, string stateMachineAttributeFullName) + { + diagnostics.Add(MessageProvider.CreateDiagnostic( + MessageProvider.ERR_EncUpdateFailedMissingAttribute, + method.Locations.First(), + MessageProvider.GetErrorDisplayString(method), + stateMachineAttributeFullName)); + } + private static void MakeLambdaAndClosureMaps( ImmutableArray lambdaDebugInfo, ImmutableArray closureDebugInfo, diff --git a/src/Compilers/Core/Portable/Emit/EditAndContinue/EncVariableSlotAllocator.cs b/src/Compilers/Core/Portable/Emit/EditAndContinue/EncVariableSlotAllocator.cs index 89aa9e89e079ca84d39ce0e3dd90d0b5e23a0e45..691f6cb2477aedf5509b69dac77d97bb06ab4dd7 100644 --- a/src/Compilers/Core/Portable/Emit/EditAndContinue/EncVariableSlotAllocator.cs +++ b/src/Compilers/Core/Portable/Emit/EditAndContinue/EncVariableSlotAllocator.cs @@ -191,11 +191,9 @@ private bool TryGetPreviousLocalId(SyntaxNode currentDeclarator, LocalDebugId cu DiagnosticBag diagnostics, out int slotIndex) { - // Well-formed state machine attribute wasn't found in the baseline (the type is missing or bad). - // Should rarely happen since the IDE reports a rude edit if the attribute type doesn't exist. + // The previous method was not a state machine (it is allowed to change non-state machine to a state machine): if (_hoistedLocalSlotsOpt == null) { - ReportMissingStateMachineAttribute(diagnostics); slotIndex = -1; return false; } @@ -226,11 +224,9 @@ private bool TryGetPreviousLocalId(SyntaxNode currentDeclarator, LocalDebugId cu public override bool TryGetPreviousAwaiterSlotIndex(Cci.ITypeReference currentType, DiagnosticBag diagnostics, out int slotIndex) { - // Well-formed state machine attribute wasn't found in the baseline (the type is missing or bad). - // Should rarely happen since the IDE reports a rude edit if the attribute type doesn't exist. + // The previous method was not a state machine (it is allowed to change non-state machine to a state machine): if (_awaiterMapOpt == null) { - ReportMissingStateMachineAttribute(diagnostics); slotIndex = -1; return false; } @@ -238,16 +234,6 @@ public override bool TryGetPreviousAwaiterSlotIndex(Cci.ITypeReference currentTy return _awaiterMapOpt.TryGetValue(_symbolMap.MapReference(currentType), out slotIndex); } - private void ReportMissingStateMachineAttribute(DiagnosticBag diagnostics) - { - diagnostics.Add(_messageProvider.CreateDiagnostic( - _messageProvider.ERR_EncUpdateFailedMissingAttribute, - NoLocation.Singleton, - _messageProvider.GetErrorDisplayString(_previousTopLevelMethod), - (_previousTopLevelMethod.IsAsync ? AttributeDescription.AsyncStateMachineAttribute : AttributeDescription.IteratorStateMachineAttribute).FullName)); - } - - private bool TryGetPreviousSyntaxOffset(SyntaxNode currentSyntax, out int previousSyntaxOffset) { // no syntax map diff --git a/src/Compilers/Core/Portable/Symbols/IMethodSymbolInternal.cs b/src/Compilers/Core/Portable/Symbols/IMethodSymbolInternal.cs index fad5e5c6140f86123a538da8c7018a052d65cff9..d7b043b90c12face726da4d60944d3e36f34d148 100644 --- a/src/Compilers/Core/Portable/Symbols/IMethodSymbolInternal.cs +++ b/src/Compilers/Core/Portable/Symbols/IMethodSymbolInternal.cs @@ -4,6 +4,11 @@ namespace Microsoft.CodeAnalysis.Symbols { internal interface IMethodSymbolInternal : IMethodSymbol { + /// + /// True if the method is a source method implemented as an iterator. + /// + bool IsIterator { get; } + int CalculateLocalSyntaxOffset(int declaratorPosition, SyntaxTree declaratorTree); } } diff --git a/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/PEDeltaAssemblyBuilder.vb b/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/PEDeltaAssemblyBuilder.vb index 19ab9a046d34b977b30bd1011b60999a535bd35e..8b6caeda3cd0bc5ac42547899c36bf4e2c578c7f 100644 --- a/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/PEDeltaAssemblyBuilder.vb +++ b/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/PEDeltaAssemblyBuilder.vb @@ -213,8 +213,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit Return anonymousTypes End Function - Friend Overrides Function TryCreateVariableSlotAllocator(method As MethodSymbol, topLevelMethod As MethodSymbol) As VariableSlotAllocator - Return _previousDefinitions.TryCreateVariableSlotAllocator(_previousGeneration, method, topLevelMethod) + Friend Overrides Function TryCreateVariableSlotAllocator(method As MethodSymbol, topLevelMethod As MethodSymbol, diagnostics As DiagnosticBag) As VariableSlotAllocator + Return _previousDefinitions.TryCreateVariableSlotAllocator(_previousGeneration, Compilation, method, topLevelMethod, diagnostics) End Function Friend Overrides Function GetPreviousAnonymousTypes() As ImmutableArray(Of AnonymousTypeKey) diff --git a/src/Compilers/VisualBasic/Portable/Emit/PEModuleBuilder.vb b/src/Compilers/VisualBasic/Portable/Emit/PEModuleBuilder.vb index a98e1a6753d130e668b090b0e58fc096ed32cef1..d1f8f628d518f3f9a97a1a5e62a5531eadc73915 100644 --- a/src/Compilers/VisualBasic/Portable/Emit/PEModuleBuilder.vb +++ b/src/Compilers/VisualBasic/Portable/Emit/PEModuleBuilder.vb @@ -310,7 +310,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit End Get End Property - Friend Overridable Function TryCreateVariableSlotAllocator(method As MethodSymbol, topLevelMethod As MethodSymbol) As VariableSlotAllocator + Friend Overridable Function TryCreateVariableSlotAllocator(method As MethodSymbol, topLevelMethod As MethodSymbol, diagnostics As DiagnosticBag) As VariableSlotAllocator Return Nothing End Function diff --git a/src/Compilers/VisualBasic/Portable/Lowering/LambdaRewriter/LambdaRewriter.vb b/src/Compilers/VisualBasic/Portable/Lowering/LambdaRewriter/LambdaRewriter.vb index 9061551bfe5c888df6b6e1c46d1886831a6b59ba..1970ff42e88fb6691dfbd2f76a248ca8b9f51092 100644 --- a/src/Compilers/VisualBasic/Portable/Lowering/LambdaRewriter/LambdaRewriter.vb +++ b/src/Compilers/VisualBasic/Portable/Lowering/LambdaRewriter/LambdaRewriter.vb @@ -898,7 +898,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ' produce a unique method ordinal for the corresponding state machine type, whose name includes the (unique) method name. Const methodOrdinal As Integer = -1 - Dim slotAllocatorOpt = CompilationState.ModuleBuilderOpt.TryCreateVariableSlotAllocator(method, method.TopLevelMethod) + Dim slotAllocatorOpt = CompilationState.ModuleBuilderOpt.TryCreateVariableSlotAllocator(method, method.TopLevelMethod, Diagnostics) Return Rewriter.RewriteIteratorAndAsync(loweredBody, method, methodOrdinal, CompilationState, Diagnostics, slotAllocatorOpt, stateMachineTypeOpt) End Function diff --git a/src/Compilers/VisualBasic/Portable/Lowering/Rewriter.vb b/src/Compilers/VisualBasic/Portable/Lowering/Rewriter.vb index a8518e5be00e7d6d471b2c2aea695e896dcd51f6..0273dde67fd006e045d9a2732ab4b826c84185e7 100644 --- a/src/Compilers/VisualBasic/Portable/Lowering/Rewriter.vb +++ b/src/Compilers/VisualBasic/Portable/Lowering/Rewriter.vb @@ -61,7 +61,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic If lazyVariableSlotAllocator Is Nothing Then ' synthesized lambda methods are handled in LambdaRewriter.RewriteLambdaAsMethod Debug.Assert(TypeOf method IsNot SynthesizedLambdaMethod) - lazyVariableSlotAllocator = compilationState.ModuleBuilderOpt.TryCreateVariableSlotAllocator(method, method) + lazyVariableSlotAllocator = compilationState.ModuleBuilderOpt.TryCreateVariableSlotAllocator(method, method, diagnostics) End If ' Lowers lambda expressions into expressions that construct delegates. diff --git a/src/Compilers/VisualBasic/Portable/Symbols/MethodSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/MethodSymbol.vb index c1747feeb5584bda6e94c49f929e3b06bb05ec37..03745051ee6d40ddc6b9dbcb4ab8b679de6711ae 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/MethodSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/MethodSymbol.vb @@ -978,6 +978,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols #End Region #Region "IMethodSymbolInternal" + Private ReadOnly Property IMethodSymbolInternal_IsIterator As Boolean Implements IMethodSymbolInternal.IsIterator + Get + Return Me.IsIterator + End Get + End Property + Private Function IMethodSymbolInternal_CalculateLocalSyntaxOffset(localPosition As Integer, localTree As SyntaxTree) As Integer Implements IMethodSymbolInternal.CalculateLocalSyntaxOffset Return CalculateLocalSyntaxOffset(localPosition, localTree) End Function diff --git a/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueStateMachineTests.vb b/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueStateMachineTests.vb index 786280bd43478b3fdec605ee68486b48c3c61a34..f270dc13c3bde0bba5af95eba58a504397566fa7 100644 --- a/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueStateMachineTests.vb +++ b/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueStateMachineTests.vb @@ -4447,12 +4447,185 @@ End Class ImmutableArray.Create(New SemanticEdit(SemanticEditKind.Update, f0, f1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables:=True))) diff1.EmitResult.Diagnostics.Verify( - Diagnostic(ERRID.ERR_EncUpdateFailedMissingAttribute).WithArguments("Public Function F() As IEnumerable(Of Integer)", "System.Runtime.CompilerServices.IteratorStateMachineAttribute")) + Diagnostic(ERRID.ERR_EncUpdateFailedMissingAttribute, "F").WithArguments("Public Function F() As IEnumerable(Of Integer)", "System.Runtime.CompilerServices.IteratorStateMachineAttribute").WithLocation(6, 30)) End Sub - - Public Sub MissingAsyncStateMachineAttribute() - Dim common = " + + Public Sub BadIteratorStateMachineAttribute() + Dim source0 = MarkedSource(" +Imports System +Imports System.Collections.Generic + +Namespace System.Runtime.CompilerServices + Public Class IteratorStateMachineAttribute + Inherits Attribute + End Class +End Namespace + +Class C + Public Iterator Function F() As IEnumerable(Of Integer) + Dim a As Integer = 0 + Yield 0 + Console.WriteLine(a) + End Function +End Class +") + Dim source1 = MarkedSource(" +Imports System +Imports System.Collections.Generic + +Namespace System.Runtime.CompilerServices + Public Class IteratorStateMachineAttribute + Inherits Attribute + End Class +End Namespace + +Class C + Public Iterator Function F() As IEnumerable(Of Integer) + Dim a As Integer = 1 + Yield 1 + Console.WriteLine(a) + End Function +End Class +") + Dim compilation0 = CreateCompilationWithMscorlib({source0.Tree}, options:=ComSafeDebugDll) + Dim compilation1 = compilation0.WithSource(source1.Tree) + + ' the ctor is missing a parameter + Assert.Null(compilation0.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_IteratorStateMachineAttribute__ctor)) + + Dim v0 = CompileAndVerify(compilation0, verify:=False) + Dim md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData) + Dim f0 = compilation0.GetMember(Of MethodSymbol)("C.F") + Dim f1 = compilation1.GetMember(Of MethodSymbol)("C.F") + + Dim generation0 = EmitBaseline.CreateInitialBaseline(md0, AddressOf v0.CreateSymReader().GetEncMethodDebugInfo) + Dim diff1 = compilation1.EmitDifference( + generation0, + ImmutableArray.Create(New SemanticEdit(SemanticEditKind.Update, f0, f1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables:=True))) + + diff1.EmitResult.Diagnostics.Verify( + Diagnostic(ERRID.ERR_EncUpdateFailedMissingAttribute, "F").WithArguments("Public Function F() As IEnumerable(Of Integer)", "System.Runtime.CompilerServices.IteratorStateMachineAttribute").WithLocation(12, 30)) + End Sub + + + Public Sub AddedIteratorStateMachineAttribute() + Dim source0 = MarkedSource(" +Imports System +Imports System.Collections.Generic + +Class C + Public Iterator Function F() As IEnumerable(Of Integer) + Dim a As Integer = 0 + Yield 0 + Console.WriteLine(a) + End Function +End Class +") + Dim source1 = MarkedSource(" +Imports System +Imports System.Collections.Generic + +Namespace System.Runtime.CompilerServices + Public Class IteratorStateMachineAttribute + Inherits Attribute + + Sub New(type As Type) + End Sub + End Class +End Namespace + +Class C + Public Iterator Function F() As IEnumerable(Of Integer) + Dim a As Integer = 1 + Yield 1 + Console.WriteLine(a) + End Function +End Class +") + Dim compilation0 = CreateCompilationWithMscorlib({source0.Tree}, options:=ComSafeDebugDll) + Dim compilation1 = compilation0.WithSource(source1.Tree) + + ' older versions of mscorlib don't contain IteratorStateMachineAttribute + Assert.Null(compilation0.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_IteratorStateMachineAttribute__ctor)) + + Dim v0 = CompileAndVerify(compilation0, verify:=False) + Dim md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData) + Dim f0 = compilation0.GetMember(Of MethodSymbol)("C.F") + Dim f1 = compilation1.GetMember(Of MethodSymbol)("C.F") + Dim ism1 = compilation1.GetMember(Of TypeSymbol)("System.Runtime.CompilerServices.IteratorStateMachineAttribute") + + Dim generation0 = EmitBaseline.CreateInitialBaseline(md0, AddressOf v0.CreateSymReader().GetEncMethodDebugInfo) + Dim diff1 = compilation1.EmitDifference( + generation0, + ImmutableArray.Create( + New SemanticEdit(SemanticEditKind.Insert, Nothing, ism1), + New SemanticEdit(SemanticEditKind.Update, f0, f1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables:=True))) + + diff1.EmitResult.Diagnostics.Verify() + End Sub + + + Public Sub SourceIteratorStateMachineAttribute() + Dim source0 = MarkedSource(" +Imports System +Imports System.Collections.Generic + +Namespace System.Runtime.CompilerServices + Public Class IteratorStateMachineAttribute + Inherits Attribute + + Sub New(type As Type) + End Sub + End Class +End Namespace + +Class C + Public Iterator Function F() As IEnumerable(Of Integer) + Dim a As Integer = 0 + Yield 0 + Console.WriteLine(a) + End Function +End Class +") + Dim source1 = MarkedSource(" +Imports System +Imports System.Collections.Generic + +Namespace System.Runtime.CompilerServices + Public Class IteratorStateMachineAttribute + Inherits Attribute + + Sub New(type As Type) + End Sub + End Class +End Namespace + +Class C + Public Iterator Function F() As IEnumerable(Of Integer) + Dim a As Integer = 1 + Yield 1 + Console.WriteLine(a) + End Function +End Class +") + Dim compilation0 = CreateCompilationWithMscorlib({source0.Tree}, options:=ComSafeDebugDll) + Dim compilation1 = compilation0.WithSource(source1.Tree) + + Dim v0 = CompileAndVerify(compilation0, verify:=False) + Dim md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData) + Dim f0 = compilation0.GetMember(Of MethodSymbol)("C.F") + Dim f1 = compilation1.GetMember(Of MethodSymbol)("C.F") + + Dim generation0 = EmitBaseline.CreateInitialBaseline(md0, AddressOf v0.CreateSymReader().GetEncMethodDebugInfo) + Dim diff1 = compilation1.EmitDifference( + generation0, + ImmutableArray.Create(New SemanticEdit(SemanticEditKind.Update, f0, f1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables:=True))) + + diff1.EmitResult.Diagnostics.Verify() + End Sub + + Const AsyncHelpers = " Imports System Imports System.Threading.Tasks @@ -4466,7 +4639,9 @@ Namespace Microsoft.VisualBasic.CompilerServices End Class End Namespace" - Dim source0 = MarkedSource(common & " + + Public Sub MissingAsyncStateMachineAttribute() + Dim source0 = MarkedSource(AsyncHelpers & " Class C Public Async Function F() As Task(Of Integer) Dim a As Integer = 0 @@ -4475,7 +4650,7 @@ Class C End Function End Class ") - Dim source1 = MarkedSource(common & " + Dim source1 = MarkedSource(AsyncHelpers & " Class C Public Async Function F() As Task(Of Integer) Dim a As Integer = 1 @@ -4501,8 +4676,123 @@ End Class ImmutableArray.Create(New SemanticEdit(SemanticEditKind.Update, f0, f1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables:=True))) diff1.EmitResult.Diagnostics.Verify( - Diagnostic(ERRID.ERR_EncUpdateFailedMissingAttribute).WithArguments("Public Function F() As Task(Of Integer)", "System.Runtime.CompilerServices.AsyncStateMachineAttribute"), - Diagnostic(ERRID.ERR_EncUpdateFailedMissingAttribute).WithArguments("Public Function F() As Task(Of Integer)", "System.Runtime.CompilerServices.AsyncStateMachineAttribute")) + Diagnostic(ERRID.ERR_EncUpdateFailedMissingAttribute, "F").WithArguments("Public Function F() As Task(Of Integer)", "System.Runtime.CompilerServices.AsyncStateMachineAttribute").WithLocation(15, 27)) + End Sub + + + Public Sub NonAsyncToAsync() + Dim source0 = MarkedSource(AsyncHelpers & " +Class C + Public Function F() As Task(Of Integer) + Dim a As Integer = 0 + Return Task.FromResult(a) + End Function +End Class +") + Dim source1 = MarkedSource(AsyncHelpers & " +Class C + Public Async Function F() As Task(Of Integer) + Dim a As Integer = 1 + Return Await Task.FromResult(a) + End Function +End Class +") + Dim compilation0 = CompilationUtils.CreateCompilation({source0.Tree}, {TestReferences.NetFx.v4_0_30316_17626.mscorlib}, options:=ComSafeDebugDll) + Dim compilation1 = compilation0.WithSource(source1.Tree) + + Assert.NotNull(compilation0.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_AsyncStateMachineAttribute__ctor)) + + Dim v0 = CompileAndVerify(compilation0, verify:=False) + Dim md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData) + + Dim f0 = compilation0.GetMember(Of MethodSymbol)("C.F") + Dim f1 = compilation1.GetMember(Of MethodSymbol)("C.F") + + Dim generation0 = EmitBaseline.CreateInitialBaseline(md0, AddressOf v0.CreateSymReader().GetEncMethodDebugInfo) + Dim diff1 = compilation1.EmitDifference( + generation0, + ImmutableArray.Create(New SemanticEdit(SemanticEditKind.Update, f0, f1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables:=True))) + + diff1.EmitResult.Diagnostics.Verify() + End Sub + + + Public Sub NonAsyncToAsync_MissingAttribute() + Dim source0 = MarkedSource(AsyncHelpers & " +Class C + Public Function F() As Task(Of Integer) + Dim a As Integer = 0 + a = a + 1 + Return New Task(Of Integer)() + End Function +End Class +") + Dim source1 = MarkedSource(AsyncHelpers & " +Class C + Public Async Function F() As Task(Of Integer) + Dim a As Integer = 1 + a = a + 1 + Return Await New Task(Of Integer)() + End Function +End Class +") + Dim compilation0 = CompilationUtils.CreateCompilation({source0.Tree}, {TestReferences.NetFx.Minimal.mincorlib, TestReferences.NetFx.Minimal.minasync}, options:=ComSafeDebugDll) + Dim compilation1 = compilation0.WithSource(source1.Tree) + + Assert.Null(compilation0.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_AsyncStateMachineAttribute__ctor)) + + Dim v0 = CompileAndVerify(compilation0, verify:=False) + Dim md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData) + + Dim f0 = compilation0.GetMember(Of MethodSymbol)("C.F") + Dim f1 = compilation1.GetMember(Of MethodSymbol)("C.F") + + Dim generation0 = EmitBaseline.CreateInitialBaseline(md0, AddressOf v0.CreateSymReader().GetEncMethodDebugInfo) + Dim diff1 = compilation1.EmitDifference( + generation0, + ImmutableArray.Create(New SemanticEdit(SemanticEditKind.Update, f0, f1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables:=True))) + + diff1.EmitResult.Diagnostics.Verify( + Diagnostic(ERRID.ERR_EncUpdateFailedMissingAttribute, "F").WithArguments("Public Function F() As Task(Of Integer)", "System.Runtime.CompilerServices.AsyncStateMachineAttribute").WithLocation(15, 27)) + End Sub + + + Public Sub NonIteratorToIterator_MissingAttribute() + Dim source0 = MarkedSource(" +Imports System.Collections.Generic + +Class C + Public Function F() As IEnumerable(Of Integer) + Dim a As Integer = 0 + Return { 0 } + End Function +End Class +") + Dim source1 = MarkedSource(" +Imports System.Collections.Generic + +Class C + Public Iterator Function F() As IEnumerable(Of Integer) + Dim a As Integer = 1 + Yield a + End Function +End Class +") + Dim compilation0 = CreateCompilationWithMscorlib({source0.Tree}, options:=ComSafeDebugDll) + Dim compilation1 = compilation0.WithSource(source1.Tree) + + Dim v0 = CompileAndVerify(compilation0, verify:=False) + Dim md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData) + Dim f0 = compilation0.GetMember(Of MethodSymbol)("C.F") + Dim f1 = compilation1.GetMember(Of MethodSymbol)("C.F") + + Dim generation0 = EmitBaseline.CreateInitialBaseline(md0, AddressOf v0.CreateSymReader().GetEncMethodDebugInfo) + Dim diff1 = compilation1.EmitDifference( + generation0, + ImmutableArray.Create(New SemanticEdit(SemanticEditKind.Update, f0, f1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables:=True))) + + diff1.EmitResult.Diagnostics.Verify( + Diagnostic(ERRID.ERR_EncUpdateFailedMissingAttribute, "F").WithArguments("Public Function F() As IEnumerable(Of Integer)", "System.Runtime.CompilerServices.IteratorStateMachineAttribute").WithLocation(5, 30)) End Sub End Class End Namespace diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/EEAssemblyBuilder.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/EEAssemblyBuilder.cs index a6ca9f67080672495e1fa117626be2367b2a0345..2b5bcd10b233382038d7e3e6bc653f32d2e769f7 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/EEAssemblyBuilder.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/EEAssemblyBuilder.cs @@ -71,7 +71,7 @@ protected override IModuleReference TranslateModule(ModuleSymbol symbol, Diagnos public override int CurrentGenerationOrdinal => 0; - internal override VariableSlotAllocator TryCreateVariableSlotAllocator(MethodSymbol symbol, MethodSymbol topLevelMethod) + internal override VariableSlotAllocator TryCreateVariableSlotAllocator(MethodSymbol symbol, MethodSymbol topLevelMethod, DiagnosticBag diagnostics) { var method = symbol as EEMethodSymbol; if (((object)method != null) && Methods.Contains(method)) diff --git a/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/EEAssemblyBuilder.vb b/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/EEAssemblyBuilder.vb index 76eacb8cb018c01c0b77e3f82343491d45746242..eeb490f11ae1185e8838a470c6d9f12e84294331 100644 --- a/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/EEAssemblyBuilder.vb +++ b/src/ExpressionEvaluator/VisualBasic/Source/ExpressionCompiler/EEAssemblyBuilder.vb @@ -72,7 +72,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator End Get End Property - Friend Overrides Function TryCreateVariableSlotAllocator(symbol As MethodSymbol, topLevelMethod As MethodSymbol) As VariableSlotAllocator + Friend Overrides Function TryCreateVariableSlotAllocator(symbol As MethodSymbol, topLevelMethod As MethodSymbol, diagnostics As DiagnosticBag) As VariableSlotAllocator Dim method = TryCast(symbol, EEMethodSymbol) If method IsNot Nothing AndAlso _methods.Contains(method) Then Dim defs = GetLocalDefinitions(method.Locals) diff --git a/src/Workspaces/Core/Portable/SymbolId/SymbolKey.BodyLevelSymbolKey.cs b/src/Workspaces/Core/Portable/SymbolId/SymbolKey.BodyLevelSymbolKey.cs index ec6bcc77de19ef3ddcd82166078747911b6a0f19..783d0a35d4e1a265d42618572ec9d23790275dd0 100644 --- a/src/Workspaces/Core/Portable/SymbolId/SymbolKey.BodyLevelSymbolKey.cs +++ b/src/Workspaces/Core/Portable/SymbolId/SymbolKey.BodyLevelSymbolKey.cs @@ -69,6 +69,26 @@ public override SymbolKeyResolution Resolve(Compilation compilation, bool ignore foreach (var declaringLocation in containingSymbol.DeclaringSyntaxReferences) { + // This operation can potentially fail. If containingSymbol came from + // a SpeculativeSemanticModel, containingSymbol.ContainingAssembly.Compilation + // may not have been rebuilt to reflect the trees used by the + // SpeculativeSemanticModel to produce containingSymbol. In that case, + // asking the ContainingAssembly's complation for a SemanticModel based + // on trees for containingSymbol with throw an ArgumentException. + // Unfortunately, the best way to avoid this (currently) is to see if + // we're asking for a model for a tree that's part of the compilation. + // (There's no way to get back to a SemanticModel from a symbol). + + // TODO (rchande): It might be better to call compilation.GetSemanticModel + // and catch the ArgumentException. The compilation internally has a + // Dictionary that it uses to check if the SyntaxTree + // is applicable wheras the public interface requires us to enumerate + // the entire IEnumerable of trees in the Compilation. + if (!compilation.SyntaxTrees.Contains(declaringLocation.SyntaxTree)) + { + continue; + } + var node = declaringLocation.GetSyntax(cancellationToken); if (node.Language == LanguageNames.VisualBasic) {