From 99f4c484c208bafcde855e8a25c92445bd82a3f6 Mon Sep 17 00:00:00 2001 From: Brandon Neth <brandon.neth@hpe.com> Date: Wed, 2 Oct 2024 11:52:24 -0700 Subject: [PATCH 1/7] code for the resolution, but the opcall intents are still not sorted. --- Signed-off-by: Brandon Neth <brandon.neth@hpe.com> --- frontend/lib/resolution/InitResolver.cpp | 10 +++++++--- frontend/lib/resolution/InitResolver.h | 3 +++ frontend/lib/resolution/call-init-deinit.cpp | 5 ++++- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/frontend/lib/resolution/InitResolver.cpp b/frontend/lib/resolution/InitResolver.cpp index a95db6ea8b7a..40aee6fda1ca 100644 --- a/frontend/lib/resolution/InitResolver.cpp +++ b/frontend/lib/resolution/InitResolver.cpp @@ -769,13 +769,17 @@ bool InitResolver::handleAssignmentToField(const OpCall* node) { // field doesn't contribute to the receiver type. updateResolverVisibleReceiverType(); - auto lhsKind = state->qt.kind(); - if (lhsKind != QualifiedType::TYPE && lhsKind != QualifiedType::PARAM) { + auto reLhs = initResolver_.byPostorder.byId(lhs->id()); + auto lhsQt = reLhs.type(); + + auto lhsKind = lhsQt.kind(); + if (lhsKind != QualifiedType::TYPE && lhsKind != QualifiedType::PARAM && isConstQualifier(lhsKind)) { // Regardless of the field's intent, it is mutable in this expression. lhsKind = QualifiedType::REF; } - auto lhsType = QualifiedType(lhsKind, state->qt.type(), state->qt.param()); + auto lhsType = QualifiedType(lhsKind, lhsQt.type(), lhsQt.param()); initResolver_.byPostorder.byAst(lhs).setType(lhsType); + initPoints.insert(node); } else { CHPL_ASSERT(0 == "Not handled yet!"); diff --git a/frontend/lib/resolution/InitResolver.h b/frontend/lib/resolution/InitResolver.h index 471762d746f6..2c61db7dc9c8 100644 --- a/frontend/lib/resolution/InitResolver.h +++ b/frontend/lib/resolution/InitResolver.h @@ -129,6 +129,9 @@ class InitResolver { public: + //initialization points to guide handling `=` operators + std::set<const uast::AstNode*> initPoints; + static owned<InitResolver> create(Context* context, Resolver& visitor, const uast::Function* fn); diff --git a/frontend/lib/resolution/call-init-deinit.cpp b/frontend/lib/resolution/call-init-deinit.cpp index 30b2bcdad1de..f3260de622be 100644 --- a/frontend/lib/resolution/call-init-deinit.cpp +++ b/frontend/lib/resolution/call-init-deinit.cpp @@ -899,12 +899,15 @@ void CallInitDeinit::handleAssign(const OpCall* ast, RV& rv) { // check for use of deinited variables processMentions(ast, rv); - + + bool isIniting = resolver.initResolver->initPoints.count(ast) > 0; if (lhsType.isType() || lhsType.isParam()) { // these are basically 'move' initialization resolveMoveInit(ast, rhsAst, lhsType, rhsType, rv); } else if (splitInited) { processInit(frame, ast, lhsType, rhsType, rv); + } else if (isIniting) { + processInit(frame, ast, lhsType, rhsType, rv); } else { // it is assignment, so resolve the '=' call resolveAssign(ast, lhsType, rhsType, rv); From d6842be3bffe1a8ca9ba8edc7d9d4e050184abf9 Mon Sep 17 00:00:00 2001 From: Brandon Neth <brandon.neth@hpe.com> Date: Wed, 2 Oct 2024 11:54:49 -0700 Subject: [PATCH 2/7] simplified logic. --- Signed-off-by: Brandon Neth <brandon.neth@hpe.com> --- frontend/lib/resolution/call-init-deinit.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/frontend/lib/resolution/call-init-deinit.cpp b/frontend/lib/resolution/call-init-deinit.cpp index f3260de622be..b4f7b6ad3037 100644 --- a/frontend/lib/resolution/call-init-deinit.cpp +++ b/frontend/lib/resolution/call-init-deinit.cpp @@ -900,12 +900,10 @@ void CallInitDeinit::handleAssign(const OpCall* ast, RV& rv) { // check for use of deinited variables processMentions(ast, rv); - bool isIniting = resolver.initResolver->initPoints.count(ast) > 0; + bool isIniting = splitInited || resolver.initResolver->initPoints.count(ast) > 0; if (lhsType.isType() || lhsType.isParam()) { // these are basically 'move' initialization resolveMoveInit(ast, rhsAst, lhsType, rhsType, rv); - } else if (splitInited) { - processInit(frame, ast, lhsType, rhsType, rv); } else if (isIniting) { processInit(frame, ast, lhsType, rhsType, rv); } else { From d530bdedcd9549f723b2916bd2b2195275a106d2 Mon Sep 17 00:00:00 2001 From: Brandon Neth <brandon.neth@hpe.com> Date: Wed, 2 Oct 2024 12:35:49 -0700 Subject: [PATCH 3/7] test based on github issue code --- Signed-off-by: Brandon Neth <brandon.neth@hpe.com> --- .../test/resolution/testInitSemantics.cpp | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/frontend/test/resolution/testInitSemantics.cpp b/frontend/test/resolution/testInitSemantics.cpp index 28d5a22321c7..db5262e2ffcf 100644 --- a/frontend/test/resolution/testInitSemantics.cpp +++ b/frontend/test/resolution/testInitSemantics.cpp @@ -1627,6 +1627,28 @@ static void testInitGenericAfterConcrete() { } } +static void testNilFieldInit() { + std::string program = R"""( + class C { var x: int; } + + record R { + var x: unmanaged C?; + proc init() { + x = nil; + } + } + + var x: R; + )"""; + Context ctx; + Context* context = &ctx; + ErrorGuard guard(context); + auto t = resolveTypeOfX(context, program); + assert(t); + assert(t->isRecordType()); + + assert(guard.errors().size() == 0); +}; // TODO: // - test using defaults for types and params // - also in conditionals @@ -1673,6 +1695,7 @@ int main() { testInitGenericAfterConcrete(); + testNilFieldInit(); return 0; } From bbc7c26de134fa23f5b1f77c2795a56f89a9b35f Mon Sep 17 00:00:00 2001 From: Brandon Neth <brandon.neth@hpe.com> Date: Wed, 2 Oct 2024 13:28:31 -0700 Subject: [PATCH 4/7] updated tests --- Signed-off-by: Brandon Neth <brandon.neth@hpe.com> --- frontend/test/resolution/testInitSemantics.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/frontend/test/resolution/testInitSemantics.cpp b/frontend/test/resolution/testInitSemantics.cpp index db5262e2ffcf..3fe0615b4f8e 100644 --- a/frontend/test/resolution/testInitSemantics.cpp +++ b/frontend/test/resolution/testInitSemantics.cpp @@ -1643,12 +1643,21 @@ static void testNilFieldInit() { Context ctx; Context* context = &ctx; ErrorGuard guard(context); - auto t = resolveTypeOfX(context, program); - assert(t); - assert(t->isRecordType()); + ResolutionContext rcval(context); + auto rc = &rcval; + auto m = parseModule(context, std::move(program)); + auto recordDecl = m->stmt(1)->toAggregateDecl(); + auto initFunc = recordDecl->declOrComment(1)->toFunction(); + assert(initFunc); + + auto untyped = UntypedFnSignature::get(context, initFunc); + auto typed = typedSignatureInitial(rc, untyped); + auto inFn = resolveFunction(rc, typed, nullptr); + assert(inFn); assert(guard.errors().size() == 0); }; + // TODO: // - test using defaults for types and params // - also in conditionals From 538f734f46baeedededc32f179d1e568bd34a7e2 Mon Sep 17 00:00:00 2001 From: Brandon Neth <brandon.neth@hpe.com> Date: Wed, 2 Oct 2024 13:40:18 -0700 Subject: [PATCH 5/7] fixed nullptr segfault --- Signed-off-by: Brandon Neth <brandon.neth@hpe.com> --- frontend/lib/resolution/call-init-deinit.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frontend/lib/resolution/call-init-deinit.cpp b/frontend/lib/resolution/call-init-deinit.cpp index b4f7b6ad3037..9e1c4562e9e1 100644 --- a/frontend/lib/resolution/call-init-deinit.cpp +++ b/frontend/lib/resolution/call-init-deinit.cpp @@ -900,7 +900,8 @@ void CallInitDeinit::handleAssign(const OpCall* ast, RV& rv) { // check for use of deinited variables processMentions(ast, rv); - bool isIniting = splitInited || resolver.initResolver->initPoints.count(ast) > 0; + bool isIniting = splitInited; + isIniting |= resolver.initResolver && resolver.initResolver->initPoints.count(ast) > 0; if (lhsType.isType() || lhsType.isParam()) { // these are basically 'move' initialization resolveMoveInit(ast, rhsAst, lhsType, rhsType, rv); From 7f81b4968b52071f2725e041cd90a10021bec9cc Mon Sep 17 00:00:00 2001 From: Brandon Neth <brandon.neth@hpe.com> Date: Wed, 2 Oct 2024 15:06:13 -0700 Subject: [PATCH 6/7] whitespace and matching lhs to rhs --- Signed-off-by: Brandon Neth <brandon.neth@hpe.com> --- frontend/lib/resolution/InitResolver.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/frontend/lib/resolution/InitResolver.cpp b/frontend/lib/resolution/InitResolver.cpp index 40aee6fda1ca..5fe535be1dc6 100644 --- a/frontend/lib/resolution/InitResolver.cpp +++ b/frontend/lib/resolution/InitResolver.cpp @@ -769,9 +769,8 @@ bool InitResolver::handleAssignmentToField(const OpCall* node) { // field doesn't contribute to the receiver type. updateResolverVisibleReceiverType(); - auto reLhs = initResolver_.byPostorder.byId(lhs->id()); + auto& reLhs = initResolver_.byPostorder.byId(lhs->id()); auto lhsQt = reLhs.type(); - auto lhsKind = lhsQt.kind(); if (lhsKind != QualifiedType::TYPE && lhsKind != QualifiedType::PARAM && isConstQualifier(lhsKind)) { // Regardless of the field's intent, it is mutable in this expression. From 0ee005a2aac7bad5cda879ebcef66e818510c294 Mon Sep 17 00:00:00 2001 From: Brandon Neth <brandon.neth@hpe.com> Date: Thu, 10 Oct 2024 12:55:23 -0700 Subject: [PATCH 7/7] Ben's feedback on PR --- Signed-off-by: Brandon Neth <brandon.neth@hpe.com> --- frontend/lib/resolution/InitResolver.cpp | 6 +++++- frontend/lib/resolution/InitResolver.h | 3 +++ frontend/lib/resolution/call-init-deinit.cpp | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/frontend/lib/resolution/InitResolver.cpp b/frontend/lib/resolution/InitResolver.cpp index 5fe535be1dc6..48c92bb12b25 100644 --- a/frontend/lib/resolution/InitResolver.cpp +++ b/frontend/lib/resolution/InitResolver.cpp @@ -760,6 +760,7 @@ bool InitResolver::handleAssignmentToField(const OpCall* node) { // TODO: Anything to do if the opposite is true? if (!isAlreadyInitialized) { auto& reRhs = initResolver_.byPostorder.byAst(rhs); + auto& reLhs = initResolver_.byPostorder.byId(lhs->id()); state->qt = reRhs.type(); state->initPointId = node->id(); state->isInitialized = true; @@ -769,7 +770,6 @@ bool InitResolver::handleAssignmentToField(const OpCall* node) { // field doesn't contribute to the receiver type. updateResolverVisibleReceiverType(); - auto& reLhs = initResolver_.byPostorder.byId(lhs->id()); auto lhsQt = reLhs.type(); auto lhsKind = lhsQt.kind(); if (lhsKind != QualifiedType::TYPE && lhsKind != QualifiedType::PARAM && isConstQualifier(lhsKind)) { @@ -893,5 +893,9 @@ void InitResolver::checkEarlyReturn(const Return* ret) { } } +bool InitResolver::isInitPoint(const uast::AstNode* node) { + return initPoints.find(node) != initPoints.end(); +} + } // end namespace resolution } // end namespace chpl diff --git a/frontend/lib/resolution/InitResolver.h b/frontend/lib/resolution/InitResolver.h index 2c61db7dc9c8..73450a9a9129 100644 --- a/frontend/lib/resolution/InitResolver.h +++ b/frontend/lib/resolution/InitResolver.h @@ -158,6 +158,9 @@ class InitResolver { const TypedFnSignature* finalize(void); void checkEarlyReturn(const uast::Return* ret); + + // Returns true if the AST node is an initialization point + bool isInitPoint(const uast::AstNode* node); }; } // end namespace resolution diff --git a/frontend/lib/resolution/call-init-deinit.cpp b/frontend/lib/resolution/call-init-deinit.cpp index 9e1c4562e9e1..3bd1474416d6 100644 --- a/frontend/lib/resolution/call-init-deinit.cpp +++ b/frontend/lib/resolution/call-init-deinit.cpp @@ -901,7 +901,7 @@ void CallInitDeinit::handleAssign(const OpCall* ast, RV& rv) { processMentions(ast, rv); bool isIniting = splitInited; - isIniting |= resolver.initResolver && resolver.initResolver->initPoints.count(ast) > 0; + isIniting |= resolver.initResolver && resolver.initResolver->isInitPoint(ast); if (lhsType.isType() || lhsType.isParam()) { // these are basically 'move' initialization resolveMoveInit(ast, rhsAst, lhsType, rhsType, rv);