Skip to content

Commit 3cda934

Browse files
authored
[Typechecker] Fix duplicate diagnostics when using attributes (swiftlang#28888)
* [Typechecker] resolveAttributedType() should invalidate the type repr after emitting a diagnostic, to prevent duplicate diagnostics later * [Test] Update '@NoEscape' attribute diagnostics * [Typechecker] Add a special diagnose method to TypeResolver that accepts a TypeRepr and invalidates it * [Typechecker] Rename the special 'diagnose' method to 'diagnoseInvalid' for clarity
1 parent 4062012 commit 3cda934

File tree

4 files changed

+75
-60
lines changed

4 files changed

+75
-60
lines changed

lib/Sema/TypeCheckType.cpp

Lines changed: 55 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1782,6 +1782,14 @@ namespace {
17821782
return diags.diagnose(std::forward<ArgTypes>(Args)...);
17831783
}
17841784

1785+
template <typename... ArgTypes>
1786+
InFlightDiagnostic diagnoseInvalid(TypeRepr *repr,
1787+
ArgTypes &&... Args) const {
1788+
auto &diags = Context.Diags;
1789+
repr->setInvalid();
1790+
return diags.diagnose(std::forward<ArgTypes>(Args)...);
1791+
}
1792+
17851793
Type resolveAttributedType(AttributedTypeRepr *repr,
17861794
TypeResolutionOptions options);
17871795
Type resolveAttributedType(TypeAttributes &attrs, TypeRepr *repr,
@@ -2080,18 +2088,21 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs,
20802088

20812089
// Check for @thick.
20822090
if (attrs.has(TAK_thick)) {
2083-
if (storedRepr)
2084-
diagnose(repr->getStartLoc(), diag::sil_metatype_multiple_reprs);
2085-
2091+
if (storedRepr) {
2092+
diagnoseInvalid(repr, repr->getStartLoc(),
2093+
diag::sil_metatype_multiple_reprs);
2094+
}
2095+
20862096
storedRepr = MetatypeRepresentation::Thick;
20872097
attrs.clearAttribute(TAK_thick);
20882098
}
20892099

20902100
// Check for @objc_metatype.
20912101
if (attrs.has(TAK_objc_metatype)) {
2092-
if (storedRepr)
2093-
diagnose(repr->getStartLoc(), diag::sil_metatype_multiple_reprs);
2094-
2102+
if (storedRepr) {
2103+
diagnoseInvalid(repr, repr->getStartLoc(),
2104+
diag::sil_metatype_multiple_reprs);
2105+
}
20952106
storedRepr = MetatypeRepresentation::ObjC;
20962107
attrs.clearAttribute(TAK_objc_metatype);
20972108
}
@@ -2119,8 +2130,8 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs,
21192130

21202131
auto checkUnsupportedAttr = [&](TypeAttrKind attr) {
21212132
if (attrs.has(attr)) {
2122-
diagnose(attrs.getLoc(attr), diag::unknown_attribute,
2123-
TypeAttributes::getAttrName(attr));
2133+
diagnoseInvalid(repr, attrs.getLoc(attr), diag::unknown_attribute,
2134+
TypeAttributes::getAttrName(attr));
21242135
attrs.clearAttribute(attr);
21252136
}
21262137
};
@@ -2170,8 +2181,8 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs,
21702181
auto calleeConvention = ParameterConvention::Direct_Unowned;
21712182
if (attrs.has(TAK_callee_owned)) {
21722183
if (attrs.has(TAK_callee_guaranteed)) {
2173-
diagnose(attrs.getLoc(TAK_callee_owned),
2174-
diag::sil_function_repeat_convention, /*callee*/ 2);
2184+
diagnoseInvalid(repr, attrs.getLoc(TAK_callee_owned),
2185+
diag::sil_function_repeat_convention, /*callee*/ 2);
21752186
}
21762187
calleeConvention = ParameterConvention::Direct_Owned;
21772188
} else if (attrs.has(TAK_callee_guaranteed)) {
@@ -2197,8 +2208,9 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs,
21972208
SILFunctionType::Representation::WitnessMethod)
21982209
.Default(None);
21992210
if (!parsedRep) {
2200-
diagnose(attrs.getLoc(TAK_convention),
2201-
diag::unsupported_sil_convention, attrs.getConventionName());
2211+
diagnoseInvalid(repr, attrs.getLoc(TAK_convention),
2212+
diag::unsupported_sil_convention,
2213+
attrs.getConventionName());
22022214
rep = SILFunctionType::Representation::Thin;
22032215
} else {
22042216
rep = *parsedRep;
@@ -2214,8 +2226,8 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs,
22142226

22152227
if (attrs.has(TAK_differentiable) &&
22162228
!Context.LangOpts.EnableExperimentalDifferentiableProgramming) {
2217-
diagnose(attrs.getLoc(TAK_differentiable),
2218-
diag::experimental_differentiable_programming_disabled);
2229+
diagnoseInvalid(repr, attrs.getLoc(TAK_differentiable),
2230+
diag::experimental_differentiable_programming_disabled);
22192231
}
22202232

22212233
DifferentiabilityKind diffKind = DifferentiabilityKind::NonDifferentiable;
@@ -2246,8 +2258,9 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs,
22462258
.Case("c", FunctionType::Representation::CFunctionPointer)
22472259
.Default(None);
22482260
if (!parsedRep) {
2249-
diagnose(attrs.getLoc(TAK_convention), diag::unsupported_convention,
2250-
attrs.getConventionName());
2261+
diagnoseInvalid(repr, attrs.getLoc(TAK_convention),
2262+
diag::unsupported_convention,
2263+
attrs.getConventionName());
22512264
rep = FunctionType::Representation::Swift;
22522265
} else {
22532266
rep = *parsedRep;
@@ -2256,8 +2269,8 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs,
22562269

22572270
if (attrs.has(TAK_differentiable) &&
22582271
!Context.LangOpts.EnableExperimentalDifferentiableProgramming) {
2259-
diagnose(attrs.getLoc(TAK_differentiable),
2260-
diag::experimental_differentiable_programming_disabled);
2272+
diagnoseInvalid(repr, attrs.getLoc(TAK_differentiable),
2273+
diag::experimental_differentiable_programming_disabled);
22612274
}
22622275

22632276
DifferentiabilityKind diffKind = DifferentiabilityKind::NonDifferentiable;
@@ -2279,21 +2292,21 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs,
22792292
if (attrs.hasConvention()) {
22802293
if (attrs.getConventionName() == "c" ||
22812294
attrs.getConventionName() == "block") {
2282-
diagnose(attrs.getLoc(TAK_convention),
2283-
diag::invalid_autoclosure_and_convention_attributes,
2284-
attrs.getConventionName());
2295+
diagnoseInvalid(repr, attrs.getLoc(TAK_convention),
2296+
diag::invalid_autoclosure_and_convention_attributes,
2297+
attrs.getConventionName());
22852298
attrs.clearAttribute(TAK_convention);
22862299
didDiagnose = true;
22872300
}
22882301
} else if (options.is(TypeResolverContext::VariadicFunctionInput) &&
22892302
!options.hasBase(TypeResolverContext::EnumElementDecl)) {
2290-
diagnose(attrs.getLoc(TAK_autoclosure),
2291-
diag::attr_not_on_variadic_parameters, "@autoclosure");
2303+
diagnoseInvalid(repr, attrs.getLoc(TAK_autoclosure),
2304+
diag::attr_not_on_variadic_parameters, "@autoclosure");
22922305
attrs.clearAttribute(TAK_autoclosure);
22932306
didDiagnose = true;
22942307
} else if (!options.is(TypeResolverContext::FunctionInput)) {
2295-
diagnose(attrs.getLoc(TAK_autoclosure), diag::attr_only_on_parameters,
2296-
"@autoclosure");
2308+
diagnoseInvalid(repr, attrs.getLoc(TAK_autoclosure),
2309+
diag::attr_only_on_parameters, "@autoclosure");
22972310
attrs.clearAttribute(TAK_autoclosure);
22982311
didDiagnose = true;
22992312
}
@@ -2328,12 +2341,13 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs,
23282341
auto loc = attrs.getLoc(TAK_escaping);
23292342
auto attrRange = getTypeAttrRangeWithAt(Context, loc);
23302343

2331-
diagnose(loc, diag::escaping_non_function_parameter)
2332-
.fixItRemove(attrRange);
2344+
diagnoseInvalid(repr, loc, diag::escaping_non_function_parameter)
2345+
.fixItRemove(attrRange);
23332346

23342347
// Try to find a helpful note based on how the type is being used
23352348
if (options.is(TypeResolverContext::ImmediateOptionalTypeArgument)) {
2336-
diagnose(repr->getLoc(), diag::escaping_optional_type_argument);
2349+
diagnoseInvalid(repr, repr->getLoc(),
2350+
diag::escaping_optional_type_argument);
23372351
}
23382352
}
23392353

@@ -2349,16 +2363,17 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs,
23492363
// @autoclosure is going to be diagnosed when type of
23502364
// the parameter is validated, because that attribute
23512365
// applies to the declaration now.
2366+
repr->setInvalid();
23522367
attrs.clearAttribute(TAK_autoclosure);
23532368
}
23542369

23552370
for (auto i : FunctionAttrs) {
23562371
if (!attrs.has(i))
23572372
continue;
23582373

2359-
auto diag = diagnose(attrs.getLoc(i),
2360-
diag::attribute_requires_function_type,
2361-
TypeAttributes::getAttrName(i));
2374+
auto diag = diagnoseInvalid(repr, attrs.getLoc(i),
2375+
diag::attribute_requires_function_type,
2376+
TypeAttributes::getAttrName(i));
23622377

23632378
// If we see @escaping among the attributes on this type, because it isn't
23642379
// a function type, we'll remove it.
@@ -2368,7 +2383,8 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs,
23682383
// Specialize the diagnostic for Optionals.
23692384
if (ty->getOptionalObjectType()) {
23702385
diag.flush();
2371-
diagnose(repr->getLoc(), diag::escaping_optional_type_argument);
2386+
diagnoseInvalid(repr, repr->getLoc(),
2387+
diag::escaping_optional_type_argument);
23722388
}
23732389
}
23742390
attrs.clearAttribute(i);
@@ -2398,7 +2414,8 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs,
23982414
// In SIL, handle @opened (n), which creates an existential archetype.
23992415
if (attrs.has(TAK_opened)) {
24002416
if (!ty->isExistentialType()) {
2401-
diagnose(attrs.getLoc(TAK_opened), diag::opened_non_protocol, ty);
2417+
diagnoseInvalid(repr, attrs.getLoc(TAK_opened), diag::opened_non_protocol,
2418+
ty);
24022419
} else {
24032420
ty = OpenedArchetypeType::get(ty, attrs.OpenedID);
24042421
}
@@ -2438,9 +2455,10 @@ Type TypeResolver::resolveAttributedType(TypeAttributes &attrs,
24382455
}
24392456

24402457
for (unsigned i = 0; i != TypeAttrKind::TAK_Count; ++i)
2441-
if (attrs.has((TypeAttrKind)i))
2442-
diagnose(attrs.getLoc((TypeAttrKind)i),
2443-
diag::attribute_does_not_apply_to_type);
2458+
if (attrs.has((TypeAttrKind)i)) {
2459+
diagnoseInvalid(repr, attrs.getLoc((TypeAttrKind)i),
2460+
diag::attribute_does_not_apply_to_type);
2461+
}
24442462

24452463
return ty;
24462464
}
@@ -3080,8 +3098,7 @@ Type TypeResolver::resolveSpecifierTypeRepr(SpecifierTypeRepr *repr,
30803098
default:
30813099
llvm_unreachable("unknown SpecifierTypeRepr kind");
30823100
}
3083-
diagnose(repr->getSpecifierLoc(), diagID, name);
3084-
repr->setInvalid();
3101+
diagnoseInvalid(repr, repr->getSpecifierLoc(), diagID, name);
30853102
return ErrorType::get(Context);
30863103
}
30873104

test/attr/attr_autoclosure.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,3 +292,6 @@ func sr_11938_3(_ x: [@autoclosure String]) {} // expected-error {{'@autoclosure
292292

293293
protocol SR_11938_P {}
294294
struct SR_11938_S : @autoclosure SR_11938_P {} // expected-error {{'@autoclosure' may only be used on parameters}}
295+
296+
// SR-9178
297+
func bar<T>(_ x: @autoclosure T) {} // expected-error 1{{@autoclosure attribute only applies to function types}}

test/attr/attr_escaping.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,3 +226,6 @@ extension SR_9760 {
226226
func fiz<T>(_: T, _: @escaping F) {} // Ok
227227
func baz<T>(_: @escaping G<T>) {} // Ok
228228
}
229+
230+
// SR-9178
231+
func foo<T>(_ x: @escaping T) {} // expected-error 1{{@escaping attribute only applies to function types}}

test/attr/attr_noescape.swift

Lines changed: 14 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ func conflictingAttrs(_ fn: @noescape @escaping () -> Int) {} // expected-error
66

77
func doesEscape(_ fn : @escaping () -> Int) {}
88

9-
func takesGenericClosure<T>(_ a : Int, _ fn : @noescape () -> T) {} // expected-error 2{{unknown attribute 'noescape'}}
9+
func takesGenericClosure<T>(_ a : Int, _ fn : @noescape () -> T) {} // expected-error {{unknown attribute 'noescape'}}
1010

1111

1212
var globalAny: Any = 0
@@ -23,8 +23,8 @@ func takesVariadic(_ fns: () -> Int...) {
2323
doesEscape(fns[0]) // Okay - variadic-of-function parameters are escaping
2424
}
2525

26-
func takesNoEscapeClosure(_ fn : () -> Int) { // expected-note 2 {{parameter 'fn' is implicitly non-escaping}} {{34-34=@escaping }}
27-
// expected-note@-1 5{{parameter 'fn' is implicitly non-escaping}} {{34-34=@escaping }}
26+
func takesNoEscapeClosure(_ fn : () -> Int) { // expected-note 1 {{parameter 'fn' is implicitly non-escaping}} {{34-34=@escaping }}
27+
// expected-note@-1 6{{parameter 'fn' is implicitly non-escaping}} {{34-34=@escaping }}
2828
takesNoEscapeClosure { 4 } // ok
2929

3030
_ = fn() // ok
@@ -195,10 +195,7 @@ func testAutoclosure(_ a : @autoclosure () -> Int) { // expected-note{{parameter
195195

196196

197197
// <rdar://problem/19470858> QoI: @autoclosure implies @noescape, so you shouldn't be allowed to specify both
198-
func redundant(_ fn : @noescape
199-
@autoclosure () -> Int) {
200-
// expected-error@-2{{unknown attribute 'noescape'}}
201-
}
198+
func redundant(_ fn : @noescape @autoclosure () -> Int) {} // expected-error {{unknown attribute 'noescape'}}
202199

203200

204201
protocol P1 {
@@ -215,9 +212,7 @@ func overloadedEach<P: P2, T>(_ source: P, _ transform: @escaping (P.Element) ->
215212
struct S : P2 {
216213
typealias Element = Int
217214
func each(_ transform: @noescape (Int) -> ()) { // expected-error{{unknown attribute 'noescape'}}
218-
// expected-note@-1 {{parameter 'transform' is implicitly non-escaping}}
219215
overloadedEach(self, transform, 1)
220-
// expected-error@-1 {{passing non-escaping parameter 'transform' to function expecting an @escaping closure}}
221216
}
222217
}
223218

@@ -261,22 +256,22 @@ public func XCTAssert(_ expression: @autoclosure () -> Bool, _ message: String =
261256

262257

263258
/// SR-770 - Currying and `noescape`/`rethrows` don't work together anymore
264-
func curriedFlatMap<A, B>(_ x: [A]) -> (@noescape (A) -> [B]) -> [B] { // expected-error 2{{unknown attribute 'noescape'}}
259+
func curriedFlatMap<A, B>(_ x: [A]) -> (@noescape (A) -> [B]) -> [B] { // expected-error 1{{unknown attribute 'noescape'}}
265260
return { f in
266261
x.flatMap(f)
267262
}
268263
}
269264

270-
func curriedFlatMap2<A, B>(_ x: [A]) -> (@noescape (A) -> [B]) -> [B] { // expected-error 2{{unknown attribute 'noescape'}}
271-
return { (f : @noescape (A) -> [B]) in // expected-error{{unknown attribute 'noescape'}}
265+
func curriedFlatMap2<A, B>(_ x: [A]) -> (@noescape (A) -> [B]) -> [B] { // expected-error {{unknown attribute 'noescape'}}
266+
return { (f : @noescape (A) -> [B]) in
272267
x.flatMap(f)
273268
}
274269
}
275270

276271
func bad(_ a : @escaping (Int)-> Int) -> Int { return 42 }
277272
func escapeNoEscapeResult(_ x: [Int]) -> (@noescape (Int) -> Int) -> Int { // expected-error{{unknown attribute 'noescape'}}
278-
return { f in // expected-note {{parameter 'f' is implicitly non-escaping}}
279-
bad(f) // expected-error {{passing non-escaping parameter 'f' to function expecting an @escaping closure}}
273+
return { f in
274+
bad(f)
280275
}
281276
}
282277

@@ -296,24 +291,21 @@ typealias CompletionHandler = (_ success: Bool) -> ()
296291
var escape : CompletionHandlerNE
297292
var escapeOther : CompletionHandler
298293
func doThing1(_ completion: (_ success: Bool) -> ()) {
299-
// expected-note@-1 {{parameter 'completion' is implicitly non-escaping}}
300-
escape = completion // expected-error {{assigning non-escaping parameter 'completion' to an @escaping closure}}
294+
escape = completion
301295
}
302296
func doThing2(_ completion: CompletionHandlerNE) {
303-
// expected-note@-1 {{parameter 'completion' is implicitly non-escaping}}
304-
escape = completion // expected-error {{assigning non-escaping parameter 'completion' to an @escaping closure}}
297+
escape = completion
305298
}
306299
func doThing3(_ completion: CompletionHandler) {
307-
// expected-note@-1 {{parameter 'completion' is implicitly non-escaping}}
308-
escape = completion // expected-error {{assigning non-escaping parameter 'completion' to an @escaping closure}}
300+
escape = completion
309301
}
310302
func doThing4(_ completion: @escaping CompletionHandler) {
311303
escapeOther = completion
312304
}
313305

314306
// <rdar://problem/19997680> @noescape doesn't work on parameters of function type
315307
func apply<T, U>(_ f: @noescape (T) -> U, g: @noescape (@noescape (T) -> U) -> U) -> U {
316-
// expected-error@-1 6{{unknown attribute 'noescape'}}
308+
// expected-error@-1 2{{unknown attribute 'noescape'}}
317309
return g(f)
318310
}
319311

@@ -323,7 +315,7 @@ enum r19997577Type {
323315
case Function(() -> r19997577Type, () -> r19997577Type)
324316
case Sum(() -> r19997577Type, () -> r19997577Type)
325317

326-
func reduce<Result>(_ initial: Result, _ combine: @noescape (Result, r19997577Type) -> Result) -> Result { // expected-error 2{{unknown attribute 'noescape'}}
318+
func reduce<Result>(_ initial: Result, _ combine: @noescape (Result, r19997577Type) -> Result) -> Result { // expected-error 1{{unknown attribute 'noescape'}}
327319
let binary: @noescape (r19997577Type, r19997577Type) -> Result = { combine(combine(combine(initial, self), $0), $1) } // expected-error{{unknown attribute 'noescape'}}
328320
switch self {
329321
case .Unit:

0 commit comments

Comments
 (0)