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
2 changes: 2 additions & 0 deletions tslang/include/TypeScript/MLIRLogic/MLIRGenStore.h
Original file line number Diff line number Diff line change
Expand Up @@ -779,6 +779,8 @@ struct ClassInfo
bool hasRTTI;
ProcessingStages processingAtEvaluation;
ProcessingStages processing;
// the module `processing` was reached in: a discovery module is thrown away with what it holds
mlir::Operation *processingModule = nullptr;

ClassInfo()
: isDeclaration(false), hasNew(false), hasConstructor(false), constructorAccessLevel(mlir_ts::AccessLevel::Public), hasInitializers(false), hasStaticConstructor(false),
Expand Down
11 changes: 10 additions & 1 deletion tslang/lib/TypeScript/MLIRGenClasses.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,12 +115,21 @@ namespace mlirgen

// do not process specialized class second time;
// TODO: investigate why classType is provided already for class
if (testProcessingState(newClassPtr, ProcessingStages::Processing, genContext))
// Not across modules, though: an import met during discovery is generated in full, but
// into the discovery module, which is erased. The members of a specialization made there
// are gone, and the module that uses it has to have its own.
if (testProcessingState(newClassPtr, ProcessingStages::Processing, genContext)
&& (genContext.allowPartialResolve || newClassPtr->processingModule == theModule.getOperation()))
{
return {mlir::success(), newClassPtr->classType.getName().getValue()};
}
}

if (!genContext.allowPartialResolve)
{
newClassPtr->processingModule = theModule.getOperation();
}

setProcessingState(newClassPtr, ProcessingStages::Processing, genContext);

auto location = loc(classDeclarationAST);
Expand Down
11 changes: 11 additions & 0 deletions tslang/lib/TypeScript/MLIRGenGenerics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1141,6 +1141,10 @@ namespace mlirgen
<< " name: " << typeAlias.getKey() << " type: " << typeAlias.getValue();
llvm::dbgs() << "\n";);

// generated in full even inside an imported file; see the overload below
MLIRValueGuard<bool> declarationModeGuard(declarationMode);
declarationMode = false;

// create new instance of interface with TypeArguments
if (mlir::failed(std::get<0>(mlirGen(genericClassInfo->classDeclaration, genericTypeGenContext))))
{
Expand Down Expand Up @@ -1217,6 +1221,13 @@ namespace mlirgen
// llvm_unreachable(s.c_str());
}

// A specialization belongs to every module that uses it (its members are linkonce_odr),
// so it is generated in full even while an imported file is only being declared: the
// module keeps this copy for its own uses too, and must not depend on the imported
// module's object happening to keep the members it needs.
MLIRValueGuard<bool> declarationModeGuard(declarationMode);
declarationMode = false;

auto res = std::get<0>(mlirGen(genericClassInfo->classDeclaration, genericTypeGenContext));
count--;

Expand Down
6 changes: 6 additions & 0 deletions tslang/test/tester/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2433,6 +2433,12 @@ set(import_bindings_dir "${PROJECT_SOURCE_DIR}/test/tester/import-bindings")
tslang_add_import_tests(import-bindings-renamed "${import_bindings_dir}" import_renamed names_module)
tslang_add_import_tests(import-bindings-namespace "${import_bindings_dir}" import_namespace names_module)

# 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")

# The same for a shared library: imported directly and through a source module - see
# shared-import-reimport.cmake.
if (WIN32)
Expand Down
33 changes: 33 additions & 0 deletions tslang/test/tester/import-specialization/box_module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// A module whose class has a field of a generic class specialized on it.

export class Box<T> {
items: T[] = [];

[index: int]: T;

get(index: int): T {
return this.items[index];
}

set(index: int, value: T) {
this.items[index] = value;
}

add(v: T) {
this.items.push(v);
}

get length() {
return this.items.length;
}
}

export class Tree {
name: string;
children: Box<Tree>;

constructor(name: string) {
this.name = name;
this.children = new Box<Tree>();
}
}
34 changes: 34 additions & 0 deletions tslang/test/tester/import-specialization/import_specialization.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Box<Tree> is first specialized while its module is imported, during this file's discovery pass.
// Its members went into the discovery module, which is thrown away, and the specialization was
// then taken as done: calls to them here failed to lower ("failed to legalize operation
// 'ts.SymbolCallInternal'"), found in the BrowserLib sources attached to #231.

import { Tree } from "./box_module";

function find(n: Tree, name: string): Tree | null {
if (n.name == name) {
return n;
}

for (let i = 0; i < n.children.length; i++) {
const found = find(n.children[i], name);
if (found !== null) {
return found;
}
}

return null;
}

function main() {
const root = new Tree("root");
const a = new Tree("a");
root.children.add(a);
a.children.add(new Tree("b"));

assert(find(root, "b") !== null);
assert(find(root, "z") === null);
assert(root.children[0].name == "a");

print("done.");
}
Loading