Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6856,7 +6856,13 @@ Type ConstructorDecl::getInitializerInterfaceType() {
return InitializerInterfaceType;

// Lazily calculate initializer type.
auto funcTy = getInterfaceType()->castTo<AnyFunctionType>()->getResult();
auto allocatorTy = getInterfaceType();
if (!allocatorTy->is<AnyFunctionType>()) {
InitializerInterfaceType = ErrorType::get(getASTContext());
return InitializerInterfaceType;
}

auto funcTy = allocatorTy->castTo<AnyFunctionType>()->getResult();
assert(funcTy->is<FunctionType>());

// Constructors have an initializer type that takes an instance
Expand Down
19 changes: 19 additions & 0 deletions lib/SILGen/SILGenExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -931,6 +931,25 @@ RValue RValueEmitter::visitOtherConstructorDeclRefExpr(
}

RValue RValueEmitter::visitNilLiteralExpr(NilLiteralExpr *E, SGFContext C) {
// Peephole away the call to Optional<T>(nilLiteral: ()).
if (E->getType()->getOptionalObjectType()) {
auto *noneDecl = SGF.getASTContext().getOptionalNoneDecl();
auto enumTy = SGF.getLoweredType(E->getType());

ManagedValue noneValue;
if (enumTy.isLoadable(SGF.F) || !SGF.silConv.useLoweredAddresses()) {
noneValue = ManagedValue::forUnmanaged(
SGF.B.createEnum(E, SILValue(), noneDecl, enumTy));
} else {
noneValue =
SGF.B.bufferForExpr(E, enumTy, SGF.getTypeLowering(enumTy), C,
[&](SILValue newAddr) {
SGF.B.createInjectEnumAddr(E, newAddr, noneDecl);
});
}
return RValue(SGF, E, noneValue);
}

return SGF.emitLiteral(E, C);
}

Expand Down
50 changes: 10 additions & 40 deletions lib/Sema/CSApply.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1912,57 +1912,27 @@ namespace {
}

Expr *visitNilLiteralExpr(NilLiteralExpr *expr) {
auto type = simplifyType(cs.getType(expr));

// By far the most common 'nil' literal is for Optional<T>.none.
// We don't have to look up the witness in this case since SILGen
// knows how to lower it directly.
if (auto objectType = type->getOptionalObjectType()) {
cs.setType(expr, type);
return expr;
}

auto &tc = cs.getTypeChecker();
auto *protocol = tc.getProtocol(expr->getLoc(),
KnownProtocolKind::ExpressibleByNilLiteral);

// For type-sugar reasons, prefer the spelling of the default literal
// type.
auto type = simplifyType(cs.getType(expr));
if (auto defaultType = tc.getDefaultType(protocol, dc)) {
if (defaultType->isEqual(type))
type = defaultType;
}

// By far the most common 'nil' literal is for Optional<T>.none.
//
// Emit this case directly instead of calling Optional.init(nilLiteral:),
// since this generates more efficient SIL.
if (auto objectType = type->getOptionalObjectType()) {
auto *nilDecl = tc.Context.getOptionalNoneDecl();
tc.validateDecl(nilDecl);
if (!nilDecl->hasInterfaceType())
return nullptr;

auto genericSig =
nilDecl->getDeclContext()->getGenericSignatureOfContext();
SubstitutionMap subs =
SubstitutionMap::get(genericSig, llvm::makeArrayRef(objectType),
{ });
ConcreteDeclRef concreteDeclRef(nilDecl, subs);

auto nilType = FunctionType::get(
{FunctionType::Param(MetatypeType::get(type))}, type);
auto *nilRefExpr = new (tc.Context) DeclRefExpr(
concreteDeclRef, DeclNameLoc(expr->getLoc()),
/*implicit=*/true, AccessSemantics::Ordinary,
nilType);
cs.cacheType(nilRefExpr);

auto *typeExpr = TypeExpr::createImplicitHack(
expr->getLoc(),
type,
tc.Context);
cs.cacheType(typeExpr);

auto *callExpr = new (tc.Context) DotSyntaxCallExpr(
nilRefExpr, expr->getLoc(), typeExpr, type);
callExpr->setImplicit(true);
cs.cacheType(callExpr);

return callExpr;
}

DeclName initName(tc.Context, DeclBaseName::createConstructor(),
{ tc.Context.Id_nilLiteral });
return convertLiteralInPlace(expr, type, protocol,
Expand Down
Loading