@@ -1903,12 +1903,21 @@ static ManagedValue convertFunctionRepresentation(SILGenFunction &SGF,
19031903 llvm_unreachable (" bad representation" );
19041904}
19051905
1906+ // / Whether the given abstraction pattern as an opaque thrown error.
1907+ static bool hasOpaqueThrownError (const AbstractionPattern &pattern) {
1908+ if (auto thrownPattern = pattern.getFunctionThrownErrorType ())
1909+ return thrownPattern->isTypeParameterOrOpaqueArchetype ();
1910+
1911+ return false ;
1912+ }
1913+
19061914// Ideally our prolog/epilog emission would be able to handle all possible
19071915// reabstractions and conversions. Until then, this returns true if a closure
19081916// literal of type `literalType` can be directly emitted by SILGen as
19091917// `convertedType`.
1910- static bool canPeepholeLiteralClosureConversion (Type literalType,
1911- Type convertedType) {
1918+ static bool canPeepholeLiteralClosureConversion (
1919+ Type literalType, Type convertedType,
1920+ const std::optional<AbstractionPattern> &closurePattern) {
19121921 auto literalFnType = literalType->getAs <FunctionType>();
19131922 auto convertedFnType = convertedType->getAs <FunctionType>();
19141923
@@ -1919,22 +1928,28 @@ static bool canPeepholeLiteralClosureConversion(Type literalType,
19191928 if (literalFnType->isEqual (convertedFnType)) {
19201929 return true ;
19211930 }
1922-
1931+
19231932 // Are the types equivalent aside from effects (throws) or coeffects
19241933 // (escaping)? Then we should emit the literal as having the destination type
19251934 // (co)effects, even if it doesn't exercise them.
19261935 //
19271936 // TODO: We could also in principle let `async` through here, but that
19281937 // interferes with the implementation of `reasync`.
19291938 auto literalWithoutEffects = literalFnType->getExtInfo ().intoBuilder ()
1930- .withThrows (false , Type ())
19311939 .withNoEscape (false )
19321940 .build ();
19331941
19341942 auto convertedWithoutEffects = convertedFnType->getExtInfo ().intoBuilder ()
1935- .withThrows (false , Type ())
19361943 .withNoEscape (false )
19371944 .build ();
1945+
1946+ // If the closure pattern has an abstract thrown error, we are unable to
1947+ // emit the literal with a difference in the thrown error type.
1948+ if (!(closurePattern && hasOpaqueThrownError (*closurePattern))) {
1949+ literalWithoutEffects = literalWithoutEffects.withThrows (false , Type ());
1950+ convertedWithoutEffects = convertedWithoutEffects.withThrows (false , Type ());
1951+ }
1952+
19381953 if (literalFnType->withExtInfo (literalWithoutEffects)
19391954 ->isEqual (convertedFnType->withExtInfo (convertedWithoutEffects))) {
19401955 return true ;
@@ -2000,7 +2015,8 @@ RValue RValueEmitter::visitFunctionConversionExpr(FunctionConversionExpr *e,
20002015
20012016 if ((isa<AbstractClosureExpr>(subExpr) || isa<CaptureListExpr>(subExpr))
20022017 && canPeepholeLiteralClosureConversion (subExpr->getType (),
2003- e->getType ())) {
2018+ e->getType (),
2019+ C.getAbstractionPattern ())) {
20042020 // If we're emitting into a context with a preferred abstraction pattern
20052021 // already, carry that along.
20062022 auto origType = C.getAbstractionPattern ();
0 commit comments