steep 0.34.0 → 0.39.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 (39) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +31 -0
  3. data/lib/steep.rb +6 -0
  4. data/lib/steep/ast/types/bot.rb +1 -1
  5. data/lib/steep/ast/types/factory.rb +122 -53
  6. data/lib/steep/ast/types/logic.rb +33 -1
  7. data/lib/steep/ast/types/proc.rb +32 -20
  8. data/lib/steep/ast/types/top.rb +1 -1
  9. data/lib/steep/cli.rb +2 -2
  10. data/lib/steep/drivers/print_project.rb +11 -0
  11. data/lib/steep/drivers/vendor.rb +1 -20
  12. data/lib/steep/errors.rb +67 -38
  13. data/lib/steep/index/rbs_index.rb +334 -0
  14. data/lib/steep/index/signature_symbol_provider.rb +154 -0
  15. data/lib/steep/index/source_index.rb +100 -0
  16. data/lib/steep/interface/block.rb +79 -0
  17. data/lib/steep/interface/function.rb +770 -0
  18. data/lib/steep/interface/method_type.rb +32 -812
  19. data/lib/steep/project/dsl.rb +13 -17
  20. data/lib/steep/project/options.rb +4 -4
  21. data/lib/steep/project/target.rb +21 -12
  22. data/lib/steep/server/master.rb +5 -1
  23. data/lib/steep/server/signature_worker.rb +63 -6
  24. data/lib/steep/signature/errors.rb +51 -5
  25. data/lib/steep/signature/validator.rb +28 -4
  26. data/lib/steep/subtyping/check.rb +72 -34
  27. data/lib/steep/subtyping/variable_occurrence.rb +2 -2
  28. data/lib/steep/subtyping/variable_variance.rb +2 -2
  29. data/lib/steep/type_construction.rb +308 -152
  30. data/lib/steep/type_inference/block_params.rb +1 -1
  31. data/lib/steep/type_inference/constant_env.rb +5 -1
  32. data/lib/steep/type_inference/logic_type_interpreter.rb +102 -26
  33. data/lib/steep/typing.rb +8 -2
  34. data/lib/steep/version.rb +1 -1
  35. data/smoke/tsort/Steepfile +6 -0
  36. data/smoke/tsort/a.rb +15 -0
  37. data/smoke/type_case/a.rb +1 -1
  38. data/steep.gemspec +1 -1
  39. metadata +12 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0ec77465913e4b2146e068c58f63b7ae8b5c51fd2391f6eb2776dba8372a81c2
4
- data.tar.gz: 7528dbaf4873d9eb77728521837ecb0fe43a2010036572be2c3dc017c5b903cc
3
+ metadata.gz: 33c89b6005654ebdc947af336b1c7fa47e02c45c480d27b9f4ef0ab6d3403dd1
4
+ data.tar.gz: be7b7812e1ba321b91680884fccc55fd57dd5836c89bf7817624b72706490d6e
5
5
  SHA512:
6
- metadata.gz: b0426373f8fb9e48ccec48d0676d70d5a674a389a83624df78dc3deacaba23840b02cc94becba92304de35f98c8d8bb3af12ef185161e4e6a6c37600cb61a82d
7
- data.tar.gz: 5f3a32240541f116b6299c354fada0c8de398b6139b9d5e275e7b05490ccc401aa1b4f70978af5561e2ce9c6c7bb2587c1c8e43801276c0875000496ed332a5b
6
+ metadata.gz: 36945eb5fe4a04061c87bc76488c65ef2b009fcdb8279fd542a1249a10a223cd9571371f333e4ec29870a66dd120c4d9e65d572a9d3c90d56dba5c2c1dd95761
7
+ data.tar.gz: d9c2e56878f06d71edeb9a10b275c19afd7ba42b1af16ef01ef890ca3791ad4f92f903f7679fcf77b310638b0d0f5fced596e094ec225ff2f567e0f063bfc527
@@ -2,6 +2,37 @@
2
2
 
3
3
  ## master
4
4
 
5
+ ## 0.39.0 (2020-12-25)
6
+
7
+ * Update RBS to 1.0.0 ([#282](https://github.com/soutaro/steep/pull/282))
8
+ * Better `&&` and `||` typing ([#276](https://github.com/soutaro/steep/pull/276))
9
+ * Type case based on literals ([#277](https://github.com/soutaro/steep/pull/277))
10
+ * Type case improvements ([#279](https://github.com/soutaro/steep/pull/279), [#283](https://github.com/soutaro/steep/pull/283))
11
+ * Improvements on untyped classes/modules, unsupported syntax error handling, and argument types in untyped methods ([#280](https://github.com/soutaro/steep/pull/280))
12
+ * Fix `bot` and `top` type format ([#278](https://github.com/soutaro/steep/pull/278))
13
+ * Colorfull error messages ([#273](https://github.com/soutaro/steep/pull/273))
14
+
15
+ ## 0.38.0 (2020-12-10)
16
+
17
+ * Improve `break`/`next` typing ([#271](https://github.com/soutaro/steep/pull/271))
18
+ * Add LSP `workspace/symbol` feature ([#267](https://github.com/soutaro/steep/pull/267))
19
+
20
+ ## 0.37.0 (2020-12-06)
21
+
22
+ * Update to RBS 0.20.0 with _singleton attribute_ syntax and _proc types with blocks_. ([#264](https://github.com/soutaro/steep/pull/264))
23
+
24
+ ## 0.36.0 (2020-11-16)
25
+
26
+ * Flow-sensitive typing improvements with `||` and `&&` ([#260](https://github.com/soutaro/steep/pull/260))
27
+ * Type-case improvement ([#259](https://github.com/soutaro/steep/pull/259))
28
+ * Subtyping between `bool` and logic types ([#258](https://github.com/soutaro/steep/pull/258))
29
+
30
+ ## 0.35.0 (2020-11-14)
31
+
32
+ * Support third party RBS repository ([#231](https://github.com/soutaro/steep/pull/231), [#254](https://github.com/soutaro/steep/pull/254), [#255](https://github.com/soutaro/steep/pull/255))
33
+ * Boolean type semantics update ([#252](https://github.com/soutaro/steep/pull/252))
34
+ * More flexible record typing ([#256](https://github.com/soutaro/steep/pull/256))
35
+
5
36
  ## 0.34.0 (2020-10-27)
6
37
 
7
38
  * Add `steep stats` command to show method call typing stats ([#246](https://github.com/soutaro/steep/pull/246))
@@ -42,6 +42,8 @@ require "steep/ast/annotation/collection"
42
42
  require "steep/ast/builtin"
43
43
  require "steep/ast/types/factory"
44
44
 
45
+ require "steep/interface/function"
46
+ require "steep/interface/block"
45
47
  require "steep/interface/method_type"
46
48
  require "steep/interface/substitution"
47
49
  require "steep/interface/interface"
@@ -74,6 +76,10 @@ require "steep/type_inference/logic_type_interpreter"
74
76
  require "steep/type_inference/method_call"
75
77
  require "steep/ast/types"
76
78
 
79
+ require "steep/index/rbs_index"
80
+ require "steep/index/signature_symbol_provider"
81
+ require "steep/index/source_index"
82
+
77
83
  require "steep/server/utils"
78
84
  require "steep/server/base_worker"
79
85
  require "steep/server/code_worker"
@@ -23,7 +23,7 @@ module Steep
23
23
  end
24
24
 
25
25
  def to_s
26
- ""
26
+ "bot"
27
27
  end
28
28
 
29
29
  include Helper::NoFreeVariables
@@ -75,9 +75,23 @@ module Steep
75
75
  end
76
76
  Record.new(elements: elements, location: nil)
77
77
  when RBS::Types::Proc
78
- params = params(type.type)
79
- return_type = type(type.type.return_type)
80
- Proc.new(params: params, return_type: return_type, location: nil)
78
+ func = Interface::Function.new(
79
+ params: params(type.type),
80
+ return_type: type(type.type.return_type),
81
+ location: type.location
82
+ )
83
+ block = if type.block
84
+ Interface::Block.new(
85
+ type: Interface::Function.new(
86
+ params: params(type.block.type),
87
+ return_type: type(type.block.type.return_type),
88
+ location: type.location
89
+ ),
90
+ optional: !type.block.required
91
+ )
92
+ end
93
+
94
+ Proc.new(type: func, block: block)
81
95
  else
82
96
  raise "Unexpected type given: #{type}"
83
97
  end
@@ -145,8 +159,15 @@ module Steep
145
159
  end
146
160
  RBS::Types::Record.new(fields: fields, location: nil)
147
161
  when Proc
162
+ block = if type.block
163
+ RBS::Types::Block.new(
164
+ type: function_1(type.block.type),
165
+ required: !type.block.optional?
166
+ )
167
+ end
148
168
  RBS::Types::Proc.new(
149
- type: function_1(type.params, type.return_type),
169
+ type: function_1(type.type),
170
+ block: block,
150
171
  location: nil
151
172
  )
152
173
  when Logic::Base
@@ -156,7 +177,10 @@ module Steep
156
177
  end
157
178
  end
158
179
 
159
- def function_1(params, return_type)
180
+ def function_1(func)
181
+ params = func.params
182
+ return_type = func.return_type
183
+
160
184
  RBS::Types::Function.new(
161
185
  required_positionals: params.required.map {|type| RBS::Types::Function::Param.new(name: nil, type: type_1(type)) },
162
186
  optional_positionals: params.optional.map {|type| RBS::Types::Function::Param.new(name: nil, type: type_1(type)) },
@@ -170,7 +194,7 @@ module Steep
170
194
  end
171
195
 
172
196
  def params(type)
173
- Interface::Params.new(
197
+ Interface::Function::Params.new(
174
198
  required: type.required_positionals.map {|param| type(param.type) },
175
199
  optional: type.optional_positionals.map {|param| type(param.type) },
176
200
  rest: type.rest_positionals&.yield_self {|param| type(param.type) },
@@ -202,13 +226,19 @@ module Steep
202
226
 
203
227
  type = Interface::MethodType.new(
204
228
  type_params: type_params,
205
- return_type: type(method_type.type.return_type).subst(subst),
206
- params: params(method_type.type).subst(subst),
229
+ type: Interface::Function.new(
230
+ params: params(method_type.type).subst(subst),
231
+ return_type: type(method_type.type.return_type).subst(subst),
232
+ location: method_type.location
233
+ ),
207
234
  block: method_type.block&.yield_self do |block|
208
235
  Interface::Block.new(
209
236
  optional: !block.required,
210
- type: Proc.new(params: params(block.type).subst(subst),
211
- return_type: type(block.type.return_type).subst(subst), location: nil)
237
+ type: Interface::Function.new(
238
+ params: params(block.type).subst(subst),
239
+ return_type: type(block.type.return_type).subst(subst),
240
+ location: nil
241
+ )
212
242
  )
213
243
  end,
214
244
  method_decls: method_decls
@@ -242,12 +272,12 @@ module Steep
242
272
 
243
273
  type = RBS::MethodType.new(
244
274
  type_params: type_params,
245
- type: function_1(method_type.params.subst(subst), method_type.return_type.subst(subst)),
275
+ type: function_1(method_type.type.subst(subst)),
246
276
  block: method_type.block&.yield_self do |block|
247
277
  block_type = block.type.subst(subst)
248
278
 
249
- RBS::MethodType::Block.new(
250
- type: function_1(block_type.params, block_type.return_type),
279
+ RBS::Types::Block.new(
280
+ type: function_1(block_type),
251
281
  required: !block.optional
252
282
  )
253
283
  end,
@@ -338,6 +368,8 @@ module Steep
338
368
  ]
339
369
  when AST::Types::Name::Alias
340
370
  unwrap_optional(expand_alias(type))
371
+ when AST::Types::Boolean
372
+ [AST::Builtin.true_type, AST::Builtin.false_type]
341
373
  else
342
374
  [type, nil]
343
375
  end
@@ -354,7 +386,9 @@ module Steep
354
386
  when :is_a?, :kind_of?, :instance_of?
355
387
  if defined_in == RBS::BuiltinNames::Object.name && member.instance?
356
388
  return method_type.with(
357
- return_type: AST::Types::Logic::ReceiverIsArg.new(location: method_type.return_type.location)
389
+ type: method_type.type.with(
390
+ return_type: AST::Types::Logic::ReceiverIsArg.new(location: method_type.type.return_type.location)
391
+ )
358
392
  )
359
393
  end
360
394
 
@@ -363,7 +397,9 @@ module Steep
363
397
  when RBS::BuiltinNames::Object.name,
364
398
  NilClassName
365
399
  return method_type.with(
366
- return_type: AST::Types::Logic::ReceiverIsNil.new(location: method_type.return_type.location)
400
+ type: method_type.type.with(
401
+ return_type: AST::Types::Logic::ReceiverIsNil.new(location: method_type.type.return_type.location)
402
+ )
367
403
  )
368
404
  end
369
405
 
@@ -373,7 +409,9 @@ module Steep
373
409
  RBS::BuiltinNames::TrueClass.name,
374
410
  RBS::BuiltinNames::FalseClass.name
375
411
  return method_type.with(
376
- return_type: AST::Types::Logic::Not.new(location: method_type.return_type.location)
412
+ type: method_type.type.with(
413
+ return_type: AST::Types::Logic::Not.new(location: method_type.type.return_type.location)
414
+ )
377
415
  )
378
416
  end
379
417
 
@@ -381,7 +419,17 @@ module Steep
381
419
  case defined_in
382
420
  when RBS::BuiltinNames::Module.name
383
421
  return method_type.with(
384
- return_type: AST::Types::Logic::ArgIsReceiver.new(location: method_type.return_type.location)
422
+ type: method_type.type.with(
423
+ return_type: AST::Types::Logic::ArgIsReceiver.new(location: method_type.type.return_type.location)
424
+ )
425
+ )
426
+ when RBS::BuiltinNames::Object.name, RBS::BuiltinNames::String.name, RBS::BuiltinNames::Integer.name, RBS::BuiltinNames::Symbol.name,
427
+ RBS::BuiltinNames::TrueClass.name, RBS::BuiltinNames::FalseClass.name, TypeName("::NilClass")
428
+ # Value based type-case works on literal types which is available for String, Integer, Symbol, TrueClass, FalseClass, and NilClass
429
+ return method_type.with(
430
+ type: method_type.type.with(
431
+ return_type: AST::Types::Logic::ArgEqualsReceiver.new(location: method_type.type.return_type.location)
432
+ )
385
433
  )
386
434
  end
387
435
  end
@@ -572,14 +620,17 @@ module Steep
572
620
  method_types: type.types.map.with_index {|elem_type, index|
573
621
  Interface::MethodType.new(
574
622
  type_params: [],
575
- params: Interface::Params.new(required: [AST::Types::Literal.new(value: index)],
576
- optional: [],
577
- rest: nil,
578
- required_keywords: {},
579
- optional_keywords: {},
580
- rest_keywords: nil),
623
+ type: Interface::Function.new(
624
+ params: Interface::Function::Params.new(required: [AST::Types::Literal.new(value: index)],
625
+ optional: [],
626
+ rest: nil,
627
+ required_keywords: {},
628
+ optional_keywords: {},
629
+ rest_keywords: nil),
630
+ return_type: elem_type,
631
+ location: nil
632
+ ),
581
633
  block: nil,
582
- return_type: elem_type,
583
634
  method_decls: Set[]
584
635
  )
585
636
  } + aref.method_types
@@ -591,14 +642,17 @@ module Steep
591
642
  method_types: type.types.map.with_index {|elem_type, index|
592
643
  Interface::MethodType.new(
593
644
  type_params: [],
594
- params: Interface::Params.new(required: [AST::Types::Literal.new(value: index), elem_type],
595
- optional: [],
596
- rest: nil,
597
- required_keywords: {},
598
- optional_keywords: {},
599
- rest_keywords: nil),
645
+ type: Interface::Function.new(
646
+ params: Interface::Function::Params.new(required: [AST::Types::Literal.new(value: index), elem_type],
647
+ optional: [],
648
+ rest: nil,
649
+ required_keywords: {},
650
+ optional_keywords: {},
651
+ rest_keywords: nil),
652
+ return_type: elem_type,
653
+ location: nil
654
+ ),
600
655
  block: nil,
601
- return_type: elem_type,
602
656
  method_decls: Set[]
603
657
  )
604
658
  } + update.method_types
@@ -610,9 +664,12 @@ module Steep
610
664
  method_types: [
611
665
  Interface::MethodType.new(
612
666
  type_params: [],
613
- params: Interface::Params.empty,
667
+ type: Interface::Function.new(
668
+ params: Interface::Function::Params.empty,
669
+ return_type: type.types[0] || AST::Builtin.nil_type,
670
+ location: nil
671
+ ),
614
672
  block: nil,
615
- return_type: type.types[0] || AST::Builtin.nil_type,
616
673
  method_decls: Set[]
617
674
  )
618
675
  ]
@@ -624,9 +681,12 @@ module Steep
624
681
  method_types: [
625
682
  Interface::MethodType.new(
626
683
  type_params: [],
627
- params: Interface::Params.empty,
684
+ type: Interface::Function.new(
685
+ params: Interface::Function::Params.empty,
686
+ return_type: type.types.last || AST::Builtin.nil_type,
687
+ location: nil
688
+ ),
628
689
  block: nil,
629
- return_type: type.types.last || AST::Builtin.nil_type,
630
690
  method_decls: Set[]
631
691
  )
632
692
  ]
@@ -651,14 +711,17 @@ module Steep
651
711
 
652
712
  Interface::MethodType.new(
653
713
  type_params: [],
654
- params: Interface::Params.new(required: [key_type],
655
- optional: [],
656
- rest: nil,
657
- required_keywords: {},
658
- optional_keywords: {},
659
- rest_keywords: nil),
714
+ type: Interface::Function.new(
715
+ params: Interface::Function::Params.new(required: [key_type],
716
+ optional: [],
717
+ rest: nil,
718
+ required_keywords: {},
719
+ optional_keywords: {},
720
+ rest_keywords: nil),
721
+ return_type: value_type,
722
+ location: nil
723
+ ),
660
724
  block: nil,
661
- return_type: value_type,
662
725
  method_decls: Set[]
663
726
  )
664
727
  } + ref.method_types
@@ -671,14 +734,16 @@ module Steep
671
734
  key_type = Literal.new(value: key_value, location: nil)
672
735
  Interface::MethodType.new(
673
736
  type_params: [],
674
- params: Interface::Params.new(required: [key_type, value_type],
675
- optional: [],
676
- rest: nil,
677
- required_keywords: {},
678
- optional_keywords: {},
679
- rest_keywords: nil),
737
+ type: Interface::Function.new(
738
+ params: Interface::Function::Params.new(required: [key_type, value_type],
739
+ optional: [],
740
+ rest: nil,
741
+ required_keywords: {},
742
+ optional_keywords: {},
743
+ rest_keywords: nil),
744
+ return_type: value_type,
745
+ location: nil),
680
746
  block: nil,
681
- return_type: value_type,
682
747
  method_decls: Set[]
683
748
  )
684
749
  } + update.method_types
@@ -691,14 +756,18 @@ module Steep
691
756
  interface(Builtin::Proc.instance_type, private: private, self_type: self_type).tap do |interface|
692
757
  method_type = Interface::MethodType.new(
693
758
  type_params: [],
694
- params: type.params,
695
- return_type: type.return_type,
696
- block: nil,
759
+ type: type.type,
760
+ block: type.block,
697
761
  method_decls: Set[]
698
762
  )
699
763
 
700
- interface.methods[:[]] = Interface::Interface::Entry.new(method_types: [method_type])
701
764
  interface.methods[:call] = Interface::Interface::Entry.new(method_types: [method_type])
765
+
766
+ if type.block_required?
767
+ interface.methods.delete(:[])
768
+ else
769
+ interface.methods[:[]] = Interface::Interface::Entry.new(method_types: [method_type.with(block: nil)])
770
+ end
702
771
  end
703
772
 
704
773
  when Logic::Base
@@ -18,7 +18,7 @@ module Steep
18
18
  end
19
19
 
20
20
  def ==(other)
21
- other.class ==self.class
21
+ other.class == self.class
22
22
  end
23
23
 
24
24
  alias eql? ==
@@ -57,6 +57,38 @@ module Steep
57
57
  @location = location
58
58
  end
59
59
  end
60
+
61
+ class ArgEqualsReceiver < Base
62
+ def initialize(location: nil)
63
+ @location = location
64
+ end
65
+ end
66
+
67
+ class Env < Base
68
+ attr_reader :truthy, :falsy, :type
69
+
70
+ def initialize(truthy:, falsy:, type:, location: nil)
71
+ @truthy = truthy
72
+ @falsy = falsy
73
+ @type = type
74
+ end
75
+
76
+ def ==(other)
77
+ other.is_a?(Env) && other.truthy == truthy && other.falsy == falsy && other.type == type
78
+ end
79
+
80
+ alias eql? ==
81
+
82
+ def hash
83
+ self.class.hash ^ truthy.hash ^ falsy.hash
84
+ end
85
+
86
+ def inspect
87
+ "#<Steep::AST::Types::Env @type=#{type}, @truthy=..., @falsy=...>"
88
+ end
89
+
90
+ alias to_s inspect
91
+ end
60
92
  end
61
93
  end
62
94
  end
@@ -3,68 +3,76 @@ module Steep
3
3
  module Types
4
4
  class Proc
5
5
  attr_reader :location
6
- attr_reader :params
7
- attr_reader :return_type
6
+ attr_reader :type
7
+ attr_reader :block
8
8
 
9
- def initialize(params:, return_type:, location: nil)
9
+ def initialize(type:, block:, location: type.location)
10
+ @type = type
11
+ @block = block
10
12
  @location = location
11
- @params = params
12
- @return_type = return_type
13
13
  end
14
14
 
15
15
  def ==(other)
16
- other.is_a?(self.class) &&
17
- other.params == params &&
18
- other.return_type == return_type
16
+ other.is_a?(self.class) && other.type == type && other.block == block
19
17
  end
20
18
 
21
19
  def hash
22
- self.class.hash && params.hash && return_type.hash
20
+ self.class.hash ^ type.hash ^ block.hash
23
21
  end
24
22
 
25
23
  alias eql? ==
26
24
 
27
25
  def subst(s)
28
26
  self.class.new(
29
- params: params.subst(s),
30
- return_type: return_type.subst(s),
27
+ type: type.subst(s),
28
+ block: block&.subst(s),
31
29
  location: location
32
30
  )
33
31
  end
34
32
 
35
33
  def to_s
36
- "^#{params} -> #{return_type}"
34
+ if block
35
+ "^#{type.params} #{block} -> #{type.return_type}"
36
+ else
37
+ "^#{type.params} -> #{type.return_type}"
38
+ end
37
39
  end
38
40
 
39
41
  def free_variables()
40
- @fvs ||= Set.new.tap do |set|
41
- set.merge(params.free_variables)
42
- set.merge(return_type.free_variables)
42
+ @fvs ||= Set[].tap do |fvs|
43
+ fvs.merge(type.free_variables)
44
+ fvs.merge(block.free_variables) if block
43
45
  end
44
46
  end
45
47
 
46
48
  def level
47
- children = params.each_type.to_a + [return_type]
49
+ children = type.params.each_type.to_a + [type.return_type]
50
+ if block
51
+ children.push(*block.type.params.each_type.to_a)
52
+ children.push(block.type.return_type)
53
+ end
48
54
  [0] + level_of_children(children)
49
55
  end
50
56
 
51
57
  def closed?
52
- params.closed? && return_type.closed?
58
+ type.closed? && (block.nil? || block.closed?)
53
59
  end
54
60
 
55
61
  def with_location(new_location)
56
- self.class.new(location: new_location, params: params, return_type: return_type)
62
+ self.class.new(location: new_location, block: block, type: type)
57
63
  end
58
64
 
59
65
  def map_type(&block)
60
66
  self.class.new(
61
- params: params.map_type(&block),
62
- return_type: yield(return_type),
67
+ type: type.map_type(&block),
68
+ block: self.block&.map_type(&block),
63
69
  location: location
64
70
  )
65
71
  end
66
72
 
67
73
  def one_arg?
74
+ params = type.params
75
+
68
76
  params.required.size == 1 &&
69
77
  params.optional.empty? &&
70
78
  !params.rest &&
@@ -78,6 +86,10 @@ module Steep
78
86
  args: [],
79
87
  location: location)
80
88
  end
89
+
90
+ def block_required?
91
+ block && !block.optional?
92
+ end
81
93
  end
82
94
  end
83
95
  end