Skip to content

Commit 7d7c726

Browse files
committed
[Typed throws] Teach associated type inference to infer from thrown errors
When comparing a requirement that uses typed throws and uses an associated type for the thrown error type against a potential witness, infer the associated type from the thrown error of the witness---whether explicitly specified, untyped throws (`any Error`), or non-throwing (`Never`).
1 parent fc78ad3 commit 7d7c726

15 files changed

+88
-32
lines changed

include/swift/AST/Decl.h

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

71287128
/// Returns if the function throws or is async.
71297129
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
@@ -3391,8 +3391,15 @@ class AnyFunctionType : public TypeBase {
33913391
///
33923392
/// Functions with untyped throws will produce "any Error", functions that
33933393
/// cannot throw or are specified to throw "Never" will return llvm::None.
3394-
llvm::Optional<Type> getEffectiveThrownInterfaceType() const;
3395-
3394+
llvm::Optional<Type> getEffectiveThrownErrorType() const;
3395+
3396+
/// Retrieve the "effective" thrown interface type, or `Never` if
3397+
/// this function cannot throw.
3398+
///
3399+
/// Functions with untyped throws will produce `any Error`, functions that
3400+
/// cannot throw or are specified to throw `Never` will return `Never`.
3401+
Type getEffectiveThrownErrorTypeOrNever() const;
3402+
33963403
/// Returns true if the function type stores a Clang type that cannot
33973404
/// be derived from its Swift type. Returns false otherwise, including if
33983405
/// 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: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2957,8 +2957,8 @@ matchFunctionThrowing(ConstraintSystem &cs,
29572957
// that throws error type E2 when E1 is a subtype of E2. For the purpose
29582958
// of this comparison, a non-throwing function has thrown error type 'Never',
29592959
// and an untyped throwing function has thrown error type 'any Error'.
2960-
Type thrownError1 = getEffectiveThrownErrorTypeOrNever(func1);
2961-
Type thrownError2 = getEffectiveThrownErrorTypeOrNever(func2);
2960+
Type thrownError1 = func1->getEffectiveThrownErrorTypeOrNever();
2961+
Type thrownError2 = func2->getEffectiveThrownErrorTypeOrNever();
29622962
if (!thrownError1 || !thrownError2)
29632963
return cs.getTypeMatchSuccess();
29642964

0 commit comments

Comments
 (0)