Files
swift-mirror/test/decl/protocol/conforms/init.swift
Jordan Rose 6bd7e5e5b4 Make sure protocol witness errors don't leave the conformance context
That is, if there's a problem with a witness, and the witness comes
from a different extension from the conformance (or the original type,
when the conformance is on an extension), put the main diagnostic on
the conformance, with a note on the witness. This involves some
shuffling and rephrasing of existing diagnostics too.

There's a few reasons for this change:

- More context. It may not be obvious why a declaration in file
  A.swift needs to be marked 'public' if you can't see the conformance
  in B.swift.

- Better locations for imported declarations. If you're checking a
  conformance in a source file but the witness came from an imported
  module, it's better to put the diagnostic on the part you have
  control over. (This is especially true in Xcode, which can't display
  diagnostics on imported declarations in the source editor.)

- Plays better with batch mode. Without this change, you can have
  diagnostics being reported in file A.swift that are tied to a
  conformance declared in file B.swift. Of course the contents of
  A.swift also affect the diagnostic, but compiling A.swift on its
  own wouldn't produce the diagnostic, and so putting it there is
  problematic.

The change does in some cases make for a worse user experience,
though; if you just want to apply the changes and move on, the main
diagnostic isn't in the "right place". It's the note that has the info
and possible fix-it. It's also a slightly more complicated
implementation.
2018-05-10 19:31:12 -07:00

79 lines
1.8 KiB
Swift

// RUN: %target-typecheck-verify-swift
protocol P1 {
init() // expected-note{{protocol requires initializer 'init()' with type '()'}}
}
// ------------------------------------------------------------------------
// Conformance to initializer requirements
// ------------------------------------------------------------------------
struct S1 : P1 {
init() { } // okay
}
enum E1 : P1 {
case A, B
init() { self = .A } // okay
}
class C1a : P1 {
required init() { } // okay
}
final class C1b : P1 {
required init() { } // okay
}
class C1c : P1 {
init() { } // expected-error{{initializer requirement 'init()' can only be satisfied by a 'required' initializer in non-final class 'C1c'}}{{3-3=required }}
}
struct S2 : P1 { } // okay
enum E2 : P1 { } // expected-error{{type 'E2' does not conform to protocol 'P1'}}
final class C2a : P1 { } // okay
class C2b : P1 { } // expected-error{{initializer requirement 'init()' can only be satisfied by a 'required' initializer in non-final class 'C2b'}}
class C2c {
init(x: Int) { }
}
extension C2c : P1 {
convenience init() { self.init(x: 0) } // expected-error{{initializer requirement 'init()' can only be satisfied by a 'required' initializer in the definition of non-final class 'C2c'}}
}
class C2d {
init(x: Int) { }
convenience init() { self.init(x: 0) } // expected-note {{'init()' declared here}} {{3-3=required }}
}
extension C2d : P1 { // expected-error{{initializer requirement 'init()' can only be satisfied by a 'required' initializer in non-final class 'C2d'}}
}
// rdar://problem/24575507
protocol P2 {
init()
init(int: Int)
}
extension P2 {
init() {
self.init(int: 17)
}
}
class Foo : P2 {
var value: Int
// okay: init() requirement satisfied by protocol extension
required init(int value: Int) {
self.value = value
}
}