Skip to content

Commit ea63089

Browse files
committed
Sema: Request the layout for generic parameters if there is a body
Generic parameters can become sources of metadata types and conformances. To access them the layout needs to be available to IRGen. rdar://37086144 SR-6879
1 parent cc1d258 commit ea63089

13 files changed

+187
-14
lines changed

lib/Sema/CSApply.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7611,6 +7611,10 @@ namespace {
76117611
if (tc.coerceParameterListToType(params, closure, fnType))
76127612
return { false, nullptr };
76137613

7614+
// Require layout of dependent types that could be used to materialize
7615+
// metadata types/conformances during IRGen.
7616+
tc.requestRequiredNominalTypeLayoutForParameters(params);
7617+
76147618
// If this is a single-expression closure, convert the expression
76157619
// in the body to the result type of the closure.
76167620
if (closure->hasSingleExpressionBody()) {

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1015,7 +1015,7 @@ bool PreCheckExpression::walkToClosureExprPre(ClosureExpr *closure) {
10151015

10161016
GenericTypeToArchetypeResolver resolver(closure);
10171017

1018-
if (TC.typeCheckParameterList(PL, DC, options, resolver)) {
1018+
if (TC.typeCheckParameterList(PL, DC, options, resolver, true)) {
10191019
closure->setType(ErrorType::get(TC.Context));
10201020

10211021
// If we encounter an error validating the parameter list, don't bail.

lib/Sema/TypeCheckDecl.cpp

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4354,9 +4354,8 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
43544354
TypeResolutionOptions options;
43554355
options |= TypeResolutionFlags::SubscriptParameters;
43564356

4357-
isInvalid |= TC.typeCheckParameterList(SD->getIndices(), SD,
4358-
options,
4359-
resolver);
4357+
isInvalid |= TC.typeCheckParameterList(SD->getIndices(), SD, options,
4358+
resolver, false);
43604359

43614360
if (isInvalid || SD->isInvalid()) {
43624361
SD->setInterfaceType(ErrorType::get(TC.Context));
@@ -4906,8 +4905,8 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
49064905
GenericTypeResolver &resolver) {
49074906
bool hadError = false;
49084907
for (auto paramList : fd->getParameterLists()) {
4909-
hadError |= TC.typeCheckParameterList(paramList, fd,
4910-
TypeResolutionOptions(), resolver);
4908+
hadError |= TC.typeCheckParameterList(
4909+
paramList, fd, TypeResolutionOptions(), resolver, fd->hasBody());
49114910
}
49124911

49134912
return hadError;
@@ -5341,6 +5340,10 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
53415340
case AccessorKind::IsMaterializeForSet:
53425341
break;
53435342
}
5343+
// Request nominal layout for any types that could be sources of
5344+
// typemetadata or conformances.
5345+
if (accessor->hasBody())
5346+
TC.requestRequiredNominalTypeLayoutForParameters(valueParams);
53445347
}
53455348

53465349
// Before anything else, set up the 'self' argument correctly if present.

lib/Sema/TypeCheckGeneric.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -506,7 +506,7 @@ static bool checkGenericFuncSignature(TypeChecker &tc,
506506
for (auto params : func->getParameterLists()) {
507507
// Check the pattern.
508508
if (tc.typeCheckParameterList(params, func, TypeResolutionOptions(),
509-
resolver))
509+
resolver, func->hasBody()))
510510
badType = true;
511511

512512
// Infer requirements from the pattern.
@@ -1004,9 +1004,8 @@ static bool checkGenericSubscriptSignature(TypeChecker &tc,
10041004
auto params = subscript->getIndices();
10051005
TypeResolutionOptions options = TypeResolutionFlags::SubscriptParameters;
10061006

1007-
badType |= tc.typeCheckParameterList(params, subscript,
1008-
options,
1009-
resolver);
1007+
badType |=
1008+
tc.typeCheckParameterList(params, subscript, options, resolver, false);
10101009

10111010
// Infer requirements from the pattern.
10121011
if (builder) {

lib/Sema/TypeCheckPattern.cpp

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -775,10 +775,31 @@ static bool validateParameterType(ParamDecl *decl, DeclContext *DC,
775775
return hadError;
776776
}
777777

778+
/// Request nominal layout for any types that could be sources of typemetadata
779+
/// or conformances.
780+
void TypeChecker::requestRequiredNominalTypeLayoutForParameters(
781+
ParameterList *PL) {
782+
for (auto param : *PL) {
783+
auto type = param->hasType() ? param->getType()->getCanonicalType()
784+
: param->getTypeLoc().getType();
785+
if (!type)
786+
continue;
787+
if (auto *generic = dyn_cast<BoundGenericType>(type.getPointer())) {
788+
// Generic types are sources for typemetadata and conformances. If a
789+
// parameter is of dependent type then the body of a function with said
790+
// parameter could potentially require the generic type's layout to
791+
// recover them.
792+
if (auto *nominalDecl = dyn_cast<NominalTypeDecl>(generic->getDecl())) {
793+
requestNominalLayout(nominalDecl);
794+
}
795+
}
796+
}
797+
}
798+
778799
/// Type check a parameter list.
779-
bool TypeChecker::typeCheckParameterList(ParameterList *PL, DeclContext *DC,
780-
TypeResolutionOptions options,
781-
GenericTypeResolver &resolver) {
800+
bool TypeChecker::typeCheckParameterList(
801+
ParameterList *PL, DeclContext *DC, TypeResolutionOptions options,
802+
GenericTypeResolver &resolver, bool bodyCouldRequireTypeOrConformance) {
782803
bool hadError = false;
783804

784805
for (auto param : *PL) {
@@ -823,6 +844,9 @@ bool TypeChecker::typeCheckParameterList(ParameterList *PL, DeclContext *DC,
823844
}
824845
}
825846
}
847+
848+
if (!hadError && bodyCouldRequireTypeOrConformance)
849+
requestRequiredNominalTypeLayoutForParameters(PL);
826850

827851
return hadError;
828852
}

lib/Sema/TypeChecker.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1809,10 +1809,15 @@ class TypeChecker final : public LazyResolver {
18091809

18101810
bool typeCheckCatchPattern(CatchStmt *S, DeclContext *dc);
18111811

1812+
/// Request nominal layout for any types that could be sources of typemetadata
1813+
/// or conformances.
1814+
void requestRequiredNominalTypeLayoutForParameters(ParameterList *PL);
1815+
18121816
/// Type check a parameter list.
18131817
bool typeCheckParameterList(ParameterList *PL, DeclContext *dc,
18141818
TypeResolutionOptions options,
1815-
GenericTypeResolver &resolver);
1819+
GenericTypeResolver &resolver,
1820+
bool bodyCouldRequireTypeOrConformance);
18161821

18171822
/// Coerce a pattern to the given type.
18181823
///
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
public class Base<T> {
2+
var t: T
3+
init(_ a: T) {
4+
t = a
5+
}
6+
}
7+
8+
public class Sub<T> : Base<T> {
9+
}
10+
11+
public func requestTypeThrough<T>(closure: (Sub<T>) -> (), arg: T) {
12+
closure(Sub(arg))
13+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// RUN: %target-swift-frontend -module-name test -emit-ir -verify -primary-file %s %S/Inputs/require-layout-generic-class.swift | %FileCheck --check-prefix=FILE1 %s
2+
// RUN: %target-swift-frontend -module-name test -emit-ir -verify %s -primary-file %S/Inputs/require-layout-generic-class.swift | %FileCheck --check-prefix=FILE2 %s
3+
4+
// REQUIRES: CPU=x86_64
5+
6+
// The offset of the typemetadata in the class typemetadata must match.
7+
8+
// FILE1-LABEL: define internal swiftcc void @"$S4test12requestType21xyx_tlFyAA3SubCyxGcfU_"(%T4test3SubC*)
9+
// FILE1: entry:
10+
// FILE1: [[T1:%.*]] = bitcast %T4test3SubC* %0 to %swift.type**
11+
// FILE1: [[TYPEMETADATA:%.*]] = load %swift.type*, %swift.type** [[T1]]
12+
// FILE1: [[T2:%.*]] = bitcast %swift.type* [[TYPEMETADATA]] to %swift.type**
13+
// This offset of T needs to be the same as the offset below.
14+
// FILE1: [[T_PTR:%.*]] = getelementptr inbounds %swift.type*, %swift.type** [[T2]], i64 16
15+
// FILE1: [[T:%.*]] = load %swift.type*, %swift.type** [[T_PTR]]
16+
// FILE1: call %swift.type* @"$S4test3SubCMa"(%swift.type* [[T]])
17+
18+
public func requestType2<T>(x: T) {
19+
requestTypeThrough(closure: { x in print(x) }, arg: x)
20+
}
21+
// FILE2-LABEL: define private %swift.type* @create_generic_metadata_Sub(%swift.type_pattern*, i8**)
22+
// FILE2: [[T_ADDR:%.*]] = bitcast i8** %1 to %swift.type**
23+
// FILE2: [[T:%.*]] = load %swift.type*, %swift.type** %2
24+
// FILE2: [[CLASSMETADATA:%.*]] = call %swift.type* @swift_allocateGenericClassMetadata
25+
// FILE2: [[ADDR:%.*]] = bitcast %swift.type* [[CLASSMETADATA]] to i8**
26+
// This offset of T here needs to be the same as the offset above.
27+
// FILE2: [[T_IN_CLASSMETADATA:%.*]] = getelementptr inbounds i8*, i8** [[ADDR]], i64 16
28+
// FILE2: [[T2:%.*]] = bitcast %swift.type* [[T]] to i8*
29+
// FILE2: store i8* [[T2]], i8** [[T_IN_CLASSMETADATA]]
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// RUN: %target-swift-frontend -module-name test -emit-ir -verify -primary-file %s %S/Inputs/require-layout-generic-class.swift | %FileCheck --check-prefix=FILE1 %s
2+
// RUN: %target-swift-frontend -module-name test -emit-ir -verify %s -primary-file %S/Inputs/require-layout-generic-class.swift | %FileCheck --check-prefix=FILE2 %s
3+
4+
// REQUIRES: CPU=x86_64
5+
6+
// The offset of the typemetadata in the class typemetadata must match.
7+
8+
// FILE1: define hidden swiftcc i64 @"$S4test12AccessorTestCySiAA3SubCyxGcluig"(%T4test3SubC*, %T4test12AccessorTestC* swiftself)
9+
// FILE1: [[T1:%.*]] = bitcast %T4test3SubC* %0 to %swift.type**
10+
// FILE1: [[TYPEMETADATA:%.*]] = load %swift.type*, %swift.type** [[T1]]
11+
// FILE1: [[T2:%.*]] = bitcast %swift.type* [[TYPEMETADATA]] to %swift.type**
12+
// This offset must match the offset below.
13+
// FILE1: [[T_IN_CLASSMETADATA:%.*]] = getelementptr inbounds %swift.type*, %swift.type** [[T2]], i64 16
14+
// FILE1: [[T:%.*]] = load %swift.type*, %swift.type** [[T_IN_CLASSMETADATA]]
15+
// FILE1: call %swift.type* @swift_getMetatypeMetadata(%swift.type* [[T]])
16+
public class AccessorTest {
17+
subscript<T>(_ a: Sub<T>) -> Int {
18+
get {
19+
print(T.self)
20+
return 1
21+
}
22+
}
23+
}
24+
25+
// FILE2-LABEL: define private %swift.type* @create_generic_metadata_Sub(%swift.type_pattern*, i8**)
26+
// FILE2: [[T_ADDR:%.*]] = bitcast i8** %1 to %swift.type**
27+
// FILE2: [[T:%.*]] = load %swift.type*, %swift.type** %2
28+
// FILE2: [[CLASSMETADATA:%.*]] = call %swift.type* @swift_allocateGenericClassMetadata
29+
// FILE2: [[ADDR:%.*]] = bitcast %swift.type* [[CLASSMETADATA]] to i8**
30+
// This offset must match the offset above.
31+
// FILE2: [[T_IN_CLASSMETADATA:%.*]] = getelementptr inbounds i8*, i8** [[ADDR]], i64 16
32+
// FILE2: [[T2:%.*]] = bitcast %swift.type* [[T]] to i8*
33+
// FILE2: store i8* [[T2]], i8** [[T_IN_CLASSMETADATA]]
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// RUN: %target-swift-frontend -module-name test -emit-ir -verify -primary-file %s %S/Inputs/require-layout-generic-class.swift | %FileCheck --check-prefix=FILE1 %s
2+
// RUN: %target-swift-frontend -module-name test -emit-ir -verify %s -primary-file %S/Inputs/require-layout-generic-class.swift | %FileCheck --check-prefix=FILE2 %s
3+
4+
// REQUIRES: CPU=x86_64
5+
6+
// The offset of the typemetadata in the class typemetadata must match.
7+
8+
// FILE1-LABEL: define swiftcc void @"$S4test11requestTypeyyAA3SubCyxGlF"(%T4test3SubC*)
9+
// FILE1: [[T1:%.*]] = bitcast %T4test3SubC* %0 to %swift.type**
10+
// FILE1: [[TYPEMETADATA:%.*]] = load %swift.type*, %swift.type** [[T1]]
11+
// FILE1: [[T2:%.*]] = bitcast %swift.type* [[TYPEMETADATA]] to %swift.type**
12+
// This offset must match the offset below.
13+
// FILE1: [[T_PTR:%.*]] = getelementptr inbounds %swift.type*, %swift.type** [[T2]], i64 16
14+
// FILE1: [[T:%.*]] = load %swift.type*, %swift.type** [[T_PTR]]
15+
public func requestType<T>(_ c: Sub<T>) {
16+
print(T.self)
17+
}
18+
19+
// FILE2-LABEL: define private %swift.type* @create_generic_metadata_Sub(%swift.type_pattern*, i8**)
20+
// FILE2: [[T_ADDR:%.*]] = bitcast i8** %1 to %swift.type**
21+
// FILE2: [[T:%.*]] = load %swift.type*, %swift.type** %2
22+
// FILE2: [[CLASSMETADATA:%.*]] = call %swift.type* @swift_allocateGenericClassMetadata
23+
// FILE2: [[ADDR:%.*]] = bitcast %swift.type* [[CLASSMETADATA]] to i8**
24+
// This offset must match the offset above.
25+
// FILE2: [[T_IN_CLASSMETADATA:%.*]] = getelementptr inbounds i8*, i8** [[ADDR]], i64 16
26+
// FILE2: [[T2:%.*]] = bitcast %swift.type* [[T]] to i8*
27+
// FILE2: store i8* [[T2]], i8** [[T_IN_CLASSMETADATA]]
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-build-swift %S/../require-layout-generic-arg.swift %S/../Inputs/require-layout-generic-class.swift %s -o %t/test
3+
// RUN: %target-run %t/test | %FileCheck %s
4+
5+
// REQUIRES: executable_test
6+
7+
func test() {
8+
requestType(Sub(1))
9+
}
10+
11+
// CHECK: Int
12+
test()
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-build-swift %S/../require-layout-generic-arg-closure.swift %S/../Inputs/require-layout-generic-class.swift %s -o %t/test
3+
// RUN: %target-run %t/test | %FileCheck %s
4+
5+
// REQUIRES: executable_test
6+
7+
func test() {
8+
requestType2(x: 1)
9+
}
10+
11+
// CHECK: test.Sub<Swift.Int>
12+
test()
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-build-swift %S/../require-layout-generic-arg-subscript.swift %S/../Inputs/require-layout-generic-class.swift %s -o %t/test
3+
// RUN: %target-run %t/test | %FileCheck %s
4+
5+
// REQUIRES: executable_test
6+
7+
func test() {
8+
_ = AccessorTest()[Sub(1)]
9+
}
10+
11+
// CHECK: Int
12+
test()

0 commit comments

Comments
 (0)