Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
78 commits
Select commit Hold shift + click to select a range
3d2c18e
Add tests for tuple unpacking variable init/assignment
arifthpe Jul 24, 2025
333c191
Test normal assignment rather than split-init
arifthpe Jul 25, 2025
c98ac78
Switch tuple expression kind back to CONST_VAR
arifthpe Aug 1, 2025
7e99afa
Get copy init for tuple unpack assignment working
arifthpe Aug 1, 2025
6b2cf61
Comment out most CID tests for iterating on tuples
arifthpe Aug 13, 2025
77e9482
Add stub VarScopeVisitor::handleTupleDeclaration
arifthpe Aug 13, 2025
d4bf443
Stub out resolveTupleInit
arifthpe Aug 13, 2025
6a6489f
Uncomment more tuple tests
arifthpe Aug 13, 2025
4b0c626
Add sub-actions and second ID to AssociatedAction
arifthpe Aug 13, 2025
8f0c9fa
Set up testing sub-actions and other ID in testCallInitDeinit
arifthpe Aug 13, 2025
13e6085
Add some tests for tuple init= with sub actions
arifthpe Aug 13, 2025
ee0e749
Reorder and stringify new AssociatedAction fields
arifthpe Aug 13, 2025
4520f8a
Restore semantics of getLhsForTupleUnpackAssign
arifthpe Aug 14, 2025
8eba0aa
Resolve init for each tuple elt
arifthpe Aug 14, 2025
015466f
Resolve sub-actions per tuple idx
arifthpe Aug 14, 2025
0b3e213
Add AssociatedAction::dump
arifthpe Aug 19, 2025
68e44ac
Fix sub-action hierarchy for nested tuple expr
arifthpe Aug 19, 2025
7d97c95
Adjust tuple destructuring LHS types to var
arifthpe Aug 19, 2025
b87ba39
Use type alias for sub-actions field
arifthpe Aug 19, 2025
c0d526c
wip checkpoint on copy elision/split init for destructuring assignment
arifthpe Aug 27, 2025
6c7669a
Rename resolveTupleUnpackAssignOrInit
arifthpe Aug 28, 2025
9f39b77
Cleanups
arifthpe Aug 28, 2025
71354cf
Checkpoint on destructuring declarations
arifthpe Aug 28, 2025
d1aa2ff
Fix actions generated for destructuring decl
arifthpe Aug 29, 2025
c32e6f2
Uncomment tests
arifthpe Aug 29, 2025
9bec97b
Implement tuple destructuring decl copy elision
arifthpe Aug 29, 2025
eae7af8
Implement tuple destucturing decl copy elision
arifthpe Aug 29, 2025
68d780f
Fix saving multiple elision points for tuple destructuring decl
arifthpe Aug 29, 2025
5dccddb
Fix copy elision for tuple destructuring assignment
arifthpe Aug 29, 2025
29d0c79
Allow TupleDecl to contain Formals
arifthpe Aug 29, 2025
3d1fce3
Fix some attempts to use nonexistent init expr
arifthpe Aug 29, 2025
f797081
Remove straggling breakpoint
arifthpe Aug 29, 2025
938f25c
Improve test cases
arifthpe Aug 29, 2025
763dfdd
Skip underscores in tuple decl copy elision
arifthpe Sep 2, 2025
6db0c2f
Implement copy elision from tuple expr RHS
arifthpe Sep 2, 2025
d29e3c5
Avoid move init for tuple elts (rather than assign)
arifthpe Sep 2, 2025
c157870
Expect VAR kind for lhs tuple expr elts
arifthpe Sep 2, 2025
1bf2078
Expect tuple = actions on op rather than elt
arifthpe Sep 2, 2025
8786426
Emit tuple unpack assign size mismatch error just once
arifthpe Sep 2, 2025
b23fe24
Add test for tuple expr containing tuple vars
arifthpe Nov 7, 2025
d0c9e61
Fix handling of tuple expr containing tuple vars
arifthpe Nov 7, 2025
ff9c9cf
Skip default-init of tuple-grouped loop indices
arifthpe Nov 12, 2025
d752c18
Remove debugger breakpoints
arifthpe Nov 12, 2025
97a8f94
Use helper for loop index decl check, make VSV enter tuples
arifthpe Nov 12, 2025
152c453
Track current position in tuple decl nests
arifthpe Nov 13, 2025
2b70846
Clean up and document VSV helper methods
arifthpe Nov 13, 2025
69d2d71
Fix some index mistakes
arifthpe Nov 13, 2025
fa0be9b
Unify decl handling interface between VSV subclasses
arifthpe Nov 13, 2025
950d51c
Use tuple decl's properties for nested decls
arifthpe Nov 13, 2025
1425de1
Fix bad autoformat
arifthpe Nov 13, 2025
8c789b4
Fix AST stack indexing and handle unknown types
arifthpe Nov 18, 2025
5ec1186
Fix recovering decl type info from containing tuple decl
arifthpe Nov 18, 2025
ada9d6b
call-init-deinit add tuple idx to associated actions
arifthpe Nov 18, 2025
c554c9b
Fix copy elision from tuple var
arifthpe Nov 18, 2025
e1097e2
Skip _ var decls in VarScopeVisitor
arifthpe Nov 19, 2025
3876f9e
Loop through tuple expr RHS in copy elision
arifthpe Nov 19, 2025
ea34161
Fix copy elision on nested tuple expr
arifthpe Nov 19, 2025
ef57e02
Merge branch 'main' into tuple-unpacking-copy-init
arifthpe Nov 20, 2025
a3c994c
Merge branch 'main' into tuple-unpacking-copy-init
arifthpe Dec 1, 2025
0aa0858
Merge branch 'main' into tuple-unpacking-copy-init
arifthpe Dec 3, 2025
bda4c81
Expect MOVE_INIT after NEW_INIT as appropriate
arifthpe Dec 3, 2025
e596dfb
Additional tuple copy elision fixes, simplify CID
arifthpe Dec 4, 2025
6d0183f
Add more tuple split init test cases
arifthpe Dec 4, 2025
6e8436e
Merge branch 'main' into tuple-unpacking-copy-init
arifthpe Dec 5, 2025
900c0f8
checkpoint
arifthpe Dec 5, 2025
3e64886
Merge branch 'main' into tuple-unpacking-copy-init
arifthpe Dec 8, 2025
23958ee
Fix traversal of tuple expr assignments
arifthpe Dec 9, 2025
df803a8
Fix order of traversing nested tuples, plus refactor
arifthpe Dec 9, 2025
ce001a4
Adjust tuple expr special case comment
arifthpe Dec 9, 2025
393cb54
Pass rhsAst to more processInit call sites
arifthpe Dec 9, 2025
86691e0
Merge branch 'main' into tuple-unpacking-copy-init
arifthpe Dec 9, 2025
24e7aca
Skip _ in tuple assign
arifthpe Dec 9, 2025
6ec00dc
Put back tuple unpack assignment kind adjustments
arifthpe Dec 9, 2025
c0cd5bf
Merge branch 'main' into tuple-unpacking-copy-init
arifthpe Dec 10, 2025
a3a0f48
Fix detecting split-init via tuple destructuring
arifthpe Dec 10, 2025
85167d6
Set rhsAst for tuple assign even if RHS isn't tuple expr
arifthpe Dec 10, 2025
f3e3cc3
Count copy elision in assignment LHS rather than assignment itself
arifthpe Dec 10, 2025
1f78bef
Track copy-elided tuple expr RHS components
arifthpe Dec 10, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions frontend/include/chpl/framework/mark-functions.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,15 @@ template<typename T, size_t i> struct mark<llvm::SmallVector<T, i>> {
}
};

