Skip to content

Commit 575a29c

Browse files
committed
Sema: Fix crash-on-invalid with incorrect use of variadic generic type
Applying generic arguments to a variadic generic type uses the PackMatcher to build a mapping between generic parameters and arguments. The PackMatcher is symmetric, so there was an unexpected failure mode that wasn't handled: if the variadic generic type had some non-pack parameters, but the argument list was a single pack expansion type, the match would succeed, grouping all of the generic parameters into a single match. This is non-sensical, so we need to explicitly check for this case and diagnose it. This requires a new diagnostic, since otherwise the general diagnostic we emit for variadic generic type mismatches doesn't make sense, since it's complaining about there being too few generic parameters. Fixes rdar://116713961 / #69012.
1 parent 9c7df7a commit 575a29c

File tree

6 files changed

+98
-27
lines changed

6 files changed

+98
-27
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4373,10 +4373,21 @@ ERROR(cannot_specialize_self,none,
43734373
"cannot specialize 'Self'", ())
43744374
NOTE(specialize_explicit_type_instead,none,
43754375
"did you mean to explicitly reference %0 instead?", (Type))
4376-
ERROR(type_parameter_count_mismatch,none,
4377-
"generic type %0 specialized with %select{too many|too few}3 type "
4378-
"parameters (got %2, but expected %select{%1|at least %1}4)",
4379-
(Identifier, unsigned, unsigned, bool, bool))
4376+
ERROR(too_few_generic_arguments,none,
4377+
"generic type %0 specialized with too few type parameters "
4378+
"(got %1, but expected %2)",
4379+
(Identifier, unsigned, unsigned))
4380+
ERROR(too_few_generic_arguments_pack,none,
4381+
"generic type %0 specialized with too few type parameters "
4382+
"(got %1, but expected at least %2)",
4383+
(Identifier, unsigned, unsigned))
4384+
ERROR(too_many_generic_arguments,none,
4385+
"generic type %0 specialized with too many type parameters "
4386+
"(got %1, but expected %2)",
4387+
(Identifier, unsigned, unsigned))
4388+
ERROR(generic_argument_pack_mismatch,none,
4389+
"generic type %0 specialized with mismatched type parameter pack",
4390+
(Identifier))
43804391
ERROR(generic_type_requires_arguments,none,
43814392
"reference to generic type %0 requires arguments in <...>", (Type))
43824393
NOTE(descriptive_generic_type_declared_here,none,

lib/Sema/CSDiagnostics.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "CSDiagnostics.h"
1818
#include "MiscDiagnostics.h"
1919
#include "TypeCheckProtocol.h"
20+
#include "TypeCheckType.h"
2021
#include "TypoCorrection.h"
2122
#include "swift/AST/ASTContext.h"
2223
#include "swift/AST/ASTPrinter.h"
@@ -9173,7 +9174,9 @@ bool OutOfPlaceThenStmtFailure::diagnoseAsError() {
91739174
}
91749175

91759176
bool InvalidTypeSpecializationArity::diagnoseAsError() {
9176-
emitDiagnostic(diag::type_parameter_count_mismatch, D->getBaseIdentifier(),
9177-
NumParams, NumArgs, NumArgs < NumParams, HasParameterPack);
9177+
diagnoseInvalidGenericArguments(getLoc(), D,
9178+
NumArgs, NumParams,
9179+
HasParameterPack,
9180+
/*generic=*/nullptr);
91789181
return true;
91799182
}

lib/Sema/TypeCheckType.cpp

Lines changed: 54 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include "swift/AST/SourceFile.h"
3939
#include "swift/AST/TypeCheckRequests.h"
4040
#include "swift/AST/TypeLoc.h"
41+
#include "swift/AST/TypeRepr.h"
4142
#include "swift/AST/TypeResolutionStage.h"
4243
#include "swift/Basic/SourceManager.h"
4344
#include "swift/Basic/Statistic.h"
@@ -667,6 +668,51 @@ bool TypeChecker::checkContextualRequirements(GenericTypeDecl *decl,
667668
llvm_unreachable("invalid requirement check type");
668669
}
669670

671+
void swift::diagnoseInvalidGenericArguments(SourceLoc loc,
672+
ValueDecl *decl,
673+
unsigned argCount,
674+
unsigned paramCount,
675+
bool hasParameterPack,
676+
GenericIdentTypeRepr *generic) {
677+
auto &ctx = decl->getASTContext();
678+
auto &diags = ctx.Diags;
679+
680+
if (!hasParameterPack) {
681+
// For generic types without type parameter packs, we require
682+
// the number of declared generic parameters match the number of
683+
// arguments.
684+
if (argCount < paramCount) {
685+
auto diag = diags
686+
.diagnose(loc, diag::too_few_generic_arguments, decl->getBaseIdentifier(),
687+
argCount, paramCount);
688+
if (generic)
689+
diag.highlight(generic->getAngleBrackets());
690+
} else {
691+
auto diag = diags
692+
.diagnose(loc, diag::too_many_generic_arguments, decl->getBaseIdentifier(),
693+
argCount, paramCount);
694+
if (generic)
695+
diag.highlight(generic->getAngleBrackets());
696+
}
697+
} else {
698+
if (argCount < paramCount - 1) {
699+
auto diag = diags
700+
.diagnose(loc, diag::too_few_generic_arguments_pack, decl->getBaseIdentifier(),
701+
argCount, paramCount - 1);
702+
if (generic)
703+
diag.highlight(generic->getAngleBrackets());
704+
} else {
705+
auto diag = diags
706+
.diagnose(loc, diag::generic_argument_pack_mismatch, decl->getBaseIdentifier());
707+
if (generic)
708+
diag.highlight(generic->getAngleBrackets());
709+
}
710+
}
711+
712+
decl->diagnose(diag::kind_declname_declared_here,
713+
DescriptiveDeclKind::GenericType, decl->getName());
714+
}
715+
670716
/// Apply generic arguments to the given type.
671717
///
672718
/// If the type is itself not generic, this does nothing.
@@ -851,7 +897,6 @@ static Type applyGenericArguments(Type type, TypeResolution resolution,
851897
return paramDecl->isParameterPack();
852898
});
853899

