Class: Solargraph::ComplexType::Conformance

Inherits:
Object
  • Object
show all
Defined in:
lib/solargraph/complex_type/conformance.rb

Overview

Checks whether a type can be used in a given situation

Instance Method Summary collapse

Constructor Details

#initialize(api_map, inferred, expected, situation = :method_call, rules = [], variance: inferred.erased_variance(situation)) ⇒ Conformance

Returns a new instance of Conformance.

Parameters:

  • api_map (ApiMap)
  • inferred (ComplexType::UniqueType)
  • expected (ComplexType::UniqueType)
  • situation (:method_call, :return_type) (defaults to: :method_call)
  • rules (Array<:allow_subtype_skew, :allow_empty_params, :allow_reverse_match, :allow_any_match, :allow_undefined, :allow_unresolved_generic, :allow_unmatched_interface>) (defaults to: [])
  • variance (:invariant, :covariant, :contravariant) (defaults to: inferred.erased_variance(situation))


15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/solargraph/complex_type/conformance.rb', line 15

def initialize api_map, inferred, expected,
               situation = :method_call, rules = [],
               variance: inferred.erased_variance(situation)
  @api_map = api_map
  @inferred = inferred
  @expected = expected
  @situation = situation
  @rules = rules
  @variance = variance
  # :nocov:
  unless expected.is_a?(UniqueType)
    # @sg-ignore This should never happen and the typechecker is angry about it
    raise "Expected type must be a UniqueType, got #{expected.class} in #{expected.inspect}"
  end
  # :nocov:
  return if inferred.is_a?(UniqueType)
  # :nocov:
  # @sg-ignore This should never happen and the typechecker is angry about it
  raise "Inferred type must be a UniqueType, got #{inferred.class} in #{inferred.inspect}"
  # :nocov:
end

Instance Method Details

#conforms_to_unique_type?Boolean

Returns:

  • (Boolean)


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
73
74
75
76
77
# File 'lib/solargraph/complex_type/conformance.rb', line 37

def conforms_to_unique_type?
  unless expected.is_a?(UniqueType)
    # :nocov:
    raise "Expected type must be a UniqueType, got #{expected.class} in #{expected.inspect}"
    # :nocov:
  end

  return true if ignore_interface?
  return true if conforms_via_reverse_match?

  downcast_inferred = inferred.downcast_to_literal_if_possible
  downcast_expected = expected.downcast_to_literal_if_possible
  if (downcast_inferred.name != inferred.name) || (downcast_expected.name != expected.name)
    return with_new_types(downcast_inferred, downcast_expected).conforms_to_unique_type?
  end

  if rules.include?(:allow_subtype_skew) && !expected.all_params.empty?
    # parameters are not considered in this case
    return with_new_types(inferred, expected.erase_parameters).conforms_to_unique_type?
  end

  return with_new_types(inferred.erase_parameters, expected).conforms_to_unique_type? if only_inferred_parameters?

  return conforms_via_stripped_expected_parameters? if can_strip_expected_parameters?

  return true if inferred == expected

  return false unless erased_type_conforms?

  return true if inferred.all_params.empty? && rules.include?(:allow_empty_params)

  # at this point we know the erased type is fine - time to look at parameters

  # there's an implicit 'any' on the expectation parameters
  # if there are none specified
  return true if expected.all_params.empty?

  return false unless key_types_conform?

  subtypes_conform?
end