Files
swift-mirror/lib/SILGen/ResultPlan.h
Michael Gottesman 227ab376cf [silgen] When emitting a foreign async completion handler for a method, use merge isolation region to tie self and the block storage into the same region.
This is an extension of a similar problem that I had fixed earlier where due to
the usage of intermediate Sendable types we do not propagate regions correctly.

The previous issue I fixed was that we were not properly tieing the result of a
foreign async completion handler to the block storage since we used an
intervening UnsafeContinuation (which is Sendable) to propagate the result into
the block storage. I fixed this by changing SILGen to insert a
merge_isolation_region that explicitly ties the result to the block storage.

This new issue is that the block that we create and then pass as the completion
handler is an @Sendable block. Thus when we call the actual objc_method, the
block storage and self are not viewed as being in the same region. In this PR, I
change it so that we add a merge_isolation_region from self onto the block
storage.

The end result of this is that we have that self, the result of the call, and
the block storage are all in the same region meaning that we properly diagnose
that returning an NSObject from the imported Objective-C function is task
isolated and thus we cannot return it as a sending result.

rdar://131422332
2025-04-23 10:01:24 -07:00

136 lines
4.9 KiB
C++

//===--- ResultPlan.h -------------------------------------------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_SILGEN_RESULTPLAN_H
#define SWIFT_SILGEN_RESULTPLAN_H
#include "Callee.h"
#include "ExecutorBreadcrumb.h"
#include "Initialization.h"
#include "ManagedValue.h"
#include "swift/AST/Types.h"
#include "swift/Basic/Assertions.h"
#include "swift/Basic/LLVM.h"
#include "swift/SIL/SILLocation.h"
#include <memory>
namespace swift {
class CanType;
class SILValue;
namespace Lowering {
class AbstractionPattern;
class Initialization;
class RValue;
class SILGenFunction;
class SGFContext;
class CalleeTypeInfo;
/// An abstract class for working with results.of applies.
class ResultPlan {
public:
virtual RValue finish(SILGenFunction &SGF, SILLocation loc,
ArrayRef<ManagedValue> &directResults,
SILValue bridgedForeignError) = 0;
virtual void finishAndAddTo(SILGenFunction &SGF, SILLocation loc,
ArrayRef<ManagedValue> &directResults,
SILValue bridgedForeignError,
RValue &result);
virtual ~ResultPlan() = default;
/// Defers the emission of the given breadcrumb until \p finish is invoked.
virtual void deferExecutorBreadcrumb(ExecutorBreadcrumb &&breadcrumb) {
llvm_unreachable("this ResultPlan does not handle deferred breadcrumbs!");
}
virtual void
gatherIndirectResultAddrs(SILGenFunction &SGF, SILLocation loc,
SmallVectorImpl<SILValue> &outList) const = 0;
virtual std::optional<std::pair<ManagedValue, ManagedValue>>
emitForeignErrorArgument(SILGenFunction &SGF, SILLocation loc) {
return std::nullopt;
}
virtual ManagedValue
emitForeignAsyncCompletionHandler(SILGenFunction &SGF,
AbstractionPattern origFormalType,
ManagedValue self, SILLocation loc) {
return {};
}
};
using ResultPlanPtr = std::unique_ptr<ResultPlan>;
/// The class for building result plans.
struct ResultPlanBuilder {
SILGenFunction &SGF;
SILLocation loc;
const CalleeTypeInfo &calleeTypeInfo;
/// A list of all of the results that we are tracking in reverse order. The
/// reason that it is in reverse order is to allow us to simply traverse the
/// list by popping values off the back.
SmallVector<SILResultInfo, 8> allResults;
ResultPlanBuilder(SILGenFunction &SGF, SILLocation loc,
const CalleeTypeInfo &calleeTypeInfo)
: SGF(SGF), loc(loc), calleeTypeInfo(calleeTypeInfo),
// We reverse the order so we can pop values off the back.
allResults(llvm::reverse(calleeTypeInfo.substFnType->getResults())) {}
ResultPlanPtr build(Initialization *emitInto, AbstractionPattern origType,
CanType substType);
ResultPlanPtr buildForScalar(Initialization *emitInto,
AbstractionPattern origType,
CanType substType,
SILResultInfo result);
ResultPlanPtr buildForTuple(Initialization *emitInto,
AbstractionPattern origType,
CanType substType);
ResultPlanPtr
buildForPackExpansion(std::optional<ArrayRef<Initialization *>> inits,
AbstractionPattern origExpansionType,
CanTupleEltTypeArrayRef substTypes);
ResultPlanPtr buildPackExpansionIntoPack(SILValue packAddr,
CanPackType formalPackType,
unsigned componentIndex,
Initialization *init,
AbstractionPattern origType);
ResultPlanPtr buildScalarIntoPack(SILValue packAddr,
CanPackType formalPackType,
unsigned componentIndex,
Initialization *init,
AbstractionPattern origType);
static ResultPlanPtr computeResultPlan(SILGenFunction &SGF,
const CalleeTypeInfo &calleeTypeInfo,
SILLocation loc,
SGFContext evalContext);
~ResultPlanBuilder() {
assert(allResults.empty() && "didn't consume all results!");
}
private:
ResultPlanPtr buildTopLevelResult(Initialization *init, SILLocation loc);
};
} // end namespace Lowering
} // end namespace swift
#endif