提交 646459eb 编写于 作者: E Evan Hauck

Make generic local functions work in EE

上级 42d71a8f
......@@ -1209,6 +1209,7 @@ private BoundStatement ChainImplicitStructConstructor(MethodSymbol methodSymbol,
method.ThisParameter,
method,
methodOrdinal,
null,
lambdaDebugInfoBuilder,
closureDebugInfoBuilder,
lazyVariableSlotAllocator,
......
......@@ -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<LambdaDebugInfo> 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)
/// <param name="thisParameter">The "this" parameter in the top-most frame, or null if static method</param>
/// <param name="method">The containing method of the node to be rewritten</param>
/// <param name="methodOrdinal">Index of the method symbol in its containing type member list.</param>
/// <param name="substitutedSourceMethod">If this is non-null, then <paramref name="method"/> will be treated as this for uses of parent symbols. For use in EE.</param>
/// <param name="lambdaDebugInfoBuilder">Information on lambdas defined in <paramref name="method"/> needed for debugging.</param>
/// <param name="closureDebugInfoBuilder">Information on closures defined in <paramref name="method"/> needed for debugging.</param>
/// <param name="slotAllocatorOpt">Slot allocator.</param>
......@@ -194,6 +198,7 @@ protected override bool NeedsProxy(Symbol localOrParameter)
ParameterSymbol thisParameter,
MethodSymbol method,
int methodOrdinal,
MethodSymbol substitutedSourceMethod,
ArrayBuilder<LambdaDebugInfo> lambdaDebugInfoBuilder,
ArrayBuilder<ClosureDebugInfo> 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<ClosureDebugI
DebugId closureId = GetClosureId(syntax, closureDebugInfo);
var containingMethod = _analysis.scopeOwner[scope];
if (_substitutedSourceMethod != null && containingMethod == _topLevelMethod)
{
containingMethod = _substitutedSourceMethod;
}
frame = new LambdaFrame(_topLevelMethod, containingMethod, syntax, methodId, closureId);
_frames.Add(scope, frame);
......@@ -361,7 +371,8 @@ private LambdaFrame GetStaticFrame(DiagnosticBag diagnostics, IBoundLambdaOrFunc
DebugId closureId = default(DebugId);
// using _topLevelMethod as containing member because the static frame does not have generic parameters, except for the top level method's
_lazyStaticLambdaFrame = new LambdaFrame(_topLevelMethod, isNonGeneric ? null : _topLevelMethod, scopeSyntaxOpt: null, methodId: methodId, closureId: closureId);
var containingMethod = isNonGeneric ? null : (_substitutedSourceMethod ?? _topLevelMethod);
_lazyStaticLambdaFrame = new LambdaFrame(_topLevelMethod, containingMethod, scopeSyntaxOpt: null, methodId: methodId, closureId: closureId);
// nongeneric static lambdas can share the frame
if (isNonGeneric)
......
......@@ -674,7 +674,6 @@ private static NamedTypeSymbol CreateCallSiteContainer(SyntheticBoundNodeFactory
if (factory.TopLevelMethod.IsGenericMethod)
{
// TODO: This probably doesn't work with generic local functions
return synthesizedContainer.Construct(factory.TopLevelMethod.TypeParameters.Cast<TypeParameterSymbol, TypeSymbol>());
}
......
......@@ -129,6 +129,7 @@ internal TypeMap WithAlphaRename(MethodSymbol oldOwner, Symbol newOwner, out Imm
internal TypeMap WithConcatAlphaRename(MethodSymbol oldOwner, Symbol newOwner, out ImmutableArray<TypeParameterSymbol> 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);
}
......
......@@ -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;
......
......@@ -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()
{
......
......@@ -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,
......
......@@ -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 =
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册