Skip to content

Commit d847321

Browse files
KaanOzkanst0012
authored andcommitted
Preserve generic type overrides in Sorbet casts
Assisted-By: devx/eb25d669-b4ee-4e28-9b69-129b45e1e178
1 parent 3ddaca4 commit d847321

4 files changed

Lines changed: 69 additions & 20 deletions

File tree

lib/tapioca/internal.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
require "tapioca/sorbet_ext/backcompat_patches"
1313
require "tapioca/sorbet_ext/name_patch"
1414
require "tapioca/sorbet_ext/generic_name_patch"
15+
require "tapioca/sorbet_ext/generic_type_patch"
1516
require "tapioca/sorbet_ext/proc_bind_patch"
1617
require "tapioca/sorbet_ext/void_patch"
1718
require "tapioca/runtime/generic_type_registry"

lib/tapioca/sorbet_ext/generic_name_patch.rb

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -82,26 +82,6 @@ def name
8282
prepend GenericPatch
8383
end
8484
end
85-
86-
module Utils
87-
module Private
88-
module PrivateCoercePatch
89-
def coerce_and_check_module_types(val, check_val, check_module_type)
90-
if val.is_a?(Tapioca::TypeVariableModule)
91-
val.coerce_to_type_variable
92-
elsif val.respond_to?(:__tapioca_override_type)
93-
val.__tapioca_override_type
94-
else
95-
super
96-
end
97-
end
98-
end
99-
100-
class << self
101-
prepend(PrivateCoercePatch)
102-
end
103-
end
104-
end
10585
end
10686

10787
module Tapioca
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# typed: true
2+
# frozen_string_literal: true
3+
4+
module T
5+
module Utils
6+
module Private
7+
# Preserve Tapioca's generic type variables and instantiated generic
8+
# names when Sorbet coerces them into runtime types.
9+
module TapiocaGenericTypeCoercePatch
10+
def coerce_and_check_module_types(val, check_val, check_module_type)
11+
if val.is_a?(Tapioca::TypeVariableModule)
12+
val.coerce_to_type_variable
13+
elsif val.respond_to?(:__tapioca_override_type)
14+
val.__tapioca_override_type
15+
else
16+
super
17+
end
18+
end
19+
end
20+
21+
class << self
22+
prepend(TapiocaGenericTypeCoercePatch)
23+
end
24+
end
25+
end
26+
27+
module Private
28+
module Casts
29+
module TapiocaGenericTypeCastPatch
30+
# https://github.com/sorbet/sorbet/commit/b8d64c7fd9a08e2b9159b5d592bc2de6d586b44a
31+
# inlines the Module fast path in `T.let`, `T.cast`, `T.bind`, and
32+
# `T.assert_type!`, so generic module clones can reach this cast path
33+
# without going through `T::Utils::Private::TapiocaGenericTypeCoercePatch`.
34+
def cast(value, type, cast_method)
35+
if type.respond_to?(:__tapioca_override_type)
36+
type = type.__tapioca_override_type
37+
end
38+
39+
super(value, type, cast_method)
40+
end
41+
end
42+
43+
class << self
44+
prepend(TapiocaGenericTypeCastPatch)
45+
end
46+
end
47+
end
48+
end

spec/tapioca/runtime/generic_type_registry_spec.rb

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,10 @@ class GenericTypeRegistrySpec < Minitest::Spec
5858
end
5959

6060
describe ".register_type" do
61+
it "allows generic interface implementations to be cast to generic interface types" do
62+
T.let(SampleGenericInterfaceImplementation.new, SampleGenericInterface[Object])
63+
end
64+
6165
it "does not reuse generic instances for redefined constants with the same name" do
6266
first_constant, first_generic_type = register_reloadable_generic
6367

@@ -107,6 +111,22 @@ class SampleGenericClass
107111
Element = type_member
108112
end
109113

114+
module SampleGenericInterface
115+
extend T::Generic
116+
117+
interface!
118+
119+
Element = type_member
120+
end
121+
122+
class SampleGenericInterfaceImplementation
123+
extend T::Generic
124+
125+
include SampleGenericInterface
126+
127+
Element = type_member
128+
end
129+
110130
class RaisesInInheritedCallback
111131
extend T::Generic
112132

0 commit comments

Comments
 (0)