Skip to content

Commit 801168f

Browse files
committed
[Diagnostics] Fix missing 'any' warnings for type aliases.
Only warn when using a type alias if the underlying type is directly a constraint type. Also check the underlying type for missing 'any' if the underlying type is not directly a constraint type.
1 parent b0c2dbe commit 801168f

File tree

4 files changed

+60
-19
lines changed

4 files changed

+60
-19
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4705,8 +4705,8 @@ ERROR(any_not_existential,none,
47054705
"'any' has no effect on %select{concrete type|type parameter}0 %1",
47064706
(bool, Type))
47074707
ERROR(existential_requires_any,none,
4708-
"protocol %0 as a type must be explicitly marked as 'any'",
4709-
(Identifier))
4708+
"%select{protocol |}1%0 as a type must be explicitly marked as 'any'",
4709+
(Type, bool))
47104710

47114711
ERROR(nonisolated_let,none,
47124712
"'nonisolated' is meaningless on 'let' declarations because "

lib/Sema/TypeCheckType.cpp

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4148,29 +4148,29 @@ class ExistentialTypeVisitor
41484148
if (proto->existentialRequiresAny()) {
41494149
Ctx.Diags.diagnose(comp->getNameLoc(),
41504150
diag::existential_requires_any,
4151-
proto->getName())
4151+
proto->getDeclaredInterfaceType(),
4152+
/*isAlias=*/false)
41524153
.limitBehavior(DiagnosticBehavior::Warning);
41534154
}
41544155
} else if (auto *alias = dyn_cast_or_null<TypeAliasDecl>(comp->getBoundDecl())) {
41554156
auto type = Type(alias->getDeclaredInterfaceType()->getDesugaredType());
4156-
type.findIf([&](Type type) -> bool {
4157-
if (T->isInvalid())
4158-
return false;
4159-
if (type->isExistentialType()) {
4160-
auto layout = type->getExistentialLayout();
4161-
for (auto *proto : layout.getProtocols()) {
4162-
auto *protoDecl = proto->getDecl();
4163-
if (!protoDecl->existentialRequiresAny())
4164-
continue;
4157+
// If this is a type alias to a constraint type, the type
4158+
// alias name must be prefixed with 'any' to be used as an
4159+
// existential type.
4160+
if (type->isConstraintType()) {
4161+
auto layout = type->getExistentialLayout();
4162+
for (auto *proto : layout.getProtocols()) {
4163+
auto *protoDecl = proto->getDecl();
4164+
if (!protoDecl->existentialRequiresAny())
4165+
continue;
41654166

4166-
Ctx.Diags.diagnose(comp->getNameLoc(),
4167-
diag::existential_requires_any,
4168-
protoDecl->getName())
4169-
.limitBehavior(DiagnosticBehavior::Warning);
4170-
}
4167+
Ctx.Diags.diagnose(comp->getNameLoc(),
4168+
diag::existential_requires_any,
4169+
alias->getDeclaredInterfaceType(),
4170+
/*isAlias=*/true)
4171+
.limitBehavior(DiagnosticBehavior::Warning);
41714172
}
4172-
return false;
4173-
});
4173+
}
41744174
}
41754175
}
41764176

@@ -4198,6 +4198,9 @@ void TypeChecker::checkExistentialTypes(Decl *decl) {
41984198
} else if (auto *genericDecl = dyn_cast<GenericTypeDecl>(decl)) {
41994199
checkExistentialTypes(ctx, genericDecl->getGenericParams());
42004200
checkExistentialTypes(ctx, genericDecl->getTrailingWhereClause());
4201+
if (auto *typeAlias = dyn_cast<TypeAliasDecl>(decl)) {
4202+
checkExistentialTypes(ctx, typeAlias);
4203+
}
42014204
} else if (auto *assocType = dyn_cast<AssociatedTypeDecl>(decl)) {
42024205
checkExistentialTypes(ctx, assocType->getTrailingWhereClause());
42034206
} else if (auto *extDecl = dyn_cast<ExtensionDecl>(decl)) {
@@ -4227,6 +4230,19 @@ void TypeChecker::checkExistentialTypes(ASTContext &ctx, Stmt *stmt) {
42274230
stmt->walk(visitor);
42284231
}
42294232

4233+
void TypeChecker::checkExistentialTypes(ASTContext &ctx,
4234+
TypeAliasDecl *typeAlias) {
4235+
if (!typeAlias || !typeAlias->getUnderlyingTypeRepr())
4236+
return;
4237+
4238+
// A type alias to a plain constraint type is allowed.
4239+
if (typeAlias->getUnderlyingType()->isConstraintType())
4240+
return;
4241+
4242+
ExistentialTypeVisitor visitor(ctx, /*checkStatements=*/true);
4243+
typeAlias->getUnderlyingTypeRepr()->walk(visitor);
4244+
}
4245+
42304246
void TypeChecker::checkExistentialTypes(
42314247
ASTContext &ctx, TrailingWhereClause *whereClause) {
42324248
if (whereClause == nullptr)

lib/Sema/TypeChecker.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,10 @@ void checkExistentialTypes(Decl *decl);
251251
/// Check for invalid existential types in the given statement.
252252
void checkExistentialTypes(ASTContext &ctx, Stmt *stmt);
253253

254+
/// Check for invalid existential types in the underlying type of
255+
/// the given type alias.
256+
void checkExistentialTypes(ASTContext &ctx, TypeAliasDecl *typeAlias);
257+
254258
/// Check for invalid existential types in the given generic requirement
255259
/// list.
256260
void checkExistentialTypes(ASTContext &ctx,

test/type/explicit_existential.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,3 +236,24 @@ func testAnyTypeExpr() {
236236

237237
func hasInvalidExistential(_: any DoesNotExistIHope) {}
238238
// expected-error@-1 {{cannot find type 'DoesNotExistIHope' in scope}}
239+
240+
protocol Input {
241+
associatedtype A
242+
}
243+
protocol Output {
244+
associatedtype A
245+
}
246+
247+
// expected-warning@+2{{protocol 'Input' as a type must be explicitly marked as 'any'}}
248+
// expected-warning@+1{{protocol 'Output' as a type must be explicitly marked as 'any'}}
249+
typealias InvalidFunction = (Input) -> Output
250+
func testInvalidFunctionAlias(fn: InvalidFunction) {}
251+
252+
typealias ExistentialFunction = (any Input) -> any Output
253+
func testFunctionAlias(fn: ExistentialFunction) {}
254+
255+
typealias Constraint = Input
256+
func testConstraintAlias(x: Constraint) {} // expected-warning{{'Constraint' (aka 'Input') as a type must be explicitly marked as 'any'}}
257+
258+
typealias Existential = any Input
259+
func testExistentialAlias(x: Existential, y: any Constraint) {}

0 commit comments

Comments
 (0)