Skip to content

Commit 6f706e9

Browse files
committed
[AutoDiff] Change TangentVector memberwise initializer access level.
Change the access level of synthesized `TangentVector` struct memberwise initializers to match the access level of the `TangentVector` struct itself. Previously, memberwise initializers of public synthesized `TangentVector` structs were internal. Now, they are public, improving usability. Note that public synthesized memberwise initializers have no precedent in Swift. For normal public structs, it's possible to manually define a public memberwise initializer, skipping synthesis. However, since `TangentVector` structs are always synthesized with a memberwise initializer, manually defining a public memberwise initializer in an extension leads to a redeclaration error. A broader discussion on memberwise initializer access levels may be worthwhile. Resolves TF-1077.
1 parent b3e4951 commit 6f706e9

6 files changed

+95
-24
lines changed

lib/Sema/CodeSynthesis.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,32 @@ ConstructorDecl *swift::createMemberwiseImplicitConstructor(
278278
ctx);
279279
}
280280

281+
// SWIFT_ENABLE_TENSORFLOW
282+
ConstructorDecl *swift::getOrCreateEffectiveMemberwiseInitializer(
283+
ASTContext &ctx, NominalTypeDecl *nominal) {
284+
// Compute the access level for the memberwise initializer: the minimum of:
285+
// - The access level of the nominal type declaration itself.
286+
// - The access level of each memberwise-initialized property in the nominal
287+
// type declaration.
288+
auto accessLevel = std::min(AccessLevel::Public, nominal->getFormalAccess());
289+
for (auto *member : nominal->getMembers()) {
290+
auto var = dyn_cast<VarDecl>(member);
291+
if (!var ||
292+
!var->isMemberwiseInitialized(/*preferDeclaredProperties=*/true))
293+
continue;
294+
accessLevel = std::min(accessLevel, var->getFormalAccess());
295+
}
296+
if (auto *initDecl = nominal->getEffectiveMemberwiseInitializer()) {
297+
initDecl->overwriteAccess(accessLevel);
298+
return initDecl;
299+
}
300+
auto *initDecl = createMemberwiseImplicitConstructor(ctx, nominal);
301+
initDecl->overwriteAccess(accessLevel);
302+
nominal->addMember(initDecl);
303+
return initDecl;
304+
}
305+
// SWIFT_ENABLE_TENSORFLOW END
306+
281307
/// Create a stub body that emits a fatal error message.
282308
static std::pair<BraceStmt *, bool>
283309
synthesizeStubBody(AbstractFunctionDecl *fn, void *) {

lib/Sema/CodeSynthesis.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,18 @@ Expr *buildArgumentForwardingExpr(ArrayRef<ParamDecl*> params,
6565

6666
ConstructorDecl *createMemberwiseImplicitConstructor(ASTContext &ctx,
6767
NominalTypeDecl *decl);
68+
69+
// SWIFT_ENABLE_TENSORFLOW
70+
// Get the effective memberwise initializer of the given nominal type, or create
71+
// it if it does not exist.
72+
// Sets the access level of the memberwise initializer to the minimum of:
73+
// - The access level of the nominal type declaration itself.
74+
// - The access level of each memberwise-initialized property in the nominal
75+
// type declaration.
76+
ConstructorDecl *getOrCreateEffectiveMemberwiseInitializer(
77+
ASTContext &ctx, NominalTypeDecl *nominal);
78+
// SWIFT_ENABLE_TENSORFLOW END
79+
6880
} // end namespace swift
6981

7082
#endif

lib/Sema/DerivedConformanceElementaryFunctions.cpp

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -100,17 +100,6 @@ static ValueDecl *getElementaryFunctionRequirement(
100100
}
101101
}
102102

