Skip to content
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

Multiple Return Values #272

Draft
wants to merge 88 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 85 commits
Commits
Show all changes
88 commits
Select commit Hold shift + click to select a range
6b823d1
old files
fritzladwig Dec 7, 2022
aa8b5cb
Factor out optimizations to separate file
b-studios Oct 31, 2022
5395a8e
Update `Optimizer` for new core.
marzipankaiser Dec 7, 2022
4d45049
Optimizer after Aggregate
marzipankaiser Dec 7, 2022
694b51a
rewrite of functions complete. Tests pending
fritzladwig Dec 15, 2022
bafe3c4
dealiasing seems functional
fritzladwig Dec 19, 2022
6eb700d
dealiasing should work now
fritzladwig Dec 30, 2022
c273ae5
Static Argument Transformation WIP
fritzladwig Jan 19, 2023
f8d0c29
Static Argument Transformation added
fritzladwig Feb 4, 2023
4eaad1d
added inlining of unique and small functions
fritzladwig Feb 11, 2023
b591cff
deadcode elimination ignores exports now
fritzladwig Feb 15, 2023
0eefbc2
constant propagation
fritzladwig Feb 15, 2023
d04faf5
beta reduction
fritzladwig Feb 15, 2023
85978bf
renaming not yet added to inlining
fritzladwig Feb 23, 2023
454532a
general inlining disabled
fritzladwig Feb 24, 2023
451525a
small changes that appear to impact test results
fritzladwig Feb 24, 2023
1d7377e
all inlining disabled
fritzladwig Feb 24, 2023
c0d2ce9
substitute didn't look into implementations and operations...
fritzladwig Feb 24, 2023
5b02e20
inlining bugfix
fritzladwig Feb 25, 2023
3a8f996
enabled renaming when inlining
fritzladwig Feb 25, 2023
c4cd529
some documentation and another bugfix
fritzladwig Feb 28, 2023
eb49413
another beta reduction pass, might fix tests
fritzladwig Feb 28, 2023
7bf5ab8
bug fixes
fritzladwig Mar 1, 2023
9074472
added benchmarks to branch
fritzladwig Mar 1, 2023
5e11d28
added optimizer options to config
fritzladwig Mar 6, 2023
8b6c5d0
added some more documentation
fritzladwig Mar 14, 2023
48617d9
Remove tupleLiteral
denhie May 12, 2023
76b5276
Remove tuple syntactic sugar from types
denhie May 17, 2023
1d5b757
Modify tests to use explicit tuple constructor
denhie May 17, 2023
8ef7dfc
Add simple test for multiple return values
denhie May 17, 2023
6577958
old files
fritzladwig Dec 7, 2022
84795af
Factor out optimizations to separate file
b-studios Oct 31, 2022
60700c9
Optimizer after Aggregate
marzipankaiser Dec 7, 2022
6fd6bd3
rewrite of functions complete. Tests pending
fritzladwig Dec 15, 2022
3aea6b1
dealiasing seems functional
fritzladwig Dec 19, 2022
de0e898
dealiasing should work now
fritzladwig Dec 30, 2022
16bd12f
Static Argument Transformation WIP
fritzladwig Jan 19, 2023
d6fac7c
Static Argument Transformation added
fritzladwig Feb 4, 2023
736747b
added inlining of unique and small functions
fritzladwig Feb 11, 2023
7cd2f30
deadcode elimination ignores exports now
fritzladwig Feb 15, 2023
7e04e92
constant propagation
fritzladwig Feb 15, 2023
3626576
beta reduction
fritzladwig Feb 15, 2023
dfbacb7
renaming not yet added to inlining
fritzladwig Feb 23, 2023
3d947bf
general inlining disabled
fritzladwig Feb 24, 2023
d2cf0bd
small changes that appear to impact test results
fritzladwig Feb 24, 2023
2cf8689
substitute didn't look into implementations and operations...
fritzladwig Feb 24, 2023
29a05ef
inlining bugfix
fritzladwig Feb 25, 2023
773d69c
enabled renaming when inlining
fritzladwig Feb 25, 2023
7b57a89
some documentation and another bugfix
fritzladwig Feb 28, 2023
7d474dd
bug fixes
fritzladwig Mar 1, 2023
e864867
added benchmarks to branch
fritzladwig Mar 1, 2023
64f6516
added optimizer options to config
fritzladwig Mar 6, 2023
be558f1
added some more documentation
fritzladwig Mar 14, 2023
81780fa
Remove tupleLiteral
denhie May 12, 2023
49c376a
Remove tuple syntactic sugar from types
denhie May 17, 2023
1c79967
Modify tests to use explicit tuple constructor
denhie May 17, 2023
ce3dd71
Add simple test for multiple return values
denhie May 17, 2023
a9b5fda
Return list of terms
denhie May 23, 2023
35b9cd2
Return list of terms
denhie May 23, 2023
45d1d1f
Merge branch 'feature/multiple-return-values' of github.com:effekt-la…
denhie May 23, 2023
8e31679
make compilable
denhie Jun 20, 2023
1b1d5b6
Make most tests work
denhie Jul 17, 2023
3fa4202
Remove leftovers from optimization PR
denhie Jul 18, 2023
9fcab70
Improve pretty printing
denhie Aug 29, 2023
be3c155
Functions return multiple values
denhie Aug 29, 2023
21150b6
catch multiple return values in backend
denhie Aug 29, 2023
bf1886d
multiple return values in machine
denhie Aug 29, 2023
2b4e4fe
multiple return values in ML
denhie Aug 29, 2023
6456db7
infer type for expressions returning multiple values
denhie Aug 29, 2023
86ddb95
stmts in lifted return multiple values
denhie Aug 29, 2023
0f23b83
ids function for Definitions returning a list of ids.
denhie Sep 25, 2023
0a66d8f
Definition.symbol now return a list of symbols corresponding to the l…
denhie Sep 25, 2023
f09152d
Remove TODOs
denhie Sep 25, 2023
2f4e95f
pure in monadic js accepts multiple expressions.
denhie Sep 25, 2023
d7b7a32
Remove TODOs
denhie Sep 25, 2023
50642f2
Pattern matching on multiple return values
denhie Sep 25, 2023
2ccc64d
Valdef checks only against annotation, if an annotation for every val…
denhie Nov 2, 2023
174f35c
break down big boolean expression
denhie Nov 16, 2023
441c144
rename tpe to tpes to reflect type change
denhie Nov 16, 2023
5038350
revert auto-formatting
denhie Nov 16, 2023
ea5dff5
remove unused code
denhie Nov 16, 2023
831ea16
Try to maintain invariant that there is only one symbol per definition
phischu Nov 15, 2023
47a0b3b
Add default field to ValDef
phischu Nov 16, 2023
d4bd084
Apply suggestions from review
phischu Nov 16, 2023
d2e089b
Merge pull request #312 from effekt-lang/feature/multiple-return-valu…
denhie Nov 16, 2023
176fd62
Avoid class cast exception
phischu Nov 24, 2023
7fea84e
Decide number of returns before pretty printing
phischu Dec 4, 2023
74d1e9d
Insert bindings further down
phischu Dec 4, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions effekt/jvm/src/main/scala/effekt/Repl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ class Repl(driver: Driver) extends REPL[Tree, EffektConfig, EffektError] {
runFrontend(StringSource(""), module.make(UnitLit()), config) { cu =>
module.definitions.foreach {
case u: Def =>
outputCode(DeclPrinter(context.symbolOf(u)), config)
outputCode(DeclPrinter(List(u.id.symbol)), config)
}
}
}
Expand All @@ -123,7 +123,7 @@ class Repl(driver: Driver) extends REPL[Tree, EffektConfig, EffektError] {
// TODO this is a bit ad-hoc
val mainSym = mod.terms("main").head
val mainTpe = context.functionTypeOf(mainSym)
output.emitln(pp"${mainTpe.result}")
output.emitln(pp"${mainTpe.result.map{ t => pp"$t"}.mkString(", ")}")
}

case Success(other, _) =>
Expand Down Expand Up @@ -199,14 +199,14 @@ class Repl(driver: Driver) extends REPL[Tree, EffektConfig, EffektError] {
output.emitln(s"Imported Types\n==============")
cu.types.toList.sortBy { case (n, _) => n }.collect {
case (name, sym) if !sym.isSynthetic =>
outputCode(DeclPrinter(sym), config)
outputCode(DeclPrinter(List(sym)), config)
}
output.emitln(s"\nImported Functions\n==================")
cu.terms.toList.sortBy { case (n, _) => n }.foreach {
case (name, syms) =>
syms.collect {
case sym if !sym.isSynthetic =>
outputCode(DeclPrinter(sym), config)
outputCode(DeclPrinter(List(sym)), config)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like that DeclPrinter now takes a list... This feels wrong.

}
}
module = extendedImports
Expand All @@ -220,15 +220,15 @@ class Repl(driver: Driver) extends REPL[Tree, EffektConfig, EffektError] {
module = extendedDefs

// try to find the symbol for the def to print the type
(context.symbolOption(d.id) match {
context.symbolOption(d.id) match {
case Some(v: ValueSymbol) =>
Some(context.valueTypeOf(v))
Some(v, context.valueTypeOf(v))
case Some(b: BlockSymbol) =>
Some(context.blockTypeOf(b))
Some(b, context.blockTypeOf(b))
case t =>
None
}) map { tpe =>
outputCode(pp"${d.id}: ${tpe}", config)
} map { case (id, tpe) =>
outputCode(pp"${id}: ${tpe}", config)
}
}

Expand Down Expand Up @@ -308,7 +308,7 @@ class Repl(driver: Driver) extends REPL[Tree, EffektConfig, EffektError] {
*/
def make(expr: Term): ModuleDecl = {

val body = Return(expr)
val body = Return(List(expr))

ModuleDecl("interactive", imports,
definitions :+ FunDef(IdDef("main"), Nil, Nil, Nil, None,
Expand Down
29 changes: 19 additions & 10 deletions effekt/jvm/src/main/scala/effekt/Server.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ import effekt.util.messages.EffektError

import kiama.util.{ Filenames, Position, Services, Source }
import kiama.output.PrettyPrinterTypes.Document

import org.eclipse.lsp4j.{ Diagnostic, DocumentSymbol, SymbolKind, ExecuteCommandParams }
import org.eclipse.lsp4j.{Diagnostic, DocumentSymbol, ExecuteCommandParams, SymbolKind}

/**
* effekt.Intelligence <--- gathers information -- LSPServer --- provides LSP interface ---> kiama.Server
Expand Down Expand Up @@ -201,15 +200,19 @@ trait LSPServer extends kiama.util.Server[Tree, EffektConfig, EffektError] with
* Also, it is necessary to be able to manually set the code action kind (and register them on startup).
* This way, we can use custom kinds like `refactor.closehole` that can be mapped to keys.
*/
def inferEffectsAction(fun: FunDef)(using C: Context): Option[TreeAction] = for {
def inferEffectsAction(fun: FunDef)(using C: Context): Option[TreeAction] =
val symbol = fun.symbol
for {
// the inferred type
(tpe, eff) <- C.inferredTypeAndEffectOption(fun)
// the annotated type
ann = for {
result <- fun.symbol.annotatedResult
effects <- fun.symbol.annotatedEffects
result <- symbol.annotatedResult
effects <- symbol.annotatedEffects
} yield (result, effects)
if ann.map { needsUpdate(_, (tpe, eff)) }.getOrElse(true)
if ann.map {
(y, eff1) => needsUpdate((y, eff1), (tpe, eff))
}.getOrElse(true)
res <- CodeAction("Update return type with inferred effects", fun.ret, s": $tpe / $eff")
} yield res

Expand All @@ -231,10 +234,16 @@ trait LSPServer extends kiama.util.Server[Tree, EffektConfig, EffektError] with
}
} yield res

def needsUpdate(annotated: (ValueType, Effects), inferred: (ValueType, Effects))(using Context): Boolean = {
val (tpe1, effs1) = annotated
val (tpe2, effs2) = inferred
tpe1 != tpe2 || effs1 != effs2
def needsUpdate(annotated: (List[ValueType], Effects), inferred: (List[ValueType], Effects))(using Context): Boolean = {
val (tpes1, effs1) = annotated
val (tpes2, effs2) = inferred

val differentArity = tpes1.size != tpes2.size
val differentEffects = effs1 != effs2

def differentTypes = (tpes1 zip tpes2).forall { case (tpe1, tpe2) => tpe1 != tpe2 }

differentArity || differentEffects || differentTypes
}

case class CaptureInfo(location: Location, captureText: String)
Expand Down
10 changes: 5 additions & 5 deletions effekt/jvm/src/test/scala/effekt/PolymorphismBoxingTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -72,14 +72,14 @@ abstract class AbstractPolymorphismBoxingTests extends munit.FunSuite {
}

override def stmt: PartialFunction[Stmt, Stmt] = {
case core.Scope(definitions, rest) => withBindings(definitions.map{
case core.Definition.Def(id, _) => id
case core.Definition.Let(id, _) => id
case core.Scope(definitions, rest) => withBindings(definitions.flatMap{
case core.Definition.Def(id, _) => List(id)
case core.Definition.Let(ids, _) => ids
}){
core.Scope(definitions map rewrite, rewrite(rest))
}
case core.Val(id, binding, body) => withBinding(id){
core.Val(rewrite(id), rewrite(binding), rewrite(body))
case core.Val(ids, binding, body) => withBindings(ids){
core.Val(ids.map(rewrite), rewrite(binding), rewrite(body))
}
case core.State(id, init, reg, body) => withBinding(id){
core.State(rewrite(id), rewrite(init), rewrite(reg), rewrite(body))
Expand Down
18 changes: 9 additions & 9 deletions effekt/shared/src/main/scala/effekt/Intelligence.scala
Original file line number Diff line number Diff line change
Expand Up @@ -122,10 +122,10 @@ trait Intelligence {
def getInfoOf(sym: Symbol)(implicit C: Context): Option[SymbolInfo] = PartialFunction.condOpt(resolveCallTarget(sym)) {

case b: ExternFunction =>
SymbolInfo(b, "External function definition", Some(DeclPrinter(b)), None)
SymbolInfo(b, "External function definition", Some(DeclPrinter(List(b))), None)

case f: UserFunction if C.functionTypeOption(f).isDefined =>
SymbolInfo(f, "Function", Some(DeclPrinter(f)), None)
SymbolInfo(f, "Function", Some(DeclPrinter(List(f))), None)

case f: Operation =>
val ex =
Expand All @@ -147,30 +147,30 @@ trait Intelligence {
|handled by the handler. This is important when considering higher-order functions.
|""".stripMargin

SymbolInfo(f, "Effect operation", Some(DeclPrinter(f)), Some(ex))
SymbolInfo(f, "Effect operation", Some(DeclPrinter(List(f))), Some(ex))

case f: EffectAlias =>
SymbolInfo(f, "Effect alias", Some(DeclPrinter(f)), None)
SymbolInfo(f, "Effect alias", Some(DeclPrinter(List(f))), None)

case t: TypeAlias =>
SymbolInfo(t, "Type alias", Some(DeclPrinter(t)), None)
SymbolInfo(t, "Type alias", Some(DeclPrinter(List(t))), None)

case t: ExternType =>
SymbolInfo(t, "External type definition", Some(DeclPrinter(t)), None)
SymbolInfo(t, "External type definition", Some(DeclPrinter(List(t))), None)

case t: ExternInterface =>
SymbolInfo(t, "External interface definition", Some(DeclPrinter(t)), None)
SymbolInfo(t, "External interface definition", Some(DeclPrinter(List(t))), None)

case t: ExternResource =>
SymbolInfo(t, "External resource definition", Some(DeclPrinter(t)), None)
SymbolInfo(t, "External resource definition", Some(DeclPrinter(List(t))), None)

case c: Constructor =>
val ex = pp"""|Instances of data types like `${c.tpe}` can only store
|_values_, not _blocks_. Hence, constructors like `${c.name}` only have
|value parameter lists, not block parameters.
|""".stripMargin

SymbolInfo(c, s"Constructor of data type `${c.tpe}`", Some(DeclPrinter(c)), Some(ex))
SymbolInfo(c, s"Constructor of data type `${c.tpe}`", Some(DeclPrinter(List(c))), Some(ex))

case c: BlockParam =>
val signature = C.functionTypeOption(c).map { tpe => pp"{ ${c.name}: ${tpe} }" }
Expand Down
21 changes: 11 additions & 10 deletions effekt/shared/src/main/scala/effekt/Namer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ object Namer extends Phase[Parsed, NameResolved] {
*/
def preresolve(d: Def)(using Context): Unit = Context.focusing(d) {

case d @ source.ValDef(id, annot, binding) =>
case d @ source.ValDef(binders, binding, _) =>
()

case d @ source.VarDef(id, annot, region, binding) =>
Expand Down Expand Up @@ -225,10 +225,11 @@ object Namer extends Phase[Parsed, NameResolved] {
Context.define(id, p)
Context.bind(p.capture)

case d @ source.ValDef(id, annot, binding) =>
val tpe = annot.map(resolve)
case d @ source.ValDef(binders, binding, _) =>
resolveGeneric(binding)
Context.define(id, ValBinder(Context.nameFor(id), tpe, d))
binders.foreach { case source.ValueParam(id, tpe) =>
Context.define(id, ValBinder(Name.local(id), tpe.map(resolve), d))
}

case d @ source.VarDef(id, annot, region, binding) =>
val tpe = annot.map(resolve)
Expand Down Expand Up @@ -377,8 +378,8 @@ object Namer extends Phase[Parsed, NameResolved] {
}
}

case source.MatchClause(pattern, body) =>
val ps = resolve(pattern)
case source.MatchClause(patterns, body) =>
val ps = patterns.flatMap(resolve)

// wellformedness: only linear patterns
var names: Set[Name] = Set.empty
Expand Down Expand Up @@ -552,7 +553,7 @@ object Namer extends Phase[Parsed, NameResolved] {
case constructor: TypeConstructor => ValueTypeApp(constructor, args.map(resolve))
case id: TypeVar =>
if (args.nonEmpty) {
Context.abort(pretty"Type variables cannot be applied, but receieved ${args.size} arguments.")
Context.abort(pretty"Type variables cannot be applied, but received ${args.size} arguments.")
}
ValueTypeRef(id)
case TypeAlias(name, tparams, tpe) =>
Expand Down Expand Up @@ -604,7 +605,7 @@ object Namer extends Phase[Parsed, NameResolved] {

cps foreach Context.bind

val res = resolve(ret)
val res = ret map resolve

FunctionType(tps, cps, vps, bps, res, effs)
}
Expand Down Expand Up @@ -640,8 +641,8 @@ object Namer extends Phase[Parsed, NameResolved] {
def resolve(tpe: source.Effects)(using Context): Effects =
Effects(tpe.effs.flatMap(resolveWithAliases).toSeq: _*) // TODO this otherwise is calling the wrong apply

def resolve(e: source.Effectful)(using Context): (ValueType, Effects) =
(resolve(e.tpe), resolve(e.eff))
def resolve(e: source.Effectful)(using Context): (List[ValueType], Effects) =
(e.tpe map resolve, resolve(e.eff))

def resolve(capt: source.CaptureSet)(using Context): CaptureSet = {
val captResolved = CaptureSet(capt.captures.map { Context.resolveCapture }.toSet)
Expand Down
Loading
Loading