# frozen_string_literal: true# typed: truemoduleT::Private::Methods::SignatureValidationMethods=T::Private::MethodsModes=Methods::Modesdefself.validate(signature)ifsignature.method_name==:initialize&&signature.method.owner.is_a?(Class)# Constructors are special. They look like overrides in terms of a super_method existing,# but in practice, you never call them polymorphically. Conceptually, they're standard# methods (this is consistent with how they're treated in other languages, e.g. Java)ifsignature.mode!=Modes.standardraise"`initialize` should not use `.abstract` or `.implementation` or any other inheritance modifiers."endreturnendsuper_method=signature.method.super_methodifsuper_method&&super_method.owner!=signature.method.ownerMethods.maybe_run_sig_block_for_method(super_method)super_signature=Methods.signature_for_method(super_method)# If the super_method has any kwargs we can't build a# Signature for it, so we'll just skip validation in that case.if!super_signature&&!super_method.parameters.select{|kind,_|kind==:rest||kind==:kwrest}.empty?nilelse# super_signature can be nil when we're overriding a method (perhaps a builtin) that didn't use# one of the method signature helpers. Use an untyped signature so we can still validate# everything but types.## We treat these signatures as overridable, that way people can use `.override` with# overrides of builtins. In the future we could try to distinguish when the method is a# builtin and treat non-builtins as non-overridable (so you'd be forced to declare them with# `.overridable`).#super_signature||=Methods::Signature.new_untyped(method: super_method)validate_override_mode(signature,super_signature)validate_override_shape(signature,super_signature)validate_override_types(signature,super_signature)endelsevalidate_non_override_mode(signature)endendprivate_class_methoddefself.pretty_mode(signature)ifsignature.mode==Modes.overridable_override'.overridable.override'else".#{signature.mode}"endenddefself.validate_override_mode(signature,super_signature)casesignature.modewhen*Modes::OVERRIDE_MODES# PeacefulwhenModes.abstract# Either the parent method is abstract, or it's not.## If it's abstract, we want to allow overriding abstract with abstract to# possibly narrow the type or provide more specific documentation.## If it's not, then marking this method `abstract` will silently be a no-op.# That's bad and we probably want to report an error, but fixing that# will have to be a separate fix (that bad behavior predates this current# comment, introduced when we fixed the abstract/abstract case).## Therefore:# Peaceful (mostly)when*Modes::NON_OVERRIDE_MODESifsuper_signature.mode==Modes.standard# Peacefulelsifsuper_signature.mode==Modes.abstractraise"You must use `.override` when overriding the abstract method `#{signature.method_name}`.\n"\" Abstract definition: #{method_loc_str(super_signature.method)}\n"\" Implementation definition: #{method_loc_str(signature.method)}\n"elsifsuper_signature.mode!=Modes.untypedraise"You must use `.override` when overriding the existing method `#{signature.method_name}`.\n"\" Parent definition: #{method_loc_str(super_signature.method)}\n"\" Child definition: #{method_loc_str(signature.method)}\n"endelseraise"Unexpected mode: #{signature.mode}. Please report this bug at https://github.com/sorbet/sorbet/issues"endenddefself.validate_non_override_mode(signature)casesignature.modewhenModes.overrideifsignature.method_name==:each&&signature.method.owner<Enumerable# Enumerable#each is the only method in Sorbet's RBI payload that defines an abstract method.# Enumerable#each does not actually exist at runtime, but it is required to be implemented by# any class which includes Enumerable. We want to declare Enumerable#each as abstract so that# people can call it anything which implements the Enumerable interface, and so that it's a# static error to forget to implement it.## This is a one-off hack, and we should think carefully before adding more methods here.nilelseraise"You marked `#{signature.method_name}` as #{pretty_mode(signature)}, but that method doesn't already exist in this class/module to be overriden.\n"\" Either check for typos and for missing includes or super classes to make the parent method shows up\n"\" ... or remove #{pretty_mode(signature)} here: #{method_loc_str(signature.method)}\n"endwhenModes.standard,*Modes::NON_OVERRIDE_MODES# Peacefulnilelseraise"Unexpected mode: #{signature.mode}. Please report this bug at https://github.com/sorbet/sorbet/issues"end# Given a singleton class, we can check if it belongs to a# module by looking at its superclass; given `module M`,# `M.singleton_class.superclass == Module`, which is not true# for any class.owner=signature.method.ownerif(signature.mode==Modes.abstract||Modes::OVERRIDABLE_MODES.include?(signature.mode))&&owner.singleton_class?&&owner.superclass==Moduleraise"Defining an overridable class method (via #{pretty_mode(signature)}) "\"on a module is not allowed. Class methods on "\"modules do not get inherited and thus cannot be overridden."endenddefself.validate_override_shape(signature,super_signature)returnifsignature.override_allow_incompatiblereturnifsuper_signature.mode==Modes.untypedmethod_name=signature.method_namemode_verb=super_signature.mode==Modes.abstract?'implements':'overrides'if!signature.has_rest&&signature.arg_count<super_signature.arg_countraise"Your definition of `#{method_name}` must accept at least #{super_signature.arg_count} "\"positional arguments to be compatible with the method it #{mode_verb}: "\"#{base_override_loc_str(signature,super_signature)}"endif!signature.has_rest&&super_signature.has_restraise"Your definition of `#{method_name}` must have `*#{super_signature.rest_name}` "\"to be compatible with the method it #{mode_verb}: "\"#{base_override_loc_str(signature,super_signature)}"endifsignature.req_arg_count>super_signature.req_arg_countraise"Your definition of `#{method_name}` must have no more than #{super_signature.req_arg_count} "\"required argument(s) to be compatible with the method it #{mode_verb}: "\"#{base_override_loc_str(signature,super_signature)}"endif!signature.has_keyrest# O(nm), but n and m are tiny heremissing_kwargs=super_signature.kwarg_names-signature.kwarg_namesif!missing_kwargs.empty?raise"Your definition of `#{method_name}` is missing these keyword arg(s): #{missing_kwargs} "\"which are defined in the method it #{mode_verb}: "\"#{base_override_loc_str(signature,super_signature)}"endendif!signature.has_keyrest&&super_signature.has_keyrestraise"Your definition of `#{method_name}` must have `**#{super_signature.keyrest_name}` "\"to be compatible with the method it #{mode_verb}: "\"#{base_override_loc_str(signature,super_signature)}"end# O(nm), but n and m are tiny hereextra_req_kwargs=signature.req_kwarg_names-super_signature.req_kwarg_namesif!extra_req_kwargs.empty?raise"Your definition of `#{method_name}` has extra required keyword arg(s) "\"#{extra_req_kwargs} relative to the method it #{mode_verb}, making it incompatible: "\"#{base_override_loc_str(signature,super_signature)}"endifsuper_signature.block_name&&!signature.block_nameraise"Your definition of `#{method_name}` must accept a block parameter to be compatible "\"with the method it #{mode_verb}: "\"#{base_override_loc_str(signature,super_signature)}"endenddefself.validate_override_types(signature,super_signature)returnifsignature.override_allow_incompatiblereturnifsuper_signature.mode==Modes.untypedreturnunless[signature,super_signature].all?do|sig|sig.check_level==:always||sig.check_level==:compiled||(sig.check_level==:tests&&T::Private::RuntimeLevels.check_tests?)endmode_noun=super_signature.mode==Modes.abstract?'implementation':'override'# arg types must be contravariantsuper_signature.arg_types.zip(signature.arg_types).each_with_indexdo|((_super_name,super_type),(name,type)),index|if!super_type.subtype_of?(type)raise"Incompatible type for arg ##{index+1} (`#{name}`) in signature for #{mode_noun} of method "\"`#{signature.method_name}`:\n"\"* Base: `#{super_type}` (in #{method_loc_str(super_signature.method)})\n"\"* #{mode_noun.capitalize}: `#{type}` (in #{method_loc_str(signature.method)})\n"\"(The types must be contravariant.)"endend# kwarg types must be contravariantsuper_signature.kwarg_types.eachdo|name,super_type|type=signature.kwarg_types[name]if!super_type.subtype_of?(type)raise"Incompatible type for arg `#{name}` in signature for #{mode_noun} of method `#{signature.method_name}`:\n"\"* Base: `#{super_type}` (in #{method_loc_str(super_signature.method)})\n"\"* #{mode_noun.capitalize}: `#{type}` (in #{method_loc_str(signature.method)})\n"\"(The types must be contravariant.)"endend# return types must be covariantif!signature.return_type.subtype_of?(super_signature.return_type)raise"Incompatible return type in signature for #{mode_noun} of method `#{signature.method_name}`:\n"\"* Base: `#{super_signature.return_type}` (in #{method_loc_str(super_signature.method)})\n"\"* #{mode_noun.capitalize}: `#{signature.return_type}` (in #{method_loc_str(signature.method)})\n"\"(The types must be covariant.)"endendprivate_class_methoddefself.base_override_loc_str(signature,super_signature)mode_noun=super_signature.mode==Modes.abstract?'Implementation':'Override'"\n * Base definition: in #{method_loc_str(super_signature.method)}"\"\n * #{mode_noun}: in #{method_loc_str(signature.method)}"endprivate_class_methoddefself.method_loc_str(method)loc=ifmethod.source_locationmethod.source_location.join(':')else"<unknown location>"end"#{method.owner} at #{loc}"endend