Skip to content

Conversation

InsertCreativityHere
Copy link
Member

This PR follows #4223 and #4276, and continues improving the way the Slice parser handles keyword or missing identifiers.

It improves identifier handling for modules, structs, and operations. All that's left after this are classes, interfaces, and exceptions.

It also slightly tweaks how the parser checks for 'changed meaning' errors. Often the logic was double-counting 'redefinition' errors as 'changed meaning' errors, which isn't helpful.

Copilot

This comment was marked as outdated.

@@ -309,7 +309,7 @@ definition
// ----------------------------------------------------------------------
: module_def opt_semicolon
{
assert($1 == nullptr || dynamic_pointer_cast<Module>($1));
Copy link
Member Author

Choose a reason for hiding this comment

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

We always create the element now, even if it has a 'bad' identifier.
So the returned element should never be nullptr.

@@ -368,35 +368,22 @@ definition
// ----------------------------------------------------------------------
module_def
// ----------------------------------------------------------------------
: ICE_MODULE ICE_IDENTIFIER
: ICE_MODULE definition_name
{
currentUnit->setSeenDefinition();

auto ident = dynamic_pointer_cast<StringTok>($2);
ContainerPtr cont = currentUnit->currentContainer();
ModulePtr module = cont->createModule(ident->v, false);
Copy link
Member Author

Choose a reason for hiding this comment

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

Again, we always create the element, so there's no risk of module being nullptr.
This helps simplify the rest of the logic here.

@@ -618,25 +579,10 @@ optional_type_id
}
;

// ----------------------------------------------------------------------
Copy link
Member Author

Choose a reason for hiding this comment

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

The new definition_name rule handles keywords and identifiers.
It replaces these little side-rules we used to have before.

@@ -700,7 +634,7 @@ class_name
// ----------------------------------------------------------------------
class_id
// ----------------------------------------------------------------------
Copy link
Member Author

Choose a reason for hiding this comment

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

ICE_IDENT_OPEN is just <identifier>(, same for definition_name_open, it just means 'something' followed by an opening parenthesis.

currentUnit->pushContainer(op);
}
interface->checkHasChangedMeaning(name, op);
currentUnit->pushContainer(op);
$$ = op;
}
else
{
$$ = nullptr;
}
}
Copy link
Member Author

Choose a reason for hiding this comment

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

No longer needed. definition_name handles the keyword case.

