mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[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:
@@ -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);
|
||||
|
||||
17
test/Concurrency/preconcurrency_anyobject_lookup.swift
Normal file
17
test/Concurrency/preconcurrency_anyobject_lookup.swift
Normal 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
|
||||
}
|
||||
29
test/Constraints/rdar140212823.swift
Normal file
29
test/Constraints/rdar140212823.swift
Normal 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 = (+)
|
||||
@@ -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> {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user