Skip to content

Commit a14f280

Browse files
authored
Merge pull request #69087 from DougGregor/typed-throws-conformances
2 parents 66ac1c0 + 7d7c726 commit a14f280

16 files changed

+400
-107
lines changed

include/swift/AST/Decl.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7129,7 +7129,7 @@ class AbstractFunctionDecl : public GenericContext, public ValueDecl {
71297129
///
71307130
/// Functions with untyped throws will produce "any Error", functions that
71317131
/// cannot throw or are specified to throw "Never" will return llvm::None.
7132-
llvm::Optional<Type> getEffectiveThrownInterfaceType() const;
7132+
llvm::Optional<Type> getEffectiveThrownErrorType() const;
71337133

71347134
/// Returns if the function throws or is async.
71357135
bool hasEffect(EffectKind kind) const;

include/swift/AST/TypeMatcher.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,15 @@ class TypeMatcher {
397397
return false;
398398
}
399399

400+
// If requested, compare the thrown error types.
401+
Type thrownError1 = firstFunc->getEffectiveThrownErrorTypeOrNever();
402+
Type thrownError2 = secondFunc->getEffectiveThrownErrorTypeOrNever();
403+
if (Matcher.asDerived().considerThrownErrorTypes(thrownError1,
404+
thrownError2) &&
405+
!this->visit(thrownError1->getCanonicalType(),
406+
thrownError2, thrownError1))
407+
return false;
408+
400409
return this->visit(firstFunc.getResult(), secondFunc->getResult(),
401410
sugaredFirstFunc->getResult());
402411
}
@@ -558,6 +567,10 @@ class TypeMatcher {
558567
return MatchVisitor(*this).visit(first->getCanonicalType(), second,
559568
first);
560569
}
570+
571+
bool considerThrownErrorTypes(Type errorType1, Type errorType2) const {
572+
return false;
573+
}
561574
};
562575

563576
} // end namespace swift

