carbon-core 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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) })