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:
Doug Gregor
2014-09-15 23:59:30 +00:00
parent e60b5f4d99
commit d93eaed9f7
13 changed files with 108 additions and 56 deletions

View File

@@ -57,32 +57,38 @@ 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(),
/*implicit*/ true,
/*direct access*/false,
convertFuncTy);
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 = new (C) CallExpr(call, arg, /*implicit*/ true,
// 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;
}