class Puppet::Pops::Types::PTypeAliasType
Describes a named alias for another Type
. The alias is created with a name and an unresolved type expression. The type expression may in turn contain other aliases (including the alias that contains it) which means that an alias might contain self recursion. Whether or not that is the case is computed and remembered when the alias is resolved since guarding against self recursive constructs is relatively expensive.
@api public
Constants
- DEFAULT
Attributes
Public Class Methods
@param name [String] The name of the type @param type_expr
[Model::PopsObject] The expression that describes the aliased type @param resolved_type
[PAnyType] the resolve type (only used for the DEFAULT
initialization)
# File lib/puppet/pops/types/types.rb 3370 def initialize(name, type_expr, resolved_type = nil) 3371 @name = name 3372 @type_expr = type_expr 3373 @resolved_type = resolved_type 3374 @self_recursion = false 3375 end
# File lib/puppet/pops/types/types.rb 3354 def self.register_ptype(loader, ir) 3355 create_ptype(loader, ir, 'AnyType', 3356 'name' => PStringType::NON_EMPTY, 3357 'type_expr' => PAnyType::DEFAULT, 3358 'resolved_type' => { 3359 KEY_TYPE => POptionalType.new(PTypeType::DEFAULT), 3360 KEY_VALUE => nil 3361 } 3362 ) 3363 end
Public Instance Methods
Puppet::Pops::Types::PAnyType#accept
# File lib/puppet/pops/types/types.rb 3514 def accept(visitor, guard) 3515 guarded_recursion(guard, nil) do |g| 3516 super(visitor, g) 3517 @resolved_type.accept(visitor, g) unless @resolved_type.nil? 3518 end 3519 end
Puppet::Pops::Types::PAnyType#assignable?
# File lib/puppet/pops/types/types.rb 3377 def assignable?(o, guard = nil) 3378 if @self_recursion 3379 guard ||= RecursionGuard.new 3380 guard.with_this(self) { |state| state == RecursionGuard::SELF_RECURSION_IN_BOTH ? true : super(o, guard) } 3381 else 3382 super(o, guard) 3383 end 3384 end
# File lib/puppet/pops/types/types.rb 3396 def callable_args?(callable, guard) 3397 guarded_recursion(guard, false) { |g| resolved_type.callable_args?(callable, g) } 3398 end
# File lib/puppet/pops/types/types.rb 3400 def check_self_recursion(originator) 3401 resolved_type.check_self_recursion(originator) unless originator.equal?(self) 3402 end
Puppet::Pops::Types::PAnyType#eql?
# File lib/puppet/pops/types/types.rb 3510 def eql?(o) 3511 super && o.name == @name 3512 end
# File lib/puppet/pops/types/types.rb 3420 def hash 3421 @name.hash 3422 end
# File lib/puppet/pops/types/types.rb 3408 def instance?(o, guard = nil) 3409 really_instance?(o, guard) == 1 3410 end
# File lib/puppet/pops/types/types.rb 3412 def iterable?(guard = nil) 3413 guarded_recursion(guard, false) { |g| resolved_type.iterable?(g) } 3414 end
# File lib/puppet/pops/types/types.rb 3416 def iterable_type(guard = nil) 3417 guarded_recursion(guard, nil) { |g| resolved_type.iterable_type(g) } 3418 end
# File lib/puppet/pops/types/types.rb 3404 def kind_of_callable?(optional=true, guard = nil) 3405 guarded_recursion(guard, false) { |g| resolved_type.kind_of_callable?(optional, g) } 3406 end
Delegates to resolved type
# File lib/puppet/pops/types/types.rb 3539 def method_missing(name, *arguments, &block) 3540 super if @resolved_type.equal?(PTypeReferenceType::DEFAULT) 3541 resolved_type.send(name, *arguments, &block) 3542 end
@api private
# File lib/puppet/pops/types/types.rb 3545 def really_instance?(o, guard = nil) 3546 if @self_recursion 3547 guard ||= RecursionGuard.new 3548 guard.with_that(o) do 3549 guard.with_this(self) { |state| state == RecursionGuard::SELF_RECURSION_IN_BOTH ? 0 : resolved_type.really_instance?(o, guard) } 3550 end 3551 else 3552 resolved_type.really_instance?(o, guard) 3553 end 3554 end
Called from the TypeParser
once it has found a type using the Loader
. The TypeParser
will interpret the contained expression and the resolved type is remembered. This method also checks and remembers if the resolve type contains self recursion.
@param type_parser [TypeParser] type parser that will interpret the type expression @param loader [Loader::Loader] loader to use when loading type aliases @return [PTypeAliasType] the receiver of the call, i.e. `self` @api private
# File lib/puppet/pops/types/types.rb 3470 def resolve(loader) 3471 @loader = loader 3472 if @resolved_type.nil? 3473 # resolved to PTypeReferenceType::DEFAULT during resolve to avoid endless recursion 3474 @resolved_type = PTypeReferenceType::DEFAULT 3475 @self_recursion = true # assumed while it being found out below 3476 begin 3477 if @type_expr.is_a?(PTypeReferenceType) 3478 @resolved_type = @type_expr.resolve(loader) 3479 else 3480 @resolved_type = TypeParser.singleton.interpret(@type_expr, loader).normalize 3481 end 3482 3483 # Find out if this type is recursive. A recursive type has performance implications 3484 # on several methods and this knowledge is used to avoid that for non-recursive 3485 # types. 3486 guard = RecursionGuard.new 3487 real_type_asserter = AssertOtherTypeAcceptor.new 3488 accept(real_type_asserter, guard) 3489 unless real_type_asserter.other_type_detected? 3490 raise ArgumentError, "Type alias '#{name}' cannot be resolved to a real type" 3491 end 3492 @self_recursion = guard.recursive_this?(self) 3493 # All aliases involved must re-check status since this alias is now resolved 3494 if @self_recursion 3495 accept(AssertSelfRecursionStatusAcceptor.new, RecursionGuard.new) 3496 when_self_recursion_detected 3497 end 3498 rescue 3499 @resolved_type = nil 3500 raise 3501 end 3502 else 3503 # An alias may appoint an Object type that isn't resolved yet. The default type 3504 # reference is used to prevent endless recursion and should not be resolved here. 3505 @resolved_type.resolve(loader) unless @resolved_type.equal?(PTypeReferenceType::DEFAULT) 3506 end 3507 self 3508 end
Returns the resolved type. The type must have been resolved by a call prior to calls to this method or an error will be raised.
@return [PAnyType] The resolved type of this alias. @raise [Puppet::Error] unless the type has been resolved prior to calling this method
# File lib/puppet/pops/types/types.rb 3391 def resolved_type 3392 raise Puppet::Error, "Reference to unresolved type #{@name}" unless @resolved_type 3393 @resolved_type 3394 end
Delegates to resolved type
# File lib/puppet/pops/types/types.rb 3534 def respond_to_missing?(name, include_private) 3535 resolved_type.respond_to?(name, include_private) 3536 end
# File lib/puppet/pops/types/types.rb 3521 def self_recursion? 3522 @self_recursion 3523 end
# File lib/puppet/pops/types/types.rb 3453 def set_self_recursion_status 3454 return if @self_recursion || @resolved_type.is_a?(PTypeReferenceType) 3455 @self_recursion = true 3456 guard = RecursionGuard.new 3457 accept(NoopTypeAcceptor::INSTANCE, guard) 3458 @self_recursion = guard.recursive_this?(self) 3459 when_self_recursion_detected if @self_recursion # no difference 3460 end
Returns the expanded string the form of the alias, e.g. <alias name> = <resolved type>
@return [String] the expanded form of this alias @api public
# File lib/puppet/pops/types/types.rb 3529 def to_s 3530 TypeFormatter.singleton.alias_expanded_string(self) 3531 end
@return `nil` to prevent serialization of the type_expr
used when first initializing this instance @api private
# File lib/puppet/pops/types/types.rb 3558 def type_expr 3559 nil 3560 end
Protected Instance Methods
# File lib/puppet/pops/types/types.rb 3564 def _assignable?(o, guard) 3565 resolved_type.assignable?(o, guard) 3566 end
# File lib/puppet/pops/types/types.rb 3568 def new_function 3569 resolved_type.new_function 3570 end
Private Instance Methods
# File lib/puppet/pops/types/types.rb 3574 def guarded_recursion(guard, dflt) 3575 if @self_recursion 3576 guard ||= RecursionGuard.new 3577 guard.with_this(self) { |state| (state & RecursionGuard::SELF_RECURSION_IN_THIS) == 0 ? yield(guard) : dflt } 3578 else 3579 yield(guard) 3580 end 3581 end
# File lib/puppet/pops/types/types.rb 3583 def when_self_recursion_detected 3584 if @resolved_type.is_a?(PVariantType) 3585 # Drop variants that are not real types 3586 resolved_types = @resolved_type.types 3587 real_types = resolved_types.select do |type| 3588 next false if type == self 3589 real_type_asserter = AssertOtherTypeAcceptor.new 3590 type.accept(real_type_asserter, RecursionGuard.new) 3591 real_type_asserter.other_type_detected? 3592 end 3593 if real_types.size != resolved_types.size 3594 if real_types.size == 1 3595 @resolved_type = real_types[0] 3596 else 3597 @resolved_type = PVariantType.maybe_create(real_types) 3598 end 3599 # Drop self recursion status in case it's not self recursive anymore 3600 guard = RecursionGuard.new 3601 accept(NoopTypeAcceptor::INSTANCE, guard) 3602 @self_recursion = guard.recursive_this?(self) 3603 end 3604 end 3605 @resolved_type.check_self_recursion(self) if @self_recursion 3606 end