Skip to content

Commit

Permalink
Merge pull request #34358 from jckarter/imported-async-type-lowering
Browse files Browse the repository at this point in the history
Type lowering and SILGen for imported ObjC async decls.
  • Loading branch information
jckarter committed Oct 29, 2020
2 parents ed3ac15 + 7ab9e87 commit 096828e
Show file tree
Hide file tree
Showing 19 changed files with 591 additions and 247 deletions.
2 changes: 2 additions & 0 deletions docs/ABI/Mangling.rst
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,8 @@ types where the metadata itself has unknown layout.)
global ::= global 'Tm' // merged function
global ::= entity // some identifiable thing
global ::= from-type to-type generic-signature? 'TR' // reabstraction thunk
global ::= from-type to-type generic-signature? 'TR' // reabstraction thunk
global ::= impl-function-type 'Tz' // objc-to-swift-async completion handler block implementation
global ::= from-type to-type self-type generic-signature? 'Ty' // reabstraction thunk with dynamic 'Self' capture
global ::= from-type to-type generic-signature? 'Tr' // obsolete mangling for reabstraction thunk
global ::= entity generic-signature? type type* 'TK' // key path getter
Expand Down
33 changes: 21 additions & 12 deletions include/swift/AST/ForeignAsyncConvention.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,42 +26,51 @@ namespace swift {
class ForeignAsyncConvention {
public:
struct Info {
private:
/// The index of the completion handler parameters.
unsigned CompletionHandlerParamIndex;

/// When non-zero, indicates which parameter to the completion handler is
/// the Error? parameter (minus one) that makes this async function also
/// throwing.
unsigned CompletionHandlerErrorParamIndex;

unsigned CompletionHandlerErrorParamIndexPlusOneOrZero;

public:
Info()
: CompletionHandlerParamIndex(0), CompletionHandlerErrorParamIndex(0) { }
: CompletionHandlerParamIndex(0),
CompletionHandlerErrorParamIndexPlusOneOrZero(0) { }

Info(
unsigned completionHandlerParamIndex,
Optional<unsigned> completionHandlerErrorParamIndex)
: CompletionHandlerParamIndex(completionHandlerParamIndex),
CompletionHandlerErrorParamIndex(
CompletionHandlerErrorParamIndexPlusOneOrZero(
completionHandlerErrorParamIndex
? *completionHandlerErrorParamIndex + 1
: 0) {}

/// Retrieve the index of the completion handler argument in the method's
/// parameter list.
unsigned completionHandlerParamIndex() const {
return CompletionHandlerParamIndex;
}

/// Retrieve the index of the \c Error? parameter in the completion handler's
/// parameter list. When argument passed to this parameter is non-null, the
/// provided error will be thrown by the async function.
Optional<unsigned> completionHandlerErrorParamIndex() const {
if (CompletionHandlerErrorParamIndex == 0)
if (CompletionHandlerErrorParamIndexPlusOneOrZero == 0)
return None;

return CompletionHandlerErrorParamIndex - 1;
return CompletionHandlerErrorParamIndexPlusOneOrZero - 1;
}

/// Whether the async function is throwing due to the completion handler
/// having an \c Error? parameter.
///
/// Equivalent to \c static_cast<bool>(completionHandlerErrorParamIndex()).
bool isThrowing() const {
return CompletionHandlerErrorParamIndex != 0;
return CompletionHandlerErrorParamIndexPlusOneOrZero != 0;
}
};

Expand All @@ -88,7 +97,7 @@ class ForeignAsyncConvention {
/// Retrieve the index of the completion handler parameter, which will be
/// erased from the Swift signature of the imported async function.
unsigned completionHandlerParamIndex() const {
return TheInfo.CompletionHandlerParamIndex;
return TheInfo.completionHandlerParamIndex();
}

/// Retrieve the index of the \c Error? parameter in the completion handler's
Expand All @@ -108,10 +117,10 @@ class ForeignAsyncConvention {

bool operator==(ForeignAsyncConvention other) const {
return CompletionHandlerType == other.CompletionHandlerType
&& TheInfo.CompletionHandlerParamIndex ==
other.TheInfo.CompletionHandlerParamIndex
&& TheInfo.CompletionHandlerErrorParamIndex ==
other.TheInfo.CompletionHandlerErrorParamIndex;
&& TheInfo.completionHandlerParamIndex()
== other.TheInfo.completionHandlerParamIndex()
&& TheInfo.completionHandlerErrorParamIndex()
== other.TheInfo.completionHandlerErrorParamIndex();
}

bool operator!=(ForeignAsyncConvention other) const {
Expand Down
2 changes: 2 additions & 0 deletions include/swift/AST/ForeignInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#ifndef SWIFT_FOREIGN_INFO_H
#define SWIFT_FOREIGN_INFO_H

#include "swift/AST/ForeignAsyncConvention.h"
#include "swift/AST/ForeignErrorConvention.h"
#include "swift/AST/Decl.h"

Expand All @@ -27,6 +28,7 @@ namespace swift {
struct ForeignInfo {
ImportAsMemberStatus Self;
Optional<ForeignErrorConvention> Error;
Optional<ForeignAsyncConvention> Async;
};

} // end namespace swift
Expand Down
1 change: 1 addition & 0 deletions include/swift/Demangling/DemangleNodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ CONTEXT_NODE(NativePinningMutableAddressor)
NODE(NominalTypeDescriptor)
NODE(NonObjCAttribute)
NODE(Number)
NODE(ObjCAsyncCompletionHandlerImpl)
NODE(ObjCAttribute)
NODE(ObjCBlock)
NODE(EscapingObjCBlock)
Expand Down
156 changes: 118 additions & 38 deletions include/swift/SIL/AbstractionPattern.h
Original file line number Diff line number Diff line change
Expand Up @@ -260,46 +260,116 @@ class AbstractionPattern {
OpaqueDerivativeFunction,
};

class EncodedForeignErrorInfo {
class EncodedForeignInfo {
unsigned Value;

enum Error_t {
Error,
};

enum Async_t {
Async,
};

public:
enum ForeignKind {
IsNotForeign,
IsError,
IsAsync,
};

private:
friend AbstractionPattern;

EncodedForeignInfo() : Value(0) {}
EncodedForeignInfo(Error_t,
unsigned errorParameterIndex,
bool replaceParamWithVoid,
bool stripsResultOptionality)
: Value(1
+ (unsigned(IsError) - 1)
+ (unsigned(stripsResultOptionality) << 1)
+ (unsigned(replaceParamWithVoid) << 2)
+ (errorParameterIndex << 3)) {
assert(getKind() == IsError);
assert(getErrorParamIndex() == errorParameterIndex);
assert(hasErrorParameterReplacedWithVoid() == replaceParamWithVoid);
assert(errorStripsResultOptionality() == stripsResultOptionality);
}

EncodedForeignInfo(Async_t,
unsigned completionParameterIndex,
Optional<unsigned> completionErrorParameterIndex)
: Value(1
+ (unsigned(IsAsync) - 1)
+ (unsigned(completionParameterIndex) << 1)
+ ((completionErrorParameterIndex ? *completionErrorParameterIndex + 1
: 0) << 21)) {
assert(getKind() == IsAsync);
assert(getAsyncCompletionHandlerParamIndex() == completionParameterIndex);
assert(getAsyncCompletionHandlerErrorParamIndex() == completionErrorParameterIndex);
}

public:
EncodedForeignErrorInfo() : Value(0) {}
EncodedForeignErrorInfo(unsigned errorParameterIndex,
bool replaceParamWithVoid,
bool stripsResultOptionality)
: Value(1 +
(unsigned(stripsResultOptionality)) +
(unsigned(replaceParamWithVoid) << 1) +
(errorParameterIndex << 2)) {}

static EncodedForeignErrorInfo
encode(const Optional<ForeignErrorConvention> &foreignError);
static EncodedForeignInfo
encode(const Optional<ForeignErrorConvention> &foreignError,
const Optional<ForeignAsyncConvention> &foreignAsync);

bool hasValue() const { return Value != 0; }
bool hasErrorParameter() const { return hasValue(); }
bool hasUnreplacedErrorParameter() const {
return hasValue() && !isErrorParameterReplacedWithVoid();
ForeignKind getKind() const {
if (!hasValue())
return IsNotForeign;

return ForeignKind((Value - 1 & 1) + 1);
}

bool errorStripsResultOptionality() const {
if (getKind() != IsError) return false;
return (Value - 1) & 2;
}

bool stripsResultOptionality() const {
assert(hasValue());
return (Value - 1) & 1;
bool hasErrorParameterReplacedWithVoid() const {
if (getKind() != IsError) return false;
return (Value - 1) & 4;
}

bool isErrorParameterReplacedWithVoid() const {
assert(hasValue());
return (Value - 1) & 2;
unsigned getErrorParamIndex() const {
assert(getKind() == IsError);
return (Value - 1) >> 3;
}

unsigned getAsyncCompletionHandlerParamIndex() const {
assert(getKind() == IsAsync);
return ((Value - 1) >> 1) & 0xFFFFFu;
}

Optional<unsigned> getAsyncCompletionHandlerErrorParamIndex() const {
assert(getKind() == IsAsync);

unsigned getErrorParameterIndex() const {
assert(hasValue());
return (Value - 1) >> 2;
unsigned encodedValue = (Value - 1) >> 21;
if (encodedValue == 0) {
return llvm::None;
}
return encodedValue - 1;
}

unsigned getForeignParamIndex() const {
switch (getKind()) {
case IsNotForeign:
llvm_unreachable("no foreign param");

case IsError:
return getErrorParamIndex();

case IsAsync:
return getAsyncCompletionHandlerParamIndex();
}
llvm_unreachable("uncovered switch");
}

unsigned getOpaqueValue() const { return Value; }
static EncodedForeignErrorInfo fromOpaqueValue(unsigned value) {
EncodedForeignErrorInfo result;
static EncodedForeignInfo fromOpaqueValue(unsigned value) {
EncodedForeignInfo result;
result.Value = value;
return result;
}
Expand Down Expand Up @@ -374,7 +444,7 @@ class AbstractionPattern {
}
}

bool hasStoredForeignErrorInfo() const {
bool hasStoredForeignInfo() const {
return hasStoredObjCMethod();
}

Expand Down Expand Up @@ -411,7 +481,7 @@ class AbstractionPattern {

void initObjCMethod(CanGenericSignature signature,
CanType origType, const clang::ObjCMethodDecl *method,
Kind kind, EncodedForeignErrorInfo errorInfo) {
Kind kind, EncodedForeignInfo errorInfo) {
initSwiftType(signature, origType, kind);
ObjCMethod = method;
OtherData = errorInfo.getOpaqueValue();
Expand Down Expand Up @@ -519,7 +589,8 @@ class AbstractionPattern {
/// Objective-C method.
static AbstractionPattern
getCurriedObjCMethod(CanType origType, const clang::ObjCMethodDecl *method,
const Optional<ForeignErrorConvention> &foreignError);
const Optional<ForeignErrorConvention> &foreignError,
const Optional<ForeignAsyncConvention> &foreignAsync);

/// Return an abstraction pattern for the uncurried type of a C function
/// imported as a method.
Expand Down Expand Up @@ -644,7 +715,7 @@ class AbstractionPattern {
/// Objective-C method.
static AbstractionPattern
getCurriedObjCMethod(CanType origType, const clang::ObjCMethodDecl *method,
EncodedForeignErrorInfo errorInfo) {
EncodedForeignInfo errorInfo) {
assert(isa<AnyFunctionType>(origType));
AbstractionPattern pattern;
pattern.initObjCMethod(nullptr, origType, method,
Expand All @@ -670,7 +741,7 @@ class AbstractionPattern {
getPartialCurriedObjCMethod(CanGenericSignature signature,
CanType origType,
const clang::ObjCMethodDecl *method,
EncodedForeignErrorInfo errorInfo) {
EncodedForeignInfo errorInfo) {
assert(isa<AnyFunctionType>(origType));
AbstractionPattern pattern;
pattern.initObjCMethod(signature, origType, method,
Expand Down Expand Up @@ -733,14 +804,15 @@ class AbstractionPattern {
/// Return an abstraction pattern for the type of an Objective-C method.
static AbstractionPattern
getObjCMethod(CanType origType, const clang::ObjCMethodDecl *method,
const Optional<ForeignErrorConvention> &foreignError);
const Optional<ForeignErrorConvention> &foreignError,
const Optional<ForeignAsyncConvention> &foreignAsync);

private:
/// Return an abstraction pattern for the uncurried type of an
/// Objective-C method.
static AbstractionPattern
getObjCMethod(CanType origType, const clang::ObjCMethodDecl *method,
EncodedForeignErrorInfo errorInfo) {
EncodedForeignInfo errorInfo) {
assert(isa<AnyFunctionType>(origType));
AbstractionPattern pattern;
pattern.initObjCMethod(nullptr, origType, method, Kind::ObjCMethodType,
Expand Down Expand Up @@ -998,9 +1070,9 @@ class AbstractionPattern {
getKind() == Kind::OpaqueDerivativeFunction);
}

EncodedForeignErrorInfo getEncodedForeignErrorInfo() const {
assert(hasStoredForeignErrorInfo());
return EncodedForeignErrorInfo::fromOpaqueValue(OtherData);
EncodedForeignInfo getEncodedForeignInfo() const {
assert(hasStoredForeignInfo());
return EncodedForeignInfo::fromOpaqueValue(OtherData);
}

bool hasForeignErrorStrippingResultOptionality() const {
Expand Down Expand Up @@ -1029,8 +1101,8 @@ class AbstractionPattern {
case Kind::PartialCurriedObjCMethodType:
case Kind::CurriedObjCMethodType:
case Kind::ObjCMethodType: {
auto errorInfo = getEncodedForeignErrorInfo();
return (errorInfo.hasValue() && errorInfo.stripsResultOptionality());
auto errorInfo = getEncodedForeignInfo();
return errorInfo.errorStripsResultOptionality();
}
}
llvm_unreachable("bad kind");
Expand Down Expand Up @@ -1203,6 +1275,14 @@ class AbstractionPattern {
GenericSignature derivativeGenericSignature = GenericSignature(),
bool makeSelfParamFirst = false);

/// If this pattern refers to a foreign ObjC method that was imported as async, this returns
/// the abstraction pattern for the completion callback with the original ObjC block type.
///
/// Otherwise, this produces the default fully-concrete abstraction pattern for the given
/// Swift type.
AbstractionPattern getObjCMethodAsyncCompletionHandlerType(
CanType swiftCompletionHandlerType) const;

void dump() const LLVM_ATTRIBUTE_USED;
void print(raw_ostream &OS) const;
};
Expand Down
4 changes: 2 additions & 2 deletions lib/ClangImporter/ImportName.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1965,12 +1965,12 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D,
method->hasRelatedResultType(), method->isInstanceMethod(),
result.getAsyncInfo().map(
[](const ForeignAsyncConvention::Info &info) {
return info.CompletionHandlerParamIndex;
return info.completionHandlerParamIndex();
}),
result.getAsyncInfo().map(
[&](const ForeignAsyncConvention::Info &info) {
return method->getDeclName().getObjCSelector().getNameForSlot(
info.CompletionHandlerParamIndex);
info.completionHandlerParamIndex());
}),
*this);
}
Expand Down
6 changes: 3 additions & 3 deletions lib/ClangImporter/ImportType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2218,7 +2218,7 @@ ImportedType ClangImporter::Implementation::importMethodParamsAndReturnType(
}

bool paramIsCompletionHandler =
asyncInfo && paramIndex == asyncInfo->CompletionHandlerParamIndex;
asyncInfo && paramIndex == asyncInfo->completionHandlerParamIndex();

// Import the parameter type into Swift.

Expand Down Expand Up @@ -2392,8 +2392,8 @@ ImportedType ClangImporter::Implementation::importMethodParamsAndReturnType(

if (asyncInfo) {
asyncConvention = ForeignAsyncConvention(
completionHandlerType, asyncInfo->CompletionHandlerParamIndex,
asyncInfo->CompletionHandlerErrorParamIndex);
completionHandlerType, asyncInfo->completionHandlerParamIndex(),
asyncInfo->completionHandlerErrorParamIndex());
}

if (errorInfo) {
Expand Down
Loading

0 comments on commit 096828e

Please sign in to comment.