Skip to content

Commit

Permalink
TMP arg parsing
Browse files Browse the repository at this point in the history
Signed-off-by: Alexandre Terrasa <[email protected]>
  • Loading branch information
Morriar committed Dec 3, 2024
1 parent 5f4bdf0 commit ae2ad1f
Show file tree
Hide file tree
Showing 6 changed files with 145 additions and 62 deletions.
30 changes: 9 additions & 21 deletions docs/rbs_support.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
* Alias types
* Literal types
* Boolish
* class -> T::Class[CurrentClass]

# Generics types

Expand All @@ -14,35 +15,22 @@ We automatically translate `Array`, `Hash`, to their `T::` counterparts.

## TODO

// Test comments parsing
// test sigs (attributes, methods, const?)

// - Translate `rbi` gems signatures to RBS for methods
// - Handle required positional args
// - Handle optional positional args
// - Handle required keyword args
// - Handle optional keyword args
// - Handle rest args
// - Handle keyword rest args
// - Handle block args
// - Handle type params
// - Handle return types
// - Handle block binding
// - tests

// - Handle types
* Proc types: Self binding
* Generic methods: Type variales

* class -> T::Class[CurrentClass]
// - tests method sigs
// - Handle block self binding
// - Generic methods: Type variales

// Test comments parsing
// attribute sigs + tests
// const sigs?
// Inline annotations? #: Type

// - Remove unnessary `to_s` calls?
// - Translate attributes
// - Handle errors
// test errors
// - Handle abstract, interface, final, sealed, mixes_in, overrides, required_ancestors


