Skip to content

Commit

Permalink
retry compilation when a type is forwarded or unforwarded
Browse files Browse the repository at this point in the history
  • Loading branch information
tjknoth committed Mar 1, 2024
1 parent 0cbcd2c commit e70ac16
Show file tree
Hide file tree
Showing 13 changed files with 110 additions and 25 deletions.
9 changes: 7 additions & 2 deletions compiler/dl-ir.stanza
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,17 @@ defmethod equal? (p1 : ImportedPackage, p2 : ImportedPackage) :
public defstruct PackageIO :
package: Symbol
imported-packages: Tuple<ImportedPackage> with: (updater => sub-imported-packages)
forwarded-imports: Tuple<Symbol>
direct-imports: Tuple<Symbol>
imports: Tuple<Import> with: (updater => sub-imports)
exports: Tuple<Export> with: (updater => sub-exports)
documentation?:False|String with: (updater => sub-documentation)

public defstruct PackageExports :
package: Symbol
imported-packages: Tuple<ImportedPackage>
forwarded-imports: Tuple<Symbol>
direct-imports: Tuple<Symbol>
exports: Tuple<Export> with: (updater => sub-exports)

;============================================================
Expand Down Expand Up @@ -442,7 +446,7 @@ public defn match? (x:Rec, y:Rec, types-in-io:HashSet<TypeId>|False) -> True|Fal
;============================================================

public defn to-package-exports (io:PackageIO) :
PackageExports(package(io), imported-packages(io), exports(io))
PackageExports(package(io), imported-packages(io), forwarded-imports(io), direct-imports(io), exports(io))

public defn to-package-exports? (io:PackageIO|False) :
match(io:PackageIO) :
Expand Down Expand Up @@ -603,7 +607,8 @@ defsyntax dl-ir :
?imports:#import ...
?exports:#export ...) :
;[TODO] Add doc string reader macro. Defaulted to false for now.
PackageIO(name, to-tuple(map({ImportedPackage(_)}, ips)), to-tuple(imports), to-tuple(exports), false)
;[TODO]: is the empty direct-import list OK?
PackageIO(name, to-tuple(map({ImportedPackage(_)}, ips)), [], [], to-tuple(imports), to-tuple(exports), false)