854-
// Resolve the types of the generic arguments.
855900
auto argOptions = options.withoutContext().withContext(
856901
TypeResolverContext::GenericArgument);
857902
auto genericResolution = resolution.withOptions(argOptions);
@@ -865,6 +910,7 @@ static Type applyGenericArguments(Type type, TypeResolution resolution,
865910
}
866911
}
867912

913+
// Resolve the types of the generic arguments.
868914
SmallVector<Type, 2> args;
869915
for (auto tyR : genericArgs) {
870916
// Propagate failure.
@@ -881,15 +927,9 @@ static Type applyGenericArguments(Type type, TypeResolution resolution,
881927
// arguments.
882928
if (genericArgs.size() != genericParams->size()) {
883929
if (!options.contains(TypeResolutionFlags::SilenceErrors)) {
884-
diags
885-
.diagnose(loc, diag::type_parameter_count_mismatch, decl->getName(),
886-
genericParams->size(),
887-
genericArgs.size(),
888-
genericArgs.size() < genericParams->size(),
889-
/*hasParameterPack=*/0)
890-
.highlight(generic->getAngleBrackets());
891-
decl->diagnose(diag::kind_declname_declared_here,
892-
DescriptiveDeclKind::GenericType, decl->getName());
930+
diagnoseInvalidGenericArguments(
931+
loc, decl, genericArgs.size(), genericParams->size(),
932+
/*hasParameterPack=*/false, generic);
893933
}
894934
return ErrorType::get(ctx);
895935
}
@@ -907,17 +947,11 @@ static Type applyGenericArguments(Type type, TypeResolution resolution,
907947
}
908948

909949
PackMatcher matcher(params, args, ctx);
910-
if (matcher.match()) {
950+
if (matcher.match() || matcher.pairs.size() != params.size()) {
911951
if (!options.contains(TypeResolutionFlags::SilenceErrors)) {
912-
diags
913-
.diagnose(loc, diag::type_parameter_count_mismatch, decl->getName(),
914-
genericParams->size() - 1,
915-
genericArgs.size(),
916-
genericArgs.size() < genericParams->size(),
917-
/*hasParameterPack=*/1)
918-
.highlight(generic->getAngleBrackets());
919-
decl->diagnose(diag::kind_declname_declared_here,
920-
DescriptiveDeclKind::GenericType, decl->getName());
952+
diagnoseInvalidGenericArguments(
953+
loc, decl, genericArgs.size(), genericParams->size(),
954+
/*hasParameterPack=*/true, generic);
921955
}
922956
return ErrorType::get(ctx);
923957
}

lib/Sema/TypeCheckType.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ class PackElementTypeRepr;
3131
class GenericEnvironment;
3232
class GenericSignature;
3333
class SILTypeResolutionContext;
34+
class GenericIdentTypeRepr;
3435

3536
/// Flags that describe the context of type checking a pattern or
3637
/// type.
@@ -655,6 +656,13 @@ class TypeResolution {
655656
ArrayRef<Type> genericArgs) const;
656657
};
657658

659+
void diagnoseInvalidGenericArguments(SourceLoc loc,
660+
ValueDecl *decl,
661+
unsigned argCount,
662+
unsigned paramCount,
663+
bool hasParameterPack,
664+
GenericIdentTypeRepr *generic);
665+
658666
} // end namespace swift
659667

660668
#endif /* SWIFT_SEMA_TYPE_CHECK_TYPE_H */

test/Generics/variadic_generic_types.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,3 +96,18 @@ func bindAliasPrefixAndSuffix() {
9696
typealias Three = Bind<Int, String, Float> // OK
9797
typealias Four = Bind<Int, String, Float, Bool> // OK
9898
}
99+
100+
func invalidPackExpansion<each X, each Y, Z>(x: repeat each X, y: repeat each Y, z: Z) {
101+
typealias A<T, each U> = (T, repeat each U) // expected-note 4{{generic type 'A' declared here}}
102+
typealias B<each T, U> = (repeat each T, U) // expected-note 4{{generic type 'B' declared here}}
103+
104+
typealias One = A<repeat each X> // expected-error {{generic type 'A' specialized with mismatched type parameter pack}}
105+
typealias Two = A<repeat each X, repeat each Y> // expected-error {{generic type 'A' specialized with mismatched type parameter pack}}
106+
typealias Three = A<repeat each X, Z> // expected-error {{generic type 'A' specialized with mismatched type parameter pack}}
107+
typealias Four = A<repeat each X, repeat each Y, Z> // expected-error {{generic type 'A' specialized with mismatched type parameter pack}}
108+
109+
typealias Five = B<repeat each X> // expected-error {{generic type 'B' specialized with mismatched type parameter pack}}
110+
typealias Six = B<repeat each X, repeat each Y> // expected-error {{generic type 'B' specialized with mismatched type parameter pack}}
111+
typealias Seven = B<Z, repeat each X> // expected-error {{generic type 'B' specialized with mismatched type parameter pack}}
112+
typealias Eight = B<Z, repeat each X, repeat each Y> // expected-error {{generic type 'B' specialized with mismatched type parameter pack}}
113+
}

test/Macros/macros_diagnostics.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
// RUN: %target-typecheck-verify-swift -swift-version 5 -enable-experimental-feature CodeItemMacros -module-name MacrosTest
44

55
@expression macro stringify<T>(_ value: T) -> (T, String) = #externalMacro(module: "MacroDefinition", type: "StringifyMacro")
6-
// expected-note@-1 2{{'stringify' declared here}}
6+
// expected-note@-1 3{{'stringify' declared here}}
77
// expected-warning@-2{{external macro implementation type}}
88
// expected-warning@-3{{@expression has been removed in favor of @freestanding(expression)}}{{1-12=@freestanding(expression)}}
99
@freestanding(expression) macro missingMacro1(_: Any) = MissingModule.MissingType // expected-note{{'missingMacro1' declared here}}

0 commit comments

Comments
 (0)