include/swift/AST/Types.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3392,8 +3392,15 @@ class AnyFunctionType : public TypeBase {
33923392
///
33933393
/// Functions with untyped throws will produce "any Error", functions that
33943394
/// cannot throw or are specified to throw "Never" will return llvm::None.
3395-
llvm::Optional<Type> getEffectiveThrownInterfaceType() const;
3396-
3395+
llvm::Optional<Type> getEffectiveThrownErrorType() const;
3396+
3397+
/// Retrieve the "effective" thrown interface type, or `Never` if
3398+
/// this function cannot throw.
3399+
///
3400+
/// Functions with untyped throws will produce `any Error`, functions that
3401+
/// cannot throw or are specified to throw `Never` will return `Never`.
3402+
Type getEffectiveThrownErrorTypeOrNever() const;
3403+
33973404
/// Returns true if the function type stores a Clang type that cannot
33983405
/// be derived from its Swift type. Returns false otherwise, including if
33993406
/// the function type is not @convention(c) or @convention(block).

lib/AST/Decl.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -951,15 +951,15 @@ Type AbstractFunctionDecl::getThrownInterfaceType() const {
951951
}
952952

953953
llvm::Optional<Type>
954-
AbstractFunctionDecl::getEffectiveThrownInterfaceType() const {
954+
AbstractFunctionDecl::getEffectiveThrownErrorType() const {
955955
Type interfaceType = getInterfaceType();
956956
if (hasImplicitSelfDecl()) {
957957
if (auto fnType = interfaceType->getAs<AnyFunctionType>())
958958
interfaceType = fnType->getResult();
959959
}
960960

961961
return interfaceType->castTo<AnyFunctionType>()
962-
->getEffectiveThrownInterfaceType();
962+
->getEffectiveThrownErrorType();
963963
}
964964

965965
Expr *AbstractFunctionDecl::getSingleExpressionBody() const {

lib/AST/Expr.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1937,7 +1937,7 @@ Type AbstractClosureExpr::getResultType(
19371937

19381938
llvm::Optional<Type> AbstractClosureExpr::getEffectiveThrownType() const {
19391939
return getType()->castTo<AnyFunctionType>()
1940-
->getEffectiveThrownInterfaceType();
1940+
->getEffectiveThrownErrorType();
19411941
}
19421942

19431943
bool AbstractClosureExpr::isBodyThrowing() const {

lib/AST/Type.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5419,7 +5419,7 @@ AnyFunctionType *AnyFunctionType::getWithoutThrowing() const {
54195419
return withExtInfo(info);
54205420
}
54215421

5422-
llvm::Optional<Type> AnyFunctionType::getEffectiveThrownInterfaceType() const {
5422+
llvm::Optional<Type> AnyFunctionType::getEffectiveThrownErrorType() const {
54235423
// A non-throwing function... has no thrown interface type.
54245424
if (!isThrowing())
54255425
return llvm::None;
@@ -5437,6 +5437,13 @@ llvm::Optional<Type> AnyFunctionType::getEffectiveThrownInterfaceType() const {
54375437
return thrownError;
54385438
}
54395439

5440+
Type AnyFunctionType::getEffectiveThrownErrorTypeOrNever() const {
5441+
if (auto thrown = getEffectiveThrownErrorType())
5442+
return *thrown;
5443+
5444+
return getASTContext().getNeverType();
5445+
}
5446+
54405447
llvm::Optional<TangentSpace>
54415448
TypeBase::getAutoDiffTangentSpace(LookupConformanceFn lookupConformance) {
54425449
assert(lookupConformance);

lib/SILGen/SILGenBackDeploy.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ void SILGenFunction::emitBackDeploymentThunk(SILDeclRef thunk) {
238238
}
239239

240240
prepareEpilog(getResultInterfaceType(AFD),
241-
AFD->getEffectiveThrownInterfaceType(),
241+
AFD->getEffectiveThrownErrorType(),
242242
CleanupLocation(AFD));
243243

244244
SILBasicBlock *availableBB = createBasicBlock("availableBB");

lib/SILGen/SILGenConstructor.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -680,7 +680,7 @@ void SILGenFunction::emitValueConstructor(ConstructorDecl *ctor) {
680680
// Create a basic block to jump to for the implicit 'self' return.
681681
// We won't emit this until after we've emitted the body.
682682
// The epilog takes a void return because the return of 'self' is implicit.
683-
prepareEpilog(llvm::None, ctor->getEffectiveThrownInterfaceType(),
683+
prepareEpilog(llvm::None, ctor->getEffectiveThrownErrorType(),
684684
CleanupLocation(ctor));
685685

686686
// If the constructor can fail, set up an alternative epilog for constructor
@@ -1185,7 +1185,7 @@ void SILGenFunction::emitClassConstructorInitializer(ConstructorDecl *ctor) {
11851185

11861186
// Create a basic block to jump to for the implicit 'self' return.
11871187
// We won't emit the block until after we've emitted the body.
1188-
prepareEpilog(llvm::None, ctor->getEffectiveThrownInterfaceType(),
1188+
prepareEpilog(llvm::None, ctor->getEffectiveThrownErrorType(),
11891189
CleanupLocation(endOfInitLoc));
11901190

11911191
auto resultType = ctor->mapTypeIntoContext(ctor->getResultInterfaceType());
@@ -1751,7 +1751,7 @@ void SILGenFunction::emitInitAccessor(AccessorDecl *accessor) {
17511751
}
17521752

17531753
prepareEpilog(accessor->getResultInterfaceType(),
1754-
accessor->getEffectiveThrownInterfaceType(),
1754+
accessor->getEffectiveThrownErrorType(),
17551755
CleanupLocation(accessor));
17561756

17571757
emitProfilerIncrement(accessor->getTypecheckedBody());

lib/SILGen/SILGenFunction.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1051,7 +1051,7 @@ void SILGenFunction::emitFunction(FuncDecl *fd) {
10511051
emitDistributedActorFactory(fd);
10521052
} else {
10531053
prepareEpilog(fd->getResultInterfaceType(),
1054-
fd->getEffectiveThrownInterfaceType(), CleanupLocation(fd));
1054+
fd->getEffectiveThrownErrorType(), CleanupLocation(fd));
10551055

10561056
if (fd->requiresUnavailableDeclABICompatibilityStubs())
10571057
emitApplyOfUnavailableCodeReached();

lib/Sema/CSSimplify.cpp

Lines changed: 45 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
#include "CSDiagnostics.h"
1919
#include "TypeCheckConcurrency.h"
20+
#include "TypeCheckEffects.h"
2021
#include "swift/AST/ASTPrinter.h"
2122
#include "swift/AST/Decl.h"
2223
#include "swift/AST/ExistentialLayout.h"
@@ -2945,28 +2946,6 @@ bool ConstraintSystem::hasPreconcurrencyCallee(
29452946
return calleeOverload->choice.getDecl()->preconcurrency();
29462947
}
29472948

2948-
namespace {
2949-
/// Classifies a thrown error kind as Never, a specific type, or 'any Error'.
2950-
enum class ThrownErrorKind {
2951-
Never,
2952-
Specific,
2953-
AnyError,
2954-
};
2955-
2956-
ThrownErrorKind getThrownErrorKind(Type type) {
2957-
if (type->isNever())
2958-
return ThrownErrorKind::Never;
2959-
2960-
if (type->isExistentialType()) {
2961-
Type anyError = type->getASTContext().getErrorExistentialType();
2962-
if (anyError->isEqual(type))
2963-
return ThrownErrorKind::AnyError;
2964-
}
2965-
2966-
return ThrownErrorKind::Specific;
2967-
}
2968-
}
2969-
29702949
/// Match the throwing specifier of the two function types.
29712950
static ConstraintSystem::TypeMatchResult
29722951
matchFunctionThrowing(ConstraintSystem &cs,
@@ -2978,82 +2957,45 @@ matchFunctionThrowing(ConstraintSystem &cs,
29782957
// that throws error type E2 when E1 is a subtype of E2. For the purpose
29792958
// of this comparison, a non-throwing function has thrown error type 'Never',
29802959
// and an untyped throwing function has thrown error type 'any Error'.
2981-
Type neverType = cs.getASTContext().getNeverType();
2982-
Type thrownError1 = func1->getEffectiveThrownInterfaceType().value_or(neverType);
2983-
Type thrownError2 = func2->getEffectiveThrownInterfaceType().value_or(neverType);
2984-
if (!thrownError1 || !thrownError2 || thrownError1->isEqual(thrownError2))
2960+
Type thrownError1 = func1->getEffectiveThrownErrorTypeOrNever();
2961+
Type thrownError2 = func2->getEffectiveThrownErrorTypeOrNever();
2962+
if (!thrownError1 || !thrownError2)
29852963
return cs.getTypeMatchSuccess();
29862964

2987-
auto thrownErrorKind1 = getThrownErrorKind(thrownError1);
2988-
auto thrownErrorKind2 = getThrownErrorKind(thrownError2);
2989-
2990-
bool mustUnify = false;
2991-
bool dropThrows = false;
2992-
2993-
switch (thrownErrorKind1) {
2994-
case ThrownErrorKind::Specific:
2995-
// If the specific thrown error contains no type variables and we're
2996-
// going to try to convert it to \c Never, treat this as dropping throws.
2997-
if (thrownErrorKind2 == ThrownErrorKind::Never &&
2998-
!thrownError1->hasTypeVariable()) {
2999-
dropThrows = true;
3000-
} else {
3001-
// We need to unify the thrown error types.
3002-
mustUnify = true;
3003-
}
3004-
break;
3005-
3006-
case ThrownErrorKind::Never:
3007-
switch (thrownErrorKind2) {
3008-
case ThrownErrorKind::Specific:
3009-
// We need to unify the thrown error types.
3010-
mustUnify = true;
3011-
break;
3012-
3013-
case ThrownErrorKind::Never:
3014-
llvm_unreachable("The thrown error types should have been equal");
3015-
break;
3016-
3017-
case ThrownErrorKind::AnyError:
3018-
// We have a subtype. If we're not allowed to do the subtype,
3019-
// then we need to drop "throws".
3020-
if (kind < ConstraintKind::Subtype)
3021-
dropThrows = true;
3022-
break;
3023-
}
3024-
break;
3025-
3026-
case ThrownErrorKind::AnyError:
3027-
switch (thrownErrorKind2) {
3028-
case ThrownErrorKind::Specific:
3029-
// We need to unify the thrown error types.
3030-
mustUnify = true;
3031-
break;
3032-
3033-
case ThrownErrorKind::Never:
3034-
// We're going to have to drop the "throws" entirely.
3035-
dropThrows = true;
3036-
break;
3037-
3038-
case ThrownErrorKind::AnyError:
3039-
llvm_unreachable("The thrown error types should have been equal");
3040-
}
3041-
break;
3042-
}
3043-
3044-
// If we know we need to drop 'throws', try it now.
3045-
if (dropThrows) {
2965+
switch (compareThrownErrorsForSubtyping(thrownError1, thrownError2, cs.DC)) {
2966+
case ThrownErrorSubtyping::DropsThrows: {
2967+
// We need to drop 'throws' to make this work.
30462968
if (!cs.shouldAttemptFixes())
30472969
return cs.getTypeMatchFailure(locator);
30482970

30492971
auto *fix = DropThrowsAttribute::create(cs, func1, func2,
30502972
cs.getConstraintLocator(locator));
30512973
if (cs.recordFix(fix))
30522974
return cs.getTypeMatchFailure(locator);
2975+
2976+
return cs.getTypeMatchSuccess();
30532977
}
30542978

3055-
// If we need to unify the thrown error types, do so now.
3056-
if (mustUnify) {
2979+
case ThrownErrorSubtyping::ExactMatch:
2980+
return cs.getTypeMatchSuccess();
2981+
2982+
case ThrownErrorSubtyping::Subtype:
2983+
// We know this is going to work, but we might still need to generate a
2984+
// constraint if one of the error types involves type variables.
2985+
if (thrownError1->hasTypeVariable() || thrownError2->hasTypeVariable()) {
2986+
// Fall through to the dependent case.
2987+
} else if (kind < ConstraintKind::Subtype) {
2988+
// We aren't allowed to have a subtype, so fail here.
2989+
return cs.getTypeMatchFailure(locator);
2990+
} else {
2991+
// We have a subtype. All set!
2992+
return cs.getTypeMatchSuccess();
2993+
}
2994+
LLVM_FALLTHROUGH;
2995+
2996+
case ThrownErrorSubtyping::Dependent: {
2997+
// The presence of type variables in the thrown error types require that
2998+
// we generate a constraint to unify the thrown error types, so do so now.
30572999
ConstraintKind subKind = (kind < ConstraintKind::Subtype)
30583000
? ConstraintKind::Equal
30593001
: ConstraintKind::Subtype;
@@ -3064,9 +3006,24 @@ matchFunctionThrowing(ConstraintSystem &cs,
30643006
locator.withPathElement(LocatorPathElt::ThrownErrorType()));
30653007
if (result == ConstraintSystem::SolutionKind::Error)
30663008
return cs.getTypeMatchFailure(locator);
3009+
3010+
return cs.getTypeMatchSuccess();
30673011
}
30683012

3069-
return cs.getTypeMatchSuccess();
3013+
case ThrownErrorSubtyping::Mismatch: {
3014+
auto thrownErrorLocator = cs.getConstraintLocator(
3015+
locator.withPathElement(LocatorPathElt::ThrownErrorType()));
3016+
if (!cs.shouldAttemptFixes())
3017+
return cs.getTypeMatchFailure(thrownErrorLocator);
3018+
3019+
auto *fix = IgnoreThrownErrorMismatch::create(
3020+
cs, thrownError1, thrownError2, thrownErrorLocator);
3021+
if (cs.recordFix(fix))
3022+
return cs.getTypeMatchFailure(thrownErrorLocator);
3023+
3024+
return cs.getTypeMatchSuccess();
3025+
}
3026+
}
30703027
}
30713028

30723029
ConstraintSystem::TypeMatchResult

0 commit comments

Comments
 (0)