public override BoundNode VisitConversion(BoundConversion node) { BoundExpression operand = (BoundExpression)this.Visit(node.Operand); TypeSymbol type = this.VisitType(node.Type); if (operand.Kind != BoundKind.SpillSequence) { return(node.Update(operand, node.ConversionKind, node.SymbolOpt, node.Checked, node.ExplicitCastInCode, node.IsExtensionMethod, node.IsArrayIndex, node.ConstantValueOpt, node.ResultKind, type)); } var spill = (BoundSpillSequence)operand; return(RewriteSpillSequence(spill, node.Update( spill.Value, node.ConversionKind, node.SymbolOpt, node.Checked, node.ExplicitCastInCode, node.IsExtensionMethod, node.IsArrayIndex, node.ConstantValueOpt, node.ResultKind, type))); }
public override BoundNode VisitConversion(BoundConversion node) { BoundSpillSequence2 ss = null; var operand = VisitExpression(ref ss, node.Operand); return(UpdateExpression(ss, node.Update(operand, node.ConversionKind, node.SymbolOpt, node.Checked, node.ExplicitCastInCode, node.IsExtensionMethod, node.IsArrayIndex, node.ConstantValueOpt, node.ResultKind, node.Type))); }
public override BoundNode VisitConversion(BoundConversion node) { BoundSpillSequenceBuilder builder = null; var operand = VisitExpression(ref builder, node.Operand); return(UpdateExpression( builder, node.Update( operand, node.Conversion, isBaseConversion: node.IsBaseConversion, @checked: node.Checked, explicitCastInCode: node.ExplicitCastInCode, constantValueOpt: node.ConstantValueOpt, type: node.Type))); }
public override BoundNode VisitConversion(BoundConversion node) { BoundSpillSequenceBuilder builder = null; var operand = VisitExpression(ref builder, node.Operand); return(UpdateExpression( builder, node.Update( operand, node.ConversionKind, node.ResultKind, isBaseConversion: node.IsBaseConversion, symbolOpt: node.SymbolOpt, @checked: node.Checked, explicitCastInCode: node.ExplicitCastInCode, isExtensionMethod: node.IsExtensionMethod, isArrayIndex: node.IsArrayIndex, constantValueOpt: node.ConstantValueOpt, type: node.Type))); }
public override BoundNode VisitConversion(BoundConversion node) { BoundSpillSequence2 ss = null; var operand = VisitExpression(ref ss, node.Operand); return UpdateExpression( ss, node.Update( operand, node.ConversionKind, node.ResultKind, isBaseConversion: node.IsBaseConversion, symbolOpt: node.SymbolOpt, @checked: node.Checked, explicitCastInCode: node.ExplicitCastInCode, isExtensionMethod: node.IsExtensionMethod, isArrayIndex: node.IsArrayIndex, constantValueOpt: node.ConstantValueOpt, type: node.Type)); }
private BoundExpression RewriteIntPtrConversion( BoundConversion oldNode, CSharpSyntaxNode syntax, BoundExpression rewrittenOperand, ConversionKind conversionKind, MethodSymbol symbolOpt, bool @checked, bool explicitCastInCode, bool isExtensionMethod, bool isArrayIndex, ConstantValue constantValueOpt, TypeSymbol rewrittenType) { Debug.Assert(rewrittenOperand != null); Debug.Assert((object)rewrittenType != null); TypeSymbol source = rewrittenOperand.Type; TypeSymbol target = rewrittenType; TypeSymbol t0 = target.StrippedType(); TypeSymbol s0 = source.StrippedType(); if (t0 != target && s0 != source) { // UNDONE: RewriteLiftedIntPtrConversion return oldNode != null ? oldNode.Update( rewrittenOperand, conversionKind, oldNode.ResultKind, isBaseConversion: oldNode.IsBaseConversion, symbolOpt: symbolOpt, @checked: @checked, explicitCastInCode: explicitCastInCode, isExtensionMethod: isExtensionMethod, isArrayIndex: isArrayIndex, constantValueOpt: constantValueOpt, type: rewrittenType) : new BoundConversion( syntax, rewrittenOperand, conversionKind, LookupResultKind.Viable, isBaseConversion: false, symbolOpt: symbolOpt, @checked: @checked, explicitCastInCode: explicitCastInCode, isExtensionMethod: isExtensionMethod, isArrayIndex: isArrayIndex, constantValueOpt: constantValueOpt, type: rewrittenType); } SpecialMember member = GetIntPtrConversionMethod(source: rewrittenOperand.Type, target: rewrittenType); MethodSymbol method = GetSpecialTypeMethod(syntax, member); Debug.Assert(!method.ReturnsVoid); Debug.Assert(method.ParameterCount == 1); rewrittenOperand = MakeConversion(rewrittenOperand, method.ParameterTypes[0], @checked); var returnType = method.ReturnType; Debug.Assert((object)returnType != null); if (inExpressionLambda) { return BoundConversion.Synthesized(syntax, rewrittenOperand, new Conversion(conversionKind, method, false), @checked, explicitCastInCode, constantValueOpt, rewrittenType); } var rewrittenCall = inExpressionLambda && oldNode != null ? new BoundConversion(syntax, rewrittenOperand, new Conversion(conversionKind, method, false), @checked, explicitCastInCode, constantValueOpt, returnType) : MakeCall( syntax: syntax, rewrittenReceiver: null, method: method, rewrittenArguments: ImmutableArray.Create<BoundExpression>(rewrittenOperand), type: returnType); return MakeConversion(rewrittenCall, rewrittenType, @checked); }
/// <summary> /// Helper method to generate a lowered conversion. /// </summary> private BoundExpression MakeConversion( BoundConversion oldNode, CSharpSyntaxNode syntax, BoundExpression rewrittenOperand, ConversionKind conversionKind, MethodSymbol symbolOpt, bool @checked, bool explicitCastInCode, bool isExtensionMethod, bool isArrayIndex, ConstantValue constantValueOpt, TypeSymbol rewrittenType) { Debug.Assert(oldNode == null || oldNode.Syntax == syntax); Debug.Assert((object)rewrittenType != null); @checked = @checked && (inExpressionLambda && (explicitCastInCode || DistinctSpecialTypes(rewrittenOperand.Type, rewrittenType)) || NeedsChecked(rewrittenOperand.Type, rewrittenType)); switch (conversionKind) { case ConversionKind.Identity: // Spec 6.1.1: // An identity conversion converts from any type to the same type. // This conversion exists such that an entity that already has a required type can be said to be convertible to that type. // Because object and dynamic are considered equivalent there is an identity conversion between object and dynamic, // and between constructed types that are the same when replacing all occurrences of dynamic with object. // Why ignoreDynamic: false? // Lowering phase treats object and dynamic as equivalent types. So we don't need to produce any conversion here, // but we need to change the Type property on the resulting BoundExpression to match the rewrittenType. // This is necessary so that subsequent lowering transformations see that the expression is dynamic. if (inExpressionLambda || !rewrittenOperand.Type.Equals(rewrittenType, ignoreCustomModifiers: false, ignoreDynamic: false)) { break; } // 4.1.6 C# spec: To force a value of a floating point type to the exact precision of its type, an explicit cast can be used. // If this is not an identity conversion of a float with unknown precision, strip away the identity conversion. if (!(explicitCastInCode && IsFloatPointExpressionOfUnknownPrecision(rewrittenOperand))) { return rewrittenOperand; } break; case ConversionKind.ExplicitUserDefined: case ConversionKind.ImplicitUserDefined: return RewriteUserDefinedConversion( syntax: syntax, rewrittenOperand: rewrittenOperand, method: symbolOpt, rewrittenType: rewrittenType, conversionKind: conversionKind); case ConversionKind.IntPtr: return RewriteIntPtrConversion(oldNode, syntax, rewrittenOperand, conversionKind, symbolOpt, @checked, explicitCastInCode, isExtensionMethod, isArrayIndex, constantValueOpt, rewrittenType); case ConversionKind.ImplicitNullable: case ConversionKind.ExplicitNullable: return RewriteNullableConversion( syntax: syntax, rewrittenOperand: rewrittenOperand, conversionKind: conversionKind, @checked: @checked, explicitCastInCode: explicitCastInCode, rewrittenType: rewrittenType); case ConversionKind.Boxing: if (!inExpressionLambda) { // We can perform some optimizations if we have a nullable value type // as the operand and we know its nullability: // * (object)new int?() is the same as (object)null // * (object)new int?(123) is the same as (object)123 if (NullableNeverHasValue(rewrittenOperand)) { return new BoundDefaultOperator(syntax, rewrittenType); } BoundExpression nullableValue = NullableAlwaysHasValue(rewrittenOperand); if (nullableValue != null) { // Recurse, eliminating the unnecessary ctor. return MakeConversion(oldNode, syntax, nullableValue, conversionKind, symbolOpt, @checked, explicitCastInCode, isExtensionMethod, isArrayIndex, constantValueOpt, rewrittenType); } } break; case ConversionKind.NullLiteral: if (!inExpressionLambda || !explicitCastInCode) { return new BoundDefaultOperator(syntax, rewrittenType); } break; case ConversionKind.ImplicitReference: case ConversionKind.ExplicitReference: if (rewrittenOperand.IsDefaultValue() && (!inExpressionLambda || !explicitCastInCode)) { return new BoundDefaultOperator(syntax, rewrittenType); } break; case ConversionKind.ImplicitNumeric: case ConversionKind.ExplicitNumeric: if (rewrittenOperand.IsDefaultValue() && (!inExpressionLambda || !explicitCastInCode)) { return new BoundDefaultOperator(syntax, rewrittenType); } if (rewrittenType.SpecialType == SpecialType.System_Decimal || rewrittenOperand.Type.SpecialType == SpecialType.System_Decimal) { return RewriteDecimalConversion(oldNode, syntax, rewrittenOperand, rewrittenOperand.Type, rewrittenType); } break; case ConversionKind.ImplicitEnumeration: // A conversion from constant zero to nullable is actually classified as an // implicit enumeration conversion, not an implicit nullable conversion. // Lower it to (E?)(E)0. if (rewrittenType.IsNullableType()) { var operand = MakeConversion( oldNode, syntax, rewrittenOperand, ConversionKind.ImplicitEnumeration, symbolOpt, @checked, explicitCastInCode, isExtensionMethod, false, constantValueOpt, rewrittenType.GetNullableUnderlyingType()); return MakeConversion( oldNode, syntax, operand, ConversionKind.ImplicitNullable, symbolOpt, @checked, explicitCastInCode, isExtensionMethod, isArrayIndex, constantValueOpt, rewrittenType); } goto case ConversionKind.ExplicitEnumeration; case ConversionKind.ExplicitEnumeration: if (!rewrittenType.IsNullableType() && rewrittenOperand.IsDefaultValue() && (!inExpressionLambda || !explicitCastInCode)) { return new BoundDefaultOperator(syntax, rewrittenType); } if (rewrittenType.SpecialType == SpecialType.System_Decimal) { Debug.Assert(rewrittenOperand.Type.IsEnumType()); var underlyingTypeFrom = rewrittenOperand.Type.GetEnumUnderlyingType(); rewrittenOperand = MakeConversion(rewrittenOperand, underlyingTypeFrom, false); return RewriteDecimalConversion(oldNode, syntax, rewrittenOperand, underlyingTypeFrom, rewrittenType); } else if (rewrittenOperand.Type.SpecialType == SpecialType.System_Decimal) { // This is where we handle conversion from Decimal to Enum: e.g., E e = (E) d; // where 'e' is of type Enum E and 'd' is of type Decimal. // Conversion can be simply done by applying its underlying numeric type to RewriteDecimalConversion(). Debug.Assert(rewrittenType.IsEnumType()); var underlyingTypeTo = rewrittenType.GetEnumUnderlyingType(); var rewrittenNode = RewriteDecimalConversion(oldNode, syntax, rewrittenOperand, rewrittenOperand.Type, underlyingTypeTo); // However, the type of the rewritten node becomes underlying numeric type, not Enum type, // which violates the overall constraint saying the type cannot be changed during rewriting (see LocalRewriter.cs). // Instead of loosening this constraint, we return BoundConversion from underlying numeric type to Enum type, // which will be eliminated during emitting (see EmitEnumConversion): e.g., E e = (E)(int) d; return new BoundConversion( syntax, rewrittenNode, conversionKind, LookupResultKind.Viable, isBaseConversion: false, symbolOpt: symbolOpt, @checked: false, explicitCastInCode: explicitCastInCode, isExtensionMethod: isExtensionMethod, isArrayIndex: false, constantValueOpt: constantValueOpt, type: rewrittenType); } break; case ConversionKind.ImplicitDynamic: case ConversionKind.ExplicitDynamic: Debug.Assert((object)symbolOpt == null); Debug.Assert(!isExtensionMethod); Debug.Assert(constantValueOpt == null); return dynamicFactory.MakeDynamicConversion(rewrittenOperand, explicitCastInCode || conversionKind == ConversionKind.ExplicitDynamic, isArrayIndex, @checked, rewrittenType).ToExpression(); default: break; } return oldNode != null ? oldNode.Update( rewrittenOperand, conversionKind, oldNode.ResultKind, isBaseConversion: oldNode.IsBaseConversion, symbolOpt: symbolOpt, @checked: @checked, explicitCastInCode: explicitCastInCode, isExtensionMethod: isExtensionMethod, isArrayIndex: isArrayIndex, constantValueOpt: constantValueOpt, type: rewrittenType) : new BoundConversion( syntax, rewrittenOperand, conversionKind, LookupResultKind.Viable, isBaseConversion: false, symbolOpt: symbolOpt, @checked: @checked, explicitCastInCode: explicitCastInCode, isExtensionMethod: isExtensionMethod, isArrayIndex: isArrayIndex, constantValueOpt: constantValueOpt, type: rewrittenType); }
private BoundExpression RewriteDecimalConversion(BoundConversion oldNode, CSharpSyntaxNode syntax, BoundExpression operand, TypeSymbol fromType, TypeSymbol toType) { Debug.Assert(fromType.SpecialType == SpecialType.System_Decimal || toType.SpecialType == SpecialType.System_Decimal); // call the method SpecialMember member = DecimalConversionMethod(fromType, toType); var method = (MethodSymbol)this.compilation.Assembly.GetSpecialTypeMember(member); Debug.Assert((object)method != null); // Should have been checked during Warnings pass if (inExpressionLambda && oldNode != null) { ConversionKind conversionKind = oldNode.ConversionKind.IsImplicitConversion() ? ConversionKind.ImplicitUserDefined : ConversionKind.ExplicitUserDefined; return oldNode.Update( operand, conversionKind, oldNode.ResultKind, isBaseConversion: oldNode.IsBaseConversion, symbolOpt: method, @checked: oldNode.Checked, explicitCastInCode: oldNode.ExplicitCastInCode, isExtensionMethod: oldNode.IsExtensionMethod, isArrayIndex: oldNode.IsArrayIndex, constantValueOpt: oldNode.ConstantValueOpt, type: toType); } else { Debug.Assert(method.ReturnType == toType); return BoundCall.Synthesized(syntax, null, method, operand); } }
public override BoundNode VisitConversion(BoundConversion node) { BoundExpression operand = (BoundExpression)this.Visit(node.Operand); TypeSymbol type = this.VisitType(node.Type); if (operand.Kind != BoundKind.SpillSequence) { return node.Update(operand, node.ConversionKind, node.SymbolOpt, node.Checked, node.ExplicitCastInCode, node.IsExtensionMethod, node.IsArrayIndex, node.ConstantValueOpt, node.ResultKind, type); } var spill = (BoundSpillSequence)operand; return RewriteSpillSequence(spill, node.Update( spill.Value, node.ConversionKind, node.SymbolOpt, node.Checked, node.ExplicitCastInCode, node.IsExtensionMethod, node.IsArrayIndex, node.ConstantValueOpt, node.ResultKind, type)); }