carbon-core 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/.gitattributes +17 -0
  3. data/.gitignore +0 -0
  4. data/.rspec +0 -0
  5. data/.rubocop.yml +0 -0
  6. data/.travis.yml +0 -0
  7. data/.yardopts +0 -0
  8. data/CODE_OF_CONDUCT.md +0 -0
  9. data/Gemfile +0 -0
  10. data/LICENSE.txt +0 -0
  11. data/README.md +0 -0
  12. data/Rakefile +0 -0
  13. data/Vagrantfile +0 -0
  14. data/carbon.gemspec +0 -0
  15. data/lib/carbon.rb +25 -1
  16. data/lib/carbon/concrete.rb +4 -2
  17. data/lib/carbon/concrete/build.rb +21 -13
  18. data/lib/carbon/concrete/index.rb +53 -159
  19. data/lib/carbon/concrete/item.rb +0 -0
  20. data/lib/carbon/concrete/item/base.rb +14 -27
  21. data/lib/carbon/concrete/item/class.rb +71 -0
  22. data/lib/carbon/concrete/item/class/element.rb +42 -0
  23. data/lib/carbon/concrete/item/data.rb +0 -0
  24. data/lib/carbon/concrete/item/function.rb +35 -39
  25. data/lib/carbon/concrete/item/internal.rb +17 -19
  26. data/lib/carbon/concrete/item/struct.rb +12 -7
  27. data/lib/carbon/concrete/item/struct/element.rb +0 -0
  28. data/lib/carbon/concrete/item/trait.rb +9 -10
  29. data/lib/carbon/concrete/item/trait/expectation.rb +0 -0
  30. data/lib/carbon/concrete/request.rb +137 -136
  31. data/lib/carbon/concrete/type.rb +126 -21
  32. data/lib/carbon/concrete/type/function.rb +26 -10
  33. data/lib/carbon/concrete/type/generic.rb +19 -3
  34. data/lib/carbon/concrete/type/name.rb +0 -0
  35. data/lib/carbon/concrete/type/parse.rb +1 -0
  36. data/lib/carbon/concrete/type/part.rb +9 -1
  37. data/lib/carbon/core.rb +6 -1
  38. data/lib/carbon/core/int.rb +0 -0
  39. data/lib/carbon/core/integer.rb +0 -0
  40. data/lib/carbon/core/integer/cast.rb +0 -0
  41. data/lib/carbon/core/integer/math.rb +0 -0
  42. data/lib/carbon/core/integer/misc.rb +17 -1
  43. data/lib/carbon/core/integer/pole.rb +0 -0
  44. data/lib/carbon/core/integer/ship.rb +8 -4
  45. data/lib/carbon/core/integer/sign.rb +0 -0
  46. data/lib/carbon/core/integer/type.rb +0 -0
  47. data/lib/carbon/core/integer/zero.rb +0 -0
  48. data/lib/carbon/core/main.rb +50 -0
  49. data/lib/carbon/core/pointer.rb +0 -0
  50. data/lib/carbon/core/pointer/access.rb +1 -1
  51. data/lib/carbon/core/pointer/cast.rb +0 -0
  52. data/lib/carbon/core/pointer/math.rb +14 -0
  53. data/lib/carbon/core/pointer/memory.rb +2 -4
  54. data/lib/carbon/core/pointer/type.rb +0 -0
  55. data/lib/carbon/core/void.rb +20 -0
  56. data/lib/carbon/counter.rb +27 -0
  57. data/lib/carbon/errors.rb +13 -0
  58. data/lib/carbon/tacky.rb +0 -0
  59. data/lib/carbon/tacky/block.rb +0 -0
  60. data/lib/carbon/tacky/builder.rb +3 -6
  61. data/lib/carbon/tacky/context.rb +4 -10
  62. data/lib/carbon/tacky/function.rb +0 -24
  63. data/lib/carbon/tacky/instruction.rb +2 -5
  64. data/lib/carbon/tacky/instruction/generation.rb +19 -41
  65. data/lib/carbon/tacky/parameter.rb +0 -0
  66. data/lib/carbon/tacky/reference.rb +0 -0
  67. data/lib/carbon/tacky/typed.rb +0 -0
  68. data/lib/carbon/tacky/value.rb +0 -2
  69. data/lib/carbon/version.rb +1 -1
  70. data/scripts/core.rb +0 -0
  71. data/scripts/test.rb +5 -7
  72. metadata +9 -4
  73. data/lib/carbon/tacky/instruction/dependencies.rb +0 -33
  74. data/lib/carbon/tacky/instruction/typeof.rb +0 -25
