Skip to content

Commit 0243497

Browse files
committed
General bike shedding
1 parent 43a582e commit 0243497

File tree

3 files changed

+56
-28
lines changed

3 files changed

+56
-28
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2405,16 +2405,21 @@ WARNING(optional_pattern_match_promotion,none,
24052405
(Type, Type))
24062406
WARNING(optional_to_any_coercion,none,
24072407
"expression implicitly coerced from %0 to Any", (Type))
2408-
WARNING(optional_in_string_interpolation_segment,none,
2409-
"string interpolation of optional can have unintended effects", ())
24102408
NOTE(default_optional_to_any,none,
24112409
"provide a default value to avoid this warning", ())
24122410
NOTE(force_optional_to_any,none,
24132411
"force-unwrap the value to avoid this warning", ())
24142412
NOTE(silence_optional_to_any,none,
24152413
"explicitly cast to Any with 'as Any' to silence this warning", ())
2416-
NOTE(silence_optional_in_interpolation_segment,none,
2417-
"explicitly use '.debugDescription' to silence this warning", ())
2414+
WARNING(optional_in_string_interpolation_segment,none,
2415+
"string interpolation produces a debug description for an optional "
2416+
"value; did you mean to make this explicit?",
2417+
())
2418+
NOTE(silence_optional_in_interpolation_segment_cast,none,
2419+
"use 'as' to explicitly cast to %0 to silence this warning",
2420+
(Type))
2421+
NOTE(silence_optional_in_interpolation_segment_call,none,
2422+
"use '.debugDescription' to silence this warning", ())
24182423

24192424
ERROR(invalid_noescape_use,none,
24202425
"non-escaping %select{value|parameter}1 %0 may only be called",

lib/Sema/MiscDiagnostics.cpp

Lines changed: 32 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3672,12 +3672,12 @@ checkImplicitPromotionsInCondition(const StmtConditionElement &cond,
36723672
}
36733673
}
36743674

