Skip to content

Commit b58c3a2

Browse files
authored
[FixCode] Add @escaping when overriding mismatch is because of it. (#4273)
* [FixCode] Add @escaping when overriding mismatch is because of it. rdar://27814862 With the change of default escaping behavior, users' existing code overriding objc functions may need to add @escaping to make the overriding match as before. This patch checks if an overriding mismatch is due to the lacking of @escaping and add it as a fixit. * [test] Update existing test. NFC
1 parent c1cf3c7 commit b58c3a2

File tree

3 files changed

+46
-3
lines changed

3 files changed

+46
-3
lines changed

lib/Sema/MiscDiagnostics.cpp

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1130,8 +1130,8 @@ bool swift::fixItOverrideDeclarationTypes(TypeChecker &TC,
11301130
// override uses a reference type, and the value type is bridged to the
11311131
// reference type. This is a way to migrate code that makes use of types
11321132
// that previously were not bridged to value types.
1133-
auto checkType = [&](Type overrideTy, Type baseTy,
1134-
SourceRange typeRange) -> bool {
1133+
auto checkValueReferenceType = [&](Type overrideTy, Type baseTy,
1134+
SourceRange typeRange) -> bool {
11351135
if (typeRange.isInvalid())
11361136
return false;
11371137

@@ -1184,6 +1184,39 @@ bool swift::fixItOverrideDeclarationTypes(TypeChecker &TC,
11841184
return true;
11851185
};
11861186

1187+
// Check if overriding fails because we lack @escaping attribute on the function
1188+
// type repr.
1189+
auto checkTypeMissingEscaping = [&](Type overrideTy, Type baseTy,
1190+
SourceRange typeRange) -> bool {
1191+
// Fix-it needs position to apply.
1192+
if (typeRange.isInvalid())
1193+
return false;
1194+
auto overrideFnTy = overrideTy->getCanonicalType()->getAs<FunctionType>();
1195+
auto baseFnTy = baseTy->getCanonicalType()->getAs<FunctionType>();
1196+
1197+
// Both types should be function.
1198+
if (overrideFnTy && baseFnTy &&
1199+
// Both function types should have same input/result types.
1200+
overrideFnTy->getInput()->isEqual(baseFnTy->getInput()) &&
1201+
overrideFnTy->getResult()->isEqual(baseFnTy->getResult()) &&
1202+
// The overriding function type should be no escaping.
1203+
overrideFnTy->getExtInfo().isNoEscape() &&
1204+
// The overriden function type should be escaping.
1205+
!baseFnTy->getExtInfo().isNoEscape() &&
1206+
// Being escaping or not should be the only difference.
1207+
baseFnTy->getExtInfo().withNoEscape() == overrideFnTy->getExtInfo()) {
1208+
diag.fixItInsert(typeRange.Start, "@escaping ");
1209+
return true;
1210+
}
1211+
return false;
1212+
};
1213+
1214+
auto checkType = [&](Type overrideTy, Type baseTy,
1215+
SourceRange typeRange) -> bool {
1216+
return checkValueReferenceType(overrideTy, baseTy, typeRange) ||
1217+
checkTypeMissingEscaping(overrideTy, baseTy, typeRange);
1218+
};
1219+
11871220
if (auto *var = dyn_cast<VarDecl>(decl)) {
11881221
SourceRange typeRange = var->getTypeSourceRangeForDiagnostics();
11891222
return checkType(var->getType(), base->getType(), typeRange);

test/Constraints/override.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,13 @@ func removeOverrides<SomeSub: Sub>(concrete: Sub, generic: SomeSub) {
1212
_ = concrete.foo()
1313
_ = generic.foo()
1414
}
15+
16+
class Base1 {
17+
func foo1(a : Int, b : @escaping ()->()) {} // expected-note{{potential overridden instance method 'foo1(a:b:)' here}}
18+
func foo2(a : @escaping (Int)->(Int), b : @escaping ()->()) {} // expected-note{{potential overridden instance method 'foo2(a:b:)' here}}
19+
}
20+
21+
class Sub1 : Base1 {
22+
override func foo1(a : Int, b : ()->()) {} // expected-error {{method does not override any method from its superclass}} expected-note {{type does not match superclass instance method with type '(Int, @escaping () -> ()) -> ()'}} {{34-34=@escaping }}
23+
override func foo2(a : (Int)->(Int), b : ()->()) {} // expected-error {{method does not override any method from its superclass}} expected-note{{type does not match superclass instance method with type '(@escaping (Int) -> (Int), @escaping () -> ()) -> ()'}} {{25-25=@escaping }} {{43-43=@escaping }}
24+
}

test/attr/attr_autoclosure.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ class Super {
8888
class Sub : Super {
8989
override func f1(_ x: @autoclosure(escaping)() -> ()) { }
9090
// expected-warning@-1{{@autoclosure(escaping) is deprecated; use @autoclosure @escaping instead}} {{26-47=@autoclosure @escaping }}
91-
override func f2(_ x: @autoclosure () -> ()) { } // expected-error{{does not override any method}}
91+
override func f2(_ x: @autoclosure () -> ()) { } // expected-error{{does not override any method}} // expected-note{{type does not match superclass instance method with type '(@autoclosure @escaping () -> ()) -> ()'}}
9292
override func f3(_ x: @autoclosure(escaping) () -> ()) { } // expected-error{{does not override any method}}
9393
// expected-warning@-1{{@autoclosure(escaping) is deprecated; use @autoclosure @escaping instead}} {{26-47=@autoclosure @escaping }}
9494
}

0 commit comments

Comments
 (0)