diff --git a/ets2panda/checker/ETSAnalyzer.cpp b/ets2panda/checker/ETSAnalyzer.cpp index ec729cf22942eacc61d2ca5a674062973d981b88..54d88d386b8b022290202c0959fc453e8994c63c 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 { @@ -180,58 +172,213 @@ checker::Type *ETSAnalyzer::Check(ir::TSPropertySignature *node) const UNREACHABLE(); } -checker::Type *ETSAnalyzer::Check(ir::TSSignatureDeclaration *node) const +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSSignatureDeclaration *node) const { - (void)node; UNREACHABLE(); } // from ets folder checker::Type *ETSAnalyzer::Check(ir::ETSClassLiteral *expr) const { - (void)expr; - UNREACHABLE(); + ETSChecker *checker = GetETSChecker(); + checker->ThrowTypeError("Class literal is not yet supported.", expr->expr_->Start()); + + expr->expr_->Check(checker); + auto *expr_type = expr->expr_->GetType(checker); + + if (expr_type->IsETSVoidType()) { + checker->ThrowTypeError("Invalid .class reference", expr->expr_->Start()); + } + + ArenaVector type_arg_types(checker->Allocator()->Adapter()); + type_arg_types.push_back(expr_type); // NOTE: Box it if it's a primitive type + + checker::InstantiationContext ctx(checker, checker->GlobalBuiltinTypeType(), type_arg_types, expr->range_.start); + expr->SetTsType(ctx.Result()); + return expr->TsType(); } checker::Type *ETSAnalyzer::Check(ir::ETSFunctionType *node) const { - (void)node; - UNREACHABLE(); + ETSChecker *checker = GetETSChecker(); + checker->CreateFunctionalInterfaceForFunctionType(node); + auto *interface_type = + checker->CreateETSObjectType(node->FunctionalInterface()->Id()->Name(), node->FunctionalInterface(), + checker::ETSObjectFlags::FUNCTIONAL_INTERFACE); + interface_type->SetSuperType(checker->GlobalETSObjectType()); + + auto *invoke_func = node->FunctionalInterface()->Body()->Body()[0]->AsMethodDefinition()->Function(); + auto *signature_info = checker->Allocator()->New(checker->Allocator()); + + for (auto *it : invoke_func->Params()) { + auto *const param = it->AsETSParameterExpression(); + if (param->IsRestParameter()) { + auto *rest_ident = param->Ident(); + + ASSERT(rest_ident->Variable()); + signature_info->rest_var = rest_ident->Variable()->AsLocalVariable(); + + ASSERT(param->TypeAnnotation()); + signature_info->rest_var->SetTsType(checker->GetTypeFromTypeAnnotation(param->TypeAnnotation())); + + auto array_type = signature_info->rest_var->TsType()->AsETSArrayType(); + checker->CreateBuiltinArraySignature(array_type, array_type->Rank()); + } else { + auto *param_ident = param->Ident(); + + ASSERT(param_ident->Variable()); + varbinder::Variable *param_var = param_ident->Variable(); + + ASSERT(param->TypeAnnotation()); + param_var->SetTsType(checker->GetTypeFromTypeAnnotation(param->TypeAnnotation())); + signature_info->params.push_back(param_var->AsLocalVariable()); + ++signature_info->min_arg_count; + } + } + + invoke_func->ReturnTypeAnnotation()->Check(checker); + auto *signature = checker->Allocator()->New(signature_info, + node->ReturnType()->GetType(checker), invoke_func); + signature->SetOwnerVar(invoke_func->Id()->Variable()->AsLocalVariable()); + signature->AddSignatureFlag(checker::SignatureFlags::FUNCTIONAL_INTERFACE_SIGNATURE); + signature->SetOwner(interface_type); + + auto *func_type = checker->CreateETSFunctionType(signature); + invoke_func->SetSignature(signature); + invoke_func->Id()->Variable()->SetTsType(func_type); + interface_type->AddProperty( + invoke_func->Id()->Variable()->AsLocalVariable()); + node->FunctionalInterface()->SetTsType(interface_type); + + auto *this_var = invoke_func->Scope()->ParamScope()->Params().front(); + this_var->SetTsType(interface_type); + checker->BuildFunctionalInterfaceName(node); + + node->SetTsType(interface_type); + return interface_type; } -checker::Type *ETSAnalyzer::Check(ir::ETSImportDeclaration *node) const +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::ETSImportDeclaration *node) const { - (void)node; UNREACHABLE(); } checker::Type *ETSAnalyzer::Check(ir::ETSLaunchExpression *expr) const { - (void)expr; - UNREACHABLE(); + ETSChecker *checker = GetETSChecker(); + expr->expr_->Check(checker); + auto *const launch_promise_type = + checker->GlobalBuiltinPromiseType() + ->Instantiate(checker->Allocator(), checker->Relation(), checker->GetGlobalTypesHolder()) + ->AsETSObjectType(); + launch_promise_type->AddTypeFlag(checker::TypeFlag::GENERIC); + + // Launch expression returns a Promise type, so we need to insert the expression's type + // as type parameter for the Promise class. + + auto *expr_type = + expr->expr_->TsType()->HasTypeFlag(checker::TypeFlag::ETS_PRIMITIVE) && !expr->expr_->TsType()->IsETSVoidType() + ? checker->PrimitiveTypeAsETSBuiltinType(expr->expr_->TsType()) + : expr->expr_->TsType(); + checker::Substitution *substitution = checker->NewSubstitution(); + ASSERT(launch_promise_type->TypeArguments().size() == 1); + substitution->emplace(checker->GetOriginalBaseType(launch_promise_type->TypeArguments()[0]), expr_type); + + expr->SetTsType(launch_promise_type->Substitute(checker->Relation(), substitution)); + return expr->TsType(); } checker::Type *ETSAnalyzer::Check(ir::ETSNewArrayInstanceExpression *expr) const { - (void)expr; - UNREACHABLE(); + ETSChecker *checker = GetETSChecker(); + + auto *element_type = expr->type_reference_->GetType(checker); + checker->ValidateArrayIndex(expr->dimension_); + + expr->SetTsType(checker->CreateETSArrayType(element_type)); + checker->CreateBuiltinArraySignature(expr->TsType()->AsETSArrayType(), 1); + return expr->TsType(); } checker::Type *ETSAnalyzer::Check(ir::ETSNewClassInstanceExpression *expr) const { - (void)expr; - UNREACHABLE(); + ETSChecker *checker = GetETSChecker(); + checker::Type *callee_type = expr->GetTypeRef()->Check(checker); + + if (!callee_type->IsETSObjectType()) { + checker->ThrowTypeError("This expression is not constructible.", expr->Start()); + } + + auto *callee_obj = callee_type->AsETSObjectType(); + expr->SetTsType(callee_obj); + + if (expr->ClassDefinition() != nullptr) { + if (!callee_obj->HasObjectFlag(checker::ETSObjectFlags::ABSTRACT) && callee_obj->GetDeclNode()->IsFinal()) { + checker->ThrowTypeError({"Class ", callee_obj->Name(), " cannot be both 'abstract' and 'final'."}, + callee_obj->GetDeclNode()->Start()); + } + + bool from_interface = callee_obj->HasObjectFlag(checker::ETSObjectFlags::INTERFACE); + auto *class_type = checker->BuildAnonymousClassProperties( + expr->ClassDefinition(), from_interface ? checker->GlobalETSObjectType() : callee_obj); + if (from_interface) { + class_type->AddInterface(callee_obj); + callee_obj = checker->GlobalETSObjectType(); + } + expr->ClassDefinition()->SetTsType(class_type); + checker->CheckClassDefinition(expr->ClassDefinition()); + checker->CheckInnerClassMembers(class_type); + expr->SetTsType(class_type); + } else if (callee_obj->HasObjectFlag(checker::ETSObjectFlags::ABSTRACT)) { + checker->ThrowTypeError({callee_obj->Name(), " is abstract therefore cannot be instantiated."}, expr->Start()); + } + + if (callee_type->IsETSDynamicType() && !callee_type->AsETSDynamicType()->HasDecl()) { + auto lang = callee_type->AsETSDynamicType()->Language(); + expr->signature_ = checker->ResolveDynamicCallExpression(expr->GetTypeRef(), expr->GetArguments(), lang, true); + } else { + auto *signature = checker->ResolveConstructExpression(callee_obj, expr->GetArguments(), expr->Start()); + + checker->CheckObjectLiteralArguments(signature, expr->GetArguments()); + checker->ValidateSignatureAccessibility(callee_obj, signature, expr->Start()); + + ASSERT(signature->Function() != nullptr); + + if (signature->Function()->IsThrowing() || signature->Function()->IsRethrowing()) { + checker->CheckThrowingStatements(expr); + } + + if (callee_type->IsETSDynamicType()) { + ASSERT(signature->Function()->IsDynamic()); + auto lang = callee_type->AsETSDynamicType()->Language(); + expr->signature_ = + checker->ResolveDynamicCallExpression(expr->GetTypeRef(), signature->Params(), lang, true); + } else { + ASSERT(!signature->Function()->IsDynamic()); + expr->signature_ = signature; + } + } + + return expr->TsType(); } checker::Type *ETSAnalyzer::Check(ir::ETSNewMultiDimArrayInstanceExpression *expr) const { - (void)expr; - UNREACHABLE(); + ETSChecker *checker = GetETSChecker(); + auto *element_type = expr->type_reference_->GetType(checker); + + for (auto *dim : expr->dimensions_) { + checker->ValidateArrayIndex(dim); + element_type = checker->CreateETSArrayType(element_type); + } + + expr->SetTsType(element_type); + expr->signature_ = checker->CreateBuiltinArraySignature(element_type->AsETSArrayType(), expr->dimensions_.size()); + return expr->TsType(); } -checker::Type *ETSAnalyzer::Check(ir::ETSPackageDeclaration *st) const +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::ETSPackageDeclaration *st) const { - (void)st; - UNREACHABLE(); + return nullptr; } checker::Type *ETSAnalyzer::Check(ir::ETSParameterExpression *expr) const @@ -420,25 +567,168 @@ checker::Type *ETSAnalyzer::Check(ir::FunctionExpression *expr) const checker::Type *ETSAnalyzer::Check(ir::Identifier *expr) const { - (void)expr; - UNREACHABLE(); + ETSChecker *checker = GetETSChecker(); + if (expr->TsType() != nullptr) { + return expr->TsType(); + } + + expr->SetTsType(checker->ResolveIdentifier(expr)); + return expr->TsType(); } -checker::Type *ETSAnalyzer::Check(ir::ImportExpression *expr) const +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::ImportExpression *expr) const { - (void)expr; UNREACHABLE(); } +static std::pair ResolveEnumMember(checker::ETSChecker *checker, + checker::Type *type, + ir::MemberExpression *expr) +{ + auto const *const enum_interface = [type]() -> checker::ETSEnumInterface const * { + if (type->IsETSEnumType()) { + return type->AsETSEnumType(); + } + return type->AsETSStringEnumType(); + }(); + + if (expr->Parent()->Type() == ir::AstNodeType::CALL_EXPRESSION && + expr->Parent()->AsCallExpression()->Callee() == expr) { + return {enum_interface->LookupMethod(checker, expr->Object(), expr->Property()->AsIdentifier()), nullptr}; + } + + auto *const literal_type = + enum_interface->LookupConstant(checker, expr->Object(), expr->Property()->AsIdentifier()); + return {literal_type, literal_type->GetMemberVar()}; +} + +static std::pair ResolveObjectMember(checker::ETSChecker *checker, + ir::MemberExpression *expr) +{ + auto resolve_res = checker->ResolveMemberReference(expr, expr->ObjType()); + switch (resolve_res.size()) { + case 1U: { + if (resolve_res[0]->Kind() == checker::ResolvedKind::PROPERTY) { + auto var = resolve_res[0]->Variable()->AsLocalVariable(); + checker->ValidatePropertyAccess(var, expr->ObjType(), expr->Property()->Start()); + return {checker->GetTypeOfVariable(var), var}; + } + return {checker->GetTypeOfVariable(resolve_res[0]->Variable()), nullptr}; + } + case 2U: { + // ETSExtensionFuncHelperType(class_method_type, extension_method_type) + auto *resolved_type = checker->CreateETSExtensionFuncHelperType( + checker->GetTypeOfVariable(resolve_res[1]->Variable())->AsETSFunctionType(), + checker->GetTypeOfVariable(resolve_res[0]->Variable())->AsETSFunctionType()); + return {resolved_type, nullptr}; + } + default: { + UNREACHABLE(); + } + } +} + +static checker::Type *CheckUnionMember(checker::ETSChecker *checker, checker::Type *base_type, + ir::MemberExpression *expr) +{ + auto *const union_type = base_type->AsETSUnionType(); + checker::Type *common_prop_type = nullptr; + auto const add_prop_type = [expr, checker, &common_prop_type](checker::Type *member_type) { + if (common_prop_type != nullptr && common_prop_type != member_type) { + checker->ThrowTypeError("Member type must be the same for all union objects.", expr->Start()); + } + common_prop_type = member_type; + }; + for (auto *const type : union_type->ConstituentTypes()) { + if (type->IsETSObjectType()) { + expr->SetObjectType(type->AsETSObjectType()); + add_prop_type(ResolveObjectMember(checker, expr).first); + } else if (type->IsETSEnumType() || base_type->IsETSStringEnumType()) { + add_prop_type(ResolveEnumMember(checker, type, expr).first); + } else { + UNREACHABLE(); + } + } + expr->SetObjectType(union_type->GetLeastUpperBoundType(checker)->AsETSObjectType()); + return common_prop_type; +} + +static checker::Type *CheckComputed(checker::ETSChecker *checker, checker::Type *base_type, ir::MemberExpression *expr) +{ + if (!base_type->IsETSArrayType() && !base_type->IsETSDynamicType()) { + checker->ThrowTypeError("Indexed access expression can only be used in array type.", expr->Object()->Start()); + } + checker->ValidateArrayIndex(expr->Property()); + + if (expr->Property()->IsIdentifier()) { + expr->SetPropVar(expr->Property()->AsIdentifier()->Variable()->AsLocalVariable()); + } else if (auto var = expr->Property()->Variable(); (var != nullptr) && var->IsLocalVariable()) { + expr->SetPropVar(var->AsLocalVariable()); + } + + // NOTE: apply capture conversion on this type + if (base_type->IsETSArrayType()) { + return base_type->AsETSArrayType()->ElementType(); + } + + // Dynamic + return checker->GlobalBuiltinDynamicType(base_type->AsETSDynamicType()->Language()); +} + +static checker::Type *AdjustOptional(checker::ETSChecker *checker, checker::Type *type, ir::MemberExpression *expr) +{ + expr->SetOptionalType(type); + if (expr->IsOptional() && expr->Object()->TsType()->IsNullishOrNullLike()) { + checker->Relation()->SetNode(expr); + type = checker->CreateOptionalResultType(type); + checker->Relation()->SetNode(nullptr); + } + expr->SetTsType(type); + return expr->TsType(); +} + checker::Type *ETSAnalyzer::Check(ir::MemberExpression *expr) const { - (void)expr; - UNREACHABLE(); + ETSChecker *checker = GetETSChecker(); + if (expr->TsType() != nullptr) { + return expr->TsType(); + } + auto *const left_type = expr->Object()->Check(checker); + auto *const base_type = expr->IsOptional() ? checker->GetNonNullishType(left_type) : left_type; + if (!expr->IsOptional()) { + checker->CheckNonNullishType(left_type, expr->Start()); + } + + if (expr->IsComputed()) { + return AdjustOptional(checker, CheckComputed(checker, base_type, expr), expr); + } + + if (base_type->IsETSArrayType() && expr->Property()->AsIdentifier()->Name().Is("length")) { + return AdjustOptional(checker, checker->GlobalIntType(), expr); + } + + if (base_type->IsETSObjectType()) { + expr->SetObjectType(base_type->AsETSObjectType()); + auto [res_type, res_var] = ResolveObjectMember(checker, expr); + expr->SetPropVar(res_var); + return AdjustOptional(checker, res_type, expr); + } + + if (base_type->IsETSEnumType() || base_type->IsETSStringEnumType()) { + auto [member_type, member_var] = ResolveEnumMember(checker, base_type, expr); + expr->SetPropVar(member_var); + return AdjustOptional(checker, member_type, expr); + } + + if (base_type->IsETSUnionType()) { + return AdjustOptional(checker, CheckUnionMember(checker, base_type, expr), expr); + } + + checker->ThrowTypeError({"Cannot access property of non-object or non-enum type"}, expr->Object()->Start()); } -checker::Type *ETSAnalyzer::Check(ir::NewExpression *expr) const +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::NewExpression *expr) const { - (void)expr; UNREACHABLE(); } @@ -448,9 +738,8 @@ checker::Type *ETSAnalyzer::Check(ir::ObjectExpression *expr) const UNREACHABLE(); } -checker::Type *ETSAnalyzer::Check(ir::OmittedExpression *expr) const +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::OmittedExpression *expr) const { - (void)expr; UNREACHABLE(); } @@ -462,14 +751,26 @@ checker::Type *ETSAnalyzer::Check(ir::OpaqueTypeNode *expr) const checker::Type *ETSAnalyzer::Check(ir::SequenceExpression *expr) const { - (void)expr; - UNREACHABLE(); + ETSChecker *checker = GetETSChecker(); + if (expr->TsType() != nullptr) { + return expr->TsType(); + } + + for (auto *it : expr->Sequence()) { + it->Check(checker); + } + return nullptr; } checker::Type *ETSAnalyzer::Check(ir::SuperExpression *expr) const { - (void)expr; - UNREACHABLE(); + ETSChecker *checker = GetETSChecker(); + if (expr->TsType() != nullptr) { + return expr->TsType(); + } + + expr->SetTsType(checker->CheckThisOrSuperAccess(expr, checker->Context().ContainingClass()->SuperType(), "super")); + return expr->TsType(); } checker::Type *ETSAnalyzer::Check(ir::TaggedTemplateExpression *expr) const @@ -508,22 +809,27 @@ checker::Type *ETSAnalyzer::Check(ir::YieldExpression *expr) const UNREACHABLE(); } // compile methods for LITERAL EXPRESSIONS in alphabetical order -checker::Type *ETSAnalyzer::Check(ir::BigIntLiteral *expr) const +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::BigIntLiteral *expr) const { - (void)expr; UNREACHABLE(); } checker::Type *ETSAnalyzer::Check(ir::BooleanLiteral *expr) const { - (void)expr; - UNREACHABLE(); + ETSChecker *checker = GetETSChecker(); + if (expr->TsType() == nullptr) { + expr->SetTsType(checker->CreateETSBooleanType(expr->Value())); + } + return expr->TsType(); } checker::Type *ETSAnalyzer::Check(ir::CharLiteral *expr) const { - (void)expr; - UNREACHABLE(); + ETSChecker *checker = GetETSChecker(); + if (expr->TsType() == nullptr) { + expr->SetTsType(checker->Allocator()->New(expr->Char())); + } + return expr->TsType(); } checker::Type *ETSAnalyzer::Check(ir::NullLiteral *expr) const @@ -607,20 +913,44 @@ checker::Type *ETSAnalyzer::Check(ir::ImportSpecifier *st) const // compile methods for STATEMENTS in alphabetical order checker::Type *ETSAnalyzer::Check(ir::AssertStatement *st) const { - (void)st; - UNREACHABLE(); + ETSChecker *checker = GetETSChecker(); + checker->CheckTruthinessOfType(st->test_); + + if (st->Second() != nullptr) { + auto *msg_type = st->second_->Check(checker); + + if (!msg_type->IsETSStringType()) { + checker->ThrowTypeError("Assert message must be string", st->Second()->Start()); + } + } + + return nullptr; } checker::Type *ETSAnalyzer::Check(ir::BlockStatement *st) const { - (void)st; - UNREACHABLE(); + ETSChecker *checker = GetETSChecker(); + checker::ScopeContext scope_ctx(checker, st->Scope()); + + for (auto *it : st->Statements()) { + it->Check(checker); + } + + for (auto [stmt, trailing_block] : st->trailing_blocks_) { + auto iterator = std::find(st->Statements().begin(), st->Statements().end(), stmt); + ASSERT(iterator != st->Statements().end()); + st->Statements().insert(iterator + 1, trailing_block); + trailing_block->Check(checker); + } + + return nullptr; } checker::Type *ETSAnalyzer::Check(ir::BreakStatement *st) const { - (void)st; - UNREACHABLE(); + ETSChecker *checker = GetETSChecker(); + st->target_ = checker->FindJumpTarget(st->Type(), st, st->Ident()); + return nullptr; } checker::Type *ETSAnalyzer::Check(ir::ClassDeclaration *st) const @@ -985,9 +1315,8 @@ checker::Type *ETSAnalyzer::Check(ir::TSClassImplements *expr) const UNREACHABLE(); } -checker::Type *ETSAnalyzer::Check(ir::TSConditionalType *node) const +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSConditionalType *node) const { - (void)node; UNREACHABLE(); } @@ -1027,9 +1356,8 @@ checker::Type *ETSAnalyzer::Check(ir::TSImportEqualsDeclaration *st) const UNREACHABLE(); } -checker::Type *ETSAnalyzer::Check(ir::TSImportType *node) const +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSImportType *node) const { - (void)node; UNREACHABLE(); } @@ -1039,9 +1367,8 @@ checker::Type *ETSAnalyzer::Check(ir::TSIndexedAccessType *node) const UNREACHABLE(); } -checker::Type *ETSAnalyzer::Check(ir::TSInferType *node) const +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSInferType *node) const { - (void)node; UNREACHABLE(); } @@ -1063,9 +1390,8 @@ checker::Type *ETSAnalyzer::Check(ir::TSInterfaceHeritage *expr) const UNREACHABLE(); } -checker::Type *ETSAnalyzer::Check(ir::TSIntersectionType *node) const +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSIntersectionType *node) const { - (void)node; UNREACHABLE(); } @@ -1075,15 +1401,13 @@ checker::Type *ETSAnalyzer::Check(ir::TSLiteralType *node) const UNREACHABLE(); } -checker::Type *ETSAnalyzer::Check(ir::TSMappedType *node) const +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSMappedType *node) const { - (void)node; UNREACHABLE(); } -checker::Type *ETSAnalyzer::Check(ir::TSModuleBlock *st) const +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSModuleBlock *st) const { - (void)st; UNREACHABLE(); } @@ -1111,9 +1435,8 @@ checker::Type *ETSAnalyzer::Check(ir::TSNonNullExpression *expr) const UNREACHABLE(); } -checker::Type *ETSAnalyzer::Check(ir::TSNullKeyword *node) const +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSNullKeyword *node) const { - (void)node; UNREACHABLE(); } @@ -1153,9 +1476,8 @@ checker::Type *ETSAnalyzer::Check(ir::TSStringKeyword *node) const UNREACHABLE(); } -checker::Type *ETSAnalyzer::Check(ir::TSThisType *node) const +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSThisType *node) const { - (void)node; UNREACHABLE(); } diff --git a/ets2panda/checker/TSAnalyzer.cpp b/ets2panda/checker/TSAnalyzer.cpp index d3e96e821ffd6bb149a2337acaa909ed200d7dca..b16a384e7feca67dbebd8fe6ab9ab839537e9d02 100644 --- a/ets2panda/checker/TSAnalyzer.cpp +++ b/ets2panda/checker/TSAnalyzer.cpp @@ -134,55 +134,84 @@ checker::Type *TSAnalyzer::Check(ir::TSPropertySignature *node) const checker::Type *TSAnalyzer::Check(ir::TSSignatureDeclaration *node) const { - (void)node; - UNREACHABLE(); + TSChecker *checker = GetTSChecker(); + if (node->TsType() != nullptr) { + return node->TsType(); + } + + checker::ScopeContext scope_ctx(checker, node->Scope()); + + auto *signature_info = checker->Allocator()->New(checker->Allocator()); + checker->CheckFunctionParameterDeclarations(node->Params(), signature_info); + + bool is_call_signature = (node->Kind() == ir::TSSignatureDeclaration::TSSignatureDeclarationKind::CALL_SIGNATURE); + + if (node->ReturnTypeAnnotation() == nullptr) { + if (is_call_signature) { + checker->ThrowTypeError( + "Call signature, which lacks return-type annotation, implicitly has an 'any' return type.", + node->Start()); + } + + checker->ThrowTypeError( + "Construct signature, which lacks return-type annotation, implicitly has an 'any' return type.", + node->Start()); + } + + node->return_type_annotation_->Check(checker); + checker::Type *return_type = node->return_type_annotation_->GetType(checker); + + auto *signature = checker->Allocator()->New(signature_info, return_type); + + checker::Type *placeholder_obj = nullptr; + + if (is_call_signature) { + placeholder_obj = checker->CreateObjectTypeWithCallSignature(signature); + } else { + placeholder_obj = checker->CreateObjectTypeWithConstructSignature(signature); + } + + node->SetTsType(placeholder_obj); + return placeholder_obj; } // from ets folder -checker::Type *TSAnalyzer::Check(ir::ETSClassLiteral *expr) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::ETSClassLiteral *expr) const { - (void)expr; UNREACHABLE(); } -checker::Type *TSAnalyzer::Check(ir::ETSFunctionType *node) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::ETSFunctionType *node) const { - (void)node; UNREACHABLE(); } -checker::Type *TSAnalyzer::Check(ir::ETSImportDeclaration *node) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::ETSImportDeclaration *node) const { - (void)node; UNREACHABLE(); } -checker::Type *TSAnalyzer::Check(ir::ETSLaunchExpression *expr) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::ETSLaunchExpression *expr) const { - (void)expr; UNREACHABLE(); } -checker::Type *TSAnalyzer::Check(ir::ETSNewArrayInstanceExpression *expr) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::ETSNewArrayInstanceExpression *expr) const { - (void)expr; UNREACHABLE(); } -checker::Type *TSAnalyzer::Check(ir::ETSNewClassInstanceExpression *expr) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::ETSNewClassInstanceExpression *expr) const { - (void)expr; UNREACHABLE(); } -checker::Type *TSAnalyzer::Check(ir::ETSNewMultiDimArrayInstanceExpression *expr) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::ETSNewMultiDimArrayInstanceExpression *expr) const { - (void)expr; UNREACHABLE(); } -checker::Type *TSAnalyzer::Check(ir::ETSPackageDeclaration *st) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::ETSPackageDeclaration *st) const { - (void)st; UNREACHABLE(); } @@ -317,26 +346,121 @@ checker::Type *TSAnalyzer::Check(ir::FunctionExpression *expr) const checker::Type *TSAnalyzer::Check(ir::Identifier *expr) const { - (void)expr; - UNREACHABLE(); + TSChecker *checker = GetTSChecker(); + if (expr->Variable() == nullptr) { + if (expr->Name().Is("undefined")) { + return checker->GlobalUndefinedType(); + } + + checker->ThrowTypeError({"Cannot find name ", expr->Name()}, expr->Start()); + } + + const varbinder::Decl *decl = expr->Variable()->Declaration(); + + if (decl->IsTypeAliasDecl() || decl->IsInterfaceDecl()) { + checker->ThrowTypeError({expr->Name(), " only refers to a type, but is being used as a value here."}, + expr->Start()); + } + + expr->SetTsType(checker->GetTypeOfVariable(expr->Variable())); + return expr->TsType(); } -checker::Type *TSAnalyzer::Check(ir::ImportExpression *expr) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::ImportExpression *expr) const { - (void)expr; UNREACHABLE(); } checker::Type *TSAnalyzer::Check(ir::MemberExpression *expr) const { - (void)expr; - UNREACHABLE(); + TSChecker *checker = GetTSChecker(); + checker::Type *base_type = checker->CheckNonNullType(expr->Object()->Check(checker), expr->Object()->Start()); + + if (expr->IsComputed()) { + checker::Type *index_type = expr->Property()->Check(checker); + checker::Type *indexed_access_type = checker->GetPropertyTypeForIndexType(base_type, index_type); + + if (indexed_access_type != nullptr) { + return indexed_access_type; + } + + if (!index_type->HasTypeFlag(checker::TypeFlag::STRING_LIKE | checker::TypeFlag::NUMBER_LIKE)) { + checker->ThrowTypeError({"Type ", index_type, " cannot be used as index type"}, expr->Property()->Start()); + } + + if (index_type->IsNumberType()) { + checker->ThrowTypeError("No index signature with a parameter of type 'string' was found on type this type", + expr->Start()); + } + + if (index_type->IsStringType()) { + checker->ThrowTypeError("No index signature with a parameter of type 'number' was found on type this type", + expr->Start()); + } + + switch (expr->Property()->Type()) { + case ir::AstNodeType::IDENTIFIER: { + checker->ThrowTypeError( + {"Property ", expr->Property()->AsIdentifier()->Name(), " does not exist on this type."}, + expr->Property()->Start()); + } + case ir::AstNodeType::NUMBER_LITERAL: { + checker->ThrowTypeError( + {"Property ", expr->Property()->AsNumberLiteral()->Str(), " does not exist on this type."}, + expr->Property()->Start()); + } + case ir::AstNodeType::STRING_LITERAL: { + checker->ThrowTypeError( + {"Property ", expr->Property()->AsStringLiteral()->Str(), " does not exist on this type."}, + expr->Property()->Start()); + } + default: { + UNREACHABLE(); + } + } + } + + varbinder::Variable *prop = checker->GetPropertyOfType(base_type, expr->Property()->AsIdentifier()->Name()); + + if (prop != nullptr) { + checker::Type *prop_type = checker->GetTypeOfVariable(prop); + if (prop->HasFlag(varbinder::VariableFlags::READONLY)) { + prop_type->AddTypeFlag(checker::TypeFlag::READONLY); + } + + return prop_type; + } + + if (base_type->IsObjectType()) { + checker::ObjectType *obj_type = base_type->AsObjectType(); + + if (obj_type->StringIndexInfo() != nullptr) { + checker::Type *index_type = obj_type->StringIndexInfo()->GetType(); + if (obj_type->StringIndexInfo()->Readonly()) { + index_type->AddTypeFlag(checker::TypeFlag::READONLY); + } + + return index_type; + } + } + + checker->ThrowTypeError({"Property ", expr->Property()->AsIdentifier()->Name(), " does not exist on this type."}, + expr->Property()->Start()); + return nullptr; } checker::Type *TSAnalyzer::Check(ir::NewExpression *expr) const { - (void)expr; - UNREACHABLE(); + TSChecker *checker = GetTSChecker(); + checker::Type *callee_type = expr->callee_->Check(checker); + + if (callee_type->IsObjectType()) { + checker::ObjectType *callee_obj = callee_type->AsObjectType(); + return checker->ResolveCallOrNewExpression(callee_obj->ConstructSignatures(), expr->Arguments(), expr->Start()); + } + + checker->ThrowTypeError("This expression is not callable.", expr->Start()); + return nullptr; } checker::Type *TSAnalyzer::Check(ir::ObjectExpression *expr) const @@ -345,10 +469,10 @@ checker::Type *TSAnalyzer::Check(ir::ObjectExpression *expr) const UNREACHABLE(); } -checker::Type *TSAnalyzer::Check(ir::OmittedExpression *expr) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::OmittedExpression *expr) const { - (void)expr; - UNREACHABLE(); + TSChecker *checker = GetTSChecker(); + return checker->GlobalUndefinedType(); } checker::Type *TSAnalyzer::Check(ir::OpaqueTypeNode *expr) const @@ -357,16 +481,18 @@ checker::Type *TSAnalyzer::Check(ir::OpaqueTypeNode *expr) const UNREACHABLE(); } -checker::Type *TSAnalyzer::Check(ir::SequenceExpression *expr) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::SequenceExpression *expr) const { - (void)expr; - UNREACHABLE(); + TSChecker *checker = GetTSChecker(); + // NOTE: aszilagyi. + return checker->GlobalAnyType(); } -checker::Type *TSAnalyzer::Check(ir::SuperExpression *expr) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::SuperExpression *expr) const { - (void)expr; - UNREACHABLE(); + TSChecker *checker = GetTSChecker(); + // NOTE: aszilagyi. + return checker->GlobalAnyType(); } checker::Type *TSAnalyzer::Check(ir::TaggedTemplateExpression *expr) const @@ -407,19 +533,25 @@ checker::Type *TSAnalyzer::Check(ir::YieldExpression *expr) const // compile methods for LITERAL EXPRESSIONS in alphabetical order checker::Type *TSAnalyzer::Check(ir::BigIntLiteral *expr) const { - (void)expr; - UNREACHABLE(); + TSChecker *checker = GetTSChecker(); + auto search = checker->BigintLiteralMap().find(expr->Str()); + if (search != checker->BigintLiteralMap().end()) { + return search->second; + } + + auto *new_bigint_literal_type = checker->Allocator()->New(expr->Str(), false); + checker->BigintLiteralMap().insert({expr->Str(), new_bigint_literal_type}); + return new_bigint_literal_type; } checker::Type *TSAnalyzer::Check(ir::BooleanLiteral *expr) const { - (void)expr; - UNREACHABLE(); + TSChecker *checker = GetTSChecker(); + return expr->Value() ? checker->GlobalTrueType() : checker->GlobalFalseType(); } -checker::Type *TSAnalyzer::Check(ir::CharLiteral *expr) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::CharLiteral *expr) const { - (void)expr; UNREACHABLE(); } @@ -502,22 +634,26 @@ checker::Type *TSAnalyzer::Check(ir::ImportSpecifier *st) const UNREACHABLE(); } // compile methods for STATEMENTS in alphabetical order -checker::Type *TSAnalyzer::Check(ir::AssertStatement *st) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::AssertStatement *st) const { - (void)st; UNREACHABLE(); } checker::Type *TSAnalyzer::Check(ir::BlockStatement *st) const { - (void)st; - UNREACHABLE(); + TSChecker *checker = GetTSChecker(); + checker::ScopeContext scope_ctx(checker, st->Scope()); + + for (auto *it : st->Statements()) { + it->Check(checker); + } + + return nullptr; } -checker::Type *TSAnalyzer::Check(ir::BreakStatement *st) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::BreakStatement *st) const { - (void)st; - UNREACHABLE(); + return nullptr; } checker::Type *TSAnalyzer::Check(ir::ClassDeclaration *st) const @@ -701,9 +837,8 @@ checker::Type *TSAnalyzer::Check(ir::TSClassImplements *expr) const UNREACHABLE(); } -checker::Type *TSAnalyzer::Check(ir::TSConditionalType *node) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::TSConditionalType *node) const { - (void)node; UNREACHABLE(); } @@ -743,9 +878,8 @@ checker::Type *TSAnalyzer::Check(ir::TSImportEqualsDeclaration *st) const UNREACHABLE(); } -checker::Type *TSAnalyzer::Check(ir::TSImportType *node) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::TSImportType *node) const { - (void)node; UNREACHABLE(); } @@ -755,9 +889,8 @@ checker::Type *TSAnalyzer::Check(ir::TSIndexedAccessType *node) const UNREACHABLE(); } -checker::Type *TSAnalyzer::Check(ir::TSInferType *node) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::TSInferType *node) const { - (void)node; UNREACHABLE(); } @@ -779,9 +912,8 @@ checker::Type *TSAnalyzer::Check(ir::TSInterfaceHeritage *expr) const UNREACHABLE(); } -checker::Type *TSAnalyzer::Check(ir::TSIntersectionType *node) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::TSIntersectionType *node) const { - (void)node; UNREACHABLE(); } @@ -791,15 +923,13 @@ checker::Type *TSAnalyzer::Check(ir::TSLiteralType *node) const UNREACHABLE(); } -checker::Type *TSAnalyzer::Check(ir::TSMappedType *node) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::TSMappedType *node) const { - (void)node; UNREACHABLE(); } -checker::Type *TSAnalyzer::Check(ir::TSModuleBlock *st) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::TSModuleBlock *st) const { - (void)st; UNREACHABLE(); } @@ -827,10 +957,9 @@ checker::Type *TSAnalyzer::Check(ir::TSNonNullExpression *expr) const UNREACHABLE(); } -checker::Type *TSAnalyzer::Check(ir::TSNullKeyword *node) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::TSNullKeyword *node) const { - (void)node; - UNREACHABLE(); + return nullptr; } checker::Type *TSAnalyzer::Check(ir::TSNumberKeyword *node) const @@ -869,9 +998,8 @@ checker::Type *TSAnalyzer::Check(ir::TSStringKeyword *node) const UNREACHABLE(); } -checker::Type *TSAnalyzer::Check(ir::TSThisType *node) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::TSThisType *node) const { - (void)node; UNREACHABLE(); } diff --git a/ets2panda/compiler/core/ETSCompiler.cpp b/ets2panda/compiler/core/ETSCompiler.cpp index 46dd096ae82d9c812db8af28704dee330951bdcd..424a77d0b8c0fd441f9abe57b527fb365c3139ce 100644 --- a/ets2panda/compiler/core/ETSCompiler.cpp +++ b/ets2panda/compiler/core/ETSCompiler.cpp @@ -140,57 +140,151 @@ void ETSCompiler::Compile(const ir::TSPropertySignature *node) const UNREACHABLE(); } -void ETSCompiler::Compile(const ir::TSSignatureDeclaration *node) const +void ETSCompiler::Compile([[maybe_unused]] const ir::TSSignatureDeclaration *node) const { - (void)node; UNREACHABLE(); } // from ets folder void ETSCompiler::Compile(const ir::ETSClassLiteral *expr) const { - (void)expr; - UNREACHABLE(); + ETSGen *etsg = GetETSGen(); + if (expr->expr_->TsType()->HasTypeFlag(checker::TypeFlag::ETS_ARRAY_OR_OBJECT)) { + expr->expr_->Compile(etsg); + etsg->GetType(expr, false); + } else { + ASSERT(expr->expr_->TsType()->HasTypeFlag(checker::TypeFlag::ETS_PRIMITIVE)); + etsg->SetAccumulatorType(expr->expr_->TsType()); + etsg->GetType(expr, true); + } } -void ETSCompiler::Compile(const ir::ETSFunctionType *node) const +void ETSCompiler::Compile([[maybe_unused]] const ir::ETSFunctionType *node) const { - (void)node; UNREACHABLE(); } -void ETSCompiler::Compile(const ir::ETSImportDeclaration *node) const +void ETSCompiler::Compile([[maybe_unused]] const ir::ETSImportDeclaration *node) const { - (void)node; UNREACHABLE(); } -void ETSCompiler::Compile(const ir::ETSLaunchExpression *expr) const +void ETSCompiler::Compile([[maybe_unused]] const ir::ETSLaunchExpression *expr) const { - (void)expr; - UNREACHABLE(); +#ifdef PANDA_WITH_ETS + ETSGen *etsg = GetETSGen(); + compiler::RegScope rs(etsg); + compiler::VReg callee_reg = etsg->AllocReg(); + checker::Signature *signature = expr->expr_->Signature(); + bool is_static = signature->HasSignatureFlag(checker::SignatureFlags::STATIC); + bool is_reference = signature->HasSignatureFlag(checker::SignatureFlags::TYPE); + + if (!is_reference && expr->expr_->Callee()->IsIdentifier()) { + if (!is_static) { + etsg->LoadThis(expr->expr_); + etsg->StoreAccumulator(expr, callee_reg); + } + } else if (!is_reference && expr->expr_->Callee()->IsMemberExpression()) { + if (!is_static) { + expr->expr_->Callee()->AsMemberExpression()->Object()->Compile(etsg); + etsg->StoreAccumulator(expr, callee_reg); + } + } else { + expr->expr_->Callee()->Compile(etsg); + etsg->StoreAccumulator(expr, callee_reg); + } + + if (is_static) { + etsg->LaunchStatic(expr, signature, expr->expr_->Arguments()); + } else if (signature->HasSignatureFlag(checker::SignatureFlags::PRIVATE)) { + etsg->LaunchThisStatic(expr, callee_reg, signature, expr->expr_->Arguments()); + } else { + etsg->LaunchThisVirtual(expr, callee_reg, signature, expr->expr_->Arguments()); + } + + etsg->SetAccumulatorType(expr->TsType()); +#endif // PANDA_WITH_ETS } void ETSCompiler::Compile(const ir::ETSNewArrayInstanceExpression *expr) const { - (void)expr; - UNREACHABLE(); + ETSGen *etsg = GetETSGen(); + compiler::RegScope rs(etsg); + compiler::TargetTypeContext ttctx(etsg, etsg->Checker()->GlobalIntType()); + + expr->dimension_->Compile(etsg); + + compiler::VReg arr = etsg->AllocReg(); + compiler::VReg dim = etsg->AllocReg(); + etsg->ApplyConversionAndStoreAccumulator(expr, dim, expr->dimension_->TsType()); + etsg->NewArray(expr, arr, dim, expr->TsType()); + etsg->SetVRegType(arr, expr->TsType()); + etsg->LoadAccumulator(expr, arr); +} + +static void CreateDynamicObject(const ir::AstNode *node, compiler::ETSGen *etsg, compiler::VReg &obj_reg, + ir::Expression *name, checker::Signature *signature, + const ArenaVector &arguments) +{ + auto qname_reg = etsg->AllocReg(); + + std::vector parts; + + while (name->IsTSQualifiedName()) { + auto *qname = name->AsTSQualifiedName(); + name = qname->Left(); + parts.push_back(qname->Right()->AsIdentifier()->Name()); + } + + auto *var = name->AsIdentifier()->Variable(); + auto *data = etsg->VarBinder()->DynamicImportDataForVar(var); + if (data != nullptr) { + auto *import = data->import; + auto *specifier = data->specifier; + ASSERT(import->Language().IsDynamic()); + etsg->LoadAccumulatorDynamicModule(node, import); + if (specifier->IsImportSpecifier()) { + parts.push_back(specifier->AsImportSpecifier()->Imported()->Name()); + } + } else { + name->Compile(etsg); + } + + etsg->StoreAccumulator(node, obj_reg); + + std::stringstream ss; + std::for_each(parts.rbegin(), parts.rend(), [&ss](util::StringView sv) { ss << "." << sv; }); + + etsg->LoadAccumulatorString(node, util::UString(ss.str(), etsg->Allocator()).View()); + etsg->StoreAccumulator(node, qname_reg); + + etsg->CallDynamic(node, obj_reg, qname_reg, signature, arguments); } void ETSCompiler::Compile(const ir::ETSNewClassInstanceExpression *expr) const { - (void)expr; - UNREACHABLE(); + ETSGen *etsg = GetETSGen(); + if (expr->TsType()->IsETSDynamicType()) { + auto obj_reg = etsg->AllocReg(); + auto *name = expr->GetTypeRef()->AsETSTypeReference()->Part()->Name(); + CreateDynamicObject(expr, etsg, obj_reg, name, expr->signature_, expr->GetArguments()); + } else { + etsg->InitObject(expr, expr->signature_, expr->GetArguments()); + } + + if (expr->GetBoxingUnboxingFlags() == ir::BoxingUnboxingFlags::NONE) { + etsg->SetAccumulatorType(expr->TsType()); + } } void ETSCompiler::Compile(const ir::ETSNewMultiDimArrayInstanceExpression *expr) const { - (void)expr; - UNREACHABLE(); + ETSGen *etsg = GetETSGen(); + etsg->InitObject(expr, expr->signature_, expr->dimensions_); + etsg->SetAccumulatorType(expr->TsType()); } -void ETSCompiler::Compile(const ir::ETSPackageDeclaration *st) const +void ETSCompiler::Compile([[maybe_unused]] const ir::ETSPackageDeclaration *st) const { - (void)st; UNREACHABLE(); } @@ -318,25 +412,156 @@ void ETSCompiler::Compile(const ir::FunctionExpression *expr) const void ETSCompiler::Compile(const ir::Identifier *expr) const { - (void)expr; - UNREACHABLE(); + ETSGen *etsg = GetETSGen(); + auto lambda = etsg->VarBinder()->LambdaObjects().find(expr); + if (lambda != etsg->VarBinder()->LambdaObjects().end()) { + etsg->CreateLambdaObjectFromIdentReference(expr, lambda->second.first); + return; + } + + auto ttctx = compiler::TargetTypeContext(etsg, expr->TsType()); + + ASSERT(expr->Variable() != nullptr); + if (!expr->Variable()->HasFlag(varbinder::VariableFlags::TYPE_ALIAS)) { + etsg->LoadVar(expr, expr->Variable()); + } else { + etsg->LoadVar(expr, expr->TsType()->Variable()); + } } -void ETSCompiler::Compile(const ir::ImportExpression *expr) const +void ETSCompiler::Compile([[maybe_unused]] const ir::ImportExpression *expr) const { - (void)expr; UNREACHABLE(); } +static bool CompileComputed(compiler::ETSGen *etsg, const ir::MemberExpression *expr) +{ + if (expr->IsComputed()) { + auto *const object_type = etsg->Checker()->GetNonNullishType(expr->Object()->TsType()); + + auto ottctx = compiler::TargetTypeContext(etsg, expr->Object()->TsType()); + etsg->CompileAndCheck(expr->Object()); + + auto const load_element = [expr, etsg, object_type]() { + compiler::VReg obj_reg = etsg->AllocReg(); + etsg->StoreAccumulator(expr, obj_reg); + + etsg->CompileAndCheck(expr->Property()); + etsg->ApplyConversion(expr->Property(), expr->Property()->TsType()); + + auto ttctx = compiler::TargetTypeContext(etsg, expr->OptionalType()); + + if (object_type->IsETSDynamicType()) { + auto lang = object_type->AsETSDynamicType()->Language(); + etsg->LoadElementDynamic(expr, obj_reg, lang); + } else { + etsg->LoadArrayElement(expr, obj_reg); + } + }; + + etsg->EmitMaybeOptional(expr, load_element, expr->IsOptional()); + return true; + } + return false; +} + void ETSCompiler::Compile(const ir::MemberExpression *expr) const { - (void)expr; - UNREACHABLE(); + ETSGen *etsg = GetETSGen(); + auto lambda = etsg->VarBinder()->LambdaObjects().find(expr); + if (lambda != etsg->VarBinder()->LambdaObjects().end()) { + etsg->CreateLambdaObjectFromMemberReference(expr, expr->object_, lambda->second.first); + etsg->SetAccumulatorType(expr->TsType()); + return; + } + + compiler::RegScope rs(etsg); + + auto *const object_type = etsg->Checker()->GetNonNullishType(expr->Object()->TsType()); + + if (CompileComputed(etsg, expr)) { + return; + } + + auto &prop_name = expr->Property()->AsIdentifier()->Name(); + + if (object_type->IsETSArrayType() && prop_name.Is("length")) { + auto ottctx = compiler::TargetTypeContext(etsg, object_type); + etsg->CompileAndCheck(expr->Object()); + + auto const load_length = [expr, etsg]() { + compiler::VReg obj_reg = etsg->AllocReg(); + etsg->StoreAccumulator(expr, obj_reg); + + auto ttctx = compiler::TargetTypeContext(etsg, expr->OptionalType()); + etsg->LoadArrayLength(expr, obj_reg); + etsg->ApplyConversion(expr, expr->TsType()); + }; + + etsg->EmitMaybeOptional(expr, load_length, expr->IsOptional()); + return; + } + + if (object_type->IsETSEnumType() || object_type->IsETSStringEnumType()) { + auto const *const enum_interface = [object_type, expr]() -> checker::ETSEnumInterface const * { + if (object_type->IsETSEnumType()) { + return expr->OptionalType()->AsETSEnumType(); + } + return expr->OptionalType()->AsETSStringEnumType(); + }(); + + auto ottctx = compiler::TargetTypeContext(etsg, object_type); + auto ttctx = compiler::TargetTypeContext(etsg, expr->OptionalType()); + etsg->LoadAccumulatorInt(expr, enum_interface->GetOrdinal()); + return; + } + + if (etsg->Checker()->IsVariableStatic(expr->PropVar())) { + auto ttctx = compiler::TargetTypeContext(etsg, expr->OptionalType()); + + if (expr->PropVar()->TsType()->HasTypeFlag(checker::TypeFlag::GETTER_SETTER)) { + checker::Signature *sig = expr->PropVar()->TsType()->AsETSFunctionType()->FindGetter(); + etsg->CallStatic0(expr, sig->InternalName()); + etsg->SetAccumulatorType(expr->TsType()); + return; + } + + util::StringView full_name = + etsg->FormClassPropReference(expr->Object()->TsType()->AsETSObjectType(), prop_name); + etsg->LoadStaticProperty(expr, expr->OptionalType(), full_name); + return; + } + + auto ottctx = compiler::TargetTypeContext(etsg, expr->Object()->TsType()); + etsg->CompileAndCheck(expr->Object()); + + auto const load_property = [expr, etsg, prop_name, object_type]() { + etsg->ApplyConversion(expr->Object()); + compiler::VReg obj_reg = etsg->AllocReg(); + etsg->StoreAccumulator(expr, obj_reg); + + auto ttctx = compiler::TargetTypeContext(etsg, expr->OptionalType()); + + if (expr->PropVar()->TsType()->HasTypeFlag(checker::TypeFlag::GETTER_SETTER)) { + checker::Signature *sig = expr->PropVar()->TsType()->AsETSFunctionType()->FindGetter(); + etsg->CallThisVirtual0(expr, obj_reg, sig->InternalName()); + etsg->SetAccumulatorType(expr->TsType()); + } else if (object_type->IsETSDynamicType()) { + auto lang = object_type->AsETSDynamicType()->Language(); + etsg->LoadPropertyDynamic(expr, expr->OptionalType(), obj_reg, prop_name, lang); + } else if (object_type->IsETSUnionType()) { + etsg->LoadUnionProperty(expr, expr->OptionalType(), obj_reg, prop_name); + } else { + const auto full_name = etsg->FormClassPropReference(object_type->AsETSObjectType(), prop_name); + etsg->LoadProperty(expr, expr->OptionalType(), obj_reg, full_name); + } + }; + + etsg->EmitMaybeOptional(expr, load_property, expr->IsOptional()); } -void ETSCompiler::Compile(const ir::NewExpression *expr) const +void ETSCompiler::Compile([[maybe_unused]] const ir::NewExpression *expr) const { - (void)expr; UNREACHABLE(); } @@ -346,9 +571,8 @@ void ETSCompiler::Compile(const ir::ObjectExpression *expr) const UNREACHABLE(); } -void ETSCompiler::Compile(const ir::OmittedExpression *expr) const +void ETSCompiler::Compile([[maybe_unused]] const ir::OmittedExpression *expr) const { - (void)expr; UNREACHABLE(); } @@ -360,14 +584,17 @@ void ETSCompiler::Compile(const ir::OpaqueTypeNode *node) const void ETSCompiler::Compile(const ir::SequenceExpression *expr) const { - (void)expr; - UNREACHABLE(); + ETSGen *etsg = GetETSGen(); + for (const auto *it : expr->Sequence()) { + it->Compile(etsg); + } } void ETSCompiler::Compile(const ir::SuperExpression *expr) const { - (void)expr; - UNREACHABLE(); + ETSGen *etsg = GetETSGen(); + etsg->LoadThis(expr); + etsg->SetAccumulatorType(etsg->GetAccumulatorType()->AsETSObjectType()->SuperType()); } void ETSCompiler::Compile(const ir::TaggedTemplateExpression *expr) const @@ -406,22 +633,21 @@ void ETSCompiler::Compile(const ir::YieldExpression *expr) const UNREACHABLE(); } // compile methods for LITERAL EXPRESSIONS in alphabetical order -void ETSCompiler::Compile(const ir::BigIntLiteral *expr) const +void ETSCompiler::Compile([[maybe_unused]] const ir::BigIntLiteral *expr) const { - (void)expr; UNREACHABLE(); } void ETSCompiler::Compile(const ir::BooleanLiteral *expr) const { - (void)expr; - UNREACHABLE(); + ETSGen *etsg = GetETSGen(); + etsg->LoadAccumulatorBoolean(expr, expr->Value()); } void ETSCompiler::Compile(const ir::CharLiteral *expr) const { - (void)expr; - UNREACHABLE(); + ETSGen *etsg = GetETSGen(); + etsg->LoadAccumulatorChar(expr, expr->Char()); } void ETSCompiler::Compile(const ir::NullLiteral *expr) const @@ -502,23 +728,73 @@ void ETSCompiler::Compile(const ir::ImportSpecifier *st) const (void)st; UNREACHABLE(); } + +static void ThrowError(compiler::ETSGen *const etsg, const ir::AssertStatement *st) +{ + const compiler::RegScope rs(etsg); + + if (st->Second() != nullptr) { + st->Second()->Compile(etsg); + } else { + etsg->LoadAccumulatorString(st, "Assertion failed."); + } + + const auto message = etsg->AllocReg(); + etsg->StoreAccumulator(st, message); + + const auto assertion_error = etsg->AllocReg(); + etsg->NewObject(st, assertion_error, compiler::Signatures::BUILTIN_ASSERTION_ERROR); + etsg->CallThisStatic1(st, assertion_error, compiler::Signatures::BUILTIN_ASSERTION_ERROR_CTOR, message); + etsg->EmitThrow(st, assertion_error); +} // compile methods for STATEMENTS in alphabetical order void ETSCompiler::Compile(const ir::AssertStatement *st) const { - (void)st; - UNREACHABLE(); + ETSGen *etsg = GetETSGen(); + auto res = compiler::Condition::CheckConstantExpr(etsg, st->Test()); + if (res == compiler::Condition::Result::CONST_TRUE) { + return; + } + + if (res == compiler::Condition::Result::CONST_FALSE) { + ThrowError(etsg, st); + return; + } + + compiler::Label *true_label = etsg->AllocLabel(); + compiler::Label *false_label = etsg->AllocLabel(); + + compiler::Condition::Compile(etsg, st->Test(), false_label); + etsg->JumpTo(st, true_label); + + etsg->SetLabel(st, false_label); + ThrowError(etsg, st); + + etsg->SetLabel(st, true_label); } void ETSCompiler::Compile(const ir::BlockStatement *st) const { - (void)st; - UNREACHABLE(); + ETSGen *etsg = GetETSGen(); + compiler::LocalRegScope lrs(etsg, st->Scope()); + + etsg->CompileStatements(st->Statements()); +} + +template +static void CompileImpl(const ir::BreakStatement *self, [[maybe_unused]] CodeGen *cg) +{ + compiler::Label *target = cg->ControlFlowChangeBreak(self->Ident()); + cg->Branch(self, target); } void ETSCompiler::Compile(const ir::BreakStatement *st) const { - (void)st; - UNREACHABLE(); + ETSGen *etsg = GetETSGen(); + if (etsg->ExtendWithFinalizer(st->parent_, st)) { + return; + } + CompileImpl(st, etsg); } void ETSCompiler::Compile(const ir::ClassDeclaration *st) const @@ -714,9 +990,8 @@ void ETSCompiler::Compile(const ir::TSClassImplements *expr) const UNREACHABLE(); } -void ETSCompiler::Compile(const ir::TSConditionalType *node) const +void ETSCompiler::Compile([[maybe_unused]] const ir::TSConditionalType *node) const { - (void)node; UNREACHABLE(); } @@ -756,9 +1031,8 @@ void ETSCompiler::Compile(const ir::TSImportEqualsDeclaration *st) const UNREACHABLE(); } -void ETSCompiler::Compile(const ir::TSImportType *node) const +void ETSCompiler::Compile([[maybe_unused]] const ir::TSImportType *node) const { - (void)node; UNREACHABLE(); } @@ -768,9 +1042,8 @@ void ETSCompiler::Compile(const ir::TSIndexedAccessType *node) const UNREACHABLE(); } -void ETSCompiler::Compile(const ir::TSInferType *node) const +void ETSCompiler::Compile([[maybe_unused]] const ir::TSInferType *node) const { - (void)node; UNREACHABLE(); } @@ -792,9 +1065,8 @@ void ETSCompiler::Compile(const ir::TSInterfaceHeritage *expr) const UNREACHABLE(); } -void ETSCompiler::Compile(const ir::TSIntersectionType *node) const +void ETSCompiler::Compile([[maybe_unused]] const ir::TSIntersectionType *node) const { - (void)node; UNREACHABLE(); } @@ -804,15 +1076,13 @@ void ETSCompiler::Compile(const ir::TSLiteralType *node) const UNREACHABLE(); } -void ETSCompiler::Compile(const ir::TSMappedType *node) const +void ETSCompiler::Compile([[maybe_unused]] const ir::TSMappedType *node) const { - (void)node; UNREACHABLE(); } -void ETSCompiler::Compile(const ir::TSModuleBlock *st) const +void ETSCompiler::Compile([[maybe_unused]] const ir::TSModuleBlock *st) const { - (void)st; UNREACHABLE(); } @@ -840,9 +1110,8 @@ void ETSCompiler::Compile(const ir::TSNonNullExpression *expr) const UNREACHABLE(); } -void ETSCompiler::Compile(const ir::TSNullKeyword *node) const +void ETSCompiler::Compile([[maybe_unused]] const ir::TSNullKeyword *node) const { - (void)node; UNREACHABLE(); } @@ -882,9 +1151,8 @@ void ETSCompiler::Compile(const ir::TSStringKeyword *node) const UNREACHABLE(); } -void ETSCompiler::Compile(const ir::TSThisType *node) const +void ETSCompiler::Compile([[maybe_unused]] const ir::TSThisType *node) const { - (void)node; UNREACHABLE(); } diff --git a/ets2panda/compiler/core/JSCompiler.cpp b/ets2panda/compiler/core/JSCompiler.cpp index 10a894d364243fe8b74d0bd55d96c5d90df2551c..29a650840584dae023034c3bdcab8003f095f65d 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 @@ -461,57 +460,48 @@ void JSCompiler::Compile(const ir::TSPropertySignature *node) const UNREACHABLE(); } -void JSCompiler::Compile(const ir::TSSignatureDeclaration *node) const +void JSCompiler::Compile([[maybe_unused]] const ir::TSSignatureDeclaration *node) const { - (void)node; UNREACHABLE(); } // from ets folder -void JSCompiler::Compile(const ir::ETSClassLiteral *expr) const +void JSCompiler::Compile([[maybe_unused]] const ir::ETSClassLiteral *expr) const { - (void)expr; UNREACHABLE(); } -void JSCompiler::Compile(const ir::ETSFunctionType *expr) const +void JSCompiler::Compile([[maybe_unused]] const ir::ETSFunctionType *expr) const { - (void)expr; UNREACHABLE(); } -void JSCompiler::Compile(const ir::ETSImportDeclaration *node) const +void JSCompiler::Compile([[maybe_unused]] const ir::ETSImportDeclaration *node) const { - (void)node; UNREACHABLE(); } -void JSCompiler::Compile(const ir::ETSLaunchExpression *expr) const +void JSCompiler::Compile([[maybe_unused]] const ir::ETSLaunchExpression *expr) const { - (void)expr; UNREACHABLE(); } -void JSCompiler::Compile(const ir::ETSNewArrayInstanceExpression *expr) const +void JSCompiler::Compile([[maybe_unused]] const ir::ETSNewArrayInstanceExpression *expr) const { - (void)expr; UNREACHABLE(); } -void JSCompiler::Compile(const ir::ETSNewClassInstanceExpression *expr) const +void JSCompiler::Compile([[maybe_unused]] const ir::ETSNewClassInstanceExpression *expr) const { - (void)expr; UNREACHABLE(); } -void JSCompiler::Compile(const ir::ETSNewMultiDimArrayInstanceExpression *expr) const +void JSCompiler::Compile([[maybe_unused]] const ir::ETSNewMultiDimArrayInstanceExpression *expr) const { - (void)expr; UNREACHABLE(); } -void JSCompiler::Compile(const ir::ETSPackageDeclaration *expr) const +void JSCompiler::Compile([[maybe_unused]] const ir::ETSPackageDeclaration *expr) const { - (void)expr; UNREACHABLE(); } @@ -620,26 +610,83 @@ void JSCompiler::Compile(const ir::FunctionExpression *expr) const void JSCompiler::Compile(const ir::Identifier *expr) const { - (void)expr; - UNREACHABLE(); + PandaGen *pg = GetPandaGen(); + auto res = pg->Scope()->Find(expr->Name()); + if (res.variable != nullptr) { + pg->LoadVar(expr, res); + return; + } + + if (pg->IsDirectEval()) { + pg->LoadEvalVariable(expr, expr->Name()); + return; + } + + if (expr->Name().Is("NaN")) { + pg->LoadConst(expr, compiler::Constant::JS_NAN); + return; + } + + if (expr->Name().Is("Infinity")) { + pg->LoadConst(expr, compiler::Constant::JS_INFINITY); + return; + } + + if (expr->Name().Is("globalThis")) { + pg->LoadConst(expr, compiler::Constant::JS_GLOBAL); + return; + } + + if (expr->Name().Is("undefined")) { + pg->LoadConst(expr, compiler::Constant::JS_UNDEFINED); + return; + } + + pg->TryLoadGlobalByName(expr, expr->Name()); } -void JSCompiler::Compile(const ir::ImportExpression *expr) const +void JSCompiler::Compile([[maybe_unused]] const ir::ImportExpression *expr) const { - (void)expr; - UNREACHABLE(); + PandaGen *pg = GetPandaGen(); + pg->Unimplemented(); } void JSCompiler::Compile(const ir::MemberExpression *expr) const { - (void)expr; - UNREACHABLE(); + PandaGen *pg = GetPandaGen(); + expr->Object()->Compile(pg); + pg->OptionalChainCheck(expr->IsOptional(), compiler::VReg::Invalid()); + expr->LoadRhs(pg); } void JSCompiler::Compile(const ir::NewExpression *expr) const { - (void)expr; - UNREACHABLE(); + PandaGen *pg = GetPandaGen(); + compiler::RegScope rs(pg); + compiler::VReg ctor = pg->AllocReg(); + compiler::VReg new_target = pg->AllocReg(); + + expr->Callee()->Compile(pg); + pg->StoreAccumulator(expr, ctor); + + // new.Target will be the same as ctor + pg->StoreAccumulator(expr, new_target); + + if (!util::Helpers::ContainSpreadElement(expr->Arguments()) && + expr->Arguments().size() < compiler::PandaGen::MAX_RANGE_CALL_ARG) { + for (const auto *it : expr->Arguments()) { + compiler::VReg arg = pg->AllocReg(); + it->Compile(pg); + pg->StoreAccumulator(expr, arg); + } + + pg->NewObject(expr, ctor, expr->Arguments().size() + 2); + } else { + compiler::VReg args_obj = pg->AllocReg(); + + pg->CreateArray(expr, expr->Arguments(), args_obj); + pg->NewObjSpread(expr, ctor, new_target); + } } void JSCompiler::Compile(const ir::ObjectExpression *expr) const @@ -654,22 +701,29 @@ void JSCompiler::Compile(const ir::OpaqueTypeNode *node) const UNREACHABLE(); } -void JSCompiler::Compile(const ir::OmittedExpression *expr) const +void JSCompiler::Compile([[maybe_unused]] const ir::OmittedExpression *expr) const { - (void)expr; UNREACHABLE(); } void JSCompiler::Compile(const ir::SequenceExpression *expr) const { - (void)expr; - UNREACHABLE(); + PandaGen *pg = GetPandaGen(); + for (const auto *it : expr->Sequence()) { + it->Compile(pg); + } } void JSCompiler::Compile(const ir::SuperExpression *expr) const { - (void)expr; - UNREACHABLE(); + PandaGen *pg = GetPandaGen(); + pg->GetThis(expr); + + const ir::ScriptFunction *func = util::Helpers::GetContainingConstructor(expr); + + if (func != nullptr) { + pg->ThrowIfSuperNotCorrectCall(expr, 0); + } } void JSCompiler::Compile(const ir::TaggedTemplateExpression *expr) const @@ -710,19 +764,18 @@ void JSCompiler::Compile(const ir::YieldExpression *expr) const // Compile methods for LITERAL EXPRESSIONS in alphabetical order void JSCompiler::Compile(const ir::BigIntLiteral *expr) const { - (void)expr; - UNREACHABLE(); + PandaGen *pg = GetPandaGen(); + pg->LoadAccumulatorBigInt(expr, expr->Str()); } void JSCompiler::Compile(const ir::BooleanLiteral *expr) const { - (void)expr; - UNREACHABLE(); + PandaGen *pg = GetPandaGen(); + pg->LoadConst(expr, expr->Value() ? compiler::Constant::JS_TRUE : compiler::Constant::JS_FALSE); } -void JSCompiler::Compile(const ir::CharLiteral *expr) const +void JSCompiler::Compile([[maybe_unused]] const ir::CharLiteral *expr) const { - (void)expr; UNREACHABLE(); } @@ -805,22 +858,31 @@ void JSCompiler::Compile(const ir::ImportSpecifier *st) const UNREACHABLE(); } // Compile methods for STATEMENTS in alphabetical order -void JSCompiler::Compile(const ir::AssertStatement *st) const +void JSCompiler::Compile([[maybe_unused]] const ir::AssertStatement *st) const { - (void)st; UNREACHABLE(); } void JSCompiler::Compile(const ir::BlockStatement *st) const { - (void)st; - UNREACHABLE(); + PandaGen *pg = GetPandaGen(); + compiler::LocalRegScope lrs(pg, st->Scope()); + + for (const auto *it : st->Statements()) { + it->Compile(pg); + } } +template +static void CompileImpl(const ir::BreakStatement *self, [[maybe_unused]] CodeGen *cg) +{ + compiler::Label *target = cg->ControlFlowChangeBreak(self->Ident()); + cg->Branch(self, target); +} void JSCompiler::Compile(const ir::BreakStatement *st) const { - (void)st; - UNREACHABLE(); + PandaGen *pg = GetPandaGen(); + CompileImpl(st, pg); } void JSCompiler::Compile(const ir::ClassDeclaration *st) const @@ -999,9 +1061,8 @@ void JSCompiler::Compile(const ir::TSClassImplements *expr) const UNREACHABLE(); } -void JSCompiler::Compile(const ir::TSConditionalType *node) const +void JSCompiler::Compile([[maybe_unused]] const ir::TSConditionalType *node) const { - (void)node; UNREACHABLE(); } @@ -1041,9 +1102,8 @@ void JSCompiler::Compile(const ir::TSImportEqualsDeclaration *st) const UNREACHABLE(); } -void JSCompiler::Compile(const ir::TSImportType *node) const +void JSCompiler::Compile([[maybe_unused]] const ir::TSImportType *node) const { - (void)node; UNREACHABLE(); } @@ -1053,9 +1113,8 @@ void JSCompiler::Compile(const ir::TSIndexedAccessType *node) const UNREACHABLE(); } -void JSCompiler::Compile(const ir::TSInferType *node) const +void JSCompiler::Compile([[maybe_unused]] const ir::TSInferType *node) const { - (void)node; UNREACHABLE(); } @@ -1077,9 +1136,8 @@ void JSCompiler::Compile(const ir::TSInterfaceHeritage *expr) const UNREACHABLE(); } -void JSCompiler::Compile(const ir::TSIntersectionType *node) const +void JSCompiler::Compile([[maybe_unused]] const ir::TSIntersectionType *node) const { - (void)node; UNREACHABLE(); } @@ -1089,15 +1147,13 @@ void JSCompiler::Compile(const ir::TSLiteralType *node) const UNREACHABLE(); } -void JSCompiler::Compile(const ir::TSMappedType *node) const +void JSCompiler::Compile([[maybe_unused]] const ir::TSMappedType *node) const { - (void)node; UNREACHABLE(); } -void JSCompiler::Compile(const ir::TSModuleBlock *st) const +void JSCompiler::Compile([[maybe_unused]] const ir::TSModuleBlock *st) const { - (void)st; UNREACHABLE(); } @@ -1125,9 +1181,8 @@ void JSCompiler::Compile(const ir::TSNonNullExpression *expr) const UNREACHABLE(); } -void JSCompiler::Compile(const ir::TSNullKeyword *node) const +void JSCompiler::Compile([[maybe_unused]] const ir::TSNullKeyword *node) const { - (void)node; UNREACHABLE(); } @@ -1167,9 +1222,8 @@ void JSCompiler::Compile(const ir::TSStringKeyword *node) const UNREACHABLE(); } -void JSCompiler::Compile(const ir::TSThisType *node) const +void JSCompiler::Compile([[maybe_unused]] const ir::TSThisType *node) const { - (void)node; UNREACHABLE(); } diff --git a/ets2panda/ir/base/tsSignatureDeclaration.cpp b/ets2panda/ir/base/tsSignatureDeclaration.cpp index 734c4613f9cdd7b80be713cadb2c229dd837689d..306dccd59ca1519de8aaa484e00c35aef46e183a 100644 --- a/ets2panda/ir/base/tsSignatureDeclaration.cpp +++ b/ets2panda/ir/base/tsSignatureDeclaration.cpp @@ -16,12 +16,10 @@ #include "tsSignatureDeclaration.h" #include "varbinder/scope.h" -#include "ir/typeNode.h" -#include "ir/astDump.h" -#include "ir/ts/tsTypeParameter.h" -#include "ir/ts/tsTypeParameterDeclaration.h" - +#include "checker/ETSchecker.h" #include "checker/TSchecker.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" namespace panda::es2panda::ir { void TSSignatureDeclaration::TransformChildren(const NodeTransformer &cb) @@ -64,50 +62,23 @@ void TSSignatureDeclaration::Dump(ir::AstDumper *dumper) const {"returnType", AstDumper::Optional(return_type_annotation_)}}); } -void TSSignatureDeclaration::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} - -checker::Type *TSSignatureDeclaration::Check([[maybe_unused]] checker::TSChecker *checker) +void TSSignatureDeclaration::Compile(compiler::PandaGen *pg) const { - if (TsType() != nullptr) { - return TsType(); - } - - checker::ScopeContext scope_ctx(checker, scope_); - - auto *signature_info = checker->Allocator()->New(checker->Allocator()); - checker->CheckFunctionParameterDeclarations(params_, signature_info); - - bool is_call_signature = (Kind() == ir::TSSignatureDeclaration::TSSignatureDeclarationKind::CALL_SIGNATURE); - - if (return_type_annotation_ == nullptr) { - if (is_call_signature) { - checker->ThrowTypeError( - "Call signature, which lacks return-type annotation, implicitly has an 'any' return type.", Start()); - } - - checker->ThrowTypeError( - "Construct signature, which lacks return-type annotation, implicitly has an 'any' return type.", Start()); - } - - return_type_annotation_->Check(checker); - checker::Type *return_type = return_type_annotation_->GetType(checker); - - auto *signature = checker->Allocator()->New(signature_info, return_type); - - checker::Type *placeholder_obj = nullptr; + pg->GetAstCompiler()->Compile(this); +} - if (is_call_signature) { - placeholder_obj = checker->CreateObjectTypeWithCallSignature(signature); - } else { - placeholder_obj = checker->CreateObjectTypeWithConstructSignature(signature); - } +void TSSignatureDeclaration::Compile(compiler::ETSGen *etsg) const +{ + etsg->GetAstCompiler()->Compile(this); +} - SetTsType(placeholder_obj); - return placeholder_obj; +checker::Type *TSSignatureDeclaration::Check(checker::TSChecker *checker) +{ + return checker->GetAnalyzer()->Check(this); } -checker::Type *TSSignatureDeclaration::Check([[maybe_unused]] checker::ETSChecker *checker) +checker::Type *TSSignatureDeclaration::Check(checker::ETSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/base/tsSignatureDeclaration.h b/ets2panda/ir/base/tsSignatureDeclaration.h index bd89af7fa3b833cc3542d3b60d05ae871697f8e6..5df54c3555406e5dd66e8155ac37b46b14f7f93d 100644 --- a/ets2panda/ir/base/tsSignatureDeclaration.h +++ b/ets2panda/ir/base/tsSignatureDeclaration.h @@ -18,6 +18,10 @@ #include "ir/statement.h" +namespace panda::es2panda::checker { +class TSAnalyzer; +} // namespace panda::es2panda::checker + namespace panda::es2panda::ir { class TSTypeParameterDeclaration; @@ -36,6 +40,8 @@ public: return_type_annotation_(return_type_annotation) { } + // TODO (csabahurton): friend relationship can be removed once there are getters for private fields + friend class checker::TSAnalyzer; bool IsScopeBearer() const override { @@ -70,9 +76,10 @@ public: void TransformChildren(const NodeTransformer &cb) override; void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; - void Compile([[maybe_unused]] compiler::PandaGen *pg) const override; - checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + void Compile(compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; + checker::Type *Check(checker::TSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; private: varbinder::Scope *scope_; diff --git a/ets2panda/ir/ets/etsClassLiteral.cpp b/ets2panda/ir/ets/etsClassLiteral.cpp index 79c11f531ecd7fc26d5fb88e412abc91c73b012b..2bad3b3171f1133f178ef4022de8466e1e43db15 100644 --- a/ets2panda/ir/ets/etsClassLiteral.cpp +++ b/ets2panda/ir/ets/etsClassLiteral.cpp @@ -15,12 +15,10 @@ #include "etsClassLiteral.h" -#include "ir/astNode.h" -#include "ir/astDump.h" -#include "ir/typeNode.h" #include "checker/TSchecker.h" -#include "checker/ets/typeRelationContext.h" #include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" +#include "ir/astDump.h" namespace panda::es2panda::ir { void ETSClassLiteral::TransformChildren(const NodeTransformer &cb) @@ -38,42 +36,24 @@ void ETSClassLiteral::Dump(ir::AstDumper *dumper) const dumper->Add({{"type", "ETSClassLiteral"}}); } -void ETSClassLiteral::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} - -void ETSClassLiteral::Compile([[maybe_unused]] compiler::ETSGen *etsg) const +void ETSClassLiteral::Compile(compiler::PandaGen *pg) const { - if (expr_->TsType()->HasTypeFlag(checker::TypeFlag::ETS_ARRAY_OR_OBJECT)) { - expr_->Compile(etsg); - etsg->GetType(this, false); - } else { - ASSERT(expr_->TsType()->HasTypeFlag(checker::TypeFlag::ETS_PRIMITIVE)); - etsg->SetAccumulatorType(expr_->TsType()); - etsg->GetType(this, true); - } + pg->GetAstCompiler()->Compile(this); } -checker::Type *ETSClassLiteral::Check([[maybe_unused]] checker::TSChecker *checker) +void ETSClassLiteral::Compile(compiler::ETSGen *etsg) const { - return nullptr; + etsg->GetAstCompiler()->Compile(this); } -checker::Type *ETSClassLiteral::Check([[maybe_unused]] checker::ETSChecker *checker) +checker::Type *ETSClassLiteral::Check(checker::TSChecker *checker) { - checker->ThrowTypeError("Class literal is not yet supported.", expr_->Start()); - - expr_->Check(checker); - auto *expr_type = expr_->GetType(checker); - - if (expr_type->IsETSVoidType()) { - checker->ThrowTypeError("Invalid .class reference", expr_->Start()); - } - - ArenaVector type_arg_types(checker->Allocator()->Adapter()); - type_arg_types.push_back(expr_type); // NOTE: Box it if it's a primitive type + return checker->GetAnalyzer()->Check(this); +} - checker::InstantiationContext ctx(checker, checker->GlobalBuiltinTypeType(), type_arg_types, range_.start); - SetTsType(ctx.Result()); - return TsType(); +checker::Type *ETSClassLiteral::Check(checker::ETSChecker *checker) +{ + return checker->GetAnalyzer()->Check(this); } // NOLINTNEXTLINE(google-default-arguments) diff --git a/ets2panda/ir/ets/etsClassLiteral.h b/ets2panda/ir/ets/etsClassLiteral.h index 64dadfd65bbfb304b5a993444ee73cbba8bbe36f..980c27ab40f1fc165b1dbef121980c898f0f7806 100644 --- a/ets2panda/ir/ets/etsClassLiteral.h +++ b/ets2panda/ir/ets/etsClassLiteral.h @@ -18,6 +18,14 @@ #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 ETSClassLiteral : public Expression { @@ -33,13 +41,17 @@ public: // NOLINTNEXTLINE(google-default-arguments) [[nodiscard]] Expression *Clone(ArenaAllocator *allocator, AstNode *parent = nullptr) override; + // TODO (csabahurton): these friend relationships can be removed once there are getters for private fields + friend class checker::ETSAnalyzer; + friend class compiler::ETSCompiler; + void TransformChildren(const NodeTransformer &cb) override; 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([[maybe_unused]] compiler::ETSGen *etsg) const override; - checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + void Compile(compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; + checker::Type *Check(checker::TSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; private: ir::TypeNode *expr_; diff --git a/ets2panda/ir/ets/etsFunctionType.cpp b/ets2panda/ir/ets/etsFunctionType.cpp index 57e2248c5636d922988e83ab2e0197695e8c9644..ba44e619633c78f02df22e2da0299bdef97f1727 100644 --- a/ets2panda/ir/ets/etsFunctionType.cpp +++ b/ets2panda/ir/ets/etsFunctionType.cpp @@ -18,17 +18,9 @@ #include "varbinder/scope.h" #include "checker/TSchecker.h" #include "checker/ETSchecker.h" -#include "checker/types/signature.h" -#include "ir/astDump.h" -#include "ir/base/spreadElement.h" -#include "ir/base/methodDefinition.h" -#include "ir/base/scriptFunction.h" -#include "ir/expressions/identifier.h" -#include "ir/ts/tsTypeParameter.h" -#include "ir/ts/tsInterfaceDeclaration.h" -#include "ir/ts/tsInterfaceBody.h" -#include "ir/ts/tsTypeParameterDeclaration.h" -#include "ir/ets/etsParameterExpression.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" +// #include "ir/astDump.h" namespace panda::es2panda::ir { void ETSFunctionType::TransformChildren(const NodeTransformer &cb) @@ -73,11 +65,19 @@ void ETSFunctionType::Dump(ir::AstDumper *dumper) const } } -void ETSFunctionType::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} +void ETSFunctionType::Compile(compiler::PandaGen *pg) const +{ + pg->GetAstCompiler()->Compile(this); +} -checker::Type *ETSFunctionType::Check([[maybe_unused]] checker::TSChecker *checker) +void ETSFunctionType::Compile(compiler::ETSGen *etsg) const { - return nullptr; + etsg->GetAstCompiler()->Compile(this); +} + +checker::Type *ETSFunctionType::Check(checker::TSChecker *checker) +{ + return checker->GetAnalyzer()->Check(this); } checker::Type *ETSFunctionType::GetType([[maybe_unused]] checker::TSChecker *checker) @@ -87,60 +87,7 @@ checker::Type *ETSFunctionType::GetType([[maybe_unused]] checker::TSChecker *che checker::Type *ETSFunctionType::Check(checker::ETSChecker *checker) { - checker->CreateFunctionalInterfaceForFunctionType(this); - auto *interface_type = checker->CreateETSObjectType(functional_interface_->Id()->Name(), functional_interface_, - checker::ETSObjectFlags::FUNCTIONAL_INTERFACE); - interface_type->SetSuperType(checker->GlobalETSObjectType()); - - auto *invoke_func = functional_interface_->Body()->Body()[0]->AsMethodDefinition()->Function(); - auto *signature_info = checker->Allocator()->New(checker->Allocator()); - - for (auto *it : invoke_func->Params()) { - auto *const param = it->AsETSParameterExpression(); - if (param->IsRestParameter()) { - auto *rest_ident = param->Ident(); - - ASSERT(rest_ident->Variable()); - signature_info->rest_var = rest_ident->Variable()->AsLocalVariable(); - - ASSERT(param->TypeAnnotation()); - signature_info->rest_var->SetTsType(checker->GetTypeFromTypeAnnotation(param->TypeAnnotation())); - - auto array_type = signature_info->rest_var->TsType()->AsETSArrayType(); - checker->CreateBuiltinArraySignature(array_type, array_type->Rank()); - } else { - auto *param_ident = param->Ident(); - - ASSERT(param_ident->Variable()); - varbinder::Variable *param_var = param_ident->Variable(); - - ASSERT(param->TypeAnnotation()); - param_var->SetTsType(checker->GetTypeFromTypeAnnotation(param->TypeAnnotation())); - signature_info->params.push_back(param_var->AsLocalVariable()); - ++signature_info->min_arg_count; - } - } - - invoke_func->ReturnTypeAnnotation()->Check(checker); - auto *signature = - checker->Allocator()->New(signature_info, return_type_->GetType(checker), invoke_func); - signature->SetOwnerVar(invoke_func->Id()->Variable()->AsLocalVariable()); - signature->AddSignatureFlag(checker::SignatureFlags::FUNCTIONAL_INTERFACE_SIGNATURE); - signature->SetOwner(interface_type); - - auto *func_type = checker->CreateETSFunctionType(signature); - invoke_func->SetSignature(signature); - invoke_func->Id()->Variable()->SetTsType(func_type); - interface_type->AddProperty( - invoke_func->Id()->Variable()->AsLocalVariable()); - functional_interface_->SetTsType(interface_type); - - auto *this_var = invoke_func->Scope()->ParamScope()->Params().front(); - this_var->SetTsType(interface_type); - checker->BuildFunctionalInterfaceName(this); - - ts_type_ = interface_type; - return interface_type; + return checker->GetAnalyzer()->Check(this); } checker::Type *ETSFunctionType::GetType(checker::ETSChecker *checker) diff --git a/ets2panda/ir/ets/etsFunctionType.h b/ets2panda/ir/ets/etsFunctionType.h index 62c59ffd9fb30b2a00ef9ef17bfc878c4961f611..954db878ea7dda28b515fd9a7d9806c02c711770 100644 --- a/ets2panda/ir/ets/etsFunctionType.h +++ b/ets2panda/ir/ets/etsFunctionType.h @@ -18,6 +18,10 @@ #include "ir/typeNode.h" +namespace panda::es2panda::checker { +class ETSAnalyzer; +} // namespace panda::es2panda::checker + namespace panda::es2panda::ir { class TSTypeParameterDeclaration; @@ -35,6 +39,9 @@ public: { } + // TODO (csabahurton): friend relationship can be removed once there are getters for private fields + friend class checker::ETSAnalyzer; + bool IsScopeBearer() const override { return true; @@ -88,10 +95,11 @@ public: void TransformChildren(const NodeTransformer &cb) override; void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; - void Compile([[maybe_unused]] compiler::PandaGen *pg) const override; - checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; + void Compile(compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; + checker::Type *Check(checker::TSChecker *checker) override; checker::Type *GetType([[maybe_unused]] checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; checker::Type *GetType([[maybe_unused]] checker::ETSChecker *checker) override; private: diff --git a/ets2panda/ir/ets/etsLaunchExpression.cpp b/ets2panda/ir/ets/etsLaunchExpression.cpp index f5d880a47f87fba81be68b8bcdd7c9ea5d3983b0..7b5f0290d586cf76e26494b51acbf090db51b8d9 100644 --- a/ets2panda/ir/ets/etsLaunchExpression.cpp +++ b/ets2panda/ir/ets/etsLaunchExpression.cpp @@ -19,10 +19,6 @@ #include "compiler/core/ETSGen.h" #include "checker/ETSchecker.h" #include "checker/TSchecker.h" -#include "ir/astDump.h" -#include "ir/expressions/identifier.h" -#include "ir/expressions/callExpression.h" -#include "ir/expressions/memberExpression.h" namespace panda::es2panda::ir { ETSLaunchExpression::ETSLaunchExpression(CallExpression *expr) @@ -45,70 +41,26 @@ void ETSLaunchExpression::Dump(ir::AstDumper *dumper) const dumper->Add({{"type", "ETSLaunchExpression"}, {"expr", expr_}}); } -void ETSLaunchExpression::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} +void ETSLaunchExpression::Compile(compiler::PandaGen *pg) const +{ + pg->GetAstCompiler()->Compile(this); +} void ETSLaunchExpression::Compile([[maybe_unused]] compiler::ETSGen *etsg) const { #ifdef PANDA_WITH_ETS - compiler::RegScope rs(etsg); - compiler::VReg callee_reg = etsg->AllocReg(); - checker::Signature *signature = expr_->Signature(); - bool is_static = signature->HasSignatureFlag(checker::SignatureFlags::STATIC); - bool is_reference = signature->HasSignatureFlag(checker::SignatureFlags::TYPE); - if (!is_reference && expr_->Callee()->IsIdentifier()) { - if (!is_static) { - etsg->LoadThis(expr_); - etsg->StoreAccumulator(this, callee_reg); - } - } else if (!is_reference && expr_->Callee()->IsMemberExpression()) { - if (!is_static) { - expr_->Callee()->AsMemberExpression()->Object()->Compile(etsg); - etsg->StoreAccumulator(this, callee_reg); - } - } else { - expr_->Callee()->Compile(etsg); - etsg->StoreAccumulator(this, callee_reg); - } - - if (is_static) { - etsg->LaunchStatic(this, signature, expr_->Arguments()); - } else if (signature->HasSignatureFlag(checker::SignatureFlags::PRIVATE)) { - etsg->LaunchThisStatic(this, callee_reg, signature, expr_->Arguments()); - } else { - etsg->LaunchThisVirtual(this, callee_reg, signature, expr_->Arguments()); - } - - etsg->SetAccumulatorType(TsType()); + etsg->GetAstCompiler()->Compile(this); #endif // PANDA_WITH_ETS } -checker::Type *ETSLaunchExpression::Check([[maybe_unused]] checker::TSChecker *checker) +checker::Type *ETSLaunchExpression::Check(checker::TSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } checker::Type *ETSLaunchExpression::Check(checker::ETSChecker *checker) { - expr_->Check(checker); - auto *const launch_promise_type = - checker->GlobalBuiltinPromiseType() - ->Instantiate(checker->Allocator(), checker->Relation(), checker->GetGlobalTypesHolder()) - ->AsETSObjectType(); - launch_promise_type->AddTypeFlag(checker::TypeFlag::GENERIC); - - // Launch expression returns a Promise type, so we need to insert the expression's type - // as type parameter for the Promise class. - - auto *expr_type = - expr_->TsType()->HasTypeFlag(checker::TypeFlag::ETS_PRIMITIVE) && !expr_->TsType()->IsETSVoidType() - ? checker->PrimitiveTypeAsETSBuiltinType(expr_->TsType()) - : expr_->TsType(); - checker::Substitution *substitution = checker->NewSubstitution(); - ASSERT(launch_promise_type->TypeArguments().size() == 1); - substitution->emplace(checker->GetOriginalBaseType(launch_promise_type->TypeArguments()[0]), expr_type); - - SetTsType(launch_promise_type->Substitute(checker->Relation(), substitution)); - return TsType(); + return checker->GetAnalyzer()->Check(this); } bool ETSLaunchExpression::IsStaticCall() const diff --git a/ets2panda/ir/ets/etsLaunchExpression.h b/ets2panda/ir/ets/etsLaunchExpression.h index db99d9e6a58b6fd1a65e0be5066bdb06cb764bed..70b2b565d34dac0217758b7d23a6e3bdb2d21c3b 100644 --- a/ets2panda/ir/ets/etsLaunchExpression.h +++ b/ets2panda/ir/ets/etsLaunchExpression.h @@ -18,6 +18,14 @@ #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 CallExpression; @@ -32,16 +40,19 @@ public: explicit ETSLaunchExpression(CallExpression *expr); + // TODO (csabahurton): these friend relationships can be removed once there are getters for private fields + friend class checker::ETSAnalyzer; + friend class compiler::ETSCompiler; + // NOLINTNEXTLINE(google-default-arguments) [[nodiscard]] Expression *Clone(ArenaAllocator *allocator, AstNode *parent = nullptr) override; - void TransformChildren(const NodeTransformer &cb) override; 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([[maybe_unused]] compiler::ETSGen *etsg) const override; - checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + void Compile(compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; + checker::Type *Check(checker::TSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; bool IsStaticCall() const; [[nodiscard]] const CallExpression *Call() const noexcept diff --git a/ets2panda/ir/ets/etsNewArrayInstanceExpression.cpp b/ets2panda/ir/ets/etsNewArrayInstanceExpression.cpp index bf3d63aafe6f8230f4e2f8cb39ebd7dc9b536ce3..89cc122d3933037ca6493f0e987448fe9fd135f0 100644 --- a/ets2panda/ir/ets/etsNewArrayInstanceExpression.cpp +++ b/ets2panda/ir/ets/etsNewArrayInstanceExpression.cpp @@ -15,10 +15,12 @@ #include "etsNewArrayInstanceExpression.h" +#include "checker/ETSchecker.h" +#include "checker/TSchecker.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" #include "ir/astDump.h" #include "ir/typeNode.h" -#include "compiler/core/ETSGen.h" -#include "checker/ETSchecker.h" namespace panda::es2panda::ir { void ETSNewArrayInstanceExpression::TransformChildren(const NodeTransformer &cb) @@ -39,35 +41,23 @@ void ETSNewArrayInstanceExpression::Dump(ir::AstDumper *dumper) const {{"type", "ETSNewArrayInstanceExpression"}, {"typeReference", type_reference_}, {"dimension", dimension_}}); } -void ETSNewArrayInstanceExpression::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} -void ETSNewArrayInstanceExpression::Compile([[maybe_unused]] compiler::ETSGen *etsg) const +void ETSNewArrayInstanceExpression::Compile(compiler::PandaGen *pg) const { - compiler::RegScope rs(etsg); - compiler::TargetTypeContext ttctx(etsg, etsg->Checker()->GlobalIntType()); - - dimension_->Compile(etsg); - - compiler::VReg arr = etsg->AllocReg(); - compiler::VReg dim = etsg->AllocReg(); - etsg->ApplyConversionAndStoreAccumulator(this, dim, dimension_->TsType()); - etsg->NewArray(this, arr, dim, TsType()); - etsg->SetVRegType(arr, TsType()); - etsg->LoadAccumulator(this, arr); + pg->GetAstCompiler()->Compile(this); } - -checker::Type *ETSNewArrayInstanceExpression::Check([[maybe_unused]] checker::TSChecker *checker) +void ETSNewArrayInstanceExpression::Compile(compiler::ETSGen *etsg) const { - return nullptr; + etsg->GetAstCompiler()->Compile(this); } -checker::Type *ETSNewArrayInstanceExpression::Check([[maybe_unused]] checker::ETSChecker *checker) +checker::Type *ETSNewArrayInstanceExpression::Check(checker::TSChecker *checker) { - auto *element_type = type_reference_->GetType(checker); - checker->ValidateArrayIndex(dimension_); + return checker->GetAnalyzer()->Check(this); +} - SetTsType(checker->CreateETSArrayType(element_type)); - checker->CreateBuiltinArraySignature(TsType()->AsETSArrayType(), 1); - return TsType(); +checker::Type *ETSNewArrayInstanceExpression::Check(checker::ETSChecker *checker) +{ + return checker->GetAnalyzer()->Check(this); } // NOLINTNEXTLINE(google-default-arguments) diff --git a/ets2panda/ir/ets/etsNewArrayInstanceExpression.h b/ets2panda/ir/ets/etsNewArrayInstanceExpression.h index 553bb75120377bf84d5ead2276bf5323fbf855b6..14e05d00ce897bd6e88112592b626b68ee5f8c0a 100644 --- a/ets2panda/ir/ets/etsNewArrayInstanceExpression.h +++ b/ets2panda/ir/ets/etsNewArrayInstanceExpression.h @@ -18,6 +18,14 @@ #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 ETSNewArrayInstanceExpression : public Expression { @@ -34,6 +42,9 @@ public: dimension_(dimension) { } + // TODO (csabahurton): these friend relationships can be removed once there are getters for private fields + friend class checker::ETSAnalyzer; + friend class compiler::ETSCompiler; // NOLINTNEXTLINE(google-default-arguments) [[nodiscard]] Expression *Clone(ArenaAllocator *allocator, AstNode *parent = nullptr) override; @@ -41,10 +52,10 @@ public: void TransformChildren(const NodeTransformer &cb) override; 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([[maybe_unused]] compiler::ETSGen *etsg) const override; - checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + void Compile(compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; + checker::Type *Check(checker::TSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; private: ir::TypeNode *type_reference_; diff --git a/ets2panda/ir/ets/etsNewClassInstanceExpression.cpp b/ets2panda/ir/ets/etsNewClassInstanceExpression.cpp index 0e55a8ac981c704ab2e0c4719cf31b7094de37d2..1a1cb1af2634ea8ba0ca6ce79e73d57508ef852d 100644 --- a/ets2panda/ir/ets/etsNewClassInstanceExpression.cpp +++ b/ets2panda/ir/ets/etsNewClassInstanceExpression.cpp @@ -16,17 +16,9 @@ #include "etsNewClassInstanceExpression.h" #include "compiler/core/ETSGen.h" -#include "ir/base/classDefinition.h" -#include "ir/base/scriptFunction.h" -#include "ir/astDump.h" -#include "ir/ets/etsTypeReference.h" -#include "ir/ets/etsTypeReferencePart.h" -#include "ir/expressions/identifier.h" -#include "ir/statements/variableDeclarator.h" -#include "ir/ts/tsQualifiedName.h" +#include "compiler/core/pandagen.h" #include "checker/TSchecker.h" -#include "checker/ETSchecker.h" -#include "checker/types/ets/types.h" +#include "ir/astDump.h" namespace panda::es2panda::ir { void ETSNewClassInstanceExpression::TransformChildren(const NodeTransformer &cb) @@ -63,125 +55,23 @@ void ETSNewClassInstanceExpression::Dump(ir::AstDumper *dumper) const {"classBody", AstDumper::Optional(class_def_)}}); } -void ETSNewClassInstanceExpression::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} - -void ETSNewClassInstanceExpression::CreateDynamicObject(const ir::AstNode *node, compiler::ETSGen *etsg, - compiler::VReg &obj_reg, ir::Expression *name, - checker::Signature *signature, - const ArenaVector &arguments) +void ETSNewClassInstanceExpression::Compile(compiler::PandaGen *pg) const { - auto qname_reg = etsg->AllocReg(); - - std::vector parts; - - while (name->IsTSQualifiedName()) { - auto *qname = name->AsTSQualifiedName(); - name = qname->Left(); - parts.push_back(qname->Right()->AsIdentifier()->Name()); - } - - auto *var = name->AsIdentifier()->Variable(); - auto *data = etsg->VarBinder()->DynamicImportDataForVar(var); - if (data != nullptr) { - auto *import = data->import; - auto *specifier = data->specifier; - ASSERT(import->Language().IsDynamic()); - etsg->LoadAccumulatorDynamicModule(node, import); - if (specifier->IsImportSpecifier()) { - parts.push_back(specifier->AsImportSpecifier()->Imported()->Name()); - } - } else { - name->Compile(etsg); - } - - etsg->StoreAccumulator(node, obj_reg); - - std::stringstream ss; - std::for_each(parts.rbegin(), parts.rend(), [&ss](util::StringView sv) { ss << "." << sv; }); - - etsg->LoadAccumulatorString(node, util::UString(ss.str(), etsg->Allocator()).View()); - etsg->StoreAccumulator(node, qname_reg); - - etsg->CallDynamic(node, obj_reg, qname_reg, signature, arguments); + pg->GetAstCompiler()->Compile(this); } -void ETSNewClassInstanceExpression::Compile([[maybe_unused]] compiler::ETSGen *etsg) const +void ETSNewClassInstanceExpression::Compile(compiler::ETSGen *etsg) const { - if (TsType()->IsETSDynamicType()) { - auto obj_reg = etsg->AllocReg(); - auto *name = type_reference_->AsETSTypeReference()->Part()->Name(); - CreateDynamicObject(this, etsg, obj_reg, name, signature_, arguments_); - } else { - etsg->InitObject(this, signature_, arguments_); - } - - if (GetBoxingUnboxingFlags() == ir::BoxingUnboxingFlags::NONE) { - etsg->SetAccumulatorType(TsType()); - } + etsg->GetAstCompiler()->Compile(this); } -checker::Type *ETSNewClassInstanceExpression::Check([[maybe_unused]] checker::TSChecker *checker) +checker::Type *ETSNewClassInstanceExpression::Check(checker::TSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } -checker::Type *ETSNewClassInstanceExpression::Check([[maybe_unused]] checker::ETSChecker *checker) +checker::Type *ETSNewClassInstanceExpression::Check(checker::ETSChecker *checker) { - checker::Type *callee_type = type_reference_->Check(checker); - - if (!callee_type->IsETSObjectType()) { - checker->ThrowTypeError("This expression is not constructible.", Start()); - } - - auto *callee_obj = callee_type->AsETSObjectType(); - SetTsType(callee_obj); - - if (class_def_ != nullptr) { - if (!callee_obj->HasObjectFlag(checker::ETSObjectFlags::ABSTRACT) && callee_obj->GetDeclNode()->IsFinal()) { - checker->ThrowTypeError({"Class ", callee_obj->Name(), " cannot be both 'abstract' and 'final'."}, - callee_obj->GetDeclNode()->Start()); - } - - bool from_interface = callee_obj->HasObjectFlag(checker::ETSObjectFlags::INTERFACE); - auto *class_type = checker->BuildAnonymousClassProperties( - class_def_, from_interface ? checker->GlobalETSObjectType() : callee_obj); - if (from_interface) { - class_type->AddInterface(callee_obj); - callee_obj = checker->GlobalETSObjectType(); - } - class_def_->SetTsType(class_type); - checker->CheckClassDefinition(class_def_); - checker->CheckInnerClassMembers(class_type); - SetTsType(class_type); - } else if (callee_obj->HasObjectFlag(checker::ETSObjectFlags::ABSTRACT)) { - checker->ThrowTypeError({callee_obj->Name(), " is abstract therefore cannot be instantiated."}, Start()); - } - - if (callee_type->IsETSDynamicType() && !callee_type->AsETSDynamicType()->HasDecl()) { - auto lang = callee_type->AsETSDynamicType()->Language(); - signature_ = checker->ResolveDynamicCallExpression(type_reference_, arguments_, lang, true); - } else { - auto *signature = checker->ResolveConstructExpression(callee_obj, arguments_, Start()); - - checker->CheckObjectLiteralArguments(signature, arguments_); - checker->ValidateSignatureAccessibility(callee_obj, signature, Start()); - - ASSERT(signature->Function() != nullptr); - - if (signature->Function()->IsThrowing() || signature->Function()->IsRethrowing()) { - checker->CheckThrowingStatements(this); - } - - if (callee_type->IsETSDynamicType()) { - ASSERT(signature->Function()->IsDynamic()); - auto lang = callee_type->AsETSDynamicType()->Language(); - signature_ = checker->ResolveDynamicCallExpression(type_reference_, signature->Params(), lang, true); - } else { - ASSERT(!signature->Function()->IsDynamic()); - signature_ = signature; - } - } - - return TsType(); + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/ets/etsNewClassInstanceExpression.h b/ets2panda/ir/ets/etsNewClassInstanceExpression.h index ffed6e65cdd9747a1bde4c1841d2ce62757f987f..425a0a5bf41e5f0ff819a143fea03aed624a0fb2 100644 --- a/ets2panda/ir/ets/etsNewClassInstanceExpression.h +++ b/ets2panda/ir/ets/etsNewClassInstanceExpression.h @@ -20,9 +20,14 @@ #include "ir/expression.h" namespace panda::es2panda::checker { +class ETSAnalyzer; class Signature; } // namespace panda::es2panda::checker +namespace panda::es2panda::compiler { +class ETSCompiler; +} // namespace panda::es2panda::compiler + namespace panda::es2panda::ir { class ClassDefinition; @@ -37,6 +42,9 @@ public: class_def_(class_definition) { } + // TODO (csabahurton): these friend relationships can be removed once there are getters for private fields + friend class checker::ETSAnalyzer; + friend class compiler::ETSCompiler; ir::ClassDefinition *ClassDefinition() { @@ -63,17 +71,13 @@ public: signature_ = signature; } - static void CreateDynamicObject(const ir::AstNode *node, compiler::ETSGen *etsg, compiler::VReg &obj_reg, - ir::Expression *name, checker::Signature *signature, - const ArenaVector &arguments); - void TransformChildren(const NodeTransformer &cb) override; 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([[maybe_unused]] compiler::ETSGen *etsg) const override; - checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + void Compile(compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; + checker::Type *Check(checker::TSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; private: ir::Expression *type_reference_; diff --git a/ets2panda/ir/ets/etsNewMultiDimArrayInstanceExpression.cpp b/ets2panda/ir/ets/etsNewMultiDimArrayInstanceExpression.cpp index 3671c96b28d60c2b1e9c1f9b1465aea951eb4738..95d44163b0b0c79f2627e1ed0dc56511af7ceee2 100644 --- a/ets2panda/ir/ets/etsNewMultiDimArrayInstanceExpression.cpp +++ b/ets2panda/ir/ets/etsNewMultiDimArrayInstanceExpression.cpp @@ -16,11 +16,9 @@ #include "etsNewMultiDimArrayInstanceExpression.h" #include "varbinder/ETSBinder.h" -#include "ir/astDump.h" -#include "ir/typeNode.h" +#include "checker/TSchecker.h" #include "compiler/core/ETSGen.h" -#include "checker/ETSchecker.h" -#include "checker/types/signature.h" +#include "compiler/core/pandagen.h" namespace panda::es2panda::ir { void ETSNewMultiDimArrayInstanceExpression::TransformChildren(const NodeTransformer &cb) @@ -46,29 +44,22 @@ void ETSNewMultiDimArrayInstanceExpression::Dump(ir::AstDumper *dumper) const {"dimensions", dimensions_}}); } -void ETSNewMultiDimArrayInstanceExpression::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} -void ETSNewMultiDimArrayInstanceExpression::Compile([[maybe_unused]] compiler::ETSGen *etsg) const +void ETSNewMultiDimArrayInstanceExpression::Compile(compiler::PandaGen *pg) const { - etsg->InitObject(this, signature_, dimensions_); - etsg->SetAccumulatorType(TsType()); + pg->GetAstCompiler()->Compile(this); } - -checker::Type *ETSNewMultiDimArrayInstanceExpression::Check([[maybe_unused]] checker::TSChecker *checker) +void ETSNewMultiDimArrayInstanceExpression::Compile(compiler::ETSGen *etsg) const { - return nullptr; + etsg->GetAstCompiler()->Compile(this); } -checker::Type *ETSNewMultiDimArrayInstanceExpression::Check([[maybe_unused]] checker::ETSChecker *checker) +checker::Type *ETSNewMultiDimArrayInstanceExpression::Check(checker::TSChecker *checker) { - auto *element_type = type_reference_->GetType(checker); - - for (auto *dim : dimensions_) { - checker->ValidateArrayIndex(dim); - element_type = checker->CreateETSArrayType(element_type); - } + return checker->GetAnalyzer()->Check(this); +} - SetTsType(element_type); - signature_ = checker->CreateBuiltinArraySignature(element_type->AsETSArrayType(), dimensions_.size()); - return TsType(); +checker::Type *ETSNewMultiDimArrayInstanceExpression::Check(checker::ETSChecker *checker) +{ + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/ets/etsNewMultiDimArrayInstanceExpression.h b/ets2panda/ir/ets/etsNewMultiDimArrayInstanceExpression.h index 1cf38efa643435cccf347872aed8957b3912a35d..e7ecee053e27ad92d46e6c9b679a888d3f44dfe3 100644 --- a/ets2panda/ir/ets/etsNewMultiDimArrayInstanceExpression.h +++ b/ets2panda/ir/ets/etsNewMultiDimArrayInstanceExpression.h @@ -19,9 +19,14 @@ #include "ir/expression.h" namespace panda::es2panda::checker { +class ETSAnalyzer; class Signature; } // namespace panda::es2panda::checker +namespace panda::es2panda::compiler { +class ETSCompiler; +} // namespace panda::es2panda::compiler + namespace panda::es2panda::ir { class ETSNewMultiDimArrayInstanceExpression : public Expression { @@ -33,6 +38,9 @@ public: dimensions_(std::move(dimensions)) { } + // TODO (csabahurton): these friend relationships can be removed once there are getters for private fields + friend class checker::ETSAnalyzer; + friend class compiler::ETSCompiler; checker::Signature *Signature() { @@ -47,10 +55,10 @@ public: void TransformChildren(const NodeTransformer &cb) override; 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([[maybe_unused]] compiler::ETSGen *etsg) const override; - checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + void Compile(compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; + checker::Type *Check(checker::TSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; private: ir::TypeNode *type_reference_; diff --git a/ets2panda/ir/ets/etsPackageDeclaration.cpp b/ets2panda/ir/ets/etsPackageDeclaration.cpp index b31ed8e71ba451b99890227ca2d99567b4091c56..16b7028bd92683506ee62f22d6582388e95fa1e0 100644 --- a/ets2panda/ir/ets/etsPackageDeclaration.cpp +++ b/ets2panda/ir/ets/etsPackageDeclaration.cpp @@ -15,9 +15,10 @@ #include "etsPackageDeclaration.h" -#include "ir/astDump.h" #include "checker/TSchecker.h" #include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" +#include "ir/astDump.h" namespace panda::es2panda::ir { void ETSPackageDeclaration::TransformChildren(const NodeTransformer &cb) @@ -35,19 +36,22 @@ void ETSPackageDeclaration::Dump(ir::AstDumper *dumper) const dumper->Add({{"type", "ETSPackageDeclaration"}, {"name", name_}}); } -void ETSPackageDeclaration::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} -void ETSPackageDeclaration::Compile([[maybe_unused]] compiler::ETSGen *etsg) const +void ETSPackageDeclaration::Compile(compiler::PandaGen *pg) const +{ + pg->GetAstCompiler()->Compile(this); +} +void ETSPackageDeclaration::Compile(compiler::ETSGen *etsg) const { - UNREACHABLE(); + etsg->GetAstCompiler()->Compile(this); } -checker::Type *ETSPackageDeclaration::Check([[maybe_unused]] checker::TSChecker *checker) +checker::Type *ETSPackageDeclaration::Check(checker::TSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } -checker::Type *ETSPackageDeclaration::Check([[maybe_unused]] checker::ETSChecker *checker) +checker::Type *ETSPackageDeclaration::Check(checker::ETSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/ets/etsPackageDeclaration.h b/ets2panda/ir/ets/etsPackageDeclaration.h index 8ca20442d3d93240c979767e8aae6325cd873180..9e53f3bee4a849529f09a93c5803733f421120d0 100644 --- a/ets2panda/ir/ets/etsPackageDeclaration.h +++ b/ets2panda/ir/ets/etsPackageDeclaration.h @@ -29,10 +29,10 @@ public: void TransformChildren(const NodeTransformer &cb) override; 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([[maybe_unused]] compiler::ETSGen *etsg) const override; - checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + void Compile(compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; + checker::Type *Check(checker::TSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; private: ir::Expression *name_; diff --git a/ets2panda/ir/expressions/identifier.cpp b/ets2panda/ir/expressions/identifier.cpp index e1f2b3cd2a574197000bf42a07baec92d04bfec7..6a3754ac71c546d35c5a837e58f0c740b38267b7 100644 --- a/ets2panda/ir/expressions/identifier.cpp +++ b/ets2panda/ir/expressions/identifier.cpp @@ -16,14 +16,10 @@ #include "identifier.h" #include "varbinder/scope.h" +#include "checker/ETSchecker.h" +#include "checker/TSchecker.h" #include "compiler/core/pandagen.h" #include "compiler/core/ETSGen.h" -#include "checker/TSchecker.h" -#include "checker/ETSchecker.h" -#include "ir/astDump.h" -#include "ir/typeNode.h" -#include "ir/base/decorator.h" -#include "ir/expression.h" namespace panda::es2panda::ir { Identifier::Identifier([[maybe_unused]] Tag const tag, Identifier const &other, ArenaAllocator *const allocator) @@ -98,85 +94,21 @@ void Identifier::Dump(ir::AstDumper *dumper) const void Identifier::Compile(compiler::PandaGen *pg) const { - auto res = pg->Scope()->Find(name_); - if (res.variable != nullptr) { - pg->LoadVar(this, res); - return; - } - - if (pg->IsDirectEval()) { - pg->LoadEvalVariable(this, name_); - return; - } - - if (name_.Is("NaN")) { - pg->LoadConst(this, compiler::Constant::JS_NAN); - return; - } - - if (name_.Is("Infinity")) { - pg->LoadConst(this, compiler::Constant::JS_INFINITY); - return; - } - - if (name_.Is("globalThis")) { - pg->LoadConst(this, compiler::Constant::JS_GLOBAL); - return; - } - - if (name_.Is("undefined")) { - pg->LoadConst(this, compiler::Constant::JS_UNDEFINED); - return; - } - - pg->TryLoadGlobalByName(this, name_); + pg->GetAstCompiler()->Compile(this); } void Identifier::Compile(compiler::ETSGen *etsg) const { - auto lambda = etsg->VarBinder()->LambdaObjects().find(this); - if (lambda != etsg->VarBinder()->LambdaObjects().end()) { - etsg->CreateLambdaObjectFromIdentReference(this, lambda->second.first); - return; - } - - auto ttctx = compiler::TargetTypeContext(etsg, TsType()); - - ASSERT(variable_ != nullptr); - if (!variable_->HasFlag(varbinder::VariableFlags::TYPE_ALIAS)) { - etsg->LoadVar(this, variable_); - } else { - etsg->LoadVar(this, TsType()->Variable()); - } + etsg->GetAstCompiler()->Compile(this); } checker::Type *Identifier::Check(checker::TSChecker *checker) { - if (Variable() == nullptr) { - if (name_.Is("undefined")) { - return checker->GlobalUndefinedType(); - } - - checker->ThrowTypeError({"Cannot find name ", name_}, Start()); - } - - const varbinder::Decl *decl = Variable()->Declaration(); - - if (decl->IsTypeAliasDecl() || decl->IsInterfaceDecl()) { - checker->ThrowTypeError({name_, " only refers to a type, but is being used as a value here."}, Start()); - } - - SetTsType(checker->GetTypeOfVariable(Variable())); - return TsType(); + return checker->GetAnalyzer()->Check(this); } checker::Type *Identifier::Check(checker::ETSChecker *checker) { - if (TsType() != nullptr) { - return TsType(); - } - - SetTsType(checker->ResolveIdentifier(this)); - return TsType(); + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/expressions/identifier.h b/ets2panda/ir/expressions/identifier.h index a6ee3dd78ef7aaa4e9400a3bb702c9cd6a3ddc0b..289806701a66905f94d6167acdd1ead2f2da3249 100644 --- a/ets2panda/ir/expressions/identifier.h +++ b/ets2panda/ir/expressions/identifier.h @@ -193,10 +193,10 @@ public: void TransformChildren(const NodeTransformer &cb) override; 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([[maybe_unused]] compiler::ETSGen *etsg) const override; - checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + void Compile(compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; + checker::Type *Check(checker::TSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; private: util::StringView name_; diff --git a/ets2panda/ir/expressions/importExpression.cpp b/ets2panda/ir/expressions/importExpression.cpp index e812123c13e5fbc49ccd6910fa2868d0bbde7c13..1f7c3620722bd09190d40988e4abe2c7a1197fae 100644 --- a/ets2panda/ir/expressions/importExpression.cpp +++ b/ets2panda/ir/expressions/importExpression.cpp @@ -15,8 +15,9 @@ #include "importExpression.h" +#include "checker/TSchecker.h" +#include "compiler/core/ETSGen.h" #include "compiler/core/pandagen.h" -#include "ir/astDump.h" namespace panda::es2panda::ir { void ImportExpression::TransformChildren(const NodeTransformer &cb) @@ -34,19 +35,23 @@ void ImportExpression::Dump(ir::AstDumper *dumper) const dumper->Add({{"type", "ImportExpression"}, {"source", source_}}); } -void ImportExpression::Compile([[maybe_unused]] compiler::PandaGen *pg) const +void ImportExpression::Compile(compiler::PandaGen *pg) const { - pg->Unimplemented(); + pg->GetAstCompiler()->Compile(this); } -checker::Type *ImportExpression::Check([[maybe_unused]] checker::TSChecker *checker) +void ImportExpression::Compile(compiler::ETSGen *etsg) const { - return nullptr; + etsg->GetAstCompiler()->Compile(this); +} +checker::Type *ImportExpression::Check(checker::TSChecker *checker) +{ + return checker->GetAnalyzer()->Check(this); } -checker::Type *ImportExpression::Check([[maybe_unused]] checker::ETSChecker *checker) +checker::Type *ImportExpression::Check(checker::ETSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } // NOLINTNEXTLINE(google-default-arguments) diff --git a/ets2panda/ir/expressions/importExpression.h b/ets2panda/ir/expressions/importExpression.h index d275dd9a9a4e87384f2455bf2f8a0fa934ec7ca4..5d33ba3666cc7475b8e977dbca07bb7b437470d9 100644 --- a/ets2panda/ir/expressions/importExpression.h +++ b/ets2panda/ir/expressions/importExpression.h @@ -35,9 +35,10 @@ public: void TransformChildren(const NodeTransformer &cb) override; void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; - void Compile([[maybe_unused]] compiler::PandaGen *pg) const override; - checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + void Compile(compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; + checker::Type *Check(checker::TSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; private: Expression *source_; diff --git a/ets2panda/ir/expressions/literals/bigIntLiteral.cpp b/ets2panda/ir/expressions/literals/bigIntLiteral.cpp index b59d2f83c9ae771c68c70ca915af97c031505b6d..47e43c721e3bd1818498d435077c549277b788aa 100644 --- a/ets2panda/ir/expressions/literals/bigIntLiteral.cpp +++ b/ets2panda/ir/expressions/literals/bigIntLiteral.cpp @@ -15,8 +15,9 @@ #include "bigIntLiteral.h" -#include "compiler/core/pandagen.h" #include "checker/TSchecker.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" #include "ir/astDump.h" namespace panda::es2panda::ir { @@ -30,24 +31,22 @@ void BigIntLiteral::Dump(ir::AstDumper *dumper) const void BigIntLiteral::Compile(compiler::PandaGen *pg) const { - pg->LoadAccumulatorBigInt(this, src_); + pg->GetAstCompiler()->Compile(this); } -checker::Type *BigIntLiteral::Check(checker::TSChecker *checker) +void BigIntLiteral::Compile(compiler::ETSGen *etsg) const { - auto search = checker->BigintLiteralMap().find(src_); - if (search != checker->BigintLiteralMap().end()) { - return search->second; - } + etsg->GetAstCompiler()->Compile(this); +} - auto *new_bigint_literal_type = checker->Allocator()->New(src_, false); - checker->BigintLiteralMap().insert({src_, new_bigint_literal_type}); - return new_bigint_literal_type; +checker::Type *BigIntLiteral::Check(checker::TSChecker *checker) +{ + return checker->GetAnalyzer()->Check(this); } checker::Type *BigIntLiteral::Check([[maybe_unused]] checker::ETSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } // NOLINTNEXTLINE(google-default-arguments) diff --git a/ets2panda/ir/expressions/literals/bigIntLiteral.h b/ets2panda/ir/expressions/literals/bigIntLiteral.h index a017c4912ac80e3d975aa02b7b965edbae1793a1..a0b72c484fd532be0f758ff14c017e7f74ff800d 100644 --- a/ets2panda/ir/expressions/literals/bigIntLiteral.h +++ b/ets2panda/ir/expressions/literals/bigIntLiteral.h @@ -41,9 +41,10 @@ public: void TransformChildren(const NodeTransformer &cb) override; void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; - void Compile([[maybe_unused]] compiler::PandaGen *pg) const override; - checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + void Compile(compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; + checker::Type *Check(checker::TSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; private: util::StringView const src_; diff --git a/ets2panda/ir/expressions/literals/booleanLiteral.cpp b/ets2panda/ir/expressions/literals/booleanLiteral.cpp index 81fc1cb14718f2c6e99534c32beca2b02f6e38fb..6e66795cdfd9ebd4fb57b1d5ab543ed6ddbebec1 100644 --- a/ets2panda/ir/expressions/literals/booleanLiteral.cpp +++ b/ets2panda/ir/expressions/literals/booleanLiteral.cpp @@ -32,25 +32,22 @@ void BooleanLiteral::Dump(ir::AstDumper *dumper) const void BooleanLiteral::Compile(compiler::PandaGen *pg) const { - pg->LoadConst(this, boolean_ ? compiler::Constant::JS_TRUE : compiler::Constant::JS_FALSE); + pg->GetAstCompiler()->Compile(this); } void BooleanLiteral::Compile(compiler::ETSGen *etsg) const { - etsg->LoadAccumulatorBoolean(this, boolean_); + etsg->GetAstCompiler()->Compile(this); } checker::Type *BooleanLiteral::Check(checker::TSChecker *checker) { - return boolean_ ? checker->GlobalTrueType() : checker->GlobalFalseType(); + return checker->GetAnalyzer()->Check(this); } checker::Type *BooleanLiteral::Check([[maybe_unused]] checker::ETSChecker *checker) { - if (TsType() == nullptr) { - SetTsType(checker->CreateETSBooleanType(boolean_)); - } - return TsType(); + return checker->GetAnalyzer()->Check(this); } // NOLINTNEXTLINE(google-default-arguments) diff --git a/ets2panda/ir/expressions/literals/charLiteral.cpp b/ets2panda/ir/expressions/literals/charLiteral.cpp index 6596de257711f061e06f4395377b7ac1fea59ac0..c3ce97217d338713dbc635b9c6f97ab3e2045ab3 100644 --- a/ets2panda/ir/expressions/literals/charLiteral.cpp +++ b/ets2panda/ir/expressions/literals/charLiteral.cpp @@ -15,6 +15,7 @@ #include "charLiteral.h" +#include "checker/TSchecker.h" #include "compiler/core/pandagen.h" #include "compiler/core/ETSGen.h" #include "checker/ETSchecker.h" @@ -31,24 +32,24 @@ void CharLiteral::Dump(ir::AstDumper *dumper) const dumper->Add({{"type", "CharLiteral"}, {"value", char_}}); } -void CharLiteral::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} +void CharLiteral::Compile([[maybe_unused]] compiler::PandaGen *pg) const +{ + pg->GetAstCompiler()->Compile(this); +} void CharLiteral::Compile([[maybe_unused]] compiler::ETSGen *etsg) const { - etsg->LoadAccumulatorChar(this, char_); + etsg->GetAstCompiler()->Compile(this); } checker::Type *CharLiteral::Check([[maybe_unused]] checker::TSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } checker::Type *CharLiteral::Check([[maybe_unused]] checker::ETSChecker *checker) { - if (TsType() == nullptr) { - SetTsType(checker->Allocator()->New(char_)); - } - return TsType(); + return checker->GetAnalyzer()->Check(this); } // NOLINTNEXTLINE(google-default-arguments) diff --git a/ets2panda/ir/expressions/memberExpression.cpp b/ets2panda/ir/expressions/memberExpression.cpp index 44936411def8039ca48d27983c70f5b50f85269e..f9ad86792100b76cb9a4ebbe871b271219b18749 100644 --- a/ets2panda/ir/expressions/memberExpression.cpp +++ b/ets2panda/ir/expressions/memberExpression.cpp @@ -15,24 +15,9 @@ #include "memberExpression.h" -#include "checker/types/typeRelation.h" #include "compiler/core/pandagen.h" #include "compiler/core/ETSGen.h" -#include "compiler/core/function.h" #include "checker/TSchecker.h" -#include "checker/ETSchecker.h" -#include "checker/types/ets/etsExtensionFuncHelperType.h" -#include "checker/types/ets/etsFunctionType.h" -#include "checker/types/signature.h" -#include "ir/astDump.h" -#include "ir/base/methodDefinition.h" -#include "ir/base/scriptFunction.h" -#include "ir/expressions/callExpression.h" -#include "ir/expressions/identifier.h" -#include "ir/expressions/literals/numberLiteral.h" -#include "ir/expressions/literals/stringLiteral.h" -#include "ir/ts/tsEnumMember.h" -#include "util/helpers.h" namespace panda::es2panda::ir { MemberExpression::MemberExpression([[maybe_unused]] Tag const tag, Expression *const object, Expression *const property) @@ -113,9 +98,7 @@ void MemberExpression::CompileToRegs(compiler::PandaGen *pg, compiler::VReg obje void MemberExpression::Compile(compiler::PandaGen *pg) const { - object_->Compile(pg); - pg->OptionalChainCheck(IsOptional(), compiler::VReg::Invalid()); - LoadRhs(pg); + pg->GetAstCompiler()->Compile(this); } void MemberExpression::CompileToReg(compiler::PandaGen *pg, compiler::VReg obj_reg) const @@ -126,346 +109,19 @@ void MemberExpression::CompileToReg(compiler::PandaGen *pg, compiler::VReg obj_r LoadRhs(pg); } -bool MemberExpression::CompileComputed(compiler::ETSGen *etsg) const -{ - if (computed_) { - auto *const object_type = etsg->Checker()->GetNonNullishType(object_->TsType()); - - auto ottctx = compiler::TargetTypeContext(etsg, object_->TsType()); - etsg->CompileAndCheck(object_); - - auto const load_element = [this, etsg, object_type]() { - compiler::VReg obj_reg = etsg->AllocReg(); - etsg->StoreAccumulator(this, obj_reg); - - etsg->CompileAndCheck(property_); - etsg->ApplyConversion(property_, property_->TsType()); - - auto ttctx = compiler::TargetTypeContext(etsg, OptionalType()); - - if (object_type->IsETSDynamicType()) { - auto lang = object_type->AsETSDynamicType()->Language(); - etsg->LoadElementDynamic(this, obj_reg, lang); - } else { - etsg->LoadArrayElement(this, obj_reg); - } - }; - - etsg->EmitMaybeOptional(this, load_element, IsOptional()); - return true; - } - return false; -} - void MemberExpression::Compile(compiler::ETSGen *etsg) const { - auto lambda = etsg->VarBinder()->LambdaObjects().find(this); - if (lambda != etsg->VarBinder()->LambdaObjects().end()) { - etsg->CreateLambdaObjectFromMemberReference(this, object_, lambda->second.first); - etsg->SetAccumulatorType(TsType()); - return; - } - - compiler::RegScope rs(etsg); - - auto *const object_type = etsg->Checker()->GetNonNullishType(object_->TsType()); - - if (CompileComputed(etsg)) { - return; - } - - auto &prop_name = property_->AsIdentifier()->Name(); - - if (object_type->IsETSArrayType() && prop_name.Is("length")) { - auto ottctx = compiler::TargetTypeContext(etsg, object_type); - etsg->CompileAndCheck(object_); - - auto const load_length = [this, etsg]() { - compiler::VReg obj_reg = etsg->AllocReg(); - etsg->StoreAccumulator(this, obj_reg); - - auto ttctx = compiler::TargetTypeContext(etsg, OptionalType()); - etsg->LoadArrayLength(this, obj_reg); - etsg->ApplyConversion(this, TsType()); - }; - - etsg->EmitMaybeOptional(this, load_length, IsOptional()); - return; - } - - if (object_type->IsETSEnumType() || object_type->IsETSStringEnumType()) { - auto const *const enum_interface = [object_type, this]() -> checker::ETSEnumInterface const * { - if (object_type->IsETSEnumType()) { - return OptionalType()->AsETSEnumType(); - } - return OptionalType()->AsETSStringEnumType(); - }(); - - auto ottctx = compiler::TargetTypeContext(etsg, object_type); - auto ttctx = compiler::TargetTypeContext(etsg, OptionalType()); - etsg->LoadAccumulatorInt(this, enum_interface->GetOrdinal()); - return; - } - - if (etsg->Checker()->IsVariableStatic(prop_var_)) { - auto ttctx = compiler::TargetTypeContext(etsg, OptionalType()); - - if (prop_var_->TsType()->HasTypeFlag(checker::TypeFlag::GETTER_SETTER)) { - checker::Signature *sig = prop_var_->TsType()->AsETSFunctionType()->FindGetter(); - etsg->CallStatic0(this, sig->InternalName()); - etsg->SetAccumulatorType(TsType()); - return; - } - - util::StringView full_name = etsg->FormClassPropReference(object_->TsType()->AsETSObjectType(), prop_name); - etsg->LoadStaticProperty(this, OptionalType(), full_name); - return; - } - - auto ottctx = compiler::TargetTypeContext(etsg, object_->TsType()); - etsg->CompileAndCheck(object_); - - auto const load_property = [this, etsg, prop_name, object_type]() { - etsg->ApplyConversion(object_); - compiler::VReg obj_reg = etsg->AllocReg(); - etsg->StoreAccumulator(this, obj_reg); - - auto ttctx = compiler::TargetTypeContext(etsg, OptionalType()); - - if (prop_var_->TsType()->HasTypeFlag(checker::TypeFlag::GETTER_SETTER)) { - checker::Signature *sig = prop_var_->TsType()->AsETSFunctionType()->FindGetter(); - etsg->CallThisVirtual0(this, obj_reg, sig->InternalName()); - etsg->SetAccumulatorType(TsType()); - } else if (object_type->IsETSDynamicType()) { - auto lang = object_type->AsETSDynamicType()->Language(); - etsg->LoadPropertyDynamic(this, OptionalType(), obj_reg, prop_name, lang); - } else if (object_type->IsETSUnionType()) { - etsg->LoadUnionProperty(this, OptionalType(), obj_reg, prop_name); - } else { - const auto full_name = etsg->FormClassPropReference(object_type->AsETSObjectType(), prop_name); - etsg->LoadProperty(this, OptionalType(), obj_reg, full_name); - } - }; - - etsg->EmitMaybeOptional(this, load_property, IsOptional()); + etsg->GetAstCompiler()->Compile(this); } checker::Type *MemberExpression::Check(checker::TSChecker *checker) { - checker::Type *base_type = checker->CheckNonNullType(object_->Check(checker), object_->Start()); - - if (computed_) { - checker::Type *index_type = property_->Check(checker); - checker::Type *indexed_access_type = checker->GetPropertyTypeForIndexType(base_type, index_type); - - if (indexed_access_type != nullptr) { - return indexed_access_type; - } - - if (!index_type->HasTypeFlag(checker::TypeFlag::STRING_LIKE | checker::TypeFlag::NUMBER_LIKE)) { - checker->ThrowTypeError({"Type ", index_type, " cannot be used as index type"}, property_->Start()); - } - - if (index_type->IsNumberType()) { - checker->ThrowTypeError("No index signature with a parameter of type 'string' was found on type this type", - Start()); - } - - if (index_type->IsStringType()) { - checker->ThrowTypeError("No index signature with a parameter of type 'number' was found on type this type", - Start()); - } - - switch (property_->Type()) { - case ir::AstNodeType::IDENTIFIER: { - checker->ThrowTypeError( - {"Property ", property_->AsIdentifier()->Name(), " does not exist on this type."}, - property_->Start()); - } - case ir::AstNodeType::NUMBER_LITERAL: { - checker->ThrowTypeError( - {"Property ", property_->AsNumberLiteral()->Str(), " does not exist on this type."}, - property_->Start()); - } - case ir::AstNodeType::STRING_LITERAL: { - checker->ThrowTypeError( - {"Property ", property_->AsStringLiteral()->Str(), " does not exist on this type."}, - property_->Start()); - } - default: { - UNREACHABLE(); - } - } - } - - varbinder::Variable *prop = checker->GetPropertyOfType(base_type, property_->AsIdentifier()->Name()); - - if (prop != nullptr) { - checker::Type *prop_type = checker->GetTypeOfVariable(prop); - if (prop->HasFlag(varbinder::VariableFlags::READONLY)) { - prop_type->AddTypeFlag(checker::TypeFlag::READONLY); - } - - return prop_type; - } - - if (base_type->IsObjectType()) { - checker::ObjectType *obj_type = base_type->AsObjectType(); - - if (obj_type->StringIndexInfo() != nullptr) { - checker::Type *index_type = obj_type->StringIndexInfo()->GetType(); - if (obj_type->StringIndexInfo()->Readonly()) { - index_type->AddTypeFlag(checker::TypeFlag::READONLY); - } - - return index_type; - } - } - - checker->ThrowTypeError({"Property ", property_->AsIdentifier()->Name(), " does not exist on this type."}, - property_->Start()); - return nullptr; -} - -std::pair MemberExpression::ResolveEnumMember(checker::ETSChecker *checker, - checker::Type *type) const -{ - auto const *const enum_interface = [type]() -> checker::ETSEnumInterface const * { - if (type->IsETSEnumType()) { - return type->AsETSEnumType(); - } - return type->AsETSStringEnumType(); - }(); - - if (parent_->Type() == ir::AstNodeType::CALL_EXPRESSION && parent_->AsCallExpression()->Callee() == this) { - return {enum_interface->LookupMethod(checker, object_, property_->AsIdentifier()), nullptr}; - } - - auto *const literal_type = enum_interface->LookupConstant(checker, object_, property_->AsIdentifier()); - return {literal_type, literal_type->GetMemberVar()}; -} - -std::pair MemberExpression::ResolveObjectMember( - checker::ETSChecker *checker) const -{ - auto resolve_res = checker->ResolveMemberReference(this, obj_type_); - switch (resolve_res.size()) { - case 1U: { - if (resolve_res[0]->Kind() == checker::ResolvedKind::PROPERTY) { - auto var = resolve_res[0]->Variable()->AsLocalVariable(); - checker->ValidatePropertyAccess(var, obj_type_, property_->Start()); - return {checker->GetTypeOfVariable(var), var}; - } - return {checker->GetTypeOfVariable(resolve_res[0]->Variable()), nullptr}; - } - case 2U: { - // ETSExtensionFuncHelperType(class_method_type, extension_method_type) - auto *resolved_type = checker->CreateETSExtensionFuncHelperType( - checker->GetTypeOfVariable(resolve_res[1]->Variable())->AsETSFunctionType(), - checker->GetTypeOfVariable(resolve_res[0]->Variable())->AsETSFunctionType()); - return {resolved_type, nullptr}; - } - default: { - UNREACHABLE(); - } - } -} - -checker::Type *MemberExpression::CheckUnionMember(checker::ETSChecker *checker, checker::Type *base_type) -{ - auto *const union_type = base_type->AsETSUnionType(); - checker::Type *common_prop_type = nullptr; - auto const add_prop_type = [this, checker, &common_prop_type](checker::Type *member_type) { - if (common_prop_type != nullptr && common_prop_type != member_type) { - checker->ThrowTypeError("Member type must be the same for all union objects.", Start()); - } - common_prop_type = member_type; - }; - for (auto *const type : union_type->ConstituentTypes()) { - if (type->IsETSObjectType()) { - SetObjectType(type->AsETSObjectType()); - add_prop_type(ResolveObjectMember(checker).first); - } else if (type->IsETSEnumType() || base_type->IsETSStringEnumType()) { - add_prop_type(ResolveEnumMember(checker, type).first); - } else { - UNREACHABLE(); - } - } - SetObjectType(union_type->GetLeastUpperBoundType(checker)->AsETSObjectType()); - return common_prop_type; -} - -checker::Type *MemberExpression::AdjustOptional(checker::ETSChecker *checker, checker::Type *type) -{ - SetOptionalType(type); - if (IsOptional() && Object()->TsType()->IsNullishOrNullLike()) { - checker->Relation()->SetNode(this); - type = checker->CreateOptionalResultType(type); - checker->Relation()->SetNode(nullptr); - } - SetTsType(type); - return TsType(); -} - -checker::Type *MemberExpression::CheckComputed(checker::ETSChecker *checker, checker::Type *base_type) -{ - if (!base_type->IsETSArrayType() && !base_type->IsETSDynamicType()) { - checker->ThrowTypeError("Indexed access expression can only be used in array type.", Object()->Start()); - } - checker->ValidateArrayIndex(Property()); - - if (Property()->IsIdentifier()) { - SetPropVar(Property()->AsIdentifier()->Variable()->AsLocalVariable()); - } else if (auto var = Property()->Variable(); (var != nullptr) && var->IsLocalVariable()) { - SetPropVar(var->AsLocalVariable()); - } - - // NOTE: apply capture conversion on this type - if (base_type->IsETSArrayType()) { - return base_type->AsETSArrayType()->ElementType(); - } - - // Dynamic - return checker->GlobalBuiltinDynamicType(base_type->AsETSDynamicType()->Language()); + return checker->GetAnalyzer()->Check(this); } checker::Type *MemberExpression::Check(checker::ETSChecker *checker) { - if (TsType() != nullptr) { - return TsType(); - } - auto *const left_type = object_->Check(checker); - auto *const base_type = IsOptional() ? checker->GetNonNullishType(left_type) : left_type; - if (!IsOptional()) { - checker->CheckNonNullishType(left_type, object_->Start()); - } - - if (computed_) { - return AdjustOptional(checker, CheckComputed(checker, base_type)); - } - - if (base_type->IsETSArrayType() && property_->AsIdentifier()->Name().Is("length")) { - return AdjustOptional(checker, checker->GlobalIntType()); - } - - if (base_type->IsETSObjectType()) { - SetObjectType(base_type->AsETSObjectType()); - auto [res_type, res_var] = ResolveObjectMember(checker); - SetPropVar(res_var); - return AdjustOptional(checker, res_type); - } - - if (base_type->IsETSEnumType() || base_type->IsETSStringEnumType()) { - auto [member_type, member_var] = ResolveEnumMember(checker, base_type); - SetPropVar(member_var); - return AdjustOptional(checker, member_type); - } - - if (base_type->IsETSUnionType()) { - return AdjustOptional(checker, CheckUnionMember(checker, base_type)); - } - - checker->ThrowTypeError({"Cannot access property of non-object or non-enum type"}, object_->Start()); + return checker->GetAnalyzer()->Check(this); } // NOLINTNEXTLINE(google-default-arguments) diff --git a/ets2panda/ir/expressions/memberExpression.h b/ets2panda/ir/expressions/memberExpression.h index 47c172e843045b4e1361a60898a1fbd5630f39b7..308eeb75a2e4dbe779f636f81eaf68497fd0553d 100644 --- a/ets2panda/ir/expressions/memberExpression.h +++ b/ets2panda/ir/expressions/memberExpression.h @@ -21,6 +21,11 @@ #include "ir/expression.h" #include "ir/irnode.h" +namespace panda::es2panda::compiler { +class JSCompiler; +class ETSCompiler; +} // namespace panda::es2panda::compiler + namespace panda::es2panda::checker { class ETSObjectType; } // namespace panda::es2panda::checker @@ -59,6 +64,10 @@ public: explicit MemberExpression(Tag tag, Expression *object, Expression *property); + // TODO (csabahurton): these friend relationships can be removed once there are getters for private fields + friend class compiler::JSCompiler; + friend class compiler::ETSCompiler; + [[nodiscard]] Expression *Object() noexcept { return object_; @@ -153,7 +162,7 @@ public: void CompileToReg(compiler::PandaGen *pg, compiler::VReg obj_reg) const; void CompileToRegs(compiler::PandaGen *pg, compiler::VReg object, compiler::VReg property) const; checker::Type *Check(checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; protected: MemberExpression(MemberExpression const &other) : MaybeOptionalExpression(other) @@ -167,14 +176,6 @@ protected: } private: - std::pair ResolveEnumMember(checker::ETSChecker *checker, - checker::Type *type) const; - std::pair ResolveObjectMember(checker::ETSChecker *checker) const; - - checker::Type *AdjustOptional(checker::ETSChecker *checker, checker::Type *type); - checker::Type *CheckComputed(checker::ETSChecker *checker, checker::Type *base_type); - checker::Type *CheckUnionMember(checker::ETSChecker *checker, checker::Type *base_type); - void LoadRhs(compiler::PandaGen *pg) const; Expression *object_ = nullptr; Expression *property_ = nullptr; diff --git a/ets2panda/ir/expressions/newExpression.cpp b/ets2panda/ir/expressions/newExpression.cpp index 565ba8caa42aac382506643a66d32de7706a6e23..afd01242f22aab6b680c40a9412c6ef91a41662a 100644 --- a/ets2panda/ir/expressions/newExpression.cpp +++ b/ets2panda/ir/expressions/newExpression.cpp @@ -15,12 +15,10 @@ #include "newExpression.h" -#include "util/helpers.h" -#include "compiler/core/pandagen.h" -#include "compiler/core/ETSGen.h" -#include "compiler/core/regScope.h" #include "checker/TSchecker.h" -#include "ir/astDump.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" +#include "util/helpers.h" namespace panda::es2panda::ir { NewExpression::NewExpression([[maybe_unused]] Tag const tag, NewExpression const &other, @@ -73,53 +71,21 @@ void NewExpression::Dump(ir::AstDumper *dumper) const void NewExpression::Compile(compiler::PandaGen *pg) const { - compiler::RegScope rs(pg); - compiler::VReg ctor = pg->AllocReg(); - compiler::VReg new_target = pg->AllocReg(); - - callee_->Compile(pg); - pg->StoreAccumulator(this, ctor); - - // new.Target will be the same as ctor - pg->StoreAccumulator(this, new_target); - - if (!util::Helpers::ContainSpreadElement(arguments_) && - arguments_.size() < compiler::PandaGen::MAX_RANGE_CALL_ARG) { - for (const auto *it : arguments_) { - compiler::VReg arg = pg->AllocReg(); - it->Compile(pg); - pg->StoreAccumulator(this, arg); - } - - pg->NewObject(this, ctor, arguments_.size() + 2U); - } else { - compiler::VReg args_obj = pg->AllocReg(); - - pg->CreateArray(this, arguments_, args_obj); - pg->NewObjSpread(this, ctor, new_target); - } + pg->GetAstCompiler()->Compile(this); } -void NewExpression::Compile([[maybe_unused]] compiler::ETSGen *etsg) const +void NewExpression::Compile(compiler::ETSGen *etsg) const { - UNREACHABLE(); + etsg->GetAstCompiler()->Compile(this); } -checker::Type *NewExpression::Check([[maybe_unused]] checker::TSChecker *checker) +checker::Type *NewExpression::Check(checker::TSChecker *checker) { - checker::Type *callee_type = callee_->Check(checker); - - if (callee_type->IsObjectType()) { - checker::ObjectType *callee_obj = callee_type->AsObjectType(); - return checker->ResolveCallOrNewExpression(callee_obj->ConstructSignatures(), arguments_, Start()); - } - - checker->ThrowTypeError("This expression is not callable.", Start()); - return nullptr; + return checker->GetAnalyzer()->Check(this); } -checker::Type *NewExpression::Check([[maybe_unused]] checker::ETSChecker *checker) +checker::Type *NewExpression::Check(checker::ETSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/expressions/newExpression.h b/ets2panda/ir/expressions/newExpression.h index 2cefd3ce6d746341f26e6e2d26aca857bb0219c0..2183cb9576991af01200bcf18734425d49dd385b 100644 --- a/ets2panda/ir/expressions/newExpression.h +++ b/ets2panda/ir/expressions/newExpression.h @@ -18,6 +18,10 @@ #include "ir/expression.h" +namespace panda::es2panda::checker { +class TSAnalyzer; +} // namespace panda::es2panda::checker + namespace panda::es2panda::ir { class NewExpression : public Expression { private: @@ -34,9 +38,11 @@ public: : Expression(AstNodeType::NEW_EXPRESSION), callee_(callee), arguments_(std::move(arguments)) { } - explicit NewExpression(Tag tag, NewExpression const &other, ArenaAllocator *allocator); + // TODO (csabahurton): friend relationship can be removed once there are getters for private fields + friend class checker::TSAnalyzer; + [[nodiscard]] const Expression *Callee() const noexcept { return callee_; @@ -56,7 +62,7 @@ public: void Compile(compiler::PandaGen *pg) const override; void Compile(compiler::ETSGen *etsg) const override; checker::Type *Check(checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; private: Expression *callee_ = nullptr; diff --git a/ets2panda/ir/expressions/omittedExpression.cpp b/ets2panda/ir/expressions/omittedExpression.cpp index b24ea45bebab63c11dc55a32528f0a71ea030e1e..6b08d81d02c93b1abb2cda91494fcf73b7722d25 100644 --- a/ets2panda/ir/expressions/omittedExpression.cpp +++ b/ets2panda/ir/expressions/omittedExpression.cpp @@ -15,8 +15,10 @@ #include "omittedExpression.h" -#include "ir/astDump.h" #include "checker/TSchecker.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" +// #include "ir/astDump.h" namespace panda::es2panda::ir { void OmittedExpression::TransformChildren([[maybe_unused]] const NodeTransformer &cb) {} @@ -27,16 +29,24 @@ void OmittedExpression::Dump(ir::AstDumper *dumper) const dumper->Add({{"type", "OmittedExpression"}}); } -void OmittedExpression::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} +void OmittedExpression::Compile(compiler::PandaGen *pg) const +{ + pg->GetAstCompiler()->Compile(this); +} + +void OmittedExpression::Compile(compiler::ETSGen *etsg) const +{ + etsg->GetAstCompiler()->Compile(this); +} -checker::Type *OmittedExpression::Check([[maybe_unused]] checker::TSChecker *checker) +checker::Type *OmittedExpression::Check(checker::TSChecker *checker) { - return checker->GlobalUndefinedType(); + return checker->GetAnalyzer()->Check(this); } -checker::Type *OmittedExpression::Check([[maybe_unused]] checker::ETSChecker *checker) +checker::Type *OmittedExpression::Check(checker::ETSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } // NOLINTNEXTLINE(google-default-arguments) diff --git a/ets2panda/ir/expressions/omittedExpression.h b/ets2panda/ir/expressions/omittedExpression.h index ee722bf0c336ee9e36d8d58fc9d017e7f02ca9db..5ff6b4fe99b941493d8c87dab0432308d95105b0 100644 --- a/ets2panda/ir/expressions/omittedExpression.h +++ b/ets2panda/ir/expressions/omittedExpression.h @@ -35,9 +35,10 @@ public: void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; - void Compile([[maybe_unused]] compiler::PandaGen *pg) const override; - checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + void Compile(compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; + checker::Type *Check(checker::TSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; }; } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/expressions/sequenceExpression.cpp b/ets2panda/ir/expressions/sequenceExpression.cpp index cde77a042f784b3d3574295e4c64f03e31ef02f6..edf20e42de20cc8780480a94b5e72ebc7ae43662 100644 --- a/ets2panda/ir/expressions/sequenceExpression.cpp +++ b/ets2panda/ir/expressions/sequenceExpression.cpp @@ -15,8 +15,10 @@ #include "sequenceExpression.h" +#include "checker/ETSchecker.h" #include "checker/TSchecker.h" -#include "ir/astDump.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" namespace panda::es2panda::ir { SequenceExpression::SequenceExpression([[maybe_unused]] Tag const tag, SequenceExpression const &other, @@ -59,35 +61,23 @@ void SequenceExpression::Dump(ir::AstDumper *dumper) const dumper->Add({{"type", "SequenceExpression"}, {"expressions", sequence_}}); } -void SequenceExpression::Compile([[maybe_unused]] compiler::PandaGen *pg) const +void SequenceExpression::Compile(compiler::PandaGen *pg) const { - for (const auto *it : sequence_) { - it->Compile(pg); - } + pg->GetAstCompiler()->Compile(this); } void SequenceExpression::Compile(compiler::ETSGen *etsg) const { - for (const auto *it : sequence_) { - it->Compile(etsg); - } + etsg->GetAstCompiler()->Compile(this); } -checker::Type *SequenceExpression::Check([[maybe_unused]] checker::TSChecker *checker) +checker::Type *SequenceExpression::Check(checker::TSChecker *checker) { - // NOTE: aszilagyi. - return checker->GlobalAnyType(); + return checker->GetAnalyzer()->Check(this); } checker::Type *SequenceExpression::Check(checker::ETSChecker *checker) { - if (TsType() != nullptr) { - return TsType(); - } - - for (auto *it : sequence_) { - it->Check(checker); - } - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/expressions/sequenceExpression.h b/ets2panda/ir/expressions/sequenceExpression.h index 29a1fd2aec43f64f48f98152123afb97c7f8a0d6..50cf4e4a3fc86df599b18b710a9954d99a0e5b7f 100644 --- a/ets2panda/ir/expressions/sequenceExpression.h +++ b/ets2panda/ir/expressions/sequenceExpression.h @@ -53,9 +53,9 @@ public: void TransformChildren(const NodeTransformer &cb) override; 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::PandaGen *pg) const override; void Compile(compiler::ETSGen *etsg) const override; - checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; + checker::Type *Check(checker::TSChecker *checker) override; checker::Type *Check(checker::ETSChecker *checker) override; private: diff --git a/ets2panda/ir/expressions/superExpression.cpp b/ets2panda/ir/expressions/superExpression.cpp index 8858bffbc9e4ff10e2b72a72c26d99b24b8b8f17..234cedbfc15511a5523e2f1551f8eaf7577ff2da 100644 --- a/ets2panda/ir/expressions/superExpression.cpp +++ b/ets2panda/ir/expressions/superExpression.cpp @@ -15,12 +15,11 @@ #include "superExpression.h" -#include "util/helpers.h" -#include "compiler/core/pandagen.h" -#include "compiler/core/ETSGen.h" -#include "checker/TSchecker.h" #include "checker/ETSchecker.h" -#include "ir/astDump.h" +#include "checker/TSchecker.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" +#include "util/helpers.h" namespace panda::es2panda::ir { void SuperExpression::TransformChildren([[maybe_unused]] const NodeTransformer &cb) {} @@ -33,35 +32,22 @@ void SuperExpression::Dump(ir::AstDumper *dumper) const void SuperExpression::Compile(compiler::PandaGen *pg) const { - pg->GetThis(this); - - const ir::ScriptFunction *func = util::Helpers::GetContainingConstructor(this); - - if (func != nullptr) { - pg->ThrowIfSuperNotCorrectCall(this, 0); - } + pg->GetAstCompiler()->Compile(this); } void SuperExpression::Compile(compiler::ETSGen *etsg) const { - etsg->LoadThis(this); // remains as long as we consider super 'super' expression - etsg->SetAccumulatorType(etsg->GetAccumulatorType()->AsETSObjectType()->SuperType()); + etsg->GetAstCompiler()->Compile(this); } checker::Type *SuperExpression::Check(checker::TSChecker *checker) { - // NOTE: aszilagyi. - return checker->GlobalAnyType(); + return checker->GetAnalyzer()->Check(this); } checker::Type *SuperExpression::Check([[maybe_unused]] checker::ETSChecker *checker) { - if (TsType() != nullptr) { - return TsType(); - } - - SetTsType(checker->CheckThisOrSuperAccess(this, checker->Context().ContainingClass()->SuperType(), "super")); - return TsType(); + return checker->GetAnalyzer()->Check(this); } // NOLINTNEXTLINE(google-default-arguments) diff --git a/ets2panda/ir/expressions/superExpression.h b/ets2panda/ir/expressions/superExpression.h index 31b2835975906406105493339f80923749dc2e28..fdbfd9146eea3c536507eaae5d56bd75bb660b27 100644 --- a/ets2panda/ir/expressions/superExpression.h +++ b/ets2panda/ir/expressions/superExpression.h @@ -37,7 +37,7 @@ public: void Compile(compiler::PandaGen *pg) const override; void Compile(compiler::ETSGen *etsg) const override; checker::Type *Check(checker::TSChecker *checker) override; - checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; + checker::Type *Check(checker::ETSChecker *checker) override; private: }; diff --git a/ets2panda/ir/statements/assertStatement.cpp b/ets2panda/ir/statements/assertStatement.cpp index dd22e25631a5e9f0cb58731585230952c9379293..4b09acd2363cb58e067ae6d980f16ba92745b84f 100644 --- a/ets2panda/ir/statements/assertStatement.cpp +++ b/ets2panda/ir/statements/assertStatement.cpp @@ -48,68 +48,23 @@ void AssertStatement::Dump(ir::AstDumper *dumper) const dumper->Add({{"type", "AssertStatement"}, {"test", test_}, {"second", AstDumper::Nullish(second_)}}); } -void AssertStatement::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} - -void AssertStatement::ThrowError(compiler::ETSGen *const etsg) const +void AssertStatement::Compile([[maybe_unused]] compiler::PandaGen *pg) const { - const compiler::RegScope rs(etsg); - - if (second_ != nullptr) { - second_->Compile(etsg); - } else { - etsg->LoadAccumulatorString(this, "Assertion failed."); - } - - const auto message = etsg->AllocReg(); - etsg->StoreAccumulator(this, message); - - const auto assertion_error = etsg->AllocReg(); - etsg->NewObject(this, assertion_error, compiler::Signatures::BUILTIN_ASSERTION_ERROR); - etsg->CallThisStatic1(this, assertion_error, compiler::Signatures::BUILTIN_ASSERTION_ERROR_CTOR, message); - etsg->EmitThrow(this, assertion_error); + pg->GetAstCompiler()->Compile(this); } void AssertStatement::Compile([[maybe_unused]] compiler::ETSGen *etsg) const { - auto res = compiler::Condition::CheckConstantExpr(etsg, test_); - if (res == compiler::Condition::Result::CONST_TRUE) { - return; - } - - if (res == compiler::Condition::Result::CONST_FALSE) { - ThrowError(etsg); - return; - } - - compiler::Label *true_label = etsg->AllocLabel(); - compiler::Label *false_label = etsg->AllocLabel(); - - compiler::Condition::Compile(etsg, test_, false_label); - etsg->JumpTo(this, true_label); - - etsg->SetLabel(this, false_label); - ThrowError(etsg); - - etsg->SetLabel(this, true_label); + etsg->GetAstCompiler()->Compile(this); } checker::Type *AssertStatement::Check([[maybe_unused]] checker::TSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } checker::Type *AssertStatement::Check([[maybe_unused]] checker::ETSChecker *checker) { - checker->CheckTruthinessOfType(test_); - - if (second_ != nullptr) { - auto *msg_type = second_->Check(checker); - - if (!msg_type->IsETSStringType()) { - checker->ThrowTypeError("Assert message must be string", second_->Start()); - } - } - - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/statements/assertStatement.h b/ets2panda/ir/statements/assertStatement.h index e66acedc864197bd635f4c78263cf317a372a0b0..cf7c59ebb03fc40c1298195347151a907e33a551 100644 --- a/ets2panda/ir/statements/assertStatement.h +++ b/ets2panda/ir/statements/assertStatement.h @@ -18,6 +18,10 @@ #include "ir/statement.h" +namespace panda::es2panda::checker { +class ETSAnalyzer; +} // namespace panda::es2panda::checker + namespace panda::es2panda::ir { class Expression; @@ -27,6 +31,8 @@ public: : Statement(AstNodeType::ASSERT_STATEMENT), test_(test), second_(second) { } + // TODO (somas): this friend relationship can be removed once there are getters for private fields + friend class checker::ETSAnalyzer; const Expression *Test() const { @@ -46,9 +52,6 @@ public: checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; -protected: - void ThrowError(compiler::ETSGen *etsg) const; - private: Expression *test_; Expression *second_; diff --git a/ets2panda/ir/statements/blockStatement.cpp b/ets2panda/ir/statements/blockStatement.cpp index 948c0fc83d9bc093bcf44dea5bbd4936efd2ceb9..4bb8908d3267e607162f9dadd5ee17defdd5a595 100644 --- a/ets2panda/ir/statements/blockStatement.cpp +++ b/ets2panda/ir/statements/blockStatement.cpp @@ -16,6 +16,7 @@ #include "blockStatement.h" #include "varbinder/scope.h" +#include "compiler/core/pandagen.h" #include "compiler/core/regScope.h" #include "compiler/core/ETSGen.h" #include "checker/TSchecker.h" @@ -44,46 +45,21 @@ void BlockStatement::Dump(ir::AstDumper *dumper) const void BlockStatement::Compile([[maybe_unused]] compiler::PandaGen *pg) const { - compiler::LocalRegScope lrs(pg, scope_); - - for (const auto *it : statements_) { - it->Compile(pg); - } + pg->GetAstCompiler()->Compile(this); } void BlockStatement::Compile([[maybe_unused]] compiler::ETSGen *etsg) const { - compiler::LocalRegScope lrs(etsg, scope_); - - etsg->CompileStatements(statements_); + etsg->GetAstCompiler()->Compile(this); } checker::Type *BlockStatement::Check([[maybe_unused]] checker::TSChecker *checker) { - checker::ScopeContext scope_ctx(checker, scope_); - - for (auto *it : statements_) { - it->Check(checker); - } - - return nullptr; + return checker->GetAnalyzer()->Check(this); } checker::Type *BlockStatement::Check([[maybe_unused]] checker::ETSChecker *checker) { - checker::ScopeContext scope_ctx(checker, scope_); - - for (auto *it : statements_) { - it->Check(checker); - } - - for (auto [stmt, trailing_block] : trailing_blocks_) { - auto iterator = std::find(statements_.begin(), statements_.end(), stmt); - ASSERT(iterator != statements_.end()); - statements_.insert(iterator + 1, trailing_block); - trailing_block->Check(checker); - } - - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/statements/blockStatement.h b/ets2panda/ir/statements/blockStatement.h index 2716162ef20cc46ff94cf86713ebf9e7c520eabb..86a00ffc80d01086bc4e05833df41a00a6130013 100644 --- a/ets2panda/ir/statements/blockStatement.h +++ b/ets2panda/ir/statements/blockStatement.h @@ -18,6 +18,10 @@ #include "ir/statement.h" +namespace panda::es2panda::checker { +class ETSAnalyzer; +} // namespace panda::es2panda::checker + namespace panda::es2panda::ir { class BlockStatement : public Statement { public: @@ -30,6 +34,9 @@ public: { } + // TODO (somas): this friend relationship can be removed once there are getters for private fields + friend class checker::ETSAnalyzer; + bool IsScopeBearer() const override { return true; diff --git a/ets2panda/ir/statements/breakStatement.cpp b/ets2panda/ir/statements/breakStatement.cpp index 185f261d97272e2ac344cbaaf8ad88688660d1e1..674edc681c0e989196b346678710c8d284341d38 100644 --- a/ets2panda/ir/statements/breakStatement.cpp +++ b/ets2panda/ir/statements/breakStatement.cpp @@ -15,6 +15,7 @@ #include "breakStatement.h" +#include "checker/TSchecker.h" #include "compiler/core/pandagen.h" #include "compiler/core/ETSGen.h" #include "ir/astDump.h" @@ -41,34 +42,23 @@ void BreakStatement::Dump(ir::AstDumper *dumper) const dumper->Add({{"type", "BreakStatement"}, {"label", AstDumper::Nullish(ident_)}}); } -template -void CompileImpl(const BreakStatement *self, [[maybe_unused]] CodeGen *cg) -{ - compiler::Label *target = cg->ControlFlowChangeBreak(self->Ident()); - cg->Branch(self, target); -} - void BreakStatement::Compile([[maybe_unused]] compiler::PandaGen *pg) const { - CompileImpl(this, pg); + pg->GetAstCompiler()->Compile(this); } void BreakStatement::Compile([[maybe_unused]] compiler::ETSGen *etsg) const { - if (etsg->ExtendWithFinalizer(parent_, this)) { - return; - } - CompileImpl(this, etsg); + etsg->GetAstCompiler()->Compile(this); } checker::Type *BreakStatement::Check([[maybe_unused]] checker::TSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } checker::Type *BreakStatement::Check(checker::ETSChecker *checker) { - target_ = checker->FindJumpTarget(Type(), this, ident_); - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/statements/breakStatement.h b/ets2panda/ir/statements/breakStatement.h index e9273960969cb2db367eca55bf3d22aa841a017a..e51f71040d11e53d898057087787f37402efba1c 100644 --- a/ets2panda/ir/statements/breakStatement.h +++ b/ets2panda/ir/statements/breakStatement.h @@ -18,6 +18,14 @@ #include "ir/statement.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 Identifier; @@ -26,6 +34,9 @@ public: explicit BreakStatement() : Statement(AstNodeType::BREAK_STATEMENT) {} explicit BreakStatement(Identifier *ident) : Statement(AstNodeType::BREAK_STATEMENT), ident_(ident) {} + friend checker::ETSAnalyzer; + friend compiler::ETSCompiler; + const Identifier *Ident() const { return ident_; diff --git a/ets2panda/ir/ts/tsConditionalType.cpp b/ets2panda/ir/ts/tsConditionalType.cpp index 175de0652ff92201aaa38c1c0d7e0a05aed3fa8b..dc194f4b9cd1c0cf6687ed3a1fbd2980a9748423 100644 --- a/ets2panda/ir/ts/tsConditionalType.cpp +++ b/ets2panda/ir/ts/tsConditionalType.cpp @@ -15,6 +15,9 @@ #include "tsConditionalType.h" +#include "checker/TSchecker.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" #include "ir/astDump.h" namespace panda::es2panda::ir { @@ -43,11 +46,18 @@ void TSConditionalType::Dump(ir::AstDumper *dumper) const {"falseType", false_type_}}); } -void TSConditionalType::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} +void TSConditionalType::Compile([[maybe_unused]] compiler::PandaGen *pg) const +{ + pg->GetAstCompiler()->Compile(this); +} +void TSConditionalType::Compile(compiler::ETSGen *etsg) const +{ + etsg->GetAstCompiler()->Compile(this); +} checker::Type *TSConditionalType::Check([[maybe_unused]] checker::TSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } checker::Type *TSConditionalType::GetType([[maybe_unused]] checker::TSChecker *checker) @@ -57,6 +67,6 @@ checker::Type *TSConditionalType::GetType([[maybe_unused]] checker::TSChecker *c checker::Type *TSConditionalType::Check([[maybe_unused]] checker::ETSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/ts/tsConditionalType.h b/ets2panda/ir/ts/tsConditionalType.h index d2a26839ea1f37c9a65d12bc02216d786bc4529b..eb19607ef19c6f7af6e8acc6f3458f37b8a579ef 100644 --- a/ets2panda/ir/ts/tsConditionalType.h +++ b/ets2panda/ir/ts/tsConditionalType.h @@ -55,6 +55,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/tsImportType.cpp b/ets2panda/ir/ts/tsImportType.cpp index 6cdc3ba60ccc9f71c4dfd4b5cd79cb4c77545471..316ba0551154e56b010124d5e1fdd61efabd044d 100644 --- a/ets2panda/ir/ts/tsImportType.cpp +++ b/ets2panda/ir/ts/tsImportType.cpp @@ -15,6 +15,9 @@ #include "tsImportType.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" @@ -55,11 +58,19 @@ void TSImportType::Dump(ir::AstDumper *dumper) const {"isTypeOf", is_typeof_}}); } -void TSImportType::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} +void TSImportType::Compile([[maybe_unused]] compiler::PandaGen *pg) const +{ + pg->GetAstCompiler()->Compile(this); +} + +void TSImportType::Compile(compiler::ETSGen *etsg) const +{ + etsg->GetAstCompiler()->Compile(this); +} checker::Type *TSImportType::Check([[maybe_unused]] checker::TSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } checker::Type *TSImportType::GetType([[maybe_unused]] checker::TSChecker *checker) @@ -69,6 +80,6 @@ checker::Type *TSImportType::GetType([[maybe_unused]] checker::TSChecker *checke checker::Type *TSImportType::Check([[maybe_unused]] checker::ETSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/ts/tsImportType.h b/ets2panda/ir/ts/tsImportType.h index 2813e2a83178f566a339e93e735ba06d1763af8c..9f721f2cc0ca86407fa29645f8ca814dc59ed06e 100644 --- a/ets2panda/ir/ts/tsImportType.h +++ b/ets2panda/ir/ts/tsImportType.h @@ -57,6 +57,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/tsInferType.cpp b/ets2panda/ir/ts/tsInferType.cpp index 5c06f1613556beebec0eba10434a272e058b3d0f..d108bb9540087e4571bec027eecfd970346b17c8 100644 --- a/ets2panda/ir/ts/tsInferType.cpp +++ b/ets2panda/ir/ts/tsInferType.cpp @@ -15,6 +15,9 @@ #include "tsInferType.h" +#include "checker/TSchecker.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" #include "ir/astDump.h" #include "ir/ts/tsTypeParameter.h" @@ -34,11 +37,18 @@ void TSInferType::Dump(ir::AstDumper *dumper) const dumper->Add({{"type", "TSInferType"}, {"typeParameter", type_param_}}); } -void TSInferType::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} +void TSInferType::Compile([[maybe_unused]] compiler::PandaGen *pg) const +{ + pg->GetAstCompiler()->Compile(this); +} +void TSInferType::Compile(compiler::ETSGen *etsg) const +{ + etsg->GetAstCompiler()->Compile(this); +} checker::Type *TSInferType::Check([[maybe_unused]] checker::TSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } checker::Type *TSInferType::GetType([[maybe_unused]] checker::TSChecker *checker) @@ -48,6 +58,6 @@ checker::Type *TSInferType::GetType([[maybe_unused]] checker::TSChecker *checker checker::Type *TSInferType::Check([[maybe_unused]] checker::ETSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/ts/tsInferType.h b/ets2panda/ir/ts/tsInferType.h index 5d62c9776c69c87527c9f9809754817341d5cf0d..c06cb053c531172f4cb3cdac12f5bba46019fa96 100644 --- a/ets2panda/ir/ts/tsInferType.h +++ b/ets2panda/ir/ts/tsInferType.h @@ -34,6 +34,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/tsIntersectionType.cpp b/ets2panda/ir/ts/tsIntersectionType.cpp index 2e96dbb3fffee08d5a902213a6c4c311b662543d..a25efa4371b2611fea732dc37e1ce2dd278bf8c0 100644 --- a/ets2panda/ir/ts/tsIntersectionType.cpp +++ b/ets2panda/ir/ts/tsIntersectionType.cpp @@ -15,6 +15,9 @@ #include "tsIntersectionType.h" +#include "checker/TSchecker.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" #include "ir/astDump.h" #include "checker/ETSchecker.h" @@ -38,11 +41,18 @@ void TSIntersectionType::Dump(ir::AstDumper *dumper) const dumper->Add({{"type", "TSIntersectionType"}, {"types", types_}}); } -void TSIntersectionType::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} +void TSIntersectionType::Compile([[maybe_unused]] compiler::PandaGen *pg) const +{ + pg->GetAstCompiler()->Compile(this); +} +void TSIntersectionType::Compile(compiler::ETSGen *etsg) const +{ + etsg->GetAstCompiler()->Compile(this); +} checker::Type *TSIntersectionType::Check([[maybe_unused]] checker::TSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } checker::Type *TSIntersectionType::GetType([[maybe_unused]] checker::TSChecker *checker) @@ -58,6 +68,6 @@ checker::Type *TSIntersectionType::GetType([[maybe_unused]] checker::ETSChecker checker::Type *TSIntersectionType::Check([[maybe_unused]] checker::ETSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/ts/tsIntersectionType.h b/ets2panda/ir/ts/tsIntersectionType.h index 7ed628faa41db80069289bf66613f79a967e215c..70556f32db9e400242b432646fd04762bd23d6ce 100644 --- a/ets2panda/ir/ts/tsIntersectionType.h +++ b/ets2panda/ir/ts/tsIntersectionType.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 *GetType([[maybe_unused]] checker::TSChecker *checker) override; checker::Type *GetType([[maybe_unused]] checker::ETSChecker *checker) override; diff --git a/ets2panda/ir/ts/tsMappedType.cpp b/ets2panda/ir/ts/tsMappedType.cpp index bc7946d3f40fd0bd8e3b493254ea84c7afdb7e7c..cb9c54072d10beec131d13ad3906b1f410c81ad8 100644 --- a/ets2panda/ir/ts/tsMappedType.cpp +++ b/ets2panda/ir/ts/tsMappedType.cpp @@ -15,6 +15,9 @@ #include "tsMappedType.h" +#include "checker/TSchecker.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" #include "ir/astDump.h" #include "ir/typeNode.h" #include "ir/ts/tsTypeParameter.h" @@ -49,11 +52,18 @@ void TSMappedType::Dump(ir::AstDumper *dumper) const : AstDumper::Optional("-")}}); } -void TSMappedType::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} +void TSMappedType::Compile([[maybe_unused]] compiler::PandaGen *pg) const +{ + pg->GetAstCompiler()->Compile(this); +} +void TSMappedType::Compile(compiler::ETSGen *etsg) const +{ + etsg->GetAstCompiler()->Compile(this); +} checker::Type *TSMappedType::Check([[maybe_unused]] checker::TSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } checker::Type *TSMappedType::GetType([[maybe_unused]] checker::TSChecker *checker) @@ -63,6 +73,6 @@ checker::Type *TSMappedType::GetType([[maybe_unused]] checker::TSChecker *checke checker::Type *TSMappedType::Check([[maybe_unused]] checker::ETSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/ts/tsMappedType.h b/ets2panda/ir/ts/tsMappedType.h index c2fe678170a84aa44e7233cf74eb2eaa2cee5430..33a22120f1fa5a47a054c792f7fa899cfe203ab5 100644 --- a/ets2panda/ir/ts/tsMappedType.h +++ b/ets2panda/ir/ts/tsMappedType.h @@ -56,6 +56,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/tsModuleBlock.cpp b/ets2panda/ir/ts/tsModuleBlock.cpp index 9c7b5a802983ce8b999ff0ffc33be970ed2f08aa..1b3443a72c8b68448e704a76dfe84cfdc75561fd 100644 --- a/ets2panda/ir/ts/tsModuleBlock.cpp +++ b/ets2panda/ir/ts/tsModuleBlock.cpp @@ -16,6 +16,9 @@ #include "tsModuleBlock.h" #include "varbinder/scope.h" +#include "checker/TSchecker.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" #include "ir/astDump.h" namespace panda::es2panda::ir { @@ -38,15 +41,22 @@ void TSModuleBlock::Dump(ir::AstDumper *dumper) const dumper->Add({{"type", "TSModuleBlock"}, {"body", statements_}}); } -void TSModuleBlock::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} +void TSModuleBlock::Compile([[maybe_unused]] compiler::PandaGen *pg) const +{ + pg->GetAstCompiler()->Compile(this); +} +void TSModuleBlock::Compile(compiler::ETSGen *etsg) const +{ + etsg->GetAstCompiler()->Compile(this); +} checker::Type *TSModuleBlock::Check([[maybe_unused]] checker::TSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } checker::Type *TSModuleBlock::Check([[maybe_unused]] checker::ETSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/ts/tsModuleBlock.h b/ets2panda/ir/ts/tsModuleBlock.h index 8154d30a82e187972d685df1cd8462ad02202d24..64c1479c7df8ea488d4896308e50a846449b0814 100644 --- a/ets2panda/ir/ts/tsModuleBlock.h +++ b/ets2panda/ir/ts/tsModuleBlock.h @@ -46,6 +46,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/tsNullKeyword.cpp b/ets2panda/ir/ts/tsNullKeyword.cpp index 49f02916f8439c5dcccab44cab1e9458e6c0f876..1ecd8382424dbc59c457fbed877881178e5524a4 100644 --- a/ets2panda/ir/ts/tsNullKeyword.cpp +++ b/ets2panda/ir/ts/tsNullKeyword.cpp @@ -15,6 +15,8 @@ #include "tsNullKeyword.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" #include "ir/astDump.h" #include "checker/TSchecker.h" @@ -27,11 +29,18 @@ void TSNullKeyword::Dump(ir::AstDumper *dumper) const dumper->Add({{"type", "TSNullKeyword"}}); } -void TSNullKeyword::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} +void TSNullKeyword::Compile([[maybe_unused]] compiler::PandaGen *pg) const +{ + pg->GetAstCompiler()->Compile(this); +} +void TSNullKeyword::Compile(compiler::ETSGen *etsg) const +{ + etsg->GetAstCompiler()->Compile(this); +} checker::Type *TSNullKeyword::Check([[maybe_unused]] checker::TSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } checker::Type *TSNullKeyword::GetType([[maybe_unused]] checker::TSChecker *checker) @@ -41,6 +50,6 @@ checker::Type *TSNullKeyword::GetType([[maybe_unused]] checker::TSChecker *check checker::Type *TSNullKeyword::Check([[maybe_unused]] checker::ETSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/ts/tsNullKeyword.h b/ets2panda/ir/ts/tsNullKeyword.h index a443f194ed8276988fec7ef7d5892453b22f93d6..a53935ce169c56689fcd19340ad1a8e2cf0be5d1 100644 --- a/ets2panda/ir/ts/tsNullKeyword.h +++ b/ets2panda/ir/ts/tsNullKeyword.h @@ -27,6 +27,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/tsThisType.cpp b/ets2panda/ir/ts/tsThisType.cpp index 445cf9b41fead0940e374ff2049be6f713bfe537..9827778d624a63a5faa7d69a5a3b5240ec7b3dba 100644 --- a/ets2panda/ir/ts/tsThisType.cpp +++ b/ets2panda/ir/ts/tsThisType.cpp @@ -15,6 +15,9 @@ #include "tsThisType.h" +#include "checker/TSchecker.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" #include "ir/astDump.h" namespace panda::es2panda::ir { @@ -26,11 +29,18 @@ void TSThisType::Dump(ir::AstDumper *dumper) const dumper->Add({{"type", "TSThisType"}}); } -void TSThisType::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} +void TSThisType::Compile([[maybe_unused]] compiler::PandaGen *pg) const +{ + pg->GetAstCompiler()->Compile(this); +} +void TSThisType::Compile(compiler::ETSGen *etsg) const +{ + etsg->GetAstCompiler()->Compile(this); +} checker::Type *TSThisType::Check([[maybe_unused]] checker::TSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } checker::Type *TSThisType::GetType([[maybe_unused]] checker::TSChecker *checker) @@ -40,6 +50,6 @@ checker::Type *TSThisType::GetType([[maybe_unused]] checker::TSChecker *checker) checker::Type *TSThisType::Check([[maybe_unused]] checker::ETSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/ts/tsThisType.h b/ets2panda/ir/ts/tsThisType.h index 0cbf2359b8ebfd1b9aaa3f358789b7ed6c662d39..d501237363dd12390bb5f5693450942f3e1df7c7 100644 --- a/ets2panda/ir/ts/tsThisType.h +++ b/ets2panda/ir/ts/tsThisType.h @@ -27,6 +27,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;