|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable disable
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.ExpressionEvaluator;
using System.Collections.Immutable;
using System.Diagnostics;
namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator
{
internal sealed class ObjectIdLocalSymbol : PlaceholderLocalSymbol
{
private readonly bool _isWritable;
internal ObjectIdLocalSymbol(MethodSymbol method, TypeSymbol type, string name, string displayName, bool isWritable) :
base(method, name, displayName, type)
{
_isWritable = isWritable;
}
internal override bool IsWritableVariable
{
get { return _isWritable; }
}
internal override BoundExpression RewriteLocal(CSharpCompilation compilation, SyntaxNode syntax, DiagnosticBag diagnostics)
{
return RewriteLocalInternal(compilation, syntax, this);
}
internal static BoundExpression RewriteLocal(CSharpCompilation compilation, SyntaxNode syntax, LocalSymbol local)
{
return RewriteLocalInternal(compilation, syntax, local);
}
private static BoundExpression RewriteLocalInternal(CSharpCompilation compilation, SyntaxNode syntax, LocalSymbol local)
{
return new BoundPseudoVariable(
syntax,
local,
new ObjectIdExpressions(compilation),
local.Type);
}
private sealed class ObjectIdExpressions : PseudoVariableExpressions
{
private readonly CSharpCompilation _compilation;
internal ObjectIdExpressions(CSharpCompilation compilation)
{
_compilation = compilation;
}
internal override BoundExpression GetValue(BoundPseudoVariable variable, DiagnosticBag diagnostics)
{
var method = GetIntrinsicMethod(_compilation, ExpressionCompilerConstants.GetVariableValueMethodName);
var local = variable.LocalSymbol;
var expr = InvokeGetMethod(method, variable.Syntax, local.Name);
return ConvertToLocalType(_compilation, expr, local.Type, diagnostics);
}
internal override BoundExpression GetAddress(BoundPseudoVariable variable)
{
var method = GetIntrinsicMethod(_compilation, ExpressionCompilerConstants.GetVariableAddressMethodName);
// Currently the MetadataDecoder does not support byref return types
// so the return type of GetVariableAddress(Of T)(name As String)
// is an error type. Since the method is only used for emit, an
// updated placeholder method is used instead.
// TODO: refs are available
// Debug.Assert(method.ReturnType.TypeKind == TypeKind.Error); // If byref return types are supported in the future, use method as is.
method = new PlaceholderMethodSymbol(
method.ContainingType,
method.Name,
m => method.TypeParameters.SelectAsArray(t => (TypeParameterSymbol)new SimpleTypeParameterSymbol(m, t.Ordinal, t.Name)),
m => m.TypeParameters[0], // return type is <>T&
m => method.Parameters.SelectAsArray(p => SynthesizedParameterSymbol.Create(m, p.TypeWithAnnotations, p.Ordinal, p.RefKind, p.Name, p.EffectiveScope, refCustomModifiers: p.RefCustomModifiers)));
var local = variable.LocalSymbol;
return InvokeGetMethod(method.Construct(local.Type), variable.Syntax, local.Name);
}
private static BoundExpression InvokeGetMethod(MethodSymbol method, SyntaxNode 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));
}
}
}
}
|