class TypedRb::Model::TmAbs

abstraction

Attributes

abs_type[RW]
args[RW]
arity[RW]
term[RW]

Public Class Methods

new(args, term, abs_type, node) click to toggle source
Calls superclass method TypedRb::Model::Expr::new
# File lib/typed/model/tm_abs.rb, line 8
def initialize(args, term, abs_type, node)
  super(node, type)
  @args     = args
  @term     = term
  @abs_type = abs_type
  @arity    = args.count { |(arg_type, _, _)|  arg_type == :arg }
  @instantiation_count = 0
end

Public Instance Methods

check_type(context) click to toggle source
# File lib/typed/model/tm_abs.rb, line 17
def check_type(context)
  with_fresh_bindings(context) do |var_type_args, var_type_return, context|
    type_term = term.check_type(context)
    fail TypeCheckError.new("Invalid 'return' statement inside abstraction", type_term.node) if type_term.stack_jump? && type_term.return?
    if type_term.stack_jump? && type_term.break?
      Types::TyGenericFunction.new(var_type_args, type_term, resolve_ruby_method_parameters, node)
    elsif type_term.stack_jump? && (type_term.next? || type_term.return?)
      wrapped_type = type_term.wrapped_type.check_type(context)
      if var_type_return.compatible?(wrapped_type, :gt)
        Types::TyGenericFunction.new(var_type_args, var_type_return, resolve_ruby_method_parameters, node)
      else
        # TODO: improve message
        error_msg = "Error parsing abstraction, incompatible break return type found: #{var_type_return} < #{wrapped_type}"
        fail TypeCheckError.new(error_msg, node)
      end
    elsif type_term.either?
      max_either_type = type_term.check_type(context, [:normal, :return, :next])
      if var_type_return.compatible?(max_either_type, :gt)
        if type_term.break?
          either_return = Types::TyEither.new(node)
          either_return[:break] = type_term[:break]
          either_return[:normal] = var_type_return
          Types::TyGenericFunction.new(var_type_args, either_return, resolve_ruby_method_parameters, node)
        else
          Types::TyGenericFunction.new(var_type_args, var_type_return, resolve_ruby_method_parameters, node)
        end
      else
        error_msg = "Error parsing abstraction, incompatible either return type found: #{var_type_return} < #{type_term}}"
        fail TypeCheckError.new(error_msg, node)
      end
    elsif var_type_return.compatible?(type_term, :gt)
      Types::TyGenericFunction.new(var_type_args, var_type_return, resolve_ruby_method_parameters, node)
    else
      # TODO: improve message
      error_msg = "Error parsing abstraction, incompatible return type found: #{var_type_return} < #{type_term}"
      fail TypeCheckError.new(error_msg, node)
    end
  end
end
with_fresh_bindings(context) { |fresh_args, return_type_var_arg, context| ... } click to toggle source

abstractions are polymorphic universal types by default, we need new bindings in the type variables with each instantiation of the lambda.

# File lib/typed/model/tm_abs.rb, line 59
def with_fresh_bindings(context)
  orig_context = Types::TypingContext.type_variables_register
  Types::TypingContext.push_context(:lambda)
  fresh_args = args.map do |(type, var, opt)|
    if type == :mlhs
      context = var.check_type(:lambda, context)
      var
    else
      type_var_arg = Types::TypingContext.type_variable_for_abstraction(:lambda, "#{var}", context)
      type_var_arg.node = node
      context = case type
                when :arg, :block
                  context.add_binding(var, type_var_arg)
                when :optarg
                  declared_arg_type = opt.check_type(orig_context)
                  if type_var_arg.compatible?(declared_arg_type, :gt)
                    context.add_binding(var, type_var_arg)
                  end
                end
      type_var_arg
    end
  end

  return_type_var_arg = Types::TypingContext.type_variable_for_abstraction(:lambda, nil, context)
  return_type_var_arg.node = node
  lambda_type  = yield fresh_args, return_type_var_arg, context
  lambda_type.local_typing_context = Types::TypingContext.pop_context
  lambda_type
end

Protected Instance Methods

resolve_ruby_method_parameters() click to toggle source
# File lib/typed/model/tm_abs.rb, line 91
def resolve_ruby_method_parameters
  args.map do |(arg_type, val, _)|
    if arg_type == :optarg
      [:opt, val]
    elsif arg_type == :blockarg
      [:block, val]
    else
      [:req, val]
    end
  end
end