class Puppet::Pops::Types::TypeMismatchDescriber
@api private
Public Class Methods
# File lib/puppet/pops/types/type_mismatch_describer.rb 507 def self.describe_signatures(closure, signatures, args_tuple) 508 singleton.describe_signatures(closure, signatures, args_tuple) 509 end
# File lib/puppet/pops/types/type_mismatch_describer.rb 511 def self.singleton 512 @singleton ||= new 513 end
# File lib/puppet/pops/types/type_mismatch_describer.rb 503 def self.validate_default_parameter(subject, param_name, param_type, value) 504 singleton.validate_default_parameter(subject, param_name, param_type, value) 505 end
# File lib/puppet/pops/types/type_mismatch_describer.rb 499 def self.validate_parameters(subject, params_struct, given_hash, missing_ok = false) 500 singleton.validate_parameters(subject, params_struct, given_hash, missing_ok) 501 end
Public Instance Methods
# File lib/puppet/pops/types/type_mismatch_describer.rb 991 def describe(expected, actual, path) 992 ures_finder = UnresolvedTypeFinder.new 993 expected.accept(ures_finder, nil) 994 unresolved = ures_finder.unresolved 995 if unresolved 996 [UnresolvedTypeReference.new(path, unresolved)] 997 else 998 internal_describe(expected.normalize, expected, actual, path) 999 end 1000 end
# File lib/puppet/pops/types/type_mismatch_describer.rb 971 def describe_PAnyType(expected, original, actual, path) 972 expected.assignable?(actual) ? EMPTY_ARRAY : [TypeMismatch.new(path, original, actual)] 973 end
# File lib/puppet/pops/types/type_mismatch_describer.rb 794 def describe_PArrayType(expected, original, actual, path) 795 descriptions = [] 796 element_type = expected.element_type || PAnyType::DEFAULT 797 if actual.is_a?(PTupleType) 798 types = actual.types 799 expected_size = expected.size_type || PCollectionType::DEFAULT_SIZE 800 actual_size = actual.size_type || PIntegerType.new(types.size, types.size) 801 if expected_size.assignable?(actual_size) 802 types.each_with_index do |type, idx| 803 descriptions.concat(describe(element_type, type, path + [ArrayPathElement.new(idx)])) unless element_type.assignable?(type) 804 end 805 else 806 descriptions << SizeMismatch.new(path, expected_size, actual_size) 807 end 808 elsif actual.is_a?(PArrayType) 809 expected_size = expected.size_type 810 actual_size = actual.size_type || PCollectionType::DEFAULT_SIZE 811 if expected_size.nil? || expected_size.assignable?(actual_size) 812 descriptions << TypeMismatch.new(path, original, PArrayType.new(actual.element_type)) 813 else 814 descriptions << SizeMismatch.new(path, expected_size, actual_size) 815 end 816 else 817 descriptions << TypeMismatch.new(path, original, actual) 818 end 819 descriptions 820 end
# File lib/puppet/pops/types/type_mismatch_describer.rb 937 def describe_PCallableType(expected, original, actual, path) 938 if actual.is_a?(PCallableType) 939 # nil param_types means, any other Callable is assignable 940 if expected.param_types.nil? && expected.return_type.nil? 941 EMPTY_ARRAY 942 else 943 # NOTE: these tests are made in reverse as it is calling the callable that is constrained 944 # (it's lower bound), not its upper bound 945 param_errors = describe_argument_tuple(expected.param_types, actual.param_types, path) 946 if param_errors.empty? 947 this_return_t = expected.return_type || PAnyType::DEFAULT 948 that_return_t = actual.return_type || PAnyType::DEFAULT 949 unless this_return_t.assignable?(that_return_t) 950 [TypeMismatch.new(path + [ReturnTypeElement.new], this_return_t, that_return_t)] 951 else 952 # names are ignored, they are just information 953 # Blocks must be compatible 954 this_block_t = expected.block_type || PUndefType::DEFAULT 955 that_block_t = actual.block_type || PUndefType::DEFAULT 956 if that_block_t.assignable?(this_block_t) 957 EMPTY_ARRAY 958 else 959 [TypeMismatch.new(path + [BlockPathElement.new], this_block_t, that_block_t)] 960 end 961 end 962 else 963 param_errors 964 end 965 end 966 else 967 [TypeMismatch.new(path, original, actual)] 968 end 969 end
# File lib/puppet/pops/types/type_mismatch_describer.rb 782 def describe_PEnumType(expected, original, actual, path) 783 [PatternMismatch.new(path, original, actual)] 784 end
# File lib/puppet/pops/types/type_mismatch_describer.rb 822 def describe_PHashType(expected, original, actual, path) 823 descriptions = [] 824 key_type = expected.key_type || PAnyType::DEFAULT 825 value_type = expected.value_type || PAnyType::DEFAULT 826 if actual.is_a?(PStructType) 827 elements = actual.elements 828 expected_size = expected.size_type || PCollectionType::DEFAULT_SIZE 829 actual_size = PIntegerType.new(elements.count { |a| !a.key_type.assignable?(PUndefType::DEFAULT) }, elements.size) 830 if expected_size.assignable?(actual_size) 831 elements.each do |a| 832 descriptions.concat(describe(key_type, a.key_type, path + [EntryKeyPathElement.new(a.name)])) unless key_type.assignable?(a.key_type) 833 descriptions.concat(describe(value_type, a.value_type, path + [EntryValuePathElement.new(a.name)])) unless value_type.assignable?(a.value_type) 834 end 835 else 836 descriptions << SizeMismatch.new(path, expected_size, actual_size) 837 end 838 elsif actual.is_a?(PHashType) 839 expected_size = expected.size_type 840 actual_size = actual.size_type || PCollectionType::DEFAULT_SIZE 841 if expected_size.nil? || expected_size.assignable?(actual_size) 842 descriptions << TypeMismatch.new(path, original, PHashType.new(actual.key_type, actual.value_type)) 843 else 844 descriptions << SizeMismatch.new(path, expected_size, actual_size) 845 end 846 else 847 descriptions << TypeMismatch.new(path, original, actual) 848 end 849 descriptions 850 end
# File lib/puppet/pops/types/type_mismatch_describer.rb 777 def describe_POptionalType(expected, original, actual, path) 778 return EMPTY_ARRAY if actual.is_a?(PUndefType) || expected.optional_type.nil? 779 internal_describe(expected.optional_type, original.is_a?(PTypeAliasType) ? original : expected, actual, path) 780 end
# File lib/puppet/pops/types/type_mismatch_describer.rb 786 def describe_PPatternType(expected, original, actual, path) 787 [PatternMismatch.new(path, original, actual)] 788 end
# File lib/puppet/pops/types/type_mismatch_describer.rb 852 def describe_PStructType(expected, original, actual, path) 853 elements = expected.elements 854 descriptions = [] 855 if actual.is_a?(PStructType) 856 h2 = actual.hashed_elements.clone 857 elements.each do |e1| 858 key = e1.name 859 e2 = h2.delete(key) 860 if e2.nil? 861 descriptions << MissingKey.new(path, key) unless e1.key_type.assignable?(PUndefType::DEFAULT) 862 else 863 descriptions.concat(describe(e1.key_type, e2.key_type, path + [EntryKeyPathElement.new(key)])) unless e1.key_type.assignable?(e2.key_type) 864 descriptions.concat(describe(e1.value_type, e2.value_type, path + [EntryValuePathElement.new(key)])) unless e1.value_type.assignable?(e2.value_type) 865 end 866 end 867 h2.each_key { |key| descriptions << ExtraneousKey.new(path, key) } 868 elsif actual.is_a?(PHashType) 869 actual_size = actual.size_type || PCollectionType::DEFAULT_SIZE 870 expected_size = PIntegerType.new(elements.count { |e| !e.key_type.assignable?(PUndefType::DEFAULT) }, elements.size) 871 if expected_size.assignable?(actual_size) 872 descriptions << TypeMismatch.new(path, original, PHashType.new(actual.key_type, actual.value_type)) 873 else 874 descriptions << SizeMismatch.new(path, expected_size, actual_size) 875 end 876 else 877 descriptions << TypeMismatch.new(path, original, actual) 878 end 879 descriptions 880 end
# File lib/puppet/pops/types/type_mismatch_describer.rb 882 def describe_PTupleType(expected, original, actual, path) 883 describe_tuple(expected, original, actual, path, SizeMismatch) 884 end
# File lib/puppet/pops/types/type_mismatch_describer.rb 790 def describe_PTypeAliasType(expected, original, actual, path) 791 internal_describe(expected.resolved_type.normalize, expected, actual, path) 792 end
# File lib/puppet/pops/types/type_mismatch_describer.rb 737 def describe_PVariantType(expected, original, actual, path) 738 variant_descriptions = [] 739 types = expected.types 740 types = [PUndefType::DEFAULT] + types if original.is_a?(POptionalType) 741 types.each_with_index do |vt, index| 742 d = describe(vt, actual, path + [VariantPathElement.new(index)]) 743 return EMPTY_ARRAY if d.empty? 744 variant_descriptions << d 745 end 746 descriptions = merge_descriptions(path.length, SizeMismatch, variant_descriptions) 747 if original.is_a?(PTypeAliasType) && descriptions.size == 1 748 # All variants failed in this alias so we report it as a mismatch on the alias 749 # rather than reporting individual failures of the variants 750 [TypeMismatch.new(path, original, actual)] 751 else 752 descriptions 753 end 754 end
# File lib/puppet/pops/types/type_mismatch_describer.rb 886 def describe_argument_tuple(expected, actual, path) 887 describe_tuple(expected, expected, actual, path, CountMismatch) 888 end
Describe a confirmed mismatch using present tense
@param name [String] name of mismatch @param expected [PAnyType] expected type @param actual [PAnyType] actual type @param tense [Symbol] deprecated and ignored
# File lib/puppet/pops/types/type_mismatch_describer.rb 551 def describe_mismatch(name, expected, actual, tense = :ignored) 552 tense_deprecated unless tense == :ignored 553 errors = describe(expected, actual, [SubjectPathElement.new(name)]) 554 case errors.size 555 when 0 556 '' 557 when 1 558 errors[0].format.strip 559 else 560 errors.map { |error| error.format }.join("\n ") 561 end 562 end
# File lib/puppet/pops/types/type_mismatch_describer.rb 718 def describe_no_block_arguments(signature, atypes, path, expected_size, actual_size, arg_count) 719 # not assignable if the number of types in actual is outside number of types in expected 720 if expected_size.assignable?(actual_size) 721 etypes = signature.type.param_types.types 722 enames = signature.parameter_names 723 arg_count.times do |index| 724 adx = index >= etypes.size ? etypes.size - 1 : index 725 etype = etypes[adx] 726 unless etype.assignable?(atypes[index]) 727 descriptions = describe(etype, atypes[index], path + [ParameterPathElement.new(enames[adx])]) 728 return descriptions unless descriptions.empty? 729 end 730 end 731 EMPTY_ARRAY 732 else 733 [CountMismatch.new(path, expected_size, actual_size)] 734 end 735 end
# File lib/puppet/pops/types/type_mismatch_describer.rb 675 def describe_signature_arguments(signature, args_tuple, path) 676 params_tuple = signature.type.param_types 677 params_size_t = params_tuple.size_type || TypeFactory.range(*params_tuple.size_range) 678 679 if args_tuple.is_a?(PTupleType) 680 arg_types = args_tuple.types 681 elsif args_tuple.is_a?(PArrayType) 682 arg_types = Array.new(params_tuple.types.size, args_tuple.element_type || PUndefType::DEFAULT) 683 else 684 return [TypeMismatch.new(path, params_tuple, args_tuple)] 685 end 686 687 if arg_types.last.kind_of_callable? 688 # Check other arguments 689 arg_count = arg_types.size - 1 690 describe_no_block_arguments(signature, arg_types, path, params_size_t, TypeFactory.range(arg_count, arg_count), arg_count) 691 else 692 args_size_t = TypeFactory.range(*args_tuple.size_range) 693 describe_no_block_arguments(signature, arg_types, path, params_size_t, args_size_t, arg_types.size) 694 end 695 end
# File lib/puppet/pops/types/type_mismatch_describer.rb 697 def describe_signature_block(signature, args_tuple, path) 698 param_block_t = signature.block_type 699 arg_block_t = args_tuple.is_a?(PTupleType) ? args_tuple.types.last : nil 700 if TypeCalculator.is_kind_of_callable?(arg_block_t) 701 # Can't pass a block to a callable that doesn't accept one 702 if param_block_t.nil? 703 [UnexpectedBlock.new(path)] 704 else 705 # Check that the block is of the right type 706 describe(param_block_t, arg_block_t, path + [BlockPathElement.new]) 707 end 708 else 709 # Check that the block is optional 710 if param_block_t.nil? || param_block_t.assignable?(PUndefType::DEFAULT) 711 EMPTY_ARRAY 712 else 713 [MissingRequiredBlock.new(path)] 714 end 715 end 716 end
# File lib/puppet/pops/types/type_mismatch_describer.rb 631 def describe_signatures(closure, signatures, args_tuple, tense = :ignored) 632 tense_deprecated unless tense == :ignored 633 error_arrays = [] 634 signatures.each_with_index do |signature, index| 635 error_arrays << describe_signature_arguments(signature, args_tuple, [SignaturePathElement.new(index)]) 636 end 637 638 # Skip block checks if all signatures have argument errors 639 unless error_arrays.all? { |a| !a.empty? } 640 block_arrays = [] 641 signatures.each_with_index do |signature, index| 642 block_arrays << describe_signature_block(signature, args_tuple, [SignaturePathElement.new(index)]) 643 end 644 bc_count = block_arrays.count { |a| !a.empty? } 645 if bc_count == block_arrays.size 646 # Skip argument errors when all alternatives have block errors 647 error_arrays = block_arrays 648 elsif bc_count > 0 649 # Merge errors giving argument errors precedence over block errors 650 error_arrays.each_with_index { |a, index| error_arrays[index] = block_arrays[index] if a.empty? } 651 end 652 end 653 return nil if error_arrays.empty? 654 655 label = closure == 'lambda' ? 'block' : "'#{closure}'" 656 errors = merge_descriptions(0, CountMismatch, error_arrays) 657 if errors.size == 1 658 "#{label}#{errors[0].format}" 659 else 660 if signatures.size == 1 661 sig = signatures[0] 662 result = ["#{label} expects (#{signature_string(sig)})"] 663 result.concat(error_arrays[0].map { |e| " rejected:#{e.chop_path(0).format}" }) 664 else 665 result = ["The function #{label} was called with arguments it does not accept. It expects one of:"] 666 signatures.each_with_index do |sg, index| 667 result << " (#{signature_string(sg)})" 668 result.concat(error_arrays[index].map { |e| " rejected:#{e.chop_path(0).format}" }) 669 end 670 end 671 result.join("\n") 672 end 673 end
Validates that all entries in the param_hash exists in the given param_struct, that their type conforms with the corresponding param_struct element and that all required values are provided. An error message is created for each problem found.
@param params_struct [PStructType] Struct to use for validation @param param_hash [Hash<String,Object>] The parameters to validate @param missing_ok [Boolean] Do not generate errors on missing parameters @return [Array<Mismatch>] An array of found errors. An empty array indicates no errors.
# File lib/puppet/pops/types/type_mismatch_describer.rb 602 def describe_struct_signature(params_struct, param_hash, missing_ok = false) 603 param_type_hash = params_struct.hashed_elements 604 result = param_hash.each_key.reject { |name| param_type_hash.include?(name) }.map { |name| InvalidParameter.new(nil, name) } 605 606 params_struct.elements.each do |elem| 607 name = elem.name 608 value = param_hash[name] 609 value_type = elem.value_type 610 if param_hash.include?(name) 611 if Puppet::Pops::Types::TypeFactory.deferred.implementation_class == value.class 612 if (df_return_type = get_deferred_function_return_type(value)) 613 result << describe(value_type, df_return_type, [ParameterPathElement.new(name)]) unless value_type.generalize.assignable?(df_return_type.generalize) 614 else 615 warning_text = _("Deferred function %{function_name} has no return_type, unable to guarantee value type during compilation.") % 616 {function_name: value.name } 617 Puppet.warn_once('deprecations', 618 "#{value.name}_deferred_warning", 619 warning_text) 620 end 621 else 622 result << describe(value_type, TypeCalculator.singleton.infer_set(value), [ParameterPathElement.new(name)]) unless value_type.instance?(value) 623 end 624 else 625 result << MissingParameter.new(nil, name) unless missing_ok || elem.key_type.is_a?(POptionalType) 626 end 627 end 628 result 629 end
# File lib/puppet/pops/types/type_mismatch_describer.rb 890 def describe_tuple(expected, original, actual, path, size_mismatch_class) 891 return EMPTY_ARRAY if expected == actual || expected.types.empty? && (actual.is_a?(PArrayType)) 892 expected_size = expected.size_type || TypeFactory.range(*expected.size_range) 893 894 if actual.is_a?(PTupleType) 895 actual_size = actual.size_type || TypeFactory.range(*actual.size_range) 896 897 # not assignable if the number of types in actual is outside number of types in expected 898 if expected_size.assignable?(actual_size) 899 etypes = expected.types 900 descriptions = [] 901 unless etypes.empty? 902 actual.types.each_with_index do |atype, index| 903 adx = index >= etypes.size ? etypes.size - 1 : index 904 descriptions.concat(describe(etypes[adx], atype, path + [ArrayPathElement.new(adx)])) 905 end 906 end 907 descriptions 908 else 909 [size_mismatch_class.new(path, expected_size, actual_size)] 910 end 911 elsif actual.is_a?(PArrayType) 912 t2_entry = actual.element_type 913 914 if t2_entry.nil? 915 # Array of anything can not be assigned (unless tuple is tuple of anything) - this case 916 # was handled at the top of this method. 917 # 918 [TypeMismatch.new(path, original, actual)] 919 else 920 expected_size = expected.size_type || TypeFactory.range(*expected.size_range) 921 actual_size = actual.size_type || PCollectionType::DEFAULT_SIZE 922 if expected_size.assignable?(actual_size) 923 descriptions = [] 924 expected.types.each_with_index do |etype, index| 925 descriptions.concat(describe(etype, actual.element_type, path + [ArrayPathElement.new(index)])) 926 end 927 descriptions 928 else 929 [size_mismatch_class.new(path, expected_size, actual_size)] 930 end 931 end 932 else 933 [TypeMismatch.new(path, original, actual)] 934 end 935 end
Why oh why Ruby do you not have a standard Math.max ? @api private
# File lib/puppet/pops/types/type_mismatch_describer.rb 1086 def max(a, b) 1087 a >= b ? a : b 1088 end
# File lib/puppet/pops/types/type_mismatch_describer.rb 756 def merge_descriptions(varying_path_position, size_mismatch_class, variant_descriptions) 757 descriptions = variant_descriptions.flatten 758 [size_mismatch_class, MissingRequiredBlock, UnexpectedBlock, TypeMismatch].each do |mismatch_class| 759 mismatches = descriptions.select { |desc| desc.is_a?(mismatch_class) } 760 if mismatches.size == variant_descriptions.size 761 # If they all have the same canonical path, then we can compact this into one 762 generic_mismatch = mismatches.inject do |prev, curr| 763 break nil unless prev.canonical_path == curr.canonical_path 764 prev.merge(prev.path, curr) 765 end 766 unless generic_mismatch.nil? 767 # Report the generic mismatch and skip the rest 768 descriptions = [generic_mismatch] 769 break 770 end 771 end 772 end 773 descriptions = descriptions.uniq 774 descriptions.size == 1 ? [descriptions[0].chop_path(varying_path_position)] : descriptions 775 end
@api private
# File lib/puppet/pops/types/type_mismatch_describer.rb 1091 def optional(index, required_count) 1092 count = index + 1 1093 count > required_count 1094 end
Produces a string for the signature(s)
@api private
# File lib/puppet/pops/types/type_mismatch_describer.rb 1033 def signature_string(signature) 1034 param_types = signature.type.param_types 1035 param_names = signature.parameter_names 1036 1037 from, to = param_types.size_range 1038 if from == 0 && to == 0 1039 # No parameters function 1040 return '' 1041 end 1042 1043 required_count = from 1044 types = 1045 case param_types 1046 when PTupleType 1047 param_types.types 1048 when PArrayType 1049 [param_types.element_type] 1050 end 1051 1052 # join type with names (types are always present, names are optional) 1053 # separate entries with comma 1054 # 1055 param_names = Array.new(types.size, '') if param_names.empty? 1056 limit = param_names.size 1057 result = param_names.each_with_index.map do |name, index| 1058 type = types[index] || types[-1] 1059 indicator = '' 1060 if to == Float::INFINITY && index == limit - 1 1061 # Last is a repeated_param. 1062 indicator = from == param_names.size ? '+' : '*' 1063 elsif optional(index, required_count) 1064 indicator = '?' 1065 type = type.optional_type if type.is_a?(POptionalType) 1066 end 1067 "#{type} #{name}#{indicator}" 1068 end.join(', ') 1069 1070 # If there is a block, include it 1071 case signature.type.block_type 1072 when POptionalType 1073 result << ', ' unless result == '' 1074 result << "#{signature.type.block_type.optional_type} #{signature.block_name}?" 1075 when PCallableType 1076 result << ', ' unless result == '' 1077 result << "#{signature.type.block_type} #{signature.block_name}" 1078 when NilClass 1079 # nothing 1080 end 1081 result 1082 end
# File lib/puppet/pops/types/type_mismatch_describer.rb 515 def tense_deprecated 516 #TRANSLATORS TypeMismatchDescriber is a class name and 'tense' is a method name and should not be translated 517 message = _("Passing a 'tense' argument to the TypeMismatchDescriber is deprecated and ignored.") 518 message += ' ' + _("Everything is now reported using present tense") 519 Puppet.warn_once('deprecations', 'typemismatch#tense', message) 520 end
@param subject [String] string to be prepended to the exception message @param param_name [String] parameter name @param param_type [PAnyType] parameter type @param value [Object] value to be validated against the given type @param tense [Symbol] deprecated and ignored
# File lib/puppet/pops/types/type_mismatch_describer.rb 570 def validate_default_parameter(subject, param_name, param_type, value, tense = :ignored) 571 tense_deprecated unless tense == :ignored 572 unless param_type.instance?(value) 573 errors = describe(param_type, TypeCalculator.singleton.infer_set(value).generalize, [ParameterPathElement.new(param_name)]) 574 case errors.size 575 when 0 576 when 1 577 raise Puppet::ParseError.new("#{subject}:#{errors[0].format}") 578 else 579 errors_str = errors.map { |error| error.format }.join("\n ") 580 raise Puppet::ParseError.new("#{subject}:\n #{errors_str}") 581 end 582 end 583 end
Validates that all entries in the give_hash exists in the given param_struct, that their type conforms with the corresponding param_struct element and that all required values are provided.
@param subject [String] string to be prepended to the exception message @param params_struct [PStructType] Struct to use for validation @param given_hash [Hash<String,Object>] the parameters to validate @param missing_ok [Boolean] Do not generate errors on missing parameters @param tense [Symbol] deprecated and ignored
# File lib/puppet/pops/types/type_mismatch_describer.rb 531 def validate_parameters(subject, params_struct, given_hash, missing_ok = false, tense = :ignored) 532 tense_deprecated unless tense == :ignored 533 errors = describe_struct_signature(params_struct, given_hash, missing_ok).flatten 534 case errors.size 535 when 0 536 when 1 537 raise Puppet::ParseError.new("#{subject}:#{errors[0].format}") 538 else 539 errors_str = errors.map { |error| error.format }.join("\n ") 540 raise Puppet::ParseError.new("#{subject}:\n #{errors_str}") 541 end 542 end
Private Instance Methods
# File lib/puppet/pops/types/type_mismatch_describer.rb 585 def get_deferred_function_return_type(value) 586 func = Puppet.lookup(:loaders).private_environment_loader. 587 load(:function, value.name) 588 dispatcher = func.class.dispatcher.find_matching_dispatcher(value.arguments) 589 raise ArgumentError, "No matching arity found for #{func.class.name} with arguments #{value.arguments}" unless dispatcher 590 dispatcher.type.return_type 591 end
# File lib/puppet/pops/types/type_mismatch_describer.rb 1002 def internal_describe(expected, original, actual, path) 1003 case expected 1004 when PVariantType 1005 describe_PVariantType(expected, original, actual, path) 1006 when PStructType 1007 describe_PStructType(expected, original, actual, path) 1008 when PHashType 1009 describe_PHashType(expected, original, actual, path) 1010 when PTupleType 1011 describe_PTupleType(expected, original, actual, path) 1012 when PArrayType 1013 describe_PArrayType(expected, original, actual, path) 1014 when PCallableType 1015 describe_PCallableType(expected, original, actual, path) 1016 when POptionalType 1017 describe_POptionalType(expected, original, actual, path) 1018 when PPatternType 1019 describe_PPatternType(expected, original, actual, path) 1020 when PEnumType 1021 describe_PEnumType(expected, original, actual, path) 1022 when PTypeAliasType 1023 describe_PTypeAliasType(expected, original, actual, path) 1024 else 1025 describe_PAnyType(expected, original, actual, path) 1026 end 1027 end