Skip to content

Commit 9297ba1

Browse files
authored
Merge pull request #41481 from hborla/missing-any-diagnostics
[Diagnostics] Fix missing `any` warnings for type aliases.
2 parents d526dcf + 801168f commit 9297ba1

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
@@ -4707,8 +4707,8 @@ ERROR(any_not_existential,none,
47074707
"'any' has no effect on %select{concrete type|type parameter}0 %1",
47084708
(bool, Type))
47094709
ERROR(existential_requires_any,none,
4710-
"protocol %0 as a type must be explicitly marked as 'any'",
4711-
(Identifier))
4710+
"%select{protocol |}1%0 as a type must be explicitly marked as 'any'",
4711+
(Type, bool))
47124712

47134713
ERROR(nonisolated_let,none,
47144714
"'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
@@ -4154,29 +4154,29 @@ class ExistentialTypeVisitor
41544154
if (proto->existentialRequiresAny()) {
41554155
Ctx.Diags.diagnose(comp->getNameLoc(),
41564156
diag::existential_requires_any,
4157-
proto->getName())
4157+
proto->getDeclaredInterfaceType(),
4158+
/*isAlias=*/false)
41584159
.limitBehavior(DiagnosticBehavior::Warning);
41594160
}
41604161
} else if (auto *alias = dyn_cast_or_null<TypeAliasDecl>(comp->getBoundDecl())) {
41614162
auto type = Type(alias->getDeclaredInterfaceType()->getDesugaredType());
4162-
type.findIf([&](Type type) -> bool {
4163-
if (T->isInvalid())
4164-
return false;
4165-
if (type->isExistentialType()) {
4166-
auto layout = type->getExistentialLayout();
4167-
for (auto *proto : layout.getProtocols()) {
4168-
auto *protoDecl = proto->getDecl();
4169-
if (!protoDecl->existentialRequiresAny())
4170-
continue;
4163+
// If this is a type alias to a constraint type, the type
4164+
// alias name must be prefixed with 'any' to be used as an
4165+
// existential type.
4166+
if (type->isConstraintType()) {
4167+
auto layout = type->getExistentialLayout();
4168+
for (auto *proto : layout.getProtocols()) {
4169+
auto *protoDecl = proto->getDecl();
4170+
if (!protoDecl->existentialRequiresAny())
4171+
continue;
41714172

4172-
Ctx.Diags.diagnose(comp->getNameLoc(),
4173-
diag::existential_requires_any,
4174-
protoDecl->getName())
4175-
.limitBehavior(DiagnosticBehavior::Warning);
4176-
}
4173+
Ctx.Diags.diagnose(comp->getNameLoc(),
4174+
diag::existential_requires_any,
4175+
alias->getDeclaredInterfaceType(),
4176+
/*isAlias=*/true)
4177+
.limitBehavior(DiagnosticBehavior::Warning);
41774178
}
4178-
return false;
4179-
});
4179+
}
41804180
}
41814181
}
41824182

@@ -4204,6 +4204,9 @@ void TypeChecker::checkExistentialTypes(Decl *decl) {
42044204
} else if (auto *genericDecl = dyn_cast<GenericTypeDecl>(decl)) {
42054205
checkExistentialTypes(ctx, genericDecl->getGenericParams());
42064206
checkExistentialTypes(ctx, genericDecl->getTrailingWhereClause());
4207+
if (auto *typeAlias = dyn_cast<TypeAliasDecl>(decl)) {
4208+
checkExistentialTypes(ctx, typeAlias);
4209+
}
42074210
} else if (auto *assocType = dyn_cast<AssociatedTypeDecl>(decl)) {
42084211
checkExistentialTypes(ctx, assocType->getTrailingWhereClause());
42094212
} else if (auto *extDecl = dyn_cast<ExtensionDecl>(decl)) {
@@ -4233,6 +4236,19 @@ void TypeChecker::checkExistentialTypes(ASTContext &ctx, Stmt *stmt) {
42334236
stmt->walk(visitor);
42344237
}
42354238

4239+
void TypeChecker::checkExistentialTypes(ASTContext &ctx,
4240+
TypeAliasDecl *typeAlias) {
4241+
if (!typeAlias || !typeAlias->getUnderlyingTypeRepr())
4242+
return;
4243+
4244+
// A type alias to a plain constraint type is allowed.
4245+
if (typeAlias->getUnderlyingType()->isConstraintType())
4246+
return;
4247+
4248+
ExistentialTypeVisitor visitor(ctx, /*checkStatements=*/true);
4249+
typeAlias->getUnderlyingTypeRepr()->walk(visitor);
4250+
}
4251+
42364252
void TypeChecker::checkExistentialTypes(
42374253
ASTContext &ctx, TrailingWhereClause *whereClause) {
42384254
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)