A -shared library's class can hold a specialization of its own generic - #390
Merged
Merged
Conversation
An importer of a -shared library whose exported class has a field typed by a specialization of a generic from the same module (`children: Box<Tree>`) failed: "generic type Box can't be found". Two things: - The specialization was declared on its own in __decls, as `class Box<!ts.class<@Tree, ...>>`, and fields named it that way; neither parses. It is no longer declared: the importer makes it from the generic, as a use in its own source would. The declaration printer names it `Box<Tree>` (MLIRPrinter::getClassSpecialization, supplied by MLIRGen, which has the generic registry), and the generic - this module's own, even when not marked `export` - and the type arguments are exported in its place. - __decls_generic_<module> sorted after __decls_<module>, so the field was read before the generic existed. The importer loads generics first. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A class type argument printed as a symbol reference, so a
specialization was named Box<!ts.class<@Tree, ...>>, and so were its
symbols. In an ELF symbol name `@` separates the version, and ld failed
to link a -shared library that exports one ("version node not found for
symbol Box<...>..vtbl"). The `@` before a symbol reference is now left
out of the name, and one inside a quoted literal type is written as
MLIR's escape \40. Windows linked such names; they change there too, so
a prebuilt DefaultLib must be rebuilt.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ASDAlexander77
force-pushed
the
shared-generic-class-import
branch
from
September 28, 2026 15:06
83d5e03 to
3cbff1e
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Suppose a
-sharedlibrary exports a class with a field typed by a specialization of a generic from the same module:Any importer of that library failed with
generic type Box can't be found. This was the-sharedgap left open in #380, whose test was registered static-only.The library's
__declsshowed the causes:Fix, in two parts:
Box<Tree>.addClassDeclarationToExportrecognizes a specialization (getClassSpecializationOf). Instead of printing it, it exports the generic and the type arguments. The generic is exported only when it is this module's own, and then even when it isn't markedexport. The importer buildsBox<Tree>from the generic, as a use in its own source would. So the declaration printer can name a specialization the way it is written,MLIRPrintergains an optionalgetClassSpecializationhook, supplied by MLIRGen, which has the generic registry. Diagnostics leave it unset. All tenMLIRDeclarationPrintersites pass it.__decls_<module>sorts before__decls_generic_<module>. SoTree's field was read beforeBoxexisted.mlirGenImportSharedLibnow puts the generic declarations first. Registering a generic only records it, so a generic that names a class declared later still works.The library's
__declsare now:and the generic
Box<T>is in__decls_generic_box_module_….Tests:
import-specializationis now registered throughtslang_add_import_tests, so it runs static,-sharedand-jit -shared.Second commit (Linux CI): a specialization's name has no
@. On Linux both new-sharedtests failed to link the library:A specialization's name embeds its type arguments as MLIR prints them, and MLIR writes a class as a symbol reference,
@Tree. In an ELF symbol name,@separates the symbol version, so ld can't export such a name. Windows accepts it.appendSpecializedTypeNames(both overloads) now goes throughappendTypeToSymbolName:@before a symbol reference is left out, which givesBox<!ts.class<Tree, !ts.class_storage<Tree>>>.@inside a quoted literal type is written as MLIR's escape\40, so two different literals can't end up with the same name.These two overloads are the only places a specialization name is built, so the IR, the exported symbols and every
SearchForAddressOfSymbolstring stay consistent.ABI note: every specialization with a class or interface type argument changes its symbol name on Windows as well. A prebuilt DefaultLib must be rebuilt with this compiler.
Results (after rebasing onto main, with #389/#391/#392):
test-compile-shared-import-specializationandtest-jit-shared-import-specialization.🤖 Generated with Claude Code