File without changes
@@ -19,7 +19,7 @@ module Carbon
19
19
 
20
20
  # (see Item::Base.from)
21
21
  def self.from(type)
22
- { module: type, expectations: [] }
22
+ { type: type, expectations: [] }
23
23
  end
24
24
 
25
25
  # The expectations for the trait.
@@ -34,14 +34,13 @@ module Carbon
34
34
  # Initialize the trait with data.
35
35
  #
36
36
  # @param data [::Hash] The data to initialize the trait with.
37
- # @option data [Type] :module The name of the trait type.
37
+ # @option data [Type] :type The name of the trait type.
38
38
  # @option data [<(::String, <Type>, Type)>] :expectations
39
39
  # The expectations that the trait requires.
40
40
  def initialize(data)
41
- @module = data.fetch(:module)
42
- @generics = @module.generics
43
- @intern = @module.intern
44
- @name = @module.to_s
41
+ @type = data.fetch(:type)
42
+ @generics = @type.generics
43
+ @name = @type.to_s
45
44
 
46
45
  derive_expectations(data.fetch(:expectations))
47
46
  derive_dependencies
@@ -49,8 +48,8 @@ module Carbon
49
48
  end
50
49
 
51
50
  # (see Base#call)
52
- def call(build, generics)
53
- super # TODO: fixme.
51
+ def call(_build, _generics)
52
+ # do nothing.
54
53
  end
55
54
 
56
55
  private
@@ -62,8 +61,8 @@ module Carbon
62
61
 
63
62
  def derive_dependencies
64
63
  @expectations.each do |expect|
65
- @dependencies.merge(expect.parameters.map(&:to_request))
66
- @dependencies << expect.return.to_request
64
+ @dependencies.merge(expect.parameters)
65
+ @dependencies << expect.return
67
66
  end
68
67
  end
69
68
  end
File without changes
@@ -1,137 +1,138 @@
1
- # encoding: utf-8
1
+ # # encoding: utf-8
2
2
  # frozen_string_literal: true
