jade-lang 0.9.0 → 0.10.1

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 (153) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +442 -12
  3. data/README.md +1 -0
  4. data/docs/interop.md +18 -1
  5. data/docs/json.md +34 -3
  6. data/docs/stdlib.md +3 -1
  7. data/docs/syntax.md +96 -0
  8. data/lib/jade/api.rb +9 -0
  9. data/lib/jade/ast.rb +37 -1
  10. data/lib/jade/cli/eject.rb +132 -0
  11. data/lib/jade/cli/init.rb +86 -0
  12. data/lib/jade/cli.rb +4 -0
  13. data/lib/jade/codegen/boundary/specialized/list.rb +11 -7
  14. data/lib/jade/codegen/boundary/specialized/maybe.rb +2 -2
  15. data/lib/jade/codegen/boundary/specialized/record.rb +19 -4
  16. data/lib/jade/codegen/boundary/specialized/scalar.rb +2 -2
  17. data/lib/jade/codegen/boundary/specialized.rb +13 -5
  18. data/lib/jade/codegen/boundary.rb +12 -2
  19. data/lib/jade/codegen/context.rb +17 -0
  20. data/lib/jade/codegen/error.rb +1 -0
  21. data/lib/jade/codegen/function_call.rb +38 -7
  22. data/lib/jade/codegen/function_declaration.rb +25 -13
  23. data/lib/jade/codegen/helpers.rb +27 -4
  24. data/lib/jade/codegen/implementation.rb +2 -2
  25. data/lib/jade/codegen/inline.rb +1 -1
  26. data/lib/jade/codegen/inlines.rb +6 -1
  27. data/lib/jade/codegen/names.rb +31 -0
  28. data/lib/jade/codegen/pattern/constructor.rb +2 -2
  29. data/lib/jade/codegen/transforms/fold_shape.rb +1 -1
  30. data/lib/jade/codegen.rb +76 -15
  31. data/lib/jade/compiler.rb +2 -0
  32. data/lib/jade/entry.rb +1 -1
  33. data/lib/jade/formatter/calls.rb +68 -11
  34. data/lib/jade/formatter/collections.rb +4 -4
  35. data/lib/jade/formatter/declarations.rb +13 -15
  36. data/lib/jade/formatter/helper.rb +20 -0
  37. data/lib/jade/formatter/infix_application.rb +19 -4
  38. data/lib/jade/formatter/lambda.rb +24 -12
  39. data/lib/jade/formatter/pattern.rb +3 -0
  40. data/lib/jade/formatter/type.rb +3 -5
  41. data/lib/jade/frontend/desugaring/placeholder.rb +40 -17
  42. data/lib/jade/frontend/desugaring.rb +29 -9
  43. data/lib/jade/frontend/fixity_fixer.rb +6 -4
  44. data/lib/jade/frontend/forward_declaration/error/alias_expansion.rb +23 -0
  45. data/lib/jade/frontend/forward_declaration/error/duplicate_constructor_name.rb +45 -0
  46. data/lib/jade/frontend/forward_declaration/error/duplicate_type_name.rb +42 -0
  47. data/lib/jade/frontend/forward_declaration/error.rb +3 -0
  48. data/lib/jade/frontend/forward_declaration/helper.rb +58 -0
  49. data/lib/jade/frontend/forward_declaration/import_declaration.rb +4 -0
  50. data/lib/jade/frontend/forward_declaration/interface_declaration.rb +6 -0
  51. data/lib/jade/frontend/forward_declaration/module.rb +4 -0
  52. data/lib/jade/frontend/forward_declaration/struct_declaration.rb +10 -1
  53. data/lib/jade/frontend/forward_declaration/type_alias_declaration.rb +37 -0
  54. data/lib/jade/frontend/forward_declaration/type_declaration.rb +10 -1
  55. data/lib/jade/frontend/forward_declaration.rb +2 -0
  56. data/lib/jade/frontend/pattern_analysis/exhaustiveness.rb +47 -43
  57. data/lib/jade/frontend/pattern_analysis/matrix.rb +28 -219
  58. data/lib/jade/frontend/pattern_analysis/pattern.rb +132 -0
  59. data/lib/jade/frontend/pattern_analysis/redundancy.rb +24 -0
  60. data/lib/jade/frontend/pattern_analysis/signature.rb +220 -0
  61. data/lib/jade/frontend/pattern_analysis/usefulness.rb +72 -0
  62. data/lib/jade/frontend/pattern_analysis/witnesses.rb +73 -0
  63. data/lib/jade/frontend/pattern_analysis.rb +5 -38
  64. data/lib/jade/frontend/semantic_analysis/error/implementation_on_alias.rb +24 -0
  65. data/lib/jade/frontend/semantic_analysis/error/no_base_case.rb +45 -0
  66. data/lib/jade/frontend/semantic_analysis/error/placeholder_not_allowed.rb +15 -3
  67. data/lib/jade/frontend/semantic_analysis/error/recursive_type_alias.rb +24 -0
  68. data/lib/jade/frontend/semantic_analysis/error.rb +3 -0
  69. data/lib/jade/frontend/semantic_analysis/helper.rb +31 -0
  70. data/lib/jade/frontend/semantic_analysis/implementation.rb +13 -0
  71. data/lib/jade/frontend/semantic_analysis/inhabitedness.rb +90 -0
  72. data/lib/jade/frontend/semantic_analysis/interop_import_declaration.rb +28 -16
  73. data/lib/jade/frontend/semantic_analysis/keyed_call.rb +21 -5
  74. data/lib/jade/frontend/semantic_analysis/pattern_range.rb +16 -0
  75. data/lib/jade/frontend/semantic_analysis/struct_declaration.rb +1 -0
  76. data/lib/jade/frontend/semantic_analysis/type_alias_declaration/cycle_detection.rb +95 -0
  77. data/lib/jade/frontend/semantic_analysis/type_alias_declaration.rb +48 -0
  78. data/lib/jade/frontend/semantic_analysis/type_declaration.rb +1 -0
  79. data/lib/jade/frontend/semantic_analysis.rb +5 -0
  80. data/lib/jade/frontend/type_checking/canonicalize.rb +1 -0
  81. data/lib/jade/frontend/type_checking/cascade.rb +90 -0
  82. data/lib/jade/frontend/type_checking/constraints/deriving/encodable.rb +10 -0
  83. data/lib/jade/frontend/type_checking/constraints.rb +18 -3
  84. data/lib/jade/frontend/type_checking/error/display.rb +49 -0
  85. data/lib/jade/frontend/type_checking/error/division_by_zero.rb +31 -0
  86. data/lib/jade/frontend/type_checking/error/empty_range_pattern.rb +25 -0
  87. data/lib/jade/frontend/type_checking/error/function_body_type_mismatch.rb +4 -3
  88. data/lib/jade/frontend/type_checking/error/function_call_type_mismatch.rb +108 -5
  89. data/lib/jade/frontend/type_checking/error/if_branch_type_mismatch.rb +1 -1
  90. data/lib/jade/frontend/type_checking/error/if_branches_type_mismatch.rb +1 -1
  91. data/lib/jade/frontend/type_checking/error/if_condition_type_mismatch.rb +1 -1
  92. data/lib/jade/frontend/type_checking/error/implementation_type_mismatch.rb +1 -1
  93. data/lib/jade/frontend/type_checking/error/list_item_type_mismatch.rb +1 -1
  94. data/lib/jade/frontend/type_checking/error/missing_patterns.rb +20 -4
  95. data/lib/jade/frontend/type_checking/error/pattern_type_mismatch.rb +7 -1
  96. data/lib/jade/frontend/type_checking/error/range_pattern_type.rb +29 -0
  97. data/lib/jade/frontend/type_checking/error/record_access_type_mismatch.rb +2 -2
  98. data/lib/jade/frontend/type_checking/error/record_update_type_mismatch.rb +21 -0
  99. data/lib/jade/frontend/type_checking/error/recursive_derivation.rb +25 -0
  100. data/lib/jade/frontend/type_checking/error/type_mismatch.rb +10 -2
  101. data/lib/jade/frontend/type_checking/error/unreachable_branch.rb +22 -0
  102. data/lib/jade/frontend/type_checking/error.rb +7 -0
  103. data/lib/jade/frontend/type_checking/inference/assign.rb +1 -1
  104. data/lib/jade/frontend/type_checking/inference/case_of.rb +21 -4
  105. data/lib/jade/frontend/type_checking/inference/division.rb +50 -0
  106. data/lib/jade/frontend/type_checking/inference/function_call.rb +26 -1
  107. data/lib/jade/frontend/type_checking/inference/lambda.rb +1 -1
  108. data/lib/jade/frontend/type_checking/inference/pattern.rb +35 -0
  109. data/lib/jade/frontend/type_checking/inference/record_update.rb +8 -1
  110. data/lib/jade/frontend/type_checking/inference/type_alias_declaration.rb +18 -0
  111. data/lib/jade/frontend/type_checking/inference.rb +2 -0
  112. data/lib/jade/frontend/type_checking/loader.rb +11 -0
  113. data/lib/jade/frontend/type_checking/port_resolution.rb +26 -8
  114. data/lib/jade/frontend/type_checking/substitution.rb +2 -2
  115. data/lib/jade/frontend/type_checking.rb +3 -1
  116. data/lib/jade/frontend/usage_analysis.rb +5 -1
  117. data/lib/jade/interop/boundary.rb +64 -24
  118. data/lib/jade/interop/error.rb +35 -7
  119. data/lib/jade/interop/lowering.rb +8 -2
  120. data/lib/jade/lsp/converters.rb +83 -2
  121. data/lib/jade/lsp/handlers.rb +122 -25
  122. data/lib/jade/lsp/snippets.rb +12 -0
  123. data/lib/jade/lsp/state.rb +11 -4
  124. data/lib/jade/module_loader/build.rb +36 -0
  125. data/lib/jade/module_loader.rb +1 -0
  126. data/lib/jade/parsing/combinators.rb +78 -2
  127. data/lib/jade/parsing/error.rb +43 -6
  128. data/lib/jade/parsing/type.rb +6 -4
  129. data/lib/jade/parsing.rb +140 -26
  130. data/lib/jade/runtime.rb +32 -13
  131. data/lib/jade/source.rb +6 -2
  132. data/lib/jade/stdlib/basics.rb +22 -3
  133. data/lib/jade/stdlib/char.rb +2 -0
  134. data/lib/jade/stdlib/clock.rb +6 -2
  135. data/lib/jade/stdlib/decimal.rb +51 -14
  136. data/lib/jade/stdlib/decode.rb +11 -0
  137. data/lib/jade/stdlib/intrinsics.rb +59 -6
  138. data/lib/jade/stdlib/list.rb +37 -1
  139. data/lib/jade/stdlib/number.rb +47 -0
  140. data/lib/jade/stdlib/range.rb +211 -0
  141. data/lib/jade/stdlib.rb +11 -4
  142. data/lib/jade/symbol/alias.rb +11 -0
  143. data/lib/jade/symbol/parser.rb +1 -1
  144. data/lib/jade/symbol/stdlib_function.rb +1 -1
  145. data/lib/jade/symbol.rb +13 -1
  146. data/lib/jade/task.rb +0 -2
  147. data/lib/jade/type/anonymous_record.rb +11 -2
  148. data/lib/jade/type/application.rb +11 -2
  149. data/lib/jade/type/base.rb +26 -0
  150. data/lib/jade/type/function.rb +11 -3
  151. data/lib/jade/type.rb +36 -10
  152. data/lib/jade/version.rb +1 -1
  153. metadata +35 -2
