Commit ed8d35ce authored by Tobias Tebbi's avatar Tobias Tebbi Committed by Commit Bot

[torque] infer type of local const bindings

We currently only expose this to desugarings and not in the grammar
to keep 'const' and 'let' bindings consistent.
A side-effect of this change is that it is now possible to use a
shadowed name in the initializer of a const binding.

Bug: v8:7793
Change-Id: Ic2ca6af0735acf0e748d394f9039fe6612bd4a06
Reviewed-on: https://chromium-review.googlesource.com/1150534
Commit-Queue: Tobias Tebbi <tebbi@chromium.org>
Reviewed-by: 's avatarDaniel Clifford <danno@chromium.org>
Cr-Commit-Position: refs/heads/master@{#54755}
parent 352e408b
......@@ -440,7 +440,7 @@ struct VarDeclarationStatement : Statement {
DEFINE_AST_NODE_LEAF_BOILERPLATE(VarDeclarationStatement)
VarDeclarationStatement(
SourcePosition pos, bool const_qualified, std::string name,
TypeExpression* type,
base::Optional<TypeExpression*> type,
base::Optional<Expression*> initializer = base::nullopt)
: Statement(kKind, pos),
const_qualified(const_qualified),
......@@ -449,7 +449,7 @@ struct VarDeclarationStatement : Statement {
initializer(initializer) {}
bool const_qualified;
std::string name;
TypeExpression* type;
base::Optional<TypeExpression*> type;
base::Optional<Expression*> initializer;
};
......
......@@ -299,15 +299,22 @@ Parameter* DeclarationVisitor::DeclareParameter(const std::string& name,
void DeclarationVisitor::Visit(VarDeclarationStatement* stmt) {
std::string variable_name = stmt->name;
const Type* type = declarations()->GetType(stmt->type);
if (type->IsConstexpr() && !stmt->const_qualified) {
ReportError(
"cannot declare variable with constexpr type. Use 'const' instead.");
}
DeclareVariable(variable_name, type, stmt->const_qualified);
if (global_context_.verbose()) {
std::cout << "declared variable " << variable_name << " with type " << *type
<< "\n";
if (!stmt->const_qualified) {
if (!stmt->type) {
ReportError(
"variable declaration is missing type. Only 'const' bindings can "
"infer the type.");
}
const Type* type = declarations()->GetType(*stmt->type);
if (type->IsConstexpr()) {
ReportError(
"cannot declare variable with constexpr type. Use 'const' instead.");
}
DeclareVariable(variable_name, type, stmt->const_qualified);
if (global_context_.verbose()) {
std::cout << "declared variable " << variable_name << " with type "
<< *type << "\n";
}
}
// const qualified variables are required to be initialized properly.
......
......@@ -43,10 +43,13 @@ Scope* Declarations::GetGenericScope(Generic* generic,
return result;
}
bool Declarations::IsDeclaredInCurrentScope(const std::string& name) {
return chain_.ShallowLookup(name) != nullptr;
}
void Declarations::CheckAlreadyDeclared(const std::string& name,
const char* new_type) {
auto i = chain_.ShallowLookup(name);
if (i != nullptr) {
if (IsDeclaredInCurrentScope(name)) {
std::stringstream s;
s << "cannot redeclare " << name << " (type " << new_type << ")";
ReportError(s.str());
......
......@@ -115,6 +115,8 @@ class Declarations {
return chain_.GetLiveVariables();
}
bool IsDeclaredInCurrentScope(const std::string& name);
Statement* next_body() const { return next_body_; }
void PrintScopeChain() { chain_.Print(); }
......
......@@ -220,7 +220,7 @@ void ImplementationVisitor::Visit(TorqueMacroDeclaration* decl,
const Variable* result_var = nullptr;
if (macro->HasReturnValue()) {
result_var =
GenerateVariableDeclaration(decl, kReturnValueVariable, {}, {});
GeneratePredeclaredVariableDeclaration(kReturnValueVariable, {});
}
Label* macro_end = declarations()->DeclareLabel("macro_end");
GenerateLabelDefinition(macro_end, decl);
......@@ -320,7 +320,10 @@ const Type* ImplementationVisitor::Visit(VarDeclarationStatement* stmt) {
if (stmt->initializer) {
init_result = Visit(*stmt->initializer);
}
GenerateVariableDeclaration(stmt, stmt->name, {}, init_result);
base::Optional<const Type*> type;
if (stmt->type) type = declarations()->GetType(*stmt->type);
GenerateVariableDeclaration(stmt, stmt->name, stmt->const_qualified, type,
init_result);
return TypeOracle::GetVoidType();
}
......@@ -360,7 +363,8 @@ VisitResult ImplementationVisitor::Visit(ConditionalExpression* expr) {
const Type* common_type = GetCommonType(left.type(), right.type());
std::string result_var = NewTempVariable();
Variable* result = GenerateVariableDeclaration(expr, result_var, common_type);
Variable* result =
GenerateVariableDeclaration(expr, result_var, false, common_type);
{
ScopedIndent indent(this);
......@@ -861,7 +865,7 @@ const Type* ImplementationVisitor::Visit(ForOfLoopStatement* stmt) {
const Type* common_type = GetCommonType(begin.type(), end.type());
Variable* index_var = GenerateVariableDeclaration(
stmt, std::string(kForIndexValueVariable) + "_" + NewTempVariable(),
common_type, begin);
false, common_type, begin);
VisitResult index_for_read = {index_var->type(), index_var};
......@@ -881,8 +885,12 @@ const Type* ImplementationVisitor::Visit(ForOfLoopStatement* stmt) {
GenerateLabelBind(body_label);
VisitResult element_result =
GenerateCall("[]", {{expression_result, index_for_read}, {}});
GenerateVariableDeclaration(stmt->var_declaration,
stmt->var_declaration->name, {}, element_result);
base::Optional<const Type*> declared_type;
if (stmt->var_declaration->type)
declared_type = declarations()->GetType(*stmt->var_declaration->type);
GenerateVariableDeclaration(
stmt->var_declaration, stmt->var_declaration->name,
stmt->var_declaration->const_qualified, declared_type, element_result);
Visit(stmt->body);
GenerateLabelGoto(increment_label);
......@@ -923,7 +931,7 @@ const Type* ImplementationVisitor::Visit(TryLabelStatement* stmt) {
Declarations::NodeScopeActivator scope(declarations(),
stmt->label_blocks[i]->body);
for (auto& v : label->GetParameters()) {
GenerateVariableDeclaration(stmt, v->name(), v->type());
GenerateVariableDeclaration(stmt, v->name(), false, v->type());
v->Define();
}
++i;
......@@ -1519,23 +1527,36 @@ void ImplementationVisitor::GenerateVariableDeclaration(const Variable* var) {
}
}
Variable* ImplementationVisitor::GeneratePredeclaredVariableDeclaration(
const std::string& name,
const base::Optional<VisitResult>& initialization) {
Variable* variable = Variable::cast(declarations()->LookupValue(name));
GenerateVariableDeclaration(variable);
if (initialization) {
GenerateAssignToVariable(variable, *initialization);
}
return variable;
}
Variable* ImplementationVisitor::GenerateVariableDeclaration(
AstNode* node, const std::string& name,
AstNode* node, const std::string& name, bool is_const,
const base::Optional<const Type*>& type,
const base::Optional<VisitResult>& initialization) {
Variable* variable = nullptr;
if (declarations()->TryLookup(name)) {
if (declarations()->IsDeclaredInCurrentScope(name)) {
variable = Variable::cast(declarations()->LookupValue(name));
} else {
variable = declarations()->DeclareVariable(name, *type, false);
// Because the variable is being defined during code generation, it must be
// assumed that it changes along all control split paths because it's no
// longer possible to run the control-flow anlaysis in the declaration pass
// over the variable.
global_context_.MarkVariableChanged(
node, declarations()->GetCurrentSpecializationTypeNamesVector(),
variable);
variable = declarations()->DeclareVariable(
name, type ? *type : initialization->type(), is_const);
if (!is_const) {
// Because the variable is being defined during code generation, it must
// be assumed that it changes along all control split paths because it's
// no longer possible to run the control-flow anlaysis in the declaration
// pass over the variable.
global_context_.MarkVariableChanged(
node, declarations()->GetCurrentSpecializationTypeNamesVector(),
variable);
}
}
GenerateVariableDeclaration(variable);
if (initialization) {
......
......@@ -189,8 +189,12 @@ class ImplementationVisitor : public FileVisitor {
void GenerateVariableDeclaration(const Variable* var);
Variable* GeneratePredeclaredVariableDeclaration(
const std::string& name,
const base::Optional<VisitResult>& initialization);
Variable* GenerateVariableDeclaration(
AstNode* node, const std::string& name,
AstNode* node, const std::string& name, bool is_const,
const base::Optional<const Type*>& type,
const base::Optional<VisitResult>& initialization = {});
......
......@@ -242,8 +242,17 @@ module test {
}
macro TestLocalConstBindings() {
const kSmi: Smi = 3;
check(kSmi == 3);
const x : constexpr int31 = 3;
const x_smi : Smi = x;
{
const x : Smi = x + from_constexpr<Smi>(1);
check(x == x_smi + 1);
const x_smi : Smi = x;
check(x == x_smi);
check(x == 4);
}
check(x_smi == 3);
check(x == x_smi);
}
struct TestStructA {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment