Skip to content

Commit a011d65

Browse files
committed
Update requirements for explicit @differentiable attribute on protocol witnesses.
Require explicit `@differentiable` attribute on witnesses declared in a different type context or file than the protocol conformance.
1 parent f7ddfa7 commit a011d65

File tree

4 files changed

+27
-17
lines changed

4 files changed

+27
-17
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3112,10 +3112,11 @@ ERROR(overriding_decl_missing_differentiable_attr,none,
31123112
"overriding declaration is missing attribute '%0'", (StringRef))
31133113
NOTE(protocol_witness_missing_differentiable_attr,none,
31143114
"candidate is missing attribute '%0'", (StringRef))
3115-
NOTE(protocol_witness_missing_differentiable_attr_other_file,none,
3115+
NOTE(protocol_witness_missing_differentiable_attr_invalid_context,none,
31163116
"candidate is missing explicit '%0' attribute to satisfy requirement %1 "
3117-
"(in protocol %3) because it is declared in a different file than the "
3118-
"conformance of %2 to %3", (StringRef, DeclName, Type, Type))
3117+
"(in protocol %3); explicit attribute is necessary because candidate is "
3118+
"declared in a different type context or file than the conformance of %2 "
3119+
"to %3", (StringRef, DeclName, Type, Type))
31193120

31203121
// @derivative
31213122
ERROR(derivative_attr_expected_result_tuple,none,

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -388,11 +388,15 @@ matchWitnessDifferentiableAttr(DeclContext *dc, ValueDecl *req,
388388
// conditions for creating an implicit witness `@differentiable` attribute
389389
// with the exact derivative configuration.
390390

391-
// If witness is declared in a different file as the conformance, we
392-
// should not create an implicit `@differentiable` attribute on the
393-
// witness. Produce an error.
394-
if (dc->getModuleScopeContext() !=
395-
witness->getDeclContext()->getModuleScopeContext()) {
391+
// If witness is declared in a different file or type context than the
392+
// conformance, we should not create an implicit `@differentiable`
393+
// attribute on the witness. Produce an error.
394+
auto sameTypeContext =
395+
dc->getInnermostTypeContext() ==
396+
witness->getDeclContext()->getInnermostTypeContext();
397+
auto sameModule = dc->getModuleScopeContext() ==
398+
witness->getDeclContext()->getModuleScopeContext();
399+
if (!sameTypeContext || !sameModule) {
396400
// FIXME(TF-1014): `@differentiable` attribute diagnostic does not
397401
// appear if associated type inference is involved.
398402
if (auto *vdWitness = dyn_cast<VarDecl>(witness)) {
@@ -2454,14 +2458,19 @@ diagnoseMatch(ModuleDecl *module, NormalProtocolConformance *conformance,
24542458
llvm::raw_string_ostream os(reqDiffAttrString);
24552459
reqAttr->print(os, req, omitWrtClause);
24562460
os.flush();
2457-
// If the witness is declared in a different file than the conformance, emit
2458-
// a specialized diagnostic.
2459-
if (conformance->getDeclContext()->getModuleScopeContext() !=
2460-
witness->getDeclContext()->getModuleScopeContext()) {
2461+
// If the witness is declared in a different file or type context than the
2462+
// conformance, emit a specialized diagnostic.
2463+
auto sameModule = conformance->getDeclContext()->getModuleScopeContext() !=
2464+
witness->getDeclContext()->getModuleScopeContext();
2465+
auto sameTypeContext =
2466+
conformance->getDeclContext()->getInnermostTypeContext() !=
2467+
witness->getDeclContext()->getInnermostTypeContext();
2468+
if (sameModule || sameTypeContext) {
24612469
diags
24622470
.diagnose(
24632471
witness,
2464-
diag::protocol_witness_missing_differentiable_attr_other_file,
2472+
diag::
2473+
protocol_witness_missing_differentiable_attr_invalid_context,
24652474
reqDiffAttrString, req->getName(), conformance->getType(),
24662475
conformance->getProtocol()->getDeclaredInterfaceType())
24672476
.fixItInsert(match.Witness->getStartLoc(), reqDiffAttrString + ' ');

test/AutoDiff/Sema/ImplicitDifferentiableAttributeCrossFile/Inputs/other_file.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,20 +32,20 @@ protocol Protocol2: Differentiable {
3232

3333
struct ConformingStruct: Differentiable {
3434
// Error for missing `@differentiable` attribute.
35-
// expected-note @+1 {{candidate is missing explicit '@differentiable' attribute to satisfy requirement 'internalMethod1' (in protocol 'Protocol1') because it is declared in a different file than the conformance of 'ConformingStruct' to 'Protocol1'}} {{3-3=@differentiable }}
35+
// expected-note @+1 {{candidate is missing explicit '@differentiable' attribute to satisfy requirement 'internalMethod1' (in protocol 'Protocol1'); explicit attribute is necessary because candidate is declared in a different type context or file than the conformance of 'ConformingStruct' to 'Protocol1'}} {{3-3=@differentiable }}
3636
func internalMethod1(_ x: Float) -> Float {
3737
x
3838
}
3939

4040
// Error for missing `@differentiable` superset attribute.
41-
// expected-note @+2 {{candidate is missing explicit '@differentiable' attribute to satisfy requirement 'internalMethod2' (in protocol 'Protocol1') because it is declared in a different file than the conformance of 'ConformingStruct' to 'Protocol1'}} {{3-3=@differentiable }}
41+
// expected-note @+2 {{candidate is missing explicit '@differentiable' attribute to satisfy requirement 'internalMethod2' (in protocol 'Protocol1'); explicit attribute is necessary because candidate is declared in a different type context or file than the conformance of 'ConformingStruct' to 'Protocol1'}} {{3-3=@differentiable }}
4242
@differentiable(wrt: x)
4343
func internalMethod2(_ x: Float) -> Float {
4444
x
4545
}
4646

4747
// Error for missing `@differentiable` subset attribute.
48-
// expected-note @+2 {{candidate is missing explicit '@differentiable(wrt: x)' attribute to satisfy requirement 'internalMethod3' (in protocol 'Protocol1') because it is declared in a different file than the conformance of 'ConformingStruct' to 'Protocol1'}} {{3-3=@differentiable(wrt: x) }}
48+
// expected-note @+2 {{candidate is missing explicit '@differentiable(wrt: x)' attribute to satisfy requirement 'internalMethod3' (in protocol 'Protocol1'); explicit attribute is necessary because candidate is declared in a different type context or file than the conformance of 'ConformingStruct' to 'Protocol1'}} {{3-3=@differentiable(wrt: x) }}
4949
@differentiable(wrt: (self, x))
5050
func internalMethod3(_ x: Float) -> Float {
5151
x

test/AutoDiff/Sema/ImplicitDifferentiableAttributeCrossFile/Inputs/other_file_protocol_default_implementation_witness.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ protocol P2: P1 {}
1010

1111
extension P2 {
1212
@differentiable(wrt: (self, input))
13-
// expected-note @+1 {{candidate is missing explicit '@differentiable(wrt: self)' attribute to satisfy requirement 'callAsFunction' (in protocol 'P1') because it is declared in a different file than the conformance of 'ConformingStruct' to 'P1'}}
13+
// expected-note @+1 {{candidate is missing explicit '@differentiable(wrt: self)' attribute to satisfy requirement 'callAsFunction' (in protocol 'P1'); explicit attribute is necessary because candidate is declared in a different type context or file than the conformance of 'ConformingStruct' to 'P1'}}
1414
public func callAsFunction(_ input: Float) -> Float {
1515
return input
1616
}

0 commit comments

Comments
 (0)