Git Product home page Git Product logo

scala-typed-holes's Introduction

scala-typed-holes

This is a Scala compiler plugin to emulate the "typed holes" feature of Haskell, Idris, Agda, etc.

Whenever you use ??? in your code, the compiler plugin will generate a compiler warning containing useful information about it.

For example, given the Scala code

package example

object Example {

  def foo(x: Int, y: String): Boolean = {
    if (y.length == x) {
      ??? // TODO implement!
    } else {
      true
    }
  }

  def bar(x: Int): String = x match {
    case 0 => "zero"
    case 1 => "one"
    case _ => ???
  }

}

you'll get warnings that look something like this:

[warn] /Users/chris/code/scala-typed-holes/src/test/scala/example/Example.scala:7:7:
[warn] Found hole with type: Boolean
[warn] Relevant bindings include
[warn]   x: Int (bound at Example.scala:5:11)
[warn]   y: String (bound at Example.scala:5:19)
[warn]
[warn]       ??? // TODO implement!
[warn]       ^
[warn] /Users/chris/code/scala-typed-holes/src/test/scala/example/Example.scala:16:15:
[warn] Found hole with type: String
[warn] Relevant bindings include
[warn]   x: Int (bound at Example.scala:13:11)
[warn]
[warn]     case _ => ???
[warn]               ^

Named holes

The plugin also supports named holes. Instead of using ???, you can give custom names to your holes.

For example, code like this

def hello(args: Array[String]): Option[Result] = Foo.doStuff(args) match {
  case Left(error)  => __left
  case Right(x)     => __right
}

will result in warnings like this

Found hole 'left' with type: Option[Result]
Relevant bindings include
  args: Array[String] (bound at input.scala:11:13)
  error: String (bound at input.scala:12:15)

    case Left(error)  => __left
                         ^

Named holes must start with a double underscore.

Warning: if you happen to use a naming convention that includes double underscores (which is pretty rare in Scala), this plugin will probably trash your code!

How to use

In sbt:

addCompilerPlugin("com.github.cb372" % "scala-typed-holes" % "0.1.11" cross CrossVersion.full)

The plugin is published for the following Scala versions:

  • 2.11.12
  • 2.12.15
  • 2.13.{0, 1, 2, 3, 4, 5, 6, 7, 8}

Changing the log level

By passing a compiler option -P:typed-holes:log-level:<level>, you can control the severity with which holes are logged.

  • info means holes will be logged as informational messages
  • warn means holes will be logged as compiler warnings
  • error means holes will be logged as compiler errors, so your program will fail to compile if it contains any holes.

The default behaviour is to log holes as warnings.

If you are using sbt, you can pass the option like this:

scalacOptions += "-P:typed-holes:log-level:info"

scala-typed-holes's People

Contributors

cb372 avatar github-actions[bot] avatar grafblutwurst avatar kubukoz avatar philippus avatar regadas avatar ruchira088 avatar sideeffffect avatar simy4 avatar toniogela avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

scala-typed-holes's Issues

holes within some expressions are missed

I have some code that contains ??? which is not recognized as a hole. In the sample below the holes in parseCmdLine do not result in output of the type while the one in foo does.

import caseapp._                                                                                                           
                                                                                                                           
object Main {                                                                                                              
  def main(args: Array[String]): Unit =                                                                                    
    println("Hello, world!")                                                                                               
                                                                                                                           
                                                                                                                           
  def parseCmdLine(args: List[String]): Option[Ops] = CaseApp.parse[Ops](args.toSeq) match {                               
    case Left(_)  => ???                                                                                                   
    case Right(_) => ???                                                                                                   
  }                                                                                                                        
                                                                                                                           
  def foo:Int = ???                                                                                                        
}                                                                                                                          

Not minimal yet. I'm filling this before I forget.

Migrate to GitHub Actions

travis-ci.org is going away at the end of the year. This repo has been migrated to travis-ci.com, but it's hard to tell whether builds will be free forever for migrated repos, or it's on the free trial plan and the credits will run out at some point.

All in all, I'd rather migrate to GH Actions.

Integration tests

Unit testing this thing is pretty much impossible. I think an integration test that compiles a Scala file and checks the stdout/stderr is more useful and achievable.

More intelligent binding suggestions

In the Relevant bindings include... section, currently we list all the bindings we can find. It would be nice to use the type of the hole to prioritise these bindings in some way, and maybe filter out any that are clearly irrelevant.

