Skip to content

Commit 2bbedbe

Browse files
committed
Handle in/inout formals when promotion occurs in call-init-deinit etc.
Prior to this commit, call-init-deinit would always resolve `init=` or `=` using the exact type of the actual. This is not the appropriate thing to do when promotion is involved, since it's the yielded type / scalar type that's being copied. This commit adjusts VarScopeVisitor's API to behave properly in this case (including, but not limited to, disabling copy elision for promoted calls) Signed-off-by: Danila Fedorin <[email protected]>
1 parent 46b70a1 commit 2bbedbe

File tree

7 files changed

+78
-15
lines changed

7 files changed

+78
-15
lines changed

frontend/lib/resolution/Resolver.cpp

+10-4
Original file line numberDiff line numberDiff line change
@@ -2548,12 +2548,18 @@ void Resolver::adjustTypesOnAssign(const AstNode* lhsAst,
25482548
void
25492549
Resolver::adjustTypesForOutFormals(const CallInfo& ci,
25502550
const std::vector<const AstNode*>& asts,
2551-
const MostSpecificCandidates& fns) {
2551+
const CallResolutionResult& crr) {
25522552

2553+
const PromotionIteratorType* promotionCtx = nullptr;
2554+
if (!crr.exprType().isUnknownOrErroneous()) {
2555+
promotionCtx = crr.exprType().type()->toPromotionIteratorType();
2556+
}
25532557
std::vector<QualifiedType> actualFormalTypes;
25542558
std::vector<Qualifier> actualIntents;
2555-
computeActualFormalIntents(context, fns, ci, asts,
2556-
actualIntents, actualFormalTypes);
2559+
std::vector<bool> actualPromoted;
2560+
computeActualFormalIntents(context, crr.mostSpecific(), ci, asts,
2561+
actualIntents, actualFormalTypes, actualPromoted,
2562+
promotionCtx);
25572563

25582564
int actualIdx = 0;
25592565
for (const auto& actual : ci.actuals()) {
@@ -5560,7 +5566,7 @@ void Resolver::handleCallExpr(const uast::Call* call) {
55605566
c.noteResultPrintCandidates(&r);
55615567

55625568
// handle type inference for variables split-inited by 'out' formals
5563-
adjustTypesForOutFormals(ci, actualAsts, c.result.mostSpecific());
5569+
adjustTypesForOutFormals(ci, actualAsts, c.result);
55645570

55655571
// issue errors for iterator groups where e.g. serial/standalone types mismatch
55665572
issueIteratorDiagnosticsIfNeeded(*this, call, inScopes, c.result);

frontend/lib/resolution/Resolver.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -602,7 +602,7 @@ struct Resolver : BranchSensitiveVisitor<DefaultFrame> {
602602
// handles setting types of variables for split init with 'out' formals
603603
void adjustTypesForOutFormals(const CallInfo& ci,
604604
const std::vector<const uast::AstNode*>& asts,
605-
const MostSpecificCandidates& fns);
605+
const CallResolutionResult& crr);
606606

607607
// helper for resolveTupleDecl
608608
// e.g. var (a, b) = mytuple

frontend/lib/resolution/VarScopeVisitor.cpp

+38-5
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
#include "chpl/parsing/parsing-queries.h"
2323
#include "chpl/resolution/ResolvedVisitor.h"
24+
#include "chpl/resolution/resolution-queries.h"
2425
#include "chpl/resolution/resolution-types.h"
2526
#include "chpl/resolution/scope-queries.h"
2627
#include "chpl/uast/all-uast.h"
@@ -404,13 +405,34 @@ bool VarScopeVisitor::enter(const FnCall* callAst, RV& rv) {
404405
actualAsts.insert(actualAsts.begin(), nullptr);
405406
}
406407

408+
407409
// compute a vector indicating which actuals are passed to
408410
// an 'out' formal in all return intent overloads
411+
const PromotionIteratorType* promoCtx = nullptr;
412+
if (!rr->type().isUnknownOrErroneous()) {
413+
promoCtx = rr->type().type()->toPromotionIteratorType();
414+
}
409415
std::vector<QualifiedType> actualFormalTypes;
410416
std::vector<Qualifier> actualFormalIntents;
417+
std::vector<bool> actualPromoted;
411418
computeActualFormalIntents(context, candidates, ci, actualAsts,
412-
actualFormalIntents, actualFormalTypes);
413-
419+
actualFormalIntents, actualFormalTypes,
420+
actualPromoted, promoCtx);
421+
422+
// for a given actual index, returns:
423+
// * nullptr if no promotion ocurred
424+
// * the scalar type of the given actual was used in promotion
425+
// * the actual type itself if it was not
426+
// This can be used to signal to handleInFormal() etc. to adjust
427+
// their behavior for promotion, and to provide the additional information
428+
// of the scalar type.
429+
auto getScalarType = [&](int idx) {
430+
auto& actualQt = ci.actual(idx).type();
431+
return
432+
promoCtx == nullptr ? nullptr :
433+
actualPromoted[idx] ? &getPromotionType(context, actualQt) :
434+
&actualQt;
435+
};
414436
int actualIdx = 0;
415437
for (auto actual : ci.actuals()) {
416438
(void) actual; // avoid compilation error about unused variable
@@ -428,11 +450,12 @@ bool VarScopeVisitor::enter(const FnCall* callAst, RV& rv) {
428450
!(ci.name() == "init" && actualIdx == 0)) {
429451
// don't do this for the 'this' argument to 'init', because it
430452
// is not getting copied.
453+
431454
handleInFormal(callAst, actualAst,
432-
actualFormalTypes[actualIdx], rv);
455+
actualFormalTypes[actualIdx], getScalarType(actualIdx), rv);
433456
} else if (kind == Qualifier::INOUT) {
434457
handleInoutFormal(callAst, actualAst,
435-
actualFormalTypes[actualIdx], rv);
458+
actualFormalTypes[actualIdx], getScalarType(actualIdx), rv);
436459
} else {
437460
// otherwise, visit the actuals to gather mentions
438461
actualAst->traverse(rv);
@@ -576,13 +599,17 @@ computeActualFormalIntents(Context* context,
576599
const CallInfo& ci,
577600
const std::vector<const AstNode*>& actualAsts,
578601
std::vector<Qualifier>& actualFormalIntents,
579-
std::vector<QualifiedType>& actualFormalTypes) {
602+
std::vector<QualifiedType>& actualFormalTypes,
603+
std::vector<bool>& actualPromoted,
604+
const types::PromotionIteratorType* promoCtx) {
580605

581606
int nActuals = ci.numActuals();
582607
actualFormalIntents.clear();
583608
actualFormalIntents.resize(nActuals);
584609
actualFormalTypes.clear();
585610
actualFormalTypes.resize(nActuals);
611+
actualPromoted.clear();
612+
actualPromoted.resize(nActuals);
586613

587614
int nFns = candidates.numBest();
588615
if (nFns == 0) {
@@ -599,6 +626,12 @@ computeActualFormalIntents(Context* context,
599626
auto intent = normalizeFormalIntent(fa->formalType().kind());
600627
QualifiedType& aft = actualFormalTypes[actualIdx];
601628

629+
// all actualPromoted are guaranteed to be the same IF all the
630+
// formal types are guaranteed to be the same, which they are
631+
// using the checks below.
632+
actualPromoted[actualIdx] =
633+
promoCtx && promoCtx->promotedFormals().count(fa->formal()->id()) > 0;
634+
602635
if (firstCandidate) {
603636
actualFormalIntents[actualIdx] = intent;
604637
if (intent != Qualifier::UNKNOWN) {

frontend/lib/resolution/VarScopeVisitor.h

+5-1
Original file line numberDiff line numberDiff line change
@@ -80,11 +80,13 @@ class VarScopeVisitor : public BranchSensitiveVisitor<VarFrame, MutatingResolved
8080
virtual void handleInFormal(const uast::FnCall* ast,
8181
const uast::AstNode* actual,
8282
const types::QualifiedType& formalType,
83+
const types::QualifiedType* actualScalarType,
8384
RV& rv) = 0;
8485
/** Called for an actual passed to an 'out' formal */
8586
virtual void handleInoutFormal(const uast::FnCall* ast,
8687
const uast::AstNode* actual,
8788
const types::QualifiedType& formalType,
89+
const types::QualifiedType* actualScalarType,
8890
RV& rv) = 0;
8991

9092
/** Called for a 'return' */
@@ -302,7 +304,9 @@ computeActualFormalIntents(Context* context,
302304
const CallInfo& ci,
303305
const std::vector<const AstNode*>& actualAsts,
304306
std::vector<uast::Qualifier>& actualFrmlIntents,
305-
std::vector<types::QualifiedType>& actualFrmlTypes);
307+
std::vector<types::QualifiedType>& actualFrmlTypes,
308+
std::vector<bool>& actualWasPromoted,
309+
const types::PromotionIteratorType* promoCtx);
306310

307311
} // end namespace resolution
308312

frontend/lib/resolution/call-init-deinit.cpp

+11-3
Original file line numberDiff line numberDiff line change
@@ -131,9 +131,11 @@ struct CallInitDeinit : VarScopeVisitor {
131131
RV& rv) override;
132132
void handleInFormal(const FnCall* ast, const AstNode* actual,
133133
const QualifiedType& formalType,
134+
const QualifiedType* actualScalarType,
134135
RV& rv) override;
135136
void handleInoutFormal(const FnCall* ast, const AstNode* actual,
136137
const QualifiedType& formalType,
138+
const QualifiedType* actualScalarType,
137139
RV& rv) override;
138140
void handleReturn(const uast::Return* ast, RV& rv) override;
139141
void handleThrow(const uast::Throw* ast, RV& rv) override;
@@ -719,9 +721,10 @@ void CallInitDeinit::resolveCopyInit(const AstNode* ast,
719721

720722
std::vector<Qualifier> intents;
721723
std::vector<QualifiedType> formalTypes;
724+
std::vector<bool> actualPromoted;
722725

723726
computeActualFormalIntents(context, c.result.mostSpecific(), ci, actualAsts,
724-
intents, formalTypes);
727+
intents, formalTypes, actualPromoted, /* promotionCtx */ nullptr);
725728

726729
bool formalUsesInIntent = false;
727730
CHPL_ASSERT(intents.size() >= 1);
@@ -1128,6 +1131,7 @@ void CallInitDeinit::handleOutFormal(const FnCall* ast,
11281131
}
11291132
void CallInitDeinit::handleInFormal(const FnCall* ast, const AstNode* actual,
11301133
const QualifiedType& formalType,
1134+
const QualifiedType* actualScalarType,
11311135
RV& rv) {
11321136
VarFrame* frame = currentFrame();
11331137

@@ -1147,6 +1151,7 @@ void CallInitDeinit::handleInFormal(const FnCall* ast, const AstNode* actual,
11471151
if (elidedCopyFromIds.count(actual->id()) > 0 &&
11481152
isValue(actualType.kind()) &&
11491153
Type::needsInitDeinitCall(actualType.type())) {
1154+
CHPL_ASSERT(actualScalarType == nullptr);
11501155
// it is move initialization
11511156
resolveMoveInit(actual, actual, formalType, actualType, rv);
11521157

@@ -1157,13 +1162,15 @@ void CallInitDeinit::handleInFormal(const FnCall* ast, const AstNode* actual,
11571162
CHPL_ASSERT(!actualId.isEmpty());
11581163
frame->deinitedVars.emplace(actualId, ast->id());
11591164
} else {
1160-
processInit(frame, actual, formalType, actualType, rv);
1165+
processInit(frame, actual, formalType,
1166+
actualScalarType ? *actualScalarType : actualType, rv);
11611167
}
11621168
}
11631169

11641170
void CallInitDeinit::handleInoutFormal(const FnCall* ast,
11651171
const AstNode* actual,
11661172
const QualifiedType& formalType,
1173+
const QualifiedType* actualScalarType,
11671174
RV& rv) {
11681175
// check for use of deinited variables
11691176
processMentions(actual, rv);
@@ -1172,7 +1179,8 @@ void CallInitDeinit::handleInoutFormal(const FnCall* ast,
11721179
QualifiedType actualType = rv.byAst(actual).type();
11731180

11741181
// resolve '=' for storing and writeback
1175-
resolveAssign(actual, actualType, formalType, rv);
1182+
resolveAssign(actual,
1183+
actualScalarType ? *actualScalarType : actualType, formalType, rv);
11761184
}
11771185

11781186
void CallInitDeinit::processReturnThrowYield(const uast::AstNode* ast, RV& rv) {

frontend/lib/resolution/copy-elision.cpp

+9-1
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,11 @@ struct FindElidedCopies : VarScopeVisitor {
9393
RV& rv) override;
9494
void handleInFormal(const FnCall* ast, const AstNode* actual,
9595
const QualifiedType& formalType,
96+
const QualifiedType* actualScalarType,
9697
RV& rv) override;
9798
void handleInoutFormal(const FnCall* ast, const AstNode* actual,
9899
const QualifiedType& formalType,
100+
const QualifiedType* actualScalarType,
99101
RV& rv) override;
100102

101103
void handleReturn(const uast::Return* ast, RV& rv) override;
@@ -345,13 +347,18 @@ void FindElidedCopies::handleOutFormal(const FnCall* ast,
345347
}
346348
void FindElidedCopies::handleInFormal(const FnCall* ast, const AstNode* actual,
347349
const QualifiedType& formalType,
350+
const QualifiedType* actualScalarType,
348351
RV& rv) {
349352
// 'in' formal can be copied from another variable, and that
350353
// copy might need to be elided
351354
VarFrame* frame = currentFrame();
352355
ID actualToId = refersToId(actual, rv);
353356
bool elide = false;
354-
if (!actualToId.isEmpty() && isEligibleVarInAnyFrame(actualToId)) {
357+
if (actualScalarType) {
358+
// cannot do copy elision across promotion, since a single actual variable
359+
// feeds into several scalar formals.
360+
elide = false;
361+
} else if (!actualToId.isEmpty() && isEligibleVarInAnyFrame(actualToId)) {
355362
// check that the types are the same
356363
if (rv.hasId(actualToId)) {
357364
QualifiedType actualType = rv.byId(actualToId).type();
@@ -370,6 +377,7 @@ void FindElidedCopies::handleInFormal(const FnCall* ast, const AstNode* actual,
370377
void FindElidedCopies::handleInoutFormal(const FnCall* ast,
371378
const AstNode* actual,
372379
const QualifiedType& formalType,
380+
const QualifiedType* actualScalarType,
373381
RV& rv) {
374382
// 'inout' can't be the RHS for an elided copy
375383
processMentions(actual, rv);

frontend/lib/resolution/split-init.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,11 @@ struct FindSplitInits : VarScopeVisitor {
6969
RV& rv) override;
7070
void handleInFormal(const FnCall* ast, const AstNode* actual,
7171
const QualifiedType& formalType,
72+
const QualifiedType* actualScalarType,
7273
RV& rv) override;
7374
void handleInoutFormal(const FnCall* ast, const AstNode* actual,
7475
const QualifiedType& formalType,
76+
const QualifiedType* actualScalarType,
7577
RV& rv) override;
7678

7779
void handleReturn(const uast::Return* ast, RV& rv) override;
@@ -210,12 +212,14 @@ void FindSplitInits::handleOutFormal(const FnCall* ast, const AstNode* actual,
210212

211213
void FindSplitInits::handleInFormal(const FnCall* ast, const AstNode* actual,
212214
const QualifiedType& formalType,
215+
const QualifiedType* actualScalarType,
213216
RV& rv) {
214217
processMentions(actual, rv);
215218
}
216219

217220
void FindSplitInits::handleInoutFormal(const FnCall* ast, const AstNode* actual,
218221
const QualifiedType& formalType,
222+
const QualifiedType* actualScalarType,
219223
RV& rv) {
220224
processMentions(actual, rv);
221225
}

0 commit comments

Comments
 (0)