Skip to content

Commit 3e95e81

Browse files
authored
Merge pull request #77765 from hamishknight/thunk-fix
[CS] Use adjusted type for single curry thunks
2 parents 015830e + 68648f7 commit 3e95e81

File tree

7 files changed

+167
-64
lines changed

7 files changed

+167
-64
lines changed

lib/Sema/CSApply.cpp

Lines changed: 36 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -759,22 +759,27 @@ namespace {
759759
new (ctx) DeclRefExpr(ref, loc, implicit, semantics, fullType);
760760
cs.cacheType(declRefExpr);
761761
declRefExpr->setFunctionRefKind(choice.getFunctionRefKind());
762-
Expr *result = adjustTypeForDeclReference(
763-
declRefExpr, fullType, adjustedFullType, locator);
764-
// If we have to load, do so now.
765-
if (loadImmediately)
766-
result = cs.addImplicitLoadExpr(result);
767762

768-
result = forceUnwrapIfExpected(result, locator);
763+
Expr *result = forceUnwrapIfExpected(declRefExpr, locator);
769764

770765
if (auto *fnDecl = dyn_cast<AbstractFunctionDecl>(decl)) {
771766
if (AnyFunctionRef(fnDecl).hasExternalPropertyWrapperParameters() &&
772767
(declRefExpr->getFunctionRefKind() == FunctionRefKind::Compound ||
773768
declRefExpr->getFunctionRefKind() == FunctionRefKind::Unapplied)) {
774-
result = buildSingleCurryThunk(result, fnDecl, locator);
769+
// We don't need to do any further adjustment once we've built the
770+
// curry thunk.
771+
return buildSingleCurryThunk(result, fnDecl,
772+
adjustedFullType->castTo<FunctionType>(),
773+
locator);
775774
}
776775
}
777776

777+
result = adjustTypeForDeclReference(result, fullType, adjustedFullType,
778+
locator);
779+
// If we have to load, do so now.
780+
if (loadImmediately)
781+
result = cs.addImplicitLoadExpr(result);
782+
778783
return result;
779784
}
780785

