@@ -549,16 +549,67 @@ bool MemberAccessOnOptionalBaseFailure::diagnoseAsError() {
549
549
resultIsOptional, SourceRange ());
550
550
}
551
551
552
- // Suggest a default value via ?? <default value>
553
- static void offerDefaultValueUnwrapFixit (TypeChecker &TC, DeclContext *DC, Expr *expr, Expr *rootExpr) {
554
- auto diag =
555
- TC.diagnose (expr->getLoc (), diag::unwrap_with_default_value);
552
+ Optional<AnyFunctionType::Param>
553
+ MissingOptionalUnwrapFailure::getOperatorParameterFor (Expr *expr) const {
554
+ auto *parentExpr = findParentExpr (expr);
555
+ if (!parentExpr)
556
+ return None;
557
+
558
+ auto getArgIdx = [](TupleExpr *tuple, Expr *argExpr) -> unsigned {
559
+ for (unsigned i = 0 , n = tuple->getNumElements (); i != n; ++i) {
560
+ if (tuple->getElement (i) == argExpr)
561
+ return i;
562
+ }
563
+ llvm_unreachable (" argument is not in enclosing tuple?!" );
564
+ };
565
+
566
+ auto *tupleExpr = dyn_cast<TupleExpr>(parentExpr);
567
+ if (!(tupleExpr && tupleExpr->isImplicit ()))
568
+ return None;
569
+
570
+ parentExpr = findParentExpr (tupleExpr);
571
+ if (!(parentExpr && isa<ApplyExpr>(parentExpr)))
572
+ return None;
573
+
574
+ auto &cs = getConstraintSystem ();
575
+ auto *fnExpr = cast<ApplyExpr>(parentExpr)->getFn ();
576
+ if (auto overload =
577
+ getOverloadChoiceIfAvailable (cs.getConstraintLocator (fnExpr))) {
578
+ if (auto *decl = overload->choice .getDecl ()) {
579
+ if (!decl->isOperator ())
580
+ return None;
581
+
582
+ auto *fnType = overload->openedType ->castTo <FunctionType>();
583
+ return fnType->getParams ()[getArgIdx (tupleExpr, expr)];
584
+ }
585
+ }
586
+
587
+ return None;
588
+ }
589
+
590
+ void MissingOptionalUnwrapFailure::offerDefaultValueUnwrapFixIt (
591
+ DeclContext *DC, Expr *expr) const {
592
+ auto *anchor = getAnchor ();
593
+
594
+ // If anchor is an explicit address-of, or expression which produces
595
+ // an l-value (e.g. first argument of `+=` operator), let's not
596
+ // suggest default value here because that would produce r-value type.
597
+ if (isa<InOutExpr>(anchor))
598
+ return ;
556
599
600
+ if (auto param = getOperatorParameterFor (anchor)) {
601
+ if (param->isInOut ())
602
+ return ;
603
+ }
604
+
605
+ auto diag = emitDiagnostic (expr->getLoc (), diag::unwrap_with_default_value);
606
+
607
+ auto &TC = getTypeChecker ();
557
608
// Figure out what we need to parenthesize.
558
609
bool needsParensInside =
559
- exprNeedsParensBeforeAddingNilCoalescing (TC, DC, expr);
610
+ exprNeedsParensBeforeAddingNilCoalescing (TC, DC, expr);
560
611
bool needsParensOutside =
561
- exprNeedsParensAfterAddingNilCoalescing (TC, DC, expr, rootExpr );
612
+ exprNeedsParensAfterAddingNilCoalescing (TC, DC, expr, getParentExpr () );
562
613
563
614
llvm::SmallString<2 > insertBefore;
564
615
llvm::SmallString<32 > insertAfter;
@@ -580,8 +631,8 @@ static void offerDefaultValueUnwrapFixit(TypeChecker &TC, DeclContext *DC, Expr
580
631
}
581
632
582
633
// Suggest a force-unwrap.
583
- static void offerForceUnwrapFixit (ConstraintSystem &CS, Expr *expr) {
584
- auto diag = CS. TC . diagnose (expr->getLoc (), diag::unwrap_with_force_value);
634
+ void MissingOptionalUnwrapFailure::offerForceUnwrapFixIt ( Expr *expr) const {
635
+ auto diag = emitDiagnostic (expr->getLoc (), diag::unwrap_with_force_value);
585
636
586
637
// If expr is optional as the result of an optional chain and this last
587
638
// dot isn't a member returning optional, then offer to force the last
@@ -590,7 +641,7 @@ static void offerForceUnwrapFixit(ConstraintSystem &CS, Expr *expr) {
590
641
if (auto dotExpr =
591
642
dyn_cast<UnresolvedDotExpr>(optionalChain->getSubExpr ())) {
592
643
auto bind = dyn_cast<BindOptionalExpr>(dotExpr->getBase ());
593
- if (bind && !CS. getType (dotExpr)->getOptionalObjectType ()) {
644
+ if (bind && !getType (dotExpr)->getOptionalObjectType ()) {
594
645
diag.fixItReplace (SourceRange (bind->getLoc ()), " !" );
595
646
return ;
596
647
}
@@ -601,7 +652,7 @@ static void offerForceUnwrapFixit(ConstraintSystem &CS, Expr *expr) {
601
652
diag.fixItInsertAfter (expr->getEndLoc (), " !" );
602
653
} else {
603
654
diag.fixItInsert (expr->getStartLoc (), " (" )
604
- .fixItInsertAfter (expr->getEndLoc (), " )!" );
655
+ .fixItInsertAfter (expr->getEndLoc (), " )!" );
605
656
}
606
657
}
607
658
@@ -622,8 +673,38 @@ class VarDeclMultipleReferencesChecker : public ASTWalker {
622
673
int referencesCount () { return count; }
623
674
};
624
675
625
- static bool diagnoseUnwrap (ConstraintSystem &CS, Expr *expr, Expr *rootExpr, Type baseType,
626
- Type unwrappedType) {
676
+ bool MissingOptionalUnwrapFailure::diagnoseAsError () {
677
+ if (hasComplexLocator ())
678
+ return false ;
679
+
680
+ auto *anchor = getAnchor ();
681
+
682
+ if (auto assignExpr = dyn_cast<AssignExpr>(anchor))
683
+ anchor = assignExpr->getSrc ();
684
+
685
+ auto *unwrappedExpr = anchor->getValueProvidingExpr ();
686
+
687
+ if (auto *tryExpr = dyn_cast<OptionalTryExpr>(unwrappedExpr)) {
688
+ bool isSwift5OrGreater = getASTContext ().isSwiftVersionAtLeast (5 );
689
+ auto subExprType = getType (tryExpr->getSubExpr ());
690
+ bool subExpressionIsOptional = (bool )subExprType->getOptionalObjectType ();
691
+
692
+ if (isSwift5OrGreater && subExpressionIsOptional) {
693
+ // Using 'try!' won't change the type for a 'try?' with an optional
694
+ // sub-expr under Swift 5+, so just report that a missing unwrap can't be
695
+ // handled here.
696
+ return false ;
697
+ }
698
+
699
+ emitDiagnostic (tryExpr->getTryLoc (), diag::missing_unwrap_optional_try,
700
+ getType (anchor)->getRValueType ())
701
+ .fixItReplace ({tryExpr->getTryLoc (), tryExpr->getQuestionLoc ()},
702
+ " try!" );
703
+ return true ;
704
+ }
705
+
706
+ auto baseType = getBaseType ();
707
+ auto unwrappedType = getUnwrappedType ();
627
708
628
709
assert (!baseType->hasTypeVariable () &&
629
710
" Base type must not be a type variable" );
@@ -633,15 +714,14 @@ static bool diagnoseUnwrap(ConstraintSystem &CS, Expr *expr, Expr *rootExpr, Typ
633
714
if (!baseType->getOptionalObjectType ())
634
715
return false ;
635
716
636
- CS. TC . diagnose (expr ->getLoc (), diag::optional_not_unwrapped, baseType ,
637
- unwrappedType);
717
+ emitDiagnostic (unwrappedExpr ->getLoc (), diag::optional_not_unwrapped,
718
+ baseType, unwrappedType);
638
719
639
720
// If the expression we're unwrapping is the only reference to a
640
721
// local variable whose type isn't explicit in the source, then
641
722
// offer unwrapping fixits on the initializer as well.
642
- if (auto declRef = dyn_cast<DeclRefExpr>(expr )) {
723
+ if (auto declRef = dyn_cast<DeclRefExpr>(unwrappedExpr )) {
643
724
if (auto varDecl = dyn_cast<VarDecl>(declRef->getDecl ())) {
644
-
645
725
bool singleUse = false ;
646
726
AbstractFunctionDecl *AFD = nullptr ;
647
727
if (auto contextDecl = varDecl->getDeclContext ()->getAsDecl ()) {
@@ -658,69 +738,37 @@ static bool diagnoseUnwrap(ConstraintSystem &CS, Expr *expr, Expr *rootExpr, Typ
658
738
659
739
Expr *initializer = varDecl->getParentInitializer ();
660
740
if (auto declRefExpr = dyn_cast<DeclRefExpr>(initializer)) {
661
- if (declRefExpr->getDecl ()->getAttrs ().hasAttribute <ImplicitlyUnwrappedOptionalAttr>()) {
662
- CS.TC .diagnose (declRefExpr->getLoc (), diag::unwrap_iuo_initializer,
741
+ if (declRefExpr->getDecl ()
742
+ ->getAttrs ()
743
+ .hasAttribute <ImplicitlyUnwrappedOptionalAttr>()) {
744
+ emitDiagnostic (declRefExpr->getLoc (), diag::unwrap_iuo_initializer,
663
745
baseType);
664
746
}
665
747
}
666
748
667
749
auto fnTy = AFD->getInterfaceType ()->castTo <AnyFunctionType>();
668
- bool voidReturn = fnTy->getResult ()->isEqual (TupleType::getEmpty (CS.DC ->getASTContext ()));
750
+ bool voidReturn =
751
+ fnTy->getResult ()->isEqual (TupleType::getEmpty (getASTContext ()));
669
752
670
- auto diag = CS. TC . diagnose (varDecl->getLoc (), diag::unwrap_with_guard);
753
+ auto diag = emitDiagnostic (varDecl->getLoc (), diag::unwrap_with_guard);
671
754
diag.fixItInsert (binding->getStartLoc (), " guard " );
672
755
if (voidReturn) {
673
756
diag.fixItInsertAfter (binding->getEndLoc (), " else { return }" );
674
757
} else {
675
758
diag.fixItInsertAfter (binding->getEndLoc (), " else { return <"
676
- " #default value#" " > }" );
759
+ " #default value#"
760
+ " > }" );
677
761
}
678
762
diag.flush ();
679
763
680
- offerDefaultValueUnwrapFixit (CS.TC , varDecl->getDeclContext (),
681
- initializer, rootExpr);
682
- offerForceUnwrapFixit (CS, initializer);
764
+ offerDefaultValueUnwrapFixIt (varDecl->getDeclContext (), initializer);
765
+ offerForceUnwrapFixIt (initializer);
683
766
}
684
767
}
685
768
}
686
769
687
- offerDefaultValueUnwrapFixit (CS.TC , CS.DC , expr, rootExpr);
688
- offerForceUnwrapFixit (CS, expr);
689
- return true ;
690
- }
691
-
692
- bool MissingOptionalUnwrapFailure::diagnoseAsError () {
693
- if (hasComplexLocator ())
694
- return false ;
695
-
696
- auto *anchor = getAnchor ();
697
- auto *rootExpr = getParentExpr ();
698
-
699
- if (auto assignExpr = dyn_cast<AssignExpr>(anchor))
700
- anchor = assignExpr->getSrc ();
701
-
702
- auto *unwrapped = anchor->getValueProvidingExpr ();
703
- auto type = getType (anchor)->getRValueType ();
704
-
705
- auto *tryExpr = dyn_cast<OptionalTryExpr>(unwrapped);
706
- if (!tryExpr) {
707
- return diagnoseUnwrap (getConstraintSystem (), unwrapped, rootExpr, getBaseType (),
708
- getUnwrappedType ());
709
- }
710
-
711
- bool isSwift5OrGreater = getTypeChecker ().getLangOpts ().isSwiftVersionAtLeast (5 );
712
- auto subExprType = getType (tryExpr->getSubExpr ());
713
- bool subExpressionIsOptional = (bool )subExprType->getOptionalObjectType ();
714
-
715
-
716
- if (isSwift5OrGreater && subExpressionIsOptional) {
717
- // Using 'try!' won't change the type for a 'try?' with an optional sub-expr
718
- // under Swift 5+, so just report that a missing unwrap can't be handled here.
719
- return false ;
720
- }
721
-
722
- emitDiagnostic (tryExpr->getTryLoc (), diag::missing_unwrap_optional_try, type)
723
- .fixItReplace ({tryExpr->getTryLoc (), tryExpr->getQuestionLoc ()}, " try!" );
770
+ offerDefaultValueUnwrapFixIt (getDC (), unwrappedExpr);
771
+ offerForceUnwrapFixIt (unwrappedExpr);
724
772
return true ;
725
773
}
726
774
0 commit comments