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 3371 def initialize(name, type_expr, resolved_type = nil) 3372 @name = name 3373 @type_expr = type_expr 3374 @resolved_type = resolved_type 3375 @self_recursion = false 3376 end
# File lib/puppet/pops/types/types.rb 3355 def self.register_ptype(loader, ir) 3356 create_ptype(loader, ir, 'AnyType', 3357 'name' => PStringType::NON_EMPTY, 3358 'type_expr' => PAnyType::DEFAULT, 3359 'resolved_type' => { 3360 KEY_TYPE => POptionalType.new(PTypeType::DEFAULT), 3361 KEY_VALUE => nil 3362 } 3363 ) 3364 end
Public Instance Methods
Puppet::Pops::Types::PAnyType#accept
# File lib/puppet/pops/types/types.rb 3515 def accept(visitor, guard) 3516 guarded_recursion(guard, nil) do |g| 3517 super(visitor, g) 3518 @resolved_type.accept(visitor, g) unless @resolved_type.nil? 3519 end 3520 end
Puppet::Pops::Types::PAnyType#assignable?
# File lib/puppet/pops/types/types.rb 3378 def assignable?(o, guard = nil) 3379 if @self_recursion 3380 guard ||= RecursionGuard.new 3381 guard.with_this(self) { |state| state == RecursionGuard::SELF_RECURSION_IN_BOTH ? true : super(o, guard) } 3382 else 3383 super(o, guard) 3384 end 3385 end
# File lib/puppet/pops/types/types.rb 3397 def callable_args?(callable, guard) 3398 guarded_recursion(guard, false) { |g| resolved_type.callable_args?(callable, g) } 3399 end
# File lib/puppet/pops/types/types.rb 3401 def check_self_recursion(originator) 3402 resolved_type.check_self_recursion(originator) unless originator.equal?(self) 3403 end
Puppet::Pops::Types::PAnyType#eql?
# File lib/puppet/pops/types/types.rb 3511 def eql?(o) 3512 super && o.name == @name 3513 end
# File lib/puppet/pops/types/types.rb 3421 def hash 3422 @name.hash 3423 end
# File lib/puppet/pops/types/types.rb 3409 def instance?(o, guard = nil) 3410 really_instance?(o, guard) == 1 3411 end
# File lib/puppet/pops/types/types.rb 3413 def iterable?(guard = nil) 3414 guarded_recursion(guard, false) { |g| resolved_type.iterable?(g) } 3415 end
# File lib/puppet/pops/types/types.rb 3417 def iterable_type(guard = nil) 3418 guarded_recursion(guard, nil) { |g| resolved_type.iterable_type(g) } 3419 end
# File lib/puppet/pops/types/types.rb 3405 def kind_of_callable?(optional=true, guard = nil) 3406 guarded_recursion(guard, false) { |g| resolved_type.kind_of_callable?(optional, g) } 3407 end
Delegates to resolved type
# File lib/puppet/pops/types/types.rb 3540 def method_missing(name, *arguments, &block) 3541 super if @resolved_type.equal?(PTypeReferenceType::DEFAULT) 3542 resolved_type.send(name, *arguments, &block) 3543 end
@api private
# File lib/puppet/pops/types/types.rb 3546 def really_instance?(o, guard = nil) 3547 if @self_recursion 3548 guard ||= RecursionGuard.new 3549 guard.with_that(o) do 3550 guard.with_this(self) { |state| state == RecursionGuard::SELF_RECURSION_IN_BOTH ? 0 : resolved_type.really_instance?(o, guard) } 3551 end 3552 else 3553 resolved_type.really_instance?(o, guard) 3554 end 3555 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 3471 def resolve(loader) 3472 @loader = loader 3473 if @resolved_type.nil? 3474 # resolved to PTypeReferenceType::DEFAULT during resolve to avoid endless recursion 3475 @resolved_type = PTypeReferenceType::DEFAULT 3476 @self_recursion = true # assumed while it being found out below 3477 begin 3478 if @type_expr.is_a?(PTypeReferenceType) 3479 @resolved_type = @type_expr.resolve(loader) 3480 else 3481 @resolved_type = TypeParser.singleton.interpret(@type_expr, loader).normalize 3482 end 3483 3484 # Find out if this type is recursive. A recursive type has performance implications 3485 # on several methods and this knowledge is used to avoid that for non-recursive 3486 # types. 3487 guard = RecursionGuard.new 3488 real_type_asserter = AssertOtherTypeAcceptor.new 3489 accept(real_type_asserter, guard) 3490 unless real_type_asserter.other_type_detected? 3491 raise ArgumentError, "Type alias '#{name}' cannot be resolved to a real type" 3492 end 3493 @self_recursion = guard.recursive_this?(self) 3494 # All aliases involved must re-check status since this alias is now resolved 3495 if @self_recursion 3496 accept(AssertSelfRecursionStatusAcceptor.new, RecursionGuard.new) 3497 when_self_recursion_detected 3498 end 3499 rescue 3500 @resolved_type = nil 3501 raise 3502 end 3503 else 3504 # An alias may appoint an Object type that isn't resolved yet. The default type 3505 # reference is used to prevent endless recursion and should not be resolved here. 3506 @resolved_type.resolve(loader) unless @resolved_type.equal?(PTypeReferenceType::DEFAULT) 3507 end 3508 self 3509 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 3392 def resolved_type 3393 raise Puppet::Error, "Reference to unresolved type #{@name}" unless @resolved_type 3394 @resolved_type 3395 end
Delegates to resolved type
# File lib/puppet/pops/types/types.rb 3535 def respond_to_missing?(name, include_private) 3536 resolved_type.respond_to?(name, include_private) 3537 end
# File lib/puppet/pops/types/types.rb 3522 def self_recursion? 3523 @self_recursion 3524 end
# File lib/puppet/pops/types/types.rb 3454 def set_self_recursion_status 3455 return if @self_recursion || @resolved_type.is_a?(PTypeReferenceType) 3456 @self_recursion = true 3457 guard = RecursionGuard.new 3458 accept(NoopTypeAcceptor::INSTANCE, guard) 3459 @self_recursion = guard.recursive_this?(self) 3460 when_self_recursion_detected if @self_recursion # no difference 3461 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 3530 def to_s 3531 TypeFormatter.singleton.alias_expanded_string(self) 3532 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 3559 def type_expr 3560 nil 3561 end
Protected Instance Methods
# File lib/puppet/pops/types/types.rb 3565 def _assignable?(o, guard) 3566 resolved_type.assignable?(o, guard) 3567 end
# File lib/puppet/pops/types/types.rb 3569 def new_function 3570 resolved_type.new_function 3571 end
Private Instance Methods
# File lib/puppet/pops/types/types.rb 3575 def guarded_recursion(guard, dflt) 3576 if @self_recursion 3577 guard ||= RecursionGuard.new 3578 guard.with_this(self) { |state| (state & RecursionGuard::SELF_RECURSION_IN_THIS) == 0 ? yield(guard) : dflt } 3579 else 3580 yield(guard) 3581 end 3582 end
# File lib/puppet/pops/types/types.rb 3584 def when_self_recursion_detected 3585 if @resolved_type.is_a?(PVariantType) 3586 # Drop variants that are not real types 3587 resolved_types = @resolved_type.types 3588 real_types = resolved_types.select do |type| 3589 next false if type == self 3590 real_type_asserter = AssertOtherTypeAcceptor.new 3591 type.accept(real_type_asserter, RecursionGuard.new) 3592 real_type_asserter.other_type_detected? 3593 end 3594 if real_types.size != resolved_types.size 3595 if real_types.size == 1 3596 @resolved_type = real_types[0] 3597 else 3598 @resolved_type = PVariantType.maybe_create(real_types) 3599 end 3600 # Drop self recursion status in case it's not self recursive anymore 3601 guard = RecursionGuard.new 3602 accept(NoopTypeAcceptor::INSTANCE, guard) 3603 @self_recursion = guard.recursive_this?(self) 3604 end 3605 end 3606 @resolved_type.check_self_recursion(self) if @self_recursion 3607 end