Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion tslang/include/TypeScript/MLIRLogic/MLIRDeclarationPrinter.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@ namespace typescript
raw_ostream &os;

public:
MLIRDeclarationPrinter(raw_ostream &os) : os(os) {};
// see MLIRPrinter::getClassSpecialization
using ClassSpecializationFn = std::function<bool(mlir_ts::ClassType, std::string &, SmallVectorImpl<mlir::Type> &)>;

MLIRDeclarationPrinter(raw_ostream &os, ClassSpecializationFn getClassSpecialization = {})
: os(os), getClassSpecialization(std::move(getClassSpecialization)) {};

void printTypeDeclaration(StringRef, NamespaceInfo::TypePtr, mlir::Type);
void printEnum(StringRef, NamespaceInfo::TypePtr, mlir::DictionaryAttr);
Expand All @@ -25,6 +29,8 @@ namespace typescript
void printGenericClass(NamespaceInfo::TypePtr, StringRef);

protected:
ClassSpecializationFn getClassSpecialization;

void newline();
void printBeforeDeclaration();
void printAsFieldName(mlir::Attribute);
Expand Down
27 changes: 27 additions & 0 deletions tslang/include/TypeScript/MLIRLogic/MLIRPrinter.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ class MLIRPrinter
// the whole declaration. Off for diagnostics.
bool quoteNonIdentifierFieldNames = false;

// a specialization of a generic class printed the way it is written, `Box<Tree>`, rather
// than by its internal name `Box<!ts.class<Tree, ...>>`, which does not parse back. Gives
// the generic's name and the type arguments in order; the printer has no class registry, so
// declaration text (__decls) supplies it. Unset for diagnostics.
std::function<bool(mlir_ts::ClassType, std::string &, SmallVectorImpl<mlir::Type> &)> getClassSpecialization;

