Skip to content

Commit 1385964

Browse files
authored
Merge pull request #13680 from rudkx/map-signature-looking-through-inout
Sema: Look through inout when mapping IUOs to Optionals.
2 parents 1ebc8e9 + e5a0c96 commit 1385964

File tree

4 files changed

+103
-9
lines changed

4 files changed

+103
-9
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -613,6 +613,12 @@ ERROR(invalid_redecl,none,"invalid redeclaration of %0", (DeclName))
613613
NOTE(invalid_redecl_prev,none,
614614
"%0 previously declared here", (DeclName))
615615

616+
WARNING(deprecated_redecl_by_optionality, none,
617+
"invalid redeclaration of %0 which differs only by the kind of optional passed as an inout argument (%1 vs. %2)",
618+
(DeclName, Type, Type))
619+
NOTE(deprecated_redecl_by_optionality_note, none,
620+
"overloading by kind of optional is deprecated and will be removed in a future release", ())
621+
616622
ERROR(ambiguous_type_base,none,
617623
"%0 is ambiguous for type lookup in this context", (Identifier))
618624
ERROR(invalid_member_type,none,

lib/AST/Decl.cpp

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1703,8 +1703,15 @@ static Type mapSignatureType(ASTContext &ctx, Type type) {
17031703

17041704
/// Map a signature type for a parameter.
17051705
static Type mapSignatureParamType(ASTContext &ctx, Type type) {
1706-
/// Translate implicitly unwrapped optionals into strict optionals.
1707-
if (auto uncheckedOptOf = type->getImplicitlyUnwrappedOptionalObjectType()) {
1706+
// Translate implicitly unwrapped optionals into strict optionals.
1707+
if (auto inOutTy = type->getAs<InOutType>()) {
1708+
if (auto uncheckedOptOf =
1709+
inOutTy->getObjectType()
1710+
->getImplicitlyUnwrappedOptionalObjectType()) {
1711+
type = InOutType::get(OptionalType::get(uncheckedOptOf));
1712+
}
1713+
} else if (auto uncheckedOptOf =
1714+
type->getImplicitlyUnwrappedOptionalObjectType()) {
17081715
type = OptionalType::get(uncheckedOptOf);
17091716
}
17101717

@@ -1746,16 +1753,17 @@ static Type mapSignatureFunctionType(ASTContext &ctx, Type type,
17461753
if (curryLevels == 0) {
17471754
// In an initializer, ignore optionality.
17481755
if (isInitializer) {
1749-
if (auto objectType = type->getAnyOptionalObjectType())
1756+
if (auto inOutTy = type->getAs<InOutType>()) {
1757+
if (auto objectType =
1758+
inOutTy->getObjectType()->getAnyOptionalObjectType()) {
1759+
type = InOutType::get(objectType);
1760+
}
1761+
} else if (auto objectType = type->getAnyOptionalObjectType()) {
17501762
type = objectType;
1763+
}
17511764
}
17521765

1753-
// Translate implicitly unwrapped optionals into strict optionals.
1754-
if (auto uncheckedOptOf = type->getImplicitlyUnwrappedOptionalObjectType()) {
1755-
type = OptionalType::get(uncheckedOptOf);
1756-
}
1757-
1758-
return mapSignatureType(ctx, type);
1766+
return mapSignatureParamType(ctx, type);
17591767
}
17601768

17611769
auto funcTy = type->castTo<AnyFunctionType>();

lib/Sema/TypeCheckDecl.cpp

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -982,6 +982,63 @@ static void checkRedeclaration(TypeChecker &tc, ValueDecl *current) {
982982
continue;
983983
}
984984

985+
// Signatures are the same, but interface types are not. We must
986+
// have a type that we've massaged as part of signature
987+
// interface type generation. If it's a result of remapping a
988+
// function parameter from 'inout T!' to 'inout T?', emit a
989+
// warning that these overloads are deprecated and will no
990+
// longer be supported in the future.
991+
if (!current->getInterfaceType()->isEqual(other->getInterfaceType())) {
992+
if (currentDC->isTypeContext() == other->getDeclContext()->isTypeContext()) {
993+
auto currFnTy = current->getInterfaceType()->getAs<AnyFunctionType>();
994+
auto otherFnTy = other->getInterfaceType()->getAs<AnyFunctionType>();
995+
if (currFnTy && otherFnTy && currentDC->isTypeContext()) {
996+
currFnTy = currFnTy->getResult()->getAs<AnyFunctionType>();
997+
otherFnTy = otherFnTy->getResult()->getAs<AnyFunctionType>();
998+
}
999+
1000+
if (currFnTy && otherFnTy) {
1001+
ArrayRef<AnyFunctionType::Param> currParams = currFnTy->getParams();
1002+
ArrayRef<AnyFunctionType::Param> otherParams = otherFnTy->getParams();
1003+
1004+
if (currParams.size() == otherParams.size()) {
1005+
auto diagnosed = false;
1006+
for (unsigned i : indices(currParams)) {
1007+
if (currParams[i].isInOut() && otherParams[i].isInOut()) {
1008+
auto currParamTy = currParams[i]
1009+
.getType()
1010+
->getAs<InOutType>()
1011+
->getObjectType();
1012+
auto otherParamTy = otherParams[i]
1013+
.getType()
1014+
->getAs<InOutType>()
1015+
->getObjectType();
1016+
OptionalTypeKind currOTK;
1017+
OptionalTypeKind otherOTK;
1018+
(void)currParamTy->getAnyOptionalObjectType(currOTK);
1019+
(void)otherParamTy->getAnyOptionalObjectType(otherOTK);
1020+
if (currOTK != OTK_None && otherOTK != OTK_None &&
1021+
currOTK != otherOTK) {
1022+
tc.diagnose(current, diag::deprecated_redecl_by_optionality,
1023+
current->getFullName(), currParamTy,
1024+
otherParamTy);
1025+
tc.diagnose(other, diag::invalid_redecl_prev,
1026+
other->getFullName());
1027+
tc.diagnose(current,
1028+
diag::deprecated_redecl_by_optionality_note);
1029+
diagnosed = true;
1030+
break;
1031+
}
1032+
}
1033+
}
1034+
1035+
if (diagnosed)
1036+
break;
1037+
}
1038+
}
1039+
}
1040+
}
1041+
9851042
// If the conflicting declarations have non-overlapping availability and,
9861043
// we allow the redeclaration to proceed if...
9871044
//

test/decl/overload.swift

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,29 @@ func inout2(x: inout Int) { }
261261
func optional(x: Int?) { } // expected-note{{previously declared}}
262262
func optional(x: Int!) { } // expected-error{{invalid redeclaration of 'optional(x:)'}}
263263

264+
func optionalInOut(x: inout Int?) { } // expected-note{{previously declared}}
265+
// expected-note@-1 {{previously declared}}
266+
func optionalInOut(x: inout Int!) { } // expected-warning{{invalid redeclaration of 'optionalInOut(x:)' which differs only by the kind of optional passed as an inout argument ('Int!' vs. 'Int?')}}
267+
// expected-note@-1 {{overloading by kind of optional is deprecated and will be removed in a future release}}
268+
// expected-warning@-2 {{invalid redeclaration of 'optionalInOut(x:)' which differs only by the kind of optional passed as an inout argument ('Int!' vs. 'Int?')}}
269+
// expected-note@-3 {{overloading by kind of optional is deprecated and will be removed in a future release}}
270+
271+
class optionalOverloads {
272+
class func optionalInOut(x: inout Int?) { } // expected-note{{previously declared}}
273+
// expected-note@-1 {{previously declared}}
274+
class func optionalInOut(x: inout Int!) { } // expected-warning{{invalid redeclaration of 'optionalInOut(x:)' which differs only by the kind of optional passed as an inout argument ('Int!' vs. 'Int?')}}
275+
// expected-note@-1 {{overloading by kind of optional is deprecated and will be removed in a future release}}
276+
// expected-warning@-2 {{invalid redeclaration of 'optionalInOut(x:)' which differs only by the kind of optional passed as an inout argument ('Int!' vs. 'Int?')}}
277+
// expected-note@-3 {{overloading by kind of optional is deprecated and will be removed in a future release}}
278+
279+
func optionalInOut(x: inout Int?) { } // expected-note{{previously declared}}
280+
// expected-note@-1 {{previously declared}}
281+
func optionalInOut(x: inout Int!) { } // expected-warning{{invalid redeclaration of 'optionalInOut(x:)' which differs only by the kind of optional passed as an inout argument ('Int!' vs. 'Int?')}}
282+
// expected-note@-1 {{overloading by kind of optional is deprecated and will be removed in a future release}}
283+
// expected-warning@-2 {{invalid redeclaration of 'optionalInOut(x:)' which differs only by the kind of optional passed as an inout argument ('Int!' vs. 'Int?')}}
284+
// expected-note@-3 {{overloading by kind of optional is deprecated and will be removed in a future release}}
285+
}
286+
264287
func optional_3() -> Int? { } // expected-note{{previously declared}}
265288
func optional_3() -> Int! { } // expected-error{{invalid redeclaration of 'optional_3()'}}
266289

0 commit comments

Comments
 (0)