Skip to content

Commit b1eb79b

Browse files
committed
Merge ability to retry compilation if forwarded package is no longer available from Tristan Knoth.
2 parents 20ef802 + d292bcc commit b1eb79b

13 files changed

+160
-23
lines changed

compiler/dl-ir.stanza

+37-6
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ defpackage stz/dl-ir :
66
import stz/type-fargs
77
import stz/absolute-info
88
import stz/base-dir
9+
import stz/printing-utils
910

1011
;============================================================
1112
;======================== PackageIO =========================
@@ -31,16 +32,29 @@ defmethod hash (p : ImportedPackage) :
3132
defmethod equal? (p1 : ImportedPackage, p2 : ImportedPackage) :
3233
equal?(package-name(p1), package-name(p2))
3334

35+
;- forwarded-imports: If package A imports B, and B forwards C,
36+
; then we say that C is imported into A via forwarding (assuming
37+
; that C is not already directly imported into A).
38+
; This field stores all packages that are imported via forwarding.
39+
;- direct-imports: These are the packages that are explicitly imported
40+
; by the user via an import statement. This is a subset of the
41+
; 'imported-packages' field in that it does not include the packages
42+
; that are implicitly imported due to type signatures.
3443
public defstruct PackageIO :
3544
package: Symbol
3645
imported-packages: Tuple<ImportedPackage> with: (updater => sub-imported-packages)
46+
forwarded-imports: Tuple<Symbol>
47+
direct-imports: Tuple<Symbol>
3748
imports: Tuple<Import> with: (updater => sub-imports)
3849
exports: Tuple<Export> with: (updater => sub-exports)
3950
documentation?:False|String with: (updater => sub-documentation)
4051

52+
;Subset of PackageIO which does not include 'Import' field.
4153
public defstruct PackageExports :
4254
package: Symbol
4355
imported-packages: Tuple<ImportedPackage>
56+
forwarded-imports: Tuple<Symbol>
57+
direct-imports: Tuple<Symbol>
4458
exports: Tuple<Export> with: (updater => sub-exports)
4559

4660
;============================================================
@@ -442,7 +456,7 @@ public defn match? (x:Rec, y:Rec, types-in-io:HashSet<TypeId>|False) -> True|Fal
442456
;============================================================
443457

444458
public defn to-package-exports (io:PackageIO) :
445-
PackageExports(package(io), imported-packages(io), exports(io))
459+
PackageExports(package(io), imported-packages(io), forwarded-imports(io), direct-imports(io), exports(io))
446460

447461
public defn to-package-exports? (io:PackageIO|False) :
448462
match(io:PackageIO) :
@@ -567,10 +581,26 @@ defmethod print (o:OutputStream, x:Export) :
567581
lnprint(o2, "doc: %_" % [documentation?(x)])
568582

569583
defmethod print (o:OutputStream, x:PackageIO) :
570-
print(o, "package %~ :" % [package(x)])
571-
val o2 = IndentedStream(o)
572-
lnprint(o2, "imported-packages = (%@)" % [imported-packages(x)])
573-
lnprints(o2, cat(imports(x), exports(x)))
584+
val items = [
585+
falseable-field("documentation", documentation?(x))
586+
named-list-fields("imported-packages", imported-packages(x))
587+
line-wrapped-field("forwarded-imports", forwarded-imports(x))
588+
line-wrapped-field("direct-imports", direct-imports(x))
589+
inline-fields(imports(x))
590+
inline-fields(exports(x))]
591+
print(o, "package %~ %_" % [package(x), colon-field-list(items)])
592+
593+
defmethod print (o:OutputStream, x:ImportedPackage) :
594+
val items = [
595+
simple-field("forward", forward(x))
596+
falseable-field("only", only(x))
597+
inline-fields(prefix(x))]
598+
print(o, "import package %~ %_" % [package-name(x), colon-field-list(items)])
599+
600+
defmethod print (o:OutputStream, x:ImportPrefix) :
601+
match(names(x)) :
602+
(names:Tuple<Symbol>) : print(o, "prefix(%,) => %~" % [names, prefix(x)])
603+
(f:False) : print(o, "prefix => %~" % [prefix(x)])
574604

