@@ -9108,57 +9108,136 @@ bool ConstraintSystem::salvage(SmallVectorImpl<Solution> &viable, Expr *expr) {
9108
9108
return true ;
9109
9109
}
9110
9110
9111
- bool swift::diagnoseUnwrap (TypeChecker &TC, DeclContext *DC,
9112
- Expr *expr, Type type) {
9111
+ // Suggest a default value via ?? <default value>
9112
+ static void offerDefaultValueUnwrapFixit (TypeChecker &TC, DeclContext *DC, Expr *expr) {
9113
+ auto diag =
9114
+ TC.diagnose (expr->getLoc (), diag::unwrap_with_default_value);
9115
+
9116
+ // Figure out what we need to parenthesize.
9117
+ bool needsParensInside =
9118
+ exprNeedsParensBeforeAddingNilCoalescing (TC, DC, expr);
9119
+ bool needsParensOutside =
9120
+ exprNeedsParensAfterAddingNilCoalescing (TC, DC, expr, expr);
9121
+
9122
+ llvm::SmallString<2 > insertBefore;
9123
+ llvm::SmallString<32 > insertAfter;
9124
+ if (needsParensOutside) {
9125
+ insertBefore += " (" ;
9126
+ }
9127
+ if (needsParensInside) {
9128
+ insertBefore += " (" ;
9129
+ insertAfter += " )" ;
9130
+ }
9131
+ insertAfter += " ?? <" " #default value#" " >" ;
9132
+ if (needsParensOutside)
9133
+ insertAfter += " )" ;
9134
+
9135
+ if (!insertBefore.empty ()) {
9136
+ diag.fixItInsert (expr->getStartLoc (), insertBefore);
9137
+ }
9138
+ diag.fixItInsertAfter (expr->getEndLoc (), insertAfter);
9139
+ }
9140
+
9141
+ // Suggest a force-unwrap.
9142
+ static void offerForceUnwrapFixit (ConstraintSystem &CS, Expr *expr) {
9143
+ auto diag = CS.TC .diagnose (expr->getLoc (), diag::unwrap_with_force_value);
9144
+
9145
+ // If expr is optional as the result of an optional chain and this last
9146
+ // dot isn't a member returning optional, then offer to force the last
9147
+ // link in the chain, rather than an ugly parenthesized postfix force.
9148
+ if (auto optionalChain = dyn_cast<OptionalEvaluationExpr>(expr)) {
9149
+ if (auto dotExpr =
9150
+ dyn_cast<UnresolvedDotExpr>(optionalChain->getSubExpr ())) {
9151
+ auto bind = dyn_cast<BindOptionalExpr>(dotExpr->getBase ());
9152
+ if (bind && !CS.getType (dotExpr)->getOptionalObjectType ()) {
9153
+ diag.fixItReplace (SourceRange (bind->getLoc ()), " !" );
9154
+ return ;
9155
+ }
9156
+ }
9157
+ }
9158
+
9159
+ if (expr->canAppendPostfixExpression (true )) {
9160
+ diag.fixItInsertAfter (expr->getEndLoc (), " !" );
9161
+ } else {
9162
+ diag.fixItInsert (expr->getStartLoc (), " (" )
9163
+ .fixItInsertAfter (expr->getEndLoc (), " )!" );
9164
+ }
9165
+ }
9166
+
9167
+ class VarDeclMultipleReferencesChecker : public ASTWalker {
9168
+ VarDecl *varDecl;
9169
+ int count;
9170
+
9171
+ std::pair<bool , Expr *> walkToExprPre (Expr *E) {
9172
+ if (auto *DRE = dyn_cast<DeclRefExpr>(E)) {
9173
+ if (DRE->getDecl () == varDecl)
9174
+ count++;
9175
+ }
9176
+ return { true , E };
9177
+ }
9178
+
9179
+ public:
9180
+ VarDeclMultipleReferencesChecker (VarDecl *varDecl) : varDecl(varDecl),count(0 ) {}
9181
+ int referencesCount () { return count; }
9182
+ };
9183
+
9184
+ bool swift::diagnoseUnwrap (ConstraintSystem &CS, Expr *expr, Type type) {
9113
9185
Type unwrappedType = type->getOptionalObjectType ();
9114
9186
if (!unwrappedType)
9115
9187
return false ;
9116
9188
9117
- TC.diagnose (expr->getLoc (), diag::optional_not_unwrapped, type,
9118
- unwrappedType);
9189
+ CS.TC .diagnose (expr->getLoc (), diag::optional_not_unwrapped, type,
9190
+ unwrappedType);
9191
+
9192
+ // If the expression we're unwrapping is the only reference to a
9193
+ // local variable whose type isn't explicit in the source, then
9194
+ // offer unwrapping fixits on the initializer as well.
9195
+ if (auto declRef = dyn_cast<DeclRefExpr>(expr)) {
9196
+ if (auto varDecl = dyn_cast<VarDecl>(declRef->getDecl ())) {
9197
+
9198
+ bool singleUse = false ;
9199
+ AbstractFunctionDecl *AFD = nullptr ;
9200
+ if (auto contextDecl = varDecl->getDeclContext ()->getAsDeclOrDeclExtensionContext ()) {
9201
+ if ((AFD = dyn_cast<AbstractFunctionDecl>(contextDecl))) {
9202
+ auto checker = VarDeclMultipleReferencesChecker (varDecl);
9203
+ AFD->getBody ()->walk (checker);
9204
+ singleUse = checker.referencesCount () == 1 ;
9205
+ }
9206
+ }
9119
9207
9120
- // Suggest a default value via ?? <default value>
9121
- {
9122
- auto diag =
9123
- TC.diagnose (expr->getLoc (), diag::unwrap_with_default_value);
9208
+ PatternBindingDecl *binding = varDecl->getParentPatternBinding ();
9209
+ if (singleUse && binding && binding->getNumPatternEntries () == 1 &&
9210
+ varDecl->getTypeSourceRangeForDiagnostics ().isInvalid ()) {
9124
9211
9125
- // Figure out what we need to parenthesize.
9126
- bool needsParensInside =
9127
- exprNeedsParensBeforeAddingNilCoalescing (TC, DC, expr);
9128
- bool needsParensOutside =
9129
- exprNeedsParensAfterAddingNilCoalescing (TC, DC, expr, expr);
9212
+ Expr *initializer = varDecl->getParentInitializer ();
9213
+ if (auto declRefExpr = dyn_cast<DeclRefExpr>(initializer)) {
9214
+ if (declRefExpr->getDecl ()->getAttrs ().hasAttribute <ImplicitlyUnwrappedOptionalAttr>()) {
9215
+ CS.TC .diagnose (declRefExpr->getLoc (), diag::unwrap_iuo_initializer, type);
9216
+ }
9217
+ }
9130
9218
9131
- llvm::SmallString<2 > insertBefore;
9132
- llvm::SmallString<32 > insertAfter;
9133
- if (needsParensOutside) {
9134
- insertBefore += " (" ;
9135
- }
9136
- if (needsParensInside) {
9137
- insertBefore += " (" ;
9138
- insertAfter += " )" ;
9139
- }
9140
- insertAfter += " ?? <" " #default value#" " >" ;
9141
- if (needsParensOutside)
9142
- insertAfter += " )" ;
9219
+ auto fnTy = AFD->getInterfaceType ()->castTo <AnyFunctionType>();
9220
+ bool voidReturn = fnTy->getResult ()->isEqual (TupleType::getEmpty (CS.DC ->getASTContext ()));
9143
9221
9144
- if (!insertBefore.empty ()) {
9145
- diag.fixItInsert (expr->getStartLoc (), insertBefore);
9146
- }
9147
- diag.fixItInsertAfter (expr->getEndLoc (), insertAfter);
9148
- }
9222
+ auto diag = CS.TC .diagnose (varDecl->getLoc (), diag::unwrap_with_guard);
9223
+ diag.fixItInsert (binding->getStartLoc (), " guard " );
9224
+ if (voidReturn) {
9225
+ diag.fixItInsertAfter (binding->getEndLoc (), " else { return }" );
9226
+ } else {
9227
+ diag.fixItInsertAfter (binding->getEndLoc (), " else { return <"
9228
+ " #default value#" " > }" );
9229
+ }
9230
+ diag.flush ();
9149
9231
9150
- // Suggest a force-unwrap.
9151
- {
9152
- auto diag =
9153
- TC.diagnose (expr->getLoc (), diag::unwrap_with_force_value);
9154
- if (expr->canAppendPostfixExpression (true )) {
9155
- diag.fixItInsertAfter (expr->getEndLoc (), " !" );
9156
- } else {
9157
- diag.fixItInsert (expr->getStartLoc (), " (" )
9158
- .fixItInsertAfter (expr->getEndLoc (), " )!" );
9232
+ offerDefaultValueUnwrapFixit (CS.TC , varDecl->getDeclContext (),
9233
+ initializer);
9234
+ offerForceUnwrapFixit (CS, initializer);
9235
+ }
9159
9236
}
9160
9237
}
9161
9238
9239
+ offerDefaultValueUnwrapFixit (CS.TC , CS.DC , expr);
9240
+ offerForceUnwrapFixit (CS, expr);
9162
9241
return true ;
9163
9242
}
9164
9243
0 commit comments