Skip to content

Commit 28c35ff

Browse files
committed
SILGen: Fix problems with local generic functions
When evaluating if a call of a local function requires substitutions, we checked if the immediate function being referenced captured generic parameters, without checking if it transitively captured generic parameters via other local functions it references. Also, when calling accessors, we did not perform this check at all. Fix both ordinary function calls and accessor calls to drop the substitutions only if the *lowered* local captures say it is safe. Finally, fix Sema to not consider substitutions in local function references as generic parameter captures, since we now correctly calculate the transitive closure of all captures. Fixes <rdar://problem/32761305> and related issues.
1 parent 4b0597a commit 28c35ff

File tree

4 files changed

+88
-12
lines changed

4 files changed

+88
-12
lines changed

lib/SILGen/SILGenApply.cpp

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -868,13 +868,17 @@ class SILGenApply : public Lowering::ExprVisitor<SILGenApply> {
868868

869869
auto afd = dyn_cast<AbstractFunctionDecl>(e->getDecl());
870870

871+
CaptureInfo captureInfo;
872+
871873
// Otherwise, we have a statically-dispatched call.
872-
SubstitutionList subs;
873-
if (e->getDeclRef().isSpecialized() &&
874-
(!afd ||
875-
!afd->getDeclContext()->isLocalContext() ||
876-
afd->getCaptureInfo().hasGenericParamCaptures()))
877-
subs = e->getDeclRef().getSubstitutions();
874+
SubstitutionList subs = e->getDeclRef().getSubstitutions();
875+
876+
if (afd) {
877+
captureInfo = SGF.SGM.Types.getLoweredLocalCaptures(afd);
878+
if (afd->getDeclContext()->isLocalContext() &&
879+
!captureInfo.hasGenericParamCaptures())
880+
subs = SubstitutionList();
881+
}
878882

879883
// Enum case constructor references are open-coded.
880884
if (isa<EnumElementDecl>(e->getDecl()))
@@ -884,7 +888,7 @@ class SILGenApply : public Lowering::ExprVisitor<SILGenApply> {
884888

885889
// If the decl ref requires captures, emit the capture params.
886890
if (afd) {
887-
if (SGF.SGM.M.Types.hasLoweredLocalCaptures(afd)) {
891+
if (!captureInfo.getCaptures().empty()) {
888892
SmallVector<ManagedValue, 4> captures;
889893
SGF.emitCaptures(e, afd, CaptureEmission::ImmediateApplication,
890894
captures);
@@ -4900,6 +4904,15 @@ static Callee getBaseAccessorFunctionRef(SILGenFunction &SGF,
49004904
SubstitutionList subs) {
49014905
auto *decl = cast<AbstractFunctionDecl>(constant.getDecl());
49024906

4907+
// The accessor might be a local function that does not capture any
4908+
// generic parameters, in which case we don't want to pass in any
4909+
// substitutions.
4910+
auto captureInfo = SGF.SGM.Types.getLoweredLocalCaptures(decl);
4911+
if (decl->getDeclContext()->isLocalContext() &&
4912+
!captureInfo.hasGenericParamCaptures()) {
4913+
subs = SubstitutionList();
4914+
}
4915+
49034916
// If this is a method in a protocol, generate it as a protocol call.
49044917
if (isa<ProtocolDecl>(decl->getDeclContext())) {
49054918
assert(!isDirectUse && "direct use of protocol accessor?");

lib/Sema/TypeCheckCaptures.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -229,10 +229,14 @@ class FindCapturedVars : public ASTWalker {
229229
std::pair<bool, Expr *> walkToDeclRefExpr(DeclRefExpr *DRE) {
230230
auto *D = DRE->getDecl();
231231

232-
// Capture the generic parameters of the decl.
233-
if (!AFR.isObjC() || !D->isObjC() || isa<ConstructorDecl>(D)) {
234-
for (auto sub : DRE->getDeclRef().getSubstitutions()) {
235-
checkType(sub.getReplacement(), DRE->getLoc());
232+
// Capture the generic parameters of the decl, unless it's a
233+
// local declaration in which case we will pick up generic
234+
// parameter references transitively.
235+
if (!D->getDeclContext()->isLocalContext()) {
236+
if (!AFR.isObjC() || !D->isObjC() || isa<ConstructorDecl>(D)) {
237+
for (auto sub : DRE->getDeclRef().getSubstitutions()) {
238+
checkType(sub.getReplacement(), DRE->getLoc());
239+
}
236240
}
237241
}
238242

test/SILGen/generic_closures.swift

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,27 @@ var zero: Int
88
func generic_nondependent_context<T>(_ x: T, y: Int) -> Int {
99
func foo() -> Int { return y }
1010

11+
func bar() -> Int { return y }
12+
1113
// CHECK: [[FOO:%.*]] = function_ref @_T016generic_closures0A21_nondependent_context{{.*}} : $@convention(thin) (Int) -> Int
1214
// CHECK: [[FOO_CLOSURE:%.*]] = partial_apply [[FOO]](%1)
1315
// CHECK: destroy_value [[FOO_CLOSURE]]
1416
let _ = foo
1517

18+
// CHECK: [[BAR:%.*]] = function_ref @_T016generic_closures0A21_nondependent_context{{.*}} : $@convention(thin) (Int) -> Int
19+
// CHECK: [[BAR_CLOSURE:%.*]] = partial_apply [[BAR]](%1)
20+
// CHECK: destroy_value [[BAR_CLOSURE]]
21+
let _ = bar
22+
1623
// CHECK: [[FOO:%.*]] = function_ref @_T016generic_closures0A21_nondependent_context{{.*}} : $@convention(thin) (Int) -> Int
1724
// CHECK: [[FOO_CLOSURE:%.*]] = apply [[FOO]]
18-
return foo()
25+
_ = foo()
26+
27+
// CHECK: [[BAR:%.*]] = function_ref @_T016generic_closures0A21_nondependent_context{{.*}} : $@convention(thin) (Int) -> Int
28+
// CHECK: [[BAR_CLOSURE:%.*]] = apply [[BAR]]
29+
30+
// CHECK: [[BAR_CLOSURE]]
31+
return bar()
1932
}
2033

2134
// CHECK-LABEL: sil hidden @_T016generic_closures0A8_capture{{[_0-9a-zA-Z]*}}F
@@ -29,6 +42,8 @@ func generic_capture<T>(_ x: T) -> Any.Type {
2942

3043
// CHECK: [[FOO:%.*]] = function_ref @_T016generic_closures0A8_capture{{.*}} : $@convention(thin) <τ_0_0> () -> @thick Any.Type
3144
// CHECK: [[FOO_CLOSURE:%.*]] = apply [[FOO]]<T>()
45+
46+
// CHECK: return [[FOO_CLOSURE]]
3247
return foo()
3348
}
3449

@@ -43,6 +58,8 @@ func generic_capture_cast<T>(_ x: T, y: Any) -> Bool {
4358

4459
// CHECK: [[FOO:%.*]] = function_ref @_T016generic_closures0A13_capture_cast{{.*}} : $@convention(thin) <τ_0_0> (@in Any) -> Bool
4560
// CHECK: [[FOO_CLOSURE:%.*]] = apply [[FOO]]<T>([[ARG:%.*]])
61+
62+
// CHECK: return [[FOO_CLOSURE]]
4663
return foo(y)
4764
}
4865

@@ -61,6 +78,8 @@ func generic_nocapture_existential<T>(_ x: T, y: Concept) -> Bool {
6178

6279
// CHECK: [[FOO:%.*]] = function_ref @_T016generic_closures0A22_nocapture_existential{{.*}} : $@convention(thin) (@in Concept) -> Bool
6380
// CHECK: [[FOO_CLOSURE:%.*]] = apply [[FOO]]([[ARG:%.*]])
81+
82+
// CHECK: return [[FOO_CLOSURE]]
6483
return foo(y)
6584
}
6685

@@ -75,6 +94,8 @@ func generic_dependent_context<T>(_ x: T, y: Int) -> T {
7594

7695
// CHECK: [[FOO:%.*]] = function_ref @_T016generic_closures0A18_dependent_context{{.*}} : $@convention(thin) <τ_0_0> (@owned <τ_0_0> { var τ_0_0 } <τ_0_0>) -> @out τ_0_0
7796
// CHECK: [[FOO_CLOSURE:%.*]] = apply [[FOO]]<T>
97+
98+
// CHECK: return
7899
return foo()
79100
}
80101

test/SILGen/properties.swift

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,25 @@ func logical_local_get(_ x: Int) -> Int {
325325
// CHECK-: sil private [[PROP_GET_CLOSURE]]
326326
// CHECK: bb0(%{{[0-9]+}} : $Int):
327327

328+
func logical_generic_local_get<T>(_ x: Int, _: T) {
329+
var prop1: Int {
330+
get {
331+
return x
332+
}
333+
}
334+
335+
_ = prop1
336+
337+
var prop2: Int {
338+
get {
339+
_ = T.self
340+
return x
341+
}
342+
}
343+
344+
_ = prop2
345+
}
346+
328347
// CHECK-LABEL: sil hidden @_T010properties26logical_local_captured_get{{[_0-9a-zA-Z]*}}F
329348
func logical_local_captured_get(_ x: Int) -> Int {
330349
var prop : Int {
@@ -654,7 +673,26 @@ func local_observing_property(_ arg: Int) {
654673
// CHECK: [[PB:%.*]] = project_box [[BOX]]
655674
// CHECK: store [[ARG]] to [trivial] [[PB]]
656675

676+
func local_generic_observing_property<T>(_ arg: Int, _: T) {
677+
var localproperty1: Int = arg {
678+
didSet {
679+
takeInt(localproperty1)
680+
}
681+
}
682+
683+
takeInt(localproperty1)
684+
localproperty1 = arg
657685

686+
var localproperty2: Int = arg {
687+
didSet {
688+
_ = T.self
689+
takeInt(localproperty2)
690+
}
691+
}
692+
693+
takeInt(localproperty2)
694+
localproperty2 = arg
695+
}
658696

659697

660698
// <rdar://problem/16006333> observing properties don't work in @objc classes

0 commit comments

Comments
 (0)