@@ -1642,7 +1653,6 @@ SequencePtr
Slice::Container::createSequence(const string& name, const TypePtr& type, MetadataList metadata)
{
SequencePtr p = make_shared<Sequence>(shared_from_this(), name, type, std::move(metadata));
_contents.push_back(p);
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 moved these to the bottoms of their respective createXXX methods for consistency of placement.
It doesn't meaningfully change anything.

Comment on lines +2291 to +2297
// If the two identifiers resolve to different elements, but those elements are in the same container,
// then the 'real' error is that the user redefined an element, not that an element changed meaning.
// This error is reported elsewhere in the code, so nothing to do here.
if (it->second->container() == namedThing->container())
{
return;
}
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 new addition to this logic.
You'll see that adding it reduced the number of unnecessary changed meaning errors in the errorDetection tests.

Comment on lines 26 to -27
CaseInsensitive.ice:151: enumeration 'eN1' differs only in capitalization from enumeration 'en1'
CaseInsensitive.ice:151: 'eN1' has changed meaning
Copy link
Member Author

Choose a reason for hiding this comment

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

The real error was that eN1 and en1 conflict with one another.
Not that eN1 changed meaning...

Comment on lines 10 to -11
ChangedMeaning.ice:123: 'E' is not an exception
ChangedMeaning.ice:123: 'E' has changed meaning
Copy link
Member Author

Choose a reason for hiding this comment

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

The real error is that E was used as an exception when it is not, not that it changed meaning.

Comment on lines 63 to +64
IdentAsKeyword.ice:60: interfaces can only be defined within a module
IdentAsKeyword.ice:60: keyword 'module' cannot be used as a name
Copy link
Member Author

Choose a reason for hiding this comment

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

Here it's actually good to have 2 errors, because they're both true and unrelated.
We didn't see the 2nd error before, because the createInterface logic exited early with nullptr.
Now that it doesn't exit early, we report all the errors we see.

Comment on lines +3 to 4
DerivedRedefinition.ice:15: redefinition of operation 'op'
DerivedRedefinition.ice:15: operation 'op' is already defined as an operation in a base interface
Copy link
Member Author

Choose a reason for hiding this comment

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

Maybe we could improve it, but getting 2 errors for line 15 is correct, because op is doubly-redefined.
One in the same interface and once in a parent interface.

Copy link
Member Author

Choose a reason for hiding this comment

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

Generated code, probably not worth reading.

bool differsOnlyInCase = matches.front()->name() != name;
ModulePtr module = dynamic_pointer_cast<Module>(p);
if (module)
bool hasValidIdentifier = true;
Copy link
Member

Choose a reason for hiding this comment

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

Should be something like hasConflictingIdentifier

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, that's a more clear name.
I updated them all as suggested.

Comment on lines 1275 to 1276
unit()->error(os.str());
hasValidIdentifier = false;
Copy link
Member

Choose a reason for hiding this comment

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

I would add a break after the (first) error.

if (!checkIdentifier(name))
{
return nullptr;
checkIdentifier(name);
Copy link
Member

Choose a reason for hiding this comment

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

Add a comment - why do we check the identifier so late?

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 updated the name of this function to reportIllegalSuffixOrUnderscore.

  1. This is much more clear than checkIdentifier
  2. It makes it clear that (going forward) we don't care about the return value.
    After I finish updating classes, exceptions, and interfaces like I did in this PR, I'll remove the return value all together.

unit()->error(os.str());
return nullptr;
}
bool hasValidIdentifier = !doesNameConflict(name, "operation", _contents);
Copy link
Member

Choose a reason for hiding this comment

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

Need to rename variable: it's not about valid identifier (as checked by checkIdentifier, that this function doesn't call as far as I can tell).
It's only about a name that is not empty and non-conflicting.

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 renamed the variable to hasConflictingIdentifier per your other suggestion.

return nullptr;
// If this module has a valid identifier and doesn't conflict with another definition,
// add it to the unit's contentMap so it can be looked up later.
unit()->addContent(q);
Copy link
Member

Choose a reason for hiding this comment

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

Should we be doing this after checkIdentifier like before?

Copy link
Member Author

Choose a reason for hiding this comment

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

The order really doesn't matter.
I updated the name of this function to reportIllegalSuffixOrUnderscore, which is much clearer than checkIdentifier.

Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR improves how the Slice parser handles keyword or missing identifiers for modules, structs, and operations, as part of a series of improvements to bad-identifier handling. The changes make error messages more consistent and fix issues with "changed meaning" error detection.

  • Standardizes error messages for keyword misuse to use "cannot be used as a name"
  • Refactors identifier validation logic to better handle edge cases and reduce duplicate error reporting
  • Improves "changed meaning" error detection to avoid double-counting redefinition errors

Reviewed Changes

Copilot reviewed 11 out of 12 changed files in this pull request and generated no comments.

Show a summary per file
File Description
IllegalUseOfKeyword.err Updates expected error messages to use standardized "cannot be used as a name" format
IdentAsKeyword.err Updates expected error messages and removes duplicate "changed meaning" errors
DerivedRedefinition.err Adds expected redefinition error that was previously missing
ChangedMeaning.ice Updates comment to reflect corrected error detection logic
ChangedMeaning.err Removes duplicate "changed meaning" error that was incorrectly reported
CaseInsensitive.err Removes duplicate "changed meaning" errors for redefinition cases
Util.h Renames function from checkIdentifier to reportIllegalSuffixOrUnderscore
SliceUtil.cpp Updates function name to match header
Parser.h Removes unused nodeType parameter from createStruct
Parser.cpp Major refactoring of module, struct, and operation creation with improved error handling
Grammar.y Simplifies grammar rules and consolidates keyword error handling

@InsertCreativityHere InsertCreativityHere merged commit 5484ea4 into zeroc-ice:main Aug 6, 2025
26 of 27 checks passed
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