3
-
4
- require "forwardable"
5
-
6
- module Carbon
7
- module Concrete
8
- # A "request." This is used to note the generics that a given module
9
- # should be compiled with. This is used for items to note the dependencies
10
- # that an item has; otherwise, it is used in the index for build
11
- # information.
12
- #
13
- # @note
14
- # **This class is frozen upon initialization.** This means that any
15
- # attempt to modify it will result in an error. In most cases, the
16
- # attributes on this class will also be frozen, as well.
17
- class Request
18
- extend Forwardable
19
-
20
- # The interned name of a module. This is used for module lookup. This
21
- # contains no generic information. For generic functions, all generics
22
- # are pushed onto the defining module.
23
- #
24
- # @api public
25
- # @example
26
- # request.intern # => "Carbon::Pointer"
27
- # @note See {Item::Base#intern} For more information about interned
28
- # names.
29
- # @return [::String]
30
- attr_reader :intern
31
-
32
- # The generics of the request. Even if the request has no definable
33
- # generics, these are still kept in place for both name information and
34
- # for placement information (e.g. identity and size).
35
- #
36
- # @api public
37
- # @example
38
- # request.generics # => [#<Carbon::Concrete::Type::Generic T>]
39
- # @return [<Type::Generic>]
40
- attr_reader :generics
41
-
42
- # Initialize the request with the given interned name and generics,
43
- # and then freezes the request.
44
- #
45
- # @api public
46
- # @see #intern
47
- # @see #generics
48
- # @param intern [::String] The interned name.
49
- # @param generics [<Type::Generic>] The generics.
50
- def initialize(intern, generics)
51
- @intern = intern
52
- @generics = generics
53
- deep_freeze!
54
- end
55
-
56
- # Replaces this request or this request's generics with the corresponding
57
- # correct module. This is designed to resolve generic names; for
58
- # example, it resolves `Carbon::Pointer<T>` to
59
- # `Carbon::Pointer<Carbon::String>` with the right argument. It checks
60
- # for three seperate cases.
61
- #
62
- # 1. The request has no generics, and the request's {#intern} has a
63
- # mapping in the argument. In this case, it creates a new request
64
- # object with the new module's name and no generics (because the
65
- # mapping could not have added any worthwhile generics).
66
- # 2. The request has no generics, and the request's {#intern} has no
67
- # mapping in the argument. In this case, it returns itself.
68
- # 3. The request has generics. In this case, the generics are mapped
69
- # using {Type::Generic#sub}, and a new request is created with the
70
- # mapped generics.
71
- #
72
- # @api public
73
- # @example
74
- # string # => #<Carbon::Concrete::Type::Generic Carbon::String>
75
- # request.intern # => "Carbon::Pointer"
76
- # request.generics # => [#<Carbon::Concrete::Type::Generic T>]
77
- # mapped = request.sub("T" => string)
78
- # mapped.intern # => "Carbon::Pointer"
79
- # request.generics.first.equal?(string) # => true
80
- # @param mapping [{::String => Type::Generic}] The mapping.
81
- # @return [Request] The new request, if the request has no generics,
82
- # and the request's {#intern} is not a key in the mapping, or if
83
- # the request has generics.
84
- # @return [self] If the request has no generics and it is not a key
85
- # in the mapping.
86
- def sub(mapping)
87
- case [@generics.none?, mapping.key?(@intern)]
88
- when [true, true]
89
- Request.new(mapping[@intern].name.intern, [])
90
- when [true, false]
91
- self
92
- else
93
- generics = @generics.map { |generic| generic.sub(mapping) }
94
- Request.new(intern, generics)
95
- end
96
- end
97
-
98
- # Compares this request to another. If this request _is_ the other
99
- # request, it returns true; otherwise, if the other is a request, and
100
- # the other request's {#intern} is equal to this request's, it
101
- # returns true; otherwise, it returns false.
102
- #
103
- # @api public
104
- # @param other [Request, ::String, ::Object] The object to compare.
105
- # @return [::Boolean]
106
- def ==(other)
107
- equal?(other) ||
108
- (other.is_a?(Request) && other.intern == intern &&
109
- other.generics == generics)
110
- end
111
-
112
- alias_method :eql?, :==
113
-
114
- # Creates a hash of the request. This is used mostly in the Hash
115
- # class.
116
- #
117
- # @api private
118
- # @return [Numeric]
119
- def hash
120
- @intern.hash
121
- end
122
-
123
- # Returns a string representation of this request. This includes all
124
- # generics that are associated with the request, if applicable.
125
- #
126
- # @api public
127
- # @return [::String]
128
- def to_s
129
- if @generics.any?
130
- "#{@intern}<#{@generics.map(&:to_s).join(', ')}>".freeze
131
- else
132
- @intern
133
- end
134
- end
135
- end
136
- end
137
- end
3
+ # # frozen_string_literal: true
4
+ #
5
+ # require "forwardable"
6
+ #
7
+ # module Carbon
8
+ # module Concrete
9
+ # # A "request." This is used to note the generics that a given module
10
+ # # should be compiled with. This is used for items to note the dependencies
11
+ # # that an item has; otherwise, it is used in the index for build
12
+ # # information.
13
+ # #
14
+ # # @note
15
+ # # **This class is frozen upon initialization.** This means that any
16
+ # # attempt to modify it will result in an error. In most cases, the
17
+ # # attributes on this class will also be frozen, as well.
18
+ # class Request
19
+ # extend Forwardable
20
+ #
21
+ # # The interned name of a module. This is used for module lookup. This
22
+ # # contains no generic information. For generic functions, all generics
23
+ # # are pushed onto the defining module.
24
+ # #
25
+ # # @api public
26
+ # # @example
27
+ # # request.intern # => "Carbon::Pointer"
28
+ # # @note See {Item::Base#intern} For more information about interned
29
+ # # names.
30
+ # # @return [::String]
31
+ # attr_reader :intern
32
+ #
33
+ # # The generics of the request. Even if the request has no definable
34
+ # # generics, these are still kept in place for both name information and
35
+ # # for placement information (e.g. identity and size).
36
+ # #
37
+ # # @api public
38
+ # # @example
39
+ # # request.generics # => [#<Carbon::Concrete::Type::Generic T>]
40
+ # # @return [<Type::Generic>]
41
+ # attr_reader :generics
42
+ #
43
+ # # Initialize the request with the given interned name and generics,
44
+ # # and then freezes the request.
45
+ # #
46
+ # # @api public
47
+ # # @see #intern
48
+ # # @see #generics
49
+ # # @param intern [::String] The interned name.
50
+ # # @param generics [<Type::Generic>] The generics.
51
+ # def initialize(intern, generics)
52
+ # @intern = intern
53
+ # @generics = generics
54
+ # deep_freeze!
55
+ # end
56
+ #
57
+ # # Replaces this request or this request's generics with the corresponding
58
+ # # correct module. This is designed to resolve generic names; for
59
+ # # example, it resolves `Carbon::Pointer<T>` to
60
+ # # `Carbon::Pointer<Carbon::String>` with the right argument. It checks
61
+ # # for three seperate cases.
62
+ # #
63
+ # # 1. The request has no generics, and the request's {#intern} has a
64
+ # # mapping in the argument. In this case, it creates a new request
65
+ # # object with the new module's name and no generics (because the
66
+ # # mapping could not have added any worthwhile generics).
67
+ # # 2. The request has no generics, and the request's {#intern} has no
68
+ # # mapping in the argument. In this case, it returns itself.
69
+ # # 3. The request has generics. In this case, the generics are mapped
70
+ # # using {Type::Generic#sub}, and a new request is created with the
71
+ # # mapped generics.
72
+ # #
73
+ # # @api public
74
+ # # @example
75
+ # # string # => #<Carbon::Concrete::Type::Generic Carbon::String>
76
+ # # request.intern # => "Carbon::Pointer"
77
+ # # request.generics # => [#<Carbon::Concrete::Type::Generic T>]
78
+ # # mapped = request.sub("T" => string)
79
+ # # mapped.intern # => "Carbon::Pointer"
80
+ # # request.generics.first.equal?(string) # => true
81
+ # # @param mapping [{::String => Type::Generic}] The mapping.
82
+ # # @return [Request] The new request, if the request has no generics,
83
+ # # and the request's {#intern} is not a key in the mapping, or if
84
+ # # the request has generics.
85
+ # # @return [self] If the request has no generics and it is not a key
86
+ # # in the mapping.
87
+ # def sub(mapping)
88
+ # case [@generics.none?, mapping.key?(@intern)]
89
+ # when [true, true]
90
+ # Request.new(mapping[@intern].name.intern, [])
91
+ # when [true, false]
92
+ # self
93
+ # else
94
+ # generics = @generics.map { |generic| generic.sub(mapping) }
95
+ # Request.new(intern, generics)
96
+ # end
97
+ # end
98
+ #
99
+ # # Compares this request to another. If this request _is_ the other
100
+ # # request, it returns true; otherwise, if the other is a request, and
101
+ # # the other request's {#intern} is equal to this request's, it
102
+ # # returns true; otherwise, it returns false.
103
+ # #
104
+ # # @api public
105
+ # # @param other [Request, ::String, ::Object] The object to compare.
106
+ # # @return [::Boolean]
107
+ # def ==(other)
108
+ # equal?(other) ||
109
+ # (other.is_a?(Request) && other.intern == intern &&
110
+ # other.generics == generics)
111
+ # end
112
+ #
113
+ # alias_method :eql?, :==
114
+ #
115
+ # # Creates a hash of the request. This is used mostly in the Hash
116
+ # # class.
117
+ # #
118
+ # # @api private
119
+ # # @return [Numeric]
120
+ # def hash
121
+ # @intern.hash
122
+ # end
123
+ #
124
+ # # Returns a string representation of this request. This includes all
125
+ # # generics that are associated with the request, if applicable.
126
+ # #
127
+ # # @api public
128
+ # # @return [::String]
129
+ # def to_s
130
+ # if @generics.any?
131
+ # "#{@intern}<#{@generics.map(&:to_s).join(', ')}>".freeze
132
+ # else
133
+ # @intern
134
+ # end
135
+ # end
136
+ # end
137
+ # end
138
+ # end
@@ -19,8 +19,6 @@ module Carbon
19
19
  # **This class is frozen upon initialization.** This means that any
20
20
  # attempt to modify it will result in an error. In most cases, the
21
21
  # attributes on this class will also be frozen, as well.
22
- # @todo
23
- # TODO: Add function generics.
24
22
  class Type
25
23
  # A cache of types. This maps unparsed strings to their parsed
26
24
  # derivatives. The cache is guarenteed to be thread-safe.
@@ -70,14 +68,23 @@ module Carbon
70
68
  # @return [<Type::Generic>]
71
69
  attr_reader :generics
72
70
 
71
+ # The location of the type. This is used for interfacing with other
72
+ # programs that require a location of some sort.
73
+ #
74
+ # @api semiprivate
75
+ # @return [Object]
76
+ attr_reader :location
77
+
73
78
  # Initialize the type with the given name. After initialization, this
74
79
  # freezes the type, preventing modification.
75
80
  #
76
81
  # @api public
77
82
  # @param name [Type::Name] The name.
78
- def initialize(name)
83
+ def initialize(name, location: nil)
79
84
  @name = name
80
85
  @generics = name.last.generics
86
+ @generics += function.generics if function?
87
+ @location = location
81
88
  deep_freeze!
82
89
  end
83
90
 
@@ -95,7 +102,27 @@ module Carbon
95
102
  # type.function? # => true
96
103
  # @return [::Boolean] True if the type is a function, false otherwise.
