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#include "switchCaseStatement.h" 17 18#include "checker/TSchecker.h" 19#include "compiler/core/ETSGen.h" 20#include "compiler/core/pandagen.h" 21#include "checker/ets/typeRelationContext.h" 22#include "ir/astDump.h" 23#include "ir/srcDump.h" 24 25namespace ark::es2panda::ir { 26void SwitchCaseStatement::TransformChildren(const NodeTransformer &cb, std::string_view transformationName) 27{ 28 if (test_ != nullptr) { 29 if (auto *transformedNode = cb(test_); test_ != transformedNode) { 30 test_->SetTransformedNode(transformationName, transformedNode); 31 test_ = transformedNode->AsExpression(); 32 } 33 } 34 35 for (auto *&it : consequent_) { 36 if (auto *transformedNode = cb(it); it != transformedNode) { 37 it->SetTransformedNode(transformationName, transformedNode); 38 it = transformedNode->AsStatement(); 39 } 40 } 41} 42 43void SwitchCaseStatement::Iterate(const NodeTraverser &cb) const 44{ 45 if (test_ != nullptr) { 46 cb(test_); 47 } 48 49 for (auto *it : consequent_) { 50 cb(it); 51 } 52} 53 54void SwitchCaseStatement::Dump(ir::AstDumper *dumper) const 55{ 56 dumper->Add({{"type", "SwitchCase"}, {"test", AstDumper::Nullish(test_)}, {"consequent", consequent_}}); 57} 58 59void SwitchCaseStatement::Dump(ir::SrcDumper *dumper) const 60{ 61 if (test_ != nullptr) { 62 dumper->Add("case "); 63 test_->Dump(dumper); 64 dumper->Add(":"); 65 } else { 66 dumper->Add("default:"); 67 } 68 if (!consequent_.empty()) { 69 dumper->IncrIndent(); 70 dumper->Endl(); 71 for (auto cs : consequent_) { 72 cs->Dump(dumper); 73 if (!cs->IsBlockStatement() && cs != consequent_.back()) { 74 dumper->Endl(); 75 } 76 } 77 dumper->DecrIndent(); 78 } 79} 80 81void SwitchCaseStatement::Compile(compiler::PandaGen *pg) const 82{ 83 pg->GetAstCompiler()->Compile(this); 84} 85 86void SwitchCaseStatement::Compile(compiler::ETSGen *etsg) const 87{ 88 etsg->GetAstCompiler()->Compile(this); 89} 90 91checker::Type *SwitchCaseStatement::Check(checker::TSChecker *checker) 92{ 93 return checker->GetAnalyzer()->Check(this); 94} 95 96checker::Type *SwitchCaseStatement::Check(checker::ETSChecker *checker) 97{ 98 return checker->GetAnalyzer()->Check(this); 99} 100 101// Auxilary function extracted from the 'Check' method for 'SwitchStatement' to reduce function's size. 102void SwitchCaseStatement::CheckAndTestCase(checker::ETSChecker *checker, checker::Type *comparedExprType, 103 checker::Type *unboxedDiscType, ir::Expression *node, bool &isDefaultCase) 104{ 105 if (test_ != nullptr) { 106 auto *caseType = test_->Check(checker); 107 bool validCaseType = true; 108 109 if (caseType->HasTypeFlag(checker::TypeFlag::CHAR)) { 110 validCaseType = comparedExprType->HasTypeFlag(checker::TypeFlag::ETS_INTEGRAL); 111 } else if (caseType->IsETSIntEnumType() && comparedExprType->IsETSIntEnumType()) { 112 validCaseType = comparedExprType->AsETSIntEnumType()->IsSameEnumType(caseType->AsETSIntEnumType()); 113 } else if (caseType->IsETSStringEnumType() && comparedExprType->IsETSStringEnumType()) { 114 validCaseType = comparedExprType->AsETSStringEnumType()->IsSameEnumType(caseType->AsETSStringEnumType()); 115 } else { 116 if (!checker::AssignmentContext( 117 checker->Relation(), node, caseType, unboxedDiscType, test_->Start(), {}, 118 (comparedExprType->IsETSObjectType() ? checker::TypeRelationFlag::NO_WIDENING 119 : checker::TypeRelationFlag::NO_UNBOXING) | 120 checker::TypeRelationFlag::NO_BOXING | checker::TypeRelationFlag::NO_THROW) 121 .IsAssignable()) { 122 checker->LogTypeError({"Switch case type '", caseType, "' is not comparable to discriminant type '", 123 comparedExprType, "'"}, 124 test_->Start()); 125 return; 126 } 127 } 128 129 if (!validCaseType) { 130 checker->LogTypeError( 131 {"Switch case type '", caseType, "' is not comparable to discriminant type '", comparedExprType, "'"}, 132 test_->Start()); 133 return; 134 } 135 } else { 136 isDefaultCase = true; 137 } 138 139 for (auto *caseStmt : consequent_) { 140 caseStmt->Check(checker); 141 } 142} 143} // namespace ark::es2panda::ir 144