Module: T

Defined in:
lib/types/_types.rb,
lib/types/boolean.rb,
lib/sorbet-runtime.rb,
lib/types/compatibility_patches.rb,
lib/types/compatibility_patches.rb,
lib/types/compatibility_patches.rb

Overview

Work around for sorbet-runtime wrapped methods.

When a sig is defined, sorbet-runtime will replace the sigged method with a wrapper. Those wrapper methods look like ‘foo(*args, &blk)` so that wrappers can handle and pass on all the arguments supplied.

However, that creates a problem with runtime reflection on the methods, since when a sigged method is introspected, it will always return its ‘arity` as `-1`, its `parameters` as `[[:rest, :args], [:block, :blk]]`, and its `source_location` as `[<some_file_in_sorbet>, <some_line_number>]`.

This might be a problem for some applications that rely on getting the correct information from these methods.

This compatibility module, when prepended to the ‘Method` class, would fix the return values of `arity`, `parameters` and `source_location`.

Examples:

require 'sorbet-runtime'
::Method.prepend(T::CompatibilityPatches::MethodExtensions)

Defined Under Namespace

Modules: AbstractUtils, Array, Class, CompatibilityPatches, Configuration, DefMods, Enumerable, Enumerator, Generic, Hash, Helpers, Module, Private, Props, Range, Set, Sig, Syntax, Types, Utils Classes: Enum, ImmutableStruct, InexactStruct, Struct

Constant Summary collapse

Boolean =

T::Boolean is a type alias helper for the common ‘T.any(TrueClass, FalseClass)`. Defined separately from _types.rb because it has a dependency on T::Types::Union.

T.type_alias { T.any(TrueClass, FalseClass) }

Class Method Summary collapse

Class Method Details

.absurd(value) ⇒ Object

A way to ask Sorbet to prove that a certain branch of control flow never happens. Commonly used to assert that a case or if statement exhausts all possible cases.



302
303
304
305
306
307
308
309
310
311
312
313
314
315
# File 'lib/types/_types.rb', line 302

def self.absurd(value)
  msg = "Control flow reached T.absurd."

  case value
  when Kernel
    msg += " Got value: #{value}"
  end

  begin
    raise TypeError.new(msg)
  rescue TypeError => e # raise into rescue to ensure e.backtrace is populated
    T::Configuration.inline_type_error_handler(e, {kind: 'T.absurd', value: value, type: nil})
  end
end

.all(type_a, type_b, *types) ⇒ Object

T.all(<Type>, <Type>, …) – matches an object that has all of the types listed



55
56
57
# File 'lib/types/_types.rb', line 55

def self.all(type_a, type_b, *types)
  T::Types::Intersection.new([type_a, type_b] + types)
end

.any(type_a, type_b, *types) ⇒ Object

T.any(<Type>, <Type>, …) – matches any of the types listed



27
28
29
30
31
32
# File 'lib/types/_types.rb', line 27

def self.any(type_a, type_b, *types)
  type_a = T::Utils.coerce(type_a)
  type_b = T::Utils.coerce(type_b)
  types = types.map { |t| T::Utils.coerce(t) } if !types.empty?
  T::Types::Union::Private::Pool.union_of_types(type_a, type_b, types)
end

.anythingObject



50
51
52
# File 'lib/types/_types.rb', line 50

def self.anything
  T::Types::Anything::Private::INSTANCE
end

.assert_type!(value, type, checked: true) ⇒ Object

Tells the typechecker to ensure that ‘value` is of type `type` (if not, the typechecker will fail). Use this for debugging typechecking errors, or to ensure that type information is statically known and being checked appropriately. If `checked` is true, raises an exception at runtime if the value doesn’t match the type.



206
207
208
209
210
211
212
213
214
215
216
217
218
# File 'lib/types/_types.rb', line 206

def self.assert_type!(value, type, checked: true)
  return value unless checked

  # Happy paths for Module literals and T.nilable; see T.cast.
  case type
  when ::Module
    return value if value.is_a?(type)
  when T::Private::Types::SimplePairUnion
    return value if type.valid?(value)
  end

  Private::Casts.cast(value, type, "T.assert_type!")
end

.attached_classObject

Matches the instance type in a singleton-class context



76
77
78
# File 'lib/types/_types.rb', line 76

def self.attached_class
  T::Types::AttachedClassType::Private::INSTANCE
end

.bind(value, type, checked: true) ⇒ Object

Tells the type checker to treat ‘self` in the current block as `type`. Useful for blocks that are captured and executed later with instance_exec. Use like:

seconds = lambda do
  T.bind(self, NewBinding)
  ...
end

‘T.bind` behaves like `T.cast` in that it is assumed to be true statically.

If ‘checked` is true, raises an exception at runtime if the value doesn’t match the type (this is the default).



188
189
190
191
192
193
194
195
196
197
198
199
200
# File 'lib/types/_types.rb', line 188

def self.bind(value, type, checked: true)
  return value unless checked

  # Happy paths for Module literals and T.nilable; see T.cast.
  case type
  when ::Module
    return value if value.is_a?(type)
  when T::Private::Types::SimplePairUnion
    return value if type.valid?(value)
  end

  Private::Casts.cast(value, type, "T.bind")
end

.cast(value, type, checked: true) ⇒ Object

Tells the typechecker that ‘value` is of type `type`. Use this to get additional checking after an expression that the typechecker is unable to analyze. If `checked` is true, raises an exception at runtime if the value doesn’t match the type.

Compared to ‘T.let`, `T.cast` is trusted by static system.



134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/types/_types.rb', line 134

def self.cast(value, type, checked: true)
  return value unless checked

  # Happy paths for the two dominant type shapes at inline-cast sites,
  # duplicated from Private::Casts.cast to skip its call frame: Module
  # literals (e.g. `T.cast(x, Foo)`) and the SimplePairUnion that
  # `T.nilable(SomeModule)` produces. Failures and other type shapes take
  # the full path below.
  case type
  when ::Module
    return value if value.is_a?(type)
  when T::Private::Types::SimplePairUnion
    return value if type.valid?(value)
  end

  Private::Casts.cast(value, type, "T.cast")
end

.class_of(klass) ⇒ Object

Matches any class that subclasses or includes the provided class or module



82
83
84
# File 'lib/types/_types.rb', line 82

def self.class_of(klass)
  T::Types::ClassOf.new(klass)
end

.deprecated_enum(values) ⇒ Object

Deprecated.

Use T::Enum instead.

Matches any of the listed values



61
62
63
# File 'lib/types/_types.rb', line 61

def self.deprecated_enum(values)
  T::Types::Enum.new(values)
end

.let(value, type, checked: true) ⇒ Object

Tells the typechecker to declare a variable of type ‘type`. Use like:

seconds = T.let(0.0, Float)

Compared to ‘T.cast`, `T.let` is checked by static system.

If ‘checked` is true, raises an exception at runtime if the value doesn’t match the type.



161
162
163
164
165
166
167
168
169
170
171
172
173
# File 'lib/types/_types.rb', line 161

def self.let(value, type, checked: true)
  return value unless checked

  # Happy paths for Module literals and T.nilable; see T.cast.
  case type
  when ::Module
    return value if value.is_a?(type)
  when T::Private::Types::SimplePairUnion
    return value if type.valid?(value)
  end

  Private::Casts.cast(value, type, "T.let")
end

.must(arg) ⇒ Object

A convenience method to ‘raise` when the argument is `nil` and return it otherwise.

Intended to be used as:

needs_foo(T.must(maybe_gives_foo))

Equivalent to:

foo = maybe_gives_foo
raise "nil" if foo.nil?
needs_foo(foo)

Intended to be used to promise sorbet that a given nilable value happens to contain a non-nil value at this point.

‘sig T.nilable(A)).returns(A)`



253
254
255
256
257
258
259
260
261
262
# File 'lib/types/_types.rb', line 253

def self.must(arg)
  return arg if arg
  return arg if arg == false

  begin
    raise TypeError.new("Passed `nil` into T.must")
  rescue TypeError => e # raise into rescue to ensure e.backtrace is populated
    T::Configuration.inline_type_error_handler(e, {kind: 'T.must', value: arg, type: nil})
  end
end

.must_because(arg) ⇒ Object

A convenience method to ‘raise` with a provided error reason when the argument is `nil` and return it otherwise.