@@ -1406,41 +1411,20 @@ namespace {
14061411
/// parameters.
14071412
/// \param declOrClosure The underlying function-like declaration or
14081413
/// closure we're going to call.
1414+
/// \param thunkTy The type of the resulting thunk. This should be the
1415+
/// type of the \c fnExpr, with any potential adjustments for things like
1416+
/// concurrency.
14091417
/// \param locator The locator pinned on the function reference carried
14101418
/// by \p fnExpr. If the function has associated applied property wrappers,
14111419
/// the locator is used to pull them in.
14121420
AutoClosureExpr *buildSingleCurryThunk(Expr *fnExpr,
14131421
DeclContext *declOrClosure,
1422+
FunctionType *thunkTy,
14141423
ConstraintLocatorBuilder locator) {
1415-
auto *const thunkTy = cs.getType(fnExpr)->castTo<FunctionType>();
1416-
14171424
return buildSingleCurryThunk(/*baseExpr=*/nullptr, fnExpr, declOrClosure,
14181425
thunkTy, locator);
14191426
}
14201427

1421-
/// Build a "{ args in base.fn(args) }" single-expression curry thunk.
1422-
///
1423-
/// \param baseExpr The base expression to be captured.
1424-
/// \param fnExpr The expression to be called by consecutively applying
1425-
/// the \p baseExpr and thunk parameters.
1426-
/// \param declOrClosure The underlying function-like declaration or
1427-
/// closure we're going to call.
1428-
/// \param locator The locator pinned on the function reference carried
1429-
/// by \p fnExpr. If the function has associated applied property wrappers,
1430-
/// the locator is used to pull them in.
1431-
AutoClosureExpr *buildSingleCurryThunk(Expr *baseExpr, Expr *fnExpr,
1432-
DeclContext *declOrClosure,
1433-
ConstraintLocatorBuilder locator) {
1434-
assert(baseExpr);
1435-
auto *const thunkTy = cs.getType(fnExpr)
1436-
->castTo<FunctionType>()
1437-
->getResult()
1438-
->castTo<FunctionType>();
1439-
1440-
return buildSingleCurryThunk(baseExpr, fnExpr, declOrClosure, thunkTy,
1441-
locator);
1442-
}
1443-
14441428
/// Build a "{ self in { args in self.fn(args) } }" nested curry thunk.
14451429
///
14461430
/// \param memberRef The expression to be called in the inner thunk by
@@ -1577,8 +1561,8 @@ namespace {
15771561
ConstraintLocatorBuilder memberLocator, bool Implicit,
15781562
AccessSemantics semantics) {
15791563
const auto &choice = overload.choice;
1580-
const auto openedType = overload.openedType;
1581-
const auto adjustedOpenedType = overload.adjustedOpenedType;
1564+
const auto openedType = simplifyType(overload.openedType);
1565+
const auto adjustedOpenedType = simplifyType(overload.adjustedOpenedType);
15821566

15831567
ValueDecl *member = choice.getDecl();
15841568

@@ -1639,7 +1623,7 @@ namespace {
16391623
// If we're referring to a member type, it's just a type
16401624
// reference.
16411625
if (auto *TD = dyn_cast<TypeDecl>(member)) {
1642-
Type refType = simplifyType(adjustedOpenedType);
1626+
Type refType = adjustedOpenedType;
16431627
auto ref = TypeExpr::createForDecl(memberLoc, TD, dc);
16441628
cs.setType(ref, refType);
16451629
auto *result = new (context) DotSyntaxBaseIgnoredExpr(
@@ -1770,10 +1754,8 @@ namespace {
17701754
ref->setImplicit(Implicit);
17711755
// FIXME: FunctionRefKind
17721756

1773-
auto computeRefType = [&](Type openedType) {
1774-
// Compute the type of the reference.
1775-
Type refType = simplifyType(openedType);
1776-
1757+
// Compute the type of the reference.
1758+
auto computeRefType = [&](Type refType) {
17771759
// If the base was an opened existential, erase the opened
17781760
// existential.
17791761
if (openedExistential) {
@@ -1859,7 +1841,7 @@ namespace {
18591841
// type having 'Self' swapped for the appropriate replacement
18601842
// type -- usually the base object type.
18611843
if (hasDynamicSelf) {
1862-
const auto conversionTy = simplifyType(adjustedOpenedType);
1844+
const auto conversionTy = adjustedOpenedType;
18631845
if (!containerTy->isEqual(conversionTy)) {
18641846
result = cs.cacheType(new (context) CovariantReturnConversionExpr(
18651847
result, conversionTy));
@@ -1911,9 +1893,10 @@ namespace {
19111893
// have side effects, instead of abstracting out a 'self' parameter.
19121894
const auto isSuperPartialApplication = needsCurryThunk && isSuper;
19131895
if (isSuperPartialApplication) {
1914-
ref = buildSingleCurryThunk(base, declRefExpr,
1915-
cast<AbstractFunctionDecl>(member),
1916-
memberLocator);
1896+
ref = buildSingleCurryThunk(
1897+
base, declRefExpr, cast<AbstractFunctionDecl>(member),
1898+
adjustedOpenedType->castTo<FunctionType>(),
1899+
memberLocator);
19171900
} else if (needsCurryThunk) {
19181901
// Another case where we want to build a single closure is when
19191902
// we have a partial application of a static member. It is better
@@ -1929,14 +1912,13 @@ namespace {
19291912
cs.getType(base));
19301913
cs.setType(base, base->getType());
19311914

1932-
auto *closure = buildSingleCurryThunk(
1933-
base, declRefExpr, cast<AbstractFunctionDecl>(member),
1934-
memberLocator);
1935-
19361915
// Skip the code below -- we're not building an extra level of
19371916
// call by applying the metatype; instead, the closure we just
19381917
// built is the curried reference.
1939-
return closure;
1918+
return buildSingleCurryThunk(
1919+
base, declRefExpr, cast<AbstractFunctionDecl>(member),
1920+
adjustedOpenedType->castTo<FunctionType>(),
1921+
memberLocator);
19401922
} else {
19411923
// Add a useless ".self" to avoid downstream diagnostics, in case
19421924
// the type ref is still a TypeExpr.
@@ -1967,7 +1949,7 @@ namespace {
19671949

19681950
auto *closure = buildSingleCurryThunk(
19691951
baseRef, declRefExpr, cast<AbstractFunctionDecl>(member),
1970-
simplifyType(adjustedOpenedType)->castTo<FunctionType>(),
1952+
adjustedOpenedType->castTo<FunctionType>(),
19711953
memberLocator);
19721954

19731955
// Wrap the closure in a capture list.
@@ -1994,7 +1976,7 @@ namespace {
19941976
// must be downcast to the opened archetype before being erased to the
19951977
// subclass existential to cope with the expectations placed
19961978
// on 'CovariantReturnConversionExpr'.
1997-
curryThunkTy = simplifyType(adjustedOpenedType)->castTo<FunctionType>();
1979+
curryThunkTy = adjustedOpenedType->castTo<FunctionType>();
19981980
} else {
19991981
curryThunkTy = adjustedRefTy->castTo<FunctionType>();
20001982

@@ -2060,7 +2042,7 @@ namespace {
20602042
apply = ConstructorRefCallExpr::create(context, ref, base);
20612043
} else if (isUnboundInstanceMember) {
20622044
ref = adjustTypeForDeclReference(
2063-
ref, cs.getType(ref), cs.simplifyType(adjustedOpenedType),
2045+
ref, cs.getType(ref), adjustedOpenedType,
20642046
locator);
20652047

20662048
// Reference to an unbound instance method.
@@ -8876,8 +8858,10 @@ namespace {
88768858
rewriteFunction(closure);
88778859

88788860
if (AnyFunctionRef(closure).hasExternalPropertyWrapperParameters()) {
8861+
auto *thunkTy = Rewriter.cs.getType(closure)->castTo<FunctionType>();
88798862
return Action::SkipNode(Rewriter.buildSingleCurryThunk(
8880-
closure, closure, Rewriter.cs.getConstraintLocator(closure)));
8863+
closure, closure, thunkTy,
8864+
Rewriter.cs.getConstraintLocator(closure)));
88818865
}
88828866

88838867
return Action::SkipNode(closure);

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4458,17 +4458,21 @@ namespace {
44584458
}
44594459

44604460
// Attempt to resolve the global actor type of a closure.
4461-
Type resolveGlobalActorType(ClosureExpr *closure) {
4461+
Type resolveGlobalActorType(AbstractClosureExpr *ACE) {
44624462
// Check whether the closure's type has a global actor already.
4463-
if (Type closureType = getType(closure)) {
4463+
if (Type closureType = getType(ACE)) {
44644464
if (auto closureFnType = closureType->getAs<FunctionType>()) {
44654465
if (Type globalActor = closureFnType->getGlobalActor())
44664466
return globalActor;
44674467
}
44684468
}
44694469

44704470
// Look for an explicit attribute.
4471-
return getExplicitGlobalActor(closure);
4471+
if (auto *CE = dyn_cast<ClosureExpr>(ACE)) {
4472+
if (auto globalActor = getExplicitGlobalActor(CE))
4473+
return globalActor;
4474+
}
4475+
return Type();
44724476
}
44734477

44744478
public:
@@ -4480,14 +4484,16 @@ namespace {
44804484
AbstractClosureExpr *closure) {
44814485
bool preconcurrency = false;
44824486

4483-
if (auto explicitClosure = dyn_cast<ClosureExpr>(closure)) {
4487+
if (auto explicitClosure = dyn_cast<ClosureExpr>(closure))
44844488
preconcurrency = explicitClosure->isIsolatedByPreconcurrency();
44854489

4486-
// If the closure specifies a global actor, use it.
4487-
if (Type globalActor = resolveGlobalActorType(explicitClosure))
4488-
return ActorIsolation::forGlobalActor(globalActor)
4489-
.withPreconcurrency(preconcurrency);
4490+
// If the closure specifies a global actor, use it.
4491+
if (Type globalActor = resolveGlobalActorType(closure)) {
4492+
return ActorIsolation::forGlobalActor(globalActor)
4493+
.withPreconcurrency(preconcurrency);
4494+
}
44904495

4496+
if (auto *explicitClosure = dyn_cast<ClosureExpr>(closure)) {
44914497
if (auto *attr =
44924498
explicitClosure->getAttrs().getAttribute<NonisolatedAttr>();
44934499
attr && ctx.LangOpts.hasFeature(Feature::ClosureIsolation)) {

test/Concurrency/global_actor_function_types.swift

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,3 +413,28 @@ extension GlobalType {
413413
rhs: GlobalType
414414
) -> Bool { true }
415415
}
416+
417+
func takesMainActorFn(_ x: @MainActor () -> Int) {}
418+
func takesMainActorAutoclosure(_ x: @autoclosure @MainActor () -> Int) {}
419+
420+
func nonisolatedIntFn() -> Int { 0 }
421+
@MainActor func mainActorIntFn() -> Int { 0 }
422+
423+
struct HasMainActorFns {
424+
@MainActor static func staticFn() -> Int { 0 }
425+
@MainActor func instanceFn() -> Int { 0 }
426+
}
427+
428+
func testGlobalActorAutoclosure(_ x: HasMainActorFns) {
429+
takesMainActorFn(nonisolatedIntFn)
430+
takesMainActorFn(mainActorIntFn)
431+
432+
// Make sure we respect global actors on autoclosures.
433+
takesMainActorAutoclosure(nonisolatedIntFn())
434+
takesMainActorAutoclosure(mainActorIntFn())
435+
436+
// Including autoclosure thunks.
437+
takesMainActorFn(HasMainActorFns.staticFn)
438+
takesMainActorFn(HasMainActorFns.instanceFn(x))
439+
takesMainActorFn(x.instanceFn)
440+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// RUN: %target-swift-emit-silgen -verify -disable-objc-attr-requires-foundation-module %s
2+
// RUN: %target-swift-emit-silgen -verify -swift-version 6 -disable-objc-attr-requires-foundation-module %s
3+
4+
// REQUIRES: objc_interop
5+
6+
@objc class C {
7+
@preconcurrency @objc func foo(_ x: Sendable) {}
8+
}
9+
10+
func bar(_ fn: (Any) -> Void) {}
11+
func bar(_ fn: (Sendable) -> Void) {}
12+
13+
// Make sure we can handle both the implicit unwrap and concurrency adjustment.
14+
func foo(_ x: AnyObject) {
15+
bar(x.foo)
16+
let _ = AnyObject.foo
17+
}

test/Constraints/rdar140212823.swift

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// RUN: %target-swift-emit-silgen %s -verify -swift-version 6
2+
3+
// rdar://140212823 - Make sure we build curry thunks using the adjusted
4+
// reference type, such that the ParenExpr agrees with the type.
5+
6+
class C: @unchecked Sendable {
7+
func foo() {}
8+
}
9+
class D: C, @unchecked Sendable {
10+
func bar() {
11+
let _ = (super.foo)
12+
}
13+
}
14+
15+
struct S {
16+
func instanceMethod() {}
17+
func foo() {
18+
let _ = (self.instanceMethod)
19+
}
20+
static func staticMethod() {}
21+
}
22+
23+
let _ = (S.instanceMethod)
24+
let _ = (type(of: S()).instanceMethod)
25+
26+
let _ = (S.staticMethod)
27+
let _ = (type(of: S()).staticMethod)
28+
29+
let _: (Int, Int) -> Int = (+)

test/SILGen/dynamic_self.swift

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,7 @@ class Base {
362362

363363
class Derived : Base {
364364
// CHECK-LABEL: sil hidden [ossa] @$s12dynamic_self7DerivedC9superCallyyF : $@convention(method) (@guaranteed Derived) -> ()
365-
// CHECK: convert_function %{{[0-9]+}} : $@callee_guaranteed () -> @owned Base to $@callee_guaranteed () -> @owned Derived
365+
// CHECK: function_ref @$s12dynamic_self7DerivedC9superCallyyFACycfu_ : $@convention(thin) (@guaranteed Derived) -> @owned Derived
366366
// CHECK-COUNT-3: unchecked_ref_cast %{{[0-9]+}} : $Base to $Derived
367367
// CHECK-NOT: unchecked_ref_cast
368368
// CHECK: end sil function '$s12dynamic_self7DerivedC9superCallyyF'
@@ -372,9 +372,12 @@ class Derived : Base {
372372
_ = super.property
373373
_ = super[]
374374
}
375+
// CHECK-LABEL: sil private [ossa] @$s12dynamic_self7DerivedC9superCallyyFACycfu_ : $@convention(thin) (@guaranteed Derived) -> @owned Derived
376+
// CHECK: unchecked_ref_cast %{{[0-9]+}} : $Base to $Derived
377+
// CHECK: end sil function '$s12dynamic_self7DerivedC9superCallyyFACycfu_'
375378

376379
// CHECK-LABEL: sil hidden [ossa] @$s12dynamic_self7DerivedC15superCallStaticyyFZ : $@convention(method) (@thick Derived.Type) -> ()
377-
// CHECK: convert_function %{{[0-9]+}} : $@callee_guaranteed () -> @owned Base to $@callee_guaranteed () -> @owned Derived
380+
// CHECK: function_ref @$s12dynamic_self7DerivedC15superCallStaticyyFZACycfu_ : $@convention(thin) (@thick Derived.Type) -> @owned Derived
378381
// CHECK-COUNT-3: unchecked_ref_cast %{{[0-9]+}} : $Base to $Derived
379382
// CHECK-NOT: unchecked_ref_cast
380383
// CHECK: end sil function '$s12dynamic_self7DerivedC15superCallStaticyyFZ'
@@ -384,9 +387,12 @@ class Derived : Base {
384387
_ = super.staticProperty
385388
_ = super[]
386389
}
390+
// CHECK-LABEL: sil private [ossa] @$s12dynamic_self7DerivedC15superCallStaticyyFZACycfu_ : $@convention(thin) (@thick Derived.Type) -> @owned Derived
391+
// CHECK: unchecked_ref_cast %{{[0-9]+}} : $Base to $Derived
392+
// CHECK: end sil function '$s12dynamic_self7DerivedC15superCallStaticyyFZACycfu_'
387393

388394
// CHECK-LABEL: sil hidden [ossa] @$s12dynamic_self7DerivedC32superCallFromMethodReturningSelfACXDyF : $@convention(method) (@guaranteed Derived) -> @owned Derived
389-
// CHECK: convert_function %{{[0-9]+}} : $@callee_guaranteed () -> @owned Base to $@callee_guaranteed () -> @owned Derived
395+
// CHECK: function_ref @$s12dynamic_self7DerivedC32superCallFromMethodReturningSelfACXDyFACXDycfu_ : $@convention(thin) (@guaranteed Derived) -> @owned Derived
390396
// CHECK-COUNT-3: unchecked_ref_cast %{{[0-9]+}} : $Base to $Derived
391397
// CHECK-NOT: unchecked_ref_cast
392398
// CHECK: end sil function '$s12dynamic_self7DerivedC32superCallFromMethodReturningSelfACXDyF'
@@ -396,9 +402,12 @@ class Derived : Base {
396402
_ = super[]
397403
return super.property
398404
}
405+
// CHECK-LABEL: sil private [ossa] @$s12dynamic_self7DerivedC32superCallFromMethodReturningSelfACXDyFACXDycfu_ : $@convention(thin) (@guaranteed Derived) -> @owned Derived
406+
// CHECK: unchecked_ref_cast %{{[0-9]+}} : $Base to $Derived
407+
// CHECK: end sil function '$s12dynamic_self7DerivedC32superCallFromMethodReturningSelfACXDyFACXDycfu_'
399408

400409
// CHECK-LABEL: sil hidden [ossa] @$s12dynamic_self7DerivedC38superCallFromMethodReturningSelfStaticACXDyFZ : $@convention(method) (@thick Derived.Type) -> @owned Derived
401-
// CHECK: convert_function %{{[0-9]+}} : $@callee_guaranteed () -> @owned Base to $@callee_guaranteed () -> @owned Derived
410+
// CHECK: function_ref @$s12dynamic_self7DerivedC38superCallFromMethodReturningSelfStaticACXDyFZACXDycfu_ : $@convention(thin) (@thick @dynamic_self Derived.Type) -> @owned Derived
402411
// CHECK-COUNT-3: unchecked_ref_cast %{{[0-9]+}} : $Base to $Derived
403412
// CHECK-NOT: unchecked_ref_cast
404413
// CHECK: end sil function '$s12dynamic_self7DerivedC38superCallFromMethodReturningSelfStaticACXDyFZ'
@@ -408,6 +417,9 @@ class Derived : Base {
408417
_ = super[]
409418
return super.staticProperty
410419
}
420+
// CHECK-LABEL: sil private [ossa] @$s12dynamic_self7DerivedC38superCallFromMethodReturningSelfStaticACXDyFZACXDycfu_ : $@convention(thin) (@thick @dynamic_self Derived.Type) -> @owned Derived
421+
// CHECK: unchecked_ref_cast %{{[0-9]+}} : $Base to $Derived
422+
// CHECK: end sil function '$s12dynamic_self7DerivedC38superCallFromMethodReturningSelfStaticACXDyFZACXDycfu_'
411423
}
412424

413425
class Generic<T> {

0 commit comments

Comments
 (0)