Module: Jade::Frontend::SemanticAnalysis::Implementation

Extended by:
Helper, Implementation
Included in:
Implementation
Defined in:
lib/jade/frontend/semantic_analysis/implementation.rb

Instance Method Summary collapse

Methods included from Helper

analyze_duplicate_fields, analyze_in_parallel, analyze_in_sequence, analyze_node, bind, collect_vars, lookup, validate_type_symbol

Instance Method Details

#analyze(node, registry, scope, entry) ⇒ Object



8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/jade/frontend/semantic_analysis/implementation.rb', line 8

def analyze(node, registry, scope, entry)
  node => AST::Implementation(interface:, applied_type:, extends:, functions:)

  interface_ref = entry.lookup_type(interface).to_ref
  type_sym = lookup_applied_type(applied_type, entry)
  type_ref = type_sym.to_ref

  impl_symbol = entry.implementations[[
    interface_ref.qualified_name,
    type_ref.qualified_name,
  ]]

  functions_r = analyze_in_parallel(functions, registry, scope, entry)

  make_error = ->(klass, **kw) { klass.new(entry.name, node.range, **kw) }
  type_is_local = entry.defined_types.key?(local_type_name(applied_type))

  unless entry.defined_types.key?(interface) || type_is_local
    return make_error
      .(
        Error::OrphanImplementation,
        interface: entry.lookup_type(interface).qname,
        type:      type_sym.qname,
      )
      .then { Result[node, [it], scope] }
  end

  iface_sym = registry.lookup(interface_ref)

  extends_errors = extends
    .flat_map do |iface_name|
      ext_sym = entry.lookup_type(iface_name)
      next [] if entry.implementations.key?([ext_sym.qname, type_sym.qname])

      [make_error.(
        Error::MissingExtendsImplementation,
        interface:   ext_sym.qname,
        type:        type_sym.qname,
        required_by: iface_sym.qname,
      )]
    end

  cycle_errors =
    if extends_errors.empty? && cycle_in_extends?(iface_sym.qname, type_sym.qname, entry)
      [make_error.(Error::CircularExtends, interface: iface_sym.qname, type: type_sym.qname)]
    else
      []
    end

  type_param_errors =
    case [parameterized_interface?(iface_sym), type_sym]
    in [true, { type_params: [] }]
      [make_error.(Error::TypeParamRequired, interface: iface_sym.qname, type: type_sym.qname)]
    else
      []
    end

  Result
    .combine(node, scope:, functions: functions_r)
    .map_node { it.with(symbol: impl_symbol) }
    .add_errors(
      fn_name_errors(functions, iface_sym, &make_error) +
        extends_errors + cycle_errors + type_param_errors,
    )
end