The concept of ~Constraint is that you're peeling away bits that are assumed about a type, directly on the declaration, to give you the most minimally capable version of the type that you can later extend.
So, the proposal mentions this as a "not allowed yet" thing, but I think ~Constraint cannot in general be written on an extension because it doesn't make sense conceptually. Extensions don't remove functionality or capabilities, they can only add them. Copying is a capability, so adding it back after suppressing or removing the assumption of it via ~ (or whatever syntax) can make sense.
Before diving into this, I want to note that almost everything below are forward-looking statements and not currently proposed functionality.
Let's start with an example that also has methods and data:
struct GenericBox<T: ~Copyable>: ~Copyable {
var data: T
func withLoan(_ f: (borrowing Self) -> Void) { f(self) }
}
struct ConcreteBox: ~Copyable {
var data: Int
func withLoan(_ f: (borrowing Self) -> Void) { f(self) }
}
So far, we have two noncopyable types that support a withLoan method. That method works whether the type is copyable or not, and that's important to note. We cannot have the existence of an extension cause other functionality of the type to now be invalid. So you couldn't write a getCopy method that returns a copy of self in that GenericBox definition, because it does not assume the ability to copy. But the future goal is that you could write a conditional conformance to Copyable that has such a method, like this:
extension GenericBox: Copyable where T: Copyable {
func getCopy() -> Self { return self }
// other things only available for copyable instances of the box ...
}
extension GenericBox {
// more methods that work with copyable and noncopyable boxes ...
}
Here we have two extensions. One adds the ability for some GenericBoxes to be Copyable and extra functionality only for those Copyable boxes. The other extension adds functionality for all boxes, copyable or not. Notice how that side-steps the idea of "not Copyable" in the type system, i.e., you don't write "extension of GenericBox when it is not copyable" and add methods that only work for noncopyable boxes. Instead, you're extending a box that never had the capability to copy. Everything a noncopyable box can do, a copyable box can do as well.
It's OK if you add a capability unconditionally after having suppressed its implicit conformance. The proposal cites an example of adding Equatable back after implicitly suppressing it for an enum. That's probably not very controversial since the extension adds the missing functionality to make it work. Like for Sendable, when you add Copyable in an extension, there are some rules:
struct ConcreteBox: ~Copyable {
var data: Int
// .. other things ..
}
extension ConcreteBox: Copyable {
func getCopy() -> Self { return self }
}
An extension adding Copyable can only technically work in the same translation unit (and really ought to be limited to just the same file) since all of the data stored within it must be known to the compiler. That's just a property of Copyable being a sort of data layout constraint like Sendable.
Otherwise, if you read the above strictly as "ConcreteBox suppresses Copyable" ... "extension of ConcreteBox where all instances are Copyable" then it does seem a bit silly to have suppressed Copyable initially, since it doesn't have any explicit requirements that you can group up under this extension as an organizational tool to show readers "here is how it conforms".
So the unconditional Copyable after initially ~Copyable is something the compiler could warn about as being silly. But I don't necessarily think it's a problem, since it's already impossible to write this extension outside of the same module / file the type is defined within.