// - Pass `tc` on `rbi`
// - Clean how we depend on `rbs_parser`
// - Remove rbs parser dependency on ruby_vm
105 changes: 75 additions & 30 deletions rbs/MethodTypeTranslator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -70,67 +70,112 @@ sorbet::ast::ExpressionPtr MethodTypeTranslator::toRBI(core::MutableContext ctx,
VALUE optionalPositionalsValue = rb_funcall(functionType, rb_intern("optional_positionals"), 0);
VALUE restPositionalsValue = rb_funcall(functionType, rb_intern("rest_positionals"), 0);
VALUE requiredKeywordsValue = rb_funcall(functionType, rb_intern("required_keywords"), 0);
// VALUE optionalKeywordsValue = rb_funcall(functionType, rb_intern("optional_keywords"), 0);
// VALUE restKeywordsValue = rb_funcall(functionType, rb_intern("rest_keywords"), 0);
// VALUE blockValue = rb_funcall(functionType, rb_intern("block"), 0);
VALUE optionalKeywordsValue = rb_funcall(functionType, rb_intern("optional_keywords"), 0);
VALUE restKeywordsValue = rb_funcall(functionType, rb_intern("rest_keywords"), 0);
VALUE blockValue = rb_funcall(methodType, rb_intern("block"), 0);

Send::ARGS_store sigArgs;
auto argIndex = 0;

for (int i = 0; i < methodDef->args.size(); i++) {
auto &methodArg = methodDef->args[i];

core::NameRef argName;
VALUE arg;
ast::ExpressionPtr argType;

// std::cout << "ARG: " << methodArg.showRaw(ctx) << std::endl;

auto requiredPositionalsIndex = 0;
auto optionalPositionalsIndex = 0;
auto requiredKeywordsIndex = 0;
typecase(
methodArg,
[&](const ast::UnresolvedIdent &p) {
argName = p.name;
arg = rb_ary_entry(requiredPositionalsValue, requiredPositionalsIndex);
auto argValue = rb_ary_entry(requiredPositionalsValue, requiredPositionalsIndex);
argType = TypeTranslator::toRBI(ctx, rb_funcall(argValue, rb_intern("type"), 0), methodArg.loc());
requiredPositionalsIndex++;
},
[&](const ast::OptionalArg &p) {
},
[&](const ast::OptionalArg &p) {
typecase(
p.expr,
[&](const ast::UnresolvedIdent &p) {
argName = p.name;
auto argValue = rb_ary_entry(optionalPositionalsValue, optionalPositionalsIndex);
argType = ast::MK::Nilable(methodArg.loc(),
TypeTranslator::toRBI(ctx, rb_funcall(argValue, rb_intern("type"), 0), methodArg.loc()));
optionalPositionalsIndex++;
},
[&](const ast::KeywordArg &p) {
auto argIdent = ast::cast_tree<ast::UnresolvedIdent>(p.expr);
if(argIdent != nullptr) {
argName = argIdent->name;
VALUE key = ID2SYM(rb_intern(argName.show(ctx).c_str()));
auto argValue = rb_hash_aref(optionalKeywordsValue, key);
argType = ast::MK::Nilable(methodArg.loc(),
TypeTranslator::toRBI(ctx, rb_funcall(argValue, rb_intern("type"), 0), methodArg.loc()));
}
},
[&](const ast::ExpressionPtr &p) {
std::cout << "UNKNOWN EXPRESSION " << p.showRaw(ctx) << std::endl;
}
);
},
[&](const ast::RestArg &p) {
typecase(
p.expr,
[&](const ast::UnresolvedIdent &p) {
argName = p.name;
argType = TypeTranslator::toRBI(ctx, rb_funcall(restPositionalsValue, rb_intern("type"), 0), methodArg.loc());
},
[&](const ast::KeywordArg &p) {
auto argIdent = ast::cast_tree<ast::UnresolvedIdent>(p.expr);
if(argIdent != nullptr) {
argName = argIdent->name;
argType = TypeTranslator::toRBI(ctx, rb_funcall(restKeywordsValue, rb_intern("type"), 0), methodArg.loc());
}
},
[&](const ast::ExpressionPtr &p) {
std::cout << "UNKNOWN EXPRESSION " << p.showRaw(ctx) << std::endl;
}
);
},
// TODO: Access the hash
[&](const ast::KeywordArg &p) {
auto argIdent = ast::cast_tree<ast::UnresolvedIdent>(p.expr);
if(argIdent != nullptr) {
argName = argIdent->name;
VALUE key = ID2SYM(rb_intern(argName.show(ctx).c_str()));
auto argValue = rb_hash_aref(requiredKeywordsValue, key);
argType = TypeTranslator::toRBI(ctx, rb_funcall(argValue, rb_intern("type"), 0), methodArg.loc());
}
arg = rb_ary_entry(optionalPositionalsValue, optionalPositionalsIndex);
optionalPositionalsIndex++;
},
[&](const ast::RestArg &p) {
},
[&](const ast::BlockArg &p) {
auto argIdent = ast::cast_tree<ast::UnresolvedIdent>(p.expr);
if(argIdent != nullptr) {
argName = argIdent->name;
}
arg = restPositionalsValue;
},
// [&](const ast::KeywordArg &p) {
// auto argIdent = ast::cast_tree<ast::UnresolvedIdent>(p.expr);
// if(argIdent != nullptr) {
// argName = argIdent->name;
// }
// arg = rb_ary_entry(requiredKeywordsValue, requiredKeywordsIndex);
// requiredKeywordsIndex++;
// },
[&](const ast::ExpressionPtr &p) {
if (blockValue != Qnil) {
argType = TypeTranslator::toRBI(ctx, rb_funcall(blockValue, rb_intern("type"), 0), methodArg.loc());
}
},
[&](const ast::ExpressionPtr &p) {
std::cout << "UNKNOWN EXPRESSION " << p.showRaw(ctx) << std::endl;
}
}
);

if (argType == nullptr) {
// std::cout << "NIL ARG: " << methodArg.showRaw(ctx) << std::endl;
continue;
}

if (!argName.exists()) {
std::cout << "MISSING ARG NAME: " << argIndex << std::endl;
std::cout << "MISSING ARG NAME: " << methodArg.showRaw(ctx) << std::endl;
// TODO raise error
continue;
} else {
// std::cout << "ARG NAME: " << argName.show(ctx) << std::endl;
}

sigArgs.emplace_back(ast::MK::Symbol(methodArg.loc(), argName));

VALUE argType = rb_funcall(arg, rb_intern("type"), 0);
sigArgs.emplace_back(TypeTranslator::toRBI(ctx, argType, methodArg.loc()));
sigArgs.emplace_back(std::move(argType));
}

//visitParameterList(parameterList);
Expand Down
19 changes: 11 additions & 8 deletions rbs/TypeTranslator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -116,10 +116,9 @@ sorbet::ast::ExpressionPtr voidType(core::MutableContext ctx, VALUE type, core::
return ast::MK::UnresolvedConstant(loc, std::move(cStatic), core::Names::Constants::Void());
}

sorbet::ast::ExpressionPtr procType(core::MutableContext ctx, VALUE type, core::LocOffsets loc) {
VALUE typeValue = rb_funcall(type, rb_intern("type"), 0);
VALUE requiredPositionalsValue = rb_funcall(typeValue, rb_intern("required_positionals"), 0);
VALUE returnValue = rb_funcall(typeValue, rb_intern("return_type"), 0);
sorbet::ast::ExpressionPtr functionType(core::MutableContext ctx, VALUE type, core::LocOffsets loc) {
VALUE requiredPositionalsValue = rb_funcall(type, rb_intern("required_positionals"), 0);
VALUE returnValue = rb_funcall(type, rb_intern("return_type"), 0);
auto returnType = TypeTranslator::toRBI(ctx, returnValue, loc);


Expand All @@ -134,12 +133,14 @@ sorbet::ast::ExpressionPtr procType(core::MutableContext ctx, VALUE type, core::
paramsStore.emplace_back(std::move(innerType));
}

// auto block = ast::MK::Block(loc, ast::MK::Self(loc));
// auto blockSig = ast::MK::Sig(loc, std::move(paramsStore), std::move(returnType));

return ast::MK::T_Proc(loc, std::move(paramsStore), std::move(returnType));
}

sorbet::ast::ExpressionPtr procType(core::MutableContext ctx, VALUE type, core::LocOffsets loc) {
VALUE typeValue = rb_funcall(type, rb_intern("type"), 0);
return functionType(ctx, typeValue, loc);
}

sorbet::ast::ExpressionPtr tupleType(core::MutableContext ctx, VALUE type, core::LocOffsets loc) {
VALUE types = rb_funcall(type, rb_intern("types"), 0);
auto typesStore = Array::ENTRY_store();
Expand Down Expand Up @@ -180,7 +181,7 @@ sorbet::ast::ExpressionPtr recordType(core::MutableContext ctx, VALUE type, core
} // namespace

sorbet::ast::ExpressionPtr TypeTranslator::toRBI(core::MutableContext ctx, VALUE type, core::LocOffsets loc) {
rb_p(type);
// rb_p(type);
const char* className = rb_obj_classname(type);
// TODO: handle errors

Expand Down Expand Up @@ -215,6 +216,8 @@ sorbet::ast::ExpressionPtr TypeTranslator::toRBI(core::MutableContext ctx, VALUE
return voidType(ctx, type, loc);
case hash("RBS::Types::Proc"):
return procType(ctx, type, loc);
case hash("RBS::Types::Function"):
return functionType(ctx, type, loc);
case hash("RBS::Types::Tuple"):
return tupleType(ctx, type, loc);
case hash("RBS::Types::Record"):
Expand Down
18 changes: 16 additions & 2 deletions test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,24 @@

extend T::Sig

sig { params(p1: Integer, p2: T.nilable(String), p3: String, p4: Integer, p5: T.nilable(String), p6: Integer, block: T.proc.void).void }
module P1; end
module P2; end
module P3; end
module P4; end
module P5; end
module P6; end

sig { params(p1: P1, p2: T.nilable(P2), p3: P3, p4: P4, p5: T.nilable(P5), p6: P6, block: T.proc.void).void }
def bar(p1, p2 = nil, *p3, p4:, p5: nil, **p6, &block)
end

#: (Integer, ?String, *String, p4: Integer, ?p5: String, **Integer) { -> void } -> void
#: (P1, ?P2, *P3, p4: P4, ?p5: P5, **P6) { -> void } -> void
def foo(p1, p2 = nil, *p3, p4:, p5: nil, **p6, &block)
T.reveal_type(p1)
T.reveal_type(p2)
T.reveal_type(p3)
T.reveal_type(p4)
T.reveal_type(p5)
T.reveal_type(p6)
T.reveal_type(block)
end
34 changes: 34 additions & 0 deletions test/testdata/rewriter/rbs_signatures_sigs.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# typed: strict

extend T::Sig

module P1; end
module P2; end
module P3; end
module P4; end
module P5; end
module P6; end

# Method sigs

#: (P1, P2) -> void
def method1(p1, p2)
T.reveal_type(p1) # error: Revealed type: `P1`
T.reveal_type(p2) # error: Revealed type: `P2`
end

#: (?P1) -> void
def method2(p1 = nil)
T.reveal_type(p1) # error: Revealed type: `T.nilable(P1)`
end

#: (P1, ?P2, *P3, p4: P4, ?p5: P5, **P6) { -> void } -> void
def methodX(p1, p2 = nil, *p3, p4:, p5: nil, **p6, &block)
T.reveal_type(p1) # error: Revealed type: `P1`
T.reveal_type(p2) # error: Revealed type: `T.nilable(P2)`
T.reveal_type(p3) # error: Revealed type: `T::Array[P3]`
T.reveal_type(p4) # error: Revealed type: `P4`
T.reveal_type(p5) # error: Revealed type: `T.nilable(P5)`
T.reveal_type(p6) # error: Revealed type: `T::Hash[Symbol, P6]`
T.reveal_type(block) # error: Revealed type: `T.proc.void`
end
1 change: 0 additions & 1 deletion test/testdata/rewriter/rbs_signatures_types.rb
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,6 @@ def shape_type1; T.unsafe(nil); end
def proc_type1; T.unsafe(nil); end
T.reveal_type(proc_type1) # error: Revealed type: `T.proc.params(arg0: Integer, arg1: String).returns(String)`


# TODO
# proc_type -> Proc
# self binding
Expand Down

0 comments on commit ae2ad1f

Please sign in to comment.