@@ -1903,12 +1903,21 @@ static ManagedValue convertFunctionRepresentation(SILGenFunction &SGF,
1903
1903
llvm_unreachable (" bad representation" );
1904
1904
}
1905
1905
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
+
1906
1914
// Ideally our prolog/epilog emission would be able to handle all possible
1907
1915
// reabstractions and conversions. Until then, this returns true if a closure
1908
1916
// literal of type `literalType` can be directly emitted by SILGen as
1909
1917
// `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) {
1912
1921
auto literalFnType = literalType->getAs <FunctionType>();
1913
1922
auto convertedFnType = convertedType->getAs <FunctionType>();
1914
1923
@@ -1919,22 +1928,28 @@ static bool canPeepholeLiteralClosureConversion(Type literalType,
1919
1928
if (literalFnType->isEqual (convertedFnType)) {
1920
1929
return true ;
1921
1930
}
1922
-
1931
+
1923
1932
// Are the types equivalent aside from effects (throws) or coeffects
1924
1933
// (escaping)? Then we should emit the literal as having the destination type
1925
1934
// (co)effects, even if it doesn't exercise them.
1926
1935
//
1927
1936
// TODO: We could also in principle let `async` through here, but that
1928
1937
// interferes with the implementation of `reasync`.
1929
1938
auto literalWithoutEffects = literalFnType->getExtInfo ().intoBuilder ()
1930
- .withThrows (false , Type ())
1931
1939
.withNoEscape (false )
1932
1940
.build ();
1933
1941
1934
1942
auto convertedWithoutEffects = convertedFnType->getExtInfo ().intoBuilder ()
1935
- .withThrows (false , Type ())
1936
1943
.withNoEscape (false )
1937
1944
.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
+
1938
1953
if (literalFnType->withExtInfo (literalWithoutEffects)
1939
1954
->isEqual (convertedFnType->withExtInfo (convertedWithoutEffects))) {
1940
1955
return true ;
@@ -2000,7 +2015,8 @@ RValue RValueEmitter::visitFunctionConversionExpr(FunctionConversionExpr *e,
2000
2015
2001
2016
if ((isa<AbstractClosureExpr>(subExpr) || isa<CaptureListExpr>(subExpr))
2002
2017
&& canPeepholeLiteralClosureConversion (subExpr->getType (),
2003
- e->getType ())) {
2018
+ e->getType (),
2019
+ C.getAbstractionPattern ())) {
2004
2020
// If we're emitting into a context with a preferred abstraction pattern
2005
2021
// already, carry that along.
2006
2022
auto origType = C.getAbstractionPattern ();
0 commit comments