@@ -10,6 +10,64 @@ module Jade
10
10
  ForwardDeclaration.deep_declare_node(ast, entry, registry)
11
11
  end
12
12
 
13
+ # Only the shallow pass still has the declaration being replaced;
14
+ # by the deep pass the entry holds the winner alone. The deep pass
15
+ # keeps its kind check to bail out, not to report.
16
+ def duplicate_type_error(entry, name, span, declaring:)
17
+ entry.defined_types[name].then do |existing|
18
+ next nil if existing.nil? || existing.decl_span == span
19
+
20
+ Error::DuplicateTypeName.new(
21
+ entry.name,
22
+ span,
23
+ name,
24
+ declaring:,
25
+ existing: Error::DuplicateTypeName.kind_of(existing),
26
+ first_span: existing.decl_span,
27
+ )
28
+ end
29
+ end
30
+
31
+ # A constructor is named without its type, so one module cannot hold
32
+ # two of a name — a union's variant and a struct both define one, and
33
+ # the second shadows the first. `introduced` is what this declaration
34
+ # is about to define, each with the span to point at.
35
+ def duplicate_constructor_errors(entry, name, introduced, declaring:)
36
+ declared_constructors(entry).then do |seen|
37
+ introduced.filter_map { duplicate_constructor_error(entry, name, it, seen, declaring) }
38
+ end
39
+ end
40
+
41
+ def declared_constructors(entry)
42
+ entry
43
+ .defined_types
44
+ .values
45
+ .flat_map do |symbol|
46
+ case symbol
47
+ in Symbol::Union then symbol.variants.map { [it.name, symbol] }
48
+ in Symbol::Struct then [[symbol.name, symbol]]
49
+ else []
50
+ end
51
+ end
52
+ .to_h
53
+ end
54
+
55
+ def duplicate_constructor_error(entry, name, (constructor, span), seen, declaring)
56
+ seen[constructor].then do |owner|
57
+ next nil if owner.nil? || owner.name == name
58
+
59
+ Error::DuplicateConstructorName.new(
60
+ entry.name,
61
+ span,
62
+ constructor,
63
+ declaring:,
64
+ type: name,
65
+ owner:,
66
+ first_span: owner.decl_span,
67
+ )
68
+ end
69
+ end
70
+
13
71
  def figure_out_type(entry, node)