97
104
  def function?
98
- !@name.function.nil?
105
+ !function.nil?
106
+ end
107
+
108
+ # Returns the function information of the type. If this isn't a function
109
+ # type (see {#function?}), then this returns `nil`.
110
+ #
111
+ # @api public
112
+ # @example Not a function.
113
+ # type.to_s # => "Carbon::Pointer<T>"
114
+ # type.function? # => false
115
+ # type.function # => nil
116
+ # @example A function.
117
+ # type.to_s
118
+ # # => "Carbon::Pointer<T>.add(Carbon::Pointer<T>, Carbon::Int32)"
119
+ # type.function? # => true
120
+ # type.function # => #<Carbon::Concrete::Type::Function ...>
121
+ # @return [Concrete::Type::Function] The function information, if this is
122
+ # a function type; otherwise,
123
+ # @return [nil] returns nil.
124
+ def function
125
+ @name.function
99
126
  end
100
127
 
101
128
  # Compares this type to another type. If the other type _is_ this type,
@@ -123,6 +150,25 @@ module Carbon
123
150
 
124
151
  alias_method :eql?, :==
125
152
 
153
+ # Checks if the given type "matches" the current type. This
154
+ # matches if any of the following conditions apply:
155
+ #
156
+ # 1. If the types match exactly, with no generics; otherwise,
157
+ # 2. If the types match exactly, with generics; otherwise,
158
+ # 3. If the given type can be made to look like the item type by
159
+ # introducing generics; otherwise,
160
+ # 4. They don't match.
161
+ #
162
+ # The base item provides a good default for most items.
163
+ #
164
+ # @param type [Concrete::Type] The type to check for matching.
165
+ # @return [Boolean] If the type matches the item.
166
+ def match?(other, generics = {})
167
+ (@generics.none? && to_s == other.to_s && generics) ||
168
+ (!function? && match_generic_module?(other, generics)) ||
169
+ (function? && match_generic_function?(other, generics))
170
+ end
171
+
126
172
  # Creates a hash of the request. This is used mostly in the Hash class.
127
173
  #
128
174
  # @api private
@@ -158,8 +204,8 @@ module Carbon
158
204
  # @param parameters [<Type>] The parameters that the function is
159
205
  # called with.
160
206
  # @return [Type] The new type.
161
- def call(name, parameters)
162
- func = Type::Function.new(name, parameters)
207
+ def call(name, parameters, generics = [])
208
+ func = Type::Function.new(name.to_s, parameters, generics)
163
209
  name = Name.new(@name.parts, func)
164
210
  Type.new(name)
165
211
  end
@@ -185,7 +231,8 @@ module Carbon
185
231
  # replace.
186
232
  # @return [Concrete::Type] The new type.
187
233
  def sub(generics)
188
- return generics[key] if generics.key?(intern)
234
+ return sub_function(generics) if function?
235
+ return generics[self] if generics.key?(self)
189
236
  return self if generics.none?
190
237
  replace_generics(generics)
191
238
  end
@@ -204,26 +251,13 @@ module Carbon
204
251
  # "Carbon::Int32)"
205
252
  # type = Carbon::Type(form)
206
253
  # type.to_s == form # => true
207
- # second = Carbon::Type`(type.to_s)
254
+ # second = Carbon::Type(type.to_s)
208
255
  # type == second # => true
