Skip to content

Commit 34b1532

Browse files
Merge pull request #14435 from aschwaighofer/swift-5.0-branch-sema_require_layout_generic_params
[5.0] Sema: Request the layout for generic parameters if there is a body
2 parents 1a168a6 + 5dabf28 commit 34b1532

File tree

11 files changed

+169
-1
lines changed

11 files changed

+169
-1
lines changed

lib/Sema/CSApply.cpp

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

7534+
// Require layout of dependent types that could be used to materialize
7535+
// metadata types/conformances during IRGen.
7536+
tc.requestRequiredNominalTypeLayoutForParameters(params);
7537+
75347538
// If this is a single-expression closure, convert the expression
75357539
// in the body to the result type of the closure.
75367540
if (closure->hasSingleExpressionBody()) {

lib/Sema/TypeCheckPattern.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -775,6 +775,25 @@ 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+
if (!param->hasType())
784+
continue;
785+
786+
// Generic types are sources for typemetadata and conformances. If a
787+
// parameter is of dependent type then the body of a function with said
788+
// parameter could potentially require the generic type's layout to
789+
// recover them.
790+
if (auto *nominalDecl = dyn_cast_or_null<NominalTypeDecl>(
791+
param->getType()->getAnyGeneric())) {
792+
requestNominalLayout(nominalDecl);
793+
}
794+
}
795+
}
796+
778797
/// Type check a parameter list.
779798
bool TypeChecker::typeCheckParameterList(ParameterList *PL, DeclContext *DC,
780799
TypeResolutionOptions options,

lib/Sema/TypeCheckStmt.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1373,6 +1373,9 @@ bool TypeChecker::typeCheckAbstractFunctionBody(AbstractFunctionDecl *AFD) {
13731373
if (DebugTimeFunctionBodies || WarnLongFunctionBodies)
13741374
timer.emplace(AFD, DebugTimeFunctionBodies, WarnLongFunctionBodies);
13751375

1376+
for (auto paramList : AFD->getParameterLists())
1377+
requestRequiredNominalTypeLayoutForParameters(paramList);
1378+
13761379
if (typeCheckAbstractFunctionBodyUntil(AFD, SourceLoc()))
13771380
return true;
13781381

lib/Sema/TypeChecker.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1810,11 +1810,15 @@ class TypeChecker final : public LazyResolver {
18101810

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

1813+
/// Request nominal layout for any types that could be sources of typemetadata
1814+
/// or conformances.
1815+
void requestRequiredNominalTypeLayoutForParameters(ParameterList *PL);
1816+
18131817
/// Type check a parameter list.
18141818
bool typeCheckParameterList(ParameterList *PL, DeclContext *dc,
18151819
TypeResolutionOptions options,
18161820
GenericTypeResolver &resolver);
1817-
1821+
18181822
/// Coerce a pattern to the given type.
18191823
///
18201824
/// \param P The pattern, which may be modified by this coercion.
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)