Intended to be used as:

needs_foo(T.must_because(maybe_gives_foo) {"reason_foo_should_not_be_nil"})

Equivalent to:

foo = maybe_gives_foo
raise "reason_foo_should_not_be_nil" if foo.nil?
needs_foo(foo)

Intended to be used to promise sorbet that a given nilable value happens to contain a non-nil value at this point.

‘sig T.nilable(A), reason_blk: T.proc.returns(String)).returns(A)`



281
282
283
284
285
286
287
288
289
290
# File 'lib/types/_types.rb', line 281

def self.must_because(arg)
  return arg if arg
  return arg if arg == false

  begin
    raise TypeError.new("Unexpected `nil` because #{yield}")
  rescue TypeError => e # raise into rescue to ensure e.backtrace is populated
    T::Configuration.inline_type_error_handler(e, {kind: 'T.must_because', value: arg, type: nil})
  end
end

.nilable(type) ⇒ Object

Shorthand for T.any(type, NilClass)



35
36
37
# File 'lib/types/_types.rb', line 35

def self.nilable(type)
  T::Types::Union::Private::Pool.union_of_types(T::Utils.coerce(type), T::Utils::Nilable::NIL_TYPE)
end

.noreturnObject

Indicates a function never returns (e.g. “Kernel#raise”)



46
47
48
# File 'lib/types/_types.rb', line 46

def self.noreturn
  T::Types::NoReturn::Private::INSTANCE
end

.procObject

Creates a proc type



66
67
68
# File 'lib/types/_types.rb', line 66

def self.proc
  T::Private::Methods.start_proc
end

.reveal_type(value) ⇒ Object

A way to ask Sorbet to show what type it thinks an expression has. This can be useful for debugging and checking assumptions. In the runtime, merely returns the value passed in.



295
296
297
# File 'lib/types/_types.rb', line 295

def self.reveal_type(value)
  value
end

.self_typeObject

Matches ‘self`:



71
72
73
# File 'lib/types/_types.rb', line 71

def self.self_type
  T::Types::SelfType::Private::INSTANCE
end

.type_alias(type = nil, &blk) ⇒ Object

Constructs a type alias. Used to create a short name for a larger type. In Ruby this returns a wrapper that contains a proc that is evaluated to get the underlying type. This syntax however is needed for support by the static checker.

The name of the type alias is not preserved; Error messages will be printed with reference to the underlying type.

TODO Remove ‘type` parameter. This was left in to make life easier while migrating.

Examples:

NilableString = T.type_alias {T.nilable(String)}

sig {params(arg: NilableString, default: String).returns(String)}
def or_else(arg, default)
  arg || default
end


104
105
106
107
108
109
110
# File 'lib/types/_types.rb', line 104

def self.type_alias(type=nil, &blk)
  if blk
    T::Private::Types::TypeAlias.new(blk)
  else
    T::Utils.coerce(type)
  end
end

.type_parameter(name) ⇒ Object

References a type parameter which was previously defined with ‘type_parameters`.

This is used for generic methods.

Examples:

sig
.type_parameters(:U)
.params(
  blk: T.proc.params(arg0: Elem).returns(T.type_parameter(:U)),
)
.returns(T::Array[T.type_parameter(:U)])
def map(&blk); end


125
126
127
# File 'lib/types/_types.rb', line 125

def self.type_parameter(name)
  T::Types::TypeParameter.make(name)
end

.unsafe(value) ⇒ Object

For the static type checker, strips all type information from a value and returns the same value, but statically-typed as ‘T.untyped`. Can be used to tell the static checker to “trust you” by discarding type information you know to be incorrect. Use with care! (This has no effect at runtime.)

We can’t actually write this sig because we ourselves are inside the ‘T::` module and doing this would create a bootstrapping cycle. However, we also don’t actually need to do so; An untyped identity method works just as well here.

‘sig T.untyped).returns(T.untyped)`



232
233
234
# File 'lib/types/_types.rb', line 232

def self.unsafe(value)
  value
end

.untypedObject

Matches any object. In the static checker, T.untyped allows any method calls or operations.



41
42
43
# File 'lib/types/_types.rb', line 41

def self.untyped
  T::Types::Untyped::Private::INSTANCE
end