/// <summary> /// Emits expression and converts it to required type. /// </summary> public void EmitConvert(BoundExpression expr, TypeSymbol to) { Debug.Assert(expr != null); Debug.Assert(to != null); // pop effectively if (to.IsVoid()) { expr.Access = BoundAccess.None; if (!expr.IsConstant()) { // POP LOAD <expr> EmitPop(Emit(expr)); } return; } // bind target expression type expr.Access = expr.Access.WithRead(to); if (!expr.Access.IsReadRef) { // constants if (expr.ConstantValue.HasValue && to != null) { EmitConvert(EmitLoadConstant(expr.ConstantValue.Value, to), 0, to); return; } // loads value from place most effectively without runtime type checking var place = PlaceOrNull(expr); if (place != null && place.Type != to) { var type = TryEmitVariableSpecialize(place, expr.TypeRefMask); if (type != null) { EmitConvert(type, 0, to); return; } } // avoiding of load of full value if (place != null && place.HasAddress && place.Type != null && place.Type.IsValueType) { var conv = DeclaringCompilation.ClassifyCommonConversion(place.Type, to); if (conv.Exists && conv.IsUserDefined && !conv.MethodSymbol.IsStatic) { // (ADDR expr).Method() this.EmitImplicitConversion(EmitCall(ILOpCode.Call, (MethodSymbol)conv.MethodSymbol, expr, ImmutableArray <BoundArgument> .Empty), to, @checked: true); return; } } } // EmitConvert(expr.Emit(this), expr.TypeRefMask, to); }
public TypeSymbol EmitConvertToPhpValue(TypeSymbol from, TypeRefMask fromHint) { // Nullable<T> -> HasValue ? T : NULL if (from.IsNullableType()) { from = EmitNullableCastToNull(from, false); // (HasValue ? Value : NULL) } var conv = DeclaringCompilation.ClassifyCommonConversion(from, CoreTypes.PhpValue.Symbol); if (conv.IsImplicit) { this.EmitConversion(conv, from, CoreTypes.PhpValue.Symbol); } else { // some conversion we did not implement as operator yet: if (from.IsReferenceType) { EmitCall(ILOpCode.Call, CoreMethods.PhpValue.FromClass_Object).Expect(CoreTypes.PhpValue); } else if (from.SpecialType == SpecialType.System_Void) { // PhpValue.Void Emit_PhpValue_Void(); } else { // box & wrap to PhpValue.Object // Template: PhpValue.FromStruct<T>( STACK ) EmitCall(ILOpCode.Call, CoreMethods.PhpValue.FromStruct_T.Symbol.Construct(from)).Expect(CoreTypes.PhpValue); } } // return(CoreTypes.PhpValue); }
public TypeSymbol EmitConvertToPhpValue(TypeSymbol from, TypeRefMask fromHint) { // Nullable<T> -> HasValue ? T : NULL if (from.IsNullableType()) { from = EmitNullableCastToNull(from, false); // (HasValue ? Value : NULL) } var conv = DeclaringCompilation.ClassifyCommonConversion(from, CoreTypes.PhpValue.Symbol); if (conv.IsImplicit) { this.EmitConversion(conv, from, CoreTypes.PhpValue.Symbol); } else { // some conversion we did not implement as operator yet: if (from.IsReferenceType) { EmitCall(ILOpCode.Call, CoreMethods.PhpValue.FromClass_Object) .Expect(CoreTypes.PhpValue); } else if (from.SpecialType == SpecialType.System_Void) { // PhpValue.Void Emit_PhpValue_Void(); } else { throw ExceptionUtilities.NotImplementedException(this, $"{from.Name} -> PhpValue"); } } // return(CoreTypes.PhpValue); }