Skip to content
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

Swap the Order that the Parser Creates 'Def' and 'Decl' Types #3359

Conversation

InsertCreativityHere
Copy link
Member

@InsertCreativityHere InsertCreativityHere commented Jan 14, 2025

This PR is a long overdue follow up to my PRs which centralized the metadata validation.

There are two types which can be forward declared in Slice: Interfaces and Classes.
There are separate types for definitions (InterfaceDef and ClassDef) vs forward declarations (InterfaceDecl, ClassDecl).
And, whenever the compiler creates a Def type, it also implicitly creates a Decl type to go with it.

But, the fact that the compiler creates Def first and then Decl after causes us to emit some errors/warnings in a weird order.
This was only really noticed after implementing the metadata changes. I tried fixing it in that PR, but that caused an obscure ruby bug (#2442), so it was split off into a separate PR (this one).


Now, the compiler will create the Decl types before the Def types.
This fixes the order of diagnostic messages, but it also lets us simplify some code in the compilers as well,
since whenever we look up a type by name, we are guaranteed to hit Decls before we hit Defs.

@InsertCreativityHere
Copy link
Member Author

This no longer seems to trigger the Ice/exception Ruby bug anymore.
It's not clear what changed.

@InsertCreativityHere InsertCreativityHere marked this pull request as ready for review January 15, 2025 02:52
Comment on lines -1176 to -1179
bool declared = dynamic_pointer_cast<InterfaceDecl>(matches.front()) != nullptr;
ostringstream os;
os << "class '" << name << "' was previously " << (declared ? "declared" : "defined") << " as "
<< prependA(matches.front()->kindOf());
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When discussing this before we decided to no longer emit
was previously declared vs was previously defined based on whether we hit a forward declaration. Now we always say was previously defined.

Comment on lines +1191 to +1193
ClassDeclPtr decl = createClassDecl(name);
def->_declaration = decl;
decl->_definition = def;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the main part of this PR. We want to call createXXXDecl before we do:

    _unit->addContent(def);
    _contents.push_back(def);

So that Decls come before Defs in the _contents list.

Comment on lines -1238 to -1241
bool declared = dynamic_pointer_cast<InterfaceDecl>(matches.front()) != nullptr;
ostringstream os;
os << "class '" << name << "' was previously " << (declared ? "declared" : "defined") << " as "
<< prependA(matches.front()->kindOf());
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Always say previously defined instead of previously declared

Comment on lines -1267 to -1268
def = dynamic_pointer_cast<ClassDef>(q);
assert(def);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is impossible to hit.
Whenever we see ClassDef, we know there's a ClassDecl right before it in the 'ast'.

And the line above this is basically:
if we see a ClassDecl, return it to avoid creating a new ClassDecl.

So, even if a ClassDef exists, we will always hit the ClassDecl branch first...

Comment on lines -1276 to -1279
if (def)
{
decl->_definition = def;
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

... And a result, def is always unset.

Comment on lines -642 to -648
if (_classHistory.count(scoped) == 0 && p->canBeCyclic())
{
//
// Emit a forward declaration for the class in case a data member refers to this type.
//
_out << sp << nl << "_M_" << type << " = IcePy.declareValue('" << scoped << "')";
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Impossible to hit.

visitClassDecl also has this logic, and at the end, adds scoped to _classHistory.
Now that we're guaranteed to call visitClassDecl before visitClassDef,
_classHistory.count(scoped) == 0 will always be false.

visitInterfaceDecl also has this logic. And since we're guaranteed to call visitInterfaceDecl before a call to visitInterfaceDef, _classHistory will always contain this element by this point.

@@ -551,7 +551,6 @@ Slice::Python::CodeVisitor::visitClassDefStart(const ClassDefPtr& p)
{
string scoped = p->scoped();
string type = getAbsolute(p, "_t_");
string classType = getAbsolute(p, "_t_", "Disp");
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So many dead variables.

@@ -1114,11 +1100,6 @@ Slice::Python::CodeVisitor::visitInterfaceDefStart(const InterfaceDefPtr& p)
registerName(className);
_out.dec();

if (_classHistory.count(scoped) == 0)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same but for InterfaceDecl.

Comment on lines -135 to -138
_out << nl << "if(!isset(" << type << "))";
_out << sb;
_out << nl << type << " = IcePHP_declareClass('" << scoped << "');";
_out << eb;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe that this check for isset is unnecessary.
This block is wrapped in an if statement:

if (_classHistory.count(scoped) == 0)
{...
_classHistory.insert(scoped); // Avoid redundant declarations.
}

which should ensure that this code is only generated once.

Even if I'm wrong (which I don't think I am), there's nothing wrong with setting type = IcePHP_declareClass multiple times, it's just redundant is all.

Comment on lines -274 to -278
if (_classHistory.count(scoped) == 0 && p->canBeCyclic())
{
// Emit a forward declaration for the class in case a data member refers to this type.
_out << sp << nl << type << " = IcePHP_declareClass('" << scoped << "');";
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Impossible to hit.
visitClassDecl also checks for _classHistory.count(scoped) == 0 and inserts scoped if so. Since we always call visitClassDecl before visitClassDef, by the time we get here, the count will always be non-zero.

@InsertCreativityHere InsertCreativityHere merged commit 603000d into zeroc-ice:main Jan 15, 2025
23 checks passed
InsertCreativityHere added a commit to InsertCreativityHere/compiler-comparison that referenced this pull request Jan 21, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants