Skip to content

Commit 3d387dd

Browse files
committed
Change typeCheckExpression() to Type.
Doing this allows us to return ErrorType in some circumstances where we want to communicate that we don't have a usable type rather than writing ErrorType directly into the type of the expression root, avoiding a mutation of the expression tree in a failure case.
1 parent 9e4523a commit 3d387dd

File tree

7 files changed

+85
-84
lines changed

7 files changed

+85
-84
lines changed

lib/Sema/CSApply.cpp

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -495,9 +495,10 @@ namespace {
495495
refExpr = declRefExpr;
496496
}
497497

498-
if (tc.typeCheckExpression(refExpr, cs.DC,
499-
TypeLoc::withoutLoc(expectedFnType),
500-
CTP_CannotFail))
498+
auto resultTy = tc.typeCheckExpression(
499+
refExpr, cs.DC, TypeLoc::withoutLoc(expectedFnType),
500+
CTP_CannotFail);
501+
if (!resultTy)
501502
return nullptr;
502503

503504
cs.cacheExprTypes(refExpr);
@@ -3613,14 +3614,12 @@ namespace {
36133614
Expr *callExpr = CallExpr::createImplicit(ctx, fnRef, { argExpr },
36143615
{ Identifier() });
36153616

3616-
bool invalid = tc.typeCheckExpression(callExpr, cs.DC,
3617-
TypeLoc::withoutLoc(valueType),
3618-
CTP_CannotFail);
3619-
cs.cacheExprTypes(callExpr);
3620-
3621-
(void) invalid;
3622-
assert(!invalid && "conversion cannot fail");
3617+
auto resultTy = tc.typeCheckExpression(
3618+
callExpr, cs.DC, TypeLoc::withoutLoc(valueType), CTP_CannotFail);
3619+
assert(resultTy && "Conversion cannot fail!");
3620+
(void)resultTy;
36233621

3622+
cs.cacheExprTypes(callExpr);
36243623
E->setSemanticExpr(callExpr);
36253624
return E;
36263625
}
@@ -4515,13 +4514,12 @@ getCallerDefaultArg(ConstraintSystem &cs, DeclContext *dc,
45154514

45164515
// Convert the literal to the appropriate type.
45174516
auto defArgType = ownerFn->mapTypeIntoContext(defArg.second);
4518-
bool invalid = tc.typeCheckExpression(init, dc,
4519-
TypeLoc::withoutLoc(defArgType),
4520-
CTP_CannotFail);
4521-
cs.cacheExprTypes(init);
4517+
auto resultTy = tc.typeCheckExpression(
4518+
init, dc, TypeLoc::withoutLoc(defArgType), CTP_CannotFail);
4519+
assert(resultTy && "Conversion cannot fail");
4520+
(void)resultTy;
45224521

4523-
assert(!invalid && "conversion cannot fail");
4524-
(void)invalid;
4522+
cs.cacheExprTypes(init);
45254523

45264524
return {init, defArg.first};
45274525
}