209
256
  # @return [::String] The string representation of the type.
210
257
  def to_s
211
258
  @name.to_s
212
259
  end
213
260
 
214
- # Creates a request based on this type.
215
- #
216
- # @api semipublic
217
- # @example
218
- # type = Carbon::Type("Carbon::Pointer<T>")
219
- # req = type.to_request
220
- # req.intern # => "Carbon::Pointer"
221
- # req.generics # => [#<Carbon::Concrete::Type::Generic T>]
222
- # @return [Request]
223
- def to_request
224
- Request.new(intern, generics)
225
- end
226
-
227
261
  # Removes all function information from the type. This is the complete
228
262
  # opposite of {#call}. This just leaves the module that the function
229
263
  # was defined on.
@@ -239,6 +273,21 @@ module Carbon
239
273
  Type.new(name)
240
274
  end
241
275
 
276
+ # Converts the type into a pointer type. Essentially, it just
277
+ # encapsulates the current type in a pointer.
278
+ #
279
+ # @example
280
+ # inner = Carbon::Boolean
281
+ # inner.to_s # => "Carbon::Boolean"
282
+ # inner.to_pointer.to_s # => "Carbon::Pointer<Carbon::Boolean>"
283
+ # @return [Type] The encapsulated type.
284
+ def to_pointer
285
+ ptype = Carbon::Type("Carbon::Pointer<T>")
286
+ tgen = Carbon::Type("T")
287
+
288
+ ptype.sub(tgen => self)
289
+ end
290
+
242
291
  # Pretty inspect.
243
292
  #
244
293
  # @api private
@@ -247,8 +296,64 @@ module Carbon
247
296
  "#<Carbon::Concrete::Type #{self}>".freeze
248
297
  end
249
298
 
299
+ # Accepts the current visitor unto itself.
300
+ #
301
+ # @param visitor [#visit]
302
+ # @return [Object]
303
+ def accept(visitor, *params)
304
+ visitor.visit(self, *params)
305
+ end
306
+
250
307
  private
251
308
 
309
+ def sub_function(generics)
310
+ return self if !@generics.any? &&
311
+ function.parameters.all? { |p| !p.generics.any? }
312
+ basic = to_module.sub(generics)
313
+ gens = function.generics.map { |p| p.sub(generics) }
314
+ params = function.parameters.map { |p| p.sub(generics) }
315
+ basic.call(function.name, params, gens)
316
+ end
317
+
318
+ def match_generic_module?(other, generics)
319
+ return intern == other.intern && {} unless generics.any?
320
+ intern == other.intern &&
321
+ other.generics.all? { |g| generics.values.include?(g.name) } &&
322
+ generics
323
+ end
324
+
325
+ def match_generic_function_preflight?(other, _)
326
+ # If neither have generics, then this can't match them.
327
+ @generics.any? && other.generics.any? &&
328
+ # If the types are modules, then they should have matched earlier.
329
+ function? && other.function? &&
330
+ # The function names should be the same.
331
+ (function.name == other.function.name) &&
332
+ # They should have the same number of generics.
333
+ (@generics.size == other.generics.size) &&
334
+ # They should have the same number of parameters.
335
+ (function.parameters.size == other.function.parameters.size)
336
+ end
337
+
338
+ def match_generic_function?(other, generics)
339
+ return false unless match_generic_function_preflight?(other, generics)
340
+ mapping = generics.merge(@generics.map(&:name)
341
+ .zip(other.generics.map(&:name)).to_h)
342
+ params = function.parameters.zip(other.function.parameters)
343
+ # If any of the parameters don't match, then the whole doesn't match.
344
+ # However, if one of the parameters is a generic, then we check to make
345
+ # sure that the same generic placement is used in the other type.
346
+ # For example, `A<T>.+(A<T>, T)` would match `A<B>.+(A<B>, B)`, but not
347
+ # `A<B>.+(A<B>, C)`.
348
+ params.all? do |(ours, theirs)|
349
+ if mapping.key?(ours)
350
+ mapping[ours].match?(theirs, mapping)
351
+ else
352
+ ours.match?(theirs, mapping)
353
+ end
354
+ end && mapping
355
+ end
356
+
252
357
  def replace_generics(generics)
253
358
  part = Part.new(@name.parts.last.value,
254
359
  @generics.map { |g| g.sub(generics) })