-
Notifications
You must be signed in to change notification settings - Fork 156
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Invalid expression discarding when using semicolons #317
Comments
Thanks for your contribution fellow Rustacean |
I checked with a debugger. The syntax is parsed correctly( |
The offending code is at Excerpt of the offending code: void
TypeCheckExpr::visit (HIR::BlockExpr &expr)
{
TyTy::BaseType *block_tyty
= new TyTy::TupleType (expr.get_mappings ().get_hirid ());
expr.iterate_stmts ([&] (HIR::Stmt *s) mutable -> bool {
bool is_final_stmt = expr.is_final_stmt (s);
bool has_final_expr = expr.has_expr () && expr.tail_expr_reachable ();
bool stmt_is_final_expr = is_final_stmt && !has_final_expr;
auto resolved = TypeCheckStmt::Resolve (s, inside_loop);
if (resolved == nullptr)
{
rust_error_at (s->get_locus_slow (), "failure to resolve type");
return false;
}
if (stmt_is_final_expr)
{
delete block_tyty;
block_tyty = resolved;
}
else if (!resolved->is_unit ())
{
rust_error_at (s->get_locus_slow (), "expected () got %s",
resolved->as_string ().c_str ());
}
return true;
});
if (expr.has_expr ())
{
delete block_tyty;
block_tyty
= TypeCheckExpr::Resolve (expr.get_final_expr ().get (), inside_loop);
}
infered = block_tyty->clone ();
} @CohenArthur Maybe you'll be interested in implementing a fix? It should help you get comfortable with the codebase too. |
Wow thanks for the headstart @YizhePKU ! I hadn't even started to research the issue yet. I'd love to implement that fix |
I've known about this bug but haven't decided if the bug is in the parser to make the ExprStmtWithoutBlock the final expression or if this can be handled as part of HIR lowering. The other side of this problem is you can have an ExprStmtWithBlock but this is the final expression such as:
|
@SimplyTheOther do you have any opinions on this? |
In that case, wouldn't the type of the ExprStmtWithBlock resolve as an |
Yes I am just showing that the final expr can be an ExprStmtWithBlock. Another more awkward example is this one that is difficult: This is a testcase deadcode1.rs
Usually anything that is not the final expr should ensure is UnitType but because the final return is unreachable it is not required. |
Related discussion from rustc: rust-lang/rust#61733 |
After reading the reference and various discussions, here's my understanding:
rustc currently handles this by distinguishing AST statements with and without semicolons(doc). This information is then removed during the AST-to-HIR lowering process. We could follow rustc, but our current approaching of handling this in the parser seems cleaner. |
My understanding of it is that code like this:
should be parsed as For code like this:
My understanding was that this was technically not allowed. According to the Rust reference, only On the other hand, I tested that code in Rust Playground, and apparently it works fine. So this actually seems to me to be a type resolution error as a result of a parser error as a result of an error in the Rust reference. EDIT: there is an open issue on the Rust reference regarding this. The issue implies that poor wording may have caused a misinterpretation on my part. |
It seems that rustc does not represent the unit type directly, but rather considers it as a tuple with 0 elements. |
#286 :D |
Haha what a coincidence! Well in the end I used an empty Tuple as well, I have a fix ready and I'm cleaning it up and adding tests. This way it's closer to the rustc implementation, but I think we should also add documentation to clear that up |
To add to the complexity of the issue: Both fn function() -> i32 {
return 15;
return 1.2;
} and fn function() -> i32 {
return 1.2;
return 15;
} Produce an error, meaning that the typechecker probably knows about the "expected" return type of a function block when typechecking all the statements inside said block. This is a bit different to the approach actually taken from gccrs, and needs a bit more modification than I thought. The dilemma I'm currently facing is the following. Consider the following blocks: { // 1
8;
8
} // -> implicit return of an i32
{ // 2
8;
8;
} // no last expression, therefore i32 type is "discarded" and () is returned
{ // 3
8;
return 8;
} // no last expression, but last statement is a return, so returns an i32 You can't simply discard the types of every statement in the block, and you can't simply use the type of the last statement, because sometimes it needs to be discarded! |
@lrh2000 is this fixed now? |
rustc
does not produce any warnings for the following code:(which is very different from this code, which does not compile with rustc either, obviously)
What's happening is that, despite
8
being an "expression", the use of a semicolon afterwards allows not using it. This would be similar to something likewhere discarding the return value of a function is fine, unless said function or type is marked with
#[must_use]
.However, gccrs does not seem to be able to discard the value of an expression (and thus transforming said expression into a "statement"). Therefore, the snippets of code above fail with the following error:
I haven't found any issues about the subject, but might not have looked hard enough! If so, I apologize
The text was updated successfully, but these errors were encountered: