From 9ba6c9c018e2058a755f72a5280ce62120ab2ca5 Mon Sep 17 00:00:00 2001 From: Vivien Voros Date: Wed, 18 Oct 2023 15:31:48 +0200 Subject: [PATCH] Compile logic is moved to JSCompiler and ETSCompiler classes. Check logic with their helper functions is moved to TSAnalyzer and ETSAnalyzer classes. TSInterfaceDeclaration, TSIndexedAccessType, TSQualifiedName, TSTypeReference, TSTypeAliasDeclaration, TSConstructorType, TSFunctionType, TSImportEqualsDeclaration Linked Internal issue: 13840 Change-Id: Ida6173218899a7e034c03b799e0946d0fa06b6d5 Signed-off-by: Vivien Voros --- ets2panda/checker/ETSAnalyzer.cpp | 65 +++++--- ets2panda/checker/TSAnalyzer.cpp | 154 ++++++++++++++++-- ets2panda/compiler/core/ETSCompiler.cpp | 25 +-- ets2panda/compiler/core/JSCompiler.cpp | 24 +-- ets2panda/ir/ts/tsConstructorType.cpp | 23 +-- ets2panda/ir/ts/tsConstructorType.h | 6 + ets2panda/ir/ts/tsFunctionType.cpp | 23 +-- ets2panda/ir/ts/tsFunctionType.h | 7 +- ets2panda/ir/ts/tsImportEqualsDeclaration.cpp | 16 +- ets2panda/ir/ts/tsImportEqualsDeclaration.h | 1 + ets2panda/ir/ts/tsIndexedAccessType.cpp | 34 ++-- ets2panda/ir/ts/tsIndexedAccessType.h | 7 + ets2panda/ir/ts/tsInterfaceDeclaration.cpp | 94 ++--------- ets2panda/ir/ts/tsInterfaceDeclaration.h | 1 + ets2panda/ir/ts/tsQualifiedName.cpp | 41 ++--- ets2panda/ir/ts/tsQualifiedName.h | 1 + ets2panda/ir/ts/tsTypeAliasDeclaration.cpp | 18 +- ets2panda/ir/ts/tsTypeAliasDeclaration.h | 1 + ets2panda/ir/ts/tsTypeReference.cpp | 16 +- ets2panda/ir/ts/tsTypeReference.h | 1 + 20 files changed, 313 insertions(+), 245 deletions(-) diff --git a/ets2panda/checker/ETSAnalyzer.cpp b/ets2panda/checker/ETSAnalyzer.cpp index ec729cf229..d334ddfbaf 100644 --- a/ets2panda/checker/ETSAnalyzer.cpp +++ b/ets2panda/checker/ETSAnalyzer.cpp @@ -20,16 +20,7 @@ #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 { ETSChecker *ETSAnalyzer::GetETSChecker() const @@ -991,9 +982,8 @@ checker::Type *ETSAnalyzer::Check(ir::TSConditionalType *node) const UNREACHABLE(); } -checker::Type *ETSAnalyzer::Check(ir::TSConstructorType *node) const +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSConstructorType *node) const { - (void)node; UNREACHABLE(); } @@ -1015,15 +1005,13 @@ checker::Type *ETSAnalyzer::Check(ir::TSExternalModuleReference *expr) const UNREACHABLE(); } -checker::Type *ETSAnalyzer::Check(ir::TSFunctionType *node) const +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSFunctionType *node) const { - (void)node; UNREACHABLE(); } -checker::Type *ETSAnalyzer::Check(ir::TSImportEqualsDeclaration *st) const +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSImportEqualsDeclaration *st) const { - (void)st; UNREACHABLE(); } @@ -1033,9 +1021,8 @@ checker::Type *ETSAnalyzer::Check(ir::TSImportType *node) const UNREACHABLE(); } -checker::Type *ETSAnalyzer::Check(ir::TSIndexedAccessType *node) const +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSIndexedAccessType *node) const { - (void)node; UNREACHABLE(); } @@ -1053,8 +1040,26 @@ checker::Type *ETSAnalyzer::Check(ir::TSInterfaceBody *expr) const checker::Type *ETSAnalyzer::Check(ir::TSInterfaceDeclaration *st) const { - (void)st; - UNREACHABLE(); + ETSChecker *checker = GetETSChecker(); + + checker::ETSObjectType *interface_type {}; + + if (st->TsType() == nullptr) { + interface_type = checker->BuildInterfaceProperties(st); + ASSERT(interface_type != nullptr); + interface_type->SetSuperType(checker->GlobalETSObjectType()); + checker->CheckInvokeMethodsLegitimacy(interface_type); + st->SetTsType(interface_type); + } + + checker::ScopeContext scope_ctx(checker, st->Scope()); + auto saved_context = checker::SavedCheckerContext(checker, checker::CheckerStatus::IN_INTERFACE, interface_type); + + for (auto *it : st->Body()->Body()) { + it->Check(checker); + } + + return nullptr; } checker::Type *ETSAnalyzer::Check(ir::TSInterfaceHeritage *expr) const @@ -1143,8 +1148,18 @@ checker::Type *ETSAnalyzer::Check(ir::TSParenthesizedType *node) const checker::Type *ETSAnalyzer::Check(ir::TSQualifiedName *expr) const { - (void)expr; - UNREACHABLE(); + ETSChecker *checker = GetETSChecker(); + checker::Type *base_type = expr->Left()->Check(checker); + if (base_type->IsETSObjectType()) { + varbinder::Variable *prop = + base_type->AsETSObjectType()->GetProperty(expr->Right()->Name(), checker::PropertySearchFlags::SEARCH_DECL); + + if (prop != nullptr) { + return checker->GetTypeOfVariable(prop); + } + } + + checker->ThrowTypeError({"'", expr->Right()->Name(), "' type does not exist."}, expr->Right()->Start()); } checker::Type *ETSAnalyzer::Check(ir::TSStringKeyword *node) const @@ -1167,8 +1182,9 @@ checker::Type *ETSAnalyzer::Check(ir::TSTupleType *node) const checker::Type *ETSAnalyzer::Check(ir::TSTypeAliasDeclaration *st) const { - (void)st; - UNREACHABLE(); + ETSChecker *checker = GetETSChecker(); + st->TypeAnnotation()->Check(checker); + return nullptr; } checker::Type *ETSAnalyzer::Check(ir::TSTypeAssertion *expr) const @@ -1219,9 +1235,8 @@ checker::Type *ETSAnalyzer::Check(ir::TSTypeQuery *node) const UNREACHABLE(); } -checker::Type *ETSAnalyzer::Check(ir::TSTypeReference *node) const +checker::Type *ETSAnalyzer::Check([[maybe_unused]] ir::TSTypeReference *node) const { - (void)node; UNREACHABLE(); } diff --git a/ets2panda/checker/TSAnalyzer.cpp b/ets2panda/checker/TSAnalyzer.cpp index d3e96e821f..49cf14c4e3 100644 --- a/ets2panda/checker/TSAnalyzer.cpp +++ b/ets2panda/checker/TSAnalyzer.cpp @@ -18,7 +18,6 @@ #include "checker/TSchecker.h" #include "checker/ts/destructuringContext.h" #include "util/helpers.h" - namespace panda::es2panda::checker { TSChecker *TSAnalyzer::GetTSChecker() const @@ -709,8 +708,16 @@ checker::Type *TSAnalyzer::Check(ir::TSConditionalType *node) const checker::Type *TSAnalyzer::Check(ir::TSConstructorType *node) const { - (void)node; - UNREACHABLE(); + TSChecker *checker = GetTSChecker(); + checker::ScopeContext scope_ctx(checker, node->Scope()); + + auto *signature_info = checker->Allocator()->New(checker->Allocator()); + checker->CheckFunctionParameterDeclarations(node->Params(), signature_info); + node->return_type_->Check(checker); + auto *construct_signature = + checker->Allocator()->New(signature_info, node->return_type_->GetType(checker)); + + return checker->CreateConstructorTypeWithSignature(construct_signature); } checker::Type *TSAnalyzer::Check(ir::TSEnumDeclaration *st) const @@ -733,13 +740,20 @@ checker::Type *TSAnalyzer::Check(ir::TSExternalModuleReference *expr) const checker::Type *TSAnalyzer::Check(ir::TSFunctionType *node) const { - (void)node; - UNREACHABLE(); + TSChecker *checker = GetTSChecker(); + checker::ScopeContext scope_ctx(checker, node->Scope()); + + auto *signature_info = checker->Allocator()->New(checker->Allocator()); + checker->CheckFunctionParameterDeclarations(node->Params(), signature_info); + node->return_type_->Check(checker); + auto *call_signature = + checker->Allocator()->New(signature_info, node->return_type_->GetType(checker)); + + return checker->CreateFunctionTypeWithSignature(call_signature); } -checker::Type *TSAnalyzer::Check(ir::TSImportEqualsDeclaration *st) const +checker::Type *TSAnalyzer::Check([[maybe_unused]] ir::TSImportEqualsDeclaration *st) const { - (void)st; UNREACHABLE(); } @@ -751,8 +765,27 @@ checker::Type *TSAnalyzer::Check(ir::TSImportType *node) const checker::Type *TSAnalyzer::Check(ir::TSIndexedAccessType *node) const { - (void)node; - UNREACHABLE(); + TSChecker *checker = GetTSChecker(); + node->object_type_->Check(checker); + node->index_type_->Check(checker); + checker::Type *resolved = node->GetType(checker); + + if (resolved != nullptr) { + return nullptr; + } + + checker::Type *index_type = checker->CheckTypeCached(node->index_type_); + + if (!index_type->HasTypeFlag(checker::TypeFlag::STRING_LIKE | checker::TypeFlag::NUMBER_LIKE)) { + checker->ThrowTypeError({"Type ", index_type, " cannot be used as index type"}, node->IndexType()->Start()); + } + + if (index_type->IsNumberType()) { + checker->ThrowTypeError("Type has no matching signature for type 'number'", node->Start()); + } + + checker->ThrowTypeError("Type has no matching signature for type 'string'", node->Start()); + return nullptr; } checker::Type *TSAnalyzer::Check(ir::TSInferType *node) const @@ -767,10 +800,78 @@ checker::Type *TSAnalyzer::Check(ir::TSInterfaceBody *expr) const UNREACHABLE(); } +static void CheckInheritedPropertiesAreIdentical(checker::TSChecker *checker, checker::InterfaceType *type, + const lexer::SourcePosition &loc_info) +{ + checker->GetBaseTypes(type); + + size_t constexpr BASE_SIZE_LIMIT = 2; + if (type->Bases().size() < BASE_SIZE_LIMIT) { + return; + } + + checker->ResolveDeclaredMembers(type); + + checker::InterfacePropertyMap properties; + + for (auto *it : type->Properties()) { + properties.insert({it->Name(), {it, type}}); + } + + for (auto *base : type->Bases()) { + checker->ResolveStructuredTypeMembers(base); + ArenaVector inherited_properties(checker->Allocator()->Adapter()); + base->AsInterfaceType()->CollectProperties(&inherited_properties); + + for (auto *inherited_prop : inherited_properties) { + auto res = properties.find(inherited_prop->Name()); + if (res == properties.end()) { + properties.insert({inherited_prop->Name(), {inherited_prop, base->AsInterfaceType()}}); + } else if (res->second.second != type) { + checker::Type *source_type = checker->GetTypeOfVariable(inherited_prop); + checker::Type *target_type = checker->GetTypeOfVariable(res->second.first); + checker->IsTypeIdenticalTo(source_type, target_type, + {"Interface '", type, "' cannot simultaneously extend types '", + res->second.second, "' and '", base->AsInterfaceType(), "'."}, + loc_info); + } + } + } +} + checker::Type *TSAnalyzer::Check(ir::TSInterfaceDeclaration *st) const { - (void)st; - UNREACHABLE(); + TSChecker *checker = GetTSChecker(); + varbinder::Variable *var = st->Id()->Variable(); + ASSERT(var->Declaration()->Node() && var->Declaration()->Node()->IsTSInterfaceDeclaration()); + + if (st == var->Declaration()->Node()) { + checker::Type *resolved_type = var->TsType(); + + if (resolved_type == nullptr) { + checker::ObjectDescriptor *desc = + checker->Allocator()->New(checker->Allocator()); + resolved_type = + checker->Allocator()->New(checker->Allocator(), st->Id()->Name(), desc); + resolved_type->SetVariable(var); + var->SetTsType(resolved_type); + } + + checker::InterfaceType *resolved_interface = resolved_type->AsObjectType()->AsInterfaceType(); + CheckInheritedPropertiesAreIdentical(checker, resolved_interface, st->Id()->Start()); + + for (auto *base : resolved_interface->Bases()) { + checker->IsTypeAssignableTo( + resolved_interface, base, + {"Interface '", st->Id()->Name(), "' incorrectly extends interface '", base, "'"}, st->Id()->Start()); + } + + checker->CheckIndexConstraints(resolved_interface); + } + + st->Body()->Check(checker); + + return nullptr; } checker::Type *TSAnalyzer::Check(ir::TSInterfaceHeritage *expr) const @@ -859,8 +960,25 @@ checker::Type *TSAnalyzer::Check(ir::TSParenthesizedType *node) const checker::Type *TSAnalyzer::Check(ir::TSQualifiedName *expr) const { - (void)expr; - UNREACHABLE(); + TSChecker *checker = GetTSChecker(); + checker::Type *base_type = checker->CheckNonNullType(expr->Left()->Check(checker), expr->Left()->Start()); + varbinder::Variable *prop = checker->GetPropertyOfType(base_type, expr->Right()->Name()); + + if (prop != nullptr) { + return checker->GetTypeOfVariable(prop); + } + + if (base_type->IsObjectType()) { + checker::ObjectType *obj_type = base_type->AsObjectType(); + + if (obj_type->StringIndexInfo() != nullptr) { + return obj_type->StringIndexInfo()->GetType(); + } + } + + checker->ThrowTypeError({"Property ", expr->Right()->Name(), " does not exist on this type."}, + expr->Right()->Start()); + return nullptr; } checker::Type *TSAnalyzer::Check(ir::TSStringKeyword *node) const @@ -883,8 +1001,9 @@ checker::Type *TSAnalyzer::Check(ir::TSTupleType *node) const checker::Type *TSAnalyzer::Check(ir::TSTypeAliasDeclaration *st) const { - (void)st; - UNREACHABLE(); + TSChecker *checker = GetTSChecker(); + st->TypeAnnotation()->Check(checker); + return nullptr; } checker::Type *TSAnalyzer::Check(ir::TSTypeAssertion *expr) const @@ -937,8 +1056,9 @@ checker::Type *TSAnalyzer::Check(ir::TSTypeQuery *node) const checker::Type *TSAnalyzer::Check(ir::TSTypeReference *node) const { - (void)node; - UNREACHABLE(); + TSChecker *checker = GetTSChecker(); + node->GetType(checker); + return nullptr; } checker::Type *TSAnalyzer::Check(ir::TSUndefinedKeyword *node) const diff --git a/ets2panda/compiler/core/ETSCompiler.cpp b/ets2panda/compiler/core/ETSCompiler.cpp index 46dd096ae8..114ea4212e 100644 --- a/ets2panda/compiler/core/ETSCompiler.cpp +++ b/ets2panda/compiler/core/ETSCompiler.cpp @@ -20,7 +20,6 @@ #include "compiler/base/lreference.h" #include "compiler/core/ETSGen.h" #include "compiler/function/functionBuilder.h" - namespace panda::es2panda::compiler { ETSGen *ETSCompiler::GetETSGen() const @@ -720,9 +719,8 @@ void ETSCompiler::Compile(const ir::TSConditionalType *node) const UNREACHABLE(); } -void ETSCompiler::Compile(const ir::TSConstructorType *node) const +void ETSCompiler::Compile([[maybe_unused]] const ir::TSConstructorType *node) const { - (void)node; UNREACHABLE(); } @@ -744,15 +742,13 @@ void ETSCompiler::Compile(const ir::TSExternalModuleReference *expr) const UNREACHABLE(); } -void ETSCompiler::Compile(const ir::TSFunctionType *node) const +void ETSCompiler::Compile([[maybe_unused]] const ir::TSFunctionType *node) const { - (void)node; UNREACHABLE(); } -void ETSCompiler::Compile(const ir::TSImportEqualsDeclaration *st) const +void ETSCompiler::Compile([[maybe_unused]] const ir::TSImportEqualsDeclaration *st) const { - (void)st; UNREACHABLE(); } @@ -762,9 +758,8 @@ void ETSCompiler::Compile(const ir::TSImportType *node) const UNREACHABLE(); } -void ETSCompiler::Compile(const ir::TSIndexedAccessType *node) const +void ETSCompiler::Compile([[maybe_unused]] const ir::TSIndexedAccessType *node) const { - (void)node; UNREACHABLE(); } @@ -780,9 +775,8 @@ void ETSCompiler::Compile(const ir::TSInterfaceBody *expr) const UNREACHABLE(); } -void ETSCompiler::Compile(const ir::TSInterfaceDeclaration *st) const +void ETSCompiler::Compile([[maybe_unused]] const ir::TSInterfaceDeclaration *st) const { - (void)st; UNREACHABLE(); } @@ -870,9 +864,8 @@ void ETSCompiler::Compile(const ir::TSParenthesizedType *node) const UNREACHABLE(); } -void ETSCompiler::Compile(const ir::TSQualifiedName *expr) const +void ETSCompiler::Compile([[maybe_unused]] const ir::TSQualifiedName *expr) const { - (void)expr; UNREACHABLE(); } @@ -894,9 +887,8 @@ void ETSCompiler::Compile(const ir::TSTupleType *node) const UNREACHABLE(); } -void ETSCompiler::Compile(const ir::TSTypeAliasDeclaration *st) const +void ETSCompiler::Compile([[maybe_unused]] const ir::TSTypeAliasDeclaration *st) const { - (void)st; UNREACHABLE(); } @@ -948,9 +940,8 @@ void ETSCompiler::Compile(const ir::TSTypeQuery *node) const UNREACHABLE(); } -void ETSCompiler::Compile(const ir::TSTypeReference *node) const +void ETSCompiler::Compile([[maybe_unused]] const ir::TSTypeReference *node) const { - (void)node; UNREACHABLE(); } diff --git a/ets2panda/compiler/core/JSCompiler.cpp b/ets2panda/compiler/core/JSCompiler.cpp index 10a894d364..62eba33481 100644 --- a/ets2panda/compiler/core/JSCompiler.cpp +++ b/ets2panda/compiler/core/JSCompiler.cpp @@ -1005,9 +1005,8 @@ void JSCompiler::Compile(const ir::TSConditionalType *node) const UNREACHABLE(); } -void JSCompiler::Compile(const ir::TSConstructorType *node) const +void JSCompiler::Compile([[maybe_unused]] const ir::TSConstructorType *node) const { - (void)node; UNREACHABLE(); } @@ -1029,15 +1028,13 @@ void JSCompiler::Compile(const ir::TSExternalModuleReference *expr) const UNREACHABLE(); } -void JSCompiler::Compile(const ir::TSFunctionType *node) const +void JSCompiler::Compile([[maybe_unused]] const ir::TSFunctionType *node) const { - (void)node; UNREACHABLE(); } -void JSCompiler::Compile(const ir::TSImportEqualsDeclaration *st) const +void JSCompiler::Compile([[maybe_unused]] const ir::TSImportEqualsDeclaration *st) const { - (void)st; UNREACHABLE(); } @@ -1047,9 +1044,8 @@ void JSCompiler::Compile(const ir::TSImportType *node) const UNREACHABLE(); } -void JSCompiler::Compile(const ir::TSIndexedAccessType *node) const +void JSCompiler::Compile([[maybe_unused]] const ir::TSIndexedAccessType *node) const { - (void)node; UNREACHABLE(); } @@ -1065,9 +1061,8 @@ void JSCompiler::Compile(const ir::TSInterfaceBody *expr) const UNREACHABLE(); } -void JSCompiler::Compile(const ir::TSInterfaceDeclaration *st) const +void JSCompiler::Compile([[maybe_unused]] const ir::TSInterfaceDeclaration *st) const { - (void)st; UNREACHABLE(); } @@ -1155,9 +1150,8 @@ void JSCompiler::Compile(const ir::TSParenthesizedType *node) const UNREACHABLE(); } -void JSCompiler::Compile(const ir::TSQualifiedName *expr) const +void JSCompiler::Compile([[maybe_unused]] const ir::TSQualifiedName *expr) const { - (void)expr; UNREACHABLE(); } @@ -1179,9 +1173,8 @@ void JSCompiler::Compile(const ir::TSTupleType *node) const UNREACHABLE(); } -void JSCompiler::Compile(const ir::TSTypeAliasDeclaration *st) const +void JSCompiler::Compile([[maybe_unused]] const ir::TSTypeAliasDeclaration *st) const { - (void)st; UNREACHABLE(); } @@ -1233,9 +1226,8 @@ void JSCompiler::Compile(const ir::TSTypeQuery *node) const UNREACHABLE(); } -void JSCompiler::Compile(const ir::TSTypeReference *node) const +void JSCompiler::Compile([[maybe_unused]] const ir::TSTypeReference *node) const { - (void)node; UNREACHABLE(); } diff --git a/ets2panda/ir/ts/tsConstructorType.cpp b/ets2panda/ir/ts/tsConstructorType.cpp index 0b720e9834..8401dc267d 100644 --- a/ets2panda/ir/ts/tsConstructorType.cpp +++ b/ets2panda/ir/ts/tsConstructorType.cpp @@ -18,6 +18,8 @@ #include "varbinder/scope.h" #include "checker/TSchecker.h" #include "checker/types/signature.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" #include "ir/astDump.h" #include "ir/ts/tsTypeParameter.h" #include "ir/ts/tsTypeParameterDeclaration.h" @@ -58,19 +60,18 @@ void TSConstructorType::Dump(ir::AstDumper *dumper) const {"abstract", AstDumper::Optional(abstract_)}}); } -void TSConstructorType::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} +void TSConstructorType::Compile([[maybe_unused]] compiler::PandaGen *pg) const +{ + pg->GetAstCompiler()->Compile(this); +} +void TSConstructorType::Compile(compiler::ETSGen *etsg) const +{ + etsg->GetAstCompiler()->Compile(this); +} checker::Type *TSConstructorType::Check(checker::TSChecker *checker) { - checker::ScopeContext scope_ctx(checker, scope_); - - auto *signature_info = checker->Allocator()->New(checker->Allocator()); - checker->CheckFunctionParameterDeclarations(params_, signature_info); - return_type_->Check(checker); - auto *construct_signature = - checker->Allocator()->New(signature_info, return_type_->GetType(checker)); - - return checker->CreateConstructorTypeWithSignature(construct_signature); + return checker->GetAnalyzer()->Check(this); } checker::Type *TSConstructorType::GetType(checker::TSChecker *checker) @@ -80,6 +81,6 @@ checker::Type *TSConstructorType::GetType(checker::TSChecker *checker) checker::Type *TSConstructorType::Check([[maybe_unused]] checker::ETSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/ts/tsConstructorType.h b/ets2panda/ir/ts/tsConstructorType.h index c3e7d0e085..c617833920 100644 --- a/ets2panda/ir/ts/tsConstructorType.h +++ b/ets2panda/ir/ts/tsConstructorType.h @@ -18,6 +18,9 @@ #include "ir/typeNode.h" +namespace panda::es2panda::checker { +class TSAnalyzer; +} // namespace panda::es2panda::checker namespace panda::es2panda::ir { class TSTypeParameterDeclaration; @@ -33,6 +36,8 @@ public: abstract_(abstract) { } + // TODO (vivienvoros): these friend relationships can be removed once there are getters for private fields + friend class checker::TSAnalyzer; bool IsScopeBearer() const override { @@ -68,6 +73,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/tsFunctionType.cpp b/ets2panda/ir/ts/tsFunctionType.cpp index b58d0c2dcb..61c32ed96f 100644 --- a/ets2panda/ir/ts/tsFunctionType.cpp +++ b/ets2panda/ir/ts/tsFunctionType.cpp @@ -19,6 +19,8 @@ #include "checker/TSchecker.h" #include "checker/ETSchecker.h" #include "checker/types/signature.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" #include "ir/astDump.h" #include "ir/base/spreadElement.h" #include "ir/expressions/identifier.h" @@ -61,19 +63,18 @@ void TSFunctionType::Dump(ir::AstDumper *dumper) const {"isNullable", AstDumper::Optional(nullable_)}}); } -void TSFunctionType::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} +void TSFunctionType::Compile([[maybe_unused]] compiler::PandaGen *pg) const +{ + pg->GetAstCompiler()->Compile(this); +} +void TSFunctionType::Compile(compiler::ETSGen *etsg) const +{ + etsg->GetAstCompiler()->Compile(this); +} checker::Type *TSFunctionType::Check(checker::TSChecker *checker) { - checker::ScopeContext scope_ctx(checker, scope_); - - auto *signature_info = checker->Allocator()->New(checker->Allocator()); - checker->CheckFunctionParameterDeclarations(params_, signature_info); - return_type_->Check(checker); - auto *call_signature = - checker->Allocator()->New(signature_info, return_type_->GetType(checker)); - - return checker->CreateFunctionTypeWithSignature(call_signature); + return checker->GetAnalyzer()->Check(this); } checker::Type *TSFunctionType::GetType(checker::TSChecker *checker) @@ -83,7 +84,7 @@ checker::Type *TSFunctionType::GetType(checker::TSChecker *checker) checker::Type *TSFunctionType::Check([[maybe_unused]] checker::ETSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } checker::Type *TSFunctionType::GetType([[maybe_unused]] checker::ETSChecker *checker) diff --git a/ets2panda/ir/ts/tsFunctionType.h b/ets2panda/ir/ts/tsFunctionType.h index cebf62ad5f..d0ecd35392 100644 --- a/ets2panda/ir/ts/tsFunctionType.h +++ b/ets2panda/ir/ts/tsFunctionType.h @@ -17,7 +17,9 @@ #define ES2PANDA_IR_TS_FUNCTION_TYPE_H #include "ir/typeNode.h" - +namespace panda::es2panda::checker { +class TSAnalyzer; +} // namespace panda::es2panda::checker namespace panda::es2panda::ir { class TSTypeParameterDeclaration; @@ -32,6 +34,8 @@ public: return_type_(return_type) { } + // TODO (vivienvoros): these friend relationships can be removed once there are getters for private fields + friend class checker::TSAnalyzer; bool IsScopeBearer() const override { @@ -67,6 +71,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/tsImportEqualsDeclaration.cpp b/ets2panda/ir/ts/tsImportEqualsDeclaration.cpp index eb615a791e..3f08423270 100644 --- a/ets2panda/ir/ts/tsImportEqualsDeclaration.cpp +++ b/ets2panda/ir/ts/tsImportEqualsDeclaration.cpp @@ -15,6 +15,9 @@ #include "tsImportEqualsDeclaration.h" +#include "checker/TSchecker.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" #include "ir/astDump.h" #include "ir/expression.h" #include "ir/expressions/identifier.h" @@ -40,15 +43,22 @@ void TSImportEqualsDeclaration::Dump(ir::AstDumper *dumper) const {"isExport", is_export_}}); } -void TSImportEqualsDeclaration::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} +void TSImportEqualsDeclaration::Compile([[maybe_unused]] compiler::PandaGen *pg) const +{ + pg->GetAstCompiler()->Compile(this); +} +void TSImportEqualsDeclaration::Compile(compiler::ETSGen *etsg) const +{ + etsg->GetAstCompiler()->Compile(this); +} checker::Type *TSImportEqualsDeclaration::Check([[maybe_unused]] checker::TSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } checker::Type *TSImportEqualsDeclaration::Check([[maybe_unused]] checker::ETSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/ts/tsImportEqualsDeclaration.h b/ets2panda/ir/ts/tsImportEqualsDeclaration.h index cc2d7dea4b..eaca31099c 100644 --- a/ets2panda/ir/ts/tsImportEqualsDeclaration.h +++ b/ets2panda/ir/ts/tsImportEqualsDeclaration.h @@ -50,6 +50,7 @@ public: void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; void Compile([[maybe_unused]] compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; diff --git a/ets2panda/ir/ts/tsIndexedAccessType.cpp b/ets2panda/ir/ts/tsIndexedAccessType.cpp index 6c4f97c569..22d534af67 100644 --- a/ets2panda/ir/ts/tsIndexedAccessType.cpp +++ b/ets2panda/ir/ts/tsIndexedAccessType.cpp @@ -15,6 +15,8 @@ #include "tsIndexedAccessType.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" #include "ir/astDump.h" #include "checker/TSchecker.h" @@ -37,30 +39,18 @@ void TSIndexedAccessType::Dump(ir::AstDumper *dumper) const dumper->Add({{"type", "TSIndexedAccessType"}, {"objectType", object_type_}, {"indexType", index_type_}}); } -void TSIndexedAccessType::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} +void TSIndexedAccessType::Compile([[maybe_unused]] compiler::PandaGen *pg) const +{ + pg->GetAstCompiler()->Compile(this); +} +void TSIndexedAccessType::Compile(compiler::ETSGen *etsg) const +{ + etsg->GetAstCompiler()->Compile(this); +} checker::Type *TSIndexedAccessType::Check([[maybe_unused]] checker::TSChecker *checker) { - object_type_->Check(checker); - index_type_->Check(checker); - checker::Type *resolved = GetType(checker); - - if (resolved != nullptr) { - return nullptr; - } - - checker::Type *index_type = checker->CheckTypeCached(index_type_); - - if (!index_type->HasTypeFlag(checker::TypeFlag::STRING_LIKE | checker::TypeFlag::NUMBER_LIKE)) { - checker->ThrowTypeError({"Type ", index_type, " cannot be used as index type"}, index_type_->Start()); - } - - if (index_type->IsNumberType()) { - checker->ThrowTypeError("Type has no matching signature for type 'number'", Start()); - } - - checker->ThrowTypeError("Type has no matching signature for type 'string'", Start()); - return nullptr; + return checker->GetAnalyzer()->Check(this); } checker::Type *TSIndexedAccessType::GetType([[maybe_unused]] checker::TSChecker *checker) @@ -79,6 +69,6 @@ checker::Type *TSIndexedAccessType::GetType([[maybe_unused]] checker::TSChecker checker::Type *TSIndexedAccessType::Check([[maybe_unused]] checker::ETSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/ts/tsIndexedAccessType.h b/ets2panda/ir/ts/tsIndexedAccessType.h index 1d456ed9b3..13372ab350 100644 --- a/ets2panda/ir/ts/tsIndexedAccessType.h +++ b/ets2panda/ir/ts/tsIndexedAccessType.h @@ -18,6 +18,10 @@ #include "ir/typeNode.h" +namespace panda::es2panda::checker { +class TSAnalyzer; +} // namespace panda::es2panda::checker + namespace panda::es2panda::ir { class TSIndexedAccessType : public TypeNode { public: @@ -25,6 +29,8 @@ public: : TypeNode(AstNodeType::TS_INDEXED_ACCESS_TYPE), object_type_(object_type), index_type_(index_type) { } + // TODO (vivienvoros): these friend relationships can be removed once there are getters for private fields + friend class checker::TSAnalyzer; const TypeNode *ObjectType() const { @@ -40,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 *GetType([[maybe_unused]] checker::TSChecker *checker) override; checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; diff --git a/ets2panda/ir/ts/tsInterfaceDeclaration.cpp b/ets2panda/ir/ts/tsInterfaceDeclaration.cpp index 3740664b32..9dc4135dce 100644 --- a/ets2panda/ir/ts/tsInterfaceDeclaration.cpp +++ b/ets2panda/ir/ts/tsInterfaceDeclaration.cpp @@ -20,6 +20,8 @@ #include "varbinder/variable.h" #include "checker/TSchecker.h" #include "checker/ETSchecker.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" #include "ir/astDump.h" #include "ir/base/decorator.h" #include "ir/expressions/identifier.h" @@ -77,99 +79,23 @@ void TSInterfaceDeclaration::Dump(ir::AstDumper *dumper) const {"typeParameters", AstDumper::Optional(type_params_)}}); } -void TSInterfaceDeclaration::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} - -void CheckInheritedPropertiesAreIdentical(checker::TSChecker *checker, checker::InterfaceType *type, - const lexer::SourcePosition &loc_info) +void TSInterfaceDeclaration::Compile([[maybe_unused]] compiler::PandaGen *pg) const { - checker->GetBaseTypes(type); - - size_t constexpr BASE_SIZE_LIMIT = 2; - if (type->Bases().size() < BASE_SIZE_LIMIT) { - return; - } - - checker->ResolveDeclaredMembers(type); - - checker::InterfacePropertyMap properties; - - for (auto *it : type->Properties()) { - properties.insert({it->Name(), {it, type}}); - } + pg->GetAstCompiler()->Compile(this); +} - for (auto *base : type->Bases()) { - checker->ResolveStructuredTypeMembers(base); - ArenaVector inherited_properties(checker->Allocator()->Adapter()); - base->AsInterfaceType()->CollectProperties(&inherited_properties); - - for (auto *inherited_prop : inherited_properties) { - auto res = properties.find(inherited_prop->Name()); - if (res == properties.end()) { - properties.insert({inherited_prop->Name(), {inherited_prop, base->AsInterfaceType()}}); - } else if (res->second.second != type) { - checker::Type *source_type = checker->GetTypeOfVariable(inherited_prop); - checker::Type *target_type = checker->GetTypeOfVariable(res->second.first); - checker->IsTypeIdenticalTo(source_type, target_type, - {"Interface '", type, "' cannot simultaneously extend types '", - res->second.second, "' and '", base->AsInterfaceType(), "'."}, - loc_info); - } - } - } +void TSInterfaceDeclaration::Compile(compiler::ETSGen *etsg) const +{ + etsg->GetAstCompiler()->Compile(this); } checker::Type *TSInterfaceDeclaration::Check([[maybe_unused]] checker::TSChecker *checker) { - varbinder::Variable *var = id_->Variable(); - ASSERT(var->Declaration()->Node() && var->Declaration()->Node()->IsTSInterfaceDeclaration()); - - if (this == var->Declaration()->Node()) { - checker::Type *resolved_type = var->TsType(); - - if (resolved_type == nullptr) { - checker::ObjectDescriptor *desc = - checker->Allocator()->New(checker->Allocator()); - resolved_type = checker->Allocator()->New(checker->Allocator(), id_->Name(), desc); - resolved_type->SetVariable(var); - var->SetTsType(resolved_type); - } - - checker::InterfaceType *resolved_interface = resolved_type->AsObjectType()->AsInterfaceType(); - CheckInheritedPropertiesAreIdentical(checker, resolved_interface, id_->Start()); - - for (auto *base : resolved_interface->Bases()) { - checker->IsTypeAssignableTo(resolved_interface, base, - {"Interface '", id_->Name(), "' incorrectly extends interface '", base, "'"}, - id_->Start()); - } - - checker->CheckIndexConstraints(resolved_interface); - } - - body_->Check(checker); - - return nullptr; + return checker->GetAnalyzer()->Check(this); } checker::Type *TSInterfaceDeclaration::Check(checker::ETSChecker *checker) { - checker::ETSObjectType *interface_type {}; - - if (TsType() == nullptr) { - interface_type = checker->BuildInterfaceProperties(this); - ASSERT(interface_type != nullptr); - interface_type->SetSuperType(checker->GlobalETSObjectType()); - checker->CheckInvokeMethodsLegitimacy(interface_type); - SetTsType(interface_type); - } - - checker::ScopeContext scope_ctx(checker, scope_); - auto saved_context = checker::SavedCheckerContext(checker, checker::CheckerStatus::IN_INTERFACE, interface_type); - - for (auto *it : body_->Body()) { - it->Check(checker); - } - - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/ts/tsInterfaceDeclaration.h b/ets2panda/ir/ts/tsInterfaceDeclaration.h index e209324087..65140c2fac 100644 --- a/ets2panda/ir/ts/tsInterfaceDeclaration.h +++ b/ets2panda/ir/ts/tsInterfaceDeclaration.h @@ -140,6 +140,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; checker::Type *InferType(checker::TSChecker *checker, varbinder::Variable *binding_var) const; diff --git a/ets2panda/ir/ts/tsQualifiedName.cpp b/ets2panda/ir/ts/tsQualifiedName.cpp index cf72fa5f72..c9099debbd 100644 --- a/ets2panda/ir/ts/tsQualifiedName.cpp +++ b/ets2panda/ir/ts/tsQualifiedName.cpp @@ -17,6 +17,8 @@ #include "checker/ETSchecker.h" #include "checker/TSchecker.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" #include "ir/astDump.h" #include "ir/expressions/identifier.h" @@ -38,42 +40,23 @@ void TSQualifiedName::Dump(ir::AstDumper *dumper) const dumper->Add({{"type", "TSQualifiedName"}, {"left", left_}, {"right", right_}}); } -void TSQualifiedName::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} +void TSQualifiedName::Compile([[maybe_unused]] compiler::PandaGen *pg) const +{ + pg->GetAstCompiler()->Compile(this); +} +void TSQualifiedName::Compile(compiler::ETSGen *etsg) const +{ + etsg->GetAstCompiler()->Compile(this); +} checker::Type *TSQualifiedName::Check([[maybe_unused]] checker::TSChecker *checker) { - checker::Type *base_type = checker->CheckNonNullType(left_->Check(checker), left_->Start()); - varbinder::Variable *prop = checker->GetPropertyOfType(base_type, right_->Name()); - - if (prop != nullptr) { - return checker->GetTypeOfVariable(prop); - } - - if (base_type->IsObjectType()) { - checker::ObjectType *obj_type = base_type->AsObjectType(); - - if (obj_type->StringIndexInfo() != nullptr) { - return obj_type->StringIndexInfo()->GetType(); - } - } - - checker->ThrowTypeError({"Property ", right_->Name(), " does not exist on this type."}, right_->Start()); - return nullptr; + return checker->GetAnalyzer()->Check(this); } checker::Type *TSQualifiedName::Check(checker::ETSChecker *checker) { - checker::Type *base_type = left_->Check(checker); - if (base_type->IsETSObjectType()) { - varbinder::Variable *prop = - base_type->AsETSObjectType()->GetProperty(right_->Name(), checker::PropertySearchFlags::SEARCH_DECL); - - if (prop != nullptr) { - return checker->GetTypeOfVariable(prop); - } - } - - checker->ThrowTypeError({"'", right_->Name(), "' type does not exist."}, right_->Start()); + return checker->GetAnalyzer()->Check(this); } util::StringView TSQualifiedName::ToString(ArenaAllocator *allocator) const diff --git a/ets2panda/ir/ts/tsQualifiedName.h b/ets2panda/ir/ts/tsQualifiedName.h index d86985550f..89f24fdafa 100644 --- a/ets2panda/ir/ts/tsQualifiedName.h +++ b/ets2panda/ir/ts/tsQualifiedName.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 *Check([[maybe_unused]] checker::ETSChecker *checker) override; diff --git a/ets2panda/ir/ts/tsTypeAliasDeclaration.cpp b/ets2panda/ir/ts/tsTypeAliasDeclaration.cpp index 52028ef4fb..83bf379328 100644 --- a/ets2panda/ir/ts/tsTypeAliasDeclaration.cpp +++ b/ets2panda/ir/ts/tsTypeAliasDeclaration.cpp @@ -17,6 +17,8 @@ #include "varbinder/scope.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/base/decorator.h" @@ -69,17 +71,23 @@ void TSTypeAliasDeclaration::Dump(ir::AstDumper *dumper) const {"declare", AstDumper::Optional(declare_)}}); } -void TSTypeAliasDeclaration::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} +void TSTypeAliasDeclaration::Compile([[maybe_unused]] compiler::PandaGen *pg) const +{ + pg->GetAstCompiler()->Compile(this); +} + +void TSTypeAliasDeclaration::Compile(compiler::ETSGen *etsg) const +{ + etsg->GetAstCompiler()->Compile(this); +} checker::Type *TSTypeAliasDeclaration::Check([[maybe_unused]] checker::TSChecker *checker) { - TypeAnnotation()->Check(checker); - return nullptr; + return checker->GetAnalyzer()->Check(this); } checker::Type *TSTypeAliasDeclaration::Check([[maybe_unused]] checker::ETSChecker *checker) { - TypeAnnotation()->Check(checker); - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/ts/tsTypeAliasDeclaration.h b/ets2panda/ir/ts/tsTypeAliasDeclaration.h index 5dc000528a..0eb0038144 100644 --- a/ets2panda/ir/ts/tsTypeAliasDeclaration.h +++ b/ets2panda/ir/ts/tsTypeAliasDeclaration.h @@ -91,6 +91,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/tsTypeReference.cpp b/ets2panda/ir/ts/tsTypeReference.cpp index df1c13a9c3..ed6d359cef 100644 --- a/ets2panda/ir/ts/tsTypeReference.cpp +++ b/ets2panda/ir/ts/tsTypeReference.cpp @@ -19,6 +19,8 @@ #include "varbinder/scope.h" #include "varbinder/variable.h" #include "checker/TSchecker.h" +#include "compiler/core/ETSGen.h" +#include "compiler/core/pandagen.h" #include "ir/astDump.h" #include "ir/expressions/identifier.h" #include "ir/ts/tsInterfaceDeclaration.h" @@ -52,7 +54,14 @@ void TSTypeReference::Dump(ir::AstDumper *dumper) const {{"type", "TSTypeReference"}, {"typeName", type_name_}, {"typeParameters", AstDumper::Optional(type_params_)}}); } -void TSTypeReference::Compile([[maybe_unused]] compiler::PandaGen *pg) const {} +void TSTypeReference::Compile([[maybe_unused]] compiler::PandaGen *pg) const +{ + pg->GetAstCompiler()->Compile(this); +} +void TSTypeReference::Compile(compiler::ETSGen *etsg) const +{ + etsg->GetAstCompiler()->Compile(this); +} ir::Identifier *TSTypeReference::BaseName() const { @@ -71,8 +80,7 @@ ir::Identifier *TSTypeReference::BaseName() const checker::Type *TSTypeReference::Check([[maybe_unused]] checker::TSChecker *checker) { - GetType(checker); - return nullptr; + return checker->GetAnalyzer()->Check(this); } checker::Type *TSTypeReference::GetType([[maybe_unused]] checker::TSChecker *checker) @@ -98,6 +106,6 @@ checker::Type *TSTypeReference::GetType([[maybe_unused]] checker::TSChecker *che checker::Type *TSTypeReference::Check([[maybe_unused]] checker::ETSChecker *checker) { - return nullptr; + return checker->GetAnalyzer()->Check(this); } } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/ts/tsTypeReference.h b/ets2panda/ir/ts/tsTypeReference.h index 2f96fd8a6b..6f19629456 100644 --- a/ets2panda/ir/ts/tsTypeReference.h +++ b/ets2panda/ir/ts/tsTypeReference.h @@ -48,6 +48,7 @@ public: void Iterate(const NodeTraverser &cb) const override; void Dump(ir::AstDumper *dumper) const override; void Compile([[maybe_unused]] compiler::PandaGen *pg) const override; + void Compile(compiler::ETSGen *etsg) const override; checker::Type *Check([[maybe_unused]] checker::TSChecker *checker) override; checker::Type *GetType([[maybe_unused]] checker::TSChecker *checker) override; checker::Type *Check([[maybe_unused]] checker::ETSChecker *checker) override; -- Gitee