diff --git a/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs b/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs index 64d53958187ed0d06a7ac0ffe248714c70cde90e..f5d372e1ba6e9367dbb01da9b11d5d5ee3a93ff8 100644 --- a/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs +++ b/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs @@ -1209,6 +1209,7 @@ private BoundStatement ChainImplicitStructConstructor(MethodSymbol methodSymbol, method.ThisParameter, method, methodOrdinal, + null, lambdaDebugInfoBuilder, closureDebugInfoBuilder, lazyVariableSlotAllocator, diff --git a/src/Compilers/CSharp/Portable/Lowering/LambdaRewriter/LambdaRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/LambdaRewriter/LambdaRewriter.cs index 355248e0f7423d42f3fa2b7cdd9fc6e77fbda43e..17200b0b9eea0764dce33cc11fe6bf30cd01002e 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LambdaRewriter/LambdaRewriter.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LambdaRewriter/LambdaRewriter.cs @@ -58,6 +58,7 @@ internal sealed partial class LambdaRewriter : MethodToClassRewriter { private readonly Analysis _analysis; private readonly MethodSymbol _topLevelMethod; + private readonly MethodSymbol _substitutedSourceMethod; private readonly int _topLevelMethodOrdinal; // lambda frame for static lambdas. @@ -137,6 +138,7 @@ public MappedLocalFunction(MethodSymbol symbol, ClosureKind closureKind) ParameterSymbol thisParameterOpt, MethodSymbol method, int methodOrdinal, + MethodSymbol substitutedSourceMethod, ArrayBuilder lambdaDebugInfoBuilder, VariableSlotAllocator slotAllocatorOpt, TypeCompilationState compilationState, @@ -151,6 +153,7 @@ public MappedLocalFunction(MethodSymbol symbol, ClosureKind closureKind) Debug.Assert(diagnostics != null); _topLevelMethod = method; + _substitutedSourceMethod = substitutedSourceMethod; _topLevelMethodOrdinal = methodOrdinal; _lambdaDebugInfoBuilder = lambdaDebugInfoBuilder; _currentMethod = method; @@ -182,6 +185,7 @@ protected override bool NeedsProxy(Symbol localOrParameter) /// The "this" parameter in the top-most frame, or null if static method /// The containing method of the node to be rewritten /// Index of the method symbol in its containing type member list. + /// If this is non-null, then will be treated as this for uses of parent symbols. For use in EE. /// Information on lambdas defined in needed for debugging. /// Information on closures defined in needed for debugging. /// Slot allocator. @@ -194,6 +198,7 @@ protected override bool NeedsProxy(Symbol localOrParameter) ParameterSymbol thisParameter, MethodSymbol method, int methodOrdinal, + MethodSymbol substitutedSourceMethod, ArrayBuilder lambdaDebugInfoBuilder, ArrayBuilder closureDebugInfoBuilder, VariableSlotAllocator slotAllocatorOpt, @@ -223,6 +228,7 @@ protected override bool NeedsProxy(Symbol localOrParameter) thisParameter, method, methodOrdinal, + substitutedSourceMethod, lambdaDebugInfoBuilder, slotAllocatorOpt, compilationState, @@ -324,6 +330,10 @@ private LambdaFrame GetFrameForScope(BoundNode scope, ArrayBuilder()); } diff --git a/src/Compilers/CSharp/Portable/Symbols/TypeMap.cs b/src/Compilers/CSharp/Portable/Symbols/TypeMap.cs index 75d2cb52fcabc9210d39408aecc2d731112abd0f..1b18d9354705a385fd179710fe29a2c5ceaa0331 100644 --- a/src/Compilers/CSharp/Portable/Symbols/TypeMap.cs +++ b/src/Compilers/CSharp/Portable/Symbols/TypeMap.cs @@ -129,6 +129,7 @@ internal TypeMap WithAlphaRename(MethodSymbol oldOwner, Symbol newOwner, out Imm internal TypeMap WithConcatAlphaRename(MethodSymbol oldOwner, Symbol newOwner, out ImmutableArray newTypeParameters, MethodSymbol stopAt = null) { Debug.Assert(oldOwner.ConstructedFrom == oldOwner); + Debug.Assert(stopAt == null || stopAt.ConstructedFrom == stopAt); // Build the array up backwards, then reverse it. // The following example goes through the do-loop in order M3, M2, M1 @@ -152,19 +153,13 @@ internal TypeMap WithConcatAlphaRename(MethodSymbol oldOwner, Symbol newOwner, o parameters.Add(currentParameters[i]); } - oldOwner = oldOwner.ContainingSymbol as MethodSymbol; + oldOwner = oldOwner.ContainingSymbol.OriginalDefinition as MethodSymbol; } parameters.ReverseContents(); // Ensure that if stopAt was provided, it actually was in the chain and we stopped at it. // If not provided, both should be null (if stopAt != null && oldOwner == null, then it wasn't in the chain) - - // TODO: Expression Evaluator breaks this assert. In EEMethodSymbol.GenerateMethodBody call to LambdaRewriter.Rewrite, - // "method: this" is passed in, when really the method being compiled is "method: this.SubstitutedSourceMethod". - // However, we can't just do that, because it breaks things: e.g. the assembly of EEMethod.SubSourceMethod != assembly of EEMethod. - // We might have to refactor LambdaRewriter to accept two MethodSymbols, one for the EE one, one for the SubSource one. - // Note that ignoring this assert does break things, if EEMethodSymbol is generic then things blow up. - //Debug.Assert(stopAt == oldOwner); + Debug.Assert(stopAt == oldOwner); return WithAlphaRename(parameters.ToImmutableAndFree(), newOwner, out newTypeParameters); } diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxFacts.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxFacts.cs index 54e874c1eae035fe678faab90c8cb5df5f9a9b0c..6d5501362c23aa0845915106466701067c43911f 100644 --- a/src/Compilers/CSharp/Portable/Syntax/SyntaxFacts.cs +++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxFacts.cs @@ -164,6 +164,9 @@ public static bool IsInTypeOnlyContext(ExpressionSyntax node) case EventDeclaration: return ((EventDeclarationSyntax)parent).Type == node; + case LocalFunctionStatement: + return ((LocalFunctionStatementSyntax)parent).ReturnType == node; + case SimpleBaseType: return true; diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/LocalFunctionTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/LocalFunctionTests.cs index b8c9ebe973672da76256e0b30bf150af08032f78..9bba65694a5cc714b235faa9d804efb4a3ef3b35 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/LocalFunctionTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/LocalFunctionTests.cs @@ -1585,6 +1585,44 @@ static void Main(string[] args) "); } + [Fact] + public void Dynamic() + { + object f = 0; + var source = @" +using System; + +class Program +{ + static void Main(string[] args) + { + // TODO: Fix local functions with dynamic arguments + //void Local(int x) + //{ + // Console.WriteLine(x); + //} + //dynamic val = 2; + //Local(val); + dynamic RetDyn() + { + return 2; + } + Console.WriteLine(RetDyn()); + var RetDynVar() + { + return (dynamic)2; + } + Console.WriteLine(RetDynVar()); + } +} +"; + var comp = CreateCompilationWithMscorlib45AndCSruntime(source, options: TestOptions.ReleaseExe, parseOptions: _parseOptions); + var verify = CompileAndVerify(comp, expectedOutput: @" +2 +2 +"); + } + [Fact] public void Shadows() { diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EEMethodSymbol.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EEMethodSymbol.cs index 44bb98ac80b5967aede3c31db929343efa7d48ec..ac65986cdb4a74709816353bd6c4d073122b65bd 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EEMethodSymbol.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EEMethodSymbol.cs @@ -567,6 +567,7 @@ internal override void GenerateMethodBody(TypeCompilationState compilationState, thisParameter: _thisParameter, method: this, methodOrdinal: _methodOrdinal, + substitutedSourceMethod: this.SubstitutedSourceMethod.OriginalDefinition, closureDebugInfoBuilder: closureDebugInfoBuilder, lambdaDebugInfoBuilder: lambdaDebugInfoBuilder, slotAllocatorOpt: null, diff --git a/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/ExpressionCompilerTests.cs b/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/ExpressionCompilerTests.cs index 9154c81c6e1ae1acf046f7c885d0758241df186e..9e2d6a80c5c10abe63f0567bcb97f8cd91a2696d 100644 --- a/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/ExpressionCompilerTests.cs +++ b/src/ExpressionEvaluator/CSharp/Test/ExpressionCompiler/ExpressionCompilerTests.cs @@ -2515,8 +2515,7 @@ .maxstack 2 Assert.Equal(((Cci.IMethodDefinition)methodData.Method).CallingConvention, Cci.CallingConvention.Default); } - // TODO: fix this before merging local functions into dotnet/future - [Fact(Skip = "See comment in TypeMap.WithConcatAlphaRename next to assert for why this is skipped.")] + [Fact] public void GenericClosureClass() { var source =