|
20 | 20 | #include "VarScopeVisitor.h" |
21 | 21 |
|
22 | 22 | #include "chpl/parsing/parsing-queries.h" |
| 23 | +#include "chpl/resolution/can-pass.h" |
23 | 24 | #include "chpl/resolution/ResolvedVisitor.h" |
24 | 25 | #include "chpl/resolution/resolution-queries.h" |
25 | 26 | #include "chpl/resolution/resolution-types.h" |
@@ -227,6 +228,45 @@ int VarScopeVisitor::indexWithinContainingTuple(const AstNode* ast) const { |
227 | 228 | return indexWithinParent; |
228 | 229 | } |
229 | 230 |
|
| 231 | +// Adjusts LHS tuple type so that its components are all values. |
| 232 | +// Does no sanity checks. |
| 233 | +static QualifiedType |
| 234 | +getLhsForTupleUnpackAssign(Context* context, |
| 235 | + const uast::AstNode* astForErr, |
| 236 | + const Tuple* lhsTuple, |
| 237 | + const QualifiedType& lhsType) { |
| 238 | + std::vector<QualifiedType> eltTypes; |
| 239 | + |
| 240 | + auto lhsT = lhsType.type() ? lhsType.type()->toTupleType() : nullptr; |
| 241 | + if (!lhsT || lhsT->numElements() != lhsTuple->numActuals()) return lhsType; |
| 242 | + |
| 243 | + for (int i = 0; i < lhsTuple->numActuals(); i++) { |
| 244 | + auto actual = lhsTuple->actual(i); |
| 245 | + auto ident = actual->toIdentifier(); |
| 246 | + QualifiedType qt; |
| 247 | + |
| 248 | + if (ident && ident->name() == USTR("_")) { |
| 249 | + // If the LHS actual is '_', then use the Nothing type. This is fine |
| 250 | + // since the '_' will never be set. |
| 251 | + qt = { QualifiedType::VAR, NothingType::get(context) }; |
| 252 | + |
| 253 | + } else { |
| 254 | + // Otherwise, turn its qualifier into 'var' / 'const var' |
| 255 | + auto eqt = lhsT->elementType(i); |
| 256 | + auto useKind = KindProperties::removeRef(eqt.kind()); |
| 257 | + qt = { useKind, eqt.type(), eqt.param() }; |
| 258 | + } |
| 259 | + |
| 260 | + eltTypes.push_back(std::move(qt)); |
| 261 | + } |
| 262 | + |
| 263 | + // Set the 'LHS' tuple type. |
| 264 | + auto k = QualifiedType::VAR; |
| 265 | + auto t = TupleType::getQualifiedTuple(context, std::move(eltTypes)); |
| 266 | + QualifiedType ret = { k, t }; |
| 267 | + return ret; |
| 268 | +} |
| 269 | + |
230 | 270 | const QualifiedType& VarScopeVisitor::returnOrYieldType() { |
231 | 271 | return fnReturnType; |
232 | 272 | } |
@@ -546,6 +586,13 @@ bool VarScopeVisitor::enter(const Tuple* ast, RV& rv) { |
546 | 586 |
|
547 | 587 | if (!inTupleAssignment) return true; |
548 | 588 |
|
| 589 | + // TODO: tests expect these kind adjustments to be done, but why here vs |
| 590 | + // in resolution? |
| 591 | + auto lhsTupleType = rv.byAst(ast).type(); |
| 592 | + auto adjustedLhsType = |
| 593 | + getLhsForTupleUnpackAssign(context, inTupleAssignment, ast, lhsTupleType); |
| 594 | + rv.byPostorder().byAst(ast).setType(adjustedLhsType); |
| 595 | + |
549 | 596 | // Gather info for this assignment (at whatever level of nesting) |
550 | 597 | QualifiedType tupInitType = QualifiedType(); |
551 | 598 | const Tuple* tupInitPart = nullptr; |
|
0 commit comments