Skip to content

Commit d5cdfb2

Browse files
committed
AST: Clone generic parameter list of tuple extension from extended typealias
1 parent fd06bd8 commit d5cdfb2

File tree

9 files changed

+104
-45
lines changed

9 files changed

+104
-45
lines changed

include/swift/AST/Decl.h

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5178,21 +5178,19 @@ class ProtocolDecl final : public NominalTypeDecl {
51785178
/// and conformances for tuple types.
51795179
///
51805180
/// - The declared interface type is the special TheTupleType singleton.
5181-
/// - The generic parameter list has one pack generic parameter, <Elements...>
5182-
/// - The generic signature has no requirements, <Elements...>
5181+
/// - The generic parameter list has one pack generic parameter, <each Element>
5182+
/// - The generic signature has no requirements, <each Element>
51835183
/// - The self interface type is the tuple type containing a single pack
5184-
/// expansion, (Elements...).
5184+
/// expansion, (repeat each Element).
51855185
class BuiltinTupleDecl final : public NominalTypeDecl {
5186-
TupleType *TupleSelfType = nullptr;
5187-
51885186
public:
51895187
BuiltinTupleDecl(Identifier Name, DeclContext *Parent);
51905188

51915189
SourceRange getSourceRange() const {
51925190
return SourceRange();
51935191
}
51945192

5195-
TupleType *getTupleSelfType() const;
5193+
TupleType *getTupleSelfType(const ExtensionDecl *owner) const;
51965194

51975195
// Implement isa/cast/dyncast/etc.
51985196
static bool classof(const Decl *D) {

include/swift/AST/DiagnosticsSema.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2353,6 +2353,8 @@ ERROR(extension_access_with_conformances,none,
23532353
ERROR(experimental_tuple_extension,none,
23542354
"tuple extensions are experimental",
23552355
())
2356+
ERROR(tuple_extension_wrong_type,none,
2357+
"tuple extension must be written as extension of %0", (Type))
23562358
ERROR(extension_metatype,none,
23572359
"cannot extend a metatype %0", (Type))
23582360
ERROR(extension_placeholder,none,

lib/AST/Decl.cpp

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7861,27 +7861,24 @@ Type DeclContext::getSelfTypeInContext() const {
78617861
return mapTypeIntoContext(getSelfInterfaceType());
78627862
}
78637863

7864-
TupleType *BuiltinTupleDecl::getTupleSelfType() const {
7865-
if (TupleSelfType)
7866-
return TupleSelfType;
7867-
7864+
TupleType *BuiltinTupleDecl::getTupleSelfType(const ExtensionDecl *owner) const {
78687865
auto &ctx = getASTContext();
78697866

7870-
// Get the generic parameter type 'Elements'.
7871-
auto paramType = getGenericParams()->getParams()[0]
7872-
->getDeclaredInterfaceType();
7867+
// Get the generic parameter type 'each T'.
7868+
auto *genericParams = owner->getGenericParams();
7869+
assert(genericParams != nullptr);
7870+
assert(genericParams->getParams().size() == 1);
7871+
assert(genericParams->getOuterParameters() == nullptr);
7872+
auto paramType = genericParams->getParams()[0]->getDeclaredInterfaceType();
78737873

7874-
// Build the pack expansion type 'Elements...'.
7874+
// Build the pack expansion type 'repeat each T'.
78757875
Type packExpansionType = PackExpansionType::get(paramType, paramType);
78767876

7877-
// Build the one-element tuple type '(Elements...)'.
7877+
// Build the one-element tuple type '(repeat each T)'.
78787878
SmallVector<TupleTypeElt, 1> elts;
78797879
elts.push_back(packExpansionType);
78807880

7881-
const_cast<BuiltinTupleDecl *>(this)->TupleSelfType =
7882-
TupleType::get(elts, ctx);
7883-
7884-
return TupleSelfType;
7881+
return TupleType::get(elts, ctx);
78857882
}
78867883

78877884
/// Retrieve the interface type of 'self' for the given context.
@@ -7890,7 +7887,7 @@ Type DeclContext::getSelfInterfaceType() const {
78907887

78917888
if (auto *nominalDecl = getSelfNominalTypeDecl()) {
78927889
if (auto *builtinTupleDecl = dyn_cast<BuiltinTupleDecl>(nominalDecl))
7893-
return builtinTupleDecl->getTupleSelfType();
7890+
return builtinTupleDecl->getTupleSelfType(cast<ExtensionDecl>(this));
78947891

78957892
if (isa<ProtocolDecl>(nominalDecl)) {
78967893
auto *genericParams = nominalDecl->getGenericParams();

lib/AST/NameLookup.cpp

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3279,10 +3279,10 @@ bool TypeRepr::isProtocolOrProtocolComposition(DeclContext *dc){
32793279
static GenericParamList *
32803280
createExtensionGenericParams(ASTContext &ctx,
32813281
ExtensionDecl *ext,
3282-
NominalTypeDecl *nominal) {
3282+
DeclContext *source) {
32833283
// Collect generic parameters from all outer contexts.
32843284
SmallVector<GenericParamList *, 2> allGenericParams;
3285-
nominal->forEachGenericContext([&](GenericParamList *gpList) {
3285+
source->forEachGenericContext([&](GenericParamList *gpList) {
32863286
allGenericParams.push_back(gpList->clone(ext));
32873287
});
32883288

@@ -3295,6 +3295,28 @@ createExtensionGenericParams(ASTContext &ctx,
32953295
return toParams;
32963296
}
32973297

3298+
/// If the extended type is a generic typealias whose underlying type is
3299+
/// a tuple, the extension inherits the generic paramter list from the
3300+
/// typealias.
3301+
static GenericParamList *
3302+
createTupleExtensionGenericParams(ASTContext &ctx,
3303+
ExtensionDecl *ext,
3304+
TypeRepr *extendedTypeRepr) {
3305+
DirectlyReferencedTypeDecls referenced =
3306+
directReferencesForTypeRepr(ctx.evaluator, ctx,
3307+
extendedTypeRepr,
3308+
ext->getParent());
3309+
3310+
if (referenced.size() != 1 || !isa<TypeAliasDecl>(referenced[0]))
3311+
return nullptr;
3312+
3313+
auto *typeAlias = cast<TypeAliasDecl>(referenced[0]);
3314+
if (!typeAlias->isGeneric())
3315+
return nullptr;
3316+
3317+
return createExtensionGenericParams(ctx, ext, typeAlias);
3318+
}
3319+
32983320
CollectedOpaqueReprs swift::collectOpaqueTypeReprs(TypeRepr *r, ASTContext &ctx,
32993321
DeclContext *d) {
33003322
class Walker : public ASTWalker {
@@ -3416,9 +3438,9 @@ GenericParamListRequest::evaluate(Evaluator &evaluator, GenericContext *value) c
34163438
if (auto *tupleDecl = dyn_cast<BuiltinTupleDecl>(value)) {
34173439
auto &ctx = value->getASTContext();
34183440

3419-
// Builtin.TheTupleType has a single pack generic parameter: <Elements...>
3441+
// Builtin.TheTupleType has a single pack generic parameter: <each Element>
34203442
auto *genericParam = GenericTypeParamDecl::createImplicit(
3421-
tupleDecl->getDeclContext(), ctx.Id_Elements, /*depth*/ 0, /*index*/ 0,
3443+
tupleDecl->getDeclContext(), ctx.Id_Element, /*depth*/ 0, /*index*/ 0,
34223444
/*isParameterPack*/ true);
34233445

34243446
return GenericParamList::create(ctx, SourceLoc(), genericParam,
@@ -3433,6 +3455,21 @@ GenericParamListRequest::evaluate(Evaluator &evaluator, GenericContext *value) c
34333455
if (!nominal) {
34343456
return nullptr;
34353457
}
3458+
3459+
// For a tuple extension, the generic parameter list comes from the
3460+
// extended type alias.
3461+
if (isa<BuiltinTupleDecl>(nominal)) {
3462+
if (auto *extendedTypeRepr = ext->getExtendedTypeRepr()) {
3463+
auto *genericParams = createTupleExtensionGenericParams(
3464+
ctx, ext, extendedTypeRepr);
3465+
if (genericParams)
3466+
return genericParams;
3467+
3468+
// Otherwise, just clone the generic parameter list of the
3469+
// Builtin.TheTupleType. We'll diagnose later.
3470+
}
3471+
}
3472+
34363473
auto *genericParams = createExtensionGenericParams(ctx, ext, nominal);
34373474

34383475
// Protocol extensions need an inheritance clause due to how name lookup

lib/Sema/TypeCheckDecl.cpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2979,21 +2979,24 @@ ExtendedTypeRequest::evaluate(Evaluator &eval, ExtensionDecl *ext) const {
29792979
PlaceholderType::get,
29802980
/*packElementOpener*/ nullptr);
29812981

2982-
const auto extendedType = resolution.resolveType(extendedRepr);
2982+
auto extendedType = resolution.resolveType(extendedRepr);
29832983

29842984
if (extendedType->hasError())
29852985
return error();
29862986

29872987
// Hack to allow extending a generic typealias.
29882988
if (auto *unboundGeneric = extendedType->getAs<UnboundGenericType>()) {
29892989
if (auto *aliasDecl = dyn_cast<TypeAliasDecl>(unboundGeneric->getDecl())) {
2990-
auto extendedNominal =
2991-
aliasDecl->getUnderlyingType()->getAnyNominal();
2992-
if (extendedNominal)
2990+
auto underlyingType = aliasDecl->getUnderlyingType();
2991+
if (auto extendedNominal = underlyingType->getAnyNominal()) {
29932992
return TypeChecker::isPassThroughTypealias(
29942993
aliasDecl, extendedNominal)
29952994
? extendedType
29962995
: extendedNominal->getDeclaredType();
2996+
}
2997+
2998+
if (underlyingType->is<TupleType>())
2999+
extendedType = underlyingType;
29973000
}
29983001
}
29993002

@@ -3006,8 +3009,9 @@ ExtendedTypeRequest::evaluate(Evaluator &eval, ExtensionDecl *ext) const {
30063009
return error();
30073010
}
30083011

3009-
// Cannot extend function types, tuple types, etc.
3010-
if (!extendedType->getAnyNominal() &&
3012+
// Cannot extend function types, metatypes, existentials, etc.
3013+
if (!extendedType->is<TupleType>() &&
3014+
!extendedType->getAnyNominal() &&
30113015
!extendedType->is<ParameterizedProtocolType>()) {
30123016
diags.diagnose(ext->getLoc(), diag::non_nominal_extension, extendedType)
30133017
.highlight(extendedRepr->getSourceRange());

lib/Sema/TypeCheckDeclPrimary.cpp

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3493,9 +3493,17 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
34933493
auto *nominal = ED->getExtendedNominal();
34943494

34953495
// Diagnose experimental tuple extensions.
3496-
if (nominal && isa<BuiltinTupleDecl>(nominal) &&
3497-
!getASTContext().LangOpts.hasFeature(Feature::TupleConformances)) {
3498-
ED->diagnose(diag::experimental_tuple_extension);
3496+
if (nominal && isa<BuiltinTupleDecl>(nominal)) {
3497+
if (!getASTContext().LangOpts.hasFeature(Feature::TupleConformances)) {
3498+
ED->diagnose(diag::experimental_tuple_extension);
3499+
}
3500+
3501+
if (extType->is<TupleType>()) {
3502+
auto selfType = ED->getSelfInterfaceType();
3503+
if (!extType->isEqual(selfType)) {
3504+
ED->diagnose(diag::tuple_extension_wrong_type, selfType);
3505+
}
3506+
}
34993507
}
35003508

35013509
if (nominal == nullptr) {

lib/Sema/TypeCheckGeneric.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -571,6 +571,10 @@ static void collectAdditionalExtensionRequirements(
571571
if (type->is<ErrorType>())
572572
return;
573573

574+
// Tuple extensions cannot introduce requirements via this mechanism.
575+
if (type->is<TupleType>())
576+
return;
577+
574578
// Find the nominal type declaration and its parent type.
575579
if (type->is<ProtocolCompositionType>())
576580
type = type->getCanonicalType();
@@ -775,7 +779,11 @@ GenericSignatureRequest::evaluate(Evaluator &evaluator,
775779
collectAdditionalExtensionRequirements(ext->getExtendedType(), sameTypeReqs);
776780

777781
// Re-use the signature of the type being extended by default.
778-
if (sameTypeReqs.empty() && !ext->getTrailingWhereClause()) {
782+
// For tuple extensions, always build a new signature to get
783+
// the right sugared types, since we don't want to expose the
784+
// name of the generic parameter of BuiltinTupleDecl itself.
785+
if (sameTypeReqs.empty() && !ext->getTrailingWhereClause() &&
786+
!isa<BuiltinTupleDecl>(ext->getExtendedNominal())) {
779787
return parentSig;
780788
}
781789

test/Generics/tuple-conformances.swift

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,23 @@
1-
// RUN: %target-typecheck-verify-swift -enable-experimental-feature TupleConformances -parse-stdlib
1+
// RUN: %target-typecheck-verify-swift -enable-experimental-feature TupleConformances
22

3+
// Because of -enable-experimental-feature TupleConformances
34
// REQUIRES: asserts
45

5-
import Swift
6-
76
protocol P {
87
associatedtype A
98
associatedtype B
109

1110
func f()
1211
}
1312

14-
extension Builtin.TheTupleType: P where repeat each Elements: P {
15-
typealias A = (repeat (each Elements).A)
13+
extension () {}
14+
// expected-error@-1 {{tuple extension must be written as extension of '(repeat each Element)'}}
15+
// FIXME: Inaccurate
16+
17+
typealias Tuple<each Element> = (repeat each Element)
18+
19+
extension Tuple: P where repeat each Element: P {
20+
typealias A = (repeat (each Element).A)
1621
typealias B = Float
1722
func f() {}
1823
}
@@ -37,7 +42,7 @@ func useConformance() {
3742

3843
////
3944

40-
extension Builtin.TheTupleType: Equatable where repeat each Elements: Equatable {
45+
extension Tuple: Equatable where repeat each Element: Equatable {
4146
// FIXME: Hack
4247
@_disfavoredOverload
4348
public static func ==(lhs: Self, rhs: Self) -> Bool {
@@ -51,7 +56,7 @@ extension Builtin.TheTupleType: Equatable where repeat each Elements: Equatable
5156
}
5257
}
5358

54-
extension Builtin.TheTupleType: Hashable where repeat each Elements: Hashable {
59+
extension Tuple: Hashable where repeat each Element: Hashable {
5560
public func hash(into hasher: inout Hasher) {
5661
repeat (each self).hash(into: &hasher)
5762
}

test/IRGen/tuple_conformances.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
1-
// RUN: %target-swift-frontend -emit-ir -parse-stdlib -primary-file %s -enable-experimental-feature TupleConformances -parse-as-library | %FileCheck %s
1+
// RUN: %target-swift-frontend -emit-ir -primary-file %s -enable-experimental-feature TupleConformances -parse-as-library | %FileCheck %s
22

33
// -enable-experimental-feature requires an asserts build
44
// REQUIRES: asserts
55

6-
import Swift
7-
86
protocol P {
97
func defaultRequirement()
108
static func staticRequirement()
@@ -14,7 +12,9 @@ extension P {
1412
func defaultRequirement() {}
1513
}
1614

17-
extension Builtin.TheTupleType: P where repeat each Elements: P {
15+
typealias Tuple<each Element> = (repeat each Element)
16+
17+
extension Tuple: P where repeat each Element: P {
1818
static func staticRequirement() {}
1919
}
2020

0 commit comments

Comments
 (0)