defproduction dtype : DType
defrule dtype = (byte) : DByte()
Expand Down
2 changes: 1 addition & 1 deletion compiler/el-ir.stanza
Original file line number Diff line number Diff line change
Expand Up @@ -1065,7 +1065,7 @@ defsyntax el-ir :
defrule epackage = (package ?name:#symbol : (?ss:#tstmt ... #E)) :
val ins = to-tuple(filter-by<Import>(ss))
val exs = to-tuple(filter-by<Export>(ss))
val io = PackageIO(name, [], ins, exs, false)
val io = PackageIO(name, [], [], [], ins, exs, false)
val es = to-tuple(filter-by<ETExp>(ss))
EPackage(io, to-tuple(es))

Expand Down
2 changes: 1 addition & 1 deletion compiler/el.stanza
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ defn collapse (epackages:Tuple<EPackage>) -> EPackage :
for ex in exports(packageio(e)) seq :
val n* = global-rec-ids[id(rec(ex))]
sub-n(ex, n*)
PackageIO(`prog, [], [], exports*, false)
PackageIO(`prog, [], [], [], [], exports*, false)

;Rename one specific package
defn renamed-exps (epackage:EPackage) :
Expand Down
15 changes: 10 additions & 5 deletions compiler/front-end.stanza
Original file line number Diff line number Diff line change
Expand Up @@ -540,11 +540,16 @@ defn FrontEnd (sys:FrontEndInputs) -> FrontEnd :
val resolved = resolve-packages(package-names, errorlist)
val new-inputs = HashTable<Symbol,PackageInFile>()
for e in errorlist do :
match(e:MissingType) :
match(source-file?(src-package(e))) :
(file:String) : new-inputs[src-package(e)] = PackageInFile(src-package(e), file)
(file:False) : throw(FrontEndErrors(errorlist))
else : throw(FrontEndErrors(errorlist))
match(e) :
(e:MissingType) :
match(source-file?(src-package(e))) :
(file:String) : new-inputs[src-package(e)] = PackageInFile(src-package(e), file)
(file:False) : throw(FrontEndErrors(errorlist))
(e:MissingForwardedPackage) :
match(source-file?(src-package(e))) :
(file:String) : new-inputs[src-package(e)] = PackageInFile(src-package(e), file)
(file:False) : throw(FrontEndErrors(errorlist))
(otherwise) : throw(FrontEndErrors(errorlist))
[resolved, to-tuple(values(new-inputs))]

defn resolve-packages! (package-names:Tuple<Symbol>) -> ResolverResult :
Expand Down
1 change: 1 addition & 0 deletions compiler/il-ir.stanza
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public defstruct IPackage :
name: Symbol
documentation?: IDoc|False
imports: Tuple<IImport> with: (updater => sub-imports)
forwarded-imports: Tuple<Symbol> with: (updater => sub-forwarded-imports)
exps: List<IExp> with: (updater => sub-exps)
info: AbsoluteFileInfo|False
namemap: NameMap with: (default => void, updater => sub-namemap)
Expand Down
3 changes: 2 additions & 1 deletion compiler/il-to-tl.stanza
Original file line number Diff line number Diff line change
Expand Up @@ -169,11 +169,12 @@ defn to-imported-package (i:IImport) -> ImportedPackage :
;The imported/exported entries will be populated
;after type inference.
defn to-packageio (ipackage:IPackage) -> PackageIO :
val direct-imports = to-tuple $ seq(package, imports(ipackage))
val imports = to-tuple(seq(to-imported-package, imports(ipackage)))
val doc? = match(documentation?(ipackage)) :
(d:IDoc) : value(string(d) as ILiteral) as String
(f:False) : false
PackageIO(name(ipackage), imports, [], [], doc?)
PackageIO(name(ipackage), imports, forwarded-imports(ipackage), direct-imports, [], [], doc?)

;============================================================
;=============== Conversion Functions =======================
Expand Down
6 changes: 3 additions & 3 deletions compiler/input.stanza
Original file line number Diff line number Diff line change
Expand Up @@ -468,23 +468,23 @@ defn split-packages (e:IExp,
val e = all-exps[i + 1] as IDefPackage
val [exps, end] = package-exps(i + 2)
val imports = to-tuple $ seq(to-iimport, imports(e) as List<IImportExp>)
add(packages, IPackage(name!(e), doc, imports, exps, info(e)))
add(packages, IPackage(name!(e), doc, imports, [], exps, info(e)))
loop(end)

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

;Default package.
WithinPackageExp:
val [exps, end] = package-exps(i)
val info = info(head(exps)) when not empty?(exps)
val name = gensym(`default)
add(packages, IPackage(name, false, default-imports, exps, info))
add(packages, IPackage(name, false, default-imports, [], exps, info))
loop(end)

;Return packages
Expand Down
2 changes: 2 additions & 0 deletions compiler/pkg-serializer.stanza
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,8 @@ defserializer PkgSerializer (include-asm?:True|False) :
deftype packageio (PackageIO) :
package:symbol
imported-packages:tuple(importedpackage)
forwarded-imports:tuple(symbol)
direct-imports:tuple(symbol)
imports:tuple(dimport)
exports:tuple(dexport)
documentation?:opt(string)
Expand Down
1 change: 1 addition & 0 deletions compiler/repl.stanza
Original file line number Diff line number Diff line change
Expand Up @@ -800,6 +800,7 @@ defn REPLEnv () :
IPackage(gensym(`repl),
false,
to-tuple(values(exp-imports)),
[]
List(wrap-display-result(exp)),
info(exp))

Expand Down
88 changes: 78 additions & 10 deletions compiler/resolver.stanza
Original file line number Diff line number Diff line change
Expand Up @@ -159,15 +159,15 @@ public defn resolve-il (packages:Tuple<IPackage|PackageExports>, env:Env) -> Res
add-all(cond-dependencies, ds)
val ps = new-ipackages(symtables)
for p in ps do :
val p* = resolve-package(p, symtables, package-priority(env), error-accum)
val p* = resolve-package(p, symtables, package-priority(env), error-accum, env)
match(p*:IPackage) :
add(import-lists*, ImportList(name(p), imports(p)))
add(ipackages*, p*)
resolve-ipackages() when not empty?(ps) or not empty?(ds)

;Resolve type dependencies from pkgs
check-exported-types(symtables, ipackages*, package-exports(symtables), error-accum)

check-forwarded-imports(symtables, package-exports(symtables), env, error-accum)

;Compute initialization order
defn init-order () :
Expand Down Expand Up @@ -219,7 +219,8 @@ public defn resolve-il (packages:Tuple<IPackage|PackageExports>, env:Env) -> Res
defn resolve-package (ipackage:IPackage,
symtables:SymbolTables,
priority:False|(Symbol -> Int),
error-accum:Vector<ResolveError>) -> IPackage|False :
error-accum:Vector<ResolveError>,
env:Env) -> IPackage|False :
;Retrieve symbol table for the package to resolve
val num-errors = length(error-accum)
val symtable = symtables[name(ipackage)] as SymbolTable
Expand All @@ -228,7 +229,9 @@ defn resolve-package (ipackage:IPackage,
map(resolve-exp{_, eng}, exps(ipackage))
val ipackage* = sub-exps(ipackage, exps*)
if length(error-accum) == num-errors :
add-qualified-imports(ipackage*, qualified-imports(eng))
ipackage*
$> {add-qualified-imports(_, qualified-imports(eng))}
$> {record-forwarded-imports(_, env)}

;<doc>=======================================================
;=================== Check Type Dependencies ================
Expand Down Expand Up @@ -257,10 +260,38 @@ issue an error if it doesn't.
;=======================================================<doc>
;+<5218000E>

defn check-forwarded-imports (symtables:SymbolTables, pexs:Tuple<PackageExports>, env:Env, error-accum:Vector<ResolveError>) -> False :
; Overloaded helpers for dealing with IImport or ImportedPackage
defn matches? (i:IImport, s:Symbol) : /package(i) == s
defn matches? (i:ImportedPackage, s:Symbol) : package-name(i) == s
defn get-package (p:Symbol) : imported-package(env, p) as IPackage|PackageExports
defn get-package (p:IImport) : get-package(/package(p))
defn get-package (p:ImportedPackage) : get-package(package-name(p))

; does the transitive closure of package forward a package named p?
defn forwards? (p:Symbol, package:PackageExports|IPackage) -> True|False :
val forwarded-imports = {filter(forward, _)} $
match(package) :
(package*:IPackage) : imports(package*)
(package*:PackageExports) : imported-packages(package*)
if any?({matches?(_, p)}, forwarded-imports) : true
else : any?({forwards?(p, get-package(_))}, forwarded-imports)

; Check all PackageExports
for pex in pexs do :
for i in imported-packages(pex) do :
; make sure that any non-directly-imported package is still
; available via forwarding
if contains?(forwarded-imports(pex), package-name(i)) :
val direct-imports = to-tuple $ seq(get-package, direct-imports(pex))
; search direct imports for the package
if not any?({forwards?(package-name(i), _)}, direct-imports) :
add(error-accum, MissingForwardedPackage(package(pex), package-name(i)))

defn check-exported-types (symtables:SymbolTables, pkgs:Collection<IPackage>, pexs:Tuple<PackageExports>, error-accum:Vector<ResolveError>) :
;Ensure that all types referenced in exports are defined
for pex in pexs do :
;Check for existence of typeid
;Check for existence of typeid
defn check-for-type (e:TypeId) :
val symtable = symtables[package(e)]
match(symtable:SymbolTable) :
Expand Down Expand Up @@ -686,14 +717,44 @@ defn add-qualified-imports (ipackage:IPackage, imps:Tuple<Symbol>) :
;Add imports
sub-imports(ipackage, to-tuple(imports))

defn record-forwarded-imports (ipackage:IPackage, env:Env) -> IPackage :
; Accumulator
val forwarded-set = HashSet<Symbol>()

; recursively store all forwarded imports
defn get-forwarded-imports (i:IImport|ImportedPackage) :
val name =
match(i) :
(i*:IImport) : package(i*)
(i*:ImportedPackage) : package-name(i*)
val p = imported-package(env, name) ;get?(package-table, name)
match(p) :
(p:IPackage) :
for i* in imports(p) do :
if forward(i*) :
add(forwarded-set, package(i*))
get-forwarded-imports(i*)
(p:PackageExports) :
for i* in imported-packages(p) do :
if forward(i*) :
add(forwarded-set, package-name(i*))
get-forwarded-imports(i*)
(f:False) : false ; should not happen

; Get imports that are forwarded via all top-level imports
for i in imports(ipackage) do : get-forwarded-imports(i)
; Update IPackage definition
sub-forwarded-imports(ipackage, to-tuple(forwarded-set))


;============================================================
;=================== Symbol Tables ==========================
;============================================================

deftype SymbolTables
defmulti get (st:SymbolTables, package:Symbol) -> SymbolTable|False
defmulti package-exports (st:SymbolTables) -> Tuple<PackageExports>
defmulti new-ipackages (st:SymbolTables) -> Tuple<IPackage>
defmulti new-ipackages (st:SymbolTables) -> Tuple<IPackage> ; Note: This can only be called once: it clears the accumulator
defmulti load-conditional-dependencies (st:SymbolTables) -> Vector<Symbol>

; Three different import modes:
Expand Down Expand Up @@ -955,7 +1016,7 @@ defn SymbolTable (package-name:Symbol, base:NameMap|Tuple<Export>) :
val basetable = HashTable<Symbol, List<BaseEntry>>(List())



; Update an entry in the basetable
; Assumes the resulting entry should be forwarded
defn forward-base-entry (e:VEntry, f, xs:List<BaseEntry>) -> List<BaseEntry> :
Expand All @@ -964,8 +1025,8 @@ defn SymbolTable (package-name:Symbol, base:NameMap|Tuple<Export>) :
else : cons(BaseEntry(f(e), true), xs)

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

; Add a VEntry to the symbol table under its prefix
defn add-entry (e:VEntry, prefix:String|False) :
Expand Down Expand Up @@ -1203,6 +1264,9 @@ public defstruct NotCapVar <: ResolveError :
public defstruct MissingType <: ResolveError :
src-package:Symbol
typeid:TypeId
public defstruct MissingForwardedPackage <: ResolveError :
src-package:Symbol
imported-package:Symbol
public defstruct ForwardingCycle <: ResolveError :
src-packages:Seq<Symbol>

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

defmethod print (o:OutputStream, e:MissingForwardedPackage) :
val FMT = "Missing forwarded package: The %~ package needs the %~ package."
print(o, FMT % [src-package(e), imported-package(e)])

defmethod print (o:OutputStream, e:NoResolve) :
val FMT = "%_Could not resolve %~."
print(o, FMT % [infostr(e), name(e)])
Expand Down
2 changes: 2 additions & 0 deletions compiler/tl-to-el.stanza
Original file line number Diff line number Diff line change
Expand Up @@ -1309,6 +1309,8 @@ defn analyze-imports (p:EPackage, export-table:ExportTable, transient-package?:T
add-all(pset, seq(ImportedPackage{package(id(rec(_)))}, new-imports))
val io* = PackageIO(name(p),
new-imported-packages,
forwarded-imports(io)
direct-imports(io),
to-tuple(new-imports),
exports(io),
documentation?(io))
Expand Down
2 changes: 1 addition & 1 deletion compiler/vm-ir.stanza
Original file line number Diff line number Diff line change
Expand Up @@ -1173,7 +1173,7 @@ defsyntax vmcode :
?stmts:#tstmt ...) :
val ins = to-tuple(filter-by<Import>(stmts))
val exs = to-tuple(filter-by<Export>(stmts))
val io = PackageIO(name, [], ins, exs, false)
val io = PackageIO(name, [], [], [], ins, exs, false)
val gs = to-tuple(filter-by<VMGlobal>(stmts))
val ds = to-tuple(filter-by<VMData>(stmts))
val cts = to-tuple(filter-by<VMConst>(stmts))
Expand Down
2 changes: 1 addition & 1 deletion compiler/vm.stanza
Original file line number Diff line number Diff line change
Expand Up @@ -931,7 +931,7 @@ public defn load (vm:VirtualMachine, vmps:Collection<VMPackage>, keep-existing-g

public defn unload (vm:VirtualMachine, ps:Collection<Symbol>) :
val vmps = to-tuple $ for p in ps seq :
val io = PackageIO(p, [], [], [], false)
val io = PackageIO(p, [], [], [], [], [], false)
VMPackage(io, false, [], [], [], [], [], [], [], [], , VMDebugNameTable([]), VMDebugInfoTable([]), VMSafepointTable([]))
load(vm, vmps, false)

Expand Down

0 comments on commit e70ac16

Please sign in to comment.