Skip to content

Provide unique name from closures with same name#488

Open
kvpanch wants to merge 3 commits intomainfrom
kvpanch/issue_474
Open

Provide unique name from closures with same name#488
kvpanch wants to merge 3 commits intomainfrom
kvpanch/issue_474

Conversation

@kvpanch
Copy link
Contributor

@kvpanch kvpanch commented Mar 4, 2026

In YUL it's possible to declare closure with a same name, but in different scope, which previously resulted to func name conflict during LLVM IR construction.
To solve this, track YUL scope when building LLVM IR and a special counter that increments every time function with the same name exists in LLVM module.
There's still assert if somehow within the same scope there 2 functions with the same name, which should be forbidden by Yul

Fixes: #474

In YUL it's possible to declare closure with a same name, but in
different scope, which previously resulted to func name conflict during LLVM
IR construction.
To solve this, track YUL scope when building LLVM IR and a special
counter that increments every time function with the same name exists in
LLVM module.
There's still assert if somehow within the same scope there 2 functions
with the same name, which should be forbidden by Yul

Fixes: #474
@kvpanch kvpanch requested review from elle-j and xermicus March 4, 2026 20:01
Comment on lines +88 to +91
/// Monotonic counter for unique frontend function name mangling.
function_counter: usize,
/// Scope stack mapping Yul names to mangled LLVM names.
function_scope: Vec<BTreeMap<String, String>>,
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: What do you think about prefixing with frontend_ for more clarity?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'd say it's not necessary as this code belongs to FE. Also, seems naming convention in this file does omit frontend, except for is_frontend, which I find a bit confusing and maybe better name would be get_mangled or something like that.

}
let counter = self.function_counter;
self.function_counter += 1;
let mangled = format!("{name}_{}__{counter}", self.code_type().unwrap());
Copy link
Contributor

Choose a reason for hiding this comment

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

Is the double _ intentional here?

Suggested change
let mangled = format!("{name}_{}__{counter}", self.code_type().unwrap());
let mangled = format!("{name}_{}_{counter}", self.code_type().unwrap());

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Used double underscores to indicate compiler-generated suffix as user less likely use it to name a function.
Since we have rules to mangle function names, we can make one: even have $ here instead of __ which would help later to debug code

Copy link
Contributor

Choose a reason for hiding this comment

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

Gotcha 👍 Yeah makes sense

kvpanch and others added 2 commits March 8, 2026 21:21
Co-authored-by: LJ <81748770+elle-j@users.noreply.github.com>
Co-authored-by: LJ <81748770+elle-j@users.noreply.github.com>
Copy link
Contributor

@elle-j elle-j left a comment

Choose a reason for hiding this comment

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

LGTM

Comment on lines +478 to +481
let mangled = format!("{name}_{}__{counter}", self.code_type().unwrap());
if let Some(scope) = self.function_scope.last_mut() {
scope.insert(name.to_string(), mangled.clone());
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Ah, I see now why you couldn't remove this if let Some() as part of this commit in order to just scope.insert(..) directly.

If you extract the code type before let scope, you'll be able to replace it 👍

let name = if is_frontend {
    let code_type = self.code_type().unwrap();
    let scope = /* ... */;
        
    // ...
    
    let mangled = format!("{name}_{code_type}__{counter}");
    scope.insert(name.to_string(), mangled.clone());
    
    // ...
}

Copy link
Member

@xermicus xermicus left a comment

Choose a reason for hiding this comment

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

Thanks! The logic looks good to me, couldn't find an obvious issue. However some integration tests with mangled functions, to ensure the mangling logic works correctly, would be nice to have

Comment on lines +467 to +470
let scope = self
.function_scope
.last_mut()
.expect("ICE: function scope must be pushed before declaring frontend functions");
Copy link
Member

Choose a reason for hiding this comment

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

I prefer this to be a getter function like current_function_scope (ensures same access / error pattern for future use)

self.function_counter += 1;
let mangled = format!("{name}_{}__{counter}", self.code_type().unwrap());
if let Some(scope) = self.function_scope.last_mut() {
scope.insert(name.to_string(), mangled.clone());
Copy link
Member

Choose a reason for hiding this comment

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

Looking at the code above, last_mut() returning None here is unreachable making the if let redundant.

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.

ICE same-named Yul functions in sibling blocks

3 participants