Share
Embed
Transcript
102 slides
-
Soutaro Matsumoto • Ruby committer working for RBS/ Steep •
Working at Timee • Started writing a series of articles for ιϑτΣΞσβΠϯ New -
Soutaro Matsumoto • Ruby committer working for RBS/ Steep •
Working at Timee • Started writing a series of articles for ιϑτΣΞσβΠϯ New -
Steep & RBS updates • RBS 3.4 (RubyKaigi 2024) →
3.9 • Steep 1.6 (RubyKaigi 2024) → 1.10 -
Generics with default types rbs-3.6 steep:ignore annotation steep-1.7 Better project
organization steep-1.9 -
Generics with default types rbs-3.6 resolve-type-names magic comment rbs-3.9 steep:ignore
annotation steep-1.7 Better project organization steep-1.9 -
Generics with default types rbs-3.6 resolve-type-names magic comment rbs-3.9 Deprecation
annotation rbs-3.9, steep-1.10 steep:ignore annotation steep-1.7 Better project organization steep-1.9 -
Generics with default types rbs-3.6 resolve-type-names magic comment rbs-3.9 Deprecation
annotation rbs-3.9, steep-1.10 steep:ignore annotation steep-1.7 Better project organization steep-1.9 Memory footprint improvement steep-1.9 $ steep langserver --refork -
Generics with default types rbs-3.6 resolve-type-names magic comment rbs-3.9 Deprecation
annotation rbs-3.9, steep-1.10 steep:ignore annotation steep-1.7 Better project organization steep-1.9 Memory footprint improvement steep-1.9 $ steep langserver --refork Receiver type narrowing steep-1.10 -
Generics with default types rbs-3.6 resolve-type-names magic comment rbs-3.9 Deprecation
annotation rbs-3.9, steep-1.10 steep:ignore annotation steep-1.7 Better project organization steep-1.9 Memory footprint improvement steep-1.9 $ steep langserver --refork Receiver type narrowing steep-1.10 -
Generics with default types rbs-3.6 resolve-type-names magic comment rbs-3.9 Deprecation
annotation rbs-3.9, steep-1.10 steep:ignore annotation steep-1.7 Better project organization steep-1.9 Memory footprint improvement steep-1.9 $ steep langserver --refork Receiver type narrowing steep-1.10 -
Inline RBS declaration • Not yet... 🙇 • Working for
RBS 4.0/Steep 2.0 with the feature • They will support inline RBS declaration directly, without rbs-inline gem -
Documentation helper in Steep • Steep helps reading docs associated
to the Ruby program components -- classes/modules/methods/interfaces/constants • Hover • Completion • Signature Help -
Writing docs • You can put markdown text associated to
RBS constructs -
This is API • These features are implemented on the
top of API that looks up docs with classes/modules/methods RBS fi les Internal data structure API Language Server -
What is RDoc? ## # Creates a new shape described
by a +polyline+. # # If the +polyline+ does not end at the same point it started at the # first pointed is copied and placed at the end of the line. # # An ArgumentError is raised if the line crosses itself, but shapes may # be concave. def initialize polyline # ... end The syntax to annotate Ruby code -
What is RDoc? ## # Creates a new shape described
by a +polyline+. # # If the +polyline+ does not end at the same point it started at the # first pointed is copied and placed at the end of the line. # # An ArgumentError is raised if the line crosses itself, but shapes may # be concave. def initialize polyline # ... end The syntax to annotate Ruby code The generated HTML fi les -
What is RDoc? ## # Creates a new shape described
by a +polyline+. # # If the +polyline+ does not end at the same point it started at the # first pointed is copied and placed at the end of the line. # # An ArgumentError is raised if the line crosses itself, but shapes may # be concave. def initialize polyline # ... end The syntax to annotate Ruby code The generated HTML fi les The internal structure -
## # Creates a new shape described by a +polyline+.
# # If the +polyline+ does not end at the same point it started at the # first pointed is copied and placed at the end of the line. # # An ArgumentError is raised if the line crosses itself, but shapes may # be concave. def initialize polyline # ... end Input Internal structure Output RBS fi les -
## # Creates a new shape described by a +polyline+.
# # If the +polyline+ does not end at the same point it started at the # first pointed is copied and placed at the end of the line. # # An ArgumentError is raised if the line crosses itself, but shapes may # be concave. def initialize polyline # ... end Input Internal structure Output RBS fi les -
RBS/Steep Implementation 1. The AST 2. The parser 3. The
environment 4. The type checker 5. Displaying the docs RBS RBS RBS Steep Steep -
The AST • The AST has comments associated to each
RBS construct -
The AST • The AST has comments associated to each
RBS construct -
The AST • The AST has comments associated to each
RBS construct -
The AST • The AST has comments associated to each
RBS construct -
The environment • Environment stores all of the RBS declarations
• Definition is the data structure that has methods and variables of a class/module -
The environment • Environment stores all of the RBS declarations
• Definition is the data structure that has methods and variables of a class/module -
The environment • Environment stores all of the RBS declarations
• Definition is the data structure that has methods and variables of a class/module -
The environment • Environment stores all of the RBS declarations
• Definition is the data structure that has methods and variables of a class/module -
Type checker • The type checker identi fi es the
type of each Ruby node • It also detects which method overload is called by a send node s = String.new() s.encoding -
Type checker • The type checker identi fi es the
type of each Ruby node • It also detects which method overload is called by a send node s = String.new() s.encoding -
Type checker • The type checker identi fi es the
type of each Ruby node • It also detects which method overload is called by a send node s = String.new() s.encoding -
Type checker • The type checker identi fi es the
type of each Ruby node • It also detects which method overload is called by a send node s = String.new() s.encoding -
Type checker • The type checker identi fi es the
type of each Ruby node • It also detects which method overload is called by a send node s = String.new() s.encoding -
Type checker • The type checker identi fi es the
type of each Ruby node • It also detects which method overload is called by a send node s = String.new() s.encoding -
Type checker • The type checker identi fi es the
type of each Ruby node • It also detects which method overload is called by a send node s = String.new() s.encoding -
Displaying the docs { "method": "document/hover", "id": 1, "params": {
"textDocument": { uri: "file://..." }, "position": { "line": 10, "character": 20 } } } Language server { "id": 1, "result": { "contents": "## 📚 String#encoding\n\nReturns the encoding" } } 1. Find the Ruby node associated at the position 2. Fetch the docs for the node 3. Format the docs for LSP -
Problems • Steep starts type checking when you edit only
comments in RBS fi les -
Problems • Steep starts type checking when you edit only
comments in RBS fi les -
Index • Introducing an index would solve the problem •
RBS docs are registered to the index • The language server pulls the docs from the index using identi fi ers • The index may be reused after server restart Index Language server Query the docs by identi fi ers -
Overload identi fi er • With line number of the
overload? • Foo#[email protected]:4 • Foo#[email protected]:4 -
Overload identi fi er • With line number of the
overload? • Foo#[email protected]:4 • Foo#[email protected]:4 -
Overload identi fi er • With line number of the
overload? • Foo#[email protected]:4 • Foo#[email protected]:4 -
Overload identi fi er • The line number may change
after comment update 😫 • Foo#[email protected]:4 • Foo#[email protected]:4 -
Overload identi fi er • The line number may change
after comment update 😫 • Foo#[email protected]:4 • Foo#[email protected]:4 -
Overload identi fi er • The line number may change
after comment update 😫 • Foo#[email protected]:4 • Foo#[email protected]:4 -
Overload identi fi er • With the index of the
overload? • Foo#foo@0 • Foo#foo@1 • Overloads added with ... comes fi rst -
Overload identi fi er • With the index of the
overload? • Foo#foo@0 • Foo#foo@1 • Overloads added with ... comes fi rst -
Overload identi fi er • With the index of the
overload? • Foo#foo@0 • Foo#foo@1 • Overloads added with ... comes fi rst -
Overload identi fi er • The fi le loading order
is unspeci fi ed • Foo#foo@0 • Foo#foo@1 • Foo#foo@2 • (Foo#foo@2 always points to String case) -
Overload identi fi er • The fi le loading order
is unspeci fi ed • Foo#foo@0 • Foo#foo@1 • Foo#foo@2 • (Foo#foo@2 always points to String case) -
Overload identi fi er • The fi le loading order
is unspeci fi ed • Foo#foo@0 • Foo#foo@1 • Foo#foo@2 • (Foo#foo@2 always points to String case) -
Annotate method names with types • Foo#foo@(String) -> void •
Foo#foo@(Integer) -> void -
JVM method descriptor • JVM method name contains parameter types
and return type hello(Ljava/lang/String;I)Ljava/lang/String; String hello(String s, int i) -
Method name normalization • Let's call it MethodType#normalize • Implementation
agnostic • Stable after restarts (String name, id: ::Integer, email: String?) -> void (String, email: String?, id: Integer) -> void -
Method name normalization • Let's call it MethodType#normalize • Implementation
agnostic • Stable after restarts (String name, id: ::Integer, email: String?) -> void (String, email: String?, id: Integer) -> void Drop parameter names -
Method name normalization • Let's call it MethodType#normalize • Implementation
agnostic • Stable after restarts (String name, id: ::Integer, email: String?) -> void (String, email: String?, id: Integer) -> void Drop parameter names Sort keyword args -
s = String.new() s.encoding singleton(String) type String class name Type
checker Doc system -
s = String.new() s.encoding singleton(String) type String class name Type
checker Doc system -
s = String.new() s.encoding singleton(String) type String class name Type
checker Doc system -
s = String.new() s.encoding singleton(String) type String class name String#encoding@()
-> Encoding overload Type checker Doc system -
s = String.new() s.encoding singleton(String) type String class name String#encoding@()
-> Encoding overload Type checker Doc system -
Can it be universal? • Making the index from other
gems would be great idea • RDoc/YARD makes the index with their docs • Steep/ruby-lsp can use the index for their documentation features ## # Creates a new shape described by a +polyline+. # # If the +polyline+ does not end at the same point it started at the # first pointed is copied and placed at the end of the line. # # An ArgumentError is raised if the line crosses itself, but shapes may # be concave. def initialize polyline # ... end Input Universal index Output RBS fi les -
Index content • Discussed the key of the index; assume
we have a solution • How can we de fi ne the content of the index? • A data structure that can be shared with RBS/Steep, RDoc, YARD, which keeps the contents of all of them? • How about go-to-de fi nition? -
Summary • The documentation needs APIs because it's used by
IDE/editors to help programming • Steep already has implementation, but it is tightly coupled with type checker and causing problems • I plan to implement a doc system API (index) • The index may help other tools too (but I'm not sure if it's a good idea)