1 /**
2 * Copyright (c) 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 #include "typeFromLowering.h"
17
18 #include "checker/ETSchecker.h"
19 #include "checker/types/ets/etsTupleType.h"
20 #include "compiler/lowering/util.h"
21 #include "compiler/lowering/scopesInit/scopesInitPhase.h"
22 #include "ir/astNode.h"
23
24 namespace ark::es2panda::compiler {
25
26 using AstNodePtr = ir::AstNode *;
27
Name() const28 std::string_view TypeFromLowering::Name() const
29 {
30 return "TypeFromLowering";
31 }
32
TypeToString(const std::string & name)33 static std::string TypeToString(const std::string &name)
34 {
35 std::string src {"Type.resolve"};
36 src += "(\"";
37 src += name;
38 src += "\") as Type";
39 return src;
40 }
41
PrimitiveTypeToString(const checker::Type * type,checker::ETSChecker * checker)42 std::string PrimitiveTypeToString(const checker::Type *type, checker::ETSChecker *checker)
43 {
44 switch (checker->TypeKind(type)) {
45 case checker::TypeFlag::ETS_BOOLEAN:
46 return std::string(compiler::Signatures::BOOLEANTYPE_VAL);
47 case checker::TypeFlag::BYTE:
48 return std::string(compiler::Signatures::BYTETYPE_VAL);
49 case checker::TypeFlag::CHAR:
50 return std::string(compiler::Signatures::CHARTYPE_VAL);
51 case checker::TypeFlag::SHORT:
52 return std::string(compiler::Signatures::SHORTTYPE_VAL);
53 case checker::TypeFlag::INT:
54 return std::string(compiler::Signatures::INTTYPE_VAL);
55 case checker::TypeFlag::LONG:
56 return std::string(compiler::Signatures::LONGTYPE_VAL);
57 case checker::TypeFlag::FLOAT:
58 return std::string(compiler::Signatures::FLOATTYPE_VAL);
59 case checker::TypeFlag::DOUBLE:
60 return std::string(compiler::Signatures::DOUBLETYPE_VAL);
61 case checker::TypeFlag::ETS_VOID:
62 return std::string(compiler::Signatures::VOIDTYPE_VAL);
63 default:
64 ES2PANDA_UNREACHABLE();
65 }
66 }
67
HandleSpecialTypes(checker::Type * type)68 std::string HandleSpecialTypes(checker::Type *type)
69 {
70 if (type->IsETSUndefinedType()) {
71 return std::string(compiler::Signatures::UNDEFINEDTYPE_REF);
72 }
73
74 if (type->IsETSNullType()) {
75 return std::string(compiler::Signatures::NULLTYPE_REF);
76 }
77
78 if (type->IsETSVoidType()) {
79 return std::string(compiler::Signatures::VOIDTYPE_VAL);
80 }
81 return "";
82 }
83
IsTypeFrom(ir::Expression * callee)84 static bool IsTypeFrom(ir::Expression *callee)
85 {
86 if (!callee->IsMemberExpression()) {
87 return false;
88 }
89
90 auto *memberExpr = callee->AsMemberExpression();
91 return memberExpr->HasMemberKind(ir::MemberExpressionKind::PROPERTY_ACCESS) &&
92 memberExpr->Object()->IsIdentifier() &&
93 memberExpr->Object()->AsIdentifier()->Name() == compiler::Signatures::TYPE &&
94 memberExpr->Property()->IsIdentifier() &&
95 memberExpr->Property()->AsIdentifier()->Name() == compiler::Signatures::FROM;
96 }
97
HandleTypeParameter(ir::Expression * param,checker::ETSChecker * checker)98 std::string HandleTypeParameter(ir::Expression *param, checker::ETSChecker *checker)
99 {
100 auto *source = param->TsType();
101 if (source->IsETSObjectType()) {
102 return TypeToString(std::string(source->AsETSObjectType()->AssemblerName()));
103 }
104
105 if (source->IsETSPrimitiveType()) {
106 return PrimitiveTypeToString(source, checker);
107 }
108
109 if (source->IsETSArrayType()) {
110 return TypeToString(std::string(compiler::Signatures::ESCOMPAT_ARRAY));
111 }
112
113 return HandleSpecialTypes(source);
114 }
115
ReplaceTypeFrom(public_lib::Context * ctx,ir::CallExpression * ast)116 ir::Expression *ReplaceTypeFrom(public_lib::Context *ctx, ir::CallExpression *ast)
117 {
118 auto parser = ctx->parser->AsETSParser();
119 auto checker = ctx->checker->AsETSChecker();
120 auto *typeParams = ast->AsCallExpression()->TypeParams();
121
122 ES2PANDA_ASSERT(typeParams != nullptr && typeParams->Params().size() == 1);
123
124 auto *param = typeParams->Params().front();
125 if (param->IsETSUnionType()) {
126 checker->LogError(diagnostic::TYPE_FROM_UNION_TYPE_UNSUPPORTED, {}, ast->Start());
127 return ast;
128 }
129
130 if (param->IsETSTuple()) {
131 checker->LogError(diagnostic::TYPE_FROM_TUPLE_TYPE_UNSUPPORTED, {}, ast->Start());
132 return ast;
133 }
134
135 if (param->IsETSStringLiteralType()) {
136 checker->LogError(diagnostic::TYPE_FROM_STRING_LITERAL_TYPE_UNSUPPORTED, {}, ast->Start());
137 return ast;
138 }
139
140 std::string src = HandleTypeParameter(param, checker);
141 if (src.empty()) {
142 checker->LogError(diagnostic::TYPE_FROM_UNRESOLVABLE_TYPE, {}, ast->Start());
143 return ast;
144 }
145
146 auto loweringResult = parser->CreateExpression(src);
147 loweringResult->SetParent(ast->Parent());
148
149 InitScopesPhaseETS::RunExternalNode(loweringResult, checker->VarBinder());
150 checker->VarBinder()->AsETSBinder()->ResolveReferencesForScope(loweringResult, NearestScope(loweringResult));
151 loweringResult->Check(checker);
152 return loweringResult;
153 }
154
PerformForModule(public_lib::Context * ctx,parser::Program * program)155 bool TypeFromLowering::PerformForModule(public_lib::Context *ctx, parser::Program *program)
156 {
157 program->Ast()->TransformChildrenRecursively(
158 // CC-OFFNXT(G.FMT.14-CPP) project code style
159 [ctx](ir::AstNode *ast) -> AstNodePtr {
160 if (ast->IsCallExpression() && IsTypeFrom(ast->AsCallExpression()->Callee())) {
161 return ReplaceTypeFrom(ctx, ast->AsCallExpression());
162 }
163 return ast;
164 },
165 Name());
166
167 return true;
168 }
169 } // namespace ark::es2panda::compiler
170