Skip to content

Commit f9b82bc

Browse files
committed
Ban IUOs in illegal positions harder under Swift 5 and later.
SE-0054 specified that the use of implicitly unwrapped optionals was limited to just a few places, but the implementation at the time did not completely ban the other uses. This is another attempt to do so, but it's only on for compilations in Swift 5 mode and later. For earlier versions, we fall back on the existing implementation. Fixes: rdar://problem/27707015
1 parent f53826a commit f9b82bc

File tree

3 files changed

+122
-12
lines changed

3 files changed

+122
-12
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3113,6 +3113,12 @@ WARNING(implicitly_unwrapped_optional_spelling_deprecated,none,
31133113
WARNING(implicitly_unwrapped_optional_spelling_deprecated_with_fixit,none,
31143114
"the spelling 'ImplicitlyUnwrappedOptional' is deprecated; use '!' after the type name", ())
31153115

3116+
ERROR(implicitly_unwrapped_optional_spelling_error,none,
3117+
"the spelling 'ImplicitlyUnwrappedOptional' in unsupported; use an explicit type followed by '!'", ())
3118+
3119+
ERROR(implicitly_unwrapped_optional_spelling_error_with_fixit,none,
3120+
"the spelling 'ImplicitlyUnwrappedOptional' is unsupported; use '!' after the type name", ())
3121+
31163122
ERROR(iuo_in_illegal_position,none,
31173123
"implicitly unwrapped optionals are only allowed at top level and as "
31183124
"function results", ())

lib/Sema/TypeCheckType.cpp

Lines changed: 56 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1184,24 +1184,56 @@ resolveTopLevelIdentTypeComponent(TypeChecker &TC, DeclContext *DC,
11841184
// ImplicitlyUnwrappedOptional rather than using a trailing '!'.
11851185
auto *IUODecl = TC.Context.getImplicitlyUnwrappedOptionalDecl();
11861186
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)
1187+
if (options.contains(TR_AllowIUO)) {
1188+
if (isa<GenericIdentTypeRepr>(comp)) {
1189+
auto *genericTyR = cast<GenericIdentTypeRepr>(comp);
1190+
assert(genericTyR->getGenericArgs().size() == 1);
1191+
auto *genericArgTyR = genericTyR->getGenericArgs()[0];
1192+
1193+
Diagnostic diag = diag::implicitly_unwrapped_optional_spelling_deprecated_with_fixit;
1194+
1195+
// For Swift 5 and later, spelling the full name is an error.
1196+
if (TC.Context.isSwiftVersionAtLeast(5))
1197+
diag = diag::implicitly_unwrapped_optional_spelling_error_with_fixit;
1198+
1199+
TC.diagnose(comp->getStartLoc(), diag)
11951200
.fixItRemoveChars(
11961201
genericTyR->getStartLoc(),
11971202
genericTyR->getAngleBrackets().Start.getAdvancedLoc(1))
11981203
.fixItInsertAfter(genericArgTyR->getEndLoc(), "!")
11991204
.fixItRemoveChars(
12001205
genericTyR->getAngleBrackets().End,
12011206
genericTyR->getAngleBrackets().End.getAdvancedLoc(1));
1207+
} else {
1208+
Diagnostic diag = diag::implicitly_unwrapped_optional_spelling_deprecated;
1209+
1210+
// For Swift 5 and later, spelling the full name is an error.
1211+
if (TC.Context.isSwiftVersionAtLeast(5))
1212+
diag = diag::implicitly_unwrapped_optional_spelling_error;
1213+
1214+
TC.diagnose(comp->getStartLoc(), diag);
1215+
}
1216+
} else if (TC.Context.isSwiftVersionAtLeast(5)) {
1217+
if (isa<GenericIdentTypeRepr>(comp)) {
1218+
auto *genericTyR = cast<GenericIdentTypeRepr>(comp);
1219+
assert(genericTyR->getGenericArgs().size() == 1);
1220+
auto *genericArgTyR = genericTyR->getGenericArgs()[0];
1221+
1222+
TC.diagnose(comp->getStartLoc(), diag::iuo_in_illegal_position)
1223+
.fixItRemoveChars(
1224+
genericTyR->getStartLoc(),
1225+
genericTyR->getAngleBrackets().Start.getAdvancedLoc(1))
1226+
.fixItInsertAfter(genericArgTyR->getEndLoc(), "?")
1227+
.fixItRemoveChars(
1228+
genericTyR->getAngleBrackets().End,
1229+
genericTyR->getAngleBrackets().End.getAdvancedLoc(1));
1230+
} else {
1231+
TC.diagnose(comp->getStartLoc(), diag::iuo_in_illegal_position);
1232+
}
12021233
} else {
1203-
TC.diagnose(comp->getStartLoc(),
1204-
diag::implicitly_unwrapped_optional_spelling_deprecated);
1234+
// Pre-Swift-5 warning for spelling ImplicitlyUnwrappedOptional
1235+
// in places we shouldn't even allow it.
1236+
TC.diagnose(comp->getStartLoc(), diag::implicitly_unwrapped_optional_spelling_deprecated);
12051237
}
12061238
}
12071239

