Module: Jade::Frontend::TypeChecking::Inference::Implementation
- Extended by:
- Helpers, Implementation
- Included in:
- Implementation
- Defined in:
- lib/jade/frontend/type_checking/inference/implementation.rb
Instance Method Summary collapse
Methods included from Helpers
check, generalize, instantiate, type_from_symbol, unify
Instance Method Details
#infer(node, registry, state, _expected) ⇒ Object
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 |
# File 'lib/jade/frontend/type_checking/inference/implementation.rb', line 9 def infer(node, registry, state, _expected) node => AST::Implementation(functions:) impl = node.symbol interface_sym = registry.lookup(impl.interface) interface_qname = impl.interface.qualified_name # Build the concrete type for the constructor, respecting its type params concrete_type, = type_from_symbol(impl.type, registry, state.env.var_gen) functions .reduce(state) do |st, impl_fn| impl_fn => AST::ImplementationFunction(name:) iface_fn = interface_sym .functions .find { |f| f.name == name } # Instantiate the interface function with fresh vars iface_fn_type, iface_fn_constraints = type_from_symbol(iface_fn, registry, st.env.var_gen) # The type var standing for the interface's type param t_var = iface_fn_constraints .find { |c| c.interface == interface_qname } .type # When the interface uses t_var as a constructor (e.g. f(a) -> f(b)), # bind it to a partial application so that f(a) beta-reduces correctly. # For 1-param types (Maybe): tail = [] → constructor # For 2-param types (Result): tail = [e] → PartialApplication[Constructor, [e]] binding_type = case [constructor_var_in?(iface_fn_type, t_var.id), concrete_type] in [true, Type::Application(constructor:, args:)] tail = args.drop(1) tail.empty? ? constructor : Type::PartialApplication[constructor, tail] else concrete_type end # Bind the interface type var to the concrete type st_after_bind = st.unify(t_var, binding_type) { nil } expected_type = st_after_bind.env.substitution.apply(iface_fn_type) infer_fn( impl_fn, registry, st_after_bind, Expected.check(expected_type), interface_qname, ) end .then { [it, Result.init(Type.unit)] } end |