From 666a4511c0a30e898729a5a692b480bf3acea4be Mon Sep 17 00:00:00 2001 From: Vivien Voros Date: Thu, 12 Oct 2023 14:55:45 +0200 Subject: [PATCH] Compile logic is moved to JSCompiler and ETSCompiler classes. Check logic with their helper functions is moved to TSAnalyzer and ETSAnalyzer classes. VariableDeclaration, UpdateExpression, TaggedTemplateExpression, TSTypeAssertion, TSClassImplements, TSAsExpression, TSTypeQuery, TSNamedTupleMember, TSTupleType, TSInterfaceHeritage, TSInterfaceBody Linked Internal issue: 13840 Change-Id: I68c105237ed17faad9551a18907affd4ac0b3b2b Signed-off-by: Vivien Voros --- ets2panda/checker/ETSAnalyzer.cpp | 105 +++++++---- ets2panda/checker/TSAnalyzer.cpp | 141 ++++++++++++--- ets2panda/compiler/core/ETSCompiler.cpp | 142 ++++++++++++--- ets2panda/compiler/core/JSCompiler.cpp | 67 ++++--- .../expressions/taggedTemplateExpression.cpp | 23 +-- .../ir/expressions/taggedTemplateExpression.h | 1 + ets2panda/ir/expressions/updateExpression.cpp | 93 +--------- ets2panda/ir/expressions/updateExpression.h | 9 +- .../ir/statements/variableDeclaration.cpp | 22 +-- ets2panda/ir/ts/tsAsExpression.cpp | 169 +----------------- ets2panda/ir/ts/tsAsExpression.h | 10 +- ets2panda/ir/ts/tsClassImplements.cpp | 17 +- ets2panda/ir/ts/tsClassImplements.h | 1 + ets2panda/ir/ts/tsInterfaceBody.cpp | 21 ++- ets2panda/ir/ts/tsInterfaceBody.h | 1 + ets2panda/ir/ts/tsInterfaceHeritage.cpp | 17 +- ets2panda/ir/ts/tsInterfaceHeritage.h | 1 + ets2panda/ir/ts/tsNamedTupleMember.cpp | 19 +- ets2panda/ir/ts/tsNamedTupleMember.h | 1 + ets2panda/ir/ts/tsTupleType.cpp | 21 ++- ets2panda/ir/ts/tsTupleType.h | 1 + ets2panda/ir/ts/tsTypeAssertion.cpp | 17 +- ets2panda/ir/ts/tsTypeAssertion.h | 1 + ets2panda/ir/ts/tsTypeQuery.cpp | 25 +-- ets2panda/ir/ts/tsTypeQuery.h | 7 +- 25 files changed, 508 insertions(+), 424 deletions(-) diff --git a/ets2panda/checker/ETSAnalyzer.cpp b/ets2panda/checker/ETSAnalyzer.cpp index f91ee6ca74..402dbe8ddc 100644 --- a/ets2panda/checker/ETSAnalyzer.cpp +++ b/ets2panda/checker/ETSAnalyzer.cpp @@ -20,14 +20,6 @@ #include "checker/ETSchecker.h" #include "checker/ets/castingContext.h" #include "checker/ets/typeRelationContext.h" -#include "ir/base/catchClause.h" -#include "ir/base/classProperty.h" -#include "ir/base/classStaticBlock.h" -#include "ir/expressions/identifier.h" -#include "ir/expressions/objectExpression.h" -#include "ir/expressions/arrayExpression.h" -#include "ir/statements/blockStatement.h" -#include "ir/statements/returnStatement.h" #include "util/helpers.h" namespace panda::es2panda::checker { @@ -472,9 +464,8 @@ checker::Type *ETSAnalyzer::Check(ir::SuperExpression *expr) const UNREACHABLE(); } -checker::Type *ETSAnalyzer::Check(ir::TaggedTemplateExpression *expr) const +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TaggedTemplateExpression *expr) const { - (void)expr; UNREACHABLE(); } @@ -498,8 +489,36 @@ checker::Type *ETSAnalyzer::Check(ir::UnaryExpression *expr) const checker::Type *ETSAnalyzer::Check(ir::UpdateExpression *expr) const { - (void)expr; - UNREACHABLE(); + ETSChecker *checker = GetETSChecker(); + if (expr->TsType() != nullptr) { + return expr->TsType(); + } + + checker::Type *operand_type = expr->argument_->Check(checker); + if (expr->Argument()->IsIdentifier()) { + checker->ValidateUnaryOperatorOperand(expr->Argument()->AsIdentifier()->Variable()); + } else { + ASSERT(expr->Argument()->IsMemberExpression()); + varbinder::LocalVariable *prop_var = expr->argument_->AsMemberExpression()->PropVar(); + if (prop_var != nullptr) { + checker->ValidateUnaryOperatorOperand(prop_var); + } + } + + auto unboxed_type = checker->ETSBuiltinTypeAsPrimitiveType(operand_type); + + if (unboxed_type == nullptr || !unboxed_type->HasTypeFlag(checker::TypeFlag::ETS_NUMERIC)) { + checker->ThrowTypeError("Bad operand type, the type of the operand must be numeric type.", + expr->Argument()->Start()); + } + + if (operand_type->IsETSObjectType()) { + expr->Argument()->AddBoxingUnboxingFlag(checker->GetUnboxingFlag(unboxed_type) | + checker->GetBoxingFlag(unboxed_type)); + } + + expr->SetTsType(operand_type); + return expr->TsType(); } checker::Type *ETSAnalyzer::Check(ir::YieldExpression *expr) const @@ -938,8 +957,12 @@ checker::Type *ETSAnalyzer::Check(ir::VariableDeclarator *st) const checker::Type *ETSAnalyzer::Check(ir::VariableDeclaration *st) const { - (void)st; - UNREACHABLE(); + ETSChecker *checker = GetETSChecker(); + for (auto *it : st->Declarators()) { + it->Check(checker); + } + + return nullptr; } checker::Type *ETSAnalyzer::Check(ir::WhileStatement *st) const @@ -962,8 +985,37 @@ checker::Type *ETSAnalyzer::Check(ir::TSArrayType *node) const checker::Type *ETSAnalyzer::Check(ir::TSAsExpression *expr) const { - (void)expr; - UNREACHABLE(); + ETSChecker *checker = GetETSChecker(); + + auto *const target_type = expr->TypeAnnotation()->AsTypeNode()->GetType(checker); + // Object expression requires that its type be set by the context before checking. in this case, the target type + // provides that context. + if (expr->Expr()->IsObjectExpression()) { + expr->Expr()->AsObjectExpression()->SetPreferredType(target_type); + } + auto *const source_type = expr->Expr()->Check(checker); + + const checker::CastingContext ctx(checker->Relation(), expr->Expr(), source_type, target_type, + expr->Expr()->Start(), + {"Cannot cast type '", source_type, "' to '", target_type, "'"}); + + if (source_type->IsETSDynamicType() && target_type->IsLambdaObject()) { + // NOTE: itrubachev. change target_type to created lambdaobject type. + // Now target_type is not changed, only construct signature is added to it + checker->BuildLambdaObjectClass(target_type->AsETSObjectType(), + expr->TypeAnnotation()->AsETSFunctionType()->ReturnType()); + } + expr->is_unchecked_cast_ = ctx.UncheckedCast(); + + // Make sure the array type symbol gets created for the assembler to be able to emit checkcast. + // Because it might not exist, if this particular array type was never created explicitly. + if (!expr->is_unchecked_cast_ && target_type->IsETSArrayType()) { + auto *const target_array_type = target_type->AsETSArrayType(); + checker->CreateBuiltinArraySignature(target_array_type, target_array_type->Rank()); + } + + expr->SetTsType(target_type); + return expr->TsType(); } checker::Type *ETSAnalyzer::Check(ir::TSBigintKeyword *node) const @@ -978,9 +1030,8 @@ checker::Type *ETSAnalyzer::Check(ir::TSBooleanKeyword *node) const UNREACHABLE(); } -checker::Type *ETSAnalyzer::Check(ir::TSClassImplements *expr) const +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSClassImplements *expr) const { - (void)expr; UNREACHABLE(); } @@ -1044,9 +1095,8 @@ checker::Type *ETSAnalyzer::Check(ir::TSInferType *node) const UNREACHABLE(); } -checker::Type *ETSAnalyzer::Check(ir::TSInterfaceBody *expr) const +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSInterfaceBody *expr) const { - (void)expr; UNREACHABLE(); } @@ -1056,9 +1106,8 @@ checker::Type *ETSAnalyzer::Check(ir::TSInterfaceDeclaration *st) const UNREACHABLE(); } -checker::Type *ETSAnalyzer::Check(ir::TSInterfaceHeritage *expr) const +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSInterfaceHeritage *expr) const { - (void)expr; UNREACHABLE(); } @@ -1092,9 +1141,8 @@ checker::Type *ETSAnalyzer::Check(ir::TSModuleDeclaration *st) const UNREACHABLE(); } -checker::Type *ETSAnalyzer::Check(ir::TSNamedTupleMember *node) const +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSNamedTupleMember *node) const { - (void)node; UNREACHABLE(); } @@ -1158,9 +1206,8 @@ checker::Type *ETSAnalyzer::Check(ir::TSThisType *node) const UNREACHABLE(); } -checker::Type *ETSAnalyzer::Check(ir::TSTupleType *node) const +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSTupleType *node) const { - (void)node; UNREACHABLE(); } @@ -1170,9 +1217,8 @@ checker::Type *ETSAnalyzer::Check(ir::TSTypeAliasDeclaration *st) const UNREACHABLE(); } -checker::Type *ETSAnalyzer::Check(ir::TSTypeAssertion *expr) const +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSTypeAssertion *expr) const { - (void)expr; UNREACHABLE(); } @@ -1212,9 +1258,8 @@ checker::Type *ETSAnalyzer::Check(ir::TSTypePredicate *node) const UNREACHABLE(); } -checker::Type *ETSAnalyzer::Check(ir::TSTypeQuery *node) const +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSTypeQuery *node) const { - (void)node; UNREACHABLE(); } diff --git a/ets2panda/checker/TSAnalyzer.cpp b/ets2panda/checker/TSAnalyzer.cpp index d3e96e821f..e0bb87a81a 100644 --- a/ets2panda/checker/TSAnalyzer.cpp +++ b/ets2panda/checker/TSAnalyzer.cpp @@ -369,10 +369,11 @@ checker::Type *TSAnalyzer::Check(ir::SuperExpression *expr) const UNREACHABLE(); } -checker::Type *TSAnalyzer::Check(ir::TaggedTemplateExpression *expr) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::TaggedTemplateExpression *expr) const { - (void)expr; - UNREACHABLE(); + TSChecker *checker = GetTSChecker(); + // NOTE: aszilagyi. + return checker->GlobalAnyType(); } checker::Type *TSAnalyzer::Check(ir::TemplateLiteral *expr) const @@ -395,8 +396,20 @@ checker::Type *TSAnalyzer::Check(ir::UnaryExpression *expr) const checker::Type *TSAnalyzer::Check(ir::UpdateExpression *expr) const { - (void)expr; - UNREACHABLE(); + TSChecker *checker = GetTSChecker(); + checker::Type *operand_type = expr->argument_->Check(checker); + checker->CheckNonNullType(operand_type, expr->Start()); + + if (!operand_type->HasTypeFlag(checker::TypeFlag::VALID_ARITHMETIC_TYPE)) { + checker->ThrowTypeError("An arithmetic operand must be of type 'any', 'number', 'bigint' or an enum type.", + expr->Start()); + } + + checker->CheckReferenceExpression( + expr->argument_, "The operand of an increment or decrement operator must be a variable or a property access", + "The operand of an increment or decrement operator may not be an optional property access"); + + return checker->GetUnaryResultType(operand_type); } checker::Type *TSAnalyzer::Check(ir::YieldExpression *expr) const @@ -655,8 +668,12 @@ checker::Type *TSAnalyzer::Check(ir::VariableDeclarator *st) const checker::Type *TSAnalyzer::Check(ir::VariableDeclaration *st) const { - (void)st; - UNREACHABLE(); + TSChecker *checker = GetTSChecker(); + for (auto *it : st->Declarators()) { + it->Check(checker); + } + + return nullptr; } checker::Type *TSAnalyzer::Check(ir::WhileStatement *st) const @@ -677,10 +694,76 @@ checker::Type *TSAnalyzer::Check(ir::TSArrayType *node) const UNREACHABLE(); } +static bool IsValidConstAssertionArgument(checker::Checker *checker, const ir::AstNode *arg) +{ + switch (arg->Type()) { + case ir::AstNodeType::NUMBER_LITERAL: + case ir::AstNodeType::STRING_LITERAL: + case ir::AstNodeType::BIGINT_LITERAL: + case ir::AstNodeType::BOOLEAN_LITERAL: + case ir::AstNodeType::ARRAY_EXPRESSION: + case ir::AstNodeType::OBJECT_EXPRESSION: + case ir::AstNodeType::TEMPLATE_LITERAL: { + return true; + } + case ir::AstNodeType::UNARY_EXPRESSION: { + const ir::UnaryExpression *unary_expr = arg->AsUnaryExpression(); + lexer::TokenType op = unary_expr->OperatorType(); + const ir::Expression *unary_arg = unary_expr->Argument(); + return (op == lexer::TokenType::PUNCTUATOR_MINUS && unary_arg->IsLiteral() && + (unary_arg->AsLiteral()->IsNumberLiteral() || unary_arg->AsLiteral()->IsBigIntLiteral())) || + (op == lexer::TokenType::PUNCTUATOR_PLUS && unary_arg->IsLiteral() && + unary_arg->AsLiteral()->IsNumberLiteral()); + } + case ir::AstNodeType::MEMBER_EXPRESSION: { + const ir::MemberExpression *member_expr = arg->AsMemberExpression(); + if (member_expr->Object()->IsIdentifier()) { + auto result = checker->Scope()->Find(member_expr->Object()->AsIdentifier()->Name()); + constexpr auto ENUM_LITERAL_TYPE = checker::EnumLiteralType::EnumLiteralTypeKind::LITERAL; + if (result.variable != nullptr && + result.variable->TsType()->HasTypeFlag(checker::TypeFlag::ENUM_LITERAL) && + result.variable->TsType()->AsEnumLiteralType()->Kind() == ENUM_LITERAL_TYPE) { + return true; + } + } + return false; + } + default: + return false; + } +} + checker::Type *TSAnalyzer::Check(ir::TSAsExpression *expr) const { - (void)expr; - UNREACHABLE(); + TSChecker *checker = GetTSChecker(); + if (expr->IsConst()) { + auto context = checker::SavedCheckerContext(checker, checker::CheckerStatus::IN_CONST_CONTEXT); + checker::Type *expr_type = expr->Expr()->Check(checker); + + if (!IsValidConstAssertionArgument(checker, expr->Expr())) { + checker->ThrowTypeError( + "A 'const' assertions can only be applied to references to enum members, or string, number, " + "boolean, array, or object literals.", + expr->Expr()->Start()); + } + + return expr_type; + } + + auto context = checker::SavedCheckerContext(checker, checker::CheckerStatus::NO_OPTS); + + expr->TypeAnnotation()->Check(checker); + checker::Type *expr_type = checker->GetBaseTypeOfLiteralType(expr->Expr()->Check(checker)); + checker::Type *target_type = expr->TypeAnnotation()->GetType(checker); + + checker->IsTypeComparableTo( + target_type, expr_type, + {"Conversion of type '", expr_type, "' to type '", target_type, + "' may be a mistake because neither type sufficiently overlaps with the other. If this was ", + "intentional, convert the expression to 'unknown' first."}, + expr->Start()); + + return target_type; } checker::Type *TSAnalyzer::Check(ir::TSBigintKeyword *node) const @@ -695,9 +778,8 @@ checker::Type *TSAnalyzer::Check(ir::TSBooleanKeyword *node) const UNREACHABLE(); } -checker::Type *TSAnalyzer::Check(ir::TSClassImplements *expr) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::TSClassImplements *expr) const { - (void)expr; UNREACHABLE(); } @@ -763,8 +845,12 @@ checker::Type *TSAnalyzer::Check(ir::TSInferType *node) const checker::Type *TSAnalyzer::Check(ir::TSInterfaceBody *expr) const { - (void)expr; - UNREACHABLE(); + TSChecker *checker = GetTSChecker(); + for (auto *it : expr->Body()) { + it->Check(checker); + } + + return nullptr; } checker::Type *TSAnalyzer::Check(ir::TSInterfaceDeclaration *st) const @@ -773,9 +859,8 @@ checker::Type *TSAnalyzer::Check(ir::TSInterfaceDeclaration *st) const UNREACHABLE(); } -checker::Type *TSAnalyzer::Check(ir::TSInterfaceHeritage *expr) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::TSInterfaceHeritage *expr) const { - (void)expr; UNREACHABLE(); } @@ -811,8 +896,9 @@ checker::Type *TSAnalyzer::Check(ir::TSModuleDeclaration *st) const checker::Type *TSAnalyzer::Check(ir::TSNamedTupleMember *node) const { - (void)node; - UNREACHABLE(); + TSChecker *checker = GetTSChecker(); + node->ElementType()->Check(checker); + return nullptr; } checker::Type *TSAnalyzer::Check(ir::TSNeverKeyword *node) const @@ -877,8 +963,13 @@ checker::Type *TSAnalyzer::Check(ir::TSThisType *node) const checker::Type *TSAnalyzer::Check(ir::TSTupleType *node) const { - (void)node; - UNREACHABLE(); + TSChecker *checker = GetTSChecker(); + for (auto *it : node->ElementType()) { + it->Check(checker); + } + + node->GetType(checker); + return nullptr; } checker::Type *TSAnalyzer::Check(ir::TSTypeAliasDeclaration *st) const @@ -887,9 +978,8 @@ checker::Type *TSAnalyzer::Check(ir::TSTypeAliasDeclaration *st) const UNREACHABLE(); } -checker::Type *TSAnalyzer::Check(ir::TSTypeAssertion *expr) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::TSTypeAssertion *expr) const { - (void)expr; UNREACHABLE(); } @@ -931,8 +1021,13 @@ checker::Type *TSAnalyzer::Check(ir::TSTypePredicate *node) const checker::Type *TSAnalyzer::Check(ir::TSTypeQuery *node) const { - (void)node; - UNREACHABLE(); + TSChecker *checker = GetTSChecker(); + if (node->TsType() != nullptr) { + return node->TsType(); + } + + node->SetTsType(node->expr_name_->Check(checker)); + return node->TsType(); } checker::Type *TSAnalyzer::Check(ir::TSTypeReference *node) const diff --git a/ets2panda/compiler/core/ETSCompiler.cpp b/ets2panda/compiler/core/ETSCompiler.cpp index 46dd096ae8..507b291ea3 100644 --- a/ets2panda/compiler/core/ETSCompiler.cpp +++ b/ets2panda/compiler/core/ETSCompiler.cpp @@ -16,11 +16,11 @@ #include "ETSCompiler.h" #include "checker/types/ets/etsDynamicFunctionType.h" +#include "checker/types/ts/enumLiteralType.h" #include "compiler/base/condition.h" #include "compiler/base/lreference.h" #include "compiler/core/ETSGen.h" #include "compiler/function/functionBuilder.h" - namespace panda::es2panda::compiler { ETSGen *ETSCompiler::GetETSGen() const @@ -370,9 +370,8 @@ void ETSCompiler::Compile(const ir::SuperExpression *expr) const UNREACHABLE(); } -void ETSCompiler::Compile(const ir::TaggedTemplateExpression *expr) const +void ETSCompiler::Compile([[maybe_unused]] const ir::TaggedTemplateExpression *expr) const { - (void)expr; UNREACHABLE(); } @@ -396,8 +395,43 @@ void ETSCompiler::Compile(const ir::UnaryExpression *expr) const void ETSCompiler::Compile(const ir::UpdateExpression *expr) const { - (void)expr; - UNREACHABLE(); + ETSGen *etsg = GetETSGen(); + + auto lref = compiler::ETSLReference::Create(etsg, expr->Argument(), false); + + const auto argument_boxing_flags = static_cast(expr->Argument()->GetBoxingUnboxingFlags() & + ir::BoxingUnboxingFlags::BOXING_FLAG); + const auto argument_unboxing_flags = static_cast( + expr->Argument()->GetBoxingUnboxingFlags() & ir::BoxingUnboxingFlags::UNBOXING_FLAG); + + if (expr->IsPrefix()) { + lref.GetValue(); + expr->Argument()->SetBoxingUnboxingFlags(argument_unboxing_flags); + etsg->ApplyConversion(expr->Argument(), nullptr); + etsg->Update(expr, expr->OperatorType()); + expr->Argument()->SetBoxingUnboxingFlags(argument_boxing_flags); + etsg->ApplyConversion(expr->Argument(), expr->Argument()->TsType()); + lref.SetValue(); + return; + } + + // workaround so argument_ does not get auto unboxed by lref.GetValue() + expr->Argument()->SetBoxingUnboxingFlags(ir::BoxingUnboxingFlags::NONE); + lref.GetValue(); + + compiler::RegScope rs(etsg); + compiler::VReg original_value_reg = etsg->AllocReg(); + etsg->StoreAccumulator(expr->Argument(), original_value_reg); + + expr->Argument()->SetBoxingUnboxingFlags(argument_unboxing_flags); + etsg->ApplyConversion(expr->Argument(), nullptr); + etsg->Update(expr, expr->OperatorType()); + + expr->Argument()->SetBoxingUnboxingFlags(argument_boxing_flags); + etsg->ApplyConversion(expr->Argument(), expr->Argument()->TsType()); + lref.SetValue(); + + etsg->LoadAccumulator(expr->Argument(), original_value_reg); } void ETSCompiler::Compile(const ir::YieldExpression *expr) const @@ -668,8 +702,10 @@ void ETSCompiler::Compile(const ir::VariableDeclarator *st) const void ETSCompiler::Compile(const ir::VariableDeclaration *st) const { - (void)st; - UNREACHABLE(); + ETSGen *etsg = GetETSGen(); + for (const auto *it : st->Declarators()) { + it->Compile(etsg); + } } void ETSCompiler::Compile(const ir::WhileStatement *st) const @@ -692,8 +728,75 @@ void ETSCompiler::Compile(const ir::TSArrayType *node) const void ETSCompiler::Compile(const ir::TSAsExpression *expr) const { - (void)expr; - UNREACHABLE(); + ETSGen *etsg = GetETSGen(); + + auto ttctx = compiler::TargetTypeContext(etsg, nullptr); + if (!etsg->TryLoadConstantExpression(expr->Expr())) { + expr->Expr()->Compile(etsg); + } + + etsg->ApplyConversion(expr->Expr(), nullptr); + + auto *target_type = expr->TsType(); + if (target_type->IsETSUnionType()) { + target_type = target_type->AsETSUnionType()->FindTypeIsCastableToThis( + expr->expression_, etsg->Checker()->Relation(), expr->expression_->TsType()); + } + switch (checker::ETSChecker::TypeKind(target_type)) { + case checker::TypeFlag::ETS_BOOLEAN: { + etsg->CastToBoolean(expr); + break; + } + case checker::TypeFlag::CHAR: { + etsg->CastToChar(expr); + break; + } + case checker::TypeFlag::BYTE: { + etsg->CastToByte(expr); + break; + } + case checker::TypeFlag::SHORT: { + etsg->CastToShort(expr); + break; + } + case checker::TypeFlag::INT: { + etsg->CastToInt(expr); + break; + } + case checker::TypeFlag::LONG: { + etsg->CastToLong(expr); + break; + } + case checker::TypeFlag::FLOAT: { + etsg->CastToFloat(expr); + break; + } + case checker::TypeFlag::DOUBLE: { + etsg->CastToDouble(expr); + break; + } + case checker::TypeFlag::ETS_ARRAY: + case checker::TypeFlag::ETS_OBJECT: + case checker::TypeFlag::ETS_DYNAMIC_TYPE: { + etsg->CastToArrayOrObject(expr, target_type, expr->is_unchecked_cast_); + break; + } + case checker::TypeFlag::ETS_STRING_ENUM: + [[fallthrough]]; + case checker::TypeFlag::ETS_ENUM: { + auto *const signature = expr->TsType()->IsETSEnumType() + ? expr->TsType()->AsETSEnumType()->FromIntMethod().global_signature + : expr->TsType()->AsETSStringEnumType()->FromIntMethod().global_signature; + ArenaVector arguments(etsg->Allocator()->Adapter()); + arguments.push_back(expr->expression_); + etsg->CallStatic(expr, signature, arguments); + etsg->SetAccumulatorType(signature->ReturnType()); + break; + } + default: { + UNREACHABLE(); + } + } } void ETSCompiler::Compile(const ir::TSBigintKeyword *node) const @@ -708,9 +811,8 @@ void ETSCompiler::Compile(const ir::TSBooleanKeyword *node) const UNREACHABLE(); } -void ETSCompiler::Compile(const ir::TSClassImplements *expr) const +void ETSCompiler::Compile([[maybe_unused]] const ir::TSClassImplements *expr) const { - (void)expr; UNREACHABLE(); } @@ -774,9 +876,8 @@ void ETSCompiler::Compile(const ir::TSInferType *node) const UNREACHABLE(); } -void ETSCompiler::Compile(const ir::TSInterfaceBody *expr) const +void ETSCompiler::Compile([[maybe_unused]] const ir::TSInterfaceBody *expr) const { - (void)expr; UNREACHABLE(); } @@ -786,9 +887,8 @@ void ETSCompiler::Compile(const ir::TSInterfaceDeclaration *st) const UNREACHABLE(); } -void ETSCompiler::Compile(const ir::TSInterfaceHeritage *expr) const +void ETSCompiler::Compile([[maybe_unused]] const ir::TSInterfaceHeritage *expr) const { - (void)expr; UNREACHABLE(); } @@ -822,9 +922,8 @@ void ETSCompiler::Compile(const ir::TSModuleDeclaration *st) const UNREACHABLE(); } -void ETSCompiler::Compile(const ir::TSNamedTupleMember *node) const +void ETSCompiler::Compile([[maybe_unused]] const ir::TSNamedTupleMember *node) const { - (void)node; UNREACHABLE(); } @@ -888,9 +987,8 @@ void ETSCompiler::Compile(const ir::TSThisType *node) const UNREACHABLE(); } -void ETSCompiler::Compile(const ir::TSTupleType *node) const +void ETSCompiler::Compile([[maybe_unused]] const ir::TSTupleType *node) const { - (void)node; UNREACHABLE(); } @@ -900,9 +998,8 @@ void ETSCompiler::Compile(const ir::TSTypeAliasDeclaration *st) const UNREACHABLE(); } -void ETSCompiler::Compile(const ir::TSTypeAssertion *expr) const +void ETSCompiler::Compile([[maybe_unused]] const ir::TSTypeAssertion *expr) const { - (void)expr; UNREACHABLE(); } @@ -942,9 +1039,8 @@ void ETSCompiler::Compile(const ir::TSTypePredicate *node) const UNREACHABLE(); } -void ETSCompiler::Compile(const ir::TSTypeQuery *node) const +void ETSCompiler::Compile([[maybe_unused]] const ir::TSTypeQuery *node) const { - (void)node; UNREACHABLE(); } diff --git a/ets2panda/compiler/core/JSCompiler.cpp b/ets2panda/compiler/core/JSCompiler.cpp index 10a894d364..45b9f8f018 100644 --- a/ets2panda/compiler/core/JSCompiler.cpp +++ b/ets2panda/compiler/core/JSCompiler.cpp @@ -20,7 +20,6 @@ #include "compiler/core/pandagen.h" #include "compiler/function/functionBuilder.h" #include "util/helpers.h" - namespace panda::es2panda::compiler { PandaGen *JSCompiler::GetPandaGen() const @@ -674,8 +673,20 @@ void JSCompiler::Compile(const ir::SuperExpression *expr) const void JSCompiler::Compile(const ir::TaggedTemplateExpression *expr) const { - (void)expr; - UNREACHABLE(); + PandaGen *pg = GetPandaGen(); + compiler::RegScope rs(pg); + compiler::VReg callee = pg->AllocReg(); + compiler::VReg this_reg = compiler::VReg::Invalid(); + + if (expr->Tag()->IsMemberExpression()) { + this_reg = pg->AllocReg(); + compiler::RegScope mrs(pg); + expr->Tag()->AsMemberExpression()->CompileToReg(pg, this_reg); + } else { + expr->Tag()->Compile(pg); + } + + pg->CallTagged(expr, callee, this_reg, expr->Quasi()->Expressions()); } void JSCompiler::Compile(const ir::TemplateLiteral *expr) const @@ -698,8 +709,21 @@ void JSCompiler::Compile(const ir::UnaryExpression *expr) const void JSCompiler::Compile(const ir::UpdateExpression *expr) const { - (void)expr; - UNREACHABLE(); + PandaGen *pg = GetPandaGen(); + compiler::RegScope rs(pg); + compiler::VReg operand_reg = pg->AllocReg(); + + auto lref = compiler::JSLReference::Create(pg, expr->Argument(), false); + lref.GetValue(); + + pg->StoreAccumulator(expr, operand_reg); + pg->Unary(expr, expr->OperatorType(), operand_reg); + + lref.SetValue(); + + if (!expr->IsPrefix()) { + pg->ToNumber(expr, operand_reg); + } } void JSCompiler::Compile(const ir::YieldExpression *expr) const @@ -953,8 +977,10 @@ void JSCompiler::Compile(const ir::VariableDeclarator *st) const void JSCompiler::Compile(const ir::VariableDeclaration *st) const { - (void)st; - UNREACHABLE(); + PandaGen *pg = GetPandaGen(); + for (const auto *it : st->Declarators()) { + it->Compile(pg); + } } void JSCompiler::Compile(const ir::WhileStatement *st) const @@ -975,9 +1001,8 @@ void JSCompiler::Compile(const ir::TSArrayType *node) const UNREACHABLE(); } -void JSCompiler::Compile(const ir::TSAsExpression *expr) const +void JSCompiler::Compile([[maybe_unused]] const ir::TSAsExpression *expr) const { - (void)expr; UNREACHABLE(); } @@ -993,9 +1018,8 @@ void JSCompiler::Compile(const ir::TSBooleanKeyword *node) const UNREACHABLE(); } -void JSCompiler::Compile(const ir::TSClassImplements *expr) const +void JSCompiler::Compile([[maybe_unused]] const ir::TSClassImplements *expr) const { - (void)expr; UNREACHABLE(); } @@ -1059,9 +1083,8 @@ void JSCompiler::Compile(const ir::TSInferType *node) const UNREACHABLE(); } -void JSCompiler::Compile(const ir::TSInterfaceBody *expr) const +void JSCompiler::Compile([[maybe_unused]] const ir::TSInterfaceBody *expr) const { - (void)expr; UNREACHABLE(); } @@ -1071,9 +1094,8 @@ void JSCompiler::Compile(const ir::TSInterfaceDeclaration *st) const UNREACHABLE(); } -void JSCompiler::Compile(const ir::TSInterfaceHeritage *expr) const +void JSCompiler::Compile([[maybe_unused]] const ir::TSInterfaceHeritage *expr) const { - (void)expr; UNREACHABLE(); } @@ -1107,9 +1129,8 @@ void JSCompiler::Compile(const ir::TSModuleDeclaration *st) const UNREACHABLE(); } -void JSCompiler::Compile(const ir::TSNamedTupleMember *node) const +void JSCompiler::Compile([[maybe_unused]] const ir::TSNamedTupleMember *node) const { - (void)node; UNREACHABLE(); } @@ -1173,9 +1194,8 @@ void JSCompiler::Compile(const ir::TSThisType *node) const UNREACHABLE(); } -void JSCompiler::Compile(const ir::TSTupleType *node) const +void JSCompiler::Compile([[maybe_unused]] const ir::TSTupleType *node) const { - (void)node; UNREACHABLE(); } @@ -1185,9 +1205,8 @@ void JSCompiler::Compile(const ir::TSTypeAliasDeclaration *st) const UNREACHABLE(); } -void JSCompiler::Compile(const ir::TSTypeAssertion *expr) const +void JSCompiler::Compile([[maybe_unused]] const ir::TSTypeAssertion *expr) const { - (void)expr; UNREACHABLE(); } @@ -1221,15 +1240,13 @@ void JSCompiler::Compile(const ir::TSTypeParameterInstantiation *expr) const UNREACHABLE(); } -void JSCompiler::Compile(const ir::TSTypePredicate *node) const +void JSCompiler::Compile([[maybe_unused]] const ir::TSTypePredicate *node) const { - (void)node; UNREACHABLE(); } -void JSCompiler::Compile(const ir::TSTypeQuery *node) const +void JSCompiler::Compile([[maybe_unused]] const ir::TSTypeQuery *node) const { - (void)node; UNREACHABLE(); } diff --git a/ets2panda/ir/expressions/taggedTemplateExpression.cpp b/ets2panda/ir/expressions/taggedTemplateExpression.cpp index 3960c0d1c3..2e36f30718 100644 --- a/ets2panda/ir/expressions/taggedTemplateExpression.cpp +++ b/ets2panda/ir/expressions/taggedTemplateExpression.cpp @@ -17,6 +17,7 @@ #include "varbinder/variable.h" #include "compiler/base/literals.h" +#include "compiler/core/ETSGen.h" #include "compiler/core/pandagen.h" #include "compiler/core/regScope.h" #include "checker/TSchecker.h" @@ -56,30 +57,22 @@ void TaggedTemplateExpression::Dump(ir::AstDumper *dumper) const void TaggedTemplateExpression::Compile(compiler::PandaGen *pg) const { - compiler::RegScope rs(pg); - compiler::VReg callee = pg->AllocReg(); - compiler::VReg this_reg = compiler::VReg::Invalid(); - - if (tag_->IsMemberExpression()) { - this_reg = pg->AllocReg(); - compiler::RegScope mrs(pg); - tag_->AsMemberExpression()->CompileToReg(pg, this_reg); - } else { - tag_->Compile(pg); - } + pg->GetAstCompiler()->Compile(this); +} - pg->CallTagged(this, callee, this_reg, quasi_->Expressions()); +void TaggedTemplateExpression::Compile(compiler::ETSGen *etsg) const +{ + etsg->GetAstCompiler()->Compile(this); } checker::Type *TaggedTemplateExpression::Check(checker::TSChecker *checker) { - // NOTE: aszilagyi. - return checker->GlobalAnyType(); + return checker->GetAnalyzer()->Check(this); } checker::Type *TaggedTemplateExpression::Check([[maybe_unused]] checker::ETSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } // NOLINTNEXTLINE(google-default-arguments) diff --git a/ets2panda/ir/expressions/taggedTemplateExpression.h b/ets2panda/ir/expressions/taggedTemplateExpression.h index 194571cf79..5cbfe869c4 100644 --- a/ets2panda/ir/expressions/taggedTemplateExpression.h +++ b/ets2panda/ir/expressions/taggedTemplateExpression.h @@ -58,6 +58,7 @@ public: void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; void Compile([[maybe_unused]] compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; diff --git a/ets2panda/ir/expressions/updateExpression.cpp b/ets2panda/ir/expressions/updateExpression.cpp index e72ca193e8..0266964d17 100644 --- a/ets2panda/ir/expressions/updateExpression.cpp +++ b/ets2panda/ir/expressions/updateExpression.cpp @@ -45,107 +45,22 @@ void UpdateExpression::Dump(ir::AstDumper *dumper) const void UpdateExpression::Compile(compiler::PandaGen *pg) const { - compiler::RegScope rs(pg); - compiler::VReg operand_reg = pg->AllocReg(); - - auto lref = compiler::JSLReference::Create(pg, argument_, false); - lref.GetValue(); - - pg->StoreAccumulator(this, operand_reg); - pg->Unary(this, operator_, operand_reg); - - lref.SetValue(); - - if (!IsPrefix()) { - pg->ToNumber(this, operand_reg); - } + pg->GetAstCompiler()->Compile(this); } void UpdateExpression::Compile(compiler::ETSGen *etsg) const { - auto lref = compiler::ETSLReference::Create(etsg, argument_, false); - - const auto argument_boxing_flags = - static_cast(argument_->GetBoxingUnboxingFlags() & BoxingUnboxingFlags::BOXING_FLAG); - const auto argument_unboxing_flags = - static_cast(argument_->GetBoxingUnboxingFlags() & BoxingUnboxingFlags::UNBOXING_FLAG); - - if (prefix_) { - lref.GetValue(); - argument_->SetBoxingUnboxingFlags(argument_unboxing_flags); - etsg->ApplyConversion(argument_, nullptr); - etsg->Update(this, operator_); - argument_->SetBoxingUnboxingFlags(argument_boxing_flags); - etsg->ApplyConversion(argument_, argument_->TsType()); - lref.SetValue(); - return; - } - - // workaround so argument_ does not get auto unboxed by lref.GetValue() - argument_->SetBoxingUnboxingFlags(BoxingUnboxingFlags::NONE); - lref.GetValue(); - - compiler::RegScope rs(etsg); - compiler::VReg original_value_reg = etsg->AllocReg(); - etsg->StoreAccumulator(argument_, original_value_reg); - - argument_->SetBoxingUnboxingFlags(argument_unboxing_flags); - etsg->ApplyConversion(argument_, nullptr); - etsg->Update(this, operator_); - - argument_->SetBoxingUnboxingFlags(argument_boxing_flags); - etsg->ApplyConversion(argument_, argument_->TsType()); - lref.SetValue(); - - etsg->LoadAccumulator(argument_, original_value_reg); + etsg->GetAstCompiler()->Compile(this); } checker::Type *UpdateExpression::Check(checker::TSChecker *checker) { - checker::Type *operand_type = argument_->Check(checker); - checker->CheckNonNullType(operand_type, Start()); - - if (!operand_type->HasTypeFlag(checker::TypeFlag::VALID_ARITHMETIC_TYPE)) { - checker->ThrowTypeError("An arithmetic operand must be of type 'any', 'number', 'bigint' or an enum type.", - Start()); - } - - checker->CheckReferenceExpression( - argument_, "The operand of an increment or decrement operator must be a variable or a property access", - "The operand of an increment or decrement operator may not be an optional property access"); - - return checker->GetUnaryResultType(operand_type); + return checker->GetAnalyzer()->Check(this); } checker::Type *UpdateExpression::Check(checker::ETSChecker *checker) { - if (TsType() != nullptr) { - return TsType(); - } - - checker::Type *operand_type = argument_->Check(checker); - if (argument_->IsIdentifier()) { - checker->ValidateUnaryOperatorOperand(argument_->AsIdentifier()->Variable()); - } else { - ASSERT(argument_->IsMemberExpression()); - varbinder::LocalVariable *prop_var = argument_->AsMemberExpression()->PropVar(); - if (prop_var != nullptr) { - checker->ValidateUnaryOperatorOperand(prop_var); - } - } - - auto unboxed_type = checker->ETSBuiltinTypeAsPrimitiveType(operand_type); - - if (unboxed_type == nullptr || !unboxed_type->HasTypeFlag(checker::TypeFlag::ETS_NUMERIC)) { - checker->ThrowTypeError("Bad operand type, the type of the operand must be numeric type.", argument_->Start()); - } - - if (operand_type->IsETSObjectType()) { - argument_->AddBoxingUnboxingFlag(checker->GetUnboxingFlag(unboxed_type) | checker->GetBoxingFlag(unboxed_type)); - } - - SetTsType(operand_type); - return TsType(); + return checker->GetAnalyzer()->Check(this); } // NOLINTNEXTLINE(google-default-arguments) diff --git a/ets2panda/ir/expressions/updateExpression.h b/ets2panda/ir/expressions/updateExpression.h index 34901b1845..aa908e434b 100644 --- a/ets2panda/ir/expressions/updateExpression.h +++ b/ets2panda/ir/expressions/updateExpression.h @@ -18,7 +18,10 @@ #include "ir/expression.h" #include "lexer/token/tokenType.h" - +namespace panda::es2panda::checker { +class TSAnalyzer; +class ETSAnalyzer; +} // namespace panda::es2panda::checker namespace panda::es2panda::ir { class UpdateExpression : public Expression { public: @@ -38,6 +41,10 @@ public: update_operator == lexer::TokenType::PUNCTUATOR_MINUS_MINUS); } + // TODO (vivienvoros): these friend relationships can be removed once there are getters for private fields + friend class checker::TSAnalyzer; + friend class checker::ETSAnalyzer; + [[nodiscard]] lexer::TokenType OperatorType() const noexcept { return operator_; diff --git a/ets2panda/ir/statements/variableDeclaration.cpp b/ets2panda/ir/statements/variableDeclaration.cpp index a8a79bc6d7..205265a3da 100644 --- a/ets2panda/ir/statements/variableDeclaration.cpp +++ b/ets2panda/ir/statements/variableDeclaration.cpp @@ -19,6 +19,8 @@ #include "varbinder/variable.h" #include "checker/TSchecker.h" #include "checker/ETSchecker.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" #include "ir/astDump.h" #include "ir/base/decorator.h" #include "ir/expressions/arrayExpression.h" @@ -80,33 +82,21 @@ void VariableDeclaration::Dump(ir::AstDumper *dumper) const void VariableDeclaration::Compile(compiler::PandaGen *pg) const { - for (const auto *it : declarators_) { - it->Compile(pg); - } + pg->GetAstCompiler()->Compile(this); } void VariableDeclaration::Compile(compiler::ETSGen *etsg) const { - for (const auto *it : declarators_) { - it->Compile(etsg); - } + etsg->GetAstCompiler()->Compile(this); } checker::Type *VariableDeclaration::Check(checker::TSChecker *checker) { - for (auto *it : declarators_) { - it->Check(checker); - } - - return nullptr; + return checker->GetAnalyzer()->Check(this); } checker::Type *VariableDeclaration::Check([[maybe_unused]] checker::ETSChecker *checker) { - for (auto *it : declarators_) { - it->Check(checker); - } - - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/ts/tsAsExpression.cpp b/ets2panda/ir/ts/tsAsExpression.cpp index fc81c5a920..faeaf45c3c 100644 --- a/ets2panda/ir/ts/tsAsExpression.cpp +++ b/ets2panda/ir/ts/tsAsExpression.cpp @@ -20,6 +20,7 @@ #include "checker/ets/castingContext.h" #include "checker/types/ets/etsUnionType.h" #include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" #include "ir/expressions/identifier.h" #include "ir/expressions/literal.h" #include "ir/expressions/memberExpression.h" @@ -57,179 +58,23 @@ void TSAsExpression::Dump(ir::AstDumper *dumper) const dumper->Add({{"type", "TSAsExpression"}, {"expression", expression_}, {"typeAnnotation", TypeAnnotation()}}); } -void TSAsExpression::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} - -void TSAsExpression::Compile(compiler::ETSGen *etsg) const +void TSAsExpression::Compile([[maybe_unused]] compiler::PandaGen *pg) const { - auto ttctx = compiler::TargetTypeContext(etsg, nullptr); - if (!etsg->TryLoadConstantExpression(expression_)) { - expression_->Compile(etsg); - } - - etsg->ApplyConversion(expression_, nullptr); - - auto *target_type = TsType(); - if (target_type->IsETSUnionType()) { - target_type = target_type->AsETSUnionType()->FindTypeIsCastableToThis(expression_, etsg->Checker()->Relation(), - expression_->TsType()); - } - switch (checker::ETSChecker::TypeKind(target_type)) { - case checker::TypeFlag::ETS_BOOLEAN: { - etsg->CastToBoolean(this); - break; - } - case checker::TypeFlag::CHAR: { - etsg->CastToChar(this); - break; - } - case checker::TypeFlag::BYTE: { - etsg->CastToByte(this); - break; - } - case checker::TypeFlag::SHORT: { - etsg->CastToShort(this); - break; - } - case checker::TypeFlag::INT: { - etsg->CastToInt(this); - break; - } - case checker::TypeFlag::LONG: { - etsg->CastToLong(this); - break; - } - case checker::TypeFlag::FLOAT: { - etsg->CastToFloat(this); - break; - } - case checker::TypeFlag::DOUBLE: { - etsg->CastToDouble(this); - break; - } - case checker::TypeFlag::ETS_ARRAY: - case checker::TypeFlag::ETS_OBJECT: - case checker::TypeFlag::ETS_DYNAMIC_TYPE: { - etsg->CastToArrayOrObject(this, target_type, is_unchecked_cast_); - break; - } - case checker::TypeFlag::ETS_STRING_ENUM: - [[fallthrough]]; - case checker::TypeFlag::ETS_ENUM: { - auto *const signature = TsType()->IsETSEnumType() - ? TsType()->AsETSEnumType()->FromIntMethod().global_signature - : TsType()->AsETSStringEnumType()->FromIntMethod().global_signature; - ArenaVector arguments(etsg->Allocator()->Adapter()); - arguments.push_back(expression_); - etsg->CallStatic(this, signature, arguments); - etsg->SetAccumulatorType(signature->ReturnType()); - break; - } - default: { - UNREACHABLE(); - } - } + pg->GetAstCompiler()->Compile(this); } -static bool IsValidConstAssertionArgument(checker::Checker *checker, const ir::AstNode *arg) +void TSAsExpression::Compile(compiler::ETSGen *etsg) const { - switch (arg->Type()) { - case ir::AstNodeType::NUMBER_LITERAL: - case ir::AstNodeType::STRING_LITERAL: - case ir::AstNodeType::BIGINT_LITERAL: - case ir::AstNodeType::BOOLEAN_LITERAL: - case ir::AstNodeType::ARRAY_EXPRESSION: - case ir::AstNodeType::OBJECT_EXPRESSION: - case ir::AstNodeType::TEMPLATE_LITERAL: { - return true; - } - case ir::AstNodeType::UNARY_EXPRESSION: { - const ir::UnaryExpression *unary_expr = arg->AsUnaryExpression(); - lexer::TokenType op = unary_expr->OperatorType(); - const ir::Expression *unary_arg = unary_expr->Argument(); - return (op == lexer::TokenType::PUNCTUATOR_MINUS && unary_arg->IsLiteral() && - (unary_arg->AsLiteral()->IsNumberLiteral() || unary_arg->AsLiteral()->IsBigIntLiteral())) || - (op == lexer::TokenType::PUNCTUATOR_PLUS && unary_arg->IsLiteral() && - unary_arg->AsLiteral()->IsNumberLiteral()); - } - case ir::AstNodeType::MEMBER_EXPRESSION: { - const ir::MemberExpression *member_expr = arg->AsMemberExpression(); - if (member_expr->Object()->IsIdentifier()) { - auto result = checker->Scope()->Find(member_expr->Object()->AsIdentifier()->Name()); - constexpr auto ENUM_LITERAL_TYPE = checker::EnumLiteralType::EnumLiteralTypeKind::LITERAL; - if (result.variable != nullptr && - result.variable->TsType()->HasTypeFlag(checker::TypeFlag::ENUM_LITERAL) && - result.variable->TsType()->AsEnumLiteralType()->Kind() == ENUM_LITERAL_TYPE) { - return true; - } - } - return false; - } - default: - return false; - } + etsg->GetAstCompiler()->Compile(this); } checker::Type *TSAsExpression::Check([[maybe_unused]] checker::TSChecker *checker) { - if (is_const_) { - auto context = checker::SavedCheckerContext(checker, checker::CheckerStatus::IN_CONST_CONTEXT); - checker::Type *expr_type = expression_->Check(checker); - - if (!IsValidConstAssertionArgument(checker, expression_)) { - checker->ThrowTypeError( - "A 'const' assertions can only be applied to references to enum members, or string, number, " - "boolean, array, or object literals.", - expression_->Start()); - } - - return expr_type; - } - - auto context = checker::SavedCheckerContext(checker, checker::CheckerStatus::NO_OPTS); - - TypeAnnotation()->Check(checker); - checker::Type *expr_type = checker->GetBaseTypeOfLiteralType(expression_->Check(checker)); - checker::Type *target_type = TypeAnnotation()->GetType(checker); - - checker->IsTypeComparableTo( - target_type, expr_type, - {"Conversion of type '", expr_type, "' to type '", target_type, - "' may be a mistake because neither type sufficiently overlaps with the other. If this was ", - "intentional, convert the expression to 'unknown' first."}, - Start()); - - return target_type; + return checker->GetAnalyzer()->Check(this); } checker::Type *TSAsExpression::Check(checker::ETSChecker *const checker) { - auto *const target_type = TypeAnnotation()->AsTypeNode()->GetType(checker); - // Object expression requires that its type be set by the context before checking. in this case, the target type - // provides that context. - if (expression_->IsObjectExpression()) { - expression_->AsObjectExpression()->SetPreferredType(target_type); - } - auto *const source_type = expression_->Check(checker); - - const checker::CastingContext ctx(checker->Relation(), expression_, source_type, target_type, expression_->Start(), - {"Cannot cast type '", source_type, "' to '", target_type, "'"}); - - if (source_type->IsETSDynamicType() && target_type->IsLambdaObject()) { - // NOTE: itrubachev. change target_type to created lambdaobject type. - // Now target_type is not changed, only construct signature is added to it - checker->BuildLambdaObjectClass(target_type->AsETSObjectType(), - TypeAnnotation()->AsETSFunctionType()->ReturnType()); - } - is_unchecked_cast_ = ctx.UncheckedCast(); - - // Make sure the array type symbol gets created for the assembler to be able to emit checkcast. - // Because it might not exist, if this particular array type was never created explicitly. - if (!is_unchecked_cast_ && target_type->IsETSArrayType()) { - auto *const target_array_type = target_type->AsETSArrayType(); - checker->CreateBuiltinArraySignature(target_array_type, target_array_type->Rank()); - } - - SetTsType(target_type); - return TsType(); + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/ts/tsAsExpression.h b/ets2panda/ir/ts/tsAsExpression.h index 549851835e..07242c06db 100644 --- a/ets2panda/ir/ts/tsAsExpression.h +++ b/ets2panda/ir/ts/tsAsExpression.h @@ -18,7 +18,13 @@ #include "ir/astDump.h" #include "ir/expression.h" +namespace panda::es2panda::checker { +class ETSAnalyzer; +} // namespace panda::es2panda::checker +namespace panda::es2panda::compiler { +class ETSCompiler; +} // namespace panda::es2panda::compiler namespace panda::es2panda::ir { class TSAsExpression : public AnnotatedExpression { public: @@ -28,7 +34,9 @@ public: is_const_(is_const) { } - + // TODO (vivienvoros): these friend relationships can be removed once there are getters for private fields + friend class checker::ETSAnalyzer; + friend class compiler::ETSCompiler; const Expression *Expr() const { return expression_; diff --git a/ets2panda/ir/ts/tsClassImplements.cpp b/ets2panda/ir/ts/tsClassImplements.cpp index 00ad11e2df..c3183cd250 100644 --- a/ets2panda/ir/ts/tsClassImplements.cpp +++ b/ets2panda/ir/ts/tsClassImplements.cpp @@ -15,6 +15,9 @@ #include "tsClassImplements.h" +#include "checker/TSchecker.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" #include "ir/astDump.h" #include "ir/ts/tsTypeParameter.h" #include "ir/ts/tsTypeParameterInstantiation.h" @@ -41,15 +44,23 @@ void TSClassImplements::Dump(ir::AstDumper *dumper) const {"typeParameters", AstDumper::Optional(type_parameters_)}}); } -void TSClassImplements::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} +void TSClassImplements::Compile([[maybe_unused]] compiler::PandaGen *pg) const +{ + pg->GetAstCompiler()->Compile(this); +} + +void TSClassImplements::Compile(compiler::ETSGen *etsg) const +{ + etsg->GetAstCompiler()->Compile(this); +} checker::Type *TSClassImplements::Check([[maybe_unused]] checker::TSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } checker::Type *TSClassImplements::Check([[maybe_unused]] checker::ETSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/ts/tsClassImplements.h b/ets2panda/ir/ts/tsClassImplements.h index 82b5510f92..ca5e0ddd14 100644 --- a/ets2panda/ir/ts/tsClassImplements.h +++ b/ets2panda/ir/ts/tsClassImplements.h @@ -52,6 +52,7 @@ public: void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; void Compile([[maybe_unused]] compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; diff --git a/ets2panda/ir/ts/tsInterfaceBody.cpp b/ets2panda/ir/ts/tsInterfaceBody.cpp index 369391dfbd..418b66f22d 100644 --- a/ets2panda/ir/ts/tsInterfaceBody.cpp +++ b/ets2panda/ir/ts/tsInterfaceBody.cpp @@ -15,6 +15,9 @@ #include "tsInterfaceBody.h" +#include "checker/TSchecker.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" #include "ir/astDump.h" namespace panda::es2panda::ir { @@ -37,19 +40,23 @@ void TSInterfaceBody::Dump(ir::AstDumper *dumper) const dumper->Add({{"type", "TSInterfaceBody"}, {"body", body_}}); } -void TSInterfaceBody::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} +void TSInterfaceBody::Compile([[maybe_unused]] compiler::PandaGen *pg) const +{ + pg->GetAstCompiler()->Compile(this); +} -checker::Type *TSInterfaceBody::Check([[maybe_unused]] checker::TSChecker *checker) +void TSInterfaceBody::Compile(compiler::ETSGen *etsg) const { - for (auto *it : body_) { - it->Check(checker); - } + etsg->GetAstCompiler()->Compile(this); +} - return nullptr; +checker::Type *TSInterfaceBody::Check([[maybe_unused]] checker::TSChecker *checker) +{ + return checker->GetAnalyzer()->Check(this); } checker::Type *TSInterfaceBody::Check([[maybe_unused]] checker::ETSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/ts/tsInterfaceBody.h b/ets2panda/ir/ts/tsInterfaceBody.h index 7197e7c2fc..7124ef9192 100644 --- a/ets2panda/ir/ts/tsInterfaceBody.h +++ b/ets2panda/ir/ts/tsInterfaceBody.h @@ -45,6 +45,7 @@ public: void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; void Compile([[maybe_unused]] compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; diff --git a/ets2panda/ir/ts/tsInterfaceHeritage.cpp b/ets2panda/ir/ts/tsInterfaceHeritage.cpp index fe81446c5c..e14e86ecaa 100644 --- a/ets2panda/ir/ts/tsInterfaceHeritage.cpp +++ b/ets2panda/ir/ts/tsInterfaceHeritage.cpp @@ -17,6 +17,9 @@ #include "varbinder/scope.h" #include "checker/TSchecker.h" +#include "compiler/core/ETSCompiler.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" #include "ir/astDump.h" #include "ir/expressions/identifier.h" #include "ir/ts/tsTypeParameterInstantiation.h" @@ -41,15 +44,23 @@ void TSInterfaceHeritage::Dump(ir::AstDumper *dumper) const }); } -void TSInterfaceHeritage::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} +void TSInterfaceHeritage::Compile([[maybe_unused]] compiler::PandaGen *pg) const +{ + pg->GetAstCompiler()->Compile(this); +} + +void TSInterfaceHeritage::Compile(compiler::ETSGen *etsg) const +{ + etsg->GetAstCompiler()->Compile(this); +} checker::Type *TSInterfaceHeritage::Check([[maybe_unused]] checker::TSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } checker::Type *TSInterfaceHeritage::Check([[maybe_unused]] checker::ETSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/ts/tsInterfaceHeritage.h b/ets2panda/ir/ts/tsInterfaceHeritage.h index 3ce89c33f7..c33615e585 100644 --- a/ets2panda/ir/ts/tsInterfaceHeritage.h +++ b/ets2panda/ir/ts/tsInterfaceHeritage.h @@ -40,6 +40,7 @@ public: void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; void Compile([[maybe_unused]] compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; diff --git a/ets2panda/ir/ts/tsNamedTupleMember.cpp b/ets2panda/ir/ts/tsNamedTupleMember.cpp index e92c5787dd..bfea9f07de 100644 --- a/ets2panda/ir/ts/tsNamedTupleMember.cpp +++ b/ets2panda/ir/ts/tsNamedTupleMember.cpp @@ -15,6 +15,10 @@ #include "tsNamedTupleMember.h" +#include "checker/ETSchecker.h" +#include "checker/TSchecker.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" #include "ir/astDump.h" namespace panda::es2panda::ir { @@ -38,16 +42,23 @@ void TSNamedTupleMember::Dump(ir::AstDumper *dumper) const {"optional", AstDumper::Optional(optional_)}}); } -void TSNamedTupleMember::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} +void TSNamedTupleMember::Compile([[maybe_unused]] compiler::PandaGen *pg) const +{ + pg->GetAstCompiler()->Compile(this); +} + +void TSNamedTupleMember::Compile(compiler::ETSGen *etsg) const +{ + etsg->GetAstCompiler()->Compile(this); +} checker::Type *TSNamedTupleMember::Check([[maybe_unused]] checker::TSChecker *checker) { - element_type_->Check(checker); - return nullptr; + return checker->GetAnalyzer()->Check(this); } checker::Type *TSNamedTupleMember::Check([[maybe_unused]] checker::ETSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/ts/tsNamedTupleMember.h b/ets2panda/ir/ts/tsNamedTupleMember.h index a7266a6a42..47f8bda2ac 100644 --- a/ets2panda/ir/ts/tsNamedTupleMember.h +++ b/ets2panda/ir/ts/tsNamedTupleMember.h @@ -50,6 +50,7 @@ public: void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; void Compile([[maybe_unused]] compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; diff --git a/ets2panda/ir/ts/tsTupleType.cpp b/ets2panda/ir/ts/tsTupleType.cpp index ac326b4659..624d958233 100644 --- a/ets2panda/ir/ts/tsTupleType.cpp +++ b/ets2panda/ir/ts/tsTupleType.cpp @@ -15,6 +15,8 @@ #include "tsTupleType.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" #include "util/helpers.h" #include "varbinder/scope.h" #include "checker/TSchecker.h" @@ -43,7 +45,15 @@ void TSTupleType::Dump(ir::AstDumper *dumper) const dumper->Add({{"type", "TSTupleType"}, {"elementTypes", element_types_}}); } -void TSTupleType::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} +void TSTupleType::Compile([[maybe_unused]] compiler::PandaGen *pg) const +{ + pg->GetAstCompiler()->Compile(this); +} + +void TSTupleType::Compile(compiler::ETSGen *etsg) const +{ + etsg->GetAstCompiler()->Compile(this); +} checker::Type *TSTupleType::GetType(checker::TSChecker *checker) { @@ -118,16 +128,11 @@ checker::Type *TSTupleType::GetType(checker::TSChecker *checker) checker::Type *TSTupleType::Check(checker::TSChecker *checker) { - for (auto *it : element_types_) { - it->Check(checker); - } - - GetType(checker); - return nullptr; + return checker->GetAnalyzer()->Check(this); } checker::Type *TSTupleType::Check([[maybe_unused]] checker::ETSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/ts/tsTupleType.h b/ets2panda/ir/ts/tsTupleType.h index 53a7035397..b0a1d7012b 100644 --- a/ets2panda/ir/ts/tsTupleType.h +++ b/ets2panda/ir/ts/tsTupleType.h @@ -37,6 +37,7 @@ public: void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; void Compile([[maybe_unused]] compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; checker::Type *GetType([[maybe_unused]] checker::TSChecker *checker) override; checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; diff --git a/ets2panda/ir/ts/tsTypeAssertion.cpp b/ets2panda/ir/ts/tsTypeAssertion.cpp index 7abafef59d..2c2bd745e3 100644 --- a/ets2panda/ir/ts/tsTypeAssertion.cpp +++ b/ets2panda/ir/ts/tsTypeAssertion.cpp @@ -15,6 +15,9 @@ #include "tsTypeAssertion.h" +#include "checker/TSchecker.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" #include "ir/astDump.h" #include "ir/typeNode.h" @@ -36,15 +39,23 @@ void TSTypeAssertion::Dump(ir::AstDumper *dumper) const dumper->Add({{"type", "TSTypeAssertion"}, {"typeAnnotation", TypeAnnotation()}, {"expression", expression_}}); } -void TSTypeAssertion::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} +void TSTypeAssertion::Compile([[maybe_unused]] compiler::PandaGen *pg) const +{ + pg->GetAstCompiler()->Compile(this); +} + +void TSTypeAssertion::Compile(compiler::ETSGen *etsg) const +{ + etsg->GetAstCompiler()->Compile(this); +} checker::Type *TSTypeAssertion::Check([[maybe_unused]] checker::TSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } checker::Type *TSTypeAssertion::Check([[maybe_unused]] checker::ETSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/ts/tsTypeAssertion.h b/ets2panda/ir/ts/tsTypeAssertion.h index e8a6617164..8779446839 100644 --- a/ets2panda/ir/ts/tsTypeAssertion.h +++ b/ets2panda/ir/ts/tsTypeAssertion.h @@ -35,6 +35,7 @@ public: void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; void Compile([[maybe_unused]] compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; diff --git a/ets2panda/ir/ts/tsTypeQuery.cpp b/ets2panda/ir/ts/tsTypeQuery.cpp index 31752510bd..cb45ace08c 100644 --- a/ets2panda/ir/ts/tsTypeQuery.cpp +++ b/ets2panda/ir/ts/tsTypeQuery.cpp @@ -15,6 +15,9 @@ #include "tsTypeQuery.h" +#include "checker/ETSchecker.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" #include "ir/astDump.h" #include "checker/TSchecker.h" @@ -34,26 +37,28 @@ void TSTypeQuery::Dump(ir::AstDumper *dumper) const dumper->Add({{"type", "TSTypeQuery"}, {"exprName", expr_name_}}); } -void TSTypeQuery::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} +void TSTypeQuery::Compile([[maybe_unused]] compiler::PandaGen *pg) const +{ + pg->GetAstCompiler()->Compile(this); +} + +void TSTypeQuery::Compile(compiler::ETSGen *etsg) const +{ + etsg->GetAstCompiler()->Compile(this); +} checker::Type *TSTypeQuery::Check([[maybe_unused]] checker::TSChecker *checker) { - GetType(checker); - return nullptr; + return checker->GetAnalyzer()->Check(this); } checker::Type *TSTypeQuery::GetType([[maybe_unused]] checker::TSChecker *checker) { - if (TsType() != nullptr) { - return TsType(); - } - - SetTsType(expr_name_->Check(checker)); - return TsType(); + return checker->GetAnalyzer()->Check(this); } checker::Type *TSTypeQuery::Check([[maybe_unused]] checker::ETSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/ts/tsTypeQuery.h b/ets2panda/ir/ts/tsTypeQuery.h index c4442a5902..b5a3a0d7b0 100644 --- a/ets2panda/ir/ts/tsTypeQuery.h +++ b/ets2panda/ir/ts/tsTypeQuery.h @@ -17,12 +17,16 @@ #define ES2PANDA_IR_TS_TYPE_QUERY_H #include "ir/typeNode.h" - +namespace panda::es2panda::checker { +class TSAnalyzer; +} // namespace panda::es2panda::checker namespace panda::es2panda::ir { class TSTypeQuery : public TypeNode { public: explicit TSTypeQuery(Expression *expr_name) : TypeNode(AstNodeType::TS_TYPE_QUERY), expr_name_(expr_name) {} + friend class checker::TSAnalyzer; + const Expression *ExprName() const { return expr_name_; @@ -32,6 +36,7 @@ public: void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; void Compile([[maybe_unused]] compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; checker::Type *GetType([[maybe_unused]] checker::TSChecker *checker) override; checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; -- Gitee