From 175476b04b01ea939a36a4ee0a1654c023cff9e3 Mon Sep 17 00:00:00 2001 From: xingshunxiang Date: Fri, 15 Aug 2025 17:22:46 +0800 Subject: [PATCH] Revert Frontend PR7225 Fix CTE when assign class prop in namespace Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/ICT7VG?from=project-issue Description: Revert Frontend PR7225 Reason: Revert Frontend PR7225 Tests: ninja tests passed tests/tests-u-runner/runner.sh --ets-cts --show-progress --build-dir x64.release --processes=all passed tests/tests-u-runner/runner.sh --ets-func-tests --show-progress --build-dir x64.release --processes=all passed tests/tests-u-runner/runner.sh --astchecker --show-progress --build-dir x64.release --processes=all passed tests/tests-u-runner/runner.sh --ets-runtime --show-progress --build-dir x64.release --processes=all passed tests/tests-u-runner/runner.sh --parser --no-js --show-progress --build-dir x64.release --processes=all passed Signed-off-by: xingshunxiang --- .../invariants/getterSetterValidation.cpp | 22 ++++++ ets2panda/checker/ETSAnalyzer.cpp | 3 +- ets2panda/checker/ETSAnalyzer.h | 18 +++++ ets2panda/checker/ETSAnalyzerHelpers.cpp | 17 ++++ ets2panda/checker/ETSchecker.h | 4 +- ets2panda/checker/ets/function.cpp | 19 ++++- ets2panda/checker/ets/helpers.cpp | 10 +-- ets2panda/checker/ets/typeCheckingHelpers.cpp | 40 ++-------- ets2panda/checker/ets/typeRelationContext.cpp | 6 +- ets2panda/checker/types/ets/etsNeverType.cpp | 2 +- ets2panda/checker/types/ets/etsUnionType.cpp | 4 +- ets2panda/checker/types/ets/etsVoidType.cpp | 26 +++---- ets2panda/checker/types/signature.cpp | 4 + ets2panda/compiler/core/ETSCompiler.cpp | 4 - ets2panda/compiler/core/ETSGen.cpp | 15 ++-- .../lowering/ets/enumPostCheckLowering.cpp | 2 +- .../lowering/ets/expressionLambdaLowering.cpp | 4 +- .../lowering/ets/genericBridgesLowering.cpp | 5 +- .../compiler/lowering/ets/lambdaLowering.cpp | 36 +-------- .../compiler/lowering/ets/unboxLowering.cpp | 3 +- .../ir/expressions/arrowFunctionExpression.h | 11 --- ets2panda/ir/statements/forOfStatement.cpp | 2 +- .../ast/compiler/ets/Incorrect_arrow_func.ets | 1 + .../compiler/ets/absent_return_statement.ets | 22 +++--- .../extensionGetMustReturnValue.ets | 4 +- .../ast/compiler/ets/type_error_test2.ets | 1 + .../ets/unmatch_arg_for_trailing_lambda.ets | 2 +- .../ast/compiler/ets/voidTypeArg_neg_1.ets | 24 ------ .../ets/voidTypeInBinaryOperation.ets | 6 +- .../ets/void_as_return_type_neg_2.ets | 2 +- .../ast/compiler/ets/void_as_value_neg_4.ets | 3 +- .../ets/FixedArray/MultipleParserErrors.ets | 20 +++-- .../ets/FixedArray/unexpected_token_31.ets | 1 + .../test/ast/parser/ets/InvalidParserImpl.ets | 1 + .../ast/parser/ets/InvalidStatements2.ets | 1 + .../ast/parser/ets/MultipleParserErrors.ets | 12 ++- .../test/ast/parser/ets/accessor_void.ets | 2 + .../extension_function_error2.ets | 1 + .../test/ast/parser/ets/static_block.ets | 1 + ...ing_lambda_mismatch_lambda_signature_1.ets | 2 +- ...ing_lambda_mismatch_lambda_signature_2.ets | 2 +- .../ast/parser/ets/unexpected_token_31.ets | 1 + .../ast/parser/ets/update_funcscope_error.ets | 1 + .../test/runtime/ets/async_return_void_2.ets | 2 +- .../test/runtime/ets/async_return_void_3.ets | 2 +- ets2panda/test/runtime/ets/voidTypeArg.ets | 4 + .../ast_verifier_getter_setter_neg_test.cpp | 77 +++++++++++++++++++ ets2panda/util/diagnostic/semantic.yaml | 10 ++- 48 files changed, 267 insertions(+), 195 deletions(-) delete mode 100644 ets2panda/test/ast/compiler/ets/voidTypeArg_neg_1.ets diff --git a/ets2panda/ast_verifier/invariants/getterSetterValidation.cpp b/ets2panda/ast_verifier/invariants/getterSetterValidation.cpp index cd9cf38c86..300639288b 100644 --- a/ets2panda/ast_verifier/invariants/getterSetterValidation.cpp +++ b/ets2panda/ast_verifier/invariants/getterSetterValidation.cpp @@ -70,6 +70,20 @@ bool GetterSetterValidation::ValidateGetter(ir::MethodDefinition const *const me report("GETTER METHOD DOES NOT HAVE GETTER FLAG"); } + // Check return type annotation if it exists + if (function->ReturnTypeAnnotation() != nullptr) { + auto const *const type = function->ReturnTypeAnnotation()->TsType(); + if (type != nullptr && type->IsETSVoidType()) { + report("GETTER METHOD HAS VOID RETURN TYPE IN RETURN TYPE ANNOTATION"); + } + } + + // For non-abstract, non-ambient and non-native getters return statement should always exist + if (!function->HasReturnStatement() && !function->HasThrowStatement() && !function->IsAbstract() && + !function->IsDeclare() && !function->IsNative()) { + report("MISSING RETURN STATEMENT IN GETTER METHOD"); + } + // Check return statements auto const &returns = function->ReturnStatements(); if (function->ReturnTypeAnnotation() == nullptr) { @@ -78,6 +92,14 @@ bool GetterSetterValidation::ValidateGetter(ir::MethodDefinition const *const me } } + // Check that all return statements are not void + for (auto const *const stmt : returns) { + if (stmt->ReturnType()->IsETSVoidType()) { + // All getters should have non-void return type + report("GETTER METHOD HAS VOID RETURN TYPE"); + } + } + // Check number of arguments auto const ¶ms = function->Params(); if (!params.empty()) { diff --git a/ets2panda/checker/ETSAnalyzer.cpp b/ets2panda/checker/ETSAnalyzer.cpp index 2f25b810ce..110ba4ec5c 100644 --- a/ets2panda/checker/ETSAnalyzer.cpp +++ b/ets2panda/checker/ETSAnalyzer.cpp @@ -1388,7 +1388,6 @@ checker::Type *ETSAnalyzer::Check(ir::AwaitExpression *expr) const } expr->SetTsType(checker->HandleAwaitExpression(expr->argument_->Check(checker), expr)); - checker->CheckVoidTypeExpression(expr); return expr->TsType(); } @@ -1727,7 +1726,7 @@ checker::Type *ETSAnalyzer::Check(ir::CallExpression *expr) const } CheckOverloadCall(checker, expr); - checker->CheckVoidTypeExpression(expr); + CheckVoidTypeExpression(checker, expr); CheckAbstractCall(checker, expr); return expr->TsType(); } diff --git a/ets2panda/checker/ETSAnalyzer.h b/ets2panda/checker/ETSAnalyzer.h index 4b2adeea2a..94fe5f4030 100644 --- a/ets2panda/checker/ETSAnalyzer.h +++ b/ets2panda/checker/ETSAnalyzer.h @@ -71,6 +71,24 @@ private: checker::Type *ResolveMemberExpressionByBaseType(ETSChecker *checker, checker::Type *baseType, ir::MemberExpression *expr) const; + void CheckVoidTypeExpression(ETSChecker *checker, const ir::Expression *expr) const + { + // Existing void expression inconsistency,refer to #17762 + if (expr->TsType() == nullptr || !expr->TsType()->IsETSVoidType() || expr->Parent() == nullptr) { + return; + } + auto parent = expr->Parent(); + while (parent->IsConditionalExpression()) { + parent = parent->Parent(); + if (parent == nullptr) { + return; + } + } + bool acceptVoid = parent->IsExpressionStatement() || parent->IsReturnStatement(); + if (!acceptVoid) { + checker->LogError(diagnostic::VOID_VALUE, {}, expr->Start()); + } + } mutable std::vector catchParamStack_ {}; }; diff --git a/ets2panda/checker/ETSAnalyzerHelpers.cpp b/ets2panda/checker/ETSAnalyzerHelpers.cpp index c0ed36c716..d3127e33aa 100644 --- a/ets2panda/checker/ETSAnalyzerHelpers.cpp +++ b/ets2panda/checker/ETSAnalyzerHelpers.cpp @@ -273,6 +273,10 @@ void CheckPredefinedMethodReturnType(ETSChecker *checker, ir::ScriptFunction *sc auto const &position = scriptFunc->Start(); + if (scriptFunc->IsGetter() && (scriptFunc->Signature()->ReturnType() == checker->GlobalVoidType())) { + checker->LogError(diagnostic::GETTER_VOID, {}, position); + } + auto const name = scriptFunc->Id()->Name(); auto const methodName = std::string {ir::PREDEFINED_METHOD} + std::string {name.Utf8()}; @@ -605,6 +609,14 @@ bool CheckArgumentVoidType(checker::Type *funcReturnType, ETSChecker *checker, c bool CheckReturnType(ETSChecker *checker, checker::Type *funcReturnType, checker::Type *argumentType, ir::Expression *stArgument, ir::ScriptFunction *containingFunc) { + if (funcReturnType->IsETSVoidType() || funcReturnType == checker->GlobalVoidType()) { + if (argumentType != checker->GlobalVoidType()) { + checker->LogError(diagnostic::UNEXPECTED_VALUE_RETURN, {}, stArgument->Start()); + return false; + } + return true; + } + if (containingFunc->IsAsyncFunc() && funcReturnType->IsETSObjectType() && funcReturnType->AsETSObjectType()->GetOriginalBaseType() == checker->GlobalBuiltinPromiseType()) { auto promiseArg = funcReturnType->AsETSObjectType()->TypeArguments()[0]; @@ -706,6 +718,11 @@ checker::Type *ProcessReturnStatements(ETSChecker *checker, ir::ScriptFunction * // previous return statement(s) don't have any value ES2PANDA_ASSERT(argumentType != nullptr); + if (funcReturnType->IsETSVoidType() && !argumentType->IsETSVoidType()) { + checker->LogError(diagnostic::MIXED_VOID_NONVOID, {}, stArgument->Start()); + return funcReturnType; + } + const auto name = containingFunc->Scope()->InternalName().Mutf8(); if (!CheckArgumentVoidType(funcReturnType, checker, name, st)) { return funcReturnType; diff --git a/ets2panda/checker/ETSchecker.h b/ets2panda/checker/ETSchecker.h index 97e8a6d3c3..a42ab34a91 100644 --- a/ets2panda/checker/ETSchecker.h +++ b/ets2panda/checker/ETSchecker.h @@ -631,7 +631,7 @@ public: Type *GetNonConstantType(Type *type); checker::Type *GetElementTypeOfArray(checker::Type *type) const; const checker::Type *GetElementTypeOfArray(const checker::Type *type) const; - bool IsNullLikeExpression(const ir::Expression *expr) const; + bool IsNullLikeOrVoidExpression(const ir::Expression *expr) const; bool IsConstantExpression(ir::Expression *expr, Type *type); void ValidateUnaryOperatorOperand(varbinder::Variable *variable, ir::Expression *expr); void CheckFunctionSignatureAnnotations(const ArenaVector ¶ms, @@ -769,8 +769,6 @@ public: ArenaVector &&args); Signature *FindRelativeExtensionGetter(ir::MemberExpression *const expr, ETSFunctionType *funcType); Signature *FindRelativeExtensionSetter(ir::MemberExpression *const expr, ETSFunctionType *funcType); - static bool IsTypeVoidOrUnionContainsVoid(const Type *const possibleVoidType); - void CheckVoidTypeExpression(const ir::Expression *expr); Type *GetExtensionAccessorReturnType(ir::MemberExpression *expr); // Utility type handler functions std::optional GetUtilityTypeTypeParamNode(const ir::TSTypeParameterInstantiation *typeParams, diff --git a/ets2panda/checker/ets/function.cpp b/ets2panda/checker/ets/function.cpp index 5ec50aaf72..dec595875f 100644 --- a/ets2panda/checker/ets/function.cpp +++ b/ets2panda/checker/ets/function.cpp @@ -73,7 +73,10 @@ bool ETSChecker::IsCompatibleTypeArgument(ETSTypeParameter *typeParam, Type *typ if (typeArgument->IsTypeError()) { return true; } - + // NOTE(vpukhov): #19701 void refactoring + if (typeArgument->IsETSVoidType()) { + typeArgument = GlobalETSUndefinedType(); + } ES2PANDA_ASSERT(IsReferenceType(typeArgument)); auto constraint = typeParam->GetConstraintType()->Substitute(Relation(), substitution); return Relation()->IsSupertypeOf(constraint, typeArgument); @@ -1914,8 +1917,6 @@ bool ETSChecker::IsMethodOverridesOther(Signature *base, Signature *derived) OverrideErrorCode ETSChecker::CheckOverride(Signature *signature, Signature *other) { - SavedTypeRelationFlagsContext savedFlagsCtx(Relation(), TypeRelationFlag::OVERRIDING_CONTEXT); - if (other->HasSignatureFlag(SignatureFlags::STATIC)) { ES2PANDA_ASSERT(signature->HasSignatureFlag(SignatureFlags::STATIC)); return OverrideErrorCode::NO_ERROR; @@ -2269,6 +2270,18 @@ bool ETSChecker::IsReturnTypeSubstitutable(Signature *const s1, Signature *const // A method declaration d1 with return type R1 is return-type-substitutable for another method d2 with return // type R2 if any of the following is true: + // NOTE(vpukhov): void type leaks into type arguments, so we have to check the original signature if the return type + // is parametrized or not to use a proper subtyping check. To be replaced with IsETSPrimitiveType after #19701. + auto const hasPrimitiveReturnType = [](Signature *s) { + bool origIsRef = s->Function()->Signature()->ReturnType()->IsETSReferenceType(); + ES2PANDA_ASSERT_POS(origIsRef == s->ReturnType()->IsETSReferenceType(), s->Function()->Start()); + return !origIsRef; + }; + // - If R1 is a primitive type then R2 is identical to R1. + if (hasPrimitiveReturnType(s1) || hasPrimitiveReturnType(s2)) { + return Relation()->IsIdenticalTo(r2, r1); + } + auto const hasThisReturnType = [](Signature *s) { auto *retAnn = s->Function()->ReturnTypeAnnotation(); return retAnn != nullptr && retAnn->IsTSThisType(); diff --git a/ets2panda/checker/ets/helpers.cpp b/ets2panda/checker/ets/helpers.cpp index 7c7f91dbef..7af0038d52 100644 --- a/ets2panda/checker/ets/helpers.cpp +++ b/ets2panda/checker/ets/helpers.cpp @@ -450,14 +450,16 @@ Type *ETSChecker::ApplyUnaryOperatorPromotion(ir::Expression *expr, Type *type, return type; } -bool ETSChecker::IsNullLikeExpression(const ir::Expression *expr) const +bool ETSChecker::IsNullLikeOrVoidExpression(const ir::Expression *expr) const { - return expr->TsType()->DefinitelyETSNullish(); + // NOTE(vpukhov): #19701 void refactoring + return expr->TsType()->DefinitelyETSNullish() || expr->TsType()->IsETSVoidType(); } std::tuple ETSChecker::IsResolvedAndValue(const ir::Expression *expr, Type *type) const { - auto [isResolve, isValue] = IsNullLikeExpression(expr) ? std::make_tuple(true, false) : IsConstantTestValue(expr); + auto [isResolve, isValue] = + IsNullLikeOrVoidExpression(expr) ? std::make_tuple(true, false) : IsConstantTestValue(expr); const Type *tsType = expr->TsType(); if (tsType->DefinitelyNotETSNullish() && !type->IsETSPrimitiveOrEnumType()) { @@ -2680,10 +2682,8 @@ void ETSChecker::InferTypesForLambda(ir::ScriptFunction *lambda, ir::ETSFunction inferredType = GetElementTypeOfArray(maybeSubstitutedFunctionSig->RestVar()->TsType()); } } - lambdaParam->Variable()->SetTsType(inferredType); lambdaParam->SetTsType(inferredType); - CheckVoidTypeExpression(lambdaParam); } if (lambda->ReturnTypeAnnotation() == nullptr) { diff --git a/ets2panda/checker/ets/typeCheckingHelpers.cpp b/ets2panda/checker/ets/typeCheckingHelpers.cpp index f3bd5643d6..6f0a218600 100644 --- a/ets2panda/checker/ets/typeCheckingHelpers.cpp +++ b/ets2panda/checker/ets/typeCheckingHelpers.cpp @@ -385,9 +385,12 @@ bool Type::IsETSMethodType() const TypeFlag::ETS_TYPE_PARAMETER | TypeFlag::WILDCARD | TypeFlag::ETS_NONNULLISH | TypeFlag::ETS_REQUIRED_TYPE_PARAMETER | TypeFlag::ETS_ANY | TypeFlag::ETS_NEVER | TypeFlag::ETS_UNION | TypeFlag::ETS_ARRAY | TypeFlag::FUNCTION | TypeFlag::ETS_PARTIAL_TYPE_PARAMETER | TypeFlag::ETS_TUPLE | - TypeFlag::ETS_ENUM | TypeFlag::ETS_READONLY | TypeFlag::GRADUAL_TYPE | TypeFlag::ETS_VOID | - TypeFlag::ETS_AWAITED; + TypeFlag::ETS_ENUM | TypeFlag::ETS_READONLY | TypeFlag::GRADUAL_TYPE | TypeFlag::ETS_AWAITED; + // Issues + if (type->IsETSVoidType()) { // NOTE(vpukhov): #19701 void refactoring + return true; + } if (type->IsETSTypeAliasType()) { // NOTE(vpukhov): #20561 return true; } @@ -1849,39 +1852,6 @@ void ETSChecker::CheckInterfaceMethodOverloadDeclaration(ETSChecker *checker, ir } } -bool ETSChecker::IsTypeVoidOrUnionContainsVoid(const Type *const possibleVoidType) -{ - return possibleVoidType->IsETSVoidType() || - (possibleVoidType->IsETSUnionType() && - possibleVoidType->AsETSUnionType()->AnyOfConstituentTypes( - [](const checker::Type *consType) { return consType->IsETSVoidType(); })); -} - -void ETSChecker::CheckVoidTypeExpression(const ir::Expression *expr) -{ - // Existing void expression inconsistency,refer to #17762 - const bool isExpressionNotVoidType = - expr->TsType() == nullptr || expr->Parent() == nullptr || !IsTypeVoidOrUnionContainsVoid(expr->TsType()); - if (isExpressionNotVoidType) { - return; - } - - const auto *parent = expr->Parent(); - while (parent->IsConditionalExpression()) { - parent = parent->Parent(); - if (parent == nullptr) { - return; - } - } - - // NOTE (smartin): The case for return statement will need to be removed. Currently some generated code uses it, - // that can't be modified. Codegen will load an 'undefined' value instead. - const bool acceptVoid = parent->IsExpressionStatement() || parent->IsReturnStatement(); - if (!acceptVoid) { - LogError(diagnostic::VOID_VALUE, {}, expr->Start()); - } -} - void ETSChecker::CheckConstructorOverloadDeclaration(ETSChecker *checker, ir::OverloadDeclaration *node) const { for (auto *overloadedName : node->OverloadedList()) { diff --git a/ets2panda/checker/ets/typeRelationContext.cpp b/ets2panda/checker/ets/typeRelationContext.cpp index a4dbb310cb..d2835dec80 100644 --- a/ets2panda/checker/ets/typeRelationContext.cpp +++ b/ets2panda/checker/ets/typeRelationContext.cpp @@ -123,9 +123,11 @@ static void CheckInstantiationConstraints(ETSChecker *checker, ArenaVectorIsTypeError()) { continue; } - ES2PANDA_ASSERT(typeArg->IsETSReferenceType()); + // NOTE(vpukhov): #19701 void refactoring + ES2PANDA_ASSERT(typeArg->IsETSReferenceType() || typeArg->IsETSVoidType()); + auto maybeIrrelevantTypeArg = typeArg->IsETSVoidType() ? checker->GlobalETSUndefinedType() : typeArg; auto constraint = typeParam->GetConstraintType()->Substitute(relation, substitution); - if (!relation->IsSupertypeOf(constraint, typeArg)) { + if (!relation->IsSupertypeOf(constraint, maybeIrrelevantTypeArg)) { checker->LogError(diagnostic::TYPEARG_TYPEPARAM_SUBTYPING, {typeArg, constraint}, pos); } } diff --git a/ets2panda/checker/types/ets/etsNeverType.cpp b/ets2panda/checker/types/ets/etsNeverType.cpp index 7eb22f2d50..0b5401c3ba 100644 --- a/ets2panda/checker/types/ets/etsNeverType.cpp +++ b/ets2panda/checker/types/ets/etsNeverType.cpp @@ -86,4 +86,4 @@ Type *ETSNeverType::Instantiate([[maybe_unused]] ArenaAllocator *allocator, [[ma { return allocator->New(); } -} // namespace ark::es2panda::checker +} // namespace ark::es2panda::checker \ No newline at end of file diff --git a/ets2panda/checker/types/ets/etsUnionType.cpp b/ets2panda/checker/types/ets/etsUnionType.cpp index 09676d80a6..b927ff0afe 100644 --- a/ets2panda/checker/types/ets/etsUnionType.cpp +++ b/ets2panda/checker/types/ets/etsUnionType.cpp @@ -250,10 +250,10 @@ static std::optional TryMergeTypes(TypeRelation *relation, Type *const t auto *const checker = relation->GetChecker()->AsETSChecker(); auto *const never = checker->GetGlobalTypesHolder()->GlobalETSNeverType(); - if (relation->IsSupertypeOf(t1, t2) || relation->IsIdenticalTo(t2, never)) { + if (relation->IsSupertypeOf(t1, t2) || t2 == never) { return t1; } - if (relation->IsSupertypeOf(t2, t1) || relation->IsIdenticalTo(t1, never)) { + if (relation->IsSupertypeOf(t2, t1) || t1 == never) { return t2; } return std::nullopt; diff --git a/ets2panda/checker/types/ets/etsVoidType.cpp b/ets2panda/checker/types/ets/etsVoidType.cpp index c1e859faa0..0fe7ede620 100644 --- a/ets2panda/checker/types/ets/etsVoidType.cpp +++ b/ets2panda/checker/types/ets/etsVoidType.cpp @@ -25,31 +25,29 @@ void ETSVoidType::Identical(TypeRelation *relation, Type *other) void ETSVoidType::IsSupertypeOf(TypeRelation *const relation, Type *source) { - if (relation->IsOverridingCheck()) { - relation->Result(false); - return; - } - - relation->Result(source->IsETSUndefinedType() || source->IsETSNeverType()); + relation->Result(source->IsETSUndefinedType()); } bool ETSVoidType::AssignmentSource(TypeRelation *relation, Type *target) { - if (relation->IsOverridingCheck()) { - return relation->Result(false); + // NOTE(vpukhov): #19701 void refactoring + if (!target->IsETSUndefinedType()) { + Identical(relation, target); + } else { + relation->Result(true); } - return relation->Result(target->IsETSAnyType()); + return relation->IsTrue(); } void ETSVoidType::AssignmentTarget([[maybe_unused]] TypeRelation *relation, [[maybe_unused]] Type *source) { - if (relation->IsOverridingCheck()) { - relation->Result(false); - return; + // NOTE(vpukhov): #19701 void refactoring + if (!source->IsETSUndefinedType()) { + Identical(relation, source); + } else { + relation->Result(true); } - - relation->Result(source->IsETSUndefinedType() || source->IsETSNeverType()); } Type *ETSVoidType::Instantiate([[maybe_unused]] ArenaAllocator *allocator, [[maybe_unused]] TypeRelation *relation, diff --git a/ets2panda/checker/types/signature.cpp b/ets2panda/checker/types/signature.cpp index 7fe0932483..0aaeab3066 100644 --- a/ets2panda/checker/types/signature.cpp +++ b/ets2panda/checker/types/signature.cpp @@ -51,6 +51,10 @@ Signature *Signature::Substitute(TypeRelation *relation, const Substitution *sub if (newParamType != param->TsType()) { anyChange = true; newParam = param->Copy(allocator, param->Declaration()); + if (newParamType->IsETSVoidType()) { + // since `void` is not allowed to be used as param type + newParamType = checker->GlobalETSUndefinedType(); + } newParam->SetTsType(newParamType); } newSigInfo->params.push_back(newParam); diff --git a/ets2panda/compiler/core/ETSCompiler.cpp b/ets2panda/compiler/core/ETSCompiler.cpp index 9afe0f1b71..cc7cef4a40 100644 --- a/ets2panda/compiler/core/ETSCompiler.cpp +++ b/ets2panda/compiler/core/ETSCompiler.cpp @@ -1427,9 +1427,6 @@ void ETSCompiler::Compile(const ir::ReturnStatement *st) const return; } - // NOTE (smartin): This case needs to be deleted, and asserted, that we won't return with a call to a void function. - // Some taihe generated code couldn't be modified accordingly, so until solution this stays here, but eventually - // this needs to be removed. if (argument->IsCallExpression() && argument->AsCallExpression()->Signature()->ReturnType()->IsETSVoidType()) { argument->Compile(etsg); @@ -1444,7 +1441,6 @@ void ETSCompiler::Compile(const ir::ReturnStatement *st) const etsg->LoadDefaultValue(st, etsg->ReturnType()); etsg->ReturnAcc(st); } - return; } diff --git a/ets2panda/compiler/core/ETSGen.cpp b/ets2panda/compiler/core/ETSGen.cpp index 0b745c71f6..5d2309adfc 100644 --- a/ets2panda/compiler/core/ETSGen.cpp +++ b/ets2panda/compiler/core/ETSGen.cpp @@ -775,9 +775,7 @@ void ETSGen::CheckedReferenceNarrowingObject(const ir::AstNode *node, const chec // Implemented on top of the runtime type system, do not relax checks, do not introduce new types void ETSGen::CheckedReferenceNarrowing(const ir::AstNode *node, const checker::Type *target) { - // NOTE(smartin): When void is returned FE validates to not use the value, so accumulator type won't ever be - // accessed. Currently setting the target type is necessary, because only in one case we allow this construction, - // when a function returns a call to another void function. This case will be eventually removed. + // NOTE(vpukhov): #19701 void refactoring if (target->IsETSVoidType()) { SetAccumulatorType(target); return; @@ -1719,11 +1717,12 @@ void ETSGen::BranchIfNullish(const ir::AstNode *node, Label *ifNullish) auto *const type = GetAccumulatorType(); ES2PANDA_ASSERT(type != nullptr); - if (type->DefinitelyNotETSNullish()) { - return; - } - - if (type->DefinitelyETSNullish()) { + if (type->IsETSVoidType()) { + // NOTE(): #19701 need void refactoring + Sa().Emit(node, ifNullish); + } else if (type->DefinitelyNotETSNullish()) { + // no action + } else if (type->DefinitelyETSNullish()) { Sa().Emit(node, ifNullish); } else if (!type->PossiblyETSNull()) { Sa().Emit(node, ifNullish); diff --git a/ets2panda/compiler/lowering/ets/enumPostCheckLowering.cpp b/ets2panda/compiler/lowering/ets/enumPostCheckLowering.cpp index c72860f3d2..e62ba6a091 100644 --- a/ets2panda/compiler/lowering/ets/enumPostCheckLowering.cpp +++ b/ets2panda/compiler/lowering/ets/enumPostCheckLowering.cpp @@ -413,7 +413,7 @@ ir::AstNode *EnumPostCheckLoweringPhase::BuildEnumCasting(ir::AstNode *const nod return node; } return GenerateEnumCasting(node->AsTSAsExpression(), castFlag); -} +}; bool EnumPostCheckLoweringPhase::PerformForModule(public_lib::Context *ctx, parser::Program *program) { diff --git a/ets2panda/compiler/lowering/ets/expressionLambdaLowering.cpp b/ets2panda/compiler/lowering/ets/expressionLambdaLowering.cpp index d99b165b5c..e09b2b2af2 100644 --- a/ets2panda/compiler/lowering/ets/expressionLambdaLowering.cpp +++ b/ets2panda/compiler/lowering/ets/expressionLambdaLowering.cpp @@ -31,9 +31,7 @@ static ir::AstNode *ConvertExpression(public_lib::Context *ctx, ir::ArrowFunctio function->ReturnTypeAnnotation()->AsETSPrimitiveType()->GetPrimitiveType() == ir::PrimitiveType::VOID)) { statements.emplace_back(ctx->AllocNode(expr)); } else { - auto *const newReturnNode = ctx->AllocNode(expr); - arrow->SetConvertedLambdaMayNeedFix(); - statements.emplace_back(newReturnNode); + statements.emplace_back(ctx->AllocNode(expr)); function->AddFlag(ir::ScriptFunctionFlags::HAS_RETURN); } diff --git a/ets2panda/compiler/lowering/ets/genericBridgesLowering.cpp b/ets2panda/compiler/lowering/ets/genericBridgesLowering.cpp index 4200e1366a..7ec0e78cdb 100644 --- a/ets2panda/compiler/lowering/ets/genericBridgesLowering.cpp +++ b/ets2panda/compiler/lowering/ets/genericBridgesLowering.cpp @@ -67,10 +67,7 @@ std::string GenericBridgesPhase::CreateMethodDefinitionString(ir::ClassDefinitio typeNodes.emplace_back(context_->AllocNode( const_cast(classDefinition->TsType()), context_->Allocator())); - - const bool isDerivedFunctionReturnVoid = derivedFunction->Signature()->ReturnType()->IsETSVoidType(); - const std::string possibleReturnStatement = isDerivedFunctionReturnVoid ? "" : "return "; - str2 = "{ " + possibleReturnStatement + "(this as @@T" + std::to_string(typeNodes.size()) + str2 + "); }"; + str2 = "{ return (this as @@T" + std::to_string(typeNodes.size()) + str2 + "); }"; str1 += str2; return str1; diff --git a/ets2panda/compiler/lowering/ets/lambdaLowering.cpp b/ets2panda/compiler/lowering/ets/lambdaLowering.cpp index e985a94b85..f1ad2c1386 100644 --- a/ets2panda/compiler/lowering/ets/lambdaLowering.cpp +++ b/ets2panda/compiler/lowering/ets/lambdaLowering.cpp @@ -881,7 +881,7 @@ static ir::BlockStatement *CreateLambdaClassInvokeBody(public_lib::Context *ctx, auto *call = CreateCallForLambdaClassInvoke(ctx, info, lciInfo, wrapToObject, false); auto bodyStmts = CreateRestArgumentsArrayReallocation(ctx, lciInfo, 0); - if (checker::ETSChecker::IsTypeVoidOrUnionContainsVoid(lciInfo->lambdaSignature->ReturnType())) { + if (lciInfo->lambdaSignature->ReturnType() == checker->GlobalVoidType()) { auto *callStmt = util::NodeAllocator::ForceSetParent(allocator, call); bodyStmts.push_back(callStmt); if (wrapToObject) { @@ -975,7 +975,7 @@ static ir::BlockStatement *CreateLambdaClassInvokeNBody(public_lib::Context *ctx lciInfo->argNames = tempVarNames; auto *call = CreateCallForLambdaClassInvoke(ctx, info, lciInfo, false, true); - if (lciInfo->lambdaSignature->ReturnType()->IsETSVoidType()) { + if (lciInfo->lambdaSignature->ReturnType() == checker->GlobalVoidType()) { auto *callStmt = util::NodeAllocator::ForceSetParent(allocator, call); bodyStmts.push_back(callStmt); auto *returnStmt = @@ -1243,32 +1243,6 @@ static ir::ETSNewClassInstanceExpression *CreateConstructorCall(public_lib::Cont return newExpr; } -static void FixConvertedLambdaBody(public_lib::Context *ctx, ir::ArrowFunctionExpression *lambda) -{ - // After the 'expressionLambdaLowering', the last statement should be the newly generated return statement. Other - // statements can appear before it, eg. because of optional/default params. - auto *const convertedReturnStatement = - lambda->Function()->Body()->AsBlockStatement()->Statements().back()->AsReturnStatement(); - - const auto *const lambdaReturnType = lambda->TsType()->AsETSFunctionType()->ArrowSignature()->ReturnType(); - const bool lambdaHasVoidReturn = checker::ETSChecker::IsTypeVoidOrUnionContainsVoid(lambdaReturnType); - const auto *const convertedArgumentType = convertedReturnStatement->Argument()->TsType(); - const bool convertedArgumentIsVoid = checker::ETSChecker::IsTypeVoidOrUnionContainsVoid(convertedArgumentType); - if (!lambdaHasVoidReturn || !convertedArgumentIsVoid) { - return; - } - - auto *allocator = ctx->allocator; - - ArenaVector newStatementList(allocator->Adapter()); - const auto &originalStatements = lambda->Function()->Body()->AsBlockStatement()->Statements(); - newStatementList.insert(end(newStatementList), begin(originalStatements), end(originalStatements)); - newStatementList.pop_back(); // Remove the return statement with argument - auto *const newCall = ctx->AllocNode(convertedReturnStatement->Argument()); - newStatementList.emplace_back(newCall); - lambda->Function()->Body()->AsBlockStatement()->SetStatements(std::move(newStatementList)); -} - static ir::AstNode *ConvertLambda(public_lib::Context *ctx, ir::ArrowFunctionExpression *lambda) { auto *allocator = ctx->allocator; @@ -1277,10 +1251,6 @@ static ir::AstNode *ConvertLambda(public_lib::Context *ctx, ir::ArrowFunctionExp lambda->Check(checker); ES2PANDA_ASSERT(lambda->TsType()->IsETSFunctionType()); - if (lambda->DoesConvertedLambdaMayNeedFix()) { - FixConvertedLambdaBody(ctx, lambda); - } - LambdaInfo info; std::tie(info.calleeClass, info.enclosingFunction) = FindEnclosingClassAndFunction(lambda); info.name = CreateCalleeName(allocator); @@ -1340,7 +1310,7 @@ static ir::ScriptFunction *GetWrappingLambdaParentFunction(public_lib::Context * auto *callExpr = util::NodeAllocator::ForceSetParent(allocator, funcRef, std::move(callArgs), nullptr, false); ir::Statement *stmt; - if (signature->ReturnType()->IsETSVoidType()) { + if (signature->ReturnType() == ctx->GetChecker()->AsETSChecker()->GlobalVoidType()) { stmt = util::NodeAllocator::ForceSetParent(allocator, callExpr); } else { stmt = util::NodeAllocator::ForceSetParent(allocator, callExpr); diff --git a/ets2panda/compiler/lowering/ets/unboxLowering.cpp b/ets2panda/compiler/lowering/ets/unboxLowering.cpp index 3d97acae28..2ad5b19d69 100644 --- a/ets2panda/compiler/lowering/ets/unboxLowering.cpp +++ b/ets2panda/compiler/lowering/ets/unboxLowering.cpp @@ -659,10 +659,9 @@ static ir::Expression *AdjustType(UnboxContext *uctx, ir::Expression *expr, chec expectedType = uctx->checker->GetApparentType(expectedType); checker::Type *actualType = expr->Check(uctx->checker); - if (expectedType->HasTypeFlag(checker::TypeFlag::ETS_NEVER | checker::TypeFlag::ETS_VOID)) { + if (expectedType->HasTypeFlag(checker::TypeFlag::ETS_NEVER)) { return expr; } - if (actualType->IsETSPrimitiveType() && checker::ETSChecker::IsReferenceType(expectedType)) { expr = InsertPrimitiveConversionIfNeeded(uctx, expr, expectedType); ES2PANDA_ASSERT( diff --git a/ets2panda/ir/expressions/arrowFunctionExpression.h b/ets2panda/ir/expressions/arrowFunctionExpression.h index 2885c5eb2f..2550cc7e0d 100644 --- a/ets2panda/ir/expressions/arrowFunctionExpression.h +++ b/ets2panda/ir/expressions/arrowFunctionExpression.h @@ -61,16 +61,6 @@ public: return preferredType_; } - void SetConvertedLambdaMayNeedFix() noexcept - { - convertedLambdaMayNeedFix_ = true; - } - - [[nodiscard]] bool DoesConvertedLambdaMayNeedFix() const noexcept - { - return convertedLambdaMayNeedFix_; - } - [[nodiscard]] ArrowFunctionExpression *Clone(ArenaAllocator *allocator, AstNode *parent) override; void TransformChildren(const NodeTransformer &cb, std::string_view transformationName) override; @@ -93,7 +83,6 @@ public: private: ScriptFunction *func_; checker::Type *preferredType_ {}; - bool convertedLambdaMayNeedFix_ = false; }; } // namespace ark::es2panda::ir diff --git a/ets2panda/ir/statements/forOfStatement.cpp b/ets2panda/ir/statements/forOfStatement.cpp index b838576473..6292698091 100644 --- a/ets2panda/ir/statements/forOfStatement.cpp +++ b/ets2panda/ir/statements/forOfStatement.cpp @@ -207,7 +207,7 @@ bool ForOfStatement::CheckReturnTypeOfIteratorMethod(checker::ETSChecker *checke checker::Signature *signature, const lexer::SourcePosition &position) { - if ((signature->ReturnType() == nullptr || signature->ReturnType()->IsETSVoidType()) && + if ((signature->ReturnType() == nullptr || signature->ReturnType() == checker->GlobalVoidType()) && signature->Function()->HasBody() && signature->Function()->Body()->IsBlockStatement()) { for (auto *const it : signature->Function()->Body()->AsBlockStatement()->Statements()) { if (it->IsReturnStatement()) { diff --git a/ets2panda/test/ast/compiler/ets/Incorrect_arrow_func.ets b/ets2panda/test/ast/compiler/ets/Incorrect_arrow_func.ets index bd9dd2215f..3f64bda07d 100644 --- a/ets2panda/test/ast/compiler/ets/Incorrect_arrow_func.ets +++ b/ets2panda/test/ast/compiler/ets/Incorrect_arrow_func.ets @@ -17,4 +17,5 @@ let f = ()=>int {} f() /* @@? 16:13 Error SyntaxError: Unexpected token 'int'. */ +/* @@? 16:13 Error TypeError: Unexpected return value, enclosing method return type is void. */ /* @@? 16:17 Error SyntaxError: Unexpected token '{'. */ diff --git a/ets2panda/test/ast/compiler/ets/absent_return_statement.ets b/ets2panda/test/ast/compiler/ets/absent_return_statement.ets index b32c474bc0..aff155f691 100644 --- a/ets2panda/test/ast/compiler/ets/absent_return_statement.ets +++ b/ets2panda/test/ast/compiler/ets/absent_return_statement.ets @@ -27,21 +27,19 @@ class C{} function main(): void { foo1(() => { return /* @@ label1 */new C(); }); - foo1(() => /* @@ label2 */{ console.println("TEST"); }); - foo1(() => /* @@ label3 */new C()); - foo1(() => /* @@ label4 */console.println("TEST")); + foo1(() => { console.println("TEST"); }); + foo1(() => /* @@ label2 */new C()); + foo1(() => console.println("TEST")); - foo2(() => { return /* @@ label5 */new C(); }); - foo2(() => /* @@ label6 */{ console.println("TEST"); }); - foo2(() => /* @@ label7 */new C()); - foo2(() => /* @@ label8 */console.println("TEST")); + foo2(() => { return /* @@ label3 */new C(); }); + foo2(() => /* @@ label4 */{ console.println("TEST"); }); + foo2(() => /* @@ label5 */new C()); + foo2(() => /* @@ label6 */console.println("TEST")); } /* @@@ label1 Error TypeError: Type 'C' is not compatible with the enclosing method's return type 'Int|String|undefined' */ -/* @@@ label2 Error TypeError: Type 'void' is not compatible with the enclosing method's return type 'Int|String|undefined' */ -/* @@@ label3 Error TypeError: Type 'C' is not compatible with the enclosing method's return type 'Int|String|undefined' */ -/* @@@ label4 Error TypeError: Type 'void' is not compatible with the enclosing method's return type 'Int|String|undefined' */ +/* @@@ label2 Error TypeError: Type 'C' is not compatible with the enclosing method's return type 'Int|String|undefined' */ +/* @@@ label3 Error TypeError: Type 'C' is not compatible with the enclosing method's return type 'Int|String' */ +/* @@@ label4 Error TypeError: Type 'void' is not compatible with the enclosing method's return type 'Int|String' */ /* @@@ label5 Error TypeError: Type 'C' is not compatible with the enclosing method's return type 'Int|String' */ /* @@@ label6 Error TypeError: Type 'void' is not compatible with the enclosing method's return type 'Int|String' */ -/* @@@ label7 Error TypeError: Type 'C' is not compatible with the enclosing method's return type 'Int|String' */ -/* @@@ label8 Error TypeError: Type 'void' is not compatible with the enclosing method's return type 'Int|String' */ diff --git a/ets2panda/test/ast/compiler/ets/extension_accessor_tests/extensionGetMustReturnValue.ets b/ets2panda/test/ast/compiler/ets/extension_accessor_tests/extensionGetMustReturnValue.ets index 82cc4bca1c..f6fdb9f662 100644 --- a/ets2panda/test/ast/compiler/ets/extension_accessor_tests/extensionGetMustReturnValue.ets +++ b/ets2panda/test/ast/compiler/ets/extension_accessor_tests/extensionGetMustReturnValue.ets @@ -16,4 +16,6 @@ class A{ field_: int; } -get field(this: A){} +get /* @@ label */field(this: A){} + +/* @@@ label Error TypeError: Getter must return a value */ diff --git a/ets2panda/test/ast/compiler/ets/type_error_test2.ets b/ets2panda/test/ast/compiler/ets/type_error_test2.ets index f1877196e9..08c72c921a 100644 --- a/ets2panda/test/ast/compiler/ets/type_error_test2.ets +++ b/ets2panda/test/ast/compiler/ets/type_error_test2.ets @@ -23,6 +23,7 @@ let f:(c:string, ...abe])=>void = (c:be ...abe])=>{} /* @@? 16:41 Error SyntaxError: Unexpected token, expected ',' or ')'. */ /* @@? 16:41 Error SyntaxError: Expected '=>', got '...'. */ /* @@? 16:41 Error SyntaxError: Unexpected token '...'. */ +/* @@? 16:41 Error TypeError: Unexpected return value, enclosing method return type is void. */ /* @@? 16:44 Error SyntaxError: Unexpected token 'abe'. */ /* @@? 16:44 Error TypeError: Unresolved reference abe */ /* @@? 16:47 Error SyntaxError: Unexpected token ']'. */ diff --git a/ets2panda/test/ast/compiler/ets/unmatch_arg_for_trailing_lambda.ets b/ets2panda/test/ast/compiler/ets/unmatch_arg_for_trailing_lambda.ets index 620bc3e0ac..81037bd2a5 100644 --- a/ets2panda/test/ast/compiler/ets/unmatch_arg_for_trailing_lambda.ets +++ b/ets2panda/test/ast/compiler/ets/unmatch_arg_for_trailing_lambda.ets @@ -23,4 +23,4 @@ foo(1, () => { return "1" }) /* @@? 18:8 Error TypeError: Type '"2"' is not compatible with type '() => void|undefined' at index 2 */ /* @@? 19:1 Error TypeError: No matching call signature for foo(Double, Int) */ /* @@? 19:8 Error TypeError: Type 'Int' is not compatible with type '() => void|undefined' at index 2 */ -/* @@? 20:23 Error TypeError: Type '"1"' is not compatible with the enclosing method's return type 'void' */ +/* @@? 20:23 Error TypeError: Unexpected return value, enclosing method return type is void. */ diff --git a/ets2panda/test/ast/compiler/ets/voidTypeArg_neg_1.ets b/ets2panda/test/ast/compiler/ets/voidTypeArg_neg_1.ets deleted file mode 100644 index b3177c569d..0000000000 --- a/ets2panda/test/ast/compiler/ets/voidTypeArg_neg_1.ets +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2024-2025 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -type Fn = (e: T) => void; - -function test(arg: Fn) {} - -function main() : void { - test((/* @@ label */e) => { }) -} - -/* @@@ label Error TypeError: Cannot use type 'void' as value. */ diff --git a/ets2panda/test/ast/compiler/ets/voidTypeInBinaryOperation.ets b/ets2panda/test/ast/compiler/ets/voidTypeInBinaryOperation.ets index 82b707b4a2..92db5f8ba8 100644 --- a/ets2panda/test/ast/compiler/ets/voidTypeInBinaryOperation.ets +++ b/ets2panda/test/ast/compiler/ets/voidTypeInBinaryOperation.ets @@ -20,6 +20,6 @@ function main(): void { arktest.assertTrue(false || check()) } -/* @@? 20:3 Error TypeError: No matching call signature for assertTrue(Boolean|void) */ -/* @@? 20:22 Error TypeError: Type 'Boolean|void' is not compatible with type 'Boolean' at index 1 */ -/* @@? 20:31 Error TypeError: Cannot use type 'void' as value. */ +/* @@? 20:3 Error TypeError: No matching call signature for assertTrue(Boolean|void) */ +/* @@? 20:22 Error TypeError: Type 'Boolean|void' is not compatible with type 'Boolean' at index 1 */ +/* @@? 20:31 Error TypeError: Cannot use type 'void' as value. */ diff --git a/ets2panda/test/ast/compiler/ets/void_as_return_type_neg_2.ets b/ets2panda/test/ast/compiler/ets/void_as_return_type_neg_2.ets index 987b3fc2d4..50e646c928 100644 --- a/ets2panda/test/ast/compiler/ets/void_as_return_type_neg_2.ets +++ b/ets2panda/test/ast/compiler/ets/void_as_return_type_neg_2.ets @@ -20,4 +20,4 @@ async function foo():Promise{ return test() } -/* @@? 20:12 Error TypeError: Type 'void' is not compatible with the enclosing method's return type 'Promise | Int' */ +/* @@? 20:12 Error TypeError: Type 'void' is not compatible with the enclosing method's return type 'Promise | Int' */ \ No newline at end of file diff --git a/ets2panda/test/ast/compiler/ets/void_as_value_neg_4.ets b/ets2panda/test/ast/compiler/ets/void_as_value_neg_4.ets index 3de18e1f08..bafb8f9d54 100644 --- a/ets2panda/test/ast/compiler/ets/void_as_value_neg_4.ets +++ b/ets2panda/test/ast/compiler/ets/void_as_value_neg_4.ets @@ -24,6 +24,5 @@ function main(): void { foo(void_function()); } -/* @@? 24:5 Error TypeError: No matching call signature for foo(void) */ /* @@? 24:9 Error TypeError: Cannot use type 'void' as value. */ -/* @@? 24:9 Error TypeError: Type 'void' is not compatible with type 'Object|undefined' at index 1 */ + diff --git a/ets2panda/test/ast/parser/ets/FixedArray/MultipleParserErrors.ets b/ets2panda/test/ast/parser/ets/FixedArray/MultipleParserErrors.ets index d681b670c6..93e45d5454 100644 --- a/ets2panda/test/ast/parser/ets/FixedArray/MultipleParserErrors.ets +++ b/ets2panda/test/ast/parser/ets/FixedArray/MultipleParserErrors.ets @@ -178,6 +178,7 @@ function main(): void { /* @@? 39:27 Error SyntaxError: Unexpected token ')'. */ /* @@? 39:29 Error SyntaxError: Unexpected token '{'. */ /* @@? 39:31 Error SyntaxError: return keyword should be used in function body. */ +/* @@? 39:38 Error TypeError: All return statements in the function should be empty or have a value. */ /* @@? 41:1 Error TypeError: Unresolved reference type */ /* @@? 41:6 Error SyntaxError: Unexpected token '123'. */ /* @@? 41:6 Error TypeError: Invalid left-hand side of assignment expression */ @@ -201,10 +202,12 @@ function main(): void { /* @@? 51:43 Error TypeError: Unresolved reference FixedArray */ /* @@? 51:58 Error SyntaxError: Unexpected token, expected '('. */ /* @@? 51:59 Error SyntaxError: Unexpected token ':'. */ +/* @@? 51:61 Error SyntaxError: Unexpected token 'int'. */ /* @@? 51:61 Error SyntaxError: Unexpected token, expected ',' or ')'. */ /* @@? 51:61 Error SyntaxError: Unexpected token 'int'. */ /* @@? 51:65 Error SyntaxError: Unexpected token '{'. */ /* @@? 52:5 Error SyntaxError: return keyword should be used in function body. */ +/* @@? 52:12 Error TypeError: All return statements in the function should be empty or have a value. */ /* @@? 52:12 Error TypeError: Unresolved reference q */ /* @@? 52:23 Error TypeError: Unresolved reference p */ /* @@? 55:14 Error SyntaxError: Rest parameter should be either array or tuple type. */ @@ -220,18 +223,18 @@ function main(): void { /* @@? 77:20 Error TypeError: Interface expected here. */ /* @@? 77:22 Error TypeError: 'I' type does not exist. */ /* @@? 78:22 Error TypeError: Method fee(): Int in B not overriding any method */ -/* @@? 83:7 Error TypeError: Variable 'A' has already been declared. */ /* @@? 83:7 Error TypeError: Merging declarations is not supported, please keep all definitions of classes, interfaces and enums compact in the codebase! */ +/* @@? 83:7 Error TypeError: Variable 'A' has already been declared. */ /* @@? 84:3 Error SyntaxError: Unexpected token. A constructor, method, accessor, or property was expected. */ -/* @@? 92:7 Error TypeError: Variable 'A' has already been declared. */ /* @@? 92:7 Error TypeError: Merging declarations is not supported, please keep all definitions of classes, interfaces and enums compact in the codebase! */ +/* @@? 92:7 Error TypeError: Variable 'A' has already been declared. */ /* @@? 93:3 Error SyntaxError: Unexpected token. A constructor, method, accessor, or property was expected. */ /* @@? 103:14 Error SyntaxError: Rest parameter should be either array or tuple type. */ /* @@? 104:21 Error SyntaxError: Rest parameter should be either array or tuple type. */ -/* @@? 115:26 Error SyntaxError: Unexpected token 'case'. */ +/* @@? 115:26 Error SyntaxError: Parameter declaration should have an explicit type annotation. */ /* @@? 115:26 Error SyntaxError: Unexpected token, expected ',' or ')'. */ +/* @@? 115:26 Error SyntaxError: Unexpected token 'case'. */ /* @@? 115:26 Error SyntaxError: Unexpected token, expected an identifier. */ -/* @@? 115:26 Error SyntaxError: Parameter declaration should have an explicit type annotation. */ /* @@? 115:30 Error SyntaxError: Unexpected token ':'. */ /* @@? 115:32 Error SyntaxError: Unexpected token 'U'. */ /* @@? 115:32 Error TypeError: Unresolved reference U */ @@ -241,9 +244,10 @@ function main(): void { /* @@? 115:36 Error TypeError: Unresolved reference T */ /* @@? 115:38 Error SyntaxError: Unexpected token '{'. */ /* @@? 116:5 Error SyntaxError: return keyword should be used in function body. */ +/* @@? 116:12 Error TypeError: All return statements in the function should be empty or have a value. */ /* @@? 119:1 Error TypeError: Function foo with this assembly signature already declared. */ -/* @@? 119:26 Error SyntaxError: Parameter declaration should have an explicit type annotation. */ /* @@? 119:26 Error SyntaxError: Unexpected token, expected an identifier. */ +/* @@? 119:26 Error SyntaxError: Parameter declaration should have an explicit type annotation. */ /* @@? 119:26 Error SyntaxError: Unexpected token, expected ',' or ')'. */ /* @@? 119:26 Error SyntaxError: Unexpected token 'case'. */ /* @@? 119:30 Error SyntaxError: Unexpected token ':'. */ @@ -253,7 +257,9 @@ function main(): void { /* @@? 119:36 Error SyntaxError: Unexpected token 'T'. */ /* @@? 119:38 Error SyntaxError: Unexpected token '{'. */ /* @@? 120:5 Error SyntaxError: return keyword should be used in function body. */ +/* @@? 120:12 Error TypeError: All return statements in the function should be empty or have a value. */ /* @@? 123:5 Error SyntaxError: Identifier expected, got ','. */ +/* @@? 123:6 Error SyntaxError: Variable must be initialized or it's type must be declared. */ /* @@? 123:6 Error SyntaxError: Unexpected token 'abc'. */ /* @@? 123:6 Error SyntaxError: Variable must be initialized or it's type must be declared. */ /* @@? 123:6 Error TypeError: Unresolved reference abc */ @@ -284,6 +290,6 @@ function main(): void { /* @@? 163:9 Error SyntaxError: Hard keyword 'new' cannot be used as identifier */ /* @@? 164:5 Error TypeError: This expression is not callable. */ /* @@? 165:5 Error TypeError: This expression is not callable. */ -/* @@? 166:5 Error TypeError: Expected 1 arguments, got 0. */ /* @@? 166:5 Error TypeError: No matching call signature */ -/* @@? 290:1 Error SyntaxError: Expected '}', got 'end of stream'. */ +/* @@? 166:5 Error TypeError: Expected 1 arguments, got 0. */ +/* @@? 296:1 Error SyntaxError: Expected '}', got 'end of stream'. */ diff --git a/ets2panda/test/ast/parser/ets/FixedArray/unexpected_token_31.ets b/ets2panda/test/ast/parser/ets/FixedArray/unexpected_token_31.ets index 575024cc8c..37de6fe998 100644 --- a/ets2panda/test/ast/parser/ets/FixedArray/unexpected_token_31.ets +++ b/ets2panda/test/ast/parser/ets/FixedArray/unexpected_token_31.ets @@ -29,3 +29,4 @@ function foo(...^number: FixedArray): int { /* @@? 17:5 Error SyntaxError: return keyword should be used in function body. */ /* @@? 17:12 Error TypeError: Type name 'number' used in the wrong context */ /* @@? 17:12 Error TypeError: Indexed access is not supported for such expression type. */ +/* @@? 17:12 Error TypeError: All return statements in the function should be empty or have a value. */ diff --git a/ets2panda/test/ast/parser/ets/InvalidParserImpl.ets b/ets2panda/test/ast/parser/ets/InvalidParserImpl.ets index 1231f1dcf7..899de53972 100644 --- a/ets2panda/test/ast/parser/ets/InvalidParserImpl.ets +++ b/ets2panda/test/ast/parser/ets/InvalidParserImpl.ets @@ -22,6 +22,7 @@ function fun(this: A) {} class int {} +/* @@? 17:12 Error TypeError: Getter must return a value */ /* @@? 18:5 Error SyntaxError: Getter must not have formal parameters. */ /* @@? 19:1 Error SyntaxError: Setter must have exactly one formal parameter. */ /* @@? 23:7 Error SyntaxError: int is a predefined type, cannot be used as an identifier */ diff --git a/ets2panda/test/ast/parser/ets/InvalidStatements2.ets b/ets2panda/test/ast/parser/ets/InvalidStatements2.ets index 61e084ecdf..c3d305e424 100644 --- a/ets2panda/test/ast/parser/ets/InvalidStatements2.ets +++ b/ets2panda/test/ast/parser/ets/InvalidStatements2.ets @@ -55,6 +55,7 @@ function g(x: int): int { /* @@? 20:27 Error TypeError: struct B is not extensible. */ /* @@? 30:17 Error SyntaxError: Label already declared. */ /* @@? 40:1 Error SyntaxError: return keyword should be used in function body. */ +/* @@? 40:8 Error TypeError: All return statements in the function should be empty or have a value. */ /* @@? 43:12 Error SyntaxError: Expected '(', got 'identification literal'. */ /* @@? 44:9 Error SyntaxError: Expected ')', got 'case'. */ /* @@? 44:9 Error SyntaxError: Expected '{', got 'case'. */ diff --git a/ets2panda/test/ast/parser/ets/MultipleParserErrors.ets b/ets2panda/test/ast/parser/ets/MultipleParserErrors.ets index f1e0c37280..f5ca1c97b2 100644 --- a/ets2panda/test/ast/parser/ets/MultipleParserErrors.ets +++ b/ets2panda/test/ast/parser/ets/MultipleParserErrors.ets @@ -178,6 +178,7 @@ function main(): void { /* @@? 39:27 Error SyntaxError: Unexpected token ')'. */ /* @@? 39:29 Error SyntaxError: Unexpected token '{'. */ /* @@? 39:31 Error SyntaxError: return keyword should be used in function body. */ +/* @@? 39:38 Error TypeError: All return statements in the function should be empty or have a value. */ /* @@? 41:1 Error TypeError: Unresolved reference type */ /* @@? 41:6 Error SyntaxError: Unexpected token '123'. */ /* @@? 41:6 Error TypeError: Invalid left-hand side of assignment expression */ @@ -203,6 +204,7 @@ function main(): void { /* @@? 51:41 Error SyntaxError: Unexpected token 'int'. */ /* @@? 51:45 Error SyntaxError: Unexpected token '{'. */ /* @@? 52:5 Error SyntaxError: return keyword should be used in function body. */ +/* @@? 52:12 Error TypeError: All return statements in the function should be empty or have a value. */ /* @@? 52:12 Error TypeError: Unresolved reference q */ /* @@? 52:23 Error TypeError: Unresolved reference p */ /* @@? 55:14 Error SyntaxError: Rest parameter should be either array or tuple type. */ @@ -218,18 +220,18 @@ function main(): void { /* @@? 77:20 Error TypeError: Interface expected here. */ /* @@? 77:22 Error TypeError: 'I' type does not exist. */ /* @@? 78:22 Error TypeError: Method fee(): Int in B not overriding any method */ -/* @@? 83:7 Error TypeError: Variable 'A' has already been declared. */ /* @@? 83:7 Error TypeError: Merging declarations is not supported, please keep all definitions of classes, interfaces and enums compact in the codebase! */ +/* @@? 83:7 Error TypeError: Variable 'A' has already been declared. */ /* @@? 84:3 Error SyntaxError: Unexpected token. A constructor, method, accessor, or property was expected. */ /* @@? 92:7 Error TypeError: Variable 'A' has already been declared. */ /* @@? 92:7 Error TypeError: Merging declarations is not supported, please keep all definitions of classes, interfaces and enums compact in the codebase! */ /* @@? 93:3 Error SyntaxError: Unexpected token. A constructor, method, accessor, or property was expected. */ /* @@? 103:14 Error SyntaxError: Rest parameter should be either array or tuple type. */ /* @@? 104:21 Error SyntaxError: Rest parameter should be either array or tuple type. */ -/* @@? 115:26 Error SyntaxError: Unexpected token 'case'. */ -/* @@? 115:26 Error SyntaxError: Unexpected token, expected ',' or ')'. */ /* @@? 115:26 Error SyntaxError: Unexpected token, expected an identifier. */ /* @@? 115:26 Error SyntaxError: Parameter declaration should have an explicit type annotation. */ +/* @@? 115:26 Error SyntaxError: Unexpected token, expected ',' or ')'. */ +/* @@? 115:26 Error SyntaxError: Unexpected token 'case'. */ /* @@? 115:30 Error SyntaxError: Unexpected token ':'. */ /* @@? 115:32 Error SyntaxError: Unexpected token 'U'. */ /* @@? 115:32 Error TypeError: Unresolved reference U */ @@ -239,6 +241,7 @@ function main(): void { /* @@? 115:36 Error TypeError: Unresolved reference T */ /* @@? 115:38 Error SyntaxError: Unexpected token '{'. */ /* @@? 116:5 Error SyntaxError: return keyword should be used in function body. */ +/* @@? 116:12 Error TypeError: All return statements in the function should be empty or have a value. */ /* @@? 119:1 Error TypeError: Function foo with this assembly signature already declared. */ /* @@? 119:26 Error SyntaxError: Unexpected token, expected an identifier. */ /* @@? 119:26 Error SyntaxError: Parameter declaration should have an explicit type annotation. */ @@ -251,6 +254,7 @@ function main(): void { /* @@? 119:36 Error SyntaxError: Unexpected token 'T'. */ /* @@? 119:38 Error SyntaxError: Unexpected token '{'. */ /* @@? 120:5 Error SyntaxError: return keyword should be used in function body. */ +/* @@? 120:12 Error TypeError: All return statements in the function should be empty or have a value. */ /* @@? 123:5 Error SyntaxError: Identifier expected, got ','. */ /* @@? 123:6 Error SyntaxError: Variable must be initialized or it's type must be declared. */ /* @@? 123:6 Error SyntaxError: Unexpected token 'abc'. */ @@ -284,4 +288,4 @@ function main(): void { /* @@? 165:5 Error TypeError: This expression is not callable. */ /* @@? 166:5 Error TypeError: No matching call signature */ /* @@? 166:5 Error TypeError: Expected 1 arguments, got 0. */ -/* @@? 288:1 Error SyntaxError: Expected '}', got 'end of stream'. */ +/* @@? 292:1 Error SyntaxError: Expected '}', got 'end of stream'. */ diff --git a/ets2panda/test/ast/parser/ets/accessor_void.ets b/ets2panda/test/ast/parser/ets/accessor_void.ets index 5bce3fe8e0..966e7b1f3f 100644 --- a/ets2panda/test/ast/parser/ets/accessor_void.ets +++ b/ets2panda/test/ast/parser/ets/accessor_void.ets @@ -16,3 +16,5 @@ class A { get x/* @@ label */(): void { } } + +/* @@@ label Error TypeError: Getter must return a value */ diff --git a/ets2panda/test/ast/parser/ets/extension_function_tests/extension_function_error2.ets b/ets2panda/test/ast/parser/ets/extension_function_tests/extension_function_error2.ets index 58100d1064..569109a6ae 100644 --- a/ets2panda/test/ast/parser/ets/extension_function_tests/extension_function_error2.ets +++ b/ets2panda/test/ast/parser/ets/extension_function_tests/extension_function_error2.ets @@ -28,3 +28,4 @@ let a = (this: TextAttribute, this { this.width(width); return this; /* @@? 16:43 Error TypeError: Property 'width' does not exist on type 'ETSGLOBAL' */ /* @@? 16:57 Error SyntaxError: return keyword should be used in function body. */ /* @@? 16:64 Error TypeError: 'this' cannot be referenced from a static context */ +/* @@? 16:64 Error TypeError: All return statements in the function should be empty or have a value. */ diff --git a/ets2panda/test/ast/parser/ets/static_block.ets b/ets2panda/test/ast/parser/ets/static_block.ets index f274fd00d5..0543023636 100644 --- a/ets2panda/test/ast/parser/ets/static_block.ets +++ b/ets2panda/test/ast/parser/ets/static_block.ets @@ -22,3 +22,4 @@ class A { } /* @@? 20:12 Error SyntaxError: Unexpected return value. */ +/* @@? 20:12 Error TypeError: All return statements in the function should be empty or have a value. */ diff --git a/ets2panda/test/ast/parser/ets/trailing_lambda_tests/trailing_lambda_mismatch_lambda_signature_1.ets b/ets2panda/test/ast/parser/ets/trailing_lambda_tests/trailing_lambda_mismatch_lambda_signature_1.ets index 15e8d7d0e9..95bf39bd29 100644 --- a/ets2panda/test/ast/parser/ets/trailing_lambda_tests/trailing_lambda_mismatch_lambda_signature_1.ets +++ b/ets2panda/test/ast/parser/ets/trailing_lambda_tests/trailing_lambda_mismatch_lambda_signature_1.ets @@ -23,4 +23,4 @@ function main() { } } -/* @@@ label Error TypeError: Type 'Int' is not compatible with the enclosing method's return type 'void' */ +/* @@@ label Error TypeError: Unexpected return value, enclosing method return type is void. */ diff --git a/ets2panda/test/ast/parser/ets/trailing_lambda_tests/trailing_lambda_mismatch_lambda_signature_2.ets b/ets2panda/test/ast/parser/ets/trailing_lambda_tests/trailing_lambda_mismatch_lambda_signature_2.ets index 7786e5e3a9..90b3b80d95 100644 --- a/ets2panda/test/ast/parser/ets/trailing_lambda_tests/trailing_lambda_mismatch_lambda_signature_2.ets +++ b/ets2panda/test/ast/parser/ets/trailing_lambda_tests/trailing_lambda_mismatch_lambda_signature_2.ets @@ -23,4 +23,4 @@ function main() { } } -/* @@@ label Error TypeError: Type 'Int' is not compatible with the enclosing method's return type 'void' */ +/* @@@ label Error TypeError: Unexpected return value, enclosing method return type is void. */ diff --git a/ets2panda/test/ast/parser/ets/unexpected_token_31.ets b/ets2panda/test/ast/parser/ets/unexpected_token_31.ets index 67b36f092f..01374410c3 100644 --- a/ets2panda/test/ast/parser/ets/unexpected_token_31.ets +++ b/ets2panda/test/ast/parser/ets/unexpected_token_31.ets @@ -29,3 +29,4 @@ function foo(...^number: int[]): int { /* @@? 17:5 Error SyntaxError: return keyword should be used in function body. */ /* @@? 17:12 Error TypeError: Type name 'number' used in the wrong context */ /* @@? 17:12 Error TypeError: Indexed access is not supported for such expression type. */ +/* @@? 17:12 Error TypeError: All return statements in the function should be empty or have a value. */ diff --git a/ets2panda/test/ast/parser/ets/update_funcscope_error.ets b/ets2panda/test/ast/parser/ets/update_funcscope_error.ets index ed15a9352e..3216a64552 100644 --- a/ets2panda/test/ast/parser/ets/update_funcscope_error.ets +++ b/ets2panda/test/ast/parser/ets/update_funcscope_error.ets @@ -49,4 +49,5 @@ export const updateIfChanged = (t: Record) => { /* @@? 30:16 Error TypeError: This expression is not callable. */ /* @@? 32:5 Error SyntaxError: Unexpected token ')'. */ /* @@? 33:12 Error TypeError: Unresolved reference reduceResult */ +/* @@? 33:12 Error TypeError: Unexpected return value, enclosing method return type is void. */ /* @@? 35:1 Error SyntaxError: Unexpected token '}'. */ diff --git a/ets2panda/test/runtime/ets/async_return_void_2.ets b/ets2panda/test/runtime/ets/async_return_void_2.ets index fce70c3748..b78d951ce2 100644 --- a/ets2panda/test/runtime/ets/async_return_void_2.ets +++ b/ets2panda/test/runtime/ets/async_return_void_2.ets @@ -15,5 +15,5 @@ function test(){} async function foo(){ - test(); + return test(); } diff --git a/ets2panda/test/runtime/ets/async_return_void_3.ets b/ets2panda/test/runtime/ets/async_return_void_3.ets index 0e2c4eebbf..de99b21477 100644 --- a/ets2panda/test/runtime/ets/async_return_void_3.ets +++ b/ets2panda/test/runtime/ets/async_return_void_3.ets @@ -15,5 +15,5 @@ function test(){} async function foo(){ - test(); + return test(); } diff --git a/ets2panda/test/runtime/ets/voidTypeArg.ets b/ets2panda/test/runtime/ets/voidTypeArg.ets index d6ec50f882..e9367a44f6 100644 --- a/ets2panda/test/runtime/ets/voidTypeArg.ets +++ b/ets2panda/test/runtime/ets/voidTypeArg.ets @@ -26,4 +26,8 @@ function main() : void { let bfoo = foo(undefined); arktest.assertEQ(bfoo, undefined) + + test((e) => { + arktest.assertEQ(e, undefined) + }) } diff --git a/ets2panda/test/unit/public/ast_verifier_getter_setter_neg_test.cpp b/ets2panda/test/unit/public/ast_verifier_getter_setter_neg_test.cpp index 74b0e74406..651b6ab840 100644 --- a/ets2panda/test/unit/public/ast_verifier_getter_setter_neg_test.cpp +++ b/ets2panda/test/unit/public/ast_verifier_getter_setter_neg_test.cpp @@ -26,6 +26,45 @@ using ark::es2panda::ir::ETSParameterExpression; using ark::es2panda::ir::Identifier; using ark::es2panda::util::DiagnosticEngine; namespace { +TEST_F(ASTVerifierTest, ValidateGetterReturnTypeAnnotation) +{ + DiagnosticEngine de {}; + ETSChecker checker {Allocator(), de}; + + char const *text = + R"( + class A { + private _value: number = 0; + get value(): number { + return this._value + } + + set value(v: number) { + this._value = v + } + } + )"; + + auto cb = [&checker](ark::es2panda::ir::AstNode *child) { + if (child->IsMethodDefinition()) { + auto *const method = child->AsMethodDefinition(); + if (method->IsGetter() && method->Value()->IsFunctionExpression()) { + auto *const function = method->Value()->AsFunctionExpression()->Function(); + ASSERT_NE(function->ReturnTypeAnnotation(), nullptr); + function->ReturnTypeAnnotation()->SetTsType(checker.GlobalVoidType()); + } + } + }; + + CONTEXT(ES2PANDA_STATE_CHECKED, text) + { + // Change annotation return type to void + GetAst()->IterateRecursively(cb); + EXPECT_TRUE(Verify( + ExpectVerifierMessage {"GETTER METHOD HAS VOID RETURN TYPE IN RETURN TYPE ANNOTATION"})); + } +} + TEST_F(ASTVerifierTest, ValidateGetterHasReturnStatement) { // Program with no type annotation for getter @@ -62,6 +101,44 @@ TEST_F(ASTVerifierTest, ValidateGetterHasReturnStatement) } } +TEST_F(ASTVerifierTest, ValidateGetterVoidReturnStatement) +{ + DiagnosticEngine de {}; + ETSChecker checker {Allocator(), de}; + + char const *text = + R"( + class A { + private _value: number = 0; + get value() { + return this._value + } + + set value(v: number) { + this._value = v + } + } + )"; + auto cb = [&checker](ark::es2panda::ir::AstNode *child) { + if (child->IsMethodDefinition()) { + auto *const method = child->AsMethodDefinition(); + if (method->IsGetter() && method->Value()->IsFunctionExpression()) { + auto *const function = method->Value()->AsFunctionExpression()->Function(); + auto &returns = function->ReturnStatements(); + ASSERT_EQ(returns.size(), 1); + returns[0]->SetArgument(nullptr); + returns[0]->SetReturnType(&checker, checker.GlobalVoidType()); + } + } + }; + CONTEXT(ES2PANDA_STATE_CHECKED, text) + { + // Change return statement type to void + GetAst()->IterateRecursively(cb); + EXPECT_TRUE(Verify(ExpectVerifierMessage {"GETTER METHOD HAS VOID RETURN TYPE"})); + } +} + TEST_F(ASTVerifierTest, ValidateGetterArguments) { DiagnosticEngine de {}; diff --git a/ets2panda/util/diagnostic/semantic.yaml b/ets2panda/util/diagnostic/semantic.yaml index d9295dba3c..e169f1b748 100644 --- a/ets2panda/util/diagnostic/semantic.yaml +++ b/ets2panda/util/diagnostic/semantic.yaml @@ -523,6 +523,10 @@ semantic: message: "{} is not abstract and does not implement getter for {} property in {}" code_fix_ids: [FixClassIncorrectlyImplementsInterfaceForSetter] +- name: GETTER_VOID + id: 86 + message: "Getter must return a value" + - name: ID_IN_WRONG_CTX id: 144 message: "{} name '{}' used in the wrong context" @@ -1377,6 +1381,10 @@ semantic: id: 364 message: "Structs are only used to define UI components, it should be translated at 'plugin after parser' phase." +- name: UNEXPECTED_VALUE_RETURN + id: 89 + message: "Unexpected return value, enclosing method return type is void." + - name: UNEXPECTED_VOID id: 93 message: "'{}' shouldn't have void return type." @@ -1462,8 +1470,6 @@ graveyard: - 60 - 75 - 85 -- 86 -- 89 - 90 - 95 - 102 -- Gitee