Confusion surrounding new(?) error output structure — multiple errors associated with the same source location?

Looks like with Xcode 16, some errors have started coming in like this, where the same file:line:col of some decl will be reused over and over for multiple different errors within that decl, such as a class decl or an extension, or even a typealias.

In the below excerpt, all errors point to MyProject/AppDependencies.swift:1819:5, even though they reference properties in other areas:

MyProject/AppDependencies.swift:1819:5: error: property 'networkProgressSubject' must be declared public because it matches a requirement in public protocol 'NetworkProgressSubjectDependency'
1222 | 
1223 |     // swiftlint:disable:next private_subject
1224 |     var networkProgressSubject: PassthroughSubject<NetworkProgress, Never> {
     |         `- note: mark the property as 'public' to satisfy the requirement
1225 |         <redacted>
1226 |     }
     :
1817 | 
1818 | #if INTERNAL
1819 |     extension AppDependencies: _AllDependencies &
     |     `- error: property 'networkProgressSubject' must be declared public because it matches a requirement in public protocol 'NetworkProgressSubjectDependency'
1820 |     Foo &
1821 |     Bar &

MyProject/AppDependencies.swift:1819:5: error: property 'xyzDataManager' must be declared public because it matches a requirement in public protocol 'XYZDataDependency'
 935 |     }
 936 | 
 937 |     var xyzDataManager: XYZDataManager {
     |         `- note: mark the property as 'public' to satisfy the requirement
 938 |         <redacted>
 939 |     }
     :
1817 | 
1818 | #if INTERNAL
1819 |     extension AppDependencies: _AllDependencies &
     |     `- error: property 'xyzDataManager' must be declared public because it matches a requirement in public protocol 'XYZDataDependency'
1820 |     Foo &
1821 |     Bar &

MyProject/AppDependencies.swift:1819:5: error: property 'someService' must be declared public because it matches a requirement in public protocol 'SomeServiceDependency'
1079 |     }
1080 | 
1081 |     var someService: SomeService {
     |         `- note: mark the property as 'public' to satisfy the requirement
1082 |         <redacted>
1083 |     }
     :
1817 | 
1818 | #if INTERNAL
1819 |     extension AppDependencies: _AllDependencies &
     |     `- error: property 'someService' must be declared public because it matches a requirement in public protocol 'SomeServiceDependency'
1820 |     Foo &
1821 |     Bar &

MyProject/AppDependencies.swift:1819:5: error: property 'somePublisher' must be declared public because it matches a requirement in public protocol 'SomeDependency'
1234 |     }
1235 | 
1236 |     var somePublisher: AnyPublisher<Bool, Never> {
     |         `- note: mark the property as 'public' to satisfy the requirement
1237 |         <redacted>
1238 |     }
     :
1817 | 
1818 | #if INTERNAL
1819 |     extension AppDependencies: _AllDependencies &
     |     `- error: property 'somePublisher' must be declared public because it matches a requirement in public protocol 'SomeDependency'
1820 |     Foo &
1821 |     Bar &

In this particular example, what's happening is we are conforming a type to multiple different protocols all in one go like this:

1819 |     extension AppDependencies: _AllDependencies &
1820 |     Foo &
1821 |     Bar &

and the errors reference the conformance, but not the properties/methods that need to be updated to fix the conformance.

If this is not new, then, well, idk how our devex team hasn't come across this before... I haven't either. This is really bad though, because it makes a lot of error-parsing tooling only pick up the last error at that source location:

Ideally, each of these errors would point to the exact property that needs to be marked public. That could be done many ways, i.e. the enclosing decl could still be referenced as another error, or a note, etc. But the actual problem needs to be pointed to by the error, not just the enclosing decl.

Whether or not these diagnostics should change, you and/or Xcode should not be assuming two unrelated diagnostics can’t be emitted at the same location. That’s a totally valid thing that has always been possible all the way back to GCC in the 90s (and presumably earlier.)

1 Like

That's totally correct, but that is somewhat orthogonal to my real issue, which is that there is no longer an error/note that points directly to the affected member.

I also don't think it is very useful for the error to point to the parent declaration at all. It would be like if you forgot to return a value from a method, and the error pointed you to the class decl, imo.

Perhaps I'm confused about what you're trying to illustrate, but in the example you've posted I see a note emitted for each of the declarations you've posted an error for, e.g.:

My bad, to clarify, what I mean is that the note is emitted as - note: and not <source location>: note:. IDEs and tooling cannot properly emit diagnostics without a source location.

sidestepping the question about how the new diagnostic format should behave, you can go back to the 'old' diagnostic style by passing the flag -diagnostic-style=llvm to the compiler invocation if that is more useful in certain contexts.

1 Like

Got it, that makes sense.

Without commenting on the new format more generally, IMO in this specific case I do agree the 'hierarchy' is just bad—we should emit the error at the most specific location and the note should point to the conformance here, e.g., 'conformance to NetworkProgressSubjectDependency declared here'—in some cases I think that would be genuinely useful because the conformance might be declared arbitrarily far away from the member itself.

1 Like

That did the trick, thanks Jamie!

1 Like

Agreed :100: