public void EmitConvert(BoundExpression expr, TypeSymbol to) { // bind target expression type expr.Access = expr.Access.WithRead(to); // 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); 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) { if (place.TypeOpt == CoreTypes.PhpNumber) { if (to.SpecialType == SpecialType.System_Int64) { // <place>.ToLong() place.EmitLoadAddress(_il); EmitCall(ILOpCode.Call, CoreMethods.PhpNumber.ToLong); return; } if (to.SpecialType == SpecialType.System_Double) { // <place>.ToDouble() place.EmitLoadAddress(_il); EmitCall(ILOpCode.Call, CoreMethods.PhpNumber.ToDouble); return; } if (to.SpecialType == SpecialType.System_Boolean) { // <place>.ToBoolean() place.EmitLoadAddress(_il); EmitCall(ILOpCode.Call, CoreMethods.PhpNumber.ToBoolean); return; } if (to.SpecialType == SpecialType.System_String) { // <place>.ToString(<ctx>) place.EmitLoadAddress(_il); EmitLoadContext(); EmitCall(ILOpCode.Call, CoreMethods.PhpNumber.ToString_Context); return; } if (to == CoreTypes.PhpValue) { // TODO } // TODO: Object, Array } else if (place.TypeOpt == CoreTypes.PhpValue) { if (to.SpecialType == SpecialType.System_Int64) { // <place>.ToLong() place.EmitLoadAddress(_il); EmitCall(ILOpCode.Call, CoreMethods.PhpValue.ToLong); return; } if (to.SpecialType == SpecialType.System_Double) { // <place>.ToDouble() place.EmitLoadAddress(_il); EmitCall(ILOpCode.Call, CoreMethods.PhpValue.ToDouble); return; } if (to.SpecialType == SpecialType.System_Boolean) { // <place>.ToBoolean() place.EmitLoadAddress(_il); EmitCall(ILOpCode.Call, CoreMethods.PhpValue.ToBoolean); return; } if (to.SpecialType == SpecialType.System_String) { // <place>.ToString(<ctx>) place.EmitLoadAddress(_il); EmitLoadContext(); EmitCall(ILOpCode.Call, CoreMethods.PhpValue.ToString_Context); return; } if (to.SpecialType == SpecialType.System_Object) { // <place>.ToClass() place.EmitLoadAddress(_il); EmitCall(ILOpCode.Call, CoreMethods.PhpValue.ToClass); return; } //if (to == CoreTypes.PhpArray) //{ // // <place>.AsArray() // place.EmitLoadAddress(_il); // EmitCall(ILOpCode.Call, CoreMethods.PhpValue.ToArray); // return; //} } else if (place.TypeOpt == CoreTypes.Long) { if (to.SpecialType == SpecialType.System_String) { // <place>.ToString() place.EmitLoadAddress(_il); EmitCall(ILOpCode.Call, CoreMethods.Operators.Long_ToString); return; } } } // EmitConvert(expr.Emit(this), expr.TypeRefMask, to); }
/// <summary> /// If possible, based on type analysis, unwraps more specific type from a value currently on stack without a runtime type check. /// </summary> /// <returns>New type on top of evaluation stack.</returns> internal TypeSymbol EmitSpecialize(BoundExpression expr) { // load resulting value directly if resolved: if (expr.ConstantValue.HasValue) { if (expr.Access.IsNone) { return CoreTypes.Void; } if (expr.Access.IsRead) { return EmitLoadConstant(expr.ConstantValue.Value, expr.Access.TargetType); } } // if (expr.Access.IsNone) // no need for specializing, the value won't be read anyway { return (expr.ResultType = expr.Emit(this)); } else { Debug.Assert(expr.Access.IsRead); return expr.ResultType = (TryEmitVariableSpecialize(expr) ?? EmitSpecialize(expr.Emit(this), expr.TypeRefMask)); } }