Method: Puppet::Pops::Types::PAnyType#assignable?

Defined in:
lib/puppet/pops/types/types.rb

#assignable?(o, guard = nil) ⇒ Boolean

Checks if o is a type that is assignable to this type. If o is a ‘Class` then it is first converted to a type. If o is a Variant, then it is considered assignable when all its types are assignable

The check for assignable must be guarded against self recursion since ‘self`, the given type o, or both, might be a `TypeAlias`. The initial caller of this method will typically never care about this and hence pass only the first argument, but as soon as a check of a contained type encounters a `TypeAlias`, then a `RecursionGuard` instance is created and passed on in all subsequent calls. The recursion is allowed to continue until self recursion has been detected in both `self` and in the given type. At that point the given type is considered to be assignable to `self` since all checks up to that point were positive.

Parameters:

  • o (Class, PAnyType)

    the class or type to test

  • guard (RecursionGuard) (defaults to: nil)

    guard against recursion. Only used by internal calls

Returns:

  • (Boolean)

    ‘true` when o is assignable to this type



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# File 'lib/puppet/pops/types/types.rb', line 109

def assignable?(o, guard = nil)
  case o
  when Class
    # Safe to call _assignable directly since a Class never is a Unit or Variant
    _assignable?(TypeCalculator.singleton.type(o), guard)
  when PUnitType
    true
  when PTypeAliasType
    # An alias may contain self recursive constructs.
    if o.self_recursion?
      guard ||= RecursionGuard.new
      if guard.add_that(o) == RecursionGuard::SELF_RECURSION_IN_BOTH
        # Recursion detected both in self and other. This means that other is assignable
        # to self. This point would not have been reached otherwise
        true
      else
        assignable?(o.resolved_type, guard)
      end
    else
      assignable?(o.resolved_type, guard)
    end
  when PVariantType
    # Assignable if all contained types are assignable, or if this is exactly Any
    return true if self.class == PAnyType
    # An empty variant may be assignable to NotUndef[T] if T is assignable to empty variant
    return _assignable?(o, guard) if is_a?(PNotUndefType) && o.types.empty?
    !o.types.empty? && o.types.all? { |vt| assignable?(vt, guard) }
  when POptionalType
    # Assignable if undef and contained type is assignable
    assignable?(PUndefType::DEFAULT) && (o.type.nil? || assignable?(o.type))
  when PNotUndefType
    if !(o.type.nil? || o.type.assignable?(PUndefType::DEFAULT))
      assignable?(o.type, guard)
    else
      _assignable?(o, guard)
    end
  else
    _assignable?(o, guard)
  end
end