14
72
  case node
15
73
  in AST::TypeVar(type:)
@@ -83,6 +83,10 @@ module Jade
83
83
  end
84
84
 
85
85
  def handling_exposing_type_expansion(type, name, span, current_entry, importing_module)
86
+ if importing_module.types[name].is_a?(Symbol::Alias)
87
+ return Err[Error::AliasExpansion.new(current_entry.name, span, name:)]
88
+ end
89
+
86
90
  importing_module
87
91
  .exposed_type_variants(name)
88
92
  .then do |variants|
@@ -8,6 +8,9 @@ module Jade
8
8
  def shallow(node, _registry, entry)
9
9
  node => AST::InterfaceDeclaration(name:, type_param:, functions:)
10
10
 
11
+ duplicate_type_error(entry, name, node.range, declaring: 'an interface')
12
+ .then { return Result[entry, [it]] if it }
13
+
11
14
  interface_ref = Symbol.type_ref(entry.name, name)
12
15
  type_var = Symbol.var(type_param.name, type_param.range)
13
16
 
@@ -28,6 +31,9 @@ module Jade
28
31
  node => AST::InterfaceDeclaration(name:, functions:)
29
32
 
30
33
  symbol = entry.lookup_type(name)
34
+
35
+ return Result[entry, []] unless symbol.is_a?(Symbol::Interface)
36
+
31
37
  interface_ref = symbol.to_ref