3675-
static void diagnoseOptionalToAnyCoercion(TypeChecker &TC, const Expr *E,
3676-
const DeclContext *DC) {
3675+
static void diagnoseUnintendedOptionalBehavior(TypeChecker &TC, const Expr *E,
3676+
const DeclContext *DC) {
36773677
if (!E || isa<ErrorExpr>(E) || !E->getType())
36783678
return;
36793679

3680-
class OptionalToAnyCoercionWalker : public ASTWalker {
3680+
class UnintendedOptionalBehaviorWalker : public ASTWalker {
36813681
TypeChecker &TC;
36823682
SmallPtrSet<Expr *, 4> ErasureCoercedToAny;
36833683

@@ -3711,37 +3711,45 @@ static void diagnoseOptionalToAnyCoercion(TypeChecker &TC, const Expr *E,
37113711
// Warn about interpolated segments that contain optionals.
37123712
for (auto &segment : literal->getSegments()) {
37133713
// Allow explicit casts.
3714-
if (isa<ExplicitCastExpr>(segment)) {
3715-
continue;
3714+
if (auto paren = dyn_cast<ParenExpr>(segment)) {
3715+
if (isa<ExplicitCastExpr>(paren->getSubExpr())) {
3716+
continue;
3717+
}
37163718
}
37173719

3718-
auto segmentTy = segment->getType();
3719-
if (segmentTy && !segmentTy->getOptionalObjectType().isNull()) {
3720-
TC.diagnose(segment->getStartLoc(),
3721-
diag::optional_in_string_interpolation_segment)
3722-
.highlight(segment->getSourceRange());
3723-
3724-
TC.diagnose(segment->getLoc(),
3725-
diag::silence_optional_in_interpolation_segment)
3726-
.highlight(segment->getSourceRange())
3727-
.fixItInsertAfter(segment->getEndLoc(), ".debugDescription");
3728-
TC.diagnose(segment->getLoc(), diag::default_optional_to_any)
3729-
.highlight(segment->getSourceRange())
3730-
.fixItInsertAfter(segment->getEndLoc(), " ?? <#default value#>");
3731-
TC.diagnose(segment->getLoc(), diag::force_optional_to_any)
3732-
.highlight(segment->getSourceRange())
3733-
.fixItInsertAfter(segment->getEndLoc(), "!");
3720+
// Bail out if we don't have an optional.
3721+
auto objectTy = segment->getType()->getOptionalObjectType();
3722+
if (!objectTy) {
3723+
continue;
37343724
}
3725+
auto segmentTy = OptionalType::get(objectTy);
3726+
3727+
TC.diagnose(segment->getStartLoc(),
3728+
diag::optional_in_string_interpolation_segment)
3729+
.highlight(segment->getSourceRange());
3730+
3731+
TC.diagnose(segment->getLoc(),
3732+
diag::silence_optional_in_interpolation_segment_call)
3733+
.highlight(segment->getSourceRange())
3734+
.fixItInsert(segment->getEndLoc(), ".debugDescription");
3735+
3736+
auto opts = PrintOptions::printForDiagnostics();
3737+
TC.diagnose(segment->getLoc(),
3738+
diag::silence_optional_in_interpolation_segment_cast,
3739+
segmentTy)
3740+
.highlight(segment->getSourceRange())
3741+
.fixItInsert(segment->getEndLoc(),
3742+
" as " + segmentTy->getString(opts));
37353743
}
37363744
}
37373745
return { true, E };
37383746
}
37393747

37403748
public:
3741-
OptionalToAnyCoercionWalker(TypeChecker &tc) : TC(tc) { }
3749+
UnintendedOptionalBehaviorWalker(TypeChecker &tc) : TC(tc) { }
37423750
};
37433751

3744-
OptionalToAnyCoercionWalker Walker(TC);
3752+
UnintendedOptionalBehaviorWalker Walker(TC);
37453753
const_cast<Expr *>(E)->walk(Walker);
37463754
}
37473755

@@ -3757,7 +3765,7 @@ void swift::performSyntacticExprDiagnostics(TypeChecker &TC, const Expr *E,
37573765
diagSyntacticUseRestrictions(TC, E, DC, isExprStmt);
37583766
diagRecursivePropertyAccess(TC, E, DC);
37593767
diagnoseImplicitSelfUseInClosure(TC, E, DC);
3760-
diagnoseOptionalToAnyCoercion(TC, E, DC);
3768+
diagnoseUnintendedOptionalBehavior(TC, E, DC);
37613769
if (!TC.getLangOpts().DisableAvailabilityChecking)
37623770
diagAvailability(TC, E, const_cast<DeclContext*>(DC));
37633771
if (TC.Context.LangOpts.EnableObjCInterop)

test/Sema/diag_optional_to_any.swift renamed to test/Sema/diag_unintended_optional_behavior.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,18 @@ func warnOptionalToAnyCoercion(value x: Int?) -> Any {
5858
// expected-note@-2 {{force-unwrap the value to avoid this warning}}
5959
// expected-note@-3 {{explicitly cast to Any with 'as Any' to silence this warning}}
6060
}
61+
62+
func warnOptionalInStringInterpolationSegment(_ o : Int?) {
63+
print("Always some, Always some, Always some: \(o)")
64+
// expected-warning@-1 {{string interpolation produces a debug description for an optional value; did you mean to make this explicit?}}
65+
// expected-note@-2 {{use '.debugDescription' to silence this warning}} {{52-52=.debugDescription}}
66+
// expected-note@-3 {{use 'as' to explicitly cast to 'Int?' to silence this warning}} {{52-52= as Int?}}
67+
print("Always some, Always some, Always some: \(o.map { $0 + 1 })")
68+
// expected-warning@-1 {{string interpolation produces a debug description for an optional value; did you mean to make this explicit?}}
69+
// expected-note@-2 {{use '.debugDescription' to silence this warning}} {{67-67=.debugDescription}}
70+
// expected-note@-3 {{use 'as' to explicitly cast to 'Int?' to silence this warning}} {{67-67= as Int?}}
71+
72+
print("Always some, Always some, Always some: \(o as Int?)") // No warning
73+
print("Always some, Always some, Always some: \(o.debugDescription)") // No warning.
74+
}
75+

0 commit comments

Comments
 (0)