Skip to content

Commit f53826a

Browse files
authored
Merge pull request #12631 from rudkx/warn-on-iuo-spelling
Add a warning that ImplicitlyUnwrappedOptional is deprecated
2 parents 430853c + e07a736 commit f53826a

File tree

10 files changed

+109
-16
lines changed

10 files changed

+109
-16
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1924,10 +1924,6 @@ NOTE(override_unnecessary_IUO_use_strict,none,
19241924
NOTE(override_unnecessary_IUO_silence,none,
19251925
"add parentheses to silence this warning", ())
19261926

1927-
ERROR(iuo_in_illegal_position,none,
1928-
"implicitly unwrapped optionals are only allowed at top level and as "
1929-
"function results", ())
1930-
19311927
ERROR(override_mutable_covariant_property,none,
19321928
"cannot override mutable property %0 of type %1 with covariant type %2",
19331929
(Identifier, Type, Type))
@@ -3111,6 +3107,16 @@ ERROR(tuple_single_element,none,
31113107
ERROR(tuple_ellipsis,none,
31123108
"cannot create a variadic tuple", ())
31133109

3110+
WARNING(implicitly_unwrapped_optional_spelling_deprecated,none,
3111+
"the spelling 'ImplicitlyUnwrappedOptional' is deprecated", ())
3112+
3113+
WARNING(implicitly_unwrapped_optional_spelling_deprecated_with_fixit,none,
3114+
"the spelling 'ImplicitlyUnwrappedOptional' is deprecated; use '!' after the type name", ())
3115+
3116+
ERROR(iuo_in_illegal_position,none,
3117+
"implicitly unwrapped optionals are only allowed at top level and as "
3118+
"function results", ())
3119+
31143120
// Ownership
31153121
ERROR(invalid_ownership_type,none,
31163122
"'%select{strong|weak|unowned|unowned}0' may only be applied to "

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1012,6 +1012,7 @@ bool PreCheckExpression::walkToClosureExprPre(ClosureExpr *closure) {
10121012
options |= TR_AllowUnspecifiedTypes;
10131013
options |= TR_AllowUnboundGenerics;
10141014
options |= TR_InExpression;
1015+
options |= TR_AllowIUO;
10151016
bool hadParameterError = false;
10161017

10171018
GenericTypeToArchetypeResolver resolver(closure);

lib/Sema/TypeCheckDecl.cpp

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1118,6 +1118,8 @@ static void validatePatternBindingEntry(TypeChecker &tc,
11181118
// top-level variables in a script file are accessible from other files,
11191119
// even though the PBD is inside a TopLevelCodeDecl.
11201120
TypeResolutionOptions options = TR_InExpression;
1121+
1122+
options |= TR_AllowIUO;
11211123
if (binding->getInit(entryNumber)) {
11221124
// If we have an initializer, we can also have unknown types.
11231125
options |= TR_AllowUnspecifiedTypes;
@@ -4246,10 +4248,14 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
42464248
GenericTypeToArchetypeResolver resolver(SD);
42474249

42484250
bool isInvalid = TC.validateType(SD->getElementTypeLoc(), SD,
4249-
TypeResolutionOptions(),
4251+
TR_AllowIUO,
42504252
&resolver);
4253+
TypeResolutionOptions options;
4254+
options |= TR_SubscriptParameters;
4255+
options |= TR_AllowIUO;
4256+
42514257
isInvalid |= TC.typeCheckParameterList(SD->getIndices(), SD,
4252-
TR_SubscriptParameters,
4258+
options,
42534259
resolver);
42544260

42554261
if (isInvalid || SD->isInvalid()) {
@@ -4786,9 +4792,8 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
47864792
GenericTypeResolver &resolver) {
47874793
bool hadError = false;
47884794
for (auto paramList : fd->getParameterLists()) {
4789-
hadError |= TC.typeCheckParameterList(paramList, fd,
4790-
TypeResolutionOptions(),
4791-
resolver);
4795+
hadError |=
4796+
TC.typeCheckParameterList(paramList, fd, TR_AllowIUO, resolver);
47924797
}
47934798

47944799
return hadError;
@@ -4799,9 +4804,10 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
47994804

48004805
bool badType = false;
48014806
if (!FD->getBodyResultTypeLoc().isNull()) {
4802-
TypeResolutionOptions options;
4807+
TypeResolutionOptions options = TR_AllowIUO;
48034808
if (FD->hasDynamicSelf())
48044809
options |= TR_DynamicSelfResult;
4810+
48054811
if (TC.validateType(FD->getBodyResultTypeLoc(), FD, options,
48064812
&resolver)) {
48074813
badType = true;

lib/Sema/TypeCheckGeneric.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -457,7 +457,7 @@ static bool checkGenericFuncSignature(TypeChecker &tc,
457457
// Check the parameter patterns.
458458
for (auto params : func->getParameterLists()) {
459459
// Check the pattern.
460-
if (tc.typeCheckParameterList(params, func, TypeResolutionOptions(),
460+
if (tc.typeCheckParameterList(params, func, TR_AllowIUO,
461461
resolver))
462462
badType = true;
463463

@@ -472,7 +472,7 @@ static bool checkGenericFuncSignature(TypeChecker &tc,
472472
if (auto fn = dyn_cast<FuncDecl>(func)) {
473473
if (!fn->getBodyResultTypeLoc().isNull()) {
474474
// Check the result type of the function.
475-
TypeResolutionOptions options;
475+
TypeResolutionOptions options = TR_AllowIUO;
476476
if (fn->hasDynamicSelf())
477477
options |= TR_DynamicSelfResult;
478478

@@ -949,8 +949,12 @@ static bool checkGenericSubscriptSignature(TypeChecker &tc,
949949
// Check the indices.
950950
auto params = subscript->getIndices();
951951

952+
TypeResolutionOptions options;
953+
options |= TR_SubscriptParameters;
954+
options |= TR_AllowIUO;
955+
952956
badType |= tc.typeCheckParameterList(params, subscript,
953-
TR_SubscriptParameters,
957+
options,
954958
resolver);
955959

956960
// Infer requirements from the pattern.

lib/Sema/TypeCheckType.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1180,6 +1180,31 @@ resolveTopLevelIdentTypeComponent(TypeChecker &TC, DeclContext *DC,
11801180
return ErrorType::get(TC.Context);
11811181
}
11821182

1183+
// Emit a warning about directly spelling
1184+
// ImplicitlyUnwrappedOptional rather than using a trailing '!'.
1185+
auto *IUODecl = TC.Context.getImplicitlyUnwrappedOptionalDecl();
1186+
if (currentDecl == IUODecl) {
1187+
if (isa<GenericIdentTypeRepr>(comp) && options.contains(TR_AllowIUO)) {
1188+
auto *genericTyR = cast<GenericIdentTypeRepr>(comp);
1189+
assert(genericTyR->getGenericArgs().size() == 1);
1190+
auto *genericArgTyR = genericTyR->getGenericArgs()[0];
1191+
1192+
TC.diagnose(
1193+
comp->getStartLoc(),
1194+
diag::implicitly_unwrapped_optional_spelling_deprecated_with_fixit)
1195+
.fixItRemoveChars(
1196+
genericTyR->getStartLoc(),
1197+
genericTyR->getAngleBrackets().Start.getAdvancedLoc(1))
1198+
.fixItInsertAfter(genericArgTyR->getEndLoc(), "!")
1199+
.fixItRemoveChars(
1200+
genericTyR->getAngleBrackets().End,
1201+
genericTyR->getAngleBrackets().End.getAdvancedLoc(1));
1202+
} else {
1203+
TC.diagnose(comp->getStartLoc(),
1204+
diag::implicitly_unwrapped_optional_spelling_deprecated);
1205+
}
1206+
}
1207+
11831208
// If we found nothing, complain and give ourselves a chance to recover.
11841209
if (current.isNull()) {
11851210
// If we're not allowed to complain or we couldn't fix the

lib/Sema/TypeChecker.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,9 @@ enum TypeResolutionFlags : unsigned {
536536

537537
/// Whether we are checking the parameter list of a subscript.
538538
TR_SubscriptParameters = 0x2000000,
539+
540+
/// Is it okay to resolve an IUO sigil ("!") here?
541+
TR_AllowIUO = 0x4000000,
539542
};
540543

541544
/// Option set describing how type resolution should work.

test/Sema/diag_deprecated_iuo.swift

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// RUN: %target-typecheck-verify-swift
2+
3+
let _: ImplicitlyUnwrappedOptional<Int> = 1 // expected-warning {{the spelling 'ImplicitlyUnwrappedOptional' is deprecated; use '!' after the type name}}{{8-36=}}{{39-39=!}}{{39-40=}}
4+
let _: ImplicitlyUnwrappedOptional = 1 // expected-warning {{the spelling 'ImplicitlyUnwrappedOptional' is deprecated}}
5+
6+
extension ImplicitlyUnwrappedOptional {} // expected-warning {{the spelling 'ImplicitlyUnwrappedOptional' is deprecated}}
7+
8+
func function(
9+
_: ImplicitlyUnwrappedOptional<Int> // expected-warning {{the spelling 'ImplicitlyUnwrappedOptional' is deprecated; use '!' after the type name}}{{6-34=}}{{37-37=!}}{{37-38=}}
10+
) -> ImplicitlyUnwrappedOptional<Int> { // expected-warning {{the spelling 'ImplicitlyUnwrappedOptional' is deprecated; use '!' after the type name}}{{6-34=}}{{37-37=!}}{{37-38=}}
11+
return 1
12+
}
13+
14+
func genericFunction<T>(
15+
iuo: ImplicitlyUnwrappedOptional<T> // expected-warning {{the spelling 'ImplicitlyUnwrappedOptional' is deprecated; use '!' after the type name}}{{8-36=}}{{37-37=!}}{{37-38=}}
16+
) -> ImplicitlyUnwrappedOptional<T> { // expected-warning {{the spelling 'ImplicitlyUnwrappedOptional' is deprecated; use '!' after the type name}}{{6-34=}}{{35-35=!}}{{35-36=}}
17+
return iuo
18+
}
19+
20+
protocol P {
21+
associatedtype T
22+
associatedtype U
23+
}
24+
25+
struct S : P {
26+
typealias T = ImplicitlyUnwrappedOptional<Int> // expected-warning {{the spelling 'ImplicitlyUnwrappedOptional' is deprecated}}
27+
typealias U = Optional<ImplicitlyUnwrappedOptional<Int>> // expected-warning {{the spelling 'ImplicitlyUnwrappedOptional' is deprecated}}
28+
29+
subscript (
30+
index: ImplicitlyUnwrappedOptional<Int> // expected-warning {{the spelling 'ImplicitlyUnwrappedOptional' is deprecated; use '!' after the type name}}{{12-40=}}{{43-43=!}}{{43-44=}}
31+
) -> ImplicitlyUnwrappedOptional<Int> { // expected-warning {{the spelling 'ImplicitlyUnwrappedOptional' is deprecated; use '!' after the type name}}{{12-40=}}{{43-43=!}}{{43-44=}}
32+
return index
33+
}
34+
}
35+
36+
func generic<T : P>(_: T) where T.T == ImplicitlyUnwrappedOptional<Int> { } // expected-warning {{the spelling 'ImplicitlyUnwrappedOptional' is deprecated}}
37+
func genericOptIUO<T : P>(_: T) where T.U == Optional<ImplicitlyUnwrappedOptional<Int>> {} // expected-warning {{the spelling 'ImplicitlyUnwrappedOptional' is deprecated}}
38+
39+
func testClosure() -> Int {
40+
return {
41+
(i: ImplicitlyUnwrappedOptional<Int>) // expected-warning {{the spelling 'ImplicitlyUnwrappedOptional' is deprecated; use '!' after the type name}}{{9-37=}}{{40-40=!}}{{40-41=}}
42+
-> ImplicitlyUnwrappedOptional<Int> in // expected-warning {{the spelling 'ImplicitlyUnwrappedOptional' is deprecated}}
43+
return i
44+
}(1)
45+
}

test/attr/attr_escaping.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ func testModuloOptionalness() {
121121
func setIUOClosure(_ fn: () -> Void) { // expected-note {{parameter 'fn' is implicitly non-escaping}} {{28-28=@escaping }}
122122
iuoClosure = fn // expected-error{{assigning non-escaping parameter 'fn' to an @escaping closure}}
123123
}
124-
var iuoClosureExplicit: ImplicitlyUnwrappedOptional<() -> Void>
124+
var iuoClosureExplicit: ImplicitlyUnwrappedOptional<() -> Void> // expected-warning {{the spelling 'ImplicitlyUnwrappedOptional' is deprecated; use '!' after the type name}}
125125
func setExplicitIUOClosure(_ fn: () -> Void) { // expected-note {{parameter 'fn' is implicitly non-escaping}} {{36-36=@escaping }}
126126
iuoClosureExplicit = fn // expected-error{{assigning non-escaping parameter 'fn' to an @escaping closure}}
127127
}

test/decl/class/override.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -221,8 +221,10 @@ class IUOTestSubclass2 : IUOTestBaseClass {
221221
// expected-note@-1 {{remove '!' to make the parameter required}} {{36-37=}}
222222
// expected-note@-2 {{add parentheses to silence this warning}} {{27-27=(}} {{37-37=)}}
223223

224-
override func oneB(x: ImplicitlyUnwrappedOptional<AnyObject>) {} // expected-warning {{overriding instance method parameter of type 'AnyObject' with implicitly unwrapped optional type 'ImplicitlyUnwrappedOptional<AnyObject>'}}
225-
// expected-note@-1 {{add parentheses to silence this warning}} {{25-25=(}} {{63-63=)}}
224+
override func oneB(x: ImplicitlyUnwrappedOptional<AnyObject>) {}
225+
// expected-warning@-1 {{the spelling 'ImplicitlyUnwrappedOptional' is deprecated; use '!' after the type name}}{{25-53=}}{{62-62=!}}{{62-63=}}
226+
// expected-warning@-2 {{overriding instance method parameter of type 'AnyObject' with implicitly unwrapped optional type 'ImplicitlyUnwrappedOptional<AnyObject>'}}
227+
// expected-note@-3 {{add parentheses to silence this warning}} {{25-25=(}} {{63-63=)}}
226228

227229
override func oneC(_: AnyObject!) {} // expected-warning {{overriding instance method parameter of type 'AnyObject' with implicitly unwrapped optional type 'AnyObject!'}}
228230
// expected-note@-1 {{remove '!' to make the parameter required}} {{34-35=}}

validation-test/Sema/type_checker_crashers_fixed/rdar28048391.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,4 @@ extension rdar28048391 {
1212
}
1313

1414
extension ImplicitlyUnwrappedOptional : rdar28048391 { }
15+
// expected-warning@-1 {{the spelling 'ImplicitlyUnwrappedOptional' is deprecated}}

0 commit comments

Comments
 (0)