32
38
 
33
39
  functions
@@ -71,6 +71,10 @@ module Jade
71
71
  ]
72
72
  end
73
73
 
74
+ if symbol.is_a?(Symbol::Alias)
75
+ return Result[entry, [Error::AliasExpansion.new(entry.name, span, name:)]]
76
+ end
77
+
74
78
  symbol
75
79
  .constructor_refs
76
80
  .reduce(entry) { |acc, ctor| acc.expose(ctor.to_ref) }
@@ -8,11 +8,18 @@ module Jade
8
8
  def shallow(node, registry, entry)
9
9
  node => AST::StructDeclaration(name:, type_params:)
10
10
 
11
+ duplicate_type_error(entry, name, node.range, declaring: 'a struct')
12
+ .then { return Result[entry, [it]] if it }
13
+
14
+ # The struct is still declared, so a signature naming it does not
15
+ # report a second, misleading error.
16
+ errors = duplicate_constructor_errors(entry, name, [[name, node.range]], declaring: :struct)
17
+
11
18
  type_params
12
19
  .map { Symbol.var(it.name, it.range) }
13
20
  .then { Symbol.predeclared_struct(name, it, node.range) }
14
21
  .then { entry.define(it) }
15
- .then { Result[it, []] }
22
+ .then { Result[it, errors] }
16
23
  end
17
24
 
18
25
  def deep(node, entry, _)
@@ -20,6 +27,8 @@ module Jade
20
27
 
21
28
  symbol = entry.lookup_type(name)
