[CS] Use adjusted type for single curry thunks

This matches the double curry thunk logic and
ensures that the resulting autoclosure matches the
expected type of the reference, avoiding mismatches
with parent expressions.

rdar://140212823
This commit is contained in:
Hamish Knight
2024-11-21 12:14:00 +00:00
parent 683c7ceb31
commit 68648f74ef
5 changed files with 119 additions and 45 deletions

View File

@@ -759,22 +759,27 @@ namespace {
new (ctx) DeclRefExpr(ref, loc, implicit, semantics, fullType);
cs.cacheType(declRefExpr);
declRefExpr->setFunctionRefKind(choice.getFunctionRefKind());
Expr *result = adjustTypeForDeclReference(
declRefExpr, fullType, adjustedFullType, locator);
// If we have to load, do so now.
if (loadImmediately)
result = cs.addImplicitLoadExpr(result);
result = forceUnwrapIfExpected(result, locator);
Expr *result = forceUnwrapIfExpected(declRefExpr, locator);
if (auto *fnDecl = dyn_cast<AbstractFunctionDecl>(decl)) {
if (AnyFunctionRef(fnDecl).hasExternalPropertyWrapperParameters() &&
(declRefExpr->getFunctionRefKind() == FunctionRefKind::Compound ||
declRefExpr->getFunctionRefKind() == FunctionRefKind::Unapplied)) {
result = buildSingleCurryThunk(result, fnDecl, locator);
// We don't need to do any further adjustment once we've built the
// curry thunk.
return buildSingleCurryThunk(result, fnDecl,
adjustedFullType->castTo<FunctionType>(),
locator);
}
}
result = adjustTypeForDeclReference(result, fullType, adjustedFullType,
locator);
// If we have to load, do so now.
if (loadImmediately)
result = cs.addImplicitLoadExpr(result);
return result;
}
@@ -1406,41 +1411,20 @@ namespace {
/// parameters.
/// \param declOrClosure The underlying function-like declaration or
/// closure we're going to call.
/// \param thunkTy The type of the resulting thunk. This should be the
/// type of the \c fnExpr, with any potential adjustments for things like
/// concurrency.
/// \param locator The locator pinned on the function reference carried
/// by \p fnExpr. If the function has associated applied property wrappers,
/// the locator is used to pull them in.
AutoClosureExpr *buildSingleCurryThunk(Expr *fnExpr,
DeclContext *declOrClosure,
FunctionType *thunkTy,
ConstraintLocatorBuilder locator) {
auto *const thunkTy = cs.getType(fnExpr)->castTo<FunctionType>();
return buildSingleCurryThunk(/*baseExpr=*/nullptr, fnExpr, declOrClosure,
thunkTy, locator);
}
/// Build a "{ args in base.fn(args) }" single-expression curry thunk.
///
/// \param baseExpr The base expression to be captured.
/// \param fnExpr The expression to be called by consecutively applying
/// the \p baseExpr and thunk parameters.
/// \param declOrClosure The underlying function-like declaration or
/// closure we're going to call.
/// \param locator The locator pinned on the function reference carried
/// by \p fnExpr. If the function has associated applied property wrappers,
/// the locator is used to pull them in.
AutoClosureExpr *buildSingleCurryThunk(Expr *baseExpr, Expr *fnExpr,
DeclContext *declOrClosure,
ConstraintLocatorBuilder locator) {
assert(baseExpr);
auto *const thunkTy = cs.getType(fnExpr)
->castTo<FunctionType>()
->getResult()
->castTo<FunctionType>();
return buildSingleCurryThunk(baseExpr, fnExpr, declOrClosure, thunkTy,
locator);
}
/// Build a "{ self in { args in self.fn(args) } }" nested curry thunk.
///
/// \param memberRef The expression to be called in the inner thunk by
@@ -1909,9 +1893,10 @@ namespace {
// have side effects, instead of abstracting out a 'self' parameter.
const auto isSuperPartialApplication = needsCurryThunk && isSuper;
if (isSuperPartialApplication) {
ref = buildSingleCurryThunk(base, declRefExpr,
cast<AbstractFunctionDecl>(member),
memberLocator);
ref = buildSingleCurryThunk(
base, declRefExpr, cast<AbstractFunctionDecl>(member),
adjustedOpenedType->castTo<FunctionType>(),
memberLocator);
} else if (needsCurryThunk) {
// Another case where we want to build a single closure is when
// we have a partial application of a static member. It is better
@@ -1927,14 +1912,13 @@ namespace {
cs.getType(base));
cs.setType(base, base->getType());
auto *closure = buildSingleCurryThunk(
base, declRefExpr, cast<AbstractFunctionDecl>(member),
memberLocator);
// Skip the code below -- we're not building an extra level of
// call by applying the metatype; instead, the closure we just
// built is the curried reference.
return closure;
return buildSingleCurryThunk(
base, declRefExpr, cast<AbstractFunctionDecl>(member),
adjustedOpenedType->castTo<FunctionType>(),
memberLocator);
} else {
// Add a useless ".self" to avoid downstream diagnostics, in case
// the type ref is still a TypeExpr.
@@ -8874,8 +8858,10 @@ namespace {
rewriteFunction(closure);
if (AnyFunctionRef(closure).hasExternalPropertyWrapperParameters()) {
auto *thunkTy = Rewriter.cs.getType(closure)->castTo<FunctionType>();
return Action::SkipNode(Rewriter.buildSingleCurryThunk(
closure, closure, Rewriter.cs.getConstraintLocator(closure)));
closure, closure, thunkTy,
Rewriter.cs.getConstraintLocator(closure)));
}
return Action::SkipNode(closure);

View File

@@ -0,0 +1,17 @@
// RUN: %target-swift-emit-silgen -verify -disable-objc-attr-requires-foundation-module %s
// RUN: %target-swift-emit-silgen -verify -swift-version 6 -disable-objc-attr-requires-foundation-module %s
// REQUIRES: objc_interop
@objc class C {
@preconcurrency @objc func foo(_ x: Sendable) {}
}
func bar(_ fn: (Any) -> Void) {}
func bar(_ fn: (Sendable) -> Void) {}
// Make sure we can handle both the implicit unwrap and concurrency adjustment.
func foo(_ x: AnyObject) {
bar(x.foo)
let _ = AnyObject.foo
}

View File

@@ -0,0 +1,29 @@
// RUN: %target-swift-emit-silgen %s -verify -swift-version 6
// rdar://140212823 - Make sure we build curry thunks using the adjusted
// reference type, such that the ParenExpr agrees with the type.
class C: @unchecked Sendable {
func foo() {}
}
class D: C, @unchecked Sendable {
func bar() {
let _ = (super.foo)
}
}
struct S {
func instanceMethod() {}
func foo() {
let _ = (self.instanceMethod)
}
static func staticMethod() {}
}
let _ = (S.instanceMethod)
let _ = (type(of: S()).instanceMethod)
let _ = (S.staticMethod)
let _ = (type(of: S()).staticMethod)
let _: (Int, Int) -> Int = (+)

View File

@@ -362,7 +362,7 @@ class Base {
class Derived : Base {
// CHECK-LABEL: sil hidden [ossa] @$s12dynamic_self7DerivedC9superCallyyF : $@convention(method) (@guaranteed Derived) -> ()
// CHECK: convert_function %{{[0-9]+}} : $@callee_guaranteed () -> @owned Base to $@callee_guaranteed () -> @owned Derived
// CHECK: function_ref @$s12dynamic_self7DerivedC9superCallyyFACycfu_ : $@convention(thin) (@guaranteed Derived) -> @owned Derived
// CHECK-COUNT-3: unchecked_ref_cast %{{[0-9]+}} : $Base to $Derived
// CHECK-NOT: unchecked_ref_cast
// CHECK: end sil function '$s12dynamic_self7DerivedC9superCallyyF'
@@ -372,9 +372,12 @@ class Derived : Base {
_ = super.property
_ = super[]
}
// CHECK-LABEL: sil private [ossa] @$s12dynamic_self7DerivedC9superCallyyFACycfu_ : $@convention(thin) (@guaranteed Derived) -> @owned Derived
// CHECK: unchecked_ref_cast %{{[0-9]+}} : $Base to $Derived
// CHECK: end sil function '$s12dynamic_self7DerivedC9superCallyyFACycfu_'
// CHECK-LABEL: sil hidden [ossa] @$s12dynamic_self7DerivedC15superCallStaticyyFZ : $@convention(method) (@thick Derived.Type) -> ()
// CHECK: convert_function %{{[0-9]+}} : $@callee_guaranteed () -> @owned Base to $@callee_guaranteed () -> @owned Derived
// CHECK: function_ref @$s12dynamic_self7DerivedC15superCallStaticyyFZACycfu_ : $@convention(thin) (@thick Derived.Type) -> @owned Derived
// CHECK-COUNT-3: unchecked_ref_cast %{{[0-9]+}} : $Base to $Derived
// CHECK-NOT: unchecked_ref_cast
// CHECK: end sil function '$s12dynamic_self7DerivedC15superCallStaticyyFZ'
@@ -384,9 +387,12 @@ class Derived : Base {
_ = super.staticProperty
_ = super[]
}
// CHECK-LABEL: sil private [ossa] @$s12dynamic_self7DerivedC15superCallStaticyyFZACycfu_ : $@convention(thin) (@thick Derived.Type) -> @owned Derived
// CHECK: unchecked_ref_cast %{{[0-9]+}} : $Base to $Derived
// CHECK: end sil function '$s12dynamic_self7DerivedC15superCallStaticyyFZACycfu_'
// CHECK-LABEL: sil hidden [ossa] @$s12dynamic_self7DerivedC32superCallFromMethodReturningSelfACXDyF : $@convention(method) (@guaranteed Derived) -> @owned Derived
// CHECK: convert_function %{{[0-9]+}} : $@callee_guaranteed () -> @owned Base to $@callee_guaranteed () -> @owned Derived
// CHECK: function_ref @$s12dynamic_self7DerivedC32superCallFromMethodReturningSelfACXDyFACXDycfu_ : $@convention(thin) (@guaranteed Derived) -> @owned Derived
// CHECK-COUNT-3: unchecked_ref_cast %{{[0-9]+}} : $Base to $Derived
// CHECK-NOT: unchecked_ref_cast
// CHECK: end sil function '$s12dynamic_self7DerivedC32superCallFromMethodReturningSelfACXDyF'
@@ -396,9 +402,12 @@ class Derived : Base {
_ = super[]
return super.property
}
// CHECK-LABEL: sil private [ossa] @$s12dynamic_self7DerivedC32superCallFromMethodReturningSelfACXDyFACXDycfu_ : $@convention(thin) (@guaranteed Derived) -> @owned Derived
// CHECK: unchecked_ref_cast %{{[0-9]+}} : $Base to $Derived
// CHECK: end sil function '$s12dynamic_self7DerivedC32superCallFromMethodReturningSelfACXDyFACXDycfu_'
// CHECK-LABEL: sil hidden [ossa] @$s12dynamic_self7DerivedC38superCallFromMethodReturningSelfStaticACXDyFZ : $@convention(method) (@thick Derived.Type) -> @owned Derived
// CHECK: convert_function %{{[0-9]+}} : $@callee_guaranteed () -> @owned Base to $@callee_guaranteed () -> @owned Derived
// CHECK: function_ref @$s12dynamic_self7DerivedC38superCallFromMethodReturningSelfStaticACXDyFZACXDycfu_ : $@convention(thin) (@thick @dynamic_self Derived.Type) -> @owned Derived
// CHECK-COUNT-3: unchecked_ref_cast %{{[0-9]+}} : $Base to $Derived
// CHECK-NOT: unchecked_ref_cast
// CHECK: end sil function '$s12dynamic_self7DerivedC38superCallFromMethodReturningSelfStaticACXDyFZ'
@@ -408,6 +417,9 @@ class Derived : Base {
_ = super[]
return super.staticProperty
}
// CHECK-LABEL: sil private [ossa] @$s12dynamic_self7DerivedC38superCallFromMethodReturningSelfStaticACXDyFZACXDycfu_ : $@convention(thin) (@thick @dynamic_self Derived.Type) -> @owned Derived
// CHECK: unchecked_ref_cast %{{[0-9]+}} : $Base to $Derived
// CHECK: end sil function '$s12dynamic_self7DerivedC38superCallFromMethodReturningSelfStaticACXDyFZACXDycfu_'
}
class Generic<T> {

View File

@@ -37,3 +37,33 @@ func test(from request: Request) {
// for preconcurrency
let _ = request.identifier
}
@propertyWrapper
struct Wrapper<T> {
var wrappedValue: T
init(wrappedValue: T) {
self.wrappedValue = wrappedValue
}
init(projectedValue: Self) {
self = projectedValue
}
var projectedValue: Self { self }
}
// rdar://140212823 - Make sure we can handle the Sendable promotion of `y` in
// the curry thunk.
@preconcurrency func hasWrapperAndPreconcurrency(@Wrapper _ x: Int, _ y: Sendable) {}
struct HasWrapperAndPreconcurrency {
@preconcurrency func instanceMethod(@Wrapper _ x: Int, _ y: Sendable) {}
@preconcurrency static func staticMethod(@Wrapper _ x: Int, _ y: Sendable) {}
}
func testPropertyWrapperPreconcurrencyThunk(_ x: HasWrapperAndPreconcurrency) {
let fn = (hasWrapperAndPreconcurrency)
fn(0, C())
_ = (HasWrapperAndPreconcurrency.staticMethod)
_ = (type(of: x).staticMethod)
_ = (x.instanceMethod)
_ = (type(of: x).instanceMethod)
}