本文整理汇总了C#中Microsoft.CodeAnalysis.CSharp.BoundLocal类的典型用法代码示例。如果您正苦于以下问题:C# BoundLocal类的具体用法?C# BoundLocal怎么用?C# BoundLocal使用的例子?那么恭喜您, 这里精选的类代码示例或许可以为您提供帮助。
BoundLocal类属于Microsoft.CodeAnalysis.CSharp命名空间,在下文中一共展示了BoundLocal类的15个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的C#代码示例。
示例1: ApplyConversions
/// <summary>
/// Applies the conversions.
/// Adds any new locals to the temps and any new expressions to be evaluated to the stores.
/// </summary>
private void ApplyConversions(BoundDeconstructionAssignmentOperator node, ArrayBuilder<LocalSymbol> temps, ArrayBuilder<BoundExpression> stores, ArrayBuilder<BoundValuePlaceholderBase> placeholders)
{
int numConversions = node.ConversionSteps.Length;
var conversionLocals = ArrayBuilder<BoundExpression>.GetInstance();
foreach (var conversionInfo in node.ConversionSteps)
{
// lower the conversions and assignments to locals
var localSymbol = new SynthesizedLocal(_factory.CurrentMethod, conversionInfo.OutputPlaceholder.Type, SynthesizedLocalKind.LoweringTemp);
var localBound = new BoundLocal(node.Syntax,
localSymbol,
null,
conversionInfo.OutputPlaceholder.Type)
{ WasCompilerGenerated = true };
temps.Add(localSymbol);
conversionLocals.Add(localBound);
AddPlaceholderReplacement(conversionInfo.OutputPlaceholder, localBound);
placeholders.Add(conversionInfo.OutputPlaceholder);
var conversion = VisitExpression(conversionInfo.Assignment);
stores.Add(conversion);
}
}
示例2: Create
public static DecisionTree Create(BoundExpression expression, TypeSymbol type, Symbol enclosingSymbol)
{
Debug.Assert(expression.Type == type);
LocalSymbol temp = null;
if (expression.ConstantValue == null)
{
// Unless it is a constant, the decision tree acts on a copy of the input expression.
// We create a temp to represent that copy. Lowering will assign into this temp.
temp = new SynthesizedLocal(enclosingSymbol as MethodSymbol, type, SynthesizedLocalKind.PatternMatchingTemp, expression.Syntax, false, RefKind.None);
expression = new BoundLocal(expression.Syntax, temp, null, type);
}
if (expression.Type.CanBeAssignedNull())
{
// We need the ByType decision tree to separate null from non-null values.
// Note that, for the purpose of the decision tree (and subsumption), we
// ignore the fact that the input may be a constant, and therefore always
// or never null.
return new ByType(expression, type, temp);
}
else
{
// If it is a (e.g. builtin) value type, we can switch on its (constant) values.
// If it isn't a builtin, in practice we will only use the Default part of the
// ByValue.
return new ByValue(expression, type, temp);
}
}
示例3: StoreToTemp
/// <summary>
/// Takes an expression and returns the bound local expression "temp"
/// and the bound assignment expression "temp = expr".
/// </summary>
/// <param name="argument"></param>
/// <param name="refKind"></param>
/// <param name="containingMethod"></param>
/// <returns></returns>
public static Pair<BoundAssignmentOperator, BoundLocal> StoreToTemp(BoundExpression argument, RefKind refKind, MethodSymbol containingMethod)
{
var syntax = argument.Syntax;
var type = argument.Type;
var local = new BoundLocal(
syntax,
// TODO: the following temp local symbol should have its ContainingSymbol set.
new TempLocalSymbol(type, refKind, containingMethod),
null,
type);
var store = new BoundAssignmentOperator(
syntax,
local,
argument,
refKind,
type);
return Pair.Make(store, local);
}
示例4: VisitDeclarationExpression
public override BoundNode VisitDeclarationExpression(BoundDeclarationExpression node)
{
var local = new BoundLocal(node.Syntax, node.LocalSymbol, null, node.LocalSymbol.Type);
if (node.InitializerOpt == null)
{
return local;
}
return new BoundSequence(node.Syntax,
ImmutableArray<LocalSymbol>.Empty,
ImmutableArray.Create<BoundExpression>(new BoundAssignmentOperator(
node.Syntax,
new BoundLocal(
local.Syntax,
local.LocalSymbol,
null,
local.Type
),
VisitExpression(node.InitializerOpt),
local.Type)),
local,
local.Type);
}
示例5: RewriteMultiDimensionalArrayForEachStatement
/// <summary>
/// Lower a foreach loop that will enumerate a multi-dimensional array.
///
/// A[...] a = x;
/// int q_0 = a.GetUpperBound(0), q_1 = a.GetUpperBound(1), ...;
/// for (int p_0 = a.GetLowerBound(0); p_0 <= q_0; p_0 = p_0 + 1)
/// for (int p_1 = a.GetLowerBound(1); p_1 <= q_1; p_1 = p_1 + 1)
/// ...
/// { V v = (V)a[p_0, p_1, ...]; /* body */ }
/// </summary>
/// <remarks>
/// We will follow Dev10 in diverging from the C# 4 spec by ignoring Array's
/// implementation of IEnumerable and just indexing into its elements.
///
/// NOTE: We're assuming that sequence points have already been generated.
/// Otherwise, lowering to nested for-loops would generated spurious ones.
/// </remarks>
private BoundStatement RewriteMultiDimensionalArrayForEachStatement(BoundForEachStatement node)
{
ForEachStatementSyntax forEachSyntax = (ForEachStatementSyntax)node.Syntax;
BoundExpression collectionExpression = GetUnconvertedCollectionExpression(node);
Debug.Assert(collectionExpression.Type.IsArray());
ArrayTypeSymbol arrayType = (ArrayTypeSymbol)collectionExpression.Type;
int rank = arrayType.Rank;
Debug.Assert(!arrayType.IsSZArray);
TypeSymbol intType = _compilation.GetSpecialType(SpecialType.System_Int32);
TypeSymbol boolType = _compilation.GetSpecialType(SpecialType.System_Boolean);
// Values we'll use every iteration
MethodSymbol getLowerBoundMethod = GetSpecialTypeMethod(forEachSyntax, SpecialMember.System_Array__GetLowerBound);
MethodSymbol getUpperBoundMethod = GetSpecialTypeMethod(forEachSyntax, SpecialMember.System_Array__GetUpperBound);
BoundExpression rewrittenExpression = (BoundExpression)Visit(collectionExpression);
BoundStatement rewrittenBody = (BoundStatement)Visit(node.Body);
// A[...] a
LocalSymbol arrayVar = _factory.SynthesizedLocal(arrayType, syntax: forEachSyntax, kind: SynthesizedLocalKind.ForEachArray);
BoundLocal boundArrayVar = MakeBoundLocal(forEachSyntax, arrayVar, arrayType);
// A[...] a = /*node.Expression*/;
BoundStatement arrayVarDecl = MakeLocalDeclaration(forEachSyntax, arrayVar, rewrittenExpression);
AddForEachExpressionSequencePoint(forEachSyntax, ref arrayVarDecl);
// NOTE: dev10 initializes all of the upper bound temps before entering the loop (as opposed to
// initializing each one at the corresponding level of nesting). Doing it at the same time as
// the lower bound would make this code a bit simpler, but it would make it harder to compare
// the roslyn and dev10 IL.
// int q_0, q_1, ...
LocalSymbol[] upperVar = new LocalSymbol[rank];
BoundLocal[] boundUpperVar = new BoundLocal[rank];
BoundStatement[] upperVarDecl = new BoundStatement[rank];
for (int dimension = 0; dimension < rank; dimension++)
{
// int q_dimension
upperVar[dimension] = _factory.SynthesizedLocal(intType, syntax: forEachSyntax, kind: SynthesizedLocalKind.ForEachArrayLimit);
boundUpperVar[dimension] = MakeBoundLocal(forEachSyntax, upperVar[dimension], intType);
ImmutableArray<BoundExpression> dimensionArgument = ImmutableArray.Create(
MakeLiteral(forEachSyntax,
constantValue: ConstantValue.Create(dimension, ConstantValueTypeDiscriminator.Int32),
type: intType));
// a.GetUpperBound(dimension)
BoundExpression currentDimensionUpperBound = BoundCall.Synthesized(forEachSyntax, boundArrayVar, getUpperBoundMethod, dimensionArgument);
// int q_dimension = a.GetUpperBound(dimension);
upperVarDecl[dimension] = MakeLocalDeclaration(forEachSyntax, upperVar[dimension], currentDimensionUpperBound);
}
// int p_0, p_1, ...
LocalSymbol[] positionVar = new LocalSymbol[rank];
BoundLocal[] boundPositionVar = new BoundLocal[rank];
for (int dimension = 0; dimension < rank; dimension++)
{
positionVar[dimension] = _factory.SynthesizedLocal(intType, syntax: forEachSyntax, kind: SynthesizedLocalKind.ForEachArrayIndex);
boundPositionVar[dimension] = MakeBoundLocal(forEachSyntax, positionVar[dimension], intType);
}
// V v
LocalSymbol iterationVar = node.IterationVariable;
TypeSymbol iterationVarType = iterationVar.Type;
// (V)a[p_0, p_1, ...]
BoundExpression iterationVarInitValue = MakeConversion(
syntax: forEachSyntax,
rewrittenOperand: new BoundArrayAccess(forEachSyntax,
expression: boundArrayVar,
indices: ImmutableArray.Create((BoundExpression[])boundPositionVar),
type: arrayType.ElementType),
conversion: node.ElementConversion,
rewrittenType: iterationVarType,
@checked: node.Checked);
// V v = (V)a[p_0, p_1, ...];
//.........这里部分代码省略.........
示例6: VisitLvalue
protected override void VisitLvalue(BoundLocal node)
{
VisitLocal(node);
}
示例7: RewriteUsingStatementTryFinally
private BoundStatement RewriteUsingStatementTryFinally(CSharpSyntaxNode syntax, BoundBlock tryBlock, BoundLocal local)
{
// SPEC: When ResourceType is a non-nullable value type, the expansion is:
// SPEC:
// SPEC: {
// SPEC: ResourceType resource = expr;
// SPEC: try { statement; }
// SPEC: finally { ((IDisposable)resource).Dispose(); }
// SPEC: }
// SPEC:
// SPEC: Otherwise, when Resource type is a nullable value type or
// SPEC: a reference type other than dynamic, the expansion is:
// SPEC:
// SPEC: {
// SPEC: ResourceType resource = expr;
// SPEC: try { statement; }
// SPEC: finally { if (resource != null) ((IDisposable)resource).Dispose(); }
// SPEC: }
// SPEC:
// SPEC: Otherwise, when ResourceType is dynamic, the expansion is:
// SPEC: {
// SPEC: dynamic resource = expr;
// SPEC: IDisposable d = (IDisposable)resource;
// SPEC: try { statement; }
// SPEC: finally { if (d != null) d.Dispose(); }
// SPEC: }
// SPEC:
// SPEC: An implementation is permitted to implement a given using statement
// SPEC: differently -- for example, for performance reasons -- as long as the
// SPEC: behavior is consistent with the above expansion.
//
// And we do in fact generate the code slightly differently than precisely how it is
// described above.
//
// First: if the type is a non-nullable value type then we do not do the
// *boxing conversion* from the resource to IDisposable. Rather, we do
// a *constrained virtual call* that elides the boxing if possible.
//
// Now, you might wonder if that is legal; isn't skipping the boxing producing
// an observable difference? Because if the value type is mutable and the Dispose
// mutates it, then skipping the boxing means that we are now mutating the original,
// not the boxed copy. But this is never observable. Either (1) we have "using(R r = x){}"
// and r is out of scope after the finally, so it is not possible to observe the mutation,
// or (2) we have "using(x) {}". But that has the semantics of "using(R temp = x){}",
// so again, we are not mutating x to begin with; we're always mutating a copy. Therefore
// it doesn't matter if we skip making *a copy of the copy*.
//
// This is what the dev10 compiler does, and we do so as well.
//
// Second: if the type is a nullable value type then we can similarly elide the boxing.
// We can generate
//
// {
// ResourceType resource = expr;
// try { statement; }
// finally { if (resource.HasValue) resource.GetValueOrDefault().Dispose(); }
// }
//
// Where again we do a constrained virtual call to Dispose, rather than boxing
// the value to IDisposable.
//
// Note that this optimization is *not* what the native compiler does; in this case
// the native compiler behavior is to test for HasValue, then *box* and convert
// the boxed value to IDisposable. There's no need to do that.
//
// Third: if we have "using(x)" and x is dynamic then obviously we need not generate
// "{ dynamic temp1 = x; IDisposable temp2 = (IDisposable) temp1; ... }". Rather, we elide
// the completely unnecessary first temporary.
BoundExpression disposedExpression;
bool isNullableValueType = local.Type.IsNullableType();
if (isNullableValueType)
{
MethodSymbol getValueOrDefault = GetNullableMethod(syntax, local.Type, SpecialMember.System_Nullable_T_GetValueOrDefault);
// local.GetValueOrDefault()
disposedExpression = BoundCall.Synthesized(syntax, local, getValueOrDefault);
}
else
{
// local
disposedExpression = local;
}
// local.Dispose()
BoundExpression disposeCall;
MethodSymbol disposeMethodSymbol;
if (TryGetSpecialTypeMember(syntax, SpecialMember.System_IDisposable__Dispose, out disposeMethodSymbol))
{
disposeCall = BoundCall.Synthesized(syntax, disposedExpression, disposeMethodSymbol);
}
else
{
disposeCall = new BoundBadExpression(syntax, LookupResultKind.NotInvocable, ImmutableArray<Symbol>.Empty, ImmutableArray.Create<BoundNode>(disposedExpression), ErrorTypeSymbol.UnknownResultType);
}
// local.Dispose();
BoundStatement disposeStatement = new BoundExpressionStatement(syntax, disposeCall);
//.........这里部分代码省略.........
示例8: CallDeconstruct
/// <summary>
/// Prepares local variables to be used in Deconstruct call
/// Adds a invocation of Deconstruct with those as out parameters onto the 'stores' sequence
/// Returns the expressions for those out parameters
/// </summary>
private void CallDeconstruct(BoundDeconstructionAssignmentOperator node, BoundDeconstructionDeconstructStep deconstruction, ArrayBuilder<LocalSymbol> temps, ArrayBuilder<BoundExpression> stores, ArrayBuilder<BoundValuePlaceholderBase> placeholders)
{
Debug.Assert((object)deconstruction.DeconstructInvocationOpt != null);
CSharpSyntaxNode syntax = node.Syntax;
// prepare out parameters for Deconstruct
var deconstructParameters = deconstruction.OutputPlaceholders;
var outParametersBuilder = ArrayBuilder<BoundExpression>.GetInstance(deconstructParameters.Length);
for (var i = 0; i < deconstructParameters.Length; i++)
{
var deconstructParameter = deconstructParameters[i];
var localSymbol = new SynthesizedLocal(_factory.CurrentMethod, deconstructParameter.Type, SynthesizedLocalKind.LoweringTemp);
var localBound = new BoundLocal(syntax,
localSymbol,
null,
deconstructParameter.Type
)
{ WasCompilerGenerated = true };
temps.Add(localSymbol);
outParametersBuilder.Add(localBound);
AddPlaceholderReplacement(deconstruction.OutputPlaceholders[i], localBound);
placeholders.Add(deconstruction.OutputPlaceholders[i]);
}
var outParameters = outParametersBuilder.ToImmutableAndFree();
// invoke Deconstruct with placeholders replaced by locals
stores.Add(VisitExpression(deconstruction.DeconstructInvocationOpt));
}
示例9: BindCatchBlock
private BoundCatchBlock BindCatchBlock(CatchClauseSyntax node, ArrayBuilder<BoundCatchBlock> previousBlocks, DiagnosticBag diagnostics)
{
bool hasError = false;
TypeSymbol type = null;
BoundExpression boundFilter = null;
var declaration = node.Declaration;
if (declaration != null)
{
// Note: The type is being bound twice: here and in LocalSymbol.Type. Currently,
// LocalSymbol.Type ignores diagnostics so it seems cleaner to bind the type here
// as well. However, if LocalSymbol.Type is changed to report diagnostics, we'll
// need to avoid binding here since that will result in duplicate diagnostics.
type = this.BindType(declaration.Type, diagnostics);
Debug.Assert((object)type != null);
if (type.IsErrorType())
{
hasError = true;
}
else
{
HashSet<DiagnosticInfo> useSiteDiagnostics = null;
TypeSymbol effectiveType = type.EffectiveType(ref useSiteDiagnostics);
if (!Compilation.IsExceptionType(effectiveType, ref useSiteDiagnostics))
{
// "The type caught or thrown must be derived from System.Exception"
Error(diagnostics, ErrorCode.ERR_BadExceptionType, declaration.Type);
hasError = true;
diagnostics.Add(declaration.Type, useSiteDiagnostics);
}
}
}
var filter = node.Filter;
if (filter != null)
{
var filterBinder = this.GetBinder(filter);
boundFilter = filterBinder.BindCatchFilter(filter, diagnostics);
hasError |= boundFilter.HasAnyErrors;
}
if (!hasError)
{
// TODO: Loop is O(n), caller is O(n^2). Perhaps we could iterate in reverse order (since it's easier to find
// base types than to find derived types).
Debug.Assert(((object)type == null) || !type.IsErrorType());
foreach (var previousBlock in previousBlocks)
{
var previousType = previousBlock.ExceptionTypeOpt;
// If the previous type is a generic parameter we don't know what exception types it's gonna catch exactly.
// If it is a class-type we know it's gonna catch all exception types of its type and types that are derived from it.
// So if the current type is a class-type (or an effective base type of a generic parameter)
// that derives from the previous type the current catch is unreachable.
if (previousBlock.ExceptionFilterOpt == null && (object)previousType != null && !previousType.IsErrorType())
{
if ((object)type != null)
{
HashSet<DiagnosticInfo> useSiteDiagnostics = null;
if (Conversions.HasIdentityOrImplicitReferenceConversion(type, previousType, ref useSiteDiagnostics))
{
// "A previous catch clause already catches all exceptions of this or of a super type ('{0}')"
Error(diagnostics, ErrorCode.ERR_UnreachableCatch, declaration.Type, previousType);
diagnostics.Add(declaration.Type, useSiteDiagnostics);
hasError = true;
break;
}
diagnostics.Add(declaration.Type, useSiteDiagnostics);
}
else if (previousType == Compilation.GetWellKnownType(WellKnownType.System_Exception) &&
Compilation.SourceAssembly.RuntimeCompatibilityWrapNonExceptionThrows)
{
// If the RuntimeCompatibility(WrapNonExceptionThrows = false) is applied on the source assembly or any referenced netmodule.
// an empty catch may catch exceptions that don't derive from System.Exception.
// "A previous catch clause already catches all exceptions..."
Error(diagnostics, ErrorCode.WRN_UnreachableGeneralCatch, node.CatchKeyword);
break;
}
}
}
}
BoundExpression exceptionSource = null;
LocalSymbol local = this.Locals.FirstOrDefault();
if ((object)local != null)
{
Debug.Assert(this.Locals.Length == 1);
// Check for local variable conflicts in the *enclosing* binder, not the *current* binder;
// obviously we will find a local of the given name in the current binder.
hasError |= this.ValidateDeclarationNameConflictsInScope(local, diagnostics);
exceptionSource = new BoundLocal(declaration, local, ConstantValue.NotAvailable, local.Type);
}
var block = this.BindBlock(node.Block, diagnostics);
//.........这里部分代码省略.........
示例10: EmitFinallyFrame
/// <summary>
/// Produces a Try/Finally if frame has a handler (otherwise a regular block).
/// Handler goes into the Finally.
/// If there are nested frames, they are emitted into the try block.
/// This way the handler for the current frame is guaranteed to run even if
/// nested handlers throw exceptions.
///
/// {
/// switch(state)
/// {
/// case state1:
/// case state2:
/// case state3:
/// case state4:
/// try
/// {
/// switch(state)
/// {
/// case state3:
/// case state4:
/// try
/// {
/// ... more nested state dispatches if any ....
/// }
/// finally
/// {
/// // handler for a try where state3 and state4 can be observed
/// handler_3_4()
/// }
/// break;
/// }
/// }
/// finally
/// {
/// // handler for a try where state1 and state2 can be observed
/// handler_1_2()
/// }
/// break;
///
/// case state5:
/// ... another dispatch of nested states to their finally blocks ...
/// break;
/// }
/// }
///
/// </summary>
private BoundStatement EmitFinallyFrame(IteratorFinallyFrame frame, BoundLocal state)
{
BoundStatement body = null;
if (frame.knownStates != null)
{
var breakLabel = F.GenerateLabel("break");
var sections = from ft in frame.knownStates
group ft.Key by ft.Value into g
select F.SwitchSection(
new List<int>(g),
EmitFinallyFrame(g.Key, state),
F.Goto(breakLabel));
body = F.Block(
F.Switch(state, sections),
F.Label(breakLabel));
}
if (!frame.IsRoot())
{
var tryBlock = body != null ? F.Block(body) : F.Block();
body = F.Try(
tryBlock,
ImmutableArray<BoundCatchBlock>.Empty,
F.Block(F.ExpressionStatement(F.Call(F.This(), frame.handler))));
}
Debug.Assert(body != null, "we should have either sub-dispatch or a handler");
return body;
}
示例11: VisitIncrementOperator
/// <summary>
/// The rewrites are as follows: suppose the operand x is a variable of type X. The
/// chosen increment/decrement operator is modelled as a static method on a type T,
/// which takes a value of type T and returns the result of incrementing or decrementing
/// that value.
///
/// x++
/// X temp = x
/// x = (X)(T.Increment((T)temp))
/// return temp
/// x--
/// X temp = x
/// x = (X)(T.Decrement((T)temp))
/// return temp
/// ++x
/// X temp = (X)(T.Increment((T)x))
/// x = temp
/// return temp
/// --x
/// X temp = (X)(T.Decrement((T)x))
/// x = temp
/// return temp
///
/// Note:
/// Dev11 implements dynamic prefix operators incorrectly.
///
/// result = ++x.P is emitted as result = SetMember{"P"}(t, UnaryOperation{Inc}(GetMember{"P"}(x)))
///
/// The difference is that Dev11 relies on SetMember returning the same value as it was given as an argument.
/// Failing to do so changes the semantics of ++/-- operator which is undesirable. We emit the same pattern for
/// both dynamic and static operators.
///
/// For example, we might have a class X with user-defined implicit conversions
/// to and from short, but no user-defined increment or decrement operators. We
/// would bind x++ as "X temp = x; x = (X)(short)((int)(short)temp + 1); return temp;"
/// </summary>
/// <param name="node">The unary operator expression representing the increment/decrement.</param>
/// <returns>A bound sequence that uses a temp to achieve the correct side effects and return value.</returns>
public override BoundNode VisitIncrementOperator(BoundIncrementOperator node)
{
bool isPrefix = IsPrefix(node);
bool isDynamic = node.OperatorKind.IsDynamic();
bool isChecked = node.OperatorKind.IsChecked();
ArrayBuilder<LocalSymbol> tempSymbols = ArrayBuilder<LocalSymbol>.GetInstance();
ArrayBuilder<BoundExpression> tempInitializers = ArrayBuilder<BoundExpression>.GetInstance();
CSharpSyntaxNode syntax = node.Syntax;
// This will be filled in with the LHS that uses temporaries to prevent
// double-evaluation of side effects.
BoundExpression transformedLHS = TransformCompoundAssignmentLHS(node.Operand, tempInitializers, tempSymbols, isDynamic);
TypeSymbol operandType = transformedLHS.Type; //type of the variable being incremented
Debug.Assert(operandType == node.Type);
LocalSymbol tempSymbol = _factory.SynthesizedLocal(operandType);
tempSymbols.Add(tempSymbol);
// Not adding an entry to tempInitializers because the initial value depends on the case.
BoundExpression boundTemp = new BoundLocal(
syntax: syntax,
localSymbol: tempSymbol,
constantValueOpt: null,
type: operandType);
// prefix: (X)(T.Increment((T)operand)))
// postfix: (X)(T.Increment((T)temp)))
var newValue = MakeIncrementOperator(node, rewrittenValueToIncrement: (isPrefix ? MakeRValue(transformedLHS) : boundTemp));
// there are two strategies for completing the rewrite.
// The reason is that indirect assignments read the target of the assignment before evaluating
// of the assignment value and that may cause reads of operand and boundTemp to cross which
// in turn would require one of them to be a real temp (not a stack local)
//
// To avoid this issue, in a case of ByRef operand, we perform a "nested sequence" rewrite.
//
// Ex:
// Seq{..., operand = Seq{temp = operand + 1, temp}, ...}
// instead of
// Seq{.... temp = operand + 1, operand = temp, ...}
//
// Such rewrite will nest reads of boundTemp relative to reads of operand so both
// operand and boundTemp could be optimizable (subject to all other conditions of course).
//
// In a case of the non-byref operand we use a single-sequence strategy as it results in shorter
// overall life time of temps and as such more appropriate. (problem of crossed reads does not affect that case)
//
if (IsIndirectOrInstanceField(transformedLHS))
{
return RewriteWithRefOperand(isPrefix, isChecked, tempSymbols, tempInitializers, syntax, transformedLHS, operandType, boundTemp, newValue);
}
else
{
return RewriteWithNotRefOperand(isPrefix, isChecked, tempSymbols, tempInitializers, syntax, transformedLHS, operandType, boundTemp, newValue);
}
}
示例12: CheckOutVarDeclaration
private void CheckOutVarDeclaration(BoundLocal node)
{
if (IsInside &&
!node.WasCompilerGenerated && node.Syntax.Kind() == SyntaxKind.Argument &&
((ArgumentSyntax)node.Syntax).Identifier == node.LocalSymbol.IdentifierToken)
{
_variablesDeclared.Add(node.LocalSymbol);
}
}
示例13: VisitLvalue
protected override void VisitLvalue(BoundLocal node)
{
CheckOutVarDeclaration(node);
base.VisitLvalue(node);
}
示例14: AddByType
private DecisionTree AddByType(DecisionTree.ByType byType, TypeSymbol type, DecisionMaker makeDecision)
{
if (byType.Default != null)
{
try
{
return AddByType(byType.Default, type, makeDecision);
}
finally
{
if (byType.Default.MatchIsComplete)
{
byType.MatchIsComplete = true;
}
}
}
foreach (var kvp in byType.TypeAndDecision)
{
var MatchedType = kvp.Key;
var Decision = kvp.Value;
// See if matching Type matches this value
switch (ExpressionOfTypeMatchesPatternType(type, MatchedType, ref _useSiteDiagnostics))
{
case true:
if (Decision.MatchIsComplete)
{
return null;
}
continue;
case false:
continue;
case null:
continue;
}
}
var localSymbol = new SynthesizedLocal(_enclosingSymbol as MethodSymbol, type, SynthesizedLocalKind.PatternMatchingTemp, Syntax, false, RefKind.None);
var expression = new BoundLocal(Syntax, localSymbol, null, type);
var result = makeDecision(expression, type);
Debug.Assert(result.Temp == null);
result.Temp = localSymbol;
byType.TypeAndDecision.Add(new KeyValuePair<TypeSymbol, DecisionTree>(type, result));
if (ExpressionOfTypeMatchesPatternType(byType.Type, type, ref _useSiteDiagnostics) == true &&
result.MatchIsComplete &&
byType.WhenNull?.MatchIsComplete == true)
{
byType.MatchIsComplete = true;
}
return result;
}
示例15: AddByValue
private DecisionTree AddByValue(DecisionTree.ByType byType, BoundConstantPattern value, DecisionMaker makeDecision)
{
if (byType.Default != null)
{
try
{
return AddByValue(byType.Default, value, makeDecision);
}
finally
{
if (byType.Default.MatchIsComplete)
{
byType.MatchIsComplete = true;
}
}
}
if (value.ConstantValue == ConstantValue.Null)
{
return byType.Expression.ConstantValue?.IsNull == false
? null : AddByNull((DecisionTree)byType, makeDecision);
}
foreach (var kvp in byType.TypeAndDecision)
{
var matchedType = kvp.Key;
var decision = kvp.Value;
// See if the test is already subsumed
switch (ExpressionOfTypeMatchesPatternType(value.Value.Type, matchedType, ref _useSiteDiagnostics))
{
case true:
if (decision.MatchIsComplete)
{
return null;
}
continue;
case false:
case null:
continue;
}
}
DecisionTree forType = null;
// Find an existing decision tree for the expression's type. Since this new test
// should logically be last, we look for the last one we can piggy-back it onto.
for (int i = byType.TypeAndDecision.Count - 1; i >= 0 && forType == null; i--)
{
var kvp = byType.TypeAndDecision[i];
var matchedType = kvp.Key;
var decision = kvp.Value;
if (matchedType.TupleUnderlyingTypeOrSelf() == value.Value.Type.TupleUnderlyingTypeOrSelf())
{
forType = decision;
break;
}
else if (ExpressionOfTypeMatchesPatternType(value.Value.Type, matchedType, ref _useSiteDiagnostics) != false)
{
break;
}
}
if (forType == null)
{
var type = value.Value.Type;
var localSymbol = new SynthesizedLocal(_enclosingSymbol as MethodSymbol, type, SynthesizedLocalKind.PatternMatchingTemp, Syntax, false, RefKind.None);
var narrowedExpression = new BoundLocal(Syntax, localSymbol, null, type);
forType = new DecisionTree.ByValue(narrowedExpression, value.Value.Type.TupleUnderlyingTypeOrSelf(), localSymbol);
byType.TypeAndDecision.Add(new KeyValuePair<TypeSymbol, DecisionTree>(value.Value.Type, forType));
}
return AddByValue(forType, value, makeDecision);
}