mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Switch BooleanLiteralConvertible over to an initializer requirement.
Conforming to BooleanLiteralConvertible now requires init(booleanLiteral: Bool) rather than static func convertFromBooleanLiteral(value: Bool) -> Self This posed a problem for NSNumber's conformance to BooleanLiteralConvertible. A class needs a required initializer to satisfy an initializer requirement, but one cannot add a required initializer via an extension. To that end, we hack the Clang importer to import NSNumber's initWithBool with the name init(booleanLiteral:) and add back the expected init(bool:) initializer in the overlay. These tricks make NSNumber even harder to subclass, but we don't really care: it's nearly impossible to do well anyway, and is generally a Bad Idea. Part of rdar://problem/18154091. Swift SVN r21961
This commit is contained in:
@@ -72,9 +72,8 @@ IDENTIFIER_WITH_NAME(ConvertFromFloatLiteral, "convertFromFloatLiteral")
|
||||
IDENTIFIER_WITH_NAME(ConvertFromBuiltinFloatLiteral,
|
||||
"_convertFromBuiltinFloatLiteral")
|
||||
IDENTIFIER(BooleanLiteralType)
|
||||
IDENTIFIER_WITH_NAME(ConvertFromBooleanLiteral, "convertFromBooleanLiteral")
|
||||
IDENTIFIER_WITH_NAME(ConvertFromBuiltinBooleanLiteral,
|
||||
"_convertFromBuiltinBooleanLiteral")
|
||||
IDENTIFIER_WITH_NAME(BuiltinBooleanLiteral, "_builtinBooleanLiteral")
|
||||
IDENTIFIER_WITH_NAME(BooleanLiteral, "booleanLiteral")
|
||||
|
||||
IDENTIFIER(CharacterLiteralType)
|
||||
IDENTIFIER_WITH_NAME(ConvertFromCharacterLiteral,
|
||||
|
||||
@@ -427,6 +427,13 @@ ClangImporter::create(ASTContext &ctx,
|
||||
importer->Impl.setObjectForKeyedSubscript
|
||||
= clangContext.Selectors.getSelector(2, setObjectForKeyedSubscriptIdents);
|
||||
|
||||
// Create the selectors for literal conformances.
|
||||
clang::IdentifierInfo *initWithBoolIdents[1] = {
|
||||
&clangContext.Idents.get("initWithBool")
|
||||
};
|
||||
importer->Impl.initWithBool
|
||||
= clangContext.Selectors.getSelector(1, initWithBoolIdents);
|
||||
|
||||
// Set up the imported header module.
|
||||
auto *importedHeaderModule = Module::create(ctx.getIdentifier("__ObjC"), ctx);
|
||||
importer->Impl.ImportedHeaderUnit =
|
||||
|
||||
@@ -2482,6 +2482,17 @@ namespace {
|
||||
return Impl.mapSelectorToDeclName(selector, /*initializer*/true);
|
||||
}
|
||||
|
||||
/// Determine whether the given class is NSNumber or a subclass thereof.
|
||||
static bool isNSNumberSubclass(const clang::ObjCInterfaceDecl *classDecl) {
|
||||
if (!classDecl)
|
||||
return nullptr;
|
||||
|
||||
if (classDecl->getName() == "NSNumber")
|
||||
return true;
|
||||
|
||||
return isNSNumberSubclass(classDecl->getSuperClass());
|
||||
}
|
||||
|
||||
/// \brief Given an imported method, try to import it as a constructor.
|
||||
///
|
||||
/// Objective-C methods in the 'init' family are imported as
|
||||
@@ -2548,6 +2559,17 @@ namespace {
|
||||
bool &redundant) {
|
||||
redundant = false;
|
||||
|
||||
// Map NSNumber's initializers over to their corresponding literal-
|
||||
// conversion initializers.
|
||||
// FIXME: This would go away if we could implement convenience factory
|
||||
// initializers in Swift.
|
||||
if (objcMethod->getSelector() == Impl.initWithBool &&
|
||||
isNSNumberSubclass(objcMethod->getClassInterface())) {
|
||||
name = DeclName(Impl.SwiftContext, Impl.SwiftContext.Id_init,
|
||||
{ Impl.SwiftContext.Id_BooleanLiteral });
|
||||
required = true;
|
||||
}
|
||||
|
||||
// Figure out the type of the container.
|
||||
auto containerTy = dc->getDeclaredTypeOfContext();
|
||||
assert(containerTy && "Method in non-type context?");
|
||||
@@ -2637,6 +2659,10 @@ namespace {
|
||||
ctor->getAttrs().isUnavailable(Impl.SwiftContext))
|
||||
continue;
|
||||
|
||||
// Resolve the type of the constructor.
|
||||
if (!ctor->hasType())
|
||||
Impl.getTypeResolver()->resolveDeclSignature(ctor);
|
||||
|
||||
// If the types don't match, this is a different constructor with
|
||||
// the same selector. This can happen when an overlay overloads an
|
||||
// existing selector with a Swift-only signature.
|
||||
|
||||
@@ -486,6 +486,9 @@ public:
|
||||
/// \brief Clang's setObject:forKeyedSubscript: selector.
|
||||
clang::Selector setObjectForKeyedSubscript;
|
||||
|
||||
/// Clang's initWithBool: selector.
|
||||
clang::Selector initWithBool;
|
||||
|
||||
private:
|
||||
Optional<Module *> checkedFoundationModule;
|
||||
|
||||
|
||||
@@ -166,7 +166,7 @@ Type Solution::computeSubstitutions(Type origType, DeclContext *dc,
|
||||
/// \returns The named witness.
|
||||
template <typename DeclTy>
|
||||
static DeclTy *findNamedWitnessImpl(TypeChecker &tc, DeclContext *dc, Type type,
|
||||
ProtocolDecl *proto, Identifier name,
|
||||
ProtocolDecl *proto, DeclName name,
|
||||
Diag<> diag) {
|
||||
// Find the named requirement.
|
||||
DeclTy *requirement = nullptr;
|
||||
@@ -175,7 +175,7 @@ static DeclTy *findNamedWitnessImpl(TypeChecker &tc, DeclContext *dc, Type type,
|
||||
if (!d || !d->hasName())
|
||||
continue;
|
||||
|
||||
if (d->getName() == name) {
|
||||
if (d->getFullName().matchesRef(name)) {
|
||||
requirement = d;
|
||||
break;
|
||||
}
|
||||
@@ -854,10 +854,10 @@ namespace {
|
||||
Type openedType,
|
||||
ProtocolDecl *protocol,
|
||||
TypeOrName literalType,
|
||||
Identifier literalFuncName,
|
||||
DeclName literalFuncName,
|
||||
ProtocolDecl *builtinProtocol,
|
||||
TypeOrName builtinLiteralType,
|
||||
Identifier builtinLiteralFuncName,
|
||||
DeclName builtinLiteralFuncName,
|
||||
bool (*isBuiltinArgType)(Type),
|
||||
Diag<> brokenProtocolDiag,
|
||||
Diag<> brokenBuiltinProtocolDiag);
|
||||
@@ -1395,17 +1395,21 @@ namespace {
|
||||
return nullptr;
|
||||
|
||||
auto type = simplifyType(expr->getType());
|
||||
DeclName initName(tc.Context, tc.Context.Id_init,
|
||||
{ tc.Context.Id_BooleanLiteral });
|
||||
DeclName builtinInitName(tc.Context, tc.Context.Id_init,
|
||||
{ tc.Context.Id_BuiltinBooleanLiteral });
|
||||
return convertLiteral(
|
||||
expr,
|
||||
type,
|
||||
expr->getType(),
|
||||
protocol,
|
||||
tc.Context.Id_BooleanLiteralType,
|
||||
tc.Context.Id_ConvertFromBooleanLiteral,
|
||||
initName,
|
||||
builtinProtocol,
|
||||
Type(BuiltinIntegerType::get(BuiltinIntegerWidth::fixed(1),
|
||||
tc.Context)),
|
||||
tc.Context.Id_ConvertFromBuiltinBooleanLiteral,
|
||||
builtinInitName,
|
||||
nullptr,
|
||||
diag::boolean_literal_broken_proto,
|
||||
diag::builtin_boolean_literal_broken_proto);
|
||||
@@ -4187,10 +4191,10 @@ Expr *ExprRewriter::convertLiteral(Expr *literal,
|
||||
Type openedType,
|
||||
ProtocolDecl *protocol,
|
||||
TypeOrName literalType,
|
||||
Identifier literalFuncName,
|
||||
DeclName literalFuncName,
|
||||
ProtocolDecl *builtinProtocol,
|
||||
TypeOrName builtinLiteralType,
|
||||
Identifier builtinLiteralFuncName,
|
||||
DeclName builtinLiteralFuncName,
|
||||
bool (*isBuiltinArgType)(Type),
|
||||
Diag<> brokenProtocolDiag,
|
||||
Diag<> brokenBuiltinProtocolDiag) {
|
||||
@@ -4948,7 +4952,7 @@ Expr *Solution::coerceToType(Expr *expr, Type toType,
|
||||
Expr *TypeChecker::callWitness(Expr *base, DeclContext *dc,
|
||||
ProtocolDecl *protocol,
|
||||
ProtocolConformance *conformance,
|
||||
Identifier name,
|
||||
DeclName name,
|
||||
MutableArrayRef<Expr *> arguments,
|
||||
Diag<> brokenProtocolDiag) {
|
||||
// Construct an empty constraint system and solution.
|
||||
@@ -4959,7 +4963,8 @@ Expr *TypeChecker::callWitness(Expr *base, DeclContext *dc,
|
||||
if (auto metaType = type->getAs<AnyMetatypeType>())
|
||||
type = metaType->getInstanceType();
|
||||
|
||||
auto witness = findNamedWitness(*this, dc, type->getRValueType(), protocol,
|
||||
auto witness = findNamedWitnessImpl<AbstractFunctionDecl>(
|
||||
*this, dc, type->getRValueType(), protocol,
|
||||
name, brokenProtocolDiag);
|
||||
if (!witness)
|
||||
return nullptr;
|
||||
@@ -4975,17 +4980,25 @@ Expr *TypeChecker::callWitness(Expr *base, DeclContext *dc,
|
||||
|
||||
// Form the call argument.
|
||||
Expr *arg;
|
||||
if (arguments.size() == 1)
|
||||
if (arguments.size() == 1 && name.isSimpleName()) {
|
||||
arg = arguments[0];
|
||||
else {
|
||||
} else {
|
||||
SmallVector<TupleTypeElt, 4> elementTypes;
|
||||
for (auto elt : arguments)
|
||||
elementTypes.push_back(TupleTypeElt(elt->getType()));
|
||||
auto names = witness->getFullName().getArgumentNames();
|
||||
unsigned i = 0;
|
||||
for (auto elt : arguments) {
|
||||
Identifier name;
|
||||
if (i < names.size())
|
||||
name = names[i];
|
||||
|
||||
elementTypes.push_back(TupleTypeElt(elt->getType(), name));
|
||||
++i;
|
||||
}
|
||||
|
||||
arg = TupleExpr::create(Context,
|
||||
base->getStartLoc(),
|
||||
arguments,
|
||||
witness->getFullName().getArgumentNames(),
|
||||
names,
|
||||
{ },
|
||||
base->getEndLoc(),
|
||||
/*hasTrailingClosure=*/false,
|
||||
|
||||
@@ -57,31 +57,37 @@ static Expr *getBooleanLiteral(ASTContext &C, bool value) {
|
||||
// need to rely on it already having been type-checked. This only
|
||||
// matters when building the standard library.
|
||||
auto boolDecl = C.getBoolDecl();
|
||||
auto convertFunc
|
||||
= boolDecl->lookupDirect(C.Id_ConvertFromBuiltinBooleanLiteral)[0];
|
||||
auto convertFuncAppliedTy = FunctionType::get(ParenType::get(C, i1Ty),
|
||||
DeclName initName(C, C.Id_init, { C.Id_BuiltinBooleanLiteral });
|
||||
|
||||
auto convertInit = boolDecl->lookupDirect(initName)[0];
|
||||
auto convertFuncParamTy = TupleType::get(
|
||||
{TupleTypeElt(i1Ty, C.Id_BuiltinBooleanLiteral)},
|
||||
C);
|
||||
auto convertFuncAppliedTy = FunctionType::get(convertFuncParamTy,
|
||||
boolDecl->getDeclaredType());
|
||||
auto convertFuncTy = FunctionType::get(boolDecl->getType(),
|
||||
convertFuncAppliedTy);
|
||||
assert(!convertFunc->hasType() ||
|
||||
convertFunc->getType()->isEqual(convertFuncTy) &&
|
||||
"_convertFromBuiltinBooleanLiteral has unexpected type");
|
||||
auto convertRef = new (C) DeclRefExpr(convertFunc, SourceLoc(),
|
||||
assert(!convertInit->hasType() ||
|
||||
convertInit->getType()->isEqual(convertFuncTy) &&
|
||||
"init(_builtinBooleanLiteral:) has unexpected type");
|
||||
auto initRef = new (C) DeclRefExpr(convertInit, SourceLoc(),
|
||||
/*implicit*/ true,
|
||||
/*direct access*/false,
|
||||
convertFuncTy);
|
||||
|
||||
// Form Bool._convertFromBuiltinBooleanLiteral
|
||||
// Form Bool.init(_builtinBooleanLiteral:).
|
||||
auto boolRef = TypeExpr::createImplicit(boolDecl->getDeclaredType(), C);
|
||||
Expr *call = new (C) DotSyntaxCallExpr(convertRef, SourceLoc(), boolRef);
|
||||
Expr *call = new (C) ConstructorRefCallExpr(initRef, boolRef,
|
||||
convertFuncAppliedTy);
|
||||
call->setImplicit(true);
|
||||
call->setType(convertFuncAppliedTy);
|
||||
|
||||
// Call Bool._convertFromBuiltinBooleanLiteral.
|
||||
Expr *arg = new (C) ParenExpr(SourceLoc(), lit, SourceLoc(),
|
||||
/*has trailing closure*/ false,
|
||||
lit->getType());
|
||||
arg->setImplicit();
|
||||
// Call Bool.init(_builtinBooleanLiteral:).
|
||||
Expr *arg = TupleExpr::create(
|
||||
C, SourceLoc(), lit,
|
||||
{ C.Id_BuiltinBooleanLiteral }, { SourceLoc() },
|
||||
SourceLoc(), /*hasTrailingClosure=*/false,
|
||||
/*Implicit=*/true, convertFuncParamTy);
|
||||
|
||||
call = new (C) CallExpr(call, arg, /*implicit*/ true,
|
||||
boolDecl->getDeclaredType());
|
||||
return call;
|
||||
|
||||
@@ -929,7 +929,7 @@ public:
|
||||
Expr *callWitness(Expr *base, DeclContext *dc,
|
||||
ProtocolDecl *protocol,
|
||||
ProtocolConformance *conformance,
|
||||
Identifier name,
|
||||
DeclName name,
|
||||
MutableArrayRef<Expr *> arguments,
|
||||
Diag<> brokenProtocolDiag);
|
||||
|
||||
|
||||
@@ -26,14 +26,13 @@ public struct Bool {
|
||||
|
||||
extension Bool : _BuiltinBooleanLiteralConvertible, BooleanLiteralConvertible {
|
||||
@transparent
|
||||
public static func _convertFromBuiltinBooleanLiteral(value: Builtin.Int1)
|
||||
-> Bool {
|
||||
return Bool(value)
|
||||
public init(_builtinBooleanLiteral value: Builtin.Int1) {
|
||||
self.value = value
|
||||
}
|
||||
|
||||
@transparent
|
||||
public static func convertFromBooleanLiteral(value: Bool) -> Bool {
|
||||
return value
|
||||
public init(booleanLiteral value: Bool) {
|
||||
self = value
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -228,13 +228,12 @@ public protocol FloatLiteralConvertible {
|
||||
}
|
||||
|
||||
public protocol _BuiltinBooleanLiteralConvertible {
|
||||
class func _convertFromBuiltinBooleanLiteral(
|
||||
value: Builtin.Int1) -> Self
|
||||
init(_builtinBooleanLiteral value: Builtin.Int1)
|
||||
}
|
||||
|
||||
public protocol BooleanLiteralConvertible {
|
||||
typealias BooleanLiteralType : _BuiltinBooleanLiteralConvertible
|
||||
class func convertFromBooleanLiteral(value: BooleanLiteralType) -> Self
|
||||
init(booleanLiteral value: BooleanLiteralType)
|
||||
}
|
||||
|
||||
public protocol _BuiltinCharacterLiteralConvertible {
|
||||
|
||||
@@ -585,8 +585,8 @@ extension NSNumber : FloatLiteralConvertible, IntegerLiteralConvertible,
|
||||
return self(double: value)
|
||||
}
|
||||
|
||||
public class func convertFromBooleanLiteral(value: Bool) -> Self {
|
||||
return self(bool: value)
|
||||
public convenience init(bool value: Bool) {
|
||||
self.init(booleanLiteral: value)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -54,8 +54,8 @@ public struct ObjCBool : BooleanType, BooleanLiteralConvertible {
|
||||
}
|
||||
|
||||
@transparent
|
||||
public static func convertFromBooleanLiteral(value: Bool) -> ObjCBool {
|
||||
return ObjCBool(value)
|
||||
public init(booleanLiteral value: Bool) {
|
||||
self.init(value)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,14 +17,14 @@ func matchesEither(#input: Hive, #a: Hive, #b: Hive) -> Bool {
|
||||
// CHECK: br [[RET_TRUE]]
|
||||
case a, b:
|
||||
// CHECK: [[RET_TRUE]]:
|
||||
// CHECK: function_ref @_TFSb33_convertFromBuiltinBooleanLiteral
|
||||
// CHECK: function_ref @_TFSbCfMSbFT22_builtinBooleanLiteralBi1__Sb
|
||||
return true
|
||||
|
||||
// CHECK: [[NOT_CASE2]]:
|
||||
// CHECK: br [[RET_FALSE:bb[0-9]+]]
|
||||
default:
|
||||
// CHECK: [[RET_FALSE]]:
|
||||
// CHECK: function_ref @_TFSb33_convertFromBuiltinBooleanLiteral
|
||||
// CHECK: function_ref @_TFSbCfMSbFT22_builtinBooleanLiteralBi1__Sb
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,8 +13,8 @@ func defaultBoolLiterals() {
|
||||
struct CustomBool : BooleanLiteralConvertible {
|
||||
let value: Bool
|
||||
|
||||
static func convertFromBooleanLiteral(value: Bool) -> CustomBool {
|
||||
return CustomBool(value: value)
|
||||
init(booleanLiteral value: Bool) {
|
||||
self.value = value
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user