@@ -1607,8 +1639,12 @@ bool TypeChecker::validateType(TypeLoc &Loc, DeclContext *DC,
16071639
Context.Stats->getFrontendCounters().NumTypesValidated++;
16081640

16091641
if (Loc.getType().isNull()) {
1610-
// Raise error if we parse an IUO type in an illegal position.
1611-
checkForIllegalIUOs(*this, Loc.getTypeRepr(), options);
1642+
// Swift version < 5? Use the old "illegal IUO" check for
1643+
// backwards compatibiliy.
1644+
if (!Context.isSwiftVersionAtLeast(5)) {
1645+
// Raise error if we parse an IUO type in an illegal position.
1646+
checkForIllegalIUOs(*this, Loc.getTypeRepr(), options);
1647+
}
16121648

16131649
auto type = resolveType(Loc.getTypeRepr(), DC, options, resolver,
16141650
unsatisfiedDependency);
@@ -2741,6 +2777,14 @@ Type TypeResolver::resolveImplicitlyUnwrappedOptionalType(
27412777
auto elementOptions = withoutContext(options, true);
27422778
elementOptions |= TR_ImmediateOptionalTypeArgument;
27432779

2780+
// Swift version >= 5? Use the newer check for IUOs appearing in
2781+
// illegal positions.
2782+
if (TC.Context.isSwiftVersionAtLeast(5) &&
2783+
!elementOptions.contains(TR_AllowIUO)) {
2784+
TC.diagnose(repr->getStartLoc(), diag::iuo_in_illegal_position)
2785+
.fixItReplace(repr->getExclamationLoc(), "?");
2786+
}
2787+
27442788
// The T in T! is a generic type argument and therefore always an AST type.
27452789
// FIXME: diagnose non-materializability of element type!
27462790
Type baseTy = resolveType(repr->getBase(), elementOptions);

test/Sema/diag_erroneous_iuo.swift

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// RUN: %target-typecheck-verify-swift -swift-version 5
2+
3+
let _: ImplicitlyUnwrappedOptional<Int> = 1 // expected-error {{the spelling 'ImplicitlyUnwrappedOptional' is unsupported; use '!' after the type name}}{{8-36=}}{{39-39=!}}{{39-40=}}
4+
let _: ImplicitlyUnwrappedOptional = 1 // expected-error {{the spelling 'ImplicitlyUnwrappedOptional' in unsupported; use an explicit type followed by '!'}}
5+
6+
extension ImplicitlyUnwrappedOptional {} // expected-error {{implicitly unwrapped optionals are only allowed at top level and as function results}}
7+
8+
func function(
9+
_: ImplicitlyUnwrappedOptional<Int> // expected-error {{the spelling 'ImplicitlyUnwrappedOptional' is unsupported; use '!' after the type name}}{{6-34=}}{{37-37=!}}{{37-38=}}
10+
) -> ImplicitlyUnwrappedOptional<Int> { // expected-error {{the spelling 'ImplicitlyUnwrappedOptional' is unsupported; 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-error {{the spelling 'ImplicitlyUnwrappedOptional' is unsupported; use '!' after the type name}}{{8-36=}}{{37-37=!}}{{37-38=}}
16+
) -> ImplicitlyUnwrappedOptional<T> { // expected-error {{the spelling 'ImplicitlyUnwrappedOptional' is unsupported; 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-error {{implicitly unwrapped optionals are only allowed at top level and as function results}}
27+
typealias U = Optional<ImplicitlyUnwrappedOptional<Int>> // expected-error {{implicitly unwrapped optionals are only allowed at top level and as function results}}
28+
29+
subscript (
30+
index: ImplicitlyUnwrappedOptional<Int> // expected-error {{the spelling 'ImplicitlyUnwrappedOptional' is unsupported; use '!' after the type name}}{{12-40=}}{{43-43=!}}{{43-44=}}
31+
) -> ImplicitlyUnwrappedOptional<Int> { // expected-error {{the spelling 'ImplicitlyUnwrappedOptional' is unsupported; 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-error {{implicitly unwrapped optionals are only allowed at top level and as function results}}
37+
func genericOptIUO<T : P>(_: T) where T.U == Optional<ImplicitlyUnwrappedOptional<Int>> {} // expected-error {{implicitly unwrapped optionals are only allowed at top level and as function results}}
38+
39+
func testClosure() -> Int {
40+
return {
41+
(i: ImplicitlyUnwrappedOptional<Int>) // expected-error {{the spelling 'ImplicitlyUnwrappedOptional' is unsupported; use '!' after the type name}}{{9-37=}}{{40-40=!}}{{40-41=}}
42+
-> ImplicitlyUnwrappedOptional<Int> in // expected-error {{implicitly unwrapped optionals are only allowed at top level and as function results}}
43+
return i
44+
}(1)
45+
}
46+
47+
_ = Array<Int!>() // expected-error {{implicitly unwrapped optionals are only allowed at top level and as function results}}
48+
_ = [Int!]() // expected-error {{implicitly unwrapped optionals are only allowed at top level and as function results}}
49+
_ = Optional<Int!>(nil) // expected-error {{implicitly unwrapped optionals are only allowed at top level and as function results}}
50+
_ = Int!?(0) // expected-error {{implicitly unwrapped optionals are only allowed at top level and as function results}}
51+
_ = (
52+
Int!, // expected-error {{implicitly unwrapped optionals are only allowed at top level and as function results}}
53+
Float!, // expected-error {{implicitly unwrapped optionals are only allowed at top level and as function results}}
54+
String! // expected-error {{implicitly unwrapped optionals are only allowed at top level and as function results}}
55+
)(1, 2.0, "3")
56+
57+
struct Generic<T, U, C> {}
58+
_ = Generic<Int!, // expected-error {{implicitly unwrapped optionals are only allowed at top level and as function results}}
59+
Float!, // expected-error {{implicitly unwrapped optionals are only allowed at top level and as function results}}
60+
String!>() // expected-error {{implicitly unwrapped optionals are only allowed at top level and as function results}}

0 commit comments

Comments
 (0)