575605
defmethod print (o:OutputStream, x:PackageExports) :
576606
print(o, "package %~ :" % [package(x)])
@@ -603,7 +633,8 @@ defsyntax dl-ir :
603633
?imports:#import ...
604634
?exports:#export ...) :
605635
;[TODO] Add doc string reader macro. Defaulted to false for now.
606-
PackageIO(name, to-tuple(map({ImportedPackage(_)}, ips)), to-tuple(imports), to-tuple(exports), false)
636+
;[TODO]: is the empty direct-import list OK?
637+
PackageIO(name, to-tuple(map({ImportedPackage(_)}, ips)), [], [], to-tuple(imports), to-tuple(exports), false)
607638

608639
defproduction dtype : DType
609640
defrule dtype = (byte) : DByte()

compiler/el-ir.stanza

+1-1
Original file line numberDiff line numberDiff line change
@@ -1065,7 +1065,7 @@ defsyntax el-ir :
10651065
defrule epackage = (package ?name:#symbol : (?ss:#tstmt ... #E)) :
10661066
val ins = to-tuple(filter-by<Import>(ss))
10671067
val exs = to-tuple(filter-by<Export>(ss))
1068-
val io = PackageIO(name, [], ins, exs, false)
1068+
val io = PackageIO(name, [], [], [], ins, exs, false)
10691069
val es = to-tuple(filter-by<ETExp>(ss))
10701070
EPackage(io, to-tuple(es))
10711071

compiler/el.stanza

+1-1
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ defn collapse (epackages:Tuple<EPackage>) -> EPackage :
262262
for ex in exports(packageio(e)) seq :
263263
val n* = global-rec-ids[id(rec(ex))]
264264
sub-n(ex, n*)
265-
PackageIO(`prog, [], [], exports*, false)
265+
PackageIO(`prog, [], [], [], [], exports*, false)
266266

267267
;Rename one specific package
268268
defn renamed-exps (epackage:EPackage) :

compiler/front-end.stanza

+3-2
Original file line numberDiff line numberDiff line change
@@ -540,11 +540,12 @@ defn FrontEnd (sys:FrontEndInputs) -> FrontEnd :
540540
val resolved = resolve-packages(package-names, errorlist)
541541
val new-inputs = HashTable<Symbol,PackageInFile>()
542542
for e in errorlist do :
543-
match(e:MissingType) :
543+
match(e:MissingType|MissingForwardedPackage) :
544544
match(source-file?(src-package(e))) :
545545
(file:String) : new-inputs[src-package(e)] = PackageInFile(src-package(e), file)
546546
(file:False) : throw(FrontEndErrors(errorlist))
547-
else : throw(FrontEndErrors(errorlist))
547+
else :
548+
throw(FrontEndErrors(errorlist))
548549
[resolved, to-tuple(values(new-inputs))]
549550

550551
defn resolve-packages! (package-names:Tuple<Symbol>) -> ResolverResult :

compiler/il-ir.stanza

+7
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,17 @@ defpackage stz/il-ir :
1010
;General Multis for IExp
1111
public defmulti info (e:IExp) -> False|AbsoluteFileInfo
1212

13+
;- imports: Corresponds one-to-one with the user's 'import' statements
14+
; nested under 'defpackage'.
15+
;- forwarded-imports: If package A imports B, and B forwards C,
16+
; then we say that C is imported into A via forwarding (assuming
17+
; that C is not already directly imported into A).
18+
; This field stores all packages that are imported via forwarding.
1319
public defstruct IPackage :
1420
name: Symbol
1521
documentation?: IDoc|False
1622
imports: Tuple<IImport> with: (updater => sub-imports)
23+
forwarded-imports: Tuple<Symbol> with: (updater => sub-forwarded-imports)
1724
exps: List<IExp> with: (updater => sub-exps)
1825
info: AbsoluteFileInfo|False
1926
namemap: NameMap with: (default => void, updater => sub-namemap)

compiler/il-to-tl.stanza

+2-1
Original file line numberDiff line numberDiff line change
@@ -169,11 +169,12 @@ defn to-imported-package (i:IImport) -> ImportedPackage :
169169
;The imported/exported entries will be populated
170170
;after type inference.
171171
defn to-packageio (ipackage:IPackage) -> PackageIO :
172+
val direct-imports = to-tuple(seq(package, imports(ipackage)))
172173
val imports = to-tuple(seq(to-imported-package, imports(ipackage)))
173174
val doc? = match(documentation?(ipackage)) :
174175
(d:IDoc) : value(string(d) as ILiteral) as String
175176
(f:False) : false
176-
PackageIO(name(ipackage), imports, [], [], doc?)
177+
PackageIO(name(ipackage), imports, forwarded-imports(ipackage), direct-imports, [], [], doc?)
177178

178179
;============================================================
179180
;=============== Conversion Functions =======================

compiler/input.stanza

+3-3
Original file line numberDiff line numberDiff line change
@@ -468,23 +468,23 @@ defn split-packages (e:IExp,
468468
val e = all-exps[i + 1] as IDefPackage
469469
val [exps, end] = package-exps(i + 2)
470470
val imports = to-tuple $ seq(to-iimport, imports(e) as List<IImportExp>)
471-
add(packages, IPackage(name!(e), doc, imports, exps, info(e)))
471+
add(packages, IPackage(name!(e), doc, imports, [], exps, info(e)))
472472
loop(end)
473473

474474
;Package without preceding IDoc form.
475475
DefPackageExp:
476476
val e = all-exps[i] as IDefPackage
477477
val [exps, end] = package-exps(i + 1)
478478
val imports = to-tuple $ seq(to-iimport, imports(e) as List<IImportExp>)
479-
add(packages, IPackage(name!(e), false, imports, exps, info(e)))
479+
add(packages, IPackage(name!(e), false, imports, [], exps, info(e)))
480480
loop(end)
481481

482482
;Default package.
483483
WithinPackageExp:
484484
val [exps, end] = package-exps(i)
485485
val info = info(head(exps)) when not empty?(exps)
486486
val name = gensym(`default)
487-
add(packages, IPackage(name, false, default-imports, exps, info))
487+
add(packages, IPackage(name, false, default-imports, [], exps, info))
488488
loop(end)
489489

490490
;Return packages

compiler/pkg-serializer.stanza

+2
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,8 @@ defserializer PkgSerializer (include-asm?:True|False) :
154154
deftype packageio (PackageIO) :
155155
package:symbol
156156
imported-packages:tuple(importedpackage)
157+
forwarded-imports:tuple(symbol)
158+
direct-imports:tuple(symbol)
157159
imports:tuple(dimport)
158160
exports:tuple(dexport)
159161
documentation?:opt(string)

compiler/repl.stanza

+1
Original file line numberDiff line numberDiff line change
@@ -797,6 +797,7 @@ defn REPLEnv () :
797797
IPackage(gensym(`repl),
798798
false,
799799
to-tuple(values(exp-imports)),
800+
[]
800801
List(wrap-display-result(exp)),
801802
info(exp))
802803

compiler/resolver.stanza

+99-7
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ public defn resolve-il (packages:Tuple<IPackage|PackageExports>, env:Env) -> Res
167167

168168
;Resolve type dependencies from pkgs
169169
check-exported-types(symtables, ipackages*, package-exports(symtables), error-accum)
170-
170+
check-forwarded-imports(symtables, package-exports(symtables), error-accum)
171171

172172
;Compute initialization order
173173
defn init-order () :
@@ -228,7 +228,9 @@ defn resolve-package (ipackage:IPackage,
228228
map(resolve-exp{_, eng}, exps(ipackage))
229229
val ipackage* = sub-exps(ipackage, exps*)
230230
if length(error-accum) == num-errors :
231-
add-qualified-imports(ipackage*, qualified-imports(eng))
231+
ipackage*
232+
$> add-qualified-imports{_, qualified-imports(eng)}
233+
$> compute-forwarded-imports{_, symtables}
232234

233235
;<doc>=======================================================
234236
;=================== Check Type Dependencies ================
@@ -260,7 +262,7 @@ issue an error if it doesn't.
260262
defn check-exported-types (symtables:SymbolTables, pkgs:Collection<IPackage>, pexs:Tuple<PackageExports>, error-accum:Vector<ResolveError>) :
261263
;Ensure that all types referenced in exports are defined
262264
for pex in pexs do :
263-
;Check for existence of typeid
265+
;Check for existence of typeid
264266
defn check-for-type (e:TypeId) :
265267
val symtable = symtables[package(e)]
266268
match(symtable:SymbolTable) :
@@ -276,6 +278,41 @@ defn check-exported-types (symtables:SymbolTables, pkgs:Collection<IPackage>, pe
276278
;Scan all exports
277279
do(scan-for-type, exports(pex))
278280

281+
;<doc>=======================================================
282+
;================ Check Forwarded Imports ===================
283+
;============================================================
284+
285+
At the time of creation, each .pkg file stores the packages
286+
that were imported via forwarding.
287+
288+
This check ensures that for each of the .pkg files, any
289+
package that was previously imported via forwarding is still
290+
imported via forwarding.
291+
292+
;============================================================
293+
;=======================================================<doc>
294+
295+
defn check-forwarded-imports (symtables:SymbolTables,
296+
pexs:Tuple<PackageExports>,
297+
error-accum:Vector<ResolveError>) ->
298+
False :
299+
300+
;For each PackageExports.
301+
for pex in pexs do :
302+
303+
;Compute the set of packages that are currently forwarded to the .pkg file.
304+
val currently-forwarded = forwarded-imports(symtables, direct-imports(pex))
305+
306+
;Retrieve the set of packages that were previously forwarded to the .pkg file
307+
;at the time the .pkg file was originally compiled.
308+
val previously-forwarded = forwarded-imports(pex)
309+
310+
;Ensure that any package that was previously imported via forwarding,
311+
;is still imported via forwarding.
312+
for forwarded in previously-forwarded do :
313+
if not currently-forwarded[forwarded] :
314+
add(error-accum, MissingForwardedPackage(package(pex), forwarded))
315+
279316
;============================================================
280317
;===================== Defresolver ==========================
281318
;============================================================
@@ -686,6 +723,39 @@ defn add-qualified-imports (ipackage:IPackage, imps:Tuple<Symbol>) :
686723
;Add imports
687724
sub-imports(ipackage, to-tuple(imports))
688725

726+
;Compute the 'forwarded-inputs' field for the given IPackage.
727+
;Finds all packages that are imported via forwarding.
728+
defn compute-forwarded-imports (ipackage:IPackage,
729+
symtables:SymbolTables) ->
730+
IPackage :
731+
val directly-imported = to-tuple(seq(package-name, imports(ipackage)))
732+
val forwarded = forwarded-imports(symtables, directly-imported)
733+
sub-forwarded-imports(ipackage, to-tuple(forwarded))
734+
735+
;Given the list of direct imports, compute the set of
736+
;all additional packages that are imported via forwarding.
737+
defn forwarded-imports (symtables:SymbolTables,
738+
direct-imports:Seqable<Symbol>) ->
739+
HashSet<Symbol> :
740+
val forwarded-set = within package = transitive-set(direct-imports) :
741+
seq(package-name, filter(forward,imports(symtables,package)))
742+
do(remove{forwarded-set, _}, direct-imports)
743+
forwarded-set
744+
745+
;Helper: Return the name of the package being imported.
746+
defn package-name (i:IImport) : package(i)
747+
748+
;Returns all symbols reachable from the initial set 'xs'
749+
;via the 'next' relation.
750+
defn transitive-set (next:Symbol -> Seqable<Symbol>,
751+
xs:Seqable<Symbol>) ->
752+
HashSet<Symbol> :
753+
val hashset = HashSet<Symbol>()
754+
defn scan (x:Symbol) :
755+
do(scan,next(x)) when add(hashset,x)
756+
do(scan, xs)
757+
hashset
758+
689759
;============================================================
690760
;=================== Symbol Tables ==========================
691761
;============================================================
@@ -696,6 +766,10 @@ defmulti package-exports (st:SymbolTables) -> Tuple<PackageExports>
696766
defmulti new-ipackages (st:SymbolTables) -> Tuple<IPackage>
697767
defmulti load-conditional-dependencies (st:SymbolTables) -> Vector<Symbol>
698768

769+
;Return the explicit import statements (ImportedPackage) listed
770+
;in the given package. Returns empty if the package could not be loaded.
771+
defmulti imports (st:SymbolTables, package:Symbol) -> Tuple<IImport|ImportedPackage>
772+
699773
; Three different import modes:
700774
; - "import" mode: copy all imported definitions into symbol table.
701775
; Corresponds to "import" clause
@@ -907,6 +981,11 @@ defn SymbolTables (packages:Tuple<IPackage|PackageExports>, env:Env, errors:Vect
907981
new SymbolTables :
908982
defmethod get (this, package:Symbol) :
909983
symtables[package]
984+
defmethod imports (this, package:Symbol) :
985+
match(load-package(package)) :
986+
(p:IPackage) : imports(p)
987+
(p:PackageExports) : imported-packages(p)
988+
(f:False) : []
910989
defmethod package-exports (this) :
911990
to-tuple $ filter-by<PackageExports>(values(pkg-table))
912991
defmethod new-ipackages (this) :
@@ -955,7 +1034,7 @@ defn SymbolTable (package-name:Symbol, base:NameMap|Tuple<Export>) :
9551034
val basetable = HashTable<Symbol, List<BaseEntry>>(List())
9561035

9571036

958-
1037+
9591038
; Update an entry in the basetable
9601039
; Assumes the resulting entry should be forwarded
9611040
defn forward-base-entry (e:VEntry, f, xs:List<BaseEntry>) -> List<BaseEntry> :
@@ -964,8 +1043,8 @@ defn SymbolTable (package-name:Symbol, base:NameMap|Tuple<Export>) :
9641043
else : cons(BaseEntry(f(e), true), xs)
9651044

9661045
; Forward symbol table entry to new-package under some prefix by updating its package field
967-
; Concretely:
968-
; Search for existing entry e, update package field if found.
1046+
; Concretely:
1047+
; Search for existing entry e, update package field if found.
9691048
; If not found, simply update package field in e and add
9701049
defn forward-entry (e:VEntry, new-package:Symbol, prefix:String|False) :
9711050
defn fwd (e) : sub-package(e, new-package) ; Update package field
@@ -986,7 +1065,7 @@ defn SymbolTable (package-name:Symbol, base:NameMap|Tuple<Export>) :
9861065
; already been added
9871066
defn add-unique<?E> (e:?E&Equalable, entries:List<E&Equalable>) -> List<E> :
9881067
if contains?(entries, e) : entries
989-
else : cons(e, entries)
1068+
else : cons(e, entries)
9901069

9911070
; Add a VEntry to the symbol table under its prefix
9921071
defn add-entry (e:VEntry, prefix:String|False) :
@@ -1203,6 +1282,15 @@ public defstruct NotCapVar <: ResolveError :
12031282
public defstruct MissingType <: ResolveError :
12041283
src-package:Symbol
12051284
typeid:TypeId
1285+
1286+
;Indicates that a package expected to be imported via forwarding
1287+
;is missing.
1288+
;- src-package: The package that is being analyzed by the resolver.
1289+
;- imported-package: The package that is being imported (via
1290+
; forwarding) that is missing.
1291+
public defstruct MissingForwardedPackage <: ResolveError :
1292+
src-package:Symbol
1293+
imported-package:Symbol
12061294
public defstruct ForwardingCycle <: ResolveError :
12071295
src-packages:Seq<Symbol>
12081296

@@ -1214,6 +1302,10 @@ defmethod print (o:OutputStream, e:MissingType) :
12141302
val FMT = "Missing type: The %~ package requires the %_/%_ type to be defined."
12151303
print(o, FMT % [src-package(e), package(typeid(e)), name(typeid(e))])
12161304

1305+
defmethod print (o:OutputStream, e:MissingForwardedPackage) :
1306+
val FMT = "Missing forwarded package: The %~ package needs the %~ package."
1307+
print(o, FMT % [src-package(e), imported-package(e)])
1308+
12171309
defmethod print (o:OutputStream, e:NoResolve) :
12181310
val FMT = "%_Could not resolve %~."
12191311
print(o, FMT % [infostr(e), name(e)])

compiler/tl-to-el.stanza

+2
Original file line numberDiff line numberDiff line change
@@ -1309,6 +1309,8 @@ defn analyze-imports (p:EPackage, export-table:ExportTable, transient-package?:T
13091309
add-all(pset, seq(ImportedPackage{package(id(rec(_)))}, new-imports))
13101310
val io* = PackageIO(name(p),
13111311
new-imported-packages,
1312+
forwarded-imports(io)
1313+
direct-imports(io),
13121314
to-tuple(new-imports),
13131315
exports(io),
13141316
documentation?(io))

0 commit comments

Comments
 (0)