-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Closed
Labels
area:metaprogramming:quotesIssues related to quotes and splicesIssues related to quotes and splicesarea:nullabilityitype:bugitype:crash
Milestone
Description
Compiler version
3.8.1
Minimized code
in one file:
package Foo
import scala.quoted.*
object NonNullFold:
extension [A](inline arg: A | Null)
/**
* Extension method to fold over a nullable value.
* Uses pattern matching to ensure compatibility with strict equality.
*/
inline def foldNN[B](inline default: => B)(inline fn: A => B): B =
${ foldNNImpl('arg, 'default, 'fn) }
inline def notNull[B]: Boolean =
foldNN(false)(_ => true)
private def foldNNImpl[A: Type, B: Type](
arg: Expr[A | Null],
default: Expr[B],
fn: Expr[A => B]
)(using Quotes): Expr[B] =
'{
// 1. Bind the argument to a val to prevent multiple evaluations
val t = $arg
// 2.
// This works even if 'import scala.language.strictEquality' is active.
given CanEqual[A | Null, Null] = CanEqual.derived
if (t == null) $default
else {
// CRITICAL FIX:
// We define a new local 'val' with the explicit type 'A'.
// This strips away the complex intersection types (flow typing) from 't'
// that were causing the MatchError in the unpickler.
//val safe: A = t.asInstanceOf[A]
// 3. We cast to A safely because we are in the not-null branch.
// 4. betaReduce inlines the function body directly here.
//${ Expr.betaReduce('{ $fn(safe) }) }
${ Expr.betaReduce('{ $fn(t) }) }
}
}In another:
import NonNullFold.*
package Foo
val x: String | Null = "not null"
val y = x.foldNN("it's null")(x => x)Output (click arrow to expand)
Details
error] 135 |val y = x.foldNN("it's null")(x => x)
[error] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
[error] |Exception occurred while executing macro expansion.
[error] |scala.MatchError: AndType(TermRef(NoPrefix,val t),TypeRef(NoPrefix,type evidence$1$1)) (of class dotty.tools.dotc.core.Types$CachedAndType)
[error] | at dotty.tools.dotc.core.tasty.TreeUnpickler$TreeReader.readPathTree$1(TreeUnpickler.scala:1285)
[error] | at dotty.tools.dotc.core.tasty.TreeUnpickler$TreeReader.readLengthTree$1(TreeUnpickler.scala:1702)
[error] | at dotty.tools.dotc.core.tasty.TreeUnpickler$TreeReader.readTree(TreeUnpickler.scala:1708)
[error] | at dotty.tools.dotc.core.tasty.TreeUnpickler$TreeReader.$anonfun$50(TreeUnpickler.scala:1767)
[error] | at dotty.tools.tasty.TastyReader.until(TastyReader.scala:135)
[error] | at dotty.tools.dotc.core.tasty.TreeUnpickler$TreeReader.readHole(TreeUnpickler.scala:1767)
[error] | at dotty.tools.dotc.core.tasty.TreeUnpickler$TreeReader.readLengthTree$1(TreeUnpickler.scala:1700)
[error] | at dotty.tools.dotc.core.tasty.TreeUnpickler$TreeReader.readTree(TreeUnpickler.scala:1708)
[error] | at dotty.tools.dotc.core.tasty.TreeUnpickler$TreeReader.readLengthTree$1(TreeUnpickler.scala:1531)
[error] | at dotty.tools.dotc.core.tasty.TreeUnpickler$TreeReader.readTree(TreeUnpickler.scala:1708)
[error] | at dotty.tools.dotc.core.tasty.TreeUnpickler.dotty$tools$dotc$core$tasty$TreeUnpickler$TreeReader$$_$_$$anonfun$34(TreeUnpickler.scala:1521)
[error] | at dotty.tools.dotc.core.tasty.TreeUnpickler$TreeReader.readIndexedStats(TreeUnpickler.scala:1248)
[error] | at dotty.tools.dotc.core.tasty.TreeUnpickler$TreeReader.readStats(TreeUnpickler.scala:1252)
[error] | at dotty.tools.dotc.core.tasty.TreeUnpickler$TreeReader.readLengthTree$1(TreeUnpickler.scala:1521)
[error] | at dotty.tools.dotc.core.tasty.TreeUnpickler$TreeReader.readTree(TreeUnpickler.scala:1708)
[error] | at dotty.tools.dotc.core.tasty.TreeUnpickler$TreeReader.readLengthTree$1(TreeUnpickler.scala:1539)
[error] | at dotty.tools.dotc.core.tasty.TreeUnpickler$TreeReader.readTree(TreeUnpickler.scala:1708)
[error] | at dotty.tools.dotc.core.tasty.TreeUnpickler.dotty$tools$dotc$core$tasty$TreeUnpickler$TreeReader$$_$_$$anonfun$34(TreeUnpickler.scala:1521)
[error] | at dotty.tools.dotc.core.tasty.TreeUnpickler$TreeReader.readIndexedStats(TreeUnpickler.scala:1248)
[error] | at dotty.tools.dotc.core.tasty.TreeUnpickler$TreeReader.readStats(TreeUnpickler.scala:1252)
[error] | at dotty.tools.dotc.core.tasty.TreeUnpickler$TreeReader.readLengthTree$1(TreeUnpickler.scala:1521)
[error] | at dotty.tools.dotc.core.tasty.TreeUnpickler$TreeReader.readTree(TreeUnpickler.scala:1708)
[error] | at dotty.tools.dotc.core.tasty.TreeUnpickler.dotty$tools$dotc$core$tasty$TreeUnpickler$TreeReader$$_$_$$anonfun$34(TreeUnpickler.scala:1521)
[error] | at dotty.tools.dotc.core.tasty.TreeUnpickler$TreeReader.readIndexedStats(TreeUnpickler.scala:1248)
[error] | at dotty.tools.dotc.core.tasty.TreeUnpickler$TreeReader.readStats(TreeUnpickler.scala:1252)
[error] | at dotty.tools.dotc.core.tasty.TreeUnpickler$TreeReader.readLengthTree$1(TreeUnpickler.scala:1521)
[error] | at dotty.tools.dotc.core.tasty.TreeUnpickler$TreeReader.readTree(TreeUnpickler.scala:1708)
[error] | at dotty.tools.dotc.core.tasty.TreeUnpickler$TreeReader.readLengthTree$1(TreeUnpickler.scala:1531)
[error] | at dotty.tools.dotc.core.tasty.TreeUnpickler$TreeReader.readTree(TreeUnpickler.scala:1708)
[error] | at dotty.tools.dotc.core.tasty.TreeUnpickler$TreeReader.readTree(TreeUnpickler.scala:1273)
[error] | at dotty.tools.dotc.core.tasty.TreeUnpickler.unpickle(TreeUnpickler.scala:146)
[error] | at dotty.tools.dotc.core.tasty.DottyUnpickler.computeRootTrees(DottyUnpickler.scala:95)
[error] | at dotty.tools.dotc.ast.tpd$TreeProvider.rootTrees(tpd.scala:1374)
[error] | at dotty.tools.dotc.ast.tpd$TreeProvider.rootTrees$(tpd.scala:1363)
[error] | at dotty.tools.dotc.core.tasty.DottyUnpickler.rootTrees(DottyUnpickler.scala:58)
[error] | at dotty.tools.dotc.ast.tpd$TreeProvider.tree(tpd.scala:1378)
[error] | at dotty.tools.dotc.ast.tpd$TreeProvider.tree$(tpd.scala:1363)
[error] | at dotty.tools.dotc.core.tasty.DottyUnpickler.tree(DottyUnpickler.scala:58)
[error] | at dotty.tools.dotc.quoted.PickledQuotes$.unpickle(PickledQuotes.scala:278)
[error] | at dotty.tools.dotc.quoted.PickledQuotes$.unpickleTerm(PickledQuotes.scala:86)
[error] | at scala.quoted.runtime.impl.QuotesImpl.unpickleExprV2(QuotesImpl.scala:3562)
[error] | at dev.bosatsu.NonNullFold$.foldNNImpl(NonNullFold.scala:40)
[error] | at dev.bosatsu.NonNullFold$.inline$foldNNImpl(NonNullFold.scala:18)
[error] |
[error] |---------------------------------------------------------------------------
[error] |Inline stack trace
[error] |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
[error] |This location contains code that was inlined from NonNullFold.scala:13
[error] 13 | ${ foldNNImpl('arg, 'default, 'fn) }
[error] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
[error] ---------------------------------------------------------------------------
[error] one error foundMy work around is to uncomment the safe related variables and cast away the flow typing added by explicit nulls, but I shouldn't have to do that. The compiler shouldn't crash
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
area:metaprogramming:quotesIssues related to quotes and splicesIssues related to quotes and splicesarea:nullabilityitype:bugitype:crash