Skip to content

Support type aliases as module self types and ntersections in module self types - #3256

Open
HoneyryderChuck wants to merge 2 commits into
ruby:masterfrom
HoneyryderChuck:module-self-type-aliases
Open

HoneyryderChuck wants to merge 2 commits into
ruby:masterfrom
HoneyryderChuck:module-self-type-aliases

Conversation

@HoneyryderChuck

Copy link
Copy Markdown
Contributor

This PR adds the following changes:

Support type aliases as module self types

Module self types can now be type aliases (`module Foo : foo`), including
generic and namespaced ones, both in RBS files and in inline
`@rbs module-self:` annotations. The alias is expanded into the class
instance and interface types it's composed of, so an alias to an
intersection is equivalent to listing each component as a self type.

    interface _Reader[T]
      def read: () -> T
    end

    module Writer
      def write: (String) -> void
    end

    type io[T] = _Reader[T] & Writer

    # Same as `module Buffered : _Reader[String], Writer`
    module Buffered : io[String]
    end

    # @rbs module-self: io[String]
    module InlineBuffered
    end

Aliases expanding to other types (e.g. unions) raise the new
`InvalidSelfTypeError`, and recursive aliases raise
`RecursiveTypeAliasError`.

Support intersections in module self types

Self types can now be separated with `&` in addition to `,`, and an
intersection is equivalent to listing each component as a self type.

    module Persistent
    end

    module Stream
    end

    # Same as `module GRPC : Persistent, Stream`
    module GRPC : Persistent & Stream
    end

    # Components can be classes, modules, interfaces, or type aliases
    module Foo : Persistent & _Each[String] & io[String]
    end

HoneyryderChuck and others added 2 commits October 23, 2026 09:38
Module self types can now be type aliases (`module Foo : foo`), including
generic and namespaced ones, both in RBS files and in inline
`@rbs module-self:` annotations. The alias is expanded into the class
instance and interface types it's composed of, so an alias to an
intersection is equivalent to listing each component as a self type.

    interface _Reader[T]
      def read: () -> T
    end

    module Writer
      def write: (String) -> void
    end

    type io[T] = _Reader[T] & Writer

    # Same as `module Buffered : _Reader[String], Writer`
    module Buffered : io[String]
    end

    # @RBS module-self: io[String]
    module InlineBuffered
    end

Aliases expanding to other types (e.g. unions) raise the new
`InvalidSelfTypeError`, and recursive aliases raise
`RecursiveTypeAliasError`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Self types can now be separated with `&` in addition to `,`, and an
intersection is equivalent to listing each component as a self type.

    module Persistent
    end

    module Stream
    end

    # Same as `module GRPC : Persistent, Stream`
    module GRPC : Persistent & Stream
    end

    # Components can be classes, modules, interfaces, or type aliases
    module Foo : Persistent & _Each[String] & io[String]
    end

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant