lib/tapioca/compilers/symbol_table/symbol_generator.rb in tapioca-0.6.1 vs lib/tapioca/compilers/symbol_table/symbol_generator.rb in tapioca-0.6.2
- old
+ new
@@ -139,11 +139,10 @@
sig { params(tree: RBI::Tree, name: String, value: BasicObject).void.checked(:never) }
def compile_object(tree, name, value)
return if symbol_ignored?(name)
klass = class_of(value)
- return if klass == TypeMember || klass == TypeTemplate
klass_name = if klass == ObjectSpace::WeakMap
# WeakMap is an implicit generic with one type variable
"ObjectSpace::WeakMap[T.untyped]"
elsif T::Generic === klass
@@ -170,10 +169,11 @@
end
sig { params(tree: RBI::Tree, name: String, constant: Module).void }
def compile_module(tree, name, constant)
return unless defined_in_gem?(constant, strict: false)
+ return if Tapioca::TypeVariableModule === constant
comments = documentation_comments(name)
scope =
if constant.is_a?(Class)
superclass = compile_superclass(constant)
@@ -280,34 +280,20 @@
def compile_type_variable_declarations(tree, constant)
# Try to find the type variables defined on this constant, bail if we can't
type_variables = GenericTypeRegistry.lookup_type_variables(constant)
return unless type_variables
- # Create a map of subconstants (via their object ids) to their names.
- # We need this later when we want to lookup the name of the registered type
- # variable via the value of the type variable constant.
- subconstant_to_name_lookup = constants_of(constant)
- .each_with_object({}.compare_by_identity) do |constant_name, table|
- table[constantize(constant_name.to_s, namespace: constant)] = constant_name.to_s
- end
-
# Map each type variable to its string representation.
#
- # Each entry of `type_variables` maps an object_id to a String,
+ # Each entry of `type_variables` maps a Module to a String,
# and the order they are inserted into the hash is the order they should be
# defined in the source code.
- #
- # By looping over these entries and then getting the actual constant name
- # from the `subconstant_to_name_lookup` we defined above, gives us all the
- # information we need to serialize type variable definitions.
- type_variable_declarations = type_variables.map do |type_variable, serialized_type_variable|
- constant_name = subconstant_to_name_lookup[type_variable]
- type_variable.name = constant_name
- # Here, we know that constant_value will be an instance of
- # T::Types::CustomTypeVariable, which knows how to serialize
- # itself to a type_member/type_template
- tree << RBI::TypeMember.new(constant_name, serialized_type_variable)
+ type_variable_declarations = type_variables.map do |type_variable|
+ type_variable_name = type_variable.name
+ next unless type_variable_name
+
+ tree << RBI::TypeMember.new(type_variable_name, type_variable.serialize)
end
return if type_variable_declarations.empty?
tree << RBI::Extend.new("T::Generic")
@@ -390,11 +376,11 @@
def add_mixins(tree, mods, mixin_type)
mods
.select do |mod|
name = name_of(mod)
- name && !name.start_with?("T::")
+ name && !filtered_mixin?(name)
end
.map do |mod|
add_to_symbol_queue(name_of(mod))
qname = qualified_name_of(mod)
@@ -494,11 +480,13 @@
parameters = T.let(method.parameters, T::Array[[Symbol, T.nilable(Symbol)]])
sanitized_parameters = parameters.each_with_index.map do |(type, name), index|
fallback_arg_name = "_arg#{index}"
- unless name
+ name = if name
+ name.to_s
+ else
# For attr_writer methods, Sorbet signatures have the name
# of the method (without the trailing = sign) as the name of
# the only parameter. So, if the parameter does not have a name
# then the replacement name should be the name of the method
# (minus trailing =) if and only if there is a signature for the
@@ -510,19 +498,19 @@
parameters.size == 1 &&
signature.arg_types.size == 1 &&
method_name[-1] == "="
)
- name = if writer_method_with_sig
- T.must(method_name[0...-1]).to_sym
+ if writer_method_with_sig
+ method_name.delete_suffix("=")
else
fallback_arg_name
end
end
# Sanitize param names
- name = name.to_s.gsub(/[^a-zA-Z0-9_]/, fallback_arg_name)
+ name = fallback_arg_name unless valid_parameter_name?(name)
[type, name]
end
separator = constant.singleton_class? ? "." : "#"
@@ -611,18 +599,30 @@
sig { params(symbol_name: String).returns(T::Boolean) }
def symbol_ignored?(symbol_name)
SymbolLoader.ignore_symbol?(symbol_name)
end
+ sig { params(mixin_name: String).returns(T::Boolean) }
+ def filtered_mixin?(mixin_name)
+ # filter T:: namespace mixins that aren't T::Props
+ # T::Props and subconstants have semantic value
+ mixin_name.start_with?("T::") && !mixin_name.start_with?("T::Props")
+ end
+
SPECIAL_METHOD_NAMES = T.let([
"!", "~", "+@", "**", "-@", "*", "/", "%", "+", "-", "<<", ">>", "&", "|", "^",
"<", "<=", "=>", ">", ">=", "==", "===", "!=", "=~", "!~", "<=>", "[]", "[]=", "`"
], T::Array[String])
sig { params(name: String).returns(T::Boolean) }
def valid_method_name?(name)
return true if SPECIAL_METHOD_NAMES.include?(name)
!!name.match(/^[[:word:]]+[?!=]?$/)
+ end
+
+ sig { params(name: String).returns(T::Boolean) }
+ def valid_parameter_name?(name)
+ name.match?(/^[[[:alnum:]]_]+$/)
end
sig { params(method: UnboundMethod).returns(T::Boolean) }
def method_in_gem?(method)
source_location = method.source_location&.first