1 /* 2 * Copyright (c) 2021-2024 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_TYPE_RELATION_CONTEXT_H 17 #define ES2PANDA_COMPILER_CHECKER_ETS_TYPE_RELATION_CONTEXT_H 18 19 #include "ir/expression.h" 20 #include "ir/base/classDefinition.h" 21 #include "ir/ts/tsTypeParameterInstantiation.h" 22 #include "ir/ts/tsTypeParameterDeclaration.h" 23 #include "ir/ts/tsInterfaceDeclaration.h" 24 #include "checker/types/type.h" 25 #include "checker/ETSchecker.h" 26 27 namespace panda::es2panda::checker { 28 class ETSChecker; 29 30 class AssignmentContext { 31 public: 32 AssignmentContext(TypeRelation *relation, ir::Expression *node, Type *source, Type *target, 33 const lexer::SourcePosition &pos, std::initializer_list<TypeErrorMessageElement> list, 34 TypeRelationFlag flags = TypeRelationFlag::NONE) 35 { 36 flags_ |= ((flags & TypeRelationFlag::NO_BOXING) != 0) ? TypeRelationFlag::NONE : TypeRelationFlag::BOXING; 37 flags_ |= ((flags & TypeRelationFlag::NO_UNBOXING) != 0) ? TypeRelationFlag::NONE : TypeRelationFlag::UNBOXING; 38 flags_ |= ((flags & TypeRelationFlag::NO_WIDENING) != 0) ? TypeRelationFlag::NONE : TypeRelationFlag::WIDENING; 39 40 auto *const etsChecker = relation->GetChecker()->AsETSChecker(); 41 42 if (target->IsETSArrayType() && node->IsArrayExpression()) { 43 ValidateArrayTypeInitializerByElement(relation, node->AsArrayExpression(), target->AsETSArrayType()); 44 return; 45 } 46 47 flags_ |= flags; 48 relation->SetNode(node); 49 50 if (source->HasTypeFlag(TypeFlag::CONSTANT)) { 51 flags_ |= TypeRelationFlag::NARROWING; 52 } 53 54 relation->SetFlags(flags_); 55 56 if (!relation->IsAssignableTo(source, target)) { 57 if (((flags_ & TypeRelationFlag::UNBOXING) != 0) && !relation->IsTrue() && source->IsETSObjectType() && 58 !target->IsETSObjectType()) { 59 etsChecker->CheckUnboxedTypesAssignable(relation, source, target); 60 } 61 if (((flags_ & TypeRelationFlag::BOXING) != 0) && target->IsETSObjectType() && !relation->IsTrue()) { 62 etsChecker->CheckBoxedSourceTypeAssignable(relation, source, target); 63 } 64 } 65 66 if (!relation->IsTrue() && (flags_ & TypeRelationFlag::NO_THROW) == 0) { 67 relation->RaiseError(list, pos); 68 } 69 70 relation->SetNode(nullptr); 71 relation->SetFlags(TypeRelationFlag::NONE); 72 assignable_ = relation->IsTrue(); 73 } 74 IsAssignable()75 bool IsAssignable() const 76 { 77 return assignable_; 78 } 79 80 void ValidateArrayTypeInitializerByElement(TypeRelation *relation, ir::ArrayExpression *node, ETSArrayType *target); 81 82 private: 83 TypeRelationFlag flags_ = TypeRelationFlag::IN_ASSIGNMENT_CONTEXT; 84 bool assignable_ {false}; 85 }; 86 87 class InvocationContext { 88 public: 89 InvocationContext(TypeRelation *relation, ir::Expression *node, Type *source, Type *target, 90 const lexer::SourcePosition &pos, std::initializer_list<TypeErrorMessageElement> list, 91 TypeRelationFlag initialFlags = TypeRelationFlag::NONE) 92 { 93 flags_ |= 94 ((initialFlags & TypeRelationFlag::NO_BOXING) != 0) ? TypeRelationFlag::NONE : TypeRelationFlag::BOXING; 95 flags_ |= 96 ((initialFlags & TypeRelationFlag::NO_UNBOXING) != 0) ? TypeRelationFlag::NONE : TypeRelationFlag::UNBOXING; 97 98 auto *const etsChecker = relation->GetChecker()->AsETSChecker(); 99 100 relation->SetNode(node); 101 relation->SetFlags(flags_ | initialFlags); 102 103 if (!relation->IsAssignableTo(source, target)) { 104 if (((flags_ & TypeRelationFlag::UNBOXING) != 0U) && !relation->IsTrue() && source->IsETSObjectType() && 105 !target->IsETSObjectType()) { 106 etsChecker->CheckUnboxedSourceTypeWithWideningAssignable(relation, source, target); 107 } 108 if (((flags_ & TypeRelationFlag::BOXING) != 0) && target->IsETSObjectType() && !relation->IsTrue()) { 109 etsChecker->CheckBoxedSourceTypeAssignable(relation, source, target); 110 } 111 } 112 113 relation->SetNode(nullptr); 114 relation->SetFlags(TypeRelationFlag::NONE); 115 116 if (!relation->IsTrue()) { 117 if ((initialFlags & TypeRelationFlag::NO_THROW) == 0) { 118 relation->RaiseError(list, pos); 119 } 120 return; 121 } 122 123 invocable_ = true; 124 } 125 IsInvocable()126 bool IsInvocable() const 127 { 128 return invocable_; 129 } 130 131 private: 132 TypeRelationFlag flags_ = TypeRelationFlag::NONE; 133 bool invocable_ {false}; 134 }; 135 136 class InstantiationContext { 137 public: InstantiationContext(ETSChecker * checker,ETSObjectType * type,ir::TSTypeParameterInstantiation * typeArgs,const lexer::SourcePosition & pos)138 InstantiationContext(ETSChecker *checker, ETSObjectType *type, ir::TSTypeParameterInstantiation *typeArgs, 139 const lexer::SourcePosition &pos) 140 : checker_(checker) 141 { 142 if (ValidateTypeArguments(type, typeArgs, pos)) { 143 return; 144 } 145 InstantiateType(type, typeArgs); 146 } 147 InstantiationContext(ETSChecker * checker,ETSObjectType * type,ArenaVector<Type * > & typeArgs,const lexer::SourcePosition & pos)148 InstantiationContext(ETSChecker *checker, ETSObjectType *type, ArenaVector<Type *> &typeArgs, 149 const lexer::SourcePosition &pos) 150 : checker_(checker) 151 { 152 if (type->HasObjectFlag(ETSObjectFlags::ENUM)) { 153 return; 154 } 155 InstantiateType(type, typeArgs, pos); 156 } 157 Result()158 ETSObjectType *Result() 159 { 160 return result_; 161 } 162 163 private: 164 bool ValidateTypeArguments(ETSObjectType *type, ir::TSTypeParameterInstantiation *typeArgs, 165 const lexer::SourcePosition &pos); 166 167 bool ValidateTypeArg(Type *constraintType, Type *typeArg); 168 169 void InstantiateType(ETSObjectType *type, ir::TSTypeParameterInstantiation *typeArgs); 170 171 void InstantiateType(ETSObjectType *type, ArenaVector<Type *> &typeArgTypes, const lexer::SourcePosition &pos); 172 util::StringView GetHashFromTypeArguments(ArenaVector<Type *> &typeArgTypes); 173 174 ETSChecker *checker_; 175 ETSObjectType *result_ {}; 176 }; 177 178 } // namespace panda::es2panda::checker 179 180 #endif 181