1 /* 2 * Copyright (c) 2021-2025 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef ES2PANDA_COMPILER_CHECKER_ETS_NARROWING_CONVERTER_H 17 #define ES2PANDA_COMPILER_CHECKER_ETS_NARROWING_CONVERTER_H 18 19 #include "checker/ETSchecker.h" 20 #include "checker/ets/typeConverter.h" 21 #include "util/helpers.h" 22 23 namespace ark::es2panda::checker { 24 class NarrowingConverter : public TypeConverter { 25 public: 26 static constexpr TypeFlag NARROWABLE_TO_FLOAT = TypeFlag::DOUBLE; 27 static constexpr TypeFlag NARROWABLE_TO_LONG = TypeFlag::FLOAT | NARROWABLE_TO_FLOAT; 28 static constexpr TypeFlag NARROWABLE_TO_INT = TypeFlag::LONG | NARROWABLE_TO_LONG; 29 static constexpr TypeFlag NARROWABLE_TO_CHAR = TypeFlag::SHORT | TypeFlag::INT | NARROWABLE_TO_INT; 30 static constexpr TypeFlag NARROWABLE_TO_SHORT = TypeFlag::CHAR | TypeFlag::INT | NARROWABLE_TO_INT; 31 static constexpr TypeFlag NARROWABLE_TO_BYTE = TypeFlag::CHAR | NARROWABLE_TO_CHAR; 32 NarrowingConverter(ETSChecker * checker,TypeRelation * relation,Type * target,Type * source)33 explicit NarrowingConverter(ETSChecker *checker, TypeRelation *relation, Type *target, Type *source) 34 : TypeConverter(checker, relation, target, source) 35 { 36 if (!relation->ApplyNarrowing()) { 37 return; 38 } 39 40 ES2PANDA_ASSERT(relation->GetNode()); 41 42 switch (ETSChecker::ETSChecker::ETSType(target)) { 43 case TypeFlag::BYTE: { 44 ApplyNarrowing<ByteType>(NARROWABLE_TO_BYTE); 45 break; 46 } 47 case TypeFlag::CHAR: { 48 ApplyNarrowing<CharType>(NARROWABLE_TO_CHAR); 49 break; 50 } 51 case TypeFlag::SHORT: { 52 ApplyNarrowing<ShortType>(NARROWABLE_TO_SHORT); 53 break; 54 } 55 case TypeFlag::INT: { 56 ApplyNarrowing<IntType>(NARROWABLE_TO_INT); 57 break; 58 } 59 case TypeFlag::LONG: { 60 ApplyNarrowing<LongType>(NARROWABLE_TO_LONG); 61 break; 62 } 63 case TypeFlag::FLOAT: { 64 ApplyNarrowing<FloatType>(NARROWABLE_TO_FLOAT); 65 break; 66 } 67 68 default: { 69 break; 70 } 71 } 72 } 73 74 private: 75 template <typename TargetType> ApplyNarrowing(TypeFlag flag)76 void ApplyNarrowing(TypeFlag flag) 77 { 78 if (!Source()->HasTypeFlag(flag)) { 79 return; 80 } 81 82 switch (ETSChecker::ETSChecker::ETSType(Source())) { 83 case TypeFlag::CHAR: { 84 ApplyNarrowing<TargetType, CharType>(); 85 break; 86 } 87 case TypeFlag::SHORT: { 88 ApplyNarrowing<TargetType, ShortType>(); 89 break; 90 } 91 case TypeFlag::INT: { 92 ApplyNarrowing<TargetType, IntType>(); 93 break; 94 } 95 case TypeFlag::LONG: { 96 ApplyNarrowing<TargetType, LongType>(); 97 break; 98 } 99 case TypeFlag::FLOAT: { 100 ApplyNarrowing<TargetType, FloatType>(); 101 break; 102 } 103 case TypeFlag::DOUBLE: { 104 ApplyNarrowing<TargetType, DoubleType>(); 105 break; 106 } 107 default: { 108 break; 109 } 110 } 111 } 112 113 template <typename From, typename To> CastFloatingPointToIntOrLong(From value)114 To CastFloatingPointToIntOrLong(From value) 115 { 116 if (std::isinf(value)) { 117 if (std::signbit(value)) { 118 return std::numeric_limits<To>::min(); 119 } 120 return std::numeric_limits<To>::max(); 121 } 122 ES2PANDA_ASSERT(std::is_floating_point_v<From>); 123 ES2PANDA_ASSERT(std::is_integral_v<To>); 124 To minInt = std::numeric_limits<To>::min(); 125 To maxInt = std::numeric_limits<To>::max(); 126 auto floatMinInt = static_cast<From>(minInt); 127 auto floatMaxInt = static_cast<From>(maxInt); 128 129 if (value > floatMinInt) { 130 if (value < floatMaxInt) { 131 return static_cast<To>(value); 132 } 133 return maxInt; 134 } 135 if (std::isnan(value)) { 136 return 0; 137 } 138 return minInt; 139 } 140 141 template <typename TType, typename SType> CalculateNarrowedValue(Type * target,Type * source,SType value)142 TType CalculateNarrowedValue(Type *target, Type *source, SType value) 143 { 144 switch (ETSChecker::ETSChecker::ETSType(target)) { 145 case TypeFlag::BYTE: 146 case TypeFlag::CHAR: 147 case TypeFlag::SHORT: { 148 if (source->HasTypeFlag(checker::TypeFlag::DOUBLE) || source->HasTypeFlag(checker::TypeFlag::FLOAT)) { 149 return static_cast<TType>(CastFloatingPointToIntOrLong<SType, int32_t>(value)); 150 } 151 return static_cast<TType>(value); 152 } 153 case TypeFlag::INT: 154 case TypeFlag::LONG: { 155 if (source->HasTypeFlag(checker::TypeFlag::DOUBLE) || source->HasTypeFlag(checker::TypeFlag::FLOAT)) { 156 return CastFloatingPointToIntOrLong<SType, TType>(value); 157 } 158 return static_cast<TType>(value); 159 } 160 case TypeFlag::FLOAT: 161 case TypeFlag::DOUBLE: { 162 return static_cast<TType>(value); 163 } 164 default: { 165 ES2PANDA_UNREACHABLE(); 166 } 167 } 168 } 169 170 template <typename TargetType, typename SourceType> ApplyNarrowing()171 void ApplyNarrowing() 172 { 173 using SType = typename SourceType::UType; 174 using TType = typename TargetType::UType; 175 176 if (Source()->HasTypeFlag(TypeFlag::CONSTANT)) { 177 SType value = reinterpret_cast<SourceType *>(Source())->GetValue(); 178 if (!Relation()->InCastingContext() && Source()->HasTypeFlag(TypeFlag::ETS_FLOATING_POINT) && 179 Target()->HasTypeFlag(TypeFlag::ETS_INTEGRAL)) { 180 auto narrowedValue = CalculateNarrowedValue<TType, SType>(Target(), Source(), value); 181 if (narrowedValue != value) { 182 Relation()->Result(RelationResult::ERROR); 183 return; 184 } 185 } 186 187 if (Relation()->InCastingContext() || util::Helpers::IsTargetFitInSourceRange<TType, SType>(value)) { 188 Relation()->Result(true); 189 return; 190 } 191 192 Relation()->Result(RelationResult::ERROR); 193 return; 194 } 195 196 Relation()->Result(true); 197 } 198 }; 199 } // namespace ark::es2panda::checker 200 201 #endif 202