Skip to content

Commit 9c6acbe

Browse files
committed
Implement Generic Argument Binding for Variadic Types
The algorithm is detailed below: Suppose we encounter a type T<..., U, V..., W, ...> for V... the _sole_ variadic generic parameter. When we encounter an argument list <A, B, C, D, E, F, ...> to T, we must work in three steps - Bind all generic parameters up to U in parallel with the argument list until we encounter V... - Measure the tail of parameters after V... and call it `t`. Assuming `m` type variables hav been bound already, we must bind `n - t - m` type arguments to V... - Finally, bind the remaining `t` arguments. This procedure is often called "Saturation" in the literature. Variadic generics have a special saturation property where unlike normal generic parameters it is possible to bind zero arguments to them. In such a case, the result is an empty pack type, which is semantically well-formed.
1 parent ab47063 commit 9c6acbe

File tree

4 files changed

+148
-23
lines changed

4 files changed

+148
-23
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3700,8 +3700,8 @@ NOTE(specialize_explicit_type_instead,none,
37003700
"did you mean to explicitly reference %0 instead?", (Type))
37013701
ERROR(type_parameter_count_mismatch,none,
37023702
"generic type %0 specialized with %select{too many|too few}3 type "
3703-
"parameters (got %2, but expected %1)",
3704-
(Identifier, unsigned, unsigned, bool))
3703+
"parameters (got %2, but expected %select{%1|at least %1}4)",
3704+
(Identifier, unsigned, unsigned, bool, bool))
37053705
ERROR(generic_type_requires_arguments,none,
37063706
"reference to generic type %0 requires arguments in <...>", (Type))
37073707
NOTE(descriptive_generic_type_declared_here,none,
@@ -4813,6 +4813,8 @@ ERROR(tuple_single_element,none,
48134813
"cannot create a single-element tuple with an element label", ())
48144814
ERROR(tuple_ellipsis,none,
48154815
"cannot create a variadic tuple", ())
4816+
ERROR(expansion_not_variadic,none,
4817+
"cannot create expansion with non-variadic type %0", (Type))
48164818
ERROR(tuple_duplicate_label,none,
48174819
"cannot create a tuple with a duplicate element label", ())
48184820
ERROR(enum_element_ellipsis,none,

lib/Sema/CSGen.cpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1605,11 +1605,12 @@ namespace {
16051605
if (specializations.size() > typeVars.size()) {
16061606
de.diagnose(expr->getSubExpr()->getLoc(),
16071607
diag::type_parameter_count_mismatch,
1608-
bgt->getDecl()->getName(),
1609-
typeVars.size(), specializations.size(),
1610-
false)
1611-
.highlight(SourceRange(expr->getLAngleLoc(),
1612-
expr->getRAngleLoc()));
1608+
bgt->getDecl()->getName(), typeVars.size(),
1609+
specializations.size(),
1610+
/*too many arguments*/ false,
1611+
/*type sequence?*/ false)
1612+
.highlight(
1613+
SourceRange(expr->getLAngleLoc(), expr->getRAngleLoc()));
16131614
de.diagnose(bgt->getDecl(), diag::kind_declname_declared_here,
16141615
DescriptiveDeclKind::GenericType,
16151616
bgt->getDecl()->getName());
@@ -2779,7 +2780,7 @@ namespace {
27792780

27802781
CS.addConstraint(ConstraintKind::ApplicableFunction,
27812782
FunctionType::get(params, resultType, extInfo),
2782-
CS.getType(expr->getFn()),
2783+
CS.getType(fnExpr),
27832784
CS.getConstraintLocator(expr, ConstraintLocator::ApplyFunction));
27842785

27852786
// If we ended up resolving the result type variable to a concrete type,

lib/Sema/TypeCheckType.cpp

Lines changed: 94 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -623,15 +623,41 @@ static Type applyGenericArguments(Type type, TypeResolution resolution,
623623
auto *decl = unboundType->getDecl();
624624

625625
// Make sure we have the right number of generic arguments.
626+
//
627+
// For generic types without type sequence parameters, we require
628+
// the number of declared generic parameters match the number of
629+
// arguments.
630+
//
631+
// For generic types with type sequence parameters, we only require
632+
// that the number of arguments is enough to saturate the number of
633+
// regular generic parameters. The type sequence parameter will absorb
634+
// any excess parameters, or will have a substitution of `Void` if there
635+
// is nothing to bind. This Void-binding behavior of type sequences
636+
// also explains the offset of one that isn't otherwise present in
637+
// the plain generic parameter case.
638+
//
639+
// struct Foo<Prefix, T..., Suffix> {}
640+
// typealias X = Foo<String, Int, Float, Double> // Prefix -> String, Suffix
641+
// -> Double, T... -> (Int, Float) typealias X = Foo<String, Int> // Prefix ->
642+
// String, Suffix -> Int, T... -> Void typealias Y = Foo<String> // error: Not
643+
// enough arguments to bind Suffix.
644+
//
626645
// FIXME: If we have fewer arguments than we need, that might be okay, if
627-
// we're allowed to deduce the remaining arguments from context.
646+
// we're allowed to deduce the remaining arguments from context. The
647+
// expression checker certainly only cares about the case where too many
648+
// arguments are given.
628649
auto genericArgs = generic->getGenericArgs();
629650
auto genericParams = decl->getGenericParams();
630-
if (genericParams->size() != genericArgs.size()) {
651+
auto hasTypeSequence = llvm::any_of(
652+
*genericParams, [](const auto *GPT) { return GPT->isTypeSequence(); });
653+
if ((!hasTypeSequence && genericArgs.size() != genericParams->size()) ||
654+
(hasTypeSequence && genericArgs.size() < genericParams->size() - 1)) {
631655
if (!options.contains(TypeResolutionFlags::SilenceErrors)) {
632-
diags.diagnose(loc, diag::type_parameter_count_mismatch, decl->getName(),
633-
genericParams->size(), genericArgs.size(),
634-
genericArgs.size() < genericParams->size())
656+
diags
657+
.diagnose(loc, diag::type_parameter_count_mismatch, decl->getName(),
658+
genericParams->size() - (hasTypeSequence ? 1 : 0),
659+
genericArgs.size(),
660+
genericArgs.size() < genericParams->size(), hasTypeSequence)
635661
.highlight(generic->getAngleBrackets());
636662
decl->diagnose(diag::kind_declname_declared_here,
637663
DescriptiveDeclKind::GenericType, decl->getName());
@@ -728,8 +754,15 @@ static Type applyGenericArguments(Type type, TypeResolution resolution,
728754
Type TypeResolution::applyUnboundGenericArguments(
729755
GenericTypeDecl *decl, Type parentTy, SourceLoc loc,
730756
ArrayRef<Type> genericArgs) const {
731-
assert(genericArgs.size() == decl->getGenericParams()->size() &&
732-
"invalid arguments, use applyGenericArguments for diagnostic emitting");
757+
const bool hasTypeSequence =
758+
llvm::any_of(*decl->getGenericParams(),
759+
[](const auto *GPT) { return GPT->isTypeSequence(); });
760+
assert(
761+
((!hasTypeSequence &&
762+
genericArgs.size() == decl->getGenericParams()->size()) ||
763+
(hasTypeSequence &&
764+
genericArgs.size() >= decl->getGenericParams()->size() - 1)) &&
765+
"invalid arguments, use applyGenericArguments for diagnostic emitting");
733766

734767
auto genericSig = decl->getGenericSignature();
735768
assert(!genericSig.isNull());
@@ -777,16 +810,62 @@ Type TypeResolution::applyUnboundGenericArguments(
777810

778811
// Realize the types of the generic arguments and add them to the
779812
// substitution map.
780-
for (const unsigned i : indices(genericArgs)) {
781-
auto origTy = genericSig.getInnermostGenericParams()[i];
782-
auto substTy = genericArgs[i];
813+
auto innerParams = genericSig.getInnermostGenericParams();
814+
for (unsigned i = 0; i < innerParams.size(); ++i) {
815+
auto origTy = innerParams[i];
816+
auto origGP = origTy->getCanonicalType()->castTo<GenericTypeParamType>();
817+
818+
if (!origGP->isTypeSequence()) {
819+
auto substTy = genericArgs[i];
820+
821+
// Enter a substitution.
822+
subs[origGP] = substTy;
823+
824+
skipRequirementsCheck |=
825+
substTy->hasTypeVariable() || substTy->hasUnboundGenericType();
826+
827+
continue;
828+
}
783829

784-
// Enter a substitution.
785-
subs[origTy->getCanonicalType()->castTo<GenericTypeParamType>()] =
786-
substTy;
830+
// Scan backwards to find the bounds of the longest run of
831+
// types we can bind to this type sequence parameter.
832+
unsigned tail;
833+
for (tail = 1; tail <= innerParams.size(); ++tail) {
834+
auto tailTy = innerParams[innerParams.size() - tail];
835+
auto tailGP = tailTy->getCanonicalType()->castTo<GenericTypeParamType>();
836+
if (tailGP->isTypeSequence()) {
837+
assert(tailGP->isEqual(origGP) &&
838+
"Found multiple type sequence parameters!");
787839

788-
skipRequirementsCheck |=
789-
substTy->hasTypeVariable() || substTy->hasUnboundGenericType();
840+
// Saturate the type sequence. Take care that if the prefix and suffix
841+
// have bound all available arguments that we bind the type sequence
842+
// parameter to `Void`.
843+
const size_t sequenceLength = tail + i <= genericArgs.size()
844+
? genericArgs.size() - tail - i + 1
845+
: 0;
846+
847+
auto substTy = PackType::get(getASTContext(),
848+
genericArgs.slice(i, sequenceLength));
849+
850+
// Enter a substitution.
851+
subs[origGP] = substTy;
852+
853+
skipRequirementsCheck |=
854+
substTy->hasTypeVariable() || substTy->hasUnboundGenericType();
855+
856+
break;
857+
}
858+
859+
auto substTy = genericArgs[genericArgs.size() - tail];
860+
861+
// Enter a substitution.
862+
subs[tailGP] = substTy;
863+
864+
skipRequirementsCheck |=
865+
substTy->hasTypeVariable() || substTy->hasUnboundGenericType();
866+
}
867+
868+
break;
790869
}
791870

792871
// Check the generic arguments against the requirements of the declaration's

test/Constraints/type_sequence.swift

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,46 @@ func min<@_typeSequence T: Comparable>(_ values: T...) -> T? {
2525

2626
func badParameter<T>(_ : @_typeSequence T) {} // expected-error {{attribute does not apply to type}}
2727

28+
func directAliases() {
29+
typealias Tuple<@_typeSequence Ts> = (Ts...)
30+
31+
typealias Many<T, U, V, @_typeSequence Ws> = Tuple<T, U, V, Ws>
32+
33+
let _: Many<Int, String, Double, Void, Void, Void, Void> = 42 // expected-error {{cannot convert value of type 'Int' to specified type}}
34+
}
35+
36+
func bindPrefix() {
37+
struct Bind<Prefix, @_typeSequence U> {}
38+
39+
typealias TooFew0 = Bind<> // expected-error {{expected type}}
40+
typealias TooFew1 = Bind<String> // OK
41+
typealias TooFew2 = Bind<String, String> // OK
42+
typealias JustRight = Bind<String, String, String> // OK
43+
typealias Oversaturated = Bind<String, String, String, String, String, String, String, String> // OK
44+
}
45+
46+
func bindSuffix() {
47+
struct Bind<@_typeSequence U, Suffix> {}
48+
49+
typealias TooFew0 = Bind<> // expected-error {{expected type}}
50+
typealias TooFew1 = Bind<String> // OK
51+
typealias TooFew2 = Bind<String, String> // OK
52+
typealias JustRight = Bind<String, String, String> // OK
53+
typealias Oversaturated = Bind<String, String, String, String, String, String, String, String> // OK
54+
}
55+
56+
func bindPrefixAndSuffix() {
57+
struct Bind<Prefix, @_typeSequence U, Suffix> {} // expected-note {{generic type 'Bind' declared here}}
58+
59+
typealias TooFew0 = Bind<> // expected-error {{expected type}}
60+
typealias TooFew1 = Bind<String> // expected-error {{generic type 'Bind' specialized with too few type parameters (got 1, but expected at least 2)}}
61+
typealias TooFew2 = Bind<String, String> // OK
62+
typealias JustRight = Bind<String, String, String> // OK
63+
typealias Oversaturated = Bind<String, String, String, String, String, String, String, String> // OK
64+
}
65+
66+
func invalidPacks() {
67+
func monovariadic1() -> (String...) {} // expected-error {{cannot create expansion with non-variadic type 'String'}}
68+
func monovariadic2<T>() -> (T...) {} // expected-error 2 {{cannot create expansion with non-variadic type 'T'}}
69+
func monovariadic3<T, U>() -> (T, U...) {} // expected-error {{cannot create a variadic tuple}}
70+
}

0 commit comments

Comments
 (0)