lib/Sema/CSDiag.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3357,7 +3357,7 @@ Expr *FailureDiagnosis::typeCheckChildIndependently(
33573357
// important, isn't itself sufficient because of AST mutation.
33583358
eraseOpenedExistentials(subExpr);
33593359

3360-
bool hadError = CS.TC.typeCheckExpression(
3360+
auto resultTy = CS.TC.typeCheckExpression(
33613361
subExpr, CS.DC, TypeLoc::withoutLoc(convertType), convertTypePurpose,
33623362
TCEOptions, listener, &CS);
33633363

@@ -3371,12 +3371,12 @@ Expr *FailureDiagnosis::typeCheckChildIndependently(
33713371

33723372
// If recursive type checking failed, then an error was emitted. Return
33733373
// null to indicate this to the caller.
3374-
if (hadError)
3374+
if (!resultTy)
33753375
return nullptr;
33763376

33773377
// If we type checked the result but failed to get a usable output from it,
33783378
// just pretend as though nothing happened.
3379-
if (subExpr->getType()->is<ErrorType>()) {
3379+
if (resultTy->is<ErrorType>()) {
33803380
subExpr = preCheckedExpr;
33813381
SavedTypeData.restore();
33823382
}

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 25 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1771,7 +1771,7 @@ namespace {
17711771
} // end anonymous namespace
17721772

17731773
#pragma mark High-level entry points
1774-
bool TypeChecker::typeCheckExpression(Expr *&expr, DeclContext *dc,
1774+
Type TypeChecker::typeCheckExpression(Expr *&expr, DeclContext *dc,
17751775
TypeLoc convertType,
17761776
ContextualTypePurpose convertTypePurpose,
17771777
TypeCheckExprOptions options,
@@ -1782,7 +1782,7 @@ bool TypeChecker::typeCheckExpression(Expr *&expr, DeclContext *dc,
17821782
// First, pre-check the expression, validating any types that occur in the
17831783
// expression and folding sequence expressions.
17841784
if (preCheckExpression(expr, dc))
1785-
return true;
1785+
return Type();
17861786

17871787
// Construct a constraint system from this expression.
17881788
ConstraintSystemOptions csOptions = ConstraintSystemFlags::AllowFixes;
@@ -1833,29 +1833,28 @@ bool TypeChecker::typeCheckExpression(Expr *&expr, DeclContext *dc,
18331833
SmallVector<Solution, 4> viable;
18341834
if (solveForExpression(expr, dc, convertType.getType(),
18351835
allowFreeTypeVariables, listener, cs, viable, options))
1836-
return true;
1836+
return Type();
18371837

18381838
// If the client allows the solution to have unresolved type expressions,
18391839
// check for them now. We cannot apply the solution with unresolved TypeVars,
18401840
// because they will leak out into arbitrary places in the resultant AST.
18411841
if (options.contains(TypeCheckExprFlags::AllowUnresolvedTypeVariables) &&
18421842
(viable.size() != 1 ||
18431843
(convertType.getType() && convertType.getType()->hasUnresolvedType()))) {
1844-
expr->setType(ErrorType::get(Context));
1845-
return false;
1844+
return ErrorType::get(Context);
18461845
}
18471846

18481847
auto result = expr;
18491848
auto &solution = viable[0];
18501849
if (listener) {
18511850
result = listener->foundSolution(solution, result);
18521851
if (!result)
1853-
return true;
1852+
return Type();
18541853
}
18551854

18561855
if (options.contains(TypeCheckExprFlags::SkipApplyingSolution)) {
18571856
cleanup.disable();
1858-
return false;
1857+
return cs.getType(expr);
18591858
}
18601859

18611860
// Apply the solution to the expression.
@@ -1866,7 +1865,7 @@ bool TypeChecker::typeCheckExpression(Expr *&expr, DeclContext *dc,
18661865
skipClosures);
18671866
if (!result) {
18681867
// Failure already diagnosed, above, as part of applying the solution.
1869-
return true;
1868+
return Type();
18701869
}
18711870

18721871
if (getLangOpts().DebugConstraintSolver) {
@@ -1879,7 +1878,7 @@ bool TypeChecker::typeCheckExpression(Expr *&expr, DeclContext *dc,
18791878
if (listener) {
18801879
result = listener->appliedSolution(solution, result);
18811880
if (!result) {
1882-
return true;
1881+
return Type();
18831882
}
18841883
}
18851884

@@ -1893,7 +1892,7 @@ bool TypeChecker::typeCheckExpression(Expr *&expr, DeclContext *dc,
18931892

18941893
expr = result;
18951894
cleanup.disable();
1896-
return false;
1895+
return cs.getType(expr);
18971896
}
18981897

18991898
Optional<Type> TypeChecker::
@@ -2241,12 +2240,9 @@ bool TypeChecker::typeCheckBinding(Pattern *&pattern, Expr *&initializer,
22412240
if (skipApplyingSolution)
22422241
flags |= TypeCheckExprFlags::SkipApplyingSolution;
22432242

2244-
bool hadError = typeCheckExpression(initializer, DC, contextualType,
2245-
contextualPurpose,
2246-
flags,
2247-
&listener);
2248-
2249-
if (!hadError) {
2243+
auto resultTy = typeCheckExpression(initializer, DC, contextualType,
2244+
contextualPurpose, flags, &listener);
2245+
if (resultTy) {
22502246
TypeResolutionOptions options;
22512247
options |= TR_OverrideType;
22522248
options |= TR_InExpression;
@@ -2260,15 +2256,14 @@ bool TypeChecker::typeCheckBinding(Pattern *&pattern, Expr *&initializer,
22602256
}
22612257
}
22622258

2263-
if (hadError && !initializer->getType())
2259+
if (!resultTy && !initializer->getType())
22642260
initializer->setType(ErrorType::get(Context));
22652261

22662262
// If the type of the pattern is inferred, assign error types to the pattern
22672263
// and its variables, to prevent it from being referenced by the constraint
22682264
// system.
2269-
if (hadError &&
2270-
(!pattern->hasType() ||
2271-
pattern->getType()->hasUnboundGenericType())) {
2265+
if (!resultTy &&
2266+
(!pattern->hasType() || pattern->getType()->hasUnboundGenericType())) {
22722267
pattern->setType(ErrorType::get(Context));
22732268
pattern->forEachVariable([&](VarDecl *var) {
22742269
// Don't change the type of a variable that we've been able to
@@ -2282,7 +2277,7 @@ bool TypeChecker::typeCheckBinding(Pattern *&pattern, Expr *&initializer,
22822277
});
22832278
}
22842279

2285-
return hadError;
2280+
return !resultTy;
22862281
}
22872282

22882283
bool TypeChecker::typeCheckPatternBinding(PatternBindingDecl *PBD,
@@ -2484,7 +2479,8 @@ bool TypeChecker::typeCheckForEachBinding(DeclContext *dc, ForEachStmt *stmt) {
24842479
assert(seq && "type-checking an uninitialized for-each statement?");
24852480

24862481
// Type-check the for-each loop sequence and element pattern.
2487-
return typeCheckExpression(seq, dc, &listener);
2482+
auto resultTy = typeCheckExpression(seq, dc, &listener);
2483+
return !resultTy;
24882484
}
24892485

24902486
/// \brief Compute the rvalue type of the given expression, which is the
@@ -2545,9 +2541,11 @@ bool TypeChecker::typeCheckCondition(Expr *&expr, DeclContext *dc) {
25452541
// If this expression is already typechecked and has an i1 type, then it has
25462542
// already got its conversion from Boolean back to i1. Just re-typecheck
25472543
// it.
2548-
if (expr->getType() && expr->getType()->isBuiltinIntegerType(1))
2549-
return typeCheckExpression(expr, dc);
2550-
2544+
if (expr->getType() && expr->getType()->isBuiltinIntegerType(1)) {
2545+
auto resultTy = typeCheckExpression(expr, dc);
2546+
return !resultTy;
2547+
}
2548+
25512549
/// Expression type checking listener for conditions.
25522550
class ConditionListener : public ExprTypeCheckListener {
25532551
Expr *OrigExpr = nullptr;
@@ -2585,7 +2583,8 @@ bool TypeChecker::typeCheckCondition(Expr *&expr, DeclContext *dc) {
25852583
};
25862584

25872585
ConditionListener listener;
2588-
return typeCheckExpression(expr, dc, &listener);
2586+
auto resultTy = typeCheckExpression(expr, dc, &listener);
2587+
return !resultTy;
25892588
}
25902589

25912590
bool TypeChecker::typeCheckStmtCondition(StmtCondition &cond, DeclContext *dc,

lib/Sema/TypeCheckDecl.cpp

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3108,9 +3108,10 @@ static void checkEnumRawValues(TypeChecker &TC, EnumDecl *ED) {
31083108
// Check the raw value expr, if we have one.
31093109
if (auto *rawValue = elt->getRawValueExpr()) {
31103110
Expr *typeCheckedExpr = rawValue;
3111-
if (!TC.typeCheckExpression(typeCheckedExpr, ED,
3112-
TypeLoc::withoutLoc(rawTy),
3113-
CTP_EnumCaseRawValue)) {
3111+
auto resultTy = TC.typeCheckExpression(typeCheckedExpr, ED,
3112+
TypeLoc::withoutLoc(rawTy),
3113+
CTP_EnumCaseRawValue);
3114+
if (resultTy) {
31143115
elt->setTypeCheckedRawValueExpr(typeCheckedExpr);
31153116
}
31163117
lastExplicitValueElt = elt;
@@ -3125,9 +3126,9 @@ static void checkEnumRawValues(TypeChecker &TC, EnumDecl *ED) {
31253126
}
31263127
elt->setRawValueExpr(nextValue);
31273128
Expr *typeChecked = nextValue;
3128-
if (!TC.typeCheckExpression(typeChecked, ED,
3129-
TypeLoc::withoutLoc(rawTy),
3130-
CTP_EnumCaseRawValue))
3129+
auto resultTy = TC.typeCheckExpression(
3130+
typeChecked, ED, TypeLoc::withoutLoc(rawTy), CTP_EnumCaseRawValue);
3131+
if (resultTy)
31313132
elt->setTypeCheckedRawValueExpr(typeChecked);
31323133
}
31333134
prevValue = elt->getRawValueExpr();
@@ -8431,10 +8432,10 @@ void TypeChecker::addImplicitEnumConformances(EnumDecl *ED) {
84318432
if (elt->getTypeCheckedRawValueExpr()) continue;
84328433
Expr *typeChecked = elt->getRawValueExpr();
84338434
Type rawTy = ED->mapTypeIntoContext(ED->getRawType());
8434-
bool error = typeCheckExpression(typeChecked, ED,
8435-
TypeLoc::withoutLoc(rawTy),
8436-
CTP_EnumCaseRawValue);
8437-
assert(!error); (void)error;
8435+
auto resultTy = typeCheckExpression(
8436+
typeChecked, ED, TypeLoc::withoutLoc(rawTy), CTP_EnumCaseRawValue);
8437+
assert(resultTy);
8438+
(void)resultTy;
84388439
elt->setTypeCheckedRawValueExpr(typeChecked);
84398440
checkEnumElementErrorHandling(elt);
84408441
}

lib/Sema/TypeCheckStmt.cpp

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -442,12 +442,11 @@ class StmtChecker : public StmtVisitor<StmtChecker, Stmt*> {
442442
RS->isImplicit());
443443
}
444444

445-
auto hadTypeError = TC.typeCheckExpression(E, DC,
446-
TypeLoc::withoutLoc(ResultTy),
447-
CTP_ReturnStmt);
445+
auto exprTy = TC.typeCheckExpression(E, DC, TypeLoc::withoutLoc(ResultTy),
446+
CTP_ReturnStmt);
448447
RS->setResult(E);
449-
450-
if (hadTypeError) {
448+
449+
if (!exprTy) {
451450
tryDiagnoseUnnecessaryCastOverOptionSet(TC.Context, E, ResultTy,
452451
DC->getParentModule());
453452
}
@@ -463,7 +462,7 @@ class StmtChecker : public StmtVisitor<StmtChecker, Stmt*> {
463462

464463
Type exnType = TC.getExceptionType(DC, TS->getThrowLoc());
465464
if (!exnType) return TS;
466-
465+
467466
TC.typeCheckExpression(E, DC, TypeLoc::withoutLoc(exnType), CTP_ThrowStmt);
468467
TS->setSubExpr(E);
469468

@@ -849,11 +848,10 @@ class StmtChecker : public StmtVisitor<StmtChecker, Stmt*> {
849848
}
850849

851850
Stmt *visitSwitchStmt(SwitchStmt *S) {
852-
bool hadError = false;
853-
854851
// Type-check the subject expression.
855852
Expr *subjectExpr = S->getSubjectExpr();
856-
hadError |= TC.typeCheckExpression(subjectExpr, DC);
853+
auto resultTy = TC.typeCheckExpression(subjectExpr, DC);
854+
auto hadError = !resultTy;
857855
if (Expr *newSubjectExpr = TC.coerceToRValue(subjectExpr))
858856
subjectExpr = newSubjectExpr;
859857
S->setSubjectExpr(subjectExpr);
@@ -1261,8 +1259,8 @@ Stmt *StmtChecker::visitBraceStmt(BraceStmt *BS) {
12611259
if (isDiscarded)
12621260
options |= TypeCheckExprFlags::IsDiscarded;
12631261

1264-
bool hadTypeError = TC.typeCheckExpression(SubExpr, DC, TypeLoc(),
1265-
CTP_Unused, options);
1262+
auto resultTy =
1263+
TC.typeCheckExpression(SubExpr, DC, TypeLoc(), CTP_Unused, options);
12661264

12671265
// If a closure expression is unused, the user might have intended
12681266
// to write "do { ... }".
@@ -1275,7 +1273,7 @@ Stmt *StmtChecker::visitBraceStmt(BraceStmt *BS) {
12751273
TC.diagnose(CE->getStartLoc(), diag::brace_stmt_suggest_do)
12761274
.fixItInsert(CE->getStartLoc(), "do ");
12771275
}
1278-
} else if (isDiscarded && !hadTypeError)
1276+
} else if (isDiscarded && resultTy)
12791277
TC.checkIgnoredExpr(SubExpr);
12801278

12811279
elem = SubExpr;
@@ -1331,10 +1329,10 @@ static void checkDefaultArguments(TypeChecker &tc,
13311329
->changeResilienceExpansion(expansion);
13321330

13331331
// Type-check the initializer, then flag that we did so.
1334-
bool hadError = tc.typeCheckExpression(e, initContext,
1335-
TypeLoc::withoutLoc(param->getType()),
1336-
CTP_DefaultParameter);
1337-
if (!hadError) {
1332+
auto resultTy = tc.typeCheckExpression(
1333+
e, initContext, TypeLoc::withoutLoc(param->getType()),
1334+
CTP_DefaultParameter);
1335+
if (resultTy) {
13381336
param->setDefaultValue(e);
13391337
} else {
13401338
param->setDefaultValue(nullptr);
@@ -1422,9 +1420,11 @@ Expr* TypeChecker::constructCallToSuperInit(ConstructorDecl *ctor,
14221420
if (ctor->hasThrows())
14231421
r = new (Context) TryExpr(SourceLoc(), r, Type(), /*implicit=*/true);
14241422

1425-
if (typeCheckExpression(r, ctor, TypeLoc(), CTP_Unused,
1426-
TypeCheckExprFlags::IsDiscarded |
1427-
TypeCheckExprFlags::SuppressDiagnostics))
1423+
auto resultTy =
1424+
typeCheckExpression(r, ctor, TypeLoc(), CTP_Unused,
1425+
TypeCheckExprFlags::IsDiscarded |
1426+
TypeCheckExprFlags::SuppressDiagnostics);
1427+
if (!resultTy)
14281428
return nullptr;
14291429

14301430
return r;

lib/Sema/TypeChecker.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -918,12 +918,14 @@ bool swift::typeCheckExpression(DeclContext *DC, Expr *&parsedExpr) {
918918
auto &ctx = DC->getASTContext();
919919
if (ctx.getLazyResolver()) {
920920
TypeChecker *TC = static_cast<TypeChecker *>(ctx.getLazyResolver());
921-
return TC->typeCheckExpression(parsedExpr, DC);
921+
auto resultTy = TC->typeCheckExpression(parsedExpr, DC);
922+
return !resultTy;
922923
} else {
923924
// Set up a diagnostics engine that swallows diagnostics.
924925
DiagnosticEngine diags(ctx.SourceMgr);
925926
TypeChecker TC(ctx, diags);
926-
return TC.typeCheckExpression(parsedExpr, DC);
927+
auto resultTy = TC.typeCheckExpression(parsedExpr, DC);
928+
return !resultTy;
927929
}
928930
}
929931

0 commit comments

Comments
 (0)