Skip to content

Commit 3264433

Browse files
committed
TypeCheckType: Fix missing any fix-it for compositions
1 parent 4b80606 commit 3264433

File tree

3 files changed

+60
-17
lines changed

3 files changed

+60
-17
lines changed

lib/Sema/TypeCheckType.cpp

Lines changed: 35 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6033,40 +6033,58 @@ class ExistentialTypeSyntaxChecker : public ASTWalker {
60336033
}
60346034

60356035
void emitInsertAnyFixit(InFlightDiagnostic &diag, DeclRefTypeRepr *T) const {
6036-
TypeRepr *replaceRepr = T;
6036+
TypeRepr *replacementSource = T;
60376037

60386038
// Insert parens in expression context for '(any P).self'
60396039
bool needsParens = (exprCount != 0);
6040+
6041+
// Compute the replacement source (the node to which to apply `any`).
60406042
if (reprStack.size() > 1) {
6041-
auto parentIt = reprStack.end() - 2;
6042-
needsParens = existentialNeedsParens(*parentIt);
6043-
6044-
// Expand to include parenthesis before checking if the parent needs
6045-
// to be replaced.
6046-
while (parentIt != reprStack.begin() &&
6047-
(*parentIt)->getWithoutParens() != *parentIt)
6048-
parentIt -= 1;
6049-
6050-
// For existential metatypes, 'any' is applied to the metatype.
6051-
if ((*parentIt)->getKind() == TypeReprKind::Metatype) {
6052-
replaceRepr = *parentIt;
6053-
if (parentIt != reprStack.begin())
6054-
needsParens = existentialNeedsParens(*(parentIt - 1));
6043+
auto it = reprStack.end() - 1;
6044+
auto replacementSourceIt = it;
6045+
6046+
// Backtrack the stack and expand the replacement source to any parent
6047+
// compositions or `.Type` metatypes, skipping only parentheses.
6048+
//
6049+
// - `P` → `any P`.
6050+
// - `P.Type` → `any P.Type`
6051+
// - `X & P` → `any X & P`, not `X & any P`.
6052+
// - `(X & P).Type` → `any (X & P).Type`, not `(any X & P).Type`.
6053+
do {
6054+
--it;
6055+
if ((*it)->getWithoutParens() != *it) {
6056+
continue;
6057+
}
6058+
6059+
if (isa<CompositionTypeRepr>(*it) || isa<MetatypeTypeRepr>(*it)) {
6060+
replacementSourceIt = it;
6061+
continue;
6062+
}
6063+
6064+
break;
6065+
} while (it != reprStack.begin());
6066+
6067+
// Whether parentheses are necessary is determined by the immediate parent
6068+
// of the replacement source.
6069+
if (replacementSourceIt != reprStack.begin()) {
6070+
needsParens = existentialNeedsParens(*(replacementSourceIt - 1));
60556071
}
6072+
6073+
replacementSource = *replacementSourceIt;
60566074
}
60576075

60586076
llvm::SmallString<64> fix;
60596077
{
60606078
llvm::raw_svector_ostream OS(fix);
60616079
if (needsParens)
60626080
OS << "(";
6063-
ExistentialTypeRepr existential(SourceLoc(), replaceRepr);
6081+
ExistentialTypeRepr existential(SourceLoc(), replacementSource);
60646082
existential.print(OS);
60656083
if (needsParens)
60666084
OS << ")";
60676085
}
60686086

6069-
diag.fixItReplace(replaceRepr->getSourceRange(), fix);
6087+
diag.fixItReplace(replacementSource->getSourceRange(), fix);
60706088
}
60716089

60726090
void checkDeclRefTypeRepr(DeclRefTypeRepr *T) const {

test/type/explicit_existential.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,8 @@ func testAnyFixIt() {
301301
let _: (HasAssoc).Type = ConformingType.self
302302
// expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{10-27=any ((HasAssoc)).Type}}
303303
let _: ((HasAssoc)).Type = ConformingType.self
304+
// expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{10-32=any ((HasAssoc).Type).Type}}
305+
let _: ((HasAssoc).Type).Type
304306
// expected-error@+2 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{10-18=(any HasAssoc)}}
305307
// expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{30-38=(any HasAssoc)}}
306308
let _: HasAssoc.Protocol = HasAssoc.self
@@ -335,6 +337,17 @@ func testAnyFixIt() {
335337
// expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{37-45=any HasAssoc}}
336338
func f2(_: some ((HasAssocGeneric<HasAssoc>)) & (HasAssoc)) {}
337339

340+
// https://github.com/apple/swift/issues/65027
341+
342+
// expected-error@+2:10 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{10-29=any HasAssoc & HasAssoc}}
343+
// expected-error@+1:21 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{10-29=any HasAssoc & HasAssoc}}
344+
let _: HasAssoc & HasAssoc
345+
// expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{11-27=any C & ((HasAssoc))}}
346+
let _: (C & ((HasAssoc)))
347+
// expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{10-40=(any (C & (HasAssoc & C)).Type.Type)}}
348+
let _: (C & (HasAssoc & C)).Type.Type?
349+
350+
338351
// expected-error@+1 {{optional 'any' type must be written '(any HasAssoc)?'}}{{10-23=(any HasAssoc)?}}
339352
let _: any HasAssoc? = nil
340353
// expected-error@+1 {{optional 'any' type must be written '(any HasAssoc.Type)?'}}{{10-28=(any HasAssoc.Type)?}}

test/type/explicit_existential_swift6.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,8 @@ func testAnyFixIt() {
334334
let _: (HasAssoc).Type = ConformingType.self
335335
// expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{10-27=any ((HasAssoc)).Type}}
336336
let _: ((HasAssoc)).Type = ConformingType.self
337+
// expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{10-32=any ((HasAssoc).Type).Type}}
338+
let _: ((HasAssoc).Type).Type
337339
// expected-error@+2 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{10-18=(any HasAssoc)}}
338340
// expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{30-38=(any HasAssoc)}}
339341
let _: HasAssoc.Protocol = HasAssoc.self
@@ -368,6 +370,16 @@ func testAnyFixIt() {
368370
// expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{37-45=any HasAssoc}}
369371
func f2(_: some ((HasAssocGeneric<HasAssoc>)) & (HasAssoc)) {}
370372

373+
// https://github.com/apple/swift/issues/65027
374+
375+
// expected-error@+2:10 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{10-29=any HasAssoc & HasAssoc}}
376+
// expected-error@+1:21 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{10-29=any HasAssoc & HasAssoc}}
377+
let _: HasAssoc & HasAssoc
378+
// expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{11-27=any C & ((HasAssoc))}}
379+
let _: (C & ((HasAssoc)))
380+
// expected-error@+1 {{use of protocol 'HasAssoc' as a type must be written 'any HasAssoc'}}{{10-40=(any (C & (HasAssoc & C)).Type.Type)}}
381+
let _: (C & (HasAssoc & C)).Type.Type?
382+
371383
// expected-error@+1 {{optional 'any' type must be written '(any HasAssoc)?'}}{{10-23=(any HasAssoc)?}}
372384
let _: any HasAssoc? = nil
373385
// expected-error@+1 {{optional 'any' type must be written '(any HasAssoc.Type)?'}}{{10-28=(any HasAssoc.Type)?}}

0 commit comments

Comments
 (0)