Skip to content

Commit b5d15ae

Browse files
committed
Update type checking for mutate accessors
1 parent ca2a2e7 commit b5d15ae

File tree

5 files changed

+40
-13
lines changed

5 files changed

+40
-13
lines changed

include/swift/Sema/SyntacticElementTarget.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -262,8 +262,9 @@ class SyntacticElementTarget {
262262
unsigned patternBindingIndex, bool bindPatternVarsOneWay);
263263

264264
/// Form an expression target for a ReturnStmt.
265-
static SyntacticElementTarget
266-
forReturn(ReturnStmt *returnStmt, Type contextTy, DeclContext *dc);
265+
static SyntacticElementTarget forReturn(ReturnStmt *returnStmt,
266+
Expr *returnExpr, Type contextTy,
267+
DeclContext *dc);
267268

268269
/// Form a target for the preamble of a for-in loop, excluding its where
269270
/// clause and body.

lib/AST/ASTVerifier.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1097,9 +1097,15 @@ class Verifier : public ASTWalker {
10971097
void verifyChecked(ReturnStmt *S) {
10981098
auto func = Functions.back();
10991099
Type resultType;
1100+
bool hasInOutResult = false;
1101+
11001102
if (auto *FD = dyn_cast<FuncDecl>(func)) {
11011103
resultType = FD->getResultInterfaceType();
11021104
resultType = FD->mapTypeIntoContext(resultType);
1105+
hasInOutResult = FD->getInterfaceType()
1106+
->castTo<AnyFunctionType>()
1107+
->getExtInfo()
1108+
.hasInOutResult();
11031109
} else if (auto closure = dyn_cast<AbstractClosureExpr>(func)) {
11041110
resultType = closure->getResultType();
11051111
} else if (isa<ConstructorDecl>(func)) {
@@ -1112,6 +1118,9 @@ class Verifier : public ASTWalker {
11121118
auto result = S->getResult();
11131119
auto returnType = result->getType();
11141120
// Make sure that the return has the same type as the function.
1121+
if (hasInOutResult) {
1122+
resultType = InOutType::get(resultType);
1123+
}
11151124
checkSameType(resultType, returnType, "return type");
11161125
} else {
11171126
// Make sure that the function has a Void result type.

lib/Sema/SyntacticElementTarget.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -170,13 +170,14 @@ SyntacticElementTarget SyntacticElementTarget::forInitialization(
170170
return result;
171171
}
172172

173-
SyntacticElementTarget
174-
SyntacticElementTarget::forReturn(ReturnStmt *returnStmt, Type contextTy,
175-
DeclContext *dc) {
173+
SyntacticElementTarget SyntacticElementTarget::forReturn(ReturnStmt *returnStmt,
174+
Expr *returnExpr,
175+
Type contextTy,
176+
DeclContext *dc) {
176177
assert(contextTy);
177178
assert(returnStmt->hasResult() && "Must have result to be type-checked");
178179
ContextualTypeInfo contextInfo(contextTy, CTP_ReturnStmt);
179-
SyntacticElementTarget target(returnStmt->getResult(), dc, contextInfo,
180+
SyntacticElementTarget target(returnExpr, dc, contextInfo,
180181
/*isDiscarded*/ false);
181182
target.expression.parentReturnStmt = returnStmt;
182183
return target;

lib/Sema/TypeCheckDecl.cpp

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2571,11 +2571,6 @@ InterfaceTypeRequest::evaluate(Evaluator &eval, ValueDecl *D) const {
25712571
infoBuilder.withLifetimeDependencies(*lifetimeDependenceInfo);
25722572
}
25732573

2574-
auto *accessor = dyn_cast<AccessorDecl>(AFD);
2575-
if (accessor && accessor->isMutateAccessor()) {
2576-
infoBuilder = infoBuilder.withHasInOutResult();
2577-
}
2578-
25792574
auto info = infoBuilder.build();
25802575

25812576
if (sig && !hasSelf) {
@@ -2595,7 +2590,10 @@ InterfaceTypeRequest::evaluate(Evaluator &eval, ValueDecl *D) const {
25952590
selfInfoBuilder =
25962591
selfInfoBuilder.withLifetimeDependencies(*lifetimeDependenceInfo);
25972592
}
2598-
2593+
auto *accessor = dyn_cast<AccessorDecl>(AFD);
2594+
if (accessor && accessor->isMutateAccessor()) {
2595+
selfInfoBuilder = selfInfoBuilder.withHasInOutResult();
2596+
}
25992597
// FIXME: Verify ExtInfo state is correct, not working by accident.
26002598
auto selfInfo = selfInfoBuilder.build();
26012599
if (sig) {

lib/Sema/TypeCheckStmt.cpp

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1112,8 +1112,26 @@ class StmtChecker : public StmtVisitor<StmtChecker, Stmt*> {
11121112
return RS;
11131113
}
11141114

1115+
auto *accessor = TheFunc->getAccessorDecl();
1116+
auto *exprToCheck = RS->getResult();
1117+
InOutExpr *inout = nullptr;
1118+
1119+
if (accessor && accessor->isMutateAccessor()) {
1120+
// Check that the returned expression is a &.
1121+
if ((inout = dyn_cast<InOutExpr>(exprToCheck))) {
1122+
ResultTy = InOutType::get(ResultTy);
1123+
} else {
1124+
getASTContext()
1125+
.Diags
1126+
.diagnose(exprToCheck->getLoc(), diag::missing_address_of_return)
1127+
.highlight(exprToCheck->getSourceRange());
1128+
inout = new (getASTContext()) InOutExpr(
1129+
exprToCheck->getStartLoc(), exprToCheck, Type(), /*implicit*/ true);
1130+
}
1131+
}
11151132
using namespace constraints;
1116-
auto target = SyntacticElementTarget::forReturn(RS, ResultTy, DC);
1133+
auto target =
1134+
SyntacticElementTarget::forReturn(RS, exprToCheck, ResultTy, DC);
11171135
auto resultTarget = TypeChecker::typeCheckTarget(target);
11181136
if (resultTarget) {
11191137
RS->setResult(resultTarget->getAsExpr());

0 commit comments

Comments
 (0)