I still have concerns about how well something like ~Copyable could scale, and think we should be seriously considering a syntax that can apply to more than one type at a time. I think something like a @suppressImplicit(Copyable) attribute could serve us better in that context.
For noncopyable-aware code, the implicit Copyable constraint on generic functions (and likely type arguments) is likely to be the wrong default moving forward. For types, you generally want them to be copyable unless there's a good reason for them not to be; for generic functions, you generally want them to allow non-Copyable arguments unless you explicitly need to copy them. Annotating every generic argument with ~Copyable would be unnecessary visual noise, and not doing so would lead to the wrong default. I'd worry that we'd end up with a similar situation to people (including me) applying @inlinable to every function in the absence of -cross-module-optimization.
On the other hand, if we had something like @suppressImplicit(Copyable), then the following:
struct NonCopyableStruct: ~Copyable {}
func allowsNonCopyable<T: ~Copyable>(argument: T) {}
func requiresCopyable<T>(argument: T) {}
func requiresCopyableA<A, B: ~Copyable>(a: A, b: B) {}
would instead become:
@suppressImplicit(Copyable)
struct NonCopyableStruct {}
@suppressImplicit(Copyable)
func allowsNonCopyable<T>(argument: T) {}
func requiresCopyable<T>(argument: T) {}
@suppressImplicit(Copyable)
func requiresCopyableA<A: Copyable, B>(a: A, b: B) {}
which is a little verbose but unambiguous. The flexibility of this approach, however, means that could optionally be equivalent to something like:
@begin(suppressImplicit(Copyable))
// meaning "apply `@suppressImplicit(Copyable)` to everything in this scope"
struct NonCopyableStruct {}
func allowsNonCopyable<T>(argument: T) {}
func requiresCopyable<T: Copyable>(argument: T) {}
func requiresCopyableA<A: Copyable, B>(a: A, b: B) {}
@end(suppressImplicit(Copyable))
where the suppressImplicit(Copyable) directives could be omitted with a -suppress-implicit=Copyable compiler flag, which is where I think most ownership-aware modules would end up.
It's also worth noting that most generic arguments would still be copyable if they're at all constrained – for example, a Scalar: BinaryFloatingPoint argument would be copyable because BinaryFloatingPoint would presumably conform to Copyable.
The main caveat with this approach is that you might not know you're in a noncopyable scope from glancing at a section of code. However, I think there'd be other indicators to mitigate that – ownership markers on parameters, for example, and the fact that you'd very quickly get a compiler error when you try to copy a not-implicitly-copyable type. On the other hand, a generic function that doesn't accept noncopyable types gives no indicators of that when you write it; you'd instead find out later when you try to use it with a noncopyable type.