mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
When a Swift declaration witnesses an ObjC protocol requirement, its error convention needs to match the requirement. Furthermore, if there are different protocol requirements that the Swift method can witness, with different error conventions, we need to bail out because we can't simultaneously match all of them. Fixes rdar://problem/59496036 | SR-12201.
200 lines
7.0 KiB
C++
200 lines
7.0 KiB
C++
//===--- ForeignErrorConvention.h - Error conventions -----------*- 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file defines the ForeignErrorConvention structure, which
|
|
// describes the rules for how to detect that a foreign API returns an
|
|
// error.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef SWIFT_FOREIGN_ERROR_CONVENTION_H
|
|
#define SWIFT_FOREIGN_ERROR_CONVENTION_H
|
|
|
|
#include "swift/AST/Type.h"
|
|
|
|
namespace swift {
|
|
|
|
/// A small structure describing the error convention of a foreign declaration.
|
|
class ForeignErrorConvention {
|
|
public:
|
|
enum Kind {
|
|
/// An error is indicated by a zero result. The function has
|
|
/// been imported as returning Void.
|
|
///
|
|
/// This convention provides a result type, which has a single
|
|
/// field of integer type.
|
|
ZeroResult,
|
|
|
|
/// An error is indicated by a non-zero result. The function has
|
|
/// been imported as returning Void.
|
|
///
|
|
/// This convention provides a result type, which has a single
|
|
/// field of integer type.
|
|
NonZeroResult,
|
|
|
|
/// An error is indicated by a zero result, but the rest of the
|
|
/// result is meaningful.
|
|
ZeroPreservedResult,
|
|
|
|
/// An error is indicated by a nil result. The function has been
|
|
/// imported as returning a non-optional type (which is not
|
|
/// address-only).
|
|
NilResult,
|
|
|
|
/// An error is indicated by a non-nil error value being left in
|
|
/// the error parameter.
|
|
NonNilError,
|
|
};
|
|
|
|
/// Is the error owned by the caller, given that it exists?
|
|
enum IsOwned_t : bool {
|
|
IsNotOwned = false, IsOwned = true
|
|
};
|
|
|
|
/// Was the error parameter replaced by () or just removed?
|
|
enum IsReplaced_t : bool {
|
|
IsNotReplaced = false, IsReplaced = true
|
|
};
|
|
|
|
struct Info {
|
|
unsigned TheKind : 8;
|
|
unsigned ErrorIsOwned : 1;
|
|
unsigned ErrorParameterIsReplaced : 1;
|
|
unsigned ErrorParameterIndex : 22;
|
|
|
|
Info(Kind kind, unsigned parameterIndex, IsOwned_t isOwned,
|
|
IsReplaced_t isReplaced)
|
|
: TheKind(unsigned(kind)), ErrorIsOwned(bool(isOwned)),
|
|
ErrorParameterIsReplaced(bool(isReplaced)),
|
|
ErrorParameterIndex(parameterIndex) {
|
|
assert(parameterIndex == ErrorParameterIndex &&
|
|
"parameter index overflowed");
|
|
}
|
|
|
|
Info() = default;
|
|
};
|
|
|
|
private:
|
|
Info info;
|
|
|
|
/// The error parameter type. This is currently assumed to be an
|
|
/// indirect out-parameter.
|
|
CanType ErrorParameterType;
|
|
|
|
/// The result type. This is meaningful only for ZeroResult and
|
|
/// NonZeroResult.
|
|
CanType ResultType;
|
|
|
|
ForeignErrorConvention(Kind kind, unsigned parameterIndex, IsOwned_t isOwned,
|
|
IsReplaced_t isReplaced, Type parameterType,
|
|
Type resultType = Type())
|
|
: info(kind, parameterIndex, isOwned, isReplaced),
|
|
ErrorParameterType(parameterType), ResultType(resultType) {}
|
|
|
|
public:
|
|
static ForeignErrorConvention getZeroResult(unsigned parameterIndex,
|
|
IsOwned_t isOwned,
|
|
IsReplaced_t isReplaced,
|
|
CanType parameterType,
|
|
CanType resultType) {
|
|
return { ZeroResult, parameterIndex, isOwned, isReplaced,
|
|
parameterType, resultType };
|
|
}
|
|
|
|
static ForeignErrorConvention getNonZeroResult(unsigned parameterIndex,
|
|
IsOwned_t isOwned,
|
|
IsReplaced_t isReplaced,
|
|
CanType parameterType,
|
|
CanType resultType) {
|
|
return { NonZeroResult, parameterIndex, isOwned, isReplaced,
|
|
parameterType, resultType };
|
|
}
|
|
|
|
static ForeignErrorConvention getZeroPreservedResult(unsigned parameterIndex,
|
|
IsOwned_t isOwned,
|
|
IsReplaced_t isReplaced,
|
|
CanType parameterType) {
|
|
return { ZeroPreservedResult, parameterIndex, isOwned, isReplaced,
|
|
parameterType };
|
|
}
|
|
|
|
static ForeignErrorConvention getNilResult(unsigned parameterIndex,
|
|
IsOwned_t isOwned,
|
|
IsReplaced_t isReplaced,
|
|
CanType parameterType) {
|
|
return { NilResult, parameterIndex, isOwned, isReplaced, parameterType };
|
|
}
|
|
|
|
static ForeignErrorConvention getNonNilError(unsigned parameterIndex,
|
|
IsOwned_t isOwned,
|
|
IsReplaced_t isReplaced,
|
|
CanType parameterType) {
|
|
return { NonNilError, parameterIndex, isOwned, isReplaced, parameterType };
|
|
}
|
|
|
|
/// Returns the error convention in use.
|
|
Kind getKind() const {
|
|
return Kind(info.TheKind);
|
|
}
|
|
|
|
/// Returns true if this convention strips a layer of optionality
|
|
/// from the formal result type.
|
|
bool stripsResultOptionality() const {
|
|
return getKind() == Kind::NilResult;
|
|
}
|
|
|
|
/// Returns the index of the error parameter.
|
|
unsigned getErrorParameterIndex() const {
|
|
return info.ErrorParameterIndex;
|
|
}
|
|
|
|
/// Has the error parameter been replaced with void?
|
|
IsReplaced_t isErrorParameterReplacedWithVoid() const {
|
|
return IsReplaced_t(info.ErrorParameterIsReplaced);
|
|
}
|
|
|
|
/// Returns whether the error result is owned. It's assumed that the
|
|
/// error parameter should be ignored if no error is present (unless
|
|
/// it needs to be checked explicitly to determine that).
|
|
IsOwned_t isErrorOwned() const {
|
|
return IsOwned_t(info.ErrorIsOwned);
|
|
}
|
|
|
|
/// Returns the type of the error parameter. Assumed to be an
|
|
/// UnsafeMutablePointer<T?> for some T.
|
|
CanType getErrorParameterType() const {
|
|
return ErrorParameterType;
|
|
}
|
|
|
|
/// Returns the physical result type of the function, for functions
|
|
/// that completely erase this information.
|
|
CanType getResultType() const {
|
|
assert(getKind() == ZeroResult ||
|
|
getKind() == NonZeroResult);
|
|
return ResultType;
|
|
}
|
|
|
|
bool operator==(ForeignErrorConvention other) const {
|
|
return info.TheKind == other.info.TheKind
|
|
&& info.ErrorIsOwned == other.info.ErrorIsOwned
|
|
&& info.ErrorParameterIsReplaced == other.info.ErrorParameterIsReplaced
|
|
&& info.ErrorParameterIndex == other.info.ErrorParameterIndex;
|
|
}
|
|
bool operator!=(ForeignErrorConvention other) const {
|
|
return !(*this == other);
|
|
}
|
|
};
|
|
|
|
}
|
|
|
|
#endif
|