Skip to content

Commit 67308e6

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 b013e11 commit 67308e6

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
@@ -4411,10 +4411,21 @@ ERROR(cannot_specialize_self,none,
44114411
"cannot specialize 'Self'", ())
44124412
NOTE(specialize_explicit_type_instead,none,
44134413
"did you mean to explicitly reference %0 instead?", (Type))
4414-
ERROR(type_parameter_count_mismatch,none,
4415-
"generic type %0 specialized with %select{too many|too few}3 type "
4416-
"parameters (got %2, but expected %select{%1|at least %1}4)",
4417-
(Identifier, unsigned, unsigned, bool, bool))
4414+
ERROR(too_few_generic_arguments,none,
4415+
"generic type %0 specialized with too few type parameters "
4416+
"(got %1, but expected %2)",
4417+
(Identifier, unsigned, unsigned))
4418+
ERROR(too_few_generic_arguments_pack,none,
4419+
"generic type %0 specialized with too few type parameters "
4420+
"(got %1, but expected at least %2)",
4421+
(Identifier, unsigned, unsigned))
4422+
ERROR(too_many_generic_arguments,none,
4423+
"generic type %0 specialized with too many type parameters "
4424+
"(got %1, but expected %2)",
4425+
(Identifier, unsigned, unsigned))
4426+
ERROR(generic_argument_pack_mismatch,none,
4427+
"generic type %0 specialized with mismatched type parameter pack",
4428+
(Identifier))
44184429
ERROR(generic_type_requires_arguments,none,
44194430
"reference to generic type %0 requires arguments in <...>", (Type))
44204431
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"
@@ -9306,7 +9307,9 @@ bool OutOfPlaceThenStmtFailure::diagnoseAsError() {
93069307
}
93079308

93089309
bool InvalidTypeSpecializationArity::diagnoseAsError() {
9309-
emitDiagnostic(diag::type_parameter_count_mismatch, D->getBaseIdentifier(),
9310-
NumParams, NumArgs, NumArgs < NumParams, HasParameterPack);
9310+
diagnoseInvalidGenericArguments(getLoc(), D,
9311+
NumArgs, NumParams,
9312+
HasParameterPack,
9313+
/*generic=*/nullptr);
93119314
return true;
93129315
}

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.
@@ -834,7 +880,6 @@ static Type applyGenericArguments(Type type, TypeResolution resolution,
834880
return paramDecl->isParameterPack();
835881
});
836882

837-
// Resolve the types of the generic arguments.
838883
auto argOptions = options.withoutContext().withContext(
839884
TypeResolverContext::GenericArgument);
840885
auto genericResolution = resolution.withOptions(argOptions);
@@ -848,6 +893,7 @@ static Type applyGenericArguments(Type type, TypeResolution resolution,
848893
}
849894
}
850895

896+
// Resolve the types of the generic arguments.
851897
SmallVector<Type, 2> args;
852898
for (auto tyR : genericArgs) {
853899
// Propagate failure.
@@ -864,15 +910,9 @@ static Type applyGenericArguments(Type type, TypeResolution resolution,
864910
// arguments.
865911
if (genericArgs.size() != genericParams->size()) {
866912
if (!options.contains(TypeResolutionFlags::SilenceErrors)) {
867-
diags
868-
.diagnose(loc, diag::type_parameter_count_mismatch, decl->getName(),
869-
genericParams->size(),
870-
genericArgs.size(),
871-
genericArgs.size() < genericParams->size(),
872-
/*hasParameterPack=*/0)
873-
.highlight(generic->getAngleBrackets());
874-
decl->diagnose(diag::kind_declname_declared_here,
875-
DescriptiveDeclKind::GenericType, decl->getName());
913+
diagnoseInvalidGenericArguments(
914+
loc, decl, genericArgs.size(), genericParams->size(),
915+
/*hasParameterPack=*/false, generic);
876916
}
877917
return ErrorType::get(ctx);
878918
}
@@ -890,17 +930,11 @@ static Type applyGenericArguments(Type type, TypeResolution resolution,
890930
}
891931

892932
PackMatcher matcher(params, args, ctx);
893-
if (matcher.match()) {
933+
if (matcher.match() || matcher.pairs.size() != params.size()) {
894934
if (!options.contains(TypeResolutionFlags::SilenceErrors)) {
895-
diags
896-
.diagnose(loc, diag::type_parameter_count_mismatch, decl->getName(),
897-
genericParams->size() - 1,
898-
genericArgs.size(),
899-
genericArgs.size() < genericParams->size(),
900-
/*hasParameterPack=*/1)
901-
.highlight(generic->getAngleBrackets());
902-
decl->diagnose(diag::kind_declname_declared_here,
903-
DescriptiveDeclKind::GenericType, decl->getName());
935+
diagnoseInvalidGenericArguments(
936+
loc, decl, genericArgs.size(), genericParams->size(),
937+
/*hasParameterPack=*/true, generic);
904938
}
905939
return ErrorType::get(ctx);
906940
}

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)