template<typename T, size_t i> struct mark<llvm::SmallVector<T*, i>> {
void operator()(Context* context, const llvm::SmallVector<T*, i>& keep) const {
for (auto const &elt : keep) {
chpl::mark<T> marker;
marker(context, elt);
}
}
};

template<typename T> struct mark<chpl::optional<T>> {
void operator()(Context* context, const chpl::optional<T>& keep) const {
if (keep) {
Expand Down
8 changes: 6 additions & 2 deletions frontend/include/chpl/resolution/copy-elision.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,13 @@
#include "chpl/resolution/resolution-types.h"

#include <set>
#include <unordered_map>

namespace chpl {
namespace resolution {


/* Computes the set of IDs of initialization points
/* Computes the IDs of initialization points
that can be 'move's rather than '=' or 'copy-init'.
* If the elided initialization point is a variable initialization expr,
the ID of the initialized variable is stored in the set.
Expand All @@ -40,14 +41,17 @@ namespace resolution {
* If the elided initialization point is a 'yield' statement, the
ID of the 'yield' is stored in the set.

The value corresponding to the ID key is the ID of the init part being moved
from.

Does not consider copy elision that only work with temporary
variables (e.g. acceptsWithIn(returnsByValue())).

This is not a query. It may raise errors within the currently running query.

allSplitInitedVars can be computed by computeSplitInits.
*/
std::set<ID>
std::unordered_map<ID, ID>
computeElidedCopies(Context* context,
const uast::AstNode* symbol,
const ResolutionResultByPostorderID& byPostorder,
Expand Down
65 changes: 59 additions & 6 deletions frontend/include/chpl/resolution/resolution-types.h
Original file line number Diff line number Diff line change
Expand Up @@ -2569,22 +2569,41 @@ class AssociatedAction {
TUPLE_CAST,
};

using ActionsList = llvm::SmallVector<const AssociatedAction*>;

private:
Action action_;
const TypedFnSignature* fn_;
ID id_;
types::QualifiedType type_;

// An index associated with some tuple per-element actions, where it is
// necessary to keep track of which tuple element the action applies to.
// The sentinel value of -1 indicates no associated tuple element.
int tupleEltIdx_ = -1;

// A list of actions contained within this one.
// Currently only used for tuple copy-init-deinit, where each element may
// have a sub-action.
ActionsList subActions_;

public:
AssociatedAction(Action action, const TypedFnSignature* fn, ID id,
types::QualifiedType type)
: action_(action), fn_(fn), id_(id), type_(type) {
}
types::QualifiedType type, int tupleEltIdx = -1,
ActionsList subActions = {})
: action_(action),
fn_(fn),
id_(id),
type_(type),
tupleEltIdx_(tupleEltIdx),
subActions_(std::move(subActions)) {}
bool operator==(const AssociatedAction& other) const {
return action_ == other.action_ &&
fn_ == other.fn_ &&
id_ == other.id_ &&
type_ == other.type_;
type_ == other.type_ &&
tupleEltIdx_ == other.tupleEltIdx_ &&
subActions_ == other.subActions_;
}
bool operator!=(const AssociatedAction& other) const {
return !(*this == other);
Expand All @@ -2600,15 +2619,40 @@ class AssociatedAction {

const types::QualifiedType type() const { return type_; }

bool hasTupleEltIdx() const {
return tupleEltIdx_ != -1;
}

const int tupleEltIndex() const {
CHPL_ASSERT(hasTupleEltIdx());
return tupleEltIdx_;
}

const ActionsList& subActions() const {
return subActions_;
}

size_t hash() const {
return chpl::hash(action_, fn_, id_, type_, tupleEltIdx_, subActions_);
}

void mark(Context* context) const {
if (fn_ != nullptr) fn_->mark(context);
id_.mark(context);
type_.mark(context);
chpl::mark<decltype(tupleEltIdx_)>{}(context, tupleEltIdx_);
for (const auto& subAction : subActions_) {
subAction->mark(context);
}
}

void stringify(std::ostream& ss, chpl::StringifyKind stringKind) const;

static const char* kindToString(Action a);

/// \cond DO_NOT_DOCUMENT
DECLARE_DUMP;
/// \endcond DO_NOT_DOCUMENT
};

class ResolvedParamLoop;
Expand Down Expand Up @@ -2729,12 +2773,20 @@ class ResolvedExpression {
/** set the point-of-instantiation scope */
void setPoiScope(const PoiScope* poiScope) { poiScope_ = poiScope; }

/** add an associated function */
/** remove all associated actions */
void clearAssociatedActions() {
associatedActions_.clear();
}

/** add an associated action */
void addAssociatedAction(AssociatedAction::Action action,
const TypedFnSignature* fn,
ID id,
types::QualifiedType type) {
associatedActions_.push_back(AssociatedAction(action, fn, id, type));
addAssociatedAction(AssociatedAction(action, fn, id, type));
}
void addAssociatedAction(AssociatedAction action) {
associatedActions_.push_back(action);
}

void setParamLoop(const ResolvedParamLoop* paramLoop) { paramLoop_ = paramLoop; }
Expand Down Expand Up @@ -3689,6 +3741,7 @@ CHPL_DEFINE_STD_HASH_(MostSpecificCandidate, (key.hash()));
CHPL_DEFINE_STD_HASH_(MostSpecificCandidates, (key.hash()));
CHPL_DEFINE_STD_HASH_(CallResolutionResult, (key.hash()));
CHPL_DEFINE_STD_HASH_(TheseResolutionResult, (key.hash()));
CHPL_DEFINE_STD_HASH_(AssociatedAction, (key.hash()));
CHPL_DEFINE_STD_HASH_(ResolvedFields, (key.hash()));
CHPL_DEFINE_STD_HASH_(FieldDetail, (key.hash()));
CHPL_DEFINE_STD_HASH_(ForwardingDetail, (key.hash()));
Expand Down
2 changes: 1 addition & 1 deletion frontend/include/chpl/uast/TupleDecl.h
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ class TupleDecl final : public Decl {
const Decl* decl(int i) const {
CHPL_ASSERT(i >= 0 && i < numDecls());
const AstNode* ast = this->child(i);
CHPL_ASSERT(ast->isVariable() || ast->isTupleDecl());
CHPL_ASSERT(ast->isVariable() || ast->isFormal() || ast->isTupleDecl());
CHPL_ASSERT(ast->isDecl());
return (const Decl*)ast;
}
Expand Down
2 changes: 2 additions & 0 deletions frontend/lib/resolution/InitResolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1021,6 +1021,8 @@ bool InitResolver::handleAssignmentToField(const OpCall* node) {
auto lhs = node->actual(0);
auto rhs = node->actual(1);

// TODO: handle assignment to field(s) via tuple destructuring

// TODO: Is 'field' or 'this.field' too strict of a pattern?
auto [fieldId, isSuperField] = fieldIdFromPossibleMentionOfField(lhs);

Expand Down
11 changes: 11 additions & 0 deletions frontend/lib/resolution/Resolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3251,6 +3251,17 @@ bool Resolver::resolveSpecialOpCall(const Call* call) {
if (op->numActuals() == 2) {
// Update a generic/unknown type when split-init is used.
adjustTypesOnAssign(op->actual(0), op->actual(1));

if (auto lhsTuple = op->actual(0)->toTuple()) {
auto rhsQt = byPostorder.byAst(op->actual(1)).type();
if (auto rhsTupleType = rhsQt.type()->toTupleType()) {
if (lhsTuple->numActuals() != rhsTupleType->numElements()) {
context->error(call, "tuple size mismatch in split tuple assign");
byPostorder.byAst(call).setType(QualifiedType(
QualifiedType::UNKNOWN, ErroneousType::get(context)));
}
}
}
}
} else if (op->op() == USTR("...")) {
// just leave it unknown -- tuple expansion only makes sense
Expand Down
Loading
Loading