There's a wide spectrum of how clever we want to be with this. We need to be careful not to accidentally write our own typechecker or go too far down the road of Idris-style proof search or Curry-Howard correspondence. I'd like to see how far we could get with just some simple heuristics first.

2.13.6 support

As usual, the plugin needs to be cross-compiled to 2.13.6. I will make the change based on ef5f700, just wanted to leave an issue so nobody duplicates the work.

Compiler warnings break standard testing workflow

This is a great idea! Sadly, because it emits compiler warnings it breaks my workflow and I suspect my approach is not unique.

TL;DR; this plugin does not support TDD if fatal warnings are enabled (and they should be enabled). I'm going to describe my workflow to highlight what is broken, but I'd observe that this also breaks PDD (println-driven-development™) and I think these two approaches combined probably cover most developers.

Every Scala project should have -Xfatal-warnings enabled. This means things that emit compiler warnings need to be "real" problems, rather than things that are only warnings in a given context. In the case of ??? I would expect this to be a fatal error when building a production jar, but during development (and particularly while tests are compiling and executing) ??? is perfectly normal or indeed even encouraged.

My workflow for Scala code is as follows:

1. Stub functions to see how a part of the program fits together

This means writing the signatures and filling in the implementations with ???. This allows the computer and I to work together designing a program that makes sense before I start spending time on the implementations.

Using this plugin with fatal warnings (and as above, all Scala projects should have fatal warnings enabled) prevents this approach from working. It may be that if the only remaining compiler errors are from this plugin then the program is ready for the next step, but I'd always be nervous that one of these errors is masking something else that would only be revealed after the implementation removes the typed hole warnings.

2. Write unit tests that capture the expected behaviour of the stubbed functions

Doing this first makes sure I understand the problem before I start implementing, encourages higher quality tests by thinking about them separately to the implementation and makes sure the tests are in place while the code evolves to speed implementation (below).

Using this plugin prevents this step from working as well. In this case we can never get as far as running the tests until all the implementations are in place.

3. Evolve the implementation with help from the tests

It's impossible to work on everything at once so here I'd expect to fill in the building bit by bit using the scaffolding of types and tests. It's important the tests are in place before the code so we can see them turn from red to green as we progress.

Of course, the same applies here. We can only run the tests (or indeed, parts of the program) when the whole thing is finished.

What I'd like

This plugin is a fantastic idea, but I think in this form it isn't quite right. I'd say my "ideal dreamland" for this plugin would be that compilation fails when building a production jar (e.g. sbt commands like build, start, package, release), but only warn during tests (test, test*) - even if fatal warnings is enabled. For locally running the program in dev mode (run) I could be convinced either way but I suspect most people would expect compilation to succeed while running a partially built application to support PDD™. This is taking some inspiration from Elm, where the Debug package can be used in testing and development, but will cause a compilation error when building a production application.

I'm not sure how this could be achieved by a single plugin, I'd imagine it would need explicit support from all the plugins that do testing and building, so they'd be able to select the correct mode based on which of their commands is being invoked. I mention it in case I'm missing something, Elm hangs this behaviour off the optimize flag (which it uses when creating prod builds). It's possible there's a corresponding piece of state in sbt that could be used to determine whether ??? should be a real warning that causes compilation to fail (Elm output for a use of the equivalent, Debug.todo is below and here's the docs for it).

Because of all of the above, I don't think this plugin should emit warnings by default, or if it should then it needs to be overridable somehow. If it printed at a message level then the workflow problem would be fixed but we'd lose some of the safety it adds. If this plugin adds a flag then we'd be able to whitelist/blacklist it ourselves to be able to tailor the behaviour to our own needs, particularly if we're using non-standard sbt plugins (warnOnNotImplemented in Release := true / warnOnNotImplemented in (Test, Run) := false, for example).

Sorry for the long issue! I was really excited by the idea, then correspondingly saddened to find I couldn't use it so I put a bit of thought into what it would take to make it work.

Reference

Here's the Elm's output if you try and build an app that contains a TODO, but you can run it locally and run the tests just fine. Elm does not have fancy typed hole messages yet though ;-)

$ elm-app build

Creating an optimized production build...
Failed to compile.

./src/Main.elm
Error: Compiler process exited with error Compilation failed

-- DEBUG REMNANTS --------------------------------------------------------------

There are uses of the `Debug` module in the following modules:

    Main

But the --optimize flag only works if all `Debug` functions are removed!

