Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Label="Settings">
<Import Project="..\..\..\..\Tools\Microsoft.CodeAnalysis.Toolset.Open\Targets\VSL.Settings.targets" />
<Import Project="..\..\..\..\..\build\VSL.Settings.Closed.targets" />
</ImportGroup>
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{FD6BA96C-7905-4876-8BCC-E38E2CA64F31}</ProjectGuid>
<OutputType>Library</OutputType>
<RootNamespace>Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator</RootNamespace>
<AssemblyName>Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator.ExpressionCompiler</AssemblyName>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<SolutionDir Condition="'$(SolutionDir)' == '' OR '$(SolutionDir)' == '*Undefined*'">..\..\..\..\..\</SolutionDir>
<UseCommonOutputDirectory>True</UseCommonOutputDirectory>
<RestorePackages>true</RestorePackages>
<!-- Don't transitively copy output files, since everything builds to the same folder. -->
</PropertyGroup>
<ItemGroup Label="File References">
<Reference Include="$(OutDir)Microsoft.VisualStudio.Debugger.Engine.dll" />
<Reference Include="System.Reflection.Metadata, Version=1.0.18.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\packages\System.Reflection.Metadata.1.0.18-beta\lib\portable-net45+win8\System.Reflection.Metadata.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup Label="Project References">
<ProjectReference Include="..\..\..\Core\Source\Concord\Concord.csproj">
<Project>{5002636a-fe8d-40bf-8818-ab513a2194fa}</Project>
<Name>Concord</Name>
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
</ProjectReference>
<ProjectReference Include="..\..\..\..\Compilers\Core\Desktop\CodeAnalysis.Desktop.csproj">
<Project>{dfa21ca1-7f96-47ee-940c-069858e81727}</Project>
<Name>CodeAnalysis.Desktop</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\..\Compilers\Core\Portable\CodeAnalysis.csproj">
<Project>{1EE8CAD3-55F9-4D91-96B2-084641DA9A6C}</Project>
<Name>CodeAnalysis</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\..\Compilers\CSharp\Portable\CSharpCodeAnalysis.csproj">
<Project>{B501A547-C911-4A05-AC6E-274A50DFF30E}</Project>
<Name>CSharpCodeAnalysis</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\Core\Source\ExpressionCompiler\ExpressionCompiler.csproj">
<Project>{b8da3a90-a60c-42e3-9d8e-6c67b800c395}</Project>
<Name>ExpressionCompiler</Name>
</ProjectReference>
</ItemGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DefineConstants>TRACE;DEBUG</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Collections.Immutable, Version=1.1.33.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\packages\System.Collections.Immutable.1.1.33-beta\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath>
</Reference>
<Reference Include="System.Core" />
</ItemGroup>
<ItemGroup>
<Compile Include="Binders\EEMethodBinder.cs" />
<Compile Include="Binders\WithTypeArgumentsBinder.cs" />
<Compile Include="Binders\PlaceholderLocalBinder.cs" />
<Compile Include="CompilationContext.cs" />
<Compile Include="CompilationExtensions.cs" />
<Compile Include="CSharpLanguageInstructionDecoder.cs" />
<Compile Include="CSharpMetadataContext.cs" />
<Compile Include="CSharpExpressionCompiler.cs" />
<Compile Include="CSharpFrameDecoder.cs" />
<Compile Include="CSharpInstructionDecoder.cs" />
<Compile Include="EEAssemblyBuilder.cs" />
<Compile Include="EETypeNameDecoder.cs" />
<Compile Include="EvaluationContext.cs" />
<Compile Include="InternalsVisibleTo.cs" />
<Compile Include="Rewriters\CapturedVariableRewriter.cs" />
<Compile Include="Rewriters\LocalDeclarationRewriter.cs" />
<Compile Include="Rewriters\MayHaveSideEffectsVisitor.cs" />
<Compile Include="Rewriters\PlaceholderLocalRewriter.cs" />
<Compile Include="Symbols\DisplayClassInstance.cs" />
<Compile Include="Symbols\DisplayClassVariable.cs" />
<Compile Include="Symbols\EEDisplayClassFieldLocalSymbol.cs" />
<Compile Include="Symbols\EELocalConstantSymbol.cs" />
<Compile Include="Symbols\EELocalSymbol.cs" />
<Compile Include="Symbols\EELocalSymbolBase.cs" />
<Compile Include="Symbols\EEConstructorSymbol.cs" />
<Compile Include="Symbols\EEMethodSymbol.cs" />
<Compile Include="Symbols\EENamedTypeSymbol.cs" />
<Compile Include="Symbols\EETypeParameterSymbol.cs" />
<Compile Include="Symbols\ObjectAddressLocalSymbol.cs" />
<Compile Include="Symbols\ObjectIdLocalSymbol.cs" />
<Compile Include="Symbols\PlaceholderLocalSymbol.cs" />
<Compile Include="Symbols\PlaceholderMethodSymbol.cs" />
<Compile Include="Symbols\ExceptionLocalSymbol.cs" />
<Compile Include="Symbols\ReturnValueLocalSymbol.cs" />
<Compile Include="Symbols\SimpleTypeParameterSymbol.cs" />
<Compile Include="Symbols\SynthesizedContextMethodSymbol.cs" />
<Compile Include="SyntaxHelpers.cs" />
<Compile Include="TypeParameterChecker.cs" />
<VsdConfigXml Include="CSharpExpressionCompiler.vsdconfigxml" />
</ItemGroup>
<ItemGroup>
<InternalsVisibleToTest Include="Roslyn.ExpressionEvaluator.CSharp.ExpressionCompiler.UnitTests" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<ImportGroup Label="Targets">
<Import Project="..\..\..\..\Tools\Vsdconfig\Vsdconfig.targets" />
<Import Project="..\..\..\..\Tools\Microsoft.CodeAnalysis.Toolset.Open\Targets\VSL.Imports.targets" />
<Import Project="..\..\..\..\..\build\VSL.Imports.Closed.targets" />
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
</ImportGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (c) Microsoft Corporation. All rights reserved.
-->
<Configuration xmlns="http://schemas.microsoft.com/vstudio/vsdconfig/2008">
<DefineGuid Name="CSharpExpressionCompilerId" Value="CFC88282-E29A-47A1-9FAD-E46391CBD26D"/>
<ManagedComponent
ComponentId="CSharpExpressionCompilerId"
ComponentLevel="9991500"
Synchronized="true"
AssemblyName="Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator.ExpressionCompiler">
<Class Name="Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator.CSharpExpressionCompiler">
<Implements>
<InterfaceGroup Priority="Low">
<NoFilter/>
<Interface Name="IDkmClrExpressionCompiler"/>
<Interface Name="IDkmClrExpressionCompilerCallback"/>
</InterfaceGroup>
<InterfaceGroup
CallOnlyWhenLoaded="true">
<NoFilter/>
<Interface Name="IDkmModuleModifiedNotification"/>
</InterfaceGroup>
</Implements>
</Class>
<Class Name="Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator.CSharpFrameDecoder">
<Implements>
<InterfaceGroup Priority="Low">
<Filter>
<RuntimeId RequiredValue="DkmRuntimeId.Clr"/>
</Filter>
<Interface Name="IDkmLanguageFrameDecoder"/>
</InterfaceGroup>
</Implements>
</Class>
<Class Name="Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator.CSharpLanguageInstructionDecoder">
<Implements>
<InterfaceGroup Priority="Low">
<Filter>
<RuntimeId RequiredValue="DkmRuntimeId.Clr"/>
</Filter>
<Interface Name="IDkmLanguageInstructionDecoder"/>
</InterfaceGroup>
</Implements>
</Class>
</ManagedComponent>
</Configuration>
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// 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 Microsoft.CodeAnalysis.ExpressionEvaluator;

namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator
{
[DkmReportNonFatalWatsonException(ExcludeExceptionType = typeof(NotImplementedException)), DkmContinueCorruptingException]
internal sealed class CSharpFrameDecoder : FrameDecoder
{
public CSharpFrameDecoder()
: base(CSharpInstructionDecoder.Instance)
{
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
// 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.Text;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE;
using Microsoft.CodeAnalysis.ExpressionEvaluator;
using Microsoft.VisualStudio.Debugger;
using Microsoft.VisualStudio.Debugger.Clr;

namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator
{
internal sealed class CSharpInstructionDecoder : InstructionDecoder<PEMethodSymbol>
{
// This string was not localized in the old EE. We'll keep it that way
// so as not to break consumers who may have been parsing frame names...
private const string AnonymousMethodName = "AnonymousMethod";

/// <summary>
/// Singleton instance of <see cref="CSharpInstructionDecoder"/> (created using default constructor).
/// </summary>
internal static readonly CSharpInstructionDecoder Instance = new CSharpInstructionDecoder();

private CSharpInstructionDecoder()
{
}

private static readonly SymbolDisplayFormat s_propertyDisplayFormat = DisplayFormat.
AddMemberOptions(SymbolDisplayMemberOptions.IncludeParameters).
WithParameterOptions(SymbolDisplayParameterOptions.IncludeType);

internal override void AppendFullName(StringBuilder builder, PEMethodSymbol method)
{
var displayFormat =
((method.MethodKind == MethodKind.PropertyGet) || (method.MethodKind == MethodKind.PropertySet)) ?
s_propertyDisplayFormat :
DisplayFormat;

var parts = method.ToDisplayParts(displayFormat);
var numParts = parts.Length;
for (int i = 0; i < numParts; i++)
{
var part = parts[i];
var displayString = part.ToString();

switch (part.Kind)
{
case SymbolDisplayPartKind.ClassName:
if (GeneratedNames.GetKind(displayString) != GeneratedNameKind.LambdaDisplayClass)
{
builder.Append(displayString);
}
else
{
// Drop any remaining display class name parts and the subsequent dot...
do
{
i++;
}
while ((i < numParts) && parts[i].Kind != SymbolDisplayPartKind.MethodName);
i--;
}
break;
case SymbolDisplayPartKind.MethodName:
GeneratedNameKind kind;
int openBracketOffset, closeBracketOffset;
if (GeneratedNames.TryParseGeneratedName(displayString, out kind, out openBracketOffset, out closeBracketOffset) &&
(kind == GeneratedNameKind.LambdaMethod))
{
builder.Append(displayString, openBracketOffset + 1, closeBracketOffset - openBracketOffset - 1); // source method name
builder.Append('.');
builder.Append(AnonymousMethodName);
// NOTE: The old implementation only appended the first ordinal number. Since this is not useful
// in uniquely identifying the lambda, we'll append the entire ordinal suffix (which may contain
// multiple numbers, as well as '-' or '_').
builder.Append(displayString.Substring(closeBracketOffset + 2)); // ordinal suffix (e.g. "__1")
}
else
{
builder.Append(displayString);
}
break;
default:
builder.Append(displayString);
break;
}
}
}

internal override PEMethodSymbol GetMethod(DkmClrInstructionAddress instructionAddress)
{
var moduleInstance = instructionAddress.ModuleInstance;
var appDomain = moduleInstance.AppDomain;
var previous = appDomain.GetDataItem<CSharpMetadataContext>();
var metadataBlocks = instructionAddress.Process.GetMetadataBlocks(appDomain);

CSharpCompilation compilation;
if (metadataBlocks.HaveNotChanged(previous))
{
compilation = previous.Compilation;
}
else
{
var dataItem = new CSharpMetadataContext(metadataBlocks);
appDomain.SetDataItem(DkmDataCreationDisposition.CreateAlways, dataItem);
compilation = dataItem.Compilation;
}

return compilation.GetSourceMethod(moduleInstance.Mvid, instructionAddress.MethodId.Token);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// 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 Microsoft.CodeAnalysis.ExpressionEvaluator;
using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE;

namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator
{
[DkmReportNonFatalWatsonException(ExcludeExceptionType = typeof(NotImplementedException)), DkmContinueCorruptingException]
internal sealed class CSharpLanguageInstructionDecoder : LanguageInstructionDecoder<PEMethodSymbol>
{
public CSharpLanguageInstructionDecoder()
: base(CSharpInstructionDecoder.Instance)
{
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// 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.Collections.Immutable;
using Microsoft.CodeAnalysis.ExpressionEvaluator;

namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator
{
internal sealed class CSharpMetadataContext : MetadataContext
{
internal readonly CSharpCompilation Compilation;
internal readonly EvaluationContext EvaluationContext;

internal CSharpMetadataContext(ImmutableArray<MetadataBlock> metadataBlocks)
: base(metadataBlocks)
{
this.Compilation = metadataBlocks.ToCompilation();
}

internal CSharpMetadataContext(EvaluationContext evaluationContext)
: base(evaluationContext.MetadataBlocks)
{
this.Compilation = evaluationContext.Compilation;
this.EvaluationContext = evaluationContext;
}
}
}
1,500 changes: 1,500 additions & 0 deletions src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/CompilationContext.cs

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
// 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 System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE;
using Microsoft.CodeAnalysis.ExpressionEvaluator;

namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator
{
internal static class CompilationExtensions
{
private static PENamedTypeSymbol GetType(PEModuleSymbol module, TypeDefinitionHandle typeHandle)
{
var metadataDecoder = new MetadataDecoder(module);
return (PENamedTypeSymbol)metadataDecoder.GetTypeOfToken(typeHandle);
}

internal static PENamedTypeSymbol GetType(this CSharpCompilation compilation, Guid moduleVersionId, int typeToken, out MetadataDecoder metadataDecoder)
{
var module = compilation.GetModule(moduleVersionId);
var reader = module.Module.MetadataReader;
var typeHandle = (TypeDefinitionHandle)MetadataTokens.Handle(typeToken);
var type = GetType(module, typeHandle);
metadataDecoder = new MetadataDecoder(module, type);
return type;
}

internal static PEMethodSymbol GetSourceMethod(this CSharpCompilation compilation, Guid moduleVersionId, int methodToken)
{
var methodHandle = (MethodDefinitionHandle)MetadataTokens.Handle(methodToken);
var method = GetMethod(compilation, moduleVersionId, methodHandle);
var metadataDecoder = new MetadataDecoder((PEModuleSymbol)method.ContainingModule);
var containingType = method.ContainingType;
string sourceMethodName;
if (GeneratedNames.TryParseSourceMethodNameFromGeneratedName(containingType.Name, GeneratedNameKind.StateMachineType, out sourceMethodName))
{
foreach (var member in containingType.ContainingType.GetMembers(sourceMethodName))
{
var candidateMethod = member as PEMethodSymbol;
if (candidateMethod != null)
{
var module = metadataDecoder.Module;
methodHandle = candidateMethod.Handle;
string stateMachineTypeName;
if (module.HasStringValuedAttribute(methodHandle, AttributeDescription.AsyncStateMachineAttribute, out stateMachineTypeName) ||
module.HasStringValuedAttribute(methodHandle, AttributeDescription.IteratorStateMachineAttribute, out stateMachineTypeName))
{
if (metadataDecoder.GetTypeSymbolForSerializedType(stateMachineTypeName).OriginalDefinition.Equals(containingType))
{
return candidateMethod;
}
}
}
}
}
return method;
}

internal static PEMethodSymbol GetMethod(this CSharpCompilation compilation, Guid moduleVersionId, MethodDefinitionHandle methodHandle)
{
var module = compilation.GetModule(moduleVersionId);
var reader = module.Module.MetadataReader;
var typeHandle = reader.GetMethodDefinition(methodHandle).GetDeclaringType();
var type = GetType(module, typeHandle);
var method = (PEMethodSymbol)new MetadataDecoder(module, type).GetMethodSymbolForMethodDefOrMemberRef(methodHandle, type);
return method;
}

internal static PEModuleSymbol GetModule(this CSharpCompilation compilation, Guid moduleVersionId)
{
foreach (var pair in compilation.GetBoundReferenceManager().GetReferencedAssemblies())
{
var assembly = (AssemblySymbol)pair.Value;
foreach (var module in assembly.Modules)
{
var m = (PEModuleSymbol)module;
var id = m.Module.GetModuleVersionIdOrThrow();
if (id == moduleVersionId)
{
return m;
}
}
}

return null;
}

internal static CSharpCompilation ToCompilation(this ImmutableArray<MetadataBlock> metadataBlocks)
{
return CSharpCompilation.Create(
assemblyName: ExpressionCompilerUtilities.GenerateUniqueName(),
references: metadataBlocks.MakeAssemblyReferences(),
options: s_compilationOptions);
}

// XML file references, #r directives not supported:
private static readonly CSharpCompilationOptions s_compilationOptions = new CSharpCompilationOptions(
outputKind: OutputKind.DynamicallyLinkedLibrary,
allowUnsafe: true,
platform: Platform.AnyCpu, // Platform should match PEModule.Machine, in this case I386.
optimizationLevel: OptimizationLevel.Release,
assemblyIdentityComparer: DesktopAssemblyIdentityComparer.Default).
WithMetadataImportOptions(MetadataImportOptions.All);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
// 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 Microsoft.Cci;
using Microsoft.CodeAnalysis.CodeGen;
using Microsoft.CodeAnalysis.CSharp.Emit;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE;
using Microsoft.CodeAnalysis.Emit;
using Microsoft.CodeAnalysis.ExpressionEvaluator;
using Roslyn.Utilities;
using System.Collections.Immutable;
using System.Diagnostics;

namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator
{
internal sealed class EEAssemblyBuilder : PEAssemblyBuilderBase
{
private readonly ImmutableHashSet<MethodSymbol> _methods;

public EEAssemblyBuilder(
SourceAssemblySymbol sourceAssembly,
EmitOptions emitOptions,
ImmutableArray<MethodSymbol> methods,
ModulePropertiesForSerialization serializationProperties,
ImmutableArray<NamedTypeSymbol> additionalTypes,
CompilationTestData testData) :
base(
sourceAssembly,
emitOptions,
outputKind: OutputKind.DynamicallyLinkedLibrary,
serializationProperties: serializationProperties,
manifestResources: SpecializedCollections.EmptyEnumerable<ResourceDescription>(),
assemblySymbolMapper: null,
additionalTypes: additionalTypes)
{
_methods = ImmutableHashSet.CreateRange(methods);

if (testData != null)
{
this.SetMethodTestData(testData.Methods);
testData.Module = this;
}
}

protected override IModuleReference TranslateModule(ModuleSymbol symbol, DiagnosticBag diagnostics)
{
var moduleSymbol = symbol as PEModuleSymbol;
if ((object)moduleSymbol != null)
{
var module = moduleSymbol.Module;
// Expose the individual runtime Windows.*.winmd modules as assemblies.
// (The modules were wrapped in a placeholder Windows.winmd assembly
// in MetadataUtilities.MakeAssemblyReferences.)
if (MetadataUtilities.IsWindowsComponent(module.MetadataReader, module.Name) &&
MetadataUtilities.IsWindowsAssemblyName(moduleSymbol.ContainingAssembly.Name))
{
var identity = module.ReadAssemblyIdentityOrThrow();
return new Microsoft.CodeAnalysis.ExpressionEvaluator.AssemblyReference(identity);
}
}
return base.TranslateModule(symbol, diagnostics);
}

public override int CurrentGenerationOrdinal => 0;

internal override VariableSlotAllocator TryCreateVariableSlotAllocator(MethodSymbol symbol)
{
var method = symbol as EEMethodSymbol;
if (((object)method != null) && _methods.Contains(method))
{
var defs = GetLocalDefinitions(method.Locals);
return new SlotAllocator(defs);
}

Debug.Assert(!_methods.Contains(symbol));
return null;
}

private static ImmutableArray<LocalDefinition> GetLocalDefinitions(ImmutableArray<LocalSymbol> locals)
{
var builder = ArrayBuilder<LocalDefinition>.GetInstance();
foreach (var local in locals)
{
if (local.DeclarationKind == LocalDeclarationKind.Constant)
{
continue;
}
var def = ToLocalDefinition(local, builder.Count);
Debug.Assert(((EELocalSymbol)local).Ordinal == def.SlotIndex);
builder.Add(def);
}
return builder.ToImmutableAndFree();
}

private static LocalDefinition ToLocalDefinition(LocalSymbol local, int index)
{
// See EvaluationContext.GetLocals.
TypeSymbol type;
LocalSlotConstraints constraints;
if (local.DeclarationKind == LocalDeclarationKind.FixedVariable)
{
type = ((PointerTypeSymbol)local.Type).PointedAtType;
constraints = LocalSlotConstraints.ByRef | LocalSlotConstraints.Pinned;
}
else
{
type = local.Type;
constraints = (local.IsPinned ? LocalSlotConstraints.Pinned : LocalSlotConstraints.None) |
((local.RefKind == RefKind.None) ? LocalSlotConstraints.None : LocalSlotConstraints.ByRef);
}
return new LocalDefinition(
local,
local.Name,
(Cci.ITypeReference)type,
slot: index,
synthesizedKind: (SynthesizedLocalKind)local.SynthesizedKind,
id: LocalDebugId.None,
pdbAttributes: Cci.PdbWriter.DefaultLocalAttributesValue,
constraints: constraints,
isDynamic: false,
dynamicTransformFlags: ImmutableArray<TypedConstant>.Empty);
}

private sealed class SlotAllocator : VariableSlotAllocator
{
private readonly ImmutableArray<LocalDefinition> _locals;

internal SlotAllocator(ImmutableArray<LocalDefinition> locals)
{
_locals = locals;
}

public override void AddPreviousLocals(ArrayBuilder<Cci.ILocalDefinition> builder)
{
builder.AddRange(_locals);
}

public override LocalDefinition GetPreviousLocal(
Cci.ITypeReference type,
ILocalSymbolInternal symbol,
string nameOpt,
SynthesizedLocalKind synthesizedKind,
LocalDebugId id,
uint pdbAttributes,
LocalSlotConstraints constraints,
bool isDynamic,
ImmutableArray<TypedConstant> dynamicTransformFlags)
{
var local = symbol as EELocalSymbol;
if ((object)local == null)
{
return null;
}

return _locals[local.Ordinal];
}

public override string PreviousStateMachineTypeName
{
get { return null; }
}

public override bool TryGetPreviousHoistedLocalSlotIndex(SyntaxNode currentDeclarator, Cci.ITypeReference currentType, SynthesizedLocalKind synthesizedKind, LocalDebugId currentId, out int slotIndex)
{
slotIndex = -1;
return false;
}

public override int PreviousHoistedLocalSlotCount
{
get { return 0; }
}

public override bool TryGetPreviousAwaiterSlotIndex(Cci.ITypeReference currentType, out int slotIndex)
{
slotIndex = -1;
return false;
}

public override bool TryGetPreviousClosure(SyntaxNode closureSyntax, out int closureOrdinal)
{
closureOrdinal = -1;
return false;
}

public override bool TryGetPreviousLambda(SyntaxNode lambdaOrLambdaBodySyntax, bool isLambdaBody, out int lambdaOrdinal)
{
lambdaOrdinal = -1;
return false;
}

public override int PreviousAwaiterSlotCount
{
get { return 0; }
}

public override MethodDebugId PreviousMethodId
{
get
{
return default(MethodDebugId);
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// 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.Collections.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE;
using Microsoft.CodeAnalysis.ExpressionEvaluator;

namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator
{
internal sealed class EETypeNameDecoder : TypeNameDecoder<PEModuleSymbol, TypeSymbol>
{
private readonly CSharpCompilation _compilation;

internal EETypeNameDecoder(CSharpCompilation compilation, PEModuleSymbol moduleSymbol) :
base(SymbolFactory.Instance, moduleSymbol)
{
_compilation = compilation;
}

protected override int GetIndexOfReferencedAssembly(AssemblyIdentity identity)
{
var assemblies = this.GetAssemblies();
// Find assembly matching identity.
int index = assemblies.IndexOf((assembly, id) => id.Equals(assembly.Identity), identity);
if (index >= 0)
{
return index;
}
if (identity.IsWindowsComponent())
{
// Find placeholder Windows.winmd assembly (created
// in MetadataUtilities.MakeAssemblyReferences).
index = assemblies.IndexOf((assembly, unused) => assembly.Identity.IsWindowsRuntime(), (object)null);
if (index >= 0)
{
// Find module in Windows.winmd matching identity.
var modules = assemblies[index].Modules;
var moduleIndex = modules.IndexOf((m, id) => id.Equals(GetComponentAssemblyIdentity(m)), identity);
if (moduleIndex >= 0)
{
return index;
}
}
}
return -1;
}

protected override bool IsContainingAssembly(AssemblyIdentity identity)
{
return false;
}

protected override TypeSymbol LookupNestedTypeDefSymbol(TypeSymbol container, ref MetadataTypeName emittedName)
{
return container.LookupMetadataType(ref emittedName);
}

protected override TypeSymbol LookupTopLevelTypeDefSymbol(int referencedAssemblyIndex, ref MetadataTypeName emittedName)
{
var assembly = this.GetAssemblies()[referencedAssemblyIndex];
return assembly.LookupTopLevelMetadataType(ref emittedName, digThroughForwardedTypes: true);
}

protected override TypeSymbol LookupTopLevelTypeDefSymbol(ref MetadataTypeName emittedName, out bool isNoPiaLocalType)
{
return this.moduleSymbol.LookupTopLevelMetadataType(ref emittedName, out isNoPiaLocalType);
}

private ImmutableArray<AssemblySymbol> GetAssemblies()
{
return _compilation.Assembly.Modules.Single().GetReferencedAssemblySymbols();
}

private static AssemblyIdentity GetComponentAssemblyIdentity(ModuleSymbol module)
{
return ((PEModuleSymbol)module).Module.ReadAssemblyIdentityOrThrow();
}
}
}

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// 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.Runtime.CompilerServices;

[assembly: InternalsVisibleTo("Microsoft.VisualStudio.ProductionBreakpoints.CodeAnalysis, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")]
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
// 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 Microsoft.CodeAnalysis.CSharp.Symbols;
using Roslyn.Utilities;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;

namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator
{
internal sealed class CapturedVariableRewriter : BoundTreeRewriter
{
internal static BoundNode Rewrite(
ParameterSymbol targetMethodThisParameter,
Conversions conversions,
ImmutableDictionary<string, DisplayClassVariable> displayClassVariables,
BoundNode node,
DiagnosticBag diagnostics)
{
var rewriter = new CapturedVariableRewriter(targetMethodThisParameter, conversions, displayClassVariables, diagnostics);
return rewriter.Visit(node);
}

private readonly ParameterSymbol _targetMethodThisParameter;
private readonly Conversions _conversions;
private readonly ImmutableDictionary<string, DisplayClassVariable> _displayClassVariables;
private readonly DiagnosticBag _diagnostics;

private CapturedVariableRewriter(
ParameterSymbol targetMethodThisParameter,
Conversions conversions,
ImmutableDictionary<string, DisplayClassVariable> displayClassVariables,
DiagnosticBag diagnostics)
{
_targetMethodThisParameter = targetMethodThisParameter;
_conversions = conversions;
_displayClassVariables = displayClassVariables;
_diagnostics = diagnostics;
}

public override BoundNode VisitBlock(BoundBlock node)
{
var rewrittenLocals = node.Locals.WhereAsArray(local => local.IsCompilerGenerated || local.Name == null || this.GetVariable(local.Name) == null);
var rewrittenStatements = VisitList(node.Statements);
return node.Update(rewrittenLocals, rewrittenStatements);
}

public override BoundNode VisitLocal(BoundLocal node)
{
var local = node.LocalSymbol;
if (!local.IsCompilerGenerated)
{
var variable = this.GetVariable(local.Name);
if (variable != null)
{
var result = variable.ToBoundExpression(node.Syntax);
Debug.Assert(node.Type == result.Type);
return result;
}
}
return node;
}

public override BoundNode VisitParameter(BoundParameter node)
{
return RewriteParameter(node.Syntax, node.ParameterSymbol, node);
}

public override BoundNode VisitMethodGroup(BoundMethodGroup node)
{
if ((node.Flags & BoundMethodGroupFlags.HasImplicitReceiver) == BoundMethodGroupFlags.HasImplicitReceiver &&
(object)_targetMethodThisParameter == null)
{
// This can happen in static contexts.
// NOTE: LocalRewriter has already been run, so the receiver has already been replaced with an
// appropriate type expression, if this is a static context.
// NOTE: Don't go through VisitThisReference, because it'll produce a diagnostic.
return node.Update(
node.TypeArgumentsOpt,
node.Name,
node.Methods,
node.LookupSymbolOpt,
node.LookupError,
node.Flags,
receiverOpt: null,
resultKind: node.ResultKind);
}
else
{
return base.VisitMethodGroup(node);
}
}

public override BoundNode VisitThisReference(BoundThisReference node)
{
return RewriteParameter(node.Syntax, _targetMethodThisParameter, node);
}

public override BoundNode VisitBaseReference(BoundBaseReference node)
{
var syntax = node.Syntax;
var rewrittenParameter = RewriteParameter(syntax, _targetMethodThisParameter, node);

var baseType = node.Type;
HashSet<DiagnosticInfo> unusedUseSiteDiagnostics = null;
var conversion = _conversions.ClassifyImplicitConversionFromExpression(rewrittenParameter, baseType, ref unusedUseSiteDiagnostics);
Debug.Assert(unusedUseSiteDiagnostics == null || !conversion.IsValid || unusedUseSiteDiagnostics.All(d => d.Severity < DiagnosticSeverity.Error));

// It would be nice if we could just call BoundConversion.Synthesized, but it doesn't seem worthwile to
// introduce a bunch of new overloads to accommodate isBaseConversion.
return new BoundConversion(
syntax,
rewrittenParameter,
conversion.Kind,
conversion.ResultKind,
isBaseConversion: true,
symbolOpt: conversion.Method,
@checked: false,
explicitCastInCode: false,
isExtensionMethod: conversion.IsExtensionMethod,
isArrayIndex: conversion.IsArrayIndex,
constantValueOpt: null,
type: baseType,
hasErrors: !conversion.IsValid)
{ WasCompilerGenerated = true };
}

private BoundExpression RewriteParameter(CSharpSyntaxNode syntax, ParameterSymbol symbol, BoundExpression node)
{
// This can happen in error scenarios (e.g. user binds "this" in a lambda in a static method).
if ((object)symbol == null)
{
ReportMissingThis(node.Kind, syntax);
return node;
}

var variable = this.GetVariable(symbol.Name);
if (variable == null)
{
var typeNameKind = GeneratedNames.GetKind(symbol.Type.Name);
if (typeNameKind != GeneratedNameKind.None)
{
// The state machine case is for async lambdas. The state machine
// will have a hoisted "this" field if it needs to access the
// containing display class, but the display class may not have a
// "this" field.
Debug.Assert(typeNameKind == GeneratedNameKind.LambdaDisplayClass ||
typeNameKind == GeneratedNameKind.StateMachineType);
ReportMissingThis(node.Kind, syntax);
return node;
}

return (node as BoundParameter) ?? new BoundParameter(syntax, symbol);
}

var result = variable.ToBoundExpression(syntax);
Debug.Assert(node.Kind == BoundKind.BaseReference
? result.Type.BaseType.Equals(node.Type, ignoreDynamic: true)
: result.Type.Equals(node.Type, ignoreDynamic: true));
return result;
}

private void ReportMissingThis(BoundKind boundKind, CSharpSyntaxNode syntax)
{
Debug.Assert(boundKind == BoundKind.ThisReference || boundKind == BoundKind.BaseReference);
var errorCode = boundKind == BoundKind.BaseReference
? ErrorCode.ERR_BaseInBadContext
: ErrorCode.ERR_ThisInBadContext;
_diagnostics.Add(new CSDiagnostic(new CSDiagnosticInfo(errorCode), syntax.Location));
}

private DisplayClassVariable GetVariable(string name)
{
DisplayClassVariable variable;
_displayClassVariables.TryGetValue(name, out variable);
return variable;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
// 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 Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.ExpressionEvaluator;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;

namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator
{
internal sealed class LocalDeclarationRewriter
{
internal static BoundNode Rewrite(CSharpCompilation compilation, EENamedTypeSymbol container, HashSet<LocalSymbol> declaredLocals, BoundNode node)
{
var builder = ArrayBuilder<BoundStatement>.GetInstance();
bool hasChanged;

// Rewrite top-level declarations only.
switch (node.Kind)
{
case BoundKind.LocalDeclaration:
RewriteLocalDeclaration(compilation, container, declaredLocals, builder, (BoundLocalDeclaration)node);
hasChanged = true;
break;
case BoundKind.MultipleLocalDeclarations:
foreach (var declaration in ((BoundMultipleLocalDeclarations)node).LocalDeclarations)
{
RewriteLocalDeclaration(compilation, container, declaredLocals, builder, declaration);
}
hasChanged = true;
break;
default:
hasChanged = false;
break;
}

if (hasChanged)
{
node = new BoundBlock(node.Syntax, ImmutableArray<LocalSymbol>.Empty, builder.ToImmutable()) { WasCompilerGenerated = true };
}

builder.Free();
return node;
}

private static void RewriteLocalDeclaration(
CSharpCompilation compilation,
EENamedTypeSymbol container,
HashSet<LocalSymbol> declaredLocals,
ArrayBuilder<BoundStatement> statements,
BoundLocalDeclaration node)
{
Debug.Assert(node.ArgumentsOpt.IsDefault);

var local = node.LocalSymbol;
var syntax = node.Syntax;

declaredLocals.Add(local);

var voidType = compilation.GetSpecialType(SpecialType.System_Void);
var objectType = compilation.GetSpecialType(SpecialType.System_Object);
var typeType = compilation.GetWellKnownType(WellKnownType.System_Type);
var stringType = compilation.GetSpecialType(SpecialType.System_String);

// <>CreateVariable(Type type, string name)
var method = container.GetOrAddSynthesizedMethod(
ExpressionCompilerConstants.CreateVariableMethodName,
(c, n, s) => new PlaceholderMethodSymbol(
c,
s,
n,
voidType,
m => ImmutableArray.Create<ParameterSymbol>(
new SynthesizedParameterSymbol(m, typeType, ordinal: 0, refKind: RefKind.None),
new SynthesizedParameterSymbol(m, stringType, ordinal: 1, refKind: RefKind.None))));
var type = new BoundTypeOfOperator(syntax, new BoundTypeExpression(syntax, aliasOpt: null, type: local.Type), null, typeType);
var name = new BoundLiteral(syntax, ConstantValue.Create(local.Name), stringType);
var call = BoundCall.Synthesized(
syntax,
receiverOpt: null,
method: method,
arguments: ImmutableArray.Create<BoundExpression>(type, name));
statements.Add(new BoundExpressionStatement(syntax, call));

var initializer = node.InitializerOpt;
if (initializer != null)
{
// Generate assignment to local. The assignment will
// be rewritten in PlaceholderLocalRewriter.
var assignment = new BoundAssignmentOperator(
syntax,
new BoundLocal(syntax, local, constantValueOpt: null, type: local.Type),
initializer,
RefKind.None,
local.Type);
statements.Add(new BoundExpressionStatement(syntax, assignment));
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator
{
internal sealed class MayHaveSideEffectsVisitor : BoundTreeWalker
{
private bool _mayHaveSideEffects;

internal static bool MayHaveSideEffects(BoundNode node)
{
var visitor = new MayHaveSideEffectsVisitor();
visitor.Visit(node);
return visitor._mayHaveSideEffects;
}

public override BoundNode Visit(BoundNode node)
{
if (_mayHaveSideEffects)
{
return null;
}
return base.Visit(node);
}

public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node)
{
return this.SetMayHaveSideEffects();
}

// Calls are treated as having side effects, but properties and
// indexers are not. (Since this visitor is run on the bound tree
// before lowering, properties are not represented as calls.)
public override BoundNode VisitCall(BoundCall node)
{
return this.SetMayHaveSideEffects();
}

public override BoundNode VisitDynamicInvocation(BoundDynamicInvocation node)
{
return this.SetMayHaveSideEffects();
}

public override BoundNode VisitCompoundAssignmentOperator(BoundCompoundAssignmentOperator node)
{
return this.SetMayHaveSideEffects();
}

public override BoundNode VisitEventAssignmentOperator(BoundEventAssignmentOperator node)
{
return this.SetMayHaveSideEffects();
}

public override BoundNode VisitIncrementOperator(BoundIncrementOperator node)
{
return this.SetMayHaveSideEffects();
}

public override BoundNode VisitObjectInitializerExpression(BoundObjectInitializerExpression node)
{
foreach (var initializer in node.Initializers)
{
// Do not treat initializer assignment as a side effect since it is
// part of an object creation. In short, visit the RHS only.
var expr = (initializer.Kind == BoundKind.AssignmentOperator) ?
((BoundAssignmentOperator)initializer).Right :
initializer;
this.Visit(expr);
}
return null;
}

private BoundNode SetMayHaveSideEffects()
{
_mayHaveSideEffects = true;
return null;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// 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 Microsoft.CodeAnalysis.CSharp.Symbols;
using System.Collections.Generic;
using System.Diagnostics;

namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator
{
internal sealed class PlaceholderLocalRewriter : BoundTreeRewriter
{
internal static BoundNode Rewrite(CSharpCompilation compilation, EENamedTypeSymbol container, HashSet<LocalSymbol> declaredLocals, BoundNode node)
{
var rewriter = new PlaceholderLocalRewriter(compilation, container, declaredLocals);
return rewriter.Visit(node);
}

private readonly CSharpCompilation _compilation;
private readonly EENamedTypeSymbol _container;
private readonly HashSet<LocalSymbol> _declaredLocals;

private PlaceholderLocalRewriter(CSharpCompilation compilation, EENamedTypeSymbol container, HashSet<LocalSymbol> declaredLocals)
{
_compilation = compilation;
_container = container;
_declaredLocals = declaredLocals;
}

public override BoundNode VisitLocal(BoundLocal node)
{
var result = RewriteLocal(node);
Debug.Assert(result.Type == node.Type);
return result;
}

private BoundExpression RewriteLocal(BoundLocal node)
{
var local = node.LocalSymbol;
var placeholder = local as PlaceholderLocalSymbol;
if ((object)placeholder != null)
{
return placeholder.RewriteLocal(_compilation, _container, node.Syntax);
}
if (_declaredLocals.Contains(local))
{
return ObjectIdLocalSymbol.RewriteLocal(_compilation, _container, node.Syntax, local);
}
return node;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// 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 Microsoft.CodeAnalysis.CSharp.Symbols;
using System.Diagnostics;

namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator
{
internal abstract class DisplayClassInstance
{
internal abstract Symbol ContainingSymbol { get; }

internal abstract NamedTypeSymbol Type { get; }

internal abstract DisplayClassInstance ToOtherMethod(MethodSymbol method, TypeMap typeMap);

internal abstract BoundExpression ToBoundExpression(CSharpSyntaxNode syntax);
}

internal sealed class DisplayClassInstanceFromLocal : DisplayClassInstance
{
internal readonly EELocalSymbol Local;

internal DisplayClassInstanceFromLocal(EELocalSymbol local)
{
Debug.Assert(!local.IsPinned);
Debug.Assert(local.RefKind == RefKind.None);
Debug.Assert(local.DeclarationKind == LocalDeclarationKind.RegularVariable);

this.Local = local;
}

internal override Symbol ContainingSymbol
{
get { return this.Local.ContainingSymbol; }
}

internal override NamedTypeSymbol Type
{
get { return (NamedTypeSymbol)this.Local.Type; }
}

internal override DisplayClassInstance ToOtherMethod(MethodSymbol method, TypeMap typeMap)
{
var otherInstance = (EELocalSymbol)this.Local.ToOtherMethod(method, typeMap);
return new DisplayClassInstanceFromLocal(otherInstance);
}

internal override BoundExpression ToBoundExpression(CSharpSyntaxNode syntax)
{
return new BoundLocal(syntax, this.Local, constantValueOpt: null, type: this.Local.Type) { WasCompilerGenerated = true };
}
}

internal sealed class DisplayClassInstanceFromThis : DisplayClassInstance
{
internal readonly ParameterSymbol ThisParameter;

internal DisplayClassInstanceFromThis(ParameterSymbol thisParameter)
{
Debug.Assert(thisParameter != null);
this.ThisParameter = thisParameter;
}

internal override Symbol ContainingSymbol
{
get { return this.ThisParameter.ContainingSymbol; }
}

internal override NamedTypeSymbol Type
{
get { return (NamedTypeSymbol)this.ThisParameter.Type; }
}

internal override DisplayClassInstance ToOtherMethod(MethodSymbol method, TypeMap typeMap)
{
Debug.Assert(method.IsStatic);
var otherParameter = method.Parameters[0];
return new DisplayClassInstanceFromThis(otherParameter);
}

internal override BoundExpression ToBoundExpression(CSharpSyntaxNode syntax)
{
return new BoundParameter(syntax, this.ThisParameter) { WasCompilerGenerated = true };
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
// 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 Microsoft.CodeAnalysis.CSharp.Symbols;
using Roslyn.Utilities;
using System.Collections.Immutable;
using System.Diagnostics;

namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator
{
internal enum DisplayClassVariableKind
{
Local,
Parameter,
This,
}

/// <summary>
/// A field in a display class that represents a captured
/// variable: either a local, a parameter, or "this".
/// </summary>
internal sealed class DisplayClassVariable
{
internal readonly string Name;
internal readonly DisplayClassVariableKind Kind;
internal readonly DisplayClassInstance DisplayClassInstance;
internal readonly ConsList<FieldSymbol> DisplayClassFields;

internal DisplayClassVariable(string name, DisplayClassVariableKind kind, DisplayClassInstance displayClassInstance, ConsList<FieldSymbol> displayClassFields)
{
Debug.Assert(displayClassFields.Any());

this.Name = name;
this.Kind = kind;
this.DisplayClassInstance = displayClassInstance;
this.DisplayClassFields = displayClassFields;

// Verify all type parameters are substituted.
Debug.Assert(this.ContainingSymbol.IsContainingSymbolOfAllTypeParameters(this.Type));
}

internal TypeSymbol Type
{
get { return this.DisplayClassFields.Head.Type; }
}

internal Symbol ContainingSymbol
{
get { return this.DisplayClassInstance.ContainingSymbol; }
}

internal DisplayClassVariable ToOtherMethod(MethodSymbol method, TypeMap typeMap)
{
var otherInstance = this.DisplayClassInstance.ToOtherMethod(method, typeMap);
return SubstituteFields(otherInstance, typeMap);
}

internal BoundExpression ToBoundExpression(CSharpSyntaxNode syntax)
{
var expr = this.DisplayClassInstance.ToBoundExpression(syntax);
var fields = ArrayBuilder<FieldSymbol>.GetInstance();
fields.AddRange(this.DisplayClassFields);
fields.ReverseContents();
foreach (var field in fields)
{
expr = new BoundFieldAccess(syntax, expr, field, constantValueOpt: null) { WasCompilerGenerated = true };
}
fields.Free();
return expr;
}

internal DisplayClassVariable SubstituteFields(DisplayClassInstance otherInstance, TypeMap typeMap)
{
var otherFields = SubstituteFields(this.DisplayClassFields, typeMap);
return new DisplayClassVariable(this.Name, this.Kind, otherInstance, otherFields);
}

private static ConsList<FieldSymbol> SubstituteFields(ConsList<FieldSymbol> fields, TypeMap typeMap)
{
if (!fields.Any())
{
return ConsList<FieldSymbol>.Empty;
}

var head = SubstituteField(fields.Head, typeMap);
var tail = SubstituteFields(fields.Tail, typeMap);
return tail.Prepend(head);
}

private static FieldSymbol SubstituteField(FieldSymbol field, TypeMap typeMap)
{
Debug.Assert(!field.IsStatic);
Debug.Assert(!field.IsReadOnly);
Debug.Assert(field.CustomModifiers.Length == 0);
// CONSIDER: Instead of digging fields out of the unsubstituted type and then performing substitution
// on each one individually, we could dig fields out of the substituted type.
return new EEDisplayClassFieldSymbol(typeMap.SubstituteNamedType(field.ContainingType), field.Name, typeMap.SubstituteType(field.Type));
}

private sealed class EEDisplayClassFieldSymbol : FieldSymbol
{
private readonly NamedTypeSymbol _container;
private readonly string _name;
private readonly TypeSymbol _type;

internal EEDisplayClassFieldSymbol(NamedTypeSymbol container, string name, TypeSymbol type)
{
_container = container;
_name = name;
_type = type;
}

public override Symbol AssociatedSymbol
{
get { throw ExceptionUtilities.Unreachable; }
}

public override Symbol ContainingSymbol
{
get { return _container; }
}

public override ImmutableArray<CustomModifier> CustomModifiers
{
get { return ImmutableArray<CustomModifier>.Empty; }
}

public override Accessibility DeclaredAccessibility
{
get { throw ExceptionUtilities.Unreachable; }
}

public override ImmutableArray<SyntaxReference> DeclaringSyntaxReferences
{
get { throw ExceptionUtilities.Unreachable; }
}

public override bool IsConst
{
get { return false; }
}

public override bool IsReadOnly
{
get { return false; }
}

public override bool IsStatic
{
get { return false; }
}

public override bool IsVolatile
{
get { return false; }
}

public override ImmutableArray<Location> Locations
{
get { throw ExceptionUtilities.Unreachable; }
}

public override string Name
{
get { return _name; }
}

internal override bool HasRuntimeSpecialName
{
get { throw ExceptionUtilities.Unreachable; }
}

internal override bool HasSpecialName
{
get { throw ExceptionUtilities.Unreachable; }
}

internal override bool IsNotSerialized
{
get { throw ExceptionUtilities.Unreachable; }
}

internal override MarshalPseudoCustomAttributeData MarshallingInformation
{
get { throw ExceptionUtilities.Unreachable; }
}

internal override ObsoleteAttributeData ObsoleteAttributeData
{
get { throw ExceptionUtilities.Unreachable; }
}

internal override int? TypeLayoutOffset
{
get { throw ExceptionUtilities.Unreachable; }
}

internal override ConstantValue GetConstantValue(ConstantFieldsInProgress inProgress, bool earlyDecodingWellKnownAttributes)
{
throw ExceptionUtilities.Unreachable;
}

internal override TypeSymbol GetFieldType(ConsList<FieldSymbol> fieldsBeingBound)
{
return _type;
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// 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.Collections.Immutable;
using Microsoft.CodeAnalysis.CSharp.Symbols;

namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator
{
/// <summary>
/// Synthesized expression evaluation method.
/// </summary>
internal sealed class EEConstructorSymbol : SynthesizedInstanceConstructor
{
internal EEConstructorSymbol(NamedTypeSymbol containingType)
: base(containingType)
{
}

internal override void GenerateMethodBody(TypeCompilationState compilationState, DiagnosticBag diagnostics)
{
var noLocals = ImmutableArray<LocalSymbol>.Empty;
var initializerInvocation = MethodCompiler.BindConstructorInitializer(this, diagnostics, compilationState.Compilation);
var syntax = initializerInvocation.Syntax;

compilationState.AddSynthesizedMethod(this,
new BoundBlock(
syntax,
noLocals,
ImmutableArray.Create<BoundStatement>(
new BoundExpressionStatement(syntax, initializerInvocation),
new BoundReturnStatement(syntax, null))));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// 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 Microsoft.CodeAnalysis.CSharp.Symbols;
using System.Collections.Immutable;
using System.Diagnostics;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator
{
/// <summary>
/// A display class field representing a local, exposed
/// as a local on the original method.
/// </summary>
internal sealed class EEDisplayClassFieldLocalSymbol : EELocalSymbolBase
{
private readonly DisplayClassVariable _variable;

public EEDisplayClassFieldLocalSymbol(DisplayClassVariable variable)
{
_variable = variable;

// Verify all type parameters are substituted.
Debug.Assert(this.ContainingSymbol.IsContainingSymbolOfAllTypeParameters(this.Type));
}

internal override EELocalSymbolBase ToOtherMethod(MethodSymbol method, TypeMap typeMap)
{
return new EEDisplayClassFieldLocalSymbol(_variable.ToOtherMethod(method, typeMap));
}

public override string Name
{
get { return _variable.Name; }
}

internal override LocalDeclarationKind DeclarationKind
{
get { return LocalDeclarationKind.RegularVariable; }
}

internal override SyntaxToken IdentifierToken
{
get { throw ExceptionUtilities.Unreachable; }
}

public override Symbol ContainingSymbol
{
get { return _variable.ContainingSymbol; }
}

public override TypeSymbol Type
{
get { return _variable.Type; }
}

internal override bool IsPinned
{
get { return false; }
}

internal override bool IsCompilerGenerated
{
get { return false; }
}

internal override RefKind RefKind
{
get { return RefKind.None; }
}

public override ImmutableArray<Location> Locations
{
get { return NoLocations; }
}

public override ImmutableArray<SyntaxReference> DeclaringSyntaxReferences
{
get { return ImmutableArray<SyntaxReference>.Empty; }
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// 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.Collections.Immutable;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator
{
internal sealed class EELocalConstantSymbol : EELocalSymbolBase
{
private readonly MethodSymbol _method;
private readonly string _name;
private readonly TypeSymbol _type;
private readonly ConstantValue _value;

public EELocalConstantSymbol(
MethodSymbol method,
string name,
TypeSymbol type,
ConstantValue value)
{
_method = method;
_name = name;
_type = type;
_value = value;
}

internal override EELocalSymbolBase ToOtherMethod(MethodSymbol method, TypeMap typeMap)
{
var type = typeMap.SubstituteType(_type);
return new EELocalConstantSymbol(method, _name, type, _value);
}

public override string Name
{
get { return _name; }
}

internal override LocalDeclarationKind DeclarationKind
{
get { return LocalDeclarationKind.Constant; }
}

internal override SyntaxToken IdentifierToken
{
get { throw ExceptionUtilities.Unreachable; }
}

public override Symbol ContainingSymbol
{
get { return _method; }
}

public override TypeSymbol Type
{
get { return _type; }
}

internal override bool IsPinned
{
get { return false; }
}

internal override bool IsCompilerGenerated
{
get { return false; }
}

internal override ConstantValue GetConstantValue(SyntaxNode node, LocalSymbol inProgress, DiagnosticBag diagnostics)
{
return _value;
}

internal override RefKind RefKind
{
get { return RefKind.None; }
}

public override ImmutableArray<Location> Locations
{
get { return NoLocations; }
}

public override ImmutableArray<SyntaxReference> DeclaringSyntaxReferences
{
get { return ImmutableArray<SyntaxReference>.Empty; }
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
// 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 System.Diagnostics;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator
{
internal sealed class EELocalSymbol : EELocalSymbolBase
{
private readonly MethodSymbol _method;
private readonly TypeSymbol _type;

private readonly LocalDeclarationKind _declarationKind;
private readonly bool _isCompilerGenerated;
private readonly ImmutableArray<Location> _locations;
private readonly string _nameOpt;
private readonly int _ordinal; // index in locals of containing block
private readonly bool _isPinned;
private readonly RefKind _refKind;
private readonly bool _canScheduleToStack;

public EELocalSymbol(
MethodSymbol method,
ImmutableArray<Location> locations,
string nameOpt,
int ordinal,
LocalDeclarationKind declarationKind,
TypeSymbol type,
RefKind refKind,
bool isPinned,
bool isCompilerGenerated,
bool canScheduleToStack)
{
Debug.Assert(method != null);
Debug.Assert(ordinal >= -1);
Debug.Assert(!locations.IsDefault);
Debug.Assert(type != null);

_method = method;
_locations = locations;
_nameOpt = nameOpt;
_ordinal = ordinal;
_declarationKind = declarationKind;
_type = type;
_refKind = refKind;
_isPinned = isPinned;
_isCompilerGenerated = isCompilerGenerated;
_canScheduleToStack = canScheduleToStack;
}

internal override EELocalSymbolBase ToOtherMethod(MethodSymbol method, TypeMap typeMap)
{
var type = typeMap.SubstituteType(_type);
return new EELocalSymbol(method, _locations, _nameOpt, _ordinal, _declarationKind, type, _refKind, _isPinned, _isCompilerGenerated, _canScheduleToStack);
}

internal override LocalDeclarationKind DeclarationKind
{
get { return _declarationKind; }
}

internal override bool CanScheduleToStack
{
get { return _canScheduleToStack; }
}

internal int Ordinal
{
get { return _ordinal; }
}

public override string Name
{
get { return _nameOpt; }
}

internal override SyntaxToken IdentifierToken
{
get { throw ExceptionUtilities.Unreachable; }
}

public override ImmutableArray<SyntaxReference> DeclaringSyntaxReferences
{
get { return ImmutableArray<SyntaxReference>.Empty; }
}

public override ImmutableArray<Location> Locations
{
get { return _locations; }
}

public override Symbol ContainingSymbol
{
get { return _method; }
}

public override TypeSymbol Type
{
get { return _type; }
}

internal override bool IsPinned
{
get { return _isPinned; }
}

internal override bool IsCompilerGenerated
{
get { return _isCompilerGenerated; }
}

internal override RefKind RefKind
{
get { return _refKind; }
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// 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.Generic;
using System.Collections.Immutable;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator
{
internal static class LocalSymbolExtensions
{
internal static LocalSymbol ToOtherMethod(this LocalSymbol local, MethodSymbol method, TypeMap typeMap)
{
var l = local as EELocalSymbolBase;
if ((object)l != null)
{
return l.ToOtherMethod(method, typeMap);
}
var type = typeMap.SubstituteType(local.Type);
return new EELocalSymbol(method, local.Locations, local.Name, -1, local.DeclarationKind, type, local.RefKind, local.IsPinned, local.IsCompilerGenerated, local.CanScheduleToStack);
}
}

internal abstract class EELocalSymbolBase : LocalSymbol
{
internal static readonly ImmutableArray<Location> NoLocations = ImmutableArray.Create(NoLocation.Singleton);

internal abstract EELocalSymbolBase ToOtherMethod(MethodSymbol method, TypeMap typeMap);

internal override ConstantValue GetConstantValue(SyntaxNode node, LocalSymbol inProgress, DiagnosticBag diagnostics)
{
return null;
}

internal override ImmutableArray<Diagnostic> GetConstantValueDiagnostics(BoundExpression boundInitValue)
{
return ImmutableArray<Diagnostic>.Empty;
}

internal sealed override SynthesizedLocalKind SynthesizedKind
{
get { return SynthesizedLocalKind.UserDefined; }
}

internal sealed override bool IsImportedFromMetadata
{
get { return true; }
}

internal override SyntaxNode GetDeclaratorSyntax()
{
throw ExceptionUtilities.Unreachable;
}

internal sealed override DiagnosticInfo GetUseSiteDiagnostic()
{
var type = this.Type;
DiagnosticInfo result = null;
if (!DeriveUseSiteDiagnosticFromType(ref result, type) && this.ContainingModule.HasUnifiedReferences)
{
// If the member is in an assembly with unified references,
// we check if its definition depends on a type from a unified reference.
HashSet<TypeSymbol> unificationCheckedTypes = null;
type.GetUnificationUseSiteDiagnosticRecursive(ref result, this, ref unificationCheckedTypes);
}
return result;
}
}
}

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,380 @@
// 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.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator
{
internal sealed class EENamedTypeSymbol : NamedTypeSymbol
{
internal readonly NamedTypeSymbol SubstitutedSourceType;
internal readonly ImmutableArray<TypeParameterSymbol> SourceTypeParameters;

private readonly NamespaceSymbol _container;
private readonly NamedTypeSymbol _baseType;
private readonly string _name;
private readonly CSharpSyntaxNode _syntax;
private readonly ImmutableArray<TypeParameterSymbol> _typeParameters;
private readonly ImmutableArray<MethodSymbol> _methods;

private Dictionary<string, PlaceholderMethodSymbol> _lazySynthesizedMethods;
#if DEBUG
private bool _sealed;
#endif

internal EENamedTypeSymbol(
NamespaceSymbol container,
NamedTypeSymbol baseType,
CSharpSyntaxNode syntax,
MethodSymbol currentFrame,
string typeName,
string methodName,
CompilationContext context,
GenerateMethodBody generateMethodBody) :
this(container, baseType, syntax, currentFrame, typeName, (m, t) => ImmutableArray.Create<MethodSymbol>(context.CreateMethod(t, methodName, syntax, generateMethodBody)))
{
}

internal EENamedTypeSymbol(
NamespaceSymbol container,
NamedTypeSymbol baseType,
CSharpSyntaxNode syntax,
MethodSymbol currentFrame,
string typeName,
Func<MethodSymbol, EENamedTypeSymbol, ImmutableArray<MethodSymbol>> getMethods,
ImmutableArray<TypeParameterSymbol> sourceTypeParameters,
Func<NamedTypeSymbol, EENamedTypeSymbol, ImmutableArray<TypeParameterSymbol>> getTypeParameters)
{
_container = container;
_baseType = baseType;
_syntax = syntax;
_name = typeName;
this.SourceTypeParameters = sourceTypeParameters;
_typeParameters = getTypeParameters(currentFrame.ContainingType, this);
VerifyTypeParameters(this, _typeParameters);
_methods = getMethods(currentFrame, this);
}

internal EENamedTypeSymbol(
NamespaceSymbol container,
NamedTypeSymbol baseType,
CSharpSyntaxNode syntax,
MethodSymbol currentFrame,
string typeName,
Func<MethodSymbol, EENamedTypeSymbol, ImmutableArray<MethodSymbol>> getMethods)
{
_container = container;
_baseType = baseType;
_syntax = syntax;
_name = typeName;

// What we want is to map all original type parameters to the corresponding new type parameters
// (since the old ones have the wrong owners). Unfortunately, we have a circular dependency:
// 1) Each new type parameter requires the entire map in order to be able to construct its constraint list.
// 2) The map cannot be constructed until all new type parameters exist.
// Our solution is to pass each new type parameter a lazy reference to the type map. We then
// initialize the map as soon as the new type parameters are available - and before they are
// handed out - so that there is never a period where they can require the type map and find
// it uninitialized.

var sourceType = currentFrame.ContainingType;
this.SourceTypeParameters = sourceType.GetAllTypeParameters();

TypeMap typeMap = null;
var getTypeMap = new Func<TypeMap>(() => typeMap);
_typeParameters = this.SourceTypeParameters.SelectAsArray(
(tp, i, arg) => (TypeParameterSymbol)new EETypeParameterSymbol(this, tp, i, getTypeMap),
(object)null);

typeMap = new TypeMap(this.SourceTypeParameters, _typeParameters);

VerifyTypeParameters(this, _typeParameters);

this.SubstitutedSourceType = typeMap.SubstituteNamedType(sourceType);
TypeParameterChecker.Check(this.SubstitutedSourceType, _typeParameters);

_methods = getMethods(currentFrame, this);
}

internal ImmutableArray<MethodSymbol> Methods
{
get { return _methods; }
}

internal override IEnumerable<FieldSymbol> GetFieldsToEmit()
{
return SpecializedCollections.EmptyEnumerable<FieldSymbol>();
}

internal override IEnumerable<MethodSymbol> GetMethodsToEmit()
{
foreach (var method in _methods)
{
yield return method;
}
#if DEBUG
_sealed = true;
#endif
if (_lazySynthesizedMethods != null)
{
foreach (var method in _lazySynthesizedMethods.Values)
{
yield return method;
}
}
}

internal override ImmutableArray<NamedTypeSymbol> GetInterfacesToEmit()
{
return ImmutableArray<NamedTypeSymbol>.Empty;
}

public override int Arity
{
get { return _typeParameters.Length; }
}

public override ImmutableArray<TypeParameterSymbol> TypeParameters
{
get { return _typeParameters; }
}

internal override ImmutableArray<TypeSymbol> TypeArgumentsNoUseSiteDiagnostics
{
get { return _typeParameters.Cast<TypeParameterSymbol, TypeSymbol>(); }
}

public override NamedTypeSymbol ConstructedFrom
{
get { return this; }
}

public override bool MightContainExtensionMethods
{
get { return false; }
}

internal override AttributeUsageInfo GetAttributeUsageInfo()
{
throw ExceptionUtilities.Unreachable;
}

public override string Name
{
get { return _name; }
}

// No additional name mangling since CompileExpression
// is providing an explicit type name.
internal override bool MangleName
{
get { return false; }
}

public override IEnumerable<string> MemberNames
{
get { throw ExceptionUtilities.Unreachable; }
}

public override ImmutableArray<Symbol> GetMembers()
{
return _methods.Cast<MethodSymbol, Symbol>();
}

public override ImmutableArray<Symbol> GetMembers(string name)
{
// Should not be requesting generated members
// by name other than constructors.
Debug.Assert((name == WellKnownMemberNames.InstanceConstructorName) || (name == WellKnownMemberNames.StaticConstructorName));
return this.GetMembers().WhereAsArray(m => m.Name == name);
}

public override ImmutableArray<NamedTypeSymbol> GetTypeMembers()
{
return ImmutableArray<NamedTypeSymbol>.Empty;
}

public override ImmutableArray<NamedTypeSymbol> GetTypeMembers(string name)
{
throw ExceptionUtilities.Unreachable;
}

public override ImmutableArray<NamedTypeSymbol> GetTypeMembers(string name, int arity)
{
throw ExceptionUtilities.Unreachable;
}

public override Accessibility DeclaredAccessibility
{
get { return Accessibility.Internal; }
}

internal override ImmutableArray<Symbol> GetEarlyAttributeDecodingMembers()
{
throw ExceptionUtilities.Unreachable;
}

internal override ImmutableArray<Symbol> GetEarlyAttributeDecodingMembers(string name)
{
throw ExceptionUtilities.Unreachable;
}

internal override NamedTypeSymbol GetDeclaredBaseType(ConsList<Symbol> basesBeingResolved)
{
return _baseType;
}

internal override ImmutableArray<NamedTypeSymbol> GetDeclaredInterfaces(ConsList<Symbol> basesBeingResolved)
{
throw ExceptionUtilities.Unreachable;
}

internal override bool HasSpecialName
{
get { return true; }
}

internal override bool IsComImport
{
get { return false; }
}

internal override bool IsWindowsRuntimeImport
{
get { return false; }
}

internal override bool ShouldAddWinRTMembers
{
get { return false; }
}

internal override bool IsSerializable
{
get { return false; }
}

internal override TypeLayout Layout
{
get { return default(TypeLayout); }
}

internal override System.Runtime.InteropServices.CharSet MarshallingCharSet
{
get { return System.Runtime.InteropServices.CharSet.Ansi; }
}

internal override bool HasDeclarativeSecurity
{
get { return false; }
}

internal override IEnumerable<Cci.SecurityAttribute> GetSecurityInformation()
{
throw ExceptionUtilities.Unreachable;
}

internal override ImmutableArray<string> GetAppliedConditionalSymbols()
{
throw ExceptionUtilities.Unreachable;
}

internal override NamedTypeSymbol BaseTypeNoUseSiteDiagnostics
{
get { return _baseType; }
}

internal override ImmutableArray<NamedTypeSymbol> InterfacesNoUseSiteDiagnostics(ConsList<Symbol> basesBeingResolved)
{
throw ExceptionUtilities.Unreachable;
}

public override TypeKind TypeKind
{
get { return TypeKind.Class; }
}

public override NamedTypeSymbol ContainingType
{
get { return null; }
}

public override Symbol ContainingSymbol
{
get { return _container; }
}

public override ImmutableArray<Location> Locations
{
get { return ImmutableArray<Location>.Empty; }
}

public override ImmutableArray<SyntaxReference> DeclaringSyntaxReferences
{
get { return ImmutableArray<SyntaxReference>.Empty; }
}

public override bool IsStatic
{
get { return true; }
}

public override bool IsAbstract
{
get { return false; }
}

public override bool IsSealed
{
get { return true; }
}

internal override ObsoleteAttributeData ObsoleteAttributeData
{
get { return null; }
}

internal override bool IsInterface
{
get { return false; }
}

internal delegate PlaceholderMethodSymbol CreateSynthesizedMethod(EENamedTypeSymbol container, string methodName, CSharpSyntaxNode syntax);

// Not thread-safe.
internal PlaceholderMethodSymbol GetOrAddSynthesizedMethod(string methodName, CreateSynthesizedMethod factory)
{
#if DEBUG
Debug.Assert(!_sealed);
#endif
if (_lazySynthesizedMethods == null)
{
_lazySynthesizedMethods = new Dictionary<string, PlaceholderMethodSymbol>();
}
PlaceholderMethodSymbol method;
if (!_lazySynthesizedMethods.TryGetValue(methodName, out method))
{
method = factory(this, methodName, _syntax);
Debug.Assert((object)method != null);
Debug.Assert(method.Name == methodName);
_lazySynthesizedMethods.Add(methodName, method);
}
return method;
}

[Conditional("DEBUG")]
internal static void VerifyTypeParameters(Symbol container, ImmutableArray<TypeParameterSymbol> typeParameters)
{
for (int i = 0; i < typeParameters.Length; i++)
{
var typeParameter = typeParameters[i];
Debug.Assert((object)typeParameter.ContainingSymbol == (object)container);
Debug.Assert(typeParameter.Ordinal == i);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
// 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 System.Diagnostics;
using System.Threading;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator
{
internal sealed class EETypeParameterSymbol : TypeParameterSymbol
{
private readonly Symbol _container;
private readonly TypeParameterSymbol _sourceTypeParameter;
private readonly int _ordinal;
private readonly Func<TypeMap> _getTypeMap;
private TypeMap _lazyTypeMap;

public EETypeParameterSymbol(
Symbol container,
TypeParameterSymbol sourceTypeParameter,
int ordinal,
Func<TypeMap> getTypeMap)
{
Debug.Assert((container.Kind == SymbolKind.NamedType) || (container.Kind == SymbolKind.Method));
_container = container;
_sourceTypeParameter = sourceTypeParameter;
_ordinal = ordinal;
_getTypeMap = getTypeMap;
}

public override Symbol ContainingSymbol
{
get { return _container; }
}

public override string Name
{
get { return _sourceTypeParameter.Name; }
}

public override ImmutableArray<SyntaxReference> DeclaringSyntaxReferences
{
get { throw ExceptionUtilities.Unreachable; }
}

public override bool HasConstructorConstraint
{
get { return _sourceTypeParameter.HasConstructorConstraint; }
}

public override bool HasReferenceTypeConstraint
{
get { return _sourceTypeParameter.HasReferenceTypeConstraint; }
}

public override bool HasValueTypeConstraint
{
get { return _sourceTypeParameter.HasValueTypeConstraint; }
}

public override ImmutableArray<Location> Locations
{
get { throw ExceptionUtilities.Unreachable; }
}

public override int Ordinal
{
get { return _ordinal; }
}

public override TypeParameterKind TypeParameterKind
{
get { throw ExceptionUtilities.Unreachable; }
}

public override VarianceKind Variance
{
get { return _sourceTypeParameter.Variance; }
}

public override bool IsImplicitlyDeclared
{
get { return true; }
}

internal override void EnsureAllConstraintsAreResolved()
{
_sourceTypeParameter.EnsureAllConstraintsAreResolved();
}

internal override ImmutableArray<TypeSymbol> GetConstraintTypes(ConsList<TypeParameterSymbol> inProgress)
{
var constraintTypes = _sourceTypeParameter.GetConstraintTypes(inProgress);

if (constraintTypes.IsEmpty)
{
return constraintTypes;
}

// Remap constraints from sourceTypeParameter since constraints
// may be defined in terms of other type parameters.
return this.TypeMap.SubstituteTypes(constraintTypes);
}

internal override TypeSymbol GetDeducedBaseType(ConsList<TypeParameterSymbol> inProgress)
{
var type = _sourceTypeParameter.GetDeducedBaseType(inProgress);
return this.TypeMap.SubstituteType(type);
}

internal override NamedTypeSymbol GetEffectiveBaseClass(ConsList<TypeParameterSymbol> inProgress)
{
var type = _sourceTypeParameter.GetEffectiveBaseClass(inProgress);
return this.TypeMap.SubstituteNamedType(type);
}

internal override ImmutableArray<NamedTypeSymbol> GetInterfaces(ConsList<TypeParameterSymbol> inProgress)
{
var interfaces = _sourceTypeParameter.GetInterfaces(inProgress);
return this.TypeMap.SubstituteNamedTypes(Interfaces);
}

private TypeMap TypeMap
{
get
{
if (_lazyTypeMap == null)
{
Interlocked.CompareExchange(ref _lazyTypeMap, _getTypeMap(), null);
}
return _lazyTypeMap;
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// 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.Collections.Immutable;
using System.Diagnostics;
using Microsoft.CodeAnalysis.CSharp.Symbols;

namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator
{
internal sealed class ExceptionLocalSymbol : PlaceholderLocalSymbol
{
internal ExceptionLocalSymbol(MethodSymbol method, string name, TypeSymbol type) :
base(method, name, type)
{
}

internal override bool IsWritable
{
get { return false; }
}

internal override BoundExpression RewriteLocal(CSharpCompilation compilation, EENamedTypeSymbol container, CSharpSyntaxNode syntax)
{
Debug.Assert(this.Name == this.Name.ToLowerInvariant());
var method = container.GetOrAddSynthesizedMethod(
this.Name,
(c, n, s) =>
{
var returnType = compilation.GetWellKnownType(WellKnownType.System_Exception);
return new PlaceholderMethodSymbol(
c,
s,
n,
returnType,
m => ImmutableArray<ParameterSymbol>.Empty);
});
var call = BoundCall.Synthesized(syntax, receiverOpt: null, method: method);
return ConvertToLocalType(compilation, call, this.Type);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// 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.Collections.Immutable;
using System.Diagnostics;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.ExpressionEvaluator;

namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator
{
internal sealed class ObjectAddressLocalSymbol : PlaceholderLocalSymbol
{
private readonly ulong _address;

internal ObjectAddressLocalSymbol(MethodSymbol method, string name, TypeSymbol type, ulong address) :
base(method, name, type)
{
Debug.Assert(type.SpecialType == SpecialType.System_Object);
_address = address;
}

internal override bool IsWritable
{
// Return true?
get { return false; }
}

internal override BoundExpression RewriteLocal(CSharpCompilation compilation, EENamedTypeSymbol container, CSharpSyntaxNode syntax)
{
var method = container.GetOrAddSynthesizedMethod(
ExpressionCompilerConstants.GetObjectAtAddressMethodName,
(c, n, s) =>
{
var parameterType = compilation.GetSpecialType(SpecialType.System_UInt64);
return new PlaceholderMethodSymbol(
c,
s,
n,
this.Type,
m => ImmutableArray.Create<ParameterSymbol>(new SynthesizedParameterSymbol(m, parameterType, ordinal: 0, refKind: RefKind.None)));
});
var argument = new BoundLiteral(
syntax,
Microsoft.CodeAnalysis.ConstantValue.Create(_address),
method.Parameters[0].Type);
var call = BoundCall.Synthesized(
syntax,
receiverOpt: null,
method: method,
arguments: ImmutableArray.Create<BoundExpression>(argument));
Debug.Assert(call.Type == this.Type);
return call;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
// 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 Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.ExpressionEvaluator;
using System.Collections.Immutable;

namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator
{
internal sealed class ObjectIdLocalSymbol : PlaceholderLocalSymbol
{
private readonly string _id;
private readonly bool _isWritable;

internal ObjectIdLocalSymbol(MethodSymbol method, TypeSymbol type, string id, bool isWritable) :
base(method, id, type)
{
_id = id;
_isWritable = isWritable;
}

internal override bool IsWritable
{
get { return _isWritable; }
}

internal override BoundExpression RewriteLocal(CSharpCompilation compilation, EENamedTypeSymbol container, CSharpSyntaxNode syntax)
{
return RewriteLocalInternal(compilation, container, syntax, this);
}

internal static BoundExpression RewriteLocal(CSharpCompilation compilation, EENamedTypeSymbol container, CSharpSyntaxNode syntax, LocalSymbol local)
{
return RewriteLocalInternal(compilation, container, syntax, local);
}

private static BoundExpression RewriteLocalInternal(CSharpCompilation compilation, EENamedTypeSymbol container, CSharpSyntaxNode syntax, LocalSymbol local)
{
var parameterType = compilation.GetSpecialType(SpecialType.System_String);
var getValueMethod = container.GetOrAddSynthesizedMethod(
ExpressionCompilerConstants.GetVariableValueMethodName,
(c, n, s) =>
{
var returnType = compilation.GetSpecialType(SpecialType.System_Object);
return new PlaceholderMethodSymbol(
c,
s,
n,
returnType,
m => ImmutableArray.Create<ParameterSymbol>(new SynthesizedParameterSymbol(m, parameterType, ordinal: 0, refKind: RefKind.None)));
});
var getAddressMethod = container.GetOrAddSynthesizedMethod(
ExpressionCompilerConstants.GetVariableAddressMethodName,
(c, n, s) =>
{
return new PlaceholderMethodSymbol(
c,
s,
n,
m => ImmutableArray.Create<TypeParameterSymbol>(new SimpleTypeParameterSymbol(m, 0, "<>T")),
m => m.TypeParameters[0], // return type is <>T&
m => ImmutableArray.Create<ParameterSymbol>(new SynthesizedParameterSymbol(m, parameterType, ordinal: 0, refKind: RefKind.None)),
returnValueIsByRef: true);
});
return new BoundPseudoVariable(
syntax,
local,
new ObjectIdExpressions(compilation, getValueMethod, getAddressMethod),
local.Type);
}

private sealed class ObjectIdExpressions : PseudoVariableExpressions
{
private readonly CSharpCompilation _compilation;
private readonly MethodSymbol _getValueMethod;
private readonly MethodSymbol _getAddressMethod;

internal ObjectIdExpressions(CSharpCompilation compilation, MethodSymbol getValueMethod, MethodSymbol getAddressMethod)
{
_compilation = compilation;
_getValueMethod = getValueMethod;
_getAddressMethod = getAddressMethod;
}

internal override BoundExpression GetValue(BoundPseudoVariable variable)
{
var local = variable.LocalSymbol;
var expr = InvokeGetMethod(_getValueMethod, variable.Syntax, local.Name);
return ConvertToLocalType(_compilation, expr, local.Type);
}

internal override BoundExpression GetAddress(BoundPseudoVariable variable)
{
var local = variable.LocalSymbol;
return InvokeGetMethod(_getAddressMethod.Construct(local.Type), variable.Syntax, local.Name);
}

private static BoundExpression InvokeGetMethod(MethodSymbol method, CSharpSyntaxNode syntax, string name)
{
var argument = new BoundLiteral(
syntax,
Microsoft.CodeAnalysis.ConstantValue.Create(name),
method.Parameters[0].Type);
return BoundCall.Synthesized(
syntax,
receiverOpt: null,
method: method,
arguments: ImmutableArray.Create<BoundExpression>(argument));
}
}
}
}