From 87a030172b1a0106f0323e4cffcdfcc609fb8431 Mon Sep 17 00:00:00 2001 From: aleksisch Date: Thu, 9 Nov 2023 17:58:44 +0300 Subject: [PATCH] fix signature substituted return type Signed-off-by: aleksisch --- ets2panda/checker/ets/function.cpp | 7 +- ets2panda/checker/types/signature.cpp | 10 +- ets2panda/checker/types/signature.h | 8 +- ets2panda/checker/types/type.h | 7 ++ ets2panda/compiler/core/ETSGen.cpp | 52 ++++++--- ets2panda/compiler/core/ETSGen.h | 25 ++--- ets2panda/ir/expressions/memberExpression.cpp | 22 +++- ets2panda/ir/expressions/memberExpression.h | 2 + .../generics_implicit_lambda1-expected.txt | 106 ++++++++++++++++-- .../ets/generics_implicit_lambda1.ets | 2 +- 10 files changed, 192 insertions(+), 49 deletions(-) diff --git a/ets2panda/checker/ets/function.cpp b/ets2panda/checker/ets/function.cpp index ed412dc646..21f158cb7c 100644 --- a/ets2panda/checker/ets/function.cpp +++ b/ets2panda/checker/ets/function.cpp @@ -190,10 +190,9 @@ Signature *ETSChecker::ValidateSignature(Signature *signature, const ir::TSTypeP } } - if (substituted_sig->ReturnType()->IsETSObjectType() && signature->ReturnType()->IsETSObjectType() && - substituted_sig->ReturnType()->AsETSObjectType()->AssemblerName() != - signature->ReturnType()->AsETSObjectType()->AssemblerName()) { - substituted_sig->AddSignatureFlag(SignatureFlags::SUBSTITUTED_RETURN_TYPE); + if (substituted_sig->IsBaseReturnDiff() && substituted_sig->ReturnType()->IsETSArrayType()) { + CreateBuiltinArraySignature(substituted_sig->ReturnType()->AsETSArrayType(), + substituted_sig->ReturnType()->AsETSArrayType()->Rank()); } // Check all required formal parameter(s) first diff --git a/ets2panda/checker/types/signature.cpp b/ets2panda/checker/types/signature.cpp index ab2188c6c0..65e10fa68e 100644 --- a/ets2panda/checker/types/signature.cpp +++ b/ets2panda/checker/types/signature.cpp @@ -84,7 +84,7 @@ Signature *Signature::Substitute(TypeRelation *relation, const Substitution *sub if (!any_change) { return this; } - auto *result = allocator->New(new_sig_info, new_return_type); + auto *result = allocator->New(new_sig_info, new_return_type, this); result->func_ = func_; result->flags_ = flags_; result->internal_name_ = internal_name_; @@ -298,4 +298,12 @@ void Signature::AssignmentTarget(TypeRelation *relation, Signature *source) relation->IsAssignableTo(source->RestVar()->TsType(), signature_info_->rest_var->TsType()); } } + +bool Signature::IsBaseReturnDiff() const +{ + if (base_sig_ == nullptr) { + return false; + } + return ReturnType()->ToAssemblerName().str() != base_sig_->ReturnType()->ToAssemblerName().str(); +} } // namespace panda::es2panda::checker diff --git a/ets2panda/checker/types/signature.h b/ets2panda/checker/types/signature.h index 2341dd5745..751b5092ab 100644 --- a/ets2panda/checker/types/signature.h +++ b/ets2panda/checker/types/signature.h @@ -79,7 +79,6 @@ enum class SignatureFlags : uint32_t { INTERNAL = 1U << 12U, NEED_RETURN_TYPE = 1U << 13U, INFERRED_RETURN_TYPE = 1U << 14U, - SUBSTITUTED_RETURN_TYPE = 1U << 15U, INTERNAL_PROTECTED = INTERNAL | PROTECTED, FUNCTIONAL_INTERFACE_SIGNATURE = VIRTUAL | ABSTRACT | CALL | PUBLIC | TYPE @@ -89,8 +88,8 @@ DEFINE_BITOPS(SignatureFlags) class Signature { public: - Signature(SignatureInfo *signature_info, Type *return_type) - : signature_info_(signature_info), return_type_(return_type) + Signature(SignatureInfo *signature_info, Type *return_type, Signature *base_sig = nullptr) + : signature_info_(signature_info), return_type_(return_type), base_sig_(base_sig) { } @@ -221,6 +220,8 @@ public: return (flags_ & flag) != 0U; } + bool IsBaseReturnDiff() const; + bool IsFinal() const noexcept { return HasSignatureFlag(SignatureFlags::FINAL); @@ -257,6 +258,7 @@ private: util::StringView internal_name_ {}; ETSObjectType *owner_obj_ {}; varbinder::Variable *owner_var_ {}; + const Signature *base_sig_ = nullptr; }; } // namespace panda::es2panda::checker diff --git a/ets2panda/checker/types/type.h b/ets2panda/checker/types/type.h index 83d97754ba..470524b486 100644 --- a/ets2panda/checker/types/type.h +++ b/ets2panda/checker/types/type.h @@ -207,6 +207,13 @@ public: return util::UString(ss.str(), allocator).View(); } + std::stringstream ToAssemblerName() const + { + std::stringstream ss; + ToAssemblerType(ss); + return ss; + } + bool IsLambdaObject() const; virtual void ToString(std::stringstream &ss) const = 0; virtual void ToStringAsSrc(std::stringstream &ss) const; diff --git a/ets2panda/compiler/core/ETSGen.cpp b/ets2panda/compiler/core/ETSGen.cpp index 30b8519653..a755d45b49 100644 --- a/ets2panda/compiler/core/ETSGen.cpp +++ b/ets2panda/compiler/core/ETSGen.cpp @@ -290,7 +290,7 @@ void ETSGen::LoadVar(const ir::AstNode *node, varbinder::Variable const *const v } case ReferenceKind::FIELD: { const auto full_name = FormClassPropReference(GetVRegType(GetThisReg())->AsETSObjectType(), var->Name()); - LoadProperty(node, var->TsType(), GetThisReg(), full_name); + LoadProperty(node, var->TsType(), false, GetThisReg(), full_name); break; } case ReferenceKind::METHOD: @@ -422,14 +422,17 @@ void ETSGen::StoreProperty(const ir::AstNode *const node, const checker::Type *p } } -void ETSGen::LoadProperty(const ir::AstNode *const node, const checker::Type *prop_type, const VReg obj_reg, - const util::StringView &full_name) +void ETSGen::LoadProperty(const ir::AstNode *const node, const checker::Type *prop_type, bool is_generic, + const VReg obj_reg, const util::StringView &full_name) { if (node->IsIdentifier() && node->AsIdentifier()->Variable()->HasFlag(varbinder::VariableFlags::BOXED)) { prop_type = Checker()->GlobalBuiltinBoxType(prop_type); } if (prop_type->HasTypeFlag(checker::TypeFlag::ETS_ARRAY_OR_OBJECT | checker::TypeFlag::ETS_UNION)) { Ra().Emit(node, obj_reg, full_name); + if (is_generic) { + EmitCheckCast(node, prop_type); + } } else if (prop_type->HasTypeFlag(checker::TypeFlag::ETS_WIDE_NUMERIC)) { Ra().Emit(node, obj_reg, full_name); } else { @@ -450,11 +453,14 @@ void ETSGen::StoreUnionProperty([[maybe_unused]] const ir::AstNode *node, [[mayb } void ETSGen::LoadUnionProperty([[maybe_unused]] const ir::AstNode *const node, - [[maybe_unused]] const checker::Type *prop_type, [[maybe_unused]] const VReg obj_reg, - [[maybe_unused]] const util::StringView &prop_name) + [[maybe_unused]] const checker::Type *prop_type, [[maybe_unused]] bool is_generic, + [[maybe_unused]] const VReg obj_reg, [[maybe_unused]] const util::StringView &prop_name) { #ifdef PANDA_WITH_ETS Ra().Emit(node, obj_reg, prop_name); + if (is_generic) { + EmitCheckCast(node, prop_type); + } SetAccumulatorType(prop_type); #else UNREACHABLE(); @@ -1158,7 +1164,7 @@ void ETSGen::EmitLocalBoxGet(ir::AstNode const *node, checker::Type const *conte break; default: Ra().Emit(node, Signatures::BUILTIN_BOX_GET, dummy_reg_, 0); - Ra().Emit(node, content_type->AsETSObjectType()->AssemblerName()); + EmitCheckCast(node, content_type); break; } SetAccumulatorType(content_type); @@ -1778,13 +1784,7 @@ void ETSGen::EmitCheckedNarrowingReferenceConversion(const ir::AstNode *const no ASSERT(target_type->HasTypeFlag(checker::TypeFlag::ETS_ARRAY_OR_OBJECT | checker::TypeFlag::ETS_UNION) && !target_type->IsETSNullLike()); - if (target_type->IsETSObjectType()) { - Sa().Emit(node, target_type->AsETSObjectType()->AssemblerName()); - } else { - std::stringstream ss; - target_type->AsETSArrayType()->ToAssemblerTypeWithRank(ss); - Sa().Emit(node, util::UString(ss.str(), Allocator()).View()); - } + Sa().Emit(node, ToCheckCastTypeView(target_type)); SetAccumulatorType(target_type); } @@ -2247,6 +2247,13 @@ void ETSGen::UnaryDollarDollar(const ir::AstNode *node) EmitThrow(node, exception); } +void ETSGen::InsertNeededCheckCast(const checker::Signature *signature, const ir::AstNode *node) +{ + if (signature->IsBaseReturnDiff()) { + EmitCheckCast(node, signature->ReturnType()); + } +} + void ETSGen::Update(const ir::AstNode *node, lexer::TokenType op) { switch (op) { @@ -2607,4 +2614,23 @@ bool ETSGen::ExtendWithFinalizer(ir::AstNode *node, const ir::AstNode *original_ return ExtendWithFinalizer(parent, original_node, prev_finnaly); } +util::StringView ETSGen::ToCheckCastTypeView(const es2panda::checker::Type *type) const +{ + auto asm_t = type; + if (type->IsETSUnionType()) { + asm_t = type->AsETSUnionType()->GetLeastUpperBoundType(); + } + std::stringstream ss; + asm_t->ToAssemblerTypeWithRank(ss); + return util::UString(ss.str(), Allocator()).View(); +} + +void ETSGen::EmitCheckCast(const ir::AstNode *node, const es2panda::checker::Type *type) +{ + if (type->IsETSArrayType()) { + return; // Since generic arrays allowed we can't add checkcast for them. + } + Ra().Emit(node, ToCheckCastTypeView(type)); +} + } // namespace panda::es2panda::compiler diff --git a/ets2panda/compiler/core/ETSGen.h b/ets2panda/compiler/core/ETSGen.h index 7ee98c5619..8fb06d8bb6 100644 --- a/ets2panda/compiler/core/ETSGen.h +++ b/ets2panda/compiler/core/ETSGen.h @@ -69,7 +69,7 @@ public: void StoreProperty(const ir::AstNode *node, const checker::Type *prop_type, VReg obj_reg, const util::StringView &name); - void LoadProperty(const ir::AstNode *node, const checker::Type *prop_type, VReg obj_reg, + void LoadProperty(const ir::AstNode *node, const checker::Type *prop_type, bool is_generic, VReg obj_reg, const util::StringView &full_name); void StorePropertyDynamic(const ir::AstNode *node, const checker::Type *prop_type, VReg obj_reg, const util::StringView &name, Language lang); @@ -80,7 +80,7 @@ public: void LoadElementDynamic(const ir::AstNode *node, VReg object_reg, Language lang); void StoreUnionProperty(const ir::AstNode *node, VReg obj_reg, const util::StringView &name); - void LoadUnionProperty(const ir::AstNode *node, const checker::Type *prop_type, VReg obj_reg, + void LoadUnionProperty(const ir::AstNode *node, const checker::Type *prop_type, bool is_generic, VReg obj_reg, const util::StringView &prop_name); void LoadUndefinedDynamic(const ir::AstNode *node, Language lang); @@ -650,6 +650,12 @@ private: void UnaryTilde(const ir::AstNode *node); void UnaryDollarDollar(const ir::AstNode *node); + util::StringView ToCheckCastTypeView(const es2panda::checker::Type *type) const; + void EmitCheckCast(const ir::AstNode *node, const es2panda::checker::Type *type); + + // To avoid verifier error checkcast is needed + void InsertNeededCheckCast(const checker::Signature *signature, const ir::AstNode *node); + template void StoreValueIntoArray(const ir::AstNode *const node, const VReg arr, const VReg index) { @@ -950,10 +956,7 @@ private: } } - // To avoid verifier error checkcast is needed - if (signature->HasSignatureFlag(checker::SignatureFlags::SUBSTITUTED_RETURN_TYPE)) { - Ra().Emit(node, signature->ReturnType()->AsETSObjectType()->AssemblerName()); - } + InsertNeededCheckCast(signature, node); } template @@ -1009,10 +1012,7 @@ private: } } - // To avoid verifier error checkcast is needed - if (signature->HasSignatureFlag(checker::SignatureFlags::SUBSTITUTED_RETURN_TYPE)) { - Ra().Emit(node, signature->ReturnType()->AsETSObjectType()->AssemblerName()); - } + InsertNeededCheckCast(signature, node); } #undef COMPILE_ARG @@ -1067,10 +1067,7 @@ private: } } - // To avoid verifier error checkcast is needed - if (signature->HasSignatureFlag(checker::SignatureFlags::SUBSTITUTED_RETURN_TYPE)) { - Ra().Emit(node, signature->ReturnType()->AsETSObjectType()->AssemblerName()); - } + InsertNeededCheckCast(signature, node); } #undef COMPILE_ARG diff --git a/ets2panda/ir/expressions/memberExpression.cpp b/ets2panda/ir/expressions/memberExpression.cpp index eda32a4f54..000ba793fd 100644 --- a/ets2panda/ir/expressions/memberExpression.cpp +++ b/ets2panda/ir/expressions/memberExpression.cpp @@ -226,10 +226,10 @@ void MemberExpression::Compile(compiler::ETSGen *etsg) const auto lang = object_type->AsETSDynamicType()->Language(); etsg->LoadPropertyDynamic(this, OptionalType(), obj_reg, prop_name, lang); } else if (object_type->IsETSUnionType()) { - etsg->LoadUnionProperty(this, OptionalType(), obj_reg, prop_name); + etsg->LoadUnionProperty(this, OptionalType(), IsGenericField(), obj_reg, prop_name); } else { const auto full_name = etsg->FormClassPropReference(object_type->AsETSObjectType(), prop_name); - etsg->LoadProperty(this, OptionalType(), obj_reg, full_name); + etsg->LoadProperty(this, OptionalType(), IsGenericField(), obj_reg, full_name); } }; @@ -469,4 +469,22 @@ MemberExpression *MemberExpression::Clone(ArenaAllocator *const allocator, AstNo throw Error(ErrorType::GENERIC, "", CLONE_ALLOCATION_ERROR); } + +bool MemberExpression::IsGenericField() const +{ + const auto obj_t = object_->TsType(); + if (!obj_t->IsETSObjectType()) { + return false; + } + auto base_class_t = obj_t->AsETSObjectType()->GetBaseType(); + if (base_class_t == nullptr) { + return false; + } + const auto &prop_name = property_->AsIdentifier()->Name(); + auto base_prop = base_class_t->GetProperty(prop_name, checker::PropertySearchFlags::SEARCH_FIELD); + if (base_prop == nullptr || base_prop->TsType() == nullptr) { + return false; + } + return TsType()->ToAssemblerName().str() != base_prop->TsType()->ToAssemblerName().str(); +} } // namespace panda::es2panda::ir diff --git a/ets2panda/ir/expressions/memberExpression.h b/ets2panda/ir/expressions/memberExpression.h index 7b638ddffe..5deeabfe47 100644 --- a/ets2panda/ir/expressions/memberExpression.h +++ b/ets2panda/ir/expressions/memberExpression.h @@ -176,6 +176,8 @@ private: checker::Type *CheckUnionMember(checker::ETSChecker *checker, checker::Type *base_type); void LoadRhs(compiler::PandaGen *pg) const; + bool IsGenericField() const; + Expression *object_ = nullptr; Expression *property_ = nullptr; MemberExpressionKind kind_; diff --git a/ets2panda/test/compiler/ets/generics_implicit_lambda1-expected.txt b/ets2panda/test/compiler/ets/generics_implicit_lambda1-expected.txt index 6e86df9a9d..7fc151e937 100644 --- a/ets2panda/test/compiler/ets/generics_implicit_lambda1-expected.txt +++ b/ets2panda/test/compiler/ets/generics_implicit_lambda1-expected.txt @@ -1836,7 +1836,35 @@ "expression": false, "params": [], "returnType": { - "type": "ETSPrimitiveType", + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "Int", + "decorators": [], + "loc": { + "start": { + "line": 38, + "column": 13 + }, + "end": { + "line": 38, + "column": 16 + } + } + }, + "loc": { + "start": { + "line": 38, + "column": 13 + }, + "end": { + "line": 38, + "column": 19 + } + } + }, "loc": { "start": { "line": 38, @@ -1844,7 +1872,7 @@ }, "end": { "line": 38, - "column": 16 + "column": 19 } } }, @@ -1854,8 +1882,64 @@ { "type": "ReturnStatement", "argument": { - "type": "NumberLiteral", - "value": 42, + "type": "ETSNewClassInstanceExpression", + "typeReference": { + "type": "ETSTypeReference", + "part": { + "type": "ETSTypeReferencePart", + "name": { + "type": "Identifier", + "name": "Int", + "decorators": [], + "loc": { + "start": { + "line": 38, + "column": 33 + }, + "end": { + "line": 38, + "column": 36 + } + } + }, + "loc": { + "start": { + "line": 38, + "column": 33 + }, + "end": { + "line": 38, + "column": 37 + } + } + }, + "loc": { + "start": { + "line": 38, + "column": 33 + }, + "end": { + "line": 38, + "column": 37 + } + } + }, + "arguments": [ + { + "type": "NumberLiteral", + "value": 42, + "loc": { + "start": { + "line": 38, + "column": 37 + }, + "end": { + "line": 38, + "column": 39 + } + } + } + ], "loc": { "start": { "line": 38, @@ -1863,7 +1947,7 @@ }, "end": { "line": 38, - "column": 31 + "column": 42 } } }, @@ -1874,7 +1958,7 @@ }, "end": { "line": 38, - "column": 31 + "column": 42 } } } @@ -1886,7 +1970,7 @@ }, "end": { "line": 38, - "column": 33 + "column": 42 } } }, @@ -1897,7 +1981,7 @@ }, "end": { "line": 38, - "column": 33 + "column": 42 } } }, @@ -1908,7 +1992,7 @@ }, "end": { "line": 38, - "column": 33 + "column": 42 } } } @@ -1921,7 +2005,7 @@ }, "end": { "line": 38, - "column": 34 + "column": 43 } } }, @@ -1932,7 +2016,7 @@ }, "end": { "line": 38, - "column": 35 + "column": 44 } } }, diff --git a/ets2panda/test/compiler/ets/generics_implicit_lambda1.ets b/ets2panda/test/compiler/ets/generics_implicit_lambda1.ets index 4a3a18e2c8..d48b0a74d2 100644 --- a/ets2panda/test/compiler/ets/generics_implicit_lambda1.ets +++ b/ets2panda/test/compiler/ets/generics_implicit_lambda1.ets @@ -35,7 +35,7 @@ class X { function main() { foo((): String => { return "XXX" }); - foo((): int => { return 42 }); + foo((): Int => { return new Int(42) }); X( (): String => { return "XXX" }, -- Gitee