Skip to content

Commit 83a028d

Browse files
authored
[AutoDiff] Allow closure differentiation when used as default arg val (#78373)
If the default argument generator (and, consequently, the function taking this default argument) has public visibility, it's OK to have a closure (which always has private visibility) as the default value of the argument.
1 parent 3a8cb9b commit 83a028d

File tree

2 files changed

+23
-12
lines changed

2 files changed

+23
-12
lines changed

lib/SILOptimizer/Mandatory/Differentiation.cpp

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -681,15 +681,28 @@ DifferentiationTransformer::emitDerivativeFunctionReference(
681681
}
682682
assert(minimalWitness);
683683
if (original->getFunction()->isSerialized()) {
684-
// When dealing with curry thunk, look at the function being wrapped
685-
// inside implicit closure. If it has public visibility, the corresponding
686-
// differentiability witness also has public visibility. It should be OK
687-
// for implicit wrapper closure and its witness to have private linkage.
688-
SILFunction *unwrappedFn = getUnwrappedCurryThunkFunction(originalFn);
689-
bool isWitnessPublic =
690-
unwrappedFn == nullptr
691-
? hasPublicVisibility(minimalWitness->getLinkage())
692-
: hasPublicVisibility(unwrappedFn->getLinkage());
684+
bool isWitnessPublic;
685+
if (SILFunction *unwrappedFn =
686+
getUnwrappedCurryThunkFunction(originalFn)) {
687+
// When dealing with curry thunk, look at the function being wrapped
688+
// inside implicit closure. If it has public visibility, the
689+
// corresponding differentiability witness also has public visibility.
690+
// It should be OK for implicit wrapper closure and its witness to have
691+
// private linkage.
692+
isWitnessPublic = hasPublicVisibility(unwrappedFn->getLinkage());
693+
} else if (originalFn->getDeclRef().getAbstractClosureExpr() &&
694+
originalFRI->getFunction()
695+
->getDeclRef()
696+
.isDefaultArgGenerator()) {
697+
// If we reference a closure from inside default argument generator,
698+
// check against generator's visibility. If the function having this
699+
// default argument has public visibility, it's OK to have a closure
700+
// (which always has private visibility) as its default value.
701+
isWitnessPublic =
702+
hasPublicVisibility(originalFRI->getFunction()->getLinkage());
703+
} else {
704+
isWitnessPublic = hasPublicVisibility(minimalWitness->getLinkage());
705+
}
693706
if (!isWitnessPublic) {
694707
enum { Inlinable = 0, DefaultArgument = 1 };
695708
unsigned fragileKind = Inlinable;

test/AutoDiff/SILOptimizer/differentiation_diagnostics.swift

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -751,9 +751,7 @@ public func hasImplicitlyDifferentiatedTopLevelDefaultArgument(
751751
_ f: @differentiable(reverse) (Float) -> Float = implicitlyDifferentiableFromFragile
752752
) {}
753753

754-
// TODO(TF-1030): This will eventually not be an error.
755-
// expected-error @+2 {{function is not differentiable}}
756-
// expected-note @+1 {{differentiated functions in default arguments must be marked '@differentiable' or have a public '@derivative'; this is not possible with a closure, make a top-level function instead}}
754+
// No error expected
757755
public func hasImplicitlyDifferentiatedClosureDefaultArgument(_ f: @differentiable(reverse) (Float) -> Float = { $0 }) {}
758756

759757
@inlinable

0 commit comments

Comments
 (0)