Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -573,8 +573,11 @@ nodes:
fields:
- name: name
c_type: rbs_type_name
- name: args
c_type: rbs_node_list
locations:
- required: name
- optional: args
- name: RBS::Types::Function
rust_name: FunctionTypeNode
expose_location: false
Expand Down
25 changes: 13 additions & 12 deletions docs/syntax.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,17 @@
## Types

```markdown
_type_ ::= _class-name_ _type-arguments_ (Class instance type)
| _interface-name_ _type-arguments_ (Interface type)
| _alias-name_ _type-arguments_ (Alias type)
| `singleton(` _class-name_ `)` (Class singleton type)
| _literal_ (Literal type)
| _type_ `|` _type_ (Union type)
| _type_ `&` _type_ (Intersection type)
| _type_ `?` (Optional type)
| `{` _record-name_ `:` _type_ `,` etc. `}` (Record type)
| `[]` | `[` _type_ `,` etc. `]` (Tuples)
| _type-variable_ (Type variables)
_type_ ::= _class-name_ _type-arguments_ (Class instance type)
| _interface-name_ _type-arguments_ (Interface type)
| _alias-name_ _type-arguments_ (Alias type)
| `singleton(` _class-name_ `)` _type-arguments_ (Class singleton type)
| _literal_ (Literal type)
| _type_ `|` _type_ (Union type)
| _type_ `&` _type_ (Intersection type)
| _type_ `?` (Optional type)
| `{` _record-name_ `:` _type_ `,` etc. `}` (Record type)
| `[]` | `[` _type_ `,` etc. `]` (Tuples)
| _type-variable_ (Type variables)
| `self`
| `instance`
| `class`
Expand Down Expand Up @@ -85,7 +85,8 @@ Class singleton type denotes _the type of a singleton object of a class_.

```rbs
singleton(String)
singleton(::Hash) # Class singleton type cannot be parametrized.
singleton(::Hash) # Class singleton type
singleton(Array)[String] # Class singleton type with type application
```

### Literal type
Expand Down
4 changes: 3 additions & 1 deletion ext/rbs_extension/ast_translation.c
Original file line number Diff line number Diff line change
Expand Up @@ -1229,10 +1229,12 @@ VALUE rbs_struct_to_ruby_value(rbs_translation_context_t ctx, rbs_node_t *instan
VALUE h = rb_hash_new();
VALUE location = rbs_location_range_to_ruby_location(ctx, node->base.location);
rbs_loc *loc = rbs_check_location(location);
rbs_loc_legacy_alloc_children(loc, 1);
rbs_loc_legacy_alloc_children(loc, 2);
rbs_loc_legacy_add_required_child(loc, rb_intern("name"), (rbs_loc_range) { .start = node->name_range.start_char, .end = node->name_range.end_char });
rbs_loc_legacy_add_optional_child(loc, rb_intern("args"), (rbs_loc_range) { .start = node->args_range.start_char, .end = node->args_range.end_char });
rb_hash_aset(h, ID2SYM(rb_intern("location")), location);
rb_hash_aset(h, ID2SYM(rb_intern("name")), rbs_struct_to_ruby_value(ctx, (rbs_node_t *) node->name)); // rbs_type_name
rb_hash_aset(h, ID2SYM(rb_intern("args")), rbs_node_list_to_ruby_array(ctx, node->args));

return CLASS_NEW_INSTANCE(
RBS_Types_ClassSingleton,
Expand Down
4 changes: 3 additions & 1 deletion include/rbs/ast.h
Original file line number Diff line number Diff line change
Expand Up @@ -772,8 +772,10 @@ typedef struct rbs_types_class_singleton {
rbs_node_t base;

struct rbs_type_name *name;
struct rbs_node_list *args;

rbs_location_range name_range; /* Required */
rbs_location_range args_range; /* Optional */
} rbs_types_class_singleton_t;

typedef struct rbs_types_function {
Expand Down Expand Up @@ -947,7 +949,7 @@ rbs_types_bases_top_t *rbs_types_bases_top_new(rbs_allocator_t *allocator, rbs_l
rbs_types_bases_void_t *rbs_types_bases_void_new(rbs_allocator_t *allocator, rbs_location_range location);
rbs_types_block_t *rbs_types_block_new(rbs_allocator_t *allocator, rbs_location_range location, rbs_node_t *type, bool required, rbs_node_t *self_type);
rbs_types_class_instance_t *rbs_types_class_instance_new(rbs_allocator_t *allocator, rbs_location_range location, rbs_type_name_t *name, rbs_node_list_t *args, rbs_location_range name_range);
rbs_types_class_singleton_t *rbs_types_class_singleton_new(rbs_allocator_t *allocator, rbs_location_range location, rbs_type_name_t *name, rbs_location_range name_range);
rbs_types_class_singleton_t *rbs_types_class_singleton_new(rbs_allocator_t *allocator, rbs_location_range location, rbs_type_name_t *name, rbs_node_list_t *args, rbs_location_range name_range);
rbs_types_function_t *rbs_types_function_new(rbs_allocator_t *allocator, rbs_location_range location, rbs_node_list_t *required_positionals, rbs_node_list_t *optional_positionals, rbs_node_t *rest_positionals, rbs_node_list_t *trailing_positionals, rbs_hash_t *required_keywords, rbs_hash_t *optional_keywords, rbs_node_t *rest_keywords, rbs_node_t *return_type);
rbs_types_function_param_t *rbs_types_function_param_new(rbs_allocator_t *allocator, rbs_location_range location, rbs_node_t *type, rbs_ast_symbol_t *name);
rbs_types_interface_t *rbs_types_interface_new(rbs_allocator_t *allocator, rbs_location_range location, rbs_type_name_t *name, rbs_node_list_t *args, rbs_location_range name_range);
Expand Down
114 changes: 62 additions & 52 deletions lib/rbs/types.rb
Original file line number Diff line number Diff line change
Expand Up @@ -199,58 +199,6 @@ def with_nonreturn_void?
end
end

class ClassSingleton
attr_reader :name
attr_reader :location

def initialize(name:, location:)
@name = name
@location = location
end

def ==(other)
other.is_a?(ClassSingleton) && other.name == name
end

alias eql? ==

def hash
self.class.hash ^ name.hash
end

include NoFreeVariables
include NoSubst

def to_json(state = nil)
{ class: :class_singleton, name: name, location: location }.to_json(state)
end

def to_s(level = 0)
"singleton(#{name})"
end

include EmptyEachType

def map_type_name(&)
ClassSingleton.new(
name: yield(name, location, self),
location: location
)
end

def has_self_type?
false
end

def has_classish_type?
false
end

def with_nonreturn_void?
false
end
end

module Application
attr_reader :name
attr_reader :args
Expand Down Expand Up @@ -309,6 +257,68 @@ def with_nonreturn_void?
end
end

class ClassSingleton
attr_reader :location

include Application

def initialize(name:, location:, args: [])
@name = name
@location = location
@args = args
end

def ==(other)
other.is_a?(ClassSingleton) && other.name == name && other.args == args
end

alias eql? ==

def hash
self.class.hash ^ name.hash ^ args.hash
end

def sub(s)
return self if s.empty?

self.class.new(name: name,
args: args.map {|ty| ty.sub(s) },
location: location)
end

def to_json(state = _ = nil)
{ class: :class_singleton, name: name, args: args, location: location }.to_json(state)
end

def to_s(level = 0)
if args.empty?
"singleton(#{name})"
else
"singleton(#{name})[#{args.join(", ")}]"
end
end

def map_type_name(&block)
ClassSingleton.new(
name: yield(name, location, self),
args: args.map {|type| type.map_type_name(&block) },
location: location
)
end

def map_type(&block)
if block
ClassSingleton.new(
name: name,
args: args.map {|type| yield type },
location: location
)
else
enum_for :map_type
end
end
end

class Interface
attr_reader :location

Expand Down
18 changes: 10 additions & 8 deletions lib/rbs/unit_test/type_assertions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -256,15 +256,17 @@ def method_defs(method)
type, definition = target

case type
when Types::ClassInstance
subst = RBS::Substitution.build(definition.type_params, type.args)
definition.methods[method].defs.map do |type_def|
type_def.update(
type: type_def.type.sub(subst)
)
when Types::ClassInstance, Types::ClassSingleton
if type.is_a?(Types::ClassSingleton) && type.args.empty?
definition.methods[method].defs
else
subst = RBS::Substitution.build(definition.type_params, type.args)
definition.methods[method].defs.map do |type_def|
type_def.update(
type: type_def.type.sub(subst)
)
end
end
when Types::ClassSingleton
definition.methods[method].defs
else
raise
end
Expand Down
13 changes: 6 additions & 7 deletions sig/types.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -172,24 +172,23 @@ module RBS
class ClassSingleton
# singleton(::Foo)
# ^^^^^ => name
type loc = Location[:name, bot]

def initialize: (name: TypeName, location: loc?) -> void
type loc = Location[:name, :args]

attr_reader name: TypeName
def initialize: (name: TypeName, location: loc?, ?args: Array[t]) -> void

attr_reader location: loc?

include _TypeBase
include NoFreeVariables
include NoSubst
include EmptyEachType
include Application

def ==: (untyped other) -> bool

alias eql? ==

def hash: () -> Integer

def map_type: () { (t) -> t } -> ClassSingleton
| () -> Enumerator[t, ClassSingleton]
end

module Application
Expand Down
4 changes: 3 additions & 1 deletion src/ast.c
Original file line number Diff line number Diff line change
Expand Up @@ -1303,7 +1303,7 @@ rbs_types_class_instance_t *rbs_types_class_instance_new(rbs_allocator_t *alloca
return instance;
}
#line 140 "prism/templates/src/ast.c.erb"
rbs_types_class_singleton_t *rbs_types_class_singleton_new(rbs_allocator_t *allocator, rbs_location_range location, rbs_type_name_t *name, rbs_location_range name_range) {
rbs_types_class_singleton_t *rbs_types_class_singleton_new(rbs_allocator_t *allocator, rbs_location_range location, rbs_type_name_t *name, rbs_node_list_t *args, rbs_location_range name_range) {
rbs_types_class_singleton_t *instance = rbs_allocator_alloc(allocator, rbs_types_class_singleton_t);

*instance = (rbs_types_class_singleton_t) {
Expand All @@ -1312,7 +1312,9 @@ rbs_types_class_singleton_t *rbs_types_class_singleton_new(rbs_allocator_t *allo
.location = location,
},
.name = name,
.args = args,
.name_range = name_range,
.args_range = RBS_LOCATION_NULL_RANGE,
};

return instance;
Expand Down
25 changes: 21 additions & 4 deletions src/parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -1042,10 +1042,10 @@ static bool parse_instance_type(rbs_parser_t *parser, bool parse_alias, rbs_node
}

/*
singleton_type ::= {`singleton`} `(` type_name <`)`>
singleton_type ::= {`singleton`} `(` type_name <`)`> type_args?
*/
NODISCARD
static bool parse_singleton_type(rbs_parser_t *parser, rbs_types_class_singleton_t **singleton) {
static bool parse_singleton_type(rbs_parser_t *parser, rbs_types_class_singleton_t **singleton, bool self_allowed, bool classish_allowed) {
ASSERT_TOKEN(parser, kSINGLETON);

rbs_range_t type_range;
Expand All @@ -1058,9 +1058,26 @@ static bool parse_singleton_type(rbs_parser_t *parser, rbs_types_class_singleton
CHECK_PARSE(parse_type_name(parser, CLASS_NAME, &name_range, &type_name));

ADVANCE_ASSERT(parser, pRPAREN);

rbs_node_list_t *types = rbs_node_list_new(ALLOCATOR());

rbs_location_range args_range = RBS_LOCATION_NULL_RANGE;
if (parser->next_token.type == pLBRACKET) {
rbs_parser_advance(parser);
args_range.start_byte = parser->current_token.range.start.byte_pos;
args_range.start_char = parser->current_token.range.start.char_pos;
CHECK_PARSE(parse_type_list(parser, pRBRACKET, types, true, self_allowed, classish_allowed));
ADVANCE_ASSERT(parser, pRBRACKET);
args_range.end_byte = parser->current_token.range.end.byte_pos;
args_range.end_char = parser->current_token.range.end.char_pos;
}

type_range.end = parser->current_token.range.end;
rbs_location_range loc = RBS_RANGE_LEX2AST(type_range);

*singleton = rbs_types_class_singleton_new(ALLOCATOR(), loc, type_name, types, RBS_RANGE_LEX2AST(name_range));
(*singleton)->args_range = args_range;

*singleton = rbs_types_class_singleton_new(ALLOCATOR(), RBS_RANGE_LEX2AST(type_range), type_name, RBS_RANGE_LEX2AST(name_range));
return true;
}

Expand Down Expand Up @@ -1242,7 +1259,7 @@ static bool parse_simple(rbs_parser_t *parser, rbs_node_t **type, bool void_allo
}
case kSINGLETON: {
rbs_types_class_singleton_t *singleton = NULL;
CHECK_PARSE(parse_singleton_type(parser, &singleton));
CHECK_PARSE(parse_singleton_type(parser, &singleton, self_allowed, classish_allowed));
*type = (rbs_node_t *) singleton;
return true;
}
Expand Down
Loading