lib/rbs/environment.rb in rbs-3.0.0.dev.1 vs lib/rbs/environment.rb in rbs-3.0.0.dev.2

- old
+ new

@@ -4,19 +4,25 @@ class Environment attr_reader :declarations attr_reader :class_decls attr_reader :interface_decls - attr_reader :alias_decls + attr_reader :type_alias_decls attr_reader :constant_decls attr_reader :global_decls + attr_reader :class_alias_decls + attr_reader :buffer_directives module ContextUtil def calculate_context(decls) - decls.each.with_object([Namespace.root]) do |decl, array| - first = array.first or raise - array.unshift(first + decl.name.to_namespace) + decls.inject(nil) do |context, decl| #$ Resolver::context + if (_, last = context) + last or raise + [context, last + decl.name] + else + [nil, decl.name.absolute!] + end end end end class MultiEntry @@ -88,16 +94,10 @@ decls.first or raise("decls cannot be empty") end end end - def foo - a = [1].sample() - return unless a - a + 1 - end - class ClassEntry < MultiEntry def primary @primary ||= begin validate_type_params decls.find {|d| d.decl.super_class } || decls.first or raise("decls cannot be empty") @@ -117,57 +117,225 @@ end include ContextUtil def context - @context = calculate_context(outer) + @context ||= calculate_context(outer) end end + class ModuleAliasEntry < SingleEntry + end + + class ClassAliasEntry < SingleEntry + end + + class InterfaceEntry < SingleEntry + end + + class TypeAliasEntry < SingleEntry + end + + class ConstantEntry < SingleEntry + end + + class GlobalEntry < SingleEntry + end + def initialize @buffers = [] @declarations = [] @class_decls = {} @interface_decls = {} - @alias_decls = {} + @type_alias_decls = {} @constant_decls = {} @global_decls = {} + @class_alias_decls = {} + @normalize_module_name_cache = {} + @buffer_directives = {} end def initialize_copy(other) @buffers = other.buffers.dup @declarations = other.declarations.dup @class_decls = other.class_decls.dup @interface_decls = other.interface_decls.dup - @alias_decls = other.alias_decls.dup + @type_alias_decls = other.type_alias_decls.dup @constant_decls = other.constant_decls.dup @global_decls = other.global_decls.dup + @class_alias_decls = other.class_alias_decls.dup + @buffer_directives = other.buffer_directives.dup end def self.from_loader(loader) self.new.tap do |env| loader.load(env: env) end end - def cache_name(cache, name:, decl:, outer:) - if cache.key?(name) - raise DuplicatedDeclarationError.new(_ = name, _ = decl, _ = cache[name].decl) + def interface_name?(name) + interface_decls.key?(name) + end + + def type_alias_name?(name) + type_alias_decls.key?(name) + end + + def module_name?(name) + class_decls.key?(name) || class_alias_decls.key?(name) + end + + def type_name?(name) + interface_name?(name) || + type_alias_name?(name) || + module_name?(name) + end + + def constant_name?(name) + constant_decl?(name) || module_name?(name) + end + + def constant_decl?(name) + constant_decls.key?(name) + end + + def class_decl?(name) + class_decls[name].is_a?(ClassEntry) + end + + def module_decl?(name) + class_decls[name].is_a?(ModuleEntry) + end + + def module_alias?(name) + if decl = class_alias_decls[name] + decl.decl.is_a?(AST::Declarations::ModuleAlias) + else + false end + end - cache[name] = SingleEntry.new(name: name, decl: decl, outer: outer) + def class_alias?(name) + if decl = class_alias_decls[name] + decl.decl.is_a?(AST::Declarations::ClassAlias) + else + false + end end + def class_entry(type_name) + case + when (class_entry = class_decls[type_name]).is_a?(ClassEntry) + class_entry + when (class_alias = class_alias_decls[type_name]).is_a?(ClassAliasEntry) + class_alias + end + end + + def module_entry(type_name) + case + when (module_entry = class_decls[type_name]).is_a?(ModuleEntry) + module_entry + when (module_alias = class_alias_decls[type_name]).is_a?(ModuleAliasEntry) + module_alias + end + end + + def normalized_class_entry(type_name) + if name = normalize_module_name?(type_name) + case entry = class_entry(name) + when ClassEntry, nil + entry + when ClassAliasEntry + raise + end + end + end + + def normalized_module_entry(type_name) + if name = normalize_module_name?(type_name) + case entry = module_entry(name) + when ModuleEntry, nil + entry + when ModuleAliasEntry + raise + end + end + end + + def module_class_entry(type_name) + class_entry(type_name) || module_entry(type_name) + end + + def normalized_module_class_entry(type_name) + normalized_class_entry(type_name) || normalized_module_entry(type_name) + end + + def constant_entry(type_name) + class_entry(type_name) || module_entry(type_name) || constant_decls[type_name] + end + + def normalize_module_name(name) + normalize_module_name?(name) or name + end + + def normalize_module_name?(name) + raise "Class/module name is expected: #{name}" unless name.class? + name = name.absolute! if name.relative! + + if @normalize_module_name_cache.key?(name) + return @normalize_module_name_cache[name] + end + + @normalize_module_name_cache[name] = false + + entry = constant_entry(name) + case entry + when ClassEntry, ModuleEntry + @normalize_module_name_cache[name] = entry.name + entry.name + + when ClassAliasEntry, ModuleAliasEntry + old_name = entry.decl.old_name + if old_name.namespace.empty? + @normalize_module_name_cache[name] = normalize_module_name?(old_name) + else + parent = old_name.namespace.to_type_name + + if normalized_parent = normalize_module_name?(parent) + @normalize_module_name_cache[name] = + if normalized_parent == parent + normalize_module_name?(old_name) + else + normalize_module_name?( + TypeName.new(name: old_name.name, namespace: normalized_parent.to_namespace) + ) + end + else + @normalize_module_name_cache[name] = nil + end + end + + when ConstantEntry + raise "#{name} is a constant name" + + else + @normalize_module_name_cache[name] = nil + end + end + def insert_decl(decl, outer:, namespace:) case decl when AST::Declarations::Class, AST::Declarations::Module name = decl.name.with_prefix(namespace) - if constant_decls.key?(name) - raise DuplicatedDeclarationError.new(name, decl, constant_decls[name].decl) + if cdecl = constant_entry(name) + if cdecl.is_a?(ConstantEntry) || cdecl.is_a?(ModuleAliasEntry) || cdecl.is_a?(ClassAliasEntry) + raise DuplicatedDeclarationError.new(name, decl, cdecl.decl) + end end unless class_decls.key?(name) case decl when AST::Declarations::Class @@ -179,16 +347,12 @@ existing_entry = class_decls[name] case when decl.is_a?(AST::Declarations::Module) && existing_entry.is_a?(ModuleEntry) - # @type var existing_entry: ModuleEntry - # @type var decl: AST::Declarations::Module existing_entry.insert(decl: decl, outer: outer) when decl.is_a?(AST::Declarations::Class) && existing_entry.is_a?(ClassEntry) - # @type var existing_entry: ClassEntry - # @type var decl: AST::Declarations::Class existing_entry.insert(decl: decl, outer: outer) else raise DuplicatedDeclarationError.new(name, decl, existing_entry.decls[0].decl) end @@ -197,95 +361,176 @@ decl.each_decl do |d| insert_decl(d, outer: prefix, namespace: ns) end when AST::Declarations::Interface - cache_name interface_decls, name: decl.name.with_prefix(namespace), decl: decl, outer: outer + name = decl.name.with_prefix(namespace) - when AST::Declarations::Alias - cache_name alias_decls, name: decl.name.with_prefix(namespace), decl: decl, outer: outer + if interface_entry = interface_decls[name] + DuplicatedDeclarationError.new(name, decl, interface_entry.decl) + end + interface_decls[name] = InterfaceEntry.new(name: name, decl: decl, outer: outer) + + when AST::Declarations::TypeAlias + name = decl.name.with_prefix(namespace) + + if entry = type_alias_decls[name] + DuplicatedDeclarationError.new(name, decl, entry.decl) + end + + type_alias_decls[name] = TypeAliasEntry.new(name: name, decl: decl, outer: outer) + when AST::Declarations::Constant name = decl.name.with_prefix(namespace) - if class_decls.key?(name) - raise DuplicatedDeclarationError.new(name, decl, class_decls[name].decls[0].decl) + if entry = constant_entry(name) + case entry + when ClassAliasEntry, ModuleAliasEntry, ConstantEntry + raise DuplicatedDeclarationError.new(name, decl, entry.decl) + when ClassEntry, ModuleEntry + raise DuplicatedDeclarationError.new(name, decl, *entry.decls.map(&:decl)) + end end - cache_name constant_decls, name: name, decl: decl, outer: outer + constant_decls[name] = ConstantEntry.new(name: name, decl: decl, outer: outer) when AST::Declarations::Global - cache_name global_decls, name: decl.name, decl: decl, outer: outer + if entry = global_decls[decl.name] + raise DuplicatedDeclarationError.new(name, decl, entry.decl) + end + + global_decls[decl.name] = GlobalEntry.new(name: decl.name, decl: decl, outer: outer) + + when AST::Declarations::ClassAlias, AST::Declarations::ModuleAlias + name = decl.new_name.with_prefix(namespace) + + if entry = constant_entry(name) + case entry + when ClassAliasEntry, ModuleAliasEntry, ConstantEntry + raise DuplicatedDeclarationError.new(name, decl, entry.decl) + when ClassEntry, ModuleEntry + raise DuplicatedDeclarationError.new(name, decl, *entry.decls.map(&:decl)) + end + end + + case decl + when AST::Declarations::ClassAlias + class_alias_decls[name] = ClassAliasEntry.new(name: name, decl: decl, outer: outer) + when AST::Declarations::ModuleAlias + class_alias_decls[name] = ModuleAliasEntry.new(name: name, decl: decl, outer: outer) + end end end def <<(decl) declarations << decl insert_decl(decl, outer: [], namespace: Namespace.root) self end + def add_signature(buffer:, directives:, decls:) + buffer_directives[buffer] = directives + decls.each do |decl| + self << decl + end + end + def validate_type_params class_decls.each_value do |decl| decl.primary end end def resolve_type_names(only: nil) - resolver = TypeNameResolver.from_env(self) - env = Environment.new() + resolver = Resolver::TypeNameResolver.new(self) + env = Environment.new - declarations.each do |decl| - if only && !only.member?(decl) - env << decl - else - env << resolve_declaration(resolver, decl, outer: [], prefix: Namespace.root) + table = UseMap::Table.new() + table.known_types.merge(class_decls.keys) + table.known_types.merge(class_alias_decls.keys) + table.known_types.merge(type_alias_decls.keys) + table.known_types.merge(interface_decls.keys) + table.compute_children + + buffers_decls.each do |buffer, decls| + dirs = buffer_directives.fetch(buffer) + + map = UseMap.new(table: table) + dirs.each do |dir| + dir.clauses.each do |clause| + map.build_map(clause) + end end + + decls = decls.map do |decl| + if only && !only.member?(decl) + decl + else + resolve_declaration(resolver, map, decl, outer: [], prefix: Namespace.root) + end + end + + env.add_signature(buffer: buffer, directives: dirs, decls: decls) end env end - def resolve_declaration(resolver, decl, outer:, prefix:) + def resolver_context(*nesting) + nesting.inject(nil) {|context, decl| #$ Resolver::context + append_context(context, decl) + } + end + + def append_context(context, decl) + if (_, last = context) + last or raise + [context, last + decl.name] + else + [nil, decl.name.absolute!] + end + end + + def resolve_declaration(resolver, map, decl, outer:, prefix:) if decl.is_a?(AST::Declarations::Global) # @type var decl: AST::Declarations::Global return AST::Declarations::Global.new( name: decl.name, - type: absolute_type(resolver, decl.type, context: [Namespace.root]), + type: absolute_type(resolver, map, decl.type, context: nil), location: decl.location, comment: decl.comment ) end - context = (outer + [decl]).each.with_object([Namespace.root]) do |decl, array| - head = array.first or raise - array.unshift(head + decl.name.to_namespace) - end + context = resolver_context(*outer) - outer_context = context.drop(1) - case decl when AST::Declarations::Class + outer_context = context + inner_context = append_context(outer_context, decl) + outer_ = outer + [decl] prefix_ = prefix + decl.name.to_namespace AST::Declarations::Class.new( name: decl.name.with_prefix(prefix), - type_params: resolve_type_params(resolver, decl.type_params, context: context), + type_params: resolve_type_params(resolver, map, decl.type_params, context: inner_context), super_class: decl.super_class&.yield_self do |super_class| AST::Declarations::Class::Super.new( - name: absolute_type_name(resolver, super_class.name, context: outer_context), - args: super_class.args.map {|type| absolute_type(resolver, type, context: outer_context) }, + name: absolute_type_name(resolver, map, super_class.name, context: outer_context), + args: super_class.args.map {|type| absolute_type(resolver, map, type, context: outer_context) }, location: super_class.location ) end, members: decl.members.map do |member| case member when AST::Members::Base - resolve_member(resolver, member, context: context) + resolve_member(resolver, map, member, context: inner_context) when AST::Declarations::Base resolve_declaration( resolver, + map, member, outer: outer_, prefix: prefix_ ) else @@ -294,30 +539,35 @@ end, location: decl.location, annotations: decl.annotations, comment: decl.comment ) + when AST::Declarations::Module + outer_context = context + inner_context = append_context(outer_context, decl) + outer_ = outer + [decl] prefix_ = prefix + decl.name.to_namespace AST::Declarations::Module.new( name: decl.name.with_prefix(prefix), - type_params: resolve_type_params(resolver, decl.type_params, context: context), + type_params: resolve_type_params(resolver, map, decl.type_params, context: inner_context), self_types: decl.self_types.map do |module_self| AST::Declarations::Module::Self.new( - name: absolute_type_name(resolver, module_self.name, context: context), - args: module_self.args.map {|type| absolute_type(resolver, type, context: context) }, + name: absolute_type_name(resolver, map, module_self.name, context: inner_context), + args: module_self.args.map {|type| absolute_type(resolver, map, type, context: inner_context) }, location: module_self.location ) end, members: decl.members.map do |member| case member when AST::Members::Base - resolve_member(resolver, member, context: context) + resolve_member(resolver, map, member, context: inner_context) when AST::Declarations::Base resolve_declaration( resolver, + map, member, outer: outer_, prefix: prefix_ ) else @@ -326,50 +576,68 @@ end, location: decl.location, annotations: decl.annotations, comment: decl.comment ) + when AST::Declarations::Interface AST::Declarations::Interface.new( name: decl.name.with_prefix(prefix), - type_params: resolve_type_params(resolver, decl.type_params, context: context), + type_params: resolve_type_params(resolver, map, decl.type_params, context: context), members: decl.members.map do |member| - resolve_member(resolver, member, context: context) + resolve_member(resolver, map, member, context: context) end, comment: decl.comment, location: decl.location, annotations: decl.annotations ) - when AST::Declarations::Alias - AST::Declarations::Alias.new( + + when AST::Declarations::TypeAlias + AST::Declarations::TypeAlias.new( name: decl.name.with_prefix(prefix), - type_params: resolve_type_params(resolver, decl.type_params, context: context), - type: absolute_type(resolver, decl.type, context: context), + type_params: resolve_type_params(resolver, map, decl.type_params, context: context), + type: absolute_type(resolver, map, decl.type, context: context), location: decl.location, annotations: decl.annotations, comment: decl.comment ) when AST::Declarations::Constant AST::Declarations::Constant.new( name: decl.name.with_prefix(prefix), - type: absolute_type(resolver, decl.type, context: context), + type: absolute_type(resolver, map, decl.type, context: context), location: decl.location, comment: decl.comment ) + + when AST::Declarations::ClassAlias + AST::Declarations::ClassAlias.new( + new_name: decl.new_name.with_prefix(prefix), + old_name: absolute_type_name(resolver, map, decl.old_name, context: context), + location: decl.location, + comment: decl.comment + ) + + when AST::Declarations::ModuleAlias + AST::Declarations::ModuleAlias.new( + new_name: decl.new_name.with_prefix(prefix), + old_name: absolute_type_name(resolver, map, decl.old_name, context: context), + location: decl.location, + comment: decl.comment + ) end end - def resolve_member(resolver, member, context:) + def resolve_member(resolver, map, member, context:) case member when AST::Members::MethodDefinition AST::Members::MethodDefinition.new( name: member.name, kind: member.kind, overloads: member.overloads.map do |overload| overload.update( - method_type: resolve_method_type(resolver, overload.method_type, context: context) + method_type: resolve_method_type(resolver, map, overload.method_type, context: context) ) end, comment: member.comment, overloading: member.overloading?, annotations: member.annotations, @@ -377,115 +645,116 @@ visibility: member.visibility ) when AST::Members::AttrAccessor AST::Members::AttrAccessor.new( name: member.name, - type: absolute_type(resolver, member.type, context: context), + type: absolute_type(resolver, map, member.type, context: context), kind: member.kind, annotations: member.annotations, comment: member.comment, location: member.location, ivar_name: member.ivar_name, visibility: member.visibility ) when AST::Members::AttrReader AST::Members::AttrReader.new( name: member.name, - type: absolute_type(resolver, member.type, context: context), + type: absolute_type(resolver, map, member.type, context: context), kind: member.kind, annotations: member.annotations, comment: member.comment, location: member.location, ivar_name: member.ivar_name, visibility: member.visibility ) when AST::Members::AttrWriter AST::Members::AttrWriter.new( name: member.name, - type: absolute_type(resolver, member.type, context: context), + type: absolute_type(resolver, map, member.type, context: context), kind: member.kind, annotations: member.annotations, comment: member.comment, location: member.location, ivar_name: member.ivar_name, visibility: member.visibility ) when AST::Members::InstanceVariable AST::Members::InstanceVariable.new( name: member.name, - type: absolute_type(resolver, member.type, context: context), + type: absolute_type(resolver, map, member.type, context: context), comment: member.comment, location: member.location ) when AST::Members::ClassInstanceVariable AST::Members::ClassInstanceVariable.new( name: member.name, - type: absolute_type(resolver, member.type, context: context), + type: absolute_type(resolver, map, member.type, context: context), comment: member.comment, location: member.location ) when AST::Members::ClassVariable AST::Members::ClassVariable.new( name: member.name, - type: absolute_type(resolver, member.type, context: context), + type: absolute_type(resolver, map, member.type, context: context), comment: member.comment, location: member.location ) when AST::Members::Include AST::Members::Include.new( - name: absolute_type_name(resolver, member.name, context: context), - args: member.args.map {|type| absolute_type(resolver, type, context: context) }, + name: absolute_type_name(resolver, map, member.name, context: context), + args: member.args.map {|type| absolute_type(resolver, map, type, context: context) }, comment: member.comment, location: member.location, annotations: member.annotations ) when AST::Members::Extend AST::Members::Extend.new( - name: absolute_type_name(resolver, member.name, context: context), - args: member.args.map {|type| absolute_type(resolver, type, context: context) }, + name: absolute_type_name(resolver, map, member.name, context: context), + args: member.args.map {|type| absolute_type(resolver, map, type, context: context) }, comment: member.comment, location: member.location, annotations: member.annotations ) when AST::Members::Prepend AST::Members::Prepend.new( - name: absolute_type_name(resolver, member.name, context: context), - args: member.args.map {|type| absolute_type(resolver, type, context: context) }, + name: absolute_type_name(resolver, map, member.name, context: context), + args: member.args.map {|type| absolute_type(resolver, map, type, context: context) }, comment: member.comment, location: member.location, annotations: member.annotations ) else member end end - def resolve_method_type(resolver, type, context:) + def resolve_method_type(resolver, map, type, context:) type.map_type do |ty| - absolute_type(resolver, ty, context: context) + absolute_type(resolver, map, ty, context: context) end.map_type_bound do |bound| - _ = absolute_type(resolver, bound, context: context) + _ = absolute_type(resolver, map, bound, context: context) end end - def resolve_type_params(resolver, params, context:) + def resolve_type_params(resolver, map, params, context:) params.map do |param| - param.map_type {|type| _ = absolute_type(resolver, type, context: context) } + param.map_type {|type| _ = absolute_type(resolver, map, type, context: context) } end end - def absolute_type_name(resolver, type_name, context:) + def absolute_type_name(resolver, map, type_name, context:) + type_name = map.resolve(type_name) resolver.resolve(type_name, context: context) || type_name end - def absolute_type(resolver, type, context:) + def absolute_type(resolver, map, type, context:) type.map_type_name do |name, _, _| - absolute_type_name(resolver, name, context: context) + absolute_type_name(resolver, map, name, context: context) end end def inspect - ivars = %i[@declarations @class_decls @interface_decls @alias_decls @constant_decls @global_decls] + ivars = %i[@declarations @class_decls @class_alias_decls @interface_decls @type_alias_decls @constant_decls @global_decls] "\#<RBS::Environment #{ivars.map { |iv| "#{iv}=(#{instance_variable_get(iv).size} items)"}.join(' ')}>" end def buffers buffers_decls.keys.compact