Note: The issue is that --optimize strips out info needed by `Debug` functions.
Here are two examples:

    (1) It shortens record field names. This makes the generated JavaScript is
    smaller, but `Debug.toString` cannot know the real field names anymore.

    (2) Values like `type Height = Height Float` are unboxed. This reduces
    allocation, but it also means that `Debug.toString` cannot tell if it is
    looking at a `Height` or `Float` value.

There are a few other cases like that, and it will be much worse once we start
inlining code. That optimization could move `Debug.log` and `Debug.todo` calls,
resulting in unpredictable behavior. I hope that clarifies why this restriction
exists!

Type hole is not recognised in function literals

In this example:

object test {
  def ex1(i: => Int): Int = ??? // <- works fine
  def ex2(i: Int => Int): Int = ??? // <- works fine

  ex1 { ??? } // <- doesn't work
  ex2 { _ => ??? } // <- doesn't work
}

Is this expected? I'm using scala 2.12.8

Global plugin

Is it possible to use this as a global plugin (so that you don't need to commit changes to your build.sbt if you want to use this but other people working on the same project don't necessarily).

Sorry, this is probably not an issue with the plugin but rather my lack of knowledge of sbt!

I tried adding it to my ~/.sbt/1.0/plugins.sbt and then adding -P:typed-holes:log-level:error to .sbtopts (which can be git-ignored) but this gave me the error

[error] Expected ';'
[error] -P:typed-holes:log-level:error
[error]

when I launched sbt

Named holes

e.g.

x match {
 case 1 => "yeah"
 case _ => ?wut
}

Rough idea of implementation (no idea if it would work):

  1. Add a phase before parser that finds named holes, rewrites them to ??? and annotates them with the name of the hole.

  2. Check for that annotation in the existing post-typer phase.

SBT cannot load Scala 2.13 project

I tried with Scala 2.13.1, 2.13.0, and 2.12.8. The former two don't work. I forced the plugin version with

addCompilerPlugin("com.github.cb372" % "scala-typed-holes_2.13.1" % "0.1.1")

(similarly for the other versions of Scala, all with plugin 0.1.1).

Full stack trace