22
29
 
30
+ return Result[entry, []] unless symbol.is_a?(Symbol::Struct)
31
+
23
32
  figure_out_type(entry, record_type)
24
33
  .map do |record_type_symbol|
25
34
  constructor_fn_symbol = Symbol.constructor(
@@ -0,0 +1,37 @@
1
+ module Jade
2
+ module Frontend
3
+ module ForwardDeclaration
4
+ module TypeAliasDeclaration
5
+ extend self
6
+ extend Helper
7
+
8
+ def shallow(node, registry, entry)
9
+ node => AST::TypeAliasDeclaration(name:, type_params:)
10
+
11
+ duplicate_type_error(entry, name, node.range, declaring: 'a type alias')
12
+ .then { return Result[entry, [it]] if it }
13
+
14
+ type_params
15
+ .map { Symbol.var(it.name, it.range) }
16
+ .then { Symbol.predeclared_alias(name, it, node.range) }
17
+ .then { entry.define(it) }
18
+ .then { Result[it, []] }
19
+ end
20
+
21
+ def deep(node, entry, _)
22
+ node => AST::TypeAliasDeclaration(name:, body_type:)
23
+
24
+ symbol = entry.lookup_type(name)
25
+
26
+ return Result[entry, []] unless symbol.is_a?(Symbol::Alias)
27
+
28
+ figure_out_type(entry, body_type)
29
+ .map do |body_symbol|
30
+ entry.define(symbol.with(body: body_symbol))
31
+ end
32
+ .then { to_declaration_result(entry, it) }
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -8,13 +8,20 @@ module Jade
8
8
  def shallow(node, registry, entry)
9
9
  node => AST::TypeDeclaration(name:, type_params:, variants:)
10
10
 
11
+ duplicate_type_error(entry, name, node.range, declaring: 'a type')
12
+ .then { return Result[entry, [it]] if it }
13
+
14
+ # The type is still declared, so a signature naming it does not
15
+ # report a second, misleading error.
16
+ errors = duplicate_constructor_errors(entry, name, variants.map { [it.name, it.range] }, declaring: :variant)
17
+
11
18
  predeclared_variants = variants
12
19
  .map { |var| Symbol.predeclared_constructor(var.name, var.range) }
13
20
 
14
21
  type_params.map { Symbol.var(it.name, it.range) }
15
22
  .then { Symbol.union(name, it, predeclared_variants, node.range) }
16
23
  .then { entry.define(it) }
17
- .then { Result[it, []] }
24
+ .then { Result[it, errors] }
18
25
  end
19
26
 
20
27
  def deep(node, entry, _)
@@ -22,6 +29,8 @@ module Jade
22
29
 
23
30
  symbol = entry.lookup_type(name)
24
31
 
32
+ return Result[entry, []] unless symbol.is_a?(Symbol::Union)
33
+
25
34
  variants
26
35
  .map do |var|
27
36
  var.args.map { figure_out_type(entry, it) }
@@ -11,6 +11,7 @@ require 'jade/frontend/forward_declaration/import_declaration'
11
11
  require 'jade/frontend/forward_declaration/interop_import_declaration'
12
12
  require 'jade/frontend/forward_declaration/module'
13
13
  require 'jade/frontend/forward_declaration/struct_declaration'
14
+ require 'jade/frontend/forward_declaration/type_alias_declaration'
14
15
  require 'jade/frontend/forward_declaration/type_declaration'
15
16
  require 'jade/frontend/forward_declaration/interface_declaration'
16
17
 
@@ -60,6 +61,7 @@ module Jade
60
61
  in AST::InteropImportDeclaration then InteropImportDeclaration
61
62
  in AST::Module then Module
62
63
  in AST::StructDeclaration then StructDeclaration
64
+ in AST::TypeAliasDeclaration then TypeAliasDeclaration
63
65
  in AST::TypeDeclaration then TypeDeclaration
64
66
  in AST::InterfaceDeclaration then InterfaceDeclaration
65
67
  else
@@ -4,17 +4,58 @@ module Jade
4
4
  module Exhaustiveness
5
5
  extend self
6
6
 
7
- def assert(patterns, range, env, registry, expected)
8
- Matrix[
9
- patterns.map { [node_to_matrix_pattern(it)] },
10
- [expected],
11
- ]
12
- .missing_patterns(env)
7
+ def assert(patterns, range, env, expected)
8
+ Matrix[patterns.map { [Pattern.from_node(it)] }, [expected]]
9
+ .then { Witnesses.missing(it, env) }
10
+ .then { it.with(rows: coalesced(it.rows)) }
13
11
  .then { to_errors(it, range, env) }
14
12
  end
15
13
 
16
14
  private
17
15
 
16
+ # Splitting a column cuts it at every bound any pattern mentions, so
17
+ # one hole can come back as several touching pieces. Report the hole.
18
+ def coalesced(rows)
19
+ joined = rows
20
+ .combination(2)
21
+ .lazy
22
+ .filter_map { |(left, right)| join(left, right)&.then { [left, right, it] } }
23
+ .first
24
+
25
+ return rows if joined.nil?
26
+
27
+ joined => [left, right, combined]
28
+
29
+ coalesced(rows - [left, right] + [combined])
30
+ end
31
+
32
+ def join(left, right)
33
+ return if left.size != right.size
34
+
35
+ differing = left.each_index.reject { left[it] == right[it] }
36
+
37
+ return if differing.size != 1
38
+
39
+ index = differing.first
40
+
41
+ span(left[index], right[index])
42
+ &.then { |joined| left.take(index) + [joined] + left.drop(index + 1) }
43
+ end
44
+
45
+ def span(left, right)
46
+ case [left, right]
47
+ in [Interval(from:, to: Integer => last), Interval(from: ^(last + 1), to:)]
48
+ Interval[from, to]
49
+
50
+ in [Constructor(constructor: name, args: left_args),
51
+ Constructor(constructor: ^name, args: right_args)]
52
+ join(left_args, right_args)&.then { Constructor[name, it] }
53
+
54
+ else
55
+ nil
56
+ end
57
+ end
58
+
18
59
  def to_errors(matrix, range, env)
19
60
  return [] if matrix.empty?
20
61
 
@@ -22,43 +63,6 @@ module Jade
22
63
  .new(env.entry_name, range, missing_patterns: matrix.rows)
23
64
  .then { [it] }
24
65
  end
25
-
26
- def node_to_matrix_pattern(pattern_node)
27
- case pattern_node
28
- in AST::Pattern::Record(fields:)
29
- Record[
30
- fields
31
- .map(&:name)
32
- .zip(fields.map(&:pattern))
33
- .to_h
34
- .transform_values { node_to_matrix_pattern(it) },
35
- ]
36
-
37
- in AST::Pattern::Constructor(constructor:, patterns:)
38
- Constructor[
39
- constructor.symbol.qualified_name,
40
- patterns.map { node_to_matrix_pattern(it) },
41
- ]
42
-
43
- in AST::Pattern::List(patterns:, rest:)
44
- # Rewrite [x, y | xs] / [x, y] into nested Cons/Nil constructors
45
- tail = rest ? Wildcard[] : Constructor['List.Nil', []]
46
- patterns
47
- .map { node_to_matrix_pattern(it) }
48
- .reverse
49
- .reduce(tail) { |acc, head| Constructor['List.Cons', [head, acc]] }
50
-
51
- in AST::Pattern::Binding | AST::Pattern::Wildcard
52
- Wildcard[]
53
-
54
- in AST::Pattern::Literal(literal: { value:, symbol: })
55
- Literal[
56
- value,
57
- symbol.qualified_name,
58
- ]
59
-
60
- end
61
- end
62
66
  end
63
67
  end
64
68
  end
@@ -5,12 +5,11 @@ module Jade
5
5
  def self.wildcard(types)
6
6
  types
7
7
  .map { Wildcard[] }
8
- .then { [it] }
9
- .then { Matrix[it, types] }
8
+ .then { Matrix[[it], types] }
10
9
  end
11
10
 
12
11
  def self.empty(types = [])
13
- self.new([], types)
12
+ Matrix[[], types]
14
13
  end
15
14
 
16
15
  def map
@@ -19,248 +18,58 @@ module Jade
19
18
  .then { with(rows: it) }
20
19
  end
21
20
 
22
- def include?(row)
23
- rows.include?(row)
24
- end
25
-
26
- def size
27
- rows.size
28
- end
29
-
30
21
  def empty?
31
22
  rows.empty?
32
23
  end
33
24
 
34
- def any?
35
- rows.any?
36
- end
37
-
38
25
  def concat(other)
39
26
  with(rows: rows + other.rows)
40
27
  end
41
28
 
42
- def missing_patterns(env)
43
- if types.empty?
44
- return rows.empty? ? Matrix[[[]], types] : Matrix.empty
45
- end
46
-
47
- type = types.first
48
-
49
- return Matrix.empty if never?(type)
50
- return Matrix.wildcard(types) if rows.empty?
51
-
52
- heads = head_constructors
53
-
54
- if infinite?(type) || type_var?(type)
55
- unmatched_column(env)
56
-
57
- elsif expandable?(type, env)
58
- expand(env).missing_patterns(env)
59
-
60
- elsif heads.empty?
61
- unmatched_column(env)
62
-
63
- else
64
- constructors_of(type, env)
65
- .reduce(Matrix.empty.with(types:)) do |acc, constructor|
66
- witnesses(constructor, env, heads.include?(constructor.name))
67
- .then { acc.concat(it) }
68
- end
69
- end
29
+ def heads
30
+ rows.map(&:first)
70
31
  end
71
32
 
72
- protected
73
-
74
- # Nothing in this column narrows anything — a type with no constructors
75
- # to enumerate, or one every row left open. Whatever is missing lives in
76
- # the columns after it.
77
- def unmatched_column(env)
78
- default
79
- .missing_patterns(env)
80
- .map { [Wildcard[]] + it }
81
- end
82
-
83
- # A constructor the first column matches is explored by specializing on
84
- # it. One it never matches can only be missing as a whole, so its
85
- # witnesses come from the rows that would have covered it — the ones
86
- # headed by a wildcard. Recursing there instead of into the constructor
87
- # is what keeps a recursive type from expanding forever.
88
- def witnesses(constructor, env, matched)
89
- return Matrix.empty if constructor.args.any? { never?(it) }
90
-
91
- arity = constructor.args.size
92
-
93
- if matched
94
- specialize(constructor)
95
- .missing_patterns(env)
96
- .map { [Constructor[constructor.name, it.take(arity)]] + it.drop(arity) }
97
-
98
- else
99
- default
100
- .missing_patterns(env)
101
- .map { [Constructor[constructor.name, Array.new(arity) { Wildcard[] }]] + it }
102
- end
103
- end
104
-
105
- def head_constructors
106
- rows.filter_map { head_constructor(it.first) }
107
- end
108
-
109
- def head_constructor(pattern)
110
- case pattern
111
- in Constructor(constructor: name) then name
112
- in Literal(value: true) then 'Basics.True'
113
- in Literal(value: false) then 'Basics.False'
114
- in Literal | Record | Wildcard then nil
115
- end
116
- end
117
-
118
- def expandable?(type, env)
119
- case type
120
- in Type::AnonymousRecord
121
- true
122
-
123
- in Type::Application(constructor:)
124
- env.lookup_def(constructor.name).is_a?(TypeChecking::StructDef)
125
-
126
- else
127
- false
128
- end
129
- end
130
-
131
- def expand(env)
132
- type_fields =
133
- case types.first
134
- in Type::AnonymousRecord(fields:)
135
- fields
136
-
137
- in Type::Application(constructor:)
138
- env.lookup_def(constructor.name).body.fields
139
- end
140
-
141
- map do |row|
142
- case row.first
143
- in Record(fields:)
144
- type_fields
145
- .map do |(k, v)|
146
- fields[k] || Wildcard[]
147
- end + row.drop(1)
148
-
149
- in Wildcard
150
- type_fields.map { Wildcard[] } + row.drop(1)
151
- end
152
- end
153
- .with(types: type_fields.values + types.drop(1))
154
- end
155
-
156
- def constructors_of(type, env)
157
- case type
158
- in Type::Application(constructor: Type::Constructor(name: 'Basics.Bool'))
159
- [
160
- TypeChecking::ConstructorDef['Basics.True', 'Basics.Bool', []],
161
- TypeChecking::ConstructorDef['Basics.False', 'Basics.Bool', []],
162
- ]
163
- in Type::Application(constructor: Type::Constructor(name: /^Tuple\.Tuple[2-4]$/ => name), args:)
164
- [TypeChecking::Definition.constructor(name, name, args)]
165
-
166
- in Type::Application(constructor: Type::Constructor(name: 'List.List'), args: [elem_type])
167
- [
168
- TypeChecking::ConstructorDef['List.Nil', 'List.List', []],
169
- TypeChecking::ConstructorDef['List.Cons', 'List.List', [elem_type, type]],
170
- ]
171
-
172
- else
173
- type_def = env.lookup_def(type.constructor.name)
174
-
175
- # Type the user can't destructure from here (transitively reached
176
- # through an imported struct field, or opaque intrinsic) —
177
- # any pattern they can write is trivially exhaustive.
178
- return [] if type_def.nil? || type_def.opaque?
179
-
180
- type_def
181
- .constructors
182
- .map do |con|
183
- con
184
- .args
185
- .map do |arg|
186
- if type_var?(arg)
187
- type_def
188
- .type_params
189
- .find_index { arg.name == it.name }
190
- .then { type.args.at(it) }
191
-
192
- else
193
- arg
194
- end
195
- end
196
- .then { con.with(args: it) }
197
- end
198
- end
199
- end
200
-
201
- def specialize(constructor)
33
+ # Rows the case can match, each opened up into the columns the case
34
+ # carries. A row headed by a wildcard matches every case, and says
35
+ # nothing about the columns it opens.
36
+ def specialize(kase)
202
37
  rows
203
- .filter_map do |cols|
204
- case cols.first
205
- in Literal(value:)
206
- next [] + cols.drop(1) if value == false && "Basics.False" == constructor.name
207
- next [] + cols.drop(1) if value == true && "Basics.True" == constructor.name
208
-
209
- in Constructor(constructor: cons_name, args:)
210
- args + cols.drop(1) if cons_name == constructor.name
211
-
212
- in Wildcard
213
- constructor.args.map { Wildcard[] } + cols.drop(1)
38
+ .filter_map do |row|
39
+ head = row.first
214
40
 
41
+ if kase.matches?(head)
42
+ head.args + row.drop(1)
43
+ elsif head.wildcard?
44
+ Array.new(kase.arity) { Wildcard[] } + row.drop(1)
215
45
  end
216
46
  end
217
- .then { with(rows: it) }
218
- .then { it.with(types: constructor.args + types.drop(1)) }
47
+ .then { Matrix[it, kase.arg_types + types.drop(1)] }
219
48
  end
220
49
 
50
+ # The rows that survive when the first column is decided by no case at
51
+ # all — only the ones that were not asking about it.
221
52
  def default
222
53
  rows
223
54
  .select { it.first.wildcard? }
224
55
  .map { it.drop(1) }
225
- .then { with(rows: it) }
226
- .with(types: types.drop(1))
56
+ .then { Matrix[it, types.drop(1)] }
227
57
  end
228
58
 
229
- def add(columns)
230
- with(rows: rows.concat(columns))
231
- end
232
-
233
- private
234
-
235
- def never?(type)
236
- case type
237
- in Type::Application(constructor: Type::Constructor(name: 'Basics.Never'))
238
- true
239
- else
240
- false
241
- end
242
- end
59
+ def expand(env)
60
+ fields = Signature.fields(types.first, env)
243
61
 
244
- def type_var?(type)
245
- type.is_a?(Type::Var)
62
+ map { |row| expand_row(row, fields) }
63
+ .with(types: fields.values + types.drop(1))
246
64
  end
247
65
 
248
- def infinite?(type)
249
- case type
250
- in Type::Function
251
- true
252
-
253
- in Type::Application(constructor:)
254
- case constructor
255
- in Type::Constructor(name: 'Basics.Int') then true
256
- in Type::Constructor(name: 'Basics.Float') then true
257
- in Type::Constructor(name: 'String.String') then true
258
- else
259
- false
260
- end
66
+ def expand_row(row, fields)
67
+ case row.first
68
+ in Record(fields: matched)
69
+ fields.keys.map { matched[it] || Wildcard[] } + row.drop(1)
261
70
 
262
- else
263
- false
71
+ in Wildcard
72
+ fields.keys.map { Wildcard[] } + row.drop(1)
264
73
  end
265
74
  end
266
75
  end