タイミーでバックエンドのテックリードをしている新谷(@euglena1215)です。
タイミーでは RBS の活用を推進する取り組みを少しずつ進めています。意図はこちら
メンバーと雑談していたときに「steep check でコケたときにその名前で調べても全然ヒットしないので型周りのキャッチアップが難しい」という話を聞きました。
いくつかのエラー名でググってみたところ、 Ruby::ArgumentTypeMismatch
や Ruby::NoMethod
など有名なエラーはヒットしますがほとんどのエラーはヒットせず、ヒットするのは Steep リポジトリの該当実装のみでした。
これでは確かにキャッチアップは難しいだろうと感じたので、Steep のエラーリファレンスを作ってみました。ググってヒットするのが目的なのでテックブログとして公開してインデックスされることを期待します。
各エラーの説明は以下のフォーマットで行います。
エラー名
説明: 簡単なエラーの説明
例:
エラーが検出される Ruby コード
steep check を実行して得られるエラーメッセージ
severity:
Steep のエラープリセットに対して、該当エラーの severity がどのように設定されているかの表
説明: メソッドの型が一致しない場合に発生します。
違反例:
'1' + 1
test.rb:1:6: [error] Cannot pass a value of type `::Integer` as an argument of type `::string`
│ ::Integer <: ::string
│ ::Integer <: (::String | ::_ToStr)
│ ::Integer <: ::String
│ ::Numeric <: ::String
│ ::Object <: ::String
│ ::BasicObject <: ::String
│
│ Diagnostic ID: Ruby::ArgumentTypeMismatch
│
└ '1' + 1
~
severity:
all_error |
default |
strict |
lenient |
silent |
error |
error |
error |
information |
nil |
説明: ブロックの body の返り値の型が期待される型と一致しない場合に発生します。
違反例:
lambda {|x| x + 1 }
test.rb:1:7: [error] Cannot allow block body have type `::Integer` because declared as type `::String`
│ ::Integer <: ::String
│ ::Numeric <: ::String
│ ::Object <: ::String
│ ::BasicObject <: ::String
│
│ Diagnostic ID: Ruby::BlockBodyTypeMismatch
│
└ lambda {|x| x + 1 } #: ^(Integer) -> String
~~~~~~~~~~~~
severity:
all_error |
default |
strict |
lenient |
silent |
error |
warning |
error |
information |
nil |
説明: ブロックの型が期待される型と一致しない場合に発生します。
違反例:
multi = ->(x, y) { x * y }
[1, 2, 3].map(&multi)
test.rb:2:14: [error] Cannot pass a value of type `^(::Integer, ::Integer) -> ::Integer` as a block-pass-argument of type `^(::Integer) -> U(1)`
│ ^(::Integer, ::Integer) -> ::Integer <: ^(::Integer) -> U(1)
│ (Params are incompatible)
│
│ Diagnostic ID: Ruby::BlockTypeMismatch
│
└ [1, 2, 3].map(&multi)
~~~~~~
severity:
all_error |
default |
strict |
lenient |
silent |
error |
warning |
error |
information |
nil |
説明: break
の型が期待される型と一致しない場合に発生します。
違反例:
123.tap { break "" }
test.rb:1:10: [error] Cannot break with a value of type `::String` because type `::Integer` is assumed
│ ::String <: ::Integer
│ ::Object <: ::Integer
│ ::BasicObject <: ::Integer
│
│ Diagnostic ID: Ruby::BreakTypeMismatch
│
└ 123.tap { break "" }
~~~~~~~~
severity:
all_error |
default |
strict |
lenient |
silent |
error |
hint |
error |
hint |
nil |
説明: メソッドのパラメータの種類が一致しない場合に発生します。省略可能な引数の prefix に ?
をつけ忘れることで発生することが多いです。
違反例:
def bar(name: "foo")
end
test.rb:2:8: [error] The method parameter has different kind from the declaration `(name: ::String) -> void`
│ Diagnostic ID: Ruby::DifferentMethodParameterKind
│
└ def bar(name: "foo")
~~~~~~~~~~~
severity:
all_error |
default |
strict |
lenient |
silent |
error |
hint |
error |
nil |
nil |
説明: 型が不明な場合に untyped
が使用されることを示します。一度 []
で値を初期化したのちに再代入するような実装で発生することが多いです。
違反例:
a = []
a << 1
test.rb:1:4: [error] Cannot detect the type of the expression
│ Diagnostic ID: Ruby::FallbackAny
│
└ a = []
~~
severity:
all_error |
default |
strict |
lenient |
silent |
error |
hint |
warning |
nil |
nil |
説明: Steep の型アサーションが誤っている場合に発生します。
違反例:
array = []
hash = array
test.rb:2:7: [error] Assertion cannot hold: no relationship between inferred type (`::Array[::Integer]`) and asserted type (`::Hash[::Symbol, ::String]`)
│ Diagnostic ID: Ruby::FalseAssertion
│
└ hash = array #: Hash[Symbol, String]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
severity:
all_error |
default |
strict |
lenient |
silent |
error |
hint |
error |
nil |
nil |
説明: 引数無し break
の値( nil
)がメソッドの返り値の期待される型と一致しない場合に発生します。
違反例:
class Foo
def foo
''
end
end
Foo.new.foo do |x|
break
end
test.rb:9:2: [error] Breaking without a value may result an error because a value of type `::String` is expected
│ nil <: ::String
│
│ Diagnostic ID: Ruby::ImplicitBreakValueMismatch
│
└ break
~~~~~
severity:
all_error |
default |
strict |
lenient |
silent |
error |
hint |
information |
nil |
nil |
説明: 型注釈が不適切または一致しない場合に発生します。
違反例:
a = [1,2,3]
if _ = 1
a + ""
end
test.rb:5:2: [error] Type annotation about `a` is incompatible since ::String <: ::Array[::Integer] doesn't hold
│ ::String <: ::Array[::Integer]
│ ::Object <: ::Array[::Integer]
│ ::BasicObject <: ::Array[::Integer]
│
│ Diagnostic ID: Ruby::IncompatibleAnnotation
│
└ a + ""
~~~~~~
severity:
all_error |
default |
strict |
lenient |
silent |
error |
hint |
error |
nil |
nil |
説明: 引数に ...
を使ってメソッドの引数を forward する際に、引数の型が一致しない場合に発生します。
違反例:
class Foo
def foo(*args)
end
def bar(...)
foo(...)
end
end
test.rb:8:8: [error] Cannot forward arguments to `foo`:
│ (*::Integer) <: (*::String)
│ ::String <: ::Integer
│ ::Object <: ::Integer
│
│ Diagnostic ID: Ruby::IncompatibleArgumentForwarding
│
└ foo(...)
~~~
severity:
all_error |
default |
strict |
lenient |
silent |
error |
warning |
error |
information |
nil |
説明: 代入の際の型が不適切または一致しない場合に発生します。
違反例:
x = "string"
test.rb:2:0: [error] Cannot assign a value of type `::String` to a variable of type `::Integer`
│ ::String <: ::Integer
│ ::Object <: ::Integer
│ ::BasicObject <: ::Integer
│
│ Diagnostic ID: Ruby::IncompatibleAssignment
│
└ x = "string"
~~~~~~~~~~~~
severity:
all_error |
default |
strict |
lenient |
silent |
error |
hint |
error |
hint |
nil |
説明: キーワード引数が不足している場合に発生します。
違反例:
class Foo
def foo(a:, b:)
end
end
Foo.new.foo(a: 1)
test.rb:5:8: [error] More keyword arguments are required: b
│ Diagnostic ID: Ruby::InsufficientKeywordArguments
│
└ Foo.new.foo(a: 1)
~~~~~~~~~
severity:
all_error |
default |
strict |
lenient |
silent |
error |
error |
error |
information |
nil |
説明: 位置引数が不足している場合に発生します。
違反例:
class Foo
def foo(a, b)
end
end
Foo.new.foo(1)
test.rb:5:8: [error] More keyword arguments are required: b
│ Diagnostic ID: Ruby::InsufficientKeywordArguments
│
└ Foo.new.foo(a: 1)
~~~~~~~~~
severity:
all_error |
default |
strict |
lenient |
silent |
error |
error |
error |
information |
nil |
説明: 型引数に対する型注釈が不足している場合に発生します。
違反例:
class Foo
def foo(x, y)
[x, y]
end
end
Foo.new.foo(1, 2)
test.rb:8:0: [error] Requires 2 types, but 1 given: `[T, S] (T, S) -> [T, S]`
│ Diagnostic ID: Ruby::InsufficientTypeArgument
│
└ Foo.new.foo(1, 2) #$ Integer
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
severity:
all_error |
default |
strict |
lenient |
silent |
error |
hint |
error |
nil |
nil |
説明: steep:ignore:start
コメントはあるが steep:ignore:end
コメントがないなど、無効なコメントが存在する場合に発生します。
違反例:
test.rb:1:0: [error] Invalid ignore comment
│ Diagnostic ID: Ruby::InvalidIgnoreComment
│
└ # steep:ignore:start
~~~~~~~~~~~~~~~~~~~~
severity:
all_error |
default |
strict |
lenient |
silent |
error |
warning |
warning |
warning |
nil |
説明: キーワード引数なのに順序引数としてメソッドの引数の型を記述しているなど、メソッドの引数の型が一致しない場合に発生します。
違反例:
class Foo
def foo(x:)
x
end
end
test.rb:3:9: [error] Method parameters are incompatible with declaration `(::Integer) -> ::Integer`
│ Diagnostic ID: Ruby::MethodArityMismatch
│
└ def foo(x:)
~~~~
severity:
all_error |
default |
strict |
lenient |
silent |
error |
error |
error |
information |
nil |
説明: メソッドの返り値が期待される型と一致しない場合に発生します。
違反例:
class Foo
def foo
1
end
end
test.rb:3:6: [error] Cannot allow method body have type `::Integer` because declared as type `::String`
│ ::Integer <: ::String
│ ::Numeric <: ::String
│ ::Object <: ::String
│ ::BasicObject <: ::String
│
│ Diagnostic ID: Ruby::MethodBodyTypeMismatch
│
└ def foo
~~~
severity:
all_error |
default |
strict |
lenient |
silent |
error |
error |
error |
warning |
nil |
説明: メソッドの型定義が存在するがメソッドの実装が欠落している場合に発生します。
違反例:
class Foo
end
test.rb:1:6: [error] Cannot find implementation of method `::Foo#bar`
│ Diagnostic ID: Ruby::MethodDefinitionMissing
│
└ class Foo
~~~
severity:
all_error |
default |
strict |
lenient |
silent |
error |
nil |
hint |
nil |
nil |
説明: メソッドのパラメータの型が一致しない場合に発生します。
違反例:
class Foo
def foo(x:)
x
end
end
test.rb:3:10: [error] The method parameter is incompatible with the declaration `(::Integer) -> ::Integer`
│ Diagnostic ID: Ruby::MethodParameterMismatch
│
└ def foo(x:)
~~
severity:
all_error |
default |
strict |
lenient |
silent |
error |
error |
error |
warning |
nil |
説明: メソッドの戻り値の型注釈が期待される型と一致しない場合に発生します。
違反例:
class Foo
def foo
123
end
end
test.rb:3:2: [error] Annotation `@type return` specifies type `::Integer` where declared as type `::String`
│ ::Integer <: ::String
│ ::Numeric <: ::String
│ ::Object <: ::String
│ ::BasicObject <: ::String
│
│ Diagnostic ID: Ruby::MethodReturnTypeAnnotationMismatch
│
└ def foo
~~~~~~~
severity:
all_error |
default |
strict |
lenient |
silent |
error |
hint |
error |
nil |
nil |
説明: 複数代入の変換に失敗した場合に発生します。
違反例:
class WithToAry
def to_ary
1
end
end
a, b = WithToAry.new()
test.rb:8:8: [error] Cannot convert `::WithToAry` to Array or tuple (`#to_ary` returns `::Integer`)
│ Diagnostic ID: Ruby::MultipleAssignmentConversionError
│
└ (a, b = WithToAry.new())
~~~~~~~~~~~~~~~
severity:
all_error |
default |
strict |
lenient |
silent |
error |
hint |
error |
nil |
nil |
説明: 型定義が存在しないメソッドが呼び出された場合に発生します。
違反例:
"".non_existent_method
test.rb:1:3: [error] Type `::String` does not have method `non_existent_method`
│ Diagnostic ID: Ruby::NoMethod
│
└ "".non_existent_method
~~~~~~~~~~~~~~~~~~~
severity:
all_error |
default |
strict |
lenient |
silent |
error |
error |
error |
information |
nil |
説明: Proc
に関する型注釈が無視された場合に発生します。
違反例:
proc = -> (x) { x.to_s }
test.rb:2:7: [error] The type hint given to the block is ignored: `(^(::Integer) -> ::String | ^(::String, ::String) -> ::Integer)`
│ Diagnostic ID: Ruby::ProcHintIgnored
│
└ proc = -> (x) { x.to_s }
~~~~~~~~~~~~~~~~~
severity:
all_error |
default |
strict |
lenient |
silent |
error |
hint |
information |
nil |
nil |
説明: Proc
型が期待される場合に発生します。
違反例:
-> (&block) do
end
test.rb:1:4: [error] Proc type is expected but `::Integer` is specified
│ Diagnostic ID: Ruby::ProcTypeExpected
│
└ -> (&block) do
~~~~~~
severity:
all_error |
default |
strict |
lenient |
silent |
error |
hint |
error |
nil |
nil |
説明: 型アサーションや型適用に書かれたRBS型がエラーを生じる場合に発生します。
違反例:
a = 1
test.rb:1:9: [error] Cannot find type `::Int`
│ Diagnostic ID: Ruby::RBSError
│
└ a = 1 #: Int
~~~
severity:
all_error |
default |
strict |
lenient |
silent |
error |
information |
error |
information |
nil |
説明: メソッド呼び出し時に必要な block が欠落している場合に発生します。
違反例:
class Foo
def foo
yield
end
end
Foo.new.foo
test.rb:7:8: [error] The method cannot be called without a block
│ Diagnostic ID: Ruby::RequiredBlockMissing
│
└ Foo.new.foo
~~~
severity:
all_error |
default |
strict |
lenient |
silent |
error |
error |
error |
hint |
nil |
説明: return
の型とメソッドの戻り値の型が一致しない場合に発生します。
違反例:
def foo
return "string"
end
test.rb:3:2: [error] The method cannot return a value of type `::String` because declared as type `::Integer`
│ ::String <: ::Integer
│ ::Object <: ::Integer
│ ::BasicObject <: ::Integer
│
│ Diagnostic ID: Ruby::ReturnTypeMismatch
│
└ return "string"
~~~~~~~~~~~~~~~
severity:
all_error |
default |
strict |
lenient |
silent |
error |
error |
error |
warning |
nil |
説明: セッターメソッドの戻り値の型が期待される型と一致しない場合に発生します。
違反例:
class Foo
def foo=(value)
123
end
end
test.rb:3:6: [error] Setter method `foo=` cannot have type `::Integer` because declared as type `::String`
│ ::Integer <: ::String
│ ::Numeric <: ::String
│ ::Object <: ::String
│ ::BasicObject <: ::String
│
│ Diagnostic ID: Ruby::SetterBodyTypeMismatch
│
└ def foo=(value)
~~~~
severity:
all_error |
default |
strict |
lenient |
silent |
error |
information |
error |
nil |
nil |
説明: セッターメソッドの return
の型が期待される型と一致しない場合に発生します。
違反例:
class Foo
def foo=(value)
return 123
end
end
test.rb:4:4: [error] The setter method `foo=` cannot return a value of type `::Integer` because declared as type `::String`
│ ::Integer <: ::String
│ ::Numeric <: ::String
│ ::Object <: ::String
│ ::BasicObject <: ::String
│
│ Diagnostic ID: Ruby::SetterReturnTypeMismatch
│
└ return 123
~~~~~~~~~~
severity:
all_error |
default |
strict |
lenient |
silent |
error |
information |
error |
nil |
nil |
説明: Ruby の構文エラーが発生した場合に発生します。
違反例:
if x == 1
puts "Hello"
test.rb:2:14: [error] SyntaxError: unexpected token $end
│ Diagnostic ID: Ruby::SyntaxError
│
└ puts "Hello"
severity:
all_error |
default |
strict |
lenient |
silent |
error |
hint |
hint |
hint |
nil |
説明: 型引数が期待される型と一致しない場合に発生します。
違反例:
class Foo
def foo(x)
x
end
end
Foo.new.foo("")
test.rb:7:19: [error] Cannot pass a type `::String` as a type parameter `T < ::Numeric`
│ ::String <: ::Numeric
│ ::Object <: ::Numeric
│ ::BasicObject <: ::Numeric
│
│ Diagnostic ID: Ruby::TypeArgumentMismatchError
│
└ Foo.new.foo("") #$ String
~~~~~~
severity:
all_error |
default |
strict |
lenient |
silent |
error |
hint |
error |
nil |
nil |
説明: ブロックが予期されない場面で渡された場合に発生します。
違反例:
[1].at(1) { 123 }
test.rb:1:10: [error] The method cannot be called with a block
│ Diagnostic ID: Ruby::UnexpectedBlockGiven
│
└ [1].at(1) { 123 }
~~~~~~~
severity:
all_error |
default |
strict |
lenient |
silent |
error |
warning |
error |
hint |
nil |
説明: 動的に定義されたメソッドが存在しない場合に発生します。
違反例:
class Foo
def bar
end
end
test.rb:1:6: [error] @dynamic annotation contains unknown method name `foo`
│ Diagnostic ID: Ruby::UnexpectedDynamicMethod
│
└ class Foo
~~~
severity:
all_error |
default |
strict |
lenient |
silent |
error |
hint |
information |
nil |
nil |
説明: 予期しない一般的なエラーが発生した場合に発生します。
違反例:
class Foo
def foo
end
end
test.rb:1:0: [error] UnexpectedError: sig/generated/test.rbs:5:17...5:26: Could not find String123(RBS::NoTypeFoundError)
│ ...
│ (36 more backtrace)
│
│ Diagnostic ID: Ruby::UnexpectedError
│
└ class Foo
~~~~~~~~~
severity:
all_error |
default |
strict |
lenient |
silent |
error |
hint |
information |
hint |
nil |
説明: 予期しないジャンプが発生した場合に発生します。
違反例:
break
test.rb:1:0: [error] Cannot jump from here
│ Diagnostic ID: Ruby::UnexpectedJump
│
└ break
~~~~~
severity:
all_error |
default |
strict |
lenient |
silent |
error |
hint |
error |
nil |
nil |
説明: ジャンプの値を渡しても値が無視される場合に発生します。
違反例:
while true
next 3
end
test.rb:2:2: [error] The value given to next will be ignored
│ Diagnostic ID: Ruby::UnexpectedJumpValue
│
└ next 3
~~~~~~
severity:
all_error |
default |
strict |
lenient |
silent |
error |
hint |
error |
nil |
nil |
説明: 予期しないキーワード引数が渡された場合に発生します。
違反例:
class Foo
def foo(x:)
end
end
Foo.new.foo(x: 1, y: 2)
test.rb:7:18: [error] Unexpected keyword argument
│ Diagnostic ID: Ruby::UnexpectedKeywordArgument
│
└ Foo.new.foo(x: 1, y: 2)
~
severity:
all_error |
default |
strict |
lenient |
silent |
error |
error |
error |
information |
nil |
説明: 予期しない位置引数が渡された場合に発生します。
違反例:
class Foo
def foo(x)
end
end
Foo.new.foo(1, 2)
test.rb:7:15: [error] Unexpected positional argument
│ Diagnostic ID: Ruby::UnexpectedPositionalArgument
│
└ Foo.new.foo(1, 2)
~
severity:
all_error |
default |
strict |
lenient |
silent |
error |
error |
error |
information |
nil |
説明: super
を呼び出した際に親クラスに同名のメソッドが定義されていないなど、予期しない場面で super
が使用された場合に発生します。
違反例:
class Foo
def foo
super
end
end
test.rb:3:4: [error] No superclass method `foo` defined
│ Diagnostic ID: Ruby::UnexpectedSuper
│
└ super
~~~~~
severity:
all_error |
default |
strict |
lenient |
silent |
error |
information |
error |
nil |
nil |
説明: 予期しない型引数が渡された場合に発生します。
違反例:
class Foo
def foo(x)
x
end
end
Foo.new.foo(1)
test.rb:8:27: [error] Unexpected type arg is given to method type `[T] (T) -> T`
│ Diagnostic ID: Ruby::UnexpectedTypeArgument
│
└ Foo.new.foo(1) #$ Integer, Integer
~~~~~~~
severity:
all_error |
default |
strict |
lenient |
silent |
error |
hint |
error |
nil |
nil |
説明: yield
が予期しない場面で使用された場合に発生します。
違反例:
class Foo
def foo
yield
end
end
test.rb:4:4: [error] No block given for `yield`
│ Diagnostic ID: Ruby::UnexpectedYield
│
└ yield
~~~~~
severity:
all_error |
default |
strict |
lenient |
silent |
error |
warning |
error |
information |
nil |
説明: 未知の定数が参照された場合に発生します。
違反例:
FOO
test.rb:1:0: [error] Cannot find the declaration of constant: `FOO`
│ Diagnostic ID: Ruby::UnknownConstant
│
└ FOO
~~~
severity:
all_error |
default |
strict |
lenient |
silent |
error |
warning |
error |
hint |
nil |
説明: 未知のグローバル変数が参照された場合に発生します。
違反例:
$foo
test.rb:1:0: [error] Cannot find the declaration of global variable: `$foo`
│ Diagnostic ID: Ruby::UnknownGlobalVariable
│
└ $foo
~~~~
severity:
all_error |
default |
strict |
lenient |
silent |
error |
warning |
error |
hint |
nil |
説明: 未知のインスタンス変数が参照された場合に発生します。
違反例:
class Foo
def foo
@foo = 'foo'
end
end
test.rb:3:4: [error] Cannot find the declaration of instance variable: `@foo`
│ Diagnostic ID: Ruby::UnknownInstanceVariable
│
└ @foo = 'foo'
~~~~
severity:
all_error |
default |
strict |
lenient |
silent |
error |
information |
error |
hint |
nil |
説明: if
,unless
による到達不可能な分岐が存在する場合に発生します。
違反例:
if false
1
end
test.rb:1:0: [error] The branch is unreachable
│ Diagnostic ID: Ruby::UnreachableBranch
│
└ if false
~~
severity:
all_error |
default |
strict |
lenient |
silent |
error |
hint |
information |
hint |
nil |
説明: case when
による到達不可能な分岐が存在し、分岐の型が bot
でなかった場合に発生します。
違反例:
x = 1
case x
when Integer
"one"
when String
"two"
end
test.rb:5:0: [error] The branch may evaluate to a value of `::String` but unreachable
│ Diagnostic ID: Ruby::UnreachableValueBranch
│
└ when String
~~~~
severity:
all_error |
default |
strict |
lenient |
silent |
error |
hint |
warning |
hint |
nil |
説明: オーバーロードが行われているメソッドに対して型が解決できない場合に発生します。
違反例:
3 + "foo"
test.rb:1:0: [error] Cannot find compatible overloading of method `+` of type `::Integer`
│ Method types:
│ def +: (::Integer) -> ::Integer
│ | (::Float) -> ::Float
│ | (::Rational) -> ::Rational
│ | (::Complex) -> ::Complex
│
│ Diagnostic ID: Ruby::UnresolvedOverloading
│
└ 3 + "foo"
~~~~~~~~~
severity:
all_error |
default |
strict |
lenient |
silent |
error |
error |
error |
information |
nil |
説明: RBSと型注釈の辻褄が合わないなど、どうやっても型制約が満たされない場合に発生します。
違反例:
class Foo
def foo(x)
end
end
test = Foo.new
test.foo(1) do |x|
end
test.rb:9:0: [error] Unsatisfiable constraint `::Integer <: A(1) <: ::String` is generated through (A(1)) { (A(1)) -> void } -> B(2)
│ ::Integer <: ::String
│ ::Numeric <: ::String
│ ::Object <: ::String
│ ::BasicObject <: ::String
│
│ Diagnostic ID: Ruby::UnsatisfiableConstraint
│
└ test.foo(1) do |x|
~~~~~~~~~~~~~~~~~~
severity:
all_error |
default |
strict |
lenient |
silent |
error |
hint |
error |
hint |
nil |
説明: Steep としてサポートされていない構文が使用された場合に発生します。
違反例:
(_ = []).[]=(*(_ = nil))
test.rb:1:13: [error] Unsupported splat node occurrence
│ Diagnostic ID: Ruby::UnsupportedSyntax
│
└ (_ = []).[]=(*(_ = nil))
~~~~~~~~~~
severity:
all_error |
default |
strict |
lenient |
silent |
error |
hint |
information |
hint |
nil |
狙ったエラーを引き起こすというのは今年の RubyKaigi であった Ruby "enbugging" Quiz に近い感覚でした。難しい。
基本的には Steep リポジトリにあるテストケースを見ながら埋めていったんですが、中にはテストケースがないものもあったので soutaro さんに直接質問をしながら進めていきました。
また、副産物として Steep で使われなくなったが定義として残っているルールを発見し、削除する patch を作れたのも個人的には良かったです。
github.com