[error] java.lang.NoClassDefFoundError: scala/$less$colon$less
[error]         at holes.TypedHolesComponent$$anon$1.apply(TypedHolesComponent.scala:19)
[error]         at scala.tools.nsc.Global$GlobalPhase.applyPhase(Global.scala:441)
[error]         at scala.tools.nsc.Global$GlobalPhase.run(Global.scala:392)
[error]         at sbt.compiler.Eval.$anonfun$compileAndLoad$1(Eval.scala:248)
[error]         at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:12)
[error]         at scala.reflect.internal.SymbolTable.enteringPhase(SymbolTable.scala:282)
[error]         at sbt.compiler.Eval.compile$1(Eval.scala:248)
[error]         at sbt.compiler.Eval.compileAndLoad(Eval.scala:253)
[error]         at sbt.compiler.Eval.evalCommon(Eval.scala:218)
[error]         at sbt.compiler.Eval.eval(Eval.scala:128)
[error]         at sbt.internal.EvaluateConfigurations$.evaluateDslEntry(EvaluateConfigurations.scala:239)
[error]         at sbt.internal.EvaluateConfigurations$.$anonfun$evaluateSbtFile$2(EvaluateConfigurations.scala:158)
[error]         at scala.collection.TraversableLike.$anonfun$map$1(TraversableLike.scala:233)
[error]         at scala.collection.immutable.List.foreach(List.scala:388)
[error]         at scala.collection.TraversableLike.map(TraversableLike.scala:233)
[error]         at scala.collection.TraversableLike.map$(TraversableLike.scala:226)
[error]         at scala.collection.immutable.List.map(List.scala:294)
[error]         at sbt.internal.EvaluateConfigurations$.evaluateSbtFile(EvaluateConfigurations.scala:156)
[error]         at sbt.internal.Load$.loadSettingsFile$1(Load.scala:1136)
[error]         at sbt.internal.Load$.$anonfun$discoverProjects$2(Load.scala:1144)
[error]         at scala.collection.MapLike.getOrElse(MapLike.scala:127)
[error]         at scala.collection.MapLike.getOrElse$(MapLike.scala:125)
[error]         at scala.collection.AbstractMap.getOrElse(Map.scala:59)
[error]         at sbt.internal.Load$.memoLoadSettingsFile$1(Load.scala:1143)
[error]         at sbt.internal.Load$.$anonfun$discoverProjects$4(Load.scala:1151)
[error]         at scala.collection.TraversableLike.$anonfun$map$1(TraversableLike.scala:233)
[error]         at scala.collection.mutable.ResizableArray.foreach(ResizableArray.scala:58)
[error]         at scala.collection.mutable.ResizableArray.foreach$(ResizableArray.scala:51)
[error]         at scala.collection.mutable.ArrayBuffer.foreach(ArrayBuffer.scala:47)
[error]         at scala.collection.TraversableLike.map(TraversableLike.scala:233)
[error]         at scala.collection.TraversableLike.map$(TraversableLike.scala:226)
[error]         at scala.collection.AbstractTraversable.map(Traversable.scala:104)
[error]         at sbt.internal.Load$.loadFiles$1(Load.scala:1151)
[error]         at sbt.internal.Load$.discoverProjects(Load.scala:1165)
[error]         at sbt.internal.Load$.discover$1(Load.scala:862)
[error]         at sbt.internal.Load$.loadTransitive(Load.scala:937)
[error]         at sbt.internal.Load$.loadProjects$1(Load.scala:726)
[error]         at sbt.internal.Load$.$anonfun$loadUnit$11(Load.scala:729)
[error]         at sbt.internal.Load$.timed(Load.scala:1395)
[error]         at sbt.internal.Load$.$anonfun$loadUnit$1(Load.scala:729)
[error]         at sbt.internal.Load$.timed(Load.scala:1395)
[error]         at sbt.internal.Load$.loadUnit(Load.scala:688)
[error]         at sbt.internal.Load$.$anonfun$builtinLoader$4(Load.scala:484)
[error]         at sbt.internal.BuildLoader$.$anonfun$componentLoader$5(BuildLoader.scala:176)
[error]         at sbt.internal.BuildLoader.apply(BuildLoader.scala:241)
[error]         at sbt.internal.Load$.loadURI$1(Load.scala:546)
[error]         at sbt.internal.Load$.loadAll(Load.scala:562)
[error]         at sbt.internal.Load$.loadURI(Load.scala:492)
[error]         at sbt.internal.Load$.load(Load.scala:471)
[error]         at sbt.internal.Load$.$anonfun$apply$1(Load.scala:251)
[error]         at sbt.internal.Load$.timed(Load.scala:1395)
[error]         at sbt.internal.Load$.apply(Load.scala:251)
[error]         at sbt.internal.Load$.defaultLoad(Load.scala:69)
[error]         at sbt.BuiltinCommands$.liftedTree1$1(Main.scala:829)
[error]         at sbt.BuiltinCommands$.doLoadProject(Main.scala:829)
[error]         at sbt.BuiltinCommands$.$anonfun$loadProjectImpl$2(Main.scala:800)
[error]         at sbt.Command$.$anonfun$applyEffect$4(Command.scala:142)
[error]         at sbt.Command$.$anonfun$applyEffect$2(Command.scala:137)
[error]         at sbt.Command$.process(Command.scala:181)
[error]         at sbt.MainLoop$.processCommand(MainLoop.scala:151)
[error]         at sbt.MainLoop$.$anonfun$next$2(MainLoop.scala:139)
[error]         at sbt.State$$anon$1.runCmd$1(State.scala:246)
[error]         at sbt.State$$anon$1.process(State.scala:250)
[error]         at sbt.MainLoop$.$anonfun$next$1(MainLoop.scala:139)
[error]         at sbt.internal.util.ErrorHandling$.wideConvert(ErrorHandling.scala:16)
[error]         at sbt.MainLoop$.next(MainLoop.scala:139)
[error]         at sbt.MainLoop$.run(MainLoop.scala:132)
[error]         at sbt.MainLoop$.$anonfun$runWithNewLog$1(MainLoop.scala:110)
[error]         at sbt.io.Using.apply(Using.scala:22)
[error]         at sbt.MainLoop$.runWithNewLog(MainLoop.scala:104)
[error]         at sbt.MainLoop$.runAndClearLast(MainLoop.scala:59)
[error]         at sbt.MainLoop$.runLoggedLoop(MainLoop.scala:44)
[error]         at sbt.MainLoop$.runLogged(MainLoop.scala:35)
[error]         at sbt.StandardMain$.runManaged(Main.scala:138)
[error]         at sbt.xMain.run(Main.scala:89)
[error]         at xsbt.boot.Launch$$anonfun$run$1.apply(Launch.scala:111)
[error]         at xsbt.boot.Launch$.withContextLoader(Launch.scala:130)
[error]         at xsbt.boot.Launch$.run(Launch.scala:111)
[error]         at xsbt.boot.Launch$$anonfun$apply$1.apply(Launch.scala:37)
[error]         at xsbt.boot.Launch$.launch(Launch.scala:119)
[error]         at xsbt.boot.Launch$.apply(Launch.scala:20)
[error]         at xsbt.boot.Boot$.runImpl(Boot.scala:56)
[error]         at xsbt.boot.Boot$.main(Boot.scala:18)
[error]         at xsbt.boot.Boot.main(Boot.scala)
[error] Caused by: java.lang.ClassNotFoundException: scala.$less$colon$less
[error]         at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
[error]         at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
[error]         at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
[error]         at holes.TypedHolesComponent$$anon$1.apply(TypedHolesComponent.scala:19)
[error]         at scala.tools.nsc.Global$GlobalPhase.applyPhase(Global.scala:441)
[error]         at scala.tools.nsc.Global$GlobalPhase.run(Global.scala:392)
[error]         at sbt.compiler.Eval.$anonfun$compileAndLoad$1(Eval.scala:248)
[error]         at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:12)
[error]         at scala.reflect.internal.SymbolTable.enteringPhase(SymbolTable.scala:282)
[error]         at sbt.compiler.Eval.compile$1(Eval.scala:248)
[error]         at sbt.compiler.Eval.compileAndLoad(Eval.scala:253)
[error]         at sbt.compiler.Eval.evalCommon(Eval.scala:218)
[error]         at sbt.compiler.Eval.eval(Eval.scala:128)
[error]         at sbt.internal.EvaluateConfigurations$.evaluateDslEntry(EvaluateConfigurations.scala:239)
[error]         at sbt.internal.EvaluateConfigurations$.$anonfun$evaluateSbtFile$2(EvaluateConfigurations.scala:158)
[error]         at scala.collection.TraversableLike.$anonfun$map$1(TraversableLike.scala:233)
[error]         at scala.collection.immutable.List.foreach(List.scala:388)
[error]         at scala.collection.TraversableLike.map(TraversableLike.scala:233)
[error]         at scala.collection.TraversableLike.map$(TraversableLike.scala:226)
[error]         at scala.collection.immutable.List.map(List.scala:294)
[error]         at sbt.internal.EvaluateConfigurations$.evaluateSbtFile(EvaluateConfigurations.scala:156)
[error]         at sbt.internal.Load$.loadSettingsFile$1(Load.scala:1136)
[error]         at sbt.internal.Load$.$anonfun$discoverProjects$2(Load.scala:1144)
[error]         at scala.collection.MapLike.getOrElse(MapLike.scala:127)
[error]         at scala.collection.MapLike.getOrElse$(MapLike.scala:125)
[error]         at scala.collection.AbstractMap.getOrElse(Map.scala:59)
[error]         at sbt.internal.Load$.memoLoadSettingsFile$1(Load.scala:1143)
[error]         at sbt.internal.Load$.$anonfun$discoverProjects$4(Load.scala:1151)
[error]         at scala.collection.TraversableLike.$anonfun$map$1(TraversableLike.scala:233)
[error]         at scala.collection.mutable.ResizableArray.foreach(ResizableArray.scala:58)
[error]         at scala.collection.mutable.ResizableArray.foreach$(ResizableArray.scala:51)
[error]         at scala.collection.mutable.ArrayBuffer.foreach(ArrayBuffer.scala:47)
[error]         at scala.collection.TraversableLike.map(TraversableLike.scala:233)
[error]         at scala.collection.TraversableLike.map$(TraversableLike.scala:226)
[error]         at scala.collection.AbstractTraversable.map(Traversable.scala:104)
[error]         at sbt.internal.Load$.loadFiles$1(Load.scala:1151)
[error]         at sbt.internal.Load$.discoverProjects(Load.scala:1165)
[error]         at sbt.internal.Load$.discover$1(Load.scala:862)
[error]         at sbt.internal.Load$.loadTransitive(Load.scala:937)
[error]         at sbt.internal.Load$.loadProjects$1(Load.scala:726)
[error]         at sbt.internal.Load$.$anonfun$loadUnit$11(Load.scala:729)
[error]         at sbt.internal.Load$.timed(Load.scala:1395)
[error]         at sbt.internal.Load$.$anonfun$loadUnit$1(Load.scala:729)
[error]         at sbt.internal.Load$.timed(Load.scala:1395)
[error]         at sbt.internal.Load$.loadUnit(Load.scala:688)
[error]         at sbt.internal.Load$.$anonfun$builtinLoader$4(Load.scala:484)
[error]         at sbt.internal.BuildLoader$.$anonfun$componentLoader$5(BuildLoader.scala:176)
[error]         at sbt.internal.BuildLoader.apply(BuildLoader.scala:241)
[error]         at sbt.internal.Load$.loadURI$1(Load.scala:546)
[error]         at sbt.internal.Load$.loadAll(Load.scala:562)
[error]         at sbt.internal.Load$.loadURI(Load.scala:492)
[error]         at sbt.internal.Load$.load(Load.scala:471)
[error]         at sbt.internal.Load$.$anonfun$apply$1(Load.scala:251)
[error]         at sbt.internal.Load$.timed(Load.scala:1395)
[error]         at sbt.internal.Load$.apply(Load.scala:251)
[error]         at sbt.internal.Load$.defaultLoad(Load.scala:69)
[error]         at sbt.BuiltinCommands$.liftedTree1$1(Main.scala:829)
[error]         at sbt.BuiltinCommands$.doLoadProject(Main.scala:829)
[error]         at sbt.BuiltinCommands$.$anonfun$loadProjectImpl$2(Main.scala:800)
[error]         at sbt.Command$.$anonfun$applyEffect$4(Command.scala:142)
[error]         at sbt.Command$.$anonfun$applyEffect$2(Command.scala:137)
[error]         at sbt.Command$.process(Command.scala:181)
[error]         at sbt.MainLoop$.processCommand(MainLoop.scala:151)
[error]         at sbt.MainLoop$.$anonfun$next$2(MainLoop.scala:139)
[error]         at sbt.State$$anon$1.runCmd$1(State.scala:246)
[error]         at sbt.State$$anon$1.process(State.scala:250)
[error]         at sbt.MainLoop$.$anonfun$next$1(MainLoop.scala:139)
[error]         at sbt.internal.util.ErrorHandling$.wideConvert(ErrorHandling.scala:16)
[error]         at sbt.MainLoop$.next(MainLoop.scala:139)
[error]         at sbt.MainLoop$.run(MainLoop.scala:132)
[error]         at sbt.MainLoop$.$anonfun$runWithNewLog$1(MainLoop.scala:110)
[error]         at sbt.io.Using.apply(Using.scala:22)
[error]         at sbt.MainLoop$.runWithNewLog(MainLoop.scala:104)
[error]         at sbt.MainLoop$.runAndClearLast(MainLoop.scala:59)
[error]         at sbt.MainLoop$.runLoggedLoop(MainLoop.scala:44)
[error]         at sbt.MainLoop$.runLogged(MainLoop.scala:35)
[error]         at sbt.StandardMain$.runManaged(Main.scala:138)
[error]         at sbt.xMain.run(Main.scala:89)
[error]         at xsbt.boot.Launch$$anonfun$run$1.apply(Launch.scala:111)
[error]         at xsbt.boot.Launch$.withContextLoader(Launch.scala:130)
[error]         at xsbt.boot.Launch$.run(Launch.scala:111)
[error]         at xsbt.boot.Launch$$anonfun$apply$1.apply(Launch.scala:37)
[error]         at xsbt.boot.Launch$.launch(Launch.scala:119)
[error]         at xsbt.boot.Launch$.apply(Launch.scala:20)
[error]         at xsbt.boot.Boot$.runImpl(Boot.scala:56)
[error]         at xsbt.boot.Boot$.main(Boot.scala:18)
[error]         at xsbt.boot.Boot.main(Boot.scala)
[error] java.lang.NoClassDefFoundError: scala/$less$colon$less
[error] Use 'last' for the full log.
Project loading failed: (r)etry, (q)uit, (l)ast, or (i)gnore?

Relevant code

override def newPhase(prev: Phase): StdPhase = new StdPhase(prev) {
override def apply(unit: CompilationUnit): Unit = {
new TypedHolesTraverser(unit).traverse(unit.body)
}
}

Note that while line 19 is the only one which shows up in the stack trace, it makes no apparent use of the missing <:<.

Investigate building a Scala 3 plugin

This issue is to investigate the feasibility of porting scala-typed-holes to Scala 3.

I haven't looked at all at how to write compiler plugins in Scala 3. I imagine the plugin architecture is roughly the same, although the AST and the compiler internals are different from Scala 2.

I don't think there's much chance of sharing any code between Scala 2 and Scala 3. I imagine it'll be separate branches, or maybe even separate repos.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.