Skip to content

Conversation

@AlexWaygood
Copy link
Member

Summary

Protocol classes are abstract and thus cannot be directly instantiated (although concrete subclasses of protocols can be!). This PR adds logic to detect attempts to instantiate them, and report such attempts as diagnostics.

I also factored out some common code from diagnostics.rs into class.rs.

Test Plan

Existing mdtests updated, and snapshots added.

Local screenshot to show what it looks like in the terminal:

image

@AlexWaygood AlexWaygood added the ty Multi-file analysis & type inference label Apr 23, 2025
@AlexWaygood AlexWaygood force-pushed the alex/ban-protocol-instantiation branch from 1fa7488 to ef3a4b7 Compare April 23, 2025 23:28
@github-actions
Copy link
Contributor

github-actions bot commented Apr 23, 2025

mypy_primer results

No ecosystem changes detected ✅

Copy link
Contributor

@carljm carljm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great!

let db = context.db();
let class_name = protocol.name(db);
let mut diagnostic = builder.into_diagnostic(format_args!(
"Cannot instantiate abstract class `{class_name}`",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure that it's clearest to use the term "abstract" for this? I can see why it's not unreasonable, but both mypy and pyright just say "Cannot instantiate protocol class 'MyProtocol'". It seems like introducing the term "abstract" might be unnecessary complexity, and evoke only-sort-of-related things like ABCMeta? It just forces us to explain below that inheriting Protocol makes a class "implicitly abstract", which seems unnecessary when we could just as well say "it inherits Protocol, making it a protocol class, and protocol classes can't be instantiated"

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, fair point. In my mental model, protocol classes are banned from being instantiated for exactly the same reason that ABCs with abstract methods are banned from being instantiated: both classes represent abstract interfaces to some extent (with the former really just being an extension of the latter in terms of how far you take that idea). But using the term "abstract" probably doesn't help our users, who won't necessary have the same mental model!

@AlexWaygood AlexWaygood enabled auto-merge (squash) April 24, 2025 09:29
@AlexWaygood AlexWaygood merged commit 21fd28d into main Apr 24, 2025
31 checks passed
@AlexWaygood AlexWaygood deleted the alex/ban-protocol-instantiation branch April 24, 2025 09:31
@carljm carljm mentioned this pull request Apr 24, 2025
5 tasks
dcreager added a commit that referenced this pull request Apr 24, 2025
* main:
  [red-knot] fix collapsing literal and its negation to object (#17605)
  [red-knot] Add more tests for protocols (#17603)
  [red-knot] Ban direct instantiations of `Protocol` classes (#17597)
  [`pyupgrade`] Preserve parenthesis when fixing native literals containing newlines (`UP018`) (#17220)
  [`airflow`] fix typos (`AIR302`, `AIR312`) (#17574)
  [red-knot] Special case `@abstractmethod` for function type (#17591)
  [red-knot] Emit diagnostics for isinstance() and issubclass() calls where a non-runtime-checkable protocol is the second argument (#17561)
  [red-knot] Infer the members of a protocol class (#17556)
  [red-knot] Add `FunctionType::to_overloaded` (#17585)
  [red-knot] Add mdtests for `global` statement (#17563)
  [syntax-errors] Make duplicate parameter names a semantic error (#17131)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ty Multi-file analysis & type inference

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants