Skip to content

Instantly share code, notes, and snippets.

@nivekastoreth
Last active January 23, 2019 01:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nivekastoreth/fbe5dfb12687c565587f279909ff04f0 to your computer and use it in GitHub Desktop.
Save nivekastoreth/fbe5dfb12687c565587f279909ff04f0 to your computer and use it in GitHub Desktop.
Exploration revolving around https://github.com/scala/bug/issues/11379
// Initial exploration of various means of writing similar expressions
// and what (if any) errors/warnings they emit when compiling
private def unitRight[A]: A \/ Unit = ().right[A]
// fails with: discarded non-Unit value
def test1: \/[String, Unit] = \/-(\/-(()))
def test2: \/[String, Unit] = ().right[String].map(_ => unitRight[String])
def test3: \/[String, Unit] = ().right[String].map { case _ => unitRight[String] }
// fails with: type mismatch;
def test4: \/[String, Unit] = ().right[String].right[String]
// fails with: polymorphic expression cannot be instantiated to expected type;
def test5: \/[String, Unit] = ().right[String].map(().right)
// compiles just fine
def test6: \/[String, Unit] = ().right[String].map { case _ => unitRight }
def test7: \/[String, Unit] = ().right[String].map { _ => unitRight}
def test8: \/[String, Unit] = ().right[String].map(_ => unitRight)
// I believe this to be the most concise example of what I believe the actual bug to be
// I stumbled across this when attempting to figure out why this was happening for
// scalaz's Disjunction but was not happening for scala's Future class.
class OneTypeParam[B](value: B) {
def map[B1](fn: B => B1): OneTypeParam[B1] = new OneTypeParam(fn(value))
def unitValue: OneTypeParam[Unit] = new OneTypeParam(())
def checkCompiler: OneTypeParam[Unit] = unitValue.map(_ => unitValue)
}
class TwoTypeParam[A, B](value: B) {
def map[B1](fn: B => B1): TwoTypeParam[A, B1] = new TwoTypeParam(fn(value))
def unitValue[C]: TwoTypeParam[C, Unit] = new TwoTypeParam(())
def checkCompiler: TwoTypeParam[String, Unit] = unitValue.map(_ => unitValue)
}
/*
jmaki@jmaki-pc ~/test/scala
$ rm -f *.class; /build/env/scala-2.12.8/bin/scalac -Xfatal-warnings -Ywarn-value-discard -deprecation -print TypeNumExample.scala
TypeNumExample.scala:4: warning: discarded non-Unit value
def checkCompiler: OneTypeParam[Unit] = unitValue.map(_ => unitValue)
^
[[syntax trees at end of cleanup]] // TypeNumExample.scala
package <empty> {
class OneTypeParam extends Object {
<paramaccessor> private[this] val value: Object = _;
def map(fn: Function1): OneTypeParam = new OneTypeParam(fn.apply(OneTypeParam.this.value));
def unitValue(): OneTypeParam = new OneTypeParam(scala.runtime.BoxedUnit.UNIT);
def checkCompiler(): OneTypeParam = OneTypeParam.this.unitValue().map({
((x$1: scala.runtime.BoxedUnit) => OneTypeParam.this.$anonfun$checkCompiler$1(x$1))
});
final <artifact> private[this] def $anonfun$checkCompiler$1(x$1: scala.runtime.BoxedUnit): Unit = {
OneTypeParam.this.unitValue();
()
};
def <init>(value: Object): OneTypeParam = {
OneTypeParam.this.value = value;
OneTypeParam.super.<init>();
()
}
};
class TwoTypeParam extends Object {
<paramaccessor> private[this] val value: Object = _;
def map(fn: Function1): TwoTypeParam = new TwoTypeParam(fn.apply(TwoTypeParam.this.value));
def unitValue(): TwoTypeParam = new TwoTypeParam(scala.runtime.BoxedUnit.UNIT);
def checkCompiler(): TwoTypeParam = TwoTypeParam.this.unitValue().map({
((x$2: scala.runtime.BoxedUnit) => TwoTypeParam.this.$anonfun$checkCompiler$2(x$2))
});
final <artifact> private[this] def $anonfun$checkCompiler$2(x$2: scala.runtime.BoxedUnit): Unit = {
TwoTypeParam.this.unitValue();
()
};
def <init>(value: Object): TwoTypeParam = {
TwoTypeParam.this.value = value;
TwoTypeParam.super.<init>();
()
}
}
}
error: No warnings can be incurred under -Xfatal-warnings.
one warning found
one error found
*/
// Small example in response to https://github.com/scala/bug/issues/11233#issuecomment-434508694
// that shows this bug happens even when specifying compiler flags -Xfatal-warnings and -Ywarn-value-discard
import scala.util._
object UnitExample {
def unitEither[A]: A Either Unit = Right(())
def shouldFailEither[A](l: List[A]): String Either Unit = unitEither.map(_ => unitEither)
}
/*
jmaki@jmaki-pc ~/test/scala
$ cat UnitExample.scala
import scala.util._
object UnitExample {
def unitEither[A]: A Either Unit = Right(())
def shouldFailEither: String Either Unit = unitEither.map(_ => unitEither)
}
jmaki@jmaki-pc ~/test/scala
$ rm -f *.class; /build/env/scala-2.12.8/bin/scalac -Xfatal-warnings -Ywarn-value-discard -deprecation -print UnitExample.scala
[[syntax trees at end of cleanup]] // UnitExample.scala
package <empty> {
object UnitExample extends Object {
def unitEither(): scala.util.Either = new scala.util.Right(scala.runtime.BoxedUnit.UNIT);
def shouldFailEither(): scala.util.Either = UnitExample.this.unitEither().map({
((x$1: scala.runtime.BoxedUnit) => UnitExample.this.$anonfun$shouldFailEither$1(x$1))
});
final <artifact> private[this] def $anonfun$shouldFailEither$1(x$1: scala.runtime.BoxedUnit): Unit = {
UnitExample.unitEither();
()
};
def <init>(): UnitExample.type = {
UnitExample.super.<init>();
()
}
}
}
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment