Skip to content

Commit cbf3cab

Browse files
authored
Merge pull request #30746 from ismetanin/fix-it-for-removing-escaping-from-optional-closure-parameter
Add new error diagnostic for escaping optional closures
2 parents c34739c + 0beddca commit cbf3cab

File tree

3 files changed

+31
-30
lines changed

3 files changed

+31
-30
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2856,8 +2856,8 @@ ERROR(autoclosure_function_input_nonunit,none,
28562856
ERROR(escaping_non_function_parameter,none,
28572857
"@escaping attribute may only be used in function parameter position", ())
28582858

2859-
NOTE(escaping_optional_type_argument, none,
2860-
"closure is already escaping in optional type argument", ())
2859+
ERROR(escaping_optional_type_argument, none,
2860+
"closure is already escaping in optional type argument", ())
28612861

28622862
// @_nonEphemeral attribute
28632863
ERROR(non_ephemeral_non_pointer_type,none,

lib/Sema/TypeCheckType.cpp

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2392,13 +2392,14 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs,
23922392
auto loc = attrs.getLoc(TAK_escaping);
23932393
auto attrRange = getTypeAttrRangeWithAt(Context, loc);
23942394

2395-
diagnoseInvalid(repr, loc, diag::escaping_non_function_parameter)
2396-
.fixItRemove(attrRange);
2397-
2398-
// Try to find a helpful note based on how the type is being used
2395+
// Try to find a better diagnostic based on how the type is being used
23992396
if (options.is(TypeResolverContext::ImmediateOptionalTypeArgument)) {
24002397
diagnoseInvalid(repr, repr->getLoc(),
2401-
diag::escaping_optional_type_argument);
2398+
diag::escaping_optional_type_argument)
2399+
.fixItRemove(attrRange);
2400+
} else {
2401+
diagnoseInvalid(repr, loc, diag::escaping_non_function_parameter)
2402+
.fixItRemove(attrRange);
24022403
}
24032404
}
24042405

@@ -2418,25 +2419,29 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs,
24182419
attrs.clearAttribute(TAK_autoclosure);
24192420
}
24202421

2422+
const auto diagnoseInvalidAttr = [&](TypeAttrKind kind) {
2423+
if (kind == TAK_escaping) {
2424+
Type optionalObjectType = ty->getOptionalObjectType();
2425+
if (optionalObjectType && optionalObjectType->is<AnyFunctionType>()) {
2426+
return diagnoseInvalid(repr, attrs.getLoc(kind),
2427+
diag::escaping_optional_type_argument);
2428+
}
2429+
}
2430+
return diagnoseInvalid(repr, attrs.getLoc(kind),
2431+
diag::attribute_requires_function_type,
2432+
TypeAttributes::getAttrName(kind));
2433+
};
2434+
24212435
for (auto i : FunctionAttrs) {
24222436
if (!attrs.has(i))
24232437
continue;
24242438

2425-
auto diag = diagnoseInvalid(repr, attrs.getLoc(i),
2426-
diag::attribute_requires_function_type,
2427-
TypeAttributes::getAttrName(i));
2428-
2429-
// If we see @escaping among the attributes on this type, because it isn't
2430-
// a function type, we'll remove it.
2439+
auto diag = diagnoseInvalidAttr(i);
2440+
// If we see @escaping among the attributes on this type, because it
2441+
// isn't a function type, we'll remove it.
24312442
if (i == TAK_escaping) {
2432-
diag.fixItRemove(getTypeAttrRangeWithAt(Context,
2433-
attrs.getLoc(TAK_escaping)));
2434-
// Specialize the diagnostic for Optionals.
2435-
if (ty->getOptionalObjectType()) {
2436-
diag.flush();
2437-
diagnoseInvalid(repr, repr->getLoc(),
2438-
diag::escaping_optional_type_argument);
2439-
}
2443+
diag.fixItRemove(
2444+
getTypeAttrRangeWithAt(Context, attrs.getLoc(TAK_escaping)));
24402445
}
24412446
attrs.clearAttribute(i);
24422447
}

test/attr/attr_escaping.swift

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -72,15 +72,11 @@ struct GenericStruct<T> {}
7272

7373
func misuseEscaping(_ a: @escaping Int) {} // expected-error{{@escaping attribute only applies to function types}} {{26-36=}}
7474
func misuseEscaping(_ a: (@escaping Int)?) {} // expected-error{{@escaping attribute only applies to function types}} {{27-36=}}
75-
func misuseEscaping(opt a: @escaping ((Int) -> Int)?) {} // expected-error{{@escaping attribute only applies to function types}} {{28-38=}}
76-
// expected-note@-1{{closure is already escaping in optional type argument}}
77-
78-
func misuseEscaping(_ a: (@escaping (Int) -> Int)?) {} // expected-error{{@escaping attribute may only be used in function parameter position}} {{27-36=}}
79-
// expected-note@-1{{closure is already escaping in optional type argument}}
80-
func misuseEscaping(nest a: (((@escaping (Int) -> Int))?)) {} // expected-error{{@escaping attribute may only be used in function parameter position}} {{32-41=}}
81-
// expected-note@-1{{closure is already escaping in optional type argument}}
82-
func misuseEscaping(iuo a: (@escaping (Int) -> Int)!) {} // expected-error{{@escaping attribute may only be used in function parameter position}} {{29-38=}}
83-
// expected-note@-1{{closure is already escaping in optional type argument}}
75+
func misuseEscaping(opt a: @escaping ((Int) -> Int)?) {} // expected-error{{closure is already escaping in optional type argument}} {{28-38=}}
76+
77+
func misuseEscaping(_ a: (@escaping (Int) -> Int)?) {} // expected-error{{closure is already escaping in optional type argument}} {{27-36=}}
78+
func misuseEscaping(nest a: (((@escaping (Int) -> Int))?)) {} // expected-error{{closure is already escaping in optional type argument}} {{32-41=}}
79+
func misuseEscaping(iuo a: (@escaping (Int) -> Int)!) {} // expected-error{{closure is already escaping in optional type argument}} {{29-38=}}
8480

8581
func misuseEscaping(_ a: Optional<@escaping (Int) -> Int>, _ b: Int) {} // expected-error{{@escaping attribute may only be used in function parameter position}} {{35-44=}}
8682
func misuseEscaping(_ a: (@escaping (Int) -> Int, Int)) {} // expected-error{{@escaping attribute may only be used in function parameter position}} {{27-36=}}

0 commit comments

Comments
 (0)