提交 ef76ee11 编写于 作者: E Evan Hauck

Allow generic local functions

上级 f507de44
......@@ -131,7 +131,7 @@ public override void VisitParenthesizedLambdaExpression(ParenthesizedLambdaExpre
public override void VisitLocalFunctionStatement(LocalFunctionStatementSyntax node)
{
var body = (CSharpSyntaxNode)node.Body ?? node.ExpressionBody;
MethodSymbol match = null;
LocalFunctionSymbol match = null;
// Don't use LookupLocalFunction because it recurses up the tree, as it
// should be defined in the directly enclosing block (see note below)
foreach (var candidate in _enclosing.LocalFunctions)
......@@ -149,11 +149,20 @@ public override void VisitLocalFunctionStatement(LocalFunctionStatementSyntax no
{
var oldMethod = _method;
_method = match;
var inMethod = new InMethodBinder(match, _enclosing);
AddToMap(node, inMethod);
Binder addToMap;
if (match.IsGenericMethod)
{
addToMap = new WithMethodTypeParametersBinder(match, _enclosing);
}
else
{
addToMap = _enclosing;
}
addToMap = new InMethodBinder(match, addToMap);
AddToMap(node, addToMap);
if (body != null)
{
Visit(body, inMethod);
Visit(body, addToMap);
}
_method = oldMethod;
}
......
......@@ -22,8 +22,8 @@ internal sealed class LambdaFrame : SynthesizedContainer, ISynthesizedMethodBody
internal readonly CSharpSyntaxNode ScopeSyntaxOpt;
internal readonly int ClosureOrdinal;
internal LambdaFrame(MethodSymbol topLevelMethod, CSharpSyntaxNode scopeSyntaxOpt, DebugId methodId, DebugId closureId)
: base(MakeName(scopeSyntaxOpt, methodId, closureId), topLevelMethod)
internal LambdaFrame(MethodSymbol topLevelMethod, MethodSymbol containingMethod, CSharpSyntaxNode scopeSyntaxOpt, DebugId methodId, DebugId closureId)
: base(MakeName(scopeSyntaxOpt, methodId, closureId), containingMethod)
{
_topLevelMethod = topLevelMethod;
_constructor = new LambdaFrameConstructor(this);
......
......@@ -50,6 +50,11 @@ internal sealed class Analysis : BoundTreeWalker
/// </summary>
public readonly Dictionary<Symbol, BoundNode> variableScope = new Dictionary<Symbol, BoundNode>();
/// <summary>
/// For each value in variableScope, identifies the closest owning method, lambda, or local function.
/// </summary>
public readonly Dictionary<BoundNode, MethodSymbol> scopeOwner = new Dictionary<BoundNode, MethodSymbol>();
/// <summary>
/// The syntax nodes associated with each captured variable.
/// </summary>
......@@ -102,6 +107,7 @@ public static Analysis Analyze(BoundNode node, MethodSymbol method)
private void Analyze(BoundNode node)
{
_currentScope = FindNodeToAnalyze(node);
scopeOwner[_currentScope] = _currentParent;
Debug.Assert(!_inExpressionLambda);
Debug.Assert((object)_topLevelMethod != null);
......@@ -267,6 +273,8 @@ private BoundNode PushBlock(BoundNode node, ImmutableArray<LocalSymbol> locals)
variableScope[local] = _currentScope;
}
scopeOwner[_currentScope] = _currentParent;
return previousBlock;
}
......@@ -362,6 +370,7 @@ private BoundNode VisitLambdaOrFunction(IBoundLambdaOrFunction node)
_currentParent = node.Symbol;
_currentScope = node.Body;
scopeParent[_currentScope] = oldBlock;
scopeOwner[_currentScope] = _currentParent;
var wasInExpressionLambda = _inExpressionLambda;
_inExpressionLambda = _inExpressionLambda || ((node as BoundLambda)?.Type.IsExpressionTree() ?? false);
......
......@@ -323,7 +323,8 @@ private LambdaFrame GetFrameForScope(BoundNode scope, ArrayBuilder<ClosureDebugI
DebugId methodId = GetTopLevelMethodId();
DebugId closureId = GetClosureId(syntax, closureDebugInfo);
frame = new LambdaFrame(_topLevelMethod, syntax, methodId, closureId);
var containingMethod = _analysis.scopeOwner[scope];
frame = new LambdaFrame(_topLevelMethod, containingMethod, syntax, methodId, closureId);
_frames.Add(scope, frame);
CompilationState.ModuleBuilderOpt.AddSynthesizedDefinition(this.ContainingType, frame);
......@@ -359,7 +360,8 @@ private LambdaFrame GetStaticFrame(DiagnosticBag diagnostics, IBoundLambdaOrFunc
}
DebugId closureId = default(DebugId);
_lazyStaticLambdaFrame = new LambdaFrame(_topLevelMethod, scopeSyntaxOpt: null, methodId: methodId, closureId: closureId);
// 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, _topLevelMethod, scopeSyntaxOpt: null, methodId: methodId, closureId: closureId);
// nongeneric static lambdas can share the frame
if (isNonGeneric)
......@@ -465,7 +467,8 @@ private static void InsertAndFreePrologue(ArrayBuilder<BoundStatement> result, A
/// <returns>The translated statement, as returned from F</returns>
private T IntroduceFrame<T>(BoundNode node, LambdaFrame frame, Func<ArrayBuilder<BoundExpression>, ArrayBuilder<LocalSymbol>, T> F)
{
NamedTypeSymbol frameType = frame.ConstructIfGeneric(StaticCast<TypeSymbol>.From(_currentTypeParameters));
var frameTypeParameters = ImmutableArray.Create(StaticCast<TypeSymbol>.From(_currentTypeParameters), 0, frame.Arity);
NamedTypeSymbol frameType = frame.ConstructIfGeneric(frameTypeParameters);
Debug.Assert(frame.ScopeSyntaxOpt != null);
LocalSymbol framePointer = new SynthesizedLocal(_topLevelMethod, frameType, SynthesizedLocalKind.LambdaDisplayClass, frame.ScopeSyntaxOpt);
......@@ -644,30 +647,41 @@ public override BoundNode VisitBaseReference(BoundBaseReference node)
: FramePointer(node.Syntax, _topLevelMethod.ContainingType); // technically, not the correct static type
}
private void RemapLocalFunction(CSharpSyntaxNode syntax, MethodSymbol symbol, out BoundExpression receiver, out MethodSymbol method)
private void RemapLambdaOrLocalFunction(
CSharpSyntaxNode syntax,
MethodSymbol originalMethod,
ImmutableArray<TypeSymbol> typeArgumentsOpt,
ClosureKind closureKind,
ref MethodSymbol synthesizedMethod,
out BoundExpression receiver,
out NamedTypeSymbol constructedFrame)
{
Debug.Assert(symbol.MethodKind == MethodKind.LocalFunction);
var translatedLambdaContainer = synthesizedMethod.ContainingType;
var containerAsFrame = translatedLambdaContainer as LambdaFrame;
var constructed = symbol as SubstitutedMethodSymbol;
if (constructed != null)
// All of _currentTypeParameters might not be preserved due to recursively calling upwards in the chain of local functions/lambdas
Debug.Assert((typeArgumentsOpt.IsDefault && !originalMethod.IsGenericMethod) || (typeArgumentsOpt.Length == originalMethod.Arity));
var totalTypeArgumentCount = translatedLambdaContainer.Arity + synthesizedMethod.Arity;
var realTypeArguments = ImmutableArray.Create(StaticCast<TypeSymbol>.From(_currentTypeParameters), 0, totalTypeArgumentCount - originalMethod.Arity);
if (!typeArgumentsOpt.IsDefault)
{
RemapLocalFunction(syntax, constructed.ConstructedFrom, out receiver, out method);
return;
realTypeArguments = realTypeArguments.Concat(typeArgumentsOpt);
}
var mappedLocalFunction = _localFunctionMap[(LocalFunctionSymbol)symbol];
method = mappedLocalFunction.Symbol;
var translatedLambdaContainer = method.ContainingType;
var containerAsFrame = translatedLambdaContainer as LambdaFrame;
// Rewrite the lambda expression (and the enclosing anonymous method conversion) as a delegate creation expression
NamedTypeSymbol constructedFrame = (object)containerAsFrame != null ?
translatedLambdaContainer.ConstructIfGeneric(StaticCast<TypeSymbol>.From(_currentTypeParameters)) :
translatedLambdaContainer;
if (containerAsFrame != null && containerAsFrame.Arity != 0)
{
var containerTypeArguments = ImmutableArray.Create(realTypeArguments, 0, containerAsFrame.Arity);
realTypeArguments = ImmutableArray.Create(realTypeArguments, containerAsFrame.Arity, realTypeArguments.Length - containerAsFrame.Arity);
constructedFrame = containerAsFrame.Construct(containerTypeArguments);
}
else
{
constructedFrame = translatedLambdaContainer;
}
// for instance lambdas, receiver is the frame
// for static lambdas, get the singleton receiver
if (mappedLocalFunction.ClosureKind != ClosureKind.Static)
if (closureKind != ClosureKind.Static)
{
receiver = FrameOfType(syntax, constructedFrame);
}
......@@ -677,13 +691,38 @@ private void RemapLocalFunction(CSharpSyntaxNode syntax, MethodSymbol symbol, ou
receiver = new BoundFieldAccess(syntax, null, field, constantValueOpt: null);
}
method = method.AsMember(constructedFrame);
if (method.IsGenericMethod)
synthesizedMethod = synthesizedMethod.AsMember(constructedFrame);
if (synthesizedMethod.IsGenericMethod)
{
synthesizedMethod = synthesizedMethod.Construct(StaticCast<TypeSymbol>.From(realTypeArguments));
}
else
{
method = method.Construct(StaticCast<TypeSymbol>.From(_currentTypeParameters));
Debug.Assert(realTypeArguments.Length == 0);
}
}
private void RemapLocalFunction(
CSharpSyntaxNode syntax, MethodSymbol symbol,
out BoundExpression receiver, out MethodSymbol method,
ImmutableArray<TypeSymbol> typeArguments = default(ImmutableArray<TypeSymbol>))
{
Debug.Assert(symbol.MethodKind == MethodKind.LocalFunction);
var constructed = symbol as ConstructedMethodSymbol;
if (constructed != null)
{
RemapLocalFunction(syntax, constructed.ConstructedFrom, out receiver, out method, this.TypeMap.SubstituteTypes(constructed.TypeArguments));
return;
}
var mappedLocalFunction = _localFunctionMap[(LocalFunctionSymbol)symbol];
method = mappedLocalFunction.Symbol;
NamedTypeSymbol constructedFrame;
RemapLambdaOrLocalFunction(syntax, symbol, typeArguments, mappedLocalFunction.ClosureKind, ref method, out receiver, out constructedFrame);
}
public override BoundNode VisitCall(BoundCall node)
{
if (node.Method.MethodKind == MethodKind.LocalFunction)
......@@ -1160,16 +1199,8 @@ private DebugId GetLambdaId(SyntaxNode syntax, ClosureKind closureKind, int clos
_framePointers.TryGetValue(translatedLambdaContainer, out _innermostFramePointer);
}
if ((object)containerAsFrame != null)
{
_currentTypeParameters = translatedLambdaContainer.TypeParameters;
_currentLambdaBodyTypeMap = ((LambdaFrame)translatedLambdaContainer).TypeMap;
}
else
{
_currentTypeParameters = synthesizedMethod.TypeParameters;
_currentLambdaBodyTypeMap = new TypeMap(_topLevelMethod.TypeParameters, _currentTypeParameters);
}
_currentTypeParameters = translatedLambdaContainer?.TypeParameters.Concat(synthesizedMethod.TypeParameters) ?? synthesizedMethod.TypeParameters;
_currentLambdaBodyTypeMap = synthesizedMethod.TypeMap;
var body = AddStatementsIfNeeded((BoundStatement)VisitBlock(node.Body));
CheckLocalsDefined(body);
......@@ -1218,29 +1249,12 @@ private BoundNode RewriteLambdaConversion(BoundLambda node)
out topLevelMethodId,
out lambdaId);
// Rewrite the lambda expression (and the enclosing anonymous method conversion) as a delegate creation expression
NamedTypeSymbol constructedFrame = (object)containerAsFrame != null ?
translatedLambdaContainer.ConstructIfGeneric(StaticCast<TypeSymbol>.From(_currentTypeParameters)) :
translatedLambdaContainer;
// for instance lambdas, receiver is the frame
// for static lambdas, get the singleton receiver
MethodSymbol referencedMethod = synthesizedMethod;
BoundExpression receiver;
if (closureKind != ClosureKind.Static)
{
receiver = FrameOfType(node.Syntax, constructedFrame);
}
else
{
var field = containerAsFrame.SingletonCache.AsMember(constructedFrame);
receiver = new BoundFieldAccess(node.Syntax, null, field, constantValueOpt: null);
}
NamedTypeSymbol constructedFrame;
RemapLambdaOrLocalFunction(node.Syntax, node.Symbol, default(ImmutableArray<TypeSymbol>), closureKind, ref referencedMethod, out receiver, out constructedFrame);
MethodSymbol referencedMethod = synthesizedMethod.AsMember(constructedFrame);
if (referencedMethod.IsGenericMethod)
{
referencedMethod = referencedMethod.Construct(StaticCast<TypeSymbol>.From(_currentTypeParameters));
}
// Rewrite the lambda expression (and the enclosing anonymous method conversion) as a delegate creation expression
TypeSymbol type = this.VisitType(node.Type);
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Immutable;
using Microsoft.CodeAnalysis.CodeGen;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using System.Diagnostics;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp
{
......@@ -36,19 +37,23 @@ internal sealed class SynthesizedLambdaMethod : SynthesizedMethodBaseSymbol, ISy
ImmutableArray<TypeParameterSymbol> typeParameters;
LambdaFrame lambdaFrame;
if (!topLevelMethod.IsGenericMethod)
lambdaFrame = this.ContainingType as LambdaFrame;
switch (closureKind)
{
typeMap = TypeMap.Empty;
typeParameters = ImmutableArray<TypeParameterSymbol>.Empty;
}
else if ((object)(lambdaFrame = this.ContainingType as LambdaFrame) != null)
{
typeMap = lambdaFrame.TypeMap;
typeParameters = ImmutableArray<TypeParameterSymbol>.Empty;
}
else
{
typeMap = TypeMap.Empty.WithAlphaRename(topLevelMethod, this, out typeParameters);
case ClosureKind.Static: // all type parameters on method (except the top level method's)
Debug.Assert(lambdaFrame != null);
typeMap = lambdaFrame.TypeMap.WithConcatAlphaRename(lambdaNode.Symbol, this, out typeParameters, lambdaFrame.Arity);
break;
case ClosureKind.ThisOnly: // all type parameters on method
Debug.Assert(lambdaFrame == null);
typeMap = TypeMap.Empty.WithConcatAlphaRename(lambdaNode.Symbol, this, out typeParameters);
break;
case ClosureKind.General: // only lambda's type parameters on method (rest on class)
Debug.Assert(lambdaFrame != null);
typeMap = lambdaFrame.TypeMap.WithConcatAlphaRename(lambdaNode.Symbol, this, out typeParameters, lambdaFrame.Arity);
break;
default:
throw ExceptionUtilities.Unreachable;
}
AssignTypeMapAndTypeParameters(typeMap, typeParameters);
......
......@@ -674,6 +674,7 @@ 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>());
}
......
......@@ -13,7 +13,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols
internal abstract class SynthesizedMethodBaseSymbol : SourceMethodSymbol
{
protected readonly MethodSymbol BaseMethod;
protected TypeMap TypeMap { get; private set; }
internal TypeMap TypeMap { get; private set; }
private readonly string _name;
private ImmutableArray<TypeParameterSymbol> _typeParameters;
......
......@@ -46,8 +46,6 @@ internal class LocalFunctionSymbol : MethodSymbol
if (_syntax.TypeParameterList != null)
{
// TODO: Generics are broken. Fix binder issues when allowing generics.
diagnostics.Add(ErrorCode.ERR_InvalidMemberDecl, syntax.TypeParameterList.Location, syntax.TypeParameterList);
binder = new WithMethodTypeParametersBinder(this, binder);
_typeParameters = MakeTypeParameters(diagnostics);
}
......
......@@ -15,19 +15,21 @@ internal class SubstitutedTypeParameterSymbol : TypeParameterSymbol
private readonly Symbol _container;
private readonly TypeMap _map;
private readonly TypeParameterSymbol _substitutedFrom;
private readonly int _ordinal;
#if DEBUG_ALPHA
private static int _nextSequence = 1;
private readonly int _mySequence;
#endif
internal SubstitutedTypeParameterSymbol(Symbol newContainer, TypeMap map, TypeParameterSymbol substitutedFrom)
internal SubstitutedTypeParameterSymbol(Symbol newContainer, TypeMap map, TypeParameterSymbol substitutedFrom, int ordinal)
{
_container = newContainer;
// it is important that we don't use the map here in the constructor, as the map is still being filled
// in by TypeMap.WithAlphaRename. Instead, we can use the map lazily when yielding the constraints.
_map = map;
_substitutedFrom = substitutedFrom;
_ordinal = ordinal;
#if DEBUG_ALPHA
_mySequence = _nextSequence++;
#endif
......@@ -107,7 +109,7 @@ public override int Ordinal
{
get
{
return _substitutedFrom.Ordinal;
return _ordinal;
}
}
......
......@@ -27,13 +27,19 @@ protected SynthesizedContainer(string name, int parameterCount, bool returnsVoid
_typeParameters = CreateTypeParameters(parameterCount, returnsVoid);
}
protected SynthesizedContainer(string name, MethodSymbol topLevelMethod)
protected SynthesizedContainer(string name, MethodSymbol containingMethod)
{
Debug.Assert(name != null);
Debug.Assert(topLevelMethod != null);
_name = name;
_typeMap = TypeMap.Empty.WithAlphaRename(topLevelMethod, this, out _typeParameters);
if (containingMethod == null)
{
_typeMap = TypeMap.Empty;
_typeParameters = ImmutableArray<TypeParameterSymbol>.Empty;
}
else
{
_typeMap = TypeMap.Empty.WithConcatAlphaRename(containingMethod, this, out _typeParameters);
}
}
protected SynthesizedContainer(string name, ImmutableArray<TypeParameterSymbol> typeParameters, TypeMap typeMap)
......
......@@ -7,8 +7,8 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols
/// </summary>
internal sealed class SynthesizedSubstitutedTypeParameterSymbol : SubstitutedTypeParameterSymbol
{
public SynthesizedSubstitutedTypeParameterSymbol(Symbol owner, TypeMap map, TypeParameterSymbol substitutedFrom)
: base(owner, map, substitutedFrom)
public SynthesizedSubstitutedTypeParameterSymbol(Symbol owner, TypeMap map, TypeParameterSymbol substitutedFrom, int ordinal)
: base(owner, map, substitutedFrom, ordinal)
{
}
......
......@@ -36,7 +36,8 @@ internal TypeMap(SmallDictionary<TypeParameterSymbol, TypeSymbol> mapping)
: base(new SmallDictionary<TypeParameterSymbol, TypeSymbol>(mapping, ReferenceEqualityComparer.Instance))
{
// mapping contents are read-only hereafter
Debug.Assert(!mapping.Keys.Any(tp => tp is SubstitutedTypeParameterSymbol));
// This assert fails on generic local functions
//Debug.Assert(!mapping.Keys.Any(tp => tp is SubstitutedTypeParameterSymbol));
}
private static SmallDictionary<TypeParameterSymbol, TypeSymbol> ForType(NamedTypeSymbol containingType)
......@@ -100,13 +101,15 @@ private TypeMap WithAlphaRename(ImmutableArray<TypeParameterSymbol> oldTypeParam
// class or method for a lambda appearing in a generic method.
bool synthesized = !ReferenceEquals(oldTypeParameters[0].ContainingSymbol.OriginalDefinition, newOwner.OriginalDefinition);
int ordinal = 0;
foreach (var tp in oldTypeParameters)
{
var newTp = synthesized ?
new SynthesizedSubstitutedTypeParameterSymbol(newOwner, result, tp) :
new SubstitutedTypeParameterSymbol(newOwner, result, tp);
new SynthesizedSubstitutedTypeParameterSymbol(newOwner, result, tp, ordinal) :
new SubstitutedTypeParameterSymbol(newOwner, result, tp, ordinal);
result.Mapping.Add(tp, newTp);
newTypeParametersBuilder.Add(newTp);
ordinal++;
}
newTypeParameters = newTypeParametersBuilder.ToImmutableAndFree();
......@@ -125,6 +128,41 @@ internal TypeMap WithAlphaRename(MethodSymbol oldOwner, Symbol newOwner, out Imm
return WithAlphaRename(oldOwner.OriginalDefinition.TypeParameters, newOwner, out newTypeParameters);
}
internal TypeMap WithConcatAlphaRename(MethodSymbol oldOwner, Symbol newOwner, out ImmutableArray<TypeParameterSymbol> newTypeParameters, int trimOffAt = 0)
{
Debug.Assert(oldOwner.ConstructedFrom == oldOwner);
// Build the array up backwards, then reverse it.
// The following example goes through the do-loop in order M3, M2, M1
// but the type parameters have to be <T1, T2, T3, T4>
// void M1<T1>() {
// void M2<T2, T3>() {
// void M3<T4>() {
// }
// }
// }
var parameters = ArrayBuilder<TypeParameterSymbol>.GetInstance();
do
{
var currentParameters = oldOwner.OriginalDefinition.TypeParameters;
for (int i = currentParameters.Length - 1; i >= 0; i--)
{
parameters.Add(currentParameters[i]);
}
oldOwner = oldOwner.ContainingSymbol as MethodSymbol;
} while (oldOwner != null);
parameters.ReverseContents();
var finalParameters = parameters.ToImmutableAndFree();
if (trimOffAt != 0)
{
finalParameters = ImmutableArray.Create(finalParameters, trimOffAt, finalParameters.Length - trimOffAt);
}
return WithAlphaRename(finalParameters, newOwner, out newTypeParameters);
}
private static SmallDictionary<TypeParameterSymbol, TypeSymbol> ConstructMapping(ImmutableArray<TypeParameterSymbol> from, ImmutableArray<TypeSymbol> to)
{
SmallDictionary<TypeParameterSymbol, TypeSymbol> mapping = new SmallDictionary<TypeParameterSymbol, TypeSymbol>(ReferenceEqualityComparer.Instance);
......
......@@ -584,54 +584,642 @@ public void Generic()
class Program
{
static void Main(string[] args)
// No closure. Return 'valu'.
static T A1<T>(T val)
{
T Local(T valu)
{
return valu;
}
return Local(val);
}
static int B1(int val)
{
T Local<T>(T valu)
{
return valu;
}
return Local(val);
}
static T1 C1<T1>(T1 val)
{
T Local<T>(T val)
T2 Local<T2>(T2 valu)
{
return valu;
}
return Local<T1>(val);
}
// General closure. Return 'val'.
static T A2<T>(T val)
{
T Local(T valu)
{
return val;
}
Console.WriteLine(Local<int>(2));
return Local(val);
}
static int B2(int val)
{
T Local<T>(T valu)
{
return (T)(object)val;
}
return Local(val);
}
static T1 C2<T1>(T1 val)
{
T2 Local<T2>(T2 valu)
{
return (T2)(object)val;
}
return Local<T1>(val);
}
// This-only closure. Return 'field'.
int field = 2;
T A3<T>(T val)
{
T Local(T valu)
{
return (T)(object)field;
}
return Local(val);
}
int B3(int val)
{
T Local<T>(T valu)
{
return (T)(object)field;
}
return Local(val);
}
T1 C3<T1>(T1 val)
{
T2 Local<T2>(T2 valu)
{
return (T2)(object)field;
}
return Local<T1>(val);
}
static void Main(string[] args)
{
var program = new Program();
Console.WriteLine(Program.A1(2));
Console.WriteLine(Program.B1(2));
Console.WriteLine(Program.C1(2));
Console.WriteLine(Program.A2(2));
Console.WriteLine(Program.B2(2));
Console.WriteLine(Program.C2(2));
Console.WriteLine(program.A3(2));
Console.WriteLine(program.B3(2));
Console.WriteLine(program.C3(2));
}
}
";
// TODO: Eventually support this
var option = TestOptions.ReleaseExe.WithWarningLevel(0);
CreateCompilationWithMscorlibAndSystemCore(source, options: option, parseOptions: _parseOptions).VerifyDiagnostics(
// (8,16): error CS1519: Invalid token '<T>' in class, struct, or interface member declaration
// T Local<T>(T val)
Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "<T>").WithArguments("<T>").WithLocation(8, 16)
);
var compilation = CreateCompilationWithMscorlib45(source,
options: new CSharpCompilationOptions(OutputKind.ConsoleApplication),
parseOptions: _parseOptions);
var comp = CompileAndVerify(compilation, expectedOutput: @"
2
2
2
2
2
2
2
2
2
");
}
[Fact]
public void GenericClosure()
public void GenericTripleNestedNoClosure()
{
var source = @"
using System;
using System.Collections.Generic;
class Program
{
static T Outer<T>(T val)
// Name of method is T[outer][middle][inner] where brackets are g=generic n=nongeneric
// One generic
static T1 Tgnn<T1>(T1 a)
{
T Local(T valu)
T1 Local(T1 aa)
{
return valu;
T1 Local2(T1 aaa)
{
return aaa;
}
return Local2(aa);
}
return Local(val);
return Local(a);
}
static int Tngn(int a)
{
T1 Local<T1>(T1 aa)
{
T1 Local2(T1 aaa)
{
return aaa;
}
return Local2(aa);
}
return Local(a);
}
static int Tnng(int a)
{
int Local(int aa)
{
T1 Local2<T1>(T1 aaa)
{
return aaa;
}
return Local2(aa);
}
return Local(a);
}
// Two generic
static T1 Tggn<T1>(T1 a)
{
T2 Local<T2>(T2 aa)
{
T2 Local2(T2 aaa)
{
return aaa;
}
return Local2(aa);
}
return Local(a);
}
static T1 Tgng<T1>(T1 a)
{
T1 Local(T1 aa)
{
T2 Local2<T2>(T2 aaa)
{
return aaa;
}
return Local2(aa);
}
return Local(a);
}
static int Tngg(int a)
{
T1 Local<T1>(T1 aa)
{
T2 Local2<T2>(T2 aaa)
{
return aaa;
}
return Local2(aa);
}
return Local(a);
}
// Three generic
static T1 Tggg<T1>(T1 a)
{
T2 Local<T2>(T2 aa)
{
T3 Local2<T3>(T3 aaa)
{
return aaa;
}
return Local2(aa);
}
return Local(a);
}
static void Main(string[] args)
{
Console.WriteLine(Outer(2));
Console.WriteLine(Program.Tgnn(2));
Console.WriteLine(Program.Tngn(2));
Console.WriteLine(Program.Tnng(2));
Console.WriteLine(Program.Tggn(2));
Console.WriteLine(Program.Tgng(2));
Console.WriteLine(Program.Tngg(2));
Console.WriteLine(Program.Tggg(2));
}
}
";
var comp = CreateCompilationWithMscorlib(source, options: TestOptions.ReleaseExe, parseOptions: _parseOptions);
var verify = CompileAndVerify(comp, expectedOutput: @"
var compilation = CreateCompilationWithMscorlib45(source,
options: new CSharpCompilationOptions(OutputKind.ConsoleApplication),
parseOptions: _parseOptions);
var comp = CompileAndVerify(compilation, expectedOutput: @"
2
2
2
2
2
2
2
");
}
[Fact]
public void GenericTripleNestedMiddleClosure()
{
var source = @"
using System;
class Program
{
// Name of method is T[outer][middle][inner] where brackets are g=generic n=nongeneric
// One generic
static T1 Tgnn<T1>(T1 a)
{
T1 Local(T1 aa)
{
T1 Local2(T1 aaa)
{
return (T1)(object)aa;
}
return Local2(aa);
}
return Local(a);
}
static int Tngn(int a)
{
T1 Local<T1>(T1 aa)
{
T1 Local2(T1 aaa)
{
return (T1)(object)aa;
}
return Local2(aa);
}
return Local(a);
}
static int Tnng(int a)
{
int Local(int aa)
{
T1 Local2<T1>(T1 aaa)
{
return (T1)(object)aa;
}
return Local2(aa);
}
return Local(a);
}
// Two generic
static T1 Tggn<T1>(T1 a)
{
T2 Local<T2>(T2 aa)
{
T2 Local2(T2 aaa)
{
return (T2)(object)aa;
}
return Local2(aa);
}
return Local(a);
}
static T1 Tgng<T1>(T1 a)
{
T1 Local(T1 aa)
{
T2 Local2<T2>(T2 aaa)
{
return (T2)(object)aa;
}
return Local2(aa);
}
return Local(a);
}
static int Tngg(int a)
{
T1 Local<T1>(T1 aa)
{
T2 Local2<T2>(T2 aaa)
{
return (T2)(object)aa;
}
return Local2(aa);
}
return Local(a);
}
// Three generic
static T1 Tggg<T1>(T1 a)
{
T2 Local<T2>(T2 aa)
{
T3 Local2<T3>(T3 aaa)
{
return (T3)(object)aa;
}
return Local2(aa);
}
return Local(a);
}
static void Main(string[] args)
{
Console.WriteLine(Program.Tgnn(2));
Console.WriteLine(Program.Tngn(2));
Console.WriteLine(Program.Tnng(2));
Console.WriteLine(Program.Tggn(2));
Console.WriteLine(Program.Tgng(2));
Console.WriteLine(Program.Tngg(2));
Console.WriteLine(Program.Tggg(2));
}
}
";
var compilation = CreateCompilationWithMscorlib45(source,
options: new CSharpCompilationOptions(OutputKind.ConsoleApplication),
parseOptions: _parseOptions);
var comp = CompileAndVerify(compilation, expectedOutput: @"
2
2
2
2
2
2
2
");
}
[Fact]
public void GenericTripleNestedOuterClosure()
{
var source = @"
using System;
class Program
{
// Name of method is T[outer][middle][inner] where brackets are g=generic n=nongeneric
// One generic
static T1 Tgnn<T1>(T1 a)
{
T1 Local(T1 aa)
{
T1 Local2(T1 aaa)
{
return (T1)(object)a;
}
return Local2(aa);
}
return Local(a);
}
static int Tngn(int a)
{
T1 Local<T1>(T1 aa)
{
T1 Local2(T1 aaa)
{
return (T1)(object)a;
}
return Local2(aa);
}
return Local(a);
}
static int Tnng(int a)
{
int Local(int aa)
{
T1 Local2<T1>(T1 aaa)
{
return (T1)(object)a;
}
return Local2(aa);
}
return Local(a);
}
// Two generic
static T1 Tggn<T1>(T1 a)
{
T2 Local<T2>(T2 aa)
{
T2 Local2(T2 aaa)
{
return (T2)(object)a;
}
return Local2(aa);
}
return Local(a);
}
static T1 Tgng<T1>(T1 a)
{
T1 Local(T1 aa)
{
T2 Local2<T2>(T2 aaa)
{
return (T2)(object)a;
}
return Local2(aa);
}
return Local(a);
}
static int Tngg(int a)
{
T1 Local<T1>(T1 aa)
{
T2 Local2<T2>(T2 aaa)
{
return (T2)(object)a;
}
return Local2(aa);
}
return Local(a);
}
// Three generic
static T1 Tggg<T1>(T1 a)
{
T2 Local<T2>(T2 aa)
{
T3 Local2<T3>(T3 aaa)
{
return (T3)(object)a;
}
return Local2(aa);
}
return Local(a);
}
static void Main(string[] args)
{
Console.WriteLine(Program.Tgnn(2));
Console.WriteLine(Program.Tngn(2));
Console.WriteLine(Program.Tnng(2));
Console.WriteLine(Program.Tggn(2));
Console.WriteLine(Program.Tgng(2));
Console.WriteLine(Program.Tngg(2));
Console.WriteLine(Program.Tggg(2));
}
}
";
var compilation = CreateCompilationWithMscorlib45(source,
options: new CSharpCompilationOptions(OutputKind.ConsoleApplication),
parseOptions: _parseOptions);
var comp = CompileAndVerify(compilation, expectedOutput: @"
2
2
2
2
2
2
2
");
}
[Fact]
public void GenericTripleNestedNoClosureLambda()
{
var source = @"
using System;
class Program
{
// Name of method is T[outer][middle][inner] where brackets are g=generic n=nongeneric
// One generic
static T1 Tgnn<T1>(T1 a)
{
Func<T1, T1> Local = aa =>
{
Func<T1, T1> Local2 = aaa =>
{
return aaa;
};
return Local2(aa);
};
return Local(a);
}
static int Tngn(int a)
{
T1 Local<T1>(T1 aa)
{
Func<T1, T1> Local2 = aaa =>
{
return aaa;
};
return Local2(aa);
}
return Local(a);
}
static int Tnng(int a)
{
Func<int, int> Local = aa =>
{
T1 Local2<T1>(T1 aaa)
{
return aaa;
}
return Local2(aa);
};
return Local(a);
}
// Two generic
static T1 Tggn<T1>(T1 a)
{
T2 Local<T2>(T2 aa)
{
Func<T2, T2> Local2 = aaa =>
{
return aaa;
};
return Local2(aa);
}
return Local(a);
}
static T1 Tgng<T1>(T1 a)
{
Func<T1, T1> Local = aa =>
{
T2 Local2<T2>(T2 aaa)
{
return aaa;
}
return Local2(aa);
};
return Local(a);
}
// Tngg and Tggg are impossible with lambdas
static void Main(string[] args)
{
Console.WriteLine(Program.Tgnn(2));
Console.WriteLine(Program.Tngn(2));
Console.WriteLine(Program.Tnng(2));
Console.WriteLine(Program.Tggn(2));
Console.WriteLine(Program.Tgng(2));
}
}
";
var compilation = CreateCompilationWithMscorlib45(source,
options: new CSharpCompilationOptions(OutputKind.ConsoleApplication),
parseOptions: _parseOptions);
var comp = CompileAndVerify(compilation, expectedOutput: @"
2
2
2
2
2
");
}
[Fact]
public void GenericUpperCall()
{
var source = @"
using System;
class Program
{
static T1 InnerToOuter<T1>(T1 a)
{
T2 Local<T2>(T2 aa)
{
T3 Local2<T3>(T3 aaa)
{
if ((object)aaa == null)
return InnerToOuter((T3)new object());
return aaa;
}
return Local2(aa);
}
return Local(a);
}
static T1 InnerToMiddle<T1>(T1 a)
{
T2 Local<T2>(T2 aa)
{
T3 Local2<T3>(T3 aaa)
{
if ((object)aaa == null)
return InnerToMiddle((T3)new object());
return aaa;
}
return Local2(aa);
}
return Local(a);
}
static T1 InnerToOuterScoping<T1>(T1 a)
{
T2 Local<T2>(T2 aa)
{
T3 Local2<T3>(T3 aaa)
{
if ((object)aaa == null)
return (T3)(object)InnerToOuter((T1)new object());
return aaa;
}
return Local2(aa);
}
return Local(a);
}
// Tngg and Tggg are impossible with lambdas
static void Main(string[] args)
{
Console.WriteLine(Program.InnerToOuter((object)null));
Console.WriteLine(Program.InnerToMiddle((object)null));
Console.WriteLine(Program.InnerToOuterScoping((object)null));
}
}
";
var compilation = CreateCompilationWithMscorlib45(source,
options: new CSharpCompilationOptions(OutputKind.ConsoleApplication),
parseOptions: _parseOptions);
var comp = CompileAndVerify(compilation, expectedOutput: @"
System.Object
System.Object
System.Object
");
}
[Fact]
public void Shadows()
{
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册