diff --git a/ets2panda/checker/ETSAnalyzer.cpp b/ets2panda/checker/ETSAnalyzer.cpp index ec729cf22942eacc61d2ca5a674062973d981b88..d334ddfbafd01f69728500c82934a4744d464ed0 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 d3e96e821ffd6bb149a2337acaa909ed200d7dca..49cf14c4e3a84e6dd856d1dfcd7cf688404f541b 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 46dd096ae82d9c812db8af28704dee330951bdcd..114ea4212e599b57ed1db92e9734e6de574440c0 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 10a894d364243fe8b74d0bd55d96c5d90df2551c..62eba33481c35f4f0a44a6c7574719f7e765603a 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 0b720e9834e9bb124e3bd731ce63d9bd67ff9c37..8401dc267d7e9eace4dc45a57d203caff5955024 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 c3e7d0e085b2b0e1e1b65d10c2b851d6ec9bfdca..c617833920eb235bc650ca19563ba766e25a02a5 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 b58d0c2dcb746fe4f702e627028e5937234df5ac..61c32ed96f02fc15760cc7a6656c06981b28d2ab 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 cebf62ad5f697a7db9c114de0ddb2b6d422b7c0e..d0ecd3539289008977a85caec6eaf1b0f26352b2 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 eb615a791ebf495e47bb4b41db224e1e41bfbd76..3f08423270aaf6035b71c4e422312f5bf79acd15 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 cc2d7dea4b72747b0df89e9983df872e5c92a575..eaca31099cabd74448200193c06129bbd92c4810 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 6c4f97c5699bf0c013e391c57659b8a2e1fc72fb..22d534af67ca2e7c2ba32f4340e059482c1fc213 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 1d456ed9b39d08f8ee1d1205ff6f9ff1003c1a10..13372ab35019a1d580a5177c6e0908617f1efe6e 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 3740664b32e6f4fac4323668bfee774085bc99af..9dc4135dcef03f75145752a0ae9c485875a23d51 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 e209324087ebff6e72b4d94dd77acfee8c52eb2d..65140c2facaa414c4b1596415aad4ae7fe936759 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 cf72fa5f727e7be2f033ac105acb73b86c2836a7..c9099debbde40ea9d58efeaf21ecdd026ec2cf55 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 d86985550f2cc90ca759c94879b9767efee6a4a9..89f24fdafa0d79dca9e9a53d5659464a7ada9520 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 52028ef4fb687df6365785a0bb53b093e958ced6..83bf379328b27f1fb35a5f84590a85d7ecb6d82e 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 5dc000528a098a4fca951d7e7431644d01f39082..0eb0038144a07af635793b6a79d78c19ec62b850 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 df1c13a9c392748f8e7f154a71ad92cf1ad06ecb..ed6d359cefcf88b11ff1ff199c8c0aecb4c191ca 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 2f96fd8a6bb3875eb72a5f7a7d91e7a6440f5e3f..6f196294568164f7cb53ae20f4e1cef1cca1ed52 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;