-
Notifications
You must be signed in to change notification settings - Fork 31
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Refactor/replace environments by substitution #787
Changes from 13 commits
9a929ae
b779413
9ffbcf0
6b261c6
e5f2c27
15145c1
2832f70
a9f2583
19042d4
eeedccc
ae9b43d
54e1a91
84beb0b
07e2740
d9cd332
2b2e53e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,4 +3,5 @@ package effekt | |
class Backend { | ||
val compiler = generator.js.JavaScriptWeb() | ||
val runner = () | ||
val name = "js-web" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -97,19 +97,21 @@ object Type { | |
/** | ||
* Function types are the only type constructor that we have subtyping on. | ||
*/ | ||
def merge(tpe1: ValueType, tpe2: ValueType, covariant: Boolean): ValueType = (tpe1, tpe2) match { | ||
case (ValueType.Boxed(btpe1, capt1), ValueType.Boxed(btpe2, capt2)) => | ||
def merge(tpe1: ValueType, tpe2: ValueType, covariant: Boolean): ValueType = (tpe1, tpe2, covariant) match { | ||
case (tpe1, tpe2, covariant) if tpe1 == tpe2 => tpe1 | ||
case (ValueType.Boxed(btpe1, capt1), ValueType.Boxed(btpe2, capt2), covariant) => | ||
ValueType.Boxed(merge(btpe1, btpe2, covariant), merge(capt1, capt2, covariant)) | ||
case (tpe1, tpe2) if covariant => | ||
if (isSubtype(tpe1, tpe2)) tpe2 else tpe1 | ||
case (tpe1, tpe2) if !covariant => | ||
if (isSubtype(tpe1, tpe2)) tpe1 else tpe2 | ||
case (TBottom, tpe2, true) => tpe2 | ||
case (tpe1, TBottom, true) => tpe1 | ||
case (TTop, tpe2, true) => TTop | ||
case (tpe1, TTop, true) => TTop | ||
case (TBottom, tpe2, false) => TBottom | ||
case (tpe1, TBottom, false) => TBottom | ||
case (TTop, tpe2, false) => tpe2 | ||
case (tpe1, TTop, false) => tpe1 | ||
// TODO this swallows a lot of bugs that we NEED to fix | ||
case _ => tpe1 | ||
} | ||
private def isSubtype(tpe1: ValueType, tpe2: ValueType): Boolean = (tpe1, tpe2) match { | ||
case (tpe1, TTop) => true | ||
case (TBottom, tpe1) => true | ||
case _ => false // conservative :) | ||
// sys error s"Cannot compare ${tpe1} ${tpe2} in ${covariant}" // conservative :) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you ever want to fix more bugs, comment this in again. |
||
} | ||
|
||
def merge(tpe1: BlockType, tpe2: BlockType, covariant: Boolean): BlockType = (tpe1, tpe2) match { | ||
|
@@ -129,12 +131,12 @@ object Type { | |
assert(targs.size == tparams.size, "Wrong number of type arguments") | ||
assert(cargs.size == cparams.size, "Wrong number of capture arguments") | ||
|
||
val vsubst = (tparams zip targs).toMap | ||
val tsubst = (tparams zip targs).toMap | ||
val csubst = (cparams zip cargs).toMap | ||
BlockType.Function(Nil, Nil, | ||
vparams.map { tpe => substitute(tpe, vsubst, Map.empty) }, | ||
bparams.map { tpe => substitute(tpe, vsubst, Map.empty) }, | ||
substitute(result, vsubst, csubst)) | ||
vparams.map { tpe => substitute(tpe, tsubst, Map.empty) }, | ||
bparams.map { tpe => substitute(tpe, tsubst, Map.empty) }, | ||
substitute(result, tsubst, csubst)) | ||
} | ||
|
||
def substitute(capt: Captures, csubst: Map[Id, Captures]): Captures = capt.flatMap { | ||
|
@@ -206,7 +208,11 @@ object Type { | |
case Stmt.Var(id, init, cap, body) => body.tpe | ||
case Stmt.Get(id, capt, tpe) => tpe | ||
case Stmt.Put(id, capt, value) => TUnit | ||
case Stmt.Reset(body) => body.returnType | ||
case Stmt.Reset(BlockLit(_, _, _, prompt :: Nil, body)) => prompt.tpe match { | ||
case TPrompt(tpe) => tpe | ||
case _ => ??? | ||
} | ||
case Stmt.Reset(body) => ??? | ||
case Stmt.Shift(prompt, body) => body.bparams match { | ||
case core.BlockParam(id, BlockType.Interface(ResumeSymbol, List(result, answer)), captures) :: Nil => result | ||
case _ => ??? | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,6 +21,8 @@ object Optimizer extends Phase[CoreTransformed, CoreTransformed] { | |
|
||
def optimize(source: Source, mainSymbol: symbols.Symbol, core: ModuleDecl)(using Context): ModuleDecl = | ||
|
||
val isLLVM = Context.config.backend().name == "llvm" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is REALLY hacky. Another solution would be to first optimize and then do polymorphism boxing. However, this alternative currently (I didn't try to find out why) fails a lot of test. |
||
|
||
var tree = core | ||
|
||
// (1) first thing we do is simply remove unused definitions (this speeds up all following analysis and rewrites) | ||
|
@@ -37,18 +39,16 @@ object Optimizer extends Phase[CoreTransformed, CoreTransformed] { | |
|
||
def normalize(m: ModuleDecl) = { | ||
val anfed = BindSubexpressions.transform(m) | ||
val normalized = Normalizer.normalize(Set(mainSymbol), anfed, Context.config.maxInlineSize().toInt) | ||
Deadcode.remove(mainSymbol, normalized) | ||
val normalized = Normalizer.normalize(Set(mainSymbol), anfed, Context.config.maxInlineSize().toInt, isLLVM) | ||
val live = Deadcode.remove(mainSymbol, normalized) | ||
val tailRemoved = RemoveTailResumptions(live) | ||
tailRemoved | ||
} | ||
|
||
// (3) normalize once and remove beta redexes | ||
// (3) normalize a few times (since tail resumptions might only surface after normalization and leave dead Resets) | ||
tree = Context.timed("normalize-1", source.name) { normalize(tree) } | ||
|
||
// (4) optimize continuation capture in the tail-resumptive case | ||
tree = Context.timed("tail-resumptions", source.name) { RemoveTailResumptions(tree) } | ||
|
||
// (5) normalize again to clean up and remove new redexes | ||
tree = Context.timed("normalize-2", source.name) { normalize(tree) } | ||
tree = Context.timed("normalize-3", source.name) { normalize(tree) } | ||
|
||
tree | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change is particularly significant...