103-
// Get the effective memberwise initializer of the given nominal type, or create
104-
// it if it does not exist.
105-
static ConstructorDecl *getOrCreateEffectiveMemberwiseInitializer(
106-
ASTContext &ctx, NominalTypeDecl *nominal) {
107-
if (auto *initDecl = nominal->getEffectiveMemberwiseInitializer())
108-
return initDecl;
109-
auto *initDecl = createMemberwiseImplicitConstructor(ctx, nominal);
110-
nominal->addMember(initDecl);
111-
return initDecl;
112-
}
113-
114103
bool DerivedConformance::canDeriveElementaryFunctions(NominalTypeDecl *nominal,
115104
DeclContext *DC) {
116105
// Nominal type must be a struct. (Zero stored properties is okay.)

lib/Sema/DerivedConformanceRingMathProtocols.cpp

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -75,18 +75,6 @@ static ValueDecl *getProtocolRequirement(ProtocolDecl *proto, Identifier name) {
7575
return lookup.front();
7676
}
7777

78-
// Get the effective memberwise initializer of the given nominal type, or create
79-
// it if it does not exist.
80-
static ConstructorDecl *getOrCreateEffectiveMemberwiseInitializer(
81-
ASTContext &ctx, NominalTypeDecl *nominal) {
82-
if (auto *initDecl = nominal->getEffectiveMemberwiseInitializer())
83-
return initDecl;
84-
auto *initDecl = createMemberwiseImplicitConstructor(
85-
ctx, nominal);
86-
nominal->addMember(initDecl);
87-
return initDecl;
88-
}
89-
9078
// Return true if given nominal type has a `let` stored with an initial value.
9179
// TODO: Move function to shared place for use with other derived conformances.
9280
static bool hasLetStoredPropertyWithInitialValue(NominalTypeDecl *nominal) {
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// SWIFT_ENABLE_TENSORFLOW
2+
// RUN: %target-swift-frontend -print-ast %s | %FileCheck %s
3+
4+
// Test `Differentiable` derived conformances.
5+
// Verify access levels of synthesized `TangentVector` types and their memberwise initializers.
6+
// `TangentVector` memberwise initializer access level should match `TangentVector` access level.
7+
8+
public struct PublicStruct: Differentiable {}
9+
internal struct InternalStruct: Differentiable {}
10+
private struct PrivateStruct: Differentiable {}
11+
12+
// CHECK-LABEL: public struct PublicStruct : Differentiable {
13+
// CHECK: internal init()
14+
// CHECK: public struct TangentVector : Differentiable, AdditiveArithmetic, PointwiseMultiplicative, ElementaryFunctions {
15+
// CHECK: public init()
16+
// CHECK: }
17+
// CHECK: }
18+
19+
// CHECK-LABEL: internal struct InternalStruct : Differentiable {
20+
// CHECK: internal init()
21+
// CHECK: internal struct TangentVector : Differentiable, AdditiveArithmetic, PointwiseMultiplicative, ElementaryFunctions {
22+
// CHECK: internal init()
23+
// CHECK: }
24+
// CHECK: }
25+
26+
// CHECK-LABEL: private struct PrivateStruct : Differentiable {
27+
// CHECK: internal init()
28+
// CHECK: fileprivate struct TangentVector : Differentiable, AdditiveArithmetic, PointwiseMultiplicative, ElementaryFunctions {
29+
// CHECK: fileprivate init()
30+
// CHECK: }
31+
// CHECK: }
32+
33+
public class PublicClass: Differentiable {}
34+
internal class InternalClass: Differentiable {}
35+
private class PrivateClass: Differentiable {}
36+
37+
// CHECK-LABEL: public class PublicClass : Differentiable {
38+
// CHECK: internal init()
39+
// CHECK: public struct TangentVector : Differentiable, AdditiveArithmetic, PointwiseMultiplicative, ElementaryFunctions {
40+
// CHECK: public init()
41+
// CHECK: }
42+
// CHECK: }
43+
44+
// CHECK-LABEL: internal class InternalClass : Differentiable {
45+
// CHECK: internal init()
46+
// CHECK: internal struct TangentVector : Differentiable, AdditiveArithmetic, PointwiseMultiplicative, ElementaryFunctions {
47+
// CHECK: internal init()
48+
// CHECK: }
49+
// CHECK: }
50+
51+
// CHECK-LABEL: private class PrivateClass : Differentiable {
52+
// CHECK: internal init()
53+
// CHECK: fileprivate struct TangentVector : Differentiable, AdditiveArithmetic, PointwiseMultiplicative, ElementaryFunctions {
54+
// CHECK: fileprivate init()
55+
// CHECK: }
56+
// CHECK: }

test/Sema/struct_differentiable.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,7 @@ extension NoMemberwiseInitializerExtended: Differentiable
414414
extension NoMemberwiseInitializerExtended: EuclideanDifferentiable
415415
where T : Differentiable & AdditiveArithmetic {}
416416

417-
// Test derived conformances in disallowed contexts.
417+
// Verify that cross-file derived conformances are disallowed.
418418

419419
// expected-error @+2 {{type 'OtherFileNonconforming' does not conform to protocol 'Differentiable'}}
420420
// expected-error @+1 {{implementation of 'Differentiable' cannot be automatically synthesized in an extension in a different file to the type}}

0 commit comments

Comments
 (0)