Skip to content

Commit 9d9ddf3

Browse files
committed
SILGen: Add AnyHashable erasure support for function conversions
When AnyHashable was added, SILGen gained support for lowering AnyHashableErasureExpr, however we forgot to also add support for AnyHashable parameter and result conversions to FunctionConversionExpr. Fixes <https://bugs.swift.org/browse/SR-2603>.
1 parent a1e4680 commit 9d9ddf3

File tree

4 files changed

+62
-8
lines changed

4 files changed

+62
-8
lines changed

lib/SILGen/SILGenExpr.cpp

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1326,23 +1326,34 @@ RValue RValueEmitter::visitErasureExpr(ErasureExpr *E, SGFContext C) {
13261326
return RValue(SGF, E, mv);
13271327
}
13281328

1329-
RValue RValueEmitter::visitAnyHashableErasureExpr(AnyHashableErasureExpr *E,
1330-
SGFContext C) {
1329+
RValue SILGenFunction::emitAnyHashableErasure(SILLocation loc,
1330+
ManagedValue value,
1331+
Type type,
1332+
ProtocolConformanceRef conformance,
1333+
SGFContext C) {
13311334
// Ensure that the intrinsic function exists.
1332-
auto convertFn = SGF.SGM.getConvertToAnyHashable(E);
1333-
if (!convertFn) return SGF.emitUndefRValue(E, E->getType());
1335+
auto convertFn = SGM.getConvertToAnyHashable(loc);
1336+
if (!convertFn)
1337+
return emitUndefRValue(
1338+
loc, getASTContext().getAnyHashableDecl()->getDeclaredType());
13341339

13351340
// Construct the substitution for T: Hashable.
1336-
ProtocolConformanceRef conformances[] = { E->getConformance() };
1337-
Substitution sub(E->getSubExpr()->getType(),
1338-
SGF.getASTContext().AllocateCopy(conformances));
1341+
ProtocolConformanceRef conformances[] = { conformance };
1342+
Substitution sub(type, getASTContext().AllocateCopy(conformances));
13391343

1344+
return emitApplyOfLibraryIntrinsic(loc, convertFn, sub, value, C);
1345+
}
1346+
1347+
RValue RValueEmitter::visitAnyHashableErasureExpr(AnyHashableErasureExpr *E,
1348+
SGFContext C) {
13401349
// Emit the source value into a temporary.
13411350
auto sourceOrigType = AbstractionPattern::getOpaque();
13421351
auto source =
13431352
SGF.emitMaterializedRValueAsOrig(E->getSubExpr(), sourceOrigType);
13441353

1345-
return SGF.emitApplyOfLibraryIntrinsic(E, convertFn, sub, source, C);
1354+
return SGF.emitAnyHashableErasure(E, source,
1355+
E->getSubExpr()->getType(),
1356+
E->getConformance(), C);
13461357
}
13471358

13481359
/// Treating this as a successful operation, turn a CMV into a +1 MV.

lib/SILGen/SILGenFunction.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1203,6 +1203,12 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
12031203

12041204
void emitReturnExpr(SILLocation loc, Expr *ret);
12051205

1206+
RValue emitAnyHashableErasure(SILLocation loc,
1207+
ManagedValue value,
1208+
Type type,
1209+
ProtocolConformanceRef conformance,
1210+
SGFContext C);
1211+
12061212
/// Turn a consumable managed value into a +1 managed value.
12071213
ManagedValue getManagedValue(SILLocation loc,
12081214
ConsumableManagedValue value);

lib/SILGen/SILGenPoly.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -520,6 +520,21 @@ ManagedValue Transform::transform(ManagedValue v,
520520
ctxt);
521521
}
522522

523+
// - T : Hashable to AnyHashable
524+
if (isa<StructType>(outputSubstType) &&
525+
outputSubstType->getAnyNominal() ==
526+
SGF.getASTContext().getAnyHashableDecl()) {
527+
auto *protocol = SGF.getASTContext().getProtocol(
528+
KnownProtocolKind::Hashable);
529+
auto conformance = SGF.SGM.M.getSwiftModule()->lookupConformance(
530+
inputSubstType, protocol, nullptr);
531+
auto result = SGF.emitAnyHashableErasure(Loc, v, inputSubstType,
532+
*conformance, ctxt);
533+
if (result.isInContext())
534+
return ManagedValue::forInContext();
535+
return std::move(result).getAsSingleValue(SGF, Loc);
536+
}
537+
523538
// Should have handled the conversion in one of the cases above.
524539
llvm_unreachable("Unhandled transform?");
525540
}

test/SILGen/function_conversion.swift

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,3 +429,25 @@ func convTupleScalar(_ f1: @escaping (Q) -> (),
429429
func convTupleScalarOpaque<T>(_ f: @escaping (T...) -> ()) -> ((_ args: T...) -> ())? {
430430
return f
431431
}
432+
433+
// ==== Make sure we support AnyHashable erasure
434+
435+
// CHECK-LABEL: sil hidden @_TF19function_conversion15convAnyHashableuRxs8HashablerFT1tx_T_
436+
// CHECK: function_ref @_TFF19function_conversion15convAnyHashableuRxs8HashablerFT1tx_T_U_FTVs11AnyHashableS1__Sb
437+
// CHECK: function_ref @_TTRGRxs8HashablerXFo_iVs11AnyHashableiS0__dSb_XFo_ixix_dSb_
438+
439+
// CHECK-LABEL: sil shared [transparent] [reabstraction_thunk] @_TTRGRxs8HashablerXFo_iVs11AnyHashableiS0__dSb_XFo_ixix_dSb_ : $@convention(thin) <T where T : Hashable> (@in T, @in T, @owned @callee_owned (@in AnyHashable, @in AnyHashable) -> Bool) -> Bool
440+
// CHECK: alloc_stack $AnyHashable
441+
// CHECK: function_ref @_swift_convertToAnyHashable
442+
// CHECK: apply {{.*}}<T>
443+
// CHECK: alloc_stack $AnyHashable
444+
// CHECK: function_ref @_swift_convertToAnyHashable
445+
// CHECK: apply {{.*}}<T>
446+
// CHECK: return
447+
448+
449+
func convAnyHashable<T : Hashable>(t: T) {
450+
let fn: (T, T) -> Bool = {
451+
(x: AnyHashable, y: AnyHashable) in x == y
452+
}
453+
}

0 commit comments

Comments
 (0)