From 4584531fcf9c065d87cf6fb728029a8355333807 Mon Sep 17 00:00:00 2001 From: Csaba Osztrogonac Date: Wed, 21 Dec 2022 00:53:17 +0100 Subject: [PATCH 1/2] [ETS] Abstract classes shouldn't be marked as final in the abc file Change-Id: Id0d9bba371c91a44cbeab071b2dc1c1df39a4f99 Signed-off-by: Csaba Osztrogonac --- compiler/core/ETSemitter.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/compiler/core/ETSemitter.cpp b/compiler/core/ETSemitter.cpp index 9d80cc4cb..c67ae58c4 100644 --- a/compiler/core/ETSemitter.cpp +++ b/compiler/core/ETSemitter.cpp @@ -455,9 +455,7 @@ void ETSEmitter::GenClassRecord(const ir::ClassDefinition *classDef, bool extern if (classDef->IsAbstract()) { accessFlags |= ACC_ABSTRACT; - } - - if (!classDef->IsOpen()) { + } else if (!classDef->IsOpen()) { accessFlags |= ACC_FINAL; } -- Gitee From a5c177201469fff33f7c7955c899f1918b822f78 Mon Sep 17 00:00:00 2001 From: Csaba Osztrogonac Date: Fri, 23 Dec 2022 15:56:19 +0100 Subject: [PATCH 2/2] Basic generics implementation Change-Id: I2858e8980bd221d4c75a0909a7c01b7d271c8b85 --- checker/ETSchecker.h | 2 +- checker/ets/function.cpp | 4 + checker/ets/helpers.cpp | 2 +- checker/ets/object.cpp | 23 +- compiler/core/ETSGen.cpp | 6 + compiler/core/ETSemitter.cpp | 2 +- ir/base/scriptFunction.h | 5 + ir/ets/etsNewClassInstanceExpression.cpp | 4 + ir/expressions/memberExpression.cpp | 9 +- ir/statements/returnStatement.cpp | 9 + parser/ETSparser.cpp | 37 +- parser/expressionParser.cpp | 4 +- parser/parserImpl.h | 5 +- test/parser/ets/generic_function-expected.txt | 903 +++++++++++++++++- test/parser/ets/generic_function.ets | 4 +- test/parser/ets/type_variance4-expected.txt | 2 +- test/runtime/ets/generic-function.ets | 28 + test/runtime/ets/generic-set.ets | 81 ++ 18 files changed, 1095 insertions(+), 35 deletions(-) create mode 100644 test/runtime/ets/generic-function.ets create mode 100644 test/runtime/ets/generic-set.ets diff --git a/checker/ETSchecker.h b/checker/ETSchecker.h index 36f271d16..992e8c187 100644 --- a/checker/ETSchecker.h +++ b/checker/ETSchecker.h @@ -344,7 +344,7 @@ public: GlobalTypesHolder *globalTypes); private: - void CreateTypeForTypeParameters(ETSObjectType *type, ir::TSTypeParameterDeclaration *typeParams); + void CreateTypeForTypeParameters(ir::TSTypeParameterDeclaration *typeParams); ETSObjectType *CheckException(checker::Type *type, lexer::SourcePosition pos, ETSObjectType *expected, std::string_view msg); ETSObjectType *CreateETSObjectTypeCheckBuiltins(util::StringView name, ir::AstNode *declNode, ETSObjectFlags flags); diff --git a/checker/ets/function.cpp b/checker/ets/function.cpp index ae9b0f376..552bdadbf 100644 --- a/checker/ets/function.cpp +++ b/checker/ets/function.cpp @@ -202,6 +202,10 @@ checker::ETSFunctionType *ETSChecker::BuildFunctionSignature(ir::ScriptFunction thisVar->SetTsType(Context().ContainingClass()); } + if (func->TypeParams() != nullptr) { + CreateTypeForTypeParameters(func->TypeParams()); + } + for (auto *it : func->Params()) { if (it->IsRestElement()) { auto *restParam = it->AsRestElement(); diff --git a/checker/ets/helpers.cpp b/checker/ets/helpers.cpp index 2ab32e5d2..ff7534f29 100644 --- a/checker/ets/helpers.cpp +++ b/checker/ets/helpers.cpp @@ -311,7 +311,7 @@ Type *ETSChecker::ResolveIdentifier(ir::Identifier *ident) break; } - if (!resolvedType->IsETSObjectType() && !resolvedType->IsETSArrayType()) { + if (!resolvedType->IsETSObjectType() && !resolvedType->IsETSArrayType() && !resolvedType->IsETSTypeReference()) { resolved = nullptr; } diff --git a/checker/ets/object.cpp b/checker/ets/object.cpp index a8a18208d..a54f64094 100644 --- a/checker/ets/object.cpp +++ b/checker/ets/object.cpp @@ -164,11 +164,8 @@ void ETSChecker::SetTypeParameterType(ir::TSTypeParameter *typeParam, Type *asse var->SetTsType(typeParamType); } -void ETSChecker::CreateTypeForTypeParameters(ETSObjectType *type, ir::TSTypeParameterDeclaration *typeParams) +void ETSChecker::CreateTypeForTypeParameters(ir::TSTypeParameterDeclaration *typeParams) { - if (type->HasObjectFlag(ETSObjectFlags::RESOLVED_TYPE_PARAMS)) { - return; - } checker::ScopeContext scopeCtx(this, typeParams->Scope()); @@ -194,20 +191,30 @@ void ETSChecker::CreateTypeForTypeParameters(ETSObjectType *type, ir::TSTypePara SetTypeParameterType(param, paramType); } - - type->AddObjectFlag(ETSObjectFlags::RESOLVED_TYPE_PARAMS); } void ETSChecker::CreateTypeForInterfaceTypeParameters(ETSObjectType *type) { + if (type->HasObjectFlag(ETSObjectFlags::RESOLVED_TYPE_PARAMS)) { + return; + } + ir::TSTypeParameterDeclaration *typeParams = type->GetDeclNode()->AsTSInterfaceDeclaration()->TypeParams(); - CreateTypeForTypeParameters(type, typeParams); + CreateTypeForTypeParameters(typeParams); + + type->AddObjectFlag(ETSObjectFlags::RESOLVED_TYPE_PARAMS); } void ETSChecker::CreateTypeForClassTypeParameters(ETSObjectType *type) { + if (type->HasObjectFlag(ETSObjectFlags::RESOLVED_TYPE_PARAMS)) { + return; + } + ir::TSTypeParameterDeclaration *typeParams = type->GetDeclNode()->AsClassDefinition()->TypeParams(); - CreateTypeForTypeParameters(type, typeParams); + CreateTypeForTypeParameters(typeParams); + + type->AddObjectFlag(ETSObjectFlags::RESOLVED_TYPE_PARAMS); } ETSObjectType *ETSChecker::BuildInterfaceProperties(ir::TSInterfaceDeclaration *interfaceDecl) diff --git a/compiler/core/ETSGen.cpp b/compiler/core/ETSGen.cpp index 305570a35..4a8b301f2 100644 --- a/compiler/core/ETSGen.cpp +++ b/compiler/core/ETSGen.cpp @@ -1318,6 +1318,9 @@ void ETSGen::LoadArrayLength(const ir::AstNode *node, VReg arrayReg) void ETSGen::LoadArrayElement(const ir::AstNode *node, VReg objectReg) { auto *elementType = GetVRegType(objectReg)->AsETSArrayType()->ElementType(); + if (elementType->IsETSTypeReference()) { + elementType = Checker()->GlobalETSObjectType(); + } switch (checker::ETSChecker::ETSType(elementType)) { case checker::TypeFlag::ETS_BOOLEAN: @@ -1366,6 +1369,9 @@ void ETSGen::LoadArrayElement(const ir::AstNode *node, VReg objectReg) void ETSGen::StoreArrayElement(const ir::AstNode *node, VReg objectReg, VReg index) { auto *elementType = GetVRegType(objectReg)->AsETSArrayType()->ElementType(); + if (elementType->IsETSTypeReference()) { + elementType = Checker()->GlobalETSObjectType(); + } switch (checker::ETSChecker::ETSType(elementType)) { case checker::TypeFlag::ETS_BOOLEAN: diff --git a/compiler/core/ETSemitter.cpp b/compiler/core/ETSemitter.cpp index c67ae58c4..db37eeced 100644 --- a/compiler/core/ETSemitter.cpp +++ b/compiler/core/ETSemitter.cpp @@ -493,7 +493,7 @@ void ETSEmitter::GenClassRecord(const ir::ClassDefinition *classDef, bool extern std::vector annotations; if (classDef->TypeParams() != nullptr) { - annotations.emplace_back(GenAnnotationSignature(classDef)); + //annotations.emplace_back(GenAnnotationSignature(classDef)); } const ir::AstNode *parent = classDef->Parent(); diff --git a/ir/base/scriptFunction.h b/ir/base/scriptFunction.h index 1fb954d1a..5582dc4da 100644 --- a/ir/base/scriptFunction.h +++ b/ir/base/scriptFunction.h @@ -96,6 +96,11 @@ public: return typeParams_; } + TSTypeParameterDeclaration *TypeParams() + { + return typeParams_; + } + const AstNode *Body() const { return body_; diff --git a/ir/ets/etsNewClassInstanceExpression.cpp b/ir/ets/etsNewClassInstanceExpression.cpp index 7e80b1268..b6eb97a50 100644 --- a/ir/ets/etsNewClassInstanceExpression.cpp +++ b/ir/ets/etsNewClassInstanceExpression.cpp @@ -62,6 +62,10 @@ checker::Type *ETSNewClassInstanceExpression::Check([[maybe_unused]] checker::ET { checker::Type *calleeType = typeReference_->Check(checker); + if (calleeType->IsETSTypeReference()) { + calleeType = checker->GlobalETSObjectType(); + } + if (!calleeType->IsETSObjectType()) { checker->ThrowTypeError("This expression is not constructible.", Start()); } diff --git a/ir/expressions/memberExpression.cpp b/ir/expressions/memberExpression.cpp index 63035683a..a12d1ad7b 100644 --- a/ir/expressions/memberExpression.cpp +++ b/ir/expressions/memberExpression.cpp @@ -239,7 +239,7 @@ checker::Type *MemberExpression::Check(checker::ETSChecker *checker) checker::Type *baseType = object_->Check(checker); - if (!baseType->IsETSObjectType()) { + if (!baseType->IsETSObjectType() && !baseType->IsETSTypeReference()) { if (baseType->IsETSArrayType() && property_->AsIdentifier()->Name().Is("length")) { SetTsType(checker->GlobalIntType()); return TsType(); @@ -248,7 +248,12 @@ checker::Type *MemberExpression::Check(checker::ETSChecker *checker) checker->ThrowTypeError({"Cannot access property of non-object type"}, object_->Start()); } - objType_ = baseType->AsETSObjectType(); + if (baseType->IsETSTypeReference()) { + objType_ = checker->GlobalETSObjectType(); + } else { + objType_ = baseType->AsETSObjectType(); + } + propVar_ = checker->ResolveMemberReference(this, objType_); checker->ValidatePropertyAccess(propVar_, objType_, property_->Start()); SetTsType(checker->GetTypeOfVariable(propVar_)); diff --git a/ir/statements/returnStatement.cpp b/ir/statements/returnStatement.cpp index 4ef5420fa..065f7901c 100644 --- a/ir/statements/returnStatement.cpp +++ b/ir/statements/returnStatement.cpp @@ -146,6 +146,15 @@ checker::Type *ReturnStatement::Check(checker::ETSChecker *checker) ASSERT(argument_); checker::Type *returnType = argument_->Check(checker); + + if (funcReturnType->IsETSTypeReference()) { + funcReturnType = checker->GlobalETSObjectType(); + } + + if (returnType->IsETSTypeReference()) { + returnType = checker->GlobalETSObjectType(); + } + checker::AssignmentContext( checker->Relation(), argument_, returnType, funcReturnType, argument_->Start(), {"Return statements return type is not compatible with the containing functions return type"}, diff --git a/parser/ETSparser.cpp b/parser/ETSparser.cpp index 98bc8cf0a..2d8ef9c21 100644 --- a/parser/ETSparser.cpp +++ b/parser/ETSparser.cpp @@ -336,8 +336,6 @@ ArenaVector ETSParser::ParseTopLevelStatements(ArenaVectorNextToken(); auto *memberName = ExpectIdentifier(); - - ExpectToken(lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS, false); auto classCtx = binder::LexicalScope::Enter(Binder(), GetProgram()->GlobalClassScope()); auto *classMethod = ParseClassMethodDefinition(memberName, memberModifiers); @@ -540,8 +538,10 @@ ir::ModifierFlags ETSParser::ParseClassModifiers() std::tuple ETSParser::ParseClassImplementsElement() { - TypeAnnotationParsingOptions options = - TypeAnnotationParsingOptions::THROW_ERROR | TypeAnnotationParsingOptions::DISALLOW_PRIMARY_TYPE; + TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR | + TypeAnnotationParsingOptions::DISALLOW_PRIMARY_TYPE | + TypeAnnotationParsingOptions::IGNORE_FUNCTION_TYPE | + TypeAnnotationParsingOptions::ALLOW_WILDCARD; return {ParseTypeReference(&options), nullptr}; } @@ -550,8 +550,10 @@ ir::Expression *ETSParser::ParseSuperClassReference() if (Lexer()->GetToken().Type() == lexer::TokenType::KEYW_EXTENDS) { Lexer()->NextToken(); - TypeAnnotationParsingOptions options = - TypeAnnotationParsingOptions::THROW_ERROR | TypeAnnotationParsingOptions::DISALLOW_PRIMARY_TYPE; + TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR | + TypeAnnotationParsingOptions::DISALLOW_PRIMARY_TYPE | + TypeAnnotationParsingOptions::IGNORE_FUNCTION_TYPE | + TypeAnnotationParsingOptions::ALLOW_WILDCARD; return ParseTypeReference(&options); } @@ -560,8 +562,10 @@ ir::Expression *ETSParser::ParseSuperClassReference() ir::TypeNode *ETSParser::ParseInterfaceExtendsElement() { - TypeAnnotationParsingOptions options = - TypeAnnotationParsingOptions::THROW_ERROR | TypeAnnotationParsingOptions::DISALLOW_PRIMARY_TYPE; + TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR | + TypeAnnotationParsingOptions::DISALLOW_PRIMARY_TYPE | + TypeAnnotationParsingOptions::IGNORE_FUNCTION_TYPE | + TypeAnnotationParsingOptions::ALLOW_WILDCARD; return ParseTypeReference(&options); } @@ -879,7 +883,8 @@ ir::AstNode *ETSParser::ParseClassElement([[maybe_unused]] const ArenaVectorLookahead(); if (Lexer()->GetToken().KeywordType() == lexer::TokenType::KEYW_STATIC && nextCp != lexer::LEX_CHAR_EQUALS && - nextCp != lexer::LEX_CHAR_COLON && nextCp != lexer::LEX_CHAR_LEFT_PAREN) { + nextCp != lexer::LEX_CHAR_COLON && nextCp != lexer::LEX_CHAR_LEFT_PAREN && + nextCp != lexer::LEX_CHAR_LESS_THAN) { Lexer()->NextToken(); memberModifiers |= ir::ModifierFlags::STATIC; seenStatic = true; @@ -2256,8 +2261,9 @@ bool ETSParser::ParsePotentialGenericFunctionCall(ir::Expression *primaryExpr, i Lexer()->BackwardToken(lexer::TokenType::PUNCTUATOR_LESS_THAN, 1); } - TypeAnnotationParsingOptions options = - TypeAnnotationParsingOptions::DISALLOW_PRIMARY_TYPE | TypeAnnotationParsingOptions::IGNORE_FUNCTION_TYPE; + TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::DISALLOW_PRIMARY_TYPE | + TypeAnnotationParsingOptions::ALLOW_WILDCARD | + TypeAnnotationParsingOptions::IGNORE_FUNCTION_TYPE; ir::TSTypeParameterInstantiation *typeParams = ParseTypeParameterInstantiation(&options); if (typeParams == nullptr) { @@ -2271,7 +2277,7 @@ bool ETSParser::ParsePotentialGenericFunctionCall(ir::Expression *primaryExpr, i if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS) { if (!ignoreCallExpression) { - *returnExpression = ParseCallExpression(*returnExpression, false); + *returnExpression = ParseCallExpression(*returnExpression, false, false); (*returnExpression)->AsCallExpression()->SetTypeParams(typeParams); return false; } @@ -2317,7 +2323,7 @@ ir::Expression *ETSParser::ParsePostPrimaryExpression(ir::Expression *primaryExp break; } - returnExpression = ParseCallExpression(returnExpression, false); + returnExpression = ParseCallExpression(returnExpression, false, false); continue; } default: { @@ -2353,7 +2359,9 @@ ir::Expression *ETSParser::ParseNewExpression() TypeAnnotationParsingOptions options = TypeAnnotationParsingOptions::THROW_ERROR; ir::TypeNode *typeReference = ParseBaseTypeReference(&options); if (typeReference == nullptr) { - options |= TypeAnnotationParsingOptions::DISALLOW_PRIMARY_TYPE; + options |= TypeAnnotationParsingOptions::DISALLOW_PRIMARY_TYPE | + TypeAnnotationParsingOptions::IGNORE_FUNCTION_TYPE | + TypeAnnotationParsingOptions::ALLOW_WILDCARD; typeReference = ParseTypeReference(&options); } else if (Lexer()->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_BRACE) { ThrowSyntaxError("Invalid { after base types."); @@ -2488,6 +2496,7 @@ ir::TSTypeParameter *ETSParser::ParseTypeParameter([[maybe_unused]] TypeAnnotati Lexer()->NextToken(); TypeAnnotationParsingOptions newOptions = TypeAnnotationParsingOptions::THROW_ERROR | TypeAnnotationParsingOptions::ALLOW_INTERSECTION | + TypeAnnotationParsingOptions::IGNORE_FUNCTION_TYPE | TypeAnnotationParsingOptions::DISALLOW_PRIMARY_TYPE; constraint = ParseTypeAnnotation(&newOptions); } diff --git a/parser/expressionParser.cpp b/parser/expressionParser.cpp index e83ccde23..a96a127d4 100644 --- a/parser/expressionParser.cpp +++ b/parser/expressionParser.cpp @@ -1177,7 +1177,7 @@ ir::Expression *ParserImpl::ParseBinaryExpression(ir::Expression *left) return rightExpr; } -ir::CallExpression *ParserImpl::ParseCallExpression(ir::Expression *callee, bool isOptionalChain) +ir::CallExpression *ParserImpl::ParseCallExpression(ir::Expression *callee, bool isOptionalChain, bool handleEval) { ASSERT(lexer_->GetToken().Type() == lexer::TokenType::PUNCTUATOR_LEFT_PARENTHESIS); bool trailingComma {}; @@ -1207,7 +1207,7 @@ ir::CallExpression *ParserImpl::ParseCallExpression(ir::Expression *callee, bool ir::CallExpression *callExpr {}; - if (!isOptionalChain && callee->IsIdentifier() && callee->AsIdentifier()->Name().Is("eval")) { + if (!isOptionalChain && handleEval && callee->IsIdentifier() && callee->AsIdentifier()->Name().Is("eval")) { auto parserStatus = static_cast(context_.Status() | ParserStatus::DIRECT_EVAL); callExpr = AllocNode(callee, std::move(arguments), nullptr, isOptionalChain, parserStatus); diff --git a/parser/parserImpl.h b/parser/parserImpl.h index e2044a76e..f9db2c426 100644 --- a/parser/parserImpl.h +++ b/parser/parserImpl.h @@ -304,7 +304,8 @@ protected: ir::ArrowFunctionExpression *ParseArrowFunctionExpression(ir::Expression *expr, ir::TSTypeParameterDeclaration *typeParamDecl, ir::TypeNode *returnTypeAnnotation, bool isAsync); - ir::CallExpression *ParseCallExpression(ir::Expression *callee, bool isOptionalChain = false); + ir::CallExpression *ParseCallExpression(ir::Expression *callee, bool isOptionalChain = false, + bool handleEval = true); ir::TemplateLiteral *ParseTemplateLiteral(); ir::Expression *ParseLeftHandSideExpression(ExpressionParseFlags flags = ExpressionParseFlags::NO_OPTS); void ParseNameSpaceImport(ArenaVector *specifiers); @@ -383,6 +384,7 @@ protected: ParserStatus newStatus = ParserStatus::NO_OPTS); ir::ClassDeclaration *ParseClassDeclaration(ir::ClassDefinitionModifiers modifiers, ir::ModifierFlags flags = ir::ModifierFlags::NONE); + FunctionSignature ParseFunctionSignature(ParserStatus status); [[nodiscard]] virtual std::unique_ptr InitLexer(const std::string_view &fileName, const std::string_view &source); @@ -486,7 +488,6 @@ protected: virtual std::tuple ParseFunctionBody( const ArenaVector ¶ms, ParserStatus newStatus, ParserStatus contextStatus, binder::FunctionScope *funcScope); - virtual FunctionSignature ParseFunctionSignature(ParserStatus status); virtual ir::AstNode *ParseImportDefaultSpecifier(ArenaVector *specifiers); virtual ir::Statement *ParseExportDeclaration(StatementParsingFlags flags); diff --git a/test/parser/ets/generic_function-expected.txt b/test/parser/ets/generic_function-expected.txt index 5df0a47e6..42c0f5843 100644 --- a/test/parser/ets/generic_function-expected.txt +++ b/test/parser/ets/generic_function-expected.txt @@ -1 +1,902 @@ -SyntaxError: Unexpected token, expected: '('. [generic_function.ets:20:17] +{ + "type": "Program", + "statements": [ + { + "type": "TSInterfaceDeclaration", + "body": { + "type": "TSInterfaceBody", + "body": [ + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "localeCompare", + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 3 + }, + "end": { + "line": 17, + "column": 16 + } + } + }, + "kind": "method", + "accessibility": "public", + "static": false, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "localeCompare", + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 3 + }, + "end": { + "line": 17, + "column": 16 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [ + { + "type": "Identifier", + "name": "other", + "typeAnnotation": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "Object", + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 24 + }, + "end": { + "line": 17, + "column": 30 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 24 + }, + "end": { + "line": 17, + "column": 31 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 24 + }, + "end": { + "line": 17, + "column": 31 + } + } + }, + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 17 + }, + "end": { + "line": 17, + "column": 31 + } + } + } + ], + "returnType": { + "type": "ETSPrimitiveType", + "loc": { + "start": { + "line": 17, + "column": 33 + }, + "end": { + "line": 17, + "column": 36 + } + } + }, + "declare": true, + "loc": { + "start": { + "line": 17, + "column": 16 + }, + "end": { + "line": 17, + "column": 36 + } + } + }, + "loc": { + "start": { + "line": 17, + "column": 16 + }, + "end": { + "line": 17, + "column": 36 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 17, + "column": 3 + }, + "end": { + "line": 17, + "column": 36 + } + } + } + ], + "loc": { + "start": { + "line": 16, + "column": 23 + }, + "end": { + "line": 18, + "column": 2 + } + } + }, + "id": { + "type": "Identifier", + "name": "Comparable2", + "decorators": [], + "loc": { + "start": { + "line": 16, + "column": 11 + }, + "end": { + "line": 16, + "column": 22 + } + } + }, + "extends": [], + "loc": { + "start": { + "line": 16, + "column": 1 + }, + "end": { + "line": 20, + "column": 9 + } + } + }, + { + "type": "ClassDeclaration", + "definition": { + "id": { + "type": "Identifier", + "name": "ETSGLOBAL", + "decorators": [], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "superClass": null, + "implements": [], + "body": [ + { + "type": "MethodDefinition", + "key": { + "type": "Identifier", + "name": "compare", + "decorators": [], + "loc": { + "start": { + "line": 20, + "column": 10 + }, + "end": { + "line": 20, + "column": 17 + } + } + }, + "kind": "method", + "accessibility": "public", + "static": true, + "optional": false, + "computed": false, + "value": { + "type": "FunctionExpression", + "function": { + "type": "ScriptFunction", + "id": { + "type": "Identifier", + "name": "compare", + "decorators": [], + "loc": { + "start": { + "line": 20, + "column": 10 + }, + "end": { + "line": 20, + "column": 17 + } + } + }, + "generator": false, + "async": false, + "expression": false, + "params": [ + { + "type": "Identifier", + "name": "x", + "typeAnnotation": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "T", + "decorators": [], + "loc": { + "start": { + "line": 20, + "column": 44 + }, + "end": { + "line": 20, + "column": 45 + } + } + }, + "loc": { + "start": { + "line": 20, + "column": 44 + }, + "end": { + "line": 20, + "column": 46 + } + } + }, + "loc": { + "start": { + "line": 20, + "column": 44 + }, + "end": { + "line": 20, + "column": 46 + } + } + }, + "decorators": [], + "loc": { + "start": { + "line": 20, + "column": 41 + }, + "end": { + "line": 20, + "column": 46 + } + } + }, + { + "type": "Identifier", + "name": "y", + "typeAnnotation": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "T", + "decorators": [], + "loc": { + "start": { + "line": 20, + "column": 50 + }, + "end": { + "line": 20, + "column": 51 + } + } + }, + "loc": { + "start": { + "line": 20, + "column": 50 + }, + "end": { + "line": 20, + "column": 52 + } + } + }, + "loc": { + "start": { + "line": 20, + "column": 50 + }, + "end": { + "line": 20, + "column": 52 + } + } + }, + "decorators": [], + "loc": { + "start": { + "line": 20, + "column": 47 + }, + "end": { + "line": 20, + "column": 52 + } + } + } + ], + "returnType": { + "type": "ETSPrimitiveType", + "loc": { + "start": { + "line": 20, + "column": 54 + }, + "end": { + "line": 20, + "column": 57 + } + } + }, + "typeParameters": { + "type": "TSTypeParameterDeclaration", + "params": [ + { + "type": "TSTypeParameter", + "name": { + "type": "Identifier", + "name": "T", + "decorators": [], + "loc": { + "start": { + "line": 20, + "column": 18 + }, + "end": { + "line": 20, + "column": 19 + } + } + }, + "constraint": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "Comparable2", + "decorators": [], + "loc": { + "start": { + "line": 20, + "column": 28 + }, + "end": { + "line": 20, + "column": 39 + } + } + }, + "loc": { + "start": { + "line": 20, + "column": 28 + }, + "end": { + "line": 20, + "column": 40 + } + } + }, + "loc": { + "start": { + "line": 20, + "column": 28 + }, + "end": { + "line": 20, + "column": 40 + } + } + }, + "loc": { + "start": { + "line": 20, + "column": 18 + }, + "end": { + "line": 20, + "column": 40 + } + } + } + ], + "loc": { + "start": { + "line": 20, + "column": 17 + }, + "end": { + "line": 20, + "column": 40 + } + } + }, + "body": { + "type": "BlockStatement", + "statements": [ + { + "type": "IfStatement", + "test": { + "type": "BinaryExpression", + "operator": "==", + "left": { + "type": "Identifier", + "name": "x", + "decorators": [], + "loc": { + "start": { + "line": 21, + "column": 7 + }, + "end": { + "line": 21, + "column": 8 + } + } + }, + "right": { + "type": "NullLiteral", + "value": null, + "loc": { + "start": { + "line": 21, + "column": 12 + }, + "end": { + "line": 21, + "column": 16 + } + } + }, + "loc": { + "start": { + "line": 21, + "column": 7 + }, + "end": { + "line": 21, + "column": 16 + } + } + }, + "consequent": { + "type": "ReturnStatement", + "argument": { + "type": "ConditionalExpression", + "test": { + "type": "BinaryExpression", + "operator": "==", + "left": { + "type": "Identifier", + "name": "y", + "decorators": [], + "loc": { + "start": { + "line": 21, + "column": 25 + }, + "end": { + "line": 21, + "column": 26 + } + } + }, + "right": { + "type": "NullLiteral", + "value": null, + "loc": { + "start": { + "line": 21, + "column": 30 + }, + "end": { + "line": 21, + "column": 34 + } + } + }, + "loc": { + "start": { + "line": 21, + "column": 25 + }, + "end": { + "line": 21, + "column": 34 + } + } + }, + "consequent": { + "type": "NumberLiteral", + "value": 0, + "loc": { + "start": { + "line": 21, + "column": 37 + }, + "end": { + "line": 21, + "column": 38 + } + } + }, + "alternate": { + "type": "UnaryExpression", + "operator": "-", + "prefix": true, + "argument": { + "type": "NumberLiteral", + "value": 1, + "loc": { + "start": { + "line": 21, + "column": 42 + }, + "end": { + "line": 21, + "column": 43 + } + } + }, + "loc": { + "start": { + "line": 21, + "column": 41 + }, + "end": { + "line": 21, + "column": 43 + } + } + }, + "loc": { + "start": { + "line": 21, + "column": 25 + }, + "end": { + "line": 21, + "column": 43 + } + } + }, + "loc": { + "start": { + "line": 21, + "column": 18 + }, + "end": { + "line": 21, + "column": 44 + } + } + }, + "alternate": null, + "loc": { + "start": { + "line": 21, + "column": 3 + }, + "end": { + "line": 21, + "column": 44 + } + } + }, + { + "type": "IfStatement", + "test": { + "type": "BinaryExpression", + "operator": "==", + "left": { + "type": "Identifier", + "name": "y", + "decorators": [], + "loc": { + "start": { + "line": 22, + "column": 7 + }, + "end": { + "line": 22, + "column": 8 + } + } + }, + "right": { + "type": "NullLiteral", + "value": null, + "loc": { + "start": { + "line": 22, + "column": 12 + }, + "end": { + "line": 22, + "column": 16 + } + } + }, + "loc": { + "start": { + "line": 22, + "column": 7 + }, + "end": { + "line": 22, + "column": 16 + } + } + }, + "consequent": { + "type": "ReturnStatement", + "argument": { + "type": "NumberLiteral", + "value": 1, + "loc": { + "start": { + "line": 22, + "column": 25 + }, + "end": { + "line": 22, + "column": 26 + } + } + }, + "loc": { + "start": { + "line": 22, + "column": 18 + }, + "end": { + "line": 22, + "column": 27 + } + } + }, + "alternate": null, + "loc": { + "start": { + "line": 22, + "column": 3 + }, + "end": { + "line": 22, + "column": 27 + } + } + }, + { + "type": "ReturnStatement", + "argument": { + "type": "CallExpression", + "callee": { + "type": "MemberExpression", + "object": { + "type": "Identifier", + "name": "x", + "decorators": [], + "loc": { + "start": { + "line": 23, + "column": 10 + }, + "end": { + "line": 23, + "column": 11 + } + } + }, + "property": { + "type": "Identifier", + "name": "localeCompare", + "decorators": [], + "loc": { + "start": { + "line": 23, + "column": 12 + }, + "end": { + "line": 23, + "column": 25 + } + } + }, + "computed": false, + "optional": false, + "loc": { + "start": { + "line": 23, + "column": 10 + }, + "end": { + "line": 23, + "column": 25 + } + } + }, + "arguments": [ + { + "type": "Identifier", + "name": "y", + "decorators": [], + "loc": { + "start": { + "line": 23, + "column": 26 + }, + "end": { + "line": 23, + "column": 27 + } + } + } + ], + "optional": false, + "loc": { + "start": { + "line": 23, + "column": 10 + }, + "end": { + "line": 23, + "column": 28 + } + } + }, + "loc": { + "start": { + "line": 23, + "column": 3 + }, + "end": { + "line": 23, + "column": 29 + } + } + } + ], + "loc": { + "start": { + "line": 20, + "column": 58 + }, + "end": { + "line": 24, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 20, + "column": 17 + }, + "end": { + "line": 24, + "column": 2 + } + } + }, + "loc": { + "start": { + "line": 20, + "column": 17 + }, + "end": { + "line": 24, + "column": 2 + } + } + }, + "overloads": [], + "decorators": [], + "loc": { + "start": { + "line": 20, + "column": 1 + }, + "end": { + "line": 24, + "column": 2 + } + } + } + ], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 1 + } + } + } + ], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 25, + "column": 1 + } + } +} +TypeError: Extends constraint must be an object [generic_function.ets:20:28] diff --git a/test/parser/ets/generic_function.ets b/test/parser/ets/generic_function.ets index d2c097d70..3f7aebabb 100644 --- a/test/parser/ets/generic_function.ets +++ b/test/parser/ets/generic_function.ets @@ -13,11 +13,11 @@ * limitations under the License. */ -interface Comparable { +interface Comparable2 { localeCompare(other: Object): int; } -function compare(x: T, y: T): int { +function compare(x: T, y: T): int { if (x == null) return y == null ? 0 : -1; if (y == null) return 1; return x.localeCompare(y); diff --git a/test/parser/ets/type_variance4-expected.txt b/test/parser/ets/type_variance4-expected.txt index 8b9967672..3976c5fe6 100644 --- a/test/parser/ets/type_variance4-expected.txt +++ b/test/parser/ets/type_variance4-expected.txt @@ -1 +1 @@ -SyntaxError: Unexpected token, expected: '('. [type_variance4.ets:18:12] +SyntaxError: Variance modifier is not allowed here. [type_variance4.ets:18:13] diff --git a/test/runtime/ets/generic-function.ets b/test/runtime/ets/generic-function.ets new file mode 100644 index 000000000..9be4ad121 --- /dev/null +++ b/test/runtime/ets/generic-function.ets @@ -0,0 +1,28 @@ +class cls extends Object { + override toString() : String { + return "cls"; + } +} + +function foo(item : T) : String { + let str = item.toString(); + return str; +} + +function bar() : T { + // crash + // let x : T; + return new T(); +} + +function main() : void { +/* TypeError: No matching call signature + foo(10); + foo(new Int(20)); + foo(new cls()); +*/ + bar(); + bar(); + bar(); + bar(); +} diff --git a/test/runtime/ets/generic-set.ets b/test/runtime/ets/generic-set.ets new file mode 100644 index 000000000..642957de5 --- /dev/null +++ b/test/runtime/ets/generic-set.ets @@ -0,0 +1,81 @@ +interface MyStack { + getTop() : Item; + pop() : Item; + push(item : Item) : void; + isEmpty() : boolean; + size() : int; +} + +class MyArrayStack implements MyStack { + + private container : Item[]; + private top : int = -1; + private const DEFAULT_SIZE : int = 100; + + constructor() { + container = new Item[DEFAULT_SIZE]; + top = -1; + } + + constructor(size: int) { + container = new Item[size]; + } + + override getTop() : Item { + if (top == -1) { + return null; + } + return container[top]; + } + + override pop() : Item { + if (top == -1) { + return null; + } + return container[top--]; + } + + override push(item : Item) : void { + container[++top] = item; + } + + override isEmpty() : boolean { + return (top == -1); + } + + override size() : int { + return (top + 1); + } +} + +function main() : void { + let stack1 : MyArrayStack; + stack1 = new MyArrayStack(); + assert(stack1.isEmpty() == true); + assert(stack1.size() == 0); + + stack1.push(new Int(10)); + assert(stack1.isEmpty() == false); + assert(stack1.size() == 1); + assert(stack1.getTop() == 10); + + stack1.push(new Int(20)); + stack1.push(new Int(30)); + assert(stack1.isEmpty() == false); + assert(stack1.size() == 3); + assert(stack1.getTop() == 30); + + assert(stack1.pop() == 30); + assert(stack1.size() == 2); + assert(stack1.pop() == 20); + assert(stack1.size() == 1); + assert(stack1.pop() == 10); + assert(stack1.size() == 0); + assert(stack1.isEmpty() == true); + + assert(stack1.getTop() == null); + assert(stack1.pop() == null); + assert(stack1.size() == 0); + assert(stack1.isEmpty() == true); + +} -- Gitee