Skip to content
This repository was archived by the owner on May 18, 2019. It is now read-only.

Commit 90be434

Browse files
perostOpenModelica-Hudson
authored andcommitted
[NF] Improve handling of imports.
- Qualified imports are now resolved ondemand, to avoid dependency issues when importing a subpackage. - Added error checks for conflicting imports. Belonging to [master]: - #2292 - OpenModelica/OpenModelica-testsuite#883
1 parent df1cb27 commit 90be434

File tree

5 files changed

+270
-77
lines changed

5 files changed

+270
-77
lines changed

Compiler/NFFrontEnd/NFClassTree.mo

Lines changed: 85 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ encapsulated package NFClassTree
3535
import NFType.Type;
3636
import Mutable;
3737
import NFModifier.Modifier;
38+
import Import = NFImport;
3839

3940
protected
4041
import Array;
@@ -165,7 +166,7 @@ public
165166
array<InstNode> classes;
166167
array<InstNode> components;
167168
array<InstNode> exts;
168-
array<InstNode> imports;
169+
array<Import> imports;
169170
DuplicateTree.Tree duplicates;
170171
end PARTIAL_TREE;
171172

@@ -177,7 +178,7 @@ public
177178
array<InstNode> classes;
178179
array<InstNode> components;
179180
array<InstNode> exts;
180-
array<InstNode> imports;
181+
array<Import> imports;
181182
DuplicateTree.Tree duplicates;
182183
end EXPANDED_TREE;
183184

@@ -188,7 +189,7 @@ public
188189
array<Mutable<InstNode>> components;
189190
list<Integer> localComponents;
190191
array<InstNode> exts;
191-
array<InstNode> imports;
192+
array<Import> imports;
192193
DuplicateTree.Tree duplicates;
193194
end INSTANTIATED_TREE;
194195

@@ -197,7 +198,7 @@ public
197198
LookupTree.Tree tree;
198199
array<InstNode> classes;
199200
array<InstNode> components;
200-
array<InstNode> imports;
201+
array<Import> imports;
201202
DuplicateTree.Tree duplicates;
202203
end FLAT_TREE;
203204

@@ -211,10 +212,12 @@ public
211212
LookupTree.Tree ltree;
212213
LookupTree.Entry lentry;
213214
Integer clsc, compc, extc, i;
214-
array<InstNode> clss, comps, exts, imps;
215+
array<InstNode> clss, comps, exts;
215216
Integer cls_idx = 0, ext_idx = 0, comp_idx = 0;
216-
list<InstNode> imported_elems = {};
217217
DuplicateTree.Tree dups;
218+
list<Import> imps = {};
219+
array<Import> imps_arr;
220+
SourceInfo info;
218221
algorithm
219222
ltree := LookupTree.new();
220223

@@ -286,12 +289,22 @@ public
286289
then
287290
();
288291

289-
// An import clause. Instantiate it to get the elements it points to
290-
// (might be multiple elements if it's unqualified) and store them in
291-
// the list for later.
292+
// An unqualified import clause. We need to know which names are
293+
// imported by the clause, so it needs to be instantiated.
294+
case SCode.IMPORT(imp = Absyn.Import.UNQUAL_IMPORT(), info = info)
295+
algorithm
296+
imps := Import.instUnqualified(e.imp, parent, info, imps);
297+
then
298+
();
299+
300+
// A qualified import clause. Since the import itself gives the name
301+
// of the imported element we can delay resolving the path until we
302+
// need it (i.e. when the name is used). Doing so avoids some
303+
// dependency issues, like when a package is imported into one of it's
304+
// enclosing scopes.
292305
case SCode.IMPORT()
293306
algorithm
294-
imported_elems := Inst.instImport(e.imp, parent, e.info, imported_elems);
307+
imps := Import.UNRESOLVED_IMPORT(e.imp, parent, e.info) :: imps;
295308
then
296309
();
297310

@@ -304,14 +317,16 @@ public
304317
end match;
305318
end for;
306319

307-
// Add all the imports to the tree.
320+
321+
// Add all the imported names to the lookup tree.
322+
imps_arr := listArray(imps);
308323
i := 1;
309-
for e in imported_elems loop
310-
ltree := addImport(e, i, ltree);
324+
for e in imps loop
325+
ltree := addImport(e, i, ltree, imps_arr);
311326
i := i + 1;
312327
end for;
313328

314-
tree := PARTIAL_TREE(ltree, clss, comps, exts, listArray(imported_elems), dups);
329+
tree := PARTIAL_TREE(ltree, clss, comps, exts, imps_arr, dups);
315330
end fromSCode;
316331

317332
function fromEnumeration
@@ -360,7 +375,8 @@ public
360375
protected
361376
LookupTree.Tree ltree;
362377
LookupTree.Entry lentry;
363-
array<InstNode> exts, clss, comps, imps;
378+
array<InstNode> exts, clss, comps;
379+
array<Import> imps;
364380
list<tuple<Integer, Integer>> ext_idxs = {};
365381
Integer ccount, cls_idx, comp_idx = 1;
366382
DuplicateTree.Tree dups;
@@ -448,7 +464,8 @@ public
448464
Class cls;
449465
ClassTree tree, ext_tree;
450466
LookupTree.Tree ltree;
451-
array<InstNode> exts, old_clss, old_comps, imps;
467+
array<InstNode> exts, old_clss, old_comps;
468+
array<Import> imps;
452469
array<Mutable<InstNode>> clss, comps, ext_clss;
453470
list<Integer> local_comps = {};
454471
Integer cls_idx = 1, comp_idx = 1, cls_count, comp_count;
@@ -1182,25 +1199,59 @@ public
11821199
end addEnumConflict;
11831200

11841201
function addImport
1185-
input InstNode node;
1202+
input Import imp;
11861203
input Integer index;
11871204
input output LookupTree.Tree tree;
1205+
input array<Import> imports;
11881206
algorithm
1189-
tree := LookupTree.add(tree, InstNode.name(node),
1190-
LookupTree.Entry.IMPORT(index), addImportConflict);
1207+
tree := LookupTree.add(tree, Import.name(imp), LookupTree.Entry.IMPORT(index),
1208+
function addImportConflict(imports = imports));
11911209
end addImport;
11921210

11931211
function addImportConflict
11941212
input LookupTree.Entry newEntry;
11951213
input LookupTree.Entry oldEntry;
11961214
input String name;
1215+
input array<Import> imports;
11971216
output LookupTree.Entry entry;
11981217
algorithm
1199-
entry := oldEntry;
1200-
// TODO: We should probably give an error message here in some cases:
1201-
// * Named/qualified import conflicting with normal element: warning
1202-
// * Unqualified import conflicting with normal element: ignore import
1203-
// * Import conflicting with import: Error, but only if used
1218+
entry := match (newEntry, oldEntry)
1219+
local
1220+
Import imp1, imp2;
1221+
1222+
case (LookupTree.Entry.IMPORT(), LookupTree.Entry.IMPORT())
1223+
algorithm
1224+
imp1 := imports[newEntry.index];
1225+
imp2 := imports[oldEntry.index];
1226+
1227+
// Check what kind of imports we have. In case of an error we replace the import
1228+
// with the error information, and only print the error if the name is looked up.
1229+
entry := match (imp1, imp2)
1230+
// Two qualified imports of the same name gives an error.
1231+
case (Import.UNRESOLVED_IMPORT(), Import.UNRESOLVED_IMPORT())
1232+
algorithm
1233+
arrayUpdate(imports, oldEntry.index, Import.CONFLICTING_IMPORT(imp1, imp2));
1234+
then
1235+
oldEntry;
1236+
1237+
// A name imported from several unqualified imports gives an error.
1238+
case (Import.RESOLVED_IMPORT(), Import.RESOLVED_IMPORT())
1239+
algorithm
1240+
arrayUpdate(imports, oldEntry.index, Import.CONFLICTING_IMPORT(imp1, imp2));
1241+
then
1242+
oldEntry;
1243+
1244+
// Qualified import overwrites an unqualified.
1245+
case (Import.UNRESOLVED_IMPORT(), _) then newEntry;
1246+
// oldEntry is either qualified or a delayed error, keep it.
1247+
else oldEntry;
1248+
end match;
1249+
then
1250+
entry;
1251+
1252+
// Other elements overwrite an imported name.
1253+
else oldEntry;
1254+
end match;
12041255
end addImportConflict;
12051256

12061257
function addDuplicate
@@ -1307,7 +1358,9 @@ public
13071358
input ClassTree tree;
13081359
output InstNode element;
13091360
protected
1310-
array<InstNode> imports;
1361+
array<Import> imports;
1362+
Import imp;
1363+
Boolean changed;
13111364
algorithm
13121365
imports := match tree
13131366
case PARTIAL_TREE() then tree.imports;
@@ -1316,7 +1369,13 @@ public
13161369
case FLAT_TREE() then tree.imports;
13171370
end match;
13181371

1319-
element := imports[index];
1372+
// Imports are resolved on demand, i.e. here.
1373+
(element, changed, imp) := Import.resolve(imports[index]);
1374+
1375+
// Save the import if it wasn't already resolved.
1376+
if changed then
1377+
arrayUpdate(imports, index, imp);
1378+
end if;
13201379
end resolveImport;
13211380

13221381
function countElements

0 commit comments

Comments
 (0)