Skip to content

Commit bd09616

Browse files
authored
Merge pull request #3689 from swiftwasm/main
[pull] swiftwasm from main
2 parents 76bbf27 + ca8b660 commit bd09616

File tree

11 files changed

+195
-15
lines changed

11 files changed

+195
-15
lines changed

include/swift/AST/KnownIdentifiers.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,7 @@ IDENTIFIER(identifier)
264264
IDENTIFIER(_distributedActorRemoteInitialize)
265265
IDENTIFIER(_distributedActorDestroy)
266266
IDENTIFIER(__isRemoteActor)
267+
IDENTIFIER(whenLocal)
267268

268269
#undef IDENTIFIER
269270
#undef IDENTIFIER_

include/swift/Sema/ConstraintSystem.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2181,6 +2181,10 @@ class SolutionApplicationTarget {
21812181
using RewriteTargetFn = std::function<
21822182
Optional<SolutionApplicationTarget> (SolutionApplicationTarget)>;
21832183

2184+
/// Represents a conversion restriction between two types.
2185+
using ConversionRestriction =
2186+
std::tuple<TypeBase *, TypeBase *, ConversionRestrictionKind>;
2187+
21842188
enum class ConstraintSystemPhase {
21852189
ConstraintGeneration,
21862190
Solving,
@@ -2367,8 +2371,7 @@ class ConstraintSystem {
23672371
/// there are multiple ways in which one type could convert to another, e.g.,
23682372
/// given class types A and B, the solver might choose either a superclass
23692373
/// conversion or a user-defined conversion.
2370-
std::vector<std::tuple<Type, Type, ConversionRestrictionKind>>
2371-
ConstraintRestrictions;
2374+
std::vector<ConversionRestriction> ConstraintRestrictions;
23722375

23732376
/// The set of fixes applied to make the solution work.
23742377
llvm::SmallVector<ConstraintFix *, 4> Fixes;

lib/Sema/CSDiagnostics.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2957,6 +2957,20 @@ bool ContextualFailure::tryTypeCoercionFixIt(
29572957
if (!toType->hasTypeRepr())
29582958
return false;
29592959

2960+
// If object of the optional type is a subtype of the specified contextual
2961+
// type, let's suggest a force unwrap "!". Otherwise fallback to potential
2962+
// coercion or force cast.
2963+
if (!bothOptional && fromType->getOptionalObjectType()) {
2964+
if (TypeChecker::isSubtypeOf(fromType->lookThroughAllOptionalTypes(),
2965+
toType, getDC())) {
2966+
diagnostic.fixItInsert(
2967+
Lexer::getLocForEndOfToken(getASTContext().SourceMgr,
2968+
getSourceRange().End),
2969+
"!");
2970+
return true;
2971+
}
2972+
}
2973+
29602974
CheckedCastKind Kind =
29612975
TypeChecker::typeCheckCheckedCast(fromType, toType,
29622976
CheckedCastContextKind::None, getDC(),

lib/Sema/CSSimplify.cpp

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3908,9 +3908,8 @@ bool ConstraintSystem::repairFailures(
39083908
// If the result type of the coercion has an value to optional conversion
39093909
// we can instead suggest the conditional downcast as it is safer in
39103910
// situations like conditional binding.
3911-
auto useConditionalCast = llvm::any_of(
3912-
ConstraintRestrictions,
3913-
[&](std::tuple<Type, Type, ConversionRestrictionKind> restriction) {
3911+
auto useConditionalCast =
3912+
llvm::any_of(ConstraintRestrictions, [&](auto &restriction) {
39143913
ConversionRestrictionKind restrictionKind;
39153914
Type type1, type2;
39163915
std::tie(type1, type2, restrictionKind) = restriction;
@@ -6717,7 +6716,9 @@ static bool isCastToExpressibleByNilLiteral(ConstraintSystem &cs, Type fromType,
67176716
static ConstraintFix *maybeWarnAboutExtraneousCast(
67186717
ConstraintSystem &cs, Type origFromType, Type origToType, Type fromType,
67196718
Type toType, SmallVector<Type, 4> fromOptionals,
6720-
SmallVector<Type, 4> toOptionals, ConstraintSystem::TypeMatchOptions flags,
6719+
SmallVector<Type, 4> toOptionals,
6720+
const std::vector<ConversionRestriction> &constraintRestrictions,
6721+
ConstraintSystem::TypeMatchOptions flags,
67216722
ConstraintLocatorBuilder locator) {
67226723

67236724
auto last = locator.last();
@@ -6739,6 +6740,18 @@ static ConstraintFix *maybeWarnAboutExtraneousCast(
67396740
// "from" could be less optional than "to" e.g. `0 as Any?`, so
67406741
// we need to store the difference as a signed integer.
67416742
int extraOptionals = fromOptionals.size() - toOptionals.size();
6743+
6744+
// "from" expression could be a type variable with value-to-optional
6745+
// restrictions that we have to account for optionality mismatch.
6746+
const auto subExprType = cs.getType(castExpr->getSubExpr());
6747+
if (llvm::is_contained(
6748+
constraintRestrictions,
6749+
std::make_tuple(fromType.getPointer(), subExprType.getPointer(),
6750+
ConversionRestrictionKind::ValueToOptional))) {
6751+
extraOptionals++;
6752+
origFromType = OptionalType::get(origFromType);
6753+
}
6754+
67426755
// Removing the optionality from to type when the force cast expr is an IUO.
67436756
const auto *const TR = castExpr->getCastTypeRepr();
67446757
if (isExpr<ForcedCheckedCastExpr>(anchor) && TR &&
@@ -6894,7 +6907,7 @@ ConstraintSystem::simplifyCheckedCastConstraint(
68946907

68956908
if (auto *fix = maybeWarnAboutExtraneousCast(
68966909
*this, origFromType, origToType, fromType, toType, fromOptionals,
6897-
toOptionals, flags, locator)) {
6910+
toOptionals, ConstraintRestrictions, flags, locator)) {
68986911
(void)recordFix(fix);
68996912
}
69006913
};
@@ -6962,7 +6975,7 @@ ConstraintSystem::simplifyCheckedCastConstraint(
69626975
// succeed or fail.
69636976
if (auto *fix = maybeWarnAboutExtraneousCast(
69646977
*this, origFromType, origToType, fromType, toType, fromOptionals,
6965-
toOptionals, flags, locator)) {
6978+
toOptionals, ConstraintRestrictions, flags, locator)) {
69666979
(void)recordFix(fix);
69676980
}
69686981

@@ -11372,7 +11385,8 @@ ConstraintSystem::simplifyRestrictedConstraint(
1137211385
addFixConstraint(fix, matchKind, type1, type2, locator);
1137311386
}
1137411387

11375-
ConstraintRestrictions.push_back(std::make_tuple(type1, type2, restriction));
11388+
ConstraintRestrictions.push_back(
11389+
std::make_tuple(type1.getPointer(), type2.getPointer(), restriction));
1137611390
return SolutionKind::Solved;
1137711391
}
1137811392
case SolutionKind::Unsolved:

lib/Sema/CSSolver.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -231,9 +231,10 @@ void ConstraintSystem::applySolution(const Solution &solution) {
231231
// Register constraint restrictions.
232232
// FIXME: Copy these directly into some kind of partial solution?
233233
for (auto restriction : solution.ConstraintRestrictions) {
234-
ConstraintRestrictions.push_back(
235-
std::make_tuple(restriction.first.first, restriction.first.second,
236-
restriction.second));
234+
auto &types = restriction.first;
235+
ConstraintRestrictions.push_back(std::make_tuple(types.first.getPointer(),
236+
types.second.getPointer(),
237+
restriction.second));
237238
}
238239

239240
// Register the solution's disjunction choices.

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1432,6 +1432,11 @@ namespace {
14321432
bool isPotentiallyIsolated = false;
14331433
if (!var) {
14341434
isPotentiallyIsolated = false;
1435+
} else if (var->getName().str().equals("__secretlyKnownToBeLocal")) {
1436+
// FIXME(distributed): we did a dynamic check and know that this actor is local,
1437+
// but we can't express that to the type system; the real implementation
1438+
// will have to mark 'self' as "known to be local" after an is-local check.
1439+
isPotentiallyIsolated = true;
14351440
} else if (auto param = dyn_cast<ParamDecl>(var)) {
14361441
isPotentiallyIsolated = param->isIsolated();
14371442
} else if (var->isSelfParamCapture()) {

stdlib/public/Distributed/DistributedActor.swift

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,28 @@ extension DistributedActor {
116116
}
117117
}
118118

119+
// ==== Local actor special handling -------------------------------------------
120+
121+
@available(SwiftStdlib 5.5, *)
122+
extension DistributedActor {
123+
124+
/// Executes the passed 'body' only when the distributed actor is local instance.
125+
///
126+
/// The `Self` passed to the the body closure is isolated, meaning that the
127+
/// closure can be used to call non-distributed functions, or even access actor
128+
/// state.
129+
///
130+
/// When the actor is remote, the closure won't be executed and this function will return nil.
131+
public nonisolated func whenLocal<T>(_ body: @Sendable (isolated Self) async throws -> T)
132+
async rethrows -> T? where T: Sendable {
133+
if __isLocalActor(self) {
134+
return try await body(self)
135+
} else {
136+
return nil
137+
}
138+
}
139+
}
140+
119141
/******************************************************************************/
120142
/***************************** Actor Identity *********************************/
121143
/******************************************************************************/

test/Constraints/casts.swift

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -613,3 +613,41 @@ func decodeStringOrIntDictionary<T: FixedWidthInteger>() -> [Int: T] {
613613
fatalError()
614614
}
615615
}
616+
617+
618+
// SR-15281
619+
struct SR15281_A { }
620+
struct SR15281_B {
621+
init(a: SR15281_A) { }
622+
}
623+
624+
struct SR15281_S {
625+
var a: SR15281_A? = SR15281_A()
626+
627+
var b: SR15281_B {
628+
a.flatMap(SR15281_B.init(a:)) // expected-error{{cannot convert return expression of type 'SR15281_B?' to return type 'SR15281_B'}} {{34-34=!}}
629+
}
630+
631+
var b1: SR15281_B {
632+
a.flatMap(SR15281_B.init(a:)) as! SR15281_B
633+
// expected-warning@-1 {{forced cast from 'SR15281_B?' to 'SR15281_B' only unwraps optionals; did you mean to use '!'?}} {{34-34=!}} {{34-48=}}
634+
}
635+
}
636+
637+
class SR15281_AC {}
638+
class SR15281_BC {
639+
init(a: SR15281_AC) { }
640+
}
641+
class SR15281_CC: SR15281_BC {}
642+
643+
struct SR15281_SC {
644+
var a: SR15281_AC? = SR15281_AC()
645+
646+
var b: SR15281_BC {
647+
a.flatMap(SR15281_BC.init(a:)) // expected-error{{cannot convert return expression of type 'SR15281_BC?' to return type 'SR15281_BC'}} {{35-35=!}}
648+
}
649+
650+
var c: SR15281_BC {
651+
a.flatMap(SR15281_CC.init(a:)) // expected-error{{cannot convert return expression of type 'SR15281_CC?' to return type 'SR15281_BC'}} {{35-35=!}}
652+
}
653+
}

test/Distributed/Runtime/distributed_actor_deinit.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
// UNSUPPORTED: use_os_stdlib
88
// UNSUPPORTED: back_deployment_runtime
99

10-
// temporary non-support. tracked in rdar://82593574
10+
// FIXME(distributed): Distributed actors currently have some issues on windows, isRemote always returns false. rdar://82593574
1111
// UNSUPPORTED: windows
1212

1313
import _Distributed
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
// RUN: %target-run-simple-swift( -Xfrontend -disable-availability-checking -Xfrontend -enable-experimental-distributed -parse-as-library) | %FileCheck %s --dump-input=always
2+
3+
// REQUIRES: executable_test
4+
// REQUIRES: concurrency
5+
// REQUIRES: distributed
6+
7+
// rdar://76038845
8+
// UNSUPPORTED: use_os_stdlib
9+
// UNSUPPORTED: back_deployment_runtime
10+
11+
// FIXME(distributed): Distributed actors currently have some issues on windows, isRemote always returns false. rdar://82593574
12+
// UNSUPPORTED: windows
13+
14+
import _Distributed
15+
16+
distributed actor Capybara {
17+
// only the local capybara can do this!
18+
func eat() -> String {
19+
"watermelon"
20+
}
21+
}
22+
23+
24+
// ==== Fake Transport ---------------------------------------------------------
25+
@available(SwiftStdlib 5.5, *)
26+
struct ActorAddress: ActorIdentity {
27+
let address: String
28+
init(parse address: String) {
29+
self.address = address
30+
}
31+
}
32+
33+
@available(SwiftStdlib 5.5, *)
34+
struct FakeTransport: ActorTransport {
35+
func decodeIdentity(from decoder: Decoder) throws -> AnyActorIdentity {
36+
fatalError("not implemented:\(#function)")
37+
}
38+
39+
func resolve<Act>(_ identity: AnyActorIdentity, as actorType: Act.Type)
40+
throws -> Act? where Act: DistributedActor {
41+
return nil
42+
}
43+
44+
func assignIdentity<Act>(_ actorType: Act.Type) -> AnyActorIdentity
45+
where Act: DistributedActor {
46+
let id = ActorAddress(parse: "xxx")
47+
return .init(id)
48+
}
49+
50+
func actorReady<Act>(_ actor: Act) where Act: DistributedActor {
51+
}
52+
53+
func resignIdentity(_ id: AnyActorIdentity) {
54+
}
55+
}
56+
57+
func test() async throws {
58+
let transport = FakeTransport()
59+
60+
let local = Capybara(transport: transport)
61+
// await local.eat() // SHOULD ERROR
62+
let valueWhenLocal: String? = await local.whenLocal { __secretlyKnownToBeLocal in
63+
__secretlyKnownToBeLocal.eat()
64+
}
65+
66+
// CHECK: valueWhenLocal: watermelon
67+
print("valueWhenLocal: \(valueWhenLocal ?? "nil")")
68+
69+
let remote = try Capybara.resolve(local.id, using: transport)
70+
let valueWhenRemote: String? = await remote.whenLocal { __secretlyKnownToBeLocal in
71+
__secretlyKnownToBeLocal.eat()
72+
}
73+
74+
// CHECK: valueWhenRemote: nil
75+
print("valueWhenRemote: \(valueWhenRemote ?? "nil")")
76+
}
77+
78+
@available(SwiftStdlib 5.5, *)
79+
@main struct Main {
80+
static func main() async {
81+
try! await test()
82+
}
83+
}

0 commit comments

Comments
 (0)