Skip to content

Confusion between syntax for pattern alternative and typed pattern on a union type #3332

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

Closed
abgruszecki opened this issue Oct 17, 2017 · 3 comments

Comments

@abgruszecki
Copy link
Contributor

As in the title, running this code in REPL throws java.lang.VerifyError:

scala> def f(): String | Int = 0
def f(): String | Int
scala> f() match { case s: String | Int => s }
java.lang.VerifyError: Bad local variable type
Exception Details:
  Location:
    rs$line$2$.<init>()V @33: aload_3
  Reason:
    Type top (current frame, locals[3]) is not assignable to reference type
  Current Frame:
    bci: @33
    flags: { }
    locals: { 'rs$line$2$', 'java/lang/Object' }
    stack: { 'rs$line$2$' }
  Bytecode:
    0x0000000: 2ab7 0014 2ab3 0016 2ab2 001b b600 1f4c
    0x0000010: 2bc1 0021 9900 172b c000 214d 2c4e a700
    0x0000020: 072d a700 06a7 fffc a700 1cb2 0026 2bb6
    0x0000030: 002a 9900 09a7 ffec 0000 bfbb 002c 592b
    0x0000040: b700 2fbf b500 31b1
  Stackmap Table:
    full_frame(@33,{Object[#2],Object[#4]},{Object[#2]})
    full_frame(@37,{Object[#2],Object[#4],Object[#33],Object[#33]},{Object[#2]})
    full_frame(@40,{Object[#2],Object[#4]},{Object[#2],Top})
    same_locals_1_stack_item_frame(@43,Object[#2])
    full_frame(@56,{},{Object[#53]})
    full_frame(@59,{Object[#2],Object[#4]},{Object[#2]})
    full_frame(@68,{Object[#2],Object[#4]},{Object[#2],Top})

	at rs$line$2.res0Show(rs$line$2)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at dotty.tools.repl.Rendering.valueOf(Rendering.scala:58)
	at dotty.tools.repl.Rendering.renderVal(Rendering.scala:79)
	at dotty.tools.repl.ReplDriver.$anonfun$displayDefinitions$8(ReplDriver.scala:269)
	at scala.collection.TraversableLike.$anonfun$map$1(TraversableLike.scala:234)
	at scala.collection.mutable.ResizableArray.foreach(ResizableArray.scala:59)
	at scala.collection.mutable.ResizableArray.foreach$(ResizableArray.scala:52)
	at scala.collection.mutable.ArrayBuffer.foreach(ArrayBuffer.scala:48)
	at scala.collection.TraversableLike.map(TraversableLike.scala:234)
	at scala.collection.TraversableLike.map$(TraversableLike.scala:227)
	at scala.collection.AbstractTraversable.map(Traversable.scala:104)
	at dotty.tools.repl.ReplDriver.displayMembers$1(ReplDriver.scala:269)
	at dotty.tools.repl.ReplDriver.$anonfun$displayDefinitions$15(ReplDriver.scala:296)
	at scala.Option.map(Option.scala:146)
	at dotty.tools.repl.ReplDriver.$anonfun$displayDefinitions$13(ReplDriver.scala:294)
	at dotty.tools.dotc.core.Periods.atPhase(Periods.scala:26)
	at dotty.tools.dotc.core.Phases.atPhase(Phases.scala:36)
	at dotty.tools.dotc.core.Phases.atPhase$(Phases.scala:35)
	at dotty.tools.dotc.core.Contexts$Context.atPhase(Contexts.scala:57)
	at dotty.tools.repl.ReplDriver.displayDefinitions(ReplDriver.scala:289)
	at dotty.tools.repl.ReplDriver.$anonfun$compile$2(ReplDriver.scala:226)
	at scala.util.Either.fold(Either.scala:188)
	at dotty.tools.repl.ReplDriver.compile(ReplDriver.scala:220)
	at dotty.tools.repl.ReplDriver.interpret(ReplDriver.scala:190)
	at dotty.tools.repl.ReplDriver.runUntilQuit(ReplDriver.scala:143)
	at dotty.tools.repl.Main$.main(Main.scala:6)
	at dotty.tools.repl.Main.main(Main.scala)

Parenthesising the type, however, runs normally:

scala> f() match { case s: (String | Int) => s }
val res2: Any = 0
@allanrenucci
Copy link
Contributor

Without parenthesis, it is parsed as

case (s @ _: String) | Int => 

with parenthesis:

case s @ _: String | Int =>

@allanrenucci
Copy link
Contributor

allanrenucci commented Oct 17, 2017

But I think it is more than a parsing issue, the following code snippet compiles with Dotty and crashes at runtime:

object Main {
  def main(args: Array[String]): Unit = {
    (1: Any) match { case (s: String) | _: Int => s }
  }
}
Exception in thread "main" java.lang.VerifyError: Bad local variable type
Exception Details:
  Location:
    Main$.main([Ljava/lang/String;)V @23: aload
  Reason:
    Type top (current frame, locals[4]) is not assignable to reference type
  Current Frame:
    bci: @23
    flags: { }
    locals: { 'Main$', '[Ljava/lang/String;', 'java/lang/Integer' }
    stack: { }
  Bytecode:
    0x0000000: 04b8 0018 4d2c c100 1a99 001a 2cc0 001a
    0x0000010: 4e2d 3a04 a700 0919 0457 a700 06a7 fffa
    0x0000020: a700 1cb2 001f 2cb6 0023 9900 09a7 ffea
    0x0000030: 0000 bfbb 0025 592c b700 28bf b1       
  Stackmap Table:
    append_frame(@23,Object[#46])
    append_frame(@29,Object[#26],Object[#26])
    chop_frame(@32,2)
    same_frame(@35)
    full_frame(@48,{},{Object[#48]})
    append_frame(@51,Object[#2],Object[#49],Object[#46])
    same_frame(@60)

	at Main.main(Test.scala)

@smarter
Copy link
Member

smarter commented Oct 18, 2017

This code should not compile, as in scalac where you get:

try/i3332.scala:3: error: illegal variable in pattern alternative
    (1: Any) match { case (s: String) | _: Int => s }
                           ^

There's already an issue for that: #1612

The other issue is how to parse case s: String | Int, it's unfortunate that the current meaning is confusing when combined with union types, but I don't know if there's a good solution here

@smarter smarter changed the title java.lang.VerifyError when matching on union type Confusion between syntax for pattern alternative and typed pattern on a union type Oct 18, 2017
@odersky odersky self-assigned this Oct 25, 2017
odersky added a commit to dotty-staging/dotty that referenced this issue Nov 1, 2017
Disallow bound variables where the binder appears as a pattern alternative.
@odersky odersky assigned allanrenucci and unassigned allanrenucci Nov 2, 2017
odersky added a commit that referenced this issue Nov 11, 2017
Fix #3332: Disallow bound variables in pattern alternatives
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants