Skip to content

Commit

Permalink
SILGen for 'rethrows'. WIP; committed to get broader testing
Browse files Browse the repository at this point in the history
of an assertion.

Swift SVN r28733
  • Loading branch information
rjmccall committed May 19, 2015
1 parent 155507d commit 26a9a4d
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 34 deletions.
58 changes: 33 additions & 25 deletions lib/SILGen/SILGenApply.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1755,13 +1755,13 @@ static SILValue emitRawApply(SILGenFunction &gen,
resultType, subs, argValues);

// Otherwise, we need to create a try_apply.
// TODO: other error patterns.
} else {
SILBasicBlock *normalBB = gen.createBasicBlock();
result = normalBB->createBBArg(resultType);

SILBasicBlock *errorBB =
gen.getTryApplyErrorDest(loc, substFnType->getErrorResult());
gen.getTryApplyErrorDest(loc, substFnType->getErrorResult(),
options & ApplyOptions::DoesNotThrow);

gen.B.createTryApply(loc, fnValue, calleeType, subs, argValues,
normalBB, errorBB);
Expand All @@ -1774,9 +1774,9 @@ static SILValue emitRawApply(SILGenFunction &gen,
// Be sure to use a CleanupLocation so that unreachable code diagnostics don't
// trigger.
for (auto i : indices(args)) {

if (!inputTypes[i].isGuaranteed() || args[i].isPlusZeroRValueOrTrivial())
continue;

SILValue argValue = args[i].forward(gen);
SILType argType = argValue.getType();
CleanupLocation cleanupLoc = CleanupLocation::get(loc);
Expand Down Expand Up @@ -2024,8 +2024,9 @@ ManagedValue SILGenFunction::emitApply(
// Force immediate writeback to the error temporary.
errorTempWriteback.reset();

managedScalar = emitForeignErrorCheck(loc, managedScalar,
errorTemp, *foreignError);
bool doesNotThrow = (options & ApplyOptions::DoesNotThrow);
managedScalar = emitForeignErrorCheck(loc, managedScalar, errorTemp,
doesNotThrow, *foreignError);
}

// Fast path: no abstraction differences or bridging.
Expand Down Expand Up @@ -2927,21 +2928,23 @@ namespace {

private:
ArgumentSource ArgValue;
bool Throws;

public:
CallSite(ApplyExpr *apply)
: Loc(apply), SubstResultType(apply->getType()->getCanonicalType()),
ArgValue(apply->getArg()) {
ArgValue(apply->getArg()), Throws(apply->throws()) {
}

CallSite(SILLocation loc, Expr *expr, Type resultType)
: Loc(loc), SubstResultType(resultType->getCanonicalType()),
ArgValue(expr) {
CallSite(SILLocation loc, ArgumentSource &&value,
CanType resultType, bool throws)
: Loc(loc), SubstResultType(resultType),
ArgValue(std::move(value)), Throws(throws) {
}

CallSite(SILLocation loc, ArgumentSource &&value, Type resultType)
: Loc(loc), SubstResultType(resultType->getCanonicalType()),
ArgValue(std::move(value)) {
CallSite(SILLocation loc, ArgumentSource &&value,
CanAnyFunctionType fnType)
: CallSite(loc, std::move(value), fnType.getResult(), fnType->throws()) {
}

/// Return the substituted, unlowered AST type of the argument.
Expand All @@ -2955,6 +2958,8 @@ namespace {
return SubstResultType;
}

bool throws() const { return Throws; }

void emit(SILGenFunction &gen, AbstractionPattern origParamType,
ParamLowering &lowering, SmallVectorImpl<ManagedValue> &args,
SmallVectorImpl<InOutArgument> &inoutArgs,
Expand Down Expand Up @@ -3156,6 +3161,10 @@ namespace {
(uncurriedSites.size() == 2 &&
substFnType->hasSelfParam()));

if (!uncurriedSites.back().throws()) {
initialOptions |= ApplyOptions::DoesNotThrow;
}

// Collect the arguments to the uncurried call.
for (auto &site : uncurriedSites) {
AbstractionPattern origParamType =
Expand Down Expand Up @@ -3305,7 +3314,7 @@ static CallEmission prepareApplyExpr(SILGenFunction &gen, Expr *e) {
// Apply 'self' if provided.
if (apply.SelfParam)
emission.addCallSite(RegularLocation(e), std::move(apply.SelfParam),
apply.SelfType);
apply.SelfType->getCanonicalType(), /*throws*/ false);

// Apply arguments from call sites, innermost to outermost.
for (auto site = apply.CallSites.rbegin(), end = apply.CallSites.rend();
Expand Down Expand Up @@ -3665,15 +3674,15 @@ emitGetAccessor(SILLocation loc, SILDeclRef get,
CallEmission emission(*this, std::move(getter), std::move(writebackScope));
// Self ->
if (selfValue) {
emission.addCallSite(loc, std::move(selfValue), accessType.getResult());
emission.addCallSite(loc, std::move(selfValue), accessType);
accessType = cast<AnyFunctionType>(accessType.getResult());
}
// Index or () if none.
if (!subscripts)
subscripts = emitEmptyTupleRValue(loc, SGFContext());

emission.addCallSite(loc, ArgumentSource(loc, std::move(subscripts)),
accessType.getResult());
accessType);

// T
return emission.apply(c);
Expand Down Expand Up @@ -3703,7 +3712,7 @@ void SILGenFunction::emitSetAccessor(SILLocation loc, SILDeclRef set,
CallEmission emission(*this, std::move(setter), std::move(writebackScope));
// Self ->
if (selfValue) {
emission.addCallSite(loc, std::move(selfValue), accessType.getResult());
emission.addCallSite(loc, std::move(selfValue), accessType);
accessType = cast<AnyFunctionType>(accessType.getResult());
}

Expand All @@ -3719,7 +3728,7 @@ void SILGenFunction::emitSetAccessor(SILLocation loc, SILDeclRef set,
setValue.rewriteType(accessType.getInput());
}
emission.addCallSite(loc, ArgumentSource(loc, std::move(setValue)),
accessType.getResult());
accessType);
// ()
emission.apply();
}
Expand Down Expand Up @@ -3753,7 +3762,7 @@ emitMaterializeForSetAccessor(SILLocation loc, SILDeclRef materializeForSet,
CallEmission emission(*this, std::move(callee), std::move(writebackScope));
// Self ->
if (selfValue) {
emission.addCallSite(loc, std::move(selfValue), accessType.getResult());
emission.addCallSite(loc, std::move(selfValue), accessType);
accessType = cast<AnyFunctionType>(accessType.getResult());
}

Expand All @@ -3774,8 +3783,7 @@ emitMaterializeForSetAccessor(SILLocation loc, SILDeclRef materializeForSet,
}
return RValue(elts, accessType.getInput());
}();
emission.addCallSite(loc, ArgumentSource(loc, std::move(args)),
accessType.getResult());
emission.addCallSite(loc, ArgumentSource(loc, std::move(args)), accessType);
// (buffer, optionalCallback)
SILValue pointerAndOptionalCallback = emission.apply().getUnmanagedValue();

Expand Down Expand Up @@ -3823,15 +3831,15 @@ emitAddressorAccessor(SILLocation loc, SILDeclRef addressor,
CallEmission emission(*this, std::move(callee), std::move(writebackScope));
// Self ->
if (selfValue) {
emission.addCallSite(loc, std::move(selfValue), accessType.getResult());
emission.addCallSite(loc, std::move(selfValue), accessType);
accessType = cast<AnyFunctionType>(accessType.getResult());
}
// Index or () if none.
if (!subscripts)
subscripts = emitEmptyTupleRValue(loc, SGFContext());

emission.addCallSite(loc, ArgumentSource(loc, std::move(subscripts)),
accessType.getResult());
accessType);

// Unsafe{Mutable}Pointer<T> or
// (Unsafe{Mutable}Pointer<T>, Builtin.UnknownPointer) or
Expand Down Expand Up @@ -3896,11 +3904,11 @@ ManagedValue SILGenFunction::emitApplyConversionFunction(SILLocation loc,
CallEmission emission = prepareApplyExpr(*this, funcExpr);
// Rewrite the operand type to the expected argument type, to handle tuple
// conversions etc.
operand.rewriteType(funcExpr->getType()->castTo<FunctionType>()->getInput()
->getCanonicalType());
auto funcTy = cast<FunctionType>(funcExpr->getType()->getCanonicalType());
operand.rewriteType(funcTy.getInput());
// Add the operand as the final callsite.
emission.addCallSite(loc, ArgumentSource(loc, std::move(operand)),
resultType);
resultType->getCanonicalType(), funcTy->throws());
return emission.apply();
}

Expand Down
37 changes: 30 additions & 7 deletions lib/SILGen/SILGenForeignError.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,12 @@ static SILValue emitUnwrapIntegerResult(SILGenFunction &gen,
static ManagedValue
emitResultIsZeroErrorCheck(SILGenFunction &gen, SILLocation loc,
ManagedValue result, ManagedValue errorSlot,
bool zeroIsError) {
bool suppressErrorCheck, bool zeroIsError) {
// Just ignore the call result if we're suppressing the error check.
if (suppressErrorCheck) {
return ManagedValue::forUnmanaged(gen.emitEmptyTuple(loc));
}

SILValue resultValue =
emitUnwrapIntegerResult(gen, loc, result.getUnmanagedValue());
SILValue zero =
Expand All @@ -328,7 +333,8 @@ emitResultIsZeroErrorCheck(SILGenFunction &gen, SILLocation loc,
/// Perform a foreign error check by testing whether the call result is nil.
static ManagedValue
emitResultIsNilErrorCheck(SILGenFunction &gen, SILLocation loc,
ManagedValue origResult, ManagedValue errorSlot) {
ManagedValue origResult, ManagedValue errorSlot,
bool suppressErrorCheck) {
// Take local ownership of the optional result value.
SILValue optionalResult = origResult.forward(gen);

Expand All @@ -338,6 +344,14 @@ emitResultIsNilErrorCheck(SILGenFunction &gen, SILLocation loc,

ASTContext &ctx = gen.getASTContext();

// If we're suppressing the check, just do an unchecked take.
if (suppressErrorCheck) {
SILValue objectResult =
gen.B.createUncheckedEnumData(loc, optionalResult,
ctx.getOptionalSomeDecl(optKind));
return gen.emitManagedRValueWithCleanup(objectResult);
}

// Switch on the optional result.
SILBasicBlock *errorBB = gen.createBasicBlock(FunctionSection::Postmatter);
SILBasicBlock *contBB = gen.createBasicBlock();
Expand All @@ -358,7 +372,11 @@ emitResultIsNilErrorCheck(SILGenFunction &gen, SILLocation loc,
/// Perform a foreign error check by testing whether the error was nil.
static ManagedValue
emitErrorIsNonNilErrorCheck(SILGenFunction &gen, SILLocation loc,
ManagedValue origResult, ManagedValue errorSlot) {
ManagedValue origResult, ManagedValue errorSlot,
bool suppressErrorCheck) {
// If we're suppressing the check, just don't check.
if (suppressErrorCheck) return origResult;

SILValue optionalError = gen.B.createLoad(loc, errorSlot.getValue());

OptionalTypeKind optKind;
Expand Down Expand Up @@ -389,19 +407,24 @@ ManagedValue
SILGenFunction::emitForeignErrorCheck(SILLocation loc,
ManagedValue result,
ManagedValue errorSlot,
bool suppressErrorCheck,
const ForeignErrorConvention &foreignError) {
// All of this is autogenerated.
loc.markAutoGenerated();

switch (foreignError.getKind()) {
case ForeignErrorConvention::ZeroResult:
return emitResultIsZeroErrorCheck(*this, loc, result, errorSlot, true);
return emitResultIsZeroErrorCheck(*this, loc, result, errorSlot,
suppressErrorCheck, true);
case ForeignErrorConvention::NonZeroResult:
return emitResultIsZeroErrorCheck(*this, loc, result, errorSlot, false);
return emitResultIsZeroErrorCheck(*this, loc, result, errorSlot,
suppressErrorCheck, false);
case ForeignErrorConvention::NilResult:
return emitResultIsNilErrorCheck(*this, loc, result, errorSlot);
return emitResultIsNilErrorCheck(*this, loc, result, errorSlot,
suppressErrorCheck);
case ForeignErrorConvention::NonNilError:
return emitErrorIsNonNilErrorCheck(*this, loc, result, errorSlot);
return emitErrorIsNonNilErrorCheck(*this, loc, result, errorSlot,
suppressErrorCheck);
}
llvm_unreachable("bad foreign error convention kind");
}
8 changes: 7 additions & 1 deletion lib/SILGen/SILGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,10 @@ enum class ApplyOptions : unsigned {

/// This call is transparent.
Transparent = 0x1,

/// Suppress the error-handling edge out of the call. This should
/// be used carefully; it's used to implement features like 'rethrows'.
DoesNotThrow = 0x2,
};
inline ApplyOptions operator|(ApplyOptions lhs, ApplyOptions rhs) {
return ApplyOptions(unsigned(lhs) | unsigned(rhs));
Expand Down Expand Up @@ -1135,7 +1139,8 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
};

SILBasicBlock *getTryApplyErrorDest(SILLocation loc,
SILResultInfo exnResult);
SILResultInfo exnResult,
bool isSuppressed);

/// Emit a dynamic member reference.
RValue emitDynamicMemberRefExpr(DynamicMemberRefExpr *e, SGFContext c);
Expand Down Expand Up @@ -1313,6 +1318,7 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
ManagedValue emitForeignErrorCheck(SILLocation loc,
ManagedValue result,
ManagedValue errorSlot,
bool suppressErrorCheck,
const ForeignErrorConvention &foreignError);

//===--------------------------------------------------------------------===//
Expand Down
10 changes: 9 additions & 1 deletion lib/SILGen/SILGenStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -833,7 +833,8 @@ void StmtEmitter::visitFailStmt(FailStmt *S) {
/// try_apply instruction. The block is implicitly emitted and filled in.
SILBasicBlock *
SILGenFunction::getTryApplyErrorDest(SILLocation loc,
SILResultInfo exnResult) {
SILResultInfo exnResult,
bool suppressErrorPath) {
assert(exnResult.getConvention() == ResultConvention::Owned);

// For now, don't try to re-use destination blocks for multiple
Expand All @@ -844,6 +845,13 @@ SILGenFunction::getTryApplyErrorDest(SILLocation loc,
assert(B.hasValidInsertionPoint() && B.insertingAtEndOfBlock());
SavedInsertionPoint savedIP(*this, destBB, FunctionSection::Postmatter);

// If we're suppressing error paths, just wrap it up as unreachable
// and return.
if (suppressErrorPath) {
B.createUnreachable(loc);
return destBB;
}

// We don't want to exit here with a dead cleanup on the stack,
// so push the scope first.
FullExpr scope(Cleanups, CleanupLocation::get(loc));
Expand Down
3 changes: 3 additions & 0 deletions lib/Sema/TypeCheckError.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1343,6 +1343,9 @@ void TypeChecker::checkFunctionErrorHandling(AbstractFunctionDecl *fn) {
if (auto body = fn->getBody()) {
body->walk(checker);
}
if (auto ctor = dyn_cast<ConstructorDecl>(fn))
if (auto superInit = ctor->getSuperInitCall())
superInit->walk(checker);
}

void TypeChecker::checkInitializerErrorHandling(Initializer *initCtx,
Expand Down

0 comments on commit 26a9a4d

Please sign in to comment.