template <typename T>
void printFieldName(T &out, mlir::Attribute id)
{
Expand Down Expand Up @@ -357,6 +363,27 @@ class MLIRPrinter
printType(out, t.getElementType());
})
.template Case<mlir_ts::ClassType>([&](auto t) {
std::string genericName;
SmallVector<mlir::Type> typeArgs;
if (getClassSpecialization && getClassSpecialization(t, genericName, typeArgs))
{
out << genericName.c_str() << "<";
auto first = true;
for (auto typeArg : typeArgs)
{
if (!first)
{
out << ", ";
}

first = false;
printType(out, typeArg);
}

out << ">";
return;
}

out << t.getName().getValue().str().c_str();
})
.template Case<mlir_ts::ClassStorageType>([&](auto t) {
Expand Down
1 change: 1 addition & 0 deletions tslang/lib/TypeScript/DeclarationPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ namespace typescript
MLIRPrinter mp{};
mp.printBoxedObjectTypes = true;
mp.quoteNonIdentifierFieldNames = true;
mp.getClassSpecialization = getClassSpecialization;
mp.printType<raw_ostream>(os, type);
}

Expand Down
132 changes: 118 additions & 14 deletions tslang/lib/TypeScript/MLIRGenImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -9983,6 +9983,46 @@ class MLIRGenImpl
std::pair<mlir::LogicalResult, mlir::StringRef> mlirGen(ClassLikeDeclaration classDeclarationAST,
const GenContext &genContext);

// A type argument in a specialization's name (Box<!ts.class<Tree, ...>>), which becomes the name
// of its symbols. MLIR prints a class or interface as a symbol reference, `@Tree`, but an `@`
// in an ELF symbol name is read as its version (`name@VERSION`), and ld fails to link a
// shared library that exports it. The `@` before a symbol reference is left out; one inside a
// quoted string (a literal type) is written as MLIR's escape `\40`, so no two names meet.
static void appendTypeToSymbolName(std::string &name, mlir::Type type)
{
std::string printed;
llvm::raw_string_ostream s(printed);
s << type;

auto quoted = false;
for (size_t i = 0; i < printed.size(); i++)
{
auto c = printed[i];
if (quoted && c == '\\' && i + 1 < printed.size())
{
name.push_back(c);
name.push_back(printed[++i]);
continue;
}

if (c == '"')
{
quoted = !quoted;
}
else if (c == '@')
{
if (quoted)
{
name.append("\\40");
}

continue;
}

name.push_back(c);
}
}

void appendSpecializedTypeNames(std::string &name, llvm::SmallVector<TypeParameterDOM::TypePtr> &typeParams,
const GenContext &genContext)
{
Expand All @@ -9998,8 +10038,7 @@ class MLIRGenImpl
auto type = getResolveTypeParameter(typeParam->getName(), false, genContext);
if (type)
{
llvm::raw_string_ostream s(name);
s << type;
appendTypeToSymbolName(name, type);
}
else
{
Expand Down Expand Up @@ -10751,8 +10790,7 @@ class MLIRGenImpl
auto type = getType(typeParam, genContext);
if (type)
{
llvm::raw_string_ostream s(name);
s << type;
appendTypeToSymbolName(name, type);
}
else
{
Expand Down Expand Up @@ -11879,7 +11917,7 @@ class MLIRGenImpl

SmallVector<char> out;
llvm::raw_svector_ostream ss(out);
MLIRDeclarationPrinter dp(ss);
MLIRDeclarationPrinter dp(ss, classSpecializationNamer());
dp.printTypeDeclaration(name, elementNamespace, type);

declExports << ss.str().str();
Expand All @@ -11899,7 +11937,7 @@ class MLIRGenImpl

SmallVector<char> out;
llvm::raw_svector_ostream ss(out);
MLIRDeclarationPrinter dp(ss);
MLIRDeclarationPrinter dp(ss, classSpecializationNamer());
dp.print(interfaceInfo);

declExports << ss.str().str();
Expand All @@ -11919,7 +11957,7 @@ class MLIRGenImpl

SmallVector<char> out;
llvm::raw_svector_ostream ss(out);
MLIRDeclarationPrinter dp(ss);
MLIRDeclarationPrinter dp(ss, classSpecializationNamer());
dp.printEnum(name, elementNamespace, enumType.getValues());

declExports << ss.str().str();
Expand All @@ -11934,7 +11972,7 @@ class MLIRGenImpl

SmallVector<char> out;
llvm::raw_svector_ostream ss(out);
MLIRDeclarationPrinter dp(ss);
MLIRDeclarationPrinter dp(ss, classSpecializationNamer());
dp.printVariableDeclaration(name, elementNamespace, type, isConst, dllName);

declExports << ss.str().str();
Expand All @@ -11949,12 +11987,56 @@ class MLIRGenImpl

SmallVector<char> out;
llvm::raw_svector_ostream ss(out);
MLIRDeclarationPrinter dp(ss);
MLIRDeclarationPrinter dp(ss, classSpecializationNamer());
dp.print(funcProto->getNameWithoutNamespace(), elementNamespace, funcProto->getFuncType(), dllName);

declExports << ss.str().str();
}

// A specialization of a generic class - its generic and type arguments, in order.
GenericClassInfo::TypePtr getClassSpecializationOf(ClassInfo::TypePtr classInfo, SmallVectorImpl<mlir::Type> &typeArgs)
{
if (!classInfo || !classInfo->originClassType || classInfo->originClassType == classInfo->classType)
{
return nullptr;
}

auto genericClassInfo = getGenericClassInfoByFullName(classInfo->originClassType.getName().getValue());
if (!genericClassInfo)
{
return nullptr;
}

for (auto &typeParam : genericClassInfo->typeParams)
{
auto found = classInfo->typeParamsWithArgs.find(typeParam->getName());
if (found == classInfo->typeParamsWithArgs.end())
{
return nullptr;
}

typeArgs.push_back(found->getValue().second);
}

return genericClassInfo;
}

// see MLIRPrinter::getClassSpecialization
MLIRDeclarationPrinter::ClassSpecializationFn classSpecializationNamer()
{
return [this](mlir_ts::ClassType classType, std::string &genericName, SmallVectorImpl<mlir::Type> &typeArgs) {
auto genericClassInfo = getClassSpecializationOf(getClassInfoByFullName(classType.getName().getValue()), typeArgs);
if (!genericClassInfo)
{
typeArgs.clear();
return false;
}

genericName = genericClassInfo->fullName.str();
return true;
};
}

void addClassDeclarationToExport(ClassInfo::TypePtr newClassPtr)
{
if (isAddedToExport(newClassPtr->classType))
Expand All @@ -11965,11 +12047,33 @@ class MLIRGenImpl

exportedTypes.insert(newClassPtr->classType);

// A specialization (Box<Tree>, the type of an exported class's field) is not declared on
// its own: the importer makes it from the generic, as a use in its own source would, and
// names it `Box<Tree>` (classSpecializationNamer). Declared, it came out as
// `class Box<!ts.class<Tree, ...>>`, which does not parse. What it needs is the generic
// - exported here when it is this module's own, even if not marked `export` - and its
// type arguments.
SmallVector<mlir::Type> typeArgs;
if (auto genericClassInfo = getClassSpecializationOf(newClassPtr, typeArgs))
{
if (genericClassInfo->fileName == mainSourceFileName)
{
addGenericClassDeclarationToExport(genericClassInfo);
}

for (auto typeArg : typeArgs)
{
addDependancyTypesToExport(typeArg);
}

return;
}

addDependancyTypesToExport(newClassPtr->classType);

SmallVector<char> out;
llvm::raw_svector_ostream ss(out);
MLIRDeclarationPrinter dp(ss);
MLIRDeclarationPrinter dp(ss, classSpecializationNamer());
dp.print(newClassPtr);

declExports << ss.str().str();
Expand Down Expand Up @@ -12015,7 +12119,7 @@ class MLIRGenImpl

SmallVector<char> out;
llvm::raw_svector_ostream ss(out);
MLIRDeclarationPrinter dp(ss);
MLIRDeclarationPrinter dp(ss, classSpecializationNamer());
dp.printGenericClass(genericFunctionInfo->elementNamespace, declText);

genericDeclExports << ss.str().str();
Expand Down Expand Up @@ -12060,7 +12164,7 @@ class MLIRGenImpl

SmallVector<char> out;
llvm::raw_svector_ostream ss(out);
MLIRDeclarationPrinter dp(ss);
MLIRDeclarationPrinter dp(ss, classSpecializationNamer());
dp.printGenericClass(genericClassInfo->elementNamespace, declText);

genericDeclExports << ss.str().str();
Expand Down Expand Up @@ -12101,7 +12205,7 @@ class MLIRGenImpl

SmallVector<char> out;
llvm::raw_svector_ostream ss(out);
MLIRDeclarationPrinter dp(ss);
MLIRDeclarationPrinter dp(ss, classSpecializationNamer());
dp.printGenericClass(genericInterfaceInfo->elementNamespace, declText);

genericDeclExports << ss.str().str();
Expand Down Expand Up @@ -12131,7 +12235,7 @@ class MLIRGenImpl

SmallVector<char> out;
llvm::raw_svector_ostream ss(out);
MLIRDeclarationPrinter dp(ss);
MLIRDeclarationPrinter dp(ss, classSpecializationNamer());
dp.printGenericClass(elementNamespace, declText);

genericDeclExports << ss.str().str();
Expand Down
8 changes: 8 additions & 0 deletions tslang/lib/TypeScript/MLIRGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1343,6 +1343,14 @@ namespace mlirgen
addGlobalConstructor(location, fullInitGlobalFuncName);
}

// Generics first: a declaration elsewhere names their specializations (a field typed
// `Box<Tree>`), and the symbols come sorted, which put __decls_<module> before
// __decls_generic_<module> - "generic type Box can't be found". Registering a generic
// only records it, so one naming a class declared after it is fine.
std::stable_partition(symbols.begin(), symbols.end(), [](StringRef symbol) {
return symbol.starts_with(std::string(SHARED_LIB_DECLARATIONS_2UNDERSCORE) + "_generic_");
});

// A library can hold several modules (test-runner -shared links them all into one), each
// with its own __decls_<module>. A module already in this module - imported as source,
// or through another library - is not declared again; see mlirGenInclude.
Expand Down
7 changes: 4 additions & 3 deletions tslang/test/tester/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2471,9 +2471,10 @@ tslang_add_import_tests(import-bindings-namespace "${import_bindings_dir}" impor

# A generic class specialized while its module was imported lost its members (#231).
set(import_specialization_dir "${PROJECT_SOURCE_DIR}/test/tester/import-specialization")
# Static linking only: through a -shared library the importer cannot name Box yet ("generic type
# Box can't be found"), a separate gap.
tslang_add_test(NAME test-compile-import-specialization COMMAND test-runner "${import_specialization_dir}/import_specialization.ts" "${import_specialization_dir}/box_module.ts")
# Through a -shared library the specialization was declared by its internal name
# (`class Box<!ts.class<Tree, ...>>`), and before the generic it is made from ("generic type Box
# can't be found"). On Linux the name had an `@` (`@Tree`), which ld reads as a symbol version.
tslang_add_import_tests(import-specialization "${import_specialization_dir}" import_specialization box_module)

# The same for a shared library: imported directly and through a source module - see
# shared-import-reimport.cmake.
Expand Down
Loading