Skip to content

Commit fbfc088

Browse files
committed
fix handling of circular dependencies
1 parent eb41e4b commit fbfc088

File tree

2 files changed

+23
-9
lines changed

2 files changed

+23
-9
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
## 0.5.16
4+
5+
- Change handling of circular dependencies to an incomplete but correct approach, fixing a potential issue with bad caching.
6+
37
## 0.5.15
48

59
- Fix use of `@inheritdoc` in circularly dependent files.

src/source.ts

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ class SourceFile {
6969
);
7070
}
7171

72+
@memoize
7273
get contractsInScope(): Record<string, SourceContract> {
7374
return contractsInScope(this);
7475
}
@@ -78,16 +79,22 @@ class SourceFile {
7879
}
7980
}
8081

81-
const scopeCache = new WeakMap<SourceFile, Record<string, SourceContract>>();
82-
83-
function contractsInScope(file: SourceFile): Record<string, SourceContract> {
84-
if (scopeCache.has(file)) {
85-
return scopeCache.get(file)!;
82+
function contractsInScope(
83+
file: SourceFile,
84+
stack = new Set<SourceFile>(),
85+
aliasedImport = false,
86+
): Record<string, SourceContract> {
87+
if (stack.has(file)) {
88+
if (aliasedImport) {
89+
throw new Error('Circular dependency detected: aliased imports not supported');
90+
} else {
91+
return {};
92+
}
8693
}
8794

88-
const scope: Record<string, SourceContract> = {};
95+
stack.add(file);
8996

90-
scopeCache.set(file, scope);
97+
const scope: Record<string, SourceContract> = {};
9198

9299
for (const c of file.contracts) {
93100
scope[c.name] = c;
@@ -96,15 +103,18 @@ function contractsInScope(file: SourceFile): Record<string, SourceContract> {
96103
const imports = file.ast.nodes.filter(isImportDirective);
97104
for (const i of imports) {
98105
const importedFile = file.source.fileById(i.sourceUnit);
106+
const importedScope = contractsInScope(importedFile, stack, aliasedImport || i.symbolAliases.length > 0);
99107
if (i.symbolAliases.length === 0) {
100-
Object.assign(scope, importedFile.contractsInScope);
108+
Object.assign(scope, importedScope);
101109
} else {
102110
for (const a of i.symbolAliases) {
103-
scope[a.local ?? a.foreign.name] = importedFile.contractsInScope[a.foreign.name];
111+
scope[a.local ?? a.foreign.name] = importedScope[a.foreign.name];
104112
}
105113
}
106114
};
107115

116+
stack.delete(file);
117+
108118
return scope;
109119
}
110120

0 commit comments

Comments
 (0)