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
46 changes: 33 additions & 13 deletions lib/SILGen/SILGenApply.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5727,6 +5727,8 @@ SILValue SILGenFunction::emitApplyWithRethrow(SILLocation loc, SILValue fn,
{
B.emitBlock(errorBB);

Scope scope(Cleanups, CleanupLocation(loc));

// Grab the inner error.
SILValue innerError;
bool hasInnerIndirectError = fnConv.hasIndirectSILErrorResults();
Expand Down Expand Up @@ -5754,25 +5756,43 @@ SILValue SILGenFunction::emitApplyWithRethrow(SILLocation loc, SILValue fn,
outerError = innerError;
} else {
// The error requires some kind of translation.

// Load the inner error, if it was returned indirectly.
if (innerError->getType().isAddress()) {
innerError = emitLoad(loc, innerError, getTypeLowering(innerErrorType),
SGFContext(), IsTake).forward(*this);
}
outerErrorType = outerErrorType.getObjectType();

// If we need to convert the error type, do so now.
if (innerErrorType != outerErrorType) {
auto conversion = Conversion::getOrigToSubst(
AbstractionPattern(innerErrorType.getASTType()),
outerErrorType.getASTType(),
outerErrorType);
outerError = emitConvertedRValue(loc, conversion, SGFContext(),
[innerError](SILGenFunction &SGF, SILLocation loc, SGFContext C) {
return ManagedValue::forForwardedRValue(SGF, innerError);
assert(outerErrorType == SILType::getExceptionType(getASTContext()));

ProtocolConformanceRef conformances[1] = {
getModule().getSwiftModule()->conformsToProtocol(
innerError->getType().getASTType(),
getASTContext().getErrorDecl())
};

outerError = emitExistentialErasure(
loc,
innerErrorType.getASTType(),
getTypeLowering(innerErrorType),
getTypeLowering(outerErrorType),
getASTContext().AllocateCopy(conformances),
SGFContext(),
[&](SGFContext C) -> ManagedValue {
if (innerError->getType().isAddress()) {
return emitLoad(loc, innerError,
getTypeLowering(innerErrorType), SGFContext(),
IsTake);
}

return ManagedValue::forForwardedRValue(*this, innerError);
}).forward(*this);
} else if (innerError->getType().isAddress()) {
// Load the inner error, if it was returned indirectly.
outerError = emitLoad(loc, innerError, getTypeLowering(innerErrorType),
SGFContext(), IsTake).forward(*this);
} else {
outerError = innerError;
}


// If the outer error is returned indirectly, copy from the converted
// inner error to the outer error slot.
if (IndirectErrorResult) {
Expand Down
23 changes: 20 additions & 3 deletions lib/Sema/TypeCheckEffects.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -718,6 +718,17 @@ class Classification {
return result;
}

/// Return a classification that promotes a typed throws effect to an
/// untyped throws effect.
Classification promoteToUntypedThrows() const {
if (!hasThrows())
return *this;

Classification result(*this);
result.ThrownError = ThrownError->getASTContext().getErrorExistentialType();
return result;
}

/// Return a classification that only retains the parts of this
/// classification for the requested effect kind.
Classification onlyEffect(EffectKind kind) const {
Expand Down Expand Up @@ -1109,9 +1120,15 @@ class ApplyClassifier {
}

for (unsigned i = 0, e = params.size(); i < e; ++i) {
result.merge(classifyArgument(args->getExpr(i),
params[i].getParameterType(),
kind));
auto argClassification = classifyArgument(
args->getExpr(i), params[i].getParameterType(), kind);

// Rethrows is untyped, so
if (kind == EffectKind::Throws) {
argClassification = argClassification.promoteToUntypedThrows();
}

result.merge(argClassification);
}

return;
Expand Down
3 changes: 1 addition & 2 deletions test/Profiler/coverage_closure_returns_never.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@
// CHECK-NOT: increment_profiler_counter
// CHECK: [[LOAD:%.*]] = load {{.*}} : $*Never
// CHECK-NEXT: debug_value [[LOAD]] : $Never
// CHECK-NEXT: debug_value undef : $any Error, var, name "$error", argno
// CHECK-NEXT: unreachable
// CHECK: unreachable

func closure_with_fatal_error(_ arr: [Never]) {
// CHECK-LABEL: sil_coverage_map {{.*}}// closure #1 (Swift.Never) -> Swift.Never
Expand Down
8 changes: 8 additions & 0 deletions test/decl/func/typed_throws.swift
Original file line number Diff line number Diff line change
Expand Up @@ -146,3 +146,11 @@ extension Either: Error where First: Error, Second: Error { }
func f<E1, E2>(_ error: Either<E1, E2>) throws(Either<E1, E2>) {
throw error
}

// Ensure that calls to 'rethrows' functions are always treated as throwing `any
// Error`.
func rethrowingFunc(body: () throws -> Void) rethrows { }

func typedCallsRethrowingFunc<E>(body: () throws(E) -> Void) throws(E) {
try rethrowingFunc(body: body) // expected-error{{thrown expression type 'any Error' cannot be converted to error type 'E'}}
}