jade-lang 0.9.0 → 0.10.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +400 -12
- data/docs/interop.md +18 -1
- data/docs/stdlib.md +3 -1
- data/docs/syntax.md +96 -0
- data/lib/jade/api.rb +9 -0
- data/lib/jade/ast.rb +37 -1
- data/lib/jade/cli/eject.rb +132 -0
- data/lib/jade/cli.rb +2 -0
- data/lib/jade/codegen/boundary/specialized/list.rb +11 -7
- data/lib/jade/codegen/boundary/specialized/maybe.rb +2 -2
- data/lib/jade/codegen/boundary/specialized/record.rb +19 -4
- data/lib/jade/codegen/boundary/specialized/scalar.rb +2 -2
- data/lib/jade/codegen/boundary/specialized.rb +13 -5
- data/lib/jade/codegen/boundary.rb +12 -2
- data/lib/jade/codegen/context.rb +17 -0
- data/lib/jade/codegen/error.rb +1 -0
- data/lib/jade/codegen/function_call.rb +23 -7
- data/lib/jade/codegen/function_declaration.rb +25 -13
- data/lib/jade/codegen/helpers.rb +27 -4
- data/lib/jade/codegen/implementation.rb +2 -2
- data/lib/jade/codegen/inline.rb +1 -1
- data/lib/jade/codegen/inlines.rb +6 -1
- data/lib/jade/codegen/names.rb +31 -0
- data/lib/jade/codegen/pattern/constructor.rb +2 -2
- data/lib/jade/codegen/transforms/fold_shape.rb +1 -1
- data/lib/jade/codegen.rb +76 -15
- data/lib/jade/compiler.rb +2 -0
- data/lib/jade/entry.rb +1 -1
- data/lib/jade/formatter/calls.rb +68 -11
- data/lib/jade/formatter/collections.rb +4 -4
- data/lib/jade/formatter/declarations.rb +13 -15
- data/lib/jade/formatter/helper.rb +20 -0
- data/lib/jade/formatter/infix_application.rb +19 -4
- data/lib/jade/formatter/lambda.rb +24 -12
- data/lib/jade/formatter/pattern.rb +3 -0
- data/lib/jade/frontend/desugaring/placeholder.rb +40 -17
- data/lib/jade/frontend/desugaring.rb +29 -9
- data/lib/jade/frontend/fixity_fixer.rb +6 -4
- data/lib/jade/frontend/forward_declaration/error/alias_expansion.rb +23 -0
- data/lib/jade/frontend/forward_declaration/error/duplicate_constructor_name.rb +45 -0
- data/lib/jade/frontend/forward_declaration/error/duplicate_type_name.rb +42 -0
- data/lib/jade/frontend/forward_declaration/error.rb +3 -0
- data/lib/jade/frontend/forward_declaration/helper.rb +58 -0
- data/lib/jade/frontend/forward_declaration/import_declaration.rb +4 -0
- data/lib/jade/frontend/forward_declaration/interface_declaration.rb +6 -0
- data/lib/jade/frontend/forward_declaration/module.rb +4 -0
- data/lib/jade/frontend/forward_declaration/struct_declaration.rb +10 -1
- data/lib/jade/frontend/forward_declaration/type_alias_declaration.rb +37 -0
- data/lib/jade/frontend/forward_declaration/type_declaration.rb +10 -1
- data/lib/jade/frontend/forward_declaration.rb +2 -0
- data/lib/jade/frontend/pattern_analysis/exhaustiveness.rb +47 -43
- data/lib/jade/frontend/pattern_analysis/matrix.rb +28 -219
- data/lib/jade/frontend/pattern_analysis/pattern.rb +132 -0
- data/lib/jade/frontend/pattern_analysis/redundancy.rb +24 -0
- data/lib/jade/frontend/pattern_analysis/signature.rb +220 -0
- data/lib/jade/frontend/pattern_analysis/usefulness.rb +72 -0
- data/lib/jade/frontend/pattern_analysis/witnesses.rb +73 -0
- data/lib/jade/frontend/pattern_analysis.rb +5 -38
- data/lib/jade/frontend/semantic_analysis/error/implementation_on_alias.rb +24 -0
- data/lib/jade/frontend/semantic_analysis/error/no_base_case.rb +45 -0
- data/lib/jade/frontend/semantic_analysis/error/placeholder_not_allowed.rb +15 -3
- data/lib/jade/frontend/semantic_analysis/error/recursive_type_alias.rb +24 -0
- data/lib/jade/frontend/semantic_analysis/error.rb +3 -0
- data/lib/jade/frontend/semantic_analysis/helper.rb +31 -0
- data/lib/jade/frontend/semantic_analysis/implementation.rb +13 -0
- data/lib/jade/frontend/semantic_analysis/inhabitedness.rb +90 -0
- data/lib/jade/frontend/semantic_analysis/interop_import_declaration.rb +28 -16
- data/lib/jade/frontend/semantic_analysis/keyed_call.rb +21 -5
- data/lib/jade/frontend/semantic_analysis/pattern_range.rb +16 -0
- data/lib/jade/frontend/semantic_analysis/struct_declaration.rb +1 -0
- data/lib/jade/frontend/semantic_analysis/type_alias_declaration/cycle_detection.rb +95 -0
- data/lib/jade/frontend/semantic_analysis/type_alias_declaration.rb +48 -0
- data/lib/jade/frontend/semantic_analysis/type_declaration.rb +1 -0
- data/lib/jade/frontend/semantic_analysis.rb +5 -0
- data/lib/jade/frontend/type_checking/canonicalize.rb +1 -0
- data/lib/jade/frontend/type_checking/cascade.rb +90 -0
- data/lib/jade/frontend/type_checking/constraints/deriving/encodable.rb +10 -0
- data/lib/jade/frontend/type_checking/constraints.rb +18 -3
- data/lib/jade/frontend/type_checking/error/display.rb +49 -0
- data/lib/jade/frontend/type_checking/error/division_by_zero.rb +31 -0
- data/lib/jade/frontend/type_checking/error/empty_range_pattern.rb +25 -0
- data/lib/jade/frontend/type_checking/error/function_body_type_mismatch.rb +4 -3
- data/lib/jade/frontend/type_checking/error/function_call_type_mismatch.rb +108 -5
- data/lib/jade/frontend/type_checking/error/if_branch_type_mismatch.rb +1 -1
- data/lib/jade/frontend/type_checking/error/if_branches_type_mismatch.rb +1 -1
- data/lib/jade/frontend/type_checking/error/if_condition_type_mismatch.rb +1 -1
- data/lib/jade/frontend/type_checking/error/implementation_type_mismatch.rb +1 -1
- data/lib/jade/frontend/type_checking/error/list_item_type_mismatch.rb +1 -1
- data/lib/jade/frontend/type_checking/error/missing_patterns.rb +20 -4
- data/lib/jade/frontend/type_checking/error/pattern_type_mismatch.rb +7 -1
- data/lib/jade/frontend/type_checking/error/range_pattern_type.rb +29 -0
- data/lib/jade/frontend/type_checking/error/record_access_type_mismatch.rb +2 -2
- data/lib/jade/frontend/type_checking/error/recursive_derivation.rb +25 -0
- data/lib/jade/frontend/type_checking/error/type_mismatch.rb +10 -2
- data/lib/jade/frontend/type_checking/error/unreachable_branch.rb +22 -0
- data/lib/jade/frontend/type_checking/error.rb +6 -0
- data/lib/jade/frontend/type_checking/inference/assign.rb +1 -1
- data/lib/jade/frontend/type_checking/inference/case_of.rb +21 -4
- data/lib/jade/frontend/type_checking/inference/division.rb +50 -0
- data/lib/jade/frontend/type_checking/inference/function_call.rb +26 -1
- data/lib/jade/frontend/type_checking/inference/lambda.rb +1 -1
- data/lib/jade/frontend/type_checking/inference/pattern.rb +35 -0
- data/lib/jade/frontend/type_checking/inference/type_alias_declaration.rb +18 -0
- data/lib/jade/frontend/type_checking/inference.rb +2 -0
- data/lib/jade/frontend/type_checking/loader.rb +11 -0
- data/lib/jade/frontend/type_checking/port_resolution.rb +26 -8
- data/lib/jade/frontend/type_checking/substitution.rb +2 -2
- data/lib/jade/frontend/type_checking.rb +3 -1
- data/lib/jade/frontend/usage_analysis.rb +5 -1
- data/lib/jade/interop/boundary.rb +64 -24
- data/lib/jade/interop/error.rb +35 -7
- data/lib/jade/interop/lowering.rb +8 -2
- data/lib/jade/lsp/converters.rb +83 -2
- data/lib/jade/lsp/handlers.rb +122 -25
- data/lib/jade/lsp/snippets.rb +12 -0
- data/lib/jade/lsp/state.rb +11 -4
- data/lib/jade/module_loader/build.rb +36 -0
- data/lib/jade/module_loader.rb +1 -0
- data/lib/jade/parsing/combinators.rb +78 -2
- data/lib/jade/parsing/error.rb +43 -6
- data/lib/jade/parsing/type.rb +5 -3
- data/lib/jade/parsing.rb +140 -26
- data/lib/jade/runtime.rb +32 -13
- data/lib/jade/source.rb +6 -2
- data/lib/jade/stdlib/basics.rb +22 -3
- data/lib/jade/stdlib/char.rb +2 -0
- data/lib/jade/stdlib/clock.rb +6 -2
- data/lib/jade/stdlib/decimal.rb +51 -14
- data/lib/jade/stdlib/intrinsics.rb +59 -6
- data/lib/jade/stdlib/list.rb +37 -1
- data/lib/jade/stdlib/number.rb +47 -0
- data/lib/jade/stdlib/range.rb +211 -0
- data/lib/jade/stdlib.rb +11 -4
- data/lib/jade/symbol/alias.rb +11 -0
- data/lib/jade/symbol/parser.rb +1 -1
- data/lib/jade/symbol.rb +13 -1
- data/lib/jade/task.rb +0 -2
- data/lib/jade/type/anonymous_record.rb +11 -2
- data/lib/jade/type/application.rb +11 -2
- data/lib/jade/type/base.rb +26 -0
- data/lib/jade/type/function.rb +11 -2
- data/lib/jade/type.rb +36 -10
- data/lib/jade/version.rb +1 -1
- metadata +33 -2
|
@@ -7,29 +7,52 @@ module Jade
|
|
|
7
7
|
extend self
|
|
8
8
|
extend Codegen::Helpers
|
|
9
9
|
|
|
10
|
-
def lift(
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
10
|
+
def lift(node)
|
|
11
|
+
case node
|
|
12
|
+
in AST::FunctionCall(args:)
|
|
13
|
+
fill(node, args) { |filled| node.with(args: filled) }
|
|
14
|
+
|
|
15
|
+
in AST::RecordLiteral(fields:)
|
|
16
|
+
fill(node, fields.map(&:value)) do |filled|
|
|
17
|
+
fields
|
|
18
|
+
.zip(filled)
|
|
19
|
+
.map { |field, value| field.with(value:) }
|
|
20
|
+
.then { node.with(fields: it) }
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def fill(node, slots, &rebuild)
|
|
28
|
+
return node unless slots.any?(AST::Placeholder)
|
|
29
|
+
|
|
30
|
+
named(slots)
|
|
31
|
+
.then { |filled, names| [rebuild.call(filled), names] }
|
|
32
|
+
.then { |body, names| wrap_in_lambdas(body, names, node.range) }
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def named(slots)
|
|
36
|
+
slots.reduce([[], []]) do |(filled, names), slot|
|
|
37
|
+
case slot
|
|
38
|
+
in AST::Placeholder
|
|
39
|
+
param_synthetic_name(names.size)
|
|
40
|
+
.then { [filled + [AST::VariableReference[it, nil]], names + [it]] }
|
|
41
|
+
|
|
42
|
+
else
|
|
43
|
+
[filled + [slot], names]
|
|
44
|
+
end
|
|
24
45
|
end
|
|
46
|
+
end
|
|
25
47
|
|
|
48
|
+
def wrap_in_lambdas(body, names, range)
|
|
26
49
|
names
|
|
27
50
|
.reverse
|
|
28
|
-
.reduce(
|
|
51
|
+
.reduce(body) do |inner, name|
|
|
29
52
|
AST::Lambda[
|
|
30
53
|
[AST::Pattern::Binding[name, nil]],
|
|
31
|
-
AST::Body[[
|
|
32
|
-
|
|
54
|
+
AST::Body[[inner], nil],
|
|
55
|
+
range,
|
|
33
56
|
]
|
|
34
57
|
end
|
|
35
58
|
end
|
|
@@ -38,6 +38,20 @@ module Jade
|
|
|
38
38
|
end
|
|
39
39
|
.then { desugar(it) }
|
|
40
40
|
|
|
41
|
+
# There is no `Basics.(..)` to resolve to: the operator's result
|
|
42
|
+
# type lives in Range, and Basics is loaded before it.
|
|
43
|
+
in AST::InfixOperator(value: '..')
|
|
44
|
+
AST::FunctionCall.new(
|
|
45
|
+
callee: AST::MemberAccess[
|
|
46
|
+
AST::ConstructorReference['Range', operator.range],
|
|
47
|
+
AST::VariableReference['between', operator.range],
|
|
48
|
+
operator.range,
|
|
49
|
+
],
|
|
50
|
+
args: [desugar(left), desugar(right)],
|
|
51
|
+
infix: operator,
|
|
52
|
+
range: node.range,
|
|
53
|
+
)
|
|
54
|
+
|
|
41
55
|
else
|
|
42
56
|
AST::FunctionCall.new(
|
|
43
57
|
callee: AST::VariableReference["(#{operator.value})", operator.range],
|
|
@@ -98,7 +112,10 @@ module Jade
|
|
|
98
112
|
.with(items: items.map { desugar(it) })
|
|
99
113
|
|
|
100
114
|
in AST::RecordLiteral(fields:)
|
|
101
|
-
fields
|
|
115
|
+
fields
|
|
116
|
+
.map { desugar(it) }
|
|
117
|
+
.then { node.with(fields: it) }
|
|
118
|
+
.then { Placeholder.lift(it) }
|
|
102
119
|
|
|
103
120
|
in AST::RecordUpdate(fields:)
|
|
104
121
|
fields.map { desugar(it) }.then { node.with(fields: it) }
|
|
@@ -130,12 +147,14 @@ module Jade
|
|
|
130
147
|
end
|
|
131
148
|
|
|
132
149
|
in AST::Tuple(items:)
|
|
133
|
-
AST::FunctionCall
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
150
|
+
AST::FunctionCall
|
|
151
|
+
.new(
|
|
152
|
+
callee: AST::ConstructorReference["Tuple.Tuple#{items.size}", node.range],
|
|
153
|
+
args: items.map { desugar(it) },
|
|
154
|
+
infix: false,
|
|
155
|
+
range: node.range,
|
|
156
|
+
)
|
|
157
|
+
.then { Placeholder.lift(it) }
|
|
139
158
|
|
|
140
159
|
in AST::Pattern::Tuple(patterns:)
|
|
141
160
|
AST::ConstructorReference[
|
|
@@ -174,9 +193,10 @@ module Jade
|
|
|
174
193
|
in AST::Literal | AST::CharLiteral | AST::VariableReference | AST::ConstructorReference |
|
|
175
194
|
AST::TypeDeclaration | AST::ImportDeclaration |
|
|
176
195
|
AST::Pattern::Literal | AST::Pattern::Binding | AST::Pattern::Wildcard |
|
|
196
|
+
AST::Pattern::Range |
|
|
177
197
|
AST::Pattern::Record | AST::InteropImportDeclaration | AST::StructDeclaration |
|
|
178
|
-
AST::
|
|
179
|
-
AST::CurriedConstructor
|
|
198
|
+
AST::TypeAliasDeclaration | AST::QualifiedAccess | AST::Placeholder |
|
|
199
|
+
AST::InterfaceDeclaration | AST::CurriedConstructor
|
|
180
200
|
|
|
181
201
|
node
|
|
182
202
|
end
|
|
@@ -51,6 +51,7 @@ module Jade
|
|
|
51
51
|
'>=' => Fixity[4, :none],
|
|
52
52
|
'>' => Fixity[4, :none],
|
|
53
53
|
'<' => Fixity[4, :none],
|
|
54
|
+
'..' => Fixity[5, :none],
|
|
54
55
|
'&&' => Fixity[3, :right],
|
|
55
56
|
'||' => Fixity[2, :right],
|
|
56
57
|
}.freeze
|
|
@@ -97,8 +98,9 @@ module Jade
|
|
|
97
98
|
.then { node.with(target: it) }
|
|
98
99
|
|
|
99
100
|
in AST::CaseOf(expression:, branches:)
|
|
100
|
-
branches
|
|
101
|
-
.
|
|
101
|
+
branches
|
|
102
|
+
.map { fix(it) }
|
|
103
|
+
.then { node.with(branches: it, expression: fix(expression)) }
|
|
102
104
|
|
|
103
105
|
in AST::CaseOfBranch(body:)
|
|
104
106
|
node.with(body: fix(body))
|
|
@@ -146,8 +148,8 @@ module Jade
|
|
|
146
148
|
|
|
147
149
|
in AST::VariableReference | AST::ConstructorReference | AST::TypeDeclaration |
|
|
148
150
|
AST::ImportDeclaration | AST::Literal | AST::CharLiteral | AST::RecordAccessSugar | AST::InteropImportDeclaration |
|
|
149
|
-
AST::StructDeclaration | AST::
|
|
150
|
-
AST::CurriedConstructor |
|
|
151
|
+
AST::StructDeclaration | AST::TypeAliasDeclaration | AST::QualifiedAccess |
|
|
152
|
+
AST::Placeholder | AST::InterfaceDeclaration | AST::CurriedConstructor |
|
|
151
153
|
AST::RecordUpdateSugar
|
|
152
154
|
|
|
153
155
|
node
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module Jade
|
|
2
|
+
module Frontend
|
|
3
|
+
module ForwardDeclaration
|
|
4
|
+
module Error
|
|
5
|
+
class AliasExpansion < Jade::Error
|
|
6
|
+
def initialize(entry, span, name:)
|
|
7
|
+
@name = name
|
|
8
|
+
super(entry:, span:)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def message
|
|
12
|
+
"`#{@name}` is a type alias, so `(..)` has nothing to expose; " \
|
|
13
|
+
'an alias names a shape and has no constructors of its own'
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def label
|
|
17
|
+
"write `#{@name}` without `(..)`"
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
module Jade
|
|
2
|
+
module Frontend
|
|
3
|
+
module ForwardDeclaration
|
|
4
|
+
module Error
|
|
5
|
+
# A struct and a union's variant both define a constructor, and a
|
|
6
|
+
# constructor is named without its type, so one module holds at most
|
|
7
|
+
# one of a name.
|
|
8
|
+
class DuplicateConstructorName < Jade::Error
|
|
9
|
+
def initialize(entry, span, name, declaring:, type:, owner:, first_span: nil)
|
|
10
|
+
@name = name
|
|
11
|
+
@declaring = declaring
|
|
12
|
+
@type = type
|
|
13
|
+
@owner = owner
|
|
14
|
+
@first_span = first_span
|
|
15
|
+
super(entry:, span:)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def message
|
|
19
|
+
case @owner
|
|
20
|
+
in Symbol::Struct then "`#{@name}` is already a struct in this module"
|
|
21
|
+
in Symbol::Union then "`#{@name}` is already a constructor of `#{@owner.name}`"
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def label
|
|
26
|
+
case @declaring
|
|
27
|
+
in :variant then "`#{@type}` cannot also declare `#{@name}`"
|
|
28
|
+
in :struct then "cannot declare a struct `#{@name}`"
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def secondary
|
|
33
|
+
return [] unless @first_span
|
|
34
|
+
|
|
35
|
+
[[@first_span, 'first declared here']]
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def notes
|
|
39
|
+
[Jade::Diagnostics::Annotation[:help, 'rename one of them']]
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
module Jade
|
|
2
|
+
module Frontend
|
|
3
|
+
module ForwardDeclaration
|
|
4
|
+
module Error
|
|
5
|
+
class DuplicateTypeName < Jade::Error
|
|
6
|
+
KINDS = {
|
|
7
|
+
Symbol::Interface => 'an interface',
|
|
8
|
+
Symbol::Union => 'a type',
|
|
9
|
+
Symbol::Struct => 'a struct',
|
|
10
|
+
Symbol::Alias => 'a type alias',
|
|
11
|
+
}.freeze
|
|
12
|
+
|
|
13
|
+
def self.kind_of(symbol)
|
|
14
|
+
KINDS.fetch(symbol.class)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def initialize(entry, span, name, declaring:, existing:, first_span: nil)
|
|
18
|
+
@name = name
|
|
19
|
+
@declaring = declaring
|
|
20
|
+
@existing = existing
|
|
21
|
+
@first_span = first_span
|
|
22
|
+
super(entry:, span:)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def message
|
|
26
|
+
"`#{@name}` is already declared as #{@existing} in this module"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def label
|
|
30
|
+
"cannot declare #{@declaring} `#{@name}`"
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def secondary
|
|
34
|
+
return [] unless @first_span
|
|
35
|
+
|
|
36
|
+
[[@first_span, 'first declared here']]
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
require 'jade/error'
|
|
2
2
|
|
|
3
3
|
require 'jade/frontend/forward_declaration/error/bad_import'
|
|
4
|
+
require 'jade/frontend/forward_declaration/error/alias_expansion'
|
|
5
|
+
require 'jade/frontend/forward_declaration/error/duplicate_constructor_name'
|
|
6
|
+
require 'jade/frontend/forward_declaration/error/duplicate_type_name'
|
|
4
7
|
require 'jade/frontend/forward_declaration/error/exposed_type_not_found'
|
|
5
8
|
require 'jade/frontend/forward_declaration/error/exposed_value_not_found'
|
|
6
9
|
require 'jade/frontend/forward_declaration/error/module_not_found'
|
|
@@ -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
|
|
@@ -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,
|
|
8
|
-
Matrix[
|
|
9
|
-
|
|
10
|
-
|
|
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
|