Why is the "Self == ChecklistToggleStyle" constraint necessary in this extension?

Hi all,

I'm trying to understand why the following extension needs to include where Self == ChecklistToggleStyle:

extension ToggleStyle where Self == ChecklistToggleStyle {
    static var checklist: ChecklistToggleStyle { .init() }
}

This example is from the Apple docs: ToggleStyle | Apple Developer Documentation

If I remove the Self == ChecklistToggleStyle constraint, I get the compiler error:

Contextual member reference to static property 'checklist' requires 'Self' constraint in the protocol extension

Could someone explain why this constraint is needed, and what's going on behind the scenes?

Thanks!

This is SE-0299 in action.

(Incidentally, I moved your question to "Using Swift," because it is not about developing the compiler itself.)

The relevant proposal is here: SE-0299: Extending Static Member Lookup in Generic Contexts.

Swift's implicit member syntax is a special convenience for avoiding unnecessary redundancy when looking up static members of a type like enum cases or static factory methods. It's what allows you to write something like:

label.textColor = .red

instead of

label.textColor = UIColor.red

The basic rule is relatively straightforward: when you're in a context that expects a type R and you have an implicit member reference .foo, you can look up static members foo inside R even though the base type is not named explicitly.

There are various tweaks to this basic rule to make it more ergonomic. For instance, lookup is permitted to look through optionals so that, e.g., an expression .foo will find R.foo even when the context expects a value of type R?. The rule also applies to chains of member accesses so that .foo.bar().baz will work as expected (so long as the baz member is ultimately of the proper type).

SE-0299 introduces an additional rule which allows implicit member expressions to type check even if the contextual type is an (otherwise) not-fully-constrained generic parameter. The rule is that if we have a contextual type of some generic parameter T which conforms to some protocol P then we're allowed to find static members of P. The selection of the implicit base type will be guided by the constraints applied to the extension where the member is found, or possibly by the rest of the member chain.

6 Likes

I didn't know that either. Given that Swift doesn't support parameterizied extension, I wonder if there are any other situations one may use a fully-constrained generic parameter likeSelf == ChecklistToggleStyle? Or to put it in another way, was a constraint like this valid or useful before SE-0299?